Bug 499816 - Minimizing Firefox does not release window focus. r=blassey.
[mozilla-central.git] / widget / src / windows / nsWindow.cpp
blob5eb4fc8ab4bd37aaaed74937c5530ffc1b7f96bd
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
14 * License.
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.
23 * Contributor(s):
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:
61 * Includes
62 * Variables
63 * nsIWidget impl.
64 * nsIWidget methods and utilities
65 * nsSwitchToUIThread impl.
66 * nsSwitchToUIThread methods and utilities
67 * Moz events
68 * Event initialization
69 * Event dispatching
70 * Native events
71 * Wndproc(s)
72 * Event processing
73 * OnEvent event handlers
74 * IME management and accessibility
75 * Transparency
76 * Popup hook handling
77 * Misc. utilities
78 * Child window impl.
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.
86 * Related source:
88 * nsWindowDefs.h - Definitions, macros, structs, enums
89 * and general setup.
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 **************************************************************
100 ** BLOCK: Includes
102 ** Include headers.
104 **************************************************************
105 **************************************************************/
107 #include "nsWindow.h"
109 #include <windows.h>
110 #include <process.h>
111 #include <commctrl.h>
112 #include <unknwn.h>
114 #include "prlog.h"
115 #include "prtime.h"
116 #include "prprf.h"
117 #include "prmem.h"
119 #include "nsIAppShell.h"
120 #include "nsISupportsPrimitives.h"
121 #include "nsIDOMNSUIEvent.h"
122 #include "nsITheme.h"
123 #include "nsIPrefBranch.h"
124 #include "nsIPrefService.h"
125 #include "nsIObserverService.h"
126 #include "nsIScreenManager.h"
127 #include "imgIContainer.h"
128 #include "nsIFile.h"
129 #include "nsIRollupListener.h"
130 #include "nsIMenuRollup.h"
131 #include "nsIRegion.h"
132 #include "nsIServiceManager.h"
133 #include "nsIClipboard.h"
134 #include "nsIMM32Handler.h"
135 #include "nsILocalFile.h"
136 #include "nsIFontMetrics.h"
137 #include "nsIFontEnumerator.h"
138 #include "nsIDeviceContext.h"
139 #include "nsIdleService.h"
140 #include "nsGUIEvent.h"
141 #include "nsFont.h"
142 #include "nsRect.h"
143 #include "nsThreadUtils.h"
144 #include "nsNativeCharsetUtils.h"
145 #include "nsWidgetAtoms.h"
146 #include "nsUnicharUtils.h"
147 #include "nsCRT.h"
148 #include "nsAppDirectoryServiceDefs.h"
149 #include "nsXPIDLString.h"
150 #include "nsWidgetsCID.h"
151 #include "nsTHashtable.h"
152 #include "nsHashKeys.h"
153 #include "nsString.h"
155 #if defined(WINCE)
156 #include "nsWindowCE.h"
157 #endif
159 #if defined(WINCE_WINDOWS_MOBILE)
160 #define KILL_PRIORITY_ID 2444
161 #endif
163 #include "nsWindowGfx.h"
165 #if !defined(WINCE)
166 #include "nsUXThemeData.h"
167 #include "nsUXThemeConstants.h"
168 #include "nsKeyboardLayout.h"
169 #include "nsNativeDragTarget.h"
170 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
171 #include <zmouse.h>
172 #include <pbt.h>
173 #include <richedit.h>
174 #endif // !defined(WINCE)
176 #if defined(ACCESSIBILITY)
177 #include "oleidl.h"
178 #include <winuser.h>
179 #if !defined(WINABLEAPI)
180 #include <winable.h>
181 #endif // !defined(WINABLEAPI)
182 #include "nsIAccessible.h"
183 #include "nsIAccessibleDocument.h"
184 #include "nsIAccessNode.h"
185 #endif // defined(ACCESSIBILITY)
187 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
188 #include "nsIWinTaskbar.h"
189 #endif
191 #if defined(NS_ENABLE_TSF)
192 #include "nsTextStore.h"
193 #endif // defined(NS_ENABLE_TSF)
195 #if defined(MOZ_SPLASHSCREEN)
196 #include "nsSplashScreen.h"
197 #endif // defined(MOZ_SPLASHSCREEN)
199 // Windowless plugin support
200 #include "npapi.h"
202 #include "nsWindowDefs.h"
204 #ifdef WINCE_WINDOWS_MOBILE
205 #include "nsGfxCIID.h"
206 #endif
208 // A magic APP message that can be sent to quit, sort of like a QUERYENDSESSION/ENDSESSION,
209 // but without the query.
210 #define MOZ_WM_APP_QUIT (WM_APP+0x0300)
212 /**************************************************************
213 **************************************************************
215 ** BLOCK: Variables
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
244 // messages.
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;
253 // Rollup Listener
254 nsIRollupListener* nsWindow::sRollupListener = nsnull;
255 nsIWidget* nsWindow::sRollupWidget = nsnull;
256 PRBool nsWindow::sRollupConsumeEvent = PR_FALSE;
258 // Mouse Clicks - static variable definitions for figuring
259 // out 1 - 3 Clicks.
260 POINT nsWindow::sLastMousePoint = {0};
261 POINT nsWindow::sLastMouseMovePoint = {0};
262 LONG nsWindow::sLastMouseDownTime = 0L;
263 LONG nsWindow::sLastClickCount = 0L;
264 BYTE nsWindow::sLastMouseButton = 0;
266 // Trim heap on minimize. (initialized, but still true.)
267 int nsWindow::sTrimOnMinimize = 2;
269 // Default Trackpoint Hack to off
270 PRBool nsWindow::sTrackPointHack = PR_FALSE;
272 #ifdef ACCESSIBILITY
273 BOOL nsWindow::sIsAccessibilityOn = FALSE;
274 // Accessibility wm_getobject handler
275 HINSTANCE nsWindow::sAccLib = 0;
276 LPFNLRESULTFROMOBJECT
277 nsWindow::sLresultFromObject = 0;
278 #endif // ACCESSIBILITY
280 /**************************************************************
282 * SECTION: globals variables
284 **************************************************************/
286 static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
288 #ifdef PR_LOGGING
289 PRLogModuleInfo* gWindowsLog = nsnull;
290 #endif
292 #ifndef WINCE
293 // Kbd layout. Used throughout character processing.
294 static KeyboardLayout gKbdLayout;
295 #endif
297 #ifdef WINCE_WINDOWS_MOBILE
298 // HTC Navigation Wheel Event
299 // This is the defined value for Gesture Mode
300 const int WM_HTCNAV = 0x0400 + 200;
302 typedef int (__stdcall * HTCApiNavOpen)(HANDLE, int);
303 typedef int (__stdcall * HTCApiNavSetMode)(HANDLE, unsigned int);
305 HTCApiNavOpen gHTCApiNavOpen = nsnull;
306 HTCApiNavSetMode gHTCApiNavSetMode = nsnull;
307 static PRBool gCheckForHTCApi = PR_FALSE;
308 #endif
310 // The last user input event time in microseconds. If
311 // there are any pending native toolkit input events
312 // it returns the current time. The value is compatible
313 // with PR_IntervalToMicroseconds(PR_IntervalNow()).
314 #if !defined(WINCE)
315 static PRUint32 gLastInputEventTime = 0;
316 #else
317 PRUint32 gLastInputEventTime = 0;
318 #endif
320 static void UpdateLastInputEventTime() {
321 gLastInputEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
322 nsCOMPtr<nsIIdleService> idleService = do_GetService("@mozilla.org/widget/idleservice;1");
323 nsIdleService* is = static_cast<nsIdleService*>(idleService.get());
324 if (is)
325 is->IdleTimeWasModified();
329 // Global user preference for disabling native theme. Used
330 // in NativeWindowTheme.
331 PRBool gDisableNativeTheme = PR_FALSE;
333 // Global used in Show window enumerations.
334 static PRBool gWindowsVisible = PR_FALSE;
336 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
337 #ifdef WINCE_WINDOWS_MOBILE
338 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
339 #endif
341 /**************************************************************
342 **************************************************************
344 ** BLOCK: nsIWidget impl.
346 ** nsIWidget interface implementation, broken down into
347 ** sections.
349 **************************************************************
350 **************************************************************/
352 /**************************************************************
354 * SECTION: nsWindow construction and destruction
356 **************************************************************/
358 nsWindow::nsWindow() : nsBaseWidget()
360 #ifdef PR_LOGGING
361 if (!gWindowsLog)
362 gWindowsLog = PR_NewLogModule("nsWindowsWidgets");
363 #endif
365 mWnd = nsnull;
366 mPaintDC = nsnull;
367 mPrevWndProc = nsnull;
368 mOldIMC = nsnull;
369 mNativeDragTarget = nsnull;
370 mInDtor = PR_FALSE;
371 mIsVisible = PR_FALSE;
372 mHas3DBorder = PR_FALSE;
373 mIsInMouseCapture = PR_FALSE;
374 mIsTopWidgetWindow = PR_FALSE;
375 mInScrollProcessing = PR_FALSE;
376 mUnicodeWidget = PR_TRUE;
377 mWindowType = eWindowType_child;
378 mBorderStyle = eBorderStyle_default;
379 mPopupType = ePopupTypeAny;
380 mDisplayPanFeedback = PR_FALSE;
381 mLastPoint.x = 0;
382 mLastPoint.y = 0;
383 mLastSize.width = 0;
384 mLastSize.height = 0;
385 mOldStyle = 0;
386 mOldExStyle = 0;
387 mPainting = 0;
388 mLastKeyboardLayout = 0;
389 mBlurSuppressLevel = 0;
390 mIMEEnabled = nsIWidget::IME_STATUS_ENABLED;
391 mLeadByte = '\0';
392 #ifdef MOZ_XUL
393 mTransparentSurface = nsnull;
394 mMemoryDC = nsnull;
395 mTransparencyMode = eTransparencyOpaque;
396 #endif
397 mBackground = ::GetSysColor(COLOR_BTNFACE);
398 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
399 mForeground = ::GetSysColor(COLOR_WINDOWTEXT);
401 #ifdef WINCE_WINDOWS_MOBILE
402 mInvalidatedRegion = do_CreateInstance(kRegionCID);
403 mInvalidatedRegion->Init();
404 #endif
406 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
407 mTaskbarPreview = nsnull;
408 mHasTaskbarIconBeenCreated = PR_FALSE;
409 #endif
411 // Global initialization
412 if (!sInstanceCount) {
413 #if !defined(WINCE)
414 gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
415 #endif
417 // Init IME handler
418 nsIMM32Handler::Initialize();
420 #ifdef NS_ENABLE_TSF
421 nsTextStore::Initialize();
422 #endif
424 #if !defined(WINCE)
425 if (SUCCEEDED(::OleInitialize(NULL)))
426 sIsOleInitialized = TRUE;
427 NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
428 #endif
430 #if defined(HEAP_DUMP_EVENT)
431 InitHeapDump();
432 #endif
434 #if !defined(WINCE)
435 InitTrackPointHack();
436 #endif
437 } // !sInstanceCount
439 // Set gLastInputEventTime to some valid number
440 gLastInputEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
442 sInstanceCount++;
445 nsWindow::~nsWindow()
447 mInDtor = PR_TRUE;
449 // If the widget was released without calling Destroy() then the native window still
450 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
452 // XXX How could this happen???
453 if (NULL != mWnd)
454 Destroy();
456 sInstanceCount--;
458 // Global shutdown
459 if (sInstanceCount == 0) {
460 #ifdef NS_ENABLE_TSF
461 nsTextStore::Terminate();
462 #endif
464 #if !defined(WINCE)
465 NS_IF_RELEASE(sCursorImgContainer);
466 if (sIsOleInitialized) {
467 ::OleFlushClipboard();
468 ::OleUninitialize();
469 sIsOleInitialized = FALSE;
471 // delete any of the IME structures that we allocated
472 nsIMM32Handler::Terminate();
473 #endif // !defined(WINCE)
476 #if !defined(WINCE)
477 NS_IF_RELEASE(mNativeDragTarget);
478 #endif // !defined(WINCE)
481 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
483 /**************************************************************
485 * SECTION: nsIWidget::Create, nsIWidget::Destroy
487 * Creating and destroying windows for this widget.
489 **************************************************************/
491 // Allow Derived classes to modify the height that is passed
492 // when the window is created or resized. Also add extra height
493 // if needed (on Windows CE)
494 PRInt32 nsWindow::GetHeight(PRInt32 aProposedHeight)
496 PRInt32 extra = 0;
498 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
499 DWORD style = WindowStyle();
500 if ((style & WS_SYSMENU) && (style & WS_POPUP)) {
501 extra = GetSystemMetrics(SM_CYCAPTION);
503 #endif
505 return aProposedHeight + extra;
508 // Create the proper widget
509 nsresult
510 nsWindow::Create(nsIWidget *aParent,
511 nsNativeWidget aNativeParent,
512 const nsIntRect &aRect,
513 EVENT_CALLBACK aHandleEventFunction,
514 nsIDeviceContext *aContext,
515 nsIAppShell *aAppShell,
516 nsIToolkit *aToolkit,
517 nsWidgetInitData *aInitData)
519 if (aInitData)
520 mUnicodeWidget = aInitData->mUnicode;
522 nsIWidget *baseParent = aInitData &&
523 (aInitData->mWindowType == eWindowType_dialog ||
524 aInitData->mWindowType == eWindowType_toplevel ||
525 aInitData->mWindowType == eWindowType_invisible) ?
526 nsnull : aParent;
528 mIsTopWidgetWindow = (nsnull == baseParent);
529 mBounds.width = aRect.width;
530 mBounds.height = aRect.height;
532 BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
533 aAppShell, aToolkit, aInitData);
535 HWND parent;
536 if (nsnull != aParent) { // has a nsIWidget parent
537 parent = ((aParent) ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : nsnull);
538 } else { // has a nsNative parent
539 parent = (HWND)aNativeParent;
542 if (nsnull != aInitData) {
543 mPopupType = aInitData->mPopupHint;
546 mContentType = aInitData ? aInitData->mContentType : eContentTypeInherit;
548 DWORD style = WindowStyle();
549 DWORD extendedStyle = WindowExStyle();
551 if (mWindowType == eWindowType_popup) {
552 // if a parent was specified, don't use WS_EX_TOPMOST so that the popup
553 // only appears above the parent, instead of all windows
554 if (aParent)
555 extendedStyle = WS_EX_TOOLWINDOW;
556 else
557 parent = NULL;
558 } else if (mWindowType == eWindowType_invisible) {
559 // Make sure CreateWindowEx succeeds at creating a toplevel window
560 style &= ~0x40000000; // WS_CHILDWINDOW
561 } else if (nsnull != aInitData) {
562 // See if the caller wants to explictly set clip children and clip siblings
563 if (aInitData->clipChildren) {
564 style |= WS_CLIPCHILDREN;
565 } else {
566 style &= ~WS_CLIPCHILDREN;
568 if (aInitData->clipSiblings) {
569 style |= WS_CLIPSIBLINGS;
573 mHas3DBorder = (extendedStyle & WS_EX_CLIENTEDGE) > 0;
575 mWnd = ::CreateWindowExW(extendedStyle,
576 aInitData && aInitData->mDropShadow ?
577 WindowPopupClass() : WindowClass(),
578 L"",
579 style,
580 aRect.x,
581 aRect.y,
582 aRect.width,
583 GetHeight(aRect.height),
584 parent,
585 NULL,
586 nsToolkit::mDllInstance,
587 NULL);
589 if (!mWnd)
590 return NS_ERROR_FAILURE;
592 if (nsWindow::sTrackPointHack &&
593 mWindowType != eWindowType_plugin &&
594 mWindowType != eWindowType_invisible) {
595 // Ugly Thinkpad Driver Hack (Bug 507222)
596 // We create an invisible scrollbar to trick the
597 // Trackpoint driver into sending us scrolling messages
598 ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTSCROLLBAR",
599 WS_CHILD | WS_VISIBLE, 0,0,0,0, mWnd, NULL,
600 nsToolkit::mDllInstance, NULL);
603 // call the event callback to notify about creation
605 DispatchStandardEvent(NS_CREATE);
606 SubclassWindow(TRUE);
608 if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
609 /* The internal variable set by the config.trim_on_minimize pref
610 has not yet been initialized, and this is the hidden window
611 (conveniently created before any visible windows, and after
612 the profile has been initialized).
614 Default config.trim_on_minimize to false, to fix bug 76831
615 for good. If anyone complains about this new default, saying
616 that a Mozilla app hogs too much memory while minimized, they
617 will have that entire bug tattooed on their backside. */
619 sTrimOnMinimize = 0;
620 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
621 if (prefs) {
622 nsCOMPtr<nsIPrefBranch> prefBranch;
623 prefs->GetBranch(0, getter_AddRefs(prefBranch));
624 if (prefBranch) {
626 PRBool temp;
627 if (NS_SUCCEEDED(prefBranch->GetBoolPref("config.trim_on_minimize",
628 &temp))
629 && temp)
630 sTrimOnMinimize = 1;
632 if (NS_SUCCEEDED(prefBranch->GetBoolPref("intl.keyboard.per_window_layout",
633 &temp)))
634 sSwitchKeyboardLayout = temp;
636 if (NS_SUCCEEDED(prefBranch->GetBoolPref("mozilla.widget.disable-native-theme",
637 &temp)))
638 gDisableNativeTheme = temp;
642 #if defined(WINCE_HAVE_SOFTKB)
643 if (mWindowType == eWindowType_dialog || mWindowType == eWindowType_toplevel )
644 nsWindowCE::CreateSoftKeyMenuBar(mWnd);
645 #endif
647 return NS_OK;
650 // Close this nsWindow
651 NS_METHOD nsWindow::Destroy()
653 // WM_DESTROY has already fired, we're done.
654 if (nsnull == mWnd)
655 return NS_OK;
657 // During the destruction of all of our children, make sure we don't get deleted.
658 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
660 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
661 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
662 // from it. The function also destroys the window's menu, flushes the thread message queue,
663 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
664 // the window is at the top of the viewer chain).
666 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
667 // the associated child or owned windows when it destroys the parent or owner window. The
668 // function first destroys child or owned windows, and then it destroys the parent or owner
669 // window.
670 VERIFY(::DestroyWindow(mWnd));
672 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
673 // didn't get called, call it now.
674 if (PR_FALSE == mOnDestroyCalled)
675 OnDestroy();
677 return NS_OK;
680 /**************************************************************
682 * SECTION: Window class utilities
684 * Utilities for calculating the proper window class name for
685 * Create window.
687 **************************************************************/
689 // Return the proper window class for everything except popups.
690 LPCWSTR nsWindow::WindowClass()
692 if (!nsWindow::sIsRegistered) {
693 WNDCLASSW wc;
695 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
696 wc.style = CS_DBLCLKS;
697 wc.lpfnWndProc = ::DefWindowProcW;
698 wc.cbClsExtra = 0;
699 wc.cbWndExtra = 0;
700 wc.hInstance = nsToolkit::mDllInstance;
701 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
702 wc.hCursor = NULL;
703 wc.hbrBackground = mBrush;
704 wc.lpszMenuName = NULL;
705 wc.lpszClassName = kClassNameHidden;
707 BOOL succeeded = ::RegisterClassW(&wc) != 0 &&
708 ERROR_CLASS_ALREADY_EXISTS != GetLastError();
709 nsWindow::sIsRegistered = succeeded;
711 wc.lpszClassName = kClassNameContentFrame;
712 if (!::RegisterClassW(&wc) &&
713 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
714 nsWindow::sIsRegistered = FALSE;
717 wc.lpszClassName = kClassNameContent;
718 if (!::RegisterClassW(&wc) &&
719 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
720 nsWindow::sIsRegistered = FALSE;
723 wc.lpszClassName = kClassNameUI;
724 if (!::RegisterClassW(&wc) &&
725 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
726 nsWindow::sIsRegistered = FALSE;
729 wc.lpszClassName = kClassNameGeneral;
730 ATOM generalClassAtom = ::RegisterClassW(&wc);
731 if (!generalClassAtom &&
732 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
733 nsWindow::sIsRegistered = FALSE;
736 wc.lpszClassName = kClassNameDialog;
737 wc.hIcon = 0;
738 if (!::RegisterClassW(&wc) &&
739 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
740 nsWindow::sIsRegistered = FALSE;
744 if (mWindowType == eWindowType_invisible) {
745 return kClassNameHidden;
747 if (mWindowType == eWindowType_dialog) {
748 return kClassNameDialog;
750 if (mContentType == eContentTypeContent) {
751 return kClassNameContent;
753 if (mContentType == eContentTypeContentFrame) {
754 return kClassNameContentFrame;
756 if (mContentType == eContentTypeUI) {
757 return kClassNameUI;
759 return kClassNameGeneral;
762 // Return the proper popup window class
763 LPCWSTR nsWindow::WindowPopupClass()
765 if (!nsWindow::sIsPopupClassRegistered) {
766 WNDCLASSW wc;
768 wc.style = CS_DBLCLKS | CS_XP_DROPSHADOW;
769 wc.lpfnWndProc = ::DefWindowProcW;
770 wc.cbClsExtra = 0;
771 wc.cbWndExtra = 0;
772 wc.hInstance = nsToolkit::mDllInstance;
773 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
774 wc.hCursor = NULL;
775 wc.hbrBackground = mBrush;
776 wc.lpszMenuName = NULL;
777 wc.lpszClassName = kClassNameDropShadow;
779 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
780 if (!nsWindow::sIsPopupClassRegistered) {
781 // For older versions of Win32 (i.e., not XP), the registration will
782 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
783 wc.style = CS_DBLCLKS;
784 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
788 return kClassNameDropShadow;
791 /**************************************************************
793 * SECTION: Window styles utilities
795 * Return the proper windows styles and extended styles.
797 **************************************************************/
799 // Return nsWindow styles
800 #if !defined(WINCE) // implemented in nsWindowCE.cpp
801 DWORD nsWindow::WindowStyle()
803 DWORD style;
805 switch (mWindowType) {
806 case eWindowType_plugin:
807 case eWindowType_child:
808 style = WS_OVERLAPPED;
809 break;
811 case eWindowType_dialog:
812 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK | DS_MODALFRAME;
813 if (mBorderStyle != eBorderStyle_default)
814 style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
815 break;
817 case eWindowType_popup:
818 style = WS_POPUP;
819 if (mTransparencyMode != eTransparencyGlass) {
820 style |= WS_OVERLAPPED;
822 break;
824 default:
825 NS_ERROR("unknown border style");
826 // fall through
828 case eWindowType_toplevel:
829 case eWindowType_invisible:
830 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU |
831 WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
832 break;
835 if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) {
836 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border))
837 style &= ~WS_BORDER;
839 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) {
840 style &= ~WS_DLGFRAME;
841 style |= WS_POPUP;
842 style &= ~WS_CHILD;
845 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close))
846 style &= ~0;
847 // XXX The close box can only be removed by changing the window class,
848 // as far as I know --- roc+moz@cs.cmu.edu
850 if (mBorderStyle == eBorderStyle_none ||
851 !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
852 style &= ~WS_SYSMENU;
853 // Looks like getting rid of the system menu also does away with the
854 // close box. So, we only get rid of the system menu if you want neither it
855 // nor the close box. How does the Windows "Dialog" window class get just
856 // closebox and no sysmenu? Who knows.
858 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh))
859 style &= ~WS_THICKFRAME;
861 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize))
862 style &= ~WS_MINIMIZEBOX;
864 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize))
865 style &= ~WS_MAXIMIZEBOX;
867 VERIFY_WINDOW_STYLE(style);
868 return style;
870 #endif // !defined(WINCE)
872 // Return nsWindow extended styles
873 DWORD nsWindow::WindowExStyle()
875 switch (mWindowType)
877 case eWindowType_plugin:
878 case eWindowType_child:
879 return 0;
881 case eWindowType_dialog:
882 return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
884 case eWindowType_popup:
885 return
886 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
887 WS_EX_NOACTIVATE |
888 #endif
889 WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
891 default:
892 NS_ERROR("unknown border style");
893 // fall through
895 case eWindowType_toplevel:
896 case eWindowType_invisible:
897 return WS_EX_WINDOWEDGE;
901 /**************************************************************
903 * SECTION: Window subclassing utilities
905 * Set or clear window subclasses on native windows. Used in
906 * Create and Destroy.
908 **************************************************************/
910 // Subclass (or remove the subclass from) this component's nsWindow
911 void nsWindow::SubclassWindow(BOOL bState)
913 if (NULL != mWnd) {
914 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
915 if (!::IsWindow(mWnd)) {
916 NS_ERROR("Invalid window handle");
919 if (bState) {
920 // change the nsWindow proc
921 if (mUnicodeWidget)
922 mPrevWndProc = (WNDPROC)::SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
923 (LONG_PTR)nsWindow::WindowProc);
924 else
925 mPrevWndProc = (WNDPROC)::SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
926 (LONG_PTR)nsWindow::WindowProc);
927 NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
928 // connect the this pointer to the nsWindow handle
929 SetNSWindowPtr(mWnd, this);
931 else {
932 if (mUnicodeWidget)
933 ::SetWindowLongPtrW(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
934 else
935 ::SetWindowLongPtrA(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
936 SetNSWindowPtr(mWnd, NULL);
937 mPrevWndProc = NULL;
942 /**************************************************************
944 * SECTION: Window properties
946 * Set and clear native window properties.
948 **************************************************************/
950 static PRUnichar sPropName[40] = L"";
951 static PRUnichar* GetNSWindowPropName()
953 if (!*sPropName)
955 _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p", GetCurrentProcessId());
956 sPropName[39] = '\0';
958 return sPropName;
961 nsWindow * nsWindow::GetNSWindowPtr(HWND aWnd)
963 return (nsWindow *) ::GetPropW(aWnd, GetNSWindowPropName());
966 BOOL nsWindow::SetNSWindowPtr(HWND aWnd, nsWindow * ptr)
968 if (ptr == NULL) {
969 ::RemovePropW(aWnd, GetNSWindowPropName());
970 return TRUE;
971 } else {
972 return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)ptr);
976 /**************************************************************
978 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
980 * Set or clear the parent widgets using window properties, and
981 * handles calculating native parent handles.
983 **************************************************************/
985 // Get and set parent widgets
986 NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent)
988 if (aNewParent) {
989 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
991 nsIWidget* parent = GetParent();
992 if (parent) {
993 parent->RemoveChild(this);
996 HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
997 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
998 if (newParent && mWnd) {
999 ::SetParent(mWnd, newParent);
1002 aNewParent->AddChild(this);
1004 return NS_OK;
1007 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1009 nsIWidget* parent = GetParent();
1011 if (parent) {
1012 parent->RemoveChild(this);
1015 if (mWnd) {
1016 // If we have no parent, SetParent should return the desktop.
1017 VERIFY(::SetParent(mWnd, nsnull));
1020 return NS_OK;
1023 nsIWidget* nsWindow::GetParent(void)
1025 return GetParentWindow(PR_FALSE);
1028 nsWindow* nsWindow::GetParentWindow(PRBool aIncludeOwner)
1030 if (mIsTopWidgetWindow) {
1031 // Must use a flag instead of mWindowType to tell if the window is the
1032 // owned by the topmost widget, because a child window can be embedded inside
1033 // a HWND which is not associated with a nsIWidget.
1034 return nsnull;
1037 // If this widget has already been destroyed, pretend we have no parent.
1038 // This corresponds to code in Destroy which removes the destroyed
1039 // widget from its parent's child list.
1040 if (mInDtor || mOnDestroyCalled)
1041 return nsnull;
1044 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1045 // root owner. aIncludeOwner set to false implies the search will stop at the
1046 // true parent (default).
1047 nsWindow* widget = nsnull;
1048 if (mWnd) {
1049 #ifdef WINCE
1050 HWND parent = ::GetParent(mWnd);
1051 #else
1052 HWND parent = nsnull;
1053 if (aIncludeOwner)
1054 parent = ::GetParent(mWnd);
1055 else
1056 parent = ::GetAncestor(mWnd, GA_PARENT);
1057 #endif
1058 if (parent) {
1059 widget = GetNSWindowPtr(parent);
1060 if (widget) {
1061 // If the widget is in the process of being destroyed then
1062 // do NOT return it
1063 if (widget->mInDtor) {
1064 widget = nsnull;
1070 return widget;
1073 /**************************************************************
1075 * SECTION: nsIWidget::Show
1077 * Hide or show this component.
1079 **************************************************************/
1081 NS_METHOD nsWindow::Show(PRBool bState)
1083 #if defined(MOZ_SPLASHSCREEN)
1084 // we're about to show the first toplevel window,
1085 // so kill off any splash screen if we had one
1086 nsSplashScreen *splash = nsSplashScreen::Get();
1087 if (splash && splash->IsOpen() && mWnd && bState &&
1088 (mWindowType == eWindowType_toplevel ||
1089 mWindowType == eWindowType_dialog ||
1090 mWindowType == eWindowType_popup))
1092 splash->Close();
1094 #endif
1096 PRBool wasVisible = mIsVisible;
1097 // Set the status now so that anyone asking during ShowWindow or
1098 // SetWindowPos would get the correct answer.
1099 mIsVisible = bState;
1101 if (mWnd) {
1102 if (bState) {
1103 if (!wasVisible && mWindowType == eWindowType_toplevel) {
1104 switch (mSizeMode) {
1105 #ifdef WINCE
1106 case nsSizeMode_Fullscreen:
1107 ::SetForegroundWindow(mWnd);
1108 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1109 MakeFullScreen(TRUE);
1110 break;
1112 case nsSizeMode_Maximized :
1113 ::SetForegroundWindow(mWnd);
1114 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1115 break;
1116 // use default for nsSizeMode_Minimized on Windows CE
1117 #else
1118 case nsSizeMode_Fullscreen:
1119 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1120 break;
1122 case nsSizeMode_Maximized :
1123 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1124 break;
1125 case nsSizeMode_Minimized :
1126 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
1127 break;
1128 #endif
1129 default:
1130 if (CanTakeFocus()) {
1131 #ifdef WINCE
1132 ::SetForegroundWindow(mWnd);
1133 #endif
1134 ::ShowWindow(mWnd, SW_SHOWNORMAL);
1135 } else {
1136 // Place the window behind the foreground window
1137 // (as long as it is not topmost)
1138 HWND wndAfter = ::GetForegroundWindow();
1139 if (!wndAfter)
1140 wndAfter = HWND_BOTTOM;
1141 else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)
1142 wndAfter = HWND_TOP;
1143 ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE |
1144 SWP_NOMOVE | SWP_NOACTIVATE);
1145 GetAttention(2);
1147 break;
1149 } else {
1150 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
1151 if (wasVisible)
1152 flags |= SWP_NOZORDER;
1154 if (mWindowType == eWindowType_popup) {
1155 #ifndef WINCE
1156 // ensure popups are the topmost of the TOPMOST
1157 // layer. Remember not to set the SWP_NOZORDER
1158 // flag as that might allow the taskbar to overlap
1159 // the popup. However on windows ce, we need to
1160 // activate the popup or clicks will not be sent.
1161 flags |= SWP_NOACTIVATE;
1162 #endif
1163 HWND owner = ::GetWindow(mWnd, GW_OWNER);
1164 ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
1165 } else {
1166 #ifndef WINCE
1167 if (mWindowType == eWindowType_dialog && !CanTakeFocus())
1168 flags |= SWP_NOACTIVATE;
1169 #endif
1170 ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
1173 } else {
1174 if (mWindowType != eWindowType_dialog) {
1175 ::ShowWindow(mWnd, SW_HIDE);
1176 } else {
1177 ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1178 SWP_NOZORDER | SWP_NOACTIVATE);
1183 #ifdef MOZ_XUL
1184 if (!wasVisible && bState)
1185 Invalidate(PR_FALSE);
1186 #endif
1188 return NS_OK;
1191 /**************************************************************
1193 * SECTION: nsIWidget::IsVisible
1195 * Returns the visibility state.
1197 **************************************************************/
1199 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1200 NS_METHOD nsWindow::IsVisible(PRBool & bState)
1202 bState = mIsVisible;
1203 return NS_OK;
1206 /**************************************************************
1208 * SECTION: Window clipping utilities
1210 * Used in Size and Move operations for setting the proper
1211 * window clipping regions for window transparency.
1213 **************************************************************/
1215 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1216 // transparency. These routines are called on size and move operations.
1217 void nsWindow::ClearThemeRegion()
1219 #ifndef WINCE
1220 if (nsUXThemeData::sIsVistaOrLater && mTransparencyMode != eTransparencyGlass &&
1221 mWindowType == eWindowType_popup && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel)) {
1222 SetWindowRgn(mWnd, NULL, false);
1224 #endif
1227 void nsWindow::SetThemeRegion()
1229 #ifndef WINCE
1230 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1231 // for other window types as needed. The regions are applied generically to the base window
1232 // so default constants are used for part and state. At some point we might need part and
1233 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1234 // change shape based on state haven't come up.
1235 if (nsUXThemeData::sIsVistaOrLater && mTransparencyMode != eTransparencyGlass &&
1236 mWindowType == eWindowType_popup && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel)) {
1237 HRGN hRgn = nsnull;
1238 RECT rect = {0,0,mBounds.width,mBounds.height};
1240 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), GetDC(mWnd), TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
1241 if (hRgn) {
1242 if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted.
1243 DeleteObject(hRgn);
1246 #endif
1249 /**************************************************************
1251 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1252 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1254 * Repositioning and sizing a window.
1256 **************************************************************/
1258 // Move this component
1259 NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
1261 if (mWindowType == eWindowType_toplevel ||
1262 mWindowType == eWindowType_dialog) {
1263 SetSizeMode(nsSizeMode_Normal);
1265 // Check to see if window needs to be moved first
1266 // to avoid a costly call to SetWindowPos. This check
1267 // can not be moved to the calling code in nsView, because
1268 // some platforms do not position child windows correctly
1270 // Only perform this check for non-popup windows, since the positioning can
1271 // in fact change even when the x/y do not. We always need to perform the
1272 // check. See bug #97805 for details.
1273 if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
1275 // Nothing to do, since it is already positioned correctly.
1276 return NS_OK;
1279 mBounds.x = aX;
1280 mBounds.y = aY;
1282 if (mWnd) {
1283 #ifdef DEBUG
1284 // complain if a window is moved offscreen (legal, but potentially worrisome)
1285 if (mIsTopWidgetWindow) { // only a problem for top-level windows
1286 // Make sure this window is actually on the screen before we move it
1287 // XXX: Needs multiple monitor support
1288 HDC dc = ::GetDC(mWnd);
1289 if (dc) {
1290 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1291 RECT workArea;
1292 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1293 // no annoying assertions. just mention the issue.
1294 if (aX < 0 || aX >= workArea.right || aY < 0 || aY >= workArea.bottom)
1295 printf("window moved to offscreen position\n");
1297 ::ReleaseDC(mWnd, dc);
1300 #endif
1301 ClearThemeRegion();
1302 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0,
1303 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE));
1304 SetThemeRegion();
1306 return NS_OK;
1309 // Resize this component
1310 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1312 NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
1313 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1315 #ifdef MOZ_XUL
1316 if (eTransparencyTransparent == mTransparencyMode)
1317 ResizeTranslucentWindow(aWidth, aHeight);
1318 #endif
1320 // Set cached value for lightweight and printing
1321 mBounds.width = aWidth;
1322 mBounds.height = aHeight;
1324 if (mWnd) {
1325 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
1327 #ifndef WINCE
1328 if (!aRepaint) {
1329 flags |= SWP_NOREDRAW;
1331 #endif
1333 ClearThemeRegion();
1334 VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
1335 SetThemeRegion();
1338 if (aRepaint)
1339 Invalidate(PR_FALSE);
1341 return NS_OK;
1344 // Resize this component
1345 NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1347 NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize");
1348 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1350 #ifdef MOZ_XUL
1351 if (eTransparencyTransparent == mTransparencyMode)
1352 ResizeTranslucentWindow(aWidth, aHeight);
1353 #endif
1355 // Set cached value for lightweight and printing
1356 mBounds.x = aX;
1357 mBounds.y = aY;
1358 mBounds.width = aWidth;
1359 mBounds.height = aHeight;
1361 if (mWnd) {
1362 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
1363 #ifndef WINCE
1364 if (!aRepaint) {
1365 flags |= SWP_NOREDRAW;
1367 #endif
1369 ClearThemeRegion();
1370 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
1371 SetThemeRegion();
1374 if (aRepaint)
1375 Invalidate(PR_FALSE);
1377 return NS_OK;
1380 #if !defined(WINCE)
1381 NS_IMETHODIMP
1382 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
1384 NS_ENSURE_ARG_POINTER(aEvent);
1386 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
1387 // you can only begin a resize drag with a mouse event
1388 return NS_ERROR_INVALID_ARG;
1391 nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
1392 if (mouseEvent->button != nsMouseEvent::eLeftButton) {
1393 // you can only begin a resize drag with the left mouse button
1394 return NS_ERROR_INVALID_ARG;
1397 // work out what sizemode we're talking about
1398 WPARAM syscommand;
1399 if (aVertical < 0) {
1400 if (aHorizontal < 0) {
1401 syscommand = SC_SIZE | WMSZ_TOPLEFT;
1402 } else if (aHorizontal == 0) {
1403 syscommand = SC_SIZE | WMSZ_TOP;
1404 } else {
1405 syscommand = SC_SIZE | WMSZ_TOPRIGHT;
1407 } else if (aVertical == 0) {
1408 if (aHorizontal < 0) {
1409 syscommand = SC_SIZE | WMSZ_LEFT;
1410 } else if (aHorizontal == 0) {
1411 return NS_ERROR_INVALID_ARG;
1412 } else {
1413 syscommand = SC_SIZE | WMSZ_RIGHT;
1415 } else {
1416 if (aHorizontal < 0) {
1417 syscommand = SC_SIZE | WMSZ_BOTTOMLEFT;
1418 } else if (aHorizontal == 0) {
1419 syscommand = SC_SIZE | WMSZ_BOTTOM;
1420 } else {
1421 syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT;
1425 // resizing doesn't work if the mouse is already captured
1426 CaptureMouse(PR_FALSE);
1428 // find the top-level window
1429 HWND toplevelWnd = GetTopLevelHWND(mWnd, PR_TRUE);
1431 // tell Windows to start the resize
1432 ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand,
1433 POINTTOPOINTS(aEvent->refPoint));
1435 return NS_OK;
1437 #endif
1438 /**************************************************************
1440 * SECTION: Window Z-order and state.
1442 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1443 * nsIWidget::ConstrainPosition
1445 * Z-order, positioning, restore, minimize, and maximize.
1447 **************************************************************/
1449 // Position the window behind the given window
1450 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1451 nsIWidget *aWidget, PRBool aActivate)
1453 HWND behind = HWND_TOP;
1454 if (aPlacement == eZPlacementBottom)
1455 behind = HWND_BOTTOM;
1456 else if (aPlacement == eZPlacementBelow && aWidget)
1457 behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
1458 UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
1459 if (!aActivate)
1460 flags |= SWP_NOACTIVATE;
1462 if (!CanTakeFocus() && behind == HWND_TOP)
1464 // Can't place the window to top so place it behind the foreground window
1465 // (as long as it is not topmost)
1466 HWND wndAfter = ::GetForegroundWindow();
1467 if (!wndAfter)
1468 behind = HWND_BOTTOM;
1469 else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
1470 behind = wndAfter;
1471 flags |= SWP_NOACTIVATE;
1474 ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
1475 return NS_OK;
1478 // Maximize, minimize or restore the window.
1479 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1480 NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode) {
1482 nsresult rv;
1484 // Let's not try and do anything if we're already in that state.
1485 // (This is needed to prevent problems when calling window.minimize(), which
1486 // calls us directly, and then the OS triggers another call to us.)
1487 if (aMode == mSizeMode)
1488 return NS_OK;
1490 // save the requested state
1491 rv = nsBaseWidget::SetSizeMode(aMode);
1492 if (NS_SUCCEEDED(rv) && mIsVisible) {
1493 int mode;
1495 switch (aMode) {
1496 case nsSizeMode_Fullscreen :
1497 mode = SW_MAXIMIZE;
1498 break;
1500 case nsSizeMode_Maximized :
1501 mode = SW_MAXIMIZE;
1502 break;
1504 case nsSizeMode_Minimized :
1505 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1506 // keeps the window active in the tray. So after the window is minimized,
1507 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1508 // we will do some additional processing to get the active window set right.
1509 // If sTrimOnMinimize is set, we let windows handle minimization normally
1510 // using SW_MINIMIZE.
1511 mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED;
1512 break;
1514 default :
1515 mode = SW_RESTORE;
1517 ::ShowWindow(mWnd, mode);
1518 // we dispatch an activate event here to ensure that the right child window
1519 // is focused
1520 if (mode == SW_RESTORE || mode == SW_MAXIMIZE)
1521 DispatchFocusToTopLevelWindow(NS_ACTIVATE);
1523 return rv;
1525 #endif // !defined(WINCE)
1527 // Constrain a potential move to fit onscreen
1528 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop,
1529 PRInt32 *aX, PRInt32 *aY)
1531 if (!mIsTopWidgetWindow) // only a problem for top-level windows
1532 return NS_OK;
1534 PRBool doConstrain = PR_FALSE; // whether we have enough info to do anything
1536 /* get our playing field. use the current screen, or failing that
1537 for any reason, use device caps for the default screen. */
1538 RECT screenRect;
1540 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
1541 if (screenmgr) {
1542 nsCOMPtr<nsIScreen> screen;
1543 PRInt32 left, top, width, height;
1545 // zero size rects confuse the screen manager
1546 width = mBounds.width > 0 ? mBounds.width : 1;
1547 height = mBounds.height > 0 ? mBounds.height : 1;
1548 screenmgr->ScreenForRect(*aX, *aY, width, height,
1549 getter_AddRefs(screen));
1550 if (screen) {
1551 screen->GetAvailRect(&left, &top, &width, &height);
1552 screenRect.left = left;
1553 screenRect.right = left+width;
1554 screenRect.top = top;
1555 screenRect.bottom = top+height;
1556 doConstrain = PR_TRUE;
1558 } else {
1559 if (mWnd) {
1560 HDC dc = ::GetDC(mWnd);
1561 if (dc) {
1562 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1563 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
1564 doConstrain = PR_TRUE;
1566 ::ReleaseDC(mWnd, dc);
1571 if (aAllowSlop) {
1572 if (*aX < screenRect.left - mBounds.width + kWindowPositionSlop)
1573 *aX = screenRect.left - mBounds.width + kWindowPositionSlop;
1574 else if (*aX >= screenRect.right - kWindowPositionSlop)
1575 *aX = screenRect.right - kWindowPositionSlop;
1577 if (*aY < screenRect.top - mBounds.height + kWindowPositionSlop)
1578 *aY = screenRect.top - mBounds.height + kWindowPositionSlop;
1579 else if (*aY >= screenRect.bottom - kWindowPositionSlop)
1580 *aY = screenRect.bottom - kWindowPositionSlop;
1582 } else {
1584 if (*aX < screenRect.left)
1585 *aX = screenRect.left;
1586 else if (*aX >= screenRect.right - mBounds.width)
1587 *aX = screenRect.right - mBounds.width;
1589 if (*aY < screenRect.top)
1590 *aY = screenRect.top;
1591 else if (*aY >= screenRect.bottom - mBounds.height)
1592 *aY = screenRect.bottom - mBounds.height;
1595 return NS_OK;
1598 /**************************************************************
1600 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1602 * Enabling and disabling the widget.
1604 **************************************************************/
1606 // Enable/disable this component
1607 NS_METHOD nsWindow::Enable(PRBool bState)
1609 if (mWnd) {
1610 ::EnableWindow(mWnd, bState);
1612 return NS_OK;
1615 // Return the current enable state
1616 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
1618 NS_ENSURE_ARG_POINTER(aState);
1620 #ifndef WINCE
1621 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT)));
1622 #else
1623 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(mWnd));
1624 #endif
1626 return NS_OK;
1630 /**************************************************************
1632 * SECTION: nsIWidget::SetFocus
1634 * Give the focus to this widget.
1636 **************************************************************/
1638 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
1640 if (mWnd) {
1641 #ifdef WINSTATE_DEBUG_OUTPUT
1642 if (mWnd == GetTopLevelHWND(mWnd))
1643 printf("*** SetFocus: [ top] raise=%d\n", aRaise);
1644 else
1645 printf("*** SetFocus: [child] raise=%d\n", aRaise);
1646 #endif
1647 // Uniconify, if necessary
1648 HWND toplevelWnd = GetTopLevelHWND(mWnd);
1649 if (aRaise && ::IsIconic(toplevelWnd)) {
1650 ::ShowWindow(toplevelWnd, SW_RESTORE);
1652 ::SetFocus(mWnd);
1654 return NS_OK;
1658 /**************************************************************
1660 * SECTION: Bounds
1662 * nsIWidget::GetBounds, nsIWidget::GetScreenBounds,
1663 * nsIWidget::GetClientBounds
1665 * Bound calculations.
1667 **************************************************************/
1669 // Get this component dimension
1670 NS_METHOD nsWindow::GetBounds(nsIntRect &aRect)
1672 if (mWnd) {
1673 RECT r;
1674 VERIFY(::GetWindowRect(mWnd, &r));
1676 // assign size
1677 aRect.width = r.right - r.left;
1678 aRect.height = r.bottom - r.top;
1680 // convert coordinates if parent exists
1681 HWND parent = ::GetParent(mWnd);
1682 if (parent) {
1683 RECT pr;
1684 VERIFY(::GetWindowRect(parent, &pr));
1685 r.left -= pr.left;
1686 r.top -= pr.top;
1688 aRect.x = r.left;
1689 aRect.y = r.top;
1690 } else {
1691 aRect = mBounds;
1694 return NS_OK;
1697 // Get this component dimension
1698 NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect)
1700 if (mWnd) {
1701 RECT r;
1702 VERIFY(::GetClientRect(mWnd, &r));
1704 // assign size
1705 aRect.x = 0;
1706 aRect.y = 0;
1707 aRect.width = r.right - r.left;
1708 aRect.height = r.bottom - r.top;
1710 } else {
1711 aRect.SetRect(0,0,0,0);
1713 return NS_OK;
1716 // Get the bounds, but don't take into account the client size
1717 void nsWindow::GetNonClientBounds(nsIntRect &aRect)
1719 if (mWnd) {
1720 RECT r;
1721 VERIFY(::GetWindowRect(mWnd, &r));
1723 // assign size
1724 aRect.width = r.right - r.left;
1725 aRect.height = r.bottom - r.top;
1727 // convert coordinates if parent exists
1728 HWND parent = ::GetParent(mWnd);
1729 if (parent) {
1730 RECT pr;
1731 VERIFY(::GetWindowRect(parent, &pr));
1732 r.left -= pr.left;
1733 r.top -= pr.top;
1735 aRect.x = r.left;
1736 aRect.y = r.top;
1737 } else {
1738 aRect.SetRect(0,0,0,0);
1742 // Like GetBounds, but don't offset by the parent
1743 NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect)
1745 if (mWnd) {
1746 RECT r;
1747 VERIFY(::GetWindowRect(mWnd, &r));
1749 aRect.width = r.right - r.left;
1750 aRect.height = r.bottom - r.top;
1751 aRect.x = r.left;
1752 aRect.y = r.top;
1753 } else
1754 aRect = mBounds;
1756 return NS_OK;
1759 /**************************************************************
1761 * SECTION: nsIWidget::SetBackgroundColor
1763 * Sets the window background paint color.
1765 **************************************************************/
1767 NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
1769 nsBaseWidget::SetBackgroundColor(aColor);
1771 if (mBrush)
1772 ::DeleteObject(mBrush);
1774 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
1775 #ifndef WINCE
1776 if (mWnd != NULL) {
1777 ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush);
1779 #endif
1780 return NS_OK;
1783 /**************************************************************
1785 * SECTION: nsIWidget::SetCursor
1787 * SetCursor and related utilities for manging cursor state.
1789 **************************************************************/
1791 // Set this component cursor
1792 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
1794 // Only change cursor if it's changing
1796 //XXX mCursor isn't always right. Scrollbars and others change it, too.
1797 //XXX If we want this optimization we need a better way to do it.
1798 //if (aCursor != mCursor) {
1799 HCURSOR newCursor = NULL;
1801 switch (aCursor) {
1802 case eCursor_select:
1803 newCursor = ::LoadCursor(NULL, IDC_IBEAM);
1804 break;
1806 case eCursor_wait:
1807 newCursor = ::LoadCursor(NULL, IDC_WAIT);
1808 break;
1810 case eCursor_hyperlink:
1812 newCursor = ::LoadCursor(NULL, IDC_HAND);
1813 break;
1816 case eCursor_standard:
1817 newCursor = ::LoadCursor(NULL, IDC_ARROW);
1818 break;
1820 case eCursor_n_resize:
1821 case eCursor_s_resize:
1822 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
1823 break;
1825 case eCursor_w_resize:
1826 case eCursor_e_resize:
1827 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
1828 break;
1830 case eCursor_nw_resize:
1831 case eCursor_se_resize:
1832 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
1833 break;
1835 case eCursor_ne_resize:
1836 case eCursor_sw_resize:
1837 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
1838 break;
1840 case eCursor_crosshair:
1841 newCursor = ::LoadCursor(NULL, IDC_CROSS);
1842 break;
1844 case eCursor_move:
1845 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
1846 break;
1848 case eCursor_help:
1849 newCursor = ::LoadCursor(NULL, IDC_HELP);
1850 break;
1852 case eCursor_copy: // CSS3
1853 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
1854 break;
1856 case eCursor_alias:
1857 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
1858 break;
1860 case eCursor_cell:
1861 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
1862 break;
1864 case eCursor_grab:
1865 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
1866 break;
1868 case eCursor_grabbing:
1869 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
1870 break;
1872 case eCursor_spinning:
1873 newCursor = ::LoadCursor(NULL, IDC_APPSTARTING);
1874 break;
1876 case eCursor_context_menu:
1877 // XXX this CSS3 cursor needs to be implemented
1878 break;
1880 case eCursor_zoom_in:
1881 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
1882 break;
1884 case eCursor_zoom_out:
1885 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
1886 break;
1888 case eCursor_not_allowed:
1889 case eCursor_no_drop:
1890 newCursor = ::LoadCursor(NULL, IDC_NO);
1891 break;
1893 case eCursor_col_resize:
1894 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
1895 break;
1897 case eCursor_row_resize:
1898 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
1899 break;
1901 case eCursor_vertical_text:
1902 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT));
1903 break;
1905 case eCursor_all_scroll:
1906 // XXX not 100% appropriate perhaps
1907 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
1908 break;
1910 case eCursor_nesw_resize:
1911 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
1912 break;
1914 case eCursor_nwse_resize:
1915 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
1916 break;
1918 case eCursor_ns_resize:
1919 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
1920 break;
1922 case eCursor_ew_resize:
1923 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
1924 break;
1926 case eCursor_none:
1927 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
1928 break;
1930 default:
1931 NS_ERROR("Invalid cursor type");
1932 break;
1935 if (NULL != newCursor) {
1936 mCursor = aCursor;
1937 HCURSOR oldCursor = ::SetCursor(newCursor);
1939 if (sHCursor == oldCursor) {
1940 NS_IF_RELEASE(sCursorImgContainer);
1941 if (sHCursor != NULL)
1942 ::DestroyIcon(sHCursor);
1943 sHCursor = NULL;
1947 return NS_OK;
1950 // Setting the actual cursor
1951 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
1952 PRUint32 aHotspotX, PRUint32 aHotspotY)
1954 if (sCursorImgContainer == aCursor && sHCursor) {
1955 ::SetCursor(sHCursor);
1956 return NS_OK;
1959 PRInt32 width;
1960 PRInt32 height;
1962 nsresult rv;
1963 rv = aCursor->GetWidth(&width);
1964 NS_ENSURE_SUCCESS(rv, rv);
1965 rv = aCursor->GetHeight(&height);
1966 NS_ENSURE_SUCCESS(rv, rv);
1968 // Reject cursors greater than 128 pixels in either direction, to prevent
1969 // spoofing.
1970 // XXX ideally we should rescale. Also, we could modify the API to
1971 // allow trusted content to set larger cursors.
1972 if (width > 128 || height > 128)
1973 return NS_ERROR_NOT_AVAILABLE;
1975 HCURSOR cursor;
1976 rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
1977 NS_ENSURE_SUCCESS(rv, rv);
1979 mCursor = nsCursor(-1);
1980 ::SetCursor(cursor);
1982 NS_IF_RELEASE(sCursorImgContainer);
1983 sCursorImgContainer = aCursor;
1984 NS_ADDREF(sCursorImgContainer);
1986 if (sHCursor != NULL)
1987 ::DestroyIcon(sHCursor);
1988 sHCursor = cursor;
1990 return NS_OK;
1993 /**************************************************************
1995 * SECTION: nsIWidget::Get/SetTransparencyMode
1997 * Manage the transparency mode of the top-level window
1998 * containing this widget.
2000 **************************************************************/
2002 #ifdef MOZ_XUL
2003 nsTransparencyMode nsWindow::GetTransparencyMode()
2005 return GetTopLevelWindow(PR_TRUE)->GetWindowTranslucencyInner();
2008 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
2010 GetTopLevelWindow(PR_TRUE)->SetWindowTranslucencyInner(aMode);
2012 #endif
2014 /**************************************************************
2016 * SECTION: nsIWidget::HideWindowChrome
2018 * Show or hide window chrome.
2020 **************************************************************/
2022 NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide)
2024 HWND hwnd = GetTopLevelHWND(mWnd, PR_TRUE);
2025 if (!GetNSWindowPtr(hwnd))
2027 NS_WARNING("Trying to hide window decorations in an embedded context");
2028 return NS_ERROR_FAILURE;
2031 DWORD_PTR style, exStyle;
2032 if (aShouldHide) {
2033 DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2034 DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2036 style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
2037 exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
2038 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
2040 mOldStyle = tempStyle;
2041 mOldExStyle = tempExStyle;
2043 else {
2044 if (!mOldStyle || !mOldExStyle) {
2045 mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2046 mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2049 style = mOldStyle;
2050 exStyle = mOldExStyle;
2053 VERIFY_WINDOW_STYLE(style);
2054 ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
2055 ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
2057 return NS_OK;
2060 /**************************************************************
2062 * SECTION: nsIWidget::Invalidate
2064 * Invalidate an area of the client for painting.
2066 **************************************************************/
2068 #ifdef WINCE_WINDOWS_MOBILE
2069 static inline void AddRECTToRegion(const RECT& aRect, nsIRegion* aRegion)
2071 aRegion->Union(aRect.left, aRect.top, aRect.right - aRect.left, aRect.bottom - aRect.top);
2073 #endif
2075 // Invalidate this component visible area
2076 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
2078 if (mWnd)
2080 #ifdef WIDGET_DEBUG_OUTPUT
2081 debug_DumpInvalidate(stdout,
2082 this,
2083 nsnull,
2084 aIsSynchronous,
2085 nsCAutoString("noname"),
2086 (PRInt32) mWnd);
2087 #endif // WIDGET_DEBUG_OUTPUT
2088 #ifdef WINCE_WINDOWS_MOBILE
2089 // We need to keep track of our own invalidated region for Windows CE
2090 RECT r;
2091 GetClientRect(mWnd, &r);
2092 AddRECTToRegion(r, mInvalidatedRegion);
2093 #endif
2094 VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
2096 if (aIsSynchronous) {
2097 VERIFY(::UpdateWindow(mWnd));
2100 return NS_OK;
2103 // Invalidate this component visible area
2104 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, PRBool aIsSynchronous)
2106 if (mWnd)
2108 #ifdef WIDGET_DEBUG_OUTPUT
2109 debug_DumpInvalidate(stdout,
2110 this,
2111 &aRect,
2112 aIsSynchronous,
2113 nsCAutoString("noname"),
2114 (PRInt32) mWnd);
2115 #endif // WIDGET_DEBUG_OUTPUT
2117 RECT rect;
2119 rect.left = aRect.x;
2120 rect.top = aRect.y;
2121 rect.right = aRect.x + aRect.width;
2122 rect.bottom = aRect.y + aRect.height;
2124 #ifdef WINCE_WINDOWS_MOBILE
2125 // We need to keep track of our own invalidated region for Windows CE
2126 AddRECTToRegion(rect, mInvalidatedRegion);
2127 #endif
2128 VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
2130 if (aIsSynchronous) {
2131 VERIFY(::UpdateWindow(mWnd));
2134 return NS_OK;
2137 NS_IMETHODIMP
2138 nsWindow::MakeFullScreen(PRBool aFullScreen)
2140 #if WINCE_WINDOWS_MOBILE
2141 RECT rc;
2142 if (aFullScreen) {
2143 SetForegroundWindow(mWnd);
2144 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON);
2145 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2147 else {
2148 SHFullScreen(mWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
2149 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
2151 MoveWindow(mWnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, TRUE);
2153 if (aFullScreen)
2154 mSizeMode = nsSizeMode_Fullscreen;
2155 #endif
2157 return nsBaseWidget::MakeFullScreen(aFullScreen);
2160 /**************************************************************
2162 * SECTION: nsIWidget::Update
2164 * Force a synchronous repaint of the window.
2166 **************************************************************/
2168 NS_IMETHODIMP nsWindow::Update()
2170 nsresult rv = NS_OK;
2172 // updates can come through for windows no longer holding an mWnd during
2173 // deletes triggered by JavaScript in buttons with mouse feedback
2174 if (mWnd)
2175 VERIFY(::UpdateWindow(mWnd));
2177 return rv;
2180 /**************************************************************
2182 * SECTION: nsIWidget::Scroll
2184 * Scroll this widget.
2186 **************************************************************/
2188 static PRBool
2189 ClipRegionContainedInRect(const nsTArray<nsIntRect>& aClipRects,
2190 const nsIntRect& aRect)
2192 for (PRUint32 i = 0; i < aClipRects.Length(); ++i) {
2193 if (!aRect.Contains(aClipRects[i]))
2194 return PR_FALSE;
2196 return PR_TRUE;
2199 // This function determines whether the given window has a descendant that
2200 // does not intersect the given aScreenRect. If we encounter a window owned
2201 // by another thread (which includes another process, since thread IDs
2202 // are unique system-wide), then we give up and conservatively return true.
2203 static PRBool
2204 HasDescendantWindowOutsideRect(DWORD aThisThreadID, HWND aWnd,
2205 const RECT& aScreenRect)
2207 // If the window is owned by another thread, give up now, don't try to
2208 // look at its children since they could change asynchronously.
2209 // XXX should we try harder here for out-of-process plugins?
2210 if (GetWindowThreadProcessId(aWnd, NULL) != aThisThreadID) {
2211 return PR_TRUE;
2213 for (HWND child = ::GetWindow(aWnd, GW_CHILD); child;
2214 child = ::GetWindow(child, GW_HWNDNEXT)) {
2215 RECT childScreenRect;
2216 ::GetWindowRect(child, &childScreenRect);
2217 RECT result;
2218 if (!::IntersectRect(&result, &childScreenRect, &aScreenRect)) {
2219 return PR_TRUE;
2222 if (HasDescendantWindowOutsideRect(aThisThreadID, child, aScreenRect)) {
2223 return PR_TRUE;
2227 return PR_FALSE;
2230 void
2231 nsWindow::Scroll(const nsIntPoint& aDelta,
2232 const nsTArray<nsIntRect>& aDestRects,
2233 const nsTArray<Configuration>& aConfigurations)
2235 // We use SW_SCROLLCHILDREN if all the windows that intersect the
2236 // affected area are moving by the scroll amount.
2237 // First, build the set of widgets that are to be moved by the scroll
2238 // amount.
2239 // At the same time, set the clip region of all changed windows to the
2240 // intersection of the current and new regions.
2241 nsTHashtable<nsPtrHashKey<nsWindow> > scrolledWidgets;
2242 scrolledWidgets.Init();
2243 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
2244 const Configuration& configuration = aConfigurations[i];
2245 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
2246 NS_ASSERTION(w->GetParent() == this,
2247 "Configured widget is not a child");
2248 if (configuration.mBounds == w->mBounds + aDelta) {
2249 scrolledWidgets.PutEntry(w);
2251 w->SetWindowClipRegion(configuration.mClipRegion, PR_TRUE);
2254 DWORD ourThreadID = GetWindowThreadProcessId(mWnd, NULL);
2256 for (PRUint32 i = 0; i < aDestRects.Length(); ++i) {
2257 nsIntRect affectedRect;
2258 affectedRect.UnionRect(aDestRects[i], aDestRects[i] - aDelta);
2259 // We pass SW_INVALIDATE because areas that get scrolled into view
2260 // from offscreen (but inside the scroll area) need to be repainted.
2261 UINT flags = SW_SCROLLCHILDREN | SW_INVALIDATE;
2262 // Now check if any of our children would be affected by
2263 // SW_SCROLLCHILDREN but not supposed to scroll.
2264 for (nsWindow* w = static_cast<nsWindow*>(GetFirstChild()); w;
2265 w = static_cast<nsWindow*>(w->GetNextSibling())) {
2266 if (w->mBounds.Intersects(affectedRect)) {
2267 // This child will be affected
2268 nsPtrHashKey<nsWindow>* entry = scrolledWidgets.GetEntry(w);
2269 if (entry) {
2270 // It's supposed to be scrolled, so we can still use
2271 // SW_SCROLLCHILDREN. But don't allow SW_SCROLLCHILDREN to be
2272 // used on it again by a later rectangle in aDestRects, we
2273 // don't want it to move twice!
2274 scrolledWidgets.RawRemoveEntry(entry);
2276 nsIntPoint screenOffset = WidgetToScreenOffset();
2277 RECT screenAffectedRect = {
2278 screenOffset.x + affectedRect.x,
2279 screenOffset.y + affectedRect.y,
2280 screenOffset.x + affectedRect.XMost(),
2281 screenOffset.y + affectedRect.YMost()
2283 if (HasDescendantWindowOutsideRect(ourThreadID, w->mWnd,
2284 screenAffectedRect)) {
2285 // SW_SCROLLCHILDREN seems to not move descendant windows
2286 // that don't intersect the scrolled rectangle, *even if* the
2287 // immediate child window of the scrolled window *does* intersect
2288 // the scrolled window. So if w has a descendant window
2289 // that would not be moved, SW_SCROLLCHILDREN will hopelessly mess
2290 // things up and we must not use it.
2291 flags &= ~SW_SCROLLCHILDREN;
2293 } else {
2294 flags &= ~SW_SCROLLCHILDREN;
2295 // We may have removed some children from scrolledWidgets even
2296 // though we decide here to not use SW_SCROLLCHILDREN. That's OK,
2297 // it just means that we might not use SW_SCROLLCHILDREN
2298 // for a later rectangle when we could have.
2299 break;
2304 if (flags & SW_SCROLLCHILDREN) {
2305 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
2306 const Configuration& configuration = aConfigurations[i];
2307 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
2308 // Widgets that will be scrolled by SW_SCROLLCHILDREN but which
2309 // will be partly visible outside the scroll area after scrolling
2310 // must be invalidated, because SW_SCROLLCHILDREN doesn't
2311 // update parts of widgets outside the area it scrolled, even
2312 // if it moved them.
2313 if (w->mBounds.Intersects(affectedRect) &&
2314 !ClipRegionContainedInRect(configuration.mClipRegion,
2315 affectedRect - (w->mBounds.TopLeft() + aDelta))) {
2316 w->Invalidate(PR_FALSE);
2320 // ScrollWindowEx will send WM_MOVE to each moved window to tell it
2321 // its new position. Unfortunately those messages don't reach our
2322 // WM_MOVE handler for some plugins, so we have to update their
2323 // mBounds here. For windows that do receive WM_MOVE, this is OK,
2324 // they'll just overwrite mBounds again with the correct value.
2325 for (nsWindow* w = static_cast<nsWindow*>(GetFirstChild()); w;
2326 w = static_cast<nsWindow*>(w->GetNextSibling())) {
2327 if (w->mBounds.Intersects(affectedRect)) {
2328 w->mBounds += aDelta;
2333 RECT clip = { affectedRect.x, affectedRect.y, affectedRect.XMost(), affectedRect.YMost() };
2334 ::ScrollWindowEx(mWnd, aDelta.x, aDelta.y, &clip, &clip, NULL, NULL, flags);
2337 // Now make sure all children actually get positioned, sized and clipped
2338 // correctly. If SW_SCROLLCHILDREN already moved widgets to their correct
2339 // locations, then the SetWindowPos calls this triggers will just be
2340 // no-ops.
2341 ConfigureChildren(aConfigurations);
2344 /**************************************************************
2346 * SECTION: Native data storage
2348 * nsIWidget::GetNativeData
2349 * nsIWidget::FreeNativeData
2351 * Set or clear native data based on a constant.
2353 **************************************************************/
2355 // Return some native data according to aDataType
2356 void* nsWindow::GetNativeData(PRUint32 aDataType)
2358 switch (aDataType) {
2359 case NS_NATIVE_PLUGIN_PORT:
2360 case NS_NATIVE_WIDGET:
2361 case NS_NATIVE_WINDOW:
2362 return (void*)mWnd;
2363 case NS_NATIVE_GRAPHIC:
2364 // XXX: This is sleezy!! Remember to Release the DC after using it!
2365 #ifdef MOZ_XUL
2366 return (void*)(eTransparencyTransparent == mTransparencyMode) ?
2367 mMemoryDC : ::GetDC(mWnd);
2368 #else
2369 return (void*)::GetDC(mWnd);
2370 #endif
2372 #ifdef NS_ENABLE_TSF
2373 case NS_NATIVE_TSF_THREAD_MGR:
2374 return nsTextStore::GetThreadMgr();
2375 case NS_NATIVE_TSF_CATEGORY_MGR:
2376 return nsTextStore::GetCategoryMgr();
2377 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
2378 return nsTextStore::GetDisplayAttrMgr();
2379 #endif //NS_ENABLE_TSF
2381 default:
2382 break;
2385 return NULL;
2388 // Free some native data according to aDataType
2389 void nsWindow::FreeNativeData(void * data, PRUint32 aDataType)
2391 switch (aDataType)
2393 case NS_NATIVE_GRAPHIC:
2394 #ifdef MOZ_XUL
2395 if (eTransparencyTransparent != mTransparencyMode)
2396 ::ReleaseDC(mWnd, (HDC)data);
2397 #else
2398 ::ReleaseDC(mWnd, (HDC)data);
2399 #endif
2400 break;
2401 case NS_NATIVE_WIDGET:
2402 case NS_NATIVE_WINDOW:
2403 case NS_NATIVE_PLUGIN_PORT:
2404 break;
2405 default:
2406 break;
2410 /**************************************************************
2412 * SECTION: nsIWidget::SetTitle
2414 * Set the main windows title text.
2416 **************************************************************/
2418 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
2420 const nsString& strTitle = PromiseFlatString(aTitle);
2421 ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get());
2422 return NS_OK;
2425 /**************************************************************
2427 * SECTION: nsIWidget::SetIcon
2429 * Set the main windows icon.
2431 **************************************************************/
2433 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec)
2435 #ifndef WINCE
2436 // Assume the given string is a local identifier for an icon file.
2438 nsCOMPtr<nsILocalFile> iconFile;
2439 ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
2440 getter_AddRefs(iconFile));
2441 if (!iconFile)
2442 return NS_OK; // not an error if icon is not found
2444 nsAutoString iconPath;
2445 iconFile->GetPath(iconPath);
2447 // XXX this should use MZLU (see bug 239279)
2449 ::SetLastError(0);
2451 HICON bigIcon = (HICON)::LoadImageW(NULL,
2452 (LPCWSTR)iconPath.get(),
2453 IMAGE_ICON,
2454 ::GetSystemMetrics(SM_CXICON),
2455 ::GetSystemMetrics(SM_CYICON),
2456 LR_LOADFROMFILE );
2457 HICON smallIcon = (HICON)::LoadImageW(NULL,
2458 (LPCWSTR)iconPath.get(),
2459 IMAGE_ICON,
2460 ::GetSystemMetrics(SM_CXSMICON),
2461 ::GetSystemMetrics(SM_CYSMICON),
2462 LR_LOADFROMFILE );
2464 if (bigIcon) {
2465 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon);
2466 if (icon)
2467 ::DestroyIcon(icon);
2469 #ifdef DEBUG_SetIcon
2470 else {
2471 NS_LossyConvertUTF16toASCII cPath(iconPath);
2472 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2474 #endif
2475 if (smallIcon) {
2476 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon);
2477 if (icon)
2478 ::DestroyIcon(icon);
2480 #ifdef DEBUG_SetIcon
2481 else {
2482 NS_LossyConvertUTF16toASCII cPath(iconPath);
2483 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2485 #endif
2486 #endif // WINCE
2487 return NS_OK;
2490 /**************************************************************
2492 * SECTION: nsIWidget::WidgetToScreenOffset
2494 * Return this widget's origin in screen coordinates.
2496 **************************************************************/
2498 nsIntPoint nsWindow::WidgetToScreenOffset()
2500 POINT point;
2501 point.x = 0;
2502 point.y = 0;
2503 ::ClientToScreen(mWnd, &point);
2504 return nsIntPoint(point.x, point.y);
2507 /**************************************************************
2509 * SECTION: nsIWidget::EnableDragDrop
2511 * Enables/Disables drag and drop of files on this widget.
2513 **************************************************************/
2515 #if !defined(WINCE) // implemented in nsWindowCE.cpp
2516 NS_METHOD nsWindow::EnableDragDrop(PRBool aEnable)
2518 nsresult rv = NS_ERROR_FAILURE;
2519 if (aEnable) {
2520 if (nsnull == mNativeDragTarget) {
2521 mNativeDragTarget = new nsNativeDragTarget(this);
2522 if (NULL != mNativeDragTarget) {
2523 mNativeDragTarget->AddRef();
2524 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) {
2525 if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) {
2526 rv = NS_OK;
2531 } else {
2532 if (nsnull != mWnd && NULL != mNativeDragTarget) {
2533 ::RevokeDragDrop(mWnd);
2534 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) {
2535 rv = NS_OK;
2537 mNativeDragTarget->mDragCancelled = PR_TRUE;
2538 NS_RELEASE(mNativeDragTarget);
2541 return rv;
2543 #endif
2545 /**************************************************************
2547 * SECTION: nsIWidget::CaptureMouse
2549 * Enables/Disables system mouse capture.
2551 **************************************************************/
2553 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
2555 if (!nsToolkit::gMouseTrailer) {
2556 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
2557 return NS_OK;
2560 if (aCapture) {
2561 nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd);
2562 ::SetCapture(mWnd);
2563 } else {
2564 nsToolkit::gMouseTrailer->SetCaptureWindow(NULL);
2565 ::ReleaseCapture();
2567 mIsInMouseCapture = aCapture;
2568 return NS_OK;
2571 /**************************************************************
2573 * SECTION: nsIWidget::CaptureRollupEvents
2575 * Dealing with event rollup on destroy for popups. Enables &
2576 * Disables system capture of any and all events that would
2577 * cause a dropdown to be rolled up.
2579 **************************************************************/
2581 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
2582 PRBool aDoCapture,
2583 PRBool aConsumeRollupEvent)
2585 if (aDoCapture) {
2586 /* we haven't bothered carrying a weak reference to sRollupWidget because
2587 we believe lifespan is properly scoped. this next assertion helps
2588 assure that remains true. */
2589 NS_ASSERTION(!sRollupWidget, "rollup widget reassigned before release");
2590 sRollupConsumeEvent = aConsumeRollupEvent;
2591 NS_IF_RELEASE(sRollupListener);
2592 NS_IF_RELEASE(sRollupWidget);
2593 sRollupListener = aListener;
2594 NS_ADDREF(aListener);
2595 sRollupWidget = this;
2596 NS_ADDREF(this);
2598 #ifndef WINCE
2599 if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
2600 RegisterSpecialDropdownHooks();
2602 sProcessHook = PR_TRUE;
2603 #endif
2605 } else {
2606 NS_IF_RELEASE(sRollupListener);
2607 NS_IF_RELEASE(sRollupWidget);
2609 #ifndef WINCE
2610 sProcessHook = PR_FALSE;
2611 UnregisterSpecialDropdownHooks();
2612 #endif
2615 return NS_OK;
2618 /**************************************************************
2620 * SECTION: nsIWidget::GetAttention
2622 * Bring this window to the user's attention.
2624 **************************************************************/
2626 // Draw user's attention to this window until it comes to foreground.
2627 NS_IMETHODIMP
2628 nsWindow::GetAttention(PRInt32 aCycleCount)
2630 #ifndef WINCE
2631 // Got window?
2632 if (!mWnd)
2633 return NS_ERROR_NOT_INITIALIZED;
2635 // Don't flash if the flash count is 0 or if the
2636 // top level window is already active.
2637 HWND fgWnd = ::GetForegroundWindow();
2638 if (aCycleCount == 0 || fgWnd == GetTopLevelHWND(mWnd))
2639 return NS_OK;
2641 HWND flashWnd = mWnd;
2642 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
2643 flashWnd = ownerWnd;
2646 // Don't flash if the owner window is active either.
2647 if (fgWnd == flashWnd)
2648 return NS_OK;
2650 DWORD defaultCycleCount = 0;
2651 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
2653 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
2654 FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 };
2655 ::FlashWindowEx(&flashInfo);
2656 #endif
2657 return NS_OK;
2660 void nsWindow::StopFlashing()
2662 #ifndef WINCE
2663 HWND flashWnd = mWnd;
2664 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
2665 flashWnd = ownerWnd;
2668 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
2669 FLASHW_STOP, 0, 0 };
2670 ::FlashWindowEx(&flashInfo);
2671 #endif
2674 /**************************************************************
2676 * SECTION: nsIWidget::HasPendingInputEvent
2678 * Ask whether there user input events pending. All input events are
2679 * included, including those not targeted at this nsIwidget instance.
2681 **************************************************************/
2683 PRBool
2684 nsWindow::HasPendingInputEvent()
2686 // If there is pending input or the user is currently
2687 // moving the window then return true.
2688 // Note: When the user is moving the window WIN32 spins
2689 // a separate event loop and input events are not
2690 // reported to the application.
2691 if (HIWORD(GetQueueStatus(QS_INPUT)))
2692 return PR_TRUE;
2693 #ifdef WINCE
2694 return PR_FALSE;
2695 #else
2696 GUITHREADINFO guiInfo;
2697 guiInfo.cbSize = sizeof(GUITHREADINFO);
2698 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo))
2699 return PR_FALSE;
2700 return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE);
2701 #endif
2704 /**************************************************************
2706 * SECTION: nsIWidget::GetThebesSurface
2708 * Get the Thebes surface associated with this widget.
2710 **************************************************************/
2712 gfxASurface *nsWindow::GetThebesSurface()
2714 if (mPaintDC)
2715 return (new gfxWindowsSurface(mPaintDC));
2717 return (new gfxWindowsSurface(mWnd));
2720 /**************************************************************
2722 * SECTION: nsIWidget::OnDefaultButtonLoaded
2724 * Called after the dialog is loaded and it has a default button.
2726 **************************************************************/
2728 NS_IMETHODIMP
2729 nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect)
2731 #ifdef WINCE
2732 return NS_ERROR_NOT_IMPLEMENTED;
2733 #else
2734 if (aButtonRect.IsEmpty())
2735 return NS_OK;
2737 // Don't snap when we are not active.
2738 HWND activeWnd = ::GetActiveWindow();
2739 if (activeWnd != ::GetForegroundWindow() ||
2740 GetTopLevelHWND(mWnd, PR_TRUE) != GetTopLevelHWND(activeWnd, PR_TRUE)) {
2741 return NS_OK;
2744 PRBool isAlwaysSnapCursor = PR_FALSE;
2745 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
2746 if (prefs) {
2747 nsCOMPtr<nsIPrefBranch> prefBranch;
2748 prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
2749 if (prefBranch) {
2750 prefBranch->GetBoolPref("ui.cursor_snapping.always_enabled",
2751 &isAlwaysSnapCursor);
2755 if (!isAlwaysSnapCursor) {
2756 BOOL snapDefaultButton;
2757 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0,
2758 &snapDefaultButton, 0) || !snapDefaultButton)
2759 return NS_OK;
2762 nsIntRect widgetRect;
2763 nsresult rv = GetScreenBounds(widgetRect);
2764 NS_ENSURE_SUCCESS(rv, rv);
2765 nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft());
2767 nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2,
2768 buttonRect.y + buttonRect.height / 2);
2769 // The center of the button can be outside of the widget.
2770 // E.g., it could be hidden by scrolling.
2771 if (!widgetRect.Contains(centerOfButton)) {
2772 return NS_OK;
2775 if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) {
2776 NS_ERROR("SetCursorPos failed");
2777 return NS_ERROR_FAILURE;
2779 return NS_OK;
2780 #endif
2783 NS_IMETHODIMP
2784 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta,
2785 PRBool aIsHorizontal,
2786 PRInt32 &aOverriddenDelta)
2788 // The default vertical and horizontal scrolling speed is 3, this is defined
2789 // on the document of SystemParametersInfo in MSDN.
2790 const PRInt32 kSystemDefaultScrollingSpeed = 3;
2792 // Compute the simple overridden speed.
2793 PRInt32 computedOverriddenDelta;
2794 nsresult rv =
2795 nsBaseWidget::OverrideSystemMouseScrollSpeed(aOriginalDelta, aIsHorizontal,
2796 computedOverriddenDelta);
2797 NS_ENSURE_SUCCESS(rv, rv);
2799 aOverriddenDelta = aOriginalDelta;
2801 if (computedOverriddenDelta == aOriginalDelta) {
2802 // We don't override now.
2803 return NS_OK;
2806 // Otherwise, we should check whether the user customized the system settings
2807 // or not. If the user did it, we should respect the will.
2808 UINT systemSpeed;
2809 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) {
2810 return NS_ERROR_FAILURE;
2812 // The default vertical scrolling speed is 3, this is defined on the document
2813 // of SystemParametersInfo in MSDN.
2814 if (systemSpeed != kSystemDefaultScrollingSpeed) {
2815 return NS_OK;
2818 // Only Vista and later, Windows has the system setting of horizontal
2819 // scrolling by the mouse wheel.
2820 if (GetWindowsVersion() >= VISTA_VERSION) {
2821 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) {
2822 return NS_ERROR_FAILURE;
2824 // The default horizontal scrolling speed is 3, this is defined on the
2825 // document of SystemParametersInfo in MSDN.
2826 if (systemSpeed != kSystemDefaultScrollingSpeed) {
2827 return NS_OK;
2831 // Limit the overridden delta value from the system settings. The mouse
2832 // driver might accelerate the scrolling speed already. If so, we shouldn't
2833 // override the scrolling speed for preventing the unexpected high speed
2834 // scrolling.
2835 PRInt32 deltaLimit;
2836 rv =
2837 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed,
2838 aIsHorizontal, deltaLimit);
2839 NS_ENSURE_SUCCESS(rv, rv);
2841 aOverriddenDelta = PR_MIN(computedOverriddenDelta, deltaLimit);
2843 return NS_OK;
2846 /**************************************************************
2847 **************************************************************
2849 ** BLOCK: Moz Events
2851 ** Moz GUI event management.
2853 **************************************************************
2854 **************************************************************/
2856 /**************************************************************
2858 * SECTION: Mozilla event initialization
2860 * Helpers for initializing moz events.
2862 **************************************************************/
2864 // Event intialization
2865 MSG nsWindow::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam)
2867 MSG msg;
2868 msg.message = aMessage;
2869 msg.wParam = wParam;
2870 msg.lParam = lParam;
2871 return msg;
2874 void nsWindow::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
2876 if (nsnull == aPoint) { // use the point from the event
2877 // get the message position in client coordinates
2878 if (mWnd != NULL) {
2880 DWORD pos = ::GetMessagePos();
2881 POINT cpos;
2883 cpos.x = GET_X_LPARAM(pos);
2884 cpos.y = GET_Y_LPARAM(pos);
2886 ::ScreenToClient(mWnd, &cpos);
2887 event.refPoint.x = cpos.x;
2888 event.refPoint.y = cpos.y;
2889 } else {
2890 event.refPoint.x = 0;
2891 event.refPoint.y = 0;
2894 else {
2895 // use the point override if provided
2896 event.refPoint.x = aPoint->x;
2897 event.refPoint.y = aPoint->y;
2900 #ifndef WINCE
2901 event.time = ::GetMessageTime();
2902 #else
2903 event.time = PR_Now() / 1000;
2904 #endif
2906 mLastPoint = event.refPoint;
2909 /**************************************************************
2911 * SECTION: Moz event dispatch helpers
2913 * Helpers for dispatching different types of moz events.
2915 **************************************************************/
2917 // Main event dispatch. Invokes callback and ProcessEvent method on
2918 // Event Listener object. Part of nsIWidget.
2919 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
2921 #ifdef WIDGET_DEBUG_OUTPUT
2922 debug_DumpEvent(stdout,
2923 event->widget,
2924 event,
2925 nsCAutoString("something"),
2926 (PRInt32) mWnd);
2927 #endif // WIDGET_DEBUG_OUTPUT
2929 aStatus = nsEventStatus_eIgnore;
2931 // skip processing of suppressed blur events
2932 if (event->message == NS_DEACTIVATE && BlurEventsSuppressed())
2933 return NS_OK;
2935 if (nsnull != mEventCallback) {
2936 aStatus = (*mEventCallback)(event);
2939 // the window can be destroyed during processing of seemingly innocuous events like, say,
2940 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
2941 // which causes problems with the deleted window. therefore:
2942 if (mOnDestroyCalled)
2943 aStatus = nsEventStatus_eConsumeNoDefault;
2944 return NS_OK;
2947 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
2949 nsGUIEvent event(PR_TRUE, aMsg, this);
2950 InitEvent(event);
2952 PRBool result = DispatchWindowEvent(&event);
2953 return result;
2956 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
2958 nsEventStatus status;
2959 DispatchEvent(event, status);
2960 return ConvertStatus(status);
2963 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event, nsEventStatus &aStatus) {
2964 DispatchEvent(event, aStatus);
2965 return ConvertStatus(aStatus);
2968 PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
2969 const nsTArray<nsAlternativeCharCode>* aAlternativeCharCodes,
2970 UINT aVirtualCharCode, const MSG *aMsg,
2971 const nsModifierKeyState &aModKeyState,
2972 PRUint32 aFlags)
2974 nsKeyEvent event(PR_TRUE, aEventType, this);
2975 nsIntPoint point(0, 0);
2977 InitEvent(event, &point); // this add ref's event.widget
2979 event.flags |= aFlags;
2980 event.charCode = aCharCode;
2981 if (aAlternativeCharCodes)
2982 event.alternativeCharCodes.AppendElements(*aAlternativeCharCodes);
2983 event.keyCode = aVirtualCharCode;
2985 #ifdef KE_DEBUG
2986 static cnt=0;
2987 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt++,
2988 (NS_KEY_PRESS == aEventType) ? "PRESS" : (aEventType == NS_KEY_UP ? "Up" : "Down"),
2989 event.charCode, event.keyCode);
2990 printf("Shift: %s Control %s Alt: %s \n",
2991 (mIsShiftDown ? "D" : "U"), (mIsControlDown ? "D" : "U"), (mIsAltDown ? "D" : "U"));
2992 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
2993 IS_VK_DOWN(NS_VK_SHIFT) ? 'S' : ' ',
2994 IS_VK_DOWN(NS_VK_CONTROL) ? 'C' : ' ',
2995 IS_VK_DOWN(NS_VK_ALT) ? 'A' : ' ',
2996 IS_VK_DOWN(VK_LSHIFT) ? 'S' : ' ',
2997 IS_VK_DOWN(VK_LCONTROL) ? 'C' : ' ',
2998 IS_VK_DOWN(VK_LMENU) ? 'A' : ' ',
2999 IS_VK_DOWN(VK_RMENU) ? 'A' : ' ',
3000 IS_VK_DOWN(VK_RCONTROL) ? 'C' : ' ',
3001 IS_VK_DOWN(VK_RSHIFT) ? 'S' : ' ');
3002 #endif
3004 event.isShift = aModKeyState.mIsShiftDown;
3005 event.isControl = aModKeyState.mIsControlDown;
3006 event.isMeta = PR_FALSE;
3007 event.isAlt = aModKeyState.mIsAltDown;
3009 NPEvent pluginEvent;
3010 if (aMsg && PluginHasFocus()) {
3011 pluginEvent.event = aMsg->message;
3012 pluginEvent.wParam = aMsg->wParam;
3013 pluginEvent.lParam = aMsg->lParam;
3014 event.pluginEvent = (void *)&pluginEvent;
3017 PRBool result = DispatchWindowEvent(&event);
3019 return result;
3022 PRBool nsWindow::DispatchCommandEvent(PRUint32 aEventCommand)
3024 nsCOMPtr<nsIAtom> command;
3025 switch (aEventCommand) {
3026 case APPCOMMAND_BROWSER_BACKWARD:
3027 command = nsWidgetAtoms::Back;
3028 break;
3029 case APPCOMMAND_BROWSER_FORWARD:
3030 command = nsWidgetAtoms::Forward;
3031 break;
3032 case APPCOMMAND_BROWSER_REFRESH:
3033 command = nsWidgetAtoms::Reload;
3034 break;
3035 case APPCOMMAND_BROWSER_STOP:
3036 command = nsWidgetAtoms::Stop;
3037 break;
3038 case APPCOMMAND_BROWSER_SEARCH:
3039 command = nsWidgetAtoms::Search;
3040 break;
3041 case APPCOMMAND_BROWSER_FAVORITES:
3042 command = nsWidgetAtoms::Bookmarks;
3043 break;
3044 case APPCOMMAND_BROWSER_HOME:
3045 command = nsWidgetAtoms::Home;
3046 break;
3047 default:
3048 return PR_FALSE;
3050 nsCommandEvent event(PR_TRUE, nsWidgetAtoms::onAppCommand, command, this);
3052 InitEvent(event);
3053 DispatchWindowEvent(&event);
3055 return PR_TRUE;
3058 // Recursively dispatch synchronous paints for nsIWidget
3059 // descendants with invalidated rectangles.
3060 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
3062 LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
3063 if (proc == (LONG_PTR)&nsWindow::WindowProc) {
3064 // its one of our windows so check to see if it has a
3065 // invalidated rect. If it does. Dispatch a synchronous
3066 // paint.
3067 if (GetUpdateRect(aWnd, NULL, FALSE)) {
3068 VERIFY(::UpdateWindow(aWnd));
3071 return TRUE;
3074 // Check for pending paints and dispatch any pending paint
3075 // messages for any nsIWidget which is a descendant of the
3076 // top-level window that *this* window is embedded within.
3078 // Note: We do not dispatch pending paint messages for non
3079 // nsIWidget managed windows.
3080 void nsWindow::DispatchPendingEvents()
3082 UpdateLastInputEventTime();
3084 // We need to ensure that reflow events do not get starved.
3085 // At the same time, we don't want to recurse through here
3086 // as that would prevent us from dispatching starved paints.
3087 static int recursionBlocker = 0;
3088 if (recursionBlocker++ == 0) {
3089 NS_ProcessPendingEvents(nsnull, PR_MillisecondsToInterval(100));
3090 --recursionBlocker;
3093 // Quickly check to see if there are any
3094 // paint events pending.
3095 if (::GetQueueStatus(QS_PAINT)) {
3096 // Find the top level window.
3097 HWND topWnd = GetTopLevelHWND(mWnd);
3099 // Dispatch pending paints for all topWnd's descendant windows.
3100 // Note: EnumChildWindows enumerates all descendant windows not just
3101 // it's children.
3102 #if !defined(WINCE)
3103 ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3104 #else
3105 nsWindowCE::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3106 #endif
3110 // Deal with plugin events
3111 PRBool nsWindow::DispatchPluginEvent(const MSG &aMsg)
3113 if (!PluginHasFocus())
3114 return PR_FALSE;
3116 nsGUIEvent event(PR_TRUE, NS_PLUGIN_EVENT, this);
3117 nsIntPoint point(0, 0);
3118 InitEvent(event, &point);
3119 NPEvent pluginEvent;
3120 pluginEvent.event = aMsg.message;
3121 pluginEvent.wParam = aMsg.wParam;
3122 pluginEvent.lParam = aMsg.lParam;
3123 event.pluginEvent = (void *)&pluginEvent;
3124 return DispatchWindowEvent(&event);
3127 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
3128 UINT aLastMsg)
3130 MSG msg;
3131 ::GetMessageW(&msg, mWnd, aFirstMsg, aLastMsg);
3132 DispatchPluginEvent(msg);
3135 // Deal with all sort of mouse event
3136 PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
3137 LPARAM lParam, PRBool aIsContextMenuKey,
3138 PRInt16 aButton)
3140 PRBool result = PR_FALSE;
3142 if (!mEventCallback) {
3143 return result;
3146 nsIntPoint eventPoint;
3147 eventPoint.x = GET_X_LPARAM(lParam);
3148 eventPoint.y = GET_Y_LPARAM(lParam);
3150 nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal,
3151 aIsContextMenuKey
3152 ? nsMouseEvent::eContextMenuKey
3153 : nsMouseEvent::eNormal);
3154 if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) {
3155 nsIntPoint zero(0, 0);
3156 InitEvent(event, &zero);
3157 } else {
3158 InitEvent(event, &eventPoint);
3161 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
3162 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
3163 event.isMeta = PR_FALSE;
3164 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
3165 event.button = aButton;
3167 nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
3169 // Suppress mouse moves caused by widget creation
3170 if (aEventType == NS_MOUSE_MOVE)
3172 if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y))
3173 return result;
3174 sLastMouseMovePoint.x = mpScreen.x;
3175 sLastMouseMovePoint.y = mpScreen.y;
3178 PRBool insideMovementThreshold = (abs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
3179 (abs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
3181 BYTE eventButton;
3182 switch (aButton) {
3183 case nsMouseEvent::eLeftButton:
3184 eventButton = VK_LBUTTON;
3185 break;
3186 case nsMouseEvent::eMiddleButton:
3187 eventButton = VK_MBUTTON;
3188 break;
3189 case nsMouseEvent::eRightButton:
3190 eventButton = VK_RBUTTON;
3191 break;
3192 default:
3193 eventButton = 0;
3194 break;
3197 // Doubleclicks are used to set the click count, then changed to mousedowns
3198 // We're going to time double-clicks from mouse *up* to next mouse *down*
3199 #ifndef WINCE
3200 LONG curMsgTime = ::GetMessageTime();
3201 #else
3202 LONG curMsgTime = PR_Now() / 1000;
3203 #endif
3205 if (aEventType == NS_MOUSE_DOUBLECLICK) {
3206 event.message = NS_MOUSE_BUTTON_DOWN;
3207 event.button = aButton;
3208 sLastClickCount = 2;
3210 else if (aEventType == NS_MOUSE_BUTTON_UP) {
3211 // remember when this happened for the next mouse down
3212 sLastMousePoint.x = eventPoint.x;
3213 sLastMousePoint.y = eventPoint.y;
3214 sLastMouseButton = eventButton;
3216 else if (aEventType == NS_MOUSE_BUTTON_DOWN) {
3217 // now look to see if we want to convert this to a double- or triple-click
3218 if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold &&
3219 eventButton == sLastMouseButton) {
3220 sLastClickCount ++;
3221 } else {
3222 // reset the click count, to count *this* click
3223 sLastClickCount = 1;
3225 // Set last Click time on MouseDown only
3226 sLastMouseDownTime = curMsgTime;
3228 else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
3229 sLastClickCount = 0;
3231 else if (aEventType == NS_MOUSE_EXIT) {
3232 event.exit = IsTopLevelMouseExit(mWnd) ? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
3234 event.clickCount = sLastClickCount;
3236 #ifdef NS_DEBUG_XX
3237 printf("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount);
3238 #endif
3240 NPEvent pluginEvent;
3242 switch (aEventType)
3244 case NS_MOUSE_BUTTON_DOWN:
3245 switch (aButton) {
3246 case nsMouseEvent::eLeftButton:
3247 pluginEvent.event = WM_LBUTTONDOWN;
3248 break;
3249 case nsMouseEvent::eMiddleButton:
3250 pluginEvent.event = WM_MBUTTONDOWN;
3251 break;
3252 case nsMouseEvent::eRightButton:
3253 pluginEvent.event = WM_RBUTTONDOWN;
3254 break;
3255 default:
3256 break;
3258 break;
3259 case NS_MOUSE_BUTTON_UP:
3260 switch (aButton) {
3261 case nsMouseEvent::eLeftButton:
3262 pluginEvent.event = WM_LBUTTONUP;
3263 break;
3264 case nsMouseEvent::eMiddleButton:
3265 pluginEvent.event = WM_MBUTTONUP;
3266 break;
3267 case nsMouseEvent::eRightButton:
3268 pluginEvent.event = WM_RBUTTONUP;
3269 break;
3270 default:
3271 break;
3273 break;
3274 case NS_MOUSE_DOUBLECLICK:
3275 switch (aButton) {
3276 case nsMouseEvent::eLeftButton:
3277 pluginEvent.event = WM_LBUTTONDBLCLK;
3278 break;
3279 case nsMouseEvent::eMiddleButton:
3280 pluginEvent.event = WM_MBUTTONDBLCLK;
3281 break;
3282 case nsMouseEvent::eRightButton:
3283 pluginEvent.event = WM_RBUTTONDBLCLK;
3284 break;
3285 default:
3286 break;
3288 break;
3289 case NS_MOUSE_MOVE:
3290 pluginEvent.event = WM_MOUSEMOVE;
3291 break;
3292 default:
3293 pluginEvent.event = WM_NULL;
3294 break;
3297 pluginEvent.wParam = wParam; // plugins NEED raw OS event flags!
3298 pluginEvent.lParam = lParam;
3300 event.pluginEvent = (void *)&pluginEvent;
3302 // call the event callback
3303 if (nsnull != mEventCallback) {
3304 if (nsToolkit::gMouseTrailer)
3305 nsToolkit::gMouseTrailer->Disable();
3306 if (aEventType == NS_MOUSE_MOVE) {
3307 if (nsToolkit::gMouseTrailer && !mIsInMouseCapture) {
3308 nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd);
3310 nsIntRect rect;
3311 GetBounds(rect);
3312 rect.x = 0;
3313 rect.y = 0;
3315 if (rect.Contains(event.refPoint)) {
3316 if (sCurrentWindow == NULL || sCurrentWindow != this) {
3317 if ((nsnull != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
3318 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3319 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos);
3321 sCurrentWindow = this;
3322 if (!mInDtor) {
3323 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3324 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos);
3328 } else if (aEventType == NS_MOUSE_EXIT) {
3329 if (sCurrentWindow == this) {
3330 sCurrentWindow = nsnull;
3334 result = DispatchWindowEvent(&event);
3336 if (nsToolkit::gMouseTrailer)
3337 nsToolkit::gMouseTrailer->Enable();
3339 // Release the widget with NS_IF_RELEASE() just in case
3340 // the context menu key code in nsEventListenerManager::HandleEvent()
3341 // released it already.
3342 return result;
3345 return result;
3348 // Deal with accessibile event
3349 #ifdef ACCESSIBILITY
3350 PRBool nsWindow::DispatchAccessibleEvent(PRUint32 aEventType, nsIAccessible** aAcc, nsIntPoint* aPoint)
3352 PRBool result = PR_FALSE;
3354 if (nsnull == mEventCallback) {
3355 return result;
3358 *aAcc = nsnull;
3360 nsAccessibleEvent event(PR_TRUE, aEventType, this);
3361 InitEvent(event, aPoint);
3363 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
3364 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
3365 event.isMeta = PR_FALSE;
3366 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
3367 event.accessible = nsnull;
3369 result = DispatchWindowEvent(&event);
3371 // if the event returned an accesssible get it.
3372 if (event.accessible)
3373 *aAcc = event.accessible;
3375 return result;
3377 #endif
3379 PRBool nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType)
3381 if (aEventType == NS_ACTIVATE)
3382 sJustGotActivate = PR_FALSE;
3383 sJustGotDeactivate = PR_FALSE;
3385 // clear the flags, and retrieve the toplevel window. This way, it doesn't
3386 // mattter what child widget received the focus event and it will always be
3387 // fired at the toplevel window.
3388 HWND toplevelWnd = GetTopLevelHWND(mWnd);
3389 if (toplevelWnd) {
3390 nsWindow *win = GetNSWindowPtr(toplevelWnd);
3391 if (win)
3392 return win->DispatchFocus(aEventType);
3395 return PR_FALSE;
3398 // Deal with focus messages
3399 PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
3401 // call the event callback
3402 if (mEventCallback) {
3403 nsGUIEvent event(PR_TRUE, aEventType, this);
3404 InitEvent(event);
3406 //focus and blur event should go to their base widget loc, not current mouse pos
3407 event.refPoint.x = 0;
3408 event.refPoint.y = 0;
3410 NPEvent pluginEvent;
3412 switch (aEventType)
3414 case NS_ACTIVATE:
3415 pluginEvent.event = WM_SETFOCUS;
3416 break;
3417 case NS_DEACTIVATE:
3418 pluginEvent.event = WM_KILLFOCUS;
3419 break;
3420 case NS_PLUGIN_ACTIVATE:
3421 pluginEvent.event = WM_KILLFOCUS;
3422 break;
3423 default:
3424 break;
3427 event.pluginEvent = (void *)&pluginEvent;
3429 return DispatchWindowEvent(&event);
3431 return PR_FALSE;
3434 PRBool nsWindow::IsTopLevelMouseExit(HWND aWnd)
3436 DWORD pos = ::GetMessagePos();
3437 POINT mp;
3438 mp.x = GET_X_LPARAM(pos);
3439 mp.y = GET_Y_LPARAM(pos);
3440 HWND mouseWnd = ::WindowFromPoint(mp);
3442 // GetTopLevelHWND will return a HWND for the window frame (which includes
3443 // the non-client area). If the mouse has moved into the non-client area,
3444 // we should treat it as a top-level exit.
3445 HWND mouseTopLevel = nsWindow::GetTopLevelHWND(mouseWnd);
3446 if (mouseWnd == mouseTopLevel)
3447 return PR_TRUE;
3449 return nsWindow::GetTopLevelHWND(aWnd) != mouseTopLevel;
3452 PRBool nsWindow::BlurEventsSuppressed()
3454 // are they suppressed in this window?
3455 if (mBlurSuppressLevel > 0)
3456 return PR_TRUE;
3458 // are they suppressed by any container widget?
3459 HWND parentWnd = ::GetParent(mWnd);
3460 if (parentWnd) {
3461 nsWindow *parent = GetNSWindowPtr(parentWnd);
3462 if (parent)
3463 return parent->BlurEventsSuppressed();
3465 return PR_FALSE;
3468 // In some circumstances (opening dependent windows) it makes more sense
3469 // (and fixes a crash bug) to not blur the parent window. Called from
3470 // nsFilePicker.
3471 void nsWindow::SuppressBlurEvents(PRBool aSuppress)
3473 if (aSuppress)
3474 ++mBlurSuppressLevel; // for this widget
3475 else {
3476 NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression");
3477 if (mBlurSuppressLevel > 0)
3478 --mBlurSuppressLevel;
3482 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
3484 return aStatus == nsEventStatus_eConsumeNoDefault;
3487 /**************************************************************
3488 **************************************************************
3490 ** BLOCK: Native events
3492 ** Main Windows message handlers and OnXXX handlers for
3493 ** Windows event handling.
3495 **************************************************************
3496 **************************************************************/
3498 /**************************************************************
3500 * SECTION: Wind proc.
3502 * The main Windows event procedures and associated
3503 * message processing methods.
3505 **************************************************************/
3507 // The WndProc procedure for all nsWindows in this toolkit
3508 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
3510 // create this here so that we store the last rolled up popup until after
3511 // the event has been processed.
3512 nsAutoRollup autoRollup;
3514 LRESULT popupHandlingResult;
3515 if ( DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult) )
3516 return popupHandlingResult;
3518 // Get the window which caused the event and ask it to process the message
3519 nsWindow *someWindow = GetNSWindowPtr(hWnd);
3521 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
3522 // why we are hitting this assert
3523 if (nsnull == someWindow) {
3524 NS_ASSERTION(someWindow, "someWindow is null, cannot call any CallWindowProc");
3525 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
3528 // hold on to the window for the life of this method, in case it gets
3529 // deleted during processing. yes, it's a double hack, since someWindow
3530 // is not really an interface.
3531 nsCOMPtr<nsISupports> kungFuDeathGrip;
3532 if (!someWindow->mInDtor) // not if we're in the destructor!
3533 kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)someWindow);
3535 // Re-direct a tab change message destined for its parent window to the
3536 // the actual window which generated the event.
3537 if (msg == WM_NOTIFY) {
3538 LPNMHDR pnmh = (LPNMHDR) lParam;
3539 if (pnmh->code == TCN_SELCHANGE) {
3540 someWindow = GetNSWindowPtr(pnmh->hwndFrom);
3544 // Call ProcessMessage
3545 if (nsnull != someWindow) {
3546 LRESULT retValue;
3547 if (PR_TRUE == someWindow->ProcessMessage(msg, wParam, lParam, &retValue)) {
3548 return retValue;
3552 return ::CallWindowProcW(someWindow->GetPrevWindowProc(),
3553 hWnd, msg, wParam, lParam);
3556 // The main windows message processing method for plugins.
3557 // The result means whether this method processed the native
3558 // event for plugin. If false, the native event should be
3559 // processed by the caller self.
3560 PRBool
3561 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
3562 LRESULT *aResult,
3563 PRBool &aCallDefWndProc)
3565 NS_PRECONDITION(aResult, "aResult must be non-null.");
3566 *aResult = 0;
3568 aCallDefWndProc = PR_FALSE;
3569 PRBool fallBackToNonPluginProcess = PR_FALSE;
3570 PRBool eventDispatched = PR_FALSE;
3571 PRBool dispatchPendingEvents = PR_TRUE;
3572 switch (aMsg.message) {
3573 case WM_INPUTLANGCHANGEREQUEST:
3574 case WM_INPUTLANGCHANGE:
3575 DispatchPluginEvent(aMsg);
3576 return PR_FALSE; // go to non-plug-ins processing
3578 case WM_CHAR:
3579 case WM_SYSCHAR:
3580 *aResult = ProcessCharMessage(aMsg, &eventDispatched);
3581 break;
3583 case WM_KEYUP:
3584 case WM_SYSKEYUP:
3585 *aResult = ProcessKeyUpMessage(aMsg, &eventDispatched);
3586 break;
3588 case WM_KEYDOWN:
3589 case WM_SYSKEYDOWN:
3590 *aResult = ProcessKeyDownMessage(aMsg, &eventDispatched);
3591 break;
3593 case WM_DEADCHAR:
3594 case WM_SYSDEADCHAR:
3595 case WM_CONTEXTMENU:
3597 case WM_CUT:
3598 case WM_COPY:
3599 case WM_PASTE:
3600 case WM_CLEAR:
3601 case WM_UNDO:
3603 case WM_IME_STARTCOMPOSITION:
3604 case WM_IME_COMPOSITION:
3605 case WM_IME_ENDCOMPOSITION:
3606 case WM_IME_CHAR:
3607 case WM_IME_COMPOSITIONFULL:
3608 case WM_IME_CONTROL:
3609 case WM_IME_KEYDOWN:
3610 case WM_IME_KEYUP:
3611 case WM_IME_NOTIFY:
3612 case WM_IME_REQUEST:
3613 case WM_IME_SELECT:
3614 break;
3616 case WM_IME_SETCONTEXT:
3617 // Don't synchronously dispatch when we receive WM_IME_SETCONTEXT
3618 // because we get it during plugin destruction. (bug 491848)
3619 dispatchPendingEvents = PR_FALSE;
3620 break;
3622 default:
3623 return PR_FALSE;
3626 if (!eventDispatched)
3627 aCallDefWndProc = !DispatchPluginEvent(aMsg);
3628 if (dispatchPendingEvents)
3629 DispatchPendingEvents();
3630 return PR_TRUE;
3633 // The main windows message processing method.
3634 PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
3635 LRESULT *aRetValue)
3637 // (Large blocks of code should be broken out into OnEvent handlers.)
3638 if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
3639 return PR_TRUE;
3641 PRBool eatMessage;
3642 if (nsIMM32Handler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
3643 eatMessage)) {
3644 return mWnd ? eatMessage : PR_TRUE;
3647 if (PluginHasFocus()) {
3648 PRBool callDefaultWndProc;
3649 MSG nativeMsg = InitMSG(msg, wParam, lParam);
3650 if (ProcessMessageForPlugin(nativeMsg, aRetValue, callDefaultWndProc)) {
3651 return mWnd ? !callDefaultWndProc : PR_TRUE;
3655 static UINT vkKeyCached = 0; // caches VK code fon WM_KEYDOWN
3656 PRBool result = PR_FALSE; // call the default nsWindow proc
3657 *aRetValue = 0;
3659 static PRBool getWheelInfo = PR_TRUE;
3661 #if defined(EVENT_DEBUG_OUTPUT)
3662 // First param shows all events, second param indicates whether
3663 // to show mouse move events. See nsWindowDbg for details.
3664 PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
3665 #endif
3667 switch (msg) {
3668 case WM_COMMAND:
3670 WORD wNotifyCode = HIWORD(wParam); // notification code
3671 if ((CBN_SELENDOK == wNotifyCode) || (CBN_SELENDCANCEL == wNotifyCode)) { // Combo box change
3672 nsGUIEvent event(PR_TRUE, NS_CONTROL_CHANGE, this);
3673 nsIntPoint point(0,0);
3674 InitEvent(event, &point); // this add ref's event.widget
3675 result = DispatchWindowEvent(&event);
3676 } else if (wNotifyCode == 0) { // Menu selection
3677 nsMenuEvent event(PR_TRUE, NS_MENU_SELECTED, this);
3678 event.mCommand = LOWORD(wParam);
3679 InitEvent(event);
3680 result = DispatchWindowEvent(&event);
3683 break;
3685 #ifndef WINCE
3686 // WM_QUERYENDSESSION must be handled by all windows.
3687 // Otherwise Windows thinks the window can just be killed at will.
3688 case WM_QUERYENDSESSION:
3689 if (sCanQuit == TRI_UNKNOWN)
3691 // Ask if it's ok to quit, and store the answer until we
3692 // get WM_ENDSESSION signaling the round is complete.
3693 nsCOMPtr<nsIObserverService> obsServ =
3694 do_GetService("@mozilla.org/observer-service;1");
3695 nsCOMPtr<nsISupportsPRBool> cancelQuit =
3696 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
3697 cancelQuit->SetData(PR_FALSE);
3698 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
3700 PRBool abortQuit;
3701 cancelQuit->GetData(&abortQuit);
3702 sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
3704 *aRetValue = sCanQuit ? TRUE : FALSE;
3705 result = PR_TRUE;
3706 break;
3707 #endif
3709 #ifndef WINCE
3710 case WM_ENDSESSION:
3711 #endif
3712 case MOZ_WM_APP_QUIT:
3713 if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE))
3715 // Let's fake a shutdown sequence without actually closing windows etc.
3716 // to avoid Windows killing us in the middle. A proper shutdown would
3717 // require having a chance to pump some messages. Unfortunately
3718 // Windows won't let us do that. Bug 212316.
3719 nsCOMPtr<nsIObserverService> obsServ =
3720 do_GetService("@mozilla.org/observer-service;1");
3721 NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
3722 obsServ->NotifyObservers(nsnull, "quit-application-granted", nsnull);
3723 obsServ->NotifyObservers(nsnull, "quit-application-forced", nsnull);
3724 obsServ->NotifyObservers(nsnull, "quit-application", nsnull);
3725 obsServ->NotifyObservers(nsnull, "profile-change-net-teardown", context.get());
3726 obsServ->NotifyObservers(nsnull, "profile-change-teardown", context.get());
3727 obsServ->NotifyObservers(nsnull, "profile-before-change", context.get());
3728 // Then a controlled but very quick exit.
3729 _exit(0);
3731 sCanQuit = TRI_UNKNOWN;
3732 result = PR_TRUE;
3733 break;
3735 #ifndef WINCE
3736 case WM_DISPLAYCHANGE:
3737 DispatchStandardEvent(NS_DISPLAYCHANGED);
3738 break;
3739 #endif
3741 case WM_SYSCOLORCHANGE:
3742 // Note: This is sent for child windows as well as top-level windows.
3743 // The Win32 toolkit normally only sends these events to top-level windows.
3744 // But we cycle through all of the childwindows and send it to them as well
3745 // so all presentations get notified properly.
3746 // See nsWindow::GlobalMsgWindowProc.
3747 DispatchStandardEvent(NS_SYSCOLORCHANGED);
3748 break;
3750 case WM_NOTIFY:
3751 // TAB change
3753 LPNMHDR pnmh = (LPNMHDR) lParam;
3755 switch (pnmh->code) {
3756 case TCN_SELCHANGE:
3758 DispatchStandardEvent(NS_TABCHANGE);
3759 result = PR_TRUE;
3761 break;
3764 break;
3766 case WM_XP_THEMECHANGED:
3768 DispatchStandardEvent(NS_THEMECHANGED);
3770 // Invalidate the window so that the repaint will
3771 // pick up the new theme.
3772 Invalidate(PR_FALSE);
3774 break;
3776 case WM_FONTCHANGE:
3778 nsresult rv;
3779 PRBool didChange = PR_FALSE;
3781 // update the global font list
3782 nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
3783 if (NS_SUCCEEDED(rv)) {
3784 fontEnum->UpdateFontList(&didChange);
3785 //didChange is TRUE only if new font langGroup is added to the list.
3786 if (didChange) {
3787 // update device context font cache
3788 // Dirty but easiest way:
3789 // Changing nsIPrefBranch entry which triggers callbacks
3790 // and flows into calling mDeviceContext->FlushFontCache()
3791 // to update the font cache in all the instance of Browsers
3792 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3793 if (prefs) {
3794 nsCOMPtr<nsIPrefBranch> fiPrefs;
3795 prefs->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs));
3796 if (fiPrefs) {
3797 PRBool fontInternalChange = PR_FALSE;
3798 fiPrefs->GetBoolPref("changed", &fontInternalChange);
3799 fiPrefs->SetBoolPref("changed", !fontInternalChange);
3803 } //if (NS_SUCCEEDED(rv))
3805 break;
3807 #ifndef WINCE
3808 case WM_POWERBROADCAST:
3809 // only hidden window handle this
3810 // to prevent duplicate notification
3811 if (mWindowType == eWindowType_invisible) {
3812 switch (wParam)
3814 case PBT_APMSUSPEND:
3815 PostSleepWakeNotification("sleep_notification");
3816 break;
3817 case PBT_APMRESUMEAUTOMATIC:
3818 case PBT_APMRESUMECRITICAL:
3819 case PBT_APMRESUMESUSPEND:
3820 PostSleepWakeNotification("wake_notification");
3821 break;
3824 break;
3825 #endif
3827 case WM_MOVE: // Window moved
3829 PRInt32 x = GET_X_LPARAM(lParam); // horizontal position in screen coordinates
3830 PRInt32 y = GET_Y_LPARAM(lParam); // vertical position in screen coordinates
3831 result = OnMove(x, y);
3833 break;
3835 case WM_CLOSE: // close request
3836 DispatchStandardEvent(NS_XUL_CLOSE);
3837 result = PR_TRUE; // abort window closure
3838 break;
3840 case WM_DESTROY:
3841 // clean up.
3842 OnDestroy();
3843 result = PR_TRUE;
3844 break;
3846 case WM_PAINT:
3847 *aRetValue = (int) OnPaint();
3848 result = PR_TRUE;
3849 break;
3851 #ifndef WINCE
3852 case WM_PRINTCLIENT:
3853 result = OnPaint((HDC) wParam);
3854 break;
3855 #endif
3857 case WM_HOTKEY:
3858 result = OnHotKey(wParam, lParam);
3859 break;
3861 case WM_SYSCHAR:
3862 case WM_CHAR:
3864 MSG nativeMsg = InitMSG(msg, wParam, lParam);
3865 result = ProcessCharMessage(nativeMsg, nsnull);
3866 DispatchPendingEvents();
3868 break;
3870 case WM_SYSKEYUP:
3871 case WM_KEYUP:
3873 MSG nativeMsg = InitMSG(msg, wParam, lParam);
3874 result = ProcessKeyUpMessage(nativeMsg, nsnull);
3875 DispatchPendingEvents();
3877 break;
3879 case WM_SYSKEYDOWN:
3880 case WM_KEYDOWN:
3882 MSG nativeMsg = InitMSG(msg, wParam, lParam);
3883 result = ProcessKeyDownMessage(nativeMsg, nsnull);
3884 DispatchPendingEvents();
3886 break;
3888 // say we've dealt with erase background if widget does
3889 // not need auto-erasing
3890 case WM_ERASEBKGND:
3891 if (!AutoErase((HDC)wParam)) {
3892 *aRetValue = 1;
3893 result = PR_TRUE;
3895 break;
3897 case WM_GETDLGCODE:
3898 *aRetValue = DLGC_WANTALLKEYS;
3899 result = PR_TRUE;
3900 break;
3902 case WM_MOUSEMOVE:
3904 #ifdef WINCE_WINDOWS_MOBILE
3905 // Reset the kill timer so that we can continue at this
3906 // priority
3907 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2seconds */, NULL);
3908 #endif
3909 // Suppress dispatch of pending events
3910 // when mouse moves are generated by widget
3911 // creation instead of user input.
3912 LPARAM lParamScreen = lParamToScreen(lParam);
3913 POINT mp;
3914 mp.x = GET_X_LPARAM(lParamScreen);
3915 mp.y = GET_Y_LPARAM(lParamScreen);
3916 PRBool userMovedMouse = PR_FALSE;
3917 if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) {
3918 userMovedMouse = PR_TRUE;
3921 result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam);
3922 if (userMovedMouse) {
3923 DispatchPendingEvents();
3926 break;
3928 #ifdef WINCE_WINDOWS_MOBILE
3929 case WM_TIMER:
3930 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
3931 KillTimer(mWnd, KILL_PRIORITY_ID);
3932 break;
3933 #endif
3935 case WM_LBUTTONDOWN:
3937 #ifdef WINCE_WINDOWS_MOBILE
3938 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
3939 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2 seconds */, NULL);
3940 #endif
3941 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
3942 PR_FALSE, nsMouseEvent::eLeftButton);
3943 DispatchPendingEvents();
3945 break;
3947 case WM_LBUTTONUP:
3949 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam,
3950 PR_FALSE, nsMouseEvent::eLeftButton);
3951 DispatchPendingEvents();
3953 #ifdef WINCE_WINDOWS_MOBILE
3954 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
3955 KillTimer(mWnd, KILL_PRIORITY_ID);
3956 #endif
3958 break;
3960 #ifndef WINCE
3961 case WM_MOUSELEAVE:
3963 // We need to check mouse button states and put them in for
3964 // wParam.
3965 WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
3966 | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
3967 | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
3968 // Synthesize an event position because we don't get one from
3969 // WM_MOUSELEAVE.
3970 LPARAM pos = lParamToClient(::GetMessagePos());
3971 DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos);
3973 break;
3974 #endif
3976 case WM_CONTEXTMENU:
3978 // if the context menu is brought up from the keyboard, |lParam|
3979 // will be maxlong.
3980 LPARAM pos;
3981 PRBool contextMenukey = PR_FALSE;
3982 if (lParam == 0xFFFFFFFF)
3984 contextMenukey = PR_TRUE;
3985 pos = lParamToClient(GetMessagePos());
3987 else
3989 pos = lParamToClient(lParam);
3991 result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey,
3992 contextMenukey ?
3993 nsMouseEvent::eLeftButton :
3994 nsMouseEvent::eRightButton);
3996 break;
3998 case WM_LBUTTONDBLCLK:
3999 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4000 nsMouseEvent::eLeftButton);
4001 break;
4003 case WM_MBUTTONDOWN:
4005 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4006 nsMouseEvent::eMiddleButton);
4007 DispatchPendingEvents();
4009 break;
4011 case WM_MBUTTONUP:
4012 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4013 nsMouseEvent::eMiddleButton);
4014 DispatchPendingEvents();
4015 break;
4017 case WM_MBUTTONDBLCLK:
4018 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4019 nsMouseEvent::eMiddleButton);
4020 break;
4022 case WM_RBUTTONDOWN:
4024 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4025 nsMouseEvent::eRightButton);
4026 DispatchPendingEvents();
4028 break;
4030 case WM_RBUTTONUP:
4031 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4032 nsMouseEvent::eRightButton);
4033 DispatchPendingEvents();
4034 break;
4036 case WM_RBUTTONDBLCLK:
4037 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4038 nsMouseEvent::eRightButton);
4039 break;
4041 case WM_APPCOMMAND:
4043 PRUint32 appCommand = GET_APPCOMMAND_LPARAM(lParam);
4045 switch (appCommand)
4047 case APPCOMMAND_BROWSER_BACKWARD:
4048 case APPCOMMAND_BROWSER_FORWARD:
4049 case APPCOMMAND_BROWSER_REFRESH:
4050 case APPCOMMAND_BROWSER_STOP:
4051 case APPCOMMAND_BROWSER_SEARCH:
4052 case APPCOMMAND_BROWSER_FAVORITES:
4053 case APPCOMMAND_BROWSER_HOME:
4054 DispatchCommandEvent(appCommand);
4055 // tell the driver that we handled the event
4056 *aRetValue = 1;
4057 result = PR_TRUE;
4058 break;
4060 // default = PR_FALSE - tell the driver that the event was not handled
4062 break;
4064 case WM_HSCROLL:
4065 case WM_VSCROLL:
4066 // check for the incoming nsWindow handle to be null in which case
4067 // we assume the message is coming from a horizontal scrollbar inside
4068 // a listbox and we don't bother processing it (well, we don't have to)
4069 if (lParam) {
4070 nsWindow* scrollbar = GetNSWindowPtr((HWND)lParam);
4072 if (scrollbar) {
4073 result = scrollbar->OnScroll(msg, wParam, lParam);
4076 break;
4078 case WM_CTLCOLORLISTBOX:
4079 case WM_CTLCOLOREDIT:
4080 case WM_CTLCOLORBTN:
4081 //case WM_CTLCOLORSCROLLBAR: //XXX causes the scrollbar to be drawn incorrectly
4082 case WM_CTLCOLORSTATIC:
4083 if (lParam) {
4084 nsWindow* control = GetNSWindowPtr((HWND)lParam);
4085 if (control) {
4086 control->SetUpForPaint((HDC)wParam);
4087 *aRetValue = (LPARAM)control->OnControlColor();
4091 result = PR_TRUE;
4092 break;
4094 // The WM_ACTIVATE event is fired when a window is raised or lowered,
4095 // and the loword of wParam specifies which. But we don't want to tell
4096 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
4097 // events are fired. Instead, set either the sJustGotActivate or
4098 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
4099 // events once the focus events arrive.
4100 case WM_ACTIVATE:
4101 if (mEventCallback) {
4102 PRInt32 fActive = LOWORD(wParam);
4104 #if defined(WINCE_HAVE_SOFTKB)
4105 if (mIsTopWidgetWindow && sSoftKeyboardState)
4106 nsWindowCE::ToggleSoftKB(fActive);
4107 if (nsWindowCE::sShowSIPButton != TRI_TRUE && WA_INACTIVE != fActive) {
4108 HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL );
4109 if (hWndSIPB)
4110 ShowWindow(hWndSIPB, SW_HIDE);
4113 #endif
4115 if (WA_INACTIVE == fActive) {
4116 // when minimizing a window, the deactivation and focus events will
4117 // be fired in the reverse order. Instead, just dispatch
4118 // NS_DEACTIVATE right away.
4119 if (HIWORD(wParam))
4120 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
4121 else
4122 sJustGotDeactivate = PR_TRUE;
4123 #ifndef WINCE
4124 if (mIsTopWidgetWindow)
4125 mLastKeyboardLayout = gKbdLayout.GetLayout();
4126 #endif
4128 } else {
4129 StopFlashing();
4131 sJustGotActivate = PR_TRUE;
4132 nsMouseEvent event(PR_TRUE, NS_MOUSE_ACTIVATE, this,
4133 nsMouseEvent::eReal);
4134 InitEvent(event);
4136 event.acceptActivation = PR_TRUE;
4138 PRBool result = DispatchWindowEvent(&event);
4139 #ifndef WINCE
4140 if (event.acceptActivation)
4141 *aRetValue = MA_ACTIVATE;
4142 else
4143 *aRetValue = MA_NOACTIVATE;
4145 if (sSwitchKeyboardLayout && mLastKeyboardLayout)
4146 ActivateKeyboardLayout(mLastKeyboardLayout, 0);
4147 #else
4148 *aRetValue = 0;
4149 #endif
4150 if (mSizeMode == nsSizeMode_Fullscreen)
4151 MakeFullScreen(TRUE);
4154 #ifdef WINCE_WINDOWS_MOBILE
4155 if (!gCheckForHTCApi && gHTCApiNavOpen == nsnull) {
4156 gCheckForHTCApi = PR_TRUE;
4158 HINSTANCE library = LoadLibrary(L"HTCAPI.dll");
4159 gHTCApiNavOpen = (HTCApiNavOpen) GetProcAddress(library, "HTCNavOpen");
4160 gHTCApiNavSetMode = (HTCApiNavSetMode) GetProcAddress(library ,"HTCNavSetMode");
4163 if (gHTCApiNavOpen != nsnull) {
4164 gHTCApiNavOpen(mWnd, 1 /* undocumented value */);
4166 if (gHTCApiNavSetMode != nsnull)
4167 gHTCApiNavSetMode ( mWnd, 4);
4168 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
4170 #endif
4171 break;
4173 #ifndef WINCE
4174 case WM_MOUSEACTIVATE:
4175 if (mWindowType == eWindowType_popup) {
4176 // a popup with a parent owner should not be activated when clicked
4177 // but should still allow the mouse event to be fired, so the return
4178 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
4179 // window, just use default processing so that the window is activated.
4180 HWND owner = ::GetWindow(mWnd, GW_OWNER);
4181 if (owner && owner == ::GetForegroundWindow()) {
4182 *aRetValue = MA_NOACTIVATE;
4183 result = PR_TRUE;
4186 break;
4188 case WM_WINDOWPOSCHANGING:
4190 LPWINDOWPOS info = (LPWINDOWPOS) lParam;
4191 OnWindowPosChanging(info);
4193 break;
4194 #endif
4196 case WM_SETFOCUS:
4197 if (sJustGotActivate) {
4198 result = DispatchFocusToTopLevelWindow(NS_ACTIVATE);
4201 #ifdef ACCESSIBILITY
4202 if (nsWindow::sIsAccessibilityOn) {
4203 // Create it for the first time so that it can start firing events
4204 nsCOMPtr<nsIAccessible> rootAccessible = GetRootAccessible();
4206 #endif
4208 #if defined(WINCE_HAVE_SOFTKB)
4210 // On Windows CE, we have a window that overlaps
4211 // the ISP button. In this case, we should always
4212 // try to hide it when we are activated
4214 nsIMEContext IMEContext(mWnd);
4215 // Open the IME
4216 ImmSetOpenStatus(IMEContext.get(), TRUE);
4218 #endif
4219 break;
4221 case WM_KILLFOCUS:
4222 #if defined(WINCE_HAVE_SOFTKB)
4224 nsIMEContext IMEContext(mWnd);
4225 ImmSetOpenStatus(IMEContext.get(), FALSE);
4227 #endif
4228 if (sJustGotDeactivate) {
4229 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
4231 break;
4233 case WM_WINDOWPOSCHANGED:
4235 WINDOWPOS *wp = (LPWINDOWPOS)lParam;
4236 OnWindowPosChanged(wp, result);
4238 break;
4240 case WM_SETTINGCHANGE:
4241 #if !defined (WINCE_WINDOWS_MOBILE)
4242 getWheelInfo = PR_TRUE;
4243 #else
4244 switch (wParam) {
4245 case SPI_SIPMOVE:
4246 case SPI_SETSIPINFO:
4247 case SPI_SETCURRENTIM:
4248 nsWindowCE::NotifySoftKbObservers();
4249 break;
4250 case SETTINGCHANGE_RESET:
4251 if (mWindowType == eWindowType_invisible) {
4252 // The OS sees to get confused and think that the invisable window
4253 // is in the foreground after an orientation change. By actually
4254 // setting it to the foreground and hiding it, we set it strait.
4255 // See bug 514007 for details.
4256 SetForegroundWindow(mWnd);
4257 ShowWindow(mWnd, SW_HIDE);
4259 break;
4261 #endif
4262 OnSettingsChange(wParam, lParam);
4263 break;
4265 #ifndef WINCE
4266 case WM_INPUTLANGCHANGEREQUEST:
4267 *aRetValue = TRUE;
4268 result = PR_FALSE;
4269 break;
4271 case WM_INPUTLANGCHANGE:
4272 result = OnInputLangChange((HKL)lParam);
4273 break;
4274 #endif // WINCE
4276 case WM_DESTROYCLIPBOARD:
4278 nsIClipboard* clipboard;
4279 nsresult rv = CallGetService(kCClipboardCID, &clipboard);
4280 clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
4281 NS_RELEASE(clipboard);
4283 break;
4285 #ifdef ACCESSIBILITY
4286 case WM_GETOBJECT:
4288 *aRetValue = 0;
4289 if (lParam == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
4290 nsCOMPtr<nsIAccessible> rootAccessible = GetRootAccessible(); // Held by a11y cache
4291 if (rootAccessible) {
4292 IAccessible *msaaAccessible = NULL;
4293 rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref
4294 if (msaaAccessible) {
4295 *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref
4296 msaaAccessible->Release(); // release extra addref
4297 result = PR_TRUE; // We handled the WM_GETOBJECT message
4302 #endif
4304 #ifndef WINCE
4305 case WM_SYSCOMMAND:
4306 // prevent Windows from trimming the working set. bug 76831
4307 if (!sTrimOnMinimize && wParam == SC_MINIMIZE) {
4308 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
4309 result = PR_TRUE;
4311 break;
4312 #endif
4315 #ifdef WINCE
4316 case WM_HIBERNATE:
4317 nsMemory::HeapMinimize(PR_TRUE);
4318 break;
4319 #endif
4321 case WM_MOUSEWHEEL:
4322 case WM_MOUSEHWHEEL:
4324 // If OnMouseWheel returns true, the event was forwarded directly to another
4325 // mozilla window message handler (ProcessMessage). In this case the return
4326 // value of the forwarded event is in 'result' which we should return immediately.
4327 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
4328 // 'result' and 'aRetValue' will be set based on what we did with the event, so
4329 // we should fall through.
4330 if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue))
4331 return result;
4333 break;
4335 #ifndef WINCE
4336 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4337 case WM_DWMCOMPOSITIONCHANGED:
4338 BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
4339 DispatchStandardEvent(NS_THEMECHANGED);
4340 if (nsUXThemeData::CheckForCompositor() && mTransparencyMode == eTransparencyGlass) {
4341 MARGINS margins = { -1, -1, -1, -1 };
4342 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(mWnd, &margins);
4344 Invalidate(PR_FALSE);
4345 break;
4346 #endif
4348 /* Gesture support events */
4349 case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
4350 // According to MS samples, this must be handled to enable
4351 // rotational support in multi-touch drivers.
4352 result = PR_TRUE;
4353 *aRetValue = TABLET_ROTATE_GESTURE_ENABLE;
4354 break;
4356 case WM_GESTURE:
4357 result = OnGesture(wParam, lParam);
4358 break;
4360 case WM_GESTURENOTIFY:
4362 if (mWindowType != eWindowType_invisible &&
4363 mWindowType != eWindowType_plugin &&
4364 mWindowType != eWindowType_toplevel) {
4365 // eWindowType_toplevel is the top level main frame window. Gesture support
4366 // there prevents the user from interacting with the title bar or nc
4367 // areas using a single finger. Java and plugin windows can make their
4368 // own calls.
4369 GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
4370 nsPointWin touchPoint;
4371 touchPoint = gestureinfo->ptsLocation;
4372 touchPoint.ScreenToClient(mWnd);
4373 nsGestureNotifyEvent gestureNotifyEvent(PR_TRUE, NS_GESTURENOTIFY_EVENT_START, this);
4374 gestureNotifyEvent.refPoint = touchPoint;
4375 nsEventStatus status;
4376 DispatchEvent(&gestureNotifyEvent, status);
4377 mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
4378 mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
4380 result = PR_FALSE; //should always bubble to DefWindowProc
4382 break;
4383 #endif // !defined(WINCE)
4385 case WM_CLEAR:
4387 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_DELETE, this);
4388 DispatchWindowEvent(&command);
4389 result = PR_TRUE;
4391 break;
4393 case WM_CUT:
4395 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_CUT, this);
4396 DispatchWindowEvent(&command);
4397 result = PR_TRUE;
4399 break;
4401 case WM_COPY:
4403 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_COPY, this);
4404 DispatchWindowEvent(&command);
4405 result = PR_TRUE;
4407 break;
4409 case WM_PASTE:
4411 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE, this);
4412 DispatchWindowEvent(&command);
4413 result = PR_TRUE;
4415 break;
4417 #ifndef WINCE
4418 case EM_UNDO:
4420 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO, this);
4421 DispatchWindowEvent(&command);
4422 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
4423 result = PR_TRUE;
4425 break;
4427 case EM_REDO:
4429 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO, this);
4430 DispatchWindowEvent(&command);
4431 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
4432 result = PR_TRUE;
4434 break;
4436 case EM_CANPASTE:
4438 // Support EM_CANPASTE message only when wParam isn't specified or
4439 // is plain text format.
4440 if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
4441 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE,
4442 this, PR_TRUE);
4443 DispatchWindowEvent(&command);
4444 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
4445 result = PR_TRUE;
4448 break;
4450 case EM_CANUNDO:
4452 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO,
4453 this, PR_TRUE);
4454 DispatchWindowEvent(&command);
4455 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
4456 result = PR_TRUE;
4458 break;
4460 case EM_CANREDO:
4462 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO,
4463 this, PR_TRUE);
4464 DispatchWindowEvent(&command);
4465 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
4466 result = PR_TRUE;
4468 break;
4469 #endif
4471 #ifdef WINCE_WINDOWS_MOBILE
4472 //HTC NAVIGATION WHEEL EVENT
4473 case WM_HTCNAV:
4475 int distance = wParam & 0x000000FF;
4476 if ( (wParam & 0x000000100) != 0) // Counter Clockwise
4477 distance *= -1;
4478 if (OnMouseWheel(WM_MOUSEWHEEL, MAKEWPARAM(0, distance),
4479 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN) / 2,
4480 GetSystemMetrics(SM_CYSCREEN) / 2),
4481 getWheelInfo, result, aRetValue))
4482 return result;
4484 break;
4485 #endif
4487 default:
4489 #ifdef NS_ENABLE_TSF
4490 if (msg == WM_USER_TSF_TEXTCHANGE) {
4491 nsTextStore::OnTextChangeMsg();
4493 #endif //NS_ENABLE_TSF
4494 #if defined(HEAP_DUMP_EVENT)
4495 if (msg == GetHeapMsg()) {
4496 HeapDump(msg, wParam, lParam);
4497 result = PR_TRUE;
4499 #endif
4500 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
4501 if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
4502 SetHasTaskbarIconBeenCreated();
4503 #endif
4505 break;
4508 //*aRetValue = result;
4509 if (mWnd) {
4510 return result;
4512 else {
4513 //Events which caused mWnd destruction and aren't consumed
4514 //will crash during the Windows default processing.
4515 return PR_TRUE;
4519 /**************************************************************
4521 * SECTION: Broadcast messaging
4523 * Broadcast messages to all windows.
4525 **************************************************************/
4527 // Enumerate all child windows sending aMsg to each of them
4528 BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg)
4530 WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
4531 if (winProc == &nsWindow::WindowProc) {
4532 // it's one of our windows so go ahead and send a message to it
4533 ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0);
4535 return TRUE;
4538 // Enumerate all top level windows specifying that the children of each
4539 // top level window should be enumerated. Do *not* send the message to
4540 // each top level window since it is assumed that the toolkit will send
4541 // aMsg to them directly.
4542 BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg)
4544 // Iterate each of aTopWindows child windows sending the aMsg
4545 // to each of them.
4546 #if !defined(WINCE)
4547 ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
4548 #else
4549 nsWindowCE::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
4550 #endif
4551 return TRUE;
4554 // This method is called from nsToolkit::WindowProc to forward global
4555 // messages which need to be dispatched to all child windows.
4556 void nsWindow::GlobalMsgWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4558 switch (msg) {
4559 case WM_SYSCOLORCHANGE:
4560 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
4561 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
4562 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
4563 // all child windows as well. When running in an embedded application
4564 // we may not receive a WM_SYSCOLORCHANGE message because the top
4565 // level window is owned by the embeddor.
4566 // System color changes are posted to top-level windows only.
4567 // The NS_SYSCOLORCHANGE must be dispatched to all child
4568 // windows as well.
4569 #if !defined(WINCE)
4570 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, msg);
4571 #endif
4572 break;
4576 /**************************************************************
4578 * SECTION: Event processing helpers
4580 * Special processing for certain event types and
4581 * synthesized events.
4583 **************************************************************/
4585 #ifndef WINCE
4586 void nsWindow::PostSleepWakeNotification(const char* aNotification)
4588 nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
4589 if (observerService)
4591 observerService->NotifyObservers(nsnull, aNotification, nsnull);
4594 #endif
4596 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, PRBool *aEventDispatched)
4598 NS_PRECONDITION(aMsg.message == WM_CHAR || aMsg.message == WM_SYSCHAR,
4599 "message is not keydown event");
4600 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
4601 ("%s charCode=%d scanCode=%d\n",
4602 aMsg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
4603 aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF));
4605 // These must be checked here too as a lone WM_CHAR could be received
4606 // if a child window didn't handle it (for example Alt+Space in a content window)
4607 nsModifierKeyState modKeyState;
4608 return OnChar(aMsg, modKeyState, aEventDispatched);
4611 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, PRBool *aEventDispatched)
4613 NS_PRECONDITION(aMsg.message == WM_KEYUP || aMsg.message == WM_SYSKEYUP,
4614 "message is not keydown event");
4615 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
4616 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
4617 "WM_SYSKEYUP" : "WM_KEYUP", aMsg.wParam));
4619 nsModifierKeyState modKeyState;
4621 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
4622 // scan code. However, this breaks Alt+Num pad input.
4623 // MSDN states the following:
4624 // Typically, ToAscii performs the translation based on the
4625 // virtual-key code. In some cases, however, bit 15 of the
4626 // uScanCode parameter may be used to distinguish between a key
4627 // press and a key release. The scan code is used for
4628 // translating ALT+number key combinations.
4630 // ignore [shift+]alt+space so the OS can handle it
4631 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
4632 IS_VK_DOWN(NS_VK_SPACE)) {
4633 return FALSE;
4636 if (!nsIMM32Handler::IsComposing(this) &&
4637 (aMsg.message != WM_KEYUP || aMsg.message != VK_MENU)) {
4638 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
4639 // This helps avoid triggering the menu bar for ALT key accelerators used in
4640 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
4641 // to switch back to Mozilla in Windows 95 and Windows 98
4642 return OnKeyUp(aMsg, modKeyState, aEventDispatched);
4645 return 0;
4648 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
4649 PRBool *aEventDispatched)
4651 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
4652 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
4653 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg.wParam));
4654 NS_PRECONDITION(aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN,
4655 "message is not keydown event");
4657 nsModifierKeyState modKeyState;
4659 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
4660 // scan code. However, this breaks Alt+Num pad input.
4661 // MSDN states the following:
4662 // Typically, ToAscii performs the translation based on the
4663 // virtual-key code. In some cases, however, bit 15 of the
4664 // uScanCode parameter may be used to distinguish between a key
4665 // press and a key release. The scan code is used for
4666 // translating ALT+number key combinations.
4668 // ignore [shift+]alt+space so the OS can handle it
4669 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
4670 IS_VK_DOWN(NS_VK_SPACE))
4671 return FALSE;
4673 LRESULT result = 0;
4674 if (modKeyState.mIsAltDown && nsIMM32Handler::IsStatusChanged()) {
4675 nsIMM32Handler::NotifyEndStatusChange();
4676 } else if (!nsIMM32Handler::IsComposing(this)) {
4677 result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nsnull);
4680 #ifndef WINCE
4681 if (aMsg.wParam == VK_MENU ||
4682 (aMsg.wParam == VK_F10 && !modKeyState.mIsShiftDown)) {
4683 // We need to let Windows handle this keypress,
4684 // by returning PR_FALSE, if there's a native menu
4685 // bar somewhere in our containing window hierarchy.
4686 // Otherwise we handle the keypress and don't pass
4687 // it on to Windows, by returning PR_TRUE.
4688 PRBool hasNativeMenu = PR_FALSE;
4689 HWND hWnd = mWnd;
4690 while (hWnd) {
4691 if (::GetMenu(hWnd)) {
4692 hasNativeMenu = PR_TRUE;
4693 break;
4695 hWnd = ::GetParent(hWnd);
4697 result = !hasNativeMenu;
4699 #endif
4701 return result;
4704 nsresult
4705 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
4706 PRInt32 aNativeKeyCode,
4707 PRUint32 aModifierFlags,
4708 const nsAString& aCharacters,
4709 const nsAString& aUnmodifiedCharacters)
4711 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
4712 nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
4713 HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
4714 if (loadedLayout == NULL)
4715 return NS_ERROR_NOT_AVAILABLE;
4717 // Setup clean key state and load desired layout
4718 BYTE originalKbdState[256];
4719 ::GetKeyboardState(originalKbdState);
4720 BYTE kbdState[256];
4721 memset(kbdState, 0, sizeof(kbdState));
4722 // This changes the state of the keyboard for the current thread only,
4723 // and we'll restore it soon, so this should be OK.
4724 ::SetKeyboardState(kbdState);
4725 HKL oldLayout = gKbdLayout.GetLayout();
4726 gKbdLayout.LoadLayout(loadedLayout);
4728 nsAutoTArray<KeyPair,10> keySequence;
4729 SetupKeyModifiersSequence(&keySequence, aModifierFlags);
4730 NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
4731 "Native VK key code out of range");
4732 keySequence.AppendElement(KeyPair(aNativeKeyCode, 0));
4734 // Simulate the pressing of each modifier key and then the real key
4735 for (PRUint32 i = 0; i < keySequence.Length(); ++i) {
4736 PRUint8 key = keySequence[i].mGeneral;
4737 PRUint8 keySpecific = keySequence[i].mSpecific;
4738 kbdState[key] = 0x81; // key is down and toggled on if appropriate
4739 if (keySpecific) {
4740 kbdState[keySpecific] = 0x81;
4742 ::SetKeyboardState(kbdState);
4743 nsModifierKeyState modKeyState;
4744 MSG msg = InitMSG(WM_KEYDOWN, key, 0);
4745 if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
4746 UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
4747 gKbdLayout.GetLayout());
4748 nsFakeCharMessage fakeMsg = { aCharacters.CharAt(0), scanCode };
4749 OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
4750 } else {
4751 OnKeyDown(msg, modKeyState, nsnull, nsnull);
4754 for (PRUint32 i = keySequence.Length(); i > 0; --i) {
4755 PRUint8 key = keySequence[i - 1].mGeneral;
4756 PRUint8 keySpecific = keySequence[i - 1].mSpecific;
4757 kbdState[key] = 0; // key is up and toggled off if appropriate
4758 if (keySpecific) {
4759 kbdState[keySpecific] = 0;
4761 ::SetKeyboardState(kbdState);
4762 nsModifierKeyState modKeyState;
4763 MSG msg = InitMSG(WM_KEYUP, key, 0);
4764 OnKeyUp(msg, modKeyState, nsnull);
4767 // Restore old key state and layout
4768 ::SetKeyboardState(originalKbdState);
4769 gKbdLayout.LoadLayout(oldLayout);
4771 UnloadKeyboardLayout(loadedLayout);
4772 return NS_OK;
4773 #else //XXX: is there another way to do this?
4774 return NS_ERROR_NOT_IMPLEMENTED;
4775 #endif
4778 nsresult
4779 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
4780 PRUint32 aNativeMessage,
4781 PRUint32 aModifierFlags)
4783 #ifndef WINCE // I don't think WINCE supports SendInput
4784 RECT r;
4785 ::GetWindowRect(mWnd, &r);
4786 ::SetCursorPos(r.left + aPoint.x, r.top + aPoint.y);
4788 INPUT input;
4789 memset(&input, 0, sizeof(input));
4791 input.type = INPUT_MOUSE;
4792 input.mi.dwFlags = aNativeMessage;
4793 ::SendInput(1, &input, sizeof(INPUT));
4795 return NS_OK;
4796 #else
4797 return NS_ERROR_NOT_IMPLEMENTED;
4798 #endif
4801 /**************************************************************
4803 * SECTION: OnXXX message handlers
4805 * For message handlers that need to be broken out or
4806 * implemented in specific platform code.
4808 **************************************************************/
4810 BOOL nsWindow::OnInputLangChange(HKL aHKL)
4812 #ifdef KE_DEBUG
4813 printf("OnInputLanguageChange\n");
4814 #endif
4816 #ifndef WINCE
4817 gKbdLayout.LoadLayout(aHKL);
4818 #endif
4820 return PR_FALSE; // always pass to child window
4823 #if !defined(WINCE) // implemented in nsWindowCE.cpp
4824 void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, PRBool& result)
4826 if (wp == nsnull)
4827 return;
4829 #ifdef WINSTATE_DEBUG_OUTPUT
4830 if (mWnd == GetTopLevelHWND(mWnd))
4831 printf("*** OnWindowPosChanged: [ top] ");
4832 else
4833 printf("*** OnWindowPosChanged: [child] ");
4834 printf("WINDOWPOS flags:");
4835 if (wp->flags & SWP_FRAMECHANGED)
4836 printf("SWP_FRAMECHANGED ");
4837 if (wp->flags & SWP_SHOWWINDOW)
4838 printf("SWP_SHOWWINDOW ");
4839 if (wp->flags & SWP_NOSIZE)
4840 printf("SWP_NOSIZE ");
4841 if (wp->flags & SWP_HIDEWINDOW)
4842 printf("SWP_HIDEWINDOW ");
4843 printf("\n");
4844 #endif
4846 // Handle window size mode changes
4847 if (wp->flags & SWP_FRAMECHANGED) {
4848 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
4850 WINDOWPLACEMENT pl;
4851 pl.length = sizeof(pl);
4852 ::GetWindowPlacement(mWnd, &pl);
4854 if (pl.showCmd == SW_SHOWMAXIMIZED)
4855 event.mSizeMode = nsSizeMode_Maximized;
4856 else if (pl.showCmd == SW_SHOWMINIMIZED)
4857 event.mSizeMode = nsSizeMode_Minimized;
4858 else
4859 event.mSizeMode = nsSizeMode_Normal;
4861 // Windows has just changed the size mode of this window. The following
4862 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
4863 // set the min/max window state again or for nsSizeMode_Normal, call
4864 // SetWindow with a parameter of SW_RESTORE. There's no need however as
4865 // this window's mode has already changed. Updating mSizeMode here
4866 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
4867 // to window docking. (bug 489258)
4868 mSizeMode = event.mSizeMode;
4870 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
4871 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
4872 // prevents the working set from being trimmed but keeps the window active.
4873 // After the window is minimized, we need to do some touch up work on the
4874 // active window. (bugs 76831 & 499816)
4875 if (!sTrimOnMinimize && nsSizeMode_Minimized == event.mSizeMode)
4876 ActivateOtherWindowHelper(mWnd);
4878 #ifdef WINSTATE_DEBUG_OUTPUT
4879 switch (mSizeMode) {
4880 case nsSizeMode_Normal:
4881 printf("*** mSizeMode: nsSizeMode_Normal\n");
4882 break;
4883 case nsSizeMode_Minimized:
4884 printf("*** mSizeMode: nsSizeMode_Minimized\n");
4885 break;
4886 case nsSizeMode_Maximized:
4887 printf("*** mSizeMode: nsSizeMode_Maximized\n");
4888 break;
4889 default:
4890 printf("*** mSizeMode: ??????\n");
4891 break;
4893 #endif
4895 InitEvent(event);
4897 result = DispatchWindowEvent(&event);
4899 // Skip window size change events below on minimization.
4900 if (mSizeMode == nsSizeMode_Minimized)
4901 return;
4904 // Handle window size changes
4905 if (0 == (wp->flags & SWP_NOSIZE)) {
4906 RECT r;
4907 PRInt32 newWidth, newHeight;
4909 ::GetWindowRect(mWnd, &r);
4911 newWidth = r.right - r.left;
4912 newHeight = r.bottom - r.top;
4913 nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
4915 #ifdef MOZ_XUL
4916 if (eTransparencyTransparent == mTransparencyMode)
4917 ResizeTranslucentWindow(newWidth, newHeight);
4918 #endif
4920 if (newWidth > mLastSize.width)
4922 RECT drect;
4924 // getting wider
4925 drect.left = wp->x + mLastSize.width;
4926 drect.top = wp->y;
4927 drect.right = drect.left + (newWidth - mLastSize.width);
4928 drect.bottom = drect.top + newHeight;
4930 ::RedrawWindow(mWnd, &drect, NULL,
4931 RDW_INVALIDATE |
4932 RDW_NOERASE |
4933 RDW_NOINTERNALPAINT |
4934 RDW_ERASENOW |
4935 RDW_ALLCHILDREN);
4937 if (newHeight > mLastSize.height)
4939 RECT drect;
4941 // getting taller
4942 drect.left = wp->x;
4943 drect.top = wp->y + mLastSize.height;
4944 drect.right = drect.left + newWidth;
4945 drect.bottom = drect.top + (newHeight - mLastSize.height);
4947 ::RedrawWindow(mWnd, &drect, NULL,
4948 RDW_INVALIDATE |
4949 RDW_NOERASE |
4950 RDW_NOINTERNALPAINT |
4951 RDW_ERASENOW |
4952 RDW_ALLCHILDREN);
4955 mBounds.width = newWidth;
4956 mBounds.height = newHeight;
4957 mLastSize.width = newWidth;
4958 mLastSize.height = newHeight;
4960 #ifdef WINSTATE_DEBUG_OUTPUT
4961 printf("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, newWidth, newHeight);
4962 #endif
4964 // Recalculate the width and height based on the client area for gecko events.
4965 if (::GetClientRect(mWnd, &r)) {
4966 rect.width = r.right - r.left;
4967 rect.height = r.bottom - r.top;
4970 // Send a gecko resize event
4971 result = OnResize(rect);
4975 // static
4976 void nsWindow::ActivateOtherWindowHelper(HWND aWnd)
4978 // Find the next window that is enabled, visible, and not minimized.
4979 HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT);
4980 while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) ||
4981 ::IsIconic(hwndBelow))) {
4982 hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT);
4985 // Push ourselves to the bottom of the stack, then activate the
4986 // next window.
4987 ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0,
4988 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
4989 if (hwndBelow)
4990 ::SetForegroundWindow(hwndBelow);
4992 // Play the minimize sound while we're here, since that is also
4993 // forgotten when we use SW_SHOWMINIMIZED.
4994 ::PlaySoundW(L"Minimize", nsnull, SND_ALIAS | SND_NODEFAULT | SND_ASYNC);
4996 #endif // !defined(WINCE)
4998 #if !defined(WINCE)
4999 void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info)
5001 // enforce local z-order rules
5002 if (!(info->flags & SWP_NOZORDER)) {
5003 HWND hwndAfter = info->hwndInsertAfter;
5005 nsZLevelEvent event(PR_TRUE, NS_SETZLEVEL, this);
5006 nsWindow *aboveWindow = 0;
5008 InitEvent(event);
5010 if (hwndAfter == HWND_BOTTOM)
5011 event.mPlacement = nsWindowZBottom;
5012 else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
5013 event.mPlacement = nsWindowZTop;
5014 else {
5015 event.mPlacement = nsWindowZRelative;
5016 aboveWindow = GetNSWindowPtr(hwndAfter);
5018 event.mReqBelow = aboveWindow;
5019 event.mActualBelow = nsnull;
5021 event.mImmediate = PR_FALSE;
5022 event.mAdjusted = PR_FALSE;
5023 DispatchWindowEvent(&event);
5025 if (event.mAdjusted) {
5026 if (event.mPlacement == nsWindowZBottom)
5027 info->hwndInsertAfter = HWND_BOTTOM;
5028 else if (event.mPlacement == nsWindowZTop)
5029 info->hwndInsertAfter = HWND_TOP;
5030 else {
5031 info->hwndInsertAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
5034 NS_IF_RELEASE(event.mActualBelow);
5036 // prevent rude external programs from making hidden window visible
5037 if (mWindowType == eWindowType_invisible)
5038 info->flags &= ~SWP_SHOWWINDOW;
5040 #endif
5042 // Gesture event processing. Handles WM_GESTURE events.
5043 #if !defined(WINCE)
5044 PRBool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
5046 // Treatment for pan events which translate into scroll events:
5047 if (mGesture.IsPanEvent(lParam)) {
5048 nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
5050 if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
5051 return PR_FALSE; // ignore
5053 nsEventStatus status;
5055 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
5056 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
5057 event.isMeta = PR_FALSE;
5058 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
5059 event.button = 0;
5060 event.time = ::GetMessageTime();
5062 PRBool endFeedback = PR_TRUE;
5064 PRInt32 scrollOverflowX = 0;
5065 PRInt32 scrollOverflowY = 0;
5067 if (mGesture.PanDeltaToPixelScrollX(event)) {
5068 DispatchEvent(&event, status);
5069 scrollOverflowX = event.scrollOverflow;
5072 if (mGesture.PanDeltaToPixelScrollY(event)) {
5073 DispatchEvent(&event, status);
5074 scrollOverflowY = event.scrollOverflow;
5077 if (mDisplayPanFeedback) {
5078 mGesture.UpdatePanFeedbackX(mWnd, scrollOverflowX, endFeedback);
5079 mGesture.UpdatePanFeedbackY(mWnd, scrollOverflowY, endFeedback);
5080 mGesture.PanFeedbackFinalize(mWnd, endFeedback);
5083 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
5085 return PR_TRUE;
5088 // Other gestures translate into simple gesture events:
5089 nsSimpleGestureEvent event(PR_TRUE, 0, this, 0, 0.0);
5090 if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) {
5091 return PR_FALSE; // fall through to DefWndProc
5094 // Polish up and send off the new event
5095 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
5096 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
5097 event.isMeta = PR_FALSE;
5098 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
5099 event.button = 0;
5100 event.time = ::GetMessageTime();
5102 nsEventStatus status;
5103 DispatchEvent(&event, status);
5104 if (status == nsEventStatus_eIgnore) {
5105 return PR_FALSE; // Ignored, fall through
5108 // Only close this if we process and return true.
5109 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
5111 return PR_TRUE; // Handled
5113 #endif // !defined(WINCE)
5116 * OnMouseWheel - mouse wheele event processing. This was originally embedded
5117 * within the message case block. If returning true result should be returned
5118 * immediately (no more processing).
5120 PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue)
5122 // Handle both flavors of mouse wheel events.
5123 static int iDeltaPerLine, iDeltaPerChar;
5124 static ULONG ulScrollLines, ulScrollChars = 1;
5125 static int currentVDelta, currentHDelta;
5126 static HWND currentWindow = 0;
5128 PRBool isVertical = msg == WM_MOUSEWHEEL;
5130 // Get mouse wheel metrics (but only once).
5131 if (getWheelInfo) {
5132 getWheelInfo = PR_FALSE;
5134 SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
5136 // ulScrollLines usually equals 3 or 0 (for no scrolling)
5137 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
5139 // However, if ulScrollLines > WHEEL_DELTA, we assume that
5140 // the mouse driver wants a page scroll. The docs state that
5141 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
5142 // since some mouse drivers use an arbitrary large number instead,
5143 // we have to handle that as well.
5145 iDeltaPerLine = 0;
5146 if (ulScrollLines) {
5147 if (ulScrollLines <= WHEEL_DELTA) {
5148 iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
5149 } else {
5150 ulScrollLines = WHEEL_PAGESCROLL;
5154 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
5155 &ulScrollChars, 0)) {
5156 // Note that we may always fail to get the value before Win Vista.
5157 ulScrollChars = 1;
5160 iDeltaPerChar = 0;
5161 if (ulScrollChars) {
5162 if (ulScrollChars <= WHEEL_DELTA) {
5163 iDeltaPerChar = WHEEL_DELTA / ulScrollChars;
5164 } else {
5165 ulScrollChars = WHEEL_PAGESCROLL;
5170 if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) ||
5171 (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar))
5172 return PR_FALSE; // break
5174 // The mousewheel event will be dispatched to the toplevel
5175 // window. We need to give it to the child window
5176 if (!HandleScrollingPlugins(msg, wParam, lParam, result))
5177 return result; // return immediately if its not our window
5179 // We should cancel the surplus delta if the current window is not
5180 // same as previous.
5181 if (currentWindow != mWnd) {
5182 currentVDelta = 0;
5183 currentHDelta = 0;
5184 currentWindow = mWnd;
5187 nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
5188 scrollEvent.delta = 0;
5189 if (isVertical) {
5190 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
5191 if (ulScrollLines == WHEEL_PAGESCROLL) {
5192 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
5193 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1;
5194 } else {
5195 currentVDelta -= (short) HIWORD (wParam);
5196 if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
5197 scrollEvent.delta = currentVDelta / iDeltaPerLine;
5198 currentVDelta %= iDeltaPerLine;
5201 } else {
5202 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
5203 if (ulScrollChars == WHEEL_PAGESCROLL) {
5204 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
5205 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1;
5206 } else {
5207 currentHDelta += (short) HIWORD (wParam);
5208 if (PR_ABS(currentHDelta) >= iDeltaPerChar) {
5209 scrollEvent.delta = currentHDelta / iDeltaPerChar;
5210 currentHDelta %= iDeltaPerChar;
5215 if (!scrollEvent.delta)
5216 return PR_FALSE; // break
5218 scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
5219 scrollEvent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
5220 scrollEvent.isMeta = PR_FALSE;
5221 scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT);
5222 InitEvent(scrollEvent);
5223 if (nsnull != mEventCallback) {
5224 result = DispatchWindowEvent(&scrollEvent);
5226 // Note that we should return zero if we process WM_MOUSEWHEEL.
5227 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
5229 if (result)
5230 *aRetValue = isVertical ? 0 : TRUE;
5232 return PR_FALSE; // break;
5235 static PRBool
5236 StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,
5237 const PRUnichar* aChars2, const PRUint32 aNumChars2)
5239 if (aNumChars1 != aNumChars2)
5240 return PR_FALSE;
5242 nsCaseInsensitiveStringComparator comp;
5243 return comp(aChars1, aChars2, aNumChars1) == 0;
5246 UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
5248 #ifndef WINCE
5249 switch (aNativeKeyCode) {
5250 case VK_OEM_1: return NS_VK_SEMICOLON; // 0xBA, For the US standard keyboard, the ';:' key
5251 case VK_OEM_PLUS: return NS_VK_ADD; // 0xBB, For any country/region, the '+' key
5252 case VK_OEM_MINUS: return NS_VK_SUBTRACT; // 0xBD, For any country/region, the '-' key
5254 #endif
5256 return aNativeKeyCode;
5260 * nsWindow::OnKeyDown peeks into the message queue and pulls out
5261 * WM_CHAR messages for processing. During testing we don't want to
5262 * mess with the real message queue. Instead we pass a
5263 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
5264 * that as if it was in the message queue, and refrain from actually
5265 * looking at or touching the message queue.
5267 LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
5268 nsModifierKeyState &aModKeyState,
5269 PRBool *aEventDispatched,
5270 nsFakeCharMessage* aFakeCharMessage)
5272 UINT virtualKeyCode = aMsg.wParam;
5274 #ifndef WINCE
5275 gKbdLayout.OnKeyDown (virtualKeyCode);
5276 #endif
5278 // Use only DOMKeyCode for XP processing.
5279 // Use aVirtualKeyCode for gKbdLayout and native processing.
5280 UINT DOMKeyCode = nsIMM32Handler::IsComposing(this) ?
5281 virtualKeyCode : MapFromNativeToDOM(virtualKeyCode);
5283 #ifdef DEBUG
5284 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
5285 #endif
5287 PRBool noDefault =
5288 DispatchKeyEvent(NS_KEY_DOWN, 0, nsnull, DOMKeyCode, &aMsg, aModKeyState);
5289 if (aEventDispatched)
5290 *aEventDispatched = PR_TRUE;
5292 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
5293 // for almost all keys
5294 switch (DOMKeyCode) {
5295 case NS_VK_SHIFT:
5296 case NS_VK_CONTROL:
5297 case NS_VK_ALT:
5298 case NS_VK_CAPS_LOCK:
5299 case NS_VK_NUM_LOCK:
5300 case NS_VK_SCROLL_LOCK: return noDefault;
5303 PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
5304 MSG msg;
5305 BOOL gotMsg = aFakeCharMessage ||
5306 ::PeekMessageW(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
5307 // Enter and backspace are always handled here to avoid for example the
5308 // confusion between ctrl-enter and ctrl-J.
5309 if (DOMKeyCode == NS_VK_RETURN || DOMKeyCode == NS_VK_BACK ||
5310 ((aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)
5311 #ifdef WINCE
5313 #else
5314 && !gKbdLayout.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
5315 #endif
5317 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
5318 // They can be more than one because of:
5319 // * Dead-keys not pairing with base character
5320 // * Some keyboard layouts may map up to 4 characters to the single key
5321 PRBool anyCharMessagesRemoved = PR_FALSE;
5323 if (aFakeCharMessage) {
5324 anyCharMessagesRemoved = PR_TRUE;
5325 } else {
5326 while (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR))
5328 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5329 ("%s charCode=%d scanCode=%d\n", msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
5330 msg.wParam, HIWORD(msg.lParam) & 0xFF));
5331 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST, WM_KEYLAST);
5332 anyCharMessagesRemoved = PR_TRUE;
5334 gotMsg = ::PeekMessageW (&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
5338 if (!anyCharMessagesRemoved && DOMKeyCode == NS_VK_BACK &&
5339 nsIMM32Handler::IsDoingKakuteiUndo(mWnd)) {
5340 NS_ASSERTION(!aFakeCharMessage,
5341 "We shouldn't be touching the real msg queue");
5342 RemoveMessageAndDispatchPluginEvent(WM_CHAR, WM_CHAR);
5345 else if (gotMsg &&
5346 (aFakeCharMessage ||
5347 msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
5348 if (aFakeCharMessage)
5349 return OnCharRaw(aFakeCharMessage->mCharCode,
5350 aFakeCharMessage->mScanCode, aModKeyState, extraFlags);
5352 // If prevent default set for keydown, do same for keypress
5353 ::GetMessageW(&msg, mWnd, msg.message, msg.message);
5355 if (msg.message == WM_DEADCHAR) {
5356 if (!PluginHasFocus())
5357 return PR_FALSE;
5359 // We need to send the removed message to focused plug-in.
5360 DispatchPluginEvent(msg);
5361 return noDefault;
5364 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5365 ("%s charCode=%d scanCode=%d\n",
5366 msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
5367 msg.wParam, HIWORD(msg.lParam) & 0xFF));
5369 BOOL result = OnChar(msg, aModKeyState, nsnull, extraFlags);
5370 // If a syschar keypress wasn't processed, Windows may want to
5371 // handle it to activate a native menu.
5372 if (!result && msg.message == WM_SYSCHAR)
5373 ::DefWindowProcW(mWnd, msg.message, msg.wParam, msg.lParam);
5374 return result;
5376 #ifndef WINCE
5377 else if (!aModKeyState.mIsControlDown && !aModKeyState.mIsAltDown &&
5378 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode) ||
5379 KeyboardLayout::IsNumpadKey(virtualKeyCode)))
5381 // If this is simple KeyDown event but next message is not WM_CHAR,
5382 // this event may not input text, so we should ignore this event.
5383 // See bug 314130.
5384 return PluginHasFocus() && noDefault;
5387 if (gKbdLayout.IsDeadKey ())
5388 return PluginHasFocus() && noDefault;
5390 PRUint8 shiftStates[5];
5391 PRUnichar uniChars[5];
5392 PRUnichar shiftedChars[5] = {0, 0, 0, 0, 0};
5393 PRUnichar unshiftedChars[5] = {0, 0, 0, 0, 0};
5394 PRUnichar shiftedLatinChar = 0;
5395 PRUnichar unshiftedLatinChar = 0;
5396 PRUint32 numOfUniChars = 0;
5397 PRUint32 numOfShiftedChars = 0;
5398 PRUint32 numOfUnshiftedChars = 0;
5399 PRUint32 numOfShiftStates = 0;
5401 switch (virtualKeyCode) {
5402 // keys to be sent as characters
5403 case VK_ADD: uniChars [0] = '+'; numOfUniChars = 1; break;
5404 case VK_SUBTRACT: uniChars [0] = '-'; numOfUniChars = 1; break;
5405 case VK_DIVIDE: uniChars [0] = '/'; numOfUniChars = 1; break;
5406 case VK_MULTIPLY: uniChars [0] = '*'; numOfUniChars = 1; break;
5407 case VK_NUMPAD0:
5408 case VK_NUMPAD1:
5409 case VK_NUMPAD2:
5410 case VK_NUMPAD3:
5411 case VK_NUMPAD4:
5412 case VK_NUMPAD5:
5413 case VK_NUMPAD6:
5414 case VK_NUMPAD7:
5415 case VK_NUMPAD8:
5416 case VK_NUMPAD9:
5417 uniChars [0] = virtualKeyCode - VK_NUMPAD0 + '0';
5418 numOfUniChars = 1;
5419 break;
5420 default:
5421 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
5422 numOfUniChars = numOfShiftStates =
5423 gKbdLayout.GetUniChars(uniChars, shiftStates,
5424 NS_ARRAY_LENGTH(uniChars));
5427 if (aModKeyState.mIsControlDown ^ aModKeyState.mIsAltDown) {
5428 PRUint8 capsLockState = (::GetKeyState(VK_CAPITAL) & 1) ? eCapsLock : 0;
5429 numOfUnshiftedChars =
5430 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode, capsLockState,
5431 unshiftedChars, NS_ARRAY_LENGTH(unshiftedChars));
5432 numOfShiftedChars =
5433 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode,
5434 capsLockState | eShift,
5435 shiftedChars, NS_ARRAY_LENGTH(shiftedChars));
5437 // The current keyboard cannot input alphabets or numerics,
5438 // we should append them for Shortcut/Access keys.
5439 // E.g., for Cyrillic keyboard layout.
5440 if (NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z) {
5441 shiftedLatinChar = unshiftedLatinChar = DOMKeyCode;
5442 if (capsLockState)
5443 shiftedLatinChar += 0x20;
5444 else
5445 unshiftedLatinChar += 0x20;
5446 if (unshiftedLatinChar == unshiftedChars[0] &&
5447 shiftedLatinChar == shiftedChars[0]) {
5448 shiftedLatinChar = unshiftedLatinChar = 0;
5450 } else {
5451 PRUint16 ch = 0;
5452 if (NS_VK_0 <= DOMKeyCode && DOMKeyCode <= NS_VK_9) {
5453 ch = DOMKeyCode;
5454 } else {
5455 switch (virtualKeyCode) {
5456 case VK_OEM_PLUS: ch = '+'; break;
5457 case VK_OEM_MINUS: ch = '-'; break;
5460 if (ch && unshiftedChars[0] != ch && shiftedChars[0] != ch) {
5461 // Windows has assigned a virtual key code to the key even though
5462 // the character can't be produced with this key. That probably
5463 // means the character can't be produced with any key in the
5464 // current layout and so the assignment is based on a QWERTY
5465 // layout. Append this code so that users can access the shortcut.
5466 unshiftedLatinChar = ch;
5470 // If the charCode is not ASCII character, we should replace the
5471 // charCode with ASCII character only when Ctrl is pressed.
5472 // But don't replace the charCode when the charCode is not same as
5473 // unmodified characters. In such case, Ctrl is sometimes used for a
5474 // part of character inputting key combination like Shift.
5475 if (aModKeyState.mIsControlDown) {
5476 PRUint8 currentState = eCtrl;
5477 if (aModKeyState.mIsShiftDown)
5478 currentState |= eShift;
5480 PRUint32 ch =
5481 aModKeyState.mIsShiftDown ? shiftedLatinChar : unshiftedLatinChar;
5482 if (ch &&
5483 (numOfUniChars == 0 ||
5484 StringCaseInsensitiveEquals(uniChars, numOfUniChars,
5485 aModKeyState.mIsShiftDown ? shiftedChars : unshiftedChars,
5486 aModKeyState.mIsShiftDown ? numOfShiftedChars :
5487 numOfUnshiftedChars))) {
5488 numOfUniChars = numOfShiftStates = 1;
5489 uniChars[0] = ch;
5490 shiftStates[0] = currentState;
5496 if (numOfUniChars > 0 || numOfShiftedChars > 0 || numOfUnshiftedChars > 0) {
5497 PRUint32 num = PR_MAX(numOfUniChars,
5498 PR_MAX(numOfShiftedChars, numOfUnshiftedChars));
5499 PRUint32 skipUniChars = num - numOfUniChars;
5500 PRUint32 skipShiftedChars = num - numOfShiftedChars;
5501 PRUint32 skipUnshiftedChars = num - numOfUnshiftedChars;
5502 UINT keyCode = numOfUniChars == 0 ? DOMKeyCode : 0;
5503 for (PRUint32 cnt = 0; cnt < num; cnt++) {
5504 PRUint16 uniChar, shiftedChar, unshiftedChar;
5505 uniChar = shiftedChar = unshiftedChar = 0;
5506 if (skipUniChars <= cnt) {
5507 if (cnt - skipUniChars < numOfShiftStates) {
5508 // If key in combination with Alt and/or Ctrl produces a different
5509 // character than without them then do not report these flags
5510 // because it is separate keyboard layout shift state. If dead-key
5511 // and base character does not produce a valid composite character
5512 // then both produced dead-key character and following base
5513 // character may have different modifier flags, too.
5514 aModKeyState.mIsShiftDown =
5515 (shiftStates[cnt - skipUniChars] & eShift) != 0;
5516 aModKeyState.mIsControlDown =
5517 (shiftStates[cnt - skipUniChars] & eCtrl) != 0;
5518 aModKeyState.mIsAltDown =
5519 (shiftStates[cnt - skipUniChars] & eAlt) != 0;
5521 uniChar = uniChars[cnt - skipUniChars];
5523 if (skipShiftedChars <= cnt)
5524 shiftedChar = shiftedChars[cnt - skipShiftedChars];
5525 if (skipUnshiftedChars <= cnt)
5526 unshiftedChar = unshiftedChars[cnt - skipUnshiftedChars];
5527 nsAutoTArray<nsAlternativeCharCode, 5> altArray;
5529 if (shiftedChar || unshiftedChar) {
5530 nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
5531 altArray.AppendElement(chars);
5533 if (cnt == num - 1 && (unshiftedLatinChar || shiftedLatinChar)) {
5534 nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
5535 altArray.AppendElement(chars);
5538 DispatchKeyEvent(NS_KEY_PRESS, uniChar, &altArray,
5539 keyCode, nsnull, aModKeyState, extraFlags);
5541 } else {
5542 DispatchKeyEvent(NS_KEY_PRESS, 0, nsnull, DOMKeyCode, nsnull, aModKeyState,
5543 extraFlags);
5545 #else
5547 UINT unichar = ::MapVirtualKey(virtualKeyCode, MAPVK_VK_TO_CHAR);
5548 // Check for dead characters or no mapping
5549 if (unichar & 0x80) {
5550 return noDefault;
5552 DispatchKeyEvent(NS_KEY_PRESS, unichar, nsnull, DOMKeyCode, nsnull, aModKeyState,
5553 extraFlags);
5555 #endif
5557 return noDefault;
5560 // OnKeyUp
5561 LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
5562 nsModifierKeyState &aModKeyState,
5563 PRBool *aEventDispatched)
5565 UINT virtualKeyCode = aMsg.wParam;
5567 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5568 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
5570 if (!nsIMM32Handler::IsComposing(this)) {
5571 virtualKeyCode = MapFromNativeToDOM(virtualKeyCode);
5574 if (aEventDispatched)
5575 *aEventDispatched = PR_TRUE;
5576 return DispatchKeyEvent(NS_KEY_UP, 0, nsnull, virtualKeyCode, &aMsg,
5577 aModKeyState);
5580 // OnChar
5581 LRESULT nsWindow::OnChar(const MSG &aMsg, nsModifierKeyState &aModKeyState,
5582 PRBool *aEventDispatched, PRUint32 aFlags)
5584 return OnCharRaw(aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF, aModKeyState,
5585 aFlags, &aMsg, aEventDispatched);
5588 // OnCharRaw
5589 LRESULT nsWindow::OnCharRaw(UINT charCode, UINT aScanCode,
5590 nsModifierKeyState &aModKeyState, PRUint32 aFlags,
5591 const MSG *aMsg, PRBool *aEventDispatched)
5593 // ignore [shift+]alt+space so the OS can handle it
5594 if (aModKeyState.mIsAltDown && !aModKeyState.mIsControlDown &&
5595 IS_VK_DOWN(NS_VK_SPACE)) {
5596 return FALSE;
5599 // Ignore Ctrl+Enter (bug 318235)
5600 if (aModKeyState.mIsControlDown && charCode == 0xA) {
5601 return FALSE;
5604 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
5605 PRBool saveIsAltDown = aModKeyState.mIsAltDown;
5606 PRBool saveIsControlDown = aModKeyState.mIsControlDown;
5607 if (aModKeyState.mIsAltDown && aModKeyState.mIsControlDown)
5608 aModKeyState.mIsAltDown = aModKeyState.mIsControlDown = PR_FALSE;
5610 wchar_t uniChar;
5612 if (nsIMM32Handler::IsComposing(this)) {
5613 ResetInputState();
5616 if (aModKeyState.mIsControlDown && charCode <= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
5617 // need to account for shift here. bug 16486
5618 if (aModKeyState.mIsShiftDown)
5619 uniChar = charCode - 1 + 'A';
5620 else
5621 uniChar = charCode - 1 + 'a';
5622 charCode = 0;
5624 else if (aModKeyState.mIsControlDown && charCode <= 0x1F) {
5625 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
5626 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
5627 // for some reason the keypress handler need to have the uniChar code set
5628 // with the addition of a upper case A not the lower case.
5629 uniChar = charCode - 1 + 'A';
5630 charCode = 0;
5631 } else { // 0x20 - SPACE, 0x3D - EQUALS
5632 if (charCode < 0x20 || (charCode == 0x3D && aModKeyState.mIsControlDown)) {
5633 uniChar = 0;
5634 } else {
5635 uniChar = charCode;
5636 charCode = 0;
5640 // Keep the characters unshifted for shortcuts and accesskeys and make sure
5641 // that numbers are always passed as such (among others: bugs 50255 and 351310)
5642 if (uniChar && (aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)) {
5643 UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK,
5644 gKbdLayout.GetLayout());
5645 UINT unshiftedCharCode =
5646 virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
5647 aModKeyState.mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode,
5648 MAPVK_VK_TO_CHAR,
5649 gKbdLayout.GetLayout()) : 0;
5650 // ignore diacritics (top bit set) and key mapping errors (char code 0)
5651 if ((INT)unshiftedCharCode > 0)
5652 uniChar = unshiftedCharCode;
5655 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
5656 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
5657 // pressed too.
5658 if (!aModKeyState.mIsShiftDown && (saveIsAltDown || saveIsControlDown)) {
5659 uniChar = towlower(uniChar);
5662 PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, nsnull,
5663 charCode, aMsg, aModKeyState, aFlags);
5664 if (aEventDispatched)
5665 *aEventDispatched = PR_TRUE;
5666 aModKeyState.mIsAltDown = saveIsAltDown;
5667 aModKeyState.mIsControlDown = saveIsControlDown;
5668 return result;
5671 void
5672 nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers)
5674 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierKeyMap); ++i) {
5675 const PRUint32* map = sModifierKeyMap[i];
5676 if (aModifiers & map[0]) {
5677 aArray->AppendElement(KeyPair(map[1], map[2]));
5682 nsresult
5683 nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
5685 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
5686 // here, if that helps in some situations. So far I haven't seen a
5687 // need.
5688 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
5689 const Configuration& configuration = aConfigurations[i];
5690 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
5691 NS_ASSERTION(w->GetParent() == this,
5692 "Configured widget is not a child");
5693 #ifdef WINCE
5694 // MSDN says we should do on WinCE this before moving or resizing the window
5695 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
5696 // We put the region back just below, anyway.
5697 ::SetWindowRgn(w->mWnd, NULL, TRUE);
5698 #endif
5699 nsIntRect bounds;
5700 w->GetBounds(bounds);
5701 if (bounds.Size() != configuration.mBounds.Size()) {
5702 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
5703 configuration.mBounds.width, configuration.mBounds.height,
5704 PR_TRUE);
5705 } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
5706 w->Move(configuration.mBounds.x, configuration.mBounds.y);
5708 nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_FALSE);
5709 NS_ENSURE_SUCCESS(rv, rv);
5711 return NS_OK;
5714 static HRGN
5715 CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
5717 PRInt32 size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
5718 nsAutoTArray<PRUint8,100> buf;
5719 if (!buf.SetLength(size))
5720 return NULL;
5721 RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
5722 RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
5723 data->rdh.dwSize = sizeof(data->rdh);
5724 data->rdh.iType = RDH_RECTANGLES;
5725 data->rdh.nCount = aRects.Length();
5726 nsIntRect bounds;
5727 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
5728 const nsIntRect& r = aRects[i];
5729 bounds.UnionRect(bounds, r);
5730 ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
5732 ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
5733 return ::ExtCreateRegion(NULL, buf.Length(), data);
5736 nsresult
5737 nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
5738 PRBool aIntersectWithExisting)
5740 if (!aIntersectWithExisting) {
5741 if (!StoreWindowClipRegion(aRects))
5742 return NS_OK;
5745 HRGN dest = CreateHRGNFromArray(aRects);
5746 if (!dest)
5747 return NS_ERROR_OUT_OF_MEMORY;
5749 if (aIntersectWithExisting) {
5750 HRGN current = ::CreateRectRgn(0, 0, 0, 0);
5751 if (current) {
5752 if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
5753 ::CombineRgn(dest, dest, current, RGN_AND);
5755 ::DeleteObject(current);
5759 if (!::SetWindowRgn(mWnd, dest, TRUE)) {
5760 ::DeleteObject(dest);
5761 return NS_ERROR_FAILURE;
5763 return NS_OK;
5766 // WM_DESTROY event handler
5767 void nsWindow::OnDestroy()
5769 mOnDestroyCalled = PR_TRUE;
5771 // Make sure we don't get destroyed in the process of tearing down.
5772 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
5774 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
5775 if (!mInDtor)
5776 DispatchStandardEvent(NS_DESTROY);
5778 // Prevent the widget from sending additional events.
5779 mEventCallback = nsnull;
5781 // Free our subclass and clear |this| stored in the window props. We will no longer
5782 // receive events from Windows after this point.
5783 SubclassWindow(FALSE);
5785 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
5786 // cleared. (It's used in tracking windows for mouse events.)
5787 if (sCurrentWindow == this)
5788 sCurrentWindow = nsnull;
5790 // Disconnects us from our parent, will call our GetParent().
5791 nsBaseWidget::Destroy();
5793 // Release references to children, device context, toolkit, and app shell.
5794 nsBaseWidget::OnDestroy();
5796 // Clear our native parent handle.
5797 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
5798 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
5799 //SetParent(nsnull);
5801 // We have to destroy the native drag target before we null out our window pointer.
5802 EnableDragDrop(PR_FALSE);
5804 // If we're going away and for some reason we're still the rollup widget, rollup and
5805 // turn off capture.
5806 if ( this == sRollupWidget ) {
5807 if ( sRollupListener )
5808 sRollupListener->Rollup(nsnull, nsnull);
5809 CaptureRollupEvents(nsnull, PR_FALSE, PR_TRUE);
5812 // If IME is disabled, restore it.
5813 if (mOldIMC) {
5814 mOldIMC = ::ImmAssociateContext(mWnd, mOldIMC);
5815 NS_ASSERTION(!mOldIMC, "Another IMC was associated");
5818 // Turn off mouse trails if enabled.
5819 MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
5820 if (mtrailer) {
5821 if (mtrailer->GetMouseTrailerWindow() == mWnd)
5822 mtrailer->DestroyTimer();
5824 if (mtrailer->GetCaptureWindow() == mWnd)
5825 mtrailer->SetCaptureWindow(nsnull);
5828 // Free GDI window class objects
5829 if (mBrush) {
5830 VERIFY(::DeleteObject(mBrush));
5831 mBrush = NULL;
5834 // Free app icon resources.
5835 HICON icon;
5836 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM) 0);
5837 if (icon)
5838 ::DestroyIcon(icon);
5840 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM) 0);
5841 if (icon)
5842 ::DestroyIcon(icon);
5844 // Destroy any custom cursor resources.
5845 if (mCursor == -1)
5846 SetCursor(eCursor_standard);
5848 #ifdef MOZ_XUL
5849 // Reset transparency
5850 if (eTransparencyTransparent == mTransparencyMode)
5851 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
5852 #endif
5854 // Clear the main HWND.
5855 mWnd = NULL;
5858 // OnMove
5859 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
5861 mBounds.x = aX;
5862 mBounds.y = aY;
5864 nsGUIEvent event(PR_TRUE, NS_MOVE, this);
5865 InitEvent(event);
5866 event.refPoint.x = aX;
5867 event.refPoint.y = aY;
5869 return DispatchWindowEvent(&event);
5872 // Send a resize message to the listener
5873 PRBool nsWindow::OnResize(nsIntRect &aWindowRect)
5875 // call the event callback
5876 if (mEventCallback) {
5877 nsSizeEvent event(PR_TRUE, NS_SIZE, this);
5878 InitEvent(event);
5879 event.windowSize = &aWindowRect;
5880 RECT r;
5881 if (::GetWindowRect(mWnd, &r)) {
5882 event.mWinWidth = PRInt32(r.right - r.left);
5883 event.mWinHeight = PRInt32(r.bottom - r.top);
5884 } else {
5885 event.mWinWidth = 0;
5886 event.mWinHeight = 0;
5888 return DispatchWindowEvent(&event);
5891 return PR_FALSE;
5894 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5895 PRBool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
5897 return PR_TRUE;
5899 #endif // !defined(WINCE)
5901 void nsWindow::OnSettingsChange(WPARAM wParam, LPARAM lParam)
5903 if (mWindowType == eWindowType_dialog ||
5904 mWindowType == eWindowType_toplevel )
5905 nsWindowGfx::OnSettingsChangeGfx(wParam);
5908 // Scrolling helper function for handling plugins.
5909 // Return value indicates whether the calling function should handle this
5910 // result indicates whether this was handled at all
5911 PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
5912 LPARAM aLParam, PRBool& aHandled)
5914 // The scroll event will be dispatched to the toplevel
5915 // window. We need to give it to the child window
5916 aHandled = PR_FALSE; // default is to have not handled
5917 POINT point;
5918 DWORD dwPoints = ::GetMessagePos();
5919 point.x = GET_X_LPARAM(dwPoints);
5920 point.y = GET_Y_LPARAM(dwPoints);
5922 static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
5923 if (aMsg == WM_MOUSEHWHEEL) {
5924 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
5925 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
5926 // message at first time, this time, ::GetMessagePos works fine.
5927 // Then, we will return 0 (0 means we process it) to the message. Then, the
5928 // driver will POST the same messages continuously during the wheel tilted.
5929 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
5930 // cursor isn't 0,0. Therefore, we cannot trust the result of
5931 // ::GetMessagePos API if the sender is the driver.
5932 if (!sMayBeUsingLogitechMouse && aLParam == 0 && aLParam != dwPoints &&
5933 ::InSendMessage()) {
5934 sMayBeUsingLogitechMouse = PR_TRUE;
5935 } else if (sMayBeUsingLogitechMouse && aLParam != 0 && ::InSendMessage()) {
5936 // The user has changed the mouse from Logitech's to another one (e.g.,
5937 // the user has changed to the touchpad of the notebook.
5938 sMayBeUsingLogitechMouse = PR_FALSE;
5940 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
5941 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
5942 // instead.
5943 if (sMayBeUsingLogitechMouse && aLParam == 0 && dwPoints == 0) {
5944 ::GetCursorPos(&point);
5948 HWND destWnd = ::WindowFromPoint(point);
5949 // Since we receive scroll events for as long as
5950 // we are focused, it's entirely possible that there
5951 // is another app's window or no window under the
5952 // pointer.
5954 if (!destWnd) {
5955 // No window is under the pointer
5956 return PR_FALSE; // break
5958 // We don't care about windows belonging to other processes.
5959 DWORD processId = 0;
5960 GetWindowThreadProcessId(destWnd, &processId);
5961 if (processId != GetCurrentProcessId())
5963 // Somebody elses window
5964 return PR_FALSE; // break
5966 nsWindow* destWindow = GetNSWindowPtr(destWnd);
5967 if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
5968 // Some other app, or a plugin window.
5969 // Windows directs scrolling messages to the focused window.
5970 // However, Mozilla does not like plugins having focus, so a
5971 // Mozilla window (ie, the plugin's parent (us!) has focus.)
5972 // Therefore, plugins etc _should_ get first grab at the
5973 // message, but this focus vaguary means the plugin misses
5974 // out. If the window is a child of ours, forward it on.
5975 // Determine if a child by walking the parent list until
5976 // we find a parent matching our wndproc.
5977 HWND parentWnd = ::GetParent(destWnd);
5978 while (parentWnd) {
5979 nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
5980 if (parentWindow) {
5981 // We have a child window - quite possibly a plugin window.
5982 // However, not all plugins are created equal - some will handle this
5983 // message themselves, some will forward directly back to us, while
5984 // others will call DefWndProc, which itself still forwards back to us.
5985 // So if we have sent it once, we need to handle it ourself.
5986 if (mInScrollProcessing) {
5987 destWnd = parentWnd;
5988 destWindow = parentWindow;
5989 } else {
5990 // First time we have seen this message.
5991 // Call the child - either it will consume it, or
5992 // it will wind it's way back to us,triggering the destWnd case above
5993 // either way,when the call returns,we are all done with the message,
5994 mInScrollProcessing = PR_TRUE;
5995 if (0 == ::SendMessageW(destWnd, aMsg, aWParam, aLParam))
5996 aHandled = PR_TRUE;
5997 destWnd = nsnull;
5998 mInScrollProcessing = PR_FALSE;
6000 return PR_FALSE; // break; // stop parent search
6002 parentWnd = ::GetParent(parentWnd);
6003 } // while parentWnd
6005 if (destWnd == nsnull)
6006 return PR_FALSE;
6007 if (destWnd != mWnd) {
6008 if (destWindow) {
6009 LRESULT aRetValue;
6010 destWindow->ProcessMessage(aMsg, aWParam, aLParam, &aRetValue);
6011 aHandled = PR_TRUE;
6012 return PR_FALSE; // return result immediately
6014 #ifdef DEBUG
6015 else
6016 printf("WARNING: couldn't get child window for SCROLL event\n");
6017 #endif
6019 return PR_TRUE; // caller should handle this
6022 PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
6024 if (aLParam)
6026 // Scroll message generated by Thinkpad Trackpoint Driver or similar
6027 // Treat as a mousewheel message and scroll appropriately
6029 PRBool result;
6030 if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result))
6031 return result; // Return if it's not our message or has been dispatched
6033 nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
6034 scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
6035 ? nsMouseScrollEvent::kIsVertical
6036 : nsMouseScrollEvent::kIsHorizontal;
6037 switch (LOWORD(aWParam))
6039 case SB_PAGEDOWN:
6040 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6041 case SB_LINEDOWN:
6042 scrollevent.delta = 1;
6043 break;
6044 case SB_PAGEUP:
6045 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6046 case SB_LINEUP:
6047 scrollevent.delta = -1;
6048 break;
6049 default:
6050 return PR_FALSE;
6052 scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6053 scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6054 scrollevent.isMeta = PR_FALSE;
6055 scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
6056 InitEvent(scrollevent);
6057 if (nsnull != mEventCallback)
6059 DispatchWindowEvent(&scrollevent);
6061 return PR_TRUE;
6063 // Scroll message generated by external application
6064 // XXX Handle by scrolling the window in the desired manner (Bug 315727)
6065 return PR_FALSE;
6068 // Return the brush used to paint the background of this control
6069 HBRUSH nsWindow::OnControlColor()
6071 return mBrush;
6074 // Can be overriden. Controls auto-erase of background.
6075 PRBool nsWindow::AutoErase(HDC dc)
6077 #ifdef WINCE_WINDOWS_MOBILE
6078 RECT wrect;
6079 GetClipBox(dc, &wrect);
6080 AddRECTToRegion(wrect, mInvalidatedRegion);
6081 #endif
6082 return PR_FALSE;
6085 /**************************************************************
6086 **************************************************************
6088 ** BLOCK: IME management and accessibility
6090 ** Handles managing IME input and accessibility.
6092 **************************************************************
6093 **************************************************************/
6095 NS_IMETHODIMP nsWindow::ResetInputState()
6097 #ifdef DEBUG_KBSTATE
6098 printf("ResetInputState\n");
6099 #endif
6101 #ifdef NS_ENABLE_TSF
6102 nsTextStore::CommitComposition(PR_FALSE);
6103 #endif //NS_ENABLE_TSF
6105 nsIMEContext IMEContext(mWnd);
6106 if (IMEContext.IsValid()) {
6107 ::ImmNotifyIME(IMEContext.get(), NI_COMPOSITIONSTR, CPS_COMPLETE, NULL);
6108 ::ImmNotifyIME(IMEContext.get(), NI_COMPOSITIONSTR, CPS_CANCEL, NULL);
6110 return NS_OK;
6113 NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState)
6115 #ifdef DEBUG_KBSTATE
6116 printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
6117 #endif
6119 #ifdef NS_ENABLE_TSF
6120 nsTextStore::SetIMEOpenState(aState);
6121 #endif //NS_ENABLE_TSF
6123 nsIMEContext IMEContext(mWnd);
6124 if (IMEContext.IsValid()) {
6125 ::ImmSetOpenStatus(IMEContext.get(), aState ? TRUE : FALSE);
6127 return NS_OK;
6130 NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState)
6132 nsIMEContext IMEContext(mWnd);
6133 if (IMEContext.IsValid()) {
6134 BOOL isOpen = ::ImmGetOpenStatus(IMEContext.get());
6135 *aState = isOpen ? PR_TRUE : PR_FALSE;
6136 } else
6137 *aState = PR_FALSE;
6139 #ifdef NS_ENABLE_TSF
6140 *aState |= nsTextStore::GetIMEOpenState();
6141 #endif //NS_ENABLE_TSF
6143 return NS_OK;
6146 NS_IMETHODIMP nsWindow::SetIMEEnabled(PRUint32 aState)
6148 #ifdef NS_ENABLE_TSF
6149 nsTextStore::SetIMEEnabled(aState);
6150 #endif //NS_ENABLE_TSF
6151 #ifdef DEBUG_KBSTATE
6152 printf("SetIMEEnabled: %s\n", (aState == nsIWidget::IME_STATUS_ENABLED ||
6153 aState == nsIWidget::IME_STATUS_PLUGIN)?
6154 "Enabled": "Disabled");
6155 #endif
6156 if (nsIMM32Handler::IsComposing(this))
6157 ResetInputState();
6158 mIMEEnabled = aState;
6159 PRBool enable = (aState == nsIWidget::IME_STATUS_ENABLED ||
6160 aState == nsIWidget::IME_STATUS_PLUGIN);
6162 #if defined(WINCE_HAVE_SOFTKB)
6163 sSoftKeyboardState = (aState != nsIWidget::IME_STATUS_DISABLED);
6164 nsWindowCE::ToggleSoftKB(sSoftKeyboardState);
6165 #endif
6167 if (!enable != !mOldIMC)
6168 return NS_OK;
6169 mOldIMC = ::ImmAssociateContext(mWnd, enable ? mOldIMC : NULL);
6170 NS_ASSERTION(!enable || !mOldIMC, "Another IMC was associated");
6172 return NS_OK;
6175 NS_IMETHODIMP nsWindow::GetIMEEnabled(PRUint32* aState)
6177 #ifdef DEBUG_KBSTATE
6178 printf("GetIMEEnabled: %s\n", mIMEEnabled? "Enabled": "Disabled");
6179 #endif
6180 *aState = mIMEEnabled;
6181 return NS_OK;
6184 NS_IMETHODIMP nsWindow::CancelIMEComposition()
6186 #ifdef DEBUG_KBSTATE
6187 printf("CancelIMEComposition\n");
6188 #endif
6190 #ifdef NS_ENABLE_TSF
6191 nsTextStore::CommitComposition(PR_TRUE);
6192 #endif //NS_ENABLE_TSF
6194 nsIMEContext IMEContext(mWnd);
6195 if (IMEContext.IsValid()) {
6196 ::ImmNotifyIME(IMEContext.get(), NI_COMPOSITIONSTR, CPS_CANCEL, NULL);
6198 return NS_OK;
6201 NS_IMETHODIMP
6202 nsWindow::GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState)
6204 #ifdef DEBUG_KBSTATE
6205 printf("GetToggledKeyState\n");
6206 #endif
6207 NS_ENSURE_ARG_POINTER(aLEDState);
6208 *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
6209 return NS_OK;
6212 #ifdef NS_ENABLE_TSF
6213 NS_IMETHODIMP
6214 nsWindow::OnIMEFocusChange(PRBool aFocus)
6216 nsresult rv = nsTextStore::OnFocusChange(aFocus, this, mIMEEnabled);
6217 if (rv == NS_ERROR_NOT_AVAILABLE)
6218 rv = NS_ERROR_NOT_IMPLEMENTED; // TSF is not enabled, maybe.
6219 return rv;
6222 NS_IMETHODIMP
6223 nsWindow::OnIMETextChange(PRUint32 aStart,
6224 PRUint32 aOldEnd,
6225 PRUint32 aNewEnd)
6227 return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
6230 NS_IMETHODIMP
6231 nsWindow::OnIMESelectionChange(void)
6233 return nsTextStore::OnSelectionChange();
6235 #endif //NS_ENABLE_TSF
6237 #ifdef ACCESSIBILITY
6238 already_AddRefed<nsIAccessible> nsWindow::GetRootAccessible()
6240 nsWindow::sIsAccessibilityOn = TRUE;
6242 if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) {
6243 return nsnull;
6246 nsIAccessible *rootAccessible = nsnull;
6248 // If accessibility is turned on, we create this even before it is requested
6249 // when the window gets focused. We need it to be created early so it can
6250 // generate accessibility events right away
6251 nsWindow* accessibleWindow = nsnull;
6252 if (mContentType != eContentTypeInherit) {
6253 // We're on a MozillaContentWindowClass or MozillaUIWindowClass window.
6254 // Search for the correct visible child window to get an accessible
6255 // document from. Make sure to use an active child window
6256 HWND accessibleWnd = ::GetTopWindow(mWnd);
6257 while (accessibleWnd) {
6258 // Loop through windows and find the first one with accessibility info
6259 accessibleWindow = GetNSWindowPtr(accessibleWnd);
6260 if (accessibleWindow) {
6261 accessibleWindow->DispatchAccessibleEvent(NS_GETACCESSIBLE, &rootAccessible);
6262 if (rootAccessible) {
6263 break; // Success, one of the child windows was active
6266 accessibleWnd = ::GetNextWindow(accessibleWnd, GW_HWNDNEXT);
6269 else {
6270 DispatchAccessibleEvent(NS_GETACCESSIBLE, &rootAccessible);
6272 return rootAccessible;
6275 STDMETHODIMP_(LRESULT)
6276 nsWindow::LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc)
6278 // open the dll dynamically
6279 if (!sAccLib)
6280 sAccLib =::LoadLibraryW(L"OLEACC.DLL");
6282 if (sAccLib) {
6283 if (!sLresultFromObject)
6284 sLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(sAccLib,"LresultFromObject");
6286 if (sLresultFromObject)
6287 return sLresultFromObject(riid,wParam,pAcc);
6290 return 0;
6292 #endif
6294 /**************************************************************
6295 **************************************************************
6297 ** BLOCK: Transparency
6299 ** Window transparency helpers.
6301 **************************************************************
6302 **************************************************************/
6304 #ifdef MOZ_XUL
6306 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force)
6308 if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
6309 return;
6311 mTransparentSurface = new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
6312 mMemoryDC = mTransparentSurface->GetDC();
6315 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
6317 #ifndef WINCE
6319 if (aMode == mTransparencyMode)
6320 return;
6322 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
6323 nsWindow* topWindow = GetNSWindowPtr(hWnd);
6325 if (!topWindow)
6327 NS_WARNING("Trying to use transparent chrome in an embedded context");
6328 return;
6331 LONG_PTR style = 0, exStyle = 0;
6332 switch(aMode) {
6333 case eTransparencyTransparent:
6334 exStyle |= WS_EX_LAYERED;
6335 case eTransparencyOpaque:
6336 case eTransparencyGlass:
6337 topWindow->mTransparencyMode = aMode;
6338 break;
6341 style |= topWindow->WindowStyle();
6342 exStyle |= topWindow->WindowExStyle();
6344 if (aMode == eTransparencyTransparent) {
6345 style &= ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
6346 exStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
6349 VERIFY_WINDOW_STYLE(style);
6350 ::SetWindowLongPtrW(hWnd, GWL_STYLE, style);
6351 ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle);
6353 mTransparencyMode = aMode;
6355 SetupTranslucentWindowMemoryBitmap(aMode);
6356 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
6357 MARGINS margins = { 0, 0, 0, 0 };
6358 DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE;
6359 if(eTransparencyGlass == aMode) {
6360 margins.cxLeftWidth = -1;
6361 policy = DWMNCRP_ENABLED;
6363 if(nsUXThemeData::sHaveCompositor) {
6364 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd, &margins);
6365 nsUXThemeData::dwmSetWindowAttributePtr(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy);
6367 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
6368 #endif // #ifndef WINCE
6371 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
6373 if (eTransparencyTransparent == aMode) {
6374 ResizeTranslucentWindow(mBounds.width, mBounds.height, PR_TRUE);
6375 } else {
6376 mTransparentSurface = nsnull;
6377 mMemoryDC = NULL;
6381 nsresult nsWindow::UpdateTranslucentWindow()
6383 #ifndef WINCE
6384 if (mBounds.IsEmpty())
6385 return NS_OK;
6387 ::GdiFlush();
6389 BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
6390 SIZE winSize = { mBounds.width, mBounds.height };
6391 POINT srcPos = { 0, 0 };
6392 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
6393 RECT winRect;
6394 ::GetWindowRect(hWnd, &winRect);
6396 // perform the alpha blend
6397 if (!::UpdateLayeredWindow(hWnd, NULL, (POINT*)&winRect, &winSize, mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA))
6398 return NS_ERROR_FAILURE;
6399 #endif
6401 return NS_OK;
6404 #endif //MOZ_XUL
6406 /**************************************************************
6407 **************************************************************
6409 ** BLOCK: Popup rollup hooks
6411 ** Deals with CaptureRollup on popup windows.
6413 **************************************************************
6414 **************************************************************/
6416 #ifndef WINCE
6417 // Schedules a timer for a window, so we can rollup after processing the hook event
6418 void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId)
6420 // In some cases multiple hooks may be scheduled
6421 // so ignore any other requests once one timer is scheduled
6422 if (sHookTimerId == 0) {
6423 // Remember the window handle and the message ID to be used later
6424 sRollupMsgId = aMsgId;
6425 sRollupMsgWnd = aWnd;
6426 // Schedule native timer for doing the rollup after
6427 // this event is done being processed
6428 sHookTimerId = ::SetTimer(NULL, 0, 0, (TIMERPROC)HookTimerForPopups);
6429 NS_ASSERTION(sHookTimerId, "Timer couldn't be created.");
6433 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6434 int gLastMsgCode = 0;
6435 extern MSGFEventMsgInfo gMSGFEvents[];
6436 #endif
6438 // Process Menu messages, rollup when popup is clicked.
6439 LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam)
6441 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6442 if (sProcessHook) {
6443 MSG* pMsg = (MSG*)lParam;
6445 int inx = 0;
6446 while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != NULL) {
6447 inx++;
6449 if (code != gLastMsgCode) {
6450 if (gMSGFEvents[inx].mId == code) {
6451 #ifdef DEBUG
6452 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code, gMSGFEvents[inx].mStr, pMsg->hwnd);
6453 #endif
6454 } else {
6455 #ifdef DEBUG
6456 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code, gMSGFEvents[inx].mId, pMsg->hwnd);
6457 #endif
6459 gLastMsgCode = code;
6461 PrintEvent(pMsg->message, FALSE, FALSE);
6463 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6465 if (sProcessHook && code == MSGF_MENU) {
6466 MSG* pMsg = (MSG*)lParam;
6467 ScheduleHookTimer( pMsg->hwnd, pMsg->message);
6470 return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
6473 // Process all mouse messages. Roll up when a click is in a native window
6474 // that doesn't have an nsIWidget.
6475 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
6477 if (sProcessHook) {
6478 switch (wParam) {
6479 case WM_LBUTTONDOWN:
6480 case WM_RBUTTONDOWN:
6481 case WM_MBUTTONDOWN:
6482 case WM_MOUSEWHEEL:
6483 case WM_MOUSEHWHEEL:
6485 MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
6486 nsIWidget* mozWin = (nsIWidget*)GetNSWindowPtr(ms->hwnd);
6487 if (mozWin) {
6488 // If this window is windowed plugin window, the mouse events are not
6489 // sent to us.
6490 if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin)
6491 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
6492 } else {
6493 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
6495 break;
6499 return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam);
6502 // Process all messages. Roll up when the window is moving, or
6503 // is resizing or when maximized or mininized.
6504 LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam)
6506 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6507 if (sProcessHook) {
6508 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
6509 PrintEvent(cwpt->message, FALSE, FALSE);
6511 #endif
6513 if (sProcessHook) {
6514 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
6515 if (cwpt->message == WM_MOVING ||
6516 cwpt->message == WM_SIZING ||
6517 cwpt->message == WM_GETMINMAXINFO) {
6518 ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message);
6522 return ::CallNextHookEx(sCallProcHook, code, wParam, lParam);
6525 // Register the special "hooks" for dropdown processing.
6526 void nsWindow::RegisterSpecialDropdownHooks()
6528 NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!");
6529 NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!");
6531 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
6533 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
6535 // Install msg hook for moving the window and resizing
6536 if (!sMsgFilterHook) {
6537 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
6538 sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, NULL, GetCurrentThreadId());
6539 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6540 if (!sMsgFilterHook) {
6541 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
6543 #endif
6546 // Install msg hook for menus
6547 if (!sCallProcHook) {
6548 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
6549 sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, NULL, GetCurrentThreadId());
6550 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6551 if (!sCallProcHook) {
6552 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
6554 #endif
6557 // Install msg hook for the mouse
6558 if (!sCallMouseHook) {
6559 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
6560 sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, NULL, GetCurrentThreadId());
6561 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
6562 if (!sCallMouseHook) {
6563 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
6565 #endif
6569 // Unhook special message hooks for dropdowns.
6570 void nsWindow::UnregisterSpecialDropdownHooks()
6572 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
6574 if (sCallProcHook) {
6575 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
6576 if (!::UnhookWindowsHookEx(sCallProcHook)) {
6577 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
6579 sCallProcHook = NULL;
6582 if (sMsgFilterHook) {
6583 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
6584 if (!::UnhookWindowsHookEx(sMsgFilterHook)) {
6585 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
6587 sMsgFilterHook = NULL;
6590 if (sCallMouseHook) {
6591 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
6592 if (!::UnhookWindowsHookEx(sCallMouseHook)) {
6593 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
6595 sCallMouseHook = NULL;
6599 // This timer is designed to only fire one time at most each time a "hook" function
6600 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
6601 // hook, but that hook event or a subsequent event may roll up the dropdown before
6602 // this timer function is executed.
6604 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
6605 // before this function fires.
6606 VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
6608 if (sHookTimerId != 0) {
6609 // if the window is NULL then we need to use the ID to kill the timer
6610 BOOL status = ::KillTimer(NULL, sHookTimerId);
6611 NS_ASSERTION(status, "Hook Timer was not killed.");
6612 sHookTimerId = 0;
6615 if (sRollupMsgId != 0) {
6616 // Note: DealWithPopups does the check to make sure that
6617 // sRollupListener and sRollupWidget are not NULL
6618 LRESULT popupHandlingResult;
6619 nsAutoRollup autoRollup;
6620 DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
6621 sRollupMsgId = 0;
6622 sRollupMsgWnd = NULL;
6625 #endif // WinCE
6627 static PRBool IsDifferentThreadWindow(HWND aWnd)
6629 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, NULL);
6632 PRBool
6633 nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
6635 RECT r;
6637 #ifndef WINCE
6638 if (Msg == WM_ACTIVATEAPP)
6639 // don't care about activation/deactivation
6640 return PR_FALSE;
6641 #else
6642 if (Msg == WM_ACTIVATE)
6643 // but on Windows CE we do care about
6644 // activation/deactivation because there doesn't exist
6645 // cancelable Mouse Activation events
6646 return PR_TRUE;
6647 #endif
6649 ::GetWindowRect(aWindow->mWnd, &r);
6650 DWORD pos = ::GetMessagePos();
6651 POINT mp;
6652 mp.x = GET_X_LPARAM(pos);
6653 mp.y = GET_Y_LPARAM(pos);
6655 // was the event inside this window?
6656 return (PRBool) PtInRect(&r, mp);
6659 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
6660 BOOL
6661 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
6663 if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
6665 if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
6666 inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
6667 (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam))
6668 #ifndef WINCE
6670 inMsg == WM_NCRBUTTONDOWN ||
6671 inMsg == WM_MOVING ||
6672 inMsg == WM_SIZING ||
6673 inMsg == WM_NCLBUTTONDOWN ||
6674 inMsg == WM_NCMBUTTONDOWN ||
6675 inMsg == WM_MOUSEACTIVATE ||
6676 inMsg == WM_ACTIVATEAPP ||
6677 inMsg == WM_MENUSELECT
6678 #endif
6681 // Rollup if the event is outside the popup.
6682 PRBool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)sRollupWidget);
6684 if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL))
6686 sRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
6687 *outResult = PR_TRUE;
6690 // If we're dealing with menus, we probably have submenus and we don't
6691 // want to rollup if the click is in a parent menu of the current submenu.
6692 PRUint32 popupsToRollup = PR_UINT32_MAX;
6693 if (rollup) {
6694 nsCOMPtr<nsIMenuRollup> menuRollup ( do_QueryInterface(sRollupListener) );
6695 if ( menuRollup ) {
6696 nsAutoTArray<nsIWidget*, 5> widgetChain;
6697 PRUint32 sameTypeCount = menuRollup->GetSubmenuWidgetChain(&widgetChain);
6698 for ( PRUint32 i = 0; i < widgetChain.Length(); ++i ) {
6699 nsIWidget* widget = widgetChain[i];
6700 if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
6701 // don't roll up if the mouse event occured within a menu of the
6702 // same type. If the mouse event occured in a menu higher than
6703 // that, roll up, but pass the number of popups to Rollup so
6704 // that only those of the same type close up.
6705 if (i < sameTypeCount) {
6706 rollup = PR_FALSE;
6708 else {
6709 popupsToRollup = sameTypeCount;
6711 break;
6713 } // foreach parent menu widget
6714 } // if rollup listener knows about menus
6717 #ifndef WINCE
6718 if (inMsg == WM_MOUSEACTIVATE && popupsToRollup == PR_UINT32_MAX) {
6719 // Prevent the click inside the popup from causing a change in window
6720 // activation. Since the popup is shown non-activated, we need to eat
6721 // any requests to activate the window while it is displayed. Windows
6722 // will automatically activate the popup on the mousedown otherwise.
6723 if (!rollup) {
6724 *outResult = MA_NOACTIVATE;
6725 return TRUE;
6727 else
6729 UINT uMsg = HIWORD(inLParam);
6730 if (uMsg == WM_MOUSEMOVE)
6732 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
6733 // must be enabled in Windows.
6734 sRollupListener->ShouldRollupOnMouseActivate(&rollup);
6735 if (!rollup)
6737 *outResult = MA_NOACTIVATE;
6738 return true;
6743 // if we've still determined that we should still rollup everything, do it.
6744 else
6745 #endif
6746 if ( rollup ) {
6747 // sRollupConsumeEvent may be modified by
6748 // nsIRollupListener::Rollup.
6749 PRBool consumeRollupEvent = sRollupConsumeEvent;
6750 // only need to deal with the last rollup for left mouse down events.
6751 sRollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN ? &mLastRollup : nsnull);
6753 // Tell hook to stop processing messages
6754 sProcessHook = PR_FALSE;
6755 sRollupMsgId = 0;
6756 sRollupMsgWnd = NULL;
6758 // return TRUE tells Windows that the event is consumed,
6759 // false allows the event to be dispatched
6761 // So if we are NOT supposed to be consuming events, let it go through
6762 if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
6763 *outResult = TRUE;
6764 return TRUE;
6766 #ifndef WINCE
6767 // if we are only rolling up some popups, don't activate and don't let
6768 // the event go through. This prevents clicks menus higher in the
6769 // chain from opening when a context menu is open
6770 if (popupsToRollup != PR_UINT32_MAX && inMsg == WM_MOUSEACTIVATE) {
6771 *outResult = MA_NOACTIVATEANDEAT;
6772 return TRUE;
6774 #endif
6776 } // if event that might trigger a popup to rollup
6777 } // if rollup listeners registered
6779 return FALSE;
6782 /**************************************************************
6783 **************************************************************
6785 ** BLOCK: Misc. utility methods and functions.
6787 ** General use.
6789 **************************************************************
6790 **************************************************************/
6792 // nsModifierKeyState used in various character processing.
6793 nsModifierKeyState::nsModifierKeyState()
6795 mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT);
6796 mIsControlDown = IS_VK_DOWN(NS_VK_CONTROL);
6797 mIsAltDown = IS_VK_DOWN(NS_VK_ALT);
6801 PRInt32 nsWindow::GetWindowsVersion()
6803 #ifdef WINCE
6804 return 0x500;
6805 #else
6806 static PRInt32 version = 0;
6807 static PRBool didCheck = PR_FALSE;
6809 if (!didCheck)
6811 didCheck = PR_TRUE;
6812 OSVERSIONINFOEX osInfo;
6813 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
6814 // This cast is safe and supposed to be here, don't worry
6815 ::GetVersionEx((OSVERSIONINFO*)&osInfo);
6816 version = (osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
6818 return version;
6819 #endif
6822 // Note that the result of GetTopLevelWindow method can be different from the
6823 // result of GetTopLevelHWND method. The result can be non-floating window.
6824 // Because our top level window may be contained in another window which is
6825 // not managed by us.
6826 nsWindow* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup)
6828 nsWindow* curWindow = this;
6830 while (PR_TRUE) {
6831 if (aStopOnDialogOrPopup) {
6832 switch (curWindow->mWindowType) {
6833 case eWindowType_dialog:
6834 case eWindowType_popup:
6835 return curWindow;
6839 // Retrieve the top level parent or owner window
6840 nsWindow* parentWindow = curWindow->GetParentWindow(PR_TRUE);
6842 if (!parentWindow)
6843 return curWindow;
6845 curWindow = parentWindow;
6849 // Note that the result of GetTopLevelHWND can be different from the result
6850 // of GetTopLevelWindow method. Because this is checking whether the window
6851 // is top level only in Win32 window system. Therefore, the result window
6852 // may not be managed by us.
6853 HWND nsWindow::GetTopLevelHWND(HWND aWnd, PRBool aStopOnDialogOrPopup)
6855 HWND curWnd = aWnd;
6856 HWND topWnd = NULL;
6857 HWND upWnd = NULL;
6859 while (curWnd) {
6860 topWnd = curWnd;
6862 if (aStopOnDialogOrPopup) {
6863 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
6865 VERIFY_WINDOW_STYLE(style);
6867 if (!(style & WS_CHILD)) // first top-level window
6868 break;
6871 upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
6873 #ifdef WINCE
6874 // For dialog windows, we want just the parent, not the owner.
6875 // For other/popup windows, we want to find the first owner/parent
6876 // that's a dialog and/or has an owner.
6877 if (upWnd && ::GetWindow(curWnd, GW_OWNER) == upWnd) {
6878 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
6879 if ((style & WS_DLGFRAME) != 0)
6880 break;
6882 #endif
6884 curWnd = upWnd;
6887 return topWnd;
6890 static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam)
6892 DWORD pid;
6893 ::GetWindowThreadProcessId(hwnd, &pid);
6894 if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd))
6896 gWindowsVisible = PR_TRUE;
6897 return FALSE;
6899 return TRUE;
6902 PRBool nsWindow::CanTakeFocus()
6904 gWindowsVisible = PR_FALSE;
6905 EnumWindows(gEnumWindowsProc, 0);
6906 if (!gWindowsVisible) {
6907 return PR_TRUE;
6908 } else {
6909 HWND fgWnd = ::GetForegroundWindow();
6910 if (!fgWnd) {
6911 return PR_TRUE;
6913 DWORD pid;
6914 GetWindowThreadProcessId(fgWnd, &pid);
6915 if (pid == GetCurrentProcessId()) {
6916 return PR_TRUE;
6919 return PR_FALSE;
6922 #if !defined(WINCE)
6923 void nsWindow::InitTrackPointHack()
6925 // Init Trackpoint Hack
6926 nsresult rv;
6927 PRInt32 lHackValue;
6928 long lResult;
6929 const WCHAR wstrKeys[][40] = {L"Software\\Lenovo\\TrackPoint",
6930 L"Software\\Lenovo\\UltraNav",
6931 L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
6932 // If anything fails turn the hack off
6933 sTrackPointHack = false;
6934 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
6935 if(NS_SUCCEEDED(rv) && prefs) {
6936 prefs->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue);
6937 switch (lHackValue) {
6938 // 0 means hack disabled
6939 case 0:
6940 break;
6941 // 1 means hack enabled
6942 case 1:
6943 sTrackPointHack = true;
6944 break;
6945 // -1 means autodetect
6946 case -1:
6947 for(int i = 0; i < NS_ARRAY_LENGTH(wstrKeys); i++) {
6948 HKEY hKey;
6949 lResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, (LPCWSTR)&wstrKeys[i],
6950 0, KEY_READ, &hKey);
6951 ::RegCloseKey(hKey);
6952 if(lResult == ERROR_SUCCESS) {
6953 // If we detected a registry key belonging to a TrackPoint driver
6954 // Turn on the hack
6955 sTrackPointHack = true;
6956 break;
6959 break;
6960 // Shouldn't be any other values, but treat them as disabled
6961 default:
6962 break;
6965 return;
6967 #endif // #if !defined(WINCE)
6969 LPARAM nsWindow::lParamToScreen(LPARAM lParam)
6971 POINT pt;
6972 pt.x = GET_X_LPARAM(lParam);
6973 pt.y = GET_Y_LPARAM(lParam);
6974 ::ClientToScreen(mWnd, &pt);
6975 return MAKELPARAM(pt.x, pt.y);
6978 LPARAM nsWindow::lParamToClient(LPARAM lParam)
6980 POINT pt;
6981 pt.x = GET_X_LPARAM(lParam);
6982 pt.y = GET_Y_LPARAM(lParam);
6983 ::ScreenToClient(mWnd, &pt);
6984 return MAKELPARAM(pt.x, pt.y);
6987 /**************************************************************
6988 **************************************************************
6990 ** BLOCK: ChildWindow impl.
6992 ** Child window overrides.
6994 **************************************************************
6995 **************************************************************/
6997 // Deal with all sort of mouse event
6998 PRBool ChildWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam, LPARAM lParam,
6999 PRBool aIsContextMenuKey, PRInt16 aButton)
7001 PRBool result = PR_FALSE;
7003 if (nsnull == mEventCallback) {
7004 return result;
7007 switch (aEventType) {
7008 case NS_MOUSE_BUTTON_DOWN:
7009 CaptureMouse(PR_TRUE);
7010 break;
7012 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
7013 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
7014 case NS_MOUSE_BUTTON_UP:
7015 case NS_MOUSE_MOVE:
7016 case NS_MOUSE_EXIT:
7017 if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && mIsInMouseCapture)
7018 CaptureMouse(PR_FALSE);
7019 break;
7021 default:
7022 break;
7024 } // switch
7026 return nsWindow::DispatchMouseEvent(aEventType, wParam, lParam,
7027 aIsContextMenuKey, aButton);
7030 // return the style for a child nsWindow
7031 DWORD ChildWindow::WindowStyle()
7033 DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle();
7034 if (!(style & WS_POPUP))
7035 style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
7036 VERIFY_WINDOW_STYLE(style);
7037 return style;