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