Bug 593069 - Firefox window positioning incorrect after transitioning from full scree...
[mozilla-central.git] / widget / src / windows / nsWindow.cpp
blobac449960ca59a5e58330854c73e89a5c601dd598
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 #include "LayerManagerOGL.h"
178 #endif
179 #include "BasicLayers.h"
181 #if !defined(WINCE)
182 #include "nsUXThemeConstants.h"
183 #include "KeyboardLayout.h"
184 #include "nsNativeDragTarget.h"
185 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
186 #include <zmouse.h>
187 #include <pbt.h>
188 #include <richedit.h>
189 #endif // !defined(WINCE)
191 #if defined(ACCESSIBILITY)
192 #include "oleidl.h"
193 #include <winuser.h>
194 #include "nsIAccessibleDocument.h"
195 #if !defined(WINABLEAPI)
196 #include <winable.h>
197 #endif // !defined(WINABLEAPI)
198 #endif // defined(ACCESSIBILITY)
200 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
201 #include "nsIWinTaskbar.h"
202 #endif
204 #if defined(NS_ENABLE_TSF)
205 #include "nsTextStore.h"
206 #endif // defined(NS_ENABLE_TSF)
208 #if defined(MOZ_SPLASHSCREEN)
209 #include "nsSplashScreen.h"
210 #endif // defined(MOZ_SPLASHSCREEN)
212 // Windowless plugin support
213 #include "npapi.h"
215 #include "nsWindowDefs.h"
217 #include "mozilla/FunctionTimer.h"
219 #ifdef WINCE_WINDOWS_MOBILE
220 #include "nsGfxCIID.h"
221 #endif
223 #include "mozilla/FunctionTimer.h"
225 #ifdef MOZ_CRASHREPORTER
226 #include "nsICrashReporter.h"
227 #endif
229 #include "nsIXULRuntime.h"
231 using namespace mozilla::widget;
233 /**************************************************************
234 **************************************************************
236 ** BLOCK: Variables
238 ** nsWindow Class static initializations and global variables.
240 **************************************************************
241 **************************************************************/
243 /**************************************************************
245 * SECTION: nsWindow statics
247 **************************************************************/
249 PRUint32 nsWindow::sInstanceCount = 0;
250 PRBool nsWindow::sSwitchKeyboardLayout = PR_FALSE;
251 BOOL nsWindow::sIsRegistered = FALSE;
252 BOOL nsWindow::sIsPopupClassRegistered = FALSE;
253 BOOL nsWindow::sIsOleInitialized = FALSE;
254 HCURSOR nsWindow::sHCursor = NULL;
255 imgIContainer* nsWindow::sCursorImgContainer = nsnull;
256 nsWindow* nsWindow::sCurrentWindow = nsnull;
257 PRBool nsWindow::sJustGotDeactivate = PR_FALSE;
258 PRBool nsWindow::sJustGotActivate = PR_FALSE;
260 // imported in nsWidgetFactory.cpp
261 TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN;
263 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
264 // hook methods whether they should be processing the hook
265 // messages.
266 HHOOK nsWindow::sMsgFilterHook = NULL;
267 HHOOK nsWindow::sCallProcHook = NULL;
268 HHOOK nsWindow::sCallMouseHook = NULL;
269 PRPackedBool nsWindow::sProcessHook = PR_FALSE;
270 UINT nsWindow::sRollupMsgId = 0;
271 HWND nsWindow::sRollupMsgWnd = NULL;
272 UINT nsWindow::sHookTimerId = 0;
274 // Rollup Listener
275 nsIRollupListener* nsWindow::sRollupListener = nsnull;
276 nsIMenuRollup* nsWindow::sMenuRollup = nsnull;
277 nsIWidget* nsWindow::sRollupWidget = nsnull;
278 PRBool nsWindow::sRollupConsumeEvent = PR_FALSE;
280 // Mouse Clicks - static variable definitions for figuring
281 // out 1 - 3 Clicks.
282 POINT nsWindow::sLastMousePoint = {0};
283 POINT nsWindow::sLastMouseMovePoint = {0};
284 LONG nsWindow::sLastMouseDownTime = 0L;
285 LONG nsWindow::sLastClickCount = 0L;
286 BYTE nsWindow::sLastMouseButton = 0;
288 // Trim heap on minimize. (initialized, but still true.)
289 int nsWindow::sTrimOnMinimize = 2;
291 // Default Trackpoint Hack to off
292 PRBool nsWindow::sTrackPointHack = PR_FALSE;
294 #ifdef ACCESSIBILITY
295 BOOL nsWindow::sIsAccessibilityOn = FALSE;
296 // Accessibility wm_getobject handler
297 HINSTANCE nsWindow::sAccLib = 0;
298 LPFNLRESULTFROMOBJECT
299 nsWindow::sLresultFromObject = 0;
300 #endif // ACCESSIBILITY
302 #ifdef MOZ_IPC
303 // Used in OOPP plugin focus processing.
304 const PRUnichar* kOOPPPluginFocusEventId = L"OOPP Plugin Focus Widget Event";
305 PRUint32 nsWindow::sOOPPPluginFocusEvent =
306 RegisterWindowMessageW(kOOPPPluginFocusEventId);
307 #endif
309 /**************************************************************
311 * SECTION: globals variables
313 **************************************************************/
315 static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
317 #ifdef PR_LOGGING
318 PRLogModuleInfo* gWindowsLog = nsnull;
319 #endif
321 #ifndef WINCE
322 // Kbd layout. Used throughout character processing.
323 static KeyboardLayout gKbdLayout;
324 #endif
326 #ifdef WINCE_WINDOWS_MOBILE
327 // HTC Navigation Wheel Event
328 // This is the defined value for Gesture Mode
329 const int WM_HTCNAV = 0x0400 + 200;
331 typedef int (__stdcall * HTCApiNavOpen)(HANDLE, int);
332 typedef int (__stdcall * HTCApiNavSetMode)(HANDLE, unsigned int);
334 HTCApiNavOpen gHTCApiNavOpen = nsnull;
335 HTCApiNavSetMode gHTCApiNavSetMode = nsnull;
336 static PRBool gCheckForHTCApi = PR_FALSE;
337 #endif
339 // Global user preference for disabling native theme. Used
340 // in NativeWindowTheme.
341 PRBool gDisableNativeTheme = PR_FALSE;
343 // Global used in Show window enumerations.
344 static PRBool gWindowsVisible = PR_FALSE;
346 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
347 #ifdef WINCE_WINDOWS_MOBILE
348 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
349 #endif
351 /**************************************************************
352 **************************************************************
354 ** BLOCK: nsIWidget impl.
356 ** nsIWidget interface implementation, broken down into
357 ** sections.
359 **************************************************************
360 **************************************************************/
362 /**************************************************************
364 * SECTION: nsWindow construction and destruction
366 **************************************************************/
368 nsWindow::nsWindow() : nsBaseWidget()
370 #ifdef PR_LOGGING
371 if (!gWindowsLog)
372 gWindowsLog = PR_NewLogModule("nsWindowsWidgets");
373 #endif
375 mWnd = nsnull;
376 mPaintDC = nsnull;
377 mPrevWndProc = nsnull;
378 mOldIMC = nsnull;
379 mNativeDragTarget = nsnull;
380 mInDtor = PR_FALSE;
381 mIsVisible = PR_FALSE;
382 mIsInMouseCapture = PR_FALSE;
383 mIsTopWidgetWindow = PR_FALSE;
384 mUnicodeWidget = PR_TRUE;
385 mDisplayPanFeedback = PR_FALSE;
386 mTouchWindow = PR_FALSE;
387 mCustomNonClient = PR_FALSE;
388 mHideChrome = PR_FALSE;
389 mFullscreenMode = PR_FALSE;
390 mWindowType = eWindowType_child;
391 mBorderStyle = eBorderStyle_default;
392 mPopupType = ePopupTypeAny;
393 mOldSizeMode = nsSizeMode_Normal;
394 mLastPoint.x = 0;
395 mLastPoint.y = 0;
396 mLastSize.width = 0;
397 mLastSize.height = 0;
398 mOldStyle = 0;
399 mOldExStyle = 0;
400 mPainting = 0;
401 mExitToNonClientArea = 0;
402 mLastKeyboardLayout = 0;
403 mBlurSuppressLevel = 0;
404 mIMEEnabled = nsIWidget::IME_STATUS_ENABLED;
405 #ifdef MOZ_XUL
406 mTransparentSurface = nsnull;
407 mMemoryDC = nsnull;
408 mTransparencyMode = eTransparencyOpaque;
409 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
410 memset(&mGlassMargins, 0, sizeof mGlassMargins);
411 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
412 #endif
413 mBackground = ::GetSysColor(COLOR_BTNFACE);
414 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
415 mForeground = ::GetSysColor(COLOR_WINDOWTEXT);
417 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
418 mTaskbarPreview = nsnull;
419 mHasTaskbarIconBeenCreated = PR_FALSE;
420 #endif
422 // Global initialization
423 if (!sInstanceCount) {
424 #if !defined(WINCE)
425 gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
426 #endif
428 // Init IME handler
429 nsIMM32Handler::Initialize();
431 #ifdef NS_ENABLE_TSF
432 nsTextStore::Initialize();
433 #endif
435 #if !defined(WINCE)
436 if (SUCCEEDED(::OleInitialize(NULL)))
437 sIsOleInitialized = TRUE;
438 NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
439 #endif
441 #if !defined(WINCE)
442 InitTrackPointHack();
443 #endif
445 // Init titlebar button info for custom frames.
446 nsUXThemeData::InitTitlebarInfo();
447 } // !sInstanceCount
449 mIdleService = nsnull;
451 sInstanceCount++;
454 nsWindow::~nsWindow()
456 mInDtor = PR_TRUE;
458 // If the widget was released without calling Destroy() then the native window still
459 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
461 // XXX How could this happen???
462 if (NULL != mWnd)
463 Destroy();
465 sInstanceCount--;
467 // Global shutdown
468 if (sInstanceCount == 0) {
469 #ifdef NS_ENABLE_TSF
470 nsTextStore::Terminate();
471 #endif
473 #if !defined(WINCE)
474 NS_IF_RELEASE(sCursorImgContainer);
475 if (sIsOleInitialized) {
476 ::OleFlushClipboard();
477 ::OleUninitialize();
478 sIsOleInitialized = FALSE;
480 // delete any of the IME structures that we allocated
481 nsIMM32Handler::Terminate();
482 #endif // !defined(WINCE)
485 #if !defined(WINCE)
486 NS_IF_RELEASE(mNativeDragTarget);
487 #endif // !defined(WINCE)
490 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
492 /**************************************************************
494 * SECTION: nsIWidget::Create, nsIWidget::Destroy
496 * Creating and destroying windows for this widget.
498 **************************************************************/
500 // Allow Derived classes to modify the height that is passed
501 // when the window is created or resized. Also add extra height
502 // if needed (on Windows CE)
503 PRInt32 nsWindow::GetHeight(PRInt32 aProposedHeight)
505 PRInt32 extra = 0;
507 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
508 DWORD style = WindowStyle();
509 if ((style & WS_SYSMENU) && (style & WS_POPUP)) {
510 extra = GetSystemMetrics(SM_CYCAPTION);
512 #endif
514 return aProposedHeight + extra;
517 // Create the proper widget
518 nsresult
519 nsWindow::Create(nsIWidget *aParent,
520 nsNativeWidget aNativeParent,
521 const nsIntRect &aRect,
522 EVENT_CALLBACK aHandleEventFunction,
523 nsIDeviceContext *aContext,
524 nsIAppShell *aAppShell,
525 nsIToolkit *aToolkit,
526 nsWidgetInitData *aInitData)
528 nsWidgetInitData defaultInitData;
529 if (!aInitData)
530 aInitData = &defaultInitData;
532 mUnicodeWidget = aInitData->mUnicode;
534 nsIWidget *baseParent = aInitData->mWindowType == eWindowType_dialog ||
535 aInitData->mWindowType == eWindowType_toplevel ||
536 aInitData->mWindowType == eWindowType_invisible ?
537 nsnull : aParent;
539 mIsTopWidgetWindow = (nsnull == baseParent);
540 mBounds.width = aRect.width;
541 mBounds.height = aRect.height;
543 BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
544 aAppShell, aToolkit, aInitData);
546 HWND parent;
547 if (aParent) { // has a nsIWidget parent
548 parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : NULL;
549 mParent = aParent;
550 } else { // has a nsNative parent
551 parent = (HWND)aNativeParent;
552 mParent = aNativeParent ? GetNSWindowPtr((HWND)aNativeParent) : nsnull;
555 mPopupType = aInitData->mPopupHint;
556 mContentType = aInitData->mContentType;
557 mIsRTL = aInitData->mRTL;
559 DWORD style = WindowStyle();
560 DWORD extendedStyle = WindowExStyle();
562 if (mWindowType == eWindowType_popup) {
563 if (!aParent)
564 parent = NULL;
565 } else if (mWindowType == eWindowType_invisible) {
566 // Make sure CreateWindowEx succeeds at creating a toplevel window
567 style &= ~0x40000000; // WS_CHILDWINDOW
568 } else {
569 // See if the caller wants to explictly set clip children and clip siblings
570 if (aInitData->clipChildren) {
571 style |= WS_CLIPCHILDREN;
572 } else {
573 style &= ~WS_CLIPCHILDREN;
575 if (aInitData->clipSiblings) {
576 style |= WS_CLIPSIBLINGS;
580 mWnd = ::CreateWindowExW(extendedStyle,
581 aInitData->mDropShadow ?
582 WindowPopupClass() : WindowClass(),
583 L"",
584 style,
585 aRect.x,
586 aRect.y,
587 aRect.width,
588 GetHeight(aRect.height),
589 parent,
590 NULL,
591 nsToolkit::mDllInstance,
592 NULL);
594 if (!mWnd) {
595 NS_WARNING("nsWindow CreateWindowEx failed.");
596 return NS_ERROR_FAILURE;
599 if (nsWindow::sTrackPointHack &&
600 mWindowType != eWindowType_plugin &&
601 mWindowType != eWindowType_invisible) {
602 // Ugly Thinkpad Driver Hack (Bug 507222)
603 // We create an invisible scrollbar to trick the
604 // Trackpoint driver into sending us scrolling messages
605 ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTSCROLLBAR",
606 WS_CHILD | WS_VISIBLE, 0,0,0,0, mWnd, NULL,
607 nsToolkit::mDllInstance, NULL);
610 // call the event callback to notify about creation
612 DispatchStandardEvent(NS_CREATE);
613 SubclassWindow(TRUE);
615 if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
616 /* The internal variable set by the config.trim_on_minimize pref
617 has not yet been initialized, and this is the hidden window
618 (conveniently created before any visible windows, and after
619 the profile has been initialized).
621 Default config.trim_on_minimize to false, to fix bug 76831
622 for good. If anyone complains about this new default, saying
623 that a Mozilla app hogs too much memory while minimized, they
624 will have that entire bug tattooed on their backside. */
626 sTrimOnMinimize = 0;
627 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
628 if (prefs) {
629 nsCOMPtr<nsIPrefBranch> prefBranch;
630 prefs->GetBranch(0, getter_AddRefs(prefBranch));
631 if (prefBranch) {
633 PRBool temp;
634 if (NS_SUCCEEDED(prefBranch->GetBoolPref("config.trim_on_minimize",
635 &temp))
636 && temp)
637 sTrimOnMinimize = 1;
639 if (NS_SUCCEEDED(prefBranch->GetBoolPref("intl.keyboard.per_window_layout",
640 &temp)))
641 sSwitchKeyboardLayout = temp;
643 if (NS_SUCCEEDED(prefBranch->GetBoolPref("mozilla.widget.disable-native-theme",
644 &temp)))
645 gDisableNativeTheme = temp;
649 #if defined(WINCE_HAVE_SOFTKB)
650 if (mWindowType == eWindowType_dialog || mWindowType == eWindowType_toplevel )
651 nsWindowCE::CreateSoftKeyMenuBar(mWnd);
652 #endif
654 return NS_OK;
657 // Close this nsWindow
658 NS_METHOD nsWindow::Destroy()
660 // WM_DESTROY has already fired, we're done.
661 if (nsnull == mWnd)
662 return NS_OK;
664 // During the destruction of all of our children, make sure we don't get deleted.
665 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
668 * On windows the LayerManagerOGL destructor wants the widget to be around for
669 * cleanup. It also would like to have the HWND intact, so we NULL it here.
671 if (mLayerManager) {
672 mLayerManager->Destroy();
674 mLayerManager = nsnull;
676 /* We should clear our cached resources now and not wait for the GC to
677 * delete the nsWindow. */
678 ClearCachedResources();
680 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
681 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
682 // from it. The function also destroys the window's menu, flushes the thread message queue,
683 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
684 // the window is at the top of the viewer chain).
686 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
687 // the associated child or owned windows when it destroys the parent or owner window. The
688 // function first destroys child or owned windows, and then it destroys the parent or owner
689 // window.
690 VERIFY(::DestroyWindow(mWnd));
692 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
693 // didn't get called, call it now.
694 if (PR_FALSE == mOnDestroyCalled)
695 OnDestroy();
697 return NS_OK;
700 /**************************************************************
702 * SECTION: Window class utilities
704 * Utilities for calculating the proper window class name for
705 * Create window.
707 **************************************************************/
709 // Return the proper window class for everything except popups.
710 LPCWSTR nsWindow::WindowClass()
712 if (!nsWindow::sIsRegistered) {
713 WNDCLASSW wc;
715 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
716 wc.style = CS_DBLCLKS;
717 wc.lpfnWndProc = ::DefWindowProcW;
718 wc.cbClsExtra = 0;
719 wc.cbWndExtra = 0;
720 wc.hInstance = nsToolkit::mDllInstance;
721 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
722 wc.hCursor = NULL;
723 wc.hbrBackground = mBrush;
724 wc.lpszMenuName = NULL;
725 wc.lpszClassName = kClassNameHidden;
727 BOOL succeeded = ::RegisterClassW(&wc) != 0 &&
728 ERROR_CLASS_ALREADY_EXISTS != GetLastError();
729 nsWindow::sIsRegistered = succeeded;
731 wc.lpszClassName = kClassNameContentFrame;
732 if (!::RegisterClassW(&wc) &&
733 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
734 nsWindow::sIsRegistered = FALSE;
737 wc.lpszClassName = kClassNameContent;
738 if (!::RegisterClassW(&wc) &&
739 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
740 nsWindow::sIsRegistered = FALSE;
743 wc.lpszClassName = kClassNameGeneral;
744 ATOM generalClassAtom = ::RegisterClassW(&wc);
745 if (!generalClassAtom &&
746 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
747 nsWindow::sIsRegistered = FALSE;
750 wc.lpszClassName = kClassNameDialog;
751 wc.hIcon = 0;
752 if (!::RegisterClassW(&wc) &&
753 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
754 nsWindow::sIsRegistered = FALSE;
758 if (mWindowType == eWindowType_invisible) {
759 return kClassNameHidden;
761 if (mWindowType == eWindowType_dialog) {
762 return kClassNameDialog;
764 if (mContentType == eContentTypeContent) {
765 return kClassNameContent;
767 if (mContentType == eContentTypeContentFrame) {
768 return kClassNameContentFrame;
770 return kClassNameGeneral;
773 // Return the proper popup window class
774 LPCWSTR nsWindow::WindowPopupClass()
776 if (!nsWindow::sIsPopupClassRegistered) {
777 WNDCLASSW wc;
779 wc.style = CS_DBLCLKS | CS_XP_DROPSHADOW;
780 wc.lpfnWndProc = ::DefWindowProcW;
781 wc.cbClsExtra = 0;
782 wc.cbWndExtra = 0;
783 wc.hInstance = nsToolkit::mDllInstance;
784 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
785 wc.hCursor = NULL;
786 wc.hbrBackground = mBrush;
787 wc.lpszMenuName = NULL;
788 wc.lpszClassName = kClassNameDropShadow;
790 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
791 if (!nsWindow::sIsPopupClassRegistered) {
792 // For older versions of Win32 (i.e., not XP), the registration will
793 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
794 wc.style = CS_DBLCLKS;
795 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
799 return kClassNameDropShadow;
802 /**************************************************************
804 * SECTION: Window styles utilities
806 * Return the proper windows styles and extended styles.
808 **************************************************************/
810 // Return nsWindow styles
811 #if !defined(WINCE) // implemented in nsWindowCE.cpp
812 DWORD nsWindow::WindowStyle()
814 DWORD style;
816 switch (mWindowType) {
817 case eWindowType_plugin:
818 case eWindowType_child:
819 style = WS_OVERLAPPED;
820 break;
822 case eWindowType_dialog:
823 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK |
824 DS_MODALFRAME | WS_CLIPCHILDREN;
825 if (mBorderStyle != eBorderStyle_default)
826 style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
827 break;
829 case eWindowType_popup:
830 style = WS_POPUP;
831 if (!HasGlass()) {
832 style |= WS_OVERLAPPED;
834 break;
836 default:
837 NS_ERROR("unknown border style");
838 // fall through
840 case eWindowType_toplevel:
841 case eWindowType_invisible:
842 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU |
843 WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
844 break;
847 if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) {
848 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border))
849 style &= ~WS_BORDER;
851 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) {
852 style &= ~WS_DLGFRAME;
853 style |= WS_POPUP;
854 style &= ~WS_CHILD;
857 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close))
858 style &= ~0;
859 // XXX The close box can only be removed by changing the window class,
860 // as far as I know --- roc+moz@cs.cmu.edu
862 if (mBorderStyle == eBorderStyle_none ||
863 !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
864 style &= ~WS_SYSMENU;
865 // Looks like getting rid of the system menu also does away with the
866 // close box. So, we only get rid of the system menu if you want neither it
867 // nor the close box. How does the Windows "Dialog" window class get just
868 // closebox and no sysmenu? Who knows.
870 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh))
871 style &= ~WS_THICKFRAME;
873 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize))
874 style &= ~WS_MINIMIZEBOX;
876 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize))
877 style &= ~WS_MAXIMIZEBOX;
879 if (IsPopupWithTitleBar()) {
880 style |= WS_CAPTION;
881 if (mBorderStyle & eBorderStyle_close) {
882 style |= WS_SYSMENU;
887 VERIFY_WINDOW_STYLE(style);
888 return style;
890 #endif // !defined(WINCE)
892 // Return nsWindow extended styles
893 DWORD nsWindow::WindowExStyle()
895 switch (mWindowType)
897 case eWindowType_plugin:
898 case eWindowType_child:
899 return 0;
901 case eWindowType_dialog:
902 return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
904 case eWindowType_popup:
906 DWORD extendedStyle =
907 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
908 WS_EX_NOACTIVATE |
909 #endif
910 WS_EX_TOOLWINDOW;
911 if (mPopupLevel == ePopupLevelTop)
912 extendedStyle |= WS_EX_TOPMOST;
913 return extendedStyle;
915 default:
916 NS_ERROR("unknown border style");
917 // fall through
919 case eWindowType_toplevel:
920 case eWindowType_invisible:
921 return WS_EX_WINDOWEDGE;
925 /**************************************************************
927 * SECTION: Window subclassing utilities
929 * Set or clear window subclasses on native windows. Used in
930 * Create and Destroy.
932 **************************************************************/
934 // Subclass (or remove the subclass from) this component's nsWindow
935 void nsWindow::SubclassWindow(BOOL bState)
937 if (NULL != mWnd) {
938 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
939 if (!::IsWindow(mWnd)) {
940 NS_ERROR("Invalid window handle");
943 if (bState) {
944 // change the nsWindow proc
945 if (mUnicodeWidget)
946 mPrevWndProc = (WNDPROC)::SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
947 (LONG_PTR)nsWindow::WindowProc);
948 else
949 mPrevWndProc = (WNDPROC)::SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
950 (LONG_PTR)nsWindow::WindowProc);
951 NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
952 // connect the this pointer to the nsWindow handle
953 SetNSWindowPtr(mWnd, this);
955 else {
956 if (mUnicodeWidget)
957 ::SetWindowLongPtrW(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
958 else
959 ::SetWindowLongPtrA(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
960 SetNSWindowPtr(mWnd, NULL);
961 mPrevWndProc = NULL;
966 /**************************************************************
968 * SECTION: Window properties
970 * Set and clear native window properties.
972 **************************************************************/
974 static PRUnichar sPropName[40] = L"";
975 static PRUnichar* GetNSWindowPropName()
977 if (!*sPropName)
979 _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p", GetCurrentProcessId());
980 sPropName[39] = '\0';
982 return sPropName;
985 nsWindow * nsWindow::GetNSWindowPtr(HWND aWnd)
987 return (nsWindow *) ::GetPropW(aWnd, GetNSWindowPropName());
990 BOOL nsWindow::SetNSWindowPtr(HWND aWnd, nsWindow * ptr)
992 if (ptr == NULL) {
993 ::RemovePropW(aWnd, GetNSWindowPropName());
994 return TRUE;
995 } else {
996 return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)ptr);
1000 /**************************************************************
1002 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
1004 * Set or clear the parent widgets using window properties, and
1005 * handles calculating native parent handles.
1007 **************************************************************/
1009 // Get and set parent widgets
1010 NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent)
1012 mParent = aNewParent;
1014 if (aNewParent) {
1015 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1017 nsIWidget* parent = GetParent();
1018 if (parent) {
1019 parent->RemoveChild(this);
1022 HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
1023 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
1024 if (newParent && mWnd) {
1025 ::SetParent(mWnd, newParent);
1028 aNewParent->AddChild(this);
1030 return NS_OK;
1033 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1035 nsIWidget* parent = GetParent();
1037 if (parent) {
1038 parent->RemoveChild(this);
1041 if (mWnd) {
1042 // If we have no parent, SetParent should return the desktop.
1043 VERIFY(::SetParent(mWnd, nsnull));
1046 return NS_OK;
1049 nsIWidget* nsWindow::GetParent(void)
1051 return GetParentWindow(PR_FALSE);
1054 float nsWindow::GetDPI()
1056 HDC dc = ::GetDC(mWnd);
1057 if (!dc)
1058 return 96.0f;
1060 double heightInches = ::GetDeviceCaps(dc, VERTSIZE)/MM_PER_INCH_FLOAT;
1061 int heightPx = ::GetDeviceCaps(dc, VERTRES);
1062 ::ReleaseDC(mWnd, dc);
1063 if (heightInches < 0.25) {
1064 // Something's broken
1065 return 96.0f;
1067 return float(heightPx/heightInches);
1070 nsWindow* nsWindow::GetParentWindow(PRBool aIncludeOwner)
1072 if (mIsTopWidgetWindow) {
1073 // Must use a flag instead of mWindowType to tell if the window is the
1074 // owned by the topmost widget, because a child window can be embedded inside
1075 // a HWND which is not associated with a nsIWidget.
1076 return nsnull;
1079 // If this widget has already been destroyed, pretend we have no parent.
1080 // This corresponds to code in Destroy which removes the destroyed
1081 // widget from its parent's child list.
1082 if (mInDtor || mOnDestroyCalled)
1083 return nsnull;
1086 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1087 // root owner. aIncludeOwner set to false implies the search will stop at the
1088 // true parent (default).
1089 nsWindow* widget = nsnull;
1090 if (mWnd) {
1091 #ifdef WINCE
1092 HWND parent = ::GetParent(mWnd);
1093 #else
1094 HWND parent = nsnull;
1095 if (aIncludeOwner)
1096 parent = ::GetParent(mWnd);
1097 else
1098 parent = ::GetAncestor(mWnd, GA_PARENT);
1099 #endif
1100 if (parent) {
1101 widget = GetNSWindowPtr(parent);
1102 if (widget) {
1103 // If the widget is in the process of being destroyed then
1104 // do NOT return it
1105 if (widget->mInDtor) {
1106 widget = nsnull;
1112 return widget;
1115 /**************************************************************
1117 * SECTION: nsIWidget::Show
1119 * Hide or show this component.
1121 **************************************************************/
1123 NS_METHOD nsWindow::Show(PRBool bState)
1125 #if defined(MOZ_SPLASHSCREEN)
1126 // we're about to show the first toplevel window,
1127 // so kill off any splash screen if we had one
1128 nsSplashScreen *splash = nsSplashScreen::Get();
1129 if (splash && splash->IsOpen() && mWnd && bState &&
1130 (mWindowType == eWindowType_toplevel ||
1131 mWindowType == eWindowType_dialog ||
1132 mWindowType == eWindowType_popup))
1134 splash->Close();
1136 #endif
1138 #ifdef NS_FUNCTION_TIMER
1139 static bool firstShow = true;
1140 if (firstShow &&
1141 (mWindowType == eWindowType_toplevel ||
1142 mWindowType == eWindowType_dialog ||
1143 mWindowType == eWindowType_popup))
1145 firstShow = false;
1146 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1148 #endif
1150 PRBool wasVisible = mIsVisible;
1151 // Set the status now so that anyone asking during ShowWindow or
1152 // SetWindowPos would get the correct answer.
1153 mIsVisible = bState;
1155 if (!mIsVisible && wasVisible) {
1156 ClearCachedResources();
1159 if (mWnd) {
1160 if (bState) {
1161 if (!wasVisible && mWindowType == eWindowType_toplevel) {
1162 switch (mSizeMode) {
1163 #ifdef WINCE
1164 case nsSizeMode_Fullscreen:
1165 ::SetForegroundWindow(mWnd);
1166 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1167 MakeFullScreen(TRUE);
1168 break;
1170 case nsSizeMode_Maximized :
1171 ::SetForegroundWindow(mWnd);
1172 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1173 break;
1174 // use default for nsSizeMode_Minimized on Windows CE
1175 #else
1176 case nsSizeMode_Maximized :
1177 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1178 break;
1179 case nsSizeMode_Minimized :
1180 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
1181 break;
1182 #endif
1183 default:
1184 if (CanTakeFocus()) {
1185 #ifdef WINCE
1186 ::SetForegroundWindow(mWnd);
1187 #endif
1188 ::ShowWindow(mWnd, SW_SHOWNORMAL);
1189 } else {
1190 // Place the window behind the foreground window
1191 // (as long as it is not topmost)
1192 HWND wndAfter = ::GetForegroundWindow();
1193 if (!wndAfter)
1194 wndAfter = HWND_BOTTOM;
1195 else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)
1196 wndAfter = HWND_TOP;
1197 ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE |
1198 SWP_NOMOVE | SWP_NOACTIVATE);
1199 GetAttention(2);
1201 break;
1203 } else {
1204 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
1205 if (wasVisible)
1206 flags |= SWP_NOZORDER;
1208 if (mWindowType == eWindowType_popup) {
1209 #ifndef WINCE
1210 // ensure popups are the topmost of the TOPMOST
1211 // layer. Remember not to set the SWP_NOZORDER
1212 // flag as that might allow the taskbar to overlap
1213 // the popup. However on windows ce, we need to
1214 // activate the popup or clicks will not be sent.
1215 flags |= SWP_NOACTIVATE;
1216 #endif
1217 HWND owner = ::GetWindow(mWnd, GW_OWNER);
1218 ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
1219 } else {
1220 #ifndef WINCE
1221 if (mWindowType == eWindowType_dialog && !CanTakeFocus())
1222 flags |= SWP_NOACTIVATE;
1223 #endif
1224 ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
1228 #ifndef WINCE
1229 if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) {
1230 // when a toplevel window or dialog is shown, initialize the UI state
1231 ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
1233 #endif
1234 } else {
1235 if (mWindowType != eWindowType_dialog) {
1236 ::ShowWindow(mWnd, SW_HIDE);
1237 } else {
1238 ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1239 SWP_NOZORDER | SWP_NOACTIVATE);
1244 #ifdef MOZ_XUL
1245 if (!wasVisible && bState)
1246 Invalidate(PR_FALSE);
1247 #endif
1249 return NS_OK;
1252 /**************************************************************
1254 * SECTION: nsIWidget::IsVisible
1256 * Returns the visibility state.
1258 **************************************************************/
1260 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1261 NS_METHOD nsWindow::IsVisible(PRBool & bState)
1263 bState = mIsVisible;
1264 return NS_OK;
1267 /**************************************************************
1269 * SECTION: Window clipping utilities
1271 * Used in Size and Move operations for setting the proper
1272 * window clipping regions for window transparency.
1274 **************************************************************/
1276 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1277 // transparency. These routines are called on size and move operations.
1278 void nsWindow::ClearThemeRegion()
1280 #ifndef WINCE
1281 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1282 mWindowType == eWindowType_popup && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel)) {
1283 SetWindowRgn(mWnd, NULL, false);
1285 #endif
1288 void nsWindow::SetThemeRegion()
1290 #ifndef WINCE
1291 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1292 // for other window types as needed. The regions are applied generically to the base window
1293 // so default constants are used for part and state. At some point we might need part and
1294 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1295 // change shape based on state haven't come up.
1296 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1297 mWindowType == eWindowType_popup && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel)) {
1298 HRGN hRgn = nsnull;
1299 RECT rect = {0,0,mBounds.width,mBounds.height};
1301 HDC dc = ::GetDC(mWnd);
1302 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
1303 if (hRgn) {
1304 if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted.
1305 DeleteObject(hRgn);
1307 ::ReleaseDC(mWnd, dc);
1309 #endif
1312 /**************************************************************
1314 * SECTION: nsIWidget::RegisterTouchWindow,
1315 * nsIWidget::UnregisterTouchWindow, and helper functions
1317 * Used to register the native window to receive touch events
1319 **************************************************************/
1321 NS_METHOD nsWindow::RegisterTouchWindow() {
1322 mTouchWindow = PR_TRUE;
1323 #ifndef WINCE
1324 mGesture.RegisterTouchWindow(mWnd);
1325 ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
1326 #endif
1327 return NS_OK;
1330 NS_METHOD nsWindow::UnregisterTouchWindow() {
1331 mTouchWindow = PR_FALSE;
1332 #ifndef WINCE
1333 mGesture.UnregisterTouchWindow(mWnd);
1334 ::EnumChildWindows(mWnd, nsWindow::UnregisterTouchForDescendants, 0);
1335 #endif
1336 return NS_OK;
1339 #ifndef WINCE
1340 BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1341 nsWindow* win = GetNSWindowPtr(aWnd);
1342 if (win)
1343 win->mGesture.RegisterTouchWindow(aWnd);
1344 return TRUE;
1347 BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1348 nsWindow* win = GetNSWindowPtr(aWnd);
1349 if (win)
1350 win->mGesture.UnregisterTouchWindow(aWnd);
1351 return TRUE;
1353 #endif
1355 /**************************************************************
1357 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1358 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1360 * Repositioning and sizing a window.
1362 **************************************************************/
1364 // Move this component
1365 NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
1367 if (mWindowType == eWindowType_toplevel ||
1368 mWindowType == eWindowType_dialog) {
1369 SetSizeMode(nsSizeMode_Normal);
1371 // Check to see if window needs to be moved first
1372 // to avoid a costly call to SetWindowPos. This check
1373 // can not be moved to the calling code in nsView, because
1374 // some platforms do not position child windows correctly
1376 // Only perform this check for non-popup windows, since the positioning can
1377 // in fact change even when the x/y do not. We always need to perform the
1378 // check. See bug #97805 for details.
1379 if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
1381 // Nothing to do, since it is already positioned correctly.
1382 return NS_OK;
1385 mBounds.x = aX;
1386 mBounds.y = aY;
1388 if (mWnd) {
1389 #ifdef DEBUG
1390 // complain if a window is moved offscreen (legal, but potentially worrisome)
1391 if (mIsTopWidgetWindow) { // only a problem for top-level windows
1392 // Make sure this window is actually on the screen before we move it
1393 // XXX: Needs multiple monitor support
1394 HDC dc = ::GetDC(mWnd);
1395 if (dc) {
1396 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1397 RECT workArea;
1398 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1399 // no annoying assertions. just mention the issue.
1400 if (aX < 0 || aX >= workArea.right || aY < 0 || aY >= workArea.bottom)
1401 printf("window moved to offscreen position\n");
1403 ::ReleaseDC(mWnd, dc);
1406 #endif
1407 ClearThemeRegion();
1408 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0,
1409 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE));
1410 SetThemeRegion();
1412 return NS_OK;
1415 // Resize this component
1416 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1418 NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
1419 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1421 // Avoid unnecessary resizing calls
1422 if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1423 return NS_OK;
1425 #ifdef MOZ_XUL
1426 if (eTransparencyTransparent == mTransparencyMode)
1427 ResizeTranslucentWindow(aWidth, aHeight);
1428 #endif
1430 // Set cached value for lightweight and printing
1431 mBounds.width = aWidth;
1432 mBounds.height = aHeight;
1434 if (mWnd) {
1435 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
1437 #ifndef WINCE
1438 if (!aRepaint) {
1439 flags |= SWP_NOREDRAW;
1441 #endif
1443 ClearThemeRegion();
1444 VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
1445 SetThemeRegion();
1448 if (aRepaint)
1449 Invalidate(PR_FALSE);
1451 return NS_OK;
1454 // Resize this component
1455 NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1457 NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize");
1458 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1460 // Avoid unnecessary resizing calls
1461 if (mBounds.x == aX && mBounds.y == aY &&
1462 mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1463 return NS_OK;
1465 #ifdef MOZ_XUL
1466 if (eTransparencyTransparent == mTransparencyMode)
1467 ResizeTranslucentWindow(aWidth, aHeight);
1468 #endif
1470 // Set cached value for lightweight and printing
1471 mBounds.x = aX;
1472 mBounds.y = aY;
1473 mBounds.width = aWidth;
1474 mBounds.height = aHeight;
1476 if (mWnd) {
1477 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
1478 #ifndef WINCE
1479 if (!aRepaint) {
1480 flags |= SWP_NOREDRAW;
1482 #endif
1484 ClearThemeRegion();
1485 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
1486 SetThemeRegion();
1489 if (aRepaint)
1490 Invalidate(PR_FALSE);
1492 return NS_OK;
1495 // Resize the client area and position the widget within it's parent
1496 NS_METHOD nsWindow::ResizeClient(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1498 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1499 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1501 // Adjust our existing window bounds, based on the new client dims.
1502 RECT client;
1503 GetClientRect(mWnd, &client);
1504 nsIntPoint dims(client.right - client.left, client.bottom - client.top);
1505 aWidth = mBounds.width + (aWidth - dims.x);
1506 aHeight = mBounds.height + (aHeight - dims.y);
1508 if (aX || aY) {
1509 // offsets
1510 nsIntRect bounds;
1511 GetScreenBounds(bounds);
1512 aX += bounds.x;
1513 aY += bounds.y;
1514 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1516 return Resize(aWidth, aHeight, aRepaint);
1519 #if !defined(WINCE)
1520 NS_IMETHODIMP
1521 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
1523 NS_ENSURE_ARG_POINTER(aEvent);
1525 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
1526 // you can only begin a resize drag with a mouse event
1527 return NS_ERROR_INVALID_ARG;
1530 nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
1531 if (mouseEvent->button != nsMouseEvent::eLeftButton) {
1532 // you can only begin a resize drag with the left mouse button
1533 return NS_ERROR_INVALID_ARG;
1536 // work out what sizemode we're talking about
1537 WPARAM syscommand;
1538 if (aVertical < 0) {
1539 if (aHorizontal < 0) {
1540 syscommand = SC_SIZE | WMSZ_TOPLEFT;
1541 } else if (aHorizontal == 0) {
1542 syscommand = SC_SIZE | WMSZ_TOP;
1543 } else {
1544 syscommand = SC_SIZE | WMSZ_TOPRIGHT;
1546 } else if (aVertical == 0) {
1547 if (aHorizontal < 0) {
1548 syscommand = SC_SIZE | WMSZ_LEFT;
1549 } else if (aHorizontal == 0) {
1550 return NS_ERROR_INVALID_ARG;
1551 } else {
1552 syscommand = SC_SIZE | WMSZ_RIGHT;
1554 } else {
1555 if (aHorizontal < 0) {
1556 syscommand = SC_SIZE | WMSZ_BOTTOMLEFT;
1557 } else if (aHorizontal == 0) {
1558 syscommand = SC_SIZE | WMSZ_BOTTOM;
1559 } else {
1560 syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT;
1564 // resizing doesn't work if the mouse is already captured
1565 CaptureMouse(PR_FALSE);
1567 // find the top-level window
1568 HWND toplevelWnd = GetTopLevelHWND(mWnd, PR_TRUE);
1570 // tell Windows to start the resize
1571 ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand,
1572 POINTTOPOINTS(aEvent->refPoint));
1574 return NS_OK;
1576 #endif
1577 /**************************************************************
1579 * SECTION: Window Z-order and state.
1581 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1582 * nsIWidget::ConstrainPosition
1584 * Z-order, positioning, restore, minimize, and maximize.
1586 **************************************************************/
1588 // Position the window behind the given window
1589 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1590 nsIWidget *aWidget, PRBool aActivate)
1592 HWND behind = HWND_TOP;
1593 if (aPlacement == eZPlacementBottom)
1594 behind = HWND_BOTTOM;
1595 else if (aPlacement == eZPlacementBelow && aWidget)
1596 behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
1597 UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
1598 if (!aActivate)
1599 flags |= SWP_NOACTIVATE;
1601 if (!CanTakeFocus() && behind == HWND_TOP)
1603 // Can't place the window to top so place it behind the foreground window
1604 // (as long as it is not topmost)
1605 HWND wndAfter = ::GetForegroundWindow();
1606 if (!wndAfter)
1607 behind = HWND_BOTTOM;
1608 else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
1609 behind = wndAfter;
1610 flags |= SWP_NOACTIVATE;
1613 ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
1614 return NS_OK;
1617 // Maximize, minimize or restore the window.
1618 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1619 NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode) {
1621 nsresult rv;
1623 // Let's not try and do anything if we're already in that state.
1624 // (This is needed to prevent problems when calling window.minimize(), which
1625 // calls us directly, and then the OS triggers another call to us.)
1626 if (aMode == mSizeMode)
1627 return NS_OK;
1629 // save the requested state
1630 rv = nsBaseWidget::SetSizeMode(aMode);
1631 if (NS_SUCCEEDED(rv) && mIsVisible) {
1632 int mode;
1634 switch (aMode) {
1635 case nsSizeMode_Fullscreen :
1636 mode = SW_SHOW;
1637 break;
1639 case nsSizeMode_Maximized :
1640 mode = SW_MAXIMIZE;
1641 break;
1643 case nsSizeMode_Minimized :
1644 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1645 // keeps the window active in the tray. So after the window is minimized,
1646 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1647 // we will do some additional processing to get the active window set right.
1648 // If sTrimOnMinimize is set, we let windows handle minimization normally
1649 // using SW_MINIMIZE.
1650 mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED;
1651 break;
1653 default :
1654 mode = SW_RESTORE;
1656 ::ShowWindow(mWnd, mode);
1657 // we dispatch an activate event here to ensure that the right child window
1658 // is focused
1659 if (mode == SW_RESTORE || mode == SW_MAXIMIZE)
1660 DispatchFocusToTopLevelWindow(NS_ACTIVATE);
1662 return rv;
1664 #endif // !defined(WINCE)
1666 // Constrain a potential move to fit onscreen
1667 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop,
1668 PRInt32 *aX, PRInt32 *aY)
1670 if (!mIsTopWidgetWindow) // only a problem for top-level windows
1671 return NS_OK;
1673 PRBool doConstrain = PR_FALSE; // whether we have enough info to do anything
1675 /* get our playing field. use the current screen, or failing that
1676 for any reason, use device caps for the default screen. */
1677 RECT screenRect;
1679 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
1680 if (screenmgr) {
1681 nsCOMPtr<nsIScreen> screen;
1682 PRInt32 left, top, width, height;
1684 // zero size rects confuse the screen manager
1685 width = mBounds.width > 0 ? mBounds.width : 1;
1686 height = mBounds.height > 0 ? mBounds.height : 1;
1687 screenmgr->ScreenForRect(*aX, *aY, width, height,
1688 getter_AddRefs(screen));
1689 if (screen) {
1690 if (mSizeMode != nsSizeMode_Fullscreen) {
1691 // For normalized windows, use the desktop work area.
1692 screen->GetAvailRect(&left, &top, &width, &height);
1693 } else {
1694 // For full screen windows, use the desktop.
1695 screen->GetRect(&left, &top, &width, &height);
1697 screenRect.left = left;
1698 screenRect.right = left+width;
1699 screenRect.top = top;
1700 screenRect.bottom = top+height;
1701 doConstrain = PR_TRUE;
1703 } else {
1704 if (mWnd) {
1705 HDC dc = ::GetDC(mWnd);
1706 if (dc) {
1707 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1708 if (mSizeMode != nsSizeMode_Fullscreen) {
1709 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
1710 } else {
1711 screenRect.left = screenRect.top = 0;
1712 screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN);
1713 screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
1715 doConstrain = PR_TRUE;
1717 ::ReleaseDC(mWnd, dc);
1722 if (aAllowSlop) {
1723 if (*aX < screenRect.left - mBounds.width + kWindowPositionSlop)
1724 *aX = screenRect.left - mBounds.width + kWindowPositionSlop;
1725 else if (*aX >= screenRect.right - kWindowPositionSlop)
1726 *aX = screenRect.right - kWindowPositionSlop;
1728 if (*aY < screenRect.top - mBounds.height + kWindowPositionSlop)
1729 *aY = screenRect.top - mBounds.height + kWindowPositionSlop;
1730 else if (*aY >= screenRect.bottom - kWindowPositionSlop)
1731 *aY = screenRect.bottom - kWindowPositionSlop;
1733 } else {
1735 if (*aX < screenRect.left)
1736 *aX = screenRect.left;
1737 else if (*aX >= screenRect.right - mBounds.width)
1738 *aX = screenRect.right - mBounds.width;
1740 if (*aY < screenRect.top)
1741 *aY = screenRect.top;
1742 else if (*aY >= screenRect.bottom - mBounds.height)
1743 *aY = screenRect.bottom - mBounds.height;
1746 return NS_OK;
1749 /**************************************************************
1751 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1753 * Enabling and disabling the widget.
1755 **************************************************************/
1757 // Enable/disable this component
1758 NS_METHOD nsWindow::Enable(PRBool bState)
1760 if (mWnd) {
1761 ::EnableWindow(mWnd, bState);
1763 return NS_OK;
1766 // Return the current enable state
1767 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
1769 NS_ENSURE_ARG_POINTER(aState);
1771 #ifndef WINCE
1772 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT)));
1773 #else
1774 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(mWnd));
1775 #endif
1777 return NS_OK;
1781 /**************************************************************
1783 * SECTION: nsIWidget::SetFocus
1785 * Give the focus to this widget.
1787 **************************************************************/
1789 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
1791 if (mWnd) {
1792 #ifdef WINSTATE_DEBUG_OUTPUT
1793 if (mWnd == GetTopLevelHWND(mWnd))
1794 printf("*** SetFocus: [ top] raise=%d\n", aRaise);
1795 else
1796 printf("*** SetFocus: [child] raise=%d\n", aRaise);
1797 #endif
1798 // Uniconify, if necessary
1799 HWND toplevelWnd = GetTopLevelHWND(mWnd);
1800 if (aRaise && ::IsIconic(toplevelWnd)) {
1801 ::ShowWindow(toplevelWnd, SW_RESTORE);
1803 ::SetFocus(mWnd);
1805 return NS_OK;
1809 /**************************************************************
1811 * SECTION: Bounds
1813 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1814 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1816 * Bound calculations.
1818 **************************************************************/
1820 // Return the window's full dimensions in screen coordinates.
1821 // If the window has a parent, converts the origin to an offset
1822 // of the parent's screen origin.
1823 NS_METHOD nsWindow::GetBounds(nsIntRect &aRect)
1825 if (mWnd) {
1826 RECT r;
1827 VERIFY(::GetWindowRect(mWnd, &r));
1829 // assign size
1830 aRect.width = r.right - r.left;
1831 aRect.height = r.bottom - r.top;
1833 // chrome on parent:
1834 // ___ 5,5 (chrome start)
1835 // | ____ 10,10 (client start)
1836 // | | ____ 20,20 (child start)
1837 // | | |
1838 // 20,20 - 5,5 = 15,15 (??)
1839 // minus GetClientOffset:
1840 // 15,15 - 5,5 = 10,10
1842 // no chrome on parent:
1843 // ______ 10,10 (win start)
1844 // | ____ 20,20 (child start)
1845 // | |
1846 // 20,20 - 10,10 = 10,10
1848 // walking the chain:
1849 // ___ 5,5 (chrome start)
1850 // | ___ 10,10 (client start)
1851 // | | ___ 20,20 (child start)
1852 // | | | __ 30,30 (child start)
1853 // | | | |
1854 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1855 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1856 // minus GetClientOffset:
1857 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1859 // convert coordinates if parent exists
1860 HWND parent = ::GetParent(mWnd);
1861 if (parent) {
1862 RECT pr;
1863 VERIFY(::GetWindowRect(parent, &pr));
1864 r.left -= pr.left;
1865 r.top -= pr.top;
1866 // adjust for chrome
1867 nsWindow* pWidget = static_cast<nsWindow*>(GetParent());
1868 if (pWidget && pWidget->IsTopLevelWidget()) {
1869 nsIntPoint clientOffset = pWidget->GetClientOffset();
1870 r.left -= clientOffset.x;
1871 r.top -= clientOffset.y;
1874 aRect.x = r.left;
1875 aRect.y = r.top;
1876 } else {
1877 aRect = mBounds;
1880 return NS_OK;
1883 // Get this component dimension
1884 NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect)
1886 if (mWnd) {
1887 RECT r;
1888 VERIFY(::GetClientRect(mWnd, &r));
1890 // assign size
1891 aRect.x = 0;
1892 aRect.y = 0;
1893 aRect.width = r.right - r.left;
1894 aRect.height = r.bottom - r.top;
1896 } else {
1897 aRect.SetRect(0,0,0,0);
1899 return NS_OK;
1902 // Like GetBounds, but don't offset by the parent
1903 NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect)
1905 if (mWnd) {
1906 RECT r;
1907 VERIFY(::GetWindowRect(mWnd, &r));
1909 aRect.width = r.right - r.left;
1910 aRect.height = r.bottom - r.top;
1911 aRect.x = r.left;
1912 aRect.y = r.top;
1913 } else
1914 aRect = mBounds;
1916 return NS_OK;
1919 // return the x,y offset of the client area from the origin
1920 // of the window. If the window is borderless returns (0,0).
1921 nsIntPoint nsWindow::GetClientOffset()
1923 if (!mWnd) {
1924 return nsIntPoint(0, 0);
1927 RECT r1;
1928 GetWindowRect(mWnd, &r1);
1929 nsIntPoint pt = WidgetToScreenOffset();
1930 return nsIntPoint(pt.x - r1.left, pt.y - r1.top);
1933 void
1934 nsWindow::SetDrawsInTitlebar(PRBool aState)
1936 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1937 if (window && window != this) {
1938 return window->SetDrawsInTitlebar(aState);
1941 if (aState) {
1942 // left, top, right, bottom for nsIntMargin
1943 nsIntMargin margins(-1, 0, -1, -1);
1944 SetNonClientMargins(margins);
1946 else {
1947 nsIntMargin margins(-1, -1, -1, -1);
1948 SetNonClientMargins(margins);
1952 NS_IMETHODIMP
1953 nsWindow::GetNonClientMargins(nsIntMargin &margins)
1955 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1956 if (window && window != this) {
1957 return window->GetNonClientMargins(margins);
1960 if (mCustomNonClient) {
1961 margins = mNonClientMargins;
1962 return NS_OK;
1965 margins.top = GetSystemMetrics(SM_CYCAPTION);
1966 margins.bottom = GetSystemMetrics(SM_CYFRAME);
1967 margins.top += margins.bottom;
1968 margins.left = margins.right = GetSystemMetrics(SM_CYFRAME);
1970 return NS_OK;
1973 void
1974 nsWindow::ResetLayout()
1976 // This will trigger a frame changed event, triggering
1977 // nc calc size and a sizemode gecko event.
1978 SetWindowPos(mWnd, 0, 0, 0, 0, 0,
1979 SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|
1980 SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
1982 // If hidden, just send the frame changed event for now.
1983 if (!mIsVisible)
1984 return;
1986 // Send a gecko size event to trigger reflow.
1987 RECT clientRc = {0};
1988 GetClientRect(mWnd, &clientRc);
1989 nsIntRect evRect(nsWindowGfx::ToIntRect(clientRc));
1990 OnResize(evRect);
1992 // Invalidate and update
1993 Invalidate(PR_FALSE);
1996 // Called when the window layout changes: full screen mode transitions,
1997 // theme changes, and composition changes. Calculates the new non-client
1998 // margins and fires off a frame changed event, which triggers an nc calc
1999 // size windows event, kicking the changes in.
2000 PRBool
2001 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode, PRBool aReflowWindow)
2003 if (!mCustomNonClient)
2004 return PR_FALSE;
2006 mNonClientOffset.top = mNonClientOffset.bottom =
2007 mNonClientOffset.left = mNonClientOffset.right = 0;
2009 if (aSizeMode == -1)
2010 aSizeMode = mSizeMode;
2012 if (aSizeMode == nsSizeMode_Minimized ||
2013 aSizeMode == nsSizeMode_Fullscreen) {
2014 mCaptionHeight = mVertResizeMargin = mHorResizeMargin = 0;
2015 return PR_TRUE;
2018 // Note, for maximized windows, we need to continue to offset the client by
2019 // thick frame margins of a normal window, since windows expects this
2020 // in it's DwmDefWndProc hit testing.
2021 mCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
2022 mHorResizeMargin = GetSystemMetrics(SM_CXFRAME);
2023 mVertResizeMargin = GetSystemMetrics(SM_CYFRAME);
2025 mCaptionHeight += mVertResizeMargin;
2027 // If a margin value is 0, set the offset to the default size of the frame.
2028 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2029 // so that the frame size is equal to the margin value.
2030 if (!mNonClientMargins.top)
2031 mNonClientOffset.top = mCaptionHeight;
2032 else if (mNonClientMargins.top > 0)
2033 mNonClientOffset.top = mCaptionHeight - mNonClientMargins.top;
2035 if (!mNonClientMargins.left)
2036 mNonClientOffset.left = mHorResizeMargin;
2037 else if (mNonClientMargins.left > 0)
2038 mNonClientOffset.left = mHorResizeMargin - mNonClientMargins.left;
2040 if (!mNonClientMargins.right)
2041 mNonClientOffset.right = mHorResizeMargin;
2042 else if (mNonClientMargins.right > 0)
2043 mNonClientOffset.right = mHorResizeMargin - mNonClientMargins.right;
2045 if (!mNonClientMargins.bottom)
2046 mNonClientOffset.bottom = mVertResizeMargin;
2047 else if (mNonClientMargins.bottom > 0)
2048 mNonClientOffset.bottom = mVertResizeMargin - mNonClientMargins.bottom;
2050 #ifndef WINCE
2051 if (aSizeMode == nsSizeMode_Maximized) {
2052 // Address an issue with auto-hide taskbars which fall behind the window.
2053 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2054 // the taskbar works properly.
2055 MONITORINFO info = {sizeof(MONITORINFO)};
2056 if (::GetMonitorInfo(::MonitorFromWindow(mWnd, MONITOR_DEFAULTTOPRIMARY),
2057 &info)) {
2058 RECT r;
2059 if (::GetWindowRect(mWnd, &r)) {
2060 // Adjust window rect to account for non-client margins.
2061 r.top += mVertResizeMargin - mNonClientOffset.top;
2062 r.left += mHorResizeMargin - mNonClientOffset.left;
2063 r.bottom -= mVertResizeMargin - mNonClientOffset.bottom;
2064 r.right -= mHorResizeMargin - mNonClientOffset.right;
2065 // Leave the 1 pixel margin if the window covers the monitor.
2066 if (r.top <= info.rcMonitor.top &&
2067 r.left <= info.rcMonitor.left &&
2068 r.right >= info.rcMonitor.right &&
2069 r.bottom >= info.rcMonitor.bottom)
2070 mNonClientOffset.bottom -= r.bottom - info.rcMonitor.bottom + 1;
2074 #endif
2076 if (aReflowWindow) {
2077 // Force a reflow of content based on the new client
2078 // dimensions.
2079 ResetLayout();
2082 return PR_TRUE;
2085 NS_IMETHODIMP
2086 nsWindow::SetNonClientMargins(nsIntMargin &margins)
2088 if (!mIsTopWidgetWindow ||
2089 mBorderStyle & eBorderStyle_none ||
2090 mHideChrome)
2091 return NS_ERROR_INVALID_ARG;
2093 // Request for a reset
2094 if (margins.top == -1 && margins.left == -1 &&
2095 margins.right == -1 && margins.bottom == -1) {
2096 mCustomNonClient = PR_FALSE;
2097 mNonClientMargins = margins;
2098 // Force a reflow of content based on the new client
2099 // dimensions.
2100 ResetLayout();
2101 return NS_OK;
2104 if (margins.top < -1 || margins.bottom < -1 ||
2105 margins.left < -1 || margins.right < -1)
2106 return NS_ERROR_INVALID_ARG;
2108 mNonClientMargins = margins;
2109 mCustomNonClient = PR_TRUE;
2110 if (!UpdateNonClientMargins()) {
2111 NS_WARNING("UpdateNonClientMargins failed!");
2112 return PR_FALSE;
2115 return NS_OK;
2118 void
2119 nsWindow::InvalidateNonClientRegion()
2121 // +-+-----------------------+-+
2122 // | | app non-client chrome | |
2123 // | +-----------------------+ |
2124 // | | app client chrome | | }
2125 // | +-----------------------+ | }
2126 // | | app content | | } area we don't want to invalidate
2127 // | +-----------------------+ | }
2128 // | | app client chrome | | }
2129 // | +-----------------------+ |
2130 // +---------------------------+ <
2131 // ^ ^ windows non-client chrome
2132 // client area = app *
2133 RECT rect;
2134 GetWindowRect(mWnd, &rect);
2135 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2136 HRGN winRgn = CreateRectRgnIndirect(&rect);
2138 // Subtract app client chrome and app content leaving
2139 // windows non-client chrome and app non-client chrome
2140 // in winRgn.
2141 GetWindowRect(mWnd, &rect);
2142 rect.top += mCaptionHeight;
2143 rect.right -= mHorResizeMargin;
2144 rect.bottom -= mHorResizeMargin;
2145 rect.left += mVertResizeMargin;
2146 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2147 HRGN clientRgn = CreateRectRgnIndirect(&rect);
2148 CombineRgn(winRgn, winRgn, clientRgn, RGN_DIFF);
2149 DeleteObject(clientRgn);
2151 // triggers ncpaint and paint events for the two areas
2152 RedrawWindow(mWnd, NULL, winRgn, RDW_FRAME|RDW_INVALIDATE);
2153 DeleteObject(winRgn);
2156 HRGN
2157 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion)
2159 RECT rect;
2160 HRGN rgn = NULL;
2161 if (aRegion == (HRGN)1) { // undocumented value indicating a full refresh
2162 GetWindowRect(mWnd, &rect);
2163 rgn = CreateRectRgnIndirect(&rect);
2164 } else {
2165 rgn = aRegion;
2167 GetClientRect(mWnd, &rect);
2168 MapWindowPoints(mWnd, NULL, (LPPOINT)&rect, 2);
2169 HRGN nonClientRgn = CreateRectRgnIndirect(&rect);
2170 CombineRgn(rgn, rgn, nonClientRgn, RGN_DIFF);
2171 DeleteObject(nonClientRgn);
2172 return rgn;
2175 /**************************************************************
2177 * SECTION: nsIWidget::SetBackgroundColor
2179 * Sets the window background paint color.
2181 **************************************************************/
2183 NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
2185 nsBaseWidget::SetBackgroundColor(aColor);
2187 if (mBrush)
2188 ::DeleteObject(mBrush);
2190 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
2191 #ifndef WINCE
2192 if (mWnd != NULL) {
2193 ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush);
2195 #endif
2196 return NS_OK;
2199 /**************************************************************
2201 * SECTION: nsIWidget::SetCursor
2203 * SetCursor and related utilities for manging cursor state.
2205 **************************************************************/
2207 // Set this component cursor
2208 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
2210 // Only change cursor if it's changing
2212 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2213 //XXX If we want this optimization we need a better way to do it.
2214 //if (aCursor != mCursor) {
2215 HCURSOR newCursor = NULL;
2217 switch (aCursor) {
2218 case eCursor_select:
2219 newCursor = ::LoadCursor(NULL, IDC_IBEAM);
2220 break;
2222 case eCursor_wait:
2223 newCursor = ::LoadCursor(NULL, IDC_WAIT);
2224 break;
2226 case eCursor_hyperlink:
2228 newCursor = ::LoadCursor(NULL, IDC_HAND);
2229 break;
2232 case eCursor_standard:
2233 newCursor = ::LoadCursor(NULL, IDC_ARROW);
2234 break;
2236 case eCursor_n_resize:
2237 case eCursor_s_resize:
2238 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2239 break;
2241 case eCursor_w_resize:
2242 case eCursor_e_resize:
2243 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2244 break;
2246 case eCursor_nw_resize:
2247 case eCursor_se_resize:
2248 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2249 break;
2251 case eCursor_ne_resize:
2252 case eCursor_sw_resize:
2253 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2254 break;
2256 case eCursor_crosshair:
2257 newCursor = ::LoadCursor(NULL, IDC_CROSS);
2258 break;
2260 case eCursor_move:
2261 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2262 break;
2264 case eCursor_help:
2265 newCursor = ::LoadCursor(NULL, IDC_HELP);
2266 break;
2268 case eCursor_copy: // CSS3
2269 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
2270 break;
2272 case eCursor_alias:
2273 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
2274 break;
2276 case eCursor_cell:
2277 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
2278 break;
2280 case eCursor_grab:
2281 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
2282 break;
2284 case eCursor_grabbing:
2285 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
2286 break;
2288 case eCursor_spinning:
2289 newCursor = ::LoadCursor(NULL, IDC_APPSTARTING);
2290 break;
2292 case eCursor_context_menu:
2293 // XXX this CSS3 cursor needs to be implemented
2294 break;
2296 case eCursor_zoom_in:
2297 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
2298 break;
2300 case eCursor_zoom_out:
2301 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
2302 break;
2304 case eCursor_not_allowed:
2305 case eCursor_no_drop:
2306 newCursor = ::LoadCursor(NULL, IDC_NO);
2307 break;
2309 case eCursor_col_resize:
2310 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
2311 break;
2313 case eCursor_row_resize:
2314 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
2315 break;
2317 case eCursor_vertical_text:
2318 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT));
2319 break;
2321 case eCursor_all_scroll:
2322 // XXX not 100% appropriate perhaps
2323 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2324 break;
2326 case eCursor_nesw_resize:
2327 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2328 break;
2330 case eCursor_nwse_resize:
2331 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2332 break;
2334 case eCursor_ns_resize:
2335 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2336 break;
2338 case eCursor_ew_resize:
2339 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2340 break;
2342 case eCursor_none:
2343 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
2344 break;
2346 default:
2347 NS_ERROR("Invalid cursor type");
2348 break;
2351 if (NULL != newCursor) {
2352 mCursor = aCursor;
2353 HCURSOR oldCursor = ::SetCursor(newCursor);
2355 if (sHCursor == oldCursor) {
2356 NS_IF_RELEASE(sCursorImgContainer);
2357 if (sHCursor != NULL)
2358 ::DestroyIcon(sHCursor);
2359 sHCursor = NULL;
2363 return NS_OK;
2366 // Setting the actual cursor
2367 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
2368 PRUint32 aHotspotX, PRUint32 aHotspotY)
2370 if (sCursorImgContainer == aCursor && sHCursor) {
2371 ::SetCursor(sHCursor);
2372 return NS_OK;
2375 PRInt32 width;
2376 PRInt32 height;
2378 nsresult rv;
2379 rv = aCursor->GetWidth(&width);
2380 NS_ENSURE_SUCCESS(rv, rv);
2381 rv = aCursor->GetHeight(&height);
2382 NS_ENSURE_SUCCESS(rv, rv);
2384 // Reject cursors greater than 128 pixels in either direction, to prevent
2385 // spoofing.
2386 // XXX ideally we should rescale. Also, we could modify the API to
2387 // allow trusted content to set larger cursors.
2388 if (width > 128 || height > 128)
2389 return NS_ERROR_NOT_AVAILABLE;
2391 HCURSOR cursor;
2392 rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
2393 NS_ENSURE_SUCCESS(rv, rv);
2395 mCursor = nsCursor(-1);
2396 ::SetCursor(cursor);
2398 NS_IF_RELEASE(sCursorImgContainer);
2399 sCursorImgContainer = aCursor;
2400 NS_ADDREF(sCursorImgContainer);
2402 if (sHCursor != NULL)
2403 ::DestroyIcon(sHCursor);
2404 sHCursor = cursor;
2406 return NS_OK;
2409 /**************************************************************
2411 * SECTION: nsIWidget::Get/SetTransparencyMode
2413 * Manage the transparency mode of the top-level window
2414 * containing this widget.
2416 **************************************************************/
2418 #ifdef MOZ_XUL
2419 nsTransparencyMode nsWindow::GetTransparencyMode()
2421 return GetTopLevelWindow(PR_TRUE)->GetWindowTranslucencyInner();
2424 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
2426 GetTopLevelWindow(PR_TRUE)->SetWindowTranslucencyInner(aMode);
2429 void nsWindow::UpdatePossiblyTransparentRegion(const nsIntRegion &aDirtyRegion,
2430 const nsIntRegion &aPossiblyTransparentRegion) {
2431 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2432 if (!HasGlass())
2433 return;
2435 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2436 nsWindow* topWindow = GetNSWindowPtr(hWnd);
2438 if (GetParent())
2439 return;
2441 mPossiblyTransparentRegion.Sub(mPossiblyTransparentRegion, aDirtyRegion);
2442 mPossiblyTransparentRegion.Or(mPossiblyTransparentRegion, aPossiblyTransparentRegion);
2444 nsIntRect clientBounds;
2445 topWindow->GetClientBounds(clientBounds);
2446 nsIntRegion opaqueRegion;
2447 opaqueRegion.Sub(clientBounds, mPossiblyTransparentRegion);
2449 MARGINS margins = { 0, 0, 0, 0 };
2450 DWORD_PTR dwStyle = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
2452 // If there is no opaque region or hidechrome=true, set margins
2453 // to support a full sheet of glass.
2454 if (opaqueRegion.IsEmpty() || mHideChrome) {
2455 // Comments in MSDN indicate all values must be set to -1
2456 margins.cxLeftWidth = margins.cxRightWidth =
2457 margins.cyTopHeight = margins.cyBottomHeight = -1;
2458 } else {
2459 // Find the largest rectangle and use that to calculate the inset
2460 nsIntRect largest = opaqueRegion.GetLargestRectangle();
2461 margins.cxLeftWidth = largest.x;
2462 margins.cxRightWidth = clientBounds.width - largest.XMost();
2463 margins.cyBottomHeight = clientBounds.height - largest.YMost();
2465 // The minimum glass height must be the caption buttons height,
2466 // otherwise the buttons are drawn incorrectly.
2467 margins.cyTopHeight = PR_MAX(largest.y, mCaptionButtons.height);
2470 // Only update glass area if there are changes
2471 if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) {
2472 mGlassMargins = margins;
2473 UpdateGlass();
2475 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2478 void nsWindow::UpdateGlass()
2480 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2481 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2482 MARGINS margins = mGlassMargins;
2484 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2485 // rendered based on the window style.
2486 // DWMNCRP_ENABLED - The non-client area rendering is
2487 // enabled; the window style is ignored.
2488 DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE;
2489 switch (mTransparencyMode) {
2490 case eTransparencyBorderlessGlass:
2491 // Only adjust if there is some opaque rectangle
2492 if (margins.cxLeftWidth >= 0) {
2493 const PRInt32 kGlassMarginAdjustment = 2;
2494 margins.cxLeftWidth += kGlassMarginAdjustment;
2495 margins.cyTopHeight += kGlassMarginAdjustment;
2496 margins.cxRightWidth += kGlassMarginAdjustment;
2497 margins.cyBottomHeight += kGlassMarginAdjustment;
2499 // Fall through
2500 case eTransparencyGlass:
2501 policy = DWMNCRP_ENABLED;
2502 break;
2505 // Extends the window frame behind the client area
2506 if(nsUXThemeData::CheckForCompositor()) {
2507 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd, &margins);
2508 nsUXThemeData::dwmSetWindowAttributePtr(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy);
2510 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2512 #endif
2514 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2515 void nsWindow::UpdateCaptionButtonsClippingRect()
2517 NS_ASSERTION(mWnd, "UpdateCaptionButtonsClippingRect called with invalid mWnd.");
2519 RECT captionButtons;
2520 mCaptionButtonsRoundedRegion.SetEmpty();
2521 mCaptionButtons.Empty();
2523 if (!mCustomNonClient ||
2524 mSizeMode == nsSizeMode_Fullscreen ||
2525 mSizeMode == nsSizeMode_Minimized ||
2526 !nsUXThemeData::CheckForCompositor() ||
2527 FAILED(nsUXThemeData::dwmGetWindowAttributePtr(mWnd,
2528 DWMWA_CAPTION_BUTTON_BOUNDS,
2529 &captionButtons,
2530 sizeof(captionButtons)))) {
2531 return;
2534 mCaptionButtons = nsWindowGfx::ToIntRect(captionButtons);
2536 // Adjustments to reported area
2537 PRInt32 leftMargin = (mNonClientMargins.left == -1) ? mHorResizeMargin : mNonClientMargins.left;
2539 // "leftMargin - 1" represents the resizer border and an
2540 // one pixel adjustment to hide the semi-transparent highlight.
2541 // The extra width is already excluded when the window is maximized.
2542 mCaptionButtons.x -= leftMargin - 1;
2544 if (mSizeMode != nsSizeMode_Maximized) {
2545 mCaptionButtons.width += leftMargin - 1;
2546 mCaptionButtons.height -= mVertResizeMargin + 1;
2547 } else {
2548 // Adjustments to the buttons' shift from the edge of the screen,
2549 // plus some apparently transparent drop shadow below them.
2550 mCaptionButtons.width -= 2;
2551 mCaptionButtons.height -= 3;
2554 // Create a rounded region by shrinking the 2 bottommost pixel rows from
2555 // the rect by 1 and 2 pixels.
2556 // mCaptionButtons: mCaptionButtonsRoundedRegion:
2557 // +-----------+ +-----------+
2558 // | | | |
2559 // | | | |
2560 // +-----------+ +-------+
2561 nsIntRect round1(mCaptionButtons.x, mCaptionButtons.y,
2562 mCaptionButtons.width, mCaptionButtons.height - 2);
2563 nsIntRect round2(mCaptionButtons.x + 1, mCaptionButtons.YMost() - 2,
2564 mCaptionButtons.width - 2, 1);
2565 nsIntRect round3(mCaptionButtons.x + 2, mCaptionButtons.YMost() - 1,
2566 mCaptionButtons.width - 4, 1);
2567 mCaptionButtonsRoundedRegion.Or(mCaptionButtonsRoundedRegion, round1);
2568 mCaptionButtonsRoundedRegion.Or(mCaptionButtonsRoundedRegion, round2);
2569 mCaptionButtonsRoundedRegion.Or(mCaptionButtonsRoundedRegion, round3);
2571 #endif
2573 /**************************************************************
2575 * SECTION: nsIWidget::HideWindowChrome
2577 * Show or hide window chrome.
2579 **************************************************************/
2581 NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide)
2583 HWND hwnd = GetTopLevelHWND(mWnd, PR_TRUE);
2584 if (!GetNSWindowPtr(hwnd))
2586 NS_WARNING("Trying to hide window decorations in an embedded context");
2587 return NS_ERROR_FAILURE;
2590 if (mHideChrome == aShouldHide)
2591 return NS_OK;
2593 DWORD_PTR style, exStyle;
2594 mHideChrome = aShouldHide;
2595 if (aShouldHide) {
2596 DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2597 DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2599 style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
2600 exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
2601 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
2603 mOldStyle = tempStyle;
2604 mOldExStyle = tempExStyle;
2606 else {
2607 if (!mOldStyle || !mOldExStyle) {
2608 mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2609 mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2612 style = mOldStyle;
2613 exStyle = mOldExStyle;
2616 VERIFY_WINDOW_STYLE(style);
2617 ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
2618 ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
2620 return NS_OK;
2623 /**************************************************************
2625 * SECTION: nsIWidget::Invalidate
2627 * Invalidate an area of the client for painting.
2629 **************************************************************/
2631 // Invalidate this component visible area
2632 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
2634 if (mWnd)
2636 #ifdef WIDGET_DEBUG_OUTPUT
2637 debug_DumpInvalidate(stdout,
2638 this,
2639 nsnull,
2640 aIsSynchronous,
2641 nsCAutoString("noname"),
2642 (PRInt32) mWnd);
2643 #endif // WIDGET_DEBUG_OUTPUT
2645 VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
2647 if (aIsSynchronous) {
2648 VERIFY(::UpdateWindow(mWnd));
2651 return NS_OK;
2654 // Invalidate this component visible area
2655 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, PRBool aIsSynchronous)
2657 if (mWnd)
2659 #ifdef WIDGET_DEBUG_OUTPUT
2660 debug_DumpInvalidate(stdout,
2661 this,
2662 &aRect,
2663 aIsSynchronous,
2664 nsCAutoString("noname"),
2665 (PRInt32) mWnd);
2666 #endif // WIDGET_DEBUG_OUTPUT
2668 RECT rect;
2670 rect.left = aRect.x;
2671 rect.top = aRect.y;
2672 rect.right = aRect.x + aRect.width;
2673 rect.bottom = aRect.y + aRect.height;
2675 VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
2677 if (aIsSynchronous) {
2678 VERIFY(::UpdateWindow(mWnd));
2681 return NS_OK;
2684 NS_IMETHODIMP
2685 nsWindow::MakeFullScreen(PRBool aFullScreen)
2687 #if WINCE_WINDOWS_MOBILE
2688 RECT rc;
2689 if (aFullScreen) {
2690 SetForegroundWindow(mWnd);
2691 if (nsWindowCE::sMenuBarShown) {
2692 SIPINFO sipInfo;
2693 memset(&sipInfo, 0, sizeof(SIPINFO));
2694 sipInfo.cbSize = sizeof(SIPINFO);
2695 if (SipGetInfo(&sipInfo))
2696 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2697 sipInfo.rcVisibleDesktop.bottom);
2698 else
2699 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2700 GetSystemMetrics(SM_CYSCREEN));
2701 RECT menuBarRect;
2702 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle, &menuBarRect) &&
2703 menuBarRect.top < rc.bottom)
2704 rc.bottom = menuBarRect.top;
2705 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_SHOWSIPBUTTON);
2706 } else {
2708 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);
2709 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2712 else {
2713 SHFullScreen(mWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
2714 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
2717 if (aFullScreen)
2718 mSizeMode = nsSizeMode_Fullscreen;
2720 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2721 HideWindowChrome(aFullScreen);
2722 Resize(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PR_TRUE);
2724 return NS_OK;
2726 #else
2728 mFullscreenMode = aFullScreen;
2729 if (aFullScreen) {
2730 if (mSizeMode == nsSizeMode_Fullscreen)
2731 return NS_OK;
2732 mOldSizeMode = mSizeMode;
2733 SetSizeMode(nsSizeMode_Fullscreen);
2734 } else {
2735 SetSizeMode(mOldSizeMode);
2738 UpdateNonClientMargins();
2740 // Will call hide chrome, reposition window. Note this will
2741 // also cache dimensions for restoration, so it should only
2742 // be called once per fullscreen request.
2743 nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen);
2745 // Let the dom know via web shell window
2746 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
2747 event.mSizeMode = mSizeMode;
2748 InitEvent(event);
2749 DispatchWindowEvent(&event);
2751 return rv;
2752 #endif
2755 /**************************************************************
2757 * SECTION: nsIWidget::Update
2759 * Force a synchronous repaint of the window.
2761 **************************************************************/
2763 NS_IMETHODIMP nsWindow::Update()
2765 nsresult rv = NS_OK;
2767 // updates can come through for windows no longer holding an mWnd during
2768 // deletes triggered by JavaScript in buttons with mouse feedback
2769 if (mWnd)
2770 VERIFY(::UpdateWindow(mWnd));
2772 return rv;
2775 /**************************************************************
2777 * SECTION: Native data storage
2779 * nsIWidget::GetNativeData
2780 * nsIWidget::FreeNativeData
2782 * Set or clear native data based on a constant.
2784 **************************************************************/
2786 // Return some native data according to aDataType
2787 void* nsWindow::GetNativeData(PRUint32 aDataType)
2789 switch (aDataType) {
2790 case NS_NATIVE_TMP_WINDOW:
2791 return (void*)::CreateWindowExW(WS_EX_NOACTIVATE |
2792 mIsRTL ? WS_EX_LAYOUTRTL : 0,
2793 WindowClass(),
2794 L"",
2795 WS_CHILD,
2796 CW_USEDEFAULT,
2797 CW_USEDEFAULT,
2798 CW_USEDEFAULT,
2799 CW_USEDEFAULT,
2800 mWnd,
2801 NULL,
2802 nsToolkit::mDllInstance,
2803 NULL);
2804 case NS_NATIVE_PLUGIN_PORT:
2805 case NS_NATIVE_WIDGET:
2806 case NS_NATIVE_WINDOW:
2807 return (void*)mWnd;
2808 case NS_NATIVE_GRAPHIC:
2809 // XXX: This is sleezy!! Remember to Release the DC after using it!
2810 #ifdef MOZ_XUL
2811 return (void*)(eTransparencyTransparent == mTransparencyMode) ?
2812 mMemoryDC : ::GetDC(mWnd);
2813 #else
2814 return (void*)::GetDC(mWnd);
2815 #endif
2817 #ifdef NS_ENABLE_TSF
2818 case NS_NATIVE_TSF_THREAD_MGR:
2819 return nsTextStore::GetThreadMgr();
2820 case NS_NATIVE_TSF_CATEGORY_MGR:
2821 return nsTextStore::GetCategoryMgr();
2822 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
2823 return nsTextStore::GetDisplayAttrMgr();
2824 #endif //NS_ENABLE_TSF
2826 default:
2827 break;
2830 return NULL;
2833 // Free some native data according to aDataType
2834 void nsWindow::FreeNativeData(void * data, PRUint32 aDataType)
2836 switch (aDataType)
2838 case NS_NATIVE_GRAPHIC:
2839 #ifdef MOZ_XUL
2840 if (eTransparencyTransparent != mTransparencyMode)
2841 ::ReleaseDC(mWnd, (HDC)data);
2842 #else
2843 ::ReleaseDC(mWnd, (HDC)data);
2844 #endif
2845 break;
2846 case NS_NATIVE_WIDGET:
2847 case NS_NATIVE_WINDOW:
2848 case NS_NATIVE_PLUGIN_PORT:
2849 break;
2850 default:
2851 break;
2855 /**************************************************************
2857 * SECTION: nsIWidget::SetTitle
2859 * Set the main windows title text.
2861 **************************************************************/
2863 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
2865 const nsString& strTitle = PromiseFlatString(aTitle);
2866 ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get());
2867 return NS_OK;
2870 /**************************************************************
2872 * SECTION: nsIWidget::SetIcon
2874 * Set the main windows icon.
2876 **************************************************************/
2878 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec)
2880 #ifndef WINCE
2881 // Assume the given string is a local identifier for an icon file.
2883 nsCOMPtr<nsILocalFile> iconFile;
2884 ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
2885 getter_AddRefs(iconFile));
2886 if (!iconFile)
2887 return NS_OK; // not an error if icon is not found
2889 nsAutoString iconPath;
2890 iconFile->GetPath(iconPath);
2892 // XXX this should use MZLU (see bug 239279)
2894 ::SetLastError(0);
2896 HICON bigIcon = (HICON)::LoadImageW(NULL,
2897 (LPCWSTR)iconPath.get(),
2898 IMAGE_ICON,
2899 ::GetSystemMetrics(SM_CXICON),
2900 ::GetSystemMetrics(SM_CYICON),
2901 LR_LOADFROMFILE );
2902 HICON smallIcon = (HICON)::LoadImageW(NULL,
2903 (LPCWSTR)iconPath.get(),
2904 IMAGE_ICON,
2905 ::GetSystemMetrics(SM_CXSMICON),
2906 ::GetSystemMetrics(SM_CYSMICON),
2907 LR_LOADFROMFILE );
2909 if (bigIcon) {
2910 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon);
2911 if (icon)
2912 ::DestroyIcon(icon);
2914 #ifdef DEBUG_SetIcon
2915 else {
2916 NS_LossyConvertUTF16toASCII cPath(iconPath);
2917 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2919 #endif
2920 if (smallIcon) {
2921 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon);
2922 if (icon)
2923 ::DestroyIcon(icon);
2925 #ifdef DEBUG_SetIcon
2926 else {
2927 NS_LossyConvertUTF16toASCII cPath(iconPath);
2928 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2930 #endif
2931 #endif // WINCE
2932 return NS_OK;
2935 /**************************************************************
2937 * SECTION: nsIWidget::WidgetToScreenOffset
2939 * Return this widget's origin in screen coordinates.
2941 **************************************************************/
2943 nsIntPoint nsWindow::WidgetToScreenOffset()
2945 POINT point;
2946 point.x = 0;
2947 point.y = 0;
2948 ::ClientToScreen(mWnd, &point);
2949 return nsIntPoint(point.x, point.y);
2952 nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize)
2954 if (!IsPopupWithTitleBar())
2955 return aClientSize;
2957 // just use (200, 200) as the position
2958 RECT r;
2959 r.left = 200;
2960 r.top = 200;
2961 r.right = 200 + aClientSize.width;
2962 r.bottom = 200 + aClientSize.height;
2963 ::AdjustWindowRectEx(&r, WindowStyle(), PR_FALSE, WindowExStyle());
2965 return nsIntSize(r.right - r.left, r.bottom - r.top);
2968 /**************************************************************
2970 * SECTION: nsIWidget::EnableDragDrop
2972 * Enables/Disables drag and drop of files on this widget.
2974 **************************************************************/
2976 #if !defined(WINCE) // implemented in nsWindowCE.cpp
2977 NS_METHOD nsWindow::EnableDragDrop(PRBool aEnable)
2979 NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()");
2981 nsresult rv = NS_ERROR_FAILURE;
2982 if (aEnable) {
2983 if (nsnull == mNativeDragTarget) {
2984 mNativeDragTarget = new nsNativeDragTarget(this);
2985 if (NULL != mNativeDragTarget) {
2986 mNativeDragTarget->AddRef();
2987 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) {
2988 if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) {
2989 rv = NS_OK;
2994 } else {
2995 if (nsnull != mWnd && NULL != mNativeDragTarget) {
2996 ::RevokeDragDrop(mWnd);
2997 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) {
2998 rv = NS_OK;
3000 mNativeDragTarget->DragCancel();
3001 NS_RELEASE(mNativeDragTarget);
3004 return rv;
3006 #endif
3008 /**************************************************************
3010 * SECTION: nsIWidget::CaptureMouse
3012 * Enables/Disables system mouse capture.
3014 **************************************************************/
3016 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
3018 if (!nsToolkit::gMouseTrailer) {
3019 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3020 return NS_OK;
3023 if (aCapture) {
3024 nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd);
3025 ::SetCapture(mWnd);
3026 } else {
3027 nsToolkit::gMouseTrailer->SetCaptureWindow(NULL);
3028 ::ReleaseCapture();
3030 mIsInMouseCapture = aCapture;
3031 return NS_OK;
3034 /**************************************************************
3036 * SECTION: nsIWidget::CaptureRollupEvents
3038 * Dealing with event rollup on destroy for popups. Enables &
3039 * Disables system capture of any and all events that would
3040 * cause a dropdown to be rolled up.
3042 **************************************************************/
3044 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
3045 nsIMenuRollup * aMenuRollup,
3046 PRBool aDoCapture,
3047 PRBool aConsumeRollupEvent)
3049 if (aDoCapture) {
3050 /* we haven't bothered carrying a weak reference to sRollupWidget because
3051 we believe lifespan is properly scoped. this next assertion helps
3052 assure that remains true. */
3053 NS_ASSERTION(!sRollupWidget, "rollup widget reassigned before release");
3054 sRollupConsumeEvent = aConsumeRollupEvent;
3055 NS_IF_RELEASE(sRollupWidget);
3056 NS_IF_RELEASE(sMenuRollup);
3057 sRollupListener = aListener;
3058 sMenuRollup = aMenuRollup;
3059 NS_IF_ADDREF(aMenuRollup);
3060 sRollupWidget = this;
3061 NS_ADDREF(this);
3063 #ifndef WINCE
3064 if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
3065 RegisterSpecialDropdownHooks();
3067 sProcessHook = PR_TRUE;
3068 #endif
3070 } else {
3071 sRollupListener = nsnull;
3072 NS_IF_RELEASE(sMenuRollup);
3073 NS_IF_RELEASE(sRollupWidget);
3075 #ifndef WINCE
3076 sProcessHook = PR_FALSE;
3077 UnregisterSpecialDropdownHooks();
3078 #endif
3081 return NS_OK;
3084 /**************************************************************
3086 * SECTION: nsIWidget::GetAttention
3088 * Bring this window to the user's attention.
3090 **************************************************************/
3092 // Draw user's attention to this window until it comes to foreground.
3093 NS_IMETHODIMP
3094 nsWindow::GetAttention(PRInt32 aCycleCount)
3096 #ifndef WINCE
3097 // Got window?
3098 if (!mWnd)
3099 return NS_ERROR_NOT_INITIALIZED;
3101 // Don't flash if the flash count is 0 or if the
3102 // top level window is already active.
3103 HWND fgWnd = ::GetForegroundWindow();
3104 if (aCycleCount == 0 || fgWnd == GetTopLevelHWND(mWnd))
3105 return NS_OK;
3107 HWND flashWnd = mWnd;
3108 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3109 flashWnd = ownerWnd;
3112 // Don't flash if the owner window is active either.
3113 if (fgWnd == flashWnd)
3114 return NS_OK;
3116 DWORD defaultCycleCount = 0;
3117 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
3119 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3120 FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 };
3121 ::FlashWindowEx(&flashInfo);
3122 #endif
3123 return NS_OK;
3126 void nsWindow::StopFlashing()
3128 #ifndef WINCE
3129 HWND flashWnd = mWnd;
3130 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3131 flashWnd = ownerWnd;
3134 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3135 FLASHW_STOP, 0, 0 };
3136 ::FlashWindowEx(&flashInfo);
3137 #endif
3140 /**************************************************************
3142 * SECTION: nsIWidget::HasPendingInputEvent
3144 * Ask whether there user input events pending. All input events are
3145 * included, including those not targeted at this nsIwidget instance.
3147 **************************************************************/
3149 PRBool
3150 nsWindow::HasPendingInputEvent()
3152 // If there is pending input or the user is currently
3153 // moving the window then return true.
3154 // Note: When the user is moving the window WIN32 spins
3155 // a separate event loop and input events are not
3156 // reported to the application.
3157 if (HIWORD(GetQueueStatus(QS_INPUT)))
3158 return PR_TRUE;
3159 #ifdef WINCE
3160 return PR_FALSE;
3161 #else
3162 GUITHREADINFO guiInfo;
3163 guiInfo.cbSize = sizeof(GUITHREADINFO);
3164 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo))
3165 return PR_FALSE;
3166 return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE);
3167 #endif
3170 /**************************************************************
3172 * SECTION: nsIWidget::GetLayerManager
3174 * Get the layer manager associated with this widget.
3176 **************************************************************/
3178 mozilla::layers::LayerManager*
3179 nsWindow::GetLayerManager()
3181 #ifndef WINCE
3182 if (!mLayerManager) {
3183 nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3185 PRBool accelerateByDefault = PR_TRUE;
3186 PRBool disableAcceleration = PR_FALSE;
3187 PRBool preferOpenGL = PR_FALSE;
3188 if (prefs) {
3189 prefs->GetBoolPref("layers.accelerate-all",
3190 &accelerateByDefault);
3191 prefs->GetBoolPref("layers.accelerate-none",
3192 &disableAcceleration);
3193 prefs->GetBoolPref("layers.prefer-opengl",
3194 &preferOpenGL);
3197 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
3198 accelerateByDefault = accelerateByDefault ||
3199 (acceleratedEnv && (*acceleratedEnv != '0'));
3201 /* We don't currently support using an accelerated layer manager with
3202 * transparent windows so don't even try. I'm also not sure if we even
3203 * want to support this case. See bug #593471 */
3204 disableAcceleration = disableAcceleration ||
3205 eTransparencyTransparent == mTransparencyMode;
3207 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
3208 PRBool safeMode = PR_FALSE;
3209 if (xr)
3210 xr->GetInSafeMode(&safeMode);
3212 if (disableAcceleration || safeMode)
3213 mUseAcceleratedRendering = PR_FALSE;
3214 else if (accelerateByDefault)
3215 mUseAcceleratedRendering = PR_TRUE;
3217 if (mUseAcceleratedRendering) {
3218 #ifdef MOZ_ENABLE_D3D9_LAYER
3219 if (!preferOpenGL) {
3220 nsRefPtr<mozilla::layers::LayerManagerD3D9> layerManager =
3221 new mozilla::layers::LayerManagerD3D9(this);
3222 if (layerManager->Initialize()) {
3223 mLayerManager = layerManager;
3226 #endif
3227 if (!mLayerManager && preferOpenGL) {
3228 nsRefPtr<mozilla::layers::LayerManagerOGL> layerManager =
3229 new mozilla::layers::LayerManagerOGL(this);
3230 if (layerManager->Initialize()) {
3231 mLayerManager = layerManager;
3236 // Fall back to software if we couldn't use any hardware backends.
3237 if (!mLayerManager)
3238 mLayerManager = new BasicLayerManager(this);
3240 #endif
3242 return mLayerManager;
3245 /**************************************************************
3247 * SECTION: nsIWidget::GetThebesSurface
3249 * Get the Thebes surface associated with this widget.
3251 **************************************************************/
3253 gfxASurface *nsWindow::GetThebesSurface()
3255 #ifdef CAIRO_HAS_D2D_SURFACE
3256 if (mD2DWindowSurface) {
3257 return mD2DWindowSurface;
3259 #endif
3260 if (mPaintDC)
3261 return (new gfxWindowsSurface(mPaintDC));
3263 #ifdef CAIRO_HAS_D2D_SURFACE
3264 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3265 gfxWindowsPlatform::RENDER_DIRECT2D) {
3266 gfxASurface::gfxContentType content = gfxASurface::CONTENT_COLOR;
3267 #if defined(MOZ_XUL)
3268 if (mTransparencyMode != eTransparencyOpaque) {
3269 content = gfxASurface::CONTENT_COLOR_ALPHA;
3271 #endif
3272 return (new gfxD2DSurface(mWnd, content));
3273 } else {
3274 #endif
3275 PRUint32 flags = gfxWindowsSurface::FLAG_TAKE_DC;
3276 if (mTransparencyMode != eTransparencyOpaque) {
3277 flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT;
3279 return (new gfxWindowsSurface(mWnd, flags));
3280 #ifdef CAIRO_HAS_D2D_SURFACE
3282 #endif
3285 /**************************************************************
3287 * SECTION: nsIWidget::OnDefaultButtonLoaded
3289 * Called after the dialog is loaded and it has a default button.
3291 **************************************************************/
3293 NS_IMETHODIMP
3294 nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect)
3296 #ifdef WINCE
3297 return NS_ERROR_NOT_IMPLEMENTED;
3298 #else
3299 if (aButtonRect.IsEmpty())
3300 return NS_OK;
3302 // Don't snap when we are not active.
3303 HWND activeWnd = ::GetActiveWindow();
3304 if (activeWnd != ::GetForegroundWindow() ||
3305 GetTopLevelHWND(mWnd, PR_TRUE) != GetTopLevelHWND(activeWnd, PR_TRUE)) {
3306 return NS_OK;
3309 PRBool isAlwaysSnapCursor = PR_FALSE;
3310 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3311 if (prefs) {
3312 nsCOMPtr<nsIPrefBranch> prefBranch;
3313 prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
3314 if (prefBranch) {
3315 prefBranch->GetBoolPref("ui.cursor_snapping.always_enabled",
3316 &isAlwaysSnapCursor);
3320 if (!isAlwaysSnapCursor) {
3321 BOOL snapDefaultButton;
3322 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0,
3323 &snapDefaultButton, 0) || !snapDefaultButton)
3324 return NS_OK;
3327 nsIntRect widgetRect;
3328 nsresult rv = GetScreenBounds(widgetRect);
3329 NS_ENSURE_SUCCESS(rv, rv);
3330 nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft());
3332 nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2,
3333 buttonRect.y + buttonRect.height / 2);
3334 // The center of the button can be outside of the widget.
3335 // E.g., it could be hidden by scrolling.
3336 if (!widgetRect.Contains(centerOfButton)) {
3337 return NS_OK;
3340 if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) {
3341 NS_ERROR("SetCursorPos failed");
3342 return NS_ERROR_FAILURE;
3344 return NS_OK;
3345 #endif
3348 NS_IMETHODIMP
3349 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta,
3350 PRBool aIsHorizontal,
3351 PRInt32 &aOverriddenDelta)
3353 // The default vertical and horizontal scrolling speed is 3, this is defined
3354 // on the document of SystemParametersInfo in MSDN.
3355 const PRUint32 kSystemDefaultScrollingSpeed = 3;
3357 PRInt32 absOriginDelta = PR_ABS(aOriginalDelta);
3359 // Compute the simple overridden speed.
3360 PRInt32 absComputedOverriddenDelta;
3361 nsresult rv =
3362 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta, aIsHorizontal,
3363 absComputedOverriddenDelta);
3364 NS_ENSURE_SUCCESS(rv, rv);
3366 aOverriddenDelta = aOriginalDelta;
3368 if (absComputedOverriddenDelta == absOriginDelta) {
3369 // We don't override now.
3370 return NS_OK;
3373 // Otherwise, we should check whether the user customized the system settings
3374 // or not. If the user did it, we should respect the will.
3375 UINT systemSpeed;
3376 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) {
3377 return NS_ERROR_FAILURE;
3379 // The default vertical scrolling speed is 3, this is defined on the document
3380 // of SystemParametersInfo in MSDN.
3381 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3382 return NS_OK;
3385 // Only Vista and later, Windows has the system setting of horizontal
3386 // scrolling by the mouse wheel.
3387 if (GetWindowsVersion() >= VISTA_VERSION) {
3388 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) {
3389 return NS_ERROR_FAILURE;
3391 // The default horizontal scrolling speed is 3, this is defined on the
3392 // document of SystemParametersInfo in MSDN.
3393 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3394 return NS_OK;
3398 // Limit the overridden delta value from the system settings. The mouse
3399 // driver might accelerate the scrolling speed already. If so, we shouldn't
3400 // override the scrolling speed for preventing the unexpected high speed
3401 // scrolling.
3402 PRInt32 absDeltaLimit;
3403 rv =
3404 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed,
3405 aIsHorizontal, absDeltaLimit);
3406 NS_ENSURE_SUCCESS(rv, rv);
3408 // If the given delta is larger than our computed limitation value, the delta
3409 // was accelerated by the mouse driver. So, we should do nothing here.
3410 if (absDeltaLimit <= absOriginDelta) {
3411 return NS_OK;
3414 absComputedOverriddenDelta =
3415 PR_MIN(absComputedOverriddenDelta, absDeltaLimit);
3417 aOverriddenDelta = (aOriginalDelta > 0) ? absComputedOverriddenDelta :
3418 -absComputedOverriddenDelta;
3419 return NS_OK;
3422 /**************************************************************
3423 **************************************************************
3425 ** BLOCK: Moz Events
3427 ** Moz GUI event management.
3429 **************************************************************
3430 **************************************************************/
3432 /**************************************************************
3434 * SECTION: Mozilla event initialization
3436 * Helpers for initializing moz events.
3438 **************************************************************/
3440 // Event intialization
3441 MSG nsWindow::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam)
3443 MSG msg;
3444 msg.message = aMessage;
3445 msg.wParam = wParam;
3446 msg.lParam = lParam;
3447 return msg;
3450 void nsWindow::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
3452 if (nsnull == aPoint) { // use the point from the event
3453 // get the message position in client coordinates
3454 if (mWnd != NULL) {
3456 DWORD pos = ::GetMessagePos();
3457 POINT cpos;
3459 cpos.x = GET_X_LPARAM(pos);
3460 cpos.y = GET_Y_LPARAM(pos);
3462 ::ScreenToClient(mWnd, &cpos);
3463 event.refPoint.x = cpos.x;
3464 event.refPoint.y = cpos.y;
3465 } else {
3466 event.refPoint.x = 0;
3467 event.refPoint.y = 0;
3470 else {
3471 // use the point override if provided
3472 event.refPoint.x = aPoint->x;
3473 event.refPoint.y = aPoint->y;
3476 #ifndef WINCE
3477 event.time = ::GetMessageTime();
3478 #else
3479 event.time = PR_Now() / 1000;
3480 #endif
3482 mLastPoint = event.refPoint;
3485 /**************************************************************
3487 * SECTION: Moz event dispatch helpers
3489 * Helpers for dispatching different types of moz events.
3491 **************************************************************/
3493 // Main event dispatch. Invokes callback and ProcessEvent method on
3494 // Event Listener object. Part of nsIWidget.
3495 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
3497 #ifdef WIDGET_DEBUG_OUTPUT
3498 debug_DumpEvent(stdout,
3499 event->widget,
3500 event,
3501 nsCAutoString("something"),
3502 (PRInt32) mWnd);
3503 #endif // WIDGET_DEBUG_OUTPUT
3505 aStatus = nsEventStatus_eIgnore;
3507 // skip processing of suppressed blur events
3508 if (event->message == NS_DEACTIVATE && BlurEventsSuppressed())
3509 return NS_OK;
3511 // Top level windows can have a view attached which requires events be sent
3512 // to the underlying base window and the view. Added when we combined the
3513 // base chrome window with the main content child for nc client area (title
3514 // bar) rendering.
3515 if (mViewCallback) {
3516 // A subset of events are sent to the base xul window first
3517 switch(event->message) {
3518 // send to the base window (view mgr ignores these for the view)
3519 case NS_UISTATECHANGED:
3520 case NS_DESTROY:
3521 case NS_SETZLEVEL:
3522 case NS_XUL_CLOSE:
3523 case NS_MOVE:
3524 (*mEventCallback)(event); // web shell / xul window
3525 return NS_OK;
3527 // sent to the base window, then to the view
3528 case NS_SIZE:
3529 case NS_DEACTIVATE:
3530 case NS_ACTIVATE:
3531 case NS_SIZEMODE:
3532 (*mEventCallback)(event); // web shell / xul window
3533 break;
3535 // attached view events
3536 aStatus = (*mViewCallback)(event);
3538 else if (mEventCallback) {
3539 aStatus = (*mEventCallback)(event);
3542 // the window can be destroyed during processing of seemingly innocuous events like, say,
3543 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3544 // which causes problems with the deleted window. therefore:
3545 if (mOnDestroyCalled)
3546 aStatus = nsEventStatus_eConsumeNoDefault;
3547 return NS_OK;
3550 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
3552 nsGUIEvent event(PR_TRUE, aMsg, this);
3553 InitEvent(event);
3555 PRBool result = DispatchWindowEvent(&event);
3556 return result;
3559 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
3561 nsEventStatus status;
3562 DispatchEvent(event, status);
3563 return ConvertStatus(status);
3566 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event, nsEventStatus &aStatus) {
3567 DispatchEvent(event, aStatus);
3568 return ConvertStatus(aStatus);
3571 PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
3572 const nsTArray<nsAlternativeCharCode>* aAlternativeCharCodes,
3573 UINT aVirtualCharCode, const MSG *aMsg,
3574 const nsModifierKeyState &aModKeyState,
3575 PRUint32 aFlags)
3577 UserActivity();
3579 nsKeyEvent event(PR_TRUE, aEventType, this);
3580 nsIntPoint point(0, 0);
3582 InitEvent(event, &point); // this add ref's event.widget
3584 event.flags |= aFlags;
3585 event.charCode = aCharCode;
3586 if (aAlternativeCharCodes)
3587 event.alternativeCharCodes.AppendElements(*aAlternativeCharCodes);
3588 event.keyCode = aVirtualCharCode;
3590 #ifdef KE_DEBUG
3591 static cnt=0;
3592 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt++,
3593 (NS_KEY_PRESS == aEventType) ? "PRESS" : (aEventType == NS_KEY_UP ? "Up" : "Down"),
3594 event.charCode, event.keyCode);
3595 printf("Shift: %s Control %s Alt: %s \n",
3596 (mIsShiftDown ? "D" : "U"), (mIsControlDown ? "D" : "U"), (mIsAltDown ? "D" : "U"));
3597 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3598 IS_VK_DOWN(NS_VK_SHIFT) ? 'S' : ' ',
3599 IS_VK_DOWN(NS_VK_CONTROL) ? 'C' : ' ',
3600 IS_VK_DOWN(NS_VK_ALT) ? 'A' : ' ',
3601 IS_VK_DOWN(VK_LSHIFT) ? 'S' : ' ',
3602 IS_VK_DOWN(VK_LCONTROL) ? 'C' : ' ',
3603 IS_VK_DOWN(VK_LMENU) ? 'A' : ' ',
3604 IS_VK_DOWN(VK_RMENU) ? 'A' : ' ',
3605 IS_VK_DOWN(VK_RCONTROL) ? 'C' : ' ',
3606 IS_VK_DOWN(VK_RSHIFT) ? 'S' : ' ');
3607 #endif
3609 event.isShift = aModKeyState.mIsShiftDown;
3610 event.isControl = aModKeyState.mIsControlDown;
3611 event.isMeta = PR_FALSE;
3612 event.isAlt = aModKeyState.mIsAltDown;
3614 NPEvent pluginEvent;
3615 if (aMsg && PluginHasFocus()) {
3616 pluginEvent.event = aMsg->message;
3617 pluginEvent.wParam = aMsg->wParam;
3618 pluginEvent.lParam = aMsg->lParam;
3619 event.pluginEvent = (void *)&pluginEvent;
3622 PRBool result = DispatchWindowEvent(&event);
3624 return result;
3627 PRBool nsWindow::DispatchCommandEvent(PRUint32 aEventCommand)
3629 nsCOMPtr<nsIAtom> command;
3630 switch (aEventCommand) {
3631 case APPCOMMAND_BROWSER_BACKWARD:
3632 command = nsWidgetAtoms::Back;
3633 break;
3634 case APPCOMMAND_BROWSER_FORWARD:
3635 command = nsWidgetAtoms::Forward;
3636 break;
3637 case APPCOMMAND_BROWSER_REFRESH:
3638 command = nsWidgetAtoms::Reload;
3639 break;
3640 case APPCOMMAND_BROWSER_STOP:
3641 command = nsWidgetAtoms::Stop;
3642 break;
3643 case APPCOMMAND_BROWSER_SEARCH:
3644 command = nsWidgetAtoms::Search;
3645 break;
3646 case APPCOMMAND_BROWSER_FAVORITES:
3647 command = nsWidgetAtoms::Bookmarks;
3648 break;
3649 case APPCOMMAND_BROWSER_HOME:
3650 command = nsWidgetAtoms::Home;
3651 break;
3652 default:
3653 return PR_FALSE;
3655 nsCommandEvent event(PR_TRUE, nsWidgetAtoms::onAppCommand, command, this);
3657 InitEvent(event);
3658 DispatchWindowEvent(&event);
3660 return PR_TRUE;
3663 // Recursively dispatch synchronous paints for nsIWidget
3664 // descendants with invalidated rectangles.
3665 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
3667 LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
3668 if (proc == (LONG_PTR)&nsWindow::WindowProc) {
3669 // its one of our windows so check to see if it has a
3670 // invalidated rect. If it does. Dispatch a synchronous
3671 // paint.
3672 if (GetUpdateRect(aWnd, NULL, FALSE))
3673 VERIFY(::UpdateWindow(aWnd));
3675 return TRUE;
3678 // Check for pending paints and dispatch any pending paint
3679 // messages for any nsIWidget which is a descendant of the
3680 // top-level window that *this* window is embedded within.
3682 // Note: We do not dispatch pending paint messages for non
3683 // nsIWidget managed windows.
3684 void nsWindow::DispatchPendingEvents()
3686 if (mPainting) {
3687 NS_WARNING("We were asked to dispatch pending events during painting, "
3688 "denying since that's unsafe.");
3689 return;
3692 // We need to ensure that reflow events do not get starved.
3693 // At the same time, we don't want to recurse through here
3694 // as that would prevent us from dispatching starved paints.
3695 static int recursionBlocker = 0;
3696 if (recursionBlocker++ == 0) {
3697 NS_ProcessPendingEvents(nsnull, PR_MillisecondsToInterval(100));
3698 --recursionBlocker;
3701 // Quickly check to see if there are any
3702 // paint events pending.
3703 if (::GetQueueStatus(QS_PAINT)) {
3704 // Find the top level window.
3705 HWND topWnd = GetTopLevelHWND(mWnd);
3707 // Dispatch pending paints for all topWnd's descendant windows.
3708 // Note: EnumChildWindows enumerates all descendant windows not just
3709 // it's children.
3710 #if !defined(WINCE)
3711 ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, 0);
3712 #else
3713 nsWindowCE::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3714 #endif
3718 // Deal with plugin events
3719 PRBool nsWindow::DispatchPluginEvent(const MSG &aMsg)
3721 if (!PluginHasFocus())
3722 return PR_FALSE;
3724 nsGUIEvent event(PR_TRUE, NS_PLUGIN_EVENT, this);
3725 nsIntPoint point(0, 0);
3726 InitEvent(event, &point);
3727 NPEvent pluginEvent;
3728 pluginEvent.event = aMsg.message;
3729 pluginEvent.wParam = aMsg.wParam;
3730 pluginEvent.lParam = aMsg.lParam;
3731 event.pluginEvent = (void *)&pluginEvent;
3732 return DispatchWindowEvent(&event);
3735 PRBool nsWindow::DispatchPluginEvent(UINT aMessage,
3736 WPARAM aWParam,
3737 LPARAM aLParam,
3738 PRBool aDispatchPendingEvents)
3740 PRBool ret = DispatchPluginEvent(InitMSG(aMessage, aWParam, aLParam));
3741 if (aDispatchPendingEvents) {
3742 DispatchPendingEvents();
3744 return ret;
3747 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
3748 UINT aLastMsg)
3750 MSG msg;
3751 ::GetMessageW(&msg, mWnd, aFirstMsg, aLastMsg);
3752 DispatchPluginEvent(msg);
3755 // Deal with all sort of mouse event
3756 PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
3757 LPARAM lParam, PRBool aIsContextMenuKey,
3758 PRInt16 aButton, PRUint16 aInputSource)
3760 PRBool result = PR_FALSE;
3762 UserActivity();
3764 if (!mEventCallback) {
3765 return result;
3768 switch (aEventType) {
3769 case NS_MOUSE_BUTTON_DOWN:
3770 CaptureMouse(PR_TRUE);
3771 break;
3773 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3774 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3775 case NS_MOUSE_BUTTON_UP:
3776 case NS_MOUSE_MOVE:
3777 case NS_MOUSE_EXIT:
3778 if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && mIsInMouseCapture)
3779 CaptureMouse(PR_FALSE);
3780 break;
3782 default:
3783 break;
3785 } // switch
3787 nsIntPoint eventPoint;
3788 eventPoint.x = GET_X_LPARAM(lParam);
3789 eventPoint.y = GET_Y_LPARAM(lParam);
3791 nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal,
3792 aIsContextMenuKey
3793 ? nsMouseEvent::eContextMenuKey
3794 : nsMouseEvent::eNormal);
3795 if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) {
3796 nsIntPoint zero(0, 0);
3797 InitEvent(event, &zero);
3798 } else {
3799 InitEvent(event, &eventPoint);
3802 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
3803 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
3804 event.isMeta = PR_FALSE;
3805 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
3806 event.button = aButton;
3807 event.inputSource = aInputSource;
3809 nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
3811 // Suppress mouse moves caused by widget creation
3812 if (aEventType == NS_MOUSE_MOVE)
3814 if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y))
3815 return result;
3816 sLastMouseMovePoint.x = mpScreen.x;
3817 sLastMouseMovePoint.y = mpScreen.y;
3820 PRBool insideMovementThreshold = (abs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
3821 (abs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
3823 BYTE eventButton;
3824 switch (aButton) {
3825 case nsMouseEvent::eLeftButton:
3826 eventButton = VK_LBUTTON;
3827 break;
3828 case nsMouseEvent::eMiddleButton:
3829 eventButton = VK_MBUTTON;
3830 break;
3831 case nsMouseEvent::eRightButton:
3832 eventButton = VK_RBUTTON;
3833 break;
3834 default:
3835 eventButton = 0;
3836 break;
3839 // Doubleclicks are used to set the click count, then changed to mousedowns
3840 // We're going to time double-clicks from mouse *up* to next mouse *down*
3841 #ifndef WINCE
3842 LONG curMsgTime = ::GetMessageTime();
3843 #else
3844 LONG curMsgTime = PR_Now() / 1000;
3845 #endif
3847 if (aEventType == NS_MOUSE_DOUBLECLICK) {
3848 event.message = NS_MOUSE_BUTTON_DOWN;
3849 event.button = aButton;
3850 sLastClickCount = 2;
3852 else if (aEventType == NS_MOUSE_BUTTON_UP) {
3853 // remember when this happened for the next mouse down
3854 sLastMousePoint.x = eventPoint.x;
3855 sLastMousePoint.y = eventPoint.y;
3856 sLastMouseButton = eventButton;
3858 else if (aEventType == NS_MOUSE_BUTTON_DOWN) {
3859 // now look to see if we want to convert this to a double- or triple-click
3860 if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold &&
3861 eventButton == sLastMouseButton) {
3862 sLastClickCount ++;
3863 } else {
3864 // reset the click count, to count *this* click
3865 sLastClickCount = 1;
3867 // Set last Click time on MouseDown only
3868 sLastMouseDownTime = curMsgTime;
3870 else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
3871 sLastClickCount = 0;
3873 else if (aEventType == NS_MOUSE_EXIT) {
3874 event.exit = IsTopLevelMouseExit(mWnd) ? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
3876 else if (aEventType == NS_MOUSE_MOZHITTEST)
3878 event.flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
3880 event.clickCount = sLastClickCount;
3882 #ifdef NS_DEBUG_XX
3883 printf("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount);
3884 #endif
3886 NPEvent pluginEvent;
3888 switch (aEventType)
3890 case NS_MOUSE_BUTTON_DOWN:
3891 switch (aButton) {
3892 case nsMouseEvent::eLeftButton:
3893 pluginEvent.event = WM_LBUTTONDOWN;
3894 break;
3895 case nsMouseEvent::eMiddleButton:
3896 pluginEvent.event = WM_MBUTTONDOWN;
3897 break;
3898 case nsMouseEvent::eRightButton:
3899 pluginEvent.event = WM_RBUTTONDOWN;
3900 break;
3901 default:
3902 break;
3904 break;
3905 case NS_MOUSE_BUTTON_UP:
3906 switch (aButton) {
3907 case nsMouseEvent::eLeftButton:
3908 pluginEvent.event = WM_LBUTTONUP;
3909 break;
3910 case nsMouseEvent::eMiddleButton:
3911 pluginEvent.event = WM_MBUTTONUP;
3912 break;
3913 case nsMouseEvent::eRightButton:
3914 pluginEvent.event = WM_RBUTTONUP;
3915 break;
3916 default:
3917 break;
3919 break;
3920 case NS_MOUSE_DOUBLECLICK:
3921 switch (aButton) {
3922 case nsMouseEvent::eLeftButton:
3923 pluginEvent.event = WM_LBUTTONDBLCLK;
3924 break;
3925 case nsMouseEvent::eMiddleButton:
3926 pluginEvent.event = WM_MBUTTONDBLCLK;
3927 break;
3928 case nsMouseEvent::eRightButton:
3929 pluginEvent.event = WM_RBUTTONDBLCLK;
3930 break;
3931 default:
3932 break;
3934 break;
3935 case NS_MOUSE_MOVE:
3936 pluginEvent.event = WM_MOUSEMOVE;
3937 break;
3938 case NS_MOUSE_EXIT:
3939 pluginEvent.event = WM_MOUSELEAVE;
3940 break;
3941 default:
3942 pluginEvent.event = WM_NULL;
3943 break;
3946 pluginEvent.wParam = wParam; // plugins NEED raw OS event flags!
3947 pluginEvent.lParam = lParam;
3949 event.pluginEvent = (void *)&pluginEvent;
3951 // call the event callback
3952 if (nsnull != mEventCallback) {
3953 if (nsToolkit::gMouseTrailer)
3954 nsToolkit::gMouseTrailer->Disable();
3955 if (aEventType == NS_MOUSE_MOVE) {
3956 if (nsToolkit::gMouseTrailer && !mIsInMouseCapture) {
3957 nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd);
3959 nsIntRect rect;
3960 GetBounds(rect);
3961 rect.x = 0;
3962 rect.y = 0;
3964 if (rect.Contains(event.refPoint)) {
3965 if (sCurrentWindow == NULL || sCurrentWindow != this) {
3966 if ((nsnull != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
3967 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3968 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, PR_FALSE,
3969 nsMouseEvent::eLeftButton, aInputSource);
3971 sCurrentWindow = this;
3972 if (!mInDtor) {
3973 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3974 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, PR_FALSE,
3975 nsMouseEvent::eLeftButton, aInputSource);
3979 } else if (aEventType == NS_MOUSE_EXIT) {
3980 if (sCurrentWindow == this) {
3981 sCurrentWindow = nsnull;
3985 result = DispatchWindowEvent(&event);
3987 if (nsToolkit::gMouseTrailer)
3988 nsToolkit::gMouseTrailer->Enable();
3990 // Release the widget with NS_IF_RELEASE() just in case
3991 // the context menu key code in nsEventListenerManager::HandleEvent()
3992 // released it already.
3993 return result;
3996 return result;
3999 // Deal with accessibile event
4000 #ifdef ACCESSIBILITY
4001 nsAccessible*
4002 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType)
4004 if (nsnull == mEventCallback) {
4005 return nsnull;
4008 nsAccessibleEvent event(PR_TRUE, aEventType, this);
4009 InitEvent(event, nsnull);
4011 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
4012 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
4013 event.isMeta = PR_FALSE;
4014 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
4016 DispatchWindowEvent(&event);
4018 return event.mAccessible;
4020 #endif
4022 PRBool nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType)
4024 if (aEventType == NS_ACTIVATE)
4025 sJustGotActivate = PR_FALSE;
4026 sJustGotDeactivate = PR_FALSE;
4028 // retrive the toplevel window or dialog
4029 HWND curWnd = mWnd;
4030 HWND toplevelWnd = NULL;
4031 while (curWnd) {
4032 toplevelWnd = curWnd;
4034 nsWindow *win = GetNSWindowPtr(curWnd);
4035 if (win) {
4036 nsWindowType wintype;
4037 win->GetWindowType(wintype);
4038 if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog)
4039 break;
4042 curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
4045 if (toplevelWnd) {
4046 nsWindow *win = GetNSWindowPtr(toplevelWnd);
4047 if (win)
4048 return win->DispatchFocus(aEventType);
4051 return PR_FALSE;
4054 // Deal with focus messages
4055 PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
4057 // call the event callback
4058 if (mEventCallback) {
4059 nsGUIEvent event(PR_TRUE, aEventType, this);
4060 InitEvent(event);
4062 //focus and blur event should go to their base widget loc, not current mouse pos
4063 event.refPoint.x = 0;
4064 event.refPoint.y = 0;
4066 NPEvent pluginEvent;
4068 switch (aEventType)
4070 case NS_ACTIVATE:
4071 pluginEvent.event = WM_SETFOCUS;
4072 break;
4073 case NS_DEACTIVATE:
4074 pluginEvent.event = WM_KILLFOCUS;
4075 break;
4076 case NS_PLUGIN_ACTIVATE:
4077 pluginEvent.event = WM_KILLFOCUS;
4078 break;
4079 default:
4080 break;
4083 event.pluginEvent = (void *)&pluginEvent;
4085 return DispatchWindowEvent(&event);
4087 return PR_FALSE;
4090 PRBool nsWindow::IsTopLevelMouseExit(HWND aWnd)
4092 DWORD pos = ::GetMessagePos();
4093 POINT mp;
4094 mp.x = GET_X_LPARAM(pos);
4095 mp.y = GET_Y_LPARAM(pos);
4096 HWND mouseWnd = ::WindowFromPoint(mp);
4098 // GetTopLevelHWND will return a HWND for the window frame (which includes
4099 // the non-client area). If the mouse has moved into the non-client area,
4100 // we should treat it as a top-level exit.
4101 HWND mouseTopLevel = nsWindow::GetTopLevelHWND(mouseWnd);
4102 if (mouseWnd == mouseTopLevel)
4103 return PR_TRUE;
4105 return nsWindow::GetTopLevelHWND(aWnd) != mouseTopLevel;
4108 PRBool nsWindow::BlurEventsSuppressed()
4110 // are they suppressed in this window?
4111 if (mBlurSuppressLevel > 0)
4112 return PR_TRUE;
4114 // are they suppressed by any container widget?
4115 HWND parentWnd = ::GetParent(mWnd);
4116 if (parentWnd) {
4117 nsWindow *parent = GetNSWindowPtr(parentWnd);
4118 if (parent)
4119 return parent->BlurEventsSuppressed();
4121 return PR_FALSE;
4124 // In some circumstances (opening dependent windows) it makes more sense
4125 // (and fixes a crash bug) to not blur the parent window. Called from
4126 // nsFilePicker.
4127 void nsWindow::SuppressBlurEvents(PRBool aSuppress)
4129 if (aSuppress)
4130 ++mBlurSuppressLevel; // for this widget
4131 else {
4132 NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression");
4133 if (mBlurSuppressLevel > 0)
4134 --mBlurSuppressLevel;
4138 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
4140 return aStatus == nsEventStatus_eConsumeNoDefault;
4143 /**************************************************************
4145 * SECTION: IPC
4147 * IPC related helpers.
4149 **************************************************************/
4151 #ifdef MOZ_IPC
4153 // static
4154 bool
4155 nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult)
4157 switch(aMsg) {
4158 case WM_SETFOCUS:
4159 case WM_KILLFOCUS:
4160 case WM_ENABLE:
4161 case WM_WINDOWPOSCHANGING:
4162 case WM_WINDOWPOSCHANGED:
4163 case WM_PARENTNOTIFY:
4164 case WM_ACTIVATEAPP:
4165 case WM_NCACTIVATE:
4166 case WM_ACTIVATE:
4167 case WM_CHILDACTIVATE:
4168 case WM_IME_SETCONTEXT:
4169 case WM_IME_NOTIFY:
4170 case WM_SHOWWINDOW:
4171 case WM_CANCELMODE:
4172 case WM_MOUSEACTIVATE:
4173 case WM_CONTEXTMENU:
4174 aResult = 0;
4175 return true;
4177 case WM_SETTINGCHANGE:
4178 case WM_SETCURSOR:
4179 return false;
4182 #ifdef DEBUG
4183 char szBuf[200];
4184 sprintf(szBuf,
4185 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg);
4186 NS_WARNING(szBuf);
4187 #endif
4189 return false;
4192 void
4193 nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
4195 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4196 "Failed to prevent a nonqueued message from running!");
4198 // Modal UI being displayed in windowless plugins.
4199 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4200 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4201 LRESULT res;
4202 if (IsAsyncResponseEvent(msg, res)) {
4203 ReplyMessage(res);
4205 return;
4208 // Handle certain sync plugin events sent to the parent which
4209 // trigger ipc calls that result in deadlocks.
4211 DWORD dwResult = 0;
4212 PRBool handled = PR_FALSE;
4214 switch(msg) {
4215 // Windowless flash sending WM_ACTIVATE events to the main window
4216 // via calls to ShowWindow.
4217 case WM_ACTIVATE:
4218 if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE &&
4219 IsWindow((HWND)lParam))
4220 handled = PR_TRUE;
4221 break;
4222 // Wheel events forwarded from the child.
4223 case WM_MOUSEWHEEL:
4224 case WM_MOUSEHWHEEL:
4225 case WM_HSCROLL:
4226 case WM_VSCROLL:
4227 // Plugins taking or losing focus triggering focus app messages.
4228 case WM_SETFOCUS:
4229 case WM_KILLFOCUS:
4230 // Windowed plugins that pass sys key events to defwndproc generate
4231 // WM_SYSCOMMAND events to the main window.
4232 case WM_SYSCOMMAND:
4233 // Windowed plugins that fire context menu selection events to parent
4234 // windows.
4235 case WM_CONTEXTMENU:
4236 // IME events fired as a result of synchronous focus changes
4237 case WM_IME_SETCONTEXT:
4238 handled = PR_TRUE;
4239 break;
4242 if (handled &&
4243 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4244 ReplyMessage(dwResult);
4248 #endif // MOZ_IPC
4250 /**************************************************************
4251 **************************************************************
4253 ** BLOCK: Native events
4255 ** Main Windows message handlers and OnXXX handlers for
4256 ** Windows event handling.
4258 **************************************************************
4259 **************************************************************/
4261 /**************************************************************
4263 * SECTION: Wind proc.
4265 * The main Windows event procedures and associated
4266 * message processing methods.
4268 **************************************************************/
4270 #ifdef _MSC_VER
4271 static int ReportException(EXCEPTION_POINTERS *aExceptionInfo)
4273 #ifdef MOZ_CRASHREPORTER
4274 nsCOMPtr<nsICrashReporter> cr =
4275 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
4276 if (cr)
4277 cr->WriteMinidumpForException(aExceptionInfo);
4278 #endif
4279 return EXCEPTION_EXECUTE_HANDLER;
4281 #endif
4283 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
4284 // exceptions and passes the real work to WindowProcInternal. See bug 587406
4285 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
4286 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4288 #ifdef _MSC_VER
4289 __try {
4290 return WindowProcInternal(hWnd, msg, wParam, lParam);
4292 __except(ReportException(GetExceptionInformation())) {
4293 ::TerminateProcess(::GetCurrentProcess(), 253);
4295 #else
4296 return WindowProcInternal(hWnd, msg, wParam, lParam);
4297 #endif
4300 LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4302 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4303 MOZ_FUNCTION_NAME, __LINE__, hWnd, msg,
4304 wParam, lParam);
4306 // Get the window which caused the event and ask it to process the message
4307 nsWindow *someWindow = GetNSWindowPtr(hWnd);
4309 #ifdef MOZ_IPC
4310 if (someWindow)
4311 someWindow->IPCWindowProcHandler(msg, wParam, lParam);
4312 #endif
4314 // create this here so that we store the last rolled up popup until after
4315 // the event has been processed.
4316 nsAutoRollup autoRollup;
4318 LRESULT popupHandlingResult;
4319 if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult))
4320 return popupHandlingResult;
4322 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4323 // why we are hitting this assert
4324 if (nsnull == someWindow) {
4325 NS_ASSERTION(someWindow, "someWindow is null, cannot call any CallWindowProc");
4326 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
4329 // hold on to the window for the life of this method, in case it gets
4330 // deleted during processing. yes, it's a double hack, since someWindow
4331 // is not really an interface.
4332 nsCOMPtr<nsISupports> kungFuDeathGrip;
4333 if (!someWindow->mInDtor) // not if we're in the destructor!
4334 kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)someWindow);
4336 // Call ProcessMessage
4337 LRESULT retValue;
4338 if (PR_TRUE == someWindow->ProcessMessage(msg, wParam, lParam, &retValue)) {
4339 return retValue;
4342 LRESULT res = ::CallWindowProcW(someWindow->GetPrevWindowProc(),
4343 hWnd, msg, wParam, lParam);
4345 return res;
4348 // The main windows message processing method for plugins.
4349 // The result means whether this method processed the native
4350 // event for plugin. If false, the native event should be
4351 // processed by the caller self.
4352 PRBool
4353 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
4354 LRESULT *aResult,
4355 PRBool &aCallDefWndProc)
4357 NS_PRECONDITION(aResult, "aResult must be non-null.");
4358 *aResult = 0;
4360 aCallDefWndProc = PR_FALSE;
4361 PRBool eventDispatched = PR_FALSE;
4362 switch (aMsg.message) {
4363 case WM_CHAR:
4364 case WM_SYSCHAR:
4365 *aResult = ProcessCharMessage(aMsg, &eventDispatched);
4366 break;
4368 case WM_KEYUP:
4369 case WM_SYSKEYUP:
4370 *aResult = ProcessKeyUpMessage(aMsg, &eventDispatched);
4371 break;
4373 case WM_KEYDOWN:
4374 case WM_SYSKEYDOWN:
4375 *aResult = ProcessKeyDownMessage(aMsg, &eventDispatched);
4376 break;
4378 case WM_DEADCHAR:
4379 case WM_SYSDEADCHAR:
4380 case WM_CONTEXTMENU:
4382 case WM_CUT:
4383 case WM_COPY:
4384 case WM_PASTE:
4385 case WM_CLEAR:
4386 case WM_UNDO:
4387 break;
4389 default:
4390 return PR_FALSE;
4393 if (!eventDispatched)
4394 aCallDefWndProc = !DispatchPluginEvent(aMsg);
4395 DispatchPendingEvents();
4396 return PR_TRUE;
4399 // The main windows message processing method.
4400 PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
4401 LRESULT *aRetValue)
4403 // (Large blocks of code should be broken out into OnEvent handlers.)
4404 if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
4405 return PR_TRUE;
4407 #if defined(EVENT_DEBUG_OUTPUT)
4408 // First param shows all events, second param indicates whether
4409 // to show mouse move events. See nsWindowDbg for details.
4410 PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
4411 #endif
4413 PRBool eatMessage;
4414 if (nsIMM32Handler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
4415 eatMessage)) {
4416 return mWnd ? eatMessage : PR_TRUE;
4419 if (PluginHasFocus()) {
4420 PRBool callDefaultWndProc;
4421 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4422 if (ProcessMessageForPlugin(nativeMsg, aRetValue, callDefaultWndProc)) {
4423 return mWnd ? !callDefaultWndProc : PR_TRUE;
4427 PRBool result = PR_FALSE; // call the default nsWindow proc
4428 *aRetValue = 0;
4430 static PRBool getWheelInfo = PR_TRUE;
4432 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4433 // Glass hit testing w/custom transparent margins
4434 LRESULT dwmHitResult;
4435 if (mCustomNonClient &&
4436 nsUXThemeData::CheckForCompositor() &&
4437 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) {
4438 *aRetValue = dwmHitResult;
4439 return PR_TRUE;
4441 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4443 switch (msg) {
4444 #ifndef WINCE
4445 // WM_QUERYENDSESSION must be handled by all windows.
4446 // Otherwise Windows thinks the window can just be killed at will.
4447 case WM_QUERYENDSESSION:
4448 if (sCanQuit == TRI_UNKNOWN)
4450 // Ask if it's ok to quit, and store the answer until we
4451 // get WM_ENDSESSION signaling the round is complete.
4452 nsCOMPtr<nsIObserverService> obsServ =
4453 mozilla::services::GetObserverService();
4454 nsCOMPtr<nsISupportsPRBool> cancelQuit =
4455 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
4456 cancelQuit->SetData(PR_FALSE);
4457 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
4459 PRBool abortQuit;
4460 cancelQuit->GetData(&abortQuit);
4461 sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
4463 *aRetValue = sCanQuit ? TRUE : FALSE;
4464 result = PR_TRUE;
4465 break;
4466 #endif
4468 #ifndef WINCE
4469 case WM_ENDSESSION:
4470 #endif
4471 case MOZ_WM_APP_QUIT:
4472 if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE))
4474 // Let's fake a shutdown sequence without actually closing windows etc.
4475 // to avoid Windows killing us in the middle. A proper shutdown would
4476 // require having a chance to pump some messages. Unfortunately
4477 // Windows won't let us do that. Bug 212316.
4478 nsCOMPtr<nsIObserverService> obsServ =
4479 mozilla::services::GetObserverService();
4480 NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
4481 obsServ->NotifyObservers(nsnull, "quit-application-granted", nsnull);
4482 obsServ->NotifyObservers(nsnull, "quit-application-forced", nsnull);
4483 obsServ->NotifyObservers(nsnull, "quit-application", nsnull);
4484 obsServ->NotifyObservers(nsnull, "profile-change-net-teardown", context.get());
4485 obsServ->NotifyObservers(nsnull, "profile-change-teardown", context.get());
4486 obsServ->NotifyObservers(nsnull, "profile-before-change", context.get());
4487 // Then a controlled but very quick exit.
4488 _exit(0);
4490 sCanQuit = TRI_UNKNOWN;
4491 result = PR_TRUE;
4492 break;
4494 #ifndef WINCE
4495 case WM_DISPLAYCHANGE:
4496 DispatchStandardEvent(NS_DISPLAYCHANGED);
4497 break;
4498 #endif
4500 case WM_SYSCOLORCHANGE:
4501 // Note: This is sent for child windows as well as top-level windows.
4502 // The Win32 toolkit normally only sends these events to top-level windows.
4503 // But we cycle through all of the childwindows and send it to them as well
4504 // so all presentations get notified properly.
4505 // See nsWindow::GlobalMsgWindowProc.
4506 DispatchStandardEvent(NS_SYSCOLORCHANGED);
4507 break;
4509 case WM_NOTIFY:
4510 // TAB change
4512 LPNMHDR pnmh = (LPNMHDR) lParam;
4514 switch (pnmh->code) {
4515 case TCN_SELCHANGE:
4517 DispatchStandardEvent(NS_TABCHANGE);
4518 result = PR_TRUE;
4520 break;
4523 break;
4525 case WM_XP_THEMECHANGED:
4527 // Update non-client margin offsets
4528 UpdateNonClientMargins();
4530 DispatchStandardEvent(NS_THEMECHANGED);
4532 // Invalidate the window so that the repaint will
4533 // pick up the new theme.
4534 Invalidate(PR_FALSE);
4536 break;
4538 case WM_FONTCHANGE:
4540 nsresult rv;
4541 PRBool didChange = PR_FALSE;
4543 // update the global font list
4544 nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
4545 if (NS_SUCCEEDED(rv)) {
4546 fontEnum->UpdateFontList(&didChange);
4547 //didChange is TRUE only if new font langGroup is added to the list.
4548 if (didChange) {
4549 // update device context font cache
4550 // Dirty but easiest way:
4551 // Changing nsIPrefBranch entry which triggers callbacks
4552 // and flows into calling mDeviceContext->FlushFontCache()
4553 // to update the font cache in all the instance of Browsers
4554 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
4555 if (prefs) {
4556 nsCOMPtr<nsIPrefBranch> fiPrefs;
4557 prefs->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs));
4558 if (fiPrefs) {
4559 PRBool fontInternalChange = PR_FALSE;
4560 fiPrefs->GetBoolPref("changed", &fontInternalChange);
4561 fiPrefs->SetBoolPref("changed", !fontInternalChange);
4565 } //if (NS_SUCCEEDED(rv))
4567 break;
4569 case WM_NCCALCSIZE:
4571 // If wParam is TRUE, it specifies that the application should indicate
4572 // which part of the client area contains valid information. The system
4573 // copies the valid information to the specified area within the new
4574 // client area. If the wParam parameter is FALSE, the application should
4575 // return zero.
4576 if (mCustomNonClient) {
4577 if (!wParam) {
4578 result = PR_TRUE;
4579 *aRetValue = 0;
4580 break;
4583 // before:
4584 // rgrc[0]: the proposed window
4585 // rgrc[1]: the current window
4586 // rgrc[2]: the source client area
4587 // pncsp->lppos: move/size data
4588 // after:
4589 // rgrc[0]: the new client area
4590 // rgrc[1]: the destination window
4591 // rgrc[2]: the source client area
4592 // (all values in screen coordiantes)
4593 NCCALCSIZE_PARAMS *pncsp = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
4594 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd, msg, wParam, lParam);
4595 pncsp->rgrc[0].top -= mNonClientOffset.top;
4596 pncsp->rgrc[0].left -= mNonClientOffset.left;
4597 pncsp->rgrc[0].right += mNonClientOffset.right;
4598 pncsp->rgrc[0].bottom += mNonClientOffset.bottom;
4600 result = PR_TRUE;
4601 *aRetValue = res;
4603 break;
4606 case WM_NCHITTEST:
4609 * If an nc client area margin has been moved, we are responsible
4610 * for calculating where the resize margins are and returning the
4611 * appropriate set of hit test constants. DwmDefWindowProc (above)
4612 * will handle hit testing on it's command buttons if we are on a
4613 * composited desktop.
4616 if (!mCustomNonClient)
4617 break;
4619 *aRetValue =
4620 ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
4621 result = PR_TRUE;
4622 break;
4625 case WM_SETTEXT:
4627 * WM_SETTEXT paints the titlebar area. Avoid this if we have a
4628 * custom titlebar we paint ourselves.
4631 if (!mCustomNonClient || mNonClientMargins.top == -1)
4632 break;
4635 // From msdn, the way around this is to disable the visible state
4636 // temporarily. We need the text to be set but we don't want the
4637 // redraw to occur.
4638 DWORD style = GetWindowLong(mWnd, GWL_STYLE);
4639 SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
4640 *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd,
4641 msg, wParam, lParam);
4642 SetWindowLong(mWnd, GWL_STYLE, style);
4643 return PR_TRUE;
4646 case WM_NCACTIVATE:
4649 * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
4650 * through WM_NCPAINT via InvalidateNonClientRegion.
4653 if (!mCustomNonClient)
4654 break;
4656 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4657 // let the dwm handle nc painting on glass
4658 if(nsUXThemeData::CheckForCompositor())
4659 break;
4660 #endif
4662 if (wParam == TRUE) {
4663 // going active
4664 *aRetValue = FALSE; // ignored
4665 result = PR_TRUE;
4666 // invalidate to trigger a paint
4667 InvalidateNonClientRegion();
4668 break;
4669 } else {
4670 // going inactive
4671 *aRetValue = TRUE; // go ahead and deactive
4672 result = PR_TRUE;
4673 // invalidate to trigger a paint
4674 InvalidateNonClientRegion();
4675 break;
4679 case WM_NCPAINT:
4682 * Reset the non-client paint region so that it excludes the
4683 * non-client areas we paint manually. Then call defwndproc
4684 * to do the actual painting.
4687 if (!mCustomNonClient)
4688 break;
4690 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4691 // let the dwm handle nc painting on glass
4692 if(nsUXThemeData::CheckForCompositor())
4693 break;
4694 #endif
4696 HRGN paintRgn = ExcludeNonClientFromPaintRegion((HRGN)wParam);
4697 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd,
4698 msg, (WPARAM)paintRgn, lParam);
4699 if (paintRgn != (HRGN)wParam)
4700 DeleteObject(paintRgn);
4701 *aRetValue = res;
4702 result = PR_TRUE;
4704 break;
4706 #ifndef WINCE
4707 case WM_POWERBROADCAST:
4708 // only hidden window handle this
4709 // to prevent duplicate notification
4710 if (mWindowType == eWindowType_invisible) {
4711 switch (wParam)
4713 case PBT_APMSUSPEND:
4714 PostSleepWakeNotification("sleep_notification");
4715 break;
4716 case PBT_APMRESUMEAUTOMATIC:
4717 case PBT_APMRESUMECRITICAL:
4718 case PBT_APMRESUMESUSPEND:
4719 PostSleepWakeNotification("wake_notification");
4720 break;
4723 break;
4724 #endif
4726 case WM_MOVE: // Window moved
4728 RECT rect;
4729 ::GetWindowRect(mWnd, &rect);
4730 result = OnMove(rect.left, rect.top);
4732 break;
4734 case WM_CLOSE: // close request
4735 DispatchStandardEvent(NS_XUL_CLOSE);
4736 result = PR_TRUE; // abort window closure
4737 break;
4739 case WM_DESTROY:
4740 // clean up.
4741 OnDestroy();
4742 result = PR_TRUE;
4743 break;
4745 case WM_PAINT:
4746 *aRetValue = (int) OnPaint(NULL, 0);
4747 result = PR_TRUE;
4748 break;
4750 #ifndef WINCE
4751 case WM_PRINTCLIENT:
4752 result = OnPaint((HDC) wParam, 0);
4753 break;
4754 #endif
4756 case WM_HOTKEY:
4757 result = OnHotKey(wParam, lParam);
4758 break;
4760 case WM_SYSCHAR:
4761 case WM_CHAR:
4763 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4764 result = ProcessCharMessage(nativeMsg, nsnull);
4765 DispatchPendingEvents();
4767 break;
4769 case WM_SYSKEYUP:
4770 case WM_KEYUP:
4772 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4773 result = ProcessKeyUpMessage(nativeMsg, nsnull);
4774 DispatchPendingEvents();
4776 break;
4778 case WM_SYSKEYDOWN:
4779 case WM_KEYDOWN:
4781 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4782 result = ProcessKeyDownMessage(nativeMsg, nsnull);
4783 DispatchPendingEvents();
4785 break;
4787 // say we've dealt with erase background if widget does
4788 // not need auto-erasing
4789 case WM_ERASEBKGND:
4790 if (!AutoErase((HDC)wParam)) {
4791 *aRetValue = 1;
4792 result = PR_TRUE;
4794 break;
4796 case WM_MOUSEMOVE:
4798 #ifdef WINCE_WINDOWS_MOBILE
4799 // Reset the kill timer so that we can continue at this
4800 // priority
4801 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2seconds */, NULL);
4802 #endif
4803 // Suppress dispatch of pending events
4804 // when mouse moves are generated by widget
4805 // creation instead of user input.
4806 LPARAM lParamScreen = lParamToScreen(lParam);
4807 POINT mp;
4808 mp.x = GET_X_LPARAM(lParamScreen);
4809 mp.y = GET_Y_LPARAM(lParamScreen);
4810 PRBool userMovedMouse = PR_FALSE;
4811 if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) {
4812 userMovedMouse = PR_TRUE;
4814 mExitToNonClientArea = PR_FALSE;
4816 result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam,
4817 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4818 if (userMovedMouse) {
4819 DispatchPendingEvents();
4822 break;
4824 #ifdef WINCE_WINDOWS_MOBILE
4825 case WM_TIMER:
4826 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4827 KillTimer(mWnd, KILL_PRIORITY_ID);
4828 break;
4829 #endif
4831 case WM_LBUTTONDOWN:
4833 #ifdef WINCE_WINDOWS_MOBILE
4834 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
4835 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2 seconds */, NULL);
4836 #endif
4837 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
4838 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4839 DispatchPendingEvents();
4841 break;
4843 case WM_LBUTTONUP:
4845 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam,
4846 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4847 DispatchPendingEvents();
4849 #ifdef WINCE_WINDOWS_MOBILE
4850 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4851 KillTimer(mWnd, KILL_PRIORITY_ID);
4852 #endif
4854 break;
4856 #ifndef WINCE
4857 case WM_MOUSELEAVE:
4859 // We need to check mouse button states and put them in for
4860 // wParam.
4861 WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
4862 | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
4863 | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
4864 // Synthesize an event position because we don't get one from
4865 // WM_MOUSELEAVE.
4866 LPARAM pos = lParamToClient(::GetMessagePos());
4867 DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, PR_FALSE,
4868 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4870 break;
4871 #endif
4873 case WM_CONTEXTMENU:
4875 // if the context menu is brought up from the keyboard, |lParam|
4876 // will be -1.
4877 LPARAM pos;
4878 PRBool contextMenukey = PR_FALSE;
4879 if (lParam == -1)
4881 contextMenukey = PR_TRUE;
4882 pos = lParamToClient(GetMessagePos());
4884 else
4886 pos = lParamToClient(lParam);
4889 result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey,
4890 contextMenukey ?
4891 nsMouseEvent::eLeftButton :
4892 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4894 break;
4896 case WM_LBUTTONDBLCLK:
4897 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4898 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4899 break;
4901 case WM_MBUTTONDOWN:
4903 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4904 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4905 DispatchPendingEvents();
4907 break;
4909 case WM_MBUTTONUP:
4910 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4911 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4912 DispatchPendingEvents();
4913 break;
4915 case WM_MBUTTONDBLCLK:
4916 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4917 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4918 break;
4920 case WM_NCMBUTTONDOWN:
4921 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam), PR_FALSE,
4922 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4923 DispatchPendingEvents();
4924 break;
4926 case WM_NCMBUTTONUP:
4927 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam), PR_FALSE,
4928 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4929 DispatchPendingEvents();
4930 break;
4932 case WM_NCMBUTTONDBLCLK:
4933 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam), PR_FALSE,
4934 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4935 DispatchPendingEvents();
4936 break;
4938 case WM_RBUTTONDOWN:
4940 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4941 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4942 DispatchPendingEvents();
4944 break;
4946 case WM_RBUTTONUP:
4947 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4948 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4949 DispatchPendingEvents();
4950 break;
4952 case WM_RBUTTONDBLCLK:
4953 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4954 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4955 break;
4957 case WM_NCRBUTTONDOWN:
4958 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam),
4959 PR_FALSE, nsMouseEvent::eRightButton,
4960 MOUSE_INPUT_SOURCE());
4961 DispatchPendingEvents();
4962 break;
4964 case WM_NCRBUTTONUP:
4965 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam),
4966 PR_FALSE, nsMouseEvent::eRightButton,
4967 MOUSE_INPUT_SOURCE());
4968 DispatchPendingEvents();
4969 break;
4971 case WM_NCRBUTTONDBLCLK:
4972 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam),
4973 PR_FALSE, nsMouseEvent::eRightButton,
4974 MOUSE_INPUT_SOURCE());
4976 case WM_APPCOMMAND:
4978 PRUint32 appCommand = GET_APPCOMMAND_LPARAM(lParam);
4980 switch (appCommand)
4982 case APPCOMMAND_BROWSER_BACKWARD:
4983 case APPCOMMAND_BROWSER_FORWARD:
4984 case APPCOMMAND_BROWSER_REFRESH:
4985 case APPCOMMAND_BROWSER_STOP:
4986 case APPCOMMAND_BROWSER_SEARCH:
4987 case APPCOMMAND_BROWSER_FAVORITES:
4988 case APPCOMMAND_BROWSER_HOME:
4989 DispatchCommandEvent(appCommand);
4990 // tell the driver that we handled the event
4991 *aRetValue = 1;
4992 result = PR_TRUE;
4993 break;
4995 // default = PR_FALSE - tell the driver that the event was not handled
4997 break;
4999 case WM_HSCROLL:
5000 case WM_VSCROLL:
5001 *aRetValue = 0;
5002 result = OnScroll(msg, wParam, lParam);
5003 break;
5005 // The WM_ACTIVATE event is fired when a window is raised or lowered,
5006 // and the loword of wParam specifies which. But we don't want to tell
5007 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
5008 // events are fired. Instead, set either the sJustGotActivate or
5009 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
5010 // events once the focus events arrive.
5011 case WM_ACTIVATE:
5012 if (mEventCallback) {
5013 PRInt32 fActive = LOWORD(wParam);
5015 #if defined(WINCE_HAVE_SOFTKB)
5016 if (mIsTopWidgetWindow && sSoftKeyboardState)
5017 nsWindowCE::ToggleSoftKB(mWnd, fActive);
5018 if (nsWindowCE::sShowSIPButton == TRI_FALSE && WA_INACTIVE != fActive) {
5019 HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL );
5020 if (hWndSIPB)
5021 ShowWindow(hWndSIPB, SW_HIDE);
5024 #endif
5026 if (WA_INACTIVE == fActive) {
5027 // when minimizing a window, the deactivation and focus events will
5028 // be fired in the reverse order. Instead, just dispatch
5029 // NS_DEACTIVATE right away.
5030 if (HIWORD(wParam))
5031 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5032 else
5033 sJustGotDeactivate = PR_TRUE;
5034 #ifndef WINCE
5035 if (mIsTopWidgetWindow)
5036 mLastKeyboardLayout = gKbdLayout.GetLayout();
5037 #endif
5039 } else {
5040 StopFlashing();
5042 sJustGotActivate = PR_TRUE;
5043 nsMouseEvent event(PR_TRUE, NS_MOUSE_ACTIVATE, this,
5044 nsMouseEvent::eReal);
5045 InitEvent(event);
5047 event.acceptActivation = PR_TRUE;
5049 DispatchWindowEvent(&event);
5050 #ifndef WINCE
5051 if (event.acceptActivation)
5052 *aRetValue = MA_ACTIVATE;
5053 else
5054 *aRetValue = MA_NOACTIVATE;
5056 if (sSwitchKeyboardLayout && mLastKeyboardLayout)
5057 ActivateKeyboardLayout(mLastKeyboardLayout, 0);
5058 #else
5059 *aRetValue = 0;
5060 #endif
5063 #ifdef WINCE_WINDOWS_MOBILE
5064 if (!gCheckForHTCApi && gHTCApiNavOpen == nsnull) {
5065 gCheckForHTCApi = PR_TRUE;
5067 HINSTANCE library = LoadLibrary(L"HTCAPI.dll");
5068 gHTCApiNavOpen = (HTCApiNavOpen) GetProcAddress(library, "HTCNavOpen");
5069 gHTCApiNavSetMode = (HTCApiNavSetMode) GetProcAddress(library ,"HTCNavSetMode");
5072 if (gHTCApiNavOpen != nsnull) {
5073 gHTCApiNavOpen(mWnd, 1 /* undocumented value */);
5075 if (gHTCApiNavSetMode != nsnull)
5076 gHTCApiNavSetMode ( mWnd, 4);
5077 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5079 #endif
5080 break;
5082 #ifndef WINCE
5083 case WM_MOUSEACTIVATE:
5084 if (mWindowType == eWindowType_popup) {
5085 // a popup with a parent owner should not be activated when clicked
5086 // but should still allow the mouse event to be fired, so the return
5087 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5088 // window, just use default processing so that the window is activated.
5089 HWND owner = ::GetWindow(mWnd, GW_OWNER);
5090 if (owner && owner == ::GetForegroundWindow()) {
5091 *aRetValue = MA_NOACTIVATE;
5092 result = PR_TRUE;
5095 break;
5097 case WM_WINDOWPOSCHANGING:
5099 LPWINDOWPOS info = (LPWINDOWPOS) lParam;
5100 OnWindowPosChanging(info);
5102 break;
5103 #endif
5105 case WM_SETFOCUS:
5106 if (sJustGotActivate) {
5107 result = DispatchFocusToTopLevelWindow(NS_ACTIVATE);
5110 #ifdef ACCESSIBILITY
5111 if (nsWindow::sIsAccessibilityOn) {
5112 // Create it for the first time so that it can start firing events
5113 nsAccessible *rootAccessible = GetRootAccessible();
5115 #endif
5117 #if defined(WINCE_HAVE_SOFTKB)
5119 // On Windows CE, we have a window that overlaps
5120 // the ISP button. In this case, we should always
5121 // try to hide it when we are activated
5123 nsIMEContext IMEContext(mWnd);
5124 // Open the IME
5125 ImmSetOpenStatus(IMEContext.get(), TRUE);
5127 #endif
5128 break;
5130 case WM_KILLFOCUS:
5131 #if defined(WINCE_HAVE_SOFTKB)
5133 nsIMEContext IMEContext(mWnd);
5134 ImmSetOpenStatus(IMEContext.get(), FALSE);
5136 #endif
5137 if (sJustGotDeactivate) {
5138 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5140 break;
5142 case WM_WINDOWPOSCHANGED:
5144 WINDOWPOS *wp = (LPWINDOWPOS)lParam;
5145 OnWindowPosChanged(wp, result);
5147 break;
5149 case WM_SETTINGCHANGE:
5150 #if !defined (WINCE_WINDOWS_MOBILE)
5151 getWheelInfo = PR_TRUE;
5152 #else
5153 switch (wParam) {
5154 case SPI_SETSIPINFO:
5155 case SPI_SETCURRENTIM:
5156 nsWindowCE::OnSoftKbSettingsChange(mWnd);
5157 break;
5158 case SETTINGCHANGE_RESET:
5159 if (mWindowType == eWindowType_invisible) {
5160 // The OS sees to get confused and think that the invisable window
5161 // is in the foreground after an orientation change. By actually
5162 // setting it to the foreground and hiding it, we set it strait.
5163 // See bug 514007 for details.
5164 SetForegroundWindow(mWnd);
5165 ShowWindow(mWnd, SW_HIDE);
5167 break;
5169 #endif
5170 OnSettingsChange(wParam, lParam);
5171 break;
5173 #ifndef WINCE
5174 case WM_INPUTLANGCHANGEREQUEST:
5175 *aRetValue = TRUE;
5176 result = PR_FALSE;
5177 break;
5179 case WM_INPUTLANGCHANGE:
5180 result = OnInputLangChange((HKL)lParam);
5181 break;
5182 #endif // WINCE
5184 case WM_DESTROYCLIPBOARD:
5186 nsIClipboard* clipboard;
5187 nsresult rv = CallGetService(kCClipboardCID, &clipboard);
5188 if(NS_SUCCEEDED(rv)) {
5189 clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
5190 NS_RELEASE(clipboard);
5193 break;
5195 #ifdef ACCESSIBILITY
5196 case WM_GETOBJECT:
5198 *aRetValue = 0;
5199 if (lParam == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
5200 nsAccessible *rootAccessible = GetRootAccessible(); // Held by a11y cache
5201 if (rootAccessible) {
5202 IAccessible *msaaAccessible = NULL;
5203 rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref
5204 if (msaaAccessible) {
5205 *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref
5206 msaaAccessible->Release(); // release extra addref
5207 result = PR_TRUE; // We handled the WM_GETOBJECT message
5212 #endif
5214 #ifndef WINCE
5215 case WM_SYSCOMMAND:
5216 // prevent Windows from trimming the working set. bug 76831
5217 if (!sTrimOnMinimize && wParam == SC_MINIMIZE) {
5218 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
5219 result = PR_TRUE;
5221 break;
5222 #endif
5225 #ifdef WINCE
5226 case WM_HIBERNATE:
5227 nsMemory::HeapMinimize(PR_TRUE);
5228 break;
5229 #endif
5231 case WM_MOUSEWHEEL:
5232 case WM_MOUSEHWHEEL:
5234 // If OnMouseWheel returns true, the event was forwarded directly to another
5235 // mozilla window message handler (ProcessMessage). In this case the return
5236 // value of the forwarded event is in 'result' which we should return immediately.
5237 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5238 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5239 // we should fall through.
5240 if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue))
5241 return result;
5243 break;
5245 #ifndef WINCE
5246 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5247 case WM_DWMCOMPOSITIONCHANGED:
5248 UpdateNonClientMargins();
5249 BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
5250 DispatchStandardEvent(NS_THEMECHANGED);
5251 UpdateGlass();
5252 Invalidate(PR_FALSE);
5253 break;
5254 #endif
5256 case WM_UPDATEUISTATE:
5258 // If the UI state has changed, fire an event so the UI updates the
5259 // keyboard cues based on the system setting and how the window was
5260 // opened. For example, a dialog opened via a keyboard press on a button
5261 // should enable cues, whereas the same dialog opened via a mouse click of
5262 // the button should not.
5263 PRInt32 action = LOWORD(wParam);
5264 if (action == UIS_SET || action == UIS_CLEAR) {
5265 nsUIStateChangeEvent event(PR_TRUE, NS_UISTATECHANGED, this);
5266 PRInt32 flags = HIWORD(wParam);
5267 if (flags & UISF_HIDEACCEL)
5268 event.showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5269 if (flags & UISF_HIDEFOCUS)
5270 event.showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5271 DispatchWindowEvent(&event);
5274 break;
5277 /* Gesture support events */
5278 case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
5279 // According to MS samples, this must be handled to enable
5280 // rotational support in multi-touch drivers.
5281 result = PR_TRUE;
5282 *aRetValue = TABLET_ROTATE_GESTURE_ENABLE;
5283 break;
5285 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5286 case WM_TOUCH:
5287 result = OnTouch(wParam, lParam);
5288 if (result) {
5289 *aRetValue = 0;
5291 break;
5292 #endif
5294 case WM_GESTURE:
5295 result = OnGesture(wParam, lParam);
5296 break;
5298 case WM_GESTURENOTIFY:
5300 if (mWindowType != eWindowType_invisible &&
5301 mWindowType != eWindowType_plugin) {
5302 // A GestureNotify event is dispatched to decide which single-finger panning
5303 // direction should be active (including none) and if pan feedback should
5304 // be displayed. Java and plugin windows can make their own calls.
5305 GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
5306 nsPointWin touchPoint;
5307 touchPoint = gestureinfo->ptsLocation;
5308 touchPoint.ScreenToClient(mWnd);
5309 nsGestureNotifyEvent gestureNotifyEvent(PR_TRUE, NS_GESTURENOTIFY_EVENT_START, this);
5310 gestureNotifyEvent.refPoint = touchPoint;
5311 nsEventStatus status;
5312 DispatchEvent(&gestureNotifyEvent, status);
5313 mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
5314 if (!mTouchWindow)
5315 mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
5317 result = PR_FALSE; //should always bubble to DefWindowProc
5319 break;
5320 #endif // !defined(WINCE)
5322 case WM_CLEAR:
5324 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_DELETE, this);
5325 DispatchWindowEvent(&command);
5326 result = PR_TRUE;
5328 break;
5330 case WM_CUT:
5332 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_CUT, this);
5333 DispatchWindowEvent(&command);
5334 result = PR_TRUE;
5336 break;
5338 case WM_COPY:
5340 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_COPY, this);
5341 DispatchWindowEvent(&command);
5342 result = PR_TRUE;
5344 break;
5346 case WM_PASTE:
5348 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE, this);
5349 DispatchWindowEvent(&command);
5350 result = PR_TRUE;
5352 break;
5354 #ifndef WINCE
5355 case EM_UNDO:
5357 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO, this);
5358 DispatchWindowEvent(&command);
5359 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5360 result = PR_TRUE;
5362 break;
5364 case EM_REDO:
5366 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO, this);
5367 DispatchWindowEvent(&command);
5368 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5369 result = PR_TRUE;
5371 break;
5373 case EM_CANPASTE:
5375 // Support EM_CANPASTE message only when wParam isn't specified or
5376 // is plain text format.
5377 if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
5378 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE,
5379 this, PR_TRUE);
5380 DispatchWindowEvent(&command);
5381 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5382 result = PR_TRUE;
5385 break;
5387 case EM_CANUNDO:
5389 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO,
5390 this, PR_TRUE);
5391 DispatchWindowEvent(&command);
5392 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5393 result = PR_TRUE;
5395 break;
5397 case EM_CANREDO:
5399 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO,
5400 this, PR_TRUE);
5401 DispatchWindowEvent(&command);
5402 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5403 result = PR_TRUE;
5405 break;
5406 #endif
5408 #ifdef WINCE_WINDOWS_MOBILE
5409 //HTC NAVIGATION WHEEL EVENT
5410 case WM_HTCNAV:
5412 int distance = wParam & 0x000000FF;
5413 if ( (wParam & 0x000000100) != 0) // Counter Clockwise
5414 distance *= -1;
5415 if (OnMouseWheel(WM_MOUSEWHEEL, MAKEWPARAM(0, distance),
5416 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN) / 2,
5417 GetSystemMetrics(SM_CYSCREEN) / 2),
5418 getWheelInfo, result, aRetValue))
5419 return result;
5421 break;
5422 #endif
5424 default:
5426 #ifdef NS_ENABLE_TSF
5427 if (msg == WM_USER_TSF_TEXTCHANGE) {
5428 nsTextStore::OnTextChangeMsg();
5430 #endif //NS_ENABLE_TSF
5431 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5432 if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
5433 SetHasTaskbarIconBeenCreated();
5434 #endif
5435 #ifdef MOZ_IPC
5436 if (msg == sOOPPPluginFocusEvent) {
5437 if (wParam == 1) {
5438 // With OOPP, the plugin window exists in another process and is a child of
5439 // this window. This window is a placeholder plugin window for the dom. We
5440 // receive this event when the child window receives focus. (sent from
5441 // PluginInstanceParent.cpp)
5442 ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
5443 } else {
5444 // WM_KILLFOCUS was received by the child process.
5445 if (sJustGotDeactivate) {
5446 DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5450 #endif
5452 break;
5455 //*aRetValue = result;
5456 if (mWnd) {
5457 return result;
5459 else {
5460 //Events which caused mWnd destruction and aren't consumed
5461 //will crash during the Windows default processing.
5462 return PR_TRUE;
5466 /**************************************************************
5468 * SECTION: Broadcast messaging
5470 * Broadcast messages to all windows.
5472 **************************************************************/
5474 // Enumerate all child windows sending aMsg to each of them
5475 BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg)
5477 WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
5478 if (winProc == &nsWindow::WindowProc) {
5479 // it's one of our windows so go ahead and send a message to it
5480 ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0);
5482 return TRUE;
5485 // Enumerate all top level windows specifying that the children of each
5486 // top level window should be enumerated. Do *not* send the message to
5487 // each top level window since it is assumed that the toolkit will send
5488 // aMsg to them directly.
5489 BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg)
5491 // Iterate each of aTopWindows child windows sending the aMsg
5492 // to each of them.
5493 #if !defined(WINCE)
5494 ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5495 #else
5496 nsWindowCE::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5497 #endif
5498 return TRUE;
5501 // This method is called from nsToolkit::WindowProc to forward global
5502 // messages which need to be dispatched to all child windows.
5503 void nsWindow::GlobalMsgWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
5505 switch (msg) {
5506 case WM_SYSCOLORCHANGE:
5507 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5508 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5509 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5510 // all child windows as well. When running in an embedded application
5511 // we may not receive a WM_SYSCOLORCHANGE message because the top
5512 // level window is owned by the embeddor.
5513 // System color changes are posted to top-level windows only.
5514 // The NS_SYSCOLORCHANGE must be dispatched to all child
5515 // windows as well.
5516 #if !defined(WINCE)
5517 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, msg);
5518 #endif
5519 break;
5523 /**************************************************************
5525 * SECTION: Event processing helpers
5527 * Special processing for certain event types and
5528 * synthesized events.
5530 **************************************************************/
5532 PRInt32
5533 nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
5535 // Calculations are done in screen coords
5536 RECT winRect;
5537 GetWindowRect(mWnd, &winRect);
5539 // hit return constants:
5540 // HTBORDER - non-resizable border
5541 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5542 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5543 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5544 // HTCAPTION - general title bar area
5545 // HTCLIENT - area considered the client
5546 // HTCLOSE - hovering over the close button
5547 // HTMAXBUTTON - maximize button
5548 // HTMINBUTTON - minimize button
5550 PRInt32 testResult = HTCLIENT;
5552 PRBool top = PR_FALSE;
5553 PRBool bottom = PR_FALSE;
5554 PRBool left = PR_FALSE;
5555 PRBool right = PR_FALSE;
5557 if (my >= winRect.top && my <=
5558 (winRect.top + mVertResizeMargin + (mCaptionHeight - mNonClientOffset.top)))
5559 top = PR_TRUE;
5560 else if (my <= winRect.bottom && my >= (winRect.bottom - mVertResizeMargin))
5561 bottom = PR_TRUE;
5563 if (mx >= winRect.left && mx <= (winRect.left + mHorResizeMargin))
5564 left = PR_TRUE;
5565 else if (mx <= winRect.right && mx >= (winRect.right - mHorResizeMargin))
5566 right = PR_TRUE;
5568 if (top) {
5569 testResult = HTTOP;
5570 if (left)
5571 testResult = HTTOPLEFT;
5572 else if (right)
5573 testResult = HTTOPRIGHT;
5574 } else if (bottom) {
5575 testResult = HTBOTTOM;
5576 if (left)
5577 testResult = HTBOTTOMLEFT;
5578 else if (right)
5579 testResult = HTBOTTOMRIGHT;
5580 } else {
5581 if (left)
5582 testResult = HTLEFT;
5583 if (right)
5584 testResult = HTRIGHT;
5587 PRBool contentOverlap = PR_TRUE;
5589 if (mSizeMode == nsSizeMode_Maximized) {
5590 // There's no HTTOP in maximized state (bug 575493)
5591 if (testResult == HTTOP) {
5592 testResult = HTCAPTION;
5594 } else {
5595 PRInt32 leftMargin = mNonClientMargins.left == -1 ? mHorResizeMargin : mNonClientMargins.left;
5596 PRInt32 rightMargin = mNonClientMargins.right == -1 ? mHorResizeMargin : mNonClientMargins.right;
5597 PRInt32 topMargin = mNonClientMargins.top == -1 ? mVertResizeMargin : mNonClientMargins.top;
5598 PRInt32 bottomMargin = mNonClientMargins.bottom == -1 ? mVertResizeMargin : mNonClientMargins.bottom;
5600 contentOverlap = mx >= winRect.left + leftMargin &&
5601 mx <= winRect.right - rightMargin &&
5602 my >= winRect.top + topMargin &&
5603 my <= winRect.bottom - bottomMargin;
5606 if (!mIsInMouseCapture &&
5607 contentOverlap &&
5608 (testResult == HTCLIENT ||
5609 testResult == HTTOP ||
5610 testResult == HTTOPLEFT ||
5611 testResult == HTCAPTION)) {
5612 LPARAM lParam = MAKELPARAM(mx, my);
5613 LPARAM lParamClient = lParamToClient(lParam);
5614 PRBool result = DispatchMouseEvent(NS_MOUSE_MOZHITTEST, 0, lParamClient,
5615 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5616 if (result) {
5617 // The mouse is over a blank area
5618 testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
5620 if (!mExitToNonClientArea) {
5621 // The first time the mouse pointer goes from client area to non-client area,
5622 // we don't want to miss that movement so we can interpret mouseout input.
5623 ::SendMessage(mWnd, WM_MOUSEMOVE, 0, lParamClient);
5624 mExitToNonClientArea = PR_TRUE;
5626 } else {
5627 // There's content over the mouse pointer. Set HTCLIENT
5628 // to possibly override a resizer border.
5629 testResult = HTCLIENT;
5633 return testResult;
5637 #ifndef WINCE
5638 void nsWindow::PostSleepWakeNotification(const char* aNotification)
5640 nsCOMPtr<nsIObserverService> observerService =
5641 mozilla::services::GetObserverService();
5642 if (observerService)
5643 observerService->NotifyObservers(nsnull, aNotification, nsnull);
5645 #endif
5647 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, PRBool *aEventDispatched)
5649 NS_PRECONDITION(aMsg.message == WM_CHAR || aMsg.message == WM_SYSCHAR,
5650 "message is not keydown event");
5651 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5652 ("%s charCode=%d scanCode=%d\n",
5653 aMsg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
5654 aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF));
5656 // These must be checked here too as a lone WM_CHAR could be received
5657 // if a child window didn't handle it (for example Alt+Space in a content window)
5658 nsModifierKeyState modKeyState;
5659 return OnChar(aMsg, modKeyState, aEventDispatched);
5662 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, PRBool *aEventDispatched)
5664 NS_PRECONDITION(aMsg.message == WM_KEYUP || aMsg.message == WM_SYSKEYUP,
5665 "message is not keydown event");
5666 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5667 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5668 "WM_SYSKEYUP" : "WM_KEYUP", aMsg.wParam));
5670 nsModifierKeyState modKeyState;
5672 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5673 // scan code. However, this breaks Alt+Num pad input.
5674 // MSDN states the following:
5675 // Typically, ToAscii performs the translation based on the
5676 // virtual-key code. In some cases, however, bit 15 of the
5677 // uScanCode parameter may be used to distinguish between a key
5678 // press and a key release. The scan code is used for
5679 // translating ALT+number key combinations.
5681 // ignore [shift+]alt+space so the OS can handle it
5682 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5683 IS_VK_DOWN(NS_VK_SPACE)) {
5684 return FALSE;
5687 if (!nsIMM32Handler::IsComposingOn(this) &&
5688 (aMsg.message != WM_KEYUP || aMsg.wParam != VK_MENU)) {
5689 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5690 // This helps avoid triggering the menu bar for ALT key accelerators used in
5691 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5692 // to switch back to Mozilla in Windows 95 and Windows 98
5693 return OnKeyUp(aMsg, modKeyState, aEventDispatched);
5696 return 0;
5699 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
5700 PRBool *aEventDispatched)
5702 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5703 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5704 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg.wParam));
5705 NS_PRECONDITION(aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN,
5706 "message is not keydown event");
5708 nsModifierKeyState modKeyState;
5710 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
5711 // scan code. However, this breaks Alt+Num pad input.
5712 // MSDN states the following:
5713 // Typically, ToAscii performs the translation based on the
5714 // virtual-key code. In some cases, however, bit 15 of the
5715 // uScanCode parameter may be used to distinguish between a key
5716 // press and a key release. The scan code is used for
5717 // translating ALT+number key combinations.
5719 // ignore [shift+]alt+space so the OS can handle it
5720 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5721 IS_VK_DOWN(NS_VK_SPACE))
5722 return FALSE;
5724 LRESULT result = 0;
5725 if (modKeyState.mIsAltDown && nsIMM32Handler::IsStatusChanged()) {
5726 nsIMM32Handler::NotifyEndStatusChange();
5727 } else if (!nsIMM32Handler::IsComposingOn(this)) {
5728 result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nsnull);
5731 #ifndef WINCE
5732 if (aMsg.wParam == VK_MENU ||
5733 (aMsg.wParam == VK_F10 && !modKeyState.mIsShiftDown)) {
5734 // We need to let Windows handle this keypress,
5735 // by returning PR_FALSE, if there's a native menu
5736 // bar somewhere in our containing window hierarchy.
5737 // Otherwise we handle the keypress and don't pass
5738 // it on to Windows, by returning PR_TRUE.
5739 PRBool hasNativeMenu = PR_FALSE;
5740 HWND hWnd = mWnd;
5741 while (hWnd) {
5742 if (::GetMenu(hWnd)) {
5743 hasNativeMenu = PR_TRUE;
5744 break;
5746 hWnd = ::GetParent(hWnd);
5748 result = !hasNativeMenu;
5750 #endif
5752 return result;
5755 nsresult
5756 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
5757 PRInt32 aNativeKeyCode,
5758 PRUint32 aModifierFlags,
5759 const nsAString& aCharacters,
5760 const nsAString& aUnmodifiedCharacters)
5762 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
5763 nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
5764 HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
5765 if (loadedLayout == NULL)
5766 return NS_ERROR_NOT_AVAILABLE;
5768 // Setup clean key state and load desired layout
5769 BYTE originalKbdState[256];
5770 ::GetKeyboardState(originalKbdState);
5771 BYTE kbdState[256];
5772 memset(kbdState, 0, sizeof(kbdState));
5773 // This changes the state of the keyboard for the current thread only,
5774 // and we'll restore it soon, so this should be OK.
5775 ::SetKeyboardState(kbdState);
5776 HKL oldLayout = gKbdLayout.GetLayout();
5777 gKbdLayout.LoadLayout(loadedLayout);
5779 nsAutoTArray<KeyPair,10> keySequence;
5780 SetupKeyModifiersSequence(&keySequence, aModifierFlags);
5781 NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
5782 "Native VK key code out of range");
5783 keySequence.AppendElement(KeyPair(aNativeKeyCode, 0));
5785 // Simulate the pressing of each modifier key and then the real key
5786 for (PRUint32 i = 0; i < keySequence.Length(); ++i) {
5787 PRUint8 key = keySequence[i].mGeneral;
5788 PRUint8 keySpecific = keySequence[i].mSpecific;
5789 kbdState[key] = 0x81; // key is down and toggled on if appropriate
5790 if (keySpecific) {
5791 kbdState[keySpecific] = 0x81;
5793 ::SetKeyboardState(kbdState);
5794 nsModifierKeyState modKeyState;
5795 MSG msg = InitMSG(WM_KEYDOWN, key, 0);
5796 if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
5797 UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
5798 gKbdLayout.GetLayout());
5799 nsFakeCharMessage fakeMsg = { aCharacters.CharAt(0), scanCode };
5800 OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
5801 } else {
5802 OnKeyDown(msg, modKeyState, nsnull, nsnull);
5805 for (PRUint32 i = keySequence.Length(); i > 0; --i) {
5806 PRUint8 key = keySequence[i - 1].mGeneral;
5807 PRUint8 keySpecific = keySequence[i - 1].mSpecific;
5808 kbdState[key] = 0; // key is up and toggled off if appropriate
5809 if (keySpecific) {
5810 kbdState[keySpecific] = 0;
5812 ::SetKeyboardState(kbdState);
5813 nsModifierKeyState modKeyState;
5814 MSG msg = InitMSG(WM_KEYUP, key, 0);
5815 OnKeyUp(msg, modKeyState, nsnull);
5818 // Restore old key state and layout
5819 ::SetKeyboardState(originalKbdState);
5820 gKbdLayout.LoadLayout(oldLayout);
5822 UnloadKeyboardLayout(loadedLayout);
5823 return NS_OK;
5824 #else //XXX: is there another way to do this?
5825 return NS_ERROR_NOT_IMPLEMENTED;
5826 #endif
5829 nsresult
5830 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
5831 PRUint32 aNativeMessage,
5832 PRUint32 aModifierFlags)
5834 #ifndef WINCE // I don't think WINCE supports SendInput
5835 RECT r;
5836 ::GetWindowRect(mWnd, &r);
5837 ::SetCursorPos(r.left + aPoint.x, r.top + aPoint.y);
5839 INPUT input;
5840 memset(&input, 0, sizeof(input));
5842 input.type = INPUT_MOUSE;
5843 input.mi.dwFlags = aNativeMessage;
5844 ::SendInput(1, &input, sizeof(INPUT));
5846 return NS_OK;
5847 #else
5848 return NS_ERROR_NOT_IMPLEMENTED;
5849 #endif
5852 /**************************************************************
5854 * SECTION: OnXXX message handlers
5856 * For message handlers that need to be broken out or
5857 * implemented in specific platform code.
5859 **************************************************************/
5861 BOOL nsWindow::OnInputLangChange(HKL aHKL)
5863 #ifdef KE_DEBUG
5864 printf("OnInputLanguageChange\n");
5865 #endif
5867 #ifndef WINCE
5868 gKbdLayout.LoadLayout(aHKL);
5869 #endif
5871 return PR_FALSE; // always pass to child window
5874 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5875 void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, PRBool& result)
5877 if (wp == nsnull)
5878 return;
5880 #ifdef WINSTATE_DEBUG_OUTPUT
5881 if (mWnd == GetTopLevelHWND(mWnd))
5882 printf("*** OnWindowPosChanged: [ top] ");
5883 else
5884 printf("*** OnWindowPosChanged: [child] ");
5885 printf("WINDOWPOS flags:");
5886 if (wp->flags & SWP_FRAMECHANGED)
5887 printf("SWP_FRAMECHANGED ");
5888 if (wp->flags & SWP_SHOWWINDOW)
5889 printf("SWP_SHOWWINDOW ");
5890 if (wp->flags & SWP_NOSIZE)
5891 printf("SWP_NOSIZE ");
5892 if (wp->flags & SWP_HIDEWINDOW)
5893 printf("SWP_HIDEWINDOW ");
5894 printf("\n");
5895 #endif
5897 // Handle window size mode changes
5898 if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
5899 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
5901 WINDOWPLACEMENT pl;
5902 pl.length = sizeof(pl);
5903 ::GetWindowPlacement(mWnd, &pl);
5905 if (pl.showCmd == SW_SHOWMAXIMIZED)
5906 event.mSizeMode = nsSizeMode_Maximized;
5907 else if (pl.showCmd == SW_SHOWMINIMIZED)
5908 event.mSizeMode = nsSizeMode_Minimized;
5909 else if (mFullscreenMode)
5910 event.mSizeMode = nsSizeMode_Fullscreen;
5911 else
5912 event.mSizeMode = nsSizeMode_Normal;
5914 // Windows has just changed the size mode of this window. The following
5915 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
5916 // set the min/max window state again or for nsSizeMode_Normal, call
5917 // SetWindow with a parameter of SW_RESTORE. There's no need however as
5918 // this window's mode has already changed. Updating mSizeMode here
5919 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
5920 // to window docking. (bug 489258)
5921 mSizeMode = event.mSizeMode;
5923 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
5924 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
5925 // prevents the working set from being trimmed but keeps the window active.
5926 // After the window is minimized, we need to do some touch up work on the
5927 // active window. (bugs 76831 & 499816)
5928 if (!sTrimOnMinimize && nsSizeMode_Minimized == event.mSizeMode)
5929 ActivateOtherWindowHelper(mWnd);
5931 #ifdef WINSTATE_DEBUG_OUTPUT
5932 switch (mSizeMode) {
5933 case nsSizeMode_Normal:
5934 printf("*** mSizeMode: nsSizeMode_Normal\n");
5935 break;
5936 case nsSizeMode_Minimized:
5937 printf("*** mSizeMode: nsSizeMode_Minimized\n");
5938 break;
5939 case nsSizeMode_Maximized:
5940 printf("*** mSizeMode: nsSizeMode_Maximized\n");
5941 break;
5942 default:
5943 printf("*** mSizeMode: ??????\n");
5944 break;
5946 #endif
5948 InitEvent(event);
5950 result = DispatchWindowEvent(&event);
5952 // Skip window size change events below on minimization.
5953 if (mSizeMode == nsSizeMode_Minimized)
5954 return;
5957 // Handle window size changes
5958 if (0 == (wp->flags & SWP_NOSIZE)) {
5959 RECT r;
5960 PRInt32 newWidth, newHeight;
5962 ::GetWindowRect(mWnd, &r);
5964 newWidth = r.right - r.left;
5965 newHeight = r.bottom - r.top;
5966 nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
5968 #ifdef MOZ_XUL
5969 if (eTransparencyTransparent == mTransparencyMode)
5970 ResizeTranslucentWindow(newWidth, newHeight);
5971 #endif
5973 if (newWidth > mLastSize.width)
5975 RECT drect;
5977 // getting wider
5978 drect.left = wp->x + mLastSize.width;
5979 drect.top = wp->y;
5980 drect.right = drect.left + (newWidth - mLastSize.width);
5981 drect.bottom = drect.top + newHeight;
5983 ::RedrawWindow(mWnd, &drect, NULL,
5984 RDW_INVALIDATE |
5985 RDW_NOERASE |
5986 RDW_NOINTERNALPAINT |
5987 RDW_ERASENOW |
5988 RDW_ALLCHILDREN);
5990 if (newHeight > mLastSize.height)
5992 RECT drect;
5994 // getting taller
5995 drect.left = wp->x;
5996 drect.top = wp->y + mLastSize.height;
5997 drect.right = drect.left + newWidth;
5998 drect.bottom = drect.top + (newHeight - mLastSize.height);
6000 ::RedrawWindow(mWnd, &drect, NULL,
6001 RDW_INVALIDATE |
6002 RDW_NOERASE |
6003 RDW_NOINTERNALPAINT |
6004 RDW_ERASENOW |
6005 RDW_ALLCHILDREN);
6008 mBounds.width = newWidth;
6009 mBounds.height = newHeight;
6010 mLastSize.width = newWidth;
6011 mLastSize.height = newHeight;
6013 #ifdef WINSTATE_DEBUG_OUTPUT
6014 printf("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, newWidth, newHeight);
6015 #endif
6017 // If a maximized window is resized, recalculate the non-client margins and
6018 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
6019 // work properly.
6020 if (mSizeMode == nsSizeMode_Maximized) {
6021 if (UpdateNonClientMargins(nsSizeMode_Maximized, PR_TRUE)) {
6022 // gecko resize event already sent by UpdateNonClientMargins.
6023 result = PR_TRUE;
6024 return;
6028 // Recalculate the width and height based on the client area for gecko events.
6029 if (::GetClientRect(mWnd, &r)) {
6030 rect.width = r.right - r.left;
6031 rect.height = r.bottom - r.top;
6034 // Send a gecko resize event
6035 result = OnResize(rect);
6039 // static
6040 void nsWindow::ActivateOtherWindowHelper(HWND aWnd)
6042 // Find the next window that is enabled, visible, and not minimized.
6043 HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT);
6044 while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) ||
6045 ::IsIconic(hwndBelow))) {
6046 hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT);
6049 // Push ourselves to the bottom of the stack, then activate the
6050 // next window.
6051 ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0,
6052 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
6053 if (hwndBelow)
6054 ::SetForegroundWindow(hwndBelow);
6056 // Play the minimize sound while we're here, since that is also
6057 // forgotten when we use SW_SHOWMINIMIZED.
6058 ::PlaySoundW(L"Minimize", nsnull, SND_ALIAS | SND_NODEFAULT | SND_ASYNC);
6060 #endif // !defined(WINCE)
6062 #if !defined(WINCE)
6063 void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info)
6065 // Update non-client margins if the frame size is changing, and let the
6066 // browser know we are changing size modes, so alternative css can kick in.
6067 // If we're going into fullscreen mode, ignore this, since it'll reset
6068 // margins to normal mode.
6069 if (info->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
6070 WINDOWPLACEMENT pl;
6071 pl.length = sizeof(pl);
6072 ::GetWindowPlacement(mWnd, &pl);
6073 PRInt32 sizeMode;
6074 if (pl.showCmd == SW_SHOWMAXIMIZED)
6075 sizeMode = nsSizeMode_Maximized;
6076 else if (pl.showCmd == SW_SHOWMINIMIZED)
6077 sizeMode = nsSizeMode_Minimized;
6078 else if (mFullscreenMode)
6079 sizeMode = nsSizeMode_Fullscreen;
6080 else
6081 sizeMode = nsSizeMode_Normal;
6083 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
6085 InitEvent(event);
6086 event.mSizeMode = static_cast<nsSizeMode>(sizeMode);
6087 DispatchWindowEvent(&event);
6089 UpdateNonClientMargins(sizeMode, PR_FALSE);
6092 // enforce local z-order rules
6093 if (!(info->flags & SWP_NOZORDER)) {
6094 HWND hwndAfter = info->hwndInsertAfter;
6096 nsZLevelEvent event(PR_TRUE, NS_SETZLEVEL, this);
6097 nsWindow *aboveWindow = 0;
6099 InitEvent(event);
6101 if (hwndAfter == HWND_BOTTOM)
6102 event.mPlacement = nsWindowZBottom;
6103 else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
6104 event.mPlacement = nsWindowZTop;
6105 else {
6106 event.mPlacement = nsWindowZRelative;
6107 aboveWindow = GetNSWindowPtr(hwndAfter);
6109 event.mReqBelow = aboveWindow;
6110 event.mActualBelow = nsnull;
6112 event.mImmediate = PR_FALSE;
6113 event.mAdjusted = PR_FALSE;
6114 DispatchWindowEvent(&event);
6116 if (event.mAdjusted) {
6117 if (event.mPlacement == nsWindowZBottom)
6118 info->hwndInsertAfter = HWND_BOTTOM;
6119 else if (event.mPlacement == nsWindowZTop)
6120 info->hwndInsertAfter = HWND_TOP;
6121 else {
6122 info->hwndInsertAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
6125 NS_IF_RELEASE(event.mActualBelow);
6127 // prevent rude external programs from making hidden window visible
6128 if (mWindowType == eWindowType_invisible)
6129 info->flags &= ~SWP_SHOWWINDOW;
6131 #endif
6133 void nsWindow::UserActivity()
6135 // Check if we have the idle service, if not we try to get it.
6136 if (!mIdleService) {
6137 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
6140 // Check that we now have the idle service.
6141 if (mIdleService) {
6142 mIdleService->ResetIdleTimeOut();
6146 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6147 PRBool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam)
6149 PRUint32 cInputs = LOWORD(wParam);
6150 PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
6152 if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) {
6153 for (PRUint32 i = 0; i < cInputs; i++) {
6154 PRUint32 msg;
6155 if (pInputs[i].dwFlags & TOUCHEVENTF_MOVE) {
6156 msg = NS_MOZTOUCH_MOVE;
6157 } else if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) {
6158 msg = NS_MOZTOUCH_DOWN;
6159 } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) {
6160 msg = NS_MOZTOUCH_UP;
6161 } else {
6162 continue;
6165 nsPointWin touchPoint;
6166 touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
6167 touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
6168 touchPoint.ScreenToClient(mWnd);
6170 nsMozTouchEvent touchEvent(PR_TRUE, msg, this, pInputs[i].dwID);
6171 touchEvent.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6172 touchEvent.refPoint = touchPoint;
6174 nsEventStatus status;
6175 DispatchEvent(&touchEvent, status);
6179 delete [] pInputs;
6180 mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam);
6181 return PR_TRUE;
6183 #endif
6185 // Gesture event processing. Handles WM_GESTURE events.
6186 #if !defined(WINCE)
6187 PRBool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
6189 // Treatment for pan events which translate into scroll events:
6190 if (mGesture.IsPanEvent(lParam)) {
6191 nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
6193 if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
6194 return PR_FALSE; // ignore
6196 nsEventStatus status;
6198 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6199 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6200 event.isMeta = PR_FALSE;
6201 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6202 event.button = 0;
6203 event.time = ::GetMessageTime();
6204 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6206 PRBool endFeedback = PR_TRUE;
6208 PRInt32 scrollOverflowX = 0;
6209 PRInt32 scrollOverflowY = 0;
6211 if (mGesture.PanDeltaToPixelScrollX(event)) {
6212 DispatchEvent(&event, status);
6213 scrollOverflowX = event.scrollOverflow;
6216 if (mGesture.PanDeltaToPixelScrollY(event)) {
6217 DispatchEvent(&event, status);
6218 scrollOverflowY = event.scrollOverflow;
6221 if (mDisplayPanFeedback) {
6222 mGesture.UpdatePanFeedbackX(mWnd, scrollOverflowX, endFeedback);
6223 mGesture.UpdatePanFeedbackY(mWnd, scrollOverflowY, endFeedback);
6224 mGesture.PanFeedbackFinalize(mWnd, endFeedback);
6227 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6229 return PR_TRUE;
6232 // Other gestures translate into simple gesture events:
6233 nsSimpleGestureEvent event(PR_TRUE, 0, this, 0, 0.0);
6234 if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) {
6235 return PR_FALSE; // fall through to DefWndProc
6238 // Polish up and send off the new event
6239 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6240 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6241 event.isMeta = PR_FALSE;
6242 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6243 event.button = 0;
6244 event.time = ::GetMessageTime();
6245 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6247 nsEventStatus status;
6248 DispatchEvent(&event, status);
6249 if (status == nsEventStatus_eIgnore) {
6250 return PR_FALSE; // Ignored, fall through
6253 // Only close this if we process and return true.
6254 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6256 return PR_TRUE; // Handled
6258 #endif // !defined(WINCE)
6260 #if !defined(WINCE)
6261 PRUint16 nsWindow::GetMouseInputSource()
6263 PRUint16 inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE;
6264 LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
6265 if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
6266 inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ?
6267 PRUint16(nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH) : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN;
6269 return inputSource;
6271 #endif
6273 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6274 * within the message case block. If returning true result should be returned
6275 * immediately (no more processing).
6277 PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue)
6279 // Handle both flavors of mouse wheel events.
6280 static int iDeltaPerLine, iDeltaPerChar;
6281 static ULONG ulScrollLines, ulScrollChars = 1;
6282 static int currentVDelta, currentHDelta;
6283 static HWND currentWindow = 0;
6285 PRBool isVertical = msg == WM_MOUSEWHEEL;
6287 // Get mouse wheel metrics (but only once).
6288 if (getWheelInfo) {
6289 getWheelInfo = PR_FALSE;
6291 SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
6293 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6294 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6296 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6297 // the mouse driver wants a page scroll. The docs state that
6298 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6299 // since some mouse drivers use an arbitrary large number instead,
6300 // we have to handle that as well.
6302 iDeltaPerLine = 0;
6303 if (ulScrollLines) {
6304 if (ulScrollLines <= WHEEL_DELTA) {
6305 iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
6306 } else {
6307 ulScrollLines = WHEEL_PAGESCROLL;
6311 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
6312 &ulScrollChars, 0)) {
6313 // Note that we may always fail to get the value before Win Vista.
6314 ulScrollChars = 1;
6317 iDeltaPerChar = 0;
6318 if (ulScrollChars) {
6319 if (ulScrollChars <= WHEEL_DELTA) {
6320 iDeltaPerChar = WHEEL_DELTA / ulScrollChars;
6321 } else {
6322 ulScrollChars = WHEEL_PAGESCROLL;
6327 if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) ||
6328 (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar))
6329 return PR_FALSE; // break
6331 // The mousewheel event will be dispatched to the toplevel
6332 // window. We need to give it to the child window
6333 PRBool quit;
6334 if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit))
6335 return quit; // return immediately if its not our window
6337 // We should cancel the surplus delta if the current window is not
6338 // same as previous.
6339 if (currentWindow != mWnd) {
6340 currentVDelta = 0;
6341 currentHDelta = 0;
6342 currentWindow = mWnd;
6345 nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
6346 scrollEvent.delta = 0;
6347 if (isVertical) {
6348 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
6349 if (ulScrollLines == WHEEL_PAGESCROLL) {
6350 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6351 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1;
6352 } else {
6353 currentVDelta -= (short) HIWORD (wParam);
6354 if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
6355 scrollEvent.delta = currentVDelta / iDeltaPerLine;
6356 currentVDelta %= iDeltaPerLine;
6359 } else {
6360 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
6361 if (ulScrollChars == WHEEL_PAGESCROLL) {
6362 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6363 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1;
6364 } else {
6365 currentHDelta += (short) HIWORD (wParam);
6366 if (PR_ABS(currentHDelta) >= iDeltaPerChar) {
6367 scrollEvent.delta = currentHDelta / iDeltaPerChar;
6368 currentHDelta %= iDeltaPerChar;
6373 if (!scrollEvent.delta) {
6374 // We store the wheel delta, and it will be used next wheel message, so,
6375 // we consume this message actually. We shouldn't call next wndproc.
6376 result = PR_TRUE;
6377 return PR_FALSE; // break
6380 #ifdef MOZ_IPC
6381 // The event may go to a plug-in which already dispatched this message.
6382 // Then, the event can cause deadlock. We should unlock the sender here.
6383 ::ReplyMessage(isVertical ? 0 : TRUE);
6384 #endif
6386 scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6387 scrollEvent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6388 scrollEvent.isMeta = PR_FALSE;
6389 scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT);
6390 InitEvent(scrollEvent);
6391 if (nsnull != mEventCallback) {
6392 result = DispatchWindowEvent(&scrollEvent);
6394 // Note that we should return zero if we process WM_MOUSEWHEEL.
6395 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6397 if (result)
6398 *aRetValue = isVertical ? 0 : TRUE;
6400 return PR_FALSE; // break;
6403 static PRBool
6404 StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,
6405 const PRUnichar* aChars2, const PRUint32 aNumChars2)
6407 if (aNumChars1 != aNumChars2)
6408 return PR_FALSE;
6410 nsCaseInsensitiveStringComparator comp;
6411 return comp(aChars1, aChars2, aNumChars1) == 0;
6414 UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
6416 #ifndef WINCE
6417 switch (aNativeKeyCode) {
6418 case VK_OEM_1: return NS_VK_SEMICOLON; // 0xBA, For the US standard keyboard, the ';:' key
6419 case VK_OEM_PLUS: return NS_VK_ADD; // 0xBB, For any country/region, the '+' key
6420 case VK_OEM_MINUS: return NS_VK_SUBTRACT; // 0xBD, For any country/region, the '-' key
6422 #endif
6424 return aNativeKeyCode;
6428 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6429 * WM_CHAR messages for processing. During testing we don't want to
6430 * mess with the real message queue. Instead we pass a
6431 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6432 * that as if it was in the message queue, and refrain from actually
6433 * looking at or touching the message queue.
6435 LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
6436 nsModifierKeyState &aModKeyState,
6437 PRBool *aEventDispatched,
6438 nsFakeCharMessage* aFakeCharMessage)
6440 UINT virtualKeyCode = aMsg.wParam;
6442 #ifndef WINCE
6443 gKbdLayout.OnKeyDown (virtualKeyCode);
6444 #endif
6446 // Use only DOMKeyCode for XP processing.
6447 // Use aVirtualKeyCode for gKbdLayout and native processing.
6448 UINT DOMKeyCode = nsIMM32Handler::IsComposingOn(this) ?
6449 virtualKeyCode : MapFromNativeToDOM(virtualKeyCode);
6451 #ifdef DEBUG
6452 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6453 #endif
6455 PRBool noDefault =
6456 DispatchKeyEvent(NS_KEY_DOWN, 0, nsnull, DOMKeyCode, &aMsg, aModKeyState);
6457 if (aEventDispatched)
6458 *aEventDispatched = PR_TRUE;
6460 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6461 // for almost all keys
6462 switch (DOMKeyCode) {
6463 case NS_VK_SHIFT:
6464 case NS_VK_CONTROL:
6465 case NS_VK_ALT:
6466 case NS_VK_CAPS_LOCK:
6467 case NS_VK_NUM_LOCK:
6468 case NS_VK_SCROLL_LOCK: return noDefault;
6471 PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
6472 MSG msg;
6473 BOOL gotMsg = aFakeCharMessage ||
6474 ::PeekMessageW(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6475 // Enter and backspace are always handled here to avoid for example the
6476 // confusion between ctrl-enter and ctrl-J.
6477 if (DOMKeyCode == NS_VK_RETURN || DOMKeyCode == NS_VK_BACK ||
6478 ((aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)
6479 #ifdef WINCE
6481 #else
6482 && !gKbdLayout.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
6483 #endif
6485 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6486 // They can be more than one because of:
6487 // * Dead-keys not pairing with base character
6488 // * Some keyboard layouts may map up to 4 characters to the single key
6489 PRBool anyCharMessagesRemoved = PR_FALSE;
6491 if (aFakeCharMessage) {
6492 anyCharMessagesRemoved = PR_TRUE;
6493 } else {
6494 while (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR))
6496 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6497 ("%s charCode=%d scanCode=%d\n", msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6498 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6499 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST, WM_KEYLAST);
6500 anyCharMessagesRemoved = PR_TRUE;
6502 gotMsg = ::PeekMessageW (&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6506 if (!anyCharMessagesRemoved && DOMKeyCode == NS_VK_BACK &&
6507 nsIMM32Handler::IsDoingKakuteiUndo(mWnd)) {
6508 NS_ASSERTION(!aFakeCharMessage,
6509 "We shouldn't be touching the real msg queue");
6510 RemoveMessageAndDispatchPluginEvent(WM_CHAR, WM_CHAR);
6513 else if (gotMsg &&
6514 (aFakeCharMessage ||
6515 msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
6516 if (aFakeCharMessage)
6517 return OnCharRaw(aFakeCharMessage->mCharCode,
6518 aFakeCharMessage->mScanCode, aModKeyState, extraFlags);
6520 // If prevent default set for keydown, do same for keypress
6521 ::GetMessageW(&msg, mWnd, msg.message, msg.message);
6523 if (msg.message == WM_DEADCHAR) {
6524 if (!PluginHasFocus())
6525 return PR_FALSE;
6527 // We need to send the removed message to focused plug-in.
6528 DispatchPluginEvent(msg);
6529 return noDefault;
6532 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6533 ("%s charCode=%d scanCode=%d\n",
6534 msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6535 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6537 BOOL result = OnChar(msg, aModKeyState, nsnull, extraFlags);
6538 // If a syschar keypress wasn't processed, Windows may want to
6539 // handle it to activate a native menu.
6540 if (!result && msg.message == WM_SYSCHAR)
6541 ::DefWindowProcW(mWnd, msg.message, msg.wParam, msg.lParam);
6542 return result;
6544 #ifndef WINCE
6545 else if (!aModKeyState.mIsControlDown && !aModKeyState.mIsAltDown &&
6546 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode) ||
6547 KeyboardLayout::IsNumpadKey(virtualKeyCode)))
6549 // If this is simple KeyDown event but next message is not WM_CHAR,
6550 // this event may not input text, so we should ignore this event.
6551 // See bug 314130.
6552 return PluginHasFocus() && noDefault;
6555 if (gKbdLayout.IsDeadKey ())
6556 return PluginHasFocus() && noDefault;
6558 PRUint8 shiftStates[5];
6559 PRUnichar uniChars[5];
6560 PRUnichar shiftedChars[5] = {0, 0, 0, 0, 0};
6561 PRUnichar unshiftedChars[5] = {0, 0, 0, 0, 0};
6562 PRUnichar shiftedLatinChar = 0;
6563 PRUnichar unshiftedLatinChar = 0;
6564 PRUint32 numOfUniChars = 0;
6565 PRUint32 numOfShiftedChars = 0;
6566 PRUint32 numOfUnshiftedChars = 0;
6567 PRUint32 numOfShiftStates = 0;
6569 switch (virtualKeyCode) {
6570 // keys to be sent as characters
6571 case VK_ADD: uniChars [0] = '+'; numOfUniChars = 1; break;
6572 case VK_SUBTRACT: uniChars [0] = '-'; numOfUniChars = 1; break;
6573 case VK_DIVIDE: uniChars [0] = '/'; numOfUniChars = 1; break;
6574 case VK_MULTIPLY: uniChars [0] = '*'; numOfUniChars = 1; break;
6575 case VK_NUMPAD0:
6576 case VK_NUMPAD1:
6577 case VK_NUMPAD2:
6578 case VK_NUMPAD3:
6579 case VK_NUMPAD4:
6580 case VK_NUMPAD5:
6581 case VK_NUMPAD6:
6582 case VK_NUMPAD7:
6583 case VK_NUMPAD8:
6584 case VK_NUMPAD9:
6585 uniChars [0] = virtualKeyCode - VK_NUMPAD0 + '0';
6586 numOfUniChars = 1;
6587 break;
6588 default:
6589 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
6590 numOfUniChars = numOfShiftStates =
6591 gKbdLayout.GetUniChars(uniChars, shiftStates,
6592 NS_ARRAY_LENGTH(uniChars));
6595 if (aModKeyState.mIsControlDown ^ aModKeyState.mIsAltDown) {
6596 PRUint8 capsLockState = (::GetKeyState(VK_CAPITAL) & 1) ? eCapsLock : 0;
6597 numOfUnshiftedChars =
6598 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode, capsLockState,
6599 unshiftedChars, NS_ARRAY_LENGTH(unshiftedChars));
6600 numOfShiftedChars =
6601 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode,
6602 capsLockState | eShift,
6603 shiftedChars, NS_ARRAY_LENGTH(shiftedChars));
6605 // The current keyboard cannot input alphabets or numerics,
6606 // we should append them for Shortcut/Access keys.
6607 // E.g., for Cyrillic keyboard layout.
6608 if (NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z) {
6609 shiftedLatinChar = unshiftedLatinChar = DOMKeyCode;
6610 if (capsLockState)
6611 shiftedLatinChar += 0x20;
6612 else
6613 unshiftedLatinChar += 0x20;
6614 if (unshiftedLatinChar == unshiftedChars[0] &&
6615 shiftedLatinChar == shiftedChars[0]) {
6616 shiftedLatinChar = unshiftedLatinChar = 0;
6618 } else {
6619 PRUint16 ch = 0;
6620 if (NS_VK_0 <= DOMKeyCode && DOMKeyCode <= NS_VK_9) {
6621 ch = DOMKeyCode;
6622 } else {
6623 switch (virtualKeyCode) {
6624 case VK_OEM_PLUS: ch = '+'; break;
6625 case VK_OEM_MINUS: ch = '-'; break;
6628 if (ch && unshiftedChars[0] != ch && shiftedChars[0] != ch) {
6629 // Windows has assigned a virtual key code to the key even though
6630 // the character can't be produced with this key. That probably
6631 // means the character can't be produced with any key in the
6632 // current layout and so the assignment is based on a QWERTY
6633 // layout. Append this code so that users can access the shortcut.
6634 unshiftedLatinChar = ch;
6638 // If the charCode is not ASCII character, we should replace the
6639 // charCode with ASCII character only when Ctrl is pressed.
6640 // But don't replace the charCode when the charCode is not same as
6641 // unmodified characters. In such case, Ctrl is sometimes used for a
6642 // part of character inputting key combination like Shift.
6643 if (aModKeyState.mIsControlDown) {
6644 PRUint8 currentState = eCtrl;
6645 if (aModKeyState.mIsShiftDown)
6646 currentState |= eShift;
6648 PRUint32 ch =
6649 aModKeyState.mIsShiftDown ? shiftedLatinChar : unshiftedLatinChar;
6650 if (ch &&
6651 (numOfUniChars == 0 ||
6652 StringCaseInsensitiveEquals(uniChars, numOfUniChars,
6653 aModKeyState.mIsShiftDown ? shiftedChars : unshiftedChars,
6654 aModKeyState.mIsShiftDown ? numOfShiftedChars :
6655 numOfUnshiftedChars))) {
6656 numOfUniChars = numOfShiftStates = 1;
6657 uniChars[0] = ch;
6658 shiftStates[0] = currentState;
6664 if (numOfUniChars > 0 || numOfShiftedChars > 0 || numOfUnshiftedChars > 0) {
6665 PRUint32 num = PR_MAX(numOfUniChars,
6666 PR_MAX(numOfShiftedChars, numOfUnshiftedChars));
6667 PRUint32 skipUniChars = num - numOfUniChars;
6668 PRUint32 skipShiftedChars = num - numOfShiftedChars;
6669 PRUint32 skipUnshiftedChars = num - numOfUnshiftedChars;
6670 UINT keyCode = numOfUniChars == 0 ? DOMKeyCode : 0;
6671 for (PRUint32 cnt = 0; cnt < num; cnt++) {
6672 PRUint16 uniChar, shiftedChar, unshiftedChar;
6673 uniChar = shiftedChar = unshiftedChar = 0;
6674 if (skipUniChars <= cnt) {
6675 if (cnt - skipUniChars < numOfShiftStates) {
6676 // If key in combination with Alt and/or Ctrl produces a different
6677 // character than without them then do not report these flags
6678 // because it is separate keyboard layout shift state. If dead-key
6679 // and base character does not produce a valid composite character
6680 // then both produced dead-key character and following base
6681 // character may have different modifier flags, too.
6682 aModKeyState.mIsShiftDown =
6683 (shiftStates[cnt - skipUniChars] & eShift) != 0;
6684 aModKeyState.mIsControlDown =
6685 (shiftStates[cnt - skipUniChars] & eCtrl) != 0;
6686 aModKeyState.mIsAltDown =
6687 (shiftStates[cnt - skipUniChars] & eAlt) != 0;
6689 uniChar = uniChars[cnt - skipUniChars];
6691 if (skipShiftedChars <= cnt)
6692 shiftedChar = shiftedChars[cnt - skipShiftedChars];
6693 if (skipUnshiftedChars <= cnt)
6694 unshiftedChar = unshiftedChars[cnt - skipUnshiftedChars];
6695 nsAutoTArray<nsAlternativeCharCode, 5> altArray;
6697 if (shiftedChar || unshiftedChar) {
6698 nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
6699 altArray.AppendElement(chars);
6701 if (cnt == num - 1 && (unshiftedLatinChar || shiftedLatinChar)) {
6702 nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
6703 altArray.AppendElement(chars);
6706 DispatchKeyEvent(NS_KEY_PRESS, uniChar, &altArray,
6707 keyCode, nsnull, aModKeyState, extraFlags);
6709 } else {
6710 DispatchKeyEvent(NS_KEY_PRESS, 0, nsnull, DOMKeyCode, nsnull, aModKeyState,
6711 extraFlags);
6713 #else
6715 UINT unichar = ::MapVirtualKey(virtualKeyCode, MAPVK_VK_TO_CHAR);
6716 // Check for dead characters or no mapping
6717 if (unichar & 0x80) {
6718 return noDefault;
6720 DispatchKeyEvent(NS_KEY_PRESS, unichar, nsnull, DOMKeyCode, nsnull, aModKeyState,
6721 extraFlags);
6723 #endif
6725 return noDefault;
6728 // OnKeyUp
6729 LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
6730 nsModifierKeyState &aModKeyState,
6731 PRBool *aEventDispatched)
6733 UINT virtualKeyCode = aMsg.wParam;
6735 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6736 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
6738 if (!nsIMM32Handler::IsComposingOn(this)) {
6739 virtualKeyCode = MapFromNativeToDOM(virtualKeyCode);
6742 if (aEventDispatched)
6743 *aEventDispatched = PR_TRUE;
6744 return DispatchKeyEvent(NS_KEY_UP, 0, nsnull, virtualKeyCode, &aMsg,
6745 aModKeyState);
6748 // OnChar
6749 LRESULT nsWindow::OnChar(const MSG &aMsg, nsModifierKeyState &aModKeyState,
6750 PRBool *aEventDispatched, PRUint32 aFlags)
6752 return OnCharRaw(aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF, aModKeyState,
6753 aFlags, &aMsg, aEventDispatched);
6756 // OnCharRaw
6757 LRESULT nsWindow::OnCharRaw(UINT charCode, UINT aScanCode,
6758 nsModifierKeyState &aModKeyState, PRUint32 aFlags,
6759 const MSG *aMsg, PRBool *aEventDispatched)
6761 // ignore [shift+]alt+space so the OS can handle it
6762 if (aModKeyState.mIsAltDown && !aModKeyState.mIsControlDown &&
6763 IS_VK_DOWN(NS_VK_SPACE)) {
6764 return FALSE;
6767 // Ignore Ctrl+Enter (bug 318235)
6768 if (aModKeyState.mIsControlDown && charCode == 0xA) {
6769 return FALSE;
6772 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
6773 PRBool saveIsAltDown = aModKeyState.mIsAltDown;
6774 PRBool saveIsControlDown = aModKeyState.mIsControlDown;
6775 if (aModKeyState.mIsAltDown && aModKeyState.mIsControlDown)
6776 aModKeyState.mIsAltDown = aModKeyState.mIsControlDown = PR_FALSE;
6778 wchar_t uniChar;
6780 if (nsIMM32Handler::IsComposingOn(this)) {
6781 ResetInputState();
6784 if (aModKeyState.mIsControlDown && charCode <= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
6785 // need to account for shift here. bug 16486
6786 if (aModKeyState.mIsShiftDown)
6787 uniChar = charCode - 1 + 'A';
6788 else
6789 uniChar = charCode - 1 + 'a';
6790 charCode = 0;
6792 else if (aModKeyState.mIsControlDown && charCode <= 0x1F) {
6793 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
6794 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
6795 // for some reason the keypress handler need to have the uniChar code set
6796 // with the addition of a upper case A not the lower case.
6797 uniChar = charCode - 1 + 'A';
6798 charCode = 0;
6799 } else { // 0x20 - SPACE, 0x3D - EQUALS
6800 if (charCode < 0x20 || (charCode == 0x3D && aModKeyState.mIsControlDown)) {
6801 uniChar = 0;
6802 } else {
6803 uniChar = charCode;
6804 charCode = 0;
6808 // Keep the characters unshifted for shortcuts and accesskeys and make sure
6809 // that numbers are always passed as such (among others: bugs 50255 and 351310)
6810 if (uniChar && (aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)) {
6811 UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK,
6812 gKbdLayout.GetLayout());
6813 UINT unshiftedCharCode =
6814 virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
6815 aModKeyState.mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode,
6816 MAPVK_VK_TO_CHAR,
6817 gKbdLayout.GetLayout()) : 0;
6818 // ignore diacritics (top bit set) and key mapping errors (char code 0)
6819 if ((INT)unshiftedCharCode > 0)
6820 uniChar = unshiftedCharCode;
6823 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
6824 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
6825 // pressed too.
6826 if (!aModKeyState.mIsShiftDown && (saveIsAltDown || saveIsControlDown)) {
6827 uniChar = towlower(uniChar);
6830 PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, nsnull,
6831 charCode, aMsg, aModKeyState, aFlags);
6832 if (aEventDispatched)
6833 *aEventDispatched = PR_TRUE;
6834 aModKeyState.mIsAltDown = saveIsAltDown;
6835 aModKeyState.mIsControlDown = saveIsControlDown;
6836 return result;
6839 void
6840 nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers)
6842 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierKeyMap); ++i) {
6843 const PRUint32* map = sModifierKeyMap[i];
6844 if (aModifiers & map[0]) {
6845 aArray->AppendElement(KeyPair(map[1], map[2]));
6850 nsresult
6851 nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
6853 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
6854 // here, if that helps in some situations. So far I haven't seen a
6855 // need.
6856 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
6857 const Configuration& configuration = aConfigurations[i];
6858 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
6859 NS_ASSERTION(w->GetParent() == this,
6860 "Configured widget is not a child");
6861 #ifdef WINCE
6862 // MSDN says we should do on WinCE this before moving or resizing the window
6863 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
6864 // We put the region back just below, anyway.
6865 ::SetWindowRgn(w->mWnd, NULL, TRUE);
6866 #endif
6867 nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_TRUE);
6868 NS_ENSURE_SUCCESS(rv, rv);
6869 nsIntRect bounds;
6870 w->GetBounds(bounds);
6871 if (bounds.Size() != configuration.mBounds.Size()) {
6872 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
6873 configuration.mBounds.width, configuration.mBounds.height,
6874 PR_TRUE);
6875 } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
6876 w->Move(configuration.mBounds.x, configuration.mBounds.y);
6878 rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_FALSE);
6879 NS_ENSURE_SUCCESS(rv, rv);
6881 return NS_OK;
6884 static HRGN
6885 CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
6887 PRInt32 size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
6888 nsAutoTArray<PRUint8,100> buf;
6889 if (!buf.SetLength(size))
6890 return NULL;
6891 RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
6892 RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
6893 data->rdh.dwSize = sizeof(data->rdh);
6894 data->rdh.iType = RDH_RECTANGLES;
6895 data->rdh.nCount = aRects.Length();
6896 nsIntRect bounds;
6897 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
6898 const nsIntRect& r = aRects[i];
6899 bounds.UnionRect(bounds, r);
6900 ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
6902 ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
6903 return ::ExtCreateRegion(NULL, buf.Length(), data);
6906 nsresult
6907 nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
6908 PRBool aIntersectWithExisting)
6910 if (!aIntersectWithExisting) {
6911 if (!StoreWindowClipRegion(aRects))
6912 return NS_OK;
6913 } else {
6914 // In this case still early return if nothing changed.
6915 if (mClipRects && mClipRectCount == aRects.Length() &&
6916 memcmp(mClipRects,
6917 aRects.Elements(),
6918 sizeof(nsIntRect)*mClipRectCount) == 0) {
6919 return NS_OK;
6923 HRGN dest = CreateHRGNFromArray(aRects);
6924 if (!dest)
6925 return NS_ERROR_OUT_OF_MEMORY;
6927 if (aIntersectWithExisting) {
6928 HRGN current = ::CreateRectRgn(0, 0, 0, 0);
6929 if (current) {
6930 if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
6931 ::CombineRgn(dest, dest, current, RGN_AND);
6933 ::DeleteObject(current);
6937 if (!::SetWindowRgn(mWnd, dest, TRUE)) {
6938 ::DeleteObject(dest);
6939 return NS_ERROR_FAILURE;
6941 return NS_OK;
6944 // WM_DESTROY event handler
6945 void nsWindow::OnDestroy()
6947 mOnDestroyCalled = PR_TRUE;
6949 // Make sure we don't get destroyed in the process of tearing down.
6950 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
6952 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
6953 if (!mInDtor)
6954 DispatchStandardEvent(NS_DESTROY);
6956 // Prevent the widget from sending additional events.
6957 mEventCallback = nsnull;
6959 // Free our subclass and clear |this| stored in the window props. We will no longer
6960 // receive events from Windows after this point.
6961 SubclassWindow(FALSE);
6963 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
6964 // cleared. (It's used in tracking windows for mouse events.)
6965 if (sCurrentWindow == this)
6966 sCurrentWindow = nsnull;
6968 // Disconnects us from our parent, will call our GetParent().
6969 nsBaseWidget::Destroy();
6971 // Release references to children, device context, toolkit, and app shell.
6972 nsBaseWidget::OnDestroy();
6974 // Clear our native parent handle.
6975 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
6976 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
6977 //SetParent(nsnull);
6978 mParent = nsnull;
6980 // We have to destroy the native drag target before we null out our window pointer.
6981 EnableDragDrop(PR_FALSE);
6983 // If we're going away and for some reason we're still the rollup widget, rollup and
6984 // turn off capture.
6985 if ( this == sRollupWidget ) {
6986 if ( sRollupListener )
6987 sRollupListener->Rollup(nsnull, nsnull);
6988 CaptureRollupEvents(nsnull, nsnull, PR_FALSE, PR_TRUE);
6991 // If IME is disabled, restore it.
6992 if (mOldIMC) {
6993 mOldIMC = ::ImmAssociateContext(mWnd, mOldIMC);
6994 NS_ASSERTION(!mOldIMC, "Another IMC was associated");
6997 // Turn off mouse trails if enabled.
6998 MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
6999 if (mtrailer) {
7000 if (mtrailer->GetMouseTrailerWindow() == mWnd)
7001 mtrailer->DestroyTimer();
7003 if (mtrailer->GetCaptureWindow() == mWnd)
7004 mtrailer->SetCaptureWindow(nsnull);
7007 // Free GDI window class objects
7008 if (mBrush) {
7009 VERIFY(::DeleteObject(mBrush));
7010 mBrush = NULL;
7013 // Free app icon resources.
7014 HICON icon;
7015 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM) 0);
7016 if (icon)
7017 ::DestroyIcon(icon);
7019 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM) 0);
7020 if (icon)
7021 ::DestroyIcon(icon);
7023 // Destroy any custom cursor resources.
7024 if (mCursor == -1)
7025 SetCursor(eCursor_standard);
7027 #ifdef MOZ_XUL
7028 // Reset transparency
7029 if (eTransparencyTransparent == mTransparencyMode)
7030 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
7031 #endif
7033 #if defined(WINCE_HAVE_SOFTKB)
7034 // Revert the changes made for the software keyboard settings
7035 nsWindowCE::ResetSoftKB(mWnd);
7036 #endif
7038 #if !defined(WINCE)
7039 // Finalize panning feedback to possibly restore window displacement
7040 mGesture.PanFeedbackFinalize(mWnd, PR_TRUE);
7041 #endif
7043 // Clear the main HWND.
7044 mWnd = NULL;
7047 // OnMove
7048 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
7050 mBounds.x = aX;
7051 mBounds.y = aY;
7053 nsGUIEvent event(PR_TRUE, NS_MOVE, this);
7054 InitEvent(event);
7055 event.refPoint.x = aX;
7056 event.refPoint.y = aY;
7058 return DispatchWindowEvent(&event);
7061 // Send a resize message to the listener
7062 PRBool nsWindow::OnResize(nsIntRect &aWindowRect)
7064 #ifdef CAIRO_HAS_D2D_SURFACE
7065 if (mD2DWindowSurface) {
7066 mD2DWindowSurface = NULL;
7067 Invalidate(PR_FALSE);
7069 #endif
7071 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7072 UpdateCaptionButtonsClippingRect();
7073 #endif
7075 // call the event callback
7076 if (mEventCallback) {
7077 nsSizeEvent event(PR_TRUE, NS_SIZE, this);
7078 InitEvent(event);
7079 event.windowSize = &aWindowRect;
7080 RECT r;
7081 if (::GetWindowRect(mWnd, &r)) {
7082 event.mWinWidth = PRInt32(r.right - r.left);
7083 event.mWinHeight = PRInt32(r.bottom - r.top);
7084 } else {
7085 event.mWinWidth = 0;
7086 event.mWinHeight = 0;
7089 #if 0
7090 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7091 aWindowRect.x, aWindowRect.y, aWindowRect.width, aWindowRect.height,
7092 event.mWinWidth, event.mWinHeight);
7093 #endif
7095 return DispatchWindowEvent(&event);
7098 return PR_FALSE;
7101 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7102 PRBool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
7104 return PR_TRUE;
7106 #endif // !defined(WINCE)
7108 void nsWindow::OnSettingsChange(WPARAM wParam, LPARAM lParam)
7110 if (mWindowType == eWindowType_dialog ||
7111 mWindowType == eWindowType_toplevel )
7112 nsWindowGfx::OnSettingsChangeGfx(wParam);
7115 static PRBool IsOurProcessWindow(HWND aHWND)
7117 DWORD processId = 0;
7118 ::GetWindowThreadProcessId(aHWND, &processId);
7119 return processId == ::GetCurrentProcessId();
7122 static HWND FindOurProcessWindow(HWND aHWND)
7124 for (HWND wnd = ::GetParent(aHWND); wnd; wnd = ::GetParent(wnd)) {
7125 if (IsOurProcessWindow(wnd)) {
7126 return wnd;
7129 return nsnull;
7132 // Scrolling helper function for handling plugins.
7133 // Return value indicates whether the calling function should handle this
7134 // aHandled indicates whether this was handled at all
7135 // aQuitProcessing tells whether or not to continue processing the message
7136 PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
7137 LPARAM aLParam, PRBool& aHandled,
7138 LRESULT* aRetValue,
7139 PRBool& aQuitProcessing)
7141 // The scroll event will be dispatched to the toplevel
7142 // window. We need to give it to the child window
7143 aQuitProcessing = PR_FALSE; // default is to not stop processing
7144 POINT point;
7145 DWORD dwPoints = ::GetMessagePos();
7146 point.x = GET_X_LPARAM(dwPoints);
7147 point.y = GET_Y_LPARAM(dwPoints);
7149 static PRBool sIsProcessing = PR_FALSE;
7150 if (sIsProcessing) {
7151 return PR_TRUE; // the caller should handle this.
7154 static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
7155 if (aMsg == WM_MOUSEHWHEEL) {
7156 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7157 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7158 // message at first time, this time, ::GetMessagePos works fine.
7159 // Then, we will return 0 (0 means we process it) to the message. Then, the
7160 // driver will POST the same messages continuously during the wheel tilted.
7161 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7162 // cursor isn't 0,0. Therefore, we cannot trust the result of
7163 // ::GetMessagePos API if the sender is the driver.
7164 if (!sMayBeUsingLogitechMouse && aLParam == 0 && (DWORD)aLParam != dwPoints &&
7165 ::InSendMessage()) {
7166 sMayBeUsingLogitechMouse = PR_TRUE;
7167 } else if (sMayBeUsingLogitechMouse && aLParam != 0 && ::InSendMessage()) {
7168 // The user has changed the mouse from Logitech's to another one (e.g.,
7169 // the user has changed to the touchpad of the notebook.
7170 sMayBeUsingLogitechMouse = PR_FALSE;
7172 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7173 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7174 // instead.
7175 if (sMayBeUsingLogitechMouse && aLParam == 0 && dwPoints == 0) {
7176 ::GetCursorPos(&point);
7180 HWND destWnd = ::WindowFromPoint(point);
7181 // Since we receive scroll events for as long as
7182 // we are focused, it's entirely possible that there
7183 // is another app's window or no window under the
7184 // pointer.
7186 if (!destWnd) {
7187 // No window is under the pointer
7188 return PR_FALSE; // break, but continue processing
7191 nsWindow* destWindow;
7193 // We don't handle the message if the found window belongs to another
7194 // process's top window. If it belongs window, that is a plug-in's window.
7195 // Then, we need to send the message to the plug-in window.
7196 if (!IsOurProcessWindow(destWnd)) {
7197 HWND ourPluginWnd = FindOurProcessWindow(destWnd);
7198 if (!ourPluginWnd) {
7199 // Somebody elses window
7200 return PR_FALSE; // break, but continue processing
7202 destWindow = GetNSWindowPtr(ourPluginWnd);
7203 } else {
7204 destWindow = GetNSWindowPtr(destWnd);
7207 if (destWindow == this && mWindowType == eWindowType_plugin) {
7208 // If this is plug-in window, the message came from the plug-in window.
7209 // Then, the message should be processed on the parent window.
7210 destWindow = static_cast<nsWindow*>(GetParent());
7211 NS_ENSURE_TRUE(destWindow, PR_FALSE); // break, but continue processing
7212 destWnd = destWindow->mWnd;
7213 NS_ENSURE_TRUE(destWnd, PR_FALSE); // break, but continue processing
7216 if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
7217 // Some other app, or a plugin window.
7218 // Windows directs scrolling messages to the focused window.
7219 // However, Mozilla does not like plugins having focus, so a
7220 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7221 // Therefore, plugins etc _should_ get first grab at the
7222 // message, but this focus vaguary means the plugin misses
7223 // out. If the window is a child of ours, forward it on.
7224 // Determine if a child by walking the parent list until
7225 // we find a parent matching our wndproc.
7226 HWND parentWnd = ::GetParent(destWnd);
7227 while (parentWnd) {
7228 nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
7229 if (parentWindow) {
7230 // We have a child window - quite possibly a plugin window.
7231 // However, not all plugins are created equal - some will handle this
7232 // message themselves, some will forward directly back to us, while
7233 // others will call DefWndProc, which itself still forwards back to us.
7234 // So if we have sent it once, we need to handle it ourself.
7236 #ifdef MOZ_IPC
7237 // XXX The message shouldn't come from the plugin window at here.
7238 // But the message might come from it due to some bugs. If it happens,
7239 // SendMessage causes deadlock. For safety, we should unlock the
7240 // sender here.
7241 ::ReplyMessage(aMsg == WM_MOUSEHWHEEL ? TRUE : 0);
7242 #endif
7244 // First time we have seen this message.
7245 // Call the child - either it will consume it, or
7246 // it will wind it's way back to us,triggering the destWnd case above
7247 // either way,when the call returns,we are all done with the message,
7248 sIsProcessing = PR_TRUE;
7249 ::SendMessageW(destWnd, aMsg, aWParam, aLParam);
7250 sIsProcessing = PR_FALSE;
7251 aHandled = PR_TRUE;
7252 aQuitProcessing = PR_TRUE;
7253 return PR_FALSE; // break, and stop processing
7255 parentWnd = ::GetParent(parentWnd);
7256 } // while parentWnd
7258 if (destWnd == nsnull)
7259 return PR_FALSE;
7260 if (destWnd != mWnd) {
7261 if (destWindow) {
7262 sIsProcessing = PR_TRUE;
7263 aHandled = destWindow->ProcessMessage(aMsg, aWParam, aLParam, aRetValue);
7264 sIsProcessing = PR_FALSE;
7265 aQuitProcessing = PR_TRUE;
7266 return PR_FALSE; // break, and stop processing
7268 #ifdef DEBUG
7269 else
7270 printf("WARNING: couldn't get child window for SCROLL event\n");
7271 #endif
7273 return PR_TRUE; // caller should handle this
7276 PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
7278 static PRInt8 sMouseWheelEmulation = -1;
7279 if (sMouseWheelEmulation < 0) {
7280 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7281 NS_ENSURE_TRUE(prefs, PR_FALSE);
7282 nsCOMPtr<nsIPrefBranch> prefBranch;
7283 prefs->GetBranch(0, getter_AddRefs(prefBranch));
7284 NS_ENSURE_TRUE(prefBranch, PR_FALSE);
7285 PRBool emulate;
7286 nsresult rv =
7287 prefBranch->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate);
7288 NS_ENSURE_SUCCESS(rv, PR_FALSE);
7289 sMouseWheelEmulation = PRInt8(emulate);
7292 if (aLParam || sMouseWheelEmulation) {
7293 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7294 // Treat as a mousewheel message and scroll appropriately
7295 PRBool quit, result;
7296 LRESULT retVal;
7298 if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result, &retVal, quit))
7299 return quit; // Return if it's not our message or has been dispatched
7301 nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
7302 scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
7303 ? nsMouseScrollEvent::kIsVertical
7304 : nsMouseScrollEvent::kIsHorizontal;
7305 switch (LOWORD(aWParam))
7307 case SB_PAGEDOWN:
7308 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7309 case SB_LINEDOWN:
7310 scrollevent.delta = 1;
7311 break;
7312 case SB_PAGEUP:
7313 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7314 case SB_LINEUP:
7315 scrollevent.delta = -1;
7316 break;
7317 default:
7318 return PR_FALSE;
7320 #ifdef MOZ_IPC
7321 // The event may go to a plug-in which already dispatched this message.
7322 // Then, the event can cause deadlock. We should unlock the sender here.
7323 ::ReplyMessage(0);
7324 #endif
7325 scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
7326 scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
7327 scrollevent.isMeta = PR_FALSE;
7328 scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
7329 InitEvent(scrollevent);
7330 if (nsnull != mEventCallback)
7332 DispatchWindowEvent(&scrollevent);
7334 return PR_TRUE;
7337 // Scroll message generated by external application
7338 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_SCROLL, this);
7340 command.mScroll.mIsHorizontal = (aMsg == WM_HSCROLL);
7342 switch (LOWORD(aWParam))
7344 case SB_LINEUP: // SB_LINELEFT
7345 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7346 command.mScroll.mAmount = -1;
7347 break;
7348 case SB_LINEDOWN: // SB_LINERIGHT
7349 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7350 command.mScroll.mAmount = 1;
7351 break;
7352 case SB_PAGEUP: // SB_PAGELEFT
7353 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7354 command.mScroll.mAmount = -1;
7355 break;
7356 case SB_PAGEDOWN: // SB_PAGERIGHT
7357 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7358 command.mScroll.mAmount = 1;
7359 break;
7360 case SB_TOP: // SB_LEFT
7361 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7362 command.mScroll.mAmount = -1;
7363 break;
7364 case SB_BOTTOM: // SB_RIGHT
7365 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7366 command.mScroll.mAmount = 1;
7367 break;
7368 default:
7369 return PR_FALSE;
7371 DispatchWindowEvent(&command);
7372 return PR_TRUE;
7375 // Can be overriden. Controls auto-erase of background.
7376 PRBool nsWindow::AutoErase(HDC dc)
7378 return PR_FALSE;
7381 /**************************************************************
7382 **************************************************************
7384 ** BLOCK: IME management and accessibility
7386 ** Handles managing IME input and accessibility.
7388 **************************************************************
7389 **************************************************************/
7391 NS_IMETHODIMP nsWindow::ResetInputState()
7393 #ifdef DEBUG_KBSTATE
7394 printf("ResetInputState\n");
7395 #endif
7397 #ifdef NS_ENABLE_TSF
7398 nsTextStore::CommitComposition(PR_FALSE);
7399 #endif //NS_ENABLE_TSF
7401 nsIMM32Handler::CommitComposition(this);
7402 return NS_OK;
7405 NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState)
7407 #ifdef DEBUG_KBSTATE
7408 printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
7409 #endif
7411 #ifdef NS_ENABLE_TSF
7412 nsTextStore::SetIMEOpenState(aState);
7413 #endif //NS_ENABLE_TSF
7415 nsIMEContext IMEContext(mWnd);
7416 if (IMEContext.IsValid()) {
7417 ::ImmSetOpenStatus(IMEContext.get(), aState ? TRUE : FALSE);
7419 return NS_OK;
7422 NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState)
7424 nsIMEContext IMEContext(mWnd);
7425 if (IMEContext.IsValid()) {
7426 BOOL isOpen = ::ImmGetOpenStatus(IMEContext.get());
7427 *aState = isOpen ? PR_TRUE : PR_FALSE;
7428 } else
7429 *aState = PR_FALSE;
7431 #ifdef NS_ENABLE_TSF
7432 *aState |= nsTextStore::GetIMEOpenState();
7433 #endif //NS_ENABLE_TSF
7435 return NS_OK;
7438 NS_IMETHODIMP nsWindow::SetIMEEnabled(PRUint32 aState)
7440 #ifdef NS_ENABLE_TSF
7441 nsTextStore::SetIMEEnabled(aState);
7442 #endif //NS_ENABLE_TSF
7443 #ifdef DEBUG_KBSTATE
7444 printf("SetIMEEnabled: %s\n", (aState == nsIWidget::IME_STATUS_ENABLED ||
7445 aState == nsIWidget::IME_STATUS_PLUGIN)?
7446 "Enabled": "Disabled");
7447 #endif
7448 if (nsIMM32Handler::IsComposing()) {
7449 ResetInputState();
7451 mIMEEnabled = aState;
7452 PRBool enable = (aState == nsIWidget::IME_STATUS_ENABLED ||
7453 aState == nsIWidget::IME_STATUS_PLUGIN);
7455 #if defined(WINCE_HAVE_SOFTKB)
7456 sSoftKeyboardState = (aState != nsIWidget::IME_STATUS_DISABLED);
7457 nsWindowCE::ToggleSoftKB(mWnd, sSoftKeyboardState);
7458 #endif
7460 if (!enable != !mOldIMC)
7461 return NS_OK;
7462 mOldIMC = ::ImmAssociateContext(mWnd, enable ? mOldIMC : NULL);
7463 NS_ASSERTION(!enable || !mOldIMC, "Another IMC was associated");
7465 return NS_OK;
7468 NS_IMETHODIMP nsWindow::GetIMEEnabled(PRUint32* aState)
7470 #ifdef DEBUG_KBSTATE
7471 printf("GetIMEEnabled: %s\n", mIMEEnabled? "Enabled": "Disabled");
7472 #endif
7473 *aState = mIMEEnabled;
7474 return NS_OK;
7477 NS_IMETHODIMP nsWindow::CancelIMEComposition()
7479 #ifdef DEBUG_KBSTATE
7480 printf("CancelIMEComposition\n");
7481 #endif
7483 #ifdef NS_ENABLE_TSF
7484 nsTextStore::CommitComposition(PR_TRUE);
7485 #endif //NS_ENABLE_TSF
7487 nsIMM32Handler::CancelComposition(this);
7488 return NS_OK;
7491 NS_IMETHODIMP
7492 nsWindow::GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState)
7494 #ifdef DEBUG_KBSTATE
7495 printf("GetToggledKeyState\n");
7496 #endif
7497 NS_ENSURE_ARG_POINTER(aLEDState);
7498 *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
7499 return NS_OK;
7502 #ifdef NS_ENABLE_TSF
7503 NS_IMETHODIMP
7504 nsWindow::OnIMEFocusChange(PRBool aFocus)
7506 nsresult rv = nsTextStore::OnFocusChange(aFocus, this, mIMEEnabled);
7507 if (rv == NS_ERROR_NOT_AVAILABLE)
7508 rv = NS_ERROR_NOT_IMPLEMENTED; // TSF is not enabled, maybe.
7509 return rv;
7512 NS_IMETHODIMP
7513 nsWindow::OnIMETextChange(PRUint32 aStart,
7514 PRUint32 aOldEnd,
7515 PRUint32 aNewEnd)
7517 return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
7520 NS_IMETHODIMP
7521 nsWindow::OnIMESelectionChange(void)
7523 return nsTextStore::OnSelectionChange();
7525 #endif //NS_ENABLE_TSF
7527 #ifdef ACCESSIBILITY
7529 #ifdef DEBUG_WMGETOBJECT
7530 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
7531 nsAccessible* acc = aWnd ? \
7532 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
7533 printf(" acc: %p", acc); \
7534 if (acc) { \
7535 nsAutoString name; \
7536 acc->GetName(name); \
7537 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
7538 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
7539 void *hwnd = nsnull; \
7540 doc->GetWindowHandle(&hwnd); \
7541 printf(", acc hwnd: %d", hwnd); \
7544 #define NS_LOG_WMGETOBJECT_THISWND \
7546 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
7547 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p, content type: %d,\n",\
7548 mWnd, ::GetParent(mWnd), this, mContentType); \
7549 NS_LOG_WMGETOBJECT_WNDACC(this) \
7550 printf("\n }\n"); \
7553 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
7555 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
7556 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7557 aHwnd, ::GetParent(aHwnd), wnd); \
7558 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
7559 printf("\n }\n"); \
7561 #else
7562 #define NS_LOG_WMGETOBJECT_THISWND
7563 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
7564 #endif // DEBUG_WMGETOBJECT
7566 nsAccessible*
7567 nsWindow::GetRootAccessible()
7569 // We want the ability to forcibly disable a11y on windows, because
7570 // some non-a11y-related components attempt to bring it up. See bug
7571 // 538530 for details; we have a pref here that allows it to be disabled
7572 // for performance and testing resons.
7574 // This pref is checked only once, and the browser needs a restart to
7575 // pick up any changes.
7576 static int accForceDisable = -1;
7578 if (accForceDisable == -1) {
7579 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7580 PRBool b = PR_FALSE;
7581 nsresult rv = prefs->GetBoolPref("accessibility.win32.force_disabled", &b);
7582 if (NS_SUCCEEDED(rv) && b) {
7583 accForceDisable = 1;
7584 } else {
7585 accForceDisable = 0;
7589 // If the pref was true, return null here, disabling a11y.
7590 if (accForceDisable)
7591 return nsnull;
7593 nsWindow::sIsAccessibilityOn = TRUE;
7595 if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) {
7596 return nsnull;
7599 NS_LOG_WMGETOBJECT_THISWND
7601 if (mContentType != eContentTypeInherit) {
7602 // We're on a MozillaContentWindowClass or MozillaUIWindowClass window.
7603 // Search for the correct visible child window to get an accessible
7604 // document from. Make sure to use an active child window. If this window
7605 // doesn't have child windows then return an accessible for it.
7606 HWND accessibleWnd = ::GetTopWindow(mWnd);
7607 NS_LOG_WMGETOBJECT_WND("Top Window", accessibleWnd);
7608 if (!accessibleWnd) {
7609 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
7610 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
7613 nsWindow* accessibleWindow = nsnull;
7614 while (accessibleWnd) {
7615 // Loop through windows and find the first one with accessibility info
7616 accessibleWindow = GetNSWindowPtr(accessibleWnd);
7617 if (accessibleWindow) {
7618 nsAccessible *rootAccessible =
7619 accessibleWindow->DispatchAccessibleEvent(NS_GETACCESSIBLE);
7620 if (rootAccessible) {
7621 // Success, one of the child windows was active.
7622 return rootAccessible;
7625 accessibleWnd = ::GetNextWindow(accessibleWnd, GW_HWNDNEXT);
7626 NS_LOG_WMGETOBJECT_WND("Next Window", accessibleWnd);
7628 return nsnull;
7631 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
7632 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
7635 STDMETHODIMP_(LRESULT)
7636 nsWindow::LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc)
7638 // open the dll dynamically
7639 if (!sAccLib)
7640 sAccLib =::LoadLibraryW(L"OLEACC.DLL");
7642 if (sAccLib) {
7643 if (!sLresultFromObject)
7644 sLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(sAccLib,"LresultFromObject");
7646 if (sLresultFromObject)
7647 return sLresultFromObject(riid,wParam,pAcc);
7650 return 0;
7652 #endif
7654 /**************************************************************
7655 **************************************************************
7657 ** BLOCK: Transparency
7659 ** Window transparency helpers.
7661 **************************************************************
7662 **************************************************************/
7664 #ifdef MOZ_XUL
7666 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force)
7668 if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
7669 return;
7671 #ifdef CAIRO_HAS_D2D_SURFACE
7672 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7673 gfxWindowsPlatform::RENDER_DIRECT2D) {
7674 nsRefPtr<gfxD2DSurface> newSurface =
7675 new gfxD2DSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7676 mTransparentSurface = newSurface;
7677 mMemoryDC = nsnull;
7678 } else
7679 #endif
7681 nsRefPtr<gfxWindowsSurface> newSurface =
7682 new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7683 mTransparentSurface = newSurface;
7684 mMemoryDC = newSurface->GetDC();
7688 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
7690 #ifndef WINCE
7692 if (aMode == mTransparencyMode)
7693 return;
7695 // stop on dialogs and popups!
7696 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7697 nsWindow* parent = GetNSWindowPtr(hWnd);
7699 if (!parent)
7701 NS_WARNING("Trying to use transparent chrome in an embedded context");
7702 return;
7705 if (parent != this) {
7706 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
7709 if (aMode == eTransparencyTransparent) {
7710 // If we're switching to the use of a transparent window, hide the chrome
7711 // on our parent.
7712 HideWindowChrome(PR_TRUE);
7713 } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) {
7714 // if we're switching out of transparent, re-enable our parent's chrome.
7715 HideWindowChrome(PR_FALSE);
7718 LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE),
7719 exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
7721 if (parent->mIsVisible)
7722 style |= WS_VISIBLE;
7723 if (parent->mSizeMode == nsSizeMode_Maximized)
7724 style |= WS_MAXIMIZE;
7725 else if (parent->mSizeMode == nsSizeMode_Minimized)
7726 style |= WS_MINIMIZE;
7728 if (aMode == eTransparencyTransparent)
7729 exStyle |= WS_EX_LAYERED;
7730 else
7731 exStyle &= ~WS_EX_LAYERED;
7733 VERIFY_WINDOW_STYLE(style);
7734 ::SetWindowLongPtrW(hWnd, GWL_STYLE, style);
7735 ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle);
7737 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7738 if (HasGlass())
7739 memset(&mGlassMargins, 0, sizeof mGlassMargins);
7740 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7741 mTransparencyMode = aMode;
7743 SetupTranslucentWindowMemoryBitmap(aMode);
7744 UpdateGlass();
7745 #endif // #ifndef WINCE
7748 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
7750 if (eTransparencyTransparent == aMode) {
7751 ResizeTranslucentWindow(mBounds.width, mBounds.height, PR_TRUE);
7752 } else {
7753 mTransparentSurface = nsnull;
7754 mMemoryDC = NULL;
7758 nsresult nsWindow::UpdateTranslucentWindow()
7760 #ifndef WINCE
7761 if (mBounds.IsEmpty())
7762 return NS_OK;
7764 ::GdiFlush();
7766 BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
7767 SIZE winSize = { mBounds.width, mBounds.height };
7768 POINT srcPos = { 0, 0 };
7769 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7770 RECT winRect;
7771 ::GetWindowRect(hWnd, &winRect);
7773 #ifdef CAIRO_HAS_D2D_SURFACE
7774 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7775 gfxWindowsPlatform::RENDER_DIRECT2D) {
7776 mMemoryDC = static_cast<gfxD2DSurface*>(mTransparentSurface.get())->
7777 GetDC(PR_TRUE);
7779 #endif
7780 // perform the alpha blend
7781 PRBool updateSuccesful =
7782 ::UpdateLayeredWindow(hWnd, NULL, (POINT*)&winRect, &winSize, mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA);
7784 #ifdef CAIRO_HAS_D2D_SURFACE
7785 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7786 gfxWindowsPlatform::RENDER_DIRECT2D) {
7787 nsIntRect r(0, 0, 0, 0);
7788 static_cast<gfxD2DSurface*>(mTransparentSurface.get())->ReleaseDC(&r);
7790 #endif
7792 if (!updateSuccesful) {
7793 return NS_ERROR_FAILURE;
7795 #endif
7797 return NS_OK;
7800 #endif //MOZ_XUL
7802 /**************************************************************
7803 **************************************************************
7805 ** BLOCK: Popup rollup hooks
7807 ** Deals with CaptureRollup on popup windows.
7809 **************************************************************
7810 **************************************************************/
7812 #ifndef WINCE
7813 // Schedules a timer for a window, so we can rollup after processing the hook event
7814 void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId)
7816 // In some cases multiple hooks may be scheduled
7817 // so ignore any other requests once one timer is scheduled
7818 if (sHookTimerId == 0) {
7819 // Remember the window handle and the message ID to be used later
7820 sRollupMsgId = aMsgId;
7821 sRollupMsgWnd = aWnd;
7822 // Schedule native timer for doing the rollup after
7823 // this event is done being processed
7824 sHookTimerId = ::SetTimer(NULL, 0, 0, (TIMERPROC)HookTimerForPopups);
7825 NS_ASSERTION(sHookTimerId, "Timer couldn't be created.");
7829 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7830 int gLastMsgCode = 0;
7831 extern MSGFEventMsgInfo gMSGFEvents[];
7832 #endif
7834 // Process Menu messages, rollup when popup is clicked.
7835 LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam)
7837 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7838 if (sProcessHook) {
7839 MSG* pMsg = (MSG*)lParam;
7841 int inx = 0;
7842 while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != NULL) {
7843 inx++;
7845 if (code != gLastMsgCode) {
7846 if (gMSGFEvents[inx].mId == code) {
7847 #ifdef DEBUG
7848 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code, gMSGFEvents[inx].mStr, pMsg->hwnd);
7849 #endif
7850 } else {
7851 #ifdef DEBUG
7852 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code, gMSGFEvents[inx].mId, pMsg->hwnd);
7853 #endif
7855 gLastMsgCode = code;
7857 PrintEvent(pMsg->message, FALSE, FALSE);
7859 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7861 if (sProcessHook && code == MSGF_MENU) {
7862 MSG* pMsg = (MSG*)lParam;
7863 ScheduleHookTimer( pMsg->hwnd, pMsg->message);
7866 return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
7869 // Process all mouse messages. Roll up when a click is in a native window
7870 // that doesn't have an nsIWidget.
7871 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
7873 if (sProcessHook) {
7874 switch (wParam) {
7875 case WM_LBUTTONDOWN:
7876 case WM_RBUTTONDOWN:
7877 case WM_MBUTTONDOWN:
7878 case WM_MOUSEWHEEL:
7879 case WM_MOUSEHWHEEL:
7881 MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
7882 nsIWidget* mozWin = (nsIWidget*)GetNSWindowPtr(ms->hwnd);
7883 if (mozWin) {
7884 // If this window is windowed plugin window, the mouse events are not
7885 // sent to us.
7886 if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin)
7887 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7888 } else {
7889 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7891 break;
7895 return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam);
7898 // Process all messages. Roll up when the window is moving, or
7899 // is resizing or when maximized or mininized.
7900 LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam)
7902 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7903 if (sProcessHook) {
7904 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7905 PrintEvent(cwpt->message, FALSE, FALSE);
7907 #endif
7909 if (sProcessHook) {
7910 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7911 if (cwpt->message == WM_MOVING ||
7912 cwpt->message == WM_SIZING ||
7913 cwpt->message == WM_GETMINMAXINFO) {
7914 ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message);
7918 return ::CallNextHookEx(sCallProcHook, code, wParam, lParam);
7921 // Register the special "hooks" for dropdown processing.
7922 void nsWindow::RegisterSpecialDropdownHooks()
7924 NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!");
7925 NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!");
7927 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
7929 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
7931 // Install msg hook for moving the window and resizing
7932 if (!sMsgFilterHook) {
7933 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
7934 sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, NULL, GetCurrentThreadId());
7935 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7936 if (!sMsgFilterHook) {
7937 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
7939 #endif
7942 // Install msg hook for menus
7943 if (!sCallProcHook) {
7944 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
7945 sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, NULL, GetCurrentThreadId());
7946 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7947 if (!sCallProcHook) {
7948 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
7950 #endif
7953 // Install msg hook for the mouse
7954 if (!sCallMouseHook) {
7955 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
7956 sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, NULL, GetCurrentThreadId());
7957 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7958 if (!sCallMouseHook) {
7959 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
7961 #endif
7965 // Unhook special message hooks for dropdowns.
7966 void nsWindow::UnregisterSpecialDropdownHooks()
7968 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
7970 if (sCallProcHook) {
7971 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
7972 if (!::UnhookWindowsHookEx(sCallProcHook)) {
7973 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
7975 sCallProcHook = NULL;
7978 if (sMsgFilterHook) {
7979 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
7980 if (!::UnhookWindowsHookEx(sMsgFilterHook)) {
7981 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
7983 sMsgFilterHook = NULL;
7986 if (sCallMouseHook) {
7987 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
7988 if (!::UnhookWindowsHookEx(sCallMouseHook)) {
7989 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
7991 sCallMouseHook = NULL;
7995 // This timer is designed to only fire one time at most each time a "hook" function
7996 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
7997 // hook, but that hook event or a subsequent event may roll up the dropdown before
7998 // this timer function is executed.
8000 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
8001 // before this function fires.
8002 VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
8004 if (sHookTimerId != 0) {
8005 // if the window is NULL then we need to use the ID to kill the timer
8006 BOOL status = ::KillTimer(NULL, sHookTimerId);
8007 NS_ASSERTION(status, "Hook Timer was not killed.");
8008 sHookTimerId = 0;
8011 if (sRollupMsgId != 0) {
8012 // Note: DealWithPopups does the check to make sure that
8013 // sRollupListener and sRollupWidget are not NULL
8014 LRESULT popupHandlingResult;
8015 nsAutoRollup autoRollup;
8016 DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
8017 sRollupMsgId = 0;
8018 sRollupMsgWnd = NULL;
8021 #endif // WinCE
8023 BOOL CALLBACK nsWindow::ClearResourcesCallback(HWND aWnd, LPARAM aMsg)
8025 nsWindow *window = nsWindow::GetNSWindowPtr(aWnd);
8026 if (window) {
8027 window->ClearCachedResources();
8029 return TRUE;
8032 void
8033 nsWindow::ClearCachedResources()
8035 #ifdef CAIRO_HAS_D2D_SURFACE
8036 mD2DWindowSurface = nsnull;
8037 #endif
8038 if (mLayerManager &&
8039 mLayerManager->GetBackendType() == LayerManager::LAYERS_BASIC) {
8040 static_cast<BasicLayerManager*>(mLayerManager.get())->
8041 ClearCachedResources();
8043 ::EnumChildWindows(mWnd, nsWindow::ClearResourcesCallback, NULL);
8046 static PRBool IsDifferentThreadWindow(HWND aWnd)
8048 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, NULL);
8051 PRBool
8052 nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
8054 RECT r;
8056 #ifndef WINCE
8057 if (Msg == WM_ACTIVATEAPP)
8058 // don't care about activation/deactivation
8059 return PR_FALSE;
8060 #else
8061 if (Msg == WM_ACTIVATE)
8062 // but on Windows CE we do care about
8063 // activation/deactivation because there doesn't exist
8064 // cancelable Mouse Activation events
8065 return PR_TRUE;
8066 #endif
8068 ::GetWindowRect(aWindow->mWnd, &r);
8069 DWORD pos = ::GetMessagePos();
8070 POINT mp;
8071 mp.x = GET_X_LPARAM(pos);
8072 mp.y = GET_Y_LPARAM(pos);
8074 // was the event inside this window?
8075 return (PRBool) PtInRect(&r, mp);
8078 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8079 BOOL
8080 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
8082 if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
8084 if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
8085 inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
8086 (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam))
8087 #ifndef WINCE
8089 inMsg == WM_NCRBUTTONDOWN ||
8090 inMsg == WM_MOVING ||
8091 inMsg == WM_SIZING ||
8092 inMsg == WM_NCLBUTTONDOWN ||
8093 inMsg == WM_NCMBUTTONDOWN ||
8094 inMsg == WM_MOUSEACTIVATE ||
8095 inMsg == WM_ACTIVATEAPP ||
8096 inMsg == WM_MENUSELECT
8097 #endif
8100 // Rollup if the event is outside the popup.
8101 PRBool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)sRollupWidget);
8103 if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL))
8105 sRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
8106 *outResult = PR_TRUE;
8109 // If we're dealing with menus, we probably have submenus and we don't
8110 // want to rollup if the click is in a parent menu of the current submenu.
8111 PRUint32 popupsToRollup = PR_UINT32_MAX;
8112 if (rollup) {
8113 if ( sMenuRollup ) {
8114 nsAutoTArray<nsIWidget*, 5> widgetChain;
8115 PRUint32 sameTypeCount = sMenuRollup->GetSubmenuWidgetChain(&widgetChain);
8116 for ( PRUint32 i = 0; i < widgetChain.Length(); ++i ) {
8117 nsIWidget* widget = widgetChain[i];
8118 if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
8119 // don't roll up if the mouse event occurred within a menu of the
8120 // same type. If the mouse event occurred in a menu higher than
8121 // that, roll up, but pass the number of popups to Rollup so
8122 // that only those of the same type close up.
8123 if (i < sameTypeCount) {
8124 rollup = PR_FALSE;
8126 else {
8127 popupsToRollup = sameTypeCount;
8129 break;
8131 } // foreach parent menu widget
8132 } // if rollup listener knows about menus
8135 #ifndef WINCE
8136 if (inMsg == WM_MOUSEACTIVATE && popupsToRollup == PR_UINT32_MAX) {
8137 // Prevent the click inside the popup from causing a change in window
8138 // activation. Since the popup is shown non-activated, we need to eat
8139 // any requests to activate the window while it is displayed. Windows
8140 // will automatically activate the popup on the mousedown otherwise.
8141 if (!rollup) {
8142 *outResult = MA_NOACTIVATE;
8143 return TRUE;
8145 else
8147 UINT uMsg = HIWORD(inLParam);
8148 if (uMsg == WM_MOUSEMOVE)
8150 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8151 // must be enabled in Windows.
8152 sRollupListener->ShouldRollupOnMouseActivate(&rollup);
8153 if (!rollup)
8155 *outResult = MA_NOACTIVATE;
8156 return true;
8161 // if we've still determined that we should still rollup everything, do it.
8162 else
8163 #endif
8164 if ( rollup ) {
8165 // sRollupConsumeEvent may be modified by
8166 // nsIRollupListener::Rollup.
8167 PRBool consumeRollupEvent = sRollupConsumeEvent;
8168 // only need to deal with the last rollup for left mouse down events.
8169 sRollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN ? &mLastRollup : nsnull);
8171 // Tell hook to stop processing messages
8172 sProcessHook = PR_FALSE;
8173 sRollupMsgId = 0;
8174 sRollupMsgWnd = NULL;
8176 // return TRUE tells Windows that the event is consumed,
8177 // false allows the event to be dispatched
8179 // So if we are NOT supposed to be consuming events, let it go through
8180 if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
8181 *outResult = TRUE;
8182 return TRUE;
8184 #ifndef WINCE
8185 // if we are only rolling up some popups, don't activate and don't let
8186 // the event go through. This prevents clicks menus higher in the
8187 // chain from opening when a context menu is open
8188 if (popupsToRollup != PR_UINT32_MAX && inMsg == WM_MOUSEACTIVATE) {
8189 *outResult = MA_NOACTIVATEANDEAT;
8190 return TRUE;
8192 #endif
8194 } // if event that might trigger a popup to rollup
8195 } // if rollup listeners registered
8197 return FALSE;
8200 /**************************************************************
8201 **************************************************************
8203 ** BLOCK: Misc. utility methods and functions.
8205 ** General use.
8207 **************************************************************
8208 **************************************************************/
8210 // nsModifierKeyState used in various character processing.
8211 nsModifierKeyState::nsModifierKeyState()
8213 mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT);
8214 mIsControlDown = IS_VK_DOWN(NS_VK_CONTROL);
8215 mIsAltDown = IS_VK_DOWN(NS_VK_ALT);
8219 PRInt32 nsWindow::GetWindowsVersion()
8221 #ifdef WINCE
8222 return 0x500;
8223 #else
8224 static PRInt32 version = 0;
8225 static PRBool didCheck = PR_FALSE;
8227 if (!didCheck)
8229 didCheck = PR_TRUE;
8230 OSVERSIONINFOEX osInfo;
8231 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
8232 // This cast is safe and supposed to be here, don't worry
8233 ::GetVersionEx((OSVERSIONINFO*)&osInfo);
8234 version = (osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
8236 return version;
8237 #endif
8240 // Note that the result of GetTopLevelWindow method can be different from the
8241 // result of GetTopLevelHWND method. The result can be non-floating window.
8242 // Because our top level window may be contained in another window which is
8243 // not managed by us.
8244 nsWindow* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup)
8246 nsWindow* curWindow = this;
8248 while (PR_TRUE) {
8249 if (aStopOnDialogOrPopup) {
8250 switch (curWindow->mWindowType) {
8251 case eWindowType_dialog:
8252 case eWindowType_popup:
8253 return curWindow;
8254 default:
8255 break;
8259 // Retrieve the top level parent or owner window
8260 nsWindow* parentWindow = curWindow->GetParentWindow(PR_TRUE);
8262 if (!parentWindow)
8263 return curWindow;
8265 curWindow = parentWindow;
8269 // Note that the result of GetTopLevelHWND can be different from the result
8270 // of GetTopLevelWindow method. Because this is checking whether the window
8271 // is top level only in Win32 window system. Therefore, the result window
8272 // may not be managed by us.
8273 HWND nsWindow::GetTopLevelHWND(HWND aWnd, PRBool aStopOnDialogOrPopup)
8275 HWND curWnd = aWnd;
8276 HWND topWnd = NULL;
8277 HWND upWnd = NULL;
8279 while (curWnd) {
8280 topWnd = curWnd;
8282 if (aStopOnDialogOrPopup) {
8283 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8285 VERIFY_WINDOW_STYLE(style);
8287 if (!(style & WS_CHILD)) // first top-level window
8288 break;
8291 upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
8293 #ifdef WINCE
8294 // For dialog windows, we want just the parent, not the owner.
8295 // For other/popup windows, we want to find the first owner/parent
8296 // that's a dialog and/or has an owner.
8297 if (upWnd && ::GetWindow(curWnd, GW_OWNER) == upWnd) {
8298 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8299 if ((style & WS_DLGFRAME) != 0)
8300 break;
8302 #endif
8304 curWnd = upWnd;
8307 return topWnd;
8310 static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam)
8312 DWORD pid;
8313 ::GetWindowThreadProcessId(hwnd, &pid);
8314 if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd))
8316 gWindowsVisible = PR_TRUE;
8317 return FALSE;
8319 return TRUE;
8322 PRBool nsWindow::CanTakeFocus()
8324 gWindowsVisible = PR_FALSE;
8325 EnumWindows(gEnumWindowsProc, 0);
8326 if (!gWindowsVisible) {
8327 return PR_TRUE;
8328 } else {
8329 HWND fgWnd = ::GetForegroundWindow();
8330 if (!fgWnd) {
8331 return PR_TRUE;
8333 DWORD pid;
8334 GetWindowThreadProcessId(fgWnd, &pid);
8335 if (pid == GetCurrentProcessId()) {
8336 return PR_TRUE;
8339 return PR_FALSE;
8342 #if !defined(WINCE)
8343 void nsWindow::InitTrackPointHack()
8345 // Init Trackpoint Hack
8346 nsresult rv;
8347 PRInt32 lHackValue;
8348 long lResult;
8349 const WCHAR wstrKeys[][40] = {L"Software\\Lenovo\\TrackPoint",
8350 L"Software\\Lenovo\\UltraNav",
8351 L"Software\\Alps\\Apoint\\TrackPoint",
8352 L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
8353 L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
8354 // If anything fails turn the hack off
8355 sTrackPointHack = false;
8356 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8357 if(NS_SUCCEEDED(rv) && prefs) {
8358 prefs->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue);
8359 switch (lHackValue) {
8360 // 0 means hack disabled
8361 case 0:
8362 break;
8363 // 1 means hack enabled
8364 case 1:
8365 sTrackPointHack = true;
8366 break;
8367 // -1 means autodetect
8368 case -1:
8369 for(unsigned i = 0; i < NS_ARRAY_LENGTH(wstrKeys); i++) {
8370 HKEY hKey;
8371 lResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, (LPCWSTR)&wstrKeys[i],
8372 0, KEY_READ, &hKey);
8373 ::RegCloseKey(hKey);
8374 if(lResult == ERROR_SUCCESS) {
8375 // If we detected a registry key belonging to a TrackPoint driver
8376 // Turn on the hack
8377 sTrackPointHack = true;
8378 break;
8381 break;
8382 // Shouldn't be any other values, but treat them as disabled
8383 default:
8384 break;
8387 return;
8389 #endif // #if !defined(WINCE)
8391 LPARAM nsWindow::lParamToScreen(LPARAM lParam)
8393 POINT pt;
8394 pt.x = GET_X_LPARAM(lParam);
8395 pt.y = GET_Y_LPARAM(lParam);
8396 ::ClientToScreen(mWnd, &pt);
8397 return MAKELPARAM(pt.x, pt.y);
8400 LPARAM nsWindow::lParamToClient(LPARAM lParam)
8402 POINT pt;
8403 pt.x = GET_X_LPARAM(lParam);
8404 pt.y = GET_Y_LPARAM(lParam);
8405 ::ScreenToClient(mWnd, &pt);
8406 return MAKELPARAM(pt.x, pt.y);
8409 /**************************************************************
8410 **************************************************************
8412 ** BLOCK: ChildWindow impl.
8414 ** Child window overrides.
8416 **************************************************************
8417 **************************************************************/
8419 // return the style for a child nsWindow
8420 DWORD ChildWindow::WindowStyle()
8422 DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle();
8423 if (!(style & WS_POPUP))
8424 style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
8425 VERIFY_WINDOW_STYLE(style);
8426 return style;