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 (nsWindow::sTrackPointHack
&&
600 mWindowType
!= eWindowType_plugin
&&
601 mWindowType
!= eWindowType_invisible
) {
602 // Ugly Thinkpad Driver Hack (Bug 507222)
603 // We create an invisible scrollbar to trick the
604 // Trackpoint driver into sending us scrolling messages
605 ::CreateWindowW(L
"SCROLLBAR", L
"FAKETRACKPOINTSCROLLBAR",
606 WS_CHILD
| WS_VISIBLE
, 0,0,0,0, mWnd
, NULL
,
607 nsToolkit::mDllInstance
, NULL
);
610 // call the event callback to notify about creation
612 DispatchStandardEvent(NS_CREATE
);
613 SubclassWindow(TRUE
);
615 if (sTrimOnMinimize
== 2 && mWindowType
== eWindowType_invisible
) {
616 /* The internal variable set by the config.trim_on_minimize pref
617 has not yet been initialized, and this is the hidden window
618 (conveniently created before any visible windows, and after
619 the profile has been initialized).
621 Default config.trim_on_minimize to false, to fix bug 76831
622 for good. If anyone complains about this new default, saying
623 that a Mozilla app hogs too much memory while minimized, they
624 will have that entire bug tattooed on their backside. */
627 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
629 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
630 prefs
->GetBranch(0, getter_AddRefs(prefBranch
));
634 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("config.trim_on_minimize",
639 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("intl.keyboard.per_window_layout",
641 sSwitchKeyboardLayout
= temp
;
643 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("mozilla.widget.disable-native-theme",
645 gDisableNativeTheme
= temp
;
649 #if defined(WINCE_HAVE_SOFTKB)
650 if (mWindowType
== eWindowType_dialog
|| mWindowType
== eWindowType_toplevel
)
651 nsWindowCE::CreateSoftKeyMenuBar(mWnd
);
657 // Close this nsWindow
658 NS_METHOD
nsWindow::Destroy()
660 // WM_DESTROY has already fired, we're done.
664 // During the destruction of all of our children, make sure we don't get deleted.
665 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
668 * On windows the LayerManagerOGL destructor wants the widget to be around for
669 * cleanup. It also would like to have the HWND intact, so we NULL it here.
672 mLayerManager
->Destroy();
674 mLayerManager
= nsnull
;
676 /* We should clear our cached resources now and not wait for the GC to
677 * delete the nsWindow. */
678 ClearCachedResources();
680 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
681 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
682 // from it. The function also destroys the window's menu, flushes the thread message queue,
683 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
684 // the window is at the top of the viewer chain).
686 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
687 // the associated child or owned windows when it destroys the parent or owner window. The
688 // function first destroys child or owned windows, and then it destroys the parent or owner
690 VERIFY(::DestroyWindow(mWnd
));
692 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
693 // didn't get called, call it now.
694 if (PR_FALSE
== mOnDestroyCalled
)
700 /**************************************************************
702 * SECTION: Window class utilities
704 * Utilities for calculating the proper window class name for
707 **************************************************************/
709 // Return the proper window class for everything except popups.
710 LPCWSTR
nsWindow::WindowClass()
712 if (!nsWindow::sIsRegistered
) {
715 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
716 wc
.style
= CS_DBLCLKS
;
717 wc
.lpfnWndProc
= ::DefWindowProcW
;
720 wc
.hInstance
= nsToolkit::mDllInstance
;
721 wc
.hIcon
= ::LoadIconW(::GetModuleHandleW(NULL
), (LPWSTR
)IDI_APPLICATION
);
723 wc
.hbrBackground
= mBrush
;
724 wc
.lpszMenuName
= NULL
;
725 wc
.lpszClassName
= kClassNameHidden
;
727 BOOL succeeded
= ::RegisterClassW(&wc
) != 0 &&
728 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError();
729 nsWindow::sIsRegistered
= succeeded
;
731 wc
.lpszClassName
= kClassNameContentFrame
;
732 if (!::RegisterClassW(&wc
) &&
733 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
734 nsWindow::sIsRegistered
= FALSE
;
737 wc
.lpszClassName
= kClassNameContent
;
738 if (!::RegisterClassW(&wc
) &&
739 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
740 nsWindow::sIsRegistered
= FALSE
;
743 wc
.lpszClassName
= kClassNameGeneral
;
744 ATOM generalClassAtom
= ::RegisterClassW(&wc
);
745 if (!generalClassAtom
&&
746 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
747 nsWindow::sIsRegistered
= FALSE
;
750 wc
.lpszClassName
= kClassNameDialog
;
752 if (!::RegisterClassW(&wc
) &&
753 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
754 nsWindow::sIsRegistered
= FALSE
;
758 if (mWindowType
== eWindowType_invisible
) {
759 return kClassNameHidden
;
761 if (mWindowType
== eWindowType_dialog
) {
762 return kClassNameDialog
;
764 if (mContentType
== eContentTypeContent
) {
765 return kClassNameContent
;
767 if (mContentType
== eContentTypeContentFrame
) {
768 return kClassNameContentFrame
;
770 return kClassNameGeneral
;
773 // Return the proper popup window class
774 LPCWSTR
nsWindow::WindowPopupClass()
776 if (!nsWindow::sIsPopupClassRegistered
) {
779 wc
.style
= CS_DBLCLKS
| CS_XP_DROPSHADOW
;
780 wc
.lpfnWndProc
= ::DefWindowProcW
;
783 wc
.hInstance
= nsToolkit::mDllInstance
;
784 wc
.hIcon
= ::LoadIconW(::GetModuleHandleW(NULL
), (LPWSTR
)IDI_APPLICATION
);
786 wc
.hbrBackground
= mBrush
;
787 wc
.lpszMenuName
= NULL
;
788 wc
.lpszClassName
= kClassNameDropShadow
;
790 nsWindow::sIsPopupClassRegistered
= ::RegisterClassW(&wc
);
791 if (!nsWindow::sIsPopupClassRegistered
) {
792 // For older versions of Win32 (i.e., not XP), the registration will
793 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
794 wc
.style
= CS_DBLCLKS
;
795 nsWindow::sIsPopupClassRegistered
= ::RegisterClassW(&wc
);
799 return kClassNameDropShadow
;
802 /**************************************************************
804 * SECTION: Window styles utilities
806 * Return the proper windows styles and extended styles.
808 **************************************************************/
810 // Return nsWindow styles
811 #if !defined(WINCE) // implemented in nsWindowCE.cpp
812 DWORD
nsWindow::WindowStyle()
816 switch (mWindowType
) {
817 case eWindowType_plugin
:
818 case eWindowType_child
:
819 style
= WS_OVERLAPPED
;
822 case eWindowType_dialog
:
823 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
| DS_3DLOOK
|
824 DS_MODALFRAME
| WS_CLIPCHILDREN
;
825 if (mBorderStyle
!= eBorderStyle_default
)
826 style
|= WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
;
829 case eWindowType_popup
:
832 style
|= WS_OVERLAPPED
;
837 NS_ERROR("unknown border style");
840 case eWindowType_toplevel
:
841 case eWindowType_invisible
:
842 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
|
843 WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
| WS_CLIPCHILDREN
;
847 if (mBorderStyle
!= eBorderStyle_default
&& mBorderStyle
!= eBorderStyle_all
) {
848 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_border
))
851 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_title
)) {
852 style
&= ~WS_DLGFRAME
;
857 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_close
))
859 // XXX The close box can only be removed by changing the window class,
860 // as far as I know --- roc+moz@cs.cmu.edu
862 if (mBorderStyle
== eBorderStyle_none
||
863 !(mBorderStyle
& (eBorderStyle_menu
| eBorderStyle_close
)))
864 style
&= ~WS_SYSMENU
;
865 // Looks like getting rid of the system menu also does away with the
866 // close box. So, we only get rid of the system menu if you want neither it
867 // nor the close box. How does the Windows "Dialog" window class get just
868 // closebox and no sysmenu? Who knows.
870 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_resizeh
))
871 style
&= ~WS_THICKFRAME
;
873 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_minimize
))
874 style
&= ~WS_MINIMIZEBOX
;
876 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_maximize
))
877 style
&= ~WS_MAXIMIZEBOX
;
879 if (IsPopupWithTitleBar()) {
881 if (mBorderStyle
& eBorderStyle_close
) {
887 VERIFY_WINDOW_STYLE(style
);
890 #endif // !defined(WINCE)
892 // Return nsWindow extended styles
893 DWORD
nsWindow::WindowExStyle()
897 case eWindowType_plugin
:
898 case eWindowType_child
:
901 case eWindowType_dialog
:
902 return WS_EX_WINDOWEDGE
| WS_EX_DLGMODALFRAME
;
904 case eWindowType_popup
:
906 DWORD extendedStyle
=
907 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
911 if (mPopupLevel
== ePopupLevelTop
)
912 extendedStyle
|= WS_EX_TOPMOST
;
913 return extendedStyle
;
916 NS_ERROR("unknown border style");
919 case eWindowType_toplevel
:
920 case eWindowType_invisible
:
921 return WS_EX_WINDOWEDGE
;
925 /**************************************************************
927 * SECTION: Window subclassing utilities
929 * Set or clear window subclasses on native windows. Used in
930 * Create and Destroy.
932 **************************************************************/
934 // Subclass (or remove the subclass from) this component's nsWindow
935 void nsWindow::SubclassWindow(BOOL bState
)
938 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
939 if (!::IsWindow(mWnd
)) {
940 NS_ERROR("Invalid window handle");
944 // change the nsWindow proc
946 mPrevWndProc
= (WNDPROC
)::SetWindowLongPtrW(mWnd
, GWLP_WNDPROC
,
947 (LONG_PTR
)nsWindow::WindowProc
);
949 mPrevWndProc
= (WNDPROC
)::SetWindowLongPtrA(mWnd
, GWLP_WNDPROC
,
950 (LONG_PTR
)nsWindow::WindowProc
);
951 NS_ASSERTION(mPrevWndProc
, "Null standard window procedure");
952 // connect the this pointer to the nsWindow handle
953 SetNSWindowPtr(mWnd
, this);
957 ::SetWindowLongPtrW(mWnd
, GWLP_WNDPROC
, (LONG_PTR
)mPrevWndProc
);
959 ::SetWindowLongPtrA(mWnd
, GWLP_WNDPROC
, (LONG_PTR
)mPrevWndProc
);
960 SetNSWindowPtr(mWnd
, NULL
);
966 /**************************************************************
968 * SECTION: Window properties
970 * Set and clear native window properties.
972 **************************************************************/
974 static PRUnichar sPropName
[40] = L
"";
975 static PRUnichar
* GetNSWindowPropName()
979 _snwprintf(sPropName
, 39, L
"MozillansIWidgetPtr%p", GetCurrentProcessId());
980 sPropName
[39] = '\0';
985 nsWindow
* nsWindow::GetNSWindowPtr(HWND aWnd
)
987 return (nsWindow
*) ::GetPropW(aWnd
, GetNSWindowPropName());
990 BOOL
nsWindow::SetNSWindowPtr(HWND aWnd
, nsWindow
* ptr
)
993 ::RemovePropW(aWnd
, GetNSWindowPropName());
996 return ::SetPropW(aWnd
, GetNSWindowPropName(), (HANDLE
)ptr
);
1000 /**************************************************************
1002 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
1004 * Set or clear the parent widgets using window properties, and
1005 * handles calculating native parent handles.
1007 **************************************************************/
1009 // Get and set parent widgets
1010 NS_IMETHODIMP
nsWindow::SetParent(nsIWidget
*aNewParent
)
1012 mParent
= aNewParent
;
1015 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
1017 nsIWidget
* parent
= GetParent();
1019 parent
->RemoveChild(this);
1022 HWND newParent
= (HWND
)aNewParent
->GetNativeData(NS_NATIVE_WINDOW
);
1023 NS_ASSERTION(newParent
, "Parent widget has a null native window handle");
1024 if (newParent
&& mWnd
) {
1025 ::SetParent(mWnd
, newParent
);
1028 aNewParent
->AddChild(this);
1033 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
1035 nsIWidget
* parent
= GetParent();
1038 parent
->RemoveChild(this);
1042 // If we have no parent, SetParent should return the desktop.
1043 VERIFY(::SetParent(mWnd
, nsnull
));
1049 nsIWidget
* nsWindow::GetParent(void)
1051 return GetParentWindow(PR_FALSE
);
1054 float nsWindow::GetDPI()
1056 HDC dc
= ::GetDC(mWnd
);
1060 double heightInches
= ::GetDeviceCaps(dc
, VERTSIZE
)/MM_PER_INCH_FLOAT
;
1061 int heightPx
= ::GetDeviceCaps(dc
, VERTRES
);
1062 ::ReleaseDC(mWnd
, dc
);
1063 if (heightInches
< 0.25) {
1064 // Something's broken
1067 return float(heightPx
/heightInches
);
1070 nsWindow
* nsWindow::GetParentWindow(PRBool aIncludeOwner
)
1072 if (mIsTopWidgetWindow
) {
1073 // Must use a flag instead of mWindowType to tell if the window is the
1074 // owned by the topmost widget, because a child window can be embedded inside
1075 // a HWND which is not associated with a nsIWidget.
1079 // If this widget has already been destroyed, pretend we have no parent.
1080 // This corresponds to code in Destroy which removes the destroyed
1081 // widget from its parent's child list.
1082 if (mInDtor
|| mOnDestroyCalled
)
1086 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1087 // root owner. aIncludeOwner set to false implies the search will stop at the
1088 // true parent (default).
1089 nsWindow
* widget
= nsnull
;
1092 HWND parent
= ::GetParent(mWnd
);
1094 HWND parent
= nsnull
;
1096 parent
= ::GetParent(mWnd
);
1098 parent
= ::GetAncestor(mWnd
, GA_PARENT
);
1101 widget
= GetNSWindowPtr(parent
);
1103 // If the widget is in the process of being destroyed then
1105 if (widget
->mInDtor
) {
1115 /**************************************************************
1117 * SECTION: nsIWidget::Show
1119 * Hide or show this component.
1121 **************************************************************/
1123 NS_METHOD
nsWindow::Show(PRBool bState
)
1125 #if defined(MOZ_SPLASHSCREEN)
1126 // we're about to show the first toplevel window,
1127 // so kill off any splash screen if we had one
1128 nsSplashScreen
*splash
= nsSplashScreen::Get();
1129 if (splash
&& splash
->IsOpen() && mWnd
&& bState
&&
1130 (mWindowType
== eWindowType_toplevel
||
1131 mWindowType
== eWindowType_dialog
||
1132 mWindowType
== eWindowType_popup
))
1138 #ifdef NS_FUNCTION_TIMER
1139 static bool firstShow
= true;
1141 (mWindowType
== eWindowType_toplevel
||
1142 mWindowType
== eWindowType_dialog
||
1143 mWindowType
== eWindowType_popup
))
1146 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1150 PRBool wasVisible
= mIsVisible
;
1151 // Set the status now so that anyone asking during ShowWindow or
1152 // SetWindowPos would get the correct answer.
1153 mIsVisible
= bState
;
1155 if (!mIsVisible
&& wasVisible
) {
1156 ClearCachedResources();
1161 if (!wasVisible
&& mWindowType
== eWindowType_toplevel
) {
1162 switch (mSizeMode
) {
1164 case nsSizeMode_Fullscreen
:
1165 ::SetForegroundWindow(mWnd
);
1166 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1167 MakeFullScreen(TRUE
);
1170 case nsSizeMode_Maximized
:
1171 ::SetForegroundWindow(mWnd
);
1172 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1174 // use default for nsSizeMode_Minimized on Windows CE
1176 case nsSizeMode_Maximized
:
1177 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1179 case nsSizeMode_Minimized
:
1180 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
1184 if (CanTakeFocus()) {
1186 ::SetForegroundWindow(mWnd
);
1188 ::ShowWindow(mWnd
, SW_SHOWNORMAL
);
1190 // Place the window behind the foreground window
1191 // (as long as it is not topmost)
1192 HWND wndAfter
= ::GetForegroundWindow();
1194 wndAfter
= HWND_BOTTOM
;
1195 else if (GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
1196 wndAfter
= HWND_TOP
;
1197 ::SetWindowPos(mWnd
, wndAfter
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOSIZE
|
1198 SWP_NOMOVE
| SWP_NOACTIVATE
);
1204 DWORD flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_SHOWWINDOW
;
1206 flags
|= SWP_NOZORDER
;
1208 if (mWindowType
== eWindowType_popup
) {
1210 // ensure popups are the topmost of the TOPMOST
1211 // layer. Remember not to set the SWP_NOZORDER
1212 // flag as that might allow the taskbar to overlap
1213 // the popup. However on windows ce, we need to
1214 // activate the popup or clicks will not be sent.
1215 flags
|= SWP_NOACTIVATE
;
1217 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
1218 ::SetWindowPos(mWnd
, owner
? 0 : HWND_TOPMOST
, 0, 0, 0, 0, flags
);
1221 if (mWindowType
== eWindowType_dialog
&& !CanTakeFocus())
1222 flags
|= SWP_NOACTIVATE
;
1224 ::SetWindowPos(mWnd
, HWND_TOP
, 0, 0, 0, 0, flags
);
1229 if (!wasVisible
&& (mWindowType
== eWindowType_toplevel
|| mWindowType
== eWindowType_dialog
)) {
1230 // when a toplevel window or dialog is shown, initialize the UI state
1231 ::SendMessageW(mWnd
, WM_CHANGEUISTATE
, MAKEWPARAM(UIS_INITIALIZE
, UISF_HIDEFOCUS
| UISF_HIDEACCEL
), 0);
1235 if (mWindowType
!= eWindowType_dialog
) {
1236 ::ShowWindow(mWnd
, SW_HIDE
);
1238 ::SetWindowPos(mWnd
, 0, 0, 0, 0, 0, SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
|
1239 SWP_NOZORDER
| SWP_NOACTIVATE
);
1245 if (!wasVisible
&& bState
)
1246 Invalidate(PR_FALSE
);
1252 /**************************************************************
1254 * SECTION: nsIWidget::IsVisible
1256 * Returns the visibility state.
1258 **************************************************************/
1260 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1261 NS_METHOD
nsWindow::IsVisible(PRBool
& bState
)
1263 bState
= mIsVisible
;
1267 /**************************************************************
1269 * SECTION: Window clipping utilities
1271 * Used in Size and Move operations for setting the proper
1272 * window clipping regions for window transparency.
1274 **************************************************************/
1276 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1277 // transparency. These routines are called on size and move operations.
1278 void nsWindow::ClearThemeRegion()
1281 if (nsUXThemeData::sIsVistaOrLater
&& !HasGlass() &&
1282 mWindowType
== eWindowType_popup
&& (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
)) {
1283 SetWindowRgn(mWnd
, NULL
, false);
1288 void nsWindow::SetThemeRegion()
1291 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1292 // for other window types as needed. The regions are applied generically to the base window
1293 // so default constants are used for part and state. At some point we might need part and
1294 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1295 // change shape based on state haven't come up.
1296 if (nsUXThemeData::sIsVistaOrLater
&& !HasGlass() &&
1297 mWindowType
== eWindowType_popup
&& (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
)) {
1299 RECT rect
= {0,0,mBounds
.width
,mBounds
.height
};
1301 HDC dc
= ::GetDC(mWnd
);
1302 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip
), dc
, TTP_STANDARD
, TS_NORMAL
, &rect
, &hRgn
);
1304 if (!SetWindowRgn(mWnd
, hRgn
, false)) // do not delete or alter hRgn if accepted.
1307 ::ReleaseDC(mWnd
, dc
);
1312 /**************************************************************
1314 * SECTION: nsIWidget::RegisterTouchWindow,
1315 * nsIWidget::UnregisterTouchWindow, and helper functions
1317 * Used to register the native window to receive touch events
1319 **************************************************************/
1321 NS_METHOD
nsWindow::RegisterTouchWindow() {
1322 mTouchWindow
= PR_TRUE
;
1324 mGesture
.RegisterTouchWindow(mWnd
);
1325 ::EnumChildWindows(mWnd
, nsWindow::RegisterTouchForDescendants
, 0);
1330 NS_METHOD
nsWindow::UnregisterTouchWindow() {
1331 mTouchWindow
= PR_FALSE
;
1333 mGesture
.UnregisterTouchWindow(mWnd
);
1334 ::EnumChildWindows(mWnd
, nsWindow::UnregisterTouchForDescendants
, 0);
1340 BOOL CALLBACK
nsWindow::RegisterTouchForDescendants(HWND aWnd
, LPARAM aMsg
) {
1341 nsWindow
* win
= GetNSWindowPtr(aWnd
);
1343 win
->mGesture
.RegisterTouchWindow(aWnd
);
1347 BOOL CALLBACK
nsWindow::UnregisterTouchForDescendants(HWND aWnd
, LPARAM aMsg
) {
1348 nsWindow
* win
= GetNSWindowPtr(aWnd
);
1350 win
->mGesture
.UnregisterTouchWindow(aWnd
);
1355 /**************************************************************
1357 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1358 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1360 * Repositioning and sizing a window.
1362 **************************************************************/
1364 // Move this component
1365 NS_METHOD
nsWindow::Move(PRInt32 aX
, PRInt32 aY
)
1367 if (mWindowType
== eWindowType_toplevel
||
1368 mWindowType
== eWindowType_dialog
) {
1369 SetSizeMode(nsSizeMode_Normal
);
1371 // Check to see if window needs to be moved first
1372 // to avoid a costly call to SetWindowPos. This check
1373 // can not be moved to the calling code in nsView, because
1374 // some platforms do not position child windows correctly
1376 // Only perform this check for non-popup windows, since the positioning can
1377 // in fact change even when the x/y do not. We always need to perform the
1378 // check. See bug #97805 for details.
1379 if (mWindowType
!= eWindowType_popup
&& (mBounds
.x
== aX
) && (mBounds
.y
== aY
))
1381 // Nothing to do, since it is already positioned correctly.
1390 // complain if a window is moved offscreen (legal, but potentially worrisome)
1391 if (mIsTopWidgetWindow
) { // only a problem for top-level windows
1392 // Make sure this window is actually on the screen before we move it
1393 // XXX: Needs multiple monitor support
1394 HDC dc
= ::GetDC(mWnd
);
1396 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1398 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &workArea
, 0);
1399 // no annoying assertions. just mention the issue.
1400 if (aX
< 0 || aX
>= workArea
.right
|| aY
< 0 || aY
>= workArea
.bottom
)
1401 printf("window moved to offscreen position\n");
1403 ::ReleaseDC(mWnd
, dc
);
1408 VERIFY(::SetWindowPos(mWnd
, NULL
, aX
, aY
, 0, 0,
1409 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOSIZE
));
1415 // Resize this component
1416 NS_METHOD
nsWindow::Resize(PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1418 NS_ASSERTION((aWidth
>=0 ) , "Negative width passed to nsWindow::Resize");
1419 NS_ASSERTION((aHeight
>=0 ), "Negative height passed to nsWindow::Resize");
1421 // Avoid unnecessary resizing calls
1422 if (mBounds
.width
== aWidth
&& mBounds
.height
== aHeight
&& !aRepaint
)
1426 if (eTransparencyTransparent
== mTransparencyMode
)
1427 ResizeTranslucentWindow(aWidth
, aHeight
);
1430 // Set cached value for lightweight and printing
1431 mBounds
.width
= aWidth
;
1432 mBounds
.height
= aHeight
;
1435 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOMOVE
;
1439 flags
|= SWP_NOREDRAW
;
1444 VERIFY(::SetWindowPos(mWnd
, NULL
, 0, 0, aWidth
, GetHeight(aHeight
), flags
));
1449 Invalidate(PR_FALSE
);
1454 // Resize this component
1455 NS_METHOD
nsWindow::Resize(PRInt32 aX
, PRInt32 aY
, PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1457 NS_ASSERTION((aWidth
>=0 ), "Negative width passed to nsWindow::Resize");
1458 NS_ASSERTION((aHeight
>=0 ), "Negative height passed to nsWindow::Resize");
1460 // Avoid unnecessary resizing calls
1461 if (mBounds
.x
== aX
&& mBounds
.y
== aY
&&
1462 mBounds
.width
== aWidth
&& mBounds
.height
== aHeight
&& !aRepaint
)
1466 if (eTransparencyTransparent
== mTransparencyMode
)
1467 ResizeTranslucentWindow(aWidth
, aHeight
);
1470 // Set cached value for lightweight and printing
1473 mBounds
.width
= aWidth
;
1474 mBounds
.height
= aHeight
;
1477 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
1480 flags
|= SWP_NOREDRAW
;
1485 VERIFY(::SetWindowPos(mWnd
, NULL
, aX
, aY
, aWidth
, GetHeight(aHeight
), flags
));
1490 Invalidate(PR_FALSE
);
1495 // Resize the client area and position the widget within it's parent
1496 NS_METHOD
nsWindow::ResizeClient(PRInt32 aX
, PRInt32 aY
, PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1498 NS_ASSERTION((aWidth
>=0) , "Negative width passed to ResizeClient");
1499 NS_ASSERTION((aHeight
>=0), "Negative height passed to ResizeClient");
1501 // Adjust our existing window bounds, based on the new client dims.
1503 GetClientRect(mWnd
, &client
);
1504 nsIntPoint
dims(client
.right
- client
.left
, client
.bottom
- client
.top
);
1505 aWidth
= mBounds
.width
+ (aWidth
- dims
.x
);
1506 aHeight
= mBounds
.height
+ (aHeight
- dims
.y
);
1511 GetScreenBounds(bounds
);
1514 return Resize(aX
, aY
, aWidth
, aHeight
, aRepaint
);
1516 return Resize(aWidth
, aHeight
, aRepaint
);
1521 nsWindow::BeginResizeDrag(nsGUIEvent
* aEvent
, PRInt32 aHorizontal
, PRInt32 aVertical
)
1523 NS_ENSURE_ARG_POINTER(aEvent
);
1525 if (aEvent
->eventStructType
!= NS_MOUSE_EVENT
) {
1526 // you can only begin a resize drag with a mouse event
1527 return NS_ERROR_INVALID_ARG
;
1530 nsMouseEvent
* mouseEvent
= static_cast<nsMouseEvent
*>(aEvent
);
1531 if (mouseEvent
->button
!= nsMouseEvent::eLeftButton
) {
1532 // you can only begin a resize drag with the left mouse button
1533 return NS_ERROR_INVALID_ARG
;
1536 // work out what sizemode we're talking about
1538 if (aVertical
< 0) {
1539 if (aHorizontal
< 0) {
1540 syscommand
= SC_SIZE
| WMSZ_TOPLEFT
;
1541 } else if (aHorizontal
== 0) {
1542 syscommand
= SC_SIZE
| WMSZ_TOP
;
1544 syscommand
= SC_SIZE
| WMSZ_TOPRIGHT
;
1546 } else if (aVertical
== 0) {
1547 if (aHorizontal
< 0) {
1548 syscommand
= SC_SIZE
| WMSZ_LEFT
;
1549 } else if (aHorizontal
== 0) {
1550 return NS_ERROR_INVALID_ARG
;
1552 syscommand
= SC_SIZE
| WMSZ_RIGHT
;
1555 if (aHorizontal
< 0) {
1556 syscommand
= SC_SIZE
| WMSZ_BOTTOMLEFT
;
1557 } else if (aHorizontal
== 0) {
1558 syscommand
= SC_SIZE
| WMSZ_BOTTOM
;
1560 syscommand
= SC_SIZE
| WMSZ_BOTTOMRIGHT
;
1564 // resizing doesn't work if the mouse is already captured
1565 CaptureMouse(PR_FALSE
);
1567 // find the top-level window
1568 HWND toplevelWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
1570 // tell Windows to start the resize
1571 ::PostMessage(toplevelWnd
, WM_SYSCOMMAND
, syscommand
,
1572 POINTTOPOINTS(aEvent
->refPoint
));
1577 /**************************************************************
1579 * SECTION: Window Z-order and state.
1581 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1582 * nsIWidget::ConstrainPosition
1584 * Z-order, positioning, restore, minimize, and maximize.
1586 **************************************************************/
1588 // Position the window behind the given window
1589 NS_METHOD
nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement
,
1590 nsIWidget
*aWidget
, PRBool aActivate
)
1592 HWND behind
= HWND_TOP
;
1593 if (aPlacement
== eZPlacementBottom
)
1594 behind
= HWND_BOTTOM
;
1595 else if (aPlacement
== eZPlacementBelow
&& aWidget
)
1596 behind
= (HWND
)aWidget
->GetNativeData(NS_NATIVE_WINDOW
);
1597 UINT flags
= SWP_NOMOVE
| SWP_NOREPOSITION
| SWP_NOSIZE
;
1599 flags
|= SWP_NOACTIVATE
;
1601 if (!CanTakeFocus() && behind
== HWND_TOP
)
1603 // Can't place the window to top so place it behind the foreground window
1604 // (as long as it is not topmost)
1605 HWND wndAfter
= ::GetForegroundWindow();
1607 behind
= HWND_BOTTOM
;
1608 else if (!(GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
1610 flags
|= SWP_NOACTIVATE
;
1613 ::SetWindowPos(mWnd
, behind
, 0, 0, 0, 0, flags
);
1617 // Maximize, minimize or restore the window.
1618 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1619 NS_IMETHODIMP
nsWindow::SetSizeMode(PRInt32 aMode
) {
1623 // Let's not try and do anything if we're already in that state.
1624 // (This is needed to prevent problems when calling window.minimize(), which
1625 // calls us directly, and then the OS triggers another call to us.)
1626 if (aMode
== mSizeMode
)
1629 // save the requested state
1630 rv
= nsBaseWidget::SetSizeMode(aMode
);
1631 if (NS_SUCCEEDED(rv
) && mIsVisible
) {
1635 case nsSizeMode_Fullscreen
:
1639 case nsSizeMode_Maximized
:
1643 case nsSizeMode_Minimized
:
1644 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1645 // keeps the window active in the tray. So after the window is minimized,
1646 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1647 // we will do some additional processing to get the active window set right.
1648 // If sTrimOnMinimize is set, we let windows handle minimization normally
1649 // using SW_MINIMIZE.
1650 mode
= sTrimOnMinimize
? SW_MINIMIZE
: SW_SHOWMINIMIZED
;
1656 ::ShowWindow(mWnd
, mode
);
1657 // we dispatch an activate event here to ensure that the right child window
1659 if (mode
== SW_RESTORE
|| mode
== SW_MAXIMIZE
)
1660 DispatchFocusToTopLevelWindow(NS_ACTIVATE
);
1664 #endif // !defined(WINCE)
1666 // Constrain a potential move to fit onscreen
1667 NS_METHOD
nsWindow::ConstrainPosition(PRBool aAllowSlop
,
1668 PRInt32
*aX
, PRInt32
*aY
)
1670 if (!mIsTopWidgetWindow
) // only a problem for top-level windows
1673 PRBool doConstrain
= PR_FALSE
; // whether we have enough info to do anything
1675 /* get our playing field. use the current screen, or failing that
1676 for any reason, use device caps for the default screen. */
1679 nsCOMPtr
<nsIScreenManager
> screenmgr
= do_GetService(sScreenManagerContractID
);
1681 nsCOMPtr
<nsIScreen
> screen
;
1682 PRInt32 left
, top
, width
, height
;
1684 // zero size rects confuse the screen manager
1685 width
= mBounds
.width
> 0 ? mBounds
.width
: 1;
1686 height
= mBounds
.height
> 0 ? mBounds
.height
: 1;
1687 screenmgr
->ScreenForRect(*aX
, *aY
, width
, height
,
1688 getter_AddRefs(screen
));
1690 if (mSizeMode
!= nsSizeMode_Fullscreen
) {
1691 // For normalized windows, use the desktop work area.
1692 screen
->GetAvailRect(&left
, &top
, &width
, &height
);
1694 // For full screen windows, use the desktop.
1695 screen
->GetRect(&left
, &top
, &width
, &height
);
1697 screenRect
.left
= left
;
1698 screenRect
.right
= left
+width
;
1699 screenRect
.top
= top
;
1700 screenRect
.bottom
= top
+height
;
1701 doConstrain
= PR_TRUE
;
1705 HDC dc
= ::GetDC(mWnd
);
1707 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1708 if (mSizeMode
!= nsSizeMode_Fullscreen
) {
1709 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &screenRect
, 0);
1711 screenRect
.left
= screenRect
.top
= 0;
1712 screenRect
.right
= GetSystemMetrics(SM_CXFULLSCREEN
);
1713 screenRect
.bottom
= GetSystemMetrics(SM_CYFULLSCREEN
);
1715 doConstrain
= PR_TRUE
;
1717 ::ReleaseDC(mWnd
, dc
);
1723 if (*aX
< screenRect
.left
- mBounds
.width
+ kWindowPositionSlop
)
1724 *aX
= screenRect
.left
- mBounds
.width
+ kWindowPositionSlop
;
1725 else if (*aX
>= screenRect
.right
- kWindowPositionSlop
)
1726 *aX
= screenRect
.right
- kWindowPositionSlop
;
1728 if (*aY
< screenRect
.top
- mBounds
.height
+ kWindowPositionSlop
)
1729 *aY
= screenRect
.top
- mBounds
.height
+ kWindowPositionSlop
;
1730 else if (*aY
>= screenRect
.bottom
- kWindowPositionSlop
)
1731 *aY
= screenRect
.bottom
- kWindowPositionSlop
;
1735 if (*aX
< screenRect
.left
)
1736 *aX
= screenRect
.left
;
1737 else if (*aX
>= screenRect
.right
- mBounds
.width
)
1738 *aX
= screenRect
.right
- mBounds
.width
;
1740 if (*aY
< screenRect
.top
)
1741 *aY
= screenRect
.top
;
1742 else if (*aY
>= screenRect
.bottom
- mBounds
.height
)
1743 *aY
= screenRect
.bottom
- mBounds
.height
;
1749 /**************************************************************
1751 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1753 * Enabling and disabling the widget.
1755 **************************************************************/
1757 // Enable/disable this component
1758 NS_METHOD
nsWindow::Enable(PRBool bState
)
1761 ::EnableWindow(mWnd
, bState
);
1766 // Return the current enable state
1767 NS_METHOD
nsWindow::IsEnabled(PRBool
*aState
)
1769 NS_ENSURE_ARG_POINTER(aState
);
1772 *aState
= !mWnd
|| (::IsWindowEnabled(mWnd
) && ::IsWindowEnabled(::GetAncestor(mWnd
, GA_ROOT
)));
1774 *aState
= !mWnd
|| (::IsWindowEnabled(mWnd
) && ::IsWindowEnabled(mWnd
));
1781 /**************************************************************
1783 * SECTION: nsIWidget::SetFocus
1785 * Give the focus to this widget.
1787 **************************************************************/
1789 NS_METHOD
nsWindow::SetFocus(PRBool aRaise
)
1792 #ifdef WINSTATE_DEBUG_OUTPUT
1793 if (mWnd
== GetTopLevelHWND(mWnd
))
1794 printf("*** SetFocus: [ top] raise=%d\n", aRaise
);
1796 printf("*** SetFocus: [child] raise=%d\n", aRaise
);
1798 // Uniconify, if necessary
1799 HWND toplevelWnd
= GetTopLevelHWND(mWnd
);
1800 if (aRaise
&& ::IsIconic(toplevelWnd
)) {
1801 ::ShowWindow(toplevelWnd
, SW_RESTORE
);
1809 /**************************************************************
1813 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1814 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1816 * Bound calculations.
1818 **************************************************************/
1820 // Return the window's full dimensions in screen coordinates.
1821 // If the window has a parent, converts the origin to an offset
1822 // of the parent's screen origin.
1823 NS_METHOD
nsWindow::GetBounds(nsIntRect
&aRect
)
1827 VERIFY(::GetWindowRect(mWnd
, &r
));
1830 aRect
.width
= r
.right
- r
.left
;
1831 aRect
.height
= r
.bottom
- r
.top
;
1833 // chrome on parent:
1834 // ___ 5,5 (chrome start)
1835 // | ____ 10,10 (client start)
1836 // | | ____ 20,20 (child start)
1838 // 20,20 - 5,5 = 15,15 (??)
1839 // minus GetClientOffset:
1840 // 15,15 - 5,5 = 10,10
1842 // no chrome on parent:
1843 // ______ 10,10 (win start)
1844 // | ____ 20,20 (child start)
1846 // 20,20 - 10,10 = 10,10
1848 // walking the chain:
1849 // ___ 5,5 (chrome start)
1850 // | ___ 10,10 (client start)
1851 // | | ___ 20,20 (child start)
1852 // | | | __ 30,30 (child start)
1854 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1855 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1856 // minus GetClientOffset:
1857 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1859 // convert coordinates if parent exists
1860 HWND parent
= ::GetParent(mWnd
);
1863 VERIFY(::GetWindowRect(parent
, &pr
));
1866 // adjust for chrome
1867 nsWindow
* pWidget
= static_cast<nsWindow
*>(GetParent());
1868 if (pWidget
&& pWidget
->IsTopLevelWidget()) {
1869 nsIntPoint clientOffset
= pWidget
->GetClientOffset();
1870 r
.left
-= clientOffset
.x
;
1871 r
.top
-= clientOffset
.y
;
1883 // Get this component dimension
1884 NS_METHOD
nsWindow::GetClientBounds(nsIntRect
&aRect
)
1888 VERIFY(::GetClientRect(mWnd
, &r
));
1893 aRect
.width
= r
.right
- r
.left
;
1894 aRect
.height
= r
.bottom
- r
.top
;
1897 aRect
.SetRect(0,0,0,0);
1902 // Like GetBounds, but don't offset by the parent
1903 NS_METHOD
nsWindow::GetScreenBounds(nsIntRect
&aRect
)
1907 VERIFY(::GetWindowRect(mWnd
, &r
));
1909 aRect
.width
= r
.right
- r
.left
;
1910 aRect
.height
= r
.bottom
- r
.top
;
1919 // return the x,y offset of the client area from the origin
1920 // of the window. If the window is borderless returns (0,0).
1921 nsIntPoint
nsWindow::GetClientOffset()
1924 return nsIntPoint(0, 0);
1928 GetWindowRect(mWnd
, &r1
);
1929 nsIntPoint pt
= WidgetToScreenOffset();
1930 return nsIntPoint(pt
.x
- r1
.left
, pt
.y
- r1
.top
);
1934 nsWindow::SetDrawsInTitlebar(PRBool aState
)
1936 nsWindow
* window
= GetTopLevelWindow(PR_TRUE
);
1937 if (window
&& window
!= this) {
1938 return window
->SetDrawsInTitlebar(aState
);
1942 // left, top, right, bottom for nsIntMargin
1943 nsIntMargin
margins(-1, 0, -1, -1);
1944 SetNonClientMargins(margins
);
1947 nsIntMargin
margins(-1, -1, -1, -1);
1948 SetNonClientMargins(margins
);
1953 nsWindow::GetNonClientMargins(nsIntMargin
&margins
)
1955 nsWindow
* window
= GetTopLevelWindow(PR_TRUE
);
1956 if (window
&& window
!= this) {
1957 return window
->GetNonClientMargins(margins
);
1960 if (mCustomNonClient
) {
1961 margins
= mNonClientMargins
;
1965 margins
.top
= GetSystemMetrics(SM_CYCAPTION
);
1966 margins
.bottom
= GetSystemMetrics(SM_CYFRAME
);
1967 margins
.top
+= margins
.bottom
;
1968 margins
.left
= margins
.right
= GetSystemMetrics(SM_CYFRAME
);
1974 nsWindow::ResetLayout()
1976 // This will trigger a frame changed event, triggering
1977 // nc calc size and a sizemode gecko event.
1978 SetWindowPos(mWnd
, 0, 0, 0, 0, 0,
1979 SWP_FRAMECHANGED
|SWP_NOACTIVATE
|SWP_NOMOVE
|
1980 SWP_NOOWNERZORDER
|SWP_NOSIZE
|SWP_NOZORDER
);
1982 // If hidden, just send the frame changed event for now.
1986 // Send a gecko size event to trigger reflow.
1987 RECT clientRc
= {0};
1988 GetClientRect(mWnd
, &clientRc
);
1989 nsIntRect
evRect(nsWindowGfx::ToIntRect(clientRc
));
1992 // Invalidate and update
1993 Invalidate(PR_FALSE
);
1996 // Called when the window layout changes: full screen mode transitions,
1997 // theme changes, and composition changes. Calculates the new non-client
1998 // margins and fires off a frame changed event, which triggers an nc calc
1999 // size windows event, kicking the changes in.
2001 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode
, PRBool aReflowWindow
)
2003 if (!mCustomNonClient
)
2006 mNonClientOffset
.top
= mNonClientOffset
.bottom
=
2007 mNonClientOffset
.left
= mNonClientOffset
.right
= 0;
2009 if (aSizeMode
== -1)
2010 aSizeMode
= mSizeMode
;
2012 if (aSizeMode
== nsSizeMode_Minimized
||
2013 aSizeMode
== nsSizeMode_Fullscreen
) {
2014 mCaptionHeight
= mVertResizeMargin
= mHorResizeMargin
= 0;
2018 // Note, for maximized windows, we need to continue to offset the client by
2019 // thick frame margins of a normal window, since windows expects this
2020 // in it's DwmDefWndProc hit testing.
2021 mCaptionHeight
= GetSystemMetrics(SM_CYCAPTION
);
2022 mHorResizeMargin
= GetSystemMetrics(SM_CXFRAME
);
2023 mVertResizeMargin
= GetSystemMetrics(SM_CYFRAME
);
2025 mCaptionHeight
+= mVertResizeMargin
;
2027 // If a margin value is 0, set the offset to the default size of the frame.
2028 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2029 // so that the frame size is equal to the margin value.
2030 if (!mNonClientMargins
.top
)
2031 mNonClientOffset
.top
= mCaptionHeight
;
2032 else if (mNonClientMargins
.top
> 0)
2033 mNonClientOffset
.top
= mCaptionHeight
- mNonClientMargins
.top
;
2035 if (!mNonClientMargins
.left
)
2036 mNonClientOffset
.left
= mHorResizeMargin
;
2037 else if (mNonClientMargins
.left
> 0)
2038 mNonClientOffset
.left
= mHorResizeMargin
- mNonClientMargins
.left
;
2040 if (!mNonClientMargins
.right
)
2041 mNonClientOffset
.right
= mHorResizeMargin
;
2042 else if (mNonClientMargins
.right
> 0)
2043 mNonClientOffset
.right
= mHorResizeMargin
- mNonClientMargins
.right
;
2045 if (!mNonClientMargins
.bottom
)
2046 mNonClientOffset
.bottom
= mVertResizeMargin
;
2047 else if (mNonClientMargins
.bottom
> 0)
2048 mNonClientOffset
.bottom
= mVertResizeMargin
- mNonClientMargins
.bottom
;
2051 if (aSizeMode
== nsSizeMode_Maximized
) {
2052 // Address an issue with auto-hide taskbars which fall behind the window.
2053 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2054 // the taskbar works properly.
2055 MONITORINFO info
= {sizeof(MONITORINFO
)};
2056 if (::GetMonitorInfo(::MonitorFromWindow(mWnd
, MONITOR_DEFAULTTOPRIMARY
),
2059 if (::GetWindowRect(mWnd
, &r
)) {
2060 // Adjust window rect to account for non-client margins.
2061 r
.top
+= mVertResizeMargin
- mNonClientOffset
.top
;
2062 r
.left
+= mHorResizeMargin
- mNonClientOffset
.left
;
2063 r
.bottom
-= mVertResizeMargin
- mNonClientOffset
.bottom
;
2064 r
.right
-= mHorResizeMargin
- mNonClientOffset
.right
;
2065 // Leave the 1 pixel margin if the window covers the monitor.
2066 if (r
.top
<= info
.rcMonitor
.top
&&
2067 r
.left
<= info
.rcMonitor
.left
&&
2068 r
.right
>= info
.rcMonitor
.right
&&
2069 r
.bottom
>= info
.rcMonitor
.bottom
)
2070 mNonClientOffset
.bottom
-= r
.bottom
- info
.rcMonitor
.bottom
+ 1;
2076 if (aReflowWindow
) {
2077 // Force a reflow of content based on the new client
2086 nsWindow::SetNonClientMargins(nsIntMargin
&margins
)
2088 if (!mIsTopWidgetWindow
||
2089 mBorderStyle
& eBorderStyle_none
||
2091 return NS_ERROR_INVALID_ARG
;
2093 // Request for a reset
2094 if (margins
.top
== -1 && margins
.left
== -1 &&
2095 margins
.right
== -1 && margins
.bottom
== -1) {
2096 mCustomNonClient
= PR_FALSE
;
2097 mNonClientMargins
= margins
;
2098 // Force a reflow of content based on the new client
2104 if (margins
.top
< -1 || margins
.bottom
< -1 ||
2105 margins
.left
< -1 || margins
.right
< -1)
2106 return NS_ERROR_INVALID_ARG
;
2108 mNonClientMargins
= margins
;
2109 mCustomNonClient
= PR_TRUE
;
2110 if (!UpdateNonClientMargins()) {
2111 NS_WARNING("UpdateNonClientMargins failed!");
2119 nsWindow::InvalidateNonClientRegion()
2121 // +-+-----------------------+-+
2122 // | | app non-client chrome | |
2123 // | +-----------------------+ |
2124 // | | app client chrome | | }
2125 // | +-----------------------+ | }
2126 // | | app content | | } area we don't want to invalidate
2127 // | +-----------------------+ | }
2128 // | | app client chrome | | }
2129 // | +-----------------------+ |
2130 // +---------------------------+ <
2131 // ^ ^ windows non-client chrome
2132 // client area = app *
2134 GetWindowRect(mWnd
, &rect
);
2135 MapWindowPoints(NULL
, mWnd
, (LPPOINT
)&rect
, 2);
2136 HRGN winRgn
= CreateRectRgnIndirect(&rect
);
2138 // Subtract app client chrome and app content leaving
2139 // windows non-client chrome and app non-client chrome
2141 GetWindowRect(mWnd
, &rect
);
2142 rect
.top
+= mCaptionHeight
;
2143 rect
.right
-= mHorResizeMargin
;
2144 rect
.bottom
-= mHorResizeMargin
;
2145 rect
.left
+= mVertResizeMargin
;
2146 MapWindowPoints(NULL
, mWnd
, (LPPOINT
)&rect
, 2);
2147 HRGN clientRgn
= CreateRectRgnIndirect(&rect
);
2148 CombineRgn(winRgn
, winRgn
, clientRgn
, RGN_DIFF
);
2149 DeleteObject(clientRgn
);
2151 // triggers ncpaint and paint events for the two areas
2152 RedrawWindow(mWnd
, NULL
, winRgn
, RDW_FRAME
|RDW_INVALIDATE
);
2153 DeleteObject(winRgn
);
2157 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion
)
2161 if (aRegion
== (HRGN
)1) { // undocumented value indicating a full refresh
2162 GetWindowRect(mWnd
, &rect
);
2163 rgn
= CreateRectRgnIndirect(&rect
);
2167 GetClientRect(mWnd
, &rect
);
2168 MapWindowPoints(mWnd
, NULL
, (LPPOINT
)&rect
, 2);
2169 HRGN nonClientRgn
= CreateRectRgnIndirect(&rect
);
2170 CombineRgn(rgn
, rgn
, nonClientRgn
, RGN_DIFF
);
2171 DeleteObject(nonClientRgn
);
2175 /**************************************************************
2177 * SECTION: nsIWidget::SetBackgroundColor
2179 * Sets the window background paint color.
2181 **************************************************************/
2183 NS_METHOD
nsWindow::SetBackgroundColor(const nscolor
&aColor
)
2185 nsBaseWidget::SetBackgroundColor(aColor
);
2188 ::DeleteObject(mBrush
);
2190 mBrush
= ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground
));
2193 ::SetClassLongPtrW(mWnd
, GCLP_HBRBACKGROUND
, (LONG_PTR
)mBrush
);
2199 /**************************************************************
2201 * SECTION: nsIWidget::SetCursor
2203 * SetCursor and related utilities for manging cursor state.
2205 **************************************************************/
2207 // Set this component cursor
2208 NS_METHOD
nsWindow::SetCursor(nsCursor aCursor
)
2210 // Only change cursor if it's changing
2212 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2213 //XXX If we want this optimization we need a better way to do it.
2214 //if (aCursor != mCursor) {
2215 HCURSOR newCursor
= NULL
;
2218 case eCursor_select
:
2219 newCursor
= ::LoadCursor(NULL
, IDC_IBEAM
);
2223 newCursor
= ::LoadCursor(NULL
, IDC_WAIT
);
2226 case eCursor_hyperlink
:
2228 newCursor
= ::LoadCursor(NULL
, IDC_HAND
);
2232 case eCursor_standard
:
2233 newCursor
= ::LoadCursor(NULL
, IDC_ARROW
);
2236 case eCursor_n_resize
:
2237 case eCursor_s_resize
:
2238 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
2241 case eCursor_w_resize
:
2242 case eCursor_e_resize
:
2243 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
2246 case eCursor_nw_resize
:
2247 case eCursor_se_resize
:
2248 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
2251 case eCursor_ne_resize
:
2252 case eCursor_sw_resize
:
2253 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
2256 case eCursor_crosshair
:
2257 newCursor
= ::LoadCursor(NULL
, IDC_CROSS
);
2261 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
2265 newCursor
= ::LoadCursor(NULL
, IDC_HELP
);
2268 case eCursor_copy
: // CSS3
2269 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COPY
));
2273 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ALIAS
));
2277 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_CELL
));
2281 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRAB
));
2284 case eCursor_grabbing
:
2285 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRABBING
));
2288 case eCursor_spinning
:
2289 newCursor
= ::LoadCursor(NULL
, IDC_APPSTARTING
);
2292 case eCursor_context_menu
:
2293 // XXX this CSS3 cursor needs to be implemented
2296 case eCursor_zoom_in
:
2297 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMIN
));
2300 case eCursor_zoom_out
:
2301 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMOUT
));
2304 case eCursor_not_allowed
:
2305 case eCursor_no_drop
:
2306 newCursor
= ::LoadCursor(NULL
, IDC_NO
);
2309 case eCursor_col_resize
:
2310 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COLRESIZE
));
2313 case eCursor_row_resize
:
2314 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ROWRESIZE
));
2317 case eCursor_vertical_text
:
2318 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_VERTICALTEXT
));
2321 case eCursor_all_scroll
:
2322 // XXX not 100% appropriate perhaps
2323 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
2326 case eCursor_nesw_resize
:
2327 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
2330 case eCursor_nwse_resize
:
2331 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
2334 case eCursor_ns_resize
:
2335 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
2338 case eCursor_ew_resize
:
2339 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
2343 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_NONE
));
2347 NS_ERROR("Invalid cursor type");
2351 if (NULL
!= newCursor
) {
2353 HCURSOR oldCursor
= ::SetCursor(newCursor
);
2355 if (sHCursor
== oldCursor
) {
2356 NS_IF_RELEASE(sCursorImgContainer
);
2357 if (sHCursor
!= NULL
)
2358 ::DestroyIcon(sHCursor
);
2366 // Setting the actual cursor
2367 NS_IMETHODIMP
nsWindow::SetCursor(imgIContainer
* aCursor
,
2368 PRUint32 aHotspotX
, PRUint32 aHotspotY
)
2370 if (sCursorImgContainer
== aCursor
&& sHCursor
) {
2371 ::SetCursor(sHCursor
);
2379 rv
= aCursor
->GetWidth(&width
);
2380 NS_ENSURE_SUCCESS(rv
, rv
);
2381 rv
= aCursor
->GetHeight(&height
);
2382 NS_ENSURE_SUCCESS(rv
, rv
);
2384 // Reject cursors greater than 128 pixels in either direction, to prevent
2386 // XXX ideally we should rescale. Also, we could modify the API to
2387 // allow trusted content to set larger cursors.
2388 if (width
> 128 || height
> 128)
2389 return NS_ERROR_NOT_AVAILABLE
;
2392 rv
= nsWindowGfx::CreateIcon(aCursor
, PR_TRUE
, aHotspotX
, aHotspotY
, &cursor
);
2393 NS_ENSURE_SUCCESS(rv
, rv
);
2395 mCursor
= nsCursor(-1);
2396 ::SetCursor(cursor
);
2398 NS_IF_RELEASE(sCursorImgContainer
);
2399 sCursorImgContainer
= aCursor
;
2400 NS_ADDREF(sCursorImgContainer
);
2402 if (sHCursor
!= NULL
)
2403 ::DestroyIcon(sHCursor
);
2409 /**************************************************************
2411 * SECTION: nsIWidget::Get/SetTransparencyMode
2413 * Manage the transparency mode of the top-level window
2414 * containing this widget.
2416 **************************************************************/
2419 nsTransparencyMode
nsWindow::GetTransparencyMode()
2421 return GetTopLevelWindow(PR_TRUE
)->GetWindowTranslucencyInner();
2424 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode
)
2426 GetTopLevelWindow(PR_TRUE
)->SetWindowTranslucencyInner(aMode
);
2429 void nsWindow::UpdatePossiblyTransparentRegion(const nsIntRegion
&aDirtyRegion
,
2430 const nsIntRegion
&aPossiblyTransparentRegion
) {
2431 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2435 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2436 nsWindow
* topWindow
= GetNSWindowPtr(hWnd
);
2441 mPossiblyTransparentRegion
.Sub(mPossiblyTransparentRegion
, aDirtyRegion
);
2442 mPossiblyTransparentRegion
.Or(mPossiblyTransparentRegion
, aPossiblyTransparentRegion
);
2444 nsIntRect clientBounds
;
2445 topWindow
->GetClientBounds(clientBounds
);
2446 nsIntRegion opaqueRegion
;
2447 opaqueRegion
.Sub(clientBounds
, mPossiblyTransparentRegion
);
2449 MARGINS margins
= { 0, 0, 0, 0 };
2450 DWORD_PTR dwStyle
= ::GetWindowLongPtrW(hWnd
, GWL_STYLE
);
2452 // If there is no opaque region or hidechrome=true, set margins
2453 // to support a full sheet of glass.
2454 if (opaqueRegion
.IsEmpty() || mHideChrome
) {
2455 // Comments in MSDN indicate all values must be set to -1
2456 margins
.cxLeftWidth
= margins
.cxRightWidth
=
2457 margins
.cyTopHeight
= margins
.cyBottomHeight
= -1;
2459 // Find the largest rectangle and use that to calculate the inset
2460 nsIntRect largest
= opaqueRegion
.GetLargestRectangle();
2461 margins
.cxLeftWidth
= largest
.x
;
2462 margins
.cxRightWidth
= clientBounds
.width
- largest
.XMost();
2463 margins
.cyBottomHeight
= clientBounds
.height
- largest
.YMost();
2465 // The minimum glass height must be the caption buttons height,
2466 // otherwise the buttons are drawn incorrectly.
2467 margins
.cyTopHeight
= PR_MAX(largest
.y
, mCaptionButtons
.height
);
2470 // Only update glass area if there are changes
2471 if (memcmp(&mGlassMargins
, &margins
, sizeof mGlassMargins
)) {
2472 mGlassMargins
= margins
;
2475 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2478 void nsWindow::UpdateGlass()
2480 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2481 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2482 MARGINS margins
= mGlassMargins
;
2484 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2485 // rendered based on the window style.
2486 // DWMNCRP_ENABLED - The non-client area rendering is
2487 // enabled; the window style is ignored.
2488 DWMNCRENDERINGPOLICY policy
= DWMNCRP_USEWINDOWSTYLE
;
2489 switch (mTransparencyMode
) {
2490 case eTransparencyBorderlessGlass
:
2491 // Only adjust if there is some opaque rectangle
2492 if (margins
.cxLeftWidth
>= 0) {
2493 const PRInt32 kGlassMarginAdjustment
= 2;
2494 margins
.cxLeftWidth
+= kGlassMarginAdjustment
;
2495 margins
.cyTopHeight
+= kGlassMarginAdjustment
;
2496 margins
.cxRightWidth
+= kGlassMarginAdjustment
;
2497 margins
.cyBottomHeight
+= kGlassMarginAdjustment
;
2500 case eTransparencyGlass
:
2501 policy
= DWMNCRP_ENABLED
;
2505 // Extends the window frame behind the client area
2506 if(nsUXThemeData::CheckForCompositor()) {
2507 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd
, &margins
);
2508 nsUXThemeData::dwmSetWindowAttributePtr(hWnd
, DWMWA_NCRENDERING_POLICY
, &policy
, sizeof policy
);
2510 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2514 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2515 void nsWindow::UpdateCaptionButtonsClippingRect()
2517 NS_ASSERTION(mWnd
, "UpdateCaptionButtonsClippingRect called with invalid mWnd.");
2519 RECT captionButtons
;
2520 mCaptionButtonsRoundedRegion
.SetEmpty();
2521 mCaptionButtons
.Empty();
2523 if (!mCustomNonClient
||
2524 mSizeMode
== nsSizeMode_Fullscreen
||
2525 mSizeMode
== nsSizeMode_Minimized
||
2526 !nsUXThemeData::CheckForCompositor() ||
2527 FAILED(nsUXThemeData::dwmGetWindowAttributePtr(mWnd
,
2528 DWMWA_CAPTION_BUTTON_BOUNDS
,
2530 sizeof(captionButtons
)))) {
2534 mCaptionButtons
= nsWindowGfx::ToIntRect(captionButtons
);
2536 // Adjustments to reported area
2537 PRInt32 leftMargin
= (mNonClientMargins
.left
== -1) ? mHorResizeMargin
: mNonClientMargins
.left
;
2539 // "leftMargin - 1" represents the resizer border and an
2540 // one pixel adjustment to hide the semi-transparent highlight.
2541 // The extra width is already excluded when the window is maximized.
2542 mCaptionButtons
.x
-= leftMargin
- 1;
2544 if (mSizeMode
!= nsSizeMode_Maximized
) {
2545 mCaptionButtons
.width
+= leftMargin
- 1;
2546 mCaptionButtons
.height
-= mVertResizeMargin
+ 1;
2548 // Adjustments to the buttons' shift from the edge of the screen,
2549 // plus some apparently transparent drop shadow below them.
2550 mCaptionButtons
.width
-= 2;
2551 mCaptionButtons
.height
-= 3;
2554 // Create a rounded region by shrinking the 2 bottommost pixel rows from
2555 // the rect by 1 and 2 pixels.
2556 // mCaptionButtons: mCaptionButtonsRoundedRegion:
2557 // +-----------+ +-----------+
2560 // +-----------+ +-------+
2561 nsIntRect
round1(mCaptionButtons
.x
, mCaptionButtons
.y
,
2562 mCaptionButtons
.width
, mCaptionButtons
.height
- 2);
2563 nsIntRect
round2(mCaptionButtons
.x
+ 1, mCaptionButtons
.YMost() - 2,
2564 mCaptionButtons
.width
- 2, 1);
2565 nsIntRect
round3(mCaptionButtons
.x
+ 2, mCaptionButtons
.YMost() - 1,
2566 mCaptionButtons
.width
- 4, 1);
2567 mCaptionButtonsRoundedRegion
.Or(mCaptionButtonsRoundedRegion
, round1
);
2568 mCaptionButtonsRoundedRegion
.Or(mCaptionButtonsRoundedRegion
, round2
);
2569 mCaptionButtonsRoundedRegion
.Or(mCaptionButtonsRoundedRegion
, round3
);
2573 /**************************************************************
2575 * SECTION: nsIWidget::HideWindowChrome
2577 * Show or hide window chrome.
2579 **************************************************************/
2581 NS_IMETHODIMP
nsWindow::HideWindowChrome(PRBool aShouldHide
)
2583 HWND hwnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2584 if (!GetNSWindowPtr(hwnd
))
2586 NS_WARNING("Trying to hide window decorations in an embedded context");
2587 return NS_ERROR_FAILURE
;
2590 if (mHideChrome
== aShouldHide
)
2593 DWORD_PTR style
, exStyle
;
2594 mHideChrome
= aShouldHide
;
2596 DWORD_PTR tempStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2597 DWORD_PTR tempExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2599 style
= tempStyle
& ~(WS_CAPTION
| WS_THICKFRAME
);
2600 exStyle
= tempExStyle
& ~(WS_EX_DLGMODALFRAME
| WS_EX_WINDOWEDGE
|
2601 WS_EX_CLIENTEDGE
| WS_EX_STATICEDGE
);
2603 mOldStyle
= tempStyle
;
2604 mOldExStyle
= tempExStyle
;
2607 if (!mOldStyle
|| !mOldExStyle
) {
2608 mOldStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2609 mOldExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2613 exStyle
= mOldExStyle
;
2616 VERIFY_WINDOW_STYLE(style
);
2617 ::SetWindowLongPtrW(hwnd
, GWL_STYLE
, style
);
2618 ::SetWindowLongPtrW(hwnd
, GWL_EXSTYLE
, exStyle
);
2623 /**************************************************************
2625 * SECTION: nsIWidget::Invalidate
2627 * Invalidate an area of the client for painting.
2629 **************************************************************/
2631 // Invalidate this component visible area
2632 NS_METHOD
nsWindow::Invalidate(PRBool aIsSynchronous
)
2636 #ifdef WIDGET_DEBUG_OUTPUT
2637 debug_DumpInvalidate(stdout
,
2641 nsCAutoString("noname"),
2643 #endif // WIDGET_DEBUG_OUTPUT
2645 VERIFY(::InvalidateRect(mWnd
, NULL
, FALSE
));
2647 if (aIsSynchronous
) {
2648 VERIFY(::UpdateWindow(mWnd
));
2654 // Invalidate this component visible area
2655 NS_METHOD
nsWindow::Invalidate(const nsIntRect
& aRect
, PRBool aIsSynchronous
)
2659 #ifdef WIDGET_DEBUG_OUTPUT
2660 debug_DumpInvalidate(stdout
,
2664 nsCAutoString("noname"),
2666 #endif // WIDGET_DEBUG_OUTPUT
2670 rect
.left
= aRect
.x
;
2672 rect
.right
= aRect
.x
+ aRect
.width
;
2673 rect
.bottom
= aRect
.y
+ aRect
.height
;
2675 VERIFY(::InvalidateRect(mWnd
, &rect
, FALSE
));
2677 if (aIsSynchronous
) {
2678 VERIFY(::UpdateWindow(mWnd
));
2685 nsWindow::MakeFullScreen(PRBool aFullScreen
)
2687 #if WINCE_WINDOWS_MOBILE
2690 SetForegroundWindow(mWnd
);
2691 if (nsWindowCE::sMenuBarShown
) {
2693 memset(&sipInfo
, 0, sizeof(SIPINFO
));
2694 sipInfo
.cbSize
= sizeof(SIPINFO
);
2695 if (SipGetInfo(&sipInfo
))
2696 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
),
2697 sipInfo
.rcVisibleDesktop
.bottom
);
2699 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
),
2700 GetSystemMetrics(SM_CYSCREEN
));
2702 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle
, &menuBarRect
) &&
2703 menuBarRect
.top
< rc
.bottom
)
2704 rc
.bottom
= menuBarRect
.top
;
2705 SHFullScreen(mWnd
, SHFS_HIDETASKBAR
| SHFS_HIDESTARTICON
| SHFS_SHOWSIPBUTTON
);
2708 SHFullScreen(mWnd
, SHFS_HIDETASKBAR
| SHFS_HIDESTARTICON
| SHFS_HIDESIPBUTTON
);
2709 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
), GetSystemMetrics(SM_CYSCREEN
));
2713 SHFullScreen(mWnd
, SHFS_SHOWTASKBAR
| SHFS_SHOWSTARTICON
);
2714 SystemParametersInfo(SPI_GETWORKAREA
, 0, &rc
, FALSE
);
2718 mSizeMode
= nsSizeMode_Fullscreen
;
2720 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2721 HideWindowChrome(aFullScreen
);
2722 Resize(rc
.left
, rc
.top
, rc
.right
-rc
.left
, rc
.bottom
-rc
.top
, PR_TRUE
);
2728 mFullscreenMode
= aFullScreen
;
2730 if (mSizeMode
== nsSizeMode_Fullscreen
)
2732 mOldSizeMode
= mSizeMode
;
2733 SetSizeMode(nsSizeMode_Fullscreen
);
2735 SetSizeMode(mOldSizeMode
);
2738 UpdateNonClientMargins();
2740 // Will call hide chrome, reposition window. Note this will
2741 // also cache dimensions for restoration, so it should only
2742 // be called once per fullscreen request.
2743 nsresult rv
= nsBaseWidget::MakeFullScreen(aFullScreen
);
2745 // Let the dom know via web shell window
2746 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
2747 event
.mSizeMode
= mSizeMode
;
2749 DispatchWindowEvent(&event
);
2755 /**************************************************************
2757 * SECTION: nsIWidget::Update
2759 * Force a synchronous repaint of the window.
2761 **************************************************************/
2763 NS_IMETHODIMP
nsWindow::Update()
2765 nsresult rv
= NS_OK
;
2767 // updates can come through for windows no longer holding an mWnd during
2768 // deletes triggered by JavaScript in buttons with mouse feedback
2770 VERIFY(::UpdateWindow(mWnd
));
2775 /**************************************************************
2777 * SECTION: Native data storage
2779 * nsIWidget::GetNativeData
2780 * nsIWidget::FreeNativeData
2782 * Set or clear native data based on a constant.
2784 **************************************************************/
2786 // Return some native data according to aDataType
2787 void* nsWindow::GetNativeData(PRUint32 aDataType
)
2789 switch (aDataType
) {
2790 case NS_NATIVE_TMP_WINDOW
:
2791 return (void*)::CreateWindowExW(WS_EX_NOACTIVATE
|
2792 mIsRTL
? WS_EX_LAYOUTRTL
: 0,
2802 nsToolkit::mDllInstance
,
2804 case NS_NATIVE_PLUGIN_PORT
:
2805 case NS_NATIVE_WIDGET
:
2806 case NS_NATIVE_WINDOW
:
2808 case NS_NATIVE_GRAPHIC
:
2809 // XXX: This is sleezy!! Remember to Release the DC after using it!
2811 return (void*)(eTransparencyTransparent
== mTransparencyMode
) ?
2812 mMemoryDC
: ::GetDC(mWnd
);
2814 return (void*)::GetDC(mWnd
);
2817 #ifdef NS_ENABLE_TSF
2818 case NS_NATIVE_TSF_THREAD_MGR
:
2819 return nsTextStore::GetThreadMgr();
2820 case NS_NATIVE_TSF_CATEGORY_MGR
:
2821 return nsTextStore::GetCategoryMgr();
2822 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR
:
2823 return nsTextStore::GetDisplayAttrMgr();
2824 #endif //NS_ENABLE_TSF
2833 // Free some native data according to aDataType
2834 void nsWindow::FreeNativeData(void * data
, PRUint32 aDataType
)
2838 case NS_NATIVE_GRAPHIC
:
2840 if (eTransparencyTransparent
!= mTransparencyMode
)
2841 ::ReleaseDC(mWnd
, (HDC
)data
);
2843 ::ReleaseDC(mWnd
, (HDC
)data
);
2846 case NS_NATIVE_WIDGET
:
2847 case NS_NATIVE_WINDOW
:
2848 case NS_NATIVE_PLUGIN_PORT
:
2855 /**************************************************************
2857 * SECTION: nsIWidget::SetTitle
2859 * Set the main windows title text.
2861 **************************************************************/
2863 NS_METHOD
nsWindow::SetTitle(const nsAString
& aTitle
)
2865 const nsString
& strTitle
= PromiseFlatString(aTitle
);
2866 ::SendMessageW(mWnd
, WM_SETTEXT
, (WPARAM
)0, (LPARAM
)(LPCWSTR
)strTitle
.get());
2870 /**************************************************************
2872 * SECTION: nsIWidget::SetIcon
2874 * Set the main windows icon.
2876 **************************************************************/
2878 NS_METHOD
nsWindow::SetIcon(const nsAString
& aIconSpec
)
2881 // Assume the given string is a local identifier for an icon file.
2883 nsCOMPtr
<nsILocalFile
> iconFile
;
2884 ResolveIconName(aIconSpec
, NS_LITERAL_STRING(".ico"),
2885 getter_AddRefs(iconFile
));
2887 return NS_OK
; // not an error if icon is not found
2889 nsAutoString iconPath
;
2890 iconFile
->GetPath(iconPath
);
2892 // XXX this should use MZLU (see bug 239279)
2896 HICON bigIcon
= (HICON
)::LoadImageW(NULL
,
2897 (LPCWSTR
)iconPath
.get(),
2899 ::GetSystemMetrics(SM_CXICON
),
2900 ::GetSystemMetrics(SM_CYICON
),
2902 HICON smallIcon
= (HICON
)::LoadImageW(NULL
,
2903 (LPCWSTR
)iconPath
.get(),
2905 ::GetSystemMetrics(SM_CXSMICON
),
2906 ::GetSystemMetrics(SM_CYSMICON
),
2910 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_BIG
, (LPARAM
)bigIcon
);
2912 ::DestroyIcon(icon
);
2914 #ifdef DEBUG_SetIcon
2916 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
2917 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath
.get(), ::GetLastError() );
2921 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_SMALL
, (LPARAM
)smallIcon
);
2923 ::DestroyIcon(icon
);
2925 #ifdef DEBUG_SetIcon
2927 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
2928 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath
.get(), ::GetLastError() );
2935 /**************************************************************
2937 * SECTION: nsIWidget::WidgetToScreenOffset
2939 * Return this widget's origin in screen coordinates.
2941 **************************************************************/
2943 nsIntPoint
nsWindow::WidgetToScreenOffset()
2948 ::ClientToScreen(mWnd
, &point
);
2949 return nsIntPoint(point
.x
, point
.y
);
2952 nsIntSize
nsWindow::ClientToWindowSize(const nsIntSize
& aClientSize
)
2954 if (!IsPopupWithTitleBar())
2957 // just use (200, 200) as the position
2961 r
.right
= 200 + aClientSize
.width
;
2962 r
.bottom
= 200 + aClientSize
.height
;
2963 ::AdjustWindowRectEx(&r
, WindowStyle(), PR_FALSE
, WindowExStyle());
2965 return nsIntSize(r
.right
- r
.left
, r
.bottom
- r
.top
);
2968 /**************************************************************
2970 * SECTION: nsIWidget::EnableDragDrop
2972 * Enables/Disables drag and drop of files on this widget.
2974 **************************************************************/
2976 #if !defined(WINCE) // implemented in nsWindowCE.cpp
2977 NS_METHOD
nsWindow::EnableDragDrop(PRBool aEnable
)
2979 NS_ASSERTION(mWnd
, "nsWindow::EnableDragDrop() called after Destroy()");
2981 nsresult rv
= NS_ERROR_FAILURE
;
2983 if (nsnull
== mNativeDragTarget
) {
2984 mNativeDragTarget
= new nsNativeDragTarget(this);
2985 if (NULL
!= mNativeDragTarget
) {
2986 mNativeDragTarget
->AddRef();
2987 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
,TRUE
,FALSE
)) {
2988 if (S_OK
== ::RegisterDragDrop(mWnd
, (LPDROPTARGET
)mNativeDragTarget
)) {
2995 if (nsnull
!= mWnd
&& NULL
!= mNativeDragTarget
) {
2996 ::RevokeDragDrop(mWnd
);
2997 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
, FALSE
, TRUE
)) {
3000 mNativeDragTarget
->DragCancel();
3001 NS_RELEASE(mNativeDragTarget
);
3008 /**************************************************************
3010 * SECTION: nsIWidget::CaptureMouse
3012 * Enables/Disables system mouse capture.
3014 **************************************************************/
3016 NS_METHOD
nsWindow::CaptureMouse(PRBool aCapture
)
3018 if (!nsToolkit::gMouseTrailer
) {
3019 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3024 nsToolkit::gMouseTrailer
->SetCaptureWindow(mWnd
);
3027 nsToolkit::gMouseTrailer
->SetCaptureWindow(NULL
);
3030 mIsInMouseCapture
= aCapture
;
3034 /**************************************************************
3036 * SECTION: nsIWidget::CaptureRollupEvents
3038 * Dealing with event rollup on destroy for popups. Enables &
3039 * Disables system capture of any and all events that would
3040 * cause a dropdown to be rolled up.
3042 **************************************************************/
3044 NS_IMETHODIMP
nsWindow::CaptureRollupEvents(nsIRollupListener
* aListener
,
3045 nsIMenuRollup
* aMenuRollup
,
3047 PRBool aConsumeRollupEvent
)
3050 /* we haven't bothered carrying a weak reference to sRollupWidget because
3051 we believe lifespan is properly scoped. this next assertion helps
3052 assure that remains true. */
3053 NS_ASSERTION(!sRollupWidget
, "rollup widget reassigned before release");
3054 sRollupConsumeEvent
= aConsumeRollupEvent
;
3055 NS_IF_RELEASE(sRollupWidget
);
3056 NS_IF_RELEASE(sMenuRollup
);
3057 sRollupListener
= aListener
;
3058 sMenuRollup
= aMenuRollup
;
3059 NS_IF_ADDREF(aMenuRollup
);
3060 sRollupWidget
= this;
3064 if (!sMsgFilterHook
&& !sCallProcHook
&& !sCallMouseHook
) {
3065 RegisterSpecialDropdownHooks();
3067 sProcessHook
= PR_TRUE
;
3071 sRollupListener
= nsnull
;
3072 NS_IF_RELEASE(sMenuRollup
);
3073 NS_IF_RELEASE(sRollupWidget
);
3076 sProcessHook
= PR_FALSE
;
3077 UnregisterSpecialDropdownHooks();
3084 /**************************************************************
3086 * SECTION: nsIWidget::GetAttention
3088 * Bring this window to the user's attention.
3090 **************************************************************/
3092 // Draw user's attention to this window until it comes to foreground.
3094 nsWindow::GetAttention(PRInt32 aCycleCount
)
3099 return NS_ERROR_NOT_INITIALIZED
;
3101 // Don't flash if the flash count is 0 or if the
3102 // top level window is already active.
3103 HWND fgWnd
= ::GetForegroundWindow();
3104 if (aCycleCount
== 0 || fgWnd
== GetTopLevelHWND(mWnd
))
3107 HWND flashWnd
= mWnd
;
3108 while (HWND ownerWnd
= ::GetWindow(flashWnd
, GW_OWNER
)) {
3109 flashWnd
= ownerWnd
;
3112 // Don't flash if the owner window is active either.
3113 if (fgWnd
== flashWnd
)
3116 DWORD defaultCycleCount
= 0;
3117 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT
, 0, &defaultCycleCount
, 0);
3119 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
3120 FLASHW_ALL
, aCycleCount
> 0 ? aCycleCount
: defaultCycleCount
, 0 };
3121 ::FlashWindowEx(&flashInfo
);
3126 void nsWindow::StopFlashing()
3129 HWND flashWnd
= mWnd
;
3130 while (HWND ownerWnd
= ::GetWindow(flashWnd
, GW_OWNER
)) {
3131 flashWnd
= ownerWnd
;
3134 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
3135 FLASHW_STOP
, 0, 0 };
3136 ::FlashWindowEx(&flashInfo
);
3140 /**************************************************************
3142 * SECTION: nsIWidget::HasPendingInputEvent
3144 * Ask whether there user input events pending. All input events are
3145 * included, including those not targeted at this nsIwidget instance.
3147 **************************************************************/
3150 nsWindow::HasPendingInputEvent()
3152 // If there is pending input or the user is currently
3153 // moving the window then return true.
3154 // Note: When the user is moving the window WIN32 spins
3155 // a separate event loop and input events are not
3156 // reported to the application.
3157 if (HIWORD(GetQueueStatus(QS_INPUT
)))
3162 GUITHREADINFO guiInfo
;
3163 guiInfo
.cbSize
= sizeof(GUITHREADINFO
);
3164 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo
))
3166 return GUI_INMOVESIZE
== (guiInfo
.flags
& GUI_INMOVESIZE
);
3170 /**************************************************************
3172 * SECTION: nsIWidget::GetLayerManager
3174 * Get the layer manager associated with this widget.
3176 **************************************************************/
3178 mozilla::layers::LayerManager
*
3179 nsWindow::GetLayerManager()
3182 if (!mLayerManager
) {
3183 nsCOMPtr
<nsIPrefBranch2
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
3185 PRBool accelerateByDefault
= PR_TRUE
;
3186 PRBool disableAcceleration
= PR_FALSE
;
3187 PRBool preferOpenGL
= PR_FALSE
;
3189 prefs
->GetBoolPref("layers.accelerate-all",
3190 &accelerateByDefault
);
3191 prefs
->GetBoolPref("layers.accelerate-none",
3192 &disableAcceleration
);
3193 prefs
->GetBoolPref("layers.prefer-opengl",
3197 const char *acceleratedEnv
= PR_GetEnv("MOZ_ACCELERATED");
3198 accelerateByDefault
= accelerateByDefault
||
3199 (acceleratedEnv
&& (*acceleratedEnv
!= '0'));
3201 /* We don't currently support using an accelerated layer manager with
3202 * transparent windows so don't even try. I'm also not sure if we even
3203 * want to support this case. See bug #593471 */
3204 disableAcceleration
= disableAcceleration
||
3205 eTransparencyTransparent
== mTransparencyMode
;
3207 nsCOMPtr
<nsIXULRuntime
> xr
= do_GetService("@mozilla.org/xre/runtime;1");
3208 PRBool safeMode
= PR_FALSE
;
3210 xr
->GetInSafeMode(&safeMode
);
3212 if (disableAcceleration
|| safeMode
)
3213 mUseAcceleratedRendering
= PR_FALSE
;
3214 else if (accelerateByDefault
)
3215 mUseAcceleratedRendering
= PR_TRUE
;
3217 if (mUseAcceleratedRendering
) {
3218 #ifdef MOZ_ENABLE_D3D9_LAYER
3219 if (!preferOpenGL
) {
3220 nsRefPtr
<mozilla::layers::LayerManagerD3D9
> layerManager
=
3221 new mozilla::layers::LayerManagerD3D9(this);
3222 if (layerManager
->Initialize()) {
3223 mLayerManager
= layerManager
;
3227 if (!mLayerManager
&& preferOpenGL
) {
3228 nsRefPtr
<mozilla::layers::LayerManagerOGL
> layerManager
=
3229 new mozilla::layers::LayerManagerOGL(this);
3230 if (layerManager
->Initialize()) {
3231 mLayerManager
= layerManager
;
3236 // Fall back to software if we couldn't use any hardware backends.
3238 mLayerManager
= new BasicLayerManager(this);
3242 return mLayerManager
;
3245 /**************************************************************
3247 * SECTION: nsIWidget::GetThebesSurface
3249 * Get the Thebes surface associated with this widget.
3251 **************************************************************/
3253 gfxASurface
*nsWindow::GetThebesSurface()
3255 #ifdef CAIRO_HAS_D2D_SURFACE
3256 if (mD2DWindowSurface
) {
3257 return mD2DWindowSurface
;
3261 return (new gfxWindowsSurface(mPaintDC
));
3263 #ifdef CAIRO_HAS_D2D_SURFACE
3264 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3265 gfxWindowsPlatform::RENDER_DIRECT2D
) {
3266 gfxASurface::gfxContentType content
= gfxASurface::CONTENT_COLOR
;
3267 #if defined(MOZ_XUL)
3268 if (mTransparencyMode
!= eTransparencyOpaque
) {
3269 content
= gfxASurface::CONTENT_COLOR_ALPHA
;
3272 return (new gfxD2DSurface(mWnd
, content
));
3275 PRUint32 flags
= gfxWindowsSurface::FLAG_TAKE_DC
;
3276 if (mTransparencyMode
!= eTransparencyOpaque
) {
3277 flags
|= gfxWindowsSurface::FLAG_IS_TRANSPARENT
;
3279 return (new gfxWindowsSurface(mWnd
, flags
));
3280 #ifdef CAIRO_HAS_D2D_SURFACE
3285 /**************************************************************
3287 * SECTION: nsIWidget::OnDefaultButtonLoaded
3289 * Called after the dialog is loaded and it has a default button.
3291 **************************************************************/
3294 nsWindow::OnDefaultButtonLoaded(const nsIntRect
&aButtonRect
)
3297 return NS_ERROR_NOT_IMPLEMENTED
;
3299 if (aButtonRect
.IsEmpty())
3302 // Don't snap when we are not active.
3303 HWND activeWnd
= ::GetActiveWindow();
3304 if (activeWnd
!= ::GetForegroundWindow() ||
3305 GetTopLevelHWND(mWnd
, PR_TRUE
) != GetTopLevelHWND(activeWnd
, PR_TRUE
)) {
3309 PRBool isAlwaysSnapCursor
= PR_FALSE
;
3310 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
3312 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
3313 prefs
->GetBranch(nsnull
, getter_AddRefs(prefBranch
));
3315 prefBranch
->GetBoolPref("ui.cursor_snapping.always_enabled",
3316 &isAlwaysSnapCursor
);
3320 if (!isAlwaysSnapCursor
) {
3321 BOOL snapDefaultButton
;
3322 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON
, 0,
3323 &snapDefaultButton
, 0) || !snapDefaultButton
)
3327 nsIntRect widgetRect
;
3328 nsresult rv
= GetScreenBounds(widgetRect
);
3329 NS_ENSURE_SUCCESS(rv
, rv
);
3330 nsIntRect
buttonRect(aButtonRect
+ widgetRect
.TopLeft());
3332 nsIntPoint
centerOfButton(buttonRect
.x
+ buttonRect
.width
/ 2,
3333 buttonRect
.y
+ buttonRect
.height
/ 2);
3334 // The center of the button can be outside of the widget.
3335 // E.g., it could be hidden by scrolling.
3336 if (!widgetRect
.Contains(centerOfButton
)) {
3340 if (!::SetCursorPos(centerOfButton
.x
, centerOfButton
.y
)) {
3341 NS_ERROR("SetCursorPos failed");
3342 return NS_ERROR_FAILURE
;
3349 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta
,
3350 PRBool aIsHorizontal
,
3351 PRInt32
&aOverriddenDelta
)
3353 // The default vertical and horizontal scrolling speed is 3, this is defined
3354 // on the document of SystemParametersInfo in MSDN.
3355 const PRUint32 kSystemDefaultScrollingSpeed
= 3;
3357 PRInt32 absOriginDelta
= PR_ABS(aOriginalDelta
);
3359 // Compute the simple overridden speed.
3360 PRInt32 absComputedOverriddenDelta
;
3362 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta
, aIsHorizontal
,
3363 absComputedOverriddenDelta
);
3364 NS_ENSURE_SUCCESS(rv
, rv
);
3366 aOverriddenDelta
= aOriginalDelta
;
3368 if (absComputedOverriddenDelta
== absOriginDelta
) {
3369 // We don't override now.
3373 // Otherwise, we should check whether the user customized the system settings
3374 // or not. If the user did it, we should respect the will.
3376 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &systemSpeed
, 0)) {
3377 return NS_ERROR_FAILURE
;
3379 // The default vertical scrolling speed is 3, this is defined on the document
3380 // of SystemParametersInfo in MSDN.
3381 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
3385 // Only Vista and later, Windows has the system setting of horizontal
3386 // scrolling by the mouse wheel.
3387 if (GetWindowsVersion() >= VISTA_VERSION
) {
3388 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS
, 0, &systemSpeed
, 0)) {
3389 return NS_ERROR_FAILURE
;
3391 // The default horizontal scrolling speed is 3, this is defined on the
3392 // document of SystemParametersInfo in MSDN.
3393 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
3398 // Limit the overridden delta value from the system settings. The mouse
3399 // driver might accelerate the scrolling speed already. If so, we shouldn't
3400 // override the scrolling speed for preventing the unexpected high speed
3402 PRInt32 absDeltaLimit
;
3404 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed
,
3405 aIsHorizontal
, absDeltaLimit
);
3406 NS_ENSURE_SUCCESS(rv
, rv
);
3408 // If the given delta is larger than our computed limitation value, the delta
3409 // was accelerated by the mouse driver. So, we should do nothing here.
3410 if (absDeltaLimit
<= absOriginDelta
) {
3414 absComputedOverriddenDelta
=
3415 PR_MIN(absComputedOverriddenDelta
, absDeltaLimit
);
3417 aOverriddenDelta
= (aOriginalDelta
> 0) ? absComputedOverriddenDelta
:
3418 -absComputedOverriddenDelta
;
3422 /**************************************************************
3423 **************************************************************
3425 ** BLOCK: Moz Events
3427 ** Moz GUI event management.
3429 **************************************************************
3430 **************************************************************/
3432 /**************************************************************
3434 * SECTION: Mozilla event initialization
3436 * Helpers for initializing moz events.
3438 **************************************************************/
3440 // Event intialization
3441 MSG
nsWindow::InitMSG(UINT aMessage
, WPARAM wParam
, LPARAM lParam
)
3444 msg
.message
= aMessage
;
3445 msg
.wParam
= wParam
;
3446 msg
.lParam
= lParam
;
3450 void nsWindow::InitEvent(nsGUIEvent
& event
, nsIntPoint
* aPoint
)
3452 if (nsnull
== aPoint
) { // use the point from the event
3453 // get the message position in client coordinates
3456 DWORD pos
= ::GetMessagePos();
3459 cpos
.x
= GET_X_LPARAM(pos
);
3460 cpos
.y
= GET_Y_LPARAM(pos
);
3462 ::ScreenToClient(mWnd
, &cpos
);
3463 event
.refPoint
.x
= cpos
.x
;
3464 event
.refPoint
.y
= cpos
.y
;
3466 event
.refPoint
.x
= 0;
3467 event
.refPoint
.y
= 0;
3471 // use the point override if provided
3472 event
.refPoint
.x
= aPoint
->x
;
3473 event
.refPoint
.y
= aPoint
->y
;
3477 event
.time
= ::GetMessageTime();
3479 event
.time
= PR_Now() / 1000;
3482 mLastPoint
= event
.refPoint
;
3485 /**************************************************************
3487 * SECTION: Moz event dispatch helpers
3489 * Helpers for dispatching different types of moz events.
3491 **************************************************************/
3493 // Main event dispatch. Invokes callback and ProcessEvent method on
3494 // Event Listener object. Part of nsIWidget.
3495 NS_IMETHODIMP
nsWindow::DispatchEvent(nsGUIEvent
* event
, nsEventStatus
& aStatus
)
3497 #ifdef WIDGET_DEBUG_OUTPUT
3498 debug_DumpEvent(stdout
,
3501 nsCAutoString("something"),
3503 #endif // WIDGET_DEBUG_OUTPUT
3505 aStatus
= nsEventStatus_eIgnore
;
3507 // skip processing of suppressed blur events
3508 if (event
->message
== NS_DEACTIVATE
&& BlurEventsSuppressed())
3511 // Top level windows can have a view attached which requires events be sent
3512 // to the underlying base window and the view. Added when we combined the
3513 // base chrome window with the main content child for nc client area (title
3515 if (mViewCallback
) {
3516 // A subset of events are sent to the base xul window first
3517 switch(event
->message
) {
3518 // send to the base window (view mgr ignores these for the view)
3519 case NS_UISTATECHANGED
:
3524 (*mEventCallback
)(event
); // web shell / xul window
3527 // sent to the base window, then to the view
3532 (*mEventCallback
)(event
); // web shell / xul window
3535 // attached view events
3536 aStatus
= (*mViewCallback
)(event
);
3538 else if (mEventCallback
) {
3539 aStatus
= (*mEventCallback
)(event
);
3542 // the window can be destroyed during processing of seemingly innocuous events like, say,
3543 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3544 // which causes problems with the deleted window. therefore:
3545 if (mOnDestroyCalled
)
3546 aStatus
= nsEventStatus_eConsumeNoDefault
;
3550 PRBool
nsWindow::DispatchStandardEvent(PRUint32 aMsg
)
3552 nsGUIEvent
event(PR_TRUE
, aMsg
, this);
3555 PRBool result
= DispatchWindowEvent(&event
);
3559 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
* event
)
3561 nsEventStatus status
;
3562 DispatchEvent(event
, status
);
3563 return ConvertStatus(status
);
3566 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
* event
, nsEventStatus
&aStatus
) {
3567 DispatchEvent(event
, aStatus
);
3568 return ConvertStatus(aStatus
);
3571 PRBool
nsWindow::DispatchKeyEvent(PRUint32 aEventType
, WORD aCharCode
,
3572 const nsTArray
<nsAlternativeCharCode
>* aAlternativeCharCodes
,
3573 UINT aVirtualCharCode
, const MSG
*aMsg
,
3574 const nsModifierKeyState
&aModKeyState
,
3579 nsKeyEvent
event(PR_TRUE
, aEventType
, this);
3580 nsIntPoint
point(0, 0);
3582 InitEvent(event
, &point
); // this add ref's event.widget
3584 event
.flags
|= aFlags
;
3585 event
.charCode
= aCharCode
;
3586 if (aAlternativeCharCodes
)
3587 event
.alternativeCharCodes
.AppendElements(*aAlternativeCharCodes
);
3588 event
.keyCode
= aVirtualCharCode
;
3592 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt
++,
3593 (NS_KEY_PRESS
== aEventType
) ? "PRESS" : (aEventType
== NS_KEY_UP
? "Up" : "Down"),
3594 event
.charCode
, event
.keyCode
);
3595 printf("Shift: %s Control %s Alt: %s \n",
3596 (mIsShiftDown
? "D" : "U"), (mIsControlDown
? "D" : "U"), (mIsAltDown
? "D" : "U"));
3597 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3598 IS_VK_DOWN(NS_VK_SHIFT
) ? 'S' : ' ',
3599 IS_VK_DOWN(NS_VK_CONTROL
) ? 'C' : ' ',
3600 IS_VK_DOWN(NS_VK_ALT
) ? 'A' : ' ',
3601 IS_VK_DOWN(VK_LSHIFT
) ? 'S' : ' ',
3602 IS_VK_DOWN(VK_LCONTROL
) ? 'C' : ' ',
3603 IS_VK_DOWN(VK_LMENU
) ? 'A' : ' ',
3604 IS_VK_DOWN(VK_RMENU
) ? 'A' : ' ',
3605 IS_VK_DOWN(VK_RCONTROL
) ? 'C' : ' ',
3606 IS_VK_DOWN(VK_RSHIFT
) ? 'S' : ' ');
3609 event
.isShift
= aModKeyState
.mIsShiftDown
;
3610 event
.isControl
= aModKeyState
.mIsControlDown
;
3611 event
.isMeta
= PR_FALSE
;
3612 event
.isAlt
= aModKeyState
.mIsAltDown
;
3614 NPEvent pluginEvent
;
3615 if (aMsg
&& PluginHasFocus()) {
3616 pluginEvent
.event
= aMsg
->message
;
3617 pluginEvent
.wParam
= aMsg
->wParam
;
3618 pluginEvent
.lParam
= aMsg
->lParam
;
3619 event
.pluginEvent
= (void *)&pluginEvent
;
3622 PRBool result
= DispatchWindowEvent(&event
);
3627 PRBool
nsWindow::DispatchCommandEvent(PRUint32 aEventCommand
)
3629 nsCOMPtr
<nsIAtom
> command
;
3630 switch (aEventCommand
) {
3631 case APPCOMMAND_BROWSER_BACKWARD
:
3632 command
= nsWidgetAtoms::Back
;
3634 case APPCOMMAND_BROWSER_FORWARD
:
3635 command
= nsWidgetAtoms::Forward
;
3637 case APPCOMMAND_BROWSER_REFRESH
:
3638 command
= nsWidgetAtoms::Reload
;
3640 case APPCOMMAND_BROWSER_STOP
:
3641 command
= nsWidgetAtoms::Stop
;
3643 case APPCOMMAND_BROWSER_SEARCH
:
3644 command
= nsWidgetAtoms::Search
;
3646 case APPCOMMAND_BROWSER_FAVORITES
:
3647 command
= nsWidgetAtoms::Bookmarks
;
3649 case APPCOMMAND_BROWSER_HOME
:
3650 command
= nsWidgetAtoms::Home
;
3655 nsCommandEvent
event(PR_TRUE
, nsWidgetAtoms::onAppCommand
, command
, this);
3658 DispatchWindowEvent(&event
);
3663 // Recursively dispatch synchronous paints for nsIWidget
3664 // descendants with invalidated rectangles.
3665 BOOL CALLBACK
nsWindow::DispatchStarvedPaints(HWND aWnd
, LPARAM aMsg
)
3667 LONG_PTR proc
= ::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
3668 if (proc
== (LONG_PTR
)&nsWindow::WindowProc
) {
3669 // its one of our windows so check to see if it has a
3670 // invalidated rect. If it does. Dispatch a synchronous
3672 if (GetUpdateRect(aWnd
, NULL
, FALSE
))
3673 VERIFY(::UpdateWindow(aWnd
));
3678 // Check for pending paints and dispatch any pending paint
3679 // messages for any nsIWidget which is a descendant of the
3680 // top-level window that *this* window is embedded within.
3682 // Note: We do not dispatch pending paint messages for non
3683 // nsIWidget managed windows.
3684 void nsWindow::DispatchPendingEvents()
3687 NS_WARNING("We were asked to dispatch pending events during painting, "
3688 "denying since that's unsafe.");
3692 // We need to ensure that reflow events do not get starved.
3693 // At the same time, we don't want to recurse through here
3694 // as that would prevent us from dispatching starved paints.
3695 static int recursionBlocker
= 0;
3696 if (recursionBlocker
++ == 0) {
3697 NS_ProcessPendingEvents(nsnull
, PR_MillisecondsToInterval(100));
3701 // Quickly check to see if there are any
3702 // paint events pending.
3703 if (::GetQueueStatus(QS_PAINT
)) {
3704 // Find the top level window.
3705 HWND topWnd
= GetTopLevelHWND(mWnd
);
3707 // Dispatch pending paints for all topWnd's descendant windows.
3708 // Note: EnumChildWindows enumerates all descendant windows not just
3711 ::EnumChildWindows(topWnd
, nsWindow::DispatchStarvedPaints
, 0);
3713 nsWindowCE::EnumChildWindows(topWnd
, nsWindow::DispatchStarvedPaints
, NULL
);
3718 // Deal with plugin events
3719 PRBool
nsWindow::DispatchPluginEvent(const MSG
&aMsg
)
3721 if (!PluginHasFocus())
3724 nsGUIEvent
event(PR_TRUE
, NS_PLUGIN_EVENT
, this);
3725 nsIntPoint
point(0, 0);
3726 InitEvent(event
, &point
);
3727 NPEvent pluginEvent
;
3728 pluginEvent
.event
= aMsg
.message
;
3729 pluginEvent
.wParam
= aMsg
.wParam
;
3730 pluginEvent
.lParam
= aMsg
.lParam
;
3731 event
.pluginEvent
= (void *)&pluginEvent
;
3732 return DispatchWindowEvent(&event
);
3735 PRBool
nsWindow::DispatchPluginEvent(UINT aMessage
,
3738 PRBool aDispatchPendingEvents
)
3740 PRBool ret
= DispatchPluginEvent(InitMSG(aMessage
, aWParam
, aLParam
));
3741 if (aDispatchPendingEvents
) {
3742 DispatchPendingEvents();
3747 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg
,
3751 ::GetMessageW(&msg
, mWnd
, aFirstMsg
, aLastMsg
);
3752 DispatchPluginEvent(msg
);
3755 // Deal with all sort of mouse event
3756 PRBool
nsWindow::DispatchMouseEvent(PRUint32 aEventType
, WPARAM wParam
,
3757 LPARAM lParam
, PRBool aIsContextMenuKey
,
3758 PRInt16 aButton
, PRUint16 aInputSource
)
3760 PRBool result
= PR_FALSE
;
3764 if (!mEventCallback
) {
3768 switch (aEventType
) {
3769 case NS_MOUSE_BUTTON_DOWN
:
3770 CaptureMouse(PR_TRUE
);
3773 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3774 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3775 case NS_MOUSE_BUTTON_UP
:
3778 if (!(wParam
& (MK_LBUTTON
| MK_MBUTTON
| MK_RBUTTON
)) && mIsInMouseCapture
)
3779 CaptureMouse(PR_FALSE
);
3787 nsIntPoint eventPoint
;
3788 eventPoint
.x
= GET_X_LPARAM(lParam
);
3789 eventPoint
.y
= GET_Y_LPARAM(lParam
);
3791 nsMouseEvent
event(PR_TRUE
, aEventType
, this, nsMouseEvent::eReal
,
3793 ? nsMouseEvent::eContextMenuKey
3794 : nsMouseEvent::eNormal
);
3795 if (aEventType
== NS_CONTEXTMENU
&& aIsContextMenuKey
) {
3796 nsIntPoint
zero(0, 0);
3797 InitEvent(event
, &zero
);
3799 InitEvent(event
, &eventPoint
);
3802 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
3803 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
3804 event
.isMeta
= PR_FALSE
;
3805 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
3806 event
.button
= aButton
;
3807 event
.inputSource
= aInputSource
;
3809 nsIntPoint mpScreen
= eventPoint
+ WidgetToScreenOffset();
3811 // Suppress mouse moves caused by widget creation
3812 if (aEventType
== NS_MOUSE_MOVE
)
3814 if ((sLastMouseMovePoint
.x
== mpScreen
.x
) && (sLastMouseMovePoint
.y
== mpScreen
.y
))
3816 sLastMouseMovePoint
.x
= mpScreen
.x
;
3817 sLastMouseMovePoint
.y
= mpScreen
.y
;
3820 PRBool insideMovementThreshold
= (abs(sLastMousePoint
.x
- eventPoint
.x
) < (short)::GetSystemMetrics(SM_CXDOUBLECLK
)) &&
3821 (abs(sLastMousePoint
.y
- eventPoint
.y
) < (short)::GetSystemMetrics(SM_CYDOUBLECLK
));
3825 case nsMouseEvent::eLeftButton
:
3826 eventButton
= VK_LBUTTON
;
3828 case nsMouseEvent::eMiddleButton
:
3829 eventButton
= VK_MBUTTON
;
3831 case nsMouseEvent::eRightButton
:
3832 eventButton
= VK_RBUTTON
;
3839 // Doubleclicks are used to set the click count, then changed to mousedowns
3840 // We're going to time double-clicks from mouse *up* to next mouse *down*
3842 LONG curMsgTime
= ::GetMessageTime();
3844 LONG curMsgTime
= PR_Now() / 1000;
3847 if (aEventType
== NS_MOUSE_DOUBLECLICK
) {
3848 event
.message
= NS_MOUSE_BUTTON_DOWN
;
3849 event
.button
= aButton
;
3850 sLastClickCount
= 2;
3852 else if (aEventType
== NS_MOUSE_BUTTON_UP
) {
3853 // remember when this happened for the next mouse down
3854 sLastMousePoint
.x
= eventPoint
.x
;
3855 sLastMousePoint
.y
= eventPoint
.y
;
3856 sLastMouseButton
= eventButton
;
3858 else if (aEventType
== NS_MOUSE_BUTTON_DOWN
) {
3859 // now look to see if we want to convert this to a double- or triple-click
3860 if (((curMsgTime
- sLastMouseDownTime
) < (LONG
)::GetDoubleClickTime()) && insideMovementThreshold
&&
3861 eventButton
== sLastMouseButton
) {
3864 // reset the click count, to count *this* click
3865 sLastClickCount
= 1;
3867 // Set last Click time on MouseDown only
3868 sLastMouseDownTime
= curMsgTime
;
3870 else if (aEventType
== NS_MOUSE_MOVE
&& !insideMovementThreshold
) {
3871 sLastClickCount
= 0;
3873 else if (aEventType
== NS_MOUSE_EXIT
) {
3874 event
.exit
= IsTopLevelMouseExit(mWnd
) ? nsMouseEvent::eTopLevel
: nsMouseEvent::eChild
;
3876 else if (aEventType
== NS_MOUSE_MOZHITTEST
)
3878 event
.flags
|= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH
;
3880 event
.clickCount
= sLastClickCount
;
3883 printf("Msg Time: %d Click Count: %d\n", curMsgTime
, event
.clickCount
);
3886 NPEvent pluginEvent
;
3890 case NS_MOUSE_BUTTON_DOWN
:
3892 case nsMouseEvent::eLeftButton
:
3893 pluginEvent
.event
= WM_LBUTTONDOWN
;
3895 case nsMouseEvent::eMiddleButton
:
3896 pluginEvent
.event
= WM_MBUTTONDOWN
;
3898 case nsMouseEvent::eRightButton
:
3899 pluginEvent
.event
= WM_RBUTTONDOWN
;
3905 case NS_MOUSE_BUTTON_UP
:
3907 case nsMouseEvent::eLeftButton
:
3908 pluginEvent
.event
= WM_LBUTTONUP
;
3910 case nsMouseEvent::eMiddleButton
:
3911 pluginEvent
.event
= WM_MBUTTONUP
;
3913 case nsMouseEvent::eRightButton
:
3914 pluginEvent
.event
= WM_RBUTTONUP
;
3920 case NS_MOUSE_DOUBLECLICK
:
3922 case nsMouseEvent::eLeftButton
:
3923 pluginEvent
.event
= WM_LBUTTONDBLCLK
;
3925 case nsMouseEvent::eMiddleButton
:
3926 pluginEvent
.event
= WM_MBUTTONDBLCLK
;
3928 case nsMouseEvent::eRightButton
:
3929 pluginEvent
.event
= WM_RBUTTONDBLCLK
;
3936 pluginEvent
.event
= WM_MOUSEMOVE
;
3939 pluginEvent
.event
= WM_MOUSELEAVE
;
3942 pluginEvent
.event
= WM_NULL
;
3946 pluginEvent
.wParam
= wParam
; // plugins NEED raw OS event flags!
3947 pluginEvent
.lParam
= lParam
;
3949 event
.pluginEvent
= (void *)&pluginEvent
;
3951 // call the event callback
3952 if (nsnull
!= mEventCallback
) {
3953 if (nsToolkit::gMouseTrailer
)
3954 nsToolkit::gMouseTrailer
->Disable();
3955 if (aEventType
== NS_MOUSE_MOVE
) {
3956 if (nsToolkit::gMouseTrailer
&& !mIsInMouseCapture
) {
3957 nsToolkit::gMouseTrailer
->SetMouseTrailerWindow(mWnd
);
3964 if (rect
.Contains(event
.refPoint
)) {
3965 if (sCurrentWindow
== NULL
|| sCurrentWindow
!= this) {
3966 if ((nsnull
!= sCurrentWindow
) && (!sCurrentWindow
->mInDtor
)) {
3967 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
3968 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_EXIT
, wParam
, pos
, PR_FALSE
,
3969 nsMouseEvent::eLeftButton
, aInputSource
);
3971 sCurrentWindow
= this;
3973 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
3974 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_ENTER
, wParam
, pos
, PR_FALSE
,
3975 nsMouseEvent::eLeftButton
, aInputSource
);
3979 } else if (aEventType
== NS_MOUSE_EXIT
) {
3980 if (sCurrentWindow
== this) {
3981 sCurrentWindow
= nsnull
;
3985 result
= DispatchWindowEvent(&event
);
3987 if (nsToolkit::gMouseTrailer
)
3988 nsToolkit::gMouseTrailer
->Enable();
3990 // Release the widget with NS_IF_RELEASE() just in case
3991 // the context menu key code in nsEventListenerManager::HandleEvent()
3992 // released it already.
3999 // Deal with accessibile event
4000 #ifdef ACCESSIBILITY
4002 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType
)
4004 if (nsnull
== mEventCallback
) {
4008 nsAccessibleEvent
event(PR_TRUE
, aEventType
, this);
4009 InitEvent(event
, nsnull
);
4011 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
4012 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
4013 event
.isMeta
= PR_FALSE
;
4014 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
4016 DispatchWindowEvent(&event
);
4018 return event
.mAccessible
;
4022 PRBool
nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType
)
4024 if (aEventType
== NS_ACTIVATE
)
4025 sJustGotActivate
= PR_FALSE
;
4026 sJustGotDeactivate
= PR_FALSE
;
4028 // retrive the toplevel window or dialog
4030 HWND toplevelWnd
= NULL
;
4032 toplevelWnd
= curWnd
;
4034 nsWindow
*win
= GetNSWindowPtr(curWnd
);
4036 nsWindowType wintype
;
4037 win
->GetWindowType(wintype
);
4038 if (wintype
== eWindowType_toplevel
|| wintype
== eWindowType_dialog
)
4042 curWnd
= ::GetParent(curWnd
); // Parent or owner (if has no parent)
4046 nsWindow
*win
= GetNSWindowPtr(toplevelWnd
);
4048 return win
->DispatchFocus(aEventType
);
4054 // Deal with focus messages
4055 PRBool
nsWindow::DispatchFocus(PRUint32 aEventType
)
4057 // call the event callback
4058 if (mEventCallback
) {
4059 nsGUIEvent
event(PR_TRUE
, aEventType
, this);
4062 //focus and blur event should go to their base widget loc, not current mouse pos
4063 event
.refPoint
.x
= 0;
4064 event
.refPoint
.y
= 0;
4066 NPEvent pluginEvent
;
4071 pluginEvent
.event
= WM_SETFOCUS
;
4074 pluginEvent
.event
= WM_KILLFOCUS
;
4076 case NS_PLUGIN_ACTIVATE
:
4077 pluginEvent
.event
= WM_KILLFOCUS
;
4083 event
.pluginEvent
= (void *)&pluginEvent
;
4085 return DispatchWindowEvent(&event
);
4090 PRBool
nsWindow::IsTopLevelMouseExit(HWND aWnd
)
4092 DWORD pos
= ::GetMessagePos();
4094 mp
.x
= GET_X_LPARAM(pos
);
4095 mp
.y
= GET_Y_LPARAM(pos
);
4096 HWND mouseWnd
= ::WindowFromPoint(mp
);
4098 // GetTopLevelHWND will return a HWND for the window frame (which includes
4099 // the non-client area). If the mouse has moved into the non-client area,
4100 // we should treat it as a top-level exit.
4101 HWND mouseTopLevel
= nsWindow::GetTopLevelHWND(mouseWnd
);
4102 if (mouseWnd
== mouseTopLevel
)
4105 return nsWindow::GetTopLevelHWND(aWnd
) != mouseTopLevel
;
4108 PRBool
nsWindow::BlurEventsSuppressed()
4110 // are they suppressed in this window?
4111 if (mBlurSuppressLevel
> 0)
4114 // are they suppressed by any container widget?
4115 HWND parentWnd
= ::GetParent(mWnd
);
4117 nsWindow
*parent
= GetNSWindowPtr(parentWnd
);
4119 return parent
->BlurEventsSuppressed();
4124 // In some circumstances (opening dependent windows) it makes more sense
4125 // (and fixes a crash bug) to not blur the parent window. Called from
4127 void nsWindow::SuppressBlurEvents(PRBool aSuppress
)
4130 ++mBlurSuppressLevel
; // for this widget
4132 NS_ASSERTION(mBlurSuppressLevel
> 0, "unbalanced blur event suppression");
4133 if (mBlurSuppressLevel
> 0)
4134 --mBlurSuppressLevel
;
4138 PRBool
nsWindow::ConvertStatus(nsEventStatus aStatus
)
4140 return aStatus
== nsEventStatus_eConsumeNoDefault
;
4143 /**************************************************************
4147 * IPC related helpers.
4149 **************************************************************/
4155 nsWindow::IsAsyncResponseEvent(UINT aMsg
, LRESULT
& aResult
)
4161 case WM_WINDOWPOSCHANGING
:
4162 case WM_WINDOWPOSCHANGED
:
4163 case WM_PARENTNOTIFY
:
4164 case WM_ACTIVATEAPP
:
4167 case WM_CHILDACTIVATE
:
4168 case WM_IME_SETCONTEXT
:
4172 case WM_MOUSEACTIVATE
:
4173 case WM_CONTEXTMENU
:
4177 case WM_SETTINGCHANGE
:
4185 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg
);
4193 nsWindow::IPCWindowProcHandler(UINT
& msg
, WPARAM
& wParam
, LPARAM
& lParam
)
4195 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4196 "Failed to prevent a nonqueued message from running!");
4198 // Modal UI being displayed in windowless plugins.
4199 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4200 (InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
4202 if (IsAsyncResponseEvent(msg
, res
)) {
4208 // Handle certain sync plugin events sent to the parent which
4209 // trigger ipc calls that result in deadlocks.
4212 PRBool handled
= PR_FALSE
;
4215 // Windowless flash sending WM_ACTIVATE events to the main window
4216 // via calls to ShowWindow.
4218 if (lParam
!= 0 && LOWORD(wParam
) == WA_ACTIVE
&&
4219 IsWindow((HWND
)lParam
))
4222 // Wheel events forwarded from the child.
4224 case WM_MOUSEHWHEEL
:
4227 // Plugins taking or losing focus triggering focus app messages.
4230 // Windowed plugins that pass sys key events to defwndproc generate
4231 // WM_SYSCOMMAND events to the main window.
4233 // Windowed plugins that fire context menu selection events to parent
4235 case WM_CONTEXTMENU
:
4236 // IME events fired as a result of synchronous focus changes
4237 case WM_IME_SETCONTEXT
:
4243 (InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
4244 ReplyMessage(dwResult
);
4250 /**************************************************************
4251 **************************************************************
4253 ** BLOCK: Native events
4255 ** Main Windows message handlers and OnXXX handlers for
4256 ** Windows event handling.
4258 **************************************************************
4259 **************************************************************/
4261 /**************************************************************
4263 * SECTION: Wind proc.
4265 * The main Windows event procedures and associated
4266 * message processing methods.
4268 **************************************************************/
4271 static int ReportException(EXCEPTION_POINTERS
*aExceptionInfo
)
4273 #ifdef MOZ_CRASHREPORTER
4274 nsCOMPtr
<nsICrashReporter
> cr
=
4275 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
4277 cr
->WriteMinidumpForException(aExceptionInfo
);
4279 return EXCEPTION_EXECUTE_HANDLER
;
4283 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
4284 // exceptions and passes the real work to WindowProcInternal. See bug 587406
4285 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
4286 LRESULT CALLBACK
nsWindow::WindowProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
4290 return WindowProcInternal(hWnd
, msg
, wParam
, lParam
);
4292 __except(ReportException(GetExceptionInformation())) {
4293 ::TerminateProcess(::GetCurrentProcess(), 253);
4296 return WindowProcInternal(hWnd
, msg
, wParam
, lParam
);
4300 LRESULT CALLBACK
nsWindow::WindowProcInternal(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
4302 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4303 MOZ_FUNCTION_NAME
, __LINE__
, hWnd
, msg
,
4306 // Get the window which caused the event and ask it to process the message
4307 nsWindow
*someWindow
= GetNSWindowPtr(hWnd
);
4311 someWindow
->IPCWindowProcHandler(msg
, wParam
, lParam
);
4314 // create this here so that we store the last rolled up popup until after
4315 // the event has been processed.
4316 nsAutoRollup autoRollup
;
4318 LRESULT popupHandlingResult
;
4319 if (DealWithPopups(hWnd
, msg
, wParam
, lParam
, &popupHandlingResult
))
4320 return popupHandlingResult
;
4322 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4323 // why we are hitting this assert
4324 if (nsnull
== someWindow
) {
4325 NS_ASSERTION(someWindow
, "someWindow is null, cannot call any CallWindowProc");
4326 return ::DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
4329 // hold on to the window for the life of this method, in case it gets
4330 // deleted during processing. yes, it's a double hack, since someWindow
4331 // is not really an interface.
4332 nsCOMPtr
<nsISupports
> kungFuDeathGrip
;
4333 if (!someWindow
->mInDtor
) // not if we're in the destructor!
4334 kungFuDeathGrip
= do_QueryInterface((nsBaseWidget
*)someWindow
);
4336 // Call ProcessMessage
4338 if (PR_TRUE
== someWindow
->ProcessMessage(msg
, wParam
, lParam
, &retValue
)) {
4342 LRESULT res
= ::CallWindowProcW(someWindow
->GetPrevWindowProc(),
4343 hWnd
, msg
, wParam
, lParam
);
4348 // The main windows message processing method for plugins.
4349 // The result means whether this method processed the native
4350 // event for plugin. If false, the native event should be
4351 // processed by the caller self.
4353 nsWindow::ProcessMessageForPlugin(const MSG
&aMsg
,
4355 PRBool
&aCallDefWndProc
)
4357 NS_PRECONDITION(aResult
, "aResult must be non-null.");
4360 aCallDefWndProc
= PR_FALSE
;
4361 PRBool eventDispatched
= PR_FALSE
;
4362 switch (aMsg
.message
) {
4365 *aResult
= ProcessCharMessage(aMsg
, &eventDispatched
);
4370 *aResult
= ProcessKeyUpMessage(aMsg
, &eventDispatched
);
4375 *aResult
= ProcessKeyDownMessage(aMsg
, &eventDispatched
);
4379 case WM_SYSDEADCHAR
:
4380 case WM_CONTEXTMENU
:
4393 if (!eventDispatched
)
4394 aCallDefWndProc
= !DispatchPluginEvent(aMsg
);
4395 DispatchPendingEvents();
4399 // The main windows message processing method.
4400 PRBool
nsWindow::ProcessMessage(UINT msg
, WPARAM
&wParam
, LPARAM
&lParam
,
4403 // (Large blocks of code should be broken out into OnEvent handlers.)
4404 if (mWindowHook
.Notify(mWnd
, msg
, wParam
, lParam
, aRetValue
))
4407 #if defined(EVENT_DEBUG_OUTPUT)
4408 // First param shows all events, second param indicates whether
4409 // to show mouse move events. See nsWindowDbg for details.
4410 PrintEvent(msg
, SHOW_REPEAT_EVENTS
, SHOW_MOUSEMOVE_EVENTS
);
4414 if (nsIMM32Handler::ProcessMessage(this, msg
, wParam
, lParam
, aRetValue
,
4416 return mWnd
? eatMessage
: PR_TRUE
;
4419 if (PluginHasFocus()) {
4420 PRBool callDefaultWndProc
;
4421 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4422 if (ProcessMessageForPlugin(nativeMsg
, aRetValue
, callDefaultWndProc
)) {
4423 return mWnd
? !callDefaultWndProc
: PR_TRUE
;
4427 PRBool result
= PR_FALSE
; // call the default nsWindow proc
4430 static PRBool getWheelInfo
= PR_TRUE
;
4432 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4433 // Glass hit testing w/custom transparent margins
4434 LRESULT dwmHitResult
;
4435 if (mCustomNonClient
&&
4436 nsUXThemeData::CheckForCompositor() &&
4437 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd
, msg
, wParam
, lParam
, &dwmHitResult
)) {
4438 *aRetValue
= dwmHitResult
;
4441 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4445 // WM_QUERYENDSESSION must be handled by all windows.
4446 // Otherwise Windows thinks the window can just be killed at will.
4447 case WM_QUERYENDSESSION
:
4448 if (sCanQuit
== TRI_UNKNOWN
)
4450 // Ask if it's ok to quit, and store the answer until we
4451 // get WM_ENDSESSION signaling the round is complete.
4452 nsCOMPtr
<nsIObserverService
> obsServ
=
4453 mozilla::services::GetObserverService();
4454 nsCOMPtr
<nsISupportsPRBool
> cancelQuit
=
4455 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID
);
4456 cancelQuit
->SetData(PR_FALSE
);
4457 obsServ
->NotifyObservers(cancelQuit
, "quit-application-requested", nsnull
);
4460 cancelQuit
->GetData(&abortQuit
);
4461 sCanQuit
= abortQuit
? TRI_FALSE
: TRI_TRUE
;
4463 *aRetValue
= sCanQuit
? TRUE
: FALSE
;
4471 case MOZ_WM_APP_QUIT
:
4472 if (msg
== MOZ_WM_APP_QUIT
|| (wParam
== TRUE
&& sCanQuit
== TRI_TRUE
))
4474 // Let's fake a shutdown sequence without actually closing windows etc.
4475 // to avoid Windows killing us in the middle. A proper shutdown would
4476 // require having a chance to pump some messages. Unfortunately
4477 // Windows won't let us do that. Bug 212316.
4478 nsCOMPtr
<nsIObserverService
> obsServ
=
4479 mozilla::services::GetObserverService();
4480 NS_NAMED_LITERAL_STRING(context
, "shutdown-persist");
4481 obsServ
->NotifyObservers(nsnull
, "quit-application-granted", nsnull
);
4482 obsServ
->NotifyObservers(nsnull
, "quit-application-forced", nsnull
);
4483 obsServ
->NotifyObservers(nsnull
, "quit-application", nsnull
);
4484 obsServ
->NotifyObservers(nsnull
, "profile-change-net-teardown", context
.get());
4485 obsServ
->NotifyObservers(nsnull
, "profile-change-teardown", context
.get());
4486 obsServ
->NotifyObservers(nsnull
, "profile-before-change", context
.get());
4487 // Then a controlled but very quick exit.
4490 sCanQuit
= TRI_UNKNOWN
;
4495 case WM_DISPLAYCHANGE
:
4496 DispatchStandardEvent(NS_DISPLAYCHANGED
);
4500 case WM_SYSCOLORCHANGE
:
4501 // Note: This is sent for child windows as well as top-level windows.
4502 // The Win32 toolkit normally only sends these events to top-level windows.
4503 // But we cycle through all of the childwindows and send it to them as well
4504 // so all presentations get notified properly.
4505 // See nsWindow::GlobalMsgWindowProc.
4506 DispatchStandardEvent(NS_SYSCOLORCHANGED
);
4512 LPNMHDR pnmh
= (LPNMHDR
) lParam
;
4514 switch (pnmh
->code
) {
4517 DispatchStandardEvent(NS_TABCHANGE
);
4525 case WM_XP_THEMECHANGED
:
4527 // Update non-client margin offsets
4528 UpdateNonClientMargins();
4530 DispatchStandardEvent(NS_THEMECHANGED
);
4532 // Invalidate the window so that the repaint will
4533 // pick up the new theme.
4534 Invalidate(PR_FALSE
);
4541 PRBool didChange
= PR_FALSE
;
4543 // update the global font list
4544 nsCOMPtr
<nsIFontEnumerator
> fontEnum
= do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv
);
4545 if (NS_SUCCEEDED(rv
)) {
4546 fontEnum
->UpdateFontList(&didChange
);
4547 //didChange is TRUE only if new font langGroup is added to the list.
4549 // update device context font cache
4550 // Dirty but easiest way:
4551 // Changing nsIPrefBranch entry which triggers callbacks
4552 // and flows into calling mDeviceContext->FlushFontCache()
4553 // to update the font cache in all the instance of Browsers
4554 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
4556 nsCOMPtr
<nsIPrefBranch
> fiPrefs
;
4557 prefs
->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs
));
4559 PRBool fontInternalChange
= PR_FALSE
;
4560 fiPrefs
->GetBoolPref("changed", &fontInternalChange
);
4561 fiPrefs
->SetBoolPref("changed", !fontInternalChange
);
4565 } //if (NS_SUCCEEDED(rv))
4571 // If wParam is TRUE, it specifies that the application should indicate
4572 // which part of the client area contains valid information. The system
4573 // copies the valid information to the specified area within the new
4574 // client area. If the wParam parameter is FALSE, the application should
4576 if (mCustomNonClient
) {
4584 // rgrc[0]: the proposed window
4585 // rgrc[1]: the current window
4586 // rgrc[2]: the source client area
4587 // pncsp->lppos: move/size data
4589 // rgrc[0]: the new client area
4590 // rgrc[1]: the destination window
4591 // rgrc[2]: the source client area
4592 // (all values in screen coordiantes)
4593 NCCALCSIZE_PARAMS
*pncsp
= reinterpret_cast<NCCALCSIZE_PARAMS
*>(lParam
);
4594 LRESULT res
= CallWindowProcW(GetPrevWindowProc(), mWnd
, msg
, wParam
, lParam
);
4595 pncsp
->rgrc
[0].top
-= mNonClientOffset
.top
;
4596 pncsp
->rgrc
[0].left
-= mNonClientOffset
.left
;
4597 pncsp
->rgrc
[0].right
+= mNonClientOffset
.right
;
4598 pncsp
->rgrc
[0].bottom
+= mNonClientOffset
.bottom
;
4609 * If an nc client area margin has been moved, we are responsible
4610 * for calculating where the resize margins are and returning the
4611 * appropriate set of hit test constants. DwmDefWindowProc (above)
4612 * will handle hit testing on it's command buttons if we are on a
4613 * composited desktop.
4616 if (!mCustomNonClient
)
4620 ClientMarginHitTestPoint(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
4627 * WM_SETTEXT paints the titlebar area. Avoid this if we have a
4628 * custom titlebar we paint ourselves.
4631 if (!mCustomNonClient
|| mNonClientMargins
.top
== -1)
4635 // From msdn, the way around this is to disable the visible state
4636 // temporarily. We need the text to be set but we don't want the
4638 DWORD style
= GetWindowLong(mWnd
, GWL_STYLE
);
4639 SetWindowLong(mWnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
4640 *aRetValue
= CallWindowProcW(GetPrevWindowProc(), mWnd
,
4641 msg
, wParam
, lParam
);
4642 SetWindowLong(mWnd
, GWL_STYLE
, style
);
4649 * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
4650 * through WM_NCPAINT via InvalidateNonClientRegion.
4653 if (!mCustomNonClient
)
4656 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4657 // let the dwm handle nc painting on glass
4658 if(nsUXThemeData::CheckForCompositor())
4662 if (wParam
== TRUE
) {
4664 *aRetValue
= FALSE
; // ignored
4666 // invalidate to trigger a paint
4667 InvalidateNonClientRegion();
4671 *aRetValue
= TRUE
; // go ahead and deactive
4673 // invalidate to trigger a paint
4674 InvalidateNonClientRegion();
4682 * Reset the non-client paint region so that it excludes the
4683 * non-client areas we paint manually. Then call defwndproc
4684 * to do the actual painting.
4687 if (!mCustomNonClient
)
4690 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4691 // let the dwm handle nc painting on glass
4692 if(nsUXThemeData::CheckForCompositor())
4696 HRGN paintRgn
= ExcludeNonClientFromPaintRegion((HRGN
)wParam
);
4697 LRESULT res
= CallWindowProcW(GetPrevWindowProc(), mWnd
,
4698 msg
, (WPARAM
)paintRgn
, lParam
);
4699 if (paintRgn
!= (HRGN
)wParam
)
4700 DeleteObject(paintRgn
);
4707 case WM_POWERBROADCAST
:
4708 // only hidden window handle this
4709 // to prevent duplicate notification
4710 if (mWindowType
== eWindowType_invisible
) {
4713 case PBT_APMSUSPEND
:
4714 PostSleepWakeNotification("sleep_notification");
4716 case PBT_APMRESUMEAUTOMATIC
:
4717 case PBT_APMRESUMECRITICAL
:
4718 case PBT_APMRESUMESUSPEND
:
4719 PostSleepWakeNotification("wake_notification");
4726 case WM_MOVE
: // Window moved
4729 ::GetWindowRect(mWnd
, &rect
);
4730 result
= OnMove(rect
.left
, rect
.top
);
4734 case WM_CLOSE
: // close request
4735 DispatchStandardEvent(NS_XUL_CLOSE
);
4736 result
= PR_TRUE
; // abort window closure
4746 *aRetValue
= (int) OnPaint(NULL
, 0);
4751 case WM_PRINTCLIENT
:
4752 result
= OnPaint((HDC
) wParam
, 0);
4757 result
= OnHotKey(wParam
, lParam
);
4763 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4764 result
= ProcessCharMessage(nativeMsg
, nsnull
);
4765 DispatchPendingEvents();
4772 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4773 result
= ProcessKeyUpMessage(nativeMsg
, nsnull
);
4774 DispatchPendingEvents();
4781 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4782 result
= ProcessKeyDownMessage(nativeMsg
, nsnull
);
4783 DispatchPendingEvents();
4787 // say we've dealt with erase background if widget does
4788 // not need auto-erasing
4790 if (!AutoErase((HDC
)wParam
)) {
4798 #ifdef WINCE_WINDOWS_MOBILE
4799 // Reset the kill timer so that we can continue at this
4801 SetTimer(mWnd
, KILL_PRIORITY_ID
, 2000 /* 2seconds */, NULL
);
4803 // Suppress dispatch of pending events
4804 // when mouse moves are generated by widget
4805 // creation instead of user input.
4806 LPARAM lParamScreen
= lParamToScreen(lParam
);
4808 mp
.x
= GET_X_LPARAM(lParamScreen
);
4809 mp
.y
= GET_Y_LPARAM(lParamScreen
);
4810 PRBool userMovedMouse
= PR_FALSE
;
4811 if ((sLastMouseMovePoint
.x
!= mp
.x
) || (sLastMouseMovePoint
.y
!= mp
.y
)) {
4812 userMovedMouse
= PR_TRUE
;
4814 mExitToNonClientArea
= PR_FALSE
;
4816 result
= DispatchMouseEvent(NS_MOUSE_MOVE
, wParam
, lParam
,
4817 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4818 if (userMovedMouse
) {
4819 DispatchPendingEvents();
4824 #ifdef WINCE_WINDOWS_MOBILE
4826 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL
);
4827 KillTimer(mWnd
, KILL_PRIORITY_ID
);
4831 case WM_LBUTTONDOWN
:
4833 #ifdef WINCE_WINDOWS_MOBILE
4834 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL
);
4835 SetTimer(mWnd
, KILL_PRIORITY_ID
, 2000 /* 2 seconds */, NULL
);
4837 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
,
4838 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4839 DispatchPendingEvents();
4845 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
,
4846 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4847 DispatchPendingEvents();
4849 #ifdef WINCE_WINDOWS_MOBILE
4850 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL
);
4851 KillTimer(mWnd
, KILL_PRIORITY_ID
);
4859 // We need to check mouse button states and put them in for
4861 WPARAM mouseState
= (GetKeyState(VK_LBUTTON
) ? MK_LBUTTON
: 0)
4862 | (GetKeyState(VK_MBUTTON
) ? MK_MBUTTON
: 0)
4863 | (GetKeyState(VK_RBUTTON
) ? MK_RBUTTON
: 0);
4864 // Synthesize an event position because we don't get one from
4866 LPARAM pos
= lParamToClient(::GetMessagePos());
4867 DispatchMouseEvent(NS_MOUSE_EXIT
, mouseState
, pos
, PR_FALSE
,
4868 nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4873 case WM_CONTEXTMENU
:
4875 // if the context menu is brought up from the keyboard, |lParam|
4878 PRBool contextMenukey
= PR_FALSE
;
4881 contextMenukey
= PR_TRUE
;
4882 pos
= lParamToClient(GetMessagePos());
4886 pos
= lParamToClient(lParam
);
4889 result
= DispatchMouseEvent(NS_CONTEXTMENU
, wParam
, pos
, contextMenukey
,
4891 nsMouseEvent::eLeftButton
:
4892 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4896 case WM_LBUTTONDBLCLK
:
4897 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4898 nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4901 case WM_MBUTTONDOWN
:
4903 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4904 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4905 DispatchPendingEvents();
4910 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, PR_FALSE
,
4911 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4912 DispatchPendingEvents();
4915 case WM_MBUTTONDBLCLK
:
4916 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4917 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4920 case WM_NCMBUTTONDOWN
:
4921 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, 0, lParamToClient(lParam
), PR_FALSE
,
4922 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4923 DispatchPendingEvents();
4926 case WM_NCMBUTTONUP
:
4927 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, 0, lParamToClient(lParam
), PR_FALSE
,
4928 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4929 DispatchPendingEvents();
4932 case WM_NCMBUTTONDBLCLK
:
4933 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, 0, lParamToClient(lParam
), PR_FALSE
,
4934 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4935 DispatchPendingEvents();
4938 case WM_RBUTTONDOWN
:
4940 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4941 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4942 DispatchPendingEvents();
4947 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, PR_FALSE
,
4948 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4949 DispatchPendingEvents();
4952 case WM_RBUTTONDBLCLK
:
4953 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4954 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4957 case WM_NCRBUTTONDOWN
:
4958 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, 0, lParamToClient(lParam
),
4959 PR_FALSE
, nsMouseEvent::eRightButton
,
4960 MOUSE_INPUT_SOURCE());
4961 DispatchPendingEvents();
4964 case WM_NCRBUTTONUP
:
4965 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, 0, lParamToClient(lParam
),
4966 PR_FALSE
, nsMouseEvent::eRightButton
,
4967 MOUSE_INPUT_SOURCE());
4968 DispatchPendingEvents();
4971 case WM_NCRBUTTONDBLCLK
:
4972 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, 0, lParamToClient(lParam
),
4973 PR_FALSE
, nsMouseEvent::eRightButton
,
4974 MOUSE_INPUT_SOURCE());
4978 PRUint32 appCommand
= GET_APPCOMMAND_LPARAM(lParam
);
4982 case APPCOMMAND_BROWSER_BACKWARD
:
4983 case APPCOMMAND_BROWSER_FORWARD
:
4984 case APPCOMMAND_BROWSER_REFRESH
:
4985 case APPCOMMAND_BROWSER_STOP
:
4986 case APPCOMMAND_BROWSER_SEARCH
:
4987 case APPCOMMAND_BROWSER_FAVORITES
:
4988 case APPCOMMAND_BROWSER_HOME
:
4989 DispatchCommandEvent(appCommand
);
4990 // tell the driver that we handled the event
4995 // default = PR_FALSE - tell the driver that the event was not handled
5002 result
= OnScroll(msg
, wParam
, lParam
);
5005 // The WM_ACTIVATE event is fired when a window is raised or lowered,
5006 // and the loword of wParam specifies which. But we don't want to tell
5007 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
5008 // events are fired. Instead, set either the sJustGotActivate or
5009 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
5010 // events once the focus events arrive.
5012 if (mEventCallback
) {
5013 PRInt32 fActive
= LOWORD(wParam
);
5015 #if defined(WINCE_HAVE_SOFTKB)
5016 if (mIsTopWidgetWindow
&& sSoftKeyboardState
)
5017 nsWindowCE::ToggleSoftKB(mWnd
, fActive
);
5018 if (nsWindowCE::sShowSIPButton
== TRI_FALSE
&& WA_INACTIVE
!= fActive
) {
5019 HWND hWndSIPB
= FindWindowW(L
"MS_SIPBUTTON", NULL
);
5021 ShowWindow(hWndSIPB
, SW_HIDE
);
5026 if (WA_INACTIVE
== fActive
) {
5027 // when minimizing a window, the deactivation and focus events will
5028 // be fired in the reverse order. Instead, just dispatch
5029 // NS_DEACTIVATE right away.
5031 result
= DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5033 sJustGotDeactivate
= PR_TRUE
;
5035 if (mIsTopWidgetWindow
)
5036 mLastKeyboardLayout
= gKbdLayout
.GetLayout();
5042 sJustGotActivate
= PR_TRUE
;
5043 nsMouseEvent
event(PR_TRUE
, NS_MOUSE_ACTIVATE
, this,
5044 nsMouseEvent::eReal
);
5047 event
.acceptActivation
= PR_TRUE
;
5049 DispatchWindowEvent(&event
);
5051 if (event
.acceptActivation
)
5052 *aRetValue
= MA_ACTIVATE
;
5054 *aRetValue
= MA_NOACTIVATE
;
5056 if (sSwitchKeyboardLayout
&& mLastKeyboardLayout
)
5057 ActivateKeyboardLayout(mLastKeyboardLayout
, 0);
5063 #ifdef WINCE_WINDOWS_MOBILE
5064 if (!gCheckForHTCApi
&& gHTCApiNavOpen
== nsnull
) {
5065 gCheckForHTCApi
= PR_TRUE
;
5067 HINSTANCE library
= LoadLibrary(L
"HTCAPI.dll");
5068 gHTCApiNavOpen
= (HTCApiNavOpen
) GetProcAddress(library
, "HTCNavOpen");
5069 gHTCApiNavSetMode
= (HTCApiNavSetMode
) GetProcAddress(library
,"HTCNavSetMode");
5072 if (gHTCApiNavOpen
!= nsnull
) {
5073 gHTCApiNavOpen(mWnd
, 1 /* undocumented value */);
5075 if (gHTCApiNavSetMode
!= nsnull
)
5076 gHTCApiNavSetMode ( mWnd
, 4);
5077 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5083 case WM_MOUSEACTIVATE
:
5084 if (mWindowType
== eWindowType_popup
) {
5085 // a popup with a parent owner should not be activated when clicked
5086 // but should still allow the mouse event to be fired, so the return
5087 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5088 // window, just use default processing so that the window is activated.
5089 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
5090 if (owner
&& owner
== ::GetForegroundWindow()) {
5091 *aRetValue
= MA_NOACTIVATE
;
5097 case WM_WINDOWPOSCHANGING
:
5099 LPWINDOWPOS info
= (LPWINDOWPOS
) lParam
;
5100 OnWindowPosChanging(info
);
5106 if (sJustGotActivate
) {
5107 result
= DispatchFocusToTopLevelWindow(NS_ACTIVATE
);
5110 #ifdef ACCESSIBILITY
5111 if (nsWindow::sIsAccessibilityOn
) {
5112 // Create it for the first time so that it can start firing events
5113 nsAccessible
*rootAccessible
= GetRootAccessible();
5117 #if defined(WINCE_HAVE_SOFTKB)
5119 // On Windows CE, we have a window that overlaps
5120 // the ISP button. In this case, we should always
5121 // try to hide it when we are activated
5123 nsIMEContext
IMEContext(mWnd
);
5125 ImmSetOpenStatus(IMEContext
.get(), TRUE
);
5131 #if defined(WINCE_HAVE_SOFTKB)
5133 nsIMEContext
IMEContext(mWnd
);
5134 ImmSetOpenStatus(IMEContext
.get(), FALSE
);
5137 if (sJustGotDeactivate
) {
5138 result
= DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5142 case WM_WINDOWPOSCHANGED
:
5144 WINDOWPOS
*wp
= (LPWINDOWPOS
)lParam
;
5145 OnWindowPosChanged(wp
, result
);
5149 case WM_SETTINGCHANGE
:
5150 #if !defined (WINCE_WINDOWS_MOBILE)
5151 getWheelInfo
= PR_TRUE
;
5154 case SPI_SETSIPINFO
:
5155 case SPI_SETCURRENTIM
:
5156 nsWindowCE::OnSoftKbSettingsChange(mWnd
);
5158 case SETTINGCHANGE_RESET
:
5159 if (mWindowType
== eWindowType_invisible
) {
5160 // The OS sees to get confused and think that the invisable window
5161 // is in the foreground after an orientation change. By actually
5162 // setting it to the foreground and hiding it, we set it strait.
5163 // See bug 514007 for details.
5164 SetForegroundWindow(mWnd
);
5165 ShowWindow(mWnd
, SW_HIDE
);
5170 OnSettingsChange(wParam
, lParam
);
5174 case WM_INPUTLANGCHANGEREQUEST
:
5179 case WM_INPUTLANGCHANGE
:
5180 result
= OnInputLangChange((HKL
)lParam
);
5184 case WM_DESTROYCLIPBOARD
:
5186 nsIClipboard
* clipboard
;
5187 nsresult rv
= CallGetService(kCClipboardCID
, &clipboard
);
5188 if(NS_SUCCEEDED(rv
)) {
5189 clipboard
->EmptyClipboard(nsIClipboard::kGlobalClipboard
);
5190 NS_RELEASE(clipboard
);
5195 #ifdef ACCESSIBILITY
5199 if (lParam
== OBJID_CLIENT
) { // oleacc.dll will be loaded dynamically
5200 nsAccessible
*rootAccessible
= GetRootAccessible(); // Held by a11y cache
5201 if (rootAccessible
) {
5202 IAccessible
*msaaAccessible
= NULL
;
5203 rootAccessible
->GetNativeInterface((void**)&msaaAccessible
); // does an addref
5204 if (msaaAccessible
) {
5205 *aRetValue
= LresultFromObject(IID_IAccessible
, wParam
, msaaAccessible
); // does an addref
5206 msaaAccessible
->Release(); // release extra addref
5207 result
= PR_TRUE
; // We handled the WM_GETOBJECT message
5216 // prevent Windows from trimming the working set. bug 76831
5217 if (!sTrimOnMinimize
&& wParam
== SC_MINIMIZE
) {
5218 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
5227 nsMemory::HeapMinimize(PR_TRUE
);
5232 case WM_MOUSEHWHEEL
:
5234 // If OnMouseWheel returns true, the event was forwarded directly to another
5235 // mozilla window message handler (ProcessMessage). In this case the return
5236 // value of the forwarded event is in 'result' which we should return immediately.
5237 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5238 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5239 // we should fall through.
5240 if (OnMouseWheel(msg
, wParam
, lParam
, getWheelInfo
, result
, aRetValue
))
5246 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5247 case WM_DWMCOMPOSITIONCHANGED
:
5248 UpdateNonClientMargins();
5249 BroadcastMsg(mWnd
, WM_DWMCOMPOSITIONCHANGED
);
5250 DispatchStandardEvent(NS_THEMECHANGED
);
5252 Invalidate(PR_FALSE
);
5256 case WM_UPDATEUISTATE
:
5258 // If the UI state has changed, fire an event so the UI updates the
5259 // keyboard cues based on the system setting and how the window was
5260 // opened. For example, a dialog opened via a keyboard press on a button
5261 // should enable cues, whereas the same dialog opened via a mouse click of
5262 // the button should not.
5263 PRInt32 action
= LOWORD(wParam
);
5264 if (action
== UIS_SET
|| action
== UIS_CLEAR
) {
5265 nsUIStateChangeEvent
event(PR_TRUE
, NS_UISTATECHANGED
, this);
5266 PRInt32 flags
= HIWORD(wParam
);
5267 if (flags
& UISF_HIDEACCEL
)
5268 event
.showAccelerators
= (action
== UIS_SET
) ? UIStateChangeType_Clear
: UIStateChangeType_Set
;
5269 if (flags
& UISF_HIDEFOCUS
)
5270 event
.showFocusRings
= (action
== UIS_SET
) ? UIStateChangeType_Clear
: UIStateChangeType_Set
;
5271 DispatchWindowEvent(&event
);
5277 /* Gesture support events */
5278 case WM_TABLET_QUERYSYSTEMGESTURESTATUS
:
5279 // According to MS samples, this must be handled to enable
5280 // rotational support in multi-touch drivers.
5282 *aRetValue
= TABLET_ROTATE_GESTURE_ENABLE
;
5285 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5287 result
= OnTouch(wParam
, lParam
);
5295 result
= OnGesture(wParam
, lParam
);
5298 case WM_GESTURENOTIFY
:
5300 if (mWindowType
!= eWindowType_invisible
&&
5301 mWindowType
!= eWindowType_plugin
) {
5302 // A GestureNotify event is dispatched to decide which single-finger panning
5303 // direction should be active (including none) and if pan feedback should
5304 // be displayed. Java and plugin windows can make their own calls.
5305 GESTURENOTIFYSTRUCT
* gestureinfo
= (GESTURENOTIFYSTRUCT
*)lParam
;
5306 nsPointWin touchPoint
;
5307 touchPoint
= gestureinfo
->ptsLocation
;
5308 touchPoint
.ScreenToClient(mWnd
);
5309 nsGestureNotifyEvent
gestureNotifyEvent(PR_TRUE
, NS_GESTURENOTIFY_EVENT_START
, this);
5310 gestureNotifyEvent
.refPoint
= touchPoint
;
5311 nsEventStatus status
;
5312 DispatchEvent(&gestureNotifyEvent
, status
);
5313 mDisplayPanFeedback
= gestureNotifyEvent
.displayPanFeedback
;
5315 mGesture
.SetWinGestureSupport(mWnd
, gestureNotifyEvent
.panDirection
);
5317 result
= PR_FALSE
; //should always bubble to DefWindowProc
5320 #endif // !defined(WINCE)
5324 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_DELETE
, this);
5325 DispatchWindowEvent(&command
);
5332 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_CUT
, this);
5333 DispatchWindowEvent(&command
);
5340 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_COPY
, this);
5341 DispatchWindowEvent(&command
);
5348 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_PASTE
, this);
5349 DispatchWindowEvent(&command
);
5357 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_UNDO
, this);
5358 DispatchWindowEvent(&command
);
5359 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5366 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_REDO
, this);
5367 DispatchWindowEvent(&command
);
5368 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5375 // Support EM_CANPASTE message only when wParam isn't specified or
5376 // is plain text format.
5377 if (wParam
== 0 || wParam
== CF_TEXT
|| wParam
== CF_UNICODETEXT
) {
5378 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_PASTE
,
5380 DispatchWindowEvent(&command
);
5381 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5389 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_UNDO
,
5391 DispatchWindowEvent(&command
);
5392 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5399 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_REDO
,
5401 DispatchWindowEvent(&command
);
5402 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5408 #ifdef WINCE_WINDOWS_MOBILE
5409 //HTC NAVIGATION WHEEL EVENT
5412 int distance
= wParam
& 0x000000FF;
5413 if ( (wParam
& 0x000000100) != 0) // Counter Clockwise
5415 if (OnMouseWheel(WM_MOUSEWHEEL
, MAKEWPARAM(0, distance
),
5416 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN
) / 2,
5417 GetSystemMetrics(SM_CYSCREEN
) / 2),
5418 getWheelInfo
, result
, aRetValue
))
5426 #ifdef NS_ENABLE_TSF
5427 if (msg
== WM_USER_TSF_TEXTCHANGE
) {
5428 nsTextStore::OnTextChangeMsg();
5430 #endif //NS_ENABLE_TSF
5431 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5432 if (msg
== nsAppShell::GetTaskbarButtonCreatedMessage())
5433 SetHasTaskbarIconBeenCreated();
5436 if (msg
== sOOPPPluginFocusEvent
) {
5438 // With OOPP, the plugin window exists in another process and is a child of
5439 // this window. This window is a placeholder plugin window for the dom. We
5440 // receive this event when the child window receives focus. (sent from
5441 // PluginInstanceParent.cpp)
5442 ::SendMessage(mWnd
, WM_MOUSEACTIVATE
, 0, 0); // See nsPluginNativeWindowWin.cpp
5444 // WM_KILLFOCUS was received by the child process.
5445 if (sJustGotDeactivate
) {
5446 DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5455 //*aRetValue = result;
5460 //Events which caused mWnd destruction and aren't consumed
5461 //will crash during the Windows default processing.
5466 /**************************************************************
5468 * SECTION: Broadcast messaging
5470 * Broadcast messages to all windows.
5472 **************************************************************/
5474 // Enumerate all child windows sending aMsg to each of them
5475 BOOL CALLBACK
nsWindow::BroadcastMsgToChildren(HWND aWnd
, LPARAM aMsg
)
5477 WNDPROC winProc
= (WNDPROC
)::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
5478 if (winProc
== &nsWindow::WindowProc
) {
5479 // it's one of our windows so go ahead and send a message to it
5480 ::CallWindowProcW(winProc
, aWnd
, aMsg
, 0, 0);
5485 // Enumerate all top level windows specifying that the children of each
5486 // top level window should be enumerated. Do *not* send the message to
5487 // each top level window since it is assumed that the toolkit will send
5488 // aMsg to them directly.
5489 BOOL CALLBACK
nsWindow::BroadcastMsg(HWND aTopWindow
, LPARAM aMsg
)
5491 // Iterate each of aTopWindows child windows sending the aMsg
5494 ::EnumChildWindows(aTopWindow
, nsWindow::BroadcastMsgToChildren
, aMsg
);
5496 nsWindowCE::EnumChildWindows(aTopWindow
, nsWindow::BroadcastMsgToChildren
, aMsg
);
5501 // This method is called from nsToolkit::WindowProc to forward global
5502 // messages which need to be dispatched to all child windows.
5503 void nsWindow::GlobalMsgWindowProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
5506 case WM_SYSCOLORCHANGE
:
5507 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5508 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5509 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5510 // all child windows as well. When running in an embedded application
5511 // we may not receive a WM_SYSCOLORCHANGE message because the top
5512 // level window is owned by the embeddor.
5513 // System color changes are posted to top-level windows only.
5514 // The NS_SYSCOLORCHANGE must be dispatched to all child
5517 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg
, msg
);
5523 /**************************************************************
5525 * SECTION: Event processing helpers
5527 * Special processing for certain event types and
5528 * synthesized events.
5530 **************************************************************/
5533 nsWindow::ClientMarginHitTestPoint(PRInt32 mx
, PRInt32 my
)
5535 // Calculations are done in screen coords
5537 GetWindowRect(mWnd
, &winRect
);
5539 // hit return constants:
5540 // HTBORDER - non-resizable border
5541 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5542 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5543 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5544 // HTCAPTION - general title bar area
5545 // HTCLIENT - area considered the client
5546 // HTCLOSE - hovering over the close button
5547 // HTMAXBUTTON - maximize button
5548 // HTMINBUTTON - minimize button
5550 PRInt32 testResult
= HTCLIENT
;
5552 PRBool top
= PR_FALSE
;
5553 PRBool bottom
= PR_FALSE
;
5554 PRBool left
= PR_FALSE
;
5555 PRBool right
= PR_FALSE
;
5557 if (my
>= winRect
.top
&& my
<=
5558 (winRect
.top
+ mVertResizeMargin
+ (mCaptionHeight
- mNonClientOffset
.top
)))
5560 else if (my
<= winRect
.bottom
&& my
>= (winRect
.bottom
- mVertResizeMargin
))
5563 if (mx
>= winRect
.left
&& mx
<= (winRect
.left
+ mHorResizeMargin
))
5565 else if (mx
<= winRect
.right
&& mx
>= (winRect
.right
- mHorResizeMargin
))
5571 testResult
= HTTOPLEFT
;
5573 testResult
= HTTOPRIGHT
;
5574 } else if (bottom
) {
5575 testResult
= HTBOTTOM
;
5577 testResult
= HTBOTTOMLEFT
;
5579 testResult
= HTBOTTOMRIGHT
;
5582 testResult
= HTLEFT
;
5584 testResult
= HTRIGHT
;
5587 PRBool contentOverlap
= PR_TRUE
;
5589 if (mSizeMode
== nsSizeMode_Maximized
) {
5590 // There's no HTTOP in maximized state (bug 575493)
5591 if (testResult
== HTTOP
) {
5592 testResult
= HTCAPTION
;
5595 PRInt32 leftMargin
= mNonClientMargins
.left
== -1 ? mHorResizeMargin
: mNonClientMargins
.left
;
5596 PRInt32 rightMargin
= mNonClientMargins
.right
== -1 ? mHorResizeMargin
: mNonClientMargins
.right
;
5597 PRInt32 topMargin
= mNonClientMargins
.top
== -1 ? mVertResizeMargin
: mNonClientMargins
.top
;
5598 PRInt32 bottomMargin
= mNonClientMargins
.bottom
== -1 ? mVertResizeMargin
: mNonClientMargins
.bottom
;
5600 contentOverlap
= mx
>= winRect
.left
+ leftMargin
&&
5601 mx
<= winRect
.right
- rightMargin
&&
5602 my
>= winRect
.top
+ topMargin
&&
5603 my
<= winRect
.bottom
- bottomMargin
;
5606 if (!mIsInMouseCapture
&&
5608 (testResult
== HTCLIENT
||
5609 testResult
== HTTOP
||
5610 testResult
== HTTOPLEFT
||
5611 testResult
== HTCAPTION
)) {
5612 LPARAM lParam
= MAKELPARAM(mx
, my
);
5613 LPARAM lParamClient
= lParamToClient(lParam
);
5614 PRBool result
= DispatchMouseEvent(NS_MOUSE_MOZHITTEST
, 0, lParamClient
,
5615 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
5617 // The mouse is over a blank area
5618 testResult
= testResult
== HTCLIENT
? HTCAPTION
: testResult
;
5620 if (!mExitToNonClientArea
) {
5621 // The first time the mouse pointer goes from client area to non-client area,
5622 // we don't want to miss that movement so we can interpret mouseout input.
5623 ::SendMessage(mWnd
, WM_MOUSEMOVE
, 0, lParamClient
);
5624 mExitToNonClientArea
= PR_TRUE
;
5627 // There's content over the mouse pointer. Set HTCLIENT
5628 // to possibly override a resizer border.
5629 testResult
= HTCLIENT
;
5638 void nsWindow::PostSleepWakeNotification(const char* aNotification
)
5640 nsCOMPtr
<nsIObserverService
> observerService
=
5641 mozilla::services::GetObserverService();
5642 if (observerService
)
5643 observerService
->NotifyObservers(nsnull
, aNotification
, nsnull
);
5647 LRESULT
nsWindow::ProcessCharMessage(const MSG
&aMsg
, PRBool
*aEventDispatched
)
5649 NS_PRECONDITION(aMsg
.message
== WM_CHAR
|| aMsg
.message
== WM_SYSCHAR
,
5650 "message is not keydown event");
5651 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5652 ("%s charCode=%d scanCode=%d\n",
5653 aMsg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
5654 aMsg
.wParam
, HIWORD(aMsg
.lParam
) & 0xFF));
5656 // These must be checked here too as a lone WM_CHAR could be received
5657 // if a child window didn't handle it (for example Alt+Space in a content window)
5658 nsModifierKeyState modKeyState
;
5659 return OnChar(aMsg
, modKeyState
, aEventDispatched
);
5662 LRESULT
nsWindow::ProcessKeyUpMessage(const MSG
&aMsg
, PRBool
*aEventDispatched
)
5664 NS_PRECONDITION(aMsg
.message
== WM_KEYUP
|| aMsg
.message
== WM_SYSKEYUP
,
5665 "message is not keydown event");
5666 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5667 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
5668 "WM_SYSKEYUP" : "WM_KEYUP", aMsg
.wParam
));
5670 nsModifierKeyState modKeyState
;
5672 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5673 // scan code. However, this breaks Alt+Num pad input.
5674 // MSDN states the following:
5675 // Typically, ToAscii performs the translation based on the
5676 // virtual-key code. In some cases, however, bit 15 of the
5677 // uScanCode parameter may be used to distinguish between a key
5678 // press and a key release. The scan code is used for
5679 // translating ALT+number key combinations.
5681 // ignore [shift+]alt+space so the OS can handle it
5682 if (modKeyState
.mIsAltDown
&& !modKeyState
.mIsControlDown
&&
5683 IS_VK_DOWN(NS_VK_SPACE
)) {
5687 if (!nsIMM32Handler::IsComposingOn(this) &&
5688 (aMsg
.message
!= WM_KEYUP
|| aMsg
.wParam
!= VK_MENU
)) {
5689 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5690 // This helps avoid triggering the menu bar for ALT key accelerators used in
5691 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5692 // to switch back to Mozilla in Windows 95 and Windows 98
5693 return OnKeyUp(aMsg
, modKeyState
, aEventDispatched
);
5699 LRESULT
nsWindow::ProcessKeyDownMessage(const MSG
&aMsg
,
5700 PRBool
*aEventDispatched
)
5702 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5703 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
5704 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg
.wParam
));
5705 NS_PRECONDITION(aMsg
.message
== WM_KEYDOWN
|| aMsg
.message
== WM_SYSKEYDOWN
,
5706 "message is not keydown event");
5708 nsModifierKeyState modKeyState
;
5710 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
5711 // scan code. However, this breaks Alt+Num pad input.
5712 // MSDN states the following:
5713 // Typically, ToAscii performs the translation based on the
5714 // virtual-key code. In some cases, however, bit 15 of the
5715 // uScanCode parameter may be used to distinguish between a key
5716 // press and a key release. The scan code is used for
5717 // translating ALT+number key combinations.
5719 // ignore [shift+]alt+space so the OS can handle it
5720 if (modKeyState
.mIsAltDown
&& !modKeyState
.mIsControlDown
&&
5721 IS_VK_DOWN(NS_VK_SPACE
))
5725 if (modKeyState
.mIsAltDown
&& nsIMM32Handler::IsStatusChanged()) {
5726 nsIMM32Handler::NotifyEndStatusChange();
5727 } else if (!nsIMM32Handler::IsComposingOn(this)) {
5728 result
= OnKeyDown(aMsg
, modKeyState
, aEventDispatched
, nsnull
);
5732 if (aMsg
.wParam
== VK_MENU
||
5733 (aMsg
.wParam
== VK_F10
&& !modKeyState
.mIsShiftDown
)) {
5734 // We need to let Windows handle this keypress,
5735 // by returning PR_FALSE, if there's a native menu
5736 // bar somewhere in our containing window hierarchy.
5737 // Otherwise we handle the keypress and don't pass
5738 // it on to Windows, by returning PR_TRUE.
5739 PRBool hasNativeMenu
= PR_FALSE
;
5742 if (::GetMenu(hWnd
)) {
5743 hasNativeMenu
= PR_TRUE
;
5746 hWnd
= ::GetParent(hWnd
);
5748 result
= !hasNativeMenu
;
5756 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout
,
5757 PRInt32 aNativeKeyCode
,
5758 PRUint32 aModifierFlags
,
5759 const nsAString
& aCharacters
,
5760 const nsAString
& aUnmodifiedCharacters
)
5762 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
5763 nsPrintfCString
layoutName("%08x", aNativeKeyboardLayout
);
5764 HKL loadedLayout
= LoadKeyboardLayoutA(layoutName
.get(), KLF_NOTELLSHELL
);
5765 if (loadedLayout
== NULL
)
5766 return NS_ERROR_NOT_AVAILABLE
;
5768 // Setup clean key state and load desired layout
5769 BYTE originalKbdState
[256];
5770 ::GetKeyboardState(originalKbdState
);
5772 memset(kbdState
, 0, sizeof(kbdState
));
5773 // This changes the state of the keyboard for the current thread only,
5774 // and we'll restore it soon, so this should be OK.
5775 ::SetKeyboardState(kbdState
);
5776 HKL oldLayout
= gKbdLayout
.GetLayout();
5777 gKbdLayout
.LoadLayout(loadedLayout
);
5779 nsAutoTArray
<KeyPair
,10> keySequence
;
5780 SetupKeyModifiersSequence(&keySequence
, aModifierFlags
);
5781 NS_ASSERTION(aNativeKeyCode
>= 0 && aNativeKeyCode
< 256,
5782 "Native VK key code out of range");
5783 keySequence
.AppendElement(KeyPair(aNativeKeyCode
, 0));
5785 // Simulate the pressing of each modifier key and then the real key
5786 for (PRUint32 i
= 0; i
< keySequence
.Length(); ++i
) {
5787 PRUint8 key
= keySequence
[i
].mGeneral
;
5788 PRUint8 keySpecific
= keySequence
[i
].mSpecific
;
5789 kbdState
[key
] = 0x81; // key is down and toggled on if appropriate
5791 kbdState
[keySpecific
] = 0x81;
5793 ::SetKeyboardState(kbdState
);
5794 nsModifierKeyState modKeyState
;
5795 MSG msg
= InitMSG(WM_KEYDOWN
, key
, 0);
5796 if (i
== keySequence
.Length() - 1 && aCharacters
.Length() > 0) {
5797 UINT scanCode
= ::MapVirtualKeyEx(aNativeKeyCode
, MAPVK_VK_TO_VSC
,
5798 gKbdLayout
.GetLayout());
5799 nsFakeCharMessage fakeMsg
= { aCharacters
.CharAt(0), scanCode
};
5800 OnKeyDown(msg
, modKeyState
, nsnull
, &fakeMsg
);
5802 OnKeyDown(msg
, modKeyState
, nsnull
, nsnull
);
5805 for (PRUint32 i
= keySequence
.Length(); i
> 0; --i
) {
5806 PRUint8 key
= keySequence
[i
- 1].mGeneral
;
5807 PRUint8 keySpecific
= keySequence
[i
- 1].mSpecific
;
5808 kbdState
[key
] = 0; // key is up and toggled off if appropriate
5810 kbdState
[keySpecific
] = 0;
5812 ::SetKeyboardState(kbdState
);
5813 nsModifierKeyState modKeyState
;
5814 MSG msg
= InitMSG(WM_KEYUP
, key
, 0);
5815 OnKeyUp(msg
, modKeyState
, nsnull
);
5818 // Restore old key state and layout
5819 ::SetKeyboardState(originalKbdState
);
5820 gKbdLayout
.LoadLayout(oldLayout
);
5822 UnloadKeyboardLayout(loadedLayout
);
5824 #else //XXX: is there another way to do this?
5825 return NS_ERROR_NOT_IMPLEMENTED
;
5830 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint
,
5831 PRUint32 aNativeMessage
,
5832 PRUint32 aModifierFlags
)
5834 #ifndef WINCE // I don't think WINCE supports SendInput
5836 ::GetWindowRect(mWnd
, &r
);
5837 ::SetCursorPos(r
.left
+ aPoint
.x
, r
.top
+ aPoint
.y
);
5840 memset(&input
, 0, sizeof(input
));
5842 input
.type
= INPUT_MOUSE
;
5843 input
.mi
.dwFlags
= aNativeMessage
;
5844 ::SendInput(1, &input
, sizeof(INPUT
));
5848 return NS_ERROR_NOT_IMPLEMENTED
;
5852 /**************************************************************
5854 * SECTION: OnXXX message handlers
5856 * For message handlers that need to be broken out or
5857 * implemented in specific platform code.
5859 **************************************************************/
5861 BOOL
nsWindow::OnInputLangChange(HKL aHKL
)
5864 printf("OnInputLanguageChange\n");
5868 gKbdLayout
.LoadLayout(aHKL
);
5871 return PR_FALSE
; // always pass to child window
5874 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5875 void nsWindow::OnWindowPosChanged(WINDOWPOS
*wp
, PRBool
& result
)
5880 #ifdef WINSTATE_DEBUG_OUTPUT
5881 if (mWnd
== GetTopLevelHWND(mWnd
))
5882 printf("*** OnWindowPosChanged: [ top] ");
5884 printf("*** OnWindowPosChanged: [child] ");
5885 printf("WINDOWPOS flags:");
5886 if (wp
->flags
& SWP_FRAMECHANGED
)
5887 printf("SWP_FRAMECHANGED ");
5888 if (wp
->flags
& SWP_SHOWWINDOW
)
5889 printf("SWP_SHOWWINDOW ");
5890 if (wp
->flags
& SWP_NOSIZE
)
5891 printf("SWP_NOSIZE ");
5892 if (wp
->flags
& SWP_HIDEWINDOW
)
5893 printf("SWP_HIDEWINDOW ");
5897 // Handle window size mode changes
5898 if (wp
->flags
& SWP_FRAMECHANGED
&& mSizeMode
!= nsSizeMode_Fullscreen
) {
5899 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
5902 pl
.length
= sizeof(pl
);
5903 ::GetWindowPlacement(mWnd
, &pl
);
5905 if (pl
.showCmd
== SW_SHOWMAXIMIZED
)
5906 event
.mSizeMode
= nsSizeMode_Maximized
;
5907 else if (pl
.showCmd
== SW_SHOWMINIMIZED
)
5908 event
.mSizeMode
= nsSizeMode_Minimized
;
5909 else if (mFullscreenMode
)
5910 event
.mSizeMode
= nsSizeMode_Fullscreen
;
5912 event
.mSizeMode
= nsSizeMode_Normal
;
5914 // Windows has just changed the size mode of this window. The following
5915 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
5916 // set the min/max window state again or for nsSizeMode_Normal, call
5917 // SetWindow with a parameter of SW_RESTORE. There's no need however as
5918 // this window's mode has already changed. Updating mSizeMode here
5919 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
5920 // to window docking. (bug 489258)
5921 mSizeMode
= event
.mSizeMode
;
5923 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
5924 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
5925 // prevents the working set from being trimmed but keeps the window active.
5926 // After the window is minimized, we need to do some touch up work on the
5927 // active window. (bugs 76831 & 499816)
5928 if (!sTrimOnMinimize
&& nsSizeMode_Minimized
== event
.mSizeMode
)
5929 ActivateOtherWindowHelper(mWnd
);
5931 #ifdef WINSTATE_DEBUG_OUTPUT
5932 switch (mSizeMode
) {
5933 case nsSizeMode_Normal
:
5934 printf("*** mSizeMode: nsSizeMode_Normal\n");
5936 case nsSizeMode_Minimized
:
5937 printf("*** mSizeMode: nsSizeMode_Minimized\n");
5939 case nsSizeMode_Maximized
:
5940 printf("*** mSizeMode: nsSizeMode_Maximized\n");
5943 printf("*** mSizeMode: ??????\n");
5950 result
= DispatchWindowEvent(&event
);
5952 // Skip window size change events below on minimization.
5953 if (mSizeMode
== nsSizeMode_Minimized
)
5957 // Handle window size changes
5958 if (0 == (wp
->flags
& SWP_NOSIZE
)) {
5960 PRInt32 newWidth
, newHeight
;
5962 ::GetWindowRect(mWnd
, &r
);
5964 newWidth
= r
.right
- r
.left
;
5965 newHeight
= r
.bottom
- r
.top
;
5966 nsIntRect
rect(wp
->x
, wp
->y
, newWidth
, newHeight
);
5969 if (eTransparencyTransparent
== mTransparencyMode
)
5970 ResizeTranslucentWindow(newWidth
, newHeight
);
5973 if (newWidth
> mLastSize
.width
)
5978 drect
.left
= wp
->x
+ mLastSize
.width
;
5980 drect
.right
= drect
.left
+ (newWidth
- mLastSize
.width
);
5981 drect
.bottom
= drect
.top
+ newHeight
;
5983 ::RedrawWindow(mWnd
, &drect
, NULL
,
5986 RDW_NOINTERNALPAINT
|
5990 if (newHeight
> mLastSize
.height
)
5996 drect
.top
= wp
->y
+ mLastSize
.height
;
5997 drect
.right
= drect
.left
+ newWidth
;
5998 drect
.bottom
= drect
.top
+ (newHeight
- mLastSize
.height
);
6000 ::RedrawWindow(mWnd
, &drect
, NULL
,
6003 RDW_NOINTERNALPAINT
|
6008 mBounds
.width
= newWidth
;
6009 mBounds
.height
= newHeight
;
6010 mLastSize
.width
= newWidth
;
6011 mLastSize
.height
= newHeight
;
6013 #ifdef WINSTATE_DEBUG_OUTPUT
6014 printf("*** Resize window: %d x %d x %d x %d\n", wp
->x
, wp
->y
, newWidth
, newHeight
);
6017 // If a maximized window is resized, recalculate the non-client margins and
6018 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
6020 if (mSizeMode
== nsSizeMode_Maximized
) {
6021 if (UpdateNonClientMargins(nsSizeMode_Maximized
, PR_TRUE
)) {
6022 // gecko resize event already sent by UpdateNonClientMargins.
6028 // Recalculate the width and height based on the client area for gecko events.
6029 if (::GetClientRect(mWnd
, &r
)) {
6030 rect
.width
= r
.right
- r
.left
;
6031 rect
.height
= r
.bottom
- r
.top
;
6034 // Send a gecko resize event
6035 result
= OnResize(rect
);
6040 void nsWindow::ActivateOtherWindowHelper(HWND aWnd
)
6042 // Find the next window that is enabled, visible, and not minimized.
6043 HWND hwndBelow
= ::GetNextWindow(aWnd
, GW_HWNDNEXT
);
6044 while (hwndBelow
&& (!::IsWindowEnabled(hwndBelow
) || !::IsWindowVisible(hwndBelow
) ||
6045 ::IsIconic(hwndBelow
))) {
6046 hwndBelow
= ::GetNextWindow(hwndBelow
, GW_HWNDNEXT
);
6049 // Push ourselves to the bottom of the stack, then activate the
6051 ::SetWindowPos(aWnd
, HWND_BOTTOM
, 0, 0, 0, 0,
6052 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
);
6054 ::SetForegroundWindow(hwndBelow
);
6056 // Play the minimize sound while we're here, since that is also
6057 // forgotten when we use SW_SHOWMINIMIZED.
6058 ::PlaySoundW(L
"Minimize", nsnull
, SND_ALIAS
| SND_NODEFAULT
| SND_ASYNC
);
6060 #endif // !defined(WINCE)
6063 void nsWindow::OnWindowPosChanging(LPWINDOWPOS
& info
)
6065 // Update non-client margins if the frame size is changing, and let the
6066 // browser know we are changing size modes, so alternative css can kick in.
6067 // If we're going into fullscreen mode, ignore this, since it'll reset
6068 // margins to normal mode.
6069 if (info
->flags
& SWP_FRAMECHANGED
&& mSizeMode
!= nsSizeMode_Fullscreen
) {
6071 pl
.length
= sizeof(pl
);
6072 ::GetWindowPlacement(mWnd
, &pl
);
6074 if (pl
.showCmd
== SW_SHOWMAXIMIZED
)
6075 sizeMode
= nsSizeMode_Maximized
;
6076 else if (pl
.showCmd
== SW_SHOWMINIMIZED
)
6077 sizeMode
= nsSizeMode_Minimized
;
6078 else if (mFullscreenMode
)
6079 sizeMode
= nsSizeMode_Fullscreen
;
6081 sizeMode
= nsSizeMode_Normal
;
6083 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
6086 event
.mSizeMode
= static_cast<nsSizeMode
>(sizeMode
);
6087 DispatchWindowEvent(&event
);
6089 UpdateNonClientMargins(sizeMode
, PR_FALSE
);
6092 // enforce local z-order rules
6093 if (!(info
->flags
& SWP_NOZORDER
)) {
6094 HWND hwndAfter
= info
->hwndInsertAfter
;
6096 nsZLevelEvent
event(PR_TRUE
, NS_SETZLEVEL
, this);
6097 nsWindow
*aboveWindow
= 0;
6101 if (hwndAfter
== HWND_BOTTOM
)
6102 event
.mPlacement
= nsWindowZBottom
;
6103 else if (hwndAfter
== HWND_TOP
|| hwndAfter
== HWND_TOPMOST
|| hwndAfter
== HWND_NOTOPMOST
)
6104 event
.mPlacement
= nsWindowZTop
;
6106 event
.mPlacement
= nsWindowZRelative
;
6107 aboveWindow
= GetNSWindowPtr(hwndAfter
);
6109 event
.mReqBelow
= aboveWindow
;
6110 event
.mActualBelow
= nsnull
;
6112 event
.mImmediate
= PR_FALSE
;
6113 event
.mAdjusted
= PR_FALSE
;
6114 DispatchWindowEvent(&event
);
6116 if (event
.mAdjusted
) {
6117 if (event
.mPlacement
== nsWindowZBottom
)
6118 info
->hwndInsertAfter
= HWND_BOTTOM
;
6119 else if (event
.mPlacement
== nsWindowZTop
)
6120 info
->hwndInsertAfter
= HWND_TOP
;
6122 info
->hwndInsertAfter
= (HWND
)event
.mActualBelow
->GetNativeData(NS_NATIVE_WINDOW
);
6125 NS_IF_RELEASE(event
.mActualBelow
);
6127 // prevent rude external programs from making hidden window visible
6128 if (mWindowType
== eWindowType_invisible
)
6129 info
->flags
&= ~SWP_SHOWWINDOW
;
6133 void nsWindow::UserActivity()
6135 // Check if we have the idle service, if not we try to get it.
6136 if (!mIdleService
) {
6137 mIdleService
= do_GetService("@mozilla.org/widget/idleservice;1");
6140 // Check that we now have the idle service.
6142 mIdleService
->ResetIdleTimeOut();
6146 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6147 PRBool
nsWindow::OnTouch(WPARAM wParam
, LPARAM lParam
)
6149 PRUint32 cInputs
= LOWORD(wParam
);
6150 PTOUCHINPUT pInputs
= new TOUCHINPUT
[cInputs
];
6152 if (mGesture
.GetTouchInputInfo((HTOUCHINPUT
)lParam
, cInputs
, pInputs
)) {
6153 for (PRUint32 i
= 0; i
< cInputs
; i
++) {
6155 if (pInputs
[i
].dwFlags
& TOUCHEVENTF_MOVE
) {
6156 msg
= NS_MOZTOUCH_MOVE
;
6157 } else if (pInputs
[i
].dwFlags
& TOUCHEVENTF_DOWN
) {
6158 msg
= NS_MOZTOUCH_DOWN
;
6159 } else if (pInputs
[i
].dwFlags
& TOUCHEVENTF_UP
) {
6160 msg
= NS_MOZTOUCH_UP
;
6165 nsPointWin touchPoint
;
6166 touchPoint
.x
= TOUCH_COORD_TO_PIXEL(pInputs
[i
].x
);
6167 touchPoint
.y
= TOUCH_COORD_TO_PIXEL(pInputs
[i
].y
);
6168 touchPoint
.ScreenToClient(mWnd
);
6170 nsMozTouchEvent
touchEvent(PR_TRUE
, msg
, this, pInputs
[i
].dwID
);
6171 touchEvent
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6172 touchEvent
.refPoint
= touchPoint
;
6174 nsEventStatus status
;
6175 DispatchEvent(&touchEvent
, status
);
6180 mGesture
.CloseTouchInputHandle((HTOUCHINPUT
)lParam
);
6185 // Gesture event processing. Handles WM_GESTURE events.
6187 PRBool
nsWindow::OnGesture(WPARAM wParam
, LPARAM lParam
)
6189 // Treatment for pan events which translate into scroll events:
6190 if (mGesture
.IsPanEvent(lParam
)) {
6191 nsMouseScrollEvent
event(PR_TRUE
, NS_MOUSE_PIXEL_SCROLL
, this);
6193 if ( !mGesture
.ProcessPanMessage(mWnd
, wParam
, lParam
) )
6194 return PR_FALSE
; // ignore
6196 nsEventStatus status
;
6198 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6199 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6200 event
.isMeta
= PR_FALSE
;
6201 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6203 event
.time
= ::GetMessageTime();
6204 event
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6206 PRBool endFeedback
= PR_TRUE
;
6208 PRInt32 scrollOverflowX
= 0;
6209 PRInt32 scrollOverflowY
= 0;
6211 if (mGesture
.PanDeltaToPixelScrollX(event
)) {
6212 DispatchEvent(&event
, status
);
6213 scrollOverflowX
= event
.scrollOverflow
;
6216 if (mGesture
.PanDeltaToPixelScrollY(event
)) {
6217 DispatchEvent(&event
, status
);
6218 scrollOverflowY
= event
.scrollOverflow
;
6221 if (mDisplayPanFeedback
) {
6222 mGesture
.UpdatePanFeedbackX(mWnd
, scrollOverflowX
, endFeedback
);
6223 mGesture
.UpdatePanFeedbackY(mWnd
, scrollOverflowY
, endFeedback
);
6224 mGesture
.PanFeedbackFinalize(mWnd
, endFeedback
);
6227 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
6232 // Other gestures translate into simple gesture events:
6233 nsSimpleGestureEvent
event(PR_TRUE
, 0, this, 0, 0.0);
6234 if ( !mGesture
.ProcessGestureMessage(mWnd
, wParam
, lParam
, event
) ) {
6235 return PR_FALSE
; // fall through to DefWndProc
6238 // Polish up and send off the new event
6239 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6240 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6241 event
.isMeta
= PR_FALSE
;
6242 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6244 event
.time
= ::GetMessageTime();
6245 event
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6247 nsEventStatus status
;
6248 DispatchEvent(&event
, status
);
6249 if (status
== nsEventStatus_eIgnore
) {
6250 return PR_FALSE
; // Ignored, fall through
6253 // Only close this if we process and return true.
6254 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
6256 return PR_TRUE
; // Handled
6258 #endif // !defined(WINCE)
6261 PRUint16
nsWindow::GetMouseInputSource()
6263 PRUint16 inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE
;
6264 LPARAM lParamExtraInfo
= ::GetMessageExtraInfo();
6265 if ((lParamExtraInfo
& TABLET_INK_SIGNATURE
) == TABLET_INK_CHECK
) {
6266 inputSource
= (lParamExtraInfo
& TABLET_INK_TOUCH
) ?
6267 PRUint16(nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
) : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN
;
6273 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6274 * within the message case block. If returning true result should be returned
6275 * immediately (no more processing).
6277 PRBool
nsWindow::OnMouseWheel(UINT msg
, WPARAM wParam
, LPARAM lParam
, PRBool
& getWheelInfo
, PRBool
& result
, LRESULT
*aRetValue
)
6279 // Handle both flavors of mouse wheel events.
6280 static int iDeltaPerLine
, iDeltaPerChar
;
6281 static ULONG ulScrollLines
, ulScrollChars
= 1;
6282 static int currentVDelta
, currentHDelta
;
6283 static HWND currentWindow
= 0;
6285 PRBool isVertical
= msg
== WM_MOUSEWHEEL
;
6287 // Get mouse wheel metrics (but only once).
6289 getWheelInfo
= PR_FALSE
;
6291 SystemParametersInfo (SPI_GETWHEELSCROLLLINES
, 0, &ulScrollLines
, 0);
6293 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6294 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6296 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6297 // the mouse driver wants a page scroll. The docs state that
6298 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6299 // since some mouse drivers use an arbitrary large number instead,
6300 // we have to handle that as well.
6303 if (ulScrollLines
) {
6304 if (ulScrollLines
<= WHEEL_DELTA
) {
6305 iDeltaPerLine
= WHEEL_DELTA
/ ulScrollLines
;
6307 ulScrollLines
= WHEEL_PAGESCROLL
;
6311 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS
, 0,
6312 &ulScrollChars
, 0)) {
6313 // Note that we may always fail to get the value before Win Vista.
6318 if (ulScrollChars
) {
6319 if (ulScrollChars
<= WHEEL_DELTA
) {
6320 iDeltaPerChar
= WHEEL_DELTA
/ ulScrollChars
;
6322 ulScrollChars
= WHEEL_PAGESCROLL
;
6327 if ((isVertical
&& ulScrollLines
!= WHEEL_PAGESCROLL
&& !iDeltaPerLine
) ||
6328 (!isVertical
&& ulScrollChars
!= WHEEL_PAGESCROLL
&& !iDeltaPerChar
))
6329 return PR_FALSE
; // break
6331 // The mousewheel event will be dispatched to the toplevel
6332 // window. We need to give it to the child window
6334 if (!HandleScrollingPlugins(msg
, wParam
, lParam
, result
, aRetValue
, quit
))
6335 return quit
; // return immediately if its not our window
6337 // We should cancel the surplus delta if the current window is not
6338 // same as previous.
6339 if (currentWindow
!= mWnd
) {
6342 currentWindow
= mWnd
;
6345 nsMouseScrollEvent
scrollEvent(PR_TRUE
, NS_MOUSE_SCROLL
, this);
6346 scrollEvent
.delta
= 0;
6348 scrollEvent
.scrollFlags
= nsMouseScrollEvent::kIsVertical
;
6349 if (ulScrollLines
== WHEEL_PAGESCROLL
) {
6350 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
6351 scrollEvent
.delta
= (((short) HIWORD (wParam
)) > 0) ? -1 : 1;
6353 currentVDelta
-= (short) HIWORD (wParam
);
6354 if (PR_ABS(currentVDelta
) >= iDeltaPerLine
) {
6355 scrollEvent
.delta
= currentVDelta
/ iDeltaPerLine
;
6356 currentVDelta
%= iDeltaPerLine
;
6360 scrollEvent
.scrollFlags
= nsMouseScrollEvent::kIsHorizontal
;
6361 if (ulScrollChars
== WHEEL_PAGESCROLL
) {
6362 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
6363 scrollEvent
.delta
= (((short) HIWORD (wParam
)) > 0) ? 1 : -1;
6365 currentHDelta
+= (short) HIWORD (wParam
);
6366 if (PR_ABS(currentHDelta
) >= iDeltaPerChar
) {
6367 scrollEvent
.delta
= currentHDelta
/ iDeltaPerChar
;
6368 currentHDelta
%= iDeltaPerChar
;
6373 if (!scrollEvent
.delta
) {
6374 // We store the wheel delta, and it will be used next wheel message, so,
6375 // we consume this message actually. We shouldn't call next wndproc.
6377 return PR_FALSE
; // break
6381 // The event may go to a plug-in which already dispatched this message.
6382 // Then, the event can cause deadlock. We should unlock the sender here.
6383 ::ReplyMessage(isVertical
? 0 : TRUE
);
6386 scrollEvent
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6387 scrollEvent
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6388 scrollEvent
.isMeta
= PR_FALSE
;
6389 scrollEvent
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6390 InitEvent(scrollEvent
);
6391 if (nsnull
!= mEventCallback
) {
6392 result
= DispatchWindowEvent(&scrollEvent
);
6394 // Note that we should return zero if we process WM_MOUSEWHEEL.
6395 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6398 *aRetValue
= isVertical
? 0 : TRUE
;
6400 return PR_FALSE
; // break;
6404 StringCaseInsensitiveEquals(const PRUnichar
* aChars1
, const PRUint32 aNumChars1
,
6405 const PRUnichar
* aChars2
, const PRUint32 aNumChars2
)
6407 if (aNumChars1
!= aNumChars2
)
6410 nsCaseInsensitiveStringComparator comp
;
6411 return comp(aChars1
, aChars2
, aNumChars1
) == 0;
6414 UINT
nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode
)
6417 switch (aNativeKeyCode
) {
6418 case VK_OEM_1
: return NS_VK_SEMICOLON
; // 0xBA, For the US standard keyboard, the ';:' key
6419 case VK_OEM_PLUS
: return NS_VK_ADD
; // 0xBB, For any country/region, the '+' key
6420 case VK_OEM_MINUS
: return NS_VK_SUBTRACT
; // 0xBD, For any country/region, the '-' key
6424 return aNativeKeyCode
;
6428 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6429 * WM_CHAR messages for processing. During testing we don't want to
6430 * mess with the real message queue. Instead we pass a
6431 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6432 * that as if it was in the message queue, and refrain from actually
6433 * looking at or touching the message queue.
6435 LRESULT
nsWindow::OnKeyDown(const MSG
&aMsg
,
6436 nsModifierKeyState
&aModKeyState
,
6437 PRBool
*aEventDispatched
,
6438 nsFakeCharMessage
* aFakeCharMessage
)
6440 UINT virtualKeyCode
= aMsg
.wParam
;
6443 gKbdLayout
.OnKeyDown (virtualKeyCode
);
6446 // Use only DOMKeyCode for XP processing.
6447 // Use aVirtualKeyCode for gKbdLayout and native processing.
6448 UINT DOMKeyCode
= nsIMM32Handler::IsComposingOn(this) ?
6449 virtualKeyCode
: MapFromNativeToDOM(virtualKeyCode
);
6452 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6456 DispatchKeyEvent(NS_KEY_DOWN
, 0, nsnull
, DOMKeyCode
, &aMsg
, aModKeyState
);
6457 if (aEventDispatched
)
6458 *aEventDispatched
= PR_TRUE
;
6460 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6461 // for almost all keys
6462 switch (DOMKeyCode
) {
6466 case NS_VK_CAPS_LOCK
:
6467 case NS_VK_NUM_LOCK
:
6468 case NS_VK_SCROLL_LOCK
: return noDefault
;
6471 PRUint32 extraFlags
= (noDefault
? NS_EVENT_FLAG_NO_DEFAULT
: 0);
6473 BOOL gotMsg
= aFakeCharMessage
||
6474 ::PeekMessageW(&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_NOREMOVE
| PM_NOYIELD
);
6475 // Enter and backspace are always handled here to avoid for example the
6476 // confusion between ctrl-enter and ctrl-J.
6477 if (DOMKeyCode
== NS_VK_RETURN
|| DOMKeyCode
== NS_VK_BACK
||
6478 ((aModKeyState
.mIsControlDown
|| aModKeyState
.mIsAltDown
)
6482 && !gKbdLayout
.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)))
6485 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6486 // They can be more than one because of:
6487 // * Dead-keys not pairing with base character
6488 // * Some keyboard layouts may map up to 4 characters to the single key
6489 PRBool anyCharMessagesRemoved
= PR_FALSE
;
6491 if (aFakeCharMessage
) {
6492 anyCharMessagesRemoved
= PR_TRUE
;
6494 while (gotMsg
&& (msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
))
6496 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6497 ("%s charCode=%d scanCode=%d\n", msg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
6498 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
6499 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST
, WM_KEYLAST
);
6500 anyCharMessagesRemoved
= PR_TRUE
;
6502 gotMsg
= ::PeekMessageW (&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_NOREMOVE
| PM_NOYIELD
);
6506 if (!anyCharMessagesRemoved
&& DOMKeyCode
== NS_VK_BACK
&&
6507 nsIMM32Handler::IsDoingKakuteiUndo(mWnd
)) {
6508 NS_ASSERTION(!aFakeCharMessage
,
6509 "We shouldn't be touching the real msg queue");
6510 RemoveMessageAndDispatchPluginEvent(WM_CHAR
, WM_CHAR
);
6514 (aFakeCharMessage
||
6515 msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
|| msg
.message
== WM_DEADCHAR
)) {
6516 if (aFakeCharMessage
)
6517 return OnCharRaw(aFakeCharMessage
->mCharCode
,
6518 aFakeCharMessage
->mScanCode
, aModKeyState
, extraFlags
);
6520 // If prevent default set for keydown, do same for keypress
6521 ::GetMessageW(&msg
, mWnd
, msg
.message
, msg
.message
);
6523 if (msg
.message
== WM_DEADCHAR
) {
6524 if (!PluginHasFocus())
6527 // We need to send the removed message to focused plug-in.
6528 DispatchPluginEvent(msg
);
6532 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6533 ("%s charCode=%d scanCode=%d\n",
6534 msg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
6535 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
6537 BOOL result
= OnChar(msg
, aModKeyState
, nsnull
, extraFlags
);
6538 // If a syschar keypress wasn't processed, Windows may want to
6539 // handle it to activate a native menu.
6540 if (!result
&& msg
.message
== WM_SYSCHAR
)
6541 ::DefWindowProcW(mWnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
6545 else if (!aModKeyState
.mIsControlDown
&& !aModKeyState
.mIsAltDown
&&
6546 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode
) ||
6547 KeyboardLayout::IsNumpadKey(virtualKeyCode
)))
6549 // If this is simple KeyDown event but next message is not WM_CHAR,
6550 // this event may not input text, so we should ignore this event.
6552 return PluginHasFocus() && noDefault
;
6555 if (gKbdLayout
.IsDeadKey ())
6556 return PluginHasFocus() && noDefault
;
6558 PRUint8 shiftStates
[5];
6559 PRUnichar uniChars
[5];
6560 PRUnichar shiftedChars
[5] = {0, 0, 0, 0, 0};
6561 PRUnichar unshiftedChars
[5] = {0, 0, 0, 0, 0};
6562 PRUnichar shiftedLatinChar
= 0;
6563 PRUnichar unshiftedLatinChar
= 0;
6564 PRUint32 numOfUniChars
= 0;
6565 PRUint32 numOfShiftedChars
= 0;
6566 PRUint32 numOfUnshiftedChars
= 0;
6567 PRUint32 numOfShiftStates
= 0;
6569 switch (virtualKeyCode
) {
6570 // keys to be sent as characters
6571 case VK_ADD
: uniChars
[0] = '+'; numOfUniChars
= 1; break;
6572 case VK_SUBTRACT
: uniChars
[0] = '-'; numOfUniChars
= 1; break;
6573 case VK_DIVIDE
: uniChars
[0] = '/'; numOfUniChars
= 1; break;
6574 case VK_MULTIPLY
: uniChars
[0] = '*'; numOfUniChars
= 1; break;
6585 uniChars
[0] = virtualKeyCode
- VK_NUMPAD0
+ '0';
6589 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)) {
6590 numOfUniChars
= numOfShiftStates
=
6591 gKbdLayout
.GetUniChars(uniChars
, shiftStates
,
6592 NS_ARRAY_LENGTH(uniChars
));
6595 if (aModKeyState
.mIsControlDown
^ aModKeyState
.mIsAltDown
) {
6596 PRUint8 capsLockState
= (::GetKeyState(VK_CAPITAL
) & 1) ? eCapsLock
: 0;
6597 numOfUnshiftedChars
=
6598 gKbdLayout
.GetUniCharsWithShiftState(virtualKeyCode
, capsLockState
,
6599 unshiftedChars
, NS_ARRAY_LENGTH(unshiftedChars
));
6601 gKbdLayout
.GetUniCharsWithShiftState(virtualKeyCode
,
6602 capsLockState
| eShift
,
6603 shiftedChars
, NS_ARRAY_LENGTH(shiftedChars
));
6605 // The current keyboard cannot input alphabets or numerics,
6606 // we should append them for Shortcut/Access keys.
6607 // E.g., for Cyrillic keyboard layout.
6608 if (NS_VK_A
<= DOMKeyCode
&& DOMKeyCode
<= NS_VK_Z
) {
6609 shiftedLatinChar
= unshiftedLatinChar
= DOMKeyCode
;
6611 shiftedLatinChar
+= 0x20;
6613 unshiftedLatinChar
+= 0x20;
6614 if (unshiftedLatinChar
== unshiftedChars
[0] &&
6615 shiftedLatinChar
== shiftedChars
[0]) {
6616 shiftedLatinChar
= unshiftedLatinChar
= 0;
6620 if (NS_VK_0
<= DOMKeyCode
&& DOMKeyCode
<= NS_VK_9
) {
6623 switch (virtualKeyCode
) {
6624 case VK_OEM_PLUS
: ch
= '+'; break;
6625 case VK_OEM_MINUS
: ch
= '-'; break;
6628 if (ch
&& unshiftedChars
[0] != ch
&& shiftedChars
[0] != ch
) {
6629 // Windows has assigned a virtual key code to the key even though
6630 // the character can't be produced with this key. That probably
6631 // means the character can't be produced with any key in the
6632 // current layout and so the assignment is based on a QWERTY
6633 // layout. Append this code so that users can access the shortcut.
6634 unshiftedLatinChar
= ch
;
6638 // If the charCode is not ASCII character, we should replace the
6639 // charCode with ASCII character only when Ctrl is pressed.
6640 // But don't replace the charCode when the charCode is not same as
6641 // unmodified characters. In such case, Ctrl is sometimes used for a
6642 // part of character inputting key combination like Shift.
6643 if (aModKeyState
.mIsControlDown
) {
6644 PRUint8 currentState
= eCtrl
;
6645 if (aModKeyState
.mIsShiftDown
)
6646 currentState
|= eShift
;
6649 aModKeyState
.mIsShiftDown
? shiftedLatinChar
: unshiftedLatinChar
;
6651 (numOfUniChars
== 0 ||
6652 StringCaseInsensitiveEquals(uniChars
, numOfUniChars
,
6653 aModKeyState
.mIsShiftDown
? shiftedChars
: unshiftedChars
,
6654 aModKeyState
.mIsShiftDown
? numOfShiftedChars
:
6655 numOfUnshiftedChars
))) {
6656 numOfUniChars
= numOfShiftStates
= 1;
6658 shiftStates
[0] = currentState
;
6664 if (numOfUniChars
> 0 || numOfShiftedChars
> 0 || numOfUnshiftedChars
> 0) {
6665 PRUint32 num
= PR_MAX(numOfUniChars
,
6666 PR_MAX(numOfShiftedChars
, numOfUnshiftedChars
));
6667 PRUint32 skipUniChars
= num
- numOfUniChars
;
6668 PRUint32 skipShiftedChars
= num
- numOfShiftedChars
;
6669 PRUint32 skipUnshiftedChars
= num
- numOfUnshiftedChars
;
6670 UINT keyCode
= numOfUniChars
== 0 ? DOMKeyCode
: 0;
6671 for (PRUint32 cnt
= 0; cnt
< num
; cnt
++) {
6672 PRUint16 uniChar
, shiftedChar
, unshiftedChar
;
6673 uniChar
= shiftedChar
= unshiftedChar
= 0;
6674 if (skipUniChars
<= cnt
) {
6675 if (cnt
- skipUniChars
< numOfShiftStates
) {
6676 // If key in combination with Alt and/or Ctrl produces a different
6677 // character than without them then do not report these flags
6678 // because it is separate keyboard layout shift state. If dead-key
6679 // and base character does not produce a valid composite character
6680 // then both produced dead-key character and following base
6681 // character may have different modifier flags, too.
6682 aModKeyState
.mIsShiftDown
=
6683 (shiftStates
[cnt
- skipUniChars
] & eShift
) != 0;
6684 aModKeyState
.mIsControlDown
=
6685 (shiftStates
[cnt
- skipUniChars
] & eCtrl
) != 0;
6686 aModKeyState
.mIsAltDown
=
6687 (shiftStates
[cnt
- skipUniChars
] & eAlt
) != 0;
6689 uniChar
= uniChars
[cnt
- skipUniChars
];
6691 if (skipShiftedChars
<= cnt
)
6692 shiftedChar
= shiftedChars
[cnt
- skipShiftedChars
];
6693 if (skipUnshiftedChars
<= cnt
)
6694 unshiftedChar
= unshiftedChars
[cnt
- skipUnshiftedChars
];
6695 nsAutoTArray
<nsAlternativeCharCode
, 5> altArray
;
6697 if (shiftedChar
|| unshiftedChar
) {
6698 nsAlternativeCharCode
chars(unshiftedChar
, shiftedChar
);
6699 altArray
.AppendElement(chars
);
6701 if (cnt
== num
- 1 && (unshiftedLatinChar
|| shiftedLatinChar
)) {
6702 nsAlternativeCharCode
chars(unshiftedLatinChar
, shiftedLatinChar
);
6703 altArray
.AppendElement(chars
);
6706 DispatchKeyEvent(NS_KEY_PRESS
, uniChar
, &altArray
,
6707 keyCode
, nsnull
, aModKeyState
, extraFlags
);
6710 DispatchKeyEvent(NS_KEY_PRESS
, 0, nsnull
, DOMKeyCode
, nsnull
, aModKeyState
,
6715 UINT unichar
= ::MapVirtualKey(virtualKeyCode
, MAPVK_VK_TO_CHAR
);
6716 // Check for dead characters or no mapping
6717 if (unichar
& 0x80) {
6720 DispatchKeyEvent(NS_KEY_PRESS
, unichar
, nsnull
, DOMKeyCode
, nsnull
, aModKeyState
,
6729 LRESULT
nsWindow::OnKeyUp(const MSG
&aMsg
,
6730 nsModifierKeyState
&aModKeyState
,
6731 PRBool
*aEventDispatched
)
6733 UINT virtualKeyCode
= aMsg
.wParam
;
6735 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6736 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode
));
6738 if (!nsIMM32Handler::IsComposingOn(this)) {
6739 virtualKeyCode
= MapFromNativeToDOM(virtualKeyCode
);
6742 if (aEventDispatched
)
6743 *aEventDispatched
= PR_TRUE
;
6744 return DispatchKeyEvent(NS_KEY_UP
, 0, nsnull
, virtualKeyCode
, &aMsg
,
6749 LRESULT
nsWindow::OnChar(const MSG
&aMsg
, nsModifierKeyState
&aModKeyState
,
6750 PRBool
*aEventDispatched
, PRUint32 aFlags
)
6752 return OnCharRaw(aMsg
.wParam
, HIWORD(aMsg
.lParam
) & 0xFF, aModKeyState
,
6753 aFlags
, &aMsg
, aEventDispatched
);
6757 LRESULT
nsWindow::OnCharRaw(UINT charCode
, UINT aScanCode
,
6758 nsModifierKeyState
&aModKeyState
, PRUint32 aFlags
,
6759 const MSG
*aMsg
, PRBool
*aEventDispatched
)
6761 // ignore [shift+]alt+space so the OS can handle it
6762 if (aModKeyState
.mIsAltDown
&& !aModKeyState
.mIsControlDown
&&
6763 IS_VK_DOWN(NS_VK_SPACE
)) {
6767 // Ignore Ctrl+Enter (bug 318235)
6768 if (aModKeyState
.mIsControlDown
&& charCode
== 0xA) {
6772 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
6773 PRBool saveIsAltDown
= aModKeyState
.mIsAltDown
;
6774 PRBool saveIsControlDown
= aModKeyState
.mIsControlDown
;
6775 if (aModKeyState
.mIsAltDown
&& aModKeyState
.mIsControlDown
)
6776 aModKeyState
.mIsAltDown
= aModKeyState
.mIsControlDown
= PR_FALSE
;
6780 if (nsIMM32Handler::IsComposingOn(this)) {
6784 if (aModKeyState
.mIsControlDown
&& charCode
<= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
6785 // need to account for shift here. bug 16486
6786 if (aModKeyState
.mIsShiftDown
)
6787 uniChar
= charCode
- 1 + 'A';
6789 uniChar
= charCode
- 1 + 'a';
6792 else if (aModKeyState
.mIsControlDown
&& charCode
<= 0x1F) {
6793 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
6794 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
6795 // for some reason the keypress handler need to have the uniChar code set
6796 // with the addition of a upper case A not the lower case.
6797 uniChar
= charCode
- 1 + 'A';
6799 } else { // 0x20 - SPACE, 0x3D - EQUALS
6800 if (charCode
< 0x20 || (charCode
== 0x3D && aModKeyState
.mIsControlDown
)) {
6808 // Keep the characters unshifted for shortcuts and accesskeys and make sure
6809 // that numbers are always passed as such (among others: bugs 50255 and 351310)
6810 if (uniChar
&& (aModKeyState
.mIsControlDown
|| aModKeyState
.mIsAltDown
)) {
6811 UINT virtualKeyCode
= ::MapVirtualKeyEx(aScanCode
, MAPVK_VSC_TO_VK
,
6812 gKbdLayout
.GetLayout());
6813 UINT unshiftedCharCode
=
6814 virtualKeyCode
>= '0' && virtualKeyCode
<= '9' ? virtualKeyCode
:
6815 aModKeyState
.mIsShiftDown
? ::MapVirtualKeyEx(virtualKeyCode
,
6817 gKbdLayout
.GetLayout()) : 0;
6818 // ignore diacritics (top bit set) and key mapping errors (char code 0)
6819 if ((INT
)unshiftedCharCode
> 0)
6820 uniChar
= unshiftedCharCode
;
6823 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
6824 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
6826 if (!aModKeyState
.mIsShiftDown
&& (saveIsAltDown
|| saveIsControlDown
)) {
6827 uniChar
= towlower(uniChar
);
6830 PRBool result
= DispatchKeyEvent(NS_KEY_PRESS
, uniChar
, nsnull
,
6831 charCode
, aMsg
, aModKeyState
, aFlags
);
6832 if (aEventDispatched
)
6833 *aEventDispatched
= PR_TRUE
;
6834 aModKeyState
.mIsAltDown
= saveIsAltDown
;
6835 aModKeyState
.mIsControlDown
= saveIsControlDown
;
6840 nsWindow::SetupKeyModifiersSequence(nsTArray
<KeyPair
>* aArray
, PRUint32 aModifiers
)
6842 for (PRUint32 i
= 0; i
< NS_ARRAY_LENGTH(sModifierKeyMap
); ++i
) {
6843 const PRUint32
* map
= sModifierKeyMap
[i
];
6844 if (aModifiers
& map
[0]) {
6845 aArray
->AppendElement(KeyPair(map
[1], map
[2]));
6851 nsWindow::ConfigureChildren(const nsTArray
<Configuration
>& aConfigurations
)
6853 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
6854 // here, if that helps in some situations. So far I haven't seen a
6856 for (PRUint32 i
= 0; i
< aConfigurations
.Length(); ++i
) {
6857 const Configuration
& configuration
= aConfigurations
[i
];
6858 nsWindow
* w
= static_cast<nsWindow
*>(configuration
.mChild
);
6859 NS_ASSERTION(w
->GetParent() == this,
6860 "Configured widget is not a child");
6862 // MSDN says we should do on WinCE this before moving or resizing the window
6863 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
6864 // We put the region back just below, anyway.
6865 ::SetWindowRgn(w
->mWnd
, NULL
, TRUE
);
6867 nsresult rv
= w
->SetWindowClipRegion(configuration
.mClipRegion
, PR_TRUE
);
6868 NS_ENSURE_SUCCESS(rv
, rv
);
6870 w
->GetBounds(bounds
);
6871 if (bounds
.Size() != configuration
.mBounds
.Size()) {
6872 w
->Resize(configuration
.mBounds
.x
, configuration
.mBounds
.y
,
6873 configuration
.mBounds
.width
, configuration
.mBounds
.height
,
6875 } else if (bounds
.TopLeft() != configuration
.mBounds
.TopLeft()) {
6876 w
->Move(configuration
.mBounds
.x
, configuration
.mBounds
.y
);
6878 rv
= w
->SetWindowClipRegion(configuration
.mClipRegion
, PR_FALSE
);
6879 NS_ENSURE_SUCCESS(rv
, rv
);
6885 CreateHRGNFromArray(const nsTArray
<nsIntRect
>& aRects
)
6887 PRInt32 size
= sizeof(RGNDATAHEADER
) + sizeof(RECT
)*aRects
.Length();
6888 nsAutoTArray
<PRUint8
,100> buf
;
6889 if (!buf
.SetLength(size
))
6891 RGNDATA
* data
= reinterpret_cast<RGNDATA
*>(buf
.Elements());
6892 RECT
* rects
= reinterpret_cast<RECT
*>(data
->Buffer
);
6893 data
->rdh
.dwSize
= sizeof(data
->rdh
);
6894 data
->rdh
.iType
= RDH_RECTANGLES
;
6895 data
->rdh
.nCount
= aRects
.Length();
6897 for (PRUint32 i
= 0; i
< aRects
.Length(); ++i
) {
6898 const nsIntRect
& r
= aRects
[i
];
6899 bounds
.UnionRect(bounds
, r
);
6900 ::SetRect(&rects
[i
], r
.x
, r
.y
, r
.XMost(), r
.YMost());
6902 ::SetRect(&data
->rdh
.rcBound
, bounds
.x
, bounds
.y
, bounds
.XMost(), bounds
.YMost());
6903 return ::ExtCreateRegion(NULL
, buf
.Length(), data
);
6907 nsWindow::SetWindowClipRegion(const nsTArray
<nsIntRect
>& aRects
,
6908 PRBool aIntersectWithExisting
)
6910 if (!aIntersectWithExisting
) {
6911 if (!StoreWindowClipRegion(aRects
))
6914 // In this case still early return if nothing changed.
6915 if (mClipRects
&& mClipRectCount
== aRects
.Length() &&
6918 sizeof(nsIntRect
)*mClipRectCount
) == 0) {
6923 HRGN dest
= CreateHRGNFromArray(aRects
);
6925 return NS_ERROR_OUT_OF_MEMORY
;
6927 if (aIntersectWithExisting
) {
6928 HRGN current
= ::CreateRectRgn(0, 0, 0, 0);
6930 if (::GetWindowRgn(mWnd
, current
) != 0 /*ERROR*/) {
6931 ::CombineRgn(dest
, dest
, current
, RGN_AND
);
6933 ::DeleteObject(current
);
6937 if (!::SetWindowRgn(mWnd
, dest
, TRUE
)) {
6938 ::DeleteObject(dest
);
6939 return NS_ERROR_FAILURE
;
6944 // WM_DESTROY event handler
6945 void nsWindow::OnDestroy()
6947 mOnDestroyCalled
= PR_TRUE
;
6949 // Make sure we don't get destroyed in the process of tearing down.
6950 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
6952 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
6954 DispatchStandardEvent(NS_DESTROY
);
6956 // Prevent the widget from sending additional events.
6957 mEventCallback
= nsnull
;
6959 // Free our subclass and clear |this| stored in the window props. We will no longer
6960 // receive events from Windows after this point.
6961 SubclassWindow(FALSE
);
6963 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
6964 // cleared. (It's used in tracking windows for mouse events.)
6965 if (sCurrentWindow
== this)
6966 sCurrentWindow
= nsnull
;
6968 // Disconnects us from our parent, will call our GetParent().
6969 nsBaseWidget::Destroy();
6971 // Release references to children, device context, toolkit, and app shell.
6972 nsBaseWidget::OnDestroy();
6974 // Clear our native parent handle.
6975 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
6976 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
6977 //SetParent(nsnull);
6980 // We have to destroy the native drag target before we null out our window pointer.
6981 EnableDragDrop(PR_FALSE
);
6983 // If we're going away and for some reason we're still the rollup widget, rollup and
6984 // turn off capture.
6985 if ( this == sRollupWidget
) {
6986 if ( sRollupListener
)
6987 sRollupListener
->Rollup(nsnull
, nsnull
);
6988 CaptureRollupEvents(nsnull
, nsnull
, PR_FALSE
, PR_TRUE
);
6991 // If IME is disabled, restore it.
6993 mOldIMC
= ::ImmAssociateContext(mWnd
, mOldIMC
);
6994 NS_ASSERTION(!mOldIMC
, "Another IMC was associated");
6997 // Turn off mouse trails if enabled.
6998 MouseTrailer
* mtrailer
= nsToolkit::gMouseTrailer
;
7000 if (mtrailer
->GetMouseTrailerWindow() == mWnd
)
7001 mtrailer
->DestroyTimer();
7003 if (mtrailer
->GetCaptureWindow() == mWnd
)
7004 mtrailer
->SetCaptureWindow(nsnull
);
7007 // Free GDI window class objects
7009 VERIFY(::DeleteObject(mBrush
));
7013 // Free app icon resources.
7015 icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_BIG
, (LPARAM
) 0);
7017 ::DestroyIcon(icon
);
7019 icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_SMALL
, (LPARAM
) 0);
7021 ::DestroyIcon(icon
);
7023 // Destroy any custom cursor resources.
7025 SetCursor(eCursor_standard
);
7028 // Reset transparency
7029 if (eTransparencyTransparent
== mTransparencyMode
)
7030 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque
);
7033 #if defined(WINCE_HAVE_SOFTKB)
7034 // Revert the changes made for the software keyboard settings
7035 nsWindowCE::ResetSoftKB(mWnd
);
7039 // Finalize panning feedback to possibly restore window displacement
7040 mGesture
.PanFeedbackFinalize(mWnd
, PR_TRUE
);
7043 // Clear the main HWND.
7048 PRBool
nsWindow::OnMove(PRInt32 aX
, PRInt32 aY
)
7053 nsGUIEvent
event(PR_TRUE
, NS_MOVE
, this);
7055 event
.refPoint
.x
= aX
;
7056 event
.refPoint
.y
= aY
;
7058 return DispatchWindowEvent(&event
);
7061 // Send a resize message to the listener
7062 PRBool
nsWindow::OnResize(nsIntRect
&aWindowRect
)
7064 #ifdef CAIRO_HAS_D2D_SURFACE
7065 if (mD2DWindowSurface
) {
7066 mD2DWindowSurface
= NULL
;
7067 Invalidate(PR_FALSE
);
7071 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7072 UpdateCaptionButtonsClippingRect();
7075 // call the event callback
7076 if (mEventCallback
) {
7077 nsSizeEvent
event(PR_TRUE
, NS_SIZE
, this);
7079 event
.windowSize
= &aWindowRect
;
7081 if (::GetWindowRect(mWnd
, &r
)) {
7082 event
.mWinWidth
= PRInt32(r
.right
- r
.left
);
7083 event
.mWinHeight
= PRInt32(r
.bottom
- r
.top
);
7085 event
.mWinWidth
= 0;
7086 event
.mWinHeight
= 0;
7090 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7091 aWindowRect
.x
, aWindowRect
.y
, aWindowRect
.width
, aWindowRect
.height
,
7092 event
.mWinWidth
, event
.mWinHeight
);
7095 return DispatchWindowEvent(&event
);
7101 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7102 PRBool
nsWindow::OnHotKey(WPARAM wParam
, LPARAM lParam
)
7106 #endif // !defined(WINCE)
7108 void nsWindow::OnSettingsChange(WPARAM wParam
, LPARAM lParam
)
7110 if (mWindowType
== eWindowType_dialog
||
7111 mWindowType
== eWindowType_toplevel
)
7112 nsWindowGfx::OnSettingsChangeGfx(wParam
);
7115 static PRBool
IsOurProcessWindow(HWND aHWND
)
7117 DWORD processId
= 0;
7118 ::GetWindowThreadProcessId(aHWND
, &processId
);
7119 return processId
== ::GetCurrentProcessId();
7122 static HWND
FindOurProcessWindow(HWND aHWND
)
7124 for (HWND wnd
= ::GetParent(aHWND
); wnd
; wnd
= ::GetParent(wnd
)) {
7125 if (IsOurProcessWindow(wnd
)) {
7132 // Scrolling helper function for handling plugins.
7133 // Return value indicates whether the calling function should handle this
7134 // aHandled indicates whether this was handled at all
7135 // aQuitProcessing tells whether or not to continue processing the message
7136 PRBool
nsWindow::HandleScrollingPlugins(UINT aMsg
, WPARAM aWParam
,
7137 LPARAM aLParam
, PRBool
& aHandled
,
7139 PRBool
& aQuitProcessing
)
7141 // The scroll event will be dispatched to the toplevel
7142 // window. We need to give it to the child window
7143 aQuitProcessing
= PR_FALSE
; // default is to not stop processing
7145 DWORD dwPoints
= ::GetMessagePos();
7146 point
.x
= GET_X_LPARAM(dwPoints
);
7147 point
.y
= GET_Y_LPARAM(dwPoints
);
7149 static PRBool sIsProcessing
= PR_FALSE
;
7150 if (sIsProcessing
) {
7151 return PR_TRUE
; // the caller should handle this.
7154 static PRBool sMayBeUsingLogitechMouse
= PR_FALSE
;
7155 if (aMsg
== WM_MOUSEHWHEEL
) {
7156 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7157 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7158 // message at first time, this time, ::GetMessagePos works fine.
7159 // Then, we will return 0 (0 means we process it) to the message. Then, the
7160 // driver will POST the same messages continuously during the wheel tilted.
7161 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7162 // cursor isn't 0,0. Therefore, we cannot trust the result of
7163 // ::GetMessagePos API if the sender is the driver.
7164 if (!sMayBeUsingLogitechMouse
&& aLParam
== 0 && (DWORD
)aLParam
!= dwPoints
&&
7165 ::InSendMessage()) {
7166 sMayBeUsingLogitechMouse
= PR_TRUE
;
7167 } else if (sMayBeUsingLogitechMouse
&& aLParam
!= 0 && ::InSendMessage()) {
7168 // The user has changed the mouse from Logitech's to another one (e.g.,
7169 // the user has changed to the touchpad of the notebook.
7170 sMayBeUsingLogitechMouse
= PR_FALSE
;
7172 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7173 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7175 if (sMayBeUsingLogitechMouse
&& aLParam
== 0 && dwPoints
== 0) {
7176 ::GetCursorPos(&point
);
7180 HWND destWnd
= ::WindowFromPoint(point
);
7181 // Since we receive scroll events for as long as
7182 // we are focused, it's entirely possible that there
7183 // is another app's window or no window under the
7187 // No window is under the pointer
7188 return PR_FALSE
; // break, but continue processing
7191 nsWindow
* destWindow
;
7193 // We don't handle the message if the found window belongs to another
7194 // process's top window. If it belongs window, that is a plug-in's window.
7195 // Then, we need to send the message to the plug-in window.
7196 if (!IsOurProcessWindow(destWnd
)) {
7197 HWND ourPluginWnd
= FindOurProcessWindow(destWnd
);
7198 if (!ourPluginWnd
) {
7199 // Somebody elses window
7200 return PR_FALSE
; // break, but continue processing
7202 destWindow
= GetNSWindowPtr(ourPluginWnd
);
7204 destWindow
= GetNSWindowPtr(destWnd
);
7207 if (destWindow
== this && mWindowType
== eWindowType_plugin
) {
7208 // If this is plug-in window, the message came from the plug-in window.
7209 // Then, the message should be processed on the parent window.
7210 destWindow
= static_cast<nsWindow
*>(GetParent());
7211 NS_ENSURE_TRUE(destWindow
, PR_FALSE
); // break, but continue processing
7212 destWnd
= destWindow
->mWnd
;
7213 NS_ENSURE_TRUE(destWnd
, PR_FALSE
); // break, but continue processing
7216 if (!destWindow
|| destWindow
->mWindowType
== eWindowType_plugin
) {
7217 // Some other app, or a plugin window.
7218 // Windows directs scrolling messages to the focused window.
7219 // However, Mozilla does not like plugins having focus, so a
7220 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7221 // Therefore, plugins etc _should_ get first grab at the
7222 // message, but this focus vaguary means the plugin misses
7223 // out. If the window is a child of ours, forward it on.
7224 // Determine if a child by walking the parent list until
7225 // we find a parent matching our wndproc.
7226 HWND parentWnd
= ::GetParent(destWnd
);
7228 nsWindow
* parentWindow
= GetNSWindowPtr(parentWnd
);
7230 // We have a child window - quite possibly a plugin window.
7231 // However, not all plugins are created equal - some will handle this
7232 // message themselves, some will forward directly back to us, while
7233 // others will call DefWndProc, which itself still forwards back to us.
7234 // So if we have sent it once, we need to handle it ourself.
7237 // XXX The message shouldn't come from the plugin window at here.
7238 // But the message might come from it due to some bugs. If it happens,
7239 // SendMessage causes deadlock. For safety, we should unlock the
7241 ::ReplyMessage(aMsg
== WM_MOUSEHWHEEL
? TRUE
: 0);
7244 // First time we have seen this message.
7245 // Call the child - either it will consume it, or
7246 // it will wind it's way back to us,triggering the destWnd case above
7247 // either way,when the call returns,we are all done with the message,
7248 sIsProcessing
= PR_TRUE
;
7249 ::SendMessageW(destWnd
, aMsg
, aWParam
, aLParam
);
7250 sIsProcessing
= PR_FALSE
;
7252 aQuitProcessing
= PR_TRUE
;
7253 return PR_FALSE
; // break, and stop processing
7255 parentWnd
= ::GetParent(parentWnd
);
7256 } // while parentWnd
7258 if (destWnd
== nsnull
)
7260 if (destWnd
!= mWnd
) {
7262 sIsProcessing
= PR_TRUE
;
7263 aHandled
= destWindow
->ProcessMessage(aMsg
, aWParam
, aLParam
, aRetValue
);
7264 sIsProcessing
= PR_FALSE
;
7265 aQuitProcessing
= PR_TRUE
;
7266 return PR_FALSE
; // break, and stop processing
7270 printf("WARNING: couldn't get child window for SCROLL event\n");
7273 return PR_TRUE
; // caller should handle this
7276 PRBool
nsWindow::OnScroll(UINT aMsg
, WPARAM aWParam
, LPARAM aLParam
)
7278 static PRInt8 sMouseWheelEmulation
= -1;
7279 if (sMouseWheelEmulation
< 0) {
7280 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
7281 NS_ENSURE_TRUE(prefs
, PR_FALSE
);
7282 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
7283 prefs
->GetBranch(0, getter_AddRefs(prefBranch
));
7284 NS_ENSURE_TRUE(prefBranch
, PR_FALSE
);
7287 prefBranch
->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate
);
7288 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7289 sMouseWheelEmulation
= PRInt8(emulate
);
7292 if (aLParam
|| sMouseWheelEmulation
) {
7293 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7294 // Treat as a mousewheel message and scroll appropriately
7295 PRBool quit
, result
;
7298 if (!HandleScrollingPlugins(aMsg
, aWParam
, aLParam
, result
, &retVal
, quit
))
7299 return quit
; // Return if it's not our message or has been dispatched
7301 nsMouseScrollEvent
scrollevent(PR_TRUE
, NS_MOUSE_SCROLL
, this);
7302 scrollevent
.scrollFlags
= (aMsg
== WM_VSCROLL
)
7303 ? nsMouseScrollEvent::kIsVertical
7304 : nsMouseScrollEvent::kIsHorizontal
;
7305 switch (LOWORD(aWParam
))
7308 scrollevent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
7310 scrollevent
.delta
= 1;
7313 scrollevent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
7315 scrollevent
.delta
= -1;
7321 // The event may go to a plug-in which already dispatched this message.
7322 // Then, the event can cause deadlock. We should unlock the sender here.
7325 scrollevent
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
7326 scrollevent
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
7327 scrollevent
.isMeta
= PR_FALSE
;
7328 scrollevent
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
7329 InitEvent(scrollevent
);
7330 if (nsnull
!= mEventCallback
)
7332 DispatchWindowEvent(&scrollevent
);
7337 // Scroll message generated by external application
7338 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_SCROLL
, this);
7340 command
.mScroll
.mIsHorizontal
= (aMsg
== WM_HSCROLL
);
7342 switch (LOWORD(aWParam
))
7344 case SB_LINEUP
: // SB_LINELEFT
7345 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Line
;
7346 command
.mScroll
.mAmount
= -1;
7348 case SB_LINEDOWN
: // SB_LINERIGHT
7349 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Line
;
7350 command
.mScroll
.mAmount
= 1;
7352 case SB_PAGEUP
: // SB_PAGELEFT
7353 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Page
;
7354 command
.mScroll
.mAmount
= -1;
7356 case SB_PAGEDOWN
: // SB_PAGERIGHT
7357 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Page
;
7358 command
.mScroll
.mAmount
= 1;
7360 case SB_TOP
: // SB_LEFT
7361 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Whole
;
7362 command
.mScroll
.mAmount
= -1;
7364 case SB_BOTTOM
: // SB_RIGHT
7365 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Whole
;
7366 command
.mScroll
.mAmount
= 1;
7371 DispatchWindowEvent(&command
);
7375 // Can be overriden. Controls auto-erase of background.
7376 PRBool
nsWindow::AutoErase(HDC dc
)
7381 /**************************************************************
7382 **************************************************************
7384 ** BLOCK: IME management and accessibility
7386 ** Handles managing IME input and accessibility.
7388 **************************************************************
7389 **************************************************************/
7391 NS_IMETHODIMP
nsWindow::ResetInputState()
7393 #ifdef DEBUG_KBSTATE
7394 printf("ResetInputState\n");
7397 #ifdef NS_ENABLE_TSF
7398 nsTextStore::CommitComposition(PR_FALSE
);
7399 #endif //NS_ENABLE_TSF
7401 nsIMM32Handler::CommitComposition(this);
7405 NS_IMETHODIMP
nsWindow::SetIMEOpenState(PRBool aState
)
7407 #ifdef DEBUG_KBSTATE
7408 printf("SetIMEOpenState %s\n", (aState
? "Open" : "Close"));
7411 #ifdef NS_ENABLE_TSF
7412 nsTextStore::SetIMEOpenState(aState
);
7413 #endif //NS_ENABLE_TSF
7415 nsIMEContext
IMEContext(mWnd
);
7416 if (IMEContext
.IsValid()) {
7417 ::ImmSetOpenStatus(IMEContext
.get(), aState
? TRUE
: FALSE
);
7422 NS_IMETHODIMP
nsWindow::GetIMEOpenState(PRBool
* aState
)
7424 nsIMEContext
IMEContext(mWnd
);
7425 if (IMEContext
.IsValid()) {
7426 BOOL isOpen
= ::ImmGetOpenStatus(IMEContext
.get());
7427 *aState
= isOpen
? PR_TRUE
: PR_FALSE
;
7431 #ifdef NS_ENABLE_TSF
7432 *aState
|= nsTextStore::GetIMEOpenState();
7433 #endif //NS_ENABLE_TSF
7438 NS_IMETHODIMP
nsWindow::SetIMEEnabled(PRUint32 aState
)
7440 #ifdef NS_ENABLE_TSF
7441 nsTextStore::SetIMEEnabled(aState
);
7442 #endif //NS_ENABLE_TSF
7443 #ifdef DEBUG_KBSTATE
7444 printf("SetIMEEnabled: %s\n", (aState
== nsIWidget::IME_STATUS_ENABLED
||
7445 aState
== nsIWidget::IME_STATUS_PLUGIN
)?
7446 "Enabled": "Disabled");
7448 if (nsIMM32Handler::IsComposing()) {
7451 mIMEEnabled
= aState
;
7452 PRBool enable
= (aState
== nsIWidget::IME_STATUS_ENABLED
||
7453 aState
== nsIWidget::IME_STATUS_PLUGIN
);
7455 #if defined(WINCE_HAVE_SOFTKB)
7456 sSoftKeyboardState
= (aState
!= nsIWidget::IME_STATUS_DISABLED
);
7457 nsWindowCE::ToggleSoftKB(mWnd
, sSoftKeyboardState
);
7460 if (!enable
!= !mOldIMC
)
7462 mOldIMC
= ::ImmAssociateContext(mWnd
, enable
? mOldIMC
: NULL
);
7463 NS_ASSERTION(!enable
|| !mOldIMC
, "Another IMC was associated");
7468 NS_IMETHODIMP
nsWindow::GetIMEEnabled(PRUint32
* aState
)
7470 #ifdef DEBUG_KBSTATE
7471 printf("GetIMEEnabled: %s\n", mIMEEnabled
? "Enabled": "Disabled");
7473 *aState
= mIMEEnabled
;
7477 NS_IMETHODIMP
nsWindow::CancelIMEComposition()
7479 #ifdef DEBUG_KBSTATE
7480 printf("CancelIMEComposition\n");
7483 #ifdef NS_ENABLE_TSF
7484 nsTextStore::CommitComposition(PR_TRUE
);
7485 #endif //NS_ENABLE_TSF
7487 nsIMM32Handler::CancelComposition(this);
7492 nsWindow::GetToggledKeyState(PRUint32 aKeyCode
, PRBool
* aLEDState
)
7494 #ifdef DEBUG_KBSTATE
7495 printf("GetToggledKeyState\n");
7497 NS_ENSURE_ARG_POINTER(aLEDState
);
7498 *aLEDState
= (::GetKeyState(aKeyCode
) & 1) != 0;
7502 #ifdef NS_ENABLE_TSF
7504 nsWindow::OnIMEFocusChange(PRBool aFocus
)
7506 nsresult rv
= nsTextStore::OnFocusChange(aFocus
, this, mIMEEnabled
);
7507 if (rv
== NS_ERROR_NOT_AVAILABLE
)
7508 rv
= NS_ERROR_NOT_IMPLEMENTED
; // TSF is not enabled, maybe.
7513 nsWindow::OnIMETextChange(PRUint32 aStart
,
7517 return nsTextStore::OnTextChange(aStart
, aOldEnd
, aNewEnd
);
7521 nsWindow::OnIMESelectionChange(void)
7523 return nsTextStore::OnSelectionChange();
7525 #endif //NS_ENABLE_TSF
7527 #ifdef ACCESSIBILITY
7529 #ifdef DEBUG_WMGETOBJECT
7530 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
7531 nsAccessible* acc = aWnd ? \
7532 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
7533 printf(" acc: %p", acc); \
7535 nsAutoString name; \
7536 acc->GetName(name); \
7537 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
7538 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
7539 void *hwnd = nsnull; \
7540 doc->GetWindowHandle(&hwnd); \
7541 printf(", acc hwnd: %d", hwnd); \
7544 #define NS_LOG_WMGETOBJECT_THISWND \
7546 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
7547 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p, content type: %d,\n",\
7548 mWnd, ::GetParent(mWnd), this, mContentType); \
7549 NS_LOG_WMGETOBJECT_WNDACC(this) \
7553 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
7555 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
7556 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7557 aHwnd, ::GetParent(aHwnd), wnd); \
7558 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
7562 #define NS_LOG_WMGETOBJECT_THISWND
7563 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
7564 #endif // DEBUG_WMGETOBJECT
7567 nsWindow::GetRootAccessible()
7569 // We want the ability to forcibly disable a11y on windows, because
7570 // some non-a11y-related components attempt to bring it up. See bug
7571 // 538530 for details; we have a pref here that allows it to be disabled
7572 // for performance and testing resons.
7574 // This pref is checked only once, and the browser needs a restart to
7575 // pick up any changes.
7576 static int accForceDisable
= -1;
7578 if (accForceDisable
== -1) {
7579 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
7580 PRBool b
= PR_FALSE
;
7581 nsresult rv
= prefs
->GetBoolPref("accessibility.win32.force_disabled", &b
);
7582 if (NS_SUCCEEDED(rv
) && b
) {
7583 accForceDisable
= 1;
7585 accForceDisable
= 0;
7589 // If the pref was true, return null here, disabling a11y.
7590 if (accForceDisable
)
7593 nsWindow::sIsAccessibilityOn
= TRUE
;
7595 if (mInDtor
|| mOnDestroyCalled
|| mWindowType
== eWindowType_invisible
) {
7599 NS_LOG_WMGETOBJECT_THISWND
7601 if (mContentType
!= eContentTypeInherit
) {
7602 // We're on a MozillaContentWindowClass or MozillaUIWindowClass window.
7603 // Search for the correct visible child window to get an accessible
7604 // document from. Make sure to use an active child window. If this window
7605 // doesn't have child windows then return an accessible for it.
7606 HWND accessibleWnd
= ::GetTopWindow(mWnd
);
7607 NS_LOG_WMGETOBJECT_WND("Top Window", accessibleWnd
);
7608 if (!accessibleWnd
) {
7609 NS_LOG_WMGETOBJECT_WND("This Window", mWnd
);
7610 return DispatchAccessibleEvent(NS_GETACCESSIBLE
);
7613 nsWindow
* accessibleWindow
= nsnull
;
7614 while (accessibleWnd
) {
7615 // Loop through windows and find the first one with accessibility info
7616 accessibleWindow
= GetNSWindowPtr(accessibleWnd
);
7617 if (accessibleWindow
) {
7618 nsAccessible
*rootAccessible
=
7619 accessibleWindow
->DispatchAccessibleEvent(NS_GETACCESSIBLE
);
7620 if (rootAccessible
) {
7621 // Success, one of the child windows was active.
7622 return rootAccessible
;
7625 accessibleWnd
= ::GetNextWindow(accessibleWnd
, GW_HWNDNEXT
);
7626 NS_LOG_WMGETOBJECT_WND("Next Window", accessibleWnd
);
7631 NS_LOG_WMGETOBJECT_WND("This Window", mWnd
);
7632 return DispatchAccessibleEvent(NS_GETACCESSIBLE
);
7635 STDMETHODIMP_(LRESULT
)
7636 nsWindow::LresultFromObject(REFIID riid
, WPARAM wParam
, LPUNKNOWN pAcc
)
7638 // open the dll dynamically
7640 sAccLib
=::LoadLibraryW(L
"OLEACC.DLL");
7643 if (!sLresultFromObject
)
7644 sLresultFromObject
= (LPFNLRESULTFROMOBJECT
)GetProcAddress(sAccLib
,"LresultFromObject");
7646 if (sLresultFromObject
)
7647 return sLresultFromObject(riid
,wParam
,pAcc
);
7654 /**************************************************************
7655 **************************************************************
7657 ** BLOCK: Transparency
7659 ** Window transparency helpers.
7661 **************************************************************
7662 **************************************************************/
7666 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth
, PRInt32 aNewHeight
, PRBool force
)
7668 if (!force
&& aNewWidth
== mBounds
.width
&& aNewHeight
== mBounds
.height
)
7671 #ifdef CAIRO_HAS_D2D_SURFACE
7672 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7673 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7674 nsRefPtr
<gfxD2DSurface
> newSurface
=
7675 new gfxD2DSurface(gfxIntSize(aNewWidth
, aNewHeight
), gfxASurface::ImageFormatARGB32
);
7676 mTransparentSurface
= newSurface
;
7681 nsRefPtr
<gfxWindowsSurface
> newSurface
=
7682 new gfxWindowsSurface(gfxIntSize(aNewWidth
, aNewHeight
), gfxASurface::ImageFormatARGB32
);
7683 mTransparentSurface
= newSurface
;
7684 mMemoryDC
= newSurface
->GetDC();
7688 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode
)
7692 if (aMode
== mTransparencyMode
)
7695 // stop on dialogs and popups!
7696 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
7697 nsWindow
* parent
= GetNSWindowPtr(hWnd
);
7701 NS_WARNING("Trying to use transparent chrome in an embedded context");
7705 if (parent
!= this) {
7706 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
7709 if (aMode
== eTransparencyTransparent
) {
7710 // If we're switching to the use of a transparent window, hide the chrome
7712 HideWindowChrome(PR_TRUE
);
7713 } else if (mHideChrome
&& mTransparencyMode
== eTransparencyTransparent
) {
7714 // if we're switching out of transparent, re-enable our parent's chrome.
7715 HideWindowChrome(PR_FALSE
);
7718 LONG_PTR style
= ::GetWindowLongPtrW(hWnd
, GWL_STYLE
),
7719 exStyle
= ::GetWindowLongPtr(hWnd
, GWL_EXSTYLE
);
7721 if (parent
->mIsVisible
)
7722 style
|= WS_VISIBLE
;
7723 if (parent
->mSizeMode
== nsSizeMode_Maximized
)
7724 style
|= WS_MAXIMIZE
;
7725 else if (parent
->mSizeMode
== nsSizeMode_Minimized
)
7726 style
|= WS_MINIMIZE
;
7728 if (aMode
== eTransparencyTransparent
)
7729 exStyle
|= WS_EX_LAYERED
;
7731 exStyle
&= ~WS_EX_LAYERED
;
7733 VERIFY_WINDOW_STYLE(style
);
7734 ::SetWindowLongPtrW(hWnd
, GWL_STYLE
, style
);
7735 ::SetWindowLongPtrW(hWnd
, GWL_EXSTYLE
, exStyle
);
7737 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7739 memset(&mGlassMargins
, 0, sizeof mGlassMargins
);
7740 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7741 mTransparencyMode
= aMode
;
7743 SetupTranslucentWindowMemoryBitmap(aMode
);
7745 #endif // #ifndef WINCE
7748 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode
)
7750 if (eTransparencyTransparent
== aMode
) {
7751 ResizeTranslucentWindow(mBounds
.width
, mBounds
.height
, PR_TRUE
);
7753 mTransparentSurface
= nsnull
;
7758 nsresult
nsWindow::UpdateTranslucentWindow()
7761 if (mBounds
.IsEmpty())
7766 BLENDFUNCTION bf
= { AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
7767 SIZE winSize
= { mBounds
.width
, mBounds
.height
};
7768 POINT srcPos
= { 0, 0 };
7769 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
7771 ::GetWindowRect(hWnd
, &winRect
);
7773 #ifdef CAIRO_HAS_D2D_SURFACE
7774 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7775 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7776 mMemoryDC
= static_cast<gfxD2DSurface
*>(mTransparentSurface
.get())->
7780 // perform the alpha blend
7781 PRBool updateSuccesful
=
7782 ::UpdateLayeredWindow(hWnd
, NULL
, (POINT
*)&winRect
, &winSize
, mMemoryDC
, &srcPos
, 0, &bf
, ULW_ALPHA
);
7784 #ifdef CAIRO_HAS_D2D_SURFACE
7785 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7786 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7787 nsIntRect
r(0, 0, 0, 0);
7788 static_cast<gfxD2DSurface
*>(mTransparentSurface
.get())->ReleaseDC(&r
);
7792 if (!updateSuccesful
) {
7793 return NS_ERROR_FAILURE
;
7802 /**************************************************************
7803 **************************************************************
7805 ** BLOCK: Popup rollup hooks
7807 ** Deals with CaptureRollup on popup windows.
7809 **************************************************************
7810 **************************************************************/
7813 // Schedules a timer for a window, so we can rollup after processing the hook event
7814 void nsWindow::ScheduleHookTimer(HWND aWnd
, UINT aMsgId
)
7816 // In some cases multiple hooks may be scheduled
7817 // so ignore any other requests once one timer is scheduled
7818 if (sHookTimerId
== 0) {
7819 // Remember the window handle and the message ID to be used later
7820 sRollupMsgId
= aMsgId
;
7821 sRollupMsgWnd
= aWnd
;
7822 // Schedule native timer for doing the rollup after
7823 // this event is done being processed
7824 sHookTimerId
= ::SetTimer(NULL
, 0, 0, (TIMERPROC
)HookTimerForPopups
);
7825 NS_ASSERTION(sHookTimerId
, "Timer couldn't be created.");
7829 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7830 int gLastMsgCode
= 0;
7831 extern MSGFEventMsgInfo gMSGFEvents
[];
7834 // Process Menu messages, rollup when popup is clicked.
7835 LRESULT CALLBACK
nsWindow::MozSpecialMsgFilter(int code
, WPARAM wParam
, LPARAM lParam
)
7837 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7839 MSG
* pMsg
= (MSG
*)lParam
;
7842 while (gMSGFEvents
[inx
].mId
!= code
&& gMSGFEvents
[inx
].mStr
!= NULL
) {
7845 if (code
!= gLastMsgCode
) {
7846 if (gMSGFEvents
[inx
].mId
== code
) {
7848 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code
, gMSGFEvents
[inx
].mStr
, pMsg
->hwnd
);
7852 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code
, gMSGFEvents
[inx
].mId
, pMsg
->hwnd
);
7855 gLastMsgCode
= code
;
7857 PrintEvent(pMsg
->message
, FALSE
, FALSE
);
7859 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7861 if (sProcessHook
&& code
== MSGF_MENU
) {
7862 MSG
* pMsg
= (MSG
*)lParam
;
7863 ScheduleHookTimer( pMsg
->hwnd
, pMsg
->message
);
7866 return ::CallNextHookEx(sMsgFilterHook
, code
, wParam
, lParam
);
7869 // Process all mouse messages. Roll up when a click is in a native window
7870 // that doesn't have an nsIWidget.
7871 LRESULT CALLBACK
nsWindow::MozSpecialMouseProc(int code
, WPARAM wParam
, LPARAM lParam
)
7875 case WM_LBUTTONDOWN
:
7876 case WM_RBUTTONDOWN
:
7877 case WM_MBUTTONDOWN
:
7879 case WM_MOUSEHWHEEL
:
7881 MOUSEHOOKSTRUCT
* ms
= (MOUSEHOOKSTRUCT
*)lParam
;
7882 nsIWidget
* mozWin
= (nsIWidget
*)GetNSWindowPtr(ms
->hwnd
);
7884 // If this window is windowed plugin window, the mouse events are not
7886 if (static_cast<nsWindow
*>(mozWin
)->mWindowType
== eWindowType_plugin
)
7887 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
7889 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
7895 return ::CallNextHookEx(sCallMouseHook
, code
, wParam
, lParam
);
7898 // Process all messages. Roll up when the window is moving, or
7899 // is resizing or when maximized or mininized.
7900 LRESULT CALLBACK
nsWindow::MozSpecialWndProc(int code
, WPARAM wParam
, LPARAM lParam
)
7902 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7904 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
7905 PrintEvent(cwpt
->message
, FALSE
, FALSE
);
7910 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
7911 if (cwpt
->message
== WM_MOVING
||
7912 cwpt
->message
== WM_SIZING
||
7913 cwpt
->message
== WM_GETMINMAXINFO
) {
7914 ScheduleHookTimer(cwpt
->hwnd
, (UINT
)cwpt
->message
);
7918 return ::CallNextHookEx(sCallProcHook
, code
, wParam
, lParam
);
7921 // Register the special "hooks" for dropdown processing.
7922 void nsWindow::RegisterSpecialDropdownHooks()
7924 NS_ASSERTION(!sMsgFilterHook
, "sMsgFilterHook must be NULL!");
7925 NS_ASSERTION(!sCallProcHook
, "sCallProcHook must be NULL!");
7927 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
7929 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
7931 // Install msg hook for moving the window and resizing
7932 if (!sMsgFilterHook
) {
7933 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
7934 sMsgFilterHook
= SetWindowsHookEx(WH_MSGFILTER
, MozSpecialMsgFilter
, NULL
, GetCurrentThreadId());
7935 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7936 if (!sMsgFilterHook
) {
7937 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
7942 // Install msg hook for menus
7943 if (!sCallProcHook
) {
7944 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
7945 sCallProcHook
= SetWindowsHookEx(WH_CALLWNDPROC
, MozSpecialWndProc
, NULL
, GetCurrentThreadId());
7946 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7947 if (!sCallProcHook
) {
7948 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
7953 // Install msg hook for the mouse
7954 if (!sCallMouseHook
) {
7955 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
7956 sCallMouseHook
= SetWindowsHookEx(WH_MOUSE
, MozSpecialMouseProc
, NULL
, GetCurrentThreadId());
7957 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7958 if (!sCallMouseHook
) {
7959 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
7965 // Unhook special message hooks for dropdowns.
7966 void nsWindow::UnregisterSpecialDropdownHooks()
7968 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
7970 if (sCallProcHook
) {
7971 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
7972 if (!::UnhookWindowsHookEx(sCallProcHook
)) {
7973 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
7975 sCallProcHook
= NULL
;
7978 if (sMsgFilterHook
) {
7979 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
7980 if (!::UnhookWindowsHookEx(sMsgFilterHook
)) {
7981 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
7983 sMsgFilterHook
= NULL
;
7986 if (sCallMouseHook
) {
7987 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
7988 if (!::UnhookWindowsHookEx(sCallMouseHook
)) {
7989 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
7991 sCallMouseHook
= NULL
;
7995 // This timer is designed to only fire one time at most each time a "hook" function
7996 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
7997 // hook, but that hook event or a subsequent event may roll up the dropdown before
7998 // this timer function is executed.
8000 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
8001 // before this function fires.
8002 VOID CALLBACK
nsWindow::HookTimerForPopups(HWND hwnd
, UINT uMsg
, UINT idEvent
, DWORD dwTime
)
8004 if (sHookTimerId
!= 0) {
8005 // if the window is NULL then we need to use the ID to kill the timer
8006 BOOL status
= ::KillTimer(NULL
, sHookTimerId
);
8007 NS_ASSERTION(status
, "Hook Timer was not killed.");
8011 if (sRollupMsgId
!= 0) {
8012 // Note: DealWithPopups does the check to make sure that
8013 // sRollupListener and sRollupWidget are not NULL
8014 LRESULT popupHandlingResult
;
8015 nsAutoRollup autoRollup
;
8016 DealWithPopups(sRollupMsgWnd
, sRollupMsgId
, 0, 0, &popupHandlingResult
);
8018 sRollupMsgWnd
= NULL
;
8023 BOOL CALLBACK
nsWindow::ClearResourcesCallback(HWND aWnd
, LPARAM aMsg
)
8025 nsWindow
*window
= nsWindow::GetNSWindowPtr(aWnd
);
8027 window
->ClearCachedResources();
8033 nsWindow::ClearCachedResources()
8035 #ifdef CAIRO_HAS_D2D_SURFACE
8036 mD2DWindowSurface
= nsnull
;
8038 if (mLayerManager
&&
8039 mLayerManager
->GetBackendType() == LayerManager::LAYERS_BASIC
) {
8040 static_cast<BasicLayerManager
*>(mLayerManager
.get())->
8041 ClearCachedResources();
8043 ::EnumChildWindows(mWnd
, nsWindow::ClearResourcesCallback
, NULL
);
8046 static PRBool
IsDifferentThreadWindow(HWND aWnd
)
8048 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd
, NULL
);
8052 nsWindow::EventIsInsideWindow(UINT Msg
, nsWindow
* aWindow
)
8057 if (Msg
== WM_ACTIVATEAPP
)
8058 // don't care about activation/deactivation
8061 if (Msg
== WM_ACTIVATE
)
8062 // but on Windows CE we do care about
8063 // activation/deactivation because there doesn't exist
8064 // cancelable Mouse Activation events
8068 ::GetWindowRect(aWindow
->mWnd
, &r
);
8069 DWORD pos
= ::GetMessagePos();
8071 mp
.x
= GET_X_LPARAM(pos
);
8072 mp
.y
= GET_Y_LPARAM(pos
);
8074 // was the event inside this window?
8075 return (PRBool
) PtInRect(&r
, mp
);
8078 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8080 nsWindow::DealWithPopups(HWND inWnd
, UINT inMsg
, WPARAM inWParam
, LPARAM inLParam
, LRESULT
* outResult
)
8082 if (sRollupListener
&& sRollupWidget
&& ::IsWindowVisible(inWnd
)) {
8084 if (inMsg
== WM_LBUTTONDOWN
|| inMsg
== WM_RBUTTONDOWN
|| inMsg
== WM_MBUTTONDOWN
||
8085 inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
|| inMsg
== WM_ACTIVATE
||
8086 (inMsg
== WM_KILLFOCUS
&& IsDifferentThreadWindow((HWND
)inWParam
))
8089 inMsg
== WM_NCRBUTTONDOWN
||
8090 inMsg
== WM_MOVING
||
8091 inMsg
== WM_SIZING
||
8092 inMsg
== WM_NCLBUTTONDOWN
||
8093 inMsg
== WM_NCMBUTTONDOWN
||
8094 inMsg
== WM_MOUSEACTIVATE
||
8095 inMsg
== WM_ACTIVATEAPP
||
8096 inMsg
== WM_MENUSELECT
8100 // Rollup if the event is outside the popup.
8101 PRBool rollup
= !nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)sRollupWidget
);
8103 if (rollup
&& (inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
))
8105 sRollupListener
->ShouldRollupOnMouseWheelEvent(&rollup
);
8106 *outResult
= PR_TRUE
;
8109 // If we're dealing with menus, we probably have submenus and we don't
8110 // want to rollup if the click is in a parent menu of the current submenu.
8111 PRUint32 popupsToRollup
= PR_UINT32_MAX
;
8113 if ( sMenuRollup
) {
8114 nsAutoTArray
<nsIWidget
*, 5> widgetChain
;
8115 PRUint32 sameTypeCount
= sMenuRollup
->GetSubmenuWidgetChain(&widgetChain
);
8116 for ( PRUint32 i
= 0; i
< widgetChain
.Length(); ++i
) {
8117 nsIWidget
* widget
= widgetChain
[i
];
8118 if ( nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)widget
) ) {
8119 // don't roll up if the mouse event occurred within a menu of the
8120 // same type. If the mouse event occurred in a menu higher than
8121 // that, roll up, but pass the number of popups to Rollup so
8122 // that only those of the same type close up.
8123 if (i
< sameTypeCount
) {
8127 popupsToRollup
= sameTypeCount
;
8131 } // foreach parent menu widget
8132 } // if rollup listener knows about menus
8136 if (inMsg
== WM_MOUSEACTIVATE
&& popupsToRollup
== PR_UINT32_MAX
) {
8137 // Prevent the click inside the popup from causing a change in window
8138 // activation. Since the popup is shown non-activated, we need to eat
8139 // any requests to activate the window while it is displayed. Windows
8140 // will automatically activate the popup on the mousedown otherwise.
8142 *outResult
= MA_NOACTIVATE
;
8147 UINT uMsg
= HIWORD(inLParam
);
8148 if (uMsg
== WM_MOUSEMOVE
)
8150 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8151 // must be enabled in Windows.
8152 sRollupListener
->ShouldRollupOnMouseActivate(&rollup
);
8155 *outResult
= MA_NOACTIVATE
;
8161 // if we've still determined that we should still rollup everything, do it.
8165 // sRollupConsumeEvent may be modified by
8166 // nsIRollupListener::Rollup.
8167 PRBool consumeRollupEvent
= sRollupConsumeEvent
;
8168 // only need to deal with the last rollup for left mouse down events.
8169 sRollupListener
->Rollup(popupsToRollup
, inMsg
== WM_LBUTTONDOWN
? &mLastRollup
: nsnull
);
8171 // Tell hook to stop processing messages
8172 sProcessHook
= PR_FALSE
;
8174 sRollupMsgWnd
= NULL
;
8176 // return TRUE tells Windows that the event is consumed,
8177 // false allows the event to be dispatched
8179 // So if we are NOT supposed to be consuming events, let it go through
8180 if (consumeRollupEvent
&& inMsg
!= WM_RBUTTONDOWN
) {
8185 // if we are only rolling up some popups, don't activate and don't let
8186 // the event go through. This prevents clicks menus higher in the
8187 // chain from opening when a context menu is open
8188 if (popupsToRollup
!= PR_UINT32_MAX
&& inMsg
== WM_MOUSEACTIVATE
) {
8189 *outResult
= MA_NOACTIVATEANDEAT
;
8194 } // if event that might trigger a popup to rollup
8195 } // if rollup listeners registered
8200 /**************************************************************
8201 **************************************************************
8203 ** BLOCK: Misc. utility methods and functions.
8207 **************************************************************
8208 **************************************************************/
8210 // nsModifierKeyState used in various character processing.
8211 nsModifierKeyState::nsModifierKeyState()
8213 mIsShiftDown
= IS_VK_DOWN(NS_VK_SHIFT
);
8214 mIsControlDown
= IS_VK_DOWN(NS_VK_CONTROL
);
8215 mIsAltDown
= IS_VK_DOWN(NS_VK_ALT
);
8219 PRInt32
nsWindow::GetWindowsVersion()
8224 static PRInt32 version
= 0;
8225 static PRBool didCheck
= PR_FALSE
;
8230 OSVERSIONINFOEX osInfo
;
8231 osInfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
8232 // This cast is safe and supposed to be here, don't worry
8233 ::GetVersionEx((OSVERSIONINFO
*)&osInfo
);
8234 version
= (osInfo
.dwMajorVersion
& 0xff) << 8 | (osInfo
.dwMinorVersion
& 0xff);
8240 // Note that the result of GetTopLevelWindow method can be different from the
8241 // result of GetTopLevelHWND method. The result can be non-floating window.
8242 // Because our top level window may be contained in another window which is
8243 // not managed by us.
8244 nsWindow
* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup
)
8246 nsWindow
* curWindow
= this;
8249 if (aStopOnDialogOrPopup
) {
8250 switch (curWindow
->mWindowType
) {
8251 case eWindowType_dialog
:
8252 case eWindowType_popup
:
8259 // Retrieve the top level parent or owner window
8260 nsWindow
* parentWindow
= curWindow
->GetParentWindow(PR_TRUE
);
8265 curWindow
= parentWindow
;
8269 // Note that the result of GetTopLevelHWND can be different from the result
8270 // of GetTopLevelWindow method. Because this is checking whether the window
8271 // is top level only in Win32 window system. Therefore, the result window
8272 // may not be managed by us.
8273 HWND
nsWindow::GetTopLevelHWND(HWND aWnd
, PRBool aStopOnDialogOrPopup
)
8282 if (aStopOnDialogOrPopup
) {
8283 DWORD_PTR style
= ::GetWindowLongPtrW(curWnd
, GWL_STYLE
);
8285 VERIFY_WINDOW_STYLE(style
);
8287 if (!(style
& WS_CHILD
)) // first top-level window
8291 upWnd
= ::GetParent(curWnd
); // Parent or owner (if has no parent)
8294 // For dialog windows, we want just the parent, not the owner.
8295 // For other/popup windows, we want to find the first owner/parent
8296 // that's a dialog and/or has an owner.
8297 if (upWnd
&& ::GetWindow(curWnd
, GW_OWNER
) == upWnd
) {
8298 DWORD_PTR style
= ::GetWindowLongPtrW(curWnd
, GWL_STYLE
);
8299 if ((style
& WS_DLGFRAME
) != 0)
8310 static BOOL CALLBACK
gEnumWindowsProc(HWND hwnd
, LPARAM lParam
)
8313 ::GetWindowThreadProcessId(hwnd
, &pid
);
8314 if (pid
== GetCurrentProcessId() && ::IsWindowVisible(hwnd
))
8316 gWindowsVisible
= PR_TRUE
;
8322 PRBool
nsWindow::CanTakeFocus()
8324 gWindowsVisible
= PR_FALSE
;
8325 EnumWindows(gEnumWindowsProc
, 0);
8326 if (!gWindowsVisible
) {
8329 HWND fgWnd
= ::GetForegroundWindow();
8334 GetWindowThreadProcessId(fgWnd
, &pid
);
8335 if (pid
== GetCurrentProcessId()) {
8343 void nsWindow::InitTrackPointHack()
8345 // Init Trackpoint Hack
8349 const WCHAR wstrKeys
[][40] = {L
"Software\\Lenovo\\TrackPoint",
8350 L
"Software\\Lenovo\\UltraNav",
8351 L
"Software\\Alps\\Apoint\\TrackPoint",
8352 L
"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
8353 L
"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
8354 // If anything fails turn the hack off
8355 sTrackPointHack
= false;
8356 nsCOMPtr
<nsIPrefBranch
> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
));
8357 if(NS_SUCCEEDED(rv
) && prefs
) {
8358 prefs
->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue
);
8359 switch (lHackValue
) {
8360 // 0 means hack disabled
8363 // 1 means hack enabled
8365 sTrackPointHack
= true;
8367 // -1 means autodetect
8369 for(unsigned i
= 0; i
< NS_ARRAY_LENGTH(wstrKeys
); i
++) {
8371 lResult
= ::RegOpenKeyExW(HKEY_CURRENT_USER
, (LPCWSTR
)&wstrKeys
[i
],
8372 0, KEY_READ
, &hKey
);
8373 ::RegCloseKey(hKey
);
8374 if(lResult
== ERROR_SUCCESS
) {
8375 // If we detected a registry key belonging to a TrackPoint driver
8377 sTrackPointHack
= true;
8382 // Shouldn't be any other values, but treat them as disabled
8389 #endif // #if !defined(WINCE)
8391 LPARAM
nsWindow::lParamToScreen(LPARAM lParam
)
8394 pt
.x
= GET_X_LPARAM(lParam
);
8395 pt
.y
= GET_Y_LPARAM(lParam
);
8396 ::ClientToScreen(mWnd
, &pt
);
8397 return MAKELPARAM(pt
.x
, pt
.y
);
8400 LPARAM
nsWindow::lParamToClient(LPARAM lParam
)
8403 pt
.x
= GET_X_LPARAM(lParam
);
8404 pt
.y
= GET_Y_LPARAM(lParam
);
8405 ::ScreenToClient(mWnd
, &pt
);
8406 return MAKELPARAM(pt
.x
, pt
.y
);
8409 /**************************************************************
8410 **************************************************************
8412 ** BLOCK: ChildWindow impl.
8414 ** Child window overrides.
8416 **************************************************************
8417 **************************************************************/
8419 // return the style for a child nsWindow
8420 DWORD
ChildWindow::WindowStyle()
8422 DWORD style
= WS_CLIPCHILDREN
| nsWindow::WindowStyle();
8423 if (!(style
& WS_POPUP
))
8424 style
|= WS_CHILD
; // WS_POPUP and WS_CHILD are mutually exclusive.
8425 VERIFY_WINDOW_STYLE(style
);