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"
181 #include "nsUXThemeConstants.h"
182 #include "KeyboardLayout.h"
183 #include "nsNativeDragTarget.h"
184 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
187 #include <richedit.h>
188 #endif // !defined(WINCE)
190 #if defined(ACCESSIBILITY)
193 #include "nsIAccessibleDocument.h"
194 #if !defined(WINABLEAPI)
196 #endif // !defined(WINABLEAPI)
197 #endif // defined(ACCESSIBILITY)
199 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
200 #include "nsIWinTaskbar.h"
203 #if defined(NS_ENABLE_TSF)
204 #include "nsTextStore.h"
205 #endif // defined(NS_ENABLE_TSF)
207 #if defined(MOZ_SPLASHSCREEN)
208 #include "nsSplashScreen.h"
209 #endif // defined(MOZ_SPLASHSCREEN)
211 // Windowless plugin support
214 #include "nsWindowDefs.h"
216 #include "mozilla/FunctionTimer.h"
218 #ifdef WINCE_WINDOWS_MOBILE
219 #include "nsGfxCIID.h"
222 #include "mozilla/FunctionTimer.h"
224 using namespace mozilla::widget
;
226 /**************************************************************
227 **************************************************************
231 ** nsWindow Class static initializations and global variables.
233 **************************************************************
234 **************************************************************/
236 /**************************************************************
238 * SECTION: nsWindow statics
240 **************************************************************/
242 PRUint32
nsWindow::sInstanceCount
= 0;
243 PRBool
nsWindow::sSwitchKeyboardLayout
= PR_FALSE
;
244 BOOL
nsWindow::sIsRegistered
= FALSE
;
245 BOOL
nsWindow::sIsPopupClassRegistered
= FALSE
;
246 BOOL
nsWindow::sIsOleInitialized
= FALSE
;
247 HCURSOR
nsWindow::sHCursor
= NULL
;
248 imgIContainer
* nsWindow::sCursorImgContainer
= nsnull
;
249 nsWindow
* nsWindow::sCurrentWindow
= nsnull
;
250 PRBool
nsWindow::sJustGotDeactivate
= PR_FALSE
;
251 PRBool
nsWindow::sJustGotActivate
= PR_FALSE
;
253 // imported in nsWidgetFactory.cpp
254 TriStateBool
nsWindow::sCanQuit
= TRI_UNKNOWN
;
256 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
257 // hook methods whether they should be processing the hook
259 HHOOK
nsWindow::sMsgFilterHook
= NULL
;
260 HHOOK
nsWindow::sCallProcHook
= NULL
;
261 HHOOK
nsWindow::sCallMouseHook
= NULL
;
262 PRPackedBool
nsWindow::sProcessHook
= PR_FALSE
;
263 UINT
nsWindow::sRollupMsgId
= 0;
264 HWND
nsWindow::sRollupMsgWnd
= NULL
;
265 UINT
nsWindow::sHookTimerId
= 0;
268 nsIRollupListener
* nsWindow::sRollupListener
= nsnull
;
269 nsIMenuRollup
* nsWindow::sMenuRollup
= nsnull
;
270 nsIWidget
* nsWindow::sRollupWidget
= nsnull
;
271 PRBool
nsWindow::sRollupConsumeEvent
= PR_FALSE
;
273 // Mouse Clicks - static variable definitions for figuring
275 POINT
nsWindow::sLastMousePoint
= {0};
276 POINT
nsWindow::sLastMouseMovePoint
= {0};
277 LONG
nsWindow::sLastMouseDownTime
= 0L;
278 LONG
nsWindow::sLastClickCount
= 0L;
279 BYTE
nsWindow::sLastMouseButton
= 0;
281 // Trim heap on minimize. (initialized, but still true.)
282 int nsWindow::sTrimOnMinimize
= 2;
284 // Default Trackpoint Hack to off
285 PRBool
nsWindow::sTrackPointHack
= PR_FALSE
;
288 BOOL
nsWindow::sIsAccessibilityOn
= FALSE
;
289 // Accessibility wm_getobject handler
290 HINSTANCE
nsWindow::sAccLib
= 0;
291 LPFNLRESULTFROMOBJECT
292 nsWindow::sLresultFromObject
= 0;
293 #endif // ACCESSIBILITY
296 // Used in OOPP plugin focus processing.
297 const PRUnichar
* kOOPPPluginFocusEventId
= L
"OOPP Plugin Focus Widget Event";
298 PRUint32
nsWindow::sOOPPPluginFocusEvent
=
299 RegisterWindowMessageW(kOOPPPluginFocusEventId
);
302 /**************************************************************
304 * SECTION: globals variables
306 **************************************************************/
308 static const char *sScreenManagerContractID
= "@mozilla.org/gfx/screenmanager;1";
311 PRLogModuleInfo
* gWindowsLog
= nsnull
;
315 // Kbd layout. Used throughout character processing.
316 static KeyboardLayout gKbdLayout
;
319 #ifdef WINCE_WINDOWS_MOBILE
320 // HTC Navigation Wheel Event
321 // This is the defined value for Gesture Mode
322 const int WM_HTCNAV
= 0x0400 + 200;
324 typedef int (__stdcall
* HTCApiNavOpen
)(HANDLE
, int);
325 typedef int (__stdcall
* HTCApiNavSetMode
)(HANDLE
, unsigned int);
327 HTCApiNavOpen gHTCApiNavOpen
= nsnull
;
328 HTCApiNavSetMode gHTCApiNavSetMode
= nsnull
;
329 static PRBool gCheckForHTCApi
= PR_FALSE
;
332 // Global user preference for disabling native theme. Used
333 // in NativeWindowTheme.
334 PRBool gDisableNativeTheme
= PR_FALSE
;
336 // Global used in Show window enumerations.
337 static PRBool gWindowsVisible
= PR_FALSE
;
339 static NS_DEFINE_CID(kCClipboardCID
, NS_CLIPBOARD_CID
);
340 #ifdef WINCE_WINDOWS_MOBILE
341 static NS_DEFINE_CID(kRegionCID
, NS_REGION_CID
);
344 /**************************************************************
345 **************************************************************
347 ** BLOCK: nsIWidget impl.
349 ** nsIWidget interface implementation, broken down into
352 **************************************************************
353 **************************************************************/
355 /**************************************************************
357 * SECTION: nsWindow construction and destruction
359 **************************************************************/
361 nsWindow::nsWindow() : nsBaseWidget()
365 gWindowsLog
= PR_NewLogModule("nsWindowsWidgets");
370 mPrevWndProc
= nsnull
;
372 mNativeDragTarget
= nsnull
;
374 mIsVisible
= PR_FALSE
;
375 mIsInMouseCapture
= PR_FALSE
;
376 mIsTopWidgetWindow
= PR_FALSE
;
377 mUnicodeWidget
= PR_TRUE
;
378 mDisplayPanFeedback
= PR_FALSE
;
379 mTouchWindow
= PR_FALSE
;
380 mCustomNonClient
= PR_FALSE
;
381 mCompositorFlag
= PR_FALSE
;
382 mHideChrome
= PR_FALSE
;
383 mWindowType
= eWindowType_child
;
384 mBorderStyle
= eBorderStyle_default
;
385 mPopupType
= ePopupTypeAny
;
386 mOldSizeMode
= nsSizeMode_Normal
;
390 mLastSize
.height
= 0;
394 mExitToNonClientArea
= 0;
395 mLastKeyboardLayout
= 0;
396 mBlurSuppressLevel
= 0;
397 mIMEEnabled
= nsIWidget::IME_STATUS_ENABLED
;
399 mTransparentSurface
= nsnull
;
401 mTransparencyMode
= eTransparencyOpaque
;
402 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
403 memset(&mGlassMargins
, 0, sizeof mGlassMargins
);
404 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
406 mBackground
= ::GetSysColor(COLOR_BTNFACE
);
407 mBrush
= ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground
));
408 mForeground
= ::GetSysColor(COLOR_WINDOWTEXT
);
410 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
411 mTaskbarPreview
= nsnull
;
412 mHasTaskbarIconBeenCreated
= PR_FALSE
;
415 // Global initialization
416 if (!sInstanceCount
) {
418 gKbdLayout
.LoadLayout(::GetKeyboardLayout(0));
422 nsIMM32Handler::Initialize();
425 nsTextStore::Initialize();
429 if (SUCCEEDED(::OleInitialize(NULL
)))
430 sIsOleInitialized
= TRUE
;
431 NS_ASSERTION(sIsOleInitialized
, "***** OLE is not initialized!\n");
434 #if defined(HEAP_DUMP_EVENT)
439 InitTrackPointHack();
442 // Init titlebar button info for custom frames.
443 nsUXThemeData::InitTitlebarInfo();
446 mIdleService
= nsnull
;
451 nsWindow::~nsWindow()
455 // If the widget was released without calling Destroy() then the native window still
456 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
458 // XXX How could this happen???
465 if (sInstanceCount
== 0) {
467 nsTextStore::Terminate();
471 NS_IF_RELEASE(sCursorImgContainer
);
472 if (sIsOleInitialized
) {
473 ::OleFlushClipboard();
475 sIsOleInitialized
= FALSE
;
477 // delete any of the IME structures that we allocated
478 nsIMM32Handler::Terminate();
479 #endif // !defined(WINCE)
483 NS_IF_RELEASE(mNativeDragTarget
);
484 #endif // !defined(WINCE)
487 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow
, nsBaseWidget
)
489 /**************************************************************
491 * SECTION: nsIWidget::Create, nsIWidget::Destroy
493 * Creating and destroying windows for this widget.
495 **************************************************************/
497 // Allow Derived classes to modify the height that is passed
498 // when the window is created or resized. Also add extra height
499 // if needed (on Windows CE)
500 PRInt32
nsWindow::GetHeight(PRInt32 aProposedHeight
)
504 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
505 DWORD style
= WindowStyle();
506 if ((style
& WS_SYSMENU
) && (style
& WS_POPUP
)) {
507 extra
= GetSystemMetrics(SM_CYCAPTION
);
511 return aProposedHeight
+ extra
;
514 // Create the proper widget
516 nsWindow::Create(nsIWidget
*aParent
,
517 nsNativeWidget aNativeParent
,
518 const nsIntRect
&aRect
,
519 EVENT_CALLBACK aHandleEventFunction
,
520 nsIDeviceContext
*aContext
,
521 nsIAppShell
*aAppShell
,
522 nsIToolkit
*aToolkit
,
523 nsWidgetInitData
*aInitData
)
526 mUnicodeWidget
= aInitData
->mUnicode
;
528 nsIWidget
*baseParent
= aInitData
&&
529 (aInitData
->mWindowType
== eWindowType_dialog
||
530 aInitData
->mWindowType
== eWindowType_toplevel
||
531 aInitData
->mWindowType
== eWindowType_invisible
) ?
534 mIsTopWidgetWindow
= (nsnull
== baseParent
);
535 mBounds
.width
= aRect
.width
;
536 mBounds
.height
= aRect
.height
;
538 BaseCreate(baseParent
, aRect
, aHandleEventFunction
, aContext
,
539 aAppShell
, aToolkit
, aInitData
);
542 if (aParent
) { // has a nsIWidget parent
543 parent
= aParent
? (HWND
)aParent
->GetNativeData(NS_NATIVE_WINDOW
) : NULL
;
545 } else { // has a nsNative parent
546 parent
= (HWND
)aNativeParent
;
547 mParent
= aNativeParent
? GetNSWindowPtr((HWND
)aNativeParent
) : nsnull
;
550 if (nsnull
!= aInitData
) {
551 mPopupType
= aInitData
->mPopupHint
;
554 mContentType
= aInitData
? aInitData
->mContentType
: eContentTypeInherit
;
556 DWORD style
= WindowStyle();
557 DWORD extendedStyle
= WindowExStyle();
559 if (aInitData
->mRTL
) {
560 extendedStyle
|= WS_EX_LAYOUTRTL
| WS_EX_NOINHERITLAYOUT
;
563 if (mWindowType
== eWindowType_popup
) {
566 } else if (mWindowType
== eWindowType_invisible
) {
567 // Make sure CreateWindowEx succeeds at creating a toplevel window
568 style
&= ~0x40000000; // WS_CHILDWINDOW
569 } else if (nsnull
!= aInitData
) {
570 // See if the caller wants to explictly set clip children and clip siblings
571 if (aInitData
->clipChildren
) {
572 style
|= WS_CLIPCHILDREN
;
574 style
&= ~WS_CLIPCHILDREN
;
576 if (aInitData
->clipSiblings
) {
577 style
|= WS_CLIPSIBLINGS
;
581 mWnd
= ::CreateWindowExW(extendedStyle
,
582 aInitData
&& aInitData
->mDropShadow
?
583 WindowPopupClass() : WindowClass(),
589 GetHeight(aRect
.height
),
592 nsToolkit::mDllInstance
,
596 NS_WARNING("nsWindow CreateWindowEx failed.");
597 return NS_ERROR_FAILURE
;
600 if (nsWindow::sTrackPointHack
&&
601 mWindowType
!= eWindowType_plugin
&&
602 mWindowType
!= eWindowType_invisible
) {
603 // Ugly Thinkpad Driver Hack (Bug 507222)
604 // We create an invisible scrollbar to trick the
605 // Trackpoint driver into sending us scrolling messages
606 ::CreateWindowW(L
"SCROLLBAR", L
"FAKETRACKPOINTSCROLLBAR",
607 WS_CHILD
| WS_VISIBLE
, 0,0,0,0, mWnd
, NULL
,
608 nsToolkit::mDllInstance
, NULL
);
611 // call the event callback to notify about creation
613 DispatchStandardEvent(NS_CREATE
);
614 SubclassWindow(TRUE
);
616 if (sTrimOnMinimize
== 2 && mWindowType
== eWindowType_invisible
) {
617 /* The internal variable set by the config.trim_on_minimize pref
618 has not yet been initialized, and this is the hidden window
619 (conveniently created before any visible windows, and after
620 the profile has been initialized).
622 Default config.trim_on_minimize to false, to fix bug 76831
623 for good. If anyone complains about this new default, saying
624 that a Mozilla app hogs too much memory while minimized, they
625 will have that entire bug tattooed on their backside. */
628 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
630 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
631 prefs
->GetBranch(0, getter_AddRefs(prefBranch
));
635 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("config.trim_on_minimize",
640 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("intl.keyboard.per_window_layout",
642 sSwitchKeyboardLayout
= temp
;
644 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("mozilla.widget.disable-native-theme",
646 gDisableNativeTheme
= temp
;
650 #if defined(WINCE_HAVE_SOFTKB)
651 if (mWindowType
== eWindowType_dialog
|| mWindowType
== eWindowType_toplevel
)
652 nsWindowCE::CreateSoftKeyMenuBar(mWnd
);
658 // Close this nsWindow
659 NS_METHOD
nsWindow::Destroy()
661 // WM_DESTROY has already fired, we're done.
665 // During the destruction of all of our children, make sure we don't get deleted.
666 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
669 * On windows the LayerManagerOGL destructor wants the widget to be around for
670 * cleanup. It also would like to have the HWND intact, so we NULL it here.
673 mLayerManager
->Destroy();
675 mLayerManager
= nsnull
;
677 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
678 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
679 // from it. The function also destroys the window's menu, flushes the thread message queue,
680 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
681 // the window is at the top of the viewer chain).
683 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
684 // the associated child or owned windows when it destroys the parent or owner window. The
685 // function first destroys child or owned windows, and then it destroys the parent or owner
687 VERIFY(::DestroyWindow(mWnd
));
689 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
690 // didn't get called, call it now.
691 if (PR_FALSE
== mOnDestroyCalled
)
697 /**************************************************************
699 * SECTION: Window class utilities
701 * Utilities for calculating the proper window class name for
704 **************************************************************/
706 // Return the proper window class for everything except popups.
707 LPCWSTR
nsWindow::WindowClass()
709 if (!nsWindow::sIsRegistered
) {
712 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
713 wc
.style
= CS_DBLCLKS
;
714 wc
.lpfnWndProc
= ::DefWindowProcW
;
717 wc
.hInstance
= nsToolkit::mDllInstance
;
718 wc
.hIcon
= ::LoadIconW(::GetModuleHandleW(NULL
), (LPWSTR
)IDI_APPLICATION
);
720 wc
.hbrBackground
= mBrush
;
721 wc
.lpszMenuName
= NULL
;
722 wc
.lpszClassName
= kClassNameHidden
;
724 BOOL succeeded
= ::RegisterClassW(&wc
) != 0 &&
725 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError();
726 nsWindow::sIsRegistered
= succeeded
;
728 wc
.lpszClassName
= kClassNameContentFrame
;
729 if (!::RegisterClassW(&wc
) &&
730 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
731 nsWindow::sIsRegistered
= FALSE
;
734 wc
.lpszClassName
= kClassNameContent
;
735 if (!::RegisterClassW(&wc
) &&
736 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
737 nsWindow::sIsRegistered
= FALSE
;
740 wc
.lpszClassName
= kClassNameUI
;
741 if (!::RegisterClassW(&wc
) &&
742 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
743 nsWindow::sIsRegistered
= FALSE
;
746 wc
.lpszClassName
= kClassNameGeneral
;
747 ATOM generalClassAtom
= ::RegisterClassW(&wc
);
748 if (!generalClassAtom
&&
749 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
750 nsWindow::sIsRegistered
= FALSE
;
753 wc
.lpszClassName
= kClassNameDialog
;
755 if (!::RegisterClassW(&wc
) &&
756 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
757 nsWindow::sIsRegistered
= FALSE
;
761 if (mWindowType
== eWindowType_invisible
) {
762 return kClassNameHidden
;
764 if (mWindowType
== eWindowType_dialog
) {
765 return kClassNameDialog
;
767 if (mContentType
== eContentTypeContent
) {
768 return kClassNameContent
;
770 if (mContentType
== eContentTypeContentFrame
) {
771 return kClassNameContentFrame
;
773 if (mContentType
== eContentTypeUI
) {
776 return kClassNameGeneral
;
779 // Return the proper popup window class
780 LPCWSTR
nsWindow::WindowPopupClass()
782 if (!nsWindow::sIsPopupClassRegistered
) {
785 wc
.style
= CS_DBLCLKS
| CS_XP_DROPSHADOW
;
786 wc
.lpfnWndProc
= ::DefWindowProcW
;
789 wc
.hInstance
= nsToolkit::mDllInstance
;
790 wc
.hIcon
= ::LoadIconW(::GetModuleHandleW(NULL
), (LPWSTR
)IDI_APPLICATION
);
792 wc
.hbrBackground
= mBrush
;
793 wc
.lpszMenuName
= NULL
;
794 wc
.lpszClassName
= kClassNameDropShadow
;
796 nsWindow::sIsPopupClassRegistered
= ::RegisterClassW(&wc
);
797 if (!nsWindow::sIsPopupClassRegistered
) {
798 // For older versions of Win32 (i.e., not XP), the registration will
799 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
800 wc
.style
= CS_DBLCLKS
;
801 nsWindow::sIsPopupClassRegistered
= ::RegisterClassW(&wc
);
805 return kClassNameDropShadow
;
808 /**************************************************************
810 * SECTION: Window styles utilities
812 * Return the proper windows styles and extended styles.
814 **************************************************************/
816 // Return nsWindow styles
817 #if !defined(WINCE) // implemented in nsWindowCE.cpp
818 DWORD
nsWindow::WindowStyle()
822 switch (mWindowType
) {
823 case eWindowType_plugin
:
824 case eWindowType_child
:
825 style
= WS_OVERLAPPED
;
828 case eWindowType_dialog
:
829 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
| DS_3DLOOK
|
830 DS_MODALFRAME
| WS_CLIPCHILDREN
;
831 if (mBorderStyle
!= eBorderStyle_default
)
832 style
|= WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
;
835 case eWindowType_popup
:
837 if (mTransparencyMode
!= eTransparencyGlass
) {
838 style
|= WS_OVERLAPPED
;
843 NS_ERROR("unknown border style");
846 case eWindowType_toplevel
:
847 case eWindowType_invisible
:
848 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
|
849 WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
| WS_CLIPCHILDREN
;
853 if (mBorderStyle
!= eBorderStyle_default
&& mBorderStyle
!= eBorderStyle_all
) {
854 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_border
))
857 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_title
)) {
858 style
&= ~WS_DLGFRAME
;
863 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_close
))
865 // XXX The close box can only be removed by changing the window class,
866 // as far as I know --- roc+moz@cs.cmu.edu
868 if (mBorderStyle
== eBorderStyle_none
||
869 !(mBorderStyle
& (eBorderStyle_menu
| eBorderStyle_close
)))
870 style
&= ~WS_SYSMENU
;
871 // Looks like getting rid of the system menu also does away with the
872 // close box. So, we only get rid of the system menu if you want neither it
873 // nor the close box. How does the Windows "Dialog" window class get just
874 // closebox and no sysmenu? Who knows.
876 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_resizeh
))
877 style
&= ~WS_THICKFRAME
;
879 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_minimize
))
880 style
&= ~WS_MINIMIZEBOX
;
882 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_maximize
))
883 style
&= ~WS_MAXIMIZEBOX
;
885 if (IsPopupWithTitleBar()) {
887 if (mBorderStyle
& eBorderStyle_close
) {
893 VERIFY_WINDOW_STYLE(style
);
896 #endif // !defined(WINCE)
898 // Return nsWindow extended styles
899 DWORD
nsWindow::WindowExStyle()
903 case eWindowType_plugin
:
904 case eWindowType_child
:
907 case eWindowType_dialog
:
908 return WS_EX_WINDOWEDGE
| WS_EX_DLGMODALFRAME
;
910 case eWindowType_popup
:
912 DWORD extendedStyle
=
913 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
917 if (mPopupLevel
== ePopupLevelTop
)
918 extendedStyle
|= WS_EX_TOPMOST
;
919 return extendedStyle
;
922 NS_ERROR("unknown border style");
925 case eWindowType_toplevel
:
926 case eWindowType_invisible
:
927 return WS_EX_WINDOWEDGE
;
931 /**************************************************************
933 * SECTION: Window subclassing utilities
935 * Set or clear window subclasses on native windows. Used in
936 * Create and Destroy.
938 **************************************************************/
940 // Subclass (or remove the subclass from) this component's nsWindow
941 void nsWindow::SubclassWindow(BOOL bState
)
944 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
945 if (!::IsWindow(mWnd
)) {
946 NS_ERROR("Invalid window handle");
950 // change the nsWindow proc
952 mPrevWndProc
= (WNDPROC
)::SetWindowLongPtrW(mWnd
, GWLP_WNDPROC
,
953 (LONG_PTR
)nsWindow::WindowProc
);
955 mPrevWndProc
= (WNDPROC
)::SetWindowLongPtrA(mWnd
, GWLP_WNDPROC
,
956 (LONG_PTR
)nsWindow::WindowProc
);
957 NS_ASSERTION(mPrevWndProc
, "Null standard window procedure");
958 // connect the this pointer to the nsWindow handle
959 SetNSWindowPtr(mWnd
, this);
963 ::SetWindowLongPtrW(mWnd
, GWLP_WNDPROC
, (LONG_PTR
)mPrevWndProc
);
965 ::SetWindowLongPtrA(mWnd
, GWLP_WNDPROC
, (LONG_PTR
)mPrevWndProc
);
966 SetNSWindowPtr(mWnd
, NULL
);
972 /**************************************************************
974 * SECTION: Window properties
976 * Set and clear native window properties.
978 **************************************************************/
980 static PRUnichar sPropName
[40] = L
"";
981 static PRUnichar
* GetNSWindowPropName()
985 _snwprintf(sPropName
, 39, L
"MozillansIWidgetPtr%p", GetCurrentProcessId());
986 sPropName
[39] = '\0';
991 nsWindow
* nsWindow::GetNSWindowPtr(HWND aWnd
)
993 return (nsWindow
*) ::GetPropW(aWnd
, GetNSWindowPropName());
996 BOOL
nsWindow::SetNSWindowPtr(HWND aWnd
, nsWindow
* ptr
)
999 ::RemovePropW(aWnd
, GetNSWindowPropName());
1002 return ::SetPropW(aWnd
, GetNSWindowPropName(), (HANDLE
)ptr
);
1006 /**************************************************************
1008 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
1010 * Set or clear the parent widgets using window properties, and
1011 * handles calculating native parent handles.
1013 **************************************************************/
1015 // Get and set parent widgets
1016 NS_IMETHODIMP
nsWindow::SetParent(nsIWidget
*aNewParent
)
1018 mParent
= aNewParent
;
1021 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
1023 nsIWidget
* parent
= GetParent();
1025 parent
->RemoveChild(this);
1028 HWND newParent
= (HWND
)aNewParent
->GetNativeData(NS_NATIVE_WINDOW
);
1029 NS_ASSERTION(newParent
, "Parent widget has a null native window handle");
1030 if (newParent
&& mWnd
) {
1031 ::SetParent(mWnd
, newParent
);
1034 aNewParent
->AddChild(this);
1039 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
1041 nsIWidget
* parent
= GetParent();
1044 parent
->RemoveChild(this);
1048 // If we have no parent, SetParent should return the desktop.
1049 VERIFY(::SetParent(mWnd
, nsnull
));
1055 nsIWidget
* nsWindow::GetParent(void)
1057 return GetParentWindow(PR_FALSE
);
1060 nsWindow
* nsWindow::GetParentWindow(PRBool aIncludeOwner
)
1062 if (mIsTopWidgetWindow
) {
1063 // Must use a flag instead of mWindowType to tell if the window is the
1064 // owned by the topmost widget, because a child window can be embedded inside
1065 // a HWND which is not associated with a nsIWidget.
1069 // If this widget has already been destroyed, pretend we have no parent.
1070 // This corresponds to code in Destroy which removes the destroyed
1071 // widget from its parent's child list.
1072 if (mInDtor
|| mOnDestroyCalled
)
1076 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1077 // root owner. aIncludeOwner set to false implies the search will stop at the
1078 // true parent (default).
1079 nsWindow
* widget
= nsnull
;
1082 HWND parent
= ::GetParent(mWnd
);
1084 HWND parent
= nsnull
;
1086 parent
= ::GetParent(mWnd
);
1088 parent
= ::GetAncestor(mWnd
, GA_PARENT
);
1091 widget
= GetNSWindowPtr(parent
);
1093 // If the widget is in the process of being destroyed then
1095 if (widget
->mInDtor
) {
1105 /**************************************************************
1107 * SECTION: nsIWidget::Show
1109 * Hide or show this component.
1111 **************************************************************/
1113 NS_METHOD
nsWindow::Show(PRBool bState
)
1115 #if defined(MOZ_SPLASHSCREEN)
1116 // we're about to show the first toplevel window,
1117 // so kill off any splash screen if we had one
1118 nsSplashScreen
*splash
= nsSplashScreen::Get();
1119 if (splash
&& splash
->IsOpen() && mWnd
&& bState
&&
1120 (mWindowType
== eWindowType_toplevel
||
1121 mWindowType
== eWindowType_dialog
||
1122 mWindowType
== eWindowType_popup
))
1128 #ifdef NS_FUNCTION_TIMER
1129 static bool firstShow
= true;
1131 (mWindowType
== eWindowType_toplevel
||
1132 mWindowType
== eWindowType_dialog
||
1133 mWindowType
== eWindowType_popup
))
1136 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1140 PRBool wasVisible
= mIsVisible
;
1141 // Set the status now so that anyone asking during ShowWindow or
1142 // SetWindowPos would get the correct answer.
1143 mIsVisible
= bState
;
1147 if (!wasVisible
&& mWindowType
== eWindowType_toplevel
) {
1148 switch (mSizeMode
) {
1150 case nsSizeMode_Fullscreen
:
1151 ::SetForegroundWindow(mWnd
);
1152 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1153 MakeFullScreen(TRUE
);
1156 case nsSizeMode_Maximized
:
1157 ::SetForegroundWindow(mWnd
);
1158 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1160 // use default for nsSizeMode_Minimized on Windows CE
1162 case nsSizeMode_Maximized
:
1163 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1165 case nsSizeMode_Minimized
:
1166 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
1170 if (CanTakeFocus()) {
1172 ::SetForegroundWindow(mWnd
);
1174 ::ShowWindow(mWnd
, SW_SHOWNORMAL
);
1176 // Place the window behind the foreground window
1177 // (as long as it is not topmost)
1178 HWND wndAfter
= ::GetForegroundWindow();
1180 wndAfter
= HWND_BOTTOM
;
1181 else if (GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
1182 wndAfter
= HWND_TOP
;
1183 ::SetWindowPos(mWnd
, wndAfter
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOSIZE
|
1184 SWP_NOMOVE
| SWP_NOACTIVATE
);
1190 DWORD flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_SHOWWINDOW
;
1192 flags
|= SWP_NOZORDER
;
1194 if (mWindowType
== eWindowType_popup
) {
1196 // ensure popups are the topmost of the TOPMOST
1197 // layer. Remember not to set the SWP_NOZORDER
1198 // flag as that might allow the taskbar to overlap
1199 // the popup. However on windows ce, we need to
1200 // activate the popup or clicks will not be sent.
1201 flags
|= SWP_NOACTIVATE
;
1203 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
1204 ::SetWindowPos(mWnd
, owner
? 0 : HWND_TOPMOST
, 0, 0, 0, 0, flags
);
1207 if (mWindowType
== eWindowType_dialog
&& !CanTakeFocus())
1208 flags
|= SWP_NOACTIVATE
;
1210 ::SetWindowPos(mWnd
, HWND_TOP
, 0, 0, 0, 0, flags
);
1215 if (!wasVisible
&& (mWindowType
== eWindowType_toplevel
|| mWindowType
== eWindowType_dialog
)) {
1216 // when a toplevel window or dialog is shown, initialize the UI state
1217 ::SendMessageW(mWnd
, WM_CHANGEUISTATE
, MAKEWPARAM(UIS_INITIALIZE
, UISF_HIDEFOCUS
| UISF_HIDEACCEL
), 0);
1221 if (mWindowType
!= eWindowType_dialog
) {
1222 ::ShowWindow(mWnd
, SW_HIDE
);
1224 ::SetWindowPos(mWnd
, 0, 0, 0, 0, 0, SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
|
1225 SWP_NOZORDER
| SWP_NOACTIVATE
);
1231 if (!wasVisible
&& bState
)
1232 Invalidate(PR_FALSE
);
1238 /**************************************************************
1240 * SECTION: nsIWidget::IsVisible
1242 * Returns the visibility state.
1244 **************************************************************/
1246 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1247 NS_METHOD
nsWindow::IsVisible(PRBool
& bState
)
1249 bState
= mIsVisible
;
1253 /**************************************************************
1255 * SECTION: Window clipping utilities
1257 * Used in Size and Move operations for setting the proper
1258 * window clipping regions for window transparency.
1260 **************************************************************/
1262 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1263 // transparency. These routines are called on size and move operations.
1264 void nsWindow::ClearThemeRegion()
1267 if (nsUXThemeData::sIsVistaOrLater
&& mTransparencyMode
!= eTransparencyGlass
&&
1268 mWindowType
== eWindowType_popup
&& (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
)) {
1269 SetWindowRgn(mWnd
, NULL
, false);
1274 void nsWindow::SetThemeRegion()
1277 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1278 // for other window types as needed. The regions are applied generically to the base window
1279 // so default constants are used for part and state. At some point we might need part and
1280 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1281 // change shape based on state haven't come up.
1282 if (nsUXThemeData::sIsVistaOrLater
&& mTransparencyMode
!= eTransparencyGlass
&&
1283 mWindowType
== eWindowType_popup
&& (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
)) {
1285 RECT rect
= {0,0,mBounds
.width
,mBounds
.height
};
1287 HDC dc
= ::GetDC(mWnd
);
1288 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip
), dc
, TTP_STANDARD
, TS_NORMAL
, &rect
, &hRgn
);
1290 if (!SetWindowRgn(mWnd
, hRgn
, false)) // do not delete or alter hRgn if accepted.
1293 ::ReleaseDC(mWnd
, dc
);
1298 /**************************************************************
1300 * SECTION: nsIWidget::RegisterTouchWindow,
1301 * nsIWidget::UnregisterTouchWindow, and helper functions
1303 * Used to register the native window to receive touch events
1305 **************************************************************/
1307 NS_METHOD
nsWindow::RegisterTouchWindow() {
1308 mTouchWindow
= PR_TRUE
;
1310 mGesture
.RegisterTouchWindow(mWnd
);
1311 ::EnumChildWindows(mWnd
, nsWindow::RegisterTouchForDescendants
, NULL
);
1316 NS_METHOD
nsWindow::UnregisterTouchWindow() {
1317 mTouchWindow
= PR_FALSE
;
1319 mGesture
.UnregisterTouchWindow(mWnd
);
1320 ::EnumChildWindows(mWnd
, nsWindow::UnregisterTouchForDescendants
, NULL
);
1326 BOOL CALLBACK
nsWindow::RegisterTouchForDescendants(HWND aWnd
, LPARAM aMsg
) {
1327 nsWindow
* win
= GetNSWindowPtr(aWnd
);
1329 win
->mGesture
.RegisterTouchWindow(aWnd
);
1333 BOOL CALLBACK
nsWindow::UnregisterTouchForDescendants(HWND aWnd
, LPARAM aMsg
) {
1334 nsWindow
* win
= GetNSWindowPtr(aWnd
);
1336 win
->mGesture
.UnregisterTouchWindow(aWnd
);
1341 /**************************************************************
1343 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1344 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1346 * Repositioning and sizing a window.
1348 **************************************************************/
1350 // Move this component
1351 NS_METHOD
nsWindow::Move(PRInt32 aX
, PRInt32 aY
)
1353 if (mWindowType
== eWindowType_toplevel
||
1354 mWindowType
== eWindowType_dialog
) {
1355 SetSizeMode(nsSizeMode_Normal
);
1357 // Check to see if window needs to be moved first
1358 // to avoid a costly call to SetWindowPos. This check
1359 // can not be moved to the calling code in nsView, because
1360 // some platforms do not position child windows correctly
1362 // Only perform this check for non-popup windows, since the positioning can
1363 // in fact change even when the x/y do not. We always need to perform the
1364 // check. See bug #97805 for details.
1365 if (mWindowType
!= eWindowType_popup
&& (mBounds
.x
== aX
) && (mBounds
.y
== aY
))
1367 // Nothing to do, since it is already positioned correctly.
1376 // complain if a window is moved offscreen (legal, but potentially worrisome)
1377 if (mIsTopWidgetWindow
) { // only a problem for top-level windows
1378 // Make sure this window is actually on the screen before we move it
1379 // XXX: Needs multiple monitor support
1380 HDC dc
= ::GetDC(mWnd
);
1382 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1384 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &workArea
, 0);
1385 // no annoying assertions. just mention the issue.
1386 if (aX
< 0 || aX
>= workArea
.right
|| aY
< 0 || aY
>= workArea
.bottom
)
1387 printf("window moved to offscreen position\n");
1389 ::ReleaseDC(mWnd
, dc
);
1394 VERIFY(::SetWindowPos(mWnd
, NULL
, aX
, aY
, 0, 0,
1395 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOSIZE
));
1401 // Resize this component
1402 NS_METHOD
nsWindow::Resize(PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1404 NS_ASSERTION((aWidth
>=0 ) , "Negative width passed to nsWindow::Resize");
1405 NS_ASSERTION((aHeight
>=0 ), "Negative height passed to nsWindow::Resize");
1407 // Avoid unnecessary resizing calls
1408 if (mBounds
.width
== aWidth
&& mBounds
.height
== aHeight
&& !aRepaint
)
1412 if (eTransparencyTransparent
== mTransparencyMode
)
1413 ResizeTranslucentWindow(aWidth
, aHeight
);
1416 // Set cached value for lightweight and printing
1417 mBounds
.width
= aWidth
;
1418 mBounds
.height
= aHeight
;
1421 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOMOVE
;
1425 flags
|= SWP_NOREDRAW
;
1430 VERIFY(::SetWindowPos(mWnd
, NULL
, 0, 0, aWidth
, GetHeight(aHeight
), flags
));
1435 Invalidate(PR_FALSE
);
1440 // Resize this component
1441 NS_METHOD
nsWindow::Resize(PRInt32 aX
, PRInt32 aY
, PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1443 NS_ASSERTION((aWidth
>=0 ), "Negative width passed to nsWindow::Resize");
1444 NS_ASSERTION((aHeight
>=0 ), "Negative height passed to nsWindow::Resize");
1446 // Avoid unnecessary resizing calls
1447 if (mBounds
.x
== aX
&& mBounds
.y
== aY
&&
1448 mBounds
.width
== aWidth
&& mBounds
.height
== aHeight
&& !aRepaint
)
1452 if (eTransparencyTransparent
== mTransparencyMode
)
1453 ResizeTranslucentWindow(aWidth
, aHeight
);
1456 // Set cached value for lightweight and printing
1459 mBounds
.width
= aWidth
;
1460 mBounds
.height
= aHeight
;
1463 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
1466 flags
|= SWP_NOREDRAW
;
1471 VERIFY(::SetWindowPos(mWnd
, NULL
, aX
, aY
, aWidth
, GetHeight(aHeight
), flags
));
1476 Invalidate(PR_FALSE
);
1481 // Resize the client area and position the widget within it's parent
1482 NS_METHOD
nsWindow::ResizeClient(PRInt32 aX
, PRInt32 aY
, PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1484 NS_ASSERTION((aWidth
>=0) , "Negative width passed to ResizeClient");
1485 NS_ASSERTION((aHeight
>=0), "Negative height passed to ResizeClient");
1487 // Adjust our existing window bounds, based on the new client dims.
1489 GetClientRect(mWnd
, &client
);
1490 nsIntPoint
dims(client
.right
- client
.left
, client
.bottom
- client
.top
);
1491 aWidth
= mBounds
.width
+ (aWidth
- dims
.x
);
1492 aHeight
= mBounds
.height
+ (aHeight
- dims
.y
);
1497 GetScreenBounds(bounds
);
1500 return Resize(aX
, aY
, aWidth
, aHeight
, aRepaint
);
1502 return Resize(aWidth
, aHeight
, aRepaint
);
1507 nsWindow::BeginResizeDrag(nsGUIEvent
* aEvent
, PRInt32 aHorizontal
, PRInt32 aVertical
)
1509 NS_ENSURE_ARG_POINTER(aEvent
);
1511 if (aEvent
->eventStructType
!= NS_MOUSE_EVENT
) {
1512 // you can only begin a resize drag with a mouse event
1513 return NS_ERROR_INVALID_ARG
;
1516 nsMouseEvent
* mouseEvent
= static_cast<nsMouseEvent
*>(aEvent
);
1517 if (mouseEvent
->button
!= nsMouseEvent::eLeftButton
) {
1518 // you can only begin a resize drag with the left mouse button
1519 return NS_ERROR_INVALID_ARG
;
1522 // work out what sizemode we're talking about
1524 if (aVertical
< 0) {
1525 if (aHorizontal
< 0) {
1526 syscommand
= SC_SIZE
| WMSZ_TOPLEFT
;
1527 } else if (aHorizontal
== 0) {
1528 syscommand
= SC_SIZE
| WMSZ_TOP
;
1530 syscommand
= SC_SIZE
| WMSZ_TOPRIGHT
;
1532 } else if (aVertical
== 0) {
1533 if (aHorizontal
< 0) {
1534 syscommand
= SC_SIZE
| WMSZ_LEFT
;
1535 } else if (aHorizontal
== 0) {
1536 return NS_ERROR_INVALID_ARG
;
1538 syscommand
= SC_SIZE
| WMSZ_RIGHT
;
1541 if (aHorizontal
< 0) {
1542 syscommand
= SC_SIZE
| WMSZ_BOTTOMLEFT
;
1543 } else if (aHorizontal
== 0) {
1544 syscommand
= SC_SIZE
| WMSZ_BOTTOM
;
1546 syscommand
= SC_SIZE
| WMSZ_BOTTOMRIGHT
;
1550 // resizing doesn't work if the mouse is already captured
1551 CaptureMouse(PR_FALSE
);
1553 // find the top-level window
1554 HWND toplevelWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
1556 // tell Windows to start the resize
1557 ::PostMessage(toplevelWnd
, WM_SYSCOMMAND
, syscommand
,
1558 POINTTOPOINTS(aEvent
->refPoint
));
1563 /**************************************************************
1565 * SECTION: Window Z-order and state.
1567 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1568 * nsIWidget::ConstrainPosition
1570 * Z-order, positioning, restore, minimize, and maximize.
1572 **************************************************************/
1574 // Position the window behind the given window
1575 NS_METHOD
nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement
,
1576 nsIWidget
*aWidget
, PRBool aActivate
)
1578 HWND behind
= HWND_TOP
;
1579 if (aPlacement
== eZPlacementBottom
)
1580 behind
= HWND_BOTTOM
;
1581 else if (aPlacement
== eZPlacementBelow
&& aWidget
)
1582 behind
= (HWND
)aWidget
->GetNativeData(NS_NATIVE_WINDOW
);
1583 UINT flags
= SWP_NOMOVE
| SWP_NOREPOSITION
| SWP_NOSIZE
;
1585 flags
|= SWP_NOACTIVATE
;
1587 if (!CanTakeFocus() && behind
== HWND_TOP
)
1589 // Can't place the window to top so place it behind the foreground window
1590 // (as long as it is not topmost)
1591 HWND wndAfter
= ::GetForegroundWindow();
1593 behind
= HWND_BOTTOM
;
1594 else if (!(GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
1596 flags
|= SWP_NOACTIVATE
;
1599 ::SetWindowPos(mWnd
, behind
, 0, 0, 0, 0, flags
);
1603 // Maximize, minimize or restore the window.
1604 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1605 NS_IMETHODIMP
nsWindow::SetSizeMode(PRInt32 aMode
) {
1609 // Let's not try and do anything if we're already in that state.
1610 // (This is needed to prevent problems when calling window.minimize(), which
1611 // calls us directly, and then the OS triggers another call to us.)
1612 if (aMode
== mSizeMode
)
1615 // save the requested state
1616 rv
= nsBaseWidget::SetSizeMode(aMode
);
1617 if (NS_SUCCEEDED(rv
) && mIsVisible
) {
1621 case nsSizeMode_Fullscreen
:
1625 case nsSizeMode_Maximized
:
1629 case nsSizeMode_Minimized
:
1630 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1631 // keeps the window active in the tray. So after the window is minimized,
1632 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1633 // we will do some additional processing to get the active window set right.
1634 // If sTrimOnMinimize is set, we let windows handle minimization normally
1635 // using SW_MINIMIZE.
1636 mode
= sTrimOnMinimize
? SW_MINIMIZE
: SW_SHOWMINIMIZED
;
1642 ::ShowWindow(mWnd
, mode
);
1643 // we dispatch an activate event here to ensure that the right child window
1645 if (mode
== SW_RESTORE
|| mode
== SW_MAXIMIZE
)
1646 DispatchFocusToTopLevelWindow(NS_ACTIVATE
);
1650 #endif // !defined(WINCE)
1652 // Constrain a potential move to fit onscreen
1653 NS_METHOD
nsWindow::ConstrainPosition(PRBool aAllowSlop
,
1654 PRInt32
*aX
, PRInt32
*aY
)
1656 if (!mIsTopWidgetWindow
) // only a problem for top-level windows
1659 PRBool doConstrain
= PR_FALSE
; // whether we have enough info to do anything
1661 /* get our playing field. use the current screen, or failing that
1662 for any reason, use device caps for the default screen. */
1665 nsCOMPtr
<nsIScreenManager
> screenmgr
= do_GetService(sScreenManagerContractID
);
1667 nsCOMPtr
<nsIScreen
> screen
;
1668 PRInt32 left
, top
, width
, height
;
1670 // zero size rects confuse the screen manager
1671 width
= mBounds
.width
> 0 ? mBounds
.width
: 1;
1672 height
= mBounds
.height
> 0 ? mBounds
.height
: 1;
1673 screenmgr
->ScreenForRect(*aX
, *aY
, width
, height
,
1674 getter_AddRefs(screen
));
1676 if (mSizeMode
!= nsSizeMode_Fullscreen
) {
1677 // For normalized windows, use the desktop work area.
1678 screen
->GetAvailRect(&left
, &top
, &width
, &height
);
1680 // For full screen windows, use the desktop.
1681 screen
->GetRect(&left
, &top
, &width
, &height
);
1683 screenRect
.left
= left
;
1684 screenRect
.right
= left
+width
;
1685 screenRect
.top
= top
;
1686 screenRect
.bottom
= top
+height
;
1687 doConstrain
= PR_TRUE
;
1691 HDC dc
= ::GetDC(mWnd
);
1693 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1694 if (mSizeMode
!= nsSizeMode_Fullscreen
) {
1695 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &screenRect
, 0);
1697 screenRect
.left
= screenRect
.top
= 0;
1698 screenRect
.right
= GetSystemMetrics(SM_CXFULLSCREEN
);
1699 screenRect
.bottom
= GetSystemMetrics(SM_CYFULLSCREEN
);
1701 doConstrain
= PR_TRUE
;
1703 ::ReleaseDC(mWnd
, dc
);
1709 if (*aX
< screenRect
.left
- mBounds
.width
+ kWindowPositionSlop
)
1710 *aX
= screenRect
.left
- mBounds
.width
+ kWindowPositionSlop
;
1711 else if (*aX
>= screenRect
.right
- kWindowPositionSlop
)
1712 *aX
= screenRect
.right
- kWindowPositionSlop
;
1714 if (*aY
< screenRect
.top
- mBounds
.height
+ kWindowPositionSlop
)
1715 *aY
= screenRect
.top
- mBounds
.height
+ kWindowPositionSlop
;
1716 else if (*aY
>= screenRect
.bottom
- kWindowPositionSlop
)
1717 *aY
= screenRect
.bottom
- kWindowPositionSlop
;
1721 if (*aX
< screenRect
.left
)
1722 *aX
= screenRect
.left
;
1723 else if (*aX
>= screenRect
.right
- mBounds
.width
)
1724 *aX
= screenRect
.right
- mBounds
.width
;
1726 if (*aY
< screenRect
.top
)
1727 *aY
= screenRect
.top
;
1728 else if (*aY
>= screenRect
.bottom
- mBounds
.height
)
1729 *aY
= screenRect
.bottom
- mBounds
.height
;
1735 /**************************************************************
1737 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1739 * Enabling and disabling the widget.
1741 **************************************************************/
1743 // Enable/disable this component
1744 NS_METHOD
nsWindow::Enable(PRBool bState
)
1747 ::EnableWindow(mWnd
, bState
);
1752 // Return the current enable state
1753 NS_METHOD
nsWindow::IsEnabled(PRBool
*aState
)
1755 NS_ENSURE_ARG_POINTER(aState
);
1758 *aState
= !mWnd
|| (::IsWindowEnabled(mWnd
) && ::IsWindowEnabled(::GetAncestor(mWnd
, GA_ROOT
)));
1760 *aState
= !mWnd
|| (::IsWindowEnabled(mWnd
) && ::IsWindowEnabled(mWnd
));
1767 /**************************************************************
1769 * SECTION: nsIWidget::SetFocus
1771 * Give the focus to this widget.
1773 **************************************************************/
1775 NS_METHOD
nsWindow::SetFocus(PRBool aRaise
)
1778 #ifdef WINSTATE_DEBUG_OUTPUT
1779 if (mWnd
== GetTopLevelHWND(mWnd
))
1780 printf("*** SetFocus: [ top] raise=%d\n", aRaise
);
1782 printf("*** SetFocus: [child] raise=%d\n", aRaise
);
1784 // Uniconify, if necessary
1785 HWND toplevelWnd
= GetTopLevelHWND(mWnd
);
1786 if (aRaise
&& ::IsIconic(toplevelWnd
)) {
1787 ::ShowWindow(toplevelWnd
, SW_RESTORE
);
1795 /**************************************************************
1799 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1800 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1802 * Bound calculations.
1804 **************************************************************/
1806 // Return the window's full dimensions in screen coordinates.
1807 // If the window has a parent, converts the origin to an offset
1808 // of the parent's screen origin.
1809 NS_METHOD
nsWindow::GetBounds(nsIntRect
&aRect
)
1813 VERIFY(::GetWindowRect(mWnd
, &r
));
1816 aRect
.width
= r
.right
- r
.left
;
1817 aRect
.height
= r
.bottom
- r
.top
;
1819 // chrome on parent:
1820 // ___ 5,5 (chrome start)
1821 // | ____ 10,10 (client start)
1822 // | | ____ 20,20 (child start)
1824 // 20,20 - 5,5 = 15,15 (??)
1825 // minus GetClientOffset:
1826 // 15,15 - 5,5 = 10,10
1828 // no chrome on parent:
1829 // ______ 10,10 (win start)
1830 // | ____ 20,20 (child start)
1832 // 20,20 - 10,10 = 10,10
1834 // walking the chain:
1835 // ___ 5,5 (chrome start)
1836 // | ___ 10,10 (client start)
1837 // | | ___ 20,20 (child start)
1838 // | | | __ 30,30 (child start)
1840 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1841 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1842 // minus GetClientOffset:
1843 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1845 // convert coordinates if parent exists
1846 HWND parent
= ::GetParent(mWnd
);
1849 VERIFY(::GetWindowRect(parent
, &pr
));
1852 // adjust for chrome
1853 nsWindow
* pWidget
= static_cast<nsWindow
*>(GetParent());
1854 if (pWidget
&& pWidget
->IsTopLevelWidget()) {
1855 nsIntPoint clientOffset
= pWidget
->GetClientOffset();
1856 r
.left
-= clientOffset
.x
;
1857 r
.top
-= clientOffset
.y
;
1869 // Get this component dimension
1870 NS_METHOD
nsWindow::GetClientBounds(nsIntRect
&aRect
)
1874 VERIFY(::GetClientRect(mWnd
, &r
));
1879 aRect
.width
= r
.right
- r
.left
;
1880 aRect
.height
= r
.bottom
- r
.top
;
1883 aRect
.SetRect(0,0,0,0);
1888 // Like GetBounds, but don't offset by the parent
1889 NS_METHOD
nsWindow::GetScreenBounds(nsIntRect
&aRect
)
1893 VERIFY(::GetWindowRect(mWnd
, &r
));
1895 aRect
.width
= r
.right
- r
.left
;
1896 aRect
.height
= r
.bottom
- r
.top
;
1905 // return the x,y offset of the client area from the origin
1906 // of the window. If the window is borderless returns (0,0).
1907 nsIntPoint
nsWindow::GetClientOffset()
1910 return nsIntPoint(0, 0);
1914 GetWindowRect(mWnd
, &r1
);
1915 nsIntPoint pt
= WidgetToScreenOffset();
1916 return nsIntPoint(pt
.x
- r1
.left
, pt
.y
- r1
.top
);
1920 nsWindow::SetDrawsInTitlebar(PRBool aState
)
1922 nsWindow
* window
= GetTopLevelWindow(PR_TRUE
);
1923 if (window
&& window
!= this) {
1924 return window
->SetDrawsInTitlebar(aState
);
1928 // left, top, right, bottom for nsIntMargin
1929 nsIntMargin
margins(-1, 0, -1, -1);
1930 SetNonClientMargins(margins
);
1933 nsIntMargin
margins(-1, -1, -1, -1);
1934 SetNonClientMargins(margins
);
1939 nsWindow::GetNonClientMargins(nsIntMargin
&margins
)
1941 nsWindow
* window
= GetTopLevelWindow(PR_TRUE
);
1942 if (window
&& window
!= this) {
1943 return window
->GetNonClientMargins(margins
);
1946 if (mCustomNonClient
) {
1947 margins
= mNonClientMargins
;
1951 margins
.top
= GetSystemMetrics(SM_CYCAPTION
);
1952 margins
.bottom
= GetSystemMetrics(SM_CYFRAME
);
1953 margins
.top
+= margins
.bottom
;
1954 margins
.left
= margins
.right
= GetSystemMetrics(SM_CYFRAME
);
1960 nsWindow::ResetLayout()
1962 // This will trigger a frame changed event, triggering
1963 // nc calc size and a sizemode gecko event.
1964 SetWindowPos(mWnd
, 0, 0, 0, 0, 0,
1965 SWP_FRAMECHANGED
|SWP_NOACTIVATE
|SWP_NOMOVE
|
1966 SWP_NOOWNERZORDER
|SWP_NOSIZE
|SWP_NOZORDER
);
1968 // If hidden, just send the frame changed event for now.
1972 // Send a gecko size event to trigger reflow.
1973 RECT clientRc
= {0};
1974 GetClientRect(mWnd
, &clientRc
);
1975 nsIntRect
evRect(nsWindowGfx::ToIntRect(clientRc
));
1978 // Invalidate and update
1979 Invalidate(PR_FALSE
);
1982 // Called when the window layout changes: full screen mode transitions,
1983 // theme changes, and composition changes. Calculates the new non-client
1984 // margins and fires off a frame changed event, which triggers an nc calc
1985 // size windows event, kicking the changes in.
1987 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode
, PRBool aReflowWindow
)
1989 if (!mCustomNonClient
)
1992 // XXX Temp disable margins until frame rendering is supported
1993 mCompositorFlag
= PR_TRUE
;
1994 if(!nsUXThemeData::CheckForCompositor()) {
1995 mCompositorFlag
= PR_FALSE
;
1999 mNonClientOffset
.top
= mNonClientOffset
.bottom
=
2000 mNonClientOffset
.left
= mNonClientOffset
.right
= 0;
2002 if (aSizeMode
== -1)
2003 aSizeMode
= mSizeMode
;
2005 if (aSizeMode
== nsSizeMode_Minimized
||
2006 aSizeMode
== nsSizeMode_Fullscreen
) {
2007 mCaptionHeight
= mVertResizeMargin
= mHorResizeMargin
= 0;
2011 // Note, for maximized windows, we need to continue to offset the client by
2012 // thick frame margins of a normal window, since windows expects this
2013 // in it's DwmDefWndProc hit testing.
2014 mCaptionHeight
= GetSystemMetrics(SM_CYCAPTION
);
2015 mHorResizeMargin
= GetSystemMetrics(SM_CXFRAME
);
2016 mVertResizeMargin
= GetSystemMetrics(SM_CYFRAME
);
2018 mCaptionHeight
+= mVertResizeMargin
;
2020 // If a margin value is 0, set the offset to the default size of the frame.
2021 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2022 // so that the frame size is equal to the margin value.
2023 if (!mNonClientMargins
.top
)
2024 mNonClientOffset
.top
= mCaptionHeight
;
2025 else if (mNonClientMargins
.top
> 0)
2026 mNonClientOffset
.top
= mCaptionHeight
- mNonClientMargins
.top
;
2028 if (!mNonClientMargins
.left
)
2029 mNonClientOffset
.left
= mHorResizeMargin
;
2030 else if (mNonClientMargins
.left
> 0)
2031 mNonClientOffset
.left
= mHorResizeMargin
- mNonClientMargins
.left
;
2033 if (!mNonClientMargins
.right
)
2034 mNonClientOffset
.right
= mHorResizeMargin
;
2035 else if (mNonClientMargins
.right
> 0)
2036 mNonClientOffset
.right
= mHorResizeMargin
- mNonClientMargins
.right
;
2038 if (!mNonClientMargins
.bottom
)
2039 mNonClientOffset
.bottom
= mVertResizeMargin
;
2040 else if (mNonClientMargins
.bottom
> 0)
2041 mNonClientOffset
.bottom
= mVertResizeMargin
- mNonClientMargins
.bottom
;
2044 if (aSizeMode
== nsSizeMode_Maximized
) {
2045 // Address an issue with auto-hide taskbars which fall behind the window.
2046 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2047 // the taskbar works properly.
2048 MONITORINFO info
= {sizeof(MONITORINFO
)};
2049 if (::GetMonitorInfo(::MonitorFromWindow(mWnd
, MONITOR_DEFAULTTOPRIMARY
),
2052 if (::GetWindowRect(mWnd
, &r
)) {
2053 // Adjust window rect to account for non-client margins.
2054 r
.top
+= mVertResizeMargin
- mNonClientOffset
.top
;
2055 r
.left
+= mHorResizeMargin
- mNonClientOffset
.left
;
2056 r
.bottom
-= mVertResizeMargin
- mNonClientOffset
.bottom
;
2057 r
.right
-= mHorResizeMargin
- mNonClientOffset
.right
;
2058 // Leave the 1 pixel margin if the window covers the monitor.
2059 if (r
.top
<= info
.rcMonitor
.top
&&
2060 r
.left
<= info
.rcMonitor
.left
&&
2061 r
.right
>= info
.rcMonitor
.right
&&
2062 r
.bottom
>= info
.rcMonitor
.bottom
)
2063 mNonClientOffset
.bottom
-= r
.bottom
- info
.rcMonitor
.bottom
+ 1;
2069 if (aReflowWindow
) {
2070 // Force a reflow of content based on the new client
2079 nsWindow::SetNonClientMargins(nsIntMargin
&margins
)
2081 if (!mIsTopWidgetWindow
||
2082 mBorderStyle
& eBorderStyle_none
||
2084 return NS_ERROR_INVALID_ARG
;
2086 // Request for a reset
2087 if (margins
.top
== -1 && margins
.left
== -1 &&
2088 margins
.right
== -1 && margins
.bottom
== -1) {
2089 mCustomNonClient
= PR_FALSE
;
2090 mNonClientMargins
= margins
;
2091 // Force a reflow of content based on the new client
2097 if (margins
.top
< -1 || margins
.bottom
< -1 ||
2098 margins
.left
< -1 || margins
.right
< -1)
2099 return NS_ERROR_INVALID_ARG
;
2101 mNonClientMargins
= margins
;
2102 mCustomNonClient
= PR_TRUE
;
2103 if (!UpdateNonClientMargins()) {
2104 NS_WARNING("UpdateNonClientMargins failed!");
2111 /**************************************************************
2113 * SECTION: nsIWidget::SetBackgroundColor
2115 * Sets the window background paint color.
2117 **************************************************************/
2119 NS_METHOD
nsWindow::SetBackgroundColor(const nscolor
&aColor
)
2121 nsBaseWidget::SetBackgroundColor(aColor
);
2124 ::DeleteObject(mBrush
);
2126 mBrush
= ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground
));
2129 ::SetClassLongPtrW(mWnd
, GCLP_HBRBACKGROUND
, (LONG_PTR
)mBrush
);
2135 /**************************************************************
2137 * SECTION: nsIWidget::SetCursor
2139 * SetCursor and related utilities for manging cursor state.
2141 **************************************************************/
2143 // Set this component cursor
2144 NS_METHOD
nsWindow::SetCursor(nsCursor aCursor
)
2146 // Only change cursor if it's changing
2148 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2149 //XXX If we want this optimization we need a better way to do it.
2150 //if (aCursor != mCursor) {
2151 HCURSOR newCursor
= NULL
;
2154 case eCursor_select
:
2155 newCursor
= ::LoadCursor(NULL
, IDC_IBEAM
);
2159 newCursor
= ::LoadCursor(NULL
, IDC_WAIT
);
2162 case eCursor_hyperlink
:
2164 newCursor
= ::LoadCursor(NULL
, IDC_HAND
);
2168 case eCursor_standard
:
2169 newCursor
= ::LoadCursor(NULL
, IDC_ARROW
);
2172 case eCursor_n_resize
:
2173 case eCursor_s_resize
:
2174 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
2177 case eCursor_w_resize
:
2178 case eCursor_e_resize
:
2179 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
2182 case eCursor_nw_resize
:
2183 case eCursor_se_resize
:
2184 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
2187 case eCursor_ne_resize
:
2188 case eCursor_sw_resize
:
2189 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
2192 case eCursor_crosshair
:
2193 newCursor
= ::LoadCursor(NULL
, IDC_CROSS
);
2197 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
2201 newCursor
= ::LoadCursor(NULL
, IDC_HELP
);
2204 case eCursor_copy
: // CSS3
2205 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COPY
));
2209 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ALIAS
));
2213 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_CELL
));
2217 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRAB
));
2220 case eCursor_grabbing
:
2221 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRABBING
));
2224 case eCursor_spinning
:
2225 newCursor
= ::LoadCursor(NULL
, IDC_APPSTARTING
);
2228 case eCursor_context_menu
:
2229 // XXX this CSS3 cursor needs to be implemented
2232 case eCursor_zoom_in
:
2233 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMIN
));
2236 case eCursor_zoom_out
:
2237 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMOUT
));
2240 case eCursor_not_allowed
:
2241 case eCursor_no_drop
:
2242 newCursor
= ::LoadCursor(NULL
, IDC_NO
);
2245 case eCursor_col_resize
:
2246 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COLRESIZE
));
2249 case eCursor_row_resize
:
2250 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ROWRESIZE
));
2253 case eCursor_vertical_text
:
2254 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_VERTICALTEXT
));
2257 case eCursor_all_scroll
:
2258 // XXX not 100% appropriate perhaps
2259 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
2262 case eCursor_nesw_resize
:
2263 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
2266 case eCursor_nwse_resize
:
2267 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
2270 case eCursor_ns_resize
:
2271 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
2274 case eCursor_ew_resize
:
2275 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
2279 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_NONE
));
2283 NS_ERROR("Invalid cursor type");
2287 if (NULL
!= newCursor
) {
2289 HCURSOR oldCursor
= ::SetCursor(newCursor
);
2291 if (sHCursor
== oldCursor
) {
2292 NS_IF_RELEASE(sCursorImgContainer
);
2293 if (sHCursor
!= NULL
)
2294 ::DestroyIcon(sHCursor
);
2302 // Setting the actual cursor
2303 NS_IMETHODIMP
nsWindow::SetCursor(imgIContainer
* aCursor
,
2304 PRUint32 aHotspotX
, PRUint32 aHotspotY
)
2306 if (sCursorImgContainer
== aCursor
&& sHCursor
) {
2307 ::SetCursor(sHCursor
);
2315 rv
= aCursor
->GetWidth(&width
);
2316 NS_ENSURE_SUCCESS(rv
, rv
);
2317 rv
= aCursor
->GetHeight(&height
);
2318 NS_ENSURE_SUCCESS(rv
, rv
);
2320 // Reject cursors greater than 128 pixels in either direction, to prevent
2322 // XXX ideally we should rescale. Also, we could modify the API to
2323 // allow trusted content to set larger cursors.
2324 if (width
> 128 || height
> 128)
2325 return NS_ERROR_NOT_AVAILABLE
;
2328 rv
= nsWindowGfx::CreateIcon(aCursor
, PR_TRUE
, aHotspotX
, aHotspotY
, &cursor
);
2329 NS_ENSURE_SUCCESS(rv
, rv
);
2331 mCursor
= nsCursor(-1);
2332 ::SetCursor(cursor
);
2334 NS_IF_RELEASE(sCursorImgContainer
);
2335 sCursorImgContainer
= aCursor
;
2336 NS_ADDREF(sCursorImgContainer
);
2338 if (sHCursor
!= NULL
)
2339 ::DestroyIcon(sHCursor
);
2345 /**************************************************************
2347 * SECTION: nsIWidget::Get/SetTransparencyMode
2349 * Manage the transparency mode of the top-level window
2350 * containing this widget.
2352 **************************************************************/
2355 nsTransparencyMode
nsWindow::GetTransparencyMode()
2357 return GetTopLevelWindow(PR_TRUE
)->GetWindowTranslucencyInner();
2360 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode
)
2362 GetTopLevelWindow(PR_TRUE
)->SetWindowTranslucencyInner(aMode
);
2366 BOOL CALLBACK
AddClientAreaToRegion(HWND hWnd
, LPARAM lParam
) {
2367 nsIntRegion
*region
= reinterpret_cast<nsIntRegion
*>(lParam
);
2370 ::GetWindowRect(hWnd
, &clientRect
);
2371 nsIntRect
clientArea(clientRect
.left
, clientRect
.top
,
2372 clientRect
.right
- clientRect
.left
,
2373 clientRect
.bottom
- clientRect
.top
);
2374 region
->Or(*region
, clientArea
);
2379 void nsWindow::UpdatePossiblyTransparentRegion(const nsIntRegion
&aDirtyRegion
,
2380 const nsIntRegion
&aPossiblyTransparentRegion
) {
2381 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2382 if (mTransparencyMode
!= eTransparencyGlass
)
2385 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2386 nsWindow
* topWindow
= GetNSWindowPtr(hWnd
);
2391 mPossiblyTransparentRegion
.Sub(mPossiblyTransparentRegion
, aDirtyRegion
);
2392 mPossiblyTransparentRegion
.Or(mPossiblyTransparentRegion
, aPossiblyTransparentRegion
);
2394 nsIntRegion childWindowRegion
;
2396 ::EnumChildWindows(mWnd
, AddClientAreaToRegion
, reinterpret_cast<LPARAM
>(&childWindowRegion
));
2398 nsIntPoint clientOffset
= GetClientOffset();
2399 childWindowRegion
.MoveBy(-clientOffset
);
2402 ::GetWindowRect(mWnd
, &r
);
2403 childWindowRegion
.MoveBy(-r
.left
, -r
.top
);
2405 nsIntRect clientBounds
;
2406 topWindow
->GetClientBounds(clientBounds
);
2407 nsIntRegion opaqueRegion
;
2408 opaqueRegion
.Sub(clientBounds
, mPossiblyTransparentRegion
);
2409 opaqueRegion
.Or(opaqueRegion
, childWindowRegion
);
2410 // Sometimes child windows overlap our bounds
2411 opaqueRegion
.And(opaqueRegion
, clientBounds
);
2413 MARGINS margins
= { 0, 0, 0, 0 };
2414 DWORD_PTR dwStyle
= ::GetWindowLongPtrW(hWnd
, GWL_STYLE
);
2416 // If there is no opaque region or hidechrome=true, set margins
2417 // to support a full sheet of glass.
2418 if (opaqueRegion
.IsEmpty() || mHideChrome
) {
2419 // Comments in MSDN indicate all values must be set to -1
2420 margins
.cxLeftWidth
= margins
.cxRightWidth
=
2421 margins
.cyTopHeight
= margins
.cyBottomHeight
= -1;
2423 // Find the largest rectangle and use that to calculate the inset
2424 nsIntRect largest
= opaqueRegion
.GetLargestRectangle();
2425 margins
.cxLeftWidth
= largest
.x
;
2426 margins
.cxRightWidth
= clientBounds
.width
- largest
.XMost();
2427 margins
.cyTopHeight
= largest
.y
;
2428 margins
.cyBottomHeight
= clientBounds
.height
- largest
.YMost();
2431 // Only update glass area if there are changes
2432 if (memcmp(&mGlassMargins
, &margins
, sizeof mGlassMargins
)) {
2433 mGlassMargins
= margins
;
2436 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2439 void nsWindow::UpdateGlass()
2441 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2442 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2444 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2445 // rendered based on the window style.
2446 // DWMNCRP_ENABLED - The non-client area rendering is
2447 // enabled; the window style is ignored.
2448 DWMNCRENDERINGPOLICY policy
= DWMNCRP_USEWINDOWSTYLE
;
2449 if (mTransparencyMode
== eTransparencyGlass
) {
2450 policy
= DWMNCRP_ENABLED
;
2453 // Extends the window frame behind the client area
2454 if(nsUXThemeData::CheckForCompositor()) {
2455 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd
, &mGlassMargins
);
2456 nsUXThemeData::dwmSetWindowAttributePtr(hWnd
, DWMWA_NCRENDERING_POLICY
, &policy
, sizeof policy
);
2458 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2462 /**************************************************************
2464 * SECTION: nsIWidget::HideWindowChrome
2466 * Show or hide window chrome.
2468 **************************************************************/
2470 NS_IMETHODIMP
nsWindow::HideWindowChrome(PRBool aShouldHide
)
2472 HWND hwnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2473 if (!GetNSWindowPtr(hwnd
))
2475 NS_WARNING("Trying to hide window decorations in an embedded context");
2476 return NS_ERROR_FAILURE
;
2479 if (mHideChrome
== aShouldHide
)
2482 DWORD_PTR style
, exStyle
;
2483 mHideChrome
= aShouldHide
;
2485 DWORD_PTR tempStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2486 DWORD_PTR tempExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2488 style
= tempStyle
& ~(WS_CAPTION
| WS_THICKFRAME
);
2489 exStyle
= tempExStyle
& ~(WS_EX_DLGMODALFRAME
| WS_EX_WINDOWEDGE
|
2490 WS_EX_CLIENTEDGE
| WS_EX_STATICEDGE
);
2492 mOldStyle
= tempStyle
;
2493 mOldExStyle
= tempExStyle
;
2496 if (!mOldStyle
|| !mOldExStyle
) {
2497 mOldStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2498 mOldExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2502 exStyle
= mOldExStyle
;
2505 VERIFY_WINDOW_STYLE(style
);
2506 ::SetWindowLongPtrW(hwnd
, GWL_STYLE
, style
);
2507 ::SetWindowLongPtrW(hwnd
, GWL_EXSTYLE
, exStyle
);
2512 /**************************************************************
2514 * SECTION: nsIWidget::Invalidate
2516 * Invalidate an area of the client for painting.
2518 **************************************************************/
2520 // Invalidate this component visible area
2521 NS_METHOD
nsWindow::Invalidate(PRBool aIsSynchronous
)
2525 #ifdef WIDGET_DEBUG_OUTPUT
2526 debug_DumpInvalidate(stdout
,
2530 nsCAutoString("noname"),
2532 #endif // WIDGET_DEBUG_OUTPUT
2534 VERIFY(::InvalidateRect(mWnd
, NULL
, FALSE
));
2536 if (aIsSynchronous
) {
2537 VERIFY(::UpdateWindow(mWnd
));
2543 // Invalidate this component visible area
2544 NS_METHOD
nsWindow::Invalidate(const nsIntRect
& aRect
, PRBool aIsSynchronous
)
2548 #ifdef WIDGET_DEBUG_OUTPUT
2549 debug_DumpInvalidate(stdout
,
2553 nsCAutoString("noname"),
2555 #endif // WIDGET_DEBUG_OUTPUT
2559 rect
.left
= aRect
.x
;
2561 rect
.right
= aRect
.x
+ aRect
.width
;
2562 rect
.bottom
= aRect
.y
+ aRect
.height
;
2564 VERIFY(::InvalidateRect(mWnd
, &rect
, FALSE
));
2566 if (aIsSynchronous
) {
2567 VERIFY(::UpdateWindow(mWnd
));
2574 nsWindow::MakeFullScreen(PRBool aFullScreen
)
2576 #if WINCE_WINDOWS_MOBILE
2579 SetForegroundWindow(mWnd
);
2580 if (nsWindowCE::sMenuBarShown
) {
2582 memset(&sipInfo
, 0, sizeof(SIPINFO
));
2583 sipInfo
.cbSize
= sizeof(SIPINFO
);
2584 if (SipGetInfo(&sipInfo
))
2585 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
),
2586 sipInfo
.rcVisibleDesktop
.bottom
);
2588 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
),
2589 GetSystemMetrics(SM_CYSCREEN
));
2591 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle
, &menuBarRect
) &&
2592 menuBarRect
.top
< rc
.bottom
)
2593 rc
.bottom
= menuBarRect
.top
;
2594 SHFullScreen(mWnd
, SHFS_HIDETASKBAR
| SHFS_HIDESTARTICON
| SHFS_SHOWSIPBUTTON
);
2597 SHFullScreen(mWnd
, SHFS_HIDETASKBAR
| SHFS_HIDESTARTICON
| SHFS_HIDESIPBUTTON
);
2598 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
), GetSystemMetrics(SM_CYSCREEN
));
2602 SHFullScreen(mWnd
, SHFS_SHOWTASKBAR
| SHFS_SHOWSTARTICON
);
2603 SystemParametersInfo(SPI_GETWORKAREA
, 0, &rc
, FALSE
);
2607 mSizeMode
= nsSizeMode_Fullscreen
;
2609 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2610 HideWindowChrome(aFullScreen
);
2611 Resize(rc
.left
, rc
.top
, rc
.right
-rc
.left
, rc
.bottom
-rc
.top
, PR_TRUE
);
2618 if (mSizeMode
!= nsSizeMode_Fullscreen
)
2619 mOldSizeMode
= mSizeMode
;
2620 SetSizeMode(nsSizeMode_Fullscreen
);
2622 SetSizeMode(mOldSizeMode
);
2625 UpdateNonClientMargins();
2627 // Will call hide chrome, reposition window. Note this will
2628 // also cache dimensions for restoration, so it should only
2629 // be called once per fullscreen request.
2630 return nsBaseWidget::MakeFullScreen(aFullScreen
);
2634 /**************************************************************
2636 * SECTION: nsIWidget::Update
2638 * Force a synchronous repaint of the window.
2640 **************************************************************/
2642 NS_IMETHODIMP
nsWindow::Update()
2644 nsresult rv
= NS_OK
;
2646 // updates can come through for windows no longer holding an mWnd during
2647 // deletes triggered by JavaScript in buttons with mouse feedback
2649 VERIFY(::UpdateWindow(mWnd
));
2654 /**************************************************************
2656 * SECTION: nsIWidget::Scroll
2658 * Scroll this widget.
2660 **************************************************************/
2663 ClipRegionContainedInRect(const nsTArray
<nsIntRect
>& aClipRects
,
2664 const nsIntRect
& aRect
)
2666 for (PRUint32 i
= 0; i
< aClipRects
.Length(); ++i
) {
2667 if (!aRect
.Contains(aClipRects
[i
]))
2673 // This function determines whether the given window has a descendant that
2674 // does not intersect the given aScreenRect. If we encounter a window owned
2675 // by another thread (which includes another process, since thread IDs
2676 // are unique system-wide), then we give up and conservatively return true.
2678 HasDescendantWindowOutsideRect(DWORD aThisThreadID
, HWND aWnd
,
2679 const RECT
& aScreenRect
)
2681 // If the window is owned by another thread, give up now, don't try to
2682 // look at its children since they could change asynchronously.
2683 // XXX should we try harder here for out-of-process plugins?
2684 if (GetWindowThreadProcessId(aWnd
, NULL
) != aThisThreadID
) {
2687 for (HWND child
= ::GetWindow(aWnd
, GW_CHILD
); child
;
2688 child
= ::GetWindow(child
, GW_HWNDNEXT
)) {
2689 RECT childScreenRect
;
2690 ::GetWindowRect(child
, &childScreenRect
);
2692 if (!::IntersectRect(&result
, &childScreenRect
, &aScreenRect
)) {
2696 if (HasDescendantWindowOutsideRect(aThisThreadID
, child
, aScreenRect
)) {
2705 InvalidateRgnInWindowSubtree(HWND aWnd
, HRGN aRgn
, HRGN aTmpRgn
)
2708 ::GetClientRect(aWnd
, &clientRect
);
2709 ::SetRectRgn(aTmpRgn
, clientRect
.left
, clientRect
.top
,
2710 clientRect
.right
, clientRect
.bottom
);
2711 if (::CombineRgn(aTmpRgn
, aTmpRgn
, aRgn
, RGN_AND
) == NULLREGION
) {
2715 ::InvalidateRgn(aWnd
, aTmpRgn
, FALSE
);
2717 for (HWND child
= ::GetWindow(aWnd
, GW_CHILD
); child
;
2718 child
= ::GetWindow(child
, GW_HWNDNEXT
)) {
2719 POINT pt
= { 0, 0 };
2720 ::MapWindowPoints(child
, aWnd
, &pt
, 1);
2721 ::OffsetRgn(aRgn
, -pt
.x
, -pt
.y
);
2722 InvalidateRgnInWindowSubtree(child
, aRgn
, aTmpRgn
);
2723 ::OffsetRgn(aRgn
, pt
.x
, pt
.y
);
2728 nsWindow::Scroll(const nsIntPoint
& aDelta
,
2729 const nsTArray
<nsIntRect
>& aDestRects
,
2730 const nsTArray
<Configuration
>& aConfigurations
)
2732 // We use SW_SCROLLCHILDREN if all the windows that intersect the
2733 // affected area are moving by the scroll amount.
2734 // First, build the set of widgets that are to be moved by the scroll
2736 // At the same time, set the clip region of all changed windows to the
2737 // intersection of the current and new regions.
2738 nsTHashtable
<nsPtrHashKey
<nsWindow
> > scrolledWidgets
;
2739 scrolledWidgets
.Init();
2740 for (PRUint32 i
= 0; i
< aConfigurations
.Length(); ++i
) {
2741 const Configuration
& configuration
= aConfigurations
[i
];
2742 nsWindow
* w
= static_cast<nsWindow
*>(configuration
.mChild
);
2743 NS_ASSERTION(w
->GetParent() == this,
2744 "Configured widget is not a child");
2745 if (configuration
.mBounds
== w
->mBounds
+ aDelta
) {
2746 scrolledWidgets
.PutEntry(w
);
2748 w
->SetWindowClipRegion(configuration
.mClipRegion
, PR_TRUE
);
2751 // Create temporary regions
2752 HRGN updateRgn
= ::CreateRectRgn(0, 0, 0, 0);
2757 HRGN destRgn
= ::CreateRectRgn(0, 0, 0, 0);
2760 ::DeleteObject((HGDIOBJ
)updateRgn
);
2764 DWORD ourThreadID
= GetWindowThreadProcessId(mWnd
, NULL
);
2766 for (BlitRectIter
iter(aDelta
, aDestRects
); !iter
.IsDone(); ++iter
) {
2767 const nsIntRect
& destRect
= iter
.Rect();
2768 nsIntRect affectedRect
;
2769 affectedRect
.UnionRect(destRect
, destRect
- aDelta
);
2770 UINT flags
= SW_SCROLLCHILDREN
;
2771 // Now check if any of our children would be affected by
2772 // SW_SCROLLCHILDREN but not supposed to scroll.
2773 for (nsWindow
* w
= static_cast<nsWindow
*>(GetFirstChild()); w
;
2774 w
= static_cast<nsWindow
*>(w
->GetNextSibling())) {
2775 if (w
->mBounds
.Intersects(affectedRect
)) {
2776 // This child will be affected
2777 nsPtrHashKey
<nsWindow
>* entry
= scrolledWidgets
.GetEntry(w
);
2779 // It's supposed to be scrolled, so we can still use
2780 // SW_SCROLLCHILDREN. But don't allow SW_SCROLLCHILDREN to be
2781 // used on it again by a later rectangle; we don't want it to
2783 scrolledWidgets
.RawRemoveEntry(entry
);
2785 nsIntPoint screenOffset
= WidgetToScreenOffset();
2786 RECT screenAffectedRect
= {
2787 screenOffset
.x
+ affectedRect
.x
,
2788 screenOffset
.y
+ affectedRect
.y
,
2789 screenOffset
.x
+ affectedRect
.XMost(),
2790 screenOffset
.y
+ affectedRect
.YMost()
2792 if (HasDescendantWindowOutsideRect(ourThreadID
, w
->mWnd
,
2793 screenAffectedRect
)) {
2794 // SW_SCROLLCHILDREN seems to not move descendant windows
2795 // that don't intersect the scrolled rectangle, *even if* the
2796 // immediate child window of the scrolled window *does* intersect
2797 // the scrolled window. So if w has a descendant window
2798 // that would not be moved, SW_SCROLLCHILDREN will hopelessly mess
2799 // things up and we must not use it.
2800 flags
&= ~SW_SCROLLCHILDREN
;
2803 flags
&= ~SW_SCROLLCHILDREN
;
2804 // We may have removed some children from scrolledWidgets even
2805 // though we decide here to not use SW_SCROLLCHILDREN. That's OK,
2806 // it just means that we might not use SW_SCROLLCHILDREN
2807 // for a later rectangle when we could have.
2813 if (flags
& SW_SCROLLCHILDREN
2814 #ifdef CAIRO_HAS_D2D_SURFACE
2815 && !mD2DWindowSurface
2818 // ScrollWindowEx will send WM_MOVE to each moved window to tell it
2819 // its new position. Unfortunately those messages don't reach our
2820 // WM_MOVE handler for some plugins, so we have to update their
2821 // mBounds here. For windows that do receive WM_MOVE, this is OK,
2822 // they'll just overwrite mBounds again with the correct value.
2823 for (nsWindow
* w
= static_cast<nsWindow
*>(GetFirstChild()); w
;
2824 w
= static_cast<nsWindow
*>(w
->GetNextSibling())) {
2825 if (w
->mBounds
.Intersects(affectedRect
)) {
2826 w
->mBounds
+= aDelta
;
2831 RECT clip
= { affectedRect
.x
, affectedRect
.y
, affectedRect
.XMost(), affectedRect
.YMost() };
2832 #ifdef CAIRO_HAS_D2D_SURFACE
2833 if (mD2DWindowSurface
) {
2834 mD2DWindowSurface
->Scroll(aDelta
, affectedRect
);
2836 for (PRUint32 i
= 0; i
< aConfigurations
.Length(); ++i
) {
2837 const Configuration
& configuration
= aConfigurations
[i
];
2838 nsWindow
* w
= static_cast<nsWindow
*>(configuration
.mChild
);
2839 w
->Invalidate(PR_FALSE
);
2842 // Get the system clip twice, offset one by the delta. This will make
2843 // systemClip contain the area of the systemClip, and movedSystemClip
2844 // contain the area after scrolling that was covered by the systemClip.
2845 HRGN systemClip
= ::CreateRectRgn(0, 0, 0, 0);
2846 HRGN movedSystemClip
= ::CreateRectRgn(0, 0, 0, 0);
2847 HDC dc
= ::GetDC(mWnd
);
2848 ::GetRandomRgn(dc
, systemClip
, SYSRGN
);
2849 ::GetRandomRgn(dc
, movedSystemClip
, SYSRGN
);
2850 ::OffsetRgn(movedSystemClip
, aDelta
.x
, aDelta
.y
);
2852 // RGN_DIFF will return the parts inside 'systemClip' but -not- inside
2853 // movedSystemClip. This is the area that was clipped (and possibly not
2854 // properly updated) before.
2855 ::CombineRgn(systemClip
, systemClip
, movedSystemClip
, RGN_DIFF
);
2857 // The systemClip is in screen coordinates, we need client coordinates.
2859 ::ClientToScreen(mWnd
, &p
);
2860 ::OffsetRgn(systemClip
, -p
.x
, -p
.y
);
2862 ::GetUpdateRgn(mWnd
, updateRgn
, FALSE
);
2863 ::OffsetRgn(updateRgn
, aDelta
.x
, aDelta
.y
);
2864 ::CombineRgn(updateRgn
, updateRgn
, systemClip
, RGN_OR
);
2866 ::DeleteObject((HGDIOBJ
)systemClip
);
2867 ::DeleteObject((HGDIOBJ
)movedSystemClip
);
2868 ::ReleaseDC(mWnd
, dc
);
2871 ::ScrollWindowEx(mWnd
, aDelta
.x
, aDelta
.y
, &clip
, &clip
, updateRgn
, NULL
, flags
);
2872 #ifdef CAIRO_HAS_D2D_SURFACE
2875 ::SetRectRgn(destRgn
, destRect
.x
, destRect
.y
, destRect
.XMost(), destRect
.YMost());
2876 ::CombineRgn(updateRgn
, updateRgn
, destRgn
, RGN_AND
);
2877 if (flags
& SW_SCROLLCHILDREN
) {
2878 for (nsWindow
* w
= static_cast<nsWindow
*>(GetFirstChild()); w
;
2879 w
= static_cast<nsWindow
*>(w
->GetNextSibling())) {
2880 if ((w
->mBounds
- aDelta
).Intersects(affectedRect
)) {
2881 // Widgets that have been scrolled by SW_SCROLLCHILDREN but which
2882 // were, or are, partly outside the scroll area must be invalidated
2883 // because SW_SCROLLCHILDREN doesn't update parts of widgets outside
2884 // the area it scrolled, even if it moved them.
2885 nsAutoTArray
<nsIntRect
,1> clipRegion
;
2886 w
->GetWindowClipRegion(&clipRegion
);
2887 if (!ClipRegionContainedInRect(clipRegion
,
2888 destRect
- w
->mBounds
.TopLeft()) ||
2889 !ClipRegionContainedInRect(clipRegion
,
2890 destRect
- (w
->mBounds
.TopLeft() - aDelta
))) {
2891 ::SetRectRgn(destRgn
, w
->mBounds
.x
, w
->mBounds
.y
, w
->mBounds
.XMost(), w
->mBounds
.YMost());
2892 ::CombineRgn(updateRgn
, updateRgn
, destRgn
, RGN_OR
);
2897 InvalidateRgnInWindowSubtree(mWnd
, updateRgn
, destRgn
);
2899 ::InvalidateRgn(mWnd
, updateRgn
, FALSE
);
2903 ::DeleteObject((HGDIOBJ
)updateRgn
);
2904 ::DeleteObject((HGDIOBJ
)destRgn
);
2906 // Now make sure all children actually get positioned, sized and clipped
2907 // correctly. If SW_SCROLLCHILDREN already moved widgets to their correct
2908 // locations, then the SetWindowPos calls this triggers will just be
2910 ConfigureChildren(aConfigurations
);
2913 /**************************************************************
2915 * SECTION: Native data storage
2917 * nsIWidget::GetNativeData
2918 * nsIWidget::FreeNativeData
2920 * Set or clear native data based on a constant.
2922 **************************************************************/
2924 // Return some native data according to aDataType
2925 void* nsWindow::GetNativeData(PRUint32 aDataType
)
2927 switch (aDataType
) {
2928 case NS_NATIVE_PLUGIN_PORT
:
2929 case NS_NATIVE_WIDGET
:
2930 case NS_NATIVE_WINDOW
:
2932 case NS_NATIVE_GRAPHIC
:
2933 // XXX: This is sleezy!! Remember to Release the DC after using it!
2935 return (void*)(eTransparencyTransparent
== mTransparencyMode
) ?
2936 mMemoryDC
: ::GetDC(mWnd
);
2938 return (void*)::GetDC(mWnd
);
2941 #ifdef NS_ENABLE_TSF
2942 case NS_NATIVE_TSF_THREAD_MGR
:
2943 return nsTextStore::GetThreadMgr();
2944 case NS_NATIVE_TSF_CATEGORY_MGR
:
2945 return nsTextStore::GetCategoryMgr();
2946 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR
:
2947 return nsTextStore::GetDisplayAttrMgr();
2948 #endif //NS_ENABLE_TSF
2957 // Free some native data according to aDataType
2958 void nsWindow::FreeNativeData(void * data
, PRUint32 aDataType
)
2962 case NS_NATIVE_GRAPHIC
:
2964 if (eTransparencyTransparent
!= mTransparencyMode
)
2965 ::ReleaseDC(mWnd
, (HDC
)data
);
2967 ::ReleaseDC(mWnd
, (HDC
)data
);
2970 case NS_NATIVE_WIDGET
:
2971 case NS_NATIVE_WINDOW
:
2972 case NS_NATIVE_PLUGIN_PORT
:
2979 /**************************************************************
2981 * SECTION: nsIWidget::SetTitle
2983 * Set the main windows title text.
2985 **************************************************************/
2987 NS_METHOD
nsWindow::SetTitle(const nsAString
& aTitle
)
2989 const nsString
& strTitle
= PromiseFlatString(aTitle
);
2990 ::SendMessageW(mWnd
, WM_SETTEXT
, (WPARAM
)0, (LPARAM
)(LPCWSTR
)strTitle
.get());
2994 /**************************************************************
2996 * SECTION: nsIWidget::SetIcon
2998 * Set the main windows icon.
3000 **************************************************************/
3002 NS_METHOD
nsWindow::SetIcon(const nsAString
& aIconSpec
)
3005 // Assume the given string is a local identifier for an icon file.
3007 nsCOMPtr
<nsILocalFile
> iconFile
;
3008 ResolveIconName(aIconSpec
, NS_LITERAL_STRING(".ico"),
3009 getter_AddRefs(iconFile
));
3011 return NS_OK
; // not an error if icon is not found
3013 nsAutoString iconPath
;
3014 iconFile
->GetPath(iconPath
);
3016 // XXX this should use MZLU (see bug 239279)
3020 HICON bigIcon
= (HICON
)::LoadImageW(NULL
,
3021 (LPCWSTR
)iconPath
.get(),
3023 ::GetSystemMetrics(SM_CXICON
),
3024 ::GetSystemMetrics(SM_CYICON
),
3026 HICON smallIcon
= (HICON
)::LoadImageW(NULL
,
3027 (LPCWSTR
)iconPath
.get(),
3029 ::GetSystemMetrics(SM_CXSMICON
),
3030 ::GetSystemMetrics(SM_CYSMICON
),
3034 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_BIG
, (LPARAM
)bigIcon
);
3036 ::DestroyIcon(icon
);
3038 #ifdef DEBUG_SetIcon
3040 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
3041 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath
.get(), ::GetLastError() );
3045 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_SMALL
, (LPARAM
)smallIcon
);
3047 ::DestroyIcon(icon
);
3049 #ifdef DEBUG_SetIcon
3051 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
3052 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath
.get(), ::GetLastError() );
3059 /**************************************************************
3061 * SECTION: nsIWidget::WidgetToScreenOffset
3063 * Return this widget's origin in screen coordinates.
3065 **************************************************************/
3067 nsIntPoint
nsWindow::WidgetToScreenOffset()
3072 ::ClientToScreen(mWnd
, &point
);
3073 return nsIntPoint(point
.x
, point
.y
);
3076 nsIntSize
nsWindow::ClientToWindowSize(const nsIntSize
& aClientSize
)
3078 if (!IsPopupWithTitleBar())
3081 // just use (200, 200) as the position
3085 r
.right
= 200 + aClientSize
.width
;
3086 r
.bottom
= 200 + aClientSize
.height
;
3087 ::AdjustWindowRectEx(&r
, WindowStyle(), PR_FALSE
, WindowExStyle());
3089 return nsIntSize(r
.right
- r
.left
, r
.bottom
- r
.top
);
3092 /**************************************************************
3094 * SECTION: nsIWidget::EnableDragDrop
3096 * Enables/Disables drag and drop of files on this widget.
3098 **************************************************************/
3100 #if !defined(WINCE) // implemented in nsWindowCE.cpp
3101 NS_METHOD
nsWindow::EnableDragDrop(PRBool aEnable
)
3103 NS_ASSERTION(mWnd
, "nsWindow::EnableDragDrop() called after Destroy()");
3105 nsresult rv
= NS_ERROR_FAILURE
;
3107 if (nsnull
== mNativeDragTarget
) {
3108 mNativeDragTarget
= new nsNativeDragTarget(this);
3109 if (NULL
!= mNativeDragTarget
) {
3110 mNativeDragTarget
->AddRef();
3111 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
,TRUE
,FALSE
)) {
3112 if (S_OK
== ::RegisterDragDrop(mWnd
, (LPDROPTARGET
)mNativeDragTarget
)) {
3119 if (nsnull
!= mWnd
&& NULL
!= mNativeDragTarget
) {
3120 ::RevokeDragDrop(mWnd
);
3121 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
, FALSE
, TRUE
)) {
3124 mNativeDragTarget
->DragCancel();
3125 NS_RELEASE(mNativeDragTarget
);
3132 /**************************************************************
3134 * SECTION: nsIWidget::CaptureMouse
3136 * Enables/Disables system mouse capture.
3138 **************************************************************/
3140 NS_METHOD
nsWindow::CaptureMouse(PRBool aCapture
)
3142 if (!nsToolkit::gMouseTrailer
) {
3143 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3148 nsToolkit::gMouseTrailer
->SetCaptureWindow(mWnd
);
3151 nsToolkit::gMouseTrailer
->SetCaptureWindow(NULL
);
3154 mIsInMouseCapture
= aCapture
;
3158 /**************************************************************
3160 * SECTION: nsIWidget::CaptureRollupEvents
3162 * Dealing with event rollup on destroy for popups. Enables &
3163 * Disables system capture of any and all events that would
3164 * cause a dropdown to be rolled up.
3166 **************************************************************/
3168 NS_IMETHODIMP
nsWindow::CaptureRollupEvents(nsIRollupListener
* aListener
,
3169 nsIMenuRollup
* aMenuRollup
,
3171 PRBool aConsumeRollupEvent
)
3174 /* we haven't bothered carrying a weak reference to sRollupWidget because
3175 we believe lifespan is properly scoped. this next assertion helps
3176 assure that remains true. */
3177 NS_ASSERTION(!sRollupWidget
, "rollup widget reassigned before release");
3178 sRollupConsumeEvent
= aConsumeRollupEvent
;
3179 NS_IF_RELEASE(sRollupWidget
);
3180 NS_IF_RELEASE(sMenuRollup
);
3181 sRollupListener
= aListener
;
3182 sMenuRollup
= aMenuRollup
;
3183 NS_IF_ADDREF(aMenuRollup
);
3184 sRollupWidget
= this;
3188 if (!sMsgFilterHook
&& !sCallProcHook
&& !sCallMouseHook
) {
3189 RegisterSpecialDropdownHooks();
3191 sProcessHook
= PR_TRUE
;
3195 sRollupListener
= nsnull
;
3196 NS_IF_RELEASE(sMenuRollup
);
3197 NS_IF_RELEASE(sRollupWidget
);
3200 sProcessHook
= PR_FALSE
;
3201 UnregisterSpecialDropdownHooks();
3208 /**************************************************************
3210 * SECTION: nsIWidget::GetAttention
3212 * Bring this window to the user's attention.
3214 **************************************************************/
3216 // Draw user's attention to this window until it comes to foreground.
3218 nsWindow::GetAttention(PRInt32 aCycleCount
)
3223 return NS_ERROR_NOT_INITIALIZED
;
3225 // Don't flash if the flash count is 0 or if the
3226 // top level window is already active.
3227 HWND fgWnd
= ::GetForegroundWindow();
3228 if (aCycleCount
== 0 || fgWnd
== GetTopLevelHWND(mWnd
))
3231 HWND flashWnd
= mWnd
;
3232 while (HWND ownerWnd
= ::GetWindow(flashWnd
, GW_OWNER
)) {
3233 flashWnd
= ownerWnd
;
3236 // Don't flash if the owner window is active either.
3237 if (fgWnd
== flashWnd
)
3240 DWORD defaultCycleCount
= 0;
3241 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT
, 0, &defaultCycleCount
, 0);
3243 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
3244 FLASHW_ALL
, aCycleCount
> 0 ? aCycleCount
: defaultCycleCount
, 0 };
3245 ::FlashWindowEx(&flashInfo
);
3250 void nsWindow::StopFlashing()
3253 HWND flashWnd
= mWnd
;
3254 while (HWND ownerWnd
= ::GetWindow(flashWnd
, GW_OWNER
)) {
3255 flashWnd
= ownerWnd
;
3258 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
3259 FLASHW_STOP
, 0, 0 };
3260 ::FlashWindowEx(&flashInfo
);
3264 /**************************************************************
3266 * SECTION: nsIWidget::HasPendingInputEvent
3268 * Ask whether there user input events pending. All input events are
3269 * included, including those not targeted at this nsIwidget instance.
3271 **************************************************************/
3274 nsWindow::HasPendingInputEvent()
3276 // If there is pending input or the user is currently
3277 // moving the window then return true.
3278 // Note: When the user is moving the window WIN32 spins
3279 // a separate event loop and input events are not
3280 // reported to the application.
3281 if (HIWORD(GetQueueStatus(QS_INPUT
)))
3286 GUITHREADINFO guiInfo
;
3287 guiInfo
.cbSize
= sizeof(GUITHREADINFO
);
3288 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo
))
3290 return GUI_INMOVESIZE
== (guiInfo
.flags
& GUI_INMOVESIZE
);
3294 /**************************************************************
3296 * SECTION: nsIWidget::GetLayerManager
3298 * Get the layer manager associated with this widget.
3300 **************************************************************/
3302 mozilla::layers::LayerManager
*
3303 nsWindow::GetLayerManager()
3305 nsWindow
*topWindow
= GetNSWindowPtr(GetTopLevelHWND(mWnd
, PR_TRUE
));
3308 return nsBaseWidget::GetLayerManager();
3311 if (topWindow
->GetAcceleratedRendering() != mUseAcceleratedRendering
) {
3312 mLayerManager
= NULL
;
3313 mUseAcceleratedRendering
= topWindow
->GetAcceleratedRendering();
3317 if (!mLayerManager
) {
3318 if (mUseAcceleratedRendering
) {
3319 nsCOMPtr
<nsIPrefBranch2
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
3321 PRBool allowAcceleration
= PR_TRUE
;
3322 PRBool preferOpenGL
= PR_FALSE
;
3324 prefs
->GetBoolPref("mozilla.widget.accelerated-layers",
3325 &allowAcceleration
);
3326 prefs
->GetBoolPref("mozilla.layers.prefer-opengl",
3330 if (allowAcceleration
) {
3331 #ifdef MOZ_ENABLE_D3D9_LAYER
3332 if (!preferOpenGL
) {
3333 nsRefPtr
<mozilla::layers::LayerManagerD3D9
> layerManager
=
3334 new mozilla::layers::LayerManagerD3D9(this);
3335 if (layerManager
->Initialize()) {
3336 mLayerManager
= layerManager
;
3340 if (!mLayerManager
) {
3341 nsRefPtr
<mozilla::layers::LayerManagerOGL
> layerManager
=
3342 new mozilla::layers::LayerManagerOGL(this);
3343 if (layerManager
->Initialize()) {
3344 mLayerManager
= layerManager
;
3352 return nsBaseWidget::GetLayerManager();
3355 /**************************************************************
3357 * SECTION: nsIWidget::GetThebesSurface
3359 * Get the Thebes surface associated with this widget.
3361 **************************************************************/
3363 gfxASurface
*nsWindow::GetThebesSurface()
3365 #ifdef CAIRO_HAS_D2D_SURFACE
3366 if (mD2DWindowSurface
) {
3367 return mD2DWindowSurface
;
3371 return (new gfxWindowsSurface(mPaintDC
));
3373 #ifdef CAIRO_HAS_D2D_SURFACE
3374 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3375 gfxWindowsPlatform::RENDER_DIRECT2D
) {
3376 gfxASurface::gfxContentType content
= gfxASurface::CONTENT_COLOR
;
3377 #if defined(MOZ_XUL)
3378 if (mTransparencyMode
!= eTransparencyOpaque
) {
3379 content
= gfxASurface::CONTENT_COLOR_ALPHA
;
3382 return (new gfxD2DSurface(mWnd
, content
));
3385 PRUint32 flags
= gfxWindowsSurface::FLAG_TAKE_DC
;
3386 if (mTransparencyMode
!= eTransparencyOpaque
) {
3387 flags
|= gfxWindowsSurface::FLAG_IS_TRANSPARENT
;
3389 return (new gfxWindowsSurface(mWnd
, flags
));
3390 #ifdef CAIRO_HAS_D2D_SURFACE
3395 /**************************************************************
3397 * SECTION: nsIWidget::OnDefaultButtonLoaded
3399 * Called after the dialog is loaded and it has a default button.
3401 **************************************************************/
3404 nsWindow::OnDefaultButtonLoaded(const nsIntRect
&aButtonRect
)
3407 return NS_ERROR_NOT_IMPLEMENTED
;
3409 if (aButtonRect
.IsEmpty())
3412 // Don't snap when we are not active.
3413 HWND activeWnd
= ::GetActiveWindow();
3414 if (activeWnd
!= ::GetForegroundWindow() ||
3415 GetTopLevelHWND(mWnd
, PR_TRUE
) != GetTopLevelHWND(activeWnd
, PR_TRUE
)) {
3419 PRBool isAlwaysSnapCursor
= PR_FALSE
;
3420 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
3422 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
3423 prefs
->GetBranch(nsnull
, getter_AddRefs(prefBranch
));
3425 prefBranch
->GetBoolPref("ui.cursor_snapping.always_enabled",
3426 &isAlwaysSnapCursor
);
3430 if (!isAlwaysSnapCursor
) {
3431 BOOL snapDefaultButton
;
3432 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON
, 0,
3433 &snapDefaultButton
, 0) || !snapDefaultButton
)
3437 nsIntRect widgetRect
;
3438 nsresult rv
= GetScreenBounds(widgetRect
);
3439 NS_ENSURE_SUCCESS(rv
, rv
);
3440 nsIntRect
buttonRect(aButtonRect
+ widgetRect
.TopLeft());
3442 nsIntPoint
centerOfButton(buttonRect
.x
+ buttonRect
.width
/ 2,
3443 buttonRect
.y
+ buttonRect
.height
/ 2);
3444 // The center of the button can be outside of the widget.
3445 // E.g., it could be hidden by scrolling.
3446 if (!widgetRect
.Contains(centerOfButton
)) {
3450 if (!::SetCursorPos(centerOfButton
.x
, centerOfButton
.y
)) {
3451 NS_ERROR("SetCursorPos failed");
3452 return NS_ERROR_FAILURE
;
3459 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta
,
3460 PRBool aIsHorizontal
,
3461 PRInt32
&aOverriddenDelta
)
3463 // The default vertical and horizontal scrolling speed is 3, this is defined
3464 // on the document of SystemParametersInfo in MSDN.
3465 const PRInt32 kSystemDefaultScrollingSpeed
= 3;
3467 PRInt32 absOriginDelta
= PR_ABS(aOriginalDelta
);
3469 // Compute the simple overridden speed.
3470 PRInt32 absComputedOverriddenDelta
;
3472 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta
, aIsHorizontal
,
3473 absComputedOverriddenDelta
);
3474 NS_ENSURE_SUCCESS(rv
, rv
);
3476 aOverriddenDelta
= aOriginalDelta
;
3478 if (absComputedOverriddenDelta
== absOriginDelta
) {
3479 // We don't override now.
3483 // Otherwise, we should check whether the user customized the system settings
3484 // or not. If the user did it, we should respect the will.
3486 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &systemSpeed
, 0)) {
3487 return NS_ERROR_FAILURE
;
3489 // The default vertical scrolling speed is 3, this is defined on the document
3490 // of SystemParametersInfo in MSDN.
3491 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
3495 // Only Vista and later, Windows has the system setting of horizontal
3496 // scrolling by the mouse wheel.
3497 if (GetWindowsVersion() >= VISTA_VERSION
) {
3498 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS
, 0, &systemSpeed
, 0)) {
3499 return NS_ERROR_FAILURE
;
3501 // The default horizontal scrolling speed is 3, this is defined on the
3502 // document of SystemParametersInfo in MSDN.
3503 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
3508 // Limit the overridden delta value from the system settings. The mouse
3509 // driver might accelerate the scrolling speed already. If so, we shouldn't
3510 // override the scrolling speed for preventing the unexpected high speed
3512 PRInt32 absDeltaLimit
;
3514 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed
,
3515 aIsHorizontal
, absDeltaLimit
);
3516 NS_ENSURE_SUCCESS(rv
, rv
);
3518 // If the given delta is larger than our computed limitation value, the delta
3519 // was accelerated by the mouse driver. So, we should do nothing here.
3520 if (absDeltaLimit
<= absOriginDelta
) {
3524 absComputedOverriddenDelta
=
3525 PR_MIN(absComputedOverriddenDelta
, absDeltaLimit
);
3527 aOverriddenDelta
= (aOriginalDelta
> 0) ? absComputedOverriddenDelta
:
3528 -absComputedOverriddenDelta
;
3532 /**************************************************************
3533 **************************************************************
3535 ** BLOCK: Moz Events
3537 ** Moz GUI event management.
3539 **************************************************************
3540 **************************************************************/
3542 /**************************************************************
3544 * SECTION: Mozilla event initialization
3546 * Helpers for initializing moz events.
3548 **************************************************************/
3550 // Event intialization
3551 MSG
nsWindow::InitMSG(UINT aMessage
, WPARAM wParam
, LPARAM lParam
)
3554 msg
.message
= aMessage
;
3555 msg
.wParam
= wParam
;
3556 msg
.lParam
= lParam
;
3560 void nsWindow::InitEvent(nsGUIEvent
& event
, nsIntPoint
* aPoint
)
3562 if (nsnull
== aPoint
) { // use the point from the event
3563 // get the message position in client coordinates
3566 DWORD pos
= ::GetMessagePos();
3569 cpos
.x
= GET_X_LPARAM(pos
);
3570 cpos
.y
= GET_Y_LPARAM(pos
);
3572 ::ScreenToClient(mWnd
, &cpos
);
3573 event
.refPoint
.x
= cpos
.x
;
3574 event
.refPoint
.y
= cpos
.y
;
3576 event
.refPoint
.x
= 0;
3577 event
.refPoint
.y
= 0;
3581 // use the point override if provided
3582 event
.refPoint
.x
= aPoint
->x
;
3583 event
.refPoint
.y
= aPoint
->y
;
3587 event
.time
= ::GetMessageTime();
3589 event
.time
= PR_Now() / 1000;
3592 mLastPoint
= event
.refPoint
;
3595 /**************************************************************
3597 * SECTION: Moz event dispatch helpers
3599 * Helpers for dispatching different types of moz events.
3601 **************************************************************/
3603 // Main event dispatch. Invokes callback and ProcessEvent method on
3604 // Event Listener object. Part of nsIWidget.
3605 NS_IMETHODIMP
nsWindow::DispatchEvent(nsGUIEvent
* event
, nsEventStatus
& aStatus
)
3607 #ifdef WIDGET_DEBUG_OUTPUT
3608 debug_DumpEvent(stdout
,
3611 nsCAutoString("something"),
3613 #endif // WIDGET_DEBUG_OUTPUT
3615 aStatus
= nsEventStatus_eIgnore
;
3617 // skip processing of suppressed blur events
3618 if (event
->message
== NS_DEACTIVATE
&& BlurEventsSuppressed())
3621 // Top level windows can have a view attached which requires events be sent
3622 // to the underlying base window and the view. Added when we combined the
3623 // base chrome window with the main content child for nc client area (title
3625 if (mViewCallback
) {
3626 // A subset of events are sent to the base xul window first
3627 switch(event
->message
) {
3628 // send to the base window (view mgr ignores these for the view)
3629 case NS_UISTATECHANGED
:
3634 (*mEventCallback
)(event
); // web shell / xul window
3637 // sent to the base window, then to the view
3642 (*mEventCallback
)(event
); // web shell / xul window
3645 // attached view events
3646 aStatus
= (*mViewCallback
)(event
);
3648 else if (mEventCallback
) {
3649 aStatus
= (*mEventCallback
)(event
);
3652 // the window can be destroyed during processing of seemingly innocuous events like, say,
3653 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3654 // which causes problems with the deleted window. therefore:
3655 if (mOnDestroyCalled
)
3656 aStatus
= nsEventStatus_eConsumeNoDefault
;
3660 PRBool
nsWindow::DispatchStandardEvent(PRUint32 aMsg
)
3662 nsGUIEvent
event(PR_TRUE
, aMsg
, this);
3665 PRBool result
= DispatchWindowEvent(&event
);
3669 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
* event
)
3671 nsEventStatus status
;
3672 DispatchEvent(event
, status
);
3673 return ConvertStatus(status
);
3676 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
* event
, nsEventStatus
&aStatus
) {
3677 DispatchEvent(event
, aStatus
);
3678 return ConvertStatus(aStatus
);
3681 PRBool
nsWindow::DispatchKeyEvent(PRUint32 aEventType
, WORD aCharCode
,
3682 const nsTArray
<nsAlternativeCharCode
>* aAlternativeCharCodes
,
3683 UINT aVirtualCharCode
, const MSG
*aMsg
,
3684 const nsModifierKeyState
&aModKeyState
,
3689 nsKeyEvent
event(PR_TRUE
, aEventType
, this);
3690 nsIntPoint
point(0, 0);
3692 InitEvent(event
, &point
); // this add ref's event.widget
3694 event
.flags
|= aFlags
;
3695 event
.charCode
= aCharCode
;
3696 if (aAlternativeCharCodes
)
3697 event
.alternativeCharCodes
.AppendElements(*aAlternativeCharCodes
);
3698 event
.keyCode
= aVirtualCharCode
;
3702 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt
++,
3703 (NS_KEY_PRESS
== aEventType
) ? "PRESS" : (aEventType
== NS_KEY_UP
? "Up" : "Down"),
3704 event
.charCode
, event
.keyCode
);
3705 printf("Shift: %s Control %s Alt: %s \n",
3706 (mIsShiftDown
? "D" : "U"), (mIsControlDown
? "D" : "U"), (mIsAltDown
? "D" : "U"));
3707 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3708 IS_VK_DOWN(NS_VK_SHIFT
) ? 'S' : ' ',
3709 IS_VK_DOWN(NS_VK_CONTROL
) ? 'C' : ' ',
3710 IS_VK_DOWN(NS_VK_ALT
) ? 'A' : ' ',
3711 IS_VK_DOWN(VK_LSHIFT
) ? 'S' : ' ',
3712 IS_VK_DOWN(VK_LCONTROL
) ? 'C' : ' ',
3713 IS_VK_DOWN(VK_LMENU
) ? 'A' : ' ',
3714 IS_VK_DOWN(VK_RMENU
) ? 'A' : ' ',
3715 IS_VK_DOWN(VK_RCONTROL
) ? 'C' : ' ',
3716 IS_VK_DOWN(VK_RSHIFT
) ? 'S' : ' ');
3719 event
.isShift
= aModKeyState
.mIsShiftDown
;
3720 event
.isControl
= aModKeyState
.mIsControlDown
;
3721 event
.isMeta
= PR_FALSE
;
3722 event
.isAlt
= aModKeyState
.mIsAltDown
;
3724 NPEvent pluginEvent
;
3725 if (aMsg
&& PluginHasFocus()) {
3726 pluginEvent
.event
= aMsg
->message
;
3727 pluginEvent
.wParam
= aMsg
->wParam
;
3728 pluginEvent
.lParam
= aMsg
->lParam
;
3729 event
.pluginEvent
= (void *)&pluginEvent
;
3732 PRBool result
= DispatchWindowEvent(&event
);
3737 PRBool
nsWindow::DispatchCommandEvent(PRUint32 aEventCommand
)
3739 nsCOMPtr
<nsIAtom
> command
;
3740 switch (aEventCommand
) {
3741 case APPCOMMAND_BROWSER_BACKWARD
:
3742 command
= nsWidgetAtoms::Back
;
3744 case APPCOMMAND_BROWSER_FORWARD
:
3745 command
= nsWidgetAtoms::Forward
;
3747 case APPCOMMAND_BROWSER_REFRESH
:
3748 command
= nsWidgetAtoms::Reload
;
3750 case APPCOMMAND_BROWSER_STOP
:
3751 command
= nsWidgetAtoms::Stop
;
3753 case APPCOMMAND_BROWSER_SEARCH
:
3754 command
= nsWidgetAtoms::Search
;
3756 case APPCOMMAND_BROWSER_FAVORITES
:
3757 command
= nsWidgetAtoms::Bookmarks
;
3759 case APPCOMMAND_BROWSER_HOME
:
3760 command
= nsWidgetAtoms::Home
;
3765 nsCommandEvent
event(PR_TRUE
, nsWidgetAtoms::onAppCommand
, command
, this);
3768 DispatchWindowEvent(&event
);
3773 // Recursively dispatch synchronous paints for nsIWidget
3774 // descendants with invalidated rectangles.
3775 BOOL CALLBACK
nsWindow::DispatchStarvedPaints(HWND aWnd
, LPARAM aMsg
)
3777 LONG_PTR proc
= ::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
3778 if (proc
== (LONG_PTR
)&nsWindow::WindowProc
) {
3779 // its one of our windows so check to see if it has a
3780 // invalidated rect. If it does. Dispatch a synchronous
3782 if (GetUpdateRect(aWnd
, NULL
, FALSE
))
3783 VERIFY(::UpdateWindow(aWnd
));
3788 // Check for pending paints and dispatch any pending paint
3789 // messages for any nsIWidget which is a descendant of the
3790 // top-level window that *this* window is embedded within.
3792 // Note: We do not dispatch pending paint messages for non
3793 // nsIWidget managed windows.
3794 void nsWindow::DispatchPendingEvents()
3797 NS_WARNING("We were asked to dispatch pending events during painting, "
3798 "denying since that's unsafe.");
3802 // We need to ensure that reflow events do not get starved.
3803 // At the same time, we don't want to recurse through here
3804 // as that would prevent us from dispatching starved paints.
3805 static int recursionBlocker
= 0;
3806 if (recursionBlocker
++ == 0) {
3807 NS_ProcessPendingEvents(nsnull
, PR_MillisecondsToInterval(100));
3811 // Quickly check to see if there are any
3812 // paint events pending.
3813 if (::GetQueueStatus(QS_PAINT
)) {
3814 // Find the top level window.
3815 HWND topWnd
= GetTopLevelHWND(mWnd
);
3817 // Dispatch pending paints for all topWnd's descendant windows.
3818 // Note: EnumChildWindows enumerates all descendant windows not just
3821 ::EnumChildWindows(topWnd
, nsWindow::DispatchStarvedPaints
, NULL
);
3823 nsWindowCE::EnumChildWindows(topWnd
, nsWindow::DispatchStarvedPaints
, NULL
);
3828 // Deal with plugin events
3829 PRBool
nsWindow::DispatchPluginEvent(const MSG
&aMsg
)
3831 if (!PluginHasFocus())
3834 nsGUIEvent
event(PR_TRUE
, NS_PLUGIN_EVENT
, this);
3835 nsIntPoint
point(0, 0);
3836 InitEvent(event
, &point
);
3837 NPEvent pluginEvent
;
3838 pluginEvent
.event
= aMsg
.message
;
3839 pluginEvent
.wParam
= aMsg
.wParam
;
3840 pluginEvent
.lParam
= aMsg
.lParam
;
3841 event
.pluginEvent
= (void *)&pluginEvent
;
3842 return DispatchWindowEvent(&event
);
3845 PRBool
nsWindow::DispatchPluginEvent(UINT aMessage
,
3848 PRBool aDispatchPendingEvents
)
3850 PRBool ret
= DispatchPluginEvent(InitMSG(aMessage
, aWParam
, aLParam
));
3851 if (aDispatchPendingEvents
) {
3852 DispatchPendingEvents();
3857 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg
,
3861 ::GetMessageW(&msg
, mWnd
, aFirstMsg
, aLastMsg
);
3862 DispatchPluginEvent(msg
);
3865 // Deal with all sort of mouse event
3866 PRBool
nsWindow::DispatchMouseEvent(PRUint32 aEventType
, WPARAM wParam
,
3867 LPARAM lParam
, PRBool aIsContextMenuKey
,
3868 PRInt16 aButton
, PRUint16 aInputSource
)
3870 PRBool result
= PR_FALSE
;
3874 if (!mEventCallback
) {
3878 switch (aEventType
) {
3879 case NS_MOUSE_BUTTON_DOWN
:
3880 CaptureMouse(PR_TRUE
);
3883 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3884 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3885 case NS_MOUSE_BUTTON_UP
:
3888 if (!(wParam
& (MK_LBUTTON
| MK_MBUTTON
| MK_RBUTTON
)) && mIsInMouseCapture
)
3889 CaptureMouse(PR_FALSE
);
3897 nsIntPoint eventPoint
;
3898 eventPoint
.x
= GET_X_LPARAM(lParam
);
3899 eventPoint
.y
= GET_Y_LPARAM(lParam
);
3901 nsMouseEvent
event(PR_TRUE
, aEventType
, this, nsMouseEvent::eReal
,
3903 ? nsMouseEvent::eContextMenuKey
3904 : nsMouseEvent::eNormal
);
3905 if (aEventType
== NS_CONTEXTMENU
&& aIsContextMenuKey
) {
3906 nsIntPoint
zero(0, 0);
3907 InitEvent(event
, &zero
);
3909 InitEvent(event
, &eventPoint
);
3912 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
3913 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
3914 event
.isMeta
= PR_FALSE
;
3915 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
3916 event
.button
= aButton
;
3917 event
.inputSource
= aInputSource
;
3919 nsIntPoint mpScreen
= eventPoint
+ WidgetToScreenOffset();
3921 // Suppress mouse moves caused by widget creation
3922 if (aEventType
== NS_MOUSE_MOVE
)
3924 if ((sLastMouseMovePoint
.x
== mpScreen
.x
) && (sLastMouseMovePoint
.y
== mpScreen
.y
))
3926 sLastMouseMovePoint
.x
= mpScreen
.x
;
3927 sLastMouseMovePoint
.y
= mpScreen
.y
;
3930 PRBool insideMovementThreshold
= (abs(sLastMousePoint
.x
- eventPoint
.x
) < (short)::GetSystemMetrics(SM_CXDOUBLECLK
)) &&
3931 (abs(sLastMousePoint
.y
- eventPoint
.y
) < (short)::GetSystemMetrics(SM_CYDOUBLECLK
));
3935 case nsMouseEvent::eLeftButton
:
3936 eventButton
= VK_LBUTTON
;
3938 case nsMouseEvent::eMiddleButton
:
3939 eventButton
= VK_MBUTTON
;
3941 case nsMouseEvent::eRightButton
:
3942 eventButton
= VK_RBUTTON
;
3949 // Doubleclicks are used to set the click count, then changed to mousedowns
3950 // We're going to time double-clicks from mouse *up* to next mouse *down*
3952 LONG curMsgTime
= ::GetMessageTime();
3954 LONG curMsgTime
= PR_Now() / 1000;
3957 if (aEventType
== NS_MOUSE_DOUBLECLICK
) {
3958 event
.message
= NS_MOUSE_BUTTON_DOWN
;
3959 event
.button
= aButton
;
3960 sLastClickCount
= 2;
3962 else if (aEventType
== NS_MOUSE_BUTTON_UP
) {
3963 // remember when this happened for the next mouse down
3964 sLastMousePoint
.x
= eventPoint
.x
;
3965 sLastMousePoint
.y
= eventPoint
.y
;
3966 sLastMouseButton
= eventButton
;
3968 else if (aEventType
== NS_MOUSE_BUTTON_DOWN
) {
3969 // now look to see if we want to convert this to a double- or triple-click
3970 if (((curMsgTime
- sLastMouseDownTime
) < (LONG
)::GetDoubleClickTime()) && insideMovementThreshold
&&
3971 eventButton
== sLastMouseButton
) {
3974 // reset the click count, to count *this* click
3975 sLastClickCount
= 1;
3977 // Set last Click time on MouseDown only
3978 sLastMouseDownTime
= curMsgTime
;
3980 else if (aEventType
== NS_MOUSE_MOVE
&& !insideMovementThreshold
) {
3981 sLastClickCount
= 0;
3983 else if (aEventType
== NS_MOUSE_EXIT
) {
3984 event
.exit
= IsTopLevelMouseExit(mWnd
) ? nsMouseEvent::eTopLevel
: nsMouseEvent::eChild
;
3986 else if (aEventType
== NS_MOUSE_MOZHITTEST
)
3988 event
.flags
|= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH
;
3990 event
.clickCount
= sLastClickCount
;
3993 printf("Msg Time: %d Click Count: %d\n", curMsgTime
, event
.clickCount
);
3996 NPEvent pluginEvent
;
4000 case NS_MOUSE_BUTTON_DOWN
:
4002 case nsMouseEvent::eLeftButton
:
4003 pluginEvent
.event
= WM_LBUTTONDOWN
;
4005 case nsMouseEvent::eMiddleButton
:
4006 pluginEvent
.event
= WM_MBUTTONDOWN
;
4008 case nsMouseEvent::eRightButton
:
4009 pluginEvent
.event
= WM_RBUTTONDOWN
;
4015 case NS_MOUSE_BUTTON_UP
:
4017 case nsMouseEvent::eLeftButton
:
4018 pluginEvent
.event
= WM_LBUTTONUP
;
4020 case nsMouseEvent::eMiddleButton
:
4021 pluginEvent
.event
= WM_MBUTTONUP
;
4023 case nsMouseEvent::eRightButton
:
4024 pluginEvent
.event
= WM_RBUTTONUP
;
4030 case NS_MOUSE_DOUBLECLICK
:
4032 case nsMouseEvent::eLeftButton
:
4033 pluginEvent
.event
= WM_LBUTTONDBLCLK
;
4035 case nsMouseEvent::eMiddleButton
:
4036 pluginEvent
.event
= WM_MBUTTONDBLCLK
;
4038 case nsMouseEvent::eRightButton
:
4039 pluginEvent
.event
= WM_RBUTTONDBLCLK
;
4046 pluginEvent
.event
= WM_MOUSEMOVE
;
4049 pluginEvent
.event
= WM_MOUSELEAVE
;
4052 pluginEvent
.event
= WM_NULL
;
4056 pluginEvent
.wParam
= wParam
; // plugins NEED raw OS event flags!
4057 pluginEvent
.lParam
= lParam
;
4059 event
.pluginEvent
= (void *)&pluginEvent
;
4061 // call the event callback
4062 if (nsnull
!= mEventCallback
) {
4063 if (nsToolkit::gMouseTrailer
)
4064 nsToolkit::gMouseTrailer
->Disable();
4065 if (aEventType
== NS_MOUSE_MOVE
) {
4066 if (nsToolkit::gMouseTrailer
&& !mIsInMouseCapture
) {
4067 nsToolkit::gMouseTrailer
->SetMouseTrailerWindow(mWnd
);
4074 if (rect
.Contains(event
.refPoint
)) {
4075 if (sCurrentWindow
== NULL
|| sCurrentWindow
!= this) {
4076 if ((nsnull
!= sCurrentWindow
) && (!sCurrentWindow
->mInDtor
)) {
4077 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
4078 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_EXIT
, wParam
, pos
, PR_FALSE
,
4079 nsMouseEvent::eLeftButton
, aInputSource
);
4081 sCurrentWindow
= this;
4083 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
4084 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_ENTER
, wParam
, pos
, PR_FALSE
,
4085 nsMouseEvent::eLeftButton
, aInputSource
);
4089 } else if (aEventType
== NS_MOUSE_EXIT
) {
4090 if (sCurrentWindow
== this) {
4091 sCurrentWindow
= nsnull
;
4095 result
= DispatchWindowEvent(&event
);
4097 if (nsToolkit::gMouseTrailer
)
4098 nsToolkit::gMouseTrailer
->Enable();
4100 // Release the widget with NS_IF_RELEASE() just in case
4101 // the context menu key code in nsEventListenerManager::HandleEvent()
4102 // released it already.
4109 // Deal with accessibile event
4110 #ifdef ACCESSIBILITY
4112 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType
)
4114 if (nsnull
== mEventCallback
) {
4118 nsAccessibleEvent
event(PR_TRUE
, aEventType
, this);
4119 InitEvent(event
, nsnull
);
4121 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
4122 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
4123 event
.isMeta
= PR_FALSE
;
4124 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
4126 DispatchWindowEvent(&event
);
4128 return event
.mAccessible
;
4132 PRBool
nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType
)
4134 if (aEventType
== NS_ACTIVATE
)
4135 sJustGotActivate
= PR_FALSE
;
4136 sJustGotDeactivate
= PR_FALSE
;
4138 // retrive the toplevel window or dialog
4140 HWND toplevelWnd
= NULL
;
4142 toplevelWnd
= curWnd
;
4144 nsWindow
*win
= GetNSWindowPtr(curWnd
);
4146 nsWindowType wintype
;
4147 win
->GetWindowType(wintype
);
4148 if (wintype
== eWindowType_toplevel
|| wintype
== eWindowType_dialog
)
4152 curWnd
= ::GetParent(curWnd
); // Parent or owner (if has no parent)
4156 nsWindow
*win
= GetNSWindowPtr(toplevelWnd
);
4158 return win
->DispatchFocus(aEventType
);
4164 // Deal with focus messages
4165 PRBool
nsWindow::DispatchFocus(PRUint32 aEventType
)
4167 // call the event callback
4168 if (mEventCallback
) {
4169 nsGUIEvent
event(PR_TRUE
, aEventType
, this);
4172 //focus and blur event should go to their base widget loc, not current mouse pos
4173 event
.refPoint
.x
= 0;
4174 event
.refPoint
.y
= 0;
4176 NPEvent pluginEvent
;
4181 pluginEvent
.event
= WM_SETFOCUS
;
4184 pluginEvent
.event
= WM_KILLFOCUS
;
4186 case NS_PLUGIN_ACTIVATE
:
4187 pluginEvent
.event
= WM_KILLFOCUS
;
4193 event
.pluginEvent
= (void *)&pluginEvent
;
4195 return DispatchWindowEvent(&event
);
4200 PRBool
nsWindow::IsTopLevelMouseExit(HWND aWnd
)
4202 DWORD pos
= ::GetMessagePos();
4204 mp
.x
= GET_X_LPARAM(pos
);
4205 mp
.y
= GET_Y_LPARAM(pos
);
4206 HWND mouseWnd
= ::WindowFromPoint(mp
);
4208 // GetTopLevelHWND will return a HWND for the window frame (which includes
4209 // the non-client area). If the mouse has moved into the non-client area,
4210 // we should treat it as a top-level exit.
4211 HWND mouseTopLevel
= nsWindow::GetTopLevelHWND(mouseWnd
);
4212 if (mouseWnd
== mouseTopLevel
)
4215 return nsWindow::GetTopLevelHWND(aWnd
) != mouseTopLevel
;
4218 PRBool
nsWindow::BlurEventsSuppressed()
4220 // are they suppressed in this window?
4221 if (mBlurSuppressLevel
> 0)
4224 // are they suppressed by any container widget?
4225 HWND parentWnd
= ::GetParent(mWnd
);
4227 nsWindow
*parent
= GetNSWindowPtr(parentWnd
);
4229 return parent
->BlurEventsSuppressed();
4234 // In some circumstances (opening dependent windows) it makes more sense
4235 // (and fixes a crash bug) to not blur the parent window. Called from
4237 void nsWindow::SuppressBlurEvents(PRBool aSuppress
)
4240 ++mBlurSuppressLevel
; // for this widget
4242 NS_ASSERTION(mBlurSuppressLevel
> 0, "unbalanced blur event suppression");
4243 if (mBlurSuppressLevel
> 0)
4244 --mBlurSuppressLevel
;
4248 PRBool
nsWindow::ConvertStatus(nsEventStatus aStatus
)
4250 return aStatus
== nsEventStatus_eConsumeNoDefault
;
4253 /**************************************************************
4257 * IPC related helpers.
4259 **************************************************************/
4265 nsWindow::IsAsyncResponseEvent(UINT aMsg
, LRESULT
& aResult
)
4271 case WM_WINDOWPOSCHANGING
:
4272 case WM_WINDOWPOSCHANGED
:
4273 case WM_PARENTNOTIFY
:
4274 case WM_ACTIVATEAPP
:
4277 case WM_CHILDACTIVATE
:
4278 case WM_IME_SETCONTEXT
:
4282 case WM_MOUSEACTIVATE
:
4283 case WM_CONTEXTMENU
:
4287 case WM_SETTINGCHANGE
:
4295 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg
);
4303 nsWindow::IPCWindowProcHandler(UINT
& msg
, WPARAM
& wParam
, LPARAM
& lParam
)
4305 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4306 "Failed to prevent a nonqueued message from running!");
4308 // Modal UI being displayed in windowless plugins.
4309 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4310 (InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
4312 if (IsAsyncResponseEvent(msg
, res
)) {
4318 // Handle certain sync plugin events sent to the parent which
4319 // trigger ipc calls that result in deadlocks.
4322 PRBool handled
= PR_FALSE
;
4325 // Windowless flash sending WM_ACTIVATE events to the main window
4326 // via calls to ShowWindow.
4328 if (lParam
!= 0 && LOWORD(wParam
) == WA_ACTIVE
&&
4329 IsWindow((HWND
)lParam
))
4332 // Wheel events forwarded from the child.
4334 case WM_MOUSEHWHEEL
:
4337 // Plugins taking or losing focus triggering focus app messages.
4340 // Windowed plugins that pass sys key events to defwndproc generate
4341 // WM_SYSCOMMAND events to the main window.
4343 // Windowed plugins that fire context menu selection events to parent
4345 case WM_CONTEXTMENU
:
4346 // IME events fired as a result of synchronous focus changes
4347 case WM_IME_SETCONTEXT
:
4353 (InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
4354 ReplyMessage(dwResult
);
4360 /**************************************************************
4361 **************************************************************
4363 ** BLOCK: Native events
4365 ** Main Windows message handlers and OnXXX handlers for
4366 ** Windows event handling.
4368 **************************************************************
4369 **************************************************************/
4371 /**************************************************************
4373 * SECTION: Wind proc.
4375 * The main Windows event procedures and associated
4376 * message processing methods.
4378 **************************************************************/
4380 // The WndProc procedure for all nsWindows in this toolkit
4381 LRESULT CALLBACK
nsWindow::WindowProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
4383 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4384 MOZ_FUNCTION_NAME
, __LINE__
, hWnd
, msg
,
4387 // Get the window which caused the event and ask it to process the message
4388 nsWindow
*someWindow
= GetNSWindowPtr(hWnd
);
4392 someWindow
->IPCWindowProcHandler(msg
, wParam
, lParam
);
4395 // create this here so that we store the last rolled up popup until after
4396 // the event has been processed.
4397 nsAutoRollup autoRollup
;
4399 LRESULT popupHandlingResult
;
4400 if (DealWithPopups(hWnd
, msg
, wParam
, lParam
, &popupHandlingResult
))
4401 return popupHandlingResult
;
4403 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4404 // why we are hitting this assert
4405 if (nsnull
== someWindow
) {
4406 NS_ASSERTION(someWindow
, "someWindow is null, cannot call any CallWindowProc");
4407 return ::DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
4410 // hold on to the window for the life of this method, in case it gets
4411 // deleted during processing. yes, it's a double hack, since someWindow
4412 // is not really an interface.
4413 nsCOMPtr
<nsISupports
> kungFuDeathGrip
;
4414 if (!someWindow
->mInDtor
) // not if we're in the destructor!
4415 kungFuDeathGrip
= do_QueryInterface((nsBaseWidget
*)someWindow
);
4417 // Call ProcessMessage
4419 if (PR_TRUE
== someWindow
->ProcessMessage(msg
, wParam
, lParam
, &retValue
)) {
4423 LRESULT res
= ::CallWindowProcW(someWindow
->GetPrevWindowProc(),
4424 hWnd
, msg
, wParam
, lParam
);
4429 // The main windows message processing method for plugins.
4430 // The result means whether this method processed the native
4431 // event for plugin. If false, the native event should be
4432 // processed by the caller self.
4434 nsWindow::ProcessMessageForPlugin(const MSG
&aMsg
,
4436 PRBool
&aCallDefWndProc
)
4438 NS_PRECONDITION(aResult
, "aResult must be non-null.");
4441 aCallDefWndProc
= PR_FALSE
;
4442 PRBool eventDispatched
= PR_FALSE
;
4443 switch (aMsg
.message
) {
4446 *aResult
= ProcessCharMessage(aMsg
, &eventDispatched
);
4451 *aResult
= ProcessKeyUpMessage(aMsg
, &eventDispatched
);
4456 *aResult
= ProcessKeyDownMessage(aMsg
, &eventDispatched
);
4460 case WM_SYSDEADCHAR
:
4461 case WM_CONTEXTMENU
:
4474 if (!eventDispatched
)
4475 aCallDefWndProc
= !DispatchPluginEvent(aMsg
);
4476 DispatchPendingEvents();
4480 // The main windows message processing method.
4481 PRBool
nsWindow::ProcessMessage(UINT msg
, WPARAM
&wParam
, LPARAM
&lParam
,
4484 // (Large blocks of code should be broken out into OnEvent handlers.)
4485 if (mWindowHook
.Notify(mWnd
, msg
, wParam
, lParam
, aRetValue
))
4488 #if defined(EVENT_DEBUG_OUTPUT)
4489 // First param shows all events, second param indicates whether
4490 // to show mouse move events. See nsWindowDbg for details.
4491 PrintEvent(msg
, SHOW_REPEAT_EVENTS
, SHOW_MOUSEMOVE_EVENTS
);
4495 if (nsIMM32Handler::ProcessMessage(this, msg
, wParam
, lParam
, aRetValue
,
4497 return mWnd
? eatMessage
: PR_TRUE
;
4500 if (PluginHasFocus()) {
4501 PRBool callDefaultWndProc
;
4502 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4503 if (ProcessMessageForPlugin(nativeMsg
, aRetValue
, callDefaultWndProc
)) {
4504 return mWnd
? !callDefaultWndProc
: PR_TRUE
;
4508 static UINT vkKeyCached
= 0; // caches VK code fon WM_KEYDOWN
4509 PRBool result
= PR_FALSE
; // call the default nsWindow proc
4512 static PRBool getWheelInfo
= PR_TRUE
;
4514 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4515 // Glass hit testing w/custom transparent margins
4516 LRESULT dwmHitResult
;
4517 if (mCustomNonClient
&&
4519 nsUXThemeData::CheckForCompositor() &&
4520 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd
, msg
, wParam
, lParam
, &dwmHitResult
)) {
4521 *aRetValue
= dwmHitResult
;
4524 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4528 // WM_QUERYENDSESSION must be handled by all windows.
4529 // Otherwise Windows thinks the window can just be killed at will.
4530 case WM_QUERYENDSESSION
:
4531 if (sCanQuit
== TRI_UNKNOWN
)
4533 // Ask if it's ok to quit, and store the answer until we
4534 // get WM_ENDSESSION signaling the round is complete.
4535 nsCOMPtr
<nsIObserverService
> obsServ
=
4536 mozilla::services::GetObserverService();
4537 nsCOMPtr
<nsISupportsPRBool
> cancelQuit
=
4538 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID
);
4539 cancelQuit
->SetData(PR_FALSE
);
4540 obsServ
->NotifyObservers(cancelQuit
, "quit-application-requested", nsnull
);
4543 cancelQuit
->GetData(&abortQuit
);
4544 sCanQuit
= abortQuit
? TRI_FALSE
: TRI_TRUE
;
4546 *aRetValue
= sCanQuit
? TRUE
: FALSE
;
4554 case MOZ_WM_APP_QUIT
:
4555 if (msg
== MOZ_WM_APP_QUIT
|| (wParam
== TRUE
&& sCanQuit
== TRI_TRUE
))
4557 // Let's fake a shutdown sequence without actually closing windows etc.
4558 // to avoid Windows killing us in the middle. A proper shutdown would
4559 // require having a chance to pump some messages. Unfortunately
4560 // Windows won't let us do that. Bug 212316.
4561 nsCOMPtr
<nsIObserverService
> obsServ
=
4562 mozilla::services::GetObserverService();
4563 NS_NAMED_LITERAL_STRING(context
, "shutdown-persist");
4564 obsServ
->NotifyObservers(nsnull
, "quit-application-granted", nsnull
);
4565 obsServ
->NotifyObservers(nsnull
, "quit-application-forced", nsnull
);
4566 obsServ
->NotifyObservers(nsnull
, "quit-application", nsnull
);
4567 obsServ
->NotifyObservers(nsnull
, "profile-change-net-teardown", context
.get());
4568 obsServ
->NotifyObservers(nsnull
, "profile-change-teardown", context
.get());
4569 obsServ
->NotifyObservers(nsnull
, "profile-before-change", context
.get());
4570 // Then a controlled but very quick exit.
4573 sCanQuit
= TRI_UNKNOWN
;
4578 case WM_DISPLAYCHANGE
:
4579 DispatchStandardEvent(NS_DISPLAYCHANGED
);
4583 case WM_SYSCOLORCHANGE
:
4584 // Note: This is sent for child windows as well as top-level windows.
4585 // The Win32 toolkit normally only sends these events to top-level windows.
4586 // But we cycle through all of the childwindows and send it to them as well
4587 // so all presentations get notified properly.
4588 // See nsWindow::GlobalMsgWindowProc.
4589 DispatchStandardEvent(NS_SYSCOLORCHANGED
);
4595 LPNMHDR pnmh
= (LPNMHDR
) lParam
;
4597 switch (pnmh
->code
) {
4600 DispatchStandardEvent(NS_TABCHANGE
);
4608 case WM_XP_THEMECHANGED
:
4610 // Update non-client margin offsets
4611 UpdateNonClientMargins();
4613 DispatchStandardEvent(NS_THEMECHANGED
);
4615 // Invalidate the window so that the repaint will
4616 // pick up the new theme.
4617 Invalidate(PR_FALSE
);
4624 PRBool didChange
= PR_FALSE
;
4626 // update the global font list
4627 nsCOMPtr
<nsIFontEnumerator
> fontEnum
= do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv
);
4628 if (NS_SUCCEEDED(rv
)) {
4629 fontEnum
->UpdateFontList(&didChange
);
4630 //didChange is TRUE only if new font langGroup is added to the list.
4632 // update device context font cache
4633 // Dirty but easiest way:
4634 // Changing nsIPrefBranch entry which triggers callbacks
4635 // and flows into calling mDeviceContext->FlushFontCache()
4636 // to update the font cache in all the instance of Browsers
4637 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
4639 nsCOMPtr
<nsIPrefBranch
> fiPrefs
;
4640 prefs
->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs
));
4642 PRBool fontInternalChange
= PR_FALSE
;
4643 fiPrefs
->GetBoolPref("changed", &fontInternalChange
);
4644 fiPrefs
->SetBoolPref("changed", !fontInternalChange
);
4648 } //if (NS_SUCCEEDED(rv))
4654 // If wParam is TRUE, it specifies that the application should indicate
4655 // which part of the client area contains valid information. The system
4656 // copies the valid information to the specified area within the new
4657 // client area. If the wParam parameter is FALSE, the application should
4659 if (mCustomNonClient
&& mCompositorFlag
) {
4667 // rgrc[0]: the proposed window
4668 // rgrc[1]: the current window
4669 // rgrc[2]: the source client area
4670 // pncsp->lppos: move/size data
4672 // rgrc[0]: the new client area
4673 // rgrc[1]: the destination window
4674 // rgrc[2]: the source client area
4675 // (all values in screen coordiantes)
4676 NCCALCSIZE_PARAMS
*pncsp
= reinterpret_cast<NCCALCSIZE_PARAMS
*>(lParam
);
4677 LRESULT res
= CallWindowProcW(GetPrevWindowProc(), mWnd
, msg
, wParam
, lParam
);
4678 pncsp
->rgrc
[0].top
-= mNonClientOffset
.top
;
4679 pncsp
->rgrc
[0].left
-= mNonClientOffset
.left
;
4680 pncsp
->rgrc
[0].right
+= mNonClientOffset
.right
;
4681 pncsp
->rgrc
[0].bottom
+= mNonClientOffset
.bottom
;
4692 * If an nc client area margin has been moved, we are responsible
4693 * for calculating where the resize margins are and returning the
4694 * appropriate set of hit test constants. DwmDefWindowProc (above)
4695 * will handle hit testing on it's command buttons if we are on a
4696 * composited desktop.
4699 if (!mCustomNonClient
|| !mCompositorFlag
)
4703 ClientMarginHitTestPoint(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
4709 case WM_POWERBROADCAST
:
4710 // only hidden window handle this
4711 // to prevent duplicate notification
4712 if (mWindowType
== eWindowType_invisible
) {
4715 case PBT_APMSUSPEND
:
4716 PostSleepWakeNotification("sleep_notification");
4718 case PBT_APMRESUMEAUTOMATIC
:
4719 case PBT_APMRESUMECRITICAL
:
4720 case PBT_APMRESUMESUSPEND
:
4721 PostSleepWakeNotification("wake_notification");
4728 case WM_MOVE
: // Window moved
4731 ::GetWindowRect(mWnd
, &rect
);
4732 result
= OnMove(rect
.left
, rect
.top
);
4736 case WM_CLOSE
: // close request
4737 DispatchStandardEvent(NS_XUL_CLOSE
);
4738 result
= PR_TRUE
; // abort window closure
4748 *aRetValue
= (int) OnPaint(NULL
, 0);
4753 case WM_PRINTCLIENT
:
4754 result
= OnPaint((HDC
) wParam
, 0);
4759 result
= OnHotKey(wParam
, lParam
);
4765 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4766 result
= ProcessCharMessage(nativeMsg
, nsnull
);
4767 DispatchPendingEvents();
4774 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4775 result
= ProcessKeyUpMessage(nativeMsg
, nsnull
);
4776 DispatchPendingEvents();
4783 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4784 result
= ProcessKeyDownMessage(nativeMsg
, nsnull
);
4785 DispatchPendingEvents();
4789 // say we've dealt with erase background if widget does
4790 // not need auto-erasing
4792 if (!AutoErase((HDC
)wParam
)) {
4800 #ifdef WINCE_WINDOWS_MOBILE
4801 // Reset the kill timer so that we can continue at this
4803 SetTimer(mWnd
, KILL_PRIORITY_ID
, 2000 /* 2seconds */, NULL
);
4805 // Suppress dispatch of pending events
4806 // when mouse moves are generated by widget
4807 // creation instead of user input.
4808 LPARAM lParamScreen
= lParamToScreen(lParam
);
4810 mp
.x
= GET_X_LPARAM(lParamScreen
);
4811 mp
.y
= GET_Y_LPARAM(lParamScreen
);
4812 PRBool userMovedMouse
= PR_FALSE
;
4813 if ((sLastMouseMovePoint
.x
!= mp
.x
) || (sLastMouseMovePoint
.y
!= mp
.y
)) {
4814 userMovedMouse
= PR_TRUE
;
4816 mExitToNonClientArea
= PR_FALSE
;
4818 result
= DispatchMouseEvent(NS_MOUSE_MOVE
, wParam
, lParam
,
4819 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4820 if (userMovedMouse
) {
4821 DispatchPendingEvents();
4826 #ifdef WINCE_WINDOWS_MOBILE
4828 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL
);
4829 KillTimer(mWnd
, KILL_PRIORITY_ID
);
4833 case WM_LBUTTONDOWN
:
4835 #ifdef WINCE_WINDOWS_MOBILE
4836 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL
);
4837 SetTimer(mWnd
, KILL_PRIORITY_ID
, 2000 /* 2 seconds */, NULL
);
4839 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
,
4840 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4841 DispatchPendingEvents();
4847 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
,
4848 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4849 DispatchPendingEvents();
4851 #ifdef WINCE_WINDOWS_MOBILE
4852 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL
);
4853 KillTimer(mWnd
, KILL_PRIORITY_ID
);
4861 // We need to check mouse button states and put them in for
4863 WPARAM mouseState
= (GetKeyState(VK_LBUTTON
) ? MK_LBUTTON
: 0)
4864 | (GetKeyState(VK_MBUTTON
) ? MK_MBUTTON
: 0)
4865 | (GetKeyState(VK_RBUTTON
) ? MK_RBUTTON
: 0);
4866 // Synthesize an event position because we don't get one from
4868 LPARAM pos
= lParamToClient(::GetMessagePos());
4869 DispatchMouseEvent(NS_MOUSE_EXIT
, mouseState
, pos
, PR_FALSE
,
4870 nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4875 case WM_CONTEXTMENU
:
4877 // if the context menu is brought up from the keyboard, |lParam|
4880 PRBool contextMenukey
= PR_FALSE
;
4883 contextMenukey
= PR_TRUE
;
4884 pos
= lParamToClient(GetMessagePos());
4888 pos
= lParamToClient(lParam
);
4891 result
= DispatchMouseEvent(NS_CONTEXTMENU
, wParam
, pos
, contextMenukey
,
4893 nsMouseEvent::eLeftButton
:
4894 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4898 case WM_LBUTTONDBLCLK
:
4899 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4900 nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
4903 case WM_MBUTTONDOWN
:
4905 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4906 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4907 DispatchPendingEvents();
4912 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, PR_FALSE
,
4913 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4914 DispatchPendingEvents();
4917 case WM_MBUTTONDBLCLK
:
4918 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4919 nsMouseEvent::eMiddleButton
, MOUSE_INPUT_SOURCE());
4922 case WM_RBUTTONDOWN
:
4924 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4925 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4926 DispatchPendingEvents();
4931 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, PR_FALSE
,
4932 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4933 DispatchPendingEvents();
4936 case WM_RBUTTONDBLCLK
:
4937 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4938 nsMouseEvent::eRightButton
, MOUSE_INPUT_SOURCE());
4941 case WM_NCRBUTTONDOWN
:
4942 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, 0, lParamToClient(lParam
),
4943 PR_FALSE
, nsMouseEvent::eRightButton
,
4944 MOUSE_INPUT_SOURCE());
4945 DispatchPendingEvents();
4948 case WM_NCRBUTTONUP
:
4949 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, 0, lParamToClient(lParam
),
4950 PR_FALSE
, nsMouseEvent::eRightButton
,
4951 MOUSE_INPUT_SOURCE());
4952 DispatchPendingEvents();
4955 case WM_NCRBUTTONDBLCLK
:
4956 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, 0, lParamToClient(lParam
),
4957 PR_FALSE
, nsMouseEvent::eRightButton
,
4958 MOUSE_INPUT_SOURCE());
4962 PRUint32 appCommand
= GET_APPCOMMAND_LPARAM(lParam
);
4966 case APPCOMMAND_BROWSER_BACKWARD
:
4967 case APPCOMMAND_BROWSER_FORWARD
:
4968 case APPCOMMAND_BROWSER_REFRESH
:
4969 case APPCOMMAND_BROWSER_STOP
:
4970 case APPCOMMAND_BROWSER_SEARCH
:
4971 case APPCOMMAND_BROWSER_FAVORITES
:
4972 case APPCOMMAND_BROWSER_HOME
:
4973 DispatchCommandEvent(appCommand
);
4974 // tell the driver that we handled the event
4979 // default = PR_FALSE - tell the driver that the event was not handled
4986 result
= OnScroll(msg
, wParam
, lParam
);
4989 // The WM_ACTIVATE event is fired when a window is raised or lowered,
4990 // and the loword of wParam specifies which. But we don't want to tell
4991 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
4992 // events are fired. Instead, set either the sJustGotActivate or
4993 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
4994 // events once the focus events arrive.
4996 if (mEventCallback
) {
4997 PRInt32 fActive
= LOWORD(wParam
);
4999 #if defined(WINCE_HAVE_SOFTKB)
5000 if (mIsTopWidgetWindow
&& sSoftKeyboardState
)
5001 nsWindowCE::ToggleSoftKB(mWnd
, fActive
);
5002 if (nsWindowCE::sShowSIPButton
== TRI_FALSE
&& WA_INACTIVE
!= fActive
) {
5003 HWND hWndSIPB
= FindWindowW(L
"MS_SIPBUTTON", NULL
);
5005 ShowWindow(hWndSIPB
, SW_HIDE
);
5010 if (WA_INACTIVE
== fActive
) {
5011 // when minimizing a window, the deactivation and focus events will
5012 // be fired in the reverse order. Instead, just dispatch
5013 // NS_DEACTIVATE right away.
5015 result
= DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5017 sJustGotDeactivate
= PR_TRUE
;
5019 if (mIsTopWidgetWindow
)
5020 mLastKeyboardLayout
= gKbdLayout
.GetLayout();
5026 sJustGotActivate
= PR_TRUE
;
5027 nsMouseEvent
event(PR_TRUE
, NS_MOUSE_ACTIVATE
, this,
5028 nsMouseEvent::eReal
);
5031 event
.acceptActivation
= PR_TRUE
;
5033 PRBool result
= DispatchWindowEvent(&event
);
5035 if (event
.acceptActivation
)
5036 *aRetValue
= MA_ACTIVATE
;
5038 *aRetValue
= MA_NOACTIVATE
;
5040 if (sSwitchKeyboardLayout
&& mLastKeyboardLayout
)
5041 ActivateKeyboardLayout(mLastKeyboardLayout
, 0);
5047 #ifdef WINCE_WINDOWS_MOBILE
5048 if (!gCheckForHTCApi
&& gHTCApiNavOpen
== nsnull
) {
5049 gCheckForHTCApi
= PR_TRUE
;
5051 HINSTANCE library
= LoadLibrary(L
"HTCAPI.dll");
5052 gHTCApiNavOpen
= (HTCApiNavOpen
) GetProcAddress(library
, "HTCNavOpen");
5053 gHTCApiNavSetMode
= (HTCApiNavSetMode
) GetProcAddress(library
,"HTCNavSetMode");
5056 if (gHTCApiNavOpen
!= nsnull
) {
5057 gHTCApiNavOpen(mWnd
, 1 /* undocumented value */);
5059 if (gHTCApiNavSetMode
!= nsnull
)
5060 gHTCApiNavSetMode ( mWnd
, 4);
5061 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5067 case WM_MOUSEACTIVATE
:
5068 if (mWindowType
== eWindowType_popup
) {
5069 // a popup with a parent owner should not be activated when clicked
5070 // but should still allow the mouse event to be fired, so the return
5071 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5072 // window, just use default processing so that the window is activated.
5073 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
5074 if (owner
&& owner
== ::GetForegroundWindow()) {
5075 *aRetValue
= MA_NOACTIVATE
;
5081 case WM_WINDOWPOSCHANGING
:
5083 LPWINDOWPOS info
= (LPWINDOWPOS
) lParam
;
5084 OnWindowPosChanging(info
);
5090 if (sJustGotActivate
) {
5091 result
= DispatchFocusToTopLevelWindow(NS_ACTIVATE
);
5094 #ifdef ACCESSIBILITY
5095 if (nsWindow::sIsAccessibilityOn
) {
5096 // Create it for the first time so that it can start firing events
5097 nsAccessible
*rootAccessible
= GetRootAccessible();
5101 #if defined(WINCE_HAVE_SOFTKB)
5103 // On Windows CE, we have a window that overlaps
5104 // the ISP button. In this case, we should always
5105 // try to hide it when we are activated
5107 nsIMEContext
IMEContext(mWnd
);
5109 ImmSetOpenStatus(IMEContext
.get(), TRUE
);
5115 #if defined(WINCE_HAVE_SOFTKB)
5117 nsIMEContext
IMEContext(mWnd
);
5118 ImmSetOpenStatus(IMEContext
.get(), FALSE
);
5121 if (sJustGotDeactivate
) {
5122 result
= DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5126 case WM_WINDOWPOSCHANGED
:
5128 WINDOWPOS
*wp
= (LPWINDOWPOS
)lParam
;
5129 OnWindowPosChanged(wp
, result
);
5133 case WM_SETTINGCHANGE
:
5134 #if !defined (WINCE_WINDOWS_MOBILE)
5135 getWheelInfo
= PR_TRUE
;
5138 case SPI_SETSIPINFO
:
5139 case SPI_SETCURRENTIM
:
5140 nsWindowCE::OnSoftKbSettingsChange(mWnd
);
5142 case SETTINGCHANGE_RESET
:
5143 if (mWindowType
== eWindowType_invisible
) {
5144 // The OS sees to get confused and think that the invisable window
5145 // is in the foreground after an orientation change. By actually
5146 // setting it to the foreground and hiding it, we set it strait.
5147 // See bug 514007 for details.
5148 SetForegroundWindow(mWnd
);
5149 ShowWindow(mWnd
, SW_HIDE
);
5154 OnSettingsChange(wParam
, lParam
);
5158 case WM_INPUTLANGCHANGEREQUEST
:
5163 case WM_INPUTLANGCHANGE
:
5164 result
= OnInputLangChange((HKL
)lParam
);
5168 case WM_DESTROYCLIPBOARD
:
5170 nsIClipboard
* clipboard
;
5171 nsresult rv
= CallGetService(kCClipboardCID
, &clipboard
);
5172 clipboard
->EmptyClipboard(nsIClipboard::kGlobalClipboard
);
5173 NS_RELEASE(clipboard
);
5177 #ifdef ACCESSIBILITY
5181 if (lParam
== OBJID_CLIENT
) { // oleacc.dll will be loaded dynamically
5182 nsAccessible
*rootAccessible
= GetRootAccessible(); // Held by a11y cache
5183 if (rootAccessible
) {
5184 IAccessible
*msaaAccessible
= NULL
;
5185 rootAccessible
->GetNativeInterface((void**)&msaaAccessible
); // does an addref
5186 if (msaaAccessible
) {
5187 *aRetValue
= LresultFromObject(IID_IAccessible
, wParam
, msaaAccessible
); // does an addref
5188 msaaAccessible
->Release(); // release extra addref
5189 result
= PR_TRUE
; // We handled the WM_GETOBJECT message
5198 // prevent Windows from trimming the working set. bug 76831
5199 if (!sTrimOnMinimize
&& wParam
== SC_MINIMIZE
) {
5200 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
5209 nsMemory::HeapMinimize(PR_TRUE
);
5214 case WM_MOUSEHWHEEL
:
5216 // If OnMouseWheel returns true, the event was forwarded directly to another
5217 // mozilla window message handler (ProcessMessage). In this case the return
5218 // value of the forwarded event is in 'result' which we should return immediately.
5219 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5220 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5221 // we should fall through.
5222 if (OnMouseWheel(msg
, wParam
, lParam
, getWheelInfo
, result
, aRetValue
))
5228 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5229 case WM_DWMCOMPOSITIONCHANGED
:
5230 UpdateNonClientMargins();
5231 BroadcastMsg(mWnd
, WM_DWMCOMPOSITIONCHANGED
);
5232 DispatchStandardEvent(NS_THEMECHANGED
);
5234 Invalidate(PR_FALSE
);
5238 case WM_UPDATEUISTATE
:
5240 // If the UI state has changed, fire an event so the UI updates the
5241 // keyboard cues based on the system setting and how the window was
5242 // opened. For example, a dialog opened via a keyboard press on a button
5243 // should enable cues, whereas the same dialog opened via a mouse click of
5244 // the button should not.
5245 PRInt32 action
= LOWORD(wParam
);
5246 if (action
== UIS_SET
|| action
== UIS_CLEAR
) {
5247 nsUIStateChangeEvent
event(PR_TRUE
, NS_UISTATECHANGED
, this);
5248 PRInt32 flags
= HIWORD(wParam
);
5249 if (flags
& UISF_HIDEACCEL
)
5250 event
.showAccelerators
= (action
== UIS_SET
) ? UIStateChangeType_Clear
: UIStateChangeType_Set
;
5251 if (flags
& UISF_HIDEFOCUS
)
5252 event
.showFocusRings
= (action
== UIS_SET
) ? UIStateChangeType_Clear
: UIStateChangeType_Set
;
5253 DispatchWindowEvent(&event
);
5259 /* Gesture support events */
5260 case WM_TABLET_QUERYSYSTEMGESTURESTATUS
:
5261 // According to MS samples, this must be handled to enable
5262 // rotational support in multi-touch drivers.
5264 *aRetValue
= TABLET_ROTATE_GESTURE_ENABLE
;
5267 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5269 result
= OnTouch(wParam
, lParam
);
5277 result
= OnGesture(wParam
, lParam
);
5280 case WM_GESTURENOTIFY
:
5282 if (mWindowType
!= eWindowType_invisible
&&
5283 mWindowType
!= eWindowType_plugin
&&
5284 mWindowType
!= eWindowType_toplevel
) {
5285 // eWindowType_toplevel is the top level main frame window. Gesture support
5286 // there prevents the user from interacting with the title bar or nc
5287 // areas using a single finger. Java and plugin windows can make their
5289 GESTURENOTIFYSTRUCT
* gestureinfo
= (GESTURENOTIFYSTRUCT
*)lParam
;
5290 nsPointWin touchPoint
;
5291 touchPoint
= gestureinfo
->ptsLocation
;
5292 touchPoint
.ScreenToClient(mWnd
);
5293 nsGestureNotifyEvent
gestureNotifyEvent(PR_TRUE
, NS_GESTURENOTIFY_EVENT_START
, this);
5294 gestureNotifyEvent
.refPoint
= touchPoint
;
5295 nsEventStatus status
;
5296 DispatchEvent(&gestureNotifyEvent
, status
);
5297 mDisplayPanFeedback
= gestureNotifyEvent
.displayPanFeedback
;
5299 mGesture
.SetWinGestureSupport(mWnd
, gestureNotifyEvent
.panDirection
);
5301 result
= PR_FALSE
; //should always bubble to DefWindowProc
5304 #endif // !defined(WINCE)
5308 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_DELETE
, this);
5309 DispatchWindowEvent(&command
);
5316 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_CUT
, this);
5317 DispatchWindowEvent(&command
);
5324 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_COPY
, this);
5325 DispatchWindowEvent(&command
);
5332 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_PASTE
, this);
5333 DispatchWindowEvent(&command
);
5341 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_UNDO
, this);
5342 DispatchWindowEvent(&command
);
5343 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5350 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_REDO
, this);
5351 DispatchWindowEvent(&command
);
5352 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5359 // Support EM_CANPASTE message only when wParam isn't specified or
5360 // is plain text format.
5361 if (wParam
== 0 || wParam
== CF_TEXT
|| wParam
== CF_UNICODETEXT
) {
5362 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_PASTE
,
5364 DispatchWindowEvent(&command
);
5365 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5373 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_UNDO
,
5375 DispatchWindowEvent(&command
);
5376 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5383 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_REDO
,
5385 DispatchWindowEvent(&command
);
5386 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
5392 #ifdef WINCE_WINDOWS_MOBILE
5393 //HTC NAVIGATION WHEEL EVENT
5396 int distance
= wParam
& 0x000000FF;
5397 if ( (wParam
& 0x000000100) != 0) // Counter Clockwise
5399 if (OnMouseWheel(WM_MOUSEWHEEL
, MAKEWPARAM(0, distance
),
5400 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN
) / 2,
5401 GetSystemMetrics(SM_CYSCREEN
) / 2),
5402 getWheelInfo
, result
, aRetValue
))
5410 #ifdef NS_ENABLE_TSF
5411 if (msg
== WM_USER_TSF_TEXTCHANGE
) {
5412 nsTextStore::OnTextChangeMsg();
5414 #endif //NS_ENABLE_TSF
5415 #if defined(HEAP_DUMP_EVENT)
5416 if (msg
== GetHeapMsg()) {
5417 HeapDump(msg
, wParam
, lParam
);
5421 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5422 if (msg
== nsAppShell::GetTaskbarButtonCreatedMessage())
5423 SetHasTaskbarIconBeenCreated();
5426 if (msg
== sOOPPPluginFocusEvent
) {
5428 // With OOPP, the plugin window exists in another process and is a child of
5429 // this window. This window is a placeholder plugin window for the dom. We
5430 // receive this event when the child window receives focus. (sent from
5431 // PluginInstanceParent.cpp)
5432 ::SendMessage(mWnd
, WM_MOUSEACTIVATE
, 0, 0); // See nsPluginNativeWindowWin.cpp
5434 // WM_KILLFOCUS was received by the child process.
5435 if (sJustGotDeactivate
) {
5436 DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
5445 //*aRetValue = result;
5450 //Events which caused mWnd destruction and aren't consumed
5451 //will crash during the Windows default processing.
5456 /**************************************************************
5458 * SECTION: Broadcast messaging
5460 * Broadcast messages to all windows.
5462 **************************************************************/
5464 // Enumerate all child windows sending aMsg to each of them
5465 BOOL CALLBACK
nsWindow::BroadcastMsgToChildren(HWND aWnd
, LPARAM aMsg
)
5467 WNDPROC winProc
= (WNDPROC
)::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
5468 if (winProc
== &nsWindow::WindowProc
) {
5469 // it's one of our windows so go ahead and send a message to it
5470 ::CallWindowProcW(winProc
, aWnd
, aMsg
, 0, 0);
5475 // Enumerate all top level windows specifying that the children of each
5476 // top level window should be enumerated. Do *not* send the message to
5477 // each top level window since it is assumed that the toolkit will send
5478 // aMsg to them directly.
5479 BOOL CALLBACK
nsWindow::BroadcastMsg(HWND aTopWindow
, LPARAM aMsg
)
5481 // Iterate each of aTopWindows child windows sending the aMsg
5484 ::EnumChildWindows(aTopWindow
, nsWindow::BroadcastMsgToChildren
, aMsg
);
5486 nsWindowCE::EnumChildWindows(aTopWindow
, nsWindow::BroadcastMsgToChildren
, aMsg
);
5491 // This method is called from nsToolkit::WindowProc to forward global
5492 // messages which need to be dispatched to all child windows.
5493 void nsWindow::GlobalMsgWindowProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
5496 case WM_SYSCOLORCHANGE
:
5497 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5498 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5499 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5500 // all child windows as well. When running in an embedded application
5501 // we may not receive a WM_SYSCOLORCHANGE message because the top
5502 // level window is owned by the embeddor.
5503 // System color changes are posted to top-level windows only.
5504 // The NS_SYSCOLORCHANGE must be dispatched to all child
5507 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg
, msg
);
5513 /**************************************************************
5515 * SECTION: Event processing helpers
5517 * Special processing for certain event types and
5518 * synthesized events.
5520 **************************************************************/
5523 nsWindow::ClientMarginHitTestPoint(PRInt32 mx
, PRInt32 my
)
5525 // Calculations are done in screen coords
5527 GetWindowRect(mWnd
, &winRect
);
5529 // hit return constants:
5530 // HTBORDER - non-resizable border
5531 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5532 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5533 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5534 // HTCAPTION - general title bar area
5535 // HTCLIENT - area considered the client
5536 // HTCLOSE - hovering over the close button
5537 // HTMAXBUTTON - maximize button
5538 // HTMINBUTTON - minimize button
5540 PRInt32 testResult
= HTCLIENT
;
5542 PRBool top
= PR_FALSE
;
5543 PRBool bottom
= PR_FALSE
;
5544 PRBool left
= PR_FALSE
;
5545 PRBool right
= PR_FALSE
;
5547 if (my
>= winRect
.top
&& my
<=
5548 (winRect
.top
+ mVertResizeMargin
+ (mCaptionHeight
- mNonClientOffset
.top
)))
5550 else if (my
<= winRect
.bottom
&& my
>= (winRect
.bottom
- mVertResizeMargin
))
5553 if (mx
>= winRect
.left
&& mx
<= (winRect
.left
+ mHorResizeMargin
))
5555 else if (mx
<= winRect
.right
&& mx
>= (winRect
.right
- mHorResizeMargin
))
5561 testResult
= HTTOPLEFT
;
5563 testResult
= HTTOPRIGHT
;
5564 } else if (bottom
) {
5565 testResult
= HTBOTTOM
;
5567 testResult
= HTBOTTOMLEFT
;
5569 testResult
= HTBOTTOMRIGHT
;
5572 testResult
= HTLEFT
;
5574 testResult
= HTRIGHT
;
5577 PRBool contentOverlap
= PR_TRUE
;
5579 if (mSizeMode
== nsSizeMode_Maximized
) {
5580 // There's no HTTOP in maximized state (bug 575493)
5581 if (testResult
== HTTOP
) {
5582 testResult
= HTCAPTION
;
5585 PRInt32 leftMargin
= mNonClientMargins
.left
== -1 ? mHorResizeMargin
: mNonClientMargins
.left
;
5586 PRInt32 rightMargin
= mNonClientMargins
.right
== -1 ? mHorResizeMargin
: mNonClientMargins
.right
;
5587 PRInt32 topMargin
= mNonClientMargins
.top
== -1 ? mVertResizeMargin
: mNonClientMargins
.top
;
5588 PRInt32 bottomMargin
= mNonClientMargins
.bottom
== -1 ? mVertResizeMargin
: mNonClientMargins
.bottom
;
5590 contentOverlap
= mx
>= winRect
.left
+ leftMargin
&&
5591 mx
<= winRect
.right
- rightMargin
&&
5592 my
>= winRect
.top
+ topMargin
&&
5593 my
<= winRect
.bottom
- bottomMargin
;
5596 if (!mIsInMouseCapture
&&
5598 (testResult
== HTCLIENT
||
5599 testResult
== HTTOP
||
5600 testResult
== HTTOPLEFT
||
5601 testResult
== HTCAPTION
)) {
5602 LPARAM lParam
= MAKELPARAM(mx
, my
);
5603 LPARAM lParamClient
= lParamToClient(lParam
);
5604 PRBool result
= DispatchMouseEvent(NS_MOUSE_MOZHITTEST
, 0, lParamClient
,
5605 PR_FALSE
, nsMouseEvent::eLeftButton
, MOUSE_INPUT_SOURCE());
5607 // The mouse is over a blank area
5608 testResult
= testResult
== HTCLIENT
? HTCAPTION
: testResult
;
5610 if (!mExitToNonClientArea
) {
5611 // The first time the mouse pointer goes from client area to non-client area,
5612 // we don't want to miss that movement so we can interpret mouseout input.
5613 ::SendMessage(mWnd
, WM_MOUSEMOVE
, 0, lParamClient
);
5614 mExitToNonClientArea
= PR_TRUE
;
5617 // There's content over the mouse pointer. Set HTCLIENT
5618 // to possibly override a resizer border.
5619 testResult
= HTCLIENT
;
5628 void nsWindow::PostSleepWakeNotification(const char* aNotification
)
5630 nsCOMPtr
<nsIObserverService
> observerService
=
5631 mozilla::services::GetObserverService();
5632 if (observerService
)
5633 observerService
->NotifyObservers(nsnull
, aNotification
, nsnull
);
5637 LRESULT
nsWindow::ProcessCharMessage(const MSG
&aMsg
, PRBool
*aEventDispatched
)
5639 NS_PRECONDITION(aMsg
.message
== WM_CHAR
|| aMsg
.message
== WM_SYSCHAR
,
5640 "message is not keydown event");
5641 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5642 ("%s charCode=%d scanCode=%d\n",
5643 aMsg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
5644 aMsg
.wParam
, HIWORD(aMsg
.lParam
) & 0xFF));
5646 // These must be checked here too as a lone WM_CHAR could be received
5647 // if a child window didn't handle it (for example Alt+Space in a content window)
5648 nsModifierKeyState modKeyState
;
5649 return OnChar(aMsg
, modKeyState
, aEventDispatched
);
5652 LRESULT
nsWindow::ProcessKeyUpMessage(const MSG
&aMsg
, PRBool
*aEventDispatched
)
5654 NS_PRECONDITION(aMsg
.message
== WM_KEYUP
|| aMsg
.message
== WM_SYSKEYUP
,
5655 "message is not keydown event");
5656 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5657 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
5658 "WM_SYSKEYUP" : "WM_KEYUP", aMsg
.wParam
));
5660 nsModifierKeyState modKeyState
;
5662 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5663 // scan code. However, this breaks Alt+Num pad input.
5664 // MSDN states the following:
5665 // Typically, ToAscii performs the translation based on the
5666 // virtual-key code. In some cases, however, bit 15 of the
5667 // uScanCode parameter may be used to distinguish between a key
5668 // press and a key release. The scan code is used for
5669 // translating ALT+number key combinations.
5671 // ignore [shift+]alt+space so the OS can handle it
5672 if (modKeyState
.mIsAltDown
&& !modKeyState
.mIsControlDown
&&
5673 IS_VK_DOWN(NS_VK_SPACE
)) {
5677 if (!nsIMM32Handler::IsComposingOn(this) &&
5678 (aMsg
.message
!= WM_KEYUP
|| aMsg
.wParam
!= VK_MENU
)) {
5679 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5680 // This helps avoid triggering the menu bar for ALT key accelerators used in
5681 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5682 // to switch back to Mozilla in Windows 95 and Windows 98
5683 return OnKeyUp(aMsg
, modKeyState
, aEventDispatched
);
5689 LRESULT
nsWindow::ProcessKeyDownMessage(const MSG
&aMsg
,
5690 PRBool
*aEventDispatched
)
5692 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5693 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
5694 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg
.wParam
));
5695 NS_PRECONDITION(aMsg
.message
== WM_KEYDOWN
|| aMsg
.message
== WM_SYSKEYDOWN
,
5696 "message is not keydown event");
5698 nsModifierKeyState modKeyState
;
5700 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
5701 // scan code. However, this breaks Alt+Num pad input.
5702 // MSDN states the following:
5703 // Typically, ToAscii performs the translation based on the
5704 // virtual-key code. In some cases, however, bit 15 of the
5705 // uScanCode parameter may be used to distinguish between a key
5706 // press and a key release. The scan code is used for
5707 // translating ALT+number key combinations.
5709 // ignore [shift+]alt+space so the OS can handle it
5710 if (modKeyState
.mIsAltDown
&& !modKeyState
.mIsControlDown
&&
5711 IS_VK_DOWN(NS_VK_SPACE
))
5715 if (modKeyState
.mIsAltDown
&& nsIMM32Handler::IsStatusChanged()) {
5716 nsIMM32Handler::NotifyEndStatusChange();
5717 } else if (!nsIMM32Handler::IsComposingOn(this)) {
5718 result
= OnKeyDown(aMsg
, modKeyState
, aEventDispatched
, nsnull
);
5722 if (aMsg
.wParam
== VK_MENU
||
5723 (aMsg
.wParam
== VK_F10
&& !modKeyState
.mIsShiftDown
)) {
5724 // We need to let Windows handle this keypress,
5725 // by returning PR_FALSE, if there's a native menu
5726 // bar somewhere in our containing window hierarchy.
5727 // Otherwise we handle the keypress and don't pass
5728 // it on to Windows, by returning PR_TRUE.
5729 PRBool hasNativeMenu
= PR_FALSE
;
5732 if (::GetMenu(hWnd
)) {
5733 hasNativeMenu
= PR_TRUE
;
5736 hWnd
= ::GetParent(hWnd
);
5738 result
= !hasNativeMenu
;
5746 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout
,
5747 PRInt32 aNativeKeyCode
,
5748 PRUint32 aModifierFlags
,
5749 const nsAString
& aCharacters
,
5750 const nsAString
& aUnmodifiedCharacters
)
5752 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
5753 nsPrintfCString
layoutName("%08x", aNativeKeyboardLayout
);
5754 HKL loadedLayout
= LoadKeyboardLayoutA(layoutName
.get(), KLF_NOTELLSHELL
);
5755 if (loadedLayout
== NULL
)
5756 return NS_ERROR_NOT_AVAILABLE
;
5758 // Setup clean key state and load desired layout
5759 BYTE originalKbdState
[256];
5760 ::GetKeyboardState(originalKbdState
);
5762 memset(kbdState
, 0, sizeof(kbdState
));
5763 // This changes the state of the keyboard for the current thread only,
5764 // and we'll restore it soon, so this should be OK.
5765 ::SetKeyboardState(kbdState
);
5766 HKL oldLayout
= gKbdLayout
.GetLayout();
5767 gKbdLayout
.LoadLayout(loadedLayout
);
5769 nsAutoTArray
<KeyPair
,10> keySequence
;
5770 SetupKeyModifiersSequence(&keySequence
, aModifierFlags
);
5771 NS_ASSERTION(aNativeKeyCode
>= 0 && aNativeKeyCode
< 256,
5772 "Native VK key code out of range");
5773 keySequence
.AppendElement(KeyPair(aNativeKeyCode
, 0));
5775 // Simulate the pressing of each modifier key and then the real key
5776 for (PRUint32 i
= 0; i
< keySequence
.Length(); ++i
) {
5777 PRUint8 key
= keySequence
[i
].mGeneral
;
5778 PRUint8 keySpecific
= keySequence
[i
].mSpecific
;
5779 kbdState
[key
] = 0x81; // key is down and toggled on if appropriate
5781 kbdState
[keySpecific
] = 0x81;
5783 ::SetKeyboardState(kbdState
);
5784 nsModifierKeyState modKeyState
;
5785 MSG msg
= InitMSG(WM_KEYDOWN
, key
, 0);
5786 if (i
== keySequence
.Length() - 1 && aCharacters
.Length() > 0) {
5787 UINT scanCode
= ::MapVirtualKeyEx(aNativeKeyCode
, MAPVK_VK_TO_VSC
,
5788 gKbdLayout
.GetLayout());
5789 nsFakeCharMessage fakeMsg
= { aCharacters
.CharAt(0), scanCode
};
5790 OnKeyDown(msg
, modKeyState
, nsnull
, &fakeMsg
);
5792 OnKeyDown(msg
, modKeyState
, nsnull
, nsnull
);
5795 for (PRUint32 i
= keySequence
.Length(); i
> 0; --i
) {
5796 PRUint8 key
= keySequence
[i
- 1].mGeneral
;
5797 PRUint8 keySpecific
= keySequence
[i
- 1].mSpecific
;
5798 kbdState
[key
] = 0; // key is up and toggled off if appropriate
5800 kbdState
[keySpecific
] = 0;
5802 ::SetKeyboardState(kbdState
);
5803 nsModifierKeyState modKeyState
;
5804 MSG msg
= InitMSG(WM_KEYUP
, key
, 0);
5805 OnKeyUp(msg
, modKeyState
, nsnull
);
5808 // Restore old key state and layout
5809 ::SetKeyboardState(originalKbdState
);
5810 gKbdLayout
.LoadLayout(oldLayout
);
5812 UnloadKeyboardLayout(loadedLayout
);
5814 #else //XXX: is there another way to do this?
5815 return NS_ERROR_NOT_IMPLEMENTED
;
5820 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint
,
5821 PRUint32 aNativeMessage
,
5822 PRUint32 aModifierFlags
)
5824 #ifndef WINCE // I don't think WINCE supports SendInput
5826 ::GetWindowRect(mWnd
, &r
);
5827 ::SetCursorPos(r
.left
+ aPoint
.x
, r
.top
+ aPoint
.y
);
5830 memset(&input
, 0, sizeof(input
));
5832 input
.type
= INPUT_MOUSE
;
5833 input
.mi
.dwFlags
= aNativeMessage
;
5834 ::SendInput(1, &input
, sizeof(INPUT
));
5838 return NS_ERROR_NOT_IMPLEMENTED
;
5842 /**************************************************************
5844 * SECTION: OnXXX message handlers
5846 * For message handlers that need to be broken out or
5847 * implemented in specific platform code.
5849 **************************************************************/
5851 BOOL
nsWindow::OnInputLangChange(HKL aHKL
)
5854 printf("OnInputLanguageChange\n");
5858 gKbdLayout
.LoadLayout(aHKL
);
5861 return PR_FALSE
; // always pass to child window
5864 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5865 void nsWindow::OnWindowPosChanged(WINDOWPOS
*wp
, PRBool
& result
)
5870 #ifdef WINSTATE_DEBUG_OUTPUT
5871 if (mWnd
== GetTopLevelHWND(mWnd
))
5872 printf("*** OnWindowPosChanged: [ top] ");
5874 printf("*** OnWindowPosChanged: [child] ");
5875 printf("WINDOWPOS flags:");
5876 if (wp
->flags
& SWP_FRAMECHANGED
)
5877 printf("SWP_FRAMECHANGED ");
5878 if (wp
->flags
& SWP_SHOWWINDOW
)
5879 printf("SWP_SHOWWINDOW ");
5880 if (wp
->flags
& SWP_NOSIZE
)
5881 printf("SWP_NOSIZE ");
5882 if (wp
->flags
& SWP_HIDEWINDOW
)
5883 printf("SWP_HIDEWINDOW ");
5887 // Handle window size mode changes
5888 if (wp
->flags
& SWP_FRAMECHANGED
&& mSizeMode
!= nsSizeMode_Fullscreen
) {
5889 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
5892 pl
.length
= sizeof(pl
);
5893 ::GetWindowPlacement(mWnd
, &pl
);
5895 if (pl
.showCmd
== SW_SHOWMAXIMIZED
)
5896 event
.mSizeMode
= nsSizeMode_Maximized
;
5897 else if (pl
.showCmd
== SW_SHOWMINIMIZED
)
5898 event
.mSizeMode
= nsSizeMode_Minimized
;
5900 event
.mSizeMode
= nsSizeMode_Normal
;
5902 // Windows has just changed the size mode of this window. The following
5903 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
5904 // set the min/max window state again or for nsSizeMode_Normal, call
5905 // SetWindow with a parameter of SW_RESTORE. There's no need however as
5906 // this window's mode has already changed. Updating mSizeMode here
5907 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
5908 // to window docking. (bug 489258)
5909 mSizeMode
= event
.mSizeMode
;
5911 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
5912 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
5913 // prevents the working set from being trimmed but keeps the window active.
5914 // After the window is minimized, we need to do some touch up work on the
5915 // active window. (bugs 76831 & 499816)
5916 if (!sTrimOnMinimize
&& nsSizeMode_Minimized
== event
.mSizeMode
)
5917 ActivateOtherWindowHelper(mWnd
);
5919 #ifdef WINSTATE_DEBUG_OUTPUT
5920 switch (mSizeMode
) {
5921 case nsSizeMode_Normal
:
5922 printf("*** mSizeMode: nsSizeMode_Normal\n");
5924 case nsSizeMode_Minimized
:
5925 printf("*** mSizeMode: nsSizeMode_Minimized\n");
5927 case nsSizeMode_Maximized
:
5928 printf("*** mSizeMode: nsSizeMode_Maximized\n");
5931 printf("*** mSizeMode: ??????\n");
5938 result
= DispatchWindowEvent(&event
);
5940 // Skip window size change events below on minimization.
5941 if (mSizeMode
== nsSizeMode_Minimized
)
5945 // Handle window size changes
5946 if (0 == (wp
->flags
& SWP_NOSIZE
)) {
5948 PRInt32 newWidth
, newHeight
;
5950 ::GetWindowRect(mWnd
, &r
);
5952 newWidth
= r
.right
- r
.left
;
5953 newHeight
= r
.bottom
- r
.top
;
5954 nsIntRect
rect(wp
->x
, wp
->y
, newWidth
, newHeight
);
5957 if (eTransparencyTransparent
== mTransparencyMode
)
5958 ResizeTranslucentWindow(newWidth
, newHeight
);
5961 if (newWidth
> mLastSize
.width
)
5966 drect
.left
= wp
->x
+ mLastSize
.width
;
5968 drect
.right
= drect
.left
+ (newWidth
- mLastSize
.width
);
5969 drect
.bottom
= drect
.top
+ newHeight
;
5971 ::RedrawWindow(mWnd
, &drect
, NULL
,
5974 RDW_NOINTERNALPAINT
|
5978 if (newHeight
> mLastSize
.height
)
5984 drect
.top
= wp
->y
+ mLastSize
.height
;
5985 drect
.right
= drect
.left
+ newWidth
;
5986 drect
.bottom
= drect
.top
+ (newHeight
- mLastSize
.height
);
5988 ::RedrawWindow(mWnd
, &drect
, NULL
,
5991 RDW_NOINTERNALPAINT
|
5996 mBounds
.width
= newWidth
;
5997 mBounds
.height
= newHeight
;
5998 mLastSize
.width
= newWidth
;
5999 mLastSize
.height
= newHeight
;
6001 #ifdef WINSTATE_DEBUG_OUTPUT
6002 printf("*** Resize window: %d x %d x %d x %d\n", wp
->x
, wp
->y
, newWidth
, newHeight
);
6005 // If a maximized window is resized, recalculate the non-client margins and
6006 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
6008 if (mSizeMode
== nsSizeMode_Maximized
) {
6009 if (UpdateNonClientMargins(nsSizeMode_Maximized
, PR_TRUE
)) {
6010 // gecko resize event already sent by UpdateNonClientMargins.
6016 // Recalculate the width and height based on the client area for gecko events.
6017 if (::GetClientRect(mWnd
, &r
)) {
6018 rect
.width
= r
.right
- r
.left
;
6019 rect
.height
= r
.bottom
- r
.top
;
6022 // Send a gecko resize event
6023 result
= OnResize(rect
);
6028 void nsWindow::ActivateOtherWindowHelper(HWND aWnd
)
6030 // Find the next window that is enabled, visible, and not minimized.
6031 HWND hwndBelow
= ::GetNextWindow(aWnd
, GW_HWNDNEXT
);
6032 while (hwndBelow
&& (!::IsWindowEnabled(hwndBelow
) || !::IsWindowVisible(hwndBelow
) ||
6033 ::IsIconic(hwndBelow
))) {
6034 hwndBelow
= ::GetNextWindow(hwndBelow
, GW_HWNDNEXT
);
6037 // Push ourselves to the bottom of the stack, then activate the
6039 ::SetWindowPos(aWnd
, HWND_BOTTOM
, 0, 0, 0, 0,
6040 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
);
6042 ::SetForegroundWindow(hwndBelow
);
6044 // Play the minimize sound while we're here, since that is also
6045 // forgotten when we use SW_SHOWMINIMIZED.
6046 ::PlaySoundW(L
"Minimize", nsnull
, SND_ALIAS
| SND_NODEFAULT
| SND_ASYNC
);
6048 #endif // !defined(WINCE)
6051 void nsWindow::OnWindowPosChanging(LPWINDOWPOS
& info
)
6053 // Update non-client margins if the frame size is changing, and let the
6054 // browser know we are changing size modes, so alternative css can kick in.
6055 // If we're going into fullscreen mode, ignore this, since it'll reset
6056 // margins to normal mode.
6057 if (info
->flags
& SWP_FRAMECHANGED
&& mSizeMode
!= nsSizeMode_Fullscreen
) {
6059 pl
.length
= sizeof(pl
);
6060 ::GetWindowPlacement(mWnd
, &pl
);
6062 if (pl
.showCmd
== SW_SHOWMAXIMIZED
)
6063 sizeMode
= nsSizeMode_Maximized
;
6064 else if (pl
.showCmd
== SW_SHOWMINIMIZED
)
6065 sizeMode
= nsSizeMode_Minimized
;
6067 sizeMode
= nsSizeMode_Normal
;
6069 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
6072 event
.mSizeMode
= static_cast<nsSizeMode
>(sizeMode
);
6073 DispatchWindowEvent(&event
);
6075 UpdateNonClientMargins(sizeMode
, PR_FALSE
);
6078 // enforce local z-order rules
6079 if (!(info
->flags
& SWP_NOZORDER
)) {
6080 HWND hwndAfter
= info
->hwndInsertAfter
;
6082 nsZLevelEvent
event(PR_TRUE
, NS_SETZLEVEL
, this);
6083 nsWindow
*aboveWindow
= 0;
6087 if (hwndAfter
== HWND_BOTTOM
)
6088 event
.mPlacement
= nsWindowZBottom
;
6089 else if (hwndAfter
== HWND_TOP
|| hwndAfter
== HWND_TOPMOST
|| hwndAfter
== HWND_NOTOPMOST
)
6090 event
.mPlacement
= nsWindowZTop
;
6092 event
.mPlacement
= nsWindowZRelative
;
6093 aboveWindow
= GetNSWindowPtr(hwndAfter
);
6095 event
.mReqBelow
= aboveWindow
;
6096 event
.mActualBelow
= nsnull
;
6098 event
.mImmediate
= PR_FALSE
;
6099 event
.mAdjusted
= PR_FALSE
;
6100 DispatchWindowEvent(&event
);
6102 if (event
.mAdjusted
) {
6103 if (event
.mPlacement
== nsWindowZBottom
)
6104 info
->hwndInsertAfter
= HWND_BOTTOM
;
6105 else if (event
.mPlacement
== nsWindowZTop
)
6106 info
->hwndInsertAfter
= HWND_TOP
;
6108 info
->hwndInsertAfter
= (HWND
)event
.mActualBelow
->GetNativeData(NS_NATIVE_WINDOW
);
6111 NS_IF_RELEASE(event
.mActualBelow
);
6113 // prevent rude external programs from making hidden window visible
6114 if (mWindowType
== eWindowType_invisible
)
6115 info
->flags
&= ~SWP_SHOWWINDOW
;
6119 void nsWindow::UserActivity()
6121 // Check if we have the idle service, if not we try to get it.
6122 if (!mIdleService
) {
6123 mIdleService
= do_GetService("@mozilla.org/widget/idleservice;1");
6126 // Check that we now have the idle service.
6128 mIdleService
->ResetIdleTimeOut();
6132 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6133 PRBool
nsWindow::OnTouch(WPARAM wParam
, LPARAM lParam
)
6135 PRUint32 cInputs
= LOWORD(wParam
);
6136 PTOUCHINPUT pInputs
= new TOUCHINPUT
[cInputs
];
6138 if (mGesture
.GetTouchInputInfo((HTOUCHINPUT
)lParam
, cInputs
, pInputs
)) {
6139 for (PRUint32 i
= 0; i
< cInputs
; i
++) {
6141 if (pInputs
[i
].dwFlags
& TOUCHEVENTF_MOVE
) {
6142 msg
= NS_MOZTOUCH_MOVE
;
6143 } else if (pInputs
[i
].dwFlags
& TOUCHEVENTF_DOWN
) {
6144 msg
= NS_MOZTOUCH_DOWN
;
6145 } else if (pInputs
[i
].dwFlags
& TOUCHEVENTF_UP
) {
6146 msg
= NS_MOZTOUCH_UP
;
6151 nsPointWin touchPoint
;
6152 touchPoint
.x
= TOUCH_COORD_TO_PIXEL(pInputs
[i
].x
);
6153 touchPoint
.y
= TOUCH_COORD_TO_PIXEL(pInputs
[i
].y
);
6154 touchPoint
.ScreenToClient(mWnd
);
6156 nsMozTouchEvent
touchEvent(PR_TRUE
, msg
, this, pInputs
[i
].dwID
);
6157 touchEvent
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6158 touchEvent
.refPoint
= touchPoint
;
6160 nsEventStatus status
;
6161 DispatchEvent(&touchEvent
, status
);
6166 mGesture
.CloseTouchInputHandle((HTOUCHINPUT
)lParam
);
6171 // Gesture event processing. Handles WM_GESTURE events.
6173 PRBool
nsWindow::OnGesture(WPARAM wParam
, LPARAM lParam
)
6175 // Treatment for pan events which translate into scroll events:
6176 if (mGesture
.IsPanEvent(lParam
)) {
6177 nsMouseScrollEvent
event(PR_TRUE
, NS_MOUSE_PIXEL_SCROLL
, this);
6179 if ( !mGesture
.ProcessPanMessage(mWnd
, wParam
, lParam
) )
6180 return PR_FALSE
; // ignore
6182 nsEventStatus status
;
6184 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6185 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6186 event
.isMeta
= PR_FALSE
;
6187 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6189 event
.time
= ::GetMessageTime();
6190 event
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6192 PRBool endFeedback
= PR_TRUE
;
6194 PRInt32 scrollOverflowX
= 0;
6195 PRInt32 scrollOverflowY
= 0;
6197 if (mGesture
.PanDeltaToPixelScrollX(event
)) {
6198 DispatchEvent(&event
, status
);
6199 scrollOverflowX
= event
.scrollOverflow
;
6202 if (mGesture
.PanDeltaToPixelScrollY(event
)) {
6203 DispatchEvent(&event
, status
);
6204 scrollOverflowY
= event
.scrollOverflow
;
6207 if (mDisplayPanFeedback
) {
6208 mGesture
.UpdatePanFeedbackX(mWnd
, scrollOverflowX
, endFeedback
);
6209 mGesture
.UpdatePanFeedbackY(mWnd
, scrollOverflowY
, endFeedback
);
6210 mGesture
.PanFeedbackFinalize(mWnd
, endFeedback
);
6213 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
6218 // Other gestures translate into simple gesture events:
6219 nsSimpleGestureEvent
event(PR_TRUE
, 0, this, 0, 0.0);
6220 if ( !mGesture
.ProcessGestureMessage(mWnd
, wParam
, lParam
, event
) ) {
6221 return PR_FALSE
; // fall through to DefWndProc
6224 // Polish up and send off the new event
6225 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6226 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6227 event
.isMeta
= PR_FALSE
;
6228 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6230 event
.time
= ::GetMessageTime();
6231 event
.inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
;
6233 nsEventStatus status
;
6234 DispatchEvent(&event
, status
);
6235 if (status
== nsEventStatus_eIgnore
) {
6236 return PR_FALSE
; // Ignored, fall through
6239 // Only close this if we process and return true.
6240 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
6242 return PR_TRUE
; // Handled
6244 #endif // !defined(WINCE)
6247 PRUint16
nsWindow::GetMouseInputSource()
6249 PRUint16 inputSource
= nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE
;
6250 LPARAM lParamExtraInfo
= ::GetMessageExtraInfo();
6251 if ((lParamExtraInfo
& TABLET_INK_SIGNATURE
) == TABLET_INK_CHECK
) {
6252 inputSource
= (lParamExtraInfo
& TABLET_INK_TOUCH
) ?
6253 nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH
: nsIDOMNSMouseEvent::MOZ_SOURCE_PEN
;
6259 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6260 * within the message case block. If returning true result should be returned
6261 * immediately (no more processing).
6263 PRBool
nsWindow::OnMouseWheel(UINT msg
, WPARAM wParam
, LPARAM lParam
, PRBool
& getWheelInfo
, PRBool
& result
, LRESULT
*aRetValue
)
6265 // Handle both flavors of mouse wheel events.
6266 static int iDeltaPerLine
, iDeltaPerChar
;
6267 static ULONG ulScrollLines
, ulScrollChars
= 1;
6268 static int currentVDelta
, currentHDelta
;
6269 static HWND currentWindow
= 0;
6271 PRBool isVertical
= msg
== WM_MOUSEWHEEL
;
6273 // Get mouse wheel metrics (but only once).
6275 getWheelInfo
= PR_FALSE
;
6277 SystemParametersInfo (SPI_GETWHEELSCROLLLINES
, 0, &ulScrollLines
, 0);
6279 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6280 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6282 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6283 // the mouse driver wants a page scroll. The docs state that
6284 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6285 // since some mouse drivers use an arbitrary large number instead,
6286 // we have to handle that as well.
6289 if (ulScrollLines
) {
6290 if (ulScrollLines
<= WHEEL_DELTA
) {
6291 iDeltaPerLine
= WHEEL_DELTA
/ ulScrollLines
;
6293 ulScrollLines
= WHEEL_PAGESCROLL
;
6297 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS
, 0,
6298 &ulScrollChars
, 0)) {
6299 // Note that we may always fail to get the value before Win Vista.
6304 if (ulScrollChars
) {
6305 if (ulScrollChars
<= WHEEL_DELTA
) {
6306 iDeltaPerChar
= WHEEL_DELTA
/ ulScrollChars
;
6308 ulScrollChars
= WHEEL_PAGESCROLL
;
6313 if ((isVertical
&& ulScrollLines
!= WHEEL_PAGESCROLL
&& !iDeltaPerLine
) ||
6314 (!isVertical
&& ulScrollChars
!= WHEEL_PAGESCROLL
&& !iDeltaPerChar
))
6315 return PR_FALSE
; // break
6317 // The mousewheel event will be dispatched to the toplevel
6318 // window. We need to give it to the child window
6320 if (!HandleScrollingPlugins(msg
, wParam
, lParam
, result
, aRetValue
, quit
))
6321 return quit
; // return immediately if its not our window
6323 // We should cancel the surplus delta if the current window is not
6324 // same as previous.
6325 if (currentWindow
!= mWnd
) {
6328 currentWindow
= mWnd
;
6331 nsMouseScrollEvent
scrollEvent(PR_TRUE
, NS_MOUSE_SCROLL
, this);
6332 scrollEvent
.delta
= 0;
6334 scrollEvent
.scrollFlags
= nsMouseScrollEvent::kIsVertical
;
6335 if (ulScrollLines
== WHEEL_PAGESCROLL
) {
6336 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
6337 scrollEvent
.delta
= (((short) HIWORD (wParam
)) > 0) ? -1 : 1;
6339 currentVDelta
-= (short) HIWORD (wParam
);
6340 if (PR_ABS(currentVDelta
) >= iDeltaPerLine
) {
6341 scrollEvent
.delta
= currentVDelta
/ iDeltaPerLine
;
6342 currentVDelta
%= iDeltaPerLine
;
6346 scrollEvent
.scrollFlags
= nsMouseScrollEvent::kIsHorizontal
;
6347 if (ulScrollChars
== WHEEL_PAGESCROLL
) {
6348 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
6349 scrollEvent
.delta
= (((short) HIWORD (wParam
)) > 0) ? 1 : -1;
6351 currentHDelta
+= (short) HIWORD (wParam
);
6352 if (PR_ABS(currentHDelta
) >= iDeltaPerChar
) {
6353 scrollEvent
.delta
= currentHDelta
/ iDeltaPerChar
;
6354 currentHDelta
%= iDeltaPerChar
;
6359 if (!scrollEvent
.delta
) {
6360 // We store the wheel delta, and it will be used next wheel message, so,
6361 // we consume this message actually. We shouldn't call next wndproc.
6363 return PR_FALSE
; // break
6367 // The event may go to a plug-in which already dispatched this message.
6368 // Then, the event can cause deadlock. We should unlock the sender here.
6369 ::ReplyMessage(isVertical
? 0 : TRUE
);
6372 scrollEvent
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6373 scrollEvent
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6374 scrollEvent
.isMeta
= PR_FALSE
;
6375 scrollEvent
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6376 InitEvent(scrollEvent
);
6377 if (nsnull
!= mEventCallback
) {
6378 result
= DispatchWindowEvent(&scrollEvent
);
6380 // Note that we should return zero if we process WM_MOUSEWHEEL.
6381 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6384 *aRetValue
= isVertical
? 0 : TRUE
;
6386 return PR_FALSE
; // break;
6390 StringCaseInsensitiveEquals(const PRUnichar
* aChars1
, const PRUint32 aNumChars1
,
6391 const PRUnichar
* aChars2
, const PRUint32 aNumChars2
)
6393 if (aNumChars1
!= aNumChars2
)
6396 nsCaseInsensitiveStringComparator comp
;
6397 return comp(aChars1
, aChars2
, aNumChars1
) == 0;
6400 UINT
nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode
)
6403 switch (aNativeKeyCode
) {
6404 case VK_OEM_1
: return NS_VK_SEMICOLON
; // 0xBA, For the US standard keyboard, the ';:' key
6405 case VK_OEM_PLUS
: return NS_VK_ADD
; // 0xBB, For any country/region, the '+' key
6406 case VK_OEM_MINUS
: return NS_VK_SUBTRACT
; // 0xBD, For any country/region, the '-' key
6410 return aNativeKeyCode
;
6414 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6415 * WM_CHAR messages for processing. During testing we don't want to
6416 * mess with the real message queue. Instead we pass a
6417 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6418 * that as if it was in the message queue, and refrain from actually
6419 * looking at or touching the message queue.
6421 LRESULT
nsWindow::OnKeyDown(const MSG
&aMsg
,
6422 nsModifierKeyState
&aModKeyState
,
6423 PRBool
*aEventDispatched
,
6424 nsFakeCharMessage
* aFakeCharMessage
)
6426 UINT virtualKeyCode
= aMsg
.wParam
;
6429 gKbdLayout
.OnKeyDown (virtualKeyCode
);
6432 // Use only DOMKeyCode for XP processing.
6433 // Use aVirtualKeyCode for gKbdLayout and native processing.
6434 UINT DOMKeyCode
= nsIMM32Handler::IsComposingOn(this) ?
6435 virtualKeyCode
: MapFromNativeToDOM(virtualKeyCode
);
6438 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6442 DispatchKeyEvent(NS_KEY_DOWN
, 0, nsnull
, DOMKeyCode
, &aMsg
, aModKeyState
);
6443 if (aEventDispatched
)
6444 *aEventDispatched
= PR_TRUE
;
6446 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6447 // for almost all keys
6448 switch (DOMKeyCode
) {
6452 case NS_VK_CAPS_LOCK
:
6453 case NS_VK_NUM_LOCK
:
6454 case NS_VK_SCROLL_LOCK
: return noDefault
;
6457 PRUint32 extraFlags
= (noDefault
? NS_EVENT_FLAG_NO_DEFAULT
: 0);
6459 BOOL gotMsg
= aFakeCharMessage
||
6460 ::PeekMessageW(&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_NOREMOVE
| PM_NOYIELD
);
6461 // Enter and backspace are always handled here to avoid for example the
6462 // confusion between ctrl-enter and ctrl-J.
6463 if (DOMKeyCode
== NS_VK_RETURN
|| DOMKeyCode
== NS_VK_BACK
||
6464 ((aModKeyState
.mIsControlDown
|| aModKeyState
.mIsAltDown
)
6468 && !gKbdLayout
.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)))
6471 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6472 // They can be more than one because of:
6473 // * Dead-keys not pairing with base character
6474 // * Some keyboard layouts may map up to 4 characters to the single key
6475 PRBool anyCharMessagesRemoved
= PR_FALSE
;
6477 if (aFakeCharMessage
) {
6478 anyCharMessagesRemoved
= PR_TRUE
;
6480 while (gotMsg
&& (msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
))
6482 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6483 ("%s charCode=%d scanCode=%d\n", msg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
6484 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
6485 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST
, WM_KEYLAST
);
6486 anyCharMessagesRemoved
= PR_TRUE
;
6488 gotMsg
= ::PeekMessageW (&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_NOREMOVE
| PM_NOYIELD
);
6492 if (!anyCharMessagesRemoved
&& DOMKeyCode
== NS_VK_BACK
&&
6493 nsIMM32Handler::IsDoingKakuteiUndo(mWnd
)) {
6494 NS_ASSERTION(!aFakeCharMessage
,
6495 "We shouldn't be touching the real msg queue");
6496 RemoveMessageAndDispatchPluginEvent(WM_CHAR
, WM_CHAR
);
6500 (aFakeCharMessage
||
6501 msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
|| msg
.message
== WM_DEADCHAR
)) {
6502 if (aFakeCharMessage
)
6503 return OnCharRaw(aFakeCharMessage
->mCharCode
,
6504 aFakeCharMessage
->mScanCode
, aModKeyState
, extraFlags
);
6506 // If prevent default set for keydown, do same for keypress
6507 ::GetMessageW(&msg
, mWnd
, msg
.message
, msg
.message
);
6509 if (msg
.message
== WM_DEADCHAR
) {
6510 if (!PluginHasFocus())
6513 // We need to send the removed message to focused plug-in.
6514 DispatchPluginEvent(msg
);
6518 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6519 ("%s charCode=%d scanCode=%d\n",
6520 msg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
6521 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
6523 BOOL result
= OnChar(msg
, aModKeyState
, nsnull
, extraFlags
);
6524 // If a syschar keypress wasn't processed, Windows may want to
6525 // handle it to activate a native menu.
6526 if (!result
&& msg
.message
== WM_SYSCHAR
)
6527 ::DefWindowProcW(mWnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
6531 else if (!aModKeyState
.mIsControlDown
&& !aModKeyState
.mIsAltDown
&&
6532 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode
) ||
6533 KeyboardLayout::IsNumpadKey(virtualKeyCode
)))
6535 // If this is simple KeyDown event but next message is not WM_CHAR,
6536 // this event may not input text, so we should ignore this event.
6538 return PluginHasFocus() && noDefault
;
6541 if (gKbdLayout
.IsDeadKey ())
6542 return PluginHasFocus() && noDefault
;
6544 PRUint8 shiftStates
[5];
6545 PRUnichar uniChars
[5];
6546 PRUnichar shiftedChars
[5] = {0, 0, 0, 0, 0};
6547 PRUnichar unshiftedChars
[5] = {0, 0, 0, 0, 0};
6548 PRUnichar shiftedLatinChar
= 0;
6549 PRUnichar unshiftedLatinChar
= 0;
6550 PRUint32 numOfUniChars
= 0;
6551 PRUint32 numOfShiftedChars
= 0;
6552 PRUint32 numOfUnshiftedChars
= 0;
6553 PRUint32 numOfShiftStates
= 0;
6555 switch (virtualKeyCode
) {
6556 // keys to be sent as characters
6557 case VK_ADD
: uniChars
[0] = '+'; numOfUniChars
= 1; break;
6558 case VK_SUBTRACT
: uniChars
[0] = '-'; numOfUniChars
= 1; break;
6559 case VK_DIVIDE
: uniChars
[0] = '/'; numOfUniChars
= 1; break;
6560 case VK_MULTIPLY
: uniChars
[0] = '*'; numOfUniChars
= 1; break;
6571 uniChars
[0] = virtualKeyCode
- VK_NUMPAD0
+ '0';
6575 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)) {
6576 numOfUniChars
= numOfShiftStates
=
6577 gKbdLayout
.GetUniChars(uniChars
, shiftStates
,
6578 NS_ARRAY_LENGTH(uniChars
));
6581 if (aModKeyState
.mIsControlDown
^ aModKeyState
.mIsAltDown
) {
6582 PRUint8 capsLockState
= (::GetKeyState(VK_CAPITAL
) & 1) ? eCapsLock
: 0;
6583 numOfUnshiftedChars
=
6584 gKbdLayout
.GetUniCharsWithShiftState(virtualKeyCode
, capsLockState
,
6585 unshiftedChars
, NS_ARRAY_LENGTH(unshiftedChars
));
6587 gKbdLayout
.GetUniCharsWithShiftState(virtualKeyCode
,
6588 capsLockState
| eShift
,
6589 shiftedChars
, NS_ARRAY_LENGTH(shiftedChars
));
6591 // The current keyboard cannot input alphabets or numerics,
6592 // we should append them for Shortcut/Access keys.
6593 // E.g., for Cyrillic keyboard layout.
6594 if (NS_VK_A
<= DOMKeyCode
&& DOMKeyCode
<= NS_VK_Z
) {
6595 shiftedLatinChar
= unshiftedLatinChar
= DOMKeyCode
;
6597 shiftedLatinChar
+= 0x20;
6599 unshiftedLatinChar
+= 0x20;
6600 if (unshiftedLatinChar
== unshiftedChars
[0] &&
6601 shiftedLatinChar
== shiftedChars
[0]) {
6602 shiftedLatinChar
= unshiftedLatinChar
= 0;
6606 if (NS_VK_0
<= DOMKeyCode
&& DOMKeyCode
<= NS_VK_9
) {
6609 switch (virtualKeyCode
) {
6610 case VK_OEM_PLUS
: ch
= '+'; break;
6611 case VK_OEM_MINUS
: ch
= '-'; break;
6614 if (ch
&& unshiftedChars
[0] != ch
&& shiftedChars
[0] != ch
) {
6615 // Windows has assigned a virtual key code to the key even though
6616 // the character can't be produced with this key. That probably
6617 // means the character can't be produced with any key in the
6618 // current layout and so the assignment is based on a QWERTY
6619 // layout. Append this code so that users can access the shortcut.
6620 unshiftedLatinChar
= ch
;
6624 // If the charCode is not ASCII character, we should replace the
6625 // charCode with ASCII character only when Ctrl is pressed.
6626 // But don't replace the charCode when the charCode is not same as
6627 // unmodified characters. In such case, Ctrl is sometimes used for a
6628 // part of character inputting key combination like Shift.
6629 if (aModKeyState
.mIsControlDown
) {
6630 PRUint8 currentState
= eCtrl
;
6631 if (aModKeyState
.mIsShiftDown
)
6632 currentState
|= eShift
;
6635 aModKeyState
.mIsShiftDown
? shiftedLatinChar
: unshiftedLatinChar
;
6637 (numOfUniChars
== 0 ||
6638 StringCaseInsensitiveEquals(uniChars
, numOfUniChars
,
6639 aModKeyState
.mIsShiftDown
? shiftedChars
: unshiftedChars
,
6640 aModKeyState
.mIsShiftDown
? numOfShiftedChars
:
6641 numOfUnshiftedChars
))) {
6642 numOfUniChars
= numOfShiftStates
= 1;
6644 shiftStates
[0] = currentState
;
6650 if (numOfUniChars
> 0 || numOfShiftedChars
> 0 || numOfUnshiftedChars
> 0) {
6651 PRUint32 num
= PR_MAX(numOfUniChars
,
6652 PR_MAX(numOfShiftedChars
, numOfUnshiftedChars
));
6653 PRUint32 skipUniChars
= num
- numOfUniChars
;
6654 PRUint32 skipShiftedChars
= num
- numOfShiftedChars
;
6655 PRUint32 skipUnshiftedChars
= num
- numOfUnshiftedChars
;
6656 UINT keyCode
= numOfUniChars
== 0 ? DOMKeyCode
: 0;
6657 for (PRUint32 cnt
= 0; cnt
< num
; cnt
++) {
6658 PRUint16 uniChar
, shiftedChar
, unshiftedChar
;
6659 uniChar
= shiftedChar
= unshiftedChar
= 0;
6660 if (skipUniChars
<= cnt
) {
6661 if (cnt
- skipUniChars
< numOfShiftStates
) {
6662 // If key in combination with Alt and/or Ctrl produces a different
6663 // character than without them then do not report these flags
6664 // because it is separate keyboard layout shift state. If dead-key
6665 // and base character does not produce a valid composite character
6666 // then both produced dead-key character and following base
6667 // character may have different modifier flags, too.
6668 aModKeyState
.mIsShiftDown
=
6669 (shiftStates
[cnt
- skipUniChars
] & eShift
) != 0;
6670 aModKeyState
.mIsControlDown
=
6671 (shiftStates
[cnt
- skipUniChars
] & eCtrl
) != 0;
6672 aModKeyState
.mIsAltDown
=
6673 (shiftStates
[cnt
- skipUniChars
] & eAlt
) != 0;
6675 uniChar
= uniChars
[cnt
- skipUniChars
];
6677 if (skipShiftedChars
<= cnt
)
6678 shiftedChar
= shiftedChars
[cnt
- skipShiftedChars
];
6679 if (skipUnshiftedChars
<= cnt
)
6680 unshiftedChar
= unshiftedChars
[cnt
- skipUnshiftedChars
];
6681 nsAutoTArray
<nsAlternativeCharCode
, 5> altArray
;
6683 if (shiftedChar
|| unshiftedChar
) {
6684 nsAlternativeCharCode
chars(unshiftedChar
, shiftedChar
);
6685 altArray
.AppendElement(chars
);
6687 if (cnt
== num
- 1 && (unshiftedLatinChar
|| shiftedLatinChar
)) {
6688 nsAlternativeCharCode
chars(unshiftedLatinChar
, shiftedLatinChar
);
6689 altArray
.AppendElement(chars
);
6692 DispatchKeyEvent(NS_KEY_PRESS
, uniChar
, &altArray
,
6693 keyCode
, nsnull
, aModKeyState
, extraFlags
);
6696 DispatchKeyEvent(NS_KEY_PRESS
, 0, nsnull
, DOMKeyCode
, nsnull
, aModKeyState
,
6701 UINT unichar
= ::MapVirtualKey(virtualKeyCode
, MAPVK_VK_TO_CHAR
);
6702 // Check for dead characters or no mapping
6703 if (unichar
& 0x80) {
6706 DispatchKeyEvent(NS_KEY_PRESS
, unichar
, nsnull
, DOMKeyCode
, nsnull
, aModKeyState
,
6715 LRESULT
nsWindow::OnKeyUp(const MSG
&aMsg
,
6716 nsModifierKeyState
&aModKeyState
,
6717 PRBool
*aEventDispatched
)
6719 UINT virtualKeyCode
= aMsg
.wParam
;
6721 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
6722 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode
));
6724 if (!nsIMM32Handler::IsComposingOn(this)) {
6725 virtualKeyCode
= MapFromNativeToDOM(virtualKeyCode
);
6728 if (aEventDispatched
)
6729 *aEventDispatched
= PR_TRUE
;
6730 return DispatchKeyEvent(NS_KEY_UP
, 0, nsnull
, virtualKeyCode
, &aMsg
,
6735 LRESULT
nsWindow::OnChar(const MSG
&aMsg
, nsModifierKeyState
&aModKeyState
,
6736 PRBool
*aEventDispatched
, PRUint32 aFlags
)
6738 return OnCharRaw(aMsg
.wParam
, HIWORD(aMsg
.lParam
) & 0xFF, aModKeyState
,
6739 aFlags
, &aMsg
, aEventDispatched
);
6743 LRESULT
nsWindow::OnCharRaw(UINT charCode
, UINT aScanCode
,
6744 nsModifierKeyState
&aModKeyState
, PRUint32 aFlags
,
6745 const MSG
*aMsg
, PRBool
*aEventDispatched
)
6747 // ignore [shift+]alt+space so the OS can handle it
6748 if (aModKeyState
.mIsAltDown
&& !aModKeyState
.mIsControlDown
&&
6749 IS_VK_DOWN(NS_VK_SPACE
)) {
6753 // Ignore Ctrl+Enter (bug 318235)
6754 if (aModKeyState
.mIsControlDown
&& charCode
== 0xA) {
6758 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
6759 PRBool saveIsAltDown
= aModKeyState
.mIsAltDown
;
6760 PRBool saveIsControlDown
= aModKeyState
.mIsControlDown
;
6761 if (aModKeyState
.mIsAltDown
&& aModKeyState
.mIsControlDown
)
6762 aModKeyState
.mIsAltDown
= aModKeyState
.mIsControlDown
= PR_FALSE
;
6766 if (nsIMM32Handler::IsComposingOn(this)) {
6770 if (aModKeyState
.mIsControlDown
&& charCode
<= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
6771 // need to account for shift here. bug 16486
6772 if (aModKeyState
.mIsShiftDown
)
6773 uniChar
= charCode
- 1 + 'A';
6775 uniChar
= charCode
- 1 + 'a';
6778 else if (aModKeyState
.mIsControlDown
&& charCode
<= 0x1F) {
6779 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
6780 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
6781 // for some reason the keypress handler need to have the uniChar code set
6782 // with the addition of a upper case A not the lower case.
6783 uniChar
= charCode
- 1 + 'A';
6785 } else { // 0x20 - SPACE, 0x3D - EQUALS
6786 if (charCode
< 0x20 || (charCode
== 0x3D && aModKeyState
.mIsControlDown
)) {
6794 // Keep the characters unshifted for shortcuts and accesskeys and make sure
6795 // that numbers are always passed as such (among others: bugs 50255 and 351310)
6796 if (uniChar
&& (aModKeyState
.mIsControlDown
|| aModKeyState
.mIsAltDown
)) {
6797 UINT virtualKeyCode
= ::MapVirtualKeyEx(aScanCode
, MAPVK_VSC_TO_VK
,
6798 gKbdLayout
.GetLayout());
6799 UINT unshiftedCharCode
=
6800 virtualKeyCode
>= '0' && virtualKeyCode
<= '9' ? virtualKeyCode
:
6801 aModKeyState
.mIsShiftDown
? ::MapVirtualKeyEx(virtualKeyCode
,
6803 gKbdLayout
.GetLayout()) : 0;
6804 // ignore diacritics (top bit set) and key mapping errors (char code 0)
6805 if ((INT
)unshiftedCharCode
> 0)
6806 uniChar
= unshiftedCharCode
;
6809 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
6810 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
6812 if (!aModKeyState
.mIsShiftDown
&& (saveIsAltDown
|| saveIsControlDown
)) {
6813 uniChar
= towlower(uniChar
);
6816 PRBool result
= DispatchKeyEvent(NS_KEY_PRESS
, uniChar
, nsnull
,
6817 charCode
, aMsg
, aModKeyState
, aFlags
);
6818 if (aEventDispatched
)
6819 *aEventDispatched
= PR_TRUE
;
6820 aModKeyState
.mIsAltDown
= saveIsAltDown
;
6821 aModKeyState
.mIsControlDown
= saveIsControlDown
;
6826 nsWindow::SetupKeyModifiersSequence(nsTArray
<KeyPair
>* aArray
, PRUint32 aModifiers
)
6828 for (PRUint32 i
= 0; i
< NS_ARRAY_LENGTH(sModifierKeyMap
); ++i
) {
6829 const PRUint32
* map
= sModifierKeyMap
[i
];
6830 if (aModifiers
& map
[0]) {
6831 aArray
->AppendElement(KeyPair(map
[1], map
[2]));
6837 nsWindow::ConfigureChildren(const nsTArray
<Configuration
>& aConfigurations
)
6839 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
6840 // here, if that helps in some situations. So far I haven't seen a
6842 for (PRUint32 i
= 0; i
< aConfigurations
.Length(); ++i
) {
6843 const Configuration
& configuration
= aConfigurations
[i
];
6844 nsWindow
* w
= static_cast<nsWindow
*>(configuration
.mChild
);
6845 NS_ASSERTION(w
->GetParent() == this,
6846 "Configured widget is not a child");
6848 // MSDN says we should do on WinCE this before moving or resizing the window
6849 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
6850 // We put the region back just below, anyway.
6851 ::SetWindowRgn(w
->mWnd
, NULL
, TRUE
);
6854 w
->GetBounds(bounds
);
6855 if (bounds
.Size() != configuration
.mBounds
.Size()) {
6856 w
->Resize(configuration
.mBounds
.x
, configuration
.mBounds
.y
,
6857 configuration
.mBounds
.width
, configuration
.mBounds
.height
,
6859 } else if (bounds
.TopLeft() != configuration
.mBounds
.TopLeft()) {
6860 w
->Move(configuration
.mBounds
.x
, configuration
.mBounds
.y
);
6862 nsresult rv
= w
->SetWindowClipRegion(configuration
.mClipRegion
, PR_FALSE
);
6863 NS_ENSURE_SUCCESS(rv
, rv
);
6869 CreateHRGNFromArray(const nsTArray
<nsIntRect
>& aRects
)
6871 PRInt32 size
= sizeof(RGNDATAHEADER
) + sizeof(RECT
)*aRects
.Length();
6872 nsAutoTArray
<PRUint8
,100> buf
;
6873 if (!buf
.SetLength(size
))
6875 RGNDATA
* data
= reinterpret_cast<RGNDATA
*>(buf
.Elements());
6876 RECT
* rects
= reinterpret_cast<RECT
*>(data
->Buffer
);
6877 data
->rdh
.dwSize
= sizeof(data
->rdh
);
6878 data
->rdh
.iType
= RDH_RECTANGLES
;
6879 data
->rdh
.nCount
= aRects
.Length();
6881 for (PRUint32 i
= 0; i
< aRects
.Length(); ++i
) {
6882 const nsIntRect
& r
= aRects
[i
];
6883 bounds
.UnionRect(bounds
, r
);
6884 ::SetRect(&rects
[i
], r
.x
, r
.y
, r
.XMost(), r
.YMost());
6886 ::SetRect(&data
->rdh
.rcBound
, bounds
.x
, bounds
.y
, bounds
.XMost(), bounds
.YMost());
6887 return ::ExtCreateRegion(NULL
, buf
.Length(), data
);
6891 nsWindow::SetWindowClipRegion(const nsTArray
<nsIntRect
>& aRects
,
6892 PRBool aIntersectWithExisting
)
6894 if (!aIntersectWithExisting
) {
6895 if (!StoreWindowClipRegion(aRects
))
6899 HRGN dest
= CreateHRGNFromArray(aRects
);
6901 return NS_ERROR_OUT_OF_MEMORY
;
6903 if (aIntersectWithExisting
) {
6904 HRGN current
= ::CreateRectRgn(0, 0, 0, 0);
6906 if (::GetWindowRgn(mWnd
, current
) != 0 /*ERROR*/) {
6907 ::CombineRgn(dest
, dest
, current
, RGN_AND
);
6909 ::DeleteObject(current
);
6913 if (!::SetWindowRgn(mWnd
, dest
, TRUE
)) {
6914 ::DeleteObject(dest
);
6915 return NS_ERROR_FAILURE
;
6920 // WM_DESTROY event handler
6921 void nsWindow::OnDestroy()
6923 mOnDestroyCalled
= PR_TRUE
;
6925 // Make sure we don't get destroyed in the process of tearing down.
6926 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
6928 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
6930 DispatchStandardEvent(NS_DESTROY
);
6932 // Prevent the widget from sending additional events.
6933 mEventCallback
= nsnull
;
6935 // Free our subclass and clear |this| stored in the window props. We will no longer
6936 // receive events from Windows after this point.
6937 SubclassWindow(FALSE
);
6939 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
6940 // cleared. (It's used in tracking windows for mouse events.)
6941 if (sCurrentWindow
== this)
6942 sCurrentWindow
= nsnull
;
6944 // Disconnects us from our parent, will call our GetParent().
6945 nsBaseWidget::Destroy();
6947 // Release references to children, device context, toolkit, and app shell.
6948 nsBaseWidget::OnDestroy();
6950 // Clear our native parent handle.
6951 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
6952 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
6953 //SetParent(nsnull);
6956 // We have to destroy the native drag target before we null out our window pointer.
6957 EnableDragDrop(PR_FALSE
);
6959 // If we're going away and for some reason we're still the rollup widget, rollup and
6960 // turn off capture.
6961 if ( this == sRollupWidget
) {
6962 if ( sRollupListener
)
6963 sRollupListener
->Rollup(nsnull
, nsnull
);
6964 CaptureRollupEvents(nsnull
, nsnull
, PR_FALSE
, PR_TRUE
);
6967 // If IME is disabled, restore it.
6969 mOldIMC
= ::ImmAssociateContext(mWnd
, mOldIMC
);
6970 NS_ASSERTION(!mOldIMC
, "Another IMC was associated");
6973 // Turn off mouse trails if enabled.
6974 MouseTrailer
* mtrailer
= nsToolkit::gMouseTrailer
;
6976 if (mtrailer
->GetMouseTrailerWindow() == mWnd
)
6977 mtrailer
->DestroyTimer();
6979 if (mtrailer
->GetCaptureWindow() == mWnd
)
6980 mtrailer
->SetCaptureWindow(nsnull
);
6983 // Free GDI window class objects
6985 VERIFY(::DeleteObject(mBrush
));
6989 // Free app icon resources.
6991 icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_BIG
, (LPARAM
) 0);
6993 ::DestroyIcon(icon
);
6995 icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_SMALL
, (LPARAM
) 0);
6997 ::DestroyIcon(icon
);
6999 // Destroy any custom cursor resources.
7001 SetCursor(eCursor_standard
);
7004 // Reset transparency
7005 if (eTransparencyTransparent
== mTransparencyMode
)
7006 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque
);
7009 #if defined(WINCE_HAVE_SOFTKB)
7010 // Revert the changes made for the software keyboard settings
7011 nsWindowCE::ResetSoftKB(mWnd
);
7015 // Finalize panning feedback to possibly restore window displacement
7016 mGesture
.PanFeedbackFinalize(mWnd
, PR_TRUE
);
7019 // Clear the main HWND.
7024 PRBool
nsWindow::OnMove(PRInt32 aX
, PRInt32 aY
)
7029 nsGUIEvent
event(PR_TRUE
, NS_MOVE
, this);
7031 event
.refPoint
.x
= aX
;
7032 event
.refPoint
.y
= aY
;
7034 return DispatchWindowEvent(&event
);
7037 // Send a resize message to the listener
7038 PRBool
nsWindow::OnResize(nsIntRect
&aWindowRect
)
7040 #ifdef CAIRO_HAS_D2D_SURFACE
7041 if (mD2DWindowSurface
) {
7042 mD2DWindowSurface
= NULL
;
7043 Invalidate(PR_FALSE
);
7046 // call the event callback
7047 if (mEventCallback
) {
7048 nsSizeEvent
event(PR_TRUE
, NS_SIZE
, this);
7050 event
.windowSize
= &aWindowRect
;
7052 if (::GetWindowRect(mWnd
, &r
)) {
7053 event
.mWinWidth
= PRInt32(r
.right
- r
.left
);
7054 event
.mWinHeight
= PRInt32(r
.bottom
- r
.top
);
7056 event
.mWinWidth
= 0;
7057 event
.mWinHeight
= 0;
7061 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7062 aWindowRect
.x
, aWindowRect
.y
, aWindowRect
.width
, aWindowRect
.height
,
7063 event
.mWinWidth
, event
.mWinHeight
);
7066 return DispatchWindowEvent(&event
);
7072 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7073 PRBool
nsWindow::OnHotKey(WPARAM wParam
, LPARAM lParam
)
7077 #endif // !defined(WINCE)
7079 void nsWindow::OnSettingsChange(WPARAM wParam
, LPARAM lParam
)
7081 if (mWindowType
== eWindowType_dialog
||
7082 mWindowType
== eWindowType_toplevel
)
7083 nsWindowGfx::OnSettingsChangeGfx(wParam
);
7086 static PRBool
IsOurProcessWindow(HWND aHWND
)
7088 DWORD processId
= 0;
7089 ::GetWindowThreadProcessId(aHWND
, &processId
);
7090 return processId
== ::GetCurrentProcessId();
7093 static HWND
FindOurProcessWindow(HWND aHWND
)
7095 for (HWND wnd
= ::GetParent(aHWND
); wnd
; wnd
= ::GetParent(wnd
)) {
7096 if (IsOurProcessWindow(wnd
)) {
7103 // Scrolling helper function for handling plugins.
7104 // Return value indicates whether the calling function should handle this
7105 // aHandled indicates whether this was handled at all
7106 // aQuitProcessing tells whether or not to continue processing the message
7107 PRBool
nsWindow::HandleScrollingPlugins(UINT aMsg
, WPARAM aWParam
,
7108 LPARAM aLParam
, PRBool
& aHandled
,
7110 PRBool
& aQuitProcessing
)
7112 // The scroll event will be dispatched to the toplevel
7113 // window. We need to give it to the child window
7114 aQuitProcessing
= PR_FALSE
; // default is to not stop processing
7116 DWORD dwPoints
= ::GetMessagePos();
7117 point
.x
= GET_X_LPARAM(dwPoints
);
7118 point
.y
= GET_Y_LPARAM(dwPoints
);
7120 static PRBool sIsProcessing
= PR_FALSE
;
7121 if (sIsProcessing
) {
7122 return PR_TRUE
; // the caller should handle this.
7125 static PRBool sMayBeUsingLogitechMouse
= PR_FALSE
;
7126 if (aMsg
== WM_MOUSEHWHEEL
) {
7127 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7128 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7129 // message at first time, this time, ::GetMessagePos works fine.
7130 // Then, we will return 0 (0 means we process it) to the message. Then, the
7131 // driver will POST the same messages continuously during the wheel tilted.
7132 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7133 // cursor isn't 0,0. Therefore, we cannot trust the result of
7134 // ::GetMessagePos API if the sender is the driver.
7135 if (!sMayBeUsingLogitechMouse
&& aLParam
== 0 && aLParam
!= dwPoints
&&
7136 ::InSendMessage()) {
7137 sMayBeUsingLogitechMouse
= PR_TRUE
;
7138 } else if (sMayBeUsingLogitechMouse
&& aLParam
!= 0 && ::InSendMessage()) {
7139 // The user has changed the mouse from Logitech's to another one (e.g.,
7140 // the user has changed to the touchpad of the notebook.
7141 sMayBeUsingLogitechMouse
= PR_FALSE
;
7143 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7144 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7146 if (sMayBeUsingLogitechMouse
&& aLParam
== 0 && dwPoints
== 0) {
7147 ::GetCursorPos(&point
);
7151 HWND destWnd
= ::WindowFromPoint(point
);
7152 // Since we receive scroll events for as long as
7153 // we are focused, it's entirely possible that there
7154 // is another app's window or no window under the
7158 // No window is under the pointer
7159 return PR_FALSE
; // break, but continue processing
7162 nsWindow
* destWindow
;
7164 // We don't handle the message if the found window belongs to another
7165 // process's top window. If it belongs window, that is a plug-in's window.
7166 // Then, we need to send the message to the plug-in window.
7167 if (!IsOurProcessWindow(destWnd
)) {
7168 HWND ourPluginWnd
= FindOurProcessWindow(destWnd
);
7169 if (!ourPluginWnd
) {
7170 // Somebody elses window
7171 return PR_FALSE
; // break, but continue processing
7173 destWindow
= GetNSWindowPtr(ourPluginWnd
);
7175 destWindow
= GetNSWindowPtr(destWnd
);
7178 if (destWindow
== this && mWindowType
== eWindowType_plugin
) {
7179 // If this is plug-in window, the message came from the plug-in window.
7180 // Then, the message should be processed on the parent window.
7181 destWindow
= static_cast<nsWindow
*>(GetParent());
7182 NS_ENSURE_TRUE(destWindow
, PR_FALSE
); // break, but continue processing
7183 destWnd
= destWindow
->mWnd
;
7184 NS_ENSURE_TRUE(destWnd
, PR_FALSE
); // break, but continue processing
7187 if (!destWindow
|| destWindow
->mWindowType
== eWindowType_plugin
) {
7188 // Some other app, or a plugin window.
7189 // Windows directs scrolling messages to the focused window.
7190 // However, Mozilla does not like plugins having focus, so a
7191 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7192 // Therefore, plugins etc _should_ get first grab at the
7193 // message, but this focus vaguary means the plugin misses
7194 // out. If the window is a child of ours, forward it on.
7195 // Determine if a child by walking the parent list until
7196 // we find a parent matching our wndproc.
7197 HWND parentWnd
= ::GetParent(destWnd
);
7199 nsWindow
* parentWindow
= GetNSWindowPtr(parentWnd
);
7201 // We have a child window - quite possibly a plugin window.
7202 // However, not all plugins are created equal - some will handle this
7203 // message themselves, some will forward directly back to us, while
7204 // others will call DefWndProc, which itself still forwards back to us.
7205 // So if we have sent it once, we need to handle it ourself.
7208 // XXX The message shouldn't come from the plugin window at here.
7209 // But the message might come from it due to some bugs. If it happens,
7210 // SendMessage causes deadlock. For safety, we should unlock the
7212 ::ReplyMessage(aMsg
== WM_MOUSEHWHEEL
? TRUE
: 0);
7215 // First time we have seen this message.
7216 // Call the child - either it will consume it, or
7217 // it will wind it's way back to us,triggering the destWnd case above
7218 // either way,when the call returns,we are all done with the message,
7219 sIsProcessing
= PR_TRUE
;
7220 ::SendMessageW(destWnd
, aMsg
, aWParam
, aLParam
);
7221 sIsProcessing
= PR_FALSE
;
7223 aQuitProcessing
= PR_TRUE
;
7224 return PR_FALSE
; // break, and stop processing
7226 parentWnd
= ::GetParent(parentWnd
);
7227 } // while parentWnd
7229 if (destWnd
== nsnull
)
7231 if (destWnd
!= mWnd
) {
7233 sIsProcessing
= PR_TRUE
;
7234 aHandled
= destWindow
->ProcessMessage(aMsg
, aWParam
, aLParam
, aRetValue
);
7235 sIsProcessing
= PR_FALSE
;
7236 aQuitProcessing
= PR_TRUE
;
7237 return PR_FALSE
; // break, and stop processing
7241 printf("WARNING: couldn't get child window for SCROLL event\n");
7244 return PR_TRUE
; // caller should handle this
7247 PRBool
nsWindow::OnScroll(UINT aMsg
, WPARAM aWParam
, LPARAM aLParam
)
7249 static PRInt8 sMouseWheelEmulation
= -1;
7250 if (sMouseWheelEmulation
< 0) {
7251 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
7252 NS_ENSURE_TRUE(prefs
, PR_FALSE
);
7253 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
7254 prefs
->GetBranch(0, getter_AddRefs(prefBranch
));
7255 NS_ENSURE_TRUE(prefBranch
, PR_FALSE
);
7258 prefBranch
->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate
);
7259 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7260 sMouseWheelEmulation
= PRInt8(emulate
);
7263 if (aLParam
|| sMouseWheelEmulation
) {
7264 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7265 // Treat as a mousewheel message and scroll appropriately
7266 PRBool quit
, result
;
7269 if (!HandleScrollingPlugins(aMsg
, aWParam
, aLParam
, result
, &retVal
, quit
))
7270 return quit
; // Return if it's not our message or has been dispatched
7272 nsMouseScrollEvent
scrollevent(PR_TRUE
, NS_MOUSE_SCROLL
, this);
7273 scrollevent
.scrollFlags
= (aMsg
== WM_VSCROLL
)
7274 ? nsMouseScrollEvent::kIsVertical
7275 : nsMouseScrollEvent::kIsHorizontal
;
7276 switch (LOWORD(aWParam
))
7279 scrollevent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
7281 scrollevent
.delta
= 1;
7284 scrollevent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
7286 scrollevent
.delta
= -1;
7292 // The event may go to a plug-in which already dispatched this message.
7293 // Then, the event can cause deadlock. We should unlock the sender here.
7296 scrollevent
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
7297 scrollevent
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
7298 scrollevent
.isMeta
= PR_FALSE
;
7299 scrollevent
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
7300 InitEvent(scrollevent
);
7301 if (nsnull
!= mEventCallback
)
7303 DispatchWindowEvent(&scrollevent
);
7308 // Scroll message generated by external application
7309 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_SCROLL
, this);
7311 command
.mScroll
.mIsHorizontal
= (aMsg
== WM_HSCROLL
);
7313 switch (LOWORD(aWParam
))
7315 case SB_LINEUP
: // SB_LINELEFT
7316 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Line
;
7317 command
.mScroll
.mAmount
= -1;
7319 case SB_LINEDOWN
: // SB_LINERIGHT
7320 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Line
;
7321 command
.mScroll
.mAmount
= 1;
7323 case SB_PAGEUP
: // SB_PAGELEFT
7324 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Page
;
7325 command
.mScroll
.mAmount
= -1;
7327 case SB_PAGEDOWN
: // SB_PAGERIGHT
7328 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Page
;
7329 command
.mScroll
.mAmount
= 1;
7331 case SB_TOP
: // SB_LEFT
7332 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Whole
;
7333 command
.mScroll
.mAmount
= -1;
7335 case SB_BOTTOM
: // SB_RIGHT
7336 command
.mScroll
.mUnit
= nsContentCommandEvent::eCmdScrollUnit_Whole
;
7337 command
.mScroll
.mAmount
= 1;
7342 DispatchWindowEvent(&command
);
7346 // Can be overriden. Controls auto-erase of background.
7347 PRBool
nsWindow::AutoErase(HDC dc
)
7352 /**************************************************************
7353 **************************************************************
7355 ** BLOCK: IME management and accessibility
7357 ** Handles managing IME input and accessibility.
7359 **************************************************************
7360 **************************************************************/
7362 NS_IMETHODIMP
nsWindow::ResetInputState()
7364 #ifdef DEBUG_KBSTATE
7365 printf("ResetInputState\n");
7368 #ifdef NS_ENABLE_TSF
7369 nsTextStore::CommitComposition(PR_FALSE
);
7370 #endif //NS_ENABLE_TSF
7372 nsIMM32Handler::CommitComposition(this);
7376 NS_IMETHODIMP
nsWindow::SetIMEOpenState(PRBool aState
)
7378 #ifdef DEBUG_KBSTATE
7379 printf("SetIMEOpenState %s\n", (aState
? "Open" : "Close"));
7382 #ifdef NS_ENABLE_TSF
7383 nsTextStore::SetIMEOpenState(aState
);
7384 #endif //NS_ENABLE_TSF
7386 nsIMEContext
IMEContext(mWnd
);
7387 if (IMEContext
.IsValid()) {
7388 ::ImmSetOpenStatus(IMEContext
.get(), aState
? TRUE
: FALSE
);
7393 NS_IMETHODIMP
nsWindow::GetIMEOpenState(PRBool
* aState
)
7395 nsIMEContext
IMEContext(mWnd
);
7396 if (IMEContext
.IsValid()) {
7397 BOOL isOpen
= ::ImmGetOpenStatus(IMEContext
.get());
7398 *aState
= isOpen
? PR_TRUE
: PR_FALSE
;
7402 #ifdef NS_ENABLE_TSF
7403 *aState
|= nsTextStore::GetIMEOpenState();
7404 #endif //NS_ENABLE_TSF
7409 NS_IMETHODIMP
nsWindow::SetIMEEnabled(PRUint32 aState
)
7411 #ifdef NS_ENABLE_TSF
7412 nsTextStore::SetIMEEnabled(aState
);
7413 #endif //NS_ENABLE_TSF
7414 #ifdef DEBUG_KBSTATE
7415 printf("SetIMEEnabled: %s\n", (aState
== nsIWidget::IME_STATUS_ENABLED
||
7416 aState
== nsIWidget::IME_STATUS_PLUGIN
)?
7417 "Enabled": "Disabled");
7419 if (nsIMM32Handler::IsComposing()) {
7422 mIMEEnabled
= aState
;
7423 PRBool enable
= (aState
== nsIWidget::IME_STATUS_ENABLED
||
7424 aState
== nsIWidget::IME_STATUS_PLUGIN
);
7426 #if defined(WINCE_HAVE_SOFTKB)
7427 sSoftKeyboardState
= (aState
!= nsIWidget::IME_STATUS_DISABLED
);
7428 nsWindowCE::ToggleSoftKB(mWnd
, sSoftKeyboardState
);
7431 if (!enable
!= !mOldIMC
)
7433 mOldIMC
= ::ImmAssociateContext(mWnd
, enable
? mOldIMC
: NULL
);
7434 NS_ASSERTION(!enable
|| !mOldIMC
, "Another IMC was associated");
7439 NS_IMETHODIMP
nsWindow::GetIMEEnabled(PRUint32
* aState
)
7441 #ifdef DEBUG_KBSTATE
7442 printf("GetIMEEnabled: %s\n", mIMEEnabled
? "Enabled": "Disabled");
7444 *aState
= mIMEEnabled
;
7448 NS_IMETHODIMP
nsWindow::CancelIMEComposition()
7450 #ifdef DEBUG_KBSTATE
7451 printf("CancelIMEComposition\n");
7454 #ifdef NS_ENABLE_TSF
7455 nsTextStore::CommitComposition(PR_TRUE
);
7456 #endif //NS_ENABLE_TSF
7458 nsIMM32Handler::CancelComposition(this);
7463 nsWindow::GetToggledKeyState(PRUint32 aKeyCode
, PRBool
* aLEDState
)
7465 #ifdef DEBUG_KBSTATE
7466 printf("GetToggledKeyState\n");
7468 NS_ENSURE_ARG_POINTER(aLEDState
);
7469 *aLEDState
= (::GetKeyState(aKeyCode
) & 1) != 0;
7473 #ifdef NS_ENABLE_TSF
7475 nsWindow::OnIMEFocusChange(PRBool aFocus
)
7477 nsresult rv
= nsTextStore::OnFocusChange(aFocus
, this, mIMEEnabled
);
7478 if (rv
== NS_ERROR_NOT_AVAILABLE
)
7479 rv
= NS_ERROR_NOT_IMPLEMENTED
; // TSF is not enabled, maybe.
7484 nsWindow::OnIMETextChange(PRUint32 aStart
,
7488 return nsTextStore::OnTextChange(aStart
, aOldEnd
, aNewEnd
);
7492 nsWindow::OnIMESelectionChange(void)
7494 return nsTextStore::OnSelectionChange();
7496 #endif //NS_ENABLE_TSF
7498 #ifdef ACCESSIBILITY
7500 #ifdef DEBUG_WMGETOBJECT
7501 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
7502 nsAccessible* acc = aWnd ? \
7503 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
7504 printf(" acc: %p", acc); \
7506 nsAutoString name; \
7507 acc->GetName(name); \
7508 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
7509 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
7510 void *hwnd = nsnull; \
7511 doc->GetWindowHandle(&hwnd); \
7512 printf(", acc hwnd: %d", hwnd); \
7515 #define NS_LOG_WMGETOBJECT_THISWND \
7517 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
7518 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p, content type: %d,\n",\
7519 mWnd, ::GetParent(mWnd), this, mContentType); \
7520 NS_LOG_WMGETOBJECT_WNDACC(this) \
7524 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
7526 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
7527 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7528 aHwnd, ::GetParent(aHwnd), wnd); \
7529 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
7533 #define NS_LOG_WMGETOBJECT_THISWND
7534 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
7535 #endif // DEBUG_WMGETOBJECT
7538 nsWindow::GetRootAccessible()
7540 // We want the ability to forcibly disable a11y on windows, because
7541 // some non-a11y-related components attempt to bring it up. See bug
7542 // 538530 for details; we have a pref here that allows it to be disabled
7543 // for performance and testing resons.
7545 // This pref is checked only once, and the browser needs a restart to
7546 // pick up any changes.
7547 static int accForceDisable
= -1;
7549 if (accForceDisable
== -1) {
7550 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
7551 PRBool b
= PR_FALSE
;
7552 nsresult rv
= prefs
->GetBoolPref("accessibility.win32.force_disabled", &b
);
7553 if (NS_SUCCEEDED(rv
) && b
) {
7554 accForceDisable
= 1;
7556 accForceDisable
= 0;
7560 // If the pref was true, return null here, disabling a11y.
7561 if (accForceDisable
)
7564 nsWindow::sIsAccessibilityOn
= TRUE
;
7566 if (mInDtor
|| mOnDestroyCalled
|| mWindowType
== eWindowType_invisible
) {
7570 NS_LOG_WMGETOBJECT_THISWND
7572 if (mContentType
!= eContentTypeInherit
) {
7573 // We're on a MozillaContentWindowClass or MozillaUIWindowClass window.
7574 // Search for the correct visible child window to get an accessible
7575 // document from. Make sure to use an active child window. If this window
7576 // doesn't have child windows then return an accessible for it.
7577 HWND accessibleWnd
= ::GetTopWindow(mWnd
);
7578 NS_LOG_WMGETOBJECT_WND("Top Window", accessibleWnd
);
7579 if (!accessibleWnd
) {
7580 NS_LOG_WMGETOBJECT_WND("This Window", mWnd
);
7581 return DispatchAccessibleEvent(NS_GETACCESSIBLE
);
7584 nsWindow
* accessibleWindow
= nsnull
;
7585 while (accessibleWnd
) {
7586 // Loop through windows and find the first one with accessibility info
7587 accessibleWindow
= GetNSWindowPtr(accessibleWnd
);
7588 if (accessibleWindow
) {
7589 nsAccessible
*rootAccessible
=
7590 accessibleWindow
->DispatchAccessibleEvent(NS_GETACCESSIBLE
);
7591 if (rootAccessible
) {
7592 // Success, one of the child windows was active.
7593 return rootAccessible
;
7596 accessibleWnd
= ::GetNextWindow(accessibleWnd
, GW_HWNDNEXT
);
7597 NS_LOG_WMGETOBJECT_WND("Next Window", accessibleWnd
);
7602 NS_LOG_WMGETOBJECT_WND("This Window", mWnd
);
7603 return DispatchAccessibleEvent(NS_GETACCESSIBLE
);
7606 STDMETHODIMP_(LRESULT
)
7607 nsWindow::LresultFromObject(REFIID riid
, WPARAM wParam
, LPUNKNOWN pAcc
)
7609 // open the dll dynamically
7611 sAccLib
=::LoadLibraryW(L
"OLEACC.DLL");
7614 if (!sLresultFromObject
)
7615 sLresultFromObject
= (LPFNLRESULTFROMOBJECT
)GetProcAddress(sAccLib
,"LresultFromObject");
7617 if (sLresultFromObject
)
7618 return sLresultFromObject(riid
,wParam
,pAcc
);
7625 /**************************************************************
7626 **************************************************************
7628 ** BLOCK: Transparency
7630 ** Window transparency helpers.
7632 **************************************************************
7633 **************************************************************/
7637 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth
, PRInt32 aNewHeight
, PRBool force
)
7639 if (!force
&& aNewWidth
== mBounds
.width
&& aNewHeight
== mBounds
.height
)
7642 #ifdef CAIRO_HAS_D2D_SURFACE
7643 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7644 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7645 nsRefPtr
<gfxD2DSurface
> newSurface
=
7646 new gfxD2DSurface(gfxIntSize(aNewWidth
, aNewHeight
), gfxASurface::ImageFormatARGB32
);
7647 mTransparentSurface
= newSurface
;
7652 nsRefPtr
<gfxWindowsSurface
> newSurface
=
7653 new gfxWindowsSurface(gfxIntSize(aNewWidth
, aNewHeight
), gfxASurface::ImageFormatARGB32
);
7654 mTransparentSurface
= newSurface
;
7655 mMemoryDC
= newSurface
->GetDC();
7659 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode
)
7663 if (aMode
== mTransparencyMode
)
7666 // stop on dialogs and popups!
7667 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
7668 nsWindow
* parent
= GetNSWindowPtr(hWnd
);
7672 NS_WARNING("Trying to use transparent chrome in an embedded context");
7676 if (parent
!= this) {
7677 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
7680 if (aMode
== eTransparencyTransparent
) {
7681 // If we're switching to the use of a transparent window, hide the chrome
7683 HideWindowChrome(PR_TRUE
);
7684 } else if (mHideChrome
&& mTransparencyMode
== eTransparencyTransparent
) {
7685 // if we're switching out of transparent, re-enable our parent's chrome.
7686 HideWindowChrome(PR_FALSE
);
7689 LONG_PTR style
= ::GetWindowLongPtrW(hWnd
, GWL_STYLE
),
7690 exStyle
= ::GetWindowLongPtr(hWnd
, GWL_EXSTYLE
);
7692 if (parent
->mIsVisible
)
7693 style
|= WS_VISIBLE
;
7694 if (parent
->mSizeMode
== nsSizeMode_Maximized
)
7695 style
|= WS_MAXIMIZE
;
7696 else if (parent
->mSizeMode
== nsSizeMode_Minimized
)
7697 style
|= WS_MINIMIZE
;
7699 if (aMode
== eTransparencyTransparent
)
7700 exStyle
|= WS_EX_LAYERED
;
7702 exStyle
&= ~WS_EX_LAYERED
;
7704 VERIFY_WINDOW_STYLE(style
);
7705 ::SetWindowLongPtrW(hWnd
, GWL_STYLE
, style
);
7706 ::SetWindowLongPtrW(hWnd
, GWL_EXSTYLE
, exStyle
);
7708 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7709 if (mTransparencyMode
== eTransparencyGlass
)
7710 memset(&mGlassMargins
, 0, sizeof mGlassMargins
);
7711 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7712 mTransparencyMode
= aMode
;
7714 SetupTranslucentWindowMemoryBitmap(aMode
);
7716 #endif // #ifndef WINCE
7719 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode
)
7721 if (eTransparencyTransparent
== aMode
) {
7722 ResizeTranslucentWindow(mBounds
.width
, mBounds
.height
, PR_TRUE
);
7724 mTransparentSurface
= nsnull
;
7729 nsresult
nsWindow::UpdateTranslucentWindow()
7732 if (mBounds
.IsEmpty())
7737 BLENDFUNCTION bf
= { AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
7738 SIZE winSize
= { mBounds
.width
, mBounds
.height
};
7739 POINT srcPos
= { 0, 0 };
7740 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
7742 ::GetWindowRect(hWnd
, &winRect
);
7744 #ifdef CAIRO_HAS_D2D_SURFACE
7745 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7746 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7747 mMemoryDC
= static_cast<gfxD2DSurface
*>(mTransparentSurface
.get())->
7751 // perform the alpha blend
7752 PRBool updateSuccesful
=
7753 ::UpdateLayeredWindow(hWnd
, NULL
, (POINT
*)&winRect
, &winSize
, mMemoryDC
, &srcPos
, 0, &bf
, ULW_ALPHA
);
7755 #ifdef CAIRO_HAS_D2D_SURFACE
7756 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7757 gfxWindowsPlatform::RENDER_DIRECT2D
) {
7758 nsIntRect
r(0, 0, 0, 0);
7759 static_cast<gfxD2DSurface
*>(mTransparentSurface
.get())->ReleaseDC(&r
);
7763 if (!updateSuccesful
) {
7764 return NS_ERROR_FAILURE
;
7773 /**************************************************************
7774 **************************************************************
7776 ** BLOCK: Popup rollup hooks
7778 ** Deals with CaptureRollup on popup windows.
7780 **************************************************************
7781 **************************************************************/
7784 // Schedules a timer for a window, so we can rollup after processing the hook event
7785 void nsWindow::ScheduleHookTimer(HWND aWnd
, UINT aMsgId
)
7787 // In some cases multiple hooks may be scheduled
7788 // so ignore any other requests once one timer is scheduled
7789 if (sHookTimerId
== 0) {
7790 // Remember the window handle and the message ID to be used later
7791 sRollupMsgId
= aMsgId
;
7792 sRollupMsgWnd
= aWnd
;
7793 // Schedule native timer for doing the rollup after
7794 // this event is done being processed
7795 sHookTimerId
= ::SetTimer(NULL
, 0, 0, (TIMERPROC
)HookTimerForPopups
);
7796 NS_ASSERTION(sHookTimerId
, "Timer couldn't be created.");
7800 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7801 int gLastMsgCode
= 0;
7802 extern MSGFEventMsgInfo gMSGFEvents
[];
7805 // Process Menu messages, rollup when popup is clicked.
7806 LRESULT CALLBACK
nsWindow::MozSpecialMsgFilter(int code
, WPARAM wParam
, LPARAM lParam
)
7808 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7810 MSG
* pMsg
= (MSG
*)lParam
;
7813 while (gMSGFEvents
[inx
].mId
!= code
&& gMSGFEvents
[inx
].mStr
!= NULL
) {
7816 if (code
!= gLastMsgCode
) {
7817 if (gMSGFEvents
[inx
].mId
== code
) {
7819 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code
, gMSGFEvents
[inx
].mStr
, pMsg
->hwnd
);
7823 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code
, gMSGFEvents
[inx
].mId
, pMsg
->hwnd
);
7826 gLastMsgCode
= code
;
7828 PrintEvent(pMsg
->message
, FALSE
, FALSE
);
7830 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7832 if (sProcessHook
&& code
== MSGF_MENU
) {
7833 MSG
* pMsg
= (MSG
*)lParam
;
7834 ScheduleHookTimer( pMsg
->hwnd
, pMsg
->message
);
7837 return ::CallNextHookEx(sMsgFilterHook
, code
, wParam
, lParam
);
7840 // Process all mouse messages. Roll up when a click is in a native window
7841 // that doesn't have an nsIWidget.
7842 LRESULT CALLBACK
nsWindow::MozSpecialMouseProc(int code
, WPARAM wParam
, LPARAM lParam
)
7846 case WM_LBUTTONDOWN
:
7847 case WM_RBUTTONDOWN
:
7848 case WM_MBUTTONDOWN
:
7850 case WM_MOUSEHWHEEL
:
7852 MOUSEHOOKSTRUCT
* ms
= (MOUSEHOOKSTRUCT
*)lParam
;
7853 nsIWidget
* mozWin
= (nsIWidget
*)GetNSWindowPtr(ms
->hwnd
);
7855 // If this window is windowed plugin window, the mouse events are not
7857 if (static_cast<nsWindow
*>(mozWin
)->mWindowType
== eWindowType_plugin
)
7858 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
7860 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
7866 return ::CallNextHookEx(sCallMouseHook
, code
, wParam
, lParam
);
7869 // Process all messages. Roll up when the window is moving, or
7870 // is resizing or when maximized or mininized.
7871 LRESULT CALLBACK
nsWindow::MozSpecialWndProc(int code
, WPARAM wParam
, LPARAM lParam
)
7873 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7875 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
7876 PrintEvent(cwpt
->message
, FALSE
, FALSE
);
7881 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
7882 if (cwpt
->message
== WM_MOVING
||
7883 cwpt
->message
== WM_SIZING
||
7884 cwpt
->message
== WM_GETMINMAXINFO
) {
7885 ScheduleHookTimer(cwpt
->hwnd
, (UINT
)cwpt
->message
);
7889 return ::CallNextHookEx(sCallProcHook
, code
, wParam
, lParam
);
7892 // Register the special "hooks" for dropdown processing.
7893 void nsWindow::RegisterSpecialDropdownHooks()
7895 NS_ASSERTION(!sMsgFilterHook
, "sMsgFilterHook must be NULL!");
7896 NS_ASSERTION(!sCallProcHook
, "sCallProcHook must be NULL!");
7898 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
7900 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
7902 // Install msg hook for moving the window and resizing
7903 if (!sMsgFilterHook
) {
7904 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
7905 sMsgFilterHook
= SetWindowsHookEx(WH_MSGFILTER
, MozSpecialMsgFilter
, NULL
, GetCurrentThreadId());
7906 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7907 if (!sMsgFilterHook
) {
7908 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
7913 // Install msg hook for menus
7914 if (!sCallProcHook
) {
7915 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
7916 sCallProcHook
= SetWindowsHookEx(WH_CALLWNDPROC
, MozSpecialWndProc
, NULL
, GetCurrentThreadId());
7917 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7918 if (!sCallProcHook
) {
7919 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
7924 // Install msg hook for the mouse
7925 if (!sCallMouseHook
) {
7926 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
7927 sCallMouseHook
= SetWindowsHookEx(WH_MOUSE
, MozSpecialMouseProc
, NULL
, GetCurrentThreadId());
7928 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7929 if (!sCallMouseHook
) {
7930 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
7936 // Unhook special message hooks for dropdowns.
7937 void nsWindow::UnregisterSpecialDropdownHooks()
7939 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
7941 if (sCallProcHook
) {
7942 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
7943 if (!::UnhookWindowsHookEx(sCallProcHook
)) {
7944 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
7946 sCallProcHook
= NULL
;
7949 if (sMsgFilterHook
) {
7950 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
7951 if (!::UnhookWindowsHookEx(sMsgFilterHook
)) {
7952 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
7954 sMsgFilterHook
= NULL
;
7957 if (sCallMouseHook
) {
7958 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
7959 if (!::UnhookWindowsHookEx(sCallMouseHook
)) {
7960 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
7962 sCallMouseHook
= NULL
;
7966 // This timer is designed to only fire one time at most each time a "hook" function
7967 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
7968 // hook, but that hook event or a subsequent event may roll up the dropdown before
7969 // this timer function is executed.
7971 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
7972 // before this function fires.
7973 VOID CALLBACK
nsWindow::HookTimerForPopups(HWND hwnd
, UINT uMsg
, UINT idEvent
, DWORD dwTime
)
7975 if (sHookTimerId
!= 0) {
7976 // if the window is NULL then we need to use the ID to kill the timer
7977 BOOL status
= ::KillTimer(NULL
, sHookTimerId
);
7978 NS_ASSERTION(status
, "Hook Timer was not killed.");
7982 if (sRollupMsgId
!= 0) {
7983 // Note: DealWithPopups does the check to make sure that
7984 // sRollupListener and sRollupWidget are not NULL
7985 LRESULT popupHandlingResult
;
7986 nsAutoRollup autoRollup
;
7987 DealWithPopups(sRollupMsgWnd
, sRollupMsgId
, 0, 0, &popupHandlingResult
);
7989 sRollupMsgWnd
= NULL
;
7994 static PRBool
IsDifferentThreadWindow(HWND aWnd
)
7996 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd
, NULL
);
8000 nsWindow::EventIsInsideWindow(UINT Msg
, nsWindow
* aWindow
)
8005 if (Msg
== WM_ACTIVATEAPP
)
8006 // don't care about activation/deactivation
8009 if (Msg
== WM_ACTIVATE
)
8010 // but on Windows CE we do care about
8011 // activation/deactivation because there doesn't exist
8012 // cancelable Mouse Activation events
8016 ::GetWindowRect(aWindow
->mWnd
, &r
);
8017 DWORD pos
= ::GetMessagePos();
8019 mp
.x
= GET_X_LPARAM(pos
);
8020 mp
.y
= GET_Y_LPARAM(pos
);
8022 // was the event inside this window?
8023 return (PRBool
) PtInRect(&r
, mp
);
8026 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8028 nsWindow::DealWithPopups(HWND inWnd
, UINT inMsg
, WPARAM inWParam
, LPARAM inLParam
, LRESULT
* outResult
)
8030 if (sRollupListener
&& sRollupWidget
&& ::IsWindowVisible(inWnd
)) {
8032 if (inMsg
== WM_LBUTTONDOWN
|| inMsg
== WM_RBUTTONDOWN
|| inMsg
== WM_MBUTTONDOWN
||
8033 inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
|| inMsg
== WM_ACTIVATE
||
8034 (inMsg
== WM_KILLFOCUS
&& IsDifferentThreadWindow((HWND
)inWParam
))
8037 inMsg
== WM_NCRBUTTONDOWN
||
8038 inMsg
== WM_MOVING
||
8039 inMsg
== WM_SIZING
||
8040 inMsg
== WM_NCLBUTTONDOWN
||
8041 inMsg
== WM_NCMBUTTONDOWN
||
8042 inMsg
== WM_MOUSEACTIVATE
||
8043 inMsg
== WM_ACTIVATEAPP
||
8044 inMsg
== WM_MENUSELECT
8048 // Rollup if the event is outside the popup.
8049 PRBool rollup
= !nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)sRollupWidget
);
8051 if (rollup
&& (inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
))
8053 sRollupListener
->ShouldRollupOnMouseWheelEvent(&rollup
);
8054 *outResult
= PR_TRUE
;
8057 // If we're dealing with menus, we probably have submenus and we don't
8058 // want to rollup if the click is in a parent menu of the current submenu.
8059 PRUint32 popupsToRollup
= PR_UINT32_MAX
;
8061 if ( sMenuRollup
) {
8062 nsAutoTArray
<nsIWidget
*, 5> widgetChain
;
8063 PRUint32 sameTypeCount
= sMenuRollup
->GetSubmenuWidgetChain(&widgetChain
);
8064 for ( PRUint32 i
= 0; i
< widgetChain
.Length(); ++i
) {
8065 nsIWidget
* widget
= widgetChain
[i
];
8066 if ( nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)widget
) ) {
8067 // don't roll up if the mouse event occurred within a menu of the
8068 // same type. If the mouse event occurred in a menu higher than
8069 // that, roll up, but pass the number of popups to Rollup so
8070 // that only those of the same type close up.
8071 if (i
< sameTypeCount
) {
8075 popupsToRollup
= sameTypeCount
;
8079 } // foreach parent menu widget
8080 } // if rollup listener knows about menus
8084 if (inMsg
== WM_MOUSEACTIVATE
&& popupsToRollup
== PR_UINT32_MAX
) {
8085 // Prevent the click inside the popup from causing a change in window
8086 // activation. Since the popup is shown non-activated, we need to eat
8087 // any requests to activate the window while it is displayed. Windows
8088 // will automatically activate the popup on the mousedown otherwise.
8090 *outResult
= MA_NOACTIVATE
;
8095 UINT uMsg
= HIWORD(inLParam
);
8096 if (uMsg
== WM_MOUSEMOVE
)
8098 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8099 // must be enabled in Windows.
8100 sRollupListener
->ShouldRollupOnMouseActivate(&rollup
);
8103 *outResult
= MA_NOACTIVATE
;
8109 // if we've still determined that we should still rollup everything, do it.
8113 // sRollupConsumeEvent may be modified by
8114 // nsIRollupListener::Rollup.
8115 PRBool consumeRollupEvent
= sRollupConsumeEvent
;
8116 // only need to deal with the last rollup for left mouse down events.
8117 sRollupListener
->Rollup(popupsToRollup
, inMsg
== WM_LBUTTONDOWN
? &mLastRollup
: nsnull
);
8119 // Tell hook to stop processing messages
8120 sProcessHook
= PR_FALSE
;
8122 sRollupMsgWnd
= NULL
;
8124 // return TRUE tells Windows that the event is consumed,
8125 // false allows the event to be dispatched
8127 // So if we are NOT supposed to be consuming events, let it go through
8128 if (consumeRollupEvent
&& inMsg
!= WM_RBUTTONDOWN
) {
8133 // if we are only rolling up some popups, don't activate and don't let
8134 // the event go through. This prevents clicks menus higher in the
8135 // chain from opening when a context menu is open
8136 if (popupsToRollup
!= PR_UINT32_MAX
&& inMsg
== WM_MOUSEACTIVATE
) {
8137 *outResult
= MA_NOACTIVATEANDEAT
;
8142 } // if event that might trigger a popup to rollup
8143 } // if rollup listeners registered
8148 /**************************************************************
8149 **************************************************************
8151 ** BLOCK: Misc. utility methods and functions.
8155 **************************************************************
8156 **************************************************************/
8158 // nsModifierKeyState used in various character processing.
8159 nsModifierKeyState::nsModifierKeyState()
8161 mIsShiftDown
= IS_VK_DOWN(NS_VK_SHIFT
);
8162 mIsControlDown
= IS_VK_DOWN(NS_VK_CONTROL
);
8163 mIsAltDown
= IS_VK_DOWN(NS_VK_ALT
);
8167 PRInt32
nsWindow::GetWindowsVersion()
8172 static PRInt32 version
= 0;
8173 static PRBool didCheck
= PR_FALSE
;
8178 OSVERSIONINFOEX osInfo
;
8179 osInfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
8180 // This cast is safe and supposed to be here, don't worry
8181 ::GetVersionEx((OSVERSIONINFO
*)&osInfo
);
8182 version
= (osInfo
.dwMajorVersion
& 0xff) << 8 | (osInfo
.dwMinorVersion
& 0xff);
8188 // Note that the result of GetTopLevelWindow method can be different from the
8189 // result of GetTopLevelHWND method. The result can be non-floating window.
8190 // Because our top level window may be contained in another window which is
8191 // not managed by us.
8192 nsWindow
* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup
)
8194 nsWindow
* curWindow
= this;
8197 if (aStopOnDialogOrPopup
) {
8198 switch (curWindow
->mWindowType
) {
8199 case eWindowType_dialog
:
8200 case eWindowType_popup
:
8205 // Retrieve the top level parent or owner window
8206 nsWindow
* parentWindow
= curWindow
->GetParentWindow(PR_TRUE
);
8211 curWindow
= parentWindow
;
8215 // Note that the result of GetTopLevelHWND can be different from the result
8216 // of GetTopLevelWindow method. Because this is checking whether the window
8217 // is top level only in Win32 window system. Therefore, the result window
8218 // may not be managed by us.
8219 HWND
nsWindow::GetTopLevelHWND(HWND aWnd
, PRBool aStopOnDialogOrPopup
)
8228 if (aStopOnDialogOrPopup
) {
8229 DWORD_PTR style
= ::GetWindowLongPtrW(curWnd
, GWL_STYLE
);
8231 VERIFY_WINDOW_STYLE(style
);
8233 if (!(style
& WS_CHILD
)) // first top-level window
8237 upWnd
= ::GetParent(curWnd
); // Parent or owner (if has no parent)
8240 // For dialog windows, we want just the parent, not the owner.
8241 // For other/popup windows, we want to find the first owner/parent
8242 // that's a dialog and/or has an owner.
8243 if (upWnd
&& ::GetWindow(curWnd
, GW_OWNER
) == upWnd
) {
8244 DWORD_PTR style
= ::GetWindowLongPtrW(curWnd
, GWL_STYLE
);
8245 if ((style
& WS_DLGFRAME
) != 0)
8256 static BOOL CALLBACK
gEnumWindowsProc(HWND hwnd
, LPARAM lParam
)
8259 ::GetWindowThreadProcessId(hwnd
, &pid
);
8260 if (pid
== GetCurrentProcessId() && ::IsWindowVisible(hwnd
))
8262 gWindowsVisible
= PR_TRUE
;
8268 PRBool
nsWindow::CanTakeFocus()
8270 gWindowsVisible
= PR_FALSE
;
8271 EnumWindows(gEnumWindowsProc
, 0);
8272 if (!gWindowsVisible
) {
8275 HWND fgWnd
= ::GetForegroundWindow();
8280 GetWindowThreadProcessId(fgWnd
, &pid
);
8281 if (pid
== GetCurrentProcessId()) {
8289 void nsWindow::InitTrackPointHack()
8291 // Init Trackpoint Hack
8295 const WCHAR wstrKeys
[][40] = {L
"Software\\Lenovo\\TrackPoint",
8296 L
"Software\\Lenovo\\UltraNav",
8297 L
"Software\\Alps\\Apoint\\TrackPoint",
8298 L
"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
8299 L
"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
8300 // If anything fails turn the hack off
8301 sTrackPointHack
= false;
8302 nsCOMPtr
<nsIPrefBranch
> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
));
8303 if(NS_SUCCEEDED(rv
) && prefs
) {
8304 prefs
->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue
);
8305 switch (lHackValue
) {
8306 // 0 means hack disabled
8309 // 1 means hack enabled
8311 sTrackPointHack
= true;
8313 // -1 means autodetect
8315 for(int i
= 0; i
< NS_ARRAY_LENGTH(wstrKeys
); i
++) {
8317 lResult
= ::RegOpenKeyExW(HKEY_CURRENT_USER
, (LPCWSTR
)&wstrKeys
[i
],
8318 0, KEY_READ
, &hKey
);
8319 ::RegCloseKey(hKey
);
8320 if(lResult
== ERROR_SUCCESS
) {
8321 // If we detected a registry key belonging to a TrackPoint driver
8323 sTrackPointHack
= true;
8328 // Shouldn't be any other values, but treat them as disabled
8335 #endif // #if !defined(WINCE)
8337 LPARAM
nsWindow::lParamToScreen(LPARAM lParam
)
8340 pt
.x
= GET_X_LPARAM(lParam
);
8341 pt
.y
= GET_Y_LPARAM(lParam
);
8342 ::ClientToScreen(mWnd
, &pt
);
8343 return MAKELPARAM(pt
.x
, pt
.y
);
8346 LPARAM
nsWindow::lParamToClient(LPARAM lParam
)
8349 pt
.x
= GET_X_LPARAM(lParam
);
8350 pt
.y
= GET_Y_LPARAM(lParam
);
8351 ::ScreenToClient(mWnd
, &pt
);
8352 return MAKELPARAM(pt
.x
, pt
.y
);
8355 /**************************************************************
8356 **************************************************************
8358 ** BLOCK: ChildWindow impl.
8360 ** Child window overrides.
8362 **************************************************************
8363 **************************************************************/
8365 // return the style for a child nsWindow
8366 DWORD
ChildWindow::WindowStyle()
8368 DWORD style
= WS_CLIPCHILDREN
| nsWindow::WindowStyle();
8369 if (!(style
& WS_POPUP
))
8370 style
|= WS_CHILD
; // WS_POPUP and WS_CHILD are mutually exclusive.
8371 VERIFY_WINDOW_STYLE(style
);