widget/windows/nsWindow.cpp

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

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

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

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

mercurial