widget/windows/nsWindow.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sts=2 sw=2 et cin: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * nsWindow - Native window management and event handling.
     9  * 
    10  * nsWindow is organized into a set of major blocks and
    11  * block subsections. The layout is as follows:
    12  *
    13  *  Includes
    14  *  Variables
    15  *  nsIWidget impl.
    16  *     nsIWidget methods and utilities
    17  *  nsSwitchToUIThread impl.
    18  *     nsSwitchToUIThread methods and utilities
    19  *  Moz events
    20  *     Event initialization
    21  *     Event dispatching
    22  *  Native events
    23  *     Wndproc(s)
    24  *     Event processing
    25  *     OnEvent event handlers
    26  *  IME management and accessibility
    27  *  Transparency
    28  *  Popup hook handling
    29  *  Misc. utilities
    30  *  Child window impl.
    31  *
    32  * Search for "BLOCK:" to find major blocks.
    33  * Search for "SECTION:" to find specific sections.
    34  *
    35  * Blocks should be split out into separate files if they
    36  * become unmanageable.
    37  *
    38  * Related source:
    39  *
    40  *  nsWindowDefs.h     - Definitions, macros, structs, enums
    41  *                       and general setup.
    42  *  nsWindowDbg.h/.cpp - Debug related code and directives.
    43  *  nsWindowGfx.h/.cpp - Graphics and painting.
    44  *
    45  */
    47 /**************************************************************
    48  **************************************************************
    49  **
    50  ** BLOCK: Includes
    51  **
    52  ** Include headers.
    53  **
    54  **************************************************************
    55  **************************************************************/
    57 #include "mozilla/MathAlgorithms.h"
    58 #include "mozilla/MiscEvents.h"
    59 #include "mozilla/MouseEvents.h"
    60 #include "mozilla/TouchEvents.h"
    62 #include "mozilla/ipc/MessageChannel.h"
    63 #include <algorithm>
    65 #include "nsWindow.h"
    67 #include <shellapi.h>
    68 #include <windows.h>
    69 #include <process.h>
    70 #include <commctrl.h>
    71 #include <unknwn.h>
    72 #include <psapi.h>
    74 #include "prlog.h"
    75 #include "prtime.h"
    76 #include "prprf.h"
    77 #include "prmem.h"
    78 #include "prenv.h"
    80 #include "mozilla/WidgetTraceEvent.h"
    81 #include "nsIAppShell.h"
    82 #include "nsISupportsPrimitives.h"
    83 #include "nsIDOMMouseEvent.h"
    84 #include "nsITheme.h"
    85 #include "nsIObserverService.h"
    86 #include "nsIScreenManager.h"
    87 #include "imgIContainer.h"
    88 #include "nsIFile.h"
    89 #include "nsIRollupListener.h"
    90 #include "nsIServiceManager.h"
    91 #include "nsIClipboard.h"
    92 #include "nsIMM32Handler.h"
    93 #include "WinMouseScrollHandler.h"
    94 #include "nsFontMetrics.h"
    95 #include "nsIFontEnumerator.h"
    96 #include "nsFont.h"
    97 #include "nsRect.h"
    98 #include "nsThreadUtils.h"
    99 #include "nsNativeCharsetUtils.h"
   100 #include "nsGkAtoms.h"
   101 #include "nsCRT.h"
   102 #include "nsAppDirectoryServiceDefs.h"
   103 #include "nsXPIDLString.h"
   104 #include "nsWidgetsCID.h"
   105 #include "nsTHashtable.h"
   106 #include "nsHashKeys.h"
   107 #include "nsString.h"
   108 #include "mozilla/Services.h"
   109 #include "nsNativeThemeWin.h"
   110 #include "nsWindowsDllInterceptor.h"
   111 #include "nsLayoutUtils.h"
   112 #include "nsView.h"
   113 #include "nsIWindowMediator.h"
   114 #include "nsIServiceManager.h"
   115 #include "nsWindowGfx.h"
   116 #include "gfxWindowsPlatform.h"
   117 #include "Layers.h"
   118 #include "nsPrintfCString.h"
   119 #include "mozilla/Preferences.h"
   120 #include "nsISound.h"
   121 #include "WinTaskbar.h"
   122 #include "WinUtils.h"
   123 #include "WidgetUtils.h"
   124 #include "nsIWidgetListener.h"
   125 #include "mozilla/dom/Touch.h"
   126 #include "mozilla/gfx/2D.h"
   127 #include "nsToolkitCompsCID.h"
   128 #include "nsIAppStartup.h"
   129 #include "mozilla/WindowsVersion.h"
   130 #include "nsThemeConstants.h"
   132 #ifdef MOZ_ENABLE_D3D9_LAYER
   133 #include "LayerManagerD3D9.h"
   134 #endif
   136 #ifdef MOZ_ENABLE_D3D10_LAYER
   137 #include "LayerManagerD3D10.h"
   138 #endif
   140 #include "nsIGfxInfo.h"
   141 #include "nsUXThemeConstants.h"
   142 #include "KeyboardLayout.h"
   143 #include "nsNativeDragTarget.h"
   144 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
   145 #include <zmouse.h>
   146 #include <richedit.h>
   148 #if defined(ACCESSIBILITY)
   150 #ifdef DEBUG
   151 #include "mozilla/a11y/Logging.h"
   152 #endif
   154 #include "oleidl.h"
   155 #include <winuser.h>
   156 #include "nsAccessibilityService.h"
   157 #include "mozilla/a11y/DocAccessible.h"
   158 #include "mozilla/a11y/Platform.h"
   159 #if !defined(WINABLEAPI)
   160 #include <winable.h>
   161 #endif // !defined(WINABLEAPI)
   162 #endif // defined(ACCESSIBILITY)
   164 #include "nsIWinTaskbar.h"
   165 #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
   167 #include "nsWindowDefs.h"
   169 #include "nsCrashOnException.h"
   170 #include "nsIXULRuntime.h"
   172 #include "nsIContent.h"
   174 #include "mozilla/HangMonitor.h"
   175 #include "WinIMEHandler.h"
   177 #include "npapi.h"
   179 #if !defined(SM_CONVERTIBLESLATEMODE)
   180 #define SM_CONVERTIBLESLATEMODE 0x2003
   181 #endif
   183 using namespace mozilla;
   184 using namespace mozilla::dom;
   185 using namespace mozilla::layers;
   186 using namespace mozilla::widget;
   188 /**************************************************************
   189  **************************************************************
   190  **
   191  ** BLOCK: Variables
   192  **
   193  ** nsWindow Class static initializations and global variables. 
   194  **
   195  **************************************************************
   196  **************************************************************/
   198 /**************************************************************
   199  *
   200  * SECTION: nsWindow statics
   201  *
   202  **************************************************************/
   204 bool            nsWindow::sDropShadowEnabled      = true;
   205 uint32_t        nsWindow::sInstanceCount          = 0;
   206 bool            nsWindow::sSwitchKeyboardLayout   = false;
   207 BOOL            nsWindow::sIsOleInitialized       = FALSE;
   208 HCURSOR         nsWindow::sHCursor                = nullptr;
   209 imgIContainer*  nsWindow::sCursorImgContainer     = nullptr;
   210 nsWindow*       nsWindow::sCurrentWindow          = nullptr;
   211 bool            nsWindow::sJustGotDeactivate      = false;
   212 bool            nsWindow::sJustGotActivate        = false;
   213 bool            nsWindow::sIsInMouseCapture       = false;
   215 // imported in nsWidgetFactory.cpp
   216 TriStateBool    nsWindow::sCanQuit                = TRI_UNKNOWN;
   218 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
   219 // hook methods whether they should be processing the hook
   220 // messages.
   221 HHOOK           nsWindow::sMsgFilterHook          = nullptr;
   222 HHOOK           nsWindow::sCallProcHook           = nullptr;
   223 HHOOK           nsWindow::sCallMouseHook          = nullptr;
   224 bool            nsWindow::sProcessHook            = false;
   225 UINT            nsWindow::sRollupMsgId            = 0;
   226 HWND            nsWindow::sRollupMsgWnd           = nullptr;
   227 UINT            nsWindow::sHookTimerId            = 0;
   229 // Mouse Clicks - static variable definitions for figuring
   230 // out 1 - 3 Clicks.
   231 POINT           nsWindow::sLastMousePoint         = {0};
   232 POINT           nsWindow::sLastMouseMovePoint     = {0};
   233 LONG            nsWindow::sLastMouseDownTime      = 0L;
   234 LONG            nsWindow::sLastClickCount         = 0L;
   235 BYTE            nsWindow::sLastMouseButton        = 0;
   237 // Trim heap on minimize. (initialized, but still true.)
   238 int             nsWindow::sTrimOnMinimize         = 2;
   240 // Default value for general window class (used when the pref is the empty string).
   241 const char*     nsWindow::sDefaultMainWindowClass = kClassNameGeneral;
   243 // If we're using D3D9, this will not be allowed during initial 5 seconds.
   244 bool            nsWindow::sAllowD3D9              = false;
   246 TriStateBool nsWindow::sHasBogusPopupsDropShadowOnMultiMonitor = TRI_UNKNOWN;
   248 // Used in OOPP plugin focus processing.
   249 const wchar_t* kOOPPPluginFocusEventId   = L"OOPP Plugin Focus Widget Event";
   250 uint32_t        nsWindow::sOOPPPluginFocusEvent   =
   251                   RegisterWindowMessageW(kOOPPPluginFocusEventId);
   253 /**************************************************************
   254  *
   255  * SECTION: globals variables
   256  *
   257  **************************************************************/
   259 static const char *sScreenManagerContractID       = "@mozilla.org/gfx/screenmanager;1";
   261 #ifdef PR_LOGGING
   262 extern PRLogModuleInfo* gWindowsLog;
   263 #endif
   265 // Global used in Show window enumerations.
   266 static bool     gWindowsVisible                   = false;
   268 // True if we have sent a notification that we are suspending/sleeping.
   269 static bool     gIsSleepMode                      = false;
   271 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
   273 // General purpose user32.dll hook object
   274 static WindowsDllInterceptor sUser32Intercept;
   276 // 2 pixel offset for eTransparencyBorderlessGlass which equals the size of
   277 // the default window border Windows paints. Glass will be extended inward
   278 // this distance to remove the border.
   279 static const int32_t kGlassMarginAdjustment = 2;
   281 // When the client area is extended out into the default window frame area,
   282 // this is the minimum amount of space along the edge of resizable windows
   283 // we will always display a resize cursor in, regardless of the underlying
   284 // content.
   285 static const int32_t kResizableBorderMinSize = 3;
   287 // Cached pointer events enabler value, True if pointer events are enabled.
   288 static bool gIsPointerEventsEnabled = false;
   290 // We should never really try to accelerate windows bigger than this. In some
   291 // cases this might lead to no D3D9 acceleration where we could have had it
   292 // but D3D9 does not reliably report when it supports bigger windows. 8192
   293 // is as safe as we can get, we know at least D3D10 hardware always supports
   294 // this, other hardware we expect to report correctly in D3D9.
   295 #define MAX_ACCELERATED_DIMENSION 8192
   297 // On window open (as well as after), Windows has an unfortunate habit of
   298 // sending rather a lot of WM_NCHITTEST messages. Because we have to do point
   299 // to DOM target conversions for these, we cache responses for a given
   300 // coordinate this many milliseconds:
   301 #define HITTEST_CACHE_LIFETIME_MS 50
   304 /**************************************************************
   305  **************************************************************
   306  **
   307  ** BLOCK: nsIWidget impl.
   308  **
   309  ** nsIWidget interface implementation, broken down into
   310  ** sections.
   311  **
   312  **************************************************************
   313  **************************************************************/
   315 /**************************************************************
   316  *
   317  * SECTION: nsWindow construction and destruction
   318  *
   319  **************************************************************/
   321 nsWindow::nsWindow() : nsWindowBase()
   322 {
   323   mIconSmall            = nullptr;
   324   mIconBig              = nullptr;
   325   mWnd                  = nullptr;
   326   mPaintDC              = nullptr;
   327   mCompositeDC          = nullptr;
   328   mPrevWndProc          = nullptr;
   329   mNativeDragTarget     = nullptr;
   330   mInDtor               = false;
   331   mIsVisible            = false;
   332   mIsTopWidgetWindow    = false;
   333   mUnicodeWidget        = true;
   334   mDisplayPanFeedback   = false;
   335   mTouchWindow          = false;
   336   mCustomNonClient      = false;
   337   mHideChrome           = false;
   338   mFullscreenMode       = false;
   339   mMousePresent         = false;
   340   mDestroyCalled        = false;
   341   mHasTaskbarIconBeenCreated = false;
   342   mMouseTransparent     = false;
   343   mPickerDisplayCount   = 0;
   344   mWindowType           = eWindowType_child;
   345   mBorderStyle          = eBorderStyle_default;
   346   mOldSizeMode          = nsSizeMode_Normal;
   347   mLastSizeMode         = nsSizeMode_Normal;
   348   mLastSize.width       = 0;
   349   mLastSize.height      = 0;
   350   mOldStyle             = 0;
   351   mOldExStyle           = 0;
   352   mPainting             = 0;
   353   mLastKeyboardLayout   = 0;
   354   mBlurSuppressLevel    = 0;
   355   mLastPaintEndTime     = TimeStamp::Now();
   356   mCachedHitTestPoint.x = 0;
   357   mCachedHitTestPoint.y = 0;
   358   mCachedHitTestTime    = TimeStamp::Now();
   359   mCachedHitTestResult  = 0;
   360 #ifdef MOZ_XUL
   361   mTransparentSurface   = nullptr;
   362   mMemoryDC             = nullptr;
   363   mTransparencyMode     = eTransparencyOpaque;
   364   memset(&mGlassMargins, 0, sizeof mGlassMargins);
   365 #endif
   366   DWORD background      = ::GetSysColor(COLOR_BTNFACE);
   367   mBrush                = ::CreateSolidBrush(NSRGB_2_COLOREF(background));
   369   mTaskbarPreview = nullptr;
   371   // Global initialization
   372   if (!sInstanceCount) {
   373     // Global app registration id for Win7 and up. See
   374     // WinTaskbar.cpp for details.
   375     mozilla::widget::WinTaskbar::RegisterAppUserModelID();
   376     KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0));
   377     IMEHandler::Initialize();
   378     if (SUCCEEDED(::OleInitialize(nullptr))) {
   379       sIsOleInitialized = TRUE;
   380     }
   381     NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
   382     MouseScrollHandler::Initialize();
   383     // Init titlebar button info for custom frames.
   384     nsUXThemeData::InitTitlebarInfo();
   385     // Init theme data
   386     nsUXThemeData::UpdateNativeThemeInfo();
   387     RedirectedKeyDownMessageManager::Forget();
   389     Preferences::AddBoolVarCache(&gIsPointerEventsEnabled,
   390                                  "dom.w3c_pointer_events.enabled",
   391                                  gIsPointerEventsEnabled);
   392   } // !sInstanceCount
   394   mIdleService = nullptr;
   396   sInstanceCount++;
   397 }
   399 nsWindow::~nsWindow()
   400 {
   401   mInDtor = true;
   403   // If the widget was released without calling Destroy() then the native window still
   404   // exists, and we need to destroy it. This will also result in a call to OnDestroy.
   405   //
   406   // XXX How could this happen???
   407   if (nullptr != mWnd)
   408     Destroy();
   410   // Free app icon resources.  This must happen after `OnDestroy` (see bug 708033).
   411   if (mIconSmall)
   412     ::DestroyIcon(mIconSmall);
   414   if (mIconBig)
   415     ::DestroyIcon(mIconBig);
   417   sInstanceCount--;
   419   // Global shutdown
   420   if (sInstanceCount == 0) {
   421     IMEHandler::Terminate();
   422     NS_IF_RELEASE(sCursorImgContainer);
   423     if (sIsOleInitialized) {
   424       ::OleFlushClipboard();
   425       ::OleUninitialize();
   426       sIsOleInitialized = FALSE;
   427     }
   428   }
   430   NS_IF_RELEASE(mNativeDragTarget);
   431 }
   433 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
   435 /**************************************************************
   436  *
   437  * SECTION: nsIWidget::Create, nsIWidget::Destroy
   438  *
   439  * Creating and destroying windows for this widget.
   440  *
   441  **************************************************************/
   443 // Allow Derived classes to modify the height that is passed
   444 // when the window is created or resized.
   445 int32_t nsWindow::GetHeight(int32_t aProposedHeight)
   446 {
   447   return aProposedHeight;
   448 }
   450 // Create the proper widget
   451 nsresult
   452 nsWindow::Create(nsIWidget *aParent,
   453                  nsNativeWidget aNativeParent,
   454                  const nsIntRect &aRect,
   455                  nsDeviceContext *aContext,
   456                  nsWidgetInitData *aInitData)
   457 {
   458   nsWidgetInitData defaultInitData;
   459   if (!aInitData)
   460     aInitData = &defaultInitData;
   462   mUnicodeWidget = aInitData->mUnicode;
   464   nsIWidget *baseParent = aInitData->mWindowType == eWindowType_dialog ||
   465                           aInitData->mWindowType == eWindowType_toplevel ||
   466                           aInitData->mWindowType == eWindowType_invisible ?
   467                           nullptr : aParent;
   469   mIsTopWidgetWindow = (nullptr == baseParent);
   470   mBounds = aRect;
   472   // Ensure that the toolkit is created.
   473   nsToolkit::GetToolkit();
   475   BaseCreate(baseParent, aRect, aContext, aInitData);
   477   HWND parent;
   478   if (aParent) { // has a nsIWidget parent
   479     parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : nullptr;
   480     mParent = aParent;
   481   } else { // has a nsNative parent
   482     parent = (HWND)aNativeParent;
   483     mParent = aNativeParent ?
   484       WinUtils::GetNSWindowPtr((HWND)aNativeParent) : nullptr;
   485   }
   487   mIsRTL = aInitData->mRTL;
   489   DWORD style = WindowStyle();
   490   DWORD extendedStyle = WindowExStyle();
   492   if (mWindowType == eWindowType_popup) {
   493     if (!aParent) {
   494       parent = nullptr;
   495     }
   497     if (IsVistaOrLater() && !IsWin8OrLater() &&
   498         HasBogusPopupsDropShadowOnMultiMonitor()) {
   499       extendedStyle |= WS_EX_COMPOSITED;
   500     }
   502     if (aInitData->mMouseTransparent) {
   503       // This flag makes the window transparent to mouse events
   504       mMouseTransparent = true;
   505       extendedStyle |= WS_EX_TRANSPARENT;
   506     }
   507   } else if (mWindowType == eWindowType_invisible) {
   508     // Make sure CreateWindowEx succeeds at creating a toplevel window
   509     style &= ~0x40000000; // WS_CHILDWINDOW
   510   } else {
   511     // See if the caller wants to explictly set clip children and clip siblings
   512     if (aInitData->clipChildren) {
   513       style |= WS_CLIPCHILDREN;
   514     } else {
   515       style &= ~WS_CLIPCHILDREN;
   516     }
   517     if (aInitData->clipSiblings) {
   518       style |= WS_CLIPSIBLINGS;
   519     }
   520   }
   522   nsAutoString className;
   523   if (aInitData->mDropShadow) {
   524     GetWindowPopupClass(className);
   525   } else {
   526     GetWindowClass(className);
   527   }
   528   // Plugins are created in the disabled state so that they can't
   529   // steal focus away from our main window.  This is especially
   530   // important if the plugin has loaded in a background tab.
   531   if(aInitData->mWindowType == eWindowType_plugin) {
   532     style |= WS_DISABLED;
   533   }
   534   mWnd = ::CreateWindowExW(extendedStyle,
   535                            className.get(),
   536                            L"",
   537                            style,
   538                            aRect.x,
   539                            aRect.y,
   540                            aRect.width,
   541                            GetHeight(aRect.height),
   542                            parent,
   543                            nullptr,
   544                            nsToolkit::mDllInstance,
   545                            nullptr);
   547   if (!mWnd) {
   548     NS_WARNING("nsWindow CreateWindowEx failed.");
   549     return NS_ERROR_FAILURE;
   550   }
   552   if (mIsRTL && WinUtils::dwmSetWindowAttributePtr) {
   553     DWORD dwAttribute = TRUE;    
   554     WinUtils::dwmSetWindowAttributePtr(mWnd, DWMWA_NONCLIENT_RTL_LAYOUT, &dwAttribute, sizeof dwAttribute);
   555   }
   557   if (mWindowType != eWindowType_plugin &&
   558       mWindowType != eWindowType_invisible &&
   559       MouseScrollHandler::Device::IsFakeScrollableWindowNeeded()) {
   560     // Ugly Thinkpad Driver Hack (Bugs 507222 and 594977)
   561     //
   562     // We create two zero-sized windows as descendants of the top-level window,
   563     // like so:
   564     //
   565     //   Top-level window (MozillaWindowClass)
   566     //     FAKETRACKPOINTSCROLLCONTAINER (MozillaWindowClass)
   567     //       FAKETRACKPOINTSCROLLABLE (MozillaWindowClass)
   568     //
   569     // We need to have the middle window, otherwise the Trackpoint driver
   570     // will fail to deliver scroll messages.  WM_MOUSEWHEEL messages are
   571     // sent to the FAKETRACKPOINTSCROLLABLE, which then propagate up the
   572     // window hierarchy until they are handled by nsWindow::WindowProc.
   573     // WM_HSCROLL messages are also sent to the FAKETRACKPOINTSCROLLABLE,
   574     // but these do not propagate automatically, so we have the window
   575     // procedure pretend that they were dispatched to the top-level window
   576     // instead.
   577     //
   578     // The FAKETRACKPOINTSCROLLABLE needs to have the specific window styles it
   579     // is given below so that it catches the Trackpoint driver's heuristics.
   580     HWND scrollContainerWnd = ::CreateWindowW
   581       (className.get(), L"FAKETRACKPOINTSCROLLCONTAINER",
   582        WS_CHILD | WS_VISIBLE,
   583        0, 0, 0, 0, mWnd, nullptr, nsToolkit::mDllInstance, nullptr);
   584     HWND scrollableWnd = ::CreateWindowW
   585       (className.get(), L"FAKETRACKPOINTSCROLLABLE",
   586        WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | 0x30,
   587        0, 0, 0, 0, scrollContainerWnd, nullptr, nsToolkit::mDllInstance,
   588        nullptr);
   590     // Give the FAKETRACKPOINTSCROLLABLE window a specific ID so that
   591     // WindowProcInternal can distinguish it from the top-level window
   592     // easily.
   593     ::SetWindowLongPtrW(scrollableWnd, GWLP_ID, eFakeTrackPointScrollableID);
   595     // Make FAKETRACKPOINTSCROLLABLE use nsWindow::WindowProc, and store the
   596     // old window procedure in its "user data".
   597     WNDPROC oldWndProc;
   598     if (mUnicodeWidget)
   599       oldWndProc = (WNDPROC)::SetWindowLongPtrW(scrollableWnd, GWLP_WNDPROC,
   600                                                 (LONG_PTR)nsWindow::WindowProc);
   601     else
   602       oldWndProc = (WNDPROC)::SetWindowLongPtrA(scrollableWnd, GWLP_WNDPROC,
   603                                                 (LONG_PTR)nsWindow::WindowProc);
   604     ::SetWindowLongPtrW(scrollableWnd, GWLP_USERDATA, (LONG_PTR)oldWndProc);
   605   }
   607   SubclassWindow(TRUE);
   609   IMEHandler::InitInputContext(this, mInputContext);
   611   // If the internal variable set by the config.trim_on_minimize pref has not
   612   // been initialized, and if this is the hidden window (conveniently created
   613   // before any visible windows, and after the profile has been initialized),
   614   // do some initialization work.
   615   if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
   616     // Our internal trim prevention logic is effective on 2K/XP at maintaining
   617     // the working set when windows are minimized, but on Vista and up it has
   618     // little to no effect. Since this feature has been the source of numerous
   619     // bugs over the years, disable it (sTrimOnMinimize=1) on Vista and up.
   620     sTrimOnMinimize =
   621       Preferences::GetBool("config.trim_on_minimize",
   622         IsVistaOrLater() ? 1 : 0);
   623     sSwitchKeyboardLayout =
   624       Preferences::GetBool("intl.keyboard.per_window_layout", false);
   625   }
   627   // Query for command button metric data for rendering the titlebar. We
   628   // only do this once on the first window.
   629   if (mWindowType == eWindowType_toplevel &&
   630       (!nsUXThemeData::sTitlebarInfoPopulatedThemed ||
   631        !nsUXThemeData::sTitlebarInfoPopulatedAero)) {
   632     nsUXThemeData::UpdateTitlebarInfo(mWnd);
   633   }
   634   return NS_OK;
   635 }
   637 // Close this nsWindow
   638 NS_METHOD nsWindow::Destroy()
   639 {
   640   // WM_DESTROY has already fired, avoid calling it twice
   641   if (mOnDestroyCalled)
   642     return NS_OK;
   644   // Don't destroy windows that have file pickers open, we'll tear these down
   645   // later once the picker is closed.
   646   mDestroyCalled = true;
   647   if (mPickerDisplayCount)
   648     return NS_OK;
   650   // During the destruction of all of our children, make sure we don't get deleted.
   651   nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
   653   /**
   654    * On windows the LayerManagerOGL destructor wants the widget to be around for
   655    * cleanup. It also would like to have the HWND intact, so we nullptr it here.
   656    */
   657   if (mLayerManager) {
   658     mLayerManager->Destroy();
   659   }
   660   mLayerManager = nullptr;
   662   /* We should clear our cached resources now and not wait for the GC to
   663    * delete the nsWindow. */
   664   ClearCachedResources();
   666   // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
   667   // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
   668   // from it. The function also destroys the window's menu, flushes the thread message queue,
   669   // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
   670   // the window is at the top of the viewer chain).
   671   //
   672   // If the specified window is a parent or owner window, DestroyWindow automatically destroys
   673   // the associated child or owned windows when it destroys the parent or owner window. The
   674   // function first destroys child or owned windows, and then it destroys the parent or owner
   675   // window.
   676   VERIFY(::DestroyWindow(mWnd));
   678   // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
   679   // didn't get called, call it now.
   680   if (false == mOnDestroyCalled) {
   681     MSGResult msgResult;
   682     mWindowHook.Notify(mWnd, WM_DESTROY, 0, 0, msgResult);
   683     OnDestroy();
   684   }
   686   return NS_OK;
   687 }
   689 /**************************************************************
   690  *
   691  * SECTION: Window class utilities
   692  *
   693  * Utilities for calculating the proper window class name for
   694  * Create window.
   695  *
   696  **************************************************************/
   698 void nsWindow::RegisterWindowClass(const nsString& aClassName, UINT aExtraStyle,
   699                                    LPWSTR aIconID)
   700 {
   701   WNDCLASSW wc;
   702   if (::GetClassInfoW(nsToolkit::mDllInstance, aClassName.get(), &wc)) {
   703     // already registered
   704     return;
   705   }
   707   wc.style         = CS_DBLCLKS | aExtraStyle;
   708   wc.lpfnWndProc   = ::DefWindowProcW;
   709   wc.cbClsExtra    = 0;
   710   wc.cbWndExtra    = 0;
   711   wc.hInstance     = nsToolkit::mDllInstance;
   712   wc.hIcon         = aIconID ? ::LoadIconW(::GetModuleHandleW(nullptr), aIconID) : nullptr;
   713   wc.hCursor       = nullptr;
   714   wc.hbrBackground = mBrush;
   715   wc.lpszMenuName  = nullptr;
   716   wc.lpszClassName = aClassName.get();
   718   if (!::RegisterClassW(&wc)) {
   719     // For older versions of Win32 (i.e., not XP), the registration may
   720     // fail with aExtraStyle, so we have to re-register without it.
   721     wc.style = CS_DBLCLKS;
   722     ::RegisterClassW(&wc);
   723   }
   724 }
   726 static LPWSTR const gStockApplicationIcon = MAKEINTRESOURCEW(32512);
   728 // Return the proper window class for everything except popups.
   729 void nsWindow::GetWindowClass(nsString& aWindowClass)
   730 {
   731   switch (mWindowType) {
   732   case eWindowType_invisible:
   733     aWindowClass.AssignLiteral(kClassNameHidden);
   734     RegisterWindowClass(aWindowClass, 0, gStockApplicationIcon);
   735     break;
   736   case eWindowType_dialog:
   737     aWindowClass.AssignLiteral(kClassNameDialog);
   738     RegisterWindowClass(aWindowClass, 0, 0);
   739     break;
   740   default:
   741     GetMainWindowClass(aWindowClass);
   742     RegisterWindowClass(aWindowClass, 0, gStockApplicationIcon);
   743     break;
   744   }
   745 }
   747 // Return the proper popup window class
   748 void nsWindow::GetWindowPopupClass(nsString& aWindowClass)
   749 {
   750   aWindowClass.AssignLiteral(kClassNameDropShadow);
   751   RegisterWindowClass(aWindowClass, CS_XP_DROPSHADOW, gStockApplicationIcon);
   752 }
   754 /**************************************************************
   755  *
   756  * SECTION: Window styles utilities
   757  *
   758  * Return the proper windows styles and extended styles.
   759  *
   760  **************************************************************/
   762 // Return nsWindow styles
   763 DWORD nsWindow::WindowStyle()
   764 {
   765   DWORD style;
   767   switch (mWindowType) {
   768     case eWindowType_plugin:
   769     case eWindowType_child:
   770       style = WS_OVERLAPPED;
   771       break;
   773     case eWindowType_dialog:
   774       style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK |
   775               DS_MODALFRAME | WS_CLIPCHILDREN;
   776       if (mBorderStyle != eBorderStyle_default)
   777         style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
   778       break;
   780     case eWindowType_popup:
   781       style = WS_POPUP;
   782       if (!HasGlass()) {
   783         style |= WS_OVERLAPPED;
   784       }
   785       break;
   787     default:
   788       NS_ERROR("unknown border style");
   789       // fall through
   791     case eWindowType_toplevel:
   792     case eWindowType_invisible:
   793       style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU |
   794               WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
   795       break;
   796   }
   798   if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) {
   799     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border))
   800       style &= ~WS_BORDER;
   802     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) {
   803       style &= ~WS_DLGFRAME;
   804       style |= WS_POPUP;
   805       style &= ~WS_CHILD;
   806     }
   808     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close))
   809       style &= ~0;
   810     // XXX The close box can only be removed by changing the window class,
   811     // as far as I know   --- roc+moz@cs.cmu.edu
   813     if (mBorderStyle == eBorderStyle_none ||
   814       !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
   815       style &= ~WS_SYSMENU;
   816     // Looks like getting rid of the system menu also does away with the
   817     // close box. So, we only get rid of the system menu if you want neither it
   818     // nor the close box. How does the Windows "Dialog" window class get just
   819     // closebox and no sysmenu? Who knows.
   821     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh))
   822       style &= ~WS_THICKFRAME;
   824     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize))
   825       style &= ~WS_MINIMIZEBOX;
   827     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize))
   828       style &= ~WS_MAXIMIZEBOX;
   830     if (IsPopupWithTitleBar()) {
   831       style |= WS_CAPTION;
   832       if (mBorderStyle & eBorderStyle_close) {
   833         style |= WS_SYSMENU;
   834       }
   835     }
   836   }
   838   VERIFY_WINDOW_STYLE(style);
   839   return style;
   840 }
   842 // Return nsWindow extended styles
   843 DWORD nsWindow::WindowExStyle()
   844 {
   845   switch (mWindowType)
   846   {
   847     case eWindowType_plugin:
   848     case eWindowType_child:
   849       return 0;
   851     case eWindowType_dialog:
   852       return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
   854     case eWindowType_popup:
   855     {
   856       DWORD extendedStyle = WS_EX_TOOLWINDOW;
   857       if (mPopupLevel == ePopupLevelTop)
   858         extendedStyle |= WS_EX_TOPMOST;
   859       return extendedStyle;
   860     }
   861     default:
   862       NS_ERROR("unknown border style");
   863       // fall through
   865     case eWindowType_toplevel:
   866     case eWindowType_invisible:
   867       return WS_EX_WINDOWEDGE;
   868   }
   869 }
   871 /**************************************************************
   872  *
   873  * SECTION: Window subclassing utilities
   874  *
   875  * Set or clear window subclasses on native windows. Used in
   876  * Create and Destroy.
   877  *
   878  **************************************************************/
   880 // Subclass (or remove the subclass from) this component's nsWindow
   881 void nsWindow::SubclassWindow(BOOL bState)
   882 {
   883   if (bState) {
   884     if (!mWnd || !IsWindow(mWnd)) {
   885       NS_ERROR("Invalid window handle");
   886     }
   888     if (mUnicodeWidget) {
   889       mPrevWndProc =
   890         reinterpret_cast<WNDPROC>(
   891           SetWindowLongPtrW(mWnd,
   892                             GWLP_WNDPROC,
   893                             reinterpret_cast<LONG_PTR>(nsWindow::WindowProc)));
   894     } else {
   895       mPrevWndProc =
   896         reinterpret_cast<WNDPROC>(
   897           SetWindowLongPtrA(mWnd,
   898                             GWLP_WNDPROC,
   899                             reinterpret_cast<LONG_PTR>(nsWindow::WindowProc)));
   900     }
   901     NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
   902     // connect the this pointer to the nsWindow handle
   903     WinUtils::SetNSWindowBasePtr(mWnd, this);
   904   } else {
   905     if (IsWindow(mWnd)) {
   906       if (mUnicodeWidget) {
   907         SetWindowLongPtrW(mWnd,
   908                           GWLP_WNDPROC,
   909                           reinterpret_cast<LONG_PTR>(mPrevWndProc));
   910       } else {
   911         SetWindowLongPtrA(mWnd,
   912                           GWLP_WNDPROC,
   913                           reinterpret_cast<LONG_PTR>(mPrevWndProc));
   914       }
   915     }
   916     WinUtils::SetNSWindowBasePtr(mWnd, nullptr);
   917     mPrevWndProc = nullptr;
   918   }
   919 }
   921 /**************************************************************
   922  *
   923  * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
   924  *
   925  * Set or clear the parent widgets using window properties, and
   926  * handles calculating native parent handles.
   927  *
   928  **************************************************************/
   930 // Get and set parent widgets
   931 NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent)
   932 {
   933   mParent = aNewParent;
   935   nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
   936   nsIWidget* parent = GetParent();
   937   if (parent) {
   938     parent->RemoveChild(this);
   939   }
   940   if (aNewParent) {
   941     ReparentNativeWidget(aNewParent);
   942     aNewParent->AddChild(this);
   943     return NS_OK;
   944   }
   945   if (mWnd) {
   946     // If we have no parent, SetParent should return the desktop.
   947     VERIFY(::SetParent(mWnd, nullptr));
   948   }
   949   return NS_OK;
   950 }
   952 NS_IMETHODIMP
   953 nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
   954 {
   955   NS_PRECONDITION(aNewParent, "");
   957   mParent = aNewParent;
   958   if (mWindowType == eWindowType_popup) {
   959     return NS_OK;
   960   }
   961   HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
   962   NS_ASSERTION(newParent, "Parent widget has a null native window handle");
   963   if (newParent && mWnd) {
   964     ::SetParent(mWnd, newParent);
   965   }
   966   return NS_OK;
   967 }
   969 nsIWidget* nsWindow::GetParent(void)
   970 {
   971   return GetParentWindow(false);
   972 }
   974 float nsWindow::GetDPI()
   975 {
   976   HDC dc = ::GetDC(mWnd);
   977   if (!dc)
   978     return 96.0f;
   980   double heightInches = ::GetDeviceCaps(dc, VERTSIZE)/MM_PER_INCH_FLOAT;
   981   int heightPx = ::GetDeviceCaps(dc, VERTRES);
   982   ::ReleaseDC(mWnd, dc);
   983   if (heightInches < 0.25) {
   984     // Something's broken
   985     return 96.0f;
   986   }
   987   return float(heightPx/heightInches);
   988 }
   990 double nsWindow::GetDefaultScaleInternal()
   991 {
   992   return WinUtils::LogToPhysFactor();
   993 }
   995 nsWindow*
   996 nsWindow::GetParentWindow(bool aIncludeOwner)
   997 {
   998   return static_cast<nsWindow*>(GetParentWindowBase(aIncludeOwner));
   999 }
  1001 nsWindowBase*
  1002 nsWindow::GetParentWindowBase(bool aIncludeOwner)
  1004   if (mIsTopWidgetWindow) {
  1005     // Must use a flag instead of mWindowType to tell if the window is the
  1006     // owned by the topmost widget, because a child window can be embedded inside
  1007     // a HWND which is not associated with a nsIWidget.
  1008     return nullptr;
  1011   // If this widget has already been destroyed, pretend we have no parent.
  1012   // This corresponds to code in Destroy which removes the destroyed
  1013   // widget from its parent's child list.
  1014   if (mInDtor || mOnDestroyCalled)
  1015     return nullptr;
  1018   // aIncludeOwner set to true implies walking the parent chain to retrieve the
  1019   // root owner. aIncludeOwner set to false implies the search will stop at the
  1020   // true parent (default).
  1021   nsWindow* widget = nullptr;
  1022   if (mWnd) {
  1023     HWND parent = nullptr;
  1024     if (aIncludeOwner)
  1025       parent = ::GetParent(mWnd);
  1026     else
  1027       parent = ::GetAncestor(mWnd, GA_PARENT);
  1029     if (parent) {
  1030       widget = WinUtils::GetNSWindowPtr(parent);
  1031       if (widget) {
  1032         // If the widget is in the process of being destroyed then
  1033         // do NOT return it
  1034         if (widget->mInDtor) {
  1035           widget = nullptr;
  1041   return static_cast<nsWindowBase*>(widget);
  1044 BOOL CALLBACK
  1045 nsWindow::EnumAllChildWindProc(HWND aWnd, LPARAM aParam)
  1047   nsWindow *wnd = WinUtils::GetNSWindowPtr(aWnd);
  1048   if (wnd) {
  1049     ((nsWindow::WindowEnumCallback*)aParam)(wnd);
  1051   return TRUE;
  1054 BOOL CALLBACK
  1055 nsWindow::EnumAllThreadWindowProc(HWND aWnd, LPARAM aParam)
  1057   nsWindow *wnd = WinUtils::GetNSWindowPtr(aWnd);
  1058   if (wnd) {
  1059     ((nsWindow::WindowEnumCallback*)aParam)(wnd);
  1061   EnumChildWindows(aWnd, EnumAllChildWindProc, aParam);
  1062   return TRUE;
  1065 void
  1066 nsWindow::EnumAllWindows(WindowEnumCallback aCallback)
  1068   EnumThreadWindows(GetCurrentThreadId(),
  1069                     EnumAllThreadWindowProc,
  1070                     (LPARAM)aCallback);
  1073 /**************************************************************
  1075  * SECTION: nsIWidget::Show
  1077  * Hide or show this component.
  1079  **************************************************************/
  1081 NS_METHOD nsWindow::Show(bool bState)
  1083   if (mWindowType == eWindowType_popup) {
  1084     // See bug 603793. When we try to draw D3D9/10 windows with a drop shadow
  1085     // without the DWM on a secondary monitor, windows fails to composite
  1086     // our windows correctly. We therefor switch off the drop shadow for
  1087     // pop-up windows when the DWM is disabled and two monitors are
  1088     // connected.
  1089     if (HasBogusPopupsDropShadowOnMultiMonitor() &&
  1090         WinUtils::GetMonitorCount() > 1 &&
  1091         !nsUXThemeData::CheckForCompositor())
  1093       if (sDropShadowEnabled) {
  1094         ::SetClassLongA(mWnd, GCL_STYLE, 0);
  1095         sDropShadowEnabled = false;
  1097     } else {
  1098       if (!sDropShadowEnabled) {
  1099         ::SetClassLongA(mWnd, GCL_STYLE, CS_DROPSHADOW);
  1100         sDropShadowEnabled = true;
  1104     // WS_EX_COMPOSITED conflicts with the WS_EX_LAYERED style and causes
  1105     // some popup menus to become invisible.
  1106     LONG_PTR exStyle = ::GetWindowLongPtrW(mWnd, GWL_EXSTYLE);
  1107     if (exStyle & WS_EX_LAYERED) {
  1108       ::SetWindowLongPtrW(mWnd, GWL_EXSTYLE, exStyle & ~WS_EX_COMPOSITED);
  1112   bool syncInvalidate = false;
  1114   bool wasVisible = mIsVisible;
  1115   // Set the status now so that anyone asking during ShowWindow or
  1116   // SetWindowPos would get the correct answer.
  1117   mIsVisible = bState;
  1119   // We may have cached an out of date visible state. This can happen
  1120   // when session restore sets the full screen mode.
  1121   if (mIsVisible)
  1122     mOldStyle |= WS_VISIBLE;
  1123   else
  1124     mOldStyle &= ~WS_VISIBLE;
  1126   if (!mIsVisible && wasVisible) {
  1127       ClearCachedResources();
  1130   if (mWnd) {
  1131     if (bState) {
  1132       if (!wasVisible && mWindowType == eWindowType_toplevel) {
  1133         // speed up the initial paint after show for
  1134         // top level windows:
  1135         syncInvalidate = true;
  1136         switch (mSizeMode) {
  1137           case nsSizeMode_Fullscreen:
  1138             ::ShowWindow(mWnd, SW_SHOW);
  1139             break;
  1140           case nsSizeMode_Maximized :
  1141             ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
  1142             break;
  1143           case nsSizeMode_Minimized :
  1144             ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
  1145             break;
  1146           default:
  1147             if (CanTakeFocus()) {
  1148               ::ShowWindow(mWnd, SW_SHOWNORMAL);
  1149             } else {
  1150               // Place the window behind the foreground window
  1151               // (as long as it is not topmost)
  1152               HWND wndAfter = ::GetForegroundWindow();
  1153               if (!wndAfter)
  1154                 wndAfter = HWND_BOTTOM;
  1155               else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)
  1156                 wndAfter = HWND_TOP;
  1157               ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | 
  1158                              SWP_NOMOVE | SWP_NOACTIVATE);
  1159               GetAttention(2);
  1161             break;
  1163       } else {
  1164         DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
  1165         if (wasVisible)
  1166           flags |= SWP_NOZORDER;
  1168         if (mWindowType == eWindowType_popup) {
  1169           // ensure popups are the topmost of the TOPMOST
  1170           // layer. Remember not to set the SWP_NOZORDER
  1171           // flag as that might allow the taskbar to overlap
  1172           // the popup.
  1173           flags |= SWP_NOACTIVATE;
  1174           HWND owner = ::GetWindow(mWnd, GW_OWNER);
  1175           ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
  1176         } else {
  1177           if (mWindowType == eWindowType_dialog && !CanTakeFocus())
  1178             flags |= SWP_NOACTIVATE;
  1180           ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
  1184       if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) {
  1185         // when a toplevel window or dialog is shown, initialize the UI state
  1186         ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
  1188     } else {
  1189       // Clear contents to avoid ghosting of old content if we display
  1190       // this window again.
  1191       if (wasVisible && mTransparencyMode == eTransparencyTransparent) {
  1192         ClearTranslucentWindow();
  1194       if (mWindowType != eWindowType_dialog) {
  1195         ::ShowWindow(mWnd, SW_HIDE);
  1196       } else {
  1197         ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
  1198                        SWP_NOZORDER | SWP_NOACTIVATE);
  1203 #ifdef MOZ_XUL
  1204   if (!wasVisible && bState) {
  1205     Invalidate();
  1206     if (syncInvalidate && !mInDtor && !mOnDestroyCalled) {
  1207       ::UpdateWindow(mWnd);
  1210 #endif
  1212   return NS_OK;
  1215 /**************************************************************
  1217  * SECTION: nsIWidget::IsVisible
  1219  * Returns the visibility state.
  1221  **************************************************************/
  1223 // Return true if the whether the component is visible, false otherwise
  1224 bool nsWindow::IsVisible() const
  1226   return mIsVisible;
  1229 /**************************************************************
  1231  * SECTION: Window clipping utilities
  1233  * Used in Size and Move operations for setting the proper
  1234  * window clipping regions for window transparency.
  1236  **************************************************************/
  1238 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
  1239 // transparency. These routines are called on size and move operations.
  1240 void nsWindow::ClearThemeRegion()
  1242   if (IsVistaOrLater() && !HasGlass() &&
  1243       (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
  1244        (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
  1245     SetWindowRgn(mWnd, nullptr, false);
  1249 void nsWindow::SetThemeRegion()
  1251   // Popup types that have a visual styles region applied (bug 376408). This can be expanded
  1252   // for other window types as needed. The regions are applied generically to the base window
  1253   // so default constants are used for part and state. At some point we might need part and
  1254   // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
  1255   // change shape based on state haven't come up.
  1256   if (IsVistaOrLater() && !HasGlass() &&
  1257       (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
  1258        (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
  1259     HRGN hRgn = nullptr;
  1260     RECT rect = {0,0,mBounds.width,mBounds.height};
  1262     HDC dc = ::GetDC(mWnd);
  1263     GetThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
  1264     if (hRgn) {
  1265       if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted.
  1266         DeleteObject(hRgn);
  1268     ::ReleaseDC(mWnd, dc);
  1272 /**************************************************************
  1274  * SECTION: nsIWidget::RegisterTouchWindow,
  1275  * nsIWidget::UnregisterTouchWindow, and helper functions
  1277  * Used to register the native window to receive touch events
  1279  **************************************************************/
  1281 NS_METHOD nsWindow::RegisterTouchWindow() {
  1282   if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0) ||
  1283       gIsPointerEventsEnabled) {
  1284     mTouchWindow = true;
  1285     mGesture.RegisterTouchWindow(mWnd);
  1286     ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
  1288   return NS_OK;
  1291 NS_METHOD nsWindow::UnregisterTouchWindow() {
  1292   mTouchWindow = false;
  1293   mGesture.UnregisterTouchWindow(mWnd);
  1294   ::EnumChildWindows(mWnd, nsWindow::UnregisterTouchForDescendants, 0);
  1295   return NS_OK;
  1298 BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
  1299   nsWindow* win = WinUtils::GetNSWindowPtr(aWnd);
  1300   if (win)
  1301     win->mGesture.RegisterTouchWindow(aWnd);
  1302   return TRUE;
  1305 BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
  1306   nsWindow* win = WinUtils::GetNSWindowPtr(aWnd);
  1307   if (win)
  1308     win->mGesture.UnregisterTouchWindow(aWnd);
  1309   return TRUE;
  1312 /**************************************************************
  1314  * SECTION: nsIWidget::Move, nsIWidget::Resize,
  1315  * nsIWidget::Size, nsIWidget::BeginResizeDrag
  1317  * Repositioning and sizing a window.
  1319  **************************************************************/
  1321 void
  1322 nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints)
  1324   SizeConstraints c = aConstraints;
  1325   if (mWindowType != eWindowType_popup) {
  1326     c.mMinSize.width = std::max(int32_t(::GetSystemMetrics(SM_CXMINTRACK)), c.mMinSize.width);
  1327     c.mMinSize.height = std::max(int32_t(::GetSystemMetrics(SM_CYMINTRACK)), c.mMinSize.height);
  1330   nsBaseWidget::SetSizeConstraints(c);
  1333 // Move this component
  1334 NS_METHOD nsWindow::Move(double aX, double aY)
  1336   if (mWindowType == eWindowType_toplevel ||
  1337       mWindowType == eWindowType_dialog) {
  1338     SetSizeMode(nsSizeMode_Normal);
  1341   // for top-level windows only, convert coordinates from global display pixels
  1342   // (the "parent" coordinate space) to the window's device pixel space
  1343   CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale()
  1344                                     : CSSToLayoutDeviceScale(1.0);
  1345   int32_t x = NSToIntRound(aX * scale.scale);
  1346   int32_t y = NSToIntRound(aY * scale.scale);
  1348   // Check to see if window needs to be moved first
  1349   // to avoid a costly call to SetWindowPos. This check
  1350   // can not be moved to the calling code in nsView, because
  1351   // some platforms do not position child windows correctly
  1353   // Only perform this check for non-popup windows, since the positioning can
  1354   // in fact change even when the x/y do not.  We always need to perform the
  1355   // check. See bug #97805 for details.
  1356   if (mWindowType != eWindowType_popup && (mBounds.x == x) && (mBounds.y == y))
  1358     // Nothing to do, since it is already positioned correctly.
  1359     return NS_OK;
  1362   mBounds.x = x;
  1363   mBounds.y = y;
  1365   if (mWnd) {
  1366 #ifdef DEBUG
  1367     // complain if a window is moved offscreen (legal, but potentially worrisome)
  1368     if (mIsTopWidgetWindow) { // only a problem for top-level windows
  1369       // Make sure this window is actually on the screen before we move it
  1370       // XXX: Needs multiple monitor support
  1371       HDC dc = ::GetDC(mWnd);
  1372       if (dc) {
  1373         if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
  1374           RECT workArea;
  1375           ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
  1376           // no annoying assertions. just mention the issue.
  1377           if (x < 0 || x >= workArea.right || y < 0 || y >= workArea.bottom) {
  1378             PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
  1379                    ("window moved to offscreen position\n"));
  1382       ::ReleaseDC(mWnd, dc);
  1385 #endif
  1386     ClearThemeRegion();
  1388     UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE;
  1389     // Workaround SetWindowPos bug with D3D9. If our window has a clip
  1390     // region, some drivers or OSes may incorrectly copy into the clipped-out
  1391     // area.
  1392     if (mWindowType == eWindowType_plugin &&
  1393         (!mLayerManager || mLayerManager->GetBackendType() == LayersBackend::LAYERS_D3D9) &&
  1394         mClipRects &&
  1395         (mClipRectCount != 1 || !mClipRects[0].IsEqualInterior(nsIntRect(0, 0, mBounds.width, mBounds.height)))) {
  1396       flags |= SWP_NOCOPYBITS;
  1398     VERIFY(::SetWindowPos(mWnd, nullptr, x, y, 0, 0, flags));
  1400     SetThemeRegion();
  1402   NotifyRollupGeometryChange();
  1403   return NS_OK;
  1406 // Resize this component
  1407 NS_METHOD nsWindow::Resize(double aWidth, double aHeight, bool aRepaint)
  1409   // for top-level windows only, convert coordinates from global display pixels
  1410   // (the "parent" coordinate space) to the window's device pixel space
  1411   CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale()
  1412                                     : CSSToLayoutDeviceScale(1.0);
  1413   int32_t width = NSToIntRound(aWidth * scale.scale);
  1414   int32_t height = NSToIntRound(aHeight * scale.scale);
  1416   NS_ASSERTION((width >= 0) , "Negative width passed to nsWindow::Resize");
  1417   NS_ASSERTION((height >= 0), "Negative height passed to nsWindow::Resize");
  1419   ConstrainSize(&width, &height);
  1421   // Avoid unnecessary resizing calls
  1422   if (mBounds.width == width && mBounds.height == height) {
  1423     if (aRepaint) {
  1424       Invalidate();
  1426     return NS_OK;
  1429 #ifdef MOZ_XUL
  1430   if (eTransparencyTransparent == mTransparencyMode)
  1431     ResizeTranslucentWindow(width, height);
  1432 #endif
  1434   // Set cached value for lightweight and printing
  1435   mBounds.width  = width;
  1436   mBounds.height = height;
  1438   if (mWnd) {
  1439     UINT  flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
  1441     if (!aRepaint) {
  1442       flags |= SWP_NOREDRAW;
  1445     ClearThemeRegion();
  1446     VERIFY(::SetWindowPos(mWnd, nullptr, 0, 0,
  1447                           width, GetHeight(height), flags));
  1448     SetThemeRegion();
  1451   if (aRepaint)
  1452     Invalidate();
  1454   NotifyRollupGeometryChange();
  1455   return NS_OK;
  1458 // Resize this component
  1459 NS_METHOD nsWindow::Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint)
  1461   // for top-level windows only, convert coordinates from global display pixels
  1462   // (the "parent" coordinate space) to the window's device pixel space
  1463   CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale()
  1464                                     : CSSToLayoutDeviceScale(1.0);
  1465   int32_t x = NSToIntRound(aX * scale.scale);
  1466   int32_t y = NSToIntRound(aY * scale.scale);
  1467   int32_t width = NSToIntRound(aWidth * scale.scale);
  1468   int32_t height = NSToIntRound(aHeight * scale.scale);
  1470   NS_ASSERTION((width >= 0),  "Negative width passed to nsWindow::Resize");
  1471   NS_ASSERTION((height >= 0), "Negative height passed to nsWindow::Resize");
  1473   ConstrainSize(&width, &height);
  1475   // Avoid unnecessary resizing calls
  1476   if (mBounds.x == x && mBounds.y == y &&
  1477       mBounds.width == width && mBounds.height == height) {
  1478     if (aRepaint) {
  1479       Invalidate();
  1481     return NS_OK;
  1484 #ifdef MOZ_XUL
  1485   if (eTransparencyTransparent == mTransparencyMode)
  1486     ResizeTranslucentWindow(width, height);
  1487 #endif
  1489   // Set cached value for lightweight and printing
  1490   mBounds.x      = x;
  1491   mBounds.y      = y;
  1492   mBounds.width  = width;
  1493   mBounds.height = height;
  1495   if (mWnd) {
  1496     UINT  flags = SWP_NOZORDER | SWP_NOACTIVATE;
  1497     if (!aRepaint) {
  1498       flags |= SWP_NOREDRAW;
  1501     ClearThemeRegion();
  1502     VERIFY(::SetWindowPos(mWnd, nullptr, x, y,
  1503                           width, GetHeight(height), flags));
  1504     SetThemeRegion();
  1507   if (aRepaint)
  1508     Invalidate();
  1510   NotifyRollupGeometryChange();
  1511   return NS_OK;
  1514 NS_IMETHODIMP
  1515 nsWindow::BeginResizeDrag(WidgetGUIEvent* aEvent,
  1516                           int32_t aHorizontal,
  1517                           int32_t aVertical)
  1519   NS_ENSURE_ARG_POINTER(aEvent);
  1521   if (aEvent->eventStructType != NS_MOUSE_EVENT) {
  1522     // you can only begin a resize drag with a mouse event
  1523     return NS_ERROR_INVALID_ARG;
  1526   if (aEvent->AsMouseEvent()->button != WidgetMouseEvent::eLeftButton) {
  1527     // you can only begin a resize drag with the left mouse button
  1528     return NS_ERROR_INVALID_ARG;
  1531   // work out what sizemode we're talking about
  1532   WPARAM syscommand;
  1533   if (aVertical < 0) {
  1534     if (aHorizontal < 0) {
  1535       syscommand = SC_SIZE | WMSZ_TOPLEFT;
  1536     } else if (aHorizontal == 0) {
  1537       syscommand = SC_SIZE | WMSZ_TOP;
  1538     } else {
  1539       syscommand = SC_SIZE | WMSZ_TOPRIGHT;
  1541   } else if (aVertical == 0) {
  1542     if (aHorizontal < 0) {
  1543       syscommand = SC_SIZE | WMSZ_LEFT;
  1544     } else if (aHorizontal == 0) {
  1545       return NS_ERROR_INVALID_ARG;
  1546     } else {
  1547       syscommand = SC_SIZE | WMSZ_RIGHT;
  1549   } else {
  1550     if (aHorizontal < 0) {
  1551       syscommand = SC_SIZE | WMSZ_BOTTOMLEFT;
  1552     } else if (aHorizontal == 0) {
  1553       syscommand = SC_SIZE | WMSZ_BOTTOM;
  1554     } else {
  1555       syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT;
  1559   // resizing doesn't work if the mouse is already captured
  1560   CaptureMouse(false);
  1562   // find the top-level window
  1563   HWND toplevelWnd = WinUtils::GetTopLevelHWND(mWnd, true);
  1565   // tell Windows to start the resize
  1566   ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand,
  1567                 POINTTOPOINTS(aEvent->refPoint));
  1569   return NS_OK;
  1572 /**************************************************************
  1574  * SECTION: Window Z-order and state.
  1576  * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
  1577  * nsIWidget::ConstrainPosition
  1579  * Z-order, positioning, restore, minimize, and maximize.
  1581  **************************************************************/
  1583 // Position the window behind the given window
  1584 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
  1585                                 nsIWidget *aWidget, bool aActivate)
  1587   HWND behind = HWND_TOP;
  1588   if (aPlacement == eZPlacementBottom)
  1589     behind = HWND_BOTTOM;
  1590   else if (aPlacement == eZPlacementBelow && aWidget)
  1591     behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
  1592   UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
  1593   if (!aActivate)
  1594     flags |= SWP_NOACTIVATE;
  1596   if (!CanTakeFocus() && behind == HWND_TOP)
  1598     // Can't place the window to top so place it behind the foreground window
  1599     // (as long as it is not topmost)
  1600     HWND wndAfter = ::GetForegroundWindow();
  1601     if (!wndAfter)
  1602       behind = HWND_BOTTOM;
  1603     else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
  1604       behind = wndAfter;
  1605     flags |= SWP_NOACTIVATE;
  1608   ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
  1609   return NS_OK;
  1612 // Maximize, minimize or restore the window.
  1613 NS_IMETHODIMP nsWindow::SetSizeMode(int32_t aMode) {
  1615   nsresult rv;
  1617   // Let's not try and do anything if we're already in that state.
  1618   // (This is needed to prevent problems when calling window.minimize(), which
  1619   // calls us directly, and then the OS triggers another call to us.)
  1620   if (aMode == mSizeMode)
  1621     return NS_OK;
  1623   // save the requested state
  1624   mLastSizeMode = mSizeMode;
  1625   rv = nsBaseWidget::SetSizeMode(aMode);
  1626   if (NS_SUCCEEDED(rv) && mIsVisible) {
  1627     int mode;
  1629     switch (aMode) {
  1630       case nsSizeMode_Fullscreen :
  1631         mode = SW_SHOW;
  1632         break;
  1634       case nsSizeMode_Maximized :
  1635         mode = SW_MAXIMIZE;
  1636         break;
  1638       case nsSizeMode_Minimized :
  1639         // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
  1640         // keeps the window active in the tray. So after the window is minimized,
  1641         // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
  1642         // we will do some additional processing to get the active window set right.
  1643         // If sTrimOnMinimize is set, we let windows handle minimization normally
  1644         // using SW_MINIMIZE.
  1645         mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED;
  1646         break;
  1648       default :
  1649         mode = SW_RESTORE;
  1652     WINDOWPLACEMENT pl;
  1653     pl.length = sizeof(pl);
  1654     ::GetWindowPlacement(mWnd, &pl);
  1655     // Don't call ::ShowWindow if we're trying to "restore" a window that is
  1656     // already in a normal state.  Prevents a bug where snapping to one side
  1657     // of the screen and then minimizing would cause Windows to forget our
  1658     // window's correct restored position/size.
  1659     if( !(pl.showCmd == SW_SHOWNORMAL && mode == SW_RESTORE) ) {
  1660       ::ShowWindow(mWnd, mode);
  1662     // we activate here to ensure that the right child window is focused
  1663     if (mode == SW_MAXIMIZE || mode == SW_SHOW)
  1664       DispatchFocusToTopLevelWindow(true);
  1666   return rv;
  1669 // Constrain a potential move to fit onscreen
  1670 // Position (aX, aY) is specified in Windows screen (logical) pixels
  1671 NS_METHOD nsWindow::ConstrainPosition(bool aAllowSlop,
  1672                                       int32_t *aX, int32_t *aY)
  1674   if (!mIsTopWidgetWindow) // only a problem for top-level windows
  1675     return NS_OK;
  1677   double dpiScale = GetDefaultScale().scale;
  1679   // we need to use the window size in logical screen pixels
  1680   int32_t logWidth = std::max<int32_t>(NSToIntRound(mBounds.width / dpiScale), 1);
  1681   int32_t logHeight = std::max<int32_t>(NSToIntRound(mBounds.height / dpiScale), 1);
  1683   bool doConstrain = false; // whether we have enough info to do anything
  1685   /* get our playing field. use the current screen, or failing that
  1686     for any reason, use device caps for the default screen. */
  1687   RECT screenRect;
  1689   nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
  1690   if (screenmgr) {
  1691     nsCOMPtr<nsIScreen> screen;
  1692     int32_t left, top, width, height;
  1694     screenmgr->ScreenForRect(*aX, *aY, logWidth, logHeight,
  1695                              getter_AddRefs(screen));
  1696     if (screen) {
  1697       if (mSizeMode != nsSizeMode_Fullscreen) {
  1698         // For normalized windows, use the desktop work area.
  1699         screen->GetAvailRectDisplayPix(&left, &top, &width, &height);
  1700       } else {
  1701         // For full screen windows, use the desktop.
  1702         screen->GetRectDisplayPix(&left, &top, &width, &height);
  1704       screenRect.left = left;
  1705       screenRect.right = left + width;
  1706       screenRect.top = top;
  1707       screenRect.bottom = top + height;
  1708       doConstrain = true;
  1710   } else {
  1711     if (mWnd) {
  1712       HDC dc = ::GetDC(mWnd);
  1713       if (dc) {
  1714         if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
  1715           if (mSizeMode != nsSizeMode_Fullscreen) {
  1716             ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
  1717           } else {
  1718             screenRect.left = screenRect.top = 0;
  1719             screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN);
  1720             screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
  1722           doConstrain = true;
  1724         ::ReleaseDC(mWnd, dc);
  1729   if (aAllowSlop) {
  1730     if (*aX < screenRect.left - logWidth + kWindowPositionSlop)
  1731       *aX = screenRect.left - logWidth + kWindowPositionSlop;
  1732     else if (*aX >= screenRect.right - kWindowPositionSlop)
  1733       *aX = screenRect.right - kWindowPositionSlop;
  1735     if (*aY < screenRect.top - logHeight + kWindowPositionSlop)
  1736       *aY = screenRect.top - logHeight + kWindowPositionSlop;
  1737     else if (*aY >= screenRect.bottom - kWindowPositionSlop)
  1738       *aY = screenRect.bottom - kWindowPositionSlop;
  1740   } else {
  1742     if (*aX < screenRect.left)
  1743       *aX = screenRect.left;
  1744     else if (*aX >= screenRect.right - logWidth)
  1745       *aX = screenRect.right - logWidth;
  1747     if (*aY < screenRect.top)
  1748       *aY = screenRect.top;
  1749     else if (*aY >= screenRect.bottom - logHeight)
  1750       *aY = screenRect.bottom - logHeight;
  1753   return NS_OK;
  1756 /**************************************************************
  1758  * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
  1760  * Enabling and disabling the widget.
  1762  **************************************************************/
  1764 // Enable/disable this component
  1765 NS_METHOD nsWindow::Enable(bool bState)
  1767   if (mWnd) {
  1768     ::EnableWindow(mWnd, bState);
  1770   return NS_OK;
  1773 // Return the current enable state
  1774 bool nsWindow::IsEnabled() const
  1776   return !mWnd ||
  1777          (::IsWindowEnabled(mWnd) &&
  1778           ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT)));
  1782 /**************************************************************
  1784  * SECTION: nsIWidget::SetFocus
  1786  * Give the focus to this widget.
  1788  **************************************************************/
  1790 NS_METHOD nsWindow::SetFocus(bool aRaise)
  1792   if (mWnd) {
  1793 #ifdef WINSTATE_DEBUG_OUTPUT
  1794     if (mWnd == WinUtils::GetTopLevelHWND(mWnd)) {
  1795       PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
  1796              ("*** SetFocus: [  top] raise=%d\n", aRaise));
  1797     } else {
  1798       PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
  1799              ("*** SetFocus: [child] raise=%d\n", aRaise));
  1801 #endif
  1802     // Uniconify, if necessary
  1803     HWND toplevelWnd = WinUtils::GetTopLevelHWND(mWnd);
  1804     if (aRaise && ::IsIconic(toplevelWnd)) {
  1805       ::ShowWindow(toplevelWnd, SW_RESTORE);
  1807     ::SetFocus(mWnd);
  1809   return NS_OK;
  1813 /**************************************************************
  1815  * SECTION: Bounds
  1817  * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
  1818  * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
  1820  * Bound calculations.
  1822  **************************************************************/
  1824 // Return the window's full dimensions in screen coordinates.
  1825 // If the window has a parent, converts the origin to an offset
  1826 // of the parent's screen origin.
  1827 NS_METHOD nsWindow::GetBounds(nsIntRect &aRect)
  1829   if (mWnd) {
  1830     RECT r;
  1831     VERIFY(::GetWindowRect(mWnd, &r));
  1833     // assign size
  1834     aRect.width  = r.right - r.left;
  1835     aRect.height = r.bottom - r.top;
  1837     // popup window bounds' are in screen coordinates, not relative to parent
  1838     // window
  1839     if (mWindowType == eWindowType_popup) {
  1840       aRect.x = r.left;
  1841       aRect.y = r.top;
  1842       return NS_OK;
  1845     // chrome on parent:
  1846     //  ___      5,5   (chrome start)
  1847     // |  ____   10,10 (client start)
  1848     // | |  ____ 20,20 (child start)
  1849     // | | |
  1850     // 20,20 - 5,5 = 15,15 (??)
  1851     // minus GetClientOffset:
  1852     // 15,15 - 5,5 = 10,10
  1853     //
  1854     // no chrome on parent:
  1855     //  ______   10,10 (win start)
  1856     // |  ____   20,20 (child start)
  1857     // | |
  1858     // 20,20 - 10,10 = 10,10
  1859     //
  1860     // walking the chain:
  1861     //  ___      5,5   (chrome start)
  1862     // |  ___    10,10 (client start)
  1863     // | |  ___  20,20 (child start)
  1864     // | | |  __ 30,30 (child start)
  1865     // | | | |
  1866     // 30,30 - 20,20 = 10,10 (offset from second child to first)
  1867     // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
  1868     // minus GetClientOffset:
  1869     // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
  1871     // convert coordinates if parent exists
  1872     HWND parent = ::GetParent(mWnd);
  1873     if (parent) {
  1874       RECT pr;
  1875       VERIFY(::GetWindowRect(parent, &pr));
  1876       r.left -= pr.left;
  1877       r.top  -= pr.top;
  1878       // adjust for chrome
  1879       nsWindow* pWidget = static_cast<nsWindow*>(GetParent());
  1880       if (pWidget && pWidget->IsTopLevelWidget()) {
  1881         nsIntPoint clientOffset = pWidget->GetClientOffset();
  1882         r.left -= clientOffset.x;
  1883         r.top  -= clientOffset.y;
  1886     aRect.x = r.left;
  1887     aRect.y = r.top;
  1888   } else {
  1889     aRect = mBounds;
  1891   return NS_OK;
  1894 // Get this component dimension
  1895 NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect)
  1897   if (mWnd) {
  1898     RECT r;
  1899     VERIFY(::GetClientRect(mWnd, &r));
  1901     nsIntRect bounds;
  1902     GetBounds(bounds);
  1903     aRect.MoveTo(bounds.TopLeft() + GetClientOffset());
  1904     aRect.width  = r.right - r.left;
  1905     aRect.height = r.bottom - r.top;
  1907   } else {
  1908     aRect.SetRect(0,0,0,0);
  1910   return NS_OK;
  1913 // Like GetBounds, but don't offset by the parent
  1914 NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect)
  1916   if (mWnd) {
  1917     RECT r;
  1918     VERIFY(::GetWindowRect(mWnd, &r));
  1920     aRect.width  = r.right - r.left;
  1921     aRect.height = r.bottom - r.top;
  1922     aRect.x = r.left;
  1923     aRect.y = r.top;
  1924   } else
  1925     aRect = mBounds;
  1927   return NS_OK;
  1930 // return the x,y offset of the client area from the origin
  1931 // of the window. If the window is borderless returns (0,0).
  1932 nsIntPoint nsWindow::GetClientOffset()
  1934   if (!mWnd) {
  1935     return nsIntPoint(0, 0);
  1938   RECT r1;
  1939   GetWindowRect(mWnd, &r1);
  1940   nsIntPoint pt = WidgetToScreenOffset();
  1941   return nsIntPoint(pt.x - r1.left, pt.y - r1.top);
  1944 void
  1945 nsWindow::SetDrawsInTitlebar(bool aState)
  1947   nsWindow * window = GetTopLevelWindow(true);
  1948   if (window && window != this) {
  1949     return window->SetDrawsInTitlebar(aState);
  1952   if (aState) {
  1953     // top, right, bottom, left for nsIntMargin
  1954     nsIntMargin margins(0, -1, -1, -1);
  1955     SetNonClientMargins(margins);
  1957   else {
  1958     nsIntMargin margins(-1, -1, -1, -1);
  1959     SetNonClientMargins(margins);
  1963 NS_IMETHODIMP
  1964 nsWindow::GetNonClientMargins(nsIntMargin &margins)
  1966   nsWindow * window = GetTopLevelWindow(true);
  1967   if (window && window != this) {
  1968     return window->GetNonClientMargins(margins);
  1971   if (mCustomNonClient) {
  1972     margins = mNonClientMargins;
  1973     return NS_OK;
  1976   margins.top = GetSystemMetrics(SM_CYCAPTION);
  1977   margins.bottom = GetSystemMetrics(SM_CYFRAME);
  1978   margins.top += margins.bottom;
  1979   margins.left = margins.right = GetSystemMetrics(SM_CXFRAME);
  1981   return NS_OK;
  1984 void
  1985 nsWindow::ResetLayout()
  1987   // This will trigger a frame changed event, triggering
  1988   // nc calc size and a sizemode gecko event.
  1989   SetWindowPos(mWnd, 0, 0, 0, 0, 0,
  1990                SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|
  1991                SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
  1993   // If hidden, just send the frame changed event for now.
  1994   if (!mIsVisible)
  1995     return;
  1997   // Send a gecko size event to trigger reflow.
  1998   RECT clientRc = {0};
  1999   GetClientRect(mWnd, &clientRc);
  2000   nsIntRect evRect(WinUtils::ToIntRect(clientRc));
  2001   OnResize(evRect);
  2003   // Invalidate and update
  2004   Invalidate();
  2007 // Internally track the caption status via a window property. Required
  2008 // due to our internal handling of WM_NCACTIVATE when custom client
  2009 // margins are set.
  2010 static const wchar_t kManageWindowInfoProperty[] = L"ManageWindowInfoProperty";
  2011 typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi);
  2012 static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr;
  2014 BOOL WINAPI
  2015 GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi)
  2017   if (!sGetWindowInfoPtrStub) {
  2018     NS_ASSERTION(FALSE, "Something is horribly wrong in GetWindowInfoHook!");
  2019     return FALSE;
  2021   int windowStatus = 
  2022     reinterpret_cast<LONG_PTR>(GetPropW(hWnd, kManageWindowInfoProperty));
  2023   // No property set, return the default data.
  2024   if (!windowStatus)
  2025     return sGetWindowInfoPtrStub(hWnd, pwi);
  2026   // Call GetWindowInfo and update dwWindowStatus with our
  2027   // internally tracked value. 
  2028   BOOL result = sGetWindowInfoPtrStub(hWnd, pwi);
  2029   if (result && pwi)
  2030     pwi->dwWindowStatus = (windowStatus == 1 ? 0 : WS_ACTIVECAPTION);
  2031   return result;
  2034 void
  2035 nsWindow::UpdateGetWindowInfoCaptionStatus(bool aActiveCaption)
  2037   if (!mWnd)
  2038     return;
  2040   if (!sGetWindowInfoPtrStub) {
  2041     sUser32Intercept.Init("user32.dll");
  2042     if (!sUser32Intercept.AddHook("GetWindowInfo", reinterpret_cast<intptr_t>(GetWindowInfoHook),
  2043                                   (void**) &sGetWindowInfoPtrStub))
  2044       return;
  2046   // Update our internally tracked caption status
  2047   SetPropW(mWnd, kManageWindowInfoProperty, 
  2048     reinterpret_cast<HANDLE>(static_cast<int>(aActiveCaption) + 1));
  2051 /**
  2052  * Called when the window layout changes: full screen mode transitions,
  2053  * theme changes, and composition changes. Calculates the new non-client
  2054  * margins and fires off a frame changed event, which triggers an nc calc
  2055  * size windows event, kicking the changes in.
  2057  * The offsets calculated here are based on the value of `mNonClientMargins`
  2058  * which is specified in the "chromemargins" attribute of the window.  For
  2059  * each margin, the value specified has the following meaning:
  2060  *    -1 - leave the default frame in place
  2061  *     0 - remove the frame
  2062  *    >0 - frame size equals min(0, (default frame size - margin value))
  2064  * This function calculates and populates `mNonClientOffset`.
  2065  * In our processing of `WM_NCCALCSIZE`, the frame size will be calculated
  2066  * as (default frame size - offset).  For example, if the left frame should
  2067  * be 1 pixel narrower than the default frame size, `mNonClientOffset.left`
  2068  * will equal 1.
  2070  * For maximized, fullscreen, and minimized windows, the values stored in
  2071  * `mNonClientMargins` are ignored, and special processing takes place.
  2073  * For non-glass windows, we only allow frames to be their default size
  2074  * or removed entirely.
  2075  */
  2076 bool
  2077 nsWindow::UpdateNonClientMargins(int32_t aSizeMode, bool aReflowWindow)
  2079   if (!mCustomNonClient)
  2080     return false;
  2082   if (aSizeMode == -1) {
  2083     aSizeMode = mSizeMode;
  2086   bool hasCaption = (mBorderStyle
  2087                     & (eBorderStyle_all
  2088                      | eBorderStyle_title
  2089                      | eBorderStyle_menu
  2090                      | eBorderStyle_default));
  2092   // mCaptionHeight is the default size of the NC area at
  2093   // the top of the window. If the window has a caption,
  2094   // the size is calculated as the sum of:
  2095   //      SM_CYFRAME        - The thickness of the sizing border
  2096   //                          around a resizable window
  2097   //      SM_CXPADDEDBORDER - The amount of border padding
  2098   //                          for captioned windows
  2099   //      SM_CYCAPTION      - The height of the caption area
  2100   //
  2101   // If the window does not have a caption, mCaptionHeight will be equal to
  2102   // `GetSystemMetrics(SM_CYFRAME)`
  2103   mCaptionHeight = GetSystemMetrics(SM_CYFRAME)
  2104                  + (hasCaption ? GetSystemMetrics(SM_CYCAPTION)
  2105                                  + GetSystemMetrics(SM_CXPADDEDBORDER)
  2106                                : 0);
  2108   // mHorResizeMargin is the size of the default NC areas on the
  2109   // left and right sides of our window.  It is calculated as
  2110   // the sum of:
  2111   //      SM_CXFRAME        - The thickness of the sizing border
  2112   //      SM_CXPADDEDBORDER - The amount of border padding
  2113   //                          for captioned windows
  2114   //
  2115   // If the window does not have a caption, mHorResizeMargin will be equal to
  2116   // `GetSystemMetrics(SM_CXFRAME)`
  2117   mHorResizeMargin = GetSystemMetrics(SM_CXFRAME)
  2118                    + (hasCaption ? GetSystemMetrics(SM_CXPADDEDBORDER) : 0);
  2120   // mVertResizeMargin is the size of the default NC area at the
  2121   // bottom of the window. It is calculated as the sum of:
  2122   //      SM_CYFRAME        - The thickness of the sizing border
  2123   //      SM_CXPADDEDBORDER - The amount of border padding
  2124   //                          for captioned windows.
  2125   //
  2126   // If the window does not have a caption, mVertResizeMargin will be equal to
  2127   // `GetSystemMetrics(SM_CYFRAME)`
  2128   mVertResizeMargin = GetSystemMetrics(SM_CYFRAME)
  2129                     + (hasCaption ? GetSystemMetrics(SM_CXPADDEDBORDER) : 0);
  2131   if (aSizeMode == nsSizeMode_Minimized) {
  2132     // Use default frame size for minimized windows
  2133     mNonClientOffset.top = 0;
  2134     mNonClientOffset.left = 0;
  2135     mNonClientOffset.right = 0;
  2136     mNonClientOffset.bottom = 0;
  2137   } else if (aSizeMode == nsSizeMode_Fullscreen) {
  2138     // Remove the default frame from the top of our fullscreen window.  This
  2139     // makes the whole caption part of our client area, allowing us to draw
  2140     // in the whole caption area.  Additionally remove the default frame from
  2141     // the left, right, and bottom.
  2142     mNonClientOffset.top = mCaptionHeight;
  2143     mNonClientOffset.bottom = mVertResizeMargin;
  2144     mNonClientOffset.left = mHorResizeMargin;
  2145     mNonClientOffset.right = mHorResizeMargin;
  2146   } else if (aSizeMode == nsSizeMode_Maximized) {
  2147     // Remove the default frame from the top of our maximized window.  This
  2148     // makes the whole caption part of our client area, allowing us to draw
  2149     // in the whole caption area.  Use default frame size on left, right, and
  2150     // bottom. The reason this works is that, for maximized windows,
  2151     // Windows positions them so that their frames fall off the screen.
  2152     // This gives the illusion of windows having no frames when they are
  2153     // maximized.  If we try to mess with the frame sizes by setting these
  2154     // offsets to positive values, our client area will fall off the screen.
  2155     mNonClientOffset.top = mCaptionHeight;
  2156     mNonClientOffset.bottom = 0;
  2157     mNonClientOffset.left = 0;
  2158     mNonClientOffset.right = 0;
  2160     APPBARDATA appBarData;
  2161     appBarData.cbSize = sizeof(appBarData);
  2162     UINT taskbarState = SHAppBarMessage(ABM_GETSTATE, &appBarData);
  2163     if (ABS_AUTOHIDE & taskbarState) {
  2164       UINT edge = -1;
  2165       appBarData.hWnd = FindWindow(L"Shell_TrayWnd", nullptr);
  2166       if (appBarData.hWnd) {
  2167         HMONITOR taskbarMonitor = ::MonitorFromWindow(appBarData.hWnd,
  2168                                                       MONITOR_DEFAULTTOPRIMARY);
  2169         HMONITOR windowMonitor = ::MonitorFromWindow(mWnd,
  2170                                                      MONITOR_DEFAULTTONEAREST);
  2171         if (taskbarMonitor == windowMonitor) {
  2172           SHAppBarMessage(ABM_GETTASKBARPOS, &appBarData);
  2173           edge = appBarData.uEdge;
  2177       if (ABE_LEFT == edge) {
  2178         mNonClientOffset.left -= 1;
  2179       } else if (ABE_RIGHT == edge) {
  2180         mNonClientOffset.right -= 1;
  2181       } else if (ABE_BOTTOM == edge || ABE_TOP == edge) {
  2182         mNonClientOffset.bottom -= 1;
  2185   } else {
  2186     bool glass = nsUXThemeData::CheckForCompositor();
  2188     // We're dealing with a "normal" window (not maximized, minimized, or
  2189     // fullscreen), so process `mNonClientMargins` and set `mNonClientOffset`
  2190     // accordingly.
  2191     //
  2192     // Setting `mNonClientOffset` to 0 has the effect of leaving the default
  2193     // frame intact.  Setting it to a value greater than 0 reduces the frame
  2194     // size by that amount.
  2196     if (mNonClientMargins.top > 0 && glass) {
  2197       mNonClientOffset.top = std::min(mCaptionHeight, mNonClientMargins.top);
  2198     } else if (mNonClientMargins.top == 0) {
  2199       mNonClientOffset.top = mCaptionHeight;
  2200     } else {
  2201       mNonClientOffset.top = 0;
  2204     if (mNonClientMargins.bottom > 0 && glass) {
  2205       mNonClientOffset.bottom = std::min(mVertResizeMargin, mNonClientMargins.bottom);
  2206     } else if (mNonClientMargins.bottom == 0) {
  2207       mNonClientOffset.bottom = mVertResizeMargin;
  2208     } else {
  2209       mNonClientOffset.bottom = 0;
  2212     if (mNonClientMargins.left > 0 && glass) {
  2213       mNonClientOffset.left = std::min(mHorResizeMargin, mNonClientMargins.left);
  2214     } else if (mNonClientMargins.left == 0) {
  2215       mNonClientOffset.left = mHorResizeMargin;
  2216     } else {
  2217       mNonClientOffset.left = 0;
  2220     if (mNonClientMargins.right > 0 && glass) {
  2221       mNonClientOffset.right = std::min(mHorResizeMargin, mNonClientMargins.right);
  2222     } else if (mNonClientMargins.right == 0) {
  2223       mNonClientOffset.right = mHorResizeMargin;
  2224     } else {
  2225       mNonClientOffset.right = 0;
  2229   if (aReflowWindow) {
  2230     // Force a reflow of content based on the new client
  2231     // dimensions.
  2232     ResetLayout();
  2235   return true;
  2238 NS_IMETHODIMP
  2239 nsWindow::SetNonClientMargins(nsIntMargin &margins)
  2241   if (!mIsTopWidgetWindow ||
  2242       mBorderStyle & eBorderStyle_none ||
  2243       mHideChrome)
  2244     return NS_ERROR_INVALID_ARG;
  2246   // Request for a reset
  2247   if (margins.top == -1 && margins.left == -1 &&
  2248       margins.right == -1 && margins.bottom == -1) {
  2249     mCustomNonClient = false;
  2250     mNonClientMargins = margins;
  2251     // Force a reflow of content based on the new client
  2252     // dimensions.
  2253     ResetLayout();
  2255     int windowStatus =
  2256       reinterpret_cast<LONG_PTR>(GetPropW(mWnd, kManageWindowInfoProperty));
  2257     if (windowStatus) {
  2258       ::SendMessageW(mWnd, WM_NCACTIVATE, 1 != windowStatus, 0);
  2261     return NS_OK;
  2264   if (margins.top < -1 || margins.bottom < -1 ||
  2265       margins.left < -1 || margins.right < -1)
  2266     return NS_ERROR_INVALID_ARG;
  2268   mNonClientMargins = margins;
  2269   mCustomNonClient = true;
  2270   if (!UpdateNonClientMargins()) {
  2271     NS_WARNING("UpdateNonClientMargins failed!");
  2272     return NS_OK;
  2275   return NS_OK;
  2278 void
  2279 nsWindow::InvalidateNonClientRegion()
  2281   // +-+-----------------------+-+
  2282   // | | app non-client chrome | |
  2283   // | +-----------------------+ |
  2284   // | |   app client chrome   | | }
  2285   // | +-----------------------+ | }
  2286   // | |      app content      | | } area we don't want to invalidate
  2287   // | +-----------------------+ | }
  2288   // | |   app client chrome   | | }
  2289   // | +-----------------------+ | 
  2290   // +---------------------------+ <
  2291   //  ^                         ^    windows non-client chrome
  2292   // client area = app *
  2293   RECT rect;
  2294   GetWindowRect(mWnd, &rect);
  2295   MapWindowPoints(nullptr, mWnd, (LPPOINT)&rect, 2);
  2296   HRGN winRgn = CreateRectRgnIndirect(&rect);
  2298   // Subtract app client chrome and app content leaving
  2299   // windows non-client chrome and app non-client chrome
  2300   // in winRgn.
  2301   GetWindowRect(mWnd, &rect);
  2302   rect.top += mCaptionHeight;
  2303   rect.right -= mHorResizeMargin;
  2304   rect.bottom -= mHorResizeMargin;
  2305   rect.left += mVertResizeMargin;
  2306   MapWindowPoints(nullptr, mWnd, (LPPOINT)&rect, 2);
  2307   HRGN clientRgn = CreateRectRgnIndirect(&rect);
  2308   CombineRgn(winRgn, winRgn, clientRgn, RGN_DIFF);
  2309   DeleteObject(clientRgn);
  2311   // triggers ncpaint and paint events for the two areas
  2312   RedrawWindow(mWnd, nullptr, winRgn, RDW_FRAME | RDW_INVALIDATE);
  2313   DeleteObject(winRgn);
  2316 HRGN
  2317 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion)
  2319   RECT rect;
  2320   HRGN rgn = nullptr;
  2321   if (aRegion == (HRGN)1) { // undocumented value indicating a full refresh
  2322     GetWindowRect(mWnd, &rect);
  2323     rgn = CreateRectRgnIndirect(&rect);
  2324   } else {
  2325     rgn = aRegion;
  2327   GetClientRect(mWnd, &rect);
  2328   MapWindowPoints(mWnd, nullptr, (LPPOINT)&rect, 2);
  2329   HRGN nonClientRgn = CreateRectRgnIndirect(&rect);
  2330   CombineRgn(rgn, rgn, nonClientRgn, RGN_DIFF);
  2331   DeleteObject(nonClientRgn);
  2332   return rgn;
  2335 /**************************************************************
  2337  * SECTION: nsIWidget::SetBackgroundColor
  2339  * Sets the window background paint color.
  2341  **************************************************************/
  2343 void nsWindow::SetBackgroundColor(const nscolor &aColor)
  2345   if (mBrush)
  2346     ::DeleteObject(mBrush);
  2348   mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(aColor));
  2349   if (mWnd != nullptr) {
  2350     ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush);
  2354 /**************************************************************
  2356  * SECTION: nsIWidget::SetCursor
  2358  * SetCursor and related utilities for manging cursor state.
  2360  **************************************************************/
  2362 // Set this component cursor
  2363 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
  2365   // Only change cursor if it's changing
  2367   //XXX mCursor isn't always right.  Scrollbars and others change it, too.
  2368   //XXX If we want this optimization we need a better way to do it.
  2369   //if (aCursor != mCursor) {
  2370   HCURSOR newCursor = nullptr;
  2372   switch (aCursor) {
  2373     case eCursor_select:
  2374       newCursor = ::LoadCursor(nullptr, IDC_IBEAM);
  2375       break;
  2377     case eCursor_wait:
  2378       newCursor = ::LoadCursor(nullptr, IDC_WAIT);
  2379       break;
  2381     case eCursor_hyperlink:
  2383       newCursor = ::LoadCursor(nullptr, IDC_HAND);
  2384       break;
  2387     case eCursor_standard:
  2388     case eCursor_context_menu: // XXX See bug 258960.
  2389       newCursor = ::LoadCursor(nullptr, IDC_ARROW);
  2390       break;
  2392     case eCursor_n_resize:
  2393     case eCursor_s_resize:
  2394       newCursor = ::LoadCursor(nullptr, IDC_SIZENS);
  2395       break;
  2397     case eCursor_w_resize:
  2398     case eCursor_e_resize:
  2399       newCursor = ::LoadCursor(nullptr, IDC_SIZEWE);
  2400       break;
  2402     case eCursor_nw_resize:
  2403     case eCursor_se_resize:
  2404       newCursor = ::LoadCursor(nullptr, IDC_SIZENWSE);
  2405       break;
  2407     case eCursor_ne_resize:
  2408     case eCursor_sw_resize:
  2409       newCursor = ::LoadCursor(nullptr, IDC_SIZENESW);
  2410       break;
  2412     case eCursor_crosshair:
  2413       newCursor = ::LoadCursor(nullptr, IDC_CROSS);
  2414       break;
  2416     case eCursor_move:
  2417       newCursor = ::LoadCursor(nullptr, IDC_SIZEALL);
  2418       break;
  2420     case eCursor_help:
  2421       newCursor = ::LoadCursor(nullptr, IDC_HELP);
  2422       break;
  2424     case eCursor_copy: // CSS3
  2425       newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
  2426       break;
  2428     case eCursor_alias:
  2429       newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
  2430       break;
  2432     case eCursor_cell:
  2433       newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
  2434       break;
  2436     case eCursor_grab:
  2437       newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
  2438       break;
  2440     case eCursor_grabbing:
  2441       newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
  2442       break;
  2444     case eCursor_spinning:
  2445       newCursor = ::LoadCursor(nullptr, IDC_APPSTARTING);
  2446       break;
  2448     case eCursor_zoom_in:
  2449       newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
  2450       break;
  2452     case eCursor_zoom_out:
  2453       newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
  2454       break;
  2456     case eCursor_not_allowed:
  2457     case eCursor_no_drop:
  2458       newCursor = ::LoadCursor(nullptr, IDC_NO);
  2459       break;
  2461     case eCursor_col_resize:
  2462       newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
  2463       break;
  2465     case eCursor_row_resize:
  2466       newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
  2467       break;
  2469     case eCursor_vertical_text:
  2470       newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT));
  2471       break;
  2473     case eCursor_all_scroll:
  2474       // XXX not 100% appropriate perhaps
  2475       newCursor = ::LoadCursor(nullptr, IDC_SIZEALL);
  2476       break;
  2478     case eCursor_nesw_resize:
  2479       newCursor = ::LoadCursor(nullptr, IDC_SIZENESW);
  2480       break;
  2482     case eCursor_nwse_resize:
  2483       newCursor = ::LoadCursor(nullptr, IDC_SIZENWSE);
  2484       break;
  2486     case eCursor_ns_resize:
  2487       newCursor = ::LoadCursor(nullptr, IDC_SIZENS);
  2488       break;
  2490     case eCursor_ew_resize:
  2491       newCursor = ::LoadCursor(nullptr, IDC_SIZEWE);
  2492       break;
  2494     case eCursor_none:
  2495       newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
  2496       break;
  2498     default:
  2499       NS_ERROR("Invalid cursor type");
  2500       break;
  2503   if (nullptr != newCursor) {
  2504     mCursor = aCursor;
  2505     HCURSOR oldCursor = ::SetCursor(newCursor);
  2507     if (sHCursor == oldCursor) {
  2508       NS_IF_RELEASE(sCursorImgContainer);
  2509       if (sHCursor != nullptr)
  2510         ::DestroyIcon(sHCursor);
  2511       sHCursor = nullptr;
  2515   return NS_OK;
  2518 // Setting the actual cursor
  2519 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
  2520                                   uint32_t aHotspotX, uint32_t aHotspotY)
  2522   if (sCursorImgContainer == aCursor && sHCursor) {
  2523     ::SetCursor(sHCursor);
  2524     return NS_OK;
  2527   int32_t width;
  2528   int32_t height;
  2530   nsresult rv;
  2531   rv = aCursor->GetWidth(&width);
  2532   NS_ENSURE_SUCCESS(rv, rv);
  2533   rv = aCursor->GetHeight(&height);
  2534   NS_ENSURE_SUCCESS(rv, rv);
  2536   // Reject cursors greater than 128 pixels in either direction, to prevent
  2537   // spoofing.
  2538   // XXX ideally we should rescale. Also, we could modify the API to
  2539   // allow trusted content to set larger cursors.
  2540   if (width > 128 || height > 128)
  2541     return NS_ERROR_NOT_AVAILABLE;
  2543   HCURSOR cursor;
  2544   // No scaling
  2545   gfxIntSize size(0, 0);
  2546   rv = nsWindowGfx::CreateIcon(aCursor, true, aHotspotX, aHotspotY, size, &cursor);
  2547   NS_ENSURE_SUCCESS(rv, rv);
  2549   mCursor = nsCursor(-1);
  2550   ::SetCursor(cursor);
  2552   NS_IF_RELEASE(sCursorImgContainer);
  2553   sCursorImgContainer = aCursor;
  2554   NS_ADDREF(sCursorImgContainer);
  2556   if (sHCursor != nullptr)
  2557     ::DestroyIcon(sHCursor);
  2558   sHCursor = cursor;
  2560   return NS_OK;
  2563 /**************************************************************
  2565  * SECTION: nsIWidget::Get/SetTransparencyMode
  2567  * Manage the transparency mode of the top-level window
  2568  * containing this widget.
  2570  **************************************************************/
  2572 #ifdef MOZ_XUL
  2573 nsTransparencyMode nsWindow::GetTransparencyMode()
  2575   return GetTopLevelWindow(true)->GetWindowTranslucencyInner();
  2578 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
  2580   GetTopLevelWindow(true)->SetWindowTranslucencyInner(aMode);
  2583 static const nsIntRegion
  2584 RegionFromArray(const nsTArray<nsIntRect>& aRects)
  2586   nsIntRegion region;
  2587   for (uint32_t i = 0; i < aRects.Length(); ++i) {
  2588     region.Or(region, aRects[i]);
  2590   return region;
  2593 void nsWindow::UpdateOpaqueRegion(const nsIntRegion &aOpaqueRegion)
  2595   if (!HasGlass() || GetParent())
  2596     return;
  2598   // If there is no opaque region or hidechrome=true, set margins
  2599   // to support a full sheet of glass. Comments in MSDN indicate
  2600   // all values must be set to -1 to get a full sheet of glass.
  2601   MARGINS margins = { -1, -1, -1, -1 };
  2602   if (!aOpaqueRegion.IsEmpty()) {
  2603     nsIntRect pluginBounds;
  2604     for (nsIWidget* child = GetFirstChild(); child; child = child->GetNextSibling()) {
  2605       if (child->WindowType() == eWindowType_plugin) {
  2606         // Collect the bounds of all plugins for GetLargestRectangle.
  2607         nsIntRect childBounds;
  2608         child->GetBounds(childBounds);
  2609         pluginBounds.UnionRect(pluginBounds, childBounds);
  2613     nsIntRect clientBounds;
  2614     GetClientBounds(clientBounds);
  2616     // Find the largest rectangle and use that to calculate the inset. Our top
  2617     // priority is to include the bounds of all plugins.
  2618     nsIntRect largest = aOpaqueRegion.GetLargestRectangle(pluginBounds);
  2619     margins.cxLeftWidth = largest.x;
  2620     margins.cxRightWidth = clientBounds.width - largest.XMost();
  2621     margins.cyBottomHeight = clientBounds.height - largest.YMost();
  2622     if (mCustomNonClient) {
  2623       // The minimum glass height must be the caption buttons height,
  2624       // otherwise the buttons are drawn incorrectly.
  2625       largest.y = std::max<uint32_t>(largest.y,
  2626                          nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cy);
  2628     margins.cyTopHeight = largest.y;
  2631   // Only update glass area if there are changes
  2632   if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) {
  2633     mGlassMargins = margins;
  2634     UpdateGlass();
  2638 void nsWindow::UpdateGlass()
  2640   MARGINS margins = mGlassMargins;
  2642   // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
  2643   //                          rendered based on the window style.
  2644   // DWMNCRP_ENABLED        - The non-client area rendering is
  2645   //                          enabled; the window style is ignored.
  2646   DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE;
  2647   switch (mTransparencyMode) {
  2648   case eTransparencyBorderlessGlass:
  2649     // Only adjust if there is some opaque rectangle
  2650     if (margins.cxLeftWidth >= 0) {
  2651       margins.cxLeftWidth += kGlassMarginAdjustment;
  2652       margins.cyTopHeight += kGlassMarginAdjustment;
  2653       margins.cxRightWidth += kGlassMarginAdjustment;
  2654       margins.cyBottomHeight += kGlassMarginAdjustment;
  2656     // Fall through
  2657   case eTransparencyGlass:
  2658     policy = DWMNCRP_ENABLED;
  2659     break;
  2662   PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
  2663          ("glass margins: left:%d top:%d right:%d bottom:%d\n",
  2664           margins.cxLeftWidth, margins.cyTopHeight,
  2665           margins.cxRightWidth, margins.cyBottomHeight));
  2667   // Extends the window frame behind the client area
  2668   if (nsUXThemeData::CheckForCompositor()) {
  2669     WinUtils::dwmExtendFrameIntoClientAreaPtr(mWnd, &margins);
  2670     WinUtils::dwmSetWindowAttributePtr(mWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy);
  2673 #endif
  2675 /**************************************************************
  2677  * SECTION: nsIWidget::HideWindowChrome
  2679  * Show or hide window chrome.
  2681  **************************************************************/
  2683 NS_IMETHODIMP nsWindow::HideWindowChrome(bool aShouldHide)
  2685   HWND hwnd = WinUtils::GetTopLevelHWND(mWnd, true);
  2686   if (!WinUtils::GetNSWindowPtr(hwnd))
  2688     NS_WARNING("Trying to hide window decorations in an embedded context");
  2689     return NS_ERROR_FAILURE;
  2692   if (mHideChrome == aShouldHide)
  2693     return NS_OK;
  2695   DWORD_PTR style, exStyle;
  2696   mHideChrome = aShouldHide;
  2697   if (aShouldHide) {
  2698     DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
  2699     DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
  2701     style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
  2702     exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
  2703                               WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
  2705     mOldStyle = tempStyle;
  2706     mOldExStyle = tempExStyle;
  2708   else {
  2709     if (!mOldStyle || !mOldExStyle) {
  2710       mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
  2711       mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
  2714     style = mOldStyle;
  2715     exStyle = mOldExStyle;
  2718   VERIFY_WINDOW_STYLE(style);
  2719   ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
  2720   ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
  2722   return NS_OK;
  2725 /**************************************************************
  2727  * SECTION: nsWindow::Invalidate
  2729  * Invalidate an area of the client for painting.
  2731  **************************************************************/
  2733 // Invalidate this component visible area
  2734 NS_METHOD nsWindow::Invalidate(bool aEraseBackground, 
  2735                                bool aUpdateNCArea,
  2736                                bool aIncludeChildren)
  2738   if (!mWnd) {
  2739     return NS_OK;
  2742 #ifdef WIDGET_DEBUG_OUTPUT
  2743   debug_DumpInvalidate(stdout,
  2744                        this,
  2745                        nullptr,
  2746                        nsAutoCString("noname"),
  2747                        (int32_t) mWnd);
  2748 #endif // WIDGET_DEBUG_OUTPUT
  2750   DWORD flags = RDW_INVALIDATE;
  2751   if (aEraseBackground) {
  2752     flags |= RDW_ERASE;
  2754   if (aUpdateNCArea) {
  2755     flags |= RDW_FRAME;
  2757   if (aIncludeChildren) {
  2758     flags |= RDW_ALLCHILDREN;
  2761   VERIFY(::RedrawWindow(mWnd, nullptr, nullptr, flags));
  2762   return NS_OK;
  2765 // Invalidate this component visible area
  2766 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect)
  2768   if (mWnd)
  2770 #ifdef WIDGET_DEBUG_OUTPUT
  2771     debug_DumpInvalidate(stdout,
  2772                          this,
  2773                          &aRect,
  2774                          nsAutoCString("noname"),
  2775                          (int32_t) mWnd);
  2776 #endif // WIDGET_DEBUG_OUTPUT
  2778     RECT rect;
  2780     rect.left   = aRect.x;
  2781     rect.top    = aRect.y;
  2782     rect.right  = aRect.x + aRect.width;
  2783     rect.bottom = aRect.y + aRect.height;
  2785     VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
  2787   return NS_OK;
  2790 NS_IMETHODIMP
  2791 nsWindow::MakeFullScreen(bool aFullScreen)
  2793   // taskbarInfo will be nullptr pre Windows 7 until Bug 680227 is resolved.
  2794   nsCOMPtr<nsIWinTaskbar> taskbarInfo =
  2795     do_GetService(NS_TASKBAR_CONTRACTID);
  2797   mFullscreenMode = aFullScreen;
  2798   if (aFullScreen) {
  2799     if (mSizeMode == nsSizeMode_Fullscreen)
  2800       return NS_OK;
  2801     mOldSizeMode = mSizeMode;
  2802     SetSizeMode(nsSizeMode_Fullscreen);
  2804     // Notify the taskbar that we will be entering full screen mode.
  2805     if (taskbarInfo) {
  2806       taskbarInfo->PrepareFullScreenHWND(mWnd, TRUE);
  2808   } else {
  2809     SetSizeMode(mOldSizeMode);
  2812   UpdateNonClientMargins();
  2814   bool visible = mIsVisible;
  2815   if (mOldSizeMode == nsSizeMode_Normal)
  2816     Show(false);
  2818   // Will call hide chrome, reposition window. Note this will
  2819   // also cache dimensions for restoration, so it should only
  2820   // be called once per fullscreen request.
  2821   nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen);
  2823   if (visible) {
  2824     Show(true);
  2825     Invalidate();
  2828   // Notify the taskbar that we have exited full screen mode.
  2829   if (!aFullScreen && taskbarInfo) {
  2830     taskbarInfo->PrepareFullScreenHWND(mWnd, FALSE);
  2833   if (mWidgetListener)
  2834     mWidgetListener->SizeModeChanged(mSizeMode);
  2836   return rv;
  2839 /**************************************************************
  2841  * SECTION: Native data storage
  2843  * nsIWidget::GetNativeData
  2844  * nsIWidget::FreeNativeData
  2846  * Set or clear native data based on a constant.
  2848  **************************************************************/
  2850 // Return some native data according to aDataType
  2851 void* nsWindow::GetNativeData(uint32_t aDataType)
  2853   nsAutoString className;
  2854   switch (aDataType) {
  2855     case NS_NATIVE_TMP_WINDOW:
  2856       GetWindowClass(className);
  2857       return (void*)::CreateWindowExW(mIsRTL ? WS_EX_LAYOUTRTL : 0,
  2858                                       className.get(),
  2859                                       L"",
  2860                                       WS_CHILD,
  2861                                       CW_USEDEFAULT,
  2862                                       CW_USEDEFAULT,
  2863                                       CW_USEDEFAULT,
  2864                                       CW_USEDEFAULT,
  2865                                       mWnd,
  2866                                       nullptr,
  2867                                       nsToolkit::mDllInstance,
  2868                                       nullptr);
  2869     case NS_NATIVE_PLUGIN_PORT:
  2870     case NS_NATIVE_WIDGET:
  2871     case NS_NATIVE_WINDOW:
  2872     case NS_NATIVE_SHAREABLE_WINDOW:
  2873       return (void*)mWnd;
  2874     case NS_NATIVE_GRAPHIC:
  2875       // XXX:  This is sleezy!!  Remember to Release the DC after using it!
  2876 #ifdef MOZ_XUL
  2877       return (void*)(eTransparencyTransparent == mTransparencyMode) ?
  2878         mMemoryDC : ::GetDC(mWnd);
  2879 #else
  2880       return (void*)::GetDC(mWnd);
  2881 #endif
  2883     case NS_NATIVE_TSF_THREAD_MGR:
  2884     case NS_NATIVE_TSF_CATEGORY_MGR:
  2885     case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
  2886       return IMEHandler::GetNativeData(aDataType);
  2888     default:
  2889       break;
  2892   return nullptr;
  2895 // Free some native data according to aDataType
  2896 void nsWindow::FreeNativeData(void * data, uint32_t aDataType)
  2898   switch (aDataType)
  2900     case NS_NATIVE_GRAPHIC:
  2901 #ifdef MOZ_XUL
  2902       if (eTransparencyTransparent != mTransparencyMode)
  2903         ::ReleaseDC(mWnd, (HDC)data);
  2904 #else
  2905       ::ReleaseDC(mWnd, (HDC)data);
  2906 #endif
  2907       break;
  2908     case NS_NATIVE_WIDGET:
  2909     case NS_NATIVE_WINDOW:
  2910     case NS_NATIVE_PLUGIN_PORT:
  2911       break;
  2912     default:
  2913       break;
  2917 /**************************************************************
  2919  * SECTION: nsIWidget::SetTitle
  2921  * Set the main windows title text.
  2923  **************************************************************/
  2925 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
  2927   const nsString& strTitle = PromiseFlatString(aTitle);
  2928   ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get());
  2929   return NS_OK;
  2932 /**************************************************************
  2934  * SECTION: nsIWidget::SetIcon
  2936  * Set the main windows icon.
  2938  **************************************************************/
  2940 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec) 
  2942   // Assume the given string is a local identifier for an icon file.
  2944   nsCOMPtr<nsIFile> iconFile;
  2945   ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
  2946                   getter_AddRefs(iconFile));
  2947   if (!iconFile)
  2948     return NS_OK; // not an error if icon is not found
  2950   nsAutoString iconPath;
  2951   iconFile->GetPath(iconPath);
  2953   // XXX this should use MZLU (see bug 239279)
  2955   ::SetLastError(0);
  2957   HICON bigIcon = (HICON)::LoadImageW(nullptr,
  2958                                       (LPCWSTR)iconPath.get(),
  2959                                       IMAGE_ICON,
  2960                                       ::GetSystemMetrics(SM_CXICON),
  2961                                       ::GetSystemMetrics(SM_CYICON),
  2962                                       LR_LOADFROMFILE );
  2963   HICON smallIcon = (HICON)::LoadImageW(nullptr,
  2964                                         (LPCWSTR)iconPath.get(),
  2965                                         IMAGE_ICON,
  2966                                         ::GetSystemMetrics(SM_CXSMICON),
  2967                                         ::GetSystemMetrics(SM_CYSMICON),
  2968                                         LR_LOADFROMFILE );
  2970   if (bigIcon) {
  2971     HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon);
  2972     if (icon)
  2973       ::DestroyIcon(icon);
  2974     mIconBig = bigIcon;
  2976 #ifdef DEBUG_SetIcon
  2977   else {
  2978     NS_LossyConvertUTF16toASCII cPath(iconPath);
  2979     PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
  2980            ("\nIcon load error; icon=%s, rc=0x%08X\n\n", 
  2981             cPath.get(), ::GetLastError()));
  2983 #endif
  2984   if (smallIcon) {
  2985     HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon);
  2986     if (icon)
  2987       ::DestroyIcon(icon);
  2988     mIconSmall = smallIcon;
  2990 #ifdef DEBUG_SetIcon
  2991   else {
  2992     NS_LossyConvertUTF16toASCII cPath(iconPath);
  2993     PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
  2994            ("\nSmall icon load error; icon=%s, rc=0x%08X\n\n", 
  2995             cPath.get(), ::GetLastError()));
  2997 #endif
  2998   return NS_OK;
  3001 /**************************************************************
  3003  * SECTION: nsIWidget::WidgetToScreenOffset
  3005  * Return this widget's origin in screen coordinates.
  3007  **************************************************************/
  3009 nsIntPoint nsWindow::WidgetToScreenOffset()
  3011   POINT point;
  3012   point.x = 0;
  3013   point.y = 0;
  3014   ::ClientToScreen(mWnd, &point);
  3015   return nsIntPoint(point.x, point.y);
  3018 nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize)
  3020   if (mWindowType == eWindowType_popup && !IsPopupWithTitleBar())
  3021     return aClientSize;
  3023   // just use (200, 200) as the position
  3024   RECT r;
  3025   r.left = 200;
  3026   r.top = 200;
  3027   r.right = 200 + aClientSize.width;
  3028   r.bottom = 200 + aClientSize.height;
  3029   ::AdjustWindowRectEx(&r, WindowStyle(), false, WindowExStyle());
  3031   return nsIntSize(r.right - r.left, r.bottom - r.top);
  3034 /**************************************************************
  3036  * SECTION: nsIWidget::EnableDragDrop
  3038  * Enables/Disables drag and drop of files on this widget.
  3040  **************************************************************/
  3042 NS_METHOD nsWindow::EnableDragDrop(bool aEnable)
  3044   NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()");
  3046   nsresult rv = NS_ERROR_FAILURE;
  3047   if (aEnable) {
  3048     if (nullptr == mNativeDragTarget) {
  3049        mNativeDragTarget = new nsNativeDragTarget(this);
  3050        if (nullptr != mNativeDragTarget) {
  3051          mNativeDragTarget->AddRef();
  3052          if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) {
  3053            if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) {
  3054              rv = NS_OK;
  3059   } else {
  3060     if (nullptr != mWnd && nullptr != mNativeDragTarget) {
  3061       ::RevokeDragDrop(mWnd);
  3062       if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) {
  3063         rv = NS_OK;
  3065       mNativeDragTarget->DragCancel();
  3066       NS_RELEASE(mNativeDragTarget);
  3069   return rv;
  3072 /**************************************************************
  3074  * SECTION: nsIWidget::CaptureMouse
  3076  * Enables/Disables system mouse capture.
  3078  **************************************************************/
  3080 NS_METHOD nsWindow::CaptureMouse(bool aCapture)
  3082   if (!nsToolkit::gMouseTrailer) {
  3083     NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
  3084     return NS_OK;
  3087   if (aCapture) {
  3088     nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd);
  3089     ::SetCapture(mWnd);
  3090   } else {
  3091     nsToolkit::gMouseTrailer->SetCaptureWindow(nullptr);
  3092     ::ReleaseCapture();
  3094   sIsInMouseCapture = aCapture;
  3095   return NS_OK;
  3098 /**************************************************************
  3100  * SECTION: nsIWidget::CaptureRollupEvents
  3102  * Dealing with event rollup on destroy for popups. Enables &
  3103  * Disables system capture of any and all events that would
  3104  * cause a dropdown to be rolled up.
  3106  **************************************************************/
  3108 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
  3109                                             bool aDoCapture)
  3111   if (aDoCapture) {
  3112     gRollupListener = aListener;
  3113     if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
  3114       RegisterSpecialDropdownHooks();
  3116     sProcessHook = true;
  3117   } else {
  3118     gRollupListener = nullptr;
  3119     sProcessHook = false;
  3120     UnregisterSpecialDropdownHooks();
  3123   return NS_OK;
  3126 /**************************************************************
  3128  * SECTION: nsIWidget::GetAttention
  3130  * Bring this window to the user's attention.
  3132  **************************************************************/
  3134 // Draw user's attention to this window until it comes to foreground.
  3135 NS_IMETHODIMP
  3136 nsWindow::GetAttention(int32_t aCycleCount)
  3138   // Got window?
  3139   if (!mWnd)
  3140     return NS_ERROR_NOT_INITIALIZED;
  3142   HWND flashWnd = WinUtils::GetTopLevelHWND(mWnd, false, false);
  3143   HWND fgWnd = ::GetForegroundWindow();
  3144   // Don't flash if the flash count is 0 or if the foreground window is our
  3145   // window handle or that of our owned-most window.
  3146   if (aCycleCount == 0 || 
  3147       flashWnd == fgWnd ||
  3148       flashWnd == WinUtils::GetTopLevelHWND(fgWnd, false, false)) {
  3149     return NS_OK;
  3152   DWORD defaultCycleCount = 0;
  3153   ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
  3155   FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
  3156     FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 };
  3157   ::FlashWindowEx(&flashInfo);
  3159   return NS_OK;
  3162 void nsWindow::StopFlashing()
  3164   HWND flashWnd = mWnd;
  3165   while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
  3166     flashWnd = ownerWnd;
  3169   FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
  3170     FLASHW_STOP, 0, 0 };
  3171   ::FlashWindowEx(&flashInfo);
  3174 /**************************************************************
  3176  * SECTION: nsIWidget::HasPendingInputEvent
  3178  * Ask whether there user input events pending.  All input events are
  3179  * included, including those not targeted at this nsIwidget instance.
  3181  **************************************************************/
  3183 bool
  3184 nsWindow::HasPendingInputEvent()
  3186   // If there is pending input or the user is currently
  3187   // moving the window then return true.
  3188   // Note: When the user is moving the window WIN32 spins
  3189   // a separate event loop and input events are not
  3190   // reported to the application.
  3191   if (HIWORD(GetQueueStatus(QS_INPUT)))
  3192     return true;
  3193   GUITHREADINFO guiInfo;
  3194   guiInfo.cbSize = sizeof(GUITHREADINFO);
  3195   if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo))
  3196     return false;
  3197   return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE);
  3200 /**************************************************************
  3202  * SECTION: nsIWidget::GetLayerManager
  3204  * Get the layer manager associated with this widget.
  3206  **************************************************************/
  3208 struct LayerManagerPrefs {
  3209   LayerManagerPrefs()
  3210     : mAccelerateByDefault(true)
  3211     , mDisableAcceleration(false)
  3212     , mPreferOpenGL(false)
  3213     , mPreferD3D9(false)
  3214   {}
  3215   bool mAccelerateByDefault;
  3216   bool mDisableAcceleration;
  3217   bool mForceAcceleration;
  3218   bool mPreferOpenGL;
  3219   bool mPreferD3D9;
  3220 };
  3222 static void
  3223 GetLayerManagerPrefs(LayerManagerPrefs* aManagerPrefs)
  3225   Preferences::GetBool("layers.acceleration.disabled",
  3226                        &aManagerPrefs->mDisableAcceleration);
  3227   Preferences::GetBool("layers.acceleration.force-enabled",
  3228                        &aManagerPrefs->mForceAcceleration);
  3229   Preferences::GetBool("layers.prefer-opengl",
  3230                        &aManagerPrefs->mPreferOpenGL);
  3231   Preferences::GetBool("layers.prefer-d3d9",
  3232                        &aManagerPrefs->mPreferD3D9);
  3234   const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
  3235   aManagerPrefs->mAccelerateByDefault =
  3236     aManagerPrefs->mAccelerateByDefault ||
  3237     (acceleratedEnv && (*acceleratedEnv != '0'));
  3239   bool safeMode = false;
  3240   nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
  3241   if (xr)
  3242     xr->GetInSafeMode(&safeMode);
  3243   aManagerPrefs->mDisableAcceleration =
  3244     aManagerPrefs->mDisableAcceleration || safeMode;
  3247 LayerManager*
  3248 nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
  3249                           LayersBackend aBackendHint,
  3250                           LayerManagerPersistence aPersistence,
  3251                           bool* aAllowRetaining)
  3253   if (aAllowRetaining) {
  3254     *aAllowRetaining = true;
  3257 #ifdef MOZ_ENABLE_D3D10_LAYER
  3258   if (mLayerManager) {
  3259     if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_D3D10)
  3261       LayerManagerD3D10 *layerManagerD3D10 =
  3262         static_cast<LayerManagerD3D10*>(mLayerManager.get());
  3263       if (layerManagerD3D10->device() !=
  3264           gfxWindowsPlatform::GetPlatform()->GetD3D10Device())
  3266         MOZ_ASSERT(!mLayerManager->IsInTransaction());
  3268         mLayerManager->Destroy();
  3269         mLayerManager = nullptr;
  3273 #endif
  3275   RECT windowRect;
  3276   ::GetClientRect(mWnd, &windowRect);
  3278   // Try OMTC first.
  3279   if (!mLayerManager && ShouldUseOffMainThreadCompositing()) {
  3280     // e10s uses the parameter to pass in the shadow manager from the TabChild
  3281     // so we don't expect to see it there since this doesn't support e10s.
  3282     NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s");
  3283     CreateCompositor();
  3286   if (!mLayerManager ||
  3287       (!sAllowD3D9 && aPersistence == LAYER_MANAGER_PERSISTENT &&
  3288         mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC &&
  3289         !ShouldUseOffMainThreadCompositing())) {
  3290     // If D3D9 is not currently allowed but the permanent manager is required,
  3291     // -and- we're currently using basic layers, run through this check.
  3292     LayerManagerPrefs prefs;
  3293     GetLayerManagerPrefs(&prefs);
  3295     /* We don't currently support using an accelerated layer manager with
  3296      * transparent windows so don't even try. I'm also not sure if we even
  3297      * want to support this case. See bug #593471 */
  3298     if (eTransparencyTransparent == mTransparencyMode ||
  3299         prefs.mDisableAcceleration ||
  3300         windowRect.right - windowRect.left > MAX_ACCELERATED_DIMENSION ||
  3301         windowRect.bottom - windowRect.top > MAX_ACCELERATED_DIMENSION)
  3302       mUseLayersAcceleration = false;
  3303     else if (prefs.mAccelerateByDefault)
  3304       mUseLayersAcceleration = true;
  3306     if (mUseLayersAcceleration) {
  3307       if (aPersistence == LAYER_MANAGER_PERSISTENT && !sAllowD3D9) {
  3308         MOZ_ASSERT(!mLayerManager || !mLayerManager->IsInTransaction());
  3310         // This will clear out our existing layer manager if we have one since
  3311         // if we hit this with a LayerManager we're always using BasicLayers.
  3312         nsToolkit::StartAllowingD3D9();
  3315 #ifdef MOZ_ENABLE_D3D10_LAYER
  3316       if (!prefs.mPreferD3D9 && !prefs.mPreferOpenGL) {
  3317         nsRefPtr<LayerManagerD3D10> layerManager =
  3318           new LayerManagerD3D10(this);
  3319         if (layerManager->Initialize(prefs.mForceAcceleration)) {
  3320           mLayerManager = layerManager;
  3323 #endif
  3324 #ifdef MOZ_ENABLE_D3D9_LAYER
  3325       if (!prefs.mPreferOpenGL && !mLayerManager && sAllowD3D9) {
  3326         nsRefPtr<LayerManagerD3D9> layerManager =
  3327           new LayerManagerD3D9(this);
  3328         if (layerManager->Initialize(prefs.mForceAcceleration)) {
  3329           mLayerManager = layerManager;
  3332 #endif
  3335     // Fall back to software if we couldn't use any hardware backends.
  3336     if (!mLayerManager) {
  3337       mLayerManager = CreateBasicLayerManager();
  3341   NS_ASSERTION(mLayerManager, "Couldn't provide a valid layer manager.");
  3343   return mLayerManager;
  3346 /**************************************************************
  3348  * SECTION: nsIWidget::GetThebesSurface
  3350  * Get the Thebes surface associated with this widget.
  3352  **************************************************************/
  3354 gfxASurface *nsWindow::GetThebesSurface()
  3356   if (mPaintDC)
  3357     return (new gfxWindowsSurface(mPaintDC));
  3359   uint32_t flags = gfxWindowsSurface::FLAG_TAKE_DC;
  3360   if (mTransparencyMode != eTransparencyOpaque) {
  3361       flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT;
  3363   return (new gfxWindowsSurface(mWnd, flags));
  3366 /**************************************************************
  3368  * SECTION: nsIWidget::OnDefaultButtonLoaded
  3370  * Called after the dialog is loaded and it has a default button.
  3372  **************************************************************/
  3374 NS_IMETHODIMP
  3375 nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect)
  3377   if (aButtonRect.IsEmpty())
  3378     return NS_OK;
  3380   // Don't snap when we are not active.
  3381   HWND activeWnd = ::GetActiveWindow();
  3382   if (activeWnd != ::GetForegroundWindow() ||
  3383       WinUtils::GetTopLevelHWND(mWnd, true) !=
  3384         WinUtils::GetTopLevelHWND(activeWnd, true)) {
  3385     return NS_OK;
  3388   bool isAlwaysSnapCursor =
  3389     Preferences::GetBool("ui.cursor_snapping.always_enabled", false);
  3391   if (!isAlwaysSnapCursor) {
  3392     BOOL snapDefaultButton;
  3393     if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0,
  3394                                 &snapDefaultButton, 0) || !snapDefaultButton)
  3395       return NS_OK;
  3398   nsIntRect widgetRect;
  3399   nsresult rv = GetScreenBounds(widgetRect);
  3400   NS_ENSURE_SUCCESS(rv, rv);
  3401   nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft());
  3403   nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2,
  3404                             buttonRect.y + buttonRect.height / 2);
  3405   // The center of the button can be outside of the widget.
  3406   // E.g., it could be hidden by scrolling.
  3407   if (!widgetRect.Contains(centerOfButton)) {
  3408     return NS_OK;
  3411   if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) {
  3412     NS_ERROR("SetCursorPos failed");
  3413     return NS_ERROR_FAILURE;
  3415   return NS_OK;
  3418 NS_IMETHODIMP
  3419 nsWindow::OverrideSystemMouseScrollSpeed(double aOriginalDeltaX,
  3420                                          double aOriginalDeltaY,
  3421                                          double& aOverriddenDeltaX,
  3422                                          double& aOverriddenDeltaY)
  3424   // The default vertical and horizontal scrolling speed is 3, this is defined
  3425   // on the document of SystemParametersInfo in MSDN.
  3426   const uint32_t kSystemDefaultScrollingSpeed = 3;
  3428   double absOriginDeltaX = Abs(aOriginalDeltaX);
  3429   double absOriginDeltaY = Abs(aOriginalDeltaY);
  3431   // Compute the simple overridden speed.
  3432   double absComputedOverriddenDeltaX, absComputedOverriddenDeltaY;
  3433   nsresult rv =
  3434     nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDeltaX,
  3435                                                  absOriginDeltaY,
  3436                                                  absComputedOverriddenDeltaX,
  3437                                                  absComputedOverriddenDeltaY);
  3438   NS_ENSURE_SUCCESS(rv, rv);
  3440   aOverriddenDeltaX = aOriginalDeltaX;
  3441   aOverriddenDeltaY = aOriginalDeltaY;
  3443   if (absComputedOverriddenDeltaX == absOriginDeltaX &&
  3444       absComputedOverriddenDeltaY == absOriginDeltaY) {
  3445     // We don't override now.
  3446     return NS_OK;
  3449   // Otherwise, we should check whether the user customized the system settings
  3450   // or not.  If the user did it, we should respect the will.
  3451   UINT systemSpeed;
  3452   if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) {
  3453     return NS_ERROR_FAILURE;
  3455   // The default vertical scrolling speed is 3, this is defined on the document
  3456   // of SystemParametersInfo in MSDN.
  3457   if (systemSpeed != kSystemDefaultScrollingSpeed) {
  3458     return NS_OK;
  3461   // Only Vista and later, Windows has the system setting of horizontal
  3462   // scrolling by the mouse wheel.
  3463   if (IsVistaOrLater()) {
  3464     if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) {
  3465       return NS_ERROR_FAILURE;
  3467     // The default horizontal scrolling speed is 3, this is defined on the
  3468     // document of SystemParametersInfo in MSDN.
  3469     if (systemSpeed != kSystemDefaultScrollingSpeed) {
  3470       return NS_OK;
  3474   // Limit the overridden delta value from the system settings.  The mouse
  3475   // driver might accelerate the scrolling speed already.  If so, we shouldn't
  3476   // override the scrolling speed for preventing the unexpected high speed
  3477   // scrolling.
  3478   double absDeltaLimitX, absDeltaLimitY;
  3479   rv =
  3480     nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed,
  3481                                                  kSystemDefaultScrollingSpeed,
  3482                                                  absDeltaLimitX,
  3483                                                  absDeltaLimitY);
  3484   NS_ENSURE_SUCCESS(rv, rv);
  3486   // If the given delta is larger than our computed limitation value, the delta
  3487   // was accelerated by the mouse driver.  So, we should do nothing here.
  3488   if (absDeltaLimitX <= absOriginDeltaX || absDeltaLimitY <= absOriginDeltaY) {
  3489     return NS_OK;
  3492   aOverriddenDeltaX = std::min(absComputedOverriddenDeltaX, absDeltaLimitX);
  3493   aOverriddenDeltaY = std::min(absComputedOverriddenDeltaY, absDeltaLimitY);
  3495   if (aOriginalDeltaX < 0) {
  3496     aOverriddenDeltaX *= -1;
  3498   if (aOriginalDeltaY < 0) {
  3499     aOverriddenDeltaY *= -1;
  3501   return NS_OK;
  3504 mozilla::TemporaryRef<mozilla::gfx::DrawTarget>
  3505 nsWindow::StartRemoteDrawing()
  3507   MOZ_ASSERT(!mCompositeDC);
  3508   NS_ASSERTION(IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D) ||
  3509                IsRenderMode(gfxWindowsPlatform::RENDER_GDI),
  3510                "Unexpected render mode for remote drawing");
  3512   HDC dc = (HDC)GetNativeData(NS_NATIVE_GRAPHIC);
  3513   nsRefPtr<gfxASurface> surf;
  3515   if (mTransparencyMode == eTransparencyTransparent) {
  3516     if (!mTransparentSurface) {
  3517       SetupTranslucentWindowMemoryBitmap(mTransparencyMode);
  3519     if (mTransparentSurface) {
  3520       surf = mTransparentSurface;
  3524   if (!surf) {
  3525     if (!dc) {
  3526       return nullptr;
  3528     uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 :
  3529         gfxWindowsSurface::FLAG_IS_TRANSPARENT;
  3530     surf = new gfxWindowsSurface(dc, flags);
  3533   mozilla::gfx::IntSize size(surf->GetSize().width, surf->GetSize().height);
  3534   if (size.width <= 0 || size.height <= 0) {
  3535     if (dc) {
  3536       FreeNativeData(dc, NS_NATIVE_GRAPHIC);
  3538     return nullptr;
  3541   MOZ_ASSERT(!mCompositeDC);
  3542   mCompositeDC = dc;
  3544   return mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(surf->CairoSurface(), size);
  3547 void
  3548 nsWindow::EndRemoteDrawing()
  3550   if (mTransparencyMode == eTransparencyTransparent) {
  3551     MOZ_ASSERT(IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D)
  3552                || mTransparentSurface);
  3553     UpdateTranslucentWindow();
  3555   if (mCompositeDC) {
  3556     FreeNativeData(mCompositeDC, NS_NATIVE_GRAPHIC);
  3558   mCompositeDC = nullptr;
  3561 void
  3562 nsWindow::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries)
  3564   nsIntRegion clearRegion;
  3565   for (size_t i = 0; i < aThemeGeometries.Length(); i++) {
  3566     if ((aThemeGeometries[i].mWidgetType == NS_THEME_WINDOW_BUTTON_BOX ||
  3567          aThemeGeometries[i].mWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) &&
  3568         nsUXThemeData::CheckForCompositor())
  3570       nsIntRect bounds = aThemeGeometries[i].mRect;
  3571       clearRegion = nsIntRect(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height() - 2.0);
  3572       clearRegion.Or(clearRegion, nsIntRect(bounds.X() + 1.0, bounds.YMost() - 2.0, bounds.Width() - 1.0, 1.0));
  3573       clearRegion.Or(clearRegion, nsIntRect(bounds.X() + 2.0, bounds.YMost() - 1.0, bounds.Width() - 3.0, 1.0));
  3577   nsRefPtr<LayerManager> layerManager = GetLayerManager();
  3578   if (layerManager) {
  3579     layerManager->SetRegionToClear(clearRegion);
  3583 /**************************************************************
  3584  **************************************************************
  3585  **
  3586  ** BLOCK: Moz Events
  3587  **
  3588  ** Moz GUI event management. 
  3589  **
  3590  **************************************************************
  3591  **************************************************************/
  3593 /**************************************************************
  3595  * SECTION: Mozilla event initialization
  3597  * Helpers for initializing moz events.
  3599  **************************************************************/
  3601 // Event intialization
  3602 void nsWindow::InitEvent(WidgetGUIEvent& event, nsIntPoint* aPoint)
  3604   if (nullptr == aPoint) {     // use the point from the event
  3605     // get the message position in client coordinates
  3606     if (mWnd != nullptr) {
  3608       DWORD pos = ::GetMessagePos();
  3609       POINT cpos;
  3611       cpos.x = GET_X_LPARAM(pos);
  3612       cpos.y = GET_Y_LPARAM(pos);
  3614       ::ScreenToClient(mWnd, &cpos);
  3615       event.refPoint.x = cpos.x;
  3616       event.refPoint.y = cpos.y;
  3617     } else {
  3618       event.refPoint.x = 0;
  3619       event.refPoint.y = 0;
  3622   else {  
  3623     // use the point override if provided
  3624     event.refPoint.x = aPoint->x;
  3625     event.refPoint.y = aPoint->y;
  3628   event.time = ::GetMessageTime();
  3631 /**************************************************************
  3633  * SECTION: Moz event dispatch helpers
  3635  * Helpers for dispatching different types of moz events.
  3637  **************************************************************/
  3639 // Main event dispatch. Invokes callback and ProcessEvent method on
  3640 // Event Listener object. Part of nsIWidget.
  3641 NS_IMETHODIMP nsWindow::DispatchEvent(WidgetGUIEvent* event,
  3642                                       nsEventStatus& aStatus)
  3644 #ifdef WIDGET_DEBUG_OUTPUT
  3645   debug_DumpEvent(stdout,
  3646                   event->widget,
  3647                   event,
  3648                   nsAutoCString("something"),
  3649                   (int32_t) mWnd);
  3650 #endif // WIDGET_DEBUG_OUTPUT
  3652   aStatus = nsEventStatus_eIgnore;
  3654   // Top level windows can have a view attached which requires events be sent
  3655   // to the underlying base window and the view. Added when we combined the
  3656   // base chrome window with the main content child for nc client area (title
  3657   // bar) rendering.
  3658   if (mAttachedWidgetListener) {
  3659     aStatus = mAttachedWidgetListener->HandleEvent(event, mUseAttachedEvents);
  3661   else if (mWidgetListener) {
  3662     aStatus = mWidgetListener->HandleEvent(event, mUseAttachedEvents);
  3665   // the window can be destroyed during processing of seemingly innocuous events like, say,
  3666   // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
  3667   // which causes problems with the deleted window. therefore:
  3668   if (mOnDestroyCalled)
  3669     aStatus = nsEventStatus_eConsumeNoDefault;
  3670   return NS_OK;
  3673 bool nsWindow::DispatchStandardEvent(uint32_t aMsg)
  3675   WidgetGUIEvent event(true, aMsg, this);
  3676   InitEvent(event);
  3678   bool result = DispatchWindowEvent(&event);
  3679   return result;
  3682 bool nsWindow::DispatchKeyboardEvent(WidgetGUIEvent* event)
  3684   nsEventStatus status;
  3685   DispatchEvent(event, status);
  3686   return ConvertStatus(status);
  3689 bool nsWindow::DispatchScrollEvent(WidgetGUIEvent* event)
  3691   nsEventStatus status;
  3692   DispatchEvent(event, status);
  3693   return ConvertStatus(status);
  3696 bool nsWindow::DispatchWindowEvent(WidgetGUIEvent* event)
  3698   nsEventStatus status;
  3699   DispatchEvent(event, status);
  3700   return ConvertStatus(status);
  3703 bool nsWindow::DispatchWindowEvent(WidgetGUIEvent* event,
  3704                                    nsEventStatus& aStatus)
  3706   DispatchEvent(event, aStatus);
  3707   return ConvertStatus(aStatus);
  3710 // Recursively dispatch synchronous paints for nsIWidget
  3711 // descendants with invalidated rectangles.
  3712 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
  3714   LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
  3715   if (proc == (LONG_PTR)&nsWindow::WindowProc) {
  3716     // its one of our windows so check to see if it has a
  3717     // invalidated rect. If it does. Dispatch a synchronous
  3718     // paint.
  3719     if (GetUpdateRect(aWnd, nullptr, FALSE))
  3720       VERIFY(::UpdateWindow(aWnd));
  3722   return TRUE;
  3725 // Check for pending paints and dispatch any pending paint
  3726 // messages for any nsIWidget which is a descendant of the
  3727 // top-level window that *this* window is embedded within.
  3728 //
  3729 // Note: We do not dispatch pending paint messages for non
  3730 // nsIWidget managed windows.
  3731 void nsWindow::DispatchPendingEvents()
  3733   if (mPainting) {
  3734     NS_WARNING("We were asked to dispatch pending events during painting, "
  3735                "denying since that's unsafe.");
  3736     return;
  3739   // We need to ensure that reflow events do not get starved.
  3740   // At the same time, we don't want to recurse through here
  3741   // as that would prevent us from dispatching starved paints.
  3742   static int recursionBlocker = 0;
  3743   if (recursionBlocker++ == 0) {
  3744     NS_ProcessPendingEvents(nullptr, PR_MillisecondsToInterval(100));
  3745     --recursionBlocker;
  3748   // Quickly check to see if there are any paint events pending,
  3749   // but only dispatch them if it has been long enough since the
  3750   // last paint completed.
  3751   if (::GetQueueStatus(QS_PAINT) &&
  3752       ((TimeStamp::Now() - mLastPaintEndTime).ToMilliseconds() >= 50)) {
  3753     // Find the top level window.
  3754     HWND topWnd = WinUtils::GetTopLevelHWND(mWnd);
  3756     // Dispatch pending paints for topWnd and all its descendant windows.
  3757     // Note: EnumChildWindows enumerates all descendant windows not just
  3758     // the children (but not the window itself).
  3759     nsWindow::DispatchStarvedPaints(topWnd, 0);
  3760     ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, 0);
  3764 bool nsWindow::DispatchPluginEvent(UINT aMessage,
  3765                                      WPARAM aWParam,
  3766                                      LPARAM aLParam,
  3767                                      bool aDispatchPendingEvents)
  3769   bool ret = nsWindowBase::DispatchPluginEvent(
  3770                WinUtils::InitMSG(aMessage, aWParam, aLParam, mWnd));
  3771   if (aDispatchPendingEvents && !Destroyed()) {
  3772     DispatchPendingEvents();
  3774   return ret;
  3777 // Deal with all sort of mouse event
  3778 bool nsWindow::DispatchMouseEvent(uint32_t aEventType, WPARAM wParam,
  3779                                     LPARAM lParam, bool aIsContextMenuKey,
  3780                                     int16_t aButton, uint16_t aInputSource)
  3782   bool result = false;
  3784   UserActivity();
  3786   if (!mWidgetListener) {
  3787     return result;
  3790   switch (aEventType) {
  3791     case NS_MOUSE_BUTTON_DOWN:
  3792       CaptureMouse(true);
  3793       break;
  3795     // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
  3796     // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
  3797     case NS_MOUSE_BUTTON_UP:
  3798     case NS_MOUSE_MOVE:
  3799     case NS_MOUSE_EXIT:
  3800       if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && sIsInMouseCapture)
  3801         CaptureMouse(false);
  3802       break;
  3804     default:
  3805       break;
  3807   } // switch
  3809   nsIntPoint eventPoint;
  3810   eventPoint.x = GET_X_LPARAM(lParam);
  3811   eventPoint.y = GET_Y_LPARAM(lParam);
  3813   WidgetMouseEvent event(true, aEventType, this, WidgetMouseEvent::eReal,
  3814                          aIsContextMenuKey ? WidgetMouseEvent::eContextMenuKey :
  3815                                              WidgetMouseEvent::eNormal);
  3816   if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) {
  3817     nsIntPoint zero(0, 0);
  3818     InitEvent(event, &zero);
  3819   } else {
  3820     InitEvent(event, &eventPoint);
  3823   ModifierKeyState modifierKeyState;
  3824   modifierKeyState.InitInputEvent(event);
  3825   event.button    = aButton;
  3826   event.inputSource = aInputSource;
  3827   // Convert Mouse events generated by pen device or if mouse not generated from touch
  3828   event.convertToPointer =
  3829     aInputSource == nsIDOMMouseEvent::MOZ_SOURCE_PEN ||
  3830     !(WinUtils::GetIsMouseFromTouch(aEventType) && mTouchWindow);
  3832   nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
  3834   // Suppress mouse moves caused by widget creation
  3835   if (aEventType == NS_MOUSE_MOVE) 
  3837     if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y))
  3838       return result;
  3839     sLastMouseMovePoint.x = mpScreen.x;
  3840     sLastMouseMovePoint.y = mpScreen.y;
  3843   bool insideMovementThreshold = (DeprecatedAbs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
  3844                                    (DeprecatedAbs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
  3846   BYTE eventButton;
  3847   switch (aButton) {
  3848     case WidgetMouseEvent::eLeftButton:
  3849       eventButton = VK_LBUTTON;
  3850       break;
  3851     case WidgetMouseEvent::eMiddleButton:
  3852       eventButton = VK_MBUTTON;
  3853       break;
  3854     case WidgetMouseEvent::eRightButton:
  3855       eventButton = VK_RBUTTON;
  3856       break;
  3857     default:
  3858       eventButton = 0;
  3859       break;
  3862   // Doubleclicks are used to set the click count, then changed to mousedowns
  3863   // We're going to time double-clicks from mouse *up* to next mouse *down*
  3864   LONG curMsgTime = ::GetMessageTime();
  3866   if (aEventType == NS_MOUSE_DOUBLECLICK) {
  3867     event.message = NS_MOUSE_BUTTON_DOWN;
  3868     event.button = aButton;
  3869     sLastClickCount = 2;
  3871   else if (aEventType == NS_MOUSE_BUTTON_UP) {
  3872     // remember when this happened for the next mouse down
  3873     sLastMousePoint.x = eventPoint.x;
  3874     sLastMousePoint.y = eventPoint.y;
  3875     sLastMouseButton = eventButton;
  3877   else if (aEventType == NS_MOUSE_BUTTON_DOWN) {
  3878     // now look to see if we want to convert this to a double- or triple-click
  3879     if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold &&
  3880         eventButton == sLastMouseButton) {
  3881       sLastClickCount ++;
  3882     } else {
  3883       // reset the click count, to count *this* click
  3884       sLastClickCount = 1;
  3886     // Set last Click time on MouseDown only
  3887     sLastMouseDownTime = curMsgTime;
  3889   else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
  3890     sLastClickCount = 0;
  3892   else if (aEventType == NS_MOUSE_EXIT) {
  3893     event.exit = IsTopLevelMouseExit(mWnd) ?
  3894                    WidgetMouseEvent::eTopLevel : WidgetMouseEvent::eChild;
  3896   event.clickCount = sLastClickCount;
  3898 #ifdef NS_DEBUG_XX
  3899   PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
  3900          ("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount));
  3901 #endif
  3903   NPEvent pluginEvent;
  3905   switch (aEventType)
  3907     case NS_MOUSE_BUTTON_DOWN:
  3908       switch (aButton) {
  3909         case WidgetMouseEvent::eLeftButton:
  3910           pluginEvent.event = WM_LBUTTONDOWN;
  3911           break;
  3912         case WidgetMouseEvent::eMiddleButton:
  3913           pluginEvent.event = WM_MBUTTONDOWN;
  3914           break;
  3915         case WidgetMouseEvent::eRightButton:
  3916           pluginEvent.event = WM_RBUTTONDOWN;
  3917           break;
  3918         default:
  3919           break;
  3921       break;
  3922     case NS_MOUSE_BUTTON_UP:
  3923       switch (aButton) {
  3924         case WidgetMouseEvent::eLeftButton:
  3925           pluginEvent.event = WM_LBUTTONUP;
  3926           break;
  3927         case WidgetMouseEvent::eMiddleButton:
  3928           pluginEvent.event = WM_MBUTTONUP;
  3929           break;
  3930         case WidgetMouseEvent::eRightButton:
  3931           pluginEvent.event = WM_RBUTTONUP;
  3932           break;
  3933         default:
  3934           break;
  3936       break;
  3937     case NS_MOUSE_DOUBLECLICK:
  3938       switch (aButton) {
  3939         case WidgetMouseEvent::eLeftButton:
  3940           pluginEvent.event = WM_LBUTTONDBLCLK;
  3941           break;
  3942         case WidgetMouseEvent::eMiddleButton:
  3943           pluginEvent.event = WM_MBUTTONDBLCLK;
  3944           break;
  3945         case WidgetMouseEvent::eRightButton:
  3946           pluginEvent.event = WM_RBUTTONDBLCLK;
  3947           break;
  3948         default:
  3949           break;
  3951       break;
  3952     case NS_MOUSE_MOVE:
  3953       pluginEvent.event = WM_MOUSEMOVE;
  3954       break;
  3955     case NS_MOUSE_EXIT:
  3956       pluginEvent.event = WM_MOUSELEAVE;
  3957       break;
  3958     default:
  3959       pluginEvent.event = WM_NULL;
  3960       break;
  3963   pluginEvent.wParam = wParam;     // plugins NEED raw OS event flags!
  3964   pluginEvent.lParam = lParam;
  3966   event.pluginEvent = (void *)&pluginEvent;
  3968   // call the event callback
  3969   if (mWidgetListener) {
  3970     if (nsToolkit::gMouseTrailer)
  3971       nsToolkit::gMouseTrailer->Disable();
  3972     if (aEventType == NS_MOUSE_MOVE) {
  3973       if (nsToolkit::gMouseTrailer && !sIsInMouseCapture) {
  3974         nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd);
  3976       nsIntRect rect;
  3977       GetBounds(rect);
  3978       rect.x = 0;
  3979       rect.y = 0;
  3981       if (rect.Contains(LayoutDeviceIntPoint::ToUntyped(event.refPoint))) {
  3982         if (sCurrentWindow == nullptr || sCurrentWindow != this) {
  3983           if ((nullptr != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
  3984             LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
  3985             sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, false, 
  3986                                                WidgetMouseEvent::eLeftButton,
  3987                                                aInputSource);
  3989           sCurrentWindow = this;
  3990           if (!mInDtor) {
  3991             LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
  3992             sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, false,
  3993                                                WidgetMouseEvent::eLeftButton,
  3994                                                aInputSource);
  3998     } else if (aEventType == NS_MOUSE_EXIT) {
  3999       if (sCurrentWindow == this) {
  4000         sCurrentWindow = nullptr;
  4004     result = DispatchWindowEvent(&event);
  4006     if (nsToolkit::gMouseTrailer)
  4007       nsToolkit::gMouseTrailer->Enable();
  4009     // Release the widget with NS_IF_RELEASE() just in case
  4010     // the context menu key code in EventListenerManager::HandleEvent()
  4011     // released it already.
  4012     return result;
  4015   return result;
  4018 void nsWindow::DispatchFocusToTopLevelWindow(bool aIsActivate)
  4020   if (aIsActivate)
  4021     sJustGotActivate = false;
  4022   sJustGotDeactivate = false;
  4024   // retrive the toplevel window or dialog
  4025   HWND curWnd = mWnd;
  4026   HWND toplevelWnd = nullptr;
  4027   while (curWnd) {
  4028     toplevelWnd = curWnd;
  4030     nsWindow *win = WinUtils::GetNSWindowPtr(curWnd);
  4031     if (win) {
  4032       nsWindowType wintype = win->WindowType();
  4033       if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog)
  4034         break;
  4037     curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
  4040   if (toplevelWnd) {
  4041     nsWindow *win = WinUtils::GetNSWindowPtr(toplevelWnd);
  4042     if (win && win->mWidgetListener) {
  4043       if (aIsActivate) {
  4044         win->mWidgetListener->WindowActivated();
  4045       } else {
  4046         if (!win->BlurEventsSuppressed()) {
  4047           win->mWidgetListener->WindowDeactivated();
  4054 bool nsWindow::IsTopLevelMouseExit(HWND aWnd)
  4056   DWORD pos = ::GetMessagePos();
  4057   POINT mp;
  4058   mp.x = GET_X_LPARAM(pos);
  4059   mp.y = GET_Y_LPARAM(pos);
  4060   HWND mouseWnd = ::WindowFromPoint(mp);
  4062   // WinUtils::GetTopLevelHWND() will return a HWND for the window frame
  4063   // (which includes the non-client area).  If the mouse has moved into
  4064   // the non-client area, we should treat it as a top-level exit.
  4065   HWND mouseTopLevel = WinUtils::GetTopLevelHWND(mouseWnd);
  4066   if (mouseWnd == mouseTopLevel)
  4067     return true;
  4069   return WinUtils::GetTopLevelHWND(aWnd) != mouseTopLevel;
  4072 bool nsWindow::BlurEventsSuppressed()
  4074   // are they suppressed in this window?
  4075   if (mBlurSuppressLevel > 0)
  4076     return true;
  4078   // are they suppressed by any container widget?
  4079   HWND parentWnd = ::GetParent(mWnd);
  4080   if (parentWnd) {
  4081     nsWindow *parent = WinUtils::GetNSWindowPtr(parentWnd);
  4082     if (parent)
  4083       return parent->BlurEventsSuppressed();
  4085   return false;
  4088 // In some circumstances (opening dependent windows) it makes more sense
  4089 // (and fixes a crash bug) to not blur the parent window. Called from
  4090 // nsFilePicker.
  4091 void nsWindow::SuppressBlurEvents(bool aSuppress)
  4093   if (aSuppress)
  4094     ++mBlurSuppressLevel; // for this widget
  4095   else {
  4096     NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression");
  4097     if (mBlurSuppressLevel > 0)
  4098       --mBlurSuppressLevel;
  4102 bool nsWindow::ConvertStatus(nsEventStatus aStatus)
  4104   return aStatus == nsEventStatus_eConsumeNoDefault;
  4107 /**************************************************************
  4109  * SECTION: IPC
  4111  * IPC related helpers.
  4113  **************************************************************/
  4115 // static
  4116 bool
  4117 nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult)
  4119   switch(aMsg) {
  4120     case WM_SETFOCUS:
  4121     case WM_KILLFOCUS:
  4122     case WM_ENABLE:
  4123     case WM_WINDOWPOSCHANGING:
  4124     case WM_WINDOWPOSCHANGED:
  4125     case WM_PARENTNOTIFY:
  4126     case WM_ACTIVATEAPP:
  4127     case WM_NCACTIVATE:
  4128     case WM_ACTIVATE:
  4129     case WM_CHILDACTIVATE:
  4130     case WM_IME_SETCONTEXT:
  4131     case WM_IME_NOTIFY:
  4132     case WM_SHOWWINDOW:
  4133     case WM_CANCELMODE:
  4134     case WM_MOUSEACTIVATE:
  4135     case WM_CONTEXTMENU:
  4136       aResult = 0;
  4137     return true;
  4139     case WM_SETTINGCHANGE:
  4140     case WM_SETCURSOR:
  4141     return false;
  4144 #ifdef DEBUG
  4145   char szBuf[200];
  4146   sprintf(szBuf,
  4147     "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg);
  4148   NS_WARNING(szBuf);
  4149 #endif
  4151   return false;
  4154 void
  4155 nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
  4157   NS_ASSERTION(!mozilla::ipc::MessageChannel::IsPumpingMessages(),
  4158                "Failed to prevent a nonqueued message from running!");
  4160   // Modal UI being displayed in windowless plugins.
  4161   if (mozilla::ipc::MessageChannel::IsSpinLoopActive() &&
  4162       (InSendMessageEx(nullptr) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
  4163     LRESULT res;
  4164     if (IsAsyncResponseEvent(msg, res)) {
  4165       ReplyMessage(res);
  4167     return;
  4170   // Handle certain sync plugin events sent to the parent which
  4171   // trigger ipc calls that result in deadlocks.
  4173   DWORD dwResult = 0;
  4174   bool handled = false;
  4176   switch(msg) {
  4177     // Windowless flash sending WM_ACTIVATE events to the main window
  4178     // via calls to ShowWindow.
  4179     case WM_ACTIVATE:
  4180       if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE &&
  4181           IsWindow((HWND)lParam)) {
  4182         // Check for Adobe Reader X sync activate message from their
  4183         // helper window and ignore. Fixes an annoying focus problem.
  4184         if ((InSendMessageEx(nullptr) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
  4185           wchar_t szClass[10];
  4186           HWND focusWnd = (HWND)lParam;
  4187           if (IsWindowVisible(focusWnd) &&
  4188               GetClassNameW(focusWnd, szClass,
  4189                             sizeof(szClass)/sizeof(char16_t)) &&
  4190               !wcscmp(szClass, L"Edit") &&
  4191               !WinUtils::IsOurProcessWindow(focusWnd)) {
  4192             break;
  4195         handled = true;
  4197     break;
  4198     // Plugins taking or losing focus triggering focus app messages.
  4199     case WM_SETFOCUS:
  4200     case WM_KILLFOCUS:
  4201     // Windowed plugins that pass sys key events to defwndproc generate
  4202     // WM_SYSCOMMAND events to the main window.
  4203     case WM_SYSCOMMAND:
  4204     // Windowed plugins that fire context menu selection events to parent
  4205     // windows.
  4206     case WM_CONTEXTMENU:
  4207     // IME events fired as a result of synchronous focus changes
  4208     case WM_IME_SETCONTEXT:
  4209       handled = true;
  4210     break;
  4213   if (handled &&
  4214       (InSendMessageEx(nullptr) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
  4215     ReplyMessage(dwResult);
  4219 /**************************************************************
  4220  **************************************************************
  4221  **
  4222  ** BLOCK: Native events
  4223  **
  4224  ** Main Windows message handlers and OnXXX handlers for
  4225  ** Windows event handling.
  4226  **
  4227  **************************************************************
  4228  **************************************************************/
  4230 /**************************************************************
  4232  * SECTION: Wind proc.
  4234  * The main Windows event procedures and associated
  4235  * message processing methods.
  4237  **************************************************************/
  4239 static bool
  4240 DisplaySystemMenu(HWND hWnd, nsSizeMode sizeMode, bool isRtl, int32_t x, int32_t y)
  4242   HMENU hMenu = GetSystemMenu(hWnd, FALSE);
  4243   if (hMenu) {
  4244     MENUITEMINFO mii;
  4245     mii.cbSize = sizeof(MENUITEMINFO);
  4246     mii.fMask = MIIM_STATE;
  4247     mii.fType = 0;
  4249     // update the options
  4250     mii.fState = MF_ENABLED;
  4251     SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii);
  4252     SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii);
  4253     SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii);
  4254     SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii);
  4255     SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii);
  4257     mii.fState = MF_GRAYED;
  4258     switch(sizeMode) {
  4259       case nsSizeMode_Fullscreen:
  4260         SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii);
  4261         // intentional fall through
  4262       case nsSizeMode_Maximized:
  4263         SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii);
  4264         SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii);
  4265         SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii);
  4266         break;
  4267       case nsSizeMode_Minimized:
  4268         SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii);
  4269         break;
  4270       case nsSizeMode_Normal:
  4271         SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii);
  4272         break;
  4274     LPARAM cmd =
  4275       TrackPopupMenu(hMenu,
  4276                      (TPM_LEFTBUTTON|TPM_RIGHTBUTTON|
  4277                       TPM_RETURNCMD|TPM_TOPALIGN|
  4278                       (isRtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN)),
  4279                      x, y, 0, hWnd, nullptr);
  4280     if (cmd) {
  4281       PostMessage(hWnd, WM_SYSCOMMAND, cmd, 0);
  4282       return true;
  4285   return false;
  4288 inline static mozilla::HangMonitor::ActivityType ActivityTypeForMessage(UINT msg)
  4290   if ((msg >= WM_KEYFIRST && msg <= WM_IME_KEYLAST) ||
  4291       (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
  4292       (msg >= MOZ_WM_MOUSEWHEEL_FIRST && msg <= MOZ_WM_MOUSEWHEEL_LAST) ||
  4293       (msg >= NS_WM_IMEFIRST && msg <= NS_WM_IMELAST)) {
  4294     return mozilla::HangMonitor::kUIActivity;
  4297   // This may not actually be right, but we don't want to reset the timer if
  4298   // we're not actually processing a UI message.
  4299   return mozilla::HangMonitor::kActivityUIAVail;
  4302 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
  4303 // exceptions and passes the real work to WindowProcInternal. See bug 587406
  4304 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
  4305 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  4307   HangMonitor::NotifyActivity(ActivityTypeForMessage(msg));
  4309   return mozilla::CallWindowProcCrashProtected(WindowProcInternal, hWnd, msg, wParam, lParam);
  4312 LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  4314   if (::GetWindowLongPtrW(hWnd, GWLP_ID) == eFakeTrackPointScrollableID) {
  4315     // This message was sent to the FAKETRACKPOINTSCROLLABLE.
  4316     if (msg == WM_HSCROLL) {
  4317       // Route WM_HSCROLL messages to the main window.
  4318       hWnd = ::GetParent(::GetParent(hWnd));
  4319     } else {
  4320       // Handle all other messages with its original window procedure.
  4321       WNDPROC prevWindowProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
  4322       return ::CallWindowProcW(prevWindowProc, hWnd, msg, wParam, lParam);
  4326   if (msg == MOZ_WM_TRACE) {
  4327     // This is a tracer event for measuring event loop latency.
  4328     // See WidgetTraceEvent.cpp for more details.
  4329     mozilla::SignalTracerThread();
  4330     return 0;
  4333   // Get the window which caused the event and ask it to process the message
  4334   nsWindow *targetWindow = WinUtils::GetNSWindowPtr(hWnd);
  4335   NS_ASSERTION(targetWindow, "nsWindow* is null!");
  4336   if (!targetWindow)
  4337     return ::DefWindowProcW(hWnd, msg, wParam, lParam);
  4339   // Hold the window for the life of this method, in case it gets
  4340   // destroyed during processing, unless we're in the dtor already.
  4341   nsCOMPtr<nsISupports> kungFuDeathGrip;
  4342   if (!targetWindow->mInDtor)
  4343     kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)targetWindow);
  4345   targetWindow->IPCWindowProcHandler(msg, wParam, lParam);
  4347   // Create this here so that we store the last rolled up popup until after
  4348   // the event has been processed.
  4349   nsAutoRollup autoRollup;
  4351   LRESULT popupHandlingResult;
  4352   if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult))
  4353     return popupHandlingResult;
  4355   // Call ProcessMessage
  4356   LRESULT retValue;
  4357   if (targetWindow->ProcessMessage(msg, wParam, lParam, &retValue)) {
  4358     return retValue;
  4361   LRESULT res = ::CallWindowProcW(targetWindow->GetPrevWindowProc(),
  4362                                   hWnd, msg, wParam, lParam);
  4364   return res;
  4367 // The main windows message processing method for plugins.
  4368 // The result means whether this method processed the native
  4369 // event for plugin. If false, the native event should be
  4370 // processed by the caller self.
  4371 bool
  4372 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
  4373                                   MSGResult& aResult)
  4375   aResult.mResult = 0;
  4376   aResult.mConsumed = true;
  4378   bool eventDispatched = false;
  4379   switch (aMsg.message) {
  4380     case WM_CHAR:
  4381     case WM_SYSCHAR:
  4382       aResult.mResult = ProcessCharMessage(aMsg, &eventDispatched);
  4383       break;
  4385     case WM_KEYUP:
  4386     case WM_SYSKEYUP:
  4387       aResult.mResult = ProcessKeyUpMessage(aMsg, &eventDispatched);
  4388       break;
  4390     case WM_KEYDOWN:
  4391     case WM_SYSKEYDOWN:
  4392       aResult.mResult = ProcessKeyDownMessage(aMsg, &eventDispatched);
  4393       break;
  4395     case WM_DEADCHAR:
  4396     case WM_SYSDEADCHAR:
  4398     case WM_CUT:
  4399     case WM_COPY:
  4400     case WM_PASTE:
  4401     case WM_CLEAR:
  4402     case WM_UNDO:
  4403       break;
  4405     default:
  4406       return false;
  4409   if (!eventDispatched) {
  4410     aResult.mConsumed = nsWindowBase::DispatchPluginEvent(aMsg);
  4412   if (!Destroyed()) {
  4413     DispatchPendingEvents();
  4415   return true;
  4418 static void ForceFontUpdate()
  4420   // update device context font cache
  4421   // Dirty but easiest way:
  4422   // Changing nsIPrefBranch entry which triggers callbacks
  4423   // and flows into calling mDeviceContext->FlushFontCache()
  4424   // to update the font cache in all the instance of Browsers
  4425   static const char kPrefName[] = "font.internaluseonly.changed";
  4426   bool fontInternalChange =
  4427     Preferences::GetBool(kPrefName, false);
  4428   Preferences::SetBool(kPrefName, !fontInternalChange);
  4431 static bool CleartypeSettingChanged()
  4433   static int currentQuality = -1;
  4434   BYTE quality = cairo_win32_get_system_text_quality();
  4436   if (currentQuality == quality)
  4437     return false;
  4439   if (currentQuality < 0) {
  4440     currentQuality = quality;
  4441     return false;
  4443   currentQuality = quality;
  4444   return true;
  4447 bool
  4448 nsWindow::ExternalHandlerProcessMessage(UINT aMessage,
  4449                                         WPARAM& aWParam,
  4450                                         LPARAM& aLParam,
  4451                                         MSGResult& aResult)
  4453   if (mWindowHook.Notify(mWnd, aMessage, aWParam, aLParam, aResult)) {
  4454     return true;
  4457   if (IMEHandler::ProcessMessage(this, aMessage, aWParam, aLParam, aResult)) {
  4458     return true;
  4461   if (MouseScrollHandler::ProcessMessage(this, aMessage, aWParam, aLParam,
  4462                                          aResult)) {
  4463     return true;
  4466   if (PluginHasFocus()) {
  4467     MSG nativeMsg = WinUtils::InitMSG(aMessage, aWParam, aLParam, mWnd);
  4468     if (ProcessMessageForPlugin(nativeMsg, aResult)) {
  4469       return true;
  4473   return false;
  4476 // The main windows message processing method.
  4477 bool
  4478 nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
  4479                          LRESULT *aRetValue)
  4481 #if defined(EVENT_DEBUG_OUTPUT)
  4482   // First param shows all events, second param indicates whether
  4483   // to show mouse move events. See nsWindowDbg for details.
  4484   PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
  4485 #endif
  4487   MSGResult msgResult(aRetValue);
  4488   if (ExternalHandlerProcessMessage(msg, wParam, lParam, msgResult)) {
  4489     return (msgResult.mConsumed || !mWnd);
  4492   bool result = false;    // call the default nsWindow proc
  4493   *aRetValue = 0;
  4495   // Glass hit testing w/custom transparent margins
  4496   LRESULT dwmHitResult;
  4497   if (mCustomNonClient &&
  4498       nsUXThemeData::CheckForCompositor() &&
  4499       WinUtils::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) {
  4500     *aRetValue = dwmHitResult;
  4501     return true;
  4504   // (Large blocks of code should be broken out into OnEvent handlers.)
  4505   switch (msg) {
  4506     // WM_QUERYENDSESSION must be handled by all windows.
  4507     // Otherwise Windows thinks the window can just be killed at will.
  4508     case WM_QUERYENDSESSION:
  4509       if (sCanQuit == TRI_UNKNOWN)
  4511         // Ask if it's ok to quit, and store the answer until we
  4512         // get WM_ENDSESSION signaling the round is complete.
  4513         nsCOMPtr<nsIObserverService> obsServ =
  4514           mozilla::services::GetObserverService();
  4515         nsCOMPtr<nsISupportsPRBool> cancelQuit =
  4516           do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
  4517         cancelQuit->SetData(false);
  4518         obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr);
  4520         bool abortQuit;
  4521         cancelQuit->GetData(&abortQuit);
  4522         sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
  4524       *aRetValue = sCanQuit ? TRUE : FALSE;
  4525       result = true;
  4526       break;
  4528     case WM_ENDSESSION:
  4529     case MOZ_WM_APP_QUIT:
  4530       if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE))
  4532         // Let's fake a shutdown sequence without actually closing windows etc.
  4533         // to avoid Windows killing us in the middle. A proper shutdown would
  4534         // require having a chance to pump some messages. Unfortunately
  4535         // Windows won't let us do that. Bug 212316.
  4536         nsCOMPtr<nsIObserverService> obsServ =
  4537           mozilla::services::GetObserverService();
  4538         NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
  4539         obsServ->NotifyObservers(nullptr, "quit-application-granted", nullptr);
  4540         obsServ->NotifyObservers(nullptr, "quit-application-forced", nullptr);
  4541         obsServ->NotifyObservers(nullptr, "quit-application", nullptr);
  4542         obsServ->NotifyObservers(nullptr, "profile-change-net-teardown", context.get());
  4543         obsServ->NotifyObservers(nullptr, "profile-change-teardown", context.get());
  4544         obsServ->NotifyObservers(nullptr, "profile-before-change", context.get());
  4545         obsServ->NotifyObservers(nullptr, "profile-before-change2", context.get());
  4546         // Then a controlled but very quick exit.
  4547         _exit(0);
  4549       sCanQuit = TRI_UNKNOWN;
  4550       result = true;
  4551       break;
  4553     case WM_SYSCOLORCHANGE:
  4554       OnSysColorChanged();
  4555       break;
  4557     case WM_THEMECHANGED:
  4559       // Update non-client margin offsets 
  4560       UpdateNonClientMargins();
  4561       nsUXThemeData::InitTitlebarInfo();
  4562       nsUXThemeData::UpdateNativeThemeInfo();
  4564       NotifyThemeChanged();
  4566       // Invalidate the window so that the repaint will
  4567       // pick up the new theme.
  4568       Invalidate(true, true, true);
  4570     break;
  4572     case WM_FONTCHANGE:
  4574       // We only handle this message for the hidden window,
  4575       // as we only need to update the (global) font list once
  4576       // for any given change, not once per window!
  4577       if (mWindowType != eWindowType_invisible) {
  4578         break;
  4581       nsresult rv;
  4582       bool didChange = false;
  4584       // update the global font list
  4585       nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
  4586       if (NS_SUCCEEDED(rv)) {
  4587         fontEnum->UpdateFontList(&didChange);
  4588         ForceFontUpdate();
  4589       } //if (NS_SUCCEEDED(rv))
  4591     break;
  4593     case WM_NCCALCSIZE:
  4595       if (mCustomNonClient) {
  4596         // If `wParam` is `FALSE`, `lParam` points to a `RECT` that contains
  4597         // the proposed window rectangle for our window.  During our
  4598         // processing of the `WM_NCCALCSIZE` message, we are expected to
  4599         // modify the `RECT` that `lParam` points to, so that its value upon
  4600         // our return is the new client area.  We must return 0 if `wParam`
  4601         // is `FALSE`.
  4602         //
  4603         // If `wParam` is `TRUE`, `lParam` points to a `NCCALCSIZE_PARAMS`
  4604         // struct.  This struct contains an array of 3 `RECT`s, the first of
  4605         // which has the exact same meaning as the `RECT` that is pointed to
  4606         // by `lParam` when `wParam` is `FALSE`.  The remaining `RECT`s, in
  4607         // conjunction with our return value, can
  4608         // be used to specify portions of the source and destination window
  4609         // rectangles that are valid and should be preserved.  We opt not to
  4610         // implement an elaborate client-area preservation technique, and
  4611         // simply return 0, which means "preserve the entire old client area
  4612         // and align it with the upper-left corner of our new client area".
  4613         RECT *clientRect = wParam
  4614                          ? &(reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam))->rgrc[0]
  4615                          : (reinterpret_cast<RECT*>(lParam));
  4616         clientRect->top      += (mCaptionHeight - mNonClientOffset.top);
  4617         clientRect->left     += (mHorResizeMargin - mNonClientOffset.left);
  4618         clientRect->right    -= (mHorResizeMargin - mNonClientOffset.right);
  4619         clientRect->bottom   -= (mVertResizeMargin - mNonClientOffset.bottom);
  4621         result = true;
  4622         *aRetValue = 0;
  4624       break;
  4627     case WM_NCHITTEST:
  4629       if (mMouseTransparent) {
  4630         // Treat this window as transparent.
  4631         *aRetValue = HTTRANSPARENT;
  4632         result = true;
  4633         break;
  4636       /*
  4637        * If an nc client area margin has been moved, we are responsible
  4638        * for calculating where the resize margins are and returning the
  4639        * appropriate set of hit test constants. DwmDefWindowProc (above)
  4640        * will handle hit testing on it's command buttons if we are on a
  4641        * composited desktop.
  4642        */
  4644       if (!mCustomNonClient)
  4645         break;
  4647       *aRetValue =
  4648         ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  4649       result = true;
  4650       break;
  4653     case WM_SETTEXT:
  4654       /*
  4655        * WM_SETTEXT paints the titlebar area. Avoid this if we have a
  4656        * custom titlebar we paint ourselves.
  4657        */
  4659       if (!mCustomNonClient || mNonClientMargins.top == -1)
  4660         break;
  4663         // From msdn, the way around this is to disable the visible state
  4664         // temporarily. We need the text to be set but we don't want the
  4665         // redraw to occur.
  4666         DWORD style = GetWindowLong(mWnd, GWL_STYLE);
  4667         SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
  4668         *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd,
  4669                                      msg, wParam, lParam);
  4670         SetWindowLong(mWnd, GWL_STYLE, style);
  4671         return true;
  4674     case WM_NCACTIVATE:
  4676       /*
  4677        * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
  4678        * through WM_NCPAINT via InvalidateNonClientRegion.
  4679        */
  4680       UpdateGetWindowInfoCaptionStatus(FALSE != wParam);
  4682       if (!mCustomNonClient)
  4683         break;
  4685       // let the dwm handle nc painting on glass
  4686       if(nsUXThemeData::CheckForCompositor())
  4687         break;
  4689       if (wParam == TRUE) {
  4690         // going active
  4691         *aRetValue = FALSE; // ignored
  4692         result = true;
  4693         // invalidate to trigger a paint
  4694         InvalidateNonClientRegion();
  4695         break;
  4696       } else {
  4697         // going inactive
  4698         *aRetValue = TRUE; // go ahead and deactive
  4699         result = true;
  4700         // invalidate to trigger a paint
  4701         InvalidateNonClientRegion();
  4702         break;
  4706     case WM_NCPAINT:
  4708       /*
  4709        * Reset the non-client paint region so that it excludes the
  4710        * non-client areas we paint manually. Then call defwndproc
  4711        * to do the actual painting.
  4712        */
  4714       if (!mCustomNonClient)
  4715         break;
  4717       // let the dwm handle nc painting on glass
  4718       if(nsUXThemeData::CheckForCompositor())
  4719         break;
  4721       HRGN paintRgn = ExcludeNonClientFromPaintRegion((HRGN)wParam);
  4722       LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd,
  4723                                     msg, (WPARAM)paintRgn, lParam);
  4724       if (paintRgn != (HRGN)wParam)
  4725         DeleteObject(paintRgn);
  4726       *aRetValue = res;
  4727       result = true;
  4729     break;
  4731     case WM_POWERBROADCAST:
  4732       switch (wParam)
  4734         case PBT_APMSUSPEND:
  4735           PostSleepWakeNotification(true);
  4736           break;
  4737         case PBT_APMRESUMEAUTOMATIC:
  4738         case PBT_APMRESUMECRITICAL:
  4739         case PBT_APMRESUMESUSPEND:
  4740           PostSleepWakeNotification(false);
  4741           break;
  4743       break;
  4745     case WM_CLOSE: // close request
  4746       if (mWidgetListener)
  4747         mWidgetListener->RequestWindowClose(this);
  4748       result = true; // abort window closure
  4749       break;
  4751     case WM_DESTROY:
  4752       // clean up.
  4753       OnDestroy();
  4754       result = true;
  4755       break;
  4757     case WM_PAINT:
  4758       if (CleartypeSettingChanged()) {
  4759         ForceFontUpdate();
  4760         gfxFontCache *fc = gfxFontCache::GetCache();
  4761         if (fc) {
  4762           fc->Flush();
  4765       *aRetValue = (int) OnPaint(nullptr, 0);
  4766       result = true;
  4767       break;
  4769     case WM_PRINTCLIENT:
  4770       result = OnPaint((HDC) wParam, 0);
  4771       break;
  4773     case WM_HOTKEY:
  4774       result = OnHotKey(wParam, lParam);
  4775       break;
  4777     case WM_SYSCHAR:
  4778     case WM_CHAR:
  4780       MSG nativeMsg = WinUtils::InitMSG(msg, wParam, lParam, mWnd);
  4781       result = ProcessCharMessage(nativeMsg, nullptr);
  4782       DispatchPendingEvents();
  4784     break;
  4786     case WM_SYSKEYUP:
  4787     case WM_KEYUP:
  4789       MSG nativeMsg = WinUtils::InitMSG(msg, wParam, lParam, mWnd);
  4790       nativeMsg.time = ::GetMessageTime();
  4791       result = ProcessKeyUpMessage(nativeMsg, nullptr);
  4792       DispatchPendingEvents();
  4794     break;
  4796     case WM_SYSKEYDOWN:
  4797     case WM_KEYDOWN:
  4799       MSG nativeMsg = WinUtils::InitMSG(msg, wParam, lParam, mWnd);
  4800       result = ProcessKeyDownMessage(nativeMsg, nullptr);
  4801       DispatchPendingEvents();
  4803     break;
  4805     // say we've dealt with erase background if widget does
  4806     // not need auto-erasing
  4807     case WM_ERASEBKGND:
  4808       if (!AutoErase((HDC)wParam)) {
  4809         *aRetValue = 1;
  4810         result = true;
  4812       break;
  4814     case WM_MOUSEMOVE:
  4816       mMousePresent = true;
  4818       // Suppress dispatch of pending events
  4819       // when mouse moves are generated by widget
  4820       // creation instead of user input.
  4821       LPARAM lParamScreen = lParamToScreen(lParam);
  4822       POINT mp;
  4823       mp.x      = GET_X_LPARAM(lParamScreen);
  4824       mp.y      = GET_Y_LPARAM(lParamScreen);
  4825       bool userMovedMouse = false;
  4826       if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) {
  4827         userMovedMouse = true;
  4830       result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam,
  4831                                   false, WidgetMouseEvent::eLeftButton,
  4832                                   MOUSE_INPUT_SOURCE());
  4833       if (userMovedMouse) {
  4834         DispatchPendingEvents();
  4837     break;
  4839     case WM_NCMOUSEMOVE:
  4840       // If we receive a mouse move event on non-client chrome, make sure and
  4841       // send an NS_MOUSE_EXIT event as well.
  4842       if (mMousePresent && !sIsInMouseCapture)
  4843         SendMessage(mWnd, WM_MOUSELEAVE, 0, 0);
  4844     break;
  4846     case WM_LBUTTONDOWN:
  4848       result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
  4849                                   false, WidgetMouseEvent::eLeftButton,
  4850                                   MOUSE_INPUT_SOURCE());
  4851       DispatchPendingEvents();
  4853     break;
  4855     case WM_LBUTTONUP:
  4857       result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam,
  4858                                   false, WidgetMouseEvent::eLeftButton,
  4859                                   MOUSE_INPUT_SOURCE());
  4860       DispatchPendingEvents();
  4862     break;
  4864     case WM_MOUSELEAVE:
  4866       if (!mMousePresent)
  4867         break;
  4868       mMousePresent = false;
  4870       // We need to check mouse button states and put them in for
  4871       // wParam.
  4872       WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
  4873         | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
  4874         | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
  4875       // Synthesize an event position because we don't get one from
  4876       // WM_MOUSELEAVE.
  4877       LPARAM pos = lParamToClient(::GetMessagePos());
  4878       DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, false,
  4879                          WidgetMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
  4881     break;
  4883     case WM_CONTEXTMENU:
  4885       // if the context menu is brought up from the keyboard, |lParam|
  4886       // will be -1.
  4887       LPARAM pos;
  4888       bool contextMenukey = false;
  4889       if (lParam == -1)
  4891         contextMenukey = true;
  4892         pos = lParamToClient(GetMessagePos());
  4894       else
  4896         pos = lParamToClient(lParam);
  4899       result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey,
  4900                                   contextMenukey ?
  4901                                     WidgetMouseEvent::eLeftButton :
  4902                                     WidgetMouseEvent::eRightButton,
  4903                                   MOUSE_INPUT_SOURCE());
  4904       if (lParam != -1 && !result && mCustomNonClient) {
  4905         WidgetMouseEvent event(true, NS_MOUSE_MOZHITTEST, this,
  4906                                WidgetMouseEvent::eReal,
  4907                                WidgetMouseEvent::eNormal);
  4908         event.refPoint = LayoutDeviceIntPoint(GET_X_LPARAM(pos), GET_Y_LPARAM(pos));
  4909         event.inputSource = MOUSE_INPUT_SOURCE();
  4910         event.mFlags.mOnlyChromeDispatch = true;
  4911         if (DispatchWindowEvent(&event)) {
  4912           // Blank area hit, throw up the system menu.
  4913           DisplaySystemMenu(mWnd, mSizeMode, mIsRTL, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  4914           result = true;
  4918     break;
  4920     case WM_LBUTTONDBLCLK:
  4921       result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam,
  4922                                   lParam, false,
  4923                                   WidgetMouseEvent::eLeftButton,
  4924                                   MOUSE_INPUT_SOURCE());
  4925       DispatchPendingEvents();
  4926       break;
  4928     case WM_MBUTTONDOWN:
  4929       result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam,
  4930                                   lParam, false,
  4931                                   WidgetMouseEvent::eMiddleButton,
  4932                                   MOUSE_INPUT_SOURCE());
  4933       DispatchPendingEvents();
  4934       break;
  4936     case WM_MBUTTONUP:
  4937       result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam,
  4938                                   lParam, false,
  4939                                   WidgetMouseEvent::eMiddleButton,
  4940                                   MOUSE_INPUT_SOURCE());
  4941       DispatchPendingEvents();
  4942       break;
  4944     case WM_MBUTTONDBLCLK:
  4945       result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam,
  4946                                   lParam, false,
  4947                                   WidgetMouseEvent::eMiddleButton,
  4948                                   MOUSE_INPUT_SOURCE());
  4949       DispatchPendingEvents();
  4950       break;
  4952     case WM_NCMBUTTONDOWN:
  4953       result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0,
  4954                                   lParamToClient(lParam), false,
  4955                                   WidgetMouseEvent::eMiddleButton,
  4956                                   MOUSE_INPUT_SOURCE());
  4957       DispatchPendingEvents();
  4958       break;
  4960     case WM_NCMBUTTONUP:
  4961       result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0,
  4962                                   lParamToClient(lParam), false,
  4963                                   WidgetMouseEvent::eMiddleButton,
  4964                                   MOUSE_INPUT_SOURCE());
  4965       DispatchPendingEvents();
  4966       break;
  4968     case WM_NCMBUTTONDBLCLK:
  4969       result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0,
  4970                                   lParamToClient(lParam), false,
  4971                                   WidgetMouseEvent::eMiddleButton,
  4972                                   MOUSE_INPUT_SOURCE());
  4973       DispatchPendingEvents();
  4974       break;
  4976     case WM_RBUTTONDOWN:
  4977       result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam,
  4978                                   lParam, false,
  4979                                   WidgetMouseEvent::eRightButton,
  4980                                   MOUSE_INPUT_SOURCE());
  4981       DispatchPendingEvents();
  4982       break;
  4984     case WM_RBUTTONUP:
  4985       result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam,
  4986                                   lParam, false,
  4987                                   WidgetMouseEvent::eRightButton,
  4988                                   MOUSE_INPUT_SOURCE());
  4989       DispatchPendingEvents();
  4990       break;
  4992     case WM_RBUTTONDBLCLK:
  4993       result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam,
  4994                                   lParam, false,
  4995                                   WidgetMouseEvent::eRightButton,
  4996                                   MOUSE_INPUT_SOURCE());
  4997       DispatchPendingEvents();
  4998       break;
  5000     case WM_NCRBUTTONDOWN:
  5001       result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0,
  5002                                   lParamToClient(lParam), false,
  5003                                   WidgetMouseEvent::eRightButton,
  5004                                   MOUSE_INPUT_SOURCE());
  5005       DispatchPendingEvents();
  5006       break;
  5008     case WM_NCRBUTTONUP:
  5009       result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0,
  5010                                   lParamToClient(lParam), false,
  5011                                   WidgetMouseEvent::eRightButton,
  5012                                   MOUSE_INPUT_SOURCE());
  5013       DispatchPendingEvents();
  5014       break;
  5016     case WM_NCRBUTTONDBLCLK:
  5017       result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0,
  5018                                   lParamToClient(lParam), false,
  5019                                   WidgetMouseEvent::eRightButton,
  5020                                   MOUSE_INPUT_SOURCE());
  5021       DispatchPendingEvents();
  5022       break;
  5024     case WM_EXITSIZEMOVE:
  5025       if (!sIsInMouseCapture) {
  5026         NotifySizeMoveDone();
  5028       break;
  5030     case WM_NCLBUTTONDBLCLK:
  5031       DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam),
  5032                          false, WidgetMouseEvent::eLeftButton,
  5033                          MOUSE_INPUT_SOURCE());
  5034       result = 
  5035         DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam),
  5036                            false, WidgetMouseEvent::eLeftButton,
  5037                            MOUSE_INPUT_SOURCE());
  5038       DispatchPendingEvents();
  5039       break;
  5041     case WM_APPCOMMAND:
  5042       result = HandleAppCommandMsg(wParam, lParam, aRetValue);
  5043       break;
  5045     // The WM_ACTIVATE event is fired when a window is raised or lowered,
  5046     // and the loword of wParam specifies which. But we don't want to tell
  5047     // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
  5048     // events are fired. Instead, set either the sJustGotActivate or
  5049     // gJustGotDeactivate flags and activate/deactivate once the focus
  5050     // events arrive.
  5051     case WM_ACTIVATE:
  5052       if (mWidgetListener) {
  5053         int32_t fActive = LOWORD(wParam);
  5055         if (WA_INACTIVE == fActive) {
  5056           // when minimizing a window, the deactivation and focus events will
  5057           // be fired in the reverse order. Instead, just deactivate right away.
  5058           if (HIWORD(wParam))
  5059             DispatchFocusToTopLevelWindow(false);
  5060           else
  5061             sJustGotDeactivate = true;
  5063           if (mIsTopWidgetWindow)
  5064             mLastKeyboardLayout = KeyboardLayout::GetInstance()->GetLayout();
  5066         } else {
  5067           StopFlashing();
  5069           sJustGotActivate = true;
  5070           WidgetMouseEvent event(true, NS_MOUSE_ACTIVATE, this,
  5071                                  WidgetMouseEvent::eReal);
  5072           InitEvent(event);
  5073           ModifierKeyState modifierKeyState;
  5074           modifierKeyState.InitInputEvent(event);
  5075           DispatchWindowEvent(&event);
  5076           if (sSwitchKeyboardLayout && mLastKeyboardLayout)
  5077             ActivateKeyboardLayout(mLastKeyboardLayout, 0);
  5080       break;
  5082     case WM_MOUSEACTIVATE:
  5083       // A popup with a parent owner should not be activated when clicked but
  5084       // should still allow the mouse event to be fired, so the return value
  5085       // is set to MA_NOACTIVATE. But if the owner isn't the frontmost window,
  5086       // just use default processing so that the window is activated.
  5087       if (IsPopup() && IsOwnerForegroundWindow()) {
  5088         *aRetValue = MA_NOACTIVATE;
  5089         result = true;
  5091       break;
  5093     case WM_WINDOWPOSCHANGING:
  5095       LPWINDOWPOS info = (LPWINDOWPOS)lParam;
  5096       OnWindowPosChanging(info);
  5097       result = true;
  5099     break;
  5101     case WM_GETMINMAXINFO:
  5103       MINMAXINFO* mmi = (MINMAXINFO*)lParam;
  5104       // Set the constraints. The minimum size should also be constrained to the
  5105       // default window maximum size so that it fits on screen.
  5106       mmi->ptMinTrackSize.x =
  5107         std::min((int32_t)mmi->ptMaxTrackSize.x,
  5108                std::max((int32_t)mmi->ptMinTrackSize.x, mSizeConstraints.mMinSize.width));
  5109       mmi->ptMinTrackSize.y =
  5110         std::min((int32_t)mmi->ptMaxTrackSize.y,
  5111         std::max((int32_t)mmi->ptMinTrackSize.y, mSizeConstraints.mMinSize.height));
  5112       mmi->ptMaxTrackSize.x = std::min((int32_t)mmi->ptMaxTrackSize.x, mSizeConstraints.mMaxSize.width);
  5113       mmi->ptMaxTrackSize.y = std::min((int32_t)mmi->ptMaxTrackSize.y, mSizeConstraints.mMaxSize.height);
  5115     break;
  5117     case WM_SETFOCUS:
  5118       // If previous focused window isn't ours, it must have received the
  5119       // redirected message.  So, we should forget it.
  5120       if (!WinUtils::IsOurProcessWindow(HWND(wParam))) {
  5121         RedirectedKeyDownMessageManager::Forget();
  5123       if (sJustGotActivate) {
  5124         DispatchFocusToTopLevelWindow(true);
  5126       break;
  5128     case WM_KILLFOCUS:
  5129       if (sJustGotDeactivate) {
  5130         DispatchFocusToTopLevelWindow(false);
  5132       break;
  5134     case WM_WINDOWPOSCHANGED:
  5136       WINDOWPOS* wp = (LPWINDOWPOS)lParam;
  5137       OnWindowPosChanged(wp);
  5138       result = true;
  5140     break;
  5142     case WM_INPUTLANGCHANGEREQUEST:
  5143       *aRetValue = TRUE;
  5144       result = false;
  5145       break;
  5147     case WM_INPUTLANGCHANGE:
  5148       KeyboardLayout::GetInstance()->
  5149         OnLayoutChange(reinterpret_cast<HKL>(lParam));
  5150       result = false; // always pass to child window
  5151       break;
  5153     case WM_DESTROYCLIPBOARD:
  5155       nsIClipboard* clipboard;
  5156       nsresult rv = CallGetService(kCClipboardCID, &clipboard);
  5157       if(NS_SUCCEEDED(rv)) {
  5158         clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
  5159         NS_RELEASE(clipboard);
  5162     break;
  5164 #ifdef ACCESSIBILITY
  5165     case WM_GETOBJECT:
  5167       *aRetValue = 0;
  5168       // Do explicit casting to make it working on 64bit systems (see bug 649236
  5169       // for details).
  5170       DWORD objId = static_cast<DWORD>(lParam);
  5171       if (objId == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
  5172         a11y::Accessible* rootAccessible = GetAccessible(); // Held by a11y cache
  5173         if (rootAccessible) {
  5174           IAccessible *msaaAccessible = nullptr;
  5175           rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref
  5176           if (msaaAccessible) {
  5177             *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref
  5178             msaaAccessible->Release(); // release extra addref
  5179             result = true;  // We handled the WM_GETOBJECT message
  5184 #endif
  5186     case WM_SYSCOMMAND:
  5188       WPARAM filteredWParam = (wParam &0xFFF0);
  5189       // prevent Windows from trimming the working set. bug 76831
  5190       if (!sTrimOnMinimize && filteredWParam == SC_MINIMIZE) {
  5191         ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
  5192         result = true;
  5195       // Handle the system menu manually when we're in full screen mode
  5196       // so we can set the appropriate options.
  5197       if (filteredWParam == SC_KEYMENU && lParam == VK_SPACE &&
  5198           mSizeMode == nsSizeMode_Fullscreen) {
  5199         DisplaySystemMenu(mWnd, mSizeMode, mIsRTL,
  5200                           MOZ_SYSCONTEXT_X_POS,
  5201                           MOZ_SYSCONTEXT_Y_POS);
  5202         result = true;
  5205     break;
  5207   case WM_DWMCOMPOSITIONCHANGED:
  5208     // First, update the compositor state to latest one. All other methods
  5209     // should use same state as here for consistency painting.
  5210     nsUXThemeData::CheckForCompositor(true);
  5212     UpdateNonClientMargins();
  5213     BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
  5214     NotifyThemeChanged();
  5215     UpdateGlass();
  5216     Invalidate(true, true, true);
  5217     break;
  5219   case WM_UPDATEUISTATE:
  5221     // If the UI state has changed, fire an event so the UI updates the
  5222     // keyboard cues based on the system setting and how the window was
  5223     // opened. For example, a dialog opened via a keyboard press on a button
  5224     // should enable cues, whereas the same dialog opened via a mouse click of
  5225     // the button should not.
  5226     int32_t action = LOWORD(wParam);
  5227     if (action == UIS_SET || action == UIS_CLEAR) {
  5228       int32_t flags = HIWORD(wParam);
  5229       UIStateChangeType showAccelerators = UIStateChangeType_NoChange;
  5230       UIStateChangeType showFocusRings = UIStateChangeType_NoChange;
  5231       if (flags & UISF_HIDEACCEL)
  5232         showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
  5233       if (flags & UISF_HIDEFOCUS)
  5234         showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
  5235       NotifyUIStateChanged(showAccelerators, showFocusRings);
  5238     break;
  5241   /* Gesture support events */
  5242   case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
  5243     // According to MS samples, this must be handled to enable
  5244     // rotational support in multi-touch drivers.
  5245     result = true;
  5246     *aRetValue = TABLET_ROTATE_GESTURE_ENABLE;
  5247     break;
  5249   case WM_TOUCH:
  5250     result = OnTouch(wParam, lParam);
  5251     if (result) {
  5252       *aRetValue = 0;
  5254     break;
  5256   case WM_GESTURE:
  5257     result = OnGesture(wParam, lParam);
  5258     break;
  5260   case WM_GESTURENOTIFY:
  5262       if (mWindowType != eWindowType_invisible &&
  5263           mWindowType != eWindowType_plugin) {
  5264         // A GestureNotify event is dispatched to decide which single-finger panning
  5265         // direction should be active (including none) and if pan feedback should
  5266         // be displayed. Java and plugin windows can make their own calls.
  5267         if (gIsPointerEventsEnabled) {
  5268           result = false;
  5269           break;
  5272         GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
  5273         nsPointWin touchPoint;
  5274         touchPoint = gestureinfo->ptsLocation;
  5275         touchPoint.ScreenToClient(mWnd);
  5276         WidgetGestureNotifyEvent gestureNotifyEvent(true,
  5277                                    NS_GESTURENOTIFY_EVENT_START, this);
  5278         gestureNotifyEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(touchPoint);
  5279         nsEventStatus status;
  5280         DispatchEvent(&gestureNotifyEvent, status);
  5281         mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
  5282         if (!mTouchWindow)
  5283           mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
  5285       result = false; //should always bubble to DefWindowProc
  5287     break;
  5289     case WM_CLEAR:
  5291       WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_DELETE, this);
  5292       DispatchWindowEvent(&command);
  5293       result = true;
  5295     break;
  5297     case WM_CUT:
  5299       WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_CUT, this);
  5300       DispatchWindowEvent(&command);
  5301       result = true;
  5303     break;
  5305     case WM_COPY:
  5307       WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_COPY, this);
  5308       DispatchWindowEvent(&command);
  5309       result = true;
  5311     break;
  5313     case WM_PASTE:
  5315       WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_PASTE, this);
  5316       DispatchWindowEvent(&command);
  5317       result = true;
  5319     break;
  5321     case EM_UNDO:
  5323       WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_UNDO, this);
  5324       DispatchWindowEvent(&command);
  5325       *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
  5326       result = true;
  5328     break;
  5330     case EM_REDO:
  5332       WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_REDO, this);
  5333       DispatchWindowEvent(&command);
  5334       *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
  5335       result = true;
  5337     break;
  5339     case EM_CANPASTE:
  5341       // Support EM_CANPASTE message only when wParam isn't specified or
  5342       // is plain text format.
  5343       if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
  5344         WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_PASTE,
  5345                                           this, true);
  5346         DispatchWindowEvent(&command);
  5347         *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
  5348         result = true;
  5351     break;
  5353     case EM_CANUNDO:
  5355       WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_UNDO,
  5356                                         this, true);
  5357       DispatchWindowEvent(&command);
  5358       *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
  5359       result = true;
  5361     break;
  5363     case EM_CANREDO:
  5365       WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_REDO,
  5366                                         this, true);
  5367       DispatchWindowEvent(&command);
  5368       *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
  5369       result = true;
  5371     break;
  5373     default:
  5375       if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
  5376         SetHasTaskbarIconBeenCreated();
  5377       if (msg == sOOPPPluginFocusEvent) {
  5378         if (wParam == 1) {
  5379           // With OOPP, the plugin window exists in another process and is a child of
  5380           // this window. This window is a placeholder plugin window for the dom. We
  5381           // receive this event when the child window receives focus. (sent from
  5382           // PluginInstanceParent.cpp)
  5383           ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
  5384         } else {
  5385           // WM_KILLFOCUS was received by the child process.
  5386           if (sJustGotDeactivate) {
  5387             DispatchFocusToTopLevelWindow(false);
  5392     break;
  5393     case WM_SETTINGCHANGE:
  5394       if (IsWin8OrLater() && lParam &&
  5395           !wcsicmp(L"ConvertibleSlateMode", (wchar_t*)lParam)) {
  5396         // If we're switching into slate mode, switch to Metro for hardware
  5397         // that supports this feature if the pref is set.
  5398         if (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0 &&
  5399             Preferences::GetBool("browser.shell.desktop-auto-switch-enabled",
  5400                                  false)) {
  5401           nsCOMPtr<nsIAppStartup> appStartup(do_GetService(NS_APPSTARTUP_CONTRACTID));
  5402           if (appStartup) {
  5403             appStartup->Quit(nsIAppStartup::eForceQuit |
  5404                              nsIAppStartup::eRestartTouchEnvironment);
  5408     break;
  5412   //*aRetValue = result;
  5413   if (mWnd) {
  5414     return result;
  5416   else {
  5417     //Events which caused mWnd destruction and aren't consumed
  5418     //will crash during the Windows default processing.
  5419     return true;
  5423 /**************************************************************
  5425  * SECTION: Broadcast messaging
  5427  * Broadcast messages to all windows.
  5429  **************************************************************/
  5431 // Enumerate all child windows sending aMsg to each of them
  5432 BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg)
  5434   WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
  5435   if (winProc == &nsWindow::WindowProc) {
  5436     // it's one of our windows so go ahead and send a message to it
  5437     ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0);
  5439   return TRUE;
  5442 // Enumerate all top level windows specifying that the children of each
  5443 // top level window should be enumerated. Do *not* send the message to
  5444 // each top level window since it is assumed that the toolkit will send
  5445 // aMsg to them directly.
  5446 BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg)
  5448   // Iterate each of aTopWindows child windows sending the aMsg
  5449   // to each of them.
  5450   ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
  5451   return TRUE;
  5454 /**************************************************************
  5456  * SECTION: Event processing helpers
  5458  * Special processing for certain event types and 
  5459  * synthesized events.
  5461  **************************************************************/
  5463 int32_t
  5464 nsWindow::ClientMarginHitTestPoint(int32_t mx, int32_t my)
  5466   if (mSizeMode == nsSizeMode_Minimized ||
  5467       mSizeMode == nsSizeMode_Fullscreen) {
  5468     return HTCLIENT;
  5471   // Calculations are done in screen coords
  5472   RECT winRect;
  5473   GetWindowRect(mWnd, &winRect);
  5475   // hit return constants:
  5476   // HTBORDER                     - non-resizable border
  5477   // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
  5478   // HTBOTTOMLEFT, HTBOTTOMRIGHT  - resizable corner
  5479   // HTTOPLEFT, HTTOPRIGHT        - resizable corner
  5480   // HTCAPTION                    - general title bar area
  5481   // HTCLIENT                     - area considered the client
  5482   // HTCLOSE                      - hovering over the close button
  5483   // HTMAXBUTTON                  - maximize button
  5484   // HTMINBUTTON                  - minimize button
  5486   int32_t testResult = HTCLIENT;
  5488   bool isResizable = (mBorderStyle & (eBorderStyle_all |
  5489                                       eBorderStyle_resizeh |
  5490                                       eBorderStyle_default)) > 0 ? true : false;
  5491   if (mSizeMode == nsSizeMode_Maximized)
  5492     isResizable = false;
  5494   // Ensure being accessible to borders of window.  Even if contents are in
  5495   // this area, the area must behave as border.
  5496   nsIntMargin nonClientSize(std::max(mCaptionHeight - mNonClientOffset.top,
  5497                                      kResizableBorderMinSize),
  5498                             std::max(mHorResizeMargin - mNonClientOffset.right,
  5499                                      kResizableBorderMinSize),
  5500                             std::max(mVertResizeMargin - mNonClientOffset.bottom,
  5501                                      kResizableBorderMinSize),
  5502                             std::max(mHorResizeMargin - mNonClientOffset.left,
  5503                                      kResizableBorderMinSize));
  5505   bool allowContentOverride = mSizeMode == nsSizeMode_Maximized ||
  5506                               (mx >= winRect.left + nonClientSize.left &&
  5507                                mx <= winRect.right - nonClientSize.right &&
  5508                                my >= winRect.top + nonClientSize.top &&
  5509                                my <= winRect.bottom - nonClientSize.bottom);
  5511   // The border size.  If there is no content under mouse cursor, the border
  5512   // size should be larger than the values in system settings.  Otherwise,
  5513   // contents under the mouse cursor should be able to override the behavior.
  5514   // E.g., user must expect that Firefox button always opens the popup menu
  5515   // even when the user clicks on the above edge of it.
  5516   nsIntMargin borderSize(std::max(nonClientSize.top,    mVertResizeMargin),
  5517                          std::max(nonClientSize.right,  mHorResizeMargin),
  5518                          std::max(nonClientSize.bottom, mVertResizeMargin),
  5519                          std::max(nonClientSize.left,   mHorResizeMargin));
  5521   bool top    = false;
  5522   bool bottom = false;
  5523   bool left   = false;
  5524   bool right  = false;
  5526   if (my >= winRect.top && my < winRect.top + borderSize.top) {
  5527     top = true;
  5528   } else if (my <= winRect.bottom && my > winRect.bottom - borderSize.bottom) {
  5529     bottom = true;
  5532   // (the 2x case here doubles the resize area for corners)
  5533   int multiplier = (top || bottom) ? 2 : 1;
  5534   if (mx >= winRect.left &&
  5535       mx < winRect.left + (multiplier * borderSize.left)) {
  5536     left = true;
  5537   } else if (mx <= winRect.right &&
  5538              mx > winRect.right - (multiplier * borderSize.right)) {
  5539     right = true;
  5542   if (isResizable) {
  5543     if (top) {
  5544       testResult = HTTOP;
  5545       if (left)
  5546         testResult = HTTOPLEFT;
  5547       else if (right)
  5548         testResult = HTTOPRIGHT;
  5549     } else if (bottom) {
  5550       testResult = HTBOTTOM;
  5551       if (left)
  5552         testResult = HTBOTTOMLEFT;
  5553       else if (right)
  5554         testResult = HTBOTTOMRIGHT;
  5555     } else {
  5556       if (left)
  5557         testResult = HTLEFT;
  5558       if (right)
  5559         testResult = HTRIGHT;
  5561   } else {
  5562     if (top)
  5563       testResult = HTCAPTION;
  5564     else if (bottom || left || right)
  5565       testResult = HTBORDER;
  5568   if (!sIsInMouseCapture && allowContentOverride) {
  5569     POINT pt = { mx, my };
  5570     ::ScreenToClient(mWnd, &pt);
  5571     if (pt.x == mCachedHitTestPoint.x && pt.y == mCachedHitTestPoint.y &&
  5572         TimeStamp::Now() - mCachedHitTestTime < TimeDuration::FromMilliseconds(HITTEST_CACHE_LIFETIME_MS)) {
  5573       testResult = mCachedHitTestResult;
  5574     } else {
  5575       WidgetMouseEvent event(true, NS_MOUSE_MOZHITTEST, this,
  5576                              WidgetMouseEvent::eReal,
  5577                              WidgetMouseEvent::eNormal);
  5578       event.refPoint = LayoutDeviceIntPoint(pt.x, pt.y);
  5579       event.inputSource = MOUSE_INPUT_SOURCE();
  5580       event.mFlags.mOnlyChromeDispatch = true;
  5581       bool result = DispatchWindowEvent(&event);
  5582       if (result) {
  5583         // The mouse is over a blank area
  5584         testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
  5586       } else {
  5587         // There's content over the mouse pointer. Set HTCLIENT
  5588         // to possibly override a resizer border.
  5589         testResult = HTCLIENT;
  5591       mCachedHitTestPoint = pt;
  5592       mCachedHitTestTime = TimeStamp::Now();
  5593       mCachedHitTestResult = testResult;
  5597   return testResult;
  5600 void nsWindow::PostSleepWakeNotification(const bool aIsSleepMode)
  5602   if (aIsSleepMode == gIsSleepMode)
  5603     return;
  5605   gIsSleepMode = aIsSleepMode;
  5607   nsCOMPtr<nsIObserverService> observerService =
  5608     mozilla::services::GetObserverService();
  5609   if (observerService)
  5610     observerService->NotifyObservers(nullptr,
  5611       aIsSleepMode ? NS_WIDGET_SLEEP_OBSERVER_TOPIC :
  5612                      NS_WIDGET_WAKE_OBSERVER_TOPIC, nullptr);
  5615 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, bool *aEventDispatched)
  5617   if (IMEHandler::IsComposingOn(this)) {
  5618     IMEHandler::NotifyIME(this, REQUEST_TO_COMMIT_COMPOSITION);
  5620   // These must be checked here too as a lone WM_CHAR could be received
  5621   // if a child window didn't handle it (for example Alt+Space in a content
  5622   // window)
  5623   ModifierKeyState modKeyState;
  5624   NativeKey nativeKey(this, aMsg, modKeyState);
  5625   return static_cast<LRESULT>(nativeKey.HandleCharMessage(aMsg,
  5626                                                           aEventDispatched));
  5629 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, bool *aEventDispatched)
  5631   if (IMEHandler::IsComposingOn(this)) {
  5632     return 0;
  5635   ModifierKeyState modKeyState;
  5636   NativeKey nativeKey(this, aMsg, modKeyState);
  5637   return static_cast<LRESULT>(nativeKey.HandleKeyUpMessage(aEventDispatched));
  5640 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
  5641                                         bool *aEventDispatched)
  5643   // If this method doesn't call NativeKey::HandleKeyDownMessage(), this method
  5644   // must clean up the redirected message information itself.  For more
  5645   // information, see above comment of
  5646   // RedirectedKeyDownMessageManager::AutoFlusher class definition in
  5647   // KeyboardLayout.h.
  5648   RedirectedKeyDownMessageManager::AutoFlusher redirectedMsgFlusher(this, aMsg);
  5650   ModifierKeyState modKeyState;
  5652   LRESULT result = 0;
  5653   if (!IMEHandler::IsComposingOn(this)) {
  5654     NativeKey nativeKey(this, aMsg, modKeyState);
  5655     result =
  5656       static_cast<LRESULT>(nativeKey.HandleKeyDownMessage(aEventDispatched));
  5657     // HandleKeyDownMessage cleaned up the redirected message information
  5658     // itself, so, we should do nothing.
  5659     redirectedMsgFlusher.Cancel();
  5662   if (aMsg.wParam == VK_MENU ||
  5663       (aMsg.wParam == VK_F10 && !modKeyState.IsShift())) {
  5664     // We need to let Windows handle this keypress,
  5665     // by returning false, if there's a native menu
  5666     // bar somewhere in our containing window hierarchy.
  5667     // Otherwise we handle the keypress and don't pass
  5668     // it on to Windows, by returning true.
  5669     bool hasNativeMenu = false;
  5670     HWND hWnd = mWnd;
  5671     while (hWnd) {
  5672       if (::GetMenu(hWnd)) {
  5673         hasNativeMenu = true;
  5674         break;
  5676       hWnd = ::GetParent(hWnd);
  5678     result = !hasNativeMenu;
  5681   return result;
  5684 nsresult
  5685 nsWindow::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
  5686                                    int32_t aNativeKeyCode,
  5687                                    uint32_t aModifierFlags,
  5688                                    const nsAString& aCharacters,
  5689                                    const nsAString& aUnmodifiedCharacters)
  5691   KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
  5692   return keyboardLayout->SynthesizeNativeKeyEvent(
  5693            this, aNativeKeyboardLayout, aNativeKeyCode, aModifierFlags,
  5694            aCharacters, aUnmodifiedCharacters);
  5697 nsresult
  5698 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
  5699                                      uint32_t aNativeMessage,
  5700                                      uint32_t aModifierFlags)
  5702   ::SetCursorPos(aPoint.x, aPoint.y);
  5704   INPUT input;
  5705   memset(&input, 0, sizeof(input));
  5707   input.type = INPUT_MOUSE;
  5708   input.mi.dwFlags = aNativeMessage;
  5709   ::SendInput(1, &input, sizeof(INPUT));
  5711   return NS_OK;
  5714 nsresult
  5715 nsWindow::SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint,
  5716                                            uint32_t aNativeMessage,
  5717                                            double aDeltaX,
  5718                                            double aDeltaY,
  5719                                            double aDeltaZ,
  5720                                            uint32_t aModifierFlags,
  5721                                            uint32_t aAdditionalFlags)
  5723   return MouseScrollHandler::SynthesizeNativeMouseScrollEvent(
  5724            this, aPoint, aNativeMessage,
  5725            (aNativeMessage == WM_MOUSEWHEEL || aNativeMessage == WM_VSCROLL) ?
  5726              static_cast<int32_t>(aDeltaY) : static_cast<int32_t>(aDeltaX),
  5727            aModifierFlags, aAdditionalFlags);
  5730 /**************************************************************
  5732  * SECTION: OnXXX message handlers
  5734  * For message handlers that need to be broken out or
  5735  * implemented in specific platform code.
  5737  **************************************************************/
  5739 void nsWindow::OnWindowPosChanged(WINDOWPOS* wp)
  5741   if (wp == nullptr)
  5742     return;
  5744 #ifdef WINSTATE_DEBUG_OUTPUT
  5745   if (mWnd == WinUtils::GetTopLevelHWND(mWnd)) {
  5746     PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("*** OnWindowPosChanged: [  top] "));
  5747   } else {
  5748     PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("*** OnWindowPosChanged: [child] "));
  5750   PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("WINDOWPOS flags:"));
  5751   if (wp->flags & SWP_FRAMECHANGED) {
  5752     PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_FRAMECHANGED "));
  5754   if (wp->flags & SWP_SHOWWINDOW) {
  5755     PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_SHOWWINDOW "));
  5757   if (wp->flags & SWP_NOSIZE) {
  5758     PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_NOSIZE "));
  5760   if (wp->flags & SWP_HIDEWINDOW) {
  5761     PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_HIDEWINDOW "));
  5763   if (wp->flags & SWP_NOZORDER) {
  5764     PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_NOZORDER "));
  5766   if (wp->flags & SWP_NOACTIVATE) {
  5767     PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_NOACTIVATE "));
  5769   PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("\n"));
  5770 #endif
  5772   // Handle window size mode changes
  5773   if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
  5775     // Bug 566135 - Windows theme code calls show window on SW_SHOWMINIMIZED
  5776     // windows when fullscreen games disable desktop composition. If we're
  5777     // minimized and not being activated, ignore the event and let windows
  5778     // handle it.
  5779     if (mSizeMode == nsSizeMode_Minimized && (wp->flags & SWP_NOACTIVATE))
  5780       return;
  5782     WINDOWPLACEMENT pl;
  5783     pl.length = sizeof(pl);
  5784     ::GetWindowPlacement(mWnd, &pl);
  5786     // Windows has just changed the size mode of this window. The call to
  5787     // SizeModeChanged will trigger a call into SetSizeMode where we will
  5788     // set the min/max window state again or for nsSizeMode_Normal, call
  5789     // SetWindow with a parameter of SW_RESTORE. There's no need however as
  5790     // this window's mode has already changed. Updating mSizeMode here
  5791     // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
  5792     // to window docking. (bug 489258)
  5793     if (pl.showCmd == SW_SHOWMAXIMIZED)
  5794       mSizeMode = (mFullscreenMode ? nsSizeMode_Fullscreen : nsSizeMode_Maximized);
  5795     else if (pl.showCmd == SW_SHOWMINIMIZED)
  5796       mSizeMode = nsSizeMode_Minimized;
  5797     else if (mFullscreenMode)
  5798       mSizeMode = nsSizeMode_Fullscreen;
  5799     else
  5800       mSizeMode = nsSizeMode_Normal;
  5802     // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
  5803     // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
  5804     // prevents the working set from being trimmed but keeps the window active.
  5805     // After the window is minimized, we need to do some touch up work on the
  5806     // active window. (bugs 76831 & 499816)
  5807     if (!sTrimOnMinimize && nsSizeMode_Minimized == mSizeMode)
  5808       ActivateOtherWindowHelper(mWnd);
  5810 #ifdef WINSTATE_DEBUG_OUTPUT
  5811     switch (mSizeMode) {
  5812       case nsSizeMode_Normal:
  5813           PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
  5814                  ("*** mSizeMode: nsSizeMode_Normal\n"));
  5815         break;
  5816       case nsSizeMode_Minimized:
  5817         PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
  5818                ("*** mSizeMode: nsSizeMode_Minimized\n"));
  5819         break;
  5820       case nsSizeMode_Maximized:
  5821           PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
  5822                  ("*** mSizeMode: nsSizeMode_Maximized\n"));
  5823         break;
  5824       default:
  5825           PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("*** mSizeMode: ??????\n"));
  5826         break;
  5827     };
  5828 #endif
  5830     if (mWidgetListener)
  5831       mWidgetListener->SizeModeChanged(mSizeMode);
  5833     // If window was restored, window activation was bypassed during the 
  5834     // SetSizeMode call originating from OnWindowPosChanging to avoid saving
  5835     // pre-restore attributes. Force activation now to get correct attributes.
  5836     if (mLastSizeMode != nsSizeMode_Normal && mSizeMode == nsSizeMode_Normal)
  5837       DispatchFocusToTopLevelWindow(true);
  5839     // Skip window size change events below on minimization.
  5840     if (mSizeMode == nsSizeMode_Minimized)
  5841       return;
  5844   // Handle window position changes
  5845   if (!(wp->flags & SWP_NOMOVE)) {
  5846     mBounds.x = wp->x;
  5847     mBounds.y = wp->y;
  5849     NotifyWindowMoved(wp->x, wp->y);
  5852   // Handle window size changes
  5853   if (!(wp->flags & SWP_NOSIZE)) {
  5854     RECT r;
  5855     int32_t newWidth, newHeight;
  5857     ::GetWindowRect(mWnd, &r);
  5859     newWidth  = r.right - r.left;
  5860     newHeight = r.bottom - r.top;
  5861     nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
  5863 #ifdef MOZ_XUL
  5864     if (eTransparencyTransparent == mTransparencyMode)
  5865       ResizeTranslucentWindow(newWidth, newHeight);
  5866 #endif
  5868     if (newWidth > mLastSize.width)
  5870       RECT drect;
  5872       // getting wider
  5873       drect.left   = wp->x + mLastSize.width;
  5874       drect.top    = wp->y;
  5875       drect.right  = drect.left + (newWidth - mLastSize.width);
  5876       drect.bottom = drect.top + newHeight;
  5878       ::RedrawWindow(mWnd, &drect, nullptr,
  5879                      RDW_INVALIDATE |
  5880                      RDW_NOERASE |
  5881                      RDW_NOINTERNALPAINT |
  5882                      RDW_ERASENOW |
  5883                      RDW_ALLCHILDREN);
  5885     if (newHeight > mLastSize.height)
  5887       RECT drect;
  5889       // getting taller
  5890       drect.left   = wp->x;
  5891       drect.top    = wp->y + mLastSize.height;
  5892       drect.right  = drect.left + newWidth;
  5893       drect.bottom = drect.top + (newHeight - mLastSize.height);
  5895       ::RedrawWindow(mWnd, &drect, nullptr,
  5896                      RDW_INVALIDATE |
  5897                      RDW_NOERASE |
  5898                      RDW_NOINTERNALPAINT |
  5899                      RDW_ERASENOW |
  5900                      RDW_ALLCHILDREN);
  5903     mBounds.width    = newWidth;
  5904     mBounds.height   = newHeight;
  5905     mLastSize.width  = newWidth;
  5906     mLastSize.height = newHeight;
  5908 #ifdef WINSTATE_DEBUG_OUTPUT
  5909     PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
  5910            ("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, 
  5911             newWidth, newHeight));
  5912 #endif
  5914     // If a maximized window is resized, recalculate the non-client margins.
  5915     if (mSizeMode == nsSizeMode_Maximized) {
  5916       if (UpdateNonClientMargins(nsSizeMode_Maximized, true)) {
  5917         // gecko resize event already sent by UpdateNonClientMargins.
  5918         return;
  5922     // Recalculate the width and height based on the client area for gecko events.
  5923     if (::GetClientRect(mWnd, &r)) {
  5924       rect.width  = r.right - r.left;
  5925       rect.height = r.bottom - r.top;
  5928     // Send a gecko resize event
  5929     OnResize(rect);
  5933 // static
  5934 void nsWindow::ActivateOtherWindowHelper(HWND aWnd)
  5936   // Find the next window that is enabled, visible, and not minimized.
  5937   HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT);
  5938   while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) ||
  5939                        ::IsIconic(hwndBelow))) {
  5940     hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT);
  5943   // Push ourselves to the bottom of the stack, then activate the
  5944   // next window.
  5945   ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0,
  5946                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
  5947   if (hwndBelow)
  5948     ::SetForegroundWindow(hwndBelow);
  5950   // Play the minimize sound while we're here, since that is also
  5951   // forgotten when we use SW_SHOWMINIMIZED.
  5952   nsCOMPtr<nsISound> sound(do_CreateInstance("@mozilla.org/sound;1"));
  5953   if (sound) {
  5954     sound->PlaySystemSound(NS_LITERAL_STRING("Minimize"));
  5958 void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info)
  5960   // Update non-client margins if the frame size is changing, and let the
  5961   // browser know we are changing size modes, so alternative css can kick in.
  5962   // If we're going into fullscreen mode, ignore this, since it'll reset
  5963   // margins to normal mode. 
  5964   if ((info->flags & SWP_FRAMECHANGED && !(info->flags & SWP_NOSIZE)) &&
  5965       mSizeMode != nsSizeMode_Fullscreen) {
  5966     WINDOWPLACEMENT pl;
  5967     pl.length = sizeof(pl);
  5968     ::GetWindowPlacement(mWnd, &pl);
  5969     nsSizeMode sizeMode;
  5970     if (pl.showCmd == SW_SHOWMAXIMIZED)
  5971       sizeMode = (mFullscreenMode ? nsSizeMode_Fullscreen : nsSizeMode_Maximized);
  5972     else if (pl.showCmd == SW_SHOWMINIMIZED)
  5973       sizeMode = nsSizeMode_Minimized;
  5974     else if (mFullscreenMode)
  5975       sizeMode = nsSizeMode_Fullscreen;
  5976     else
  5977       sizeMode = nsSizeMode_Normal;
  5979     if (mWidgetListener)
  5980       mWidgetListener->SizeModeChanged(sizeMode);
  5982     UpdateNonClientMargins(sizeMode, false);
  5985   // enforce local z-order rules
  5986   if (!(info->flags & SWP_NOZORDER)) {
  5987     HWND hwndAfter = info->hwndInsertAfter;
  5989     nsWindow *aboveWindow = 0;
  5990     nsWindowZ placement;
  5992     if (hwndAfter == HWND_BOTTOM)
  5993       placement = nsWindowZBottom;
  5994     else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
  5995       placement = nsWindowZTop;
  5996     else {
  5997       placement = nsWindowZRelative;
  5998       aboveWindow = WinUtils::GetNSWindowPtr(hwndAfter);
  6001     if (mWidgetListener) {
  6002       nsCOMPtr<nsIWidget> actualBelow = nullptr;
  6003       if (mWidgetListener->ZLevelChanged(false, &placement,
  6004                                          aboveWindow, getter_AddRefs(actualBelow))) {
  6005         if (placement == nsWindowZBottom)
  6006           info->hwndInsertAfter = HWND_BOTTOM;
  6007         else if (placement == nsWindowZTop)
  6008           info->hwndInsertAfter = HWND_TOP;
  6009         else {
  6010           info->hwndInsertAfter = (HWND)actualBelow->GetNativeData(NS_NATIVE_WINDOW);
  6015   // prevent rude external programs from making hidden window visible
  6016   if (mWindowType == eWindowType_invisible)
  6017     info->flags &= ~SWP_SHOWWINDOW;
  6020 void nsWindow::UserActivity()
  6022   // Check if we have the idle service, if not we try to get it.
  6023   if (!mIdleService) {
  6024     mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
  6027   // Check that we now have the idle service.
  6028   if (mIdleService) {
  6029     mIdleService->ResetIdleTimeOut(0);
  6033 bool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam)
  6035   uint32_t cInputs = LOWORD(wParam);
  6036   PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
  6038   if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) {
  6039     WidgetTouchEvent* touchEventToSend = nullptr;
  6040     WidgetTouchEvent* touchEndEventToSend = nullptr;
  6041     nsEventStatus status;
  6043     // Walk across the touch point array processing each contact point
  6044     for (uint32_t i = 0; i < cInputs; i++) {
  6045       uint32_t msg;
  6047       if (pInputs[i].dwFlags & (TOUCHEVENTF_DOWN | TOUCHEVENTF_MOVE)) {
  6048         // Create a standard touch event to send
  6049         if (!touchEventToSend) {
  6050           touchEventToSend = new WidgetTouchEvent(true, NS_TOUCH_MOVE, this);
  6051           touchEventToSend->time = ::GetMessageTime();
  6052           ModifierKeyState modifierKeyState;
  6053           modifierKeyState.InitInputEvent(*touchEventToSend);
  6056         // Pres shell expects this event to be a NS_TOUCH_START if new contact
  6057         // points have been added since the last event sent.
  6058         if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) {
  6059           touchEventToSend->message = msg = NS_TOUCH_START;
  6060         } else {
  6061           msg = NS_TOUCH_MOVE;
  6063       } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) {
  6064         // Pres shell expects removed contacts points to be delivered in a
  6065         // separate NS_TOUCH_END event containing only the contact points
  6066         // that were removed.
  6067         if (!touchEndEventToSend) {
  6068           touchEndEventToSend = new WidgetTouchEvent(true, NS_TOUCH_END, this);
  6069           touchEndEventToSend->time = ::GetMessageTime();
  6070           ModifierKeyState modifierKeyState;
  6071           modifierKeyState.InitInputEvent(*touchEndEventToSend);
  6073         msg = NS_TOUCH_END;
  6074       } else {
  6075         // Filter out spurious Windows events we don't understand, like palm
  6076         // contact.
  6077         continue;
  6080       // Setup the touch point we'll append to the touch event array
  6081       nsPointWin touchPoint;
  6082       touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
  6083       touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
  6084       touchPoint.ScreenToClient(mWnd);
  6085       nsRefPtr<Touch> touch =
  6086         new Touch(pInputs[i].dwID,
  6087                   touchPoint,
  6088                   /* radius, if known */
  6089                   pInputs[i].dwFlags & TOUCHINPUTMASKF_CONTACTAREA ?
  6090                     nsIntPoint(
  6091                       TOUCH_COORD_TO_PIXEL(pInputs[i].cxContact) / 2,
  6092                       TOUCH_COORD_TO_PIXEL(pInputs[i].cyContact) / 2) :
  6093                     nsIntPoint(1,1),
  6094                   /* rotation angle and force */
  6095                   0.0f, 0.0f);
  6097       // Append to the appropriate event
  6098       if (msg == NS_TOUCH_START || msg == NS_TOUCH_MOVE) {
  6099         touchEventToSend->touches.AppendElement(touch);
  6100       } else {
  6101         touchEndEventToSend->touches.AppendElement(touch);
  6105     // Dispatch touch start and move event if we have one.
  6106     if (touchEventToSend) {
  6107       DispatchEvent(touchEventToSend, status);
  6108       delete touchEventToSend;
  6111     // Dispatch touch end event if we have one.
  6112     if (touchEndEventToSend) {
  6113       DispatchEvent(touchEndEventToSend, status);
  6114       delete touchEndEventToSend;
  6118   delete [] pInputs;
  6119   mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam);
  6120   return true;
  6123 static int32_t RoundDown(double aDouble)
  6125   return aDouble > 0 ? static_cast<int32_t>(floor(aDouble)) :
  6126                        static_cast<int32_t>(ceil(aDouble));
  6129 // Gesture event processing. Handles WM_GESTURE events.
  6130 bool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
  6132   if (gIsPointerEventsEnabled) {
  6133     return false;
  6136   // Treatment for pan events which translate into scroll events:
  6137   if (mGesture.IsPanEvent(lParam)) {
  6138     if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
  6139       return false; // ignore
  6141     nsEventStatus status;
  6143     WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this);
  6145     ModifierKeyState modifierKeyState;
  6146     modifierKeyState.InitInputEvent(wheelEvent);
  6148     wheelEvent.button      = 0;
  6149     wheelEvent.time        = ::GetMessageTime();
  6150     wheelEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
  6152     bool endFeedback = true;
  6154     if (mGesture.PanDeltaToPixelScroll(wheelEvent)) {
  6155       DispatchEvent(&wheelEvent, status);
  6158     if (mDisplayPanFeedback) {
  6159       mGesture.UpdatePanFeedbackX(mWnd,
  6160                                   DeprecatedAbs(RoundDown(wheelEvent.overflowDeltaX)),
  6161                                   endFeedback);
  6162       mGesture.UpdatePanFeedbackY(mWnd,
  6163                                   DeprecatedAbs(RoundDown(wheelEvent.overflowDeltaY)),
  6164                                   endFeedback);
  6165       mGesture.PanFeedbackFinalize(mWnd, endFeedback);
  6168     mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
  6170     return true;
  6173   // Other gestures translate into simple gesture events:
  6174   WidgetSimpleGestureEvent event(true, 0, this);
  6175   if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) {
  6176     return false; // fall through to DefWndProc
  6179   // Polish up and send off the new event
  6180   ModifierKeyState modifierKeyState;
  6181   modifierKeyState.InitInputEvent(event);
  6182   event.button    = 0;
  6183   event.time      = ::GetMessageTime();
  6184   event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
  6186   nsEventStatus status;
  6187   DispatchEvent(&event, status);
  6188   if (status == nsEventStatus_eIgnore) {
  6189     return false; // Ignored, fall through
  6192   // Only close this if we process and return true.
  6193   mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
  6195   return true; // Handled
  6198 static BOOL WINAPI EnumFirstChild(HWND hwnd, LPARAM lParam)
  6200   *((HWND*)lParam) = hwnd;
  6201   return FALSE;
  6204 static void InvalidatePluginAsWorkaround(nsWindow *aWindow, const nsIntRect &aRect)
  6206   aWindow->Invalidate(aRect);
  6208   // XXX - Even more evil workaround!! See bug 762948, flash's bottom
  6209   // level sandboxed window doesn't seem to get our invalidate. We send
  6210   // an invalidate to it manually. This is totally specialized for this
  6211   // bug, for other child window structures this will just be a more or
  6212   // less bogus invalidate but since that should not have any bad
  6213   // side-effects this will have to do for now.
  6214   HWND current = (HWND)aWindow->GetNativeData(NS_NATIVE_WINDOW);
  6216   RECT windowRect;
  6217   RECT parentRect;
  6219   ::GetWindowRect(current, &parentRect);
  6221   HWND next = current;
  6223   do {
  6224     current = next;
  6226     ::EnumChildWindows(current, &EnumFirstChild, (LPARAM)&next);
  6228     ::GetWindowRect(next, &windowRect);
  6229     // This is relative to the screen, adjust it to be relative to the
  6230     // window we're reconfiguring.
  6231     windowRect.left -= parentRect.left;
  6232     windowRect.top -= parentRect.top;
  6233   } while (next != current && windowRect.top == 0 && windowRect.left == 0);
  6235   if (windowRect.top == 0 && windowRect.left == 0) {
  6236     RECT rect;
  6237     rect.left   = aRect.x;
  6238     rect.top    = aRect.y;
  6239     rect.right  = aRect.XMost();
  6240     rect.bottom = aRect.YMost();
  6242     ::InvalidateRect(next, &rect, FALSE);
  6246 nsresult
  6247 nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
  6249   // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
  6250   // here, if that helps in some situations. So far I haven't seen a
  6251   // need.
  6252   for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
  6253     const Configuration& configuration = aConfigurations[i];
  6254     nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
  6255     NS_ASSERTION(w->GetParent() == this,
  6256                  "Configured widget is not a child");
  6257     nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, true);
  6258     NS_ENSURE_SUCCESS(rv, rv);
  6259     nsIntRect bounds;
  6260     w->GetBounds(bounds);
  6261     if (bounds.Size() != configuration.mBounds.Size()) {
  6262       w->Resize(configuration.mBounds.x, configuration.mBounds.y,
  6263                 configuration.mBounds.width, configuration.mBounds.height,
  6264                 true);
  6265     } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
  6266       w->Move(configuration.mBounds.x, configuration.mBounds.y);
  6269       if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
  6270           gfxWindowsPlatform::RENDER_DIRECT2D ||
  6271           GetLayerManager()->GetBackendType() != LayersBackend::LAYERS_BASIC) {
  6272         // XXX - Workaround for Bug 587508. This will invalidate the part of the
  6273         // plugin window that might be touched by moving content somehow. The
  6274         // underlying problem should be found and fixed!
  6275         nsIntRegion r;
  6276         r.Sub(bounds, configuration.mBounds);
  6277         r.MoveBy(-bounds.x,
  6278                  -bounds.y);
  6279         nsIntRect toInvalidate = r.GetBounds();
  6281         InvalidatePluginAsWorkaround(w, toInvalidate);
  6284     rv = w->SetWindowClipRegion(configuration.mClipRegion, false);
  6285     NS_ENSURE_SUCCESS(rv, rv);
  6287   return NS_OK;
  6290 static HRGN
  6291 CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
  6293   int32_t size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
  6294   nsAutoTArray<uint8_t,100> buf;
  6295   buf.SetLength(size);
  6296   RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
  6297   RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
  6298   data->rdh.dwSize = sizeof(data->rdh);
  6299   data->rdh.iType = RDH_RECTANGLES;
  6300   data->rdh.nCount = aRects.Length();
  6301   nsIntRect bounds;
  6302   for (uint32_t i = 0; i < aRects.Length(); ++i) {
  6303     const nsIntRect& r = aRects[i];
  6304     bounds.UnionRect(bounds, r);
  6305     ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
  6307   ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
  6308   return ::ExtCreateRegion(nullptr, buf.Length(), data);
  6311 static void
  6312 ArrayFromRegion(const nsIntRegion& aRegion, nsTArray<nsIntRect>& aRects)
  6314   const nsIntRect* r;
  6315   for (nsIntRegionRectIterator iter(aRegion); (r = iter.Next());) {
  6316     aRects.AppendElement(*r);
  6320 nsresult
  6321 nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
  6322                               bool aIntersectWithExisting)
  6324   if (!aIntersectWithExisting) {
  6325     if (!StoreWindowClipRegion(aRects))
  6326       return NS_OK;
  6327   } else {
  6328     // In this case still early return if nothing changed.
  6329     if (mClipRects && mClipRectCount == aRects.Length() &&
  6330         memcmp(mClipRects,
  6331                aRects.Elements(),
  6332                sizeof(nsIntRect)*mClipRectCount) == 0) {
  6333       return NS_OK;
  6336     // get current rects
  6337     nsTArray<nsIntRect> currentRects;
  6338     GetWindowClipRegion(&currentRects);
  6339     // create region from them
  6340     nsIntRegion currentRegion = RegionFromArray(currentRects);
  6341     // create region from new rects
  6342     nsIntRegion newRegion = RegionFromArray(aRects);
  6343     // intersect regions
  6344     nsIntRegion intersection;
  6345     intersection.And(currentRegion, newRegion);
  6346     // create int rect array from intersection
  6347     nsTArray<nsIntRect> rects;
  6348     ArrayFromRegion(intersection, rects);
  6349     // store
  6350     if (!StoreWindowClipRegion(rects))
  6351       return NS_OK;
  6354   HRGN dest = CreateHRGNFromArray(aRects);
  6355   if (!dest)
  6356     return NS_ERROR_OUT_OF_MEMORY;
  6358   if (aIntersectWithExisting) {
  6359     HRGN current = ::CreateRectRgn(0, 0, 0, 0);
  6360     if (current) {
  6361       if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
  6362         ::CombineRgn(dest, dest, current, RGN_AND);
  6364       ::DeleteObject(current);
  6368   // If a plugin is not visible, especially if it is in a background tab,
  6369   // it should not be able to steal keyboard focus.  This code checks whether
  6370   // the region that the plugin is being clipped to is NULLREGION.  If it is,
  6371   // the plugin window gets disabled.
  6372   if(mWindowType == eWindowType_plugin) {
  6373     if(NULLREGION == ::CombineRgn(dest, dest, dest, RGN_OR)) {
  6374       ::ShowWindow(mWnd, SW_HIDE);
  6375       ::EnableWindow(mWnd, FALSE);
  6376     } else {
  6377       ::EnableWindow(mWnd, TRUE);
  6378       ::ShowWindow(mWnd, SW_SHOW);
  6381   if (!::SetWindowRgn(mWnd, dest, TRUE)) {
  6382     ::DeleteObject(dest);
  6383     return NS_ERROR_FAILURE;
  6385   return NS_OK;
  6388 // WM_DESTROY event handler
  6389 void nsWindow::OnDestroy()
  6391   mOnDestroyCalled = true;
  6393   // Make sure we don't get destroyed in the process of tearing down.
  6394   nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
  6396   // Dispatch the destroy notification.
  6397   if (!mInDtor)
  6398     NotifyWindowDestroyed();
  6400   // Prevent the widget from sending additional events.
  6401   mWidgetListener = nullptr;
  6402   mAttachedWidgetListener = nullptr;
  6404   // Free our subclass and clear |this| stored in the window props. We will no longer
  6405   // receive events from Windows after this point.
  6406   SubclassWindow(FALSE);
  6408   // Once mWidgetListener is cleared and the subclass is reset, sCurrentWindow can be
  6409   // cleared. (It's used in tracking windows for mouse events.)
  6410   if (sCurrentWindow == this)
  6411     sCurrentWindow = nullptr;
  6413   // Disconnects us from our parent, will call our GetParent().
  6414   nsBaseWidget::Destroy();
  6416   // Release references to children, device context, toolkit, and app shell.
  6417   nsBaseWidget::OnDestroy();
  6419   // Clear our native parent handle.
  6420   // XXX Windows will take care of this in the proper order, and SetParent(nullptr)'s
  6421   // remove child on the parent already took place in nsBaseWidget's Destroy call above.
  6422   //SetParent(nullptr);
  6423   mParent = nullptr;
  6425   // We have to destroy the native drag target before we null out our window pointer.
  6426   EnableDragDrop(false);
  6428   // If we're going away and for some reason we're still the rollup widget, rollup and
  6429   // turn off capture.
  6430   nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
  6431   nsCOMPtr<nsIWidget> rollupWidget;
  6432   if (rollupListener) {
  6433     rollupWidget = rollupListener->GetRollupWidget();
  6435   if (this == rollupWidget) {
  6436     if ( rollupListener )
  6437       rollupListener->Rollup(0, nullptr, nullptr);
  6438     CaptureRollupEvents(nullptr, false);
  6441   IMEHandler::OnDestroyWindow(this);
  6443   // Turn off mouse trails if enabled.
  6444   MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
  6445   if (mtrailer) {
  6446     if (mtrailer->GetMouseTrailerWindow() == mWnd)
  6447       mtrailer->DestroyTimer();
  6449     if (mtrailer->GetCaptureWindow() == mWnd)
  6450       mtrailer->SetCaptureWindow(nullptr);
  6453   // Free GDI window class objects
  6454   if (mBrush) {
  6455     VERIFY(::DeleteObject(mBrush));
  6456     mBrush = nullptr;
  6460   // Destroy any custom cursor resources.
  6461   if (mCursor == -1)
  6462     SetCursor(eCursor_standard);
  6464 #ifdef MOZ_XUL
  6465   // Reset transparency
  6466   if (eTransparencyTransparent == mTransparencyMode)
  6467     SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
  6468 #endif
  6470   // Finalize panning feedback to possibly restore window displacement
  6471   mGesture.PanFeedbackFinalize(mWnd, true);
  6473   // Clear the main HWND.
  6474   mWnd = nullptr;
  6477 // Send a resize message to the listener
  6478 bool nsWindow::OnResize(nsIntRect &aWindowRect)
  6480   bool result = mWidgetListener ?
  6481                 mWidgetListener->WindowResized(this, aWindowRect.width, aWindowRect.height) : false;
  6483   // If there is an attached view, inform it as well as the normal widget listener.
  6484   if (mAttachedWidgetListener) {
  6485     return mAttachedWidgetListener->WindowResized(this, aWindowRect.width, aWindowRect.height);
  6488   return result;
  6491 bool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
  6493   return true;
  6496 // Can be overriden. Controls auto-erase of background.
  6497 bool nsWindow::AutoErase(HDC dc)
  6499   return false;
  6502 void
  6503 nsWindow::AllowD3D9Callback(nsWindow *aWindow)
  6505   if (aWindow->mLayerManager && !aWindow->ShouldUseOffMainThreadCompositing()) {
  6506     aWindow->mLayerManager->Destroy();
  6507     aWindow->mLayerManager = nullptr;
  6511 void
  6512 nsWindow::AllowD3D9WithReinitializeCallback(nsWindow *aWindow)
  6514   if (aWindow->mLayerManager && !aWindow->ShouldUseOffMainThreadCompositing()) {
  6515     aWindow->mLayerManager->Destroy();
  6516     aWindow->mLayerManager = nullptr;
  6517     (void) aWindow->GetLayerManager();
  6521 void
  6522 nsWindow::StartAllowingD3D9(bool aReinitialize)
  6524   sAllowD3D9 = true;
  6526   LayerManagerPrefs prefs;
  6527   GetLayerManagerPrefs(&prefs);
  6528   if (prefs.mDisableAcceleration) {
  6529     // The guarantee here is, if there's *any* chance that after we
  6530     // throw out our layer managers we'd create at least one new,
  6531     // accelerated one, we *will* throw out all the current layer
  6532     // managers.  We early-return here because currently, if
  6533     // |disableAcceleration|, we will always use basic managers and
  6534     // it's a waste to recreate them. If we're using OMTC we don't want to
  6535     // recreate out layer manager and its compositor either. This is even
  6536     // more wasteful.
  6537     //
  6538     // NB: the above implies that it's eminently possible for us to
  6539     // skip this early return but still recreate basic managers.
  6540     // That's OK.  It's *not* OK to take this early return when we
  6541     // *might* have created an accelerated manager.
  6542     return;
  6545   if (aReinitialize) {
  6546     EnumAllWindows(AllowD3D9WithReinitializeCallback);
  6547   } else {
  6548     EnumAllWindows(AllowD3D9Callback);
  6552 bool
  6553 nsWindow::ShouldUseOffMainThreadCompositing()
  6555   // We don't currently support using an accelerated layer manager with
  6556   // transparent windows so don't even try. I'm also not sure if we even
  6557   // want to support this case. See bug 593471
  6558   if (mTransparencyMode == eTransparencyTransparent) {
  6559     return false;
  6562   return nsBaseWidget::ShouldUseOffMainThreadCompositing();
  6565 void
  6566 nsWindow::GetPreferredCompositorBackends(nsTArray<LayersBackend>& aHints)
  6568   LayerManagerPrefs prefs;
  6569   GetLayerManagerPrefs(&prefs);
  6571   // We don't currently support using an accelerated layer manager with
  6572   // transparent windows so don't even try. I'm also not sure if we even
  6573   // want to support this case. See bug 593471
  6574   if (!(prefs.mDisableAcceleration ||
  6575         mTransparencyMode == eTransparencyTransparent)) {
  6576     if (prefs.mPreferOpenGL) {
  6577       aHints.AppendElement(LayersBackend::LAYERS_OPENGL);
  6579     if (!prefs.mPreferD3D9) {
  6580       aHints.AppendElement(LayersBackend::LAYERS_D3D11);
  6582     aHints.AppendElement(LayersBackend::LAYERS_D3D9);
  6584   aHints.AppendElement(LayersBackend::LAYERS_BASIC);
  6587 void
  6588 nsWindow::WindowUsesOMTC()
  6590   ULONG_PTR style = ::GetClassLongPtr(mWnd, GCL_STYLE);
  6591   if (!style) {
  6592     NS_WARNING("Could not get window class style");
  6593     return;
  6595   style |= CS_HREDRAW | CS_VREDRAW;
  6596   DebugOnly<ULONG_PTR> result = ::SetClassLongPtr(mWnd, GCL_STYLE, style);
  6597   NS_WARN_IF_FALSE(result, "Could not reset window class style");
  6600 bool
  6601 nsWindow::HasBogusPopupsDropShadowOnMultiMonitor() {
  6602   if (sHasBogusPopupsDropShadowOnMultiMonitor == TRI_UNKNOWN) {
  6603     // Since any change in the preferences requires a restart, this can be
  6604     // done just once.
  6605     // Check for Direct2D first.
  6606     sHasBogusPopupsDropShadowOnMultiMonitor =
  6607       gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
  6608         gfxWindowsPlatform::RENDER_DIRECT2D ? TRI_TRUE : TRI_FALSE;
  6609     if (!sHasBogusPopupsDropShadowOnMultiMonitor) {
  6610       // Otherwise check if Direct3D 9 may be used.
  6611       LayerManagerPrefs prefs;
  6612       GetLayerManagerPrefs(&prefs);
  6613       if (!prefs.mDisableAcceleration && !prefs.mPreferOpenGL) {
  6614         nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
  6615         if (gfxInfo) {
  6616           int32_t status;
  6617           if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) {
  6618             if (status == nsIGfxInfo::FEATURE_NO_INFO || prefs.mForceAcceleration)
  6620               sHasBogusPopupsDropShadowOnMultiMonitor = TRI_TRUE;
  6627   return !!sHasBogusPopupsDropShadowOnMultiMonitor;
  6630 void
  6631 nsWindow::OnSysColorChanged()
  6633   if (mWindowType == eWindowType_invisible) {
  6634     ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, WM_SYSCOLORCHANGE);
  6636   else {
  6637     // Note: This is sent for child windows as well as top-level windows.
  6638     // The Win32 toolkit normally only sends these events to top-level windows.
  6639     // But we cycle through all of the childwindows and send it to them as well
  6640     // so all presentations get notified properly.
  6641     // See nsWindow::GlobalMsgWindowProc.
  6642     NotifySysColorChanged();
  6646 /**************************************************************
  6647  **************************************************************
  6648  **
  6649  ** BLOCK: IME management and accessibility
  6650  **
  6651  ** Handles managing IME input and accessibility.
  6652  **
  6653  **************************************************************
  6654  **************************************************************/
  6656 NS_IMETHODIMP
  6657 nsWindow::NotifyIME(const IMENotification& aIMENotification)
  6659   return IMEHandler::NotifyIME(this, aIMENotification);
  6662 NS_IMETHODIMP_(void)
  6663 nsWindow::SetInputContext(const InputContext& aContext,
  6664                           const InputContextAction& aAction)
  6666   InputContext newInputContext = aContext;
  6667   IMEHandler::SetInputContext(this, newInputContext, aAction);
  6668   mInputContext = newInputContext;
  6671 NS_IMETHODIMP_(InputContext)
  6672 nsWindow::GetInputContext()
  6674   mInputContext.mIMEState.mOpen = IMEState::CLOSED;
  6675   if (WinUtils::IsIMEEnabled(mInputContext) && IMEHandler::GetOpenState(this)) {
  6676     mInputContext.mIMEState.mOpen = IMEState::OPEN;
  6677   } else {
  6678     mInputContext.mIMEState.mOpen = IMEState::CLOSED;
  6680   return mInputContext;
  6683 NS_IMETHODIMP
  6684 nsWindow::GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState)
  6686 #ifdef DEBUG_KBSTATE
  6687   PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("GetToggledKeyState\n"));
  6688 #endif 
  6689   NS_ENSURE_ARG_POINTER(aLEDState);
  6690   *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
  6691   return NS_OK;
  6694 nsIMEUpdatePreference
  6695 nsWindow::GetIMEUpdatePreference()
  6697   return IMEHandler::GetUpdatePreference();
  6700 #ifdef ACCESSIBILITY
  6701 #ifdef DEBUG
  6702 #define NS_LOG_WMGETOBJECT(aWnd, aHwnd, aAcc)                                  \
  6703   if (a11y::logging::IsEnabled(a11y::logging::ePlatforms)) {                   \
  6704     printf("Get the window:\n  {\n     HWND: %d, parent HWND: %d, wndobj: %p,\n",\
  6705            aHwnd, ::GetParent(aHwnd), aWnd);                                   \
  6706     printf("     acc: %p", aAcc);                                              \
  6707     if (aAcc) {                                                                \
  6708       nsAutoString name;                                                       \
  6709       aAcc->Name(name);                                                        \
  6710       printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get());              \
  6711     }                                                                          \
  6712     printf("\n }\n");                                                          \
  6715 #else
  6716 #define NS_LOG_WMGETOBJECT(aWnd, aHwnd, aAcc)
  6717 #endif
  6719 a11y::Accessible*
  6720 nsWindow::GetAccessible()
  6722   // If the pref was ePlatformIsDisabled, return null here, disabling a11y.
  6723   if (a11y::PlatformDisabledState() == a11y::ePlatformIsDisabled)
  6724     return nullptr;
  6726   if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) {
  6727     return nullptr;
  6730   // In case of popup window return a popup accessible.
  6731   nsView* view = nsView::GetViewFor(this);
  6732   if (view) {
  6733     nsIFrame* frame = view->GetFrame();
  6734     if (frame && nsLayoutUtils::IsPopup(frame)) {
  6735       nsCOMPtr<nsIAccessibilityService> accService =
  6736         services::GetAccessibilityService();
  6737       if (accService) {
  6738         a11y::DocAccessible* docAcc =
  6739           GetAccService()->GetDocAccessible(frame->PresContext()->PresShell());
  6740         if (docAcc) {
  6741           NS_LOG_WMGETOBJECT(this, mWnd,
  6742                              docAcc->GetAccessibleOrDescendant(frame->GetContent()));
  6743           return docAcc->GetAccessibleOrDescendant(frame->GetContent());
  6749   // otherwise root document accessible.
  6750   NS_LOG_WMGETOBJECT(this, mWnd, GetRootAccessible());
  6751   return GetRootAccessible();
  6753 #endif
  6755 /**************************************************************
  6756  **************************************************************
  6757  **
  6758  ** BLOCK: Transparency
  6759  **
  6760  ** Window transparency helpers.
  6761  **
  6762  **************************************************************
  6763  **************************************************************/
  6765 #ifdef MOZ_XUL
  6767 void nsWindow::ResizeTranslucentWindow(int32_t aNewWidth, int32_t aNewHeight, bool force)
  6769   if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
  6770     return;
  6772   nsRefPtr<gfxWindowsSurface> newSurface =
  6773     new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxImageFormat::ARGB32);
  6774   mTransparentSurface = newSurface;
  6775   mMemoryDC = newSurface->GetDC();
  6778 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
  6780   if (aMode == mTransparencyMode)
  6781     return;
  6783   // stop on dialogs and popups!
  6784   HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true);
  6785   nsWindow* parent = WinUtils::GetNSWindowPtr(hWnd);
  6787   if (!parent)
  6789     NS_WARNING("Trying to use transparent chrome in an embedded context");
  6790     return;
  6793   if (parent != this) {
  6794     NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
  6797   if (aMode == eTransparencyTransparent) {
  6798     // If we're switching to the use of a transparent window, hide the chrome
  6799     // on our parent.
  6800     HideWindowChrome(true);
  6801   } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) {
  6802     // if we're switching out of transparent, re-enable our parent's chrome.
  6803     HideWindowChrome(false);
  6806   LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE),
  6807     exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
  6809    if (parent->mIsVisible)
  6810      style |= WS_VISIBLE;
  6811    if (parent->mSizeMode == nsSizeMode_Maximized)
  6812      style |= WS_MAXIMIZE;
  6813    else if (parent->mSizeMode == nsSizeMode_Minimized)
  6814      style |= WS_MINIMIZE;
  6816    if (aMode == eTransparencyTransparent)
  6817      exStyle |= WS_EX_LAYERED;
  6818    else
  6819      exStyle &= ~WS_EX_LAYERED;
  6821   VERIFY_WINDOW_STYLE(style);
  6822   ::SetWindowLongPtrW(hWnd, GWL_STYLE, style);
  6823   ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle);
  6825   if (HasGlass())
  6826     memset(&mGlassMargins, 0, sizeof mGlassMargins);
  6827   mTransparencyMode = aMode;
  6829   SetupTranslucentWindowMemoryBitmap(aMode);
  6830   UpdateGlass();
  6833 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
  6835   if (eTransparencyTransparent == aMode) {
  6836     ResizeTranslucentWindow(mBounds.width, mBounds.height, true);
  6837   } else {
  6838     mTransparentSurface = nullptr;
  6839     mMemoryDC = nullptr;
  6843 void nsWindow::ClearTranslucentWindow()
  6845   if (mTransparentSurface) {
  6846     nsRefPtr<gfxContext> thebesContext = new gfxContext(mTransparentSurface);
  6847     thebesContext->SetOperator(gfxContext::OPERATOR_CLEAR);
  6848     thebesContext->Paint();
  6849     UpdateTranslucentWindow();
  6853 nsresult nsWindow::UpdateTranslucentWindow()
  6855   if (mBounds.IsEmpty())
  6856     return NS_OK;
  6858   ::GdiFlush();
  6860   BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
  6861   SIZE winSize = { mBounds.width, mBounds.height };
  6862   POINT srcPos = { 0, 0 };
  6863   HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true);
  6864   RECT winRect;
  6865   ::GetWindowRect(hWnd, &winRect);
  6867   // perform the alpha blend
  6868   bool updateSuccesful = 
  6869     ::UpdateLayeredWindow(hWnd, nullptr, (POINT*)&winRect, &winSize, mMemoryDC,
  6870                           &srcPos, 0, &bf, ULW_ALPHA);
  6872   if (!updateSuccesful) {
  6873     return NS_ERROR_FAILURE;
  6876   return NS_OK;
  6879 #endif //MOZ_XUL
  6881 /**************************************************************
  6882  **************************************************************
  6883  **
  6884  ** BLOCK: Popup rollup hooks
  6885  **
  6886  ** Deals with CaptureRollup on popup windows.
  6887  **
  6888  **************************************************************
  6889  **************************************************************/
  6891 // Schedules a timer for a window, so we can rollup after processing the hook event
  6892 void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId)
  6894   // In some cases multiple hooks may be scheduled
  6895   // so ignore any other requests once one timer is scheduled
  6896   if (sHookTimerId == 0) {
  6897     // Remember the window handle and the message ID to be used later
  6898     sRollupMsgId = aMsgId;
  6899     sRollupMsgWnd = aWnd;
  6900     // Schedule native timer for doing the rollup after
  6901     // this event is done being processed
  6902     sHookTimerId = ::SetTimer(nullptr, 0, 0, (TIMERPROC)HookTimerForPopups);
  6903     NS_ASSERTION(sHookTimerId, "Timer couldn't be created.");
  6907 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
  6908 int gLastMsgCode = 0;
  6909 extern MSGFEventMsgInfo gMSGFEvents[];
  6910 #endif
  6912 // Process Menu messages, rollup when popup is clicked.
  6913 LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam)
  6915 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
  6916   if (sProcessHook) {
  6917     MSG* pMsg = (MSG*)lParam;
  6919     int inx = 0;
  6920     while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != nullptr) {
  6921       inx++;
  6923     if (code != gLastMsgCode) {
  6924       if (gMSGFEvents[inx].mId == code) {
  6925 #ifdef DEBUG
  6926         PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
  6927                ("MozSpecialMessageProc - code: 0x%X  - %s  hw: %p\n", 
  6928                 code, gMSGFEvents[inx].mStr, pMsg->hwnd));
  6929 #endif
  6930       } else {
  6931 #ifdef DEBUG
  6932         PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
  6933                ("MozSpecialMessageProc - code: 0x%X  - %d  hw: %p\n", 
  6934                 code, gMSGFEvents[inx].mId, pMsg->hwnd));
  6935 #endif
  6937       gLastMsgCode = code;
  6939     PrintEvent(pMsg->message, FALSE, FALSE);
  6941 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
  6943   if (sProcessHook && code == MSGF_MENU) {
  6944     MSG* pMsg = (MSG*)lParam;
  6945     ScheduleHookTimer( pMsg->hwnd, pMsg->message);
  6948   return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
  6951 // Process all mouse messages. Roll up when a click is in a native window
  6952 // that doesn't have an nsIWidget.
  6953 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
  6955   if (sProcessHook) {
  6956     switch (WinUtils::GetNativeMessage(wParam)) {
  6957       case WM_LBUTTONDOWN:
  6958       case WM_RBUTTONDOWN:
  6959       case WM_MBUTTONDOWN:
  6960       case WM_MOUSEWHEEL:
  6961       case WM_MOUSEHWHEEL:
  6963         MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
  6964         nsIWidget* mozWin = WinUtils::GetNSWindowPtr(ms->hwnd);
  6965         if (mozWin) {
  6966           // If this window is windowed plugin window, the mouse events are not
  6967           // sent to us.
  6968           if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin)
  6969             ScheduleHookTimer(ms->hwnd, (UINT)wParam);
  6970         } else {
  6971           ScheduleHookTimer(ms->hwnd, (UINT)wParam);
  6973         break;
  6977   return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam);
  6980 // Process all messages. Roll up when the window is moving, or
  6981 // is resizing or when maximized or mininized.
  6982 LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam)
  6984 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
  6985   if (sProcessHook) {
  6986     CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
  6987     PrintEvent(cwpt->message, FALSE, FALSE);
  6989 #endif
  6991   if (sProcessHook) {
  6992     CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
  6993     if (cwpt->message == WM_MOVING ||
  6994         cwpt->message == WM_SIZING ||
  6995         cwpt->message == WM_GETMINMAXINFO) {
  6996       ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message);
  7000   return ::CallNextHookEx(sCallProcHook, code, wParam, lParam);
  7003 // Register the special "hooks" for dropdown processing.
  7004 void nsWindow::RegisterSpecialDropdownHooks()
  7006   NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!");
  7007   NS_ASSERTION(!sCallProcHook,  "sCallProcHook must be NULL!");
  7009   DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
  7011   // Install msg hook for moving the window and resizing
  7012   if (!sMsgFilterHook) {
  7013     DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
  7014     sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter,
  7015                                       nullptr, GetCurrentThreadId());
  7016 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
  7017     if (!sMsgFilterHook) {
  7018       PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
  7019              ("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n"));
  7021 #endif
  7024   // Install msg hook for menus
  7025   if (!sCallProcHook) {
  7026     DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
  7027     sCallProcHook  = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc,
  7028                                       nullptr, GetCurrentThreadId());
  7029 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
  7030     if (!sCallProcHook) {
  7031       PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
  7032              ("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n"));
  7034 #endif
  7037   // Install msg hook for the mouse
  7038   if (!sCallMouseHook) {
  7039     DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
  7040     sCallMouseHook  = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc,
  7041                                        nullptr, GetCurrentThreadId());
  7042 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
  7043     if (!sCallMouseHook) {
  7044       PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
  7045              ("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n"));
  7047 #endif
  7051 // Unhook special message hooks for dropdowns.
  7052 void nsWindow::UnregisterSpecialDropdownHooks()
  7054   DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
  7056   if (sCallProcHook) {
  7057     DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
  7058     if (!::UnhookWindowsHookEx(sCallProcHook)) {
  7059       DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
  7061     sCallProcHook = nullptr;
  7064   if (sMsgFilterHook) {
  7065     DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
  7066     if (!::UnhookWindowsHookEx(sMsgFilterHook)) {
  7067       DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
  7069     sMsgFilterHook = nullptr;
  7072   if (sCallMouseHook) {
  7073     DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
  7074     if (!::UnhookWindowsHookEx(sCallMouseHook)) {
  7075       DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
  7077     sCallMouseHook = nullptr;
  7081 // This timer is designed to only fire one time at most each time a "hook" function
  7082 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
  7083 // hook, but that hook event or a subsequent event may roll up the dropdown before
  7084 // this timer function is executed.
  7085 //
  7086 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
  7087 // before this function fires.
  7088 VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
  7090   if (sHookTimerId != 0) {
  7091     // if the window is nullptr then we need to use the ID to kill the timer
  7092     BOOL status = ::KillTimer(nullptr, sHookTimerId);
  7093     NS_ASSERTION(status, "Hook Timer was not killed.");
  7094     sHookTimerId = 0;
  7097   if (sRollupMsgId != 0) {
  7098     // Note: DealWithPopups does the check to make sure that the rollup widget is set.
  7099     LRESULT popupHandlingResult;
  7100     nsAutoRollup autoRollup;
  7101     DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
  7102     sRollupMsgId = 0;
  7103     sRollupMsgWnd = nullptr;
  7107 BOOL CALLBACK nsWindow::ClearResourcesCallback(HWND aWnd, LPARAM aMsg)
  7109     nsWindow *window = WinUtils::GetNSWindowPtr(aWnd);
  7110     if (window) {
  7111         window->ClearCachedResources();
  7113     return TRUE;
  7116 void
  7117 nsWindow::ClearCachedResources()
  7119     if (mLayerManager &&
  7120         mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) {
  7121       mLayerManager->ClearCachedResources();
  7123     ::EnumChildWindows(mWnd, nsWindow::ClearResourcesCallback, 0);
  7126 static bool IsDifferentThreadWindow(HWND aWnd)
  7128   return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, nullptr);
  7131 // static
  7132 bool
  7133 nsWindow::EventIsInsideWindow(nsWindow* aWindow)
  7135   RECT r;
  7136   ::GetWindowRect(aWindow->mWnd, &r);
  7137   DWORD pos = ::GetMessagePos();
  7138   POINT mp;
  7139   mp.x = GET_X_LPARAM(pos);
  7140   mp.y = GET_Y_LPARAM(pos);
  7142   // was the event inside this window?
  7143   return static_cast<bool>(::PtInRect(&r, mp));
  7146 // static
  7147 bool
  7148 nsWindow::GetPopupsToRollup(nsIRollupListener* aRollupListener,
  7149                             uint32_t* aPopupsToRollup)
  7151   // If we're dealing with menus, we probably have submenus and we don't want
  7152   // to rollup some of them if the click is in a parent menu of the current
  7153   // submenu.
  7154   *aPopupsToRollup = UINT32_MAX;
  7155   nsAutoTArray<nsIWidget*, 5> widgetChain;
  7156   uint32_t sameTypeCount =
  7157     aRollupListener->GetSubmenuWidgetChain(&widgetChain);
  7158   for (uint32_t i = 0; i < widgetChain.Length(); ++i) {
  7159     nsIWidget* widget = widgetChain[i];
  7160     if (EventIsInsideWindow(static_cast<nsWindow*>(widget))) {
  7161       // Don't roll up if the mouse event occurred within a menu of the
  7162       // same type. If the mouse event occurred in a menu higher than that,
  7163       // roll up, but pass the number of popups to Rollup so that only those
  7164       // of the same type close up.
  7165       if (i < sameTypeCount) {
  7166         return false;
  7169       *aPopupsToRollup = sameTypeCount;
  7170       break;
  7173   return true;
  7176 // static
  7177 bool
  7178 nsWindow::NeedsToHandleNCActivateDelayed(HWND aWnd)
  7180   // While popup is open, popup window might be activated by other application.
  7181   // At this time, we need to take back focus to the previous window but it
  7182   // causes flickering its nonclient area because WM_NCACTIVATE comes before
  7183   // WM_ACTIVATE and we cannot know which window will take focus at receiving
  7184   // WM_NCACTIVATE. Therefore, we need a hack for preventing the flickerling.
  7185   //
  7186   // If non-popup window receives WM_NCACTIVATE at deactivating, default
  7187   // wndproc shouldn't handle it as deactivating. Instead, at receiving
  7188   // WM_ACTIVIATE after that, WM_NCACTIVATE should be sent again manually.
  7189   // This returns true if the window needs to handle WM_NCACTIVATE later.
  7191   nsWindow* window = WinUtils::GetNSWindowPtr(aWnd);
  7192   return window && !window->IsPopup();
  7195 // static
  7196 bool
  7197 nsWindow::DealWithPopups(HWND aWnd, UINT aMessage,
  7198                          WPARAM aWParam, LPARAM aLParam, LRESULT* aResult)
  7200   NS_ASSERTION(aResult, "Bad outResult");
  7202   // XXX Why do we use the return value of WM_MOUSEACTIVATE for all messages?
  7203   *aResult = MA_NOACTIVATE;
  7205   if (!::IsWindowVisible(aWnd)) {
  7206     return false;
  7209   nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
  7210   NS_ENSURE_TRUE(rollupListener, false);
  7212   nsCOMPtr<nsIWidget> popup = rollupListener->GetRollupWidget();
  7213   if (!popup) {
  7214     return false;
  7217   static bool sSendingNCACTIVATE = false;
  7218   static bool sPendingNCACTIVATE = false;
  7219   uint32_t popupsToRollup = UINT32_MAX;
  7221   nsWindow* popupWindow = static_cast<nsWindow*>(popup.get());
  7222   UINT nativeMessage = WinUtils::GetNativeMessage(aMessage);
  7223   switch (nativeMessage) {
  7224     case WM_LBUTTONDOWN:
  7225     case WM_RBUTTONDOWN:
  7226     case WM_MBUTTONDOWN:
  7227     case WM_NCLBUTTONDOWN:
  7228     case WM_NCRBUTTONDOWN:
  7229     case WM_NCMBUTTONDOWN:
  7230       if (!EventIsInsideWindow(popupWindow) &&
  7231           GetPopupsToRollup(rollupListener, &popupsToRollup)) {
  7232         break;
  7234       return false;
  7236     case WM_MOUSEWHEEL:
  7237     case WM_MOUSEHWHEEL:
  7238       // We need to check if the popup thinks that it should cause closing
  7239       // itself when mouse wheel events are fired outside the rollup widget.
  7240       if (!EventIsInsideWindow(popupWindow)) {
  7241         *aResult = MA_ACTIVATE;
  7242         if (rollupListener->ShouldRollupOnMouseWheelEvent() &&
  7243             GetPopupsToRollup(rollupListener, &popupsToRollup)) {
  7244           break;
  7247       return false;
  7249     case WM_ACTIVATEAPP:
  7250       break;
  7252     case WM_ACTIVATE:
  7253       // NOTE: Don't handle WA_INACTIVE for preventing popup taking focus
  7254       // because we cannot distinguish it's caused by mouse or not.
  7255       if (LOWORD(aWParam) == WA_ACTIVE && aLParam) {
  7256         nsWindow* window = WinUtils::GetNSWindowPtr(aWnd);
  7257         if (window && window->IsPopup()) {
  7258           // Cancel notifying widget listeners of deactivating the previous
  7259           // active window (see WM_KILLFOCUS case in ProcessMessage()).
  7260           sJustGotDeactivate = false;
  7261           // Reactivate the window later.
  7262           ::PostMessageW(aWnd, MOZ_WM_REACTIVATE, aWParam, aLParam);
  7263           return true;
  7265         // Don't rollup the popup when focus moves back to the parent window
  7266         // from a popup because such case is caused by strange mouse drivers.
  7267         nsWindow* prevWindow =
  7268           WinUtils::GetNSWindowPtr(reinterpret_cast<HWND>(aLParam));
  7269         if (prevWindow && prevWindow->IsPopup()) {
  7270           return false;
  7272       } else if (LOWORD(aWParam) == WA_INACTIVE) {
  7273         nsWindow* activeWindow =
  7274           WinUtils::GetNSWindowPtr(reinterpret_cast<HWND>(aLParam));
  7275         if (sPendingNCACTIVATE && NeedsToHandleNCActivateDelayed(aWnd)) {
  7276           // If focus moves to non-popup widget or focusable popup, the window
  7277           // needs to update its nonclient area.
  7278           if (!activeWindow || !activeWindow->IsPopup()) {
  7279             sSendingNCACTIVATE = true;
  7280             ::SendMessageW(aWnd, WM_NCACTIVATE, false, 0);
  7281             sSendingNCACTIVATE = false;
  7283           sPendingNCACTIVATE = false;
  7285         // If focus moves from/to popup, we don't need to rollup the popup
  7286         // because such case is caused by strange mouse drivers.
  7287         if (activeWindow) {
  7288           if (activeWindow->IsPopup()) {
  7289             return false;
  7291           nsWindow* deactiveWindow = WinUtils::GetNSWindowPtr(aWnd);
  7292           if (deactiveWindow && deactiveWindow->IsPopup()) {
  7293             return false;
  7296       } else if (LOWORD(aWParam) == WA_CLICKACTIVE) {
  7297         // If the WM_ACTIVATE message is caused by a click in a popup,
  7298         // we should not rollup any popups.
  7299         if (EventIsInsideWindow(popupWindow) ||
  7300             !GetPopupsToRollup(rollupListener, &popupsToRollup)) {
  7301           return false;
  7304       break;
  7306     case MOZ_WM_REACTIVATE:
  7307       // The previous active window should take back focus.
  7308       if (::IsWindow(reinterpret_cast<HWND>(aLParam))) {
  7309         ::SetForegroundWindow(reinterpret_cast<HWND>(aLParam));
  7311       return true;
  7313     case WM_NCACTIVATE:
  7314       if (!aWParam && !sSendingNCACTIVATE &&
  7315           NeedsToHandleNCActivateDelayed(aWnd)) {
  7316         // Don't just consume WM_NCACTIVATE. It doesn't handle only the
  7317         // nonclient area state change.
  7318         ::DefWindowProcW(aWnd, aMessage, TRUE, aLParam);
  7319         // Accept the deactivating because it's necessary to receive following
  7320         // WM_ACTIVATE.
  7321         *aResult = TRUE;
  7322         sPendingNCACTIVATE = true;
  7323         return true;
  7325       return false;
  7327     case WM_MOUSEACTIVATE:
  7328       if (!EventIsInsideWindow(popupWindow) &&
  7329           GetPopupsToRollup(rollupListener, &popupsToRollup)) {
  7330         // WM_MOUSEACTIVATE may be caused by moving the mouse (e.g., X-mouse
  7331         // of TweakUI is enabled. Then, check if the popup should be rolled up
  7332         // with rollup listener. If not, just consume the message.
  7333         if (HIWORD(aLParam) == WM_MOUSEMOVE &&
  7334             !rollupListener->ShouldRollupOnMouseActivate()) {
  7335           return true;
  7337         // Otherwise, it should be handled by wndproc.
  7338         return false;
  7341       // Prevent the click inside the popup from causing a change in window
  7342       // activation. Since the popup is shown non-activated, we need to eat any
  7343       // requests to activate the window while it is displayed. Windows will
  7344       // automatically activate the popup on the mousedown otherwise.
  7345       return true;
  7347     case WM_KILLFOCUS:
  7348       // If focus moves to other window created in different process/thread,
  7349       // e.g., a plugin window, popups should be rolled up.
  7350       if (IsDifferentThreadWindow(reinterpret_cast<HWND>(aWParam))) {
  7351         break;
  7353       return false;
  7355     case WM_MOVING:
  7356     case WM_SIZING:
  7357     case WM_MENUSELECT:
  7358       break;
  7360     default:
  7361       return false;
  7364   // Only need to deal with the last rollup for left mouse down events.
  7365   NS_ASSERTION(!mLastRollup, "mLastRollup is null");
  7367   bool consumeRollupEvent;
  7368   if (nativeMessage == WM_LBUTTONDOWN) {
  7369     POINT pt;
  7370     pt.x = GET_X_LPARAM(aLParam);
  7371     pt.y = GET_Y_LPARAM(aLParam);
  7372     ::ClientToScreen(aWnd, &pt);
  7373     nsIntPoint pos(pt.x, pt.y);
  7375     consumeRollupEvent =
  7376       rollupListener->Rollup(popupsToRollup, &pos, &mLastRollup);
  7377     NS_IF_ADDREF(mLastRollup);
  7378   } else {
  7379     consumeRollupEvent =
  7380       rollupListener->Rollup(popupsToRollup, nullptr, nullptr);
  7383   // Tell hook to stop processing messages
  7384   sProcessHook = false;
  7385   sRollupMsgId = 0;
  7386   sRollupMsgWnd = nullptr;
  7388   // If we are NOT supposed to be consuming events, let it go through
  7389   if (consumeRollupEvent && nativeMessage != WM_RBUTTONDOWN) {
  7390     *aResult = MA_ACTIVATE;
  7391     return true;
  7394   return false;
  7397 /**************************************************************
  7398  **************************************************************
  7399  **
  7400  ** BLOCK: Misc. utility methods and functions.
  7401  **
  7402  ** General use.
  7403  **
  7404  **************************************************************
  7405  **************************************************************/
  7407 // Note that the result of GetTopLevelWindow method can be different from the
  7408 // result of WinUtils::GetTopLevelHWND().  The result can be non-floating
  7409 // window.  Because our top level window may be contained in another window
  7410 // which is not managed by us.
  7411 nsWindow* nsWindow::GetTopLevelWindow(bool aStopOnDialogOrPopup)
  7413   nsWindow* curWindow = this;
  7415   while (true) {
  7416     if (aStopOnDialogOrPopup) {
  7417       switch (curWindow->mWindowType) {
  7418         case eWindowType_dialog:
  7419         case eWindowType_popup:
  7420           return curWindow;
  7421         default:
  7422           break;
  7426     // Retrieve the top level parent or owner window
  7427     nsWindow* parentWindow = curWindow->GetParentWindow(true);
  7429     if (!parentWindow)
  7430       return curWindow;
  7432     curWindow = parentWindow;
  7436 static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam)
  7438   DWORD pid;
  7439   ::GetWindowThreadProcessId(hwnd, &pid);
  7440   if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd))
  7442     gWindowsVisible = true;
  7443     return FALSE;
  7445   return TRUE;
  7448 bool nsWindow::CanTakeFocus()
  7450   gWindowsVisible = false;
  7451   EnumWindows(gEnumWindowsProc, 0);
  7452   if (!gWindowsVisible) {
  7453     return true;
  7454   } else {
  7455     HWND fgWnd = ::GetForegroundWindow();
  7456     if (!fgWnd) {
  7457       return true;
  7459     DWORD pid;
  7460     GetWindowThreadProcessId(fgWnd, &pid);
  7461     if (pid == GetCurrentProcessId()) {
  7462       return true;
  7465   return false;
  7468 void nsWindow::GetMainWindowClass(nsAString& aClass)
  7470   NS_PRECONDITION(aClass.IsEmpty(), "aClass should be empty string");
  7471   nsresult rv = Preferences::GetString("ui.window_class_override", &aClass);
  7472   if (NS_FAILED(rv) || aClass.IsEmpty()) {
  7473     aClass.AssignASCII(sDefaultMainWindowClass);
  7477 LPARAM nsWindow::lParamToScreen(LPARAM lParam)
  7479   POINT pt;
  7480   pt.x = GET_X_LPARAM(lParam);
  7481   pt.y = GET_Y_LPARAM(lParam);
  7482   ::ClientToScreen(mWnd, &pt);
  7483   return MAKELPARAM(pt.x, pt.y);
  7486 LPARAM nsWindow::lParamToClient(LPARAM lParam)
  7488   POINT pt;
  7489   pt.x = GET_X_LPARAM(lParam);
  7490   pt.y = GET_Y_LPARAM(lParam);
  7491   ::ScreenToClient(mWnd, &pt);
  7492   return MAKELPARAM(pt.x, pt.y);
  7495 void nsWindow::PickerOpen()
  7497   mPickerDisplayCount++;
  7500 void nsWindow::PickerClosed()
  7502   NS_ASSERTION(mPickerDisplayCount > 0, "mPickerDisplayCount out of sync!");
  7503   if (!mPickerDisplayCount)
  7504     return;
  7505   mPickerDisplayCount--;
  7506   if (!mPickerDisplayCount && mDestroyCalled) {
  7507     Destroy();
  7511 /**************************************************************
  7512  **************************************************************
  7513  **
  7514  ** BLOCK: ChildWindow impl.
  7515  **
  7516  ** Child window overrides.
  7517  **
  7518  **************************************************************
  7519  **************************************************************/
  7521 // return the style for a child nsWindow
  7522 DWORD ChildWindow::WindowStyle()
  7524   DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle();
  7525   if (!(style & WS_POPUP))
  7526     style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
  7527   VERIFY_WINDOW_STYLE(style);
  7528   return style;

mercurial