Bug 602450 - Don't bring the system menu up in the tab bar. r=neil, a=final
[mozilla-central.git] / widget / src / windows / nsWindow.cpp
blobb9ba8911ef52e3e03ab238cc6cb4b5a00764cfd1
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 <matspal@gmail.com>
37 * Ningjie Chen <chenn@email.uc.edu>
38 * Jim Mathies <jmathies@mozilla.com>
39 * Kyle Huey <me@kylehuey.com>
41 * Alternatively, the contents of this file may be used under the terms of
42 * either the GNU General Public License Version 2 or later (the "GPL"), or
43 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
44 * in which case the provisions of the GPL or the LGPL are applicable instead
45 * of those above. If you wish to allow use of your version of this file only
46 * under the terms of either the GPL or the LGPL, and not to allow others to
47 * use your version of this file under the terms of the MPL, indicate your
48 * decision by deleting the provisions above and replace them with the notice
49 * and other provisions required by the GPL or the LGPL. If you do not delete
50 * the provisions above, a recipient may use your version of this file under
51 * the terms of any one of the MPL, the GPL or the LGPL.
53 * ***** END LICENSE BLOCK ***** */
56 * nsWindow - Native window management and event handling.
58 * nsWindow is organized into a set of major blocks and
59 * block subsections. The layout is as follows:
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 "nsIPrefBranch2.h"
129 #include "nsIPrefService.h"
130 #include "nsIObserverService.h"
131 #include "nsIScreenManager.h"
132 #include "imgIContainer.h"
133 #include "nsIFile.h"
134 #include "nsIRollupListener.h"
135 #include "nsIMenuRollup.h"
136 #include "nsIRegion.h"
137 #include "nsIServiceManager.h"
138 #include "nsIClipboard.h"
139 #include "nsIMM32Handler.h"
140 #include "nsILocalFile.h"
141 #include "nsIFontMetrics.h"
142 #include "nsIFontEnumerator.h"
143 #include "nsIDeviceContext.h"
144 #include "nsILookAndFeel.h"
145 #include "nsGUIEvent.h"
146 #include "nsFont.h"
147 #include "nsRect.h"
148 #include "nsThreadUtils.h"
149 #include "nsNativeCharsetUtils.h"
150 #include "nsWidgetAtoms.h"
151 #include "nsUnicharUtils.h"
152 #include "nsCRT.h"
153 #include "nsAppDirectoryServiceDefs.h"
154 #include "nsXPIDLString.h"
155 #include "nsWidgetsCID.h"
156 #include "nsTHashtable.h"
157 #include "nsHashKeys.h"
158 #include "nsString.h"
159 #include "mozilla/Services.h"
160 #include "nsNativeThemeWin.h"
162 #if defined(WINCE)
163 #include "nsWindowCE.h"
164 #endif
166 #if defined(WINCE_WINDOWS_MOBILE)
167 #define KILL_PRIORITY_ID 2444
168 #endif
170 #include "nsWindowGfx.h"
171 #include "gfxWindowsPlatform.h"
172 #include "Layers.h"
173 #ifndef WINCE
174 #ifdef MOZ_ENABLE_D3D9_LAYER
175 #include "LayerManagerD3D9.h"
176 #endif
177 #ifdef MOZ_ENABLE_D3D10_LAYER
178 #include "LayerManagerD3D10.h"
179 #endif
180 #include "LayerManagerOGL.h"
181 #endif
182 #include "BasicLayers.h"
184 #if !defined(WINCE)
185 #include "nsUXThemeConstants.h"
186 #include "KeyboardLayout.h"
187 #include "nsNativeDragTarget.h"
188 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
189 #include <zmouse.h>
190 #include <pbt.h>
191 #include <richedit.h>
192 #endif // !defined(WINCE)
194 #if defined(ACCESSIBILITY)
195 #include "oleidl.h"
196 #include <winuser.h>
197 #include "nsIAccessibleDocument.h"
198 #if !defined(WINABLEAPI)
199 #include <winable.h>
200 #endif // !defined(WINABLEAPI)
201 #endif // defined(ACCESSIBILITY)
203 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
204 #include "nsIWinTaskbar.h"
205 #endif
207 #if defined(NS_ENABLE_TSF)
208 #include "nsTextStore.h"
209 #endif // defined(NS_ENABLE_TSF)
211 #if defined(MOZ_SPLASHSCREEN)
212 #include "nsSplashScreen.h"
213 #endif // defined(MOZ_SPLASHSCREEN)
215 // Windowless plugin support
216 #include "npapi.h"
218 #include "nsWindowDefs.h"
220 #include "mozilla/FunctionTimer.h"
222 #ifdef WINCE_WINDOWS_MOBILE
223 #include "nsGfxCIID.h"
224 #endif
226 #include "mozilla/FunctionTimer.h"
228 #ifdef MOZ_CRASHREPORTER
229 #include "nsICrashReporter.h"
230 #endif
232 #include "nsIXULRuntime.h"
234 using namespace mozilla::widget;
236 /**************************************************************
237 **************************************************************
239 ** BLOCK: Variables
241 ** nsWindow Class static initializations and global variables.
243 **************************************************************
244 **************************************************************/
246 /**************************************************************
248 * SECTION: nsWindow statics
250 **************************************************************/
252 PRUint32 nsWindow::sInstanceCount = 0;
253 PRBool nsWindow::sSwitchKeyboardLayout = PR_FALSE;
254 BOOL nsWindow::sIsRegistered = FALSE;
255 BOOL nsWindow::sIsPopupClassRegistered = FALSE;
256 BOOL nsWindow::sIsOleInitialized = FALSE;
257 HCURSOR nsWindow::sHCursor = NULL;
258 imgIContainer* nsWindow::sCursorImgContainer = nsnull;
259 nsWindow* nsWindow::sCurrentWindow = nsnull;
260 PRBool nsWindow::sJustGotDeactivate = PR_FALSE;
261 PRBool nsWindow::sJustGotActivate = PR_FALSE;
263 // imported in nsWidgetFactory.cpp
264 TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN;
266 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
267 // hook methods whether they should be processing the hook
268 // messages.
269 HHOOK nsWindow::sMsgFilterHook = NULL;
270 HHOOK nsWindow::sCallProcHook = NULL;
271 HHOOK nsWindow::sCallMouseHook = NULL;
272 PRPackedBool nsWindow::sProcessHook = PR_FALSE;
273 UINT nsWindow::sRollupMsgId = 0;
274 HWND nsWindow::sRollupMsgWnd = NULL;
275 UINT nsWindow::sHookTimerId = 0;
277 // Rollup Listener
278 nsIRollupListener* nsWindow::sRollupListener = nsnull;
279 nsIMenuRollup* nsWindow::sMenuRollup = nsnull;
280 nsIWidget* nsWindow::sRollupWidget = nsnull;
281 PRBool nsWindow::sRollupConsumeEvent = PR_FALSE;
283 // Mouse Clicks - static variable definitions for figuring
284 // out 1 - 3 Clicks.
285 POINT nsWindow::sLastMousePoint = {0};
286 POINT nsWindow::sLastMouseMovePoint = {0};
287 LONG nsWindow::sLastMouseDownTime = 0L;
288 LONG nsWindow::sLastClickCount = 0L;
289 BYTE nsWindow::sLastMouseButton = 0;
291 // Trim heap on minimize. (initialized, but still true.)
292 int nsWindow::sTrimOnMinimize = 2;
294 // Default Trackpoint Hack to off
295 PRBool nsWindow::sTrackPointHack = PR_FALSE;
297 #ifdef ACCESSIBILITY
298 BOOL nsWindow::sIsAccessibilityOn = FALSE;
299 // Accessibility wm_getobject handler
300 HINSTANCE nsWindow::sAccLib = 0;
301 LPFNLRESULTFROMOBJECT
302 nsWindow::sLresultFromObject = 0;
303 #endif // ACCESSIBILITY
305 #ifdef MOZ_IPC
306 // Used in OOPP plugin focus processing.
307 const PRUnichar* kOOPPPluginFocusEventId = L"OOPP Plugin Focus Widget Event";
308 PRUint32 nsWindow::sOOPPPluginFocusEvent =
309 RegisterWindowMessageW(kOOPPPluginFocusEventId);
310 #endif
312 /**************************************************************
314 * SECTION: globals variables
316 **************************************************************/
318 static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
320 #ifdef PR_LOGGING
321 PRLogModuleInfo* gWindowsLog = nsnull;
322 #endif
324 #ifndef WINCE
325 // Kbd layout. Used throughout character processing.
326 static KeyboardLayout gKbdLayout;
327 #endif
329 #ifdef WINCE_WINDOWS_MOBILE
330 // HTC Navigation Wheel Event
331 // This is the defined value for Gesture Mode
332 const int WM_HTCNAV = 0x0400 + 200;
334 typedef int (__stdcall * HTCApiNavOpen)(HANDLE, int);
335 typedef int (__stdcall * HTCApiNavSetMode)(HANDLE, unsigned int);
337 HTCApiNavOpen gHTCApiNavOpen = nsnull;
338 HTCApiNavSetMode gHTCApiNavSetMode = nsnull;
339 static PRBool gCheckForHTCApi = PR_FALSE;
340 #endif
342 // Global user preference for disabling native theme. Used
343 // in NativeWindowTheme.
344 PRBool gDisableNativeTheme = PR_FALSE;
346 // Global used in Show window enumerations.
347 static PRBool gWindowsVisible = PR_FALSE;
349 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
350 #ifdef WINCE_WINDOWS_MOBILE
351 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
352 #endif
354 /**************************************************************
355 **************************************************************
357 ** BLOCK: nsIWidget impl.
359 ** nsIWidget interface implementation, broken down into
360 ** sections.
362 **************************************************************
363 **************************************************************/
365 /**************************************************************
367 * SECTION: nsWindow construction and destruction
369 **************************************************************/
371 nsWindow::nsWindow() : nsBaseWidget()
373 #ifdef PR_LOGGING
374 if (!gWindowsLog)
375 gWindowsLog = PR_NewLogModule("nsWindowsWidgets");
376 #endif
378 mWnd = nsnull;
379 mPaintDC = nsnull;
380 mPrevWndProc = nsnull;
381 mOldIMC = nsnull;
382 mNativeDragTarget = nsnull;
383 mInDtor = PR_FALSE;
384 mIsVisible = PR_FALSE;
385 mIsInMouseCapture = PR_FALSE;
386 mIsTopWidgetWindow = PR_FALSE;
387 mUnicodeWidget = PR_TRUE;
388 mDisplayPanFeedback = PR_FALSE;
389 mTouchWindow = PR_FALSE;
390 mCustomNonClient = PR_FALSE;
391 mHideChrome = PR_FALSE;
392 mFullscreenMode = PR_FALSE;
393 mWindowType = eWindowType_child;
394 mBorderStyle = eBorderStyle_default;
395 mPopupType = ePopupTypeAny;
396 mOldSizeMode = nsSizeMode_Normal;
397 mLastPoint.x = 0;
398 mLastPoint.y = 0;
399 mLastSize.width = 0;
400 mLastSize.height = 0;
401 mOldStyle = 0;
402 mOldExStyle = 0;
403 mPainting = 0;
404 mExitToNonClientArea = 0;
405 mLastKeyboardLayout = 0;
406 mBlurSuppressLevel = 0;
407 mIMEEnabled = nsIWidget::IME_STATUS_ENABLED;
408 #ifdef MOZ_XUL
409 mTransparentSurface = nsnull;
410 mMemoryDC = nsnull;
411 mTransparencyMode = eTransparencyOpaque;
412 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
413 memset(&mGlassMargins, 0, sizeof mGlassMargins);
414 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
415 #endif
416 mBackground = ::GetSysColor(COLOR_BTNFACE);
417 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
418 mForeground = ::GetSysColor(COLOR_WINDOWTEXT);
420 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
421 mTaskbarPreview = nsnull;
422 mHasTaskbarIconBeenCreated = PR_FALSE;
423 #endif
425 // Global initialization
426 if (!sInstanceCount) {
427 #if !defined(WINCE)
428 gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
429 #endif
431 // Init IME handler
432 nsIMM32Handler::Initialize();
434 #ifdef NS_ENABLE_TSF
435 nsTextStore::Initialize();
436 #endif
438 #if !defined(WINCE)
439 if (SUCCEEDED(::OleInitialize(NULL)))
440 sIsOleInitialized = TRUE;
441 NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
442 #endif
444 #if !defined(WINCE)
445 InitTrackPointHack();
446 #endif
448 // Init titlebar button info for custom frames.
449 nsUXThemeData::InitTitlebarInfo();
450 } // !sInstanceCount
452 mIdleService = nsnull;
454 sInstanceCount++;
457 nsWindow::~nsWindow()
459 mInDtor = PR_TRUE;
461 // If the widget was released without calling Destroy() then the native window still
462 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
464 // XXX How could this happen???
465 if (NULL != mWnd)
466 Destroy();
468 sInstanceCount--;
470 // Global shutdown
471 if (sInstanceCount == 0) {
472 #ifdef NS_ENABLE_TSF
473 nsTextStore::Terminate();
474 #endif
476 #if !defined(WINCE)
477 NS_IF_RELEASE(sCursorImgContainer);
478 if (sIsOleInitialized) {
479 ::OleFlushClipboard();
480 ::OleUninitialize();
481 sIsOleInitialized = FALSE;
483 // delete any of the IME structures that we allocated
484 nsIMM32Handler::Terminate();
485 #endif // !defined(WINCE)
488 #if !defined(WINCE)
489 NS_IF_RELEASE(mNativeDragTarget);
490 #endif // !defined(WINCE)
493 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
495 /**************************************************************
497 * SECTION: nsIWidget::Create, nsIWidget::Destroy
499 * Creating and destroying windows for this widget.
501 **************************************************************/
503 // Allow Derived classes to modify the height that is passed
504 // when the window is created or resized. Also add extra height
505 // if needed (on Windows CE)
506 PRInt32 nsWindow::GetHeight(PRInt32 aProposedHeight)
508 PRInt32 extra = 0;
510 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
511 DWORD style = WindowStyle();
512 if ((style & WS_SYSMENU) && (style & WS_POPUP)) {
513 extra = GetSystemMetrics(SM_CYCAPTION);
515 #endif
517 return aProposedHeight + extra;
520 // Create the proper widget
521 nsresult
522 nsWindow::Create(nsIWidget *aParent,
523 nsNativeWidget aNativeParent,
524 const nsIntRect &aRect,
525 EVENT_CALLBACK aHandleEventFunction,
526 nsIDeviceContext *aContext,
527 nsIAppShell *aAppShell,
528 nsIToolkit *aToolkit,
529 nsWidgetInitData *aInitData)
531 nsWidgetInitData defaultInitData;
532 if (!aInitData)
533 aInitData = &defaultInitData;
535 mUnicodeWidget = aInitData->mUnicode;
537 nsIWidget *baseParent = aInitData->mWindowType == eWindowType_dialog ||
538 aInitData->mWindowType == eWindowType_toplevel ||
539 aInitData->mWindowType == eWindowType_invisible ?
540 nsnull : aParent;
542 mIsTopWidgetWindow = (nsnull == baseParent);
543 mBounds.width = aRect.width;
544 mBounds.height = aRect.height;
546 BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
547 aAppShell, aToolkit, aInitData);
549 HWND parent;
550 if (aParent) { // has a nsIWidget parent
551 parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : NULL;
552 mParent = aParent;
553 } else { // has a nsNative parent
554 parent = (HWND)aNativeParent;
555 mParent = aNativeParent ? GetNSWindowPtr((HWND)aNativeParent) : nsnull;
558 mPopupType = aInitData->mPopupHint;
559 mIsRTL = aInitData->mRTL;
561 DWORD style = WindowStyle();
562 DWORD extendedStyle = WindowExStyle();
564 if (mWindowType == eWindowType_popup) {
565 if (!aParent)
566 parent = NULL;
567 } else if (mWindowType == eWindowType_invisible) {
568 // Make sure CreateWindowEx succeeds at creating a toplevel window
569 style &= ~0x40000000; // WS_CHILDWINDOW
570 } else {
571 // See if the caller wants to explictly set clip children and clip siblings
572 if (aInitData->clipChildren) {
573 style |= WS_CLIPCHILDREN;
574 } else {
575 style &= ~WS_CLIPCHILDREN;
577 if (aInitData->clipSiblings) {
578 style |= WS_CLIPSIBLINGS;
582 mWnd = ::CreateWindowExW(extendedStyle,
583 aInitData->mDropShadow ?
584 WindowPopupClass() : WindowClass(),
585 L"",
586 style,
587 aRect.x,
588 aRect.y,
589 aRect.width,
590 GetHeight(aRect.height),
591 parent,
592 NULL,
593 nsToolkit::mDllInstance,
594 NULL);
596 if (!mWnd) {
597 NS_WARNING("nsWindow CreateWindowEx failed.");
598 return NS_ERROR_FAILURE;
601 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
602 if (mIsRTL && nsUXThemeData::dwmSetWindowAttributePtr) {
603 DWORD dwAttribute = TRUE;
604 nsUXThemeData::dwmSetWindowAttributePtr(mWnd, DWMWA_NONCLIENT_RTL_LAYOUT, &dwAttribute, sizeof dwAttribute);
606 #endif
608 if (nsWindow::sTrackPointHack &&
609 mWindowType != eWindowType_plugin &&
610 mWindowType != eWindowType_invisible) {
611 // Ugly Thinkpad Driver Hack (Bug 507222)
612 // We create an invisible scrollbar to trick the
613 // Trackpoint driver into sending us scrolling messages
614 ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTSCROLLBAR",
615 WS_CHILD | WS_VISIBLE, 0,0,0,0, mWnd, NULL,
616 nsToolkit::mDllInstance, NULL);
619 // call the event callback to notify about creation
621 DispatchStandardEvent(NS_CREATE);
622 SubclassWindow(TRUE);
624 if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
625 /* The internal variable set by the config.trim_on_minimize pref
626 has not yet been initialized, and this is the hidden window
627 (conveniently created before any visible windows, and after
628 the profile has been initialized).
630 Default config.trim_on_minimize to false, to fix bug 76831
631 for good. If anyone complains about this new default, saying
632 that a Mozilla app hogs too much memory while minimized, they
633 will have that entire bug tattooed on their backside. */
635 sTrimOnMinimize = 0;
636 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
637 if (prefs) {
638 nsCOMPtr<nsIPrefBranch> prefBranch;
639 prefs->GetBranch(0, getter_AddRefs(prefBranch));
640 if (prefBranch) {
642 PRBool temp;
643 if (NS_SUCCEEDED(prefBranch->GetBoolPref("config.trim_on_minimize",
644 &temp))
645 && temp)
646 sTrimOnMinimize = 1;
648 if (NS_SUCCEEDED(prefBranch->GetBoolPref("intl.keyboard.per_window_layout",
649 &temp)))
650 sSwitchKeyboardLayout = temp;
652 if (NS_SUCCEEDED(prefBranch->GetBoolPref("mozilla.widget.disable-native-theme",
653 &temp)))
654 gDisableNativeTheme = temp;
658 #if defined(WINCE_HAVE_SOFTKB)
659 if (mWindowType == eWindowType_dialog || mWindowType == eWindowType_toplevel )
660 nsWindowCE::CreateSoftKeyMenuBar(mWnd);
661 #endif
663 return NS_OK;
666 // Close this nsWindow
667 NS_METHOD nsWindow::Destroy()
669 // WM_DESTROY has already fired, we're done.
670 if (nsnull == mWnd)
671 return NS_OK;
673 // During the destruction of all of our children, make sure we don't get deleted.
674 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
677 * On windows the LayerManagerOGL destructor wants the widget to be around for
678 * cleanup. It also would like to have the HWND intact, so we NULL it here.
680 if (mLayerManager) {
681 mLayerManager->Destroy();
683 mLayerManager = nsnull;
685 /* We should clear our cached resources now and not wait for the GC to
686 * delete the nsWindow. */
687 ClearCachedResources();
689 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
690 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
691 // from it. The function also destroys the window's menu, flushes the thread message queue,
692 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
693 // the window is at the top of the viewer chain).
695 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
696 // the associated child or owned windows when it destroys the parent or owner window. The
697 // function first destroys child or owned windows, and then it destroys the parent or owner
698 // window.
699 VERIFY(::DestroyWindow(mWnd));
701 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
702 // didn't get called, call it now.
703 if (PR_FALSE == mOnDestroyCalled)
704 OnDestroy();
706 return NS_OK;
709 /**************************************************************
711 * SECTION: Window class utilities
713 * Utilities for calculating the proper window class name for
714 * Create window.
716 **************************************************************/
718 // Return the proper window class for everything except popups.
719 LPCWSTR nsWindow::WindowClass()
721 if (!nsWindow::sIsRegistered) {
722 WNDCLASSW wc;
724 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
725 wc.style = CS_DBLCLKS;
726 wc.lpfnWndProc = ::DefWindowProcW;
727 wc.cbClsExtra = 0;
728 wc.cbWndExtra = 0;
729 wc.hInstance = nsToolkit::mDllInstance;
730 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
731 wc.hCursor = NULL;
732 wc.hbrBackground = mBrush;
733 wc.lpszMenuName = NULL;
734 wc.lpszClassName = kClassNameHidden;
736 BOOL succeeded = ::RegisterClassW(&wc) != 0 &&
737 ERROR_CLASS_ALREADY_EXISTS != GetLastError();
738 nsWindow::sIsRegistered = succeeded;
740 wc.lpszClassName = kClassNameGeneral;
741 ATOM generalClassAtom = ::RegisterClassW(&wc);
742 if (!generalClassAtom &&
743 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
744 nsWindow::sIsRegistered = FALSE;
747 wc.lpszClassName = kClassNameDialog;
748 wc.hIcon = 0;
749 if (!::RegisterClassW(&wc) &&
750 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
751 nsWindow::sIsRegistered = FALSE;
755 if (mWindowType == eWindowType_invisible) {
756 return kClassNameHidden;
758 if (mWindowType == eWindowType_dialog) {
759 return kClassNameDialog;
761 return kClassNameGeneral;
764 // Return the proper popup window class
765 LPCWSTR nsWindow::WindowPopupClass()
767 if (!nsWindow::sIsPopupClassRegistered) {
768 WNDCLASSW wc;
770 wc.style = CS_DBLCLKS | CS_XP_DROPSHADOW;
771 wc.lpfnWndProc = ::DefWindowProcW;
772 wc.cbClsExtra = 0;
773 wc.cbWndExtra = 0;
774 wc.hInstance = nsToolkit::mDllInstance;
775 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
776 wc.hCursor = NULL;
777 wc.hbrBackground = mBrush;
778 wc.lpszMenuName = NULL;
779 wc.lpszClassName = kClassNameDropShadow;
781 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
782 if (!nsWindow::sIsPopupClassRegistered) {
783 // For older versions of Win32 (i.e., not XP), the registration will
784 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
785 wc.style = CS_DBLCLKS;
786 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
790 return kClassNameDropShadow;
793 /**************************************************************
795 * SECTION: Window styles utilities
797 * Return the proper windows styles and extended styles.
799 **************************************************************/
801 // Return nsWindow styles
802 #if !defined(WINCE) // implemented in nsWindowCE.cpp
803 DWORD nsWindow::WindowStyle()
805 DWORD style;
807 switch (mWindowType) {
808 case eWindowType_plugin:
809 case eWindowType_child:
810 style = WS_OVERLAPPED;
811 break;
813 case eWindowType_dialog:
814 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK |
815 DS_MODALFRAME | WS_CLIPCHILDREN;
816 if (mBorderStyle != eBorderStyle_default)
817 style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
818 break;
820 case eWindowType_popup:
821 style = WS_POPUP;
822 if (!HasGlass()) {
823 style |= WS_OVERLAPPED;
825 break;
827 default:
828 NS_ERROR("unknown border style");
829 // fall through
831 case eWindowType_toplevel:
832 case eWindowType_invisible:
833 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU |
834 WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
835 break;
838 if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) {
839 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border))
840 style &= ~WS_BORDER;
842 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) {
843 style &= ~WS_DLGFRAME;
844 style |= WS_POPUP;
845 style &= ~WS_CHILD;
848 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close))
849 style &= ~0;
850 // XXX The close box can only be removed by changing the window class,
851 // as far as I know --- roc+moz@cs.cmu.edu
853 if (mBorderStyle == eBorderStyle_none ||
854 !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
855 style &= ~WS_SYSMENU;
856 // Looks like getting rid of the system menu also does away with the
857 // close box. So, we only get rid of the system menu if you want neither it
858 // nor the close box. How does the Windows "Dialog" window class get just
859 // closebox and no sysmenu? Who knows.
861 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh))
862 style &= ~WS_THICKFRAME;
864 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize))
865 style &= ~WS_MINIMIZEBOX;
867 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize))
868 style &= ~WS_MAXIMIZEBOX;
870 if (IsPopupWithTitleBar()) {
871 style |= WS_CAPTION;
872 if (mBorderStyle & eBorderStyle_close) {
873 style |= WS_SYSMENU;
878 VERIFY_WINDOW_STYLE(style);
879 return style;
881 #endif // !defined(WINCE)
883 // Return nsWindow extended styles
884 DWORD nsWindow::WindowExStyle()
886 switch (mWindowType)
888 case eWindowType_plugin:
889 case eWindowType_child:
890 return 0;
892 case eWindowType_dialog:
893 return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
895 case eWindowType_popup:
897 DWORD extendedStyle =
898 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
899 WS_EX_NOACTIVATE |
900 #endif
901 WS_EX_TOOLWINDOW;
902 if (mPopupLevel == ePopupLevelTop)
903 extendedStyle |= WS_EX_TOPMOST;
904 return extendedStyle;
906 default:
907 NS_ERROR("unknown border style");
908 // fall through
910 case eWindowType_toplevel:
911 case eWindowType_invisible:
912 return WS_EX_WINDOWEDGE;
916 /**************************************************************
918 * SECTION: Window subclassing utilities
920 * Set or clear window subclasses on native windows. Used in
921 * Create and Destroy.
923 **************************************************************/
925 // Subclass (or remove the subclass from) this component's nsWindow
926 void nsWindow::SubclassWindow(BOOL bState)
928 if (NULL != mWnd) {
929 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
930 if (!::IsWindow(mWnd)) {
931 NS_ERROR("Invalid window handle");
934 if (bState) {
935 // change the nsWindow proc
936 if (mUnicodeWidget)
937 mPrevWndProc = (WNDPROC)::SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
938 (LONG_PTR)nsWindow::WindowProc);
939 else
940 mPrevWndProc = (WNDPROC)::SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
941 (LONG_PTR)nsWindow::WindowProc);
942 NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
943 // connect the this pointer to the nsWindow handle
944 SetNSWindowPtr(mWnd, this);
946 else {
947 if (mUnicodeWidget)
948 ::SetWindowLongPtrW(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
949 else
950 ::SetWindowLongPtrA(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
951 SetNSWindowPtr(mWnd, NULL);
952 mPrevWndProc = NULL;
957 /**************************************************************
959 * SECTION: Window properties
961 * Set and clear native window properties.
963 **************************************************************/
965 static PRUnichar sPropName[40] = L"";
966 static PRUnichar* GetNSWindowPropName()
968 if (!*sPropName)
970 _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p", GetCurrentProcessId());
971 sPropName[39] = '\0';
973 return sPropName;
976 nsWindow * nsWindow::GetNSWindowPtr(HWND aWnd)
978 return (nsWindow *) ::GetPropW(aWnd, GetNSWindowPropName());
981 BOOL nsWindow::SetNSWindowPtr(HWND aWnd, nsWindow * ptr)
983 if (ptr == NULL) {
984 ::RemovePropW(aWnd, GetNSWindowPropName());
985 return TRUE;
986 } else {
987 return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)ptr);
991 /**************************************************************
993 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
995 * Set or clear the parent widgets using window properties, and
996 * handles calculating native parent handles.
998 **************************************************************/
1000 // Get and set parent widgets
1001 NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent)
1003 mParent = aNewParent;
1005 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1006 nsIWidget* parent = GetParent();
1007 if (parent) {
1008 parent->RemoveChild(this);
1010 if (aNewParent) {
1011 ReparentNativeWidget(aNewParent);
1012 aNewParent->AddChild(this);
1013 return NS_OK;
1015 if (mWnd) {
1016 // If we have no parent, SetParent should return the desktop.
1017 VERIFY(::SetParent(mWnd, nsnull));
1019 return NS_OK;
1022 NS_IMETHODIMP
1023 nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
1025 NS_PRECONDITION(aNewParent, "");
1027 mParent = aNewParent;
1028 if (mWindowType == eWindowType_popup) {
1029 return NS_OK;
1031 HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
1032 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
1033 if (newParent && mWnd) {
1034 ::SetParent(mWnd, newParent);
1036 return NS_OK;
1039 nsIWidget* nsWindow::GetParent(void)
1041 return GetParentWindow(PR_FALSE);
1044 float nsWindow::GetDPI()
1046 HDC dc = ::GetDC(mWnd);
1047 if (!dc)
1048 return 96.0f;
1050 double heightInches = ::GetDeviceCaps(dc, VERTSIZE)/MM_PER_INCH_FLOAT;
1051 int heightPx = ::GetDeviceCaps(dc, VERTRES);
1052 ::ReleaseDC(mWnd, dc);
1053 if (heightInches < 0.25) {
1054 // Something's broken
1055 return 96.0f;
1057 return float(heightPx/heightInches);
1060 nsWindow* nsWindow::GetParentWindow(PRBool aIncludeOwner)
1062 if (mIsTopWidgetWindow) {
1063 // Must use a flag instead of mWindowType to tell if the window is the
1064 // owned by the topmost widget, because a child window can be embedded inside
1065 // a HWND which is not associated with a nsIWidget.
1066 return nsnull;
1069 // If this widget has already been destroyed, pretend we have no parent.
1070 // This corresponds to code in Destroy which removes the destroyed
1071 // widget from its parent's child list.
1072 if (mInDtor || mOnDestroyCalled)
1073 return nsnull;
1076 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1077 // root owner. aIncludeOwner set to false implies the search will stop at the
1078 // true parent (default).
1079 nsWindow* widget = nsnull;
1080 if (mWnd) {
1081 #ifdef WINCE
1082 HWND parent = ::GetParent(mWnd);
1083 #else
1084 HWND parent = nsnull;
1085 if (aIncludeOwner)
1086 parent = ::GetParent(mWnd);
1087 else
1088 parent = ::GetAncestor(mWnd, GA_PARENT);
1089 #endif
1090 if (parent) {
1091 widget = GetNSWindowPtr(parent);
1092 if (widget) {
1093 // If the widget is in the process of being destroyed then
1094 // do NOT return it
1095 if (widget->mInDtor) {
1096 widget = nsnull;
1102 return widget;
1105 /**************************************************************
1107 * SECTION: nsIWidget::Show
1109 * Hide or show this component.
1111 **************************************************************/
1113 NS_METHOD nsWindow::Show(PRBool bState)
1115 #if defined(MOZ_SPLASHSCREEN)
1116 // we're about to show the first toplevel window,
1117 // so kill off any splash screen if we had one
1118 nsSplashScreen *splash = nsSplashScreen::Get();
1119 if (splash && splash->IsOpen() && mWnd && bState &&
1120 (mWindowType == eWindowType_toplevel ||
1121 mWindowType == eWindowType_dialog ||
1122 mWindowType == eWindowType_popup))
1124 splash->Close();
1126 #endif
1128 #ifdef NS_FUNCTION_TIMER
1129 static bool firstShow = true;
1130 if (firstShow &&
1131 (mWindowType == eWindowType_toplevel ||
1132 mWindowType == eWindowType_dialog ||
1133 mWindowType == eWindowType_popup))
1135 firstShow = false;
1136 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1138 #endif
1140 PRBool wasVisible = mIsVisible;
1141 // Set the status now so that anyone asking during ShowWindow or
1142 // SetWindowPos would get the correct answer.
1143 mIsVisible = bState;
1145 if (!mIsVisible && wasVisible) {
1146 ClearCachedResources();
1149 if (mWnd) {
1150 if (bState) {
1151 if (!wasVisible && mWindowType == eWindowType_toplevel) {
1152 switch (mSizeMode) {
1153 #ifdef WINCE
1154 case nsSizeMode_Fullscreen:
1155 ::SetForegroundWindow(mWnd);
1156 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1157 MakeFullScreen(TRUE);
1158 break;
1160 case nsSizeMode_Maximized :
1161 ::SetForegroundWindow(mWnd);
1162 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1163 break;
1164 // use default for nsSizeMode_Minimized on Windows CE
1165 #else
1166 case nsSizeMode_Maximized :
1167 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1168 break;
1169 case nsSizeMode_Minimized :
1170 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
1171 break;
1172 #endif
1173 default:
1174 if (CanTakeFocus()) {
1175 #ifdef WINCE
1176 ::SetForegroundWindow(mWnd);
1177 #endif
1178 ::ShowWindow(mWnd, SW_SHOWNORMAL);
1179 } else {
1180 // Place the window behind the foreground window
1181 // (as long as it is not topmost)
1182 HWND wndAfter = ::GetForegroundWindow();
1183 if (!wndAfter)
1184 wndAfter = HWND_BOTTOM;
1185 else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)
1186 wndAfter = HWND_TOP;
1187 ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE |
1188 SWP_NOMOVE | SWP_NOACTIVATE);
1189 GetAttention(2);
1191 break;
1193 } else {
1194 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
1195 if (wasVisible)
1196 flags |= SWP_NOZORDER;
1198 if (mWindowType == eWindowType_popup) {
1199 #ifndef WINCE
1200 // ensure popups are the topmost of the TOPMOST
1201 // layer. Remember not to set the SWP_NOZORDER
1202 // flag as that might allow the taskbar to overlap
1203 // the popup. However on windows ce, we need to
1204 // activate the popup or clicks will not be sent.
1205 flags |= SWP_NOACTIVATE;
1206 #endif
1207 HWND owner = ::GetWindow(mWnd, GW_OWNER);
1208 ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
1209 } else {
1210 #ifndef WINCE
1211 if (mWindowType == eWindowType_dialog && !CanTakeFocus())
1212 flags |= SWP_NOACTIVATE;
1213 #endif
1214 ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
1218 #ifndef WINCE
1219 if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) {
1220 // when a toplevel window or dialog is shown, initialize the UI state
1221 ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
1223 #endif
1224 } else {
1225 if (mWindowType != eWindowType_dialog) {
1226 ::ShowWindow(mWnd, SW_HIDE);
1227 } else {
1228 ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1229 SWP_NOZORDER | SWP_NOACTIVATE);
1234 #ifdef MOZ_XUL
1235 if (!wasVisible && bState)
1236 Invalidate(PR_FALSE);
1237 #endif
1239 return NS_OK;
1242 /**************************************************************
1244 * SECTION: nsIWidget::IsVisible
1246 * Returns the visibility state.
1248 **************************************************************/
1250 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1251 NS_METHOD nsWindow::IsVisible(PRBool & bState)
1253 bState = mIsVisible;
1254 return NS_OK;
1257 /**************************************************************
1259 * SECTION: Window clipping utilities
1261 * Used in Size and Move operations for setting the proper
1262 * window clipping regions for window transparency.
1264 **************************************************************/
1266 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1267 // transparency. These routines are called on size and move operations.
1268 void nsWindow::ClearThemeRegion()
1270 #ifndef WINCE
1271 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1272 (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1273 (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1274 SetWindowRgn(mWnd, NULL, false);
1276 #endif
1279 void nsWindow::SetThemeRegion()
1281 #ifndef WINCE
1282 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1283 // for other window types as needed. The regions are applied generically to the base window
1284 // so default constants are used for part and state. At some point we might need part and
1285 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1286 // change shape based on state haven't come up.
1287 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1288 (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1289 (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1290 HRGN hRgn = nsnull;
1291 RECT rect = {0,0,mBounds.width,mBounds.height};
1293 HDC dc = ::GetDC(mWnd);
1294 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
1295 if (hRgn) {
1296 if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted.
1297 DeleteObject(hRgn);
1299 ::ReleaseDC(mWnd, dc);
1301 #endif
1304 /**************************************************************
1306 * SECTION: nsIWidget::RegisterTouchWindow,
1307 * nsIWidget::UnregisterTouchWindow, and helper functions
1309 * Used to register the native window to receive touch events
1311 **************************************************************/
1313 NS_METHOD nsWindow::RegisterTouchWindow() {
1314 mTouchWindow = PR_TRUE;
1315 #ifndef WINCE
1316 mGesture.RegisterTouchWindow(mWnd);
1317 ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
1318 #endif
1319 return NS_OK;
1322 NS_METHOD nsWindow::UnregisterTouchWindow() {
1323 mTouchWindow = PR_FALSE;
1324 #ifndef WINCE
1325 mGesture.UnregisterTouchWindow(mWnd);
1326 ::EnumChildWindows(mWnd, nsWindow::UnregisterTouchForDescendants, 0);
1327 #endif
1328 return NS_OK;
1331 #ifndef WINCE
1332 BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1333 nsWindow* win = GetNSWindowPtr(aWnd);
1334 if (win)
1335 win->mGesture.RegisterTouchWindow(aWnd);
1336 return TRUE;
1339 BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1340 nsWindow* win = GetNSWindowPtr(aWnd);
1341 if (win)
1342 win->mGesture.UnregisterTouchWindow(aWnd);
1343 return TRUE;
1345 #endif
1347 /**************************************************************
1349 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1350 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1352 * Repositioning and sizing a window.
1354 **************************************************************/
1356 // Move this component
1357 NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
1359 if (mWindowType == eWindowType_toplevel ||
1360 mWindowType == eWindowType_dialog) {
1361 SetSizeMode(nsSizeMode_Normal);
1363 // Check to see if window needs to be moved first
1364 // to avoid a costly call to SetWindowPos. This check
1365 // can not be moved to the calling code in nsView, because
1366 // some platforms do not position child windows correctly
1368 // Only perform this check for non-popup windows, since the positioning can
1369 // in fact change even when the x/y do not. We always need to perform the
1370 // check. See bug #97805 for details.
1371 if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
1373 // Nothing to do, since it is already positioned correctly.
1374 return NS_OK;
1377 mBounds.x = aX;
1378 mBounds.y = aY;
1380 if (mWnd) {
1381 #ifdef DEBUG
1382 // complain if a window is moved offscreen (legal, but potentially worrisome)
1383 if (mIsTopWidgetWindow) { // only a problem for top-level windows
1384 // Make sure this window is actually on the screen before we move it
1385 // XXX: Needs multiple monitor support
1386 HDC dc = ::GetDC(mWnd);
1387 if (dc) {
1388 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1389 RECT workArea;
1390 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1391 // no annoying assertions. just mention the issue.
1392 if (aX < 0 || aX >= workArea.right || aY < 0 || aY >= workArea.bottom)
1393 printf("window moved to offscreen position\n");
1395 ::ReleaseDC(mWnd, dc);
1398 #endif
1399 ClearThemeRegion();
1400 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0,
1401 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE));
1402 SetThemeRegion();
1404 return NS_OK;
1407 // Resize this component
1408 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1410 NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
1411 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1413 // Avoid unnecessary resizing calls
1414 if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1415 return NS_OK;
1417 #ifdef MOZ_XUL
1418 if (eTransparencyTransparent == mTransparencyMode)
1419 ResizeTranslucentWindow(aWidth, aHeight);
1420 #endif
1422 // Set cached value for lightweight and printing
1423 mBounds.width = aWidth;
1424 mBounds.height = aHeight;
1426 if (mWnd) {
1427 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
1429 #ifndef WINCE
1430 if (!aRepaint) {
1431 flags |= SWP_NOREDRAW;
1433 #endif
1435 ClearThemeRegion();
1436 VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
1437 SetThemeRegion();
1440 if (aRepaint)
1441 Invalidate(PR_FALSE);
1443 return NS_OK;
1446 // Resize this component
1447 NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1449 NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize");
1450 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1452 // Avoid unnecessary resizing calls
1453 if (mBounds.x == aX && mBounds.y == aY &&
1454 mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1455 return NS_OK;
1457 #ifdef MOZ_XUL
1458 if (eTransparencyTransparent == mTransparencyMode)
1459 ResizeTranslucentWindow(aWidth, aHeight);
1460 #endif
1462 // Set cached value for lightweight and printing
1463 mBounds.x = aX;
1464 mBounds.y = aY;
1465 mBounds.width = aWidth;
1466 mBounds.height = aHeight;
1468 if (mWnd) {
1469 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
1470 #ifndef WINCE
1471 if (!aRepaint) {
1472 flags |= SWP_NOREDRAW;
1474 #endif
1476 ClearThemeRegion();
1477 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
1478 SetThemeRegion();
1481 if (aRepaint)
1482 Invalidate(PR_FALSE);
1484 return NS_OK;
1487 // Resize the client area and position the widget within it's parent
1488 NS_METHOD nsWindow::ResizeClient(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1490 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1491 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1493 // Adjust our existing window bounds, based on the new client dims.
1494 RECT client;
1495 GetClientRect(mWnd, &client);
1496 nsIntPoint dims(client.right - client.left, client.bottom - client.top);
1497 aWidth = mBounds.width + (aWidth - dims.x);
1498 aHeight = mBounds.height + (aHeight - dims.y);
1500 if (aX || aY) {
1501 // offsets
1502 nsIntRect bounds;
1503 GetScreenBounds(bounds);
1504 aX += bounds.x;
1505 aY += bounds.y;
1506 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1508 return Resize(aWidth, aHeight, aRepaint);
1511 #if !defined(WINCE)
1512 NS_IMETHODIMP
1513 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
1515 NS_ENSURE_ARG_POINTER(aEvent);
1517 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
1518 // you can only begin a resize drag with a mouse event
1519 return NS_ERROR_INVALID_ARG;
1522 nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
1523 if (mouseEvent->button != nsMouseEvent::eLeftButton) {
1524 // you can only begin a resize drag with the left mouse button
1525 return NS_ERROR_INVALID_ARG;
1528 // work out what sizemode we're talking about
1529 WPARAM syscommand;
1530 if (aVertical < 0) {
1531 if (aHorizontal < 0) {
1532 syscommand = SC_SIZE | WMSZ_TOPLEFT;
1533 } else if (aHorizontal == 0) {
1534 syscommand = SC_SIZE | WMSZ_TOP;
1535 } else {
1536 syscommand = SC_SIZE | WMSZ_TOPRIGHT;
1538 } else if (aVertical == 0) {
1539 if (aHorizontal < 0) {
1540 syscommand = SC_SIZE | WMSZ_LEFT;
1541 } else if (aHorizontal == 0) {
1542 return NS_ERROR_INVALID_ARG;
1543 } else {
1544 syscommand = SC_SIZE | WMSZ_RIGHT;
1546 } else {
1547 if (aHorizontal < 0) {
1548 syscommand = SC_SIZE | WMSZ_BOTTOMLEFT;
1549 } else if (aHorizontal == 0) {
1550 syscommand = SC_SIZE | WMSZ_BOTTOM;
1551 } else {
1552 syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT;
1556 // resizing doesn't work if the mouse is already captured
1557 CaptureMouse(PR_FALSE);
1559 // find the top-level window
1560 HWND toplevelWnd = GetTopLevelHWND(mWnd, PR_TRUE);
1562 // tell Windows to start the resize
1563 ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand,
1564 POINTTOPOINTS(aEvent->refPoint));
1566 return NS_OK;
1568 #endif
1569 /**************************************************************
1571 * SECTION: Window Z-order and state.
1573 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1574 * nsIWidget::ConstrainPosition
1576 * Z-order, positioning, restore, minimize, and maximize.
1578 **************************************************************/
1580 // Position the window behind the given window
1581 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1582 nsIWidget *aWidget, PRBool aActivate)
1584 HWND behind = HWND_TOP;
1585 if (aPlacement == eZPlacementBottom)
1586 behind = HWND_BOTTOM;
1587 else if (aPlacement == eZPlacementBelow && aWidget)
1588 behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
1589 UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
1590 if (!aActivate)
1591 flags |= SWP_NOACTIVATE;
1593 if (!CanTakeFocus() && behind == HWND_TOP)
1595 // Can't place the window to top so place it behind the foreground window
1596 // (as long as it is not topmost)
1597 HWND wndAfter = ::GetForegroundWindow();
1598 if (!wndAfter)
1599 behind = HWND_BOTTOM;
1600 else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
1601 behind = wndAfter;
1602 flags |= SWP_NOACTIVATE;
1605 ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
1606 return NS_OK;
1609 // Maximize, minimize or restore the window.
1610 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1611 NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode) {
1613 nsresult rv;
1615 // Let's not try and do anything if we're already in that state.
1616 // (This is needed to prevent problems when calling window.minimize(), which
1617 // calls us directly, and then the OS triggers another call to us.)
1618 if (aMode == mSizeMode)
1619 return NS_OK;
1621 // save the requested state
1622 rv = nsBaseWidget::SetSizeMode(aMode);
1623 if (NS_SUCCEEDED(rv) && mIsVisible) {
1624 int mode;
1626 switch (aMode) {
1627 case nsSizeMode_Fullscreen :
1628 mode = SW_SHOW;
1629 break;
1631 case nsSizeMode_Maximized :
1632 mode = SW_MAXIMIZE;
1633 break;
1635 case nsSizeMode_Minimized :
1636 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1637 // keeps the window active in the tray. So after the window is minimized,
1638 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1639 // we will do some additional processing to get the active window set right.
1640 // If sTrimOnMinimize is set, we let windows handle minimization normally
1641 // using SW_MINIMIZE.
1642 mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED;
1643 break;
1645 default :
1646 mode = SW_RESTORE;
1648 ::ShowWindow(mWnd, mode);
1649 // we dispatch an activate event here to ensure that the right child window
1650 // is focused
1651 if (mode == SW_RESTORE || mode == SW_MAXIMIZE)
1652 DispatchFocusToTopLevelWindow(NS_ACTIVATE);
1654 return rv;
1656 #endif // !defined(WINCE)
1658 // Constrain a potential move to fit onscreen
1659 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop,
1660 PRInt32 *aX, PRInt32 *aY)
1662 if (!mIsTopWidgetWindow) // only a problem for top-level windows
1663 return NS_OK;
1665 PRBool doConstrain = PR_FALSE; // whether we have enough info to do anything
1667 /* get our playing field. use the current screen, or failing that
1668 for any reason, use device caps for the default screen. */
1669 RECT screenRect;
1671 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
1672 if (screenmgr) {
1673 nsCOMPtr<nsIScreen> screen;
1674 PRInt32 left, top, width, height;
1676 // zero size rects confuse the screen manager
1677 width = mBounds.width > 0 ? mBounds.width : 1;
1678 height = mBounds.height > 0 ? mBounds.height : 1;
1679 screenmgr->ScreenForRect(*aX, *aY, width, height,
1680 getter_AddRefs(screen));
1681 if (screen) {
1682 if (mSizeMode != nsSizeMode_Fullscreen) {
1683 // For normalized windows, use the desktop work area.
1684 screen->GetAvailRect(&left, &top, &width, &height);
1685 } else {
1686 // For full screen windows, use the desktop.
1687 screen->GetRect(&left, &top, &width, &height);
1689 screenRect.left = left;
1690 screenRect.right = left+width;
1691 screenRect.top = top;
1692 screenRect.bottom = top+height;
1693 doConstrain = PR_TRUE;
1695 } else {
1696 if (mWnd) {
1697 HDC dc = ::GetDC(mWnd);
1698 if (dc) {
1699 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1700 if (mSizeMode != nsSizeMode_Fullscreen) {
1701 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
1702 } else {
1703 screenRect.left = screenRect.top = 0;
1704 screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN);
1705 screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
1707 doConstrain = PR_TRUE;
1709 ::ReleaseDC(mWnd, dc);
1714 if (aAllowSlop) {
1715 if (*aX < screenRect.left - mBounds.width + kWindowPositionSlop)
1716 *aX = screenRect.left - mBounds.width + kWindowPositionSlop;
1717 else if (*aX >= screenRect.right - kWindowPositionSlop)
1718 *aX = screenRect.right - kWindowPositionSlop;
1720 if (*aY < screenRect.top - mBounds.height + kWindowPositionSlop)
1721 *aY = screenRect.top - mBounds.height + kWindowPositionSlop;
1722 else if (*aY >= screenRect.bottom - kWindowPositionSlop)
1723 *aY = screenRect.bottom - kWindowPositionSlop;
1725 } else {
1727 if (*aX < screenRect.left)
1728 *aX = screenRect.left;
1729 else if (*aX >= screenRect.right - mBounds.width)
1730 *aX = screenRect.right - mBounds.width;
1732 if (*aY < screenRect.top)
1733 *aY = screenRect.top;
1734 else if (*aY >= screenRect.bottom - mBounds.height)
1735 *aY = screenRect.bottom - mBounds.height;
1738 return NS_OK;
1741 /**************************************************************
1743 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1745 * Enabling and disabling the widget.
1747 **************************************************************/
1749 // Enable/disable this component
1750 NS_METHOD nsWindow::Enable(PRBool bState)
1752 if (mWnd) {
1753 ::EnableWindow(mWnd, bState);
1755 return NS_OK;
1758 // Return the current enable state
1759 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
1761 NS_ENSURE_ARG_POINTER(aState);
1763 #ifndef WINCE
1764 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT)));
1765 #else
1766 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(mWnd));
1767 #endif
1769 return NS_OK;
1773 /**************************************************************
1775 * SECTION: nsIWidget::SetFocus
1777 * Give the focus to this widget.
1779 **************************************************************/
1781 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
1783 if (mWnd) {
1784 #ifdef WINSTATE_DEBUG_OUTPUT
1785 if (mWnd == GetTopLevelHWND(mWnd))
1786 printf("*** SetFocus: [ top] raise=%d\n", aRaise);
1787 else
1788 printf("*** SetFocus: [child] raise=%d\n", aRaise);
1789 #endif
1790 // Uniconify, if necessary
1791 HWND toplevelWnd = GetTopLevelHWND(mWnd);
1792 if (aRaise && ::IsIconic(toplevelWnd)) {
1793 ::ShowWindow(toplevelWnd, SW_RESTORE);
1795 ::SetFocus(mWnd);
1797 return NS_OK;
1801 /**************************************************************
1803 * SECTION: Bounds
1805 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1806 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1808 * Bound calculations.
1810 **************************************************************/
1812 // Return the window's full dimensions in screen coordinates.
1813 // If the window has a parent, converts the origin to an offset
1814 // of the parent's screen origin.
1815 NS_METHOD nsWindow::GetBounds(nsIntRect &aRect)
1817 if (mWnd) {
1818 RECT r;
1819 VERIFY(::GetWindowRect(mWnd, &r));
1821 // assign size
1822 aRect.width = r.right - r.left;
1823 aRect.height = r.bottom - r.top;
1825 // chrome on parent:
1826 // ___ 5,5 (chrome start)
1827 // | ____ 10,10 (client start)
1828 // | | ____ 20,20 (child start)
1829 // | | |
1830 // 20,20 - 5,5 = 15,15 (??)
1831 // minus GetClientOffset:
1832 // 15,15 - 5,5 = 10,10
1834 // no chrome on parent:
1835 // ______ 10,10 (win start)
1836 // | ____ 20,20 (child start)
1837 // | |
1838 // 20,20 - 10,10 = 10,10
1840 // walking the chain:
1841 // ___ 5,5 (chrome start)
1842 // | ___ 10,10 (client start)
1843 // | | ___ 20,20 (child start)
1844 // | | | __ 30,30 (child start)
1845 // | | | |
1846 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1847 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1848 // minus GetClientOffset:
1849 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1851 // convert coordinates if parent exists
1852 HWND parent = ::GetParent(mWnd);
1853 if (parent) {
1854 RECT pr;
1855 VERIFY(::GetWindowRect(parent, &pr));
1856 r.left -= pr.left;
1857 r.top -= pr.top;
1858 // adjust for chrome
1859 nsWindow* pWidget = static_cast<nsWindow*>(GetParent());
1860 if (pWidget && pWidget->IsTopLevelWidget()) {
1861 nsIntPoint clientOffset = pWidget->GetClientOffset();
1862 r.left -= clientOffset.x;
1863 r.top -= clientOffset.y;
1866 aRect.x = r.left;
1867 aRect.y = r.top;
1868 } else {
1869 aRect = mBounds;
1872 return NS_OK;
1875 // Get this component dimension
1876 NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect)
1878 if (mWnd) {
1879 RECT r;
1880 VERIFY(::GetClientRect(mWnd, &r));
1882 // assign size
1883 aRect.x = 0;
1884 aRect.y = 0;
1885 aRect.width = r.right - r.left;
1886 aRect.height = r.bottom - r.top;
1888 } else {
1889 aRect.SetRect(0,0,0,0);
1891 return NS_OK;
1894 // Like GetBounds, but don't offset by the parent
1895 NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect)
1897 if (mWnd) {
1898 RECT r;
1899 VERIFY(::GetWindowRect(mWnd, &r));
1901 aRect.width = r.right - r.left;
1902 aRect.height = r.bottom - r.top;
1903 aRect.x = r.left;
1904 aRect.y = r.top;
1905 } else
1906 aRect = mBounds;
1908 return NS_OK;
1911 // return the x,y offset of the client area from the origin
1912 // of the window. If the window is borderless returns (0,0).
1913 nsIntPoint nsWindow::GetClientOffset()
1915 if (!mWnd) {
1916 return nsIntPoint(0, 0);
1919 RECT r1;
1920 GetWindowRect(mWnd, &r1);
1921 nsIntPoint pt = WidgetToScreenOffset();
1922 return nsIntPoint(pt.x - r1.left, pt.y - r1.top);
1925 void
1926 nsWindow::SetDrawsInTitlebar(PRBool aState)
1928 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1929 if (window && window != this) {
1930 return window->SetDrawsInTitlebar(aState);
1933 if (aState) {
1934 // left, top, right, bottom for nsIntMargin
1935 nsIntMargin margins(-1, 0, -1, -1);
1936 SetNonClientMargins(margins);
1938 else {
1939 nsIntMargin margins(-1, -1, -1, -1);
1940 SetNonClientMargins(margins);
1944 NS_IMETHODIMP
1945 nsWindow::GetNonClientMargins(nsIntMargin &margins)
1947 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1948 if (window && window != this) {
1949 return window->GetNonClientMargins(margins);
1952 if (mCustomNonClient) {
1953 margins = mNonClientMargins;
1954 return NS_OK;
1957 margins.top = GetSystemMetrics(SM_CYCAPTION);
1958 margins.bottom = GetSystemMetrics(SM_CYFRAME);
1959 margins.top += margins.bottom;
1960 margins.left = margins.right = GetSystemMetrics(SM_CYFRAME);
1962 return NS_OK;
1965 void
1966 nsWindow::ResetLayout()
1968 // This will trigger a frame changed event, triggering
1969 // nc calc size and a sizemode gecko event.
1970 SetWindowPos(mWnd, 0, 0, 0, 0, 0,
1971 SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|
1972 SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
1974 // If hidden, just send the frame changed event for now.
1975 if (!mIsVisible)
1976 return;
1978 // Send a gecko size event to trigger reflow.
1979 RECT clientRc = {0};
1980 GetClientRect(mWnd, &clientRc);
1981 nsIntRect evRect(nsWindowGfx::ToIntRect(clientRc));
1982 OnResize(evRect);
1984 // Invalidate and update
1985 Invalidate(PR_FALSE);
1988 // Called when the window layout changes: full screen mode transitions,
1989 // theme changes, and composition changes. Calculates the new non-client
1990 // margins and fires off a frame changed event, which triggers an nc calc
1991 // size windows event, kicking the changes in.
1992 PRBool
1993 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode, PRBool aReflowWindow)
1995 if (!mCustomNonClient)
1996 return PR_FALSE;
1998 mNonClientOffset.top = mNonClientOffset.bottom =
1999 mNonClientOffset.left = mNonClientOffset.right = 0;
2001 if (aSizeMode == -1)
2002 aSizeMode = mSizeMode;
2004 if (aSizeMode == nsSizeMode_Minimized ||
2005 aSizeMode == nsSizeMode_Fullscreen) {
2006 mCaptionHeight = mVertResizeMargin = mHorResizeMargin = 0;
2007 return PR_TRUE;
2010 // Note, for maximized windows, we need to continue to offset the client by
2011 // thick frame margins of a normal window, since windows expects this
2012 // in it's DwmDefWndProc hit testing.
2013 mCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
2014 mHorResizeMargin = GetSystemMetrics(SM_CXFRAME);
2015 mVertResizeMargin = GetSystemMetrics(SM_CYFRAME);
2017 mCaptionHeight += mVertResizeMargin;
2019 // If a margin value is 0, set the offset to the default size of the frame.
2020 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2021 // so that the frame size is equal to the margin value.
2022 if (!mNonClientMargins.top)
2023 mNonClientOffset.top = mCaptionHeight;
2024 else if (mNonClientMargins.top > 0)
2025 mNonClientOffset.top = mCaptionHeight - mNonClientMargins.top;
2027 if (!mNonClientMargins.left)
2028 mNonClientOffset.left = mHorResizeMargin;
2029 else if (mNonClientMargins.left > 0)
2030 mNonClientOffset.left = mHorResizeMargin - mNonClientMargins.left;
2032 if (!mNonClientMargins.right)
2033 mNonClientOffset.right = mHorResizeMargin;
2034 else if (mNonClientMargins.right > 0)
2035 mNonClientOffset.right = mHorResizeMargin - mNonClientMargins.right;
2037 if (!mNonClientMargins.bottom)
2038 mNonClientOffset.bottom = mVertResizeMargin;
2039 else if (mNonClientMargins.bottom > 0)
2040 mNonClientOffset.bottom = mVertResizeMargin - mNonClientMargins.bottom;
2042 #ifndef WINCE
2043 if (aSizeMode == nsSizeMode_Maximized) {
2044 // Address an issue with auto-hide taskbars which fall behind the window.
2045 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2046 // the taskbar works properly.
2047 MONITORINFO info = {sizeof(MONITORINFO)};
2048 if (::GetMonitorInfo(::MonitorFromWindow(mWnd, MONITOR_DEFAULTTOPRIMARY),
2049 &info)) {
2050 RECT r;
2051 if (::GetWindowRect(mWnd, &r)) {
2052 // Adjust window rect to account for non-client margins.
2053 r.top += mVertResizeMargin - mNonClientOffset.top;
2054 r.left += mHorResizeMargin - mNonClientOffset.left;
2055 r.bottom -= mVertResizeMargin - mNonClientOffset.bottom;
2056 r.right -= mHorResizeMargin - mNonClientOffset.right;
2057 // Leave the 1 pixel margin if the window covers the monitor.
2058 if (r.top <= info.rcMonitor.top &&
2059 r.left <= info.rcMonitor.left &&
2060 r.right >= info.rcMonitor.right &&
2061 r.bottom >= info.rcMonitor.bottom)
2062 mNonClientOffset.bottom -= r.bottom - info.rcMonitor.bottom + 1;
2066 #endif
2068 if (aReflowWindow) {
2069 // Force a reflow of content based on the new client
2070 // dimensions.
2071 ResetLayout();
2074 return PR_TRUE;
2077 NS_IMETHODIMP
2078 nsWindow::SetNonClientMargins(nsIntMargin &margins)
2080 if (!mIsTopWidgetWindow ||
2081 mBorderStyle & eBorderStyle_none ||
2082 mHideChrome)
2083 return NS_ERROR_INVALID_ARG;
2085 // Request for a reset
2086 if (margins.top == -1 && margins.left == -1 &&
2087 margins.right == -1 && margins.bottom == -1) {
2088 mCustomNonClient = PR_FALSE;
2089 mNonClientMargins = margins;
2090 // Force a reflow of content based on the new client
2091 // dimensions.
2092 ResetLayout();
2093 return NS_OK;
2096 if (margins.top < -1 || margins.bottom < -1 ||
2097 margins.left < -1 || margins.right < -1)
2098 return NS_ERROR_INVALID_ARG;
2100 mNonClientMargins = margins;
2101 mCustomNonClient = PR_TRUE;
2102 if (!UpdateNonClientMargins()) {
2103 NS_WARNING("UpdateNonClientMargins failed!");
2104 return PR_FALSE;
2107 return NS_OK;
2110 void
2111 nsWindow::InvalidateNonClientRegion()
2113 // +-+-----------------------+-+
2114 // | | app non-client chrome | |
2115 // | +-----------------------+ |
2116 // | | app client chrome | | }
2117 // | +-----------------------+ | }
2118 // | | app content | | } area we don't want to invalidate
2119 // | +-----------------------+ | }
2120 // | | app client chrome | | }
2121 // | +-----------------------+ |
2122 // +---------------------------+ <
2123 // ^ ^ windows non-client chrome
2124 // client area = app *
2125 RECT rect;
2126 GetWindowRect(mWnd, &rect);
2127 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2128 HRGN winRgn = CreateRectRgnIndirect(&rect);
2130 // Subtract app client chrome and app content leaving
2131 // windows non-client chrome and app non-client chrome
2132 // in winRgn.
2133 GetWindowRect(mWnd, &rect);
2134 rect.top += mCaptionHeight;
2135 rect.right -= mHorResizeMargin;
2136 rect.bottom -= mHorResizeMargin;
2137 rect.left += mVertResizeMargin;
2138 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2139 HRGN clientRgn = CreateRectRgnIndirect(&rect);
2140 CombineRgn(winRgn, winRgn, clientRgn, RGN_DIFF);
2141 DeleteObject(clientRgn);
2143 // triggers ncpaint and paint events for the two areas
2144 RedrawWindow(mWnd, NULL, winRgn, RDW_FRAME|RDW_INVALIDATE);
2145 DeleteObject(winRgn);
2148 HRGN
2149 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion)
2151 RECT rect;
2152 HRGN rgn = NULL;
2153 if (aRegion == (HRGN)1) { // undocumented value indicating a full refresh
2154 GetWindowRect(mWnd, &rect);
2155 rgn = CreateRectRgnIndirect(&rect);
2156 } else {
2157 rgn = aRegion;
2159 GetClientRect(mWnd, &rect);
2160 MapWindowPoints(mWnd, NULL, (LPPOINT)&rect, 2);
2161 HRGN nonClientRgn = CreateRectRgnIndirect(&rect);
2162 CombineRgn(rgn, rgn, nonClientRgn, RGN_DIFF);
2163 DeleteObject(nonClientRgn);
2164 return rgn;
2167 /**************************************************************
2169 * SECTION: nsIWidget::SetBackgroundColor
2171 * Sets the window background paint color.
2173 **************************************************************/
2175 NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
2177 nsBaseWidget::SetBackgroundColor(aColor);
2179 if (mBrush)
2180 ::DeleteObject(mBrush);
2182 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
2183 #ifndef WINCE
2184 if (mWnd != NULL) {
2185 ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush);
2187 #endif
2188 return NS_OK;
2191 /**************************************************************
2193 * SECTION: nsIWidget::SetCursor
2195 * SetCursor and related utilities for manging cursor state.
2197 **************************************************************/
2199 // Set this component cursor
2200 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
2202 // Only change cursor if it's changing
2204 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2205 //XXX If we want this optimization we need a better way to do it.
2206 //if (aCursor != mCursor) {
2207 HCURSOR newCursor = NULL;
2209 switch (aCursor) {
2210 case eCursor_select:
2211 newCursor = ::LoadCursor(NULL, IDC_IBEAM);
2212 break;
2214 case eCursor_wait:
2215 newCursor = ::LoadCursor(NULL, IDC_WAIT);
2216 break;
2218 case eCursor_hyperlink:
2220 newCursor = ::LoadCursor(NULL, IDC_HAND);
2221 break;
2224 case eCursor_standard:
2225 newCursor = ::LoadCursor(NULL, IDC_ARROW);
2226 break;
2228 case eCursor_n_resize:
2229 case eCursor_s_resize:
2230 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2231 break;
2233 case eCursor_w_resize:
2234 case eCursor_e_resize:
2235 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2236 break;
2238 case eCursor_nw_resize:
2239 case eCursor_se_resize:
2240 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2241 break;
2243 case eCursor_ne_resize:
2244 case eCursor_sw_resize:
2245 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2246 break;
2248 case eCursor_crosshair:
2249 newCursor = ::LoadCursor(NULL, IDC_CROSS);
2250 break;
2252 case eCursor_move:
2253 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2254 break;
2256 case eCursor_help:
2257 newCursor = ::LoadCursor(NULL, IDC_HELP);
2258 break;
2260 case eCursor_copy: // CSS3
2261 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
2262 break;
2264 case eCursor_alias:
2265 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
2266 break;
2268 case eCursor_cell:
2269 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
2270 break;
2272 case eCursor_grab:
2273 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
2274 break;
2276 case eCursor_grabbing:
2277 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
2278 break;
2280 case eCursor_spinning:
2281 newCursor = ::LoadCursor(NULL, IDC_APPSTARTING);
2282 break;
2284 case eCursor_context_menu:
2285 // XXX this CSS3 cursor needs to be implemented
2286 break;
2288 case eCursor_zoom_in:
2289 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
2290 break;
2292 case eCursor_zoom_out:
2293 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
2294 break;
2296 case eCursor_not_allowed:
2297 case eCursor_no_drop:
2298 newCursor = ::LoadCursor(NULL, IDC_NO);
2299 break;
2301 case eCursor_col_resize:
2302 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
2303 break;
2305 case eCursor_row_resize:
2306 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
2307 break;
2309 case eCursor_vertical_text:
2310 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT));
2311 break;
2313 case eCursor_all_scroll:
2314 // XXX not 100% appropriate perhaps
2315 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2316 break;
2318 case eCursor_nesw_resize:
2319 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2320 break;
2322 case eCursor_nwse_resize:
2323 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2324 break;
2326 case eCursor_ns_resize:
2327 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2328 break;
2330 case eCursor_ew_resize:
2331 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2332 break;
2334 case eCursor_none:
2335 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
2336 break;
2338 default:
2339 NS_ERROR("Invalid cursor type");
2340 break;
2343 if (NULL != newCursor) {
2344 mCursor = aCursor;
2345 HCURSOR oldCursor = ::SetCursor(newCursor);
2347 if (sHCursor == oldCursor) {
2348 NS_IF_RELEASE(sCursorImgContainer);
2349 if (sHCursor != NULL)
2350 ::DestroyIcon(sHCursor);
2351 sHCursor = NULL;
2355 return NS_OK;
2358 // Setting the actual cursor
2359 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
2360 PRUint32 aHotspotX, PRUint32 aHotspotY)
2362 if (sCursorImgContainer == aCursor && sHCursor) {
2363 ::SetCursor(sHCursor);
2364 return NS_OK;
2367 PRInt32 width;
2368 PRInt32 height;
2370 nsresult rv;
2371 rv = aCursor->GetWidth(&width);
2372 NS_ENSURE_SUCCESS(rv, rv);
2373 rv = aCursor->GetHeight(&height);
2374 NS_ENSURE_SUCCESS(rv, rv);
2376 // Reject cursors greater than 128 pixels in either direction, to prevent
2377 // spoofing.
2378 // XXX ideally we should rescale. Also, we could modify the API to
2379 // allow trusted content to set larger cursors.
2380 if (width > 128 || height > 128)
2381 return NS_ERROR_NOT_AVAILABLE;
2383 HCURSOR cursor;
2384 rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
2385 NS_ENSURE_SUCCESS(rv, rv);
2387 mCursor = nsCursor(-1);
2388 ::SetCursor(cursor);
2390 NS_IF_RELEASE(sCursorImgContainer);
2391 sCursorImgContainer = aCursor;
2392 NS_ADDREF(sCursorImgContainer);
2394 if (sHCursor != NULL)
2395 ::DestroyIcon(sHCursor);
2396 sHCursor = cursor;
2398 return NS_OK;
2401 /**************************************************************
2403 * SECTION: nsIWidget::Get/SetTransparencyMode
2405 * Manage the transparency mode of the top-level window
2406 * containing this widget.
2408 **************************************************************/
2410 #ifdef MOZ_XUL
2411 nsTransparencyMode nsWindow::GetTransparencyMode()
2413 return GetTopLevelWindow(PR_TRUE)->GetWindowTranslucencyInner();
2416 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
2418 GetTopLevelWindow(PR_TRUE)->SetWindowTranslucencyInner(aMode);
2421 void nsWindow::UpdatePossiblyTransparentRegion(const nsIntRegion &aDirtyRegion,
2422 const nsIntRegion &aPossiblyTransparentRegion) {
2423 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2424 if (!HasGlass())
2425 return;
2427 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2428 nsWindow* topWindow = GetNSWindowPtr(hWnd);
2430 if (GetParent())
2431 return;
2433 mPossiblyTransparentRegion.Sub(mPossiblyTransparentRegion, aDirtyRegion);
2434 mPossiblyTransparentRegion.Or(mPossiblyTransparentRegion, aPossiblyTransparentRegion);
2436 nsIntRect clientBounds;
2437 topWindow->GetClientBounds(clientBounds);
2438 nsIntRegion opaqueRegion;
2439 opaqueRegion.Sub(clientBounds, mPossiblyTransparentRegion);
2441 MARGINS margins = { 0, 0, 0, 0 };
2442 DWORD_PTR dwStyle = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
2444 // If there is no opaque region or hidechrome=true, set margins
2445 // to support a full sheet of glass.
2446 if (opaqueRegion.IsEmpty() || mHideChrome) {
2447 // Comments in MSDN indicate all values must be set to -1
2448 margins.cxLeftWidth = margins.cxRightWidth =
2449 margins.cyTopHeight = margins.cyBottomHeight = -1;
2450 } else {
2451 // Find the largest rectangle and use that to calculate the inset
2452 nsIntRect largest = opaqueRegion.GetLargestRectangle();
2453 margins.cxLeftWidth = largest.x;
2454 margins.cxRightWidth = clientBounds.width - largest.XMost();
2455 margins.cyBottomHeight = clientBounds.height - largest.YMost();
2457 // The minimum glass height must be the caption buttons height,
2458 // otherwise the buttons are drawn incorrectly.
2459 margins.cyTopHeight = PR_MAX(largest.y, mCaptionButtons.height);
2462 // Only update glass area if there are changes
2463 if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) {
2464 mGlassMargins = margins;
2465 UpdateGlass();
2467 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2470 void nsWindow::UpdateGlass()
2472 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2473 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2474 MARGINS margins = mGlassMargins;
2476 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2477 // rendered based on the window style.
2478 // DWMNCRP_ENABLED - The non-client area rendering is
2479 // enabled; the window style is ignored.
2480 DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE;
2481 switch (mTransparencyMode) {
2482 case eTransparencyBorderlessGlass:
2483 // Only adjust if there is some opaque rectangle
2484 if (margins.cxLeftWidth >= 0) {
2485 const PRInt32 kGlassMarginAdjustment = 2;
2486 margins.cxLeftWidth += kGlassMarginAdjustment;
2487 margins.cyTopHeight += kGlassMarginAdjustment;
2488 margins.cxRightWidth += kGlassMarginAdjustment;
2489 margins.cyBottomHeight += kGlassMarginAdjustment;
2491 // Fall through
2492 case eTransparencyGlass:
2493 policy = DWMNCRP_ENABLED;
2494 break;
2497 // Extends the window frame behind the client area
2498 if(nsUXThemeData::CheckForCompositor()) {
2499 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd, &margins);
2500 nsUXThemeData::dwmSetWindowAttributePtr(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy);
2502 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2504 #endif
2506 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2507 void nsWindow::UpdateCaptionButtonsClippingRect()
2509 NS_ASSERTION(mWnd, "UpdateCaptionButtonsClippingRect called with invalid mWnd.");
2511 RECT captionButtons;
2512 mCaptionButtonsRoundedRegion.SetEmpty();
2513 mCaptionButtons.Empty();
2515 if (!mCustomNonClient ||
2516 mSizeMode == nsSizeMode_Fullscreen ||
2517 mSizeMode == nsSizeMode_Minimized ||
2518 !nsUXThemeData::CheckForCompositor() ||
2519 FAILED(nsUXThemeData::dwmGetWindowAttributePtr(mWnd,
2520 DWMWA_CAPTION_BUTTON_BOUNDS,
2521 &captionButtons,
2522 sizeof(captionButtons)))) {
2523 return;
2526 mCaptionButtons = nsWindowGfx::ToIntRect(captionButtons);
2528 // Adjustments to reported area
2529 PRInt32 leftMargin = (mNonClientMargins.left == -1) ? mHorResizeMargin : mNonClientMargins.left;
2531 // "leftMargin - 1" represents the resizer border and an
2532 // one pixel adjustment to hide the semi-transparent highlight.
2533 // The extra width is already excluded when the window is maximized.
2534 mCaptionButtons.x -= leftMargin - 1;
2536 if (mSizeMode != nsSizeMode_Maximized) {
2537 mCaptionButtons.width += leftMargin - 1;
2538 mCaptionButtons.height -= mVertResizeMargin + 1;
2539 } else {
2540 // Adjustments to the buttons' shift from the edge of the screen,
2541 // plus some apparently transparent drop shadow below them.
2542 mCaptionButtons.width -= 2;
2543 mCaptionButtons.height -= 3;
2546 // Create a rounded region by shrinking the 2 bottommost pixel rows from
2547 // the rect by 1 and 2 pixels.
2548 // mCaptionButtons: mCaptionButtonsRoundedRegion:
2549 // +-----------+ +-----------+
2550 // | | | |
2551 // | | | |
2552 // +-----------+ +-------+
2553 nsIntRect round1(mCaptionButtons.x, mCaptionButtons.y,
2554 mCaptionButtons.width, mCaptionButtons.height - 2);
2555 nsIntRect round2(mCaptionButtons.x + 1, mCaptionButtons.YMost() - 2,
2556 mCaptionButtons.width - 2, 1);
2557 nsIntRect round3(mCaptionButtons.x + 2, mCaptionButtons.YMost() - 1,
2558 mCaptionButtons.width - 4, 1);
2559 mCaptionButtonsRoundedRegion.Or(mCaptionButtonsRoundedRegion, round1);
2560 mCaptionButtonsRoundedRegion.Or(mCaptionButtonsRoundedRegion, round2);
2561 mCaptionButtonsRoundedRegion.Or(mCaptionButtonsRoundedRegion, round3);
2563 #endif
2565 /**************************************************************
2567 * SECTION: nsIWidget::HideWindowChrome
2569 * Show or hide window chrome.
2571 **************************************************************/
2573 NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide)
2575 HWND hwnd = GetTopLevelHWND(mWnd, PR_TRUE);
2576 if (!GetNSWindowPtr(hwnd))
2578 NS_WARNING("Trying to hide window decorations in an embedded context");
2579 return NS_ERROR_FAILURE;
2582 if (mHideChrome == aShouldHide)
2583 return NS_OK;
2585 DWORD_PTR style, exStyle;
2586 mHideChrome = aShouldHide;
2587 if (aShouldHide) {
2588 DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2589 DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2591 style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
2592 exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
2593 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
2595 mOldStyle = tempStyle;
2596 mOldExStyle = tempExStyle;
2598 else {
2599 if (!mOldStyle || !mOldExStyle) {
2600 mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2601 mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2604 style = mOldStyle;
2605 exStyle = mOldExStyle;
2608 VERIFY_WINDOW_STYLE(style);
2609 ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
2610 ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
2612 return NS_OK;
2615 /**************************************************************
2617 * SECTION: nsIWidget::Invalidate
2619 * Invalidate an area of the client for painting.
2621 **************************************************************/
2623 // Invalidate this component visible area
2624 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
2626 if (mWnd)
2628 #ifdef WIDGET_DEBUG_OUTPUT
2629 debug_DumpInvalidate(stdout,
2630 this,
2631 nsnull,
2632 aIsSynchronous,
2633 nsCAutoString("noname"),
2634 (PRInt32) mWnd);
2635 #endif // WIDGET_DEBUG_OUTPUT
2637 VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
2639 if (aIsSynchronous) {
2640 VERIFY(::UpdateWindow(mWnd));
2643 return NS_OK;
2646 // Invalidate this component visible area
2647 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, PRBool aIsSynchronous)
2649 if (mWnd)
2651 #ifdef WIDGET_DEBUG_OUTPUT
2652 debug_DumpInvalidate(stdout,
2653 this,
2654 &aRect,
2655 aIsSynchronous,
2656 nsCAutoString("noname"),
2657 (PRInt32) mWnd);
2658 #endif // WIDGET_DEBUG_OUTPUT
2660 RECT rect;
2662 rect.left = aRect.x;
2663 rect.top = aRect.y;
2664 rect.right = aRect.x + aRect.width;
2665 rect.bottom = aRect.y + aRect.height;
2667 VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
2669 if (aIsSynchronous) {
2670 VERIFY(::UpdateWindow(mWnd));
2673 return NS_OK;
2676 NS_IMETHODIMP
2677 nsWindow::MakeFullScreen(PRBool aFullScreen)
2679 #if WINCE_WINDOWS_MOBILE
2680 RECT rc;
2681 if (aFullScreen) {
2682 SetForegroundWindow(mWnd);
2683 if (nsWindowCE::sMenuBarShown) {
2684 SIPINFO sipInfo;
2685 memset(&sipInfo, 0, sizeof(SIPINFO));
2686 sipInfo.cbSize = sizeof(SIPINFO);
2687 if (SipGetInfo(&sipInfo))
2688 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2689 sipInfo.rcVisibleDesktop.bottom);
2690 else
2691 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2692 GetSystemMetrics(SM_CYSCREEN));
2693 RECT menuBarRect;
2694 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle, &menuBarRect) &&
2695 menuBarRect.top < rc.bottom)
2696 rc.bottom = menuBarRect.top;
2697 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_SHOWSIPBUTTON);
2698 } else {
2700 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);
2701 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2704 else {
2705 SHFullScreen(mWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
2706 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
2709 if (aFullScreen)
2710 mSizeMode = nsSizeMode_Fullscreen;
2712 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2713 HideWindowChrome(aFullScreen);
2714 Resize(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PR_TRUE);
2716 return NS_OK;
2718 #else
2720 mFullscreenMode = aFullScreen;
2721 if (aFullScreen) {
2722 if (mSizeMode == nsSizeMode_Fullscreen)
2723 return NS_OK;
2724 mOldSizeMode = mSizeMode;
2725 SetSizeMode(nsSizeMode_Fullscreen);
2726 } else {
2727 SetSizeMode(mOldSizeMode);
2730 UpdateNonClientMargins();
2732 // Prevent window updates during the transition.
2733 DWORD style;
2734 if (nsUXThemeData::CheckForCompositor()) {
2735 style = GetWindowLong(mWnd, GWL_STYLE);
2736 SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
2739 // Will call hide chrome, reposition window. Note this will
2740 // also cache dimensions for restoration, so it should only
2741 // be called once per fullscreen request.
2742 nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen);
2744 if (nsUXThemeData::CheckForCompositor()) {
2745 style = GetWindowLong(mWnd, GWL_STYLE);
2746 SetWindowLong(mWnd, GWL_STYLE, style | WS_VISIBLE);
2749 // Let the dom know via web shell window
2750 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
2751 event.mSizeMode = mSizeMode;
2752 InitEvent(event);
2753 DispatchWindowEvent(&event);
2755 return rv;
2756 #endif
2759 /**************************************************************
2761 * SECTION: nsIWidget::Update
2763 * Force a synchronous repaint of the window.
2765 **************************************************************/
2767 NS_IMETHODIMP nsWindow::Update()
2769 nsresult rv = NS_OK;
2771 // updates can come through for windows no longer holding an mWnd during
2772 // deletes triggered by JavaScript in buttons with mouse feedback
2773 if (mWnd)
2774 VERIFY(::UpdateWindow(mWnd));
2776 return rv;
2779 /**************************************************************
2781 * SECTION: Native data storage
2783 * nsIWidget::GetNativeData
2784 * nsIWidget::FreeNativeData
2786 * Set or clear native data based on a constant.
2788 **************************************************************/
2790 // Return some native data according to aDataType
2791 void* nsWindow::GetNativeData(PRUint32 aDataType)
2793 switch (aDataType) {
2794 case NS_NATIVE_TMP_WINDOW:
2795 return (void*)::CreateWindowExW(mIsRTL ? WS_EX_LAYOUTRTL : 0,
2796 WindowClass(),
2797 L"",
2798 WS_CHILD,
2799 CW_USEDEFAULT,
2800 CW_USEDEFAULT,
2801 CW_USEDEFAULT,
2802 CW_USEDEFAULT,
2803 mWnd,
2804 NULL,
2805 nsToolkit::mDllInstance,
2806 NULL);
2807 case NS_NATIVE_PLUGIN_PORT:
2808 case NS_NATIVE_WIDGET:
2809 case NS_NATIVE_WINDOW:
2810 return (void*)mWnd;
2811 case NS_NATIVE_GRAPHIC:
2812 // XXX: This is sleezy!! Remember to Release the DC after using it!
2813 #ifdef MOZ_XUL
2814 return (void*)(eTransparencyTransparent == mTransparencyMode) ?
2815 mMemoryDC : ::GetDC(mWnd);
2816 #else
2817 return (void*)::GetDC(mWnd);
2818 #endif
2820 #ifdef NS_ENABLE_TSF
2821 case NS_NATIVE_TSF_THREAD_MGR:
2822 return nsTextStore::GetThreadMgr();
2823 case NS_NATIVE_TSF_CATEGORY_MGR:
2824 return nsTextStore::GetCategoryMgr();
2825 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
2826 return nsTextStore::GetDisplayAttrMgr();
2827 #endif //NS_ENABLE_TSF
2829 default:
2830 break;
2833 return NULL;
2836 // Free some native data according to aDataType
2837 void nsWindow::FreeNativeData(void * data, PRUint32 aDataType)
2839 switch (aDataType)
2841 case NS_NATIVE_GRAPHIC:
2842 #ifdef MOZ_XUL
2843 if (eTransparencyTransparent != mTransparencyMode)
2844 ::ReleaseDC(mWnd, (HDC)data);
2845 #else
2846 ::ReleaseDC(mWnd, (HDC)data);
2847 #endif
2848 break;
2849 case NS_NATIVE_WIDGET:
2850 case NS_NATIVE_WINDOW:
2851 case NS_NATIVE_PLUGIN_PORT:
2852 break;
2853 default:
2854 break;
2858 /**************************************************************
2860 * SECTION: nsIWidget::SetTitle
2862 * Set the main windows title text.
2864 **************************************************************/
2866 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
2868 const nsString& strTitle = PromiseFlatString(aTitle);
2869 ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get());
2870 return NS_OK;
2873 /**************************************************************
2875 * SECTION: nsIWidget::SetIcon
2877 * Set the main windows icon.
2879 **************************************************************/
2881 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec)
2883 #ifndef WINCE
2884 // Assume the given string is a local identifier for an icon file.
2886 nsCOMPtr<nsILocalFile> iconFile;
2887 ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
2888 getter_AddRefs(iconFile));
2889 if (!iconFile)
2890 return NS_OK; // not an error if icon is not found
2892 nsAutoString iconPath;
2893 iconFile->GetPath(iconPath);
2895 // XXX this should use MZLU (see bug 239279)
2897 ::SetLastError(0);
2899 HICON bigIcon = (HICON)::LoadImageW(NULL,
2900 (LPCWSTR)iconPath.get(),
2901 IMAGE_ICON,
2902 ::GetSystemMetrics(SM_CXICON),
2903 ::GetSystemMetrics(SM_CYICON),
2904 LR_LOADFROMFILE );
2905 HICON smallIcon = (HICON)::LoadImageW(NULL,
2906 (LPCWSTR)iconPath.get(),
2907 IMAGE_ICON,
2908 ::GetSystemMetrics(SM_CXSMICON),
2909 ::GetSystemMetrics(SM_CYSMICON),
2910 LR_LOADFROMFILE );
2912 if (bigIcon) {
2913 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon);
2914 if (icon)
2915 ::DestroyIcon(icon);
2917 #ifdef DEBUG_SetIcon
2918 else {
2919 NS_LossyConvertUTF16toASCII cPath(iconPath);
2920 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2922 #endif
2923 if (smallIcon) {
2924 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon);
2925 if (icon)
2926 ::DestroyIcon(icon);
2928 #ifdef DEBUG_SetIcon
2929 else {
2930 NS_LossyConvertUTF16toASCII cPath(iconPath);
2931 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2933 #endif
2934 #endif // WINCE
2935 return NS_OK;
2938 /**************************************************************
2940 * SECTION: nsIWidget::WidgetToScreenOffset
2942 * Return this widget's origin in screen coordinates.
2944 **************************************************************/
2946 nsIntPoint nsWindow::WidgetToScreenOffset()
2948 POINT point;
2949 point.x = 0;
2950 point.y = 0;
2951 ::ClientToScreen(mWnd, &point);
2952 return nsIntPoint(point.x, point.y);
2955 nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize)
2957 if (!IsPopupWithTitleBar())
2958 return aClientSize;
2960 // just use (200, 200) as the position
2961 RECT r;
2962 r.left = 200;
2963 r.top = 200;
2964 r.right = 200 + aClientSize.width;
2965 r.bottom = 200 + aClientSize.height;
2966 ::AdjustWindowRectEx(&r, WindowStyle(), PR_FALSE, WindowExStyle());
2968 return nsIntSize(r.right - r.left, r.bottom - r.top);
2971 /**************************************************************
2973 * SECTION: nsIWidget::EnableDragDrop
2975 * Enables/Disables drag and drop of files on this widget.
2977 **************************************************************/
2979 #if !defined(WINCE) // implemented in nsWindowCE.cpp
2980 NS_METHOD nsWindow::EnableDragDrop(PRBool aEnable)
2982 NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()");
2984 nsresult rv = NS_ERROR_FAILURE;
2985 if (aEnable) {
2986 if (nsnull == mNativeDragTarget) {
2987 mNativeDragTarget = new nsNativeDragTarget(this);
2988 if (NULL != mNativeDragTarget) {
2989 mNativeDragTarget->AddRef();
2990 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) {
2991 if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) {
2992 rv = NS_OK;
2997 } else {
2998 if (nsnull != mWnd && NULL != mNativeDragTarget) {
2999 ::RevokeDragDrop(mWnd);
3000 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) {
3001 rv = NS_OK;
3003 mNativeDragTarget->DragCancel();
3004 NS_RELEASE(mNativeDragTarget);
3007 return rv;
3009 #endif
3011 /**************************************************************
3013 * SECTION: nsIWidget::CaptureMouse
3015 * Enables/Disables system mouse capture.
3017 **************************************************************/
3019 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
3021 if (!nsToolkit::gMouseTrailer) {
3022 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3023 return NS_OK;
3026 if (aCapture) {
3027 nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd);
3028 ::SetCapture(mWnd);
3029 } else {
3030 nsToolkit::gMouseTrailer->SetCaptureWindow(NULL);
3031 ::ReleaseCapture();
3033 mIsInMouseCapture = aCapture;
3034 return NS_OK;
3037 /**************************************************************
3039 * SECTION: nsIWidget::CaptureRollupEvents
3041 * Dealing with event rollup on destroy for popups. Enables &
3042 * Disables system capture of any and all events that would
3043 * cause a dropdown to be rolled up.
3045 **************************************************************/
3047 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
3048 nsIMenuRollup * aMenuRollup,
3049 PRBool aDoCapture,
3050 PRBool aConsumeRollupEvent)
3052 if (aDoCapture) {
3053 /* we haven't bothered carrying a weak reference to sRollupWidget because
3054 we believe lifespan is properly scoped. this next assertion helps
3055 assure that remains true. */
3056 NS_ASSERTION(!sRollupWidget, "rollup widget reassigned before release");
3057 sRollupConsumeEvent = aConsumeRollupEvent;
3058 NS_IF_RELEASE(sRollupWidget);
3059 NS_IF_RELEASE(sMenuRollup);
3060 sRollupListener = aListener;
3061 sMenuRollup = aMenuRollup;
3062 NS_IF_ADDREF(aMenuRollup);
3063 sRollupWidget = this;
3064 NS_ADDREF(this);
3066 #ifndef WINCE
3067 if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
3068 RegisterSpecialDropdownHooks();
3070 sProcessHook = PR_TRUE;
3071 #endif
3073 } else {
3074 sRollupListener = nsnull;
3075 NS_IF_RELEASE(sMenuRollup);
3076 NS_IF_RELEASE(sRollupWidget);
3078 #ifndef WINCE
3079 sProcessHook = PR_FALSE;
3080 UnregisterSpecialDropdownHooks();
3081 #endif
3084 return NS_OK;
3087 /**************************************************************
3089 * SECTION: nsIWidget::GetAttention
3091 * Bring this window to the user's attention.
3093 **************************************************************/
3095 // Draw user's attention to this window until it comes to foreground.
3096 NS_IMETHODIMP
3097 nsWindow::GetAttention(PRInt32 aCycleCount)
3099 #ifndef WINCE
3100 // Got window?
3101 if (!mWnd)
3102 return NS_ERROR_NOT_INITIALIZED;
3104 // Don't flash if the flash count is 0 or if the
3105 // top level window is already active.
3106 HWND fgWnd = ::GetForegroundWindow();
3107 if (aCycleCount == 0 || fgWnd == GetTopLevelHWND(mWnd))
3108 return NS_OK;
3110 HWND flashWnd = mWnd;
3111 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3112 flashWnd = ownerWnd;
3115 // Don't flash if the owner window is active either.
3116 if (fgWnd == flashWnd)
3117 return NS_OK;
3119 DWORD defaultCycleCount = 0;
3120 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
3122 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3123 FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 };
3124 ::FlashWindowEx(&flashInfo);
3125 #endif
3126 return NS_OK;
3129 void nsWindow::StopFlashing()
3131 #ifndef WINCE
3132 HWND flashWnd = mWnd;
3133 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3134 flashWnd = ownerWnd;
3137 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3138 FLASHW_STOP, 0, 0 };
3139 ::FlashWindowEx(&flashInfo);
3140 #endif
3143 /**************************************************************
3145 * SECTION: nsIWidget::HasPendingInputEvent
3147 * Ask whether there user input events pending. All input events are
3148 * included, including those not targeted at this nsIwidget instance.
3150 **************************************************************/
3152 PRBool
3153 nsWindow::HasPendingInputEvent()
3155 // If there is pending input or the user is currently
3156 // moving the window then return true.
3157 // Note: When the user is moving the window WIN32 spins
3158 // a separate event loop and input events are not
3159 // reported to the application.
3160 if (HIWORD(GetQueueStatus(QS_INPUT)))
3161 return PR_TRUE;
3162 #ifdef WINCE
3163 return PR_FALSE;
3164 #else
3165 GUITHREADINFO guiInfo;
3166 guiInfo.cbSize = sizeof(GUITHREADINFO);
3167 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo))
3168 return PR_FALSE;
3169 return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE);
3170 #endif
3173 /**************************************************************
3175 * SECTION: nsIWidget::GetLayerManager
3177 * Get the layer manager associated with this widget.
3179 **************************************************************/
3181 mozilla::layers::LayerManager*
3182 nsWindow::GetLayerManager()
3184 #ifndef WINCE
3185 if (!mLayerManager) {
3186 nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3188 PRBool accelerateByDefault = PR_TRUE;
3189 PRBool disableAcceleration = PR_FALSE;
3190 PRBool preferOpenGL = PR_FALSE;
3191 PRBool useD3D10 = PR_FALSE;
3192 if (prefs) {
3193 prefs->GetBoolPref("layers.accelerate-all",
3194 &accelerateByDefault);
3195 prefs->GetBoolPref("layers.accelerate-none",
3196 &disableAcceleration);
3197 prefs->GetBoolPref("layers.prefer-opengl",
3198 &preferOpenGL);
3199 prefs->GetBoolPref("layers.use-d3d10",
3200 &useD3D10);
3203 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
3204 accelerateByDefault = accelerateByDefault ||
3205 (acceleratedEnv && (*acceleratedEnv != '0'));
3207 /* We don't currently support using an accelerated layer manager with
3208 * transparent windows so don't even try. I'm also not sure if we even
3209 * want to support this case. See bug #593471 */
3210 disableAcceleration = disableAcceleration ||
3211 eTransparencyTransparent == mTransparencyMode;
3213 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
3214 PRBool safeMode = PR_FALSE;
3215 if (xr)
3216 xr->GetInSafeMode(&safeMode);
3218 if (disableAcceleration || safeMode)
3219 mUseAcceleratedRendering = PR_FALSE;
3220 else if (accelerateByDefault)
3221 mUseAcceleratedRendering = PR_TRUE;
3223 if (mUseAcceleratedRendering) {
3224 #ifdef MOZ_ENABLE_D3D10_LAYER
3225 if (useD3D10) {
3226 nsRefPtr<mozilla::layers::LayerManagerD3D10> layerManager =
3227 new mozilla::layers::LayerManagerD3D10(this);
3228 if (layerManager->Initialize()) {
3229 mLayerManager = layerManager;
3232 #endif
3233 #ifdef MOZ_ENABLE_D3D9_LAYER
3234 if (!preferOpenGL && !mLayerManager) {
3235 nsRefPtr<mozilla::layers::LayerManagerD3D9> layerManager =
3236 new mozilla::layers::LayerManagerD3D9(this);
3237 if (layerManager->Initialize()) {
3238 mLayerManager = layerManager;
3241 #endif
3242 if (!mLayerManager && preferOpenGL) {
3243 nsRefPtr<mozilla::layers::LayerManagerOGL> layerManager =
3244 new mozilla::layers::LayerManagerOGL(this);
3245 if (layerManager->Initialize()) {
3246 mLayerManager = layerManager;
3251 // Fall back to software if we couldn't use any hardware backends.
3252 if (!mLayerManager)
3253 mLayerManager = CreateBasicLayerManager();
3255 #endif
3257 return mLayerManager;
3260 /**************************************************************
3262 * SECTION: nsIWidget::GetThebesSurface
3264 * Get the Thebes surface associated with this widget.
3266 **************************************************************/
3268 gfxASurface *nsWindow::GetThebesSurface()
3270 #ifdef CAIRO_HAS_D2D_SURFACE
3271 if (mD2DWindowSurface) {
3272 return mD2DWindowSurface;
3274 #endif
3275 if (mPaintDC)
3276 return (new gfxWindowsSurface(mPaintDC));
3278 #ifdef CAIRO_HAS_D2D_SURFACE
3279 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3280 gfxWindowsPlatform::RENDER_DIRECT2D) {
3281 gfxASurface::gfxContentType content = gfxASurface::CONTENT_COLOR;
3282 #if defined(MOZ_XUL)
3283 if (mTransparencyMode != eTransparencyOpaque) {
3284 content = gfxASurface::CONTENT_COLOR_ALPHA;
3286 #endif
3287 return (new gfxD2DSurface(mWnd, content));
3288 } else {
3289 #endif
3290 PRUint32 flags = gfxWindowsSurface::FLAG_TAKE_DC;
3291 if (mTransparencyMode != eTransparencyOpaque) {
3292 flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT;
3294 return (new gfxWindowsSurface(mWnd, flags));
3295 #ifdef CAIRO_HAS_D2D_SURFACE
3297 #endif
3300 /**************************************************************
3302 * SECTION: nsIWidget::OnDefaultButtonLoaded
3304 * Called after the dialog is loaded and it has a default button.
3306 **************************************************************/
3308 NS_IMETHODIMP
3309 nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect)
3311 #ifdef WINCE
3312 return NS_ERROR_NOT_IMPLEMENTED;
3313 #else
3314 if (aButtonRect.IsEmpty())
3315 return NS_OK;
3317 // Don't snap when we are not active.
3318 HWND activeWnd = ::GetActiveWindow();
3319 if (activeWnd != ::GetForegroundWindow() ||
3320 GetTopLevelHWND(mWnd, PR_TRUE) != GetTopLevelHWND(activeWnd, PR_TRUE)) {
3321 return NS_OK;
3324 PRBool isAlwaysSnapCursor = PR_FALSE;
3325 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3326 if (prefs) {
3327 nsCOMPtr<nsIPrefBranch> prefBranch;
3328 prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
3329 if (prefBranch) {
3330 prefBranch->GetBoolPref("ui.cursor_snapping.always_enabled",
3331 &isAlwaysSnapCursor);
3335 if (!isAlwaysSnapCursor) {
3336 BOOL snapDefaultButton;
3337 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0,
3338 &snapDefaultButton, 0) || !snapDefaultButton)
3339 return NS_OK;
3342 nsIntRect widgetRect;
3343 nsresult rv = GetScreenBounds(widgetRect);
3344 NS_ENSURE_SUCCESS(rv, rv);
3345 nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft());
3347 nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2,
3348 buttonRect.y + buttonRect.height / 2);
3349 // The center of the button can be outside of the widget.
3350 // E.g., it could be hidden by scrolling.
3351 if (!widgetRect.Contains(centerOfButton)) {
3352 return NS_OK;
3355 if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) {
3356 NS_ERROR("SetCursorPos failed");
3357 return NS_ERROR_FAILURE;
3359 return NS_OK;
3360 #endif
3363 NS_IMETHODIMP
3364 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta,
3365 PRBool aIsHorizontal,
3366 PRInt32 &aOverriddenDelta)
3368 // The default vertical and horizontal scrolling speed is 3, this is defined
3369 // on the document of SystemParametersInfo in MSDN.
3370 const PRUint32 kSystemDefaultScrollingSpeed = 3;
3372 PRInt32 absOriginDelta = PR_ABS(aOriginalDelta);
3374 // Compute the simple overridden speed.
3375 PRInt32 absComputedOverriddenDelta;
3376 nsresult rv =
3377 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta, aIsHorizontal,
3378 absComputedOverriddenDelta);
3379 NS_ENSURE_SUCCESS(rv, rv);
3381 aOverriddenDelta = aOriginalDelta;
3383 if (absComputedOverriddenDelta == absOriginDelta) {
3384 // We don't override now.
3385 return NS_OK;
3388 // Otherwise, we should check whether the user customized the system settings
3389 // or not. If the user did it, we should respect the will.
3390 UINT systemSpeed;
3391 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) {
3392 return NS_ERROR_FAILURE;
3394 // The default vertical scrolling speed is 3, this is defined on the document
3395 // of SystemParametersInfo in MSDN.
3396 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3397 return NS_OK;
3400 // Only Vista and later, Windows has the system setting of horizontal
3401 // scrolling by the mouse wheel.
3402 if (GetWindowsVersion() >= VISTA_VERSION) {
3403 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) {
3404 return NS_ERROR_FAILURE;
3406 // The default horizontal scrolling speed is 3, this is defined on the
3407 // document of SystemParametersInfo in MSDN.
3408 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3409 return NS_OK;
3413 // Limit the overridden delta value from the system settings. The mouse
3414 // driver might accelerate the scrolling speed already. If so, we shouldn't
3415 // override the scrolling speed for preventing the unexpected high speed
3416 // scrolling.
3417 PRInt32 absDeltaLimit;
3418 rv =
3419 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed,
3420 aIsHorizontal, absDeltaLimit);
3421 NS_ENSURE_SUCCESS(rv, rv);
3423 // If the given delta is larger than our computed limitation value, the delta
3424 // was accelerated by the mouse driver. So, we should do nothing here.
3425 if (absDeltaLimit <= absOriginDelta) {
3426 return NS_OK;
3429 absComputedOverriddenDelta =
3430 PR_MIN(absComputedOverriddenDelta, absDeltaLimit);
3432 aOverriddenDelta = (aOriginalDelta > 0) ? absComputedOverriddenDelta :
3433 -absComputedOverriddenDelta;
3434 return NS_OK;
3437 /**************************************************************
3438 **************************************************************
3440 ** BLOCK: Moz Events
3442 ** Moz GUI event management.
3444 **************************************************************
3445 **************************************************************/
3447 /**************************************************************
3449 * SECTION: Mozilla event initialization
3451 * Helpers for initializing moz events.
3453 **************************************************************/
3455 // Event intialization
3456 MSG nsWindow::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam)
3458 MSG msg;
3459 msg.message = aMessage;
3460 msg.wParam = wParam;
3461 msg.lParam = lParam;
3462 return msg;
3465 void nsWindow::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
3467 if (nsnull == aPoint) { // use the point from the event
3468 // get the message position in client coordinates
3469 if (mWnd != NULL) {
3471 DWORD pos = ::GetMessagePos();
3472 POINT cpos;
3474 cpos.x = GET_X_LPARAM(pos);
3475 cpos.y = GET_Y_LPARAM(pos);
3477 ::ScreenToClient(mWnd, &cpos);
3478 event.refPoint.x = cpos.x;
3479 event.refPoint.y = cpos.y;
3480 } else {
3481 event.refPoint.x = 0;
3482 event.refPoint.y = 0;
3485 else {
3486 // use the point override if provided
3487 event.refPoint.x = aPoint->x;
3488 event.refPoint.y = aPoint->y;
3491 #ifndef WINCE
3492 event.time = ::GetMessageTime();
3493 #else
3494 event.time = PR_Now() / 1000;
3495 #endif
3497 mLastPoint = event.refPoint;
3500 /**************************************************************
3502 * SECTION: Moz event dispatch helpers
3504 * Helpers for dispatching different types of moz events.
3506 **************************************************************/
3508 // Main event dispatch. Invokes callback and ProcessEvent method on
3509 // Event Listener object. Part of nsIWidget.
3510 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
3512 #ifdef WIDGET_DEBUG_OUTPUT
3513 debug_DumpEvent(stdout,
3514 event->widget,
3515 event,
3516 nsCAutoString("something"),
3517 (PRInt32) mWnd);
3518 #endif // WIDGET_DEBUG_OUTPUT
3520 aStatus = nsEventStatus_eIgnore;
3522 // skip processing of suppressed blur events
3523 if (event->message == NS_DEACTIVATE && BlurEventsSuppressed())
3524 return NS_OK;
3526 // Top level windows can have a view attached which requires events be sent
3527 // to the underlying base window and the view. Added when we combined the
3528 // base chrome window with the main content child for nc client area (title
3529 // bar) rendering.
3530 if (mViewCallback) {
3531 // A subset of events are sent to the base xul window first
3532 switch(event->message) {
3533 // send to the base window (view mgr ignores these for the view)
3534 case NS_UISTATECHANGED:
3535 case NS_DESTROY:
3536 case NS_SETZLEVEL:
3537 case NS_XUL_CLOSE:
3538 case NS_MOVE:
3539 (*mEventCallback)(event); // web shell / xul window
3540 return NS_OK;
3542 // sent to the base window, then to the view
3543 case NS_SIZE:
3544 case NS_DEACTIVATE:
3545 case NS_ACTIVATE:
3546 case NS_SIZEMODE:
3547 (*mEventCallback)(event); // web shell / xul window
3548 break;
3550 // attached view events
3551 aStatus = (*mViewCallback)(event);
3553 else if (mEventCallback) {
3554 aStatus = (*mEventCallback)(event);
3557 // the window can be destroyed during processing of seemingly innocuous events like, say,
3558 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3559 // which causes problems with the deleted window. therefore:
3560 if (mOnDestroyCalled)
3561 aStatus = nsEventStatus_eConsumeNoDefault;
3562 return NS_OK;
3565 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
3567 nsGUIEvent event(PR_TRUE, aMsg, this);
3568 InitEvent(event);
3570 PRBool result = DispatchWindowEvent(&event);
3571 return result;
3574 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
3576 nsEventStatus status;
3577 DispatchEvent(event, status);
3578 return ConvertStatus(status);
3581 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event, nsEventStatus &aStatus) {
3582 DispatchEvent(event, aStatus);
3583 return ConvertStatus(aStatus);
3586 PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
3587 const nsTArray<nsAlternativeCharCode>* aAlternativeCharCodes,
3588 UINT aVirtualCharCode, const MSG *aMsg,
3589 const nsModifierKeyState &aModKeyState,
3590 PRUint32 aFlags)
3592 UserActivity();
3594 nsKeyEvent event(PR_TRUE, aEventType, this);
3595 nsIntPoint point(0, 0);
3597 InitEvent(event, &point); // this add ref's event.widget
3599 event.flags |= aFlags;
3600 event.charCode = aCharCode;
3601 if (aAlternativeCharCodes)
3602 event.alternativeCharCodes.AppendElements(*aAlternativeCharCodes);
3603 event.keyCode = aVirtualCharCode;
3605 #ifdef KE_DEBUG
3606 static cnt=0;
3607 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt++,
3608 (NS_KEY_PRESS == aEventType) ? "PRESS" : (aEventType == NS_KEY_UP ? "Up" : "Down"),
3609 event.charCode, event.keyCode);
3610 printf("Shift: %s Control %s Alt: %s \n",
3611 (mIsShiftDown ? "D" : "U"), (mIsControlDown ? "D" : "U"), (mIsAltDown ? "D" : "U"));
3612 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3613 IS_VK_DOWN(NS_VK_SHIFT) ? 'S' : ' ',
3614 IS_VK_DOWN(NS_VK_CONTROL) ? 'C' : ' ',
3615 IS_VK_DOWN(NS_VK_ALT) ? 'A' : ' ',
3616 IS_VK_DOWN(VK_LSHIFT) ? 'S' : ' ',
3617 IS_VK_DOWN(VK_LCONTROL) ? 'C' : ' ',
3618 IS_VK_DOWN(VK_LMENU) ? 'A' : ' ',
3619 IS_VK_DOWN(VK_RMENU) ? 'A' : ' ',
3620 IS_VK_DOWN(VK_RCONTROL) ? 'C' : ' ',
3621 IS_VK_DOWN(VK_RSHIFT) ? 'S' : ' ');
3622 #endif
3624 event.isShift = aModKeyState.mIsShiftDown;
3625 event.isControl = aModKeyState.mIsControlDown;
3626 event.isMeta = PR_FALSE;
3627 event.isAlt = aModKeyState.mIsAltDown;
3629 NPEvent pluginEvent;
3630 if (aMsg && PluginHasFocus()) {
3631 pluginEvent.event = aMsg->message;
3632 pluginEvent.wParam = aMsg->wParam;
3633 pluginEvent.lParam = aMsg->lParam;
3634 event.pluginEvent = (void *)&pluginEvent;
3637 PRBool result = DispatchWindowEvent(&event);
3639 return result;
3642 PRBool nsWindow::DispatchCommandEvent(PRUint32 aEventCommand)
3644 nsCOMPtr<nsIAtom> command;
3645 switch (aEventCommand) {
3646 case APPCOMMAND_BROWSER_BACKWARD:
3647 command = nsWidgetAtoms::Back;
3648 break;
3649 case APPCOMMAND_BROWSER_FORWARD:
3650 command = nsWidgetAtoms::Forward;
3651 break;
3652 case APPCOMMAND_BROWSER_REFRESH:
3653 command = nsWidgetAtoms::Reload;
3654 break;
3655 case APPCOMMAND_BROWSER_STOP:
3656 command = nsWidgetAtoms::Stop;
3657 break;
3658 case APPCOMMAND_BROWSER_SEARCH:
3659 command = nsWidgetAtoms::Search;
3660 break;
3661 case APPCOMMAND_BROWSER_FAVORITES:
3662 command = nsWidgetAtoms::Bookmarks;
3663 break;
3664 case APPCOMMAND_BROWSER_HOME:
3665 command = nsWidgetAtoms::Home;
3666 break;
3667 default:
3668 return PR_FALSE;
3670 nsCommandEvent event(PR_TRUE, nsWidgetAtoms::onAppCommand, command, this);
3672 InitEvent(event);
3673 DispatchWindowEvent(&event);
3675 return PR_TRUE;
3678 // Recursively dispatch synchronous paints for nsIWidget
3679 // descendants with invalidated rectangles.
3680 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
3682 LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
3683 if (proc == (LONG_PTR)&nsWindow::WindowProc) {
3684 // its one of our windows so check to see if it has a
3685 // invalidated rect. If it does. Dispatch a synchronous
3686 // paint.
3687 if (GetUpdateRect(aWnd, NULL, FALSE))
3688 VERIFY(::UpdateWindow(aWnd));
3690 return TRUE;
3693 // Check for pending paints and dispatch any pending paint
3694 // messages for any nsIWidget which is a descendant of the
3695 // top-level window that *this* window is embedded within.
3697 // Note: We do not dispatch pending paint messages for non
3698 // nsIWidget managed windows.
3699 void nsWindow::DispatchPendingEvents()
3701 if (mPainting) {
3702 NS_WARNING("We were asked to dispatch pending events during painting, "
3703 "denying since that's unsafe.");
3704 return;
3707 // We need to ensure that reflow events do not get starved.
3708 // At the same time, we don't want to recurse through here
3709 // as that would prevent us from dispatching starved paints.
3710 static int recursionBlocker = 0;
3711 if (recursionBlocker++ == 0) {
3712 NS_ProcessPendingEvents(nsnull, PR_MillisecondsToInterval(100));
3713 --recursionBlocker;
3716 // Quickly check to see if there are any
3717 // paint events pending.
3718 if (::GetQueueStatus(QS_PAINT)) {
3719 // Find the top level window.
3720 HWND topWnd = GetTopLevelHWND(mWnd);
3722 // Dispatch pending paints for all topWnd's descendant windows.
3723 // Note: EnumChildWindows enumerates all descendant windows not just
3724 // it's children.
3725 #if !defined(WINCE)
3726 ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, 0);
3727 #else
3728 nsWindowCE::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3729 #endif
3733 // Deal with plugin events
3734 PRBool nsWindow::DispatchPluginEvent(const MSG &aMsg)
3736 if (!PluginHasFocus())
3737 return PR_FALSE;
3739 nsGUIEvent event(PR_TRUE, NS_PLUGIN_EVENT, this);
3740 nsIntPoint point(0, 0);
3741 InitEvent(event, &point);
3742 NPEvent pluginEvent;
3743 pluginEvent.event = aMsg.message;
3744 pluginEvent.wParam = aMsg.wParam;
3745 pluginEvent.lParam = aMsg.lParam;
3746 event.pluginEvent = (void *)&pluginEvent;
3747 return DispatchWindowEvent(&event);
3750 PRBool nsWindow::DispatchPluginEvent(UINT aMessage,
3751 WPARAM aWParam,
3752 LPARAM aLParam,
3753 PRBool aDispatchPendingEvents)
3755 PRBool ret = DispatchPluginEvent(InitMSG(aMessage, aWParam, aLParam));
3756 if (aDispatchPendingEvents) {
3757 DispatchPendingEvents();
3759 return ret;
3762 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
3763 UINT aLastMsg)
3765 MSG msg;
3766 ::GetMessageW(&msg, mWnd, aFirstMsg, aLastMsg);
3767 DispatchPluginEvent(msg);
3770 // Deal with all sort of mouse event
3771 PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
3772 LPARAM lParam, PRBool aIsContextMenuKey,
3773 PRInt16 aButton, PRUint16 aInputSource)
3775 PRBool result = PR_FALSE;
3777 UserActivity();
3779 if (!mEventCallback) {
3780 return result;
3783 switch (aEventType) {
3784 case NS_MOUSE_BUTTON_DOWN:
3785 CaptureMouse(PR_TRUE);
3786 break;
3788 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3789 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3790 case NS_MOUSE_BUTTON_UP:
3791 case NS_MOUSE_MOVE:
3792 case NS_MOUSE_EXIT:
3793 if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && mIsInMouseCapture)
3794 CaptureMouse(PR_FALSE);
3795 break;
3797 default:
3798 break;
3800 } // switch
3802 nsIntPoint eventPoint;
3803 eventPoint.x = GET_X_LPARAM(lParam);
3804 eventPoint.y = GET_Y_LPARAM(lParam);
3806 nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal,
3807 aIsContextMenuKey
3808 ? nsMouseEvent::eContextMenuKey
3809 : nsMouseEvent::eNormal);
3810 if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) {
3811 nsIntPoint zero(0, 0);
3812 InitEvent(event, &zero);
3813 } else {
3814 InitEvent(event, &eventPoint);
3817 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
3818 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
3819 event.isMeta = PR_FALSE;
3820 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
3821 event.button = aButton;
3822 event.inputSource = aInputSource;
3824 nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
3826 // Suppress mouse moves caused by widget creation
3827 if (aEventType == NS_MOUSE_MOVE)
3829 if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y))
3830 return result;
3831 sLastMouseMovePoint.x = mpScreen.x;
3832 sLastMouseMovePoint.y = mpScreen.y;
3835 PRBool insideMovementThreshold = (abs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
3836 (abs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
3838 BYTE eventButton;
3839 switch (aButton) {
3840 case nsMouseEvent::eLeftButton:
3841 eventButton = VK_LBUTTON;
3842 break;
3843 case nsMouseEvent::eMiddleButton:
3844 eventButton = VK_MBUTTON;
3845 break;
3846 case nsMouseEvent::eRightButton:
3847 eventButton = VK_RBUTTON;
3848 break;
3849 default:
3850 eventButton = 0;
3851 break;
3854 // Doubleclicks are used to set the click count, then changed to mousedowns
3855 // We're going to time double-clicks from mouse *up* to next mouse *down*
3856 #ifndef WINCE
3857 LONG curMsgTime = ::GetMessageTime();
3858 #else
3859 LONG curMsgTime = PR_Now() / 1000;
3860 #endif
3862 if (aEventType == NS_MOUSE_DOUBLECLICK) {
3863 event.message = NS_MOUSE_BUTTON_DOWN;
3864 event.button = aButton;
3865 sLastClickCount = 2;
3867 else if (aEventType == NS_MOUSE_BUTTON_UP) {
3868 // remember when this happened for the next mouse down
3869 sLastMousePoint.x = eventPoint.x;
3870 sLastMousePoint.y = eventPoint.y;
3871 sLastMouseButton = eventButton;
3873 else if (aEventType == NS_MOUSE_BUTTON_DOWN) {
3874 // now look to see if we want to convert this to a double- or triple-click
3875 if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold &&
3876 eventButton == sLastMouseButton) {
3877 sLastClickCount ++;
3878 } else {
3879 // reset the click count, to count *this* click
3880 sLastClickCount = 1;
3882 // Set last Click time on MouseDown only
3883 sLastMouseDownTime = curMsgTime;
3885 else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
3886 sLastClickCount = 0;
3888 else if (aEventType == NS_MOUSE_EXIT) {
3889 event.exit = IsTopLevelMouseExit(mWnd) ? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
3891 else if (aEventType == NS_MOUSE_MOZHITTEST)
3893 event.flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
3895 event.clickCount = sLastClickCount;
3897 #ifdef NS_DEBUG_XX
3898 printf("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount);
3899 #endif
3901 NPEvent pluginEvent;
3903 switch (aEventType)
3905 case NS_MOUSE_BUTTON_DOWN:
3906 switch (aButton) {
3907 case nsMouseEvent::eLeftButton:
3908 pluginEvent.event = WM_LBUTTONDOWN;
3909 break;
3910 case nsMouseEvent::eMiddleButton:
3911 pluginEvent.event = WM_MBUTTONDOWN;
3912 break;
3913 case nsMouseEvent::eRightButton:
3914 pluginEvent.event = WM_RBUTTONDOWN;
3915 break;
3916 default:
3917 break;
3919 break;
3920 case NS_MOUSE_BUTTON_UP:
3921 switch (aButton) {
3922 case nsMouseEvent::eLeftButton:
3923 pluginEvent.event = WM_LBUTTONUP;
3924 break;
3925 case nsMouseEvent::eMiddleButton:
3926 pluginEvent.event = WM_MBUTTONUP;
3927 break;
3928 case nsMouseEvent::eRightButton:
3929 pluginEvent.event = WM_RBUTTONUP;
3930 break;
3931 default:
3932 break;
3934 break;
3935 case NS_MOUSE_DOUBLECLICK:
3936 switch (aButton) {
3937 case nsMouseEvent::eLeftButton:
3938 pluginEvent.event = WM_LBUTTONDBLCLK;
3939 break;
3940 case nsMouseEvent::eMiddleButton:
3941 pluginEvent.event = WM_MBUTTONDBLCLK;
3942 break;
3943 case nsMouseEvent::eRightButton:
3944 pluginEvent.event = WM_RBUTTONDBLCLK;
3945 break;
3946 default:
3947 break;
3949 break;
3950 case NS_MOUSE_MOVE:
3951 pluginEvent.event = WM_MOUSEMOVE;
3952 break;
3953 case NS_MOUSE_EXIT:
3954 pluginEvent.event = WM_MOUSELEAVE;
3955 break;
3956 default:
3957 pluginEvent.event = WM_NULL;
3958 break;
3961 pluginEvent.wParam = wParam; // plugins NEED raw OS event flags!
3962 pluginEvent.lParam = lParam;
3964 event.pluginEvent = (void *)&pluginEvent;
3966 // call the event callback
3967 if (nsnull != mEventCallback) {
3968 if (nsToolkit::gMouseTrailer)
3969 nsToolkit::gMouseTrailer->Disable();
3970 if (aEventType == NS_MOUSE_MOVE) {
3971 if (nsToolkit::gMouseTrailer && !mIsInMouseCapture) {
3972 nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd);
3974 nsIntRect rect;
3975 GetBounds(rect);
3976 rect.x = 0;
3977 rect.y = 0;
3979 if (rect.Contains(event.refPoint)) {
3980 if (sCurrentWindow == NULL || sCurrentWindow != this) {
3981 if ((nsnull != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
3982 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3983 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, PR_FALSE,
3984 nsMouseEvent::eLeftButton, aInputSource);
3986 sCurrentWindow = this;
3987 if (!mInDtor) {
3988 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3989 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, PR_FALSE,
3990 nsMouseEvent::eLeftButton, aInputSource);
3994 } else if (aEventType == NS_MOUSE_EXIT) {
3995 if (sCurrentWindow == this) {
3996 sCurrentWindow = nsnull;
4000 result = DispatchWindowEvent(&event);
4002 if (nsToolkit::gMouseTrailer)
4003 nsToolkit::gMouseTrailer->Enable();
4005 // Release the widget with NS_IF_RELEASE() just in case
4006 // the context menu key code in nsEventListenerManager::HandleEvent()
4007 // released it already.
4008 return result;
4011 return result;
4014 // Deal with accessibile event
4015 #ifdef ACCESSIBILITY
4016 nsAccessible*
4017 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType)
4019 if (nsnull == mEventCallback) {
4020 return nsnull;
4023 nsAccessibleEvent event(PR_TRUE, aEventType, this);
4024 InitEvent(event, nsnull);
4026 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
4027 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
4028 event.isMeta = PR_FALSE;
4029 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
4031 DispatchWindowEvent(&event);
4033 return event.mAccessible;
4035 #endif
4037 PRBool nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType)
4039 if (aEventType == NS_ACTIVATE)
4040 sJustGotActivate = PR_FALSE;
4041 sJustGotDeactivate = PR_FALSE;
4043 // retrive the toplevel window or dialog
4044 HWND curWnd = mWnd;
4045 HWND toplevelWnd = NULL;
4046 while (curWnd) {
4047 toplevelWnd = curWnd;
4049 nsWindow *win = GetNSWindowPtr(curWnd);
4050 if (win) {
4051 nsWindowType wintype;
4052 win->GetWindowType(wintype);
4053 if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog)
4054 break;
4057 curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
4060 if (toplevelWnd) {
4061 nsWindow *win = GetNSWindowPtr(toplevelWnd);
4062 if (win)
4063 return win->DispatchFocus(aEventType);
4066 return PR_FALSE;
4069 // Deal with focus messages
4070 PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
4072 // call the event callback
4073 if (mEventCallback) {
4074 nsGUIEvent event(PR_TRUE, aEventType, this);
4075 InitEvent(event);
4077 //focus and blur event should go to their base widget loc, not current mouse pos
4078 event.refPoint.x = 0;
4079 event.refPoint.y = 0;
4081 NPEvent pluginEvent;
4083 switch (aEventType)
4085 case NS_ACTIVATE:
4086 pluginEvent.event = WM_SETFOCUS;
4087 break;
4088 case NS_DEACTIVATE:
4089 pluginEvent.event = WM_KILLFOCUS;
4090 break;
4091 case NS_PLUGIN_ACTIVATE:
4092 pluginEvent.event = WM_KILLFOCUS;
4093 break;
4094 default:
4095 break;
4098 event.pluginEvent = (void *)&pluginEvent;
4100 return DispatchWindowEvent(&event);
4102 return PR_FALSE;
4105 PRBool nsWindow::IsTopLevelMouseExit(HWND aWnd)
4107 DWORD pos = ::GetMessagePos();
4108 POINT mp;
4109 mp.x = GET_X_LPARAM(pos);
4110 mp.y = GET_Y_LPARAM(pos);
4111 HWND mouseWnd = ::WindowFromPoint(mp);
4113 // GetTopLevelHWND will return a HWND for the window frame (which includes
4114 // the non-client area). If the mouse has moved into the non-client area,
4115 // we should treat it as a top-level exit.
4116 HWND mouseTopLevel = nsWindow::GetTopLevelHWND(mouseWnd);
4117 if (mouseWnd == mouseTopLevel)
4118 return PR_TRUE;
4120 return nsWindow::GetTopLevelHWND(aWnd) != mouseTopLevel;
4123 PRBool nsWindow::BlurEventsSuppressed()
4125 // are they suppressed in this window?
4126 if (mBlurSuppressLevel > 0)
4127 return PR_TRUE;
4129 // are they suppressed by any container widget?
4130 HWND parentWnd = ::GetParent(mWnd);
4131 if (parentWnd) {
4132 nsWindow *parent = GetNSWindowPtr(parentWnd);
4133 if (parent)
4134 return parent->BlurEventsSuppressed();
4136 return PR_FALSE;
4139 // In some circumstances (opening dependent windows) it makes more sense
4140 // (and fixes a crash bug) to not blur the parent window. Called from
4141 // nsFilePicker.
4142 void nsWindow::SuppressBlurEvents(PRBool aSuppress)
4144 if (aSuppress)
4145 ++mBlurSuppressLevel; // for this widget
4146 else {
4147 NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression");
4148 if (mBlurSuppressLevel > 0)
4149 --mBlurSuppressLevel;
4153 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
4155 return aStatus == nsEventStatus_eConsumeNoDefault;
4158 /**************************************************************
4160 * SECTION: IPC
4162 * IPC related helpers.
4164 **************************************************************/
4166 #ifdef MOZ_IPC
4168 // static
4169 bool
4170 nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult)
4172 switch(aMsg) {
4173 case WM_SETFOCUS:
4174 case WM_KILLFOCUS:
4175 case WM_ENABLE:
4176 case WM_WINDOWPOSCHANGING:
4177 case WM_WINDOWPOSCHANGED:
4178 case WM_PARENTNOTIFY:
4179 case WM_ACTIVATEAPP:
4180 case WM_NCACTIVATE:
4181 case WM_ACTIVATE:
4182 case WM_CHILDACTIVATE:
4183 case WM_IME_SETCONTEXT:
4184 case WM_IME_NOTIFY:
4185 case WM_SHOWWINDOW:
4186 case WM_CANCELMODE:
4187 case WM_MOUSEACTIVATE:
4188 case WM_CONTEXTMENU:
4189 aResult = 0;
4190 return true;
4192 case WM_SETTINGCHANGE:
4193 case WM_SETCURSOR:
4194 return false;
4197 #ifdef DEBUG
4198 char szBuf[200];
4199 sprintf(szBuf,
4200 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg);
4201 NS_WARNING(szBuf);
4202 #endif
4204 return false;
4207 void
4208 nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
4210 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4211 "Failed to prevent a nonqueued message from running!");
4213 // Modal UI being displayed in windowless plugins.
4214 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4215 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4216 LRESULT res;
4217 if (IsAsyncResponseEvent(msg, res)) {
4218 ReplyMessage(res);
4220 return;
4223 // Handle certain sync plugin events sent to the parent which
4224 // trigger ipc calls that result in deadlocks.
4226 DWORD dwResult = 0;
4227 PRBool handled = PR_FALSE;
4229 switch(msg) {
4230 // Windowless flash sending WM_ACTIVATE events to the main window
4231 // via calls to ShowWindow.
4232 case WM_ACTIVATE:
4233 if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE &&
4234 IsWindow((HWND)lParam))
4235 handled = PR_TRUE;
4236 break;
4237 // Wheel events forwarded from the child.
4238 case WM_MOUSEWHEEL:
4239 case WM_MOUSEHWHEEL:
4240 case WM_HSCROLL:
4241 case WM_VSCROLL:
4242 // Plugins taking or losing focus triggering focus app messages.
4243 case WM_SETFOCUS:
4244 case WM_KILLFOCUS:
4245 // Windowed plugins that pass sys key events to defwndproc generate
4246 // WM_SYSCOMMAND events to the main window.
4247 case WM_SYSCOMMAND:
4248 // Windowed plugins that fire context menu selection events to parent
4249 // windows.
4250 case WM_CONTEXTMENU:
4251 // IME events fired as a result of synchronous focus changes
4252 case WM_IME_SETCONTEXT:
4253 handled = PR_TRUE;
4254 break;
4257 if (handled &&
4258 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4259 ReplyMessage(dwResult);
4263 #endif // MOZ_IPC
4265 /**************************************************************
4266 **************************************************************
4268 ** BLOCK: Native events
4270 ** Main Windows message handlers and OnXXX handlers for
4271 ** Windows event handling.
4273 **************************************************************
4274 **************************************************************/
4276 /**************************************************************
4278 * SECTION: Wind proc.
4280 * The main Windows event procedures and associated
4281 * message processing methods.
4283 **************************************************************/
4285 #ifdef _MSC_VER
4286 static int ReportException(EXCEPTION_POINTERS *aExceptionInfo)
4288 #ifdef MOZ_CRASHREPORTER
4289 nsCOMPtr<nsICrashReporter> cr =
4290 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
4291 if (cr)
4292 cr->WriteMinidumpForException(aExceptionInfo);
4293 #endif
4294 return EXCEPTION_EXECUTE_HANDLER;
4296 #endif
4298 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
4299 // exceptions and passes the real work to WindowProcInternal. See bug 587406
4300 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
4301 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4303 #ifdef _MSC_VER
4304 __try {
4305 return WindowProcInternal(hWnd, msg, wParam, lParam);
4307 __except(ReportException(GetExceptionInformation())) {
4308 ::TerminateProcess(::GetCurrentProcess(), 253);
4310 #else
4311 return WindowProcInternal(hWnd, msg, wParam, lParam);
4312 #endif
4315 LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4317 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4318 MOZ_FUNCTION_NAME, __LINE__, hWnd, msg,
4319 wParam, lParam);
4321 // Get the window which caused the event and ask it to process the message
4322 nsWindow *someWindow = GetNSWindowPtr(hWnd);
4324 #ifdef MOZ_IPC
4325 if (someWindow)
4326 someWindow->IPCWindowProcHandler(msg, wParam, lParam);
4327 #endif
4329 // create this here so that we store the last rolled up popup until after
4330 // the event has been processed.
4331 nsAutoRollup autoRollup;
4333 LRESULT popupHandlingResult;
4334 if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult))
4335 return popupHandlingResult;
4337 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4338 // why we are hitting this assert
4339 if (nsnull == someWindow) {
4340 NS_ASSERTION(someWindow, "someWindow is null, cannot call any CallWindowProc");
4341 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
4344 // hold on to the window for the life of this method, in case it gets
4345 // deleted during processing. yes, it's a double hack, since someWindow
4346 // is not really an interface.
4347 nsCOMPtr<nsISupports> kungFuDeathGrip;
4348 if (!someWindow->mInDtor) // not if we're in the destructor!
4349 kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)someWindow);
4351 // Call ProcessMessage
4352 LRESULT retValue;
4353 if (PR_TRUE == someWindow->ProcessMessage(msg, wParam, lParam, &retValue)) {
4354 return retValue;
4357 LRESULT res = ::CallWindowProcW(someWindow->GetPrevWindowProc(),
4358 hWnd, msg, wParam, lParam);
4360 return res;
4363 // The main windows message processing method for plugins.
4364 // The result means whether this method processed the native
4365 // event for plugin. If false, the native event should be
4366 // processed by the caller self.
4367 PRBool
4368 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
4369 LRESULT *aResult,
4370 PRBool &aCallDefWndProc)
4372 NS_PRECONDITION(aResult, "aResult must be non-null.");
4373 *aResult = 0;
4375 aCallDefWndProc = PR_FALSE;
4376 PRBool eventDispatched = PR_FALSE;
4377 switch (aMsg.message) {
4378 case WM_CHAR:
4379 case WM_SYSCHAR:
4380 *aResult = ProcessCharMessage(aMsg, &eventDispatched);
4381 break;
4383 case WM_KEYUP:
4384 case WM_SYSKEYUP:
4385 *aResult = ProcessKeyUpMessage(aMsg, &eventDispatched);
4386 break;
4388 case WM_KEYDOWN:
4389 case WM_SYSKEYDOWN:
4390 *aResult = ProcessKeyDownMessage(aMsg, &eventDispatched);
4391 break;
4393 case WM_DEADCHAR:
4394 case WM_SYSDEADCHAR:
4395 case WM_CONTEXTMENU:
4397 case WM_CUT:
4398 case WM_COPY:
4399 case WM_PASTE:
4400 case WM_CLEAR:
4401 case WM_UNDO:
4402 break;
4404 default:
4405 return PR_FALSE;
4408 if (!eventDispatched)
4409 aCallDefWndProc = !DispatchPluginEvent(aMsg);
4410 DispatchPendingEvents();
4411 return PR_TRUE;
4414 // The main windows message processing method.
4415 PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
4416 LRESULT *aRetValue)
4418 // (Large blocks of code should be broken out into OnEvent handlers.)
4419 if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
4420 return PR_TRUE;
4422 #if defined(EVENT_DEBUG_OUTPUT)
4423 // First param shows all events, second param indicates whether
4424 // to show mouse move events. See nsWindowDbg for details.
4425 PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
4426 #endif
4428 PRBool eatMessage;
4429 if (nsIMM32Handler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
4430 eatMessage)) {
4431 return mWnd ? eatMessage : PR_TRUE;
4434 if (PluginHasFocus()) {
4435 PRBool callDefaultWndProc;
4436 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4437 if (ProcessMessageForPlugin(nativeMsg, aRetValue, callDefaultWndProc)) {
4438 return mWnd ? !callDefaultWndProc : PR_TRUE;
4442 PRBool result = PR_FALSE; // call the default nsWindow proc
4443 *aRetValue = 0;
4445 static PRBool getWheelInfo = PR_TRUE;
4447 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4448 // Glass hit testing w/custom transparent margins
4449 LRESULT dwmHitResult;
4450 if (mCustomNonClient &&
4451 nsUXThemeData::CheckForCompositor() &&
4452 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) {
4453 *aRetValue = dwmHitResult;
4454 return PR_TRUE;
4456 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4458 switch (msg) {
4459 #ifndef WINCE
4460 // WM_QUERYENDSESSION must be handled by all windows.
4461 // Otherwise Windows thinks the window can just be killed at will.
4462 case WM_QUERYENDSESSION:
4463 if (sCanQuit == TRI_UNKNOWN)
4465 // Ask if it's ok to quit, and store the answer until we
4466 // get WM_ENDSESSION signaling the round is complete.
4467 nsCOMPtr<nsIObserverService> obsServ =
4468 mozilla::services::GetObserverService();
4469 nsCOMPtr<nsISupportsPRBool> cancelQuit =
4470 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
4471 cancelQuit->SetData(PR_FALSE);
4472 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
4474 PRBool abortQuit;
4475 cancelQuit->GetData(&abortQuit);
4476 sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
4478 *aRetValue = sCanQuit ? TRUE : FALSE;
4479 result = PR_TRUE;
4480 break;
4481 #endif
4483 #ifndef WINCE
4484 case WM_ENDSESSION:
4485 #endif
4486 case MOZ_WM_APP_QUIT:
4487 if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE))
4489 // Let's fake a shutdown sequence without actually closing windows etc.
4490 // to avoid Windows killing us in the middle. A proper shutdown would
4491 // require having a chance to pump some messages. Unfortunately
4492 // Windows won't let us do that. Bug 212316.
4493 nsCOMPtr<nsIObserverService> obsServ =
4494 mozilla::services::GetObserverService();
4495 NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
4496 obsServ->NotifyObservers(nsnull, "quit-application-granted", nsnull);
4497 obsServ->NotifyObservers(nsnull, "quit-application-forced", nsnull);
4498 obsServ->NotifyObservers(nsnull, "quit-application", nsnull);
4499 obsServ->NotifyObservers(nsnull, "profile-change-net-teardown", context.get());
4500 obsServ->NotifyObservers(nsnull, "profile-change-teardown", context.get());
4501 obsServ->NotifyObservers(nsnull, "profile-before-change", context.get());
4502 // Then a controlled but very quick exit.
4503 _exit(0);
4505 sCanQuit = TRI_UNKNOWN;
4506 result = PR_TRUE;
4507 break;
4509 #ifndef WINCE
4510 case WM_DISPLAYCHANGE:
4511 DispatchStandardEvent(NS_DISPLAYCHANGED);
4512 break;
4513 #endif
4515 case WM_SYSCOLORCHANGE:
4516 // Note: This is sent for child windows as well as top-level windows.
4517 // The Win32 toolkit normally only sends these events to top-level windows.
4518 // But we cycle through all of the childwindows and send it to them as well
4519 // so all presentations get notified properly.
4520 // See nsWindow::GlobalMsgWindowProc.
4521 DispatchStandardEvent(NS_SYSCOLORCHANGED);
4522 break;
4524 case WM_NOTIFY:
4525 // TAB change
4527 LPNMHDR pnmh = (LPNMHDR) lParam;
4529 switch (pnmh->code) {
4530 case TCN_SELCHANGE:
4532 DispatchStandardEvent(NS_TABCHANGE);
4533 result = PR_TRUE;
4535 break;
4538 break;
4540 case WM_XP_THEMECHANGED:
4542 // Update non-client margin offsets
4543 UpdateNonClientMargins();
4545 DispatchStandardEvent(NS_THEMECHANGED);
4547 // Invalidate the window so that the repaint will
4548 // pick up the new theme.
4549 Invalidate(PR_FALSE);
4551 break;
4553 case WM_FONTCHANGE:
4555 nsresult rv;
4556 PRBool didChange = PR_FALSE;
4558 // update the global font list
4559 nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
4560 if (NS_SUCCEEDED(rv)) {
4561 fontEnum->UpdateFontList(&didChange);
4562 //didChange is TRUE only if new font langGroup is added to the list.
4563 if (didChange) {
4564 // update device context font cache
4565 // Dirty but easiest way:
4566 // Changing nsIPrefBranch entry which triggers callbacks
4567 // and flows into calling mDeviceContext->FlushFontCache()
4568 // to update the font cache in all the instance of Browsers
4569 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
4570 if (prefs) {
4571 nsCOMPtr<nsIPrefBranch> fiPrefs;
4572 prefs->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs));
4573 if (fiPrefs) {
4574 PRBool fontInternalChange = PR_FALSE;
4575 fiPrefs->GetBoolPref("changed", &fontInternalChange);
4576 fiPrefs->SetBoolPref("changed", !fontInternalChange);
4580 } //if (NS_SUCCEEDED(rv))
4582 break;
4584 case WM_NCCALCSIZE:
4586 // If wParam is TRUE, it specifies that the application should indicate
4587 // which part of the client area contains valid information. The system
4588 // copies the valid information to the specified area within the new
4589 // client area. If the wParam parameter is FALSE, the application should
4590 // return zero.
4591 if (mCustomNonClient) {
4592 if (!wParam) {
4593 result = PR_TRUE;
4594 *aRetValue = 0;
4595 break;
4598 // before:
4599 // rgrc[0]: the proposed window
4600 // rgrc[1]: the current window
4601 // rgrc[2]: the source client area
4602 // pncsp->lppos: move/size data
4603 // after:
4604 // rgrc[0]: the new client area
4605 // rgrc[1]: the destination window
4606 // rgrc[2]: the source client area
4607 // (all values in screen coordiantes)
4608 NCCALCSIZE_PARAMS *pncsp = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
4609 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd, msg, wParam, lParam);
4610 pncsp->rgrc[0].top -= mNonClientOffset.top;
4611 pncsp->rgrc[0].left -= mNonClientOffset.left;
4612 pncsp->rgrc[0].right += mNonClientOffset.right;
4613 pncsp->rgrc[0].bottom += mNonClientOffset.bottom;
4615 result = PR_TRUE;
4616 *aRetValue = res;
4618 break;
4621 case WM_NCHITTEST:
4624 * If an nc client area margin has been moved, we are responsible
4625 * for calculating where the resize margins are and returning the
4626 * appropriate set of hit test constants. DwmDefWindowProc (above)
4627 * will handle hit testing on it's command buttons if we are on a
4628 * composited desktop.
4631 if (!mCustomNonClient)
4632 break;
4634 *aRetValue =
4635 ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
4636 result = PR_TRUE;
4637 break;
4640 case WM_SETTEXT:
4642 * WM_SETTEXT paints the titlebar area. Avoid this if we have a
4643 * custom titlebar we paint ourselves.
4646 if (!mCustomNonClient || mNonClientMargins.top == -1)
4647 break;
4650 // From msdn, the way around this is to disable the visible state
4651 // temporarily. We need the text to be set but we don't want the
4652 // redraw to occur.
4653 DWORD style = GetWindowLong(mWnd, GWL_STYLE);
4654 SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
4655 *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd,
4656 msg, wParam, lParam);
4657 SetWindowLong(mWnd, GWL_STYLE, style);
4658 return PR_TRUE;
4661 case WM_NCACTIVATE:
4664 * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
4665 * through WM_NCPAINT via InvalidateNonClientRegion.
4668 if (!mCustomNonClient)
4669 break;
4671 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4672 // let the dwm handle nc painting on glass
4673 if(nsUXThemeData::CheckForCompositor())
4674 break;
4675 #endif
4677 if (wParam == TRUE) {
4678 // going active
4679 *aRetValue = FALSE; // ignored
4680 result = PR_TRUE;
4681 // invalidate to trigger a paint
4682 InvalidateNonClientRegion();
4683 break;
4684 } else {
4685 // going inactive
4686 *aRetValue = TRUE; // go ahead and deactive
4687 result = PR_TRUE;
4688 // invalidate to trigger a paint
4689 InvalidateNonClientRegion();
4690 break;
4694 case WM_NCPAINT:
4697 * Reset the non-client paint region so that it excludes the
4698 * non-client areas we paint manually. Then call defwndproc
4699 * to do the actual painting.
4702 if (!mCustomNonClient)
4703 break;
4705 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4706 // let the dwm handle nc painting on glass
4707 if(nsUXThemeData::CheckForCompositor())
4708 break;
4709 #endif
4711 HRGN paintRgn = ExcludeNonClientFromPaintRegion((HRGN)wParam);
4712 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd,
4713 msg, (WPARAM)paintRgn, lParam);
4714 if (paintRgn != (HRGN)wParam)
4715 DeleteObject(paintRgn);
4716 *aRetValue = res;
4717 result = PR_TRUE;
4719 break;
4721 #ifndef WINCE
4722 case WM_POWERBROADCAST:
4723 // only hidden window handle this
4724 // to prevent duplicate notification
4725 if (mWindowType == eWindowType_invisible) {
4726 switch (wParam)
4728 case PBT_APMSUSPEND:
4729 PostSleepWakeNotification("sleep_notification");
4730 break;
4731 case PBT_APMRESUMEAUTOMATIC:
4732 case PBT_APMRESUMECRITICAL:
4733 case PBT_APMRESUMESUSPEND:
4734 PostSleepWakeNotification("wake_notification");
4735 break;
4738 break;
4739 #endif
4741 case WM_MOVE: // Window moved
4743 RECT rect;
4744 ::GetWindowRect(mWnd, &rect);
4745 result = OnMove(rect.left, rect.top);
4747 break;
4749 case WM_CLOSE: // close request
4750 DispatchStandardEvent(NS_XUL_CLOSE);
4751 result = PR_TRUE; // abort window closure
4752 break;
4754 case WM_DESTROY:
4755 // clean up.
4756 OnDestroy();
4757 result = PR_TRUE;
4758 break;
4760 case WM_PAINT:
4761 *aRetValue = (int) OnPaint(NULL, 0);
4762 result = PR_TRUE;
4763 break;
4765 #ifndef WINCE
4766 case WM_PRINTCLIENT:
4767 result = OnPaint((HDC) wParam, 0);
4768 break;
4769 #endif
4771 case WM_HOTKEY:
4772 result = OnHotKey(wParam, lParam);
4773 break;
4775 case WM_SYSCHAR:
4776 case WM_CHAR:
4778 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4779 result = ProcessCharMessage(nativeMsg, nsnull);
4780 DispatchPendingEvents();
4782 break;
4784 case WM_SYSKEYUP:
4785 case WM_KEYUP:
4787 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4788 result = ProcessKeyUpMessage(nativeMsg, nsnull);
4789 DispatchPendingEvents();
4791 break;
4793 case WM_SYSKEYDOWN:
4794 case WM_KEYDOWN:
4796 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4797 result = ProcessKeyDownMessage(nativeMsg, nsnull);
4798 DispatchPendingEvents();
4800 break;
4802 // say we've dealt with erase background if widget does
4803 // not need auto-erasing
4804 case WM_ERASEBKGND:
4805 if (!AutoErase((HDC)wParam)) {
4806 *aRetValue = 1;
4807 result = PR_TRUE;
4809 break;
4811 case WM_MOUSEMOVE:
4813 #ifdef WINCE_WINDOWS_MOBILE
4814 // Reset the kill timer so that we can continue at this
4815 // priority
4816 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2seconds */, NULL);
4817 #endif
4818 // Suppress dispatch of pending events
4819 // when mouse moves are generated by widget
4820 // creation instead of user input.
4821 LPARAM lParamScreen = lParamToScreen(lParam);
4822 POINT mp;
4823 mp.x = GET_X_LPARAM(lParamScreen);
4824 mp.y = GET_Y_LPARAM(lParamScreen);
4825 PRBool userMovedMouse = PR_FALSE;
4826 if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) {
4827 userMovedMouse = PR_TRUE;
4829 mExitToNonClientArea = PR_FALSE;
4831 result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam,
4832 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4833 if (userMovedMouse) {
4834 DispatchPendingEvents();
4837 break;
4839 #ifdef WINCE_WINDOWS_MOBILE
4840 case WM_TIMER:
4841 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4842 KillTimer(mWnd, KILL_PRIORITY_ID);
4843 break;
4844 #endif
4846 case WM_LBUTTONDOWN:
4848 #ifdef WINCE_WINDOWS_MOBILE
4849 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
4850 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2 seconds */, NULL);
4851 #endif
4852 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
4853 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4854 DispatchPendingEvents();
4856 break;
4858 case WM_LBUTTONUP:
4860 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam,
4861 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4862 DispatchPendingEvents();
4864 #ifdef WINCE_WINDOWS_MOBILE
4865 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4866 KillTimer(mWnd, KILL_PRIORITY_ID);
4867 #endif
4869 break;
4871 #ifndef WINCE
4872 case WM_MOUSELEAVE:
4874 // We need to check mouse button states and put them in for
4875 // wParam.
4876 WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
4877 | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
4878 | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
4879 // Synthesize an event position because we don't get one from
4880 // WM_MOUSELEAVE.
4881 LPARAM pos = lParamToClient(::GetMessagePos());
4882 DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, PR_FALSE,
4883 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4885 break;
4886 #endif
4888 case WM_CONTEXTMENU:
4890 // if the context menu is brought up from the keyboard, |lParam|
4891 // will be -1.
4892 LPARAM pos;
4893 PRBool contextMenukey = PR_FALSE;
4894 if (lParam == -1)
4896 contextMenukey = PR_TRUE;
4897 pos = lParamToClient(GetMessagePos());
4899 else
4901 pos = lParamToClient(lParam);
4904 result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey,
4905 contextMenukey ?
4906 nsMouseEvent::eLeftButton :
4907 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4908 if (lParam != -1 && !result && mCustomNonClient &&
4909 DispatchMouseEvent(NS_MOUSE_MOZHITTEST, wParam, pos,
4910 PR_FALSE, nsMouseEvent::eLeftButton,
4911 MOUSE_INPUT_SOURCE())) {
4912 // Blank area hit, throw up the system menu.
4913 HMENU hMenu = GetSystemMenu(mWnd, FALSE);
4914 if (hMenu) {
4915 LPARAM cmd =
4916 TrackPopupMenu(hMenu,
4917 (TPM_LEFTBUTTON|TPM_RIGHTBUTTON|
4918 TPM_RETURNCMD|TPM_TOPALIGN|
4919 (mIsRTL ? TPM_RIGHTALIGN : TPM_LEFTALIGN)),
4920 GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
4921 0, mWnd, NULL);
4922 if (cmd) {
4923 PostMessage(mWnd, WM_SYSCOMMAND, cmd, 0);
4925 result = PR_TRUE;
4929 break;
4931 case WM_LBUTTONDBLCLK:
4932 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4933 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4934 DispatchPendingEvents();
4935 break;
4937 case WM_MBUTTONDOWN:
4938 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4939 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4940 DispatchPendingEvents();
4941 break;
4943 case WM_MBUTTONUP:
4944 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4945 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4946 DispatchPendingEvents();
4947 break;
4949 case WM_MBUTTONDBLCLK:
4950 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4951 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4952 DispatchPendingEvents();
4953 break;
4955 case WM_NCMBUTTONDOWN:
4956 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam), PR_FALSE,
4957 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4958 DispatchPendingEvents();
4959 break;
4961 case WM_NCMBUTTONUP:
4962 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam), PR_FALSE,
4963 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4964 DispatchPendingEvents();
4965 break;
4967 case WM_NCMBUTTONDBLCLK:
4968 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam), PR_FALSE,
4969 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4970 DispatchPendingEvents();
4971 break;
4973 case WM_RBUTTONDOWN:
4974 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4975 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4976 DispatchPendingEvents();
4977 break;
4979 case WM_RBUTTONUP:
4980 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4981 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4982 DispatchPendingEvents();
4983 break;
4985 case WM_RBUTTONDBLCLK:
4986 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4987 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4988 DispatchPendingEvents();
4989 break;
4991 case WM_NCRBUTTONDOWN:
4992 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam),
4993 PR_FALSE, nsMouseEvent::eRightButton,
4994 MOUSE_INPUT_SOURCE());
4995 DispatchPendingEvents();
4996 break;
4998 case WM_NCRBUTTONUP:
4999 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam),
5000 PR_FALSE, nsMouseEvent::eRightButton,
5001 MOUSE_INPUT_SOURCE());
5002 DispatchPendingEvents();
5003 break;
5005 case WM_NCRBUTTONDBLCLK:
5006 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam),
5007 PR_FALSE, nsMouseEvent::eRightButton,
5008 MOUSE_INPUT_SOURCE());
5009 DispatchPendingEvents();
5010 break;
5012 case WM_APPCOMMAND:
5014 PRUint32 appCommand = GET_APPCOMMAND_LPARAM(lParam);
5016 switch (appCommand)
5018 case APPCOMMAND_BROWSER_BACKWARD:
5019 case APPCOMMAND_BROWSER_FORWARD:
5020 case APPCOMMAND_BROWSER_REFRESH:
5021 case APPCOMMAND_BROWSER_STOP:
5022 case APPCOMMAND_BROWSER_SEARCH:
5023 case APPCOMMAND_BROWSER_FAVORITES:
5024 case APPCOMMAND_BROWSER_HOME:
5025 DispatchCommandEvent(appCommand);
5026 // tell the driver that we handled the event
5027 *aRetValue = 1;
5028 result = PR_TRUE;
5029 break;
5031 // default = PR_FALSE - tell the driver that the event was not handled
5033 break;
5035 case WM_HSCROLL:
5036 case WM_VSCROLL:
5037 *aRetValue = 0;
5038 result = OnScroll(msg, wParam, lParam);
5039 break;
5041 // The WM_ACTIVATE event is fired when a window is raised or lowered,
5042 // and the loword of wParam specifies which. But we don't want to tell
5043 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
5044 // events are fired. Instead, set either the sJustGotActivate or
5045 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
5046 // events once the focus events arrive.
5047 case WM_ACTIVATE:
5048 if (mEventCallback) {
5049 PRInt32 fActive = LOWORD(wParam);
5051 #if defined(WINCE_HAVE_SOFTKB)
5052 if (mIsTopWidgetWindow && sSoftKeyboardState)
5053 nsWindowCE::ToggleSoftKB(mWnd, fActive);
5054 if (nsWindowCE::sShowSIPButton == TRI_FALSE && WA_INACTIVE != fActive) {
5055 HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL );
5056 if (hWndSIPB)
5057 ShowWindow(hWndSIPB, SW_HIDE);
5060 #endif
5062 if (WA_INACTIVE == fActive) {
5063 // when minimizing a window, the deactivation and focus events will
5064 // be fired in the reverse order. Instead, just dispatch
5065 // NS_DEACTIVATE right away.
5066 if (HIWORD(wParam))
5067 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5068 else
5069 sJustGotDeactivate = PR_TRUE;
5070 #ifndef WINCE
5071 if (mIsTopWidgetWindow)
5072 mLastKeyboardLayout = gKbdLayout.GetLayout();
5073 #endif
5075 } else {
5076 StopFlashing();
5078 sJustGotActivate = PR_TRUE;
5079 nsMouseEvent event(PR_TRUE, NS_MOUSE_ACTIVATE, this,
5080 nsMouseEvent::eReal);
5081 InitEvent(event);
5083 event.acceptActivation = PR_TRUE;
5085 DispatchWindowEvent(&event);
5086 #ifndef WINCE
5087 if (event.acceptActivation)
5088 *aRetValue = MA_ACTIVATE;
5089 else
5090 *aRetValue = MA_NOACTIVATE;
5092 if (sSwitchKeyboardLayout && mLastKeyboardLayout)
5093 ActivateKeyboardLayout(mLastKeyboardLayout, 0);
5094 #else
5095 *aRetValue = 0;
5096 #endif
5099 #ifdef WINCE_WINDOWS_MOBILE
5100 if (!gCheckForHTCApi && gHTCApiNavOpen == nsnull) {
5101 gCheckForHTCApi = PR_TRUE;
5103 HINSTANCE library = LoadLibrary(L"HTCAPI.dll");
5104 gHTCApiNavOpen = (HTCApiNavOpen) GetProcAddress(library, "HTCNavOpen");
5105 gHTCApiNavSetMode = (HTCApiNavSetMode) GetProcAddress(library ,"HTCNavSetMode");
5108 if (gHTCApiNavOpen != nsnull) {
5109 gHTCApiNavOpen(mWnd, 1 /* undocumented value */);
5111 if (gHTCApiNavSetMode != nsnull)
5112 gHTCApiNavSetMode ( mWnd, 4);
5113 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5115 #endif
5116 break;
5118 #ifndef WINCE
5119 case WM_MOUSEACTIVATE:
5120 if (mWindowType == eWindowType_popup) {
5121 // a popup with a parent owner should not be activated when clicked
5122 // but should still allow the mouse event to be fired, so the return
5123 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5124 // window, just use default processing so that the window is activated.
5125 HWND owner = ::GetWindow(mWnd, GW_OWNER);
5126 if (owner && owner == ::GetForegroundWindow()) {
5127 *aRetValue = MA_NOACTIVATE;
5128 result = PR_TRUE;
5131 break;
5133 case WM_WINDOWPOSCHANGING:
5135 LPWINDOWPOS info = (LPWINDOWPOS) lParam;
5136 OnWindowPosChanging(info);
5138 break;
5139 #endif
5141 case WM_SETFOCUS:
5142 if (sJustGotActivate) {
5143 result = DispatchFocusToTopLevelWindow(NS_ACTIVATE);
5146 #ifdef ACCESSIBILITY
5147 if (nsWindow::sIsAccessibilityOn) {
5148 // Create it for the first time so that it can start firing events
5149 nsAccessible *rootAccessible = GetRootAccessible();
5151 #endif
5153 #if defined(WINCE_HAVE_SOFTKB)
5155 // On Windows CE, we have a window that overlaps
5156 // the ISP button. In this case, we should always
5157 // try to hide it when we are activated
5159 nsIMEContext IMEContext(mWnd);
5160 // Open the IME
5161 ImmSetOpenStatus(IMEContext.get(), TRUE);
5163 #endif
5164 break;
5166 case WM_KILLFOCUS:
5167 #if defined(WINCE_HAVE_SOFTKB)
5169 nsIMEContext IMEContext(mWnd);
5170 ImmSetOpenStatus(IMEContext.get(), FALSE);
5172 #endif
5173 if (sJustGotDeactivate) {
5174 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5176 break;
5178 case WM_WINDOWPOSCHANGED:
5180 WINDOWPOS *wp = (LPWINDOWPOS)lParam;
5181 OnWindowPosChanged(wp, result);
5183 break;
5185 case WM_SETTINGCHANGE:
5186 #if !defined (WINCE_WINDOWS_MOBILE)
5187 getWheelInfo = PR_TRUE;
5188 #else
5189 switch (wParam) {
5190 case SPI_SETSIPINFO:
5191 case SPI_SETCURRENTIM:
5192 nsWindowCE::OnSoftKbSettingsChange(mWnd);
5193 break;
5194 case SETTINGCHANGE_RESET:
5195 if (mWindowType == eWindowType_invisible) {
5196 // The OS sees to get confused and think that the invisable window
5197 // is in the foreground after an orientation change. By actually
5198 // setting it to the foreground and hiding it, we set it strait.
5199 // See bug 514007 for details.
5200 SetForegroundWindow(mWnd);
5201 ShowWindow(mWnd, SW_HIDE);
5203 break;
5205 #endif
5206 OnSettingsChange(wParam, lParam);
5207 break;
5209 #ifndef WINCE
5210 case WM_INPUTLANGCHANGEREQUEST:
5211 *aRetValue = TRUE;
5212 result = PR_FALSE;
5213 break;
5215 case WM_INPUTLANGCHANGE:
5216 result = OnInputLangChange((HKL)lParam);
5217 break;
5218 #endif // WINCE
5220 case WM_DESTROYCLIPBOARD:
5222 nsIClipboard* clipboard;
5223 nsresult rv = CallGetService(kCClipboardCID, &clipboard);
5224 if(NS_SUCCEEDED(rv)) {
5225 clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
5226 NS_RELEASE(clipboard);
5229 break;
5231 #ifdef ACCESSIBILITY
5232 case WM_GETOBJECT:
5234 *aRetValue = 0;
5235 if (lParam == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
5236 nsAccessible *rootAccessible = GetRootAccessible(); // Held by a11y cache
5237 if (rootAccessible) {
5238 IAccessible *msaaAccessible = NULL;
5239 rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref
5240 if (msaaAccessible) {
5241 *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref
5242 msaaAccessible->Release(); // release extra addref
5243 result = PR_TRUE; // We handled the WM_GETOBJECT message
5248 #endif
5250 #ifndef WINCE
5251 case WM_SYSCOMMAND:
5252 // prevent Windows from trimming the working set. bug 76831
5253 if (!sTrimOnMinimize && wParam == SC_MINIMIZE) {
5254 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
5255 result = PR_TRUE;
5257 break;
5258 #endif
5261 #ifdef WINCE
5262 case WM_HIBERNATE:
5263 nsMemory::HeapMinimize(PR_TRUE);
5264 break;
5265 #endif
5267 case WM_MOUSEWHEEL:
5268 case WM_MOUSEHWHEEL:
5270 // If OnMouseWheel returns true, the event was forwarded directly to another
5271 // mozilla window message handler (ProcessMessage). In this case the return
5272 // value of the forwarded event is in 'result' which we should return immediately.
5273 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5274 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5275 // we should fall through.
5276 if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue))
5277 return result;
5279 break;
5281 #ifndef WINCE
5282 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5283 case WM_DWMCOMPOSITIONCHANGED:
5284 UpdateNonClientMargins();
5285 BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
5286 DispatchStandardEvent(NS_THEMECHANGED);
5287 UpdateGlass();
5288 Invalidate(PR_FALSE);
5289 break;
5290 #endif
5292 case WM_UPDATEUISTATE:
5294 // If the UI state has changed, fire an event so the UI updates the
5295 // keyboard cues based on the system setting and how the window was
5296 // opened. For example, a dialog opened via a keyboard press on a button
5297 // should enable cues, whereas the same dialog opened via a mouse click of
5298 // the button should not.
5299 PRInt32 action = LOWORD(wParam);
5300 if (action == UIS_SET || action == UIS_CLEAR) {
5301 nsUIStateChangeEvent event(PR_TRUE, NS_UISTATECHANGED, this);
5302 PRInt32 flags = HIWORD(wParam);
5303 if (flags & UISF_HIDEACCEL)
5304 event.showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5305 if (flags & UISF_HIDEFOCUS)
5306 event.showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5307 DispatchWindowEvent(&event);
5310 break;
5313 /* Gesture support events */
5314 case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
5315 // According to MS samples, this must be handled to enable
5316 // rotational support in multi-touch drivers.
5317 result = PR_TRUE;
5318 *aRetValue = TABLET_ROTATE_GESTURE_ENABLE;
5319 break;
5321 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5322 case WM_TOUCH:
5323 result = OnTouch(wParam, lParam);
5324 if (result) {
5325 *aRetValue = 0;
5327 break;
5328 #endif
5330 case WM_GESTURE:
5331 result = OnGesture(wParam, lParam);
5332 break;
5334 case WM_GESTURENOTIFY:
5336 if (mWindowType != eWindowType_invisible &&
5337 mWindowType != eWindowType_plugin) {
5338 // A GestureNotify event is dispatched to decide which single-finger panning
5339 // direction should be active (including none) and if pan feedback should
5340 // be displayed. Java and plugin windows can make their own calls.
5341 GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
5342 nsPointWin touchPoint;
5343 touchPoint = gestureinfo->ptsLocation;
5344 touchPoint.ScreenToClient(mWnd);
5345 nsGestureNotifyEvent gestureNotifyEvent(PR_TRUE, NS_GESTURENOTIFY_EVENT_START, this);
5346 gestureNotifyEvent.refPoint = touchPoint;
5347 nsEventStatus status;
5348 DispatchEvent(&gestureNotifyEvent, status);
5349 mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
5350 if (!mTouchWindow)
5351 mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
5353 result = PR_FALSE; //should always bubble to DefWindowProc
5355 break;
5356 #endif // !defined(WINCE)
5358 case WM_CLEAR:
5360 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_DELETE, this);
5361 DispatchWindowEvent(&command);
5362 result = PR_TRUE;
5364 break;
5366 case WM_CUT:
5368 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_CUT, this);
5369 DispatchWindowEvent(&command);
5370 result = PR_TRUE;
5372 break;
5374 case WM_COPY:
5376 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_COPY, this);
5377 DispatchWindowEvent(&command);
5378 result = PR_TRUE;
5380 break;
5382 case WM_PASTE:
5384 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE, this);
5385 DispatchWindowEvent(&command);
5386 result = PR_TRUE;
5388 break;
5390 #ifndef WINCE
5391 case EM_UNDO:
5393 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO, this);
5394 DispatchWindowEvent(&command);
5395 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5396 result = PR_TRUE;
5398 break;
5400 case EM_REDO:
5402 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO, this);
5403 DispatchWindowEvent(&command);
5404 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5405 result = PR_TRUE;
5407 break;
5409 case EM_CANPASTE:
5411 // Support EM_CANPASTE message only when wParam isn't specified or
5412 // is plain text format.
5413 if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
5414 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE,
5415 this, PR_TRUE);
5416 DispatchWindowEvent(&command);
5417 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5418 result = PR_TRUE;
5421 break;
5423 case EM_CANUNDO:
5425 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO,
5426 this, PR_TRUE);
5427 DispatchWindowEvent(&command);
5428 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5429 result = PR_TRUE;
5431 break;
5433 case EM_CANREDO:
5435 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO,
5436 this, PR_TRUE);
5437 DispatchWindowEvent(&command);
5438 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5439 result = PR_TRUE;
5441 break;
5442 #endif
5444 #ifdef WINCE_WINDOWS_MOBILE
5445 //HTC NAVIGATION WHEEL EVENT
5446 case WM_HTCNAV:
5448 int distance = wParam & 0x000000FF;
5449 if ( (wParam & 0x000000100) != 0) // Counter Clockwise
5450 distance *= -1;
5451 if (OnMouseWheel(WM_MOUSEWHEEL, MAKEWPARAM(0, distance),
5452 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN) / 2,
5453 GetSystemMetrics(SM_CYSCREEN) / 2),
5454 getWheelInfo, result, aRetValue))
5455 return result;
5457 break;
5458 #endif
5460 default:
5462 #ifdef NS_ENABLE_TSF
5463 if (msg == WM_USER_TSF_TEXTCHANGE) {
5464 nsTextStore::OnTextChangeMsg();
5466 #endif //NS_ENABLE_TSF
5467 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5468 if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
5469 SetHasTaskbarIconBeenCreated();
5470 #endif
5471 #ifdef MOZ_IPC
5472 if (msg == sOOPPPluginFocusEvent) {
5473 if (wParam == 1) {
5474 // With OOPP, the plugin window exists in another process and is a child of
5475 // this window. This window is a placeholder plugin window for the dom. We
5476 // receive this event when the child window receives focus. (sent from
5477 // PluginInstanceParent.cpp)
5478 ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
5479 } else {
5480 // WM_KILLFOCUS was received by the child process.
5481 if (sJustGotDeactivate) {
5482 DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5486 #endif
5488 break;
5491 //*aRetValue = result;
5492 if (mWnd) {
5493 return result;
5495 else {
5496 //Events which caused mWnd destruction and aren't consumed
5497 //will crash during the Windows default processing.
5498 return PR_TRUE;
5502 /**************************************************************
5504 * SECTION: Broadcast messaging
5506 * Broadcast messages to all windows.
5508 **************************************************************/
5510 // Enumerate all child windows sending aMsg to each of them
5511 BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg)
5513 WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
5514 if (winProc == &nsWindow::WindowProc) {
5515 // it's one of our windows so go ahead and send a message to it
5516 ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0);
5518 return TRUE;
5521 // Enumerate all top level windows specifying that the children of each
5522 // top level window should be enumerated. Do *not* send the message to
5523 // each top level window since it is assumed that the toolkit will send
5524 // aMsg to them directly.
5525 BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg)
5527 // Iterate each of aTopWindows child windows sending the aMsg
5528 // to each of them.
5529 #if !defined(WINCE)
5530 ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5531 #else
5532 nsWindowCE::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5533 #endif
5534 return TRUE;
5537 // This method is called from nsToolkit::WindowProc to forward global
5538 // messages which need to be dispatched to all child windows.
5539 void nsWindow::GlobalMsgWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
5541 switch (msg) {
5542 case WM_SYSCOLORCHANGE:
5543 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5544 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5545 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5546 // all child windows as well. When running in an embedded application
5547 // we may not receive a WM_SYSCOLORCHANGE message because the top
5548 // level window is owned by the embeddor.
5549 // System color changes are posted to top-level windows only.
5550 // The NS_SYSCOLORCHANGE must be dispatched to all child
5551 // windows as well.
5552 #if !defined(WINCE)
5553 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, msg);
5554 #endif
5555 break;
5559 /**************************************************************
5561 * SECTION: Event processing helpers
5563 * Special processing for certain event types and
5564 * synthesized events.
5566 **************************************************************/
5568 PRInt32
5569 nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
5571 // Calculations are done in screen coords
5572 RECT winRect;
5573 GetWindowRect(mWnd, &winRect);
5575 // hit return constants:
5576 // HTBORDER - non-resizable border
5577 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5578 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5579 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5580 // HTCAPTION - general title bar area
5581 // HTCLIENT - area considered the client
5582 // HTCLOSE - hovering over the close button
5583 // HTMAXBUTTON - maximize button
5584 // HTMINBUTTON - minimize button
5586 PRInt32 testResult = HTCLIENT;
5588 PRBool top = PR_FALSE;
5589 PRBool bottom = PR_FALSE;
5590 PRBool left = PR_FALSE;
5591 PRBool right = PR_FALSE;
5593 if (my >= winRect.top && my <=
5594 (winRect.top + mVertResizeMargin + (mCaptionHeight - mNonClientOffset.top)))
5595 top = PR_TRUE;
5596 else if (my <= winRect.bottom && my >= (winRect.bottom - mVertResizeMargin))
5597 bottom = PR_TRUE;
5599 if (mx >= winRect.left && mx <= (winRect.left + mHorResizeMargin))
5600 left = PR_TRUE;
5601 else if (mx <= winRect.right && mx >= (winRect.right - mHorResizeMargin))
5602 right = PR_TRUE;
5604 if (top) {
5605 testResult = HTTOP;
5606 if (left)
5607 testResult = HTTOPLEFT;
5608 else if (right)
5609 testResult = HTTOPRIGHT;
5610 } else if (bottom) {
5611 testResult = HTBOTTOM;
5612 if (left)
5613 testResult = HTBOTTOMLEFT;
5614 else if (right)
5615 testResult = HTBOTTOMRIGHT;
5616 } else {
5617 if (left)
5618 testResult = HTLEFT;
5619 if (right)
5620 testResult = HTRIGHT;
5623 PRBool contentOverlap = PR_TRUE;
5625 if (mSizeMode == nsSizeMode_Maximized) {
5626 // There's no HTTOP in maximized state (bug 575493)
5627 if (testResult == HTTOP) {
5628 testResult = HTCAPTION;
5630 } else {
5631 PRInt32 leftMargin = mNonClientMargins.left == -1 ? mHorResizeMargin : mNonClientMargins.left;
5632 PRInt32 rightMargin = mNonClientMargins.right == -1 ? mHorResizeMargin : mNonClientMargins.right;
5633 PRInt32 topMargin = mNonClientMargins.top == -1 ? mVertResizeMargin : mNonClientMargins.top;
5634 PRInt32 bottomMargin = mNonClientMargins.bottom == -1 ? mVertResizeMargin : mNonClientMargins.bottom;
5636 contentOverlap = mx >= winRect.left + leftMargin &&
5637 mx <= winRect.right - rightMargin &&
5638 my >= winRect.top + topMargin &&
5639 my <= winRect.bottom - bottomMargin;
5642 if (!mIsInMouseCapture &&
5643 contentOverlap &&
5644 (testResult == HTCLIENT ||
5645 testResult == HTTOP ||
5646 testResult == HTTOPLEFT ||
5647 testResult == HTCAPTION)) {
5648 LPARAM lParam = MAKELPARAM(mx, my);
5649 LPARAM lParamClient = lParamToClient(lParam);
5650 PRBool result = DispatchMouseEvent(NS_MOUSE_MOZHITTEST, 0, lParamClient,
5651 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5652 if (result) {
5653 // The mouse is over a blank area
5654 testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
5656 if (!mExitToNonClientArea) {
5657 // The first time the mouse pointer goes from client area to non-client area,
5658 // we don't want to miss that movement so we can interpret mouseout input.
5659 ::SendMessage(mWnd, WM_MOUSEMOVE, 0, lParamClient);
5660 mExitToNonClientArea = PR_TRUE;
5662 } else {
5663 // There's content over the mouse pointer. Set HTCLIENT
5664 // to possibly override a resizer border.
5665 testResult = HTCLIENT;
5669 return testResult;
5672 #ifndef WINCE
5673 void nsWindow::PostSleepWakeNotification(const char* aNotification)
5675 nsCOMPtr<nsIObserverService> observerService =
5676 mozilla::services::GetObserverService();
5677 if (observerService)
5678 observerService->NotifyObservers(nsnull, aNotification, nsnull);
5680 #endif
5682 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, PRBool *aEventDispatched)
5684 NS_PRECONDITION(aMsg.message == WM_CHAR || aMsg.message == WM_SYSCHAR,
5685 "message is not keydown event");
5686 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5687 ("%s charCode=%d scanCode=%d\n",
5688 aMsg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
5689 aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF));
5691 // These must be checked here too as a lone WM_CHAR could be received
5692 // if a child window didn't handle it (for example Alt+Space in a content window)
5693 nsModifierKeyState modKeyState;
5694 return OnChar(aMsg, modKeyState, aEventDispatched);
5697 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, PRBool *aEventDispatched)
5699 NS_PRECONDITION(aMsg.message == WM_KEYUP || aMsg.message == WM_SYSKEYUP,
5700 "message is not keydown event");
5701 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5702 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5703 "WM_SYSKEYUP" : "WM_KEYUP", aMsg.wParam));
5705 nsModifierKeyState modKeyState;
5707 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5708 // scan code. However, this breaks Alt+Num pad input.
5709 // MSDN states the following:
5710 // Typically, ToAscii performs the translation based on the
5711 // virtual-key code. In some cases, however, bit 15 of the
5712 // uScanCode parameter may be used to distinguish between a key
5713 // press and a key release. The scan code is used for
5714 // translating ALT+number key combinations.
5716 // ignore [shift+]alt+space so the OS can handle it
5717 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5718 IS_VK_DOWN(NS_VK_SPACE)) {
5719 return FALSE;
5722 if (!nsIMM32Handler::IsComposingOn(this) &&
5723 (aMsg.message != WM_KEYUP || aMsg.wParam != VK_MENU)) {
5724 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5725 // This helps avoid triggering the menu bar for ALT key accelerators used in
5726 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5727 // to switch back to Mozilla in Windows 95 and Windows 98
5728 return OnKeyUp(aMsg, modKeyState, aEventDispatched);
5731 return 0;
5734 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
5735 PRBool *aEventDispatched)
5737 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5738 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5739 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg.wParam));
5740 NS_PRECONDITION(aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN,
5741 "message is not keydown event");
5743 nsModifierKeyState modKeyState;
5745 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
5746 // scan code. However, this breaks Alt+Num pad input.
5747 // MSDN states the following:
5748 // Typically, ToAscii performs the translation based on the
5749 // virtual-key code. In some cases, however, bit 15 of the
5750 // uScanCode parameter may be used to distinguish between a key
5751 // press and a key release. The scan code is used for
5752 // translating ALT+number key combinations.
5754 // ignore [shift+]alt+space so the OS can handle it
5755 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5756 IS_VK_DOWN(NS_VK_SPACE))
5757 return FALSE;
5759 LRESULT result = 0;
5760 if (modKeyState.mIsAltDown && nsIMM32Handler::IsStatusChanged()) {
5761 nsIMM32Handler::NotifyEndStatusChange();
5762 } else if (!nsIMM32Handler::IsComposingOn(this)) {
5763 result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nsnull);
5766 #ifndef WINCE
5767 if (aMsg.wParam == VK_MENU ||
5768 (aMsg.wParam == VK_F10 && !modKeyState.mIsShiftDown)) {
5769 // We need to let Windows handle this keypress,
5770 // by returning PR_FALSE, if there's a native menu
5771 // bar somewhere in our containing window hierarchy.
5772 // Otherwise we handle the keypress and don't pass
5773 // it on to Windows, by returning PR_TRUE.
5774 PRBool hasNativeMenu = PR_FALSE;
5775 HWND hWnd = mWnd;
5776 while (hWnd) {
5777 if (::GetMenu(hWnd)) {
5778 hasNativeMenu = PR_TRUE;
5779 break;
5781 hWnd = ::GetParent(hWnd);
5783 result = !hasNativeMenu;
5785 #endif
5787 return result;
5790 nsresult
5791 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
5792 PRInt32 aNativeKeyCode,
5793 PRUint32 aModifierFlags,
5794 const nsAString& aCharacters,
5795 const nsAString& aUnmodifiedCharacters)
5797 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
5798 nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
5799 HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
5800 if (loadedLayout == NULL)
5801 return NS_ERROR_NOT_AVAILABLE;
5803 // Setup clean key state and load desired layout
5804 BYTE originalKbdState[256];
5805 ::GetKeyboardState(originalKbdState);
5806 BYTE kbdState[256];
5807 memset(kbdState, 0, sizeof(kbdState));
5808 // This changes the state of the keyboard for the current thread only,
5809 // and we'll restore it soon, so this should be OK.
5810 ::SetKeyboardState(kbdState);
5811 HKL oldLayout = gKbdLayout.GetLayout();
5812 gKbdLayout.LoadLayout(loadedLayout);
5814 nsAutoTArray<KeyPair,10> keySequence;
5815 SetupKeyModifiersSequence(&keySequence, aModifierFlags);
5816 NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
5817 "Native VK key code out of range");
5818 keySequence.AppendElement(KeyPair(aNativeKeyCode, 0));
5820 // Simulate the pressing of each modifier key and then the real key
5821 for (PRUint32 i = 0; i < keySequence.Length(); ++i) {
5822 PRUint8 key = keySequence[i].mGeneral;
5823 PRUint8 keySpecific = keySequence[i].mSpecific;
5824 kbdState[key] = 0x81; // key is down and toggled on if appropriate
5825 if (keySpecific) {
5826 kbdState[keySpecific] = 0x81;
5828 ::SetKeyboardState(kbdState);
5829 nsModifierKeyState modKeyState;
5830 MSG msg = InitMSG(WM_KEYDOWN, key, 0);
5831 if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
5832 UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
5833 gKbdLayout.GetLayout());
5834 nsFakeCharMessage fakeMsg = { aCharacters.CharAt(0), scanCode };
5835 OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
5836 } else {
5837 OnKeyDown(msg, modKeyState, nsnull, nsnull);
5840 for (PRUint32 i = keySequence.Length(); i > 0; --i) {
5841 PRUint8 key = keySequence[i - 1].mGeneral;
5842 PRUint8 keySpecific = keySequence[i - 1].mSpecific;
5843 kbdState[key] = 0; // key is up and toggled off if appropriate
5844 if (keySpecific) {
5845 kbdState[keySpecific] = 0;
5847 ::SetKeyboardState(kbdState);
5848 nsModifierKeyState modKeyState;
5849 MSG msg = InitMSG(WM_KEYUP, key, 0);
5850 OnKeyUp(msg, modKeyState, nsnull);
5853 // Restore old key state and layout
5854 ::SetKeyboardState(originalKbdState);
5855 gKbdLayout.LoadLayout(oldLayout);
5857 UnloadKeyboardLayout(loadedLayout);
5858 return NS_OK;
5859 #else //XXX: is there another way to do this?
5860 return NS_ERROR_NOT_IMPLEMENTED;
5861 #endif
5864 nsresult
5865 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
5866 PRUint32 aNativeMessage,
5867 PRUint32 aModifierFlags)
5869 #ifndef WINCE // I don't think WINCE supports SendInput
5870 RECT r;
5871 ::GetWindowRect(mWnd, &r);
5872 ::SetCursorPos(r.left + aPoint.x, r.top + aPoint.y);
5874 INPUT input;
5875 memset(&input, 0, sizeof(input));
5877 input.type = INPUT_MOUSE;
5878 input.mi.dwFlags = aNativeMessage;
5879 ::SendInput(1, &input, sizeof(INPUT));
5881 return NS_OK;
5882 #else
5883 return NS_ERROR_NOT_IMPLEMENTED;
5884 #endif
5887 /**************************************************************
5889 * SECTION: OnXXX message handlers
5891 * For message handlers that need to be broken out or
5892 * implemented in specific platform code.
5894 **************************************************************/
5896 BOOL nsWindow::OnInputLangChange(HKL aHKL)
5898 #ifdef KE_DEBUG
5899 printf("OnInputLanguageChange\n");
5900 #endif
5902 #ifndef WINCE
5903 gKbdLayout.LoadLayout(aHKL);
5904 #endif
5906 return PR_FALSE; // always pass to child window
5909 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5910 void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, PRBool& result)
5912 if (wp == nsnull)
5913 return;
5915 #ifdef WINSTATE_DEBUG_OUTPUT
5916 if (mWnd == GetTopLevelHWND(mWnd))
5917 printf("*** OnWindowPosChanged: [ top] ");
5918 else
5919 printf("*** OnWindowPosChanged: [child] ");
5920 printf("WINDOWPOS flags:");
5921 if (wp->flags & SWP_FRAMECHANGED)
5922 printf("SWP_FRAMECHANGED ");
5923 if (wp->flags & SWP_SHOWWINDOW)
5924 printf("SWP_SHOWWINDOW ");
5925 if (wp->flags & SWP_NOSIZE)
5926 printf("SWP_NOSIZE ");
5927 if (wp->flags & SWP_HIDEWINDOW)
5928 printf("SWP_HIDEWINDOW ");
5929 printf("\n");
5930 #endif
5932 // Handle window size mode changes
5933 if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
5934 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
5936 WINDOWPLACEMENT pl;
5937 pl.length = sizeof(pl);
5938 ::GetWindowPlacement(mWnd, &pl);
5940 if (pl.showCmd == SW_SHOWMAXIMIZED)
5941 event.mSizeMode = nsSizeMode_Maximized;
5942 else if (pl.showCmd == SW_SHOWMINIMIZED)
5943 event.mSizeMode = nsSizeMode_Minimized;
5944 else if (mFullscreenMode)
5945 event.mSizeMode = nsSizeMode_Fullscreen;
5946 else
5947 event.mSizeMode = nsSizeMode_Normal;
5949 // Windows has just changed the size mode of this window. The following
5950 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
5951 // set the min/max window state again or for nsSizeMode_Normal, call
5952 // SetWindow with a parameter of SW_RESTORE. There's no need however as
5953 // this window's mode has already changed. Updating mSizeMode here
5954 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
5955 // to window docking. (bug 489258)
5956 mSizeMode = event.mSizeMode;
5958 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
5959 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
5960 // prevents the working set from being trimmed but keeps the window active.
5961 // After the window is minimized, we need to do some touch up work on the
5962 // active window. (bugs 76831 & 499816)
5963 if (!sTrimOnMinimize && nsSizeMode_Minimized == event.mSizeMode)
5964 ActivateOtherWindowHelper(mWnd);
5966 #ifdef WINSTATE_DEBUG_OUTPUT
5967 switch (mSizeMode) {
5968 case nsSizeMode_Normal:
5969 printf("*** mSizeMode: nsSizeMode_Normal\n");
5970 break;
5971 case nsSizeMode_Minimized:
5972 printf("*** mSizeMode: nsSizeMode_Minimized\n");
5973 break;
5974 case nsSizeMode_Maximized:
5975 printf("*** mSizeMode: nsSizeMode_Maximized\n");
5976 break;
5977 default:
5978 printf("*** mSizeMode: ??????\n");
5979 break;
5981 #endif
5983 InitEvent(event);
5985 result = DispatchWindowEvent(&event);
5987 // Skip window size change events below on minimization.
5988 if (mSizeMode == nsSizeMode_Minimized)
5989 return;
5992 // Handle window size changes
5993 if (0 == (wp->flags & SWP_NOSIZE)) {
5994 RECT r;
5995 PRInt32 newWidth, newHeight;
5997 ::GetWindowRect(mWnd, &r);
5999 newWidth = r.right - r.left;
6000 newHeight = r.bottom - r.top;
6001 nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
6003 #ifdef MOZ_XUL
6004 if (eTransparencyTransparent == mTransparencyMode)
6005 ResizeTranslucentWindow(newWidth, newHeight);
6006 #endif
6008 if (newWidth > mLastSize.width)
6010 RECT drect;
6012 // getting wider
6013 drect.left = wp->x + mLastSize.width;
6014 drect.top = wp->y;
6015 drect.right = drect.left + (newWidth - mLastSize.width);
6016 drect.bottom = drect.top + newHeight;
6018 ::RedrawWindow(mWnd, &drect, NULL,
6019 RDW_INVALIDATE |
6020 RDW_NOERASE |
6021 RDW_NOINTERNALPAINT |
6022 RDW_ERASENOW |
6023 RDW_ALLCHILDREN);
6025 if (newHeight > mLastSize.height)
6027 RECT drect;
6029 // getting taller
6030 drect.left = wp->x;
6031 drect.top = wp->y + mLastSize.height;
6032 drect.right = drect.left + newWidth;
6033 drect.bottom = drect.top + (newHeight - mLastSize.height);
6035 ::RedrawWindow(mWnd, &drect, NULL,
6036 RDW_INVALIDATE |
6037 RDW_NOERASE |
6038 RDW_NOINTERNALPAINT |
6039 RDW_ERASENOW |
6040 RDW_ALLCHILDREN);
6043 mBounds.width = newWidth;
6044 mBounds.height = newHeight;
6045 mLastSize.width = newWidth;
6046 mLastSize.height = newHeight;
6048 #ifdef WINSTATE_DEBUG_OUTPUT
6049 printf("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, newWidth, newHeight);
6050 #endif
6052 // If a maximized window is resized, recalculate the non-client margins and
6053 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
6054 // work properly.
6055 if (mSizeMode == nsSizeMode_Maximized) {
6056 if (UpdateNonClientMargins(nsSizeMode_Maximized, PR_TRUE)) {
6057 // gecko resize event already sent by UpdateNonClientMargins.
6058 result = PR_TRUE;
6059 return;
6063 // Recalculate the width and height based on the client area for gecko events.
6064 if (::GetClientRect(mWnd, &r)) {
6065 rect.width = r.right - r.left;
6066 rect.height = r.bottom - r.top;
6069 // Send a gecko resize event
6070 result = OnResize(rect);
6074 // static
6075 void nsWindow::ActivateOtherWindowHelper(HWND aWnd)
6077 // Find the next window that is enabled, visible, and not minimized.
6078 HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT);
6079 while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) ||
6080 ::IsIconic(hwndBelow))) {
6081 hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT);
6084 // Push ourselves to the bottom of the stack, then activate the
6085 // next window.
6086 ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0,
6087 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
6088 if (hwndBelow)
6089 ::SetForegroundWindow(hwndBelow);
6091 // Play the minimize sound while we're here, since that is also
6092 // forgotten when we use SW_SHOWMINIMIZED.
6093 ::PlaySoundW(L"Minimize", nsnull, SND_ALIAS | SND_NODEFAULT | SND_ASYNC);
6095 #endif // !defined(WINCE)
6097 #if !defined(WINCE)
6098 void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info)
6100 // Update non-client margins if the frame size is changing, and let the
6101 // browser know we are changing size modes, so alternative css can kick in.
6102 // If we're going into fullscreen mode, ignore this, since it'll reset
6103 // margins to normal mode.
6104 if (info->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
6105 WINDOWPLACEMENT pl;
6106 pl.length = sizeof(pl);
6107 ::GetWindowPlacement(mWnd, &pl);
6108 PRInt32 sizeMode;
6109 if (pl.showCmd == SW_SHOWMAXIMIZED)
6110 sizeMode = nsSizeMode_Maximized;
6111 else if (pl.showCmd == SW_SHOWMINIMIZED)
6112 sizeMode = nsSizeMode_Minimized;
6113 else if (mFullscreenMode)
6114 sizeMode = nsSizeMode_Fullscreen;
6115 else
6116 sizeMode = nsSizeMode_Normal;
6118 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
6120 InitEvent(event);
6121 event.mSizeMode = static_cast<nsSizeMode>(sizeMode);
6122 DispatchWindowEvent(&event);
6124 UpdateNonClientMargins(sizeMode, PR_FALSE);
6127 // enforce local z-order rules
6128 if (!(info->flags & SWP_NOZORDER)) {
6129 HWND hwndAfter = info->hwndInsertAfter;
6131 nsZLevelEvent event(PR_TRUE, NS_SETZLEVEL, this);
6132 nsWindow *aboveWindow = 0;
6134 InitEvent(event);
6136 if (hwndAfter == HWND_BOTTOM)
6137 event.mPlacement = nsWindowZBottom;
6138 else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
6139 event.mPlacement = nsWindowZTop;
6140 else {
6141 event.mPlacement = nsWindowZRelative;
6142 aboveWindow = GetNSWindowPtr(hwndAfter);
6144 event.mReqBelow = aboveWindow;
6145 event.mActualBelow = nsnull;
6147 event.mImmediate = PR_FALSE;
6148 event.mAdjusted = PR_FALSE;
6149 DispatchWindowEvent(&event);
6151 if (event.mAdjusted) {
6152 if (event.mPlacement == nsWindowZBottom)
6153 info->hwndInsertAfter = HWND_BOTTOM;
6154 else if (event.mPlacement == nsWindowZTop)
6155 info->hwndInsertAfter = HWND_TOP;
6156 else {
6157 info->hwndInsertAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
6160 NS_IF_RELEASE(event.mActualBelow);
6162 // prevent rude external programs from making hidden window visible
6163 if (mWindowType == eWindowType_invisible)
6164 info->flags &= ~SWP_SHOWWINDOW;
6166 #endif
6168 void nsWindow::UserActivity()
6170 // Check if we have the idle service, if not we try to get it.
6171 if (!mIdleService) {
6172 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
6175 // Check that we now have the idle service.
6176 if (mIdleService) {
6177 mIdleService->ResetIdleTimeOut();
6181 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6182 PRBool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam)
6184 PRUint32 cInputs = LOWORD(wParam);
6185 PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
6187 if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) {
6188 for (PRUint32 i = 0; i < cInputs; i++) {
6189 PRUint32 msg;
6190 if (pInputs[i].dwFlags & TOUCHEVENTF_MOVE) {
6191 msg = NS_MOZTOUCH_MOVE;
6192 } else if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) {
6193 msg = NS_MOZTOUCH_DOWN;
6194 } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) {
6195 msg = NS_MOZTOUCH_UP;
6196 } else {
6197 continue;
6200 nsPointWin touchPoint;
6201 touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
6202 touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
6203 touchPoint.ScreenToClient(mWnd);
6205 nsMozTouchEvent touchEvent(PR_TRUE, msg, this, pInputs[i].dwID);
6206 touchEvent.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6207 touchEvent.refPoint = touchPoint;
6209 nsEventStatus status;
6210 DispatchEvent(&touchEvent, status);
6214 delete [] pInputs;
6215 mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam);
6216 return PR_TRUE;
6218 #endif
6220 // Gesture event processing. Handles WM_GESTURE events.
6221 #if !defined(WINCE)
6222 PRBool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
6224 // Treatment for pan events which translate into scroll events:
6225 if (mGesture.IsPanEvent(lParam)) {
6226 nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
6228 if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
6229 return PR_FALSE; // ignore
6231 nsEventStatus status;
6233 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6234 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6235 event.isMeta = PR_FALSE;
6236 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6237 event.button = 0;
6238 event.time = ::GetMessageTime();
6239 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6241 PRBool endFeedback = PR_TRUE;
6243 PRInt32 scrollOverflowX = 0;
6244 PRInt32 scrollOverflowY = 0;
6246 if (mGesture.PanDeltaToPixelScrollX(event)) {
6247 DispatchEvent(&event, status);
6248 scrollOverflowX = event.scrollOverflow;
6251 if (mGesture.PanDeltaToPixelScrollY(event)) {
6252 DispatchEvent(&event, status);
6253 scrollOverflowY = event.scrollOverflow;
6256 if (mDisplayPanFeedback) {
6257 mGesture.UpdatePanFeedbackX(mWnd, scrollOverflowX, endFeedback);
6258 mGesture.UpdatePanFeedbackY(mWnd, scrollOverflowY, endFeedback);
6259 mGesture.PanFeedbackFinalize(mWnd, endFeedback);
6262 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6264 return PR_TRUE;
6267 // Other gestures translate into simple gesture events:
6268 nsSimpleGestureEvent event(PR_TRUE, 0, this, 0, 0.0);
6269 if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) {
6270 return PR_FALSE; // fall through to DefWndProc
6273 // Polish up and send off the new event
6274 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6275 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6276 event.isMeta = PR_FALSE;
6277 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6278 event.button = 0;
6279 event.time = ::GetMessageTime();
6280 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6282 nsEventStatus status;
6283 DispatchEvent(&event, status);
6284 if (status == nsEventStatus_eIgnore) {
6285 return PR_FALSE; // Ignored, fall through
6288 // Only close this if we process and return true.
6289 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6291 return PR_TRUE; // Handled
6293 #endif // !defined(WINCE)
6295 #if !defined(WINCE)
6296 PRUint16 nsWindow::GetMouseInputSource()
6298 PRUint16 inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE;
6299 LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
6300 if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
6301 inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ?
6302 PRUint16(nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH) : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN;
6304 return inputSource;
6306 #endif
6308 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6309 * within the message case block. If returning true result should be returned
6310 * immediately (no more processing).
6312 PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue)
6314 // Handle both flavors of mouse wheel events.
6315 static int iDeltaPerLine, iDeltaPerChar;
6316 static ULONG ulScrollLines, ulScrollChars = 1;
6317 static int currentVDelta, currentHDelta;
6318 static HWND currentWindow = 0;
6320 PRBool isVertical = msg == WM_MOUSEWHEEL;
6322 // Get mouse wheel metrics (but only once).
6323 if (getWheelInfo) {
6324 getWheelInfo = PR_FALSE;
6326 SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
6328 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6329 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6331 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6332 // the mouse driver wants a page scroll. The docs state that
6333 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6334 // since some mouse drivers use an arbitrary large number instead,
6335 // we have to handle that as well.
6337 iDeltaPerLine = 0;
6338 if (ulScrollLines) {
6339 if (ulScrollLines <= WHEEL_DELTA) {
6340 iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
6341 } else {
6342 ulScrollLines = WHEEL_PAGESCROLL;
6346 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
6347 &ulScrollChars, 0)) {
6348 // Note that we may always fail to get the value before Win Vista.
6349 ulScrollChars = 1;
6352 iDeltaPerChar = 0;
6353 if (ulScrollChars) {
6354 if (ulScrollChars <= WHEEL_DELTA) {
6355 iDeltaPerChar = WHEEL_DELTA / ulScrollChars;
6356 } else {
6357 ulScrollChars = WHEEL_PAGESCROLL;
6362 if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) ||
6363 (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar))
6364 return PR_FALSE; // break
6366 // The mousewheel event will be dispatched to the toplevel
6367 // window. We need to give it to the child window
6368 PRBool quit;
6369 if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit))
6370 return quit; // return immediately if its not our window
6372 // We should cancel the surplus delta if the current window is not
6373 // same as previous.
6374 if (currentWindow != mWnd) {
6375 currentVDelta = 0;
6376 currentHDelta = 0;
6377 currentWindow = mWnd;
6380 nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
6381 scrollEvent.delta = 0;
6382 if (isVertical) {
6383 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
6384 if (ulScrollLines == WHEEL_PAGESCROLL) {
6385 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6386 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1;
6387 } else {
6388 currentVDelta -= (short) HIWORD (wParam);
6389 if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
6390 scrollEvent.delta = currentVDelta / iDeltaPerLine;
6391 currentVDelta %= iDeltaPerLine;
6394 } else {
6395 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
6396 if (ulScrollChars == WHEEL_PAGESCROLL) {
6397 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6398 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1;
6399 } else {
6400 currentHDelta += (short) HIWORD (wParam);
6401 if (PR_ABS(currentHDelta) >= iDeltaPerChar) {
6402 scrollEvent.delta = currentHDelta / iDeltaPerChar;
6403 currentHDelta %= iDeltaPerChar;
6408 if (!scrollEvent.delta) {
6409 // We store the wheel delta, and it will be used next wheel message, so,
6410 // we consume this message actually. We shouldn't call next wndproc.
6411 result = PR_TRUE;
6412 return PR_FALSE; // break
6415 #ifdef MOZ_IPC
6416 // The event may go to a plug-in which already dispatched this message.
6417 // Then, the event can cause deadlock. We should unlock the sender here.
6418 ::ReplyMessage(isVertical ? 0 : TRUE);
6419 #endif
6421 scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6422 scrollEvent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6423 scrollEvent.isMeta = PR_FALSE;
6424 scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT);
6425 InitEvent(scrollEvent);
6426 if (nsnull != mEventCallback) {
6427 result = DispatchWindowEvent(&scrollEvent);
6429 // Note that we should return zero if we process WM_MOUSEWHEEL.
6430 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6432 if (result)
6433 *aRetValue = isVertical ? 0 : TRUE;
6435 return PR_FALSE; // break;
6438 static PRBool
6439 StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,
6440 const PRUnichar* aChars2, const PRUint32 aNumChars2)
6442 if (aNumChars1 != aNumChars2)
6443 return PR_FALSE;
6445 nsCaseInsensitiveStringComparator comp;
6446 return comp(aChars1, aChars2, aNumChars1) == 0;
6449 UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
6451 #ifndef WINCE
6452 switch (aNativeKeyCode) {
6453 case VK_OEM_1: return NS_VK_SEMICOLON; // 0xBA, For the US standard keyboard, the ';:' key
6454 case VK_OEM_PLUS: return NS_VK_ADD; // 0xBB, For any country/region, the '+' key
6455 case VK_OEM_MINUS: return NS_VK_SUBTRACT; // 0xBD, For any country/region, the '-' key
6457 #endif
6459 return aNativeKeyCode;
6463 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6464 * WM_CHAR messages for processing. During testing we don't want to
6465 * mess with the real message queue. Instead we pass a
6466 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6467 * that as if it was in the message queue, and refrain from actually
6468 * looking at or touching the message queue.
6470 LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
6471 nsModifierKeyState &aModKeyState,
6472 PRBool *aEventDispatched,
6473 nsFakeCharMessage* aFakeCharMessage)
6475 UINT virtualKeyCode = aMsg.wParam;
6477 #ifndef WINCE
6478 gKbdLayout.OnKeyDown (virtualKeyCode);
6479 #endif
6481 // Use only DOMKeyCode for XP processing.
6482 // Use aVirtualKeyCode for gKbdLayout and native processing.
6483 UINT DOMKeyCode = nsIMM32Handler::IsComposingOn(this) ?
6484 virtualKeyCode : MapFromNativeToDOM(virtualKeyCode);
6486 #ifdef DEBUG
6487 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6488 #endif
6490 PRBool noDefault =
6491 DispatchKeyEvent(NS_KEY_DOWN, 0, nsnull, DOMKeyCode, &aMsg, aModKeyState);
6492 if (aEventDispatched)
6493 *aEventDispatched = PR_TRUE;
6495 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6496 // for almost all keys
6497 switch (DOMKeyCode) {
6498 case NS_VK_SHIFT:
6499 case NS_VK_CONTROL:
6500 case NS_VK_ALT:
6501 case NS_VK_CAPS_LOCK:
6502 case NS_VK_NUM_LOCK:
6503 case NS_VK_SCROLL_LOCK: return noDefault;
6506 PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
6507 MSG msg;
6508 BOOL gotMsg = aFakeCharMessage ||
6509 ::PeekMessageW(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6510 // Enter and backspace are always handled here to avoid for example the
6511 // confusion between ctrl-enter and ctrl-J.
6512 if (DOMKeyCode == NS_VK_RETURN || DOMKeyCode == NS_VK_BACK ||
6513 ((aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)
6514 #ifdef WINCE
6516 #else
6517 && !gKbdLayout.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
6518 #endif
6520 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6521 // They can be more than one because of:
6522 // * Dead-keys not pairing with base character
6523 // * Some keyboard layouts may map up to 4 characters to the single key
6524 PRBool anyCharMessagesRemoved = PR_FALSE;
6526 if (aFakeCharMessage) {
6527 anyCharMessagesRemoved = PR_TRUE;
6528 } else {
6529 while (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR))
6531 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6532 ("%s charCode=%d scanCode=%d\n", msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6533 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6534 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST, WM_KEYLAST);
6535 anyCharMessagesRemoved = PR_TRUE;
6537 gotMsg = ::PeekMessageW (&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6541 if (!anyCharMessagesRemoved && DOMKeyCode == NS_VK_BACK &&
6542 nsIMM32Handler::IsDoingKakuteiUndo(mWnd)) {
6543 NS_ASSERTION(!aFakeCharMessage,
6544 "We shouldn't be touching the real msg queue");
6545 RemoveMessageAndDispatchPluginEvent(WM_CHAR, WM_CHAR);
6548 else if (gotMsg &&
6549 (aFakeCharMessage ||
6550 msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
6551 if (aFakeCharMessage)
6552 return OnCharRaw(aFakeCharMessage->mCharCode,
6553 aFakeCharMessage->mScanCode, aModKeyState, extraFlags);
6555 // If prevent default set for keydown, do same for keypress
6556 ::GetMessageW(&msg, mWnd, msg.message, msg.message);
6558 if (msg.message == WM_DEADCHAR) {
6559 if (!PluginHasFocus())
6560 return PR_FALSE;
6562 // We need to send the removed message to focused plug-in.
6563 DispatchPluginEvent(msg);
6564 return noDefault;
6567 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6568 ("%s charCode=%d scanCode=%d\n",
6569 msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6570 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6572 BOOL result = OnChar(msg, aModKeyState, nsnull, extraFlags);
6573 // If a syschar keypress wasn't processed, Windows may want to
6574 // handle it to activate a native menu.
6575 if (!result && msg.message == WM_SYSCHAR)
6576 ::DefWindowProcW(mWnd, msg.message, msg.wParam, msg.lParam);
6577 return result;
6579 #ifndef WINCE
6580 else if (!aModKeyState.mIsControlDown && !aModKeyState.mIsAltDown &&
6581 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode) ||
6582 KeyboardLayout::IsNumpadKey(virtualKeyCode)))
6584 // If this is simple KeyDown event but next message is not WM_CHAR,
6585 // this event may not input text, so we should ignore this event.
6586 // See bug 314130.
6587 return PluginHasFocus() && noDefault;
6590 if (gKbdLayout.IsDeadKey ())
6591 return PluginHasFocus() && noDefault;
6593 PRUint8 shiftStates[5];
6594 PRUnichar uniChars[5];
6595 PRUnichar shiftedChars[5] = {0, 0, 0, 0, 0};
6596 PRUnichar unshiftedChars[5] = {0, 0, 0, 0, 0};
6597 PRUnichar shiftedLatinChar = 0;
6598 PRUnichar unshiftedLatinChar = 0;
6599 PRUint32 numOfUniChars = 0;
6600 PRUint32 numOfShiftedChars = 0;
6601 PRUint32 numOfUnshiftedChars = 0;
6602 PRUint32 numOfShiftStates = 0;
6604 switch (virtualKeyCode) {
6605 // keys to be sent as characters
6606 case VK_ADD: uniChars [0] = '+'; numOfUniChars = 1; break;
6607 case VK_SUBTRACT: uniChars [0] = '-'; numOfUniChars = 1; break;
6608 case VK_DIVIDE: uniChars [0] = '/'; numOfUniChars = 1; break;
6609 case VK_MULTIPLY: uniChars [0] = '*'; numOfUniChars = 1; break;
6610 case VK_NUMPAD0:
6611 case VK_NUMPAD1:
6612 case VK_NUMPAD2:
6613 case VK_NUMPAD3:
6614 case VK_NUMPAD4:
6615 case VK_NUMPAD5:
6616 case VK_NUMPAD6:
6617 case VK_NUMPAD7:
6618 case VK_NUMPAD8:
6619 case VK_NUMPAD9:
6620 uniChars [0] = virtualKeyCode - VK_NUMPAD0 + '0';
6621 numOfUniChars = 1;
6622 break;
6623 default:
6624 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
6625 numOfUniChars = numOfShiftStates =
6626 gKbdLayout.GetUniChars(uniChars, shiftStates,
6627 NS_ARRAY_LENGTH(uniChars));
6630 if (aModKeyState.mIsControlDown ^ aModKeyState.mIsAltDown) {
6631 PRUint8 capsLockState = (::GetKeyState(VK_CAPITAL) & 1) ? eCapsLock : 0;
6632 numOfUnshiftedChars =
6633 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode, capsLockState,
6634 unshiftedChars, NS_ARRAY_LENGTH(unshiftedChars));
6635 numOfShiftedChars =
6636 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode,
6637 capsLockState | eShift,
6638 shiftedChars, NS_ARRAY_LENGTH(shiftedChars));
6640 // The current keyboard cannot input alphabets or numerics,
6641 // we should append them for Shortcut/Access keys.
6642 // E.g., for Cyrillic keyboard layout.
6643 if (NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z) {
6644 shiftedLatinChar = unshiftedLatinChar = DOMKeyCode;
6645 if (capsLockState)
6646 shiftedLatinChar += 0x20;
6647 else
6648 unshiftedLatinChar += 0x20;
6649 if (unshiftedLatinChar == unshiftedChars[0] &&
6650 shiftedLatinChar == shiftedChars[0]) {
6651 shiftedLatinChar = unshiftedLatinChar = 0;
6653 } else {
6654 PRUint16 ch = 0;
6655 if (NS_VK_0 <= DOMKeyCode && DOMKeyCode <= NS_VK_9) {
6656 ch = DOMKeyCode;
6657 } else {
6658 switch (virtualKeyCode) {
6659 case VK_OEM_PLUS: ch = '+'; break;
6660 case VK_OEM_MINUS: ch = '-'; break;
6663 if (ch && unshiftedChars[0] != ch && shiftedChars[0] != ch) {
6664 // Windows has assigned a virtual key code to the key even though
6665 // the character can't be produced with this key. That probably
6666 // means the character can't be produced with any key in the
6667 // current layout and so the assignment is based on a QWERTY
6668 // layout. Append this code so that users can access the shortcut.
6669 unshiftedLatinChar = ch;
6673 // If the charCode is not ASCII character, we should replace the
6674 // charCode with ASCII character only when Ctrl is pressed.
6675 // But don't replace the charCode when the charCode is not same as
6676 // unmodified characters. In such case, Ctrl is sometimes used for a
6677 // part of character inputting key combination like Shift.
6678 if (aModKeyState.mIsControlDown) {
6679 PRUint8 currentState = eCtrl;
6680 if (aModKeyState.mIsShiftDown)
6681 currentState |= eShift;
6683 PRUint32 ch =
6684 aModKeyState.mIsShiftDown ? shiftedLatinChar : unshiftedLatinChar;
6685 if (ch &&
6686 (numOfUniChars == 0 ||
6687 StringCaseInsensitiveEquals(uniChars, numOfUniChars,
6688 aModKeyState.mIsShiftDown ? shiftedChars : unshiftedChars,
6689 aModKeyState.mIsShiftDown ? numOfShiftedChars :
6690 numOfUnshiftedChars))) {
6691 numOfUniChars = numOfShiftStates = 1;
6692 uniChars[0] = ch;
6693 shiftStates[0] = currentState;
6699 if (numOfUniChars > 0 || numOfShiftedChars > 0 || numOfUnshiftedChars > 0) {
6700 PRUint32 num = PR_MAX(numOfUniChars,
6701 PR_MAX(numOfShiftedChars, numOfUnshiftedChars));
6702 PRUint32 skipUniChars = num - numOfUniChars;
6703 PRUint32 skipShiftedChars = num - numOfShiftedChars;
6704 PRUint32 skipUnshiftedChars = num - numOfUnshiftedChars;
6705 UINT keyCode = numOfUniChars == 0 ? DOMKeyCode : 0;
6706 for (PRUint32 cnt = 0; cnt < num; cnt++) {
6707 PRUint16 uniChar, shiftedChar, unshiftedChar;
6708 uniChar = shiftedChar = unshiftedChar = 0;
6709 if (skipUniChars <= cnt) {
6710 if (cnt - skipUniChars < numOfShiftStates) {
6711 // If key in combination with Alt and/or Ctrl produces a different
6712 // character than without them then do not report these flags
6713 // because it is separate keyboard layout shift state. If dead-key
6714 // and base character does not produce a valid composite character
6715 // then both produced dead-key character and following base
6716 // character may have different modifier flags, too.
6717 aModKeyState.mIsShiftDown =
6718 (shiftStates[cnt - skipUniChars] & eShift) != 0;
6719 aModKeyState.mIsControlDown =
6720 (shiftStates[cnt - skipUniChars] & eCtrl) != 0;
6721 aModKeyState.mIsAltDown =
6722 (shiftStates[cnt - skipUniChars] & eAlt) != 0;
6724 uniChar = uniChars[cnt - skipUniChars];
6726 if (skipShiftedChars <= cnt)
6727 shiftedChar = shiftedChars[cnt - skipShiftedChars];
6728 if (skipUnshiftedChars <= cnt)
6729 unshiftedChar = unshiftedChars[cnt - skipUnshiftedChars];
6730 nsAutoTArray<nsAlternativeCharCode, 5> altArray;
6732 if (shiftedChar || unshiftedChar) {
6733 nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
6734 altArray.AppendElement(chars);
6736 if (cnt == num - 1 && (unshiftedLatinChar || shiftedLatinChar)) {
6737 nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
6738 altArray.AppendElement(chars);
6741 DispatchKeyEvent(NS_KEY_PRESS, uniChar, &altArray,
6742 keyCode, nsnull, aModKeyState, extraFlags);
6744 } else {
6745 DispatchKeyEvent(NS_KEY_PRESS, 0, nsnull, DOMKeyCode, nsnull, aModKeyState,
6746 extraFlags);
6748 #else
6750 UINT unichar = ::MapVirtualKey(virtualKeyCode, MAPVK_VK_TO_CHAR);
6751 // Check for dead characters or no mapping
6752 if (unichar & 0x80) {
6753 return noDefault;
6755 DispatchKeyEvent(NS_KEY_PRESS, unichar, nsnull, DOMKeyCode, nsnull, aModKeyState,
6756 extraFlags);
6758 #endif
6760 return noDefault;
6763 // OnKeyUp
6764 LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
6765 nsModifierKeyState &aModKeyState,
6766 PRBool *aEventDispatched)
6768 UINT virtualKeyCode = aMsg.wParam;
6770 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6771 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
6773 if (!nsIMM32Handler::IsComposingOn(this)) {
6774 virtualKeyCode = MapFromNativeToDOM(virtualKeyCode);
6777 if (aEventDispatched)
6778 *aEventDispatched = PR_TRUE;
6779 return DispatchKeyEvent(NS_KEY_UP, 0, nsnull, virtualKeyCode, &aMsg,
6780 aModKeyState);
6783 // OnChar
6784 LRESULT nsWindow::OnChar(const MSG &aMsg, nsModifierKeyState &aModKeyState,
6785 PRBool *aEventDispatched, PRUint32 aFlags)
6787 return OnCharRaw(aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF, aModKeyState,
6788 aFlags, &aMsg, aEventDispatched);
6791 // OnCharRaw
6792 LRESULT nsWindow::OnCharRaw(UINT charCode, UINT aScanCode,
6793 nsModifierKeyState &aModKeyState, PRUint32 aFlags,
6794 const MSG *aMsg, PRBool *aEventDispatched)
6796 // ignore [shift+]alt+space so the OS can handle it
6797 if (aModKeyState.mIsAltDown && !aModKeyState.mIsControlDown &&
6798 IS_VK_DOWN(NS_VK_SPACE)) {
6799 return FALSE;
6802 // Ignore Ctrl+Enter (bug 318235)
6803 if (aModKeyState.mIsControlDown && charCode == 0xA) {
6804 return FALSE;
6807 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
6808 PRBool saveIsAltDown = aModKeyState.mIsAltDown;
6809 PRBool saveIsControlDown = aModKeyState.mIsControlDown;
6810 if (aModKeyState.mIsAltDown && aModKeyState.mIsControlDown)
6811 aModKeyState.mIsAltDown = aModKeyState.mIsControlDown = PR_FALSE;
6813 wchar_t uniChar;
6815 if (nsIMM32Handler::IsComposingOn(this)) {
6816 ResetInputState();
6819 if (aModKeyState.mIsControlDown && charCode <= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
6820 // need to account for shift here. bug 16486
6821 if (aModKeyState.mIsShiftDown)
6822 uniChar = charCode - 1 + 'A';
6823 else
6824 uniChar = charCode - 1 + 'a';
6825 charCode = 0;
6827 else if (aModKeyState.mIsControlDown && charCode <= 0x1F) {
6828 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
6829 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
6830 // for some reason the keypress handler need to have the uniChar code set
6831 // with the addition of a upper case A not the lower case.
6832 uniChar = charCode - 1 + 'A';
6833 charCode = 0;
6834 } else { // 0x20 - SPACE, 0x3D - EQUALS
6835 if (charCode < 0x20 || (charCode == 0x3D && aModKeyState.mIsControlDown)) {
6836 uniChar = 0;
6837 } else {
6838 uniChar = charCode;
6839 charCode = 0;
6843 // Keep the characters unshifted for shortcuts and accesskeys and make sure
6844 // that numbers are always passed as such (among others: bugs 50255 and 351310)
6845 if (uniChar && (aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)) {
6846 UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK,
6847 gKbdLayout.GetLayout());
6848 UINT unshiftedCharCode =
6849 virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
6850 aModKeyState.mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode,
6851 MAPVK_VK_TO_CHAR,
6852 gKbdLayout.GetLayout()) : 0;
6853 // ignore diacritics (top bit set) and key mapping errors (char code 0)
6854 if ((INT)unshiftedCharCode > 0)
6855 uniChar = unshiftedCharCode;
6858 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
6859 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
6860 // pressed too.
6861 if (!aModKeyState.mIsShiftDown && (saveIsAltDown || saveIsControlDown)) {
6862 uniChar = towlower(uniChar);
6865 PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, nsnull,
6866 charCode, aMsg, aModKeyState, aFlags);
6867 if (aEventDispatched)
6868 *aEventDispatched = PR_TRUE;
6869 aModKeyState.mIsAltDown = saveIsAltDown;
6870 aModKeyState.mIsControlDown = saveIsControlDown;
6871 return result;
6874 void
6875 nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers)
6877 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierKeyMap); ++i) {
6878 const PRUint32* map = sModifierKeyMap[i];
6879 if (aModifiers & map[0]) {
6880 aArray->AppendElement(KeyPair(map[1], map[2]));
6885 nsresult
6886 nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
6888 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
6889 // here, if that helps in some situations. So far I haven't seen a
6890 // need.
6891 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
6892 const Configuration& configuration = aConfigurations[i];
6893 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
6894 NS_ASSERTION(w->GetParent() == this,
6895 "Configured widget is not a child");
6896 #ifdef WINCE
6897 // MSDN says we should do on WinCE this before moving or resizing the window
6898 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
6899 // We put the region back just below, anyway.
6900 ::SetWindowRgn(w->mWnd, NULL, TRUE);
6901 #endif
6902 nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_TRUE);
6903 NS_ENSURE_SUCCESS(rv, rv);
6904 nsIntRect bounds;
6905 w->GetBounds(bounds);
6906 if (bounds.Size() != configuration.mBounds.Size()) {
6907 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
6908 configuration.mBounds.width, configuration.mBounds.height,
6909 PR_TRUE);
6910 } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
6911 w->Move(configuration.mBounds.x, configuration.mBounds.y);
6914 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
6915 gfxWindowsPlatform::RENDER_DIRECT2D ||
6916 GetLayerManager()->GetBackendType() != LayerManager::LAYERS_BASIC) {
6917 // XXX - Workaround for Bug 587508. This will invalidate the part of the
6918 // plugin window that might be touched by moving content somehow. The
6919 // underlying problem should be found and fixed!
6920 nsIntRegion r;
6921 r.Sub(bounds, configuration.mBounds);
6922 r.MoveBy(-bounds.x,
6923 -bounds.y);
6924 w->Invalidate(r.GetBounds(), PR_FALSE);
6927 rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_FALSE);
6928 NS_ENSURE_SUCCESS(rv, rv);
6930 return NS_OK;
6933 static HRGN
6934 CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
6936 PRInt32 size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
6937 nsAutoTArray<PRUint8,100> buf;
6938 if (!buf.SetLength(size))
6939 return NULL;
6940 RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
6941 RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
6942 data->rdh.dwSize = sizeof(data->rdh);
6943 data->rdh.iType = RDH_RECTANGLES;
6944 data->rdh.nCount = aRects.Length();
6945 nsIntRect bounds;
6946 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
6947 const nsIntRect& r = aRects[i];
6948 bounds.UnionRect(bounds, r);
6949 ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
6951 ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
6952 return ::ExtCreateRegion(NULL, buf.Length(), data);
6955 nsresult
6956 nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
6957 PRBool aIntersectWithExisting)
6959 if (!aIntersectWithExisting) {
6960 if (!StoreWindowClipRegion(aRects))
6961 return NS_OK;
6962 } else {
6963 // In this case still early return if nothing changed.
6964 if (mClipRects && mClipRectCount == aRects.Length() &&
6965 memcmp(mClipRects,
6966 aRects.Elements(),
6967 sizeof(nsIntRect)*mClipRectCount) == 0) {
6968 return NS_OK;
6972 HRGN dest = CreateHRGNFromArray(aRects);
6973 if (!dest)
6974 return NS_ERROR_OUT_OF_MEMORY;
6976 if (aIntersectWithExisting) {
6977 HRGN current = ::CreateRectRgn(0, 0, 0, 0);
6978 if (current) {
6979 if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
6980 ::CombineRgn(dest, dest, current, RGN_AND);
6982 ::DeleteObject(current);
6986 if (!::SetWindowRgn(mWnd, dest, TRUE)) {
6987 ::DeleteObject(dest);
6988 return NS_ERROR_FAILURE;
6990 return NS_OK;
6993 // WM_DESTROY event handler
6994 void nsWindow::OnDestroy()
6996 mOnDestroyCalled = PR_TRUE;
6998 // Make sure we don't get destroyed in the process of tearing down.
6999 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
7001 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
7002 if (!mInDtor)
7003 DispatchStandardEvent(NS_DESTROY);
7005 // Prevent the widget from sending additional events.
7006 mEventCallback = nsnull;
7008 // Free our subclass and clear |this| stored in the window props. We will no longer
7009 // receive events from Windows after this point.
7010 SubclassWindow(FALSE);
7012 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
7013 // cleared. (It's used in tracking windows for mouse events.)
7014 if (sCurrentWindow == this)
7015 sCurrentWindow = nsnull;
7017 // Disconnects us from our parent, will call our GetParent().
7018 nsBaseWidget::Destroy();
7020 // Release references to children, device context, toolkit, and app shell.
7021 nsBaseWidget::OnDestroy();
7023 // Clear our native parent handle.
7024 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
7025 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
7026 //SetParent(nsnull);
7027 mParent = nsnull;
7029 // We have to destroy the native drag target before we null out our window pointer.
7030 EnableDragDrop(PR_FALSE);
7032 // If we're going away and for some reason we're still the rollup widget, rollup and
7033 // turn off capture.
7034 if ( this == sRollupWidget ) {
7035 if ( sRollupListener )
7036 sRollupListener->Rollup(nsnull, nsnull);
7037 CaptureRollupEvents(nsnull, nsnull, PR_FALSE, PR_TRUE);
7040 // If IME is disabled, restore it.
7041 if (mOldIMC) {
7042 mOldIMC = ::ImmAssociateContext(mWnd, mOldIMC);
7043 NS_ASSERTION(!mOldIMC, "Another IMC was associated");
7046 // Turn off mouse trails if enabled.
7047 MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
7048 if (mtrailer) {
7049 if (mtrailer->GetMouseTrailerWindow() == mWnd)
7050 mtrailer->DestroyTimer();
7052 if (mtrailer->GetCaptureWindow() == mWnd)
7053 mtrailer->SetCaptureWindow(nsnull);
7056 // Free GDI window class objects
7057 if (mBrush) {
7058 VERIFY(::DeleteObject(mBrush));
7059 mBrush = NULL;
7062 // Free app icon resources.
7063 HICON icon;
7064 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM) 0);
7065 if (icon)
7066 ::DestroyIcon(icon);
7068 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM) 0);
7069 if (icon)
7070 ::DestroyIcon(icon);
7072 // Destroy any custom cursor resources.
7073 if (mCursor == -1)
7074 SetCursor(eCursor_standard);
7076 #ifdef MOZ_XUL
7077 // Reset transparency
7078 if (eTransparencyTransparent == mTransparencyMode)
7079 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
7080 #endif
7082 #if defined(WINCE_HAVE_SOFTKB)
7083 // Revert the changes made for the software keyboard settings
7084 nsWindowCE::ResetSoftKB(mWnd);
7085 #endif
7087 #if !defined(WINCE)
7088 // Finalize panning feedback to possibly restore window displacement
7089 mGesture.PanFeedbackFinalize(mWnd, PR_TRUE);
7090 #endif
7092 // Clear the main HWND.
7093 mWnd = NULL;
7096 // OnMove
7097 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
7099 mBounds.x = aX;
7100 mBounds.y = aY;
7102 nsGUIEvent event(PR_TRUE, NS_MOVE, this);
7103 InitEvent(event);
7104 event.refPoint.x = aX;
7105 event.refPoint.y = aY;
7107 return DispatchWindowEvent(&event);
7110 // Send a resize message to the listener
7111 PRBool nsWindow::OnResize(nsIntRect &aWindowRect)
7113 #ifdef CAIRO_HAS_D2D_SURFACE
7114 if (mD2DWindowSurface) {
7115 mD2DWindowSurface = NULL;
7116 Invalidate(PR_FALSE);
7118 #endif
7120 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7121 UpdateCaptionButtonsClippingRect();
7122 #endif
7124 // call the event callback
7125 if (mEventCallback) {
7126 nsSizeEvent event(PR_TRUE, NS_SIZE, this);
7127 InitEvent(event);
7128 event.windowSize = &aWindowRect;
7129 RECT r;
7130 if (::GetWindowRect(mWnd, &r)) {
7131 event.mWinWidth = PRInt32(r.right - r.left);
7132 event.mWinHeight = PRInt32(r.bottom - r.top);
7133 } else {
7134 event.mWinWidth = 0;
7135 event.mWinHeight = 0;
7138 #if 0
7139 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7140 aWindowRect.x, aWindowRect.y, aWindowRect.width, aWindowRect.height,
7141 event.mWinWidth, event.mWinHeight);
7142 #endif
7144 return DispatchWindowEvent(&event);
7147 return PR_FALSE;
7150 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7151 PRBool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
7153 return PR_TRUE;
7155 #endif // !defined(WINCE)
7157 void nsWindow::OnSettingsChange(WPARAM wParam, LPARAM lParam)
7159 if (mWindowType == eWindowType_dialog ||
7160 mWindowType == eWindowType_toplevel )
7161 nsWindowGfx::OnSettingsChangeGfx(wParam);
7164 static PRBool IsOurProcessWindow(HWND aHWND)
7166 DWORD processId = 0;
7167 ::GetWindowThreadProcessId(aHWND, &processId);
7168 return processId == ::GetCurrentProcessId();
7171 static HWND FindOurProcessWindow(HWND aHWND)
7173 for (HWND wnd = ::GetParent(aHWND); wnd; wnd = ::GetParent(wnd)) {
7174 if (IsOurProcessWindow(wnd)) {
7175 return wnd;
7178 return nsnull;
7181 // Scrolling helper function for handling plugins.
7182 // Return value indicates whether the calling function should handle this
7183 // aHandled indicates whether this was handled at all
7184 // aQuitProcessing tells whether or not to continue processing the message
7185 PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
7186 LPARAM aLParam, PRBool& aHandled,
7187 LRESULT* aRetValue,
7188 PRBool& aQuitProcessing)
7190 // The scroll event will be dispatched to the toplevel
7191 // window. We need to give it to the child window
7192 aQuitProcessing = PR_FALSE; // default is to not stop processing
7193 POINT point;
7194 DWORD dwPoints = ::GetMessagePos();
7195 point.x = GET_X_LPARAM(dwPoints);
7196 point.y = GET_Y_LPARAM(dwPoints);
7198 static PRBool sIsProcessing = PR_FALSE;
7199 if (sIsProcessing) {
7200 return PR_TRUE; // the caller should handle this.
7203 static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
7204 if (aMsg == WM_MOUSEHWHEEL) {
7205 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7206 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7207 // message at first time, this time, ::GetMessagePos works fine.
7208 // Then, we will return 0 (0 means we process it) to the message. Then, the
7209 // driver will POST the same messages continuously during the wheel tilted.
7210 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7211 // cursor isn't 0,0. Therefore, we cannot trust the result of
7212 // ::GetMessagePos API if the sender is the driver.
7213 if (!sMayBeUsingLogitechMouse && aLParam == 0 && (DWORD)aLParam != dwPoints &&
7214 ::InSendMessage()) {
7215 sMayBeUsingLogitechMouse = PR_TRUE;
7216 } else if (sMayBeUsingLogitechMouse && aLParam != 0 && ::InSendMessage()) {
7217 // The user has changed the mouse from Logitech's to another one (e.g.,
7218 // the user has changed to the touchpad of the notebook.
7219 sMayBeUsingLogitechMouse = PR_FALSE;
7221 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7222 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7223 // instead.
7224 if (sMayBeUsingLogitechMouse && aLParam == 0 && dwPoints == 0) {
7225 ::GetCursorPos(&point);
7229 HWND destWnd = ::WindowFromPoint(point);
7230 // Since we receive scroll events for as long as
7231 // we are focused, it's entirely possible that there
7232 // is another app's window or no window under the
7233 // pointer.
7235 if (!destWnd) {
7236 // No window is under the pointer
7237 return PR_FALSE; // break, but continue processing
7240 nsWindow* destWindow;
7242 // We don't handle the message if the found window belongs to another
7243 // process's top window. If it belongs window, that is a plug-in's window.
7244 // Then, we need to send the message to the plug-in window.
7245 if (!IsOurProcessWindow(destWnd)) {
7246 HWND ourPluginWnd = FindOurProcessWindow(destWnd);
7247 if (!ourPluginWnd) {
7248 // Somebody elses window
7249 return PR_FALSE; // break, but continue processing
7251 destWindow = GetNSWindowPtr(ourPluginWnd);
7252 } else {
7253 destWindow = GetNSWindowPtr(destWnd);
7256 if (destWindow == this && mWindowType == eWindowType_plugin) {
7257 // If this is plug-in window, the message came from the plug-in window.
7258 // Then, the message should be processed on the parent window.
7259 destWindow = static_cast<nsWindow*>(GetParent());
7260 NS_ENSURE_TRUE(destWindow, PR_FALSE); // break, but continue processing
7261 destWnd = destWindow->mWnd;
7262 NS_ENSURE_TRUE(destWnd, PR_FALSE); // break, but continue processing
7265 if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
7266 // Some other app, or a plugin window.
7267 // Windows directs scrolling messages to the focused window.
7268 // However, Mozilla does not like plugins having focus, so a
7269 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7270 // Therefore, plugins etc _should_ get first grab at the
7271 // message, but this focus vaguary means the plugin misses
7272 // out. If the window is a child of ours, forward it on.
7273 // Determine if a child by walking the parent list until
7274 // we find a parent matching our wndproc.
7275 HWND parentWnd = ::GetParent(destWnd);
7276 while (parentWnd) {
7277 nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
7278 if (parentWindow) {
7279 // We have a child window - quite possibly a plugin window.
7280 // However, not all plugins are created equal - some will handle this
7281 // message themselves, some will forward directly back to us, while
7282 // others will call DefWndProc, which itself still forwards back to us.
7283 // So if we have sent it once, we need to handle it ourself.
7285 #ifdef MOZ_IPC
7286 // XXX The message shouldn't come from the plugin window at here.
7287 // But the message might come from it due to some bugs. If it happens,
7288 // SendMessage causes deadlock. For safety, we should unlock the
7289 // sender here.
7290 ::ReplyMessage(aMsg == WM_MOUSEHWHEEL ? TRUE : 0);
7291 #endif
7293 // First time we have seen this message.
7294 // Call the child - either it will consume it, or
7295 // it will wind it's way back to us,triggering the destWnd case above
7296 // either way,when the call returns,we are all done with the message,
7297 sIsProcessing = PR_TRUE;
7298 ::SendMessageW(destWnd, aMsg, aWParam, aLParam);
7299 sIsProcessing = PR_FALSE;
7300 aHandled = PR_TRUE;
7301 aQuitProcessing = PR_TRUE;
7302 return PR_FALSE; // break, and stop processing
7304 parentWnd = ::GetParent(parentWnd);
7305 } // while parentWnd
7307 if (destWnd == nsnull)
7308 return PR_FALSE;
7309 if (destWnd != mWnd) {
7310 if (destWindow) {
7311 sIsProcessing = PR_TRUE;
7312 aHandled = destWindow->ProcessMessage(aMsg, aWParam, aLParam, aRetValue);
7313 sIsProcessing = PR_FALSE;
7314 aQuitProcessing = PR_TRUE;
7315 return PR_FALSE; // break, and stop processing
7317 #ifdef DEBUG
7318 else
7319 printf("WARNING: couldn't get child window for SCROLL event\n");
7320 #endif
7322 return PR_TRUE; // caller should handle this
7325 PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
7327 static PRInt8 sMouseWheelEmulation = -1;
7328 if (sMouseWheelEmulation < 0) {
7329 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7330 NS_ENSURE_TRUE(prefs, PR_FALSE);
7331 nsCOMPtr<nsIPrefBranch> prefBranch;
7332 prefs->GetBranch(0, getter_AddRefs(prefBranch));
7333 NS_ENSURE_TRUE(prefBranch, PR_FALSE);
7334 PRBool emulate;
7335 nsresult rv =
7336 prefBranch->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate);
7337 NS_ENSURE_SUCCESS(rv, PR_FALSE);
7338 sMouseWheelEmulation = PRInt8(emulate);
7341 if (aLParam || sMouseWheelEmulation) {
7342 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7343 // Treat as a mousewheel message and scroll appropriately
7344 PRBool quit, result;
7345 LRESULT retVal;
7347 if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result, &retVal, quit))
7348 return quit; // Return if it's not our message or has been dispatched
7350 nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
7351 scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
7352 ? nsMouseScrollEvent::kIsVertical
7353 : nsMouseScrollEvent::kIsHorizontal;
7354 switch (LOWORD(aWParam))
7356 case SB_PAGEDOWN:
7357 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7358 case SB_LINEDOWN:
7359 scrollevent.delta = 1;
7360 break;
7361 case SB_PAGEUP:
7362 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7363 case SB_LINEUP:
7364 scrollevent.delta = -1;
7365 break;
7366 default:
7367 return PR_FALSE;
7369 #ifdef MOZ_IPC
7370 // The event may go to a plug-in which already dispatched this message.
7371 // Then, the event can cause deadlock. We should unlock the sender here.
7372 ::ReplyMessage(0);
7373 #endif
7374 scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
7375 scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
7376 scrollevent.isMeta = PR_FALSE;
7377 scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
7378 InitEvent(scrollevent);
7379 if (nsnull != mEventCallback)
7381 DispatchWindowEvent(&scrollevent);
7383 return PR_TRUE;
7386 // Scroll message generated by external application
7387 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_SCROLL, this);
7389 command.mScroll.mIsHorizontal = (aMsg == WM_HSCROLL);
7391 switch (LOWORD(aWParam))
7393 case SB_LINEUP: // SB_LINELEFT
7394 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7395 command.mScroll.mAmount = -1;
7396 break;
7397 case SB_LINEDOWN: // SB_LINERIGHT
7398 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7399 command.mScroll.mAmount = 1;
7400 break;
7401 case SB_PAGEUP: // SB_PAGELEFT
7402 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7403 command.mScroll.mAmount = -1;
7404 break;
7405 case SB_PAGEDOWN: // SB_PAGERIGHT
7406 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7407 command.mScroll.mAmount = 1;
7408 break;
7409 case SB_TOP: // SB_LEFT
7410 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7411 command.mScroll.mAmount = -1;
7412 break;
7413 case SB_BOTTOM: // SB_RIGHT
7414 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7415 command.mScroll.mAmount = 1;
7416 break;
7417 default:
7418 return PR_FALSE;
7420 DispatchWindowEvent(&command);
7421 return PR_TRUE;
7424 // Can be overriden. Controls auto-erase of background.
7425 PRBool nsWindow::AutoErase(HDC dc)
7427 return PR_FALSE;
7430 /**************************************************************
7431 **************************************************************
7433 ** BLOCK: IME management and accessibility
7435 ** Handles managing IME input and accessibility.
7437 **************************************************************
7438 **************************************************************/
7440 NS_IMETHODIMP nsWindow::ResetInputState()
7442 #ifdef DEBUG_KBSTATE
7443 printf("ResetInputState\n");
7444 #endif
7446 #ifdef NS_ENABLE_TSF
7447 nsTextStore::CommitComposition(PR_FALSE);
7448 #endif //NS_ENABLE_TSF
7450 nsIMM32Handler::CommitComposition(this);
7451 return NS_OK;
7454 NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState)
7456 #ifdef DEBUG_KBSTATE
7457 printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
7458 #endif
7460 #ifdef NS_ENABLE_TSF
7461 nsTextStore::SetIMEOpenState(aState);
7462 #endif //NS_ENABLE_TSF
7464 nsIMEContext IMEContext(mWnd);
7465 if (IMEContext.IsValid()) {
7466 ::ImmSetOpenStatus(IMEContext.get(), aState ? TRUE : FALSE);
7468 return NS_OK;
7471 NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState)
7473 nsIMEContext IMEContext(mWnd);
7474 if (IMEContext.IsValid()) {
7475 BOOL isOpen = ::ImmGetOpenStatus(IMEContext.get());
7476 *aState = isOpen ? PR_TRUE : PR_FALSE;
7477 } else
7478 *aState = PR_FALSE;
7480 #ifdef NS_ENABLE_TSF
7481 *aState |= nsTextStore::GetIMEOpenState();
7482 #endif //NS_ENABLE_TSF
7484 return NS_OK;
7487 NS_IMETHODIMP nsWindow::SetIMEEnabled(PRUint32 aState)
7489 #ifdef NS_ENABLE_TSF
7490 nsTextStore::SetIMEEnabled(aState);
7491 #endif //NS_ENABLE_TSF
7492 #ifdef DEBUG_KBSTATE
7493 printf("SetIMEEnabled: %s\n", (aState == nsIWidget::IME_STATUS_ENABLED ||
7494 aState == nsIWidget::IME_STATUS_PLUGIN)?
7495 "Enabled": "Disabled");
7496 #endif
7497 if (nsIMM32Handler::IsComposing()) {
7498 ResetInputState();
7500 mIMEEnabled = aState;
7501 PRBool enable = (aState == nsIWidget::IME_STATUS_ENABLED ||
7502 aState == nsIWidget::IME_STATUS_PLUGIN);
7504 #if defined(WINCE_HAVE_SOFTKB)
7505 sSoftKeyboardState = (aState != nsIWidget::IME_STATUS_DISABLED);
7506 nsWindowCE::ToggleSoftKB(mWnd, sSoftKeyboardState);
7507 #endif
7509 if (!enable != !mOldIMC)
7510 return NS_OK;
7511 mOldIMC = ::ImmAssociateContext(mWnd, enable ? mOldIMC : NULL);
7512 NS_ASSERTION(!enable || !mOldIMC, "Another IMC was associated");
7514 return NS_OK;
7517 NS_IMETHODIMP nsWindow::GetIMEEnabled(PRUint32* aState)
7519 #ifdef DEBUG_KBSTATE
7520 printf("GetIMEEnabled: %s\n", mIMEEnabled? "Enabled": "Disabled");
7521 #endif
7522 *aState = mIMEEnabled;
7523 return NS_OK;
7526 NS_IMETHODIMP nsWindow::CancelIMEComposition()
7528 #ifdef DEBUG_KBSTATE
7529 printf("CancelIMEComposition\n");
7530 #endif
7532 #ifdef NS_ENABLE_TSF
7533 nsTextStore::CommitComposition(PR_TRUE);
7534 #endif //NS_ENABLE_TSF
7536 nsIMM32Handler::CancelComposition(this);
7537 return NS_OK;
7540 NS_IMETHODIMP
7541 nsWindow::GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState)
7543 #ifdef DEBUG_KBSTATE
7544 printf("GetToggledKeyState\n");
7545 #endif
7546 NS_ENSURE_ARG_POINTER(aLEDState);
7547 *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
7548 return NS_OK;
7551 #ifdef NS_ENABLE_TSF
7552 NS_IMETHODIMP
7553 nsWindow::OnIMEFocusChange(PRBool aFocus)
7555 nsresult rv = nsTextStore::OnFocusChange(aFocus, this, mIMEEnabled);
7556 if (rv == NS_ERROR_NOT_AVAILABLE)
7557 rv = NS_ERROR_NOT_IMPLEMENTED; // TSF is not enabled, maybe.
7558 return rv;
7561 NS_IMETHODIMP
7562 nsWindow::OnIMETextChange(PRUint32 aStart,
7563 PRUint32 aOldEnd,
7564 PRUint32 aNewEnd)
7566 return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
7569 NS_IMETHODIMP
7570 nsWindow::OnIMESelectionChange(void)
7572 return nsTextStore::OnSelectionChange();
7574 #endif //NS_ENABLE_TSF
7576 #ifdef ACCESSIBILITY
7578 #ifdef DEBUG_WMGETOBJECT
7579 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
7580 nsAccessible* acc = aWnd ? \
7581 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
7582 printf(" acc: %p", acc); \
7583 if (acc) { \
7584 nsAutoString name; \
7585 acc->GetName(name); \
7586 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
7587 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
7588 void *hwnd = nsnull; \
7589 doc->GetWindowHandle(&hwnd); \
7590 printf(", acc hwnd: %d", hwnd); \
7593 #define NS_LOG_WMGETOBJECT_THISWND \
7595 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
7596 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7597 mWnd, ::GetParent(mWnd), this); \
7598 NS_LOG_WMGETOBJECT_WNDACC(this) \
7599 printf("\n }\n"); \
7602 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
7604 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
7605 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7606 aHwnd, ::GetParent(aHwnd), wnd); \
7607 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
7608 printf("\n }\n"); \
7610 #else
7611 #define NS_LOG_WMGETOBJECT_THISWND
7612 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
7613 #endif // DEBUG_WMGETOBJECT
7615 nsAccessible*
7616 nsWindow::GetRootAccessible()
7618 // We want the ability to forcibly disable a11y on windows, because
7619 // some non-a11y-related components attempt to bring it up. See bug
7620 // 538530 for details; we have a pref here that allows it to be disabled
7621 // for performance and testing resons.
7623 // This pref is checked only once, and the browser needs a restart to
7624 // pick up any changes.
7625 static int accForceDisable = -1;
7627 if (accForceDisable == -1) {
7628 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7629 PRBool b = PR_FALSE;
7630 nsresult rv = prefs->GetBoolPref("accessibility.win32.force_disabled", &b);
7631 if (NS_SUCCEEDED(rv) && b) {
7632 accForceDisable = 1;
7633 } else {
7634 accForceDisable = 0;
7638 // If the pref was true, return null here, disabling a11y.
7639 if (accForceDisable)
7640 return nsnull;
7642 nsWindow::sIsAccessibilityOn = TRUE;
7644 if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) {
7645 return nsnull;
7648 NS_LOG_WMGETOBJECT_THISWND
7649 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
7651 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
7654 STDMETHODIMP_(LRESULT)
7655 nsWindow::LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc)
7657 // open the dll dynamically
7658 if (!sAccLib)
7659 sAccLib =::LoadLibraryW(L"OLEACC.DLL");
7661 if (sAccLib) {
7662 if (!sLresultFromObject)
7663 sLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(sAccLib,"LresultFromObject");
7665 if (sLresultFromObject)
7666 return sLresultFromObject(riid,wParam,pAcc);
7669 return 0;
7671 #endif
7673 /**************************************************************
7674 **************************************************************
7676 ** BLOCK: Transparency
7678 ** Window transparency helpers.
7680 **************************************************************
7681 **************************************************************/
7683 #ifdef MOZ_XUL
7685 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force)
7687 if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
7688 return;
7690 #ifdef CAIRO_HAS_D2D_SURFACE
7691 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7692 gfxWindowsPlatform::RENDER_DIRECT2D) {
7693 nsRefPtr<gfxD2DSurface> newSurface =
7694 new gfxD2DSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7695 mTransparentSurface = newSurface;
7696 mMemoryDC = nsnull;
7697 } else
7698 #endif
7700 nsRefPtr<gfxWindowsSurface> newSurface =
7701 new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7702 mTransparentSurface = newSurface;
7703 mMemoryDC = newSurface->GetDC();
7707 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
7709 #ifndef WINCE
7711 if (aMode == mTransparencyMode)
7712 return;
7714 // stop on dialogs and popups!
7715 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7716 nsWindow* parent = GetNSWindowPtr(hWnd);
7718 if (!parent)
7720 NS_WARNING("Trying to use transparent chrome in an embedded context");
7721 return;
7724 if (parent != this) {
7725 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
7728 if (aMode == eTransparencyTransparent) {
7729 // If we're switching to the use of a transparent window, hide the chrome
7730 // on our parent.
7731 HideWindowChrome(PR_TRUE);
7732 } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) {
7733 // if we're switching out of transparent, re-enable our parent's chrome.
7734 HideWindowChrome(PR_FALSE);
7737 LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE),
7738 exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
7740 if (parent->mIsVisible)
7741 style |= WS_VISIBLE;
7742 if (parent->mSizeMode == nsSizeMode_Maximized)
7743 style |= WS_MAXIMIZE;
7744 else if (parent->mSizeMode == nsSizeMode_Minimized)
7745 style |= WS_MINIMIZE;
7747 if (aMode == eTransparencyTransparent)
7748 exStyle |= WS_EX_LAYERED;
7749 else
7750 exStyle &= ~WS_EX_LAYERED;
7752 VERIFY_WINDOW_STYLE(style);
7753 ::SetWindowLongPtrW(hWnd, GWL_STYLE, style);
7754 ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle);
7756 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7757 if (HasGlass())
7758 memset(&mGlassMargins, 0, sizeof mGlassMargins);
7759 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7760 mTransparencyMode = aMode;
7762 SetupTranslucentWindowMemoryBitmap(aMode);
7763 UpdateGlass();
7764 #endif // #ifndef WINCE
7767 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
7769 if (eTransparencyTransparent == aMode) {
7770 ResizeTranslucentWindow(mBounds.width, mBounds.height, PR_TRUE);
7771 } else {
7772 mTransparentSurface = nsnull;
7773 mMemoryDC = NULL;
7777 nsresult nsWindow::UpdateTranslucentWindow()
7779 #ifndef WINCE
7780 if (mBounds.IsEmpty())
7781 return NS_OK;
7783 ::GdiFlush();
7785 BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
7786 SIZE winSize = { mBounds.width, mBounds.height };
7787 POINT srcPos = { 0, 0 };
7788 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7789 RECT winRect;
7790 ::GetWindowRect(hWnd, &winRect);
7792 #ifdef CAIRO_HAS_D2D_SURFACE
7793 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7794 gfxWindowsPlatform::RENDER_DIRECT2D) {
7795 mMemoryDC = static_cast<gfxD2DSurface*>(mTransparentSurface.get())->
7796 GetDC(PR_TRUE);
7798 #endif
7799 // perform the alpha blend
7800 PRBool updateSuccesful =
7801 ::UpdateLayeredWindow(hWnd, NULL, (POINT*)&winRect, &winSize, mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA);
7803 #ifdef CAIRO_HAS_D2D_SURFACE
7804 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7805 gfxWindowsPlatform::RENDER_DIRECT2D) {
7806 nsIntRect r(0, 0, 0, 0);
7807 static_cast<gfxD2DSurface*>(mTransparentSurface.get())->ReleaseDC(&r);
7809 #endif
7811 if (!updateSuccesful) {
7812 return NS_ERROR_FAILURE;
7814 #endif
7816 return NS_OK;
7819 #endif //MOZ_XUL
7821 /**************************************************************
7822 **************************************************************
7824 ** BLOCK: Popup rollup hooks
7826 ** Deals with CaptureRollup on popup windows.
7828 **************************************************************
7829 **************************************************************/
7831 #ifndef WINCE
7832 // Schedules a timer for a window, so we can rollup after processing the hook event
7833 void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId)
7835 // In some cases multiple hooks may be scheduled
7836 // so ignore any other requests once one timer is scheduled
7837 if (sHookTimerId == 0) {
7838 // Remember the window handle and the message ID to be used later
7839 sRollupMsgId = aMsgId;
7840 sRollupMsgWnd = aWnd;
7841 // Schedule native timer for doing the rollup after
7842 // this event is done being processed
7843 sHookTimerId = ::SetTimer(NULL, 0, 0, (TIMERPROC)HookTimerForPopups);
7844 NS_ASSERTION(sHookTimerId, "Timer couldn't be created.");
7848 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7849 int gLastMsgCode = 0;
7850 extern MSGFEventMsgInfo gMSGFEvents[];
7851 #endif
7853 // Process Menu messages, rollup when popup is clicked.
7854 LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam)
7856 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7857 if (sProcessHook) {
7858 MSG* pMsg = (MSG*)lParam;
7860 int inx = 0;
7861 while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != NULL) {
7862 inx++;
7864 if (code != gLastMsgCode) {
7865 if (gMSGFEvents[inx].mId == code) {
7866 #ifdef DEBUG
7867 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code, gMSGFEvents[inx].mStr, pMsg->hwnd);
7868 #endif
7869 } else {
7870 #ifdef DEBUG
7871 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code, gMSGFEvents[inx].mId, pMsg->hwnd);
7872 #endif
7874 gLastMsgCode = code;
7876 PrintEvent(pMsg->message, FALSE, FALSE);
7878 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7880 if (sProcessHook && code == MSGF_MENU) {
7881 MSG* pMsg = (MSG*)lParam;
7882 ScheduleHookTimer( pMsg->hwnd, pMsg->message);
7885 return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
7888 // Process all mouse messages. Roll up when a click is in a native window
7889 // that doesn't have an nsIWidget.
7890 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
7892 if (sProcessHook) {
7893 switch (wParam) {
7894 case WM_LBUTTONDOWN:
7895 case WM_RBUTTONDOWN:
7896 case WM_MBUTTONDOWN:
7897 case WM_MOUSEWHEEL:
7898 case WM_MOUSEHWHEEL:
7900 MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
7901 nsIWidget* mozWin = (nsIWidget*)GetNSWindowPtr(ms->hwnd);
7902 if (mozWin) {
7903 // If this window is windowed plugin window, the mouse events are not
7904 // sent to us.
7905 if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin)
7906 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7907 } else {
7908 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7910 break;
7914 return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam);
7917 // Process all messages. Roll up when the window is moving, or
7918 // is resizing or when maximized or mininized.
7919 LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam)
7921 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7922 if (sProcessHook) {
7923 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7924 PrintEvent(cwpt->message, FALSE, FALSE);
7926 #endif
7928 if (sProcessHook) {
7929 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7930 if (cwpt->message == WM_MOVING ||
7931 cwpt->message == WM_SIZING ||
7932 cwpt->message == WM_GETMINMAXINFO) {
7933 ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message);
7937 return ::CallNextHookEx(sCallProcHook, code, wParam, lParam);
7940 // Register the special "hooks" for dropdown processing.
7941 void nsWindow::RegisterSpecialDropdownHooks()
7943 NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!");
7944 NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!");
7946 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
7948 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
7950 // Install msg hook for moving the window and resizing
7951 if (!sMsgFilterHook) {
7952 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
7953 sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, NULL, GetCurrentThreadId());
7954 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7955 if (!sMsgFilterHook) {
7956 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
7958 #endif
7961 // Install msg hook for menus
7962 if (!sCallProcHook) {
7963 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
7964 sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, NULL, GetCurrentThreadId());
7965 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7966 if (!sCallProcHook) {
7967 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
7969 #endif
7972 // Install msg hook for the mouse
7973 if (!sCallMouseHook) {
7974 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
7975 sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, NULL, GetCurrentThreadId());
7976 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7977 if (!sCallMouseHook) {
7978 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
7980 #endif
7984 // Unhook special message hooks for dropdowns.
7985 void nsWindow::UnregisterSpecialDropdownHooks()
7987 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
7989 if (sCallProcHook) {
7990 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
7991 if (!::UnhookWindowsHookEx(sCallProcHook)) {
7992 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
7994 sCallProcHook = NULL;
7997 if (sMsgFilterHook) {
7998 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
7999 if (!::UnhookWindowsHookEx(sMsgFilterHook)) {
8000 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
8002 sMsgFilterHook = NULL;
8005 if (sCallMouseHook) {
8006 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
8007 if (!::UnhookWindowsHookEx(sCallMouseHook)) {
8008 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
8010 sCallMouseHook = NULL;
8014 // This timer is designed to only fire one time at most each time a "hook" function
8015 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
8016 // hook, but that hook event or a subsequent event may roll up the dropdown before
8017 // this timer function is executed.
8019 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
8020 // before this function fires.
8021 VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
8023 if (sHookTimerId != 0) {
8024 // if the window is NULL then we need to use the ID to kill the timer
8025 BOOL status = ::KillTimer(NULL, sHookTimerId);
8026 NS_ASSERTION(status, "Hook Timer was not killed.");
8027 sHookTimerId = 0;
8030 if (sRollupMsgId != 0) {
8031 // Note: DealWithPopups does the check to make sure that
8032 // sRollupListener and sRollupWidget are not NULL
8033 LRESULT popupHandlingResult;
8034 nsAutoRollup autoRollup;
8035 DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
8036 sRollupMsgId = 0;
8037 sRollupMsgWnd = NULL;
8040 #endif // WinCE
8042 BOOL CALLBACK nsWindow::ClearResourcesCallback(HWND aWnd, LPARAM aMsg)
8044 nsWindow *window = nsWindow::GetNSWindowPtr(aWnd);
8045 if (window) {
8046 window->ClearCachedResources();
8048 return TRUE;
8051 void
8052 nsWindow::ClearCachedResources()
8054 #ifdef CAIRO_HAS_D2D_SURFACE
8055 mD2DWindowSurface = nsnull;
8056 #endif
8057 if (mLayerManager &&
8058 mLayerManager->GetBackendType() == LayerManager::LAYERS_BASIC) {
8059 static_cast<BasicLayerManager*>(mLayerManager.get())->
8060 ClearCachedResources();
8062 ::EnumChildWindows(mWnd, nsWindow::ClearResourcesCallback, NULL);
8065 static PRBool IsDifferentThreadWindow(HWND aWnd)
8067 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, NULL);
8070 PRBool
8071 nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
8073 RECT r;
8075 #ifndef WINCE
8076 if (Msg == WM_ACTIVATEAPP)
8077 // don't care about activation/deactivation
8078 return PR_FALSE;
8079 #else
8080 if (Msg == WM_ACTIVATE)
8081 // but on Windows CE we do care about
8082 // activation/deactivation because there doesn't exist
8083 // cancelable Mouse Activation events
8084 return PR_TRUE;
8085 #endif
8087 ::GetWindowRect(aWindow->mWnd, &r);
8088 DWORD pos = ::GetMessagePos();
8089 POINT mp;
8090 mp.x = GET_X_LPARAM(pos);
8091 mp.y = GET_Y_LPARAM(pos);
8093 // was the event inside this window?
8094 return (PRBool) PtInRect(&r, mp);
8097 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8098 BOOL
8099 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
8101 if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
8103 if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
8104 inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
8105 (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam))
8106 #ifndef WINCE
8108 inMsg == WM_NCRBUTTONDOWN ||
8109 inMsg == WM_MOVING ||
8110 inMsg == WM_SIZING ||
8111 inMsg == WM_NCLBUTTONDOWN ||
8112 inMsg == WM_NCMBUTTONDOWN ||
8113 inMsg == WM_MOUSEACTIVATE ||
8114 inMsg == WM_ACTIVATEAPP ||
8115 inMsg == WM_MENUSELECT
8116 #endif
8119 // Rollup if the event is outside the popup.
8120 PRBool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)sRollupWidget);
8122 if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL))
8124 sRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
8125 *outResult = PR_TRUE;
8128 // If we're dealing with menus, we probably have submenus and we don't
8129 // want to rollup if the click is in a parent menu of the current submenu.
8130 PRUint32 popupsToRollup = PR_UINT32_MAX;
8131 if (rollup) {
8132 if ( sMenuRollup ) {
8133 nsAutoTArray<nsIWidget*, 5> widgetChain;
8134 PRUint32 sameTypeCount = sMenuRollup->GetSubmenuWidgetChain(&widgetChain);
8135 for ( PRUint32 i = 0; i < widgetChain.Length(); ++i ) {
8136 nsIWidget* widget = widgetChain[i];
8137 if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
8138 // don't roll up if the mouse event occurred within a menu of the
8139 // same type. If the mouse event occurred in a menu higher than
8140 // that, roll up, but pass the number of popups to Rollup so
8141 // that only those of the same type close up.
8142 if (i < sameTypeCount) {
8143 rollup = PR_FALSE;
8145 else {
8146 popupsToRollup = sameTypeCount;
8148 break;
8150 } // foreach parent menu widget
8151 } // if rollup listener knows about menus
8154 #ifndef WINCE
8155 if (inMsg == WM_MOUSEACTIVATE && popupsToRollup == PR_UINT32_MAX) {
8156 // Prevent the click inside the popup from causing a change in window
8157 // activation. Since the popup is shown non-activated, we need to eat
8158 // any requests to activate the window while it is displayed. Windows
8159 // will automatically activate the popup on the mousedown otherwise.
8160 if (!rollup) {
8161 *outResult = MA_NOACTIVATE;
8162 return TRUE;
8164 else
8166 UINT uMsg = HIWORD(inLParam);
8167 if (uMsg == WM_MOUSEMOVE)
8169 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8170 // must be enabled in Windows.
8171 sRollupListener->ShouldRollupOnMouseActivate(&rollup);
8172 if (!rollup)
8174 *outResult = MA_NOACTIVATE;
8175 return true;
8180 // if we've still determined that we should still rollup everything, do it.
8181 else
8182 #endif
8183 if ( rollup ) {
8184 // sRollupConsumeEvent may be modified by
8185 // nsIRollupListener::Rollup.
8186 PRBool consumeRollupEvent = sRollupConsumeEvent;
8187 // only need to deal with the last rollup for left mouse down events.
8188 sRollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN ? &mLastRollup : nsnull);
8190 // Tell hook to stop processing messages
8191 sProcessHook = PR_FALSE;
8192 sRollupMsgId = 0;
8193 sRollupMsgWnd = NULL;
8195 // return TRUE tells Windows that the event is consumed,
8196 // false allows the event to be dispatched
8198 // So if we are NOT supposed to be consuming events, let it go through
8199 if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
8200 *outResult = TRUE;
8201 return TRUE;
8203 #ifndef WINCE
8204 // if we are only rolling up some popups, don't activate and don't let
8205 // the event go through. This prevents clicks menus higher in the
8206 // chain from opening when a context menu is open
8207 if (popupsToRollup != PR_UINT32_MAX && inMsg == WM_MOUSEACTIVATE) {
8208 *outResult = MA_NOACTIVATEANDEAT;
8209 return TRUE;
8211 #endif
8213 } // if event that might trigger a popup to rollup
8214 } // if rollup listeners registered
8216 return FALSE;
8219 /**************************************************************
8220 **************************************************************
8222 ** BLOCK: Misc. utility methods and functions.
8224 ** General use.
8226 **************************************************************
8227 **************************************************************/
8229 // nsModifierKeyState used in various character processing.
8230 nsModifierKeyState::nsModifierKeyState()
8232 mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT);
8233 mIsControlDown = IS_VK_DOWN(NS_VK_CONTROL);
8234 mIsAltDown = IS_VK_DOWN(NS_VK_ALT);
8238 PRInt32 nsWindow::GetWindowsVersion()
8240 #ifdef WINCE
8241 return 0x500;
8242 #else
8243 static PRInt32 version = 0;
8244 static PRBool didCheck = PR_FALSE;
8246 if (!didCheck)
8248 didCheck = PR_TRUE;
8249 OSVERSIONINFOEX osInfo;
8250 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
8251 // This cast is safe and supposed to be here, don't worry
8252 ::GetVersionEx((OSVERSIONINFO*)&osInfo);
8253 version = (osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
8255 return version;
8256 #endif
8259 // Note that the result of GetTopLevelWindow method can be different from the
8260 // result of GetTopLevelHWND method. The result can be non-floating window.
8261 // Because our top level window may be contained in another window which is
8262 // not managed by us.
8263 nsWindow* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup)
8265 nsWindow* curWindow = this;
8267 while (PR_TRUE) {
8268 if (aStopOnDialogOrPopup) {
8269 switch (curWindow->mWindowType) {
8270 case eWindowType_dialog:
8271 case eWindowType_popup:
8272 return curWindow;
8273 default:
8274 break;
8278 // Retrieve the top level parent or owner window
8279 nsWindow* parentWindow = curWindow->GetParentWindow(PR_TRUE);
8281 if (!parentWindow)
8282 return curWindow;
8284 curWindow = parentWindow;
8288 // Note that the result of GetTopLevelHWND can be different from the result
8289 // of GetTopLevelWindow method. Because this is checking whether the window
8290 // is top level only in Win32 window system. Therefore, the result window
8291 // may not be managed by us.
8292 HWND nsWindow::GetTopLevelHWND(HWND aWnd, PRBool aStopOnDialogOrPopup)
8294 HWND curWnd = aWnd;
8295 HWND topWnd = NULL;
8296 HWND upWnd = NULL;
8298 while (curWnd) {
8299 topWnd = curWnd;
8301 if (aStopOnDialogOrPopup) {
8302 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8304 VERIFY_WINDOW_STYLE(style);
8306 if (!(style & WS_CHILD)) // first top-level window
8307 break;
8310 upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
8312 #ifdef WINCE
8313 // For dialog windows, we want just the parent, not the owner.
8314 // For other/popup windows, we want to find the first owner/parent
8315 // that's a dialog and/or has an owner.
8316 if (upWnd && ::GetWindow(curWnd, GW_OWNER) == upWnd) {
8317 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8318 if ((style & WS_DLGFRAME) != 0)
8319 break;
8321 #endif
8323 curWnd = upWnd;
8326 return topWnd;
8329 static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam)
8331 DWORD pid;
8332 ::GetWindowThreadProcessId(hwnd, &pid);
8333 if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd))
8335 gWindowsVisible = PR_TRUE;
8336 return FALSE;
8338 return TRUE;
8341 PRBool nsWindow::CanTakeFocus()
8343 gWindowsVisible = PR_FALSE;
8344 EnumWindows(gEnumWindowsProc, 0);
8345 if (!gWindowsVisible) {
8346 return PR_TRUE;
8347 } else {
8348 HWND fgWnd = ::GetForegroundWindow();
8349 if (!fgWnd) {
8350 return PR_TRUE;
8352 DWORD pid;
8353 GetWindowThreadProcessId(fgWnd, &pid);
8354 if (pid == GetCurrentProcessId()) {
8355 return PR_TRUE;
8358 return PR_FALSE;
8361 #if !defined(WINCE)
8362 void nsWindow::InitTrackPointHack()
8364 // Init Trackpoint Hack
8365 nsresult rv;
8366 PRInt32 lHackValue;
8367 long lResult;
8368 const WCHAR wstrKeys[][40] = {L"Software\\Lenovo\\TrackPoint",
8369 L"Software\\Lenovo\\UltraNav",
8370 L"Software\\Alps\\Apoint\\TrackPoint",
8371 L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
8372 L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
8373 // If anything fails turn the hack off
8374 sTrackPointHack = false;
8375 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8376 if(NS_SUCCEEDED(rv) && prefs) {
8377 prefs->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue);
8378 switch (lHackValue) {
8379 // 0 means hack disabled
8380 case 0:
8381 break;
8382 // 1 means hack enabled
8383 case 1:
8384 sTrackPointHack = true;
8385 break;
8386 // -1 means autodetect
8387 case -1:
8388 for(unsigned i = 0; i < NS_ARRAY_LENGTH(wstrKeys); i++) {
8389 HKEY hKey;
8390 lResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, (LPCWSTR)&wstrKeys[i],
8391 0, KEY_READ, &hKey);
8392 ::RegCloseKey(hKey);
8393 if(lResult == ERROR_SUCCESS) {
8394 // If we detected a registry key belonging to a TrackPoint driver
8395 // Turn on the hack
8396 sTrackPointHack = true;
8397 break;
8400 break;
8401 // Shouldn't be any other values, but treat them as disabled
8402 default:
8403 break;
8406 return;
8408 #endif // #if !defined(WINCE)
8410 LPARAM nsWindow::lParamToScreen(LPARAM lParam)
8412 POINT pt;
8413 pt.x = GET_X_LPARAM(lParam);
8414 pt.y = GET_Y_LPARAM(lParam);
8415 ::ClientToScreen(mWnd, &pt);
8416 return MAKELPARAM(pt.x, pt.y);
8419 LPARAM nsWindow::lParamToClient(LPARAM lParam)
8421 POINT pt;
8422 pt.x = GET_X_LPARAM(lParam);
8423 pt.y = GET_Y_LPARAM(lParam);
8424 ::ScreenToClient(mWnd, &pt);
8425 return MAKELPARAM(pt.x, pt.y);
8428 /**************************************************************
8429 **************************************************************
8431 ** BLOCK: ChildWindow impl.
8433 ** Child window overrides.
8435 **************************************************************
8436 **************************************************************/
8438 // return the style for a child nsWindow
8439 DWORD ChildWindow::WindowStyle()
8441 DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle();
8442 if (!(style & WS_POPUP))
8443 style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
8444 VERIFY_WINDOW_STYLE(style);
8445 return style;