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/. */
8 * nsWindow - Native window management and event handling.
10 * nsWindow is organized into a set of major blocks and
11 * block subsections. The layout is as follows:
16 * nsIWidget methods and utilities
17 * nsSwitchToUIThread impl.
18 * nsSwitchToUIThread methods and utilities
20 * Event initialization
25 * OnEvent event handlers
26 * IME management and accessibility
32 * Search for "BLOCK:" to find major blocks.
33 * Search for "SECTION:" to find specific sections.
35 * Blocks should be split out into separate files if they
36 * become unmanageable.
40 * nsWindowDefs.h - Definitions, macros, structs, enums
42 * nsWindowDbg.h/.cpp - Debug related code and directives.
43 * nsWindowGfx.h/.cpp - Graphics and painting.
47 /**************************************************************
48 **************************************************************
54 **************************************************************
55 **************************************************************/
57 #include "mozilla/MathAlgorithms.h"
58 #include "mozilla/Util.h"
60 #include "mozilla/ipc/RPCChannel.h"
77 #include "mozilla/WidgetTraceEvent.h"
78 #include "nsIAppShell.h"
79 #include "nsISupportsPrimitives.h"
80 #include "nsIDOMMouseEvent.h"
82 #include "nsIObserverService.h"
83 #include "nsIScreenManager.h"
84 #include "imgIContainer.h"
86 #include "nsIRollupListener.h"
87 #include "nsIServiceManager.h"
88 #include "nsIClipboard.h"
89 #include "nsIMM32Handler.h"
90 #include "WinMouseScrollHandler.h"
91 #include "nsFontMetrics.h"
92 #include "nsIFontEnumerator.h"
93 #include "nsGUIEvent.h"
96 #include "nsThreadUtils.h"
97 #include "nsNativeCharsetUtils.h"
98 #include "nsGkAtoms.h"
100 #include "nsAppDirectoryServiceDefs.h"
101 #include "nsXPIDLString.h"
102 #include "nsWidgetsCID.h"
103 #include "nsTHashtable.h"
104 #include "nsHashKeys.h"
105 #include "nsString.h"
106 #include "mozilla/Services.h"
107 #include "nsNativeThemeWin.h"
108 #include "nsWindowsDllInterceptor.h"
109 #include "nsIWindowMediator.h"
110 #include "nsIServiceManager.h"
111 #include "nsWindowGfx.h"
112 #include "gfxWindowsPlatform.h"
114 #include "nsPrintfCString.h"
115 #include "mozilla/Preferences.h"
116 #include "nsISound.h"
117 #include "WinTaskbar.h"
118 #include "WinUtils.h"
119 #include "WidgetUtils.h"
120 #include "nsIWidgetListener.h"
121 #include "mozilla/dom/Touch.h"
123 #ifdef MOZ_ENABLE_D3D9_LAYER
124 #include "LayerManagerD3D9.h"
127 #ifdef MOZ_ENABLE_D3D10_LAYER
128 #include "LayerManagerD3D10.h"
131 #include "LayerManagerOGL.h"
132 #include "nsIGfxInfo.h"
133 #include "BasicLayers.h"
134 #include "nsUXThemeConstants.h"
135 #include "KeyboardLayout.h"
136 #include "nsNativeDragTarget.h"
137 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
139 #include <richedit.h>
141 #if defined(ACCESSIBILITY)
144 #include "nsAccessibilityService.h"
145 #include "mozilla/a11y/Platform.h"
146 #if !defined(WINABLEAPI)
148 #endif // !defined(WINABLEAPI)
149 #endif // defined(ACCESSIBILITY)
151 #include "nsIWinTaskbar.h"
152 #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
154 // Windowless plugin support
157 #include "nsWindowDefs.h"
159 #include "nsCrashOnException.h"
160 #include "nsIXULRuntime.h"
162 #include "nsIContent.h"
164 #include "mozilla/HangMonitor.h"
165 #include "WinIMEHandler.h"
167 using namespace mozilla
;
168 using namespace mozilla::dom
;
169 using namespace mozilla::layers
;
170 using namespace mozilla::widget
;
172 /**************************************************************
173 **************************************************************
177 ** nsWindow Class static initializations and global variables.
179 **************************************************************
180 **************************************************************/
182 /**************************************************************
184 * SECTION: nsWindow statics
186 **************************************************************/
188 bool nsWindow::sDropShadowEnabled
= true;
189 uint32_t nsWindow::sInstanceCount
= 0;
190 bool nsWindow::sSwitchKeyboardLayout
= false;
191 BOOL
nsWindow::sIsOleInitialized
= FALSE
;
192 HCURSOR
nsWindow::sHCursor
= NULL
;
193 imgIContainer
* nsWindow::sCursorImgContainer
= nullptr;
194 nsWindow
* nsWindow::sCurrentWindow
= nullptr;
195 bool nsWindow::sJustGotDeactivate
= false;
196 bool nsWindow::sJustGotActivate
= false;
197 bool nsWindow::sIsInMouseCapture
= false;
199 // imported in nsWidgetFactory.cpp
200 TriStateBool
nsWindow::sCanQuit
= TRI_UNKNOWN
;
202 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
203 // hook methods whether they should be processing the hook
205 HHOOK
nsWindow::sMsgFilterHook
= NULL
;
206 HHOOK
nsWindow::sCallProcHook
= NULL
;
207 HHOOK
nsWindow::sCallMouseHook
= NULL
;
208 bool nsWindow::sProcessHook
= false;
209 UINT
nsWindow::sRollupMsgId
= 0;
210 HWND
nsWindow::sRollupMsgWnd
= NULL
;
211 UINT
nsWindow::sHookTimerId
= 0;
213 // Mouse Clicks - static variable definitions for figuring
215 POINT
nsWindow::sLastMousePoint
= {0};
216 POINT
nsWindow::sLastMouseMovePoint
= {0};
217 LONG
nsWindow::sLastMouseDownTime
= 0L;
218 LONG
nsWindow::sLastClickCount
= 0L;
219 BYTE
nsWindow::sLastMouseButton
= 0;
221 // Trim heap on minimize. (initialized, but still true.)
222 int nsWindow::sTrimOnMinimize
= 2;
224 // Default value for general window class (used when the pref is the empty string).
225 const char* nsWindow::sDefaultMainWindowClass
= kClassNameGeneral
;
227 // If we're using D3D9, this will not be allowed during initial 5 seconds.
228 bool nsWindow::sAllowD3D9
= false;
230 TriStateBool
nsWindow::sHasBogusPopupsDropShadowOnMultiMonitor
= TRI_UNKNOWN
;
232 // Used in OOPP plugin focus processing.
233 const PRUnichar
* kOOPPPluginFocusEventId
= L
"OOPP Plugin Focus Widget Event";
234 uint32_t nsWindow::sOOPPPluginFocusEvent
=
235 RegisterWindowMessageW(kOOPPPluginFocusEventId
);
237 MSG
nsWindow::sRedirectedKeyDown
;
239 /**************************************************************
241 * SECTION: globals variables
243 **************************************************************/
245 static const char *sScreenManagerContractID
= "@mozilla.org/gfx/screenmanager;1";
248 PRLogModuleInfo
* gWindowsLog
= nullptr;
251 // Kbd layout. Used throughout character processing.
252 static KeyboardLayout gKbdLayout
;
254 // Global used in Show window enumerations.
255 static bool gWindowsVisible
= false;
257 // True if we have sent a notification that we are suspending/sleeping.
258 static bool gIsSleepMode
= false;
260 static NS_DEFINE_CID(kCClipboardCID
, NS_CLIPBOARD_CID
);
262 // General purpose user32.dll hook object
263 static WindowsDllInterceptor sUser32Intercept
;
265 // 2 pixel offset for eTransparencyBorderlessGlass which equals the size of
266 // the default window border Windows paints. Glass will be extended inward
267 // this distance to remove the border.
268 static const int32_t kGlassMarginAdjustment
= 2;
270 // When the client area is extended out into the default window frame area,
271 // this is the minimum amount of space along the edge of resizable windows
272 // we will always display a resize cursor in, regardless of the underlying
274 static const int32_t kResizableBorderMinSize
= 3;
276 // We should never really try to accelerate windows bigger than this. In some
277 // cases this might lead to no D3D9 acceleration where we could have had it
278 // but D3D9 does not reliably report when it supports bigger windows. 8192
279 // is as safe as we can get, we know at least D3D10 hardware always supports
280 // this, other hardware we expect to report correctly in D3D9.
281 #define MAX_ACCELERATED_DIMENSION 8192
284 /**************************************************************
285 **************************************************************
287 ** BLOCK: nsIWidget impl.
289 ** nsIWidget interface implementation, broken down into
292 **************************************************************
293 **************************************************************/
295 /**************************************************************
297 * SECTION: nsWindow construction and destruction
299 **************************************************************/
301 nsWindow::nsWindow() : nsWindowBase()
305 gWindowsLog
= PR_NewLogModule("nsWindow");
309 mIconSmall
= nullptr;
313 mPrevWndProc
= nullptr;
314 mNativeDragTarget
= nullptr;
317 mIsTopWidgetWindow
= false;
318 mUnicodeWidget
= true;
319 mDisplayPanFeedback
= false;
320 mTouchWindow
= false;
321 mCustomNonClient
= false;
323 mFullscreenMode
= false;
324 mMousePresent
= false;
325 mDestroyCalled
= false;
326 mPickerDisplayCount
= 0;
327 mWindowType
= eWindowType_child
;
328 mBorderStyle
= eBorderStyle_default
;
329 mOldSizeMode
= nsSizeMode_Normal
;
330 mLastSizeMode
= nsSizeMode_Normal
;
334 mLastSize
.height
= 0;
338 mLastKeyboardLayout
= 0;
339 mBlurSuppressLevel
= 0;
340 mLastPaintEndTime
= TimeStamp::Now();
342 mTransparentSurface
= nullptr;
344 mTransparencyMode
= eTransparencyOpaque
;
345 memset(&mGlassMargins
, 0, sizeof mGlassMargins
);
347 mBackground
= ::GetSysColor(COLOR_BTNFACE
);
348 mBrush
= ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground
));
349 mForeground
= ::GetSysColor(COLOR_WINDOWTEXT
);
351 mTaskbarPreview
= nullptr;
352 mHasTaskbarIconBeenCreated
= false;
354 // Global initialization
355 if (!sInstanceCount
) {
356 // Global app registration id for Win7 and up. See
357 // WinTaskbar.cpp for details.
358 mozilla::widget::WinTaskbar::RegisterAppUserModelID();
359 gKbdLayout
.LoadLayout(::GetKeyboardLayout(0));
360 IMEHandler::Initialize();
361 if (SUCCEEDED(::OleInitialize(NULL
))) {
362 sIsOleInitialized
= TRUE
;
364 NS_ASSERTION(sIsOleInitialized
, "***** OLE is not initialized!\n");
365 MouseScrollHandler::Initialize();
366 // Init titlebar button info for custom frames.
367 nsUXThemeData::InitTitlebarInfo();
369 nsUXThemeData::UpdateNativeThemeInfo();
370 ForgetRedirectedKeyDownMessage();
373 mIdleService
= nullptr;
378 nsWindow::~nsWindow()
382 // If the widget was released without calling Destroy() then the native window still
383 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
385 // XXX How could this happen???
389 // Free app icon resources. This must happen after `OnDestroy` (see bug 708033).
391 ::DestroyIcon(mIconSmall
);
394 ::DestroyIcon(mIconBig
);
399 if (sInstanceCount
== 0) {
400 IMEHandler::Terminate();
401 NS_IF_RELEASE(sCursorImgContainer
);
402 if (sIsOleInitialized
) {
403 ::OleFlushClipboard();
405 sIsOleInitialized
= FALSE
;
409 NS_IF_RELEASE(mNativeDragTarget
);
412 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow
, nsBaseWidget
)
414 /**************************************************************
416 * SECTION: nsIWidget::Create, nsIWidget::Destroy
418 * Creating and destroying windows for this widget.
420 **************************************************************/
422 // Allow Derived classes to modify the height that is passed
423 // when the window is created or resized.
424 int32_t nsWindow::GetHeight(int32_t aProposedHeight
)
426 return aProposedHeight
;
429 // Create the proper widget
431 nsWindow::Create(nsIWidget
*aParent
,
432 nsNativeWidget aNativeParent
,
433 const nsIntRect
&aRect
,
434 nsDeviceContext
*aContext
,
435 nsWidgetInitData
*aInitData
)
437 nsWidgetInitData defaultInitData
;
439 aInitData
= &defaultInitData
;
441 mUnicodeWidget
= aInitData
->mUnicode
;
443 nsIWidget
*baseParent
= aInitData
->mWindowType
== eWindowType_dialog
||
444 aInitData
->mWindowType
== eWindowType_toplevel
||
445 aInitData
->mWindowType
== eWindowType_invisible
?
448 mIsTopWidgetWindow
= (nullptr == baseParent
);
451 // Ensure that the toolkit is created.
452 nsToolkit::GetToolkit();
454 BaseCreate(baseParent
, aRect
, aContext
, aInitData
);
457 if (aParent
) { // has a nsIWidget parent
458 parent
= aParent
? (HWND
)aParent
->GetNativeData(NS_NATIVE_WINDOW
) : NULL
;
460 } else { // has a nsNative parent
461 parent
= (HWND
)aNativeParent
;
462 mParent
= aNativeParent
?
463 WinUtils::GetNSWindowPtr((HWND
)aNativeParent
) : nullptr;
466 mIsRTL
= aInitData
->mRTL
;
468 DWORD style
= WindowStyle();
469 DWORD extendedStyle
= WindowExStyle();
471 if (mWindowType
== eWindowType_popup
) {
476 if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION
&&
477 WinUtils::GetWindowsVersion() <= WinUtils::WIN7_VERSION
) {
478 extendedStyle
|= WS_EX_COMPOSITED
;
481 if (aInitData
->mIsDragPopup
) {
482 // This flag makes the window transparent to mouse events
483 extendedStyle
|= WS_EX_TRANSPARENT
;
485 } else if (mWindowType
== eWindowType_invisible
) {
486 // Make sure CreateWindowEx succeeds at creating a toplevel window
487 style
&= ~0x40000000; // WS_CHILDWINDOW
489 // See if the caller wants to explictly set clip children and clip siblings
490 if (aInitData
->clipChildren
) {
491 style
|= WS_CLIPCHILDREN
;
493 style
&= ~WS_CLIPCHILDREN
;
495 if (aInitData
->clipSiblings
) {
496 style
|= WS_CLIPSIBLINGS
;
500 nsAutoString className
;
501 if (aInitData
->mDropShadow
) {
502 GetWindowPopupClass(className
);
504 GetWindowClass(className
);
506 // Plugins are created in the disabled state so that they can't
507 // steal focus away from our main window. This is especially
508 // important if the plugin has loaded in a background tab.
509 if(aInitData
->mWindowType
== eWindowType_plugin
) {
510 style
|= WS_DISABLED
;
512 mWnd
= ::CreateWindowExW(extendedStyle
,
519 GetHeight(aRect
.height
),
522 nsToolkit::mDllInstance
,
526 NS_WARNING("nsWindow CreateWindowEx failed.");
527 return NS_ERROR_FAILURE
;
530 if (mIsRTL
&& nsUXThemeData::dwmSetWindowAttributePtr
) {
531 DWORD dwAttribute
= TRUE
;
532 nsUXThemeData::dwmSetWindowAttributePtr(mWnd
, DWMWA_NONCLIENT_RTL_LAYOUT
, &dwAttribute
, sizeof dwAttribute
);
535 if (mWindowType
!= eWindowType_plugin
&&
536 mWindowType
!= eWindowType_invisible
&&
537 MouseScrollHandler::Device::IsFakeScrollableWindowNeeded()) {
538 // Ugly Thinkpad Driver Hack (Bugs 507222 and 594977)
540 // We create two zero-sized windows as descendants of the top-level window,
543 // Top-level window (MozillaWindowClass)
544 // FAKETRACKPOINTSCROLLCONTAINER (MozillaWindowClass)
545 // FAKETRACKPOINTSCROLLABLE (MozillaWindowClass)
547 // We need to have the middle window, otherwise the Trackpoint driver
548 // will fail to deliver scroll messages. WM_MOUSEWHEEL messages are
549 // sent to the FAKETRACKPOINTSCROLLABLE, which then propagate up the
550 // window hierarchy until they are handled by nsWindow::WindowProc.
551 // WM_HSCROLL messages are also sent to the FAKETRACKPOINTSCROLLABLE,
552 // but these do not propagate automatically, so we have the window
553 // procedure pretend that they were dispatched to the top-level window
556 // The FAKETRACKPOINTSCROLLABLE needs to have the specific window styles it
557 // is given below so that it catches the Trackpoint driver's heuristics.
558 HWND scrollContainerWnd
= ::CreateWindowW
559 (className
.get(), L
"FAKETRACKPOINTSCROLLCONTAINER",
560 WS_CHILD
| WS_VISIBLE
,
561 0, 0, 0, 0, mWnd
, NULL
, nsToolkit::mDllInstance
, NULL
);
562 HWND scrollableWnd
= ::CreateWindowW
563 (className
.get(), L
"FAKETRACKPOINTSCROLLABLE",
564 WS_CHILD
| WS_VISIBLE
| WS_VSCROLL
| WS_TABSTOP
| 0x30,
565 0, 0, 0, 0, scrollContainerWnd
, NULL
, nsToolkit::mDllInstance
, NULL
);
567 // Give the FAKETRACKPOINTSCROLLABLE window a specific ID so that
568 // WindowProcInternal can distinguish it from the top-level window
570 ::SetWindowLongPtrW(scrollableWnd
, GWLP_ID
, eFakeTrackPointScrollableID
);
572 // Make FAKETRACKPOINTSCROLLABLE use nsWindow::WindowProc, and store the
573 // old window procedure in its "user data".
576 oldWndProc
= (WNDPROC
)::SetWindowLongPtrW(scrollableWnd
, GWLP_WNDPROC
,
577 (LONG_PTR
)nsWindow::WindowProc
);
579 oldWndProc
= (WNDPROC
)::SetWindowLongPtrA(scrollableWnd
, GWLP_WNDPROC
,
580 (LONG_PTR
)nsWindow::WindowProc
);
581 ::SetWindowLongPtrW(scrollableWnd
, GWLP_USERDATA
, (LONG_PTR
)oldWndProc
);
584 SubclassWindow(TRUE
);
586 IMEHandler::InitInputContext(this, mInputContext
);
588 // If the internal variable set by the config.trim_on_minimize pref has not
589 // been initialized, and if this is the hidden window (conveniently created
590 // before any visible windows, and after the profile has been initialized),
591 // do some initialization work.
592 if (sTrimOnMinimize
== 2 && mWindowType
== eWindowType_invisible
) {
593 // Our internal trim prevention logic is effective on 2K/XP at maintaining
594 // the working set when windows are minimized, but on Vista and up it has
595 // little to no effect. Since this feature has been the source of numerous
596 // bugs over the years, disable it (sTrimOnMinimize=1) on Vista and up.
598 Preferences::GetBool("config.trim_on_minimize",
599 (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION
)) ? 1 : 0;
600 sSwitchKeyboardLayout
=
601 Preferences::GetBool("intl.keyboard.per_window_layout", false);
607 // Close this nsWindow
608 NS_METHOD
nsWindow::Destroy()
610 // WM_DESTROY has already fired, avoid calling it twice
611 if (mOnDestroyCalled
)
614 // Don't destroy windows that have file pickers open, we'll tear these down
615 // later once the picker is closed.
616 mDestroyCalled
= true;
617 if (mPickerDisplayCount
)
620 // During the destruction of all of our children, make sure we don't get deleted.
621 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
624 * On windows the LayerManagerOGL destructor wants the widget to be around for
625 * cleanup. It also would like to have the HWND intact, so we NULL it here.
628 mLayerManager
->Destroy();
630 mLayerManager
= nullptr;
632 /* We should clear our cached resources now and not wait for the GC to
633 * delete the nsWindow. */
634 ClearCachedResources();
636 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
637 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
638 // from it. The function also destroys the window's menu, flushes the thread message queue,
639 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
640 // the window is at the top of the viewer chain).
642 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
643 // the associated child or owned windows when it destroys the parent or owner window. The
644 // function first destroys child or owned windows, and then it destroys the parent or owner
646 VERIFY(::DestroyWindow(mWnd
));
648 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
649 // didn't get called, call it now.
650 if (false == mOnDestroyCalled
) {
652 mWindowHook
.Notify(mWnd
, WM_DESTROY
, 0, 0, &result
);
659 /**************************************************************
661 * SECTION: Window class utilities
663 * Utilities for calculating the proper window class name for
666 **************************************************************/
668 void nsWindow::RegisterWindowClass(const nsString
& aClassName
, UINT aExtraStyle
,
672 if (::GetClassInfoW(nsToolkit::mDllInstance
, aClassName
.get(), &wc
)) {
673 // already registered
677 wc
.style
= CS_DBLCLKS
| aExtraStyle
;
678 wc
.lpfnWndProc
= ::DefWindowProcW
;
681 wc
.hInstance
= nsToolkit::mDllInstance
;
682 wc
.hIcon
= aIconID
? ::LoadIconW(::GetModuleHandleW(NULL
), aIconID
) : NULL
;
684 wc
.hbrBackground
= mBrush
;
685 wc
.lpszMenuName
= NULL
;
686 wc
.lpszClassName
= aClassName
.get();
688 if (!::RegisterClassW(&wc
)) {
689 // For older versions of Win32 (i.e., not XP), the registration may
690 // fail with aExtraStyle, so we have to re-register without it.
691 wc
.style
= CS_DBLCLKS
;
692 ::RegisterClassW(&wc
);
696 static LPWSTR
const gStockApplicationIcon
= MAKEINTRESOURCEW(32512);
698 // Return the proper window class for everything except popups.
699 void nsWindow::GetWindowClass(nsString
& aWindowClass
)
701 switch (mWindowType
) {
702 case eWindowType_invisible
:
703 aWindowClass
.AssignLiteral(kClassNameHidden
);
704 RegisterWindowClass(aWindowClass
, 0, gStockApplicationIcon
);
706 case eWindowType_dialog
:
707 aWindowClass
.AssignLiteral(kClassNameDialog
);
708 RegisterWindowClass(aWindowClass
, 0, 0);
711 GetMainWindowClass(aWindowClass
);
712 RegisterWindowClass(aWindowClass
, 0, gStockApplicationIcon
);
717 // Return the proper popup window class
718 void nsWindow::GetWindowPopupClass(nsString
& aWindowClass
)
720 aWindowClass
.AssignLiteral(kClassNameDropShadow
);
721 RegisterWindowClass(aWindowClass
, CS_XP_DROPSHADOW
, gStockApplicationIcon
);
724 /**************************************************************
726 * SECTION: Window styles utilities
728 * Return the proper windows styles and extended styles.
730 **************************************************************/
732 // Return nsWindow styles
733 DWORD
nsWindow::WindowStyle()
737 switch (mWindowType
) {
738 case eWindowType_plugin
:
739 case eWindowType_child
:
740 style
= WS_OVERLAPPED
;
743 case eWindowType_dialog
:
744 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
| DS_3DLOOK
|
745 DS_MODALFRAME
| WS_CLIPCHILDREN
;
746 if (mBorderStyle
!= eBorderStyle_default
)
747 style
|= WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
;
750 case eWindowType_popup
:
753 style
|= WS_OVERLAPPED
;
758 NS_ERROR("unknown border style");
761 case eWindowType_toplevel
:
762 case eWindowType_invisible
:
763 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
|
764 WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
| WS_CLIPCHILDREN
;
768 if (mBorderStyle
!= eBorderStyle_default
&& mBorderStyle
!= eBorderStyle_all
) {
769 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_border
))
772 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_title
)) {
773 style
&= ~WS_DLGFRAME
;
778 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_close
))
780 // XXX The close box can only be removed by changing the window class,
781 // as far as I know --- roc+moz@cs.cmu.edu
783 if (mBorderStyle
== eBorderStyle_none
||
784 !(mBorderStyle
& (eBorderStyle_menu
| eBorderStyle_close
)))
785 style
&= ~WS_SYSMENU
;
786 // Looks like getting rid of the system menu also does away with the
787 // close box. So, we only get rid of the system menu if you want neither it
788 // nor the close box. How does the Windows "Dialog" window class get just
789 // closebox and no sysmenu? Who knows.
791 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_resizeh
))
792 style
&= ~WS_THICKFRAME
;
794 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_minimize
))
795 style
&= ~WS_MINIMIZEBOX
;
797 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_maximize
))
798 style
&= ~WS_MAXIMIZEBOX
;
800 if (IsPopupWithTitleBar()) {
802 if (mBorderStyle
& eBorderStyle_close
) {
808 VERIFY_WINDOW_STYLE(style
);
812 // Return nsWindow extended styles
813 DWORD
nsWindow::WindowExStyle()
817 case eWindowType_plugin
:
818 case eWindowType_child
:
821 case eWindowType_dialog
:
822 return WS_EX_WINDOWEDGE
| WS_EX_DLGMODALFRAME
;
824 case eWindowType_popup
:
826 DWORD extendedStyle
= WS_EX_TOOLWINDOW
;
827 if (mPopupLevel
== ePopupLevelTop
)
828 extendedStyle
|= WS_EX_TOPMOST
;
829 return extendedStyle
;
832 NS_ERROR("unknown border style");
835 case eWindowType_toplevel
:
836 case eWindowType_invisible
:
837 return WS_EX_WINDOWEDGE
;
841 /**************************************************************
843 * SECTION: Window subclassing utilities
845 * Set or clear window subclasses on native windows. Used in
846 * Create and Destroy.
848 **************************************************************/
850 // Subclass (or remove the subclass from) this component's nsWindow
851 void nsWindow::SubclassWindow(BOOL bState
)
854 if (!mWnd
|| !IsWindow(mWnd
)) {
855 NS_ERROR("Invalid window handle");
858 if (mUnicodeWidget
) {
860 reinterpret_cast<WNDPROC
>(
861 SetWindowLongPtrW(mWnd
,
863 reinterpret_cast<LONG_PTR
>(nsWindow::WindowProc
)));
866 reinterpret_cast<WNDPROC
>(
867 SetWindowLongPtrA(mWnd
,
869 reinterpret_cast<LONG_PTR
>(nsWindow::WindowProc
)));
871 NS_ASSERTION(mPrevWndProc
, "Null standard window procedure");
872 // connect the this pointer to the nsWindow handle
873 WinUtils::SetNSWindowPtr(mWnd
, this);
875 if (IsWindow(mWnd
)) {
876 if (mUnicodeWidget
) {
877 SetWindowLongPtrW(mWnd
,
879 reinterpret_cast<LONG_PTR
>(mPrevWndProc
));
881 SetWindowLongPtrA(mWnd
,
883 reinterpret_cast<LONG_PTR
>(mPrevWndProc
));
886 WinUtils::SetNSWindowPtr(mWnd
, NULL
);
891 /**************************************************************
893 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
895 * Set or clear the parent widgets using window properties, and
896 * handles calculating native parent handles.
898 **************************************************************/
900 // Get and set parent widgets
901 NS_IMETHODIMP
nsWindow::SetParent(nsIWidget
*aNewParent
)
903 mParent
= aNewParent
;
905 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
906 nsIWidget
* parent
= GetParent();
908 parent
->RemoveChild(this);
911 ReparentNativeWidget(aNewParent
);
912 aNewParent
->AddChild(this);
916 // If we have no parent, SetParent should return the desktop.
917 VERIFY(::SetParent(mWnd
, nullptr));
923 nsWindow::ReparentNativeWidget(nsIWidget
* aNewParent
)
925 NS_PRECONDITION(aNewParent
, "");
927 mParent
= aNewParent
;
928 if (mWindowType
== eWindowType_popup
) {
931 HWND newParent
= (HWND
)aNewParent
->GetNativeData(NS_NATIVE_WINDOW
);
932 NS_ASSERTION(newParent
, "Parent widget has a null native window handle");
933 if (newParent
&& mWnd
) {
934 ::SetParent(mWnd
, newParent
);
939 nsIWidget
* nsWindow::GetParent(void)
941 return GetParentWindow(false);
944 float nsWindow::GetDPI()
946 HDC dc
= ::GetDC(mWnd
);
950 double heightInches
= ::GetDeviceCaps(dc
, VERTSIZE
)/MM_PER_INCH_FLOAT
;
951 int heightPx
= ::GetDeviceCaps(dc
, VERTRES
);
952 ::ReleaseDC(mWnd
, dc
);
953 if (heightInches
< 0.25) {
954 // Something's broken
957 return float(heightPx
/heightInches
);
960 double nsWindow::GetDefaultScaleInternal()
962 return gfxWindowsPlatform::GetPlatform()->GetDPIScale();
965 nsWindow
* nsWindow::GetParentWindow(bool aIncludeOwner
)
967 if (mIsTopWidgetWindow
) {
968 // Must use a flag instead of mWindowType to tell if the window is the
969 // owned by the topmost widget, because a child window can be embedded inside
970 // a HWND which is not associated with a nsIWidget.
974 // If this widget has already been destroyed, pretend we have no parent.
975 // This corresponds to code in Destroy which removes the destroyed
976 // widget from its parent's child list.
977 if (mInDtor
|| mOnDestroyCalled
)
981 // aIncludeOwner set to true implies walking the parent chain to retrieve the
982 // root owner. aIncludeOwner set to false implies the search will stop at the
983 // true parent (default).
984 nsWindow
* widget
= nullptr;
986 HWND parent
= nullptr;
988 parent
= ::GetParent(mWnd
);
990 parent
= ::GetAncestor(mWnd
, GA_PARENT
);
993 widget
= WinUtils::GetNSWindowPtr(parent
);
995 // If the widget is in the process of being destroyed then
997 if (widget
->mInDtor
) {
1008 nsWindow::EnumAllChildWindProc(HWND aWnd
, LPARAM aParam
)
1010 nsWindow
*wnd
= WinUtils::GetNSWindowPtr(aWnd
);
1012 ((nsWindow::WindowEnumCallback
*)aParam
)(wnd
);
1018 nsWindow::EnumAllThreadWindowProc(HWND aWnd
, LPARAM aParam
)
1020 nsWindow
*wnd
= WinUtils::GetNSWindowPtr(aWnd
);
1022 ((nsWindow::WindowEnumCallback
*)aParam
)(wnd
);
1024 EnumChildWindows(aWnd
, EnumAllChildWindProc
, aParam
);
1029 nsWindow::EnumAllWindows(WindowEnumCallback aCallback
)
1031 EnumThreadWindows(GetCurrentThreadId(),
1032 EnumAllThreadWindowProc
,
1036 /**************************************************************
1038 * SECTION: nsIWidget::Show
1040 * Hide or show this component.
1042 **************************************************************/
1044 NS_METHOD
nsWindow::Show(bool bState
)
1046 if (mWindowType
== eWindowType_popup
) {
1047 // See bug 603793. When we try to draw D3D9/10 windows with a drop shadow
1048 // without the DWM on a secondary monitor, windows fails to composite
1049 // our windows correctly. We therefor switch off the drop shadow for
1050 // pop-up windows when the DWM is disabled and two monitors are
1052 if (HasBogusPopupsDropShadowOnMultiMonitor() &&
1053 WinUtils::GetMonitorCount() > 1 &&
1054 !nsUXThemeData::CheckForCompositor())
1056 if (sDropShadowEnabled
) {
1057 ::SetClassLongA(mWnd
, GCL_STYLE
, 0);
1058 sDropShadowEnabled
= false;
1061 if (!sDropShadowEnabled
) {
1062 ::SetClassLongA(mWnd
, GCL_STYLE
, CS_DROPSHADOW
);
1063 sDropShadowEnabled
= true;
1067 // WS_EX_COMPOSITED conflicts with the WS_EX_LAYERED style and causes
1068 // some popup menus to become invisible.
1069 LONG_PTR exStyle
= ::GetWindowLongPtrW(mWnd
, GWL_EXSTYLE
);
1070 if (exStyle
& WS_EX_LAYERED
) {
1071 ::SetWindowLongPtrW(mWnd
, GWL_EXSTYLE
, exStyle
& ~WS_EX_COMPOSITED
);
1075 bool syncInvalidate
= false;
1077 bool wasVisible
= mIsVisible
;
1078 // Set the status now so that anyone asking during ShowWindow or
1079 // SetWindowPos would get the correct answer.
1080 mIsVisible
= bState
;
1082 // We may have cached an out of date visible state. This can happen
1083 // when session restore sets the full screen mode.
1085 mOldStyle
|= WS_VISIBLE
;
1087 mOldStyle
&= ~WS_VISIBLE
;
1089 if (!mIsVisible
&& wasVisible
) {
1090 ClearCachedResources();
1095 if (!wasVisible
&& mWindowType
== eWindowType_toplevel
) {
1096 // speed up the initial paint after show for
1097 // top level windows:
1098 syncInvalidate
= true;
1099 switch (mSizeMode
) {
1100 case nsSizeMode_Fullscreen
:
1101 ::ShowWindow(mWnd
, SW_SHOW
);
1103 case nsSizeMode_Maximized
:
1104 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1106 case nsSizeMode_Minimized
:
1107 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
1110 if (CanTakeFocus()) {
1111 ::ShowWindow(mWnd
, SW_SHOWNORMAL
);
1113 // Place the window behind the foreground window
1114 // (as long as it is not topmost)
1115 HWND wndAfter
= ::GetForegroundWindow();
1117 wndAfter
= HWND_BOTTOM
;
1118 else if (GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
1119 wndAfter
= HWND_TOP
;
1120 ::SetWindowPos(mWnd
, wndAfter
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOSIZE
|
1121 SWP_NOMOVE
| SWP_NOACTIVATE
);
1127 DWORD flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_SHOWWINDOW
;
1129 flags
|= SWP_NOZORDER
;
1131 if (mWindowType
== eWindowType_popup
) {
1132 // ensure popups are the topmost of the TOPMOST
1133 // layer. Remember not to set the SWP_NOZORDER
1134 // flag as that might allow the taskbar to overlap
1136 flags
|= SWP_NOACTIVATE
;
1137 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
1138 ::SetWindowPos(mWnd
, owner
? 0 : HWND_TOPMOST
, 0, 0, 0, 0, flags
);
1140 if (mWindowType
== eWindowType_dialog
&& !CanTakeFocus())
1141 flags
|= SWP_NOACTIVATE
;
1143 ::SetWindowPos(mWnd
, HWND_TOP
, 0, 0, 0, 0, flags
);
1147 if (!wasVisible
&& (mWindowType
== eWindowType_toplevel
|| mWindowType
== eWindowType_dialog
)) {
1148 // when a toplevel window or dialog is shown, initialize the UI state
1149 ::SendMessageW(mWnd
, WM_CHANGEUISTATE
, MAKEWPARAM(UIS_INITIALIZE
, UISF_HIDEFOCUS
| UISF_HIDEACCEL
), 0);
1152 // Clear contents to avoid ghosting of old content if we display
1153 // this window again.
1154 if (wasVisible
&& mTransparencyMode
== eTransparencyTransparent
) {
1155 ClearTranslucentWindow();
1157 if (mWindowType
!= eWindowType_dialog
) {
1158 ::ShowWindow(mWnd
, SW_HIDE
);
1160 ::SetWindowPos(mWnd
, 0, 0, 0, 0, 0, SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
|
1161 SWP_NOZORDER
| SWP_NOACTIVATE
);
1167 if (!wasVisible
&& bState
) {
1169 if (syncInvalidate
&& !mInDtor
&& !mOnDestroyCalled
) {
1170 ::UpdateWindow(mWnd
);
1178 /**************************************************************
1180 * SECTION: nsIWidget::IsVisible
1182 * Returns the visibility state.
1184 **************************************************************/
1186 // Return true if the whether the component is visible, false otherwise
1187 bool nsWindow::IsVisible() const
1192 /**************************************************************
1194 * SECTION: Window clipping utilities
1196 * Used in Size and Move operations for setting the proper
1197 * window clipping regions for window transparency.
1199 **************************************************************/
1201 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1202 // transparency. These routines are called on size and move operations.
1203 void nsWindow::ClearThemeRegion()
1205 if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION
&&
1207 (mWindowType
== eWindowType_popup
&& !IsPopupWithTitleBar() &&
1208 (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
))) {
1209 SetWindowRgn(mWnd
, NULL
, false);
1213 void nsWindow::SetThemeRegion()
1215 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1216 // for other window types as needed. The regions are applied generically to the base window
1217 // so default constants are used for part and state. At some point we might need part and
1218 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1219 // change shape based on state haven't come up.
1220 if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION
&&
1222 (mWindowType
== eWindowType_popup
&& !IsPopupWithTitleBar() &&
1223 (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
))) {
1224 HRGN hRgn
= nullptr;
1225 RECT rect
= {0,0,mBounds
.width
,mBounds
.height
};
1227 HDC dc
= ::GetDC(mWnd
);
1228 GetThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip
), dc
, TTP_STANDARD
, TS_NORMAL
, &rect
, &hRgn
);
1230 if (!SetWindowRgn(mWnd
, hRgn
, false)) // do not delete or alter hRgn if accepted.
1233 ::ReleaseDC(mWnd
, dc
);
1237 /**************************************************************
1239 * SECTION: nsIWidget::RegisterTouchWindow,
1240 * nsIWidget::UnregisterTouchWindow, and helper functions
1242 * Used to register the native window to receive touch events
1244 **************************************************************/
1246 NS_METHOD
nsWindow::RegisterTouchWindow() {
1247 mTouchWindow
= true;
1248 mGesture
.RegisterTouchWindow(mWnd
);
1249 ::EnumChildWindows(mWnd
, nsWindow::RegisterTouchForDescendants
, 0);
1253 NS_METHOD
nsWindow::UnregisterTouchWindow() {
1254 mTouchWindow
= false;
1255 mGesture
.UnregisterTouchWindow(mWnd
);
1256 ::EnumChildWindows(mWnd
, nsWindow::UnregisterTouchForDescendants
, 0);
1260 BOOL CALLBACK
nsWindow::RegisterTouchForDescendants(HWND aWnd
, LPARAM aMsg
) {
1261 nsWindow
* win
= WinUtils::GetNSWindowPtr(aWnd
);
1263 win
->mGesture
.RegisterTouchWindow(aWnd
);
1267 BOOL CALLBACK
nsWindow::UnregisterTouchForDescendants(HWND aWnd
, LPARAM aMsg
) {
1268 nsWindow
* win
= WinUtils::GetNSWindowPtr(aWnd
);
1270 win
->mGesture
.UnregisterTouchWindow(aWnd
);
1274 /**************************************************************
1276 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1277 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1279 * Repositioning and sizing a window.
1281 **************************************************************/
1284 nsWindow::SetSizeConstraints(const SizeConstraints
& aConstraints
)
1286 SizeConstraints c
= aConstraints
;
1287 if (mWindowType
!= eWindowType_popup
) {
1288 c
.mMinSize
.width
= std::max(int32_t(::GetSystemMetrics(SM_CXMINTRACK
)), c
.mMinSize
.width
);
1289 c
.mMinSize
.height
= std::max(int32_t(::GetSystemMetrics(SM_CYMINTRACK
)), c
.mMinSize
.height
);
1292 nsBaseWidget::SetSizeConstraints(c
);
1295 // Move this component
1296 NS_METHOD
nsWindow::Move(double aX
, double aY
)
1298 if (mWindowType
== eWindowType_toplevel
||
1299 mWindowType
== eWindowType_dialog
) {
1300 SetSizeMode(nsSizeMode_Normal
);
1303 // for top-level windows only, convert coordinates from global display pixels
1304 // (the "parent" coordinate space) to the window's device pixel space
1305 double scale
= BoundsUseDisplayPixels() ? GetDefaultScale() : 1.0;
1306 int32_t x
= NSToIntRound(aX
* scale
);
1307 int32_t y
= NSToIntRound(aY
* scale
);
1309 // Check to see if window needs to be moved first
1310 // to avoid a costly call to SetWindowPos. This check
1311 // can not be moved to the calling code in nsView, because
1312 // some platforms do not position child windows correctly
1314 // Only perform this check for non-popup windows, since the positioning can
1315 // in fact change even when the x/y do not. We always need to perform the
1316 // check. See bug #97805 for details.
1317 if (mWindowType
!= eWindowType_popup
&& (mBounds
.x
== x
) && (mBounds
.y
== y
))
1319 // Nothing to do, since it is already positioned correctly.
1328 // complain if a window is moved offscreen (legal, but potentially worrisome)
1329 if (mIsTopWidgetWindow
) { // only a problem for top-level windows
1330 // Make sure this window is actually on the screen before we move it
1331 // XXX: Needs multiple monitor support
1332 HDC dc
= ::GetDC(mWnd
);
1334 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1336 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &workArea
, 0);
1337 // no annoying assertions. just mention the issue.
1338 if (x
< 0 || x
>= workArea
.right
|| y
< 0 || y
>= workArea
.bottom
) {
1339 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
1340 ("window moved to offscreen position\n"));
1343 ::ReleaseDC(mWnd
, dc
);
1349 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOSIZE
;
1350 // Workaround SetWindowPos bug with D3D9. If our window has a clip
1351 // region, some drivers or OSes may incorrectly copy into the clipped-out
1353 if (mWindowType
== eWindowType_plugin
&&
1354 (!mLayerManager
|| mLayerManager
->GetBackendType() == LAYERS_D3D9
) &&
1356 (mClipRectCount
!= 1 || !mClipRects
[0].IsEqualInterior(nsIntRect(0, 0, mBounds
.width
, mBounds
.height
)))) {
1357 flags
|= SWP_NOCOPYBITS
;
1359 VERIFY(::SetWindowPos(mWnd
, NULL
, x
, y
, 0, 0, flags
));
1363 NotifyRollupGeometryChange();
1367 // Resize this component
1368 NS_METHOD
nsWindow::Resize(double aWidth
, double aHeight
, bool aRepaint
)
1370 // for top-level windows only, convert coordinates from global display pixels
1371 // (the "parent" coordinate space) to the window's device pixel space
1372 double scale
= BoundsUseDisplayPixels() ? GetDefaultScale() : 1.0;
1373 int32_t width
= NSToIntRound(aWidth
* scale
);
1374 int32_t height
= NSToIntRound(aHeight
* scale
);
1376 NS_ASSERTION((width
>= 0) , "Negative width passed to nsWindow::Resize");
1377 NS_ASSERTION((height
>= 0), "Negative height passed to nsWindow::Resize");
1379 ConstrainSize(&width
, &height
);
1381 // Avoid unnecessary resizing calls
1382 if (mBounds
.width
== width
&& mBounds
.height
== height
) {
1390 if (eTransparencyTransparent
== mTransparencyMode
)
1391 ResizeTranslucentWindow(width
, height
);
1394 // Set cached value for lightweight and printing
1395 mBounds
.width
= width
;
1396 mBounds
.height
= height
;
1399 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOMOVE
;
1402 flags
|= SWP_NOREDRAW
;
1406 VERIFY(::SetWindowPos(mWnd
, NULL
, 0, 0, width
, GetHeight(height
), flags
));
1413 NotifyRollupGeometryChange();
1417 // Resize this component
1418 NS_METHOD
nsWindow::Resize(double aX
, double aY
, double aWidth
, double aHeight
, bool aRepaint
)
1420 // for top-level windows only, convert coordinates from global display pixels
1421 // (the "parent" coordinate space) to the window's device pixel space
1422 double scale
= BoundsUseDisplayPixels() ? GetDefaultScale() : 1.0;
1423 int32_t x
= NSToIntRound(aX
* scale
);
1424 int32_t y
= NSToIntRound(aY
* scale
);
1425 int32_t width
= NSToIntRound(aWidth
* scale
);
1426 int32_t height
= NSToIntRound(aHeight
* scale
);
1428 NS_ASSERTION((width
>= 0), "Negative width passed to nsWindow::Resize");
1429 NS_ASSERTION((height
>= 0), "Negative height passed to nsWindow::Resize");
1431 ConstrainSize(&width
, &height
);
1433 // Avoid unnecessary resizing calls
1434 if (mBounds
.x
== x
&& mBounds
.y
== y
&&
1435 mBounds
.width
== width
&& mBounds
.height
== height
) {
1443 if (eTransparencyTransparent
== mTransparencyMode
)
1444 ResizeTranslucentWindow(width
, height
);
1447 // Set cached value for lightweight and printing
1450 mBounds
.width
= width
;
1451 mBounds
.height
= height
;
1454 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
1456 flags
|= SWP_NOREDRAW
;
1460 VERIFY(::SetWindowPos(mWnd
, NULL
, x
, y
, width
, GetHeight(height
), flags
));
1467 NotifyRollupGeometryChange();
1472 nsWindow::BeginResizeDrag(nsGUIEvent
* aEvent
, int32_t aHorizontal
, int32_t aVertical
)
1474 NS_ENSURE_ARG_POINTER(aEvent
);
1476 if (aEvent
->eventStructType
!= NS_MOUSE_EVENT
) {
1477 // you can only begin a resize drag with a mouse event
1478 return NS_ERROR_INVALID_ARG
;
1481 nsMouseEvent
* mouseEvent
= static_cast<nsMouseEvent
*>(aEvent
);
1482 if (mouseEvent
->button
!= nsMouseEvent::eLeftButton
) {
1483 // you can only begin a resize drag with the left mouse button
1484 return NS_ERROR_INVALID_ARG
;
1487 // work out what sizemode we're talking about
1489 if (aVertical
< 0) {
1490 if (aHorizontal
< 0) {
1491 syscommand
= SC_SIZE
| WMSZ_TOPLEFT
;
1492 } else if (aHorizontal
== 0) {
1493 syscommand
= SC_SIZE
| WMSZ_TOP
;
1495 syscommand
= SC_SIZE
| WMSZ_TOPRIGHT
;
1497 } else if (aVertical
== 0) {
1498 if (aHorizontal
< 0) {
1499 syscommand
= SC_SIZE
| WMSZ_LEFT
;
1500 } else if (aHorizontal
== 0) {
1501 return NS_ERROR_INVALID_ARG
;
1503 syscommand
= SC_SIZE
| WMSZ_RIGHT
;
1506 if (aHorizontal
< 0) {
1507 syscommand
= SC_SIZE
| WMSZ_BOTTOMLEFT
;
1508 } else if (aHorizontal
== 0) {
1509 syscommand
= SC_SIZE
| WMSZ_BOTTOM
;
1511 syscommand
= SC_SIZE
| WMSZ_BOTTOMRIGHT
;
1515 // resizing doesn't work if the mouse is already captured
1516 CaptureMouse(false);
1518 // find the top-level window
1519 HWND toplevelWnd
= WinUtils::GetTopLevelHWND(mWnd
, true);
1521 // tell Windows to start the resize
1522 ::PostMessage(toplevelWnd
, WM_SYSCOMMAND
, syscommand
,
1523 POINTTOPOINTS(aEvent
->refPoint
));
1528 /**************************************************************
1530 * SECTION: Window Z-order and state.
1532 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1533 * nsIWidget::ConstrainPosition
1535 * Z-order, positioning, restore, minimize, and maximize.
1537 **************************************************************/
1539 // Position the window behind the given window
1540 NS_METHOD
nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement
,
1541 nsIWidget
*aWidget
, bool aActivate
)
1543 HWND behind
= HWND_TOP
;
1544 if (aPlacement
== eZPlacementBottom
)
1545 behind
= HWND_BOTTOM
;
1546 else if (aPlacement
== eZPlacementBelow
&& aWidget
)
1547 behind
= (HWND
)aWidget
->GetNativeData(NS_NATIVE_WINDOW
);
1548 UINT flags
= SWP_NOMOVE
| SWP_NOREPOSITION
| SWP_NOSIZE
;
1550 flags
|= SWP_NOACTIVATE
;
1552 if (!CanTakeFocus() && behind
== HWND_TOP
)
1554 // Can't place the window to top so place it behind the foreground window
1555 // (as long as it is not topmost)
1556 HWND wndAfter
= ::GetForegroundWindow();
1558 behind
= HWND_BOTTOM
;
1559 else if (!(GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
1561 flags
|= SWP_NOACTIVATE
;
1564 ::SetWindowPos(mWnd
, behind
, 0, 0, 0, 0, flags
);
1568 // Maximize, minimize or restore the window.
1569 NS_IMETHODIMP
nsWindow::SetSizeMode(int32_t aMode
) {
1573 // Let's not try and do anything if we're already in that state.
1574 // (This is needed to prevent problems when calling window.minimize(), which
1575 // calls us directly, and then the OS triggers another call to us.)
1576 if (aMode
== mSizeMode
)
1579 // save the requested state
1580 mLastSizeMode
= mSizeMode
;
1581 rv
= nsBaseWidget::SetSizeMode(aMode
);
1582 if (NS_SUCCEEDED(rv
) && mIsVisible
) {
1586 case nsSizeMode_Fullscreen
:
1590 case nsSizeMode_Maximized
:
1594 case nsSizeMode_Minimized
:
1595 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1596 // keeps the window active in the tray. So after the window is minimized,
1597 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1598 // we will do some additional processing to get the active window set right.
1599 // If sTrimOnMinimize is set, we let windows handle minimization normally
1600 // using SW_MINIMIZE.
1601 mode
= sTrimOnMinimize
? SW_MINIMIZE
: SW_SHOWMINIMIZED
;
1609 pl
.length
= sizeof(pl
);
1610 ::GetWindowPlacement(mWnd
, &pl
);
1611 // Don't call ::ShowWindow if we're trying to "restore" a window that is
1612 // already in a normal state. Prevents a bug where snapping to one side
1613 // of the screen and then minimizing would cause Windows to forget our
1614 // window's correct restored position/size.
1615 if( !(pl
.showCmd
== SW_SHOWNORMAL
&& mode
== SW_RESTORE
) ) {
1616 ::ShowWindow(mWnd
, mode
);
1618 // we activate here to ensure that the right child window is focused
1619 if (mode
== SW_MAXIMIZE
|| mode
== SW_SHOW
)
1620 DispatchFocusToTopLevelWindow(true);
1625 // Constrain a potential move to fit onscreen
1626 // Position (aX, aY) is specified in Windows screen (logical) pixels
1627 NS_METHOD
nsWindow::ConstrainPosition(bool aAllowSlop
,
1628 int32_t *aX
, int32_t *aY
)
1630 if (!mIsTopWidgetWindow
) // only a problem for top-level windows
1633 double dpiScale
= GetDefaultScale();
1635 // we need to use the window size in logical screen pixels
1636 int32_t logWidth
= std::max
<int32_t>(NSToIntRound(mBounds
.width
/ dpiScale
), 1);
1637 int32_t logHeight
= std::max
<int32_t>(NSToIntRound(mBounds
.height
/ dpiScale
), 1);
1639 bool doConstrain
= false; // whether we have enough info to do anything
1641 /* get our playing field. use the current screen, or failing that
1642 for any reason, use device caps for the default screen. */
1645 nsCOMPtr
<nsIScreenManager
> screenmgr
= do_GetService(sScreenManagerContractID
);
1647 nsCOMPtr
<nsIScreen
> screen
;
1648 int32_t left
, top
, width
, height
;
1650 screenmgr
->ScreenForRect(*aX
, *aY
, logWidth
, logHeight
,
1651 getter_AddRefs(screen
));
1653 if (mSizeMode
!= nsSizeMode_Fullscreen
) {
1654 // For normalized windows, use the desktop work area.
1655 screen
->GetAvailRectDisplayPix(&left
, &top
, &width
, &height
);
1657 // For full screen windows, use the desktop.
1658 screen
->GetRectDisplayPix(&left
, &top
, &width
, &height
);
1660 screenRect
.left
= left
;
1661 screenRect
.right
= left
+ width
;
1662 screenRect
.top
= top
;
1663 screenRect
.bottom
= top
+ height
;
1668 HDC dc
= ::GetDC(mWnd
);
1670 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1671 if (mSizeMode
!= nsSizeMode_Fullscreen
) {
1672 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &screenRect
, 0);
1674 screenRect
.left
= screenRect
.top
= 0;
1675 screenRect
.right
= GetSystemMetrics(SM_CXFULLSCREEN
);
1676 screenRect
.bottom
= GetSystemMetrics(SM_CYFULLSCREEN
);
1680 ::ReleaseDC(mWnd
, dc
);
1686 if (*aX
< screenRect
.left
- logWidth
+ kWindowPositionSlop
)
1687 *aX
= screenRect
.left
- logWidth
+ kWindowPositionSlop
;
1688 else if (*aX
>= screenRect
.right
- kWindowPositionSlop
)
1689 *aX
= screenRect
.right
- kWindowPositionSlop
;
1691 if (*aY
< screenRect
.top
- logHeight
+ kWindowPositionSlop
)
1692 *aY
= screenRect
.top
- logHeight
+ kWindowPositionSlop
;
1693 else if (*aY
>= screenRect
.bottom
- kWindowPositionSlop
)
1694 *aY
= screenRect
.bottom
- kWindowPositionSlop
;
1698 if (*aX
< screenRect
.left
)
1699 *aX
= screenRect
.left
;
1700 else if (*aX
>= screenRect
.right
- logWidth
)
1701 *aX
= screenRect
.right
- logWidth
;
1703 if (*aY
< screenRect
.top
)
1704 *aY
= screenRect
.top
;
1705 else if (*aY
>= screenRect
.bottom
- logHeight
)
1706 *aY
= screenRect
.bottom
- logHeight
;
1712 /**************************************************************
1714 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1716 * Enabling and disabling the widget.
1718 **************************************************************/
1720 // Enable/disable this component
1721 NS_METHOD
nsWindow::Enable(bool bState
)
1724 ::EnableWindow(mWnd
, bState
);
1729 // Return the current enable state
1730 bool nsWindow::IsEnabled() const
1733 (::IsWindowEnabled(mWnd
) &&
1734 ::IsWindowEnabled(::GetAncestor(mWnd
, GA_ROOT
)));
1738 /**************************************************************
1740 * SECTION: nsIWidget::SetFocus
1742 * Give the focus to this widget.
1744 **************************************************************/
1746 NS_METHOD
nsWindow::SetFocus(bool aRaise
)
1749 #ifdef WINSTATE_DEBUG_OUTPUT
1750 if (mWnd
== WinUtils::GetTopLevelHWND(mWnd
)) {
1751 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
1752 ("*** SetFocus: [ top] raise=%d\n", aRaise
));
1754 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
1755 ("*** SetFocus: [child] raise=%d\n", aRaise
));
1758 // Uniconify, if necessary
1759 HWND toplevelWnd
= WinUtils::GetTopLevelHWND(mWnd
);
1760 if (aRaise
&& ::IsIconic(toplevelWnd
)) {
1761 ::ShowWindow(toplevelWnd
, SW_RESTORE
);
1769 /**************************************************************
1773 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1774 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1776 * Bound calculations.
1778 **************************************************************/
1780 // Return the window's full dimensions in screen coordinates.
1781 // If the window has a parent, converts the origin to an offset
1782 // of the parent's screen origin.
1783 NS_METHOD
nsWindow::GetBounds(nsIntRect
&aRect
)
1787 VERIFY(::GetWindowRect(mWnd
, &r
));
1790 aRect
.width
= r
.right
- r
.left
;
1791 aRect
.height
= r
.bottom
- r
.top
;
1793 // popup window bounds' are in screen coordinates, not relative to parent
1795 if (mWindowType
== eWindowType_popup
) {
1801 // chrome on parent:
1802 // ___ 5,5 (chrome start)
1803 // | ____ 10,10 (client start)
1804 // | | ____ 20,20 (child start)
1806 // 20,20 - 5,5 = 15,15 (??)
1807 // minus GetClientOffset:
1808 // 15,15 - 5,5 = 10,10
1810 // no chrome on parent:
1811 // ______ 10,10 (win start)
1812 // | ____ 20,20 (child start)
1814 // 20,20 - 10,10 = 10,10
1816 // walking the chain:
1817 // ___ 5,5 (chrome start)
1818 // | ___ 10,10 (client start)
1819 // | | ___ 20,20 (child start)
1820 // | | | __ 30,30 (child start)
1822 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1823 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1824 // minus GetClientOffset:
1825 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1827 // convert coordinates if parent exists
1828 HWND parent
= ::GetParent(mWnd
);
1831 VERIFY(::GetWindowRect(parent
, &pr
));
1834 // adjust for chrome
1835 nsWindow
* pWidget
= static_cast<nsWindow
*>(GetParent());
1836 if (pWidget
&& pWidget
->IsTopLevelWidget()) {
1837 nsIntPoint clientOffset
= pWidget
->GetClientOffset();
1838 r
.left
-= clientOffset
.x
;
1839 r
.top
-= clientOffset
.y
;
1850 // Get this component dimension
1851 NS_METHOD
nsWindow::GetClientBounds(nsIntRect
&aRect
)
1855 VERIFY(::GetClientRect(mWnd
, &r
));
1859 aRect
.MoveTo(bounds
.TopLeft() + GetClientOffset());
1860 aRect
.width
= r
.right
- r
.left
;
1861 aRect
.height
= r
.bottom
- r
.top
;
1864 aRect
.SetRect(0,0,0,0);
1869 // Like GetBounds, but don't offset by the parent
1870 NS_METHOD
nsWindow::GetScreenBounds(nsIntRect
&aRect
)
1874 VERIFY(::GetWindowRect(mWnd
, &r
));
1876 aRect
.width
= r
.right
- r
.left
;
1877 aRect
.height
= r
.bottom
- r
.top
;
1886 // return the x,y offset of the client area from the origin
1887 // of the window. If the window is borderless returns (0,0).
1888 nsIntPoint
nsWindow::GetClientOffset()
1891 return nsIntPoint(0, 0);
1895 GetWindowRect(mWnd
, &r1
);
1896 nsIntPoint pt
= WidgetToScreenOffset();
1897 return nsIntPoint(pt
.x
- r1
.left
, pt
.y
- r1
.top
);
1901 nsWindow::SetDrawsInTitlebar(bool aState
)
1903 nsWindow
* window
= GetTopLevelWindow(true);
1904 if (window
&& window
!= this) {
1905 return window
->SetDrawsInTitlebar(aState
);
1909 // top, right, bottom, left for nsIntMargin
1910 nsIntMargin
margins(0, -1, -1, -1);
1911 SetNonClientMargins(margins
);
1914 nsIntMargin
margins(-1, -1, -1, -1);
1915 SetNonClientMargins(margins
);
1920 nsWindow::GetNonClientMargins(nsIntMargin
&margins
)
1922 nsWindow
* window
= GetTopLevelWindow(true);
1923 if (window
&& window
!= this) {
1924 return window
->GetNonClientMargins(margins
);
1927 if (mCustomNonClient
) {
1928 margins
= mNonClientMargins
;
1932 margins
.top
= GetSystemMetrics(SM_CYCAPTION
);
1933 margins
.bottom
= GetSystemMetrics(SM_CYFRAME
);
1934 margins
.top
+= margins
.bottom
;
1935 margins
.left
= margins
.right
= GetSystemMetrics(SM_CXFRAME
);
1941 nsWindow::ResetLayout()
1943 // This will trigger a frame changed event, triggering
1944 // nc calc size and a sizemode gecko event.
1945 SetWindowPos(mWnd
, 0, 0, 0, 0, 0,
1946 SWP_FRAMECHANGED
|SWP_NOACTIVATE
|SWP_NOMOVE
|
1947 SWP_NOOWNERZORDER
|SWP_NOSIZE
|SWP_NOZORDER
);
1949 // If hidden, just send the frame changed event for now.
1953 // Send a gecko size event to trigger reflow.
1954 RECT clientRc
= {0};
1955 GetClientRect(mWnd
, &clientRc
);
1956 nsIntRect
evRect(WinUtils::ToIntRect(clientRc
));
1959 // Invalidate and update
1963 // Internally track the caption status via a window property. Required
1964 // due to our internal handling of WM_NCACTIVATE when custom client
1966 static const PRUnichar kManageWindowInfoProperty
[] = L
"ManageWindowInfoProperty";
1967 typedef BOOL (WINAPI
*GetWindowInfoPtr
)(HWND hwnd
, PWINDOWINFO pwi
);
1968 static GetWindowInfoPtr sGetWindowInfoPtrStub
= NULL
;
1971 GetWindowInfoHook(HWND hWnd
, PWINDOWINFO pwi
)
1973 if (!sGetWindowInfoPtrStub
) {
1974 NS_ASSERTION(FALSE
, "Something is horribly wrong in GetWindowInfoHook!");
1978 reinterpret_cast<LONG_PTR
>(GetPropW(hWnd
, kManageWindowInfoProperty
));
1979 // No property set, return the default data.
1981 return sGetWindowInfoPtrStub(hWnd
, pwi
);
1982 // Call GetWindowInfo and update dwWindowStatus with our
1983 // internally tracked value.
1984 BOOL result
= sGetWindowInfoPtrStub(hWnd
, pwi
);
1986 pwi
->dwWindowStatus
= (windowStatus
== 1 ? 0 : WS_ACTIVECAPTION
);
1991 nsWindow::UpdateGetWindowInfoCaptionStatus(bool aActiveCaption
)
1996 if (!sGetWindowInfoPtrStub
) {
1997 sUser32Intercept
.Init("user32.dll");
1998 if (!sUser32Intercept
.AddHook("GetWindowInfo", reinterpret_cast<intptr_t>(GetWindowInfoHook
),
1999 (void**) &sGetWindowInfoPtrStub
))
2002 // Update our internally tracked caption status
2003 SetPropW(mWnd
, kManageWindowInfoProperty
,
2004 reinterpret_cast<HANDLE
>(static_cast<int>(aActiveCaption
) + 1));
2008 * Called when the window layout changes: full screen mode transitions,
2009 * theme changes, and composition changes. Calculates the new non-client
2010 * margins and fires off a frame changed event, which triggers an nc calc
2011 * size windows event, kicking the changes in.
2013 * The offsets calculated here are based on the value of `mNonClientMargins`
2014 * which is specified in the "chromemargins" attribute of the window. For
2015 * each margin, the value specified has the following meaning:
2016 * -1 - leave the default frame in place
2017 * 0 - remove the frame
2018 * >0 - frame size equals min(0, (default frame size - margin value))
2020 * This function calculates and populates `mNonClientOffset`.
2021 * In our processing of `WM_NCCALCSIZE`, the frame size will be calculated
2022 * as (default frame size - offset). For example, if the left frame should
2023 * be 1 pixel narrower than the default frame size, `mNonClientOffset.left`
2026 * For maximized, fullscreen, and minimized windows, the values stored in
2027 * `mNonClientMargins` are ignored, and special processing takes place.
2029 * For non-glass windows, we only allow frames to be their default size
2030 * or removed entirely.
2033 nsWindow::UpdateNonClientMargins(int32_t aSizeMode
, bool aReflowWindow
)
2035 if (!mCustomNonClient
)
2038 if (aSizeMode
== -1) {
2039 aSizeMode
= mSizeMode
;
2042 bool hasCaption
= (mBorderStyle
2044 | eBorderStyle_title
2046 | eBorderStyle_default
));
2048 // mCaptionHeight is the default size of the NC area at
2049 // the top of the window. If the window has a caption,
2050 // the size is calculated as the sum of:
2051 // SM_CYFRAME - The thickness of the sizing border
2052 // around a resizable window
2053 // SM_CXPADDEDBORDER - The amount of border padding
2054 // for captioned windows
2055 // SM_CYCAPTION - The height of the caption area
2057 // If the window does not have a caption, mCaptionHeight will be equal to
2058 // `GetSystemMetrics(SM_CYFRAME)`
2059 mCaptionHeight
= GetSystemMetrics(SM_CYFRAME
)
2060 + (hasCaption
? GetSystemMetrics(SM_CYCAPTION
)
2061 + GetSystemMetrics(SM_CXPADDEDBORDER
)
2064 // mHorResizeMargin is the size of the default NC areas on the
2065 // left and right sides of our window. It is calculated as
2067 // SM_CXFRAME - The thickness of the sizing border
2068 // SM_CXPADDEDBORDER - The amount of border padding
2069 // for captioned windows
2071 // If the window does not have a caption, mHorResizeMargin will be equal to
2072 // `GetSystemMetrics(SM_CXFRAME)`
2073 mHorResizeMargin
= GetSystemMetrics(SM_CXFRAME
)
2074 + (hasCaption
? GetSystemMetrics(SM_CXPADDEDBORDER
) : 0);
2076 // mVertResizeMargin is the size of the default NC area at the
2077 // bottom of the window. It is calculated as the sum of:
2078 // SM_CYFRAME - The thickness of the sizing border
2079 // SM_CXPADDEDBORDER - The amount of border padding
2080 // for captioned windows.
2082 // If the window does not have a caption, mVertResizeMargin will be equal to
2083 // `GetSystemMetrics(SM_CYFRAME)`
2084 mVertResizeMargin
= GetSystemMetrics(SM_CYFRAME
)
2085 + (hasCaption
? GetSystemMetrics(SM_CXPADDEDBORDER
) : 0);
2087 if (aSizeMode
== nsSizeMode_Minimized
) {
2088 // Use default frame size for minimized windows
2089 mNonClientOffset
.top
= 0;
2090 mNonClientOffset
.left
= 0;
2091 mNonClientOffset
.right
= 0;
2092 mNonClientOffset
.bottom
= 0;
2093 } else if (aSizeMode
== nsSizeMode_Fullscreen
) {
2094 // Remove the default frame from the top of our fullscreen window. This
2095 // makes the whole caption part of our client area, allowing us to draw
2096 // in the whole caption area. Additionally remove the default frame from
2097 // the left, right, and bottom.
2098 mNonClientOffset
.top
= mCaptionHeight
;
2099 mNonClientOffset
.bottom
= mVertResizeMargin
;
2100 mNonClientOffset
.left
= mHorResizeMargin
;
2101 mNonClientOffset
.right
= mHorResizeMargin
;
2102 } else if (aSizeMode
== nsSizeMode_Maximized
) {
2103 // Remove the default frame from the top of our maximized window. This
2104 // makes the whole caption part of our client area, allowing us to draw
2105 // in the whole caption area. Use default frame size on left, right, and
2106 // bottom. The reason this works is that, for maximized windows,
2107 // Windows positions them so that their frames fall off the screen.
2108 // This gives the illusion of windows having no frames when they are
2109 // maximized. If we try to mess with the frame sizes by setting these
2110 // offsets to positive values, our client area will fall off the screen.
2111 mNonClientOffset
.top
= mCaptionHeight
;
2112 mNonClientOffset
.bottom
= 0;
2113 mNonClientOffset
.left
= 0;
2114 mNonClientOffset
.right
= 0;
2116 APPBARDATA appBarData
;
2117 appBarData
.cbSize
= sizeof(appBarData
);
2118 UINT taskbarState
= SHAppBarMessage(ABM_GETSTATE
, &appBarData
);
2119 if (ABS_AUTOHIDE
& taskbarState
) {
2121 appBarData
.hWnd
= FindWindow(L
"Shell_TrayWnd", NULL
);
2122 if (appBarData
.hWnd
) {
2123 HMONITOR taskbarMonitor
= ::MonitorFromWindow(appBarData
.hWnd
,
2124 MONITOR_DEFAULTTOPRIMARY
);
2125 HMONITOR windowMonitor
= ::MonitorFromWindow(mWnd
,
2126 MONITOR_DEFAULTTONEAREST
);
2127 if (taskbarMonitor
== windowMonitor
) {
2128 SHAppBarMessage(ABM_GETTASKBARPOS
, &appBarData
);
2129 edge
= appBarData
.uEdge
;
2133 if (ABE_LEFT
== edge
) {
2134 mNonClientOffset
.left
-= 1;
2135 } else if (ABE_RIGHT
== edge
) {
2136 mNonClientOffset
.right
-= 1;
2137 } else if (ABE_BOTTOM
== edge
|| ABE_TOP
== edge
) {
2138 mNonClientOffset
.bottom
-= 1;
2142 bool glass
= nsUXThemeData::CheckForCompositor();
2144 // We're dealing with a "normal" window (not maximized, minimized, or
2145 // fullscreen), so process `mNonClientMargins` and set `mNonClientOffset`
2148 // Setting `mNonClientOffset` to 0 has the effect of leaving the default
2149 // frame intact. Setting it to a value greater than 0 reduces the frame
2150 // size by that amount.
2152 if (mNonClientMargins
.top
> 0 && glass
) {
2153 mNonClientOffset
.top
= std::min(mCaptionHeight
, mNonClientMargins
.top
);
2154 } else if (mNonClientMargins
.top
== 0) {
2155 mNonClientOffset
.top
= mCaptionHeight
;
2157 mNonClientOffset
.top
= 0;
2160 if (mNonClientMargins
.bottom
> 0 && glass
) {
2161 mNonClientOffset
.bottom
= std::min(mVertResizeMargin
, mNonClientMargins
.bottom
);
2162 } else if (mNonClientMargins
.bottom
== 0) {
2163 mNonClientOffset
.bottom
= mVertResizeMargin
;
2165 mNonClientOffset
.bottom
= 0;
2168 if (mNonClientMargins
.left
> 0 && glass
) {
2169 mNonClientOffset
.left
= std::min(mHorResizeMargin
, mNonClientMargins
.left
);
2170 } else if (mNonClientMargins
.left
== 0) {
2171 mNonClientOffset
.left
= mHorResizeMargin
;
2173 mNonClientOffset
.left
= 0;
2176 if (mNonClientMargins
.right
> 0 && glass
) {
2177 mNonClientOffset
.right
= std::min(mHorResizeMargin
, mNonClientMargins
.right
);
2178 } else if (mNonClientMargins
.right
== 0) {
2179 mNonClientOffset
.right
= mHorResizeMargin
;
2181 mNonClientOffset
.right
= 0;
2185 if (aReflowWindow
) {
2186 // Force a reflow of content based on the new client
2195 nsWindow::SetNonClientMargins(nsIntMargin
&margins
)
2197 if (!mIsTopWidgetWindow
||
2198 mBorderStyle
& eBorderStyle_none
||
2200 return NS_ERROR_INVALID_ARG
;
2202 // Request for a reset
2203 if (margins
.top
== -1 && margins
.left
== -1 &&
2204 margins
.right
== -1 && margins
.bottom
== -1) {
2205 mCustomNonClient
= false;
2206 mNonClientMargins
= margins
;
2207 RemovePropW(mWnd
, kManageWindowInfoProperty
);
2208 // Force a reflow of content based on the new client
2214 if (margins
.top
< -1 || margins
.bottom
< -1 ||
2215 margins
.left
< -1 || margins
.right
< -1)
2216 return NS_ERROR_INVALID_ARG
;
2218 mNonClientMargins
= margins
;
2219 mCustomNonClient
= true;
2220 if (!UpdateNonClientMargins()) {
2221 NS_WARNING("UpdateNonClientMargins failed!");
2229 nsWindow::InvalidateNonClientRegion()
2231 // +-+-----------------------+-+
2232 // | | app non-client chrome | |
2233 // | +-----------------------+ |
2234 // | | app client chrome | | }
2235 // | +-----------------------+ | }
2236 // | | app content | | } area we don't want to invalidate
2237 // | +-----------------------+ | }
2238 // | | app client chrome | | }
2239 // | +-----------------------+ |
2240 // +---------------------------+ <
2241 // ^ ^ windows non-client chrome
2242 // client area = app *
2244 GetWindowRect(mWnd
, &rect
);
2245 MapWindowPoints(NULL
, mWnd
, (LPPOINT
)&rect
, 2);
2246 HRGN winRgn
= CreateRectRgnIndirect(&rect
);
2248 // Subtract app client chrome and app content leaving
2249 // windows non-client chrome and app non-client chrome
2251 GetWindowRect(mWnd
, &rect
);
2252 rect
.top
+= mCaptionHeight
;
2253 rect
.right
-= mHorResizeMargin
;
2254 rect
.bottom
-= mHorResizeMargin
;
2255 rect
.left
+= mVertResizeMargin
;
2256 MapWindowPoints(NULL
, mWnd
, (LPPOINT
)&rect
, 2);
2257 HRGN clientRgn
= CreateRectRgnIndirect(&rect
);
2258 CombineRgn(winRgn
, winRgn
, clientRgn
, RGN_DIFF
);
2259 DeleteObject(clientRgn
);
2261 // triggers ncpaint and paint events for the two areas
2262 RedrawWindow(mWnd
, NULL
, winRgn
, RDW_FRAME
|RDW_INVALIDATE
);
2263 DeleteObject(winRgn
);
2267 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion
)
2271 if (aRegion
== (HRGN
)1) { // undocumented value indicating a full refresh
2272 GetWindowRect(mWnd
, &rect
);
2273 rgn
= CreateRectRgnIndirect(&rect
);
2277 GetClientRect(mWnd
, &rect
);
2278 MapWindowPoints(mWnd
, NULL
, (LPPOINT
)&rect
, 2);
2279 HRGN nonClientRgn
= CreateRectRgnIndirect(&rect
);
2280 CombineRgn(rgn
, rgn
, nonClientRgn
, RGN_DIFF
);
2281 DeleteObject(nonClientRgn
);
2285 /**************************************************************
2287 * SECTION: nsIWidget::SetBackgroundColor
2289 * Sets the window background paint color.
2291 **************************************************************/
2293 NS_METHOD
nsWindow::SetBackgroundColor(const nscolor
&aColor
)
2295 nsBaseWidget::SetBackgroundColor(aColor
);
2298 ::DeleteObject(mBrush
);
2300 mBrush
= ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground
));
2302 ::SetClassLongPtrW(mWnd
, GCLP_HBRBACKGROUND
, (LONG_PTR
)mBrush
);
2307 /**************************************************************
2309 * SECTION: nsIWidget::SetCursor
2311 * SetCursor and related utilities for manging cursor state.
2313 **************************************************************/
2315 // Set this component cursor
2316 NS_METHOD
nsWindow::SetCursor(nsCursor aCursor
)
2318 // Only change cursor if it's changing
2320 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2321 //XXX If we want this optimization we need a better way to do it.
2322 //if (aCursor != mCursor) {
2323 HCURSOR newCursor
= NULL
;
2326 case eCursor_select
:
2327 newCursor
= ::LoadCursor(NULL
, IDC_IBEAM
);
2331 newCursor
= ::LoadCursor(NULL
, IDC_WAIT
);
2334 case eCursor_hyperlink
:
2336 newCursor
= ::LoadCursor(NULL
, IDC_HAND
);
2340 case eCursor_standard
:
2341 newCursor
= ::LoadCursor(NULL
, IDC_ARROW
);
2344 case eCursor_n_resize
:
2345 case eCursor_s_resize
:
2346 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
2349 case eCursor_w_resize
:
2350 case eCursor_e_resize
:
2351 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
2354 case eCursor_nw_resize
:
2355 case eCursor_se_resize
:
2356 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
2359 case eCursor_ne_resize
:
2360 case eCursor_sw_resize
:
2361 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
2364 case eCursor_crosshair
:
2365 newCursor
= ::LoadCursor(NULL
, IDC_CROSS
);
2369 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
2373 newCursor
= ::LoadCursor(NULL
, IDC_HELP
);
2376 case eCursor_copy
: // CSS3
2377 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COPY
));
2381 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ALIAS
));
2385 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_CELL
));
2389 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRAB
));
2392 case eCursor_grabbing
:
2393 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRABBING
));
2396 case eCursor_spinning
:
2397 newCursor
= ::LoadCursor(NULL
, IDC_APPSTARTING
);
2400 case eCursor_context_menu
:
2401 // XXX this CSS3 cursor needs to be implemented
2404 case eCursor_zoom_in
:
2405 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMIN
));
2408 case eCursor_zoom_out
:
2409 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMOUT
));
2412 case eCursor_not_allowed
:
2413 case eCursor_no_drop
:
2414 newCursor
= ::LoadCursor(NULL
, IDC_NO
);
2417 case eCursor_col_resize
:
2418 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COLRESIZE
));
2421 case eCursor_row_resize
:
2422 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ROWRESIZE
));
2425 case eCursor_vertical_text
:
2426 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_VERTICALTEXT
));
2429 case eCursor_all_scroll
:
2430 // XXX not 100% appropriate perhaps
2431 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
2434 case eCursor_nesw_resize
:
2435 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
2438 case eCursor_nwse_resize
:
2439 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
2442 case eCursor_ns_resize
:
2443 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
2446 case eCursor_ew_resize
:
2447 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
2451 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_NONE
));
2455 NS_ERROR("Invalid cursor type");
2459 if (NULL
!= newCursor
) {
2461 HCURSOR oldCursor
= ::SetCursor(newCursor
);
2463 if (sHCursor
== oldCursor
) {
2464 NS_IF_RELEASE(sCursorImgContainer
);
2465 if (sHCursor
!= NULL
)
2466 ::DestroyIcon(sHCursor
);
2474 // Setting the actual cursor
2475 NS_IMETHODIMP
nsWindow::SetCursor(imgIContainer
* aCursor
,
2476 uint32_t aHotspotX
, uint32_t aHotspotY
)
2478 if (sCursorImgContainer
== aCursor
&& sHCursor
) {
2479 ::SetCursor(sHCursor
);
2487 rv
= aCursor
->GetWidth(&width
);
2488 NS_ENSURE_SUCCESS(rv
, rv
);
2489 rv
= aCursor
->GetHeight(&height
);
2490 NS_ENSURE_SUCCESS(rv
, rv
);
2492 // Reject cursors greater than 128 pixels in either direction, to prevent
2494 // XXX ideally we should rescale. Also, we could modify the API to
2495 // allow trusted content to set larger cursors.
2496 if (width
> 128 || height
> 128)
2497 return NS_ERROR_NOT_AVAILABLE
;
2501 gfxIntSize
size(0, 0);
2502 rv
= nsWindowGfx::CreateIcon(aCursor
, true, aHotspotX
, aHotspotY
, size
, &cursor
);
2503 NS_ENSURE_SUCCESS(rv
, rv
);
2505 mCursor
= nsCursor(-1);
2506 ::SetCursor(cursor
);
2508 NS_IF_RELEASE(sCursorImgContainer
);
2509 sCursorImgContainer
= aCursor
;
2510 NS_ADDREF(sCursorImgContainer
);
2512 if (sHCursor
!= NULL
)
2513 ::DestroyIcon(sHCursor
);
2519 /**************************************************************
2521 * SECTION: nsIWidget::Get/SetTransparencyMode
2523 * Manage the transparency mode of the top-level window
2524 * containing this widget.
2526 **************************************************************/
2529 nsTransparencyMode
nsWindow::GetTransparencyMode()
2531 return GetTopLevelWindow(true)->GetWindowTranslucencyInner();
2534 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode
)
2536 GetTopLevelWindow(true)->SetWindowTranslucencyInner(aMode
);
2539 static const nsIntRegion
2540 RegionFromArray(const nsTArray
<nsIntRect
>& aRects
)
2543 for (uint32_t i
= 0; i
< aRects
.Length(); ++i
) {
2544 region
.Or(region
, aRects
[i
]);
2549 void nsWindow::UpdateOpaqueRegion(const nsIntRegion
&aOpaqueRegion
)
2551 if (!HasGlass() || GetParent())
2554 // If there is no opaque region or hidechrome=true, set margins
2555 // to support a full sheet of glass. Comments in MSDN indicate
2556 // all values must be set to -1 to get a full sheet of glass.
2557 MARGINS margins
= { -1, -1, -1, -1 };
2558 if (!aOpaqueRegion
.IsEmpty()) {
2559 nsIntRect pluginBounds
;
2560 for (nsIWidget
* child
= GetFirstChild(); child
; child
= child
->GetNextSibling()) {
2562 child
->GetWindowType(type
);
2563 if (type
== eWindowType_plugin
) {
2564 // Collect the bounds of all plugins for GetLargestRectangle.
2565 nsIntRect childBounds
;
2566 child
->GetBounds(childBounds
);
2567 pluginBounds
.UnionRect(pluginBounds
, childBounds
);
2571 nsIntRect clientBounds
;
2572 GetClientBounds(clientBounds
);
2574 // Find the largest rectangle and use that to calculate the inset. Our top
2575 // priority is to include the bounds of all plugins.
2576 nsIntRect largest
= aOpaqueRegion
.GetLargestRectangle(pluginBounds
);
2577 margins
.cxLeftWidth
= largest
.x
;
2578 margins
.cxRightWidth
= clientBounds
.width
- largest
.XMost();
2579 margins
.cyBottomHeight
= clientBounds
.height
- largest
.YMost();
2580 if (mCustomNonClient
) {
2581 // The minimum glass height must be the caption buttons height,
2582 // otherwise the buttons are drawn incorrectly.
2583 largest
.y
= std::max
<uint32_t>(largest
.y
,
2584 nsUXThemeData::sCommandButtons
[CMDBUTTONIDX_BUTTONBOX
].cy
);
2586 margins
.cyTopHeight
= largest
.y
;
2589 // Only update glass area if there are changes
2590 if (memcmp(&mGlassMargins
, &margins
, sizeof mGlassMargins
)) {
2591 mGlassMargins
= margins
;
2596 void nsWindow::UpdateGlass()
2598 MARGINS margins
= mGlassMargins
;
2600 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2601 // rendered based on the window style.
2602 // DWMNCRP_ENABLED - The non-client area rendering is
2603 // enabled; the window style is ignored.
2604 DWMNCRENDERINGPOLICY policy
= DWMNCRP_USEWINDOWSTYLE
;
2605 switch (mTransparencyMode
) {
2606 case eTransparencyBorderlessGlass
:
2607 // Only adjust if there is some opaque rectangle
2608 if (margins
.cxLeftWidth
>= 0) {
2609 margins
.cxLeftWidth
+= kGlassMarginAdjustment
;
2610 margins
.cyTopHeight
+= kGlassMarginAdjustment
;
2611 margins
.cxRightWidth
+= kGlassMarginAdjustment
;
2612 margins
.cyBottomHeight
+= kGlassMarginAdjustment
;
2615 case eTransparencyGlass
:
2616 policy
= DWMNCRP_ENABLED
;
2620 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
2621 ("glass margins: left:%d top:%d right:%d bottom:%d\n",
2622 margins
.cxLeftWidth
, margins
.cyTopHeight
,
2623 margins
.cxRightWidth
, margins
.cyBottomHeight
));
2625 // Extends the window frame behind the client area
2626 if(nsUXThemeData::CheckForCompositor()) {
2627 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(mWnd
, &margins
);
2628 nsUXThemeData::dwmSetWindowAttributePtr(mWnd
, DWMWA_NCRENDERING_POLICY
, &policy
, sizeof policy
);
2633 /**************************************************************
2635 * SECTION: nsIWidget::HideWindowChrome
2637 * Show or hide window chrome.
2639 **************************************************************/
2641 NS_IMETHODIMP
nsWindow::HideWindowChrome(bool aShouldHide
)
2643 HWND hwnd
= WinUtils::GetTopLevelHWND(mWnd
, true);
2644 if (!WinUtils::GetNSWindowPtr(hwnd
))
2646 NS_WARNING("Trying to hide window decorations in an embedded context");
2647 return NS_ERROR_FAILURE
;
2650 if (mHideChrome
== aShouldHide
)
2653 DWORD_PTR style
, exStyle
;
2654 mHideChrome
= aShouldHide
;
2656 DWORD_PTR tempStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2657 DWORD_PTR tempExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2659 style
= tempStyle
& ~(WS_CAPTION
| WS_THICKFRAME
);
2660 exStyle
= tempExStyle
& ~(WS_EX_DLGMODALFRAME
| WS_EX_WINDOWEDGE
|
2661 WS_EX_CLIENTEDGE
| WS_EX_STATICEDGE
);
2663 mOldStyle
= tempStyle
;
2664 mOldExStyle
= tempExStyle
;
2667 if (!mOldStyle
|| !mOldExStyle
) {
2668 mOldStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2669 mOldExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2673 exStyle
= mOldExStyle
;
2676 VERIFY_WINDOW_STYLE(style
);
2677 ::SetWindowLongPtrW(hwnd
, GWL_STYLE
, style
);
2678 ::SetWindowLongPtrW(hwnd
, GWL_EXSTYLE
, exStyle
);
2683 /**************************************************************
2685 * SECTION: nsWindow::Invalidate
2687 * Invalidate an area of the client for painting.
2689 **************************************************************/
2691 // Invalidate this component visible area
2692 NS_METHOD
nsWindow::Invalidate(bool aEraseBackground
,
2694 bool aIncludeChildren
)
2700 #ifdef WIDGET_DEBUG_OUTPUT
2701 debug_DumpInvalidate(stdout
,
2704 nsAutoCString("noname"),
2706 #endif // WIDGET_DEBUG_OUTPUT
2708 DWORD flags
= RDW_INVALIDATE
;
2709 if (aEraseBackground
) {
2712 if (aUpdateNCArea
) {
2715 if (aIncludeChildren
) {
2716 flags
|= RDW_ALLCHILDREN
;
2719 VERIFY(::RedrawWindow(mWnd
, NULL
, NULL
, flags
));
2723 // Invalidate this component visible area
2724 NS_METHOD
nsWindow::Invalidate(const nsIntRect
& aRect
)
2728 #ifdef WIDGET_DEBUG_OUTPUT
2729 debug_DumpInvalidate(stdout
,
2732 nsAutoCString("noname"),
2734 #endif // WIDGET_DEBUG_OUTPUT
2738 rect
.left
= aRect
.x
;
2740 rect
.right
= aRect
.x
+ aRect
.width
;
2741 rect
.bottom
= aRect
.y
+ aRect
.height
;
2743 VERIFY(::InvalidateRect(mWnd
, &rect
, FALSE
));
2749 nsWindow::MakeFullScreen(bool aFullScreen
)
2751 // taskbarInfo will be NULL pre Windows 7 until Bug 680227 is resolved.
2752 nsCOMPtr
<nsIWinTaskbar
> taskbarInfo
=
2753 do_GetService(NS_TASKBAR_CONTRACTID
);
2755 mFullscreenMode
= aFullScreen
;
2757 if (mSizeMode
== nsSizeMode_Fullscreen
)
2759 mOldSizeMode
= mSizeMode
;
2760 SetSizeMode(nsSizeMode_Fullscreen
);
2762 // Notify the taskbar that we will be entering full screen mode.
2764 taskbarInfo
->PrepareFullScreenHWND(mWnd
, TRUE
);
2767 SetSizeMode(mOldSizeMode
);
2770 UpdateNonClientMargins();
2772 bool visible
= mIsVisible
;
2773 if (mOldSizeMode
== nsSizeMode_Normal
)
2776 // Will call hide chrome, reposition window. Note this will
2777 // also cache dimensions for restoration, so it should only
2778 // be called once per fullscreen request.
2779 nsresult rv
= nsBaseWidget::MakeFullScreen(aFullScreen
);
2786 // Notify the taskbar that we have exited full screen mode.
2787 if (!aFullScreen
&& taskbarInfo
) {
2788 taskbarInfo
->PrepareFullScreenHWND(mWnd
, FALSE
);
2791 if (mWidgetListener
)
2792 mWidgetListener
->SizeModeChanged(mSizeMode
);
2797 /**************************************************************
2799 * SECTION: Native data storage
2801 * nsIWidget::GetNativeData
2802 * nsIWidget::FreeNativeData
2804 * Set or clear native data based on a constant.
2806 **************************************************************/
2808 // Return some native data according to aDataType
2809 void* nsWindow::GetNativeData(uint32_t aDataType
)
2811 nsAutoString className
;
2812 switch (aDataType
) {
2813 case NS_NATIVE_TMP_WINDOW
:
2814 GetWindowClass(className
);
2815 return (void*)::CreateWindowExW(mIsRTL
? WS_EX_LAYOUTRTL
: 0,
2825 nsToolkit::mDllInstance
,
2827 case NS_NATIVE_PLUGIN_PORT
:
2828 case NS_NATIVE_WIDGET
:
2829 case NS_NATIVE_WINDOW
:
2830 case NS_NATIVE_SHAREABLE_WINDOW
:
2832 case NS_NATIVE_GRAPHIC
:
2833 // XXX: This is sleezy!! Remember to Release the DC after using it!
2835 return (void*)(eTransparencyTransparent
== mTransparencyMode
) ?
2836 mMemoryDC
: ::GetDC(mWnd
);
2838 return (void*)::GetDC(mWnd
);
2841 case NS_NATIVE_TSF_THREAD_MGR
:
2842 case NS_NATIVE_TSF_CATEGORY_MGR
:
2843 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR
:
2844 return IMEHandler::GetNativeData(aDataType
);
2853 // Free some native data according to aDataType
2854 void nsWindow::FreeNativeData(void * data
, uint32_t aDataType
)
2858 case NS_NATIVE_GRAPHIC
:
2860 if (eTransparencyTransparent
!= mTransparencyMode
)
2861 ::ReleaseDC(mWnd
, (HDC
)data
);
2863 ::ReleaseDC(mWnd
, (HDC
)data
);
2866 case NS_NATIVE_WIDGET
:
2867 case NS_NATIVE_WINDOW
:
2868 case NS_NATIVE_PLUGIN_PORT
:
2875 /**************************************************************
2877 * SECTION: nsIWidget::SetTitle
2879 * Set the main windows title text.
2881 **************************************************************/
2883 NS_METHOD
nsWindow::SetTitle(const nsAString
& aTitle
)
2885 const nsString
& strTitle
= PromiseFlatString(aTitle
);
2886 ::SendMessageW(mWnd
, WM_SETTEXT
, (WPARAM
)0, (LPARAM
)(LPCWSTR
)strTitle
.get());
2890 /**************************************************************
2892 * SECTION: nsIWidget::SetIcon
2894 * Set the main windows icon.
2896 **************************************************************/
2898 NS_METHOD
nsWindow::SetIcon(const nsAString
& aIconSpec
)
2900 // Assume the given string is a local identifier for an icon file.
2902 nsCOMPtr
<nsIFile
> iconFile
;
2903 ResolveIconName(aIconSpec
, NS_LITERAL_STRING(".ico"),
2904 getter_AddRefs(iconFile
));
2906 return NS_OK
; // not an error if icon is not found
2908 nsAutoString iconPath
;
2909 iconFile
->GetPath(iconPath
);
2911 // XXX this should use MZLU (see bug 239279)
2915 HICON bigIcon
= (HICON
)::LoadImageW(NULL
,
2916 (LPCWSTR
)iconPath
.get(),
2918 ::GetSystemMetrics(SM_CXICON
),
2919 ::GetSystemMetrics(SM_CYICON
),
2921 HICON smallIcon
= (HICON
)::LoadImageW(NULL
,
2922 (LPCWSTR
)iconPath
.get(),
2924 ::GetSystemMetrics(SM_CXSMICON
),
2925 ::GetSystemMetrics(SM_CYSMICON
),
2929 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_BIG
, (LPARAM
)bigIcon
);
2931 ::DestroyIcon(icon
);
2934 #ifdef DEBUG_SetIcon
2936 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
2937 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
2938 ("\nIcon load error; icon=%s, rc=0x%08X\n\n",
2939 cPath
.get(), ::GetLastError()));
2943 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_SMALL
, (LPARAM
)smallIcon
);
2945 ::DestroyIcon(icon
);
2946 mIconSmall
= smallIcon
;
2948 #ifdef DEBUG_SetIcon
2950 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
2951 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
2952 ("\nSmall icon load error; icon=%s, rc=0x%08X\n\n",
2953 cPath
.get(), ::GetLastError()));
2959 /**************************************************************
2961 * SECTION: nsIWidget::WidgetToScreenOffset
2963 * Return this widget's origin in screen coordinates.
2965 **************************************************************/
2967 nsIntPoint
nsWindow::WidgetToScreenOffset()
2972 ::ClientToScreen(mWnd
, &point
);
2973 return nsIntPoint(point
.x
, point
.y
);
2976 nsIntSize
nsWindow::ClientToWindowSize(const nsIntSize
& aClientSize
)
2978 if (mWindowType
== eWindowType_popup
&& !IsPopupWithTitleBar())
2981 // just use (200, 200) as the position
2985 r
.right
= 200 + aClientSize
.width
;
2986 r
.bottom
= 200 + aClientSize
.height
;
2987 ::AdjustWindowRectEx(&r
, WindowStyle(), false, WindowExStyle());
2989 return nsIntSize(r
.right
- r
.left
, r
.bottom
- r
.top
);
2992 /**************************************************************
2994 * SECTION: nsIWidget::EnableDragDrop
2996 * Enables/Disables drag and drop of files on this widget.
2998 **************************************************************/
3000 NS_METHOD
nsWindow::EnableDragDrop(bool aEnable
)
3002 NS_ASSERTION(mWnd
, "nsWindow::EnableDragDrop() called after Destroy()");
3004 nsresult rv
= NS_ERROR_FAILURE
;
3006 if (nullptr == mNativeDragTarget
) {
3007 mNativeDragTarget
= new nsNativeDragTarget(this);
3008 if (NULL
!= mNativeDragTarget
) {
3009 mNativeDragTarget
->AddRef();
3010 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
,TRUE
,FALSE
)) {
3011 if (S_OK
== ::RegisterDragDrop(mWnd
, (LPDROPTARGET
)mNativeDragTarget
)) {
3018 if (nullptr != mWnd
&& NULL
!= mNativeDragTarget
) {
3019 ::RevokeDragDrop(mWnd
);
3020 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
, FALSE
, TRUE
)) {
3023 mNativeDragTarget
->DragCancel();
3024 NS_RELEASE(mNativeDragTarget
);
3030 /**************************************************************
3032 * SECTION: nsIWidget::CaptureMouse
3034 * Enables/Disables system mouse capture.
3036 **************************************************************/
3038 NS_METHOD
nsWindow::CaptureMouse(bool aCapture
)
3040 if (!nsToolkit::gMouseTrailer
) {
3041 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3046 nsToolkit::gMouseTrailer
->SetCaptureWindow(mWnd
);
3049 nsToolkit::gMouseTrailer
->SetCaptureWindow(NULL
);
3052 sIsInMouseCapture
= aCapture
;
3056 /**************************************************************
3058 * SECTION: nsIWidget::CaptureRollupEvents
3060 * Dealing with event rollup on destroy for popups. Enables &
3061 * Disables system capture of any and all events that would
3062 * cause a dropdown to be rolled up.
3064 **************************************************************/
3066 NS_IMETHODIMP
nsWindow::CaptureRollupEvents(nsIRollupListener
* aListener
,
3070 gRollupListener
= aListener
;
3071 if (!sMsgFilterHook
&& !sCallProcHook
&& !sCallMouseHook
) {
3072 RegisterSpecialDropdownHooks();
3074 sProcessHook
= true;
3076 gRollupListener
= nullptr;
3077 sProcessHook
= false;
3078 UnregisterSpecialDropdownHooks();
3084 /**************************************************************
3086 * SECTION: nsIWidget::GetAttention
3088 * Bring this window to the user's attention.
3090 **************************************************************/
3092 // Draw user's attention to this window until it comes to foreground.
3094 nsWindow::GetAttention(int32_t aCycleCount
)
3098 return NS_ERROR_NOT_INITIALIZED
;
3100 HWND flashWnd
= WinUtils::GetTopLevelHWND(mWnd
, false, false);
3101 HWND fgWnd
= ::GetForegroundWindow();
3102 // Don't flash if the flash count is 0 or if the foreground window is our
3103 // window handle or that of our owned-most window.
3104 if (aCycleCount
== 0 ||
3105 flashWnd
== fgWnd
||
3106 flashWnd
== WinUtils::GetTopLevelHWND(fgWnd
, false, false)) {
3110 DWORD defaultCycleCount
= 0;
3111 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT
, 0, &defaultCycleCount
, 0);
3113 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
3114 FLASHW_ALL
, aCycleCount
> 0 ? aCycleCount
: defaultCycleCount
, 0 };
3115 ::FlashWindowEx(&flashInfo
);
3120 void nsWindow::StopFlashing()
3122 HWND flashWnd
= mWnd
;
3123 while (HWND ownerWnd
= ::GetWindow(flashWnd
, GW_OWNER
)) {
3124 flashWnd
= ownerWnd
;
3127 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
3128 FLASHW_STOP
, 0, 0 };
3129 ::FlashWindowEx(&flashInfo
);
3132 /**************************************************************
3134 * SECTION: nsIWidget::HasPendingInputEvent
3136 * Ask whether there user input events pending. All input events are
3137 * included, including those not targeted at this nsIwidget instance.
3139 **************************************************************/
3142 nsWindow::HasPendingInputEvent()
3144 // If there is pending input or the user is currently
3145 // moving the window then return true.
3146 // Note: When the user is moving the window WIN32 spins
3147 // a separate event loop and input events are not
3148 // reported to the application.
3149 if (HIWORD(GetQueueStatus(QS_INPUT
)))
3151 GUITHREADINFO guiInfo
;
3152 guiInfo
.cbSize
= sizeof(GUITHREADINFO
);
3153 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo
))
3155 return GUI_INMOVESIZE
== (guiInfo
.flags
& GUI_INMOVESIZE
);
3158 /**************************************************************
3160 * SECTION: nsIWidget::GetLayerManager
3162 * Get the layer manager associated with this widget.
3164 **************************************************************/
3166 struct LayerManagerPrefs
{
3168 : mAccelerateByDefault(true)
3169 , mDisableAcceleration(false)
3170 , mPreferOpenGL(false)
3171 , mPreferD3D9(false)
3173 bool mAccelerateByDefault
;
3174 bool mDisableAcceleration
;
3175 bool mForceAcceleration
;
3181 GetLayerManagerPrefs(LayerManagerPrefs
* aManagerPrefs
)
3183 Preferences::GetBool("layers.acceleration.disabled",
3184 &aManagerPrefs
->mDisableAcceleration
);
3185 Preferences::GetBool("layers.acceleration.force-enabled",
3186 &aManagerPrefs
->mForceAcceleration
);
3187 Preferences::GetBool("layers.prefer-opengl",
3188 &aManagerPrefs
->mPreferOpenGL
);
3189 Preferences::GetBool("layers.prefer-d3d9",
3190 &aManagerPrefs
->mPreferD3D9
);
3192 const char *acceleratedEnv
= PR_GetEnv("MOZ_ACCELERATED");
3193 aManagerPrefs
->mAccelerateByDefault
=
3194 aManagerPrefs
->mAccelerateByDefault
||
3195 (acceleratedEnv
&& (*acceleratedEnv
!= '0'));
3197 bool safeMode
= false;
3198 nsCOMPtr
<nsIXULRuntime
> xr
= do_GetService("@mozilla.org/xre/runtime;1");
3200 xr
->GetInSafeMode(&safeMode
);
3201 aManagerPrefs
->mDisableAcceleration
=
3202 aManagerPrefs
->mDisableAcceleration
|| safeMode
;
3206 nsWindow::GetLayerManager(PLayerTransactionChild
* aShadowManager
,
3207 LayersBackend aBackendHint
,
3208 LayerManagerPersistence aPersistence
,
3209 bool* aAllowRetaining
)
3211 if (aAllowRetaining
) {
3212 *aAllowRetaining
= true;
3215 #ifdef MOZ_ENABLE_D3D10_LAYER
3216 if (mLayerManager
) {
3217 if (mLayerManager
->GetBackendType() == LAYERS_D3D10
)
3219 LayerManagerD3D10
*layerManagerD3D10
=
3220 static_cast<LayerManagerD3D10
*>(mLayerManager
.get());
3221 if (layerManagerD3D10
->device() !=
3222 gfxWindowsPlatform::GetPlatform()->GetD3D10Device())
3224 MOZ_ASSERT(!mLayerManager
->IsInTransaction());
3226 mLayerManager
->Destroy();
3227 mLayerManager
= nullptr;
3234 ::GetClientRect(mWnd
, &windowRect
);
3237 if (!mLayerManager
&& ShouldUseOffMainThreadCompositing()) {
3238 // e10s uses the parameter to pass in the shadow manager from the TabChild
3239 // so we don't expect to see it there since this doesn't support e10s.
3240 NS_ASSERTION(aShadowManager
== nullptr, "Async Compositor not supported with e10s");
3244 if (!mLayerManager
||
3245 (!sAllowD3D9
&& aPersistence
== LAYER_MANAGER_PERSISTENT
&&
3246 mLayerManager
->GetBackendType() == LAYERS_BASIC
&&
3247 !ShouldUseOffMainThreadCompositing())) {
3248 // If D3D9 is not currently allowed but the permanent manager is required,
3249 // -and- we're currently using basic layers, run through this check.
3250 LayerManagerPrefs prefs
;
3251 GetLayerManagerPrefs(&prefs
);
3253 /* We don't currently support using an accelerated layer manager with
3254 * transparent windows so don't even try. I'm also not sure if we even
3255 * want to support this case. See bug #593471 */
3256 if (eTransparencyTransparent
== mTransparencyMode
||
3257 prefs
.mDisableAcceleration
||
3258 windowRect
.right
- windowRect
.left
> MAX_ACCELERATED_DIMENSION
||
3259 windowRect
.bottom
- windowRect
.top
> MAX_ACCELERATED_DIMENSION
)
3260 mUseLayersAcceleration
= false;
3261 else if (prefs
.mAccelerateByDefault
)
3262 mUseLayersAcceleration
= true;
3264 if (mUseLayersAcceleration
) {
3265 if (aPersistence
== LAYER_MANAGER_PERSISTENT
&& !sAllowD3D9
) {
3266 MOZ_ASSERT(!mLayerManager
|| !mLayerManager
->IsInTransaction());
3268 // This will clear out our existing layer manager if we have one since
3269 // if we hit this with a LayerManager we're always using BasicLayers.
3270 nsToolkit::StartAllowingD3D9();
3273 #ifdef MOZ_ENABLE_D3D10_LAYER
3274 if (!prefs
.mPreferD3D9
&& !prefs
.mPreferOpenGL
) {
3275 nsRefPtr
<LayerManagerD3D10
> layerManager
=
3276 new LayerManagerD3D10(this);
3277 if (layerManager
->Initialize(prefs
.mForceAcceleration
)) {
3278 mLayerManager
= layerManager
;
3282 #ifdef MOZ_ENABLE_D3D9_LAYER
3283 if (!prefs
.mPreferOpenGL
&& !mLayerManager
&& sAllowD3D9
) {
3284 nsRefPtr
<LayerManagerD3D9
> layerManager
=
3285 new LayerManagerD3D9(this);
3286 if (layerManager
->Initialize(prefs
.mForceAcceleration
)) {
3287 mLayerManager
= layerManager
;
3291 if (!mLayerManager
&& prefs
.mPreferOpenGL
) {
3292 nsCOMPtr
<nsIGfxInfo
> gfxInfo
= do_GetService("@mozilla.org/gfx/info;1");
3293 int32_t status
= nsIGfxInfo::FEATURE_NO_INFO
;
3295 if (gfxInfo
&& !prefs
.mForceAcceleration
) {
3296 gfxInfo
->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS
, &status
);
3299 if (status
== nsIGfxInfo::FEATURE_NO_INFO
) {
3300 nsRefPtr
<LayerManagerOGL
> layerManager
=
3301 new LayerManagerOGL(this);
3302 if (layerManager
->Initialize()) {
3303 mLayerManager
= layerManager
;
3307 NS_WARNING("OpenGL accelerated layers are not supported on this system.");
3312 // Fall back to software if we couldn't use any hardware backends.
3313 if (!mLayerManager
) {
3314 // Try to use an async compositor first, if possible
3315 if (ShouldUseOffMainThreadCompositing()) {
3316 // e10s uses the parameter to pass in the shadow manager from the TabChild
3317 // so we don't expect to see it there since this doesn't support e10s.
3318 NS_ASSERTION(aShadowManager
== nullptr, "Async Compositor not supported with e10s");
3323 mLayerManager
= CreateBasicLayerManager();
3327 NS_ASSERTION(mLayerManager
, "Couldn't provide a valid layer manager.");
3329 return mLayerManager
;
3332 /**************************************************************
3334 * SECTION: nsIWidget::GetThebesSurface
3336 * Get the Thebes surface associated with this widget.
3338 **************************************************************/
3340 gfxASurface
*nsWindow::GetThebesSurface()
3342 #ifdef CAIRO_HAS_D2D_SURFACE
3343 if (mD2DWindowSurface
) {
3344 return mD2DWindowSurface
;
3348 return (new gfxWindowsSurface(mPaintDC
));
3350 #ifdef CAIRO_HAS_D2D_SURFACE
3351 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3352 gfxWindowsPlatform::RENDER_DIRECT2D
) {
3353 gfxASurface::gfxContentType content
= gfxASurface::CONTENT_COLOR
;
3354 #if defined(MOZ_XUL)
3355 if (mTransparencyMode
!= eTransparencyOpaque
) {
3356 content
= gfxASurface::CONTENT_COLOR_ALPHA
;
3359 return (new gfxD2DSurface(mWnd
, content
));
3362 uint32_t flags
= gfxWindowsSurface::FLAG_TAKE_DC
;
3363 if (mTransparencyMode
!= eTransparencyOpaque
) {
3364 flags
|= gfxWindowsSurface::FLAG_IS_TRANSPARENT
;
3366 return (new gfxWindowsSurface(mWnd
, flags
));
3367 #ifdef CAIRO_HAS_D2D_SURFACE
3372 /**************************************************************
3374 * SECTION: nsIWidget::OnDefaultButtonLoaded
3376 * Called after the dialog is loaded and it has a default button.
3378 **************************************************************/
3381 nsWindow::OnDefaultButtonLoaded(const nsIntRect
&aButtonRect
)
3383 if (aButtonRect
.IsEmpty())
3386 // Don't snap when we are not active.
3387 HWND activeWnd
= ::GetActiveWindow();
3388 if (activeWnd
!= ::GetForegroundWindow() ||
3389 WinUtils::GetTopLevelHWND(mWnd
, true) !=
3390 WinUtils::GetTopLevelHWND(activeWnd
, true)) {
3394 bool isAlwaysSnapCursor
=
3395 Preferences::GetBool("ui.cursor_snapping.always_enabled", false);
3397 if (!isAlwaysSnapCursor
) {
3398 BOOL snapDefaultButton
;
3399 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON
, 0,
3400 &snapDefaultButton
, 0) || !snapDefaultButton
)
3404 nsIntRect widgetRect
;
3405 nsresult rv
= GetScreenBounds(widgetRect
);
3406 NS_ENSURE_SUCCESS(rv
, rv
);
3407 nsIntRect
buttonRect(aButtonRect
+ widgetRect
.TopLeft());
3409 nsIntPoint
centerOfButton(buttonRect
.x
+ buttonRect
.width
/ 2,
3410 buttonRect
.y
+ buttonRect
.height
/ 2);
3411 // The center of the button can be outside of the widget.
3412 // E.g., it could be hidden by scrolling.
3413 if (!widgetRect
.Contains(centerOfButton
)) {
3417 if (!::SetCursorPos(centerOfButton
.x
, centerOfButton
.y
)) {
3418 NS_ERROR("SetCursorPos failed");
3419 return NS_ERROR_FAILURE
;
3425 nsWindow::OverrideSystemMouseScrollSpeed(double aOriginalDeltaX
,
3426 double aOriginalDeltaY
,
3427 double& aOverriddenDeltaX
,
3428 double& aOverriddenDeltaY
)
3430 // The default vertical and horizontal scrolling speed is 3, this is defined
3431 // on the document of SystemParametersInfo in MSDN.
3432 const uint32_t kSystemDefaultScrollingSpeed
= 3;
3434 double absOriginDeltaX
= Abs(aOriginalDeltaX
);
3435 double absOriginDeltaY
= Abs(aOriginalDeltaY
);
3437 // Compute the simple overridden speed.
3438 double absComputedOverriddenDeltaX
, absComputedOverriddenDeltaY
;
3440 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDeltaX
,
3442 absComputedOverriddenDeltaX
,
3443 absComputedOverriddenDeltaY
);
3444 NS_ENSURE_SUCCESS(rv
, rv
);
3446 aOverriddenDeltaX
= aOriginalDeltaX
;
3447 aOverriddenDeltaY
= aOriginalDeltaY
;
3449 if (absComputedOverriddenDeltaX
== absOriginDeltaX
&&
3450 absComputedOverriddenDeltaY
== absOriginDeltaY
) {
3451 // We don't override now.
3455 // Otherwise, we should check whether the user customized the system settings
3456 // or not. If the user did it, we should respect the will.
3458 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &systemSpeed
, 0)) {
3459 return NS_ERROR_FAILURE
;
3461 // The default vertical scrolling speed is 3, this is defined on the document
3462 // of SystemParametersInfo in MSDN.
3463 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
3467 // Only Vista and later, Windows has the system setting of horizontal
3468 // scrolling by the mouse wheel.
3469 if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION
) {
3470 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS
, 0, &systemSpeed
, 0)) {
3471 return NS_ERROR_FAILURE
;
3473 // The default horizontal scrolling speed is 3, this is defined on the
3474 // document of SystemParametersInfo in MSDN.
3475 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
3480 // Limit the overridden delta value from the system settings. The mouse
3481 // driver might accelerate the scrolling speed already. If so, we shouldn't
3482 // override the scrolling speed for preventing the unexpected high speed
3484 double absDeltaLimitX
, absDeltaLimitY
;
3486 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed
,
3487 kSystemDefaultScrollingSpeed
,
3490 NS_ENSURE_SUCCESS(rv
, rv
);
3492 // If the given delta is larger than our computed limitation value, the delta
3493 // was accelerated by the mouse driver. So, we should do nothing here.
3494 if (absDeltaLimitX
<= absOriginDeltaX
|| absDeltaLimitY
<= absOriginDeltaY
) {
3498 aOverriddenDeltaX
= std::min(absComputedOverriddenDeltaX
, absDeltaLimitX
);
3499 aOverriddenDeltaY
= std::min(absComputedOverriddenDeltaY
, absDeltaLimitY
);
3501 if (aOriginalDeltaX
< 0) {
3502 aOverriddenDeltaX
*= -1;
3504 if (aOriginalDeltaY
< 0) {
3505 aOverriddenDeltaY
*= -1;
3510 /**************************************************************
3511 **************************************************************
3513 ** BLOCK: Moz Events
3515 ** Moz GUI event management.
3517 **************************************************************
3518 **************************************************************/
3520 /**************************************************************
3522 * SECTION: Mozilla event initialization
3524 * Helpers for initializing moz events.
3526 **************************************************************/
3528 // Event intialization
3529 void nsWindow::InitEvent(nsGUIEvent
& event
, nsIntPoint
* aPoint
)
3531 if (nullptr == aPoint
) { // use the point from the event
3532 // get the message position in client coordinates
3535 DWORD pos
= ::GetMessagePos();
3538 cpos
.x
= GET_X_LPARAM(pos
);
3539 cpos
.y
= GET_Y_LPARAM(pos
);
3541 ::ScreenToClient(mWnd
, &cpos
);
3542 event
.refPoint
.x
= cpos
.x
;
3543 event
.refPoint
.y
= cpos
.y
;
3545 event
.refPoint
.x
= 0;
3546 event
.refPoint
.y
= 0;
3550 // use the point override if provided
3551 event
.refPoint
.x
= aPoint
->x
;
3552 event
.refPoint
.y
= aPoint
->y
;
3555 event
.time
= ::GetMessageTime();
3556 mLastPoint
= event
.refPoint
;
3559 /**************************************************************
3561 * SECTION: Moz event dispatch helpers
3563 * Helpers for dispatching different types of moz events.
3565 **************************************************************/
3567 // Main event dispatch. Invokes callback and ProcessEvent method on
3568 // Event Listener object. Part of nsIWidget.
3569 NS_IMETHODIMP
nsWindow::DispatchEvent(nsGUIEvent
* event
, nsEventStatus
& aStatus
)
3571 #ifdef WIDGET_DEBUG_OUTPUT
3572 debug_DumpEvent(stdout
,
3575 nsAutoCString("something"),
3577 #endif // WIDGET_DEBUG_OUTPUT
3579 aStatus
= nsEventStatus_eIgnore
;
3581 // Top level windows can have a view attached which requires events be sent
3582 // to the underlying base window and the view. Added when we combined the
3583 // base chrome window with the main content child for nc client area (title
3585 if (mAttachedWidgetListener
) {
3586 aStatus
= mAttachedWidgetListener
->HandleEvent(event
, mUseAttachedEvents
);
3588 else if (mWidgetListener
) {
3589 aStatus
= mWidgetListener
->HandleEvent(event
, mUseAttachedEvents
);
3592 // the window can be destroyed during processing of seemingly innocuous events like, say,
3593 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3594 // which causes problems with the deleted window. therefore:
3595 if (mOnDestroyCalled
)
3596 aStatus
= nsEventStatus_eConsumeNoDefault
;
3600 bool nsWindow::DispatchStandardEvent(uint32_t aMsg
)
3602 nsGUIEvent
event(true, aMsg
, this);
3605 bool result
= DispatchWindowEvent(&event
);
3609 bool nsWindow::DispatchWindowEvent(nsGUIEvent
* event
)
3611 nsEventStatus status
;
3612 DispatchEvent(event
, status
);
3613 return ConvertStatus(status
);
3616 bool nsWindow::DispatchWindowEvent(nsGUIEvent
* event
, nsEventStatus
&aStatus
) {
3617 DispatchEvent(event
, aStatus
);
3618 return ConvertStatus(aStatus
);
3621 void nsWindow::InitKeyEvent(nsKeyEvent
& aKeyEvent
,
3622 const NativeKey
& aNativeKey
,
3623 const ModifierKeyState
&aModKeyState
)
3625 nsIntPoint
point(0, 0);
3626 InitEvent(aKeyEvent
, &point
);
3627 aKeyEvent
.mKeyNameIndex
= aNativeKey
.GetKeyNameIndex();
3628 aKeyEvent
.location
= aNativeKey
.GetKeyLocation();
3629 aModKeyState
.InitInputEvent(aKeyEvent
);
3632 bool nsWindow::DispatchKeyEvent(nsKeyEvent
& aKeyEvent
,
3633 const MSG
*aMsgSentToPlugin
)
3637 NPEvent pluginEvent
;
3638 if (aMsgSentToPlugin
&& PluginHasFocus()) {
3639 pluginEvent
.event
= aMsgSentToPlugin
->message
;
3640 pluginEvent
.wParam
= aMsgSentToPlugin
->wParam
;
3641 pluginEvent
.lParam
= aMsgSentToPlugin
->lParam
;
3642 aKeyEvent
.pluginEvent
= (void *)&pluginEvent
;
3645 return DispatchWindowEvent(&aKeyEvent
);
3648 bool nsWindow::DispatchCommandEvent(uint32_t aEventCommand
)
3650 nsCOMPtr
<nsIAtom
> command
;
3651 switch (aEventCommand
) {
3652 case APPCOMMAND_BROWSER_BACKWARD
:
3653 command
= nsGkAtoms::Back
;
3655 case APPCOMMAND_BROWSER_FORWARD
:
3656 command
= nsGkAtoms::Forward
;
3658 case APPCOMMAND_BROWSER_REFRESH
:
3659 command
= nsGkAtoms::Reload
;
3661 case APPCOMMAND_BROWSER_STOP
:
3662 command
= nsGkAtoms::Stop
;
3664 case APPCOMMAND_BROWSER_SEARCH
:
3665 command
= nsGkAtoms::Search
;
3667 case APPCOMMAND_BROWSER_FAVORITES
:
3668 command
= nsGkAtoms::Bookmarks
;
3670 case APPCOMMAND_BROWSER_HOME
:
3671 command
= nsGkAtoms::Home
;
3673 case APPCOMMAND_CLOSE
:
3674 command
= nsGkAtoms::Close
;
3676 case APPCOMMAND_FIND
:
3677 command
= nsGkAtoms::Find
;
3679 case APPCOMMAND_HELP
:
3680 command
= nsGkAtoms::Help
;
3682 case APPCOMMAND_NEW
:
3683 command
= nsGkAtoms::New
;
3685 case APPCOMMAND_OPEN
:
3686 command
= nsGkAtoms::Open
;
3688 case APPCOMMAND_PRINT
:
3689 command
= nsGkAtoms::Print
;
3691 case APPCOMMAND_SAVE
:
3692 command
= nsGkAtoms::Save
;
3694 case APPCOMMAND_FORWARD_MAIL
:
3695 command
= nsGkAtoms::ForwardMail
;
3697 case APPCOMMAND_REPLY_TO_MAIL
:
3698 command
= nsGkAtoms::ReplyToMail
;
3700 case APPCOMMAND_SEND_MAIL
:
3701 command
= nsGkAtoms::SendMail
;
3706 nsCommandEvent
event(true, nsGkAtoms::onAppCommand
, command
, this);
3709 return DispatchWindowEvent(&event
);
3712 // Recursively dispatch synchronous paints for nsIWidget
3713 // descendants with invalidated rectangles.
3714 BOOL CALLBACK
nsWindow::DispatchStarvedPaints(HWND aWnd
, LPARAM aMsg
)
3716 LONG_PTR proc
= ::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
3717 if (proc
== (LONG_PTR
)&nsWindow::WindowProc
) {
3718 // its one of our windows so check to see if it has a
3719 // invalidated rect. If it does. Dispatch a synchronous
3721 if (GetUpdateRect(aWnd
, NULL
, FALSE
))
3722 VERIFY(::UpdateWindow(aWnd
));
3727 // Check for pending paints and dispatch any pending paint
3728 // messages for any nsIWidget which is a descendant of the
3729 // top-level window that *this* window is embedded within.
3731 // Note: We do not dispatch pending paint messages for non
3732 // nsIWidget managed windows.
3733 void nsWindow::DispatchPendingEvents()
3736 NS_WARNING("We were asked to dispatch pending events during painting, "
3737 "denying since that's unsafe.");
3741 // We need to ensure that reflow events do not get starved.
3742 // At the same time, we don't want to recurse through here
3743 // as that would prevent us from dispatching starved paints.
3744 static int recursionBlocker
= 0;
3745 if (recursionBlocker
++ == 0) {
3746 NS_ProcessPendingEvents(nullptr, PR_MillisecondsToInterval(100));
3750 // Quickly check to see if there are any paint events pending,
3751 // but only dispatch them if it has been long enough since the
3752 // last paint completed.
3753 if (::GetQueueStatus(QS_PAINT
) &&
3754 ((TimeStamp::Now() - mLastPaintEndTime
).ToMilliseconds() >= 50)) {
3755 // Find the top level window.
3756 HWND topWnd
= WinUtils::GetTopLevelHWND(mWnd
);
3758 // Dispatch pending paints for topWnd and all its descendant windows.
3759 // Note: EnumChildWindows enumerates all descendant windows not just
3760 // the children (but not the window itself).
3761 nsWindow::DispatchStarvedPaints(topWnd
, 0);
3762 ::EnumChildWindows(topWnd
, nsWindow::DispatchStarvedPaints
, 0);
3766 // Deal with plugin events
3767 bool nsWindow::DispatchPluginEvent(const MSG
&aMsg
)
3769 if (!PluginHasFocus())
3772 nsPluginEvent
event(true, NS_PLUGIN_INPUT_EVENT
, this);
3773 nsIntPoint
point(0, 0);
3774 InitEvent(event
, &point
);
3775 NPEvent pluginEvent
;
3776 pluginEvent
.event
= aMsg
.message
;
3777 pluginEvent
.wParam
= aMsg
.wParam
;
3778 pluginEvent
.lParam
= aMsg
.lParam
;
3779 event
.pluginEvent
= (void *)&pluginEvent
;
3780 event
.retargetToFocusedDocument
= true;
3781 return DispatchWindowEvent(&event
);
3784 bool nsWindow::DispatchPluginEvent(UINT aMessage
,
3787 bool aDispatchPendingEvents
)
3789 bool ret
= DispatchPluginEvent(WinUtils::InitMSG(aMessage
, aWParam
, aLParam
));
3790 if (aDispatchPendingEvents
) {
3791 DispatchPendingEvents();
3796 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg
,
3797 UINT aLastMsg
, nsFakeCharMessage
* aFakeCharMessage
)
3800 if (aFakeCharMessage
) {
3801 if (aFirstMsg
> WM_CHAR
|| aLastMsg
< WM_CHAR
) {
3804 msg
= aFakeCharMessage
->GetCharMessage(mWnd
);
3806 WinUtils::GetMessage(&msg
, mWnd
, aFirstMsg
, aLastMsg
);
3808 DispatchPluginEvent(msg
);
3811 // Deal with all sort of mouse event
3812 bool nsWindow::DispatchMouseEvent(uint32_t aEventType
, WPARAM wParam
,
3813 LPARAM lParam
, bool aIsContextMenuKey
,
3814 int16_t aButton
, uint16_t aInputSource
)
3816 bool result
= false;
3820 if (!mWidgetListener
) {
3824 switch (aEventType
) {
3825 case NS_MOUSE_BUTTON_DOWN
:
3829 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3830 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3831 case NS_MOUSE_BUTTON_UP
:
3834 if (!(wParam
& (MK_LBUTTON
| MK_MBUTTON
| MK_RBUTTON
)) && sIsInMouseCapture
)
3835 CaptureMouse(false);
3843 nsIntPoint eventPoint
;
3844 eventPoint
.x
= GET_X_LPARAM(lParam
);
3845 eventPoint
.y
= GET_Y_LPARAM(lParam
);
3847 nsMouseEvent
event(true, aEventType
, this, nsMouseEvent::eReal
,
3849 ? nsMouseEvent::eContextMenuKey
3850 : nsMouseEvent::eNormal
);
3851 if (aEventType
== NS_CONTEXTMENU
&& aIsContextMenuKey
) {
3852 nsIntPoint
zero(0, 0);
3853 InitEvent(event
, &zero
);
3855 InitEvent(event
, &eventPoint
);
3858 ModifierKeyState modifierKeyState
;
3859 modifierKeyState
.InitInputEvent(event
);
3860 event
.button
= aButton
;
3861 event
.inputSource
= aInputSource
;
3863 nsIntPoint mpScreen
= eventPoint
+ WidgetToScreenOffset();
3865 // Suppress mouse moves caused by widget creation
3866 if (aEventType
== NS_MOUSE_MOVE
)
3868 if ((sLastMouseMovePoint
.x
== mpScreen
.x
) && (sLastMouseMovePoint
.y
== mpScreen
.y
))
3870 sLastMouseMovePoint
.x
= mpScreen
.x
;
3871 sLastMouseMovePoint
.y
= mpScreen
.y
;
3874 bool insideMovementThreshold
= (DeprecatedAbs(sLastMousePoint
.x
- eventPoint
.x
) < (short)::GetSystemMetrics(SM_CXDOUBLECLK
)) &&
3875 (DeprecatedAbs(sLastMousePoint
.y
- eventPoint
.y
) < (short)::GetSystemMetrics(SM_CYDOUBLECLK
));
3879 case nsMouseEvent::eLeftButton
:
3880 eventButton
= VK_LBUTTON
;
3882 case nsMouseEvent::eMiddleButton
:
3883 eventButton
= VK_MBUTTON
;
3885 case nsMouseEvent::eRightButton
:
3886 eventButton
= VK_RBUTTON
;
3893 // Doubleclicks are used to set the click count, then changed to mousedowns
3894 // We're going to time double-clicks from mouse *up* to next mouse *down*
3895 LONG curMsgTime
= ::GetMessageTime();
3897 if (aEventType
== NS_MOUSE_DOUBLECLICK
) {
3898 event
.message
= NS_MOUSE_BUTTON_DOWN
;
3899 event
.button
= aButton
;
3900 sLastClickCount
= 2;
3902 else if (aEventType
== NS_MOUSE_BUTTON_UP
) {
3903 // remember when this happened for the next mouse down
3904 sLastMousePoint
.x
= eventPoint
.x
;
3905 sLastMousePoint
.y
= eventPoint
.y
;
3906 sLastMouseButton
= eventButton
;
3908 else if (aEventType
== NS_MOUSE_BUTTON_DOWN
) {
3909 // now look to see if we want to convert this to a double- or triple-click
3910 if (((curMsgTime
- sLastMouseDownTime
) < (LONG
)::GetDoubleClickTime()) && insideMovementThreshold
&&
3911 eventButton
== sLastMouseButton
) {
3914 // reset the click count, to count *this* click
3915 sLastClickCount
= 1;
3917 // Set last Click time on MouseDown only
3918 sLastMouseDownTime
= curMsgTime
;
3920 else if (aEventType
== NS_MOUSE_MOVE
&& !insideMovementThreshold
) {
3921 sLastClickCount
= 0;
3923 else if (aEventType
== NS_MOUSE_EXIT
) {
3924 event
.exit
= IsTopLevelMouseExit(mWnd
) ? nsMouseEvent::eTopLevel
: nsMouseEvent::eChild
;
3926 else if (aEventType
== NS_MOUSE_MOZHITTEST
)
3928 event
.mFlags
.mOnlyChromeDispatch
= true;
3930 event
.clickCount
= sLastClickCount
;
3933 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
3934 ("Msg Time: %d Click Count: %d\n", curMsgTime
, event
.clickCount
));
3937 NPEvent pluginEvent
;
3941 case NS_MOUSE_BUTTON_DOWN
:
3943 case nsMouseEvent::eLeftButton
:
3944 pluginEvent
.event
= WM_LBUTTONDOWN
;
3946 case nsMouseEvent::eMiddleButton
:
3947 pluginEvent
.event
= WM_MBUTTONDOWN
;
3949 case nsMouseEvent::eRightButton
:
3950 pluginEvent
.event
= WM_RBUTTONDOWN
;
3956 case NS_MOUSE_BUTTON_UP
:
3958 case nsMouseEvent::eLeftButton
:
3959 pluginEvent
.event
= WM_LBUTTONUP
;
3961 case nsMouseEvent::eMiddleButton
:
3962 pluginEvent
.event
= WM_MBUTTONUP
;
3964 case nsMouseEvent::eRightButton
:
3965 pluginEvent
.event
= WM_RBUTTONUP
;
3971 case NS_MOUSE_DOUBLECLICK
:
3973 case nsMouseEvent::eLeftButton
:
3974 pluginEvent
.event
= WM_LBUTTONDBLCLK
;
3976 case nsMouseEvent::eMiddleButton
:
3977 pluginEvent
.event
= WM_MBUTTONDBLCLK
;
3979 case nsMouseEvent::eRightButton
:
3980 pluginEvent
.event
= WM_RBUTTONDBLCLK
;
3987 pluginEvent
.event
= WM_MOUSEMOVE
;
3990 pluginEvent
.event
= WM_MOUSELEAVE
;
3993 pluginEvent
.event
= WM_NULL
;
3997 pluginEvent
.wParam
= wParam
; // plugins NEED raw OS event flags!
3998 pluginEvent
.lParam
= lParam
;
4000 event
.pluginEvent
= (void *)&pluginEvent
;
4002 // call the event callback
4003 if (mWidgetListener
) {
4004 if (nsToolkit::gMouseTrailer
)
4005 nsToolkit::gMouseTrailer
->Disable();
4006 if (aEventType
== NS_MOUSE_MOVE
) {
4007 if (nsToolkit::gMouseTrailer
&& !sIsInMouseCapture
) {
4008 nsToolkit::gMouseTrailer
->SetMouseTrailerWindow(mWnd
);
4015 if (rect
.Contains(event
.refPoint
)) {
4016 if (sCurrentWindow
== NULL
|| sCurrentWindow
!= this) {
4017 if ((nullptr != sCurrentWindow
) && (!sCurrentWindow
->mInDtor
)) {
4018 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
4019 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_EXIT
, wParam
, pos
, false,
4020 nsMouseEvent::eLeftButton
, aInputSource
);
4022 sCurrentWindow
= this;
4024 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
4025 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_ENTER
, wParam
, pos
, false,
4026 nsMouseEvent::eLeftButton
, aInputSource
);
4030 } else if (aEventType
== NS_MOUSE_EXIT
) {
4031 if (sCurrentWindow
== this) {
4032 sCurrentWindow
= nullptr;
4036 result
= DispatchWindowEvent(&event
);
4038 if (nsToolkit::gMouseTrailer
)
4039 nsToolkit::gMouseTrailer
->Enable();
4041 // Release the widget with NS_IF_RELEASE() just in case
4042 // the context menu key code in nsEventListenerManager::HandleEvent()
4043 // released it already.
4050 void nsWindow::DispatchFocusToTopLevelWindow(bool aIsActivate
)
4053 sJustGotActivate
= false;
4054 sJustGotDeactivate
= false;
4056 // retrive the toplevel window or dialog
4058 HWND toplevelWnd
= NULL
;
4060 toplevelWnd
= curWnd
;
4062 nsWindow
*win
= WinUtils::GetNSWindowPtr(curWnd
);
4064 nsWindowType wintype
;
4065 win
->GetWindowType(wintype
);
4066 if (wintype
== eWindowType_toplevel
|| wintype
== eWindowType_dialog
)
4070 curWnd
= ::GetParent(curWnd
); // Parent or owner (if has no parent)
4074 nsWindow
*win
= WinUtils::GetNSWindowPtr(toplevelWnd
);
4075 if (win
&& win
->mWidgetListener
) {
4077 win
->mWidgetListener
->WindowActivated();
4079 if (!win
->BlurEventsSuppressed()) {
4080 win
->mWidgetListener
->WindowDeactivated();
4087 bool nsWindow::IsTopLevelMouseExit(HWND aWnd
)
4089 DWORD pos
= ::GetMessagePos();
4091 mp
.x
= GET_X_LPARAM(pos
);
4092 mp
.y
= GET_Y_LPARAM(pos
);
4093 HWND mouseWnd
= ::WindowFromPoint(mp
);
4095 // WinUtils::GetTopLevelHWND() will return a HWND for the window frame
4096 // (which includes the non-client area). If the mouse has moved into
4097 // the non-client area, we should treat it as a top-level exit.
4098 HWND mouseTopLevel
= WinUtils::GetTopLevelHWND(mouseWnd
);
4099 if (mouseWnd
== mouseTopLevel
)
4102 return WinUtils::GetTopLevelHWND(aWnd
) != mouseTopLevel
;
4105 bool nsWindow::BlurEventsSuppressed()
4107 // are they suppressed in this window?
4108 if (mBlurSuppressLevel
> 0)
4111 // are they suppressed by any container widget?
4112 HWND parentWnd
= ::GetParent(mWnd
);
4114 nsWindow
*parent
= WinUtils::GetNSWindowPtr(parentWnd
);
4116 return parent
->BlurEventsSuppressed();
4121 // In some circumstances (opening dependent windows) it makes more sense
4122 // (and fixes a crash bug) to not blur the parent window. Called from
4124 void nsWindow::SuppressBlurEvents(bool aSuppress
)
4127 ++mBlurSuppressLevel
; // for this widget
4129 NS_ASSERTION(mBlurSuppressLevel
> 0, "unbalanced blur event suppression");
4130 if (mBlurSuppressLevel
> 0)
4131 --mBlurSuppressLevel
;
4135 bool nsWindow::ConvertStatus(nsEventStatus aStatus
)
4137 return aStatus
== nsEventStatus_eConsumeNoDefault
;
4140 /**************************************************************
4144 * IPC related helpers.
4146 **************************************************************/
4150 nsWindow::IsAsyncResponseEvent(UINT aMsg
, LRESULT
& aResult
)
4156 case WM_WINDOWPOSCHANGING
:
4157 case WM_WINDOWPOSCHANGED
:
4158 case WM_PARENTNOTIFY
:
4159 case WM_ACTIVATEAPP
:
4162 case WM_CHILDACTIVATE
:
4163 case WM_IME_SETCONTEXT
:
4167 case WM_MOUSEACTIVATE
:
4168 case WM_CONTEXTMENU
:
4172 case WM_SETTINGCHANGE
:
4180 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg
);
4188 nsWindow::IPCWindowProcHandler(UINT
& msg
, WPARAM
& wParam
, LPARAM
& lParam
)
4190 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4191 "Failed to prevent a nonqueued message from running!");
4193 // Modal UI being displayed in windowless plugins.
4194 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4195 (InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
4197 if (IsAsyncResponseEvent(msg
, res
)) {
4203 // Handle certain sync plugin events sent to the parent which
4204 // trigger ipc calls that result in deadlocks.
4207 bool handled
= false;
4210 // Windowless flash sending WM_ACTIVATE events to the main window
4211 // via calls to ShowWindow.
4213 if (lParam
!= 0 && LOWORD(wParam
) == WA_ACTIVE
&&
4214 IsWindow((HWND
)lParam
)) {
4215 // Check for Adobe Reader X sync activate message from their
4216 // helper window and ignore. Fixes an annoying focus problem.
4217 if ((InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
4218 PRUnichar szClass
[10];
4219 HWND focusWnd
= (HWND
)lParam
;
4220 if (IsWindowVisible(focusWnd
) &&
4221 GetClassNameW(focusWnd
, szClass
,
4222 sizeof(szClass
)/sizeof(PRUnichar
)) &&
4223 !wcscmp(szClass
, L
"Edit") &&
4224 !WinUtils::IsOurProcessWindow(focusWnd
)) {
4231 // Plugins taking or losing focus triggering focus app messages.
4234 // Windowed plugins that pass sys key events to defwndproc generate
4235 // WM_SYSCOMMAND events to the main window.
4237 // Windowed plugins that fire context menu selection events to parent
4239 case WM_CONTEXTMENU
:
4240 // IME events fired as a result of synchronous focus changes
4241 case WM_IME_SETCONTEXT
:
4247 (InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
4248 ReplyMessage(dwResult
);
4252 /**************************************************************
4253 **************************************************************
4255 ** BLOCK: Native events
4257 ** Main Windows message handlers and OnXXX handlers for
4258 ** Windows event handling.
4260 **************************************************************
4261 **************************************************************/
4263 /**************************************************************
4265 * SECTION: Wind proc.
4267 * The main Windows event procedures and associated
4268 * message processing methods.
4270 **************************************************************/
4273 DisplaySystemMenu(HWND hWnd
, nsSizeMode sizeMode
, bool isRtl
, int32_t x
, int32_t y
)
4275 HMENU hMenu
= GetSystemMenu(hWnd
, FALSE
);
4278 mii
.cbSize
= sizeof(MENUITEMINFO
);
4279 mii
.fMask
= MIIM_STATE
;
4282 // update the options
4283 mii
.fState
= MF_ENABLED
;
4284 SetMenuItemInfo(hMenu
, SC_RESTORE
, FALSE
, &mii
);
4285 SetMenuItemInfo(hMenu
, SC_SIZE
, FALSE
, &mii
);
4286 SetMenuItemInfo(hMenu
, SC_MOVE
, FALSE
, &mii
);
4287 SetMenuItemInfo(hMenu
, SC_MAXIMIZE
, FALSE
, &mii
);
4288 SetMenuItemInfo(hMenu
, SC_MINIMIZE
, FALSE
, &mii
);
4290 mii
.fState
= MF_GRAYED
;
4292 case nsSizeMode_Fullscreen
:
4293 SetMenuItemInfo(hMenu
, SC_RESTORE
, FALSE
, &mii
);
4294 // intentional fall through
4295 case nsSizeMode_Maximized
:
4296 SetMenuItemInfo(hMenu
, SC_SIZE
, FALSE
, &mii
);
4297 SetMenuItemInfo(hMenu
, SC_MOVE
, FALSE
, &mii
);
4298 SetMenuItemInfo(hMenu
, SC_MAXIMIZE
, FALSE
, &mii
);
4300 case nsSizeMode_Minimized
:
4301 SetMenuItemInfo(hMenu
, SC_MINIMIZE
, FALSE
, &mii
);
4303 case nsSizeMode_Normal
:
4304 SetMenuItemInfo(hMenu
, SC_RESTORE
, FALSE
, &mii
);
4308 TrackPopupMenu(hMenu
,
4309 (TPM_LEFTBUTTON
|TPM_RIGHTBUTTON
|
4310 TPM_RETURNCMD
|TPM_TOPALIGN
|
4311 (isRtl
? TPM_RIGHTALIGN
: TPM_LEFTALIGN
)),
4312 x
, y
, 0, hWnd
, NULL
);
4314 PostMessage(hWnd
, WM_SYSCOMMAND
, cmd
, 0);
4321 inline static mozilla::HangMonitor::ActivityType
ActivityTypeForMessage(UINT msg
)
4323 if ((msg
>= WM_KEYFIRST
&& msg
<= WM_IME_KEYLAST
) ||
4324 (msg
>= WM_MOUSEFIRST
&& msg
<= WM_MOUSELAST
) ||
4325 (msg
>= MOZ_WM_MOUSEWHEEL_FIRST
&& msg
<= MOZ_WM_MOUSEWHEEL_LAST
) ||
4326 (msg
>= NS_WM_IMEFIRST
&& msg
<= NS_WM_IMELAST
)) {
4327 return mozilla::HangMonitor::kUIActivity
;
4330 // This may not actually be right, but we don't want to reset the timer if
4331 // we're not actually processing a UI message.
4332 return mozilla::HangMonitor::kActivityUIAVail
;
4335 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
4336 // exceptions and passes the real work to WindowProcInternal. See bug 587406
4337 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
4338 LRESULT CALLBACK
nsWindow::WindowProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
4340 HangMonitor::NotifyActivity(ActivityTypeForMessage(msg
));
4342 return mozilla::CallWindowProcCrashProtected(WindowProcInternal
, hWnd
, msg
, wParam
, lParam
);
4345 LRESULT CALLBACK
nsWindow::WindowProcInternal(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
4347 if (::GetWindowLongPtrW(hWnd
, GWLP_ID
) == eFakeTrackPointScrollableID
) {
4348 // This message was sent to the FAKETRACKPOINTSCROLLABLE.
4349 if (msg
== WM_HSCROLL
) {
4350 // Route WM_HSCROLL messages to the main window.
4351 hWnd
= ::GetParent(::GetParent(hWnd
));
4353 // Handle all other messages with its original window procedure.
4354 WNDPROC prevWindowProc
= (WNDPROC
)::GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
4355 return ::CallWindowProcW(prevWindowProc
, hWnd
, msg
, wParam
, lParam
);
4359 if (msg
== MOZ_WM_TRACE
) {
4360 // This is a tracer event for measuring event loop latency.
4361 // See WidgetTraceEvent.cpp for more details.
4362 mozilla::SignalTracerThread();
4366 // Get the window which caused the event and ask it to process the message
4367 nsWindow
*targetWindow
= WinUtils::GetNSWindowPtr(hWnd
);
4368 NS_ASSERTION(targetWindow
, "nsWindow* is null!");
4370 return ::DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
4372 // Hold the window for the life of this method, in case it gets
4373 // destroyed during processing, unless we're in the dtor already.
4374 nsCOMPtr
<nsISupports
> kungFuDeathGrip
;
4375 if (!targetWindow
->mInDtor
)
4376 kungFuDeathGrip
= do_QueryInterface((nsBaseWidget
*)targetWindow
);
4378 targetWindow
->IPCWindowProcHandler(msg
, wParam
, lParam
);
4380 // Create this here so that we store the last rolled up popup until after
4381 // the event has been processed.
4382 nsAutoRollup autoRollup
;
4384 LRESULT popupHandlingResult
;
4385 if (DealWithPopups(hWnd
, msg
, wParam
, lParam
, &popupHandlingResult
))
4386 return popupHandlingResult
;
4388 // Call ProcessMessage
4390 if (targetWindow
->ProcessMessage(msg
, wParam
, lParam
, &retValue
)) {
4394 LRESULT res
= ::CallWindowProcW(targetWindow
->GetPrevWindowProc(),
4395 hWnd
, msg
, wParam
, lParam
);
4400 // The main windows message processing method for plugins.
4401 // The result means whether this method processed the native
4402 // event for plugin. If false, the native event should be
4403 // processed by the caller self.
4405 nsWindow::ProcessMessageForPlugin(const MSG
&aMsg
,
4407 bool &aCallDefWndProc
)
4409 NS_PRECONDITION(aResult
, "aResult must be non-null.");
4412 aCallDefWndProc
= false;
4413 bool eventDispatched
= false;
4414 switch (aMsg
.message
) {
4417 *aResult
= ProcessCharMessage(aMsg
, &eventDispatched
);
4422 *aResult
= ProcessKeyUpMessage(aMsg
, &eventDispatched
);
4427 *aResult
= ProcessKeyDownMessage(aMsg
, &eventDispatched
);
4431 case WM_SYSDEADCHAR
:
4444 if (!eventDispatched
)
4445 aCallDefWndProc
= !DispatchPluginEvent(aMsg
);
4446 DispatchPendingEvents();
4450 static void ForceFontUpdate()
4452 // update device context font cache
4453 // Dirty but easiest way:
4454 // Changing nsIPrefBranch entry which triggers callbacks
4455 // and flows into calling mDeviceContext->FlushFontCache()
4456 // to update the font cache in all the instance of Browsers
4457 static const char kPrefName
[] = "font.internaluseonly.changed";
4458 bool fontInternalChange
=
4459 Preferences::GetBool(kPrefName
, false);
4460 Preferences::SetBool(kPrefName
, !fontInternalChange
);
4463 static bool CleartypeSettingChanged()
4465 static int currentQuality
= -1;
4466 BYTE quality
= cairo_win32_get_system_text_quality();
4468 if (currentQuality
== quality
)
4471 if (currentQuality
< 0) {
4472 currentQuality
= quality
;
4475 currentQuality
= quality
;
4479 // The main windows message processing method.
4480 bool nsWindow::ProcessMessage(UINT msg
, WPARAM
&wParam
, LPARAM
&lParam
,
4483 // (Large blocks of code should be broken out into OnEvent handlers.)
4484 if (mWindowHook
.Notify(mWnd
, msg
, wParam
, lParam
, aRetValue
))
4487 #if defined(EVENT_DEBUG_OUTPUT)
4488 // First param shows all events, second param indicates whether
4489 // to show mouse move events. See nsWindowDbg for details.
4490 PrintEvent(msg
, SHOW_REPEAT_EVENTS
, SHOW_MOUSEMOVE_EVENTS
);
4494 if (IMEHandler::ProcessMessage(this, msg
, wParam
, lParam
, aRetValue
,
4496 return mWnd
? eatMessage
: true;
4499 if (MouseScrollHandler::ProcessMessage(this, msg
, wParam
, lParam
, aRetValue
,
4501 return mWnd
? eatMessage
: true;
4504 if (PluginHasFocus()) {
4505 bool callDefaultWndProc
;
4506 MSG nativeMsg
= WinUtils::InitMSG(msg
, wParam
, lParam
);
4507 if (ProcessMessageForPlugin(nativeMsg
, aRetValue
, callDefaultWndProc
)) {
4508 return mWnd
? !callDefaultWndProc
: true;
4512 bool result
= false; // call the default nsWindow proc
4515 // Glass hit testing w/custom transparent margins
4516 LRESULT dwmHitResult
;
4517 if (mCustomNonClient
&&
4518 nsUXThemeData::CheckForCompositor() &&
4519 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd
, msg
, wParam
, lParam
, &dwmHitResult
)) {
4520 *aRetValue
= dwmHitResult
;
4525 // WM_QUERYENDSESSION must be handled by all windows.
4526 // Otherwise Windows thinks the window can just be killed at will.
4527 case WM_QUERYENDSESSION
:
4528 if (sCanQuit
== TRI_UNKNOWN
)
4530 // Ask if it's ok to quit, and store the answer until we
4531 // get WM_ENDSESSION signaling the round is complete.
4532 nsCOMPtr
<nsIObserverService
> obsServ
=
4533 mozilla::services::GetObserverService();
4534 nsCOMPtr
<nsISupportsPRBool
> cancelQuit
=
4535 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID
);
4536 cancelQuit
->SetData(false);
4537 obsServ
->NotifyObservers(cancelQuit
, "quit-application-requested", nullptr);
4540 cancelQuit
->GetData(&abortQuit
);
4541 sCanQuit
= abortQuit
? TRI_FALSE
: TRI_TRUE
;
4543 *aRetValue
= sCanQuit
? TRUE
: FALSE
;
4548 case MOZ_WM_APP_QUIT
:
4549 if (msg
== MOZ_WM_APP_QUIT
|| (wParam
== TRUE
&& sCanQuit
== TRI_TRUE
))
4551 // Let's fake a shutdown sequence without actually closing windows etc.
4552 // to avoid Windows killing us in the middle. A proper shutdown would
4553 // require having a chance to pump some messages. Unfortunately
4554 // Windows won't let us do that. Bug 212316.
4555 nsCOMPtr
<nsIObserverService
> obsServ
=
4556 mozilla::services::GetObserverService();
4557 NS_NAMED_LITERAL_STRING(context
, "shutdown-persist");
4558 obsServ
->NotifyObservers(nullptr, "quit-application-granted", nullptr);
4559 obsServ
->NotifyObservers(nullptr, "quit-application-forced", nullptr);
4560 obsServ
->NotifyObservers(nullptr, "quit-application", nullptr);
4561 obsServ
->NotifyObservers(nullptr, "profile-change-net-teardown", context
.get());
4562 obsServ
->NotifyObservers(nullptr, "profile-change-teardown", context
.get());
4563 obsServ
->NotifyObservers(nullptr, "profile-before-change", context
.get());
4564 obsServ
->NotifyObservers(nullptr, "profile-before-change2", context
.get());
4565 // Then a controlled but very quick exit.
4568 sCanQuit
= TRI_UNKNOWN
;
4572 case WM_SYSCOLORCHANGE
:
4573 OnSysColorChanged();
4576 case WM_THEMECHANGED
:
4578 // Update non-client margin offsets
4579 UpdateNonClientMargins();
4580 nsUXThemeData::InitTitlebarInfo();
4581 nsUXThemeData::UpdateNativeThemeInfo();
4583 NotifyThemeChanged();
4585 // Invalidate the window so that the repaint will
4586 // pick up the new theme.
4587 Invalidate(true, true, true);
4593 // We only handle this message for the hidden window,
4594 // as we only need to update the (global) font list once
4595 // for any given change, not once per window!
4596 if (mWindowType
!= eWindowType_invisible
) {
4601 bool didChange
= false;
4603 // update the global font list
4604 nsCOMPtr
<nsIFontEnumerator
> fontEnum
= do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv
);
4605 if (NS_SUCCEEDED(rv
)) {
4606 fontEnum
->UpdateFontList(&didChange
);
4608 } //if (NS_SUCCEEDED(rv))
4614 if (mCustomNonClient
) {
4615 // If `wParam` is `FALSE`, `lParam` points to a `RECT` that contains
4616 // the proposed window rectangle for our window. During our
4617 // processing of the `WM_NCCALCSIZE` message, we are expected to
4618 // modify the `RECT` that `lParam` points to, so that its value upon
4619 // our return is the new client area. We must return 0 if `wParam`
4622 // If `wParam` is `TRUE`, `lParam` points to a `NCCALCSIZE_PARAMS`
4623 // struct. This struct contains an array of 3 `RECT`s, the first of
4624 // which has the exact same meaning as the `RECT` that is pointed to
4625 // by `lParam` when `wParam` is `FALSE`. The remaining `RECT`s, in
4626 // conjunction with our return value, can
4627 // be used to specify portions of the source and destination window
4628 // rectangles that are valid and should be preserved. We opt not to
4629 // implement an elaborate client-area preservation technique, and
4630 // simply return 0, which means "preserve the entire old client area
4631 // and align it with the upper-left corner of our new client area".
4632 RECT
*clientRect
= wParam
4633 ? &(reinterpret_cast<NCCALCSIZE_PARAMS
*>(lParam
))->rgrc
[0]
4634 : (reinterpret_cast<RECT
*>(lParam
));
4635 clientRect
->top
+= (mCaptionHeight
- mNonClientOffset
.top
);
4636 clientRect
->left
+= (mHorResizeMargin
- mNonClientOffset
.left
);
4637 clientRect
->right
-= (mHorResizeMargin
- mNonClientOffset
.right
);
4638 clientRect
->bottom
-= (mVertResizeMargin
- mNonClientOffset
.bottom
);
4649 * If an nc client area margin has been moved, we are responsible
4650 * for calculating where the resize margins are and returning the
4651 * appropriate set of hit test constants. DwmDefWindowProc (above)
4652 * will handle hit testing on it's command buttons if we are on a
4653 * composited desktop.
4656 if (!mCustomNonClient
)
4660 ClientMarginHitTestPoint(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
4667 * WM_SETTEXT paints the titlebar area. Avoid this if we have a
4668 * custom titlebar we paint ourselves.
4671 if (!mCustomNonClient
|| mNonClientMargins
.top
== -1)
4675 // From msdn, the way around this is to disable the visible state
4676 // temporarily. We need the text to be set but we don't want the
4678 DWORD style
= GetWindowLong(mWnd
, GWL_STYLE
);
4679 SetWindowLong(mWnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
4680 *aRetValue
= CallWindowProcW(GetPrevWindowProc(), mWnd
,
4681 msg
, wParam
, lParam
);
4682 SetWindowLong(mWnd
, GWL_STYLE
, style
);
4689 * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
4690 * through WM_NCPAINT via InvalidateNonClientRegion.
4693 if (!mCustomNonClient
)
4696 // let the dwm handle nc painting on glass
4697 if(nsUXThemeData::CheckForCompositor())
4700 if (wParam
== TRUE
) {
4702 *aRetValue
= FALSE
; // ignored
4704 UpdateGetWindowInfoCaptionStatus(true);
4705 // invalidate to trigger a paint
4706 InvalidateNonClientRegion();
4710 *aRetValue
= TRUE
; // go ahead and deactive
4712 UpdateGetWindowInfoCaptionStatus(false);
4713 // invalidate to trigger a paint
4714 InvalidateNonClientRegion();
4722 * Reset the non-client paint region so that it excludes the
4723 * non-client areas we paint manually. Then call defwndproc
4724 * to do the actual painting.
4727 if (!mCustomNonClient
)
4730 // let the dwm handle nc painting on glass
4731 if(nsUXThemeData::CheckForCompositor())
4734 HRGN paintRgn
= ExcludeNonClientFromPaintRegion((HRGN
)wParam
);
4735 LRESULT res
= CallWindowProcW(GetPrevWindowProc(), mWnd
,
4736 msg
, (WPARAM
)paintRgn
, lParam
);
4737 if (paintRgn
!= (HRGN
)wParam
)
4738 DeleteObject(paintRgn
);
4744 case WM_POWERBROADCAST
:
4747 case PBT_APMSUSPEND
:
4748 PostSleepWakeNotification(true);
4750 case PBT_APMRESUMEAUTOMATIC
:
4751 case PBT_APMRESUMECRITICAL
:
4752 case PBT_APMRESUMESUSPEND
:
4753 PostSleepWakeNotification(false);
4758 case WM_MOVE
: // Window moved
4761 ::GetWindowRect(mWnd
, &rect
);
4762 result
= OnMove(rect
.left
, rect
.top
);
4766 case WM_CLOSE
: // close request
4767 if (mWidgetListener
)
4768 mWidgetListener
->RequestWindowClose(this);
4769 result
= true; // abort window closure
4779 if (CleartypeSettingChanged()) {
4781 gfxFontCache
*fc
= gfxFontCache::GetCache();
4786 *aRetValue
= (int) OnPaint(NULL
, 0);
4790 case WM_PRINTCLIENT
:
4791 result
= OnPaint((HDC
) wParam
, 0);
4795 result
= OnHotKey(wParam
, lParam
);
4801 MSG nativeMsg
= WinUtils::InitMSG(msg
, wParam
, lParam
);
4802 result
= ProcessCharMessage(nativeMsg
, nullptr);
4803 DispatchPendingEvents();
4810 MSG nativeMsg
= WinUtils::InitMSG(msg
, wParam
, lParam
);
4811 nativeMsg
.time
= ::GetMessageTime();
4812 result
= ProcessKeyUpMessage(nativeMsg
, nullptr);
4813 DispatchPendingEvents();
4820 MSG nativeMsg
= WinUtils::InitMSG(msg
, wParam
, lParam
);
4821 result
= ProcessKeyDownMessage(nativeMsg
, nullptr);
4822 DispatchPendingEvents();
4826 // say we've dealt with erase background if widget does
4827 // not need auto-erasing
4829 if (!AutoErase((HDC
)wParam
)) {
4837 mMousePresent
= true;
4839 // Suppress dispatch of pending events
4840 // when mouse moves are generated by widget
4841 // creation instead of user input.
4842 LPARAM lParamScreen
= lParamToScreen(lParam
);
4844 mp
.x
= GET_X_LPARAM(lParamScreen
);
4845 mp
.y
= GET_Y_LPARAM(lParamScreen
);
4846 bool userMovedMouse
= false;
4847 if ((sLastMouseMovePoint
.x
!= mp
.x
) || (sLastMouseMovePoint
.y
!= mp
.y
)) {
4848 userMovedMouse
= true;
4851 result
= DispatchMouseEvent(NS_MOUSE_MOVE
, wParam
, lParam
,
4852 false, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4853 if (userMovedMouse
) {
4854 DispatchPendingEvents();
4859 case WM_NCMOUSEMOVE
:
4860 // If we receive a mouse move event on non-client chrome, make sure and
4861 // send an NS_MOUSE_EXIT event as well.
4862 if (mMousePresent
&& !sIsInMouseCapture
)
4863 SendMessage(mWnd
, WM_MOUSELEAVE
, 0, 0);
4866 case WM_LBUTTONDOWN
:
4868 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
,
4869 false, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4870 DispatchPendingEvents();
4876 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
,
4877 false, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4878 DispatchPendingEvents();
4886 mMousePresent
= false;
4888 // We need to check mouse button states and put them in for
4890 WPARAM mouseState
= (GetKeyState(VK_LBUTTON
) ? MK_LBUTTON
: 0)
4891 | (GetKeyState(VK_MBUTTON
) ? MK_MBUTTON
: 0)
4892 | (GetKeyState(VK_RBUTTON
) ? MK_RBUTTON
: 0);
4893 // Synthesize an event position because we don't get one from
4895 LPARAM pos
= lParamToClient(::GetMessagePos());
4896 DispatchMouseEvent(NS_MOUSE_EXIT
, mouseState
, pos
, false,
4897 nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4901 case WM_CONTEXTMENU
:
4903 // if the context menu is brought up from the keyboard, |lParam|
4906 bool contextMenukey
= false;
4909 contextMenukey
= true;
4910 pos
= lParamToClient(GetMessagePos());
4914 pos
= lParamToClient(lParam
);
4917 result
= DispatchMouseEvent(NS_CONTEXTMENU
, wParam
, pos
, contextMenukey
,
4919 nsMouseEvent::eLeftButton
:
4920 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4921 if (lParam
!= -1 && !result
&& mCustomNonClient
&&
4922 DispatchMouseEvent(NS_MOUSE_MOZHITTEST
, wParam
, pos
,
4923 false, nsMouseEvent::eLeftButton
,
4924 MOUSE_INPUT_SOURCE())) {
4925 // Blank area hit, throw up the system menu.
4926 DisplaySystemMenu(mWnd
, mSizeMode
, mIsRTL
, GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
4932 case WM_LBUTTONDBLCLK
:
4933 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, false,
4934 nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4935 DispatchPendingEvents();
4938 case WM_MBUTTONDOWN
:
4939 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, false,
4940 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4941 DispatchPendingEvents();
4945 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, false,
4946 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4947 DispatchPendingEvents();
4950 case WM_MBUTTONDBLCLK
:
4951 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, false,
4952 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4953 DispatchPendingEvents();
4956 case WM_NCMBUTTONDOWN
:
4957 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, 0, lParamToClient(lParam
), false,
4958 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4959 DispatchPendingEvents();
4962 case WM_NCMBUTTONUP
:
4963 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, 0, lParamToClient(lParam
), false,
4964 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4965 DispatchPendingEvents();
4968 case WM_NCMBUTTONDBLCLK
:
4969 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, 0, lParamToClient(lParam
), false,
4970 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4971 DispatchPendingEvents();
4974 case WM_RBUTTONDOWN
:
4975 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, false,
4976 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4977 DispatchPendingEvents();
4981 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, false,
4982 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4983 DispatchPendingEvents();
4986 case WM_RBUTTONDBLCLK
:
4987 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, false,
4988 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4989 DispatchPendingEvents();
4992 case WM_NCRBUTTONDOWN
:
4993 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, 0, lParamToClient(lParam
),
4994 false, nsMouseEvent::eRightButton
,
4995 MOUSE_INPUT_SOURCE());
4996 DispatchPendingEvents();
4999 case WM_NCRBUTTONUP
:
5000 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, 0, lParamToClient(lParam
),
5001 false, nsMouseEvent::eRightButton
,
5002 MOUSE_INPUT_SOURCE());
5003 DispatchPendingEvents();
5006 case WM_NCRBUTTONDBLCLK
:
5007 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, 0, lParamToClient(lParam
),
5008 false, nsMouseEvent::eRightButton
,
5009 MOUSE_INPUT_SOURCE());
5010 DispatchPendingEvents();
5013 case WM_EXITSIZEMOVE
:
5014 if (!sIsInMouseCapture
) {
5015 NotifySizeMoveDone();
5019 case WM_NCLBUTTONDBLCLK
:
5020 DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, 0, lParamToClient(lParam
),
5021 false, nsMouseEvent::eLeftButton
,
5022 MOUSE_INPUT_SOURCE());
5024 DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, 0, lParamToClient(lParam
),
5025 false, nsMouseEvent::eLeftButton
,
5026 MOUSE_INPUT_SOURCE());
5027 DispatchPendingEvents();
5032 uint32_t appCommand
= GET_APPCOMMAND_LPARAM(lParam
);
5033 uint32_t contentCommandMessage
= NS_EVENT_NULL
;
5034 // XXX After we implement KeyboardEvent.key, we should dispatch the
5035 // key event if (GET_DEVICE_LPARAM(lParam) == FAPPCOMMAND_KEY) is.
5038 case APPCOMMAND_BROWSER_BACKWARD
:
5039 case APPCOMMAND_BROWSER_FORWARD
:
5040 case APPCOMMAND_BROWSER_REFRESH
:
5041 case APPCOMMAND_BROWSER_STOP
:
5042 case APPCOMMAND_BROWSER_SEARCH
:
5043 case APPCOMMAND_BROWSER_FAVORITES
:
5044 case APPCOMMAND_BROWSER_HOME
:
5045 case APPCOMMAND_CLOSE
:
5046 case APPCOMMAND_FIND
:
5047 case APPCOMMAND_HELP
:
5048 case APPCOMMAND_NEW
:
5049 case APPCOMMAND_OPEN
:
5050 case APPCOMMAND_PRINT
:
5051 case APPCOMMAND_SAVE
:
5052 case APPCOMMAND_FORWARD_MAIL
:
5053 case APPCOMMAND_REPLY_TO_MAIL
:
5054 case APPCOMMAND_SEND_MAIL
:
5055 // We shouldn't consume the message always because if we don't handle
5056 // the message, the sender (typically, utility of keyboard or mouse)
5057 // may send other key messages which indicate well known shortcut key.
5058 if (DispatchCommandEvent(appCommand
)) {
5059 // tell the driver that we handled the event
5065 // Use content command for following commands:
5066 case APPCOMMAND_COPY
:
5067 contentCommandMessage
= NS_CONTENT_COMMAND_COPY
;
5069 case APPCOMMAND_CUT
:
5070 contentCommandMessage
= NS_CONTENT_COMMAND_CUT
;
5072 case APPCOMMAND_PASTE
:
5073 contentCommandMessage
= NS_CONTENT_COMMAND_PASTE
;
5075 case APPCOMMAND_REDO
:
5076 contentCommandMessage
= NS_CONTENT_COMMAND_REDO
;
5078 case APPCOMMAND_UNDO
:
5079 contentCommandMessage
= NS_CONTENT_COMMAND_UNDO
;
5083 if (contentCommandMessage
) {
5084 nsContentCommandEvent
contentCommand(true, contentCommandMessage
, this);
5085 DispatchWindowEvent(&contentCommand
);
5086 // tell the driver that we handled the event
5090 // default = false - tell the driver that the event was not handled
5094 // The WM_ACTIVATE event is fired when a window is raised or lowered,
5095 // and the loword of wParam specifies which. But we don't want to tell
5096 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
5097 // events are fired. Instead, set either the sJustGotActivate or
5098 // gJustGotDeactivate flags and activate/deactivate once the focus
5101 if (mWidgetListener
) {
5102 int32_t fActive
= LOWORD(wParam
);
5104 if (WA_INACTIVE
== fActive
) {
5105 // when minimizing a window, the deactivation and focus events will
5106 // be fired in the reverse order. Instead, just deactivate right away.
5108 DispatchFocusToTopLevelWindow(false);
5110 sJustGotDeactivate
= true;
5112 if (mIsTopWidgetWindow
)
5113 mLastKeyboardLayout
= gKbdLayout
.GetLayout();
5118 sJustGotActivate
= true;
5119 nsMouseEvent
event(true, NS_MOUSE_ACTIVATE
, this,
5120 nsMouseEvent::eReal
);
5122 ModifierKeyState modifierKeyState
;
5123 modifierKeyState
.InitInputEvent(event
);
5124 DispatchWindowEvent(&event
);
5125 if (sSwitchKeyboardLayout
&& mLastKeyboardLayout
)
5126 ActivateKeyboardLayout(mLastKeyboardLayout
, 0);
5131 case WM_MOUSEACTIVATE
:
5132 if (mWindowType
== eWindowType_popup
) {
5133 // a popup with a parent owner should not be activated when clicked
5134 // but should still allow the mouse event to be fired, so the return
5135 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5136 // window, just use default processing so that the window is activated.
5137 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
5138 if (owner
&& owner
== ::GetForegroundWindow()) {
5139 *aRetValue
= MA_NOACTIVATE
;
5145 case WM_WINDOWPOSCHANGING
:
5147 LPWINDOWPOS info
= (LPWINDOWPOS
) lParam
;
5148 OnWindowPosChanging(info
);
5152 case WM_GETMINMAXINFO
:
5154 MINMAXINFO
* mmi
= (MINMAXINFO
*)lParam
;
5155 // Set the constraints. The minimum size should also be constrained to the
5156 // default window maximum size so that it fits on screen.
5157 mmi
->ptMinTrackSize
.x
=
5158 std::min((int32_t)mmi
->ptMaxTrackSize
.x
,
5159 std::max((int32_t)mmi
->ptMinTrackSize
.x
, mSizeConstraints
.mMinSize
.width
));
5160 mmi
->ptMinTrackSize
.y
=
5161 std::min((int32_t)mmi
->ptMaxTrackSize
.y
,
5162 std::max((int32_t)mmi
->ptMinTrackSize
.y
, mSizeConstraints
.mMinSize
.height
));
5163 mmi
->ptMaxTrackSize
.x
= std::min((int32_t)mmi
->ptMaxTrackSize
.x
, mSizeConstraints
.mMaxSize
.width
);
5164 mmi
->ptMaxTrackSize
.y
= std::min((int32_t)mmi
->ptMaxTrackSize
.y
, mSizeConstraints
.mMaxSize
.height
);
5169 // If previous focused window isn't ours, it must have received the
5170 // redirected message. So, we should forget it.
5171 if (!WinUtils::IsOurProcessWindow(HWND(wParam
))) {
5172 ForgetRedirectedKeyDownMessage();
5174 if (sJustGotActivate
) {
5175 DispatchFocusToTopLevelWindow(true);
5180 if (sJustGotDeactivate
) {
5181 DispatchFocusToTopLevelWindow(false);
5185 case WM_WINDOWPOSCHANGED
:
5187 WINDOWPOS
*wp
= (LPWINDOWPOS
)lParam
;
5188 OnWindowPosChanged(wp
, result
);
5192 case WM_INPUTLANGCHANGEREQUEST
:
5197 case WM_INPUTLANGCHANGE
:
5198 result
= OnInputLangChange((HKL
)lParam
);
5201 case WM_DESTROYCLIPBOARD
:
5203 nsIClipboard
* clipboard
;
5204 nsresult rv
= CallGetService(kCClipboardCID
, &clipboard
);
5205 if(NS_SUCCEEDED(rv
)) {
5206 clipboard
->EmptyClipboard(nsIClipboard::kGlobalClipboard
);
5207 NS_RELEASE(clipboard
);
5212 #ifdef ACCESSIBILITY
5216 // Do explicit casting to make it working on 64bit systems (see bug 649236
5218 DWORD objId
= static_cast<DWORD
>(lParam
);
5219 if (objId
== OBJID_CLIENT
) { // oleacc.dll will be loaded dynamically
5220 a11y::Accessible
* rootAccessible
= GetRootAccessible(); // Held by a11y cache
5221 if (rootAccessible
) {
5222 IAccessible
*msaaAccessible
= NULL
;
5223 rootAccessible
->GetNativeInterface((void**)&msaaAccessible
); // does an addref
5224 if (msaaAccessible
) {
5225 *aRetValue
= LresultFromObject(IID_IAccessible
, wParam
, msaaAccessible
); // does an addref
5226 msaaAccessible
->Release(); // release extra addref
5227 result
= true; // We handled the WM_GETOBJECT message
5236 WPARAM filteredWParam
= (wParam
&0xFFF0);
5237 // prevent Windows from trimming the working set. bug 76831
5238 if (!sTrimOnMinimize
&& filteredWParam
== SC_MINIMIZE
) {
5239 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
5243 // Handle the system menu manually when we're in full screen mode
5244 // so we can set the appropriate options.
5245 if (filteredWParam
== SC_KEYMENU
&& lParam
== VK_SPACE
&&
5246 mSizeMode
== nsSizeMode_Fullscreen
) {
5247 DisplaySystemMenu(mWnd
, mSizeMode
, mIsRTL
,
5248 MOZ_SYSCONTEXT_X_POS
,
5249 MOZ_SYSCONTEXT_Y_POS
);
5255 case WM_DWMCOMPOSITIONCHANGED
:
5256 // First, update the compositor state to latest one. All other methods
5257 // should use same state as here for consistency painting.
5258 nsUXThemeData::CheckForCompositor(true);
5260 UpdateNonClientMargins();
5261 RemovePropW(mWnd
, kManageWindowInfoProperty
);
5262 BroadcastMsg(mWnd
, WM_DWMCOMPOSITIONCHANGED
);
5263 NotifyThemeChanged();
5265 Invalidate(true, true, true);
5268 case WM_UPDATEUISTATE
:
5270 // If the UI state has changed, fire an event so the UI updates the
5271 // keyboard cues based on the system setting and how the window was
5272 // opened. For example, a dialog opened via a keyboard press on a button
5273 // should enable cues, whereas the same dialog opened via a mouse click of
5274 // the button should not.
5275 int32_t action
= LOWORD(wParam
);
5276 if (action
== UIS_SET
|| action
== UIS_CLEAR
) {
5277 int32_t flags
= HIWORD(wParam
);
5278 UIStateChangeType showAccelerators
= UIStateChangeType_NoChange
;
5279 UIStateChangeType showFocusRings
= UIStateChangeType_NoChange
;
5280 if (flags
& UISF_HIDEACCEL
)
5281 showAccelerators
= (action
== UIS_SET
) ? UIStateChangeType_Clear
: UIStateChangeType_Set
;
5282 if (flags
& UISF_HIDEFOCUS
)
5283 showFocusRings
= (action
== UIS_SET
) ? UIStateChangeType_Clear
: UIStateChangeType_Set
;
5284 NotifyUIStateChanged(showAccelerators
, showFocusRings
);
5290 /* Gesture support events */
5291 case WM_TABLET_QUERYSYSTEMGESTURESTATUS
:
5292 // According to MS samples, this must be handled to enable
5293 // rotational support in multi-touch drivers.
5295 *aRetValue
= TABLET_ROTATE_GESTURE_ENABLE
;
5299 result
= OnTouch(wParam
, lParam
);
5306 result
= OnGesture(wParam
, lParam
);
5309 case WM_GESTURENOTIFY
:
5311 if (mWindowType
!= eWindowType_invisible
&&
5312 mWindowType
!= eWindowType_plugin
) {
5313 // A GestureNotify event is dispatched to decide which single-finger panning
5314 // direction should be active (including none) and if pan feedback should
5315 // be displayed. Java and plugin windows can make their own calls.
5316 GESTURENOTIFYSTRUCT
* gestureinfo
= (GESTURENOTIFYSTRUCT
*)lParam
;
5317 nsPointWin touchPoint
;
5318 touchPoint
= gestureinfo
->ptsLocation
;
5319 touchPoint
.ScreenToClient(mWnd
);
5320 nsGestureNotifyEvent
gestureNotifyEvent(true, NS_GESTURENOTIFY_EVENT_START
, this);
5321 gestureNotifyEvent
.refPoint
= touchPoint
;
5322 nsEventStatus status
;
5323 DispatchEvent(&gestureNotifyEvent
, status
);
5324 mDisplayPanFeedback
= gestureNotifyEvent
.displayPanFeedback
;
5326 mGesture
.SetWinGestureSupport(mWnd
, gestureNotifyEvent
.panDirection
);
5328 result
= false; //should always bubble to DefWindowProc
5334 nsContentCommandEvent
command(true, NS_CONTENT_COMMAND_DELETE
, this);
5335 DispatchWindowEvent(&command
);
5342 nsContentCommandEvent
command(true, NS_CONTENT_COMMAND_CUT
, this);
5343 DispatchWindowEvent(&command
);
5350 nsContentCommandEvent
command(true, NS_CONTENT_COMMAND_COPY
, this);
5351 DispatchWindowEvent(&command
);
5358 nsContentCommandEvent
command(true, NS_CONTENT_COMMAND_PASTE
, this);
5359 DispatchWindowEvent(&command
);
5366 nsContentCommandEvent
command(true, NS_CONTENT_COMMAND_UNDO
, this);
5367 DispatchWindowEvent(&command
);
5368 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5375 nsContentCommandEvent
command(true, NS_CONTENT_COMMAND_REDO
, this);
5376 DispatchWindowEvent(&command
);
5377 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5384 // Support EM_CANPASTE message only when wParam isn't specified or
5385 // is plain text format.
5386 if (wParam
== 0 || wParam
== CF_TEXT
|| wParam
== CF_UNICODETEXT
) {
5387 nsContentCommandEvent
command(true, NS_CONTENT_COMMAND_PASTE
,
5389 DispatchWindowEvent(&command
);
5390 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5398 nsContentCommandEvent
command(true, NS_CONTENT_COMMAND_UNDO
,
5400 DispatchWindowEvent(&command
);
5401 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5408 nsContentCommandEvent
command(true, NS_CONTENT_COMMAND_REDO
,
5410 DispatchWindowEvent(&command
);
5411 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5418 if (msg
== nsAppShell::GetTaskbarButtonCreatedMessage())
5419 SetHasTaskbarIconBeenCreated();
5420 if (msg
== sOOPPPluginFocusEvent
) {
5422 // With OOPP, the plugin window exists in another process and is a child of
5423 // this window. This window is a placeholder plugin window for the dom. We
5424 // receive this event when the child window receives focus. (sent from
5425 // PluginInstanceParent.cpp)
5426 ::SendMessage(mWnd
, WM_MOUSEACTIVATE
, 0, 0); // See nsPluginNativeWindowWin.cpp
5428 // WM_KILLFOCUS was received by the child process.
5429 if (sJustGotDeactivate
) {
5430 DispatchFocusToTopLevelWindow(false);
5438 //*aRetValue = result;
5443 //Events which caused mWnd destruction and aren't consumed
5444 //will crash during the Windows default processing.
5449 /**************************************************************
5451 * SECTION: Broadcast messaging
5453 * Broadcast messages to all windows.
5455 **************************************************************/
5457 // Enumerate all child windows sending aMsg to each of them
5458 BOOL CALLBACK
nsWindow::BroadcastMsgToChildren(HWND aWnd
, LPARAM aMsg
)
5460 WNDPROC winProc
= (WNDPROC
)::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
5461 if (winProc
== &nsWindow::WindowProc
) {
5462 // it's one of our windows so go ahead and send a message to it
5463 ::CallWindowProcW(winProc
, aWnd
, aMsg
, 0, 0);
5468 // Enumerate all top level windows specifying that the children of each
5469 // top level window should be enumerated. Do *not* send the message to
5470 // each top level window since it is assumed that the toolkit will send
5471 // aMsg to them directly.
5472 BOOL CALLBACK
nsWindow::BroadcastMsg(HWND aTopWindow
, LPARAM aMsg
)
5474 // Iterate each of aTopWindows child windows sending the aMsg
5476 ::EnumChildWindows(aTopWindow
, nsWindow::BroadcastMsgToChildren
, aMsg
);
5480 /**************************************************************
5482 * SECTION: Event processing helpers
5484 * Special processing for certain event types and
5485 * synthesized events.
5487 **************************************************************/
5490 nsWindow::ClientMarginHitTestPoint(int32_t mx
, int32_t my
)
5492 if (mSizeMode
== nsSizeMode_Minimized
||
5493 mSizeMode
== nsSizeMode_Fullscreen
) {
5497 // Calculations are done in screen coords
5499 GetWindowRect(mWnd
, &winRect
);
5501 // hit return constants:
5502 // HTBORDER - non-resizable border
5503 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5504 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5505 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5506 // HTCAPTION - general title bar area
5507 // HTCLIENT - area considered the client
5508 // HTCLOSE - hovering over the close button
5509 // HTMAXBUTTON - maximize button
5510 // HTMINBUTTON - minimize button
5512 int32_t testResult
= HTCLIENT
;
5514 bool isResizable
= (mBorderStyle
& (eBorderStyle_all
|
5515 eBorderStyle_resizeh
|
5516 eBorderStyle_default
)) > 0 ? true : false;
5517 if (mSizeMode
== nsSizeMode_Maximized
)
5518 isResizable
= false;
5520 // Ensure being accessible to borders of window. Even if contents are in
5521 // this area, the area must behave as border.
5522 nsIntMargin
nonClientSize(std::max(mCaptionHeight
- mNonClientOffset
.top
,
5523 kResizableBorderMinSize
),
5524 std::max(mHorResizeMargin
- mNonClientOffset
.right
,
5525 kResizableBorderMinSize
),
5526 std::max(mVertResizeMargin
- mNonClientOffset
.bottom
,
5527 kResizableBorderMinSize
),
5528 std::max(mHorResizeMargin
- mNonClientOffset
.left
,
5529 kResizableBorderMinSize
));
5531 bool allowContentOverride
= mSizeMode
== nsSizeMode_Maximized
||
5532 (mx
>= winRect
.left
+ nonClientSize
.left
&&
5533 mx
<= winRect
.right
- nonClientSize
.right
&&
5534 my
>= winRect
.top
+ nonClientSize
.top
&&
5535 my
<= winRect
.bottom
- nonClientSize
.bottom
);
5537 // The border size. If there is no content under mouse cursor, the border
5538 // size should be larger than the values in system settings. Otherwise,
5539 // contents under the mouse cursor should be able to override the behavior.
5540 // E.g., user must expect that Firefox button always opens the popup menu
5541 // even when the user clicks on the above edge of it.
5542 nsIntMargin
borderSize(std::max(nonClientSize
.top
, mVertResizeMargin
),
5543 std::max(nonClientSize
.right
, mHorResizeMargin
),
5544 std::max(nonClientSize
.bottom
, mVertResizeMargin
),
5545 std::max(nonClientSize
.left
, mHorResizeMargin
));
5548 bool bottom
= false;
5552 if (my
>= winRect
.top
&& my
< winRect
.top
+ borderSize
.top
) {
5554 } else if (my
<= winRect
.bottom
&& my
> winRect
.bottom
- borderSize
.bottom
) {
5558 // (the 2x case here doubles the resize area for corners)
5559 int multiplier
= (top
|| bottom
) ? 2 : 1;
5560 if (mx
>= winRect
.left
&&
5561 mx
< winRect
.left
+ (multiplier
* borderSize
.left
)) {
5563 } else if (mx
<= winRect
.right
&&
5564 mx
> winRect
.right
- (multiplier
* borderSize
.right
)) {
5572 testResult
= HTTOPLEFT
;
5574 testResult
= HTTOPRIGHT
;
5575 } else if (bottom
) {
5576 testResult
= HTBOTTOM
;
5578 testResult
= HTBOTTOMLEFT
;
5580 testResult
= HTBOTTOMRIGHT
;
5583 testResult
= HTLEFT
;
5585 testResult
= HTRIGHT
;
5589 testResult
= HTCAPTION
;
5590 else if (bottom
|| left
|| right
)
5591 testResult
= HTBORDER
;
5594 if (!sIsInMouseCapture
&& allowContentOverride
) {
5595 LPARAM lParam
= MAKELPARAM(mx
, my
);
5596 LPARAM lParamClient
= lParamToClient(lParam
);
5597 bool result
= DispatchMouseEvent(NS_MOUSE_MOZHITTEST
, 0, lParamClient
,
5598 false, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
5600 // The mouse is over a blank area
5601 testResult
= testResult
== HTCLIENT
? HTCAPTION
: testResult
;
5604 // There's content over the mouse pointer. Set HTCLIENT
5605 // to possibly override a resizer border.
5606 testResult
= HTCLIENT
;
5613 void nsWindow::PostSleepWakeNotification(const bool aIsSleepMode
)
5615 if (aIsSleepMode
== gIsSleepMode
)
5618 gIsSleepMode
= aIsSleepMode
;
5620 nsCOMPtr
<nsIObserverService
> observerService
=
5621 mozilla::services::GetObserverService();
5622 if (observerService
)
5623 observerService
->NotifyObservers(nullptr,
5624 aIsSleepMode
? NS_WIDGET_SLEEP_OBSERVER_TOPIC
:
5625 NS_WIDGET_WAKE_OBSERVER_TOPIC
, nullptr);
5628 // RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
5629 // message handler. If there is no WM_(SYS)CHAR message for it, this
5630 // method does nothing.
5631 // NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
5632 // called in message loop. So, WM_(SYS)KEYDOWN message should have
5633 // WM_(SYS)CHAR message in the queue if the keydown event causes character
5637 void nsWindow::RemoveNextCharMessage(HWND aWnd
)
5640 if (WinUtils::PeekMessage(&msg
, aWnd
, WM_KEYFIRST
, WM_KEYLAST
,
5641 PM_NOREMOVE
| PM_NOYIELD
) &&
5642 (msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
)) {
5643 WinUtils::GetMessage(&msg
, aWnd
, msg
.message
, msg
.message
);
5647 LRESULT
nsWindow::ProcessCharMessage(const MSG
&aMsg
, bool *aEventDispatched
)
5649 NS_PRECONDITION(aMsg
.message
== WM_CHAR
|| aMsg
.message
== WM_SYSCHAR
,
5650 "message is not keydown event");
5651 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5652 ("%s charCode=%d scanCode=%d\n",
5653 aMsg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
5654 aMsg
.wParam
, HIWORD(aMsg
.lParam
) & 0xFF));
5656 // These must be checked here too as a lone WM_CHAR could be received
5657 // if a child window didn't handle it (for example Alt+Space in a content window)
5658 ModifierKeyState modKeyState
;
5659 NativeKey
nativeKey(gKbdLayout
, this, aMsg
);
5660 gKbdLayout
.InitNativeKey(nativeKey
, modKeyState
);
5661 return OnChar(aMsg
, nativeKey
, modKeyState
, aEventDispatched
);
5664 LRESULT
nsWindow::ProcessKeyUpMessage(const MSG
&aMsg
, bool *aEventDispatched
)
5666 NS_PRECONDITION(aMsg
.message
== WM_KEYUP
|| aMsg
.message
== WM_SYSKEYUP
,
5667 "message is not keydown event");
5668 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5669 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
5670 "WM_SYSKEYUP" : "WM_KEYUP", aMsg
.wParam
));
5672 ModifierKeyState modKeyState
;
5674 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5675 // scan code. However, this breaks Alt+Num pad input.
5676 // MSDN states the following:
5677 // Typically, ToAscii performs the translation based on the
5678 // virtual-key code. In some cases, however, bit 15 of the
5679 // uScanCode parameter may be used to distinguish between a key
5680 // press and a key release. The scan code is used for
5681 // translating ALT+number key combinations.
5683 // ignore [shift+]alt+space so the OS can handle it
5684 if (modKeyState
.IsAlt() && !modKeyState
.IsControl() &&
5685 IS_VK_DOWN(NS_VK_SPACE
)) {
5689 if (!IMEHandler::IsComposingOn(this)) {
5690 return OnKeyUp(aMsg
, modKeyState
, aEventDispatched
);
5696 LRESULT
nsWindow::ProcessKeyDownMessage(const MSG
&aMsg
,
5697 bool *aEventDispatched
)
5699 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5700 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
5701 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg
.wParam
));
5702 NS_PRECONDITION(aMsg
.message
== WM_KEYDOWN
|| aMsg
.message
== WM_SYSKEYDOWN
,
5703 "message is not keydown event");
5705 // If this method doesn't call OnKeyDown(), this method must clean up the
5706 // redirected message information itself. For more information, see above
5707 // comment of AutoForgetRedirectedKeyDownMessage struct definition in
5709 AutoForgetRedirectedKeyDownMessage
forgetRedirectedMessage(this, aMsg
);
5711 ModifierKeyState modKeyState
;
5713 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
5714 // scan code. However, this breaks Alt+Num pad input.
5715 // MSDN states the following:
5716 // Typically, ToAscii performs the translation based on the
5717 // virtual-key code. In some cases, however, bit 15 of the
5718 // uScanCode parameter may be used to distinguish between a key
5719 // press and a key release. The scan code is used for
5720 // translating ALT+number key combinations.
5722 // ignore [shift+]alt+space so the OS can handle it
5723 if (modKeyState
.IsAlt() && !modKeyState
.IsControl() &&
5724 IS_VK_DOWN(NS_VK_SPACE
))
5728 if (!IMEHandler::IsComposingOn(this)) {
5729 result
= OnKeyDown(aMsg
, modKeyState
, aEventDispatched
, nullptr);
5730 // OnKeyDown cleaned up the redirected message information itself, so,
5731 // we should do nothing.
5732 forgetRedirectedMessage
.mCancel
= true;
5735 if (aMsg
.wParam
== VK_MENU
||
5736 (aMsg
.wParam
== VK_F10
&& !modKeyState
.IsShift())) {
5737 // We need to let Windows handle this keypress,
5738 // by returning false, if there's a native menu
5739 // bar somewhere in our containing window hierarchy.
5740 // Otherwise we handle the keypress and don't pass
5741 // it on to Windows, by returning true.
5742 bool hasNativeMenu
= false;
5745 if (::GetMenu(hWnd
)) {
5746 hasNativeMenu
= true;
5749 hWnd
= ::GetParent(hWnd
);
5751 result
= !hasNativeMenu
;
5758 nsWindow::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout
,
5759 int32_t aNativeKeyCode
,
5760 uint32_t aModifierFlags
,
5761 const nsAString
& aCharacters
,
5762 const nsAString
& aUnmodifiedCharacters
)
5764 UINT keyboardLayoutListCount
= ::GetKeyboardLayoutList(0, NULL
);
5765 NS_ASSERTION(keyboardLayoutListCount
> 0,
5766 "One keyboard layout must be installed at least");
5767 HKL keyboardLayoutListBuff
[50];
5768 HKL
* keyboardLayoutList
=
5769 keyboardLayoutListCount
< 50 ? keyboardLayoutListBuff
:
5770 new HKL
[keyboardLayoutListCount
];
5771 keyboardLayoutListCount
=
5772 ::GetKeyboardLayoutList(keyboardLayoutListCount
, keyboardLayoutList
);
5773 NS_ASSERTION(keyboardLayoutListCount
> 0,
5774 "Failed to get all keyboard layouts installed on the system");
5776 nsPrintfCString
layoutName("%08x", aNativeKeyboardLayout
);
5777 HKL loadedLayout
= LoadKeyboardLayoutA(layoutName
.get(), KLF_NOTELLSHELL
);
5778 if (loadedLayout
== NULL
) {
5779 if (keyboardLayoutListBuff
!= keyboardLayoutList
) {
5780 delete [] keyboardLayoutList
;
5782 return NS_ERROR_NOT_AVAILABLE
;
5785 // Setup clean key state and load desired layout
5786 BYTE originalKbdState
[256];
5787 ::GetKeyboardState(originalKbdState
);
5789 memset(kbdState
, 0, sizeof(kbdState
));
5790 // This changes the state of the keyboard for the current thread only,
5791 // and we'll restore it soon, so this should be OK.
5792 ::SetKeyboardState(kbdState
);
5793 HKL oldLayout
= gKbdLayout
.GetLayout();
5794 gKbdLayout
.LoadLayout(loadedLayout
);
5796 uint8_t argumentKeySpecific
= 0;
5797 switch (aNativeKeyCode
) {
5799 aModifierFlags
&= ~(nsIWidget::SHIFT_L
| nsIWidget::SHIFT_R
);
5800 argumentKeySpecific
= VK_LSHIFT
;
5803 aModifierFlags
&= ~nsIWidget::SHIFT_L
;
5804 argumentKeySpecific
= aNativeKeyCode
;
5805 aNativeKeyCode
= VK_SHIFT
;
5808 aModifierFlags
&= ~nsIWidget::SHIFT_R
;
5809 argumentKeySpecific
= aNativeKeyCode
;
5810 aNativeKeyCode
= VK_SHIFT
;
5813 aModifierFlags
&= ~(nsIWidget::CTRL_L
| nsIWidget::CTRL_R
);
5814 argumentKeySpecific
= VK_LCONTROL
;
5817 aModifierFlags
&= ~nsIWidget::CTRL_L
;
5818 argumentKeySpecific
= aNativeKeyCode
;
5819 aNativeKeyCode
= VK_CONTROL
;
5822 aModifierFlags
&= ~nsIWidget::CTRL_R
;
5823 argumentKeySpecific
= aNativeKeyCode
;
5824 aNativeKeyCode
= VK_CONTROL
;
5827 aModifierFlags
&= ~(nsIWidget::ALT_L
| nsIWidget::ALT_R
);
5828 argumentKeySpecific
= VK_LMENU
;
5831 aModifierFlags
&= ~nsIWidget::ALT_L
;
5832 argumentKeySpecific
= aNativeKeyCode
;
5833 aNativeKeyCode
= VK_MENU
;
5836 aModifierFlags
&= ~nsIWidget::ALT_R
;
5837 argumentKeySpecific
= aNativeKeyCode
;
5838 aNativeKeyCode
= VK_MENU
;
5841 aModifierFlags
&= ~nsIWidget::CAPS_LOCK
;
5842 argumentKeySpecific
= VK_CAPITAL
;
5845 aModifierFlags
&= ~nsIWidget::NUM_LOCK
;
5846 argumentKeySpecific
= VK_NUMLOCK
;
5850 nsAutoTArray
<KeyPair
,10> keySequence
;
5851 SetupKeyModifiersSequence(&keySequence
, aModifierFlags
);
5852 NS_ASSERTION(aNativeKeyCode
>= 0 && aNativeKeyCode
< 256,
5853 "Native VK key code out of range");
5854 keySequence
.AppendElement(KeyPair(aNativeKeyCode
, argumentKeySpecific
));
5856 // Simulate the pressing of each modifier key and then the real key
5857 for (uint32_t i
= 0; i
< keySequence
.Length(); ++i
) {
5858 uint8_t key
= keySequence
[i
].mGeneral
;
5859 uint8_t keySpecific
= keySequence
[i
].mSpecific
;
5860 kbdState
[key
] = 0x81; // key is down and toggled on if appropriate
5862 kbdState
[keySpecific
] = 0x81;
5864 ::SetKeyboardState(kbdState
);
5865 ModifierKeyState modKeyState
;
5866 UINT scanCode
= ::MapVirtualKeyEx(argumentKeySpecific
?
5867 argumentKeySpecific
: aNativeKeyCode
,
5868 MAPVK_VK_TO_VSC
, gKbdLayout
.GetLayout());
5869 LPARAM lParam
= static_cast<LPARAM
>(scanCode
<< 16);
5870 // Add extended key flag to the lParam for right control key and right alt
5872 if (keySpecific
== VK_RCONTROL
|| keySpecific
== VK_RMENU
) {
5873 lParam
|= 0x1000000;
5875 MSG msg
= WinUtils::InitMSG(WM_KEYDOWN
, key
, lParam
);
5876 if (i
== keySequence
.Length() - 1) {
5877 bool makeDeadCharMessage
=
5878 gKbdLayout
.IsDeadKey(key
, modKeyState
) && aCharacters
.IsEmpty();
5879 nsAutoString
chars(aCharacters
);
5880 if (makeDeadCharMessage
) {
5881 UniCharsAndModifiers deadChars
=
5882 gKbdLayout
.GetUniCharsAndModifiers(key
, modKeyState
);
5883 chars
= deadChars
.ToString();
5884 NS_ASSERTION(chars
.Length() == 1,
5885 "Dead char must be only one character");
5887 if (chars
.IsEmpty()) {
5888 OnKeyDown(msg
, modKeyState
, nullptr, nullptr);
5890 nsFakeCharMessage fakeMsg
= { chars
.CharAt(0), scanCode
,
5891 makeDeadCharMessage
};
5892 OnKeyDown(msg
, modKeyState
, nullptr, &fakeMsg
);
5893 for (uint32_t j
= 1; j
< chars
.Length(); j
++) {
5894 nsFakeCharMessage fakeMsg
= { chars
.CharAt(j
), scanCode
, false };
5895 MSG msg
= fakeMsg
.GetCharMessage(mWnd
);
5896 NativeKey
nativeKey(gKbdLayout
, this, msg
);
5897 OnChar(msg
, nativeKey
, modKeyState
, nullptr);
5901 OnKeyDown(msg
, modKeyState
, nullptr, nullptr);
5904 for (uint32_t i
= keySequence
.Length(); i
> 0; --i
) {
5905 uint8_t key
= keySequence
[i
- 1].mGeneral
;
5906 uint8_t keySpecific
= keySequence
[i
- 1].mSpecific
;
5907 kbdState
[key
] = 0; // key is up and toggled off if appropriate
5909 kbdState
[keySpecific
] = 0;
5911 ::SetKeyboardState(kbdState
);
5912 ModifierKeyState modKeyState
;
5913 UINT scanCode
= ::MapVirtualKeyEx(argumentKeySpecific
?
5914 argumentKeySpecific
: aNativeKeyCode
,
5915 MAPVK_VK_TO_VSC
, gKbdLayout
.GetLayout());
5916 LPARAM lParam
= static_cast<LPARAM
>(scanCode
<< 16);
5917 // Add extended key flag to the lParam for right control key and right alt
5919 if (keySpecific
== VK_RCONTROL
|| keySpecific
== VK_RMENU
) {
5920 lParam
|= 0x1000000;
5922 MSG msg
= WinUtils::InitMSG(WM_KEYUP
, key
, lParam
);
5923 OnKeyUp(msg
, modKeyState
, nullptr);
5926 // Restore old key state and layout
5927 ::SetKeyboardState(originalKbdState
);
5928 gKbdLayout
.LoadLayout(oldLayout
, true);
5930 // Don't unload the layout if it's installed actually.
5931 for (uint32_t i
= 0; i
< keyboardLayoutListCount
; i
++) {
5932 if (keyboardLayoutList
[i
] == loadedLayout
) {
5937 if (keyboardLayoutListBuff
!= keyboardLayoutList
) {
5938 delete [] keyboardLayoutList
;
5941 ::UnloadKeyboardLayout(loadedLayout
);
5947 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint
,
5948 uint32_t aNativeMessage
,
5949 uint32_t aModifierFlags
)
5951 ::SetCursorPos(aPoint
.x
, aPoint
.y
);
5954 memset(&input
, 0, sizeof(input
));
5956 input
.type
= INPUT_MOUSE
;
5957 input
.mi
.dwFlags
= aNativeMessage
;
5958 ::SendInput(1, &input
, sizeof(INPUT
));
5964 nsWindow::SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint
,
5965 uint32_t aNativeMessage
,
5969 uint32_t aModifierFlags
,
5970 uint32_t aAdditionalFlags
)
5972 return MouseScrollHandler::SynthesizeNativeMouseScrollEvent(
5973 this, aPoint
, aNativeMessage
,
5974 (aNativeMessage
== WM_MOUSEWHEEL
|| aNativeMessage
== WM_VSCROLL
) ?
5975 static_cast<int32_t>(aDeltaY
) : static_cast<int32_t>(aDeltaX
),
5976 aModifierFlags
, aAdditionalFlags
);
5979 /**************************************************************
5981 * SECTION: OnXXX message handlers
5983 * For message handlers that need to be broken out or
5984 * implemented in specific platform code.
5986 **************************************************************/
5988 BOOL
nsWindow::OnInputLangChange(HKL aHKL
)
5991 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("OnInputLanguageChange\n"));
5993 gKbdLayout
.LoadLayout(aHKL
);
5994 return false; // always pass to child window
5997 void nsWindow::OnWindowPosChanged(WINDOWPOS
*wp
, bool& result
)
6002 #ifdef WINSTATE_DEBUG_OUTPUT
6003 if (mWnd
== WinUtils::GetTopLevelHWND(mWnd
)) {
6004 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("*** OnWindowPosChanged: [ top] "));
6006 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("*** OnWindowPosChanged: [child] "));
6008 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("WINDOWPOS flags:"));
6009 if (wp
->flags
& SWP_FRAMECHANGED
) {
6010 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("SWP_FRAMECHANGED "));
6012 if (wp
->flags
& SWP_SHOWWINDOW
) {
6013 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("SWP_SHOWWINDOW "));
6015 if (wp
->flags
& SWP_NOSIZE
) {
6016 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("SWP_NOSIZE "));
6018 if (wp
->flags
& SWP_HIDEWINDOW
) {
6019 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("SWP_HIDEWINDOW "));
6021 if (wp
->flags
& SWP_NOZORDER
) {
6022 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("SWP_NOZORDER "));
6024 if (wp
->flags
& SWP_NOACTIVATE
) {
6025 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("SWP_NOACTIVATE "));
6027 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("\n"));
6030 // Handle window size mode changes
6031 if (wp
->flags
& SWP_FRAMECHANGED
&& mSizeMode
!= nsSizeMode_Fullscreen
) {
6033 // Bug 566135 - Windows theme code calls show window on SW_SHOWMINIMIZED
6034 // windows when fullscreen games disable desktop composition. If we're
6035 // minimized and not being activated, ignore the event and let windows
6037 if (mSizeMode
== nsSizeMode_Minimized
&& (wp
->flags
& SWP_NOACTIVATE
))
6041 pl
.length
= sizeof(pl
);
6042 ::GetWindowPlacement(mWnd
, &pl
);
6044 // Windows has just changed the size mode of this window. The call to
6045 // SizeModeChanged will trigger a call into SetSizeMode where we will
6046 // set the min/max window state again or for nsSizeMode_Normal, call
6047 // SetWindow with a parameter of SW_RESTORE. There's no need however as
6048 // this window's mode has already changed. Updating mSizeMode here
6049 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
6050 // to window docking. (bug 489258)
6051 if (pl
.showCmd
== SW_SHOWMAXIMIZED
)
6052 mSizeMode
= (mFullscreenMode
? nsSizeMode_Fullscreen
: nsSizeMode_Maximized
);
6053 else if (pl
.showCmd
== SW_SHOWMINIMIZED
)
6054 mSizeMode
= nsSizeMode_Minimized
;
6055 else if (mFullscreenMode
)
6056 mSizeMode
= nsSizeMode_Fullscreen
;
6058 mSizeMode
= nsSizeMode_Normal
;
6060 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
6061 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
6062 // prevents the working set from being trimmed but keeps the window active.
6063 // After the window is minimized, we need to do some touch up work on the
6064 // active window. (bugs 76831 & 499816)
6065 if (!sTrimOnMinimize
&& nsSizeMode_Minimized
== mSizeMode
)
6066 ActivateOtherWindowHelper(mWnd
);
6068 #ifdef WINSTATE_DEBUG_OUTPUT
6069 switch (mSizeMode
) {
6070 case nsSizeMode_Normal
:
6071 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6072 ("*** mSizeMode: nsSizeMode_Normal\n"));
6074 case nsSizeMode_Minimized
:
6075 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6076 ("*** mSizeMode: nsSizeMode_Minimized\n"));
6078 case nsSizeMode_Maximized
:
6079 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6080 ("*** mSizeMode: nsSizeMode_Maximized\n");
6083 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("*** mSizeMode: ??????\n");
6088 if (mWidgetListener
)
6089 mWidgetListener
->SizeModeChanged(mSizeMode
);
6091 // If window was restored, window activation was bypassed during the
6092 // SetSizeMode call originating from OnWindowPosChanging to avoid saving
6093 // pre-restore attributes. Force activation now to get correct attributes.
6094 if (mLastSizeMode
!= nsSizeMode_Normal
&& mSizeMode
== nsSizeMode_Normal
)
6095 DispatchFocusToTopLevelWindow(true);
6097 // Skip window size change events below on minimization.
6098 if (mSizeMode
== nsSizeMode_Minimized
)
6102 // Handle window size changes
6103 if (!(wp
->flags
& SWP_NOSIZE
)) {
6105 int32_t newWidth
, newHeight
;
6107 ::GetWindowRect(mWnd
, &r
);
6109 newWidth
= r
.right
- r
.left
;
6110 newHeight
= r
.bottom
- r
.top
;
6111 nsIntRect
rect(wp
->x
, wp
->y
, newWidth
, newHeight
);
6114 if (eTransparencyTransparent
== mTransparencyMode
)
6115 ResizeTranslucentWindow(newWidth
, newHeight
);
6118 if (newWidth
> mLastSize
.width
)
6123 drect
.left
= wp
->x
+ mLastSize
.width
;
6125 drect
.right
= drect
.left
+ (newWidth
- mLastSize
.width
);
6126 drect
.bottom
= drect
.top
+ newHeight
;
6128 ::RedrawWindow(mWnd
, &drect
, NULL
,
6131 RDW_NOINTERNALPAINT
|
6135 if (newHeight
> mLastSize
.height
)
6141 drect
.top
= wp
->y
+ mLastSize
.height
;
6142 drect
.right
= drect
.left
+ newWidth
;
6143 drect
.bottom
= drect
.top
+ (newHeight
- mLastSize
.height
);
6145 ::RedrawWindow(mWnd
, &drect
, NULL
,
6148 RDW_NOINTERNALPAINT
|
6153 mBounds
.width
= newWidth
;
6154 mBounds
.height
= newHeight
;
6155 mLastSize
.width
= newWidth
;
6156 mLastSize
.height
= newHeight
;
6158 #ifdef WINSTATE_DEBUG_OUTPUT
6159 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6160 ("*** Resize window: %d x %d x %d x %d\n", wp
->x
, wp
->y
,
6161 newWidth
, newHeight
));
6164 // If a maximized window is resized, recalculate the non-client margins.
6165 if (mSizeMode
== nsSizeMode_Maximized
) {
6166 if (UpdateNonClientMargins(nsSizeMode_Maximized
, true)) {
6167 // gecko resize event already sent by UpdateNonClientMargins.
6173 // Recalculate the width and height based on the client area for gecko events.
6174 if (::GetClientRect(mWnd
, &r
)) {
6175 rect
.width
= r
.right
- r
.left
;
6176 rect
.height
= r
.bottom
- r
.top
;
6179 // Send a gecko resize event
6180 result
= OnResize(rect
);
6185 void nsWindow::ActivateOtherWindowHelper(HWND aWnd
)
6187 // Find the next window that is enabled, visible, and not minimized.
6188 HWND hwndBelow
= ::GetNextWindow(aWnd
, GW_HWNDNEXT
);
6189 while (hwndBelow
&& (!::IsWindowEnabled(hwndBelow
) || !::IsWindowVisible(hwndBelow
) ||
6190 ::IsIconic(hwndBelow
))) {
6191 hwndBelow
= ::GetNextWindow(hwndBelow
, GW_HWNDNEXT
);
6194 // Push ourselves to the bottom of the stack, then activate the
6196 ::SetWindowPos(aWnd
, HWND_BOTTOM
, 0, 0, 0, 0,
6197 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
);
6199 ::SetForegroundWindow(hwndBelow
);
6201 // Play the minimize sound while we're here, since that is also
6202 // forgotten when we use SW_SHOWMINIMIZED.
6203 nsCOMPtr
<nsISound
> sound(do_CreateInstance("@mozilla.org/sound;1"));
6205 sound
->PlaySystemSound(NS_LITERAL_STRING("Minimize"));
6209 void nsWindow::OnWindowPosChanging(LPWINDOWPOS
& info
)
6211 // Update non-client margins if the frame size is changing, and let the
6212 // browser know we are changing size modes, so alternative css can kick in.
6213 // If we're going into fullscreen mode, ignore this, since it'll reset
6214 // margins to normal mode.
6215 if ((info
->flags
& SWP_FRAMECHANGED
&& !(info
->flags
& SWP_NOSIZE
)) &&
6216 mSizeMode
!= nsSizeMode_Fullscreen
) {
6218 pl
.length
= sizeof(pl
);
6219 ::GetWindowPlacement(mWnd
, &pl
);
6220 nsSizeMode sizeMode
;
6221 if (pl
.showCmd
== SW_SHOWMAXIMIZED
)
6222 sizeMode
= (mFullscreenMode
? nsSizeMode_Fullscreen
: nsSizeMode_Maximized
);
6223 else if (pl
.showCmd
== SW_SHOWMINIMIZED
)
6224 sizeMode
= nsSizeMode_Minimized
;
6225 else if (mFullscreenMode
)
6226 sizeMode
= nsSizeMode_Fullscreen
;
6228 sizeMode
= nsSizeMode_Normal
;
6230 if (mWidgetListener
)
6231 mWidgetListener
->SizeModeChanged(sizeMode
);
6233 UpdateNonClientMargins(sizeMode
, false);
6236 // enforce local z-order rules
6237 if (!(info
->flags
& SWP_NOZORDER
)) {
6238 HWND hwndAfter
= info
->hwndInsertAfter
;
6240 nsWindow
*aboveWindow
= 0;
6241 nsWindowZ placement
;
6243 if (hwndAfter
== HWND_BOTTOM
)
6244 placement
= nsWindowZBottom
;
6245 else if (hwndAfter
== HWND_TOP
|| hwndAfter
== HWND_TOPMOST
|| hwndAfter
== HWND_NOTOPMOST
)
6246 placement
= nsWindowZTop
;
6248 placement
= nsWindowZRelative
;
6249 aboveWindow
= WinUtils::GetNSWindowPtr(hwndAfter
);
6252 if (mWidgetListener
) {
6253 nsCOMPtr
<nsIWidget
> actualBelow
= nullptr;
6254 if (mWidgetListener
->ZLevelChanged(false, &placement
,
6255 aboveWindow
, getter_AddRefs(actualBelow
))) {
6256 if (placement
== nsWindowZBottom
)
6257 info
->hwndInsertAfter
= HWND_BOTTOM
;
6258 else if (placement
== nsWindowZTop
)
6259 info
->hwndInsertAfter
= HWND_TOP
;
6261 info
->hwndInsertAfter
= (HWND
)actualBelow
->GetNativeData(NS_NATIVE_WINDOW
);
6266 // prevent rude external programs from making hidden window visible
6267 if (mWindowType
== eWindowType_invisible
)
6268 info
->flags
&= ~SWP_SHOWWINDOW
;
6271 void nsWindow::UserActivity()
6273 // Check if we have the idle service, if not we try to get it.
6274 if (!mIdleService
) {
6275 mIdleService
= do_GetService("@mozilla.org/widget/idleservice;1");
6278 // Check that we now have the idle service.
6280 mIdleService
->ResetIdleTimeOut(0);
6284 bool nsWindow::OnTouch(WPARAM wParam
, LPARAM lParam
)
6286 uint32_t cInputs
= LOWORD(wParam
);
6287 PTOUCHINPUT pInputs
= new TOUCHINPUT
[cInputs
];
6289 if (mGesture
.GetTouchInputInfo((HTOUCHINPUT
)lParam
, cInputs
, pInputs
)) {
6290 nsTouchEvent
* touchEventToSend
= nullptr;
6291 nsTouchEvent
* touchEndEventToSend
= nullptr;
6292 nsEventStatus status
;
6294 // Walk across the touch point array processing each contact point
6295 for (uint32_t i
= 0; i
< cInputs
; i
++) {
6298 if (pInputs
[i
].dwFlags
& (TOUCHEVENTF_DOWN
| TOUCHEVENTF_MOVE
)) {
6299 // Create a standard touch event to send
6300 if (!touchEventToSend
) {
6301 touchEventToSend
= new nsTouchEvent(true, NS_TOUCH_MOVE
, this);
6302 touchEventToSend
->time
= ::GetMessageTime();
6303 ModifierKeyState modifierKeyState
;
6304 modifierKeyState
.InitInputEvent(*touchEventToSend
);
6307 // Pres shell expects this event to be a NS_TOUCH_START if new contact
6308 // points have been added since the last event sent.
6309 if (pInputs
[i
].dwFlags
& TOUCHEVENTF_DOWN
) {
6310 touchEventToSend
->message
= msg
= NS_TOUCH_START
;
6312 msg
= NS_TOUCH_MOVE
;
6314 } else if (pInputs
[i
].dwFlags
& TOUCHEVENTF_UP
) {
6315 // Pres shell expects removed contacts points to be delivered in a
6316 // separate NS_TOUCH_END event containing only the contact points
6317 // that were removed.
6318 if (!touchEndEventToSend
) {
6319 touchEndEventToSend
= new nsTouchEvent(true, NS_TOUCH_END
, this);
6320 touchEndEventToSend
->time
= ::GetMessageTime();
6321 ModifierKeyState modifierKeyState
;
6322 modifierKeyState
.InitInputEvent(*touchEndEventToSend
);
6326 // Filter out spurious Windows events we don't understand, like palm
6331 // Setup the touch point we'll append to the touch event array
6332 nsPointWin touchPoint
;
6333 touchPoint
.x
= TOUCH_COORD_TO_PIXEL(pInputs
[i
].x
);
6334 touchPoint
.y
= TOUCH_COORD_TO_PIXEL(pInputs
[i
].y
);
6335 touchPoint
.ScreenToClient(mWnd
);
6336 nsCOMPtr
<nsIDOMTouch
> touch
=
6337 new Touch(pInputs
[i
].dwID
,
6339 /* radius, if known */
6340 pInputs
[i
].dwFlags
& TOUCHINPUTMASKF_CONTACTAREA
?
6342 TOUCH_COORD_TO_PIXEL(pInputs
[i
].cxContact
) / 2,
6343 TOUCH_COORD_TO_PIXEL(pInputs
[i
].cyContact
) / 2) :
6345 /* rotation angle and force */
6348 // Append to the appropriate event
6349 if (msg
== NS_TOUCH_START
|| msg
== NS_TOUCH_MOVE
) {
6350 touchEventToSend
->touches
.AppendElement(touch
);
6352 touchEndEventToSend
->touches
.AppendElement(touch
);
6356 // Dispatch touch start and move event if we have one.
6357 if (touchEventToSend
) {
6358 DispatchEvent(touchEventToSend
, status
);
6359 delete touchEventToSend
;
6362 // Dispatch touch end event if we have one.
6363 if (touchEndEventToSend
) {
6364 DispatchEvent(touchEndEventToSend
, status
);
6365 delete touchEndEventToSend
;
6370 mGesture
.CloseTouchInputHandle((HTOUCHINPUT
)lParam
);
6374 static int32_t RoundDown(double aDouble
)
6376 return aDouble
> 0 ? static_cast<int32_t>(floor(aDouble
)) :
6377 static_cast<int32_t>(ceil(aDouble
));
6380 // Gesture event processing. Handles WM_GESTURE events.
6381 bool nsWindow::OnGesture(WPARAM wParam
, LPARAM lParam
)
6383 // Treatment for pan events which translate into scroll events:
6384 if (mGesture
.IsPanEvent(lParam
)) {
6385 if ( !mGesture
.ProcessPanMessage(mWnd
, wParam
, lParam
) )
6386 return false; // ignore
6388 nsEventStatus status
;
6390 WheelEvent
wheelEvent(true, NS_WHEEL_WHEEL
, this);
6392 ModifierKeyState modifierKeyState
;
6393 modifierKeyState
.InitInputEvent(wheelEvent
);
6395 wheelEvent
.button
= 0;
6396 wheelEvent
.time
= ::GetMessageTime();
6397 wheelEvent
.inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
6399 bool endFeedback
= true;
6401 if (mGesture
.PanDeltaToPixelScroll(wheelEvent
)) {
6402 DispatchEvent(&wheelEvent
, status
);
6405 if (mDisplayPanFeedback
) {
6406 mGesture
.UpdatePanFeedbackX(mWnd
,
6407 DeprecatedAbs(RoundDown(wheelEvent
.overflowDeltaX
)),
6409 mGesture
.UpdatePanFeedbackY(mWnd
,
6410 DeprecatedAbs(RoundDown(wheelEvent
.overflowDeltaY
)),
6412 mGesture
.PanFeedbackFinalize(mWnd
, endFeedback
);
6415 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
6420 // Other gestures translate into simple gesture events:
6421 nsSimpleGestureEvent
event(true, 0, this, 0, 0.0);
6422 if ( !mGesture
.ProcessGestureMessage(mWnd
, wParam
, lParam
, event
) ) {
6423 return false; // fall through to DefWndProc
6426 // Polish up and send off the new event
6427 ModifierKeyState modifierKeyState
;
6428 modifierKeyState
.InitInputEvent(event
);
6430 event
.time
= ::GetMessageTime();
6431 event
.inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
6433 nsEventStatus status
;
6434 DispatchEvent(&event
, status
);
6435 if (status
== nsEventStatus_eIgnore
) {
6436 return false; // Ignored, fall through
6439 // Only close this if we process and return true.
6440 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
6442 return true; // Handled
6446 bool nsWindow::IsRedirectedKeyDownMessage(const MSG
&aMsg
)
6448 return (aMsg
.message
== WM_KEYDOWN
|| aMsg
.message
== WM_SYSKEYDOWN
) &&
6449 (sRedirectedKeyDown
.message
== aMsg
.message
&&
6450 WinUtils::GetScanCode(sRedirectedKeyDown
.lParam
) ==
6451 WinUtils::GetScanCode(aMsg
.lParam
));
6455 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6456 * WM_CHAR messages for processing. During testing we don't want to
6457 * mess with the real message queue. Instead we pass a
6458 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6459 * that as if it was in the message queue, and refrain from actually
6460 * looking at or touching the message queue.
6462 LRESULT
nsWindow::OnKeyDown(const MSG
&aMsg
,
6463 const ModifierKeyState
&aModKeyState
,
6464 bool *aEventDispatched
,
6465 nsFakeCharMessage
* aFakeCharMessage
)
6467 NativeKey
nativeKey(gKbdLayout
, this, aMsg
);
6468 gKbdLayout
.InitNativeKey(nativeKey
, aModKeyState
);
6469 UniCharsAndModifiers inputtingChars
=
6470 nativeKey
.GetCommittedCharsAndModifiers();
6471 uint32_t DOMKeyCode
= nativeKey
.GetDOMKeyCode();
6474 //PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("In OnKeyDown virt: %d\n", DOMKeyCode));
6477 static bool sRedirectedKeyDownEventPreventedDefault
= false;
6479 if (aFakeCharMessage
|| !IsRedirectedKeyDownMessage(aMsg
)) {
6480 bool isIMEEnabled
= IMEHandler::IsIMEEnabled(mInputContext
);
6481 nsKeyEvent
keydownEvent(true, NS_KEY_DOWN
, this);
6482 keydownEvent
.keyCode
= DOMKeyCode
;
6483 InitKeyEvent(keydownEvent
, nativeKey
, aModKeyState
);
6484 noDefault
= DispatchKeyEvent(keydownEvent
, &aMsg
);
6485 if (aEventDispatched
) {
6486 *aEventDispatched
= true;
6489 // If IMC wasn't associated to the window but is associated it now (i.e.,
6490 // focus is moved from a non-editable editor to an editor by keydown
6491 // event handler), WM_CHAR and WM_SYSCHAR shouldn't cause first character
6492 // inputting if IME is opened. But then, we should redirect the native
6493 // keydown message to IME.
6494 // However, note that if focus has been already moved to another
6495 // application, we shouldn't redirect the message to it because the keydown
6496 // message is processed by us, so, nobody shouldn't process it.
6497 HWND focusedWnd
= ::GetFocus();
6498 if (!noDefault
&& !aFakeCharMessage
&& focusedWnd
&& !PluginHasFocus() &&
6499 !isIMEEnabled
&& IMEHandler::IsIMEEnabled(mInputContext
)) {
6500 RemoveNextCharMessage(focusedWnd
);
6503 keyinput
.type
= INPUT_KEYBOARD
;
6504 keyinput
.ki
.wVk
= aMsg
.wParam
;
6505 keyinput
.ki
.wScan
= WinUtils::GetScanCode(aMsg
.lParam
);
6506 keyinput
.ki
.dwFlags
= KEYEVENTF_SCANCODE
;
6507 if (WinUtils::IsExtendedScanCode(aMsg
.lParam
)) {
6508 keyinput
.ki
.dwFlags
|= KEYEVENTF_EXTENDEDKEY
;
6510 keyinput
.ki
.time
= 0;
6511 keyinput
.ki
.dwExtraInfo
= 0;
6513 sRedirectedKeyDownEventPreventedDefault
= noDefault
;
6514 sRedirectedKeyDown
= aMsg
;
6516 ::SendInput(1, &keyinput
, sizeof(keyinput
));
6518 // Return here. We shouldn't dispatch keypress event for this WM_KEYDOWN.
6519 // If it's needed, it will be dispatched after next (redirected)
6524 if (mOnDestroyCalled
) {
6525 // If this was destroyed by the keydown event handler, we shouldn't
6526 // dispatch keypress event on this window.
6530 noDefault
= sRedirectedKeyDownEventPreventedDefault
;
6531 // If this is redirected keydown message, we have dispatched the keydown
6533 if (aEventDispatched
) {
6534 *aEventDispatched
= true;
6538 ForgetRedirectedKeyDownMessage();
6540 // If the key was processed by IME, we shouldn't dispatch keypress event.
6541 if (aMsg
.wParam
== VK_PROCESSKEY
) {
6545 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6546 // for almost all keys
6547 switch (DOMKeyCode
) {
6551 case NS_VK_CAPS_LOCK
:
6552 case NS_VK_NUM_LOCK
:
6553 case NS_VK_SCROLL_LOCK
:
6558 UINT virtualKeyCode
= nativeKey
.GetOriginalVirtualKeyCode();
6559 bool isDeadKey
= gKbdLayout
.IsDeadKey(virtualKeyCode
, aModKeyState
);
6560 EventFlags extraFlags
;
6561 extraFlags
.mDefaultPrevented
= noDefault
;
6563 BOOL gotMsg
= aFakeCharMessage
||
6564 WinUtils::PeekMessage(&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
,
6565 PM_NOREMOVE
| PM_NOYIELD
);
6566 // Enter and backspace are always handled here to avoid for example the
6567 // confusion between ctrl-enter and ctrl-J.
6568 if (DOMKeyCode
== NS_VK_RETURN
|| DOMKeyCode
== NS_VK_BACK
||
6569 ((aModKeyState
.IsControl() || aModKeyState
.IsAlt() || aModKeyState
.IsWin())
6570 && !isDeadKey
&& KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)))
6572 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6573 // They can be more than one because of:
6574 // * Dead-keys not pairing with base character
6575 // * Some keyboard layouts may map up to 4 characters to the single key
6576 bool anyCharMessagesRemoved
= false;
6578 if (aFakeCharMessage
) {
6579 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST
, WM_KEYLAST
,
6581 anyCharMessagesRemoved
= true;
6583 while (gotMsg
&& (msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
))
6585 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6586 ("%s charCode=%d scanCode=%d\n", msg
.message
== WM_SYSCHAR
?
6587 "WM_SYSCHAR" : "WM_CHAR",
6588 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
6589 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST
, WM_KEYLAST
);
6590 anyCharMessagesRemoved
= true;
6592 gotMsg
= WinUtils::PeekMessage(&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
,
6593 PM_NOREMOVE
| PM_NOYIELD
);
6597 if (!anyCharMessagesRemoved
&& DOMKeyCode
== NS_VK_BACK
&&
6598 IMEHandler::IsDoingKakuteiUndo(mWnd
)) {
6599 NS_ASSERTION(!aFakeCharMessage
,
6600 "We shouldn't be touching the real msg queue");
6601 RemoveMessageAndDispatchPluginEvent(WM_CHAR
, WM_CHAR
);
6605 (aFakeCharMessage
||
6606 msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
|| msg
.message
== WM_DEADCHAR
)) {
6607 if (aFakeCharMessage
) {
6608 MSG msg
= aFakeCharMessage
->GetCharMessage(mWnd
);
6609 if (msg
.message
== WM_DEADCHAR
) {
6613 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)) {
6614 nsPrintfCString
log(
6615 "virtualKeyCode=0x%02X, inputtingChar={ mChars=[ 0x%04X, 0x%04X, "
6616 "0x%04X, 0x%04X, 0x%04X ], mLength=%d }, wParam=0x%04X",
6617 virtualKeyCode
, inputtingChars
.mChars
[0], inputtingChars
.mChars
[1],
6618 inputtingChars
.mChars
[2], inputtingChars
.mChars
[3],
6619 inputtingChars
.mChars
[4], inputtingChars
.mLength
, msg
.wParam
);
6620 if (!inputtingChars
.mLength
) {
6621 log
.Insert("length is zero: ", 0);
6622 NS_ERROR(log
.get());
6624 } else if (inputtingChars
.mChars
[0] != msg
.wParam
) {
6625 log
.Insert("character mismatch: ", 0);
6626 NS_ERROR(log
.get());
6630 #endif // #ifdef DEBUG
6631 return OnChar(msg
, nativeKey
, aModKeyState
, nullptr, &extraFlags
);
6634 // If prevent default set for keydown, do same for keypress
6635 WinUtils::GetMessage(&msg
, mWnd
, msg
.message
, msg
.message
);
6637 if (msg
.message
== WM_DEADCHAR
) {
6638 if (!PluginHasFocus())
6641 // We need to send the removed message to focused plug-in.
6642 DispatchPluginEvent(msg
);
6646 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6647 ("%s charCode=%d scanCode=%d\n",
6648 msg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
6649 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
6651 BOOL result
= OnChar(msg
, nativeKey
, aModKeyState
, nullptr, &extraFlags
);
6652 // If a syschar keypress wasn't processed, Windows may want to
6653 // handle it to activate a native menu.
6654 if (!result
&& msg
.message
== WM_SYSCHAR
)
6655 ::DefWindowProcW(mWnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
6658 else if (!aModKeyState
.IsControl() && !aModKeyState
.IsAlt() &&
6659 !aModKeyState
.IsWin() &&
6660 KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)) {
6661 // If this is simple KeyDown event but next message is not WM_CHAR,
6662 // this event may not input text, so we should ignore this event.
6664 return PluginHasFocus() && noDefault
;
6668 return PluginHasFocus() && noDefault
;
6671 UniCharsAndModifiers shiftedChars
;
6672 UniCharsAndModifiers unshiftedChars
;
6673 uint32_t shiftedLatinChar
= 0;
6674 uint32_t unshiftedLatinChar
= 0;
6676 if (!KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)) {
6677 inputtingChars
.Clear();
6680 if (aModKeyState
.IsControl() ^ aModKeyState
.IsAlt()) {
6681 widget::ModifierKeyState
capsLockState(
6682 aModKeyState
.GetModifiers() & MODIFIER_CAPSLOCK
);
6684 gKbdLayout
.GetUniCharsAndModifiers(virtualKeyCode
, capsLockState
);
6685 capsLockState
.Set(MODIFIER_SHIFT
);
6687 gKbdLayout
.GetUniCharsAndModifiers(virtualKeyCode
, capsLockState
);
6689 // The current keyboard cannot input alphabets or numerics,
6690 // we should append them for Shortcut/Access keys.
6691 // E.g., for Cyrillic keyboard layout.
6692 capsLockState
.Unset(MODIFIER_SHIFT
);
6693 WidgetUtils::GetLatinCharCodeForKeyCode(DOMKeyCode
,
6694 capsLockState
.GetModifiers(),
6695 &unshiftedLatinChar
,
6698 // If the shiftedLatinChar isn't 0, the key code is NS_VK_[A-Z].
6699 if (shiftedLatinChar
) {
6700 // If the produced characters of the key on current keyboard layout
6701 // are same as computed Latin characters, we shouldn't append the
6702 // Latin characters to alternativeCharCode.
6703 if (unshiftedLatinChar
== unshiftedChars
.mChars
[0] &&
6704 shiftedLatinChar
== shiftedChars
.mChars
[0]) {
6705 shiftedLatinChar
= unshiftedLatinChar
= 0;
6707 } else if (unshiftedLatinChar
) {
6708 // If the shiftedLatinChar is 0, the keyCode doesn't produce
6709 // alphabet character. At that time, the character may be produced
6710 // with Shift key. E.g., on French keyboard layout, NS_VK_PERCENT
6711 // key produces LATIN SMALL LETTER U WITH GRAVE (U+00F9) without
6712 // Shift key but with Shift key, it produces '%'.
6713 // If the unshiftedLatinChar is produced by the key on current
6714 // keyboard layout, we shouldn't append it to alternativeCharCode.
6715 if (unshiftedLatinChar
== unshiftedChars
.mChars
[0] ||
6716 unshiftedLatinChar
== shiftedChars
.mChars
[0]) {
6717 unshiftedLatinChar
= 0;
6721 // If the charCode is not ASCII character, we should replace the
6722 // charCode with ASCII character only when Ctrl is pressed.
6723 // But don't replace the charCode when the charCode is not same as
6724 // unmodified characters. In such case, Ctrl is sometimes used for a
6725 // part of character inputting key combination like Shift.
6726 if (aModKeyState
.IsControl()) {
6728 aModKeyState
.IsShift() ? shiftedLatinChar
: unshiftedLatinChar
;
6730 (!inputtingChars
.mLength
||
6731 inputtingChars
.UniCharsCaseInsensitiveEqual(
6732 aModKeyState
.IsShift() ? shiftedChars
: unshiftedChars
))) {
6733 inputtingChars
.Clear();
6734 inputtingChars
.Append(ch
, aModKeyState
.GetModifiers());
6739 if (inputtingChars
.mLength
||
6740 shiftedChars
.mLength
|| unshiftedChars
.mLength
) {
6741 uint32_t num
= std::max(inputtingChars
.mLength
,
6742 std::max(shiftedChars
.mLength
, unshiftedChars
.mLength
));
6743 uint32_t skipUniChars
= num
- inputtingChars
.mLength
;
6744 uint32_t skipShiftedChars
= num
- shiftedChars
.mLength
;
6745 uint32_t skipUnshiftedChars
= num
- unshiftedChars
.mLength
;
6746 UINT keyCode
= !inputtingChars
.mLength
? DOMKeyCode
: 0;
6747 for (uint32_t cnt
= 0; cnt
< num
; cnt
++) {
6748 uint16_t uniChar
, shiftedChar
, unshiftedChar
;
6749 uniChar
= shiftedChar
= unshiftedChar
= 0;
6750 ModifierKeyState
modKeyState(aModKeyState
);
6751 if (skipUniChars
<= cnt
) {
6752 if (cnt
- skipUniChars
< inputtingChars
.mLength
) {
6753 // If key in combination with Alt and/or Ctrl produces a different
6754 // character than without them then do not report these flags
6755 // because it is separate keyboard layout shift state. If dead-key
6756 // and base character does not produce a valid composite character
6757 // then both produced dead-key character and following base
6758 // character may have different modifier flags, too.
6759 modKeyState
.Unset(MODIFIER_SHIFT
| MODIFIER_CONTROL
| MODIFIER_ALT
|
6760 MODIFIER_ALTGRAPH
| MODIFIER_CAPSLOCK
);
6761 modKeyState
.Set(inputtingChars
.mModifiers
[cnt
- skipUniChars
]);
6763 uniChar
= inputtingChars
.mChars
[cnt
- skipUniChars
];
6765 if (skipShiftedChars
<= cnt
)
6766 shiftedChar
= shiftedChars
.mChars
[cnt
- skipShiftedChars
];
6767 if (skipUnshiftedChars
<= cnt
)
6768 unshiftedChar
= unshiftedChars
.mChars
[cnt
- skipUnshiftedChars
];
6769 nsAutoTArray
<nsAlternativeCharCode
, 5> altArray
;
6771 if (shiftedChar
|| unshiftedChar
) {
6772 nsAlternativeCharCode
chars(unshiftedChar
, shiftedChar
);
6773 altArray
.AppendElement(chars
);
6775 if (cnt
== num
- 1) {
6776 if (unshiftedLatinChar
|| shiftedLatinChar
) {
6777 nsAlternativeCharCode
chars(unshiftedLatinChar
, shiftedLatinChar
);
6778 altArray
.AppendElement(chars
);
6781 // Typically, following virtual keycodes are used for a key which can
6782 // input the character. However, these keycodes are also used for
6783 // other keys on some keyboard layout. E.g., in spite of Shift+'1'
6784 // inputs '+' on Thai keyboard layout, a key which is at '=/+'
6785 // key on ANSI keyboard layout is VK_OEM_PLUS. Native applications
6786 // handle it as '+' key if Ctrl key is pressed.
6787 PRUnichar charForOEMKeyCode
= 0;
6788 switch (virtualKeyCode
) {
6789 case VK_OEM_PLUS
: charForOEMKeyCode
= '+'; break;
6790 case VK_OEM_COMMA
: charForOEMKeyCode
= ','; break;
6791 case VK_OEM_MINUS
: charForOEMKeyCode
= '-'; break;
6792 case VK_OEM_PERIOD
: charForOEMKeyCode
= '.'; break;
6794 if (charForOEMKeyCode
&&
6795 charForOEMKeyCode
!= unshiftedChars
.mChars
[0] &&
6796 charForOEMKeyCode
!= shiftedChars
.mChars
[0] &&
6797 charForOEMKeyCode
!= unshiftedLatinChar
&&
6798 charForOEMKeyCode
!= shiftedLatinChar
) {
6799 nsAlternativeCharCode
OEMChars(charForOEMKeyCode
, charForOEMKeyCode
);
6800 altArray
.AppendElement(OEMChars
);
6804 nsKeyEvent
keypressEvent(true, NS_KEY_PRESS
, this);
6805 keypressEvent
.mFlags
.Union(extraFlags
);
6806 keypressEvent
.charCode
= uniChar
;
6807 keypressEvent
.alternativeCharCodes
.AppendElements(altArray
);
6808 InitKeyEvent(keypressEvent
, nativeKey
, modKeyState
);
6809 DispatchKeyEvent(keypressEvent
, nullptr);
6812 nsKeyEvent
keypressEvent(true, NS_KEY_PRESS
, this);
6813 keypressEvent
.mFlags
.Union(extraFlags
);
6814 keypressEvent
.keyCode
= DOMKeyCode
;
6815 InitKeyEvent(keypressEvent
, nativeKey
, aModKeyState
);
6816 DispatchKeyEvent(keypressEvent
, nullptr);
6823 LRESULT
nsWindow::OnKeyUp(const MSG
&aMsg
,
6824 const ModifierKeyState
&aModKeyState
,
6825 bool *aEventDispatched
)
6827 // NOTE: VK_PROCESSKEY never comes with WM_KEYUP
6828 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6829 ("nsWindow::OnKeyUp wParam(VK)=%d\n", aMsg
.wParam
));
6831 if (aEventDispatched
)
6832 *aEventDispatched
= true;
6833 nsKeyEvent
keyupEvent(true, NS_KEY_UP
, this);
6834 NativeKey
nativeKey(gKbdLayout
, this, aMsg
);
6835 gKbdLayout
.InitNativeKey(nativeKey
, aModKeyState
);
6836 keyupEvent
.keyCode
= nativeKey
.GetDOMKeyCode();
6837 InitKeyEvent(keyupEvent
, nativeKey
, aModKeyState
);
6838 // Set defaultPrevented of the key event if the VK_MENU is not a system key
6839 // release, so that the menu bar does not trigger. This helps avoid
6840 // triggering the menu bar for ALT key accelerators used in assistive
6841 // technologies such as Window-Eyes and ZoomText or for switching open state
6843 keyupEvent
.mFlags
.mDefaultPrevented
=
6844 (aMsg
.wParam
== VK_MENU
&& aMsg
.message
!= WM_SYSKEYUP
);
6845 return DispatchKeyEvent(keyupEvent
, &aMsg
);
6849 LRESULT
nsWindow::OnChar(const MSG
&aMsg
,
6850 const NativeKey
& aNativeKey
,
6851 const ModifierKeyState
&aModKeyState
,
6852 bool *aEventDispatched
,
6853 const EventFlags
*aExtraFlags
)
6855 // ignore [shift+]alt+space so the OS can handle it
6856 if (aModKeyState
.IsAlt() && !aModKeyState
.IsControl() &&
6857 IS_VK_DOWN(NS_VK_SPACE
)) {
6861 uint32_t charCode
= aMsg
.wParam
;
6862 // Ignore Ctrl+Enter (bug 318235)
6863 if (aModKeyState
.IsControl() && charCode
== 0xA) {
6867 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
6868 ModifierKeyState
modKeyState(aModKeyState
);
6869 if (modKeyState
.IsAlt() && modKeyState
.IsControl()) {
6870 modKeyState
.Unset(MODIFIER_ALT
| MODIFIER_CONTROL
);
6873 if (IMEHandler::IsComposingOn(this)) {
6874 IMEHandler::NotifyIME(this, REQUEST_TO_COMMIT_COMPOSITION
);
6878 // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
6879 if (modKeyState
.IsControl() && charCode
<= 0x1A) {
6880 // need to account for shift here. bug 16486
6881 if (modKeyState
.IsShift()) {
6882 uniChar
= charCode
- 1 + 'A';
6884 uniChar
= charCode
- 1 + 'a';
6886 } else if (modKeyState
.IsControl() && charCode
<= 0x1F) {
6887 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
6888 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
6889 // for some reason the keypress handler need to have the uniChar code set
6890 // with the addition of a upper case A not the lower case.
6891 uniChar
= charCode
- 1 + 'A';
6892 } else { // 0x20 - SPACE, 0x3D - EQUALS
6893 if (charCode
< 0x20 || (charCode
== 0x3D && modKeyState
.IsControl())) {
6900 // Keep the characters unshifted for shortcuts and accesskeys and make sure
6901 // that numbers are always passed as such (among others: bugs 50255 and 351310)
6902 if (uniChar
&& (modKeyState
.IsControl() || modKeyState
.IsAlt())) {
6903 UINT virtualKeyCode
= ::MapVirtualKeyEx(aNativeKey
.GetScanCode(),
6905 gKbdLayout
.GetLayout());
6906 UINT unshiftedCharCode
=
6907 virtualKeyCode
>= '0' && virtualKeyCode
<= '9' ? virtualKeyCode
:
6908 modKeyState
.IsShift() ? ::MapVirtualKeyEx(virtualKeyCode
,
6910 gKbdLayout
.GetLayout()) : 0;
6911 // ignore diacritics (top bit set) and key mapping errors (char code 0)
6912 if ((INT
)unshiftedCharCode
> 0)
6913 uniChar
= unshiftedCharCode
;
6916 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
6917 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
6919 if (!modKeyState
.IsShift() &&
6920 (aModKeyState
.IsAlt() || aModKeyState
.IsControl())) {
6921 uniChar
= towlower(uniChar
);
6924 nsKeyEvent
keypressEvent(true, NS_KEY_PRESS
, this);
6926 keypressEvent
.mFlags
.Union(*aExtraFlags
);
6928 keypressEvent
.charCode
= uniChar
;
6929 if (!keypressEvent
.charCode
) {
6930 keypressEvent
.keyCode
= aNativeKey
.GetDOMKeyCode();
6932 InitKeyEvent(keypressEvent
, aNativeKey
, modKeyState
);
6933 bool result
= DispatchKeyEvent(keypressEvent
, &aMsg
);
6934 if (aEventDispatched
)
6935 *aEventDispatched
= true;
6940 nsWindow::SetupKeyModifiersSequence(nsTArray
<KeyPair
>* aArray
, uint32_t aModifiers
)
6942 for (uint32_t i
= 0; i
< ArrayLength(sModifierKeyMap
); ++i
) {
6943 const uint32_t* map
= sModifierKeyMap
[i
];
6944 if (aModifiers
& map
[0]) {
6945 aArray
->AppendElement(KeyPair(map
[1], map
[2]));
6950 static BOOL WINAPI
EnumFirstChild(HWND hwnd
, LPARAM lParam
)
6952 *((HWND
*)lParam
) = hwnd
;
6956 static void InvalidatePluginAsWorkaround(nsWindow
*aWindow
, const nsIntRect
&aRect
)
6958 aWindow
->Invalidate(aRect
);
6960 // XXX - Even more evil workaround!! See bug 762948, flash's bottom
6961 // level sandboxed window doesn't seem to get our invalidate. We send
6962 // an invalidate to it manually. This is totally specialized for this
6963 // bug, for other child window structures this will just be a more or
6964 // less bogus invalidate but since that should not have any bad
6965 // side-effects this will have to do for now.
6966 HWND current
= (HWND
)aWindow
->GetNativeData(NS_NATIVE_WINDOW
);
6971 ::GetWindowRect(current
, &parentRect
);
6973 HWND next
= current
;
6978 ::EnumChildWindows(current
, &EnumFirstChild
, (LPARAM
)&next
);
6980 ::GetWindowRect(next
, &windowRect
);
6981 // This is relative to the screen, adjust it to be relative to the
6982 // window we're reconfiguring.
6983 windowRect
.left
-= parentRect
.left
;
6984 windowRect
.top
-= parentRect
.top
;
6985 } while (next
!= current
&& windowRect
.top
== 0 && windowRect
.left
== 0);
6987 if (windowRect
.top
== 0 && windowRect
.left
== 0) {
6989 rect
.left
= aRect
.x
;
6991 rect
.right
= aRect
.XMost();
6992 rect
.bottom
= aRect
.YMost();
6994 ::InvalidateRect(next
, &rect
, FALSE
);
6999 nsWindow::ConfigureChildren(const nsTArray
<Configuration
>& aConfigurations
)
7001 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
7002 // here, if that helps in some situations. So far I haven't seen a
7004 for (uint32_t i
= 0; i
< aConfigurations
.Length(); ++i
) {
7005 const Configuration
& configuration
= aConfigurations
[i
];
7006 nsWindow
* w
= static_cast<nsWindow
*>(configuration
.mChild
);
7007 NS_ASSERTION(w
->GetParent() == this,
7008 "Configured widget is not a child");
7009 nsresult rv
= w
->SetWindowClipRegion(configuration
.mClipRegion
, true);
7010 NS_ENSURE_SUCCESS(rv
, rv
);
7012 w
->GetBounds(bounds
);
7013 if (bounds
.Size() != configuration
.mBounds
.Size()) {
7014 w
->Resize(configuration
.mBounds
.x
, configuration
.mBounds
.y
,
7015 configuration
.mBounds
.width
, configuration
.mBounds
.height
,
7017 } else if (bounds
.TopLeft() != configuration
.mBounds
.TopLeft()) {
7018 w
->Move(configuration
.mBounds
.x
, configuration
.mBounds
.y
);
7021 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7022 gfxWindowsPlatform::RENDER_DIRECT2D
||
7023 GetLayerManager()->GetBackendType() != LAYERS_BASIC
) {
7024 // XXX - Workaround for Bug 587508. This will invalidate the part of the
7025 // plugin window that might be touched by moving content somehow. The
7026 // underlying problem should be found and fixed!
7028 r
.Sub(bounds
, configuration
.mBounds
);
7031 nsIntRect toInvalidate
= r
.GetBounds();
7033 InvalidatePluginAsWorkaround(w
, toInvalidate
);
7036 rv
= w
->SetWindowClipRegion(configuration
.mClipRegion
, false);
7037 NS_ENSURE_SUCCESS(rv
, rv
);
7043 CreateHRGNFromArray(const nsTArray
<nsIntRect
>& aRects
)
7045 int32_t size
= sizeof(RGNDATAHEADER
) + sizeof(RECT
)*aRects
.Length();
7046 nsAutoTArray
<uint8_t,100> buf
;
7047 if (!buf
.SetLength(size
))
7049 RGNDATA
* data
= reinterpret_cast<RGNDATA
*>(buf
.Elements());
7050 RECT
* rects
= reinterpret_cast<RECT
*>(data
->Buffer
);
7051 data
->rdh
.dwSize
= sizeof(data
->rdh
);
7052 data
->rdh
.iType
= RDH_RECTANGLES
;
7053 data
->rdh
.nCount
= aRects
.Length();
7055 for (uint32_t i
= 0; i
< aRects
.Length(); ++i
) {
7056 const nsIntRect
& r
= aRects
[i
];
7057 bounds
.UnionRect(bounds
, r
);
7058 ::SetRect(&rects
[i
], r
.x
, r
.y
, r
.XMost(), r
.YMost());
7060 ::SetRect(&data
->rdh
.rcBound
, bounds
.x
, bounds
.y
, bounds
.XMost(), bounds
.YMost());
7061 return ::ExtCreateRegion(NULL
, buf
.Length(), data
);
7065 ArrayFromRegion(const nsIntRegion
& aRegion
, nsTArray
<nsIntRect
>& aRects
)
7068 for (nsIntRegionRectIterator
iter(aRegion
); (r
= iter
.Next());) {
7069 aRects
.AppendElement(*r
);
7074 nsWindow::SetWindowClipRegion(const nsTArray
<nsIntRect
>& aRects
,
7075 bool aIntersectWithExisting
)
7077 if (!aIntersectWithExisting
) {
7078 if (!StoreWindowClipRegion(aRects
))
7081 // In this case still early return if nothing changed.
7082 if (mClipRects
&& mClipRectCount
== aRects
.Length() &&
7085 sizeof(nsIntRect
)*mClipRectCount
) == 0) {
7089 // get current rects
7090 nsTArray
<nsIntRect
> currentRects
;
7091 GetWindowClipRegion(¤tRects
);
7092 // create region from them
7093 nsIntRegion currentRegion
= RegionFromArray(currentRects
);
7094 // create region from new rects
7095 nsIntRegion newRegion
= RegionFromArray(aRects
);
7096 // intersect regions
7097 nsIntRegion intersection
;
7098 intersection
.And(currentRegion
, newRegion
);
7099 // create int rect array from intersection
7100 nsTArray
<nsIntRect
> rects
;
7101 ArrayFromRegion(intersection
, rects
);
7103 if (!StoreWindowClipRegion(rects
))
7107 HRGN dest
= CreateHRGNFromArray(aRects
);
7109 return NS_ERROR_OUT_OF_MEMORY
;
7111 if (aIntersectWithExisting
) {
7112 HRGN current
= ::CreateRectRgn(0, 0, 0, 0);
7114 if (::GetWindowRgn(mWnd
, current
) != 0 /*ERROR*/) {
7115 ::CombineRgn(dest
, dest
, current
, RGN_AND
);
7117 ::DeleteObject(current
);
7121 // If a plugin is not visible, especially if it is in a background tab,
7122 // it should not be able to steal keyboard focus. This code checks whether
7123 // the region that the plugin is being clipped to is NULLREGION. If it is,
7124 // the plugin window gets disabled.
7125 if(mWindowType
== eWindowType_plugin
) {
7126 if(NULLREGION
== ::CombineRgn(dest
, dest
, dest
, RGN_OR
)) {
7127 ::ShowWindow(mWnd
, SW_HIDE
);
7128 ::EnableWindow(mWnd
, FALSE
);
7130 ::EnableWindow(mWnd
, TRUE
);
7131 ::ShowWindow(mWnd
, SW_SHOW
);
7134 if (!::SetWindowRgn(mWnd
, dest
, TRUE
)) {
7135 ::DeleteObject(dest
);
7136 return NS_ERROR_FAILURE
;
7141 // WM_DESTROY event handler
7142 void nsWindow::OnDestroy()
7144 mOnDestroyCalled
= true;
7146 // Make sure we don't get destroyed in the process of tearing down.
7147 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
7149 // Dispatch the destroy notification.
7151 NotifyWindowDestroyed();
7153 // Prevent the widget from sending additional events.
7154 mWidgetListener
= nullptr;
7155 mAttachedWidgetListener
= nullptr;
7157 // Free our subclass and clear |this| stored in the window props. We will no longer
7158 // receive events from Windows after this point.
7159 SubclassWindow(FALSE
);
7161 // Once mWidgetListener is cleared and the subclass is reset, sCurrentWindow can be
7162 // cleared. (It's used in tracking windows for mouse events.)
7163 if (sCurrentWindow
== this)
7164 sCurrentWindow
= nullptr;
7166 // Disconnects us from our parent, will call our GetParent().
7167 nsBaseWidget::Destroy();
7169 // Release references to children, device context, toolkit, and app shell.
7170 nsBaseWidget::OnDestroy();
7172 // Clear our native parent handle.
7173 // XXX Windows will take care of this in the proper order, and SetParent(nullptr)'s
7174 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
7175 //SetParent(nullptr);
7178 // We have to destroy the native drag target before we null out our window pointer.
7179 EnableDragDrop(false);
7181 // If we're going away and for some reason we're still the rollup widget, rollup and
7182 // turn off capture.
7183 nsIRollupListener
* rollupListener
= nsBaseWidget::GetActiveRollupListener();
7184 nsCOMPtr
<nsIWidget
> rollupWidget
;
7185 if (rollupListener
) {
7186 rollupWidget
= rollupListener
->GetRollupWidget();
7188 if (this == rollupWidget
) {
7189 if ( rollupListener
)
7190 rollupListener
->Rollup(0, nullptr);
7191 CaptureRollupEvents(nullptr, false);
7194 IMEHandler::OnDestroyWindow(this);
7196 // Turn off mouse trails if enabled.
7197 MouseTrailer
* mtrailer
= nsToolkit::gMouseTrailer
;
7199 if (mtrailer
->GetMouseTrailerWindow() == mWnd
)
7200 mtrailer
->DestroyTimer();
7202 if (mtrailer
->GetCaptureWindow() == mWnd
)
7203 mtrailer
->SetCaptureWindow(nullptr);
7206 // Free GDI window class objects
7208 VERIFY(::DeleteObject(mBrush
));
7213 // Destroy any custom cursor resources.
7215 SetCursor(eCursor_standard
);
7218 // Reset transparency
7219 if (eTransparencyTransparent
== mTransparencyMode
)
7220 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque
);
7223 // Finalize panning feedback to possibly restore window displacement
7224 mGesture
.PanFeedbackFinalize(mWnd
, true);
7226 // Clear the main HWND.
7231 bool nsWindow::OnMove(int32_t aX
, int32_t aY
)
7236 return mWidgetListener
? mWidgetListener
->WindowMoved(this, aX
, aY
) : false;
7239 // Send a resize message to the listener
7240 bool nsWindow::OnResize(nsIntRect
&aWindowRect
)
7242 #ifdef CAIRO_HAS_D2D_SURFACE
7243 if (mD2DWindowSurface
) {
7244 mD2DWindowSurface
= NULL
;
7249 bool result
= mWidgetListener
?
7250 mWidgetListener
->WindowResized(this, aWindowRect
.width
, aWindowRect
.height
) : false;
7252 // If there is an attached view, inform it as well as the normal widget listener.
7253 if (mAttachedWidgetListener
) {
7254 return mAttachedWidgetListener
->WindowResized(this, aWindowRect
.width
, aWindowRect
.height
);
7260 bool nsWindow::OnHotKey(WPARAM wParam
, LPARAM lParam
)
7265 // Can be overriden. Controls auto-erase of background.
7266 bool nsWindow::AutoErase(HDC dc
)
7272 nsWindow::AllowD3D9Callback(nsWindow
*aWindow
)
7274 if (aWindow
->mLayerManager
&& !aWindow
->ShouldUseOffMainThreadCompositing()) {
7275 aWindow
->mLayerManager
->Destroy();
7276 aWindow
->mLayerManager
= NULL
;
7281 nsWindow::AllowD3D9WithReinitializeCallback(nsWindow
*aWindow
)
7283 if (aWindow
->mLayerManager
&& !aWindow
->ShouldUseOffMainThreadCompositing()) {
7284 aWindow
->mLayerManager
->Destroy();
7285 aWindow
->mLayerManager
= NULL
;
7286 (void) aWindow
->GetLayerManager();
7291 nsWindow::StartAllowingD3D9(bool aReinitialize
)
7295 LayerManagerPrefs prefs
;
7296 GetLayerManagerPrefs(&prefs
);
7297 if (prefs
.mDisableAcceleration
) {
7298 // The guarantee here is, if there's *any* chance that after we
7299 // throw out our layer managers we'd create at least one new,
7300 // accelerated one, we *will* throw out all the current layer
7301 // managers. We early-return here because currently, if
7302 // |disableAcceleration|, we will always use basic managers and
7303 // it's a waste to recreate them. If we're using OMTC we don't want to
7304 // recreate out layer manager and its compositor either. This is even
7307 // NB: the above implies that it's eminently possible for us to
7308 // skip this early return but still recreate basic managers.
7309 // That's OK. It's *not* OK to take this early return when we
7310 // *might* have created an accelerated manager.
7314 if (aReinitialize
) {
7315 EnumAllWindows(AllowD3D9WithReinitializeCallback
);
7317 EnumAllWindows(AllowD3D9Callback
);
7322 nsWindow::HasBogusPopupsDropShadowOnMultiMonitor() {
7323 if (sHasBogusPopupsDropShadowOnMultiMonitor
== TRI_UNKNOWN
) {
7324 // Since any change in the preferences requires a restart, this can be
7326 // Check for Direct2D first.
7327 sHasBogusPopupsDropShadowOnMultiMonitor
=
7328 gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7329 gfxWindowsPlatform::RENDER_DIRECT2D
? TRI_TRUE
: TRI_FALSE
;
7330 if (!sHasBogusPopupsDropShadowOnMultiMonitor
) {
7331 // Otherwise check if Direct3D 9 may be used.
7332 LayerManagerPrefs prefs
;
7333 GetLayerManagerPrefs(&prefs
);
7334 if (!prefs
.mDisableAcceleration
&& !prefs
.mPreferOpenGL
) {
7335 nsCOMPtr
<nsIGfxInfo
> gfxInfo
= do_GetService("@mozilla.org/gfx/info;1");
7338 if (NS_SUCCEEDED(gfxInfo
->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
, &status
))) {
7339 if (status
== nsIGfxInfo::FEATURE_NO_INFO
|| prefs
.mForceAcceleration
)
7341 sHasBogusPopupsDropShadowOnMultiMonitor
= TRI_TRUE
;
7348 return !!sHasBogusPopupsDropShadowOnMultiMonitor
;
7352 nsWindow::OnSysColorChanged()
7354 if (mWindowType
== eWindowType_invisible
) {
7355 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg
, WM_SYSCOLORCHANGE
);
7358 // Note: This is sent for child windows as well as top-level windows.
7359 // The Win32 toolkit normally only sends these events to top-level windows.
7360 // But we cycle through all of the childwindows and send it to them as well
7361 // so all presentations get notified properly.
7362 // See nsWindow::GlobalMsgWindowProc.
7363 NotifySysColorChanged();
7367 /**************************************************************
7368 **************************************************************
7370 ** BLOCK: IME management and accessibility
7372 ** Handles managing IME input and accessibility.
7374 **************************************************************
7375 **************************************************************/
7378 nsWindow::NotifyIME(NotificationToIME aNotification
)
7380 return IMEHandler::NotifyIME(this, aNotification
);
7383 NS_IMETHODIMP_(void)
7384 nsWindow::SetInputContext(const InputContext
& aContext
,
7385 const InputContextAction
& aAction
)
7387 InputContext newInputContext
= aContext
;
7388 IMEHandler::SetInputContext(this, newInputContext
, aAction
);
7389 mInputContext
= newInputContext
;
7392 NS_IMETHODIMP_(InputContext
)
7393 nsWindow::GetInputContext()
7395 mInputContext
.mIMEState
.mOpen
= IMEState::CLOSED
;
7396 if (IMEHandler::IsIMEEnabled(mInputContext
) && IMEHandler::GetOpenState(this)) {
7397 mInputContext
.mIMEState
.mOpen
= IMEState::OPEN
;
7399 mInputContext
.mIMEState
.mOpen
= IMEState::CLOSED
;
7401 return mInputContext
;
7405 nsWindow::GetToggledKeyState(uint32_t aKeyCode
, bool* aLEDState
)
7407 #ifdef DEBUG_KBSTATE
7408 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
, ("GetToggledKeyState\n"));
7410 NS_ENSURE_ARG_POINTER(aLEDState
);
7411 *aLEDState
= (::GetKeyState(aKeyCode
) & 1) != 0;
7416 nsWindow::NotifyIMEOfTextChange(uint32_t aStart
,
7420 return IMEHandler::NotifyIMEOfTextChange(aStart
, aOldEnd
, aNewEnd
);
7423 nsIMEUpdatePreference
7424 nsWindow::GetIMEUpdatePreference()
7426 return IMEHandler::GetUpdatePreference();
7429 #ifdef ACCESSIBILITY
7431 #ifdef DEBUG_WMGETOBJECT
7432 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
7433 a11y::Accessible* acc = aWnd ? aWind->GetAccessible() : nullptr; \
7434 PR_LOG(gWindowsLog, PR_LOG_ALWAYS, (" acc: %p", acc)); \
7436 nsAutoString name; \
7437 acc->GetName(name); \
7438 PR_LOG(gWindowsLog, PR_LOG_ALWAYS, \
7439 (", accname: %s", NS_ConvertUTF16toUTF8(name).get())); \
7440 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
7441 void *hwnd = nullptr; \
7442 doc->GetWindowHandle(&hwnd); \
7443 PR_LOG(gWindowsLog, PR_LOG_ALWAYS, (", acc hwnd: %d", hwnd)); \
7446 #define NS_LOG_WMGETOBJECT_THISWND \
7448 PR_LOG(gWindowsLog, PR_LOG_ALWAYS, \
7449 ("\n*******Get Doc Accessible*******\nOrig Window: ")); \
7450 PR_LOG(gWindowsLog, PR_LOG_ALWAYS, \
7451 ("\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7452 mWnd, ::GetParent(mWnd), this)); \
7453 NS_LOG_WMGETOBJECT_WNDACC(this) \
7454 PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("\n }\n")); \
7457 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
7459 nsWindow* wnd = WinUtils::GetNSWindowPtr(aHwnd); \
7460 PR_LOG(gWindowsLog, PR_LOG_ALWAYS, \
7461 ("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7462 aHwnd, ::GetParent(aHwnd), wnd)); \
7463 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
7464 PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("\n }\n")); \
7467 #define NS_LOG_WMGETOBJECT_THISWND
7468 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
7469 #endif // DEBUG_WMGETOBJECT
7472 nsWindow::GetRootAccessible()
7474 // If the pref was ePlatformIsDisabled, return null here, disabling a11y.
7475 if (a11y::PlatformDisabledState() == a11y::ePlatformIsDisabled
)
7478 if (mInDtor
|| mOnDestroyCalled
|| mWindowType
== eWindowType_invisible
) {
7482 NS_LOG_WMGETOBJECT_THISWND
7483 NS_LOG_WMGETOBJECT_WND("This Window", mWnd
);
7485 return GetAccessible();
7489 /**************************************************************
7490 **************************************************************
7492 ** BLOCK: Transparency
7494 ** Window transparency helpers.
7496 **************************************************************
7497 **************************************************************/
7501 void nsWindow::ResizeTranslucentWindow(int32_t aNewWidth
, int32_t aNewHeight
, bool force
)
7503 if (!force
&& aNewWidth
== mBounds
.width
&& aNewHeight
== mBounds
.height
)
7506 #ifdef CAIRO_HAS_D2D_SURFACE
7507 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7508 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7509 nsRefPtr
<gfxD2DSurface
> newSurface
=
7510 new gfxD2DSurface(gfxIntSize(aNewWidth
, aNewHeight
), gfxASurface::ImageFormatARGB32
);
7511 mTransparentSurface
= newSurface
;
7512 mMemoryDC
= nullptr;
7516 nsRefPtr
<gfxWindowsSurface
> newSurface
=
7517 new gfxWindowsSurface(gfxIntSize(aNewWidth
, aNewHeight
), gfxASurface::ImageFormatARGB32
);
7518 mTransparentSurface
= newSurface
;
7519 mMemoryDC
= newSurface
->GetDC();
7523 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode
)
7525 if (aMode
== mTransparencyMode
)
7528 // stop on dialogs and popups!
7529 HWND hWnd
= WinUtils::GetTopLevelHWND(mWnd
, true);
7530 nsWindow
* parent
= WinUtils::GetNSWindowPtr(hWnd
);
7534 NS_WARNING("Trying to use transparent chrome in an embedded context");
7538 if (parent
!= this) {
7539 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
7542 if (aMode
== eTransparencyTransparent
) {
7543 // If we're switching to the use of a transparent window, hide the chrome
7545 HideWindowChrome(true);
7546 } else if (mHideChrome
&& mTransparencyMode
== eTransparencyTransparent
) {
7547 // if we're switching out of transparent, re-enable our parent's chrome.
7548 HideWindowChrome(false);
7551 LONG_PTR style
= ::GetWindowLongPtrW(hWnd
, GWL_STYLE
),
7552 exStyle
= ::GetWindowLongPtr(hWnd
, GWL_EXSTYLE
);
7554 if (parent
->mIsVisible
)
7555 style
|= WS_VISIBLE
;
7556 if (parent
->mSizeMode
== nsSizeMode_Maximized
)
7557 style
|= WS_MAXIMIZE
;
7558 else if (parent
->mSizeMode
== nsSizeMode_Minimized
)
7559 style
|= WS_MINIMIZE
;
7561 if (aMode
== eTransparencyTransparent
)
7562 exStyle
|= WS_EX_LAYERED
;
7564 exStyle
&= ~WS_EX_LAYERED
;
7566 VERIFY_WINDOW_STYLE(style
);
7567 ::SetWindowLongPtrW(hWnd
, GWL_STYLE
, style
);
7568 ::SetWindowLongPtrW(hWnd
, GWL_EXSTYLE
, exStyle
);
7571 memset(&mGlassMargins
, 0, sizeof mGlassMargins
);
7572 mTransparencyMode
= aMode
;
7574 SetupTranslucentWindowMemoryBitmap(aMode
);
7578 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode
)
7580 if (eTransparencyTransparent
== aMode
) {
7581 ResizeTranslucentWindow(mBounds
.width
, mBounds
.height
, true);
7583 mTransparentSurface
= nullptr;
7588 void nsWindow::ClearTranslucentWindow()
7590 if (mTransparentSurface
) {
7591 nsRefPtr
<gfxContext
> thebesContext
= new gfxContext(mTransparentSurface
);
7592 thebesContext
->SetOperator(gfxContext::OPERATOR_CLEAR
);
7593 thebesContext
->Paint();
7594 UpdateTranslucentWindow();
7598 nsresult
nsWindow::UpdateTranslucentWindow()
7600 if (mBounds
.IsEmpty())
7605 BLENDFUNCTION bf
= { AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
7606 SIZE winSize
= { mBounds
.width
, mBounds
.height
};
7607 POINT srcPos
= { 0, 0 };
7608 HWND hWnd
= WinUtils::GetTopLevelHWND(mWnd
, true);
7610 ::GetWindowRect(hWnd
, &winRect
);
7612 #ifdef CAIRO_HAS_D2D_SURFACE
7613 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7614 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7615 mMemoryDC
= static_cast<gfxD2DSurface
*>(mTransparentSurface
.get())->
7619 // perform the alpha blend
7620 bool updateSuccesful
=
7621 ::UpdateLayeredWindow(hWnd
, NULL
, (POINT
*)&winRect
, &winSize
, mMemoryDC
, &srcPos
, 0, &bf
, ULW_ALPHA
);
7623 #ifdef CAIRO_HAS_D2D_SURFACE
7624 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7625 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7626 nsIntRect
r(0, 0, 0, 0);
7627 static_cast<gfxD2DSurface
*>(mTransparentSurface
.get())->ReleaseDC(&r
);
7631 if (!updateSuccesful
) {
7632 return NS_ERROR_FAILURE
;
7640 /**************************************************************
7641 **************************************************************
7643 ** BLOCK: Popup rollup hooks
7645 ** Deals with CaptureRollup on popup windows.
7647 **************************************************************
7648 **************************************************************/
7650 // Schedules a timer for a window, so we can rollup after processing the hook event
7651 void nsWindow::ScheduleHookTimer(HWND aWnd
, UINT aMsgId
)
7653 // In some cases multiple hooks may be scheduled
7654 // so ignore any other requests once one timer is scheduled
7655 if (sHookTimerId
== 0) {
7656 // Remember the window handle and the message ID to be used later
7657 sRollupMsgId
= aMsgId
;
7658 sRollupMsgWnd
= aWnd
;
7659 // Schedule native timer for doing the rollup after
7660 // this event is done being processed
7661 sHookTimerId
= ::SetTimer(NULL
, 0, 0, (TIMERPROC
)HookTimerForPopups
);
7662 NS_ASSERTION(sHookTimerId
, "Timer couldn't be created.");
7666 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7667 int gLastMsgCode
= 0;
7668 extern MSGFEventMsgInfo gMSGFEvents
[];
7671 // Process Menu messages, rollup when popup is clicked.
7672 LRESULT CALLBACK
nsWindow::MozSpecialMsgFilter(int code
, WPARAM wParam
, LPARAM lParam
)
7674 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7676 MSG
* pMsg
= (MSG
*)lParam
;
7679 while (gMSGFEvents
[inx
].mId
!= code
&& gMSGFEvents
[inx
].mStr
!= NULL
) {
7682 if (code
!= gLastMsgCode
) {
7683 if (gMSGFEvents
[inx
].mId
== code
) {
7685 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
7686 ("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n",
7687 code
, gMSGFEvents
[inx
].mStr
, pMsg
->hwnd
));
7691 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
7692 ("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n",
7693 code
, gMSGFEvents
[inx
].mId
, pMsg
->hwnd
));
7696 gLastMsgCode
= code
;
7698 PrintEvent(pMsg
->message
, FALSE
, FALSE
);
7700 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7702 if (sProcessHook
&& code
== MSGF_MENU
) {
7703 MSG
* pMsg
= (MSG
*)lParam
;
7704 ScheduleHookTimer( pMsg
->hwnd
, pMsg
->message
);
7707 return ::CallNextHookEx(sMsgFilterHook
, code
, wParam
, lParam
);
7710 // Process all mouse messages. Roll up when a click is in a native window
7711 // that doesn't have an nsIWidget.
7712 LRESULT CALLBACK
nsWindow::MozSpecialMouseProc(int code
, WPARAM wParam
, LPARAM lParam
)
7715 switch (WinUtils::GetNativeMessage(wParam
)) {
7716 case WM_LBUTTONDOWN
:
7717 case WM_RBUTTONDOWN
:
7718 case WM_MBUTTONDOWN
:
7720 case WM_MOUSEHWHEEL
:
7722 MOUSEHOOKSTRUCT
* ms
= (MOUSEHOOKSTRUCT
*)lParam
;
7723 nsIWidget
* mozWin
= WinUtils::GetNSWindowPtr(ms
->hwnd
);
7725 // If this window is windowed plugin window, the mouse events are not
7727 if (static_cast<nsWindow
*>(mozWin
)->mWindowType
== eWindowType_plugin
)
7728 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
7730 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
7736 return ::CallNextHookEx(sCallMouseHook
, code
, wParam
, lParam
);
7739 // Process all messages. Roll up when the window is moving, or
7740 // is resizing or when maximized or mininized.
7741 LRESULT CALLBACK
nsWindow::MozSpecialWndProc(int code
, WPARAM wParam
, LPARAM lParam
)
7743 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7745 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
7746 PrintEvent(cwpt
->message
, FALSE
, FALSE
);
7751 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
7752 if (cwpt
->message
== WM_MOVING
||
7753 cwpt
->message
== WM_SIZING
||
7754 cwpt
->message
== WM_GETMINMAXINFO
) {
7755 ScheduleHookTimer(cwpt
->hwnd
, (UINT
)cwpt
->message
);
7759 return ::CallNextHookEx(sCallProcHook
, code
, wParam
, lParam
);
7762 // Register the special "hooks" for dropdown processing.
7763 void nsWindow::RegisterSpecialDropdownHooks()
7765 NS_ASSERTION(!sMsgFilterHook
, "sMsgFilterHook must be NULL!");
7766 NS_ASSERTION(!sCallProcHook
, "sCallProcHook must be NULL!");
7768 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
7770 // Install msg hook for moving the window and resizing
7771 if (!sMsgFilterHook
) {
7772 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
7773 sMsgFilterHook
= SetWindowsHookEx(WH_MSGFILTER
, MozSpecialMsgFilter
, NULL
, GetCurrentThreadId());
7774 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7775 if (!sMsgFilterHook
) {
7776 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
7777 ("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n"));
7782 // Install msg hook for menus
7783 if (!sCallProcHook
) {
7784 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
7785 sCallProcHook
= SetWindowsHookEx(WH_CALLWNDPROC
, MozSpecialWndProc
, NULL
, GetCurrentThreadId());
7786 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7787 if (!sCallProcHook
) {
7788 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
7789 ("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n"));
7794 // Install msg hook for the mouse
7795 if (!sCallMouseHook
) {
7796 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
7797 sCallMouseHook
= SetWindowsHookEx(WH_MOUSE
, MozSpecialMouseProc
, NULL
, GetCurrentThreadId());
7798 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7799 if (!sCallMouseHook
) {
7800 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
7801 ("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n"));
7807 // Unhook special message hooks for dropdowns.
7808 void nsWindow::UnregisterSpecialDropdownHooks()
7810 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
7812 if (sCallProcHook
) {
7813 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
7814 if (!::UnhookWindowsHookEx(sCallProcHook
)) {
7815 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
7817 sCallProcHook
= NULL
;
7820 if (sMsgFilterHook
) {
7821 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
7822 if (!::UnhookWindowsHookEx(sMsgFilterHook
)) {
7823 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
7825 sMsgFilterHook
= NULL
;
7828 if (sCallMouseHook
) {
7829 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
7830 if (!::UnhookWindowsHookEx(sCallMouseHook
)) {
7831 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
7833 sCallMouseHook
= NULL
;
7837 // This timer is designed to only fire one time at most each time a "hook" function
7838 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
7839 // hook, but that hook event or a subsequent event may roll up the dropdown before
7840 // this timer function is executed.
7842 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
7843 // before this function fires.
7844 VOID CALLBACK
nsWindow::HookTimerForPopups(HWND hwnd
, UINT uMsg
, UINT idEvent
, DWORD dwTime
)
7846 if (sHookTimerId
!= 0) {
7847 // if the window is NULL then we need to use the ID to kill the timer
7848 BOOL status
= ::KillTimer(NULL
, sHookTimerId
);
7849 NS_ASSERTION(status
, "Hook Timer was not killed.");
7853 if (sRollupMsgId
!= 0) {
7854 // Note: DealWithPopups does the check to make sure that the rollup widget is set.
7855 LRESULT popupHandlingResult
;
7856 nsAutoRollup autoRollup
;
7857 DealWithPopups(sRollupMsgWnd
, sRollupMsgId
, 0, 0, &popupHandlingResult
);
7859 sRollupMsgWnd
= NULL
;
7863 BOOL CALLBACK
nsWindow::ClearResourcesCallback(HWND aWnd
, LPARAM aMsg
)
7865 nsWindow
*window
= WinUtils::GetNSWindowPtr(aWnd
);
7867 window
->ClearCachedResources();
7873 nsWindow::ClearCachedResources()
7875 #ifdef CAIRO_HAS_D2D_SURFACE
7876 mD2DWindowSurface
= nullptr;
7878 if (mLayerManager
&&
7879 mLayerManager
->GetBackendType() == LAYERS_BASIC
) {
7880 static_cast<BasicLayerManager
*>(mLayerManager
.get())->
7881 ClearCachedResources();
7883 ::EnumChildWindows(mWnd
, nsWindow::ClearResourcesCallback
, 0);
7886 static bool IsDifferentThreadWindow(HWND aWnd
)
7888 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd
, NULL
);
7892 nsWindow::EventIsInsideWindow(UINT Msg
, nsWindow
* aWindow
)
7896 if (Msg
== WM_ACTIVATEAPP
)
7897 // don't care about activation/deactivation
7900 ::GetWindowRect(aWindow
->mWnd
, &r
);
7901 DWORD pos
= ::GetMessagePos();
7903 mp
.x
= GET_X_LPARAM(pos
);
7904 mp
.y
= GET_Y_LPARAM(pos
);
7906 // was the event inside this window?
7907 return (bool) PtInRect(&r
, mp
);
7910 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
7912 nsWindow::DealWithPopups(HWND inWnd
, UINT inMsg
, WPARAM inWParam
, LPARAM inLParam
, LRESULT
* outResult
)
7914 NS_ASSERTION(outResult
, "Bad outResult");
7916 *outResult
= MA_NOACTIVATE
;
7918 if (!::IsWindowVisible(inWnd
))
7920 nsIRollupListener
* rollupListener
= nsBaseWidget::GetActiveRollupListener();
7921 NS_ENSURE_TRUE(rollupListener
, false);
7922 nsCOMPtr
<nsIWidget
> rollupWidget
= rollupListener
->GetRollupWidget();
7926 inMsg
= WinUtils::GetNativeMessage(inMsg
);
7927 if (inMsg
== WM_LBUTTONDOWN
|| inMsg
== WM_RBUTTONDOWN
|| inMsg
== WM_MBUTTONDOWN
||
7928 inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
|| inMsg
== WM_ACTIVATE
||
7929 (inMsg
== WM_KILLFOCUS
&& IsDifferentThreadWindow((HWND
)inWParam
)) ||
7930 inMsg
== WM_NCRBUTTONDOWN
||
7931 inMsg
== WM_MOVING
||
7932 inMsg
== WM_SIZING
||
7933 inMsg
== WM_NCLBUTTONDOWN
||
7934 inMsg
== WM_NCMBUTTONDOWN
||
7935 inMsg
== WM_MOUSEACTIVATE
||
7936 inMsg
== WM_ACTIVATEAPP
||
7937 inMsg
== WM_MENUSELECT
) {
7938 // Rollup if the event is outside the popup.
7939 bool rollup
= !nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)(rollupWidget
.get()));
7941 if (rollup
&& (inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
)) {
7942 rollup
= rollupListener
->ShouldRollupOnMouseWheelEvent();
7943 *outResult
= MA_ACTIVATE
;
7946 // If we're dealing with menus, we probably have submenus and we don't
7947 // want to rollup if the click is in a parent menu of the current submenu.
7948 uint32_t popupsToRollup
= UINT32_MAX
;
7950 nsAutoTArray
<nsIWidget
*, 5> widgetChain
;
7951 uint32_t sameTypeCount
= rollupListener
->GetSubmenuWidgetChain(&widgetChain
);
7952 for ( uint32_t i
= 0; i
< widgetChain
.Length(); ++i
) {
7953 nsIWidget
* widget
= widgetChain
[i
];
7954 if ( nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)widget
) ) {
7955 // don't roll up if the mouse event occurred within a menu of the
7956 // same type. If the mouse event occurred in a menu higher than
7957 // that, roll up, but pass the number of popups to Rollup so
7958 // that only those of the same type close up.
7959 if (i
< sameTypeCount
) {
7962 popupsToRollup
= sameTypeCount
;
7966 } // foreach parent menu widget
7969 if (inMsg
== WM_MOUSEACTIVATE
) {
7970 // Prevent the click inside the popup from causing a change in window
7971 // activation. Since the popup is shown non-activated, we need to eat
7972 // any requests to activate the window while it is displayed. Windows
7973 // will automatically activate the popup on the mousedown otherwise.
7977 UINT uMsg
= HIWORD(inLParam
);
7978 if (uMsg
== WM_MOUSEMOVE
) {
7979 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
7980 // must be enabled in Windows.
7981 rollup
= rollupListener
->ShouldRollupOnMouseActivate();
7988 // if we've still determined that we should still rollup everything, do it.
7990 // only need to deal with the last rollup for left mouse down events.
7991 NS_ASSERTION(!mLastRollup
, "mLastRollup is null");
7992 bool consumeRollupEvent
=
7993 rollupListener
->Rollup(popupsToRollup
, inMsg
== WM_LBUTTONDOWN
? &mLastRollup
: nullptr);
7994 NS_IF_ADDREF(mLastRollup
);
7996 // Tell hook to stop processing messages
7997 sProcessHook
= false;
7999 sRollupMsgWnd
= NULL
;
8001 // return TRUE tells Windows that the event is consumed,
8002 // false allows the event to be dispatched
8004 // So if we are NOT supposed to be consuming events, let it go through
8005 if (consumeRollupEvent
&& inMsg
!= WM_RBUTTONDOWN
) {
8006 *outResult
= MA_ACTIVATE
;
8008 // However, don't activate panels
8009 if (inMsg
== WM_MOUSEACTIVATE
) {
8010 nsWindow
* activateWindow
= WinUtils::GetNSWindowPtr(inWnd
);
8011 if (activateWindow
) {
8012 nsWindowType wintype
;
8013 activateWindow
->GetWindowType(wintype
);
8014 if (wintype
== eWindowType_popup
&& activateWindow
->PopupType() == ePopupTypePanel
) {
8015 *outResult
= popupsToRollup
!= UINT32_MAX
? MA_NOACTIVATEANDEAT
: MA_NOACTIVATE
;
8021 // if we are only rolling up some popups, don't activate and don't let
8022 // the event go through. This prevents clicks menus higher in the
8023 // chain from opening when a context menu is open
8024 if (popupsToRollup
!= UINT32_MAX
&& inMsg
== WM_MOUSEACTIVATE
) {
8025 *outResult
= MA_NOACTIVATEANDEAT
;
8029 } // if event that might trigger a popup to rollup
8034 /**************************************************************
8035 **************************************************************
8037 ** BLOCK: Misc. utility methods and functions.
8041 **************************************************************
8042 **************************************************************/
8044 // Note that the result of GetTopLevelWindow method can be different from the
8045 // result of WinUtils::GetTopLevelHWND(). The result can be non-floating
8046 // window. Because our top level window may be contained in another window
8047 // which is not managed by us.
8048 nsWindow
* nsWindow::GetTopLevelWindow(bool aStopOnDialogOrPopup
)
8050 nsWindow
* curWindow
= this;
8053 if (aStopOnDialogOrPopup
) {
8054 switch (curWindow
->mWindowType
) {
8055 case eWindowType_dialog
:
8056 case eWindowType_popup
:
8063 // Retrieve the top level parent or owner window
8064 nsWindow
* parentWindow
= curWindow
->GetParentWindow(true);
8069 curWindow
= parentWindow
;
8073 static BOOL CALLBACK
gEnumWindowsProc(HWND hwnd
, LPARAM lParam
)
8076 ::GetWindowThreadProcessId(hwnd
, &pid
);
8077 if (pid
== GetCurrentProcessId() && ::IsWindowVisible(hwnd
))
8079 gWindowsVisible
= true;
8085 bool nsWindow::CanTakeFocus()
8087 gWindowsVisible
= false;
8088 EnumWindows(gEnumWindowsProc
, 0);
8089 if (!gWindowsVisible
) {
8092 HWND fgWnd
= ::GetForegroundWindow();
8097 GetWindowThreadProcessId(fgWnd
, &pid
);
8098 if (pid
== GetCurrentProcessId()) {
8105 void nsWindow::GetMainWindowClass(nsAString
& aClass
)
8107 NS_PRECONDITION(aClass
.IsEmpty(), "aClass should be empty string");
8108 nsresult rv
= Preferences::GetString("ui.window_class_override", &aClass
);
8109 if (NS_FAILED(rv
) || aClass
.IsEmpty()) {
8110 aClass
.AssignASCII(sDefaultMainWindowClass
);
8114 LPARAM
nsWindow::lParamToScreen(LPARAM lParam
)
8117 pt
.x
= GET_X_LPARAM(lParam
);
8118 pt
.y
= GET_Y_LPARAM(lParam
);
8119 ::ClientToScreen(mWnd
, &pt
);
8120 return MAKELPARAM(pt
.x
, pt
.y
);
8123 LPARAM
nsWindow::lParamToClient(LPARAM lParam
)
8126 pt
.x
= GET_X_LPARAM(lParam
);
8127 pt
.y
= GET_Y_LPARAM(lParam
);
8128 ::ScreenToClient(mWnd
, &pt
);
8129 return MAKELPARAM(pt
.x
, pt
.y
);
8132 void nsWindow::PickerOpen()
8134 mPickerDisplayCount
++;
8137 void nsWindow::PickerClosed()
8139 NS_ASSERTION(mPickerDisplayCount
> 0, "mPickerDisplayCount out of sync!");
8140 if (!mPickerDisplayCount
)
8142 mPickerDisplayCount
--;
8143 if (!mPickerDisplayCount
&& mDestroyCalled
) {
8148 /**************************************************************
8149 **************************************************************
8151 ** BLOCK: ChildWindow impl.
8153 ** Child window overrides.
8155 **************************************************************
8156 **************************************************************/
8158 // return the style for a child nsWindow
8159 DWORD
ChildWindow::WindowStyle()
8161 DWORD style
= WS_CLIPCHILDREN
| nsWindow::WindowStyle();
8162 if (!(style
& WS_POPUP
))
8163 style
|= WS_CHILD
; // WS_POPUP and WS_CHILD are mutually exclusive.
8164 VERIFY_WINDOW_STYLE(style
);