1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/nsWindow.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,7529 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sts=2 sw=2 et cin: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * nsWindow - Native window management and event handling. 1.12 + * 1.13 + * nsWindow is organized into a set of major blocks and 1.14 + * block subsections. The layout is as follows: 1.15 + * 1.16 + * Includes 1.17 + * Variables 1.18 + * nsIWidget impl. 1.19 + * nsIWidget methods and utilities 1.20 + * nsSwitchToUIThread impl. 1.21 + * nsSwitchToUIThread methods and utilities 1.22 + * Moz events 1.23 + * Event initialization 1.24 + * Event dispatching 1.25 + * Native events 1.26 + * Wndproc(s) 1.27 + * Event processing 1.28 + * OnEvent event handlers 1.29 + * IME management and accessibility 1.30 + * Transparency 1.31 + * Popup hook handling 1.32 + * Misc. utilities 1.33 + * Child window impl. 1.34 + * 1.35 + * Search for "BLOCK:" to find major blocks. 1.36 + * Search for "SECTION:" to find specific sections. 1.37 + * 1.38 + * Blocks should be split out into separate files if they 1.39 + * become unmanageable. 1.40 + * 1.41 + * Related source: 1.42 + * 1.43 + * nsWindowDefs.h - Definitions, macros, structs, enums 1.44 + * and general setup. 1.45 + * nsWindowDbg.h/.cpp - Debug related code and directives. 1.46 + * nsWindowGfx.h/.cpp - Graphics and painting. 1.47 + * 1.48 + */ 1.49 + 1.50 +/************************************************************** 1.51 + ************************************************************** 1.52 + ** 1.53 + ** BLOCK: Includes 1.54 + ** 1.55 + ** Include headers. 1.56 + ** 1.57 + ************************************************************** 1.58 + **************************************************************/ 1.59 + 1.60 +#include "mozilla/MathAlgorithms.h" 1.61 +#include "mozilla/MiscEvents.h" 1.62 +#include "mozilla/MouseEvents.h" 1.63 +#include "mozilla/TouchEvents.h" 1.64 + 1.65 +#include "mozilla/ipc/MessageChannel.h" 1.66 +#include <algorithm> 1.67 + 1.68 +#include "nsWindow.h" 1.69 + 1.70 +#include <shellapi.h> 1.71 +#include <windows.h> 1.72 +#include <process.h> 1.73 +#include <commctrl.h> 1.74 +#include <unknwn.h> 1.75 +#include <psapi.h> 1.76 + 1.77 +#include "prlog.h" 1.78 +#include "prtime.h" 1.79 +#include "prprf.h" 1.80 +#include "prmem.h" 1.81 +#include "prenv.h" 1.82 + 1.83 +#include "mozilla/WidgetTraceEvent.h" 1.84 +#include "nsIAppShell.h" 1.85 +#include "nsISupportsPrimitives.h" 1.86 +#include "nsIDOMMouseEvent.h" 1.87 +#include "nsITheme.h" 1.88 +#include "nsIObserverService.h" 1.89 +#include "nsIScreenManager.h" 1.90 +#include "imgIContainer.h" 1.91 +#include "nsIFile.h" 1.92 +#include "nsIRollupListener.h" 1.93 +#include "nsIServiceManager.h" 1.94 +#include "nsIClipboard.h" 1.95 +#include "nsIMM32Handler.h" 1.96 +#include "WinMouseScrollHandler.h" 1.97 +#include "nsFontMetrics.h" 1.98 +#include "nsIFontEnumerator.h" 1.99 +#include "nsFont.h" 1.100 +#include "nsRect.h" 1.101 +#include "nsThreadUtils.h" 1.102 +#include "nsNativeCharsetUtils.h" 1.103 +#include "nsGkAtoms.h" 1.104 +#include "nsCRT.h" 1.105 +#include "nsAppDirectoryServiceDefs.h" 1.106 +#include "nsXPIDLString.h" 1.107 +#include "nsWidgetsCID.h" 1.108 +#include "nsTHashtable.h" 1.109 +#include "nsHashKeys.h" 1.110 +#include "nsString.h" 1.111 +#include "mozilla/Services.h" 1.112 +#include "nsNativeThemeWin.h" 1.113 +#include "nsWindowsDllInterceptor.h" 1.114 +#include "nsLayoutUtils.h" 1.115 +#include "nsView.h" 1.116 +#include "nsIWindowMediator.h" 1.117 +#include "nsIServiceManager.h" 1.118 +#include "nsWindowGfx.h" 1.119 +#include "gfxWindowsPlatform.h" 1.120 +#include "Layers.h" 1.121 +#include "nsPrintfCString.h" 1.122 +#include "mozilla/Preferences.h" 1.123 +#include "nsISound.h" 1.124 +#include "WinTaskbar.h" 1.125 +#include "WinUtils.h" 1.126 +#include "WidgetUtils.h" 1.127 +#include "nsIWidgetListener.h" 1.128 +#include "mozilla/dom/Touch.h" 1.129 +#include "mozilla/gfx/2D.h" 1.130 +#include "nsToolkitCompsCID.h" 1.131 +#include "nsIAppStartup.h" 1.132 +#include "mozilla/WindowsVersion.h" 1.133 +#include "nsThemeConstants.h" 1.134 + 1.135 +#ifdef MOZ_ENABLE_D3D9_LAYER 1.136 +#include "LayerManagerD3D9.h" 1.137 +#endif 1.138 + 1.139 +#ifdef MOZ_ENABLE_D3D10_LAYER 1.140 +#include "LayerManagerD3D10.h" 1.141 +#endif 1.142 + 1.143 +#include "nsIGfxInfo.h" 1.144 +#include "nsUXThemeConstants.h" 1.145 +#include "KeyboardLayout.h" 1.146 +#include "nsNativeDragTarget.h" 1.147 +#include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN 1.148 +#include <zmouse.h> 1.149 +#include <richedit.h> 1.150 + 1.151 +#if defined(ACCESSIBILITY) 1.152 + 1.153 +#ifdef DEBUG 1.154 +#include "mozilla/a11y/Logging.h" 1.155 +#endif 1.156 + 1.157 +#include "oleidl.h" 1.158 +#include <winuser.h> 1.159 +#include "nsAccessibilityService.h" 1.160 +#include "mozilla/a11y/DocAccessible.h" 1.161 +#include "mozilla/a11y/Platform.h" 1.162 +#if !defined(WINABLEAPI) 1.163 +#include <winable.h> 1.164 +#endif // !defined(WINABLEAPI) 1.165 +#endif // defined(ACCESSIBILITY) 1.166 + 1.167 +#include "nsIWinTaskbar.h" 1.168 +#define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1" 1.169 + 1.170 +#include "nsWindowDefs.h" 1.171 + 1.172 +#include "nsCrashOnException.h" 1.173 +#include "nsIXULRuntime.h" 1.174 + 1.175 +#include "nsIContent.h" 1.176 + 1.177 +#include "mozilla/HangMonitor.h" 1.178 +#include "WinIMEHandler.h" 1.179 + 1.180 +#include "npapi.h" 1.181 + 1.182 +#if !defined(SM_CONVERTIBLESLATEMODE) 1.183 +#define SM_CONVERTIBLESLATEMODE 0x2003 1.184 +#endif 1.185 + 1.186 +using namespace mozilla; 1.187 +using namespace mozilla::dom; 1.188 +using namespace mozilla::layers; 1.189 +using namespace mozilla::widget; 1.190 + 1.191 +/************************************************************** 1.192 + ************************************************************** 1.193 + ** 1.194 + ** BLOCK: Variables 1.195 + ** 1.196 + ** nsWindow Class static initializations and global variables. 1.197 + ** 1.198 + ************************************************************** 1.199 + **************************************************************/ 1.200 + 1.201 +/************************************************************** 1.202 + * 1.203 + * SECTION: nsWindow statics 1.204 + * 1.205 + **************************************************************/ 1.206 + 1.207 +bool nsWindow::sDropShadowEnabled = true; 1.208 +uint32_t nsWindow::sInstanceCount = 0; 1.209 +bool nsWindow::sSwitchKeyboardLayout = false; 1.210 +BOOL nsWindow::sIsOleInitialized = FALSE; 1.211 +HCURSOR nsWindow::sHCursor = nullptr; 1.212 +imgIContainer* nsWindow::sCursorImgContainer = nullptr; 1.213 +nsWindow* nsWindow::sCurrentWindow = nullptr; 1.214 +bool nsWindow::sJustGotDeactivate = false; 1.215 +bool nsWindow::sJustGotActivate = false; 1.216 +bool nsWindow::sIsInMouseCapture = false; 1.217 + 1.218 +// imported in nsWidgetFactory.cpp 1.219 +TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN; 1.220 + 1.221 +// Hook Data Memebers for Dropdowns. sProcessHook Tells the 1.222 +// hook methods whether they should be processing the hook 1.223 +// messages. 1.224 +HHOOK nsWindow::sMsgFilterHook = nullptr; 1.225 +HHOOK nsWindow::sCallProcHook = nullptr; 1.226 +HHOOK nsWindow::sCallMouseHook = nullptr; 1.227 +bool nsWindow::sProcessHook = false; 1.228 +UINT nsWindow::sRollupMsgId = 0; 1.229 +HWND nsWindow::sRollupMsgWnd = nullptr; 1.230 +UINT nsWindow::sHookTimerId = 0; 1.231 + 1.232 +// Mouse Clicks - static variable definitions for figuring 1.233 +// out 1 - 3 Clicks. 1.234 +POINT nsWindow::sLastMousePoint = {0}; 1.235 +POINT nsWindow::sLastMouseMovePoint = {0}; 1.236 +LONG nsWindow::sLastMouseDownTime = 0L; 1.237 +LONG nsWindow::sLastClickCount = 0L; 1.238 +BYTE nsWindow::sLastMouseButton = 0; 1.239 + 1.240 +// Trim heap on minimize. (initialized, but still true.) 1.241 +int nsWindow::sTrimOnMinimize = 2; 1.242 + 1.243 +// Default value for general window class (used when the pref is the empty string). 1.244 +const char* nsWindow::sDefaultMainWindowClass = kClassNameGeneral; 1.245 + 1.246 +// If we're using D3D9, this will not be allowed during initial 5 seconds. 1.247 +bool nsWindow::sAllowD3D9 = false; 1.248 + 1.249 +TriStateBool nsWindow::sHasBogusPopupsDropShadowOnMultiMonitor = TRI_UNKNOWN; 1.250 + 1.251 +// Used in OOPP plugin focus processing. 1.252 +const wchar_t* kOOPPPluginFocusEventId = L"OOPP Plugin Focus Widget Event"; 1.253 +uint32_t nsWindow::sOOPPPluginFocusEvent = 1.254 + RegisterWindowMessageW(kOOPPPluginFocusEventId); 1.255 + 1.256 +/************************************************************** 1.257 + * 1.258 + * SECTION: globals variables 1.259 + * 1.260 + **************************************************************/ 1.261 + 1.262 +static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1"; 1.263 + 1.264 +#ifdef PR_LOGGING 1.265 +extern PRLogModuleInfo* gWindowsLog; 1.266 +#endif 1.267 + 1.268 +// Global used in Show window enumerations. 1.269 +static bool gWindowsVisible = false; 1.270 + 1.271 +// True if we have sent a notification that we are suspending/sleeping. 1.272 +static bool gIsSleepMode = false; 1.273 + 1.274 +static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); 1.275 + 1.276 +// General purpose user32.dll hook object 1.277 +static WindowsDllInterceptor sUser32Intercept; 1.278 + 1.279 +// 2 pixel offset for eTransparencyBorderlessGlass which equals the size of 1.280 +// the default window border Windows paints. Glass will be extended inward 1.281 +// this distance to remove the border. 1.282 +static const int32_t kGlassMarginAdjustment = 2; 1.283 + 1.284 +// When the client area is extended out into the default window frame area, 1.285 +// this is the minimum amount of space along the edge of resizable windows 1.286 +// we will always display a resize cursor in, regardless of the underlying 1.287 +// content. 1.288 +static const int32_t kResizableBorderMinSize = 3; 1.289 + 1.290 +// Cached pointer events enabler value, True if pointer events are enabled. 1.291 +static bool gIsPointerEventsEnabled = false; 1.292 + 1.293 +// We should never really try to accelerate windows bigger than this. In some 1.294 +// cases this might lead to no D3D9 acceleration where we could have had it 1.295 +// but D3D9 does not reliably report when it supports bigger windows. 8192 1.296 +// is as safe as we can get, we know at least D3D10 hardware always supports 1.297 +// this, other hardware we expect to report correctly in D3D9. 1.298 +#define MAX_ACCELERATED_DIMENSION 8192 1.299 + 1.300 +// On window open (as well as after), Windows has an unfortunate habit of 1.301 +// sending rather a lot of WM_NCHITTEST messages. Because we have to do point 1.302 +// to DOM target conversions for these, we cache responses for a given 1.303 +// coordinate this many milliseconds: 1.304 +#define HITTEST_CACHE_LIFETIME_MS 50 1.305 + 1.306 + 1.307 +/************************************************************** 1.308 + ************************************************************** 1.309 + ** 1.310 + ** BLOCK: nsIWidget impl. 1.311 + ** 1.312 + ** nsIWidget interface implementation, broken down into 1.313 + ** sections. 1.314 + ** 1.315 + ************************************************************** 1.316 + **************************************************************/ 1.317 + 1.318 +/************************************************************** 1.319 + * 1.320 + * SECTION: nsWindow construction and destruction 1.321 + * 1.322 + **************************************************************/ 1.323 + 1.324 +nsWindow::nsWindow() : nsWindowBase() 1.325 +{ 1.326 + mIconSmall = nullptr; 1.327 + mIconBig = nullptr; 1.328 + mWnd = nullptr; 1.329 + mPaintDC = nullptr; 1.330 + mCompositeDC = nullptr; 1.331 + mPrevWndProc = nullptr; 1.332 + mNativeDragTarget = nullptr; 1.333 + mInDtor = false; 1.334 + mIsVisible = false; 1.335 + mIsTopWidgetWindow = false; 1.336 + mUnicodeWidget = true; 1.337 + mDisplayPanFeedback = false; 1.338 + mTouchWindow = false; 1.339 + mCustomNonClient = false; 1.340 + mHideChrome = false; 1.341 + mFullscreenMode = false; 1.342 + mMousePresent = false; 1.343 + mDestroyCalled = false; 1.344 + mHasTaskbarIconBeenCreated = false; 1.345 + mMouseTransparent = false; 1.346 + mPickerDisplayCount = 0; 1.347 + mWindowType = eWindowType_child; 1.348 + mBorderStyle = eBorderStyle_default; 1.349 + mOldSizeMode = nsSizeMode_Normal; 1.350 + mLastSizeMode = nsSizeMode_Normal; 1.351 + mLastSize.width = 0; 1.352 + mLastSize.height = 0; 1.353 + mOldStyle = 0; 1.354 + mOldExStyle = 0; 1.355 + mPainting = 0; 1.356 + mLastKeyboardLayout = 0; 1.357 + mBlurSuppressLevel = 0; 1.358 + mLastPaintEndTime = TimeStamp::Now(); 1.359 + mCachedHitTestPoint.x = 0; 1.360 + mCachedHitTestPoint.y = 0; 1.361 + mCachedHitTestTime = TimeStamp::Now(); 1.362 + mCachedHitTestResult = 0; 1.363 +#ifdef MOZ_XUL 1.364 + mTransparentSurface = nullptr; 1.365 + mMemoryDC = nullptr; 1.366 + mTransparencyMode = eTransparencyOpaque; 1.367 + memset(&mGlassMargins, 0, sizeof mGlassMargins); 1.368 +#endif 1.369 + DWORD background = ::GetSysColor(COLOR_BTNFACE); 1.370 + mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(background)); 1.371 + 1.372 + mTaskbarPreview = nullptr; 1.373 + 1.374 + // Global initialization 1.375 + if (!sInstanceCount) { 1.376 + // Global app registration id for Win7 and up. See 1.377 + // WinTaskbar.cpp for details. 1.378 + mozilla::widget::WinTaskbar::RegisterAppUserModelID(); 1.379 + KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0)); 1.380 + IMEHandler::Initialize(); 1.381 + if (SUCCEEDED(::OleInitialize(nullptr))) { 1.382 + sIsOleInitialized = TRUE; 1.383 + } 1.384 + NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n"); 1.385 + MouseScrollHandler::Initialize(); 1.386 + // Init titlebar button info for custom frames. 1.387 + nsUXThemeData::InitTitlebarInfo(); 1.388 + // Init theme data 1.389 + nsUXThemeData::UpdateNativeThemeInfo(); 1.390 + RedirectedKeyDownMessageManager::Forget(); 1.391 + 1.392 + Preferences::AddBoolVarCache(&gIsPointerEventsEnabled, 1.393 + "dom.w3c_pointer_events.enabled", 1.394 + gIsPointerEventsEnabled); 1.395 + } // !sInstanceCount 1.396 + 1.397 + mIdleService = nullptr; 1.398 + 1.399 + sInstanceCount++; 1.400 +} 1.401 + 1.402 +nsWindow::~nsWindow() 1.403 +{ 1.404 + mInDtor = true; 1.405 + 1.406 + // If the widget was released without calling Destroy() then the native window still 1.407 + // exists, and we need to destroy it. This will also result in a call to OnDestroy. 1.408 + // 1.409 + // XXX How could this happen??? 1.410 + if (nullptr != mWnd) 1.411 + Destroy(); 1.412 + 1.413 + // Free app icon resources. This must happen after `OnDestroy` (see bug 708033). 1.414 + if (mIconSmall) 1.415 + ::DestroyIcon(mIconSmall); 1.416 + 1.417 + if (mIconBig) 1.418 + ::DestroyIcon(mIconBig); 1.419 + 1.420 + sInstanceCount--; 1.421 + 1.422 + // Global shutdown 1.423 + if (sInstanceCount == 0) { 1.424 + IMEHandler::Terminate(); 1.425 + NS_IF_RELEASE(sCursorImgContainer); 1.426 + if (sIsOleInitialized) { 1.427 + ::OleFlushClipboard(); 1.428 + ::OleUninitialize(); 1.429 + sIsOleInitialized = FALSE; 1.430 + } 1.431 + } 1.432 + 1.433 + NS_IF_RELEASE(mNativeDragTarget); 1.434 +} 1.435 + 1.436 +NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget) 1.437 + 1.438 +/************************************************************** 1.439 + * 1.440 + * SECTION: nsIWidget::Create, nsIWidget::Destroy 1.441 + * 1.442 + * Creating and destroying windows for this widget. 1.443 + * 1.444 + **************************************************************/ 1.445 + 1.446 +// Allow Derived classes to modify the height that is passed 1.447 +// when the window is created or resized. 1.448 +int32_t nsWindow::GetHeight(int32_t aProposedHeight) 1.449 +{ 1.450 + return aProposedHeight; 1.451 +} 1.452 + 1.453 +// Create the proper widget 1.454 +nsresult 1.455 +nsWindow::Create(nsIWidget *aParent, 1.456 + nsNativeWidget aNativeParent, 1.457 + const nsIntRect &aRect, 1.458 + nsDeviceContext *aContext, 1.459 + nsWidgetInitData *aInitData) 1.460 +{ 1.461 + nsWidgetInitData defaultInitData; 1.462 + if (!aInitData) 1.463 + aInitData = &defaultInitData; 1.464 + 1.465 + mUnicodeWidget = aInitData->mUnicode; 1.466 + 1.467 + nsIWidget *baseParent = aInitData->mWindowType == eWindowType_dialog || 1.468 + aInitData->mWindowType == eWindowType_toplevel || 1.469 + aInitData->mWindowType == eWindowType_invisible ? 1.470 + nullptr : aParent; 1.471 + 1.472 + mIsTopWidgetWindow = (nullptr == baseParent); 1.473 + mBounds = aRect; 1.474 + 1.475 + // Ensure that the toolkit is created. 1.476 + nsToolkit::GetToolkit(); 1.477 + 1.478 + BaseCreate(baseParent, aRect, aContext, aInitData); 1.479 + 1.480 + HWND parent; 1.481 + if (aParent) { // has a nsIWidget parent 1.482 + parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : nullptr; 1.483 + mParent = aParent; 1.484 + } else { // has a nsNative parent 1.485 + parent = (HWND)aNativeParent; 1.486 + mParent = aNativeParent ? 1.487 + WinUtils::GetNSWindowPtr((HWND)aNativeParent) : nullptr; 1.488 + } 1.489 + 1.490 + mIsRTL = aInitData->mRTL; 1.491 + 1.492 + DWORD style = WindowStyle(); 1.493 + DWORD extendedStyle = WindowExStyle(); 1.494 + 1.495 + if (mWindowType == eWindowType_popup) { 1.496 + if (!aParent) { 1.497 + parent = nullptr; 1.498 + } 1.499 + 1.500 + if (IsVistaOrLater() && !IsWin8OrLater() && 1.501 + HasBogusPopupsDropShadowOnMultiMonitor()) { 1.502 + extendedStyle |= WS_EX_COMPOSITED; 1.503 + } 1.504 + 1.505 + if (aInitData->mMouseTransparent) { 1.506 + // This flag makes the window transparent to mouse events 1.507 + mMouseTransparent = true; 1.508 + extendedStyle |= WS_EX_TRANSPARENT; 1.509 + } 1.510 + } else if (mWindowType == eWindowType_invisible) { 1.511 + // Make sure CreateWindowEx succeeds at creating a toplevel window 1.512 + style &= ~0x40000000; // WS_CHILDWINDOW 1.513 + } else { 1.514 + // See if the caller wants to explictly set clip children and clip siblings 1.515 + if (aInitData->clipChildren) { 1.516 + style |= WS_CLIPCHILDREN; 1.517 + } else { 1.518 + style &= ~WS_CLIPCHILDREN; 1.519 + } 1.520 + if (aInitData->clipSiblings) { 1.521 + style |= WS_CLIPSIBLINGS; 1.522 + } 1.523 + } 1.524 + 1.525 + nsAutoString className; 1.526 + if (aInitData->mDropShadow) { 1.527 + GetWindowPopupClass(className); 1.528 + } else { 1.529 + GetWindowClass(className); 1.530 + } 1.531 + // Plugins are created in the disabled state so that they can't 1.532 + // steal focus away from our main window. This is especially 1.533 + // important if the plugin has loaded in a background tab. 1.534 + if(aInitData->mWindowType == eWindowType_plugin) { 1.535 + style |= WS_DISABLED; 1.536 + } 1.537 + mWnd = ::CreateWindowExW(extendedStyle, 1.538 + className.get(), 1.539 + L"", 1.540 + style, 1.541 + aRect.x, 1.542 + aRect.y, 1.543 + aRect.width, 1.544 + GetHeight(aRect.height), 1.545 + parent, 1.546 + nullptr, 1.547 + nsToolkit::mDllInstance, 1.548 + nullptr); 1.549 + 1.550 + if (!mWnd) { 1.551 + NS_WARNING("nsWindow CreateWindowEx failed."); 1.552 + return NS_ERROR_FAILURE; 1.553 + } 1.554 + 1.555 + if (mIsRTL && WinUtils::dwmSetWindowAttributePtr) { 1.556 + DWORD dwAttribute = TRUE; 1.557 + WinUtils::dwmSetWindowAttributePtr(mWnd, DWMWA_NONCLIENT_RTL_LAYOUT, &dwAttribute, sizeof dwAttribute); 1.558 + } 1.559 + 1.560 + if (mWindowType != eWindowType_plugin && 1.561 + mWindowType != eWindowType_invisible && 1.562 + MouseScrollHandler::Device::IsFakeScrollableWindowNeeded()) { 1.563 + // Ugly Thinkpad Driver Hack (Bugs 507222 and 594977) 1.564 + // 1.565 + // We create two zero-sized windows as descendants of the top-level window, 1.566 + // like so: 1.567 + // 1.568 + // Top-level window (MozillaWindowClass) 1.569 + // FAKETRACKPOINTSCROLLCONTAINER (MozillaWindowClass) 1.570 + // FAKETRACKPOINTSCROLLABLE (MozillaWindowClass) 1.571 + // 1.572 + // We need to have the middle window, otherwise the Trackpoint driver 1.573 + // will fail to deliver scroll messages. WM_MOUSEWHEEL messages are 1.574 + // sent to the FAKETRACKPOINTSCROLLABLE, which then propagate up the 1.575 + // window hierarchy until they are handled by nsWindow::WindowProc. 1.576 + // WM_HSCROLL messages are also sent to the FAKETRACKPOINTSCROLLABLE, 1.577 + // but these do not propagate automatically, so we have the window 1.578 + // procedure pretend that they were dispatched to the top-level window 1.579 + // instead. 1.580 + // 1.581 + // The FAKETRACKPOINTSCROLLABLE needs to have the specific window styles it 1.582 + // is given below so that it catches the Trackpoint driver's heuristics. 1.583 + HWND scrollContainerWnd = ::CreateWindowW 1.584 + (className.get(), L"FAKETRACKPOINTSCROLLCONTAINER", 1.585 + WS_CHILD | WS_VISIBLE, 1.586 + 0, 0, 0, 0, mWnd, nullptr, nsToolkit::mDllInstance, nullptr); 1.587 + HWND scrollableWnd = ::CreateWindowW 1.588 + (className.get(), L"FAKETRACKPOINTSCROLLABLE", 1.589 + WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | 0x30, 1.590 + 0, 0, 0, 0, scrollContainerWnd, nullptr, nsToolkit::mDllInstance, 1.591 + nullptr); 1.592 + 1.593 + // Give the FAKETRACKPOINTSCROLLABLE window a specific ID so that 1.594 + // WindowProcInternal can distinguish it from the top-level window 1.595 + // easily. 1.596 + ::SetWindowLongPtrW(scrollableWnd, GWLP_ID, eFakeTrackPointScrollableID); 1.597 + 1.598 + // Make FAKETRACKPOINTSCROLLABLE use nsWindow::WindowProc, and store the 1.599 + // old window procedure in its "user data". 1.600 + WNDPROC oldWndProc; 1.601 + if (mUnicodeWidget) 1.602 + oldWndProc = (WNDPROC)::SetWindowLongPtrW(scrollableWnd, GWLP_WNDPROC, 1.603 + (LONG_PTR)nsWindow::WindowProc); 1.604 + else 1.605 + oldWndProc = (WNDPROC)::SetWindowLongPtrA(scrollableWnd, GWLP_WNDPROC, 1.606 + (LONG_PTR)nsWindow::WindowProc); 1.607 + ::SetWindowLongPtrW(scrollableWnd, GWLP_USERDATA, (LONG_PTR)oldWndProc); 1.608 + } 1.609 + 1.610 + SubclassWindow(TRUE); 1.611 + 1.612 + IMEHandler::InitInputContext(this, mInputContext); 1.613 + 1.614 + // If the internal variable set by the config.trim_on_minimize pref has not 1.615 + // been initialized, and if this is the hidden window (conveniently created 1.616 + // before any visible windows, and after the profile has been initialized), 1.617 + // do some initialization work. 1.618 + if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) { 1.619 + // Our internal trim prevention logic is effective on 2K/XP at maintaining 1.620 + // the working set when windows are minimized, but on Vista and up it has 1.621 + // little to no effect. Since this feature has been the source of numerous 1.622 + // bugs over the years, disable it (sTrimOnMinimize=1) on Vista and up. 1.623 + sTrimOnMinimize = 1.624 + Preferences::GetBool("config.trim_on_minimize", 1.625 + IsVistaOrLater() ? 1 : 0); 1.626 + sSwitchKeyboardLayout = 1.627 + Preferences::GetBool("intl.keyboard.per_window_layout", false); 1.628 + } 1.629 + 1.630 + // Query for command button metric data for rendering the titlebar. We 1.631 + // only do this once on the first window. 1.632 + if (mWindowType == eWindowType_toplevel && 1.633 + (!nsUXThemeData::sTitlebarInfoPopulatedThemed || 1.634 + !nsUXThemeData::sTitlebarInfoPopulatedAero)) { 1.635 + nsUXThemeData::UpdateTitlebarInfo(mWnd); 1.636 + } 1.637 + return NS_OK; 1.638 +} 1.639 + 1.640 +// Close this nsWindow 1.641 +NS_METHOD nsWindow::Destroy() 1.642 +{ 1.643 + // WM_DESTROY has already fired, avoid calling it twice 1.644 + if (mOnDestroyCalled) 1.645 + return NS_OK; 1.646 + 1.647 + // Don't destroy windows that have file pickers open, we'll tear these down 1.648 + // later once the picker is closed. 1.649 + mDestroyCalled = true; 1.650 + if (mPickerDisplayCount) 1.651 + return NS_OK; 1.652 + 1.653 + // During the destruction of all of our children, make sure we don't get deleted. 1.654 + nsCOMPtr<nsIWidget> kungFuDeathGrip(this); 1.655 + 1.656 + /** 1.657 + * On windows the LayerManagerOGL destructor wants the widget to be around for 1.658 + * cleanup. It also would like to have the HWND intact, so we nullptr it here. 1.659 + */ 1.660 + if (mLayerManager) { 1.661 + mLayerManager->Destroy(); 1.662 + } 1.663 + mLayerManager = nullptr; 1.664 + 1.665 + /* We should clear our cached resources now and not wait for the GC to 1.666 + * delete the nsWindow. */ 1.667 + ClearCachedResources(); 1.668 + 1.669 + // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY 1.670 + // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus 1.671 + // from it. The function also destroys the window's menu, flushes the thread message queue, 1.672 + // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if 1.673 + // the window is at the top of the viewer chain). 1.674 + // 1.675 + // If the specified window is a parent or owner window, DestroyWindow automatically destroys 1.676 + // the associated child or owned windows when it destroys the parent or owner window. The 1.677 + // function first destroys child or owned windows, and then it destroys the parent or owner 1.678 + // window. 1.679 + VERIFY(::DestroyWindow(mWnd)); 1.680 + 1.681 + // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy() 1.682 + // didn't get called, call it now. 1.683 + if (false == mOnDestroyCalled) { 1.684 + MSGResult msgResult; 1.685 + mWindowHook.Notify(mWnd, WM_DESTROY, 0, 0, msgResult); 1.686 + OnDestroy(); 1.687 + } 1.688 + 1.689 + return NS_OK; 1.690 +} 1.691 + 1.692 +/************************************************************** 1.693 + * 1.694 + * SECTION: Window class utilities 1.695 + * 1.696 + * Utilities for calculating the proper window class name for 1.697 + * Create window. 1.698 + * 1.699 + **************************************************************/ 1.700 + 1.701 +void nsWindow::RegisterWindowClass(const nsString& aClassName, UINT aExtraStyle, 1.702 + LPWSTR aIconID) 1.703 +{ 1.704 + WNDCLASSW wc; 1.705 + if (::GetClassInfoW(nsToolkit::mDllInstance, aClassName.get(), &wc)) { 1.706 + // already registered 1.707 + return; 1.708 + } 1.709 + 1.710 + wc.style = CS_DBLCLKS | aExtraStyle; 1.711 + wc.lpfnWndProc = ::DefWindowProcW; 1.712 + wc.cbClsExtra = 0; 1.713 + wc.cbWndExtra = 0; 1.714 + wc.hInstance = nsToolkit::mDllInstance; 1.715 + wc.hIcon = aIconID ? ::LoadIconW(::GetModuleHandleW(nullptr), aIconID) : nullptr; 1.716 + wc.hCursor = nullptr; 1.717 + wc.hbrBackground = mBrush; 1.718 + wc.lpszMenuName = nullptr; 1.719 + wc.lpszClassName = aClassName.get(); 1.720 + 1.721 + if (!::RegisterClassW(&wc)) { 1.722 + // For older versions of Win32 (i.e., not XP), the registration may 1.723 + // fail with aExtraStyle, so we have to re-register without it. 1.724 + wc.style = CS_DBLCLKS; 1.725 + ::RegisterClassW(&wc); 1.726 + } 1.727 +} 1.728 + 1.729 +static LPWSTR const gStockApplicationIcon = MAKEINTRESOURCEW(32512); 1.730 + 1.731 +// Return the proper window class for everything except popups. 1.732 +void nsWindow::GetWindowClass(nsString& aWindowClass) 1.733 +{ 1.734 + switch (mWindowType) { 1.735 + case eWindowType_invisible: 1.736 + aWindowClass.AssignLiteral(kClassNameHidden); 1.737 + RegisterWindowClass(aWindowClass, 0, gStockApplicationIcon); 1.738 + break; 1.739 + case eWindowType_dialog: 1.740 + aWindowClass.AssignLiteral(kClassNameDialog); 1.741 + RegisterWindowClass(aWindowClass, 0, 0); 1.742 + break; 1.743 + default: 1.744 + GetMainWindowClass(aWindowClass); 1.745 + RegisterWindowClass(aWindowClass, 0, gStockApplicationIcon); 1.746 + break; 1.747 + } 1.748 +} 1.749 + 1.750 +// Return the proper popup window class 1.751 +void nsWindow::GetWindowPopupClass(nsString& aWindowClass) 1.752 +{ 1.753 + aWindowClass.AssignLiteral(kClassNameDropShadow); 1.754 + RegisterWindowClass(aWindowClass, CS_XP_DROPSHADOW, gStockApplicationIcon); 1.755 +} 1.756 + 1.757 +/************************************************************** 1.758 + * 1.759 + * SECTION: Window styles utilities 1.760 + * 1.761 + * Return the proper windows styles and extended styles. 1.762 + * 1.763 + **************************************************************/ 1.764 + 1.765 +// Return nsWindow styles 1.766 +DWORD nsWindow::WindowStyle() 1.767 +{ 1.768 + DWORD style; 1.769 + 1.770 + switch (mWindowType) { 1.771 + case eWindowType_plugin: 1.772 + case eWindowType_child: 1.773 + style = WS_OVERLAPPED; 1.774 + break; 1.775 + 1.776 + case eWindowType_dialog: 1.777 + style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK | 1.778 + DS_MODALFRAME | WS_CLIPCHILDREN; 1.779 + if (mBorderStyle != eBorderStyle_default) 1.780 + style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; 1.781 + break; 1.782 + 1.783 + case eWindowType_popup: 1.784 + style = WS_POPUP; 1.785 + if (!HasGlass()) { 1.786 + style |= WS_OVERLAPPED; 1.787 + } 1.788 + break; 1.789 + 1.790 + default: 1.791 + NS_ERROR("unknown border style"); 1.792 + // fall through 1.793 + 1.794 + case eWindowType_toplevel: 1.795 + case eWindowType_invisible: 1.796 + style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | 1.797 + WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN; 1.798 + break; 1.799 + } 1.800 + 1.801 + if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) { 1.802 + if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border)) 1.803 + style &= ~WS_BORDER; 1.804 + 1.805 + if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) { 1.806 + style &= ~WS_DLGFRAME; 1.807 + style |= WS_POPUP; 1.808 + style &= ~WS_CHILD; 1.809 + } 1.810 + 1.811 + if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close)) 1.812 + style &= ~0; 1.813 + // XXX The close box can only be removed by changing the window class, 1.814 + // as far as I know --- roc+moz@cs.cmu.edu 1.815 + 1.816 + if (mBorderStyle == eBorderStyle_none || 1.817 + !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close))) 1.818 + style &= ~WS_SYSMENU; 1.819 + // Looks like getting rid of the system menu also does away with the 1.820 + // close box. So, we only get rid of the system menu if you want neither it 1.821 + // nor the close box. How does the Windows "Dialog" window class get just 1.822 + // closebox and no sysmenu? Who knows. 1.823 + 1.824 + if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh)) 1.825 + style &= ~WS_THICKFRAME; 1.826 + 1.827 + if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize)) 1.828 + style &= ~WS_MINIMIZEBOX; 1.829 + 1.830 + if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize)) 1.831 + style &= ~WS_MAXIMIZEBOX; 1.832 + 1.833 + if (IsPopupWithTitleBar()) { 1.834 + style |= WS_CAPTION; 1.835 + if (mBorderStyle & eBorderStyle_close) { 1.836 + style |= WS_SYSMENU; 1.837 + } 1.838 + } 1.839 + } 1.840 + 1.841 + VERIFY_WINDOW_STYLE(style); 1.842 + return style; 1.843 +} 1.844 + 1.845 +// Return nsWindow extended styles 1.846 +DWORD nsWindow::WindowExStyle() 1.847 +{ 1.848 + switch (mWindowType) 1.849 + { 1.850 + case eWindowType_plugin: 1.851 + case eWindowType_child: 1.852 + return 0; 1.853 + 1.854 + case eWindowType_dialog: 1.855 + return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME; 1.856 + 1.857 + case eWindowType_popup: 1.858 + { 1.859 + DWORD extendedStyle = WS_EX_TOOLWINDOW; 1.860 + if (mPopupLevel == ePopupLevelTop) 1.861 + extendedStyle |= WS_EX_TOPMOST; 1.862 + return extendedStyle; 1.863 + } 1.864 + default: 1.865 + NS_ERROR("unknown border style"); 1.866 + // fall through 1.867 + 1.868 + case eWindowType_toplevel: 1.869 + case eWindowType_invisible: 1.870 + return WS_EX_WINDOWEDGE; 1.871 + } 1.872 +} 1.873 + 1.874 +/************************************************************** 1.875 + * 1.876 + * SECTION: Window subclassing utilities 1.877 + * 1.878 + * Set or clear window subclasses on native windows. Used in 1.879 + * Create and Destroy. 1.880 + * 1.881 + **************************************************************/ 1.882 + 1.883 +// Subclass (or remove the subclass from) this component's nsWindow 1.884 +void nsWindow::SubclassWindow(BOOL bState) 1.885 +{ 1.886 + if (bState) { 1.887 + if (!mWnd || !IsWindow(mWnd)) { 1.888 + NS_ERROR("Invalid window handle"); 1.889 + } 1.890 + 1.891 + if (mUnicodeWidget) { 1.892 + mPrevWndProc = 1.893 + reinterpret_cast<WNDPROC>( 1.894 + SetWindowLongPtrW(mWnd, 1.895 + GWLP_WNDPROC, 1.896 + reinterpret_cast<LONG_PTR>(nsWindow::WindowProc))); 1.897 + } else { 1.898 + mPrevWndProc = 1.899 + reinterpret_cast<WNDPROC>( 1.900 + SetWindowLongPtrA(mWnd, 1.901 + GWLP_WNDPROC, 1.902 + reinterpret_cast<LONG_PTR>(nsWindow::WindowProc))); 1.903 + } 1.904 + NS_ASSERTION(mPrevWndProc, "Null standard window procedure"); 1.905 + // connect the this pointer to the nsWindow handle 1.906 + WinUtils::SetNSWindowBasePtr(mWnd, this); 1.907 + } else { 1.908 + if (IsWindow(mWnd)) { 1.909 + if (mUnicodeWidget) { 1.910 + SetWindowLongPtrW(mWnd, 1.911 + GWLP_WNDPROC, 1.912 + reinterpret_cast<LONG_PTR>(mPrevWndProc)); 1.913 + } else { 1.914 + SetWindowLongPtrA(mWnd, 1.915 + GWLP_WNDPROC, 1.916 + reinterpret_cast<LONG_PTR>(mPrevWndProc)); 1.917 + } 1.918 + } 1.919 + WinUtils::SetNSWindowBasePtr(mWnd, nullptr); 1.920 + mPrevWndProc = nullptr; 1.921 + } 1.922 +} 1.923 + 1.924 +/************************************************************** 1.925 + * 1.926 + * SECTION: nsIWidget::SetParent, nsIWidget::GetParent 1.927 + * 1.928 + * Set or clear the parent widgets using window properties, and 1.929 + * handles calculating native parent handles. 1.930 + * 1.931 + **************************************************************/ 1.932 + 1.933 +// Get and set parent widgets 1.934 +NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent) 1.935 +{ 1.936 + mParent = aNewParent; 1.937 + 1.938 + nsCOMPtr<nsIWidget> kungFuDeathGrip(this); 1.939 + nsIWidget* parent = GetParent(); 1.940 + if (parent) { 1.941 + parent->RemoveChild(this); 1.942 + } 1.943 + if (aNewParent) { 1.944 + ReparentNativeWidget(aNewParent); 1.945 + aNewParent->AddChild(this); 1.946 + return NS_OK; 1.947 + } 1.948 + if (mWnd) { 1.949 + // If we have no parent, SetParent should return the desktop. 1.950 + VERIFY(::SetParent(mWnd, nullptr)); 1.951 + } 1.952 + return NS_OK; 1.953 +} 1.954 + 1.955 +NS_IMETHODIMP 1.956 +nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) 1.957 +{ 1.958 + NS_PRECONDITION(aNewParent, ""); 1.959 + 1.960 + mParent = aNewParent; 1.961 + if (mWindowType == eWindowType_popup) { 1.962 + return NS_OK; 1.963 + } 1.964 + HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW); 1.965 + NS_ASSERTION(newParent, "Parent widget has a null native window handle"); 1.966 + if (newParent && mWnd) { 1.967 + ::SetParent(mWnd, newParent); 1.968 + } 1.969 + return NS_OK; 1.970 +} 1.971 + 1.972 +nsIWidget* nsWindow::GetParent(void) 1.973 +{ 1.974 + return GetParentWindow(false); 1.975 +} 1.976 + 1.977 +float nsWindow::GetDPI() 1.978 +{ 1.979 + HDC dc = ::GetDC(mWnd); 1.980 + if (!dc) 1.981 + return 96.0f; 1.982 + 1.983 + double heightInches = ::GetDeviceCaps(dc, VERTSIZE)/MM_PER_INCH_FLOAT; 1.984 + int heightPx = ::GetDeviceCaps(dc, VERTRES); 1.985 + ::ReleaseDC(mWnd, dc); 1.986 + if (heightInches < 0.25) { 1.987 + // Something's broken 1.988 + return 96.0f; 1.989 + } 1.990 + return float(heightPx/heightInches); 1.991 +} 1.992 + 1.993 +double nsWindow::GetDefaultScaleInternal() 1.994 +{ 1.995 + return WinUtils::LogToPhysFactor(); 1.996 +} 1.997 + 1.998 +nsWindow* 1.999 +nsWindow::GetParentWindow(bool aIncludeOwner) 1.1000 +{ 1.1001 + return static_cast<nsWindow*>(GetParentWindowBase(aIncludeOwner)); 1.1002 +} 1.1003 + 1.1004 +nsWindowBase* 1.1005 +nsWindow::GetParentWindowBase(bool aIncludeOwner) 1.1006 +{ 1.1007 + if (mIsTopWidgetWindow) { 1.1008 + // Must use a flag instead of mWindowType to tell if the window is the 1.1009 + // owned by the topmost widget, because a child window can be embedded inside 1.1010 + // a HWND which is not associated with a nsIWidget. 1.1011 + return nullptr; 1.1012 + } 1.1013 + 1.1014 + // If this widget has already been destroyed, pretend we have no parent. 1.1015 + // This corresponds to code in Destroy which removes the destroyed 1.1016 + // widget from its parent's child list. 1.1017 + if (mInDtor || mOnDestroyCalled) 1.1018 + return nullptr; 1.1019 + 1.1020 + 1.1021 + // aIncludeOwner set to true implies walking the parent chain to retrieve the 1.1022 + // root owner. aIncludeOwner set to false implies the search will stop at the 1.1023 + // true parent (default). 1.1024 + nsWindow* widget = nullptr; 1.1025 + if (mWnd) { 1.1026 + HWND parent = nullptr; 1.1027 + if (aIncludeOwner) 1.1028 + parent = ::GetParent(mWnd); 1.1029 + else 1.1030 + parent = ::GetAncestor(mWnd, GA_PARENT); 1.1031 + 1.1032 + if (parent) { 1.1033 + widget = WinUtils::GetNSWindowPtr(parent); 1.1034 + if (widget) { 1.1035 + // If the widget is in the process of being destroyed then 1.1036 + // do NOT return it 1.1037 + if (widget->mInDtor) { 1.1038 + widget = nullptr; 1.1039 + } 1.1040 + } 1.1041 + } 1.1042 + } 1.1043 + 1.1044 + return static_cast<nsWindowBase*>(widget); 1.1045 +} 1.1046 + 1.1047 +BOOL CALLBACK 1.1048 +nsWindow::EnumAllChildWindProc(HWND aWnd, LPARAM aParam) 1.1049 +{ 1.1050 + nsWindow *wnd = WinUtils::GetNSWindowPtr(aWnd); 1.1051 + if (wnd) { 1.1052 + ((nsWindow::WindowEnumCallback*)aParam)(wnd); 1.1053 + } 1.1054 + return TRUE; 1.1055 +} 1.1056 + 1.1057 +BOOL CALLBACK 1.1058 +nsWindow::EnumAllThreadWindowProc(HWND aWnd, LPARAM aParam) 1.1059 +{ 1.1060 + nsWindow *wnd = WinUtils::GetNSWindowPtr(aWnd); 1.1061 + if (wnd) { 1.1062 + ((nsWindow::WindowEnumCallback*)aParam)(wnd); 1.1063 + } 1.1064 + EnumChildWindows(aWnd, EnumAllChildWindProc, aParam); 1.1065 + return TRUE; 1.1066 +} 1.1067 + 1.1068 +void 1.1069 +nsWindow::EnumAllWindows(WindowEnumCallback aCallback) 1.1070 +{ 1.1071 + EnumThreadWindows(GetCurrentThreadId(), 1.1072 + EnumAllThreadWindowProc, 1.1073 + (LPARAM)aCallback); 1.1074 +} 1.1075 + 1.1076 +/************************************************************** 1.1077 + * 1.1078 + * SECTION: nsIWidget::Show 1.1079 + * 1.1080 + * Hide or show this component. 1.1081 + * 1.1082 + **************************************************************/ 1.1083 + 1.1084 +NS_METHOD nsWindow::Show(bool bState) 1.1085 +{ 1.1086 + if (mWindowType == eWindowType_popup) { 1.1087 + // See bug 603793. When we try to draw D3D9/10 windows with a drop shadow 1.1088 + // without the DWM on a secondary monitor, windows fails to composite 1.1089 + // our windows correctly. We therefor switch off the drop shadow for 1.1090 + // pop-up windows when the DWM is disabled and two monitors are 1.1091 + // connected. 1.1092 + if (HasBogusPopupsDropShadowOnMultiMonitor() && 1.1093 + WinUtils::GetMonitorCount() > 1 && 1.1094 + !nsUXThemeData::CheckForCompositor()) 1.1095 + { 1.1096 + if (sDropShadowEnabled) { 1.1097 + ::SetClassLongA(mWnd, GCL_STYLE, 0); 1.1098 + sDropShadowEnabled = false; 1.1099 + } 1.1100 + } else { 1.1101 + if (!sDropShadowEnabled) { 1.1102 + ::SetClassLongA(mWnd, GCL_STYLE, CS_DROPSHADOW); 1.1103 + sDropShadowEnabled = true; 1.1104 + } 1.1105 + } 1.1106 + 1.1107 + // WS_EX_COMPOSITED conflicts with the WS_EX_LAYERED style and causes 1.1108 + // some popup menus to become invisible. 1.1109 + LONG_PTR exStyle = ::GetWindowLongPtrW(mWnd, GWL_EXSTYLE); 1.1110 + if (exStyle & WS_EX_LAYERED) { 1.1111 + ::SetWindowLongPtrW(mWnd, GWL_EXSTYLE, exStyle & ~WS_EX_COMPOSITED); 1.1112 + } 1.1113 + } 1.1114 + 1.1115 + bool syncInvalidate = false; 1.1116 + 1.1117 + bool wasVisible = mIsVisible; 1.1118 + // Set the status now so that anyone asking during ShowWindow or 1.1119 + // SetWindowPos would get the correct answer. 1.1120 + mIsVisible = bState; 1.1121 + 1.1122 + // We may have cached an out of date visible state. This can happen 1.1123 + // when session restore sets the full screen mode. 1.1124 + if (mIsVisible) 1.1125 + mOldStyle |= WS_VISIBLE; 1.1126 + else 1.1127 + mOldStyle &= ~WS_VISIBLE; 1.1128 + 1.1129 + if (!mIsVisible && wasVisible) { 1.1130 + ClearCachedResources(); 1.1131 + } 1.1132 + 1.1133 + if (mWnd) { 1.1134 + if (bState) { 1.1135 + if (!wasVisible && mWindowType == eWindowType_toplevel) { 1.1136 + // speed up the initial paint after show for 1.1137 + // top level windows: 1.1138 + syncInvalidate = true; 1.1139 + switch (mSizeMode) { 1.1140 + case nsSizeMode_Fullscreen: 1.1141 + ::ShowWindow(mWnd, SW_SHOW); 1.1142 + break; 1.1143 + case nsSizeMode_Maximized : 1.1144 + ::ShowWindow(mWnd, SW_SHOWMAXIMIZED); 1.1145 + break; 1.1146 + case nsSizeMode_Minimized : 1.1147 + ::ShowWindow(mWnd, SW_SHOWMINIMIZED); 1.1148 + break; 1.1149 + default: 1.1150 + if (CanTakeFocus()) { 1.1151 + ::ShowWindow(mWnd, SW_SHOWNORMAL); 1.1152 + } else { 1.1153 + // Place the window behind the foreground window 1.1154 + // (as long as it is not topmost) 1.1155 + HWND wndAfter = ::GetForegroundWindow(); 1.1156 + if (!wndAfter) 1.1157 + wndAfter = HWND_BOTTOM; 1.1158 + else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST) 1.1159 + wndAfter = HWND_TOP; 1.1160 + ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | 1.1161 + SWP_NOMOVE | SWP_NOACTIVATE); 1.1162 + GetAttention(2); 1.1163 + } 1.1164 + break; 1.1165 + } 1.1166 + } else { 1.1167 + DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW; 1.1168 + if (wasVisible) 1.1169 + flags |= SWP_NOZORDER; 1.1170 + 1.1171 + if (mWindowType == eWindowType_popup) { 1.1172 + // ensure popups are the topmost of the TOPMOST 1.1173 + // layer. Remember not to set the SWP_NOZORDER 1.1174 + // flag as that might allow the taskbar to overlap 1.1175 + // the popup. 1.1176 + flags |= SWP_NOACTIVATE; 1.1177 + HWND owner = ::GetWindow(mWnd, GW_OWNER); 1.1178 + ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags); 1.1179 + } else { 1.1180 + if (mWindowType == eWindowType_dialog && !CanTakeFocus()) 1.1181 + flags |= SWP_NOACTIVATE; 1.1182 + 1.1183 + ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags); 1.1184 + } 1.1185 + } 1.1186 + 1.1187 + if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) { 1.1188 + // when a toplevel window or dialog is shown, initialize the UI state 1.1189 + ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0); 1.1190 + } 1.1191 + } else { 1.1192 + // Clear contents to avoid ghosting of old content if we display 1.1193 + // this window again. 1.1194 + if (wasVisible && mTransparencyMode == eTransparencyTransparent) { 1.1195 + ClearTranslucentWindow(); 1.1196 + } 1.1197 + if (mWindowType != eWindowType_dialog) { 1.1198 + ::ShowWindow(mWnd, SW_HIDE); 1.1199 + } else { 1.1200 + ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | 1.1201 + SWP_NOZORDER | SWP_NOACTIVATE); 1.1202 + } 1.1203 + } 1.1204 + } 1.1205 + 1.1206 +#ifdef MOZ_XUL 1.1207 + if (!wasVisible && bState) { 1.1208 + Invalidate(); 1.1209 + if (syncInvalidate && !mInDtor && !mOnDestroyCalled) { 1.1210 + ::UpdateWindow(mWnd); 1.1211 + } 1.1212 + } 1.1213 +#endif 1.1214 + 1.1215 + return NS_OK; 1.1216 +} 1.1217 + 1.1218 +/************************************************************** 1.1219 + * 1.1220 + * SECTION: nsIWidget::IsVisible 1.1221 + * 1.1222 + * Returns the visibility state. 1.1223 + * 1.1224 + **************************************************************/ 1.1225 + 1.1226 +// Return true if the whether the component is visible, false otherwise 1.1227 +bool nsWindow::IsVisible() const 1.1228 +{ 1.1229 + return mIsVisible; 1.1230 +} 1.1231 + 1.1232 +/************************************************************** 1.1233 + * 1.1234 + * SECTION: Window clipping utilities 1.1235 + * 1.1236 + * Used in Size and Move operations for setting the proper 1.1237 + * window clipping regions for window transparency. 1.1238 + * 1.1239 + **************************************************************/ 1.1240 + 1.1241 +// XP and Vista visual styles sometimes require window clipping regions to be applied for proper 1.1242 +// transparency. These routines are called on size and move operations. 1.1243 +void nsWindow::ClearThemeRegion() 1.1244 +{ 1.1245 + if (IsVistaOrLater() && !HasGlass() && 1.1246 + (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() && 1.1247 + (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) { 1.1248 + SetWindowRgn(mWnd, nullptr, false); 1.1249 + } 1.1250 +} 1.1251 + 1.1252 +void nsWindow::SetThemeRegion() 1.1253 +{ 1.1254 + // Popup types that have a visual styles region applied (bug 376408). This can be expanded 1.1255 + // for other window types as needed. The regions are applied generically to the base window 1.1256 + // so default constants are used for part and state. At some point we might need part and 1.1257 + // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that 1.1258 + // change shape based on state haven't come up. 1.1259 + if (IsVistaOrLater() && !HasGlass() && 1.1260 + (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() && 1.1261 + (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) { 1.1262 + HRGN hRgn = nullptr; 1.1263 + RECT rect = {0,0,mBounds.width,mBounds.height}; 1.1264 + 1.1265 + HDC dc = ::GetDC(mWnd); 1.1266 + GetThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn); 1.1267 + if (hRgn) { 1.1268 + if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted. 1.1269 + DeleteObject(hRgn); 1.1270 + } 1.1271 + ::ReleaseDC(mWnd, dc); 1.1272 + } 1.1273 +} 1.1274 + 1.1275 +/************************************************************** 1.1276 + * 1.1277 + * SECTION: nsIWidget::RegisterTouchWindow, 1.1278 + * nsIWidget::UnregisterTouchWindow, and helper functions 1.1279 + * 1.1280 + * Used to register the native window to receive touch events 1.1281 + * 1.1282 + **************************************************************/ 1.1283 + 1.1284 +NS_METHOD nsWindow::RegisterTouchWindow() { 1.1285 + if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0) || 1.1286 + gIsPointerEventsEnabled) { 1.1287 + mTouchWindow = true; 1.1288 + mGesture.RegisterTouchWindow(mWnd); 1.1289 + ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0); 1.1290 + } 1.1291 + return NS_OK; 1.1292 +} 1.1293 + 1.1294 +NS_METHOD nsWindow::UnregisterTouchWindow() { 1.1295 + mTouchWindow = false; 1.1296 + mGesture.UnregisterTouchWindow(mWnd); 1.1297 + ::EnumChildWindows(mWnd, nsWindow::UnregisterTouchForDescendants, 0); 1.1298 + return NS_OK; 1.1299 +} 1.1300 + 1.1301 +BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) { 1.1302 + nsWindow* win = WinUtils::GetNSWindowPtr(aWnd); 1.1303 + if (win) 1.1304 + win->mGesture.RegisterTouchWindow(aWnd); 1.1305 + return TRUE; 1.1306 +} 1.1307 + 1.1308 +BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) { 1.1309 + nsWindow* win = WinUtils::GetNSWindowPtr(aWnd); 1.1310 + if (win) 1.1311 + win->mGesture.UnregisterTouchWindow(aWnd); 1.1312 + return TRUE; 1.1313 +} 1.1314 + 1.1315 +/************************************************************** 1.1316 + * 1.1317 + * SECTION: nsIWidget::Move, nsIWidget::Resize, 1.1318 + * nsIWidget::Size, nsIWidget::BeginResizeDrag 1.1319 + * 1.1320 + * Repositioning and sizing a window. 1.1321 + * 1.1322 + **************************************************************/ 1.1323 + 1.1324 +void 1.1325 +nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints) 1.1326 +{ 1.1327 + SizeConstraints c = aConstraints; 1.1328 + if (mWindowType != eWindowType_popup) { 1.1329 + c.mMinSize.width = std::max(int32_t(::GetSystemMetrics(SM_CXMINTRACK)), c.mMinSize.width); 1.1330 + c.mMinSize.height = std::max(int32_t(::GetSystemMetrics(SM_CYMINTRACK)), c.mMinSize.height); 1.1331 + } 1.1332 + 1.1333 + nsBaseWidget::SetSizeConstraints(c); 1.1334 +} 1.1335 + 1.1336 +// Move this component 1.1337 +NS_METHOD nsWindow::Move(double aX, double aY) 1.1338 +{ 1.1339 + if (mWindowType == eWindowType_toplevel || 1.1340 + mWindowType == eWindowType_dialog) { 1.1341 + SetSizeMode(nsSizeMode_Normal); 1.1342 + } 1.1343 + 1.1344 + // for top-level windows only, convert coordinates from global display pixels 1.1345 + // (the "parent" coordinate space) to the window's device pixel space 1.1346 + CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale() 1.1347 + : CSSToLayoutDeviceScale(1.0); 1.1348 + int32_t x = NSToIntRound(aX * scale.scale); 1.1349 + int32_t y = NSToIntRound(aY * scale.scale); 1.1350 + 1.1351 + // Check to see if window needs to be moved first 1.1352 + // to avoid a costly call to SetWindowPos. This check 1.1353 + // can not be moved to the calling code in nsView, because 1.1354 + // some platforms do not position child windows correctly 1.1355 + 1.1356 + // Only perform this check for non-popup windows, since the positioning can 1.1357 + // in fact change even when the x/y do not. We always need to perform the 1.1358 + // check. See bug #97805 for details. 1.1359 + if (mWindowType != eWindowType_popup && (mBounds.x == x) && (mBounds.y == y)) 1.1360 + { 1.1361 + // Nothing to do, since it is already positioned correctly. 1.1362 + return NS_OK; 1.1363 + } 1.1364 + 1.1365 + mBounds.x = x; 1.1366 + mBounds.y = y; 1.1367 + 1.1368 + if (mWnd) { 1.1369 +#ifdef DEBUG 1.1370 + // complain if a window is moved offscreen (legal, but potentially worrisome) 1.1371 + if (mIsTopWidgetWindow) { // only a problem for top-level windows 1.1372 + // Make sure this window is actually on the screen before we move it 1.1373 + // XXX: Needs multiple monitor support 1.1374 + HDC dc = ::GetDC(mWnd); 1.1375 + if (dc) { 1.1376 + if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) { 1.1377 + RECT workArea; 1.1378 + ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0); 1.1379 + // no annoying assertions. just mention the issue. 1.1380 + if (x < 0 || x >= workArea.right || y < 0 || y >= workArea.bottom) { 1.1381 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.1382 + ("window moved to offscreen position\n")); 1.1383 + } 1.1384 + } 1.1385 + ::ReleaseDC(mWnd, dc); 1.1386 + } 1.1387 + } 1.1388 +#endif 1.1389 + ClearThemeRegion(); 1.1390 + 1.1391 + UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE; 1.1392 + // Workaround SetWindowPos bug with D3D9. If our window has a clip 1.1393 + // region, some drivers or OSes may incorrectly copy into the clipped-out 1.1394 + // area. 1.1395 + if (mWindowType == eWindowType_plugin && 1.1396 + (!mLayerManager || mLayerManager->GetBackendType() == LayersBackend::LAYERS_D3D9) && 1.1397 + mClipRects && 1.1398 + (mClipRectCount != 1 || !mClipRects[0].IsEqualInterior(nsIntRect(0, 0, mBounds.width, mBounds.height)))) { 1.1399 + flags |= SWP_NOCOPYBITS; 1.1400 + } 1.1401 + VERIFY(::SetWindowPos(mWnd, nullptr, x, y, 0, 0, flags)); 1.1402 + 1.1403 + SetThemeRegion(); 1.1404 + } 1.1405 + NotifyRollupGeometryChange(); 1.1406 + return NS_OK; 1.1407 +} 1.1408 + 1.1409 +// Resize this component 1.1410 +NS_METHOD nsWindow::Resize(double aWidth, double aHeight, bool aRepaint) 1.1411 +{ 1.1412 + // for top-level windows only, convert coordinates from global display pixels 1.1413 + // (the "parent" coordinate space) to the window's device pixel space 1.1414 + CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale() 1.1415 + : CSSToLayoutDeviceScale(1.0); 1.1416 + int32_t width = NSToIntRound(aWidth * scale.scale); 1.1417 + int32_t height = NSToIntRound(aHeight * scale.scale); 1.1418 + 1.1419 + NS_ASSERTION((width >= 0) , "Negative width passed to nsWindow::Resize"); 1.1420 + NS_ASSERTION((height >= 0), "Negative height passed to nsWindow::Resize"); 1.1421 + 1.1422 + ConstrainSize(&width, &height); 1.1423 + 1.1424 + // Avoid unnecessary resizing calls 1.1425 + if (mBounds.width == width && mBounds.height == height) { 1.1426 + if (aRepaint) { 1.1427 + Invalidate(); 1.1428 + } 1.1429 + return NS_OK; 1.1430 + } 1.1431 + 1.1432 +#ifdef MOZ_XUL 1.1433 + if (eTransparencyTransparent == mTransparencyMode) 1.1434 + ResizeTranslucentWindow(width, height); 1.1435 +#endif 1.1436 + 1.1437 + // Set cached value for lightweight and printing 1.1438 + mBounds.width = width; 1.1439 + mBounds.height = height; 1.1440 + 1.1441 + if (mWnd) { 1.1442 + UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE; 1.1443 + 1.1444 + if (!aRepaint) { 1.1445 + flags |= SWP_NOREDRAW; 1.1446 + } 1.1447 + 1.1448 + ClearThemeRegion(); 1.1449 + VERIFY(::SetWindowPos(mWnd, nullptr, 0, 0, 1.1450 + width, GetHeight(height), flags)); 1.1451 + SetThemeRegion(); 1.1452 + } 1.1453 + 1.1454 + if (aRepaint) 1.1455 + Invalidate(); 1.1456 + 1.1457 + NotifyRollupGeometryChange(); 1.1458 + return NS_OK; 1.1459 +} 1.1460 + 1.1461 +// Resize this component 1.1462 +NS_METHOD nsWindow::Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint) 1.1463 +{ 1.1464 + // for top-level windows only, convert coordinates from global display pixels 1.1465 + // (the "parent" coordinate space) to the window's device pixel space 1.1466 + CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale() 1.1467 + : CSSToLayoutDeviceScale(1.0); 1.1468 + int32_t x = NSToIntRound(aX * scale.scale); 1.1469 + int32_t y = NSToIntRound(aY * scale.scale); 1.1470 + int32_t width = NSToIntRound(aWidth * scale.scale); 1.1471 + int32_t height = NSToIntRound(aHeight * scale.scale); 1.1472 + 1.1473 + NS_ASSERTION((width >= 0), "Negative width passed to nsWindow::Resize"); 1.1474 + NS_ASSERTION((height >= 0), "Negative height passed to nsWindow::Resize"); 1.1475 + 1.1476 + ConstrainSize(&width, &height); 1.1477 + 1.1478 + // Avoid unnecessary resizing calls 1.1479 + if (mBounds.x == x && mBounds.y == y && 1.1480 + mBounds.width == width && mBounds.height == height) { 1.1481 + if (aRepaint) { 1.1482 + Invalidate(); 1.1483 + } 1.1484 + return NS_OK; 1.1485 + } 1.1486 + 1.1487 +#ifdef MOZ_XUL 1.1488 + if (eTransparencyTransparent == mTransparencyMode) 1.1489 + ResizeTranslucentWindow(width, height); 1.1490 +#endif 1.1491 + 1.1492 + // Set cached value for lightweight and printing 1.1493 + mBounds.x = x; 1.1494 + mBounds.y = y; 1.1495 + mBounds.width = width; 1.1496 + mBounds.height = height; 1.1497 + 1.1498 + if (mWnd) { 1.1499 + UINT flags = SWP_NOZORDER | SWP_NOACTIVATE; 1.1500 + if (!aRepaint) { 1.1501 + flags |= SWP_NOREDRAW; 1.1502 + } 1.1503 + 1.1504 + ClearThemeRegion(); 1.1505 + VERIFY(::SetWindowPos(mWnd, nullptr, x, y, 1.1506 + width, GetHeight(height), flags)); 1.1507 + SetThemeRegion(); 1.1508 + } 1.1509 + 1.1510 + if (aRepaint) 1.1511 + Invalidate(); 1.1512 + 1.1513 + NotifyRollupGeometryChange(); 1.1514 + return NS_OK; 1.1515 +} 1.1516 + 1.1517 +NS_IMETHODIMP 1.1518 +nsWindow::BeginResizeDrag(WidgetGUIEvent* aEvent, 1.1519 + int32_t aHorizontal, 1.1520 + int32_t aVertical) 1.1521 +{ 1.1522 + NS_ENSURE_ARG_POINTER(aEvent); 1.1523 + 1.1524 + if (aEvent->eventStructType != NS_MOUSE_EVENT) { 1.1525 + // you can only begin a resize drag with a mouse event 1.1526 + return NS_ERROR_INVALID_ARG; 1.1527 + } 1.1528 + 1.1529 + if (aEvent->AsMouseEvent()->button != WidgetMouseEvent::eLeftButton) { 1.1530 + // you can only begin a resize drag with the left mouse button 1.1531 + return NS_ERROR_INVALID_ARG; 1.1532 + } 1.1533 + 1.1534 + // work out what sizemode we're talking about 1.1535 + WPARAM syscommand; 1.1536 + if (aVertical < 0) { 1.1537 + if (aHorizontal < 0) { 1.1538 + syscommand = SC_SIZE | WMSZ_TOPLEFT; 1.1539 + } else if (aHorizontal == 0) { 1.1540 + syscommand = SC_SIZE | WMSZ_TOP; 1.1541 + } else { 1.1542 + syscommand = SC_SIZE | WMSZ_TOPRIGHT; 1.1543 + } 1.1544 + } else if (aVertical == 0) { 1.1545 + if (aHorizontal < 0) { 1.1546 + syscommand = SC_SIZE | WMSZ_LEFT; 1.1547 + } else if (aHorizontal == 0) { 1.1548 + return NS_ERROR_INVALID_ARG; 1.1549 + } else { 1.1550 + syscommand = SC_SIZE | WMSZ_RIGHT; 1.1551 + } 1.1552 + } else { 1.1553 + if (aHorizontal < 0) { 1.1554 + syscommand = SC_SIZE | WMSZ_BOTTOMLEFT; 1.1555 + } else if (aHorizontal == 0) { 1.1556 + syscommand = SC_SIZE | WMSZ_BOTTOM; 1.1557 + } else { 1.1558 + syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT; 1.1559 + } 1.1560 + } 1.1561 + 1.1562 + // resizing doesn't work if the mouse is already captured 1.1563 + CaptureMouse(false); 1.1564 + 1.1565 + // find the top-level window 1.1566 + HWND toplevelWnd = WinUtils::GetTopLevelHWND(mWnd, true); 1.1567 + 1.1568 + // tell Windows to start the resize 1.1569 + ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand, 1.1570 + POINTTOPOINTS(aEvent->refPoint)); 1.1571 + 1.1572 + return NS_OK; 1.1573 +} 1.1574 + 1.1575 +/************************************************************** 1.1576 + * 1.1577 + * SECTION: Window Z-order and state. 1.1578 + * 1.1579 + * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode, 1.1580 + * nsIWidget::ConstrainPosition 1.1581 + * 1.1582 + * Z-order, positioning, restore, minimize, and maximize. 1.1583 + * 1.1584 + **************************************************************/ 1.1585 + 1.1586 +// Position the window behind the given window 1.1587 +NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, 1.1588 + nsIWidget *aWidget, bool aActivate) 1.1589 +{ 1.1590 + HWND behind = HWND_TOP; 1.1591 + if (aPlacement == eZPlacementBottom) 1.1592 + behind = HWND_BOTTOM; 1.1593 + else if (aPlacement == eZPlacementBelow && aWidget) 1.1594 + behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW); 1.1595 + UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE; 1.1596 + if (!aActivate) 1.1597 + flags |= SWP_NOACTIVATE; 1.1598 + 1.1599 + if (!CanTakeFocus() && behind == HWND_TOP) 1.1600 + { 1.1601 + // Can't place the window to top so place it behind the foreground window 1.1602 + // (as long as it is not topmost) 1.1603 + HWND wndAfter = ::GetForegroundWindow(); 1.1604 + if (!wndAfter) 1.1605 + behind = HWND_BOTTOM; 1.1606 + else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)) 1.1607 + behind = wndAfter; 1.1608 + flags |= SWP_NOACTIVATE; 1.1609 + } 1.1610 + 1.1611 + ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags); 1.1612 + return NS_OK; 1.1613 +} 1.1614 + 1.1615 +// Maximize, minimize or restore the window. 1.1616 +NS_IMETHODIMP nsWindow::SetSizeMode(int32_t aMode) { 1.1617 + 1.1618 + nsresult rv; 1.1619 + 1.1620 + // Let's not try and do anything if we're already in that state. 1.1621 + // (This is needed to prevent problems when calling window.minimize(), which 1.1622 + // calls us directly, and then the OS triggers another call to us.) 1.1623 + if (aMode == mSizeMode) 1.1624 + return NS_OK; 1.1625 + 1.1626 + // save the requested state 1.1627 + mLastSizeMode = mSizeMode; 1.1628 + rv = nsBaseWidget::SetSizeMode(aMode); 1.1629 + if (NS_SUCCEEDED(rv) && mIsVisible) { 1.1630 + int mode; 1.1631 + 1.1632 + switch (aMode) { 1.1633 + case nsSizeMode_Fullscreen : 1.1634 + mode = SW_SHOW; 1.1635 + break; 1.1636 + 1.1637 + case nsSizeMode_Maximized : 1.1638 + mode = SW_MAXIMIZE; 1.1639 + break; 1.1640 + 1.1641 + case nsSizeMode_Minimized : 1.1642 + // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but 1.1643 + // keeps the window active in the tray. So after the window is minimized, 1.1644 + // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point 1.1645 + // we will do some additional processing to get the active window set right. 1.1646 + // If sTrimOnMinimize is set, we let windows handle minimization normally 1.1647 + // using SW_MINIMIZE. 1.1648 + mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED; 1.1649 + break; 1.1650 + 1.1651 + default : 1.1652 + mode = SW_RESTORE; 1.1653 + } 1.1654 + 1.1655 + WINDOWPLACEMENT pl; 1.1656 + pl.length = sizeof(pl); 1.1657 + ::GetWindowPlacement(mWnd, &pl); 1.1658 + // Don't call ::ShowWindow if we're trying to "restore" a window that is 1.1659 + // already in a normal state. Prevents a bug where snapping to one side 1.1660 + // of the screen and then minimizing would cause Windows to forget our 1.1661 + // window's correct restored position/size. 1.1662 + if( !(pl.showCmd == SW_SHOWNORMAL && mode == SW_RESTORE) ) { 1.1663 + ::ShowWindow(mWnd, mode); 1.1664 + } 1.1665 + // we activate here to ensure that the right child window is focused 1.1666 + if (mode == SW_MAXIMIZE || mode == SW_SHOW) 1.1667 + DispatchFocusToTopLevelWindow(true); 1.1668 + } 1.1669 + return rv; 1.1670 +} 1.1671 + 1.1672 +// Constrain a potential move to fit onscreen 1.1673 +// Position (aX, aY) is specified in Windows screen (logical) pixels 1.1674 +NS_METHOD nsWindow::ConstrainPosition(bool aAllowSlop, 1.1675 + int32_t *aX, int32_t *aY) 1.1676 +{ 1.1677 + if (!mIsTopWidgetWindow) // only a problem for top-level windows 1.1678 + return NS_OK; 1.1679 + 1.1680 + double dpiScale = GetDefaultScale().scale; 1.1681 + 1.1682 + // we need to use the window size in logical screen pixels 1.1683 + int32_t logWidth = std::max<int32_t>(NSToIntRound(mBounds.width / dpiScale), 1); 1.1684 + int32_t logHeight = std::max<int32_t>(NSToIntRound(mBounds.height / dpiScale), 1); 1.1685 + 1.1686 + bool doConstrain = false; // whether we have enough info to do anything 1.1687 + 1.1688 + /* get our playing field. use the current screen, or failing that 1.1689 + for any reason, use device caps for the default screen. */ 1.1690 + RECT screenRect; 1.1691 + 1.1692 + nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID); 1.1693 + if (screenmgr) { 1.1694 + nsCOMPtr<nsIScreen> screen; 1.1695 + int32_t left, top, width, height; 1.1696 + 1.1697 + screenmgr->ScreenForRect(*aX, *aY, logWidth, logHeight, 1.1698 + getter_AddRefs(screen)); 1.1699 + if (screen) { 1.1700 + if (mSizeMode != nsSizeMode_Fullscreen) { 1.1701 + // For normalized windows, use the desktop work area. 1.1702 + screen->GetAvailRectDisplayPix(&left, &top, &width, &height); 1.1703 + } else { 1.1704 + // For full screen windows, use the desktop. 1.1705 + screen->GetRectDisplayPix(&left, &top, &width, &height); 1.1706 + } 1.1707 + screenRect.left = left; 1.1708 + screenRect.right = left + width; 1.1709 + screenRect.top = top; 1.1710 + screenRect.bottom = top + height; 1.1711 + doConstrain = true; 1.1712 + } 1.1713 + } else { 1.1714 + if (mWnd) { 1.1715 + HDC dc = ::GetDC(mWnd); 1.1716 + if (dc) { 1.1717 + if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) { 1.1718 + if (mSizeMode != nsSizeMode_Fullscreen) { 1.1719 + ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0); 1.1720 + } else { 1.1721 + screenRect.left = screenRect.top = 0; 1.1722 + screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN); 1.1723 + screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN); 1.1724 + } 1.1725 + doConstrain = true; 1.1726 + } 1.1727 + ::ReleaseDC(mWnd, dc); 1.1728 + } 1.1729 + } 1.1730 + } 1.1731 + 1.1732 + if (aAllowSlop) { 1.1733 + if (*aX < screenRect.left - logWidth + kWindowPositionSlop) 1.1734 + *aX = screenRect.left - logWidth + kWindowPositionSlop; 1.1735 + else if (*aX >= screenRect.right - kWindowPositionSlop) 1.1736 + *aX = screenRect.right - kWindowPositionSlop; 1.1737 + 1.1738 + if (*aY < screenRect.top - logHeight + kWindowPositionSlop) 1.1739 + *aY = screenRect.top - logHeight + kWindowPositionSlop; 1.1740 + else if (*aY >= screenRect.bottom - kWindowPositionSlop) 1.1741 + *aY = screenRect.bottom - kWindowPositionSlop; 1.1742 + 1.1743 + } else { 1.1744 + 1.1745 + if (*aX < screenRect.left) 1.1746 + *aX = screenRect.left; 1.1747 + else if (*aX >= screenRect.right - logWidth) 1.1748 + *aX = screenRect.right - logWidth; 1.1749 + 1.1750 + if (*aY < screenRect.top) 1.1751 + *aY = screenRect.top; 1.1752 + else if (*aY >= screenRect.bottom - logHeight) 1.1753 + *aY = screenRect.bottom - logHeight; 1.1754 + } 1.1755 + 1.1756 + return NS_OK; 1.1757 +} 1.1758 + 1.1759 +/************************************************************** 1.1760 + * 1.1761 + * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled 1.1762 + * 1.1763 + * Enabling and disabling the widget. 1.1764 + * 1.1765 + **************************************************************/ 1.1766 + 1.1767 +// Enable/disable this component 1.1768 +NS_METHOD nsWindow::Enable(bool bState) 1.1769 +{ 1.1770 + if (mWnd) { 1.1771 + ::EnableWindow(mWnd, bState); 1.1772 + } 1.1773 + return NS_OK; 1.1774 +} 1.1775 + 1.1776 +// Return the current enable state 1.1777 +bool nsWindow::IsEnabled() const 1.1778 +{ 1.1779 + return !mWnd || 1.1780 + (::IsWindowEnabled(mWnd) && 1.1781 + ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT))); 1.1782 +} 1.1783 + 1.1784 + 1.1785 +/************************************************************** 1.1786 + * 1.1787 + * SECTION: nsIWidget::SetFocus 1.1788 + * 1.1789 + * Give the focus to this widget. 1.1790 + * 1.1791 + **************************************************************/ 1.1792 + 1.1793 +NS_METHOD nsWindow::SetFocus(bool aRaise) 1.1794 +{ 1.1795 + if (mWnd) { 1.1796 +#ifdef WINSTATE_DEBUG_OUTPUT 1.1797 + if (mWnd == WinUtils::GetTopLevelHWND(mWnd)) { 1.1798 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.1799 + ("*** SetFocus: [ top] raise=%d\n", aRaise)); 1.1800 + } else { 1.1801 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.1802 + ("*** SetFocus: [child] raise=%d\n", aRaise)); 1.1803 + } 1.1804 +#endif 1.1805 + // Uniconify, if necessary 1.1806 + HWND toplevelWnd = WinUtils::GetTopLevelHWND(mWnd); 1.1807 + if (aRaise && ::IsIconic(toplevelWnd)) { 1.1808 + ::ShowWindow(toplevelWnd, SW_RESTORE); 1.1809 + } 1.1810 + ::SetFocus(mWnd); 1.1811 + } 1.1812 + return NS_OK; 1.1813 +} 1.1814 + 1.1815 + 1.1816 +/************************************************************** 1.1817 + * 1.1818 + * SECTION: Bounds 1.1819 + * 1.1820 + * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset 1.1821 + * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins 1.1822 + * 1.1823 + * Bound calculations. 1.1824 + * 1.1825 + **************************************************************/ 1.1826 + 1.1827 +// Return the window's full dimensions in screen coordinates. 1.1828 +// If the window has a parent, converts the origin to an offset 1.1829 +// of the parent's screen origin. 1.1830 +NS_METHOD nsWindow::GetBounds(nsIntRect &aRect) 1.1831 +{ 1.1832 + if (mWnd) { 1.1833 + RECT r; 1.1834 + VERIFY(::GetWindowRect(mWnd, &r)); 1.1835 + 1.1836 + // assign size 1.1837 + aRect.width = r.right - r.left; 1.1838 + aRect.height = r.bottom - r.top; 1.1839 + 1.1840 + // popup window bounds' are in screen coordinates, not relative to parent 1.1841 + // window 1.1842 + if (mWindowType == eWindowType_popup) { 1.1843 + aRect.x = r.left; 1.1844 + aRect.y = r.top; 1.1845 + return NS_OK; 1.1846 + } 1.1847 + 1.1848 + // chrome on parent: 1.1849 + // ___ 5,5 (chrome start) 1.1850 + // | ____ 10,10 (client start) 1.1851 + // | | ____ 20,20 (child start) 1.1852 + // | | | 1.1853 + // 20,20 - 5,5 = 15,15 (??) 1.1854 + // minus GetClientOffset: 1.1855 + // 15,15 - 5,5 = 10,10 1.1856 + // 1.1857 + // no chrome on parent: 1.1858 + // ______ 10,10 (win start) 1.1859 + // | ____ 20,20 (child start) 1.1860 + // | | 1.1861 + // 20,20 - 10,10 = 10,10 1.1862 + // 1.1863 + // walking the chain: 1.1864 + // ___ 5,5 (chrome start) 1.1865 + // | ___ 10,10 (client start) 1.1866 + // | | ___ 20,20 (child start) 1.1867 + // | | | __ 30,30 (child start) 1.1868 + // | | | | 1.1869 + // 30,30 - 20,20 = 10,10 (offset from second child to first) 1.1870 + // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??) 1.1871 + // minus GetClientOffset: 1.1872 + // 25,25 - 5,5 = 20,20 (offset from second child to parent client) 1.1873 + 1.1874 + // convert coordinates if parent exists 1.1875 + HWND parent = ::GetParent(mWnd); 1.1876 + if (parent) { 1.1877 + RECT pr; 1.1878 + VERIFY(::GetWindowRect(parent, &pr)); 1.1879 + r.left -= pr.left; 1.1880 + r.top -= pr.top; 1.1881 + // adjust for chrome 1.1882 + nsWindow* pWidget = static_cast<nsWindow*>(GetParent()); 1.1883 + if (pWidget && pWidget->IsTopLevelWidget()) { 1.1884 + nsIntPoint clientOffset = pWidget->GetClientOffset(); 1.1885 + r.left -= clientOffset.x; 1.1886 + r.top -= clientOffset.y; 1.1887 + } 1.1888 + } 1.1889 + aRect.x = r.left; 1.1890 + aRect.y = r.top; 1.1891 + } else { 1.1892 + aRect = mBounds; 1.1893 + } 1.1894 + return NS_OK; 1.1895 +} 1.1896 + 1.1897 +// Get this component dimension 1.1898 +NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect) 1.1899 +{ 1.1900 + if (mWnd) { 1.1901 + RECT r; 1.1902 + VERIFY(::GetClientRect(mWnd, &r)); 1.1903 + 1.1904 + nsIntRect bounds; 1.1905 + GetBounds(bounds); 1.1906 + aRect.MoveTo(bounds.TopLeft() + GetClientOffset()); 1.1907 + aRect.width = r.right - r.left; 1.1908 + aRect.height = r.bottom - r.top; 1.1909 + 1.1910 + } else { 1.1911 + aRect.SetRect(0,0,0,0); 1.1912 + } 1.1913 + return NS_OK; 1.1914 +} 1.1915 + 1.1916 +// Like GetBounds, but don't offset by the parent 1.1917 +NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect) 1.1918 +{ 1.1919 + if (mWnd) { 1.1920 + RECT r; 1.1921 + VERIFY(::GetWindowRect(mWnd, &r)); 1.1922 + 1.1923 + aRect.width = r.right - r.left; 1.1924 + aRect.height = r.bottom - r.top; 1.1925 + aRect.x = r.left; 1.1926 + aRect.y = r.top; 1.1927 + } else 1.1928 + aRect = mBounds; 1.1929 + 1.1930 + return NS_OK; 1.1931 +} 1.1932 + 1.1933 +// return the x,y offset of the client area from the origin 1.1934 +// of the window. If the window is borderless returns (0,0). 1.1935 +nsIntPoint nsWindow::GetClientOffset() 1.1936 +{ 1.1937 + if (!mWnd) { 1.1938 + return nsIntPoint(0, 0); 1.1939 + } 1.1940 + 1.1941 + RECT r1; 1.1942 + GetWindowRect(mWnd, &r1); 1.1943 + nsIntPoint pt = WidgetToScreenOffset(); 1.1944 + return nsIntPoint(pt.x - r1.left, pt.y - r1.top); 1.1945 +} 1.1946 + 1.1947 +void 1.1948 +nsWindow::SetDrawsInTitlebar(bool aState) 1.1949 +{ 1.1950 + nsWindow * window = GetTopLevelWindow(true); 1.1951 + if (window && window != this) { 1.1952 + return window->SetDrawsInTitlebar(aState); 1.1953 + } 1.1954 + 1.1955 + if (aState) { 1.1956 + // top, right, bottom, left for nsIntMargin 1.1957 + nsIntMargin margins(0, -1, -1, -1); 1.1958 + SetNonClientMargins(margins); 1.1959 + } 1.1960 + else { 1.1961 + nsIntMargin margins(-1, -1, -1, -1); 1.1962 + SetNonClientMargins(margins); 1.1963 + } 1.1964 +} 1.1965 + 1.1966 +NS_IMETHODIMP 1.1967 +nsWindow::GetNonClientMargins(nsIntMargin &margins) 1.1968 +{ 1.1969 + nsWindow * window = GetTopLevelWindow(true); 1.1970 + if (window && window != this) { 1.1971 + return window->GetNonClientMargins(margins); 1.1972 + } 1.1973 + 1.1974 + if (mCustomNonClient) { 1.1975 + margins = mNonClientMargins; 1.1976 + return NS_OK; 1.1977 + } 1.1978 + 1.1979 + margins.top = GetSystemMetrics(SM_CYCAPTION); 1.1980 + margins.bottom = GetSystemMetrics(SM_CYFRAME); 1.1981 + margins.top += margins.bottom; 1.1982 + margins.left = margins.right = GetSystemMetrics(SM_CXFRAME); 1.1983 + 1.1984 + return NS_OK; 1.1985 +} 1.1986 + 1.1987 +void 1.1988 +nsWindow::ResetLayout() 1.1989 +{ 1.1990 + // This will trigger a frame changed event, triggering 1.1991 + // nc calc size and a sizemode gecko event. 1.1992 + SetWindowPos(mWnd, 0, 0, 0, 0, 0, 1.1993 + SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE| 1.1994 + SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER); 1.1995 + 1.1996 + // If hidden, just send the frame changed event for now. 1.1997 + if (!mIsVisible) 1.1998 + return; 1.1999 + 1.2000 + // Send a gecko size event to trigger reflow. 1.2001 + RECT clientRc = {0}; 1.2002 + GetClientRect(mWnd, &clientRc); 1.2003 + nsIntRect evRect(WinUtils::ToIntRect(clientRc)); 1.2004 + OnResize(evRect); 1.2005 + 1.2006 + // Invalidate and update 1.2007 + Invalidate(); 1.2008 +} 1.2009 + 1.2010 +// Internally track the caption status via a window property. Required 1.2011 +// due to our internal handling of WM_NCACTIVATE when custom client 1.2012 +// margins are set. 1.2013 +static const wchar_t kManageWindowInfoProperty[] = L"ManageWindowInfoProperty"; 1.2014 +typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi); 1.2015 +static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr; 1.2016 + 1.2017 +BOOL WINAPI 1.2018 +GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi) 1.2019 +{ 1.2020 + if (!sGetWindowInfoPtrStub) { 1.2021 + NS_ASSERTION(FALSE, "Something is horribly wrong in GetWindowInfoHook!"); 1.2022 + return FALSE; 1.2023 + } 1.2024 + int windowStatus = 1.2025 + reinterpret_cast<LONG_PTR>(GetPropW(hWnd, kManageWindowInfoProperty)); 1.2026 + // No property set, return the default data. 1.2027 + if (!windowStatus) 1.2028 + return sGetWindowInfoPtrStub(hWnd, pwi); 1.2029 + // Call GetWindowInfo and update dwWindowStatus with our 1.2030 + // internally tracked value. 1.2031 + BOOL result = sGetWindowInfoPtrStub(hWnd, pwi); 1.2032 + if (result && pwi) 1.2033 + pwi->dwWindowStatus = (windowStatus == 1 ? 0 : WS_ACTIVECAPTION); 1.2034 + return result; 1.2035 +} 1.2036 + 1.2037 +void 1.2038 +nsWindow::UpdateGetWindowInfoCaptionStatus(bool aActiveCaption) 1.2039 +{ 1.2040 + if (!mWnd) 1.2041 + return; 1.2042 + 1.2043 + if (!sGetWindowInfoPtrStub) { 1.2044 + sUser32Intercept.Init("user32.dll"); 1.2045 + if (!sUser32Intercept.AddHook("GetWindowInfo", reinterpret_cast<intptr_t>(GetWindowInfoHook), 1.2046 + (void**) &sGetWindowInfoPtrStub)) 1.2047 + return; 1.2048 + } 1.2049 + // Update our internally tracked caption status 1.2050 + SetPropW(mWnd, kManageWindowInfoProperty, 1.2051 + reinterpret_cast<HANDLE>(static_cast<int>(aActiveCaption) + 1)); 1.2052 +} 1.2053 + 1.2054 +/** 1.2055 + * Called when the window layout changes: full screen mode transitions, 1.2056 + * theme changes, and composition changes. Calculates the new non-client 1.2057 + * margins and fires off a frame changed event, which triggers an nc calc 1.2058 + * size windows event, kicking the changes in. 1.2059 + * 1.2060 + * The offsets calculated here are based on the value of `mNonClientMargins` 1.2061 + * which is specified in the "chromemargins" attribute of the window. For 1.2062 + * each margin, the value specified has the following meaning: 1.2063 + * -1 - leave the default frame in place 1.2064 + * 0 - remove the frame 1.2065 + * >0 - frame size equals min(0, (default frame size - margin value)) 1.2066 + * 1.2067 + * This function calculates and populates `mNonClientOffset`. 1.2068 + * In our processing of `WM_NCCALCSIZE`, the frame size will be calculated 1.2069 + * as (default frame size - offset). For example, if the left frame should 1.2070 + * be 1 pixel narrower than the default frame size, `mNonClientOffset.left` 1.2071 + * will equal 1. 1.2072 + * 1.2073 + * For maximized, fullscreen, and minimized windows, the values stored in 1.2074 + * `mNonClientMargins` are ignored, and special processing takes place. 1.2075 + * 1.2076 + * For non-glass windows, we only allow frames to be their default size 1.2077 + * or removed entirely. 1.2078 + */ 1.2079 +bool 1.2080 +nsWindow::UpdateNonClientMargins(int32_t aSizeMode, bool aReflowWindow) 1.2081 +{ 1.2082 + if (!mCustomNonClient) 1.2083 + return false; 1.2084 + 1.2085 + if (aSizeMode == -1) { 1.2086 + aSizeMode = mSizeMode; 1.2087 + } 1.2088 + 1.2089 + bool hasCaption = (mBorderStyle 1.2090 + & (eBorderStyle_all 1.2091 + | eBorderStyle_title 1.2092 + | eBorderStyle_menu 1.2093 + | eBorderStyle_default)); 1.2094 + 1.2095 + // mCaptionHeight is the default size of the NC area at 1.2096 + // the top of the window. If the window has a caption, 1.2097 + // the size is calculated as the sum of: 1.2098 + // SM_CYFRAME - The thickness of the sizing border 1.2099 + // around a resizable window 1.2100 + // SM_CXPADDEDBORDER - The amount of border padding 1.2101 + // for captioned windows 1.2102 + // SM_CYCAPTION - The height of the caption area 1.2103 + // 1.2104 + // If the window does not have a caption, mCaptionHeight will be equal to 1.2105 + // `GetSystemMetrics(SM_CYFRAME)` 1.2106 + mCaptionHeight = GetSystemMetrics(SM_CYFRAME) 1.2107 + + (hasCaption ? GetSystemMetrics(SM_CYCAPTION) 1.2108 + + GetSystemMetrics(SM_CXPADDEDBORDER) 1.2109 + : 0); 1.2110 + 1.2111 + // mHorResizeMargin is the size of the default NC areas on the 1.2112 + // left and right sides of our window. It is calculated as 1.2113 + // the sum of: 1.2114 + // SM_CXFRAME - The thickness of the sizing border 1.2115 + // SM_CXPADDEDBORDER - The amount of border padding 1.2116 + // for captioned windows 1.2117 + // 1.2118 + // If the window does not have a caption, mHorResizeMargin will be equal to 1.2119 + // `GetSystemMetrics(SM_CXFRAME)` 1.2120 + mHorResizeMargin = GetSystemMetrics(SM_CXFRAME) 1.2121 + + (hasCaption ? GetSystemMetrics(SM_CXPADDEDBORDER) : 0); 1.2122 + 1.2123 + // mVertResizeMargin is the size of the default NC area at the 1.2124 + // bottom of the window. It is calculated as the sum of: 1.2125 + // SM_CYFRAME - The thickness of the sizing border 1.2126 + // SM_CXPADDEDBORDER - The amount of border padding 1.2127 + // for captioned windows. 1.2128 + // 1.2129 + // If the window does not have a caption, mVertResizeMargin will be equal to 1.2130 + // `GetSystemMetrics(SM_CYFRAME)` 1.2131 + mVertResizeMargin = GetSystemMetrics(SM_CYFRAME) 1.2132 + + (hasCaption ? GetSystemMetrics(SM_CXPADDEDBORDER) : 0); 1.2133 + 1.2134 + if (aSizeMode == nsSizeMode_Minimized) { 1.2135 + // Use default frame size for minimized windows 1.2136 + mNonClientOffset.top = 0; 1.2137 + mNonClientOffset.left = 0; 1.2138 + mNonClientOffset.right = 0; 1.2139 + mNonClientOffset.bottom = 0; 1.2140 + } else if (aSizeMode == nsSizeMode_Fullscreen) { 1.2141 + // Remove the default frame from the top of our fullscreen window. This 1.2142 + // makes the whole caption part of our client area, allowing us to draw 1.2143 + // in the whole caption area. Additionally remove the default frame from 1.2144 + // the left, right, and bottom. 1.2145 + mNonClientOffset.top = mCaptionHeight; 1.2146 + mNonClientOffset.bottom = mVertResizeMargin; 1.2147 + mNonClientOffset.left = mHorResizeMargin; 1.2148 + mNonClientOffset.right = mHorResizeMargin; 1.2149 + } else if (aSizeMode == nsSizeMode_Maximized) { 1.2150 + // Remove the default frame from the top of our maximized window. This 1.2151 + // makes the whole caption part of our client area, allowing us to draw 1.2152 + // in the whole caption area. Use default frame size on left, right, and 1.2153 + // bottom. The reason this works is that, for maximized windows, 1.2154 + // Windows positions them so that their frames fall off the screen. 1.2155 + // This gives the illusion of windows having no frames when they are 1.2156 + // maximized. If we try to mess with the frame sizes by setting these 1.2157 + // offsets to positive values, our client area will fall off the screen. 1.2158 + mNonClientOffset.top = mCaptionHeight; 1.2159 + mNonClientOffset.bottom = 0; 1.2160 + mNonClientOffset.left = 0; 1.2161 + mNonClientOffset.right = 0; 1.2162 + 1.2163 + APPBARDATA appBarData; 1.2164 + appBarData.cbSize = sizeof(appBarData); 1.2165 + UINT taskbarState = SHAppBarMessage(ABM_GETSTATE, &appBarData); 1.2166 + if (ABS_AUTOHIDE & taskbarState) { 1.2167 + UINT edge = -1; 1.2168 + appBarData.hWnd = FindWindow(L"Shell_TrayWnd", nullptr); 1.2169 + if (appBarData.hWnd) { 1.2170 + HMONITOR taskbarMonitor = ::MonitorFromWindow(appBarData.hWnd, 1.2171 + MONITOR_DEFAULTTOPRIMARY); 1.2172 + HMONITOR windowMonitor = ::MonitorFromWindow(mWnd, 1.2173 + MONITOR_DEFAULTTONEAREST); 1.2174 + if (taskbarMonitor == windowMonitor) { 1.2175 + SHAppBarMessage(ABM_GETTASKBARPOS, &appBarData); 1.2176 + edge = appBarData.uEdge; 1.2177 + } 1.2178 + } 1.2179 + 1.2180 + if (ABE_LEFT == edge) { 1.2181 + mNonClientOffset.left -= 1; 1.2182 + } else if (ABE_RIGHT == edge) { 1.2183 + mNonClientOffset.right -= 1; 1.2184 + } else if (ABE_BOTTOM == edge || ABE_TOP == edge) { 1.2185 + mNonClientOffset.bottom -= 1; 1.2186 + } 1.2187 + } 1.2188 + } else { 1.2189 + bool glass = nsUXThemeData::CheckForCompositor(); 1.2190 + 1.2191 + // We're dealing with a "normal" window (not maximized, minimized, or 1.2192 + // fullscreen), so process `mNonClientMargins` and set `mNonClientOffset` 1.2193 + // accordingly. 1.2194 + // 1.2195 + // Setting `mNonClientOffset` to 0 has the effect of leaving the default 1.2196 + // frame intact. Setting it to a value greater than 0 reduces the frame 1.2197 + // size by that amount. 1.2198 + 1.2199 + if (mNonClientMargins.top > 0 && glass) { 1.2200 + mNonClientOffset.top = std::min(mCaptionHeight, mNonClientMargins.top); 1.2201 + } else if (mNonClientMargins.top == 0) { 1.2202 + mNonClientOffset.top = mCaptionHeight; 1.2203 + } else { 1.2204 + mNonClientOffset.top = 0; 1.2205 + } 1.2206 + 1.2207 + if (mNonClientMargins.bottom > 0 && glass) { 1.2208 + mNonClientOffset.bottom = std::min(mVertResizeMargin, mNonClientMargins.bottom); 1.2209 + } else if (mNonClientMargins.bottom == 0) { 1.2210 + mNonClientOffset.bottom = mVertResizeMargin; 1.2211 + } else { 1.2212 + mNonClientOffset.bottom = 0; 1.2213 + } 1.2214 + 1.2215 + if (mNonClientMargins.left > 0 && glass) { 1.2216 + mNonClientOffset.left = std::min(mHorResizeMargin, mNonClientMargins.left); 1.2217 + } else if (mNonClientMargins.left == 0) { 1.2218 + mNonClientOffset.left = mHorResizeMargin; 1.2219 + } else { 1.2220 + mNonClientOffset.left = 0; 1.2221 + } 1.2222 + 1.2223 + if (mNonClientMargins.right > 0 && glass) { 1.2224 + mNonClientOffset.right = std::min(mHorResizeMargin, mNonClientMargins.right); 1.2225 + } else if (mNonClientMargins.right == 0) { 1.2226 + mNonClientOffset.right = mHorResizeMargin; 1.2227 + } else { 1.2228 + mNonClientOffset.right = 0; 1.2229 + } 1.2230 + } 1.2231 + 1.2232 + if (aReflowWindow) { 1.2233 + // Force a reflow of content based on the new client 1.2234 + // dimensions. 1.2235 + ResetLayout(); 1.2236 + } 1.2237 + 1.2238 + return true; 1.2239 +} 1.2240 + 1.2241 +NS_IMETHODIMP 1.2242 +nsWindow::SetNonClientMargins(nsIntMargin &margins) 1.2243 +{ 1.2244 + if (!mIsTopWidgetWindow || 1.2245 + mBorderStyle & eBorderStyle_none || 1.2246 + mHideChrome) 1.2247 + return NS_ERROR_INVALID_ARG; 1.2248 + 1.2249 + // Request for a reset 1.2250 + if (margins.top == -1 && margins.left == -1 && 1.2251 + margins.right == -1 && margins.bottom == -1) { 1.2252 + mCustomNonClient = false; 1.2253 + mNonClientMargins = margins; 1.2254 + // Force a reflow of content based on the new client 1.2255 + // dimensions. 1.2256 + ResetLayout(); 1.2257 + 1.2258 + int windowStatus = 1.2259 + reinterpret_cast<LONG_PTR>(GetPropW(mWnd, kManageWindowInfoProperty)); 1.2260 + if (windowStatus) { 1.2261 + ::SendMessageW(mWnd, WM_NCACTIVATE, 1 != windowStatus, 0); 1.2262 + } 1.2263 + 1.2264 + return NS_OK; 1.2265 + } 1.2266 + 1.2267 + if (margins.top < -1 || margins.bottom < -1 || 1.2268 + margins.left < -1 || margins.right < -1) 1.2269 + return NS_ERROR_INVALID_ARG; 1.2270 + 1.2271 + mNonClientMargins = margins; 1.2272 + mCustomNonClient = true; 1.2273 + if (!UpdateNonClientMargins()) { 1.2274 + NS_WARNING("UpdateNonClientMargins failed!"); 1.2275 + return NS_OK; 1.2276 + } 1.2277 + 1.2278 + return NS_OK; 1.2279 +} 1.2280 + 1.2281 +void 1.2282 +nsWindow::InvalidateNonClientRegion() 1.2283 +{ 1.2284 + // +-+-----------------------+-+ 1.2285 + // | | app non-client chrome | | 1.2286 + // | +-----------------------+ | 1.2287 + // | | app client chrome | | } 1.2288 + // | +-----------------------+ | } 1.2289 + // | | app content | | } area we don't want to invalidate 1.2290 + // | +-----------------------+ | } 1.2291 + // | | app client chrome | | } 1.2292 + // | +-----------------------+ | 1.2293 + // +---------------------------+ < 1.2294 + // ^ ^ windows non-client chrome 1.2295 + // client area = app * 1.2296 + RECT rect; 1.2297 + GetWindowRect(mWnd, &rect); 1.2298 + MapWindowPoints(nullptr, mWnd, (LPPOINT)&rect, 2); 1.2299 + HRGN winRgn = CreateRectRgnIndirect(&rect); 1.2300 + 1.2301 + // Subtract app client chrome and app content leaving 1.2302 + // windows non-client chrome and app non-client chrome 1.2303 + // in winRgn. 1.2304 + GetWindowRect(mWnd, &rect); 1.2305 + rect.top += mCaptionHeight; 1.2306 + rect.right -= mHorResizeMargin; 1.2307 + rect.bottom -= mHorResizeMargin; 1.2308 + rect.left += mVertResizeMargin; 1.2309 + MapWindowPoints(nullptr, mWnd, (LPPOINT)&rect, 2); 1.2310 + HRGN clientRgn = CreateRectRgnIndirect(&rect); 1.2311 + CombineRgn(winRgn, winRgn, clientRgn, RGN_DIFF); 1.2312 + DeleteObject(clientRgn); 1.2313 + 1.2314 + // triggers ncpaint and paint events for the two areas 1.2315 + RedrawWindow(mWnd, nullptr, winRgn, RDW_FRAME | RDW_INVALIDATE); 1.2316 + DeleteObject(winRgn); 1.2317 +} 1.2318 + 1.2319 +HRGN 1.2320 +nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion) 1.2321 +{ 1.2322 + RECT rect; 1.2323 + HRGN rgn = nullptr; 1.2324 + if (aRegion == (HRGN)1) { // undocumented value indicating a full refresh 1.2325 + GetWindowRect(mWnd, &rect); 1.2326 + rgn = CreateRectRgnIndirect(&rect); 1.2327 + } else { 1.2328 + rgn = aRegion; 1.2329 + } 1.2330 + GetClientRect(mWnd, &rect); 1.2331 + MapWindowPoints(mWnd, nullptr, (LPPOINT)&rect, 2); 1.2332 + HRGN nonClientRgn = CreateRectRgnIndirect(&rect); 1.2333 + CombineRgn(rgn, rgn, nonClientRgn, RGN_DIFF); 1.2334 + DeleteObject(nonClientRgn); 1.2335 + return rgn; 1.2336 +} 1.2337 + 1.2338 +/************************************************************** 1.2339 + * 1.2340 + * SECTION: nsIWidget::SetBackgroundColor 1.2341 + * 1.2342 + * Sets the window background paint color. 1.2343 + * 1.2344 + **************************************************************/ 1.2345 + 1.2346 +void nsWindow::SetBackgroundColor(const nscolor &aColor) 1.2347 +{ 1.2348 + if (mBrush) 1.2349 + ::DeleteObject(mBrush); 1.2350 + 1.2351 + mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(aColor)); 1.2352 + if (mWnd != nullptr) { 1.2353 + ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush); 1.2354 + } 1.2355 +} 1.2356 + 1.2357 +/************************************************************** 1.2358 + * 1.2359 + * SECTION: nsIWidget::SetCursor 1.2360 + * 1.2361 + * SetCursor and related utilities for manging cursor state. 1.2362 + * 1.2363 + **************************************************************/ 1.2364 + 1.2365 +// Set this component cursor 1.2366 +NS_METHOD nsWindow::SetCursor(nsCursor aCursor) 1.2367 +{ 1.2368 + // Only change cursor if it's changing 1.2369 + 1.2370 + //XXX mCursor isn't always right. Scrollbars and others change it, too. 1.2371 + //XXX If we want this optimization we need a better way to do it. 1.2372 + //if (aCursor != mCursor) { 1.2373 + HCURSOR newCursor = nullptr; 1.2374 + 1.2375 + switch (aCursor) { 1.2376 + case eCursor_select: 1.2377 + newCursor = ::LoadCursor(nullptr, IDC_IBEAM); 1.2378 + break; 1.2379 + 1.2380 + case eCursor_wait: 1.2381 + newCursor = ::LoadCursor(nullptr, IDC_WAIT); 1.2382 + break; 1.2383 + 1.2384 + case eCursor_hyperlink: 1.2385 + { 1.2386 + newCursor = ::LoadCursor(nullptr, IDC_HAND); 1.2387 + break; 1.2388 + } 1.2389 + 1.2390 + case eCursor_standard: 1.2391 + case eCursor_context_menu: // XXX See bug 258960. 1.2392 + newCursor = ::LoadCursor(nullptr, IDC_ARROW); 1.2393 + break; 1.2394 + 1.2395 + case eCursor_n_resize: 1.2396 + case eCursor_s_resize: 1.2397 + newCursor = ::LoadCursor(nullptr, IDC_SIZENS); 1.2398 + break; 1.2399 + 1.2400 + case eCursor_w_resize: 1.2401 + case eCursor_e_resize: 1.2402 + newCursor = ::LoadCursor(nullptr, IDC_SIZEWE); 1.2403 + break; 1.2404 + 1.2405 + case eCursor_nw_resize: 1.2406 + case eCursor_se_resize: 1.2407 + newCursor = ::LoadCursor(nullptr, IDC_SIZENWSE); 1.2408 + break; 1.2409 + 1.2410 + case eCursor_ne_resize: 1.2411 + case eCursor_sw_resize: 1.2412 + newCursor = ::LoadCursor(nullptr, IDC_SIZENESW); 1.2413 + break; 1.2414 + 1.2415 + case eCursor_crosshair: 1.2416 + newCursor = ::LoadCursor(nullptr, IDC_CROSS); 1.2417 + break; 1.2418 + 1.2419 + case eCursor_move: 1.2420 + newCursor = ::LoadCursor(nullptr, IDC_SIZEALL); 1.2421 + break; 1.2422 + 1.2423 + case eCursor_help: 1.2424 + newCursor = ::LoadCursor(nullptr, IDC_HELP); 1.2425 + break; 1.2426 + 1.2427 + case eCursor_copy: // CSS3 1.2428 + newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY)); 1.2429 + break; 1.2430 + 1.2431 + case eCursor_alias: 1.2432 + newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS)); 1.2433 + break; 1.2434 + 1.2435 + case eCursor_cell: 1.2436 + newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL)); 1.2437 + break; 1.2438 + 1.2439 + case eCursor_grab: 1.2440 + newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB)); 1.2441 + break; 1.2442 + 1.2443 + case eCursor_grabbing: 1.2444 + newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING)); 1.2445 + break; 1.2446 + 1.2447 + case eCursor_spinning: 1.2448 + newCursor = ::LoadCursor(nullptr, IDC_APPSTARTING); 1.2449 + break; 1.2450 + 1.2451 + case eCursor_zoom_in: 1.2452 + newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN)); 1.2453 + break; 1.2454 + 1.2455 + case eCursor_zoom_out: 1.2456 + newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT)); 1.2457 + break; 1.2458 + 1.2459 + case eCursor_not_allowed: 1.2460 + case eCursor_no_drop: 1.2461 + newCursor = ::LoadCursor(nullptr, IDC_NO); 1.2462 + break; 1.2463 + 1.2464 + case eCursor_col_resize: 1.2465 + newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE)); 1.2466 + break; 1.2467 + 1.2468 + case eCursor_row_resize: 1.2469 + newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE)); 1.2470 + break; 1.2471 + 1.2472 + case eCursor_vertical_text: 1.2473 + newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT)); 1.2474 + break; 1.2475 + 1.2476 + case eCursor_all_scroll: 1.2477 + // XXX not 100% appropriate perhaps 1.2478 + newCursor = ::LoadCursor(nullptr, IDC_SIZEALL); 1.2479 + break; 1.2480 + 1.2481 + case eCursor_nesw_resize: 1.2482 + newCursor = ::LoadCursor(nullptr, IDC_SIZENESW); 1.2483 + break; 1.2484 + 1.2485 + case eCursor_nwse_resize: 1.2486 + newCursor = ::LoadCursor(nullptr, IDC_SIZENWSE); 1.2487 + break; 1.2488 + 1.2489 + case eCursor_ns_resize: 1.2490 + newCursor = ::LoadCursor(nullptr, IDC_SIZENS); 1.2491 + break; 1.2492 + 1.2493 + case eCursor_ew_resize: 1.2494 + newCursor = ::LoadCursor(nullptr, IDC_SIZEWE); 1.2495 + break; 1.2496 + 1.2497 + case eCursor_none: 1.2498 + newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE)); 1.2499 + break; 1.2500 + 1.2501 + default: 1.2502 + NS_ERROR("Invalid cursor type"); 1.2503 + break; 1.2504 + } 1.2505 + 1.2506 + if (nullptr != newCursor) { 1.2507 + mCursor = aCursor; 1.2508 + HCURSOR oldCursor = ::SetCursor(newCursor); 1.2509 + 1.2510 + if (sHCursor == oldCursor) { 1.2511 + NS_IF_RELEASE(sCursorImgContainer); 1.2512 + if (sHCursor != nullptr) 1.2513 + ::DestroyIcon(sHCursor); 1.2514 + sHCursor = nullptr; 1.2515 + } 1.2516 + } 1.2517 + 1.2518 + return NS_OK; 1.2519 +} 1.2520 + 1.2521 +// Setting the actual cursor 1.2522 +NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor, 1.2523 + uint32_t aHotspotX, uint32_t aHotspotY) 1.2524 +{ 1.2525 + if (sCursorImgContainer == aCursor && sHCursor) { 1.2526 + ::SetCursor(sHCursor); 1.2527 + return NS_OK; 1.2528 + } 1.2529 + 1.2530 + int32_t width; 1.2531 + int32_t height; 1.2532 + 1.2533 + nsresult rv; 1.2534 + rv = aCursor->GetWidth(&width); 1.2535 + NS_ENSURE_SUCCESS(rv, rv); 1.2536 + rv = aCursor->GetHeight(&height); 1.2537 + NS_ENSURE_SUCCESS(rv, rv); 1.2538 + 1.2539 + // Reject cursors greater than 128 pixels in either direction, to prevent 1.2540 + // spoofing. 1.2541 + // XXX ideally we should rescale. Also, we could modify the API to 1.2542 + // allow trusted content to set larger cursors. 1.2543 + if (width > 128 || height > 128) 1.2544 + return NS_ERROR_NOT_AVAILABLE; 1.2545 + 1.2546 + HCURSOR cursor; 1.2547 + // No scaling 1.2548 + gfxIntSize size(0, 0); 1.2549 + rv = nsWindowGfx::CreateIcon(aCursor, true, aHotspotX, aHotspotY, size, &cursor); 1.2550 + NS_ENSURE_SUCCESS(rv, rv); 1.2551 + 1.2552 + mCursor = nsCursor(-1); 1.2553 + ::SetCursor(cursor); 1.2554 + 1.2555 + NS_IF_RELEASE(sCursorImgContainer); 1.2556 + sCursorImgContainer = aCursor; 1.2557 + NS_ADDREF(sCursorImgContainer); 1.2558 + 1.2559 + if (sHCursor != nullptr) 1.2560 + ::DestroyIcon(sHCursor); 1.2561 + sHCursor = cursor; 1.2562 + 1.2563 + return NS_OK; 1.2564 +} 1.2565 + 1.2566 +/************************************************************** 1.2567 + * 1.2568 + * SECTION: nsIWidget::Get/SetTransparencyMode 1.2569 + * 1.2570 + * Manage the transparency mode of the top-level window 1.2571 + * containing this widget. 1.2572 + * 1.2573 + **************************************************************/ 1.2574 + 1.2575 +#ifdef MOZ_XUL 1.2576 +nsTransparencyMode nsWindow::GetTransparencyMode() 1.2577 +{ 1.2578 + return GetTopLevelWindow(true)->GetWindowTranslucencyInner(); 1.2579 +} 1.2580 + 1.2581 +void nsWindow::SetTransparencyMode(nsTransparencyMode aMode) 1.2582 +{ 1.2583 + GetTopLevelWindow(true)->SetWindowTranslucencyInner(aMode); 1.2584 +} 1.2585 + 1.2586 +static const nsIntRegion 1.2587 +RegionFromArray(const nsTArray<nsIntRect>& aRects) 1.2588 +{ 1.2589 + nsIntRegion region; 1.2590 + for (uint32_t i = 0; i < aRects.Length(); ++i) { 1.2591 + region.Or(region, aRects[i]); 1.2592 + } 1.2593 + return region; 1.2594 +} 1.2595 + 1.2596 +void nsWindow::UpdateOpaqueRegion(const nsIntRegion &aOpaqueRegion) 1.2597 +{ 1.2598 + if (!HasGlass() || GetParent()) 1.2599 + return; 1.2600 + 1.2601 + // If there is no opaque region or hidechrome=true, set margins 1.2602 + // to support a full sheet of glass. Comments in MSDN indicate 1.2603 + // all values must be set to -1 to get a full sheet of glass. 1.2604 + MARGINS margins = { -1, -1, -1, -1 }; 1.2605 + if (!aOpaqueRegion.IsEmpty()) { 1.2606 + nsIntRect pluginBounds; 1.2607 + for (nsIWidget* child = GetFirstChild(); child; child = child->GetNextSibling()) { 1.2608 + if (child->WindowType() == eWindowType_plugin) { 1.2609 + // Collect the bounds of all plugins for GetLargestRectangle. 1.2610 + nsIntRect childBounds; 1.2611 + child->GetBounds(childBounds); 1.2612 + pluginBounds.UnionRect(pluginBounds, childBounds); 1.2613 + } 1.2614 + } 1.2615 + 1.2616 + nsIntRect clientBounds; 1.2617 + GetClientBounds(clientBounds); 1.2618 + 1.2619 + // Find the largest rectangle and use that to calculate the inset. Our top 1.2620 + // priority is to include the bounds of all plugins. 1.2621 + nsIntRect largest = aOpaqueRegion.GetLargestRectangle(pluginBounds); 1.2622 + margins.cxLeftWidth = largest.x; 1.2623 + margins.cxRightWidth = clientBounds.width - largest.XMost(); 1.2624 + margins.cyBottomHeight = clientBounds.height - largest.YMost(); 1.2625 + if (mCustomNonClient) { 1.2626 + // The minimum glass height must be the caption buttons height, 1.2627 + // otherwise the buttons are drawn incorrectly. 1.2628 + largest.y = std::max<uint32_t>(largest.y, 1.2629 + nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cy); 1.2630 + } 1.2631 + margins.cyTopHeight = largest.y; 1.2632 + } 1.2633 + 1.2634 + // Only update glass area if there are changes 1.2635 + if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) { 1.2636 + mGlassMargins = margins; 1.2637 + UpdateGlass(); 1.2638 + } 1.2639 +} 1.2640 + 1.2641 +void nsWindow::UpdateGlass() 1.2642 +{ 1.2643 + MARGINS margins = mGlassMargins; 1.2644 + 1.2645 + // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is 1.2646 + // rendered based on the window style. 1.2647 + // DWMNCRP_ENABLED - The non-client area rendering is 1.2648 + // enabled; the window style is ignored. 1.2649 + DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE; 1.2650 + switch (mTransparencyMode) { 1.2651 + case eTransparencyBorderlessGlass: 1.2652 + // Only adjust if there is some opaque rectangle 1.2653 + if (margins.cxLeftWidth >= 0) { 1.2654 + margins.cxLeftWidth += kGlassMarginAdjustment; 1.2655 + margins.cyTopHeight += kGlassMarginAdjustment; 1.2656 + margins.cxRightWidth += kGlassMarginAdjustment; 1.2657 + margins.cyBottomHeight += kGlassMarginAdjustment; 1.2658 + } 1.2659 + // Fall through 1.2660 + case eTransparencyGlass: 1.2661 + policy = DWMNCRP_ENABLED; 1.2662 + break; 1.2663 + } 1.2664 + 1.2665 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.2666 + ("glass margins: left:%d top:%d right:%d bottom:%d\n", 1.2667 + margins.cxLeftWidth, margins.cyTopHeight, 1.2668 + margins.cxRightWidth, margins.cyBottomHeight)); 1.2669 + 1.2670 + // Extends the window frame behind the client area 1.2671 + if (nsUXThemeData::CheckForCompositor()) { 1.2672 + WinUtils::dwmExtendFrameIntoClientAreaPtr(mWnd, &margins); 1.2673 + WinUtils::dwmSetWindowAttributePtr(mWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy); 1.2674 + } 1.2675 +} 1.2676 +#endif 1.2677 + 1.2678 +/************************************************************** 1.2679 + * 1.2680 + * SECTION: nsIWidget::HideWindowChrome 1.2681 + * 1.2682 + * Show or hide window chrome. 1.2683 + * 1.2684 + **************************************************************/ 1.2685 + 1.2686 +NS_IMETHODIMP nsWindow::HideWindowChrome(bool aShouldHide) 1.2687 +{ 1.2688 + HWND hwnd = WinUtils::GetTopLevelHWND(mWnd, true); 1.2689 + if (!WinUtils::GetNSWindowPtr(hwnd)) 1.2690 + { 1.2691 + NS_WARNING("Trying to hide window decorations in an embedded context"); 1.2692 + return NS_ERROR_FAILURE; 1.2693 + } 1.2694 + 1.2695 + if (mHideChrome == aShouldHide) 1.2696 + return NS_OK; 1.2697 + 1.2698 + DWORD_PTR style, exStyle; 1.2699 + mHideChrome = aShouldHide; 1.2700 + if (aShouldHide) { 1.2701 + DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE); 1.2702 + DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE); 1.2703 + 1.2704 + style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME); 1.2705 + exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | 1.2706 + WS_EX_CLIENTEDGE | WS_EX_STATICEDGE); 1.2707 + 1.2708 + mOldStyle = tempStyle; 1.2709 + mOldExStyle = tempExStyle; 1.2710 + } 1.2711 + else { 1.2712 + if (!mOldStyle || !mOldExStyle) { 1.2713 + mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE); 1.2714 + mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE); 1.2715 + } 1.2716 + 1.2717 + style = mOldStyle; 1.2718 + exStyle = mOldExStyle; 1.2719 + } 1.2720 + 1.2721 + VERIFY_WINDOW_STYLE(style); 1.2722 + ::SetWindowLongPtrW(hwnd, GWL_STYLE, style); 1.2723 + ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle); 1.2724 + 1.2725 + return NS_OK; 1.2726 +} 1.2727 + 1.2728 +/************************************************************** 1.2729 + * 1.2730 + * SECTION: nsWindow::Invalidate 1.2731 + * 1.2732 + * Invalidate an area of the client for painting. 1.2733 + * 1.2734 + **************************************************************/ 1.2735 + 1.2736 +// Invalidate this component visible area 1.2737 +NS_METHOD nsWindow::Invalidate(bool aEraseBackground, 1.2738 + bool aUpdateNCArea, 1.2739 + bool aIncludeChildren) 1.2740 +{ 1.2741 + if (!mWnd) { 1.2742 + return NS_OK; 1.2743 + } 1.2744 + 1.2745 +#ifdef WIDGET_DEBUG_OUTPUT 1.2746 + debug_DumpInvalidate(stdout, 1.2747 + this, 1.2748 + nullptr, 1.2749 + nsAutoCString("noname"), 1.2750 + (int32_t) mWnd); 1.2751 +#endif // WIDGET_DEBUG_OUTPUT 1.2752 + 1.2753 + DWORD flags = RDW_INVALIDATE; 1.2754 + if (aEraseBackground) { 1.2755 + flags |= RDW_ERASE; 1.2756 + } 1.2757 + if (aUpdateNCArea) { 1.2758 + flags |= RDW_FRAME; 1.2759 + } 1.2760 + if (aIncludeChildren) { 1.2761 + flags |= RDW_ALLCHILDREN; 1.2762 + } 1.2763 + 1.2764 + VERIFY(::RedrawWindow(mWnd, nullptr, nullptr, flags)); 1.2765 + return NS_OK; 1.2766 +} 1.2767 + 1.2768 +// Invalidate this component visible area 1.2769 +NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect) 1.2770 +{ 1.2771 + if (mWnd) 1.2772 + { 1.2773 +#ifdef WIDGET_DEBUG_OUTPUT 1.2774 + debug_DumpInvalidate(stdout, 1.2775 + this, 1.2776 + &aRect, 1.2777 + nsAutoCString("noname"), 1.2778 + (int32_t) mWnd); 1.2779 +#endif // WIDGET_DEBUG_OUTPUT 1.2780 + 1.2781 + RECT rect; 1.2782 + 1.2783 + rect.left = aRect.x; 1.2784 + rect.top = aRect.y; 1.2785 + rect.right = aRect.x + aRect.width; 1.2786 + rect.bottom = aRect.y + aRect.height; 1.2787 + 1.2788 + VERIFY(::InvalidateRect(mWnd, &rect, FALSE)); 1.2789 + } 1.2790 + return NS_OK; 1.2791 +} 1.2792 + 1.2793 +NS_IMETHODIMP 1.2794 +nsWindow::MakeFullScreen(bool aFullScreen) 1.2795 +{ 1.2796 + // taskbarInfo will be nullptr pre Windows 7 until Bug 680227 is resolved. 1.2797 + nsCOMPtr<nsIWinTaskbar> taskbarInfo = 1.2798 + do_GetService(NS_TASKBAR_CONTRACTID); 1.2799 + 1.2800 + mFullscreenMode = aFullScreen; 1.2801 + if (aFullScreen) { 1.2802 + if (mSizeMode == nsSizeMode_Fullscreen) 1.2803 + return NS_OK; 1.2804 + mOldSizeMode = mSizeMode; 1.2805 + SetSizeMode(nsSizeMode_Fullscreen); 1.2806 + 1.2807 + // Notify the taskbar that we will be entering full screen mode. 1.2808 + if (taskbarInfo) { 1.2809 + taskbarInfo->PrepareFullScreenHWND(mWnd, TRUE); 1.2810 + } 1.2811 + } else { 1.2812 + SetSizeMode(mOldSizeMode); 1.2813 + } 1.2814 + 1.2815 + UpdateNonClientMargins(); 1.2816 + 1.2817 + bool visible = mIsVisible; 1.2818 + if (mOldSizeMode == nsSizeMode_Normal) 1.2819 + Show(false); 1.2820 + 1.2821 + // Will call hide chrome, reposition window. Note this will 1.2822 + // also cache dimensions for restoration, so it should only 1.2823 + // be called once per fullscreen request. 1.2824 + nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen); 1.2825 + 1.2826 + if (visible) { 1.2827 + Show(true); 1.2828 + Invalidate(); 1.2829 + } 1.2830 + 1.2831 + // Notify the taskbar that we have exited full screen mode. 1.2832 + if (!aFullScreen && taskbarInfo) { 1.2833 + taskbarInfo->PrepareFullScreenHWND(mWnd, FALSE); 1.2834 + } 1.2835 + 1.2836 + if (mWidgetListener) 1.2837 + mWidgetListener->SizeModeChanged(mSizeMode); 1.2838 + 1.2839 + return rv; 1.2840 +} 1.2841 + 1.2842 +/************************************************************** 1.2843 + * 1.2844 + * SECTION: Native data storage 1.2845 + * 1.2846 + * nsIWidget::GetNativeData 1.2847 + * nsIWidget::FreeNativeData 1.2848 + * 1.2849 + * Set or clear native data based on a constant. 1.2850 + * 1.2851 + **************************************************************/ 1.2852 + 1.2853 +// Return some native data according to aDataType 1.2854 +void* nsWindow::GetNativeData(uint32_t aDataType) 1.2855 +{ 1.2856 + nsAutoString className; 1.2857 + switch (aDataType) { 1.2858 + case NS_NATIVE_TMP_WINDOW: 1.2859 + GetWindowClass(className); 1.2860 + return (void*)::CreateWindowExW(mIsRTL ? WS_EX_LAYOUTRTL : 0, 1.2861 + className.get(), 1.2862 + L"", 1.2863 + WS_CHILD, 1.2864 + CW_USEDEFAULT, 1.2865 + CW_USEDEFAULT, 1.2866 + CW_USEDEFAULT, 1.2867 + CW_USEDEFAULT, 1.2868 + mWnd, 1.2869 + nullptr, 1.2870 + nsToolkit::mDllInstance, 1.2871 + nullptr); 1.2872 + case NS_NATIVE_PLUGIN_PORT: 1.2873 + case NS_NATIVE_WIDGET: 1.2874 + case NS_NATIVE_WINDOW: 1.2875 + case NS_NATIVE_SHAREABLE_WINDOW: 1.2876 + return (void*)mWnd; 1.2877 + case NS_NATIVE_GRAPHIC: 1.2878 + // XXX: This is sleezy!! Remember to Release the DC after using it! 1.2879 +#ifdef MOZ_XUL 1.2880 + return (void*)(eTransparencyTransparent == mTransparencyMode) ? 1.2881 + mMemoryDC : ::GetDC(mWnd); 1.2882 +#else 1.2883 + return (void*)::GetDC(mWnd); 1.2884 +#endif 1.2885 + 1.2886 + case NS_NATIVE_TSF_THREAD_MGR: 1.2887 + case NS_NATIVE_TSF_CATEGORY_MGR: 1.2888 + case NS_NATIVE_TSF_DISPLAY_ATTR_MGR: 1.2889 + return IMEHandler::GetNativeData(aDataType); 1.2890 + 1.2891 + default: 1.2892 + break; 1.2893 + } 1.2894 + 1.2895 + return nullptr; 1.2896 +} 1.2897 + 1.2898 +// Free some native data according to aDataType 1.2899 +void nsWindow::FreeNativeData(void * data, uint32_t aDataType) 1.2900 +{ 1.2901 + switch (aDataType) 1.2902 + { 1.2903 + case NS_NATIVE_GRAPHIC: 1.2904 +#ifdef MOZ_XUL 1.2905 + if (eTransparencyTransparent != mTransparencyMode) 1.2906 + ::ReleaseDC(mWnd, (HDC)data); 1.2907 +#else 1.2908 + ::ReleaseDC(mWnd, (HDC)data); 1.2909 +#endif 1.2910 + break; 1.2911 + case NS_NATIVE_WIDGET: 1.2912 + case NS_NATIVE_WINDOW: 1.2913 + case NS_NATIVE_PLUGIN_PORT: 1.2914 + break; 1.2915 + default: 1.2916 + break; 1.2917 + } 1.2918 +} 1.2919 + 1.2920 +/************************************************************** 1.2921 + * 1.2922 + * SECTION: nsIWidget::SetTitle 1.2923 + * 1.2924 + * Set the main windows title text. 1.2925 + * 1.2926 + **************************************************************/ 1.2927 + 1.2928 +NS_METHOD nsWindow::SetTitle(const nsAString& aTitle) 1.2929 +{ 1.2930 + const nsString& strTitle = PromiseFlatString(aTitle); 1.2931 + ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get()); 1.2932 + return NS_OK; 1.2933 +} 1.2934 + 1.2935 +/************************************************************** 1.2936 + * 1.2937 + * SECTION: nsIWidget::SetIcon 1.2938 + * 1.2939 + * Set the main windows icon. 1.2940 + * 1.2941 + **************************************************************/ 1.2942 + 1.2943 +NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec) 1.2944 +{ 1.2945 + // Assume the given string is a local identifier for an icon file. 1.2946 + 1.2947 + nsCOMPtr<nsIFile> iconFile; 1.2948 + ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"), 1.2949 + getter_AddRefs(iconFile)); 1.2950 + if (!iconFile) 1.2951 + return NS_OK; // not an error if icon is not found 1.2952 + 1.2953 + nsAutoString iconPath; 1.2954 + iconFile->GetPath(iconPath); 1.2955 + 1.2956 + // XXX this should use MZLU (see bug 239279) 1.2957 + 1.2958 + ::SetLastError(0); 1.2959 + 1.2960 + HICON bigIcon = (HICON)::LoadImageW(nullptr, 1.2961 + (LPCWSTR)iconPath.get(), 1.2962 + IMAGE_ICON, 1.2963 + ::GetSystemMetrics(SM_CXICON), 1.2964 + ::GetSystemMetrics(SM_CYICON), 1.2965 + LR_LOADFROMFILE ); 1.2966 + HICON smallIcon = (HICON)::LoadImageW(nullptr, 1.2967 + (LPCWSTR)iconPath.get(), 1.2968 + IMAGE_ICON, 1.2969 + ::GetSystemMetrics(SM_CXSMICON), 1.2970 + ::GetSystemMetrics(SM_CYSMICON), 1.2971 + LR_LOADFROMFILE ); 1.2972 + 1.2973 + if (bigIcon) { 1.2974 + HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon); 1.2975 + if (icon) 1.2976 + ::DestroyIcon(icon); 1.2977 + mIconBig = bigIcon; 1.2978 + } 1.2979 +#ifdef DEBUG_SetIcon 1.2980 + else { 1.2981 + NS_LossyConvertUTF16toASCII cPath(iconPath); 1.2982 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.2983 + ("\nIcon load error; icon=%s, rc=0x%08X\n\n", 1.2984 + cPath.get(), ::GetLastError())); 1.2985 + } 1.2986 +#endif 1.2987 + if (smallIcon) { 1.2988 + HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon); 1.2989 + if (icon) 1.2990 + ::DestroyIcon(icon); 1.2991 + mIconSmall = smallIcon; 1.2992 + } 1.2993 +#ifdef DEBUG_SetIcon 1.2994 + else { 1.2995 + NS_LossyConvertUTF16toASCII cPath(iconPath); 1.2996 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.2997 + ("\nSmall icon load error; icon=%s, rc=0x%08X\n\n", 1.2998 + cPath.get(), ::GetLastError())); 1.2999 + } 1.3000 +#endif 1.3001 + return NS_OK; 1.3002 +} 1.3003 + 1.3004 +/************************************************************** 1.3005 + * 1.3006 + * SECTION: nsIWidget::WidgetToScreenOffset 1.3007 + * 1.3008 + * Return this widget's origin in screen coordinates. 1.3009 + * 1.3010 + **************************************************************/ 1.3011 + 1.3012 +nsIntPoint nsWindow::WidgetToScreenOffset() 1.3013 +{ 1.3014 + POINT point; 1.3015 + point.x = 0; 1.3016 + point.y = 0; 1.3017 + ::ClientToScreen(mWnd, &point); 1.3018 + return nsIntPoint(point.x, point.y); 1.3019 +} 1.3020 + 1.3021 +nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize) 1.3022 +{ 1.3023 + if (mWindowType == eWindowType_popup && !IsPopupWithTitleBar()) 1.3024 + return aClientSize; 1.3025 + 1.3026 + // just use (200, 200) as the position 1.3027 + RECT r; 1.3028 + r.left = 200; 1.3029 + r.top = 200; 1.3030 + r.right = 200 + aClientSize.width; 1.3031 + r.bottom = 200 + aClientSize.height; 1.3032 + ::AdjustWindowRectEx(&r, WindowStyle(), false, WindowExStyle()); 1.3033 + 1.3034 + return nsIntSize(r.right - r.left, r.bottom - r.top); 1.3035 +} 1.3036 + 1.3037 +/************************************************************** 1.3038 + * 1.3039 + * SECTION: nsIWidget::EnableDragDrop 1.3040 + * 1.3041 + * Enables/Disables drag and drop of files on this widget. 1.3042 + * 1.3043 + **************************************************************/ 1.3044 + 1.3045 +NS_METHOD nsWindow::EnableDragDrop(bool aEnable) 1.3046 +{ 1.3047 + NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()"); 1.3048 + 1.3049 + nsresult rv = NS_ERROR_FAILURE; 1.3050 + if (aEnable) { 1.3051 + if (nullptr == mNativeDragTarget) { 1.3052 + mNativeDragTarget = new nsNativeDragTarget(this); 1.3053 + if (nullptr != mNativeDragTarget) { 1.3054 + mNativeDragTarget->AddRef(); 1.3055 + if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) { 1.3056 + if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) { 1.3057 + rv = NS_OK; 1.3058 + } 1.3059 + } 1.3060 + } 1.3061 + } 1.3062 + } else { 1.3063 + if (nullptr != mWnd && nullptr != mNativeDragTarget) { 1.3064 + ::RevokeDragDrop(mWnd); 1.3065 + if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) { 1.3066 + rv = NS_OK; 1.3067 + } 1.3068 + mNativeDragTarget->DragCancel(); 1.3069 + NS_RELEASE(mNativeDragTarget); 1.3070 + } 1.3071 + } 1.3072 + return rv; 1.3073 +} 1.3074 + 1.3075 +/************************************************************** 1.3076 + * 1.3077 + * SECTION: nsIWidget::CaptureMouse 1.3078 + * 1.3079 + * Enables/Disables system mouse capture. 1.3080 + * 1.3081 + **************************************************************/ 1.3082 + 1.3083 +NS_METHOD nsWindow::CaptureMouse(bool aCapture) 1.3084 +{ 1.3085 + if (!nsToolkit::gMouseTrailer) { 1.3086 + NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed"); 1.3087 + return NS_OK; 1.3088 + } 1.3089 + 1.3090 + if (aCapture) { 1.3091 + nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd); 1.3092 + ::SetCapture(mWnd); 1.3093 + } else { 1.3094 + nsToolkit::gMouseTrailer->SetCaptureWindow(nullptr); 1.3095 + ::ReleaseCapture(); 1.3096 + } 1.3097 + sIsInMouseCapture = aCapture; 1.3098 + return NS_OK; 1.3099 +} 1.3100 + 1.3101 +/************************************************************** 1.3102 + * 1.3103 + * SECTION: nsIWidget::CaptureRollupEvents 1.3104 + * 1.3105 + * Dealing with event rollup on destroy for popups. Enables & 1.3106 + * Disables system capture of any and all events that would 1.3107 + * cause a dropdown to be rolled up. 1.3108 + * 1.3109 + **************************************************************/ 1.3110 + 1.3111 +NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener, 1.3112 + bool aDoCapture) 1.3113 +{ 1.3114 + if (aDoCapture) { 1.3115 + gRollupListener = aListener; 1.3116 + if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) { 1.3117 + RegisterSpecialDropdownHooks(); 1.3118 + } 1.3119 + sProcessHook = true; 1.3120 + } else { 1.3121 + gRollupListener = nullptr; 1.3122 + sProcessHook = false; 1.3123 + UnregisterSpecialDropdownHooks(); 1.3124 + } 1.3125 + 1.3126 + return NS_OK; 1.3127 +} 1.3128 + 1.3129 +/************************************************************** 1.3130 + * 1.3131 + * SECTION: nsIWidget::GetAttention 1.3132 + * 1.3133 + * Bring this window to the user's attention. 1.3134 + * 1.3135 + **************************************************************/ 1.3136 + 1.3137 +// Draw user's attention to this window until it comes to foreground. 1.3138 +NS_IMETHODIMP 1.3139 +nsWindow::GetAttention(int32_t aCycleCount) 1.3140 +{ 1.3141 + // Got window? 1.3142 + if (!mWnd) 1.3143 + return NS_ERROR_NOT_INITIALIZED; 1.3144 + 1.3145 + HWND flashWnd = WinUtils::GetTopLevelHWND(mWnd, false, false); 1.3146 + HWND fgWnd = ::GetForegroundWindow(); 1.3147 + // Don't flash if the flash count is 0 or if the foreground window is our 1.3148 + // window handle or that of our owned-most window. 1.3149 + if (aCycleCount == 0 || 1.3150 + flashWnd == fgWnd || 1.3151 + flashWnd == WinUtils::GetTopLevelHWND(fgWnd, false, false)) { 1.3152 + return NS_OK; 1.3153 + } 1.3154 + 1.3155 + DWORD defaultCycleCount = 0; 1.3156 + ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0); 1.3157 + 1.3158 + FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd, 1.3159 + FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 }; 1.3160 + ::FlashWindowEx(&flashInfo); 1.3161 + 1.3162 + return NS_OK; 1.3163 +} 1.3164 + 1.3165 +void nsWindow::StopFlashing() 1.3166 +{ 1.3167 + HWND flashWnd = mWnd; 1.3168 + while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) { 1.3169 + flashWnd = ownerWnd; 1.3170 + } 1.3171 + 1.3172 + FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd, 1.3173 + FLASHW_STOP, 0, 0 }; 1.3174 + ::FlashWindowEx(&flashInfo); 1.3175 +} 1.3176 + 1.3177 +/************************************************************** 1.3178 + * 1.3179 + * SECTION: nsIWidget::HasPendingInputEvent 1.3180 + * 1.3181 + * Ask whether there user input events pending. All input events are 1.3182 + * included, including those not targeted at this nsIwidget instance. 1.3183 + * 1.3184 + **************************************************************/ 1.3185 + 1.3186 +bool 1.3187 +nsWindow::HasPendingInputEvent() 1.3188 +{ 1.3189 + // If there is pending input or the user is currently 1.3190 + // moving the window then return true. 1.3191 + // Note: When the user is moving the window WIN32 spins 1.3192 + // a separate event loop and input events are not 1.3193 + // reported to the application. 1.3194 + if (HIWORD(GetQueueStatus(QS_INPUT))) 1.3195 + return true; 1.3196 + GUITHREADINFO guiInfo; 1.3197 + guiInfo.cbSize = sizeof(GUITHREADINFO); 1.3198 + if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo)) 1.3199 + return false; 1.3200 + return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE); 1.3201 +} 1.3202 + 1.3203 +/************************************************************** 1.3204 + * 1.3205 + * SECTION: nsIWidget::GetLayerManager 1.3206 + * 1.3207 + * Get the layer manager associated with this widget. 1.3208 + * 1.3209 + **************************************************************/ 1.3210 + 1.3211 +struct LayerManagerPrefs { 1.3212 + LayerManagerPrefs() 1.3213 + : mAccelerateByDefault(true) 1.3214 + , mDisableAcceleration(false) 1.3215 + , mPreferOpenGL(false) 1.3216 + , mPreferD3D9(false) 1.3217 + {} 1.3218 + bool mAccelerateByDefault; 1.3219 + bool mDisableAcceleration; 1.3220 + bool mForceAcceleration; 1.3221 + bool mPreferOpenGL; 1.3222 + bool mPreferD3D9; 1.3223 +}; 1.3224 + 1.3225 +static void 1.3226 +GetLayerManagerPrefs(LayerManagerPrefs* aManagerPrefs) 1.3227 +{ 1.3228 + Preferences::GetBool("layers.acceleration.disabled", 1.3229 + &aManagerPrefs->mDisableAcceleration); 1.3230 + Preferences::GetBool("layers.acceleration.force-enabled", 1.3231 + &aManagerPrefs->mForceAcceleration); 1.3232 + Preferences::GetBool("layers.prefer-opengl", 1.3233 + &aManagerPrefs->mPreferOpenGL); 1.3234 + Preferences::GetBool("layers.prefer-d3d9", 1.3235 + &aManagerPrefs->mPreferD3D9); 1.3236 + 1.3237 + const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED"); 1.3238 + aManagerPrefs->mAccelerateByDefault = 1.3239 + aManagerPrefs->mAccelerateByDefault || 1.3240 + (acceleratedEnv && (*acceleratedEnv != '0')); 1.3241 + 1.3242 + bool safeMode = false; 1.3243 + nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1"); 1.3244 + if (xr) 1.3245 + xr->GetInSafeMode(&safeMode); 1.3246 + aManagerPrefs->mDisableAcceleration = 1.3247 + aManagerPrefs->mDisableAcceleration || safeMode; 1.3248 +} 1.3249 + 1.3250 +LayerManager* 1.3251 +nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager, 1.3252 + LayersBackend aBackendHint, 1.3253 + LayerManagerPersistence aPersistence, 1.3254 + bool* aAllowRetaining) 1.3255 +{ 1.3256 + if (aAllowRetaining) { 1.3257 + *aAllowRetaining = true; 1.3258 + } 1.3259 + 1.3260 +#ifdef MOZ_ENABLE_D3D10_LAYER 1.3261 + if (mLayerManager) { 1.3262 + if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_D3D10) 1.3263 + { 1.3264 + LayerManagerD3D10 *layerManagerD3D10 = 1.3265 + static_cast<LayerManagerD3D10*>(mLayerManager.get()); 1.3266 + if (layerManagerD3D10->device() != 1.3267 + gfxWindowsPlatform::GetPlatform()->GetD3D10Device()) 1.3268 + { 1.3269 + MOZ_ASSERT(!mLayerManager->IsInTransaction()); 1.3270 + 1.3271 + mLayerManager->Destroy(); 1.3272 + mLayerManager = nullptr; 1.3273 + } 1.3274 + } 1.3275 + } 1.3276 +#endif 1.3277 + 1.3278 + RECT windowRect; 1.3279 + ::GetClientRect(mWnd, &windowRect); 1.3280 + 1.3281 + // Try OMTC first. 1.3282 + if (!mLayerManager && ShouldUseOffMainThreadCompositing()) { 1.3283 + // e10s uses the parameter to pass in the shadow manager from the TabChild 1.3284 + // so we don't expect to see it there since this doesn't support e10s. 1.3285 + NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s"); 1.3286 + CreateCompositor(); 1.3287 + } 1.3288 + 1.3289 + if (!mLayerManager || 1.3290 + (!sAllowD3D9 && aPersistence == LAYER_MANAGER_PERSISTENT && 1.3291 + mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC && 1.3292 + !ShouldUseOffMainThreadCompositing())) { 1.3293 + // If D3D9 is not currently allowed but the permanent manager is required, 1.3294 + // -and- we're currently using basic layers, run through this check. 1.3295 + LayerManagerPrefs prefs; 1.3296 + GetLayerManagerPrefs(&prefs); 1.3297 + 1.3298 + /* We don't currently support using an accelerated layer manager with 1.3299 + * transparent windows so don't even try. I'm also not sure if we even 1.3300 + * want to support this case. See bug #593471 */ 1.3301 + if (eTransparencyTransparent == mTransparencyMode || 1.3302 + prefs.mDisableAcceleration || 1.3303 + windowRect.right - windowRect.left > MAX_ACCELERATED_DIMENSION || 1.3304 + windowRect.bottom - windowRect.top > MAX_ACCELERATED_DIMENSION) 1.3305 + mUseLayersAcceleration = false; 1.3306 + else if (prefs.mAccelerateByDefault) 1.3307 + mUseLayersAcceleration = true; 1.3308 + 1.3309 + if (mUseLayersAcceleration) { 1.3310 + if (aPersistence == LAYER_MANAGER_PERSISTENT && !sAllowD3D9) { 1.3311 + MOZ_ASSERT(!mLayerManager || !mLayerManager->IsInTransaction()); 1.3312 + 1.3313 + // This will clear out our existing layer manager if we have one since 1.3314 + // if we hit this with a LayerManager we're always using BasicLayers. 1.3315 + nsToolkit::StartAllowingD3D9(); 1.3316 + } 1.3317 + 1.3318 +#ifdef MOZ_ENABLE_D3D10_LAYER 1.3319 + if (!prefs.mPreferD3D9 && !prefs.mPreferOpenGL) { 1.3320 + nsRefPtr<LayerManagerD3D10> layerManager = 1.3321 + new LayerManagerD3D10(this); 1.3322 + if (layerManager->Initialize(prefs.mForceAcceleration)) { 1.3323 + mLayerManager = layerManager; 1.3324 + } 1.3325 + } 1.3326 +#endif 1.3327 +#ifdef MOZ_ENABLE_D3D9_LAYER 1.3328 + if (!prefs.mPreferOpenGL && !mLayerManager && sAllowD3D9) { 1.3329 + nsRefPtr<LayerManagerD3D9> layerManager = 1.3330 + new LayerManagerD3D9(this); 1.3331 + if (layerManager->Initialize(prefs.mForceAcceleration)) { 1.3332 + mLayerManager = layerManager; 1.3333 + } 1.3334 + } 1.3335 +#endif 1.3336 + } 1.3337 + 1.3338 + // Fall back to software if we couldn't use any hardware backends. 1.3339 + if (!mLayerManager) { 1.3340 + mLayerManager = CreateBasicLayerManager(); 1.3341 + } 1.3342 + } 1.3343 + 1.3344 + NS_ASSERTION(mLayerManager, "Couldn't provide a valid layer manager."); 1.3345 + 1.3346 + return mLayerManager; 1.3347 +} 1.3348 + 1.3349 +/************************************************************** 1.3350 + * 1.3351 + * SECTION: nsIWidget::GetThebesSurface 1.3352 + * 1.3353 + * Get the Thebes surface associated with this widget. 1.3354 + * 1.3355 + **************************************************************/ 1.3356 + 1.3357 +gfxASurface *nsWindow::GetThebesSurface() 1.3358 +{ 1.3359 + if (mPaintDC) 1.3360 + return (new gfxWindowsSurface(mPaintDC)); 1.3361 + 1.3362 + uint32_t flags = gfxWindowsSurface::FLAG_TAKE_DC; 1.3363 + if (mTransparencyMode != eTransparencyOpaque) { 1.3364 + flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT; 1.3365 + } 1.3366 + return (new gfxWindowsSurface(mWnd, flags)); 1.3367 +} 1.3368 + 1.3369 +/************************************************************** 1.3370 + * 1.3371 + * SECTION: nsIWidget::OnDefaultButtonLoaded 1.3372 + * 1.3373 + * Called after the dialog is loaded and it has a default button. 1.3374 + * 1.3375 + **************************************************************/ 1.3376 + 1.3377 +NS_IMETHODIMP 1.3378 +nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect) 1.3379 +{ 1.3380 + if (aButtonRect.IsEmpty()) 1.3381 + return NS_OK; 1.3382 + 1.3383 + // Don't snap when we are not active. 1.3384 + HWND activeWnd = ::GetActiveWindow(); 1.3385 + if (activeWnd != ::GetForegroundWindow() || 1.3386 + WinUtils::GetTopLevelHWND(mWnd, true) != 1.3387 + WinUtils::GetTopLevelHWND(activeWnd, true)) { 1.3388 + return NS_OK; 1.3389 + } 1.3390 + 1.3391 + bool isAlwaysSnapCursor = 1.3392 + Preferences::GetBool("ui.cursor_snapping.always_enabled", false); 1.3393 + 1.3394 + if (!isAlwaysSnapCursor) { 1.3395 + BOOL snapDefaultButton; 1.3396 + if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0, 1.3397 + &snapDefaultButton, 0) || !snapDefaultButton) 1.3398 + return NS_OK; 1.3399 + } 1.3400 + 1.3401 + nsIntRect widgetRect; 1.3402 + nsresult rv = GetScreenBounds(widgetRect); 1.3403 + NS_ENSURE_SUCCESS(rv, rv); 1.3404 + nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft()); 1.3405 + 1.3406 + nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2, 1.3407 + buttonRect.y + buttonRect.height / 2); 1.3408 + // The center of the button can be outside of the widget. 1.3409 + // E.g., it could be hidden by scrolling. 1.3410 + if (!widgetRect.Contains(centerOfButton)) { 1.3411 + return NS_OK; 1.3412 + } 1.3413 + 1.3414 + if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) { 1.3415 + NS_ERROR("SetCursorPos failed"); 1.3416 + return NS_ERROR_FAILURE; 1.3417 + } 1.3418 + return NS_OK; 1.3419 +} 1.3420 + 1.3421 +NS_IMETHODIMP 1.3422 +nsWindow::OverrideSystemMouseScrollSpeed(double aOriginalDeltaX, 1.3423 + double aOriginalDeltaY, 1.3424 + double& aOverriddenDeltaX, 1.3425 + double& aOverriddenDeltaY) 1.3426 +{ 1.3427 + // The default vertical and horizontal scrolling speed is 3, this is defined 1.3428 + // on the document of SystemParametersInfo in MSDN. 1.3429 + const uint32_t kSystemDefaultScrollingSpeed = 3; 1.3430 + 1.3431 + double absOriginDeltaX = Abs(aOriginalDeltaX); 1.3432 + double absOriginDeltaY = Abs(aOriginalDeltaY); 1.3433 + 1.3434 + // Compute the simple overridden speed. 1.3435 + double absComputedOverriddenDeltaX, absComputedOverriddenDeltaY; 1.3436 + nsresult rv = 1.3437 + nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDeltaX, 1.3438 + absOriginDeltaY, 1.3439 + absComputedOverriddenDeltaX, 1.3440 + absComputedOverriddenDeltaY); 1.3441 + NS_ENSURE_SUCCESS(rv, rv); 1.3442 + 1.3443 + aOverriddenDeltaX = aOriginalDeltaX; 1.3444 + aOverriddenDeltaY = aOriginalDeltaY; 1.3445 + 1.3446 + if (absComputedOverriddenDeltaX == absOriginDeltaX && 1.3447 + absComputedOverriddenDeltaY == absOriginDeltaY) { 1.3448 + // We don't override now. 1.3449 + return NS_OK; 1.3450 + } 1.3451 + 1.3452 + // Otherwise, we should check whether the user customized the system settings 1.3453 + // or not. If the user did it, we should respect the will. 1.3454 + UINT systemSpeed; 1.3455 + if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) { 1.3456 + return NS_ERROR_FAILURE; 1.3457 + } 1.3458 + // The default vertical scrolling speed is 3, this is defined on the document 1.3459 + // of SystemParametersInfo in MSDN. 1.3460 + if (systemSpeed != kSystemDefaultScrollingSpeed) { 1.3461 + return NS_OK; 1.3462 + } 1.3463 + 1.3464 + // Only Vista and later, Windows has the system setting of horizontal 1.3465 + // scrolling by the mouse wheel. 1.3466 + if (IsVistaOrLater()) { 1.3467 + if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) { 1.3468 + return NS_ERROR_FAILURE; 1.3469 + } 1.3470 + // The default horizontal scrolling speed is 3, this is defined on the 1.3471 + // document of SystemParametersInfo in MSDN. 1.3472 + if (systemSpeed != kSystemDefaultScrollingSpeed) { 1.3473 + return NS_OK; 1.3474 + } 1.3475 + } 1.3476 + 1.3477 + // Limit the overridden delta value from the system settings. The mouse 1.3478 + // driver might accelerate the scrolling speed already. If so, we shouldn't 1.3479 + // override the scrolling speed for preventing the unexpected high speed 1.3480 + // scrolling. 1.3481 + double absDeltaLimitX, absDeltaLimitY; 1.3482 + rv = 1.3483 + nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed, 1.3484 + kSystemDefaultScrollingSpeed, 1.3485 + absDeltaLimitX, 1.3486 + absDeltaLimitY); 1.3487 + NS_ENSURE_SUCCESS(rv, rv); 1.3488 + 1.3489 + // If the given delta is larger than our computed limitation value, the delta 1.3490 + // was accelerated by the mouse driver. So, we should do nothing here. 1.3491 + if (absDeltaLimitX <= absOriginDeltaX || absDeltaLimitY <= absOriginDeltaY) { 1.3492 + return NS_OK; 1.3493 + } 1.3494 + 1.3495 + aOverriddenDeltaX = std::min(absComputedOverriddenDeltaX, absDeltaLimitX); 1.3496 + aOverriddenDeltaY = std::min(absComputedOverriddenDeltaY, absDeltaLimitY); 1.3497 + 1.3498 + if (aOriginalDeltaX < 0) { 1.3499 + aOverriddenDeltaX *= -1; 1.3500 + } 1.3501 + if (aOriginalDeltaY < 0) { 1.3502 + aOverriddenDeltaY *= -1; 1.3503 + } 1.3504 + return NS_OK; 1.3505 +} 1.3506 + 1.3507 +mozilla::TemporaryRef<mozilla::gfx::DrawTarget> 1.3508 +nsWindow::StartRemoteDrawing() 1.3509 +{ 1.3510 + MOZ_ASSERT(!mCompositeDC); 1.3511 + NS_ASSERTION(IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D) || 1.3512 + IsRenderMode(gfxWindowsPlatform::RENDER_GDI), 1.3513 + "Unexpected render mode for remote drawing"); 1.3514 + 1.3515 + HDC dc = (HDC)GetNativeData(NS_NATIVE_GRAPHIC); 1.3516 + nsRefPtr<gfxASurface> surf; 1.3517 + 1.3518 + if (mTransparencyMode == eTransparencyTransparent) { 1.3519 + if (!mTransparentSurface) { 1.3520 + SetupTranslucentWindowMemoryBitmap(mTransparencyMode); 1.3521 + } 1.3522 + if (mTransparentSurface) { 1.3523 + surf = mTransparentSurface; 1.3524 + } 1.3525 + } 1.3526 + 1.3527 + if (!surf) { 1.3528 + if (!dc) { 1.3529 + return nullptr; 1.3530 + } 1.3531 + uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 : 1.3532 + gfxWindowsSurface::FLAG_IS_TRANSPARENT; 1.3533 + surf = new gfxWindowsSurface(dc, flags); 1.3534 + } 1.3535 + 1.3536 + mozilla::gfx::IntSize size(surf->GetSize().width, surf->GetSize().height); 1.3537 + if (size.width <= 0 || size.height <= 0) { 1.3538 + if (dc) { 1.3539 + FreeNativeData(dc, NS_NATIVE_GRAPHIC); 1.3540 + } 1.3541 + return nullptr; 1.3542 + } 1.3543 + 1.3544 + MOZ_ASSERT(!mCompositeDC); 1.3545 + mCompositeDC = dc; 1.3546 + 1.3547 + return mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(surf->CairoSurface(), size); 1.3548 +} 1.3549 + 1.3550 +void 1.3551 +nsWindow::EndRemoteDrawing() 1.3552 +{ 1.3553 + if (mTransparencyMode == eTransparencyTransparent) { 1.3554 + MOZ_ASSERT(IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D) 1.3555 + || mTransparentSurface); 1.3556 + UpdateTranslucentWindow(); 1.3557 + } 1.3558 + if (mCompositeDC) { 1.3559 + FreeNativeData(mCompositeDC, NS_NATIVE_GRAPHIC); 1.3560 + } 1.3561 + mCompositeDC = nullptr; 1.3562 +} 1.3563 + 1.3564 +void 1.3565 +nsWindow::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) 1.3566 +{ 1.3567 + nsIntRegion clearRegion; 1.3568 + for (size_t i = 0; i < aThemeGeometries.Length(); i++) { 1.3569 + if ((aThemeGeometries[i].mWidgetType == NS_THEME_WINDOW_BUTTON_BOX || 1.3570 + aThemeGeometries[i].mWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) && 1.3571 + nsUXThemeData::CheckForCompositor()) 1.3572 + { 1.3573 + nsIntRect bounds = aThemeGeometries[i].mRect; 1.3574 + clearRegion = nsIntRect(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height() - 2.0); 1.3575 + clearRegion.Or(clearRegion, nsIntRect(bounds.X() + 1.0, bounds.YMost() - 2.0, bounds.Width() - 1.0, 1.0)); 1.3576 + clearRegion.Or(clearRegion, nsIntRect(bounds.X() + 2.0, bounds.YMost() - 1.0, bounds.Width() - 3.0, 1.0)); 1.3577 + } 1.3578 + } 1.3579 + 1.3580 + nsRefPtr<LayerManager> layerManager = GetLayerManager(); 1.3581 + if (layerManager) { 1.3582 + layerManager->SetRegionToClear(clearRegion); 1.3583 + } 1.3584 +} 1.3585 + 1.3586 +/************************************************************** 1.3587 + ************************************************************** 1.3588 + ** 1.3589 + ** BLOCK: Moz Events 1.3590 + ** 1.3591 + ** Moz GUI event management. 1.3592 + ** 1.3593 + ************************************************************** 1.3594 + **************************************************************/ 1.3595 + 1.3596 +/************************************************************** 1.3597 + * 1.3598 + * SECTION: Mozilla event initialization 1.3599 + * 1.3600 + * Helpers for initializing moz events. 1.3601 + * 1.3602 + **************************************************************/ 1.3603 + 1.3604 +// Event intialization 1.3605 +void nsWindow::InitEvent(WidgetGUIEvent& event, nsIntPoint* aPoint) 1.3606 +{ 1.3607 + if (nullptr == aPoint) { // use the point from the event 1.3608 + // get the message position in client coordinates 1.3609 + if (mWnd != nullptr) { 1.3610 + 1.3611 + DWORD pos = ::GetMessagePos(); 1.3612 + POINT cpos; 1.3613 + 1.3614 + cpos.x = GET_X_LPARAM(pos); 1.3615 + cpos.y = GET_Y_LPARAM(pos); 1.3616 + 1.3617 + ::ScreenToClient(mWnd, &cpos); 1.3618 + event.refPoint.x = cpos.x; 1.3619 + event.refPoint.y = cpos.y; 1.3620 + } else { 1.3621 + event.refPoint.x = 0; 1.3622 + event.refPoint.y = 0; 1.3623 + } 1.3624 + } 1.3625 + else { 1.3626 + // use the point override if provided 1.3627 + event.refPoint.x = aPoint->x; 1.3628 + event.refPoint.y = aPoint->y; 1.3629 + } 1.3630 + 1.3631 + event.time = ::GetMessageTime(); 1.3632 +} 1.3633 + 1.3634 +/************************************************************** 1.3635 + * 1.3636 + * SECTION: Moz event dispatch helpers 1.3637 + * 1.3638 + * Helpers for dispatching different types of moz events. 1.3639 + * 1.3640 + **************************************************************/ 1.3641 + 1.3642 +// Main event dispatch. Invokes callback and ProcessEvent method on 1.3643 +// Event Listener object. Part of nsIWidget. 1.3644 +NS_IMETHODIMP nsWindow::DispatchEvent(WidgetGUIEvent* event, 1.3645 + nsEventStatus& aStatus) 1.3646 +{ 1.3647 +#ifdef WIDGET_DEBUG_OUTPUT 1.3648 + debug_DumpEvent(stdout, 1.3649 + event->widget, 1.3650 + event, 1.3651 + nsAutoCString("something"), 1.3652 + (int32_t) mWnd); 1.3653 +#endif // WIDGET_DEBUG_OUTPUT 1.3654 + 1.3655 + aStatus = nsEventStatus_eIgnore; 1.3656 + 1.3657 + // Top level windows can have a view attached which requires events be sent 1.3658 + // to the underlying base window and the view. Added when we combined the 1.3659 + // base chrome window with the main content child for nc client area (title 1.3660 + // bar) rendering. 1.3661 + if (mAttachedWidgetListener) { 1.3662 + aStatus = mAttachedWidgetListener->HandleEvent(event, mUseAttachedEvents); 1.3663 + } 1.3664 + else if (mWidgetListener) { 1.3665 + aStatus = mWidgetListener->HandleEvent(event, mUseAttachedEvents); 1.3666 + } 1.3667 + 1.3668 + // the window can be destroyed during processing of seemingly innocuous events like, say, 1.3669 + // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore, 1.3670 + // which causes problems with the deleted window. therefore: 1.3671 + if (mOnDestroyCalled) 1.3672 + aStatus = nsEventStatus_eConsumeNoDefault; 1.3673 + return NS_OK; 1.3674 +} 1.3675 + 1.3676 +bool nsWindow::DispatchStandardEvent(uint32_t aMsg) 1.3677 +{ 1.3678 + WidgetGUIEvent event(true, aMsg, this); 1.3679 + InitEvent(event); 1.3680 + 1.3681 + bool result = DispatchWindowEvent(&event); 1.3682 + return result; 1.3683 +} 1.3684 + 1.3685 +bool nsWindow::DispatchKeyboardEvent(WidgetGUIEvent* event) 1.3686 +{ 1.3687 + nsEventStatus status; 1.3688 + DispatchEvent(event, status); 1.3689 + return ConvertStatus(status); 1.3690 +} 1.3691 + 1.3692 +bool nsWindow::DispatchScrollEvent(WidgetGUIEvent* event) 1.3693 +{ 1.3694 + nsEventStatus status; 1.3695 + DispatchEvent(event, status); 1.3696 + return ConvertStatus(status); 1.3697 +} 1.3698 + 1.3699 +bool nsWindow::DispatchWindowEvent(WidgetGUIEvent* event) 1.3700 +{ 1.3701 + nsEventStatus status; 1.3702 + DispatchEvent(event, status); 1.3703 + return ConvertStatus(status); 1.3704 +} 1.3705 + 1.3706 +bool nsWindow::DispatchWindowEvent(WidgetGUIEvent* event, 1.3707 + nsEventStatus& aStatus) 1.3708 +{ 1.3709 + DispatchEvent(event, aStatus); 1.3710 + return ConvertStatus(aStatus); 1.3711 +} 1.3712 + 1.3713 +// Recursively dispatch synchronous paints for nsIWidget 1.3714 +// descendants with invalidated rectangles. 1.3715 +BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg) 1.3716 +{ 1.3717 + LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC); 1.3718 + if (proc == (LONG_PTR)&nsWindow::WindowProc) { 1.3719 + // its one of our windows so check to see if it has a 1.3720 + // invalidated rect. If it does. Dispatch a synchronous 1.3721 + // paint. 1.3722 + if (GetUpdateRect(aWnd, nullptr, FALSE)) 1.3723 + VERIFY(::UpdateWindow(aWnd)); 1.3724 + } 1.3725 + return TRUE; 1.3726 +} 1.3727 + 1.3728 +// Check for pending paints and dispatch any pending paint 1.3729 +// messages for any nsIWidget which is a descendant of the 1.3730 +// top-level window that *this* window is embedded within. 1.3731 +// 1.3732 +// Note: We do not dispatch pending paint messages for non 1.3733 +// nsIWidget managed windows. 1.3734 +void nsWindow::DispatchPendingEvents() 1.3735 +{ 1.3736 + if (mPainting) { 1.3737 + NS_WARNING("We were asked to dispatch pending events during painting, " 1.3738 + "denying since that's unsafe."); 1.3739 + return; 1.3740 + } 1.3741 + 1.3742 + // We need to ensure that reflow events do not get starved. 1.3743 + // At the same time, we don't want to recurse through here 1.3744 + // as that would prevent us from dispatching starved paints. 1.3745 + static int recursionBlocker = 0; 1.3746 + if (recursionBlocker++ == 0) { 1.3747 + NS_ProcessPendingEvents(nullptr, PR_MillisecondsToInterval(100)); 1.3748 + --recursionBlocker; 1.3749 + } 1.3750 + 1.3751 + // Quickly check to see if there are any paint events pending, 1.3752 + // but only dispatch them if it has been long enough since the 1.3753 + // last paint completed. 1.3754 + if (::GetQueueStatus(QS_PAINT) && 1.3755 + ((TimeStamp::Now() - mLastPaintEndTime).ToMilliseconds() >= 50)) { 1.3756 + // Find the top level window. 1.3757 + HWND topWnd = WinUtils::GetTopLevelHWND(mWnd); 1.3758 + 1.3759 + // Dispatch pending paints for topWnd and all its descendant windows. 1.3760 + // Note: EnumChildWindows enumerates all descendant windows not just 1.3761 + // the children (but not the window itself). 1.3762 + nsWindow::DispatchStarvedPaints(topWnd, 0); 1.3763 + ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, 0); 1.3764 + } 1.3765 +} 1.3766 + 1.3767 +bool nsWindow::DispatchPluginEvent(UINT aMessage, 1.3768 + WPARAM aWParam, 1.3769 + LPARAM aLParam, 1.3770 + bool aDispatchPendingEvents) 1.3771 +{ 1.3772 + bool ret = nsWindowBase::DispatchPluginEvent( 1.3773 + WinUtils::InitMSG(aMessage, aWParam, aLParam, mWnd)); 1.3774 + if (aDispatchPendingEvents && !Destroyed()) { 1.3775 + DispatchPendingEvents(); 1.3776 + } 1.3777 + return ret; 1.3778 +} 1.3779 + 1.3780 +// Deal with all sort of mouse event 1.3781 +bool nsWindow::DispatchMouseEvent(uint32_t aEventType, WPARAM wParam, 1.3782 + LPARAM lParam, bool aIsContextMenuKey, 1.3783 + int16_t aButton, uint16_t aInputSource) 1.3784 +{ 1.3785 + bool result = false; 1.3786 + 1.3787 + UserActivity(); 1.3788 + 1.3789 + if (!mWidgetListener) { 1.3790 + return result; 1.3791 + } 1.3792 + 1.3793 + switch (aEventType) { 1.3794 + case NS_MOUSE_BUTTON_DOWN: 1.3795 + CaptureMouse(true); 1.3796 + break; 1.3797 + 1.3798 + // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag 1.3799 + // isn't left on after a drag where we wouldn't see a button up message (see bug 324131). 1.3800 + case NS_MOUSE_BUTTON_UP: 1.3801 + case NS_MOUSE_MOVE: 1.3802 + case NS_MOUSE_EXIT: 1.3803 + if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && sIsInMouseCapture) 1.3804 + CaptureMouse(false); 1.3805 + break; 1.3806 + 1.3807 + default: 1.3808 + break; 1.3809 + 1.3810 + } // switch 1.3811 + 1.3812 + nsIntPoint eventPoint; 1.3813 + eventPoint.x = GET_X_LPARAM(lParam); 1.3814 + eventPoint.y = GET_Y_LPARAM(lParam); 1.3815 + 1.3816 + WidgetMouseEvent event(true, aEventType, this, WidgetMouseEvent::eReal, 1.3817 + aIsContextMenuKey ? WidgetMouseEvent::eContextMenuKey : 1.3818 + WidgetMouseEvent::eNormal); 1.3819 + if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) { 1.3820 + nsIntPoint zero(0, 0); 1.3821 + InitEvent(event, &zero); 1.3822 + } else { 1.3823 + InitEvent(event, &eventPoint); 1.3824 + } 1.3825 + 1.3826 + ModifierKeyState modifierKeyState; 1.3827 + modifierKeyState.InitInputEvent(event); 1.3828 + event.button = aButton; 1.3829 + event.inputSource = aInputSource; 1.3830 + // Convert Mouse events generated by pen device or if mouse not generated from touch 1.3831 + event.convertToPointer = 1.3832 + aInputSource == nsIDOMMouseEvent::MOZ_SOURCE_PEN || 1.3833 + !(WinUtils::GetIsMouseFromTouch(aEventType) && mTouchWindow); 1.3834 + 1.3835 + nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset(); 1.3836 + 1.3837 + // Suppress mouse moves caused by widget creation 1.3838 + if (aEventType == NS_MOUSE_MOVE) 1.3839 + { 1.3840 + if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y)) 1.3841 + return result; 1.3842 + sLastMouseMovePoint.x = mpScreen.x; 1.3843 + sLastMouseMovePoint.y = mpScreen.y; 1.3844 + } 1.3845 + 1.3846 + bool insideMovementThreshold = (DeprecatedAbs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) && 1.3847 + (DeprecatedAbs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK)); 1.3848 + 1.3849 + BYTE eventButton; 1.3850 + switch (aButton) { 1.3851 + case WidgetMouseEvent::eLeftButton: 1.3852 + eventButton = VK_LBUTTON; 1.3853 + break; 1.3854 + case WidgetMouseEvent::eMiddleButton: 1.3855 + eventButton = VK_MBUTTON; 1.3856 + break; 1.3857 + case WidgetMouseEvent::eRightButton: 1.3858 + eventButton = VK_RBUTTON; 1.3859 + break; 1.3860 + default: 1.3861 + eventButton = 0; 1.3862 + break; 1.3863 + } 1.3864 + 1.3865 + // Doubleclicks are used to set the click count, then changed to mousedowns 1.3866 + // We're going to time double-clicks from mouse *up* to next mouse *down* 1.3867 + LONG curMsgTime = ::GetMessageTime(); 1.3868 + 1.3869 + if (aEventType == NS_MOUSE_DOUBLECLICK) { 1.3870 + event.message = NS_MOUSE_BUTTON_DOWN; 1.3871 + event.button = aButton; 1.3872 + sLastClickCount = 2; 1.3873 + } 1.3874 + else if (aEventType == NS_MOUSE_BUTTON_UP) { 1.3875 + // remember when this happened for the next mouse down 1.3876 + sLastMousePoint.x = eventPoint.x; 1.3877 + sLastMousePoint.y = eventPoint.y; 1.3878 + sLastMouseButton = eventButton; 1.3879 + } 1.3880 + else if (aEventType == NS_MOUSE_BUTTON_DOWN) { 1.3881 + // now look to see if we want to convert this to a double- or triple-click 1.3882 + if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold && 1.3883 + eventButton == sLastMouseButton) { 1.3884 + sLastClickCount ++; 1.3885 + } else { 1.3886 + // reset the click count, to count *this* click 1.3887 + sLastClickCount = 1; 1.3888 + } 1.3889 + // Set last Click time on MouseDown only 1.3890 + sLastMouseDownTime = curMsgTime; 1.3891 + } 1.3892 + else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) { 1.3893 + sLastClickCount = 0; 1.3894 + } 1.3895 + else if (aEventType == NS_MOUSE_EXIT) { 1.3896 + event.exit = IsTopLevelMouseExit(mWnd) ? 1.3897 + WidgetMouseEvent::eTopLevel : WidgetMouseEvent::eChild; 1.3898 + } 1.3899 + event.clickCount = sLastClickCount; 1.3900 + 1.3901 +#ifdef NS_DEBUG_XX 1.3902 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.3903 + ("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount)); 1.3904 +#endif 1.3905 + 1.3906 + NPEvent pluginEvent; 1.3907 + 1.3908 + switch (aEventType) 1.3909 + { 1.3910 + case NS_MOUSE_BUTTON_DOWN: 1.3911 + switch (aButton) { 1.3912 + case WidgetMouseEvent::eLeftButton: 1.3913 + pluginEvent.event = WM_LBUTTONDOWN; 1.3914 + break; 1.3915 + case WidgetMouseEvent::eMiddleButton: 1.3916 + pluginEvent.event = WM_MBUTTONDOWN; 1.3917 + break; 1.3918 + case WidgetMouseEvent::eRightButton: 1.3919 + pluginEvent.event = WM_RBUTTONDOWN; 1.3920 + break; 1.3921 + default: 1.3922 + break; 1.3923 + } 1.3924 + break; 1.3925 + case NS_MOUSE_BUTTON_UP: 1.3926 + switch (aButton) { 1.3927 + case WidgetMouseEvent::eLeftButton: 1.3928 + pluginEvent.event = WM_LBUTTONUP; 1.3929 + break; 1.3930 + case WidgetMouseEvent::eMiddleButton: 1.3931 + pluginEvent.event = WM_MBUTTONUP; 1.3932 + break; 1.3933 + case WidgetMouseEvent::eRightButton: 1.3934 + pluginEvent.event = WM_RBUTTONUP; 1.3935 + break; 1.3936 + default: 1.3937 + break; 1.3938 + } 1.3939 + break; 1.3940 + case NS_MOUSE_DOUBLECLICK: 1.3941 + switch (aButton) { 1.3942 + case WidgetMouseEvent::eLeftButton: 1.3943 + pluginEvent.event = WM_LBUTTONDBLCLK; 1.3944 + break; 1.3945 + case WidgetMouseEvent::eMiddleButton: 1.3946 + pluginEvent.event = WM_MBUTTONDBLCLK; 1.3947 + break; 1.3948 + case WidgetMouseEvent::eRightButton: 1.3949 + pluginEvent.event = WM_RBUTTONDBLCLK; 1.3950 + break; 1.3951 + default: 1.3952 + break; 1.3953 + } 1.3954 + break; 1.3955 + case NS_MOUSE_MOVE: 1.3956 + pluginEvent.event = WM_MOUSEMOVE; 1.3957 + break; 1.3958 + case NS_MOUSE_EXIT: 1.3959 + pluginEvent.event = WM_MOUSELEAVE; 1.3960 + break; 1.3961 + default: 1.3962 + pluginEvent.event = WM_NULL; 1.3963 + break; 1.3964 + } 1.3965 + 1.3966 + pluginEvent.wParam = wParam; // plugins NEED raw OS event flags! 1.3967 + pluginEvent.lParam = lParam; 1.3968 + 1.3969 + event.pluginEvent = (void *)&pluginEvent; 1.3970 + 1.3971 + // call the event callback 1.3972 + if (mWidgetListener) { 1.3973 + if (nsToolkit::gMouseTrailer) 1.3974 + nsToolkit::gMouseTrailer->Disable(); 1.3975 + if (aEventType == NS_MOUSE_MOVE) { 1.3976 + if (nsToolkit::gMouseTrailer && !sIsInMouseCapture) { 1.3977 + nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd); 1.3978 + } 1.3979 + nsIntRect rect; 1.3980 + GetBounds(rect); 1.3981 + rect.x = 0; 1.3982 + rect.y = 0; 1.3983 + 1.3984 + if (rect.Contains(LayoutDeviceIntPoint::ToUntyped(event.refPoint))) { 1.3985 + if (sCurrentWindow == nullptr || sCurrentWindow != this) { 1.3986 + if ((nullptr != sCurrentWindow) && (!sCurrentWindow->mInDtor)) { 1.3987 + LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam)); 1.3988 + sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, false, 1.3989 + WidgetMouseEvent::eLeftButton, 1.3990 + aInputSource); 1.3991 + } 1.3992 + sCurrentWindow = this; 1.3993 + if (!mInDtor) { 1.3994 + LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam)); 1.3995 + sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, false, 1.3996 + WidgetMouseEvent::eLeftButton, 1.3997 + aInputSource); 1.3998 + } 1.3999 + } 1.4000 + } 1.4001 + } else if (aEventType == NS_MOUSE_EXIT) { 1.4002 + if (sCurrentWindow == this) { 1.4003 + sCurrentWindow = nullptr; 1.4004 + } 1.4005 + } 1.4006 + 1.4007 + result = DispatchWindowEvent(&event); 1.4008 + 1.4009 + if (nsToolkit::gMouseTrailer) 1.4010 + nsToolkit::gMouseTrailer->Enable(); 1.4011 + 1.4012 + // Release the widget with NS_IF_RELEASE() just in case 1.4013 + // the context menu key code in EventListenerManager::HandleEvent() 1.4014 + // released it already. 1.4015 + return result; 1.4016 + } 1.4017 + 1.4018 + return result; 1.4019 +} 1.4020 + 1.4021 +void nsWindow::DispatchFocusToTopLevelWindow(bool aIsActivate) 1.4022 +{ 1.4023 + if (aIsActivate) 1.4024 + sJustGotActivate = false; 1.4025 + sJustGotDeactivate = false; 1.4026 + 1.4027 + // retrive the toplevel window or dialog 1.4028 + HWND curWnd = mWnd; 1.4029 + HWND toplevelWnd = nullptr; 1.4030 + while (curWnd) { 1.4031 + toplevelWnd = curWnd; 1.4032 + 1.4033 + nsWindow *win = WinUtils::GetNSWindowPtr(curWnd); 1.4034 + if (win) { 1.4035 + nsWindowType wintype = win->WindowType(); 1.4036 + if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog) 1.4037 + break; 1.4038 + } 1.4039 + 1.4040 + curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent) 1.4041 + } 1.4042 + 1.4043 + if (toplevelWnd) { 1.4044 + nsWindow *win = WinUtils::GetNSWindowPtr(toplevelWnd); 1.4045 + if (win && win->mWidgetListener) { 1.4046 + if (aIsActivate) { 1.4047 + win->mWidgetListener->WindowActivated(); 1.4048 + } else { 1.4049 + if (!win->BlurEventsSuppressed()) { 1.4050 + win->mWidgetListener->WindowDeactivated(); 1.4051 + } 1.4052 + } 1.4053 + } 1.4054 + } 1.4055 +} 1.4056 + 1.4057 +bool nsWindow::IsTopLevelMouseExit(HWND aWnd) 1.4058 +{ 1.4059 + DWORD pos = ::GetMessagePos(); 1.4060 + POINT mp; 1.4061 + mp.x = GET_X_LPARAM(pos); 1.4062 + mp.y = GET_Y_LPARAM(pos); 1.4063 + HWND mouseWnd = ::WindowFromPoint(mp); 1.4064 + 1.4065 + // WinUtils::GetTopLevelHWND() will return a HWND for the window frame 1.4066 + // (which includes the non-client area). If the mouse has moved into 1.4067 + // the non-client area, we should treat it as a top-level exit. 1.4068 + HWND mouseTopLevel = WinUtils::GetTopLevelHWND(mouseWnd); 1.4069 + if (mouseWnd == mouseTopLevel) 1.4070 + return true; 1.4071 + 1.4072 + return WinUtils::GetTopLevelHWND(aWnd) != mouseTopLevel; 1.4073 +} 1.4074 + 1.4075 +bool nsWindow::BlurEventsSuppressed() 1.4076 +{ 1.4077 + // are they suppressed in this window? 1.4078 + if (mBlurSuppressLevel > 0) 1.4079 + return true; 1.4080 + 1.4081 + // are they suppressed by any container widget? 1.4082 + HWND parentWnd = ::GetParent(mWnd); 1.4083 + if (parentWnd) { 1.4084 + nsWindow *parent = WinUtils::GetNSWindowPtr(parentWnd); 1.4085 + if (parent) 1.4086 + return parent->BlurEventsSuppressed(); 1.4087 + } 1.4088 + return false; 1.4089 +} 1.4090 + 1.4091 +// In some circumstances (opening dependent windows) it makes more sense 1.4092 +// (and fixes a crash bug) to not blur the parent window. Called from 1.4093 +// nsFilePicker. 1.4094 +void nsWindow::SuppressBlurEvents(bool aSuppress) 1.4095 +{ 1.4096 + if (aSuppress) 1.4097 + ++mBlurSuppressLevel; // for this widget 1.4098 + else { 1.4099 + NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression"); 1.4100 + if (mBlurSuppressLevel > 0) 1.4101 + --mBlurSuppressLevel; 1.4102 + } 1.4103 +} 1.4104 + 1.4105 +bool nsWindow::ConvertStatus(nsEventStatus aStatus) 1.4106 +{ 1.4107 + return aStatus == nsEventStatus_eConsumeNoDefault; 1.4108 +} 1.4109 + 1.4110 +/************************************************************** 1.4111 + * 1.4112 + * SECTION: IPC 1.4113 + * 1.4114 + * IPC related helpers. 1.4115 + * 1.4116 + **************************************************************/ 1.4117 + 1.4118 +// static 1.4119 +bool 1.4120 +nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult) 1.4121 +{ 1.4122 + switch(aMsg) { 1.4123 + case WM_SETFOCUS: 1.4124 + case WM_KILLFOCUS: 1.4125 + case WM_ENABLE: 1.4126 + case WM_WINDOWPOSCHANGING: 1.4127 + case WM_WINDOWPOSCHANGED: 1.4128 + case WM_PARENTNOTIFY: 1.4129 + case WM_ACTIVATEAPP: 1.4130 + case WM_NCACTIVATE: 1.4131 + case WM_ACTIVATE: 1.4132 + case WM_CHILDACTIVATE: 1.4133 + case WM_IME_SETCONTEXT: 1.4134 + case WM_IME_NOTIFY: 1.4135 + case WM_SHOWWINDOW: 1.4136 + case WM_CANCELMODE: 1.4137 + case WM_MOUSEACTIVATE: 1.4138 + case WM_CONTEXTMENU: 1.4139 + aResult = 0; 1.4140 + return true; 1.4141 + 1.4142 + case WM_SETTINGCHANGE: 1.4143 + case WM_SETCURSOR: 1.4144 + return false; 1.4145 + } 1.4146 + 1.4147 +#ifdef DEBUG 1.4148 + char szBuf[200]; 1.4149 + sprintf(szBuf, 1.4150 + "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg); 1.4151 + NS_WARNING(szBuf); 1.4152 +#endif 1.4153 + 1.4154 + return false; 1.4155 +} 1.4156 + 1.4157 +void 1.4158 +nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam) 1.4159 +{ 1.4160 + NS_ASSERTION(!mozilla::ipc::MessageChannel::IsPumpingMessages(), 1.4161 + "Failed to prevent a nonqueued message from running!"); 1.4162 + 1.4163 + // Modal UI being displayed in windowless plugins. 1.4164 + if (mozilla::ipc::MessageChannel::IsSpinLoopActive() && 1.4165 + (InSendMessageEx(nullptr) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) { 1.4166 + LRESULT res; 1.4167 + if (IsAsyncResponseEvent(msg, res)) { 1.4168 + ReplyMessage(res); 1.4169 + } 1.4170 + return; 1.4171 + } 1.4172 + 1.4173 + // Handle certain sync plugin events sent to the parent which 1.4174 + // trigger ipc calls that result in deadlocks. 1.4175 + 1.4176 + DWORD dwResult = 0; 1.4177 + bool handled = false; 1.4178 + 1.4179 + switch(msg) { 1.4180 + // Windowless flash sending WM_ACTIVATE events to the main window 1.4181 + // via calls to ShowWindow. 1.4182 + case WM_ACTIVATE: 1.4183 + if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE && 1.4184 + IsWindow((HWND)lParam)) { 1.4185 + // Check for Adobe Reader X sync activate message from their 1.4186 + // helper window and ignore. Fixes an annoying focus problem. 1.4187 + if ((InSendMessageEx(nullptr) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) { 1.4188 + wchar_t szClass[10]; 1.4189 + HWND focusWnd = (HWND)lParam; 1.4190 + if (IsWindowVisible(focusWnd) && 1.4191 + GetClassNameW(focusWnd, szClass, 1.4192 + sizeof(szClass)/sizeof(char16_t)) && 1.4193 + !wcscmp(szClass, L"Edit") && 1.4194 + !WinUtils::IsOurProcessWindow(focusWnd)) { 1.4195 + break; 1.4196 + } 1.4197 + } 1.4198 + handled = true; 1.4199 + } 1.4200 + break; 1.4201 + // Plugins taking or losing focus triggering focus app messages. 1.4202 + case WM_SETFOCUS: 1.4203 + case WM_KILLFOCUS: 1.4204 + // Windowed plugins that pass sys key events to defwndproc generate 1.4205 + // WM_SYSCOMMAND events to the main window. 1.4206 + case WM_SYSCOMMAND: 1.4207 + // Windowed plugins that fire context menu selection events to parent 1.4208 + // windows. 1.4209 + case WM_CONTEXTMENU: 1.4210 + // IME events fired as a result of synchronous focus changes 1.4211 + case WM_IME_SETCONTEXT: 1.4212 + handled = true; 1.4213 + break; 1.4214 + } 1.4215 + 1.4216 + if (handled && 1.4217 + (InSendMessageEx(nullptr) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) { 1.4218 + ReplyMessage(dwResult); 1.4219 + } 1.4220 +} 1.4221 + 1.4222 +/************************************************************** 1.4223 + ************************************************************** 1.4224 + ** 1.4225 + ** BLOCK: Native events 1.4226 + ** 1.4227 + ** Main Windows message handlers and OnXXX handlers for 1.4228 + ** Windows event handling. 1.4229 + ** 1.4230 + ************************************************************** 1.4231 + **************************************************************/ 1.4232 + 1.4233 +/************************************************************** 1.4234 + * 1.4235 + * SECTION: Wind proc. 1.4236 + * 1.4237 + * The main Windows event procedures and associated 1.4238 + * message processing methods. 1.4239 + * 1.4240 + **************************************************************/ 1.4241 + 1.4242 +static bool 1.4243 +DisplaySystemMenu(HWND hWnd, nsSizeMode sizeMode, bool isRtl, int32_t x, int32_t y) 1.4244 +{ 1.4245 + HMENU hMenu = GetSystemMenu(hWnd, FALSE); 1.4246 + if (hMenu) { 1.4247 + MENUITEMINFO mii; 1.4248 + mii.cbSize = sizeof(MENUITEMINFO); 1.4249 + mii.fMask = MIIM_STATE; 1.4250 + mii.fType = 0; 1.4251 + 1.4252 + // update the options 1.4253 + mii.fState = MF_ENABLED; 1.4254 + SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii); 1.4255 + SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii); 1.4256 + SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii); 1.4257 + SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii); 1.4258 + SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii); 1.4259 + 1.4260 + mii.fState = MF_GRAYED; 1.4261 + switch(sizeMode) { 1.4262 + case nsSizeMode_Fullscreen: 1.4263 + SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii); 1.4264 + // intentional fall through 1.4265 + case nsSizeMode_Maximized: 1.4266 + SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii); 1.4267 + SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii); 1.4268 + SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii); 1.4269 + break; 1.4270 + case nsSizeMode_Minimized: 1.4271 + SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii); 1.4272 + break; 1.4273 + case nsSizeMode_Normal: 1.4274 + SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii); 1.4275 + break; 1.4276 + } 1.4277 + LPARAM cmd = 1.4278 + TrackPopupMenu(hMenu, 1.4279 + (TPM_LEFTBUTTON|TPM_RIGHTBUTTON| 1.4280 + TPM_RETURNCMD|TPM_TOPALIGN| 1.4281 + (isRtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), 1.4282 + x, y, 0, hWnd, nullptr); 1.4283 + if (cmd) { 1.4284 + PostMessage(hWnd, WM_SYSCOMMAND, cmd, 0); 1.4285 + return true; 1.4286 + } 1.4287 + } 1.4288 + return false; 1.4289 +} 1.4290 + 1.4291 +inline static mozilla::HangMonitor::ActivityType ActivityTypeForMessage(UINT msg) 1.4292 +{ 1.4293 + if ((msg >= WM_KEYFIRST && msg <= WM_IME_KEYLAST) || 1.4294 + (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) || 1.4295 + (msg >= MOZ_WM_MOUSEWHEEL_FIRST && msg <= MOZ_WM_MOUSEWHEEL_LAST) || 1.4296 + (msg >= NS_WM_IMEFIRST && msg <= NS_WM_IMELAST)) { 1.4297 + return mozilla::HangMonitor::kUIActivity; 1.4298 + } 1.4299 + 1.4300 + // This may not actually be right, but we don't want to reset the timer if 1.4301 + // we're not actually processing a UI message. 1.4302 + return mozilla::HangMonitor::kActivityUIAVail; 1.4303 +} 1.4304 + 1.4305 +// The WndProc procedure for all nsWindows in this toolkit. This merely catches 1.4306 +// exceptions and passes the real work to WindowProcInternal. See bug 587406 1.4307 +// and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx 1.4308 +LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 1.4309 +{ 1.4310 + HangMonitor::NotifyActivity(ActivityTypeForMessage(msg)); 1.4311 + 1.4312 + return mozilla::CallWindowProcCrashProtected(WindowProcInternal, hWnd, msg, wParam, lParam); 1.4313 +} 1.4314 + 1.4315 +LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 1.4316 +{ 1.4317 + if (::GetWindowLongPtrW(hWnd, GWLP_ID) == eFakeTrackPointScrollableID) { 1.4318 + // This message was sent to the FAKETRACKPOINTSCROLLABLE. 1.4319 + if (msg == WM_HSCROLL) { 1.4320 + // Route WM_HSCROLL messages to the main window. 1.4321 + hWnd = ::GetParent(::GetParent(hWnd)); 1.4322 + } else { 1.4323 + // Handle all other messages with its original window procedure. 1.4324 + WNDPROC prevWindowProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_USERDATA); 1.4325 + return ::CallWindowProcW(prevWindowProc, hWnd, msg, wParam, lParam); 1.4326 + } 1.4327 + } 1.4328 + 1.4329 + if (msg == MOZ_WM_TRACE) { 1.4330 + // This is a tracer event for measuring event loop latency. 1.4331 + // See WidgetTraceEvent.cpp for more details. 1.4332 + mozilla::SignalTracerThread(); 1.4333 + return 0; 1.4334 + } 1.4335 + 1.4336 + // Get the window which caused the event and ask it to process the message 1.4337 + nsWindow *targetWindow = WinUtils::GetNSWindowPtr(hWnd); 1.4338 + NS_ASSERTION(targetWindow, "nsWindow* is null!"); 1.4339 + if (!targetWindow) 1.4340 + return ::DefWindowProcW(hWnd, msg, wParam, lParam); 1.4341 + 1.4342 + // Hold the window for the life of this method, in case it gets 1.4343 + // destroyed during processing, unless we're in the dtor already. 1.4344 + nsCOMPtr<nsISupports> kungFuDeathGrip; 1.4345 + if (!targetWindow->mInDtor) 1.4346 + kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)targetWindow); 1.4347 + 1.4348 + targetWindow->IPCWindowProcHandler(msg, wParam, lParam); 1.4349 + 1.4350 + // Create this here so that we store the last rolled up popup until after 1.4351 + // the event has been processed. 1.4352 + nsAutoRollup autoRollup; 1.4353 + 1.4354 + LRESULT popupHandlingResult; 1.4355 + if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult)) 1.4356 + return popupHandlingResult; 1.4357 + 1.4358 + // Call ProcessMessage 1.4359 + LRESULT retValue; 1.4360 + if (targetWindow->ProcessMessage(msg, wParam, lParam, &retValue)) { 1.4361 + return retValue; 1.4362 + } 1.4363 + 1.4364 + LRESULT res = ::CallWindowProcW(targetWindow->GetPrevWindowProc(), 1.4365 + hWnd, msg, wParam, lParam); 1.4366 + 1.4367 + return res; 1.4368 +} 1.4369 + 1.4370 +// The main windows message processing method for plugins. 1.4371 +// The result means whether this method processed the native 1.4372 +// event for plugin. If false, the native event should be 1.4373 +// processed by the caller self. 1.4374 +bool 1.4375 +nsWindow::ProcessMessageForPlugin(const MSG &aMsg, 1.4376 + MSGResult& aResult) 1.4377 +{ 1.4378 + aResult.mResult = 0; 1.4379 + aResult.mConsumed = true; 1.4380 + 1.4381 + bool eventDispatched = false; 1.4382 + switch (aMsg.message) { 1.4383 + case WM_CHAR: 1.4384 + case WM_SYSCHAR: 1.4385 + aResult.mResult = ProcessCharMessage(aMsg, &eventDispatched); 1.4386 + break; 1.4387 + 1.4388 + case WM_KEYUP: 1.4389 + case WM_SYSKEYUP: 1.4390 + aResult.mResult = ProcessKeyUpMessage(aMsg, &eventDispatched); 1.4391 + break; 1.4392 + 1.4393 + case WM_KEYDOWN: 1.4394 + case WM_SYSKEYDOWN: 1.4395 + aResult.mResult = ProcessKeyDownMessage(aMsg, &eventDispatched); 1.4396 + break; 1.4397 + 1.4398 + case WM_DEADCHAR: 1.4399 + case WM_SYSDEADCHAR: 1.4400 + 1.4401 + case WM_CUT: 1.4402 + case WM_COPY: 1.4403 + case WM_PASTE: 1.4404 + case WM_CLEAR: 1.4405 + case WM_UNDO: 1.4406 + break; 1.4407 + 1.4408 + default: 1.4409 + return false; 1.4410 + } 1.4411 + 1.4412 + if (!eventDispatched) { 1.4413 + aResult.mConsumed = nsWindowBase::DispatchPluginEvent(aMsg); 1.4414 + } 1.4415 + if (!Destroyed()) { 1.4416 + DispatchPendingEvents(); 1.4417 + } 1.4418 + return true; 1.4419 +} 1.4420 + 1.4421 +static void ForceFontUpdate() 1.4422 +{ 1.4423 + // update device context font cache 1.4424 + // Dirty but easiest way: 1.4425 + // Changing nsIPrefBranch entry which triggers callbacks 1.4426 + // and flows into calling mDeviceContext->FlushFontCache() 1.4427 + // to update the font cache in all the instance of Browsers 1.4428 + static const char kPrefName[] = "font.internaluseonly.changed"; 1.4429 + bool fontInternalChange = 1.4430 + Preferences::GetBool(kPrefName, false); 1.4431 + Preferences::SetBool(kPrefName, !fontInternalChange); 1.4432 +} 1.4433 + 1.4434 +static bool CleartypeSettingChanged() 1.4435 +{ 1.4436 + static int currentQuality = -1; 1.4437 + BYTE quality = cairo_win32_get_system_text_quality(); 1.4438 + 1.4439 + if (currentQuality == quality) 1.4440 + return false; 1.4441 + 1.4442 + if (currentQuality < 0) { 1.4443 + currentQuality = quality; 1.4444 + return false; 1.4445 + } 1.4446 + currentQuality = quality; 1.4447 + return true; 1.4448 +} 1.4449 + 1.4450 +bool 1.4451 +nsWindow::ExternalHandlerProcessMessage(UINT aMessage, 1.4452 + WPARAM& aWParam, 1.4453 + LPARAM& aLParam, 1.4454 + MSGResult& aResult) 1.4455 +{ 1.4456 + if (mWindowHook.Notify(mWnd, aMessage, aWParam, aLParam, aResult)) { 1.4457 + return true; 1.4458 + } 1.4459 + 1.4460 + if (IMEHandler::ProcessMessage(this, aMessage, aWParam, aLParam, aResult)) { 1.4461 + return true; 1.4462 + } 1.4463 + 1.4464 + if (MouseScrollHandler::ProcessMessage(this, aMessage, aWParam, aLParam, 1.4465 + aResult)) { 1.4466 + return true; 1.4467 + } 1.4468 + 1.4469 + if (PluginHasFocus()) { 1.4470 + MSG nativeMsg = WinUtils::InitMSG(aMessage, aWParam, aLParam, mWnd); 1.4471 + if (ProcessMessageForPlugin(nativeMsg, aResult)) { 1.4472 + return true; 1.4473 + } 1.4474 + } 1.4475 + 1.4476 + return false; 1.4477 +} 1.4478 + 1.4479 +// The main windows message processing method. 1.4480 +bool 1.4481 +nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam, 1.4482 + LRESULT *aRetValue) 1.4483 +{ 1.4484 +#if defined(EVENT_DEBUG_OUTPUT) 1.4485 + // First param shows all events, second param indicates whether 1.4486 + // to show mouse move events. See nsWindowDbg for details. 1.4487 + PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS); 1.4488 +#endif 1.4489 + 1.4490 + MSGResult msgResult(aRetValue); 1.4491 + if (ExternalHandlerProcessMessage(msg, wParam, lParam, msgResult)) { 1.4492 + return (msgResult.mConsumed || !mWnd); 1.4493 + } 1.4494 + 1.4495 + bool result = false; // call the default nsWindow proc 1.4496 + *aRetValue = 0; 1.4497 + 1.4498 + // Glass hit testing w/custom transparent margins 1.4499 + LRESULT dwmHitResult; 1.4500 + if (mCustomNonClient && 1.4501 + nsUXThemeData::CheckForCompositor() && 1.4502 + WinUtils::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) { 1.4503 + *aRetValue = dwmHitResult; 1.4504 + return true; 1.4505 + } 1.4506 + 1.4507 + // (Large blocks of code should be broken out into OnEvent handlers.) 1.4508 + switch (msg) { 1.4509 + // WM_QUERYENDSESSION must be handled by all windows. 1.4510 + // Otherwise Windows thinks the window can just be killed at will. 1.4511 + case WM_QUERYENDSESSION: 1.4512 + if (sCanQuit == TRI_UNKNOWN) 1.4513 + { 1.4514 + // Ask if it's ok to quit, and store the answer until we 1.4515 + // get WM_ENDSESSION signaling the round is complete. 1.4516 + nsCOMPtr<nsIObserverService> obsServ = 1.4517 + mozilla::services::GetObserverService(); 1.4518 + nsCOMPtr<nsISupportsPRBool> cancelQuit = 1.4519 + do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID); 1.4520 + cancelQuit->SetData(false); 1.4521 + obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr); 1.4522 + 1.4523 + bool abortQuit; 1.4524 + cancelQuit->GetData(&abortQuit); 1.4525 + sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE; 1.4526 + } 1.4527 + *aRetValue = sCanQuit ? TRUE : FALSE; 1.4528 + result = true; 1.4529 + break; 1.4530 + 1.4531 + case WM_ENDSESSION: 1.4532 + case MOZ_WM_APP_QUIT: 1.4533 + if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE)) 1.4534 + { 1.4535 + // Let's fake a shutdown sequence without actually closing windows etc. 1.4536 + // to avoid Windows killing us in the middle. A proper shutdown would 1.4537 + // require having a chance to pump some messages. Unfortunately 1.4538 + // Windows won't let us do that. Bug 212316. 1.4539 + nsCOMPtr<nsIObserverService> obsServ = 1.4540 + mozilla::services::GetObserverService(); 1.4541 + NS_NAMED_LITERAL_STRING(context, "shutdown-persist"); 1.4542 + obsServ->NotifyObservers(nullptr, "quit-application-granted", nullptr); 1.4543 + obsServ->NotifyObservers(nullptr, "quit-application-forced", nullptr); 1.4544 + obsServ->NotifyObservers(nullptr, "quit-application", nullptr); 1.4545 + obsServ->NotifyObservers(nullptr, "profile-change-net-teardown", context.get()); 1.4546 + obsServ->NotifyObservers(nullptr, "profile-change-teardown", context.get()); 1.4547 + obsServ->NotifyObservers(nullptr, "profile-before-change", context.get()); 1.4548 + obsServ->NotifyObservers(nullptr, "profile-before-change2", context.get()); 1.4549 + // Then a controlled but very quick exit. 1.4550 + _exit(0); 1.4551 + } 1.4552 + sCanQuit = TRI_UNKNOWN; 1.4553 + result = true; 1.4554 + break; 1.4555 + 1.4556 + case WM_SYSCOLORCHANGE: 1.4557 + OnSysColorChanged(); 1.4558 + break; 1.4559 + 1.4560 + case WM_THEMECHANGED: 1.4561 + { 1.4562 + // Update non-client margin offsets 1.4563 + UpdateNonClientMargins(); 1.4564 + nsUXThemeData::InitTitlebarInfo(); 1.4565 + nsUXThemeData::UpdateNativeThemeInfo(); 1.4566 + 1.4567 + NotifyThemeChanged(); 1.4568 + 1.4569 + // Invalidate the window so that the repaint will 1.4570 + // pick up the new theme. 1.4571 + Invalidate(true, true, true); 1.4572 + } 1.4573 + break; 1.4574 + 1.4575 + case WM_FONTCHANGE: 1.4576 + { 1.4577 + // We only handle this message for the hidden window, 1.4578 + // as we only need to update the (global) font list once 1.4579 + // for any given change, not once per window! 1.4580 + if (mWindowType != eWindowType_invisible) { 1.4581 + break; 1.4582 + } 1.4583 + 1.4584 + nsresult rv; 1.4585 + bool didChange = false; 1.4586 + 1.4587 + // update the global font list 1.4588 + nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv); 1.4589 + if (NS_SUCCEEDED(rv)) { 1.4590 + fontEnum->UpdateFontList(&didChange); 1.4591 + ForceFontUpdate(); 1.4592 + } //if (NS_SUCCEEDED(rv)) 1.4593 + } 1.4594 + break; 1.4595 + 1.4596 + case WM_NCCALCSIZE: 1.4597 + { 1.4598 + if (mCustomNonClient) { 1.4599 + // If `wParam` is `FALSE`, `lParam` points to a `RECT` that contains 1.4600 + // the proposed window rectangle for our window. During our 1.4601 + // processing of the `WM_NCCALCSIZE` message, we are expected to 1.4602 + // modify the `RECT` that `lParam` points to, so that its value upon 1.4603 + // our return is the new client area. We must return 0 if `wParam` 1.4604 + // is `FALSE`. 1.4605 + // 1.4606 + // If `wParam` is `TRUE`, `lParam` points to a `NCCALCSIZE_PARAMS` 1.4607 + // struct. This struct contains an array of 3 `RECT`s, the first of 1.4608 + // which has the exact same meaning as the `RECT` that is pointed to 1.4609 + // by `lParam` when `wParam` is `FALSE`. The remaining `RECT`s, in 1.4610 + // conjunction with our return value, can 1.4611 + // be used to specify portions of the source and destination window 1.4612 + // rectangles that are valid and should be preserved. We opt not to 1.4613 + // implement an elaborate client-area preservation technique, and 1.4614 + // simply return 0, which means "preserve the entire old client area 1.4615 + // and align it with the upper-left corner of our new client area". 1.4616 + RECT *clientRect = wParam 1.4617 + ? &(reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam))->rgrc[0] 1.4618 + : (reinterpret_cast<RECT*>(lParam)); 1.4619 + clientRect->top += (mCaptionHeight - mNonClientOffset.top); 1.4620 + clientRect->left += (mHorResizeMargin - mNonClientOffset.left); 1.4621 + clientRect->right -= (mHorResizeMargin - mNonClientOffset.right); 1.4622 + clientRect->bottom -= (mVertResizeMargin - mNonClientOffset.bottom); 1.4623 + 1.4624 + result = true; 1.4625 + *aRetValue = 0; 1.4626 + } 1.4627 + break; 1.4628 + } 1.4629 + 1.4630 + case WM_NCHITTEST: 1.4631 + { 1.4632 + if (mMouseTransparent) { 1.4633 + // Treat this window as transparent. 1.4634 + *aRetValue = HTTRANSPARENT; 1.4635 + result = true; 1.4636 + break; 1.4637 + } 1.4638 + 1.4639 + /* 1.4640 + * If an nc client area margin has been moved, we are responsible 1.4641 + * for calculating where the resize margins are and returning the 1.4642 + * appropriate set of hit test constants. DwmDefWindowProc (above) 1.4643 + * will handle hit testing on it's command buttons if we are on a 1.4644 + * composited desktop. 1.4645 + */ 1.4646 + 1.4647 + if (!mCustomNonClient) 1.4648 + break; 1.4649 + 1.4650 + *aRetValue = 1.4651 + ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); 1.4652 + result = true; 1.4653 + break; 1.4654 + } 1.4655 + 1.4656 + case WM_SETTEXT: 1.4657 + /* 1.4658 + * WM_SETTEXT paints the titlebar area. Avoid this if we have a 1.4659 + * custom titlebar we paint ourselves. 1.4660 + */ 1.4661 + 1.4662 + if (!mCustomNonClient || mNonClientMargins.top == -1) 1.4663 + break; 1.4664 + 1.4665 + { 1.4666 + // From msdn, the way around this is to disable the visible state 1.4667 + // temporarily. We need the text to be set but we don't want the 1.4668 + // redraw to occur. 1.4669 + DWORD style = GetWindowLong(mWnd, GWL_STYLE); 1.4670 + SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE); 1.4671 + *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd, 1.4672 + msg, wParam, lParam); 1.4673 + SetWindowLong(mWnd, GWL_STYLE, style); 1.4674 + return true; 1.4675 + } 1.4676 + 1.4677 + case WM_NCACTIVATE: 1.4678 + { 1.4679 + /* 1.4680 + * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting 1.4681 + * through WM_NCPAINT via InvalidateNonClientRegion. 1.4682 + */ 1.4683 + UpdateGetWindowInfoCaptionStatus(FALSE != wParam); 1.4684 + 1.4685 + if (!mCustomNonClient) 1.4686 + break; 1.4687 + 1.4688 + // let the dwm handle nc painting on glass 1.4689 + if(nsUXThemeData::CheckForCompositor()) 1.4690 + break; 1.4691 + 1.4692 + if (wParam == TRUE) { 1.4693 + // going active 1.4694 + *aRetValue = FALSE; // ignored 1.4695 + result = true; 1.4696 + // invalidate to trigger a paint 1.4697 + InvalidateNonClientRegion(); 1.4698 + break; 1.4699 + } else { 1.4700 + // going inactive 1.4701 + *aRetValue = TRUE; // go ahead and deactive 1.4702 + result = true; 1.4703 + // invalidate to trigger a paint 1.4704 + InvalidateNonClientRegion(); 1.4705 + break; 1.4706 + } 1.4707 + } 1.4708 + 1.4709 + case WM_NCPAINT: 1.4710 + { 1.4711 + /* 1.4712 + * Reset the non-client paint region so that it excludes the 1.4713 + * non-client areas we paint manually. Then call defwndproc 1.4714 + * to do the actual painting. 1.4715 + */ 1.4716 + 1.4717 + if (!mCustomNonClient) 1.4718 + break; 1.4719 + 1.4720 + // let the dwm handle nc painting on glass 1.4721 + if(nsUXThemeData::CheckForCompositor()) 1.4722 + break; 1.4723 + 1.4724 + HRGN paintRgn = ExcludeNonClientFromPaintRegion((HRGN)wParam); 1.4725 + LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd, 1.4726 + msg, (WPARAM)paintRgn, lParam); 1.4727 + if (paintRgn != (HRGN)wParam) 1.4728 + DeleteObject(paintRgn); 1.4729 + *aRetValue = res; 1.4730 + result = true; 1.4731 + } 1.4732 + break; 1.4733 + 1.4734 + case WM_POWERBROADCAST: 1.4735 + switch (wParam) 1.4736 + { 1.4737 + case PBT_APMSUSPEND: 1.4738 + PostSleepWakeNotification(true); 1.4739 + break; 1.4740 + case PBT_APMRESUMEAUTOMATIC: 1.4741 + case PBT_APMRESUMECRITICAL: 1.4742 + case PBT_APMRESUMESUSPEND: 1.4743 + PostSleepWakeNotification(false); 1.4744 + break; 1.4745 + } 1.4746 + break; 1.4747 + 1.4748 + case WM_CLOSE: // close request 1.4749 + if (mWidgetListener) 1.4750 + mWidgetListener->RequestWindowClose(this); 1.4751 + result = true; // abort window closure 1.4752 + break; 1.4753 + 1.4754 + case WM_DESTROY: 1.4755 + // clean up. 1.4756 + OnDestroy(); 1.4757 + result = true; 1.4758 + break; 1.4759 + 1.4760 + case WM_PAINT: 1.4761 + if (CleartypeSettingChanged()) { 1.4762 + ForceFontUpdate(); 1.4763 + gfxFontCache *fc = gfxFontCache::GetCache(); 1.4764 + if (fc) { 1.4765 + fc->Flush(); 1.4766 + } 1.4767 + } 1.4768 + *aRetValue = (int) OnPaint(nullptr, 0); 1.4769 + result = true; 1.4770 + break; 1.4771 + 1.4772 + case WM_PRINTCLIENT: 1.4773 + result = OnPaint((HDC) wParam, 0); 1.4774 + break; 1.4775 + 1.4776 + case WM_HOTKEY: 1.4777 + result = OnHotKey(wParam, lParam); 1.4778 + break; 1.4779 + 1.4780 + case WM_SYSCHAR: 1.4781 + case WM_CHAR: 1.4782 + { 1.4783 + MSG nativeMsg = WinUtils::InitMSG(msg, wParam, lParam, mWnd); 1.4784 + result = ProcessCharMessage(nativeMsg, nullptr); 1.4785 + DispatchPendingEvents(); 1.4786 + } 1.4787 + break; 1.4788 + 1.4789 + case WM_SYSKEYUP: 1.4790 + case WM_KEYUP: 1.4791 + { 1.4792 + MSG nativeMsg = WinUtils::InitMSG(msg, wParam, lParam, mWnd); 1.4793 + nativeMsg.time = ::GetMessageTime(); 1.4794 + result = ProcessKeyUpMessage(nativeMsg, nullptr); 1.4795 + DispatchPendingEvents(); 1.4796 + } 1.4797 + break; 1.4798 + 1.4799 + case WM_SYSKEYDOWN: 1.4800 + case WM_KEYDOWN: 1.4801 + { 1.4802 + MSG nativeMsg = WinUtils::InitMSG(msg, wParam, lParam, mWnd); 1.4803 + result = ProcessKeyDownMessage(nativeMsg, nullptr); 1.4804 + DispatchPendingEvents(); 1.4805 + } 1.4806 + break; 1.4807 + 1.4808 + // say we've dealt with erase background if widget does 1.4809 + // not need auto-erasing 1.4810 + case WM_ERASEBKGND: 1.4811 + if (!AutoErase((HDC)wParam)) { 1.4812 + *aRetValue = 1; 1.4813 + result = true; 1.4814 + } 1.4815 + break; 1.4816 + 1.4817 + case WM_MOUSEMOVE: 1.4818 + { 1.4819 + mMousePresent = true; 1.4820 + 1.4821 + // Suppress dispatch of pending events 1.4822 + // when mouse moves are generated by widget 1.4823 + // creation instead of user input. 1.4824 + LPARAM lParamScreen = lParamToScreen(lParam); 1.4825 + POINT mp; 1.4826 + mp.x = GET_X_LPARAM(lParamScreen); 1.4827 + mp.y = GET_Y_LPARAM(lParamScreen); 1.4828 + bool userMovedMouse = false; 1.4829 + if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) { 1.4830 + userMovedMouse = true; 1.4831 + } 1.4832 + 1.4833 + result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam, 1.4834 + false, WidgetMouseEvent::eLeftButton, 1.4835 + MOUSE_INPUT_SOURCE()); 1.4836 + if (userMovedMouse) { 1.4837 + DispatchPendingEvents(); 1.4838 + } 1.4839 + } 1.4840 + break; 1.4841 + 1.4842 + case WM_NCMOUSEMOVE: 1.4843 + // If we receive a mouse move event on non-client chrome, make sure and 1.4844 + // send an NS_MOUSE_EXIT event as well. 1.4845 + if (mMousePresent && !sIsInMouseCapture) 1.4846 + SendMessage(mWnd, WM_MOUSELEAVE, 0, 0); 1.4847 + break; 1.4848 + 1.4849 + case WM_LBUTTONDOWN: 1.4850 + { 1.4851 + result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, 1.4852 + false, WidgetMouseEvent::eLeftButton, 1.4853 + MOUSE_INPUT_SOURCE()); 1.4854 + DispatchPendingEvents(); 1.4855 + } 1.4856 + break; 1.4857 + 1.4858 + case WM_LBUTTONUP: 1.4859 + { 1.4860 + result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, 1.4861 + false, WidgetMouseEvent::eLeftButton, 1.4862 + MOUSE_INPUT_SOURCE()); 1.4863 + DispatchPendingEvents(); 1.4864 + } 1.4865 + break; 1.4866 + 1.4867 + case WM_MOUSELEAVE: 1.4868 + { 1.4869 + if (!mMousePresent) 1.4870 + break; 1.4871 + mMousePresent = false; 1.4872 + 1.4873 + // We need to check mouse button states and put them in for 1.4874 + // wParam. 1.4875 + WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0) 1.4876 + | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0) 1.4877 + | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0); 1.4878 + // Synthesize an event position because we don't get one from 1.4879 + // WM_MOUSELEAVE. 1.4880 + LPARAM pos = lParamToClient(::GetMessagePos()); 1.4881 + DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, false, 1.4882 + WidgetMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE()); 1.4883 + } 1.4884 + break; 1.4885 + 1.4886 + case WM_CONTEXTMENU: 1.4887 + { 1.4888 + // if the context menu is brought up from the keyboard, |lParam| 1.4889 + // will be -1. 1.4890 + LPARAM pos; 1.4891 + bool contextMenukey = false; 1.4892 + if (lParam == -1) 1.4893 + { 1.4894 + contextMenukey = true; 1.4895 + pos = lParamToClient(GetMessagePos()); 1.4896 + } 1.4897 + else 1.4898 + { 1.4899 + pos = lParamToClient(lParam); 1.4900 + } 1.4901 + 1.4902 + result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey, 1.4903 + contextMenukey ? 1.4904 + WidgetMouseEvent::eLeftButton : 1.4905 + WidgetMouseEvent::eRightButton, 1.4906 + MOUSE_INPUT_SOURCE()); 1.4907 + if (lParam != -1 && !result && mCustomNonClient) { 1.4908 + WidgetMouseEvent event(true, NS_MOUSE_MOZHITTEST, this, 1.4909 + WidgetMouseEvent::eReal, 1.4910 + WidgetMouseEvent::eNormal); 1.4911 + event.refPoint = LayoutDeviceIntPoint(GET_X_LPARAM(pos), GET_Y_LPARAM(pos)); 1.4912 + event.inputSource = MOUSE_INPUT_SOURCE(); 1.4913 + event.mFlags.mOnlyChromeDispatch = true; 1.4914 + if (DispatchWindowEvent(&event)) { 1.4915 + // Blank area hit, throw up the system menu. 1.4916 + DisplaySystemMenu(mWnd, mSizeMode, mIsRTL, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); 1.4917 + result = true; 1.4918 + } 1.4919 + } 1.4920 + } 1.4921 + break; 1.4922 + 1.4923 + case WM_LBUTTONDBLCLK: 1.4924 + result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, 1.4925 + lParam, false, 1.4926 + WidgetMouseEvent::eLeftButton, 1.4927 + MOUSE_INPUT_SOURCE()); 1.4928 + DispatchPendingEvents(); 1.4929 + break; 1.4930 + 1.4931 + case WM_MBUTTONDOWN: 1.4932 + result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, 1.4933 + lParam, false, 1.4934 + WidgetMouseEvent::eMiddleButton, 1.4935 + MOUSE_INPUT_SOURCE()); 1.4936 + DispatchPendingEvents(); 1.4937 + break; 1.4938 + 1.4939 + case WM_MBUTTONUP: 1.4940 + result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, 1.4941 + lParam, false, 1.4942 + WidgetMouseEvent::eMiddleButton, 1.4943 + MOUSE_INPUT_SOURCE()); 1.4944 + DispatchPendingEvents(); 1.4945 + break; 1.4946 + 1.4947 + case WM_MBUTTONDBLCLK: 1.4948 + result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, 1.4949 + lParam, false, 1.4950 + WidgetMouseEvent::eMiddleButton, 1.4951 + MOUSE_INPUT_SOURCE()); 1.4952 + DispatchPendingEvents(); 1.4953 + break; 1.4954 + 1.4955 + case WM_NCMBUTTONDOWN: 1.4956 + result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, 1.4957 + lParamToClient(lParam), false, 1.4958 + WidgetMouseEvent::eMiddleButton, 1.4959 + MOUSE_INPUT_SOURCE()); 1.4960 + DispatchPendingEvents(); 1.4961 + break; 1.4962 + 1.4963 + case WM_NCMBUTTONUP: 1.4964 + result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, 1.4965 + lParamToClient(lParam), false, 1.4966 + WidgetMouseEvent::eMiddleButton, 1.4967 + MOUSE_INPUT_SOURCE()); 1.4968 + DispatchPendingEvents(); 1.4969 + break; 1.4970 + 1.4971 + case WM_NCMBUTTONDBLCLK: 1.4972 + result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, 1.4973 + lParamToClient(lParam), false, 1.4974 + WidgetMouseEvent::eMiddleButton, 1.4975 + MOUSE_INPUT_SOURCE()); 1.4976 + DispatchPendingEvents(); 1.4977 + break; 1.4978 + 1.4979 + case WM_RBUTTONDOWN: 1.4980 + result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, 1.4981 + lParam, false, 1.4982 + WidgetMouseEvent::eRightButton, 1.4983 + MOUSE_INPUT_SOURCE()); 1.4984 + DispatchPendingEvents(); 1.4985 + break; 1.4986 + 1.4987 + case WM_RBUTTONUP: 1.4988 + result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, 1.4989 + lParam, false, 1.4990 + WidgetMouseEvent::eRightButton, 1.4991 + MOUSE_INPUT_SOURCE()); 1.4992 + DispatchPendingEvents(); 1.4993 + break; 1.4994 + 1.4995 + case WM_RBUTTONDBLCLK: 1.4996 + result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, 1.4997 + lParam, false, 1.4998 + WidgetMouseEvent::eRightButton, 1.4999 + MOUSE_INPUT_SOURCE()); 1.5000 + DispatchPendingEvents(); 1.5001 + break; 1.5002 + 1.5003 + case WM_NCRBUTTONDOWN: 1.5004 + result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, 1.5005 + lParamToClient(lParam), false, 1.5006 + WidgetMouseEvent::eRightButton, 1.5007 + MOUSE_INPUT_SOURCE()); 1.5008 + DispatchPendingEvents(); 1.5009 + break; 1.5010 + 1.5011 + case WM_NCRBUTTONUP: 1.5012 + result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, 1.5013 + lParamToClient(lParam), false, 1.5014 + WidgetMouseEvent::eRightButton, 1.5015 + MOUSE_INPUT_SOURCE()); 1.5016 + DispatchPendingEvents(); 1.5017 + break; 1.5018 + 1.5019 + case WM_NCRBUTTONDBLCLK: 1.5020 + result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, 1.5021 + lParamToClient(lParam), false, 1.5022 + WidgetMouseEvent::eRightButton, 1.5023 + MOUSE_INPUT_SOURCE()); 1.5024 + DispatchPendingEvents(); 1.5025 + break; 1.5026 + 1.5027 + case WM_EXITSIZEMOVE: 1.5028 + if (!sIsInMouseCapture) { 1.5029 + NotifySizeMoveDone(); 1.5030 + } 1.5031 + break; 1.5032 + 1.5033 + case WM_NCLBUTTONDBLCLK: 1.5034 + DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam), 1.5035 + false, WidgetMouseEvent::eLeftButton, 1.5036 + MOUSE_INPUT_SOURCE()); 1.5037 + result = 1.5038 + DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam), 1.5039 + false, WidgetMouseEvent::eLeftButton, 1.5040 + MOUSE_INPUT_SOURCE()); 1.5041 + DispatchPendingEvents(); 1.5042 + break; 1.5043 + 1.5044 + case WM_APPCOMMAND: 1.5045 + result = HandleAppCommandMsg(wParam, lParam, aRetValue); 1.5046 + break; 1.5047 + 1.5048 + // The WM_ACTIVATE event is fired when a window is raised or lowered, 1.5049 + // and the loword of wParam specifies which. But we don't want to tell 1.5050 + // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS 1.5051 + // events are fired. Instead, set either the sJustGotActivate or 1.5052 + // gJustGotDeactivate flags and activate/deactivate once the focus 1.5053 + // events arrive. 1.5054 + case WM_ACTIVATE: 1.5055 + if (mWidgetListener) { 1.5056 + int32_t fActive = LOWORD(wParam); 1.5057 + 1.5058 + if (WA_INACTIVE == fActive) { 1.5059 + // when minimizing a window, the deactivation and focus events will 1.5060 + // be fired in the reverse order. Instead, just deactivate right away. 1.5061 + if (HIWORD(wParam)) 1.5062 + DispatchFocusToTopLevelWindow(false); 1.5063 + else 1.5064 + sJustGotDeactivate = true; 1.5065 + 1.5066 + if (mIsTopWidgetWindow) 1.5067 + mLastKeyboardLayout = KeyboardLayout::GetInstance()->GetLayout(); 1.5068 + 1.5069 + } else { 1.5070 + StopFlashing(); 1.5071 + 1.5072 + sJustGotActivate = true; 1.5073 + WidgetMouseEvent event(true, NS_MOUSE_ACTIVATE, this, 1.5074 + WidgetMouseEvent::eReal); 1.5075 + InitEvent(event); 1.5076 + ModifierKeyState modifierKeyState; 1.5077 + modifierKeyState.InitInputEvent(event); 1.5078 + DispatchWindowEvent(&event); 1.5079 + if (sSwitchKeyboardLayout && mLastKeyboardLayout) 1.5080 + ActivateKeyboardLayout(mLastKeyboardLayout, 0); 1.5081 + } 1.5082 + } 1.5083 + break; 1.5084 + 1.5085 + case WM_MOUSEACTIVATE: 1.5086 + // A popup with a parent owner should not be activated when clicked but 1.5087 + // should still allow the mouse event to be fired, so the return value 1.5088 + // is set to MA_NOACTIVATE. But if the owner isn't the frontmost window, 1.5089 + // just use default processing so that the window is activated. 1.5090 + if (IsPopup() && IsOwnerForegroundWindow()) { 1.5091 + *aRetValue = MA_NOACTIVATE; 1.5092 + result = true; 1.5093 + } 1.5094 + break; 1.5095 + 1.5096 + case WM_WINDOWPOSCHANGING: 1.5097 + { 1.5098 + LPWINDOWPOS info = (LPWINDOWPOS)lParam; 1.5099 + OnWindowPosChanging(info); 1.5100 + result = true; 1.5101 + } 1.5102 + break; 1.5103 + 1.5104 + case WM_GETMINMAXINFO: 1.5105 + { 1.5106 + MINMAXINFO* mmi = (MINMAXINFO*)lParam; 1.5107 + // Set the constraints. The minimum size should also be constrained to the 1.5108 + // default window maximum size so that it fits on screen. 1.5109 + mmi->ptMinTrackSize.x = 1.5110 + std::min((int32_t)mmi->ptMaxTrackSize.x, 1.5111 + std::max((int32_t)mmi->ptMinTrackSize.x, mSizeConstraints.mMinSize.width)); 1.5112 + mmi->ptMinTrackSize.y = 1.5113 + std::min((int32_t)mmi->ptMaxTrackSize.y, 1.5114 + std::max((int32_t)mmi->ptMinTrackSize.y, mSizeConstraints.mMinSize.height)); 1.5115 + mmi->ptMaxTrackSize.x = std::min((int32_t)mmi->ptMaxTrackSize.x, mSizeConstraints.mMaxSize.width); 1.5116 + mmi->ptMaxTrackSize.y = std::min((int32_t)mmi->ptMaxTrackSize.y, mSizeConstraints.mMaxSize.height); 1.5117 + } 1.5118 + break; 1.5119 + 1.5120 + case WM_SETFOCUS: 1.5121 + // If previous focused window isn't ours, it must have received the 1.5122 + // redirected message. So, we should forget it. 1.5123 + if (!WinUtils::IsOurProcessWindow(HWND(wParam))) { 1.5124 + RedirectedKeyDownMessageManager::Forget(); 1.5125 + } 1.5126 + if (sJustGotActivate) { 1.5127 + DispatchFocusToTopLevelWindow(true); 1.5128 + } 1.5129 + break; 1.5130 + 1.5131 + case WM_KILLFOCUS: 1.5132 + if (sJustGotDeactivate) { 1.5133 + DispatchFocusToTopLevelWindow(false); 1.5134 + } 1.5135 + break; 1.5136 + 1.5137 + case WM_WINDOWPOSCHANGED: 1.5138 + { 1.5139 + WINDOWPOS* wp = (LPWINDOWPOS)lParam; 1.5140 + OnWindowPosChanged(wp); 1.5141 + result = true; 1.5142 + } 1.5143 + break; 1.5144 + 1.5145 + case WM_INPUTLANGCHANGEREQUEST: 1.5146 + *aRetValue = TRUE; 1.5147 + result = false; 1.5148 + break; 1.5149 + 1.5150 + case WM_INPUTLANGCHANGE: 1.5151 + KeyboardLayout::GetInstance()-> 1.5152 + OnLayoutChange(reinterpret_cast<HKL>(lParam)); 1.5153 + result = false; // always pass to child window 1.5154 + break; 1.5155 + 1.5156 + case WM_DESTROYCLIPBOARD: 1.5157 + { 1.5158 + nsIClipboard* clipboard; 1.5159 + nsresult rv = CallGetService(kCClipboardCID, &clipboard); 1.5160 + if(NS_SUCCEEDED(rv)) { 1.5161 + clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard); 1.5162 + NS_RELEASE(clipboard); 1.5163 + } 1.5164 + } 1.5165 + break; 1.5166 + 1.5167 +#ifdef ACCESSIBILITY 1.5168 + case WM_GETOBJECT: 1.5169 + { 1.5170 + *aRetValue = 0; 1.5171 + // Do explicit casting to make it working on 64bit systems (see bug 649236 1.5172 + // for details). 1.5173 + DWORD objId = static_cast<DWORD>(lParam); 1.5174 + if (objId == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically 1.5175 + a11y::Accessible* rootAccessible = GetAccessible(); // Held by a11y cache 1.5176 + if (rootAccessible) { 1.5177 + IAccessible *msaaAccessible = nullptr; 1.5178 + rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref 1.5179 + if (msaaAccessible) { 1.5180 + *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref 1.5181 + msaaAccessible->Release(); // release extra addref 1.5182 + result = true; // We handled the WM_GETOBJECT message 1.5183 + } 1.5184 + } 1.5185 + } 1.5186 + } 1.5187 +#endif 1.5188 + 1.5189 + case WM_SYSCOMMAND: 1.5190 + { 1.5191 + WPARAM filteredWParam = (wParam &0xFFF0); 1.5192 + // prevent Windows from trimming the working set. bug 76831 1.5193 + if (!sTrimOnMinimize && filteredWParam == SC_MINIMIZE) { 1.5194 + ::ShowWindow(mWnd, SW_SHOWMINIMIZED); 1.5195 + result = true; 1.5196 + } 1.5197 + 1.5198 + // Handle the system menu manually when we're in full screen mode 1.5199 + // so we can set the appropriate options. 1.5200 + if (filteredWParam == SC_KEYMENU && lParam == VK_SPACE && 1.5201 + mSizeMode == nsSizeMode_Fullscreen) { 1.5202 + DisplaySystemMenu(mWnd, mSizeMode, mIsRTL, 1.5203 + MOZ_SYSCONTEXT_X_POS, 1.5204 + MOZ_SYSCONTEXT_Y_POS); 1.5205 + result = true; 1.5206 + } 1.5207 + } 1.5208 + break; 1.5209 + 1.5210 + case WM_DWMCOMPOSITIONCHANGED: 1.5211 + // First, update the compositor state to latest one. All other methods 1.5212 + // should use same state as here for consistency painting. 1.5213 + nsUXThemeData::CheckForCompositor(true); 1.5214 + 1.5215 + UpdateNonClientMargins(); 1.5216 + BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED); 1.5217 + NotifyThemeChanged(); 1.5218 + UpdateGlass(); 1.5219 + Invalidate(true, true, true); 1.5220 + break; 1.5221 + 1.5222 + case WM_UPDATEUISTATE: 1.5223 + { 1.5224 + // If the UI state has changed, fire an event so the UI updates the 1.5225 + // keyboard cues based on the system setting and how the window was 1.5226 + // opened. For example, a dialog opened via a keyboard press on a button 1.5227 + // should enable cues, whereas the same dialog opened via a mouse click of 1.5228 + // the button should not. 1.5229 + int32_t action = LOWORD(wParam); 1.5230 + if (action == UIS_SET || action == UIS_CLEAR) { 1.5231 + int32_t flags = HIWORD(wParam); 1.5232 + UIStateChangeType showAccelerators = UIStateChangeType_NoChange; 1.5233 + UIStateChangeType showFocusRings = UIStateChangeType_NoChange; 1.5234 + if (flags & UISF_HIDEACCEL) 1.5235 + showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set; 1.5236 + if (flags & UISF_HIDEFOCUS) 1.5237 + showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set; 1.5238 + NotifyUIStateChanged(showAccelerators, showFocusRings); 1.5239 + } 1.5240 + 1.5241 + break; 1.5242 + } 1.5243 + 1.5244 + /* Gesture support events */ 1.5245 + case WM_TABLET_QUERYSYSTEMGESTURESTATUS: 1.5246 + // According to MS samples, this must be handled to enable 1.5247 + // rotational support in multi-touch drivers. 1.5248 + result = true; 1.5249 + *aRetValue = TABLET_ROTATE_GESTURE_ENABLE; 1.5250 + break; 1.5251 + 1.5252 + case WM_TOUCH: 1.5253 + result = OnTouch(wParam, lParam); 1.5254 + if (result) { 1.5255 + *aRetValue = 0; 1.5256 + } 1.5257 + break; 1.5258 + 1.5259 + case WM_GESTURE: 1.5260 + result = OnGesture(wParam, lParam); 1.5261 + break; 1.5262 + 1.5263 + case WM_GESTURENOTIFY: 1.5264 + { 1.5265 + if (mWindowType != eWindowType_invisible && 1.5266 + mWindowType != eWindowType_plugin) { 1.5267 + // A GestureNotify event is dispatched to decide which single-finger panning 1.5268 + // direction should be active (including none) and if pan feedback should 1.5269 + // be displayed. Java and plugin windows can make their own calls. 1.5270 + if (gIsPointerEventsEnabled) { 1.5271 + result = false; 1.5272 + break; 1.5273 + } 1.5274 + 1.5275 + GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam; 1.5276 + nsPointWin touchPoint; 1.5277 + touchPoint = gestureinfo->ptsLocation; 1.5278 + touchPoint.ScreenToClient(mWnd); 1.5279 + WidgetGestureNotifyEvent gestureNotifyEvent(true, 1.5280 + NS_GESTURENOTIFY_EVENT_START, this); 1.5281 + gestureNotifyEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(touchPoint); 1.5282 + nsEventStatus status; 1.5283 + DispatchEvent(&gestureNotifyEvent, status); 1.5284 + mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback; 1.5285 + if (!mTouchWindow) 1.5286 + mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection); 1.5287 + } 1.5288 + result = false; //should always bubble to DefWindowProc 1.5289 + } 1.5290 + break; 1.5291 + 1.5292 + case WM_CLEAR: 1.5293 + { 1.5294 + WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_DELETE, this); 1.5295 + DispatchWindowEvent(&command); 1.5296 + result = true; 1.5297 + } 1.5298 + break; 1.5299 + 1.5300 + case WM_CUT: 1.5301 + { 1.5302 + WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_CUT, this); 1.5303 + DispatchWindowEvent(&command); 1.5304 + result = true; 1.5305 + } 1.5306 + break; 1.5307 + 1.5308 + case WM_COPY: 1.5309 + { 1.5310 + WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_COPY, this); 1.5311 + DispatchWindowEvent(&command); 1.5312 + result = true; 1.5313 + } 1.5314 + break; 1.5315 + 1.5316 + case WM_PASTE: 1.5317 + { 1.5318 + WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_PASTE, this); 1.5319 + DispatchWindowEvent(&command); 1.5320 + result = true; 1.5321 + } 1.5322 + break; 1.5323 + 1.5324 + case EM_UNDO: 1.5325 + { 1.5326 + WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_UNDO, this); 1.5327 + DispatchWindowEvent(&command); 1.5328 + *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled); 1.5329 + result = true; 1.5330 + } 1.5331 + break; 1.5332 + 1.5333 + case EM_REDO: 1.5334 + { 1.5335 + WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_REDO, this); 1.5336 + DispatchWindowEvent(&command); 1.5337 + *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled); 1.5338 + result = true; 1.5339 + } 1.5340 + break; 1.5341 + 1.5342 + case EM_CANPASTE: 1.5343 + { 1.5344 + // Support EM_CANPASTE message only when wParam isn't specified or 1.5345 + // is plain text format. 1.5346 + if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) { 1.5347 + WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_PASTE, 1.5348 + this, true); 1.5349 + DispatchWindowEvent(&command); 1.5350 + *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled); 1.5351 + result = true; 1.5352 + } 1.5353 + } 1.5354 + break; 1.5355 + 1.5356 + case EM_CANUNDO: 1.5357 + { 1.5358 + WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_UNDO, 1.5359 + this, true); 1.5360 + DispatchWindowEvent(&command); 1.5361 + *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled); 1.5362 + result = true; 1.5363 + } 1.5364 + break; 1.5365 + 1.5366 + case EM_CANREDO: 1.5367 + { 1.5368 + WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_REDO, 1.5369 + this, true); 1.5370 + DispatchWindowEvent(&command); 1.5371 + *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled); 1.5372 + result = true; 1.5373 + } 1.5374 + break; 1.5375 + 1.5376 + default: 1.5377 + { 1.5378 + if (msg == nsAppShell::GetTaskbarButtonCreatedMessage()) 1.5379 + SetHasTaskbarIconBeenCreated(); 1.5380 + if (msg == sOOPPPluginFocusEvent) { 1.5381 + if (wParam == 1) { 1.5382 + // With OOPP, the plugin window exists in another process and is a child of 1.5383 + // this window. This window is a placeholder plugin window for the dom. We 1.5384 + // receive this event when the child window receives focus. (sent from 1.5385 + // PluginInstanceParent.cpp) 1.5386 + ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp 1.5387 + } else { 1.5388 + // WM_KILLFOCUS was received by the child process. 1.5389 + if (sJustGotDeactivate) { 1.5390 + DispatchFocusToTopLevelWindow(false); 1.5391 + } 1.5392 + } 1.5393 + } 1.5394 + } 1.5395 + break; 1.5396 + case WM_SETTINGCHANGE: 1.5397 + if (IsWin8OrLater() && lParam && 1.5398 + !wcsicmp(L"ConvertibleSlateMode", (wchar_t*)lParam)) { 1.5399 + // If we're switching into slate mode, switch to Metro for hardware 1.5400 + // that supports this feature if the pref is set. 1.5401 + if (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0 && 1.5402 + Preferences::GetBool("browser.shell.desktop-auto-switch-enabled", 1.5403 + false)) { 1.5404 + nsCOMPtr<nsIAppStartup> appStartup(do_GetService(NS_APPSTARTUP_CONTRACTID)); 1.5405 + if (appStartup) { 1.5406 + appStartup->Quit(nsIAppStartup::eForceQuit | 1.5407 + nsIAppStartup::eRestartTouchEnvironment); 1.5408 + } 1.5409 + } 1.5410 + } 1.5411 + break; 1.5412 + 1.5413 + } 1.5414 + 1.5415 + //*aRetValue = result; 1.5416 + if (mWnd) { 1.5417 + return result; 1.5418 + } 1.5419 + else { 1.5420 + //Events which caused mWnd destruction and aren't consumed 1.5421 + //will crash during the Windows default processing. 1.5422 + return true; 1.5423 + } 1.5424 +} 1.5425 + 1.5426 +/************************************************************** 1.5427 + * 1.5428 + * SECTION: Broadcast messaging 1.5429 + * 1.5430 + * Broadcast messages to all windows. 1.5431 + * 1.5432 + **************************************************************/ 1.5433 + 1.5434 +// Enumerate all child windows sending aMsg to each of them 1.5435 +BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg) 1.5436 +{ 1.5437 + WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC); 1.5438 + if (winProc == &nsWindow::WindowProc) { 1.5439 + // it's one of our windows so go ahead and send a message to it 1.5440 + ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0); 1.5441 + } 1.5442 + return TRUE; 1.5443 +} 1.5444 + 1.5445 +// Enumerate all top level windows specifying that the children of each 1.5446 +// top level window should be enumerated. Do *not* send the message to 1.5447 +// each top level window since it is assumed that the toolkit will send 1.5448 +// aMsg to them directly. 1.5449 +BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg) 1.5450 +{ 1.5451 + // Iterate each of aTopWindows child windows sending the aMsg 1.5452 + // to each of them. 1.5453 + ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg); 1.5454 + return TRUE; 1.5455 +} 1.5456 + 1.5457 +/************************************************************** 1.5458 + * 1.5459 + * SECTION: Event processing helpers 1.5460 + * 1.5461 + * Special processing for certain event types and 1.5462 + * synthesized events. 1.5463 + * 1.5464 + **************************************************************/ 1.5465 + 1.5466 +int32_t 1.5467 +nsWindow::ClientMarginHitTestPoint(int32_t mx, int32_t my) 1.5468 +{ 1.5469 + if (mSizeMode == nsSizeMode_Minimized || 1.5470 + mSizeMode == nsSizeMode_Fullscreen) { 1.5471 + return HTCLIENT; 1.5472 + } 1.5473 + 1.5474 + // Calculations are done in screen coords 1.5475 + RECT winRect; 1.5476 + GetWindowRect(mWnd, &winRect); 1.5477 + 1.5478 + // hit return constants: 1.5479 + // HTBORDER - non-resizable border 1.5480 + // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border 1.5481 + // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner 1.5482 + // HTTOPLEFT, HTTOPRIGHT - resizable corner 1.5483 + // HTCAPTION - general title bar area 1.5484 + // HTCLIENT - area considered the client 1.5485 + // HTCLOSE - hovering over the close button 1.5486 + // HTMAXBUTTON - maximize button 1.5487 + // HTMINBUTTON - minimize button 1.5488 + 1.5489 + int32_t testResult = HTCLIENT; 1.5490 + 1.5491 + bool isResizable = (mBorderStyle & (eBorderStyle_all | 1.5492 + eBorderStyle_resizeh | 1.5493 + eBorderStyle_default)) > 0 ? true : false; 1.5494 + if (mSizeMode == nsSizeMode_Maximized) 1.5495 + isResizable = false; 1.5496 + 1.5497 + // Ensure being accessible to borders of window. Even if contents are in 1.5498 + // this area, the area must behave as border. 1.5499 + nsIntMargin nonClientSize(std::max(mCaptionHeight - mNonClientOffset.top, 1.5500 + kResizableBorderMinSize), 1.5501 + std::max(mHorResizeMargin - mNonClientOffset.right, 1.5502 + kResizableBorderMinSize), 1.5503 + std::max(mVertResizeMargin - mNonClientOffset.bottom, 1.5504 + kResizableBorderMinSize), 1.5505 + std::max(mHorResizeMargin - mNonClientOffset.left, 1.5506 + kResizableBorderMinSize)); 1.5507 + 1.5508 + bool allowContentOverride = mSizeMode == nsSizeMode_Maximized || 1.5509 + (mx >= winRect.left + nonClientSize.left && 1.5510 + mx <= winRect.right - nonClientSize.right && 1.5511 + my >= winRect.top + nonClientSize.top && 1.5512 + my <= winRect.bottom - nonClientSize.bottom); 1.5513 + 1.5514 + // The border size. If there is no content under mouse cursor, the border 1.5515 + // size should be larger than the values in system settings. Otherwise, 1.5516 + // contents under the mouse cursor should be able to override the behavior. 1.5517 + // E.g., user must expect that Firefox button always opens the popup menu 1.5518 + // even when the user clicks on the above edge of it. 1.5519 + nsIntMargin borderSize(std::max(nonClientSize.top, mVertResizeMargin), 1.5520 + std::max(nonClientSize.right, mHorResizeMargin), 1.5521 + std::max(nonClientSize.bottom, mVertResizeMargin), 1.5522 + std::max(nonClientSize.left, mHorResizeMargin)); 1.5523 + 1.5524 + bool top = false; 1.5525 + bool bottom = false; 1.5526 + bool left = false; 1.5527 + bool right = false; 1.5528 + 1.5529 + if (my >= winRect.top && my < winRect.top + borderSize.top) { 1.5530 + top = true; 1.5531 + } else if (my <= winRect.bottom && my > winRect.bottom - borderSize.bottom) { 1.5532 + bottom = true; 1.5533 + } 1.5534 + 1.5535 + // (the 2x case here doubles the resize area for corners) 1.5536 + int multiplier = (top || bottom) ? 2 : 1; 1.5537 + if (mx >= winRect.left && 1.5538 + mx < winRect.left + (multiplier * borderSize.left)) { 1.5539 + left = true; 1.5540 + } else if (mx <= winRect.right && 1.5541 + mx > winRect.right - (multiplier * borderSize.right)) { 1.5542 + right = true; 1.5543 + } 1.5544 + 1.5545 + if (isResizable) { 1.5546 + if (top) { 1.5547 + testResult = HTTOP; 1.5548 + if (left) 1.5549 + testResult = HTTOPLEFT; 1.5550 + else if (right) 1.5551 + testResult = HTTOPRIGHT; 1.5552 + } else if (bottom) { 1.5553 + testResult = HTBOTTOM; 1.5554 + if (left) 1.5555 + testResult = HTBOTTOMLEFT; 1.5556 + else if (right) 1.5557 + testResult = HTBOTTOMRIGHT; 1.5558 + } else { 1.5559 + if (left) 1.5560 + testResult = HTLEFT; 1.5561 + if (right) 1.5562 + testResult = HTRIGHT; 1.5563 + } 1.5564 + } else { 1.5565 + if (top) 1.5566 + testResult = HTCAPTION; 1.5567 + else if (bottom || left || right) 1.5568 + testResult = HTBORDER; 1.5569 + } 1.5570 + 1.5571 + if (!sIsInMouseCapture && allowContentOverride) { 1.5572 + POINT pt = { mx, my }; 1.5573 + ::ScreenToClient(mWnd, &pt); 1.5574 + if (pt.x == mCachedHitTestPoint.x && pt.y == mCachedHitTestPoint.y && 1.5575 + TimeStamp::Now() - mCachedHitTestTime < TimeDuration::FromMilliseconds(HITTEST_CACHE_LIFETIME_MS)) { 1.5576 + testResult = mCachedHitTestResult; 1.5577 + } else { 1.5578 + WidgetMouseEvent event(true, NS_MOUSE_MOZHITTEST, this, 1.5579 + WidgetMouseEvent::eReal, 1.5580 + WidgetMouseEvent::eNormal); 1.5581 + event.refPoint = LayoutDeviceIntPoint(pt.x, pt.y); 1.5582 + event.inputSource = MOUSE_INPUT_SOURCE(); 1.5583 + event.mFlags.mOnlyChromeDispatch = true; 1.5584 + bool result = DispatchWindowEvent(&event); 1.5585 + if (result) { 1.5586 + // The mouse is over a blank area 1.5587 + testResult = testResult == HTCLIENT ? HTCAPTION : testResult; 1.5588 + 1.5589 + } else { 1.5590 + // There's content over the mouse pointer. Set HTCLIENT 1.5591 + // to possibly override a resizer border. 1.5592 + testResult = HTCLIENT; 1.5593 + } 1.5594 + mCachedHitTestPoint = pt; 1.5595 + mCachedHitTestTime = TimeStamp::Now(); 1.5596 + mCachedHitTestResult = testResult; 1.5597 + } 1.5598 + } 1.5599 + 1.5600 + return testResult; 1.5601 +} 1.5602 + 1.5603 +void nsWindow::PostSleepWakeNotification(const bool aIsSleepMode) 1.5604 +{ 1.5605 + if (aIsSleepMode == gIsSleepMode) 1.5606 + return; 1.5607 + 1.5608 + gIsSleepMode = aIsSleepMode; 1.5609 + 1.5610 + nsCOMPtr<nsIObserverService> observerService = 1.5611 + mozilla::services::GetObserverService(); 1.5612 + if (observerService) 1.5613 + observerService->NotifyObservers(nullptr, 1.5614 + aIsSleepMode ? NS_WIDGET_SLEEP_OBSERVER_TOPIC : 1.5615 + NS_WIDGET_WAKE_OBSERVER_TOPIC, nullptr); 1.5616 +} 1.5617 + 1.5618 +LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, bool *aEventDispatched) 1.5619 +{ 1.5620 + if (IMEHandler::IsComposingOn(this)) { 1.5621 + IMEHandler::NotifyIME(this, REQUEST_TO_COMMIT_COMPOSITION); 1.5622 + } 1.5623 + // These must be checked here too as a lone WM_CHAR could be received 1.5624 + // if a child window didn't handle it (for example Alt+Space in a content 1.5625 + // window) 1.5626 + ModifierKeyState modKeyState; 1.5627 + NativeKey nativeKey(this, aMsg, modKeyState); 1.5628 + return static_cast<LRESULT>(nativeKey.HandleCharMessage(aMsg, 1.5629 + aEventDispatched)); 1.5630 +} 1.5631 + 1.5632 +LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, bool *aEventDispatched) 1.5633 +{ 1.5634 + if (IMEHandler::IsComposingOn(this)) { 1.5635 + return 0; 1.5636 + } 1.5637 + 1.5638 + ModifierKeyState modKeyState; 1.5639 + NativeKey nativeKey(this, aMsg, modKeyState); 1.5640 + return static_cast<LRESULT>(nativeKey.HandleKeyUpMessage(aEventDispatched)); 1.5641 +} 1.5642 + 1.5643 +LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg, 1.5644 + bool *aEventDispatched) 1.5645 +{ 1.5646 + // If this method doesn't call NativeKey::HandleKeyDownMessage(), this method 1.5647 + // must clean up the redirected message information itself. For more 1.5648 + // information, see above comment of 1.5649 + // RedirectedKeyDownMessageManager::AutoFlusher class definition in 1.5650 + // KeyboardLayout.h. 1.5651 + RedirectedKeyDownMessageManager::AutoFlusher redirectedMsgFlusher(this, aMsg); 1.5652 + 1.5653 + ModifierKeyState modKeyState; 1.5654 + 1.5655 + LRESULT result = 0; 1.5656 + if (!IMEHandler::IsComposingOn(this)) { 1.5657 + NativeKey nativeKey(this, aMsg, modKeyState); 1.5658 + result = 1.5659 + static_cast<LRESULT>(nativeKey.HandleKeyDownMessage(aEventDispatched)); 1.5660 + // HandleKeyDownMessage cleaned up the redirected message information 1.5661 + // itself, so, we should do nothing. 1.5662 + redirectedMsgFlusher.Cancel(); 1.5663 + } 1.5664 + 1.5665 + if (aMsg.wParam == VK_MENU || 1.5666 + (aMsg.wParam == VK_F10 && !modKeyState.IsShift())) { 1.5667 + // We need to let Windows handle this keypress, 1.5668 + // by returning false, if there's a native menu 1.5669 + // bar somewhere in our containing window hierarchy. 1.5670 + // Otherwise we handle the keypress and don't pass 1.5671 + // it on to Windows, by returning true. 1.5672 + bool hasNativeMenu = false; 1.5673 + HWND hWnd = mWnd; 1.5674 + while (hWnd) { 1.5675 + if (::GetMenu(hWnd)) { 1.5676 + hasNativeMenu = true; 1.5677 + break; 1.5678 + } 1.5679 + hWnd = ::GetParent(hWnd); 1.5680 + } 1.5681 + result = !hasNativeMenu; 1.5682 + } 1.5683 + 1.5684 + return result; 1.5685 +} 1.5686 + 1.5687 +nsresult 1.5688 +nsWindow::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout, 1.5689 + int32_t aNativeKeyCode, 1.5690 + uint32_t aModifierFlags, 1.5691 + const nsAString& aCharacters, 1.5692 + const nsAString& aUnmodifiedCharacters) 1.5693 +{ 1.5694 + KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance(); 1.5695 + return keyboardLayout->SynthesizeNativeKeyEvent( 1.5696 + this, aNativeKeyboardLayout, aNativeKeyCode, aModifierFlags, 1.5697 + aCharacters, aUnmodifiedCharacters); 1.5698 +} 1.5699 + 1.5700 +nsresult 1.5701 +nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint, 1.5702 + uint32_t aNativeMessage, 1.5703 + uint32_t aModifierFlags) 1.5704 +{ 1.5705 + ::SetCursorPos(aPoint.x, aPoint.y); 1.5706 + 1.5707 + INPUT input; 1.5708 + memset(&input, 0, sizeof(input)); 1.5709 + 1.5710 + input.type = INPUT_MOUSE; 1.5711 + input.mi.dwFlags = aNativeMessage; 1.5712 + ::SendInput(1, &input, sizeof(INPUT)); 1.5713 + 1.5714 + return NS_OK; 1.5715 +} 1.5716 + 1.5717 +nsresult 1.5718 +nsWindow::SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint, 1.5719 + uint32_t aNativeMessage, 1.5720 + double aDeltaX, 1.5721 + double aDeltaY, 1.5722 + double aDeltaZ, 1.5723 + uint32_t aModifierFlags, 1.5724 + uint32_t aAdditionalFlags) 1.5725 +{ 1.5726 + return MouseScrollHandler::SynthesizeNativeMouseScrollEvent( 1.5727 + this, aPoint, aNativeMessage, 1.5728 + (aNativeMessage == WM_MOUSEWHEEL || aNativeMessage == WM_VSCROLL) ? 1.5729 + static_cast<int32_t>(aDeltaY) : static_cast<int32_t>(aDeltaX), 1.5730 + aModifierFlags, aAdditionalFlags); 1.5731 +} 1.5732 + 1.5733 +/************************************************************** 1.5734 + * 1.5735 + * SECTION: OnXXX message handlers 1.5736 + * 1.5737 + * For message handlers that need to be broken out or 1.5738 + * implemented in specific platform code. 1.5739 + * 1.5740 + **************************************************************/ 1.5741 + 1.5742 +void nsWindow::OnWindowPosChanged(WINDOWPOS* wp) 1.5743 +{ 1.5744 + if (wp == nullptr) 1.5745 + return; 1.5746 + 1.5747 +#ifdef WINSTATE_DEBUG_OUTPUT 1.5748 + if (mWnd == WinUtils::GetTopLevelHWND(mWnd)) { 1.5749 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("*** OnWindowPosChanged: [ top] ")); 1.5750 + } else { 1.5751 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("*** OnWindowPosChanged: [child] ")); 1.5752 + } 1.5753 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("WINDOWPOS flags:")); 1.5754 + if (wp->flags & SWP_FRAMECHANGED) { 1.5755 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_FRAMECHANGED ")); 1.5756 + } 1.5757 + if (wp->flags & SWP_SHOWWINDOW) { 1.5758 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_SHOWWINDOW ")); 1.5759 + } 1.5760 + if (wp->flags & SWP_NOSIZE) { 1.5761 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_NOSIZE ")); 1.5762 + } 1.5763 + if (wp->flags & SWP_HIDEWINDOW) { 1.5764 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_HIDEWINDOW ")); 1.5765 + } 1.5766 + if (wp->flags & SWP_NOZORDER) { 1.5767 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_NOZORDER ")); 1.5768 + } 1.5769 + if (wp->flags & SWP_NOACTIVATE) { 1.5770 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_NOACTIVATE ")); 1.5771 + } 1.5772 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("\n")); 1.5773 +#endif 1.5774 + 1.5775 + // Handle window size mode changes 1.5776 + if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) { 1.5777 + 1.5778 + // Bug 566135 - Windows theme code calls show window on SW_SHOWMINIMIZED 1.5779 + // windows when fullscreen games disable desktop composition. If we're 1.5780 + // minimized and not being activated, ignore the event and let windows 1.5781 + // handle it. 1.5782 + if (mSizeMode == nsSizeMode_Minimized && (wp->flags & SWP_NOACTIVATE)) 1.5783 + return; 1.5784 + 1.5785 + WINDOWPLACEMENT pl; 1.5786 + pl.length = sizeof(pl); 1.5787 + ::GetWindowPlacement(mWnd, &pl); 1.5788 + 1.5789 + // Windows has just changed the size mode of this window. The call to 1.5790 + // SizeModeChanged will trigger a call into SetSizeMode where we will 1.5791 + // set the min/max window state again or for nsSizeMode_Normal, call 1.5792 + // SetWindow with a parameter of SW_RESTORE. There's no need however as 1.5793 + // this window's mode has already changed. Updating mSizeMode here 1.5794 + // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related 1.5795 + // to window docking. (bug 489258) 1.5796 + if (pl.showCmd == SW_SHOWMAXIMIZED) 1.5797 + mSizeMode = (mFullscreenMode ? nsSizeMode_Fullscreen : nsSizeMode_Maximized); 1.5798 + else if (pl.showCmd == SW_SHOWMINIMIZED) 1.5799 + mSizeMode = nsSizeMode_Minimized; 1.5800 + else if (mFullscreenMode) 1.5801 + mSizeMode = nsSizeMode_Fullscreen; 1.5802 + else 1.5803 + mSizeMode = nsSizeMode_Normal; 1.5804 + 1.5805 + // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See 1.5806 + // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This 1.5807 + // prevents the working set from being trimmed but keeps the window active. 1.5808 + // After the window is minimized, we need to do some touch up work on the 1.5809 + // active window. (bugs 76831 & 499816) 1.5810 + if (!sTrimOnMinimize && nsSizeMode_Minimized == mSizeMode) 1.5811 + ActivateOtherWindowHelper(mWnd); 1.5812 + 1.5813 +#ifdef WINSTATE_DEBUG_OUTPUT 1.5814 + switch (mSizeMode) { 1.5815 + case nsSizeMode_Normal: 1.5816 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.5817 + ("*** mSizeMode: nsSizeMode_Normal\n")); 1.5818 + break; 1.5819 + case nsSizeMode_Minimized: 1.5820 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.5821 + ("*** mSizeMode: nsSizeMode_Minimized\n")); 1.5822 + break; 1.5823 + case nsSizeMode_Maximized: 1.5824 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.5825 + ("*** mSizeMode: nsSizeMode_Maximized\n")); 1.5826 + break; 1.5827 + default: 1.5828 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("*** mSizeMode: ??????\n")); 1.5829 + break; 1.5830 + }; 1.5831 +#endif 1.5832 + 1.5833 + if (mWidgetListener) 1.5834 + mWidgetListener->SizeModeChanged(mSizeMode); 1.5835 + 1.5836 + // If window was restored, window activation was bypassed during the 1.5837 + // SetSizeMode call originating from OnWindowPosChanging to avoid saving 1.5838 + // pre-restore attributes. Force activation now to get correct attributes. 1.5839 + if (mLastSizeMode != nsSizeMode_Normal && mSizeMode == nsSizeMode_Normal) 1.5840 + DispatchFocusToTopLevelWindow(true); 1.5841 + 1.5842 + // Skip window size change events below on minimization. 1.5843 + if (mSizeMode == nsSizeMode_Minimized) 1.5844 + return; 1.5845 + } 1.5846 + 1.5847 + // Handle window position changes 1.5848 + if (!(wp->flags & SWP_NOMOVE)) { 1.5849 + mBounds.x = wp->x; 1.5850 + mBounds.y = wp->y; 1.5851 + 1.5852 + NotifyWindowMoved(wp->x, wp->y); 1.5853 + } 1.5854 + 1.5855 + // Handle window size changes 1.5856 + if (!(wp->flags & SWP_NOSIZE)) { 1.5857 + RECT r; 1.5858 + int32_t newWidth, newHeight; 1.5859 + 1.5860 + ::GetWindowRect(mWnd, &r); 1.5861 + 1.5862 + newWidth = r.right - r.left; 1.5863 + newHeight = r.bottom - r.top; 1.5864 + nsIntRect rect(wp->x, wp->y, newWidth, newHeight); 1.5865 + 1.5866 +#ifdef MOZ_XUL 1.5867 + if (eTransparencyTransparent == mTransparencyMode) 1.5868 + ResizeTranslucentWindow(newWidth, newHeight); 1.5869 +#endif 1.5870 + 1.5871 + if (newWidth > mLastSize.width) 1.5872 + { 1.5873 + RECT drect; 1.5874 + 1.5875 + // getting wider 1.5876 + drect.left = wp->x + mLastSize.width; 1.5877 + drect.top = wp->y; 1.5878 + drect.right = drect.left + (newWidth - mLastSize.width); 1.5879 + drect.bottom = drect.top + newHeight; 1.5880 + 1.5881 + ::RedrawWindow(mWnd, &drect, nullptr, 1.5882 + RDW_INVALIDATE | 1.5883 + RDW_NOERASE | 1.5884 + RDW_NOINTERNALPAINT | 1.5885 + RDW_ERASENOW | 1.5886 + RDW_ALLCHILDREN); 1.5887 + } 1.5888 + if (newHeight > mLastSize.height) 1.5889 + { 1.5890 + RECT drect; 1.5891 + 1.5892 + // getting taller 1.5893 + drect.left = wp->x; 1.5894 + drect.top = wp->y + mLastSize.height; 1.5895 + drect.right = drect.left + newWidth; 1.5896 + drect.bottom = drect.top + (newHeight - mLastSize.height); 1.5897 + 1.5898 + ::RedrawWindow(mWnd, &drect, nullptr, 1.5899 + RDW_INVALIDATE | 1.5900 + RDW_NOERASE | 1.5901 + RDW_NOINTERNALPAINT | 1.5902 + RDW_ERASENOW | 1.5903 + RDW_ALLCHILDREN); 1.5904 + } 1.5905 + 1.5906 + mBounds.width = newWidth; 1.5907 + mBounds.height = newHeight; 1.5908 + mLastSize.width = newWidth; 1.5909 + mLastSize.height = newHeight; 1.5910 + 1.5911 +#ifdef WINSTATE_DEBUG_OUTPUT 1.5912 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.5913 + ("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, 1.5914 + newWidth, newHeight)); 1.5915 +#endif 1.5916 + 1.5917 + // If a maximized window is resized, recalculate the non-client margins. 1.5918 + if (mSizeMode == nsSizeMode_Maximized) { 1.5919 + if (UpdateNonClientMargins(nsSizeMode_Maximized, true)) { 1.5920 + // gecko resize event already sent by UpdateNonClientMargins. 1.5921 + return; 1.5922 + } 1.5923 + } 1.5924 + 1.5925 + // Recalculate the width and height based on the client area for gecko events. 1.5926 + if (::GetClientRect(mWnd, &r)) { 1.5927 + rect.width = r.right - r.left; 1.5928 + rect.height = r.bottom - r.top; 1.5929 + } 1.5930 + 1.5931 + // Send a gecko resize event 1.5932 + OnResize(rect); 1.5933 + } 1.5934 +} 1.5935 + 1.5936 +// static 1.5937 +void nsWindow::ActivateOtherWindowHelper(HWND aWnd) 1.5938 +{ 1.5939 + // Find the next window that is enabled, visible, and not minimized. 1.5940 + HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT); 1.5941 + while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) || 1.5942 + ::IsIconic(hwndBelow))) { 1.5943 + hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT); 1.5944 + } 1.5945 + 1.5946 + // Push ourselves to the bottom of the stack, then activate the 1.5947 + // next window. 1.5948 + ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0, 1.5949 + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); 1.5950 + if (hwndBelow) 1.5951 + ::SetForegroundWindow(hwndBelow); 1.5952 + 1.5953 + // Play the minimize sound while we're here, since that is also 1.5954 + // forgotten when we use SW_SHOWMINIMIZED. 1.5955 + nsCOMPtr<nsISound> sound(do_CreateInstance("@mozilla.org/sound;1")); 1.5956 + if (sound) { 1.5957 + sound->PlaySystemSound(NS_LITERAL_STRING("Minimize")); 1.5958 + } 1.5959 +} 1.5960 + 1.5961 +void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info) 1.5962 +{ 1.5963 + // Update non-client margins if the frame size is changing, and let the 1.5964 + // browser know we are changing size modes, so alternative css can kick in. 1.5965 + // If we're going into fullscreen mode, ignore this, since it'll reset 1.5966 + // margins to normal mode. 1.5967 + if ((info->flags & SWP_FRAMECHANGED && !(info->flags & SWP_NOSIZE)) && 1.5968 + mSizeMode != nsSizeMode_Fullscreen) { 1.5969 + WINDOWPLACEMENT pl; 1.5970 + pl.length = sizeof(pl); 1.5971 + ::GetWindowPlacement(mWnd, &pl); 1.5972 + nsSizeMode sizeMode; 1.5973 + if (pl.showCmd == SW_SHOWMAXIMIZED) 1.5974 + sizeMode = (mFullscreenMode ? nsSizeMode_Fullscreen : nsSizeMode_Maximized); 1.5975 + else if (pl.showCmd == SW_SHOWMINIMIZED) 1.5976 + sizeMode = nsSizeMode_Minimized; 1.5977 + else if (mFullscreenMode) 1.5978 + sizeMode = nsSizeMode_Fullscreen; 1.5979 + else 1.5980 + sizeMode = nsSizeMode_Normal; 1.5981 + 1.5982 + if (mWidgetListener) 1.5983 + mWidgetListener->SizeModeChanged(sizeMode); 1.5984 + 1.5985 + UpdateNonClientMargins(sizeMode, false); 1.5986 + } 1.5987 + 1.5988 + // enforce local z-order rules 1.5989 + if (!(info->flags & SWP_NOZORDER)) { 1.5990 + HWND hwndAfter = info->hwndInsertAfter; 1.5991 + 1.5992 + nsWindow *aboveWindow = 0; 1.5993 + nsWindowZ placement; 1.5994 + 1.5995 + if (hwndAfter == HWND_BOTTOM) 1.5996 + placement = nsWindowZBottom; 1.5997 + else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST) 1.5998 + placement = nsWindowZTop; 1.5999 + else { 1.6000 + placement = nsWindowZRelative; 1.6001 + aboveWindow = WinUtils::GetNSWindowPtr(hwndAfter); 1.6002 + } 1.6003 + 1.6004 + if (mWidgetListener) { 1.6005 + nsCOMPtr<nsIWidget> actualBelow = nullptr; 1.6006 + if (mWidgetListener->ZLevelChanged(false, &placement, 1.6007 + aboveWindow, getter_AddRefs(actualBelow))) { 1.6008 + if (placement == nsWindowZBottom) 1.6009 + info->hwndInsertAfter = HWND_BOTTOM; 1.6010 + else if (placement == nsWindowZTop) 1.6011 + info->hwndInsertAfter = HWND_TOP; 1.6012 + else { 1.6013 + info->hwndInsertAfter = (HWND)actualBelow->GetNativeData(NS_NATIVE_WINDOW); 1.6014 + } 1.6015 + } 1.6016 + } 1.6017 + } 1.6018 + // prevent rude external programs from making hidden window visible 1.6019 + if (mWindowType == eWindowType_invisible) 1.6020 + info->flags &= ~SWP_SHOWWINDOW; 1.6021 +} 1.6022 + 1.6023 +void nsWindow::UserActivity() 1.6024 +{ 1.6025 + // Check if we have the idle service, if not we try to get it. 1.6026 + if (!mIdleService) { 1.6027 + mIdleService = do_GetService("@mozilla.org/widget/idleservice;1"); 1.6028 + } 1.6029 + 1.6030 + // Check that we now have the idle service. 1.6031 + if (mIdleService) { 1.6032 + mIdleService->ResetIdleTimeOut(0); 1.6033 + } 1.6034 +} 1.6035 + 1.6036 +bool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam) 1.6037 +{ 1.6038 + uint32_t cInputs = LOWORD(wParam); 1.6039 + PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs]; 1.6040 + 1.6041 + if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) { 1.6042 + WidgetTouchEvent* touchEventToSend = nullptr; 1.6043 + WidgetTouchEvent* touchEndEventToSend = nullptr; 1.6044 + nsEventStatus status; 1.6045 + 1.6046 + // Walk across the touch point array processing each contact point 1.6047 + for (uint32_t i = 0; i < cInputs; i++) { 1.6048 + uint32_t msg; 1.6049 + 1.6050 + if (pInputs[i].dwFlags & (TOUCHEVENTF_DOWN | TOUCHEVENTF_MOVE)) { 1.6051 + // Create a standard touch event to send 1.6052 + if (!touchEventToSend) { 1.6053 + touchEventToSend = new WidgetTouchEvent(true, NS_TOUCH_MOVE, this); 1.6054 + touchEventToSend->time = ::GetMessageTime(); 1.6055 + ModifierKeyState modifierKeyState; 1.6056 + modifierKeyState.InitInputEvent(*touchEventToSend); 1.6057 + } 1.6058 + 1.6059 + // Pres shell expects this event to be a NS_TOUCH_START if new contact 1.6060 + // points have been added since the last event sent. 1.6061 + if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) { 1.6062 + touchEventToSend->message = msg = NS_TOUCH_START; 1.6063 + } else { 1.6064 + msg = NS_TOUCH_MOVE; 1.6065 + } 1.6066 + } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) { 1.6067 + // Pres shell expects removed contacts points to be delivered in a 1.6068 + // separate NS_TOUCH_END event containing only the contact points 1.6069 + // that were removed. 1.6070 + if (!touchEndEventToSend) { 1.6071 + touchEndEventToSend = new WidgetTouchEvent(true, NS_TOUCH_END, this); 1.6072 + touchEndEventToSend->time = ::GetMessageTime(); 1.6073 + ModifierKeyState modifierKeyState; 1.6074 + modifierKeyState.InitInputEvent(*touchEndEventToSend); 1.6075 + } 1.6076 + msg = NS_TOUCH_END; 1.6077 + } else { 1.6078 + // Filter out spurious Windows events we don't understand, like palm 1.6079 + // contact. 1.6080 + continue; 1.6081 + } 1.6082 + 1.6083 + // Setup the touch point we'll append to the touch event array 1.6084 + nsPointWin touchPoint; 1.6085 + touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x); 1.6086 + touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y); 1.6087 + touchPoint.ScreenToClient(mWnd); 1.6088 + nsRefPtr<Touch> touch = 1.6089 + new Touch(pInputs[i].dwID, 1.6090 + touchPoint, 1.6091 + /* radius, if known */ 1.6092 + pInputs[i].dwFlags & TOUCHINPUTMASKF_CONTACTAREA ? 1.6093 + nsIntPoint( 1.6094 + TOUCH_COORD_TO_PIXEL(pInputs[i].cxContact) / 2, 1.6095 + TOUCH_COORD_TO_PIXEL(pInputs[i].cyContact) / 2) : 1.6096 + nsIntPoint(1,1), 1.6097 + /* rotation angle and force */ 1.6098 + 0.0f, 0.0f); 1.6099 + 1.6100 + // Append to the appropriate event 1.6101 + if (msg == NS_TOUCH_START || msg == NS_TOUCH_MOVE) { 1.6102 + touchEventToSend->touches.AppendElement(touch); 1.6103 + } else { 1.6104 + touchEndEventToSend->touches.AppendElement(touch); 1.6105 + } 1.6106 + } 1.6107 + 1.6108 + // Dispatch touch start and move event if we have one. 1.6109 + if (touchEventToSend) { 1.6110 + DispatchEvent(touchEventToSend, status); 1.6111 + delete touchEventToSend; 1.6112 + } 1.6113 + 1.6114 + // Dispatch touch end event if we have one. 1.6115 + if (touchEndEventToSend) { 1.6116 + DispatchEvent(touchEndEventToSend, status); 1.6117 + delete touchEndEventToSend; 1.6118 + } 1.6119 + } 1.6120 + 1.6121 + delete [] pInputs; 1.6122 + mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam); 1.6123 + return true; 1.6124 +} 1.6125 + 1.6126 +static int32_t RoundDown(double aDouble) 1.6127 +{ 1.6128 + return aDouble > 0 ? static_cast<int32_t>(floor(aDouble)) : 1.6129 + static_cast<int32_t>(ceil(aDouble)); 1.6130 +} 1.6131 + 1.6132 +// Gesture event processing. Handles WM_GESTURE events. 1.6133 +bool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam) 1.6134 +{ 1.6135 + if (gIsPointerEventsEnabled) { 1.6136 + return false; 1.6137 + } 1.6138 + 1.6139 + // Treatment for pan events which translate into scroll events: 1.6140 + if (mGesture.IsPanEvent(lParam)) { 1.6141 + if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) ) 1.6142 + return false; // ignore 1.6143 + 1.6144 + nsEventStatus status; 1.6145 + 1.6146 + WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this); 1.6147 + 1.6148 + ModifierKeyState modifierKeyState; 1.6149 + modifierKeyState.InitInputEvent(wheelEvent); 1.6150 + 1.6151 + wheelEvent.button = 0; 1.6152 + wheelEvent.time = ::GetMessageTime(); 1.6153 + wheelEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 1.6154 + 1.6155 + bool endFeedback = true; 1.6156 + 1.6157 + if (mGesture.PanDeltaToPixelScroll(wheelEvent)) { 1.6158 + DispatchEvent(&wheelEvent, status); 1.6159 + } 1.6160 + 1.6161 + if (mDisplayPanFeedback) { 1.6162 + mGesture.UpdatePanFeedbackX(mWnd, 1.6163 + DeprecatedAbs(RoundDown(wheelEvent.overflowDeltaX)), 1.6164 + endFeedback); 1.6165 + mGesture.UpdatePanFeedbackY(mWnd, 1.6166 + DeprecatedAbs(RoundDown(wheelEvent.overflowDeltaY)), 1.6167 + endFeedback); 1.6168 + mGesture.PanFeedbackFinalize(mWnd, endFeedback); 1.6169 + } 1.6170 + 1.6171 + mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam); 1.6172 + 1.6173 + return true; 1.6174 + } 1.6175 + 1.6176 + // Other gestures translate into simple gesture events: 1.6177 + WidgetSimpleGestureEvent event(true, 0, this); 1.6178 + if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) { 1.6179 + return false; // fall through to DefWndProc 1.6180 + } 1.6181 + 1.6182 + // Polish up and send off the new event 1.6183 + ModifierKeyState modifierKeyState; 1.6184 + modifierKeyState.InitInputEvent(event); 1.6185 + event.button = 0; 1.6186 + event.time = ::GetMessageTime(); 1.6187 + event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 1.6188 + 1.6189 + nsEventStatus status; 1.6190 + DispatchEvent(&event, status); 1.6191 + if (status == nsEventStatus_eIgnore) { 1.6192 + return false; // Ignored, fall through 1.6193 + } 1.6194 + 1.6195 + // Only close this if we process and return true. 1.6196 + mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam); 1.6197 + 1.6198 + return true; // Handled 1.6199 +} 1.6200 + 1.6201 +static BOOL WINAPI EnumFirstChild(HWND hwnd, LPARAM lParam) 1.6202 +{ 1.6203 + *((HWND*)lParam) = hwnd; 1.6204 + return FALSE; 1.6205 +} 1.6206 + 1.6207 +static void InvalidatePluginAsWorkaround(nsWindow *aWindow, const nsIntRect &aRect) 1.6208 +{ 1.6209 + aWindow->Invalidate(aRect); 1.6210 + 1.6211 + // XXX - Even more evil workaround!! See bug 762948, flash's bottom 1.6212 + // level sandboxed window doesn't seem to get our invalidate. We send 1.6213 + // an invalidate to it manually. This is totally specialized for this 1.6214 + // bug, for other child window structures this will just be a more or 1.6215 + // less bogus invalidate but since that should not have any bad 1.6216 + // side-effects this will have to do for now. 1.6217 + HWND current = (HWND)aWindow->GetNativeData(NS_NATIVE_WINDOW); 1.6218 + 1.6219 + RECT windowRect; 1.6220 + RECT parentRect; 1.6221 + 1.6222 + ::GetWindowRect(current, &parentRect); 1.6223 + 1.6224 + HWND next = current; 1.6225 + 1.6226 + do { 1.6227 + current = next; 1.6228 + 1.6229 + ::EnumChildWindows(current, &EnumFirstChild, (LPARAM)&next); 1.6230 + 1.6231 + ::GetWindowRect(next, &windowRect); 1.6232 + // This is relative to the screen, adjust it to be relative to the 1.6233 + // window we're reconfiguring. 1.6234 + windowRect.left -= parentRect.left; 1.6235 + windowRect.top -= parentRect.top; 1.6236 + } while (next != current && windowRect.top == 0 && windowRect.left == 0); 1.6237 + 1.6238 + if (windowRect.top == 0 && windowRect.left == 0) { 1.6239 + RECT rect; 1.6240 + rect.left = aRect.x; 1.6241 + rect.top = aRect.y; 1.6242 + rect.right = aRect.XMost(); 1.6243 + rect.bottom = aRect.YMost(); 1.6244 + 1.6245 + ::InvalidateRect(next, &rect, FALSE); 1.6246 + } 1.6247 +} 1.6248 + 1.6249 +nsresult 1.6250 +nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations) 1.6251 +{ 1.6252 + // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos 1.6253 + // here, if that helps in some situations. So far I haven't seen a 1.6254 + // need. 1.6255 + for (uint32_t i = 0; i < aConfigurations.Length(); ++i) { 1.6256 + const Configuration& configuration = aConfigurations[i]; 1.6257 + nsWindow* w = static_cast<nsWindow*>(configuration.mChild); 1.6258 + NS_ASSERTION(w->GetParent() == this, 1.6259 + "Configured widget is not a child"); 1.6260 + nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, true); 1.6261 + NS_ENSURE_SUCCESS(rv, rv); 1.6262 + nsIntRect bounds; 1.6263 + w->GetBounds(bounds); 1.6264 + if (bounds.Size() != configuration.mBounds.Size()) { 1.6265 + w->Resize(configuration.mBounds.x, configuration.mBounds.y, 1.6266 + configuration.mBounds.width, configuration.mBounds.height, 1.6267 + true); 1.6268 + } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) { 1.6269 + w->Move(configuration.mBounds.x, configuration.mBounds.y); 1.6270 + 1.6271 + 1.6272 + if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() == 1.6273 + gfxWindowsPlatform::RENDER_DIRECT2D || 1.6274 + GetLayerManager()->GetBackendType() != LayersBackend::LAYERS_BASIC) { 1.6275 + // XXX - Workaround for Bug 587508. This will invalidate the part of the 1.6276 + // plugin window that might be touched by moving content somehow. The 1.6277 + // underlying problem should be found and fixed! 1.6278 + nsIntRegion r; 1.6279 + r.Sub(bounds, configuration.mBounds); 1.6280 + r.MoveBy(-bounds.x, 1.6281 + -bounds.y); 1.6282 + nsIntRect toInvalidate = r.GetBounds(); 1.6283 + 1.6284 + InvalidatePluginAsWorkaround(w, toInvalidate); 1.6285 + } 1.6286 + } 1.6287 + rv = w->SetWindowClipRegion(configuration.mClipRegion, false); 1.6288 + NS_ENSURE_SUCCESS(rv, rv); 1.6289 + } 1.6290 + return NS_OK; 1.6291 +} 1.6292 + 1.6293 +static HRGN 1.6294 +CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects) 1.6295 +{ 1.6296 + int32_t size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length(); 1.6297 + nsAutoTArray<uint8_t,100> buf; 1.6298 + buf.SetLength(size); 1.6299 + RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements()); 1.6300 + RECT* rects = reinterpret_cast<RECT*>(data->Buffer); 1.6301 + data->rdh.dwSize = sizeof(data->rdh); 1.6302 + data->rdh.iType = RDH_RECTANGLES; 1.6303 + data->rdh.nCount = aRects.Length(); 1.6304 + nsIntRect bounds; 1.6305 + for (uint32_t i = 0; i < aRects.Length(); ++i) { 1.6306 + const nsIntRect& r = aRects[i]; 1.6307 + bounds.UnionRect(bounds, r); 1.6308 + ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost()); 1.6309 + } 1.6310 + ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost()); 1.6311 + return ::ExtCreateRegion(nullptr, buf.Length(), data); 1.6312 +} 1.6313 + 1.6314 +static void 1.6315 +ArrayFromRegion(const nsIntRegion& aRegion, nsTArray<nsIntRect>& aRects) 1.6316 +{ 1.6317 + const nsIntRect* r; 1.6318 + for (nsIntRegionRectIterator iter(aRegion); (r = iter.Next());) { 1.6319 + aRects.AppendElement(*r); 1.6320 + } 1.6321 +} 1.6322 + 1.6323 +nsresult 1.6324 +nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects, 1.6325 + bool aIntersectWithExisting) 1.6326 +{ 1.6327 + if (!aIntersectWithExisting) { 1.6328 + if (!StoreWindowClipRegion(aRects)) 1.6329 + return NS_OK; 1.6330 + } else { 1.6331 + // In this case still early return if nothing changed. 1.6332 + if (mClipRects && mClipRectCount == aRects.Length() && 1.6333 + memcmp(mClipRects, 1.6334 + aRects.Elements(), 1.6335 + sizeof(nsIntRect)*mClipRectCount) == 0) { 1.6336 + return NS_OK; 1.6337 + } 1.6338 + 1.6339 + // get current rects 1.6340 + nsTArray<nsIntRect> currentRects; 1.6341 + GetWindowClipRegion(¤tRects); 1.6342 + // create region from them 1.6343 + nsIntRegion currentRegion = RegionFromArray(currentRects); 1.6344 + // create region from new rects 1.6345 + nsIntRegion newRegion = RegionFromArray(aRects); 1.6346 + // intersect regions 1.6347 + nsIntRegion intersection; 1.6348 + intersection.And(currentRegion, newRegion); 1.6349 + // create int rect array from intersection 1.6350 + nsTArray<nsIntRect> rects; 1.6351 + ArrayFromRegion(intersection, rects); 1.6352 + // store 1.6353 + if (!StoreWindowClipRegion(rects)) 1.6354 + return NS_OK; 1.6355 + } 1.6356 + 1.6357 + HRGN dest = CreateHRGNFromArray(aRects); 1.6358 + if (!dest) 1.6359 + return NS_ERROR_OUT_OF_MEMORY; 1.6360 + 1.6361 + if (aIntersectWithExisting) { 1.6362 + HRGN current = ::CreateRectRgn(0, 0, 0, 0); 1.6363 + if (current) { 1.6364 + if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) { 1.6365 + ::CombineRgn(dest, dest, current, RGN_AND); 1.6366 + } 1.6367 + ::DeleteObject(current); 1.6368 + } 1.6369 + } 1.6370 + 1.6371 + // If a plugin is not visible, especially if it is in a background tab, 1.6372 + // it should not be able to steal keyboard focus. This code checks whether 1.6373 + // the region that the plugin is being clipped to is NULLREGION. If it is, 1.6374 + // the plugin window gets disabled. 1.6375 + if(mWindowType == eWindowType_plugin) { 1.6376 + if(NULLREGION == ::CombineRgn(dest, dest, dest, RGN_OR)) { 1.6377 + ::ShowWindow(mWnd, SW_HIDE); 1.6378 + ::EnableWindow(mWnd, FALSE); 1.6379 + } else { 1.6380 + ::EnableWindow(mWnd, TRUE); 1.6381 + ::ShowWindow(mWnd, SW_SHOW); 1.6382 + } 1.6383 + } 1.6384 + if (!::SetWindowRgn(mWnd, dest, TRUE)) { 1.6385 + ::DeleteObject(dest); 1.6386 + return NS_ERROR_FAILURE; 1.6387 + } 1.6388 + return NS_OK; 1.6389 +} 1.6390 + 1.6391 +// WM_DESTROY event handler 1.6392 +void nsWindow::OnDestroy() 1.6393 +{ 1.6394 + mOnDestroyCalled = true; 1.6395 + 1.6396 + // Make sure we don't get destroyed in the process of tearing down. 1.6397 + nsCOMPtr<nsIWidget> kungFuDeathGrip(this); 1.6398 + 1.6399 + // Dispatch the destroy notification. 1.6400 + if (!mInDtor) 1.6401 + NotifyWindowDestroyed(); 1.6402 + 1.6403 + // Prevent the widget from sending additional events. 1.6404 + mWidgetListener = nullptr; 1.6405 + mAttachedWidgetListener = nullptr; 1.6406 + 1.6407 + // Free our subclass and clear |this| stored in the window props. We will no longer 1.6408 + // receive events from Windows after this point. 1.6409 + SubclassWindow(FALSE); 1.6410 + 1.6411 + // Once mWidgetListener is cleared and the subclass is reset, sCurrentWindow can be 1.6412 + // cleared. (It's used in tracking windows for mouse events.) 1.6413 + if (sCurrentWindow == this) 1.6414 + sCurrentWindow = nullptr; 1.6415 + 1.6416 + // Disconnects us from our parent, will call our GetParent(). 1.6417 + nsBaseWidget::Destroy(); 1.6418 + 1.6419 + // Release references to children, device context, toolkit, and app shell. 1.6420 + nsBaseWidget::OnDestroy(); 1.6421 + 1.6422 + // Clear our native parent handle. 1.6423 + // XXX Windows will take care of this in the proper order, and SetParent(nullptr)'s 1.6424 + // remove child on the parent already took place in nsBaseWidget's Destroy call above. 1.6425 + //SetParent(nullptr); 1.6426 + mParent = nullptr; 1.6427 + 1.6428 + // We have to destroy the native drag target before we null out our window pointer. 1.6429 + EnableDragDrop(false); 1.6430 + 1.6431 + // If we're going away and for some reason we're still the rollup widget, rollup and 1.6432 + // turn off capture. 1.6433 + nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener(); 1.6434 + nsCOMPtr<nsIWidget> rollupWidget; 1.6435 + if (rollupListener) { 1.6436 + rollupWidget = rollupListener->GetRollupWidget(); 1.6437 + } 1.6438 + if (this == rollupWidget) { 1.6439 + if ( rollupListener ) 1.6440 + rollupListener->Rollup(0, nullptr, nullptr); 1.6441 + CaptureRollupEvents(nullptr, false); 1.6442 + } 1.6443 + 1.6444 + IMEHandler::OnDestroyWindow(this); 1.6445 + 1.6446 + // Turn off mouse trails if enabled. 1.6447 + MouseTrailer* mtrailer = nsToolkit::gMouseTrailer; 1.6448 + if (mtrailer) { 1.6449 + if (mtrailer->GetMouseTrailerWindow() == mWnd) 1.6450 + mtrailer->DestroyTimer(); 1.6451 + 1.6452 + if (mtrailer->GetCaptureWindow() == mWnd) 1.6453 + mtrailer->SetCaptureWindow(nullptr); 1.6454 + } 1.6455 + 1.6456 + // Free GDI window class objects 1.6457 + if (mBrush) { 1.6458 + VERIFY(::DeleteObject(mBrush)); 1.6459 + mBrush = nullptr; 1.6460 + } 1.6461 + 1.6462 + 1.6463 + // Destroy any custom cursor resources. 1.6464 + if (mCursor == -1) 1.6465 + SetCursor(eCursor_standard); 1.6466 + 1.6467 +#ifdef MOZ_XUL 1.6468 + // Reset transparency 1.6469 + if (eTransparencyTransparent == mTransparencyMode) 1.6470 + SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque); 1.6471 +#endif 1.6472 + 1.6473 + // Finalize panning feedback to possibly restore window displacement 1.6474 + mGesture.PanFeedbackFinalize(mWnd, true); 1.6475 + 1.6476 + // Clear the main HWND. 1.6477 + mWnd = nullptr; 1.6478 +} 1.6479 + 1.6480 +// Send a resize message to the listener 1.6481 +bool nsWindow::OnResize(nsIntRect &aWindowRect) 1.6482 +{ 1.6483 + bool result = mWidgetListener ? 1.6484 + mWidgetListener->WindowResized(this, aWindowRect.width, aWindowRect.height) : false; 1.6485 + 1.6486 + // If there is an attached view, inform it as well as the normal widget listener. 1.6487 + if (mAttachedWidgetListener) { 1.6488 + return mAttachedWidgetListener->WindowResized(this, aWindowRect.width, aWindowRect.height); 1.6489 + } 1.6490 + 1.6491 + return result; 1.6492 +} 1.6493 + 1.6494 +bool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam) 1.6495 +{ 1.6496 + return true; 1.6497 +} 1.6498 + 1.6499 +// Can be overriden. Controls auto-erase of background. 1.6500 +bool nsWindow::AutoErase(HDC dc) 1.6501 +{ 1.6502 + return false; 1.6503 +} 1.6504 + 1.6505 +void 1.6506 +nsWindow::AllowD3D9Callback(nsWindow *aWindow) 1.6507 +{ 1.6508 + if (aWindow->mLayerManager && !aWindow->ShouldUseOffMainThreadCompositing()) { 1.6509 + aWindow->mLayerManager->Destroy(); 1.6510 + aWindow->mLayerManager = nullptr; 1.6511 + } 1.6512 +} 1.6513 + 1.6514 +void 1.6515 +nsWindow::AllowD3D9WithReinitializeCallback(nsWindow *aWindow) 1.6516 +{ 1.6517 + if (aWindow->mLayerManager && !aWindow->ShouldUseOffMainThreadCompositing()) { 1.6518 + aWindow->mLayerManager->Destroy(); 1.6519 + aWindow->mLayerManager = nullptr; 1.6520 + (void) aWindow->GetLayerManager(); 1.6521 + } 1.6522 +} 1.6523 + 1.6524 +void 1.6525 +nsWindow::StartAllowingD3D9(bool aReinitialize) 1.6526 +{ 1.6527 + sAllowD3D9 = true; 1.6528 + 1.6529 + LayerManagerPrefs prefs; 1.6530 + GetLayerManagerPrefs(&prefs); 1.6531 + if (prefs.mDisableAcceleration) { 1.6532 + // The guarantee here is, if there's *any* chance that after we 1.6533 + // throw out our layer managers we'd create at least one new, 1.6534 + // accelerated one, we *will* throw out all the current layer 1.6535 + // managers. We early-return here because currently, if 1.6536 + // |disableAcceleration|, we will always use basic managers and 1.6537 + // it's a waste to recreate them. If we're using OMTC we don't want to 1.6538 + // recreate out layer manager and its compositor either. This is even 1.6539 + // more wasteful. 1.6540 + // 1.6541 + // NB: the above implies that it's eminently possible for us to 1.6542 + // skip this early return but still recreate basic managers. 1.6543 + // That's OK. It's *not* OK to take this early return when we 1.6544 + // *might* have created an accelerated manager. 1.6545 + return; 1.6546 + } 1.6547 + 1.6548 + if (aReinitialize) { 1.6549 + EnumAllWindows(AllowD3D9WithReinitializeCallback); 1.6550 + } else { 1.6551 + EnumAllWindows(AllowD3D9Callback); 1.6552 + } 1.6553 +} 1.6554 + 1.6555 +bool 1.6556 +nsWindow::ShouldUseOffMainThreadCompositing() 1.6557 +{ 1.6558 + // We don't currently support using an accelerated layer manager with 1.6559 + // transparent windows so don't even try. I'm also not sure if we even 1.6560 + // want to support this case. See bug 593471 1.6561 + if (mTransparencyMode == eTransparencyTransparent) { 1.6562 + return false; 1.6563 + } 1.6564 + 1.6565 + return nsBaseWidget::ShouldUseOffMainThreadCompositing(); 1.6566 +} 1.6567 + 1.6568 +void 1.6569 +nsWindow::GetPreferredCompositorBackends(nsTArray<LayersBackend>& aHints) 1.6570 +{ 1.6571 + LayerManagerPrefs prefs; 1.6572 + GetLayerManagerPrefs(&prefs); 1.6573 + 1.6574 + // We don't currently support using an accelerated layer manager with 1.6575 + // transparent windows so don't even try. I'm also not sure if we even 1.6576 + // want to support this case. See bug 593471 1.6577 + if (!(prefs.mDisableAcceleration || 1.6578 + mTransparencyMode == eTransparencyTransparent)) { 1.6579 + if (prefs.mPreferOpenGL) { 1.6580 + aHints.AppendElement(LayersBackend::LAYERS_OPENGL); 1.6581 + } 1.6582 + if (!prefs.mPreferD3D9) { 1.6583 + aHints.AppendElement(LayersBackend::LAYERS_D3D11); 1.6584 + } 1.6585 + aHints.AppendElement(LayersBackend::LAYERS_D3D9); 1.6586 + } 1.6587 + aHints.AppendElement(LayersBackend::LAYERS_BASIC); 1.6588 +} 1.6589 + 1.6590 +void 1.6591 +nsWindow::WindowUsesOMTC() 1.6592 +{ 1.6593 + ULONG_PTR style = ::GetClassLongPtr(mWnd, GCL_STYLE); 1.6594 + if (!style) { 1.6595 + NS_WARNING("Could not get window class style"); 1.6596 + return; 1.6597 + } 1.6598 + style |= CS_HREDRAW | CS_VREDRAW; 1.6599 + DebugOnly<ULONG_PTR> result = ::SetClassLongPtr(mWnd, GCL_STYLE, style); 1.6600 + NS_WARN_IF_FALSE(result, "Could not reset window class style"); 1.6601 +} 1.6602 + 1.6603 +bool 1.6604 +nsWindow::HasBogusPopupsDropShadowOnMultiMonitor() { 1.6605 + if (sHasBogusPopupsDropShadowOnMultiMonitor == TRI_UNKNOWN) { 1.6606 + // Since any change in the preferences requires a restart, this can be 1.6607 + // done just once. 1.6608 + // Check for Direct2D first. 1.6609 + sHasBogusPopupsDropShadowOnMultiMonitor = 1.6610 + gfxWindowsPlatform::GetPlatform()->GetRenderMode() == 1.6611 + gfxWindowsPlatform::RENDER_DIRECT2D ? TRI_TRUE : TRI_FALSE; 1.6612 + if (!sHasBogusPopupsDropShadowOnMultiMonitor) { 1.6613 + // Otherwise check if Direct3D 9 may be used. 1.6614 + LayerManagerPrefs prefs; 1.6615 + GetLayerManagerPrefs(&prefs); 1.6616 + if (!prefs.mDisableAcceleration && !prefs.mPreferOpenGL) { 1.6617 + nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); 1.6618 + if (gfxInfo) { 1.6619 + int32_t status; 1.6620 + if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) { 1.6621 + if (status == nsIGfxInfo::FEATURE_NO_INFO || prefs.mForceAcceleration) 1.6622 + { 1.6623 + sHasBogusPopupsDropShadowOnMultiMonitor = TRI_TRUE; 1.6624 + } 1.6625 + } 1.6626 + } 1.6627 + } 1.6628 + } 1.6629 + } 1.6630 + return !!sHasBogusPopupsDropShadowOnMultiMonitor; 1.6631 +} 1.6632 + 1.6633 +void 1.6634 +nsWindow::OnSysColorChanged() 1.6635 +{ 1.6636 + if (mWindowType == eWindowType_invisible) { 1.6637 + ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, WM_SYSCOLORCHANGE); 1.6638 + } 1.6639 + else { 1.6640 + // Note: This is sent for child windows as well as top-level windows. 1.6641 + // The Win32 toolkit normally only sends these events to top-level windows. 1.6642 + // But we cycle through all of the childwindows and send it to them as well 1.6643 + // so all presentations get notified properly. 1.6644 + // See nsWindow::GlobalMsgWindowProc. 1.6645 + NotifySysColorChanged(); 1.6646 + } 1.6647 +} 1.6648 + 1.6649 +/************************************************************** 1.6650 + ************************************************************** 1.6651 + ** 1.6652 + ** BLOCK: IME management and accessibility 1.6653 + ** 1.6654 + ** Handles managing IME input and accessibility. 1.6655 + ** 1.6656 + ************************************************************** 1.6657 + **************************************************************/ 1.6658 + 1.6659 +NS_IMETHODIMP 1.6660 +nsWindow::NotifyIME(const IMENotification& aIMENotification) 1.6661 +{ 1.6662 + return IMEHandler::NotifyIME(this, aIMENotification); 1.6663 +} 1.6664 + 1.6665 +NS_IMETHODIMP_(void) 1.6666 +nsWindow::SetInputContext(const InputContext& aContext, 1.6667 + const InputContextAction& aAction) 1.6668 +{ 1.6669 + InputContext newInputContext = aContext; 1.6670 + IMEHandler::SetInputContext(this, newInputContext, aAction); 1.6671 + mInputContext = newInputContext; 1.6672 +} 1.6673 + 1.6674 +NS_IMETHODIMP_(InputContext) 1.6675 +nsWindow::GetInputContext() 1.6676 +{ 1.6677 + mInputContext.mIMEState.mOpen = IMEState::CLOSED; 1.6678 + if (WinUtils::IsIMEEnabled(mInputContext) && IMEHandler::GetOpenState(this)) { 1.6679 + mInputContext.mIMEState.mOpen = IMEState::OPEN; 1.6680 + } else { 1.6681 + mInputContext.mIMEState.mOpen = IMEState::CLOSED; 1.6682 + } 1.6683 + return mInputContext; 1.6684 +} 1.6685 + 1.6686 +NS_IMETHODIMP 1.6687 +nsWindow::GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState) 1.6688 +{ 1.6689 +#ifdef DEBUG_KBSTATE 1.6690 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("GetToggledKeyState\n")); 1.6691 +#endif 1.6692 + NS_ENSURE_ARG_POINTER(aLEDState); 1.6693 + *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0; 1.6694 + return NS_OK; 1.6695 +} 1.6696 + 1.6697 +nsIMEUpdatePreference 1.6698 +nsWindow::GetIMEUpdatePreference() 1.6699 +{ 1.6700 + return IMEHandler::GetUpdatePreference(); 1.6701 +} 1.6702 + 1.6703 +#ifdef ACCESSIBILITY 1.6704 +#ifdef DEBUG 1.6705 +#define NS_LOG_WMGETOBJECT(aWnd, aHwnd, aAcc) \ 1.6706 + if (a11y::logging::IsEnabled(a11y::logging::ePlatforms)) { \ 1.6707 + printf("Get the window:\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n",\ 1.6708 + aHwnd, ::GetParent(aHwnd), aWnd); \ 1.6709 + printf(" acc: %p", aAcc); \ 1.6710 + if (aAcc) { \ 1.6711 + nsAutoString name; \ 1.6712 + aAcc->Name(name); \ 1.6713 + printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \ 1.6714 + } \ 1.6715 + printf("\n }\n"); \ 1.6716 + } 1.6717 + 1.6718 +#else 1.6719 +#define NS_LOG_WMGETOBJECT(aWnd, aHwnd, aAcc) 1.6720 +#endif 1.6721 + 1.6722 +a11y::Accessible* 1.6723 +nsWindow::GetAccessible() 1.6724 +{ 1.6725 + // If the pref was ePlatformIsDisabled, return null here, disabling a11y. 1.6726 + if (a11y::PlatformDisabledState() == a11y::ePlatformIsDisabled) 1.6727 + return nullptr; 1.6728 + 1.6729 + if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) { 1.6730 + return nullptr; 1.6731 + } 1.6732 + 1.6733 + // In case of popup window return a popup accessible. 1.6734 + nsView* view = nsView::GetViewFor(this); 1.6735 + if (view) { 1.6736 + nsIFrame* frame = view->GetFrame(); 1.6737 + if (frame && nsLayoutUtils::IsPopup(frame)) { 1.6738 + nsCOMPtr<nsIAccessibilityService> accService = 1.6739 + services::GetAccessibilityService(); 1.6740 + if (accService) { 1.6741 + a11y::DocAccessible* docAcc = 1.6742 + GetAccService()->GetDocAccessible(frame->PresContext()->PresShell()); 1.6743 + if (docAcc) { 1.6744 + NS_LOG_WMGETOBJECT(this, mWnd, 1.6745 + docAcc->GetAccessibleOrDescendant(frame->GetContent())); 1.6746 + return docAcc->GetAccessibleOrDescendant(frame->GetContent()); 1.6747 + } 1.6748 + } 1.6749 + } 1.6750 + } 1.6751 + 1.6752 + // otherwise root document accessible. 1.6753 + NS_LOG_WMGETOBJECT(this, mWnd, GetRootAccessible()); 1.6754 + return GetRootAccessible(); 1.6755 +} 1.6756 +#endif 1.6757 + 1.6758 +/************************************************************** 1.6759 + ************************************************************** 1.6760 + ** 1.6761 + ** BLOCK: Transparency 1.6762 + ** 1.6763 + ** Window transparency helpers. 1.6764 + ** 1.6765 + ************************************************************** 1.6766 + **************************************************************/ 1.6767 + 1.6768 +#ifdef MOZ_XUL 1.6769 + 1.6770 +void nsWindow::ResizeTranslucentWindow(int32_t aNewWidth, int32_t aNewHeight, bool force) 1.6771 +{ 1.6772 + if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height) 1.6773 + return; 1.6774 + 1.6775 + nsRefPtr<gfxWindowsSurface> newSurface = 1.6776 + new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxImageFormat::ARGB32); 1.6777 + mTransparentSurface = newSurface; 1.6778 + mMemoryDC = newSurface->GetDC(); 1.6779 +} 1.6780 + 1.6781 +void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode) 1.6782 +{ 1.6783 + if (aMode == mTransparencyMode) 1.6784 + return; 1.6785 + 1.6786 + // stop on dialogs and popups! 1.6787 + HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true); 1.6788 + nsWindow* parent = WinUtils::GetNSWindowPtr(hWnd); 1.6789 + 1.6790 + if (!parent) 1.6791 + { 1.6792 + NS_WARNING("Trying to use transparent chrome in an embedded context"); 1.6793 + return; 1.6794 + } 1.6795 + 1.6796 + if (parent != this) { 1.6797 + NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!"); 1.6798 + } 1.6799 + 1.6800 + if (aMode == eTransparencyTransparent) { 1.6801 + // If we're switching to the use of a transparent window, hide the chrome 1.6802 + // on our parent. 1.6803 + HideWindowChrome(true); 1.6804 + } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) { 1.6805 + // if we're switching out of transparent, re-enable our parent's chrome. 1.6806 + HideWindowChrome(false); 1.6807 + } 1.6808 + 1.6809 + LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE), 1.6810 + exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE); 1.6811 + 1.6812 + if (parent->mIsVisible) 1.6813 + style |= WS_VISIBLE; 1.6814 + if (parent->mSizeMode == nsSizeMode_Maximized) 1.6815 + style |= WS_MAXIMIZE; 1.6816 + else if (parent->mSizeMode == nsSizeMode_Minimized) 1.6817 + style |= WS_MINIMIZE; 1.6818 + 1.6819 + if (aMode == eTransparencyTransparent) 1.6820 + exStyle |= WS_EX_LAYERED; 1.6821 + else 1.6822 + exStyle &= ~WS_EX_LAYERED; 1.6823 + 1.6824 + VERIFY_WINDOW_STYLE(style); 1.6825 + ::SetWindowLongPtrW(hWnd, GWL_STYLE, style); 1.6826 + ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle); 1.6827 + 1.6828 + if (HasGlass()) 1.6829 + memset(&mGlassMargins, 0, sizeof mGlassMargins); 1.6830 + mTransparencyMode = aMode; 1.6831 + 1.6832 + SetupTranslucentWindowMemoryBitmap(aMode); 1.6833 + UpdateGlass(); 1.6834 +} 1.6835 + 1.6836 +void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode) 1.6837 +{ 1.6838 + if (eTransparencyTransparent == aMode) { 1.6839 + ResizeTranslucentWindow(mBounds.width, mBounds.height, true); 1.6840 + } else { 1.6841 + mTransparentSurface = nullptr; 1.6842 + mMemoryDC = nullptr; 1.6843 + } 1.6844 +} 1.6845 + 1.6846 +void nsWindow::ClearTranslucentWindow() 1.6847 +{ 1.6848 + if (mTransparentSurface) { 1.6849 + nsRefPtr<gfxContext> thebesContext = new gfxContext(mTransparentSurface); 1.6850 + thebesContext->SetOperator(gfxContext::OPERATOR_CLEAR); 1.6851 + thebesContext->Paint(); 1.6852 + UpdateTranslucentWindow(); 1.6853 + } 1.6854 +} 1.6855 + 1.6856 +nsresult nsWindow::UpdateTranslucentWindow() 1.6857 +{ 1.6858 + if (mBounds.IsEmpty()) 1.6859 + return NS_OK; 1.6860 + 1.6861 + ::GdiFlush(); 1.6862 + 1.6863 + BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; 1.6864 + SIZE winSize = { mBounds.width, mBounds.height }; 1.6865 + POINT srcPos = { 0, 0 }; 1.6866 + HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true); 1.6867 + RECT winRect; 1.6868 + ::GetWindowRect(hWnd, &winRect); 1.6869 + 1.6870 + // perform the alpha blend 1.6871 + bool updateSuccesful = 1.6872 + ::UpdateLayeredWindow(hWnd, nullptr, (POINT*)&winRect, &winSize, mMemoryDC, 1.6873 + &srcPos, 0, &bf, ULW_ALPHA); 1.6874 + 1.6875 + if (!updateSuccesful) { 1.6876 + return NS_ERROR_FAILURE; 1.6877 + } 1.6878 + 1.6879 + return NS_OK; 1.6880 +} 1.6881 + 1.6882 +#endif //MOZ_XUL 1.6883 + 1.6884 +/************************************************************** 1.6885 + ************************************************************** 1.6886 + ** 1.6887 + ** BLOCK: Popup rollup hooks 1.6888 + ** 1.6889 + ** Deals with CaptureRollup on popup windows. 1.6890 + ** 1.6891 + ************************************************************** 1.6892 + **************************************************************/ 1.6893 + 1.6894 +// Schedules a timer for a window, so we can rollup after processing the hook event 1.6895 +void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId) 1.6896 +{ 1.6897 + // In some cases multiple hooks may be scheduled 1.6898 + // so ignore any other requests once one timer is scheduled 1.6899 + if (sHookTimerId == 0) { 1.6900 + // Remember the window handle and the message ID to be used later 1.6901 + sRollupMsgId = aMsgId; 1.6902 + sRollupMsgWnd = aWnd; 1.6903 + // Schedule native timer for doing the rollup after 1.6904 + // this event is done being processed 1.6905 + sHookTimerId = ::SetTimer(nullptr, 0, 0, (TIMERPROC)HookTimerForPopups); 1.6906 + NS_ASSERTION(sHookTimerId, "Timer couldn't be created."); 1.6907 + } 1.6908 +} 1.6909 + 1.6910 +#ifdef POPUP_ROLLUP_DEBUG_OUTPUT 1.6911 +int gLastMsgCode = 0; 1.6912 +extern MSGFEventMsgInfo gMSGFEvents[]; 1.6913 +#endif 1.6914 + 1.6915 +// Process Menu messages, rollup when popup is clicked. 1.6916 +LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam) 1.6917 +{ 1.6918 +#ifdef POPUP_ROLLUP_DEBUG_OUTPUT 1.6919 + if (sProcessHook) { 1.6920 + MSG* pMsg = (MSG*)lParam; 1.6921 + 1.6922 + int inx = 0; 1.6923 + while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != nullptr) { 1.6924 + inx++; 1.6925 + } 1.6926 + if (code != gLastMsgCode) { 1.6927 + if (gMSGFEvents[inx].mId == code) { 1.6928 +#ifdef DEBUG 1.6929 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.6930 + ("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", 1.6931 + code, gMSGFEvents[inx].mStr, pMsg->hwnd)); 1.6932 +#endif 1.6933 + } else { 1.6934 +#ifdef DEBUG 1.6935 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.6936 + ("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", 1.6937 + code, gMSGFEvents[inx].mId, pMsg->hwnd)); 1.6938 +#endif 1.6939 + } 1.6940 + gLastMsgCode = code; 1.6941 + } 1.6942 + PrintEvent(pMsg->message, FALSE, FALSE); 1.6943 + } 1.6944 +#endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT 1.6945 + 1.6946 + if (sProcessHook && code == MSGF_MENU) { 1.6947 + MSG* pMsg = (MSG*)lParam; 1.6948 + ScheduleHookTimer( pMsg->hwnd, pMsg->message); 1.6949 + } 1.6950 + 1.6951 + return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam); 1.6952 +} 1.6953 + 1.6954 +// Process all mouse messages. Roll up when a click is in a native window 1.6955 +// that doesn't have an nsIWidget. 1.6956 +LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam) 1.6957 +{ 1.6958 + if (sProcessHook) { 1.6959 + switch (WinUtils::GetNativeMessage(wParam)) { 1.6960 + case WM_LBUTTONDOWN: 1.6961 + case WM_RBUTTONDOWN: 1.6962 + case WM_MBUTTONDOWN: 1.6963 + case WM_MOUSEWHEEL: 1.6964 + case WM_MOUSEHWHEEL: 1.6965 + { 1.6966 + MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam; 1.6967 + nsIWidget* mozWin = WinUtils::GetNSWindowPtr(ms->hwnd); 1.6968 + if (mozWin) { 1.6969 + // If this window is windowed plugin window, the mouse events are not 1.6970 + // sent to us. 1.6971 + if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin) 1.6972 + ScheduleHookTimer(ms->hwnd, (UINT)wParam); 1.6973 + } else { 1.6974 + ScheduleHookTimer(ms->hwnd, (UINT)wParam); 1.6975 + } 1.6976 + break; 1.6977 + } 1.6978 + } 1.6979 + } 1.6980 + return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam); 1.6981 +} 1.6982 + 1.6983 +// Process all messages. Roll up when the window is moving, or 1.6984 +// is resizing or when maximized or mininized. 1.6985 +LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam) 1.6986 +{ 1.6987 +#ifdef POPUP_ROLLUP_DEBUG_OUTPUT 1.6988 + if (sProcessHook) { 1.6989 + CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam; 1.6990 + PrintEvent(cwpt->message, FALSE, FALSE); 1.6991 + } 1.6992 +#endif 1.6993 + 1.6994 + if (sProcessHook) { 1.6995 + CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam; 1.6996 + if (cwpt->message == WM_MOVING || 1.6997 + cwpt->message == WM_SIZING || 1.6998 + cwpt->message == WM_GETMINMAXINFO) { 1.6999 + ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message); 1.7000 + } 1.7001 + } 1.7002 + 1.7003 + return ::CallNextHookEx(sCallProcHook, code, wParam, lParam); 1.7004 +} 1.7005 + 1.7006 +// Register the special "hooks" for dropdown processing. 1.7007 +void nsWindow::RegisterSpecialDropdownHooks() 1.7008 +{ 1.7009 + NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!"); 1.7010 + NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!"); 1.7011 + 1.7012 + DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n"); 1.7013 + 1.7014 + // Install msg hook for moving the window and resizing 1.7015 + if (!sMsgFilterHook) { 1.7016 + DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n"); 1.7017 + sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, 1.7018 + nullptr, GetCurrentThreadId()); 1.7019 +#ifdef POPUP_ROLLUP_DEBUG_OUTPUT 1.7020 + if (!sMsgFilterHook) { 1.7021 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.7022 + ("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n")); 1.7023 + } 1.7024 +#endif 1.7025 + } 1.7026 + 1.7027 + // Install msg hook for menus 1.7028 + if (!sCallProcHook) { 1.7029 + DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n"); 1.7030 + sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, 1.7031 + nullptr, GetCurrentThreadId()); 1.7032 +#ifdef POPUP_ROLLUP_DEBUG_OUTPUT 1.7033 + if (!sCallProcHook) { 1.7034 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.7035 + ("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n")); 1.7036 + } 1.7037 +#endif 1.7038 + } 1.7039 + 1.7040 + // Install msg hook for the mouse 1.7041 + if (!sCallMouseHook) { 1.7042 + DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n"); 1.7043 + sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, 1.7044 + nullptr, GetCurrentThreadId()); 1.7045 +#ifdef POPUP_ROLLUP_DEBUG_OUTPUT 1.7046 + if (!sCallMouseHook) { 1.7047 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.7048 + ("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n")); 1.7049 + } 1.7050 +#endif 1.7051 + } 1.7052 +} 1.7053 + 1.7054 +// Unhook special message hooks for dropdowns. 1.7055 +void nsWindow::UnregisterSpecialDropdownHooks() 1.7056 +{ 1.7057 + DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n"); 1.7058 + 1.7059 + if (sCallProcHook) { 1.7060 + DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n"); 1.7061 + if (!::UnhookWindowsHookEx(sCallProcHook)) { 1.7062 + DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n"); 1.7063 + } 1.7064 + sCallProcHook = nullptr; 1.7065 + } 1.7066 + 1.7067 + if (sMsgFilterHook) { 1.7068 + DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n"); 1.7069 + if (!::UnhookWindowsHookEx(sMsgFilterHook)) { 1.7070 + DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n"); 1.7071 + } 1.7072 + sMsgFilterHook = nullptr; 1.7073 + } 1.7074 + 1.7075 + if (sCallMouseHook) { 1.7076 + DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n"); 1.7077 + if (!::UnhookWindowsHookEx(sCallMouseHook)) { 1.7078 + DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n"); 1.7079 + } 1.7080 + sCallMouseHook = nullptr; 1.7081 + } 1.7082 +} 1.7083 + 1.7084 +// This timer is designed to only fire one time at most each time a "hook" function 1.7085 +// is used to rollup the dropdown. In some cases, the timer may be scheduled from the 1.7086 +// hook, but that hook event or a subsequent event may roll up the dropdown before 1.7087 +// this timer function is executed. 1.7088 +// 1.7089 +// For example, if an MFC control takes focus, the combobox will lose focus and rollup 1.7090 +// before this function fires. 1.7091 +VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) 1.7092 +{ 1.7093 + if (sHookTimerId != 0) { 1.7094 + // if the window is nullptr then we need to use the ID to kill the timer 1.7095 + BOOL status = ::KillTimer(nullptr, sHookTimerId); 1.7096 + NS_ASSERTION(status, "Hook Timer was not killed."); 1.7097 + sHookTimerId = 0; 1.7098 + } 1.7099 + 1.7100 + if (sRollupMsgId != 0) { 1.7101 + // Note: DealWithPopups does the check to make sure that the rollup widget is set. 1.7102 + LRESULT popupHandlingResult; 1.7103 + nsAutoRollup autoRollup; 1.7104 + DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult); 1.7105 + sRollupMsgId = 0; 1.7106 + sRollupMsgWnd = nullptr; 1.7107 + } 1.7108 +} 1.7109 + 1.7110 +BOOL CALLBACK nsWindow::ClearResourcesCallback(HWND aWnd, LPARAM aMsg) 1.7111 +{ 1.7112 + nsWindow *window = WinUtils::GetNSWindowPtr(aWnd); 1.7113 + if (window) { 1.7114 + window->ClearCachedResources(); 1.7115 + } 1.7116 + return TRUE; 1.7117 +} 1.7118 + 1.7119 +void 1.7120 +nsWindow::ClearCachedResources() 1.7121 +{ 1.7122 + if (mLayerManager && 1.7123 + mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) { 1.7124 + mLayerManager->ClearCachedResources(); 1.7125 + } 1.7126 + ::EnumChildWindows(mWnd, nsWindow::ClearResourcesCallback, 0); 1.7127 +} 1.7128 + 1.7129 +static bool IsDifferentThreadWindow(HWND aWnd) 1.7130 +{ 1.7131 + return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, nullptr); 1.7132 +} 1.7133 + 1.7134 +// static 1.7135 +bool 1.7136 +nsWindow::EventIsInsideWindow(nsWindow* aWindow) 1.7137 +{ 1.7138 + RECT r; 1.7139 + ::GetWindowRect(aWindow->mWnd, &r); 1.7140 + DWORD pos = ::GetMessagePos(); 1.7141 + POINT mp; 1.7142 + mp.x = GET_X_LPARAM(pos); 1.7143 + mp.y = GET_Y_LPARAM(pos); 1.7144 + 1.7145 + // was the event inside this window? 1.7146 + return static_cast<bool>(::PtInRect(&r, mp)); 1.7147 +} 1.7148 + 1.7149 +// static 1.7150 +bool 1.7151 +nsWindow::GetPopupsToRollup(nsIRollupListener* aRollupListener, 1.7152 + uint32_t* aPopupsToRollup) 1.7153 +{ 1.7154 + // If we're dealing with menus, we probably have submenus and we don't want 1.7155 + // to rollup some of them if the click is in a parent menu of the current 1.7156 + // submenu. 1.7157 + *aPopupsToRollup = UINT32_MAX; 1.7158 + nsAutoTArray<nsIWidget*, 5> widgetChain; 1.7159 + uint32_t sameTypeCount = 1.7160 + aRollupListener->GetSubmenuWidgetChain(&widgetChain); 1.7161 + for (uint32_t i = 0; i < widgetChain.Length(); ++i) { 1.7162 + nsIWidget* widget = widgetChain[i]; 1.7163 + if (EventIsInsideWindow(static_cast<nsWindow*>(widget))) { 1.7164 + // Don't roll up if the mouse event occurred within a menu of the 1.7165 + // same type. If the mouse event occurred in a menu higher than that, 1.7166 + // roll up, but pass the number of popups to Rollup so that only those 1.7167 + // of the same type close up. 1.7168 + if (i < sameTypeCount) { 1.7169 + return false; 1.7170 + } 1.7171 + 1.7172 + *aPopupsToRollup = sameTypeCount; 1.7173 + break; 1.7174 + } 1.7175 + } 1.7176 + return true; 1.7177 +} 1.7178 + 1.7179 +// static 1.7180 +bool 1.7181 +nsWindow::NeedsToHandleNCActivateDelayed(HWND aWnd) 1.7182 +{ 1.7183 + // While popup is open, popup window might be activated by other application. 1.7184 + // At this time, we need to take back focus to the previous window but it 1.7185 + // causes flickering its nonclient area because WM_NCACTIVATE comes before 1.7186 + // WM_ACTIVATE and we cannot know which window will take focus at receiving 1.7187 + // WM_NCACTIVATE. Therefore, we need a hack for preventing the flickerling. 1.7188 + // 1.7189 + // If non-popup window receives WM_NCACTIVATE at deactivating, default 1.7190 + // wndproc shouldn't handle it as deactivating. Instead, at receiving 1.7191 + // WM_ACTIVIATE after that, WM_NCACTIVATE should be sent again manually. 1.7192 + // This returns true if the window needs to handle WM_NCACTIVATE later. 1.7193 + 1.7194 + nsWindow* window = WinUtils::GetNSWindowPtr(aWnd); 1.7195 + return window && !window->IsPopup(); 1.7196 +} 1.7197 + 1.7198 +// static 1.7199 +bool 1.7200 +nsWindow::DealWithPopups(HWND aWnd, UINT aMessage, 1.7201 + WPARAM aWParam, LPARAM aLParam, LRESULT* aResult) 1.7202 +{ 1.7203 + NS_ASSERTION(aResult, "Bad outResult"); 1.7204 + 1.7205 + // XXX Why do we use the return value of WM_MOUSEACTIVATE for all messages? 1.7206 + *aResult = MA_NOACTIVATE; 1.7207 + 1.7208 + if (!::IsWindowVisible(aWnd)) { 1.7209 + return false; 1.7210 + } 1.7211 + 1.7212 + nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener(); 1.7213 + NS_ENSURE_TRUE(rollupListener, false); 1.7214 + 1.7215 + nsCOMPtr<nsIWidget> popup = rollupListener->GetRollupWidget(); 1.7216 + if (!popup) { 1.7217 + return false; 1.7218 + } 1.7219 + 1.7220 + static bool sSendingNCACTIVATE = false; 1.7221 + static bool sPendingNCACTIVATE = false; 1.7222 + uint32_t popupsToRollup = UINT32_MAX; 1.7223 + 1.7224 + nsWindow* popupWindow = static_cast<nsWindow*>(popup.get()); 1.7225 + UINT nativeMessage = WinUtils::GetNativeMessage(aMessage); 1.7226 + switch (nativeMessage) { 1.7227 + case WM_LBUTTONDOWN: 1.7228 + case WM_RBUTTONDOWN: 1.7229 + case WM_MBUTTONDOWN: 1.7230 + case WM_NCLBUTTONDOWN: 1.7231 + case WM_NCRBUTTONDOWN: 1.7232 + case WM_NCMBUTTONDOWN: 1.7233 + if (!EventIsInsideWindow(popupWindow) && 1.7234 + GetPopupsToRollup(rollupListener, &popupsToRollup)) { 1.7235 + break; 1.7236 + } 1.7237 + return false; 1.7238 + 1.7239 + case WM_MOUSEWHEEL: 1.7240 + case WM_MOUSEHWHEEL: 1.7241 + // We need to check if the popup thinks that it should cause closing 1.7242 + // itself when mouse wheel events are fired outside the rollup widget. 1.7243 + if (!EventIsInsideWindow(popupWindow)) { 1.7244 + *aResult = MA_ACTIVATE; 1.7245 + if (rollupListener->ShouldRollupOnMouseWheelEvent() && 1.7246 + GetPopupsToRollup(rollupListener, &popupsToRollup)) { 1.7247 + break; 1.7248 + } 1.7249 + } 1.7250 + return false; 1.7251 + 1.7252 + case WM_ACTIVATEAPP: 1.7253 + break; 1.7254 + 1.7255 + case WM_ACTIVATE: 1.7256 + // NOTE: Don't handle WA_INACTIVE for preventing popup taking focus 1.7257 + // because we cannot distinguish it's caused by mouse or not. 1.7258 + if (LOWORD(aWParam) == WA_ACTIVE && aLParam) { 1.7259 + nsWindow* window = WinUtils::GetNSWindowPtr(aWnd); 1.7260 + if (window && window->IsPopup()) { 1.7261 + // Cancel notifying widget listeners of deactivating the previous 1.7262 + // active window (see WM_KILLFOCUS case in ProcessMessage()). 1.7263 + sJustGotDeactivate = false; 1.7264 + // Reactivate the window later. 1.7265 + ::PostMessageW(aWnd, MOZ_WM_REACTIVATE, aWParam, aLParam); 1.7266 + return true; 1.7267 + } 1.7268 + // Don't rollup the popup when focus moves back to the parent window 1.7269 + // from a popup because such case is caused by strange mouse drivers. 1.7270 + nsWindow* prevWindow = 1.7271 + WinUtils::GetNSWindowPtr(reinterpret_cast<HWND>(aLParam)); 1.7272 + if (prevWindow && prevWindow->IsPopup()) { 1.7273 + return false; 1.7274 + } 1.7275 + } else if (LOWORD(aWParam) == WA_INACTIVE) { 1.7276 + nsWindow* activeWindow = 1.7277 + WinUtils::GetNSWindowPtr(reinterpret_cast<HWND>(aLParam)); 1.7278 + if (sPendingNCACTIVATE && NeedsToHandleNCActivateDelayed(aWnd)) { 1.7279 + // If focus moves to non-popup widget or focusable popup, the window 1.7280 + // needs to update its nonclient area. 1.7281 + if (!activeWindow || !activeWindow->IsPopup()) { 1.7282 + sSendingNCACTIVATE = true; 1.7283 + ::SendMessageW(aWnd, WM_NCACTIVATE, false, 0); 1.7284 + sSendingNCACTIVATE = false; 1.7285 + } 1.7286 + sPendingNCACTIVATE = false; 1.7287 + } 1.7288 + // If focus moves from/to popup, we don't need to rollup the popup 1.7289 + // because such case is caused by strange mouse drivers. 1.7290 + if (activeWindow) { 1.7291 + if (activeWindow->IsPopup()) { 1.7292 + return false; 1.7293 + } 1.7294 + nsWindow* deactiveWindow = WinUtils::GetNSWindowPtr(aWnd); 1.7295 + if (deactiveWindow && deactiveWindow->IsPopup()) { 1.7296 + return false; 1.7297 + } 1.7298 + } 1.7299 + } else if (LOWORD(aWParam) == WA_CLICKACTIVE) { 1.7300 + // If the WM_ACTIVATE message is caused by a click in a popup, 1.7301 + // we should not rollup any popups. 1.7302 + if (EventIsInsideWindow(popupWindow) || 1.7303 + !GetPopupsToRollup(rollupListener, &popupsToRollup)) { 1.7304 + return false; 1.7305 + } 1.7306 + } 1.7307 + break; 1.7308 + 1.7309 + case MOZ_WM_REACTIVATE: 1.7310 + // The previous active window should take back focus. 1.7311 + if (::IsWindow(reinterpret_cast<HWND>(aLParam))) { 1.7312 + ::SetForegroundWindow(reinterpret_cast<HWND>(aLParam)); 1.7313 + } 1.7314 + return true; 1.7315 + 1.7316 + case WM_NCACTIVATE: 1.7317 + if (!aWParam && !sSendingNCACTIVATE && 1.7318 + NeedsToHandleNCActivateDelayed(aWnd)) { 1.7319 + // Don't just consume WM_NCACTIVATE. It doesn't handle only the 1.7320 + // nonclient area state change. 1.7321 + ::DefWindowProcW(aWnd, aMessage, TRUE, aLParam); 1.7322 + // Accept the deactivating because it's necessary to receive following 1.7323 + // WM_ACTIVATE. 1.7324 + *aResult = TRUE; 1.7325 + sPendingNCACTIVATE = true; 1.7326 + return true; 1.7327 + } 1.7328 + return false; 1.7329 + 1.7330 + case WM_MOUSEACTIVATE: 1.7331 + if (!EventIsInsideWindow(popupWindow) && 1.7332 + GetPopupsToRollup(rollupListener, &popupsToRollup)) { 1.7333 + // WM_MOUSEACTIVATE may be caused by moving the mouse (e.g., X-mouse 1.7334 + // of TweakUI is enabled. Then, check if the popup should be rolled up 1.7335 + // with rollup listener. If not, just consume the message. 1.7336 + if (HIWORD(aLParam) == WM_MOUSEMOVE && 1.7337 + !rollupListener->ShouldRollupOnMouseActivate()) { 1.7338 + return true; 1.7339 + } 1.7340 + // Otherwise, it should be handled by wndproc. 1.7341 + return false; 1.7342 + } 1.7343 + 1.7344 + // Prevent the click inside the popup from causing a change in window 1.7345 + // activation. Since the popup is shown non-activated, we need to eat any 1.7346 + // requests to activate the window while it is displayed. Windows will 1.7347 + // automatically activate the popup on the mousedown otherwise. 1.7348 + return true; 1.7349 + 1.7350 + case WM_KILLFOCUS: 1.7351 + // If focus moves to other window created in different process/thread, 1.7352 + // e.g., a plugin window, popups should be rolled up. 1.7353 + if (IsDifferentThreadWindow(reinterpret_cast<HWND>(aWParam))) { 1.7354 + break; 1.7355 + } 1.7356 + return false; 1.7357 + 1.7358 + case WM_MOVING: 1.7359 + case WM_SIZING: 1.7360 + case WM_MENUSELECT: 1.7361 + break; 1.7362 + 1.7363 + default: 1.7364 + return false; 1.7365 + } 1.7366 + 1.7367 + // Only need to deal with the last rollup for left mouse down events. 1.7368 + NS_ASSERTION(!mLastRollup, "mLastRollup is null"); 1.7369 + 1.7370 + bool consumeRollupEvent; 1.7371 + if (nativeMessage == WM_LBUTTONDOWN) { 1.7372 + POINT pt; 1.7373 + pt.x = GET_X_LPARAM(aLParam); 1.7374 + pt.y = GET_Y_LPARAM(aLParam); 1.7375 + ::ClientToScreen(aWnd, &pt); 1.7376 + nsIntPoint pos(pt.x, pt.y); 1.7377 + 1.7378 + consumeRollupEvent = 1.7379 + rollupListener->Rollup(popupsToRollup, &pos, &mLastRollup); 1.7380 + NS_IF_ADDREF(mLastRollup); 1.7381 + } else { 1.7382 + consumeRollupEvent = 1.7383 + rollupListener->Rollup(popupsToRollup, nullptr, nullptr); 1.7384 + } 1.7385 + 1.7386 + // Tell hook to stop processing messages 1.7387 + sProcessHook = false; 1.7388 + sRollupMsgId = 0; 1.7389 + sRollupMsgWnd = nullptr; 1.7390 + 1.7391 + // If we are NOT supposed to be consuming events, let it go through 1.7392 + if (consumeRollupEvent && nativeMessage != WM_RBUTTONDOWN) { 1.7393 + *aResult = MA_ACTIVATE; 1.7394 + return true; 1.7395 + } 1.7396 + 1.7397 + return false; 1.7398 +} 1.7399 + 1.7400 +/************************************************************** 1.7401 + ************************************************************** 1.7402 + ** 1.7403 + ** BLOCK: Misc. utility methods and functions. 1.7404 + ** 1.7405 + ** General use. 1.7406 + ** 1.7407 + ************************************************************** 1.7408 + **************************************************************/ 1.7409 + 1.7410 +// Note that the result of GetTopLevelWindow method can be different from the 1.7411 +// result of WinUtils::GetTopLevelHWND(). The result can be non-floating 1.7412 +// window. Because our top level window may be contained in another window 1.7413 +// which is not managed by us. 1.7414 +nsWindow* nsWindow::GetTopLevelWindow(bool aStopOnDialogOrPopup) 1.7415 +{ 1.7416 + nsWindow* curWindow = this; 1.7417 + 1.7418 + while (true) { 1.7419 + if (aStopOnDialogOrPopup) { 1.7420 + switch (curWindow->mWindowType) { 1.7421 + case eWindowType_dialog: 1.7422 + case eWindowType_popup: 1.7423 + return curWindow; 1.7424 + default: 1.7425 + break; 1.7426 + } 1.7427 + } 1.7428 + 1.7429 + // Retrieve the top level parent or owner window 1.7430 + nsWindow* parentWindow = curWindow->GetParentWindow(true); 1.7431 + 1.7432 + if (!parentWindow) 1.7433 + return curWindow; 1.7434 + 1.7435 + curWindow = parentWindow; 1.7436 + } 1.7437 +} 1.7438 + 1.7439 +static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam) 1.7440 +{ 1.7441 + DWORD pid; 1.7442 + ::GetWindowThreadProcessId(hwnd, &pid); 1.7443 + if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd)) 1.7444 + { 1.7445 + gWindowsVisible = true; 1.7446 + return FALSE; 1.7447 + } 1.7448 + return TRUE; 1.7449 +} 1.7450 + 1.7451 +bool nsWindow::CanTakeFocus() 1.7452 +{ 1.7453 + gWindowsVisible = false; 1.7454 + EnumWindows(gEnumWindowsProc, 0); 1.7455 + if (!gWindowsVisible) { 1.7456 + return true; 1.7457 + } else { 1.7458 + HWND fgWnd = ::GetForegroundWindow(); 1.7459 + if (!fgWnd) { 1.7460 + return true; 1.7461 + } 1.7462 + DWORD pid; 1.7463 + GetWindowThreadProcessId(fgWnd, &pid); 1.7464 + if (pid == GetCurrentProcessId()) { 1.7465 + return true; 1.7466 + } 1.7467 + } 1.7468 + return false; 1.7469 +} 1.7470 + 1.7471 +void nsWindow::GetMainWindowClass(nsAString& aClass) 1.7472 +{ 1.7473 + NS_PRECONDITION(aClass.IsEmpty(), "aClass should be empty string"); 1.7474 + nsresult rv = Preferences::GetString("ui.window_class_override", &aClass); 1.7475 + if (NS_FAILED(rv) || aClass.IsEmpty()) { 1.7476 + aClass.AssignASCII(sDefaultMainWindowClass); 1.7477 + } 1.7478 +} 1.7479 + 1.7480 +LPARAM nsWindow::lParamToScreen(LPARAM lParam) 1.7481 +{ 1.7482 + POINT pt; 1.7483 + pt.x = GET_X_LPARAM(lParam); 1.7484 + pt.y = GET_Y_LPARAM(lParam); 1.7485 + ::ClientToScreen(mWnd, &pt); 1.7486 + return MAKELPARAM(pt.x, pt.y); 1.7487 +} 1.7488 + 1.7489 +LPARAM nsWindow::lParamToClient(LPARAM lParam) 1.7490 +{ 1.7491 + POINT pt; 1.7492 + pt.x = GET_X_LPARAM(lParam); 1.7493 + pt.y = GET_Y_LPARAM(lParam); 1.7494 + ::ScreenToClient(mWnd, &pt); 1.7495 + return MAKELPARAM(pt.x, pt.y); 1.7496 +} 1.7497 + 1.7498 +void nsWindow::PickerOpen() 1.7499 +{ 1.7500 + mPickerDisplayCount++; 1.7501 +} 1.7502 + 1.7503 +void nsWindow::PickerClosed() 1.7504 +{ 1.7505 + NS_ASSERTION(mPickerDisplayCount > 0, "mPickerDisplayCount out of sync!"); 1.7506 + if (!mPickerDisplayCount) 1.7507 + return; 1.7508 + mPickerDisplayCount--; 1.7509 + if (!mPickerDisplayCount && mDestroyCalled) { 1.7510 + Destroy(); 1.7511 + } 1.7512 +} 1.7513 + 1.7514 +/************************************************************** 1.7515 + ************************************************************** 1.7516 + ** 1.7517 + ** BLOCK: ChildWindow impl. 1.7518 + ** 1.7519 + ** Child window overrides. 1.7520 + ** 1.7521 + ************************************************************** 1.7522 + **************************************************************/ 1.7523 + 1.7524 +// return the style for a child nsWindow 1.7525 +DWORD ChildWindow::WindowStyle() 1.7526 +{ 1.7527 + DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle(); 1.7528 + if (!(style & WS_POPUP)) 1.7529 + style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive. 1.7530 + VERIFY_WINDOW_STYLE(style); 1.7531 + return style; 1.7532 +}