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 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * Dean Tessman <dean_tessman@hotmail.com>
25 * Ere Maijala <emaijala@kolumbus.fi>
26 * Mark Hammond <markh@activestate.com>
27 * Michael Lowe <michael.lowe@bigfoot.com>
28 * Peter Bajusz <hyp-x@inf.bme.hu>
29 * Pierre Phaneuf <pp@ludusdesign.com>
30 * Robert O'Callahan <roc+moz@cs.cmu.edu>
31 * Roy Yokoyama <yokoyama@netscape.com>
32 * Makoto Kato <m_kato@ga2.so-net.ne.jp>
33 * Masayuki Nakano <masayuki@d-toybox.com>
34 * Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
35 * Christian Biesinger <cbiesinger@web.de>
36 * Mats Palmgren <matspal@gmail.com>
37 * Ningjie Chen <chenn@email.uc.edu>
38 * Jim Mathies <jmathies@mozilla.com>
39 * Kyle Huey <me@kylehuey.com>
41 * Alternatively, the contents of this file may be used under the terms of
42 * either the GNU General Public License Version 2 or later (the "GPL"), or
43 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
44 * in which case the provisions of the GPL or the LGPL are applicable instead
45 * of those above. If you wish to allow use of your version of this file only
46 * under the terms of either the GPL or the LGPL, and not to allow others to
47 * use your version of this file under the terms of the MPL, indicate your
48 * decision by deleting the provisions above and replace them with the notice
49 * and other provisions required by the GPL or the LGPL. If you do not delete
50 * the provisions above, a recipient may use your version of this file under
51 * the terms of any one of the MPL, the GPL or the LGPL.
53 * ***** END LICENSE BLOCK ***** */
56 * nsWindow - Native window management and event handling.
58 * nsWindow is organized into a set of major blocks and
59 * block subsections. The layout is as follows:
64 * nsIWidget methods and utilities
65 * nsSwitchToUIThread impl.
66 * nsSwitchToUIThread methods and utilities
68 * Event initialization
73 * OnEvent event handlers
74 * IME management and accessibility
80 * Search for "BLOCK:" to find major blocks.
81 * Search for "SECTION:" to find specific sections.
83 * Blocks should be split out into separate files if they
84 * become unmanageable.
88 * nsWindowDefs.h - Definitions, macros, structs, enums
90 * nsWindowDbg.h/.cpp - Debug related code and directives.
91 * nsWindowGfx.h/.cpp - Graphics and painting.
92 * nsWindowCE.h/.cpp - WINCE specific code that can be
93 * split out from nsWindow.
97 /**************************************************************
98 **************************************************************
104 **************************************************************
105 **************************************************************/
108 #include "mozilla/ipc/RPCChannel.h"
111 #include "nsWindow.h"
115 #include <commctrl.h>
123 #include "nsIAppShell.h"
124 #include "nsISupportsPrimitives.h"
125 #include "nsIDOMNSUIEvent.h"
126 #include "nsITheme.h"
127 #include "nsIPrefBranch.h"
128 #include "nsIPrefBranch2.h"
129 #include "nsIPrefService.h"
130 #include "nsIObserverService.h"
131 #include "nsIScreenManager.h"
132 #include "imgIContainer.h"
134 #include "nsIRollupListener.h"
135 #include "nsIMenuRollup.h"
136 #include "nsIRegion.h"
137 #include "nsIServiceManager.h"
138 #include "nsIClipboard.h"
139 #include "nsIMM32Handler.h"
140 #include "nsILocalFile.h"
141 #include "nsIFontMetrics.h"
142 #include "nsIFontEnumerator.h"
143 #include "nsIDeviceContext.h"
144 #include "nsILookAndFeel.h"
145 #include "nsGUIEvent.h"
148 #include "nsThreadUtils.h"
149 #include "nsNativeCharsetUtils.h"
150 #include "nsWidgetAtoms.h"
151 #include "nsUnicharUtils.h"
153 #include "nsAppDirectoryServiceDefs.h"
154 #include "nsXPIDLString.h"
155 #include "nsWidgetsCID.h"
156 #include "nsTHashtable.h"
157 #include "nsHashKeys.h"
158 #include "nsString.h"
159 #include "mozilla/Services.h"
160 #include "nsNativeThemeWin.h"
163 #include "nsWindowCE.h"
166 #if defined(WINCE_WINDOWS_MOBILE)
167 #define KILL_PRIORITY_ID 2444
170 #include "nsWindowGfx.h"
171 #include "gfxWindowsPlatform.h"
174 #ifdef MOZ_ENABLE_D3D9_LAYER
175 #include "LayerManagerD3D9.h"
177 #ifdef MOZ_ENABLE_D3D10_LAYER
178 #include "LayerManagerD3D10.h"
180 #include "LayerManagerOGL.h"
182 #include "BasicLayers.h"
185 #include "nsUXThemeConstants.h"
186 #include "KeyboardLayout.h"
187 #include "nsNativeDragTarget.h"
188 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
191 #include <richedit.h>
192 #endif // !defined(WINCE)
194 #if defined(ACCESSIBILITY)
197 #include "nsIAccessibleDocument.h"
198 #if !defined(WINABLEAPI)
200 #endif // !defined(WINABLEAPI)
201 #endif // defined(ACCESSIBILITY)
203 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
204 #include "nsIWinTaskbar.h"
207 #if defined(NS_ENABLE_TSF)
208 #include "nsTextStore.h"
209 #endif // defined(NS_ENABLE_TSF)
211 #if defined(MOZ_SPLASHSCREEN)
212 #include "nsSplashScreen.h"
213 #endif // defined(MOZ_SPLASHSCREEN)
215 // Windowless plugin support
218 #include "nsWindowDefs.h"
220 #include "mozilla/FunctionTimer.h"
222 #ifdef WINCE_WINDOWS_MOBILE
223 #include "nsGfxCIID.h"
226 #include "mozilla/FunctionTimer.h"
228 #ifdef MOZ_CRASHREPORTER
229 #include "nsICrashReporter.h"
232 #include "nsIXULRuntime.h"
234 using namespace mozilla::widget
;
236 /**************************************************************
237 **************************************************************
241 ** nsWindow Class static initializations and global variables.
243 **************************************************************
244 **************************************************************/
246 /**************************************************************
248 * SECTION: nsWindow statics
250 **************************************************************/
252 PRUint32
nsWindow::sInstanceCount
= 0;
253 PRBool
nsWindow::sSwitchKeyboardLayout
= PR_FALSE
;
254 BOOL
nsWindow::sIsRegistered
= FALSE
;
255 BOOL
nsWindow::sIsPopupClassRegistered
= FALSE
;
256 BOOL
nsWindow::sIsOleInitialized
= FALSE
;
257 HCURSOR
nsWindow::sHCursor
= NULL
;
258 imgIContainer
* nsWindow::sCursorImgContainer
= nsnull
;
259 nsWindow
* nsWindow::sCurrentWindow
= nsnull
;
260 PRBool
nsWindow::sJustGotDeactivate
= PR_FALSE
;
261 PRBool
nsWindow::sJustGotActivate
= PR_FALSE
;
263 // imported in nsWidgetFactory.cpp
264 TriStateBool
nsWindow::sCanQuit
= TRI_UNKNOWN
;
266 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
267 // hook methods whether they should be processing the hook
269 HHOOK
nsWindow::sMsgFilterHook
= NULL
;
270 HHOOK
nsWindow::sCallProcHook
= NULL
;
271 HHOOK
nsWindow::sCallMouseHook
= NULL
;
272 PRPackedBool
nsWindow::sProcessHook
= PR_FALSE
;
273 UINT
nsWindow::sRollupMsgId
= 0;
274 HWND
nsWindow::sRollupMsgWnd
= NULL
;
275 UINT
nsWindow::sHookTimerId
= 0;
278 nsIRollupListener
* nsWindow::sRollupListener
= nsnull
;
279 nsIMenuRollup
* nsWindow::sMenuRollup
= nsnull
;
280 nsIWidget
* nsWindow::sRollupWidget
= nsnull
;
281 PRBool
nsWindow::sRollupConsumeEvent
= PR_FALSE
;
283 // Mouse Clicks - static variable definitions for figuring
285 POINT
nsWindow::sLastMousePoint
= {0};
286 POINT
nsWindow::sLastMouseMovePoint
= {0};
287 LONG
nsWindow::sLastMouseDownTime
= 0L;
288 LONG
nsWindow::sLastClickCount
= 0L;
289 BYTE
nsWindow::sLastMouseButton
= 0;
291 // Trim heap on minimize. (initialized, but still true.)
292 int nsWindow::sTrimOnMinimize
= 2;
294 // Default Trackpoint Hack to off
295 PRBool
nsWindow::sTrackPointHack
= PR_FALSE
;
298 BOOL
nsWindow::sIsAccessibilityOn
= FALSE
;
299 // Accessibility wm_getobject handler
300 HINSTANCE
nsWindow::sAccLib
= 0;
301 LPFNLRESULTFROMOBJECT
302 nsWindow::sLresultFromObject
= 0;
303 #endif // ACCESSIBILITY
306 // Used in OOPP plugin focus processing.
307 const PRUnichar
* kOOPPPluginFocusEventId
= L
"OOPP Plugin Focus Widget Event";
308 PRUint32
nsWindow::sOOPPPluginFocusEvent
=
309 RegisterWindowMessageW(kOOPPPluginFocusEventId
);
312 /**************************************************************
314 * SECTION: globals variables
316 **************************************************************/
318 static const char *sScreenManagerContractID
= "@mozilla.org/gfx/screenmanager;1";
321 PRLogModuleInfo
* gWindowsLog
= nsnull
;
325 // Kbd layout. Used throughout character processing.
326 static KeyboardLayout gKbdLayout
;
329 #ifdef WINCE_WINDOWS_MOBILE
330 // HTC Navigation Wheel Event
331 // This is the defined value for Gesture Mode
332 const int WM_HTCNAV
= 0x0400 + 200;
334 typedef int (__stdcall
* HTCApiNavOpen
)(HANDLE
, int);
335 typedef int (__stdcall
* HTCApiNavSetMode
)(HANDLE
, unsigned int);
337 HTCApiNavOpen gHTCApiNavOpen
= nsnull
;
338 HTCApiNavSetMode gHTCApiNavSetMode
= nsnull
;
339 static PRBool gCheckForHTCApi
= PR_FALSE
;
342 // Global user preference for disabling native theme. Used
343 // in NativeWindowTheme.
344 PRBool gDisableNativeTheme
= PR_FALSE
;
346 // Global used in Show window enumerations.
347 static PRBool gWindowsVisible
= PR_FALSE
;
349 static NS_DEFINE_CID(kCClipboardCID
, NS_CLIPBOARD_CID
);
350 #ifdef WINCE_WINDOWS_MOBILE
351 static NS_DEFINE_CID(kRegionCID
, NS_REGION_CID
);
354 /**************************************************************
355 **************************************************************
357 ** BLOCK: nsIWidget impl.
359 ** nsIWidget interface implementation, broken down into
362 **************************************************************
363 **************************************************************/
365 /**************************************************************
367 * SECTION: nsWindow construction and destruction
369 **************************************************************/
371 nsWindow::nsWindow() : nsBaseWidget()
375 gWindowsLog
= PR_NewLogModule("nsWindowsWidgets");
380 mPrevWndProc
= nsnull
;
382 mNativeDragTarget
= nsnull
;
384 mIsVisible
= PR_FALSE
;
385 mIsInMouseCapture
= PR_FALSE
;
386 mIsTopWidgetWindow
= PR_FALSE
;
387 mUnicodeWidget
= PR_TRUE
;
388 mDisplayPanFeedback
= PR_FALSE
;
389 mTouchWindow
= PR_FALSE
;
390 mCustomNonClient
= PR_FALSE
;
391 mHideChrome
= PR_FALSE
;
392 mFullscreenMode
= PR_FALSE
;
393 mWindowType
= eWindowType_child
;
394 mBorderStyle
= eBorderStyle_default
;
395 mPopupType
= ePopupTypeAny
;
396 mOldSizeMode
= nsSizeMode_Normal
;
400 mLastSize
.height
= 0;
404 mExitToNonClientArea
= 0;
405 mLastKeyboardLayout
= 0;
406 mBlurSuppressLevel
= 0;
407 mIMEEnabled
= nsIWidget::IME_STATUS_ENABLED
;
409 mTransparentSurface
= nsnull
;
411 mTransparencyMode
= eTransparencyOpaque
;
412 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
413 memset(&mGlassMargins
, 0, sizeof mGlassMargins
);
414 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
416 mBackground
= ::GetSysColor(COLOR_BTNFACE
);
417 mBrush
= ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground
));
418 mForeground
= ::GetSysColor(COLOR_WINDOWTEXT
);
420 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
421 mTaskbarPreview
= nsnull
;
422 mHasTaskbarIconBeenCreated
= PR_FALSE
;
425 // Global initialization
426 if (!sInstanceCount
) {
428 gKbdLayout
.LoadLayout(::GetKeyboardLayout(0));
432 nsIMM32Handler::Initialize();
435 nsTextStore::Initialize();
439 if (SUCCEEDED(::OleInitialize(NULL
)))
440 sIsOleInitialized
= TRUE
;
441 NS_ASSERTION(sIsOleInitialized
, "***** OLE is not initialized!\n");
445 InitTrackPointHack();
448 // Init titlebar button info for custom frames.
449 nsUXThemeData::InitTitlebarInfo();
452 mIdleService
= nsnull
;
457 nsWindow::~nsWindow()
461 // If the widget was released without calling Destroy() then the native window still
462 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
464 // XXX How could this happen???
471 if (sInstanceCount
== 0) {
473 nsTextStore::Terminate();
477 NS_IF_RELEASE(sCursorImgContainer
);
478 if (sIsOleInitialized
) {
479 ::OleFlushClipboard();
481 sIsOleInitialized
= FALSE
;
483 // delete any of the IME structures that we allocated
484 nsIMM32Handler::Terminate();
485 #endif // !defined(WINCE)
489 NS_IF_RELEASE(mNativeDragTarget
);
490 #endif // !defined(WINCE)
493 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow
, nsBaseWidget
)
495 /**************************************************************
497 * SECTION: nsIWidget::Create, nsIWidget::Destroy
499 * Creating and destroying windows for this widget.
501 **************************************************************/
503 // Allow Derived classes to modify the height that is passed
504 // when the window is created or resized. Also add extra height
505 // if needed (on Windows CE)
506 PRInt32
nsWindow::GetHeight(PRInt32 aProposedHeight
)
510 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
511 DWORD style
= WindowStyle();
512 if ((style
& WS_SYSMENU
) && (style
& WS_POPUP
)) {
513 extra
= GetSystemMetrics(SM_CYCAPTION
);
517 return aProposedHeight
+ extra
;
520 // Create the proper widget
522 nsWindow::Create(nsIWidget
*aParent
,
523 nsNativeWidget aNativeParent
,
524 const nsIntRect
&aRect
,
525 EVENT_CALLBACK aHandleEventFunction
,
526 nsIDeviceContext
*aContext
,
527 nsIAppShell
*aAppShell
,
528 nsIToolkit
*aToolkit
,
529 nsWidgetInitData
*aInitData
)
531 nsWidgetInitData defaultInitData
;
533 aInitData
= &defaultInitData
;
535 mUnicodeWidget
= aInitData
->mUnicode
;
537 nsIWidget
*baseParent
= aInitData
->mWindowType
== eWindowType_dialog
||
538 aInitData
->mWindowType
== eWindowType_toplevel
||
539 aInitData
->mWindowType
== eWindowType_invisible
?
542 mIsTopWidgetWindow
= (nsnull
== baseParent
);
543 mBounds
.width
= aRect
.width
;
544 mBounds
.height
= aRect
.height
;
546 BaseCreate(baseParent
, aRect
, aHandleEventFunction
, aContext
,
547 aAppShell
, aToolkit
, aInitData
);
550 if (aParent
) { // has a nsIWidget parent
551 parent
= aParent
? (HWND
)aParent
->GetNativeData(NS_NATIVE_WINDOW
) : NULL
;
553 } else { // has a nsNative parent
554 parent
= (HWND
)aNativeParent
;
555 mParent
= aNativeParent
? GetNSWindowPtr((HWND
)aNativeParent
) : nsnull
;
558 mPopupType
= aInitData
->mPopupHint
;
559 mIsRTL
= aInitData
->mRTL
;
561 DWORD style
= WindowStyle();
562 DWORD extendedStyle
= WindowExStyle();
564 if (mWindowType
== eWindowType_popup
) {
567 } else if (mWindowType
== eWindowType_invisible
) {
568 // Make sure CreateWindowEx succeeds at creating a toplevel window
569 style
&= ~0x40000000; // WS_CHILDWINDOW
571 // See if the caller wants to explictly set clip children and clip siblings
572 if (aInitData
->clipChildren
) {
573 style
|= WS_CLIPCHILDREN
;
575 style
&= ~WS_CLIPCHILDREN
;
577 if (aInitData
->clipSiblings
) {
578 style
|= WS_CLIPSIBLINGS
;
582 mWnd
= ::CreateWindowExW(extendedStyle
,
583 aInitData
->mDropShadow
?
584 WindowPopupClass() : WindowClass(),
590 GetHeight(aRect
.height
),
593 nsToolkit::mDllInstance
,
597 NS_WARNING("nsWindow CreateWindowEx failed.");
598 return NS_ERROR_FAILURE
;
601 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
602 if (mIsRTL
&& nsUXThemeData::dwmSetWindowAttributePtr
) {
603 DWORD dwAttribute
= TRUE
;
604 nsUXThemeData::dwmSetWindowAttributePtr(mWnd
, DWMWA_NONCLIENT_RTL_LAYOUT
, &dwAttribute
, sizeof dwAttribute
);
608 if (nsWindow::sTrackPointHack
&&
609 mWindowType
!= eWindowType_plugin
&&
610 mWindowType
!= eWindowType_invisible
) {
611 // Ugly Thinkpad Driver Hack (Bug 507222)
612 // We create an invisible scrollbar to trick the
613 // Trackpoint driver into sending us scrolling messages
614 ::CreateWindowW(L
"SCROLLBAR", L
"FAKETRACKPOINTSCROLLBAR",
615 WS_CHILD
| WS_VISIBLE
, 0,0,0,0, mWnd
, NULL
,
616 nsToolkit::mDllInstance
, NULL
);
619 // call the event callback to notify about creation
621 DispatchStandardEvent(NS_CREATE
);
622 SubclassWindow(TRUE
);
624 if (sTrimOnMinimize
== 2 && mWindowType
== eWindowType_invisible
) {
625 /* The internal variable set by the config.trim_on_minimize pref
626 has not yet been initialized, and this is the hidden window
627 (conveniently created before any visible windows, and after
628 the profile has been initialized).
630 Default config.trim_on_minimize to false, to fix bug 76831
631 for good. If anyone complains about this new default, saying
632 that a Mozilla app hogs too much memory while minimized, they
633 will have that entire bug tattooed on their backside. */
636 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
638 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
639 prefs
->GetBranch(0, getter_AddRefs(prefBranch
));
643 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("config.trim_on_minimize",
648 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("intl.keyboard.per_window_layout",
650 sSwitchKeyboardLayout
= temp
;
652 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("mozilla.widget.disable-native-theme",
654 gDisableNativeTheme
= temp
;
658 #if defined(WINCE_HAVE_SOFTKB)
659 if (mWindowType
== eWindowType_dialog
|| mWindowType
== eWindowType_toplevel
)
660 nsWindowCE::CreateSoftKeyMenuBar(mWnd
);
666 // Close this nsWindow
667 NS_METHOD
nsWindow::Destroy()
669 // WM_DESTROY has already fired, we're done.
673 // During the destruction of all of our children, make sure we don't get deleted.
674 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
677 * On windows the LayerManagerOGL destructor wants the widget to be around for
678 * cleanup. It also would like to have the HWND intact, so we NULL it here.
681 mLayerManager
->Destroy();
683 mLayerManager
= nsnull
;
685 /* We should clear our cached resources now and not wait for the GC to
686 * delete the nsWindow. */
687 ClearCachedResources();
689 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
690 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
691 // from it. The function also destroys the window's menu, flushes the thread message queue,
692 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
693 // the window is at the top of the viewer chain).
695 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
696 // the associated child or owned windows when it destroys the parent or owner window. The
697 // function first destroys child or owned windows, and then it destroys the parent or owner
699 VERIFY(::DestroyWindow(mWnd
));
701 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
702 // didn't get called, call it now.
703 if (PR_FALSE
== mOnDestroyCalled
)
709 /**************************************************************
711 * SECTION: Window class utilities
713 * Utilities for calculating the proper window class name for
716 **************************************************************/
718 // Return the proper window class for everything except popups.
719 LPCWSTR
nsWindow::WindowClass()
721 if (!nsWindow::sIsRegistered
) {
724 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
725 wc
.style
= CS_DBLCLKS
;
726 wc
.lpfnWndProc
= ::DefWindowProcW
;
729 wc
.hInstance
= nsToolkit::mDllInstance
;
730 wc
.hIcon
= ::LoadIconW(::GetModuleHandleW(NULL
), (LPWSTR
)IDI_APPLICATION
);
732 wc
.hbrBackground
= mBrush
;
733 wc
.lpszMenuName
= NULL
;
734 wc
.lpszClassName
= kClassNameHidden
;
736 BOOL succeeded
= ::RegisterClassW(&wc
) != 0 &&
737 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError();
738 nsWindow::sIsRegistered
= succeeded
;
740 wc
.lpszClassName
= kClassNameGeneral
;
741 ATOM generalClassAtom
= ::RegisterClassW(&wc
);
742 if (!generalClassAtom
&&
743 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
744 nsWindow::sIsRegistered
= FALSE
;
747 wc
.lpszClassName
= kClassNameDialog
;
749 if (!::RegisterClassW(&wc
) &&
750 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
751 nsWindow::sIsRegistered
= FALSE
;
755 if (mWindowType
== eWindowType_invisible
) {
756 return kClassNameHidden
;
758 if (mWindowType
== eWindowType_dialog
) {
759 return kClassNameDialog
;
761 return kClassNameGeneral
;
764 // Return the proper popup window class
765 LPCWSTR
nsWindow::WindowPopupClass()
767 if (!nsWindow::sIsPopupClassRegistered
) {
770 wc
.style
= CS_DBLCLKS
| CS_XP_DROPSHADOW
;
771 wc
.lpfnWndProc
= ::DefWindowProcW
;
774 wc
.hInstance
= nsToolkit::mDllInstance
;
775 wc
.hIcon
= ::LoadIconW(::GetModuleHandleW(NULL
), (LPWSTR
)IDI_APPLICATION
);
777 wc
.hbrBackground
= mBrush
;
778 wc
.lpszMenuName
= NULL
;
779 wc
.lpszClassName
= kClassNameDropShadow
;
781 nsWindow::sIsPopupClassRegistered
= ::RegisterClassW(&wc
);
782 if (!nsWindow::sIsPopupClassRegistered
) {
783 // For older versions of Win32 (i.e., not XP), the registration will
784 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
785 wc
.style
= CS_DBLCLKS
;
786 nsWindow::sIsPopupClassRegistered
= ::RegisterClassW(&wc
);
790 return kClassNameDropShadow
;
793 /**************************************************************
795 * SECTION: Window styles utilities
797 * Return the proper windows styles and extended styles.
799 **************************************************************/
801 // Return nsWindow styles
802 #if !defined(WINCE) // implemented in nsWindowCE.cpp
803 DWORD
nsWindow::WindowStyle()
807 switch (mWindowType
) {
808 case eWindowType_plugin
:
809 case eWindowType_child
:
810 style
= WS_OVERLAPPED
;
813 case eWindowType_dialog
:
814 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
| DS_3DLOOK
|
815 DS_MODALFRAME
| WS_CLIPCHILDREN
;
816 if (mBorderStyle
!= eBorderStyle_default
)
817 style
|= WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
;
820 case eWindowType_popup
:
823 style
|= WS_OVERLAPPED
;
828 NS_ERROR("unknown border style");
831 case eWindowType_toplevel
:
832 case eWindowType_invisible
:
833 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
|
834 WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
| WS_CLIPCHILDREN
;
838 if (mBorderStyle
!= eBorderStyle_default
&& mBorderStyle
!= eBorderStyle_all
) {
839 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_border
))
842 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_title
)) {
843 style
&= ~WS_DLGFRAME
;
848 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_close
))
850 // XXX The close box can only be removed by changing the window class,
851 // as far as I know --- roc+moz@cs.cmu.edu
853 if (mBorderStyle
== eBorderStyle_none
||
854 !(mBorderStyle
& (eBorderStyle_menu
| eBorderStyle_close
)))
855 style
&= ~WS_SYSMENU
;
856 // Looks like getting rid of the system menu also does away with the
857 // close box. So, we only get rid of the system menu if you want neither it
858 // nor the close box. How does the Windows "Dialog" window class get just
859 // closebox and no sysmenu? Who knows.
861 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_resizeh
))
862 style
&= ~WS_THICKFRAME
;
864 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_minimize
))
865 style
&= ~WS_MINIMIZEBOX
;
867 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_maximize
))
868 style
&= ~WS_MAXIMIZEBOX
;
870 if (IsPopupWithTitleBar()) {
872 if (mBorderStyle
& eBorderStyle_close
) {
878 VERIFY_WINDOW_STYLE(style
);
881 #endif // !defined(WINCE)
883 // Return nsWindow extended styles
884 DWORD
nsWindow::WindowExStyle()
888 case eWindowType_plugin
:
889 case eWindowType_child
:
892 case eWindowType_dialog
:
893 return WS_EX_WINDOWEDGE
| WS_EX_DLGMODALFRAME
;
895 case eWindowType_popup
:
897 DWORD extendedStyle
=
898 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
902 if (mPopupLevel
== ePopupLevelTop
)
903 extendedStyle
|= WS_EX_TOPMOST
;
904 return extendedStyle
;
907 NS_ERROR("unknown border style");
910 case eWindowType_toplevel
:
911 case eWindowType_invisible
:
912 return WS_EX_WINDOWEDGE
;
916 /**************************************************************
918 * SECTION: Window subclassing utilities
920 * Set or clear window subclasses on native windows. Used in
921 * Create and Destroy.
923 **************************************************************/
925 // Subclass (or remove the subclass from) this component's nsWindow
926 void nsWindow::SubclassWindow(BOOL bState
)
929 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
930 if (!::IsWindow(mWnd
)) {
931 NS_ERROR("Invalid window handle");
935 // change the nsWindow proc
937 mPrevWndProc
= (WNDPROC
)::SetWindowLongPtrW(mWnd
, GWLP_WNDPROC
,
938 (LONG_PTR
)nsWindow::WindowProc
);
940 mPrevWndProc
= (WNDPROC
)::SetWindowLongPtrA(mWnd
, GWLP_WNDPROC
,
941 (LONG_PTR
)nsWindow::WindowProc
);
942 NS_ASSERTION(mPrevWndProc
, "Null standard window procedure");
943 // connect the this pointer to the nsWindow handle
944 SetNSWindowPtr(mWnd
, this);
948 ::SetWindowLongPtrW(mWnd
, GWLP_WNDPROC
, (LONG_PTR
)mPrevWndProc
);
950 ::SetWindowLongPtrA(mWnd
, GWLP_WNDPROC
, (LONG_PTR
)mPrevWndProc
);
951 SetNSWindowPtr(mWnd
, NULL
);
957 /**************************************************************
959 * SECTION: Window properties
961 * Set and clear native window properties.
963 **************************************************************/
965 static PRUnichar sPropName
[40] = L
"";
966 static PRUnichar
* GetNSWindowPropName()
970 _snwprintf(sPropName
, 39, L
"MozillansIWidgetPtr%p", GetCurrentProcessId());
971 sPropName
[39] = '\0';
976 nsWindow
* nsWindow::GetNSWindowPtr(HWND aWnd
)
978 return (nsWindow
*) ::GetPropW(aWnd
, GetNSWindowPropName());
981 BOOL
nsWindow::SetNSWindowPtr(HWND aWnd
, nsWindow
* ptr
)
984 ::RemovePropW(aWnd
, GetNSWindowPropName());
987 return ::SetPropW(aWnd
, GetNSWindowPropName(), (HANDLE
)ptr
);
991 /**************************************************************
993 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
995 * Set or clear the parent widgets using window properties, and
996 * handles calculating native parent handles.
998 **************************************************************/
1000 // Get and set parent widgets
1001 NS_IMETHODIMP
nsWindow::SetParent(nsIWidget
*aNewParent
)
1003 mParent
= aNewParent
;
1005 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
1006 nsIWidget
* parent
= GetParent();
1008 parent
->RemoveChild(this);
1011 ReparentNativeWidget(aNewParent
);
1012 aNewParent
->AddChild(this);
1016 // If we have no parent, SetParent should return the desktop.
1017 VERIFY(::SetParent(mWnd
, nsnull
));
1023 nsWindow::ReparentNativeWidget(nsIWidget
* aNewParent
)
1025 NS_PRECONDITION(aNewParent
, "");
1027 mParent
= aNewParent
;
1028 if (mWindowType
== eWindowType_popup
) {
1031 HWND newParent
= (HWND
)aNewParent
->GetNativeData(NS_NATIVE_WINDOW
);
1032 NS_ASSERTION(newParent
, "Parent widget has a null native window handle");
1033 if (newParent
&& mWnd
) {
1034 ::SetParent(mWnd
, newParent
);
1039 nsIWidget
* nsWindow::GetParent(void)
1041 return GetParentWindow(PR_FALSE
);
1044 float nsWindow::GetDPI()
1046 HDC dc
= ::GetDC(mWnd
);
1050 double heightInches
= ::GetDeviceCaps(dc
, VERTSIZE
)/MM_PER_INCH_FLOAT
;
1051 int heightPx
= ::GetDeviceCaps(dc
, VERTRES
);
1052 ::ReleaseDC(mWnd
, dc
);
1053 if (heightInches
< 0.25) {
1054 // Something's broken
1057 return float(heightPx
/heightInches
);
1060 nsWindow
* nsWindow::GetParentWindow(PRBool aIncludeOwner
)
1062 if (mIsTopWidgetWindow
) {
1063 // Must use a flag instead of mWindowType to tell if the window is the
1064 // owned by the topmost widget, because a child window can be embedded inside
1065 // a HWND which is not associated with a nsIWidget.
1069 // If this widget has already been destroyed, pretend we have no parent.
1070 // This corresponds to code in Destroy which removes the destroyed
1071 // widget from its parent's child list.
1072 if (mInDtor
|| mOnDestroyCalled
)
1076 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1077 // root owner. aIncludeOwner set to false implies the search will stop at the
1078 // true parent (default).
1079 nsWindow
* widget
= nsnull
;
1082 HWND parent
= ::GetParent(mWnd
);
1084 HWND parent
= nsnull
;
1086 parent
= ::GetParent(mWnd
);
1088 parent
= ::GetAncestor(mWnd
, GA_PARENT
);
1091 widget
= GetNSWindowPtr(parent
);
1093 // If the widget is in the process of being destroyed then
1095 if (widget
->mInDtor
) {
1105 /**************************************************************
1107 * SECTION: nsIWidget::Show
1109 * Hide or show this component.
1111 **************************************************************/
1113 NS_METHOD
nsWindow::Show(PRBool bState
)
1115 #if defined(MOZ_SPLASHSCREEN)
1116 // we're about to show the first toplevel window,
1117 // so kill off any splash screen if we had one
1118 nsSplashScreen
*splash
= nsSplashScreen::Get();
1119 if (splash
&& splash
->IsOpen() && mWnd
&& bState
&&
1120 (mWindowType
== eWindowType_toplevel
||
1121 mWindowType
== eWindowType_dialog
||
1122 mWindowType
== eWindowType_popup
))
1128 #ifdef NS_FUNCTION_TIMER
1129 static bool firstShow
= true;
1131 (mWindowType
== eWindowType_toplevel
||
1132 mWindowType
== eWindowType_dialog
||
1133 mWindowType
== eWindowType_popup
))
1136 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1140 PRBool wasVisible
= mIsVisible
;
1141 // Set the status now so that anyone asking during ShowWindow or
1142 // SetWindowPos would get the correct answer.
1143 mIsVisible
= bState
;
1145 if (!mIsVisible
&& wasVisible
) {
1146 ClearCachedResources();
1151 if (!wasVisible
&& mWindowType
== eWindowType_toplevel
) {
1152 switch (mSizeMode
) {
1154 case nsSizeMode_Fullscreen
:
1155 ::SetForegroundWindow(mWnd
);
1156 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1157 MakeFullScreen(TRUE
);
1160 case nsSizeMode_Maximized
:
1161 ::SetForegroundWindow(mWnd
);
1162 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1164 // use default for nsSizeMode_Minimized on Windows CE
1166 case nsSizeMode_Maximized
:
1167 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1169 case nsSizeMode_Minimized
:
1170 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
1174 if (CanTakeFocus()) {
1176 ::SetForegroundWindow(mWnd
);
1178 ::ShowWindow(mWnd
, SW_SHOWNORMAL
);
1180 // Place the window behind the foreground window
1181 // (as long as it is not topmost)
1182 HWND wndAfter
= ::GetForegroundWindow();
1184 wndAfter
= HWND_BOTTOM
;
1185 else if (GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
1186 wndAfter
= HWND_TOP
;
1187 ::SetWindowPos(mWnd
, wndAfter
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOSIZE
|
1188 SWP_NOMOVE
| SWP_NOACTIVATE
);
1194 DWORD flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_SHOWWINDOW
;
1196 flags
|= SWP_NOZORDER
;
1198 if (mWindowType
== eWindowType_popup
) {
1200 // ensure popups are the topmost of the TOPMOST
1201 // layer. Remember not to set the SWP_NOZORDER
1202 // flag as that might allow the taskbar to overlap
1203 // the popup. However on windows ce, we need to
1204 // activate the popup or clicks will not be sent.
1205 flags
|= SWP_NOACTIVATE
;
1207 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
1208 ::SetWindowPos(mWnd
, owner
? 0 : HWND_TOPMOST
, 0, 0, 0, 0, flags
);
1211 if (mWindowType
== eWindowType_dialog
&& !CanTakeFocus())
1212 flags
|= SWP_NOACTIVATE
;
1214 ::SetWindowPos(mWnd
, HWND_TOP
, 0, 0, 0, 0, flags
);
1219 if (!wasVisible
&& (mWindowType
== eWindowType_toplevel
|| mWindowType
== eWindowType_dialog
)) {
1220 // when a toplevel window or dialog is shown, initialize the UI state
1221 ::SendMessageW(mWnd
, WM_CHANGEUISTATE
, MAKEWPARAM(UIS_INITIALIZE
, UISF_HIDEFOCUS
| UISF_HIDEACCEL
), 0);
1225 if (mWindowType
!= eWindowType_dialog
) {
1226 ::ShowWindow(mWnd
, SW_HIDE
);
1228 ::SetWindowPos(mWnd
, 0, 0, 0, 0, 0, SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
|
1229 SWP_NOZORDER
| SWP_NOACTIVATE
);
1235 if (!wasVisible
&& bState
)
1236 Invalidate(PR_FALSE
);
1242 /**************************************************************
1244 * SECTION: nsIWidget::IsVisible
1246 * Returns the visibility state.
1248 **************************************************************/
1250 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1251 NS_METHOD
nsWindow::IsVisible(PRBool
& bState
)
1253 bState
= mIsVisible
;
1257 /**************************************************************
1259 * SECTION: Window clipping utilities
1261 * Used in Size and Move operations for setting the proper
1262 * window clipping regions for window transparency.
1264 **************************************************************/
1266 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1267 // transparency. These routines are called on size and move operations.
1268 void nsWindow::ClearThemeRegion()
1271 if (nsUXThemeData::sIsVistaOrLater
&& !HasGlass() &&
1272 (mWindowType
== eWindowType_popup
&& !IsPopupWithTitleBar() &&
1273 (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
))) {
1274 SetWindowRgn(mWnd
, NULL
, false);
1279 void nsWindow::SetThemeRegion()
1282 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1283 // for other window types as needed. The regions are applied generically to the base window
1284 // so default constants are used for part and state. At some point we might need part and
1285 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1286 // change shape based on state haven't come up.
1287 if (nsUXThemeData::sIsVistaOrLater
&& !HasGlass() &&
1288 (mWindowType
== eWindowType_popup
&& !IsPopupWithTitleBar() &&
1289 (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
))) {
1291 RECT rect
= {0,0,mBounds
.width
,mBounds
.height
};
1293 HDC dc
= ::GetDC(mWnd
);
1294 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip
), dc
, TTP_STANDARD
, TS_NORMAL
, &rect
, &hRgn
);
1296 if (!SetWindowRgn(mWnd
, hRgn
, false)) // do not delete or alter hRgn if accepted.
1299 ::ReleaseDC(mWnd
, dc
);
1304 /**************************************************************
1306 * SECTION: nsIWidget::RegisterTouchWindow,
1307 * nsIWidget::UnregisterTouchWindow, and helper functions
1309 * Used to register the native window to receive touch events
1311 **************************************************************/
1313 NS_METHOD
nsWindow::RegisterTouchWindow() {
1314 mTouchWindow
= PR_TRUE
;
1316 mGesture
.RegisterTouchWindow(mWnd
);
1317 ::EnumChildWindows(mWnd
, nsWindow::RegisterTouchForDescendants
, 0);
1322 NS_METHOD
nsWindow::UnregisterTouchWindow() {
1323 mTouchWindow
= PR_FALSE
;
1325 mGesture
.UnregisterTouchWindow(mWnd
);
1326 ::EnumChildWindows(mWnd
, nsWindow::UnregisterTouchForDescendants
, 0);
1332 BOOL CALLBACK
nsWindow::RegisterTouchForDescendants(HWND aWnd
, LPARAM aMsg
) {
1333 nsWindow
* win
= GetNSWindowPtr(aWnd
);
1335 win
->mGesture
.RegisterTouchWindow(aWnd
);
1339 BOOL CALLBACK
nsWindow::UnregisterTouchForDescendants(HWND aWnd
, LPARAM aMsg
) {
1340 nsWindow
* win
= GetNSWindowPtr(aWnd
);
1342 win
->mGesture
.UnregisterTouchWindow(aWnd
);
1347 /**************************************************************
1349 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1350 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1352 * Repositioning and sizing a window.
1354 **************************************************************/
1356 // Move this component
1357 NS_METHOD
nsWindow::Move(PRInt32 aX
, PRInt32 aY
)
1359 if (mWindowType
== eWindowType_toplevel
||
1360 mWindowType
== eWindowType_dialog
) {
1361 SetSizeMode(nsSizeMode_Normal
);
1363 // Check to see if window needs to be moved first
1364 // to avoid a costly call to SetWindowPos. This check
1365 // can not be moved to the calling code in nsView, because
1366 // some platforms do not position child windows correctly
1368 // Only perform this check for non-popup windows, since the positioning can
1369 // in fact change even when the x/y do not. We always need to perform the
1370 // check. See bug #97805 for details.
1371 if (mWindowType
!= eWindowType_popup
&& (mBounds
.x
== aX
) && (mBounds
.y
== aY
))
1373 // Nothing to do, since it is already positioned correctly.
1382 // complain if a window is moved offscreen (legal, but potentially worrisome)
1383 if (mIsTopWidgetWindow
) { // only a problem for top-level windows
1384 // Make sure this window is actually on the screen before we move it
1385 // XXX: Needs multiple monitor support
1386 HDC dc
= ::GetDC(mWnd
);
1388 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1390 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &workArea
, 0);
1391 // no annoying assertions. just mention the issue.
1392 if (aX
< 0 || aX
>= workArea
.right
|| aY
< 0 || aY
>= workArea
.bottom
)
1393 printf("window moved to offscreen position\n");
1395 ::ReleaseDC(mWnd
, dc
);
1400 VERIFY(::SetWindowPos(mWnd
, NULL
, aX
, aY
, 0, 0,
1401 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOSIZE
));
1407 // Resize this component
1408 NS_METHOD
nsWindow::Resize(PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1410 NS_ASSERTION((aWidth
>=0 ) , "Negative width passed to nsWindow::Resize");
1411 NS_ASSERTION((aHeight
>=0 ), "Negative height passed to nsWindow::Resize");
1413 // Avoid unnecessary resizing calls
1414 if (mBounds
.width
== aWidth
&& mBounds
.height
== aHeight
&& !aRepaint
)
1418 if (eTransparencyTransparent
== mTransparencyMode
)
1419 ResizeTranslucentWindow(aWidth
, aHeight
);
1422 // Set cached value for lightweight and printing
1423 mBounds
.width
= aWidth
;
1424 mBounds
.height
= aHeight
;
1427 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOMOVE
;
1431 flags
|= SWP_NOREDRAW
;
1436 VERIFY(::SetWindowPos(mWnd
, NULL
, 0, 0, aWidth
, GetHeight(aHeight
), flags
));
1441 Invalidate(PR_FALSE
);
1446 // Resize this component
1447 NS_METHOD
nsWindow::Resize(PRInt32 aX
, PRInt32 aY
, PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1449 NS_ASSERTION((aWidth
>=0 ), "Negative width passed to nsWindow::Resize");
1450 NS_ASSERTION((aHeight
>=0 ), "Negative height passed to nsWindow::Resize");
1452 // Avoid unnecessary resizing calls
1453 if (mBounds
.x
== aX
&& mBounds
.y
== aY
&&
1454 mBounds
.width
== aWidth
&& mBounds
.height
== aHeight
&& !aRepaint
)
1458 if (eTransparencyTransparent
== mTransparencyMode
)
1459 ResizeTranslucentWindow(aWidth
, aHeight
);
1462 // Set cached value for lightweight and printing
1465 mBounds
.width
= aWidth
;
1466 mBounds
.height
= aHeight
;
1469 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
1472 flags
|= SWP_NOREDRAW
;
1477 VERIFY(::SetWindowPos(mWnd
, NULL
, aX
, aY
, aWidth
, GetHeight(aHeight
), flags
));
1482 Invalidate(PR_FALSE
);
1487 // Resize the client area and position the widget within it's parent
1488 NS_METHOD
nsWindow::ResizeClient(PRInt32 aX
, PRInt32 aY
, PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1490 NS_ASSERTION((aWidth
>=0) , "Negative width passed to ResizeClient");
1491 NS_ASSERTION((aHeight
>=0), "Negative height passed to ResizeClient");
1493 // Adjust our existing window bounds, based on the new client dims.
1495 GetClientRect(mWnd
, &client
);
1496 nsIntPoint
dims(client
.right
- client
.left
, client
.bottom
- client
.top
);
1497 aWidth
= mBounds
.width
+ (aWidth
- dims
.x
);
1498 aHeight
= mBounds
.height
+ (aHeight
- dims
.y
);
1503 GetScreenBounds(bounds
);
1506 return Resize(aX
, aY
, aWidth
, aHeight
, aRepaint
);
1508 return Resize(aWidth
, aHeight
, aRepaint
);
1513 nsWindow::BeginResizeDrag(nsGUIEvent
* aEvent
, PRInt32 aHorizontal
, PRInt32 aVertical
)
1515 NS_ENSURE_ARG_POINTER(aEvent
);
1517 if (aEvent
->eventStructType
!= NS_MOUSE_EVENT
) {
1518 // you can only begin a resize drag with a mouse event
1519 return NS_ERROR_INVALID_ARG
;
1522 nsMouseEvent
* mouseEvent
= static_cast<nsMouseEvent
*>(aEvent
);
1523 if (mouseEvent
->button
!= nsMouseEvent::eLeftButton
) {
1524 // you can only begin a resize drag with the left mouse button
1525 return NS_ERROR_INVALID_ARG
;
1528 // work out what sizemode we're talking about
1530 if (aVertical
< 0) {
1531 if (aHorizontal
< 0) {
1532 syscommand
= SC_SIZE
| WMSZ_TOPLEFT
;
1533 } else if (aHorizontal
== 0) {
1534 syscommand
= SC_SIZE
| WMSZ_TOP
;
1536 syscommand
= SC_SIZE
| WMSZ_TOPRIGHT
;
1538 } else if (aVertical
== 0) {
1539 if (aHorizontal
< 0) {
1540 syscommand
= SC_SIZE
| WMSZ_LEFT
;
1541 } else if (aHorizontal
== 0) {
1542 return NS_ERROR_INVALID_ARG
;
1544 syscommand
= SC_SIZE
| WMSZ_RIGHT
;
1547 if (aHorizontal
< 0) {
1548 syscommand
= SC_SIZE
| WMSZ_BOTTOMLEFT
;
1549 } else if (aHorizontal
== 0) {
1550 syscommand
= SC_SIZE
| WMSZ_BOTTOM
;
1552 syscommand
= SC_SIZE
| WMSZ_BOTTOMRIGHT
;
1556 // resizing doesn't work if the mouse is already captured
1557 CaptureMouse(PR_FALSE
);
1559 // find the top-level window
1560 HWND toplevelWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
1562 // tell Windows to start the resize
1563 ::PostMessage(toplevelWnd
, WM_SYSCOMMAND
, syscommand
,
1564 POINTTOPOINTS(aEvent
->refPoint
));
1569 /**************************************************************
1571 * SECTION: Window Z-order and state.
1573 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1574 * nsIWidget::ConstrainPosition
1576 * Z-order, positioning, restore, minimize, and maximize.
1578 **************************************************************/
1580 // Position the window behind the given window
1581 NS_METHOD
nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement
,
1582 nsIWidget
*aWidget
, PRBool aActivate
)
1584 HWND behind
= HWND_TOP
;
1585 if (aPlacement
== eZPlacementBottom
)
1586 behind
= HWND_BOTTOM
;
1587 else if (aPlacement
== eZPlacementBelow
&& aWidget
)
1588 behind
= (HWND
)aWidget
->GetNativeData(NS_NATIVE_WINDOW
);
1589 UINT flags
= SWP_NOMOVE
| SWP_NOREPOSITION
| SWP_NOSIZE
;
1591 flags
|= SWP_NOACTIVATE
;
1593 if (!CanTakeFocus() && behind
== HWND_TOP
)
1595 // Can't place the window to top so place it behind the foreground window
1596 // (as long as it is not topmost)
1597 HWND wndAfter
= ::GetForegroundWindow();
1599 behind
= HWND_BOTTOM
;
1600 else if (!(GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
1602 flags
|= SWP_NOACTIVATE
;
1605 ::SetWindowPos(mWnd
, behind
, 0, 0, 0, 0, flags
);
1609 // Maximize, minimize or restore the window.
1610 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1611 NS_IMETHODIMP
nsWindow::SetSizeMode(PRInt32 aMode
) {
1615 // Let's not try and do anything if we're already in that state.
1616 // (This is needed to prevent problems when calling window.minimize(), which
1617 // calls us directly, and then the OS triggers another call to us.)
1618 if (aMode
== mSizeMode
)
1621 // save the requested state
1622 rv
= nsBaseWidget::SetSizeMode(aMode
);
1623 if (NS_SUCCEEDED(rv
) && mIsVisible
) {
1627 case nsSizeMode_Fullscreen
:
1631 case nsSizeMode_Maximized
:
1635 case nsSizeMode_Minimized
:
1636 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1637 // keeps the window active in the tray. So after the window is minimized,
1638 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1639 // we will do some additional processing to get the active window set right.
1640 // If sTrimOnMinimize is set, we let windows handle minimization normally
1641 // using SW_MINIMIZE.
1642 mode
= sTrimOnMinimize
? SW_MINIMIZE
: SW_SHOWMINIMIZED
;
1648 ::ShowWindow(mWnd
, mode
);
1649 // we dispatch an activate event here to ensure that the right child window
1651 if (mode
== SW_RESTORE
|| mode
== SW_MAXIMIZE
)
1652 DispatchFocusToTopLevelWindow(NS_ACTIVATE
);
1656 #endif // !defined(WINCE)
1658 // Constrain a potential move to fit onscreen
1659 NS_METHOD
nsWindow::ConstrainPosition(PRBool aAllowSlop
,
1660 PRInt32
*aX
, PRInt32
*aY
)
1662 if (!mIsTopWidgetWindow
) // only a problem for top-level windows
1665 PRBool doConstrain
= PR_FALSE
; // whether we have enough info to do anything
1667 /* get our playing field. use the current screen, or failing that
1668 for any reason, use device caps for the default screen. */
1671 nsCOMPtr
<nsIScreenManager
> screenmgr
= do_GetService(sScreenManagerContractID
);
1673 nsCOMPtr
<nsIScreen
> screen
;
1674 PRInt32 left
, top
, width
, height
;
1676 // zero size rects confuse the screen manager
1677 width
= mBounds
.width
> 0 ? mBounds
.width
: 1;
1678 height
= mBounds
.height
> 0 ? mBounds
.height
: 1;
1679 screenmgr
->ScreenForRect(*aX
, *aY
, width
, height
,
1680 getter_AddRefs(screen
));
1682 if (mSizeMode
!= nsSizeMode_Fullscreen
) {
1683 // For normalized windows, use the desktop work area.
1684 screen
->GetAvailRect(&left
, &top
, &width
, &height
);
1686 // For full screen windows, use the desktop.
1687 screen
->GetRect(&left
, &top
, &width
, &height
);
1689 screenRect
.left
= left
;
1690 screenRect
.right
= left
+width
;
1691 screenRect
.top
= top
;
1692 screenRect
.bottom
= top
+height
;
1693 doConstrain
= PR_TRUE
;
1697 HDC dc
= ::GetDC(mWnd
);
1699 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1700 if (mSizeMode
!= nsSizeMode_Fullscreen
) {
1701 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &screenRect
, 0);
1703 screenRect
.left
= screenRect
.top
= 0;
1704 screenRect
.right
= GetSystemMetrics(SM_CXFULLSCREEN
);
1705 screenRect
.bottom
= GetSystemMetrics(SM_CYFULLSCREEN
);
1707 doConstrain
= PR_TRUE
;
1709 ::ReleaseDC(mWnd
, dc
);
1715 if (*aX
< screenRect
.left
- mBounds
.width
+ kWindowPositionSlop
)
1716 *aX
= screenRect
.left
- mBounds
.width
+ kWindowPositionSlop
;
1717 else if (*aX
>= screenRect
.right
- kWindowPositionSlop
)
1718 *aX
= screenRect
.right
- kWindowPositionSlop
;
1720 if (*aY
< screenRect
.top
- mBounds
.height
+ kWindowPositionSlop
)
1721 *aY
= screenRect
.top
- mBounds
.height
+ kWindowPositionSlop
;
1722 else if (*aY
>= screenRect
.bottom
- kWindowPositionSlop
)
1723 *aY
= screenRect
.bottom
- kWindowPositionSlop
;
1727 if (*aX
< screenRect
.left
)
1728 *aX
= screenRect
.left
;
1729 else if (*aX
>= screenRect
.right
- mBounds
.width
)
1730 *aX
= screenRect
.right
- mBounds
.width
;
1732 if (*aY
< screenRect
.top
)
1733 *aY
= screenRect
.top
;
1734 else if (*aY
>= screenRect
.bottom
- mBounds
.height
)
1735 *aY
= screenRect
.bottom
- mBounds
.height
;
1741 /**************************************************************
1743 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1745 * Enabling and disabling the widget.
1747 **************************************************************/
1749 // Enable/disable this component
1750 NS_METHOD
nsWindow::Enable(PRBool bState
)
1753 ::EnableWindow(mWnd
, bState
);
1758 // Return the current enable state
1759 NS_METHOD
nsWindow::IsEnabled(PRBool
*aState
)
1761 NS_ENSURE_ARG_POINTER(aState
);
1764 *aState
= !mWnd
|| (::IsWindowEnabled(mWnd
) && ::IsWindowEnabled(::GetAncestor(mWnd
, GA_ROOT
)));
1766 *aState
= !mWnd
|| (::IsWindowEnabled(mWnd
) && ::IsWindowEnabled(mWnd
));
1773 /**************************************************************
1775 * SECTION: nsIWidget::SetFocus
1777 * Give the focus to this widget.
1779 **************************************************************/
1781 NS_METHOD
nsWindow::SetFocus(PRBool aRaise
)
1784 #ifdef WINSTATE_DEBUG_OUTPUT
1785 if (mWnd
== GetTopLevelHWND(mWnd
))
1786 printf("*** SetFocus: [ top] raise=%d\n", aRaise
);
1788 printf("*** SetFocus: [child] raise=%d\n", aRaise
);
1790 // Uniconify, if necessary
1791 HWND toplevelWnd
= GetTopLevelHWND(mWnd
);
1792 if (aRaise
&& ::IsIconic(toplevelWnd
)) {
1793 ::ShowWindow(toplevelWnd
, SW_RESTORE
);
1801 /**************************************************************
1805 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1806 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1808 * Bound calculations.
1810 **************************************************************/
1812 // Return the window's full dimensions in screen coordinates.
1813 // If the window has a parent, converts the origin to an offset
1814 // of the parent's screen origin.
1815 NS_METHOD
nsWindow::GetBounds(nsIntRect
&aRect
)
1819 VERIFY(::GetWindowRect(mWnd
, &r
));
1822 aRect
.width
= r
.right
- r
.left
;
1823 aRect
.height
= r
.bottom
- r
.top
;
1825 // chrome on parent:
1826 // ___ 5,5 (chrome start)
1827 // | ____ 10,10 (client start)
1828 // | | ____ 20,20 (child start)
1830 // 20,20 - 5,5 = 15,15 (??)
1831 // minus GetClientOffset:
1832 // 15,15 - 5,5 = 10,10
1834 // no chrome on parent:
1835 // ______ 10,10 (win start)
1836 // | ____ 20,20 (child start)
1838 // 20,20 - 10,10 = 10,10
1840 // walking the chain:
1841 // ___ 5,5 (chrome start)
1842 // | ___ 10,10 (client start)
1843 // | | ___ 20,20 (child start)
1844 // | | | __ 30,30 (child start)
1846 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1847 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1848 // minus GetClientOffset:
1849 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1851 // convert coordinates if parent exists
1852 HWND parent
= ::GetParent(mWnd
);
1855 VERIFY(::GetWindowRect(parent
, &pr
));
1858 // adjust for chrome
1859 nsWindow
* pWidget
= static_cast<nsWindow
*>(GetParent());
1860 if (pWidget
&& pWidget
->IsTopLevelWidget()) {
1861 nsIntPoint clientOffset
= pWidget
->GetClientOffset();
1862 r
.left
-= clientOffset
.x
;
1863 r
.top
-= clientOffset
.y
;
1875 // Get this component dimension
1876 NS_METHOD
nsWindow::GetClientBounds(nsIntRect
&aRect
)
1880 VERIFY(::GetClientRect(mWnd
, &r
));
1885 aRect
.width
= r
.right
- r
.left
;
1886 aRect
.height
= r
.bottom
- r
.top
;
1889 aRect
.SetRect(0,0,0,0);
1894 // Like GetBounds, but don't offset by the parent
1895 NS_METHOD
nsWindow::GetScreenBounds(nsIntRect
&aRect
)
1899 VERIFY(::GetWindowRect(mWnd
, &r
));
1901 aRect
.width
= r
.right
- r
.left
;
1902 aRect
.height
= r
.bottom
- r
.top
;
1911 // return the x,y offset of the client area from the origin
1912 // of the window. If the window is borderless returns (0,0).
1913 nsIntPoint
nsWindow::GetClientOffset()
1916 return nsIntPoint(0, 0);
1920 GetWindowRect(mWnd
, &r1
);
1921 nsIntPoint pt
= WidgetToScreenOffset();
1922 return nsIntPoint(pt
.x
- r1
.left
, pt
.y
- r1
.top
);
1926 nsWindow::SetDrawsInTitlebar(PRBool aState
)
1928 nsWindow
* window
= GetTopLevelWindow(PR_TRUE
);
1929 if (window
&& window
!= this) {
1930 return window
->SetDrawsInTitlebar(aState
);
1934 // left, top, right, bottom for nsIntMargin
1935 nsIntMargin
margins(-1, 0, -1, -1);
1936 SetNonClientMargins(margins
);
1939 nsIntMargin
margins(-1, -1, -1, -1);
1940 SetNonClientMargins(margins
);
1945 nsWindow::GetNonClientMargins(nsIntMargin
&margins
)
1947 nsWindow
* window
= GetTopLevelWindow(PR_TRUE
);
1948 if (window
&& window
!= this) {
1949 return window
->GetNonClientMargins(margins
);
1952 if (mCustomNonClient
) {
1953 margins
= mNonClientMargins
;
1957 margins
.top
= GetSystemMetrics(SM_CYCAPTION
);
1958 margins
.bottom
= GetSystemMetrics(SM_CYFRAME
);
1959 margins
.top
+= margins
.bottom
;
1960 margins
.left
= margins
.right
= GetSystemMetrics(SM_CYFRAME
);
1966 nsWindow::ResetLayout()
1968 // This will trigger a frame changed event, triggering
1969 // nc calc size and a sizemode gecko event.
1970 SetWindowPos(mWnd
, 0, 0, 0, 0, 0,
1971 SWP_FRAMECHANGED
|SWP_NOACTIVATE
|SWP_NOMOVE
|
1972 SWP_NOOWNERZORDER
|SWP_NOSIZE
|SWP_NOZORDER
);
1974 // If hidden, just send the frame changed event for now.
1978 // Send a gecko size event to trigger reflow.
1979 RECT clientRc
= {0};
1980 GetClientRect(mWnd
, &clientRc
);
1981 nsIntRect
evRect(nsWindowGfx::ToIntRect(clientRc
));
1984 // Invalidate and update
1985 Invalidate(PR_FALSE
);
1988 // Called when the window layout changes: full screen mode transitions,
1989 // theme changes, and composition changes. Calculates the new non-client
1990 // margins and fires off a frame changed event, which triggers an nc calc
1991 // size windows event, kicking the changes in.
1993 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode
, PRBool aReflowWindow
)
1995 if (!mCustomNonClient
)
1998 mNonClientOffset
.top
= mNonClientOffset
.bottom
=
1999 mNonClientOffset
.left
= mNonClientOffset
.right
= 0;
2001 if (aSizeMode
== -1)
2002 aSizeMode
= mSizeMode
;
2004 if (aSizeMode
== nsSizeMode_Minimized
||
2005 aSizeMode
== nsSizeMode_Fullscreen
) {
2006 mCaptionHeight
= mVertResizeMargin
= mHorResizeMargin
= 0;
2010 // Note, for maximized windows, we need to continue to offset the client by
2011 // thick frame margins of a normal window, since windows expects this
2012 // in it's DwmDefWndProc hit testing.
2013 mCaptionHeight
= GetSystemMetrics(SM_CYCAPTION
);
2014 mHorResizeMargin
= GetSystemMetrics(SM_CXFRAME
);
2015 mVertResizeMargin
= GetSystemMetrics(SM_CYFRAME
);
2017 mCaptionHeight
+= mVertResizeMargin
;
2019 // If a margin value is 0, set the offset to the default size of the frame.
2020 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2021 // so that the frame size is equal to the margin value.
2022 if (!mNonClientMargins
.top
)
2023 mNonClientOffset
.top
= mCaptionHeight
;
2024 else if (mNonClientMargins
.top
> 0)
2025 mNonClientOffset
.top
= mCaptionHeight
- mNonClientMargins
.top
;
2027 if (!mNonClientMargins
.left
)
2028 mNonClientOffset
.left
= mHorResizeMargin
;
2029 else if (mNonClientMargins
.left
> 0)
2030 mNonClientOffset
.left
= mHorResizeMargin
- mNonClientMargins
.left
;
2032 if (!mNonClientMargins
.right
)
2033 mNonClientOffset
.right
= mHorResizeMargin
;
2034 else if (mNonClientMargins
.right
> 0)
2035 mNonClientOffset
.right
= mHorResizeMargin
- mNonClientMargins
.right
;
2037 if (!mNonClientMargins
.bottom
)
2038 mNonClientOffset
.bottom
= mVertResizeMargin
;
2039 else if (mNonClientMargins
.bottom
> 0)
2040 mNonClientOffset
.bottom
= mVertResizeMargin
- mNonClientMargins
.bottom
;
2043 if (aSizeMode
== nsSizeMode_Maximized
) {
2044 // Address an issue with auto-hide taskbars which fall behind the window.
2045 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2046 // the taskbar works properly.
2047 MONITORINFO info
= {sizeof(MONITORINFO
)};
2048 if (::GetMonitorInfo(::MonitorFromWindow(mWnd
, MONITOR_DEFAULTTOPRIMARY
),
2051 if (::GetWindowRect(mWnd
, &r
)) {
2052 // Adjust window rect to account for non-client margins.
2053 r
.top
+= mVertResizeMargin
- mNonClientOffset
.top
;
2054 r
.left
+= mHorResizeMargin
- mNonClientOffset
.left
;
2055 r
.bottom
-= mVertResizeMargin
- mNonClientOffset
.bottom
;
2056 r
.right
-= mHorResizeMargin
- mNonClientOffset
.right
;
2057 // Leave the 1 pixel margin if the window covers the monitor.
2058 if (r
.top
<= info
.rcMonitor
.top
&&
2059 r
.left
<= info
.rcMonitor
.left
&&
2060 r
.right
>= info
.rcMonitor
.right
&&
2061 r
.bottom
>= info
.rcMonitor
.bottom
)
2062 mNonClientOffset
.bottom
-= r
.bottom
- info
.rcMonitor
.bottom
+ 1;
2068 if (aReflowWindow
) {
2069 // Force a reflow of content based on the new client
2078 nsWindow::SetNonClientMargins(nsIntMargin
&margins
)
2080 if (!mIsTopWidgetWindow
||
2081 mBorderStyle
& eBorderStyle_none
||
2083 return NS_ERROR_INVALID_ARG
;
2085 // Request for a reset
2086 if (margins
.top
== -1 && margins
.left
== -1 &&
2087 margins
.right
== -1 && margins
.bottom
== -1) {
2088 mCustomNonClient
= PR_FALSE
;
2089 mNonClientMargins
= margins
;
2090 // Force a reflow of content based on the new client
2096 if (margins
.top
< -1 || margins
.bottom
< -1 ||
2097 margins
.left
< -1 || margins
.right
< -1)
2098 return NS_ERROR_INVALID_ARG
;
2100 mNonClientMargins
= margins
;
2101 mCustomNonClient
= PR_TRUE
;
2102 if (!UpdateNonClientMargins()) {
2103 NS_WARNING("UpdateNonClientMargins failed!");
2111 nsWindow::InvalidateNonClientRegion()
2113 // +-+-----------------------+-+
2114 // | | app non-client chrome | |
2115 // | +-----------------------+ |
2116 // | | app client chrome | | }
2117 // | +-----------------------+ | }
2118 // | | app content | | } area we don't want to invalidate
2119 // | +-----------------------+ | }
2120 // | | app client chrome | | }
2121 // | +-----------------------+ |
2122 // +---------------------------+ <
2123 // ^ ^ windows non-client chrome
2124 // client area = app *
2126 GetWindowRect(mWnd
, &rect
);
2127 MapWindowPoints(NULL
, mWnd
, (LPPOINT
)&rect
, 2);
2128 HRGN winRgn
= CreateRectRgnIndirect(&rect
);
2130 // Subtract app client chrome and app content leaving
2131 // windows non-client chrome and app non-client chrome
2133 GetWindowRect(mWnd
, &rect
);
2134 rect
.top
+= mCaptionHeight
;
2135 rect
.right
-= mHorResizeMargin
;
2136 rect
.bottom
-= mHorResizeMargin
;
2137 rect
.left
+= mVertResizeMargin
;
2138 MapWindowPoints(NULL
, mWnd
, (LPPOINT
)&rect
, 2);
2139 HRGN clientRgn
= CreateRectRgnIndirect(&rect
);
2140 CombineRgn(winRgn
, winRgn
, clientRgn
, RGN_DIFF
);
2141 DeleteObject(clientRgn
);
2143 // triggers ncpaint and paint events for the two areas
2144 RedrawWindow(mWnd
, NULL
, winRgn
, RDW_FRAME
|RDW_INVALIDATE
);
2145 DeleteObject(winRgn
);
2149 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion
)
2153 if (aRegion
== (HRGN
)1) { // undocumented value indicating a full refresh
2154 GetWindowRect(mWnd
, &rect
);
2155 rgn
= CreateRectRgnIndirect(&rect
);
2159 GetClientRect(mWnd
, &rect
);
2160 MapWindowPoints(mWnd
, NULL
, (LPPOINT
)&rect
, 2);
2161 HRGN nonClientRgn
= CreateRectRgnIndirect(&rect
);
2162 CombineRgn(rgn
, rgn
, nonClientRgn
, RGN_DIFF
);
2163 DeleteObject(nonClientRgn
);
2167 /**************************************************************
2169 * SECTION: nsIWidget::SetBackgroundColor
2171 * Sets the window background paint color.
2173 **************************************************************/
2175 NS_METHOD
nsWindow::SetBackgroundColor(const nscolor
&aColor
)
2177 nsBaseWidget::SetBackgroundColor(aColor
);
2180 ::DeleteObject(mBrush
);
2182 mBrush
= ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground
));
2185 ::SetClassLongPtrW(mWnd
, GCLP_HBRBACKGROUND
, (LONG_PTR
)mBrush
);
2191 /**************************************************************
2193 * SECTION: nsIWidget::SetCursor
2195 * SetCursor and related utilities for manging cursor state.
2197 **************************************************************/
2199 // Set this component cursor
2200 NS_METHOD
nsWindow::SetCursor(nsCursor aCursor
)
2202 // Only change cursor if it's changing
2204 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2205 //XXX If we want this optimization we need a better way to do it.
2206 //if (aCursor != mCursor) {
2207 HCURSOR newCursor
= NULL
;
2210 case eCursor_select
:
2211 newCursor
= ::LoadCursor(NULL
, IDC_IBEAM
);
2215 newCursor
= ::LoadCursor(NULL
, IDC_WAIT
);
2218 case eCursor_hyperlink
:
2220 newCursor
= ::LoadCursor(NULL
, IDC_HAND
);
2224 case eCursor_standard
:
2225 newCursor
= ::LoadCursor(NULL
, IDC_ARROW
);
2228 case eCursor_n_resize
:
2229 case eCursor_s_resize
:
2230 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
2233 case eCursor_w_resize
:
2234 case eCursor_e_resize
:
2235 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
2238 case eCursor_nw_resize
:
2239 case eCursor_se_resize
:
2240 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
2243 case eCursor_ne_resize
:
2244 case eCursor_sw_resize
:
2245 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
2248 case eCursor_crosshair
:
2249 newCursor
= ::LoadCursor(NULL
, IDC_CROSS
);
2253 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
2257 newCursor
= ::LoadCursor(NULL
, IDC_HELP
);
2260 case eCursor_copy
: // CSS3
2261 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COPY
));
2265 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ALIAS
));
2269 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_CELL
));
2273 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRAB
));
2276 case eCursor_grabbing
:
2277 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRABBING
));
2280 case eCursor_spinning
:
2281 newCursor
= ::LoadCursor(NULL
, IDC_APPSTARTING
);
2284 case eCursor_context_menu
:
2285 // XXX this CSS3 cursor needs to be implemented
2288 case eCursor_zoom_in
:
2289 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMIN
));
2292 case eCursor_zoom_out
:
2293 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMOUT
));
2296 case eCursor_not_allowed
:
2297 case eCursor_no_drop
:
2298 newCursor
= ::LoadCursor(NULL
, IDC_NO
);
2301 case eCursor_col_resize
:
2302 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COLRESIZE
));
2305 case eCursor_row_resize
:
2306 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ROWRESIZE
));
2309 case eCursor_vertical_text
:
2310 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_VERTICALTEXT
));
2313 case eCursor_all_scroll
:
2314 // XXX not 100% appropriate perhaps
2315 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
2318 case eCursor_nesw_resize
:
2319 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
2322 case eCursor_nwse_resize
:
2323 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
2326 case eCursor_ns_resize
:
2327 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
2330 case eCursor_ew_resize
:
2331 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
2335 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_NONE
));
2339 NS_ERROR("Invalid cursor type");
2343 if (NULL
!= newCursor
) {
2345 HCURSOR oldCursor
= ::SetCursor(newCursor
);
2347 if (sHCursor
== oldCursor
) {
2348 NS_IF_RELEASE(sCursorImgContainer
);
2349 if (sHCursor
!= NULL
)
2350 ::DestroyIcon(sHCursor
);
2358 // Setting the actual cursor
2359 NS_IMETHODIMP
nsWindow::SetCursor(imgIContainer
* aCursor
,
2360 PRUint32 aHotspotX
, PRUint32 aHotspotY
)
2362 if (sCursorImgContainer
== aCursor
&& sHCursor
) {
2363 ::SetCursor(sHCursor
);
2371 rv
= aCursor
->GetWidth(&width
);
2372 NS_ENSURE_SUCCESS(rv
, rv
);
2373 rv
= aCursor
->GetHeight(&height
);
2374 NS_ENSURE_SUCCESS(rv
, rv
);
2376 // Reject cursors greater than 128 pixels in either direction, to prevent
2378 // XXX ideally we should rescale. Also, we could modify the API to
2379 // allow trusted content to set larger cursors.
2380 if (width
> 128 || height
> 128)
2381 return NS_ERROR_NOT_AVAILABLE
;
2384 rv
= nsWindowGfx::CreateIcon(aCursor
, PR_TRUE
, aHotspotX
, aHotspotY
, &cursor
);
2385 NS_ENSURE_SUCCESS(rv
, rv
);
2387 mCursor
= nsCursor(-1);
2388 ::SetCursor(cursor
);
2390 NS_IF_RELEASE(sCursorImgContainer
);
2391 sCursorImgContainer
= aCursor
;
2392 NS_ADDREF(sCursorImgContainer
);
2394 if (sHCursor
!= NULL
)
2395 ::DestroyIcon(sHCursor
);
2401 /**************************************************************
2403 * SECTION: nsIWidget::Get/SetTransparencyMode
2405 * Manage the transparency mode of the top-level window
2406 * containing this widget.
2408 **************************************************************/
2411 nsTransparencyMode
nsWindow::GetTransparencyMode()
2413 return GetTopLevelWindow(PR_TRUE
)->GetWindowTranslucencyInner();
2416 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode
)
2418 GetTopLevelWindow(PR_TRUE
)->SetWindowTranslucencyInner(aMode
);
2421 void nsWindow::UpdatePossiblyTransparentRegion(const nsIntRegion
&aDirtyRegion
,
2422 const nsIntRegion
&aPossiblyTransparentRegion
) {
2423 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2427 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2428 nsWindow
* topWindow
= GetNSWindowPtr(hWnd
);
2433 mPossiblyTransparentRegion
.Sub(mPossiblyTransparentRegion
, aDirtyRegion
);
2434 mPossiblyTransparentRegion
.Or(mPossiblyTransparentRegion
, aPossiblyTransparentRegion
);
2436 nsIntRect clientBounds
;
2437 topWindow
->GetClientBounds(clientBounds
);
2438 nsIntRegion opaqueRegion
;
2439 opaqueRegion
.Sub(clientBounds
, mPossiblyTransparentRegion
);
2441 MARGINS margins
= { 0, 0, 0, 0 };
2442 DWORD_PTR dwStyle
= ::GetWindowLongPtrW(hWnd
, GWL_STYLE
);
2444 // If there is no opaque region or hidechrome=true, set margins
2445 // to support a full sheet of glass.
2446 if (opaqueRegion
.IsEmpty() || mHideChrome
) {
2447 // Comments in MSDN indicate all values must be set to -1
2448 margins
.cxLeftWidth
= margins
.cxRightWidth
=
2449 margins
.cyTopHeight
= margins
.cyBottomHeight
= -1;
2451 // Find the largest rectangle and use that to calculate the inset
2452 nsIntRect largest
= opaqueRegion
.GetLargestRectangle();
2453 margins
.cxLeftWidth
= largest
.x
;
2454 margins
.cxRightWidth
= clientBounds
.width
- largest
.XMost();
2455 margins
.cyBottomHeight
= clientBounds
.height
- largest
.YMost();
2457 // The minimum glass height must be the caption buttons height,
2458 // otherwise the buttons are drawn incorrectly.
2459 margins
.cyTopHeight
= PR_MAX(largest
.y
, mCaptionButtons
.height
);
2462 // Only update glass area if there are changes
2463 if (memcmp(&mGlassMargins
, &margins
, sizeof mGlassMargins
)) {
2464 mGlassMargins
= margins
;
2467 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2470 void nsWindow::UpdateGlass()
2472 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2473 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2474 MARGINS margins
= mGlassMargins
;
2476 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2477 // rendered based on the window style.
2478 // DWMNCRP_ENABLED - The non-client area rendering is
2479 // enabled; the window style is ignored.
2480 DWMNCRENDERINGPOLICY policy
= DWMNCRP_USEWINDOWSTYLE
;
2481 switch (mTransparencyMode
) {
2482 case eTransparencyBorderlessGlass
:
2483 // Only adjust if there is some opaque rectangle
2484 if (margins
.cxLeftWidth
>= 0) {
2485 const PRInt32 kGlassMarginAdjustment
= 2;
2486 margins
.cxLeftWidth
+= kGlassMarginAdjustment
;
2487 margins
.cyTopHeight
+= kGlassMarginAdjustment
;
2488 margins
.cxRightWidth
+= kGlassMarginAdjustment
;
2489 margins
.cyBottomHeight
+= kGlassMarginAdjustment
;
2492 case eTransparencyGlass
:
2493 policy
= DWMNCRP_ENABLED
;
2497 // Extends the window frame behind the client area
2498 if(nsUXThemeData::CheckForCompositor()) {
2499 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd
, &margins
);
2500 nsUXThemeData::dwmSetWindowAttributePtr(hWnd
, DWMWA_NCRENDERING_POLICY
, &policy
, sizeof policy
);
2502 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2506 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2507 void nsWindow::UpdateCaptionButtonsClippingRect()
2509 NS_ASSERTION(mWnd
, "UpdateCaptionButtonsClippingRect called with invalid mWnd.");
2511 RECT captionButtons
;
2512 mCaptionButtonsRoundedRegion
.SetEmpty();
2513 mCaptionButtons
.Empty();
2515 if (!mCustomNonClient
||
2516 mSizeMode
== nsSizeMode_Fullscreen
||
2517 mSizeMode
== nsSizeMode_Minimized
||
2518 !nsUXThemeData::CheckForCompositor() ||
2519 FAILED(nsUXThemeData::dwmGetWindowAttributePtr(mWnd
,
2520 DWMWA_CAPTION_BUTTON_BOUNDS
,
2522 sizeof(captionButtons
)))) {
2526 mCaptionButtons
= nsWindowGfx::ToIntRect(captionButtons
);
2528 // Adjustments to reported area
2529 PRInt32 leftMargin
= (mNonClientMargins
.left
== -1) ? mHorResizeMargin
: mNonClientMargins
.left
;
2531 // "leftMargin - 1" represents the resizer border and an
2532 // one pixel adjustment to hide the semi-transparent highlight.
2533 // The extra width is already excluded when the window is maximized.
2534 mCaptionButtons
.x
-= leftMargin
- 1;
2536 if (mSizeMode
!= nsSizeMode_Maximized
) {
2537 mCaptionButtons
.width
+= leftMargin
- 1;
2538 mCaptionButtons
.height
-= mVertResizeMargin
+ 1;
2540 // Adjustments to the buttons' shift from the edge of the screen,
2541 // plus some apparently transparent drop shadow below them.
2542 mCaptionButtons
.width
-= 2;
2543 mCaptionButtons
.height
-= 3;
2546 // Create a rounded region by shrinking the 2 bottommost pixel rows from
2547 // the rect by 1 and 2 pixels.
2548 // mCaptionButtons: mCaptionButtonsRoundedRegion:
2549 // +-----------+ +-----------+
2552 // +-----------+ +-------+
2553 nsIntRect
round1(mCaptionButtons
.x
, mCaptionButtons
.y
,
2554 mCaptionButtons
.width
, mCaptionButtons
.height
- 2);
2555 nsIntRect
round2(mCaptionButtons
.x
+ 1, mCaptionButtons
.YMost() - 2,
2556 mCaptionButtons
.width
- 2, 1);
2557 nsIntRect
round3(mCaptionButtons
.x
+ 2, mCaptionButtons
.YMost() - 1,
2558 mCaptionButtons
.width
- 4, 1);
2559 mCaptionButtonsRoundedRegion
.Or(mCaptionButtonsRoundedRegion
, round1
);
2560 mCaptionButtonsRoundedRegion
.Or(mCaptionButtonsRoundedRegion
, round2
);
2561 mCaptionButtonsRoundedRegion
.Or(mCaptionButtonsRoundedRegion
, round3
);
2565 /**************************************************************
2567 * SECTION: nsIWidget::HideWindowChrome
2569 * Show or hide window chrome.
2571 **************************************************************/
2573 NS_IMETHODIMP
nsWindow::HideWindowChrome(PRBool aShouldHide
)
2575 HWND hwnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2576 if (!GetNSWindowPtr(hwnd
))
2578 NS_WARNING("Trying to hide window decorations in an embedded context");
2579 return NS_ERROR_FAILURE
;
2582 if (mHideChrome
== aShouldHide
)
2585 DWORD_PTR style
, exStyle
;
2586 mHideChrome
= aShouldHide
;
2588 DWORD_PTR tempStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2589 DWORD_PTR tempExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2591 style
= tempStyle
& ~(WS_CAPTION
| WS_THICKFRAME
);
2592 exStyle
= tempExStyle
& ~(WS_EX_DLGMODALFRAME
| WS_EX_WINDOWEDGE
|
2593 WS_EX_CLIENTEDGE
| WS_EX_STATICEDGE
);
2595 mOldStyle
= tempStyle
;
2596 mOldExStyle
= tempExStyle
;
2599 if (!mOldStyle
|| !mOldExStyle
) {
2600 mOldStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2601 mOldExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2605 exStyle
= mOldExStyle
;
2608 VERIFY_WINDOW_STYLE(style
);
2609 ::SetWindowLongPtrW(hwnd
, GWL_STYLE
, style
);
2610 ::SetWindowLongPtrW(hwnd
, GWL_EXSTYLE
, exStyle
);
2615 /**************************************************************
2617 * SECTION: nsIWidget::Invalidate
2619 * Invalidate an area of the client for painting.
2621 **************************************************************/
2623 // Invalidate this component visible area
2624 NS_METHOD
nsWindow::Invalidate(PRBool aIsSynchronous
)
2628 #ifdef WIDGET_DEBUG_OUTPUT
2629 debug_DumpInvalidate(stdout
,
2633 nsCAutoString("noname"),
2635 #endif // WIDGET_DEBUG_OUTPUT
2637 VERIFY(::InvalidateRect(mWnd
, NULL
, FALSE
));
2639 if (aIsSynchronous
) {
2640 VERIFY(::UpdateWindow(mWnd
));
2646 // Invalidate this component visible area
2647 NS_METHOD
nsWindow::Invalidate(const nsIntRect
& aRect
, PRBool aIsSynchronous
)
2651 #ifdef WIDGET_DEBUG_OUTPUT
2652 debug_DumpInvalidate(stdout
,
2656 nsCAutoString("noname"),
2658 #endif // WIDGET_DEBUG_OUTPUT
2662 rect
.left
= aRect
.x
;
2664 rect
.right
= aRect
.x
+ aRect
.width
;
2665 rect
.bottom
= aRect
.y
+ aRect
.height
;
2667 VERIFY(::InvalidateRect(mWnd
, &rect
, FALSE
));
2669 if (aIsSynchronous
) {
2670 VERIFY(::UpdateWindow(mWnd
));
2677 nsWindow::MakeFullScreen(PRBool aFullScreen
)
2679 #if WINCE_WINDOWS_MOBILE
2682 SetForegroundWindow(mWnd
);
2683 if (nsWindowCE::sMenuBarShown
) {
2685 memset(&sipInfo
, 0, sizeof(SIPINFO
));
2686 sipInfo
.cbSize
= sizeof(SIPINFO
);
2687 if (SipGetInfo(&sipInfo
))
2688 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
),
2689 sipInfo
.rcVisibleDesktop
.bottom
);
2691 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
),
2692 GetSystemMetrics(SM_CYSCREEN
));
2694 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle
, &menuBarRect
) &&
2695 menuBarRect
.top
< rc
.bottom
)
2696 rc
.bottom
= menuBarRect
.top
;
2697 SHFullScreen(mWnd
, SHFS_HIDETASKBAR
| SHFS_HIDESTARTICON
| SHFS_SHOWSIPBUTTON
);
2700 SHFullScreen(mWnd
, SHFS_HIDETASKBAR
| SHFS_HIDESTARTICON
| SHFS_HIDESIPBUTTON
);
2701 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
), GetSystemMetrics(SM_CYSCREEN
));
2705 SHFullScreen(mWnd
, SHFS_SHOWTASKBAR
| SHFS_SHOWSTARTICON
);
2706 SystemParametersInfo(SPI_GETWORKAREA
, 0, &rc
, FALSE
);
2710 mSizeMode
= nsSizeMode_Fullscreen
;
2712 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2713 HideWindowChrome(aFullScreen
);
2714 Resize(rc
.left
, rc
.top
, rc
.right
-rc
.left
, rc
.bottom
-rc
.top
, PR_TRUE
);
2720 mFullscreenMode
= aFullScreen
;
2722 if (mSizeMode
== nsSizeMode_Fullscreen
)
2724 mOldSizeMode
= mSizeMode
;
2725 SetSizeMode(nsSizeMode_Fullscreen
);
2727 SetSizeMode(mOldSizeMode
);
2730 UpdateNonClientMargins();
2732 // Prevent window updates during the transition.
2734 if (nsUXThemeData::CheckForCompositor()) {
2735 style
= GetWindowLong(mWnd
, GWL_STYLE
);
2736 SetWindowLong(mWnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
2739 // Will call hide chrome, reposition window. Note this will
2740 // also cache dimensions for restoration, so it should only
2741 // be called once per fullscreen request.
2742 nsresult rv
= nsBaseWidget::MakeFullScreen(aFullScreen
);
2744 if (nsUXThemeData::CheckForCompositor()) {
2745 style
= GetWindowLong(mWnd
, GWL_STYLE
);
2746 SetWindowLong(mWnd
, GWL_STYLE
, style
| WS_VISIBLE
);
2749 // Let the dom know via web shell window
2750 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
2751 event
.mSizeMode
= mSizeMode
;
2753 DispatchWindowEvent(&event
);
2759 /**************************************************************
2761 * SECTION: nsIWidget::Update
2763 * Force a synchronous repaint of the window.
2765 **************************************************************/
2767 NS_IMETHODIMP
nsWindow::Update()
2769 nsresult rv
= NS_OK
;
2771 // updates can come through for windows no longer holding an mWnd during
2772 // deletes triggered by JavaScript in buttons with mouse feedback
2774 VERIFY(::UpdateWindow(mWnd
));
2779 /**************************************************************
2781 * SECTION: Native data storage
2783 * nsIWidget::GetNativeData
2784 * nsIWidget::FreeNativeData
2786 * Set or clear native data based on a constant.
2788 **************************************************************/
2790 // Return some native data according to aDataType
2791 void* nsWindow::GetNativeData(PRUint32 aDataType
)
2793 switch (aDataType
) {
2794 case NS_NATIVE_TMP_WINDOW
:
2795 return (void*)::CreateWindowExW(mIsRTL
? WS_EX_LAYOUTRTL
: 0,
2805 nsToolkit::mDllInstance
,
2807 case NS_NATIVE_PLUGIN_PORT
:
2808 case NS_NATIVE_WIDGET
:
2809 case NS_NATIVE_WINDOW
:
2811 case NS_NATIVE_GRAPHIC
:
2812 // XXX: This is sleezy!! Remember to Release the DC after using it!
2814 return (void*)(eTransparencyTransparent
== mTransparencyMode
) ?
2815 mMemoryDC
: ::GetDC(mWnd
);
2817 return (void*)::GetDC(mWnd
);
2820 #ifdef NS_ENABLE_TSF
2821 case NS_NATIVE_TSF_THREAD_MGR
:
2822 return nsTextStore::GetThreadMgr();
2823 case NS_NATIVE_TSF_CATEGORY_MGR
:
2824 return nsTextStore::GetCategoryMgr();
2825 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR
:
2826 return nsTextStore::GetDisplayAttrMgr();
2827 #endif //NS_ENABLE_TSF
2836 // Free some native data according to aDataType
2837 void nsWindow::FreeNativeData(void * data
, PRUint32 aDataType
)
2841 case NS_NATIVE_GRAPHIC
:
2843 if (eTransparencyTransparent
!= mTransparencyMode
)
2844 ::ReleaseDC(mWnd
, (HDC
)data
);
2846 ::ReleaseDC(mWnd
, (HDC
)data
);
2849 case NS_NATIVE_WIDGET
:
2850 case NS_NATIVE_WINDOW
:
2851 case NS_NATIVE_PLUGIN_PORT
:
2858 /**************************************************************
2860 * SECTION: nsIWidget::SetTitle
2862 * Set the main windows title text.
2864 **************************************************************/
2866 NS_METHOD
nsWindow::SetTitle(const nsAString
& aTitle
)
2868 const nsString
& strTitle
= PromiseFlatString(aTitle
);
2869 ::SendMessageW(mWnd
, WM_SETTEXT
, (WPARAM
)0, (LPARAM
)(LPCWSTR
)strTitle
.get());
2873 /**************************************************************
2875 * SECTION: nsIWidget::SetIcon
2877 * Set the main windows icon.
2879 **************************************************************/
2881 NS_METHOD
nsWindow::SetIcon(const nsAString
& aIconSpec
)
2884 // Assume the given string is a local identifier for an icon file.
2886 nsCOMPtr
<nsILocalFile
> iconFile
;
2887 ResolveIconName(aIconSpec
, NS_LITERAL_STRING(".ico"),
2888 getter_AddRefs(iconFile
));
2890 return NS_OK
; // not an error if icon is not found
2892 nsAutoString iconPath
;
2893 iconFile
->GetPath(iconPath
);
2895 // XXX this should use MZLU (see bug 239279)
2899 HICON bigIcon
= (HICON
)::LoadImageW(NULL
,
2900 (LPCWSTR
)iconPath
.get(),
2902 ::GetSystemMetrics(SM_CXICON
),
2903 ::GetSystemMetrics(SM_CYICON
),
2905 HICON smallIcon
= (HICON
)::LoadImageW(NULL
,
2906 (LPCWSTR
)iconPath
.get(),
2908 ::GetSystemMetrics(SM_CXSMICON
),
2909 ::GetSystemMetrics(SM_CYSMICON
),
2913 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_BIG
, (LPARAM
)bigIcon
);
2915 ::DestroyIcon(icon
);
2917 #ifdef DEBUG_SetIcon
2919 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
2920 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath
.get(), ::GetLastError() );
2924 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_SMALL
, (LPARAM
)smallIcon
);
2926 ::DestroyIcon(icon
);
2928 #ifdef DEBUG_SetIcon
2930 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
2931 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath
.get(), ::GetLastError() );
2938 /**************************************************************
2940 * SECTION: nsIWidget::WidgetToScreenOffset
2942 * Return this widget's origin in screen coordinates.
2944 **************************************************************/
2946 nsIntPoint
nsWindow::WidgetToScreenOffset()
2951 ::ClientToScreen(mWnd
, &point
);
2952 return nsIntPoint(point
.x
, point
.y
);
2955 nsIntSize
nsWindow::ClientToWindowSize(const nsIntSize
& aClientSize
)
2957 if (!IsPopupWithTitleBar())
2960 // just use (200, 200) as the position
2964 r
.right
= 200 + aClientSize
.width
;
2965 r
.bottom
= 200 + aClientSize
.height
;
2966 ::AdjustWindowRectEx(&r
, WindowStyle(), PR_FALSE
, WindowExStyle());
2968 return nsIntSize(r
.right
- r
.left
, r
.bottom
- r
.top
);
2971 /**************************************************************
2973 * SECTION: nsIWidget::EnableDragDrop
2975 * Enables/Disables drag and drop of files on this widget.
2977 **************************************************************/
2979 #if !defined(WINCE) // implemented in nsWindowCE.cpp
2980 NS_METHOD
nsWindow::EnableDragDrop(PRBool aEnable
)
2982 NS_ASSERTION(mWnd
, "nsWindow::EnableDragDrop() called after Destroy()");
2984 nsresult rv
= NS_ERROR_FAILURE
;
2986 if (nsnull
== mNativeDragTarget
) {
2987 mNativeDragTarget
= new nsNativeDragTarget(this);
2988 if (NULL
!= mNativeDragTarget
) {
2989 mNativeDragTarget
->AddRef();
2990 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
,TRUE
,FALSE
)) {
2991 if (S_OK
== ::RegisterDragDrop(mWnd
, (LPDROPTARGET
)mNativeDragTarget
)) {
2998 if (nsnull
!= mWnd
&& NULL
!= mNativeDragTarget
) {
2999 ::RevokeDragDrop(mWnd
);
3000 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
, FALSE
, TRUE
)) {
3003 mNativeDragTarget
->DragCancel();
3004 NS_RELEASE(mNativeDragTarget
);
3011 /**************************************************************
3013 * SECTION: nsIWidget::CaptureMouse
3015 * Enables/Disables system mouse capture.
3017 **************************************************************/
3019 NS_METHOD
nsWindow::CaptureMouse(PRBool aCapture
)
3021 if (!nsToolkit::gMouseTrailer
) {
3022 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3027 nsToolkit::gMouseTrailer
->SetCaptureWindow(mWnd
);
3030 nsToolkit::gMouseTrailer
->SetCaptureWindow(NULL
);
3033 mIsInMouseCapture
= aCapture
;
3037 /**************************************************************
3039 * SECTION: nsIWidget::CaptureRollupEvents
3041 * Dealing with event rollup on destroy for popups. Enables &
3042 * Disables system capture of any and all events that would
3043 * cause a dropdown to be rolled up.
3045 **************************************************************/
3047 NS_IMETHODIMP
nsWindow::CaptureRollupEvents(nsIRollupListener
* aListener
,
3048 nsIMenuRollup
* aMenuRollup
,
3050 PRBool aConsumeRollupEvent
)
3053 /* we haven't bothered carrying a weak reference to sRollupWidget because
3054 we believe lifespan is properly scoped. this next assertion helps
3055 assure that remains true. */
3056 NS_ASSERTION(!sRollupWidget
, "rollup widget reassigned before release");
3057 sRollupConsumeEvent
= aConsumeRollupEvent
;
3058 NS_IF_RELEASE(sRollupWidget
);
3059 NS_IF_RELEASE(sMenuRollup
);
3060 sRollupListener
= aListener
;
3061 sMenuRollup
= aMenuRollup
;
3062 NS_IF_ADDREF(aMenuRollup
);
3063 sRollupWidget
= this;
3067 if (!sMsgFilterHook
&& !sCallProcHook
&& !sCallMouseHook
) {
3068 RegisterSpecialDropdownHooks();
3070 sProcessHook
= PR_TRUE
;
3074 sRollupListener
= nsnull
;
3075 NS_IF_RELEASE(sMenuRollup
);
3076 NS_IF_RELEASE(sRollupWidget
);
3079 sProcessHook
= PR_FALSE
;
3080 UnregisterSpecialDropdownHooks();
3087 /**************************************************************
3089 * SECTION: nsIWidget::GetAttention
3091 * Bring this window to the user's attention.
3093 **************************************************************/
3095 // Draw user's attention to this window until it comes to foreground.
3097 nsWindow::GetAttention(PRInt32 aCycleCount
)
3102 return NS_ERROR_NOT_INITIALIZED
;
3104 // Don't flash if the flash count is 0 or if the
3105 // top level window is already active.
3106 HWND fgWnd
= ::GetForegroundWindow();
3107 if (aCycleCount
== 0 || fgWnd
== GetTopLevelHWND(mWnd
))
3110 HWND flashWnd
= mWnd
;
3111 while (HWND ownerWnd
= ::GetWindow(flashWnd
, GW_OWNER
)) {
3112 flashWnd
= ownerWnd
;
3115 // Don't flash if the owner window is active either.
3116 if (fgWnd
== flashWnd
)
3119 DWORD defaultCycleCount
= 0;
3120 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT
, 0, &defaultCycleCount
, 0);
3122 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
3123 FLASHW_ALL
, aCycleCount
> 0 ? aCycleCount
: defaultCycleCount
, 0 };
3124 ::FlashWindowEx(&flashInfo
);
3129 void nsWindow::StopFlashing()
3132 HWND flashWnd
= mWnd
;
3133 while (HWND ownerWnd
= ::GetWindow(flashWnd
, GW_OWNER
)) {
3134 flashWnd
= ownerWnd
;
3137 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
3138 FLASHW_STOP
, 0, 0 };
3139 ::FlashWindowEx(&flashInfo
);
3143 /**************************************************************
3145 * SECTION: nsIWidget::HasPendingInputEvent
3147 * Ask whether there user input events pending. All input events are
3148 * included, including those not targeted at this nsIwidget instance.
3150 **************************************************************/
3153 nsWindow::HasPendingInputEvent()
3155 // If there is pending input or the user is currently
3156 // moving the window then return true.
3157 // Note: When the user is moving the window WIN32 spins
3158 // a separate event loop and input events are not
3159 // reported to the application.
3160 if (HIWORD(GetQueueStatus(QS_INPUT
)))
3165 GUITHREADINFO guiInfo
;
3166 guiInfo
.cbSize
= sizeof(GUITHREADINFO
);
3167 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo
))
3169 return GUI_INMOVESIZE
== (guiInfo
.flags
& GUI_INMOVESIZE
);
3173 /**************************************************************
3175 * SECTION: nsIWidget::GetLayerManager
3177 * Get the layer manager associated with this widget.
3179 **************************************************************/
3181 mozilla::layers::LayerManager
*
3182 nsWindow::GetLayerManager()
3185 if (!mLayerManager
) {
3186 nsCOMPtr
<nsIPrefBranch2
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
3188 PRBool accelerateByDefault
= PR_TRUE
;
3189 PRBool disableAcceleration
= PR_FALSE
;
3190 PRBool preferOpenGL
= PR_FALSE
;
3191 PRBool useD3D10
= PR_FALSE
;
3193 prefs
->GetBoolPref("layers.accelerate-all",
3194 &accelerateByDefault
);
3195 prefs
->GetBoolPref("layers.accelerate-none",
3196 &disableAcceleration
);
3197 prefs
->GetBoolPref("layers.prefer-opengl",
3199 prefs
->GetBoolPref("layers.use-d3d10",
3203 const char *acceleratedEnv
= PR_GetEnv("MOZ_ACCELERATED");
3204 accelerateByDefault
= accelerateByDefault
||
3205 (acceleratedEnv
&& (*acceleratedEnv
!= '0'));
3207 /* We don't currently support using an accelerated layer manager with
3208 * transparent windows so don't even try. I'm also not sure if we even
3209 * want to support this case. See bug #593471 */
3210 disableAcceleration
= disableAcceleration
||
3211 eTransparencyTransparent
== mTransparencyMode
;
3213 nsCOMPtr
<nsIXULRuntime
> xr
= do_GetService("@mozilla.org/xre/runtime;1");
3214 PRBool safeMode
= PR_FALSE
;
3216 xr
->GetInSafeMode(&safeMode
);
3218 if (disableAcceleration
|| safeMode
)
3219 mUseAcceleratedRendering
= PR_FALSE
;
3220 else if (accelerateByDefault
)
3221 mUseAcceleratedRendering
= PR_TRUE
;
3223 if (mUseAcceleratedRendering
) {
3224 #ifdef MOZ_ENABLE_D3D10_LAYER
3226 nsRefPtr
<mozilla::layers::LayerManagerD3D10
> layerManager
=
3227 new mozilla::layers::LayerManagerD3D10(this);
3228 if (layerManager
->Initialize()) {
3229 mLayerManager
= layerManager
;
3233 #ifdef MOZ_ENABLE_D3D9_LAYER
3234 if (!preferOpenGL
&& !mLayerManager
) {
3235 nsRefPtr
<mozilla::layers::LayerManagerD3D9
> layerManager
=
3236 new mozilla::layers::LayerManagerD3D9(this);
3237 if (layerManager
->Initialize()) {
3238 mLayerManager
= layerManager
;
3242 if (!mLayerManager
&& preferOpenGL
) {
3243 nsRefPtr
<mozilla::layers::LayerManagerOGL
> layerManager
=
3244 new mozilla::layers::LayerManagerOGL(this);
3245 if (layerManager
->Initialize()) {
3246 mLayerManager
= layerManager
;
3251 // Fall back to software if we couldn't use any hardware backends.
3253 mLayerManager
= CreateBasicLayerManager();
3257 return mLayerManager
;
3260 /**************************************************************
3262 * SECTION: nsIWidget::GetThebesSurface
3264 * Get the Thebes surface associated with this widget.
3266 **************************************************************/
3268 gfxASurface
*nsWindow::GetThebesSurface()
3270 #ifdef CAIRO_HAS_D2D_SURFACE
3271 if (mD2DWindowSurface
) {
3272 return mD2DWindowSurface
;
3276 return (new gfxWindowsSurface(mPaintDC
));
3278 #ifdef CAIRO_HAS_D2D_SURFACE
3279 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3280 gfxWindowsPlatform::RENDER_DIRECT2D
) {
3281 gfxASurface::gfxContentType content
= gfxASurface::CONTENT_COLOR
;
3282 #if defined(MOZ_XUL)
3283 if (mTransparencyMode
!= eTransparencyOpaque
) {
3284 content
= gfxASurface::CONTENT_COLOR_ALPHA
;
3287 return (new gfxD2DSurface(mWnd
, content
));
3290 PRUint32 flags
= gfxWindowsSurface::FLAG_TAKE_DC
;
3291 if (mTransparencyMode
!= eTransparencyOpaque
) {
3292 flags
|= gfxWindowsSurface::FLAG_IS_TRANSPARENT
;
3294 return (new gfxWindowsSurface(mWnd
, flags
));
3295 #ifdef CAIRO_HAS_D2D_SURFACE
3300 /**************************************************************
3302 * SECTION: nsIWidget::OnDefaultButtonLoaded
3304 * Called after the dialog is loaded and it has a default button.
3306 **************************************************************/
3309 nsWindow::OnDefaultButtonLoaded(const nsIntRect
&aButtonRect
)
3312 return NS_ERROR_NOT_IMPLEMENTED
;
3314 if (aButtonRect
.IsEmpty())
3317 // Don't snap when we are not active.
3318 HWND activeWnd
= ::GetActiveWindow();
3319 if (activeWnd
!= ::GetForegroundWindow() ||
3320 GetTopLevelHWND(mWnd
, PR_TRUE
) != GetTopLevelHWND(activeWnd
, PR_TRUE
)) {
3324 PRBool isAlwaysSnapCursor
= PR_FALSE
;
3325 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
3327 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
3328 prefs
->GetBranch(nsnull
, getter_AddRefs(prefBranch
));
3330 prefBranch
->GetBoolPref("ui.cursor_snapping.always_enabled",
3331 &isAlwaysSnapCursor
);
3335 if (!isAlwaysSnapCursor
) {
3336 BOOL snapDefaultButton
;
3337 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON
, 0,
3338 &snapDefaultButton
, 0) || !snapDefaultButton
)
3342 nsIntRect widgetRect
;
3343 nsresult rv
= GetScreenBounds(widgetRect
);
3344 NS_ENSURE_SUCCESS(rv
, rv
);
3345 nsIntRect
buttonRect(aButtonRect
+ widgetRect
.TopLeft());
3347 nsIntPoint
centerOfButton(buttonRect
.x
+ buttonRect
.width
/ 2,
3348 buttonRect
.y
+ buttonRect
.height
/ 2);
3349 // The center of the button can be outside of the widget.
3350 // E.g., it could be hidden by scrolling.
3351 if (!widgetRect
.Contains(centerOfButton
)) {
3355 if (!::SetCursorPos(centerOfButton
.x
, centerOfButton
.y
)) {
3356 NS_ERROR("SetCursorPos failed");
3357 return NS_ERROR_FAILURE
;
3364 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta
,
3365 PRBool aIsHorizontal
,
3366 PRInt32
&aOverriddenDelta
)
3368 // The default vertical and horizontal scrolling speed is 3, this is defined
3369 // on the document of SystemParametersInfo in MSDN.
3370 const PRUint32 kSystemDefaultScrollingSpeed
= 3;
3372 PRInt32 absOriginDelta
= PR_ABS(aOriginalDelta
);
3374 // Compute the simple overridden speed.
3375 PRInt32 absComputedOverriddenDelta
;
3377 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta
, aIsHorizontal
,
3378 absComputedOverriddenDelta
);
3379 NS_ENSURE_SUCCESS(rv
, rv
);
3381 aOverriddenDelta
= aOriginalDelta
;
3383 if (absComputedOverriddenDelta
== absOriginDelta
) {
3384 // We don't override now.
3388 // Otherwise, we should check whether the user customized the system settings
3389 // or not. If the user did it, we should respect the will.
3391 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &systemSpeed
, 0)) {
3392 return NS_ERROR_FAILURE
;
3394 // The default vertical scrolling speed is 3, this is defined on the document
3395 // of SystemParametersInfo in MSDN.
3396 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
3400 // Only Vista and later, Windows has the system setting of horizontal
3401 // scrolling by the mouse wheel.
3402 if (GetWindowsVersion() >= VISTA_VERSION
) {
3403 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS
, 0, &systemSpeed
, 0)) {
3404 return NS_ERROR_FAILURE
;
3406 // The default horizontal scrolling speed is 3, this is defined on the
3407 // document of SystemParametersInfo in MSDN.
3408 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
3413 // Limit the overridden delta value from the system settings. The mouse
3414 // driver might accelerate the scrolling speed already. If so, we shouldn't
3415 // override the scrolling speed for preventing the unexpected high speed
3417 PRInt32 absDeltaLimit
;
3419 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed
,
3420 aIsHorizontal
, absDeltaLimit
);
3421 NS_ENSURE_SUCCESS(rv
, rv
);
3423 // If the given delta is larger than our computed limitation value, the delta
3424 // was accelerated by the mouse driver. So, we should do nothing here.
3425 if (absDeltaLimit
<= absOriginDelta
) {
3429 absComputedOverriddenDelta
=
3430 PR_MIN(absComputedOverriddenDelta
, absDeltaLimit
);
3432 aOverriddenDelta
= (aOriginalDelta
> 0) ? absComputedOverriddenDelta
:
3433 -absComputedOverriddenDelta
;
3437 /**************************************************************
3438 **************************************************************
3440 ** BLOCK: Moz Events
3442 ** Moz GUI event management.
3444 **************************************************************
3445 **************************************************************/
3447 /**************************************************************
3449 * SECTION: Mozilla event initialization
3451 * Helpers for initializing moz events.
3453 **************************************************************/
3455 // Event intialization
3456 MSG
nsWindow::InitMSG(UINT aMessage
, WPARAM wParam
, LPARAM lParam
)
3459 msg
.message
= aMessage
;
3460 msg
.wParam
= wParam
;
3461 msg
.lParam
= lParam
;
3465 void nsWindow::InitEvent(nsGUIEvent
& event
, nsIntPoint
* aPoint
)
3467 if (nsnull
== aPoint
) { // use the point from the event
3468 // get the message position in client coordinates
3471 DWORD pos
= ::GetMessagePos();
3474 cpos
.x
= GET_X_LPARAM(pos
);
3475 cpos
.y
= GET_Y_LPARAM(pos
);
3477 ::ScreenToClient(mWnd
, &cpos
);
3478 event
.refPoint
.x
= cpos
.x
;
3479 event
.refPoint
.y
= cpos
.y
;
3481 event
.refPoint
.x
= 0;
3482 event
.refPoint
.y
= 0;
3486 // use the point override if provided
3487 event
.refPoint
.x
= aPoint
->x
;
3488 event
.refPoint
.y
= aPoint
->y
;
3492 event
.time
= ::GetMessageTime();
3494 event
.time
= PR_Now() / 1000;
3497 mLastPoint
= event
.refPoint
;
3500 /**************************************************************
3502 * SECTION: Moz event dispatch helpers
3504 * Helpers for dispatching different types of moz events.
3506 **************************************************************/
3508 // Main event dispatch. Invokes callback and ProcessEvent method on
3509 // Event Listener object. Part of nsIWidget.
3510 NS_IMETHODIMP
nsWindow::DispatchEvent(nsGUIEvent
* event
, nsEventStatus
& aStatus
)
3512 #ifdef WIDGET_DEBUG_OUTPUT
3513 debug_DumpEvent(stdout
,
3516 nsCAutoString("something"),
3518 #endif // WIDGET_DEBUG_OUTPUT
3520 aStatus
= nsEventStatus_eIgnore
;
3522 // skip processing of suppressed blur events
3523 if (event
->message
== NS_DEACTIVATE
&& BlurEventsSuppressed())
3526 // Top level windows can have a view attached which requires events be sent
3527 // to the underlying base window and the view. Added when we combined the
3528 // base chrome window with the main content child for nc client area (title
3530 if (mViewCallback
) {
3531 // A subset of events are sent to the base xul window first
3532 switch(event
->message
) {
3533 // send to the base window (view mgr ignores these for the view)
3534 case NS_UISTATECHANGED
:
3539 (*mEventCallback
)(event
); // web shell / xul window
3542 // sent to the base window, then to the view
3547 (*mEventCallback
)(event
); // web shell / xul window
3550 // attached view events
3551 aStatus
= (*mViewCallback
)(event
);
3553 else if (mEventCallback
) {
3554 aStatus
= (*mEventCallback
)(event
);
3557 // the window can be destroyed during processing of seemingly innocuous events like, say,
3558 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3559 // which causes problems with the deleted window. therefore:
3560 if (mOnDestroyCalled
)
3561 aStatus
= nsEventStatus_eConsumeNoDefault
;
3565 PRBool
nsWindow::DispatchStandardEvent(PRUint32 aMsg
)
3567 nsGUIEvent
event(PR_TRUE
, aMsg
, this);
3570 PRBool result
= DispatchWindowEvent(&event
);
3574 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
* event
)
3576 nsEventStatus status
;
3577 DispatchEvent(event
, status
);
3578 return ConvertStatus(status
);
3581 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
* event
, nsEventStatus
&aStatus
) {
3582 DispatchEvent(event
, aStatus
);
3583 return ConvertStatus(aStatus
);
3586 PRBool
nsWindow::DispatchKeyEvent(PRUint32 aEventType
, WORD aCharCode
,
3587 const nsTArray
<nsAlternativeCharCode
>* aAlternativeCharCodes
,
3588 UINT aVirtualCharCode
, const MSG
*aMsg
,
3589 const nsModifierKeyState
&aModKeyState
,
3594 nsKeyEvent
event(PR_TRUE
, aEventType
, this);
3595 nsIntPoint
point(0, 0);
3597 InitEvent(event
, &point
); // this add ref's event.widget
3599 event
.flags
|= aFlags
;
3600 event
.charCode
= aCharCode
;
3601 if (aAlternativeCharCodes
)
3602 event
.alternativeCharCodes
.AppendElements(*aAlternativeCharCodes
);
3603 event
.keyCode
= aVirtualCharCode
;
3607 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt
++,
3608 (NS_KEY_PRESS
== aEventType
) ? "PRESS" : (aEventType
== NS_KEY_UP
? "Up" : "Down"),
3609 event
.charCode
, event
.keyCode
);
3610 printf("Shift: %s Control %s Alt: %s \n",
3611 (mIsShiftDown
? "D" : "U"), (mIsControlDown
? "D" : "U"), (mIsAltDown
? "D" : "U"));
3612 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3613 IS_VK_DOWN(NS_VK_SHIFT
) ? 'S' : ' ',
3614 IS_VK_DOWN(NS_VK_CONTROL
) ? 'C' : ' ',
3615 IS_VK_DOWN(NS_VK_ALT
) ? 'A' : ' ',
3616 IS_VK_DOWN(VK_LSHIFT
) ? 'S' : ' ',
3617 IS_VK_DOWN(VK_LCONTROL
) ? 'C' : ' ',
3618 IS_VK_DOWN(VK_LMENU
) ? 'A' : ' ',
3619 IS_VK_DOWN(VK_RMENU
) ? 'A' : ' ',
3620 IS_VK_DOWN(VK_RCONTROL
) ? 'C' : ' ',
3621 IS_VK_DOWN(VK_RSHIFT
) ? 'S' : ' ');
3624 event
.isShift
= aModKeyState
.mIsShiftDown
;
3625 event
.isControl
= aModKeyState
.mIsControlDown
;
3626 event
.isMeta
= PR_FALSE
;
3627 event
.isAlt
= aModKeyState
.mIsAltDown
;
3629 NPEvent pluginEvent
;
3630 if (aMsg
&& PluginHasFocus()) {
3631 pluginEvent
.event
= aMsg
->message
;
3632 pluginEvent
.wParam
= aMsg
->wParam
;
3633 pluginEvent
.lParam
= aMsg
->lParam
;
3634 event
.pluginEvent
= (void *)&pluginEvent
;
3637 PRBool result
= DispatchWindowEvent(&event
);
3642 PRBool
nsWindow::DispatchCommandEvent(PRUint32 aEventCommand
)
3644 nsCOMPtr
<nsIAtom
> command
;
3645 switch (aEventCommand
) {
3646 case APPCOMMAND_BROWSER_BACKWARD
:
3647 command
= nsWidgetAtoms::Back
;
3649 case APPCOMMAND_BROWSER_FORWARD
:
3650 command
= nsWidgetAtoms::Forward
;
3652 case APPCOMMAND_BROWSER_REFRESH
:
3653 command
= nsWidgetAtoms::Reload
;
3655 case APPCOMMAND_BROWSER_STOP
:
3656 command
= nsWidgetAtoms::Stop
;
3658 case APPCOMMAND_BROWSER_SEARCH
:
3659 command
= nsWidgetAtoms::Search
;
3661 case APPCOMMAND_BROWSER_FAVORITES
:
3662 command
= nsWidgetAtoms::Bookmarks
;
3664 case APPCOMMAND_BROWSER_HOME
:
3665 command
= nsWidgetAtoms::Home
;
3670 nsCommandEvent
event(PR_TRUE
, nsWidgetAtoms::onAppCommand
, command
, this);
3673 DispatchWindowEvent(&event
);
3678 // Recursively dispatch synchronous paints for nsIWidget
3679 // descendants with invalidated rectangles.
3680 BOOL CALLBACK
nsWindow::DispatchStarvedPaints(HWND aWnd
, LPARAM aMsg
)
3682 LONG_PTR proc
= ::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
3683 if (proc
== (LONG_PTR
)&nsWindow::WindowProc
) {
3684 // its one of our windows so check to see if it has a
3685 // invalidated rect. If it does. Dispatch a synchronous
3687 if (GetUpdateRect(aWnd
, NULL
, FALSE
))
3688 VERIFY(::UpdateWindow(aWnd
));
3693 // Check for pending paints and dispatch any pending paint
3694 // messages for any nsIWidget which is a descendant of the
3695 // top-level window that *this* window is embedded within.
3697 // Note: We do not dispatch pending paint messages for non
3698 // nsIWidget managed windows.
3699 void nsWindow::DispatchPendingEvents()
3702 NS_WARNING("We were asked to dispatch pending events during painting, "
3703 "denying since that's unsafe.");
3707 // We need to ensure that reflow events do not get starved.
3708 // At the same time, we don't want to recurse through here
3709 // as that would prevent us from dispatching starved paints.
3710 static int recursionBlocker
= 0;
3711 if (recursionBlocker
++ == 0) {
3712 NS_ProcessPendingEvents(nsnull
, PR_MillisecondsToInterval(100));
3716 // Quickly check to see if there are any
3717 // paint events pending.
3718 if (::GetQueueStatus(QS_PAINT
)) {
3719 // Find the top level window.
3720 HWND topWnd
= GetTopLevelHWND(mWnd
);
3722 // Dispatch pending paints for all topWnd's descendant windows.
3723 // Note: EnumChildWindows enumerates all descendant windows not just
3726 ::EnumChildWindows(topWnd
, nsWindow::DispatchStarvedPaints
, 0);
3728 nsWindowCE::EnumChildWindows(topWnd
, nsWindow::DispatchStarvedPaints
, NULL
);
3733 // Deal with plugin events
3734 PRBool
nsWindow::DispatchPluginEvent(const MSG
&aMsg
)
3736 if (!PluginHasFocus())
3739 nsGUIEvent
event(PR_TRUE
, NS_PLUGIN_EVENT
, this);
3740 nsIntPoint
point(0, 0);
3741 InitEvent(event
, &point
);
3742 NPEvent pluginEvent
;
3743 pluginEvent
.event
= aMsg
.message
;
3744 pluginEvent
.wParam
= aMsg
.wParam
;
3745 pluginEvent
.lParam
= aMsg
.lParam
;
3746 event
.pluginEvent
= (void *)&pluginEvent
;
3747 return DispatchWindowEvent(&event
);
3750 PRBool
nsWindow::DispatchPluginEvent(UINT aMessage
,
3753 PRBool aDispatchPendingEvents
)
3755 PRBool ret
= DispatchPluginEvent(InitMSG(aMessage
, aWParam
, aLParam
));
3756 if (aDispatchPendingEvents
) {
3757 DispatchPendingEvents();
3762 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg
,
3766 ::GetMessageW(&msg
, mWnd
, aFirstMsg
, aLastMsg
);
3767 DispatchPluginEvent(msg
);
3770 // Deal with all sort of mouse event
3771 PRBool
nsWindow::DispatchMouseEvent(PRUint32 aEventType
, WPARAM wParam
,
3772 LPARAM lParam
, PRBool aIsContextMenuKey
,
3773 PRInt16 aButton
, PRUint16 aInputSource
)
3775 PRBool result
= PR_FALSE
;
3779 if (!mEventCallback
) {
3783 switch (aEventType
) {
3784 case NS_MOUSE_BUTTON_DOWN
:
3785 CaptureMouse(PR_TRUE
);
3788 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3789 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3790 case NS_MOUSE_BUTTON_UP
:
3793 if (!(wParam
& (MK_LBUTTON
| MK_MBUTTON
| MK_RBUTTON
)) && mIsInMouseCapture
)
3794 CaptureMouse(PR_FALSE
);
3802 nsIntPoint eventPoint
;
3803 eventPoint
.x
= GET_X_LPARAM(lParam
);
3804 eventPoint
.y
= GET_Y_LPARAM(lParam
);
3806 nsMouseEvent
event(PR_TRUE
, aEventType
, this, nsMouseEvent::eReal
,
3808 ? nsMouseEvent::eContextMenuKey
3809 : nsMouseEvent::eNormal
);
3810 if (aEventType
== NS_CONTEXTMENU
&& aIsContextMenuKey
) {
3811 nsIntPoint
zero(0, 0);
3812 InitEvent(event
, &zero
);
3814 InitEvent(event
, &eventPoint
);
3817 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
3818 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
3819 event
.isMeta
= PR_FALSE
;
3820 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
3821 event
.button
= aButton
;
3822 event
.inputSource
= aInputSource
;
3824 nsIntPoint mpScreen
= eventPoint
+ WidgetToScreenOffset();
3826 // Suppress mouse moves caused by widget creation
3827 if (aEventType
== NS_MOUSE_MOVE
)
3829 if ((sLastMouseMovePoint
.x
== mpScreen
.x
) && (sLastMouseMovePoint
.y
== mpScreen
.y
))
3831 sLastMouseMovePoint
.x
= mpScreen
.x
;
3832 sLastMouseMovePoint
.y
= mpScreen
.y
;
3835 PRBool insideMovementThreshold
= (abs(sLastMousePoint
.x
- eventPoint
.x
) < (short)::GetSystemMetrics(SM_CXDOUBLECLK
)) &&
3836 (abs(sLastMousePoint
.y
- eventPoint
.y
) < (short)::GetSystemMetrics(SM_CYDOUBLECLK
));
3840 case nsMouseEvent::eLeftButton
:
3841 eventButton
= VK_LBUTTON
;
3843 case nsMouseEvent::eMiddleButton
:
3844 eventButton
= VK_MBUTTON
;
3846 case nsMouseEvent::eRightButton
:
3847 eventButton
= VK_RBUTTON
;
3854 // Doubleclicks are used to set the click count, then changed to mousedowns
3855 // We're going to time double-clicks from mouse *up* to next mouse *down*
3857 LONG curMsgTime
= ::GetMessageTime();
3859 LONG curMsgTime
= PR_Now() / 1000;
3862 if (aEventType
== NS_MOUSE_DOUBLECLICK
) {
3863 event
.message
= NS_MOUSE_BUTTON_DOWN
;
3864 event
.button
= aButton
;
3865 sLastClickCount
= 2;
3867 else if (aEventType
== NS_MOUSE_BUTTON_UP
) {
3868 // remember when this happened for the next mouse down
3869 sLastMousePoint
.x
= eventPoint
.x
;
3870 sLastMousePoint
.y
= eventPoint
.y
;
3871 sLastMouseButton
= eventButton
;
3873 else if (aEventType
== NS_MOUSE_BUTTON_DOWN
) {
3874 // now look to see if we want to convert this to a double- or triple-click
3875 if (((curMsgTime
- sLastMouseDownTime
) < (LONG
)::GetDoubleClickTime()) && insideMovementThreshold
&&
3876 eventButton
== sLastMouseButton
) {
3879 // reset the click count, to count *this* click
3880 sLastClickCount
= 1;
3882 // Set last Click time on MouseDown only
3883 sLastMouseDownTime
= curMsgTime
;
3885 else if (aEventType
== NS_MOUSE_MOVE
&& !insideMovementThreshold
) {
3886 sLastClickCount
= 0;
3888 else if (aEventType
== NS_MOUSE_EXIT
) {
3889 event
.exit
= IsTopLevelMouseExit(mWnd
) ? nsMouseEvent::eTopLevel
: nsMouseEvent::eChild
;
3891 else if (aEventType
== NS_MOUSE_MOZHITTEST
)
3893 event
.flags
|= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH
;
3895 event
.clickCount
= sLastClickCount
;
3898 printf("Msg Time: %d Click Count: %d\n", curMsgTime
, event
.clickCount
);
3901 NPEvent pluginEvent
;
3905 case NS_MOUSE_BUTTON_DOWN
:
3907 case nsMouseEvent::eLeftButton
:
3908 pluginEvent
.event
= WM_LBUTTONDOWN
;
3910 case nsMouseEvent::eMiddleButton
:
3911 pluginEvent
.event
= WM_MBUTTONDOWN
;
3913 case nsMouseEvent::eRightButton
:
3914 pluginEvent
.event
= WM_RBUTTONDOWN
;
3920 case NS_MOUSE_BUTTON_UP
:
3922 case nsMouseEvent::eLeftButton
:
3923 pluginEvent
.event
= WM_LBUTTONUP
;
3925 case nsMouseEvent::eMiddleButton
:
3926 pluginEvent
.event
= WM_MBUTTONUP
;
3928 case nsMouseEvent::eRightButton
:
3929 pluginEvent
.event
= WM_RBUTTONUP
;
3935 case NS_MOUSE_DOUBLECLICK
:
3937 case nsMouseEvent::eLeftButton
:
3938 pluginEvent
.event
= WM_LBUTTONDBLCLK
;
3940 case nsMouseEvent::eMiddleButton
:
3941 pluginEvent
.event
= WM_MBUTTONDBLCLK
;
3943 case nsMouseEvent::eRightButton
:
3944 pluginEvent
.event
= WM_RBUTTONDBLCLK
;
3951 pluginEvent
.event
= WM_MOUSEMOVE
;
3954 pluginEvent
.event
= WM_MOUSELEAVE
;
3957 pluginEvent
.event
= WM_NULL
;
3961 pluginEvent
.wParam
= wParam
; // plugins NEED raw OS event flags!
3962 pluginEvent
.lParam
= lParam
;
3964 event
.pluginEvent
= (void *)&pluginEvent
;
3966 // call the event callback
3967 if (nsnull
!= mEventCallback
) {
3968 if (nsToolkit::gMouseTrailer
)
3969 nsToolkit::gMouseTrailer
->Disable();
3970 if (aEventType
== NS_MOUSE_MOVE
) {
3971 if (nsToolkit::gMouseTrailer
&& !mIsInMouseCapture
) {
3972 nsToolkit::gMouseTrailer
->SetMouseTrailerWindow(mWnd
);
3979 if (rect
.Contains(event
.refPoint
)) {
3980 if (sCurrentWindow
== NULL
|| sCurrentWindow
!= this) {
3981 if ((nsnull
!= sCurrentWindow
) && (!sCurrentWindow
->mInDtor
)) {
3982 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
3983 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_EXIT
, wParam
, pos
, PR_FALSE
,
3984 nsMouseEvent::eLeftButton
, aInputSource
);
3986 sCurrentWindow
= this;
3988 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
3989 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_ENTER
, wParam
, pos
, PR_FALSE
,
3990 nsMouseEvent::eLeftButton
, aInputSource
);
3994 } else if (aEventType
== NS_MOUSE_EXIT
) {
3995 if (sCurrentWindow
== this) {
3996 sCurrentWindow
= nsnull
;
4000 result
= DispatchWindowEvent(&event
);
4002 if (nsToolkit::gMouseTrailer
)
4003 nsToolkit::gMouseTrailer
->Enable();
4005 // Release the widget with NS_IF_RELEASE() just in case
4006 // the context menu key code in nsEventListenerManager::HandleEvent()
4007 // released it already.
4014 // Deal with accessibile event
4015 #ifdef ACCESSIBILITY
4017 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType
)
4019 if (nsnull
== mEventCallback
) {
4023 nsAccessibleEvent
event(PR_TRUE
, aEventType
, this);
4024 InitEvent(event
, nsnull
);
4026 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
4027 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
4028 event
.isMeta
= PR_FALSE
;
4029 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
4031 DispatchWindowEvent(&event
);
4033 return event
.mAccessible
;
4037 PRBool
nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType
)
4039 if (aEventType
== NS_ACTIVATE
)
4040 sJustGotActivate
= PR_FALSE
;
4041 sJustGotDeactivate
= PR_FALSE
;
4043 // retrive the toplevel window or dialog
4045 HWND toplevelWnd
= NULL
;
4047 toplevelWnd
= curWnd
;
4049 nsWindow
*win
= GetNSWindowPtr(curWnd
);
4051 nsWindowType wintype
;
4052 win
->GetWindowType(wintype
);
4053 if (wintype
== eWindowType_toplevel
|| wintype
== eWindowType_dialog
)
4057 curWnd
= ::GetParent(curWnd
); // Parent or owner (if has no parent)
4061 nsWindow
*win
= GetNSWindowPtr(toplevelWnd
);
4063 return win
->DispatchFocus(aEventType
);
4069 // Deal with focus messages
4070 PRBool
nsWindow::DispatchFocus(PRUint32 aEventType
)
4072 // call the event callback
4073 if (mEventCallback
) {
4074 nsGUIEvent
event(PR_TRUE
, aEventType
, this);
4077 //focus and blur event should go to their base widget loc, not current mouse pos
4078 event
.refPoint
.x
= 0;
4079 event
.refPoint
.y
= 0;
4081 NPEvent pluginEvent
;
4086 pluginEvent
.event
= WM_SETFOCUS
;
4089 pluginEvent
.event
= WM_KILLFOCUS
;
4091 case NS_PLUGIN_ACTIVATE
:
4092 pluginEvent
.event
= WM_KILLFOCUS
;
4098 event
.pluginEvent
= (void *)&pluginEvent
;
4100 return DispatchWindowEvent(&event
);
4105 PRBool
nsWindow::IsTopLevelMouseExit(HWND aWnd
)
4107 DWORD pos
= ::GetMessagePos();
4109 mp
.x
= GET_X_LPARAM(pos
);
4110 mp
.y
= GET_Y_LPARAM(pos
);
4111 HWND mouseWnd
= ::WindowFromPoint(mp
);
4113 // GetTopLevelHWND will return a HWND for the window frame (which includes
4114 // the non-client area). If the mouse has moved into the non-client area,
4115 // we should treat it as a top-level exit.
4116 HWND mouseTopLevel
= nsWindow::GetTopLevelHWND(mouseWnd
);
4117 if (mouseWnd
== mouseTopLevel
)
4120 return nsWindow::GetTopLevelHWND(aWnd
) != mouseTopLevel
;
4123 PRBool
nsWindow::BlurEventsSuppressed()
4125 // are they suppressed in this window?
4126 if (mBlurSuppressLevel
> 0)
4129 // are they suppressed by any container widget?
4130 HWND parentWnd
= ::GetParent(mWnd
);
4132 nsWindow
*parent
= GetNSWindowPtr(parentWnd
);
4134 return parent
->BlurEventsSuppressed();
4139 // In some circumstances (opening dependent windows) it makes more sense
4140 // (and fixes a crash bug) to not blur the parent window. Called from
4142 void nsWindow::SuppressBlurEvents(PRBool aSuppress
)
4145 ++mBlurSuppressLevel
; // for this widget
4147 NS_ASSERTION(mBlurSuppressLevel
> 0, "unbalanced blur event suppression");
4148 if (mBlurSuppressLevel
> 0)
4149 --mBlurSuppressLevel
;
4153 PRBool
nsWindow::ConvertStatus(nsEventStatus aStatus
)
4155 return aStatus
== nsEventStatus_eConsumeNoDefault
;
4158 /**************************************************************
4162 * IPC related helpers.
4164 **************************************************************/
4170 nsWindow::IsAsyncResponseEvent(UINT aMsg
, LRESULT
& aResult
)
4176 case WM_WINDOWPOSCHANGING
:
4177 case WM_WINDOWPOSCHANGED
:
4178 case WM_PARENTNOTIFY
:
4179 case WM_ACTIVATEAPP
:
4182 case WM_CHILDACTIVATE
:
4183 case WM_IME_SETCONTEXT
:
4187 case WM_MOUSEACTIVATE
:
4188 case WM_CONTEXTMENU
:
4192 case WM_SETTINGCHANGE
:
4200 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg
);
4208 nsWindow::IPCWindowProcHandler(UINT
& msg
, WPARAM
& wParam
, LPARAM
& lParam
)
4210 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4211 "Failed to prevent a nonqueued message from running!");
4213 // Modal UI being displayed in windowless plugins.
4214 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4215 (InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
4217 if (IsAsyncResponseEvent(msg
, res
)) {
4223 // Handle certain sync plugin events sent to the parent which
4224 // trigger ipc calls that result in deadlocks.
4227 PRBool handled
= PR_FALSE
;
4230 // Windowless flash sending WM_ACTIVATE events to the main window
4231 // via calls to ShowWindow.
4233 if (lParam
!= 0 && LOWORD(wParam
) == WA_ACTIVE
&&
4234 IsWindow((HWND
)lParam
))
4237 // Wheel events forwarded from the child.
4239 case WM_MOUSEHWHEEL
:
4242 // Plugins taking or losing focus triggering focus app messages.
4245 // Windowed plugins that pass sys key events to defwndproc generate
4246 // WM_SYSCOMMAND events to the main window.
4248 // Windowed plugins that fire context menu selection events to parent
4250 case WM_CONTEXTMENU
:
4251 // IME events fired as a result of synchronous focus changes
4252 case WM_IME_SETCONTEXT
:
4258 (InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
4259 ReplyMessage(dwResult
);
4265 /**************************************************************
4266 **************************************************************
4268 ** BLOCK: Native events
4270 ** Main Windows message handlers and OnXXX handlers for
4271 ** Windows event handling.
4273 **************************************************************
4274 **************************************************************/
4276 /**************************************************************
4278 * SECTION: Wind proc.
4280 * The main Windows event procedures and associated
4281 * message processing methods.
4283 **************************************************************/
4286 static int ReportException(EXCEPTION_POINTERS
*aExceptionInfo
)
4288 #ifdef MOZ_CRASHREPORTER
4289 nsCOMPtr
<nsICrashReporter
> cr
=
4290 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
4292 cr
->WriteMinidumpForException(aExceptionInfo
);
4294 return EXCEPTION_EXECUTE_HANDLER
;
4298 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
4299 // exceptions and passes the real work to WindowProcInternal. See bug 587406
4300 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
4301 LRESULT CALLBACK
nsWindow::WindowProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
4305 return WindowProcInternal(hWnd
, msg
, wParam
, lParam
);
4307 __except(ReportException(GetExceptionInformation())) {
4308 ::TerminateProcess(::GetCurrentProcess(), 253);
4311 return WindowProcInternal(hWnd
, msg
, wParam
, lParam
);
4315 LRESULT CALLBACK
nsWindow::WindowProcInternal(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
4317 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4318 MOZ_FUNCTION_NAME
, __LINE__
, hWnd
, msg
,
4321 // Get the window which caused the event and ask it to process the message
4322 nsWindow
*someWindow
= GetNSWindowPtr(hWnd
);
4326 someWindow
->IPCWindowProcHandler(msg
, wParam
, lParam
);
4329 // create this here so that we store the last rolled up popup until after
4330 // the event has been processed.
4331 nsAutoRollup autoRollup
;
4333 LRESULT popupHandlingResult
;
4334 if (DealWithPopups(hWnd
, msg
, wParam
, lParam
, &popupHandlingResult
))
4335 return popupHandlingResult
;
4337 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4338 // why we are hitting this assert
4339 if (nsnull
== someWindow
) {
4340 NS_ASSERTION(someWindow
, "someWindow is null, cannot call any CallWindowProc");
4341 return ::DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
4344 // hold on to the window for the life of this method, in case it gets
4345 // deleted during processing. yes, it's a double hack, since someWindow
4346 // is not really an interface.
4347 nsCOMPtr
<nsISupports
> kungFuDeathGrip
;
4348 if (!someWindow
->mInDtor
) // not if we're in the destructor!
4349 kungFuDeathGrip
= do_QueryInterface((nsBaseWidget
*)someWindow
);
4351 // Call ProcessMessage
4353 if (PR_TRUE
== someWindow
->ProcessMessage(msg
, wParam
, lParam
, &retValue
)) {
4357 LRESULT res
= ::CallWindowProcW(someWindow
->GetPrevWindowProc(),
4358 hWnd
, msg
, wParam
, lParam
);
4363 // The main windows message processing method for plugins.
4364 // The result means whether this method processed the native
4365 // event for plugin. If false, the native event should be
4366 // processed by the caller self.
4368 nsWindow::ProcessMessageForPlugin(const MSG
&aMsg
,
4370 PRBool
&aCallDefWndProc
)
4372 NS_PRECONDITION(aResult
, "aResult must be non-null.");
4375 aCallDefWndProc
= PR_FALSE
;
4376 PRBool eventDispatched
= PR_FALSE
;
4377 switch (aMsg
.message
) {
4380 *aResult
= ProcessCharMessage(aMsg
, &eventDispatched
);
4385 *aResult
= ProcessKeyUpMessage(aMsg
, &eventDispatched
);
4390 *aResult
= ProcessKeyDownMessage(aMsg
, &eventDispatched
);
4394 case WM_SYSDEADCHAR
:
4395 case WM_CONTEXTMENU
:
4408 if (!eventDispatched
)
4409 aCallDefWndProc
= !DispatchPluginEvent(aMsg
);
4410 DispatchPendingEvents();
4414 // The main windows message processing method.
4415 PRBool
nsWindow::ProcessMessage(UINT msg
, WPARAM
&wParam
, LPARAM
&lParam
,
4418 // (Large blocks of code should be broken out into OnEvent handlers.)
4419 if (mWindowHook
.Notify(mWnd
, msg
, wParam
, lParam
, aRetValue
))
4422 #if defined(EVENT_DEBUG_OUTPUT)
4423 // First param shows all events, second param indicates whether
4424 // to show mouse move events. See nsWindowDbg for details.
4425 PrintEvent(msg
, SHOW_REPEAT_EVENTS
, SHOW_MOUSEMOVE_EVENTS
);
4429 if (nsIMM32Handler::ProcessMessage(this, msg
, wParam
, lParam
, aRetValue
,
4431 return mWnd
? eatMessage
: PR_TRUE
;
4434 if (PluginHasFocus()) {
4435 PRBool callDefaultWndProc
;
4436 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4437 if (ProcessMessageForPlugin(nativeMsg
, aRetValue
, callDefaultWndProc
)) {
4438 return mWnd
? !callDefaultWndProc
: PR_TRUE
;
4442 PRBool result
= PR_FALSE
; // call the default nsWindow proc
4445 static PRBool getWheelInfo
= PR_TRUE
;
4447 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4448 // Glass hit testing w/custom transparent margins
4449 LRESULT dwmHitResult
;
4450 if (mCustomNonClient
&&
4451 nsUXThemeData::CheckForCompositor() &&
4452 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd
, msg
, wParam
, lParam
, &dwmHitResult
)) {
4453 *aRetValue
= dwmHitResult
;
4456 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4460 // WM_QUERYENDSESSION must be handled by all windows.
4461 // Otherwise Windows thinks the window can just be killed at will.
4462 case WM_QUERYENDSESSION
:
4463 if (sCanQuit
== TRI_UNKNOWN
)
4465 // Ask if it's ok to quit, and store the answer until we
4466 // get WM_ENDSESSION signaling the round is complete.
4467 nsCOMPtr
<nsIObserverService
> obsServ
=
4468 mozilla::services::GetObserverService();
4469 nsCOMPtr
<nsISupportsPRBool
> cancelQuit
=
4470 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID
);
4471 cancelQuit
->SetData(PR_FALSE
);
4472 obsServ
->NotifyObservers(cancelQuit
, "quit-application-requested", nsnull
);
4475 cancelQuit
->GetData(&abortQuit
);
4476 sCanQuit
= abortQuit
? TRI_FALSE
: TRI_TRUE
;
4478 *aRetValue
= sCanQuit
? TRUE
: FALSE
;
4486 case MOZ_WM_APP_QUIT
:
4487 if (msg
== MOZ_WM_APP_QUIT
|| (wParam
== TRUE
&& sCanQuit
== TRI_TRUE
))
4489 // Let's fake a shutdown sequence without actually closing windows etc.
4490 // to avoid Windows killing us in the middle. A proper shutdown would
4491 // require having a chance to pump some messages. Unfortunately
4492 // Windows won't let us do that. Bug 212316.
4493 nsCOMPtr
<nsIObserverService
> obsServ
=
4494 mozilla::services::GetObserverService();
4495 NS_NAMED_LITERAL_STRING(context
, "shutdown-persist");
4496 obsServ
->NotifyObservers(nsnull
, "quit-application-granted", nsnull
);
4497 obsServ
->NotifyObservers(nsnull
, "quit-application-forced", nsnull
);
4498 obsServ
->NotifyObservers(nsnull
, "quit-application", nsnull
);
4499 obsServ
->NotifyObservers(nsnull
, "profile-change-net-teardown", context
.get());
4500 obsServ
->NotifyObservers(nsnull
, "profile-change-teardown", context
.get());
4501 obsServ
->NotifyObservers(nsnull
, "profile-before-change", context
.get());
4502 // Then a controlled but very quick exit.
4505 sCanQuit
= TRI_UNKNOWN
;
4510 case WM_DISPLAYCHANGE
:
4511 DispatchStandardEvent(NS_DISPLAYCHANGED
);
4515 case WM_SYSCOLORCHANGE
:
4516 // Note: This is sent for child windows as well as top-level windows.
4517 // The Win32 toolkit normally only sends these events to top-level windows.
4518 // But we cycle through all of the childwindows and send it to them as well
4519 // so all presentations get notified properly.
4520 // See nsWindow::GlobalMsgWindowProc.
4521 DispatchStandardEvent(NS_SYSCOLORCHANGED
);
4527 LPNMHDR pnmh
= (LPNMHDR
) lParam
;
4529 switch (pnmh
->code
) {
4532 DispatchStandardEvent(NS_TABCHANGE
);
4540 case WM_XP_THEMECHANGED
:
4542 // Update non-client margin offsets
4543 UpdateNonClientMargins();
4545 DispatchStandardEvent(NS_THEMECHANGED
);
4547 // Invalidate the window so that the repaint will
4548 // pick up the new theme.
4549 Invalidate(PR_FALSE
);
4556 PRBool didChange
= PR_FALSE
;
4558 // update the global font list
4559 nsCOMPtr
<nsIFontEnumerator
> fontEnum
= do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv
);
4560 if (NS_SUCCEEDED(rv
)) {
4561 fontEnum
->UpdateFontList(&didChange
);
4562 //didChange is TRUE only if new font langGroup is added to the list.
4564 // update device context font cache
4565 // Dirty but easiest way:
4566 // Changing nsIPrefBranch entry which triggers callbacks
4567 // and flows into calling mDeviceContext->FlushFontCache()
4568 // to update the font cache in all the instance of Browsers
4569 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
4571 nsCOMPtr
<nsIPrefBranch
> fiPrefs
;
4572 prefs
->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs
));
4574 PRBool fontInternalChange
= PR_FALSE
;
4575 fiPrefs
->GetBoolPref("changed", &fontInternalChange
);
4576 fiPrefs
->SetBoolPref("changed", !fontInternalChange
);
4580 } //if (NS_SUCCEEDED(rv))
4586 // If wParam is TRUE, it specifies that the application should indicate
4587 // which part of the client area contains valid information. The system
4588 // copies the valid information to the specified area within the new
4589 // client area. If the wParam parameter is FALSE, the application should
4591 if (mCustomNonClient
) {
4599 // rgrc[0]: the proposed window
4600 // rgrc[1]: the current window
4601 // rgrc[2]: the source client area
4602 // pncsp->lppos: move/size data
4604 // rgrc[0]: the new client area
4605 // rgrc[1]: the destination window
4606 // rgrc[2]: the source client area
4607 // (all values in screen coordiantes)
4608 NCCALCSIZE_PARAMS
*pncsp
= reinterpret_cast<NCCALCSIZE_PARAMS
*>(lParam
);
4609 LRESULT res
= CallWindowProcW(GetPrevWindowProc(), mWnd
, msg
, wParam
, lParam
);
4610 pncsp
->rgrc
[0].top
-= mNonClientOffset
.top
;
4611 pncsp
->rgrc
[0].left
-= mNonClientOffset
.left
;
4612 pncsp
->rgrc
[0].right
+= mNonClientOffset
.right
;
4613 pncsp
->rgrc
[0].bottom
+= mNonClientOffset
.bottom
;
4624 * If an nc client area margin has been moved, we are responsible
4625 * for calculating where the resize margins are and returning the
4626 * appropriate set of hit test constants. DwmDefWindowProc (above)
4627 * will handle hit testing on it's command buttons if we are on a
4628 * composited desktop.
4631 if (!mCustomNonClient
)
4635 ClientMarginHitTestPoint(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
4642 * WM_SETTEXT paints the titlebar area. Avoid this if we have a
4643 * custom titlebar we paint ourselves.
4646 if (!mCustomNonClient
|| mNonClientMargins
.top
== -1)
4650 // From msdn, the way around this is to disable the visible state
4651 // temporarily. We need the text to be set but we don't want the
4653 DWORD style
= GetWindowLong(mWnd
, GWL_STYLE
);
4654 SetWindowLong(mWnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
4655 *aRetValue
= CallWindowProcW(GetPrevWindowProc(), mWnd
,
4656 msg
, wParam
, lParam
);
4657 SetWindowLong(mWnd
, GWL_STYLE
, style
);
4664 * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
4665 * through WM_NCPAINT via InvalidateNonClientRegion.
4668 if (!mCustomNonClient
)
4671 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4672 // let the dwm handle nc painting on glass
4673 if(nsUXThemeData::CheckForCompositor())
4677 if (wParam
== TRUE
) {
4679 *aRetValue
= FALSE
; // ignored
4681 // invalidate to trigger a paint
4682 InvalidateNonClientRegion();
4686 *aRetValue
= TRUE
; // go ahead and deactive
4688 // invalidate to trigger a paint
4689 InvalidateNonClientRegion();
4697 * Reset the non-client paint region so that it excludes the
4698 * non-client areas we paint manually. Then call defwndproc
4699 * to do the actual painting.
4702 if (!mCustomNonClient
)
4705 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4706 // let the dwm handle nc painting on glass
4707 if(nsUXThemeData::CheckForCompositor())
4711 HRGN paintRgn
= ExcludeNonClientFromPaintRegion((HRGN
)wParam
);
4712 LRESULT res
= CallWindowProcW(GetPrevWindowProc(), mWnd
,
4713 msg
, (WPARAM
)paintRgn
, lParam
);
4714 if (paintRgn
!= (HRGN
)wParam
)
4715 DeleteObject(paintRgn
);
4722 case WM_POWERBROADCAST
:
4723 // only hidden window handle this
4724 // to prevent duplicate notification
4725 if (mWindowType
== eWindowType_invisible
) {
4728 case PBT_APMSUSPEND
:
4729 PostSleepWakeNotification("sleep_notification");
4731 case PBT_APMRESUMEAUTOMATIC
:
4732 case PBT_APMRESUMECRITICAL
:
4733 case PBT_APMRESUMESUSPEND
:
4734 PostSleepWakeNotification("wake_notification");
4741 case WM_MOVE
: // Window moved
4744 ::GetWindowRect(mWnd
, &rect
);
4745 result
= OnMove(rect
.left
, rect
.top
);
4749 case WM_CLOSE
: // close request
4750 DispatchStandardEvent(NS_XUL_CLOSE
);
4751 result
= PR_TRUE
; // abort window closure
4761 *aRetValue
= (int) OnPaint(NULL
, 0);
4766 case WM_PRINTCLIENT
:
4767 result
= OnPaint((HDC
) wParam
, 0);
4772 result
= OnHotKey(wParam
, lParam
);
4778 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4779 result
= ProcessCharMessage(nativeMsg
, nsnull
);
4780 DispatchPendingEvents();
4787 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4788 result
= ProcessKeyUpMessage(nativeMsg
, nsnull
);
4789 DispatchPendingEvents();
4796 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4797 result
= ProcessKeyDownMessage(nativeMsg
, nsnull
);
4798 DispatchPendingEvents();
4802 // say we've dealt with erase background if widget does
4803 // not need auto-erasing
4805 if (!AutoErase((HDC
)wParam
)) {
4813 #ifdef WINCE_WINDOWS_MOBILE
4814 // Reset the kill timer so that we can continue at this
4816 SetTimer(mWnd
, KILL_PRIORITY_ID
, 2000 /* 2seconds */, NULL
);
4818 // Suppress dispatch of pending events
4819 // when mouse moves are generated by widget
4820 // creation instead of user input.
4821 LPARAM lParamScreen
= lParamToScreen(lParam
);
4823 mp
.x
= GET_X_LPARAM(lParamScreen
);
4824 mp
.y
= GET_Y_LPARAM(lParamScreen
);
4825 PRBool userMovedMouse
= PR_FALSE
;
4826 if ((sLastMouseMovePoint
.x
!= mp
.x
) || (sLastMouseMovePoint
.y
!= mp
.y
)) {
4827 userMovedMouse
= PR_TRUE
;
4829 mExitToNonClientArea
= PR_FALSE
;
4831 result
= DispatchMouseEvent(NS_MOUSE_MOVE
, wParam
, lParam
,
4832 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4833 if (userMovedMouse
) {
4834 DispatchPendingEvents();
4839 #ifdef WINCE_WINDOWS_MOBILE
4841 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL
);
4842 KillTimer(mWnd
, KILL_PRIORITY_ID
);
4846 case WM_LBUTTONDOWN
:
4848 #ifdef WINCE_WINDOWS_MOBILE
4849 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL
);
4850 SetTimer(mWnd
, KILL_PRIORITY_ID
, 2000 /* 2 seconds */, NULL
);
4852 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
,
4853 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4854 DispatchPendingEvents();
4860 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
,
4861 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4862 DispatchPendingEvents();
4864 #ifdef WINCE_WINDOWS_MOBILE
4865 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL
);
4866 KillTimer(mWnd
, KILL_PRIORITY_ID
);
4874 // We need to check mouse button states and put them in for
4876 WPARAM mouseState
= (GetKeyState(VK_LBUTTON
) ? MK_LBUTTON
: 0)
4877 | (GetKeyState(VK_MBUTTON
) ? MK_MBUTTON
: 0)
4878 | (GetKeyState(VK_RBUTTON
) ? MK_RBUTTON
: 0);
4879 // Synthesize an event position because we don't get one from
4881 LPARAM pos
= lParamToClient(::GetMessagePos());
4882 DispatchMouseEvent(NS_MOUSE_EXIT
, mouseState
, pos
, PR_FALSE
,
4883 nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4888 case WM_CONTEXTMENU
:
4890 // if the context menu is brought up from the keyboard, |lParam|
4893 PRBool contextMenukey
= PR_FALSE
;
4896 contextMenukey
= PR_TRUE
;
4897 pos
= lParamToClient(GetMessagePos());
4901 pos
= lParamToClient(lParam
);
4904 result
= DispatchMouseEvent(NS_CONTEXTMENU
, wParam
, pos
, contextMenukey
,
4906 nsMouseEvent::eLeftButton
:
4907 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4908 if (lParam
!= -1 && !result
&& mCustomNonClient
&&
4909 DispatchMouseEvent(NS_MOUSE_MOZHITTEST
, wParam
, pos
,
4910 PR_FALSE
, nsMouseEvent::eLeftButton
,
4911 MOUSE_INPUT_SOURCE())) {
4912 // Blank area hit, throw up the system menu.
4913 HMENU hMenu
= GetSystemMenu(mWnd
, FALSE
);
4916 TrackPopupMenu(hMenu
,
4917 (TPM_LEFTBUTTON
|TPM_RIGHTBUTTON
|
4918 TPM_RETURNCMD
|TPM_TOPALIGN
|
4919 (mIsRTL
? TPM_RIGHTALIGN
: TPM_LEFTALIGN
)),
4920 GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
),
4923 PostMessage(mWnd
, WM_SYSCOMMAND
, cmd
, 0);
4931 case WM_LBUTTONDBLCLK
:
4932 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4933 nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4934 DispatchPendingEvents();
4937 case WM_MBUTTONDOWN
:
4938 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4939 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4940 DispatchPendingEvents();
4944 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, PR_FALSE
,
4945 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4946 DispatchPendingEvents();
4949 case WM_MBUTTONDBLCLK
:
4950 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4951 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4952 DispatchPendingEvents();
4955 case WM_NCMBUTTONDOWN
:
4956 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, 0, lParamToClient(lParam
), PR_FALSE
,
4957 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4958 DispatchPendingEvents();
4961 case WM_NCMBUTTONUP
:
4962 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, 0, lParamToClient(lParam
), PR_FALSE
,
4963 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4964 DispatchPendingEvents();
4967 case WM_NCMBUTTONDBLCLK
:
4968 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, 0, lParamToClient(lParam
), PR_FALSE
,
4969 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4970 DispatchPendingEvents();
4973 case WM_RBUTTONDOWN
:
4974 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4975 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4976 DispatchPendingEvents();
4980 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, PR_FALSE
,
4981 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4982 DispatchPendingEvents();
4985 case WM_RBUTTONDBLCLK
:
4986 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4987 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4988 DispatchPendingEvents();
4991 case WM_NCRBUTTONDOWN
:
4992 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, 0, lParamToClient(lParam
),
4993 PR_FALSE
, nsMouseEvent::eRightButton
,
4994 MOUSE_INPUT_SOURCE());
4995 DispatchPendingEvents();
4998 case WM_NCRBUTTONUP
:
4999 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, 0, lParamToClient(lParam
),
5000 PR_FALSE
, nsMouseEvent::eRightButton
,
5001 MOUSE_INPUT_SOURCE());
5002 DispatchPendingEvents();
5005 case WM_NCRBUTTONDBLCLK
:
5006 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, 0, lParamToClient(lParam
),
5007 PR_FALSE
, nsMouseEvent::eRightButton
,
5008 MOUSE_INPUT_SOURCE());
5009 DispatchPendingEvents();
5014 PRUint32 appCommand
= GET_APPCOMMAND_LPARAM(lParam
);
5018 case APPCOMMAND_BROWSER_BACKWARD
:
5019 case APPCOMMAND_BROWSER_FORWARD
:
5020 case APPCOMMAND_BROWSER_REFRESH
:
5021 case APPCOMMAND_BROWSER_STOP
:
5022 case APPCOMMAND_BROWSER_SEARCH
:
5023 case APPCOMMAND_BROWSER_FAVORITES
:
5024 case APPCOMMAND_BROWSER_HOME
:
5025 DispatchCommandEvent(appCommand
);
5026 // tell the driver that we handled the event
5031 // default = PR_FALSE - tell the driver that the event was not handled
5038 result
= OnScroll(msg
, wParam
, lParam
);
5041 // The WM_ACTIVATE event is fired when a window is raised or lowered,
5042 // and the loword of wParam specifies which. But we don't want to tell
5043 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
5044 // events are fired. Instead, set either the sJustGotActivate or
5045 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
5046 // events once the focus events arrive.
5048 if (mEventCallback
) {
5049 PRInt32 fActive
= LOWORD(wParam
);
5051 #if defined(WINCE_HAVE_SOFTKB)
5052 if (mIsTopWidgetWindow
&& sSoftKeyboardState
)
5053 nsWindowCE::ToggleSoftKB(mWnd
, fActive
);
5054 if (nsWindowCE::sShowSIPButton
== TRI_FALSE
&& WA_INACTIVE
!= fActive
) {
5055 HWND hWndSIPB
= FindWindowW(L
"MS_SIPBUTTON", NULL
);
5057 ShowWindow(hWndSIPB
, SW_HIDE
);
5062 if (WA_INACTIVE
== fActive
) {
5063 // when minimizing a window, the deactivation and focus events will
5064 // be fired in the reverse order. Instead, just dispatch
5065 // NS_DEACTIVATE right away.
5067 result
= DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5069 sJustGotDeactivate
= PR_TRUE
;
5071 if (mIsTopWidgetWindow
)
5072 mLastKeyboardLayout
= gKbdLayout
.GetLayout();
5078 sJustGotActivate
= PR_TRUE
;
5079 nsMouseEvent
event(PR_TRUE
, NS_MOUSE_ACTIVATE
, this,
5080 nsMouseEvent::eReal
);
5083 event
.acceptActivation
= PR_TRUE
;
5085 DispatchWindowEvent(&event
);
5087 if (event
.acceptActivation
)
5088 *aRetValue
= MA_ACTIVATE
;
5090 *aRetValue
= MA_NOACTIVATE
;
5092 if (sSwitchKeyboardLayout
&& mLastKeyboardLayout
)
5093 ActivateKeyboardLayout(mLastKeyboardLayout
, 0);
5099 #ifdef WINCE_WINDOWS_MOBILE
5100 if (!gCheckForHTCApi
&& gHTCApiNavOpen
== nsnull
) {
5101 gCheckForHTCApi
= PR_TRUE
;
5103 HINSTANCE library
= LoadLibrary(L
"HTCAPI.dll");
5104 gHTCApiNavOpen
= (HTCApiNavOpen
) GetProcAddress(library
, "HTCNavOpen");
5105 gHTCApiNavSetMode
= (HTCApiNavSetMode
) GetProcAddress(library
,"HTCNavSetMode");
5108 if (gHTCApiNavOpen
!= nsnull
) {
5109 gHTCApiNavOpen(mWnd
, 1 /* undocumented value */);
5111 if (gHTCApiNavSetMode
!= nsnull
)
5112 gHTCApiNavSetMode ( mWnd
, 4);
5113 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5119 case WM_MOUSEACTIVATE
:
5120 if (mWindowType
== eWindowType_popup
) {
5121 // a popup with a parent owner should not be activated when clicked
5122 // but should still allow the mouse event to be fired, so the return
5123 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5124 // window, just use default processing so that the window is activated.
5125 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
5126 if (owner
&& owner
== ::GetForegroundWindow()) {
5127 *aRetValue
= MA_NOACTIVATE
;
5133 case WM_WINDOWPOSCHANGING
:
5135 LPWINDOWPOS info
= (LPWINDOWPOS
) lParam
;
5136 OnWindowPosChanging(info
);
5142 if (sJustGotActivate
) {
5143 result
= DispatchFocusToTopLevelWindow(NS_ACTIVATE
);
5146 #ifdef ACCESSIBILITY
5147 if (nsWindow::sIsAccessibilityOn
) {
5148 // Create it for the first time so that it can start firing events
5149 nsAccessible
*rootAccessible
= GetRootAccessible();
5153 #if defined(WINCE_HAVE_SOFTKB)
5155 // On Windows CE, we have a window that overlaps
5156 // the ISP button. In this case, we should always
5157 // try to hide it when we are activated
5159 nsIMEContext
IMEContext(mWnd
);
5161 ImmSetOpenStatus(IMEContext
.get(), TRUE
);
5167 #if defined(WINCE_HAVE_SOFTKB)
5169 nsIMEContext
IMEContext(mWnd
);
5170 ImmSetOpenStatus(IMEContext
.get(), FALSE
);
5173 if (sJustGotDeactivate
) {
5174 result
= DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5178 case WM_WINDOWPOSCHANGED
:
5180 WINDOWPOS
*wp
= (LPWINDOWPOS
)lParam
;
5181 OnWindowPosChanged(wp
, result
);
5185 case WM_SETTINGCHANGE
:
5186 #if !defined (WINCE_WINDOWS_MOBILE)
5187 getWheelInfo
= PR_TRUE
;
5190 case SPI_SETSIPINFO
:
5191 case SPI_SETCURRENTIM
:
5192 nsWindowCE::OnSoftKbSettingsChange(mWnd
);
5194 case SETTINGCHANGE_RESET
:
5195 if (mWindowType
== eWindowType_invisible
) {
5196 // The OS sees to get confused and think that the invisable window
5197 // is in the foreground after an orientation change. By actually
5198 // setting it to the foreground and hiding it, we set it strait.
5199 // See bug 514007 for details.
5200 SetForegroundWindow(mWnd
);
5201 ShowWindow(mWnd
, SW_HIDE
);
5206 OnSettingsChange(wParam
, lParam
);
5210 case WM_INPUTLANGCHANGEREQUEST
:
5215 case WM_INPUTLANGCHANGE
:
5216 result
= OnInputLangChange((HKL
)lParam
);
5220 case WM_DESTROYCLIPBOARD
:
5222 nsIClipboard
* clipboard
;
5223 nsresult rv
= CallGetService(kCClipboardCID
, &clipboard
);
5224 if(NS_SUCCEEDED(rv
)) {
5225 clipboard
->EmptyClipboard(nsIClipboard::kGlobalClipboard
);
5226 NS_RELEASE(clipboard
);
5231 #ifdef ACCESSIBILITY
5235 if (lParam
== OBJID_CLIENT
) { // oleacc.dll will be loaded dynamically
5236 nsAccessible
*rootAccessible
= GetRootAccessible(); // Held by a11y cache
5237 if (rootAccessible
) {
5238 IAccessible
*msaaAccessible
= NULL
;
5239 rootAccessible
->GetNativeInterface((void**)&msaaAccessible
); // does an addref
5240 if (msaaAccessible
) {
5241 *aRetValue
= LresultFromObject(IID_IAccessible
, wParam
, msaaAccessible
); // does an addref
5242 msaaAccessible
->Release(); // release extra addref
5243 result
= PR_TRUE
; // We handled the WM_GETOBJECT message
5252 // prevent Windows from trimming the working set. bug 76831
5253 if (!sTrimOnMinimize
&& wParam
== SC_MINIMIZE
) {
5254 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
5263 nsMemory::HeapMinimize(PR_TRUE
);
5268 case WM_MOUSEHWHEEL
:
5270 // If OnMouseWheel returns true, the event was forwarded directly to another
5271 // mozilla window message handler (ProcessMessage). In this case the return
5272 // value of the forwarded event is in 'result' which we should return immediately.
5273 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5274 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5275 // we should fall through.
5276 if (OnMouseWheel(msg
, wParam
, lParam
, getWheelInfo
, result
, aRetValue
))
5282 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5283 case WM_DWMCOMPOSITIONCHANGED
:
5284 UpdateNonClientMargins();
5285 BroadcastMsg(mWnd
, WM_DWMCOMPOSITIONCHANGED
);
5286 DispatchStandardEvent(NS_THEMECHANGED
);
5288 Invalidate(PR_FALSE
);
5292 case WM_UPDATEUISTATE
:
5294 // If the UI state has changed, fire an event so the UI updates the
5295 // keyboard cues based on the system setting and how the window was
5296 // opened. For example, a dialog opened via a keyboard press on a button
5297 // should enable cues, whereas the same dialog opened via a mouse click of
5298 // the button should not.
5299 PRInt32 action
= LOWORD(wParam
);
5300 if (action
== UIS_SET
|| action
== UIS_CLEAR
) {
5301 nsUIStateChangeEvent
event(PR_TRUE
, NS_UISTATECHANGED
, this);
5302 PRInt32 flags
= HIWORD(wParam
);
5303 if (flags
& UISF_HIDEACCEL
)
5304 event
.showAccelerators
= (action
== UIS_SET
) ? UIStateChangeType_Clear
: UIStateChangeType_Set
;
5305 if (flags
& UISF_HIDEFOCUS
)
5306 event
.showFocusRings
= (action
== UIS_SET
) ? UIStateChangeType_Clear
: UIStateChangeType_Set
;
5307 DispatchWindowEvent(&event
);
5313 /* Gesture support events */
5314 case WM_TABLET_QUERYSYSTEMGESTURESTATUS
:
5315 // According to MS samples, this must be handled to enable
5316 // rotational support in multi-touch drivers.
5318 *aRetValue
= TABLET_ROTATE_GESTURE_ENABLE
;
5321 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5323 result
= OnTouch(wParam
, lParam
);
5331 result
= OnGesture(wParam
, lParam
);
5334 case WM_GESTURENOTIFY
:
5336 if (mWindowType
!= eWindowType_invisible
&&
5337 mWindowType
!= eWindowType_plugin
) {
5338 // A GestureNotify event is dispatched to decide which single-finger panning
5339 // direction should be active (including none) and if pan feedback should
5340 // be displayed. Java and plugin windows can make their own calls.
5341 GESTURENOTIFYSTRUCT
* gestureinfo
= (GESTURENOTIFYSTRUCT
*)lParam
;
5342 nsPointWin touchPoint
;
5343 touchPoint
= gestureinfo
->ptsLocation
;
5344 touchPoint
.ScreenToClient(mWnd
);
5345 nsGestureNotifyEvent
gestureNotifyEvent(PR_TRUE
, NS_GESTURENOTIFY_EVENT_START
, this);
5346 gestureNotifyEvent
.refPoint
= touchPoint
;
5347 nsEventStatus status
;
5348 DispatchEvent(&gestureNotifyEvent
, status
);
5349 mDisplayPanFeedback
= gestureNotifyEvent
.displayPanFeedback
;
5351 mGesture
.SetWinGestureSupport(mWnd
, gestureNotifyEvent
.panDirection
);
5353 result
= PR_FALSE
; //should always bubble to DefWindowProc
5356 #endif // !defined(WINCE)
5360 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_DELETE
, this);
5361 DispatchWindowEvent(&command
);
5368 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_CUT
, this);
5369 DispatchWindowEvent(&command
);
5376 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_COPY
, this);
5377 DispatchWindowEvent(&command
);
5384 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_PASTE
, this);
5385 DispatchWindowEvent(&command
);
5393 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_UNDO
, this);
5394 DispatchWindowEvent(&command
);
5395 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5402 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_REDO
, this);
5403 DispatchWindowEvent(&command
);
5404 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5411 // Support EM_CANPASTE message only when wParam isn't specified or
5412 // is plain text format.
5413 if (wParam
== 0 || wParam
== CF_TEXT
|| wParam
== CF_UNICODETEXT
) {
5414 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_PASTE
,
5416 DispatchWindowEvent(&command
);
5417 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5425 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_UNDO
,
5427 DispatchWindowEvent(&command
);
5428 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5435 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_REDO
,
5437 DispatchWindowEvent(&command
);
5438 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5444 #ifdef WINCE_WINDOWS_MOBILE
5445 //HTC NAVIGATION WHEEL EVENT
5448 int distance
= wParam
& 0x000000FF;
5449 if ( (wParam
& 0x000000100) != 0) // Counter Clockwise
5451 if (OnMouseWheel(WM_MOUSEWHEEL
, MAKEWPARAM(0, distance
),
5452 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN
) / 2,
5453 GetSystemMetrics(SM_CYSCREEN
) / 2),
5454 getWheelInfo
, result
, aRetValue
))
5462 #ifdef NS_ENABLE_TSF
5463 if (msg
== WM_USER_TSF_TEXTCHANGE
) {
5464 nsTextStore::OnTextChangeMsg();
5466 #endif //NS_ENABLE_TSF
5467 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5468 if (msg
== nsAppShell::GetTaskbarButtonCreatedMessage())
5469 SetHasTaskbarIconBeenCreated();
5472 if (msg
== sOOPPPluginFocusEvent
) {
5474 // With OOPP, the plugin window exists in another process and is a child of
5475 // this window. This window is a placeholder plugin window for the dom. We
5476 // receive this event when the child window receives focus. (sent from
5477 // PluginInstanceParent.cpp)
5478 ::SendMessage(mWnd
, WM_MOUSEACTIVATE
, 0, 0); // See nsPluginNativeWindowWin.cpp
5480 // WM_KILLFOCUS was received by the child process.
5481 if (sJustGotDeactivate
) {
5482 DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5491 //*aRetValue = result;
5496 //Events which caused mWnd destruction and aren't consumed
5497 //will crash during the Windows default processing.
5502 /**************************************************************
5504 * SECTION: Broadcast messaging
5506 * Broadcast messages to all windows.
5508 **************************************************************/
5510 // Enumerate all child windows sending aMsg to each of them
5511 BOOL CALLBACK
nsWindow::BroadcastMsgToChildren(HWND aWnd
, LPARAM aMsg
)
5513 WNDPROC winProc
= (WNDPROC
)::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
5514 if (winProc
== &nsWindow::WindowProc
) {
5515 // it's one of our windows so go ahead and send a message to it
5516 ::CallWindowProcW(winProc
, aWnd
, aMsg
, 0, 0);
5521 // Enumerate all top level windows specifying that the children of each
5522 // top level window should be enumerated. Do *not* send the message to
5523 // each top level window since it is assumed that the toolkit will send
5524 // aMsg to them directly.
5525 BOOL CALLBACK
nsWindow::BroadcastMsg(HWND aTopWindow
, LPARAM aMsg
)
5527 // Iterate each of aTopWindows child windows sending the aMsg
5530 ::EnumChildWindows(aTopWindow
, nsWindow::BroadcastMsgToChildren
, aMsg
);
5532 nsWindowCE::EnumChildWindows(aTopWindow
, nsWindow::BroadcastMsgToChildren
, aMsg
);
5537 // This method is called from nsToolkit::WindowProc to forward global
5538 // messages which need to be dispatched to all child windows.
5539 void nsWindow::GlobalMsgWindowProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
5542 case WM_SYSCOLORCHANGE
:
5543 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5544 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5545 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5546 // all child windows as well. When running in an embedded application
5547 // we may not receive a WM_SYSCOLORCHANGE message because the top
5548 // level window is owned by the embeddor.
5549 // System color changes are posted to top-level windows only.
5550 // The NS_SYSCOLORCHANGE must be dispatched to all child
5553 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg
, msg
);
5559 /**************************************************************
5561 * SECTION: Event processing helpers
5563 * Special processing for certain event types and
5564 * synthesized events.
5566 **************************************************************/
5569 nsWindow::ClientMarginHitTestPoint(PRInt32 mx
, PRInt32 my
)
5571 // Calculations are done in screen coords
5573 GetWindowRect(mWnd
, &winRect
);
5575 // hit return constants:
5576 // HTBORDER - non-resizable border
5577 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5578 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5579 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5580 // HTCAPTION - general title bar area
5581 // HTCLIENT - area considered the client
5582 // HTCLOSE - hovering over the close button
5583 // HTMAXBUTTON - maximize button
5584 // HTMINBUTTON - minimize button
5586 PRInt32 testResult
= HTCLIENT
;
5588 PRBool top
= PR_FALSE
;
5589 PRBool bottom
= PR_FALSE
;
5590 PRBool left
= PR_FALSE
;
5591 PRBool right
= PR_FALSE
;
5593 if (my
>= winRect
.top
&& my
<=
5594 (winRect
.top
+ mVertResizeMargin
+ (mCaptionHeight
- mNonClientOffset
.top
)))
5596 else if (my
<= winRect
.bottom
&& my
>= (winRect
.bottom
- mVertResizeMargin
))
5599 if (mx
>= winRect
.left
&& mx
<= (winRect
.left
+ mHorResizeMargin
))
5601 else if (mx
<= winRect
.right
&& mx
>= (winRect
.right
- mHorResizeMargin
))
5607 testResult
= HTTOPLEFT
;
5609 testResult
= HTTOPRIGHT
;
5610 } else if (bottom
) {
5611 testResult
= HTBOTTOM
;
5613 testResult
= HTBOTTOMLEFT
;
5615 testResult
= HTBOTTOMRIGHT
;
5618 testResult
= HTLEFT
;
5620 testResult
= HTRIGHT
;
5623 PRBool contentOverlap
= PR_TRUE
;
5625 if (mSizeMode
== nsSizeMode_Maximized
) {
5626 // There's no HTTOP in maximized state (bug 575493)
5627 if (testResult
== HTTOP
) {
5628 testResult
= HTCAPTION
;
5631 PRInt32 leftMargin
= mNonClientMargins
.left
== -1 ? mHorResizeMargin
: mNonClientMargins
.left
;
5632 PRInt32 rightMargin
= mNonClientMargins
.right
== -1 ? mHorResizeMargin
: mNonClientMargins
.right
;
5633 PRInt32 topMargin
= mNonClientMargins
.top
== -1 ? mVertResizeMargin
: mNonClientMargins
.top
;
5634 PRInt32 bottomMargin
= mNonClientMargins
.bottom
== -1 ? mVertResizeMargin
: mNonClientMargins
.bottom
;
5636 contentOverlap
= mx
>= winRect
.left
+ leftMargin
&&
5637 mx
<= winRect
.right
- rightMargin
&&
5638 my
>= winRect
.top
+ topMargin
&&
5639 my
<= winRect
.bottom
- bottomMargin
;
5642 if (!mIsInMouseCapture
&&
5644 (testResult
== HTCLIENT
||
5645 testResult
== HTTOP
||
5646 testResult
== HTTOPLEFT
||
5647 testResult
== HTCAPTION
)) {
5648 LPARAM lParam
= MAKELPARAM(mx
, my
);
5649 LPARAM lParamClient
= lParamToClient(lParam
);
5650 PRBool result
= DispatchMouseEvent(NS_MOUSE_MOZHITTEST
, 0, lParamClient
,
5651 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
5653 // The mouse is over a blank area
5654 testResult
= testResult
== HTCLIENT
? HTCAPTION
: testResult
;
5656 if (!mExitToNonClientArea
) {
5657 // The first time the mouse pointer goes from client area to non-client area,
5658 // we don't want to miss that movement so we can interpret mouseout input.
5659 ::SendMessage(mWnd
, WM_MOUSEMOVE
, 0, lParamClient
);
5660 mExitToNonClientArea
= PR_TRUE
;
5663 // There's content over the mouse pointer. Set HTCLIENT
5664 // to possibly override a resizer border.
5665 testResult
= HTCLIENT
;
5673 void nsWindow::PostSleepWakeNotification(const char* aNotification
)
5675 nsCOMPtr
<nsIObserverService
> observerService
=
5676 mozilla::services::GetObserverService();
5677 if (observerService
)
5678 observerService
->NotifyObservers(nsnull
, aNotification
, nsnull
);
5682 LRESULT
nsWindow::ProcessCharMessage(const MSG
&aMsg
, PRBool
*aEventDispatched
)
5684 NS_PRECONDITION(aMsg
.message
== WM_CHAR
|| aMsg
.message
== WM_SYSCHAR
,
5685 "message is not keydown event");
5686 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5687 ("%s charCode=%d scanCode=%d\n",
5688 aMsg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
5689 aMsg
.wParam
, HIWORD(aMsg
.lParam
) & 0xFF));
5691 // These must be checked here too as a lone WM_CHAR could be received
5692 // if a child window didn't handle it (for example Alt+Space in a content window)
5693 nsModifierKeyState modKeyState
;
5694 return OnChar(aMsg
, modKeyState
, aEventDispatched
);
5697 LRESULT
nsWindow::ProcessKeyUpMessage(const MSG
&aMsg
, PRBool
*aEventDispatched
)
5699 NS_PRECONDITION(aMsg
.message
== WM_KEYUP
|| aMsg
.message
== WM_SYSKEYUP
,
5700 "message is not keydown event");
5701 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5702 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
5703 "WM_SYSKEYUP" : "WM_KEYUP", aMsg
.wParam
));
5705 nsModifierKeyState modKeyState
;
5707 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5708 // scan code. However, this breaks Alt+Num pad input.
5709 // MSDN states the following:
5710 // Typically, ToAscii performs the translation based on the
5711 // virtual-key code. In some cases, however, bit 15 of the
5712 // uScanCode parameter may be used to distinguish between a key
5713 // press and a key release. The scan code is used for
5714 // translating ALT+number key combinations.
5716 // ignore [shift+]alt+space so the OS can handle it
5717 if (modKeyState
.mIsAltDown
&& !modKeyState
.mIsControlDown
&&
5718 IS_VK_DOWN(NS_VK_SPACE
)) {
5722 if (!nsIMM32Handler::IsComposingOn(this) &&
5723 (aMsg
.message
!= WM_KEYUP
|| aMsg
.wParam
!= VK_MENU
)) {
5724 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5725 // This helps avoid triggering the menu bar for ALT key accelerators used in
5726 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5727 // to switch back to Mozilla in Windows 95 and Windows 98
5728 return OnKeyUp(aMsg
, modKeyState
, aEventDispatched
);
5734 LRESULT
nsWindow::ProcessKeyDownMessage(const MSG
&aMsg
,
5735 PRBool
*aEventDispatched
)
5737 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5738 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
5739 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg
.wParam
));
5740 NS_PRECONDITION(aMsg
.message
== WM_KEYDOWN
|| aMsg
.message
== WM_SYSKEYDOWN
,
5741 "message is not keydown event");
5743 nsModifierKeyState modKeyState
;
5745 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
5746 // scan code. However, this breaks Alt+Num pad input.
5747 // MSDN states the following:
5748 // Typically, ToAscii performs the translation based on the
5749 // virtual-key code. In some cases, however, bit 15 of the
5750 // uScanCode parameter may be used to distinguish between a key
5751 // press and a key release. The scan code is used for
5752 // translating ALT+number key combinations.
5754 // ignore [shift+]alt+space so the OS can handle it
5755 if (modKeyState
.mIsAltDown
&& !modKeyState
.mIsControlDown
&&
5756 IS_VK_DOWN(NS_VK_SPACE
))
5760 if (modKeyState
.mIsAltDown
&& nsIMM32Handler::IsStatusChanged()) {
5761 nsIMM32Handler::NotifyEndStatusChange();
5762 } else if (!nsIMM32Handler::IsComposingOn(this)) {
5763 result
= OnKeyDown(aMsg
, modKeyState
, aEventDispatched
, nsnull
);
5767 if (aMsg
.wParam
== VK_MENU
||
5768 (aMsg
.wParam
== VK_F10
&& !modKeyState
.mIsShiftDown
)) {
5769 // We need to let Windows handle this keypress,
5770 // by returning PR_FALSE, if there's a native menu
5771 // bar somewhere in our containing window hierarchy.
5772 // Otherwise we handle the keypress and don't pass
5773 // it on to Windows, by returning PR_TRUE.
5774 PRBool hasNativeMenu
= PR_FALSE
;
5777 if (::GetMenu(hWnd
)) {
5778 hasNativeMenu
= PR_TRUE
;
5781 hWnd
= ::GetParent(hWnd
);
5783 result
= !hasNativeMenu
;
5791 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout
,
5792 PRInt32 aNativeKeyCode
,
5793 PRUint32 aModifierFlags
,
5794 const nsAString
& aCharacters
,
5795 const nsAString
& aUnmodifiedCharacters
)
5797 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
5798 nsPrintfCString
layoutName("%08x", aNativeKeyboardLayout
);
5799 HKL loadedLayout
= LoadKeyboardLayoutA(layoutName
.get(), KLF_NOTELLSHELL
);
5800 if (loadedLayout
== NULL
)
5801 return NS_ERROR_NOT_AVAILABLE
;
5803 // Setup clean key state and load desired layout
5804 BYTE originalKbdState
[256];
5805 ::GetKeyboardState(originalKbdState
);
5807 memset(kbdState
, 0, sizeof(kbdState
));
5808 // This changes the state of the keyboard for the current thread only,
5809 // and we'll restore it soon, so this should be OK.
5810 ::SetKeyboardState(kbdState
);
5811 HKL oldLayout
= gKbdLayout
.GetLayout();
5812 gKbdLayout
.LoadLayout(loadedLayout
);
5814 nsAutoTArray
<KeyPair
,10> keySequence
;
5815 SetupKeyModifiersSequence(&keySequence
, aModifierFlags
);
5816 NS_ASSERTION(aNativeKeyCode
>= 0 && aNativeKeyCode
< 256,
5817 "Native VK key code out of range");
5818 keySequence
.AppendElement(KeyPair(aNativeKeyCode
, 0));
5820 // Simulate the pressing of each modifier key and then the real key
5821 for (PRUint32 i
= 0; i
< keySequence
.Length(); ++i
) {
5822 PRUint8 key
= keySequence
[i
].mGeneral
;
5823 PRUint8 keySpecific
= keySequence
[i
].mSpecific
;
5824 kbdState
[key
] = 0x81; // key is down and toggled on if appropriate
5826 kbdState
[keySpecific
] = 0x81;
5828 ::SetKeyboardState(kbdState
);
5829 nsModifierKeyState modKeyState
;
5830 MSG msg
= InitMSG(WM_KEYDOWN
, key
, 0);
5831 if (i
== keySequence
.Length() - 1 && aCharacters
.Length() > 0) {
5832 UINT scanCode
= ::MapVirtualKeyEx(aNativeKeyCode
, MAPVK_VK_TO_VSC
,
5833 gKbdLayout
.GetLayout());
5834 nsFakeCharMessage fakeMsg
= { aCharacters
.CharAt(0), scanCode
};
5835 OnKeyDown(msg
, modKeyState
, nsnull
, &fakeMsg
);
5837 OnKeyDown(msg
, modKeyState
, nsnull
, nsnull
);
5840 for (PRUint32 i
= keySequence
.Length(); i
> 0; --i
) {
5841 PRUint8 key
= keySequence
[i
- 1].mGeneral
;
5842 PRUint8 keySpecific
= keySequence
[i
- 1].mSpecific
;
5843 kbdState
[key
] = 0; // key is up and toggled off if appropriate
5845 kbdState
[keySpecific
] = 0;
5847 ::SetKeyboardState(kbdState
);
5848 nsModifierKeyState modKeyState
;
5849 MSG msg
= InitMSG(WM_KEYUP
, key
, 0);
5850 OnKeyUp(msg
, modKeyState
, nsnull
);
5853 // Restore old key state and layout
5854 ::SetKeyboardState(originalKbdState
);
5855 gKbdLayout
.LoadLayout(oldLayout
);
5857 UnloadKeyboardLayout(loadedLayout
);
5859 #else //XXX: is there another way to do this?
5860 return NS_ERROR_NOT_IMPLEMENTED
;
5865 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint
,
5866 PRUint32 aNativeMessage
,
5867 PRUint32 aModifierFlags
)
5869 #ifndef WINCE // I don't think WINCE supports SendInput
5871 ::GetWindowRect(mWnd
, &r
);
5872 ::SetCursorPos(r
.left
+ aPoint
.x
, r
.top
+ aPoint
.y
);
5875 memset(&input
, 0, sizeof(input
));
5877 input
.type
= INPUT_MOUSE
;
5878 input
.mi
.dwFlags
= aNativeMessage
;
5879 ::SendInput(1, &input
, sizeof(INPUT
));
5883 return NS_ERROR_NOT_IMPLEMENTED
;
5887 /**************************************************************
5889 * SECTION: OnXXX message handlers
5891 * For message handlers that need to be broken out or
5892 * implemented in specific platform code.
5894 **************************************************************/
5896 BOOL
nsWindow::OnInputLangChange(HKL aHKL
)
5899 printf("OnInputLanguageChange\n");
5903 gKbdLayout
.LoadLayout(aHKL
);
5906 return PR_FALSE
; // always pass to child window
5909 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5910 void nsWindow::OnWindowPosChanged(WINDOWPOS
*wp
, PRBool
& result
)
5915 #ifdef WINSTATE_DEBUG_OUTPUT
5916 if (mWnd
== GetTopLevelHWND(mWnd
))
5917 printf("*** OnWindowPosChanged: [ top] ");
5919 printf("*** OnWindowPosChanged: [child] ");
5920 printf("WINDOWPOS flags:");
5921 if (wp
->flags
& SWP_FRAMECHANGED
)
5922 printf("SWP_FRAMECHANGED ");
5923 if (wp
->flags
& SWP_SHOWWINDOW
)
5924 printf("SWP_SHOWWINDOW ");
5925 if (wp
->flags
& SWP_NOSIZE
)
5926 printf("SWP_NOSIZE ");
5927 if (wp
->flags
& SWP_HIDEWINDOW
)
5928 printf("SWP_HIDEWINDOW ");
5932 // Handle window size mode changes
5933 if (wp
->flags
& SWP_FRAMECHANGED
&& mSizeMode
!= nsSizeMode_Fullscreen
) {
5934 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
5937 pl
.length
= sizeof(pl
);
5938 ::GetWindowPlacement(mWnd
, &pl
);
5940 if (pl
.showCmd
== SW_SHOWMAXIMIZED
)
5941 event
.mSizeMode
= nsSizeMode_Maximized
;
5942 else if (pl
.showCmd
== SW_SHOWMINIMIZED
)
5943 event
.mSizeMode
= nsSizeMode_Minimized
;
5944 else if (mFullscreenMode
)
5945 event
.mSizeMode
= nsSizeMode_Fullscreen
;
5947 event
.mSizeMode
= nsSizeMode_Normal
;
5949 // Windows has just changed the size mode of this window. The following
5950 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
5951 // set the min/max window state again or for nsSizeMode_Normal, call
5952 // SetWindow with a parameter of SW_RESTORE. There's no need however as
5953 // this window's mode has already changed. Updating mSizeMode here
5954 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
5955 // to window docking. (bug 489258)
5956 mSizeMode
= event
.mSizeMode
;
5958 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
5959 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
5960 // prevents the working set from being trimmed but keeps the window active.
5961 // After the window is minimized, we need to do some touch up work on the
5962 // active window. (bugs 76831 & 499816)
5963 if (!sTrimOnMinimize
&& nsSizeMode_Minimized
== event
.mSizeMode
)
5964 ActivateOtherWindowHelper(mWnd
);
5966 #ifdef WINSTATE_DEBUG_OUTPUT
5967 switch (mSizeMode
) {
5968 case nsSizeMode_Normal
:
5969 printf("*** mSizeMode: nsSizeMode_Normal\n");
5971 case nsSizeMode_Minimized
:
5972 printf("*** mSizeMode: nsSizeMode_Minimized\n");
5974 case nsSizeMode_Maximized
:
5975 printf("*** mSizeMode: nsSizeMode_Maximized\n");
5978 printf("*** mSizeMode: ??????\n");
5985 result
= DispatchWindowEvent(&event
);
5987 // Skip window size change events below on minimization.
5988 if (mSizeMode
== nsSizeMode_Minimized
)
5992 // Handle window size changes
5993 if (0 == (wp
->flags
& SWP_NOSIZE
)) {
5995 PRInt32 newWidth
, newHeight
;
5997 ::GetWindowRect(mWnd
, &r
);
5999 newWidth
= r
.right
- r
.left
;
6000 newHeight
= r
.bottom
- r
.top
;
6001 nsIntRect
rect(wp
->x
, wp
->y
, newWidth
, newHeight
);
6004 if (eTransparencyTransparent
== mTransparencyMode
)
6005 ResizeTranslucentWindow(newWidth
, newHeight
);
6008 if (newWidth
> mLastSize
.width
)
6013 drect
.left
= wp
->x
+ mLastSize
.width
;
6015 drect
.right
= drect
.left
+ (newWidth
- mLastSize
.width
);
6016 drect
.bottom
= drect
.top
+ newHeight
;
6018 ::RedrawWindow(mWnd
, &drect
, NULL
,
6021 RDW_NOINTERNALPAINT
|
6025 if (newHeight
> mLastSize
.height
)
6031 drect
.top
= wp
->y
+ mLastSize
.height
;
6032 drect
.right
= drect
.left
+ newWidth
;
6033 drect
.bottom
= drect
.top
+ (newHeight
- mLastSize
.height
);
6035 ::RedrawWindow(mWnd
, &drect
, NULL
,
6038 RDW_NOINTERNALPAINT
|
6043 mBounds
.width
= newWidth
;
6044 mBounds
.height
= newHeight
;
6045 mLastSize
.width
= newWidth
;
6046 mLastSize
.height
= newHeight
;
6048 #ifdef WINSTATE_DEBUG_OUTPUT
6049 printf("*** Resize window: %d x %d x %d x %d\n", wp
->x
, wp
->y
, newWidth
, newHeight
);
6052 // If a maximized window is resized, recalculate the non-client margins and
6053 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
6055 if (mSizeMode
== nsSizeMode_Maximized
) {
6056 if (UpdateNonClientMargins(nsSizeMode_Maximized
, PR_TRUE
)) {
6057 // gecko resize event already sent by UpdateNonClientMargins.
6063 // Recalculate the width and height based on the client area for gecko events.
6064 if (::GetClientRect(mWnd
, &r
)) {
6065 rect
.width
= r
.right
- r
.left
;
6066 rect
.height
= r
.bottom
- r
.top
;
6069 // Send a gecko resize event
6070 result
= OnResize(rect
);
6075 void nsWindow::ActivateOtherWindowHelper(HWND aWnd
)
6077 // Find the next window that is enabled, visible, and not minimized.
6078 HWND hwndBelow
= ::GetNextWindow(aWnd
, GW_HWNDNEXT
);
6079 while (hwndBelow
&& (!::IsWindowEnabled(hwndBelow
) || !::IsWindowVisible(hwndBelow
) ||
6080 ::IsIconic(hwndBelow
))) {
6081 hwndBelow
= ::GetNextWindow(hwndBelow
, GW_HWNDNEXT
);
6084 // Push ourselves to the bottom of the stack, then activate the
6086 ::SetWindowPos(aWnd
, HWND_BOTTOM
, 0, 0, 0, 0,
6087 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
);
6089 ::SetForegroundWindow(hwndBelow
);
6091 // Play the minimize sound while we're here, since that is also
6092 // forgotten when we use SW_SHOWMINIMIZED.
6093 ::PlaySoundW(L
"Minimize", nsnull
, SND_ALIAS
| SND_NODEFAULT
| SND_ASYNC
);
6095 #endif // !defined(WINCE)
6098 void nsWindow::OnWindowPosChanging(LPWINDOWPOS
& info
)
6100 // Update non-client margins if the frame size is changing, and let the
6101 // browser know we are changing size modes, so alternative css can kick in.
6102 // If we're going into fullscreen mode, ignore this, since it'll reset
6103 // margins to normal mode.
6104 if (info
->flags
& SWP_FRAMECHANGED
&& mSizeMode
!= nsSizeMode_Fullscreen
) {
6106 pl
.length
= sizeof(pl
);
6107 ::GetWindowPlacement(mWnd
, &pl
);
6109 if (pl
.showCmd
== SW_SHOWMAXIMIZED
)
6110 sizeMode
= nsSizeMode_Maximized
;
6111 else if (pl
.showCmd
== SW_SHOWMINIMIZED
)
6112 sizeMode
= nsSizeMode_Minimized
;
6113 else if (mFullscreenMode
)
6114 sizeMode
= nsSizeMode_Fullscreen
;
6116 sizeMode
= nsSizeMode_Normal
;
6118 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
6121 event
.mSizeMode
= static_cast<nsSizeMode
>(sizeMode
);
6122 DispatchWindowEvent(&event
);
6124 UpdateNonClientMargins(sizeMode
, PR_FALSE
);
6127 // enforce local z-order rules
6128 if (!(info
->flags
& SWP_NOZORDER
)) {
6129 HWND hwndAfter
= info
->hwndInsertAfter
;
6131 nsZLevelEvent
event(PR_TRUE
, NS_SETZLEVEL
, this);
6132 nsWindow
*aboveWindow
= 0;
6136 if (hwndAfter
== HWND_BOTTOM
)
6137 event
.mPlacement
= nsWindowZBottom
;
6138 else if (hwndAfter
== HWND_TOP
|| hwndAfter
== HWND_TOPMOST
|| hwndAfter
== HWND_NOTOPMOST
)
6139 event
.mPlacement
= nsWindowZTop
;
6141 event
.mPlacement
= nsWindowZRelative
;
6142 aboveWindow
= GetNSWindowPtr(hwndAfter
);
6144 event
.mReqBelow
= aboveWindow
;
6145 event
.mActualBelow
= nsnull
;
6147 event
.mImmediate
= PR_FALSE
;
6148 event
.mAdjusted
= PR_FALSE
;
6149 DispatchWindowEvent(&event
);
6151 if (event
.mAdjusted
) {
6152 if (event
.mPlacement
== nsWindowZBottom
)
6153 info
->hwndInsertAfter
= HWND_BOTTOM
;
6154 else if (event
.mPlacement
== nsWindowZTop
)
6155 info
->hwndInsertAfter
= HWND_TOP
;
6157 info
->hwndInsertAfter
= (HWND
)event
.mActualBelow
->GetNativeData(NS_NATIVE_WINDOW
);
6160 NS_IF_RELEASE(event
.mActualBelow
);
6162 // prevent rude external programs from making hidden window visible
6163 if (mWindowType
== eWindowType_invisible
)
6164 info
->flags
&= ~SWP_SHOWWINDOW
;
6168 void nsWindow::UserActivity()
6170 // Check if we have the idle service, if not we try to get it.
6171 if (!mIdleService
) {
6172 mIdleService
= do_GetService("@mozilla.org/widget/idleservice;1");
6175 // Check that we now have the idle service.
6177 mIdleService
->ResetIdleTimeOut();
6181 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6182 PRBool
nsWindow::OnTouch(WPARAM wParam
, LPARAM lParam
)
6184 PRUint32 cInputs
= LOWORD(wParam
);
6185 PTOUCHINPUT pInputs
= new TOUCHINPUT
[cInputs
];
6187 if (mGesture
.GetTouchInputInfo((HTOUCHINPUT
)lParam
, cInputs
, pInputs
)) {
6188 for (PRUint32 i
= 0; i
< cInputs
; i
++) {
6190 if (pInputs
[i
].dwFlags
& TOUCHEVENTF_MOVE
) {
6191 msg
= NS_MOZTOUCH_MOVE
;
6192 } else if (pInputs
[i
].dwFlags
& TOUCHEVENTF_DOWN
) {
6193 msg
= NS_MOZTOUCH_DOWN
;
6194 } else if (pInputs
[i
].dwFlags
& TOUCHEVENTF_UP
) {
6195 msg
= NS_MOZTOUCH_UP
;
6200 nsPointWin touchPoint
;
6201 touchPoint
.x
= TOUCH_COORD_TO_PIXEL(pInputs
[i
].x
);
6202 touchPoint
.y
= TOUCH_COORD_TO_PIXEL(pInputs
[i
].y
);
6203 touchPoint
.ScreenToClient(mWnd
);
6205 nsMozTouchEvent
touchEvent(PR_TRUE
, msg
, this, pInputs
[i
].dwID
);
6206 touchEvent
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6207 touchEvent
.refPoint
= touchPoint
;
6209 nsEventStatus status
;
6210 DispatchEvent(&touchEvent
, status
);
6215 mGesture
.CloseTouchInputHandle((HTOUCHINPUT
)lParam
);
6220 // Gesture event processing. Handles WM_GESTURE events.
6222 PRBool
nsWindow::OnGesture(WPARAM wParam
, LPARAM lParam
)
6224 // Treatment for pan events which translate into scroll events:
6225 if (mGesture
.IsPanEvent(lParam
)) {
6226 nsMouseScrollEvent
event(PR_TRUE
, NS_MOUSE_PIXEL_SCROLL
, this);
6228 if ( !mGesture
.ProcessPanMessage(mWnd
, wParam
, lParam
) )
6229 return PR_FALSE
; // ignore
6231 nsEventStatus status
;
6233 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6234 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6235 event
.isMeta
= PR_FALSE
;
6236 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6238 event
.time
= ::GetMessageTime();
6239 event
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6241 PRBool endFeedback
= PR_TRUE
;
6243 PRInt32 scrollOverflowX
= 0;
6244 PRInt32 scrollOverflowY
= 0;
6246 if (mGesture
.PanDeltaToPixelScrollX(event
)) {
6247 DispatchEvent(&event
, status
);
6248 scrollOverflowX
= event
.scrollOverflow
;
6251 if (mGesture
.PanDeltaToPixelScrollY(event
)) {
6252 DispatchEvent(&event
, status
);
6253 scrollOverflowY
= event
.scrollOverflow
;
6256 if (mDisplayPanFeedback
) {
6257 mGesture
.UpdatePanFeedbackX(mWnd
, scrollOverflowX
, endFeedback
);
6258 mGesture
.UpdatePanFeedbackY(mWnd
, scrollOverflowY
, endFeedback
);
6259 mGesture
.PanFeedbackFinalize(mWnd
, endFeedback
);
6262 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
6267 // Other gestures translate into simple gesture events:
6268 nsSimpleGestureEvent
event(PR_TRUE
, 0, this, 0, 0.0);
6269 if ( !mGesture
.ProcessGestureMessage(mWnd
, wParam
, lParam
, event
) ) {
6270 return PR_FALSE
; // fall through to DefWndProc
6273 // Polish up and send off the new event
6274 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6275 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6276 event
.isMeta
= PR_FALSE
;
6277 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6279 event
.time
= ::GetMessageTime();
6280 event
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6282 nsEventStatus status
;
6283 DispatchEvent(&event
, status
);
6284 if (status
== nsEventStatus_eIgnore
) {
6285 return PR_FALSE
; // Ignored, fall through
6288 // Only close this if we process and return true.
6289 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
6291 return PR_TRUE
; // Handled
6293 #endif // !defined(WINCE)
6296 PRUint16
nsWindow::GetMouseInputSource()
6298 PRUint16 inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE
;
6299 LPARAM lParamExtraInfo
= ::GetMessageExtraInfo();
6300 if ((lParamExtraInfo
& TABLET_INK_SIGNATURE
) == TABLET_INK_CHECK
) {
6301 inputSource
= (lParamExtraInfo
& TABLET_INK_TOUCH
) ?
6302 PRUint16(nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
) : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN
;
6308 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6309 * within the message case block. If returning true result should be returned
6310 * immediately (no more processing).
6312 PRBool
nsWindow::OnMouseWheel(UINT msg
, WPARAM wParam
, LPARAM lParam
, PRBool
& getWheelInfo
, PRBool
& result
, LRESULT
*aRetValue
)
6314 // Handle both flavors of mouse wheel events.
6315 static int iDeltaPerLine
, iDeltaPerChar
;
6316 static ULONG ulScrollLines
, ulScrollChars
= 1;
6317 static int currentVDelta
, currentHDelta
;
6318 static HWND currentWindow
= 0;
6320 PRBool isVertical
= msg
== WM_MOUSEWHEEL
;
6322 // Get mouse wheel metrics (but only once).
6324 getWheelInfo
= PR_FALSE
;
6326 SystemParametersInfo (SPI_GETWHEELSCROLLLINES
, 0, &ulScrollLines
, 0);
6328 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6329 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6331 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6332 // the mouse driver wants a page scroll. The docs state that
6333 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6334 // since some mouse drivers use an arbitrary large number instead,
6335 // we have to handle that as well.
6338 if (ulScrollLines
) {
6339 if (ulScrollLines
<= WHEEL_DELTA
) {
6340 iDeltaPerLine
= WHEEL_DELTA
/ ulScrollLines
;
6342 ulScrollLines
= WHEEL_PAGESCROLL
;
6346 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS
, 0,
6347 &ulScrollChars
, 0)) {
6348 // Note that we may always fail to get the value before Win Vista.
6353 if (ulScrollChars
) {
6354 if (ulScrollChars
<= WHEEL_DELTA
) {
6355 iDeltaPerChar
= WHEEL_DELTA
/ ulScrollChars
;
6357 ulScrollChars
= WHEEL_PAGESCROLL
;
6362 if ((isVertical
&& ulScrollLines
!= WHEEL_PAGESCROLL
&& !iDeltaPerLine
) ||
6363 (!isVertical
&& ulScrollChars
!= WHEEL_PAGESCROLL
&& !iDeltaPerChar
))
6364 return PR_FALSE
; // break
6366 // The mousewheel event will be dispatched to the toplevel
6367 // window. We need to give it to the child window
6369 if (!HandleScrollingPlugins(msg
, wParam
, lParam
, result
, aRetValue
, quit
))
6370 return quit
; // return immediately if its not our window
6372 // We should cancel the surplus delta if the current window is not
6373 // same as previous.
6374 if (currentWindow
!= mWnd
) {
6377 currentWindow
= mWnd
;
6380 nsMouseScrollEvent
scrollEvent(PR_TRUE
, NS_MOUSE_SCROLL
, this);
6381 scrollEvent
.delta
= 0;
6383 scrollEvent
.scrollFlags
= nsMouseScrollEvent::kIsVertical
;
6384 if (ulScrollLines
== WHEEL_PAGESCROLL
) {
6385 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
6386 scrollEvent
.delta
= (((short) HIWORD (wParam
)) > 0) ? -1 : 1;
6388 currentVDelta
-= (short) HIWORD (wParam
);
6389 if (PR_ABS(currentVDelta
) >= iDeltaPerLine
) {
6390 scrollEvent
.delta
= currentVDelta
/ iDeltaPerLine
;
6391 currentVDelta
%= iDeltaPerLine
;
6395 scrollEvent
.scrollFlags
= nsMouseScrollEvent::kIsHorizontal
;
6396 if (ulScrollChars
== WHEEL_PAGESCROLL
) {
6397 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
6398 scrollEvent
.delta
= (((short) HIWORD (wParam
)) > 0) ? 1 : -1;
6400 currentHDelta
+= (short) HIWORD (wParam
);
6401 if (PR_ABS(currentHDelta
) >= iDeltaPerChar
) {
6402 scrollEvent
.delta
= currentHDelta
/ iDeltaPerChar
;
6403 currentHDelta
%= iDeltaPerChar
;
6408 if (!scrollEvent
.delta
) {
6409 // We store the wheel delta, and it will be used next wheel message, so,
6410 // we consume this message actually. We shouldn't call next wndproc.
6412 return PR_FALSE
; // break
6416 // The event may go to a plug-in which already dispatched this message.
6417 // Then, the event can cause deadlock. We should unlock the sender here.
6418 ::ReplyMessage(isVertical
? 0 : TRUE
);
6421 scrollEvent
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6422 scrollEvent
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6423 scrollEvent
.isMeta
= PR_FALSE
;
6424 scrollEvent
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6425 InitEvent(scrollEvent
);
6426 if (nsnull
!= mEventCallback
) {
6427 result
= DispatchWindowEvent(&scrollEvent
);
6429 // Note that we should return zero if we process WM_MOUSEWHEEL.
6430 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6433 *aRetValue
= isVertical
? 0 : TRUE
;
6435 return PR_FALSE
; // break;
6439 StringCaseInsensitiveEquals(const PRUnichar
* aChars1
, const PRUint32 aNumChars1
,
6440 const PRUnichar
* aChars2
, const PRUint32 aNumChars2
)
6442 if (aNumChars1
!= aNumChars2
)
6445 nsCaseInsensitiveStringComparator comp
;
6446 return comp(aChars1
, aChars2
, aNumChars1
) == 0;
6449 UINT
nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode
)
6452 switch (aNativeKeyCode
) {
6453 case VK_OEM_1
: return NS_VK_SEMICOLON
; // 0xBA, For the US standard keyboard, the ';:' key
6454 case VK_OEM_PLUS
: return NS_VK_ADD
; // 0xBB, For any country/region, the '+' key
6455 case VK_OEM_MINUS
: return NS_VK_SUBTRACT
; // 0xBD, For any country/region, the '-' key
6459 return aNativeKeyCode
;
6463 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6464 * WM_CHAR messages for processing. During testing we don't want to
6465 * mess with the real message queue. Instead we pass a
6466 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6467 * that as if it was in the message queue, and refrain from actually
6468 * looking at or touching the message queue.
6470 LRESULT
nsWindow::OnKeyDown(const MSG
&aMsg
,
6471 nsModifierKeyState
&aModKeyState
,
6472 PRBool
*aEventDispatched
,
6473 nsFakeCharMessage
* aFakeCharMessage
)
6475 UINT virtualKeyCode
= aMsg
.wParam
;
6478 gKbdLayout
.OnKeyDown (virtualKeyCode
);
6481 // Use only DOMKeyCode for XP processing.
6482 // Use aVirtualKeyCode for gKbdLayout and native processing.
6483 UINT DOMKeyCode
= nsIMM32Handler::IsComposingOn(this) ?
6484 virtualKeyCode
: MapFromNativeToDOM(virtualKeyCode
);
6487 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6491 DispatchKeyEvent(NS_KEY_DOWN
, 0, nsnull
, DOMKeyCode
, &aMsg
, aModKeyState
);
6492 if (aEventDispatched
)
6493 *aEventDispatched
= PR_TRUE
;
6495 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6496 // for almost all keys
6497 switch (DOMKeyCode
) {
6501 case NS_VK_CAPS_LOCK
:
6502 case NS_VK_NUM_LOCK
:
6503 case NS_VK_SCROLL_LOCK
: return noDefault
;
6506 PRUint32 extraFlags
= (noDefault
? NS_EVENT_FLAG_NO_DEFAULT
: 0);
6508 BOOL gotMsg
= aFakeCharMessage
||
6509 ::PeekMessageW(&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_NOREMOVE
| PM_NOYIELD
);
6510 // Enter and backspace are always handled here to avoid for example the
6511 // confusion between ctrl-enter and ctrl-J.
6512 if (DOMKeyCode
== NS_VK_RETURN
|| DOMKeyCode
== NS_VK_BACK
||
6513 ((aModKeyState
.mIsControlDown
|| aModKeyState
.mIsAltDown
)
6517 && !gKbdLayout
.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)))
6520 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6521 // They can be more than one because of:
6522 // * Dead-keys not pairing with base character
6523 // * Some keyboard layouts may map up to 4 characters to the single key
6524 PRBool anyCharMessagesRemoved
= PR_FALSE
;
6526 if (aFakeCharMessage
) {
6527 anyCharMessagesRemoved
= PR_TRUE
;
6529 while (gotMsg
&& (msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
))
6531 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6532 ("%s charCode=%d scanCode=%d\n", msg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
6533 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
6534 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST
, WM_KEYLAST
);
6535 anyCharMessagesRemoved
= PR_TRUE
;
6537 gotMsg
= ::PeekMessageW (&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_NOREMOVE
| PM_NOYIELD
);
6541 if (!anyCharMessagesRemoved
&& DOMKeyCode
== NS_VK_BACK
&&
6542 nsIMM32Handler::IsDoingKakuteiUndo(mWnd
)) {
6543 NS_ASSERTION(!aFakeCharMessage
,
6544 "We shouldn't be touching the real msg queue");
6545 RemoveMessageAndDispatchPluginEvent(WM_CHAR
, WM_CHAR
);
6549 (aFakeCharMessage
||
6550 msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
|| msg
.message
== WM_DEADCHAR
)) {
6551 if (aFakeCharMessage
)
6552 return OnCharRaw(aFakeCharMessage
->mCharCode
,
6553 aFakeCharMessage
->mScanCode
, aModKeyState
, extraFlags
);
6555 // If prevent default set for keydown, do same for keypress
6556 ::GetMessageW(&msg
, mWnd
, msg
.message
, msg
.message
);
6558 if (msg
.message
== WM_DEADCHAR
) {
6559 if (!PluginHasFocus())
6562 // We need to send the removed message to focused plug-in.
6563 DispatchPluginEvent(msg
);
6567 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6568 ("%s charCode=%d scanCode=%d\n",
6569 msg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
6570 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
6572 BOOL result
= OnChar(msg
, aModKeyState
, nsnull
, extraFlags
);
6573 // If a syschar keypress wasn't processed, Windows may want to
6574 // handle it to activate a native menu.
6575 if (!result
&& msg
.message
== WM_SYSCHAR
)
6576 ::DefWindowProcW(mWnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
6580 else if (!aModKeyState
.mIsControlDown
&& !aModKeyState
.mIsAltDown
&&
6581 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode
) ||
6582 KeyboardLayout::IsNumpadKey(virtualKeyCode
)))
6584 // If this is simple KeyDown event but next message is not WM_CHAR,
6585 // this event may not input text, so we should ignore this event.
6587 return PluginHasFocus() && noDefault
;
6590 if (gKbdLayout
.IsDeadKey ())
6591 return PluginHasFocus() && noDefault
;
6593 PRUint8 shiftStates
[5];
6594 PRUnichar uniChars
[5];
6595 PRUnichar shiftedChars
[5] = {0, 0, 0, 0, 0};
6596 PRUnichar unshiftedChars
[5] = {0, 0, 0, 0, 0};
6597 PRUnichar shiftedLatinChar
= 0;
6598 PRUnichar unshiftedLatinChar
= 0;
6599 PRUint32 numOfUniChars
= 0;
6600 PRUint32 numOfShiftedChars
= 0;
6601 PRUint32 numOfUnshiftedChars
= 0;
6602 PRUint32 numOfShiftStates
= 0;
6604 switch (virtualKeyCode
) {
6605 // keys to be sent as characters
6606 case VK_ADD
: uniChars
[0] = '+'; numOfUniChars
= 1; break;
6607 case VK_SUBTRACT
: uniChars
[0] = '-'; numOfUniChars
= 1; break;
6608 case VK_DIVIDE
: uniChars
[0] = '/'; numOfUniChars
= 1; break;
6609 case VK_MULTIPLY
: uniChars
[0] = '*'; numOfUniChars
= 1; break;
6620 uniChars
[0] = virtualKeyCode
- VK_NUMPAD0
+ '0';
6624 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)) {
6625 numOfUniChars
= numOfShiftStates
=
6626 gKbdLayout
.GetUniChars(uniChars
, shiftStates
,
6627 NS_ARRAY_LENGTH(uniChars
));
6630 if (aModKeyState
.mIsControlDown
^ aModKeyState
.mIsAltDown
) {
6631 PRUint8 capsLockState
= (::GetKeyState(VK_CAPITAL
) & 1) ? eCapsLock
: 0;
6632 numOfUnshiftedChars
=
6633 gKbdLayout
.GetUniCharsWithShiftState(virtualKeyCode
, capsLockState
,
6634 unshiftedChars
, NS_ARRAY_LENGTH(unshiftedChars
));
6636 gKbdLayout
.GetUniCharsWithShiftState(virtualKeyCode
,
6637 capsLockState
| eShift
,
6638 shiftedChars
, NS_ARRAY_LENGTH(shiftedChars
));
6640 // The current keyboard cannot input alphabets or numerics,
6641 // we should append them for Shortcut/Access keys.
6642 // E.g., for Cyrillic keyboard layout.
6643 if (NS_VK_A
<= DOMKeyCode
&& DOMKeyCode
<= NS_VK_Z
) {
6644 shiftedLatinChar
= unshiftedLatinChar
= DOMKeyCode
;
6646 shiftedLatinChar
+= 0x20;
6648 unshiftedLatinChar
+= 0x20;
6649 if (unshiftedLatinChar
== unshiftedChars
[0] &&
6650 shiftedLatinChar
== shiftedChars
[0]) {
6651 shiftedLatinChar
= unshiftedLatinChar
= 0;
6655 if (NS_VK_0
<= DOMKeyCode
&& DOMKeyCode
<= NS_VK_9
) {
6658 switch (virtualKeyCode
) {
6659 case VK_OEM_PLUS
: ch
= '+'; break;
6660 case VK_OEM_MINUS
: ch
= '-'; break;
6663 if (ch
&& unshiftedChars
[0] != ch
&& shiftedChars
[0] != ch
) {
6664 // Windows has assigned a virtual key code to the key even though
6665 // the character can't be produced with this key. That probably
6666 // means the character can't be produced with any key in the
6667 // current layout and so the assignment is based on a QWERTY
6668 // layout. Append this code so that users can access the shortcut.
6669 unshiftedLatinChar
= ch
;
6673 // If the charCode is not ASCII character, we should replace the
6674 // charCode with ASCII character only when Ctrl is pressed.
6675 // But don't replace the charCode when the charCode is not same as
6676 // unmodified characters. In such case, Ctrl is sometimes used for a
6677 // part of character inputting key combination like Shift.
6678 if (aModKeyState
.mIsControlDown
) {
6679 PRUint8 currentState
= eCtrl
;
6680 if (aModKeyState
.mIsShiftDown
)
6681 currentState
|= eShift
;
6684 aModKeyState
.mIsShiftDown
? shiftedLatinChar
: unshiftedLatinChar
;
6686 (numOfUniChars
== 0 ||
6687 StringCaseInsensitiveEquals(uniChars
, numOfUniChars
,
6688 aModKeyState
.mIsShiftDown
? shiftedChars
: unshiftedChars
,
6689 aModKeyState
.mIsShiftDown
? numOfShiftedChars
:
6690 numOfUnshiftedChars
))) {
6691 numOfUniChars
= numOfShiftStates
= 1;
6693 shiftStates
[0] = currentState
;
6699 if (numOfUniChars
> 0 || numOfShiftedChars
> 0 || numOfUnshiftedChars
> 0) {
6700 PRUint32 num
= PR_MAX(numOfUniChars
,
6701 PR_MAX(numOfShiftedChars
, numOfUnshiftedChars
));
6702 PRUint32 skipUniChars
= num
- numOfUniChars
;
6703 PRUint32 skipShiftedChars
= num
- numOfShiftedChars
;
6704 PRUint32 skipUnshiftedChars
= num
- numOfUnshiftedChars
;
6705 UINT keyCode
= numOfUniChars
== 0 ? DOMKeyCode
: 0;
6706 for (PRUint32 cnt
= 0; cnt
< num
; cnt
++) {
6707 PRUint16 uniChar
, shiftedChar
, unshiftedChar
;
6708 uniChar
= shiftedChar
= unshiftedChar
= 0;
6709 if (skipUniChars
<= cnt
) {
6710 if (cnt
- skipUniChars
< numOfShiftStates
) {
6711 // If key in combination with Alt and/or Ctrl produces a different
6712 // character than without them then do not report these flags
6713 // because it is separate keyboard layout shift state. If dead-key
6714 // and base character does not produce a valid composite character
6715 // then both produced dead-key character and following base
6716 // character may have different modifier flags, too.
6717 aModKeyState
.mIsShiftDown
=
6718 (shiftStates
[cnt
- skipUniChars
] & eShift
) != 0;
6719 aModKeyState
.mIsControlDown
=
6720 (shiftStates
[cnt
- skipUniChars
] & eCtrl
) != 0;
6721 aModKeyState
.mIsAltDown
=
6722 (shiftStates
[cnt
- skipUniChars
] & eAlt
) != 0;
6724 uniChar
= uniChars
[cnt
- skipUniChars
];
6726 if (skipShiftedChars
<= cnt
)
6727 shiftedChar
= shiftedChars
[cnt
- skipShiftedChars
];
6728 if (skipUnshiftedChars
<= cnt
)
6729 unshiftedChar
= unshiftedChars
[cnt
- skipUnshiftedChars
];
6730 nsAutoTArray
<nsAlternativeCharCode
, 5> altArray
;
6732 if (shiftedChar
|| unshiftedChar
) {
6733 nsAlternativeCharCode
chars(unshiftedChar
, shiftedChar
);
6734 altArray
.AppendElement(chars
);
6736 if (cnt
== num
- 1 && (unshiftedLatinChar
|| shiftedLatinChar
)) {
6737 nsAlternativeCharCode
chars(unshiftedLatinChar
, shiftedLatinChar
);
6738 altArray
.AppendElement(chars
);
6741 DispatchKeyEvent(NS_KEY_PRESS
, uniChar
, &altArray
,
6742 keyCode
, nsnull
, aModKeyState
, extraFlags
);
6745 DispatchKeyEvent(NS_KEY_PRESS
, 0, nsnull
, DOMKeyCode
, nsnull
, aModKeyState
,
6750 UINT unichar
= ::MapVirtualKey(virtualKeyCode
, MAPVK_VK_TO_CHAR
);
6751 // Check for dead characters or no mapping
6752 if (unichar
& 0x80) {
6755 DispatchKeyEvent(NS_KEY_PRESS
, unichar
, nsnull
, DOMKeyCode
, nsnull
, aModKeyState
,
6764 LRESULT
nsWindow::OnKeyUp(const MSG
&aMsg
,
6765 nsModifierKeyState
&aModKeyState
,
6766 PRBool
*aEventDispatched
)
6768 UINT virtualKeyCode
= aMsg
.wParam
;
6770 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6771 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode
));
6773 if (!nsIMM32Handler::IsComposingOn(this)) {
6774 virtualKeyCode
= MapFromNativeToDOM(virtualKeyCode
);
6777 if (aEventDispatched
)
6778 *aEventDispatched
= PR_TRUE
;
6779 return DispatchKeyEvent(NS_KEY_UP
, 0, nsnull
, virtualKeyCode
, &aMsg
,
6784 LRESULT
nsWindow::OnChar(const MSG
&aMsg
, nsModifierKeyState
&aModKeyState
,
6785 PRBool
*aEventDispatched
, PRUint32 aFlags
)
6787 return OnCharRaw(aMsg
.wParam
, HIWORD(aMsg
.lParam
) & 0xFF, aModKeyState
,
6788 aFlags
, &aMsg
, aEventDispatched
);
6792 LRESULT
nsWindow::OnCharRaw(UINT charCode
, UINT aScanCode
,
6793 nsModifierKeyState
&aModKeyState
, PRUint32 aFlags
,
6794 const MSG
*aMsg
, PRBool
*aEventDispatched
)
6796 // ignore [shift+]alt+space so the OS can handle it
6797 if (aModKeyState
.mIsAltDown
&& !aModKeyState
.mIsControlDown
&&
6798 IS_VK_DOWN(NS_VK_SPACE
)) {
6802 // Ignore Ctrl+Enter (bug 318235)
6803 if (aModKeyState
.mIsControlDown
&& charCode
== 0xA) {
6807 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
6808 PRBool saveIsAltDown
= aModKeyState
.mIsAltDown
;
6809 PRBool saveIsControlDown
= aModKeyState
.mIsControlDown
;
6810 if (aModKeyState
.mIsAltDown
&& aModKeyState
.mIsControlDown
)
6811 aModKeyState
.mIsAltDown
= aModKeyState
.mIsControlDown
= PR_FALSE
;
6815 if (nsIMM32Handler::IsComposingOn(this)) {
6819 if (aModKeyState
.mIsControlDown
&& charCode
<= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
6820 // need to account for shift here. bug 16486
6821 if (aModKeyState
.mIsShiftDown
)
6822 uniChar
= charCode
- 1 + 'A';
6824 uniChar
= charCode
- 1 + 'a';
6827 else if (aModKeyState
.mIsControlDown
&& charCode
<= 0x1F) {
6828 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
6829 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
6830 // for some reason the keypress handler need to have the uniChar code set
6831 // with the addition of a upper case A not the lower case.
6832 uniChar
= charCode
- 1 + 'A';
6834 } else { // 0x20 - SPACE, 0x3D - EQUALS
6835 if (charCode
< 0x20 || (charCode
== 0x3D && aModKeyState
.mIsControlDown
)) {
6843 // Keep the characters unshifted for shortcuts and accesskeys and make sure
6844 // that numbers are always passed as such (among others: bugs 50255 and 351310)
6845 if (uniChar
&& (aModKeyState
.mIsControlDown
|| aModKeyState
.mIsAltDown
)) {
6846 UINT virtualKeyCode
= ::MapVirtualKeyEx(aScanCode
, MAPVK_VSC_TO_VK
,
6847 gKbdLayout
.GetLayout());
6848 UINT unshiftedCharCode
=
6849 virtualKeyCode
>= '0' && virtualKeyCode
<= '9' ? virtualKeyCode
:
6850 aModKeyState
.mIsShiftDown
? ::MapVirtualKeyEx(virtualKeyCode
,
6852 gKbdLayout
.GetLayout()) : 0;
6853 // ignore diacritics (top bit set) and key mapping errors (char code 0)
6854 if ((INT
)unshiftedCharCode
> 0)
6855 uniChar
= unshiftedCharCode
;
6858 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
6859 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
6861 if (!aModKeyState
.mIsShiftDown
&& (saveIsAltDown
|| saveIsControlDown
)) {
6862 uniChar
= towlower(uniChar
);
6865 PRBool result
= DispatchKeyEvent(NS_KEY_PRESS
, uniChar
, nsnull
,
6866 charCode
, aMsg
, aModKeyState
, aFlags
);
6867 if (aEventDispatched
)
6868 *aEventDispatched
= PR_TRUE
;
6869 aModKeyState
.mIsAltDown
= saveIsAltDown
;
6870 aModKeyState
.mIsControlDown
= saveIsControlDown
;
6875 nsWindow::SetupKeyModifiersSequence(nsTArray
<KeyPair
>* aArray
, PRUint32 aModifiers
)
6877 for (PRUint32 i
= 0; i
< NS_ARRAY_LENGTH(sModifierKeyMap
); ++i
) {
6878 const PRUint32
* map
= sModifierKeyMap
[i
];
6879 if (aModifiers
& map
[0]) {
6880 aArray
->AppendElement(KeyPair(map
[1], map
[2]));
6886 nsWindow::ConfigureChildren(const nsTArray
<Configuration
>& aConfigurations
)
6888 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
6889 // here, if that helps in some situations. So far I haven't seen a
6891 for (PRUint32 i
= 0; i
< aConfigurations
.Length(); ++i
) {
6892 const Configuration
& configuration
= aConfigurations
[i
];
6893 nsWindow
* w
= static_cast<nsWindow
*>(configuration
.mChild
);
6894 NS_ASSERTION(w
->GetParent() == this,
6895 "Configured widget is not a child");
6897 // MSDN says we should do on WinCE this before moving or resizing the window
6898 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
6899 // We put the region back just below, anyway.
6900 ::SetWindowRgn(w
->mWnd
, NULL
, TRUE
);
6902 nsresult rv
= w
->SetWindowClipRegion(configuration
.mClipRegion
, PR_TRUE
);
6903 NS_ENSURE_SUCCESS(rv
, rv
);
6905 w
->GetBounds(bounds
);
6906 if (bounds
.Size() != configuration
.mBounds
.Size()) {
6907 w
->Resize(configuration
.mBounds
.x
, configuration
.mBounds
.y
,
6908 configuration
.mBounds
.width
, configuration
.mBounds
.height
,
6910 } else if (bounds
.TopLeft() != configuration
.mBounds
.TopLeft()) {
6911 w
->Move(configuration
.mBounds
.x
, configuration
.mBounds
.y
);
6914 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
6915 gfxWindowsPlatform::RENDER_DIRECT2D
||
6916 GetLayerManager()->GetBackendType() != LayerManager::LAYERS_BASIC
) {
6917 // XXX - Workaround for Bug 587508. This will invalidate the part of the
6918 // plugin window that might be touched by moving content somehow. The
6919 // underlying problem should be found and fixed!
6921 r
.Sub(bounds
, configuration
.mBounds
);
6924 w
->Invalidate(r
.GetBounds(), PR_FALSE
);
6927 rv
= w
->SetWindowClipRegion(configuration
.mClipRegion
, PR_FALSE
);
6928 NS_ENSURE_SUCCESS(rv
, rv
);
6934 CreateHRGNFromArray(const nsTArray
<nsIntRect
>& aRects
)
6936 PRInt32 size
= sizeof(RGNDATAHEADER
) + sizeof(RECT
)*aRects
.Length();
6937 nsAutoTArray
<PRUint8
,100> buf
;
6938 if (!buf
.SetLength(size
))
6940 RGNDATA
* data
= reinterpret_cast<RGNDATA
*>(buf
.Elements());
6941 RECT
* rects
= reinterpret_cast<RECT
*>(data
->Buffer
);
6942 data
->rdh
.dwSize
= sizeof(data
->rdh
);
6943 data
->rdh
.iType
= RDH_RECTANGLES
;
6944 data
->rdh
.nCount
= aRects
.Length();
6946 for (PRUint32 i
= 0; i
< aRects
.Length(); ++i
) {
6947 const nsIntRect
& r
= aRects
[i
];
6948 bounds
.UnionRect(bounds
, r
);
6949 ::SetRect(&rects
[i
], r
.x
, r
.y
, r
.XMost(), r
.YMost());
6951 ::SetRect(&data
->rdh
.rcBound
, bounds
.x
, bounds
.y
, bounds
.XMost(), bounds
.YMost());
6952 return ::ExtCreateRegion(NULL
, buf
.Length(), data
);
6956 nsWindow::SetWindowClipRegion(const nsTArray
<nsIntRect
>& aRects
,
6957 PRBool aIntersectWithExisting
)
6959 if (!aIntersectWithExisting
) {
6960 if (!StoreWindowClipRegion(aRects
))
6963 // In this case still early return if nothing changed.
6964 if (mClipRects
&& mClipRectCount
== aRects
.Length() &&
6967 sizeof(nsIntRect
)*mClipRectCount
) == 0) {
6972 HRGN dest
= CreateHRGNFromArray(aRects
);
6974 return NS_ERROR_OUT_OF_MEMORY
;
6976 if (aIntersectWithExisting
) {
6977 HRGN current
= ::CreateRectRgn(0, 0, 0, 0);
6979 if (::GetWindowRgn(mWnd
, current
) != 0 /*ERROR*/) {
6980 ::CombineRgn(dest
, dest
, current
, RGN_AND
);
6982 ::DeleteObject(current
);
6986 if (!::SetWindowRgn(mWnd
, dest
, TRUE
)) {
6987 ::DeleteObject(dest
);
6988 return NS_ERROR_FAILURE
;
6993 // WM_DESTROY event handler
6994 void nsWindow::OnDestroy()
6996 mOnDestroyCalled
= PR_TRUE
;
6998 // Make sure we don't get destroyed in the process of tearing down.
6999 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
7001 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
7003 DispatchStandardEvent(NS_DESTROY
);
7005 // Prevent the widget from sending additional events.
7006 mEventCallback
= nsnull
;
7008 // Free our subclass and clear |this| stored in the window props. We will no longer
7009 // receive events from Windows after this point.
7010 SubclassWindow(FALSE
);
7012 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
7013 // cleared. (It's used in tracking windows for mouse events.)
7014 if (sCurrentWindow
== this)
7015 sCurrentWindow
= nsnull
;
7017 // Disconnects us from our parent, will call our GetParent().
7018 nsBaseWidget::Destroy();
7020 // Release references to children, device context, toolkit, and app shell.
7021 nsBaseWidget::OnDestroy();
7023 // Clear our native parent handle.
7024 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
7025 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
7026 //SetParent(nsnull);
7029 // We have to destroy the native drag target before we null out our window pointer.
7030 EnableDragDrop(PR_FALSE
);
7032 // If we're going away and for some reason we're still the rollup widget, rollup and
7033 // turn off capture.
7034 if ( this == sRollupWidget
) {
7035 if ( sRollupListener
)
7036 sRollupListener
->Rollup(nsnull
, nsnull
);
7037 CaptureRollupEvents(nsnull
, nsnull
, PR_FALSE
, PR_TRUE
);
7040 // If IME is disabled, restore it.
7042 mOldIMC
= ::ImmAssociateContext(mWnd
, mOldIMC
);
7043 NS_ASSERTION(!mOldIMC
, "Another IMC was associated");
7046 // Turn off mouse trails if enabled.
7047 MouseTrailer
* mtrailer
= nsToolkit::gMouseTrailer
;
7049 if (mtrailer
->GetMouseTrailerWindow() == mWnd
)
7050 mtrailer
->DestroyTimer();
7052 if (mtrailer
->GetCaptureWindow() == mWnd
)
7053 mtrailer
->SetCaptureWindow(nsnull
);
7056 // Free GDI window class objects
7058 VERIFY(::DeleteObject(mBrush
));
7062 // Free app icon resources.
7064 icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_BIG
, (LPARAM
) 0);
7066 ::DestroyIcon(icon
);
7068 icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_SMALL
, (LPARAM
) 0);
7070 ::DestroyIcon(icon
);
7072 // Destroy any custom cursor resources.
7074 SetCursor(eCursor_standard
);
7077 // Reset transparency
7078 if (eTransparencyTransparent
== mTransparencyMode
)
7079 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque
);
7082 #if defined(WINCE_HAVE_SOFTKB)
7083 // Revert the changes made for the software keyboard settings
7084 nsWindowCE::ResetSoftKB(mWnd
);
7088 // Finalize panning feedback to possibly restore window displacement
7089 mGesture
.PanFeedbackFinalize(mWnd
, PR_TRUE
);
7092 // Clear the main HWND.
7097 PRBool
nsWindow::OnMove(PRInt32 aX
, PRInt32 aY
)
7102 nsGUIEvent
event(PR_TRUE
, NS_MOVE
, this);
7104 event
.refPoint
.x
= aX
;
7105 event
.refPoint
.y
= aY
;
7107 return DispatchWindowEvent(&event
);
7110 // Send a resize message to the listener
7111 PRBool
nsWindow::OnResize(nsIntRect
&aWindowRect
)
7113 #ifdef CAIRO_HAS_D2D_SURFACE
7114 if (mD2DWindowSurface
) {
7115 mD2DWindowSurface
= NULL
;
7116 Invalidate(PR_FALSE
);
7120 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7121 UpdateCaptionButtonsClippingRect();
7124 // call the event callback
7125 if (mEventCallback
) {
7126 nsSizeEvent
event(PR_TRUE
, NS_SIZE
, this);
7128 event
.windowSize
= &aWindowRect
;
7130 if (::GetWindowRect(mWnd
, &r
)) {
7131 event
.mWinWidth
= PRInt32(r
.right
- r
.left
);
7132 event
.mWinHeight
= PRInt32(r
.bottom
- r
.top
);
7134 event
.mWinWidth
= 0;
7135 event
.mWinHeight
= 0;
7139 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7140 aWindowRect
.x
, aWindowRect
.y
, aWindowRect
.width
, aWindowRect
.height
,
7141 event
.mWinWidth
, event
.mWinHeight
);
7144 return DispatchWindowEvent(&event
);
7150 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7151 PRBool
nsWindow::OnHotKey(WPARAM wParam
, LPARAM lParam
)
7155 #endif // !defined(WINCE)
7157 void nsWindow::OnSettingsChange(WPARAM wParam
, LPARAM lParam
)
7159 if (mWindowType
== eWindowType_dialog
||
7160 mWindowType
== eWindowType_toplevel
)
7161 nsWindowGfx::OnSettingsChangeGfx(wParam
);
7164 static PRBool
IsOurProcessWindow(HWND aHWND
)
7166 DWORD processId
= 0;
7167 ::GetWindowThreadProcessId(aHWND
, &processId
);
7168 return processId
== ::GetCurrentProcessId();
7171 static HWND
FindOurProcessWindow(HWND aHWND
)
7173 for (HWND wnd
= ::GetParent(aHWND
); wnd
; wnd
= ::GetParent(wnd
)) {
7174 if (IsOurProcessWindow(wnd
)) {
7181 // Scrolling helper function for handling plugins.
7182 // Return value indicates whether the calling function should handle this
7183 // aHandled indicates whether this was handled at all
7184 // aQuitProcessing tells whether or not to continue processing the message
7185 PRBool
nsWindow::HandleScrollingPlugins(UINT aMsg
, WPARAM aWParam
,
7186 LPARAM aLParam
, PRBool
& aHandled
,
7188 PRBool
& aQuitProcessing
)
7190 // The scroll event will be dispatched to the toplevel
7191 // window. We need to give it to the child window
7192 aQuitProcessing
= PR_FALSE
; // default is to not stop processing
7194 DWORD dwPoints
= ::GetMessagePos();
7195 point
.x
= GET_X_LPARAM(dwPoints
);
7196 point
.y
= GET_Y_LPARAM(dwPoints
);
7198 static PRBool sIsProcessing
= PR_FALSE
;
7199 if (sIsProcessing
) {
7200 return PR_TRUE
; // the caller should handle this.
7203 static PRBool sMayBeUsingLogitechMouse
= PR_FALSE
;
7204 if (aMsg
== WM_MOUSEHWHEEL
) {
7205 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7206 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7207 // message at first time, this time, ::GetMessagePos works fine.
7208 // Then, we will return 0 (0 means we process it) to the message. Then, the
7209 // driver will POST the same messages continuously during the wheel tilted.
7210 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7211 // cursor isn't 0,0. Therefore, we cannot trust the result of
7212 // ::GetMessagePos API if the sender is the driver.
7213 if (!sMayBeUsingLogitechMouse
&& aLParam
== 0 && (DWORD
)aLParam
!= dwPoints
&&
7214 ::InSendMessage()) {
7215 sMayBeUsingLogitechMouse
= PR_TRUE
;
7216 } else if (sMayBeUsingLogitechMouse
&& aLParam
!= 0 && ::InSendMessage()) {
7217 // The user has changed the mouse from Logitech's to another one (e.g.,
7218 // the user has changed to the touchpad of the notebook.
7219 sMayBeUsingLogitechMouse
= PR_FALSE
;
7221 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7222 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7224 if (sMayBeUsingLogitechMouse
&& aLParam
== 0 && dwPoints
== 0) {
7225 ::GetCursorPos(&point
);
7229 HWND destWnd
= ::WindowFromPoint(point
);
7230 // Since we receive scroll events for as long as
7231 // we are focused, it's entirely possible that there
7232 // is another app's window or no window under the
7236 // No window is under the pointer
7237 return PR_FALSE
; // break, but continue processing
7240 nsWindow
* destWindow
;
7242 // We don't handle the message if the found window belongs to another
7243 // process's top window. If it belongs window, that is a plug-in's window.
7244 // Then, we need to send the message to the plug-in window.
7245 if (!IsOurProcessWindow(destWnd
)) {
7246 HWND ourPluginWnd
= FindOurProcessWindow(destWnd
);
7247 if (!ourPluginWnd
) {
7248 // Somebody elses window
7249 return PR_FALSE
; // break, but continue processing
7251 destWindow
= GetNSWindowPtr(ourPluginWnd
);
7253 destWindow
= GetNSWindowPtr(destWnd
);
7256 if (destWindow
== this && mWindowType
== eWindowType_plugin
) {
7257 // If this is plug-in window, the message came from the plug-in window.
7258 // Then, the message should be processed on the parent window.
7259 destWindow
= static_cast<nsWindow
*>(GetParent());
7260 NS_ENSURE_TRUE(destWindow
, PR_FALSE
); // break, but continue processing
7261 destWnd
= destWindow
->mWnd
;
7262 NS_ENSURE_TRUE(destWnd
, PR_FALSE
); // break, but continue processing
7265 if (!destWindow
|| destWindow
->mWindowType
== eWindowType_plugin
) {
7266 // Some other app, or a plugin window.
7267 // Windows directs scrolling messages to the focused window.
7268 // However, Mozilla does not like plugins having focus, so a
7269 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7270 // Therefore, plugins etc _should_ get first grab at the
7271 // message, but this focus vaguary means the plugin misses
7272 // out. If the window is a child of ours, forward it on.
7273 // Determine if a child by walking the parent list until
7274 // we find a parent matching our wndproc.
7275 HWND parentWnd
= ::GetParent(destWnd
);
7277 nsWindow
* parentWindow
= GetNSWindowPtr(parentWnd
);
7279 // We have a child window - quite possibly a plugin window.
7280 // However, not all plugins are created equal - some will handle this
7281 // message themselves, some will forward directly back to us, while
7282 // others will call DefWndProc, which itself still forwards back to us.
7283 // So if we have sent it once, we need to handle it ourself.
7286 // XXX The message shouldn't come from the plugin window at here.
7287 // But the message might come from it due to some bugs. If it happens,
7288 // SendMessage causes deadlock. For safety, we should unlock the
7290 ::ReplyMessage(aMsg
== WM_MOUSEHWHEEL
? TRUE
: 0);
7293 // First time we have seen this message.
7294 // Call the child - either it will consume it, or
7295 // it will wind it's way back to us,triggering the destWnd case above
7296 // either way,when the call returns,we are all done with the message,
7297 sIsProcessing
= PR_TRUE
;
7298 ::SendMessageW(destWnd
, aMsg
, aWParam
, aLParam
);
7299 sIsProcessing
= PR_FALSE
;
7301 aQuitProcessing
= PR_TRUE
;
7302 return PR_FALSE
; // break, and stop processing
7304 parentWnd
= ::GetParent(parentWnd
);
7305 } // while parentWnd
7307 if (destWnd
== nsnull
)
7309 if (destWnd
!= mWnd
) {
7311 sIsProcessing
= PR_TRUE
;
7312 aHandled
= destWindow
->ProcessMessage(aMsg
, aWParam
, aLParam
, aRetValue
);
7313 sIsProcessing
= PR_FALSE
;
7314 aQuitProcessing
= PR_TRUE
;
7315 return PR_FALSE
; // break, and stop processing
7319 printf("WARNING: couldn't get child window for SCROLL event\n");
7322 return PR_TRUE
; // caller should handle this
7325 PRBool
nsWindow::OnScroll(UINT aMsg
, WPARAM aWParam
, LPARAM aLParam
)
7327 static PRInt8 sMouseWheelEmulation
= -1;
7328 if (sMouseWheelEmulation
< 0) {
7329 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
7330 NS_ENSURE_TRUE(prefs
, PR_FALSE
);
7331 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
7332 prefs
->GetBranch(0, getter_AddRefs(prefBranch
));
7333 NS_ENSURE_TRUE(prefBranch
, PR_FALSE
);
7336 prefBranch
->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate
);
7337 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7338 sMouseWheelEmulation
= PRInt8(emulate
);
7341 if (aLParam
|| sMouseWheelEmulation
) {
7342 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7343 // Treat as a mousewheel message and scroll appropriately
7344 PRBool quit
, result
;
7347 if (!HandleScrollingPlugins(aMsg
, aWParam
, aLParam
, result
, &retVal
, quit
))
7348 return quit
; // Return if it's not our message or has been dispatched
7350 nsMouseScrollEvent
scrollevent(PR_TRUE
, NS_MOUSE_SCROLL
, this);
7351 scrollevent
.scrollFlags
= (aMsg
== WM_VSCROLL
)
7352 ? nsMouseScrollEvent::kIsVertical
7353 : nsMouseScrollEvent::kIsHorizontal
;
7354 switch (LOWORD(aWParam
))
7357 scrollevent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
7359 scrollevent
.delta
= 1;
7362 scrollevent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
7364 scrollevent
.delta
= -1;
7370 // The event may go to a plug-in which already dispatched this message.
7371 // Then, the event can cause deadlock. We should unlock the sender here.
7374 scrollevent
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
7375 scrollevent
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
7376 scrollevent
.isMeta
= PR_FALSE
;
7377 scrollevent
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
7378 InitEvent(scrollevent
);
7379 if (nsnull
!= mEventCallback
)
7381 DispatchWindowEvent(&scrollevent
);
7386 // Scroll message generated by external application
7387 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_SCROLL
, this);
7389 command
.mScroll
.mIsHorizontal
= (aMsg
== WM_HSCROLL
);
7391 switch (LOWORD(aWParam
))
7393 case SB_LINEUP
: // SB_LINELEFT
7394 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Line
;
7395 command
.mScroll
.mAmount
= -1;
7397 case SB_LINEDOWN
: // SB_LINERIGHT
7398 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Line
;
7399 command
.mScroll
.mAmount
= 1;
7401 case SB_PAGEUP
: // SB_PAGELEFT
7402 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Page
;
7403 command
.mScroll
.mAmount
= -1;
7405 case SB_PAGEDOWN
: // SB_PAGERIGHT
7406 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Page
;
7407 command
.mScroll
.mAmount
= 1;
7409 case SB_TOP
: // SB_LEFT
7410 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Whole
;
7411 command
.mScroll
.mAmount
= -1;
7413 case SB_BOTTOM
: // SB_RIGHT
7414 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Whole
;
7415 command
.mScroll
.mAmount
= 1;
7420 DispatchWindowEvent(&command
);
7424 // Can be overriden. Controls auto-erase of background.
7425 PRBool
nsWindow::AutoErase(HDC dc
)
7430 /**************************************************************
7431 **************************************************************
7433 ** BLOCK: IME management and accessibility
7435 ** Handles managing IME input and accessibility.
7437 **************************************************************
7438 **************************************************************/
7440 NS_IMETHODIMP
nsWindow::ResetInputState()
7442 #ifdef DEBUG_KBSTATE
7443 printf("ResetInputState\n");
7446 #ifdef NS_ENABLE_TSF
7447 nsTextStore::CommitComposition(PR_FALSE
);
7448 #endif //NS_ENABLE_TSF
7450 nsIMM32Handler::CommitComposition(this);
7454 NS_IMETHODIMP
nsWindow::SetIMEOpenState(PRBool aState
)
7456 #ifdef DEBUG_KBSTATE
7457 printf("SetIMEOpenState %s\n", (aState
? "Open" : "Close"));
7460 #ifdef NS_ENABLE_TSF
7461 nsTextStore::SetIMEOpenState(aState
);
7462 #endif //NS_ENABLE_TSF
7464 nsIMEContext
IMEContext(mWnd
);
7465 if (IMEContext
.IsValid()) {
7466 ::ImmSetOpenStatus(IMEContext
.get(), aState
? TRUE
: FALSE
);
7471 NS_IMETHODIMP
nsWindow::GetIMEOpenState(PRBool
* aState
)
7473 nsIMEContext
IMEContext(mWnd
);
7474 if (IMEContext
.IsValid()) {
7475 BOOL isOpen
= ::ImmGetOpenStatus(IMEContext
.get());
7476 *aState
= isOpen
? PR_TRUE
: PR_FALSE
;
7480 #ifdef NS_ENABLE_TSF
7481 *aState
|= nsTextStore::GetIMEOpenState();
7482 #endif //NS_ENABLE_TSF
7487 NS_IMETHODIMP
nsWindow::SetIMEEnabled(PRUint32 aState
)
7489 #ifdef NS_ENABLE_TSF
7490 nsTextStore::SetIMEEnabled(aState
);
7491 #endif //NS_ENABLE_TSF
7492 #ifdef DEBUG_KBSTATE
7493 printf("SetIMEEnabled: %s\n", (aState
== nsIWidget::IME_STATUS_ENABLED
||
7494 aState
== nsIWidget::IME_STATUS_PLUGIN
)?
7495 "Enabled": "Disabled");
7497 if (nsIMM32Handler::IsComposing()) {
7500 mIMEEnabled
= aState
;
7501 PRBool enable
= (aState
== nsIWidget::IME_STATUS_ENABLED
||
7502 aState
== nsIWidget::IME_STATUS_PLUGIN
);
7504 #if defined(WINCE_HAVE_SOFTKB)
7505 sSoftKeyboardState
= (aState
!= nsIWidget::IME_STATUS_DISABLED
);
7506 nsWindowCE::ToggleSoftKB(mWnd
, sSoftKeyboardState
);
7509 if (!enable
!= !mOldIMC
)
7511 mOldIMC
= ::ImmAssociateContext(mWnd
, enable
? mOldIMC
: NULL
);
7512 NS_ASSERTION(!enable
|| !mOldIMC
, "Another IMC was associated");
7517 NS_IMETHODIMP
nsWindow::GetIMEEnabled(PRUint32
* aState
)
7519 #ifdef DEBUG_KBSTATE
7520 printf("GetIMEEnabled: %s\n", mIMEEnabled
? "Enabled": "Disabled");
7522 *aState
= mIMEEnabled
;
7526 NS_IMETHODIMP
nsWindow::CancelIMEComposition()
7528 #ifdef DEBUG_KBSTATE
7529 printf("CancelIMEComposition\n");
7532 #ifdef NS_ENABLE_TSF
7533 nsTextStore::CommitComposition(PR_TRUE
);
7534 #endif //NS_ENABLE_TSF
7536 nsIMM32Handler::CancelComposition(this);
7541 nsWindow::GetToggledKeyState(PRUint32 aKeyCode
, PRBool
* aLEDState
)
7543 #ifdef DEBUG_KBSTATE
7544 printf("GetToggledKeyState\n");
7546 NS_ENSURE_ARG_POINTER(aLEDState
);
7547 *aLEDState
= (::GetKeyState(aKeyCode
) & 1) != 0;
7551 #ifdef NS_ENABLE_TSF
7553 nsWindow::OnIMEFocusChange(PRBool aFocus
)
7555 nsresult rv
= nsTextStore::OnFocusChange(aFocus
, this, mIMEEnabled
);
7556 if (rv
== NS_ERROR_NOT_AVAILABLE
)
7557 rv
= NS_ERROR_NOT_IMPLEMENTED
; // TSF is not enabled, maybe.
7562 nsWindow::OnIMETextChange(PRUint32 aStart
,
7566 return nsTextStore::OnTextChange(aStart
, aOldEnd
, aNewEnd
);
7570 nsWindow::OnIMESelectionChange(void)
7572 return nsTextStore::OnSelectionChange();
7574 #endif //NS_ENABLE_TSF
7576 #ifdef ACCESSIBILITY
7578 #ifdef DEBUG_WMGETOBJECT
7579 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
7580 nsAccessible* acc = aWnd ? \
7581 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
7582 printf(" acc: %p", acc); \
7584 nsAutoString name; \
7585 acc->GetName(name); \
7586 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
7587 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
7588 void *hwnd = nsnull; \
7589 doc->GetWindowHandle(&hwnd); \
7590 printf(", acc hwnd: %d", hwnd); \
7593 #define NS_LOG_WMGETOBJECT_THISWND \
7595 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
7596 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7597 mWnd, ::GetParent(mWnd), this); \
7598 NS_LOG_WMGETOBJECT_WNDACC(this) \
7602 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
7604 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
7605 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7606 aHwnd, ::GetParent(aHwnd), wnd); \
7607 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
7611 #define NS_LOG_WMGETOBJECT_THISWND
7612 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
7613 #endif // DEBUG_WMGETOBJECT
7616 nsWindow::GetRootAccessible()
7618 // We want the ability to forcibly disable a11y on windows, because
7619 // some non-a11y-related components attempt to bring it up. See bug
7620 // 538530 for details; we have a pref here that allows it to be disabled
7621 // for performance and testing resons.
7623 // This pref is checked only once, and the browser needs a restart to
7624 // pick up any changes.
7625 static int accForceDisable
= -1;
7627 if (accForceDisable
== -1) {
7628 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
7629 PRBool b
= PR_FALSE
;
7630 nsresult rv
= prefs
->GetBoolPref("accessibility.win32.force_disabled", &b
);
7631 if (NS_SUCCEEDED(rv
) && b
) {
7632 accForceDisable
= 1;
7634 accForceDisable
= 0;
7638 // If the pref was true, return null here, disabling a11y.
7639 if (accForceDisable
)
7642 nsWindow::sIsAccessibilityOn
= TRUE
;
7644 if (mInDtor
|| mOnDestroyCalled
|| mWindowType
== eWindowType_invisible
) {
7648 NS_LOG_WMGETOBJECT_THISWND
7649 NS_LOG_WMGETOBJECT_WND("This Window", mWnd
);
7651 return DispatchAccessibleEvent(NS_GETACCESSIBLE
);
7654 STDMETHODIMP_(LRESULT
)
7655 nsWindow::LresultFromObject(REFIID riid
, WPARAM wParam
, LPUNKNOWN pAcc
)
7657 // open the dll dynamically
7659 sAccLib
=::LoadLibraryW(L
"OLEACC.DLL");
7662 if (!sLresultFromObject
)
7663 sLresultFromObject
= (LPFNLRESULTFROMOBJECT
)GetProcAddress(sAccLib
,"LresultFromObject");
7665 if (sLresultFromObject
)
7666 return sLresultFromObject(riid
,wParam
,pAcc
);
7673 /**************************************************************
7674 **************************************************************
7676 ** BLOCK: Transparency
7678 ** Window transparency helpers.
7680 **************************************************************
7681 **************************************************************/
7685 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth
, PRInt32 aNewHeight
, PRBool force
)
7687 if (!force
&& aNewWidth
== mBounds
.width
&& aNewHeight
== mBounds
.height
)
7690 #ifdef CAIRO_HAS_D2D_SURFACE
7691 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7692 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7693 nsRefPtr
<gfxD2DSurface
> newSurface
=
7694 new gfxD2DSurface(gfxIntSize(aNewWidth
, aNewHeight
), gfxASurface::ImageFormatARGB32
);
7695 mTransparentSurface
= newSurface
;
7700 nsRefPtr
<gfxWindowsSurface
> newSurface
=
7701 new gfxWindowsSurface(gfxIntSize(aNewWidth
, aNewHeight
), gfxASurface::ImageFormatARGB32
);
7702 mTransparentSurface
= newSurface
;
7703 mMemoryDC
= newSurface
->GetDC();
7707 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode
)
7711 if (aMode
== mTransparencyMode
)
7714 // stop on dialogs and popups!
7715 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
7716 nsWindow
* parent
= GetNSWindowPtr(hWnd
);
7720 NS_WARNING("Trying to use transparent chrome in an embedded context");
7724 if (parent
!= this) {
7725 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
7728 if (aMode
== eTransparencyTransparent
) {
7729 // If we're switching to the use of a transparent window, hide the chrome
7731 HideWindowChrome(PR_TRUE
);
7732 } else if (mHideChrome
&& mTransparencyMode
== eTransparencyTransparent
) {
7733 // if we're switching out of transparent, re-enable our parent's chrome.
7734 HideWindowChrome(PR_FALSE
);
7737 LONG_PTR style
= ::GetWindowLongPtrW(hWnd
, GWL_STYLE
),
7738 exStyle
= ::GetWindowLongPtr(hWnd
, GWL_EXSTYLE
);
7740 if (parent
->mIsVisible
)
7741 style
|= WS_VISIBLE
;
7742 if (parent
->mSizeMode
== nsSizeMode_Maximized
)
7743 style
|= WS_MAXIMIZE
;
7744 else if (parent
->mSizeMode
== nsSizeMode_Minimized
)
7745 style
|= WS_MINIMIZE
;
7747 if (aMode
== eTransparencyTransparent
)
7748 exStyle
|= WS_EX_LAYERED
;
7750 exStyle
&= ~WS_EX_LAYERED
;
7752 VERIFY_WINDOW_STYLE(style
);
7753 ::SetWindowLongPtrW(hWnd
, GWL_STYLE
, style
);
7754 ::SetWindowLongPtrW(hWnd
, GWL_EXSTYLE
, exStyle
);
7756 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7758 memset(&mGlassMargins
, 0, sizeof mGlassMargins
);
7759 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7760 mTransparencyMode
= aMode
;
7762 SetupTranslucentWindowMemoryBitmap(aMode
);
7764 #endif // #ifndef WINCE
7767 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode
)
7769 if (eTransparencyTransparent
== aMode
) {
7770 ResizeTranslucentWindow(mBounds
.width
, mBounds
.height
, PR_TRUE
);
7772 mTransparentSurface
= nsnull
;
7777 nsresult
nsWindow::UpdateTranslucentWindow()
7780 if (mBounds
.IsEmpty())
7785 BLENDFUNCTION bf
= { AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
7786 SIZE winSize
= { mBounds
.width
, mBounds
.height
};
7787 POINT srcPos
= { 0, 0 };
7788 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
7790 ::GetWindowRect(hWnd
, &winRect
);
7792 #ifdef CAIRO_HAS_D2D_SURFACE
7793 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7794 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7795 mMemoryDC
= static_cast<gfxD2DSurface
*>(mTransparentSurface
.get())->
7799 // perform the alpha blend
7800 PRBool updateSuccesful
=
7801 ::UpdateLayeredWindow(hWnd
, NULL
, (POINT
*)&winRect
, &winSize
, mMemoryDC
, &srcPos
, 0, &bf
, ULW_ALPHA
);
7803 #ifdef CAIRO_HAS_D2D_SURFACE
7804 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7805 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7806 nsIntRect
r(0, 0, 0, 0);
7807 static_cast<gfxD2DSurface
*>(mTransparentSurface
.get())->ReleaseDC(&r
);
7811 if (!updateSuccesful
) {
7812 return NS_ERROR_FAILURE
;
7821 /**************************************************************
7822 **************************************************************
7824 ** BLOCK: Popup rollup hooks
7826 ** Deals with CaptureRollup on popup windows.
7828 **************************************************************
7829 **************************************************************/
7832 // Schedules a timer for a window, so we can rollup after processing the hook event
7833 void nsWindow::ScheduleHookTimer(HWND aWnd
, UINT aMsgId
)
7835 // In some cases multiple hooks may be scheduled
7836 // so ignore any other requests once one timer is scheduled
7837 if (sHookTimerId
== 0) {
7838 // Remember the window handle and the message ID to be used later
7839 sRollupMsgId
= aMsgId
;
7840 sRollupMsgWnd
= aWnd
;
7841 // Schedule native timer for doing the rollup after
7842 // this event is done being processed
7843 sHookTimerId
= ::SetTimer(NULL
, 0, 0, (TIMERPROC
)HookTimerForPopups
);
7844 NS_ASSERTION(sHookTimerId
, "Timer couldn't be created.");
7848 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7849 int gLastMsgCode
= 0;
7850 extern MSGFEventMsgInfo gMSGFEvents
[];
7853 // Process Menu messages, rollup when popup is clicked.
7854 LRESULT CALLBACK
nsWindow::MozSpecialMsgFilter(int code
, WPARAM wParam
, LPARAM lParam
)
7856 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7858 MSG
* pMsg
= (MSG
*)lParam
;
7861 while (gMSGFEvents
[inx
].mId
!= code
&& gMSGFEvents
[inx
].mStr
!= NULL
) {
7864 if (code
!= gLastMsgCode
) {
7865 if (gMSGFEvents
[inx
].mId
== code
) {
7867 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code
, gMSGFEvents
[inx
].mStr
, pMsg
->hwnd
);
7871 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code
, gMSGFEvents
[inx
].mId
, pMsg
->hwnd
);
7874 gLastMsgCode
= code
;
7876 PrintEvent(pMsg
->message
, FALSE
, FALSE
);
7878 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7880 if (sProcessHook
&& code
== MSGF_MENU
) {
7881 MSG
* pMsg
= (MSG
*)lParam
;
7882 ScheduleHookTimer( pMsg
->hwnd
, pMsg
->message
);
7885 return ::CallNextHookEx(sMsgFilterHook
, code
, wParam
, lParam
);
7888 // Process all mouse messages. Roll up when a click is in a native window
7889 // that doesn't have an nsIWidget.
7890 LRESULT CALLBACK
nsWindow::MozSpecialMouseProc(int code
, WPARAM wParam
, LPARAM lParam
)
7894 case WM_LBUTTONDOWN
:
7895 case WM_RBUTTONDOWN
:
7896 case WM_MBUTTONDOWN
:
7898 case WM_MOUSEHWHEEL
:
7900 MOUSEHOOKSTRUCT
* ms
= (MOUSEHOOKSTRUCT
*)lParam
;
7901 nsIWidget
* mozWin
= (nsIWidget
*)GetNSWindowPtr(ms
->hwnd
);
7903 // If this window is windowed plugin window, the mouse events are not
7905 if (static_cast<nsWindow
*>(mozWin
)->mWindowType
== eWindowType_plugin
)
7906 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
7908 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
7914 return ::CallNextHookEx(sCallMouseHook
, code
, wParam
, lParam
);
7917 // Process all messages. Roll up when the window is moving, or
7918 // is resizing or when maximized or mininized.
7919 LRESULT CALLBACK
nsWindow::MozSpecialWndProc(int code
, WPARAM wParam
, LPARAM lParam
)
7921 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7923 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
7924 PrintEvent(cwpt
->message
, FALSE
, FALSE
);
7929 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
7930 if (cwpt
->message
== WM_MOVING
||
7931 cwpt
->message
== WM_SIZING
||
7932 cwpt
->message
== WM_GETMINMAXINFO
) {
7933 ScheduleHookTimer(cwpt
->hwnd
, (UINT
)cwpt
->message
);
7937 return ::CallNextHookEx(sCallProcHook
, code
, wParam
, lParam
);
7940 // Register the special "hooks" for dropdown processing.
7941 void nsWindow::RegisterSpecialDropdownHooks()
7943 NS_ASSERTION(!sMsgFilterHook
, "sMsgFilterHook must be NULL!");
7944 NS_ASSERTION(!sCallProcHook
, "sCallProcHook must be NULL!");
7946 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
7948 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
7950 // Install msg hook for moving the window and resizing
7951 if (!sMsgFilterHook
) {
7952 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
7953 sMsgFilterHook
= SetWindowsHookEx(WH_MSGFILTER
, MozSpecialMsgFilter
, NULL
, GetCurrentThreadId());
7954 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7955 if (!sMsgFilterHook
) {
7956 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
7961 // Install msg hook for menus
7962 if (!sCallProcHook
) {
7963 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
7964 sCallProcHook
= SetWindowsHookEx(WH_CALLWNDPROC
, MozSpecialWndProc
, NULL
, GetCurrentThreadId());
7965 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7966 if (!sCallProcHook
) {
7967 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
7972 // Install msg hook for the mouse
7973 if (!sCallMouseHook
) {
7974 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
7975 sCallMouseHook
= SetWindowsHookEx(WH_MOUSE
, MozSpecialMouseProc
, NULL
, GetCurrentThreadId());
7976 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7977 if (!sCallMouseHook
) {
7978 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
7984 // Unhook special message hooks for dropdowns.
7985 void nsWindow::UnregisterSpecialDropdownHooks()
7987 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
7989 if (sCallProcHook
) {
7990 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
7991 if (!::UnhookWindowsHookEx(sCallProcHook
)) {
7992 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
7994 sCallProcHook
= NULL
;
7997 if (sMsgFilterHook
) {
7998 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
7999 if (!::UnhookWindowsHookEx(sMsgFilterHook
)) {
8000 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
8002 sMsgFilterHook
= NULL
;
8005 if (sCallMouseHook
) {
8006 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
8007 if (!::UnhookWindowsHookEx(sCallMouseHook
)) {
8008 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
8010 sCallMouseHook
= NULL
;
8014 // This timer is designed to only fire one time at most each time a "hook" function
8015 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
8016 // hook, but that hook event or a subsequent event may roll up the dropdown before
8017 // this timer function is executed.
8019 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
8020 // before this function fires.
8021 VOID CALLBACK
nsWindow::HookTimerForPopups(HWND hwnd
, UINT uMsg
, UINT idEvent
, DWORD dwTime
)
8023 if (sHookTimerId
!= 0) {
8024 // if the window is NULL then we need to use the ID to kill the timer
8025 BOOL status
= ::KillTimer(NULL
, sHookTimerId
);
8026 NS_ASSERTION(status
, "Hook Timer was not killed.");
8030 if (sRollupMsgId
!= 0) {
8031 // Note: DealWithPopups does the check to make sure that
8032 // sRollupListener and sRollupWidget are not NULL
8033 LRESULT popupHandlingResult
;
8034 nsAutoRollup autoRollup
;
8035 DealWithPopups(sRollupMsgWnd
, sRollupMsgId
, 0, 0, &popupHandlingResult
);
8037 sRollupMsgWnd
= NULL
;
8042 BOOL CALLBACK
nsWindow::ClearResourcesCallback(HWND aWnd
, LPARAM aMsg
)
8044 nsWindow
*window
= nsWindow::GetNSWindowPtr(aWnd
);
8046 window
->ClearCachedResources();
8052 nsWindow::ClearCachedResources()
8054 #ifdef CAIRO_HAS_D2D_SURFACE
8055 mD2DWindowSurface
= nsnull
;
8057 if (mLayerManager
&&
8058 mLayerManager
->GetBackendType() == LayerManager::LAYERS_BASIC
) {
8059 static_cast<BasicLayerManager
*>(mLayerManager
.get())->
8060 ClearCachedResources();
8062 ::EnumChildWindows(mWnd
, nsWindow::ClearResourcesCallback
, NULL
);
8065 static PRBool
IsDifferentThreadWindow(HWND aWnd
)
8067 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd
, NULL
);
8071 nsWindow::EventIsInsideWindow(UINT Msg
, nsWindow
* aWindow
)
8076 if (Msg
== WM_ACTIVATEAPP
)
8077 // don't care about activation/deactivation
8080 if (Msg
== WM_ACTIVATE
)
8081 // but on Windows CE we do care about
8082 // activation/deactivation because there doesn't exist
8083 // cancelable Mouse Activation events
8087 ::GetWindowRect(aWindow
->mWnd
, &r
);
8088 DWORD pos
= ::GetMessagePos();
8090 mp
.x
= GET_X_LPARAM(pos
);
8091 mp
.y
= GET_Y_LPARAM(pos
);
8093 // was the event inside this window?
8094 return (PRBool
) PtInRect(&r
, mp
);
8097 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8099 nsWindow::DealWithPopups(HWND inWnd
, UINT inMsg
, WPARAM inWParam
, LPARAM inLParam
, LRESULT
* outResult
)
8101 if (sRollupListener
&& sRollupWidget
&& ::IsWindowVisible(inWnd
)) {
8103 if (inMsg
== WM_LBUTTONDOWN
|| inMsg
== WM_RBUTTONDOWN
|| inMsg
== WM_MBUTTONDOWN
||
8104 inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
|| inMsg
== WM_ACTIVATE
||
8105 (inMsg
== WM_KILLFOCUS
&& IsDifferentThreadWindow((HWND
)inWParam
))
8108 inMsg
== WM_NCRBUTTONDOWN
||
8109 inMsg
== WM_MOVING
||
8110 inMsg
== WM_SIZING
||
8111 inMsg
== WM_NCLBUTTONDOWN
||
8112 inMsg
== WM_NCMBUTTONDOWN
||
8113 inMsg
== WM_MOUSEACTIVATE
||
8114 inMsg
== WM_ACTIVATEAPP
||
8115 inMsg
== WM_MENUSELECT
8119 // Rollup if the event is outside the popup.
8120 PRBool rollup
= !nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)sRollupWidget
);
8122 if (rollup
&& (inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
))
8124 sRollupListener
->ShouldRollupOnMouseWheelEvent(&rollup
);
8125 *outResult
= PR_TRUE
;
8128 // If we're dealing with menus, we probably have submenus and we don't
8129 // want to rollup if the click is in a parent menu of the current submenu.
8130 PRUint32 popupsToRollup
= PR_UINT32_MAX
;
8132 if ( sMenuRollup
) {
8133 nsAutoTArray
<nsIWidget
*, 5> widgetChain
;
8134 PRUint32 sameTypeCount
= sMenuRollup
->GetSubmenuWidgetChain(&widgetChain
);
8135 for ( PRUint32 i
= 0; i
< widgetChain
.Length(); ++i
) {
8136 nsIWidget
* widget
= widgetChain
[i
];
8137 if ( nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)widget
) ) {
8138 // don't roll up if the mouse event occurred within a menu of the
8139 // same type. If the mouse event occurred in a menu higher than
8140 // that, roll up, but pass the number of popups to Rollup so
8141 // that only those of the same type close up.
8142 if (i
< sameTypeCount
) {
8146 popupsToRollup
= sameTypeCount
;
8150 } // foreach parent menu widget
8151 } // if rollup listener knows about menus
8155 if (inMsg
== WM_MOUSEACTIVATE
&& popupsToRollup
== PR_UINT32_MAX
) {
8156 // Prevent the click inside the popup from causing a change in window
8157 // activation. Since the popup is shown non-activated, we need to eat
8158 // any requests to activate the window while it is displayed. Windows
8159 // will automatically activate the popup on the mousedown otherwise.
8161 *outResult
= MA_NOACTIVATE
;
8166 UINT uMsg
= HIWORD(inLParam
);
8167 if (uMsg
== WM_MOUSEMOVE
)
8169 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8170 // must be enabled in Windows.
8171 sRollupListener
->ShouldRollupOnMouseActivate(&rollup
);
8174 *outResult
= MA_NOACTIVATE
;
8180 // if we've still determined that we should still rollup everything, do it.
8184 // sRollupConsumeEvent may be modified by
8185 // nsIRollupListener::Rollup.
8186 PRBool consumeRollupEvent
= sRollupConsumeEvent
;
8187 // only need to deal with the last rollup for left mouse down events.
8188 sRollupListener
->Rollup(popupsToRollup
, inMsg
== WM_LBUTTONDOWN
? &mLastRollup
: nsnull
);
8190 // Tell hook to stop processing messages
8191 sProcessHook
= PR_FALSE
;
8193 sRollupMsgWnd
= NULL
;
8195 // return TRUE tells Windows that the event is consumed,
8196 // false allows the event to be dispatched
8198 // So if we are NOT supposed to be consuming events, let it go through
8199 if (consumeRollupEvent
&& inMsg
!= WM_RBUTTONDOWN
) {
8204 // if we are only rolling up some popups, don't activate and don't let
8205 // the event go through. This prevents clicks menus higher in the
8206 // chain from opening when a context menu is open
8207 if (popupsToRollup
!= PR_UINT32_MAX
&& inMsg
== WM_MOUSEACTIVATE
) {
8208 *outResult
= MA_NOACTIVATEANDEAT
;
8213 } // if event that might trigger a popup to rollup
8214 } // if rollup listeners registered
8219 /**************************************************************
8220 **************************************************************
8222 ** BLOCK: Misc. utility methods and functions.
8226 **************************************************************
8227 **************************************************************/
8229 // nsModifierKeyState used in various character processing.
8230 nsModifierKeyState::nsModifierKeyState()
8232 mIsShiftDown
= IS_VK_DOWN(NS_VK_SHIFT
);
8233 mIsControlDown
= IS_VK_DOWN(NS_VK_CONTROL
);
8234 mIsAltDown
= IS_VK_DOWN(NS_VK_ALT
);
8238 PRInt32
nsWindow::GetWindowsVersion()
8243 static PRInt32 version
= 0;
8244 static PRBool didCheck
= PR_FALSE
;
8249 OSVERSIONINFOEX osInfo
;
8250 osInfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
8251 // This cast is safe and supposed to be here, don't worry
8252 ::GetVersionEx((OSVERSIONINFO
*)&osInfo
);
8253 version
= (osInfo
.dwMajorVersion
& 0xff) << 8 | (osInfo
.dwMinorVersion
& 0xff);
8259 // Note that the result of GetTopLevelWindow method can be different from the
8260 // result of GetTopLevelHWND method. The result can be non-floating window.
8261 // Because our top level window may be contained in another window which is
8262 // not managed by us.
8263 nsWindow
* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup
)
8265 nsWindow
* curWindow
= this;
8268 if (aStopOnDialogOrPopup
) {
8269 switch (curWindow
->mWindowType
) {
8270 case eWindowType_dialog
:
8271 case eWindowType_popup
:
8278 // Retrieve the top level parent or owner window
8279 nsWindow
* parentWindow
= curWindow
->GetParentWindow(PR_TRUE
);
8284 curWindow
= parentWindow
;
8288 // Note that the result of GetTopLevelHWND can be different from the result
8289 // of GetTopLevelWindow method. Because this is checking whether the window
8290 // is top level only in Win32 window system. Therefore, the result window
8291 // may not be managed by us.
8292 HWND
nsWindow::GetTopLevelHWND(HWND aWnd
, PRBool aStopOnDialogOrPopup
)
8301 if (aStopOnDialogOrPopup
) {
8302 DWORD_PTR style
= ::GetWindowLongPtrW(curWnd
, GWL_STYLE
);
8304 VERIFY_WINDOW_STYLE(style
);
8306 if (!(style
& WS_CHILD
)) // first top-level window
8310 upWnd
= ::GetParent(curWnd
); // Parent or owner (if has no parent)
8313 // For dialog windows, we want just the parent, not the owner.
8314 // For other/popup windows, we want to find the first owner/parent
8315 // that's a dialog and/or has an owner.
8316 if (upWnd
&& ::GetWindow(curWnd
, GW_OWNER
) == upWnd
) {
8317 DWORD_PTR style
= ::GetWindowLongPtrW(curWnd
, GWL_STYLE
);
8318 if ((style
& WS_DLGFRAME
) != 0)
8329 static BOOL CALLBACK
gEnumWindowsProc(HWND hwnd
, LPARAM lParam
)
8332 ::GetWindowThreadProcessId(hwnd
, &pid
);
8333 if (pid
== GetCurrentProcessId() && ::IsWindowVisible(hwnd
))
8335 gWindowsVisible
= PR_TRUE
;
8341 PRBool
nsWindow::CanTakeFocus()
8343 gWindowsVisible
= PR_FALSE
;
8344 EnumWindows(gEnumWindowsProc
, 0);
8345 if (!gWindowsVisible
) {
8348 HWND fgWnd
= ::GetForegroundWindow();
8353 GetWindowThreadProcessId(fgWnd
, &pid
);
8354 if (pid
== GetCurrentProcessId()) {
8362 void nsWindow::InitTrackPointHack()
8364 // Init Trackpoint Hack
8368 const WCHAR wstrKeys
[][40] = {L
"Software\\Lenovo\\TrackPoint",
8369 L
"Software\\Lenovo\\UltraNav",
8370 L
"Software\\Alps\\Apoint\\TrackPoint",
8371 L
"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
8372 L
"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
8373 // If anything fails turn the hack off
8374 sTrackPointHack
= false;
8375 nsCOMPtr
<nsIPrefBranch
> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
));
8376 if(NS_SUCCEEDED(rv
) && prefs
) {
8377 prefs
->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue
);
8378 switch (lHackValue
) {
8379 // 0 means hack disabled
8382 // 1 means hack enabled
8384 sTrackPointHack
= true;
8386 // -1 means autodetect
8388 for(unsigned i
= 0; i
< NS_ARRAY_LENGTH(wstrKeys
); i
++) {
8390 lResult
= ::RegOpenKeyExW(HKEY_CURRENT_USER
, (LPCWSTR
)&wstrKeys
[i
],
8391 0, KEY_READ
, &hKey
);
8392 ::RegCloseKey(hKey
);
8393 if(lResult
== ERROR_SUCCESS
) {
8394 // If we detected a registry key belonging to a TrackPoint driver
8396 sTrackPointHack
= true;
8401 // Shouldn't be any other values, but treat them as disabled
8408 #endif // #if !defined(WINCE)
8410 LPARAM
nsWindow::lParamToScreen(LPARAM lParam
)
8413 pt
.x
= GET_X_LPARAM(lParam
);
8414 pt
.y
= GET_Y_LPARAM(lParam
);
8415 ::ClientToScreen(mWnd
, &pt
);
8416 return MAKELPARAM(pt
.x
, pt
.y
);
8419 LPARAM
nsWindow::lParamToClient(LPARAM lParam
)
8422 pt
.x
= GET_X_LPARAM(lParam
);
8423 pt
.y
= GET_Y_LPARAM(lParam
);
8424 ::ScreenToClient(mWnd
, &pt
);
8425 return MAKELPARAM(pt
.x
, pt
.y
);
8428 /**************************************************************
8429 **************************************************************
8431 ** BLOCK: ChildWindow impl.
8433 ** Child window overrides.
8435 **************************************************************
8436 **************************************************************/
8438 // return the style for a child nsWindow
8439 DWORD
ChildWindow::WindowStyle()
8441 DWORD style
= WS_CLIPCHILDREN
| nsWindow::WindowStyle();
8442 if (!(style
& WS_POPUP
))
8443 style
|= WS_CHILD
; // WS_POPUP and WS_CHILD are mutually exclusive.
8444 VERIFY_WINDOW_STYLE(style
);