widget/windows/nsWindow.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:5110ed61e0d4
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(&currentRects);
6339 // create region from them
6340 nsIntRegion currentRegion = RegionFromArray(currentRects);
6341 // create region from new rects
6342 nsIntRegion newRegion = RegionFromArray(aRects);
6343 // intersect regions
6344 nsIntRegion intersection;
6345 intersection.And(currentRegion, newRegion);
6346 // create int rect array from intersection
6347 nsTArray<nsIntRect> rects;
6348 ArrayFromRegion(intersection, rects);
6349 // store
6350 if (!StoreWindowClipRegion(rects))
6351 return NS_OK;
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 }

mercurial