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