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 <mats.palmgren@bredband.net>
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 "nsIPrefService.h"
129 #include "nsIObserverService.h"
130 #include "nsIScreenManager.h"
131 #include "imgIContainer.h"
133 #include "nsIRollupListener.h"
134 #include "nsIMenuRollup.h"
135 #include "nsIRegion.h"
136 #include "nsIServiceManager.h"
137 #include "nsIClipboard.h"
138 #include "nsIMM32Handler.h"
139 #include "nsILocalFile.h"
140 #include "nsIFontMetrics.h"
141 #include "nsIFontEnumerator.h"
142 #include "nsIDeviceContext.h"
143 #include "nsIdleService.h"
144 #include "nsGUIEvent.h"
147 #include "nsThreadUtils.h"
148 #include "nsNativeCharsetUtils.h"
149 #include "nsWidgetAtoms.h"
150 #include "nsUnicharUtils.h"
152 #include "nsAppDirectoryServiceDefs.h"
153 #include "nsXPIDLString.h"
154 #include "nsWidgetsCID.h"
155 #include "nsTHashtable.h"
156 #include "nsHashKeys.h"
157 #include "nsString.h"
160 #include "nsWindowCE.h"
163 #if defined(WINCE_WINDOWS_MOBILE)
164 #define KILL_PRIORITY_ID 2444
167 #include "nsWindowGfx.h"
170 #include "nsUXThemeData.h"
171 #include "nsUXThemeConstants.h"
172 #include "nsKeyboardLayout.h"
173 #include "nsNativeDragTarget.h"
174 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
177 #include <richedit.h>
178 #endif // !defined(WINCE)
180 #if defined(ACCESSIBILITY)
183 #if !defined(WINABLEAPI)
185 #endif // !defined(WINABLEAPI)
186 #include "nsIAccessible.h"
187 #include "nsIAccessibleDocument.h"
188 #include "nsIAccessNode.h"
189 #endif // defined(ACCESSIBILITY)
191 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
192 #include "nsIWinTaskbar.h"
195 #if defined(NS_ENABLE_TSF)
196 #include "nsTextStore.h"
197 #endif // defined(NS_ENABLE_TSF)
199 #if defined(MOZ_SPLASHSCREEN)
200 #include "nsSplashScreen.h"
201 #endif // defined(MOZ_SPLASHSCREEN)
203 // Windowless plugin support
206 #include "nsWindowDefs.h"
208 #ifdef WINCE_WINDOWS_MOBILE
209 #include "nsGfxCIID.h"
212 /**************************************************************
213 **************************************************************
217 ** nsWindow Class static initializations and global variables.
219 **************************************************************
220 **************************************************************/
222 /**************************************************************
224 * SECTION: nsWindow statics
226 **************************************************************/
228 PRUint32
nsWindow::sInstanceCount
= 0;
229 PRBool
nsWindow::sSwitchKeyboardLayout
= PR_FALSE
;
230 BOOL
nsWindow::sIsRegistered
= FALSE
;
231 BOOL
nsWindow::sIsPopupClassRegistered
= FALSE
;
232 BOOL
nsWindow::sIsOleInitialized
= FALSE
;
233 HCURSOR
nsWindow::sHCursor
= NULL
;
234 imgIContainer
* nsWindow::sCursorImgContainer
= nsnull
;
235 nsWindow
* nsWindow::sCurrentWindow
= nsnull
;
236 PRBool
nsWindow::sJustGotDeactivate
= PR_FALSE
;
237 PRBool
nsWindow::sJustGotActivate
= PR_FALSE
;
239 // imported in nsWidgetFactory.cpp
240 TriStateBool
nsWindow::sCanQuit
= TRI_UNKNOWN
;
242 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
243 // hook methods whether they should be processing the hook
245 HHOOK
nsWindow::sMsgFilterHook
= NULL
;
246 HHOOK
nsWindow::sCallProcHook
= NULL
;
247 HHOOK
nsWindow::sCallMouseHook
= NULL
;
248 PRPackedBool
nsWindow::sProcessHook
= PR_FALSE
;
249 UINT
nsWindow::sRollupMsgId
= 0;
250 HWND
nsWindow::sRollupMsgWnd
= NULL
;
251 UINT
nsWindow::sHookTimerId
= 0;
254 nsIRollupListener
* nsWindow::sRollupListener
= nsnull
;
255 nsIMenuRollup
* nsWindow::sMenuRollup
= nsnull
;
256 nsIWidget
* nsWindow::sRollupWidget
= nsnull
;
257 PRBool
nsWindow::sRollupConsumeEvent
= PR_FALSE
;
259 // Mouse Clicks - static variable definitions for figuring
261 POINT
nsWindow::sLastMousePoint
= {0};
262 POINT
nsWindow::sLastMouseMovePoint
= {0};
263 LONG
nsWindow::sLastMouseDownTime
= 0L;
264 LONG
nsWindow::sLastClickCount
= 0L;
265 BYTE
nsWindow::sLastMouseButton
= 0;
267 // Trim heap on minimize. (initialized, but still true.)
268 int nsWindow::sTrimOnMinimize
= 2;
270 // Default Trackpoint Hack to off
271 PRBool
nsWindow::sTrackPointHack
= PR_FALSE
;
274 BOOL
nsWindow::sIsAccessibilityOn
= FALSE
;
275 // Accessibility wm_getobject handler
276 HINSTANCE
nsWindow::sAccLib
= 0;
277 LPFNLRESULTFROMOBJECT
278 nsWindow::sLresultFromObject
= 0;
279 #endif // ACCESSIBILITY
282 // Used in OOPP plugin focus processing.
283 const PRUnichar
* kOOPPPluginFocusEventId
= L
"OOPP Plugin Focus Widget Event";
284 PRUint32
nsWindow::sOOPPPluginFocusEvent
=
285 RegisterWindowMessageW(kOOPPPluginFocusEventId
);
288 /**************************************************************
290 * SECTION: globals variables
292 **************************************************************/
294 static const char *sScreenManagerContractID
= "@mozilla.org/gfx/screenmanager;1";
297 PRLogModuleInfo
* gWindowsLog
= nsnull
;
301 // Kbd layout. Used throughout character processing.
302 static KeyboardLayout gKbdLayout
;
305 #ifdef WINCE_WINDOWS_MOBILE
306 // HTC Navigation Wheel Event
307 // This is the defined value for Gesture Mode
308 const int WM_HTCNAV
= 0x0400 + 200;
310 typedef int (__stdcall
* HTCApiNavOpen
)(HANDLE
, int);
311 typedef int (__stdcall
* HTCApiNavSetMode
)(HANDLE
, unsigned int);
313 HTCApiNavOpen gHTCApiNavOpen
= nsnull
;
314 HTCApiNavSetMode gHTCApiNavSetMode
= nsnull
;
315 static PRBool gCheckForHTCApi
= PR_FALSE
;
318 // The last user input event time in microseconds. If
319 // there are any pending native toolkit input events
320 // it returns the current time. The value is compatible
321 // with PR_IntervalToMicroseconds(PR_IntervalNow()).
323 static PRUint32 gLastInputEventTime
= 0;
325 PRUint32 gLastInputEventTime
= 0;
328 static void UpdateLastInputEventTime() {
329 gLastInputEventTime
= PR_IntervalToMicroseconds(PR_IntervalNow());
330 nsCOMPtr
<nsIIdleService
> idleService
= do_GetService("@mozilla.org/widget/idleservice;1");
331 nsIdleService
* is
= static_cast<nsIdleService
*>(idleService
.get());
333 is
->IdleTimeWasModified();
336 // Global user preference for disabling native theme. Used
337 // in NativeWindowTheme.
338 PRBool gDisableNativeTheme
= PR_FALSE
;
340 // Global used in Show window enumerations.
341 static PRBool gWindowsVisible
= PR_FALSE
;
343 static NS_DEFINE_CID(kCClipboardCID
, NS_CLIPBOARD_CID
);
344 #ifdef WINCE_WINDOWS_MOBILE
345 static NS_DEFINE_CID(kRegionCID
, NS_REGION_CID
);
348 /**************************************************************
349 **************************************************************
351 ** BLOCK: nsIWidget impl.
353 ** nsIWidget interface implementation, broken down into
356 **************************************************************
357 **************************************************************/
359 /**************************************************************
361 * SECTION: nsWindow construction and destruction
363 **************************************************************/
365 nsWindow::nsWindow() : nsBaseWidget()
369 gWindowsLog
= PR_NewLogModule("nsWindowsWidgets");
374 mPrevWndProc
= nsnull
;
376 mNativeDragTarget
= nsnull
;
378 mIsVisible
= PR_FALSE
;
379 mHas3DBorder
= PR_FALSE
;
380 mIsInMouseCapture
= PR_FALSE
;
381 mIsTopWidgetWindow
= PR_FALSE
;
382 mUnicodeWidget
= PR_TRUE
;
383 mWindowType
= eWindowType_child
;
384 mBorderStyle
= eBorderStyle_default
;
385 mPopupType
= ePopupTypeAny
;
386 mDisplayPanFeedback
= PR_FALSE
;
390 mLastSize
.height
= 0;
394 mLastKeyboardLayout
= 0;
395 mBlurSuppressLevel
= 0;
396 mIMEEnabled
= nsIWidget::IME_STATUS_ENABLED
;
399 mTransparentSurface
= nsnull
;
401 mTransparencyMode
= eTransparencyOpaque
;
403 mBackground
= ::GetSysColor(COLOR_BTNFACE
);
404 mBrush
= ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground
));
405 mForeground
= ::GetSysColor(COLOR_WINDOWTEXT
);
407 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
408 mTaskbarPreview
= nsnull
;
409 mHasTaskbarIconBeenCreated
= PR_FALSE
;
412 // Global initialization
413 if (!sInstanceCount
) {
415 gKbdLayout
.LoadLayout(::GetKeyboardLayout(0));
419 nsIMM32Handler::Initialize();
422 nsTextStore::Initialize();
426 if (SUCCEEDED(::OleInitialize(NULL
)))
427 sIsOleInitialized
= TRUE
;
428 NS_ASSERTION(sIsOleInitialized
, "***** OLE is not initialized!\n");
431 #if defined(HEAP_DUMP_EVENT)
436 InitTrackPointHack();
440 // Set gLastInputEventTime to some valid number
441 gLastInputEventTime
= PR_IntervalToMicroseconds(PR_IntervalNow());
446 nsWindow::~nsWindow()
450 // If the widget was released without calling Destroy() then the native window still
451 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
453 // XXX How could this happen???
460 if (sInstanceCount
== 0) {
462 nsTextStore::Terminate();
466 NS_IF_RELEASE(sCursorImgContainer
);
467 if (sIsOleInitialized
) {
468 ::OleFlushClipboard();
470 sIsOleInitialized
= FALSE
;
472 // delete any of the IME structures that we allocated
473 nsIMM32Handler::Terminate();
474 #endif // !defined(WINCE)
478 NS_IF_RELEASE(mNativeDragTarget
);
479 #endif // !defined(WINCE)
482 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow
, nsBaseWidget
)
484 /**************************************************************
486 * SECTION: nsIWidget::Create, nsIWidget::Destroy
488 * Creating and destroying windows for this widget.
490 **************************************************************/
492 // Allow Derived classes to modify the height that is passed
493 // when the window is created or resized. Also add extra height
494 // if needed (on Windows CE)
495 PRInt32
nsWindow::GetHeight(PRInt32 aProposedHeight
)
499 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
500 DWORD style
= WindowStyle();
501 if ((style
& WS_SYSMENU
) && (style
& WS_POPUP
)) {
502 extra
= GetSystemMetrics(SM_CYCAPTION
);
506 return aProposedHeight
+ extra
;
509 // Create the proper widget
511 nsWindow::Create(nsIWidget
*aParent
,
512 nsNativeWidget aNativeParent
,
513 const nsIntRect
&aRect
,
514 EVENT_CALLBACK aHandleEventFunction
,
515 nsIDeviceContext
*aContext
,
516 nsIAppShell
*aAppShell
,
517 nsIToolkit
*aToolkit
,
518 nsWidgetInitData
*aInitData
)
521 mUnicodeWidget
= aInitData
->mUnicode
;
523 nsIWidget
*baseParent
= aInitData
&&
524 (aInitData
->mWindowType
== eWindowType_dialog
||
525 aInitData
->mWindowType
== eWindowType_toplevel
||
526 aInitData
->mWindowType
== eWindowType_invisible
) ?
529 mIsTopWidgetWindow
= (nsnull
== baseParent
);
530 mBounds
.width
= aRect
.width
;
531 mBounds
.height
= aRect
.height
;
533 BaseCreate(baseParent
, aRect
, aHandleEventFunction
, aContext
,
534 aAppShell
, aToolkit
, aInitData
);
537 if (nsnull
!= aParent
) { // has a nsIWidget parent
538 parent
= ((aParent
) ? (HWND
)aParent
->GetNativeData(NS_NATIVE_WINDOW
) : nsnull
);
539 } else { // has a nsNative parent
540 parent
= (HWND
)aNativeParent
;
543 if (nsnull
!= aInitData
) {
544 mPopupType
= aInitData
->mPopupHint
;
547 mContentType
= aInitData
? aInitData
->mContentType
: eContentTypeInherit
;
549 DWORD style
= WindowStyle();
550 DWORD extendedStyle
= WindowExStyle();
552 if (aInitData
->mRTL
) {
553 extendedStyle
|= WS_EX_LAYOUTRTL
| WS_EX_NOINHERITLAYOUT
;
556 if (mWindowType
== eWindowType_popup
) {
557 // if a parent was specified, don't use WS_EX_TOPMOST so that the popup
558 // only appears above the parent, instead of all windows
560 extendedStyle
= WS_EX_TOOLWINDOW
;
563 } else if (mWindowType
== eWindowType_invisible
) {
564 // Make sure CreateWindowEx succeeds at creating a toplevel window
565 style
&= ~0x40000000; // WS_CHILDWINDOW
566 } else if (nsnull
!= aInitData
) {
567 // See if the caller wants to explictly set clip children and clip siblings
568 if (aInitData
->clipChildren
) {
569 style
|= WS_CLIPCHILDREN
;
571 style
&= ~WS_CLIPCHILDREN
;
573 if (aInitData
->clipSiblings
) {
574 style
|= WS_CLIPSIBLINGS
;
578 mHas3DBorder
= (extendedStyle
& WS_EX_CLIENTEDGE
) > 0;
580 mWnd
= ::CreateWindowExW(extendedStyle
,
581 aInitData
&& aInitData
->mDropShadow
?
582 WindowPopupClass() : WindowClass(),
588 GetHeight(aRect
.height
),
591 nsToolkit::mDllInstance
,
595 return NS_ERROR_FAILURE
;
597 if (nsWindow::sTrackPointHack
&&
598 mWindowType
!= eWindowType_plugin
&&
599 mWindowType
!= eWindowType_invisible
) {
600 // Ugly Thinkpad Driver Hack (Bug 507222)
601 // We create an invisible scrollbar to trick the
602 // Trackpoint driver into sending us scrolling messages
603 ::CreateWindowW(L
"SCROLLBAR", L
"FAKETRACKPOINTSCROLLBAR",
604 WS_CHILD
| WS_VISIBLE
, 0,0,0,0, mWnd
, NULL
,
605 nsToolkit::mDllInstance
, NULL
);
608 // call the event callback to notify about creation
610 DispatchStandardEvent(NS_CREATE
);
611 SubclassWindow(TRUE
);
613 if (sTrimOnMinimize
== 2 && mWindowType
== eWindowType_invisible
) {
614 /* The internal variable set by the config.trim_on_minimize pref
615 has not yet been initialized, and this is the hidden window
616 (conveniently created before any visible windows, and after
617 the profile has been initialized).
619 Default config.trim_on_minimize to false, to fix bug 76831
620 for good. If anyone complains about this new default, saying
621 that a Mozilla app hogs too much memory while minimized, they
622 will have that entire bug tattooed on their backside. */
625 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
627 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
628 prefs
->GetBranch(0, getter_AddRefs(prefBranch
));
632 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("config.trim_on_minimize",
637 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("intl.keyboard.per_window_layout",
639 sSwitchKeyboardLayout
= temp
;
641 if (NS_SUCCEEDED(prefBranch
->GetBoolPref("mozilla.widget.disable-native-theme",
643 gDisableNativeTheme
= temp
;
647 #if defined(WINCE_HAVE_SOFTKB)
648 if (mWindowType
== eWindowType_dialog
|| mWindowType
== eWindowType_toplevel
)
649 nsWindowCE::CreateSoftKeyMenuBar(mWnd
);
655 // Close this nsWindow
656 NS_METHOD
nsWindow::Destroy()
658 // WM_DESTROY has already fired, we're done.
662 // During the destruction of all of our children, make sure we don't get deleted.
663 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
665 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
666 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
667 // from it. The function also destroys the window's menu, flushes the thread message queue,
668 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
669 // the window is at the top of the viewer chain).
671 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
672 // the associated child or owned windows when it destroys the parent or owner window. The
673 // function first destroys child or owned windows, and then it destroys the parent or owner
675 VERIFY(::DestroyWindow(mWnd
));
677 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
678 // didn't get called, call it now.
679 if (PR_FALSE
== mOnDestroyCalled
)
685 /**************************************************************
687 * SECTION: Window class utilities
689 * Utilities for calculating the proper window class name for
692 **************************************************************/
694 // Return the proper window class for everything except popups.
695 LPCWSTR
nsWindow::WindowClass()
697 if (!nsWindow::sIsRegistered
) {
700 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
701 wc
.style
= CS_DBLCLKS
;
702 wc
.lpfnWndProc
= ::DefWindowProcW
;
705 wc
.hInstance
= nsToolkit::mDllInstance
;
706 wc
.hIcon
= ::LoadIconW(::GetModuleHandleW(NULL
), (LPWSTR
)IDI_APPLICATION
);
708 wc
.hbrBackground
= mBrush
;
709 wc
.lpszMenuName
= NULL
;
710 wc
.lpszClassName
= kClassNameHidden
;
712 BOOL succeeded
= ::RegisterClassW(&wc
) != 0 &&
713 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError();
714 nsWindow::sIsRegistered
= succeeded
;
716 wc
.lpszClassName
= kClassNameContentFrame
;
717 if (!::RegisterClassW(&wc
) &&
718 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
719 nsWindow::sIsRegistered
= FALSE
;
722 wc
.lpszClassName
= kClassNameContent
;
723 if (!::RegisterClassW(&wc
) &&
724 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
725 nsWindow::sIsRegistered
= FALSE
;
728 wc
.lpszClassName
= kClassNameUI
;
729 if (!::RegisterClassW(&wc
) &&
730 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
731 nsWindow::sIsRegistered
= FALSE
;
734 wc
.lpszClassName
= kClassNameGeneral
;
735 ATOM generalClassAtom
= ::RegisterClassW(&wc
);
736 if (!generalClassAtom
&&
737 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
738 nsWindow::sIsRegistered
= FALSE
;
741 wc
.lpszClassName
= kClassNameDialog
;
743 if (!::RegisterClassW(&wc
) &&
744 ERROR_CLASS_ALREADY_EXISTS
!= GetLastError()) {
745 nsWindow::sIsRegistered
= FALSE
;
749 if (mWindowType
== eWindowType_invisible
) {
750 return kClassNameHidden
;
752 if (mWindowType
== eWindowType_dialog
) {
753 return kClassNameDialog
;
755 if (mContentType
== eContentTypeContent
) {
756 return kClassNameContent
;
758 if (mContentType
== eContentTypeContentFrame
) {
759 return kClassNameContentFrame
;
761 if (mContentType
== eContentTypeUI
) {
764 return kClassNameGeneral
;
767 // Return the proper popup window class
768 LPCWSTR
nsWindow::WindowPopupClass()
770 if (!nsWindow::sIsPopupClassRegistered
) {
773 wc
.style
= CS_DBLCLKS
| CS_XP_DROPSHADOW
;
774 wc
.lpfnWndProc
= ::DefWindowProcW
;
777 wc
.hInstance
= nsToolkit::mDllInstance
;
778 wc
.hIcon
= ::LoadIconW(::GetModuleHandleW(NULL
), (LPWSTR
)IDI_APPLICATION
);
780 wc
.hbrBackground
= mBrush
;
781 wc
.lpszMenuName
= NULL
;
782 wc
.lpszClassName
= kClassNameDropShadow
;
784 nsWindow::sIsPopupClassRegistered
= ::RegisterClassW(&wc
);
785 if (!nsWindow::sIsPopupClassRegistered
) {
786 // For older versions of Win32 (i.e., not XP), the registration will
787 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
788 wc
.style
= CS_DBLCLKS
;
789 nsWindow::sIsPopupClassRegistered
= ::RegisterClassW(&wc
);
793 return kClassNameDropShadow
;
796 /**************************************************************
798 * SECTION: Window styles utilities
800 * Return the proper windows styles and extended styles.
802 **************************************************************/
804 // Return nsWindow styles
805 #if !defined(WINCE) // implemented in nsWindowCE.cpp
806 DWORD
nsWindow::WindowStyle()
810 switch (mWindowType
) {
811 case eWindowType_plugin
:
812 case eWindowType_child
:
813 style
= WS_OVERLAPPED
;
816 case eWindowType_dialog
:
817 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
| DS_3DLOOK
| DS_MODALFRAME
;
818 if (mBorderStyle
!= eBorderStyle_default
)
819 style
|= WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
;
822 case eWindowType_popup
:
824 if (mTransparencyMode
!= eTransparencyGlass
) {
825 style
|= WS_OVERLAPPED
;
830 NS_ERROR("unknown border style");
833 case eWindowType_toplevel
:
834 case eWindowType_invisible
:
835 style
= WS_OVERLAPPED
| WS_BORDER
| WS_DLGFRAME
| WS_SYSMENU
|
836 WS_THICKFRAME
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
;
840 if (mBorderStyle
!= eBorderStyle_default
&& mBorderStyle
!= eBorderStyle_all
) {
841 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_border
))
844 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_title
)) {
845 style
&= ~WS_DLGFRAME
;
850 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_close
))
852 // XXX The close box can only be removed by changing the window class,
853 // as far as I know --- roc+moz@cs.cmu.edu
855 if (mBorderStyle
== eBorderStyle_none
||
856 !(mBorderStyle
& (eBorderStyle_menu
| eBorderStyle_close
)))
857 style
&= ~WS_SYSMENU
;
858 // Looks like getting rid of the system menu also does away with the
859 // close box. So, we only get rid of the system menu if you want neither it
860 // nor the close box. How does the Windows "Dialog" window class get just
861 // closebox and no sysmenu? Who knows.
863 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_resizeh
))
864 style
&= ~WS_THICKFRAME
;
866 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_minimize
))
867 style
&= ~WS_MINIMIZEBOX
;
869 if (mBorderStyle
== eBorderStyle_none
|| !(mBorderStyle
& eBorderStyle_maximize
))
870 style
&= ~WS_MAXIMIZEBOX
;
872 VERIFY_WINDOW_STYLE(style
);
875 #endif // !defined(WINCE)
877 // Return nsWindow extended styles
878 DWORD
nsWindow::WindowExStyle()
882 case eWindowType_plugin
:
883 case eWindowType_child
:
886 case eWindowType_dialog
:
887 return WS_EX_WINDOWEDGE
| WS_EX_DLGMODALFRAME
;
889 case eWindowType_popup
:
891 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
894 WS_EX_TOPMOST
| WS_EX_TOOLWINDOW
;
897 NS_ERROR("unknown border style");
900 case eWindowType_toplevel
:
901 case eWindowType_invisible
:
902 return WS_EX_WINDOWEDGE
;
906 /**************************************************************
908 * SECTION: Window subclassing utilities
910 * Set or clear window subclasses on native windows. Used in
911 * Create and Destroy.
913 **************************************************************/
915 // Subclass (or remove the subclass from) this component's nsWindow
916 void nsWindow::SubclassWindow(BOOL bState
)
919 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
920 if (!::IsWindow(mWnd
)) {
921 NS_ERROR("Invalid window handle");
925 // change the nsWindow proc
927 mPrevWndProc
= (WNDPROC
)::SetWindowLongPtrW(mWnd
, GWLP_WNDPROC
,
928 (LONG_PTR
)nsWindow::WindowProc
);
930 mPrevWndProc
= (WNDPROC
)::SetWindowLongPtrA(mWnd
, GWLP_WNDPROC
,
931 (LONG_PTR
)nsWindow::WindowProc
);
932 NS_ASSERTION(mPrevWndProc
, "Null standard window procedure");
933 // connect the this pointer to the nsWindow handle
934 SetNSWindowPtr(mWnd
, this);
938 ::SetWindowLongPtrW(mWnd
, GWLP_WNDPROC
, (LONG_PTR
)mPrevWndProc
);
940 ::SetWindowLongPtrA(mWnd
, GWLP_WNDPROC
, (LONG_PTR
)mPrevWndProc
);
941 SetNSWindowPtr(mWnd
, NULL
);
947 /**************************************************************
949 * SECTION: Window properties
951 * Set and clear native window properties.
953 **************************************************************/
955 static PRUnichar sPropName
[40] = L
"";
956 static PRUnichar
* GetNSWindowPropName()
960 _snwprintf(sPropName
, 39, L
"MozillansIWidgetPtr%p", GetCurrentProcessId());
961 sPropName
[39] = '\0';
966 nsWindow
* nsWindow::GetNSWindowPtr(HWND aWnd
)
968 return (nsWindow
*) ::GetPropW(aWnd
, GetNSWindowPropName());
971 BOOL
nsWindow::SetNSWindowPtr(HWND aWnd
, nsWindow
* ptr
)
974 ::RemovePropW(aWnd
, GetNSWindowPropName());
977 return ::SetPropW(aWnd
, GetNSWindowPropName(), (HANDLE
)ptr
);
981 /**************************************************************
983 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
985 * Set or clear the parent widgets using window properties, and
986 * handles calculating native parent handles.
988 **************************************************************/
990 // Get and set parent widgets
991 NS_IMETHODIMP
nsWindow::SetParent(nsIWidget
*aNewParent
)
994 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
996 nsIWidget
* parent
= GetParent();
998 parent
->RemoveChild(this);
1001 HWND newParent
= (HWND
)aNewParent
->GetNativeData(NS_NATIVE_WINDOW
);
1002 NS_ASSERTION(newParent
, "Parent widget has a null native window handle");
1003 if (newParent
&& mWnd
) {
1004 ::SetParent(mWnd
, newParent
);
1007 aNewParent
->AddChild(this);
1012 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
1014 nsIWidget
* parent
= GetParent();
1017 parent
->RemoveChild(this);
1021 // If we have no parent, SetParent should return the desktop.
1022 VERIFY(::SetParent(mWnd
, nsnull
));
1028 nsIWidget
* nsWindow::GetParent(void)
1030 return GetParentWindow(PR_FALSE
);
1033 nsWindow
* nsWindow::GetParentWindow(PRBool aIncludeOwner
)
1035 if (mIsTopWidgetWindow
) {
1036 // Must use a flag instead of mWindowType to tell if the window is the
1037 // owned by the topmost widget, because a child window can be embedded inside
1038 // a HWND which is not associated with a nsIWidget.
1042 // If this widget has already been destroyed, pretend we have no parent.
1043 // This corresponds to code in Destroy which removes the destroyed
1044 // widget from its parent's child list.
1045 if (mInDtor
|| mOnDestroyCalled
)
1049 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1050 // root owner. aIncludeOwner set to false implies the search will stop at the
1051 // true parent (default).
1052 nsWindow
* widget
= nsnull
;
1055 HWND parent
= ::GetParent(mWnd
);
1057 HWND parent
= nsnull
;
1059 parent
= ::GetParent(mWnd
);
1061 parent
= ::GetAncestor(mWnd
, GA_PARENT
);
1064 widget
= GetNSWindowPtr(parent
);
1066 // If the widget is in the process of being destroyed then
1068 if (widget
->mInDtor
) {
1078 /**************************************************************
1080 * SECTION: nsIWidget::Show
1082 * Hide or show this component.
1084 **************************************************************/
1086 NS_METHOD
nsWindow::Show(PRBool bState
)
1088 #if defined(MOZ_SPLASHSCREEN)
1089 // we're about to show the first toplevel window,
1090 // so kill off any splash screen if we had one
1091 nsSplashScreen
*splash
= nsSplashScreen::Get();
1092 if (splash
&& splash
->IsOpen() && mWnd
&& bState
&&
1093 (mWindowType
== eWindowType_toplevel
||
1094 mWindowType
== eWindowType_dialog
||
1095 mWindowType
== eWindowType_popup
))
1101 PRBool wasVisible
= mIsVisible
;
1102 // Set the status now so that anyone asking during ShowWindow or
1103 // SetWindowPos would get the correct answer.
1104 mIsVisible
= bState
;
1108 if (!wasVisible
&& mWindowType
== eWindowType_toplevel
) {
1109 switch (mSizeMode
) {
1111 case nsSizeMode_Fullscreen
:
1112 ::SetForegroundWindow(mWnd
);
1113 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1114 MakeFullScreen(TRUE
);
1117 case nsSizeMode_Maximized
:
1118 ::SetForegroundWindow(mWnd
);
1119 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1121 // use default for nsSizeMode_Minimized on Windows CE
1123 case nsSizeMode_Fullscreen
:
1124 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1127 case nsSizeMode_Maximized
:
1128 ::ShowWindow(mWnd
, SW_SHOWMAXIMIZED
);
1130 case nsSizeMode_Minimized
:
1131 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
1135 if (CanTakeFocus()) {
1137 ::SetForegroundWindow(mWnd
);
1139 ::ShowWindow(mWnd
, SW_SHOWNORMAL
);
1141 // Place the window behind the foreground window
1142 // (as long as it is not topmost)
1143 HWND wndAfter
= ::GetForegroundWindow();
1145 wndAfter
= HWND_BOTTOM
;
1146 else if (GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
1147 wndAfter
= HWND_TOP
;
1148 ::SetWindowPos(mWnd
, wndAfter
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOSIZE
|
1149 SWP_NOMOVE
| SWP_NOACTIVATE
);
1155 DWORD flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_SHOWWINDOW
;
1157 flags
|= SWP_NOZORDER
;
1159 if (mWindowType
== eWindowType_popup
) {
1161 // ensure popups are the topmost of the TOPMOST
1162 // layer. Remember not to set the SWP_NOZORDER
1163 // flag as that might allow the taskbar to overlap
1164 // the popup. However on windows ce, we need to
1165 // activate the popup or clicks will not be sent.
1166 flags
|= SWP_NOACTIVATE
;
1168 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
1169 ::SetWindowPos(mWnd
, owner
? 0 : HWND_TOPMOST
, 0, 0, 0, 0, flags
);
1172 if (mWindowType
== eWindowType_dialog
&& !CanTakeFocus())
1173 flags
|= SWP_NOACTIVATE
;
1175 ::SetWindowPos(mWnd
, HWND_TOP
, 0, 0, 0, 0, flags
);
1179 if (mWindowType
!= eWindowType_dialog
) {
1180 ::ShowWindow(mWnd
, SW_HIDE
);
1182 ::SetWindowPos(mWnd
, 0, 0, 0, 0, 0, SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
|
1183 SWP_NOZORDER
| SWP_NOACTIVATE
);
1189 if (!wasVisible
&& bState
)
1190 Invalidate(PR_FALSE
);
1196 /**************************************************************
1198 * SECTION: nsIWidget::IsVisible
1200 * Returns the visibility state.
1202 **************************************************************/
1204 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1205 NS_METHOD
nsWindow::IsVisible(PRBool
& bState
)
1207 bState
= mIsVisible
;
1211 /**************************************************************
1213 * SECTION: Window clipping utilities
1215 * Used in Size and Move operations for setting the proper
1216 * window clipping regions for window transparency.
1218 **************************************************************/
1220 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1221 // transparency. These routines are called on size and move operations.
1222 void nsWindow::ClearThemeRegion()
1225 if (nsUXThemeData::sIsVistaOrLater
&& mTransparencyMode
!= eTransparencyGlass
&&
1226 mWindowType
== eWindowType_popup
&& (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
)) {
1227 SetWindowRgn(mWnd
, NULL
, false);
1232 void nsWindow::SetThemeRegion()
1235 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1236 // for other window types as needed. The regions are applied generically to the base window
1237 // so default constants are used for part and state. At some point we might need part and
1238 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1239 // change shape based on state haven't come up.
1240 if (nsUXThemeData::sIsVistaOrLater
&& mTransparencyMode
!= eTransparencyGlass
&&
1241 mWindowType
== eWindowType_popup
&& (mPopupType
== ePopupTypeTooltip
|| mPopupType
== ePopupTypePanel
)) {
1243 RECT rect
= {0,0,mBounds
.width
,mBounds
.height
};
1245 HDC dc
= ::GetDC(mWnd
);
1246 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip
), dc
, TTP_STANDARD
, TS_NORMAL
, &rect
, &hRgn
);
1248 if (!SetWindowRgn(mWnd
, hRgn
, false)) // do not delete or alter hRgn if accepted.
1251 ::ReleaseDC(mWnd
, dc
);
1256 /**************************************************************
1258 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1259 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1261 * Repositioning and sizing a window.
1263 **************************************************************/
1265 // Move this component
1266 NS_METHOD
nsWindow::Move(PRInt32 aX
, PRInt32 aY
)
1268 if (mWindowType
== eWindowType_toplevel
||
1269 mWindowType
== eWindowType_dialog
) {
1270 SetSizeMode(nsSizeMode_Normal
);
1272 // Check to see if window needs to be moved first
1273 // to avoid a costly call to SetWindowPos. This check
1274 // can not be moved to the calling code in nsView, because
1275 // some platforms do not position child windows correctly
1277 // Only perform this check for non-popup windows, since the positioning can
1278 // in fact change even when the x/y do not. We always need to perform the
1279 // check. See bug #97805 for details.
1280 if (mWindowType
!= eWindowType_popup
&& (mBounds
.x
== aX
) && (mBounds
.y
== aY
))
1282 // Nothing to do, since it is already positioned correctly.
1291 // complain if a window is moved offscreen (legal, but potentially worrisome)
1292 if (mIsTopWidgetWindow
) { // only a problem for top-level windows
1293 // Make sure this window is actually on the screen before we move it
1294 // XXX: Needs multiple monitor support
1295 HDC dc
= ::GetDC(mWnd
);
1297 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1299 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &workArea
, 0);
1300 // no annoying assertions. just mention the issue.
1301 if (aX
< 0 || aX
>= workArea
.right
|| aY
< 0 || aY
>= workArea
.bottom
)
1302 printf("window moved to offscreen position\n");
1304 ::ReleaseDC(mWnd
, dc
);
1309 VERIFY(::SetWindowPos(mWnd
, NULL
, aX
, aY
, 0, 0,
1310 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOSIZE
));
1316 // Resize this component
1317 NS_METHOD
nsWindow::Resize(PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1319 NS_ASSERTION((aWidth
>=0 ) , "Negative width passed to nsWindow::Resize");
1320 NS_ASSERTION((aHeight
>=0 ), "Negative height passed to nsWindow::Resize");
1323 if (eTransparencyTransparent
== mTransparencyMode
)
1324 ResizeTranslucentWindow(aWidth
, aHeight
);
1327 // Set cached value for lightweight and printing
1328 mBounds
.width
= aWidth
;
1329 mBounds
.height
= aHeight
;
1332 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOMOVE
;
1336 flags
|= SWP_NOREDRAW
;
1341 VERIFY(::SetWindowPos(mWnd
, NULL
, 0, 0, aWidth
, GetHeight(aHeight
), flags
));
1346 Invalidate(PR_FALSE
);
1351 // Resize this component
1352 NS_METHOD
nsWindow::Resize(PRInt32 aX
, PRInt32 aY
, PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
1354 NS_ASSERTION((aWidth
>=0 ), "Negative width passed to nsWindow::Resize");
1355 NS_ASSERTION((aHeight
>=0 ), "Negative height passed to nsWindow::Resize");
1358 if (eTransparencyTransparent
== mTransparencyMode
)
1359 ResizeTranslucentWindow(aWidth
, aHeight
);
1362 // Set cached value for lightweight and printing
1365 mBounds
.width
= aWidth
;
1366 mBounds
.height
= aHeight
;
1369 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
1372 flags
|= SWP_NOREDRAW
;
1377 VERIFY(::SetWindowPos(mWnd
, NULL
, aX
, aY
, aWidth
, GetHeight(aHeight
), flags
));
1382 Invalidate(PR_FALSE
);
1389 nsWindow::BeginResizeDrag(nsGUIEvent
* aEvent
, PRInt32 aHorizontal
, PRInt32 aVertical
)
1391 NS_ENSURE_ARG_POINTER(aEvent
);
1393 if (aEvent
->eventStructType
!= NS_MOUSE_EVENT
) {
1394 // you can only begin a resize drag with a mouse event
1395 return NS_ERROR_INVALID_ARG
;
1398 nsMouseEvent
* mouseEvent
= static_cast<nsMouseEvent
*>(aEvent
);
1399 if (mouseEvent
->button
!= nsMouseEvent::eLeftButton
) {
1400 // you can only begin a resize drag with the left mouse button
1401 return NS_ERROR_INVALID_ARG
;
1404 // work out what sizemode we're talking about
1406 if (aVertical
< 0) {
1407 if (aHorizontal
< 0) {
1408 syscommand
= SC_SIZE
| WMSZ_TOPLEFT
;
1409 } else if (aHorizontal
== 0) {
1410 syscommand
= SC_SIZE
| WMSZ_TOP
;
1412 syscommand
= SC_SIZE
| WMSZ_TOPRIGHT
;
1414 } else if (aVertical
== 0) {
1415 if (aHorizontal
< 0) {
1416 syscommand
= SC_SIZE
| WMSZ_LEFT
;
1417 } else if (aHorizontal
== 0) {
1418 return NS_ERROR_INVALID_ARG
;
1420 syscommand
= SC_SIZE
| WMSZ_RIGHT
;
1423 if (aHorizontal
< 0) {
1424 syscommand
= SC_SIZE
| WMSZ_BOTTOMLEFT
;
1425 } else if (aHorizontal
== 0) {
1426 syscommand
= SC_SIZE
| WMSZ_BOTTOM
;
1428 syscommand
= SC_SIZE
| WMSZ_BOTTOMRIGHT
;
1432 // resizing doesn't work if the mouse is already captured
1433 CaptureMouse(PR_FALSE
);
1435 // find the top-level window
1436 HWND toplevelWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
1438 // tell Windows to start the resize
1439 ::PostMessage(toplevelWnd
, WM_SYSCOMMAND
, syscommand
,
1440 POINTTOPOINTS(aEvent
->refPoint
));
1445 /**************************************************************
1447 * SECTION: Window Z-order and state.
1449 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1450 * nsIWidget::ConstrainPosition
1452 * Z-order, positioning, restore, minimize, and maximize.
1454 **************************************************************/
1456 // Position the window behind the given window
1457 NS_METHOD
nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement
,
1458 nsIWidget
*aWidget
, PRBool aActivate
)
1460 HWND behind
= HWND_TOP
;
1461 if (aPlacement
== eZPlacementBottom
)
1462 behind
= HWND_BOTTOM
;
1463 else if (aPlacement
== eZPlacementBelow
&& aWidget
)
1464 behind
= (HWND
)aWidget
->GetNativeData(NS_NATIVE_WINDOW
);
1465 UINT flags
= SWP_NOMOVE
| SWP_NOREPOSITION
| SWP_NOSIZE
;
1467 flags
|= SWP_NOACTIVATE
;
1469 if (!CanTakeFocus() && behind
== HWND_TOP
)
1471 // Can't place the window to top so place it behind the foreground window
1472 // (as long as it is not topmost)
1473 HWND wndAfter
= ::GetForegroundWindow();
1475 behind
= HWND_BOTTOM
;
1476 else if (!(GetWindowLongPtrW(wndAfter
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
1478 flags
|= SWP_NOACTIVATE
;
1481 ::SetWindowPos(mWnd
, behind
, 0, 0, 0, 0, flags
);
1485 // Maximize, minimize or restore the window.
1486 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1487 NS_IMETHODIMP
nsWindow::SetSizeMode(PRInt32 aMode
) {
1491 // Let's not try and do anything if we're already in that state.
1492 // (This is needed to prevent problems when calling window.minimize(), which
1493 // calls us directly, and then the OS triggers another call to us.)
1494 if (aMode
== mSizeMode
)
1497 // save the requested state
1498 rv
= nsBaseWidget::SetSizeMode(aMode
);
1499 if (NS_SUCCEEDED(rv
) && mIsVisible
) {
1503 case nsSizeMode_Fullscreen
:
1507 case nsSizeMode_Maximized
:
1511 case nsSizeMode_Minimized
:
1512 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1513 // keeps the window active in the tray. So after the window is minimized,
1514 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1515 // we will do some additional processing to get the active window set right.
1516 // If sTrimOnMinimize is set, we let windows handle minimization normally
1517 // using SW_MINIMIZE.
1518 mode
= sTrimOnMinimize
? SW_MINIMIZE
: SW_SHOWMINIMIZED
;
1524 ::ShowWindow(mWnd
, mode
);
1525 // we dispatch an activate event here to ensure that the right child window
1527 if (mode
== SW_RESTORE
|| mode
== SW_MAXIMIZE
)
1528 DispatchFocusToTopLevelWindow(NS_ACTIVATE
);
1532 #endif // !defined(WINCE)
1534 // Constrain a potential move to fit onscreen
1535 NS_METHOD
nsWindow::ConstrainPosition(PRBool aAllowSlop
,
1536 PRInt32
*aX
, PRInt32
*aY
)
1538 if (!mIsTopWidgetWindow
) // only a problem for top-level windows
1541 PRBool doConstrain
= PR_FALSE
; // whether we have enough info to do anything
1543 /* get our playing field. use the current screen, or failing that
1544 for any reason, use device caps for the default screen. */
1547 nsCOMPtr
<nsIScreenManager
> screenmgr
= do_GetService(sScreenManagerContractID
);
1549 nsCOMPtr
<nsIScreen
> screen
;
1550 PRInt32 left
, top
, width
, height
;
1552 // zero size rects confuse the screen manager
1553 width
= mBounds
.width
> 0 ? mBounds
.width
: 1;
1554 height
= mBounds
.height
> 0 ? mBounds
.height
: 1;
1555 screenmgr
->ScreenForRect(*aX
, *aY
, width
, height
,
1556 getter_AddRefs(screen
));
1558 screen
->GetAvailRect(&left
, &top
, &width
, &height
);
1559 screenRect
.left
= left
;
1560 screenRect
.right
= left
+width
;
1561 screenRect
.top
= top
;
1562 screenRect
.bottom
= top
+height
;
1563 doConstrain
= PR_TRUE
;
1567 HDC dc
= ::GetDC(mWnd
);
1569 if (::GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
1570 ::SystemParametersInfo(SPI_GETWORKAREA
, 0, &screenRect
, 0);
1571 doConstrain
= PR_TRUE
;
1573 ::ReleaseDC(mWnd
, dc
);
1579 if (*aX
< screenRect
.left
- mBounds
.width
+ kWindowPositionSlop
)
1580 *aX
= screenRect
.left
- mBounds
.width
+ kWindowPositionSlop
;
1581 else if (*aX
>= screenRect
.right
- kWindowPositionSlop
)
1582 *aX
= screenRect
.right
- kWindowPositionSlop
;
1584 if (*aY
< screenRect
.top
- mBounds
.height
+ kWindowPositionSlop
)
1585 *aY
= screenRect
.top
- mBounds
.height
+ kWindowPositionSlop
;
1586 else if (*aY
>= screenRect
.bottom
- kWindowPositionSlop
)
1587 *aY
= screenRect
.bottom
- kWindowPositionSlop
;
1591 if (*aX
< screenRect
.left
)
1592 *aX
= screenRect
.left
;
1593 else if (*aX
>= screenRect
.right
- mBounds
.width
)
1594 *aX
= screenRect
.right
- mBounds
.width
;
1596 if (*aY
< screenRect
.top
)
1597 *aY
= screenRect
.top
;
1598 else if (*aY
>= screenRect
.bottom
- mBounds
.height
)
1599 *aY
= screenRect
.bottom
- mBounds
.height
;
1605 /**************************************************************
1607 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1609 * Enabling and disabling the widget.
1611 **************************************************************/
1613 // Enable/disable this component
1614 NS_METHOD
nsWindow::Enable(PRBool bState
)
1617 ::EnableWindow(mWnd
, bState
);
1622 // Return the current enable state
1623 NS_METHOD
nsWindow::IsEnabled(PRBool
*aState
)
1625 NS_ENSURE_ARG_POINTER(aState
);
1628 *aState
= !mWnd
|| (::IsWindowEnabled(mWnd
) && ::IsWindowEnabled(::GetAncestor(mWnd
, GA_ROOT
)));
1630 *aState
= !mWnd
|| (::IsWindowEnabled(mWnd
) && ::IsWindowEnabled(mWnd
));
1637 /**************************************************************
1639 * SECTION: nsIWidget::SetFocus
1641 * Give the focus to this widget.
1643 **************************************************************/
1645 NS_METHOD
nsWindow::SetFocus(PRBool aRaise
)
1648 #ifdef WINSTATE_DEBUG_OUTPUT
1649 if (mWnd
== GetTopLevelHWND(mWnd
))
1650 printf("*** SetFocus: [ top] raise=%d\n", aRaise
);
1652 printf("*** SetFocus: [child] raise=%d\n", aRaise
);
1654 // Uniconify, if necessary
1655 HWND toplevelWnd
= GetTopLevelHWND(mWnd
);
1656 if (aRaise
&& ::IsIconic(toplevelWnd
)) {
1657 ::ShowWindow(toplevelWnd
, SW_RESTORE
);
1665 /**************************************************************
1669 * nsIWidget::GetBounds, nsIWidget::GetScreenBounds,
1670 * nsIWidget::GetClientBounds
1672 * Bound calculations.
1674 **************************************************************/
1676 // Get this component dimension
1677 NS_METHOD
nsWindow::GetBounds(nsIntRect
&aRect
)
1681 VERIFY(::GetWindowRect(mWnd
, &r
));
1684 aRect
.width
= r
.right
- r
.left
;
1685 aRect
.height
= r
.bottom
- r
.top
;
1687 // convert coordinates if parent exists
1688 HWND parent
= ::GetParent(mWnd
);
1691 VERIFY(::GetWindowRect(parent
, &pr
));
1704 // Get this component dimension
1705 NS_METHOD
nsWindow::GetClientBounds(nsIntRect
&aRect
)
1709 VERIFY(::GetClientRect(mWnd
, &r
));
1714 aRect
.width
= r
.right
- r
.left
;
1715 aRect
.height
= r
.bottom
- r
.top
;
1718 aRect
.SetRect(0,0,0,0);
1723 // Get the bounds, but don't take into account the client size
1724 void nsWindow::GetNonClientBounds(nsIntRect
&aRect
)
1728 VERIFY(::GetWindowRect(mWnd
, &r
));
1731 aRect
.width
= r
.right
- r
.left
;
1732 aRect
.height
= r
.bottom
- r
.top
;
1734 // convert coordinates if parent exists
1735 HWND parent
= ::GetParent(mWnd
);
1738 VERIFY(::GetWindowRect(parent
, &pr
));
1745 aRect
.SetRect(0,0,0,0);
1749 // Like GetBounds, but don't offset by the parent
1750 NS_METHOD
nsWindow::GetScreenBounds(nsIntRect
&aRect
)
1754 VERIFY(::GetWindowRect(mWnd
, &r
));
1756 aRect
.width
= r
.right
- r
.left
;
1757 aRect
.height
= r
.bottom
- r
.top
;
1766 /**************************************************************
1768 * SECTION: nsIWidget::SetBackgroundColor
1770 * Sets the window background paint color.
1772 **************************************************************/
1774 NS_METHOD
nsWindow::SetBackgroundColor(const nscolor
&aColor
)
1776 nsBaseWidget::SetBackgroundColor(aColor
);
1779 ::DeleteObject(mBrush
);
1781 mBrush
= ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground
));
1784 ::SetClassLongPtrW(mWnd
, GCLP_HBRBACKGROUND
, (LONG_PTR
)mBrush
);
1790 /**************************************************************
1792 * SECTION: nsIWidget::SetCursor
1794 * SetCursor and related utilities for manging cursor state.
1796 **************************************************************/
1798 // Set this component cursor
1799 NS_METHOD
nsWindow::SetCursor(nsCursor aCursor
)
1801 // Only change cursor if it's changing
1803 //XXX mCursor isn't always right. Scrollbars and others change it, too.
1804 //XXX If we want this optimization we need a better way to do it.
1805 //if (aCursor != mCursor) {
1806 HCURSOR newCursor
= NULL
;
1809 case eCursor_select
:
1810 newCursor
= ::LoadCursor(NULL
, IDC_IBEAM
);
1814 newCursor
= ::LoadCursor(NULL
, IDC_WAIT
);
1817 case eCursor_hyperlink
:
1819 newCursor
= ::LoadCursor(NULL
, IDC_HAND
);
1823 case eCursor_standard
:
1824 newCursor
= ::LoadCursor(NULL
, IDC_ARROW
);
1827 case eCursor_n_resize
:
1828 case eCursor_s_resize
:
1829 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
1832 case eCursor_w_resize
:
1833 case eCursor_e_resize
:
1834 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
1837 case eCursor_nw_resize
:
1838 case eCursor_se_resize
:
1839 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
1842 case eCursor_ne_resize
:
1843 case eCursor_sw_resize
:
1844 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
1847 case eCursor_crosshair
:
1848 newCursor
= ::LoadCursor(NULL
, IDC_CROSS
);
1852 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
1856 newCursor
= ::LoadCursor(NULL
, IDC_HELP
);
1859 case eCursor_copy
: // CSS3
1860 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COPY
));
1864 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ALIAS
));
1868 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_CELL
));
1872 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRAB
));
1875 case eCursor_grabbing
:
1876 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_GRABBING
));
1879 case eCursor_spinning
:
1880 newCursor
= ::LoadCursor(NULL
, IDC_APPSTARTING
);
1883 case eCursor_context_menu
:
1884 // XXX this CSS3 cursor needs to be implemented
1887 case eCursor_zoom_in
:
1888 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMIN
));
1891 case eCursor_zoom_out
:
1892 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ZOOMOUT
));
1895 case eCursor_not_allowed
:
1896 case eCursor_no_drop
:
1897 newCursor
= ::LoadCursor(NULL
, IDC_NO
);
1900 case eCursor_col_resize
:
1901 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_COLRESIZE
));
1904 case eCursor_row_resize
:
1905 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_ROWRESIZE
));
1908 case eCursor_vertical_text
:
1909 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_VERTICALTEXT
));
1912 case eCursor_all_scroll
:
1913 // XXX not 100% appropriate perhaps
1914 newCursor
= ::LoadCursor(NULL
, IDC_SIZEALL
);
1917 case eCursor_nesw_resize
:
1918 newCursor
= ::LoadCursor(NULL
, IDC_SIZENESW
);
1921 case eCursor_nwse_resize
:
1922 newCursor
= ::LoadCursor(NULL
, IDC_SIZENWSE
);
1925 case eCursor_ns_resize
:
1926 newCursor
= ::LoadCursor(NULL
, IDC_SIZENS
);
1929 case eCursor_ew_resize
:
1930 newCursor
= ::LoadCursor(NULL
, IDC_SIZEWE
);
1934 newCursor
= ::LoadCursor(nsToolkit::mDllInstance
, MAKEINTRESOURCE(IDC_NONE
));
1938 NS_ERROR("Invalid cursor type");
1942 if (NULL
!= newCursor
) {
1944 HCURSOR oldCursor
= ::SetCursor(newCursor
);
1946 if (sHCursor
== oldCursor
) {
1947 NS_IF_RELEASE(sCursorImgContainer
);
1948 if (sHCursor
!= NULL
)
1949 ::DestroyIcon(sHCursor
);
1957 // Setting the actual cursor
1958 NS_IMETHODIMP
nsWindow::SetCursor(imgIContainer
* aCursor
,
1959 PRUint32 aHotspotX
, PRUint32 aHotspotY
)
1961 if (sCursorImgContainer
== aCursor
&& sHCursor
) {
1962 ::SetCursor(sHCursor
);
1970 rv
= aCursor
->GetWidth(&width
);
1971 NS_ENSURE_SUCCESS(rv
, rv
);
1972 rv
= aCursor
->GetHeight(&height
);
1973 NS_ENSURE_SUCCESS(rv
, rv
);
1975 // Reject cursors greater than 128 pixels in either direction, to prevent
1977 // XXX ideally we should rescale. Also, we could modify the API to
1978 // allow trusted content to set larger cursors.
1979 if (width
> 128 || height
> 128)
1980 return NS_ERROR_NOT_AVAILABLE
;
1983 rv
= nsWindowGfx::CreateIcon(aCursor
, PR_TRUE
, aHotspotX
, aHotspotY
, &cursor
);
1984 NS_ENSURE_SUCCESS(rv
, rv
);
1986 mCursor
= nsCursor(-1);
1987 ::SetCursor(cursor
);
1989 NS_IF_RELEASE(sCursorImgContainer
);
1990 sCursorImgContainer
= aCursor
;
1991 NS_ADDREF(sCursorImgContainer
);
1993 if (sHCursor
!= NULL
)
1994 ::DestroyIcon(sHCursor
);
2000 /**************************************************************
2002 * SECTION: nsIWidget::Get/SetTransparencyMode
2004 * Manage the transparency mode of the top-level window
2005 * containing this widget.
2007 **************************************************************/
2010 nsTransparencyMode
nsWindow::GetTransparencyMode()
2012 return GetTopLevelWindow(PR_TRUE
)->GetWindowTranslucencyInner();
2015 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode
)
2017 GetTopLevelWindow(PR_TRUE
)->SetWindowTranslucencyInner(aMode
);
2021 /**************************************************************
2023 * SECTION: nsIWidget::HideWindowChrome
2025 * Show or hide window chrome.
2027 **************************************************************/
2029 NS_IMETHODIMP
nsWindow::HideWindowChrome(PRBool aShouldHide
)
2031 HWND hwnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
2032 if (!GetNSWindowPtr(hwnd
))
2034 NS_WARNING("Trying to hide window decorations in an embedded context");
2035 return NS_ERROR_FAILURE
;
2038 DWORD_PTR style
, exStyle
;
2040 DWORD_PTR tempStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2041 DWORD_PTR tempExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2043 style
= tempStyle
& ~(WS_CAPTION
| WS_THICKFRAME
);
2044 exStyle
= tempExStyle
& ~(WS_EX_DLGMODALFRAME
| WS_EX_WINDOWEDGE
|
2045 WS_EX_CLIENTEDGE
| WS_EX_STATICEDGE
);
2047 mOldStyle
= tempStyle
;
2048 mOldExStyle
= tempExStyle
;
2051 if (!mOldStyle
|| !mOldExStyle
) {
2052 mOldStyle
= ::GetWindowLongPtrW(hwnd
, GWL_STYLE
);
2053 mOldExStyle
= ::GetWindowLongPtrW(hwnd
, GWL_EXSTYLE
);
2057 exStyle
= mOldExStyle
;
2060 VERIFY_WINDOW_STYLE(style
);
2061 ::SetWindowLongPtrW(hwnd
, GWL_STYLE
, style
);
2062 ::SetWindowLongPtrW(hwnd
, GWL_EXSTYLE
, exStyle
);
2067 /**************************************************************
2069 * SECTION: nsIWidget::Invalidate
2071 * Invalidate an area of the client for painting.
2073 **************************************************************/
2075 #ifdef WINCE_WINDOWS_MOBILE
2076 static inline void AddRECTToRegion(const RECT
& aRect
, nsIRegion
* aRegion
)
2078 aRegion
->Union(aRect
.left
, aRect
.top
, aRect
.right
- aRect
.left
, aRect
.bottom
- aRect
.top
);
2082 // Invalidate this component visible area
2083 NS_METHOD
nsWindow::Invalidate(PRBool aIsSynchronous
)
2087 #ifdef WIDGET_DEBUG_OUTPUT
2088 debug_DumpInvalidate(stdout
,
2092 nsCAutoString("noname"),
2094 #endif // WIDGET_DEBUG_OUTPUT
2096 VERIFY(::InvalidateRect(mWnd
, NULL
, FALSE
));
2098 if (aIsSynchronous
) {
2099 VERIFY(::UpdateWindow(mWnd
));
2105 // Invalidate this component visible area
2106 NS_METHOD
nsWindow::Invalidate(const nsIntRect
& aRect
, PRBool aIsSynchronous
)
2110 #ifdef WIDGET_DEBUG_OUTPUT
2111 debug_DumpInvalidate(stdout
,
2115 nsCAutoString("noname"),
2117 #endif // WIDGET_DEBUG_OUTPUT
2121 rect
.left
= aRect
.x
;
2123 rect
.right
= aRect
.x
+ aRect
.width
;
2124 rect
.bottom
= aRect
.y
+ aRect
.height
;
2126 VERIFY(::InvalidateRect(mWnd
, &rect
, FALSE
));
2128 if (aIsSynchronous
) {
2129 VERIFY(::UpdateWindow(mWnd
));
2136 nsWindow::MakeFullScreen(PRBool aFullScreen
)
2138 #if WINCE_WINDOWS_MOBILE
2141 SetForegroundWindow(mWnd
);
2142 if (nsWindowCE::sMenuBarShown
) {
2144 memset(&sipInfo
, 0, sizeof(SIPINFO
));
2145 sipInfo
.cbSize
= sizeof(SIPINFO
);
2146 if (SipGetInfo(&sipInfo
))
2147 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
),
2148 sipInfo
.rcVisibleDesktop
.bottom
);
2150 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
),
2151 GetSystemMetrics(SM_CYSCREEN
));
2153 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle
, &menuBarRect
) &&
2154 menuBarRect
.top
< rc
.bottom
)
2155 rc
.bottom
= menuBarRect
.top
;
2156 SHFullScreen(mWnd
, SHFS_HIDETASKBAR
| SHFS_HIDESTARTICON
| SHFS_SHOWSIPBUTTON
);
2159 SHFullScreen(mWnd
, SHFS_HIDETASKBAR
| SHFS_HIDESTARTICON
| SHFS_HIDESIPBUTTON
);
2160 SetRect(&rc
, 0, 0, GetSystemMetrics(SM_CXSCREEN
), GetSystemMetrics(SM_CYSCREEN
));
2164 SHFullScreen(mWnd
, SHFS_SHOWTASKBAR
| SHFS_SHOWSTARTICON
);
2165 SystemParametersInfo(SPI_GETWORKAREA
, 0, &rc
, FALSE
);
2169 mSizeMode
= nsSizeMode_Fullscreen
;
2171 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2172 HideWindowChrome(aFullScreen
);
2173 Resize(rc
.left
, rc
.top
, rc
.right
-rc
.left
, rc
.bottom
-rc
.top
, PR_TRUE
);
2179 return nsBaseWidget::MakeFullScreen(aFullScreen
);
2183 /**************************************************************
2185 * SECTION: nsIWidget::Update
2187 * Force a synchronous repaint of the window.
2189 **************************************************************/
2191 NS_IMETHODIMP
nsWindow::Update()
2193 nsresult rv
= NS_OK
;
2195 // updates can come through for windows no longer holding an mWnd during
2196 // deletes triggered by JavaScript in buttons with mouse feedback
2198 VERIFY(::UpdateWindow(mWnd
));
2203 /**************************************************************
2205 * SECTION: nsIWidget::Scroll
2207 * Scroll this widget.
2209 **************************************************************/
2212 ClipRegionContainedInRect(const nsTArray
<nsIntRect
>& aClipRects
,
2213 const nsIntRect
& aRect
)
2215 for (PRUint32 i
= 0; i
< aClipRects
.Length(); ++i
) {
2216 if (!aRect
.Contains(aClipRects
[i
]))
2222 // This function determines whether the given window has a descendant that
2223 // does not intersect the given aScreenRect. If we encounter a window owned
2224 // by another thread (which includes another process, since thread IDs
2225 // are unique system-wide), then we give up and conservatively return true.
2227 HasDescendantWindowOutsideRect(DWORD aThisThreadID
, HWND aWnd
,
2228 const RECT
& aScreenRect
)
2230 // If the window is owned by another thread, give up now, don't try to
2231 // look at its children since they could change asynchronously.
2232 // XXX should we try harder here for out-of-process plugins?
2233 if (GetWindowThreadProcessId(aWnd
, NULL
) != aThisThreadID
) {
2236 for (HWND child
= ::GetWindow(aWnd
, GW_CHILD
); child
;
2237 child
= ::GetWindow(child
, GW_HWNDNEXT
)) {
2238 RECT childScreenRect
;
2239 ::GetWindowRect(child
, &childScreenRect
);
2241 if (!::IntersectRect(&result
, &childScreenRect
, &aScreenRect
)) {
2245 if (HasDescendantWindowOutsideRect(aThisThreadID
, child
, aScreenRect
)) {
2254 InvalidateRgnInWindowSubtree(HWND aWnd
, HRGN aRgn
, HRGN aTmpRgn
)
2257 ::GetClientRect(aWnd
, &clientRect
);
2258 ::SetRectRgn(aTmpRgn
, clientRect
.left
, clientRect
.top
,
2259 clientRect
.right
, clientRect
.bottom
);
2260 if (::CombineRgn(aTmpRgn
, aTmpRgn
, aRgn
, RGN_AND
) == NULLREGION
) {
2264 ::InvalidateRgn(aWnd
, aTmpRgn
, FALSE
);
2266 for (HWND child
= ::GetWindow(aWnd
, GW_CHILD
); child
;
2267 child
= ::GetWindow(child
, GW_HWNDNEXT
)) {
2268 POINT pt
= { 0, 0 };
2269 ::MapWindowPoints(child
, aWnd
, &pt
, 1);
2270 ::OffsetRgn(aRgn
, -pt
.x
, -pt
.y
);
2271 InvalidateRgnInWindowSubtree(child
, aRgn
, aTmpRgn
);
2272 ::OffsetRgn(aRgn
, pt
.x
, pt
.y
);
2277 nsWindow::Scroll(const nsIntPoint
& aDelta
,
2278 const nsTArray
<nsIntRect
>& aDestRects
,
2279 const nsTArray
<Configuration
>& aConfigurations
)
2281 // We use SW_SCROLLCHILDREN if all the windows that intersect the
2282 // affected area are moving by the scroll amount.
2283 // First, build the set of widgets that are to be moved by the scroll
2285 // At the same time, set the clip region of all changed windows to the
2286 // intersection of the current and new regions.
2287 nsTHashtable
<nsPtrHashKey
<nsWindow
> > scrolledWidgets
;
2288 scrolledWidgets
.Init();
2289 for (PRUint32 i
= 0; i
< aConfigurations
.Length(); ++i
) {
2290 const Configuration
& configuration
= aConfigurations
[i
];
2291 nsWindow
* w
= static_cast<nsWindow
*>(configuration
.mChild
);
2292 NS_ASSERTION(w
->GetParent() == this,
2293 "Configured widget is not a child");
2294 if (configuration
.mBounds
== w
->mBounds
+ aDelta
) {
2295 scrolledWidgets
.PutEntry(w
);
2297 w
->SetWindowClipRegion(configuration
.mClipRegion
, PR_TRUE
);
2300 // Create temporary regions
2301 HRGN updateRgn
= ::CreateRectRgn(0, 0, 0, 0);
2306 HRGN destRgn
= ::CreateRectRgn(0, 0, 0, 0);
2309 ::DeleteObject((HGDIOBJ
)updateRgn
);
2313 DWORD ourThreadID
= GetWindowThreadProcessId(mWnd
, NULL
);
2315 for (BlitRectIter
iter(aDelta
, aDestRects
); !iter
.IsDone(); ++iter
) {
2316 const nsIntRect
& destRect
= iter
.Rect();
2317 nsIntRect affectedRect
;
2318 affectedRect
.UnionRect(destRect
, destRect
- aDelta
);
2319 UINT flags
= SW_SCROLLCHILDREN
;
2320 // Now check if any of our children would be affected by
2321 // SW_SCROLLCHILDREN but not supposed to scroll.
2322 for (nsWindow
* w
= static_cast<nsWindow
*>(GetFirstChild()); w
;
2323 w
= static_cast<nsWindow
*>(w
->GetNextSibling())) {
2324 if (w
->mBounds
.Intersects(affectedRect
)) {
2325 // This child will be affected
2326 nsPtrHashKey
<nsWindow
>* entry
= scrolledWidgets
.GetEntry(w
);
2328 // It's supposed to be scrolled, so we can still use
2329 // SW_SCROLLCHILDREN. But don't allow SW_SCROLLCHILDREN to be
2330 // used on it again by a later rectangle; we don't want it to
2332 scrolledWidgets
.RawRemoveEntry(entry
);
2334 nsIntPoint screenOffset
= WidgetToScreenOffset();
2335 RECT screenAffectedRect
= {
2336 screenOffset
.x
+ affectedRect
.x
,
2337 screenOffset
.y
+ affectedRect
.y
,
2338 screenOffset
.x
+ affectedRect
.XMost(),
2339 screenOffset
.y
+ affectedRect
.YMost()
2341 if (HasDescendantWindowOutsideRect(ourThreadID
, w
->mWnd
,
2342 screenAffectedRect
)) {
2343 // SW_SCROLLCHILDREN seems to not move descendant windows
2344 // that don't intersect the scrolled rectangle, *even if* the
2345 // immediate child window of the scrolled window *does* intersect
2346 // the scrolled window. So if w has a descendant window
2347 // that would not be moved, SW_SCROLLCHILDREN will hopelessly mess
2348 // things up and we must not use it.
2349 flags
&= ~SW_SCROLLCHILDREN
;
2352 flags
&= ~SW_SCROLLCHILDREN
;
2353 // We may have removed some children from scrolledWidgets even
2354 // though we decide here to not use SW_SCROLLCHILDREN. That's OK,
2355 // it just means that we might not use SW_SCROLLCHILDREN
2356 // for a later rectangle when we could have.
2362 if (flags
& SW_SCROLLCHILDREN
) {
2363 // ScrollWindowEx will send WM_MOVE to each moved window to tell it
2364 // its new position. Unfortunately those messages don't reach our
2365 // WM_MOVE handler for some plugins, so we have to update their
2366 // mBounds here. For windows that do receive WM_MOVE, this is OK,
2367 // they'll just overwrite mBounds again with the correct value.
2368 for (nsWindow
* w
= static_cast<nsWindow
*>(GetFirstChild()); w
;
2369 w
= static_cast<nsWindow
*>(w
->GetNextSibling())) {
2370 if (w
->mBounds
.Intersects(affectedRect
)) {
2371 w
->mBounds
+= aDelta
;
2376 RECT clip
= { affectedRect
.x
, affectedRect
.y
, affectedRect
.XMost(), affectedRect
.YMost() };
2377 ::ScrollWindowEx(mWnd
, aDelta
.x
, aDelta
.y
, &clip
, &clip
, updateRgn
, NULL
, flags
);
2379 // Areas that get scrolled into view from offscreen or under another
2380 // window (but inside the scroll area) need to be repainted.
2381 // ScrollWindowEx returns those areas in updateRgn, but also includes
2382 // the area of the source that isn't covered by the destination.
2383 // ScrollWindowEx will refuse to blit into an area that's already
2384 // invalid. When we're blitting multiple adjacent rectangles, we have
2385 // a problem where the source area of rectangle A overlaps the
2386 // destination area of a subsequent rectangle B; the first ScrollWindowEx
2387 // invalidates the source area of A that's outside of the destination
2388 // area of A, and then the ScrollWindowEx for B will refuse to fully
2389 // blit into B's destination. This produces nasty temporary glitches.
2390 // We combat this by having ScrollWindowEx not invalidate directly,
2391 // but give us back the region that needs to be invalidated,
2392 // and restricting that region to the destination before invalidating
2394 ::SetRectRgn(destRgn
, destRect
.x
, destRect
.y
, destRect
.XMost(), destRect
.YMost());
2395 ::CombineRgn(updateRgn
, updateRgn
, destRgn
, RGN_AND
);
2396 if (flags
& SW_SCROLLCHILDREN
) {
2397 for (nsWindow
* w
= static_cast<nsWindow
*>(GetFirstChild()); w
;
2398 w
= static_cast<nsWindow
*>(w
->GetNextSibling())) {
2399 if ((w
->mBounds
- aDelta
).Intersects(affectedRect
)) {
2400 // Widgets that have been scrolled by SW_SCROLLCHILDREN but which
2401 // were, or are, partly outside the scroll area must be invalidated
2402 // because SW_SCROLLCHILDREN doesn't update parts of widgets outside
2403 // the area it scrolled, even if it moved them.
2404 nsAutoTArray
<nsIntRect
,1> clipRegion
;
2405 w
->GetWindowClipRegion(&clipRegion
);
2406 if (!ClipRegionContainedInRect(clipRegion
,
2407 destRect
- w
->mBounds
.TopLeft()) ||
2408 !ClipRegionContainedInRect(clipRegion
,
2409 destRect
- (w
->mBounds
.TopLeft() - aDelta
))) {
2410 ::SetRectRgn(destRgn
, w
->mBounds
.x
, w
->mBounds
.y
, w
->mBounds
.XMost(), w
->mBounds
.YMost());
2411 ::CombineRgn(updateRgn
, updateRgn
, destRgn
, RGN_OR
);
2416 InvalidateRgnInWindowSubtree(mWnd
, updateRgn
, destRgn
);
2418 ::InvalidateRgn(mWnd
, updateRgn
, FALSE
);
2422 ::DeleteObject((HGDIOBJ
)updateRgn
);
2423 ::DeleteObject((HGDIOBJ
)destRgn
);
2425 // Now make sure all children actually get positioned, sized and clipped
2426 // correctly. If SW_SCROLLCHILDREN already moved widgets to their correct
2427 // locations, then the SetWindowPos calls this triggers will just be
2429 ConfigureChildren(aConfigurations
);
2432 /**************************************************************
2434 * SECTION: Native data storage
2436 * nsIWidget::GetNativeData
2437 * nsIWidget::FreeNativeData
2439 * Set or clear native data based on a constant.
2441 **************************************************************/
2443 // Return some native data according to aDataType
2444 void* nsWindow::GetNativeData(PRUint32 aDataType
)
2446 switch (aDataType
) {
2447 case NS_NATIVE_PLUGIN_PORT
:
2448 case NS_NATIVE_WIDGET
:
2449 case NS_NATIVE_WINDOW
:
2451 case NS_NATIVE_GRAPHIC
:
2452 // XXX: This is sleezy!! Remember to Release the DC after using it!
2454 return (void*)(eTransparencyTransparent
== mTransparencyMode
) ?
2455 mMemoryDC
: ::GetDC(mWnd
);
2457 return (void*)::GetDC(mWnd
);
2460 #ifdef NS_ENABLE_TSF
2461 case NS_NATIVE_TSF_THREAD_MGR
:
2462 return nsTextStore::GetThreadMgr();
2463 case NS_NATIVE_TSF_CATEGORY_MGR
:
2464 return nsTextStore::GetCategoryMgr();
2465 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR
:
2466 return nsTextStore::GetDisplayAttrMgr();
2467 #endif //NS_ENABLE_TSF
2476 // Free some native data according to aDataType
2477 void nsWindow::FreeNativeData(void * data
, PRUint32 aDataType
)
2481 case NS_NATIVE_GRAPHIC
:
2483 if (eTransparencyTransparent
!= mTransparencyMode
)
2484 ::ReleaseDC(mWnd
, (HDC
)data
);
2486 ::ReleaseDC(mWnd
, (HDC
)data
);
2489 case NS_NATIVE_WIDGET
:
2490 case NS_NATIVE_WINDOW
:
2491 case NS_NATIVE_PLUGIN_PORT
:
2498 /**************************************************************
2500 * SECTION: nsIWidget::SetTitle
2502 * Set the main windows title text.
2504 **************************************************************/
2506 NS_METHOD
nsWindow::SetTitle(const nsAString
& aTitle
)
2508 const nsString
& strTitle
= PromiseFlatString(aTitle
);
2509 ::SendMessageW(mWnd
, WM_SETTEXT
, (WPARAM
)0, (LPARAM
)(LPCWSTR
)strTitle
.get());
2513 /**************************************************************
2515 * SECTION: nsIWidget::SetIcon
2517 * Set the main windows icon.
2519 **************************************************************/
2521 NS_METHOD
nsWindow::SetIcon(const nsAString
& aIconSpec
)
2524 // Assume the given string is a local identifier for an icon file.
2526 nsCOMPtr
<nsILocalFile
> iconFile
;
2527 ResolveIconName(aIconSpec
, NS_LITERAL_STRING(".ico"),
2528 getter_AddRefs(iconFile
));
2530 return NS_OK
; // not an error if icon is not found
2532 nsAutoString iconPath
;
2533 iconFile
->GetPath(iconPath
);
2535 // XXX this should use MZLU (see bug 239279)
2539 HICON bigIcon
= (HICON
)::LoadImageW(NULL
,
2540 (LPCWSTR
)iconPath
.get(),
2542 ::GetSystemMetrics(SM_CXICON
),
2543 ::GetSystemMetrics(SM_CYICON
),
2545 HICON smallIcon
= (HICON
)::LoadImageW(NULL
,
2546 (LPCWSTR
)iconPath
.get(),
2548 ::GetSystemMetrics(SM_CXSMICON
),
2549 ::GetSystemMetrics(SM_CYSMICON
),
2553 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_BIG
, (LPARAM
)bigIcon
);
2555 ::DestroyIcon(icon
);
2557 #ifdef DEBUG_SetIcon
2559 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
2560 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath
.get(), ::GetLastError() );
2564 HICON icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_SMALL
, (LPARAM
)smallIcon
);
2566 ::DestroyIcon(icon
);
2568 #ifdef DEBUG_SetIcon
2570 NS_LossyConvertUTF16toASCII
cPath(iconPath
);
2571 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath
.get(), ::GetLastError() );
2578 /**************************************************************
2580 * SECTION: nsIWidget::WidgetToScreenOffset
2582 * Return this widget's origin in screen coordinates.
2584 **************************************************************/
2586 nsIntPoint
nsWindow::WidgetToScreenOffset()
2591 ::ClientToScreen(mWnd
, &point
);
2592 return nsIntPoint(point
.x
, point
.y
);
2595 /**************************************************************
2597 * SECTION: nsIWidget::EnableDragDrop
2599 * Enables/Disables drag and drop of files on this widget.
2601 **************************************************************/
2603 #if !defined(WINCE) // implemented in nsWindowCE.cpp
2604 NS_METHOD
nsWindow::EnableDragDrop(PRBool aEnable
)
2606 nsresult rv
= NS_ERROR_FAILURE
;
2608 if (nsnull
== mNativeDragTarget
) {
2609 mNativeDragTarget
= new nsNativeDragTarget(this);
2610 if (NULL
!= mNativeDragTarget
) {
2611 mNativeDragTarget
->AddRef();
2612 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
,TRUE
,FALSE
)) {
2613 if (S_OK
== ::RegisterDragDrop(mWnd
, (LPDROPTARGET
)mNativeDragTarget
)) {
2620 if (nsnull
!= mWnd
&& NULL
!= mNativeDragTarget
) {
2621 ::RevokeDragDrop(mWnd
);
2622 if (S_OK
== ::CoLockObjectExternal((LPUNKNOWN
)mNativeDragTarget
, FALSE
, TRUE
)) {
2625 mNativeDragTarget
->mDragCancelled
= PR_TRUE
;
2626 NS_RELEASE(mNativeDragTarget
);
2633 /**************************************************************
2635 * SECTION: nsIWidget::CaptureMouse
2637 * Enables/Disables system mouse capture.
2639 **************************************************************/
2641 NS_METHOD
nsWindow::CaptureMouse(PRBool aCapture
)
2643 if (!nsToolkit::gMouseTrailer
) {
2644 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
2649 nsToolkit::gMouseTrailer
->SetCaptureWindow(mWnd
);
2652 nsToolkit::gMouseTrailer
->SetCaptureWindow(NULL
);
2655 mIsInMouseCapture
= aCapture
;
2659 /**************************************************************
2661 * SECTION: nsIWidget::CaptureRollupEvents
2663 * Dealing with event rollup on destroy for popups. Enables &
2664 * Disables system capture of any and all events that would
2665 * cause a dropdown to be rolled up.
2667 **************************************************************/
2669 NS_IMETHODIMP
nsWindow::CaptureRollupEvents(nsIRollupListener
* aListener
,
2670 nsIMenuRollup
* aMenuRollup
,
2672 PRBool aConsumeRollupEvent
)
2675 /* we haven't bothered carrying a weak reference to sRollupWidget because
2676 we believe lifespan is properly scoped. this next assertion helps
2677 assure that remains true. */
2678 NS_ASSERTION(!sRollupWidget
, "rollup widget reassigned before release");
2679 sRollupConsumeEvent
= aConsumeRollupEvent
;
2680 NS_IF_RELEASE(sRollupWidget
);
2681 NS_IF_RELEASE(sMenuRollup
);
2682 sRollupListener
= aListener
;
2683 sMenuRollup
= aMenuRollup
;
2684 NS_IF_ADDREF(aMenuRollup
);
2685 sRollupWidget
= this;
2689 if (!sMsgFilterHook
&& !sCallProcHook
&& !sCallMouseHook
) {
2690 RegisterSpecialDropdownHooks();
2692 sProcessHook
= PR_TRUE
;
2696 sRollupListener
= nsnull
;
2697 NS_IF_RELEASE(sMenuRollup
);
2698 NS_IF_RELEASE(sRollupWidget
);
2701 sProcessHook
= PR_FALSE
;
2702 UnregisterSpecialDropdownHooks();
2709 /**************************************************************
2711 * SECTION: nsIWidget::GetAttention
2713 * Bring this window to the user's attention.
2715 **************************************************************/
2717 // Draw user's attention to this window until it comes to foreground.
2719 nsWindow::GetAttention(PRInt32 aCycleCount
)
2724 return NS_ERROR_NOT_INITIALIZED
;
2726 // Don't flash if the flash count is 0 or if the
2727 // top level window is already active.
2728 HWND fgWnd
= ::GetForegroundWindow();
2729 if (aCycleCount
== 0 || fgWnd
== GetTopLevelHWND(mWnd
))
2732 HWND flashWnd
= mWnd
;
2733 while (HWND ownerWnd
= ::GetWindow(flashWnd
, GW_OWNER
)) {
2734 flashWnd
= ownerWnd
;
2737 // Don't flash if the owner window is active either.
2738 if (fgWnd
== flashWnd
)
2741 DWORD defaultCycleCount
= 0;
2742 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT
, 0, &defaultCycleCount
, 0);
2744 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
2745 FLASHW_ALL
, aCycleCount
> 0 ? aCycleCount
: defaultCycleCount
, 0 };
2746 ::FlashWindowEx(&flashInfo
);
2751 void nsWindow::StopFlashing()
2754 HWND flashWnd
= mWnd
;
2755 while (HWND ownerWnd
= ::GetWindow(flashWnd
, GW_OWNER
)) {
2756 flashWnd
= ownerWnd
;
2759 FLASHWINFO flashInfo
= { sizeof(FLASHWINFO
), flashWnd
,
2760 FLASHW_STOP
, 0, 0 };
2761 ::FlashWindowEx(&flashInfo
);
2765 /**************************************************************
2767 * SECTION: nsIWidget::HasPendingInputEvent
2769 * Ask whether there user input events pending. All input events are
2770 * included, including those not targeted at this nsIwidget instance.
2772 **************************************************************/
2775 nsWindow::HasPendingInputEvent()
2777 // If there is pending input or the user is currently
2778 // moving the window then return true.
2779 // Note: When the user is moving the window WIN32 spins
2780 // a separate event loop and input events are not
2781 // reported to the application.
2782 if (HIWORD(GetQueueStatus(QS_INPUT
)))
2787 GUITHREADINFO guiInfo
;
2788 guiInfo
.cbSize
= sizeof(GUITHREADINFO
);
2789 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo
))
2791 return GUI_INMOVESIZE
== (guiInfo
.flags
& GUI_INMOVESIZE
);
2795 /**************************************************************
2797 * SECTION: nsIWidget::GetThebesSurface
2799 * Get the Thebes surface associated with this widget.
2801 **************************************************************/
2803 gfxASurface
*nsWindow::GetThebesSurface()
2806 return (new gfxWindowsSurface(mPaintDC
));
2808 return (new gfxWindowsSurface(mWnd
));
2811 /**************************************************************
2813 * SECTION: nsIWidget::OnDefaultButtonLoaded
2815 * Called after the dialog is loaded and it has a default button.
2817 **************************************************************/
2820 nsWindow::OnDefaultButtonLoaded(const nsIntRect
&aButtonRect
)
2823 return NS_ERROR_NOT_IMPLEMENTED
;
2825 if (aButtonRect
.IsEmpty())
2828 // Don't snap when we are not active.
2829 HWND activeWnd
= ::GetActiveWindow();
2830 if (activeWnd
!= ::GetForegroundWindow() ||
2831 GetTopLevelHWND(mWnd
, PR_TRUE
) != GetTopLevelHWND(activeWnd
, PR_TRUE
)) {
2835 PRBool isAlwaysSnapCursor
= PR_FALSE
;
2836 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
2838 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
2839 prefs
->GetBranch(nsnull
, getter_AddRefs(prefBranch
));
2841 prefBranch
->GetBoolPref("ui.cursor_snapping.always_enabled",
2842 &isAlwaysSnapCursor
);
2846 if (!isAlwaysSnapCursor
) {
2847 BOOL snapDefaultButton
;
2848 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON
, 0,
2849 &snapDefaultButton
, 0) || !snapDefaultButton
)
2853 nsIntRect widgetRect
;
2854 nsresult rv
= GetScreenBounds(widgetRect
);
2855 NS_ENSURE_SUCCESS(rv
, rv
);
2856 nsIntRect
buttonRect(aButtonRect
+ widgetRect
.TopLeft());
2858 nsIntPoint
centerOfButton(buttonRect
.x
+ buttonRect
.width
/ 2,
2859 buttonRect
.y
+ buttonRect
.height
/ 2);
2860 // The center of the button can be outside of the widget.
2861 // E.g., it could be hidden by scrolling.
2862 if (!widgetRect
.Contains(centerOfButton
)) {
2866 if (!::SetCursorPos(centerOfButton
.x
, centerOfButton
.y
)) {
2867 NS_ERROR("SetCursorPos failed");
2868 return NS_ERROR_FAILURE
;
2875 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta
,
2876 PRBool aIsHorizontal
,
2877 PRInt32
&aOverriddenDelta
)
2879 // The default vertical and horizontal scrolling speed is 3, this is defined
2880 // on the document of SystemParametersInfo in MSDN.
2881 const PRInt32 kSystemDefaultScrollingSpeed
= 3;
2883 PRInt32 absOriginDelta
= PR_ABS(aOriginalDelta
);
2885 // Compute the simple overridden speed.
2886 PRInt32 absComputedOverriddenDelta
;
2888 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta
, aIsHorizontal
,
2889 absComputedOverriddenDelta
);
2890 NS_ENSURE_SUCCESS(rv
, rv
);
2892 aOverriddenDelta
= aOriginalDelta
;
2894 if (absComputedOverriddenDelta
== absOriginDelta
) {
2895 // We don't override now.
2899 // Otherwise, we should check whether the user customized the system settings
2900 // or not. If the user did it, we should respect the will.
2902 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &systemSpeed
, 0)) {
2903 return NS_ERROR_FAILURE
;
2905 // The default vertical scrolling speed is 3, this is defined on the document
2906 // of SystemParametersInfo in MSDN.
2907 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
2911 // Only Vista and later, Windows has the system setting of horizontal
2912 // scrolling by the mouse wheel.
2913 if (GetWindowsVersion() >= VISTA_VERSION
) {
2914 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS
, 0, &systemSpeed
, 0)) {
2915 return NS_ERROR_FAILURE
;
2917 // The default horizontal scrolling speed is 3, this is defined on the
2918 // document of SystemParametersInfo in MSDN.
2919 if (systemSpeed
!= kSystemDefaultScrollingSpeed
) {
2924 // Limit the overridden delta value from the system settings. The mouse
2925 // driver might accelerate the scrolling speed already. If so, we shouldn't
2926 // override the scrolling speed for preventing the unexpected high speed
2928 PRInt32 absDeltaLimit
;
2930 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed
,
2931 aIsHorizontal
, absDeltaLimit
);
2932 NS_ENSURE_SUCCESS(rv
, rv
);
2934 // If the given delta is larger than our computed limitation value, the delta
2935 // was accelerated by the mouse driver. So, we should do nothing here.
2936 if (absDeltaLimit
<= absOriginDelta
) {
2940 absComputedOverriddenDelta
=
2941 PR_MIN(absComputedOverriddenDelta
, absDeltaLimit
);
2943 aOverriddenDelta
= (aOriginalDelta
> 0) ? absComputedOverriddenDelta
:
2944 -absComputedOverriddenDelta
;
2948 /**************************************************************
2949 **************************************************************
2951 ** BLOCK: Moz Events
2953 ** Moz GUI event management.
2955 **************************************************************
2956 **************************************************************/
2958 /**************************************************************
2960 * SECTION: Mozilla event initialization
2962 * Helpers for initializing moz events.
2964 **************************************************************/
2966 // Event intialization
2967 MSG
nsWindow::InitMSG(UINT aMessage
, WPARAM wParam
, LPARAM lParam
)
2970 msg
.message
= aMessage
;
2971 msg
.wParam
= wParam
;
2972 msg
.lParam
= lParam
;
2976 void nsWindow::InitEvent(nsGUIEvent
& event
, nsIntPoint
* aPoint
)
2978 if (nsnull
== aPoint
) { // use the point from the event
2979 // get the message position in client coordinates
2982 DWORD pos
= ::GetMessagePos();
2985 cpos
.x
= GET_X_LPARAM(pos
);
2986 cpos
.y
= GET_Y_LPARAM(pos
);
2988 ::ScreenToClient(mWnd
, &cpos
);
2989 event
.refPoint
.x
= cpos
.x
;
2990 event
.refPoint
.y
= cpos
.y
;
2992 event
.refPoint
.x
= 0;
2993 event
.refPoint
.y
= 0;
2997 // use the point override if provided
2998 event
.refPoint
.x
= aPoint
->x
;
2999 event
.refPoint
.y
= aPoint
->y
;
3003 event
.time
= ::GetMessageTime();
3005 event
.time
= PR_Now() / 1000;
3008 mLastPoint
= event
.refPoint
;
3011 /**************************************************************
3013 * SECTION: Moz event dispatch helpers
3015 * Helpers for dispatching different types of moz events.
3017 **************************************************************/
3019 // Main event dispatch. Invokes callback and ProcessEvent method on
3020 // Event Listener object. Part of nsIWidget.
3021 NS_IMETHODIMP
nsWindow::DispatchEvent(nsGUIEvent
* event
, nsEventStatus
& aStatus
)
3023 #ifdef WIDGET_DEBUG_OUTPUT
3024 debug_DumpEvent(stdout
,
3027 nsCAutoString("something"),
3029 #endif // WIDGET_DEBUG_OUTPUT
3031 aStatus
= nsEventStatus_eIgnore
;
3033 // skip processing of suppressed blur events
3034 if (event
->message
== NS_DEACTIVATE
&& BlurEventsSuppressed())
3037 if (nsnull
!= mEventCallback
) {
3038 aStatus
= (*mEventCallback
)(event
);
3041 // the window can be destroyed during processing of seemingly innocuous events like, say,
3042 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3043 // which causes problems with the deleted window. therefore:
3044 if (mOnDestroyCalled
)
3045 aStatus
= nsEventStatus_eConsumeNoDefault
;
3049 PRBool
nsWindow::DispatchStandardEvent(PRUint32 aMsg
)
3051 nsGUIEvent
event(PR_TRUE
, aMsg
, this);
3054 PRBool result
= DispatchWindowEvent(&event
);
3058 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
* event
)
3060 nsEventStatus status
;
3061 DispatchEvent(event
, status
);
3062 return ConvertStatus(status
);
3065 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
* event
, nsEventStatus
&aStatus
) {
3066 DispatchEvent(event
, aStatus
);
3067 return ConvertStatus(aStatus
);
3070 PRBool
nsWindow::DispatchKeyEvent(PRUint32 aEventType
, WORD aCharCode
,
3071 const nsTArray
<nsAlternativeCharCode
>* aAlternativeCharCodes
,
3072 UINT aVirtualCharCode
, const MSG
*aMsg
,
3073 const nsModifierKeyState
&aModKeyState
,
3076 nsKeyEvent
event(PR_TRUE
, aEventType
, this);
3077 nsIntPoint
point(0, 0);
3079 InitEvent(event
, &point
); // this add ref's event.widget
3081 event
.flags
|= aFlags
;
3082 event
.charCode
= aCharCode
;
3083 if (aAlternativeCharCodes
)
3084 event
.alternativeCharCodes
.AppendElements(*aAlternativeCharCodes
);
3085 event
.keyCode
= aVirtualCharCode
;
3089 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt
++,
3090 (NS_KEY_PRESS
== aEventType
) ? "PRESS" : (aEventType
== NS_KEY_UP
? "Up" : "Down"),
3091 event
.charCode
, event
.keyCode
);
3092 printf("Shift: %s Control %s Alt: %s \n",
3093 (mIsShiftDown
? "D" : "U"), (mIsControlDown
? "D" : "U"), (mIsAltDown
? "D" : "U"));
3094 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3095 IS_VK_DOWN(NS_VK_SHIFT
) ? 'S' : ' ',
3096 IS_VK_DOWN(NS_VK_CONTROL
) ? 'C' : ' ',
3097 IS_VK_DOWN(NS_VK_ALT
) ? 'A' : ' ',
3098 IS_VK_DOWN(VK_LSHIFT
) ? 'S' : ' ',
3099 IS_VK_DOWN(VK_LCONTROL
) ? 'C' : ' ',
3100 IS_VK_DOWN(VK_LMENU
) ? 'A' : ' ',
3101 IS_VK_DOWN(VK_RMENU
) ? 'A' : ' ',
3102 IS_VK_DOWN(VK_RCONTROL
) ? 'C' : ' ',
3103 IS_VK_DOWN(VK_RSHIFT
) ? 'S' : ' ');
3106 event
.isShift
= aModKeyState
.mIsShiftDown
;
3107 event
.isControl
= aModKeyState
.mIsControlDown
;
3108 event
.isMeta
= PR_FALSE
;
3109 event
.isAlt
= aModKeyState
.mIsAltDown
;
3111 NPEvent pluginEvent
;
3112 if (aMsg
&& PluginHasFocus()) {
3113 pluginEvent
.event
= aMsg
->message
;
3114 pluginEvent
.wParam
= aMsg
->wParam
;
3115 pluginEvent
.lParam
= aMsg
->lParam
;
3116 event
.pluginEvent
= (void *)&pluginEvent
;
3119 PRBool result
= DispatchWindowEvent(&event
);
3124 PRBool
nsWindow::DispatchCommandEvent(PRUint32 aEventCommand
)
3126 nsCOMPtr
<nsIAtom
> command
;
3127 switch (aEventCommand
) {
3128 case APPCOMMAND_BROWSER_BACKWARD
:
3129 command
= nsWidgetAtoms::Back
;
3131 case APPCOMMAND_BROWSER_FORWARD
:
3132 command
= nsWidgetAtoms::Forward
;
3134 case APPCOMMAND_BROWSER_REFRESH
:
3135 command
= nsWidgetAtoms::Reload
;
3137 case APPCOMMAND_BROWSER_STOP
:
3138 command
= nsWidgetAtoms::Stop
;
3140 case APPCOMMAND_BROWSER_SEARCH
:
3141 command
= nsWidgetAtoms::Search
;
3143 case APPCOMMAND_BROWSER_FAVORITES
:
3144 command
= nsWidgetAtoms::Bookmarks
;
3146 case APPCOMMAND_BROWSER_HOME
:
3147 command
= nsWidgetAtoms::Home
;
3152 nsCommandEvent
event(PR_TRUE
, nsWidgetAtoms::onAppCommand
, command
, this);
3155 DispatchWindowEvent(&event
);
3160 // Recursively dispatch synchronous paints for nsIWidget
3161 // descendants with invalidated rectangles.
3162 BOOL CALLBACK
nsWindow::DispatchStarvedPaints(HWND aWnd
, LPARAM aMsg
)
3164 LONG_PTR proc
= ::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
3165 if (proc
== (LONG_PTR
)&nsWindow::WindowProc
) {
3166 // its one of our windows so check to see if it has a
3167 // invalidated rect. If it does. Dispatch a synchronous
3169 if (GetUpdateRect(aWnd
, NULL
, FALSE
))
3170 VERIFY(::UpdateWindow(aWnd
));
3175 // Check for pending paints and dispatch any pending paint
3176 // messages for any nsIWidget which is a descendant of the
3177 // top-level window that *this* window is embedded within.
3179 // Note: We do not dispatch pending paint messages for non
3180 // nsIWidget managed windows.
3181 void nsWindow::DispatchPendingEvents()
3184 NS_WARNING("We were asked to dispatch pending events during painting, "
3185 "denying since that's unsafe.");
3189 UpdateLastInputEventTime();
3191 // We need to ensure that reflow events do not get starved.
3192 // At the same time, we don't want to recurse through here
3193 // as that would prevent us from dispatching starved paints.
3194 static int recursionBlocker
= 0;
3195 if (recursionBlocker
++ == 0) {
3196 NS_ProcessPendingEvents(nsnull
, PR_MillisecondsToInterval(100));
3200 // Quickly check to see if there are any
3201 // paint events pending.
3202 if (::GetQueueStatus(QS_PAINT
)) {
3203 // Find the top level window.
3204 HWND topWnd
= GetTopLevelHWND(mWnd
);
3206 // Dispatch pending paints for all topWnd's descendant windows.
3207 // Note: EnumChildWindows enumerates all descendant windows not just
3210 ::EnumChildWindows(topWnd
, nsWindow::DispatchStarvedPaints
, NULL
);
3212 nsWindowCE::EnumChildWindows(topWnd
, nsWindow::DispatchStarvedPaints
, NULL
);
3217 // Deal with plugin events
3218 PRBool
nsWindow::DispatchPluginEvent(const MSG
&aMsg
)
3220 if (!PluginHasFocus())
3223 nsGUIEvent
event(PR_TRUE
, NS_PLUGIN_EVENT
, this);
3224 nsIntPoint
point(0, 0);
3225 InitEvent(event
, &point
);
3226 NPEvent pluginEvent
;
3227 pluginEvent
.event
= aMsg
.message
;
3228 pluginEvent
.wParam
= aMsg
.wParam
;
3229 pluginEvent
.lParam
= aMsg
.lParam
;
3230 event
.pluginEvent
= (void *)&pluginEvent
;
3231 return DispatchWindowEvent(&event
);
3234 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg
,
3238 ::GetMessageW(&msg
, mWnd
, aFirstMsg
, aLastMsg
);
3239 DispatchPluginEvent(msg
);
3242 // Deal with all sort of mouse event
3243 PRBool
nsWindow::DispatchMouseEvent(PRUint32 aEventType
, WPARAM wParam
,
3244 LPARAM lParam
, PRBool aIsContextMenuKey
,
3247 PRBool result
= PR_FALSE
;
3249 if (!mEventCallback
) {
3253 nsIntPoint eventPoint
;
3254 eventPoint
.x
= GET_X_LPARAM(lParam
);
3255 eventPoint
.y
= GET_Y_LPARAM(lParam
);
3257 nsMouseEvent
event(PR_TRUE
, aEventType
, this, nsMouseEvent::eReal
,
3259 ? nsMouseEvent::eContextMenuKey
3260 : nsMouseEvent::eNormal
);
3261 if (aEventType
== NS_CONTEXTMENU
&& aIsContextMenuKey
) {
3262 nsIntPoint
zero(0, 0);
3263 InitEvent(event
, &zero
);
3265 InitEvent(event
, &eventPoint
);
3268 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
3269 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
3270 event
.isMeta
= PR_FALSE
;
3271 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
3272 event
.button
= aButton
;
3274 nsIntPoint mpScreen
= eventPoint
+ WidgetToScreenOffset();
3276 // Suppress mouse moves caused by widget creation
3277 if (aEventType
== NS_MOUSE_MOVE
)
3279 if ((sLastMouseMovePoint
.x
== mpScreen
.x
) && (sLastMouseMovePoint
.y
== mpScreen
.y
))
3281 sLastMouseMovePoint
.x
= mpScreen
.x
;
3282 sLastMouseMovePoint
.y
= mpScreen
.y
;
3285 PRBool insideMovementThreshold
= (abs(sLastMousePoint
.x
- eventPoint
.x
) < (short)::GetSystemMetrics(SM_CXDOUBLECLK
)) &&
3286 (abs(sLastMousePoint
.y
- eventPoint
.y
) < (short)::GetSystemMetrics(SM_CYDOUBLECLK
));
3290 case nsMouseEvent::eLeftButton
:
3291 eventButton
= VK_LBUTTON
;
3293 case nsMouseEvent::eMiddleButton
:
3294 eventButton
= VK_MBUTTON
;
3296 case nsMouseEvent::eRightButton
:
3297 eventButton
= VK_RBUTTON
;
3304 // Doubleclicks are used to set the click count, then changed to mousedowns
3305 // We're going to time double-clicks from mouse *up* to next mouse *down*
3307 LONG curMsgTime
= ::GetMessageTime();
3309 LONG curMsgTime
= PR_Now() / 1000;
3312 if (aEventType
== NS_MOUSE_DOUBLECLICK
) {
3313 event
.message
= NS_MOUSE_BUTTON_DOWN
;
3314 event
.button
= aButton
;
3315 sLastClickCount
= 2;
3317 else if (aEventType
== NS_MOUSE_BUTTON_UP
) {
3318 // remember when this happened for the next mouse down
3319 sLastMousePoint
.x
= eventPoint
.x
;
3320 sLastMousePoint
.y
= eventPoint
.y
;
3321 sLastMouseButton
= eventButton
;
3323 else if (aEventType
== NS_MOUSE_BUTTON_DOWN
) {
3324 // now look to see if we want to convert this to a double- or triple-click
3325 if (((curMsgTime
- sLastMouseDownTime
) < (LONG
)::GetDoubleClickTime()) && insideMovementThreshold
&&
3326 eventButton
== sLastMouseButton
) {
3329 // reset the click count, to count *this* click
3330 sLastClickCount
= 1;
3332 // Set last Click time on MouseDown only
3333 sLastMouseDownTime
= curMsgTime
;
3335 else if (aEventType
== NS_MOUSE_MOVE
&& !insideMovementThreshold
) {
3336 sLastClickCount
= 0;
3338 else if (aEventType
== NS_MOUSE_EXIT
) {
3339 event
.exit
= IsTopLevelMouseExit(mWnd
) ? nsMouseEvent::eTopLevel
: nsMouseEvent::eChild
;
3341 event
.clickCount
= sLastClickCount
;
3344 printf("Msg Time: %d Click Count: %d\n", curMsgTime
, event
.clickCount
);
3347 NPEvent pluginEvent
;
3351 case NS_MOUSE_BUTTON_DOWN
:
3353 case nsMouseEvent::eLeftButton
:
3354 pluginEvent
.event
= WM_LBUTTONDOWN
;
3356 case nsMouseEvent::eMiddleButton
:
3357 pluginEvent
.event
= WM_MBUTTONDOWN
;
3359 case nsMouseEvent::eRightButton
:
3360 pluginEvent
.event
= WM_RBUTTONDOWN
;
3366 case NS_MOUSE_BUTTON_UP
:
3368 case nsMouseEvent::eLeftButton
:
3369 pluginEvent
.event
= WM_LBUTTONUP
;
3371 case nsMouseEvent::eMiddleButton
:
3372 pluginEvent
.event
= WM_MBUTTONUP
;
3374 case nsMouseEvent::eRightButton
:
3375 pluginEvent
.event
= WM_RBUTTONUP
;
3381 case NS_MOUSE_DOUBLECLICK
:
3383 case nsMouseEvent::eLeftButton
:
3384 pluginEvent
.event
= WM_LBUTTONDBLCLK
;
3386 case nsMouseEvent::eMiddleButton
:
3387 pluginEvent
.event
= WM_MBUTTONDBLCLK
;
3389 case nsMouseEvent::eRightButton
:
3390 pluginEvent
.event
= WM_RBUTTONDBLCLK
;
3397 pluginEvent
.event
= WM_MOUSEMOVE
;
3400 pluginEvent
.event
= WM_MOUSELEAVE
;
3403 pluginEvent
.event
= WM_NULL
;
3407 pluginEvent
.wParam
= wParam
; // plugins NEED raw OS event flags!
3408 pluginEvent
.lParam
= lParam
;
3410 event
.pluginEvent
= (void *)&pluginEvent
;
3412 // call the event callback
3413 if (nsnull
!= mEventCallback
) {
3414 if (nsToolkit::gMouseTrailer
)
3415 nsToolkit::gMouseTrailer
->Disable();
3416 if (aEventType
== NS_MOUSE_MOVE
) {
3417 if (nsToolkit::gMouseTrailer
&& !mIsInMouseCapture
) {
3418 nsToolkit::gMouseTrailer
->SetMouseTrailerWindow(mWnd
);
3425 if (rect
.Contains(event
.refPoint
)) {
3426 if (sCurrentWindow
== NULL
|| sCurrentWindow
!= this) {
3427 if ((nsnull
!= sCurrentWindow
) && (!sCurrentWindow
->mInDtor
)) {
3428 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
3429 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_EXIT
, wParam
, pos
);
3431 sCurrentWindow
= this;
3433 LPARAM pos
= sCurrentWindow
->lParamToClient(lParamToScreen(lParam
));
3434 sCurrentWindow
->DispatchMouseEvent(NS_MOUSE_ENTER
, wParam
, pos
);
3438 } else if (aEventType
== NS_MOUSE_EXIT
) {
3439 if (sCurrentWindow
== this) {
3440 sCurrentWindow
= nsnull
;
3444 result
= DispatchWindowEvent(&event
);
3446 if (nsToolkit::gMouseTrailer
)
3447 nsToolkit::gMouseTrailer
->Enable();
3449 // Release the widget with NS_IF_RELEASE() just in case
3450 // the context menu key code in nsEventListenerManager::HandleEvent()
3451 // released it already.
3458 // Deal with accessibile event
3459 #ifdef ACCESSIBILITY
3460 PRBool
nsWindow::DispatchAccessibleEvent(PRUint32 aEventType
, nsIAccessible
** aAcc
, nsIntPoint
* aPoint
)
3462 PRBool result
= PR_FALSE
;
3464 if (nsnull
== mEventCallback
) {
3470 nsAccessibleEvent
event(PR_TRUE
, aEventType
, this);
3471 InitEvent(event
, aPoint
);
3473 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
3474 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
3475 event
.isMeta
= PR_FALSE
;
3476 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
3477 event
.accessible
= nsnull
;
3479 result
= DispatchWindowEvent(&event
);
3481 // if the event returned an accesssible get it.
3482 if (event
.accessible
)
3483 *aAcc
= event
.accessible
;
3489 PRBool
nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType
)
3491 if (aEventType
== NS_ACTIVATE
)
3492 sJustGotActivate
= PR_FALSE
;
3493 sJustGotDeactivate
= PR_FALSE
;
3495 // retrive the toplevel window or dialog
3497 HWND toplevelWnd
= NULL
;
3499 toplevelWnd
= curWnd
;
3501 nsWindow
*win
= GetNSWindowPtr(curWnd
);
3503 nsWindowType wintype
;
3504 win
->GetWindowType(wintype
);
3505 if (wintype
== eWindowType_toplevel
|| wintype
== eWindowType_dialog
)
3509 curWnd
= ::GetParent(curWnd
); // Parent or owner (if has no parent)
3513 nsWindow
*win
= GetNSWindowPtr(toplevelWnd
);
3515 return win
->DispatchFocus(aEventType
);
3521 // Deal with focus messages
3522 PRBool
nsWindow::DispatchFocus(PRUint32 aEventType
)
3524 // call the event callback
3525 if (mEventCallback
) {
3526 nsGUIEvent
event(PR_TRUE
, aEventType
, this);
3529 //focus and blur event should go to their base widget loc, not current mouse pos
3530 event
.refPoint
.x
= 0;
3531 event
.refPoint
.y
= 0;
3533 NPEvent pluginEvent
;
3538 pluginEvent
.event
= WM_SETFOCUS
;
3541 pluginEvent
.event
= WM_KILLFOCUS
;
3543 case NS_PLUGIN_ACTIVATE
:
3544 pluginEvent
.event
= WM_KILLFOCUS
;
3550 event
.pluginEvent
= (void *)&pluginEvent
;
3552 return DispatchWindowEvent(&event
);
3557 PRBool
nsWindow::IsTopLevelMouseExit(HWND aWnd
)
3559 DWORD pos
= ::GetMessagePos();
3561 mp
.x
= GET_X_LPARAM(pos
);
3562 mp
.y
= GET_Y_LPARAM(pos
);
3563 HWND mouseWnd
= ::WindowFromPoint(mp
);
3565 // GetTopLevelHWND will return a HWND for the window frame (which includes
3566 // the non-client area). If the mouse has moved into the non-client area,
3567 // we should treat it as a top-level exit.
3568 HWND mouseTopLevel
= nsWindow::GetTopLevelHWND(mouseWnd
);
3569 if (mouseWnd
== mouseTopLevel
)
3572 return nsWindow::GetTopLevelHWND(aWnd
) != mouseTopLevel
;
3575 PRBool
nsWindow::BlurEventsSuppressed()
3577 // are they suppressed in this window?
3578 if (mBlurSuppressLevel
> 0)
3581 // are they suppressed by any container widget?
3582 HWND parentWnd
= ::GetParent(mWnd
);
3584 nsWindow
*parent
= GetNSWindowPtr(parentWnd
);
3586 return parent
->BlurEventsSuppressed();
3591 // In some circumstances (opening dependent windows) it makes more sense
3592 // (and fixes a crash bug) to not blur the parent window. Called from
3594 void nsWindow::SuppressBlurEvents(PRBool aSuppress
)
3597 ++mBlurSuppressLevel
; // for this widget
3599 NS_ASSERTION(mBlurSuppressLevel
> 0, "unbalanced blur event suppression");
3600 if (mBlurSuppressLevel
> 0)
3601 --mBlurSuppressLevel
;
3605 PRBool
nsWindow::ConvertStatus(nsEventStatus aStatus
)
3607 return aStatus
== nsEventStatus_eConsumeNoDefault
;
3610 /**************************************************************
3614 * IPC related helpers.
3616 **************************************************************/
3622 nsWindow::IsAsyncResponseEvent(UINT aMsg
, LRESULT
& aResult
)
3628 case WM_WINDOWPOSCHANGING
:
3629 case WM_WINDOWPOSCHANGED
:
3630 case WM_PARENTNOTIFY
:
3631 case WM_ACTIVATEAPP
:
3634 case WM_CHILDACTIVATE
:
3635 case WM_IME_SETCONTEXT
:
3639 case WM_MOUSEACTIVATE
:
3643 case WM_SETTINGCHANGE
:
3651 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg
);
3659 nsWindow::IPCWindowProcHandler(UINT
& msg
, WPARAM
& wParam
, LPARAM
& lParam
)
3661 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
3662 "Failed to prevent a nonqueued message from running!");
3664 // Windowed plugins receiving focus triggering WM_ACTIVATE app messages.
3665 if (mWindowType
== eWindowType_plugin
&& msg
== WM_SETFOCUS
&&
3666 ::GetPropW(mWnd
, L
"PluginInstanceParentProperty")) {
3671 // Modal UI being displayed in windowless plugins.
3672 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
3673 (::InSendMessageEx(NULL
)&(ISMEX_REPLIED
|ISMEX_SEND
)) == ISMEX_SEND
) {
3675 if (IsAsyncResponseEvent(msg
, res
)) {
3676 ::ReplyMessage(res
);
3683 /**************************************************************
3684 **************************************************************
3686 ** BLOCK: Native events
3688 ** Main Windows message handlers and OnXXX handlers for
3689 ** Windows event handling.
3691 **************************************************************
3692 **************************************************************/
3694 /**************************************************************
3696 * SECTION: Wind proc.
3698 * The main Windows event procedures and associated
3699 * message processing methods.
3701 **************************************************************/
3703 // The WndProc procedure for all nsWindows in this toolkit
3704 LRESULT CALLBACK
nsWindow::WindowProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
3706 // Get the window which caused the event and ask it to process the message
3707 nsWindow
*someWindow
= GetNSWindowPtr(hWnd
);
3711 someWindow
->IPCWindowProcHandler(msg
, wParam
, lParam
);
3714 // create this here so that we store the last rolled up popup until after
3715 // the event has been processed.
3716 nsAutoRollup autoRollup
;
3718 LRESULT popupHandlingResult
;
3719 if ( DealWithPopups(hWnd
, msg
, wParam
, lParam
, &popupHandlingResult
) )
3720 return popupHandlingResult
;
3722 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
3723 // why we are hitting this assert
3724 if (nsnull
== someWindow
) {
3725 NS_ASSERTION(someWindow
, "someWindow is null, cannot call any CallWindowProc");
3726 return ::DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
3729 // hold on to the window for the life of this method, in case it gets
3730 // deleted during processing. yes, it's a double hack, since someWindow
3731 // is not really an interface.
3732 nsCOMPtr
<nsISupports
> kungFuDeathGrip
;
3733 if (!someWindow
->mInDtor
) // not if we're in the destructor!
3734 kungFuDeathGrip
= do_QueryInterface((nsBaseWidget
*)someWindow
);
3736 // Re-direct a tab change message destined for its parent window to the
3737 // the actual window which generated the event.
3738 if (msg
== WM_NOTIFY
) {
3739 LPNMHDR pnmh
= (LPNMHDR
) lParam
;
3740 if (pnmh
->code
== TCN_SELCHANGE
) {
3741 someWindow
= GetNSWindowPtr(pnmh
->hwndFrom
);
3745 // Call ProcessMessage
3746 if (nsnull
!= someWindow
) {
3748 if (PR_TRUE
== someWindow
->ProcessMessage(msg
, wParam
, lParam
, &retValue
)) {
3753 return ::CallWindowProcW(someWindow
->GetPrevWindowProc(),
3754 hWnd
, msg
, wParam
, lParam
);
3757 // The main windows message processing method for plugins.
3758 // The result means whether this method processed the native
3759 // event for plugin. If false, the native event should be
3760 // processed by the caller self.
3762 nsWindow::ProcessMessageForPlugin(const MSG
&aMsg
,
3764 PRBool
&aCallDefWndProc
)
3766 NS_PRECONDITION(aResult
, "aResult must be non-null.");
3769 aCallDefWndProc
= PR_FALSE
;
3770 PRBool fallBackToNonPluginProcess
= PR_FALSE
;
3771 PRBool eventDispatched
= PR_FALSE
;
3772 PRBool dispatchPendingEvents
= PR_TRUE
;
3773 switch (aMsg
.message
) {
3774 case WM_INPUTLANGCHANGEREQUEST
:
3775 case WM_INPUTLANGCHANGE
:
3776 DispatchPluginEvent(aMsg
);
3777 return PR_FALSE
; // go to non-plug-ins processing
3781 *aResult
= ProcessCharMessage(aMsg
, &eventDispatched
);
3786 *aResult
= ProcessKeyUpMessage(aMsg
, &eventDispatched
);
3791 *aResult
= ProcessKeyDownMessage(aMsg
, &eventDispatched
);
3795 case WM_SYSDEADCHAR
:
3796 case WM_CONTEXTMENU
:
3804 case WM_IME_STARTCOMPOSITION
:
3805 case WM_IME_COMPOSITION
:
3806 case WM_IME_ENDCOMPOSITION
:
3808 case WM_IME_COMPOSITIONFULL
:
3809 case WM_IME_CONTROL
:
3810 case WM_IME_KEYDOWN
:
3813 case WM_IME_REQUEST
:
3817 case WM_IME_SETCONTEXT
:
3818 // Don't synchronously dispatch when we receive WM_IME_SETCONTEXT
3819 // because we get it during plugin destruction. (bug 491848)
3820 dispatchPendingEvents
= PR_FALSE
;
3827 if (!eventDispatched
)
3828 aCallDefWndProc
= !DispatchPluginEvent(aMsg
);
3829 if (dispatchPendingEvents
)
3830 DispatchPendingEvents();
3834 // The main windows message processing method.
3835 PRBool
nsWindow::ProcessMessage(UINT msg
, WPARAM
&wParam
, LPARAM
&lParam
,
3838 // (Large blocks of code should be broken out into OnEvent handlers.)
3839 if (mWindowHook
.Notify(mWnd
, msg
, wParam
, lParam
, aRetValue
))
3842 #if defined(EVENT_DEBUG_OUTPUT)
3843 // First param shows all events, second param indicates whether
3844 // to show mouse move events. See nsWindowDbg for details.
3845 PrintEvent(msg
, SHOW_REPEAT_EVENTS
, SHOW_MOUSEMOVE_EVENTS
);
3849 if (nsIMM32Handler::ProcessMessage(this, msg
, wParam
, lParam
, aRetValue
,
3851 return mWnd
? eatMessage
: PR_TRUE
;
3854 if (PluginHasFocus()) {
3855 PRBool callDefaultWndProc
;
3856 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
3857 if (ProcessMessageForPlugin(nativeMsg
, aRetValue
, callDefaultWndProc
)) {
3858 return mWnd
? !callDefaultWndProc
: PR_TRUE
;
3862 static UINT vkKeyCached
= 0; // caches VK code fon WM_KEYDOWN
3863 PRBool result
= PR_FALSE
; // call the default nsWindow proc
3866 static PRBool getWheelInfo
= PR_TRUE
;
3871 WORD wNotifyCode
= HIWORD(wParam
); // notification code
3872 if ((CBN_SELENDOK
== wNotifyCode
) || (CBN_SELENDCANCEL
== wNotifyCode
)) { // Combo box change
3873 nsGUIEvent
event(PR_TRUE
, NS_CONTROL_CHANGE
, this);
3874 nsIntPoint
point(0,0);
3875 InitEvent(event
, &point
); // this add ref's event.widget
3876 result
= DispatchWindowEvent(&event
);
3877 } else if (wNotifyCode
== 0) { // Menu selection
3878 nsMenuEvent
event(PR_TRUE
, NS_MENU_SELECTED
, this);
3879 event
.mCommand
= LOWORD(wParam
);
3881 result
= DispatchWindowEvent(&event
);
3887 // WM_QUERYENDSESSION must be handled by all windows.
3888 // Otherwise Windows thinks the window can just be killed at will.
3889 case WM_QUERYENDSESSION
:
3890 if (sCanQuit
== TRI_UNKNOWN
)
3892 // Ask if it's ok to quit, and store the answer until we
3893 // get WM_ENDSESSION signaling the round is complete.
3894 nsCOMPtr
<nsIObserverService
> obsServ
=
3895 do_GetService("@mozilla.org/observer-service;1");
3896 nsCOMPtr
<nsISupportsPRBool
> cancelQuit
=
3897 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID
);
3898 cancelQuit
->SetData(PR_FALSE
);
3899 obsServ
->NotifyObservers(cancelQuit
, "quit-application-requested", nsnull
);
3902 cancelQuit
->GetData(&abortQuit
);
3903 sCanQuit
= abortQuit
? TRI_FALSE
: TRI_TRUE
;
3905 *aRetValue
= sCanQuit
? TRUE
: FALSE
;
3913 case MOZ_WM_APP_QUIT
:
3914 if (msg
== MOZ_WM_APP_QUIT
|| (wParam
== TRUE
&& sCanQuit
== TRI_TRUE
))
3916 // Let's fake a shutdown sequence without actually closing windows etc.
3917 // to avoid Windows killing us in the middle. A proper shutdown would
3918 // require having a chance to pump some messages. Unfortunately
3919 // Windows won't let us do that. Bug 212316.
3920 nsCOMPtr
<nsIObserverService
> obsServ
=
3921 do_GetService("@mozilla.org/observer-service;1");
3922 NS_NAMED_LITERAL_STRING(context
, "shutdown-persist");
3923 obsServ
->NotifyObservers(nsnull
, "quit-application-granted", nsnull
);
3924 obsServ
->NotifyObservers(nsnull
, "quit-application-forced", nsnull
);
3925 obsServ
->NotifyObservers(nsnull
, "quit-application", nsnull
);
3926 obsServ
->NotifyObservers(nsnull
, "profile-change-net-teardown", context
.get());
3927 obsServ
->NotifyObservers(nsnull
, "profile-change-teardown", context
.get());
3928 obsServ
->NotifyObservers(nsnull
, "profile-before-change", context
.get());
3929 // Then a controlled but very quick exit.
3932 sCanQuit
= TRI_UNKNOWN
;
3937 case WM_DISPLAYCHANGE
:
3938 DispatchStandardEvent(NS_DISPLAYCHANGED
);
3942 case WM_SYSCOLORCHANGE
:
3943 // Note: This is sent for child windows as well as top-level windows.
3944 // The Win32 toolkit normally only sends these events to top-level windows.
3945 // But we cycle through all of the childwindows and send it to them as well
3946 // so all presentations get notified properly.
3947 // See nsWindow::GlobalMsgWindowProc.
3948 DispatchStandardEvent(NS_SYSCOLORCHANGED
);
3954 LPNMHDR pnmh
= (LPNMHDR
) lParam
;
3956 switch (pnmh
->code
) {
3959 DispatchStandardEvent(NS_TABCHANGE
);
3967 case WM_XP_THEMECHANGED
:
3969 DispatchStandardEvent(NS_THEMECHANGED
);
3971 // Invalidate the window so that the repaint will
3972 // pick up the new theme.
3973 Invalidate(PR_FALSE
);
3980 PRBool didChange
= PR_FALSE
;
3982 // update the global font list
3983 nsCOMPtr
<nsIFontEnumerator
> fontEnum
= do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv
);
3984 if (NS_SUCCEEDED(rv
)) {
3985 fontEnum
->UpdateFontList(&didChange
);
3986 //didChange is TRUE only if new font langGroup is added to the list.
3988 // update device context font cache
3989 // Dirty but easiest way:
3990 // Changing nsIPrefBranch entry which triggers callbacks
3991 // and flows into calling mDeviceContext->FlushFontCache()
3992 // to update the font cache in all the instance of Browsers
3993 nsCOMPtr
<nsIPrefService
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
3995 nsCOMPtr
<nsIPrefBranch
> fiPrefs
;
3996 prefs
->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs
));
3998 PRBool fontInternalChange
= PR_FALSE
;
3999 fiPrefs
->GetBoolPref("changed", &fontInternalChange
);
4000 fiPrefs
->SetBoolPref("changed", !fontInternalChange
);
4004 } //if (NS_SUCCEEDED(rv))
4009 case WM_POWERBROADCAST
:
4010 // only hidden window handle this
4011 // to prevent duplicate notification
4012 if (mWindowType
== eWindowType_invisible
) {
4015 case PBT_APMSUSPEND
:
4016 PostSleepWakeNotification("sleep_notification");
4018 case PBT_APMRESUMEAUTOMATIC
:
4019 case PBT_APMRESUMECRITICAL
:
4020 case PBT_APMRESUMESUSPEND
:
4021 PostSleepWakeNotification("wake_notification");
4028 case WM_MOVE
: // Window moved
4030 PRInt32 x
= GET_X_LPARAM(lParam
); // horizontal position in screen coordinates
4031 PRInt32 y
= GET_Y_LPARAM(lParam
); // vertical position in screen coordinates
4032 result
= OnMove(x
, y
);
4036 case WM_CLOSE
: // close request
4037 DispatchStandardEvent(NS_XUL_CLOSE
);
4038 result
= PR_TRUE
; // abort window closure
4048 *aRetValue
= (int) OnPaint();
4053 case WM_PRINTCLIENT
:
4054 result
= OnPaint((HDC
) wParam
);
4059 result
= OnHotKey(wParam
, lParam
);
4065 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4066 result
= ProcessCharMessage(nativeMsg
, nsnull
);
4067 DispatchPendingEvents();
4074 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4075 result
= ProcessKeyUpMessage(nativeMsg
, nsnull
);
4076 DispatchPendingEvents();
4083 MSG nativeMsg
= InitMSG(msg
, wParam
, lParam
);
4084 result
= ProcessKeyDownMessage(nativeMsg
, nsnull
);
4085 DispatchPendingEvents();
4089 // say we've dealt with erase background if widget does
4090 // not need auto-erasing
4092 if (!AutoErase((HDC
)wParam
)) {
4099 *aRetValue
= DLGC_WANTALLKEYS
;
4105 #ifdef WINCE_WINDOWS_MOBILE
4106 // Reset the kill timer so that we can continue at this
4108 SetTimer(mWnd
, KILL_PRIORITY_ID
, 2000 /* 2seconds */, NULL
);
4110 // Suppress dispatch of pending events
4111 // when mouse moves are generated by widget
4112 // creation instead of user input.
4113 LPARAM lParamScreen
= lParamToScreen(lParam
);
4115 mp
.x
= GET_X_LPARAM(lParamScreen
);
4116 mp
.y
= GET_Y_LPARAM(lParamScreen
);
4117 PRBool userMovedMouse
= PR_FALSE
;
4118 if ((sLastMouseMovePoint
.x
!= mp
.x
) || (sLastMouseMovePoint
.y
!= mp
.y
)) {
4119 userMovedMouse
= PR_TRUE
;
4122 result
= DispatchMouseEvent(NS_MOUSE_MOVE
, wParam
, lParam
);
4123 if (userMovedMouse
) {
4124 DispatchPendingEvents();
4129 #ifdef WINCE_WINDOWS_MOBILE
4131 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL
);
4132 KillTimer(mWnd
, KILL_PRIORITY_ID
);
4136 case WM_LBUTTONDOWN
:
4138 #ifdef WINCE_WINDOWS_MOBILE
4139 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL
);
4140 SetTimer(mWnd
, KILL_PRIORITY_ID
, 2000 /* 2 seconds */, NULL
);
4142 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
,
4143 PR_FALSE
, nsMouseEvent::eLeftButton
);
4144 DispatchPendingEvents();
4150 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
,
4151 PR_FALSE
, nsMouseEvent::eLeftButton
);
4152 DispatchPendingEvents();
4154 #ifdef WINCE_WINDOWS_MOBILE
4155 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL
);
4156 KillTimer(mWnd
, KILL_PRIORITY_ID
);
4164 // We need to check mouse button states and put them in for
4166 WPARAM mouseState
= (GetKeyState(VK_LBUTTON
) ? MK_LBUTTON
: 0)
4167 | (GetKeyState(VK_MBUTTON
) ? MK_MBUTTON
: 0)
4168 | (GetKeyState(VK_RBUTTON
) ? MK_RBUTTON
: 0);
4169 // Synthesize an event position because we don't get one from
4171 LPARAM pos
= lParamToClient(::GetMessagePos());
4172 DispatchMouseEvent(NS_MOUSE_EXIT
, mouseState
, pos
);
4177 case WM_CONTEXTMENU
:
4179 // if the context menu is brought up from the keyboard, |lParam|
4182 PRBool contextMenukey
= PR_FALSE
;
4183 if (lParam
== 0xFFFFFFFF)
4185 contextMenukey
= PR_TRUE
;
4186 pos
= lParamToClient(GetMessagePos());
4190 pos
= lParamToClient(lParam
);
4192 result
= DispatchMouseEvent(NS_CONTEXTMENU
, wParam
, pos
, contextMenukey
,
4194 nsMouseEvent::eLeftButton
:
4195 nsMouseEvent::eRightButton
);
4199 case WM_LBUTTONDBLCLK
:
4200 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4201 nsMouseEvent::eLeftButton
);
4204 case WM_MBUTTONDOWN
:
4206 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4207 nsMouseEvent::eMiddleButton
);
4208 DispatchPendingEvents();
4213 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, PR_FALSE
,
4214 nsMouseEvent::eMiddleButton
);
4215 DispatchPendingEvents();
4218 case WM_MBUTTONDBLCLK
:
4219 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4220 nsMouseEvent::eMiddleButton
);
4223 case WM_RBUTTONDOWN
:
4225 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, wParam
, lParam
, PR_FALSE
,
4226 nsMouseEvent::eRightButton
);
4227 DispatchPendingEvents();
4232 result
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, wParam
, lParam
, PR_FALSE
,
4233 nsMouseEvent::eRightButton
);
4234 DispatchPendingEvents();
4237 case WM_RBUTTONDBLCLK
:
4238 result
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, wParam
, lParam
, PR_FALSE
,
4239 nsMouseEvent::eRightButton
);
4244 PRUint32 appCommand
= GET_APPCOMMAND_LPARAM(lParam
);
4248 case APPCOMMAND_BROWSER_BACKWARD
:
4249 case APPCOMMAND_BROWSER_FORWARD
:
4250 case APPCOMMAND_BROWSER_REFRESH
:
4251 case APPCOMMAND_BROWSER_STOP
:
4252 case APPCOMMAND_BROWSER_SEARCH
:
4253 case APPCOMMAND_BROWSER_FAVORITES
:
4254 case APPCOMMAND_BROWSER_HOME
:
4255 DispatchCommandEvent(appCommand
);
4256 // tell the driver that we handled the event
4261 // default = PR_FALSE - tell the driver that the event was not handled
4267 // check for the incoming nsWindow handle to be null in which case
4268 // we assume the message is coming from a horizontal scrollbar inside
4269 // a listbox and we don't bother processing it (well, we don't have to)
4271 nsWindow
* scrollbar
= GetNSWindowPtr((HWND
)lParam
);
4274 result
= scrollbar
->OnScroll(msg
, wParam
, lParam
);
4279 case WM_CTLCOLORLISTBOX
:
4280 case WM_CTLCOLOREDIT
:
4281 case WM_CTLCOLORBTN
:
4282 //case WM_CTLCOLORSCROLLBAR: //XXX causes the scrollbar to be drawn incorrectly
4283 case WM_CTLCOLORSTATIC
:
4285 nsWindow
* control
= GetNSWindowPtr((HWND
)lParam
);
4287 control
->SetUpForPaint((HDC
)wParam
);
4288 *aRetValue
= (LPARAM
)control
->OnControlColor();
4295 // The WM_ACTIVATE event is fired when a window is raised or lowered,
4296 // and the loword of wParam specifies which. But we don't want to tell
4297 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
4298 // events are fired. Instead, set either the sJustGotActivate or
4299 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
4300 // events once the focus events arrive.
4302 if (mEventCallback
) {
4303 PRInt32 fActive
= LOWORD(wParam
);
4305 #if defined(WINCE_HAVE_SOFTKB)
4306 if (mIsTopWidgetWindow
&& sSoftKeyboardState
)
4307 nsWindowCE::ToggleSoftKB(mWnd
, fActive
);
4308 if (nsWindowCE::sShowSIPButton
== TRI_FALSE
&& WA_INACTIVE
!= fActive
) {
4309 HWND hWndSIPB
= FindWindowW(L
"MS_SIPBUTTON", NULL
);
4311 ShowWindow(hWndSIPB
, SW_HIDE
);
4316 if (WA_INACTIVE
== fActive
) {
4317 // when minimizing a window, the deactivation and focus events will
4318 // be fired in the reverse order. Instead, just dispatch
4319 // NS_DEACTIVATE right away.
4321 result
= DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
4323 sJustGotDeactivate
= PR_TRUE
;
4325 if (mIsTopWidgetWindow
)
4326 mLastKeyboardLayout
= gKbdLayout
.GetLayout();
4332 sJustGotActivate
= PR_TRUE
;
4333 nsMouseEvent
event(PR_TRUE
, NS_MOUSE_ACTIVATE
, this,
4334 nsMouseEvent::eReal
);
4337 event
.acceptActivation
= PR_TRUE
;
4339 PRBool result
= DispatchWindowEvent(&event
);
4341 if (event
.acceptActivation
)
4342 *aRetValue
= MA_ACTIVATE
;
4344 *aRetValue
= MA_NOACTIVATE
;
4346 if (sSwitchKeyboardLayout
&& mLastKeyboardLayout
)
4347 ActivateKeyboardLayout(mLastKeyboardLayout
, 0);
4351 if (mSizeMode
== nsSizeMode_Fullscreen
)
4352 MakeFullScreen(TRUE
);
4355 #ifdef WINCE_WINDOWS_MOBILE
4356 if (!gCheckForHTCApi
&& gHTCApiNavOpen
== nsnull
) {
4357 gCheckForHTCApi
= PR_TRUE
;
4359 HINSTANCE library
= LoadLibrary(L
"HTCAPI.dll");
4360 gHTCApiNavOpen
= (HTCApiNavOpen
) GetProcAddress(library
, "HTCNavOpen");
4361 gHTCApiNavSetMode
= (HTCApiNavSetMode
) GetProcAddress(library
,"HTCNavSetMode");
4364 if (gHTCApiNavOpen
!= nsnull
) {
4365 gHTCApiNavOpen(mWnd
, 1 /* undocumented value */);
4367 if (gHTCApiNavSetMode
!= nsnull
)
4368 gHTCApiNavSetMode ( mWnd
, 4);
4369 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
4375 case WM_MOUSEACTIVATE
:
4376 if (mWindowType
== eWindowType_popup
) {
4377 // a popup with a parent owner should not be activated when clicked
4378 // but should still allow the mouse event to be fired, so the return
4379 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
4380 // window, just use default processing so that the window is activated.
4381 HWND owner
= ::GetWindow(mWnd
, GW_OWNER
);
4382 if (owner
&& owner
== ::GetForegroundWindow()) {
4383 *aRetValue
= MA_NOACTIVATE
;
4389 case WM_WINDOWPOSCHANGING
:
4391 LPWINDOWPOS info
= (LPWINDOWPOS
) lParam
;
4392 OnWindowPosChanging(info
);
4398 if (sJustGotActivate
) {
4399 result
= DispatchFocusToTopLevelWindow(NS_ACTIVATE
);
4402 #ifdef ACCESSIBILITY
4403 if (nsWindow::sIsAccessibilityOn
) {
4404 // Create it for the first time so that it can start firing events
4405 nsCOMPtr
<nsIAccessible
> rootAccessible
= GetRootAccessible();
4409 #if defined(WINCE_HAVE_SOFTKB)
4411 // On Windows CE, we have a window that overlaps
4412 // the ISP button. In this case, we should always
4413 // try to hide it when we are activated
4415 nsIMEContext
IMEContext(mWnd
);
4417 ImmSetOpenStatus(IMEContext
.get(), TRUE
);
4423 #if defined(WINCE_HAVE_SOFTKB)
4425 nsIMEContext
IMEContext(mWnd
);
4426 ImmSetOpenStatus(IMEContext
.get(), FALSE
);
4429 if (sJustGotDeactivate
) {
4430 result
= DispatchFocusToTopLevelWindow(NS_DEACTIVATE
);
4434 case WM_WINDOWPOSCHANGED
:
4436 WINDOWPOS
*wp
= (LPWINDOWPOS
)lParam
;
4437 OnWindowPosChanged(wp
, result
);
4441 case WM_SETTINGCHANGE
:
4442 #if !defined (WINCE_WINDOWS_MOBILE)
4443 getWheelInfo
= PR_TRUE
;
4446 case SPI_SETSIPINFO
:
4447 case SPI_SETCURRENTIM
:
4448 nsWindowCE::OnSoftKbSettingsChange(mWnd
);
4450 case SETTINGCHANGE_RESET
:
4451 if (mWindowType
== eWindowType_invisible
) {
4452 // The OS sees to get confused and think that the invisable window
4453 // is in the foreground after an orientation change. By actually
4454 // setting it to the foreground and hiding it, we set it strait.
4455 // See bug 514007 for details.
4456 SetForegroundWindow(mWnd
);
4457 ShowWindow(mWnd
, SW_HIDE
);
4462 OnSettingsChange(wParam
, lParam
);
4466 case WM_INPUTLANGCHANGEREQUEST
:
4471 case WM_INPUTLANGCHANGE
:
4472 result
= OnInputLangChange((HKL
)lParam
);
4476 case WM_DESTROYCLIPBOARD
:
4478 nsIClipboard
* clipboard
;
4479 nsresult rv
= CallGetService(kCClipboardCID
, &clipboard
);
4480 clipboard
->EmptyClipboard(nsIClipboard::kGlobalClipboard
);
4481 NS_RELEASE(clipboard
);
4485 #ifdef ACCESSIBILITY
4489 if (lParam
== OBJID_CLIENT
) { // oleacc.dll will be loaded dynamically
4490 nsCOMPtr
<nsIAccessible
> rootAccessible
= GetRootAccessible(); // Held by a11y cache
4491 if (rootAccessible
) {
4492 IAccessible
*msaaAccessible
= NULL
;
4493 rootAccessible
->GetNativeInterface((void**)&msaaAccessible
); // does an addref
4494 if (msaaAccessible
) {
4495 *aRetValue
= LresultFromObject(IID_IAccessible
, wParam
, msaaAccessible
); // does an addref
4496 msaaAccessible
->Release(); // release extra addref
4497 result
= PR_TRUE
; // We handled the WM_GETOBJECT message
4506 // prevent Windows from trimming the working set. bug 76831
4507 if (!sTrimOnMinimize
&& wParam
== SC_MINIMIZE
) {
4508 ::ShowWindow(mWnd
, SW_SHOWMINIMIZED
);
4517 nsMemory::HeapMinimize(PR_TRUE
);
4522 case WM_MOUSEHWHEEL
:
4524 // If OnMouseWheel returns true, the event was forwarded directly to another
4525 // mozilla window message handler (ProcessMessage). In this case the return
4526 // value of the forwarded event is in 'result' which we should return immediately.
4527 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
4528 // 'result' and 'aRetValue' will be set based on what we did with the event, so
4529 // we should fall through.
4530 if (OnMouseWheel(msg
, wParam
, lParam
, getWheelInfo
, result
, aRetValue
))
4536 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4537 case WM_DWMCOMPOSITIONCHANGED
:
4538 BroadcastMsg(mWnd
, WM_DWMCOMPOSITIONCHANGED
);
4539 DispatchStandardEvent(NS_THEMECHANGED
);
4540 if (nsUXThemeData::CheckForCompositor() && mTransparencyMode
== eTransparencyGlass
) {
4541 MARGINS margins
= { -1, -1, -1, -1 };
4542 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(mWnd
, &margins
);
4544 Invalidate(PR_FALSE
);
4548 /* Gesture support events */
4549 case WM_TABLET_QUERYSYSTEMGESTURESTATUS
:
4550 // According to MS samples, this must be handled to enable
4551 // rotational support in multi-touch drivers.
4553 *aRetValue
= TABLET_ROTATE_GESTURE_ENABLE
;
4557 result
= OnGesture(wParam
, lParam
);
4560 case WM_GESTURENOTIFY
:
4562 if (mWindowType
!= eWindowType_invisible
&&
4563 mWindowType
!= eWindowType_plugin
&&
4564 mWindowType
!= eWindowType_toplevel
) {
4565 // eWindowType_toplevel is the top level main frame window. Gesture support
4566 // there prevents the user from interacting with the title bar or nc
4567 // areas using a single finger. Java and plugin windows can make their
4569 GESTURENOTIFYSTRUCT
* gestureinfo
= (GESTURENOTIFYSTRUCT
*)lParam
;
4570 nsPointWin touchPoint
;
4571 touchPoint
= gestureinfo
->ptsLocation
;
4572 touchPoint
.ScreenToClient(mWnd
);
4573 nsGestureNotifyEvent
gestureNotifyEvent(PR_TRUE
, NS_GESTURENOTIFY_EVENT_START
, this);
4574 gestureNotifyEvent
.refPoint
= touchPoint
;
4575 nsEventStatus status
;
4576 DispatchEvent(&gestureNotifyEvent
, status
);
4577 mDisplayPanFeedback
= gestureNotifyEvent
.displayPanFeedback
;
4578 mGesture
.SetWinGestureSupport(mWnd
, gestureNotifyEvent
.panDirection
);
4580 result
= PR_FALSE
; //should always bubble to DefWindowProc
4583 #endif // !defined(WINCE)
4587 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_DELETE
, this);
4588 DispatchWindowEvent(&command
);
4595 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_CUT
, this);
4596 DispatchWindowEvent(&command
);
4603 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_COPY
, this);
4604 DispatchWindowEvent(&command
);
4611 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_PASTE
, this);
4612 DispatchWindowEvent(&command
);
4620 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_UNDO
, this);
4621 DispatchWindowEvent(&command
);
4622 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
4629 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_REDO
, this);
4630 DispatchWindowEvent(&command
);
4631 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
4638 // Support EM_CANPASTE message only when wParam isn't specified or
4639 // is plain text format.
4640 if (wParam
== 0 || wParam
== CF_TEXT
|| wParam
== CF_UNICODETEXT
) {
4641 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_PASTE
,
4643 DispatchWindowEvent(&command
);
4644 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
4652 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_UNDO
,
4654 DispatchWindowEvent(&command
);
4655 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
4662 nsContentCommandEvent
command(PR_TRUE
, NS_CONTENT_COMMAND_REDO
,
4664 DispatchWindowEvent(&command
);
4665 *aRetValue
= (LRESULT
)(command
.mSucceeded
&& command
.mIsEnabled
);
4671 #ifdef WINCE_WINDOWS_MOBILE
4672 //HTC NAVIGATION WHEEL EVENT
4675 int distance
= wParam
& 0x000000FF;
4676 if ( (wParam
& 0x000000100) != 0) // Counter Clockwise
4678 if (OnMouseWheel(WM_MOUSEWHEEL
, MAKEWPARAM(0, distance
),
4679 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN
) / 2,
4680 GetSystemMetrics(SM_CYSCREEN
) / 2),
4681 getWheelInfo
, result
, aRetValue
))
4689 #ifdef NS_ENABLE_TSF
4690 if (msg
== WM_USER_TSF_TEXTCHANGE
) {
4691 nsTextStore::OnTextChangeMsg();
4693 #endif //NS_ENABLE_TSF
4694 #if defined(HEAP_DUMP_EVENT)
4695 if (msg
== GetHeapMsg()) {
4696 HeapDump(msg
, wParam
, lParam
);
4700 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
4701 if (msg
== nsAppShell::GetTaskbarButtonCreatedMessage())
4702 SetHasTaskbarIconBeenCreated();
4705 if (msg
== sOOPPPluginFocusEvent
) {
4706 // With OOPP, the plugin window exists in another process and is a child of
4707 // this window. This window is a placeholder plugin window for the dom. We
4708 // receive this event when the child window receives focus. (sent from
4709 // PluginInstanceParent.cpp)
4710 ::SendMessage(mWnd
, WM_MOUSEACTIVATE
, 0, 0); // See nsPluginNativeWindowWin.cpp
4717 //*aRetValue = result;
4722 //Events which caused mWnd destruction and aren't consumed
4723 //will crash during the Windows default processing.
4728 /**************************************************************
4730 * SECTION: Broadcast messaging
4732 * Broadcast messages to all windows.
4734 **************************************************************/
4736 // Enumerate all child windows sending aMsg to each of them
4737 BOOL CALLBACK
nsWindow::BroadcastMsgToChildren(HWND aWnd
, LPARAM aMsg
)
4739 WNDPROC winProc
= (WNDPROC
)::GetWindowLongPtrW(aWnd
, GWLP_WNDPROC
);
4740 if (winProc
== &nsWindow::WindowProc
) {
4741 // it's one of our windows so go ahead and send a message to it
4742 ::CallWindowProcW(winProc
, aWnd
, aMsg
, 0, 0);
4747 // Enumerate all top level windows specifying that the children of each
4748 // top level window should be enumerated. Do *not* send the message to
4749 // each top level window since it is assumed that the toolkit will send
4750 // aMsg to them directly.
4751 BOOL CALLBACK
nsWindow::BroadcastMsg(HWND aTopWindow
, LPARAM aMsg
)
4753 // Iterate each of aTopWindows child windows sending the aMsg
4756 ::EnumChildWindows(aTopWindow
, nsWindow::BroadcastMsgToChildren
, aMsg
);
4758 nsWindowCE::EnumChildWindows(aTopWindow
, nsWindow::BroadcastMsgToChildren
, aMsg
);
4763 // This method is called from nsToolkit::WindowProc to forward global
4764 // messages which need to be dispatched to all child windows.
4765 void nsWindow::GlobalMsgWindowProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
4768 case WM_SYSCOLORCHANGE
:
4769 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
4770 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
4771 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
4772 // all child windows as well. When running in an embedded application
4773 // we may not receive a WM_SYSCOLORCHANGE message because the top
4774 // level window is owned by the embeddor.
4775 // System color changes are posted to top-level windows only.
4776 // The NS_SYSCOLORCHANGE must be dispatched to all child
4779 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg
, msg
);
4785 /**************************************************************
4787 * SECTION: Event processing helpers
4789 * Special processing for certain event types and
4790 * synthesized events.
4792 **************************************************************/
4795 void nsWindow::PostSleepWakeNotification(const char* aNotification
)
4797 nsCOMPtr
<nsIObserverService
> observerService
= do_GetService("@mozilla.org/observer-service;1");
4798 if (observerService
)
4800 observerService
->NotifyObservers(nsnull
, aNotification
, nsnull
);
4805 LRESULT
nsWindow::ProcessCharMessage(const MSG
&aMsg
, PRBool
*aEventDispatched
)
4807 NS_PRECONDITION(aMsg
.message
== WM_CHAR
|| aMsg
.message
== WM_SYSCHAR
,
4808 "message is not keydown event");
4809 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
4810 ("%s charCode=%d scanCode=%d\n",
4811 aMsg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
4812 aMsg
.wParam
, HIWORD(aMsg
.lParam
) & 0xFF));
4814 // These must be checked here too as a lone WM_CHAR could be received
4815 // if a child window didn't handle it (for example Alt+Space in a content window)
4816 nsModifierKeyState modKeyState
;
4817 return OnChar(aMsg
, modKeyState
, aEventDispatched
);
4820 LRESULT
nsWindow::ProcessKeyUpMessage(const MSG
&aMsg
, PRBool
*aEventDispatched
)
4822 NS_PRECONDITION(aMsg
.message
== WM_KEYUP
|| aMsg
.message
== WM_SYSKEYUP
,
4823 "message is not keydown event");
4824 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
4825 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
4826 "WM_SYSKEYUP" : "WM_KEYUP", aMsg
.wParam
));
4828 nsModifierKeyState modKeyState
;
4830 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
4831 // scan code. However, this breaks Alt+Num pad input.
4832 // MSDN states the following:
4833 // Typically, ToAscii performs the translation based on the
4834 // virtual-key code. In some cases, however, bit 15 of the
4835 // uScanCode parameter may be used to distinguish between a key
4836 // press and a key release. The scan code is used for
4837 // translating ALT+number key combinations.
4839 // ignore [shift+]alt+space so the OS can handle it
4840 if (modKeyState
.mIsAltDown
&& !modKeyState
.mIsControlDown
&&
4841 IS_VK_DOWN(NS_VK_SPACE
)) {
4845 if (!nsIMM32Handler::IsComposing(this) &&
4846 (aMsg
.message
!= WM_KEYUP
|| aMsg
.message
!= VK_MENU
)) {
4847 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
4848 // This helps avoid triggering the menu bar for ALT key accelerators used in
4849 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
4850 // to switch back to Mozilla in Windows 95 and Windows 98
4851 return OnKeyUp(aMsg
, modKeyState
, aEventDispatched
);
4857 LRESULT
nsWindow::ProcessKeyDownMessage(const MSG
&aMsg
,
4858 PRBool
*aEventDispatched
)
4860 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
4861 ("%s VK=%d\n", aMsg
.message
== WM_SYSKEYDOWN
?
4862 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg
.wParam
));
4863 NS_PRECONDITION(aMsg
.message
== WM_KEYDOWN
|| aMsg
.message
== WM_SYSKEYDOWN
,
4864 "message is not keydown event");
4866 nsModifierKeyState modKeyState
;
4868 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
4869 // scan code. However, this breaks Alt+Num pad input.
4870 // MSDN states the following:
4871 // Typically, ToAscii performs the translation based on the
4872 // virtual-key code. In some cases, however, bit 15 of the
4873 // uScanCode parameter may be used to distinguish between a key
4874 // press and a key release. The scan code is used for
4875 // translating ALT+number key combinations.
4877 // ignore [shift+]alt+space so the OS can handle it
4878 if (modKeyState
.mIsAltDown
&& !modKeyState
.mIsControlDown
&&
4879 IS_VK_DOWN(NS_VK_SPACE
))
4883 if (modKeyState
.mIsAltDown
&& nsIMM32Handler::IsStatusChanged()) {
4884 nsIMM32Handler::NotifyEndStatusChange();
4885 } else if (!nsIMM32Handler::IsComposing(this)) {
4886 result
= OnKeyDown(aMsg
, modKeyState
, aEventDispatched
, nsnull
);
4890 if (aMsg
.wParam
== VK_MENU
||
4891 (aMsg
.wParam
== VK_F10
&& !modKeyState
.mIsShiftDown
)) {
4892 // We need to let Windows handle this keypress,
4893 // by returning PR_FALSE, if there's a native menu
4894 // bar somewhere in our containing window hierarchy.
4895 // Otherwise we handle the keypress and don't pass
4896 // it on to Windows, by returning PR_TRUE.
4897 PRBool hasNativeMenu
= PR_FALSE
;
4900 if (::GetMenu(hWnd
)) {
4901 hasNativeMenu
= PR_TRUE
;
4904 hWnd
= ::GetParent(hWnd
);
4906 result
= !hasNativeMenu
;
4914 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout
,
4915 PRInt32 aNativeKeyCode
,
4916 PRUint32 aModifierFlags
,
4917 const nsAString
& aCharacters
,
4918 const nsAString
& aUnmodifiedCharacters
)
4920 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
4921 nsPrintfCString
layoutName("%08x", aNativeKeyboardLayout
);
4922 HKL loadedLayout
= LoadKeyboardLayoutA(layoutName
.get(), KLF_NOTELLSHELL
);
4923 if (loadedLayout
== NULL
)
4924 return NS_ERROR_NOT_AVAILABLE
;
4926 // Setup clean key state and load desired layout
4927 BYTE originalKbdState
[256];
4928 ::GetKeyboardState(originalKbdState
);
4930 memset(kbdState
, 0, sizeof(kbdState
));
4931 // This changes the state of the keyboard for the current thread only,
4932 // and we'll restore it soon, so this should be OK.
4933 ::SetKeyboardState(kbdState
);
4934 HKL oldLayout
= gKbdLayout
.GetLayout();
4935 gKbdLayout
.LoadLayout(loadedLayout
);
4937 nsAutoTArray
<KeyPair
,10> keySequence
;
4938 SetupKeyModifiersSequence(&keySequence
, aModifierFlags
);
4939 NS_ASSERTION(aNativeKeyCode
>= 0 && aNativeKeyCode
< 256,
4940 "Native VK key code out of range");
4941 keySequence
.AppendElement(KeyPair(aNativeKeyCode
, 0));
4943 // Simulate the pressing of each modifier key and then the real key
4944 for (PRUint32 i
= 0; i
< keySequence
.Length(); ++i
) {
4945 PRUint8 key
= keySequence
[i
].mGeneral
;
4946 PRUint8 keySpecific
= keySequence
[i
].mSpecific
;
4947 kbdState
[key
] = 0x81; // key is down and toggled on if appropriate
4949 kbdState
[keySpecific
] = 0x81;
4951 ::SetKeyboardState(kbdState
);
4952 nsModifierKeyState modKeyState
;
4953 MSG msg
= InitMSG(WM_KEYDOWN
, key
, 0);
4954 if (i
== keySequence
.Length() - 1 && aCharacters
.Length() > 0) {
4955 UINT scanCode
= ::MapVirtualKeyEx(aNativeKeyCode
, MAPVK_VK_TO_VSC
,
4956 gKbdLayout
.GetLayout());
4957 nsFakeCharMessage fakeMsg
= { aCharacters
.CharAt(0), scanCode
};
4958 OnKeyDown(msg
, modKeyState
, nsnull
, &fakeMsg
);
4960 OnKeyDown(msg
, modKeyState
, nsnull
, nsnull
);
4963 for (PRUint32 i
= keySequence
.Length(); i
> 0; --i
) {
4964 PRUint8 key
= keySequence
[i
- 1].mGeneral
;
4965 PRUint8 keySpecific
= keySequence
[i
- 1].mSpecific
;
4966 kbdState
[key
] = 0; // key is up and toggled off if appropriate
4968 kbdState
[keySpecific
] = 0;
4970 ::SetKeyboardState(kbdState
);
4971 nsModifierKeyState modKeyState
;
4972 MSG msg
= InitMSG(WM_KEYUP
, key
, 0);
4973 OnKeyUp(msg
, modKeyState
, nsnull
);
4976 // Restore old key state and layout
4977 ::SetKeyboardState(originalKbdState
);
4978 gKbdLayout
.LoadLayout(oldLayout
);
4980 UnloadKeyboardLayout(loadedLayout
);
4982 #else //XXX: is there another way to do this?
4983 return NS_ERROR_NOT_IMPLEMENTED
;
4988 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint
,
4989 PRUint32 aNativeMessage
,
4990 PRUint32 aModifierFlags
)
4992 #ifndef WINCE // I don't think WINCE supports SendInput
4994 ::GetWindowRect(mWnd
, &r
);
4995 ::SetCursorPos(r
.left
+ aPoint
.x
, r
.top
+ aPoint
.y
);
4998 memset(&input
, 0, sizeof(input
));
5000 input
.type
= INPUT_MOUSE
;
5001 input
.mi
.dwFlags
= aNativeMessage
;
5002 ::SendInput(1, &input
, sizeof(INPUT
));
5006 return NS_ERROR_NOT_IMPLEMENTED
;
5010 /**************************************************************
5012 * SECTION: OnXXX message handlers
5014 * For message handlers that need to be broken out or
5015 * implemented in specific platform code.
5017 **************************************************************/
5019 BOOL
nsWindow::OnInputLangChange(HKL aHKL
)
5022 printf("OnInputLanguageChange\n");
5026 gKbdLayout
.LoadLayout(aHKL
);
5029 return PR_FALSE
; // always pass to child window
5032 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5033 void nsWindow::OnWindowPosChanged(WINDOWPOS
*wp
, PRBool
& result
)
5038 #ifdef WINSTATE_DEBUG_OUTPUT
5039 if (mWnd
== GetTopLevelHWND(mWnd
))
5040 printf("*** OnWindowPosChanged: [ top] ");
5042 printf("*** OnWindowPosChanged: [child] ");
5043 printf("WINDOWPOS flags:");
5044 if (wp
->flags
& SWP_FRAMECHANGED
)
5045 printf("SWP_FRAMECHANGED ");
5046 if (wp
->flags
& SWP_SHOWWINDOW
)
5047 printf("SWP_SHOWWINDOW ");
5048 if (wp
->flags
& SWP_NOSIZE
)
5049 printf("SWP_NOSIZE ");
5050 if (wp
->flags
& SWP_HIDEWINDOW
)
5051 printf("SWP_HIDEWINDOW ");
5055 // Handle window size mode changes
5056 if (wp
->flags
& SWP_FRAMECHANGED
) {
5057 nsSizeModeEvent
event(PR_TRUE
, NS_SIZEMODE
, this);
5060 pl
.length
= sizeof(pl
);
5061 ::GetWindowPlacement(mWnd
, &pl
);
5063 if (pl
.showCmd
== SW_SHOWMAXIMIZED
)
5064 event
.mSizeMode
= nsSizeMode_Maximized
;
5065 else if (pl
.showCmd
== SW_SHOWMINIMIZED
)
5066 event
.mSizeMode
= nsSizeMode_Minimized
;
5068 event
.mSizeMode
= nsSizeMode_Normal
;
5070 // Windows has just changed the size mode of this window. The following
5071 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
5072 // set the min/max window state again or for nsSizeMode_Normal, call
5073 // SetWindow with a parameter of SW_RESTORE. There's no need however as
5074 // this window's mode has already changed. Updating mSizeMode here
5075 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
5076 // to window docking. (bug 489258)
5077 mSizeMode
= event
.mSizeMode
;
5079 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
5080 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
5081 // prevents the working set from being trimmed but keeps the window active.
5082 // After the window is minimized, we need to do some touch up work on the
5083 // active window. (bugs 76831 & 499816)
5084 if (!sTrimOnMinimize
&& nsSizeMode_Minimized
== event
.mSizeMode
)
5085 ActivateOtherWindowHelper(mWnd
);
5087 #ifdef WINSTATE_DEBUG_OUTPUT
5088 switch (mSizeMode
) {
5089 case nsSizeMode_Normal
:
5090 printf("*** mSizeMode: nsSizeMode_Normal\n");
5092 case nsSizeMode_Minimized
:
5093 printf("*** mSizeMode: nsSizeMode_Minimized\n");
5095 case nsSizeMode_Maximized
:
5096 printf("*** mSizeMode: nsSizeMode_Maximized\n");
5099 printf("*** mSizeMode: ??????\n");
5106 result
= DispatchWindowEvent(&event
);
5108 // Skip window size change events below on minimization.
5109 if (mSizeMode
== nsSizeMode_Minimized
)
5113 // Handle window size changes
5114 if (0 == (wp
->flags
& SWP_NOSIZE
)) {
5116 PRInt32 newWidth
, newHeight
;
5118 ::GetWindowRect(mWnd
, &r
);
5120 newWidth
= r
.right
- r
.left
;
5121 newHeight
= r
.bottom
- r
.top
;
5122 nsIntRect
rect(wp
->x
, wp
->y
, newWidth
, newHeight
);
5125 if (eTransparencyTransparent
== mTransparencyMode
)
5126 ResizeTranslucentWindow(newWidth
, newHeight
);
5129 if (newWidth
> mLastSize
.width
)
5134 drect
.left
= wp
->x
+ mLastSize
.width
;
5136 drect
.right
= drect
.left
+ (newWidth
- mLastSize
.width
);
5137 drect
.bottom
= drect
.top
+ newHeight
;
5139 ::RedrawWindow(mWnd
, &drect
, NULL
,
5142 RDW_NOINTERNALPAINT
|
5146 if (newHeight
> mLastSize
.height
)
5152 drect
.top
= wp
->y
+ mLastSize
.height
;
5153 drect
.right
= drect
.left
+ newWidth
;
5154 drect
.bottom
= drect
.top
+ (newHeight
- mLastSize
.height
);
5156 ::RedrawWindow(mWnd
, &drect
, NULL
,
5159 RDW_NOINTERNALPAINT
|
5164 mBounds
.width
= newWidth
;
5165 mBounds
.height
= newHeight
;
5166 mLastSize
.width
= newWidth
;
5167 mLastSize
.height
= newHeight
;
5169 #ifdef WINSTATE_DEBUG_OUTPUT
5170 printf("*** Resize window: %d x %d x %d x %d\n", wp
->x
, wp
->y
, newWidth
, newHeight
);
5173 // Recalculate the width and height based on the client area for gecko events.
5174 if (::GetClientRect(mWnd
, &r
)) {
5175 rect
.width
= r
.right
- r
.left
;
5176 rect
.height
= r
.bottom
- r
.top
;
5179 // Send a gecko resize event
5180 result
= OnResize(rect
);
5185 void nsWindow::ActivateOtherWindowHelper(HWND aWnd
)
5187 // Find the next window that is enabled, visible, and not minimized.
5188 HWND hwndBelow
= ::GetNextWindow(aWnd
, GW_HWNDNEXT
);
5189 while (hwndBelow
&& (!::IsWindowEnabled(hwndBelow
) || !::IsWindowVisible(hwndBelow
) ||
5190 ::IsIconic(hwndBelow
))) {
5191 hwndBelow
= ::GetNextWindow(hwndBelow
, GW_HWNDNEXT
);
5194 // Push ourselves to the bottom of the stack, then activate the
5196 ::SetWindowPos(aWnd
, HWND_BOTTOM
, 0, 0, 0, 0,
5197 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
);
5199 ::SetForegroundWindow(hwndBelow
);
5201 // Play the minimize sound while we're here, since that is also
5202 // forgotten when we use SW_SHOWMINIMIZED.
5203 ::PlaySoundW(L
"Minimize", nsnull
, SND_ALIAS
| SND_NODEFAULT
| SND_ASYNC
);
5205 #endif // !defined(WINCE)
5208 void nsWindow::OnWindowPosChanging(LPWINDOWPOS
& info
)
5210 // enforce local z-order rules
5211 if (!(info
->flags
& SWP_NOZORDER
)) {
5212 HWND hwndAfter
= info
->hwndInsertAfter
;
5214 nsZLevelEvent
event(PR_TRUE
, NS_SETZLEVEL
, this);
5215 nsWindow
*aboveWindow
= 0;
5219 if (hwndAfter
== HWND_BOTTOM
)
5220 event
.mPlacement
= nsWindowZBottom
;
5221 else if (hwndAfter
== HWND_TOP
|| hwndAfter
== HWND_TOPMOST
|| hwndAfter
== HWND_NOTOPMOST
)
5222 event
.mPlacement
= nsWindowZTop
;
5224 event
.mPlacement
= nsWindowZRelative
;
5225 aboveWindow
= GetNSWindowPtr(hwndAfter
);
5227 event
.mReqBelow
= aboveWindow
;
5228 event
.mActualBelow
= nsnull
;
5230 event
.mImmediate
= PR_FALSE
;
5231 event
.mAdjusted
= PR_FALSE
;
5232 DispatchWindowEvent(&event
);
5234 if (event
.mAdjusted
) {
5235 if (event
.mPlacement
== nsWindowZBottom
)
5236 info
->hwndInsertAfter
= HWND_BOTTOM
;
5237 else if (event
.mPlacement
== nsWindowZTop
)
5238 info
->hwndInsertAfter
= HWND_TOP
;
5240 info
->hwndInsertAfter
= (HWND
)event
.mActualBelow
->GetNativeData(NS_NATIVE_WINDOW
);
5243 NS_IF_RELEASE(event
.mActualBelow
);
5245 // prevent rude external programs from making hidden window visible
5246 if (mWindowType
== eWindowType_invisible
)
5247 info
->flags
&= ~SWP_SHOWWINDOW
;
5251 // Gesture event processing. Handles WM_GESTURE events.
5253 PRBool
nsWindow::OnGesture(WPARAM wParam
, LPARAM lParam
)
5255 // Treatment for pan events which translate into scroll events:
5256 if (mGesture
.IsPanEvent(lParam
)) {
5257 nsMouseScrollEvent
event(PR_TRUE
, NS_MOUSE_PIXEL_SCROLL
, this);
5259 if ( !mGesture
.ProcessPanMessage(mWnd
, wParam
, lParam
) )
5260 return PR_FALSE
; // ignore
5262 nsEventStatus status
;
5264 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
5265 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
5266 event
.isMeta
= PR_FALSE
;
5267 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
5269 event
.time
= ::GetMessageTime();
5271 PRBool endFeedback
= PR_TRUE
;
5273 PRInt32 scrollOverflowX
= 0;
5274 PRInt32 scrollOverflowY
= 0;
5276 if (mGesture
.PanDeltaToPixelScrollX(event
)) {
5277 DispatchEvent(&event
, status
);
5278 scrollOverflowX
= event
.scrollOverflow
;
5281 if (mGesture
.PanDeltaToPixelScrollY(event
)) {
5282 DispatchEvent(&event
, status
);
5283 scrollOverflowY
= event
.scrollOverflow
;
5286 if (mDisplayPanFeedback
) {
5287 mGesture
.UpdatePanFeedbackX(mWnd
, scrollOverflowX
, endFeedback
);
5288 mGesture
.UpdatePanFeedbackY(mWnd
, scrollOverflowY
, endFeedback
);
5289 mGesture
.PanFeedbackFinalize(mWnd
, endFeedback
);
5292 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
5297 // Other gestures translate into simple gesture events:
5298 nsSimpleGestureEvent
event(PR_TRUE
, 0, this, 0, 0.0);
5299 if ( !mGesture
.ProcessGestureMessage(mWnd
, wParam
, lParam
, event
) ) {
5300 return PR_FALSE
; // fall through to DefWndProc
5303 // Polish up and send off the new event
5304 event
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
5305 event
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
5306 event
.isMeta
= PR_FALSE
;
5307 event
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
5309 event
.time
= ::GetMessageTime();
5311 nsEventStatus status
;
5312 DispatchEvent(&event
, status
);
5313 if (status
== nsEventStatus_eIgnore
) {
5314 return PR_FALSE
; // Ignored, fall through
5317 // Only close this if we process and return true.
5318 mGesture
.CloseGestureInfoHandle((HGESTUREINFO
)lParam
);
5320 return PR_TRUE
; // Handled
5322 #endif // !defined(WINCE)
5325 * OnMouseWheel - mouse wheele event processing. This was originally embedded
5326 * within the message case block. If returning true result should be returned
5327 * immediately (no more processing).
5329 PRBool
nsWindow::OnMouseWheel(UINT msg
, WPARAM wParam
, LPARAM lParam
, PRBool
& getWheelInfo
, PRBool
& result
, LRESULT
*aRetValue
)
5331 // Handle both flavors of mouse wheel events.
5332 static int iDeltaPerLine
, iDeltaPerChar
;
5333 static ULONG ulScrollLines
, ulScrollChars
= 1;
5334 static int currentVDelta
, currentHDelta
;
5335 static HWND currentWindow
= 0;
5337 PRBool isVertical
= msg
== WM_MOUSEWHEEL
;
5339 // Get mouse wheel metrics (but only once).
5341 getWheelInfo
= PR_FALSE
;
5343 SystemParametersInfo (SPI_GETWHEELSCROLLLINES
, 0, &ulScrollLines
, 0);
5345 // ulScrollLines usually equals 3 or 0 (for no scrolling)
5346 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
5348 // However, if ulScrollLines > WHEEL_DELTA, we assume that
5349 // the mouse driver wants a page scroll. The docs state that
5350 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
5351 // since some mouse drivers use an arbitrary large number instead,
5352 // we have to handle that as well.
5355 if (ulScrollLines
) {
5356 if (ulScrollLines
<= WHEEL_DELTA
) {
5357 iDeltaPerLine
= WHEEL_DELTA
/ ulScrollLines
;
5359 ulScrollLines
= WHEEL_PAGESCROLL
;
5363 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS
, 0,
5364 &ulScrollChars
, 0)) {
5365 // Note that we may always fail to get the value before Win Vista.
5370 if (ulScrollChars
) {
5371 if (ulScrollChars
<= WHEEL_DELTA
) {
5372 iDeltaPerChar
= WHEEL_DELTA
/ ulScrollChars
;
5374 ulScrollChars
= WHEEL_PAGESCROLL
;
5379 if ((isVertical
&& ulScrollLines
!= WHEEL_PAGESCROLL
&& !iDeltaPerLine
) ||
5380 (!isVertical
&& ulScrollChars
!= WHEEL_PAGESCROLL
&& !iDeltaPerChar
))
5381 return PR_FALSE
; // break
5383 // The mousewheel event will be dispatched to the toplevel
5384 // window. We need to give it to the child window
5386 if (!HandleScrollingPlugins(msg
, wParam
, lParam
, result
, aRetValue
, quit
))
5387 return quit
; // return immediately if its not our window
5389 // We should cancel the surplus delta if the current window is not
5390 // same as previous.
5391 if (currentWindow
!= mWnd
) {
5394 currentWindow
= mWnd
;
5397 nsMouseScrollEvent
scrollEvent(PR_TRUE
, NS_MOUSE_SCROLL
, this);
5398 scrollEvent
.delta
= 0;
5400 scrollEvent
.scrollFlags
= nsMouseScrollEvent::kIsVertical
;
5401 if (ulScrollLines
== WHEEL_PAGESCROLL
) {
5402 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
5403 scrollEvent
.delta
= (((short) HIWORD (wParam
)) > 0) ? -1 : 1;
5405 currentVDelta
-= (short) HIWORD (wParam
);
5406 if (PR_ABS(currentVDelta
) >= iDeltaPerLine
) {
5407 scrollEvent
.delta
= currentVDelta
/ iDeltaPerLine
;
5408 currentVDelta
%= iDeltaPerLine
;
5412 scrollEvent
.scrollFlags
= nsMouseScrollEvent::kIsHorizontal
;
5413 if (ulScrollChars
== WHEEL_PAGESCROLL
) {
5414 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
5415 scrollEvent
.delta
= (((short) HIWORD (wParam
)) > 0) ? 1 : -1;
5417 currentHDelta
+= (short) HIWORD (wParam
);
5418 if (PR_ABS(currentHDelta
) >= iDeltaPerChar
) {
5419 scrollEvent
.delta
= currentHDelta
/ iDeltaPerChar
;
5420 currentHDelta
%= iDeltaPerChar
;
5425 if (!scrollEvent
.delta
)
5426 return PR_FALSE
; // break
5428 scrollEvent
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
5429 scrollEvent
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
5430 scrollEvent
.isMeta
= PR_FALSE
;
5431 scrollEvent
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
5432 InitEvent(scrollEvent
);
5433 if (nsnull
!= mEventCallback
) {
5434 result
= DispatchWindowEvent(&scrollEvent
);
5436 // Note that we should return zero if we process WM_MOUSEWHEEL.
5437 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
5440 *aRetValue
= isVertical
? 0 : TRUE
;
5442 return PR_FALSE
; // break;
5446 StringCaseInsensitiveEquals(const PRUnichar
* aChars1
, const PRUint32 aNumChars1
,
5447 const PRUnichar
* aChars2
, const PRUint32 aNumChars2
)
5449 if (aNumChars1
!= aNumChars2
)
5452 nsCaseInsensitiveStringComparator comp
;
5453 return comp(aChars1
, aChars2
, aNumChars1
) == 0;
5456 UINT
nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode
)
5459 switch (aNativeKeyCode
) {
5460 case VK_OEM_1
: return NS_VK_SEMICOLON
; // 0xBA, For the US standard keyboard, the ';:' key
5461 case VK_OEM_PLUS
: return NS_VK_ADD
; // 0xBB, For any country/region, the '+' key
5462 case VK_OEM_MINUS
: return NS_VK_SUBTRACT
; // 0xBD, For any country/region, the '-' key
5466 return aNativeKeyCode
;
5470 * nsWindow::OnKeyDown peeks into the message queue and pulls out
5471 * WM_CHAR messages for processing. During testing we don't want to
5472 * mess with the real message queue. Instead we pass a
5473 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
5474 * that as if it was in the message queue, and refrain from actually
5475 * looking at or touching the message queue.
5477 LRESULT
nsWindow::OnKeyDown(const MSG
&aMsg
,
5478 nsModifierKeyState
&aModKeyState
,
5479 PRBool
*aEventDispatched
,
5480 nsFakeCharMessage
* aFakeCharMessage
)
5482 UINT virtualKeyCode
= aMsg
.wParam
;
5485 gKbdLayout
.OnKeyDown (virtualKeyCode
);
5488 // Use only DOMKeyCode for XP processing.
5489 // Use aVirtualKeyCode for gKbdLayout and native processing.
5490 UINT DOMKeyCode
= nsIMM32Handler::IsComposing(this) ?
5491 virtualKeyCode
: MapFromNativeToDOM(virtualKeyCode
);
5494 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
5498 DispatchKeyEvent(NS_KEY_DOWN
, 0, nsnull
, DOMKeyCode
, &aMsg
, aModKeyState
);
5499 if (aEventDispatched
)
5500 *aEventDispatched
= PR_TRUE
;
5502 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
5503 // for almost all keys
5504 switch (DOMKeyCode
) {
5508 case NS_VK_CAPS_LOCK
:
5509 case NS_VK_NUM_LOCK
:
5510 case NS_VK_SCROLL_LOCK
: return noDefault
;
5513 PRUint32 extraFlags
= (noDefault
? NS_EVENT_FLAG_NO_DEFAULT
: 0);
5515 BOOL gotMsg
= aFakeCharMessage
||
5516 ::PeekMessageW(&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_NOREMOVE
| PM_NOYIELD
);
5517 // Enter and backspace are always handled here to avoid for example the
5518 // confusion between ctrl-enter and ctrl-J.
5519 if (DOMKeyCode
== NS_VK_RETURN
|| DOMKeyCode
== NS_VK_BACK
||
5520 ((aModKeyState
.mIsControlDown
|| aModKeyState
.mIsAltDown
)
5524 && !gKbdLayout
.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)))
5527 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
5528 // They can be more than one because of:
5529 // * Dead-keys not pairing with base character
5530 // * Some keyboard layouts may map up to 4 characters to the single key
5531 PRBool anyCharMessagesRemoved
= PR_FALSE
;
5533 if (aFakeCharMessage
) {
5534 anyCharMessagesRemoved
= PR_TRUE
;
5536 while (gotMsg
&& (msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
))
5538 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5539 ("%s charCode=%d scanCode=%d\n", msg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
5540 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
5541 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST
, WM_KEYLAST
);
5542 anyCharMessagesRemoved
= PR_TRUE
;
5544 gotMsg
= ::PeekMessageW (&msg
, mWnd
, WM_KEYFIRST
, WM_KEYLAST
, PM_NOREMOVE
| PM_NOYIELD
);
5548 if (!anyCharMessagesRemoved
&& DOMKeyCode
== NS_VK_BACK
&&
5549 nsIMM32Handler::IsDoingKakuteiUndo(mWnd
)) {
5550 NS_ASSERTION(!aFakeCharMessage
,
5551 "We shouldn't be touching the real msg queue");
5552 RemoveMessageAndDispatchPluginEvent(WM_CHAR
, WM_CHAR
);
5556 (aFakeCharMessage
||
5557 msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
|| msg
.message
== WM_DEADCHAR
)) {
5558 if (aFakeCharMessage
)
5559 return OnCharRaw(aFakeCharMessage
->mCharCode
,
5560 aFakeCharMessage
->mScanCode
, aModKeyState
, extraFlags
);
5562 // If prevent default set for keydown, do same for keypress
5563 ::GetMessageW(&msg
, mWnd
, msg
.message
, msg
.message
);
5565 if (msg
.message
== WM_DEADCHAR
) {
5566 if (!PluginHasFocus())
5569 // We need to send the removed message to focused plug-in.
5570 DispatchPluginEvent(msg
);
5574 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5575 ("%s charCode=%d scanCode=%d\n",
5576 msg
.message
== WM_SYSCHAR
? "WM_SYSCHAR" : "WM_CHAR",
5577 msg
.wParam
, HIWORD(msg
.lParam
) & 0xFF));
5579 BOOL result
= OnChar(msg
, aModKeyState
, nsnull
, extraFlags
);
5580 // If a syschar keypress wasn't processed, Windows may want to
5581 // handle it to activate a native menu.
5582 if (!result
&& msg
.message
== WM_SYSCHAR
)
5583 ::DefWindowProcW(mWnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
5587 else if (!aModKeyState
.mIsControlDown
&& !aModKeyState
.mIsAltDown
&&
5588 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode
) ||
5589 KeyboardLayout::IsNumpadKey(virtualKeyCode
)))
5591 // If this is simple KeyDown event but next message is not WM_CHAR,
5592 // this event may not input text, so we should ignore this event.
5594 return PluginHasFocus() && noDefault
;
5597 if (gKbdLayout
.IsDeadKey ())
5598 return PluginHasFocus() && noDefault
;
5600 PRUint8 shiftStates
[5];
5601 PRUnichar uniChars
[5];
5602 PRUnichar shiftedChars
[5] = {0, 0, 0, 0, 0};
5603 PRUnichar unshiftedChars
[5] = {0, 0, 0, 0, 0};
5604 PRUnichar shiftedLatinChar
= 0;
5605 PRUnichar unshiftedLatinChar
= 0;
5606 PRUint32 numOfUniChars
= 0;
5607 PRUint32 numOfShiftedChars
= 0;
5608 PRUint32 numOfUnshiftedChars
= 0;
5609 PRUint32 numOfShiftStates
= 0;
5611 switch (virtualKeyCode
) {
5612 // keys to be sent as characters
5613 case VK_ADD
: uniChars
[0] = '+'; numOfUniChars
= 1; break;
5614 case VK_SUBTRACT
: uniChars
[0] = '-'; numOfUniChars
= 1; break;
5615 case VK_DIVIDE
: uniChars
[0] = '/'; numOfUniChars
= 1; break;
5616 case VK_MULTIPLY
: uniChars
[0] = '*'; numOfUniChars
= 1; break;
5627 uniChars
[0] = virtualKeyCode
- VK_NUMPAD0
+ '0';
5631 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode
)) {
5632 numOfUniChars
= numOfShiftStates
=
5633 gKbdLayout
.GetUniChars(uniChars
, shiftStates
,
5634 NS_ARRAY_LENGTH(uniChars
));
5637 if (aModKeyState
.mIsControlDown
^ aModKeyState
.mIsAltDown
) {
5638 PRUint8 capsLockState
= (::GetKeyState(VK_CAPITAL
) & 1) ? eCapsLock
: 0;
5639 numOfUnshiftedChars
=
5640 gKbdLayout
.GetUniCharsWithShiftState(virtualKeyCode
, capsLockState
,
5641 unshiftedChars
, NS_ARRAY_LENGTH(unshiftedChars
));
5643 gKbdLayout
.GetUniCharsWithShiftState(virtualKeyCode
,
5644 capsLockState
| eShift
,
5645 shiftedChars
, NS_ARRAY_LENGTH(shiftedChars
));
5647 // The current keyboard cannot input alphabets or numerics,
5648 // we should append them for Shortcut/Access keys.
5649 // E.g., for Cyrillic keyboard layout.
5650 if (NS_VK_A
<= DOMKeyCode
&& DOMKeyCode
<= NS_VK_Z
) {
5651 shiftedLatinChar
= unshiftedLatinChar
= DOMKeyCode
;
5653 shiftedLatinChar
+= 0x20;
5655 unshiftedLatinChar
+= 0x20;
5656 if (unshiftedLatinChar
== unshiftedChars
[0] &&
5657 shiftedLatinChar
== shiftedChars
[0]) {
5658 shiftedLatinChar
= unshiftedLatinChar
= 0;
5662 if (NS_VK_0
<= DOMKeyCode
&& DOMKeyCode
<= NS_VK_9
) {
5665 switch (virtualKeyCode
) {
5666 case VK_OEM_PLUS
: ch
= '+'; break;
5667 case VK_OEM_MINUS
: ch
= '-'; break;
5670 if (ch
&& unshiftedChars
[0] != ch
&& shiftedChars
[0] != ch
) {
5671 // Windows has assigned a virtual key code to the key even though
5672 // the character can't be produced with this key. That probably
5673 // means the character can't be produced with any key in the
5674 // current layout and so the assignment is based on a QWERTY
5675 // layout. Append this code so that users can access the shortcut.
5676 unshiftedLatinChar
= ch
;
5680 // If the charCode is not ASCII character, we should replace the
5681 // charCode with ASCII character only when Ctrl is pressed.
5682 // But don't replace the charCode when the charCode is not same as
5683 // unmodified characters. In such case, Ctrl is sometimes used for a
5684 // part of character inputting key combination like Shift.
5685 if (aModKeyState
.mIsControlDown
) {
5686 PRUint8 currentState
= eCtrl
;
5687 if (aModKeyState
.mIsShiftDown
)
5688 currentState
|= eShift
;
5691 aModKeyState
.mIsShiftDown
? shiftedLatinChar
: unshiftedLatinChar
;
5693 (numOfUniChars
== 0 ||
5694 StringCaseInsensitiveEquals(uniChars
, numOfUniChars
,
5695 aModKeyState
.mIsShiftDown
? shiftedChars
: unshiftedChars
,
5696 aModKeyState
.mIsShiftDown
? numOfShiftedChars
:
5697 numOfUnshiftedChars
))) {
5698 numOfUniChars
= numOfShiftStates
= 1;
5700 shiftStates
[0] = currentState
;
5706 if (numOfUniChars
> 0 || numOfShiftedChars
> 0 || numOfUnshiftedChars
> 0) {
5707 PRUint32 num
= PR_MAX(numOfUniChars
,
5708 PR_MAX(numOfShiftedChars
, numOfUnshiftedChars
));
5709 PRUint32 skipUniChars
= num
- numOfUniChars
;
5710 PRUint32 skipShiftedChars
= num
- numOfShiftedChars
;
5711 PRUint32 skipUnshiftedChars
= num
- numOfUnshiftedChars
;
5712 UINT keyCode
= numOfUniChars
== 0 ? DOMKeyCode
: 0;
5713 for (PRUint32 cnt
= 0; cnt
< num
; cnt
++) {
5714 PRUint16 uniChar
, shiftedChar
, unshiftedChar
;
5715 uniChar
= shiftedChar
= unshiftedChar
= 0;
5716 if (skipUniChars
<= cnt
) {
5717 if (cnt
- skipUniChars
< numOfShiftStates
) {
5718 // If key in combination with Alt and/or Ctrl produces a different
5719 // character than without them then do not report these flags
5720 // because it is separate keyboard layout shift state. If dead-key
5721 // and base character does not produce a valid composite character
5722 // then both produced dead-key character and following base
5723 // character may have different modifier flags, too.
5724 aModKeyState
.mIsShiftDown
=
5725 (shiftStates
[cnt
- skipUniChars
] & eShift
) != 0;
5726 aModKeyState
.mIsControlDown
=
5727 (shiftStates
[cnt
- skipUniChars
] & eCtrl
) != 0;
5728 aModKeyState
.mIsAltDown
=
5729 (shiftStates
[cnt
- skipUniChars
] & eAlt
) != 0;
5731 uniChar
= uniChars
[cnt
- skipUniChars
];
5733 if (skipShiftedChars
<= cnt
)
5734 shiftedChar
= shiftedChars
[cnt
- skipShiftedChars
];
5735 if (skipUnshiftedChars
<= cnt
)
5736 unshiftedChar
= unshiftedChars
[cnt
- skipUnshiftedChars
];
5737 nsAutoTArray
<nsAlternativeCharCode
, 5> altArray
;
5739 if (shiftedChar
|| unshiftedChar
) {
5740 nsAlternativeCharCode
chars(unshiftedChar
, shiftedChar
);
5741 altArray
.AppendElement(chars
);
5743 if (cnt
== num
- 1 && (unshiftedLatinChar
|| shiftedLatinChar
)) {
5744 nsAlternativeCharCode
chars(unshiftedLatinChar
, shiftedLatinChar
);
5745 altArray
.AppendElement(chars
);
5748 DispatchKeyEvent(NS_KEY_PRESS
, uniChar
, &altArray
,
5749 keyCode
, nsnull
, aModKeyState
, extraFlags
);
5752 DispatchKeyEvent(NS_KEY_PRESS
, 0, nsnull
, DOMKeyCode
, nsnull
, aModKeyState
,
5757 UINT unichar
= ::MapVirtualKey(virtualKeyCode
, MAPVK_VK_TO_CHAR
);
5758 // Check for dead characters or no mapping
5759 if (unichar
& 0x80) {
5762 DispatchKeyEvent(NS_KEY_PRESS
, unichar
, nsnull
, DOMKeyCode
, nsnull
, aModKeyState
,
5771 LRESULT
nsWindow::OnKeyUp(const MSG
&aMsg
,
5772 nsModifierKeyState
&aModKeyState
,
5773 PRBool
*aEventDispatched
)
5775 UINT virtualKeyCode
= aMsg
.wParam
;
5777 PR_LOG(gWindowsLog
, PR_LOG_ALWAYS
,
5778 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode
));
5780 if (!nsIMM32Handler::IsComposing(this)) {
5781 virtualKeyCode
= MapFromNativeToDOM(virtualKeyCode
);
5784 if (aEventDispatched
)
5785 *aEventDispatched
= PR_TRUE
;
5786 return DispatchKeyEvent(NS_KEY_UP
, 0, nsnull
, virtualKeyCode
, &aMsg
,
5791 LRESULT
nsWindow::OnChar(const MSG
&aMsg
, nsModifierKeyState
&aModKeyState
,
5792 PRBool
*aEventDispatched
, PRUint32 aFlags
)
5794 return OnCharRaw(aMsg
.wParam
, HIWORD(aMsg
.lParam
) & 0xFF, aModKeyState
,
5795 aFlags
, &aMsg
, aEventDispatched
);
5799 LRESULT
nsWindow::OnCharRaw(UINT charCode
, UINT aScanCode
,
5800 nsModifierKeyState
&aModKeyState
, PRUint32 aFlags
,
5801 const MSG
*aMsg
, PRBool
*aEventDispatched
)
5803 // ignore [shift+]alt+space so the OS can handle it
5804 if (aModKeyState
.mIsAltDown
&& !aModKeyState
.mIsControlDown
&&
5805 IS_VK_DOWN(NS_VK_SPACE
)) {
5809 // Ignore Ctrl+Enter (bug 318235)
5810 if (aModKeyState
.mIsControlDown
&& charCode
== 0xA) {
5814 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
5815 PRBool saveIsAltDown
= aModKeyState
.mIsAltDown
;
5816 PRBool saveIsControlDown
= aModKeyState
.mIsControlDown
;
5817 if (aModKeyState
.mIsAltDown
&& aModKeyState
.mIsControlDown
)
5818 aModKeyState
.mIsAltDown
= aModKeyState
.mIsControlDown
= PR_FALSE
;
5822 if (nsIMM32Handler::IsComposing(this)) {
5826 if (aModKeyState
.mIsControlDown
&& charCode
<= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
5827 // need to account for shift here. bug 16486
5828 if (aModKeyState
.mIsShiftDown
)
5829 uniChar
= charCode
- 1 + 'A';
5831 uniChar
= charCode
- 1 + 'a';
5834 else if (aModKeyState
.mIsControlDown
&& charCode
<= 0x1F) {
5835 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
5836 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
5837 // for some reason the keypress handler need to have the uniChar code set
5838 // with the addition of a upper case A not the lower case.
5839 uniChar
= charCode
- 1 + 'A';
5841 } else { // 0x20 - SPACE, 0x3D - EQUALS
5842 if (charCode
< 0x20 || (charCode
== 0x3D && aModKeyState
.mIsControlDown
)) {
5850 // Keep the characters unshifted for shortcuts and accesskeys and make sure
5851 // that numbers are always passed as such (among others: bugs 50255 and 351310)
5852 if (uniChar
&& (aModKeyState
.mIsControlDown
|| aModKeyState
.mIsAltDown
)) {
5853 UINT virtualKeyCode
= ::MapVirtualKeyEx(aScanCode
, MAPVK_VSC_TO_VK
,
5854 gKbdLayout
.GetLayout());
5855 UINT unshiftedCharCode
=
5856 virtualKeyCode
>= '0' && virtualKeyCode
<= '9' ? virtualKeyCode
:
5857 aModKeyState
.mIsShiftDown
? ::MapVirtualKeyEx(virtualKeyCode
,
5859 gKbdLayout
.GetLayout()) : 0;
5860 // ignore diacritics (top bit set) and key mapping errors (char code 0)
5861 if ((INT
)unshiftedCharCode
> 0)
5862 uniChar
= unshiftedCharCode
;
5865 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
5866 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
5868 if (!aModKeyState
.mIsShiftDown
&& (saveIsAltDown
|| saveIsControlDown
)) {
5869 uniChar
= towlower(uniChar
);
5872 PRBool result
= DispatchKeyEvent(NS_KEY_PRESS
, uniChar
, nsnull
,
5873 charCode
, aMsg
, aModKeyState
, aFlags
);
5874 if (aEventDispatched
)
5875 *aEventDispatched
= PR_TRUE
;
5876 aModKeyState
.mIsAltDown
= saveIsAltDown
;
5877 aModKeyState
.mIsControlDown
= saveIsControlDown
;
5882 nsWindow::SetupKeyModifiersSequence(nsTArray
<KeyPair
>* aArray
, PRUint32 aModifiers
)
5884 for (PRUint32 i
= 0; i
< NS_ARRAY_LENGTH(sModifierKeyMap
); ++i
) {
5885 const PRUint32
* map
= sModifierKeyMap
[i
];
5886 if (aModifiers
& map
[0]) {
5887 aArray
->AppendElement(KeyPair(map
[1], map
[2]));
5893 nsWindow::ConfigureChildren(const nsTArray
<Configuration
>& aConfigurations
)
5895 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
5896 // here, if that helps in some situations. So far I haven't seen a
5898 for (PRUint32 i
= 0; i
< aConfigurations
.Length(); ++i
) {
5899 const Configuration
& configuration
= aConfigurations
[i
];
5900 nsWindow
* w
= static_cast<nsWindow
*>(configuration
.mChild
);
5901 NS_ASSERTION(w
->GetParent() == this,
5902 "Configured widget is not a child");
5904 // MSDN says we should do on WinCE this before moving or resizing the window
5905 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
5906 // We put the region back just below, anyway.
5907 ::SetWindowRgn(w
->mWnd
, NULL
, TRUE
);
5910 w
->GetBounds(bounds
);
5911 if (bounds
.Size() != configuration
.mBounds
.Size()) {
5912 w
->Resize(configuration
.mBounds
.x
, configuration
.mBounds
.y
,
5913 configuration
.mBounds
.width
, configuration
.mBounds
.height
,
5915 } else if (bounds
.TopLeft() != configuration
.mBounds
.TopLeft()) {
5916 w
->Move(configuration
.mBounds
.x
, configuration
.mBounds
.y
);
5918 nsresult rv
= w
->SetWindowClipRegion(configuration
.mClipRegion
, PR_FALSE
);
5919 NS_ENSURE_SUCCESS(rv
, rv
);
5925 CreateHRGNFromArray(const nsTArray
<nsIntRect
>& aRects
)
5927 PRInt32 size
= sizeof(RGNDATAHEADER
) + sizeof(RECT
)*aRects
.Length();
5928 nsAutoTArray
<PRUint8
,100> buf
;
5929 if (!buf
.SetLength(size
))
5931 RGNDATA
* data
= reinterpret_cast<RGNDATA
*>(buf
.Elements());
5932 RECT
* rects
= reinterpret_cast<RECT
*>(data
->Buffer
);
5933 data
->rdh
.dwSize
= sizeof(data
->rdh
);
5934 data
->rdh
.iType
= RDH_RECTANGLES
;
5935 data
->rdh
.nCount
= aRects
.Length();
5937 for (PRUint32 i
= 0; i
< aRects
.Length(); ++i
) {
5938 const nsIntRect
& r
= aRects
[i
];
5939 bounds
.UnionRect(bounds
, r
);
5940 ::SetRect(&rects
[i
], r
.x
, r
.y
, r
.XMost(), r
.YMost());
5942 ::SetRect(&data
->rdh
.rcBound
, bounds
.x
, bounds
.y
, bounds
.XMost(), bounds
.YMost());
5943 return ::ExtCreateRegion(NULL
, buf
.Length(), data
);
5947 nsWindow::SetWindowClipRegion(const nsTArray
<nsIntRect
>& aRects
,
5948 PRBool aIntersectWithExisting
)
5950 if (!aIntersectWithExisting
) {
5951 if (!StoreWindowClipRegion(aRects
))
5955 HRGN dest
= CreateHRGNFromArray(aRects
);
5957 return NS_ERROR_OUT_OF_MEMORY
;
5959 if (aIntersectWithExisting
) {
5960 HRGN current
= ::CreateRectRgn(0, 0, 0, 0);
5962 if (::GetWindowRgn(mWnd
, current
) != 0 /*ERROR*/) {
5963 ::CombineRgn(dest
, dest
, current
, RGN_AND
);
5965 ::DeleteObject(current
);
5969 if (!::SetWindowRgn(mWnd
, dest
, TRUE
)) {
5970 ::DeleteObject(dest
);
5971 return NS_ERROR_FAILURE
;
5976 // WM_DESTROY event handler
5977 void nsWindow::OnDestroy()
5979 mOnDestroyCalled
= PR_TRUE
;
5981 // Make sure we don't get destroyed in the process of tearing down.
5982 nsCOMPtr
<nsIWidget
> kungFuDeathGrip(this);
5984 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
5986 DispatchStandardEvent(NS_DESTROY
);
5988 // Prevent the widget from sending additional events.
5989 mEventCallback
= nsnull
;
5991 // Free our subclass and clear |this| stored in the window props. We will no longer
5992 // receive events from Windows after this point.
5993 SubclassWindow(FALSE
);
5995 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
5996 // cleared. (It's used in tracking windows for mouse events.)
5997 if (sCurrentWindow
== this)
5998 sCurrentWindow
= nsnull
;
6000 // Disconnects us from our parent, will call our GetParent().
6001 nsBaseWidget::Destroy();
6003 // Release references to children, device context, toolkit, and app shell.
6004 nsBaseWidget::OnDestroy();
6006 // Clear our native parent handle.
6007 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
6008 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
6009 //SetParent(nsnull);
6011 // We have to destroy the native drag target before we null out our window pointer.
6012 EnableDragDrop(PR_FALSE
);
6014 // If we're going away and for some reason we're still the rollup widget, rollup and
6015 // turn off capture.
6016 if ( this == sRollupWidget
) {
6017 if ( sRollupListener
)
6018 sRollupListener
->Rollup(nsnull
, nsnull
);
6019 CaptureRollupEvents(nsnull
, nsnull
, PR_FALSE
, PR_TRUE
);
6022 // If IME is disabled, restore it.
6024 mOldIMC
= ::ImmAssociateContext(mWnd
, mOldIMC
);
6025 NS_ASSERTION(!mOldIMC
, "Another IMC was associated");
6028 // Turn off mouse trails if enabled.
6029 MouseTrailer
* mtrailer
= nsToolkit::gMouseTrailer
;
6031 if (mtrailer
->GetMouseTrailerWindow() == mWnd
)
6032 mtrailer
->DestroyTimer();
6034 if (mtrailer
->GetCaptureWindow() == mWnd
)
6035 mtrailer
->SetCaptureWindow(nsnull
);
6038 // Free GDI window class objects
6040 VERIFY(::DeleteObject(mBrush
));
6044 // Free app icon resources.
6046 icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_BIG
, (LPARAM
) 0);
6048 ::DestroyIcon(icon
);
6050 icon
= (HICON
) ::SendMessageW(mWnd
, WM_SETICON
, (WPARAM
)ICON_SMALL
, (LPARAM
) 0);
6052 ::DestroyIcon(icon
);
6054 // Destroy any custom cursor resources.
6056 SetCursor(eCursor_standard
);
6059 // Reset transparency
6060 if (eTransparencyTransparent
== mTransparencyMode
)
6061 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque
);
6064 #if defined(WINCE_HAVE_SOFTKB)
6065 // Revert the changes made for the software keyboard settings
6066 nsWindowCE::ResetSoftKB(mWnd
);
6069 // Clear the main HWND.
6074 PRBool
nsWindow::OnMove(PRInt32 aX
, PRInt32 aY
)
6079 nsGUIEvent
event(PR_TRUE
, NS_MOVE
, this);
6081 event
.refPoint
.x
= aX
;
6082 event
.refPoint
.y
= aY
;
6084 return DispatchWindowEvent(&event
);
6087 // Send a resize message to the listener
6088 PRBool
nsWindow::OnResize(nsIntRect
&aWindowRect
)
6090 // call the event callback
6091 if (mEventCallback
) {
6092 nsSizeEvent
event(PR_TRUE
, NS_SIZE
, this);
6094 event
.windowSize
= &aWindowRect
;
6096 if (::GetWindowRect(mWnd
, &r
)) {
6097 event
.mWinWidth
= PRInt32(r
.right
- r
.left
);
6098 event
.mWinHeight
= PRInt32(r
.bottom
- r
.top
);
6100 event
.mWinWidth
= 0;
6101 event
.mWinHeight
= 0;
6103 return DispatchWindowEvent(&event
);
6109 #if !defined(WINCE) // implemented in nsWindowCE.cpp
6110 PRBool
nsWindow::OnHotKey(WPARAM wParam
, LPARAM lParam
)
6114 #endif // !defined(WINCE)
6116 void nsWindow::OnSettingsChange(WPARAM wParam
, LPARAM lParam
)
6118 if (mWindowType
== eWindowType_dialog
||
6119 mWindowType
== eWindowType_toplevel
)
6120 nsWindowGfx::OnSettingsChangeGfx(wParam
);
6123 // Scrolling helper function for handling plugins.
6124 // Return value indicates whether the calling function should handle this
6125 // aHandled indicates whether this was handled at all
6126 // aQuitProcessing tells whether or not to continue processing the message
6127 PRBool
nsWindow::HandleScrollingPlugins(UINT aMsg
, WPARAM aWParam
,
6128 LPARAM aLParam
, PRBool
& aHandled
,
6130 PRBool
& aQuitProcessing
)
6132 // The scroll event will be dispatched to the toplevel
6133 // window. We need to give it to the child window
6134 aQuitProcessing
= PR_FALSE
; // default is to not stop processing
6136 DWORD dwPoints
= ::GetMessagePos();
6137 point
.x
= GET_X_LPARAM(dwPoints
);
6138 point
.y
= GET_Y_LPARAM(dwPoints
);
6140 static PRBool sIsProcessing
= PR_FALSE
;
6141 if (sIsProcessing
) {
6142 return PR_TRUE
; // the caller should handle this.
6145 static PRBool sMayBeUsingLogitechMouse
= PR_FALSE
;
6146 if (aMsg
== WM_MOUSEHWHEEL
) {
6147 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
6148 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
6149 // message at first time, this time, ::GetMessagePos works fine.
6150 // Then, we will return 0 (0 means we process it) to the message. Then, the
6151 // driver will POST the same messages continuously during the wheel tilted.
6152 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
6153 // cursor isn't 0,0. Therefore, we cannot trust the result of
6154 // ::GetMessagePos API if the sender is the driver.
6155 if (!sMayBeUsingLogitechMouse
&& aLParam
== 0 && aLParam
!= dwPoints
&&
6156 ::InSendMessage()) {
6157 sMayBeUsingLogitechMouse
= PR_TRUE
;
6158 } else if (sMayBeUsingLogitechMouse
&& aLParam
!= 0 && ::InSendMessage()) {
6159 // The user has changed the mouse from Logitech's to another one (e.g.,
6160 // the user has changed to the touchpad of the notebook.
6161 sMayBeUsingLogitechMouse
= PR_FALSE
;
6163 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
6164 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
6166 if (sMayBeUsingLogitechMouse
&& aLParam
== 0 && dwPoints
== 0) {
6167 ::GetCursorPos(&point
);
6171 HWND destWnd
= ::WindowFromPoint(point
);
6172 // Since we receive scroll events for as long as
6173 // we are focused, it's entirely possible that there
6174 // is another app's window or no window under the
6178 // No window is under the pointer
6179 return PR_FALSE
; // break, but continue processing
6181 // We don't care about windows belonging to other processes.
6182 DWORD processId
= 0;
6183 GetWindowThreadProcessId(destWnd
, &processId
);
6184 if (processId
!= GetCurrentProcessId())
6186 // Somebody elses window
6187 return PR_FALSE
; // break, but continue processing
6189 nsWindow
* destWindow
= GetNSWindowPtr(destWnd
);
6190 if (!destWindow
|| destWindow
->mWindowType
== eWindowType_plugin
) {
6191 // Some other app, or a plugin window.
6192 // Windows directs scrolling messages to the focused window.
6193 // However, Mozilla does not like plugins having focus, so a
6194 // Mozilla window (ie, the plugin's parent (us!) has focus.)
6195 // Therefore, plugins etc _should_ get first grab at the
6196 // message, but this focus vaguary means the plugin misses
6197 // out. If the window is a child of ours, forward it on.
6198 // Determine if a child by walking the parent list until
6199 // we find a parent matching our wndproc.
6200 HWND parentWnd
= ::GetParent(destWnd
);
6202 nsWindow
* parentWindow
= GetNSWindowPtr(parentWnd
);
6204 // We have a child window - quite possibly a plugin window.
6205 // However, not all plugins are created equal - some will handle this
6206 // message themselves, some will forward directly back to us, while
6207 // others will call DefWndProc, which itself still forwards back to us.
6208 // So if we have sent it once, we need to handle it ourself.
6210 // First time we have seen this message.
6211 // Call the child - either it will consume it, or
6212 // it will wind it's way back to us,triggering the destWnd case above
6213 // either way,when the call returns,we are all done with the message,
6214 sIsProcessing
= PR_TRUE
;
6215 if (0 == ::SendMessageW(destWnd
, aMsg
, aWParam
, aLParam
))
6217 sIsProcessing
= PR_FALSE
;
6218 return PR_FALSE
; // break, but continue processing
6220 parentWnd
= ::GetParent(parentWnd
);
6221 } // while parentWnd
6223 if (destWnd
== nsnull
)
6225 if (destWnd
!= mWnd
) {
6227 sIsProcessing
= PR_TRUE
;
6228 aHandled
= destWindow
->ProcessMessage(aMsg
, aWParam
, aLParam
, aRetValue
);
6229 sIsProcessing
= PR_FALSE
;
6230 aQuitProcessing
= PR_TRUE
;
6231 return PR_FALSE
; // break, and stop processing
6235 printf("WARNING: couldn't get child window for SCROLL event\n");
6238 return PR_TRUE
; // caller should handle this
6241 PRBool
nsWindow::OnScroll(UINT aMsg
, WPARAM aWParam
, LPARAM aLParam
)
6245 // Scroll message generated by Thinkpad Trackpoint Driver or similar
6246 // Treat as a mousewheel message and scroll appropriately
6247 PRBool quit
, result
;
6250 if (!HandleScrollingPlugins(aMsg
, aWParam
, aLParam
, result
, &retVal
, quit
))
6251 return quit
; // Return if it's not our message or has been dispatched
6253 nsMouseScrollEvent
scrollevent(PR_TRUE
, NS_MOUSE_SCROLL
, this);
6254 scrollevent
.scrollFlags
= (aMsg
== WM_VSCROLL
)
6255 ? nsMouseScrollEvent::kIsVertical
6256 : nsMouseScrollEvent::kIsHorizontal
;
6257 switch (LOWORD(aWParam
))
6260 scrollevent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
6262 scrollevent
.delta
= 1;
6265 scrollevent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
6267 scrollevent
.delta
= -1;
6272 scrollevent
.isShift
= IS_VK_DOWN(NS_VK_SHIFT
);
6273 scrollevent
.isControl
= IS_VK_DOWN(NS_VK_CONTROL
);
6274 scrollevent
.isMeta
= PR_FALSE
;
6275 scrollevent
.isAlt
= IS_VK_DOWN(NS_VK_ALT
);
6276 InitEvent(scrollevent
);
6277 if (nsnull
!= mEventCallback
)
6279 DispatchWindowEvent(&scrollevent
);
6283 // Scroll message generated by external application
6284 // XXX Handle by scrolling the window in the desired manner (Bug 315727)
6288 // Return the brush used to paint the background of this control
6289 HBRUSH
nsWindow::OnControlColor()
6294 // Can be overriden. Controls auto-erase of background.
6295 PRBool
nsWindow::AutoErase(HDC dc
)
6300 /**************************************************************
6301 **************************************************************
6303 ** BLOCK: IME management and accessibility
6305 ** Handles managing IME input and accessibility.
6307 **************************************************************
6308 **************************************************************/
6310 NS_IMETHODIMP
nsWindow::ResetInputState()
6312 #ifdef DEBUG_KBSTATE
6313 printf("ResetInputState\n");
6316 #ifdef NS_ENABLE_TSF
6317 nsTextStore::CommitComposition(PR_FALSE
);
6318 #endif //NS_ENABLE_TSF
6320 nsIMEContext
IMEContext(mWnd
);
6321 if (IMEContext
.IsValid()) {
6322 ::ImmNotifyIME(IMEContext
.get(), NI_COMPOSITIONSTR
, CPS_COMPLETE
, NULL
);
6323 ::ImmNotifyIME(IMEContext
.get(), NI_COMPOSITIONSTR
, CPS_CANCEL
, NULL
);
6328 NS_IMETHODIMP
nsWindow::SetIMEOpenState(PRBool aState
)
6330 #ifdef DEBUG_KBSTATE
6331 printf("SetIMEOpenState %s\n", (aState
? "Open" : "Close"));
6334 #ifdef NS_ENABLE_TSF
6335 nsTextStore::SetIMEOpenState(aState
);
6336 #endif //NS_ENABLE_TSF
6338 nsIMEContext
IMEContext(mWnd
);
6339 if (IMEContext
.IsValid()) {
6340 ::ImmSetOpenStatus(IMEContext
.get(), aState
? TRUE
: FALSE
);
6345 NS_IMETHODIMP
nsWindow::GetIMEOpenState(PRBool
* aState
)
6347 nsIMEContext
IMEContext(mWnd
);
6348 if (IMEContext
.IsValid()) {
6349 BOOL isOpen
= ::ImmGetOpenStatus(IMEContext
.get());
6350 *aState
= isOpen
? PR_TRUE
: PR_FALSE
;
6354 #ifdef NS_ENABLE_TSF
6355 *aState
|= nsTextStore::GetIMEOpenState();
6356 #endif //NS_ENABLE_TSF
6361 NS_IMETHODIMP
nsWindow::SetIMEEnabled(PRUint32 aState
)
6363 #ifdef NS_ENABLE_TSF
6364 nsTextStore::SetIMEEnabled(aState
);
6365 #endif //NS_ENABLE_TSF
6366 #ifdef DEBUG_KBSTATE
6367 printf("SetIMEEnabled: %s\n", (aState
== nsIWidget::IME_STATUS_ENABLED
||
6368 aState
== nsIWidget::IME_STATUS_PLUGIN
)?
6369 "Enabled": "Disabled");
6371 if (nsIMM32Handler::IsComposing(this))
6373 mIMEEnabled
= aState
;
6374 PRBool enable
= (aState
== nsIWidget::IME_STATUS_ENABLED
||
6375 aState
== nsIWidget::IME_STATUS_PLUGIN
);
6377 #if defined(WINCE_HAVE_SOFTKB)
6378 sSoftKeyboardState
= (aState
!= nsIWidget::IME_STATUS_DISABLED
);
6379 nsWindowCE::ToggleSoftKB(mWnd
, sSoftKeyboardState
);
6382 if (!enable
!= !mOldIMC
)
6384 mOldIMC
= ::ImmAssociateContext(mWnd
, enable
? mOldIMC
: NULL
);
6385 NS_ASSERTION(!enable
|| !mOldIMC
, "Another IMC was associated");
6390 NS_IMETHODIMP
nsWindow::GetIMEEnabled(PRUint32
* aState
)
6392 #ifdef DEBUG_KBSTATE
6393 printf("GetIMEEnabled: %s\n", mIMEEnabled
? "Enabled": "Disabled");
6395 *aState
= mIMEEnabled
;
6399 NS_IMETHODIMP
nsWindow::CancelIMEComposition()
6401 #ifdef DEBUG_KBSTATE
6402 printf("CancelIMEComposition\n");
6405 #ifdef NS_ENABLE_TSF
6406 nsTextStore::CommitComposition(PR_TRUE
);
6407 #endif //NS_ENABLE_TSF
6409 nsIMEContext
IMEContext(mWnd
);
6410 if (IMEContext
.IsValid()) {
6411 ::ImmNotifyIME(IMEContext
.get(), NI_COMPOSITIONSTR
, CPS_CANCEL
, NULL
);
6417 nsWindow::GetToggledKeyState(PRUint32 aKeyCode
, PRBool
* aLEDState
)
6419 #ifdef DEBUG_KBSTATE
6420 printf("GetToggledKeyState\n");
6422 NS_ENSURE_ARG_POINTER(aLEDState
);
6423 *aLEDState
= (::GetKeyState(aKeyCode
) & 1) != 0;
6427 #ifdef NS_ENABLE_TSF
6429 nsWindow::OnIMEFocusChange(PRBool aFocus
)
6431 nsresult rv
= nsTextStore::OnFocusChange(aFocus
, this, mIMEEnabled
);
6432 if (rv
== NS_ERROR_NOT_AVAILABLE
)
6433 rv
= NS_ERROR_NOT_IMPLEMENTED
; // TSF is not enabled, maybe.
6438 nsWindow::OnIMETextChange(PRUint32 aStart
,
6442 return nsTextStore::OnTextChange(aStart
, aOldEnd
, aNewEnd
);
6446 nsWindow::OnIMESelectionChange(void)
6448 return nsTextStore::OnSelectionChange();
6450 #endif //NS_ENABLE_TSF
6452 #ifdef ACCESSIBILITY
6453 already_AddRefed
<nsIAccessible
> nsWindow::GetRootAccessible()
6455 nsWindow::sIsAccessibilityOn
= TRUE
;
6457 if (mInDtor
|| mOnDestroyCalled
|| mWindowType
== eWindowType_invisible
) {
6461 nsIAccessible
*rootAccessible
= nsnull
;
6463 // If accessibility is turned on, we create this even before it is requested
6464 // when the window gets focused. We need it to be created early so it can
6465 // generate accessibility events right away
6466 nsWindow
* accessibleWindow
= nsnull
;
6467 if (mContentType
!= eContentTypeInherit
) {
6468 // We're on a MozillaContentWindowClass or MozillaUIWindowClass window.
6469 // Search for the correct visible child window to get an accessible
6470 // document from. Make sure to use an active child window
6471 HWND accessibleWnd
= ::GetTopWindow(mWnd
);
6472 while (accessibleWnd
) {
6473 // Loop through windows and find the first one with accessibility info
6474 accessibleWindow
= GetNSWindowPtr(accessibleWnd
);
6475 if (accessibleWindow
) {
6476 accessibleWindow
->DispatchAccessibleEvent(NS_GETACCESSIBLE
, &rootAccessible
);
6477 if (rootAccessible
) {
6478 break; // Success, one of the child windows was active
6481 accessibleWnd
= ::GetNextWindow(accessibleWnd
, GW_HWNDNEXT
);
6485 DispatchAccessibleEvent(NS_GETACCESSIBLE
, &rootAccessible
);
6487 return rootAccessible
;
6490 STDMETHODIMP_(LRESULT
)
6491 nsWindow::LresultFromObject(REFIID riid
, WPARAM wParam
, LPUNKNOWN pAcc
)
6493 // open the dll dynamically
6495 sAccLib
=::LoadLibraryW(L
"OLEACC.DLL");
6498 if (!sLresultFromObject
)
6499 sLresultFromObject
= (LPFNLRESULTFROMOBJECT
)GetProcAddress(sAccLib
,"LresultFromObject");
6501 if (sLresultFromObject
)
6502 return sLresultFromObject(riid
,wParam
,pAcc
);
6509 /**************************************************************
6510 **************************************************************
6512 ** BLOCK: Transparency
6514 ** Window transparency helpers.
6516 **************************************************************
6517 **************************************************************/
6521 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth
, PRInt32 aNewHeight
, PRBool force
)
6523 if (!force
&& aNewWidth
== mBounds
.width
&& aNewHeight
== mBounds
.height
)
6526 mTransparentSurface
= new gfxWindowsSurface(gfxIntSize(aNewWidth
, aNewHeight
), gfxASurface::ImageFormatARGB32
);
6527 mMemoryDC
= mTransparentSurface
->GetDC();
6530 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode
)
6534 if (aMode
== mTransparencyMode
)
6537 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
6538 nsWindow
* topWindow
= GetNSWindowPtr(hWnd
);
6542 NS_WARNING("Trying to use transparent chrome in an embedded context");
6546 LONG_PTR style
= 0, exStyle
= 0;
6548 case eTransparencyTransparent
:
6549 exStyle
|= WS_EX_LAYERED
;
6550 case eTransparencyOpaque
:
6551 case eTransparencyGlass
:
6552 topWindow
->mTransparencyMode
= aMode
;
6556 style
|= topWindow
->WindowStyle();
6557 exStyle
|= topWindow
->WindowExStyle();
6559 if (aMode
== eTransparencyTransparent
) {
6560 style
&= ~(WS_CAPTION
| WS_THICKFRAME
| WS_SYSMENU
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
);
6561 exStyle
&= ~(WS_EX_DLGMODALFRAME
| WS_EX_WINDOWEDGE
| WS_EX_CLIENTEDGE
| WS_EX_STATICEDGE
);
6564 VERIFY_WINDOW_STYLE(style
);
6565 ::SetWindowLongPtrW(hWnd
, GWL_STYLE
, style
);
6566 ::SetWindowLongPtrW(hWnd
, GWL_EXSTYLE
, exStyle
);
6568 mTransparencyMode
= aMode
;
6570 SetupTranslucentWindowMemoryBitmap(aMode
);
6571 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
6572 MARGINS margins
= { 0, 0, 0, 0 };
6573 DWMNCRENDERINGPOLICY policy
= DWMNCRP_USEWINDOWSTYLE
;
6574 if(eTransparencyGlass
== aMode
) {
6575 margins
.cxLeftWidth
= -1;
6576 policy
= DWMNCRP_ENABLED
;
6578 if(nsUXThemeData::sHaveCompositor
) {
6579 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd
, &margins
);
6580 nsUXThemeData::dwmSetWindowAttributePtr(hWnd
, DWMWA_NCRENDERING_POLICY
, &policy
, sizeof policy
);
6582 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
6583 #endif // #ifndef WINCE
6586 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode
)
6588 if (eTransparencyTransparent
== aMode
) {
6589 ResizeTranslucentWindow(mBounds
.width
, mBounds
.height
, PR_TRUE
);
6591 mTransparentSurface
= nsnull
;
6596 nsresult
nsWindow::UpdateTranslucentWindow()
6599 if (mBounds
.IsEmpty())
6604 BLENDFUNCTION bf
= { AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
6605 SIZE winSize
= { mBounds
.width
, mBounds
.height
};
6606 POINT srcPos
= { 0, 0 };
6607 HWND hWnd
= GetTopLevelHWND(mWnd
, PR_TRUE
);
6609 ::GetWindowRect(hWnd
, &winRect
);
6611 // perform the alpha blend
6612 if (!::UpdateLayeredWindow(hWnd
, NULL
, (POINT
*)&winRect
, &winSize
, mMemoryDC
, &srcPos
, 0, &bf
, ULW_ALPHA
))
6613 return NS_ERROR_FAILURE
;
6621 /**************************************************************
6622 **************************************************************
6624 ** BLOCK: Popup rollup hooks
6626 ** Deals with CaptureRollup on popup windows.
6628 **************************************************************
6629 **************************************************************/
6632 // Schedules a timer for a window, so we can rollup after processing the hook event
6633 void nsWindow::ScheduleHookTimer(HWND aWnd
, UINT aMsgId
)
6635 // In some cases multiple hooks may be scheduled
6636 // so ignore any other requests once one timer is scheduled
6637 if (sHookTimerId
== 0) {
6638 // Remember the window handle and the message ID to be used later
6639 sRollupMsgId
= aMsgId
;
6640 sRollupMsgWnd
= aWnd
;
6641 // Schedule native timer for doing the rollup after
6642 // this event is done being processed
6643 sHookTimerId
= ::SetTimer(NULL
, 0, 0, (TIMERPROC
)HookTimerForPopups
);
6644 NS_ASSERTION(sHookTimerId
, "Timer couldn't be created.");
6648 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6649 int gLastMsgCode
= 0;
6650 extern MSGFEventMsgInfo gMSGFEvents
[];
6653 // Process Menu messages, rollup when popup is clicked.
6654 LRESULT CALLBACK
nsWindow::MozSpecialMsgFilter(int code
, WPARAM wParam
, LPARAM lParam
)
6656 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6658 MSG
* pMsg
= (MSG
*)lParam
;
6661 while (gMSGFEvents
[inx
].mId
!= code
&& gMSGFEvents
[inx
].mStr
!= NULL
) {
6664 if (code
!= gLastMsgCode
) {
6665 if (gMSGFEvents
[inx
].mId
== code
) {
6667 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code
, gMSGFEvents
[inx
].mStr
, pMsg
->hwnd
);
6671 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code
, gMSGFEvents
[inx
].mId
, pMsg
->hwnd
);
6674 gLastMsgCode
= code
;
6676 PrintEvent(pMsg
->message
, FALSE
, FALSE
);
6678 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6680 if (sProcessHook
&& code
== MSGF_MENU
) {
6681 MSG
* pMsg
= (MSG
*)lParam
;
6682 ScheduleHookTimer( pMsg
->hwnd
, pMsg
->message
);
6685 return ::CallNextHookEx(sMsgFilterHook
, code
, wParam
, lParam
);
6688 // Process all mouse messages. Roll up when a click is in a native window
6689 // that doesn't have an nsIWidget.
6690 LRESULT CALLBACK
nsWindow::MozSpecialMouseProc(int code
, WPARAM wParam
, LPARAM lParam
)
6694 case WM_LBUTTONDOWN
:
6695 case WM_RBUTTONDOWN
:
6696 case WM_MBUTTONDOWN
:
6698 case WM_MOUSEHWHEEL
:
6700 MOUSEHOOKSTRUCT
* ms
= (MOUSEHOOKSTRUCT
*)lParam
;
6701 nsIWidget
* mozWin
= (nsIWidget
*)GetNSWindowPtr(ms
->hwnd
);
6703 // If this window is windowed plugin window, the mouse events are not
6705 if (static_cast<nsWindow
*>(mozWin
)->mWindowType
== eWindowType_plugin
)
6706 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
6708 ScheduleHookTimer(ms
->hwnd
, (UINT
)wParam
);
6714 return ::CallNextHookEx(sCallMouseHook
, code
, wParam
, lParam
);
6717 // Process all messages. Roll up when the window is moving, or
6718 // is resizing or when maximized or mininized.
6719 LRESULT CALLBACK
nsWindow::MozSpecialWndProc(int code
, WPARAM wParam
, LPARAM lParam
)
6721 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6723 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
6724 PrintEvent(cwpt
->message
, FALSE
, FALSE
);
6729 CWPSTRUCT
* cwpt
= (CWPSTRUCT
*)lParam
;
6730 if (cwpt
->message
== WM_MOVING
||
6731 cwpt
->message
== WM_SIZING
||
6732 cwpt
->message
== WM_GETMINMAXINFO
) {
6733 ScheduleHookTimer(cwpt
->hwnd
, (UINT
)cwpt
->message
);
6737 return ::CallNextHookEx(sCallProcHook
, code
, wParam
, lParam
);
6740 // Register the special "hooks" for dropdown processing.
6741 void nsWindow::RegisterSpecialDropdownHooks()
6743 NS_ASSERTION(!sMsgFilterHook
, "sMsgFilterHook must be NULL!");
6744 NS_ASSERTION(!sCallProcHook
, "sCallProcHook must be NULL!");
6746 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
6748 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
6750 // Install msg hook for moving the window and resizing
6751 if (!sMsgFilterHook
) {
6752 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
6753 sMsgFilterHook
= SetWindowsHookEx(WH_MSGFILTER
, MozSpecialMsgFilter
, NULL
, GetCurrentThreadId());
6754 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6755 if (!sMsgFilterHook
) {
6756 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
6761 // Install msg hook for menus
6762 if (!sCallProcHook
) {
6763 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
6764 sCallProcHook
= SetWindowsHookEx(WH_CALLWNDPROC
, MozSpecialWndProc
, NULL
, GetCurrentThreadId());
6765 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6766 if (!sCallProcHook
) {
6767 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
6772 // Install msg hook for the mouse
6773 if (!sCallMouseHook
) {
6774 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
6775 sCallMouseHook
= SetWindowsHookEx(WH_MOUSE
, MozSpecialMouseProc
, NULL
, GetCurrentThreadId());
6776 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6777 if (!sCallMouseHook
) {
6778 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
6784 // Unhook special message hooks for dropdowns.
6785 void nsWindow::UnregisterSpecialDropdownHooks()
6787 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
6789 if (sCallProcHook
) {
6790 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
6791 if (!::UnhookWindowsHookEx(sCallProcHook
)) {
6792 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
6794 sCallProcHook
= NULL
;
6797 if (sMsgFilterHook
) {
6798 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
6799 if (!::UnhookWindowsHookEx(sMsgFilterHook
)) {
6800 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
6802 sMsgFilterHook
= NULL
;
6805 if (sCallMouseHook
) {
6806 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
6807 if (!::UnhookWindowsHookEx(sCallMouseHook
)) {
6808 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
6810 sCallMouseHook
= NULL
;
6814 // This timer is designed to only fire one time at most each time a "hook" function
6815 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
6816 // hook, but that hook event or a subsequent event may roll up the dropdown before
6817 // this timer function is executed.
6819 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
6820 // before this function fires.
6821 VOID CALLBACK
nsWindow::HookTimerForPopups(HWND hwnd
, UINT uMsg
, UINT idEvent
, DWORD dwTime
)
6823 if (sHookTimerId
!= 0) {
6824 // if the window is NULL then we need to use the ID to kill the timer
6825 BOOL status
= ::KillTimer(NULL
, sHookTimerId
);
6826 NS_ASSERTION(status
, "Hook Timer was not killed.");
6830 if (sRollupMsgId
!= 0) {
6831 // Note: DealWithPopups does the check to make sure that
6832 // sRollupListener and sRollupWidget are not NULL
6833 LRESULT popupHandlingResult
;
6834 nsAutoRollup autoRollup
;
6835 DealWithPopups(sRollupMsgWnd
, sRollupMsgId
, 0, 0, &popupHandlingResult
);
6837 sRollupMsgWnd
= NULL
;
6842 static PRBool
IsDifferentThreadWindow(HWND aWnd
)
6844 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd
, NULL
);
6848 nsWindow::EventIsInsideWindow(UINT Msg
, nsWindow
* aWindow
)
6853 if (Msg
== WM_ACTIVATEAPP
)
6854 // don't care about activation/deactivation
6857 if (Msg
== WM_ACTIVATE
)
6858 // but on Windows CE we do care about
6859 // activation/deactivation because there doesn't exist
6860 // cancelable Mouse Activation events
6864 ::GetWindowRect(aWindow
->mWnd
, &r
);
6865 DWORD pos
= ::GetMessagePos();
6867 mp
.x
= GET_X_LPARAM(pos
);
6868 mp
.y
= GET_Y_LPARAM(pos
);
6870 // was the event inside this window?
6871 return (PRBool
) PtInRect(&r
, mp
);
6874 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
6876 nsWindow::DealWithPopups(HWND inWnd
, UINT inMsg
, WPARAM inWParam
, LPARAM inLParam
, LRESULT
* outResult
)
6878 if (sRollupListener
&& sRollupWidget
&& ::IsWindowVisible(inWnd
)) {
6880 if (inMsg
== WM_LBUTTONDOWN
|| inMsg
== WM_RBUTTONDOWN
|| inMsg
== WM_MBUTTONDOWN
||
6881 inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
|| inMsg
== WM_ACTIVATE
||
6882 (inMsg
== WM_KILLFOCUS
&& IsDifferentThreadWindow((HWND
)inWParam
))
6885 inMsg
== WM_NCRBUTTONDOWN
||
6886 inMsg
== WM_MOVING
||
6887 inMsg
== WM_SIZING
||
6888 inMsg
== WM_NCLBUTTONDOWN
||
6889 inMsg
== WM_NCMBUTTONDOWN
||
6890 inMsg
== WM_MOUSEACTIVATE
||
6891 inMsg
== WM_ACTIVATEAPP
||
6892 inMsg
== WM_MENUSELECT
6896 // Rollup if the event is outside the popup.
6897 PRBool rollup
= !nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)sRollupWidget
);
6899 if (rollup
&& (inMsg
== WM_MOUSEWHEEL
|| inMsg
== WM_MOUSEHWHEEL
))
6901 sRollupListener
->ShouldRollupOnMouseWheelEvent(&rollup
);
6902 *outResult
= PR_TRUE
;
6905 // If we're dealing with menus, we probably have submenus and we don't
6906 // want to rollup if the click is in a parent menu of the current submenu.
6907 PRUint32 popupsToRollup
= PR_UINT32_MAX
;
6909 if ( sMenuRollup
) {
6910 nsAutoTArray
<nsIWidget
*, 5> widgetChain
;
6911 PRUint32 sameTypeCount
= sMenuRollup
->GetSubmenuWidgetChain(&widgetChain
);
6912 for ( PRUint32 i
= 0; i
< widgetChain
.Length(); ++i
) {
6913 nsIWidget
* widget
= widgetChain
[i
];
6914 if ( nsWindow::EventIsInsideWindow(inMsg
, (nsWindow
*)widget
) ) {
6915 // don't roll up if the mouse event occured within a menu of the
6916 // same type. If the mouse event occured in a menu higher than
6917 // that, roll up, but pass the number of popups to Rollup so
6918 // that only those of the same type close up.
6919 if (i
< sameTypeCount
) {
6923 popupsToRollup
= sameTypeCount
;
6927 } // foreach parent menu widget
6928 } // if rollup listener knows about menus
6932 if (inMsg
== WM_MOUSEACTIVATE
&& popupsToRollup
== PR_UINT32_MAX
) {
6933 // Prevent the click inside the popup from causing a change in window
6934 // activation. Since the popup is shown non-activated, we need to eat
6935 // any requests to activate the window while it is displayed. Windows
6936 // will automatically activate the popup on the mousedown otherwise.
6938 *outResult
= MA_NOACTIVATE
;
6943 UINT uMsg
= HIWORD(inLParam
);
6944 if (uMsg
== WM_MOUSEMOVE
)
6946 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
6947 // must be enabled in Windows.
6948 sRollupListener
->ShouldRollupOnMouseActivate(&rollup
);
6951 *outResult
= MA_NOACTIVATE
;
6957 // if we've still determined that we should still rollup everything, do it.
6961 // sRollupConsumeEvent may be modified by
6962 // nsIRollupListener::Rollup.
6963 PRBool consumeRollupEvent
= sRollupConsumeEvent
;
6964 // only need to deal with the last rollup for left mouse down events.
6965 sRollupListener
->Rollup(popupsToRollup
, inMsg
== WM_LBUTTONDOWN
? &mLastRollup
: nsnull
);
6967 // Tell hook to stop processing messages
6968 sProcessHook
= PR_FALSE
;
6970 sRollupMsgWnd
= NULL
;
6972 // return TRUE tells Windows that the event is consumed,
6973 // false allows the event to be dispatched
6975 // So if we are NOT supposed to be consuming events, let it go through
6976 if (consumeRollupEvent
&& inMsg
!= WM_RBUTTONDOWN
) {
6981 // if we are only rolling up some popups, don't activate and don't let
6982 // the event go through. This prevents clicks menus higher in the
6983 // chain from opening when a context menu is open
6984 if (popupsToRollup
!= PR_UINT32_MAX
&& inMsg
== WM_MOUSEACTIVATE
) {
6985 *outResult
= MA_NOACTIVATEANDEAT
;
6990 } // if event that might trigger a popup to rollup
6991 } // if rollup listeners registered
6996 /**************************************************************
6997 **************************************************************
6999 ** BLOCK: Misc. utility methods and functions.
7003 **************************************************************
7004 **************************************************************/
7006 // nsModifierKeyState used in various character processing.
7007 nsModifierKeyState::nsModifierKeyState()
7009 mIsShiftDown
= IS_VK_DOWN(NS_VK_SHIFT
);
7010 mIsControlDown
= IS_VK_DOWN(NS_VK_CONTROL
);
7011 mIsAltDown
= IS_VK_DOWN(NS_VK_ALT
);
7015 PRInt32
nsWindow::GetWindowsVersion()
7020 static PRInt32 version
= 0;
7021 static PRBool didCheck
= PR_FALSE
;
7026 OSVERSIONINFOEX osInfo
;
7027 osInfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
7028 // This cast is safe and supposed to be here, don't worry
7029 ::GetVersionEx((OSVERSIONINFO
*)&osInfo
);
7030 version
= (osInfo
.dwMajorVersion
& 0xff) << 8 | (osInfo
.dwMinorVersion
& 0xff);
7036 // Note that the result of GetTopLevelWindow method can be different from the
7037 // result of GetTopLevelHWND method. The result can be non-floating window.
7038 // Because our top level window may be contained in another window which is
7039 // not managed by us.
7040 nsWindow
* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup
)
7042 nsWindow
* curWindow
= this;
7045 if (aStopOnDialogOrPopup
) {
7046 switch (curWindow
->mWindowType
) {
7047 case eWindowType_dialog
:
7048 case eWindowType_popup
:
7053 // Retrieve the top level parent or owner window
7054 nsWindow
* parentWindow
= curWindow
->GetParentWindow(PR_TRUE
);
7059 curWindow
= parentWindow
;
7063 // Note that the result of GetTopLevelHWND can be different from the result
7064 // of GetTopLevelWindow method. Because this is checking whether the window
7065 // is top level only in Win32 window system. Therefore, the result window
7066 // may not be managed by us.
7067 HWND
nsWindow::GetTopLevelHWND(HWND aWnd
, PRBool aStopOnDialogOrPopup
)
7076 if (aStopOnDialogOrPopup
) {
7077 DWORD_PTR style
= ::GetWindowLongPtrW(curWnd
, GWL_STYLE
);
7079 VERIFY_WINDOW_STYLE(style
);
7081 if (!(style
& WS_CHILD
)) // first top-level window
7085 upWnd
= ::GetParent(curWnd
); // Parent or owner (if has no parent)
7088 // For dialog windows, we want just the parent, not the owner.
7089 // For other/popup windows, we want to find the first owner/parent
7090 // that's a dialog and/or has an owner.
7091 if (upWnd
&& ::GetWindow(curWnd
, GW_OWNER
) == upWnd
) {
7092 DWORD_PTR style
= ::GetWindowLongPtrW(curWnd
, GWL_STYLE
);
7093 if ((style
& WS_DLGFRAME
) != 0)
7104 static BOOL CALLBACK
gEnumWindowsProc(HWND hwnd
, LPARAM lParam
)
7107 ::GetWindowThreadProcessId(hwnd
, &pid
);
7108 if (pid
== GetCurrentProcessId() && ::IsWindowVisible(hwnd
))
7110 gWindowsVisible
= PR_TRUE
;
7116 PRBool
nsWindow::CanTakeFocus()
7118 gWindowsVisible
= PR_FALSE
;
7119 EnumWindows(gEnumWindowsProc
, 0);
7120 if (!gWindowsVisible
) {
7123 HWND fgWnd
= ::GetForegroundWindow();
7128 GetWindowThreadProcessId(fgWnd
, &pid
);
7129 if (pid
== GetCurrentProcessId()) {
7137 void nsWindow::InitTrackPointHack()
7139 // Init Trackpoint Hack
7143 const WCHAR wstrKeys
[][40] = {L
"Software\\Lenovo\\TrackPoint",
7144 L
"Software\\Lenovo\\UltraNav",
7145 L
"Software\\Alps\\Apoint\\TrackPoint",
7146 L
"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
7147 L
"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
7148 // If anything fails turn the hack off
7149 sTrackPointHack
= false;
7150 nsCOMPtr
<nsIPrefBranch
> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
));
7151 if(NS_SUCCEEDED(rv
) && prefs
) {
7152 prefs
->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue
);
7153 switch (lHackValue
) {
7154 // 0 means hack disabled
7157 // 1 means hack enabled
7159 sTrackPointHack
= true;
7161 // -1 means autodetect
7163 for(int i
= 0; i
< NS_ARRAY_LENGTH(wstrKeys
); i
++) {
7165 lResult
= ::RegOpenKeyExW(HKEY_CURRENT_USER
, (LPCWSTR
)&wstrKeys
[i
],
7166 0, KEY_READ
, &hKey
);
7167 ::RegCloseKey(hKey
);
7168 if(lResult
== ERROR_SUCCESS
) {
7169 // If we detected a registry key belonging to a TrackPoint driver
7171 sTrackPointHack
= true;
7176 // Shouldn't be any other values, but treat them as disabled
7183 #endif // #if !defined(WINCE)
7185 LPARAM
nsWindow::lParamToScreen(LPARAM lParam
)
7188 pt
.x
= GET_X_LPARAM(lParam
);
7189 pt
.y
= GET_Y_LPARAM(lParam
);
7190 ::ClientToScreen(mWnd
, &pt
);
7191 return MAKELPARAM(pt
.x
, pt
.y
);
7194 LPARAM
nsWindow::lParamToClient(LPARAM lParam
)
7197 pt
.x
= GET_X_LPARAM(lParam
);
7198 pt
.y
= GET_Y_LPARAM(lParam
);
7199 ::ScreenToClient(mWnd
, &pt
);
7200 return MAKELPARAM(pt
.x
, pt
.y
);
7203 /**************************************************************
7204 **************************************************************
7206 ** BLOCK: ChildWindow impl.
7208 ** Child window overrides.
7210 **************************************************************
7211 **************************************************************/
7213 // Deal with all sort of mouse event
7214 PRBool
ChildWindow::DispatchMouseEvent(PRUint32 aEventType
, WPARAM wParam
, LPARAM lParam
,
7215 PRBool aIsContextMenuKey
, PRInt16 aButton
)
7217 PRBool result
= PR_FALSE
;
7219 if (nsnull
== mEventCallback
) {
7223 switch (aEventType
) {
7224 case NS_MOUSE_BUTTON_DOWN
:
7225 CaptureMouse(PR_TRUE
);
7228 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
7229 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
7230 case NS_MOUSE_BUTTON_UP
:
7233 if (!(wParam
& (MK_LBUTTON
| MK_MBUTTON
| MK_RBUTTON
)) && mIsInMouseCapture
)
7234 CaptureMouse(PR_FALSE
);
7242 return nsWindow::DispatchMouseEvent(aEventType
, wParam
, lParam
,
7243 aIsContextMenuKey
, aButton
);
7246 // return the style for a child nsWindow
7247 DWORD
ChildWindow::WindowStyle()
7249 DWORD style
= WS_CLIPCHILDREN
| nsWindow::WindowStyle();
7250 if (!(style
& WS_POPUP
))
7251 style
|= WS_CHILD
; // WS_POPUP and WS_CHILD are mutually exclusive.
7252 VERIFY_WINDOW_STYLE(style
);