Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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(¤tRects); |
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 | } |