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 #include "LayerManagerOGL.h"
179 #include "BasicLayers.h"
182 #include "nsUXThemeConstants.h"
183 #include "KeyboardLayout.h"
184 #include "nsNativeDragTarget.h"
185 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
188 #include <richedit.h>
189 #endif // !defined(WINCE)
191 #if defined(ACCESSIBILITY)
194 #include "nsIAccessibleDocument.h"
195 #if !defined(WINABLEAPI)
197 #endif // !defined(WINABLEAPI)
198 #endif // defined(ACCESSIBILITY)
200 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
201 #include "nsIWinTaskbar.h"
204 #if defined(NS_ENABLE_TSF)
205 #include "nsTextStore.h"
206 #endif // defined(NS_ENABLE_TSF)
208 #if defined(MOZ_SPLASHSCREEN)
209 #include "nsSplashScreen.h"
210 #endif // defined(MOZ_SPLASHSCREEN)
212 // Windowless plugin support
215 #include "nsWindowDefs.h"
217 #include "mozilla/FunctionTimer.h"
219 #ifdef WINCE_WINDOWS_MOBILE
220 #include "nsGfxCIID.h"
223 #include "mozilla/FunctionTimer.h"
225 #ifdef MOZ_CRASHREPORTER
226 #include "nsICrashReporter.h"
229 #include "nsIXULRuntime.h"
231 using namespace mozilla::widget
;
233 /**************************************************************
234 **************************************************************
238 ** nsWindow Class static initializations and global variables.
240 **************************************************************
241 **************************************************************/
243 /**************************************************************
245 * SECTION: nsWindow statics
247 **************************************************************/
249 PRUint32
nsWindow::sInstanceCount
= 0;
250 PRBool
nsWindow::sSwitchKeyboardLayout
= PR_FALSE
;
251 BOOL
nsWindow::sIsRegistered
= FALSE
;
252 BOOL
nsWindow::sIsPopupClassRegistered
= FALSE
;
253 BOOL
nsWindow::sIsOleInitialized
= FALSE
;
254 HCURSOR
nsWindow::sHCursor
= NULL
;
255 imgIContainer
* nsWindow::sCursorImgContainer
= nsnull
;
256 nsWindow
* nsWindow::sCurrentWindow
= nsnull
;
257 PRBool
nsWindow::sJustGotDeactivate
= PR_FALSE
;
258 PRBool
nsWindow::sJustGotActivate
= PR_FALSE
;
260 // imported in nsWidgetFactory.cpp
261 TriStateBool
nsWindow::sCanQuit
= TRI_UNKNOWN
;
263 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
264 // hook methods whether they should be processing the hook
266 HHOOK
nsWindow::sMsgFilterHook
= NULL
;
267 HHOOK
nsWindow::sCallProcHook
= NULL
;
268 HHOOK
nsWindow::sCallMouseHook
= NULL
;
269 PRPackedBool
nsWindow::sProcessHook
= PR_FALSE
;
270 UINT
nsWindow::sRollupMsgId
= 0;
271 HWND
nsWindow::sRollupMsgWnd
= NULL
;
272 UINT
nsWindow::sHookTimerId
= 0;
275 nsIRollupListener
* nsWindow::sRollupListener
= nsnull
;
276 nsIMenuRollup
* nsWindow::sMenuRollup
= nsnull
;
277 nsIWidget
* nsWindow::sRollupWidget
= nsnull
;
278 PRBool
nsWindow::sRollupConsumeEvent
= PR_FALSE
;
280 // Mouse Clicks - static variable definitions for figuring
282 POINT
nsWindow::sLastMousePoint
= {0};
283 POINT
nsWindow::sLastMouseMovePoint
= {0};
284 LONG
nsWindow::sLastMouseDownTime
= 0L;
285 LONG
nsWindow::sLastClickCount
= 0L;
286 BYTE
nsWindow::sLastMouseButton
= 0;
288 // Trim heap on minimize. (initialized, but still true.)
289 int nsWindow::sTrimOnMinimize
= 2;
291 // Default Trackpoint Hack to off
292 PRBool
nsWindow::sTrackPointHack
= PR_FALSE
;
295 BOOL
nsWindow::sIsAccessibilityOn
= FALSE
;
296 // Accessibility wm_getobject handler
297 HINSTANCE
nsWindow::sAccLib
= 0;
298 LPFNLRESULTFROMOBJECT
299 nsWindow::sLresultFromObject
= 0;
300 #endif // ACCESSIBILITY
303 // Used in OOPP plugin focus processing.
304 const PRUnichar
* kOOPPPluginFocusEventId
= L
"OOPP Plugin Focus Widget Event";
305 PRUint32
nsWindow::sOOPPPluginFocusEvent
=
306 RegisterWindowMessageW(kOOPPPluginFocusEventId
);
309 /**************************************************************
311 * SECTION: globals variables
313 **************************************************************/
315 static const char *sScreenManagerContractID
= "@mozilla.org/gfx/screenmanager;1";
318 PRLogModuleInfo
* gWindowsLog
= nsnull
;
322 // Kbd layout. Used throughout character processing.
323 static KeyboardLayout gKbdLayout
;
326 #ifdef WINCE_WINDOWS_MOBILE
327 // HTC Navigation Wheel Event
328 // This is the defined value for Gesture Mode
329 const int WM_HTCNAV
= 0x0400 + 200;
331 typedef int (__stdcall
* HTCApiNavOpen
)(HANDLE
, int);
332 typedef int (__stdcall
* HTCApiNavSetMode
)(HANDLE
, unsigned int);
334 HTCApiNavOpen gHTCApiNavOpen
= nsnull
;
335 HTCApiNavSetMode gHTCApiNavSetMode
= nsnull
;
336 static PRBool gCheckForHTCApi
= PR_FALSE
;
339 // Global user preference for disabling native theme. Used
340 // in NativeWindowTheme.
341 PRBool gDisableNativeTheme
= PR_FALSE
;
343 // Global used in Show window enumerations.
344 static PRBool gWindowsVisible
= PR_FALSE
;
346 static NS_DEFINE_CID(kCClipboardCID
, NS_CLIPBOARD_CID
);
347 #ifdef WINCE_WINDOWS_MOBILE
348 static NS_DEFINE_CID(kRegionCID
, NS_REGION_CID
);
351 /**************************************************************
352 **************************************************************
354 ** BLOCK: nsIWidget impl.
356 ** nsIWidget interface implementation, broken down into
359 **************************************************************
360 **************************************************************/
362 /**************************************************************
364 * SECTION: nsWindow construction and destruction
366 **************************************************************/
368 nsWindow::nsWindow() : nsBaseWidget()
372 gWindowsLog
= PR_NewLogModule("nsWindowsWidgets");
377 mPrevWndProc
= nsnull
;
379 mNativeDragTarget
= nsnull
;
381 mIsVisible
= PR_FALSE
;
382 mIsInMouseCapture
= PR_FALSE
;
383 mIsTopWidgetWindow
= PR_FALSE
;
384 mUnicodeWidget
= PR_TRUE
;
385 mDisplayPanFeedback
= PR_FALSE
;
386 mTouchWindow
= PR_FALSE
;
387 mCustomNonClient
= PR_FALSE
;
388 mHideChrome
= PR_FALSE
;
389 mFullscreenMode
= PR_FALSE
;
390 mWindowType
= eWindowType_child
;
391 mBorderStyle
= eBorderStyle_default
;
392 mPopupType
= ePopupTypeAny
;
393 mOldSizeMode
= nsSizeMode_Normal
;
397 mLastSize
.height
= 0;
401 mExitToNonClientArea
= 0;
402 mLastKeyboardLayout
= 0;
403 mBlurSuppressLevel
= 0;
404 mIMEEnabled
= nsIWidget::IME_STATUS_ENABLED
;
406 mTransparentSurface
= nsnull
;
408 mTransparencyMode
= eTransparencyOpaque
;
409 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
410 memset(&mGlassMargins
, 0, sizeof mGlassMargins
);
411 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
413 mBackground
= ::GetSysColor(COLOR_BTNFACE
);
414 mBrush
= ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground
));
415 mForeground
= ::GetSysColor(COLOR_WINDOWTEXT
);
417 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
418 mTaskbarPreview
= nsnull
;
419 mHasTaskbarIconBeenCreated
= PR_FALSE
;
422 // Global initialization
423 if (!sInstanceCount
) {
425 gKbdLayout
.LoadLayout(::GetKeyboardLayout(0));
429 nsIMM32Handler::Initialize();
432 nsTextStore::Initialize();
436 if (SUCCEEDED(::OleInitialize(NULL
)))
437 sIsOleInitialized
= TRUE
;
438 NS_ASSERTION(sIsOleInitialized
, "***** OLE is not initialized!\n");
442 InitTrackPointHack();
445 // Init titlebar button info for custom frames.
446 nsUXThemeData::InitTitlebarInfo();
449 mIdleService
= nsnull
;
454 nsWindow::~nsWindow()
458 // If the widget was released without calling Destroy() then the native window still
459 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
461 // XXX How could this happen???
468 if (sInstanceCount
== 0) {
470 nsTextStore::Terminate();
474 NS_IF_RELEASE(sCursorImgContainer
);
475 if (sIsOleInitialized
) {
476 ::OleFlushClipboard();
478 sIsOleInitialized
= FALSE
;
480 // delete any of the IME structures that we allocated
481 nsIMM32Handler::Terminate();
482 #endif // !defined(WINCE)
486 NS_IF_RELEASE(mNativeDragTarget
);
487 #endif // !defined(WINCE)
490 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow
, nsBaseWidget
)
492 /**************************************************************
494 * SECTION: nsIWidget::Create, nsIWidget::Destroy
496 * Creating and destroying windows for this widget.
498 **************************************************************/
500 // Allow Derived classes to modify the height that is passed
501 // when the window is created or resized. Also add extra height
502 // if needed (on Windows CE)
503 PRInt32
nsWindow::GetHeight(PRInt32 aProposedHeight
)
507 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
508 DWORD style
= WindowStyle();
509 if ((style
& WS_SYSMENU
) && (style
& WS_POPUP
)) {
510 extra
= GetSystemMetrics(SM_CYCAPTION
);
514 return aProposedHeight
+ extra
;
517 // Create the proper widget
519 nsWindow::Create(nsIWidget
*aParent
,
520 nsNativeWidget aNativeParent
,
521 const nsIntRect
&aRect
,
522 EVENT_CALLBACK aHandleEventFunction
,
523 nsIDeviceContext
*aContext
,
524 nsIAppShell
*aAppShell
,
525 nsIToolkit
*aToolkit
,
526 nsWidgetInitData
*aInitData
)
528 nsWidgetInitData defaultInitData
;
530 aInitData
= &defaultInitData
;
532 mUnicodeWidget
= aInitData
->mUnicode
;
534 nsIWidget
*baseParent
= aInitData
->mWindowType
== eWindowType_dialog
||
535 aInitData
->mWindowType
== eWindowType_toplevel
||
536 aInitData
->mWindowType
== eWindowType_invisible
?
539 mIsTopWidgetWindow
= (nsnull
== baseParent
);
540 mBounds
.width
= aRect
.width
;
541 mBounds
.height
= aRect
.height
;
543 BaseCreate(baseParent
, aRect
, aHandleEventFunction
, aContext
,
544 aAppShell
, aToolkit
, aInitData
);
547 if (aParent
) { // has a nsIWidget parent
548 parent
= aParent
? (HWND
)aParent
->GetNativeData(NS_NATIVE_WINDOW
) : NULL
;
550 } else { // has a nsNative parent
551 parent
= (HWND
)aNativeParent
;
552 mParent
= aNativeParent
? GetNSWindowPtr((HWND
)aNativeParent
) : nsnull
;
555 mPopupType
= aInitData
->mPopupHint
;
556 mContentType
= aInitData
->mContentType
;
557 mIsRTL
= aInitData
->mRTL
;
559 DWORD style
= WindowStyle();
560 DWORD extendedStyle
= WindowExStyle();
562 if (mWindowType
== eWindowType_popup
) {
565 } else if (mWindowType
== eWindowType_invisible
) {
566 // Make sure CreateWindowEx succeeds at creating a toplevel window
567 style
&= ~0x40000000; // WS_CHILDWINDOW
569 // See if the caller wants to explictly set clip children and clip siblings
570 if (aInitData
->clipChildren
) {
571 style
|= WS_CLIPCHILDREN
;
573 style
&= ~WS_CLIPCHILDREN
;
575 if (aInitData
->clipSiblings
) {
576 style
|= WS_CLIPSIBLINGS
;
580 mWnd
= ::CreateWindowExW(extendedStyle
,
581 aInitData
->mDropShadow
?
582 WindowPopupClass() : WindowClass(),
588 GetHeight(aRect
.height
),
591 nsToolkit::mDllInstance
,
595 NS_WARNING("nsWindow CreateWindowEx failed.");
596 return NS_ERROR_FAILURE
;
599 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
600 if (mIsRTL
&& nsUXThemeData::dwmSetWindowAttributePtr
) {
601 DWORD dwAttribute
= TRUE
;
602 nsUXThemeData::dwmSetWindowAttributePtr(mWnd
, DWMWA_NONCLIENT_RTL_LAYOUT
, &dwAttribute
, sizeof dwAttribute
);
606 if (nsWindow::sTrackPointHack
&&
607 mWindowType
!= eWindowType_plugin
&&
608 mWindowType
!= eWindowType_invisible
) {
609 // Ugly Thinkpad Driver Hack (Bug 507222)
610 // We create an invisible scrollbar to trick the
611 // Trackpoint driver into sending us scrolling messages
612 ::CreateWindowW(L
"SCROLLBAR", L
"FAKETRACKPOINTSCROLLBAR",
613 WS_CHILD
| WS_VISIBLE
, 0,0,0,0, mWnd
, NULL
,
614 nsToolkit::mDllInstance
, NULL
);
617 // call the event callback to notify about creation
619 DispatchStandardEvent(NS_CREATE
);
620 SubclassWindow(TRUE
);
622 if (sTrimOnMinimize
== 2 && mWindowType
== eWindowType_invisible
) {
623 /* The internal variable set by the config.trim_on_minimize pref
624 has not yet been initialized, and this is the hidden window
625 (conveniently created before any visible windows, and after
626 the profile has been initialized).
628 Default config.trim_on_minimize to false, to fix bug 76831
629 for good. If anyone complains about this new default, saying
630 that a Mozilla app hogs too much memory while minimized, they
631 will have that entire bug tattooed on their backside. */
634 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
636 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
637 prefs
->GetBranch(0, getter_AddRefs(prefBranch
));
641 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("config.trim_on_minimize",
646 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("intl.keyboard.per_window_layout",
648 sSwitchKeyboardLayout
= temp
;
650 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("mozilla.widget.disable-native-theme",
652 gDisableNativeTheme
= temp
;
656 #if defined(WINCE_HAVE_SOFTKB)
657 if (mWindowType
== eWindowType_dialog
|| mWindowType
== eWindowType_toplevel
)
658 nsWindowCE::CreateSoftKeyMenuBar(mWnd
);
664 // Close this nsWindow
665 NS_METHOD
nsWindow::Destroy()
667 // WM_DESTROY has already fired, we're done.
671 // During the destruction of all of our children, make sure we don't get deleted.
672 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
675 * On windows the LayerManagerOGL destructor wants the widget to be around for
676 * cleanup. It also would like to have the HWND intact, so we NULL it here.
679 mLayerManager
->Destroy();
681 mLayerManager
= nsnull
;
683 /* We should clear our cached resources now and not wait for the GC to
684 * delete the nsWindow. */
685 ClearCachedResources();
687 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
688 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
689 // from it. The function also destroys the window's menu, flushes the thread message queue,
690 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
691 // the window is at the top of the viewer chain).
693 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
694 // the associated child or owned windows when it destroys the parent or owner window. The
695 // function first destroys child or owned windows, and then it destroys the parent or owner
697 VERIFY(::DestroyWindow(mWnd
));
699 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
700 // didn't get called, call it now.
701 if (PR_FALSE
== mOnDestroyCalled
)
707 /**************************************************************
709 * SECTION: Window class utilities
711 * Utilities for calculating the proper window class name for
714 **************************************************************/
716 // Return the proper window class for everything except popups.
717 LPCWSTR
nsWindow::WindowClass()
719 if (!nsWindow::sIsRegistered
) {
722 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
723 wc
.style
= CS_DBLCLKS
;
724 wc
.lpfnWndProc
= ::DefWindowProcW
;
727 wc
.hInstance
= nsToolkit::mDllInstance
;
728 wc
.hIcon
= ::LoadIconW(::GetModuleHandleW(NULL
), (LPWSTR
)IDI_APPLICATION
);
730 wc
.hbrBackground
= mBrush
;
731 wc
.lpszMenuName
= NULL
;
732 wc
.lpszClassName
= kClassNameHidden
;
734 BOOL succeeded
= ::RegisterClassW(&wc
) != 0 &&
735 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError();
736 nsWindow::sIsRegistered
= succeeded
;
738 wc
.lpszClassName
= kClassNameContentFrame
;
739 if (!::RegisterClassW(&wc
) &&
740 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
741 nsWindow::sIsRegistered
= FALSE
;
744 wc
.lpszClassName
= kClassNameContent
;
745 if (!::RegisterClassW(&wc
) &&
746 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
747 nsWindow::sIsRegistered
= FALSE
;
750 wc
.lpszClassName
= kClassNameGeneral
;
751 ATOM generalClassAtom
= ::RegisterClassW(&wc
);
752 if (!generalClassAtom
&&
753 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
754 nsWindow::sIsRegistered
= FALSE
;
757 wc
.lpszClassName
= kClassNameDialog
;
759 if (!::RegisterClassW(&wc
) &&
760 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
761 nsWindow::sIsRegistered
= FALSE
;
765 if (mWindowType
== eWindowType_invisible
) {
766 return kClassNameHidden
;
768 if (mWindowType
== eWindowType_dialog
) {
769 return kClassNameDialog
;
771 if (mContentType
== eContentTypeContent
) {
772 return kClassNameContent
;
774 if (mContentType
== eContentTypeContentFrame
) {
775 return kClassNameContentFrame
;
777 return kClassNameGeneral
;
780 // Return the proper popup window class
781 LPCWSTR
nsWindow::WindowPopupClass()
783 if (!nsWindow::sIsPopupClassRegistered
) {
786 wc
.style
= CS_DBLCLKS
| CS_XP_DROPSHADOW
;
787 wc
.lpfnWndProc
= ::DefWindowProcW
;
790 wc
.hInstance
= nsToolkit::mDllInstance
;
791 wc
.hIcon
= ::LoadIconW(::GetModuleHandleW(NULL
), (LPWSTR
)IDI_APPLICATION
);
793 wc
.hbrBackground
= mBrush
;
794 wc
.lpszMenuName
= NULL
;
795 wc
.lpszClassName
= kClassNameDropShadow
;
797 nsWindow::sIsPopupClassRegistered
= ::RegisterClassW(&wc
);
798 if (!nsWindow::sIsPopupClassRegistered
) {
799 // For older versions of Win32 (i.e., not XP), the registration will
800 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
801 wc
.style
= CS_DBLCLKS
;
802 nsWindow::sIsPopupClassRegistered
= ::RegisterClassW(&wc
);
806 return kClassNameDropShadow
;
809 /**************************************************************
811 * SECTION: Window styles utilities
813 * Return the proper windows styles and extended styles.
815 **************************************************************/
817 // Return nsWindow styles
818 #if !defined(WINCE) // implemented in nsWindowCE.cpp
819 DWORD
nsWindow::WindowStyle()
823 switch (mWindowType
) {
824 case eWindowType_plugin
:
825 case eWindowType_child
:
826 style
= WS_OVERLAPPED
;
829 case eWindowType_dialog
:
830 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
| DS_3DLOOK
|
831 DS_MODALFRAME
| WS_CLIPCHILDREN
;
832 if (mBorderStyle
!= eBorderStyle_default
)
833 style
|= WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
;
836 case eWindowType_popup
:
839 style
|= WS_OVERLAPPED
;
844 NS_ERROR("unknown border style");
847 case eWindowType_toplevel
:
848 case eWindowType_invisible
:
849 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
|
850 WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
| WS_CLIPCHILDREN
;
854 if (mBorderStyle
!= eBorderStyle_default
&& mBorderStyle
!= eBorderStyle_all
) {
855 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_border
))
858 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_title
)) {
859 style
&= ~WS_DLGFRAME
;
864 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_close
))
866 // XXX The close box can only be removed by changing the window class,
867 // as far as I know --- roc+moz@cs.cmu.edu
869 if (mBorderStyle
== eBorderStyle_none
||
870 !(mBorderStyle
& (eBorderStyle_menu
| eBorderStyle_close
)))
871 style
&= ~WS_SYSMENU
;
872 // Looks like getting rid of the system menu also does away with the
873 // close box. So, we only get rid of the system menu if you want neither it
874 // nor the close box. How does the Windows "Dialog" window class get just
875 // closebox and no sysmenu? Who knows.
877 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_resizeh
))
878 style
&= ~WS_THICKFRAME
;
880 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_minimize
))
881 style
&= ~WS_MINIMIZEBOX
;
883 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_maximize
))
884 style
&= ~WS_MAXIMIZEBOX
;
886 if (IsPopupWithTitleBar()) {
888 if (mBorderStyle
& eBorderStyle_close
) {
894 VERIFY_WINDOW_STYLE(style
);
897 #endif // !defined(WINCE)
899 // Return nsWindow extended styles
900 DWORD
nsWindow::WindowExStyle()
904 case eWindowType_plugin
:
905 case eWindowType_child
:
908 case eWindowType_dialog
:
909 return WS_EX_WINDOWEDGE
| WS_EX_DLGMODALFRAME
;
911 case eWindowType_popup
:
913 DWORD extendedStyle
=
914 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
918 if (mPopupLevel
== ePopupLevelTop
)
919 extendedStyle
|= WS_EX_TOPMOST
;
920 return extendedStyle
;
923 NS_ERROR("unknown border style");
926 case eWindowType_toplevel
:
927 case eWindowType_invisible
:
928 return WS_EX_WINDOWEDGE
;
932 /**************************************************************
934 * SECTION: Window subclassing utilities
936 * Set or clear window subclasses on native windows. Used in
937 * Create and Destroy.
939 **************************************************************/
941 // Subclass (or remove the subclass from) this component's nsWindow
942 void nsWindow::SubclassWindow(BOOL bState
)
945 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
946 if (!::IsWindow(mWnd
)) {
947 NS_ERROR("Invalid window handle");
951 // change the nsWindow proc
953 mPrevWndProc
= (WNDPROC
)::SetWindowLongPtrW(mWnd
, GWLP_WNDPROC
,
954 (LONG_PTR
)nsWindow::WindowProc
);
956 mPrevWndProc
= (WNDPROC
)::SetWindowLongPtrA(mWnd
, GWLP_WNDPROC
,
957 (LONG_PTR
)nsWindow::WindowProc
);
958 NS_ASSERTION(mPrevWndProc
, "Null standard window procedure");
959 // connect the this pointer to the nsWindow handle
960 SetNSWindowPtr(mWnd
, this);
964 ::SetWindowLongPtrW(mWnd
, GWLP_WNDPROC
, (LONG_PTR
)mPrevWndProc
);
966 ::SetWindowLongPtrA(mWnd
, GWLP_WNDPROC
, (LONG_PTR
)mPrevWndProc
);
967 SetNSWindowPtr(mWnd
, NULL
);
973 /**************************************************************
975 * SECTION: Window properties
977 * Set and clear native window properties.
979 **************************************************************/
981 static PRUnichar sPropName
[40] = L
"";
982 static PRUnichar
* GetNSWindowPropName()
986 _snwprintf(sPropName
, 39, L
"MozillansIWidgetPtr%p", GetCurrentProcessId());
987 sPropName
[39] = '\0';
992 nsWindow
* nsWindow::GetNSWindowPtr(HWND aWnd
)
994 return (nsWindow
*) ::GetPropW(aWnd
, GetNSWindowPropName());
997 BOOL
nsWindow::SetNSWindowPtr(HWND aWnd
, nsWindow
* ptr
)
1000 ::RemovePropW(aWnd
, GetNSWindowPropName());
1003 return ::SetPropW(aWnd
, GetNSWindowPropName(), (HANDLE
)ptr
);
1007 /**************************************************************
1009 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
1011 * Set or clear the parent widgets using window properties, and
1012 * handles calculating native parent handles.
1014 **************************************************************/
1016 // Get and set parent widgets
1017 NS_IMETHODIMP
nsWindow::SetParent(nsIWidget
*aNewParent
)
1019 mParent
= aNewParent
;
1022 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
1024 nsIWidget
* parent
= GetParent();
1026 parent
->RemoveChild(this);
1029 HWND newParent
= (HWND
)aNewParent
->GetNativeData(NS_NATIVE_WINDOW
);
1030 NS_ASSERTION(newParent
, "Parent widget has a null native window handle");
1031 if (newParent
&& mWnd
) {
1032 ::SetParent(mWnd
, newParent
);
1035 aNewParent
->AddChild(this);
1040 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
1042 nsIWidget
* parent
= GetParent();
1045 parent
->RemoveChild(this);
1049 // If we have no parent, SetParent should return the desktop.
1050 VERIFY(::SetParent(mWnd
, nsnull
));
1056 nsIWidget
* nsWindow::GetParent(void)
1058 return GetParentWindow(PR_FALSE
);
1061 float nsWindow::GetDPI()
1063 HDC dc
= ::GetDC(mWnd
);
1067 double heightInches
= ::GetDeviceCaps(dc
, VERTSIZE
)/MM_PER_INCH_FLOAT
;
1068 int heightPx
= ::GetDeviceCaps(dc
, VERTRES
);
1069 ::ReleaseDC(mWnd
, dc
);
1070 if (heightInches
< 0.25) {
1071 // Something's broken
1074 return float(heightPx
/heightInches
);
1077 nsWindow
* nsWindow::GetParentWindow(PRBool aIncludeOwner
)
1079 if (mIsTopWidgetWindow
) {
1080 // Must use a flag instead of mWindowType to tell if the window is the
1081 // owned by the topmost widget, because a child window can be embedded inside
1082 // a HWND which is not associated with a nsIWidget.
1086 // If this widget has already been destroyed, pretend we have no parent.
1087 // This corresponds to code in Destroy which removes the destroyed
1088 // widget from its parent's child list.
1089 if (mInDtor
|| mOnDestroyCalled
)
1093 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1094 // root owner. aIncludeOwner set to false implies the search will stop at the
1095 // true parent (default).
1096 nsWindow
* widget
= nsnull
;
1099 HWND parent
= ::GetParent(mWnd
);
1101 HWND parent
= nsnull
;
1103 parent
= ::GetParent(mWnd
);
1105 parent
= ::GetAncestor(mWnd
, GA_PARENT
);
1108 widget
= GetNSWindowPtr(parent
);
1110 // If the widget is in the process of being destroyed then
1112 if (widget
->mInDtor
) {
1122 /**************************************************************
1124 * SECTION: nsIWidget::Show
1126 * Hide or show this component.
1128 **************************************************************/
1130 NS_METHOD
nsWindow::Show(PRBool bState
)
1132 #if defined(MOZ_SPLASHSCREEN)
1133 // we're about to show the first toplevel window,
1134 // so kill off any splash screen if we had one
1135 nsSplashScreen
*splash
= nsSplashScreen::Get();
1136 if (splash
&& splash
->IsOpen() && mWnd
&& bState
&&
1137 (mWindowType
== eWindowType_toplevel
||
1138 mWindowType
== eWindowType_dialog
||
1139 mWindowType
== eWindowType_popup
))
1145 #ifdef NS_FUNCTION_TIMER
1146 static bool firstShow
= true;
1148 (mWindowType
== eWindowType_toplevel
||
1149 mWindowType
== eWindowType_dialog
||
1150 mWindowType
== eWindowType_popup
))
1153 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1157 PRBool wasVisible
= mIsVisible
;
1158 // Set the status now so that anyone asking during ShowWindow or
1159 // SetWindowPos would get the correct answer.
1160 mIsVisible
= bState
;
1162 if (!mIsVisible
&& wasVisible
) {
1163 ClearCachedResources();
1168 if (!wasVisible
&& mWindowType
== eWindowType_toplevel
) {
1169 switch (mSizeMode
) {
1171 case nsSizeMode_Fullscreen
:
1172 ::SetForegroundWindow(mWnd
);
1173 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1174 MakeFullScreen(TRUE
);
1177 case nsSizeMode_Maximized
:
1178 ::SetForegroundWindow(mWnd
);
1179 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1181 // use default for nsSizeMode_Minimized on Windows CE
1183 case nsSizeMode_Maximized
:
1184 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1186 case nsSizeMode_Minimized
:
1187 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
1191 if (CanTakeFocus()) {
1193 ::SetForegroundWindow(mWnd
);
1195 ::ShowWindow(mWnd
, SW_SHOWNORMAL
);
1197 // Place the window behind the foreground window
1198 // (as long as it is not topmost)
1199 HWND wndAfter
= ::GetForegroundWindow();
1201 wndAfter
= HWND_BOTTOM
;
1202 else if (GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
1203 wndAfter
= HWND_TOP
;
1204 ::SetWindowPos(mWnd
, wndAfter
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOSIZE
|
1205 SWP_NOMOVE
| SWP_NOACTIVATE
);
1211 DWORD flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_SHOWWINDOW
;
1213 flags
|= SWP_NOZORDER
;
1215 if (mWindowType
== eWindowType_popup
) {
1217 // ensure popups are the topmost of the TOPMOST
1218 // layer. Remember not to set the SWP_NOZORDER
1219 // flag as that might allow the taskbar to overlap
1220 // the popup. However on windows ce, we need to
1221 // activate the popup or clicks will not be sent.
1222 flags
|= SWP_NOACTIVATE
;
1224 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
1225 ::SetWindowPos(mWnd
, owner
? 0 : HWND_TOPMOST
, 0, 0, 0, 0, flags
);
1228 if (mWindowType
== eWindowType_dialog
&& !CanTakeFocus())
1229 flags
|= SWP_NOACTIVATE
;
1231 ::SetWindowPos(mWnd
, HWND_TOP
, 0, 0, 0, 0, flags
);
1236 if (!wasVisible
&& (mWindowType
== eWindowType_toplevel
|| mWindowType
== eWindowType_dialog
)) {
1237 // when a toplevel window or dialog is shown, initialize the UI state
1238 ::SendMessageW(mWnd
, WM_CHANGEUISTATE
, MAKEWPARAM(UIS_INITIALIZE
, UISF_HIDEFOCUS
| UISF_HIDEACCEL
), 0);
1242 if (mWindowType
!= eWindowType_dialog
) {
1243 ::ShowWindow(mWnd
, SW_HIDE
);
1245 ::SetWindowPos(mWnd
, 0, 0, 0, 0, 0, SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
|
1246 SWP_NOZORDER
| SWP_NOACTIVATE
);
1252 if (!wasVisible
&& bState
)
1253 Invalidate(PR_FALSE
);
1259 /**************************************************************
1261 * SECTION: nsIWidget::IsVisible
1263 * Returns the visibility state.
1265 **************************************************************/
1267 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1268 NS_METHOD
nsWindow::IsVisible(PRBool
& bState
)
1270 bState
= mIsVisible
;
1274 /**************************************************************
1276 * SECTION: Window clipping utilities
1278 * Used in Size and Move operations for setting the proper
1279 * window clipping regions for window transparency.
1281 **************************************************************/
1283 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1284 // transparency. These routines are called on size and move operations.
1285 void nsWindow::ClearThemeRegion()
1288 if (nsUXThemeData::sIsVistaOrLater
&& !HasGlass() &&
1289 (mWindowType
== eWindowType_popup
&& !IsPopupWithTitleBar() &&
1290 (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
))) {
1291 SetWindowRgn(mWnd
, NULL
, false);
1296 void nsWindow::SetThemeRegion()
1299 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1300 // for other window types as needed. The regions are applied generically to the base window
1301 // so default constants are used for part and state. At some point we might need part and
1302 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1303 // change shape based on state haven't come up.
1304 if (nsUXThemeData::sIsVistaOrLater
&& !HasGlass() &&
1305 (mWindowType
== eWindowType_popup
&& !IsPopupWithTitleBar() &&
1306 (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
))) {
1308 RECT rect
= {0,0,mBounds
.width
,mBounds
.height
};
1310 HDC dc
= ::GetDC(mWnd
);
1311 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip
), dc
, TTP_STANDARD
, TS_NORMAL
, &rect
, &hRgn
);
1313 if (!SetWindowRgn(mWnd
, hRgn
, false)) // do not delete or alter hRgn if accepted.
1316 ::ReleaseDC(mWnd
, dc
);
1321 /**************************************************************
1323 * SECTION: nsIWidget::RegisterTouchWindow,
1324 * nsIWidget::UnregisterTouchWindow, and helper functions
1326 * Used to register the native window to receive touch events
1328 **************************************************************/
1330 NS_METHOD
nsWindow::RegisterTouchWindow() {
1331 mTouchWindow
= PR_TRUE
;
1333 mGesture
.RegisterTouchWindow(mWnd
);
1334 ::EnumChildWindows(mWnd
, nsWindow::RegisterTouchForDescendants
, 0);
1339 NS_METHOD
nsWindow::UnregisterTouchWindow() {
1340 mTouchWindow
= PR_FALSE
;
1342 mGesture
.UnregisterTouchWindow(mWnd
);
1343 ::EnumChildWindows(mWnd
, nsWindow::UnregisterTouchForDescendants
, 0);
1349 BOOL CALLBACK
nsWindow::RegisterTouchForDescendants(HWND aWnd
, LPARAM aMsg
) {
1350 nsWindow
* win
= GetNSWindowPtr(aWnd
);
1352 win
->mGesture
.RegisterTouchWindow(aWnd
);
1356 BOOL CALLBACK
nsWindow::UnregisterTouchForDescendants(HWND aWnd
, LPARAM aMsg
) {
1357 nsWindow
* win
= GetNSWindowPtr(aWnd
);
1359 win
->mGesture
.UnregisterTouchWindow(aWnd
);
1364 /**************************************************************
1366 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1367 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1369 * Repositioning and sizing a window.
1371 **************************************************************/
1373 // Move this component
1374 NS_METHOD
nsWindow::Move(PRInt32 aX
, PRInt32 aY
)
1376 if (mWindowType
== eWindowType_toplevel
||
1377 mWindowType
== eWindowType_dialog
) {
1378 SetSizeMode(nsSizeMode_Normal
);
1380 // Check to see if window needs to be moved first
1381 // to avoid a costly call to SetWindowPos. This check
1382 // can not be moved to the calling code in nsView, because
1383 // some platforms do not position child windows correctly
1385 // Only perform this check for non-popup windows, since the positioning can
1386 // in fact change even when the x/y do not. We always need to perform the
1387 // check. See bug #97805 for details.
1388 if (mWindowType
!= eWindowType_popup
&& (mBounds
.x
== aX
) && (mBounds
.y
== aY
))
1390 // Nothing to do, since it is already positioned correctly.
1399 // complain if a window is moved offscreen (legal, but potentially worrisome)
1400 if (mIsTopWidgetWindow
) { // only a problem for top-level windows
1401 // Make sure this window is actually on the screen before we move it
1402 // XXX: Needs multiple monitor support
1403 HDC dc
= ::GetDC(mWnd
);
1405 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1407 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &workArea
, 0);
1408 // no annoying assertions. just mention the issue.
1409 if (aX
< 0 || aX
>= workArea
.right
|| aY
< 0 || aY
>= workArea
.bottom
)
1410 printf("window moved to offscreen position\n");
1412 ::ReleaseDC(mWnd
, dc
);
1417 VERIFY(::SetWindowPos(mWnd
, NULL
, aX
, aY
, 0, 0,
1418 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOSIZE
));
1424 // Resize this component
1425 NS_METHOD
nsWindow::Resize(PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1427 NS_ASSERTION((aWidth
>=0 ) , "Negative width passed to nsWindow::Resize");
1428 NS_ASSERTION((aHeight
>=0 ), "Negative height passed to nsWindow::Resize");
1430 // Avoid unnecessary resizing calls
1431 if (mBounds
.width
== aWidth
&& mBounds
.height
== aHeight
&& !aRepaint
)
1435 if (eTransparencyTransparent
== mTransparencyMode
)
1436 ResizeTranslucentWindow(aWidth
, aHeight
);
1439 // Set cached value for lightweight and printing
1440 mBounds
.width
= aWidth
;
1441 mBounds
.height
= aHeight
;
1444 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOMOVE
;
1448 flags
|= SWP_NOREDRAW
;
1453 VERIFY(::SetWindowPos(mWnd
, NULL
, 0, 0, aWidth
, GetHeight(aHeight
), flags
));
1458 Invalidate(PR_FALSE
);
1463 // Resize this component
1464 NS_METHOD
nsWindow::Resize(PRInt32 aX
, PRInt32 aY
, PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1466 NS_ASSERTION((aWidth
>=0 ), "Negative width passed to nsWindow::Resize");
1467 NS_ASSERTION((aHeight
>=0 ), "Negative height passed to nsWindow::Resize");
1469 // Avoid unnecessary resizing calls
1470 if (mBounds
.x
== aX
&& mBounds
.y
== aY
&&
1471 mBounds
.width
== aWidth
&& mBounds
.height
== aHeight
&& !aRepaint
)
1475 if (eTransparencyTransparent
== mTransparencyMode
)
1476 ResizeTranslucentWindow(aWidth
, aHeight
);
1479 // Set cached value for lightweight and printing
1482 mBounds
.width
= aWidth
;
1483 mBounds
.height
= aHeight
;
1486 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
1489 flags
|= SWP_NOREDRAW
;
1494 VERIFY(::SetWindowPos(mWnd
, NULL
, aX
, aY
, aWidth
, GetHeight(aHeight
), flags
));
1499 Invalidate(PR_FALSE
);
1504 // Resize the client area and position the widget within it's parent
1505 NS_METHOD
nsWindow::ResizeClient(PRInt32 aX
, PRInt32 aY
, PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1507 NS_ASSERTION((aWidth
>=0) , "Negative width passed to ResizeClient");
1508 NS_ASSERTION((aHeight
>=0), "Negative height passed to ResizeClient");
1510 // Adjust our existing window bounds, based on the new client dims.
1512 GetClientRect(mWnd
, &client
);
1513 nsIntPoint
dims(client
.right
- client
.left
, client
.bottom
- client
.top
);
1514 aWidth
= mBounds
.width
+ (aWidth
- dims
.x
);
1515 aHeight
= mBounds
.height
+ (aHeight
- dims
.y
);
1520 GetScreenBounds(bounds
);
1523 return Resize(aX
, aY
, aWidth
, aHeight
, aRepaint
);
1525 return Resize(aWidth
, aHeight
, aRepaint
);
1530 nsWindow::BeginResizeDrag(nsGUIEvent
* aEvent
, PRInt32 aHorizontal
, PRInt32 aVertical
)
1532 NS_ENSURE_ARG_POINTER(aEvent
);
1534 if (aEvent
->eventStructType
!= NS_MOUSE_EVENT
) {
1535 // you can only begin a resize drag with a mouse event
1536 return NS_ERROR_INVALID_ARG
;
1539 nsMouseEvent
* mouseEvent
= static_cast<nsMouseEvent
*>(aEvent
);
1540 if (mouseEvent
->button
!= nsMouseEvent::eLeftButton
) {
1541 // you can only begin a resize drag with the left mouse button
1542 return NS_ERROR_INVALID_ARG
;
1545 // work out what sizemode we're talking about
1547 if (aVertical
< 0) {
1548 if (aHorizontal
< 0) {
1549 syscommand
= SC_SIZE
| WMSZ_TOPLEFT
;
1550 } else if (aHorizontal
== 0) {
1551 syscommand
= SC_SIZE
| WMSZ_TOP
;
1553 syscommand
= SC_SIZE
| WMSZ_TOPRIGHT
;
1555 } else if (aVertical
== 0) {
1556 if (aHorizontal
< 0) {
1557 syscommand
= SC_SIZE
| WMSZ_LEFT
;
1558 } else if (aHorizontal
== 0) {
1559 return NS_ERROR_INVALID_ARG
;
1561 syscommand
= SC_SIZE
| WMSZ_RIGHT
;
1564 if (aHorizontal
< 0) {
1565 syscommand
= SC_SIZE
| WMSZ_BOTTOMLEFT
;
1566 } else if (aHorizontal
== 0) {
1567 syscommand
= SC_SIZE
| WMSZ_BOTTOM
;
1569 syscommand
= SC_SIZE
| WMSZ_BOTTOMRIGHT
;
1573 // resizing doesn't work if the mouse is already captured
1574 CaptureMouse(PR_FALSE
);
1576 // find the top-level window
1577 HWND toplevelWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
1579 // tell Windows to start the resize
1580 ::PostMessage(toplevelWnd
, WM_SYSCOMMAND
, syscommand
,
1581 POINTTOPOINTS(aEvent
->refPoint
));
1586 /**************************************************************
1588 * SECTION: Window Z-order and state.
1590 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1591 * nsIWidget::ConstrainPosition
1593 * Z-order, positioning, restore, minimize, and maximize.
1595 **************************************************************/
1597 // Position the window behind the given window
1598 NS_METHOD
nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement
,
1599 nsIWidget
*aWidget
, PRBool aActivate
)
1601 HWND behind
= HWND_TOP
;
1602 if (aPlacement
== eZPlacementBottom
)
1603 behind
= HWND_BOTTOM
;
1604 else if (aPlacement
== eZPlacementBelow
&& aWidget
)
1605 behind
= (HWND
)aWidget
->GetNativeData(NS_NATIVE_WINDOW
);
1606 UINT flags
= SWP_NOMOVE
| SWP_NOREPOSITION
| SWP_NOSIZE
;
1608 flags
|= SWP_NOACTIVATE
;
1610 if (!CanTakeFocus() && behind
== HWND_TOP
)
1612 // Can't place the window to top so place it behind the foreground window
1613 // (as long as it is not topmost)
1614 HWND wndAfter
= ::GetForegroundWindow();
1616 behind
= HWND_BOTTOM
;
1617 else if (!(GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
1619 flags
|= SWP_NOACTIVATE
;
1622 ::SetWindowPos(mWnd
, behind
, 0, 0, 0, 0, flags
);
1626 // Maximize, minimize or restore the window.
1627 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1628 NS_IMETHODIMP
nsWindow::SetSizeMode(PRInt32 aMode
) {
1632 // Let's not try and do anything if we're already in that state.
1633 // (This is needed to prevent problems when calling window.minimize(), which
1634 // calls us directly, and then the OS triggers another call to us.)
1635 if (aMode
== mSizeMode
)
1638 // save the requested state
1639 rv
= nsBaseWidget::SetSizeMode(aMode
);
1640 if (NS_SUCCEEDED(rv
) && mIsVisible
) {
1644 case nsSizeMode_Fullscreen
:
1648 case nsSizeMode_Maximized
:
1652 case nsSizeMode_Minimized
:
1653 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1654 // keeps the window active in the tray. So after the window is minimized,
1655 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1656 // we will do some additional processing to get the active window set right.
1657 // If sTrimOnMinimize is set, we let windows handle minimization normally
1658 // using SW_MINIMIZE.
1659 mode
= sTrimOnMinimize
? SW_MINIMIZE
: SW_SHOWMINIMIZED
;
1665 ::ShowWindow(mWnd
, mode
);
1666 // we dispatch an activate event here to ensure that the right child window
1668 if (mode
== SW_RESTORE
|| mode
== SW_MAXIMIZE
)
1669 DispatchFocusToTopLevelWindow(NS_ACTIVATE
);
1673 #endif // !defined(WINCE)
1675 // Constrain a potential move to fit onscreen
1676 NS_METHOD
nsWindow::ConstrainPosition(PRBool aAllowSlop
,
1677 PRInt32
*aX
, PRInt32
*aY
)
1679 if (!mIsTopWidgetWindow
) // only a problem for top-level windows
1682 PRBool doConstrain
= PR_FALSE
; // whether we have enough info to do anything
1684 /* get our playing field. use the current screen, or failing that
1685 for any reason, use device caps for the default screen. */
1688 nsCOMPtr
<nsIScreenManager
> screenmgr
= do_GetService(sScreenManagerContractID
);
1690 nsCOMPtr
<nsIScreen
> screen
;
1691 PRInt32 left
, top
, width
, height
;
1693 // zero size rects confuse the screen manager
1694 width
= mBounds
.width
> 0 ? mBounds
.width
: 1;
1695 height
= mBounds
.height
> 0 ? mBounds
.height
: 1;
1696 screenmgr
->ScreenForRect(*aX
, *aY
, width
, height
,
1697 getter_AddRefs(screen
));
1699 if (mSizeMode
!= nsSizeMode_Fullscreen
) {
1700 // For normalized windows, use the desktop work area.
1701 screen
->GetAvailRect(&left
, &top
, &width
, &height
);
1703 // For full screen windows, use the desktop.
1704 screen
->GetRect(&left
, &top
, &width
, &height
);
1706 screenRect
.left
= left
;
1707 screenRect
.right
= left
+width
;
1708 screenRect
.top
= top
;
1709 screenRect
.bottom
= top
+height
;
1710 doConstrain
= PR_TRUE
;
1714 HDC dc
= ::GetDC(mWnd
);
1716 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1717 if (mSizeMode
!= nsSizeMode_Fullscreen
) {
1718 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &screenRect
, 0);
1720 screenRect
.left
= screenRect
.top
= 0;
1721 screenRect
.right
= GetSystemMetrics(SM_CXFULLSCREEN
);
1722 screenRect
.bottom
= GetSystemMetrics(SM_CYFULLSCREEN
);
1724 doConstrain
= PR_TRUE
;
1726 ::ReleaseDC(mWnd
, dc
);
1732 if (*aX
< screenRect
.left
- mBounds
.width
+ kWindowPositionSlop
)
1733 *aX
= screenRect
.left
- mBounds
.width
+ kWindowPositionSlop
;
1734 else if (*aX
>= screenRect
.right
- kWindowPositionSlop
)
1735 *aX
= screenRect
.right
- kWindowPositionSlop
;
1737 if (*aY
< screenRect
.top
- mBounds
.height
+ kWindowPositionSlop
)
1738 *aY
= screenRect
.top
- mBounds
.height
+ kWindowPositionSlop
;
1739 else if (*aY
>= screenRect
.bottom
- kWindowPositionSlop
)
1740 *aY
= screenRect
.bottom
- kWindowPositionSlop
;
1744 if (*aX
< screenRect
.left
)
1745 *aX
= screenRect
.left
;
1746 else if (*aX
>= screenRect
.right
- mBounds
.width
)
1747 *aX
= screenRect
.right
- mBounds
.width
;
1749 if (*aY
< screenRect
.top
)
1750 *aY
= screenRect
.top
;
1751 else if (*aY
>= screenRect
.bottom
- mBounds
.height
)
1752 *aY
= screenRect
.bottom
- mBounds
.height
;
1758 /**************************************************************
1760 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1762 * Enabling and disabling the widget.
1764 **************************************************************/
1766 // Enable/disable this component
1767 NS_METHOD
nsWindow::Enable(PRBool bState
)
1770 ::EnableWindow(mWnd
, bState
);
1775 // Return the current enable state
1776 NS_METHOD
nsWindow::IsEnabled(PRBool
*aState
)
1778 NS_ENSURE_ARG_POINTER(aState
);
1781 *aState
= !mWnd
|| (::IsWindowEnabled(mWnd
) && ::IsWindowEnabled(::GetAncestor(mWnd
, GA_ROOT
)));
1783 *aState
= !mWnd
|| (::IsWindowEnabled(mWnd
) && ::IsWindowEnabled(mWnd
));
1790 /**************************************************************
1792 * SECTION: nsIWidget::SetFocus
1794 * Give the focus to this widget.
1796 **************************************************************/
1798 NS_METHOD
nsWindow::SetFocus(PRBool aRaise
)
1801 #ifdef WINSTATE_DEBUG_OUTPUT
1802 if (mWnd
== GetTopLevelHWND(mWnd
))
1803 printf("*** SetFocus: [ top] raise=%d\n", aRaise
);
1805 printf("*** SetFocus: [child] raise=%d\n", aRaise
);
1807 // Uniconify, if necessary
1808 HWND toplevelWnd
= GetTopLevelHWND(mWnd
);
1809 if (aRaise
&& ::IsIconic(toplevelWnd
)) {
1810 ::ShowWindow(toplevelWnd
, SW_RESTORE
);
1818 /**************************************************************
1822 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1823 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1825 * Bound calculations.
1827 **************************************************************/
1829 // Return the window's full dimensions in screen coordinates.
1830 // If the window has a parent, converts the origin to an offset
1831 // of the parent's screen origin.
1832 NS_METHOD
nsWindow::GetBounds(nsIntRect
&aRect
)
1836 VERIFY(::GetWindowRect(mWnd
, &r
));
1839 aRect
.width
= r
.right
- r
.left
;
1840 aRect
.height
= r
.bottom
- r
.top
;
1842 // chrome on parent:
1843 // ___ 5,5 (chrome start)
1844 // | ____ 10,10 (client start)
1845 // | | ____ 20,20 (child start)
1847 // 20,20 - 5,5 = 15,15 (??)
1848 // minus GetClientOffset:
1849 // 15,15 - 5,5 = 10,10
1851 // no chrome on parent:
1852 // ______ 10,10 (win start)
1853 // | ____ 20,20 (child start)
1855 // 20,20 - 10,10 = 10,10
1857 // walking the chain:
1858 // ___ 5,5 (chrome start)
1859 // | ___ 10,10 (client start)
1860 // | | ___ 20,20 (child start)
1861 // | | | __ 30,30 (child start)
1863 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1864 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1865 // minus GetClientOffset:
1866 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1868 // convert coordinates if parent exists
1869 HWND parent
= ::GetParent(mWnd
);
1872 VERIFY(::GetWindowRect(parent
, &pr
));
1875 // adjust for chrome
1876 nsWindow
* pWidget
= static_cast<nsWindow
*>(GetParent());
1877 if (pWidget
&& pWidget
->IsTopLevelWidget()) {
1878 nsIntPoint clientOffset
= pWidget
->GetClientOffset();
1879 r
.left
-= clientOffset
.x
;
1880 r
.top
-= clientOffset
.y
;
1892 // Get this component dimension
1893 NS_METHOD
nsWindow::GetClientBounds(nsIntRect
&aRect
)
1897 VERIFY(::GetClientRect(mWnd
, &r
));
1902 aRect
.width
= r
.right
- r
.left
;
1903 aRect
.height
= r
.bottom
- r
.top
;
1906 aRect
.SetRect(0,0,0,0);
1911 // Like GetBounds, but don't offset by the parent
1912 NS_METHOD
nsWindow::GetScreenBounds(nsIntRect
&aRect
)
1916 VERIFY(::GetWindowRect(mWnd
, &r
));
1918 aRect
.width
= r
.right
- r
.left
;
1919 aRect
.height
= r
.bottom
- r
.top
;
1928 // return the x,y offset of the client area from the origin
1929 // of the window. If the window is borderless returns (0,0).
1930 nsIntPoint
nsWindow::GetClientOffset()
1933 return nsIntPoint(0, 0);
1937 GetWindowRect(mWnd
, &r1
);
1938 nsIntPoint pt
= WidgetToScreenOffset();
1939 return nsIntPoint(pt
.x
- r1
.left
, pt
.y
- r1
.top
);
1943 nsWindow::SetDrawsInTitlebar(PRBool aState
)
1945 nsWindow
* window
= GetTopLevelWindow(PR_TRUE
);
1946 if (window
&& window
!= this) {
1947 return window
->SetDrawsInTitlebar(aState
);
1951 // left, top, right, bottom for nsIntMargin
1952 nsIntMargin
margins(-1, 0, -1, -1);
1953 SetNonClientMargins(margins
);
1956 nsIntMargin
margins(-1, -1, -1, -1);
1957 SetNonClientMargins(margins
);
1962 nsWindow::GetNonClientMargins(nsIntMargin
&margins
)
1964 nsWindow
* window
= GetTopLevelWindow(PR_TRUE
);
1965 if (window
&& window
!= this) {
1966 return window
->GetNonClientMargins(margins
);
1969 if (mCustomNonClient
) {
1970 margins
= mNonClientMargins
;
1974 margins
.top
= GetSystemMetrics(SM_CYCAPTION
);
1975 margins
.bottom
= GetSystemMetrics(SM_CYFRAME
);
1976 margins
.top
+= margins
.bottom
;
1977 margins
.left
= margins
.right
= GetSystemMetrics(SM_CYFRAME
);
1983 nsWindow::ResetLayout()
1985 // This will trigger a frame changed event, triggering
1986 // nc calc size and a sizemode gecko event.
1987 SetWindowPos(mWnd
, 0, 0, 0, 0, 0,
1988 SWP_FRAMECHANGED
|SWP_NOACTIVATE
|SWP_NOMOVE
|
1989 SWP_NOOWNERZORDER
|SWP_NOSIZE
|SWP_NOZORDER
);
1991 // If hidden, just send the frame changed event for now.
1995 // Send a gecko size event to trigger reflow.
1996 RECT clientRc
= {0};
1997 GetClientRect(mWnd
, &clientRc
);
1998 nsIntRect
evRect(nsWindowGfx::ToIntRect(clientRc
));
2001 // Invalidate and update
2002 Invalidate(PR_FALSE
);
2005 // Called when the window layout changes: full screen mode transitions,
2006 // theme changes, and composition changes. Calculates the new non-client
2007 // margins and fires off a frame changed event, which triggers an nc calc
2008 // size windows event, kicking the changes in.
2010 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode
, PRBool aReflowWindow
)
2012 if (!mCustomNonClient
)
2015 mNonClientOffset
.top
= mNonClientOffset
.bottom
=
2016 mNonClientOffset
.left
= mNonClientOffset
.right
= 0;
2018 if (aSizeMode
== -1)
2019 aSizeMode
= mSizeMode
;
2021 if (aSizeMode
== nsSizeMode_Minimized
||
2022 aSizeMode
== nsSizeMode_Fullscreen
) {
2023 mCaptionHeight
= mVertResizeMargin
= mHorResizeMargin
= 0;
2027 // Note, for maximized windows, we need to continue to offset the client by
2028 // thick frame margins of a normal window, since windows expects this
2029 // in it's DwmDefWndProc hit testing.
2030 mCaptionHeight
= GetSystemMetrics(SM_CYCAPTION
);
2031 mHorResizeMargin
= GetSystemMetrics(SM_CXFRAME
);
2032 mVertResizeMargin
= GetSystemMetrics(SM_CYFRAME
);
2034 mCaptionHeight
+= mVertResizeMargin
;
2036 // If a margin value is 0, set the offset to the default size of the frame.
2037 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2038 // so that the frame size is equal to the margin value.
2039 if (!mNonClientMargins
.top
)
2040 mNonClientOffset
.top
= mCaptionHeight
;
2041 else if (mNonClientMargins
.top
> 0)
2042 mNonClientOffset
.top
= mCaptionHeight
- mNonClientMargins
.top
;
2044 if (!mNonClientMargins
.left
)
2045 mNonClientOffset
.left
= mHorResizeMargin
;
2046 else if (mNonClientMargins
.left
> 0)
2047 mNonClientOffset
.left
= mHorResizeMargin
- mNonClientMargins
.left
;
2049 if (!mNonClientMargins
.right
)
2050 mNonClientOffset
.right
= mHorResizeMargin
;
2051 else if (mNonClientMargins
.right
> 0)
2052 mNonClientOffset
.right
= mHorResizeMargin
- mNonClientMargins
.right
;
2054 if (!mNonClientMargins
.bottom
)
2055 mNonClientOffset
.bottom
= mVertResizeMargin
;
2056 else if (mNonClientMargins
.bottom
> 0)
2057 mNonClientOffset
.bottom
= mVertResizeMargin
- mNonClientMargins
.bottom
;
2060 if (aSizeMode
== nsSizeMode_Maximized
) {
2061 // Address an issue with auto-hide taskbars which fall behind the window.
2062 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2063 // the taskbar works properly.
2064 MONITORINFO info
= {sizeof(MONITORINFO
)};
2065 if (::GetMonitorInfo(::MonitorFromWindow(mWnd
, MONITOR_DEFAULTTOPRIMARY
),
2068 if (::GetWindowRect(mWnd
, &r
)) {
2069 // Adjust window rect to account for non-client margins.
2070 r
.top
+= mVertResizeMargin
- mNonClientOffset
.top
;
2071 r
.left
+= mHorResizeMargin
- mNonClientOffset
.left
;
2072 r
.bottom
-= mVertResizeMargin
- mNonClientOffset
.bottom
;
2073 r
.right
-= mHorResizeMargin
- mNonClientOffset
.right
;
2074 // Leave the 1 pixel margin if the window covers the monitor.
2075 if (r
.top
<= info
.rcMonitor
.top
&&
2076 r
.left
<= info
.rcMonitor
.left
&&
2077 r
.right
>= info
.rcMonitor
.right
&&
2078 r
.bottom
>= info
.rcMonitor
.bottom
)
2079 mNonClientOffset
.bottom
-= r
.bottom
- info
.rcMonitor
.bottom
+ 1;
2085 if (aReflowWindow
) {
2086 // Force a reflow of content based on the new client
2095 nsWindow::SetNonClientMargins(nsIntMargin
&margins
)
2097 if (!mIsTopWidgetWindow
||
2098 mBorderStyle
& eBorderStyle_none
||
2100 return NS_ERROR_INVALID_ARG
;
2102 // Request for a reset
2103 if (margins
.top
== -1 && margins
.left
== -1 &&
2104 margins
.right
== -1 && margins
.bottom
== -1) {
2105 mCustomNonClient
= PR_FALSE
;
2106 mNonClientMargins
= margins
;
2107 // Force a reflow of content based on the new client
2113 if (margins
.top
< -1 || margins
.bottom
< -1 ||
2114 margins
.left
< -1 || margins
.right
< -1)
2115 return NS_ERROR_INVALID_ARG
;
2117 mNonClientMargins
= margins
;
2118 mCustomNonClient
= PR_TRUE
;
2119 if (!UpdateNonClientMargins()) {
2120 NS_WARNING("UpdateNonClientMargins failed!");
2128 nsWindow::InvalidateNonClientRegion()
2130 // +-+-----------------------+-+
2131 // | | app non-client chrome | |
2132 // | +-----------------------+ |
2133 // | | app client chrome | | }
2134 // | +-----------------------+ | }
2135 // | | app content | | } area we don't want to invalidate
2136 // | +-----------------------+ | }
2137 // | | app client chrome | | }
2138 // | +-----------------------+ |
2139 // +---------------------------+ <
2140 // ^ ^ windows non-client chrome
2141 // client area = app *
2143 GetWindowRect(mWnd
, &rect
);
2144 MapWindowPoints(NULL
, mWnd
, (LPPOINT
)&rect
, 2);
2145 HRGN winRgn
= CreateRectRgnIndirect(&rect
);
2147 // Subtract app client chrome and app content leaving
2148 // windows non-client chrome and app non-client chrome
2150 GetWindowRect(mWnd
, &rect
);
2151 rect
.top
+= mCaptionHeight
;
2152 rect
.right
-= mHorResizeMargin
;
2153 rect
.bottom
-= mHorResizeMargin
;
2154 rect
.left
+= mVertResizeMargin
;
2155 MapWindowPoints(NULL
, mWnd
, (LPPOINT
)&rect
, 2);
2156 HRGN clientRgn
= CreateRectRgnIndirect(&rect
);
2157 CombineRgn(winRgn
, winRgn
, clientRgn
, RGN_DIFF
);
2158 DeleteObject(clientRgn
);
2160 // triggers ncpaint and paint events for the two areas
2161 RedrawWindow(mWnd
, NULL
, winRgn
, RDW_FRAME
|RDW_INVALIDATE
);
2162 DeleteObject(winRgn
);
2166 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion
)
2170 if (aRegion
== (HRGN
)1) { // undocumented value indicating a full refresh
2171 GetWindowRect(mWnd
, &rect
);
2172 rgn
= CreateRectRgnIndirect(&rect
);
2176 GetClientRect(mWnd
, &rect
);
2177 MapWindowPoints(mWnd
, NULL
, (LPPOINT
)&rect
, 2);
2178 HRGN nonClientRgn
= CreateRectRgnIndirect(&rect
);
2179 CombineRgn(rgn
, rgn
, nonClientRgn
, RGN_DIFF
);
2180 DeleteObject(nonClientRgn
);
2184 /**************************************************************
2186 * SECTION: nsIWidget::SetBackgroundColor
2188 * Sets the window background paint color.
2190 **************************************************************/
2192 NS_METHOD
nsWindow::SetBackgroundColor(const nscolor
&aColor
)
2194 nsBaseWidget::SetBackgroundColor(aColor
);
2197 ::DeleteObject(mBrush
);
2199 mBrush
= ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground
));
2202 ::SetClassLongPtrW(mWnd
, GCLP_HBRBACKGROUND
, (LONG_PTR
)mBrush
);
2208 /**************************************************************
2210 * SECTION: nsIWidget::SetCursor
2212 * SetCursor and related utilities for manging cursor state.
2214 **************************************************************/
2216 // Set this component cursor
2217 NS_METHOD
nsWindow::SetCursor(nsCursor aCursor
)
2219 // Only change cursor if it's changing
2221 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2222 //XXX If we want this optimization we need a better way to do it.
2223 //if (aCursor != mCursor) {
2224 HCURSOR newCursor
= NULL
;
2227 case eCursor_select
:
2228 newCursor
= ::LoadCursor(NULL
, IDC_IBEAM
);
2232 newCursor
= ::LoadCursor(NULL
, IDC_WAIT
);
2235 case eCursor_hyperlink
:
2237 newCursor
= ::LoadCursor(NULL
, IDC_HAND
);
2241 case eCursor_standard
:
2242 newCursor
= ::LoadCursor(NULL
, IDC_ARROW
);
2245 case eCursor_n_resize
:
2246 case eCursor_s_resize
:
2247 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
2250 case eCursor_w_resize
:
2251 case eCursor_e_resize
:
2252 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
2255 case eCursor_nw_resize
:
2256 case eCursor_se_resize
:
2257 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
2260 case eCursor_ne_resize
:
2261 case eCursor_sw_resize
:
2262 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
2265 case eCursor_crosshair
:
2266 newCursor
= ::LoadCursor(NULL
, IDC_CROSS
);
2270 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
2274 newCursor
= ::LoadCursor(NULL
, IDC_HELP
);
2277 case eCursor_copy
: // CSS3
2278 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COPY
));
2282 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ALIAS
));
2286 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_CELL
));
2290 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRAB
));
2293 case eCursor_grabbing
:
2294 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRABBING
));
2297 case eCursor_spinning
:
2298 newCursor
= ::LoadCursor(NULL
, IDC_APPSTARTING
);
2301 case eCursor_context_menu
:
2302 // XXX this CSS3 cursor needs to be implemented
2305 case eCursor_zoom_in
:
2306 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMIN
));
2309 case eCursor_zoom_out
:
2310 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMOUT
));
2313 case eCursor_not_allowed
:
2314 case eCursor_no_drop
:
2315 newCursor
= ::LoadCursor(NULL
, IDC_NO
);
2318 case eCursor_col_resize
:
2319 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COLRESIZE
));
2322 case eCursor_row_resize
:
2323 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ROWRESIZE
));
2326 case eCursor_vertical_text
:
2327 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_VERTICALTEXT
));
2330 case eCursor_all_scroll
:
2331 // XXX not 100% appropriate perhaps
2332 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
2335 case eCursor_nesw_resize
:
2336 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
2339 case eCursor_nwse_resize
:
2340 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
2343 case eCursor_ns_resize
:
2344 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
2347 case eCursor_ew_resize
:
2348 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
2352 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_NONE
));
2356 NS_ERROR("Invalid cursor type");
2360 if (NULL
!= newCursor
) {
2362 HCURSOR oldCursor
= ::SetCursor(newCursor
);
2364 if (sHCursor
== oldCursor
) {
2365 NS_IF_RELEASE(sCursorImgContainer
);
2366 if (sHCursor
!= NULL
)
2367 ::DestroyIcon(sHCursor
);
2375 // Setting the actual cursor
2376 NS_IMETHODIMP
nsWindow::SetCursor(imgIContainer
* aCursor
,
2377 PRUint32 aHotspotX
, PRUint32 aHotspotY
)
2379 if (sCursorImgContainer
== aCursor
&& sHCursor
) {
2380 ::SetCursor(sHCursor
);
2388 rv
= aCursor
->GetWidth(&width
);
2389 NS_ENSURE_SUCCESS(rv
, rv
);
2390 rv
= aCursor
->GetHeight(&height
);
2391 NS_ENSURE_SUCCESS(rv
, rv
);
2393 // Reject cursors greater than 128 pixels in either direction, to prevent
2395 // XXX ideally we should rescale. Also, we could modify the API to
2396 // allow trusted content to set larger cursors.
2397 if (width
> 128 || height
> 128)
2398 return NS_ERROR_NOT_AVAILABLE
;
2401 rv
= nsWindowGfx::CreateIcon(aCursor
, PR_TRUE
, aHotspotX
, aHotspotY
, &cursor
);
2402 NS_ENSURE_SUCCESS(rv
, rv
);
2404 mCursor
= nsCursor(-1);
2405 ::SetCursor(cursor
);
2407 NS_IF_RELEASE(sCursorImgContainer
);
2408 sCursorImgContainer
= aCursor
;
2409 NS_ADDREF(sCursorImgContainer
);
2411 if (sHCursor
!= NULL
)
2412 ::DestroyIcon(sHCursor
);
2418 /**************************************************************
2420 * SECTION: nsIWidget::Get/SetTransparencyMode
2422 * Manage the transparency mode of the top-level window
2423 * containing this widget.
2425 **************************************************************/
2428 nsTransparencyMode
nsWindow::GetTransparencyMode()
2430 return GetTopLevelWindow(PR_TRUE
)->GetWindowTranslucencyInner();
2433 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode
)
2435 GetTopLevelWindow(PR_TRUE
)->SetWindowTranslucencyInner(aMode
);
2438 void nsWindow::UpdatePossiblyTransparentRegion(const nsIntRegion
&aDirtyRegion
,
2439 const nsIntRegion
&aPossiblyTransparentRegion
) {
2440 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2444 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2445 nsWindow
* topWindow
= GetNSWindowPtr(hWnd
);
2450 mPossiblyTransparentRegion
.Sub(mPossiblyTransparentRegion
, aDirtyRegion
);
2451 mPossiblyTransparentRegion
.Or(mPossiblyTransparentRegion
, aPossiblyTransparentRegion
);
2453 nsIntRect clientBounds
;
2454 topWindow
->GetClientBounds(clientBounds
);
2455 nsIntRegion opaqueRegion
;
2456 opaqueRegion
.Sub(clientBounds
, mPossiblyTransparentRegion
);
2458 MARGINS margins
= { 0, 0, 0, 0 };
2459 DWORD_PTR dwStyle
= ::GetWindowLongPtrW(hWnd
, GWL_STYLE
);
2461 // If there is no opaque region or hidechrome=true, set margins
2462 // to support a full sheet of glass.
2463 if (opaqueRegion
.IsEmpty() || mHideChrome
) {
2464 // Comments in MSDN indicate all values must be set to -1
2465 margins
.cxLeftWidth
= margins
.cxRightWidth
=
2466 margins
.cyTopHeight
= margins
.cyBottomHeight
= -1;
2468 // Find the largest rectangle and use that to calculate the inset
2469 nsIntRect largest
= opaqueRegion
.GetLargestRectangle();
2470 margins
.cxLeftWidth
= largest
.x
;
2471 margins
.cxRightWidth
= clientBounds
.width
- largest
.XMost();
2472 margins
.cyBottomHeight
= clientBounds
.height
- largest
.YMost();
2474 // The minimum glass height must be the caption buttons height,
2475 // otherwise the buttons are drawn incorrectly.
2476 margins
.cyTopHeight
= PR_MAX(largest
.y
, mCaptionButtons
.height
);
2479 // Only update glass area if there are changes
2480 if (memcmp(&mGlassMargins
, &margins
, sizeof mGlassMargins
)) {
2481 mGlassMargins
= margins
;
2484 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2487 void nsWindow::UpdateGlass()
2489 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2490 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2491 MARGINS margins
= mGlassMargins
;
2493 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2494 // rendered based on the window style.
2495 // DWMNCRP_ENABLED - The non-client area rendering is
2496 // enabled; the window style is ignored.
2497 DWMNCRENDERINGPOLICY policy
= DWMNCRP_USEWINDOWSTYLE
;
2498 switch (mTransparencyMode
) {
2499 case eTransparencyBorderlessGlass
:
2500 // Only adjust if there is some opaque rectangle
2501 if (margins
.cxLeftWidth
>= 0) {
2502 const PRInt32 kGlassMarginAdjustment
= 2;
2503 margins
.cxLeftWidth
+= kGlassMarginAdjustment
;
2504 margins
.cyTopHeight
+= kGlassMarginAdjustment
;
2505 margins
.cxRightWidth
+= kGlassMarginAdjustment
;
2506 margins
.cyBottomHeight
+= kGlassMarginAdjustment
;
2509 case eTransparencyGlass
:
2510 policy
= DWMNCRP_ENABLED
;
2514 // Extends the window frame behind the client area
2515 if(nsUXThemeData::CheckForCompositor()) {
2516 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd
, &margins
);
2517 nsUXThemeData::dwmSetWindowAttributePtr(hWnd
, DWMWA_NCRENDERING_POLICY
, &policy
, sizeof policy
);
2519 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2523 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2524 void nsWindow::UpdateCaptionButtonsClippingRect()
2526 NS_ASSERTION(mWnd
, "UpdateCaptionButtonsClippingRect called with invalid mWnd.");
2528 RECT captionButtons
;
2529 mCaptionButtonsRoundedRegion
.SetEmpty();
2530 mCaptionButtons
.Empty();
2532 if (!mCustomNonClient
||
2533 mSizeMode
== nsSizeMode_Fullscreen
||
2534 mSizeMode
== nsSizeMode_Minimized
||
2535 !nsUXThemeData::CheckForCompositor() ||
2536 FAILED(nsUXThemeData::dwmGetWindowAttributePtr(mWnd
,
2537 DWMWA_CAPTION_BUTTON_BOUNDS
,
2539 sizeof(captionButtons
)))) {
2543 mCaptionButtons
= nsWindowGfx::ToIntRect(captionButtons
);
2545 // Adjustments to reported area
2546 PRInt32 leftMargin
= (mNonClientMargins
.left
== -1) ? mHorResizeMargin
: mNonClientMargins
.left
;
2548 // "leftMargin - 1" represents the resizer border and an
2549 // one pixel adjustment to hide the semi-transparent highlight.
2550 // The extra width is already excluded when the window is maximized.
2551 mCaptionButtons
.x
-= leftMargin
- 1;
2553 if (mSizeMode
!= nsSizeMode_Maximized
) {
2554 mCaptionButtons
.width
+= leftMargin
- 1;
2555 mCaptionButtons
.height
-= mVertResizeMargin
+ 1;
2557 // Adjustments to the buttons' shift from the edge of the screen,
2558 // plus some apparently transparent drop shadow below them.
2559 mCaptionButtons
.width
-= 2;
2560 mCaptionButtons
.height
-= 3;
2563 // Create a rounded region by shrinking the 2 bottommost pixel rows from
2564 // the rect by 1 and 2 pixels.
2565 // mCaptionButtons: mCaptionButtonsRoundedRegion:
2566 // +-----------+ +-----------+
2569 // +-----------+ +-------+
2570 nsIntRect
round1(mCaptionButtons
.x
, mCaptionButtons
.y
,
2571 mCaptionButtons
.width
, mCaptionButtons
.height
- 2);
2572 nsIntRect
round2(mCaptionButtons
.x
+ 1, mCaptionButtons
.YMost() - 2,
2573 mCaptionButtons
.width
- 2, 1);
2574 nsIntRect
round3(mCaptionButtons
.x
+ 2, mCaptionButtons
.YMost() - 1,
2575 mCaptionButtons
.width
- 4, 1);
2576 mCaptionButtonsRoundedRegion
.Or(mCaptionButtonsRoundedRegion
, round1
);
2577 mCaptionButtonsRoundedRegion
.Or(mCaptionButtonsRoundedRegion
, round2
);
2578 mCaptionButtonsRoundedRegion
.Or(mCaptionButtonsRoundedRegion
, round3
);
2582 /**************************************************************
2584 * SECTION: nsIWidget::HideWindowChrome
2586 * Show or hide window chrome.
2588 **************************************************************/
2590 NS_IMETHODIMP
nsWindow::HideWindowChrome(PRBool aShouldHide
)
2592 HWND hwnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2593 if (!GetNSWindowPtr(hwnd
))
2595 NS_WARNING("Trying to hide window decorations in an embedded context");
2596 return NS_ERROR_FAILURE
;
2599 if (mHideChrome
== aShouldHide
)
2602 DWORD_PTR style
, exStyle
;
2603 mHideChrome
= aShouldHide
;
2605 DWORD_PTR tempStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2606 DWORD_PTR tempExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2608 style
= tempStyle
& ~(WS_CAPTION
| WS_THICKFRAME
);
2609 exStyle
= tempExStyle
& ~(WS_EX_DLGMODALFRAME
| WS_EX_WINDOWEDGE
|
2610 WS_EX_CLIENTEDGE
| WS_EX_STATICEDGE
);
2612 mOldStyle
= tempStyle
;
2613 mOldExStyle
= tempExStyle
;
2616 if (!mOldStyle
|| !mOldExStyle
) {
2617 mOldStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2618 mOldExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2622 exStyle
= mOldExStyle
;
2625 VERIFY_WINDOW_STYLE(style
);
2626 ::SetWindowLongPtrW(hwnd
, GWL_STYLE
, style
);
2627 ::SetWindowLongPtrW(hwnd
, GWL_EXSTYLE
, exStyle
);
2632 /**************************************************************
2634 * SECTION: nsIWidget::Invalidate
2636 * Invalidate an area of the client for painting.
2638 **************************************************************/
2640 // Invalidate this component visible area
2641 NS_METHOD
nsWindow::Invalidate(PRBool aIsSynchronous
)
2645 #ifdef WIDGET_DEBUG_OUTPUT
2646 debug_DumpInvalidate(stdout
,
2650 nsCAutoString("noname"),
2652 #endif // WIDGET_DEBUG_OUTPUT
2654 VERIFY(::InvalidateRect(mWnd
, NULL
, FALSE
));
2656 if (aIsSynchronous
) {
2657 VERIFY(::UpdateWindow(mWnd
));
2663 // Invalidate this component visible area
2664 NS_METHOD
nsWindow::Invalidate(const nsIntRect
& aRect
, PRBool aIsSynchronous
)
2668 #ifdef WIDGET_DEBUG_OUTPUT
2669 debug_DumpInvalidate(stdout
,
2673 nsCAutoString("noname"),
2675 #endif // WIDGET_DEBUG_OUTPUT
2679 rect
.left
= aRect
.x
;
2681 rect
.right
= aRect
.x
+ aRect
.width
;
2682 rect
.bottom
= aRect
.y
+ aRect
.height
;
2684 VERIFY(::InvalidateRect(mWnd
, &rect
, FALSE
));
2686 if (aIsSynchronous
) {
2687 VERIFY(::UpdateWindow(mWnd
));
2694 nsWindow::MakeFullScreen(PRBool aFullScreen
)
2696 #if WINCE_WINDOWS_MOBILE
2699 SetForegroundWindow(mWnd
);
2700 if (nsWindowCE::sMenuBarShown
) {
2702 memset(&sipInfo
, 0, sizeof(SIPINFO
));
2703 sipInfo
.cbSize
= sizeof(SIPINFO
);
2704 if (SipGetInfo(&sipInfo
))
2705 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
),
2706 sipInfo
.rcVisibleDesktop
.bottom
);
2708 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
),
2709 GetSystemMetrics(SM_CYSCREEN
));
2711 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle
, &menuBarRect
) &&
2712 menuBarRect
.top
< rc
.bottom
)
2713 rc
.bottom
= menuBarRect
.top
;
2714 SHFullScreen(mWnd
, SHFS_HIDETASKBAR
| SHFS_HIDESTARTICON
| SHFS_SHOWSIPBUTTON
);
2717 SHFullScreen(mWnd
, SHFS_HIDETASKBAR
| SHFS_HIDESTARTICON
| SHFS_HIDESIPBUTTON
);
2718 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
), GetSystemMetrics(SM_CYSCREEN
));
2722 SHFullScreen(mWnd
, SHFS_SHOWTASKBAR
| SHFS_SHOWSTARTICON
);
2723 SystemParametersInfo(SPI_GETWORKAREA
, 0, &rc
, FALSE
);
2727 mSizeMode
= nsSizeMode_Fullscreen
;
2729 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2730 HideWindowChrome(aFullScreen
);
2731 Resize(rc
.left
, rc
.top
, rc
.right
-rc
.left
, rc
.bottom
-rc
.top
, PR_TRUE
);
2737 mFullscreenMode
= aFullScreen
;
2739 if (mSizeMode
== nsSizeMode_Fullscreen
)
2741 mOldSizeMode
= mSizeMode
;
2742 SetSizeMode(nsSizeMode_Fullscreen
);
2744 SetSizeMode(mOldSizeMode
);
2747 UpdateNonClientMargins();
2749 // Will call hide chrome, reposition window. Note this will
2750 // also cache dimensions for restoration, so it should only
2751 // be called once per fullscreen request.
2752 nsresult rv
= nsBaseWidget::MakeFullScreen(aFullScreen
);
2754 // Let the dom know via web shell window
2755 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
2756 event
.mSizeMode
= mSizeMode
;
2758 DispatchWindowEvent(&event
);
2764 /**************************************************************
2766 * SECTION: nsIWidget::Update
2768 * Force a synchronous repaint of the window.
2770 **************************************************************/
2772 NS_IMETHODIMP
nsWindow::Update()
2774 nsresult rv
= NS_OK
;
2776 // updates can come through for windows no longer holding an mWnd during
2777 // deletes triggered by JavaScript in buttons with mouse feedback
2779 VERIFY(::UpdateWindow(mWnd
));
2784 /**************************************************************
2786 * SECTION: Native data storage
2788 * nsIWidget::GetNativeData
2789 * nsIWidget::FreeNativeData
2791 * Set or clear native data based on a constant.
2793 **************************************************************/
2795 // Return some native data according to aDataType
2796 void* nsWindow::GetNativeData(PRUint32 aDataType
)
2798 switch (aDataType
) {
2799 case NS_NATIVE_TMP_WINDOW
:
2800 return (void*)::CreateWindowExW(WS_EX_NOACTIVATE
|
2801 mIsRTL
? WS_EX_LAYOUTRTL
: 0,
2811 nsToolkit::mDllInstance
,
2813 case NS_NATIVE_PLUGIN_PORT
:
2814 case NS_NATIVE_WIDGET
:
2815 case NS_NATIVE_WINDOW
:
2817 case NS_NATIVE_GRAPHIC
:
2818 // XXX: This is sleezy!! Remember to Release the DC after using it!
2820 return (void*)(eTransparencyTransparent
== mTransparencyMode
) ?
2821 mMemoryDC
: ::GetDC(mWnd
);
2823 return (void*)::GetDC(mWnd
);
2826 #ifdef NS_ENABLE_TSF
2827 case NS_NATIVE_TSF_THREAD_MGR
:
2828 return nsTextStore::GetThreadMgr();
2829 case NS_NATIVE_TSF_CATEGORY_MGR
:
2830 return nsTextStore::GetCategoryMgr();
2831 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR
:
2832 return nsTextStore::GetDisplayAttrMgr();
2833 #endif //NS_ENABLE_TSF
2842 // Free some native data according to aDataType
2843 void nsWindow::FreeNativeData(void * data
, PRUint32 aDataType
)
2847 case NS_NATIVE_GRAPHIC
:
2849 if (eTransparencyTransparent
!= mTransparencyMode
)
2850 ::ReleaseDC(mWnd
, (HDC
)data
);
2852 ::ReleaseDC(mWnd
, (HDC
)data
);
2855 case NS_NATIVE_WIDGET
:
2856 case NS_NATIVE_WINDOW
:
2857 case NS_NATIVE_PLUGIN_PORT
:
2864 /**************************************************************
2866 * SECTION: nsIWidget::SetTitle
2868 * Set the main windows title text.
2870 **************************************************************/
2872 NS_METHOD
nsWindow::SetTitle(const nsAString
& aTitle
)
2874 const nsString
& strTitle
= PromiseFlatString(aTitle
);
2875 ::SendMessageW(mWnd
, WM_SETTEXT
, (WPARAM
)0, (LPARAM
)(LPCWSTR
)strTitle
.get());
2879 /**************************************************************
2881 * SECTION: nsIWidget::SetIcon
2883 * Set the main windows icon.
2885 **************************************************************/
2887 NS_METHOD
nsWindow::SetIcon(const nsAString
& aIconSpec
)
2890 // Assume the given string is a local identifier for an icon file.
2892 nsCOMPtr
<nsILocalFile
> iconFile
;
2893 ResolveIconName(aIconSpec
, NS_LITERAL_STRING(".ico"),
2894 getter_AddRefs(iconFile
));
2896 return NS_OK
; // not an error if icon is not found
2898 nsAutoString iconPath
;
2899 iconFile
->GetPath(iconPath
);
2901 // XXX this should use MZLU (see bug 239279)
2905 HICON bigIcon
= (HICON
)::LoadImageW(NULL
,
2906 (LPCWSTR
)iconPath
.get(),
2908 ::GetSystemMetrics(SM_CXICON
),
2909 ::GetSystemMetrics(SM_CYICON
),
2911 HICON smallIcon
= (HICON
)::LoadImageW(NULL
,
2912 (LPCWSTR
)iconPath
.get(),
2914 ::GetSystemMetrics(SM_CXSMICON
),
2915 ::GetSystemMetrics(SM_CYSMICON
),
2919 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_BIG
, (LPARAM
)bigIcon
);
2921 ::DestroyIcon(icon
);
2923 #ifdef DEBUG_SetIcon
2925 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
2926 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath
.get(), ::GetLastError() );
2930 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_SMALL
, (LPARAM
)smallIcon
);
2932 ::DestroyIcon(icon
);
2934 #ifdef DEBUG_SetIcon
2936 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
2937 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath
.get(), ::GetLastError() );
2944 /**************************************************************
2946 * SECTION: nsIWidget::WidgetToScreenOffset
2948 * Return this widget's origin in screen coordinates.
2950 **************************************************************/
2952 nsIntPoint
nsWindow::WidgetToScreenOffset()
2957 ::ClientToScreen(mWnd
, &point
);
2958 return nsIntPoint(point
.x
, point
.y
);
2961 nsIntSize
nsWindow::ClientToWindowSize(const nsIntSize
& aClientSize
)
2963 if (!IsPopupWithTitleBar())
2966 // just use (200, 200) as the position
2970 r
.right
= 200 + aClientSize
.width
;
2971 r
.bottom
= 200 + aClientSize
.height
;
2972 ::AdjustWindowRectEx(&r
, WindowStyle(), PR_FALSE
, WindowExStyle());
2974 return nsIntSize(r
.right
- r
.left
, r
.bottom
- r
.top
);
2977 /**************************************************************
2979 * SECTION: nsIWidget::EnableDragDrop
2981 * Enables/Disables drag and drop of files on this widget.
2983 **************************************************************/
2985 #if !defined(WINCE) // implemented in nsWindowCE.cpp
2986 NS_METHOD
nsWindow::EnableDragDrop(PRBool aEnable
)
2988 NS_ASSERTION(mWnd
, "nsWindow::EnableDragDrop() called after Destroy()");
2990 nsresult rv
= NS_ERROR_FAILURE
;
2992 if (nsnull
== mNativeDragTarget
) {
2993 mNativeDragTarget
= new nsNativeDragTarget(this);
2994 if (NULL
!= mNativeDragTarget
) {
2995 mNativeDragTarget
->AddRef();
2996 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
,TRUE
,FALSE
)) {
2997 if (S_OK
== ::RegisterDragDrop(mWnd
, (LPDROPTARGET
)mNativeDragTarget
)) {
3004 if (nsnull
!= mWnd
&& NULL
!= mNativeDragTarget
) {
3005 ::RevokeDragDrop(mWnd
);
3006 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
, FALSE
, TRUE
)) {
3009 mNativeDragTarget
->DragCancel();
3010 NS_RELEASE(mNativeDragTarget
);
3017 /**************************************************************
3019 * SECTION: nsIWidget::CaptureMouse
3021 * Enables/Disables system mouse capture.
3023 **************************************************************/
3025 NS_METHOD
nsWindow::CaptureMouse(PRBool aCapture
)
3027 if (!nsToolkit::gMouseTrailer
) {
3028 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3033 nsToolkit::gMouseTrailer
->SetCaptureWindow(mWnd
);
3036 nsToolkit::gMouseTrailer
->SetCaptureWindow(NULL
);
3039 mIsInMouseCapture
= aCapture
;
3043 /**************************************************************
3045 * SECTION: nsIWidget::CaptureRollupEvents
3047 * Dealing with event rollup on destroy for popups. Enables &
3048 * Disables system capture of any and all events that would
3049 * cause a dropdown to be rolled up.
3051 **************************************************************/
3053 NS_IMETHODIMP
nsWindow::CaptureRollupEvents(nsIRollupListener
* aListener
,
3054 nsIMenuRollup
* aMenuRollup
,
3056 PRBool aConsumeRollupEvent
)
3059 /* we haven't bothered carrying a weak reference to sRollupWidget because
3060 we believe lifespan is properly scoped. this next assertion helps
3061 assure that remains true. */
3062 NS_ASSERTION(!sRollupWidget
, "rollup widget reassigned before release");
3063 sRollupConsumeEvent
= aConsumeRollupEvent
;
3064 NS_IF_RELEASE(sRollupWidget
);
3065 NS_IF_RELEASE(sMenuRollup
);
3066 sRollupListener
= aListener
;
3067 sMenuRollup
= aMenuRollup
;
3068 NS_IF_ADDREF(aMenuRollup
);
3069 sRollupWidget
= this;
3073 if (!sMsgFilterHook
&& !sCallProcHook
&& !sCallMouseHook
) {
3074 RegisterSpecialDropdownHooks();
3076 sProcessHook
= PR_TRUE
;
3080 sRollupListener
= nsnull
;
3081 NS_IF_RELEASE(sMenuRollup
);
3082 NS_IF_RELEASE(sRollupWidget
);
3085 sProcessHook
= PR_FALSE
;
3086 UnregisterSpecialDropdownHooks();
3093 /**************************************************************
3095 * SECTION: nsIWidget::GetAttention
3097 * Bring this window to the user's attention.
3099 **************************************************************/
3101 // Draw user's attention to this window until it comes to foreground.
3103 nsWindow::GetAttention(PRInt32 aCycleCount
)
3108 return NS_ERROR_NOT_INITIALIZED
;
3110 // Don't flash if the flash count is 0 or if the
3111 // top level window is already active.
3112 HWND fgWnd
= ::GetForegroundWindow();
3113 if (aCycleCount
== 0 || fgWnd
== GetTopLevelHWND(mWnd
))
3116 HWND flashWnd
= mWnd
;
3117 while (HWND ownerWnd
= ::GetWindow(flashWnd
, GW_OWNER
)) {
3118 flashWnd
= ownerWnd
;
3121 // Don't flash if the owner window is active either.
3122 if (fgWnd
== flashWnd
)
3125 DWORD defaultCycleCount
= 0;
3126 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT
, 0, &defaultCycleCount
, 0);
3128 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
3129 FLASHW_ALL
, aCycleCount
> 0 ? aCycleCount
: defaultCycleCount
, 0 };
3130 ::FlashWindowEx(&flashInfo
);
3135 void nsWindow::StopFlashing()
3138 HWND flashWnd
= mWnd
;
3139 while (HWND ownerWnd
= ::GetWindow(flashWnd
, GW_OWNER
)) {
3140 flashWnd
= ownerWnd
;
3143 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
3144 FLASHW_STOP
, 0, 0 };
3145 ::FlashWindowEx(&flashInfo
);
3149 /**************************************************************
3151 * SECTION: nsIWidget::HasPendingInputEvent
3153 * Ask whether there user input events pending. All input events are
3154 * included, including those not targeted at this nsIwidget instance.
3156 **************************************************************/
3159 nsWindow::HasPendingInputEvent()
3161 // If there is pending input or the user is currently
3162 // moving the window then return true.
3163 // Note: When the user is moving the window WIN32 spins
3164 // a separate event loop and input events are not
3165 // reported to the application.
3166 if (HIWORD(GetQueueStatus(QS_INPUT
)))
3171 GUITHREADINFO guiInfo
;
3172 guiInfo
.cbSize
= sizeof(GUITHREADINFO
);
3173 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo
))
3175 return GUI_INMOVESIZE
== (guiInfo
.flags
& GUI_INMOVESIZE
);
3179 /**************************************************************
3181 * SECTION: nsIWidget::GetLayerManager
3183 * Get the layer manager associated with this widget.
3185 **************************************************************/
3187 mozilla::layers::LayerManager
*
3188 nsWindow::GetLayerManager()
3191 if (!mLayerManager
) {
3192 nsCOMPtr
<nsIPrefBranch2
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
3194 PRBool accelerateByDefault
= PR_TRUE
;
3195 PRBool disableAcceleration
= PR_FALSE
;
3196 PRBool preferOpenGL
= PR_FALSE
;
3198 prefs
->GetBoolPref("layers.accelerate-all",
3199 &accelerateByDefault
);
3200 prefs
->GetBoolPref("layers.accelerate-none",
3201 &disableAcceleration
);
3202 prefs
->GetBoolPref("layers.prefer-opengl",
3206 const char *acceleratedEnv
= PR_GetEnv("MOZ_ACCELERATED");
3207 accelerateByDefault
= accelerateByDefault
||
3208 (acceleratedEnv
&& (*acceleratedEnv
!= '0'));
3210 /* We don't currently support using an accelerated layer manager with
3211 * transparent windows so don't even try. I'm also not sure if we even
3212 * want to support this case. See bug #593471 */
3213 disableAcceleration
= disableAcceleration
||
3214 eTransparencyTransparent
== mTransparencyMode
;
3216 nsCOMPtr
<nsIXULRuntime
> xr
= do_GetService("@mozilla.org/xre/runtime;1");
3217 PRBool safeMode
= PR_FALSE
;
3219 xr
->GetInSafeMode(&safeMode
);
3221 if (disableAcceleration
|| safeMode
)
3222 mUseAcceleratedRendering
= PR_FALSE
;
3223 else if (accelerateByDefault
)
3224 mUseAcceleratedRendering
= PR_TRUE
;
3226 if (mUseAcceleratedRendering
) {
3227 #ifdef MOZ_ENABLE_D3D9_LAYER
3228 if (!preferOpenGL
) {
3229 nsRefPtr
<mozilla::layers::LayerManagerD3D9
> layerManager
=
3230 new mozilla::layers::LayerManagerD3D9(this);
3231 if (layerManager
->Initialize()) {
3232 mLayerManager
= layerManager
;
3236 if (!mLayerManager
&& preferOpenGL
) {
3237 nsRefPtr
<mozilla::layers::LayerManagerOGL
> layerManager
=
3238 new mozilla::layers::LayerManagerOGL(this);
3239 if (layerManager
->Initialize()) {
3240 mLayerManager
= layerManager
;
3245 // Fall back to software if we couldn't use any hardware backends.
3247 mLayerManager
= new BasicLayerManager(this);
3251 return mLayerManager
;
3254 /**************************************************************
3256 * SECTION: nsIWidget::GetThebesSurface
3258 * Get the Thebes surface associated with this widget.
3260 **************************************************************/
3262 gfxASurface
*nsWindow::GetThebesSurface()
3264 #ifdef CAIRO_HAS_D2D_SURFACE
3265 if (mD2DWindowSurface
) {
3266 return mD2DWindowSurface
;
3270 return (new gfxWindowsSurface(mPaintDC
));
3272 #ifdef CAIRO_HAS_D2D_SURFACE
3273 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3274 gfxWindowsPlatform::RENDER_DIRECT2D
) {
3275 gfxASurface::gfxContentType content
= gfxASurface::CONTENT_COLOR
;
3276 #if defined(MOZ_XUL)
3277 if (mTransparencyMode
!= eTransparencyOpaque
) {
3278 content
= gfxASurface::CONTENT_COLOR_ALPHA
;
3281 return (new gfxD2DSurface(mWnd
, content
));
3284 PRUint32 flags
= gfxWindowsSurface::FLAG_TAKE_DC
;
3285 if (mTransparencyMode
!= eTransparencyOpaque
) {
3286 flags
|= gfxWindowsSurface::FLAG_IS_TRANSPARENT
;
3288 return (new gfxWindowsSurface(mWnd
, flags
));
3289 #ifdef CAIRO_HAS_D2D_SURFACE
3294 /**************************************************************
3296 * SECTION: nsIWidget::OnDefaultButtonLoaded
3298 * Called after the dialog is loaded and it has a default button.
3300 **************************************************************/
3303 nsWindow::OnDefaultButtonLoaded(const nsIntRect
&aButtonRect
)
3306 return NS_ERROR_NOT_IMPLEMENTED
;
3308 if (aButtonRect
.IsEmpty())
3311 // Don't snap when we are not active.
3312 HWND activeWnd
= ::GetActiveWindow();
3313 if (activeWnd
!= ::GetForegroundWindow() ||
3314 GetTopLevelHWND(mWnd
, PR_TRUE
) != GetTopLevelHWND(activeWnd
, PR_TRUE
)) {
3318 PRBool isAlwaysSnapCursor
= PR_FALSE
;
3319 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
3321 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
3322 prefs
->GetBranch(nsnull
, getter_AddRefs(prefBranch
));
3324 prefBranch
->GetBoolPref("ui.cursor_snapping.always_enabled",
3325 &isAlwaysSnapCursor
);
3329 if (!isAlwaysSnapCursor
) {
3330 BOOL snapDefaultButton
;
3331 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON
, 0,
3332 &snapDefaultButton
, 0) || !snapDefaultButton
)
3336 nsIntRect widgetRect
;
3337 nsresult rv
= GetScreenBounds(widgetRect
);
3338 NS_ENSURE_SUCCESS(rv
, rv
);
3339 nsIntRect
buttonRect(aButtonRect
+ widgetRect
.TopLeft());
3341 nsIntPoint
centerOfButton(buttonRect
.x
+ buttonRect
.width
/ 2,
3342 buttonRect
.y
+ buttonRect
.height
/ 2);
3343 // The center of the button can be outside of the widget.
3344 // E.g., it could be hidden by scrolling.
3345 if (!widgetRect
.Contains(centerOfButton
)) {
3349 if (!::SetCursorPos(centerOfButton
.x
, centerOfButton
.y
)) {
3350 NS_ERROR("SetCursorPos failed");
3351 return NS_ERROR_FAILURE
;
3358 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta
,
3359 PRBool aIsHorizontal
,
3360 PRInt32
&aOverriddenDelta
)
3362 // The default vertical and horizontal scrolling speed is 3, this is defined
3363 // on the document of SystemParametersInfo in MSDN.
3364 const PRUint32 kSystemDefaultScrollingSpeed
= 3;
3366 PRInt32 absOriginDelta
= PR_ABS(aOriginalDelta
);
3368 // Compute the simple overridden speed.
3369 PRInt32 absComputedOverriddenDelta
;
3371 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta
, aIsHorizontal
,
3372 absComputedOverriddenDelta
);
3373 NS_ENSURE_SUCCESS(rv
, rv
);
3375 aOverriddenDelta
= aOriginalDelta
;
3377 if (absComputedOverriddenDelta
== absOriginDelta
) {
3378 // We don't override now.
3382 // Otherwise, we should check whether the user customized the system settings
3383 // or not. If the user did it, we should respect the will.
3385 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &systemSpeed
, 0)) {
3386 return NS_ERROR_FAILURE
;
3388 // The default vertical scrolling speed is 3, this is defined on the document
3389 // of SystemParametersInfo in MSDN.
3390 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
3394 // Only Vista and later, Windows has the system setting of horizontal
3395 // scrolling by the mouse wheel.
3396 if (GetWindowsVersion() >= VISTA_VERSION
) {
3397 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS
, 0, &systemSpeed
, 0)) {
3398 return NS_ERROR_FAILURE
;
3400 // The default horizontal scrolling speed is 3, this is defined on the
3401 // document of SystemParametersInfo in MSDN.
3402 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
3407 // Limit the overridden delta value from the system settings. The mouse
3408 // driver might accelerate the scrolling speed already. If so, we shouldn't
3409 // override the scrolling speed for preventing the unexpected high speed
3411 PRInt32 absDeltaLimit
;
3413 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed
,
3414 aIsHorizontal
, absDeltaLimit
);
3415 NS_ENSURE_SUCCESS(rv
, rv
);
3417 // If the given delta is larger than our computed limitation value, the delta
3418 // was accelerated by the mouse driver. So, we should do nothing here.
3419 if (absDeltaLimit
<= absOriginDelta
) {
3423 absComputedOverriddenDelta
=
3424 PR_MIN(absComputedOverriddenDelta
, absDeltaLimit
);
3426 aOverriddenDelta
= (aOriginalDelta
> 0) ? absComputedOverriddenDelta
:
3427 -absComputedOverriddenDelta
;
3431 /**************************************************************
3432 **************************************************************
3434 ** BLOCK: Moz Events
3436 ** Moz GUI event management.
3438 **************************************************************
3439 **************************************************************/
3441 /**************************************************************
3443 * SECTION: Mozilla event initialization
3445 * Helpers for initializing moz events.
3447 **************************************************************/
3449 // Event intialization
3450 MSG
nsWindow::InitMSG(UINT aMessage
, WPARAM wParam
, LPARAM lParam
)
3453 msg
.message
= aMessage
;
3454 msg
.wParam
= wParam
;
3455 msg
.lParam
= lParam
;
3459 void nsWindow::InitEvent(nsGUIEvent
& event
, nsIntPoint
* aPoint
)
3461 if (nsnull
== aPoint
) { // use the point from the event
3462 // get the message position in client coordinates
3465 DWORD pos
= ::GetMessagePos();
3468 cpos
.x
= GET_X_LPARAM(pos
);
3469 cpos
.y
= GET_Y_LPARAM(pos
);
3471 ::ScreenToClient(mWnd
, &cpos
);
3472 event
.refPoint
.x
= cpos
.x
;
3473 event
.refPoint
.y
= cpos
.y
;
3475 event
.refPoint
.x
= 0;
3476 event
.refPoint
.y
= 0;
3480 // use the point override if provided
3481 event
.refPoint
.x
= aPoint
->x
;
3482 event
.refPoint
.y
= aPoint
->y
;
3486 event
.time
= ::GetMessageTime();
3488 event
.time
= PR_Now() / 1000;
3491 mLastPoint
= event
.refPoint
;
3494 /**************************************************************
3496 * SECTION: Moz event dispatch helpers
3498 * Helpers for dispatching different types of moz events.
3500 **************************************************************/
3502 // Main event dispatch. Invokes callback and ProcessEvent method on
3503 // Event Listener object. Part of nsIWidget.
3504 NS_IMETHODIMP
nsWindow::DispatchEvent(nsGUIEvent
* event
, nsEventStatus
& aStatus
)
3506 #ifdef WIDGET_DEBUG_OUTPUT
3507 debug_DumpEvent(stdout
,
3510 nsCAutoString("something"),
3512 #endif // WIDGET_DEBUG_OUTPUT
3514 aStatus
= nsEventStatus_eIgnore
;
3516 // skip processing of suppressed blur events
3517 if (event
->message
== NS_DEACTIVATE
&& BlurEventsSuppressed())
3520 // Top level windows can have a view attached which requires events be sent
3521 // to the underlying base window and the view. Added when we combined the
3522 // base chrome window with the main content child for nc client area (title
3524 if (mViewCallback
) {
3525 // A subset of events are sent to the base xul window first
3526 switch(event
->message
) {
3527 // send to the base window (view mgr ignores these for the view)
3528 case NS_UISTATECHANGED
:
3533 (*mEventCallback
)(event
); // web shell / xul window
3536 // sent to the base window, then to the view
3541 (*mEventCallback
)(event
); // web shell / xul window
3544 // attached view events
3545 aStatus
= (*mViewCallback
)(event
);
3547 else if (mEventCallback
) {
3548 aStatus
= (*mEventCallback
)(event
);
3551 // the window can be destroyed during processing of seemingly innocuous events like, say,
3552 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3553 // which causes problems with the deleted window. therefore:
3554 if (mOnDestroyCalled
)
3555 aStatus
= nsEventStatus_eConsumeNoDefault
;
3559 PRBool
nsWindow::DispatchStandardEvent(PRUint32 aMsg
)
3561 nsGUIEvent
event(PR_TRUE
, aMsg
, this);
3564 PRBool result
= DispatchWindowEvent(&event
);
3568 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
* event
)
3570 nsEventStatus status
;
3571 DispatchEvent(event
, status
);
3572 return ConvertStatus(status
);
3575 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
* event
, nsEventStatus
&aStatus
) {
3576 DispatchEvent(event
, aStatus
);
3577 return ConvertStatus(aStatus
);
3580 PRBool
nsWindow::DispatchKeyEvent(PRUint32 aEventType
, WORD aCharCode
,
3581 const nsTArray
<nsAlternativeCharCode
>* aAlternativeCharCodes
,
3582 UINT aVirtualCharCode
, const MSG
*aMsg
,
3583 const nsModifierKeyState
&aModKeyState
,
3588 nsKeyEvent
event(PR_TRUE
, aEventType
, this);
3589 nsIntPoint
point(0, 0);
3591 InitEvent(event
, &point
); // this add ref's event.widget
3593 event
.flags
|= aFlags
;
3594 event
.charCode
= aCharCode
;
3595 if (aAlternativeCharCodes
)
3596 event
.alternativeCharCodes
.AppendElements(*aAlternativeCharCodes
);
3597 event
.keyCode
= aVirtualCharCode
;
3601 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt
++,
3602 (NS_KEY_PRESS
== aEventType
) ? "PRESS" : (aEventType
== NS_KEY_UP
? "Up" : "Down"),
3603 event
.charCode
, event
.keyCode
);
3604 printf("Shift: %s Control %s Alt: %s \n",
3605 (mIsShiftDown
? "D" : "U"), (mIsControlDown
? "D" : "U"), (mIsAltDown
? "D" : "U"));
3606 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3607 IS_VK_DOWN(NS_VK_SHIFT
) ? 'S' : ' ',
3608 IS_VK_DOWN(NS_VK_CONTROL
) ? 'C' : ' ',
3609 IS_VK_DOWN(NS_VK_ALT
) ? 'A' : ' ',
3610 IS_VK_DOWN(VK_LSHIFT
) ? 'S' : ' ',
3611 IS_VK_DOWN(VK_LCONTROL
) ? 'C' : ' ',
3612 IS_VK_DOWN(VK_LMENU
) ? 'A' : ' ',
3613 IS_VK_DOWN(VK_RMENU
) ? 'A' : ' ',
3614 IS_VK_DOWN(VK_RCONTROL
) ? 'C' : ' ',
3615 IS_VK_DOWN(VK_RSHIFT
) ? 'S' : ' ');
3618 event
.isShift
= aModKeyState
.mIsShiftDown
;
3619 event
.isControl
= aModKeyState
.mIsControlDown
;
3620 event
.isMeta
= PR_FALSE
;
3621 event
.isAlt
= aModKeyState
.mIsAltDown
;
3623 NPEvent pluginEvent
;
3624 if (aMsg
&& PluginHasFocus()) {
3625 pluginEvent
.event
= aMsg
->message
;
3626 pluginEvent
.wParam
= aMsg
->wParam
;
3627 pluginEvent
.lParam
= aMsg
->lParam
;
3628 event
.pluginEvent
= (void *)&pluginEvent
;
3631 PRBool result
= DispatchWindowEvent(&event
);
3636 PRBool
nsWindow::DispatchCommandEvent(PRUint32 aEventCommand
)
3638 nsCOMPtr
<nsIAtom
> command
;
3639 switch (aEventCommand
) {
3640 case APPCOMMAND_BROWSER_BACKWARD
:
3641 command
= nsWidgetAtoms::Back
;
3643 case APPCOMMAND_BROWSER_FORWARD
:
3644 command
= nsWidgetAtoms::Forward
;
3646 case APPCOMMAND_BROWSER_REFRESH
:
3647 command
= nsWidgetAtoms::Reload
;
3649 case APPCOMMAND_BROWSER_STOP
:
3650 command
= nsWidgetAtoms::Stop
;
3652 case APPCOMMAND_BROWSER_SEARCH
:
3653 command
= nsWidgetAtoms::Search
;
3655 case APPCOMMAND_BROWSER_FAVORITES
:
3656 command
= nsWidgetAtoms::Bookmarks
;
3658 case APPCOMMAND_BROWSER_HOME
:
3659 command
= nsWidgetAtoms::Home
;
3664 nsCommandEvent
event(PR_TRUE
, nsWidgetAtoms::onAppCommand
, command
, this);
3667 DispatchWindowEvent(&event
);
3672 // Recursively dispatch synchronous paints for nsIWidget
3673 // descendants with invalidated rectangles.
3674 BOOL CALLBACK
nsWindow::DispatchStarvedPaints(HWND aWnd
, LPARAM aMsg
)
3676 LONG_PTR proc
= ::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
3677 if (proc
== (LONG_PTR
)&nsWindow::WindowProc
) {
3678 // its one of our windows so check to see if it has a
3679 // invalidated rect. If it does. Dispatch a synchronous
3681 if (GetUpdateRect(aWnd
, NULL
, FALSE
))
3682 VERIFY(::UpdateWindow(aWnd
));
3687 // Check for pending paints and dispatch any pending paint
3688 // messages for any nsIWidget which is a descendant of the
3689 // top-level window that *this* window is embedded within.
3691 // Note: We do not dispatch pending paint messages for non
3692 // nsIWidget managed windows.
3693 void nsWindow::DispatchPendingEvents()
3696 NS_WARNING("We were asked to dispatch pending events during painting, "
3697 "denying since that's unsafe.");
3701 // We need to ensure that reflow events do not get starved.
3702 // At the same time, we don't want to recurse through here
3703 // as that would prevent us from dispatching starved paints.
3704 static int recursionBlocker
= 0;
3705 if (recursionBlocker
++ == 0) {
3706 NS_ProcessPendingEvents(nsnull
, PR_MillisecondsToInterval(100));
3710 // Quickly check to see if there are any
3711 // paint events pending.
3712 if (::GetQueueStatus(QS_PAINT
)) {
3713 // Find the top level window.
3714 HWND topWnd
= GetTopLevelHWND(mWnd
);
3716 // Dispatch pending paints for all topWnd's descendant windows.
3717 // Note: EnumChildWindows enumerates all descendant windows not just
3720 ::EnumChildWindows(topWnd
, nsWindow::DispatchStarvedPaints
, 0);
3722 nsWindowCE::EnumChildWindows(topWnd
, nsWindow::DispatchStarvedPaints
, NULL
);
3727 // Deal with plugin events
3728 PRBool
nsWindow::DispatchPluginEvent(const MSG
&aMsg
)
3730 if (!PluginHasFocus())
3733 nsGUIEvent
event(PR_TRUE
, NS_PLUGIN_EVENT
, this);
3734 nsIntPoint
point(0, 0);
3735 InitEvent(event
, &point
);
3736 NPEvent pluginEvent
;
3737 pluginEvent
.event
= aMsg
.message
;
3738 pluginEvent
.wParam
= aMsg
.wParam
;
3739 pluginEvent
.lParam
= aMsg
.lParam
;
3740 event
.pluginEvent
= (void *)&pluginEvent
;
3741 return DispatchWindowEvent(&event
);
3744 PRBool
nsWindow::DispatchPluginEvent(UINT aMessage
,
3747 PRBool aDispatchPendingEvents
)
3749 PRBool ret
= DispatchPluginEvent(InitMSG(aMessage
, aWParam
, aLParam
));
3750 if (aDispatchPendingEvents
) {
3751 DispatchPendingEvents();
3756 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg
,
3760 ::GetMessageW(&msg
, mWnd
, aFirstMsg
, aLastMsg
);
3761 DispatchPluginEvent(msg
);
3764 // Deal with all sort of mouse event
3765 PRBool
nsWindow::DispatchMouseEvent(PRUint32 aEventType
, WPARAM wParam
,
3766 LPARAM lParam
, PRBool aIsContextMenuKey
,
3767 PRInt16 aButton
, PRUint16 aInputSource
)
3769 PRBool result
= PR_FALSE
;
3773 if (!mEventCallback
) {
3777 switch (aEventType
) {
3778 case NS_MOUSE_BUTTON_DOWN
:
3779 CaptureMouse(PR_TRUE
);
3782 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3783 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3784 case NS_MOUSE_BUTTON_UP
:
3787 if (!(wParam
& (MK_LBUTTON
| MK_MBUTTON
| MK_RBUTTON
)) && mIsInMouseCapture
)
3788 CaptureMouse(PR_FALSE
);
3796 nsIntPoint eventPoint
;
3797 eventPoint
.x
= GET_X_LPARAM(lParam
);
3798 eventPoint
.y
= GET_Y_LPARAM(lParam
);
3800 nsMouseEvent
event(PR_TRUE
, aEventType
, this, nsMouseEvent::eReal
,
3802 ? nsMouseEvent::eContextMenuKey
3803 : nsMouseEvent::eNormal
);
3804 if (aEventType
== NS_CONTEXTMENU
&& aIsContextMenuKey
) {
3805 nsIntPoint
zero(0, 0);
3806 InitEvent(event
, &zero
);
3808 InitEvent(event
, &eventPoint
);
3811 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
3812 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
3813 event
.isMeta
= PR_FALSE
;
3814 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
3815 event
.button
= aButton
;
3816 event
.inputSource
= aInputSource
;
3818 nsIntPoint mpScreen
= eventPoint
+ WidgetToScreenOffset();
3820 // Suppress mouse moves caused by widget creation
3821 if (aEventType
== NS_MOUSE_MOVE
)
3823 if ((sLastMouseMovePoint
.x
== mpScreen
.x
) && (sLastMouseMovePoint
.y
== mpScreen
.y
))
3825 sLastMouseMovePoint
.x
= mpScreen
.x
;
3826 sLastMouseMovePoint
.y
= mpScreen
.y
;
3829 PRBool insideMovementThreshold
= (abs(sLastMousePoint
.x
- eventPoint
.x
) < (short)::GetSystemMetrics(SM_CXDOUBLECLK
)) &&
3830 (abs(sLastMousePoint
.y
- eventPoint
.y
) < (short)::GetSystemMetrics(SM_CYDOUBLECLK
));
3834 case nsMouseEvent::eLeftButton
:
3835 eventButton
= VK_LBUTTON
;
3837 case nsMouseEvent::eMiddleButton
:
3838 eventButton
= VK_MBUTTON
;
3840 case nsMouseEvent::eRightButton
:
3841 eventButton
= VK_RBUTTON
;
3848 // Doubleclicks are used to set the click count, then changed to mousedowns
3849 // We're going to time double-clicks from mouse *up* to next mouse *down*
3851 LONG curMsgTime
= ::GetMessageTime();
3853 LONG curMsgTime
= PR_Now() / 1000;
3856 if (aEventType
== NS_MOUSE_DOUBLECLICK
) {
3857 event
.message
= NS_MOUSE_BUTTON_DOWN
;
3858 event
.button
= aButton
;
3859 sLastClickCount
= 2;
3861 else if (aEventType
== NS_MOUSE_BUTTON_UP
) {
3862 // remember when this happened for the next mouse down
3863 sLastMousePoint
.x
= eventPoint
.x
;
3864 sLastMousePoint
.y
= eventPoint
.y
;
3865 sLastMouseButton
= eventButton
;
3867 else if (aEventType
== NS_MOUSE_BUTTON_DOWN
) {
3868 // now look to see if we want to convert this to a double- or triple-click
3869 if (((curMsgTime
- sLastMouseDownTime
) < (LONG
)::GetDoubleClickTime()) && insideMovementThreshold
&&
3870 eventButton
== sLastMouseButton
) {
3873 // reset the click count, to count *this* click
3874 sLastClickCount
= 1;
3876 // Set last Click time on MouseDown only
3877 sLastMouseDownTime
= curMsgTime
;
3879 else if (aEventType
== NS_MOUSE_MOVE
&& !insideMovementThreshold
) {
3880 sLastClickCount
= 0;
3882 else if (aEventType
== NS_MOUSE_EXIT
) {
3883 event
.exit
= IsTopLevelMouseExit(mWnd
) ? nsMouseEvent::eTopLevel
: nsMouseEvent::eChild
;
3885 else if (aEventType
== NS_MOUSE_MOZHITTEST
)
3887 event
.flags
|= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH
;
3889 event
.clickCount
= sLastClickCount
;
3892 printf("Msg Time: %d Click Count: %d\n", curMsgTime
, event
.clickCount
);
3895 NPEvent pluginEvent
;
3899 case NS_MOUSE_BUTTON_DOWN
:
3901 case nsMouseEvent::eLeftButton
:
3902 pluginEvent
.event
= WM_LBUTTONDOWN
;
3904 case nsMouseEvent::eMiddleButton
:
3905 pluginEvent
.event
= WM_MBUTTONDOWN
;
3907 case nsMouseEvent::eRightButton
:
3908 pluginEvent
.event
= WM_RBUTTONDOWN
;
3914 case NS_MOUSE_BUTTON_UP
:
3916 case nsMouseEvent::eLeftButton
:
3917 pluginEvent
.event
= WM_LBUTTONUP
;
3919 case nsMouseEvent::eMiddleButton
:
3920 pluginEvent
.event
= WM_MBUTTONUP
;
3922 case nsMouseEvent::eRightButton
:
3923 pluginEvent
.event
= WM_RBUTTONUP
;
3929 case NS_MOUSE_DOUBLECLICK
:
3931 case nsMouseEvent::eLeftButton
:
3932 pluginEvent
.event
= WM_LBUTTONDBLCLK
;
3934 case nsMouseEvent::eMiddleButton
:
3935 pluginEvent
.event
= WM_MBUTTONDBLCLK
;
3937 case nsMouseEvent::eRightButton
:
3938 pluginEvent
.event
= WM_RBUTTONDBLCLK
;
3945 pluginEvent
.event
= WM_MOUSEMOVE
;
3948 pluginEvent
.event
= WM_MOUSELEAVE
;
3951 pluginEvent
.event
= WM_NULL
;
3955 pluginEvent
.wParam
= wParam
; // plugins NEED raw OS event flags!
3956 pluginEvent
.lParam
= lParam
;
3958 event
.pluginEvent
= (void *)&pluginEvent
;
3960 // call the event callback
3961 if (nsnull
!= mEventCallback
) {
3962 if (nsToolkit::gMouseTrailer
)
3963 nsToolkit::gMouseTrailer
->Disable();
3964 if (aEventType
== NS_MOUSE_MOVE
) {
3965 if (nsToolkit::gMouseTrailer
&& !mIsInMouseCapture
) {
3966 nsToolkit::gMouseTrailer
->SetMouseTrailerWindow(mWnd
);
3973 if (rect
.Contains(event
.refPoint
)) {
3974 if (sCurrentWindow
== NULL
|| sCurrentWindow
!= this) {
3975 if ((nsnull
!= sCurrentWindow
) && (!sCurrentWindow
->mInDtor
)) {
3976 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
3977 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_EXIT
, wParam
, pos
, PR_FALSE
,
3978 nsMouseEvent::eLeftButton
, aInputSource
);
3980 sCurrentWindow
= this;
3982 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
3983 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_ENTER
, wParam
, pos
, PR_FALSE
,
3984 nsMouseEvent::eLeftButton
, aInputSource
);
3988 } else if (aEventType
== NS_MOUSE_EXIT
) {
3989 if (sCurrentWindow
== this) {
3990 sCurrentWindow
= nsnull
;
3994 result
= DispatchWindowEvent(&event
);
3996 if (nsToolkit::gMouseTrailer
)
3997 nsToolkit::gMouseTrailer
->Enable();
3999 // Release the widget with NS_IF_RELEASE() just in case
4000 // the context menu key code in nsEventListenerManager::HandleEvent()
4001 // released it already.
4008 // Deal with accessibile event
4009 #ifdef ACCESSIBILITY
4011 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType
)
4013 if (nsnull
== mEventCallback
) {
4017 nsAccessibleEvent
event(PR_TRUE
, aEventType
, this);
4018 InitEvent(event
, nsnull
);
4020 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
4021 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
4022 event
.isMeta
= PR_FALSE
;
4023 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
4025 DispatchWindowEvent(&event
);
4027 return event
.mAccessible
;
4031 PRBool
nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType
)
4033 if (aEventType
== NS_ACTIVATE
)
4034 sJustGotActivate
= PR_FALSE
;
4035 sJustGotDeactivate
= PR_FALSE
;
4037 // retrive the toplevel window or dialog
4039 HWND toplevelWnd
= NULL
;
4041 toplevelWnd
= curWnd
;
4043 nsWindow
*win
= GetNSWindowPtr(curWnd
);
4045 nsWindowType wintype
;
4046 win
->GetWindowType(wintype
);
4047 if (wintype
== eWindowType_toplevel
|| wintype
== eWindowType_dialog
)
4051 curWnd
= ::GetParent(curWnd
); // Parent or owner (if has no parent)
4055 nsWindow
*win
= GetNSWindowPtr(toplevelWnd
);
4057 return win
->DispatchFocus(aEventType
);
4063 // Deal with focus messages
4064 PRBool
nsWindow::DispatchFocus(PRUint32 aEventType
)
4066 // call the event callback
4067 if (mEventCallback
) {
4068 nsGUIEvent
event(PR_TRUE
, aEventType
, this);
4071 //focus and blur event should go to their base widget loc, not current mouse pos
4072 event
.refPoint
.x
= 0;
4073 event
.refPoint
.y
= 0;
4075 NPEvent pluginEvent
;
4080 pluginEvent
.event
= WM_SETFOCUS
;
4083 pluginEvent
.event
= WM_KILLFOCUS
;
4085 case NS_PLUGIN_ACTIVATE
:
4086 pluginEvent
.event
= WM_KILLFOCUS
;
4092 event
.pluginEvent
= (void *)&pluginEvent
;
4094 return DispatchWindowEvent(&event
);
4099 PRBool
nsWindow::IsTopLevelMouseExit(HWND aWnd
)
4101 DWORD pos
= ::GetMessagePos();
4103 mp
.x
= GET_X_LPARAM(pos
);
4104 mp
.y
= GET_Y_LPARAM(pos
);
4105 HWND mouseWnd
= ::WindowFromPoint(mp
);
4107 // GetTopLevelHWND will return a HWND for the window frame (which includes
4108 // the non-client area). If the mouse has moved into the non-client area,
4109 // we should treat it as a top-level exit.
4110 HWND mouseTopLevel
= nsWindow::GetTopLevelHWND(mouseWnd
);
4111 if (mouseWnd
== mouseTopLevel
)
4114 return nsWindow::GetTopLevelHWND(aWnd
) != mouseTopLevel
;
4117 PRBool
nsWindow::BlurEventsSuppressed()
4119 // are they suppressed in this window?
4120 if (mBlurSuppressLevel
> 0)
4123 // are they suppressed by any container widget?
4124 HWND parentWnd
= ::GetParent(mWnd
);
4126 nsWindow
*parent
= GetNSWindowPtr(parentWnd
);
4128 return parent
->BlurEventsSuppressed();
4133 // In some circumstances (opening dependent windows) it makes more sense
4134 // (and fixes a crash bug) to not blur the parent window. Called from
4136 void nsWindow::SuppressBlurEvents(PRBool aSuppress
)
4139 ++mBlurSuppressLevel
; // for this widget
4141 NS_ASSERTION(mBlurSuppressLevel
> 0, "unbalanced blur event suppression");
4142 if (mBlurSuppressLevel
> 0)
4143 --mBlurSuppressLevel
;
4147 PRBool
nsWindow::ConvertStatus(nsEventStatus aStatus
)
4149 return aStatus
== nsEventStatus_eConsumeNoDefault
;
4152 /**************************************************************
4156 * IPC related helpers.
4158 **************************************************************/
4164 nsWindow::IsAsyncResponseEvent(UINT aMsg
, LRESULT
& aResult
)
4170 case WM_WINDOWPOSCHANGING
:
4171 case WM_WINDOWPOSCHANGED
:
4172 case WM_PARENTNOTIFY
:
4173 case WM_ACTIVATEAPP
:
4176 case WM_CHILDACTIVATE
:
4177 case WM_IME_SETCONTEXT
:
4181 case WM_MOUSEACTIVATE
:
4182 case WM_CONTEXTMENU
:
4186 case WM_SETTINGCHANGE
:
4194 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg
);
4202 nsWindow::IPCWindowProcHandler(UINT
& msg
, WPARAM
& wParam
, LPARAM
& lParam
)
4204 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4205 "Failed to prevent a nonqueued message from running!");
4207 // Modal UI being displayed in windowless plugins.
4208 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4209 (InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
4211 if (IsAsyncResponseEvent(msg
, res
)) {
4217 // Handle certain sync plugin events sent to the parent which
4218 // trigger ipc calls that result in deadlocks.
4221 PRBool handled
= PR_FALSE
;
4224 // Windowless flash sending WM_ACTIVATE events to the main window
4225 // via calls to ShowWindow.
4227 if (lParam
!= 0 && LOWORD(wParam
) == WA_ACTIVE
&&
4228 IsWindow((HWND
)lParam
))
4231 // Wheel events forwarded from the child.
4233 case WM_MOUSEHWHEEL
:
4236 // Plugins taking or losing focus triggering focus app messages.
4239 // Windowed plugins that pass sys key events to defwndproc generate
4240 // WM_SYSCOMMAND events to the main window.
4242 // Windowed plugins that fire context menu selection events to parent
4244 case WM_CONTEXTMENU
:
4245 // IME events fired as a result of synchronous focus changes
4246 case WM_IME_SETCONTEXT
:
4252 (InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
4253 ReplyMessage(dwResult
);
4259 /**************************************************************
4260 **************************************************************
4262 ** BLOCK: Native events
4264 ** Main Windows message handlers and OnXXX handlers for
4265 ** Windows event handling.
4267 **************************************************************
4268 **************************************************************/
4270 /**************************************************************
4272 * SECTION: Wind proc.
4274 * The main Windows event procedures and associated
4275 * message processing methods.
4277 **************************************************************/
4280 static int ReportException(EXCEPTION_POINTERS
*aExceptionInfo
)
4282 #ifdef MOZ_CRASHREPORTER
4283 nsCOMPtr
<nsICrashReporter
> cr
=
4284 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
4286 cr
->WriteMinidumpForException(aExceptionInfo
);
4288 return EXCEPTION_EXECUTE_HANDLER
;
4292 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
4293 // exceptions and passes the real work to WindowProcInternal. See bug 587406
4294 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
4295 LRESULT CALLBACK
nsWindow::WindowProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
4299 return WindowProcInternal(hWnd
, msg
, wParam
, lParam
);
4301 __except(ReportException(GetExceptionInformation())) {
4302 ::TerminateProcess(::GetCurrentProcess(), 253);
4305 return WindowProcInternal(hWnd
, msg
, wParam
, lParam
);
4309 LRESULT CALLBACK
nsWindow::WindowProcInternal(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
4311 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4312 MOZ_FUNCTION_NAME
, __LINE__
, hWnd
, msg
,
4315 // Get the window which caused the event and ask it to process the message
4316 nsWindow
*someWindow
= GetNSWindowPtr(hWnd
);
4320 someWindow
->IPCWindowProcHandler(msg
, wParam
, lParam
);
4323 // create this here so that we store the last rolled up popup until after
4324 // the event has been processed.
4325 nsAutoRollup autoRollup
;
4327 LRESULT popupHandlingResult
;
4328 if (DealWithPopups(hWnd
, msg
, wParam
, lParam
, &popupHandlingResult
))
4329 return popupHandlingResult
;
4331 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4332 // why we are hitting this assert
4333 if (nsnull
== someWindow
) {
4334 NS_ASSERTION(someWindow
, "someWindow is null, cannot call any CallWindowProc");
4335 return ::DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
4338 // hold on to the window for the life of this method, in case it gets
4339 // deleted during processing. yes, it's a double hack, since someWindow
4340 // is not really an interface.
4341 nsCOMPtr
<nsISupports
> kungFuDeathGrip
;
4342 if (!someWindow
->mInDtor
) // not if we're in the destructor!
4343 kungFuDeathGrip
= do_QueryInterface((nsBaseWidget
*)someWindow
);
4345 // Call ProcessMessage
4347 if (PR_TRUE
== someWindow
->ProcessMessage(msg
, wParam
, lParam
, &retValue
)) {
4351 LRESULT res
= ::CallWindowProcW(someWindow
->GetPrevWindowProc(),
4352 hWnd
, msg
, wParam
, lParam
);
4357 // The main windows message processing method for plugins.
4358 // The result means whether this method processed the native
4359 // event for plugin. If false, the native event should be
4360 // processed by the caller self.
4362 nsWindow::ProcessMessageForPlugin(const MSG
&aMsg
,
4364 PRBool
&aCallDefWndProc
)
4366 NS_PRECONDITION(aResult
, "aResult must be non-null.");
4369 aCallDefWndProc
= PR_FALSE
;
4370 PRBool eventDispatched
= PR_FALSE
;
4371 switch (aMsg
.message
) {
4374 *aResult
= ProcessCharMessage(aMsg
, &eventDispatched
);
4379 *aResult
= ProcessKeyUpMessage(aMsg
, &eventDispatched
);
4384 *aResult
= ProcessKeyDownMessage(aMsg
, &eventDispatched
);
4388 case WM_SYSDEADCHAR
:
4389 case WM_CONTEXTMENU
:
4402 if (!eventDispatched
)
4403 aCallDefWndProc
= !DispatchPluginEvent(aMsg
);
4404 DispatchPendingEvents();
4408 // The main windows message processing method.
4409 PRBool
nsWindow::ProcessMessage(UINT msg
, WPARAM
&wParam
, LPARAM
&lParam
,
4412 // (Large blocks of code should be broken out into OnEvent handlers.)
4413 if (mWindowHook
.Notify(mWnd
, msg
, wParam
, lParam
, aRetValue
))
4416 #if defined(EVENT_DEBUG_OUTPUT)
4417 // First param shows all events, second param indicates whether
4418 // to show mouse move events. See nsWindowDbg for details.
4419 PrintEvent(msg
, SHOW_REPEAT_EVENTS
, SHOW_MOUSEMOVE_EVENTS
);
4423 if (nsIMM32Handler::ProcessMessage(this, msg
, wParam
, lParam
, aRetValue
,
4425 return mWnd
? eatMessage
: PR_TRUE
;
4428 if (PluginHasFocus()) {
4429 PRBool callDefaultWndProc
;
4430 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4431 if (ProcessMessageForPlugin(nativeMsg
, aRetValue
, callDefaultWndProc
)) {
4432 return mWnd
? !callDefaultWndProc
: PR_TRUE
;
4436 PRBool result
= PR_FALSE
; // call the default nsWindow proc
4439 static PRBool getWheelInfo
= PR_TRUE
;
4441 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4442 // Glass hit testing w/custom transparent margins
4443 LRESULT dwmHitResult
;
4444 if (mCustomNonClient
&&
4445 nsUXThemeData::CheckForCompositor() &&
4446 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd
, msg
, wParam
, lParam
, &dwmHitResult
)) {
4447 *aRetValue
= dwmHitResult
;
4450 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4454 // WM_QUERYENDSESSION must be handled by all windows.
4455 // Otherwise Windows thinks the window can just be killed at will.
4456 case WM_QUERYENDSESSION
:
4457 if (sCanQuit
== TRI_UNKNOWN
)
4459 // Ask if it's ok to quit, and store the answer until we
4460 // get WM_ENDSESSION signaling the round is complete.
4461 nsCOMPtr
<nsIObserverService
> obsServ
=
4462 mozilla::services::GetObserverService();
4463 nsCOMPtr
<nsISupportsPRBool
> cancelQuit
=
4464 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID
);
4465 cancelQuit
->SetData(PR_FALSE
);
4466 obsServ
->NotifyObservers(cancelQuit
, "quit-application-requested", nsnull
);
4469 cancelQuit
->GetData(&abortQuit
);
4470 sCanQuit
= abortQuit
? TRI_FALSE
: TRI_TRUE
;
4472 *aRetValue
= sCanQuit
? TRUE
: FALSE
;
4480 case MOZ_WM_APP_QUIT
:
4481 if (msg
== MOZ_WM_APP_QUIT
|| (wParam
== TRUE
&& sCanQuit
== TRI_TRUE
))
4483 // Let's fake a shutdown sequence without actually closing windows etc.
4484 // to avoid Windows killing us in the middle. A proper shutdown would
4485 // require having a chance to pump some messages. Unfortunately
4486 // Windows won't let us do that. Bug 212316.
4487 nsCOMPtr
<nsIObserverService
> obsServ
=
4488 mozilla::services::GetObserverService();
4489 NS_NAMED_LITERAL_STRING(context
, "shutdown-persist");
4490 obsServ
->NotifyObservers(nsnull
, "quit-application-granted", nsnull
);
4491 obsServ
->NotifyObservers(nsnull
, "quit-application-forced", nsnull
);
4492 obsServ
->NotifyObservers(nsnull
, "quit-application", nsnull
);
4493 obsServ
->NotifyObservers(nsnull
, "profile-change-net-teardown", context
.get());
4494 obsServ
->NotifyObservers(nsnull
, "profile-change-teardown", context
.get());
4495 obsServ
->NotifyObservers(nsnull
, "profile-before-change", context
.get());
4496 // Then a controlled but very quick exit.
4499 sCanQuit
= TRI_UNKNOWN
;
4504 case WM_DISPLAYCHANGE
:
4505 DispatchStandardEvent(NS_DISPLAYCHANGED
);
4509 case WM_SYSCOLORCHANGE
:
4510 // Note: This is sent for child windows as well as top-level windows.
4511 // The Win32 toolkit normally only sends these events to top-level windows.
4512 // But we cycle through all of the childwindows and send it to them as well
4513 // so all presentations get notified properly.
4514 // See nsWindow::GlobalMsgWindowProc.
4515 DispatchStandardEvent(NS_SYSCOLORCHANGED
);
4521 LPNMHDR pnmh
= (LPNMHDR
) lParam
;
4523 switch (pnmh
->code
) {
4526 DispatchStandardEvent(NS_TABCHANGE
);
4534 case WM_XP_THEMECHANGED
:
4536 // Update non-client margin offsets
4537 UpdateNonClientMargins();
4539 DispatchStandardEvent(NS_THEMECHANGED
);
4541 // Invalidate the window so that the repaint will
4542 // pick up the new theme.
4543 Invalidate(PR_FALSE
);
4550 PRBool didChange
= PR_FALSE
;
4552 // update the global font list
4553 nsCOMPtr
<nsIFontEnumerator
> fontEnum
= do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv
);
4554 if (NS_SUCCEEDED(rv
)) {
4555 fontEnum
->UpdateFontList(&didChange
);
4556 //didChange is TRUE only if new font langGroup is added to the list.
4558 // update device context font cache
4559 // Dirty but easiest way:
4560 // Changing nsIPrefBranch entry which triggers callbacks
4561 // and flows into calling mDeviceContext->FlushFontCache()
4562 // to update the font cache in all the instance of Browsers
4563 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
4565 nsCOMPtr
<nsIPrefBranch
> fiPrefs
;
4566 prefs
->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs
));
4568 PRBool fontInternalChange
= PR_FALSE
;
4569 fiPrefs
->GetBoolPref("changed", &fontInternalChange
);
4570 fiPrefs
->SetBoolPref("changed", !fontInternalChange
);
4574 } //if (NS_SUCCEEDED(rv))
4580 // If wParam is TRUE, it specifies that the application should indicate
4581 // which part of the client area contains valid information. The system
4582 // copies the valid information to the specified area within the new
4583 // client area. If the wParam parameter is FALSE, the application should
4585 if (mCustomNonClient
) {
4593 // rgrc[0]: the proposed window
4594 // rgrc[1]: the current window
4595 // rgrc[2]: the source client area
4596 // pncsp->lppos: move/size data
4598 // rgrc[0]: the new client area
4599 // rgrc[1]: the destination window
4600 // rgrc[2]: the source client area
4601 // (all values in screen coordiantes)
4602 NCCALCSIZE_PARAMS
*pncsp
= reinterpret_cast<NCCALCSIZE_PARAMS
*>(lParam
);
4603 LRESULT res
= CallWindowProcW(GetPrevWindowProc(), mWnd
, msg
, wParam
, lParam
);
4604 pncsp
->rgrc
[0].top
-= mNonClientOffset
.top
;
4605 pncsp
->rgrc
[0].left
-= mNonClientOffset
.left
;
4606 pncsp
->rgrc
[0].right
+= mNonClientOffset
.right
;
4607 pncsp
->rgrc
[0].bottom
+= mNonClientOffset
.bottom
;
4618 * If an nc client area margin has been moved, we are responsible
4619 * for calculating where the resize margins are and returning the
4620 * appropriate set of hit test constants. DwmDefWindowProc (above)
4621 * will handle hit testing on it's command buttons if we are on a
4622 * composited desktop.
4625 if (!mCustomNonClient
)
4629 ClientMarginHitTestPoint(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
4636 * WM_SETTEXT paints the titlebar area. Avoid this if we have a
4637 * custom titlebar we paint ourselves.
4640 if (!mCustomNonClient
|| mNonClientMargins
.top
== -1)
4644 // From msdn, the way around this is to disable the visible state
4645 // temporarily. We need the text to be set but we don't want the
4647 DWORD style
= GetWindowLong(mWnd
, GWL_STYLE
);
4648 SetWindowLong(mWnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
4649 *aRetValue
= CallWindowProcW(GetPrevWindowProc(), mWnd
,
4650 msg
, wParam
, lParam
);
4651 SetWindowLong(mWnd
, GWL_STYLE
, style
);
4658 * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
4659 * through WM_NCPAINT via InvalidateNonClientRegion.
4662 if (!mCustomNonClient
)
4665 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4666 // let the dwm handle nc painting on glass
4667 if(nsUXThemeData::CheckForCompositor())
4671 if (wParam
== TRUE
) {
4673 *aRetValue
= FALSE
; // ignored
4675 // invalidate to trigger a paint
4676 InvalidateNonClientRegion();
4680 *aRetValue
= TRUE
; // go ahead and deactive
4682 // invalidate to trigger a paint
4683 InvalidateNonClientRegion();
4691 * Reset the non-client paint region so that it excludes the
4692 * non-client areas we paint manually. Then call defwndproc
4693 * to do the actual painting.
4696 if (!mCustomNonClient
)
4699 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4700 // let the dwm handle nc painting on glass
4701 if(nsUXThemeData::CheckForCompositor())
4705 HRGN paintRgn
= ExcludeNonClientFromPaintRegion((HRGN
)wParam
);
4706 LRESULT res
= CallWindowProcW(GetPrevWindowProc(), mWnd
,
4707 msg
, (WPARAM
)paintRgn
, lParam
);
4708 if (paintRgn
!= (HRGN
)wParam
)
4709 DeleteObject(paintRgn
);
4716 case WM_POWERBROADCAST
:
4717 // only hidden window handle this
4718 // to prevent duplicate notification
4719 if (mWindowType
== eWindowType_invisible
) {
4722 case PBT_APMSUSPEND
:
4723 PostSleepWakeNotification("sleep_notification");
4725 case PBT_APMRESUMEAUTOMATIC
:
4726 case PBT_APMRESUMECRITICAL
:
4727 case PBT_APMRESUMESUSPEND
:
4728 PostSleepWakeNotification("wake_notification");
4735 case WM_MOVE
: // Window moved
4738 ::GetWindowRect(mWnd
, &rect
);
4739 result
= OnMove(rect
.left
, rect
.top
);
4743 case WM_CLOSE
: // close request
4744 DispatchStandardEvent(NS_XUL_CLOSE
);
4745 result
= PR_TRUE
; // abort window closure
4755 *aRetValue
= (int) OnPaint(NULL
, 0);
4760 case WM_PRINTCLIENT
:
4761 result
= OnPaint((HDC
) wParam
, 0);
4766 result
= OnHotKey(wParam
, lParam
);
4772 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4773 result
= ProcessCharMessage(nativeMsg
, nsnull
);
4774 DispatchPendingEvents();
4781 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4782 result
= ProcessKeyUpMessage(nativeMsg
, nsnull
);
4783 DispatchPendingEvents();
4790 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4791 result
= ProcessKeyDownMessage(nativeMsg
, nsnull
);
4792 DispatchPendingEvents();
4796 // say we've dealt with erase background if widget does
4797 // not need auto-erasing
4799 if (!AutoErase((HDC
)wParam
)) {
4807 #ifdef WINCE_WINDOWS_MOBILE
4808 // Reset the kill timer so that we can continue at this
4810 SetTimer(mWnd
, KILL_PRIORITY_ID
, 2000 /* 2seconds */, NULL
);
4812 // Suppress dispatch of pending events
4813 // when mouse moves are generated by widget
4814 // creation instead of user input.
4815 LPARAM lParamScreen
= lParamToScreen(lParam
);
4817 mp
.x
= GET_X_LPARAM(lParamScreen
);
4818 mp
.y
= GET_Y_LPARAM(lParamScreen
);
4819 PRBool userMovedMouse
= PR_FALSE
;
4820 if ((sLastMouseMovePoint
.x
!= mp
.x
) || (sLastMouseMovePoint
.y
!= mp
.y
)) {
4821 userMovedMouse
= PR_TRUE
;
4823 mExitToNonClientArea
= PR_FALSE
;
4825 result
= DispatchMouseEvent(NS_MOUSE_MOVE
, wParam
, lParam
,
4826 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4827 if (userMovedMouse
) {
4828 DispatchPendingEvents();
4833 #ifdef WINCE_WINDOWS_MOBILE
4835 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL
);
4836 KillTimer(mWnd
, KILL_PRIORITY_ID
);
4840 case WM_LBUTTONDOWN
:
4842 #ifdef WINCE_WINDOWS_MOBILE
4843 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL
);
4844 SetTimer(mWnd
, KILL_PRIORITY_ID
, 2000 /* 2 seconds */, NULL
);
4846 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
,
4847 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4848 DispatchPendingEvents();
4854 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
,
4855 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4856 DispatchPendingEvents();
4858 #ifdef WINCE_WINDOWS_MOBILE
4859 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL
);
4860 KillTimer(mWnd
, KILL_PRIORITY_ID
);
4868 // We need to check mouse button states and put them in for
4870 WPARAM mouseState
= (GetKeyState(VK_LBUTTON
) ? MK_LBUTTON
: 0)
4871 | (GetKeyState(VK_MBUTTON
) ? MK_MBUTTON
: 0)
4872 | (GetKeyState(VK_RBUTTON
) ? MK_RBUTTON
: 0);
4873 // Synthesize an event position because we don't get one from
4875 LPARAM pos
= lParamToClient(::GetMessagePos());
4876 DispatchMouseEvent(NS_MOUSE_EXIT
, mouseState
, pos
, PR_FALSE
,
4877 nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4882 case WM_CONTEXTMENU
:
4884 // if the context menu is brought up from the keyboard, |lParam|
4887 PRBool contextMenukey
= PR_FALSE
;
4890 contextMenukey
= PR_TRUE
;
4891 pos
= lParamToClient(GetMessagePos());
4895 pos
= lParamToClient(lParam
);
4898 result
= DispatchMouseEvent(NS_CONTEXTMENU
, wParam
, pos
, contextMenukey
,
4900 nsMouseEvent::eLeftButton
:
4901 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4905 case WM_LBUTTONDBLCLK
:
4906 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4907 nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4910 case WM_MBUTTONDOWN
:
4912 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4913 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4914 DispatchPendingEvents();
4919 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, PR_FALSE
,
4920 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4921 DispatchPendingEvents();
4924 case WM_MBUTTONDBLCLK
:
4925 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4926 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4929 case WM_NCMBUTTONDOWN
:
4930 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, 0, lParamToClient(lParam
), PR_FALSE
,
4931 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4932 DispatchPendingEvents();
4935 case WM_NCMBUTTONUP
:
4936 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, 0, lParamToClient(lParam
), PR_FALSE
,
4937 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4938 DispatchPendingEvents();
4941 case WM_NCMBUTTONDBLCLK
:
4942 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, 0, lParamToClient(lParam
), PR_FALSE
,
4943 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4944 DispatchPendingEvents();
4947 case WM_RBUTTONDOWN
:
4949 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4950 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4951 DispatchPendingEvents();
4956 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, PR_FALSE
,
4957 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4958 DispatchPendingEvents();
4961 case WM_RBUTTONDBLCLK
:
4962 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4963 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4966 case WM_NCRBUTTONDOWN
:
4967 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, 0, lParamToClient(lParam
),
4968 PR_FALSE
, nsMouseEvent::eRightButton
,
4969 MOUSE_INPUT_SOURCE());
4970 DispatchPendingEvents();
4973 case WM_NCRBUTTONUP
:
4974 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, 0, lParamToClient(lParam
),
4975 PR_FALSE
, nsMouseEvent::eRightButton
,
4976 MOUSE_INPUT_SOURCE());
4977 DispatchPendingEvents();
4980 case WM_NCRBUTTONDBLCLK
:
4981 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, 0, lParamToClient(lParam
),
4982 PR_FALSE
, nsMouseEvent::eRightButton
,
4983 MOUSE_INPUT_SOURCE());
4987 PRUint32 appCommand
= GET_APPCOMMAND_LPARAM(lParam
);
4991 case APPCOMMAND_BROWSER_BACKWARD
:
4992 case APPCOMMAND_BROWSER_FORWARD
:
4993 case APPCOMMAND_BROWSER_REFRESH
:
4994 case APPCOMMAND_BROWSER_STOP
:
4995 case APPCOMMAND_BROWSER_SEARCH
:
4996 case APPCOMMAND_BROWSER_FAVORITES
:
4997 case APPCOMMAND_BROWSER_HOME
:
4998 DispatchCommandEvent(appCommand
);
4999 // tell the driver that we handled the event
5004 // default = PR_FALSE - tell the driver that the event was not handled
5011 result
= OnScroll(msg
, wParam
, lParam
);
5014 // The WM_ACTIVATE event is fired when a window is raised or lowered,
5015 // and the loword of wParam specifies which. But we don't want to tell
5016 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
5017 // events are fired. Instead, set either the sJustGotActivate or
5018 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
5019 // events once the focus events arrive.
5021 if (mEventCallback
) {
5022 PRInt32 fActive
= LOWORD(wParam
);
5024 #if defined(WINCE_HAVE_SOFTKB)
5025 if (mIsTopWidgetWindow
&& sSoftKeyboardState
)
5026 nsWindowCE::ToggleSoftKB(mWnd
, fActive
);
5027 if (nsWindowCE::sShowSIPButton
== TRI_FALSE
&& WA_INACTIVE
!= fActive
) {
5028 HWND hWndSIPB
= FindWindowW(L
"MS_SIPBUTTON", NULL
);
5030 ShowWindow(hWndSIPB
, SW_HIDE
);
5035 if (WA_INACTIVE
== fActive
) {
5036 // when minimizing a window, the deactivation and focus events will
5037 // be fired in the reverse order. Instead, just dispatch
5038 // NS_DEACTIVATE right away.
5040 result
= DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5042 sJustGotDeactivate
= PR_TRUE
;
5044 if (mIsTopWidgetWindow
)
5045 mLastKeyboardLayout
= gKbdLayout
.GetLayout();
5051 sJustGotActivate
= PR_TRUE
;
5052 nsMouseEvent
event(PR_TRUE
, NS_MOUSE_ACTIVATE
, this,
5053 nsMouseEvent::eReal
);
5056 event
.acceptActivation
= PR_TRUE
;
5058 DispatchWindowEvent(&event
);
5060 if (event
.acceptActivation
)
5061 *aRetValue
= MA_ACTIVATE
;
5063 *aRetValue
= MA_NOACTIVATE
;
5065 if (sSwitchKeyboardLayout
&& mLastKeyboardLayout
)
5066 ActivateKeyboardLayout(mLastKeyboardLayout
, 0);
5072 #ifdef WINCE_WINDOWS_MOBILE
5073 if (!gCheckForHTCApi
&& gHTCApiNavOpen
== nsnull
) {
5074 gCheckForHTCApi
= PR_TRUE
;
5076 HINSTANCE library
= LoadLibrary(L
"HTCAPI.dll");
5077 gHTCApiNavOpen
= (HTCApiNavOpen
) GetProcAddress(library
, "HTCNavOpen");
5078 gHTCApiNavSetMode
= (HTCApiNavSetMode
) GetProcAddress(library
,"HTCNavSetMode");
5081 if (gHTCApiNavOpen
!= nsnull
) {
5082 gHTCApiNavOpen(mWnd
, 1 /* undocumented value */);
5084 if (gHTCApiNavSetMode
!= nsnull
)
5085 gHTCApiNavSetMode ( mWnd
, 4);
5086 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5092 case WM_MOUSEACTIVATE
:
5093 if (mWindowType
== eWindowType_popup
) {
5094 // a popup with a parent owner should not be activated when clicked
5095 // but should still allow the mouse event to be fired, so the return
5096 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5097 // window, just use default processing so that the window is activated.
5098 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
5099 if (owner
&& owner
== ::GetForegroundWindow()) {
5100 *aRetValue
= MA_NOACTIVATE
;
5106 case WM_WINDOWPOSCHANGING
:
5108 LPWINDOWPOS info
= (LPWINDOWPOS
) lParam
;
5109 OnWindowPosChanging(info
);
5115 if (sJustGotActivate
) {
5116 result
= DispatchFocusToTopLevelWindow(NS_ACTIVATE
);
5119 #ifdef ACCESSIBILITY
5120 if (nsWindow::sIsAccessibilityOn
) {
5121 // Create it for the first time so that it can start firing events
5122 nsAccessible
*rootAccessible
= GetRootAccessible();
5126 #if defined(WINCE_HAVE_SOFTKB)
5128 // On Windows CE, we have a window that overlaps
5129 // the ISP button. In this case, we should always
5130 // try to hide it when we are activated
5132 nsIMEContext
IMEContext(mWnd
);
5134 ImmSetOpenStatus(IMEContext
.get(), TRUE
);
5140 #if defined(WINCE_HAVE_SOFTKB)
5142 nsIMEContext
IMEContext(mWnd
);
5143 ImmSetOpenStatus(IMEContext
.get(), FALSE
);
5146 if (sJustGotDeactivate
) {
5147 result
= DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5151 case WM_WINDOWPOSCHANGED
:
5153 WINDOWPOS
*wp
= (LPWINDOWPOS
)lParam
;
5154 OnWindowPosChanged(wp
, result
);
5158 case WM_SETTINGCHANGE
:
5159 #if !defined (WINCE_WINDOWS_MOBILE)
5160 getWheelInfo
= PR_TRUE
;
5163 case SPI_SETSIPINFO
:
5164 case SPI_SETCURRENTIM
:
5165 nsWindowCE::OnSoftKbSettingsChange(mWnd
);
5167 case SETTINGCHANGE_RESET
:
5168 if (mWindowType
== eWindowType_invisible
) {
5169 // The OS sees to get confused and think that the invisable window
5170 // is in the foreground after an orientation change. By actually
5171 // setting it to the foreground and hiding it, we set it strait.
5172 // See bug 514007 for details.
5173 SetForegroundWindow(mWnd
);
5174 ShowWindow(mWnd
, SW_HIDE
);
5179 OnSettingsChange(wParam
, lParam
);
5183 case WM_INPUTLANGCHANGEREQUEST
:
5188 case WM_INPUTLANGCHANGE
:
5189 result
= OnInputLangChange((HKL
)lParam
);
5193 case WM_DESTROYCLIPBOARD
:
5195 nsIClipboard
* clipboard
;
5196 nsresult rv
= CallGetService(kCClipboardCID
, &clipboard
);
5197 if(NS_SUCCEEDED(rv
)) {
5198 clipboard
->EmptyClipboard(nsIClipboard::kGlobalClipboard
);
5199 NS_RELEASE(clipboard
);
5204 #ifdef ACCESSIBILITY
5208 if (lParam
== OBJID_CLIENT
) { // oleacc.dll will be loaded dynamically
5209 nsAccessible
*rootAccessible
= GetRootAccessible(); // Held by a11y cache
5210 if (rootAccessible
) {
5211 IAccessible
*msaaAccessible
= NULL
;
5212 rootAccessible
->GetNativeInterface((void**)&msaaAccessible
); // does an addref
5213 if (msaaAccessible
) {
5214 *aRetValue
= LresultFromObject(IID_IAccessible
, wParam
, msaaAccessible
); // does an addref
5215 msaaAccessible
->Release(); // release extra addref
5216 result
= PR_TRUE
; // We handled the WM_GETOBJECT message
5225 // prevent Windows from trimming the working set. bug 76831
5226 if (!sTrimOnMinimize
&& wParam
== SC_MINIMIZE
) {
5227 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
5236 nsMemory::HeapMinimize(PR_TRUE
);
5241 case WM_MOUSEHWHEEL
:
5243 // If OnMouseWheel returns true, the event was forwarded directly to another
5244 // mozilla window message handler (ProcessMessage). In this case the return
5245 // value of the forwarded event is in 'result' which we should return immediately.
5246 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5247 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5248 // we should fall through.
5249 if (OnMouseWheel(msg
, wParam
, lParam
, getWheelInfo
, result
, aRetValue
))
5255 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5256 case WM_DWMCOMPOSITIONCHANGED
:
5257 UpdateNonClientMargins();
5258 BroadcastMsg(mWnd
, WM_DWMCOMPOSITIONCHANGED
);
5259 DispatchStandardEvent(NS_THEMECHANGED
);
5261 Invalidate(PR_FALSE
);
5265 case WM_UPDATEUISTATE
:
5267 // If the UI state has changed, fire an event so the UI updates the
5268 // keyboard cues based on the system setting and how the window was
5269 // opened. For example, a dialog opened via a keyboard press on a button
5270 // should enable cues, whereas the same dialog opened via a mouse click of
5271 // the button should not.
5272 PRInt32 action
= LOWORD(wParam
);
5273 if (action
== UIS_SET
|| action
== UIS_CLEAR
) {
5274 nsUIStateChangeEvent
event(PR_TRUE
, NS_UISTATECHANGED
, this);
5275 PRInt32 flags
= HIWORD(wParam
);
5276 if (flags
& UISF_HIDEACCEL
)
5277 event
.showAccelerators
= (action
== UIS_SET
) ? UIStateChangeType_Clear
: UIStateChangeType_Set
;
5278 if (flags
& UISF_HIDEFOCUS
)
5279 event
.showFocusRings
= (action
== UIS_SET
) ? UIStateChangeType_Clear
: UIStateChangeType_Set
;
5280 DispatchWindowEvent(&event
);
5286 /* Gesture support events */
5287 case WM_TABLET_QUERYSYSTEMGESTURESTATUS
:
5288 // According to MS samples, this must be handled to enable
5289 // rotational support in multi-touch drivers.
5291 *aRetValue
= TABLET_ROTATE_GESTURE_ENABLE
;
5294 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5296 result
= OnTouch(wParam
, lParam
);
5304 result
= OnGesture(wParam
, lParam
);
5307 case WM_GESTURENOTIFY
:
5309 if (mWindowType
!= eWindowType_invisible
&&
5310 mWindowType
!= eWindowType_plugin
) {
5311 // A GestureNotify event is dispatched to decide which single-finger panning
5312 // direction should be active (including none) and if pan feedback should
5313 // be displayed. Java and plugin windows can make their own calls.
5314 GESTURENOTIFYSTRUCT
* gestureinfo
= (GESTURENOTIFYSTRUCT
*)lParam
;
5315 nsPointWin touchPoint
;
5316 touchPoint
= gestureinfo
->ptsLocation
;
5317 touchPoint
.ScreenToClient(mWnd
);
5318 nsGestureNotifyEvent
gestureNotifyEvent(PR_TRUE
, NS_GESTURENOTIFY_EVENT_START
, this);
5319 gestureNotifyEvent
.refPoint
= touchPoint
;
5320 nsEventStatus status
;
5321 DispatchEvent(&gestureNotifyEvent
, status
);
5322 mDisplayPanFeedback
= gestureNotifyEvent
.displayPanFeedback
;
5324 mGesture
.SetWinGestureSupport(mWnd
, gestureNotifyEvent
.panDirection
);
5326 result
= PR_FALSE
; //should always bubble to DefWindowProc
5329 #endif // !defined(WINCE)
5333 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_DELETE
, this);
5334 DispatchWindowEvent(&command
);
5341 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_CUT
, this);
5342 DispatchWindowEvent(&command
);
5349 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_COPY
, this);
5350 DispatchWindowEvent(&command
);
5357 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_PASTE
, this);
5358 DispatchWindowEvent(&command
);
5366 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_UNDO
, this);
5367 DispatchWindowEvent(&command
);
5368 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5375 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_REDO
, this);
5376 DispatchWindowEvent(&command
);
5377 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5384 // Support EM_CANPASTE message only when wParam isn't specified or
5385 // is plain text format.
5386 if (wParam
== 0 || wParam
== CF_TEXT
|| wParam
== CF_UNICODETEXT
) {
5387 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_PASTE
,
5389 DispatchWindowEvent(&command
);
5390 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5398 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_UNDO
,
5400 DispatchWindowEvent(&command
);
5401 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5408 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_REDO
,
5410 DispatchWindowEvent(&command
);
5411 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5417 #ifdef WINCE_WINDOWS_MOBILE
5418 //HTC NAVIGATION WHEEL EVENT
5421 int distance
= wParam
& 0x000000FF;
5422 if ( (wParam
& 0x000000100) != 0) // Counter Clockwise
5424 if (OnMouseWheel(WM_MOUSEWHEEL
, MAKEWPARAM(0, distance
),
5425 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN
) / 2,
5426 GetSystemMetrics(SM_CYSCREEN
) / 2),
5427 getWheelInfo
, result
, aRetValue
))
5435 #ifdef NS_ENABLE_TSF
5436 if (msg
== WM_USER_TSF_TEXTCHANGE
) {
5437 nsTextStore::OnTextChangeMsg();
5439 #endif //NS_ENABLE_TSF
5440 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5441 if (msg
== nsAppShell::GetTaskbarButtonCreatedMessage())
5442 SetHasTaskbarIconBeenCreated();
5445 if (msg
== sOOPPPluginFocusEvent
) {
5447 // With OOPP, the plugin window exists in another process and is a child of
5448 // this window. This window is a placeholder plugin window for the dom. We
5449 // receive this event when the child window receives focus. (sent from
5450 // PluginInstanceParent.cpp)
5451 ::SendMessage(mWnd
, WM_MOUSEACTIVATE
, 0, 0); // See nsPluginNativeWindowWin.cpp
5453 // WM_KILLFOCUS was received by the child process.
5454 if (sJustGotDeactivate
) {
5455 DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5464 //*aRetValue = result;
5469 //Events which caused mWnd destruction and aren't consumed
5470 //will crash during the Windows default processing.
5475 /**************************************************************
5477 * SECTION: Broadcast messaging
5479 * Broadcast messages to all windows.
5481 **************************************************************/
5483 // Enumerate all child windows sending aMsg to each of them
5484 BOOL CALLBACK
nsWindow::BroadcastMsgToChildren(HWND aWnd
, LPARAM aMsg
)
5486 WNDPROC winProc
= (WNDPROC
)::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
5487 if (winProc
== &nsWindow::WindowProc
) {
5488 // it's one of our windows so go ahead and send a message to it
5489 ::CallWindowProcW(winProc
, aWnd
, aMsg
, 0, 0);
5494 // Enumerate all top level windows specifying that the children of each
5495 // top level window should be enumerated. Do *not* send the message to
5496 // each top level window since it is assumed that the toolkit will send
5497 // aMsg to them directly.
5498 BOOL CALLBACK
nsWindow::BroadcastMsg(HWND aTopWindow
, LPARAM aMsg
)
5500 // Iterate each of aTopWindows child windows sending the aMsg
5503 ::EnumChildWindows(aTopWindow
, nsWindow::BroadcastMsgToChildren
, aMsg
);
5505 nsWindowCE::EnumChildWindows(aTopWindow
, nsWindow::BroadcastMsgToChildren
, aMsg
);
5510 // This method is called from nsToolkit::WindowProc to forward global
5511 // messages which need to be dispatched to all child windows.
5512 void nsWindow::GlobalMsgWindowProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
5515 case WM_SYSCOLORCHANGE
:
5516 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5517 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5518 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5519 // all child windows as well. When running in an embedded application
5520 // we may not receive a WM_SYSCOLORCHANGE message because the top
5521 // level window is owned by the embeddor.
5522 // System color changes are posted to top-level windows only.
5523 // The NS_SYSCOLORCHANGE must be dispatched to all child
5526 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg
, msg
);
5532 /**************************************************************
5534 * SECTION: Event processing helpers
5536 * Special processing for certain event types and
5537 * synthesized events.
5539 **************************************************************/
5542 nsWindow::ClientMarginHitTestPoint(PRInt32 mx
, PRInt32 my
)
5544 // Calculations are done in screen coords
5546 GetWindowRect(mWnd
, &winRect
);
5548 // hit return constants:
5549 // HTBORDER - non-resizable border
5550 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5551 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5552 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5553 // HTCAPTION - general title bar area
5554 // HTCLIENT - area considered the client
5555 // HTCLOSE - hovering over the close button
5556 // HTMAXBUTTON - maximize button
5557 // HTMINBUTTON - minimize button
5559 PRInt32 testResult
= HTCLIENT
;
5561 PRBool top
= PR_FALSE
;
5562 PRBool bottom
= PR_FALSE
;
5563 PRBool left
= PR_FALSE
;
5564 PRBool right
= PR_FALSE
;
5566 if (my
>= winRect
.top
&& my
<=
5567 (winRect
.top
+ mVertResizeMargin
+ (mCaptionHeight
- mNonClientOffset
.top
)))
5569 else if (my
<= winRect
.bottom
&& my
>= (winRect
.bottom
- mVertResizeMargin
))
5572 if (mx
>= winRect
.left
&& mx
<= (winRect
.left
+ mHorResizeMargin
))
5574 else if (mx
<= winRect
.right
&& mx
>= (winRect
.right
- mHorResizeMargin
))
5580 testResult
= HTTOPLEFT
;
5582 testResult
= HTTOPRIGHT
;
5583 } else if (bottom
) {
5584 testResult
= HTBOTTOM
;
5586 testResult
= HTBOTTOMLEFT
;
5588 testResult
= HTBOTTOMRIGHT
;
5591 testResult
= HTLEFT
;
5593 testResult
= HTRIGHT
;
5596 PRBool contentOverlap
= PR_TRUE
;
5598 if (mSizeMode
== nsSizeMode_Maximized
) {
5599 // There's no HTTOP in maximized state (bug 575493)
5600 if (testResult
== HTTOP
) {
5601 testResult
= HTCAPTION
;
5604 PRInt32 leftMargin
= mNonClientMargins
.left
== -1 ? mHorResizeMargin
: mNonClientMargins
.left
;
5605 PRInt32 rightMargin
= mNonClientMargins
.right
== -1 ? mHorResizeMargin
: mNonClientMargins
.right
;
5606 PRInt32 topMargin
= mNonClientMargins
.top
== -1 ? mVertResizeMargin
: mNonClientMargins
.top
;
5607 PRInt32 bottomMargin
= mNonClientMargins
.bottom
== -1 ? mVertResizeMargin
: mNonClientMargins
.bottom
;
5609 contentOverlap
= mx
>= winRect
.left
+ leftMargin
&&
5610 mx
<= winRect
.right
- rightMargin
&&
5611 my
>= winRect
.top
+ topMargin
&&
5612 my
<= winRect
.bottom
- bottomMargin
;
5615 if (!mIsInMouseCapture
&&
5617 (testResult
== HTCLIENT
||
5618 testResult
== HTTOP
||
5619 testResult
== HTTOPLEFT
||
5620 testResult
== HTCAPTION
)) {
5621 LPARAM lParam
= MAKELPARAM(mx
, my
);
5622 LPARAM lParamClient
= lParamToClient(lParam
);
5623 PRBool result
= DispatchMouseEvent(NS_MOUSE_MOZHITTEST
, 0, lParamClient
,
5624 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
5626 // The mouse is over a blank area
5627 testResult
= testResult
== HTCLIENT
? HTCAPTION
: testResult
;
5629 if (!mExitToNonClientArea
) {
5630 // The first time the mouse pointer goes from client area to non-client area,
5631 // we don't want to miss that movement so we can interpret mouseout input.
5632 ::SendMessage(mWnd
, WM_MOUSEMOVE
, 0, lParamClient
);
5633 mExitToNonClientArea
= PR_TRUE
;
5636 // There's content over the mouse pointer. Set HTCLIENT
5637 // to possibly override a resizer border.
5638 testResult
= HTCLIENT
;
5647 void nsWindow::PostSleepWakeNotification(const char* aNotification
)
5649 nsCOMPtr
<nsIObserverService
> observerService
=
5650 mozilla::services::GetObserverService();
5651 if (observerService
)
5652 observerService
->NotifyObservers(nsnull
, aNotification
, nsnull
);
5656 LRESULT
nsWindow::ProcessCharMessage(const MSG
&aMsg
, PRBool
*aEventDispatched
)
5658 NS_PRECONDITION(aMsg
.message
== WM_CHAR
|| aMsg
.message
== WM_SYSCHAR
,
5659 "message is not keydown event");
5660 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5661 ("%s charCode=%d scanCode=%d\n",
5662 aMsg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
5663 aMsg
.wParam
, HIWORD(aMsg
.lParam
) & 0xFF));
5665 // These must be checked here too as a lone WM_CHAR could be received
5666 // if a child window didn't handle it (for example Alt+Space in a content window)
5667 nsModifierKeyState modKeyState
;
5668 return OnChar(aMsg
, modKeyState
, aEventDispatched
);
5671 LRESULT
nsWindow::ProcessKeyUpMessage(const MSG
&aMsg
, PRBool
*aEventDispatched
)
5673 NS_PRECONDITION(aMsg
.message
== WM_KEYUP
|| aMsg
.message
== WM_SYSKEYUP
,
5674 "message is not keydown event");
5675 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5676 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
5677 "WM_SYSKEYUP" : "WM_KEYUP", aMsg
.wParam
));
5679 nsModifierKeyState modKeyState
;
5681 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5682 // scan code. However, this breaks Alt+Num pad input.
5683 // MSDN states the following:
5684 // Typically, ToAscii performs the translation based on the
5685 // virtual-key code. In some cases, however, bit 15 of the
5686 // uScanCode parameter may be used to distinguish between a key
5687 // press and a key release. The scan code is used for
5688 // translating ALT+number key combinations.
5690 // ignore [shift+]alt+space so the OS can handle it
5691 if (modKeyState
.mIsAltDown
&& !modKeyState
.mIsControlDown
&&
5692 IS_VK_DOWN(NS_VK_SPACE
)) {
5696 if (!nsIMM32Handler::IsComposingOn(this) &&
5697 (aMsg
.message
!= WM_KEYUP
|| aMsg
.wParam
!= VK_MENU
)) {
5698 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5699 // This helps avoid triggering the menu bar for ALT key accelerators used in
5700 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5701 // to switch back to Mozilla in Windows 95 and Windows 98
5702 return OnKeyUp(aMsg
, modKeyState
, aEventDispatched
);
5708 LRESULT
nsWindow::ProcessKeyDownMessage(const MSG
&aMsg
,
5709 PRBool
*aEventDispatched
)
5711 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5712 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
5713 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg
.wParam
));
5714 NS_PRECONDITION(aMsg
.message
== WM_KEYDOWN
|| aMsg
.message
== WM_SYSKEYDOWN
,
5715 "message is not keydown event");
5717 nsModifierKeyState modKeyState
;
5719 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
5720 // scan code. However, this breaks Alt+Num pad input.
5721 // MSDN states the following:
5722 // Typically, ToAscii performs the translation based on the
5723 // virtual-key code. In some cases, however, bit 15 of the
5724 // uScanCode parameter may be used to distinguish between a key
5725 // press and a key release. The scan code is used for
5726 // translating ALT+number key combinations.
5728 // ignore [shift+]alt+space so the OS can handle it
5729 if (modKeyState
.mIsAltDown
&& !modKeyState
.mIsControlDown
&&
5730 IS_VK_DOWN(NS_VK_SPACE
))
5734 if (modKeyState
.mIsAltDown
&& nsIMM32Handler::IsStatusChanged()) {
5735 nsIMM32Handler::NotifyEndStatusChange();
5736 } else if (!nsIMM32Handler::IsComposingOn(this)) {
5737 result
= OnKeyDown(aMsg
, modKeyState
, aEventDispatched
, nsnull
);
5741 if (aMsg
.wParam
== VK_MENU
||
5742 (aMsg
.wParam
== VK_F10
&& !modKeyState
.mIsShiftDown
)) {
5743 // We need to let Windows handle this keypress,
5744 // by returning PR_FALSE, if there's a native menu
5745 // bar somewhere in our containing window hierarchy.
5746 // Otherwise we handle the keypress and don't pass
5747 // it on to Windows, by returning PR_TRUE.
5748 PRBool hasNativeMenu
= PR_FALSE
;
5751 if (::GetMenu(hWnd
)) {
5752 hasNativeMenu
= PR_TRUE
;
5755 hWnd
= ::GetParent(hWnd
);
5757 result
= !hasNativeMenu
;
5765 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout
,
5766 PRInt32 aNativeKeyCode
,
5767 PRUint32 aModifierFlags
,
5768 const nsAString
& aCharacters
,
5769 const nsAString
& aUnmodifiedCharacters
)
5771 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
5772 nsPrintfCString
layoutName("%08x", aNativeKeyboardLayout
);
5773 HKL loadedLayout
= LoadKeyboardLayoutA(layoutName
.get(), KLF_NOTELLSHELL
);
5774 if (loadedLayout
== NULL
)
5775 return NS_ERROR_NOT_AVAILABLE
;
5777 // Setup clean key state and load desired layout
5778 BYTE originalKbdState
[256];
5779 ::GetKeyboardState(originalKbdState
);
5781 memset(kbdState
, 0, sizeof(kbdState
));
5782 // This changes the state of the keyboard for the current thread only,
5783 // and we'll restore it soon, so this should be OK.
5784 ::SetKeyboardState(kbdState
);
5785 HKL oldLayout
= gKbdLayout
.GetLayout();
5786 gKbdLayout
.LoadLayout(loadedLayout
);
5788 nsAutoTArray
<KeyPair
,10> keySequence
;
5789 SetupKeyModifiersSequence(&keySequence
, aModifierFlags
);
5790 NS_ASSERTION(aNativeKeyCode
>= 0 && aNativeKeyCode
< 256,
5791 "Native VK key code out of range");
5792 keySequence
.AppendElement(KeyPair(aNativeKeyCode
, 0));
5794 // Simulate the pressing of each modifier key and then the real key
5795 for (PRUint32 i
= 0; i
< keySequence
.Length(); ++i
) {
5796 PRUint8 key
= keySequence
[i
].mGeneral
;
5797 PRUint8 keySpecific
= keySequence
[i
].mSpecific
;
5798 kbdState
[key
] = 0x81; // key is down and toggled on if appropriate
5800 kbdState
[keySpecific
] = 0x81;
5802 ::SetKeyboardState(kbdState
);
5803 nsModifierKeyState modKeyState
;
5804 MSG msg
= InitMSG(WM_KEYDOWN
, key
, 0);
5805 if (i
== keySequence
.Length() - 1 && aCharacters
.Length() > 0) {
5806 UINT scanCode
= ::MapVirtualKeyEx(aNativeKeyCode
, MAPVK_VK_TO_VSC
,
5807 gKbdLayout
.GetLayout());
5808 nsFakeCharMessage fakeMsg
= { aCharacters
.CharAt(0), scanCode
};
5809 OnKeyDown(msg
, modKeyState
, nsnull
, &fakeMsg
);
5811 OnKeyDown(msg
, modKeyState
, nsnull
, nsnull
);
5814 for (PRUint32 i
= keySequence
.Length(); i
> 0; --i
) {
5815 PRUint8 key
= keySequence
[i
- 1].mGeneral
;
5816 PRUint8 keySpecific
= keySequence
[i
- 1].mSpecific
;
5817 kbdState
[key
] = 0; // key is up and toggled off if appropriate
5819 kbdState
[keySpecific
] = 0;
5821 ::SetKeyboardState(kbdState
);
5822 nsModifierKeyState modKeyState
;
5823 MSG msg
= InitMSG(WM_KEYUP
, key
, 0);
5824 OnKeyUp(msg
, modKeyState
, nsnull
);
5827 // Restore old key state and layout
5828 ::SetKeyboardState(originalKbdState
);
5829 gKbdLayout
.LoadLayout(oldLayout
);
5831 UnloadKeyboardLayout(loadedLayout
);
5833 #else //XXX: is there another way to do this?
5834 return NS_ERROR_NOT_IMPLEMENTED
;
5839 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint
,
5840 PRUint32 aNativeMessage
,
5841 PRUint32 aModifierFlags
)
5843 #ifndef WINCE // I don't think WINCE supports SendInput
5845 ::GetWindowRect(mWnd
, &r
);
5846 ::SetCursorPos(r
.left
+ aPoint
.x
, r
.top
+ aPoint
.y
);
5849 memset(&input
, 0, sizeof(input
));
5851 input
.type
= INPUT_MOUSE
;
5852 input
.mi
.dwFlags
= aNativeMessage
;
5853 ::SendInput(1, &input
, sizeof(INPUT
));
5857 return NS_ERROR_NOT_IMPLEMENTED
;
5861 /**************************************************************
5863 * SECTION: OnXXX message handlers
5865 * For message handlers that need to be broken out or
5866 * implemented in specific platform code.
5868 **************************************************************/
5870 BOOL
nsWindow::OnInputLangChange(HKL aHKL
)
5873 printf("OnInputLanguageChange\n");
5877 gKbdLayout
.LoadLayout(aHKL
);
5880 return PR_FALSE
; // always pass to child window
5883 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5884 void nsWindow::OnWindowPosChanged(WINDOWPOS
*wp
, PRBool
& result
)
5889 #ifdef WINSTATE_DEBUG_OUTPUT
5890 if (mWnd
== GetTopLevelHWND(mWnd
))
5891 printf("*** OnWindowPosChanged: [ top] ");
5893 printf("*** OnWindowPosChanged: [child] ");
5894 printf("WINDOWPOS flags:");
5895 if (wp
->flags
& SWP_FRAMECHANGED
)
5896 printf("SWP_FRAMECHANGED ");
5897 if (wp
->flags
& SWP_SHOWWINDOW
)
5898 printf("SWP_SHOWWINDOW ");
5899 if (wp
->flags
& SWP_NOSIZE
)
5900 printf("SWP_NOSIZE ");
5901 if (wp
->flags
& SWP_HIDEWINDOW
)
5902 printf("SWP_HIDEWINDOW ");
5906 // Handle window size mode changes
5907 if (wp
->flags
& SWP_FRAMECHANGED
&& mSizeMode
!= nsSizeMode_Fullscreen
) {
5908 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
5911 pl
.length
= sizeof(pl
);
5912 ::GetWindowPlacement(mWnd
, &pl
);
5914 if (pl
.showCmd
== SW_SHOWMAXIMIZED
)
5915 event
.mSizeMode
= nsSizeMode_Maximized
;
5916 else if (pl
.showCmd
== SW_SHOWMINIMIZED
)
5917 event
.mSizeMode
= nsSizeMode_Minimized
;
5918 else if (mFullscreenMode
)
5919 event
.mSizeMode
= nsSizeMode_Fullscreen
;
5921 event
.mSizeMode
= nsSizeMode_Normal
;
5923 // Windows has just changed the size mode of this window. The following
5924 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
5925 // set the min/max window state again or for nsSizeMode_Normal, call
5926 // SetWindow with a parameter of SW_RESTORE. There's no need however as
5927 // this window's mode has already changed. Updating mSizeMode here
5928 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
5929 // to window docking. (bug 489258)
5930 mSizeMode
= event
.mSizeMode
;
5932 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
5933 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
5934 // prevents the working set from being trimmed but keeps the window active.
5935 // After the window is minimized, we need to do some touch up work on the
5936 // active window. (bugs 76831 & 499816)
5937 if (!sTrimOnMinimize
&& nsSizeMode_Minimized
== event
.mSizeMode
)
5938 ActivateOtherWindowHelper(mWnd
);
5940 #ifdef WINSTATE_DEBUG_OUTPUT
5941 switch (mSizeMode
) {
5942 case nsSizeMode_Normal
:
5943 printf("*** mSizeMode: nsSizeMode_Normal\n");
5945 case nsSizeMode_Minimized
:
5946 printf("*** mSizeMode: nsSizeMode_Minimized\n");
5948 case nsSizeMode_Maximized
:
5949 printf("*** mSizeMode: nsSizeMode_Maximized\n");
5952 printf("*** mSizeMode: ??????\n");
5959 result
= DispatchWindowEvent(&event
);
5961 // Skip window size change events below on minimization.
5962 if (mSizeMode
== nsSizeMode_Minimized
)
5966 // Handle window size changes
5967 if (0 == (wp
->flags
& SWP_NOSIZE
)) {
5969 PRInt32 newWidth
, newHeight
;
5971 ::GetWindowRect(mWnd
, &r
);
5973 newWidth
= r
.right
- r
.left
;
5974 newHeight
= r
.bottom
- r
.top
;
5975 nsIntRect
rect(wp
->x
, wp
->y
, newWidth
, newHeight
);
5978 if (eTransparencyTransparent
== mTransparencyMode
)
5979 ResizeTranslucentWindow(newWidth
, newHeight
);
5982 if (newWidth
> mLastSize
.width
)
5987 drect
.left
= wp
->x
+ mLastSize
.width
;
5989 drect
.right
= drect
.left
+ (newWidth
- mLastSize
.width
);
5990 drect
.bottom
= drect
.top
+ newHeight
;
5992 ::RedrawWindow(mWnd
, &drect
, NULL
,
5995 RDW_NOINTERNALPAINT
|
5999 if (newHeight
> mLastSize
.height
)
6005 drect
.top
= wp
->y
+ mLastSize
.height
;
6006 drect
.right
= drect
.left
+ newWidth
;
6007 drect
.bottom
= drect
.top
+ (newHeight
- mLastSize
.height
);
6009 ::RedrawWindow(mWnd
, &drect
, NULL
,
6012 RDW_NOINTERNALPAINT
|
6017 mBounds
.width
= newWidth
;
6018 mBounds
.height
= newHeight
;
6019 mLastSize
.width
= newWidth
;
6020 mLastSize
.height
= newHeight
;
6022 #ifdef WINSTATE_DEBUG_OUTPUT
6023 printf("*** Resize window: %d x %d x %d x %d\n", wp
->x
, wp
->y
, newWidth
, newHeight
);
6026 // If a maximized window is resized, recalculate the non-client margins and
6027 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
6029 if (mSizeMode
== nsSizeMode_Maximized
) {
6030 if (UpdateNonClientMargins(nsSizeMode_Maximized
, PR_TRUE
)) {
6031 // gecko resize event already sent by UpdateNonClientMargins.
6037 // Recalculate the width and height based on the client area for gecko events.
6038 if (::GetClientRect(mWnd
, &r
)) {
6039 rect
.width
= r
.right
- r
.left
;
6040 rect
.height
= r
.bottom
- r
.top
;
6043 // Send a gecko resize event
6044 result
= OnResize(rect
);
6049 void nsWindow::ActivateOtherWindowHelper(HWND aWnd
)
6051 // Find the next window that is enabled, visible, and not minimized.
6052 HWND hwndBelow
= ::GetNextWindow(aWnd
, GW_HWNDNEXT
);
6053 while (hwndBelow
&& (!::IsWindowEnabled(hwndBelow
) || !::IsWindowVisible(hwndBelow
) ||
6054 ::IsIconic(hwndBelow
))) {
6055 hwndBelow
= ::GetNextWindow(hwndBelow
, GW_HWNDNEXT
);
6058 // Push ourselves to the bottom of the stack, then activate the
6060 ::SetWindowPos(aWnd
, HWND_BOTTOM
, 0, 0, 0, 0,
6061 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
);
6063 ::SetForegroundWindow(hwndBelow
);
6065 // Play the minimize sound while we're here, since that is also
6066 // forgotten when we use SW_SHOWMINIMIZED.
6067 ::PlaySoundW(L
"Minimize", nsnull
, SND_ALIAS
| SND_NODEFAULT
| SND_ASYNC
);
6069 #endif // !defined(WINCE)
6072 void nsWindow::OnWindowPosChanging(LPWINDOWPOS
& info
)
6074 // Update non-client margins if the frame size is changing, and let the
6075 // browser know we are changing size modes, so alternative css can kick in.
6076 // If we're going into fullscreen mode, ignore this, since it'll reset
6077 // margins to normal mode.
6078 if (info
->flags
& SWP_FRAMECHANGED
&& mSizeMode
!= nsSizeMode_Fullscreen
) {
6080 pl
.length
= sizeof(pl
);
6081 ::GetWindowPlacement(mWnd
, &pl
);
6083 if (pl
.showCmd
== SW_SHOWMAXIMIZED
)
6084 sizeMode
= nsSizeMode_Maximized
;
6085 else if (pl
.showCmd
== SW_SHOWMINIMIZED
)
6086 sizeMode
= nsSizeMode_Minimized
;
6087 else if (mFullscreenMode
)
6088 sizeMode
= nsSizeMode_Fullscreen
;
6090 sizeMode
= nsSizeMode_Normal
;
6092 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
6095 event
.mSizeMode
= static_cast<nsSizeMode
>(sizeMode
);
6096 DispatchWindowEvent(&event
);
6098 UpdateNonClientMargins(sizeMode
, PR_FALSE
);
6101 // enforce local z-order rules
6102 if (!(info
->flags
& SWP_NOZORDER
)) {
6103 HWND hwndAfter
= info
->hwndInsertAfter
;
6105 nsZLevelEvent
event(PR_TRUE
, NS_SETZLEVEL
, this);
6106 nsWindow
*aboveWindow
= 0;
6110 if (hwndAfter
== HWND_BOTTOM
)
6111 event
.mPlacement
= nsWindowZBottom
;
6112 else if (hwndAfter
== HWND_TOP
|| hwndAfter
== HWND_TOPMOST
|| hwndAfter
== HWND_NOTOPMOST
)
6113 event
.mPlacement
= nsWindowZTop
;
6115 event
.mPlacement
= nsWindowZRelative
;
6116 aboveWindow
= GetNSWindowPtr(hwndAfter
);
6118 event
.mReqBelow
= aboveWindow
;
6119 event
.mActualBelow
= nsnull
;
6121 event
.mImmediate
= PR_FALSE
;
6122 event
.mAdjusted
= PR_FALSE
;
6123 DispatchWindowEvent(&event
);
6125 if (event
.mAdjusted
) {
6126 if (event
.mPlacement
== nsWindowZBottom
)
6127 info
->hwndInsertAfter
= HWND_BOTTOM
;
6128 else if (event
.mPlacement
== nsWindowZTop
)
6129 info
->hwndInsertAfter
= HWND_TOP
;
6131 info
->hwndInsertAfter
= (HWND
)event
.mActualBelow
->GetNativeData(NS_NATIVE_WINDOW
);
6134 NS_IF_RELEASE(event
.mActualBelow
);
6136 // prevent rude external programs from making hidden window visible
6137 if (mWindowType
== eWindowType_invisible
)
6138 info
->flags
&= ~SWP_SHOWWINDOW
;
6142 void nsWindow::UserActivity()
6144 // Check if we have the idle service, if not we try to get it.
6145 if (!mIdleService
) {
6146 mIdleService
= do_GetService("@mozilla.org/widget/idleservice;1");
6149 // Check that we now have the idle service.
6151 mIdleService
->ResetIdleTimeOut();
6155 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6156 PRBool
nsWindow::OnTouch(WPARAM wParam
, LPARAM lParam
)
6158 PRUint32 cInputs
= LOWORD(wParam
);
6159 PTOUCHINPUT pInputs
= new TOUCHINPUT
[cInputs
];
6161 if (mGesture
.GetTouchInputInfo((HTOUCHINPUT
)lParam
, cInputs
, pInputs
)) {
6162 for (PRUint32 i
= 0; i
< cInputs
; i
++) {
6164 if (pInputs
[i
].dwFlags
& TOUCHEVENTF_MOVE
) {
6165 msg
= NS_MOZTOUCH_MOVE
;
6166 } else if (pInputs
[i
].dwFlags
& TOUCHEVENTF_DOWN
) {
6167 msg
= NS_MOZTOUCH_DOWN
;
6168 } else if (pInputs
[i
].dwFlags
& TOUCHEVENTF_UP
) {
6169 msg
= NS_MOZTOUCH_UP
;
6174 nsPointWin touchPoint
;
6175 touchPoint
.x
= TOUCH_COORD_TO_PIXEL(pInputs
[i
].x
);
6176 touchPoint
.y
= TOUCH_COORD_TO_PIXEL(pInputs
[i
].y
);
6177 touchPoint
.ScreenToClient(mWnd
);
6179 nsMozTouchEvent
touchEvent(PR_TRUE
, msg
, this, pInputs
[i
].dwID
);
6180 touchEvent
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6181 touchEvent
.refPoint
= touchPoint
;
6183 nsEventStatus status
;
6184 DispatchEvent(&touchEvent
, status
);
6189 mGesture
.CloseTouchInputHandle((HTOUCHINPUT
)lParam
);
6194 // Gesture event processing. Handles WM_GESTURE events.
6196 PRBool
nsWindow::OnGesture(WPARAM wParam
, LPARAM lParam
)
6198 // Treatment for pan events which translate into scroll events:
6199 if (mGesture
.IsPanEvent(lParam
)) {
6200 nsMouseScrollEvent
event(PR_TRUE
, NS_MOUSE_PIXEL_SCROLL
, this);
6202 if ( !mGesture
.ProcessPanMessage(mWnd
, wParam
, lParam
) )
6203 return PR_FALSE
; // ignore
6205 nsEventStatus status
;
6207 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6208 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6209 event
.isMeta
= PR_FALSE
;
6210 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6212 event
.time
= ::GetMessageTime();
6213 event
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6215 PRBool endFeedback
= PR_TRUE
;
6217 PRInt32 scrollOverflowX
= 0;
6218 PRInt32 scrollOverflowY
= 0;
6220 if (mGesture
.PanDeltaToPixelScrollX(event
)) {
6221 DispatchEvent(&event
, status
);
6222 scrollOverflowX
= event
.scrollOverflow
;
6225 if (mGesture
.PanDeltaToPixelScrollY(event
)) {
6226 DispatchEvent(&event
, status
);
6227 scrollOverflowY
= event
.scrollOverflow
;
6230 if (mDisplayPanFeedback
) {
6231 mGesture
.UpdatePanFeedbackX(mWnd
, scrollOverflowX
, endFeedback
);
6232 mGesture
.UpdatePanFeedbackY(mWnd
, scrollOverflowY
, endFeedback
);
6233 mGesture
.PanFeedbackFinalize(mWnd
, endFeedback
);
6236 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
6241 // Other gestures translate into simple gesture events:
6242 nsSimpleGestureEvent
event(PR_TRUE
, 0, this, 0, 0.0);
6243 if ( !mGesture
.ProcessGestureMessage(mWnd
, wParam
, lParam
, event
) ) {
6244 return PR_FALSE
; // fall through to DefWndProc
6247 // Polish up and send off the new event
6248 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6249 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6250 event
.isMeta
= PR_FALSE
;
6251 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6253 event
.time
= ::GetMessageTime();
6254 event
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6256 nsEventStatus status
;
6257 DispatchEvent(&event
, status
);
6258 if (status
== nsEventStatus_eIgnore
) {
6259 return PR_FALSE
; // Ignored, fall through
6262 // Only close this if we process and return true.
6263 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
6265 return PR_TRUE
; // Handled
6267 #endif // !defined(WINCE)
6270 PRUint16
nsWindow::GetMouseInputSource()
6272 PRUint16 inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE
;
6273 LPARAM lParamExtraInfo
= ::GetMessageExtraInfo();
6274 if ((lParamExtraInfo
& TABLET_INK_SIGNATURE
) == TABLET_INK_CHECK
) {
6275 inputSource
= (lParamExtraInfo
& TABLET_INK_TOUCH
) ?
6276 PRUint16(nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
) : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN
;
6282 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6283 * within the message case block. If returning true result should be returned
6284 * immediately (no more processing).
6286 PRBool
nsWindow::OnMouseWheel(UINT msg
, WPARAM wParam
, LPARAM lParam
, PRBool
& getWheelInfo
, PRBool
& result
, LRESULT
*aRetValue
)
6288 // Handle both flavors of mouse wheel events.
6289 static int iDeltaPerLine
, iDeltaPerChar
;
6290 static ULONG ulScrollLines
, ulScrollChars
= 1;
6291 static int currentVDelta
, currentHDelta
;
6292 static HWND currentWindow
= 0;
6294 PRBool isVertical
= msg
== WM_MOUSEWHEEL
;
6296 // Get mouse wheel metrics (but only once).
6298 getWheelInfo
= PR_FALSE
;
6300 SystemParametersInfo (SPI_GETWHEELSCROLLLINES
, 0, &ulScrollLines
, 0);
6302 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6303 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6305 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6306 // the mouse driver wants a page scroll. The docs state that
6307 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6308 // since some mouse drivers use an arbitrary large number instead,
6309 // we have to handle that as well.
6312 if (ulScrollLines
) {
6313 if (ulScrollLines
<= WHEEL_DELTA
) {
6314 iDeltaPerLine
= WHEEL_DELTA
/ ulScrollLines
;
6316 ulScrollLines
= WHEEL_PAGESCROLL
;
6320 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS
, 0,
6321 &ulScrollChars
, 0)) {
6322 // Note that we may always fail to get the value before Win Vista.
6327 if (ulScrollChars
) {
6328 if (ulScrollChars
<= WHEEL_DELTA
) {
6329 iDeltaPerChar
= WHEEL_DELTA
/ ulScrollChars
;
6331 ulScrollChars
= WHEEL_PAGESCROLL
;
6336 if ((isVertical
&& ulScrollLines
!= WHEEL_PAGESCROLL
&& !iDeltaPerLine
) ||
6337 (!isVertical
&& ulScrollChars
!= WHEEL_PAGESCROLL
&& !iDeltaPerChar
))
6338 return PR_FALSE
; // break
6340 // The mousewheel event will be dispatched to the toplevel
6341 // window. We need to give it to the child window
6343 if (!HandleScrollingPlugins(msg
, wParam
, lParam
, result
, aRetValue
, quit
))
6344 return quit
; // return immediately if its not our window
6346 // We should cancel the surplus delta if the current window is not
6347 // same as previous.
6348 if (currentWindow
!= mWnd
) {
6351 currentWindow
= mWnd
;
6354 nsMouseScrollEvent
scrollEvent(PR_TRUE
, NS_MOUSE_SCROLL
, this);
6355 scrollEvent
.delta
= 0;
6357 scrollEvent
.scrollFlags
= nsMouseScrollEvent::kIsVertical
;
6358 if (ulScrollLines
== WHEEL_PAGESCROLL
) {
6359 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
6360 scrollEvent
.delta
= (((short) HIWORD (wParam
)) > 0) ? -1 : 1;
6362 currentVDelta
-= (short) HIWORD (wParam
);
6363 if (PR_ABS(currentVDelta
) >= iDeltaPerLine
) {
6364 scrollEvent
.delta
= currentVDelta
/ iDeltaPerLine
;
6365 currentVDelta
%= iDeltaPerLine
;
6369 scrollEvent
.scrollFlags
= nsMouseScrollEvent::kIsHorizontal
;
6370 if (ulScrollChars
== WHEEL_PAGESCROLL
) {
6371 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
6372 scrollEvent
.delta
= (((short) HIWORD (wParam
)) > 0) ? 1 : -1;
6374 currentHDelta
+= (short) HIWORD (wParam
);
6375 if (PR_ABS(currentHDelta
) >= iDeltaPerChar
) {
6376 scrollEvent
.delta
= currentHDelta
/ iDeltaPerChar
;
6377 currentHDelta
%= iDeltaPerChar
;
6382 if (!scrollEvent
.delta
) {
6383 // We store the wheel delta, and it will be used next wheel message, so,
6384 // we consume this message actually. We shouldn't call next wndproc.
6386 return PR_FALSE
; // break
6390 // The event may go to a plug-in which already dispatched this message.
6391 // Then, the event can cause deadlock. We should unlock the sender here.
6392 ::ReplyMessage(isVertical
? 0 : TRUE
);
6395 scrollEvent
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6396 scrollEvent
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6397 scrollEvent
.isMeta
= PR_FALSE
;
6398 scrollEvent
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6399 InitEvent(scrollEvent
);
6400 if (nsnull
!= mEventCallback
) {
6401 result
= DispatchWindowEvent(&scrollEvent
);
6403 // Note that we should return zero if we process WM_MOUSEWHEEL.
6404 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6407 *aRetValue
= isVertical
? 0 : TRUE
;
6409 return PR_FALSE
; // break;
6413 StringCaseInsensitiveEquals(const PRUnichar
* aChars1
, const PRUint32 aNumChars1
,
6414 const PRUnichar
* aChars2
, const PRUint32 aNumChars2
)
6416 if (aNumChars1
!= aNumChars2
)
6419 nsCaseInsensitiveStringComparator comp
;
6420 return comp(aChars1
, aChars2
, aNumChars1
) == 0;
6423 UINT
nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode
)
6426 switch (aNativeKeyCode
) {
6427 case VK_OEM_1
: return NS_VK_SEMICOLON
; // 0xBA, For the US standard keyboard, the ';:' key
6428 case VK_OEM_PLUS
: return NS_VK_ADD
; // 0xBB, For any country/region, the '+' key
6429 case VK_OEM_MINUS
: return NS_VK_SUBTRACT
; // 0xBD, For any country/region, the '-' key
6433 return aNativeKeyCode
;
6437 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6438 * WM_CHAR messages for processing. During testing we don't want to
6439 * mess with the real message queue. Instead we pass a
6440 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6441 * that as if it was in the message queue, and refrain from actually
6442 * looking at or touching the message queue.
6444 LRESULT
nsWindow::OnKeyDown(const MSG
&aMsg
,
6445 nsModifierKeyState
&aModKeyState
,
6446 PRBool
*aEventDispatched
,
6447 nsFakeCharMessage
* aFakeCharMessage
)
6449 UINT virtualKeyCode
= aMsg
.wParam
;
6452 gKbdLayout
.OnKeyDown (virtualKeyCode
);
6455 // Use only DOMKeyCode for XP processing.
6456 // Use aVirtualKeyCode for gKbdLayout and native processing.
6457 UINT DOMKeyCode
= nsIMM32Handler::IsComposingOn(this) ?
6458 virtualKeyCode
: MapFromNativeToDOM(virtualKeyCode
);
6461 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6465 DispatchKeyEvent(NS_KEY_DOWN
, 0, nsnull
, DOMKeyCode
, &aMsg
, aModKeyState
);
6466 if (aEventDispatched
)
6467 *aEventDispatched
= PR_TRUE
;
6469 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6470 // for almost all keys
6471 switch (DOMKeyCode
) {
6475 case NS_VK_CAPS_LOCK
:
6476 case NS_VK_NUM_LOCK
:
6477 case NS_VK_SCROLL_LOCK
: return noDefault
;
6480 PRUint32 extraFlags
= (noDefault
? NS_EVENT_FLAG_NO_DEFAULT
: 0);
6482 BOOL gotMsg
= aFakeCharMessage
||
6483 ::PeekMessageW(&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_NOREMOVE
| PM_NOYIELD
);
6484 // Enter and backspace are always handled here to avoid for example the
6485 // confusion between ctrl-enter and ctrl-J.
6486 if (DOMKeyCode
== NS_VK_RETURN
|| DOMKeyCode
== NS_VK_BACK
||
6487 ((aModKeyState
.mIsControlDown
|| aModKeyState
.mIsAltDown
)
6491 && !gKbdLayout
.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)))
6494 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6495 // They can be more than one because of:
6496 // * Dead-keys not pairing with base character
6497 // * Some keyboard layouts may map up to 4 characters to the single key
6498 PRBool anyCharMessagesRemoved
= PR_FALSE
;
6500 if (aFakeCharMessage
) {
6501 anyCharMessagesRemoved
= PR_TRUE
;
6503 while (gotMsg
&& (msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
))
6505 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6506 ("%s charCode=%d scanCode=%d\n", msg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
6507 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
6508 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST
, WM_KEYLAST
);
6509 anyCharMessagesRemoved
= PR_TRUE
;
6511 gotMsg
= ::PeekMessageW (&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_NOREMOVE
| PM_NOYIELD
);
6515 if (!anyCharMessagesRemoved
&& DOMKeyCode
== NS_VK_BACK
&&
6516 nsIMM32Handler::IsDoingKakuteiUndo(mWnd
)) {
6517 NS_ASSERTION(!aFakeCharMessage
,
6518 "We shouldn't be touching the real msg queue");
6519 RemoveMessageAndDispatchPluginEvent(WM_CHAR
, WM_CHAR
);
6523 (aFakeCharMessage
||
6524 msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
|| msg
.message
== WM_DEADCHAR
)) {
6525 if (aFakeCharMessage
)
6526 return OnCharRaw(aFakeCharMessage
->mCharCode
,
6527 aFakeCharMessage
->mScanCode
, aModKeyState
, extraFlags
);
6529 // If prevent default set for keydown, do same for keypress
6530 ::GetMessageW(&msg
, mWnd
, msg
.message
, msg
.message
);
6532 if (msg
.message
== WM_DEADCHAR
) {
6533 if (!PluginHasFocus())
6536 // We need to send the removed message to focused plug-in.
6537 DispatchPluginEvent(msg
);
6541 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6542 ("%s charCode=%d scanCode=%d\n",
6543 msg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
6544 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
6546 BOOL result
= OnChar(msg
, aModKeyState
, nsnull
, extraFlags
);
6547 // If a syschar keypress wasn't processed, Windows may want to
6548 // handle it to activate a native menu.
6549 if (!result
&& msg
.message
== WM_SYSCHAR
)
6550 ::DefWindowProcW(mWnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
6554 else if (!aModKeyState
.mIsControlDown
&& !aModKeyState
.mIsAltDown
&&
6555 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode
) ||
6556 KeyboardLayout::IsNumpadKey(virtualKeyCode
)))
6558 // If this is simple KeyDown event but next message is not WM_CHAR,
6559 // this event may not input text, so we should ignore this event.
6561 return PluginHasFocus() && noDefault
;
6564 if (gKbdLayout
.IsDeadKey ())
6565 return PluginHasFocus() && noDefault
;
6567 PRUint8 shiftStates
[5];
6568 PRUnichar uniChars
[5];
6569 PRUnichar shiftedChars
[5] = {0, 0, 0, 0, 0};
6570 PRUnichar unshiftedChars
[5] = {0, 0, 0, 0, 0};
6571 PRUnichar shiftedLatinChar
= 0;
6572 PRUnichar unshiftedLatinChar
= 0;
6573 PRUint32 numOfUniChars
= 0;
6574 PRUint32 numOfShiftedChars
= 0;
6575 PRUint32 numOfUnshiftedChars
= 0;
6576 PRUint32 numOfShiftStates
= 0;
6578 switch (virtualKeyCode
) {
6579 // keys to be sent as characters
6580 case VK_ADD
: uniChars
[0] = '+'; numOfUniChars
= 1; break;
6581 case VK_SUBTRACT
: uniChars
[0] = '-'; numOfUniChars
= 1; break;
6582 case VK_DIVIDE
: uniChars
[0] = '/'; numOfUniChars
= 1; break;
6583 case VK_MULTIPLY
: uniChars
[0] = '*'; numOfUniChars
= 1; break;
6594 uniChars
[0] = virtualKeyCode
- VK_NUMPAD0
+ '0';
6598 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)) {
6599 numOfUniChars
= numOfShiftStates
=
6600 gKbdLayout
.GetUniChars(uniChars
, shiftStates
,
6601 NS_ARRAY_LENGTH(uniChars
));
6604 if (aModKeyState
.mIsControlDown
^ aModKeyState
.mIsAltDown
) {
6605 PRUint8 capsLockState
= (::GetKeyState(VK_CAPITAL
) & 1) ? eCapsLock
: 0;
6606 numOfUnshiftedChars
=
6607 gKbdLayout
.GetUniCharsWithShiftState(virtualKeyCode
, capsLockState
,
6608 unshiftedChars
, NS_ARRAY_LENGTH(unshiftedChars
));
6610 gKbdLayout
.GetUniCharsWithShiftState(virtualKeyCode
,
6611 capsLockState
| eShift
,
6612 shiftedChars
, NS_ARRAY_LENGTH(shiftedChars
));
6614 // The current keyboard cannot input alphabets or numerics,
6615 // we should append them for Shortcut/Access keys.
6616 // E.g., for Cyrillic keyboard layout.
6617 if (NS_VK_A
<= DOMKeyCode
&& DOMKeyCode
<= NS_VK_Z
) {
6618 shiftedLatinChar
= unshiftedLatinChar
= DOMKeyCode
;
6620 shiftedLatinChar
+= 0x20;
6622 unshiftedLatinChar
+= 0x20;
6623 if (unshiftedLatinChar
== unshiftedChars
[0] &&
6624 shiftedLatinChar
== shiftedChars
[0]) {
6625 shiftedLatinChar
= unshiftedLatinChar
= 0;
6629 if (NS_VK_0
<= DOMKeyCode
&& DOMKeyCode
<= NS_VK_9
) {
6632 switch (virtualKeyCode
) {
6633 case VK_OEM_PLUS
: ch
= '+'; break;
6634 case VK_OEM_MINUS
: ch
= '-'; break;
6637 if (ch
&& unshiftedChars
[0] != ch
&& shiftedChars
[0] != ch
) {
6638 // Windows has assigned a virtual key code to the key even though
6639 // the character can't be produced with this key. That probably
6640 // means the character can't be produced with any key in the
6641 // current layout and so the assignment is based on a QWERTY
6642 // layout. Append this code so that users can access the shortcut.
6643 unshiftedLatinChar
= ch
;
6647 // If the charCode is not ASCII character, we should replace the
6648 // charCode with ASCII character only when Ctrl is pressed.
6649 // But don't replace the charCode when the charCode is not same as
6650 // unmodified characters. In such case, Ctrl is sometimes used for a
6651 // part of character inputting key combination like Shift.
6652 if (aModKeyState
.mIsControlDown
) {
6653 PRUint8 currentState
= eCtrl
;
6654 if (aModKeyState
.mIsShiftDown
)
6655 currentState
|= eShift
;
6658 aModKeyState
.mIsShiftDown
? shiftedLatinChar
: unshiftedLatinChar
;
6660 (numOfUniChars
== 0 ||
6661 StringCaseInsensitiveEquals(uniChars
, numOfUniChars
,
6662 aModKeyState
.mIsShiftDown
? shiftedChars
: unshiftedChars
,
6663 aModKeyState
.mIsShiftDown
? numOfShiftedChars
:
6664 numOfUnshiftedChars
))) {
6665 numOfUniChars
= numOfShiftStates
= 1;
6667 shiftStates
[0] = currentState
;
6673 if (numOfUniChars
> 0 || numOfShiftedChars
> 0 || numOfUnshiftedChars
> 0) {
6674 PRUint32 num
= PR_MAX(numOfUniChars
,
6675 PR_MAX(numOfShiftedChars
, numOfUnshiftedChars
));
6676 PRUint32 skipUniChars
= num
- numOfUniChars
;
6677 PRUint32 skipShiftedChars
= num
- numOfShiftedChars
;
6678 PRUint32 skipUnshiftedChars
= num
- numOfUnshiftedChars
;
6679 UINT keyCode
= numOfUniChars
== 0 ? DOMKeyCode
: 0;
6680 for (PRUint32 cnt
= 0; cnt
< num
; cnt
++) {
6681 PRUint16 uniChar
, shiftedChar
, unshiftedChar
;
6682 uniChar
= shiftedChar
= unshiftedChar
= 0;
6683 if (skipUniChars
<= cnt
) {
6684 if (cnt
- skipUniChars
< numOfShiftStates
) {
6685 // If key in combination with Alt and/or Ctrl produces a different
6686 // character than without them then do not report these flags
6687 // because it is separate keyboard layout shift state. If dead-key
6688 // and base character does not produce a valid composite character
6689 // then both produced dead-key character and following base
6690 // character may have different modifier flags, too.
6691 aModKeyState
.mIsShiftDown
=
6692 (shiftStates
[cnt
- skipUniChars
] & eShift
) != 0;
6693 aModKeyState
.mIsControlDown
=
6694 (shiftStates
[cnt
- skipUniChars
] & eCtrl
) != 0;
6695 aModKeyState
.mIsAltDown
=
6696 (shiftStates
[cnt
- skipUniChars
] & eAlt
) != 0;
6698 uniChar
= uniChars
[cnt
- skipUniChars
];
6700 if (skipShiftedChars
<= cnt
)
6701 shiftedChar
= shiftedChars
[cnt
- skipShiftedChars
];
6702 if (skipUnshiftedChars
<= cnt
)
6703 unshiftedChar
= unshiftedChars
[cnt
- skipUnshiftedChars
];
6704 nsAutoTArray
<nsAlternativeCharCode
, 5> altArray
;
6706 if (shiftedChar
|| unshiftedChar
) {
6707 nsAlternativeCharCode
chars(unshiftedChar
, shiftedChar
);
6708 altArray
.AppendElement(chars
);
6710 if (cnt
== num
- 1 && (unshiftedLatinChar
|| shiftedLatinChar
)) {
6711 nsAlternativeCharCode
chars(unshiftedLatinChar
, shiftedLatinChar
);
6712 altArray
.AppendElement(chars
);
6715 DispatchKeyEvent(NS_KEY_PRESS
, uniChar
, &altArray
,
6716 keyCode
, nsnull
, aModKeyState
, extraFlags
);
6719 DispatchKeyEvent(NS_KEY_PRESS
, 0, nsnull
, DOMKeyCode
, nsnull
, aModKeyState
,
6724 UINT unichar
= ::MapVirtualKey(virtualKeyCode
, MAPVK_VK_TO_CHAR
);
6725 // Check for dead characters or no mapping
6726 if (unichar
& 0x80) {
6729 DispatchKeyEvent(NS_KEY_PRESS
, unichar
, nsnull
, DOMKeyCode
, nsnull
, aModKeyState
,
6738 LRESULT
nsWindow::OnKeyUp(const MSG
&aMsg
,
6739 nsModifierKeyState
&aModKeyState
,
6740 PRBool
*aEventDispatched
)
6742 UINT virtualKeyCode
= aMsg
.wParam
;
6744 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6745 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode
));
6747 if (!nsIMM32Handler::IsComposingOn(this)) {
6748 virtualKeyCode
= MapFromNativeToDOM(virtualKeyCode
);
6751 if (aEventDispatched
)
6752 *aEventDispatched
= PR_TRUE
;
6753 return DispatchKeyEvent(NS_KEY_UP
, 0, nsnull
, virtualKeyCode
, &aMsg
,
6758 LRESULT
nsWindow::OnChar(const MSG
&aMsg
, nsModifierKeyState
&aModKeyState
,
6759 PRBool
*aEventDispatched
, PRUint32 aFlags
)
6761 return OnCharRaw(aMsg
.wParam
, HIWORD(aMsg
.lParam
) & 0xFF, aModKeyState
,
6762 aFlags
, &aMsg
, aEventDispatched
);
6766 LRESULT
nsWindow::OnCharRaw(UINT charCode
, UINT aScanCode
,
6767 nsModifierKeyState
&aModKeyState
, PRUint32 aFlags
,
6768 const MSG
*aMsg
, PRBool
*aEventDispatched
)
6770 // ignore [shift+]alt+space so the OS can handle it
6771 if (aModKeyState
.mIsAltDown
&& !aModKeyState
.mIsControlDown
&&
6772 IS_VK_DOWN(NS_VK_SPACE
)) {
6776 // Ignore Ctrl+Enter (bug 318235)
6777 if (aModKeyState
.mIsControlDown
&& charCode
== 0xA) {
6781 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
6782 PRBool saveIsAltDown
= aModKeyState
.mIsAltDown
;
6783 PRBool saveIsControlDown
= aModKeyState
.mIsControlDown
;
6784 if (aModKeyState
.mIsAltDown
&& aModKeyState
.mIsControlDown
)
6785 aModKeyState
.mIsAltDown
= aModKeyState
.mIsControlDown
= PR_FALSE
;
6789 if (nsIMM32Handler::IsComposingOn(this)) {
6793 if (aModKeyState
.mIsControlDown
&& charCode
<= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
6794 // need to account for shift here. bug 16486
6795 if (aModKeyState
.mIsShiftDown
)
6796 uniChar
= charCode
- 1 + 'A';
6798 uniChar
= charCode
- 1 + 'a';
6801 else if (aModKeyState
.mIsControlDown
&& charCode
<= 0x1F) {
6802 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
6803 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
6804 // for some reason the keypress handler need to have the uniChar code set
6805 // with the addition of a upper case A not the lower case.
6806 uniChar
= charCode
- 1 + 'A';
6808 } else { // 0x20 - SPACE, 0x3D - EQUALS
6809 if (charCode
< 0x20 || (charCode
== 0x3D && aModKeyState
.mIsControlDown
)) {
6817 // Keep the characters unshifted for shortcuts and accesskeys and make sure
6818 // that numbers are always passed as such (among others: bugs 50255 and 351310)
6819 if (uniChar
&& (aModKeyState
.mIsControlDown
|| aModKeyState
.mIsAltDown
)) {
6820 UINT virtualKeyCode
= ::MapVirtualKeyEx(aScanCode
, MAPVK_VSC_TO_VK
,
6821 gKbdLayout
.GetLayout());
6822 UINT unshiftedCharCode
=
6823 virtualKeyCode
>= '0' && virtualKeyCode
<= '9' ? virtualKeyCode
:
6824 aModKeyState
.mIsShiftDown
? ::MapVirtualKeyEx(virtualKeyCode
,
6826 gKbdLayout
.GetLayout()) : 0;
6827 // ignore diacritics (top bit set) and key mapping errors (char code 0)
6828 if ((INT
)unshiftedCharCode
> 0)
6829 uniChar
= unshiftedCharCode
;
6832 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
6833 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
6835 if (!aModKeyState
.mIsShiftDown
&& (saveIsAltDown
|| saveIsControlDown
)) {
6836 uniChar
= towlower(uniChar
);
6839 PRBool result
= DispatchKeyEvent(NS_KEY_PRESS
, uniChar
, nsnull
,
6840 charCode
, aMsg
, aModKeyState
, aFlags
);
6841 if (aEventDispatched
)
6842 *aEventDispatched
= PR_TRUE
;
6843 aModKeyState
.mIsAltDown
= saveIsAltDown
;
6844 aModKeyState
.mIsControlDown
= saveIsControlDown
;
6849 nsWindow::SetupKeyModifiersSequence(nsTArray
<KeyPair
>* aArray
, PRUint32 aModifiers
)
6851 for (PRUint32 i
= 0; i
< NS_ARRAY_LENGTH(sModifierKeyMap
); ++i
) {
6852 const PRUint32
* map
= sModifierKeyMap
[i
];
6853 if (aModifiers
& map
[0]) {
6854 aArray
->AppendElement(KeyPair(map
[1], map
[2]));
6860 nsWindow::ConfigureChildren(const nsTArray
<Configuration
>& aConfigurations
)
6862 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
6863 // here, if that helps in some situations. So far I haven't seen a
6865 for (PRUint32 i
= 0; i
< aConfigurations
.Length(); ++i
) {
6866 const Configuration
& configuration
= aConfigurations
[i
];
6867 nsWindow
* w
= static_cast<nsWindow
*>(configuration
.mChild
);
6868 NS_ASSERTION(w
->GetParent() == this,
6869 "Configured widget is not a child");
6871 // MSDN says we should do on WinCE this before moving or resizing the window
6872 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
6873 // We put the region back just below, anyway.
6874 ::SetWindowRgn(w
->mWnd
, NULL
, TRUE
);
6876 nsresult rv
= w
->SetWindowClipRegion(configuration
.mClipRegion
, PR_TRUE
);
6877 NS_ENSURE_SUCCESS(rv
, rv
);
6879 w
->GetBounds(bounds
);
6880 if (bounds
.Size() != configuration
.mBounds
.Size()) {
6881 w
->Resize(configuration
.mBounds
.x
, configuration
.mBounds
.y
,
6882 configuration
.mBounds
.width
, configuration
.mBounds
.height
,
6884 } else if (bounds
.TopLeft() != configuration
.mBounds
.TopLeft()) {
6885 w
->Move(configuration
.mBounds
.x
, configuration
.mBounds
.y
);
6887 rv
= w
->SetWindowClipRegion(configuration
.mClipRegion
, PR_FALSE
);
6888 NS_ENSURE_SUCCESS(rv
, rv
);
6894 CreateHRGNFromArray(const nsTArray
<nsIntRect
>& aRects
)
6896 PRInt32 size
= sizeof(RGNDATAHEADER
) + sizeof(RECT
)*aRects
.Length();
6897 nsAutoTArray
<PRUint8
,100> buf
;
6898 if (!buf
.SetLength(size
))
6900 RGNDATA
* data
= reinterpret_cast<RGNDATA
*>(buf
.Elements());
6901 RECT
* rects
= reinterpret_cast<RECT
*>(data
->Buffer
);
6902 data
->rdh
.dwSize
= sizeof(data
->rdh
);
6903 data
->rdh
.iType
= RDH_RECTANGLES
;
6904 data
->rdh
.nCount
= aRects
.Length();
6906 for (PRUint32 i
= 0; i
< aRects
.Length(); ++i
) {
6907 const nsIntRect
& r
= aRects
[i
];
6908 bounds
.UnionRect(bounds
, r
);
6909 ::SetRect(&rects
[i
], r
.x
, r
.y
, r
.XMost(), r
.YMost());
6911 ::SetRect(&data
->rdh
.rcBound
, bounds
.x
, bounds
.y
, bounds
.XMost(), bounds
.YMost());
6912 return ::ExtCreateRegion(NULL
, buf
.Length(), data
);
6916 nsWindow::SetWindowClipRegion(const nsTArray
<nsIntRect
>& aRects
,
6917 PRBool aIntersectWithExisting
)
6919 if (!aIntersectWithExisting
) {
6920 if (!StoreWindowClipRegion(aRects
))
6923 // In this case still early return if nothing changed.
6924 if (mClipRects
&& mClipRectCount
== aRects
.Length() &&
6927 sizeof(nsIntRect
)*mClipRectCount
) == 0) {
6932 HRGN dest
= CreateHRGNFromArray(aRects
);
6934 return NS_ERROR_OUT_OF_MEMORY
;
6936 if (aIntersectWithExisting
) {
6937 HRGN current
= ::CreateRectRgn(0, 0, 0, 0);
6939 if (::GetWindowRgn(mWnd
, current
) != 0 /*ERROR*/) {
6940 ::CombineRgn(dest
, dest
, current
, RGN_AND
);
6942 ::DeleteObject(current
);
6946 if (!::SetWindowRgn(mWnd
, dest
, TRUE
)) {
6947 ::DeleteObject(dest
);
6948 return NS_ERROR_FAILURE
;
6953 // WM_DESTROY event handler
6954 void nsWindow::OnDestroy()
6956 mOnDestroyCalled
= PR_TRUE
;
6958 // Make sure we don't get destroyed in the process of tearing down.
6959 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
6961 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
6963 DispatchStandardEvent(NS_DESTROY
);
6965 // Prevent the widget from sending additional events.
6966 mEventCallback
= nsnull
;
6968 // Free our subclass and clear |this| stored in the window props. We will no longer
6969 // receive events from Windows after this point.
6970 SubclassWindow(FALSE
);
6972 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
6973 // cleared. (It's used in tracking windows for mouse events.)
6974 if (sCurrentWindow
== this)
6975 sCurrentWindow
= nsnull
;
6977 // Disconnects us from our parent, will call our GetParent().
6978 nsBaseWidget::Destroy();
6980 // Release references to children, device context, toolkit, and app shell.
6981 nsBaseWidget::OnDestroy();
6983 // Clear our native parent handle.
6984 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
6985 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
6986 //SetParent(nsnull);
6989 // We have to destroy the native drag target before we null out our window pointer.
6990 EnableDragDrop(PR_FALSE
);
6992 // If we're going away and for some reason we're still the rollup widget, rollup and
6993 // turn off capture.
6994 if ( this == sRollupWidget
) {
6995 if ( sRollupListener
)
6996 sRollupListener
->Rollup(nsnull
, nsnull
);
6997 CaptureRollupEvents(nsnull
, nsnull
, PR_FALSE
, PR_TRUE
);
7000 // If IME is disabled, restore it.
7002 mOldIMC
= ::ImmAssociateContext(mWnd
, mOldIMC
);
7003 NS_ASSERTION(!mOldIMC
, "Another IMC was associated");
7006 // Turn off mouse trails if enabled.
7007 MouseTrailer
* mtrailer
= nsToolkit::gMouseTrailer
;
7009 if (mtrailer
->GetMouseTrailerWindow() == mWnd
)
7010 mtrailer
->DestroyTimer();
7012 if (mtrailer
->GetCaptureWindow() == mWnd
)
7013 mtrailer
->SetCaptureWindow(nsnull
);
7016 // Free GDI window class objects
7018 VERIFY(::DeleteObject(mBrush
));
7022 // Free app icon resources.
7024 icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_BIG
, (LPARAM
) 0);
7026 ::DestroyIcon(icon
);
7028 icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_SMALL
, (LPARAM
) 0);
7030 ::DestroyIcon(icon
);
7032 // Destroy any custom cursor resources.
7034 SetCursor(eCursor_standard
);
7037 // Reset transparency
7038 if (eTransparencyTransparent
== mTransparencyMode
)
7039 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque
);
7042 #if defined(WINCE_HAVE_SOFTKB)
7043 // Revert the changes made for the software keyboard settings
7044 nsWindowCE::ResetSoftKB(mWnd
);
7048 // Finalize panning feedback to possibly restore window displacement
7049 mGesture
.PanFeedbackFinalize(mWnd
, PR_TRUE
);
7052 // Clear the main HWND.
7057 PRBool
nsWindow::OnMove(PRInt32 aX
, PRInt32 aY
)
7062 nsGUIEvent
event(PR_TRUE
, NS_MOVE
, this);
7064 event
.refPoint
.x
= aX
;
7065 event
.refPoint
.y
= aY
;
7067 return DispatchWindowEvent(&event
);
7070 // Send a resize message to the listener
7071 PRBool
nsWindow::OnResize(nsIntRect
&aWindowRect
)
7073 #ifdef CAIRO_HAS_D2D_SURFACE
7074 if (mD2DWindowSurface
) {
7075 mD2DWindowSurface
= NULL
;
7076 Invalidate(PR_FALSE
);
7080 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7081 UpdateCaptionButtonsClippingRect();
7084 // call the event callback
7085 if (mEventCallback
) {
7086 nsSizeEvent
event(PR_TRUE
, NS_SIZE
, this);
7088 event
.windowSize
= &aWindowRect
;
7090 if (::GetWindowRect(mWnd
, &r
)) {
7091 event
.mWinWidth
= PRInt32(r
.right
- r
.left
);
7092 event
.mWinHeight
= PRInt32(r
.bottom
- r
.top
);
7094 event
.mWinWidth
= 0;
7095 event
.mWinHeight
= 0;
7099 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7100 aWindowRect
.x
, aWindowRect
.y
, aWindowRect
.width
, aWindowRect
.height
,
7101 event
.mWinWidth
, event
.mWinHeight
);
7104 return DispatchWindowEvent(&event
);
7110 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7111 PRBool
nsWindow::OnHotKey(WPARAM wParam
, LPARAM lParam
)
7115 #endif // !defined(WINCE)
7117 void nsWindow::OnSettingsChange(WPARAM wParam
, LPARAM lParam
)
7119 if (mWindowType
== eWindowType_dialog
||
7120 mWindowType
== eWindowType_toplevel
)
7121 nsWindowGfx::OnSettingsChangeGfx(wParam
);
7124 static PRBool
IsOurProcessWindow(HWND aHWND
)
7126 DWORD processId
= 0;
7127 ::GetWindowThreadProcessId(aHWND
, &processId
);
7128 return processId
== ::GetCurrentProcessId();
7131 static HWND
FindOurProcessWindow(HWND aHWND
)
7133 for (HWND wnd
= ::GetParent(aHWND
); wnd
; wnd
= ::GetParent(wnd
)) {
7134 if (IsOurProcessWindow(wnd
)) {
7141 // Scrolling helper function for handling plugins.
7142 // Return value indicates whether the calling function should handle this
7143 // aHandled indicates whether this was handled at all
7144 // aQuitProcessing tells whether or not to continue processing the message
7145 PRBool
nsWindow::HandleScrollingPlugins(UINT aMsg
, WPARAM aWParam
,
7146 LPARAM aLParam
, PRBool
& aHandled
,
7148 PRBool
& aQuitProcessing
)
7150 // The scroll event will be dispatched to the toplevel
7151 // window. We need to give it to the child window
7152 aQuitProcessing
= PR_FALSE
; // default is to not stop processing
7154 DWORD dwPoints
= ::GetMessagePos();
7155 point
.x
= GET_X_LPARAM(dwPoints
);
7156 point
.y
= GET_Y_LPARAM(dwPoints
);
7158 static PRBool sIsProcessing
= PR_FALSE
;
7159 if (sIsProcessing
) {
7160 return PR_TRUE
; // the caller should handle this.
7163 static PRBool sMayBeUsingLogitechMouse
= PR_FALSE
;
7164 if (aMsg
== WM_MOUSEHWHEEL
) {
7165 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7166 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7167 // message at first time, this time, ::GetMessagePos works fine.
7168 // Then, we will return 0 (0 means we process it) to the message. Then, the
7169 // driver will POST the same messages continuously during the wheel tilted.
7170 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7171 // cursor isn't 0,0. Therefore, we cannot trust the result of
7172 // ::GetMessagePos API if the sender is the driver.
7173 if (!sMayBeUsingLogitechMouse
&& aLParam
== 0 && (DWORD
)aLParam
!= dwPoints
&&
7174 ::InSendMessage()) {
7175 sMayBeUsingLogitechMouse
= PR_TRUE
;
7176 } else if (sMayBeUsingLogitechMouse
&& aLParam
!= 0 && ::InSendMessage()) {
7177 // The user has changed the mouse from Logitech's to another one (e.g.,
7178 // the user has changed to the touchpad of the notebook.
7179 sMayBeUsingLogitechMouse
= PR_FALSE
;
7181 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7182 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7184 if (sMayBeUsingLogitechMouse
&& aLParam
== 0 && dwPoints
== 0) {
7185 ::GetCursorPos(&point
);
7189 HWND destWnd
= ::WindowFromPoint(point
);
7190 // Since we receive scroll events for as long as
7191 // we are focused, it's entirely possible that there
7192 // is another app's window or no window under the
7196 // No window is under the pointer
7197 return PR_FALSE
; // break, but continue processing
7200 nsWindow
* destWindow
;
7202 // We don't handle the message if the found window belongs to another
7203 // process's top window. If it belongs window, that is a plug-in's window.
7204 // Then, we need to send the message to the plug-in window.
7205 if (!IsOurProcessWindow(destWnd
)) {
7206 HWND ourPluginWnd
= FindOurProcessWindow(destWnd
);
7207 if (!ourPluginWnd
) {
7208 // Somebody elses window
7209 return PR_FALSE
; // break, but continue processing
7211 destWindow
= GetNSWindowPtr(ourPluginWnd
);
7213 destWindow
= GetNSWindowPtr(destWnd
);
7216 if (destWindow
== this && mWindowType
== eWindowType_plugin
) {
7217 // If this is plug-in window, the message came from the plug-in window.
7218 // Then, the message should be processed on the parent window.
7219 destWindow
= static_cast<nsWindow
*>(GetParent());
7220 NS_ENSURE_TRUE(destWindow
, PR_FALSE
); // break, but continue processing
7221 destWnd
= destWindow
->mWnd
;
7222 NS_ENSURE_TRUE(destWnd
, PR_FALSE
); // break, but continue processing
7225 if (!destWindow
|| destWindow
->mWindowType
== eWindowType_plugin
) {
7226 // Some other app, or a plugin window.
7227 // Windows directs scrolling messages to the focused window.
7228 // However, Mozilla does not like plugins having focus, so a
7229 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7230 // Therefore, plugins etc _should_ get first grab at the
7231 // message, but this focus vaguary means the plugin misses
7232 // out. If the window is a child of ours, forward it on.
7233 // Determine if a child by walking the parent list until
7234 // we find a parent matching our wndproc.
7235 HWND parentWnd
= ::GetParent(destWnd
);
7237 nsWindow
* parentWindow
= GetNSWindowPtr(parentWnd
);
7239 // We have a child window - quite possibly a plugin window.
7240 // However, not all plugins are created equal - some will handle this
7241 // message themselves, some will forward directly back to us, while
7242 // others will call DefWndProc, which itself still forwards back to us.
7243 // So if we have sent it once, we need to handle it ourself.
7246 // XXX The message shouldn't come from the plugin window at here.
7247 // But the message might come from it due to some bugs. If it happens,
7248 // SendMessage causes deadlock. For safety, we should unlock the
7250 ::ReplyMessage(aMsg
== WM_MOUSEHWHEEL
? TRUE
: 0);
7253 // First time we have seen this message.
7254 // Call the child - either it will consume it, or
7255 // it will wind it's way back to us,triggering the destWnd case above
7256 // either way,when the call returns,we are all done with the message,
7257 sIsProcessing
= PR_TRUE
;
7258 ::SendMessageW(destWnd
, aMsg
, aWParam
, aLParam
);
7259 sIsProcessing
= PR_FALSE
;
7261 aQuitProcessing
= PR_TRUE
;
7262 return PR_FALSE
; // break, and stop processing
7264 parentWnd
= ::GetParent(parentWnd
);
7265 } // while parentWnd
7267 if (destWnd
== nsnull
)
7269 if (destWnd
!= mWnd
) {
7271 sIsProcessing
= PR_TRUE
;
7272 aHandled
= destWindow
->ProcessMessage(aMsg
, aWParam
, aLParam
, aRetValue
);
7273 sIsProcessing
= PR_FALSE
;
7274 aQuitProcessing
= PR_TRUE
;
7275 return PR_FALSE
; // break, and stop processing
7279 printf("WARNING: couldn't get child window for SCROLL event\n");
7282 return PR_TRUE
; // caller should handle this
7285 PRBool
nsWindow::OnScroll(UINT aMsg
, WPARAM aWParam
, LPARAM aLParam
)
7287 static PRInt8 sMouseWheelEmulation
= -1;
7288 if (sMouseWheelEmulation
< 0) {
7289 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
7290 NS_ENSURE_TRUE(prefs
, PR_FALSE
);
7291 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
7292 prefs
->GetBranch(0, getter_AddRefs(prefBranch
));
7293 NS_ENSURE_TRUE(prefBranch
, PR_FALSE
);
7296 prefBranch
->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate
);
7297 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7298 sMouseWheelEmulation
= PRInt8(emulate
);
7301 if (aLParam
|| sMouseWheelEmulation
) {
7302 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7303 // Treat as a mousewheel message and scroll appropriately
7304 PRBool quit
, result
;
7307 if (!HandleScrollingPlugins(aMsg
, aWParam
, aLParam
, result
, &retVal
, quit
))
7308 return quit
; // Return if it's not our message or has been dispatched
7310 nsMouseScrollEvent
scrollevent(PR_TRUE
, NS_MOUSE_SCROLL
, this);
7311 scrollevent
.scrollFlags
= (aMsg
== WM_VSCROLL
)
7312 ? nsMouseScrollEvent::kIsVertical
7313 : nsMouseScrollEvent::kIsHorizontal
;
7314 switch (LOWORD(aWParam
))
7317 scrollevent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
7319 scrollevent
.delta
= 1;
7322 scrollevent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
7324 scrollevent
.delta
= -1;
7330 // The event may go to a plug-in which already dispatched this message.
7331 // Then, the event can cause deadlock. We should unlock the sender here.
7334 scrollevent
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
7335 scrollevent
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
7336 scrollevent
.isMeta
= PR_FALSE
;
7337 scrollevent
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
7338 InitEvent(scrollevent
);
7339 if (nsnull
!= mEventCallback
)
7341 DispatchWindowEvent(&scrollevent
);
7346 // Scroll message generated by external application
7347 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_SCROLL
, this);
7349 command
.mScroll
.mIsHorizontal
= (aMsg
== WM_HSCROLL
);
7351 switch (LOWORD(aWParam
))
7353 case SB_LINEUP
: // SB_LINELEFT
7354 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Line
;
7355 command
.mScroll
.mAmount
= -1;
7357 case SB_LINEDOWN
: // SB_LINERIGHT
7358 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Line
;
7359 command
.mScroll
.mAmount
= 1;
7361 case SB_PAGEUP
: // SB_PAGELEFT
7362 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Page
;
7363 command
.mScroll
.mAmount
= -1;
7365 case SB_PAGEDOWN
: // SB_PAGERIGHT
7366 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Page
;
7367 command
.mScroll
.mAmount
= 1;
7369 case SB_TOP
: // SB_LEFT
7370 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Whole
;
7371 command
.mScroll
.mAmount
= -1;
7373 case SB_BOTTOM
: // SB_RIGHT
7374 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Whole
;
7375 command
.mScroll
.mAmount
= 1;
7380 DispatchWindowEvent(&command
);
7384 // Can be overriden. Controls auto-erase of background.
7385 PRBool
nsWindow::AutoErase(HDC dc
)
7390 /**************************************************************
7391 **************************************************************
7393 ** BLOCK: IME management and accessibility
7395 ** Handles managing IME input and accessibility.
7397 **************************************************************
7398 **************************************************************/
7400 NS_IMETHODIMP
nsWindow::ResetInputState()
7402 #ifdef DEBUG_KBSTATE
7403 printf("ResetInputState\n");
7406 #ifdef NS_ENABLE_TSF
7407 nsTextStore::CommitComposition(PR_FALSE
);
7408 #endif //NS_ENABLE_TSF
7410 nsIMM32Handler::CommitComposition(this);
7414 NS_IMETHODIMP
nsWindow::SetIMEOpenState(PRBool aState
)
7416 #ifdef DEBUG_KBSTATE
7417 printf("SetIMEOpenState %s\n", (aState
? "Open" : "Close"));
7420 #ifdef NS_ENABLE_TSF
7421 nsTextStore::SetIMEOpenState(aState
);
7422 #endif //NS_ENABLE_TSF
7424 nsIMEContext
IMEContext(mWnd
);
7425 if (IMEContext
.IsValid()) {
7426 ::ImmSetOpenStatus(IMEContext
.get(), aState
? TRUE
: FALSE
);
7431 NS_IMETHODIMP
nsWindow::GetIMEOpenState(PRBool
* aState
)
7433 nsIMEContext
IMEContext(mWnd
);
7434 if (IMEContext
.IsValid()) {
7435 BOOL isOpen
= ::ImmGetOpenStatus(IMEContext
.get());
7436 *aState
= isOpen
? PR_TRUE
: PR_FALSE
;
7440 #ifdef NS_ENABLE_TSF
7441 *aState
|= nsTextStore::GetIMEOpenState();
7442 #endif //NS_ENABLE_TSF
7447 NS_IMETHODIMP
nsWindow::SetIMEEnabled(PRUint32 aState
)
7449 #ifdef NS_ENABLE_TSF
7450 nsTextStore::SetIMEEnabled(aState
);
7451 #endif //NS_ENABLE_TSF
7452 #ifdef DEBUG_KBSTATE
7453 printf("SetIMEEnabled: %s\n", (aState
== nsIWidget::IME_STATUS_ENABLED
||
7454 aState
== nsIWidget::IME_STATUS_PLUGIN
)?
7455 "Enabled": "Disabled");
7457 if (nsIMM32Handler::IsComposing()) {
7460 mIMEEnabled
= aState
;
7461 PRBool enable
= (aState
== nsIWidget::IME_STATUS_ENABLED
||
7462 aState
== nsIWidget::IME_STATUS_PLUGIN
);
7464 #if defined(WINCE_HAVE_SOFTKB)
7465 sSoftKeyboardState
= (aState
!= nsIWidget::IME_STATUS_DISABLED
);
7466 nsWindowCE::ToggleSoftKB(mWnd
, sSoftKeyboardState
);
7469 if (!enable
!= !mOldIMC
)
7471 mOldIMC
= ::ImmAssociateContext(mWnd
, enable
? mOldIMC
: NULL
);
7472 NS_ASSERTION(!enable
|| !mOldIMC
, "Another IMC was associated");
7477 NS_IMETHODIMP
nsWindow::GetIMEEnabled(PRUint32
* aState
)
7479 #ifdef DEBUG_KBSTATE
7480 printf("GetIMEEnabled: %s\n", mIMEEnabled
? "Enabled": "Disabled");
7482 *aState
= mIMEEnabled
;
7486 NS_IMETHODIMP
nsWindow::CancelIMEComposition()
7488 #ifdef DEBUG_KBSTATE
7489 printf("CancelIMEComposition\n");
7492 #ifdef NS_ENABLE_TSF
7493 nsTextStore::CommitComposition(PR_TRUE
);
7494 #endif //NS_ENABLE_TSF
7496 nsIMM32Handler::CancelComposition(this);
7501 nsWindow::GetToggledKeyState(PRUint32 aKeyCode
, PRBool
* aLEDState
)
7503 #ifdef DEBUG_KBSTATE
7504 printf("GetToggledKeyState\n");
7506 NS_ENSURE_ARG_POINTER(aLEDState
);
7507 *aLEDState
= (::GetKeyState(aKeyCode
) & 1) != 0;
7511 #ifdef NS_ENABLE_TSF
7513 nsWindow::OnIMEFocusChange(PRBool aFocus
)
7515 nsresult rv
= nsTextStore::OnFocusChange(aFocus
, this, mIMEEnabled
);
7516 if (rv
== NS_ERROR_NOT_AVAILABLE
)
7517 rv
= NS_ERROR_NOT_IMPLEMENTED
; // TSF is not enabled, maybe.
7522 nsWindow::OnIMETextChange(PRUint32 aStart
,
7526 return nsTextStore::OnTextChange(aStart
, aOldEnd
, aNewEnd
);
7530 nsWindow::OnIMESelectionChange(void)
7532 return nsTextStore::OnSelectionChange();
7534 #endif //NS_ENABLE_TSF
7536 #ifdef ACCESSIBILITY
7538 #ifdef DEBUG_WMGETOBJECT
7539 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
7540 nsAccessible* acc = aWnd ? \
7541 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
7542 printf(" acc: %p", acc); \
7544 nsAutoString name; \
7545 acc->GetName(name); \
7546 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
7547 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
7548 void *hwnd = nsnull; \
7549 doc->GetWindowHandle(&hwnd); \
7550 printf(", acc hwnd: %d", hwnd); \
7553 #define NS_LOG_WMGETOBJECT_THISWND \
7555 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
7556 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p, content type: %d,\n",\
7557 mWnd, ::GetParent(mWnd), this, mContentType); \
7558 NS_LOG_WMGETOBJECT_WNDACC(this) \
7562 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
7564 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
7565 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7566 aHwnd, ::GetParent(aHwnd), wnd); \
7567 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
7571 #define NS_LOG_WMGETOBJECT_THISWND
7572 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
7573 #endif // DEBUG_WMGETOBJECT
7576 nsWindow::GetRootAccessible()
7578 // We want the ability to forcibly disable a11y on windows, because
7579 // some non-a11y-related components attempt to bring it up. See bug
7580 // 538530 for details; we have a pref here that allows it to be disabled
7581 // for performance and testing resons.
7583 // This pref is checked only once, and the browser needs a restart to
7584 // pick up any changes.
7585 static int accForceDisable
= -1;
7587 if (accForceDisable
== -1) {
7588 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
7589 PRBool b
= PR_FALSE
;
7590 nsresult rv
= prefs
->GetBoolPref("accessibility.win32.force_disabled", &b
);
7591 if (NS_SUCCEEDED(rv
) && b
) {
7592 accForceDisable
= 1;
7594 accForceDisable
= 0;
7598 // If the pref was true, return null here, disabling a11y.
7599 if (accForceDisable
)
7602 nsWindow::sIsAccessibilityOn
= TRUE
;
7604 if (mInDtor
|| mOnDestroyCalled
|| mWindowType
== eWindowType_invisible
) {
7608 NS_LOG_WMGETOBJECT_THISWND
7610 if (mContentType
!= eContentTypeInherit
) {
7611 // We're on a MozillaContentWindowClass or MozillaUIWindowClass window.
7612 // Search for the correct visible child window to get an accessible
7613 // document from. Make sure to use an active child window. If this window
7614 // doesn't have child windows then return an accessible for it.
7615 HWND accessibleWnd
= ::GetTopWindow(mWnd
);
7616 NS_LOG_WMGETOBJECT_WND("Top Window", accessibleWnd
);
7617 if (!accessibleWnd
) {
7618 NS_LOG_WMGETOBJECT_WND("This Window", mWnd
);
7619 return DispatchAccessibleEvent(NS_GETACCESSIBLE
);
7622 nsWindow
* accessibleWindow
= nsnull
;
7623 while (accessibleWnd
) {
7624 // Loop through windows and find the first one with accessibility info
7625 accessibleWindow
= GetNSWindowPtr(accessibleWnd
);
7626 if (accessibleWindow
) {
7627 nsAccessible
*rootAccessible
=
7628 accessibleWindow
->DispatchAccessibleEvent(NS_GETACCESSIBLE
);
7629 if (rootAccessible
) {
7630 // Success, one of the child windows was active.
7631 return rootAccessible
;
7634 accessibleWnd
= ::GetNextWindow(accessibleWnd
, GW_HWNDNEXT
);
7635 NS_LOG_WMGETOBJECT_WND("Next Window", accessibleWnd
);
7640 NS_LOG_WMGETOBJECT_WND("This Window", mWnd
);
7641 return DispatchAccessibleEvent(NS_GETACCESSIBLE
);
7644 STDMETHODIMP_(LRESULT
)
7645 nsWindow::LresultFromObject(REFIID riid
, WPARAM wParam
, LPUNKNOWN pAcc
)
7647 // open the dll dynamically
7649 sAccLib
=::LoadLibraryW(L
"OLEACC.DLL");
7652 if (!sLresultFromObject
)
7653 sLresultFromObject
= (LPFNLRESULTFROMOBJECT
)GetProcAddress(sAccLib
,"LresultFromObject");
7655 if (sLresultFromObject
)
7656 return sLresultFromObject(riid
,wParam
,pAcc
);
7663 /**************************************************************
7664 **************************************************************
7666 ** BLOCK: Transparency
7668 ** Window transparency helpers.
7670 **************************************************************
7671 **************************************************************/
7675 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth
, PRInt32 aNewHeight
, PRBool force
)
7677 if (!force
&& aNewWidth
== mBounds
.width
&& aNewHeight
== mBounds
.height
)
7680 #ifdef CAIRO_HAS_D2D_SURFACE
7681 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7682 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7683 nsRefPtr
<gfxD2DSurface
> newSurface
=
7684 new gfxD2DSurface(gfxIntSize(aNewWidth
, aNewHeight
), gfxASurface::ImageFormatARGB32
);
7685 mTransparentSurface
= newSurface
;
7690 nsRefPtr
<gfxWindowsSurface
> newSurface
=
7691 new gfxWindowsSurface(gfxIntSize(aNewWidth
, aNewHeight
), gfxASurface::ImageFormatARGB32
);
7692 mTransparentSurface
= newSurface
;
7693 mMemoryDC
= newSurface
->GetDC();
7697 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode
)
7701 if (aMode
== mTransparencyMode
)
7704 // stop on dialogs and popups!
7705 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
7706 nsWindow
* parent
= GetNSWindowPtr(hWnd
);
7710 NS_WARNING("Trying to use transparent chrome in an embedded context");
7714 if (parent
!= this) {
7715 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
7718 if (aMode
== eTransparencyTransparent
) {
7719 // If we're switching to the use of a transparent window, hide the chrome
7721 HideWindowChrome(PR_TRUE
);
7722 } else if (mHideChrome
&& mTransparencyMode
== eTransparencyTransparent
) {
7723 // if we're switching out of transparent, re-enable our parent's chrome.
7724 HideWindowChrome(PR_FALSE
);
7727 LONG_PTR style
= ::GetWindowLongPtrW(hWnd
, GWL_STYLE
),
7728 exStyle
= ::GetWindowLongPtr(hWnd
, GWL_EXSTYLE
);
7730 if (parent
->mIsVisible
)
7731 style
|= WS_VISIBLE
;
7732 if (parent
->mSizeMode
== nsSizeMode_Maximized
)
7733 style
|= WS_MAXIMIZE
;
7734 else if (parent
->mSizeMode
== nsSizeMode_Minimized
)
7735 style
|= WS_MINIMIZE
;
7737 if (aMode
== eTransparencyTransparent
)
7738 exStyle
|= WS_EX_LAYERED
;
7740 exStyle
&= ~WS_EX_LAYERED
;
7742 VERIFY_WINDOW_STYLE(style
);
7743 ::SetWindowLongPtrW(hWnd
, GWL_STYLE
, style
);
7744 ::SetWindowLongPtrW(hWnd
, GWL_EXSTYLE
, exStyle
);
7746 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7748 memset(&mGlassMargins
, 0, sizeof mGlassMargins
);
7749 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7750 mTransparencyMode
= aMode
;
7752 SetupTranslucentWindowMemoryBitmap(aMode
);
7754 #endif // #ifndef WINCE
7757 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode
)
7759 if (eTransparencyTransparent
== aMode
) {
7760 ResizeTranslucentWindow(mBounds
.width
, mBounds
.height
, PR_TRUE
);
7762 mTransparentSurface
= nsnull
;
7767 nsresult
nsWindow::UpdateTranslucentWindow()
7770 if (mBounds
.IsEmpty())
7775 BLENDFUNCTION bf
= { AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
7776 SIZE winSize
= { mBounds
.width
, mBounds
.height
};
7777 POINT srcPos
= { 0, 0 };
7778 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
7780 ::GetWindowRect(hWnd
, &winRect
);
7782 #ifdef CAIRO_HAS_D2D_SURFACE
7783 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7784 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7785 mMemoryDC
= static_cast<gfxD2DSurface
*>(mTransparentSurface
.get())->
7789 // perform the alpha blend
7790 PRBool updateSuccesful
=
7791 ::UpdateLayeredWindow(hWnd
, NULL
, (POINT
*)&winRect
, &winSize
, mMemoryDC
, &srcPos
, 0, &bf
, ULW_ALPHA
);
7793 #ifdef CAIRO_HAS_D2D_SURFACE
7794 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7795 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7796 nsIntRect
r(0, 0, 0, 0);
7797 static_cast<gfxD2DSurface
*>(mTransparentSurface
.get())->ReleaseDC(&r
);
7801 if (!updateSuccesful
) {
7802 return NS_ERROR_FAILURE
;
7811 /**************************************************************
7812 **************************************************************
7814 ** BLOCK: Popup rollup hooks
7816 ** Deals with CaptureRollup on popup windows.
7818 **************************************************************
7819 **************************************************************/
7822 // Schedules a timer for a window, so we can rollup after processing the hook event
7823 void nsWindow::ScheduleHookTimer(HWND aWnd
, UINT aMsgId
)
7825 // In some cases multiple hooks may be scheduled
7826 // so ignore any other requests once one timer is scheduled
7827 if (sHookTimerId
== 0) {
7828 // Remember the window handle and the message ID to be used later
7829 sRollupMsgId
= aMsgId
;
7830 sRollupMsgWnd
= aWnd
;
7831 // Schedule native timer for doing the rollup after
7832 // this event is done being processed
7833 sHookTimerId
= ::SetTimer(NULL
, 0, 0, (TIMERPROC
)HookTimerForPopups
);
7834 NS_ASSERTION(sHookTimerId
, "Timer couldn't be created.");
7838 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7839 int gLastMsgCode
= 0;
7840 extern MSGFEventMsgInfo gMSGFEvents
[];
7843 // Process Menu messages, rollup when popup is clicked.
7844 LRESULT CALLBACK
nsWindow::MozSpecialMsgFilter(int code
, WPARAM wParam
, LPARAM lParam
)
7846 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7848 MSG
* pMsg
= (MSG
*)lParam
;
7851 while (gMSGFEvents
[inx
].mId
!= code
&& gMSGFEvents
[inx
].mStr
!= NULL
) {
7854 if (code
!= gLastMsgCode
) {
7855 if (gMSGFEvents
[inx
].mId
== code
) {
7857 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code
, gMSGFEvents
[inx
].mStr
, pMsg
->hwnd
);
7861 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code
, gMSGFEvents
[inx
].mId
, pMsg
->hwnd
);
7864 gLastMsgCode
= code
;
7866 PrintEvent(pMsg
->message
, FALSE
, FALSE
);
7868 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7870 if (sProcessHook
&& code
== MSGF_MENU
) {
7871 MSG
* pMsg
= (MSG
*)lParam
;
7872 ScheduleHookTimer( pMsg
->hwnd
, pMsg
->message
);
7875 return ::CallNextHookEx(sMsgFilterHook
, code
, wParam
, lParam
);
7878 // Process all mouse messages. Roll up when a click is in a native window
7879 // that doesn't have an nsIWidget.
7880 LRESULT CALLBACK
nsWindow::MozSpecialMouseProc(int code
, WPARAM wParam
, LPARAM lParam
)
7884 case WM_LBUTTONDOWN
:
7885 case WM_RBUTTONDOWN
:
7886 case WM_MBUTTONDOWN
:
7888 case WM_MOUSEHWHEEL
:
7890 MOUSEHOOKSTRUCT
* ms
= (MOUSEHOOKSTRUCT
*)lParam
;
7891 nsIWidget
* mozWin
= (nsIWidget
*)GetNSWindowPtr(ms
->hwnd
);
7893 // If this window is windowed plugin window, the mouse events are not
7895 if (static_cast<nsWindow
*>(mozWin
)->mWindowType
== eWindowType_plugin
)
7896 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
7898 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
7904 return ::CallNextHookEx(sCallMouseHook
, code
, wParam
, lParam
);
7907 // Process all messages. Roll up when the window is moving, or
7908 // is resizing or when maximized or mininized.
7909 LRESULT CALLBACK
nsWindow::MozSpecialWndProc(int code
, WPARAM wParam
, LPARAM lParam
)
7911 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7913 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
7914 PrintEvent(cwpt
->message
, FALSE
, FALSE
);
7919 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
7920 if (cwpt
->message
== WM_MOVING
||
7921 cwpt
->message
== WM_SIZING
||
7922 cwpt
->message
== WM_GETMINMAXINFO
) {
7923 ScheduleHookTimer(cwpt
->hwnd
, (UINT
)cwpt
->message
);
7927 return ::CallNextHookEx(sCallProcHook
, code
, wParam
, lParam
);
7930 // Register the special "hooks" for dropdown processing.
7931 void nsWindow::RegisterSpecialDropdownHooks()
7933 NS_ASSERTION(!sMsgFilterHook
, "sMsgFilterHook must be NULL!");
7934 NS_ASSERTION(!sCallProcHook
, "sCallProcHook must be NULL!");
7936 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
7938 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
7940 // Install msg hook for moving the window and resizing
7941 if (!sMsgFilterHook
) {
7942 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
7943 sMsgFilterHook
= SetWindowsHookEx(WH_MSGFILTER
, MozSpecialMsgFilter
, NULL
, GetCurrentThreadId());
7944 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7945 if (!sMsgFilterHook
) {
7946 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
7951 // Install msg hook for menus
7952 if (!sCallProcHook
) {
7953 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
7954 sCallProcHook
= SetWindowsHookEx(WH_CALLWNDPROC
, MozSpecialWndProc
, NULL
, GetCurrentThreadId());
7955 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7956 if (!sCallProcHook
) {
7957 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
7962 // Install msg hook for the mouse
7963 if (!sCallMouseHook
) {
7964 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
7965 sCallMouseHook
= SetWindowsHookEx(WH_MOUSE
, MozSpecialMouseProc
, NULL
, GetCurrentThreadId());
7966 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7967 if (!sCallMouseHook
) {
7968 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
7974 // Unhook special message hooks for dropdowns.
7975 void nsWindow::UnregisterSpecialDropdownHooks()
7977 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
7979 if (sCallProcHook
) {
7980 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
7981 if (!::UnhookWindowsHookEx(sCallProcHook
)) {
7982 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
7984 sCallProcHook
= NULL
;
7987 if (sMsgFilterHook
) {
7988 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
7989 if (!::UnhookWindowsHookEx(sMsgFilterHook
)) {
7990 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
7992 sMsgFilterHook
= NULL
;
7995 if (sCallMouseHook
) {
7996 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
7997 if (!::UnhookWindowsHookEx(sCallMouseHook
)) {
7998 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
8000 sCallMouseHook
= NULL
;
8004 // This timer is designed to only fire one time at most each time a "hook" function
8005 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
8006 // hook, but that hook event or a subsequent event may roll up the dropdown before
8007 // this timer function is executed.
8009 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
8010 // before this function fires.
8011 VOID CALLBACK
nsWindow::HookTimerForPopups(HWND hwnd
, UINT uMsg
, UINT idEvent
, DWORD dwTime
)
8013 if (sHookTimerId
!= 0) {
8014 // if the window is NULL then we need to use the ID to kill the timer
8015 BOOL status
= ::KillTimer(NULL
, sHookTimerId
);
8016 NS_ASSERTION(status
, "Hook Timer was not killed.");
8020 if (sRollupMsgId
!= 0) {
8021 // Note: DealWithPopups does the check to make sure that
8022 // sRollupListener and sRollupWidget are not NULL
8023 LRESULT popupHandlingResult
;
8024 nsAutoRollup autoRollup
;
8025 DealWithPopups(sRollupMsgWnd
, sRollupMsgId
, 0, 0, &popupHandlingResult
);
8027 sRollupMsgWnd
= NULL
;
8032 BOOL CALLBACK
nsWindow::ClearResourcesCallback(HWND aWnd
, LPARAM aMsg
)
8034 nsWindow
*window
= nsWindow::GetNSWindowPtr(aWnd
);
8036 window
->ClearCachedResources();
8042 nsWindow::ClearCachedResources()
8044 #ifdef CAIRO_HAS_D2D_SURFACE
8045 mD2DWindowSurface
= nsnull
;
8047 if (mLayerManager
&&
8048 mLayerManager
->GetBackendType() == LayerManager::LAYERS_BASIC
) {
8049 static_cast<BasicLayerManager
*>(mLayerManager
.get())->
8050 ClearCachedResources();
8052 ::EnumChildWindows(mWnd
, nsWindow::ClearResourcesCallback
, NULL
);
8055 static PRBool
IsDifferentThreadWindow(HWND aWnd
)
8057 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd
, NULL
);
8061 nsWindow::EventIsInsideWindow(UINT Msg
, nsWindow
* aWindow
)
8066 if (Msg
== WM_ACTIVATEAPP
)
8067 // don't care about activation/deactivation
8070 if (Msg
== WM_ACTIVATE
)
8071 // but on Windows CE we do care about
8072 // activation/deactivation because there doesn't exist
8073 // cancelable Mouse Activation events
8077 ::GetWindowRect(aWindow
->mWnd
, &r
);
8078 DWORD pos
= ::GetMessagePos();
8080 mp
.x
= GET_X_LPARAM(pos
);
8081 mp
.y
= GET_Y_LPARAM(pos
);
8083 // was the event inside this window?
8084 return (PRBool
) PtInRect(&r
, mp
);
8087 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8089 nsWindow::DealWithPopups(HWND inWnd
, UINT inMsg
, WPARAM inWParam
, LPARAM inLParam
, LRESULT
* outResult
)
8091 if (sRollupListener
&& sRollupWidget
&& ::IsWindowVisible(inWnd
)) {
8093 if (inMsg
== WM_LBUTTONDOWN
|| inMsg
== WM_RBUTTONDOWN
|| inMsg
== WM_MBUTTONDOWN
||
8094 inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
|| inMsg
== WM_ACTIVATE
||
8095 (inMsg
== WM_KILLFOCUS
&& IsDifferentThreadWindow((HWND
)inWParam
))
8098 inMsg
== WM_NCRBUTTONDOWN
||
8099 inMsg
== WM_MOVING
||
8100 inMsg
== WM_SIZING
||
8101 inMsg
== WM_NCLBUTTONDOWN
||
8102 inMsg
== WM_NCMBUTTONDOWN
||
8103 inMsg
== WM_MOUSEACTIVATE
||
8104 inMsg
== WM_ACTIVATEAPP
||
8105 inMsg
== WM_MENUSELECT
8109 // Rollup if the event is outside the popup.
8110 PRBool rollup
= !nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)sRollupWidget
);
8112 if (rollup
&& (inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
))
8114 sRollupListener
->ShouldRollupOnMouseWheelEvent(&rollup
);
8115 *outResult
= PR_TRUE
;
8118 // If we're dealing with menus, we probably have submenus and we don't
8119 // want to rollup if the click is in a parent menu of the current submenu.
8120 PRUint32 popupsToRollup
= PR_UINT32_MAX
;
8122 if ( sMenuRollup
) {
8123 nsAutoTArray
<nsIWidget
*, 5> widgetChain
;
8124 PRUint32 sameTypeCount
= sMenuRollup
->GetSubmenuWidgetChain(&widgetChain
);
8125 for ( PRUint32 i
= 0; i
< widgetChain
.Length(); ++i
) {
8126 nsIWidget
* widget
= widgetChain
[i
];
8127 if ( nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)widget
) ) {
8128 // don't roll up if the mouse event occurred within a menu of the
8129 // same type. If the mouse event occurred in a menu higher than
8130 // that, roll up, but pass the number of popups to Rollup so
8131 // that only those of the same type close up.
8132 if (i
< sameTypeCount
) {
8136 popupsToRollup
= sameTypeCount
;
8140 } // foreach parent menu widget
8141 } // if rollup listener knows about menus
8145 if (inMsg
== WM_MOUSEACTIVATE
&& popupsToRollup
== PR_UINT32_MAX
) {
8146 // Prevent the click inside the popup from causing a change in window
8147 // activation. Since the popup is shown non-activated, we need to eat
8148 // any requests to activate the window while it is displayed. Windows
8149 // will automatically activate the popup on the mousedown otherwise.
8151 *outResult
= MA_NOACTIVATE
;
8156 UINT uMsg
= HIWORD(inLParam
);
8157 if (uMsg
== WM_MOUSEMOVE
)
8159 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8160 // must be enabled in Windows.
8161 sRollupListener
->ShouldRollupOnMouseActivate(&rollup
);
8164 *outResult
= MA_NOACTIVATE
;
8170 // if we've still determined that we should still rollup everything, do it.
8174 // sRollupConsumeEvent may be modified by
8175 // nsIRollupListener::Rollup.
8176 PRBool consumeRollupEvent
= sRollupConsumeEvent
;
8177 // only need to deal with the last rollup for left mouse down events.
8178 sRollupListener
->Rollup(popupsToRollup
, inMsg
== WM_LBUTTONDOWN
? &mLastRollup
: nsnull
);
8180 // Tell hook to stop processing messages
8181 sProcessHook
= PR_FALSE
;
8183 sRollupMsgWnd
= NULL
;
8185 // return TRUE tells Windows that the event is consumed,
8186 // false allows the event to be dispatched
8188 // So if we are NOT supposed to be consuming events, let it go through
8189 if (consumeRollupEvent
&& inMsg
!= WM_RBUTTONDOWN
) {
8194 // if we are only rolling up some popups, don't activate and don't let
8195 // the event go through. This prevents clicks menus higher in the
8196 // chain from opening when a context menu is open
8197 if (popupsToRollup
!= PR_UINT32_MAX
&& inMsg
== WM_MOUSEACTIVATE
) {
8198 *outResult
= MA_NOACTIVATEANDEAT
;
8203 } // if event that might trigger a popup to rollup
8204 } // if rollup listeners registered
8209 /**************************************************************
8210 **************************************************************
8212 ** BLOCK: Misc. utility methods and functions.
8216 **************************************************************
8217 **************************************************************/
8219 // nsModifierKeyState used in various character processing.
8220 nsModifierKeyState::nsModifierKeyState()
8222 mIsShiftDown
= IS_VK_DOWN(NS_VK_SHIFT
);
8223 mIsControlDown
= IS_VK_DOWN(NS_VK_CONTROL
);
8224 mIsAltDown
= IS_VK_DOWN(NS_VK_ALT
);
8228 PRInt32
nsWindow::GetWindowsVersion()
8233 static PRInt32 version
= 0;
8234 static PRBool didCheck
= PR_FALSE
;
8239 OSVERSIONINFOEX osInfo
;
8240 osInfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
8241 // This cast is safe and supposed to be here, don't worry
8242 ::GetVersionEx((OSVERSIONINFO
*)&osInfo
);
8243 version
= (osInfo
.dwMajorVersion
& 0xff) << 8 | (osInfo
.dwMinorVersion
& 0xff);
8249 // Note that the result of GetTopLevelWindow method can be different from the
8250 // result of GetTopLevelHWND method. The result can be non-floating window.
8251 // Because our top level window may be contained in another window which is
8252 // not managed by us.
8253 nsWindow
* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup
)
8255 nsWindow
* curWindow
= this;
8258 if (aStopOnDialogOrPopup
) {
8259 switch (curWindow
->mWindowType
) {
8260 case eWindowType_dialog
:
8261 case eWindowType_popup
:
8268 // Retrieve the top level parent or owner window
8269 nsWindow
* parentWindow
= curWindow
->GetParentWindow(PR_TRUE
);
8274 curWindow
= parentWindow
;
8278 // Note that the result of GetTopLevelHWND can be different from the result
8279 // of GetTopLevelWindow method. Because this is checking whether the window
8280 // is top level only in Win32 window system. Therefore, the result window
8281 // may not be managed by us.
8282 HWND
nsWindow::GetTopLevelHWND(HWND aWnd
, PRBool aStopOnDialogOrPopup
)
8291 if (aStopOnDialogOrPopup
) {
8292 DWORD_PTR style
= ::GetWindowLongPtrW(curWnd
, GWL_STYLE
);
8294 VERIFY_WINDOW_STYLE(style
);
8296 if (!(style
& WS_CHILD
)) // first top-level window
8300 upWnd
= ::GetParent(curWnd
); // Parent or owner (if has no parent)
8303 // For dialog windows, we want just the parent, not the owner.
8304 // For other/popup windows, we want to find the first owner/parent
8305 // that's a dialog and/or has an owner.
8306 if (upWnd
&& ::GetWindow(curWnd
, GW_OWNER
) == upWnd
) {
8307 DWORD_PTR style
= ::GetWindowLongPtrW(curWnd
, GWL_STYLE
);
8308 if ((style
& WS_DLGFRAME
) != 0)
8319 static BOOL CALLBACK
gEnumWindowsProc(HWND hwnd
, LPARAM lParam
)
8322 ::GetWindowThreadProcessId(hwnd
, &pid
);
8323 if (pid
== GetCurrentProcessId() && ::IsWindowVisible(hwnd
))
8325 gWindowsVisible
= PR_TRUE
;
8331 PRBool
nsWindow::CanTakeFocus()
8333 gWindowsVisible
= PR_FALSE
;
8334 EnumWindows(gEnumWindowsProc
, 0);
8335 if (!gWindowsVisible
) {
8338 HWND fgWnd
= ::GetForegroundWindow();
8343 GetWindowThreadProcessId(fgWnd
, &pid
);
8344 if (pid
== GetCurrentProcessId()) {
8352 void nsWindow::InitTrackPointHack()
8354 // Init Trackpoint Hack
8358 const WCHAR wstrKeys
[][40] = {L
"Software\\Lenovo\\TrackPoint",
8359 L
"Software\\Lenovo\\UltraNav",
8360 L
"Software\\Alps\\Apoint\\TrackPoint",
8361 L
"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
8362 L
"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
8363 // If anything fails turn the hack off
8364 sTrackPointHack
= false;
8365 nsCOMPtr
<nsIPrefBranch
> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
));
8366 if(NS_SUCCEEDED(rv
) && prefs
) {
8367 prefs
->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue
);
8368 switch (lHackValue
) {
8369 // 0 means hack disabled
8372 // 1 means hack enabled
8374 sTrackPointHack
= true;
8376 // -1 means autodetect
8378 for(unsigned i
= 0; i
< NS_ARRAY_LENGTH(wstrKeys
); i
++) {
8380 lResult
= ::RegOpenKeyExW(HKEY_CURRENT_USER
, (LPCWSTR
)&wstrKeys
[i
],
8381 0, KEY_READ
, &hKey
);
8382 ::RegCloseKey(hKey
);
8383 if(lResult
== ERROR_SUCCESS
) {
8384 // If we detected a registry key belonging to a TrackPoint driver
8386 sTrackPointHack
= true;
8391 // Shouldn't be any other values, but treat them as disabled
8398 #endif // #if !defined(WINCE)
8400 LPARAM
nsWindow::lParamToScreen(LPARAM lParam
)
8403 pt
.x
= GET_X_LPARAM(lParam
);
8404 pt
.y
= GET_Y_LPARAM(lParam
);
8405 ::ClientToScreen(mWnd
, &pt
);
8406 return MAKELPARAM(pt
.x
, pt
.y
);
8409 LPARAM
nsWindow::lParamToClient(LPARAM lParam
)
8412 pt
.x
= GET_X_LPARAM(lParam
);
8413 pt
.y
= GET_Y_LPARAM(lParam
);
8414 ::ScreenToClient(mWnd
, &pt
);
8415 return MAKELPARAM(pt
.x
, pt
.y
);
8418 /**************************************************************
8419 **************************************************************
8421 ** BLOCK: ChildWindow impl.
8423 ** Child window overrides.
8425 **************************************************************
8426 **************************************************************/
8428 // return the style for a child nsWindow
8429 DWORD
ChildWindow::WindowStyle()
8431 DWORD style
= WS_CLIPCHILDREN
| nsWindow::WindowStyle();
8432 if (!(style
& WS_POPUP
))
8433 style
|= WS_CHILD
; // WS_POPUP and WS_CHILD are mutually exclusive.
8434 VERIFY_WINDOW_STYLE(style
);