Bug 575195 - Send full screen size mode events from widget when transitioning to...
[mozilla-central.git] / widget / src / windows / nsWindow.cpp
blobb736faa7e78760eae7ed83a54176736facef6a09
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 using namespace mozilla::widget;
231 /**************************************************************
232 **************************************************************
234 ** BLOCK: Variables
236 ** nsWindow Class static initializations and global variables.
238 **************************************************************
239 **************************************************************/
241 /**************************************************************
243 * SECTION: nsWindow statics
245 **************************************************************/
247 PRUint32 nsWindow::sInstanceCount = 0;
248 PRBool nsWindow::sSwitchKeyboardLayout = PR_FALSE;
249 BOOL nsWindow::sIsRegistered = FALSE;
250 BOOL nsWindow::sIsPopupClassRegistered = FALSE;
251 BOOL nsWindow::sIsOleInitialized = FALSE;
252 HCURSOR nsWindow::sHCursor = NULL;
253 imgIContainer* nsWindow::sCursorImgContainer = nsnull;
254 nsWindow* nsWindow::sCurrentWindow = nsnull;
255 PRBool nsWindow::sJustGotDeactivate = PR_FALSE;
256 PRBool nsWindow::sJustGotActivate = PR_FALSE;
258 // imported in nsWidgetFactory.cpp
259 TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN;
261 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
262 // hook methods whether they should be processing the hook
263 // messages.
264 HHOOK nsWindow::sMsgFilterHook = NULL;
265 HHOOK nsWindow::sCallProcHook = NULL;
266 HHOOK nsWindow::sCallMouseHook = NULL;
267 PRPackedBool nsWindow::sProcessHook = PR_FALSE;
268 UINT nsWindow::sRollupMsgId = 0;
269 HWND nsWindow::sRollupMsgWnd = NULL;
270 UINT nsWindow::sHookTimerId = 0;
272 // Rollup Listener
273 nsIRollupListener* nsWindow::sRollupListener = nsnull;
274 nsIMenuRollup* nsWindow::sMenuRollup = nsnull;
275 nsIWidget* nsWindow::sRollupWidget = nsnull;
276 PRBool nsWindow::sRollupConsumeEvent = PR_FALSE;
278 // Mouse Clicks - static variable definitions for figuring
279 // out 1 - 3 Clicks.
280 POINT nsWindow::sLastMousePoint = {0};
281 POINT nsWindow::sLastMouseMovePoint = {0};
282 LONG nsWindow::sLastMouseDownTime = 0L;
283 LONG nsWindow::sLastClickCount = 0L;
284 BYTE nsWindow::sLastMouseButton = 0;
286 // Trim heap on minimize. (initialized, but still true.)
287 int nsWindow::sTrimOnMinimize = 2;
289 // Default Trackpoint Hack to off
290 PRBool nsWindow::sTrackPointHack = PR_FALSE;
292 #ifdef ACCESSIBILITY
293 BOOL nsWindow::sIsAccessibilityOn = FALSE;
294 // Accessibility wm_getobject handler
295 HINSTANCE nsWindow::sAccLib = 0;
296 LPFNLRESULTFROMOBJECT
297 nsWindow::sLresultFromObject = 0;
298 #endif // ACCESSIBILITY
300 #ifdef MOZ_IPC
301 // Used in OOPP plugin focus processing.
302 const PRUnichar* kOOPPPluginFocusEventId = L"OOPP Plugin Focus Widget Event";
303 PRUint32 nsWindow::sOOPPPluginFocusEvent =
304 RegisterWindowMessageW(kOOPPPluginFocusEventId);
305 #endif
307 /**************************************************************
309 * SECTION: globals variables
311 **************************************************************/
313 static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
315 #ifdef PR_LOGGING
316 PRLogModuleInfo* gWindowsLog = nsnull;
317 #endif
319 #ifndef WINCE
320 // Kbd layout. Used throughout character processing.
321 static KeyboardLayout gKbdLayout;
322 #endif
324 #ifdef WINCE_WINDOWS_MOBILE
325 // HTC Navigation Wheel Event
326 // This is the defined value for Gesture Mode
327 const int WM_HTCNAV = 0x0400 + 200;
329 typedef int (__stdcall * HTCApiNavOpen)(HANDLE, int);
330 typedef int (__stdcall * HTCApiNavSetMode)(HANDLE, unsigned int);
332 HTCApiNavOpen gHTCApiNavOpen = nsnull;
333 HTCApiNavSetMode gHTCApiNavSetMode = nsnull;
334 static PRBool gCheckForHTCApi = PR_FALSE;
335 #endif
337 // Global user preference for disabling native theme. Used
338 // in NativeWindowTheme.
339 PRBool gDisableNativeTheme = PR_FALSE;
341 // Global used in Show window enumerations.
342 static PRBool gWindowsVisible = PR_FALSE;
344 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
345 #ifdef WINCE_WINDOWS_MOBILE
346 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
347 #endif
349 /**************************************************************
350 **************************************************************
352 ** BLOCK: nsIWidget impl.
354 ** nsIWidget interface implementation, broken down into
355 ** sections.
357 **************************************************************
358 **************************************************************/
360 /**************************************************************
362 * SECTION: nsWindow construction and destruction
364 **************************************************************/
366 nsWindow::nsWindow() : nsBaseWidget()
368 #ifdef PR_LOGGING
369 if (!gWindowsLog)
370 gWindowsLog = PR_NewLogModule("nsWindowsWidgets");
371 #endif
373 mWnd = nsnull;
374 mPaintDC = nsnull;
375 mPrevWndProc = nsnull;
376 mOldIMC = nsnull;
377 mNativeDragTarget = nsnull;
378 mInDtor = PR_FALSE;
379 mIsVisible = PR_FALSE;
380 mIsInMouseCapture = PR_FALSE;
381 mIsTopWidgetWindow = PR_FALSE;
382 mUnicodeWidget = PR_TRUE;
383 mDisplayPanFeedback = PR_FALSE;
384 mTouchWindow = PR_FALSE;
385 mCustomNonClient = PR_FALSE;
386 mHideChrome = PR_FALSE;
387 mWindowType = eWindowType_child;
388 mBorderStyle = eBorderStyle_default;
389 mPopupType = ePopupTypeAny;
390 mOldSizeMode = nsSizeMode_Normal;
391 mLastPoint.x = 0;
392 mLastPoint.y = 0;
393 mLastSize.width = 0;
394 mLastSize.height = 0;
395 mOldStyle = 0;
396 mOldExStyle = 0;
397 mPainting = 0;
398 mExitToNonClientArea = 0;
399 mLastKeyboardLayout = 0;
400 mBlurSuppressLevel = 0;
401 mIMEEnabled = nsIWidget::IME_STATUS_ENABLED;
402 #ifdef MOZ_XUL
403 mTransparentSurface = nsnull;
404 mMemoryDC = nsnull;
405 mTransparencyMode = eTransparencyOpaque;
406 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
407 memset(&mGlassMargins, 0, sizeof mGlassMargins);
408 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
409 #endif
410 mBackground = ::GetSysColor(COLOR_BTNFACE);
411 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
412 mForeground = ::GetSysColor(COLOR_WINDOWTEXT);
414 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
415 mTaskbarPreview = nsnull;
416 mHasTaskbarIconBeenCreated = PR_FALSE;
417 #endif
419 // Global initialization
420 if (!sInstanceCount) {
421 #if !defined(WINCE)
422 gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
423 #endif
425 // Init IME handler
426 nsIMM32Handler::Initialize();
428 #ifdef NS_ENABLE_TSF
429 nsTextStore::Initialize();
430 #endif
432 #if !defined(WINCE)
433 if (SUCCEEDED(::OleInitialize(NULL)))
434 sIsOleInitialized = TRUE;
435 NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
436 #endif
438 #if defined(HEAP_DUMP_EVENT)
439 InitHeapDump();
440 #endif
442 #if !defined(WINCE)
443 InitTrackPointHack();
444 #endif
446 // Init titlebar button info for custom frames.
447 nsUXThemeData::InitTitlebarInfo();
448 } // !sInstanceCount
450 mIdleService = nsnull;
452 sInstanceCount++;
455 nsWindow::~nsWindow()
457 mInDtor = PR_TRUE;
459 // If the widget was released without calling Destroy() then the native window still
460 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
462 // XXX How could this happen???
463 if (NULL != mWnd)
464 Destroy();
466 sInstanceCount--;
468 // Global shutdown
469 if (sInstanceCount == 0) {
470 #ifdef NS_ENABLE_TSF
471 nsTextStore::Terminate();
472 #endif
474 #if !defined(WINCE)
475 NS_IF_RELEASE(sCursorImgContainer);
476 if (sIsOleInitialized) {
477 ::OleFlushClipboard();
478 ::OleUninitialize();
479 sIsOleInitialized = FALSE;
481 // delete any of the IME structures that we allocated
482 nsIMM32Handler::Terminate();
483 #endif // !defined(WINCE)
486 #if !defined(WINCE)
487 NS_IF_RELEASE(mNativeDragTarget);
488 #endif // !defined(WINCE)
491 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
493 /**************************************************************
495 * SECTION: nsIWidget::Create, nsIWidget::Destroy
497 * Creating and destroying windows for this widget.
499 **************************************************************/
501 // Allow Derived classes to modify the height that is passed
502 // when the window is created or resized. Also add extra height
503 // if needed (on Windows CE)
504 PRInt32 nsWindow::GetHeight(PRInt32 aProposedHeight)
506 PRInt32 extra = 0;
508 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
509 DWORD style = WindowStyle();
510 if ((style & WS_SYSMENU) && (style & WS_POPUP)) {
511 extra = GetSystemMetrics(SM_CYCAPTION);
513 #endif
515 return aProposedHeight + extra;
518 // Create the proper widget
519 nsresult
520 nsWindow::Create(nsIWidget *aParent,
521 nsNativeWidget aNativeParent,
522 const nsIntRect &aRect,
523 EVENT_CALLBACK aHandleEventFunction,
524 nsIDeviceContext *aContext,
525 nsIAppShell *aAppShell,
526 nsIToolkit *aToolkit,
527 nsWidgetInitData *aInitData)
529 nsWidgetInitData defaultInitData;
530 if (!aInitData)
531 aInitData = &defaultInitData;
533 mUnicodeWidget = aInitData->mUnicode;
535 nsIWidget *baseParent = aInitData->mWindowType == eWindowType_dialog ||
536 aInitData->mWindowType == eWindowType_toplevel ||
537 aInitData->mWindowType == eWindowType_invisible ?
538 nsnull : aParent;
540 mIsTopWidgetWindow = (nsnull == baseParent);
541 mBounds.width = aRect.width;
542 mBounds.height = aRect.height;
544 BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
545 aAppShell, aToolkit, aInitData);
547 HWND parent;
548 if (aParent) { // has a nsIWidget parent
549 parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : NULL;
550 mParent = aParent;
551 } else { // has a nsNative parent
552 parent = (HWND)aNativeParent;
553 mParent = aNativeParent ? GetNSWindowPtr((HWND)aNativeParent) : nsnull;
556 mPopupType = aInitData->mPopupHint;
557 mContentType = aInitData->mContentType;
559 DWORD style = WindowStyle();
560 DWORD extendedStyle = WindowExStyle();
562 if (aInitData->mRTL) {
563 extendedStyle |= WS_EX_LAYOUTRTL | WS_EX_NOINHERITLAYOUT;
566 if (mWindowType == eWindowType_popup) {
567 if (!aParent)
568 parent = NULL;
569 } else if (mWindowType == eWindowType_invisible) {
570 // Make sure CreateWindowEx succeeds at creating a toplevel window
571 style &= ~0x40000000; // WS_CHILDWINDOW
572 } else {
573 // See if the caller wants to explictly set clip children and clip siblings
574 if (aInitData->clipChildren) {
575 style |= WS_CLIPCHILDREN;
576 } else {
577 style &= ~WS_CLIPCHILDREN;
579 if (aInitData->clipSiblings) {
580 style |= WS_CLIPSIBLINGS;
584 mWnd = ::CreateWindowExW(extendedStyle,
585 aInitData->mDropShadow ?
586 WindowPopupClass() : WindowClass(),
587 L"",
588 style,
589 aRect.x,
590 aRect.y,
591 aRect.width,
592 GetHeight(aRect.height),
593 parent,
594 NULL,
595 nsToolkit::mDllInstance,
596 NULL);
598 if (!mWnd) {
599 NS_WARNING("nsWindow CreateWindowEx failed.");
600 return NS_ERROR_FAILURE;
603 if (nsWindow::sTrackPointHack &&
604 mWindowType != eWindowType_plugin &&
605 mWindowType != eWindowType_invisible) {
606 // Ugly Thinkpad Driver Hack (Bug 507222)
607 // We create an invisible scrollbar to trick the
608 // Trackpoint driver into sending us scrolling messages
609 ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTSCROLLBAR",
610 WS_CHILD | WS_VISIBLE, 0,0,0,0, mWnd, NULL,
611 nsToolkit::mDllInstance, NULL);
614 // call the event callback to notify about creation
616 DispatchStandardEvent(NS_CREATE);
617 SubclassWindow(TRUE);
619 if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
620 /* The internal variable set by the config.trim_on_minimize pref
621 has not yet been initialized, and this is the hidden window
622 (conveniently created before any visible windows, and after
623 the profile has been initialized).
625 Default config.trim_on_minimize to false, to fix bug 76831
626 for good. If anyone complains about this new default, saying
627 that a Mozilla app hogs too much memory while minimized, they
628 will have that entire bug tattooed on their backside. */
630 sTrimOnMinimize = 0;
631 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
632 if (prefs) {
633 nsCOMPtr<nsIPrefBranch> prefBranch;
634 prefs->GetBranch(0, getter_AddRefs(prefBranch));
635 if (prefBranch) {
637 PRBool temp;
638 if (NS_SUCCEEDED(prefBranch->GetBoolPref("config.trim_on_minimize",
639 &temp))
640 && temp)
641 sTrimOnMinimize = 1;
643 if (NS_SUCCEEDED(prefBranch->GetBoolPref("intl.keyboard.per_window_layout",
644 &temp)))
645 sSwitchKeyboardLayout = temp;
647 if (NS_SUCCEEDED(prefBranch->GetBoolPref("mozilla.widget.disable-native-theme",
648 &temp)))
649 gDisableNativeTheme = temp;
653 #if defined(WINCE_HAVE_SOFTKB)
654 if (mWindowType == eWindowType_dialog || mWindowType == eWindowType_toplevel )
655 nsWindowCE::CreateSoftKeyMenuBar(mWnd);
656 #endif
658 return NS_OK;
661 // Close this nsWindow
662 NS_METHOD nsWindow::Destroy()
664 // WM_DESTROY has already fired, we're done.
665 if (nsnull == mWnd)
666 return NS_OK;
668 // During the destruction of all of our children, make sure we don't get deleted.
669 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
672 * On windows the LayerManagerOGL destructor wants the widget to be around for
673 * cleanup. It also would like to have the HWND intact, so we NULL it here.
675 if (mLayerManager) {
676 mLayerManager->Destroy();
678 mLayerManager = nsnull;
680 /* We should clear our cached resources now and not wait for the GC to
681 * delete the nsWindow. */
682 ClearCachedResources();
684 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
685 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
686 // from it. The function also destroys the window's menu, flushes the thread message queue,
687 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
688 // the window is at the top of the viewer chain).
690 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
691 // the associated child or owned windows when it destroys the parent or owner window. The
692 // function first destroys child or owned windows, and then it destroys the parent or owner
693 // window.
694 VERIFY(::DestroyWindow(mWnd));
696 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
697 // didn't get called, call it now.
698 if (PR_FALSE == mOnDestroyCalled)
699 OnDestroy();
701 return NS_OK;
704 /**************************************************************
706 * SECTION: Window class utilities
708 * Utilities for calculating the proper window class name for
709 * Create window.
711 **************************************************************/
713 // Return the proper window class for everything except popups.
714 LPCWSTR nsWindow::WindowClass()
716 if (!nsWindow::sIsRegistered) {
717 WNDCLASSW wc;
719 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
720 wc.style = CS_DBLCLKS;
721 wc.lpfnWndProc = ::DefWindowProcW;
722 wc.cbClsExtra = 0;
723 wc.cbWndExtra = 0;
724 wc.hInstance = nsToolkit::mDllInstance;
725 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
726 wc.hCursor = NULL;
727 wc.hbrBackground = mBrush;
728 wc.lpszMenuName = NULL;
729 wc.lpszClassName = kClassNameHidden;
731 BOOL succeeded = ::RegisterClassW(&wc) != 0 &&
732 ERROR_CLASS_ALREADY_EXISTS != GetLastError();
733 nsWindow::sIsRegistered = succeeded;
735 wc.lpszClassName = kClassNameContentFrame;
736 if (!::RegisterClassW(&wc) &&
737 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
738 nsWindow::sIsRegistered = FALSE;
741 wc.lpszClassName = kClassNameContent;
742 if (!::RegisterClassW(&wc) &&
743 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
744 nsWindow::sIsRegistered = FALSE;
747 wc.lpszClassName = kClassNameUI;
748 if (!::RegisterClassW(&wc) &&
749 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
750 nsWindow::sIsRegistered = FALSE;
753 wc.lpszClassName = kClassNameGeneral;
754 ATOM generalClassAtom = ::RegisterClassW(&wc);
755 if (!generalClassAtom &&
756 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
757 nsWindow::sIsRegistered = FALSE;
760 wc.lpszClassName = kClassNameDialog;
761 wc.hIcon = 0;
762 if (!::RegisterClassW(&wc) &&
763 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
764 nsWindow::sIsRegistered = FALSE;
768 if (mWindowType == eWindowType_invisible) {
769 return kClassNameHidden;
771 if (mWindowType == eWindowType_dialog) {
772 return kClassNameDialog;
774 if (mContentType == eContentTypeContent) {
775 return kClassNameContent;
777 if (mContentType == eContentTypeContentFrame) {
778 return kClassNameContentFrame;
780 if (mContentType == eContentTypeUI) {
781 return kClassNameUI;
783 return kClassNameGeneral;
786 // Return the proper popup window class
787 LPCWSTR nsWindow::WindowPopupClass()
789 if (!nsWindow::sIsPopupClassRegistered) {
790 WNDCLASSW wc;
792 wc.style = CS_DBLCLKS | CS_XP_DROPSHADOW;
793 wc.lpfnWndProc = ::DefWindowProcW;
794 wc.cbClsExtra = 0;
795 wc.cbWndExtra = 0;
796 wc.hInstance = nsToolkit::mDllInstance;
797 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
798 wc.hCursor = NULL;
799 wc.hbrBackground = mBrush;
800 wc.lpszMenuName = NULL;
801 wc.lpszClassName = kClassNameDropShadow;
803 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
804 if (!nsWindow::sIsPopupClassRegistered) {
805 // For older versions of Win32 (i.e., not XP), the registration will
806 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
807 wc.style = CS_DBLCLKS;
808 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
812 return kClassNameDropShadow;
815 /**************************************************************
817 * SECTION: Window styles utilities
819 * Return the proper windows styles and extended styles.
821 **************************************************************/
823 // Return nsWindow styles
824 #if !defined(WINCE) // implemented in nsWindowCE.cpp
825 DWORD nsWindow::WindowStyle()
827 DWORD style;
829 switch (mWindowType) {
830 case eWindowType_plugin:
831 case eWindowType_child:
832 style = WS_OVERLAPPED;
833 break;
835 case eWindowType_dialog:
836 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK |
837 DS_MODALFRAME | WS_CLIPCHILDREN;
838 if (mBorderStyle != eBorderStyle_default)
839 style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
840 break;
842 case eWindowType_popup:
843 style = WS_POPUP;
844 if (!HasGlass()) {
845 style |= WS_OVERLAPPED;
847 break;
849 default:
850 NS_ERROR("unknown border style");
851 // fall through
853 case eWindowType_toplevel:
854 case eWindowType_invisible:
855 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU |
856 WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
857 break;
860 if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) {
861 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border))
862 style &= ~WS_BORDER;
864 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) {
865 style &= ~WS_DLGFRAME;
866 style |= WS_POPUP;
867 style &= ~WS_CHILD;
870 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close))
871 style &= ~0;
872 // XXX The close box can only be removed by changing the window class,
873 // as far as I know --- roc+moz@cs.cmu.edu
875 if (mBorderStyle == eBorderStyle_none ||
876 !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
877 style &= ~WS_SYSMENU;
878 // Looks like getting rid of the system menu also does away with the
879 // close box. So, we only get rid of the system menu if you want neither it
880 // nor the close box. How does the Windows "Dialog" window class get just
881 // closebox and no sysmenu? Who knows.
883 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh))
884 style &= ~WS_THICKFRAME;
886 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize))
887 style &= ~WS_MINIMIZEBOX;
889 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize))
890 style &= ~WS_MAXIMIZEBOX;
892 if (IsPopupWithTitleBar()) {
893 style |= WS_CAPTION;
894 if (mBorderStyle & eBorderStyle_close) {
895 style |= WS_SYSMENU;
900 VERIFY_WINDOW_STYLE(style);
901 return style;
903 #endif // !defined(WINCE)
905 // Return nsWindow extended styles
906 DWORD nsWindow::WindowExStyle()
908 switch (mWindowType)
910 case eWindowType_plugin:
911 case eWindowType_child:
912 return 0;
914 case eWindowType_dialog:
915 return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
917 case eWindowType_popup:
919 DWORD extendedStyle =
920 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
921 WS_EX_NOACTIVATE |
922 #endif
923 WS_EX_TOOLWINDOW;
924 if (mPopupLevel == ePopupLevelTop)
925 extendedStyle |= WS_EX_TOPMOST;
926 return extendedStyle;
928 default:
929 NS_ERROR("unknown border style");
930 // fall through
932 case eWindowType_toplevel:
933 case eWindowType_invisible:
934 return WS_EX_WINDOWEDGE;
938 /**************************************************************
940 * SECTION: Window subclassing utilities
942 * Set or clear window subclasses on native windows. Used in
943 * Create and Destroy.
945 **************************************************************/
947 // Subclass (or remove the subclass from) this component's nsWindow
948 void nsWindow::SubclassWindow(BOOL bState)
950 if (NULL != mWnd) {
951 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
952 if (!::IsWindow(mWnd)) {
953 NS_ERROR("Invalid window handle");
956 if (bState) {
957 // change the nsWindow proc
958 if (mUnicodeWidget)
959 mPrevWndProc = (WNDPROC)::SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
960 (LONG_PTR)nsWindow::WindowProc);
961 else
962 mPrevWndProc = (WNDPROC)::SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
963 (LONG_PTR)nsWindow::WindowProc);
964 NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
965 // connect the this pointer to the nsWindow handle
966 SetNSWindowPtr(mWnd, this);
968 else {
969 if (mUnicodeWidget)
970 ::SetWindowLongPtrW(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
971 else
972 ::SetWindowLongPtrA(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
973 SetNSWindowPtr(mWnd, NULL);
974 mPrevWndProc = NULL;
979 /**************************************************************
981 * SECTION: Window properties
983 * Set and clear native window properties.
985 **************************************************************/
987 static PRUnichar sPropName[40] = L"";
988 static PRUnichar* GetNSWindowPropName()
990 if (!*sPropName)
992 _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p", GetCurrentProcessId());
993 sPropName[39] = '\0';
995 return sPropName;
998 nsWindow * nsWindow::GetNSWindowPtr(HWND aWnd)
1000 return (nsWindow *) ::GetPropW(aWnd, GetNSWindowPropName());
1003 BOOL nsWindow::SetNSWindowPtr(HWND aWnd, nsWindow * ptr)
1005 if (ptr == NULL) {
1006 ::RemovePropW(aWnd, GetNSWindowPropName());
1007 return TRUE;
1008 } else {
1009 return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)ptr);
1013 /**************************************************************
1015 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
1017 * Set or clear the parent widgets using window properties, and
1018 * handles calculating native parent handles.
1020 **************************************************************/
1022 // Get and set parent widgets
1023 NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent)
1025 mParent = aNewParent;
1027 if (aNewParent) {
1028 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1030 nsIWidget* parent = GetParent();
1031 if (parent) {
1032 parent->RemoveChild(this);
1035 HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
1036 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
1037 if (newParent && mWnd) {
1038 ::SetParent(mWnd, newParent);
1041 aNewParent->AddChild(this);
1043 return NS_OK;
1046 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1048 nsIWidget* parent = GetParent();
1050 if (parent) {
1051 parent->RemoveChild(this);
1054 if (mWnd) {
1055 // If we have no parent, SetParent should return the desktop.
1056 VERIFY(::SetParent(mWnd, nsnull));
1059 return NS_OK;
1062 nsIWidget* nsWindow::GetParent(void)
1064 return GetParentWindow(PR_FALSE);
1067 float nsWindow::GetDPI()
1069 HDC dc = ::GetDC(mWnd);
1070 if (!dc)
1071 return 96.0f;
1073 double heightInches = ::GetDeviceCaps(dc, VERTSIZE)/MM_PER_INCH_FLOAT;
1074 int heightPx = ::GetDeviceCaps(dc, VERTRES);
1075 ::ReleaseDC(mWnd, dc);
1076 if (heightInches < 0.25) {
1077 // Something's broken
1078 return 96.0f;
1080 return float(heightPx/heightInches);
1083 nsWindow* nsWindow::GetParentWindow(PRBool aIncludeOwner)
1085 if (mIsTopWidgetWindow) {
1086 // Must use a flag instead of mWindowType to tell if the window is the
1087 // owned by the topmost widget, because a child window can be embedded inside
1088 // a HWND which is not associated with a nsIWidget.
1089 return nsnull;
1092 // If this widget has already been destroyed, pretend we have no parent.
1093 // This corresponds to code in Destroy which removes the destroyed
1094 // widget from its parent's child list.
1095 if (mInDtor || mOnDestroyCalled)
1096 return nsnull;
1099 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1100 // root owner. aIncludeOwner set to false implies the search will stop at the
1101 // true parent (default).
1102 nsWindow* widget = nsnull;
1103 if (mWnd) {
1104 #ifdef WINCE
1105 HWND parent = ::GetParent(mWnd);
1106 #else
1107 HWND parent = nsnull;
1108 if (aIncludeOwner)
1109 parent = ::GetParent(mWnd);
1110 else
1111 parent = ::GetAncestor(mWnd, GA_PARENT);
1112 #endif
1113 if (parent) {
1114 widget = GetNSWindowPtr(parent);
1115 if (widget) {
1116 // If the widget is in the process of being destroyed then
1117 // do NOT return it
1118 if (widget->mInDtor) {
1119 widget = nsnull;
1125 return widget;
1128 /**************************************************************
1130 * SECTION: nsIWidget::Show
1132 * Hide or show this component.
1134 **************************************************************/
1136 NS_METHOD nsWindow::Show(PRBool bState)
1138 #if defined(MOZ_SPLASHSCREEN)
1139 // we're about to show the first toplevel window,
1140 // so kill off any splash screen if we had one
1141 nsSplashScreen *splash = nsSplashScreen::Get();
1142 if (splash && splash->IsOpen() && mWnd && bState &&
1143 (mWindowType == eWindowType_toplevel ||
1144 mWindowType == eWindowType_dialog ||
1145 mWindowType == eWindowType_popup))
1147 splash->Close();
1149 #endif
1151 #ifdef NS_FUNCTION_TIMER
1152 static bool firstShow = true;
1153 if (firstShow &&
1154 (mWindowType == eWindowType_toplevel ||
1155 mWindowType == eWindowType_dialog ||
1156 mWindowType == eWindowType_popup))
1158 firstShow = false;
1159 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1161 #endif
1163 PRBool wasVisible = mIsVisible;
1164 // Set the status now so that anyone asking during ShowWindow or
1165 // SetWindowPos would get the correct answer.
1166 mIsVisible = bState;
1168 if (!mIsVisible && wasVisible) {
1169 ClearCachedResources();
1172 if (mWnd) {
1173 if (bState) {
1174 if (!wasVisible && mWindowType == eWindowType_toplevel) {
1175 switch (mSizeMode) {
1176 #ifdef WINCE
1177 case nsSizeMode_Fullscreen:
1178 ::SetForegroundWindow(mWnd);
1179 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1180 MakeFullScreen(TRUE);
1181 break;
1183 case nsSizeMode_Maximized :
1184 ::SetForegroundWindow(mWnd);
1185 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1186 break;
1187 // use default for nsSizeMode_Minimized on Windows CE
1188 #else
1189 case nsSizeMode_Maximized :
1190 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1191 break;
1192 case nsSizeMode_Minimized :
1193 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
1194 break;
1195 #endif
1196 default:
1197 if (CanTakeFocus()) {
1198 #ifdef WINCE
1199 ::SetForegroundWindow(mWnd);
1200 #endif
1201 ::ShowWindow(mWnd, SW_SHOWNORMAL);
1202 } else {
1203 // Place the window behind the foreground window
1204 // (as long as it is not topmost)
1205 HWND wndAfter = ::GetForegroundWindow();
1206 if (!wndAfter)
1207 wndAfter = HWND_BOTTOM;
1208 else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)
1209 wndAfter = HWND_TOP;
1210 ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE |
1211 SWP_NOMOVE | SWP_NOACTIVATE);
1212 GetAttention(2);
1214 break;
1216 } else {
1217 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
1218 if (wasVisible)
1219 flags |= SWP_NOZORDER;
1221 if (mWindowType == eWindowType_popup) {
1222 #ifndef WINCE
1223 // ensure popups are the topmost of the TOPMOST
1224 // layer. Remember not to set the SWP_NOZORDER
1225 // flag as that might allow the taskbar to overlap
1226 // the popup. However on windows ce, we need to
1227 // activate the popup or clicks will not be sent.
1228 flags |= SWP_NOACTIVATE;
1229 #endif
1230 HWND owner = ::GetWindow(mWnd, GW_OWNER);
1231 ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
1232 } else {
1233 #ifndef WINCE
1234 if (mWindowType == eWindowType_dialog && !CanTakeFocus())
1235 flags |= SWP_NOACTIVATE;
1236 #endif
1237 ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
1241 #ifndef WINCE
1242 if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) {
1243 // when a toplevel window or dialog is shown, initialize the UI state
1244 ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
1246 #endif
1247 } else {
1248 if (mWindowType != eWindowType_dialog) {
1249 ::ShowWindow(mWnd, SW_HIDE);
1250 } else {
1251 ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1252 SWP_NOZORDER | SWP_NOACTIVATE);
1257 #ifdef MOZ_XUL
1258 if (!wasVisible && bState)
1259 Invalidate(PR_FALSE);
1260 #endif
1262 return NS_OK;
1265 /**************************************************************
1267 * SECTION: nsIWidget::IsVisible
1269 * Returns the visibility state.
1271 **************************************************************/
1273 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1274 NS_METHOD nsWindow::IsVisible(PRBool & bState)
1276 bState = mIsVisible;
1277 return NS_OK;
1280 /**************************************************************
1282 * SECTION: Window clipping utilities
1284 * Used in Size and Move operations for setting the proper
1285 * window clipping regions for window transparency.
1287 **************************************************************/
1289 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1290 // transparency. These routines are called on size and move operations.
1291 void nsWindow::ClearThemeRegion()
1293 #ifndef WINCE
1294 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1295 mWindowType == eWindowType_popup && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel)) {
1296 SetWindowRgn(mWnd, NULL, false);
1298 #endif
1301 void nsWindow::SetThemeRegion()
1303 #ifndef WINCE
1304 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1305 // for other window types as needed. The regions are applied generically to the base window
1306 // so default constants are used for part and state. At some point we might need part and
1307 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1308 // change shape based on state haven't come up.
1309 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1310 mWindowType == eWindowType_popup && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel)) {
1311 HRGN hRgn = nsnull;
1312 RECT rect = {0,0,mBounds.width,mBounds.height};
1314 HDC dc = ::GetDC(mWnd);
1315 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
1316 if (hRgn) {
1317 if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted.
1318 DeleteObject(hRgn);
1320 ::ReleaseDC(mWnd, dc);
1322 #endif
1325 /**************************************************************
1327 * SECTION: nsIWidget::RegisterTouchWindow,
1328 * nsIWidget::UnregisterTouchWindow, and helper functions
1330 * Used to register the native window to receive touch events
1332 **************************************************************/
1334 NS_METHOD nsWindow::RegisterTouchWindow() {
1335 mTouchWindow = PR_TRUE;
1336 #ifndef WINCE
1337 mGesture.RegisterTouchWindow(mWnd);
1338 ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
1339 #endif
1340 return NS_OK;
1343 NS_METHOD nsWindow::UnregisterTouchWindow() {
1344 mTouchWindow = PR_FALSE;
1345 #ifndef WINCE
1346 mGesture.UnregisterTouchWindow(mWnd);
1347 ::EnumChildWindows(mWnd, nsWindow::UnregisterTouchForDescendants, 0);
1348 #endif
1349 return NS_OK;
1352 #ifndef WINCE
1353 BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1354 nsWindow* win = GetNSWindowPtr(aWnd);
1355 if (win)
1356 win->mGesture.RegisterTouchWindow(aWnd);
1357 return TRUE;
1360 BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1361 nsWindow* win = GetNSWindowPtr(aWnd);
1362 if (win)
1363 win->mGesture.UnregisterTouchWindow(aWnd);
1364 return TRUE;
1366 #endif
1368 /**************************************************************
1370 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1371 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1373 * Repositioning and sizing a window.
1375 **************************************************************/
1377 // Move this component
1378 NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
1380 if (mWindowType == eWindowType_toplevel ||
1381 mWindowType == eWindowType_dialog) {
1382 SetSizeMode(nsSizeMode_Normal);
1384 // Check to see if window needs to be moved first
1385 // to avoid a costly call to SetWindowPos. This check
1386 // can not be moved to the calling code in nsView, because
1387 // some platforms do not position child windows correctly
1389 // Only perform this check for non-popup windows, since the positioning can
1390 // in fact change even when the x/y do not. We always need to perform the
1391 // check. See bug #97805 for details.
1392 if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
1394 // Nothing to do, since it is already positioned correctly.
1395 return NS_OK;
1398 mBounds.x = aX;
1399 mBounds.y = aY;
1401 if (mWnd) {
1402 #ifdef DEBUG
1403 // complain if a window is moved offscreen (legal, but potentially worrisome)
1404 if (mIsTopWidgetWindow) { // only a problem for top-level windows
1405 // Make sure this window is actually on the screen before we move it
1406 // XXX: Needs multiple monitor support
1407 HDC dc = ::GetDC(mWnd);
1408 if (dc) {
1409 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1410 RECT workArea;
1411 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1412 // no annoying assertions. just mention the issue.
1413 if (aX < 0 || aX >= workArea.right || aY < 0 || aY >= workArea.bottom)
1414 printf("window moved to offscreen position\n");
1416 ::ReleaseDC(mWnd, dc);
1419 #endif
1420 ClearThemeRegion();
1421 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0,
1422 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE));
1423 SetThemeRegion();
1425 return NS_OK;
1428 // Resize this component
1429 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1431 NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
1432 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1434 // Avoid unnecessary resizing calls
1435 if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1436 return NS_OK;
1438 #ifdef MOZ_XUL
1439 if (eTransparencyTransparent == mTransparencyMode)
1440 ResizeTranslucentWindow(aWidth, aHeight);
1441 #endif
1443 // Set cached value for lightweight and printing
1444 mBounds.width = aWidth;
1445 mBounds.height = aHeight;
1447 if (mWnd) {
1448 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
1450 #ifndef WINCE
1451 if (!aRepaint) {
1452 flags |= SWP_NOREDRAW;
1454 #endif
1456 ClearThemeRegion();
1457 VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
1458 SetThemeRegion();
1461 if (aRepaint)
1462 Invalidate(PR_FALSE);
1464 return NS_OK;
1467 // Resize this component
1468 NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1470 NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize");
1471 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1473 // Avoid unnecessary resizing calls
1474 if (mBounds.x == aX && mBounds.y == aY &&
1475 mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1476 return NS_OK;
1478 #ifdef MOZ_XUL
1479 if (eTransparencyTransparent == mTransparencyMode)
1480 ResizeTranslucentWindow(aWidth, aHeight);
1481 #endif
1483 // Set cached value for lightweight and printing
1484 mBounds.x = aX;
1485 mBounds.y = aY;
1486 mBounds.width = aWidth;
1487 mBounds.height = aHeight;
1489 if (mWnd) {
1490 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
1491 #ifndef WINCE
1492 if (!aRepaint) {
1493 flags |= SWP_NOREDRAW;
1495 #endif
1497 ClearThemeRegion();
1498 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
1499 SetThemeRegion();
1502 if (aRepaint)
1503 Invalidate(PR_FALSE);
1505 return NS_OK;
1508 // Resize the client area and position the widget within it's parent
1509 NS_METHOD nsWindow::ResizeClient(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1511 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1512 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1514 // Adjust our existing window bounds, based on the new client dims.
1515 RECT client;
1516 GetClientRect(mWnd, &client);
1517 nsIntPoint dims(client.right - client.left, client.bottom - client.top);
1518 aWidth = mBounds.width + (aWidth - dims.x);
1519 aHeight = mBounds.height + (aHeight - dims.y);
1521 if (aX || aY) {
1522 // offsets
1523 nsIntRect bounds;
1524 GetScreenBounds(bounds);
1525 aX += bounds.x;
1526 aY += bounds.y;
1527 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1529 return Resize(aWidth, aHeight, aRepaint);
1532 #if !defined(WINCE)
1533 NS_IMETHODIMP
1534 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
1536 NS_ENSURE_ARG_POINTER(aEvent);
1538 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
1539 // you can only begin a resize drag with a mouse event
1540 return NS_ERROR_INVALID_ARG;
1543 nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
1544 if (mouseEvent->button != nsMouseEvent::eLeftButton) {
1545 // you can only begin a resize drag with the left mouse button
1546 return NS_ERROR_INVALID_ARG;
1549 // work out what sizemode we're talking about
1550 WPARAM syscommand;
1551 if (aVertical < 0) {
1552 if (aHorizontal < 0) {
1553 syscommand = SC_SIZE | WMSZ_TOPLEFT;
1554 } else if (aHorizontal == 0) {
1555 syscommand = SC_SIZE | WMSZ_TOP;
1556 } else {
1557 syscommand = SC_SIZE | WMSZ_TOPRIGHT;
1559 } else if (aVertical == 0) {
1560 if (aHorizontal < 0) {
1561 syscommand = SC_SIZE | WMSZ_LEFT;
1562 } else if (aHorizontal == 0) {
1563 return NS_ERROR_INVALID_ARG;
1564 } else {
1565 syscommand = SC_SIZE | WMSZ_RIGHT;
1567 } else {
1568 if (aHorizontal < 0) {
1569 syscommand = SC_SIZE | WMSZ_BOTTOMLEFT;
1570 } else if (aHorizontal == 0) {
1571 syscommand = SC_SIZE | WMSZ_BOTTOM;
1572 } else {
1573 syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT;
1577 // resizing doesn't work if the mouse is already captured
1578 CaptureMouse(PR_FALSE);
1580 // find the top-level window
1581 HWND toplevelWnd = GetTopLevelHWND(mWnd, PR_TRUE);
1583 // tell Windows to start the resize
1584 ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand,
1585 POINTTOPOINTS(aEvent->refPoint));
1587 return NS_OK;
1589 #endif
1590 /**************************************************************
1592 * SECTION: Window Z-order and state.
1594 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1595 * nsIWidget::ConstrainPosition
1597 * Z-order, positioning, restore, minimize, and maximize.
1599 **************************************************************/
1601 // Position the window behind the given window
1602 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1603 nsIWidget *aWidget, PRBool aActivate)
1605 HWND behind = HWND_TOP;
1606 if (aPlacement == eZPlacementBottom)
1607 behind = HWND_BOTTOM;
1608 else if (aPlacement == eZPlacementBelow && aWidget)
1609 behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
1610 UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
1611 if (!aActivate)
1612 flags |= SWP_NOACTIVATE;
1614 if (!CanTakeFocus() && behind == HWND_TOP)
1616 // Can't place the window to top so place it behind the foreground window
1617 // (as long as it is not topmost)
1618 HWND wndAfter = ::GetForegroundWindow();
1619 if (!wndAfter)
1620 behind = HWND_BOTTOM;
1621 else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
1622 behind = wndAfter;
1623 flags |= SWP_NOACTIVATE;
1626 ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
1627 return NS_OK;
1630 // Maximize, minimize or restore the window.
1631 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1632 NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode) {
1634 nsresult rv;
1636 // Let's not try and do anything if we're already in that state.
1637 // (This is needed to prevent problems when calling window.minimize(), which
1638 // calls us directly, and then the OS triggers another call to us.)
1639 if (aMode == mSizeMode)
1640 return NS_OK;
1642 // save the requested state
1643 rv = nsBaseWidget::SetSizeMode(aMode);
1644 if (NS_SUCCEEDED(rv) && mIsVisible) {
1645 int mode;
1647 switch (aMode) {
1648 case nsSizeMode_Fullscreen :
1649 mode = SW_SHOW;
1650 break;
1652 case nsSizeMode_Maximized :
1653 mode = SW_MAXIMIZE;
1654 break;
1656 case nsSizeMode_Minimized :
1657 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1658 // keeps the window active in the tray. So after the window is minimized,
1659 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1660 // we will do some additional processing to get the active window set right.
1661 // If sTrimOnMinimize is set, we let windows handle minimization normally
1662 // using SW_MINIMIZE.
1663 mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED;
1664 break;
1666 default :
1667 mode = SW_RESTORE;
1669 ::ShowWindow(mWnd, mode);
1670 // we dispatch an activate event here to ensure that the right child window
1671 // is focused
1672 if (mode == SW_RESTORE || mode == SW_MAXIMIZE)
1673 DispatchFocusToTopLevelWindow(NS_ACTIVATE);
1675 return rv;
1677 #endif // !defined(WINCE)
1679 // Constrain a potential move to fit onscreen
1680 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop,
1681 PRInt32 *aX, PRInt32 *aY)
1683 if (!mIsTopWidgetWindow) // only a problem for top-level windows
1684 return NS_OK;
1686 PRBool doConstrain = PR_FALSE; // whether we have enough info to do anything
1688 /* get our playing field. use the current screen, or failing that
1689 for any reason, use device caps for the default screen. */
1690 RECT screenRect;
1692 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
1693 if (screenmgr) {
1694 nsCOMPtr<nsIScreen> screen;
1695 PRInt32 left, top, width, height;
1697 // zero size rects confuse the screen manager
1698 width = mBounds.width > 0 ? mBounds.width : 1;
1699 height = mBounds.height > 0 ? mBounds.height : 1;
1700 screenmgr->ScreenForRect(*aX, *aY, width, height,
1701 getter_AddRefs(screen));
1702 if (screen) {
1703 if (mSizeMode != nsSizeMode_Fullscreen) {
1704 // For normalized windows, use the desktop work area.
1705 screen->GetAvailRect(&left, &top, &width, &height);
1706 } else {
1707 // For full screen windows, use the desktop.
1708 screen->GetRect(&left, &top, &width, &height);
1710 screenRect.left = left;
1711 screenRect.right = left+width;
1712 screenRect.top = top;
1713 screenRect.bottom = top+height;
1714 doConstrain = PR_TRUE;
1716 } else {
1717 if (mWnd) {
1718 HDC dc = ::GetDC(mWnd);
1719 if (dc) {
1720 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1721 if (mSizeMode != nsSizeMode_Fullscreen) {
1722 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
1723 } else {
1724 screenRect.left = screenRect.top = 0;
1725 screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN);
1726 screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
1728 doConstrain = PR_TRUE;
1730 ::ReleaseDC(mWnd, dc);
1735 if (aAllowSlop) {
1736 if (*aX < screenRect.left - mBounds.width + kWindowPositionSlop)
1737 *aX = screenRect.left - mBounds.width + kWindowPositionSlop;
1738 else if (*aX >= screenRect.right - kWindowPositionSlop)
1739 *aX = screenRect.right - kWindowPositionSlop;
1741 if (*aY < screenRect.top - mBounds.height + kWindowPositionSlop)
1742 *aY = screenRect.top - mBounds.height + kWindowPositionSlop;
1743 else if (*aY >= screenRect.bottom - kWindowPositionSlop)
1744 *aY = screenRect.bottom - kWindowPositionSlop;
1746 } else {
1748 if (*aX < screenRect.left)
1749 *aX = screenRect.left;
1750 else if (*aX >= screenRect.right - mBounds.width)
1751 *aX = screenRect.right - mBounds.width;
1753 if (*aY < screenRect.top)
1754 *aY = screenRect.top;
1755 else if (*aY >= screenRect.bottom - mBounds.height)
1756 *aY = screenRect.bottom - mBounds.height;
1759 return NS_OK;
1762 /**************************************************************
1764 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1766 * Enabling and disabling the widget.
1768 **************************************************************/
1770 // Enable/disable this component
1771 NS_METHOD nsWindow::Enable(PRBool bState)
1773 if (mWnd) {
1774 ::EnableWindow(mWnd, bState);
1776 return NS_OK;
1779 // Return the current enable state
1780 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
1782 NS_ENSURE_ARG_POINTER(aState);
1784 #ifndef WINCE
1785 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT)));
1786 #else
1787 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(mWnd));
1788 #endif
1790 return NS_OK;
1794 /**************************************************************
1796 * SECTION: nsIWidget::SetFocus
1798 * Give the focus to this widget.
1800 **************************************************************/
1802 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
1804 if (mWnd) {
1805 #ifdef WINSTATE_DEBUG_OUTPUT
1806 if (mWnd == GetTopLevelHWND(mWnd))
1807 printf("*** SetFocus: [ top] raise=%d\n", aRaise);
1808 else
1809 printf("*** SetFocus: [child] raise=%d\n", aRaise);
1810 #endif
1811 // Uniconify, if necessary
1812 HWND toplevelWnd = GetTopLevelHWND(mWnd);
1813 if (aRaise && ::IsIconic(toplevelWnd)) {
1814 ::ShowWindow(toplevelWnd, SW_RESTORE);
1816 ::SetFocus(mWnd);
1818 return NS_OK;
1822 /**************************************************************
1824 * SECTION: Bounds
1826 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1827 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1829 * Bound calculations.
1831 **************************************************************/
1833 // Return the window's full dimensions in screen coordinates.
1834 // If the window has a parent, converts the origin to an offset
1835 // of the parent's screen origin.
1836 NS_METHOD nsWindow::GetBounds(nsIntRect &aRect)
1838 if (mWnd) {
1839 RECT r;
1840 VERIFY(::GetWindowRect(mWnd, &r));
1842 // assign size
1843 aRect.width = r.right - r.left;
1844 aRect.height = r.bottom - r.top;
1846 // chrome on parent:
1847 // ___ 5,5 (chrome start)
1848 // | ____ 10,10 (client start)
1849 // | | ____ 20,20 (child start)
1850 // | | |
1851 // 20,20 - 5,5 = 15,15 (??)
1852 // minus GetClientOffset:
1853 // 15,15 - 5,5 = 10,10
1855 // no chrome on parent:
1856 // ______ 10,10 (win start)
1857 // | ____ 20,20 (child start)
1858 // | |
1859 // 20,20 - 10,10 = 10,10
1861 // walking the chain:
1862 // ___ 5,5 (chrome start)
1863 // | ___ 10,10 (client start)
1864 // | | ___ 20,20 (child start)
1865 // | | | __ 30,30 (child start)
1866 // | | | |
1867 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1868 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1869 // minus GetClientOffset:
1870 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1872 // convert coordinates if parent exists
1873 HWND parent = ::GetParent(mWnd);
1874 if (parent) {
1875 RECT pr;
1876 VERIFY(::GetWindowRect(parent, &pr));
1877 r.left -= pr.left;
1878 r.top -= pr.top;
1879 // adjust for chrome
1880 nsWindow* pWidget = static_cast<nsWindow*>(GetParent());
1881 if (pWidget && pWidget->IsTopLevelWidget()) {
1882 nsIntPoint clientOffset = pWidget->GetClientOffset();
1883 r.left -= clientOffset.x;
1884 r.top -= clientOffset.y;
1887 aRect.x = r.left;
1888 aRect.y = r.top;
1889 } else {
1890 aRect = mBounds;
1893 return NS_OK;
1896 // Get this component dimension
1897 NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect)
1899 if (mWnd) {
1900 RECT r;
1901 VERIFY(::GetClientRect(mWnd, &r));
1903 // assign size
1904 aRect.x = 0;
1905 aRect.y = 0;
1906 aRect.width = r.right - r.left;
1907 aRect.height = r.bottom - r.top;
1909 } else {
1910 aRect.SetRect(0,0,0,0);
1912 return NS_OK;
1915 // Like GetBounds, but don't offset by the parent
1916 NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect)
1918 if (mWnd) {
1919 RECT r;
1920 VERIFY(::GetWindowRect(mWnd, &r));
1922 aRect.width = r.right - r.left;
1923 aRect.height = r.bottom - r.top;
1924 aRect.x = r.left;
1925 aRect.y = r.top;
1926 } else
1927 aRect = mBounds;
1929 return NS_OK;
1932 // return the x,y offset of the client area from the origin
1933 // of the window. If the window is borderless returns (0,0).
1934 nsIntPoint nsWindow::GetClientOffset()
1936 if (!mWnd) {
1937 return nsIntPoint(0, 0);
1940 RECT r1;
1941 GetWindowRect(mWnd, &r1);
1942 nsIntPoint pt = WidgetToScreenOffset();
1943 return nsIntPoint(pt.x - r1.left, pt.y - r1.top);
1946 void
1947 nsWindow::SetDrawsInTitlebar(PRBool aState)
1949 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1950 if (window && window != this) {
1951 return window->SetDrawsInTitlebar(aState);
1954 if (aState) {
1955 // left, top, right, bottom for nsIntMargin
1956 nsIntMargin margins(-1, 0, -1, -1);
1957 SetNonClientMargins(margins);
1959 else {
1960 nsIntMargin margins(-1, -1, -1, -1);
1961 SetNonClientMargins(margins);
1965 NS_IMETHODIMP
1966 nsWindow::GetNonClientMargins(nsIntMargin &margins)
1968 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1969 if (window && window != this) {
1970 return window->GetNonClientMargins(margins);
1973 if (mCustomNonClient) {
1974 margins = mNonClientMargins;
1975 return NS_OK;
1978 margins.top = GetSystemMetrics(SM_CYCAPTION);
1979 margins.bottom = GetSystemMetrics(SM_CYFRAME);
1980 margins.top += margins.bottom;
1981 margins.left = margins.right = GetSystemMetrics(SM_CYFRAME);
1983 return NS_OK;
1986 void
1987 nsWindow::ResetLayout()
1989 // This will trigger a frame changed event, triggering
1990 // nc calc size and a sizemode gecko event.
1991 SetWindowPos(mWnd, 0, 0, 0, 0, 0,
1992 SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|
1993 SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
1995 // If hidden, just send the frame changed event for now.
1996 if (!mIsVisible)
1997 return;
1999 // Send a gecko size event to trigger reflow.
2000 RECT clientRc = {0};
2001 GetClientRect(mWnd, &clientRc);
2002 nsIntRect evRect(nsWindowGfx::ToIntRect(clientRc));
2003 OnResize(evRect);
2005 // Invalidate and update
2006 Invalidate(PR_FALSE);
2009 // Called when the window layout changes: full screen mode transitions,
2010 // theme changes, and composition changes. Calculates the new non-client
2011 // margins and fires off a frame changed event, which triggers an nc calc
2012 // size windows event, kicking the changes in.
2013 PRBool
2014 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode, PRBool aReflowWindow)
2016 if (!mCustomNonClient)
2017 return PR_FALSE;
2019 mNonClientOffset.top = mNonClientOffset.bottom =
2020 mNonClientOffset.left = mNonClientOffset.right = 0;
2022 if (aSizeMode == -1)
2023 aSizeMode = mSizeMode;
2025 if (aSizeMode == nsSizeMode_Minimized ||
2026 aSizeMode == nsSizeMode_Fullscreen) {
2027 mCaptionHeight = mVertResizeMargin = mHorResizeMargin = 0;
2028 return PR_TRUE;
2031 // Note, for maximized windows, we need to continue to offset the client by
2032 // thick frame margins of a normal window, since windows expects this
2033 // in it's DwmDefWndProc hit testing.
2034 mCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
2035 mHorResizeMargin = GetSystemMetrics(SM_CXFRAME);
2036 mVertResizeMargin = GetSystemMetrics(SM_CYFRAME);
2038 mCaptionHeight += mVertResizeMargin;
2040 // If a margin value is 0, set the offset to the default size of the frame.
2041 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2042 // so that the frame size is equal to the margin value.
2043 if (!mNonClientMargins.top)
2044 mNonClientOffset.top = mCaptionHeight;
2045 else if (mNonClientMargins.top > 0)
2046 mNonClientOffset.top = mCaptionHeight - mNonClientMargins.top;
2048 if (!mNonClientMargins.left)
2049 mNonClientOffset.left = mHorResizeMargin;
2050 else if (mNonClientMargins.left > 0)
2051 mNonClientOffset.left = mHorResizeMargin - mNonClientMargins.left;
2053 if (!mNonClientMargins.right)
2054 mNonClientOffset.right = mHorResizeMargin;
2055 else if (mNonClientMargins.right > 0)
2056 mNonClientOffset.right = mHorResizeMargin - mNonClientMargins.right;
2058 if (!mNonClientMargins.bottom)
2059 mNonClientOffset.bottom = mVertResizeMargin;
2060 else if (mNonClientMargins.bottom > 0)
2061 mNonClientOffset.bottom = mVertResizeMargin - mNonClientMargins.bottom;
2063 #ifndef WINCE
2064 if (aSizeMode == nsSizeMode_Maximized) {
2065 // Address an issue with auto-hide taskbars which fall behind the window.
2066 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2067 // the taskbar works properly.
2068 MONITORINFO info = {sizeof(MONITORINFO)};
2069 if (::GetMonitorInfo(::MonitorFromWindow(mWnd, MONITOR_DEFAULTTOPRIMARY),
2070 &info)) {
2071 RECT r;
2072 if (::GetWindowRect(mWnd, &r)) {
2073 // Adjust window rect to account for non-client margins.
2074 r.top += mVertResizeMargin - mNonClientOffset.top;
2075 r.left += mHorResizeMargin - mNonClientOffset.left;
2076 r.bottom -= mVertResizeMargin - mNonClientOffset.bottom;
2077 r.right -= mHorResizeMargin - mNonClientOffset.right;
2078 // Leave the 1 pixel margin if the window covers the monitor.
2079 if (r.top <= info.rcMonitor.top &&
2080 r.left <= info.rcMonitor.left &&
2081 r.right >= info.rcMonitor.right &&
2082 r.bottom >= info.rcMonitor.bottom)
2083 mNonClientOffset.bottom -= r.bottom - info.rcMonitor.bottom + 1;
2087 #endif
2089 if (aReflowWindow) {
2090 // Force a reflow of content based on the new client
2091 // dimensions.
2092 ResetLayout();
2095 return PR_TRUE;
2098 NS_IMETHODIMP
2099 nsWindow::SetNonClientMargins(nsIntMargin &margins)
2101 if (!mIsTopWidgetWindow ||
2102 mBorderStyle & eBorderStyle_none ||
2103 mHideChrome)
2104 return NS_ERROR_INVALID_ARG;
2106 // Request for a reset
2107 if (margins.top == -1 && margins.left == -1 &&
2108 margins.right == -1 && margins.bottom == -1) {
2109 mCustomNonClient = PR_FALSE;
2110 mNonClientMargins = margins;
2111 // Force a reflow of content based on the new client
2112 // dimensions.
2113 ResetLayout();
2114 return NS_OK;
2117 if (margins.top < -1 || margins.bottom < -1 ||
2118 margins.left < -1 || margins.right < -1)
2119 return NS_ERROR_INVALID_ARG;
2121 mNonClientMargins = margins;
2122 mCustomNonClient = PR_TRUE;
2123 if (!UpdateNonClientMargins()) {
2124 NS_WARNING("UpdateNonClientMargins failed!");
2125 return PR_FALSE;
2128 return NS_OK;
2131 void
2132 nsWindow::InvalidateNonClientRegion()
2134 // +-+-----------------------+-+
2135 // | | app non-client chrome | |
2136 // | +-----------------------+ |
2137 // | | app client chrome | | }
2138 // | +-----------------------+ | }
2139 // | | app content | | } area we don't want to invalidate
2140 // | +-----------------------+ | }
2141 // | | app client chrome | | }
2142 // | +-----------------------+ |
2143 // +---------------------------+ <
2144 // ^ ^ windows non-client chrome
2145 // client area = app *
2146 RECT rect;
2147 GetWindowRect(mWnd, &rect);
2148 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2149 HRGN winRgn = CreateRectRgnIndirect(&rect);
2151 // Subtract app client chrome and app content leaving
2152 // windows non-client chrome and app non-client chrome
2153 // in winRgn.
2154 GetWindowRect(mWnd, &rect);
2155 rect.top += mCaptionHeight;
2156 rect.right -= mHorResizeMargin;
2157 rect.bottom -= mHorResizeMargin;
2158 rect.left += mVertResizeMargin;
2159 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2160 HRGN clientRgn = CreateRectRgnIndirect(&rect);
2161 CombineRgn(winRgn, winRgn, clientRgn, RGN_DIFF);
2162 DeleteObject(clientRgn);
2164 // triggers ncpaint and paint events for the two areas
2165 RedrawWindow(mWnd, NULL, winRgn, RDW_FRAME|RDW_INVALIDATE);
2166 DeleteObject(winRgn);
2169 HRGN
2170 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion)
2172 RECT rect;
2173 HRGN rgn = NULL;
2174 if (aRegion == (HRGN)1) { // undocumented value indicating a full refresh
2175 GetWindowRect(mWnd, &rect);
2176 rgn = CreateRectRgnIndirect(&rect);
2177 } else {
2178 rgn = aRegion;
2180 GetClientRect(mWnd, &rect);
2181 MapWindowPoints(mWnd, NULL, (LPPOINT)&rect, 2);
2182 HRGN nonClientRgn = CreateRectRgnIndirect(&rect);
2183 CombineRgn(rgn, rgn, nonClientRgn, RGN_DIFF);
2184 DeleteObject(nonClientRgn);
2185 return rgn;
2188 /**************************************************************
2190 * SECTION: nsIWidget::SetBackgroundColor
2192 * Sets the window background paint color.
2194 **************************************************************/
2196 NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
2198 nsBaseWidget::SetBackgroundColor(aColor);
2200 if (mBrush)
2201 ::DeleteObject(mBrush);
2203 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
2204 #ifndef WINCE
2205 if (mWnd != NULL) {
2206 ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush);
2208 #endif
2209 return NS_OK;
2212 /**************************************************************
2214 * SECTION: nsIWidget::SetCursor
2216 * SetCursor and related utilities for manging cursor state.
2218 **************************************************************/
2220 // Set this component cursor
2221 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
2223 // Only change cursor if it's changing
2225 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2226 //XXX If we want this optimization we need a better way to do it.
2227 //if (aCursor != mCursor) {
2228 HCURSOR newCursor = NULL;
2230 switch (aCursor) {
2231 case eCursor_select:
2232 newCursor = ::LoadCursor(NULL, IDC_IBEAM);
2233 break;
2235 case eCursor_wait:
2236 newCursor = ::LoadCursor(NULL, IDC_WAIT);
2237 break;
2239 case eCursor_hyperlink:
2241 newCursor = ::LoadCursor(NULL, IDC_HAND);
2242 break;
2245 case eCursor_standard:
2246 newCursor = ::LoadCursor(NULL, IDC_ARROW);
2247 break;
2249 case eCursor_n_resize:
2250 case eCursor_s_resize:
2251 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2252 break;
2254 case eCursor_w_resize:
2255 case eCursor_e_resize:
2256 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2257 break;
2259 case eCursor_nw_resize:
2260 case eCursor_se_resize:
2261 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2262 break;
2264 case eCursor_ne_resize:
2265 case eCursor_sw_resize:
2266 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2267 break;
2269 case eCursor_crosshair:
2270 newCursor = ::LoadCursor(NULL, IDC_CROSS);
2271 break;
2273 case eCursor_move:
2274 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2275 break;
2277 case eCursor_help:
2278 newCursor = ::LoadCursor(NULL, IDC_HELP);
2279 break;
2281 case eCursor_copy: // CSS3
2282 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
2283 break;
2285 case eCursor_alias:
2286 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
2287 break;
2289 case eCursor_cell:
2290 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
2291 break;
2293 case eCursor_grab:
2294 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
2295 break;
2297 case eCursor_grabbing:
2298 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
2299 break;
2301 case eCursor_spinning:
2302 newCursor = ::LoadCursor(NULL, IDC_APPSTARTING);
2303 break;
2305 case eCursor_context_menu:
2306 // XXX this CSS3 cursor needs to be implemented
2307 break;
2309 case eCursor_zoom_in:
2310 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
2311 break;
2313 case eCursor_zoom_out:
2314 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
2315 break;
2317 case eCursor_not_allowed:
2318 case eCursor_no_drop:
2319 newCursor = ::LoadCursor(NULL, IDC_NO);
2320 break;
2322 case eCursor_col_resize:
2323 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
2324 break;
2326 case eCursor_row_resize:
2327 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
2328 break;
2330 case eCursor_vertical_text:
2331 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT));
2332 break;
2334 case eCursor_all_scroll:
2335 // XXX not 100% appropriate perhaps
2336 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2337 break;
2339 case eCursor_nesw_resize:
2340 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2341 break;
2343 case eCursor_nwse_resize:
2344 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2345 break;
2347 case eCursor_ns_resize:
2348 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2349 break;
2351 case eCursor_ew_resize:
2352 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2353 break;
2355 case eCursor_none:
2356 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
2357 break;
2359 default:
2360 NS_ERROR("Invalid cursor type");
2361 break;
2364 if (NULL != newCursor) {
2365 mCursor = aCursor;
2366 HCURSOR oldCursor = ::SetCursor(newCursor);
2368 if (sHCursor == oldCursor) {
2369 NS_IF_RELEASE(sCursorImgContainer);
2370 if (sHCursor != NULL)
2371 ::DestroyIcon(sHCursor);
2372 sHCursor = NULL;
2376 return NS_OK;
2379 // Setting the actual cursor
2380 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
2381 PRUint32 aHotspotX, PRUint32 aHotspotY)
2383 if (sCursorImgContainer == aCursor && sHCursor) {
2384 ::SetCursor(sHCursor);
2385 return NS_OK;
2388 PRInt32 width;
2389 PRInt32 height;
2391 nsresult rv;
2392 rv = aCursor->GetWidth(&width);
2393 NS_ENSURE_SUCCESS(rv, rv);
2394 rv = aCursor->GetHeight(&height);
2395 NS_ENSURE_SUCCESS(rv, rv);
2397 // Reject cursors greater than 128 pixels in either direction, to prevent
2398 // spoofing.
2399 // XXX ideally we should rescale. Also, we could modify the API to
2400 // allow trusted content to set larger cursors.
2401 if (width > 128 || height > 128)
2402 return NS_ERROR_NOT_AVAILABLE;
2404 HCURSOR cursor;
2405 rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
2406 NS_ENSURE_SUCCESS(rv, rv);
2408 mCursor = nsCursor(-1);
2409 ::SetCursor(cursor);
2411 NS_IF_RELEASE(sCursorImgContainer);
2412 sCursorImgContainer = aCursor;
2413 NS_ADDREF(sCursorImgContainer);
2415 if (sHCursor != NULL)
2416 ::DestroyIcon(sHCursor);
2417 sHCursor = cursor;
2419 return NS_OK;
2422 /**************************************************************
2424 * SECTION: nsIWidget::Get/SetTransparencyMode
2426 * Manage the transparency mode of the top-level window
2427 * containing this widget.
2429 **************************************************************/
2431 #ifdef MOZ_XUL
2432 nsTransparencyMode nsWindow::GetTransparencyMode()
2434 return GetTopLevelWindow(PR_TRUE)->GetWindowTranslucencyInner();
2437 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
2439 GetTopLevelWindow(PR_TRUE)->SetWindowTranslucencyInner(aMode);
2442 namespace {
2443 BOOL CALLBACK AddClientAreaToRegion(HWND hWnd, LPARAM lParam) {
2444 nsIntRegion *region = reinterpret_cast<nsIntRegion*>(lParam);
2446 RECT clientRect;
2447 ::GetWindowRect(hWnd, &clientRect);
2448 nsIntRect clientArea(clientRect.left, clientRect.top,
2449 clientRect.right - clientRect.left,
2450 clientRect.bottom - clientRect.top);
2451 region->Or(*region, clientArea);
2452 return TRUE;
2456 void nsWindow::UpdatePossiblyTransparentRegion(const nsIntRegion &aDirtyRegion,
2457 const nsIntRegion &aPossiblyTransparentRegion) {
2458 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2459 if (!HasGlass())
2460 return;
2462 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2463 nsWindow* topWindow = GetNSWindowPtr(hWnd);
2465 if (GetParent())
2466 return;
2468 mPossiblyTransparentRegion.Sub(mPossiblyTransparentRegion, aDirtyRegion);
2469 mPossiblyTransparentRegion.Or(mPossiblyTransparentRegion, aPossiblyTransparentRegion);
2471 nsIntRegion childWindowRegion;
2473 ::EnumChildWindows(mWnd, AddClientAreaToRegion, reinterpret_cast<LPARAM>(&childWindowRegion));
2475 nsIntPoint clientOffset = GetClientOffset();
2476 childWindowRegion.MoveBy(-clientOffset);
2478 RECT r;
2479 ::GetWindowRect(mWnd, &r);
2480 childWindowRegion.MoveBy(-r.left, -r.top);
2482 nsIntRect clientBounds;
2483 topWindow->GetClientBounds(clientBounds);
2484 nsIntRegion opaqueRegion;
2485 opaqueRegion.Sub(clientBounds, mPossiblyTransparentRegion);
2486 opaqueRegion.Or(opaqueRegion, childWindowRegion);
2487 // Sometimes child windows overlap our bounds
2488 opaqueRegion.And(opaqueRegion, clientBounds);
2490 MARGINS margins = { 0, 0, 0, 0 };
2491 DWORD_PTR dwStyle = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
2493 // If there is no opaque region or hidechrome=true, set margins
2494 // to support a full sheet of glass.
2495 if (opaqueRegion.IsEmpty() || mHideChrome) {
2496 // Comments in MSDN indicate all values must be set to -1
2497 margins.cxLeftWidth = margins.cxRightWidth =
2498 margins.cyTopHeight = margins.cyBottomHeight = -1;
2499 } else {
2500 // Find the largest rectangle and use that to calculate the inset
2501 nsIntRect largest = opaqueRegion.GetLargestRectangle();
2502 margins.cxLeftWidth = largest.x;
2503 margins.cxRightWidth = clientBounds.width - largest.XMost();
2504 margins.cyTopHeight = largest.y;
2505 margins.cyBottomHeight = clientBounds.height - largest.YMost();
2508 // Only update glass area if there are changes
2509 if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) {
2510 mGlassMargins = margins;
2511 UpdateGlass();
2513 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2516 void nsWindow::UpdateGlass()
2518 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2519 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2520 MARGINS margins = mGlassMargins;
2522 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2523 // rendered based on the window style.
2524 // DWMNCRP_ENABLED - The non-client area rendering is
2525 // enabled; the window style is ignored.
2526 DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE;
2527 switch (mTransparencyMode) {
2528 case eTransparencyBorderlessGlass:
2529 // Only adjust if there is some opaque rectangle
2530 if (margins.cxLeftWidth >= 0) {
2531 const PRInt32 kGlassMarginAdjustment = 2;
2532 margins.cxLeftWidth += kGlassMarginAdjustment;
2533 margins.cyTopHeight += kGlassMarginAdjustment;
2534 margins.cxRightWidth += kGlassMarginAdjustment;
2535 margins.cyBottomHeight += kGlassMarginAdjustment;
2537 // Fall through
2538 case eTransparencyGlass:
2539 policy = DWMNCRP_ENABLED;
2540 break;
2543 // Extends the window frame behind the client area
2544 if(nsUXThemeData::CheckForCompositor()) {
2545 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd, &margins);
2546 nsUXThemeData::dwmSetWindowAttributePtr(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy);
2548 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2550 #endif
2552 /**************************************************************
2554 * SECTION: nsIWidget::HideWindowChrome
2556 * Show or hide window chrome.
2558 **************************************************************/
2560 NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide)
2562 HWND hwnd = GetTopLevelHWND(mWnd, PR_TRUE);
2563 if (!GetNSWindowPtr(hwnd))
2565 NS_WARNING("Trying to hide window decorations in an embedded context");
2566 return NS_ERROR_FAILURE;
2569 if (mHideChrome == aShouldHide)
2570 return NS_OK;
2572 DWORD_PTR style, exStyle;
2573 mHideChrome = aShouldHide;
2574 if (aShouldHide) {
2575 DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2576 DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2578 style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
2579 exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
2580 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
2582 mOldStyle = tempStyle;
2583 mOldExStyle = tempExStyle;
2585 else {
2586 if (!mOldStyle || !mOldExStyle) {
2587 mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2588 mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2591 style = mOldStyle;
2592 exStyle = mOldExStyle;
2595 VERIFY_WINDOW_STYLE(style);
2596 ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
2597 ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
2599 return NS_OK;
2602 /**************************************************************
2604 * SECTION: nsIWidget::Invalidate
2606 * Invalidate an area of the client for painting.
2608 **************************************************************/
2610 // Invalidate this component visible area
2611 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
2613 if (mWnd)
2615 #ifdef WIDGET_DEBUG_OUTPUT
2616 debug_DumpInvalidate(stdout,
2617 this,
2618 nsnull,
2619 aIsSynchronous,
2620 nsCAutoString("noname"),
2621 (PRInt32) mWnd);
2622 #endif // WIDGET_DEBUG_OUTPUT
2624 VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
2626 if (aIsSynchronous) {
2627 VERIFY(::UpdateWindow(mWnd));
2630 return NS_OK;
2633 // Invalidate this component visible area
2634 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, PRBool aIsSynchronous)
2636 if (mWnd)
2638 #ifdef WIDGET_DEBUG_OUTPUT
2639 debug_DumpInvalidate(stdout,
2640 this,
2641 &aRect,
2642 aIsSynchronous,
2643 nsCAutoString("noname"),
2644 (PRInt32) mWnd);
2645 #endif // WIDGET_DEBUG_OUTPUT
2647 RECT rect;
2649 rect.left = aRect.x;
2650 rect.top = aRect.y;
2651 rect.right = aRect.x + aRect.width;
2652 rect.bottom = aRect.y + aRect.height;
2654 VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
2656 if (aIsSynchronous) {
2657 VERIFY(::UpdateWindow(mWnd));
2660 return NS_OK;
2663 NS_IMETHODIMP
2664 nsWindow::MakeFullScreen(PRBool aFullScreen)
2666 #if WINCE_WINDOWS_MOBILE
2667 RECT rc;
2668 if (aFullScreen) {
2669 SetForegroundWindow(mWnd);
2670 if (nsWindowCE::sMenuBarShown) {
2671 SIPINFO sipInfo;
2672 memset(&sipInfo, 0, sizeof(SIPINFO));
2673 sipInfo.cbSize = sizeof(SIPINFO);
2674 if (SipGetInfo(&sipInfo))
2675 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2676 sipInfo.rcVisibleDesktop.bottom);
2677 else
2678 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2679 GetSystemMetrics(SM_CYSCREEN));
2680 RECT menuBarRect;
2681 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle, &menuBarRect) &&
2682 menuBarRect.top < rc.bottom)
2683 rc.bottom = menuBarRect.top;
2684 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_SHOWSIPBUTTON);
2685 } else {
2687 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);
2688 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2691 else {
2692 SHFullScreen(mWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
2693 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
2696 if (aFullScreen)
2697 mSizeMode = nsSizeMode_Fullscreen;
2699 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2700 HideWindowChrome(aFullScreen);
2701 Resize(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PR_TRUE);
2703 return NS_OK;
2705 #else
2707 if (aFullScreen) {
2708 if (mSizeMode == nsSizeMode_Fullscreen)
2709 return NS_OK;
2710 mOldSizeMode = mSizeMode;
2711 SetSizeMode(nsSizeMode_Fullscreen);
2712 } else {
2713 SetSizeMode(mOldSizeMode);
2716 UpdateNonClientMargins();
2718 // Will call hide chrome, reposition window. Note this will
2719 // also cache dimensions for restoration, so it should only
2720 // be called once per fullscreen request.
2721 nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen);
2723 // Let the dom know via web shell window
2724 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
2725 event.mSizeMode = mSizeMode;
2726 InitEvent(event);
2727 DispatchWindowEvent(&event);
2729 return rv;
2730 #endif
2733 /**************************************************************
2735 * SECTION: nsIWidget::Update
2737 * Force a synchronous repaint of the window.
2739 **************************************************************/
2741 NS_IMETHODIMP nsWindow::Update()
2743 nsresult rv = NS_OK;
2745 // updates can come through for windows no longer holding an mWnd during
2746 // deletes triggered by JavaScript in buttons with mouse feedback
2747 if (mWnd)
2748 VERIFY(::UpdateWindow(mWnd));
2750 return rv;
2753 /**************************************************************
2755 * SECTION: Native data storage
2757 * nsIWidget::GetNativeData
2758 * nsIWidget::FreeNativeData
2760 * Set or clear native data based on a constant.
2762 **************************************************************/
2764 // Return some native data according to aDataType
2765 void* nsWindow::GetNativeData(PRUint32 aDataType)
2767 switch (aDataType) {
2768 case NS_NATIVE_PLUGIN_PORT:
2769 case NS_NATIVE_WIDGET:
2770 case NS_NATIVE_WINDOW:
2771 return (void*)mWnd;
2772 case NS_NATIVE_GRAPHIC:
2773 // XXX: This is sleezy!! Remember to Release the DC after using it!
2774 #ifdef MOZ_XUL
2775 return (void*)(eTransparencyTransparent == mTransparencyMode) ?
2776 mMemoryDC : ::GetDC(mWnd);
2777 #else
2778 return (void*)::GetDC(mWnd);
2779 #endif
2781 #ifdef NS_ENABLE_TSF
2782 case NS_NATIVE_TSF_THREAD_MGR:
2783 return nsTextStore::GetThreadMgr();
2784 case NS_NATIVE_TSF_CATEGORY_MGR:
2785 return nsTextStore::GetCategoryMgr();
2786 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
2787 return nsTextStore::GetDisplayAttrMgr();
2788 #endif //NS_ENABLE_TSF
2790 default:
2791 break;
2794 return NULL;
2797 // Free some native data according to aDataType
2798 void nsWindow::FreeNativeData(void * data, PRUint32 aDataType)
2800 switch (aDataType)
2802 case NS_NATIVE_GRAPHIC:
2803 #ifdef MOZ_XUL
2804 if (eTransparencyTransparent != mTransparencyMode)
2805 ::ReleaseDC(mWnd, (HDC)data);
2806 #else
2807 ::ReleaseDC(mWnd, (HDC)data);
2808 #endif
2809 break;
2810 case NS_NATIVE_WIDGET:
2811 case NS_NATIVE_WINDOW:
2812 case NS_NATIVE_PLUGIN_PORT:
2813 break;
2814 default:
2815 break;
2819 /**************************************************************
2821 * SECTION: nsIWidget::SetTitle
2823 * Set the main windows title text.
2825 **************************************************************/
2827 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
2829 const nsString& strTitle = PromiseFlatString(aTitle);
2830 ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get());
2831 return NS_OK;
2834 /**************************************************************
2836 * SECTION: nsIWidget::SetIcon
2838 * Set the main windows icon.
2840 **************************************************************/
2842 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec)
2844 #ifndef WINCE
2845 // Assume the given string is a local identifier for an icon file.
2847 nsCOMPtr<nsILocalFile> iconFile;
2848 ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
2849 getter_AddRefs(iconFile));
2850 if (!iconFile)
2851 return NS_OK; // not an error if icon is not found
2853 nsAutoString iconPath;
2854 iconFile->GetPath(iconPath);
2856 // XXX this should use MZLU (see bug 239279)
2858 ::SetLastError(0);
2860 HICON bigIcon = (HICON)::LoadImageW(NULL,
2861 (LPCWSTR)iconPath.get(),
2862 IMAGE_ICON,
2863 ::GetSystemMetrics(SM_CXICON),
2864 ::GetSystemMetrics(SM_CYICON),
2865 LR_LOADFROMFILE );
2866 HICON smallIcon = (HICON)::LoadImageW(NULL,
2867 (LPCWSTR)iconPath.get(),
2868 IMAGE_ICON,
2869 ::GetSystemMetrics(SM_CXSMICON),
2870 ::GetSystemMetrics(SM_CYSMICON),
2871 LR_LOADFROMFILE );
2873 if (bigIcon) {
2874 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon);
2875 if (icon)
2876 ::DestroyIcon(icon);
2878 #ifdef DEBUG_SetIcon
2879 else {
2880 NS_LossyConvertUTF16toASCII cPath(iconPath);
2881 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2883 #endif
2884 if (smallIcon) {
2885 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon);
2886 if (icon)
2887 ::DestroyIcon(icon);
2889 #ifdef DEBUG_SetIcon
2890 else {
2891 NS_LossyConvertUTF16toASCII cPath(iconPath);
2892 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2894 #endif
2895 #endif // WINCE
2896 return NS_OK;
2899 /**************************************************************
2901 * SECTION: nsIWidget::WidgetToScreenOffset
2903 * Return this widget's origin in screen coordinates.
2905 **************************************************************/
2907 nsIntPoint nsWindow::WidgetToScreenOffset()
2909 POINT point;
2910 point.x = 0;
2911 point.y = 0;
2912 ::ClientToScreen(mWnd, &point);
2913 return nsIntPoint(point.x, point.y);
2916 nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize)
2918 if (!IsPopupWithTitleBar())
2919 return aClientSize;
2921 // just use (200, 200) as the position
2922 RECT r;
2923 r.left = 200;
2924 r.top = 200;
2925 r.right = 200 + aClientSize.width;
2926 r.bottom = 200 + aClientSize.height;
2927 ::AdjustWindowRectEx(&r, WindowStyle(), PR_FALSE, WindowExStyle());
2929 return nsIntSize(r.right - r.left, r.bottom - r.top);
2932 /**************************************************************
2934 * SECTION: nsIWidget::EnableDragDrop
2936 * Enables/Disables drag and drop of files on this widget.
2938 **************************************************************/
2940 #if !defined(WINCE) // implemented in nsWindowCE.cpp
2941 NS_METHOD nsWindow::EnableDragDrop(PRBool aEnable)
2943 NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()");
2945 nsresult rv = NS_ERROR_FAILURE;
2946 if (aEnable) {
2947 if (nsnull == mNativeDragTarget) {
2948 mNativeDragTarget = new nsNativeDragTarget(this);
2949 if (NULL != mNativeDragTarget) {
2950 mNativeDragTarget->AddRef();
2951 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) {
2952 if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) {
2953 rv = NS_OK;
2958 } else {
2959 if (nsnull != mWnd && NULL != mNativeDragTarget) {
2960 ::RevokeDragDrop(mWnd);
2961 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) {
2962 rv = NS_OK;
2964 mNativeDragTarget->DragCancel();
2965 NS_RELEASE(mNativeDragTarget);
2968 return rv;
2970 #endif
2972 /**************************************************************
2974 * SECTION: nsIWidget::CaptureMouse
2976 * Enables/Disables system mouse capture.
2978 **************************************************************/
2980 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
2982 if (!nsToolkit::gMouseTrailer) {
2983 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
2984 return NS_OK;
2987 if (aCapture) {
2988 nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd);
2989 ::SetCapture(mWnd);
2990 } else {
2991 nsToolkit::gMouseTrailer->SetCaptureWindow(NULL);
2992 ::ReleaseCapture();
2994 mIsInMouseCapture = aCapture;
2995 return NS_OK;
2998 /**************************************************************
3000 * SECTION: nsIWidget::CaptureRollupEvents
3002 * Dealing with event rollup on destroy for popups. Enables &
3003 * Disables system capture of any and all events that would
3004 * cause a dropdown to be rolled up.
3006 **************************************************************/
3008 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
3009 nsIMenuRollup * aMenuRollup,
3010 PRBool aDoCapture,
3011 PRBool aConsumeRollupEvent)
3013 if (aDoCapture) {
3014 /* we haven't bothered carrying a weak reference to sRollupWidget because
3015 we believe lifespan is properly scoped. this next assertion helps
3016 assure that remains true. */
3017 NS_ASSERTION(!sRollupWidget, "rollup widget reassigned before release");
3018 sRollupConsumeEvent = aConsumeRollupEvent;
3019 NS_IF_RELEASE(sRollupWidget);
3020 NS_IF_RELEASE(sMenuRollup);
3021 sRollupListener = aListener;
3022 sMenuRollup = aMenuRollup;
3023 NS_IF_ADDREF(aMenuRollup);
3024 sRollupWidget = this;
3025 NS_ADDREF(this);
3027 #ifndef WINCE
3028 if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
3029 RegisterSpecialDropdownHooks();
3031 sProcessHook = PR_TRUE;
3032 #endif
3034 } else {
3035 sRollupListener = nsnull;
3036 NS_IF_RELEASE(sMenuRollup);
3037 NS_IF_RELEASE(sRollupWidget);
3039 #ifndef WINCE
3040 sProcessHook = PR_FALSE;
3041 UnregisterSpecialDropdownHooks();
3042 #endif
3045 return NS_OK;
3048 /**************************************************************
3050 * SECTION: nsIWidget::GetAttention
3052 * Bring this window to the user's attention.
3054 **************************************************************/
3056 // Draw user's attention to this window until it comes to foreground.
3057 NS_IMETHODIMP
3058 nsWindow::GetAttention(PRInt32 aCycleCount)
3060 #ifndef WINCE
3061 // Got window?
3062 if (!mWnd)
3063 return NS_ERROR_NOT_INITIALIZED;
3065 // Don't flash if the flash count is 0 or if the
3066 // top level window is already active.
3067 HWND fgWnd = ::GetForegroundWindow();
3068 if (aCycleCount == 0 || fgWnd == GetTopLevelHWND(mWnd))
3069 return NS_OK;
3071 HWND flashWnd = mWnd;
3072 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3073 flashWnd = ownerWnd;
3076 // Don't flash if the owner window is active either.
3077 if (fgWnd == flashWnd)
3078 return NS_OK;
3080 DWORD defaultCycleCount = 0;
3081 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
3083 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3084 FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 };
3085 ::FlashWindowEx(&flashInfo);
3086 #endif
3087 return NS_OK;
3090 void nsWindow::StopFlashing()
3092 #ifndef WINCE
3093 HWND flashWnd = mWnd;
3094 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3095 flashWnd = ownerWnd;
3098 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3099 FLASHW_STOP, 0, 0 };
3100 ::FlashWindowEx(&flashInfo);
3101 #endif
3104 /**************************************************************
3106 * SECTION: nsIWidget::HasPendingInputEvent
3108 * Ask whether there user input events pending. All input events are
3109 * included, including those not targeted at this nsIwidget instance.
3111 **************************************************************/
3113 PRBool
3114 nsWindow::HasPendingInputEvent()
3116 // If there is pending input or the user is currently
3117 // moving the window then return true.
3118 // Note: When the user is moving the window WIN32 spins
3119 // a separate event loop and input events are not
3120 // reported to the application.
3121 if (HIWORD(GetQueueStatus(QS_INPUT)))
3122 return PR_TRUE;
3123 #ifdef WINCE
3124 return PR_FALSE;
3125 #else
3126 GUITHREADINFO guiInfo;
3127 guiInfo.cbSize = sizeof(GUITHREADINFO);
3128 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo))
3129 return PR_FALSE;
3130 return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE);
3131 #endif
3134 /**************************************************************
3136 * SECTION: nsIWidget::GetLayerManager
3138 * Get the layer manager associated with this widget.
3140 **************************************************************/
3142 mozilla::layers::LayerManager*
3143 nsWindow::GetLayerManager()
3145 nsWindow *topWindow = GetNSWindowPtr(GetTopLevelHWND(mWnd, PR_TRUE));
3147 if (!topWindow) {
3148 return nsBaseWidget::GetLayerManager();
3151 if (topWindow->GetAcceleratedRendering() != mUseAcceleratedRendering) {
3152 mLayerManager = NULL;
3153 mUseAcceleratedRendering = topWindow->GetAcceleratedRendering();
3156 #ifndef WINCE
3157 if (!mLayerManager) {
3158 if (mUseAcceleratedRendering) {
3159 nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3161 PRBool allowAcceleration = PR_TRUE;
3162 PRBool preferOpenGL = PR_FALSE;
3163 if (prefs) {
3164 prefs->GetBoolPref("mozilla.widget.accelerated-layers",
3165 &allowAcceleration);
3166 prefs->GetBoolPref("mozilla.layers.prefer-opengl",
3167 &preferOpenGL);
3170 if (allowAcceleration) {
3171 #ifdef MOZ_ENABLE_D3D9_LAYER
3172 if (!preferOpenGL) {
3173 nsRefPtr<mozilla::layers::LayerManagerD3D9> layerManager =
3174 new mozilla::layers::LayerManagerD3D9(this);
3175 if (layerManager->Initialize()) {
3176 mLayerManager = layerManager;
3179 #endif
3180 if (!mLayerManager) {
3181 nsRefPtr<mozilla::layers::LayerManagerOGL> layerManager =
3182 new mozilla::layers::LayerManagerOGL(this);
3183 if (layerManager->Initialize()) {
3184 mLayerManager = layerManager;
3190 #endif
3192 return nsBaseWidget::GetLayerManager();
3195 /**************************************************************
3197 * SECTION: nsIWidget::GetThebesSurface
3199 * Get the Thebes surface associated with this widget.
3201 **************************************************************/
3203 gfxASurface *nsWindow::GetThebesSurface()
3205 #ifdef CAIRO_HAS_D2D_SURFACE
3206 if (mD2DWindowSurface) {
3207 return mD2DWindowSurface;
3209 #endif
3210 if (mPaintDC)
3211 return (new gfxWindowsSurface(mPaintDC));
3213 #ifdef CAIRO_HAS_D2D_SURFACE
3214 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3215 gfxWindowsPlatform::RENDER_DIRECT2D) {
3216 gfxASurface::gfxContentType content = gfxASurface::CONTENT_COLOR;
3217 #if defined(MOZ_XUL)
3218 if (mTransparencyMode != eTransparencyOpaque) {
3219 content = gfxASurface::CONTENT_COLOR_ALPHA;
3221 #endif
3222 return (new gfxD2DSurface(mWnd, content));
3223 } else {
3224 #endif
3225 PRUint32 flags = gfxWindowsSurface::FLAG_TAKE_DC;
3226 if (mTransparencyMode != eTransparencyOpaque) {
3227 flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT;
3229 return (new gfxWindowsSurface(mWnd, flags));
3230 #ifdef CAIRO_HAS_D2D_SURFACE
3232 #endif
3235 /**************************************************************
3237 * SECTION: nsIWidget::OnDefaultButtonLoaded
3239 * Called after the dialog is loaded and it has a default button.
3241 **************************************************************/
3243 NS_IMETHODIMP
3244 nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect)
3246 #ifdef WINCE
3247 return NS_ERROR_NOT_IMPLEMENTED;
3248 #else
3249 if (aButtonRect.IsEmpty())
3250 return NS_OK;
3252 // Don't snap when we are not active.
3253 HWND activeWnd = ::GetActiveWindow();
3254 if (activeWnd != ::GetForegroundWindow() ||
3255 GetTopLevelHWND(mWnd, PR_TRUE) != GetTopLevelHWND(activeWnd, PR_TRUE)) {
3256 return NS_OK;
3259 PRBool isAlwaysSnapCursor = PR_FALSE;
3260 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3261 if (prefs) {
3262 nsCOMPtr<nsIPrefBranch> prefBranch;
3263 prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
3264 if (prefBranch) {
3265 prefBranch->GetBoolPref("ui.cursor_snapping.always_enabled",
3266 &isAlwaysSnapCursor);
3270 if (!isAlwaysSnapCursor) {
3271 BOOL snapDefaultButton;
3272 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0,
3273 &snapDefaultButton, 0) || !snapDefaultButton)
3274 return NS_OK;
3277 nsIntRect widgetRect;
3278 nsresult rv = GetScreenBounds(widgetRect);
3279 NS_ENSURE_SUCCESS(rv, rv);
3280 nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft());
3282 nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2,
3283 buttonRect.y + buttonRect.height / 2);
3284 // The center of the button can be outside of the widget.
3285 // E.g., it could be hidden by scrolling.
3286 if (!widgetRect.Contains(centerOfButton)) {
3287 return NS_OK;
3290 if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) {
3291 NS_ERROR("SetCursorPos failed");
3292 return NS_ERROR_FAILURE;
3294 return NS_OK;
3295 #endif
3298 NS_IMETHODIMP
3299 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta,
3300 PRBool aIsHorizontal,
3301 PRInt32 &aOverriddenDelta)
3303 // The default vertical and horizontal scrolling speed is 3, this is defined
3304 // on the document of SystemParametersInfo in MSDN.
3305 const PRUint32 kSystemDefaultScrollingSpeed = 3;
3307 PRInt32 absOriginDelta = PR_ABS(aOriginalDelta);
3309 // Compute the simple overridden speed.
3310 PRInt32 absComputedOverriddenDelta;
3311 nsresult rv =
3312 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta, aIsHorizontal,
3313 absComputedOverriddenDelta);
3314 NS_ENSURE_SUCCESS(rv, rv);
3316 aOverriddenDelta = aOriginalDelta;
3318 if (absComputedOverriddenDelta == absOriginDelta) {
3319 // We don't override now.
3320 return NS_OK;
3323 // Otherwise, we should check whether the user customized the system settings
3324 // or not. If the user did it, we should respect the will.
3325 UINT systemSpeed;
3326 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) {
3327 return NS_ERROR_FAILURE;
3329 // The default vertical scrolling speed is 3, this is defined on the document
3330 // of SystemParametersInfo in MSDN.
3331 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3332 return NS_OK;
3335 // Only Vista and later, Windows has the system setting of horizontal
3336 // scrolling by the mouse wheel.
3337 if (GetWindowsVersion() >= VISTA_VERSION) {
3338 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) {
3339 return NS_ERROR_FAILURE;
3341 // The default horizontal scrolling speed is 3, this is defined on the
3342 // document of SystemParametersInfo in MSDN.
3343 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3344 return NS_OK;
3348 // Limit the overridden delta value from the system settings. The mouse
3349 // driver might accelerate the scrolling speed already. If so, we shouldn't
3350 // override the scrolling speed for preventing the unexpected high speed
3351 // scrolling.
3352 PRInt32 absDeltaLimit;
3353 rv =
3354 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed,
3355 aIsHorizontal, absDeltaLimit);
3356 NS_ENSURE_SUCCESS(rv, rv);
3358 // If the given delta is larger than our computed limitation value, the delta
3359 // was accelerated by the mouse driver. So, we should do nothing here.
3360 if (absDeltaLimit <= absOriginDelta) {
3361 return NS_OK;
3364 absComputedOverriddenDelta =
3365 PR_MIN(absComputedOverriddenDelta, absDeltaLimit);
3367 aOverriddenDelta = (aOriginalDelta > 0) ? absComputedOverriddenDelta :
3368 -absComputedOverriddenDelta;
3369 return NS_OK;
3372 /**************************************************************
3373 **************************************************************
3375 ** BLOCK: Moz Events
3377 ** Moz GUI event management.
3379 **************************************************************
3380 **************************************************************/
3382 /**************************************************************
3384 * SECTION: Mozilla event initialization
3386 * Helpers for initializing moz events.
3388 **************************************************************/
3390 // Event intialization
3391 MSG nsWindow::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam)
3393 MSG msg;
3394 msg.message = aMessage;
3395 msg.wParam = wParam;
3396 msg.lParam = lParam;
3397 return msg;
3400 void nsWindow::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
3402 if (nsnull == aPoint) { // use the point from the event
3403 // get the message position in client coordinates
3404 if (mWnd != NULL) {
3406 DWORD pos = ::GetMessagePos();
3407 POINT cpos;
3409 cpos.x = GET_X_LPARAM(pos);
3410 cpos.y = GET_Y_LPARAM(pos);
3412 ::ScreenToClient(mWnd, &cpos);
3413 event.refPoint.x = cpos.x;
3414 event.refPoint.y = cpos.y;
3415 } else {
3416 event.refPoint.x = 0;
3417 event.refPoint.y = 0;
3420 else {
3421 // use the point override if provided
3422 event.refPoint.x = aPoint->x;
3423 event.refPoint.y = aPoint->y;
3426 #ifndef WINCE
3427 event.time = ::GetMessageTime();
3428 #else
3429 event.time = PR_Now() / 1000;
3430 #endif
3432 mLastPoint = event.refPoint;
3435 /**************************************************************
3437 * SECTION: Moz event dispatch helpers
3439 * Helpers for dispatching different types of moz events.
3441 **************************************************************/
3443 // Main event dispatch. Invokes callback and ProcessEvent method on
3444 // Event Listener object. Part of nsIWidget.
3445 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
3447 #ifdef WIDGET_DEBUG_OUTPUT
3448 debug_DumpEvent(stdout,
3449 event->widget,
3450 event,
3451 nsCAutoString("something"),
3452 (PRInt32) mWnd);
3453 #endif // WIDGET_DEBUG_OUTPUT
3455 aStatus = nsEventStatus_eIgnore;
3457 // skip processing of suppressed blur events
3458 if (event->message == NS_DEACTIVATE && BlurEventsSuppressed())
3459 return NS_OK;
3461 // Top level windows can have a view attached which requires events be sent
3462 // to the underlying base window and the view. Added when we combined the
3463 // base chrome window with the main content child for nc client area (title
3464 // bar) rendering.
3465 if (mViewCallback) {
3466 // A subset of events are sent to the base xul window first
3467 switch(event->message) {
3468 // send to the base window (view mgr ignores these for the view)
3469 case NS_UISTATECHANGED:
3470 case NS_DESTROY:
3471 case NS_SETZLEVEL:
3472 case NS_XUL_CLOSE:
3473 case NS_MOVE:
3474 (*mEventCallback)(event); // web shell / xul window
3475 return NS_OK;
3477 // sent to the base window, then to the view
3478 case NS_SIZE:
3479 case NS_DEACTIVATE:
3480 case NS_ACTIVATE:
3481 case NS_SIZEMODE:
3482 (*mEventCallback)(event); // web shell / xul window
3483 break;
3485 // attached view events
3486 aStatus = (*mViewCallback)(event);
3488 else if (mEventCallback) {
3489 aStatus = (*mEventCallback)(event);
3492 // the window can be destroyed during processing of seemingly innocuous events like, say,
3493 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3494 // which causes problems with the deleted window. therefore:
3495 if (mOnDestroyCalled)
3496 aStatus = nsEventStatus_eConsumeNoDefault;
3497 return NS_OK;
3500 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
3502 nsGUIEvent event(PR_TRUE, aMsg, this);
3503 InitEvent(event);
3505 PRBool result = DispatchWindowEvent(&event);
3506 return result;
3509 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
3511 nsEventStatus status;
3512 DispatchEvent(event, status);
3513 return ConvertStatus(status);
3516 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event, nsEventStatus &aStatus) {
3517 DispatchEvent(event, aStatus);
3518 return ConvertStatus(aStatus);
3521 PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
3522 const nsTArray<nsAlternativeCharCode>* aAlternativeCharCodes,
3523 UINT aVirtualCharCode, const MSG *aMsg,
3524 const nsModifierKeyState &aModKeyState,
3525 PRUint32 aFlags)
3527 UserActivity();
3529 nsKeyEvent event(PR_TRUE, aEventType, this);
3530 nsIntPoint point(0, 0);
3532 InitEvent(event, &point); // this add ref's event.widget
3534 event.flags |= aFlags;
3535 event.charCode = aCharCode;
3536 if (aAlternativeCharCodes)
3537 event.alternativeCharCodes.AppendElements(*aAlternativeCharCodes);
3538 event.keyCode = aVirtualCharCode;
3540 #ifdef KE_DEBUG
3541 static cnt=0;
3542 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt++,
3543 (NS_KEY_PRESS == aEventType) ? "PRESS" : (aEventType == NS_KEY_UP ? "Up" : "Down"),
3544 event.charCode, event.keyCode);
3545 printf("Shift: %s Control %s Alt: %s \n",
3546 (mIsShiftDown ? "D" : "U"), (mIsControlDown ? "D" : "U"), (mIsAltDown ? "D" : "U"));
3547 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3548 IS_VK_DOWN(NS_VK_SHIFT) ? 'S' : ' ',
3549 IS_VK_DOWN(NS_VK_CONTROL) ? 'C' : ' ',
3550 IS_VK_DOWN(NS_VK_ALT) ? 'A' : ' ',
3551 IS_VK_DOWN(VK_LSHIFT) ? 'S' : ' ',
3552 IS_VK_DOWN(VK_LCONTROL) ? 'C' : ' ',
3553 IS_VK_DOWN(VK_LMENU) ? 'A' : ' ',
3554 IS_VK_DOWN(VK_RMENU) ? 'A' : ' ',
3555 IS_VK_DOWN(VK_RCONTROL) ? 'C' : ' ',
3556 IS_VK_DOWN(VK_RSHIFT) ? 'S' : ' ');
3557 #endif
3559 event.isShift = aModKeyState.mIsShiftDown;
3560 event.isControl = aModKeyState.mIsControlDown;
3561 event.isMeta = PR_FALSE;
3562 event.isAlt = aModKeyState.mIsAltDown;
3564 NPEvent pluginEvent;
3565 if (aMsg && PluginHasFocus()) {
3566 pluginEvent.event = aMsg->message;
3567 pluginEvent.wParam = aMsg->wParam;
3568 pluginEvent.lParam = aMsg->lParam;
3569 event.pluginEvent = (void *)&pluginEvent;
3572 PRBool result = DispatchWindowEvent(&event);
3574 return result;
3577 PRBool nsWindow::DispatchCommandEvent(PRUint32 aEventCommand)
3579 nsCOMPtr<nsIAtom> command;
3580 switch (aEventCommand) {
3581 case APPCOMMAND_BROWSER_BACKWARD:
3582 command = nsWidgetAtoms::Back;
3583 break;
3584 case APPCOMMAND_BROWSER_FORWARD:
3585 command = nsWidgetAtoms::Forward;
3586 break;
3587 case APPCOMMAND_BROWSER_REFRESH:
3588 command = nsWidgetAtoms::Reload;
3589 break;
3590 case APPCOMMAND_BROWSER_STOP:
3591 command = nsWidgetAtoms::Stop;
3592 break;
3593 case APPCOMMAND_BROWSER_SEARCH:
3594 command = nsWidgetAtoms::Search;
3595 break;
3596 case APPCOMMAND_BROWSER_FAVORITES:
3597 command = nsWidgetAtoms::Bookmarks;
3598 break;
3599 case APPCOMMAND_BROWSER_HOME:
3600 command = nsWidgetAtoms::Home;
3601 break;
3602 default:
3603 return PR_FALSE;
3605 nsCommandEvent event(PR_TRUE, nsWidgetAtoms::onAppCommand, command, this);
3607 InitEvent(event);
3608 DispatchWindowEvent(&event);
3610 return PR_TRUE;
3613 // Recursively dispatch synchronous paints for nsIWidget
3614 // descendants with invalidated rectangles.
3615 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
3617 LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
3618 if (proc == (LONG_PTR)&nsWindow::WindowProc) {
3619 // its one of our windows so check to see if it has a
3620 // invalidated rect. If it does. Dispatch a synchronous
3621 // paint.
3622 if (GetUpdateRect(aWnd, NULL, FALSE))
3623 VERIFY(::UpdateWindow(aWnd));
3625 return TRUE;
3628 // Check for pending paints and dispatch any pending paint
3629 // messages for any nsIWidget which is a descendant of the
3630 // top-level window that *this* window is embedded within.
3632 // Note: We do not dispatch pending paint messages for non
3633 // nsIWidget managed windows.
3634 void nsWindow::DispatchPendingEvents()
3636 if (mPainting) {
3637 NS_WARNING("We were asked to dispatch pending events during painting, "
3638 "denying since that's unsafe.");
3639 return;
3642 // We need to ensure that reflow events do not get starved.
3643 // At the same time, we don't want to recurse through here
3644 // as that would prevent us from dispatching starved paints.
3645 static int recursionBlocker = 0;
3646 if (recursionBlocker++ == 0) {
3647 NS_ProcessPendingEvents(nsnull, PR_MillisecondsToInterval(100));
3648 --recursionBlocker;
3651 // Quickly check to see if there are any
3652 // paint events pending.
3653 if (::GetQueueStatus(QS_PAINT)) {
3654 // Find the top level window.
3655 HWND topWnd = GetTopLevelHWND(mWnd);
3657 // Dispatch pending paints for all topWnd's descendant windows.
3658 // Note: EnumChildWindows enumerates all descendant windows not just
3659 // it's children.
3660 #if !defined(WINCE)
3661 ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, 0);
3662 #else
3663 nsWindowCE::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3664 #endif
3668 // Deal with plugin events
3669 PRBool nsWindow::DispatchPluginEvent(const MSG &aMsg)
3671 if (!PluginHasFocus())
3672 return PR_FALSE;
3674 nsGUIEvent event(PR_TRUE, NS_PLUGIN_EVENT, this);
3675 nsIntPoint point(0, 0);
3676 InitEvent(event, &point);
3677 NPEvent pluginEvent;
3678 pluginEvent.event = aMsg.message;
3679 pluginEvent.wParam = aMsg.wParam;
3680 pluginEvent.lParam = aMsg.lParam;
3681 event.pluginEvent = (void *)&pluginEvent;
3682 return DispatchWindowEvent(&event);
3685 PRBool nsWindow::DispatchPluginEvent(UINT aMessage,
3686 WPARAM aWParam,
3687 LPARAM aLParam,
3688 PRBool aDispatchPendingEvents)
3690 PRBool ret = DispatchPluginEvent(InitMSG(aMessage, aWParam, aLParam));
3691 if (aDispatchPendingEvents) {
3692 DispatchPendingEvents();
3694 return ret;
3697 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
3698 UINT aLastMsg)
3700 MSG msg;
3701 ::GetMessageW(&msg, mWnd, aFirstMsg, aLastMsg);
3702 DispatchPluginEvent(msg);
3705 // Deal with all sort of mouse event
3706 PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
3707 LPARAM lParam, PRBool aIsContextMenuKey,
3708 PRInt16 aButton, PRUint16 aInputSource)
3710 PRBool result = PR_FALSE;
3712 UserActivity();
3714 if (!mEventCallback) {
3715 return result;
3718 switch (aEventType) {
3719 case NS_MOUSE_BUTTON_DOWN:
3720 CaptureMouse(PR_TRUE);
3721 break;
3723 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3724 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3725 case NS_MOUSE_BUTTON_UP:
3726 case NS_MOUSE_MOVE:
3727 case NS_MOUSE_EXIT:
3728 if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && mIsInMouseCapture)
3729 CaptureMouse(PR_FALSE);
3730 break;
3732 default:
3733 break;
3735 } // switch
3737 nsIntPoint eventPoint;
3738 eventPoint.x = GET_X_LPARAM(lParam);
3739 eventPoint.y = GET_Y_LPARAM(lParam);
3741 nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal,
3742 aIsContextMenuKey
3743 ? nsMouseEvent::eContextMenuKey
3744 : nsMouseEvent::eNormal);
3745 if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) {
3746 nsIntPoint zero(0, 0);
3747 InitEvent(event, &zero);
3748 } else {
3749 InitEvent(event, &eventPoint);
3752 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
3753 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
3754 event.isMeta = PR_FALSE;
3755 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
3756 event.button = aButton;
3757 event.inputSource = aInputSource;
3759 nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
3761 // Suppress mouse moves caused by widget creation
3762 if (aEventType == NS_MOUSE_MOVE)
3764 if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y))
3765 return result;
3766 sLastMouseMovePoint.x = mpScreen.x;
3767 sLastMouseMovePoint.y = mpScreen.y;
3770 PRBool insideMovementThreshold = (abs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
3771 (abs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
3773 BYTE eventButton;
3774 switch (aButton) {
3775 case nsMouseEvent::eLeftButton:
3776 eventButton = VK_LBUTTON;
3777 break;
3778 case nsMouseEvent::eMiddleButton:
3779 eventButton = VK_MBUTTON;
3780 break;
3781 case nsMouseEvent::eRightButton:
3782 eventButton = VK_RBUTTON;
3783 break;
3784 default:
3785 eventButton = 0;
3786 break;
3789 // Doubleclicks are used to set the click count, then changed to mousedowns
3790 // We're going to time double-clicks from mouse *up* to next mouse *down*
3791 #ifndef WINCE
3792 LONG curMsgTime = ::GetMessageTime();
3793 #else
3794 LONG curMsgTime = PR_Now() / 1000;
3795 #endif
3797 if (aEventType == NS_MOUSE_DOUBLECLICK) {
3798 event.message = NS_MOUSE_BUTTON_DOWN;
3799 event.button = aButton;
3800 sLastClickCount = 2;
3802 else if (aEventType == NS_MOUSE_BUTTON_UP) {
3803 // remember when this happened for the next mouse down
3804 sLastMousePoint.x = eventPoint.x;
3805 sLastMousePoint.y = eventPoint.y;
3806 sLastMouseButton = eventButton;
3808 else if (aEventType == NS_MOUSE_BUTTON_DOWN) {
3809 // now look to see if we want to convert this to a double- or triple-click
3810 if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold &&
3811 eventButton == sLastMouseButton) {
3812 sLastClickCount ++;
3813 } else {
3814 // reset the click count, to count *this* click
3815 sLastClickCount = 1;
3817 // Set last Click time on MouseDown only
3818 sLastMouseDownTime = curMsgTime;
3820 else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
3821 sLastClickCount = 0;
3823 else if (aEventType == NS_MOUSE_EXIT) {
3824 event.exit = IsTopLevelMouseExit(mWnd) ? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
3826 else if (aEventType == NS_MOUSE_MOZHITTEST)
3828 event.flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
3830 event.clickCount = sLastClickCount;
3832 #ifdef NS_DEBUG_XX
3833 printf("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount);
3834 #endif
3836 NPEvent pluginEvent;
3838 switch (aEventType)
3840 case NS_MOUSE_BUTTON_DOWN:
3841 switch (aButton) {
3842 case nsMouseEvent::eLeftButton:
3843 pluginEvent.event = WM_LBUTTONDOWN;
3844 break;
3845 case nsMouseEvent::eMiddleButton:
3846 pluginEvent.event = WM_MBUTTONDOWN;
3847 break;
3848 case nsMouseEvent::eRightButton:
3849 pluginEvent.event = WM_RBUTTONDOWN;
3850 break;
3851 default:
3852 break;
3854 break;
3855 case NS_MOUSE_BUTTON_UP:
3856 switch (aButton) {
3857 case nsMouseEvent::eLeftButton:
3858 pluginEvent.event = WM_LBUTTONUP;
3859 break;
3860 case nsMouseEvent::eMiddleButton:
3861 pluginEvent.event = WM_MBUTTONUP;
3862 break;
3863 case nsMouseEvent::eRightButton:
3864 pluginEvent.event = WM_RBUTTONUP;
3865 break;
3866 default:
3867 break;
3869 break;
3870 case NS_MOUSE_DOUBLECLICK:
3871 switch (aButton) {
3872 case nsMouseEvent::eLeftButton:
3873 pluginEvent.event = WM_LBUTTONDBLCLK;
3874 break;
3875 case nsMouseEvent::eMiddleButton:
3876 pluginEvent.event = WM_MBUTTONDBLCLK;
3877 break;
3878 case nsMouseEvent::eRightButton:
3879 pluginEvent.event = WM_RBUTTONDBLCLK;
3880 break;
3881 default:
3882 break;
3884 break;
3885 case NS_MOUSE_MOVE:
3886 pluginEvent.event = WM_MOUSEMOVE;
3887 break;
3888 case NS_MOUSE_EXIT:
3889 pluginEvent.event = WM_MOUSELEAVE;
3890 break;
3891 default:
3892 pluginEvent.event = WM_NULL;
3893 break;
3896 pluginEvent.wParam = wParam; // plugins NEED raw OS event flags!
3897 pluginEvent.lParam = lParam;
3899 event.pluginEvent = (void *)&pluginEvent;
3901 // call the event callback
3902 if (nsnull != mEventCallback) {
3903 if (nsToolkit::gMouseTrailer)
3904 nsToolkit::gMouseTrailer->Disable();
3905 if (aEventType == NS_MOUSE_MOVE) {
3906 if (nsToolkit::gMouseTrailer && !mIsInMouseCapture) {
3907 nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd);
3909 nsIntRect rect;
3910 GetBounds(rect);
3911 rect.x = 0;
3912 rect.y = 0;
3914 if (rect.Contains(event.refPoint)) {
3915 if (sCurrentWindow == NULL || sCurrentWindow != this) {
3916 if ((nsnull != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
3917 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3918 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, PR_FALSE,
3919 nsMouseEvent::eLeftButton, aInputSource);
3921 sCurrentWindow = this;
3922 if (!mInDtor) {
3923 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3924 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, PR_FALSE,
3925 nsMouseEvent::eLeftButton, aInputSource);
3929 } else if (aEventType == NS_MOUSE_EXIT) {
3930 if (sCurrentWindow == this) {
3931 sCurrentWindow = nsnull;
3935 result = DispatchWindowEvent(&event);
3937 if (nsToolkit::gMouseTrailer)
3938 nsToolkit::gMouseTrailer->Enable();
3940 // Release the widget with NS_IF_RELEASE() just in case
3941 // the context menu key code in nsEventListenerManager::HandleEvent()
3942 // released it already.
3943 return result;
3946 return result;
3949 // Deal with accessibile event
3950 #ifdef ACCESSIBILITY
3951 nsAccessible*
3952 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType)
3954 if (nsnull == mEventCallback) {
3955 return nsnull;
3958 nsAccessibleEvent event(PR_TRUE, aEventType, this);
3959 InitEvent(event, nsnull);
3961 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
3962 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
3963 event.isMeta = PR_FALSE;
3964 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
3966 DispatchWindowEvent(&event);
3968 return event.mAccessible;
3970 #endif
3972 PRBool nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType)
3974 if (aEventType == NS_ACTIVATE)
3975 sJustGotActivate = PR_FALSE;
3976 sJustGotDeactivate = PR_FALSE;
3978 // retrive the toplevel window or dialog
3979 HWND curWnd = mWnd;
3980 HWND toplevelWnd = NULL;
3981 while (curWnd) {
3982 toplevelWnd = curWnd;
3984 nsWindow *win = GetNSWindowPtr(curWnd);
3985 if (win) {
3986 nsWindowType wintype;
3987 win->GetWindowType(wintype);
3988 if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog)
3989 break;
3992 curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
3995 if (toplevelWnd) {
3996 nsWindow *win = GetNSWindowPtr(toplevelWnd);
3997 if (win)
3998 return win->DispatchFocus(aEventType);
4001 return PR_FALSE;
4004 // Deal with focus messages
4005 PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
4007 // call the event callback
4008 if (mEventCallback) {
4009 nsGUIEvent event(PR_TRUE, aEventType, this);
4010 InitEvent(event);
4012 //focus and blur event should go to their base widget loc, not current mouse pos
4013 event.refPoint.x = 0;
4014 event.refPoint.y = 0;
4016 NPEvent pluginEvent;
4018 switch (aEventType)
4020 case NS_ACTIVATE:
4021 pluginEvent.event = WM_SETFOCUS;
4022 break;
4023 case NS_DEACTIVATE:
4024 pluginEvent.event = WM_KILLFOCUS;
4025 break;
4026 case NS_PLUGIN_ACTIVATE:
4027 pluginEvent.event = WM_KILLFOCUS;
4028 break;
4029 default:
4030 break;
4033 event.pluginEvent = (void *)&pluginEvent;
4035 return DispatchWindowEvent(&event);
4037 return PR_FALSE;
4040 PRBool nsWindow::IsTopLevelMouseExit(HWND aWnd)
4042 DWORD pos = ::GetMessagePos();
4043 POINT mp;
4044 mp.x = GET_X_LPARAM(pos);
4045 mp.y = GET_Y_LPARAM(pos);
4046 HWND mouseWnd = ::WindowFromPoint(mp);
4048 // GetTopLevelHWND will return a HWND for the window frame (which includes
4049 // the non-client area). If the mouse has moved into the non-client area,
4050 // we should treat it as a top-level exit.
4051 HWND mouseTopLevel = nsWindow::GetTopLevelHWND(mouseWnd);
4052 if (mouseWnd == mouseTopLevel)
4053 return PR_TRUE;
4055 return nsWindow::GetTopLevelHWND(aWnd) != mouseTopLevel;
4058 PRBool nsWindow::BlurEventsSuppressed()
4060 // are they suppressed in this window?
4061 if (mBlurSuppressLevel > 0)
4062 return PR_TRUE;
4064 // are they suppressed by any container widget?
4065 HWND parentWnd = ::GetParent(mWnd);
4066 if (parentWnd) {
4067 nsWindow *parent = GetNSWindowPtr(parentWnd);
4068 if (parent)
4069 return parent->BlurEventsSuppressed();
4071 return PR_FALSE;
4074 // In some circumstances (opening dependent windows) it makes more sense
4075 // (and fixes a crash bug) to not blur the parent window. Called from
4076 // nsFilePicker.
4077 void nsWindow::SuppressBlurEvents(PRBool aSuppress)
4079 if (aSuppress)
4080 ++mBlurSuppressLevel; // for this widget
4081 else {
4082 NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression");
4083 if (mBlurSuppressLevel > 0)
4084 --mBlurSuppressLevel;
4088 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
4090 return aStatus == nsEventStatus_eConsumeNoDefault;
4093 /**************************************************************
4095 * SECTION: IPC
4097 * IPC related helpers.
4099 **************************************************************/
4101 #ifdef MOZ_IPC
4103 // static
4104 bool
4105 nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult)
4107 switch(aMsg) {
4108 case WM_SETFOCUS:
4109 case WM_KILLFOCUS:
4110 case WM_ENABLE:
4111 case WM_WINDOWPOSCHANGING:
4112 case WM_WINDOWPOSCHANGED:
4113 case WM_PARENTNOTIFY:
4114 case WM_ACTIVATEAPP:
4115 case WM_NCACTIVATE:
4116 case WM_ACTIVATE:
4117 case WM_CHILDACTIVATE:
4118 case WM_IME_SETCONTEXT:
4119 case WM_IME_NOTIFY:
4120 case WM_SHOWWINDOW:
4121 case WM_CANCELMODE:
4122 case WM_MOUSEACTIVATE:
4123 case WM_CONTEXTMENU:
4124 aResult = 0;
4125 return true;
4127 case WM_SETTINGCHANGE:
4128 case WM_SETCURSOR:
4129 return false;
4132 #ifdef DEBUG
4133 char szBuf[200];
4134 sprintf(szBuf,
4135 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg);
4136 NS_WARNING(szBuf);
4137 #endif
4139 return false;
4142 void
4143 nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
4145 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4146 "Failed to prevent a nonqueued message from running!");
4148 // Modal UI being displayed in windowless plugins.
4149 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4150 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4151 LRESULT res;
4152 if (IsAsyncResponseEvent(msg, res)) {
4153 ReplyMessage(res);
4155 return;
4158 // Handle certain sync plugin events sent to the parent which
4159 // trigger ipc calls that result in deadlocks.
4161 DWORD dwResult = 0;
4162 PRBool handled = PR_FALSE;
4164 switch(msg) {
4165 // Windowless flash sending WM_ACTIVATE events to the main window
4166 // via calls to ShowWindow.
4167 case WM_ACTIVATE:
4168 if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE &&
4169 IsWindow((HWND)lParam))
4170 handled = PR_TRUE;
4171 break;
4172 // Wheel events forwarded from the child.
4173 case WM_MOUSEWHEEL:
4174 case WM_MOUSEHWHEEL:
4175 case WM_HSCROLL:
4176 case WM_VSCROLL:
4177 // Plugins taking or losing focus triggering focus app messages.
4178 case WM_SETFOCUS:
4179 case WM_KILLFOCUS:
4180 // Windowed plugins that pass sys key events to defwndproc generate
4181 // WM_SYSCOMMAND events to the main window.
4182 case WM_SYSCOMMAND:
4183 // Windowed plugins that fire context menu selection events to parent
4184 // windows.
4185 case WM_CONTEXTMENU:
4186 // IME events fired as a result of synchronous focus changes
4187 case WM_IME_SETCONTEXT:
4188 handled = PR_TRUE;
4189 break;
4192 if (handled &&
4193 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4194 ReplyMessage(dwResult);
4198 #endif // MOZ_IPC
4200 /**************************************************************
4201 **************************************************************
4203 ** BLOCK: Native events
4205 ** Main Windows message handlers and OnXXX handlers for
4206 ** Windows event handling.
4208 **************************************************************
4209 **************************************************************/
4211 /**************************************************************
4213 * SECTION: Wind proc.
4215 * The main Windows event procedures and associated
4216 * message processing methods.
4218 **************************************************************/
4220 #ifdef _MSC_VER
4221 static int ReportException(EXCEPTION_POINTERS *aExceptionInfo)
4223 #ifdef MOZ_CRASHREPORTER
4224 nsCOMPtr<nsICrashReporter> cr =
4225 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
4226 if (cr)
4227 cr->WriteMinidumpForException(aExceptionInfo);
4228 #endif
4229 return EXCEPTION_EXECUTE_HANDLER;
4231 #endif
4233 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
4234 // exceptions and passes the real work to WindowProcInternal. See bug 587406
4235 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
4236 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4238 #ifdef _MSC_VER
4239 __try {
4240 return WindowProcInternal(hWnd, msg, wParam, lParam);
4242 __except(ReportException(GetExceptionInformation())) {
4243 ::TerminateProcess(::GetCurrentProcess(), 253);
4245 #else
4246 return WindowProcInternal(hWnd, msg, wParam, lParam);
4247 #endif
4250 LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4252 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4253 MOZ_FUNCTION_NAME, __LINE__, hWnd, msg,
4254 wParam, lParam);
4256 // Get the window which caused the event and ask it to process the message
4257 nsWindow *someWindow = GetNSWindowPtr(hWnd);
4259 #ifdef MOZ_IPC
4260 if (someWindow)
4261 someWindow->IPCWindowProcHandler(msg, wParam, lParam);
4262 #endif
4264 // create this here so that we store the last rolled up popup until after
4265 // the event has been processed.
4266 nsAutoRollup autoRollup;
4268 LRESULT popupHandlingResult;
4269 if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult))
4270 return popupHandlingResult;
4272 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4273 // why we are hitting this assert
4274 if (nsnull == someWindow) {
4275 NS_ASSERTION(someWindow, "someWindow is null, cannot call any CallWindowProc");
4276 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
4279 // hold on to the window for the life of this method, in case it gets
4280 // deleted during processing. yes, it's a double hack, since someWindow
4281 // is not really an interface.
4282 nsCOMPtr<nsISupports> kungFuDeathGrip;
4283 if (!someWindow->mInDtor) // not if we're in the destructor!
4284 kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)someWindow);
4286 // Call ProcessMessage
4287 LRESULT retValue;
4288 if (PR_TRUE == someWindow->ProcessMessage(msg, wParam, lParam, &retValue)) {
4289 return retValue;
4292 LRESULT res = ::CallWindowProcW(someWindow->GetPrevWindowProc(),
4293 hWnd, msg, wParam, lParam);
4295 return res;
4298 // The main windows message processing method for plugins.
4299 // The result means whether this method processed the native
4300 // event for plugin. If false, the native event should be
4301 // processed by the caller self.
4302 PRBool
4303 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
4304 LRESULT *aResult,
4305 PRBool &aCallDefWndProc)
4307 NS_PRECONDITION(aResult, "aResult must be non-null.");
4308 *aResult = 0;
4310 aCallDefWndProc = PR_FALSE;
4311 PRBool eventDispatched = PR_FALSE;
4312 switch (aMsg.message) {
4313 case WM_CHAR:
4314 case WM_SYSCHAR:
4315 *aResult = ProcessCharMessage(aMsg, &eventDispatched);
4316 break;
4318 case WM_KEYUP:
4319 case WM_SYSKEYUP:
4320 *aResult = ProcessKeyUpMessage(aMsg, &eventDispatched);
4321 break;
4323 case WM_KEYDOWN:
4324 case WM_SYSKEYDOWN:
4325 *aResult = ProcessKeyDownMessage(aMsg, &eventDispatched);
4326 break;
4328 case WM_DEADCHAR:
4329 case WM_SYSDEADCHAR:
4330 case WM_CONTEXTMENU:
4332 case WM_CUT:
4333 case WM_COPY:
4334 case WM_PASTE:
4335 case WM_CLEAR:
4336 case WM_UNDO:
4337 break;
4339 default:
4340 return PR_FALSE;
4343 if (!eventDispatched)
4344 aCallDefWndProc = !DispatchPluginEvent(aMsg);
4345 DispatchPendingEvents();
4346 return PR_TRUE;
4349 // The main windows message processing method.
4350 PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
4351 LRESULT *aRetValue)
4353 // (Large blocks of code should be broken out into OnEvent handlers.)
4354 if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
4355 return PR_TRUE;
4357 #if defined(EVENT_DEBUG_OUTPUT)
4358 // First param shows all events, second param indicates whether
4359 // to show mouse move events. See nsWindowDbg for details.
4360 PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
4361 #endif
4363 PRBool eatMessage;
4364 if (nsIMM32Handler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
4365 eatMessage)) {
4366 return mWnd ? eatMessage : PR_TRUE;
4369 if (PluginHasFocus()) {
4370 PRBool callDefaultWndProc;
4371 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4372 if (ProcessMessageForPlugin(nativeMsg, aRetValue, callDefaultWndProc)) {
4373 return mWnd ? !callDefaultWndProc : PR_TRUE;
4377 PRBool result = PR_FALSE; // call the default nsWindow proc
4378 *aRetValue = 0;
4380 static PRBool getWheelInfo = PR_TRUE;
4382 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4383 // Glass hit testing w/custom transparent margins
4384 LRESULT dwmHitResult;
4385 if (mCustomNonClient &&
4386 nsUXThemeData::CheckForCompositor() &&
4387 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) {
4388 *aRetValue = dwmHitResult;
4389 return PR_TRUE;
4391 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4393 switch (msg) {
4394 #ifndef WINCE
4395 // WM_QUERYENDSESSION must be handled by all windows.
4396 // Otherwise Windows thinks the window can just be killed at will.
4397 case WM_QUERYENDSESSION:
4398 if (sCanQuit == TRI_UNKNOWN)
4400 // Ask if it's ok to quit, and store the answer until we
4401 // get WM_ENDSESSION signaling the round is complete.
4402 nsCOMPtr<nsIObserverService> obsServ =
4403 mozilla::services::GetObserverService();
4404 nsCOMPtr<nsISupportsPRBool> cancelQuit =
4405 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
4406 cancelQuit->SetData(PR_FALSE);
4407 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
4409 PRBool abortQuit;
4410 cancelQuit->GetData(&abortQuit);
4411 sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
4413 *aRetValue = sCanQuit ? TRUE : FALSE;
4414 result = PR_TRUE;
4415 break;
4416 #endif
4418 #ifndef WINCE
4419 case WM_ENDSESSION:
4420 #endif
4421 case MOZ_WM_APP_QUIT:
4422 if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE))
4424 // Let's fake a shutdown sequence without actually closing windows etc.
4425 // to avoid Windows killing us in the middle. A proper shutdown would
4426 // require having a chance to pump some messages. Unfortunately
4427 // Windows won't let us do that. Bug 212316.
4428 nsCOMPtr<nsIObserverService> obsServ =
4429 mozilla::services::GetObserverService();
4430 NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
4431 obsServ->NotifyObservers(nsnull, "quit-application-granted", nsnull);
4432 obsServ->NotifyObservers(nsnull, "quit-application-forced", nsnull);
4433 obsServ->NotifyObservers(nsnull, "quit-application", nsnull);
4434 obsServ->NotifyObservers(nsnull, "profile-change-net-teardown", context.get());
4435 obsServ->NotifyObservers(nsnull, "profile-change-teardown", context.get());
4436 obsServ->NotifyObservers(nsnull, "profile-before-change", context.get());
4437 // Then a controlled but very quick exit.
4438 _exit(0);
4440 sCanQuit = TRI_UNKNOWN;
4441 result = PR_TRUE;
4442 break;
4444 #ifndef WINCE
4445 case WM_DISPLAYCHANGE:
4446 DispatchStandardEvent(NS_DISPLAYCHANGED);
4447 break;
4448 #endif
4450 case WM_SYSCOLORCHANGE:
4451 // Note: This is sent for child windows as well as top-level windows.
4452 // The Win32 toolkit normally only sends these events to top-level windows.
4453 // But we cycle through all of the childwindows and send it to them as well
4454 // so all presentations get notified properly.
4455 // See nsWindow::GlobalMsgWindowProc.
4456 DispatchStandardEvent(NS_SYSCOLORCHANGED);
4457 break;
4459 case WM_NOTIFY:
4460 // TAB change
4462 LPNMHDR pnmh = (LPNMHDR) lParam;
4464 switch (pnmh->code) {
4465 case TCN_SELCHANGE:
4467 DispatchStandardEvent(NS_TABCHANGE);
4468 result = PR_TRUE;
4470 break;
4473 break;
4475 case WM_XP_THEMECHANGED:
4477 // Update non-client margin offsets
4478 UpdateNonClientMargins();
4480 DispatchStandardEvent(NS_THEMECHANGED);
4482 // Invalidate the window so that the repaint will
4483 // pick up the new theme.
4484 Invalidate(PR_FALSE);
4486 break;
4488 case WM_FONTCHANGE:
4490 nsresult rv;
4491 PRBool didChange = PR_FALSE;
4493 // update the global font list
4494 nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
4495 if (NS_SUCCEEDED(rv)) {
4496 fontEnum->UpdateFontList(&didChange);
4497 //didChange is TRUE only if new font langGroup is added to the list.
4498 if (didChange) {
4499 // update device context font cache
4500 // Dirty but easiest way:
4501 // Changing nsIPrefBranch entry which triggers callbacks
4502 // and flows into calling mDeviceContext->FlushFontCache()
4503 // to update the font cache in all the instance of Browsers
4504 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
4505 if (prefs) {
4506 nsCOMPtr<nsIPrefBranch> fiPrefs;
4507 prefs->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs));
4508 if (fiPrefs) {
4509 PRBool fontInternalChange = PR_FALSE;
4510 fiPrefs->GetBoolPref("changed", &fontInternalChange);
4511 fiPrefs->SetBoolPref("changed", !fontInternalChange);
4515 } //if (NS_SUCCEEDED(rv))
4517 break;
4519 case WM_NCCALCSIZE:
4521 // If wParam is TRUE, it specifies that the application should indicate
4522 // which part of the client area contains valid information. The system
4523 // copies the valid information to the specified area within the new
4524 // client area. If the wParam parameter is FALSE, the application should
4525 // return zero.
4526 if (mCustomNonClient) {
4527 if (!wParam) {
4528 result = PR_TRUE;
4529 *aRetValue = 0;
4530 break;
4533 // before:
4534 // rgrc[0]: the proposed window
4535 // rgrc[1]: the current window
4536 // rgrc[2]: the source client area
4537 // pncsp->lppos: move/size data
4538 // after:
4539 // rgrc[0]: the new client area
4540 // rgrc[1]: the destination window
4541 // rgrc[2]: the source client area
4542 // (all values in screen coordiantes)
4543 NCCALCSIZE_PARAMS *pncsp = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
4544 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd, msg, wParam, lParam);
4545 pncsp->rgrc[0].top -= mNonClientOffset.top;
4546 pncsp->rgrc[0].left -= mNonClientOffset.left;
4547 pncsp->rgrc[0].right += mNonClientOffset.right;
4548 pncsp->rgrc[0].bottom += mNonClientOffset.bottom;
4550 result = PR_TRUE;
4551 *aRetValue = res;
4553 break;
4556 case WM_NCHITTEST:
4559 * If an nc client area margin has been moved, we are responsible
4560 * for calculating where the resize margins are and returning the
4561 * appropriate set of hit test constants. DwmDefWindowProc (above)
4562 * will handle hit testing on it's command buttons if we are on a
4563 * composited desktop.
4566 if (!mCustomNonClient)
4567 break;
4569 *aRetValue =
4570 ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
4571 result = PR_TRUE;
4572 break;
4575 case WM_SETTEXT:
4577 * WM_SETTEXT paints the titlebar area. Avoid this if we have a
4578 * custom titlebar we paint ourselves.
4581 if (!mCustomNonClient || mNonClientMargins.top == -1)
4582 break;
4585 // From msdn, the way around this is to disable the visible state
4586 // temporarily. We need the text to be set but we don't want the
4587 // redraw to occur.
4588 DWORD style = GetWindowLong(mWnd, GWL_STYLE);
4589 SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
4590 *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd,
4591 msg, wParam, lParam);
4592 SetWindowLong(mWnd, GWL_STYLE, style);
4593 return PR_TRUE;
4596 case WM_NCACTIVATE:
4599 * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
4600 * through WM_NCPAINT via InvalidateNonClientRegion.
4603 if (!mCustomNonClient)
4604 break;
4606 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4607 // let the dwm handle nc painting on glass
4608 if(nsUXThemeData::CheckForCompositor())
4609 break;
4610 #endif
4612 if (wParam == TRUE) {
4613 // going active
4614 *aRetValue = FALSE; // ignored
4615 result = PR_TRUE;
4616 // invalidate to trigger a paint
4617 InvalidateNonClientRegion();
4618 break;
4619 } else {
4620 // going inactive
4621 *aRetValue = TRUE; // go ahead and deactive
4622 result = PR_TRUE;
4623 // invalidate to trigger a paint
4624 InvalidateNonClientRegion();
4625 break;
4629 case WM_NCPAINT:
4632 * Reset the non-client paint region so that it excludes the
4633 * non-client areas we paint manually. Then call defwndproc
4634 * to do the actual painting.
4637 if (!mCustomNonClient)
4638 break;
4640 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4641 // let the dwm handle nc painting on glass
4642 if(nsUXThemeData::CheckForCompositor())
4643 break;
4644 #endif
4646 HRGN paintRgn = ExcludeNonClientFromPaintRegion((HRGN)wParam);
4647 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd,
4648 msg, (WPARAM)paintRgn, lParam);
4649 if (paintRgn != (HRGN)wParam)
4650 DeleteObject(paintRgn);
4651 *aRetValue = res;
4652 result = PR_TRUE;
4654 break;
4656 #ifndef WINCE
4657 case WM_POWERBROADCAST:
4658 // only hidden window handle this
4659 // to prevent duplicate notification
4660 if (mWindowType == eWindowType_invisible) {
4661 switch (wParam)
4663 case PBT_APMSUSPEND:
4664 PostSleepWakeNotification("sleep_notification");
4665 break;
4666 case PBT_APMRESUMEAUTOMATIC:
4667 case PBT_APMRESUMECRITICAL:
4668 case PBT_APMRESUMESUSPEND:
4669 PostSleepWakeNotification("wake_notification");
4670 break;
4673 break;
4674 #endif
4676 case WM_MOVE: // Window moved
4678 RECT rect;
4679 ::GetWindowRect(mWnd, &rect);
4680 result = OnMove(rect.left, rect.top);
4682 break;
4684 case WM_CLOSE: // close request
4685 DispatchStandardEvent(NS_XUL_CLOSE);
4686 result = PR_TRUE; // abort window closure
4687 break;
4689 case WM_DESTROY:
4690 // clean up.
4691 OnDestroy();
4692 result = PR_TRUE;
4693 break;
4695 case WM_PAINT:
4696 *aRetValue = (int) OnPaint(NULL, 0);
4697 result = PR_TRUE;
4698 break;
4700 #ifndef WINCE
4701 case WM_PRINTCLIENT:
4702 result = OnPaint((HDC) wParam, 0);
4703 break;
4704 #endif
4706 case WM_HOTKEY:
4707 result = OnHotKey(wParam, lParam);
4708 break;
4710 case WM_SYSCHAR:
4711 case WM_CHAR:
4713 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4714 result = ProcessCharMessage(nativeMsg, nsnull);
4715 DispatchPendingEvents();
4717 break;
4719 case WM_SYSKEYUP:
4720 case WM_KEYUP:
4722 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4723 result = ProcessKeyUpMessage(nativeMsg, nsnull);
4724 DispatchPendingEvents();
4726 break;
4728 case WM_SYSKEYDOWN:
4729 case WM_KEYDOWN:
4731 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4732 result = ProcessKeyDownMessage(nativeMsg, nsnull);
4733 DispatchPendingEvents();
4735 break;
4737 // say we've dealt with erase background if widget does
4738 // not need auto-erasing
4739 case WM_ERASEBKGND:
4740 if (!AutoErase((HDC)wParam)) {
4741 *aRetValue = 1;
4742 result = PR_TRUE;
4744 break;
4746 case WM_MOUSEMOVE:
4748 #ifdef WINCE_WINDOWS_MOBILE
4749 // Reset the kill timer so that we can continue at this
4750 // priority
4751 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2seconds */, NULL);
4752 #endif
4753 // Suppress dispatch of pending events
4754 // when mouse moves are generated by widget
4755 // creation instead of user input.
4756 LPARAM lParamScreen = lParamToScreen(lParam);
4757 POINT mp;
4758 mp.x = GET_X_LPARAM(lParamScreen);
4759 mp.y = GET_Y_LPARAM(lParamScreen);
4760 PRBool userMovedMouse = PR_FALSE;
4761 if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) {
4762 userMovedMouse = PR_TRUE;
4764 mExitToNonClientArea = PR_FALSE;
4766 result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam,
4767 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4768 if (userMovedMouse) {
4769 DispatchPendingEvents();
4772 break;
4774 #ifdef WINCE_WINDOWS_MOBILE
4775 case WM_TIMER:
4776 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4777 KillTimer(mWnd, KILL_PRIORITY_ID);
4778 break;
4779 #endif
4781 case WM_LBUTTONDOWN:
4783 #ifdef WINCE_WINDOWS_MOBILE
4784 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
4785 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2 seconds */, NULL);
4786 #endif
4787 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
4788 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4789 DispatchPendingEvents();
4791 break;
4793 case WM_LBUTTONUP:
4795 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam,
4796 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4797 DispatchPendingEvents();
4799 #ifdef WINCE_WINDOWS_MOBILE
4800 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4801 KillTimer(mWnd, KILL_PRIORITY_ID);
4802 #endif
4804 break;
4806 #ifndef WINCE
4807 case WM_MOUSELEAVE:
4809 // We need to check mouse button states and put them in for
4810 // wParam.
4811 WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
4812 | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
4813 | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
4814 // Synthesize an event position because we don't get one from
4815 // WM_MOUSELEAVE.
4816 LPARAM pos = lParamToClient(::GetMessagePos());
4817 DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, PR_FALSE,
4818 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4820 break;
4821 #endif
4823 case WM_CONTEXTMENU:
4825 // if the context menu is brought up from the keyboard, |lParam|
4826 // will be -1.
4827 LPARAM pos;
4828 PRBool contextMenukey = PR_FALSE;
4829 if (lParam == -1)
4831 contextMenukey = PR_TRUE;
4832 pos = lParamToClient(GetMessagePos());
4834 else
4836 pos = lParamToClient(lParam);
4839 result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey,
4840 contextMenukey ?
4841 nsMouseEvent::eLeftButton :
4842 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4844 break;
4846 case WM_LBUTTONDBLCLK:
4847 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4848 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4849 break;
4851 case WM_MBUTTONDOWN:
4853 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4854 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4855 DispatchPendingEvents();
4857 break;
4859 case WM_MBUTTONUP:
4860 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4861 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4862 DispatchPendingEvents();
4863 break;
4865 case WM_MBUTTONDBLCLK:
4866 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4867 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4868 break;
4870 case WM_RBUTTONDOWN:
4872 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4873 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4874 DispatchPendingEvents();
4876 break;
4878 case WM_RBUTTONUP:
4879 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4880 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4881 DispatchPendingEvents();
4882 break;
4884 case WM_RBUTTONDBLCLK:
4885 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4886 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4887 break;
4889 case WM_NCRBUTTONDOWN:
4890 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam),
4891 PR_FALSE, nsMouseEvent::eRightButton,
4892 MOUSE_INPUT_SOURCE());
4893 DispatchPendingEvents();
4894 break;
4896 case WM_NCRBUTTONUP:
4897 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam),
4898 PR_FALSE, nsMouseEvent::eRightButton,
4899 MOUSE_INPUT_SOURCE());
4900 DispatchPendingEvents();
4901 break;
4903 case WM_NCRBUTTONDBLCLK:
4904 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam),
4905 PR_FALSE, nsMouseEvent::eRightButton,
4906 MOUSE_INPUT_SOURCE());
4908 case WM_APPCOMMAND:
4910 PRUint32 appCommand = GET_APPCOMMAND_LPARAM(lParam);
4912 switch (appCommand)
4914 case APPCOMMAND_BROWSER_BACKWARD:
4915 case APPCOMMAND_BROWSER_FORWARD:
4916 case APPCOMMAND_BROWSER_REFRESH:
4917 case APPCOMMAND_BROWSER_STOP:
4918 case APPCOMMAND_BROWSER_SEARCH:
4919 case APPCOMMAND_BROWSER_FAVORITES:
4920 case APPCOMMAND_BROWSER_HOME:
4921 DispatchCommandEvent(appCommand);
4922 // tell the driver that we handled the event
4923 *aRetValue = 1;
4924 result = PR_TRUE;
4925 break;
4927 // default = PR_FALSE - tell the driver that the event was not handled
4929 break;
4931 case WM_HSCROLL:
4932 case WM_VSCROLL:
4933 *aRetValue = 0;
4934 result = OnScroll(msg, wParam, lParam);
4935 break;
4937 // The WM_ACTIVATE event is fired when a window is raised or lowered,
4938 // and the loword of wParam specifies which. But we don't want to tell
4939 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
4940 // events are fired. Instead, set either the sJustGotActivate or
4941 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
4942 // events once the focus events arrive.
4943 case WM_ACTIVATE:
4944 if (mEventCallback) {
4945 PRInt32 fActive = LOWORD(wParam);
4947 #if defined(WINCE_HAVE_SOFTKB)
4948 if (mIsTopWidgetWindow && sSoftKeyboardState)
4949 nsWindowCE::ToggleSoftKB(mWnd, fActive);
4950 if (nsWindowCE::sShowSIPButton == TRI_FALSE && WA_INACTIVE != fActive) {
4951 HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL );
4952 if (hWndSIPB)
4953 ShowWindow(hWndSIPB, SW_HIDE);
4956 #endif
4958 if (WA_INACTIVE == fActive) {
4959 // when minimizing a window, the deactivation and focus events will
4960 // be fired in the reverse order. Instead, just dispatch
4961 // NS_DEACTIVATE right away.
4962 if (HIWORD(wParam))
4963 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
4964 else
4965 sJustGotDeactivate = PR_TRUE;
4966 #ifndef WINCE
4967 if (mIsTopWidgetWindow)
4968 mLastKeyboardLayout = gKbdLayout.GetLayout();
4969 #endif
4971 } else {
4972 StopFlashing();
4974 sJustGotActivate = PR_TRUE;
4975 nsMouseEvent event(PR_TRUE, NS_MOUSE_ACTIVATE, this,
4976 nsMouseEvent::eReal);
4977 InitEvent(event);
4979 event.acceptActivation = PR_TRUE;
4981 DispatchWindowEvent(&event);
4982 #ifndef WINCE
4983 if (event.acceptActivation)
4984 *aRetValue = MA_ACTIVATE;
4985 else
4986 *aRetValue = MA_NOACTIVATE;
4988 if (sSwitchKeyboardLayout && mLastKeyboardLayout)
4989 ActivateKeyboardLayout(mLastKeyboardLayout, 0);
4990 #else
4991 *aRetValue = 0;
4992 #endif
4995 #ifdef WINCE_WINDOWS_MOBILE
4996 if (!gCheckForHTCApi && gHTCApiNavOpen == nsnull) {
4997 gCheckForHTCApi = PR_TRUE;
4999 HINSTANCE library = LoadLibrary(L"HTCAPI.dll");
5000 gHTCApiNavOpen = (HTCApiNavOpen) GetProcAddress(library, "HTCNavOpen");
5001 gHTCApiNavSetMode = (HTCApiNavSetMode) GetProcAddress(library ,"HTCNavSetMode");
5004 if (gHTCApiNavOpen != nsnull) {
5005 gHTCApiNavOpen(mWnd, 1 /* undocumented value */);
5007 if (gHTCApiNavSetMode != nsnull)
5008 gHTCApiNavSetMode ( mWnd, 4);
5009 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5011 #endif
5012 break;
5014 #ifndef WINCE
5015 case WM_MOUSEACTIVATE:
5016 if (mWindowType == eWindowType_popup) {
5017 // a popup with a parent owner should not be activated when clicked
5018 // but should still allow the mouse event to be fired, so the return
5019 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5020 // window, just use default processing so that the window is activated.
5021 HWND owner = ::GetWindow(mWnd, GW_OWNER);
5022 if (owner && owner == ::GetForegroundWindow()) {
5023 *aRetValue = MA_NOACTIVATE;
5024 result = PR_TRUE;
5027 break;
5029 case WM_WINDOWPOSCHANGING:
5031 LPWINDOWPOS info = (LPWINDOWPOS) lParam;
5032 OnWindowPosChanging(info);
5034 break;
5035 #endif
5037 case WM_SETFOCUS:
5038 if (sJustGotActivate) {
5039 result = DispatchFocusToTopLevelWindow(NS_ACTIVATE);
5042 #ifdef ACCESSIBILITY
5043 if (nsWindow::sIsAccessibilityOn) {
5044 // Create it for the first time so that it can start firing events
5045 nsAccessible *rootAccessible = GetRootAccessible();
5047 #endif
5049 #if defined(WINCE_HAVE_SOFTKB)
5051 // On Windows CE, we have a window that overlaps
5052 // the ISP button. In this case, we should always
5053 // try to hide it when we are activated
5055 nsIMEContext IMEContext(mWnd);
5056 // Open the IME
5057 ImmSetOpenStatus(IMEContext.get(), TRUE);
5059 #endif
5060 break;
5062 case WM_KILLFOCUS:
5063 #if defined(WINCE_HAVE_SOFTKB)
5065 nsIMEContext IMEContext(mWnd);
5066 ImmSetOpenStatus(IMEContext.get(), FALSE);
5068 #endif
5069 if (sJustGotDeactivate) {
5070 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5072 break;
5074 case WM_WINDOWPOSCHANGED:
5076 WINDOWPOS *wp = (LPWINDOWPOS)lParam;
5077 OnWindowPosChanged(wp, result);
5079 break;
5081 case WM_SETTINGCHANGE:
5082 #if !defined (WINCE_WINDOWS_MOBILE)
5083 getWheelInfo = PR_TRUE;
5084 #else
5085 switch (wParam) {
5086 case SPI_SETSIPINFO:
5087 case SPI_SETCURRENTIM:
5088 nsWindowCE::OnSoftKbSettingsChange(mWnd);
5089 break;
5090 case SETTINGCHANGE_RESET:
5091 if (mWindowType == eWindowType_invisible) {
5092 // The OS sees to get confused and think that the invisable window
5093 // is in the foreground after an orientation change. By actually
5094 // setting it to the foreground and hiding it, we set it strait.
5095 // See bug 514007 for details.
5096 SetForegroundWindow(mWnd);
5097 ShowWindow(mWnd, SW_HIDE);
5099 break;
5101 #endif
5102 OnSettingsChange(wParam, lParam);
5103 break;
5105 #ifndef WINCE
5106 case WM_INPUTLANGCHANGEREQUEST:
5107 *aRetValue = TRUE;
5108 result = PR_FALSE;
5109 break;
5111 case WM_INPUTLANGCHANGE:
5112 result = OnInputLangChange((HKL)lParam);
5113 break;
5114 #endif // WINCE
5116 case WM_DESTROYCLIPBOARD:
5118 nsIClipboard* clipboard;
5119 nsresult rv = CallGetService(kCClipboardCID, &clipboard);
5120 if(NS_SUCCEEDED(rv)) {
5121 clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
5122 NS_RELEASE(clipboard);
5125 break;
5127 #ifdef ACCESSIBILITY
5128 case WM_GETOBJECT:
5130 *aRetValue = 0;
5131 if (lParam == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
5132 nsAccessible *rootAccessible = GetRootAccessible(); // Held by a11y cache
5133 if (rootAccessible) {
5134 IAccessible *msaaAccessible = NULL;
5135 rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref
5136 if (msaaAccessible) {
5137 *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref
5138 msaaAccessible->Release(); // release extra addref
5139 result = PR_TRUE; // We handled the WM_GETOBJECT message
5144 #endif
5146 #ifndef WINCE
5147 case WM_SYSCOMMAND:
5148 // prevent Windows from trimming the working set. bug 76831
5149 if (!sTrimOnMinimize && wParam == SC_MINIMIZE) {
5150 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
5151 result = PR_TRUE;
5153 break;
5154 #endif
5157 #ifdef WINCE
5158 case WM_HIBERNATE:
5159 nsMemory::HeapMinimize(PR_TRUE);
5160 break;
5161 #endif
5163 case WM_MOUSEWHEEL:
5164 case WM_MOUSEHWHEEL:
5166 // If OnMouseWheel returns true, the event was forwarded directly to another
5167 // mozilla window message handler (ProcessMessage). In this case the return
5168 // value of the forwarded event is in 'result' which we should return immediately.
5169 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5170 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5171 // we should fall through.
5172 if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue))
5173 return result;
5175 break;
5177 #ifndef WINCE
5178 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5179 case WM_DWMCOMPOSITIONCHANGED:
5180 UpdateNonClientMargins();
5181 BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
5182 DispatchStandardEvent(NS_THEMECHANGED);
5183 UpdateGlass();
5184 Invalidate(PR_FALSE);
5185 break;
5186 #endif
5188 case WM_UPDATEUISTATE:
5190 // If the UI state has changed, fire an event so the UI updates the
5191 // keyboard cues based on the system setting and how the window was
5192 // opened. For example, a dialog opened via a keyboard press on a button
5193 // should enable cues, whereas the same dialog opened via a mouse click of
5194 // the button should not.
5195 PRInt32 action = LOWORD(wParam);
5196 if (action == UIS_SET || action == UIS_CLEAR) {
5197 nsUIStateChangeEvent event(PR_TRUE, NS_UISTATECHANGED, this);
5198 PRInt32 flags = HIWORD(wParam);
5199 if (flags & UISF_HIDEACCEL)
5200 event.showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5201 if (flags & UISF_HIDEFOCUS)
5202 event.showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5203 DispatchWindowEvent(&event);
5206 break;
5209 /* Gesture support events */
5210 case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
5211 // According to MS samples, this must be handled to enable
5212 // rotational support in multi-touch drivers.
5213 result = PR_TRUE;
5214 *aRetValue = TABLET_ROTATE_GESTURE_ENABLE;
5215 break;
5217 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5218 case WM_TOUCH:
5219 result = OnTouch(wParam, lParam);
5220 if (result) {
5221 *aRetValue = 0;
5223 break;
5224 #endif
5226 case WM_GESTURE:
5227 result = OnGesture(wParam, lParam);
5228 break;
5230 case WM_GESTURENOTIFY:
5232 if (mWindowType != eWindowType_invisible &&
5233 mWindowType != eWindowType_plugin &&
5234 mWindowType != eWindowType_toplevel) {
5235 // eWindowType_toplevel is the top level main frame window. Gesture support
5236 // there prevents the user from interacting with the title bar or nc
5237 // areas using a single finger. Java and plugin windows can make their
5238 // own calls.
5239 GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
5240 nsPointWin touchPoint;
5241 touchPoint = gestureinfo->ptsLocation;
5242 touchPoint.ScreenToClient(mWnd);
5243 nsGestureNotifyEvent gestureNotifyEvent(PR_TRUE, NS_GESTURENOTIFY_EVENT_START, this);
5244 gestureNotifyEvent.refPoint = touchPoint;
5245 nsEventStatus status;
5246 DispatchEvent(&gestureNotifyEvent, status);
5247 mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
5248 if (!mTouchWindow)
5249 mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
5251 result = PR_FALSE; //should always bubble to DefWindowProc
5253 break;
5254 #endif // !defined(WINCE)
5256 case WM_CLEAR:
5258 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_DELETE, this);
5259 DispatchWindowEvent(&command);
5260 result = PR_TRUE;
5262 break;
5264 case WM_CUT:
5266 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_CUT, this);
5267 DispatchWindowEvent(&command);
5268 result = PR_TRUE;
5270 break;
5272 case WM_COPY:
5274 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_COPY, this);
5275 DispatchWindowEvent(&command);
5276 result = PR_TRUE;
5278 break;
5280 case WM_PASTE:
5282 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE, this);
5283 DispatchWindowEvent(&command);
5284 result = PR_TRUE;
5286 break;
5288 #ifndef WINCE
5289 case EM_UNDO:
5291 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO, this);
5292 DispatchWindowEvent(&command);
5293 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5294 result = PR_TRUE;
5296 break;
5298 case EM_REDO:
5300 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO, this);
5301 DispatchWindowEvent(&command);
5302 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5303 result = PR_TRUE;
5305 break;
5307 case EM_CANPASTE:
5309 // Support EM_CANPASTE message only when wParam isn't specified or
5310 // is plain text format.
5311 if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
5312 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE,
5313 this, PR_TRUE);
5314 DispatchWindowEvent(&command);
5315 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5316 result = PR_TRUE;
5319 break;
5321 case EM_CANUNDO:
5323 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO,
5324 this, PR_TRUE);
5325 DispatchWindowEvent(&command);
5326 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5327 result = PR_TRUE;
5329 break;
5331 case EM_CANREDO:
5333 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO,
5334 this, PR_TRUE);
5335 DispatchWindowEvent(&command);
5336 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5337 result = PR_TRUE;
5339 break;
5340 #endif
5342 #ifdef WINCE_WINDOWS_MOBILE
5343 //HTC NAVIGATION WHEEL EVENT
5344 case WM_HTCNAV:
5346 int distance = wParam & 0x000000FF;
5347 if ( (wParam & 0x000000100) != 0) // Counter Clockwise
5348 distance *= -1;
5349 if (OnMouseWheel(WM_MOUSEWHEEL, MAKEWPARAM(0, distance),
5350 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN) / 2,
5351 GetSystemMetrics(SM_CYSCREEN) / 2),
5352 getWheelInfo, result, aRetValue))
5353 return result;
5355 break;
5356 #endif
5358 default:
5360 #ifdef NS_ENABLE_TSF
5361 if (msg == WM_USER_TSF_TEXTCHANGE) {
5362 nsTextStore::OnTextChangeMsg();
5364 #endif //NS_ENABLE_TSF
5365 #if defined(HEAP_DUMP_EVENT)
5366 if (msg == GetHeapMsg()) {
5367 HeapDump(msg, wParam, lParam);
5368 result = PR_TRUE;
5370 #endif
5371 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5372 if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
5373 SetHasTaskbarIconBeenCreated();
5374 #endif
5375 #ifdef MOZ_IPC
5376 if (msg == sOOPPPluginFocusEvent) {
5377 if (wParam == 1) {
5378 // With OOPP, the plugin window exists in another process and is a child of
5379 // this window. This window is a placeholder plugin window for the dom. We
5380 // receive this event when the child window receives focus. (sent from
5381 // PluginInstanceParent.cpp)
5382 ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
5383 } else {
5384 // WM_KILLFOCUS was received by the child process.
5385 if (sJustGotDeactivate) {
5386 DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5390 #endif
5392 break;
5395 //*aRetValue = result;
5396 if (mWnd) {
5397 return result;
5399 else {
5400 //Events which caused mWnd destruction and aren't consumed
5401 //will crash during the Windows default processing.
5402 return PR_TRUE;
5406 /**************************************************************
5408 * SECTION: Broadcast messaging
5410 * Broadcast messages to all windows.
5412 **************************************************************/
5414 // Enumerate all child windows sending aMsg to each of them
5415 BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg)
5417 WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
5418 if (winProc == &nsWindow::WindowProc) {
5419 // it's one of our windows so go ahead and send a message to it
5420 ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0);
5422 return TRUE;
5425 // Enumerate all top level windows specifying that the children of each
5426 // top level window should be enumerated. Do *not* send the message to
5427 // each top level window since it is assumed that the toolkit will send
5428 // aMsg to them directly.
5429 BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg)
5431 // Iterate each of aTopWindows child windows sending the aMsg
5432 // to each of them.
5433 #if !defined(WINCE)
5434 ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5435 #else
5436 nsWindowCE::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5437 #endif
5438 return TRUE;
5441 // This method is called from nsToolkit::WindowProc to forward global
5442 // messages which need to be dispatched to all child windows.
5443 void nsWindow::GlobalMsgWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
5445 switch (msg) {
5446 case WM_SYSCOLORCHANGE:
5447 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5448 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5449 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5450 // all child windows as well. When running in an embedded application
5451 // we may not receive a WM_SYSCOLORCHANGE message because the top
5452 // level window is owned by the embeddor.
5453 // System color changes are posted to top-level windows only.
5454 // The NS_SYSCOLORCHANGE must be dispatched to all child
5455 // windows as well.
5456 #if !defined(WINCE)
5457 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, msg);
5458 #endif
5459 break;
5463 /**************************************************************
5465 * SECTION: Event processing helpers
5467 * Special processing for certain event types and
5468 * synthesized events.
5470 **************************************************************/
5472 PRInt32
5473 nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
5475 // Calculations are done in screen coords
5476 RECT winRect;
5477 GetWindowRect(mWnd, &winRect);
5479 // hit return constants:
5480 // HTBORDER - non-resizable border
5481 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5482 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5483 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5484 // HTCAPTION - general title bar area
5485 // HTCLIENT - area considered the client
5486 // HTCLOSE - hovering over the close button
5487 // HTMAXBUTTON - maximize button
5488 // HTMINBUTTON - minimize button
5490 PRInt32 testResult = HTCLIENT;
5492 PRBool top = PR_FALSE;
5493 PRBool bottom = PR_FALSE;
5494 PRBool left = PR_FALSE;
5495 PRBool right = PR_FALSE;
5497 if (my >= winRect.top && my <=
5498 (winRect.top + mVertResizeMargin + (mCaptionHeight - mNonClientOffset.top)))
5499 top = PR_TRUE;
5500 else if (my <= winRect.bottom && my >= (winRect.bottom - mVertResizeMargin))
5501 bottom = PR_TRUE;
5503 if (mx >= winRect.left && mx <= (winRect.left + mHorResizeMargin))
5504 left = PR_TRUE;
5505 else if (mx <= winRect.right && mx >= (winRect.right - mHorResizeMargin))
5506 right = PR_TRUE;
5508 if (top) {
5509 testResult = HTTOP;
5510 if (left)
5511 testResult = HTTOPLEFT;
5512 else if (right)
5513 testResult = HTTOPRIGHT;
5514 } else if (bottom) {
5515 testResult = HTBOTTOM;
5516 if (left)
5517 testResult = HTBOTTOMLEFT;
5518 else if (right)
5519 testResult = HTBOTTOMRIGHT;
5520 } else {
5521 if (left)
5522 testResult = HTLEFT;
5523 if (right)
5524 testResult = HTRIGHT;
5527 PRBool contentOverlap = PR_TRUE;
5529 if (mSizeMode == nsSizeMode_Maximized) {
5530 // There's no HTTOP in maximized state (bug 575493)
5531 if (testResult == HTTOP) {
5532 testResult = HTCAPTION;
5534 } else {
5535 PRInt32 leftMargin = mNonClientMargins.left == -1 ? mHorResizeMargin : mNonClientMargins.left;
5536 PRInt32 rightMargin = mNonClientMargins.right == -1 ? mHorResizeMargin : mNonClientMargins.right;
5537 PRInt32 topMargin = mNonClientMargins.top == -1 ? mVertResizeMargin : mNonClientMargins.top;
5538 PRInt32 bottomMargin = mNonClientMargins.bottom == -1 ? mVertResizeMargin : mNonClientMargins.bottom;
5540 contentOverlap = mx >= winRect.left + leftMargin &&
5541 mx <= winRect.right - rightMargin &&
5542 my >= winRect.top + topMargin &&
5543 my <= winRect.bottom - bottomMargin;
5546 if (!mIsInMouseCapture &&
5547 contentOverlap &&
5548 (testResult == HTCLIENT ||
5549 testResult == HTTOP ||
5550 testResult == HTTOPLEFT ||
5551 testResult == HTCAPTION)) {
5552 LPARAM lParam = MAKELPARAM(mx, my);
5553 LPARAM lParamClient = lParamToClient(lParam);
5554 PRBool result = DispatchMouseEvent(NS_MOUSE_MOZHITTEST, 0, lParamClient,
5555 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5556 if (result) {
5557 // The mouse is over a blank area
5558 testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
5560 if (!mExitToNonClientArea) {
5561 // The first time the mouse pointer goes from client area to non-client area,
5562 // we don't want to miss that movement so we can interpret mouseout input.
5563 ::SendMessage(mWnd, WM_MOUSEMOVE, 0, lParamClient);
5564 mExitToNonClientArea = PR_TRUE;
5566 } else {
5567 // There's content over the mouse pointer. Set HTCLIENT
5568 // to possibly override a resizer border.
5569 testResult = HTCLIENT;
5573 return testResult;
5577 #ifndef WINCE
5578 void nsWindow::PostSleepWakeNotification(const char* aNotification)
5580 nsCOMPtr<nsIObserverService> observerService =
5581 mozilla::services::GetObserverService();
5582 if (observerService)
5583 observerService->NotifyObservers(nsnull, aNotification, nsnull);
5585 #endif
5587 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, PRBool *aEventDispatched)
5589 NS_PRECONDITION(aMsg.message == WM_CHAR || aMsg.message == WM_SYSCHAR,
5590 "message is not keydown event");
5591 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5592 ("%s charCode=%d scanCode=%d\n",
5593 aMsg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
5594 aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF));
5596 // These must be checked here too as a lone WM_CHAR could be received
5597 // if a child window didn't handle it (for example Alt+Space in a content window)
5598 nsModifierKeyState modKeyState;
5599 return OnChar(aMsg, modKeyState, aEventDispatched);
5602 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, PRBool *aEventDispatched)
5604 NS_PRECONDITION(aMsg.message == WM_KEYUP || aMsg.message == WM_SYSKEYUP,
5605 "message is not keydown event");
5606 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5607 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5608 "WM_SYSKEYUP" : "WM_KEYUP", aMsg.wParam));
5610 nsModifierKeyState modKeyState;
5612 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5613 // scan code. However, this breaks Alt+Num pad input.
5614 // MSDN states the following:
5615 // Typically, ToAscii performs the translation based on the
5616 // virtual-key code. In some cases, however, bit 15 of the
5617 // uScanCode parameter may be used to distinguish between a key
5618 // press and a key release. The scan code is used for
5619 // translating ALT+number key combinations.
5621 // ignore [shift+]alt+space so the OS can handle it
5622 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5623 IS_VK_DOWN(NS_VK_SPACE)) {
5624 return FALSE;
5627 if (!nsIMM32Handler::IsComposingOn(this) &&
5628 (aMsg.message != WM_KEYUP || aMsg.wParam != VK_MENU)) {
5629 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5630 // This helps avoid triggering the menu bar for ALT key accelerators used in
5631 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5632 // to switch back to Mozilla in Windows 95 and Windows 98
5633 return OnKeyUp(aMsg, modKeyState, aEventDispatched);
5636 return 0;
5639 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
5640 PRBool *aEventDispatched)
5642 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5643 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5644 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg.wParam));
5645 NS_PRECONDITION(aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN,
5646 "message is not keydown event");
5648 nsModifierKeyState modKeyState;
5650 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
5651 // scan code. However, this breaks Alt+Num pad input.
5652 // MSDN states the following:
5653 // Typically, ToAscii performs the translation based on the
5654 // virtual-key code. In some cases, however, bit 15 of the
5655 // uScanCode parameter may be used to distinguish between a key
5656 // press and a key release. The scan code is used for
5657 // translating ALT+number key combinations.
5659 // ignore [shift+]alt+space so the OS can handle it
5660 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5661 IS_VK_DOWN(NS_VK_SPACE))
5662 return FALSE;
5664 LRESULT result = 0;
5665 if (modKeyState.mIsAltDown && nsIMM32Handler::IsStatusChanged()) {
5666 nsIMM32Handler::NotifyEndStatusChange();
5667 } else if (!nsIMM32Handler::IsComposingOn(this)) {
5668 result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nsnull);
5671 #ifndef WINCE
5672 if (aMsg.wParam == VK_MENU ||
5673 (aMsg.wParam == VK_F10 && !modKeyState.mIsShiftDown)) {
5674 // We need to let Windows handle this keypress,
5675 // by returning PR_FALSE, if there's a native menu
5676 // bar somewhere in our containing window hierarchy.
5677 // Otherwise we handle the keypress and don't pass
5678 // it on to Windows, by returning PR_TRUE.
5679 PRBool hasNativeMenu = PR_FALSE;
5680 HWND hWnd = mWnd;
5681 while (hWnd) {
5682 if (::GetMenu(hWnd)) {
5683 hasNativeMenu = PR_TRUE;
5684 break;
5686 hWnd = ::GetParent(hWnd);
5688 result = !hasNativeMenu;
5690 #endif
5692 return result;
5695 nsresult
5696 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
5697 PRInt32 aNativeKeyCode,
5698 PRUint32 aModifierFlags,
5699 const nsAString& aCharacters,
5700 const nsAString& aUnmodifiedCharacters)
5702 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
5703 nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
5704 HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
5705 if (loadedLayout == NULL)
5706 return NS_ERROR_NOT_AVAILABLE;
5708 // Setup clean key state and load desired layout
5709 BYTE originalKbdState[256];
5710 ::GetKeyboardState(originalKbdState);
5711 BYTE kbdState[256];
5712 memset(kbdState, 0, sizeof(kbdState));
5713 // This changes the state of the keyboard for the current thread only,
5714 // and we'll restore it soon, so this should be OK.
5715 ::SetKeyboardState(kbdState);
5716 HKL oldLayout = gKbdLayout.GetLayout();
5717 gKbdLayout.LoadLayout(loadedLayout);
5719 nsAutoTArray<KeyPair,10> keySequence;
5720 SetupKeyModifiersSequence(&keySequence, aModifierFlags);
5721 NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
5722 "Native VK key code out of range");
5723 keySequence.AppendElement(KeyPair(aNativeKeyCode, 0));
5725 // Simulate the pressing of each modifier key and then the real key
5726 for (PRUint32 i = 0; i < keySequence.Length(); ++i) {
5727 PRUint8 key = keySequence[i].mGeneral;
5728 PRUint8 keySpecific = keySequence[i].mSpecific;
5729 kbdState[key] = 0x81; // key is down and toggled on if appropriate
5730 if (keySpecific) {
5731 kbdState[keySpecific] = 0x81;
5733 ::SetKeyboardState(kbdState);
5734 nsModifierKeyState modKeyState;
5735 MSG msg = InitMSG(WM_KEYDOWN, key, 0);
5736 if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
5737 UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
5738 gKbdLayout.GetLayout());
5739 nsFakeCharMessage fakeMsg = { aCharacters.CharAt(0), scanCode };
5740 OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
5741 } else {
5742 OnKeyDown(msg, modKeyState, nsnull, nsnull);
5745 for (PRUint32 i = keySequence.Length(); i > 0; --i) {
5746 PRUint8 key = keySequence[i - 1].mGeneral;
5747 PRUint8 keySpecific = keySequence[i - 1].mSpecific;
5748 kbdState[key] = 0; // key is up and toggled off if appropriate
5749 if (keySpecific) {
5750 kbdState[keySpecific] = 0;
5752 ::SetKeyboardState(kbdState);
5753 nsModifierKeyState modKeyState;
5754 MSG msg = InitMSG(WM_KEYUP, key, 0);
5755 OnKeyUp(msg, modKeyState, nsnull);
5758 // Restore old key state and layout
5759 ::SetKeyboardState(originalKbdState);
5760 gKbdLayout.LoadLayout(oldLayout);
5762 UnloadKeyboardLayout(loadedLayout);
5763 return NS_OK;
5764 #else //XXX: is there another way to do this?
5765 return NS_ERROR_NOT_IMPLEMENTED;
5766 #endif
5769 nsresult
5770 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
5771 PRUint32 aNativeMessage,
5772 PRUint32 aModifierFlags)
5774 #ifndef WINCE // I don't think WINCE supports SendInput
5775 RECT r;
5776 ::GetWindowRect(mWnd, &r);
5777 ::SetCursorPos(r.left + aPoint.x, r.top + aPoint.y);
5779 INPUT input;
5780 memset(&input, 0, sizeof(input));
5782 input.type = INPUT_MOUSE;
5783 input.mi.dwFlags = aNativeMessage;
5784 ::SendInput(1, &input, sizeof(INPUT));
5786 return NS_OK;
5787 #else
5788 return NS_ERROR_NOT_IMPLEMENTED;
5789 #endif
5792 /**************************************************************
5794 * SECTION: OnXXX message handlers
5796 * For message handlers that need to be broken out or
5797 * implemented in specific platform code.
5799 **************************************************************/
5801 BOOL nsWindow::OnInputLangChange(HKL aHKL)
5803 #ifdef KE_DEBUG
5804 printf("OnInputLanguageChange\n");
5805 #endif
5807 #ifndef WINCE
5808 gKbdLayout.LoadLayout(aHKL);
5809 #endif
5811 return PR_FALSE; // always pass to child window
5814 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5815 void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, PRBool& result)
5817 if (wp == nsnull)
5818 return;
5820 #ifdef WINSTATE_DEBUG_OUTPUT
5821 if (mWnd == GetTopLevelHWND(mWnd))
5822 printf("*** OnWindowPosChanged: [ top] ");
5823 else
5824 printf("*** OnWindowPosChanged: [child] ");
5825 printf("WINDOWPOS flags:");
5826 if (wp->flags & SWP_FRAMECHANGED)
5827 printf("SWP_FRAMECHANGED ");
5828 if (wp->flags & SWP_SHOWWINDOW)
5829 printf("SWP_SHOWWINDOW ");
5830 if (wp->flags & SWP_NOSIZE)
5831 printf("SWP_NOSIZE ");
5832 if (wp->flags & SWP_HIDEWINDOW)
5833 printf("SWP_HIDEWINDOW ");
5834 printf("\n");
5835 #endif
5837 // Handle window size mode changes
5838 if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
5839 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
5841 WINDOWPLACEMENT pl;
5842 pl.length = sizeof(pl);
5843 ::GetWindowPlacement(mWnd, &pl);
5845 if (pl.showCmd == SW_SHOWMAXIMIZED)
5846 event.mSizeMode = nsSizeMode_Maximized;
5847 else if (pl.showCmd == SW_SHOWMINIMIZED)
5848 event.mSizeMode = nsSizeMode_Minimized;
5849 else
5850 event.mSizeMode = nsSizeMode_Normal;
5852 // Windows has just changed the size mode of this window. The following
5853 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
5854 // set the min/max window state again or for nsSizeMode_Normal, call
5855 // SetWindow with a parameter of SW_RESTORE. There's no need however as
5856 // this window's mode has already changed. Updating mSizeMode here
5857 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
5858 // to window docking. (bug 489258)
5859 mSizeMode = event.mSizeMode;
5861 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
5862 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
5863 // prevents the working set from being trimmed but keeps the window active.
5864 // After the window is minimized, we need to do some touch up work on the
5865 // active window. (bugs 76831 & 499816)
5866 if (!sTrimOnMinimize && nsSizeMode_Minimized == event.mSizeMode)
5867 ActivateOtherWindowHelper(mWnd);
5869 #ifdef WINSTATE_DEBUG_OUTPUT
5870 switch (mSizeMode) {
5871 case nsSizeMode_Normal:
5872 printf("*** mSizeMode: nsSizeMode_Normal\n");
5873 break;
5874 case nsSizeMode_Minimized:
5875 printf("*** mSizeMode: nsSizeMode_Minimized\n");
5876 break;
5877 case nsSizeMode_Maximized:
5878 printf("*** mSizeMode: nsSizeMode_Maximized\n");
5879 break;
5880 default:
5881 printf("*** mSizeMode: ??????\n");
5882 break;
5884 #endif
5886 InitEvent(event);
5888 result = DispatchWindowEvent(&event);
5890 // Skip window size change events below on minimization.
5891 if (mSizeMode == nsSizeMode_Minimized)
5892 return;
5895 // Handle window size changes
5896 if (0 == (wp->flags & SWP_NOSIZE)) {
5897 RECT r;
5898 PRInt32 newWidth, newHeight;
5900 ::GetWindowRect(mWnd, &r);
5902 newWidth = r.right - r.left;
5903 newHeight = r.bottom - r.top;
5904 nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
5906 #ifdef MOZ_XUL
5907 if (eTransparencyTransparent == mTransparencyMode)
5908 ResizeTranslucentWindow(newWidth, newHeight);
5909 #endif
5911 if (newWidth > mLastSize.width)
5913 RECT drect;
5915 // getting wider
5916 drect.left = wp->x + mLastSize.width;
5917 drect.top = wp->y;
5918 drect.right = drect.left + (newWidth - mLastSize.width);
5919 drect.bottom = drect.top + newHeight;
5921 ::RedrawWindow(mWnd, &drect, NULL,
5922 RDW_INVALIDATE |
5923 RDW_NOERASE |
5924 RDW_NOINTERNALPAINT |
5925 RDW_ERASENOW |
5926 RDW_ALLCHILDREN);
5928 if (newHeight > mLastSize.height)
5930 RECT drect;
5932 // getting taller
5933 drect.left = wp->x;
5934 drect.top = wp->y + mLastSize.height;
5935 drect.right = drect.left + newWidth;
5936 drect.bottom = drect.top + (newHeight - mLastSize.height);
5938 ::RedrawWindow(mWnd, &drect, NULL,
5939 RDW_INVALIDATE |
5940 RDW_NOERASE |
5941 RDW_NOINTERNALPAINT |
5942 RDW_ERASENOW |
5943 RDW_ALLCHILDREN);
5946 mBounds.width = newWidth;
5947 mBounds.height = newHeight;
5948 mLastSize.width = newWidth;
5949 mLastSize.height = newHeight;
5951 #ifdef WINSTATE_DEBUG_OUTPUT
5952 printf("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, newWidth, newHeight);
5953 #endif
5955 // If a maximized window is resized, recalculate the non-client margins and
5956 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
5957 // work properly.
5958 if (mSizeMode == nsSizeMode_Maximized) {
5959 if (UpdateNonClientMargins(nsSizeMode_Maximized, PR_TRUE)) {
5960 // gecko resize event already sent by UpdateNonClientMargins.
5961 result = PR_TRUE;
5962 return;
5966 // Recalculate the width and height based on the client area for gecko events.
5967 if (::GetClientRect(mWnd, &r)) {
5968 rect.width = r.right - r.left;
5969 rect.height = r.bottom - r.top;
5972 // Send a gecko resize event
5973 result = OnResize(rect);
5977 // static
5978 void nsWindow::ActivateOtherWindowHelper(HWND aWnd)
5980 // Find the next window that is enabled, visible, and not minimized.
5981 HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT);
5982 while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) ||
5983 ::IsIconic(hwndBelow))) {
5984 hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT);
5987 // Push ourselves to the bottom of the stack, then activate the
5988 // next window.
5989 ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0,
5990 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
5991 if (hwndBelow)
5992 ::SetForegroundWindow(hwndBelow);
5994 // Play the minimize sound while we're here, since that is also
5995 // forgotten when we use SW_SHOWMINIMIZED.
5996 ::PlaySoundW(L"Minimize", nsnull, SND_ALIAS | SND_NODEFAULT | SND_ASYNC);
5998 #endif // !defined(WINCE)
6000 #if !defined(WINCE)
6001 void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info)
6003 // Update non-client margins if the frame size is changing, and let the
6004 // browser know we are changing size modes, so alternative css can kick in.
6005 // If we're going into fullscreen mode, ignore this, since it'll reset
6006 // margins to normal mode.
6007 if (info->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
6008 WINDOWPLACEMENT pl;
6009 pl.length = sizeof(pl);
6010 ::GetWindowPlacement(mWnd, &pl);
6011 PRInt32 sizeMode;
6012 if (pl.showCmd == SW_SHOWMAXIMIZED)
6013 sizeMode = nsSizeMode_Maximized;
6014 else if (pl.showCmd == SW_SHOWMINIMIZED)
6015 sizeMode = nsSizeMode_Minimized;
6016 else
6017 sizeMode = nsSizeMode_Normal;
6019 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
6021 InitEvent(event);
6022 event.mSizeMode = static_cast<nsSizeMode>(sizeMode);
6023 DispatchWindowEvent(&event);
6025 UpdateNonClientMargins(sizeMode, PR_FALSE);
6028 // enforce local z-order rules
6029 if (!(info->flags & SWP_NOZORDER)) {
6030 HWND hwndAfter = info->hwndInsertAfter;
6032 nsZLevelEvent event(PR_TRUE, NS_SETZLEVEL, this);
6033 nsWindow *aboveWindow = 0;
6035 InitEvent(event);
6037 if (hwndAfter == HWND_BOTTOM)
6038 event.mPlacement = nsWindowZBottom;
6039 else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
6040 event.mPlacement = nsWindowZTop;
6041 else {
6042 event.mPlacement = nsWindowZRelative;
6043 aboveWindow = GetNSWindowPtr(hwndAfter);
6045 event.mReqBelow = aboveWindow;
6046 event.mActualBelow = nsnull;
6048 event.mImmediate = PR_FALSE;
6049 event.mAdjusted = PR_FALSE;
6050 DispatchWindowEvent(&event);
6052 if (event.mAdjusted) {
6053 if (event.mPlacement == nsWindowZBottom)
6054 info->hwndInsertAfter = HWND_BOTTOM;
6055 else if (event.mPlacement == nsWindowZTop)
6056 info->hwndInsertAfter = HWND_TOP;
6057 else {
6058 info->hwndInsertAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
6061 NS_IF_RELEASE(event.mActualBelow);
6063 // prevent rude external programs from making hidden window visible
6064 if (mWindowType == eWindowType_invisible)
6065 info->flags &= ~SWP_SHOWWINDOW;
6067 #endif
6069 void nsWindow::UserActivity()
6071 // Check if we have the idle service, if not we try to get it.
6072 if (!mIdleService) {
6073 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
6076 // Check that we now have the idle service.
6077 if (mIdleService) {
6078 mIdleService->ResetIdleTimeOut();
6082 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6083 PRBool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam)
6085 PRUint32 cInputs = LOWORD(wParam);
6086 PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
6088 if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) {
6089 for (PRUint32 i = 0; i < cInputs; i++) {
6090 PRUint32 msg;
6091 if (pInputs[i].dwFlags & TOUCHEVENTF_MOVE) {
6092 msg = NS_MOZTOUCH_MOVE;
6093 } else if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) {
6094 msg = NS_MOZTOUCH_DOWN;
6095 } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) {
6096 msg = NS_MOZTOUCH_UP;
6097 } else {
6098 continue;
6101 nsPointWin touchPoint;
6102 touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
6103 touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
6104 touchPoint.ScreenToClient(mWnd);
6106 nsMozTouchEvent touchEvent(PR_TRUE, msg, this, pInputs[i].dwID);
6107 touchEvent.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6108 touchEvent.refPoint = touchPoint;
6110 nsEventStatus status;
6111 DispatchEvent(&touchEvent, status);
6115 delete [] pInputs;
6116 mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam);
6117 return PR_TRUE;
6119 #endif
6121 // Gesture event processing. Handles WM_GESTURE events.
6122 #if !defined(WINCE)
6123 PRBool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
6125 // Treatment for pan events which translate into scroll events:
6126 if (mGesture.IsPanEvent(lParam)) {
6127 nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
6129 if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
6130 return PR_FALSE; // ignore
6132 nsEventStatus status;
6134 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6135 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6136 event.isMeta = PR_FALSE;
6137 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6138 event.button = 0;
6139 event.time = ::GetMessageTime();
6140 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6142 PRBool endFeedback = PR_TRUE;
6144 PRInt32 scrollOverflowX = 0;
6145 PRInt32 scrollOverflowY = 0;
6147 if (mGesture.PanDeltaToPixelScrollX(event)) {
6148 DispatchEvent(&event, status);
6149 scrollOverflowX = event.scrollOverflow;
6152 if (mGesture.PanDeltaToPixelScrollY(event)) {
6153 DispatchEvent(&event, status);
6154 scrollOverflowY = event.scrollOverflow;
6157 if (mDisplayPanFeedback) {
6158 mGesture.UpdatePanFeedbackX(mWnd, scrollOverflowX, endFeedback);
6159 mGesture.UpdatePanFeedbackY(mWnd, scrollOverflowY, endFeedback);
6160 mGesture.PanFeedbackFinalize(mWnd, endFeedback);
6163 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6165 return PR_TRUE;
6168 // Other gestures translate into simple gesture events:
6169 nsSimpleGestureEvent event(PR_TRUE, 0, this, 0, 0.0);
6170 if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) {
6171 return PR_FALSE; // fall through to DefWndProc
6174 // Polish up and send off the new event
6175 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6176 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6177 event.isMeta = PR_FALSE;
6178 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6179 event.button = 0;
6180 event.time = ::GetMessageTime();
6181 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6183 nsEventStatus status;
6184 DispatchEvent(&event, status);
6185 if (status == nsEventStatus_eIgnore) {
6186 return PR_FALSE; // Ignored, fall through
6189 // Only close this if we process and return true.
6190 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6192 return PR_TRUE; // Handled
6194 #endif // !defined(WINCE)
6196 #if !defined(WINCE)
6197 PRUint16 nsWindow::GetMouseInputSource()
6199 PRUint16 inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE;
6200 LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
6201 if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
6202 inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ?
6203 PRUint16(nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH) : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN;
6205 return inputSource;
6207 #endif
6209 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6210 * within the message case block. If returning true result should be returned
6211 * immediately (no more processing).
6213 PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue)
6215 // Handle both flavors of mouse wheel events.
6216 static int iDeltaPerLine, iDeltaPerChar;
6217 static ULONG ulScrollLines, ulScrollChars = 1;
6218 static int currentVDelta, currentHDelta;
6219 static HWND currentWindow = 0;
6221 PRBool isVertical = msg == WM_MOUSEWHEEL;
6223 // Get mouse wheel metrics (but only once).
6224 if (getWheelInfo) {
6225 getWheelInfo = PR_FALSE;
6227 SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
6229 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6230 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6232 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6233 // the mouse driver wants a page scroll. The docs state that
6234 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6235 // since some mouse drivers use an arbitrary large number instead,
6236 // we have to handle that as well.
6238 iDeltaPerLine = 0;
6239 if (ulScrollLines) {
6240 if (ulScrollLines <= WHEEL_DELTA) {
6241 iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
6242 } else {
6243 ulScrollLines = WHEEL_PAGESCROLL;
6247 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
6248 &ulScrollChars, 0)) {
6249 // Note that we may always fail to get the value before Win Vista.
6250 ulScrollChars = 1;
6253 iDeltaPerChar = 0;
6254 if (ulScrollChars) {
6255 if (ulScrollChars <= WHEEL_DELTA) {
6256 iDeltaPerChar = WHEEL_DELTA / ulScrollChars;
6257 } else {
6258 ulScrollChars = WHEEL_PAGESCROLL;
6263 if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) ||
6264 (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar))
6265 return PR_FALSE; // break
6267 // The mousewheel event will be dispatched to the toplevel
6268 // window. We need to give it to the child window
6269 PRBool quit;
6270 if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit))
6271 return quit; // return immediately if its not our window
6273 // We should cancel the surplus delta if the current window is not
6274 // same as previous.
6275 if (currentWindow != mWnd) {
6276 currentVDelta = 0;
6277 currentHDelta = 0;
6278 currentWindow = mWnd;
6281 nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
6282 scrollEvent.delta = 0;
6283 if (isVertical) {
6284 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
6285 if (ulScrollLines == WHEEL_PAGESCROLL) {
6286 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6287 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1;
6288 } else {
6289 currentVDelta -= (short) HIWORD (wParam);
6290 if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
6291 scrollEvent.delta = currentVDelta / iDeltaPerLine;
6292 currentVDelta %= iDeltaPerLine;
6295 } else {
6296 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
6297 if (ulScrollChars == WHEEL_PAGESCROLL) {
6298 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6299 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1;
6300 } else {
6301 currentHDelta += (short) HIWORD (wParam);
6302 if (PR_ABS(currentHDelta) >= iDeltaPerChar) {
6303 scrollEvent.delta = currentHDelta / iDeltaPerChar;
6304 currentHDelta %= iDeltaPerChar;
6309 if (!scrollEvent.delta) {
6310 // We store the wheel delta, and it will be used next wheel message, so,
6311 // we consume this message actually. We shouldn't call next wndproc.
6312 result = PR_TRUE;
6313 return PR_FALSE; // break
6316 #ifdef MOZ_IPC
6317 // The event may go to a plug-in which already dispatched this message.
6318 // Then, the event can cause deadlock. We should unlock the sender here.
6319 ::ReplyMessage(isVertical ? 0 : TRUE);
6320 #endif
6322 scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6323 scrollEvent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6324 scrollEvent.isMeta = PR_FALSE;
6325 scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT);
6326 InitEvent(scrollEvent);
6327 if (nsnull != mEventCallback) {
6328 result = DispatchWindowEvent(&scrollEvent);
6330 // Note that we should return zero if we process WM_MOUSEWHEEL.
6331 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6333 if (result)
6334 *aRetValue = isVertical ? 0 : TRUE;
6336 return PR_FALSE; // break;
6339 static PRBool
6340 StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,
6341 const PRUnichar* aChars2, const PRUint32 aNumChars2)
6343 if (aNumChars1 != aNumChars2)
6344 return PR_FALSE;
6346 nsCaseInsensitiveStringComparator comp;
6347 return comp(aChars1, aChars2, aNumChars1) == 0;
6350 UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
6352 #ifndef WINCE
6353 switch (aNativeKeyCode) {
6354 case VK_OEM_1: return NS_VK_SEMICOLON; // 0xBA, For the US standard keyboard, the ';:' key
6355 case VK_OEM_PLUS: return NS_VK_ADD; // 0xBB, For any country/region, the '+' key
6356 case VK_OEM_MINUS: return NS_VK_SUBTRACT; // 0xBD, For any country/region, the '-' key
6358 #endif
6360 return aNativeKeyCode;
6364 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6365 * WM_CHAR messages for processing. During testing we don't want to
6366 * mess with the real message queue. Instead we pass a
6367 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6368 * that as if it was in the message queue, and refrain from actually
6369 * looking at or touching the message queue.
6371 LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
6372 nsModifierKeyState &aModKeyState,
6373 PRBool *aEventDispatched,
6374 nsFakeCharMessage* aFakeCharMessage)
6376 UINT virtualKeyCode = aMsg.wParam;
6378 #ifndef WINCE
6379 gKbdLayout.OnKeyDown (virtualKeyCode);
6380 #endif
6382 // Use only DOMKeyCode for XP processing.
6383 // Use aVirtualKeyCode for gKbdLayout and native processing.
6384 UINT DOMKeyCode = nsIMM32Handler::IsComposingOn(this) ?
6385 virtualKeyCode : MapFromNativeToDOM(virtualKeyCode);
6387 #ifdef DEBUG
6388 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6389 #endif
6391 PRBool noDefault =
6392 DispatchKeyEvent(NS_KEY_DOWN, 0, nsnull, DOMKeyCode, &aMsg, aModKeyState);
6393 if (aEventDispatched)
6394 *aEventDispatched = PR_TRUE;
6396 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6397 // for almost all keys
6398 switch (DOMKeyCode) {
6399 case NS_VK_SHIFT:
6400 case NS_VK_CONTROL:
6401 case NS_VK_ALT:
6402 case NS_VK_CAPS_LOCK:
6403 case NS_VK_NUM_LOCK:
6404 case NS_VK_SCROLL_LOCK: return noDefault;
6407 PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
6408 MSG msg;
6409 BOOL gotMsg = aFakeCharMessage ||
6410 ::PeekMessageW(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6411 // Enter and backspace are always handled here to avoid for example the
6412 // confusion between ctrl-enter and ctrl-J.
6413 if (DOMKeyCode == NS_VK_RETURN || DOMKeyCode == NS_VK_BACK ||
6414 ((aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)
6415 #ifdef WINCE
6417 #else
6418 && !gKbdLayout.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
6419 #endif
6421 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6422 // They can be more than one because of:
6423 // * Dead-keys not pairing with base character
6424 // * Some keyboard layouts may map up to 4 characters to the single key
6425 PRBool anyCharMessagesRemoved = PR_FALSE;
6427 if (aFakeCharMessage) {
6428 anyCharMessagesRemoved = PR_TRUE;
6429 } else {
6430 while (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR))
6432 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6433 ("%s charCode=%d scanCode=%d\n", msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6434 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6435 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST, WM_KEYLAST);
6436 anyCharMessagesRemoved = PR_TRUE;
6438 gotMsg = ::PeekMessageW (&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6442 if (!anyCharMessagesRemoved && DOMKeyCode == NS_VK_BACK &&
6443 nsIMM32Handler::IsDoingKakuteiUndo(mWnd)) {
6444 NS_ASSERTION(!aFakeCharMessage,
6445 "We shouldn't be touching the real msg queue");
6446 RemoveMessageAndDispatchPluginEvent(WM_CHAR, WM_CHAR);
6449 else if (gotMsg &&
6450 (aFakeCharMessage ||
6451 msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
6452 if (aFakeCharMessage)
6453 return OnCharRaw(aFakeCharMessage->mCharCode,
6454 aFakeCharMessage->mScanCode, aModKeyState, extraFlags);
6456 // If prevent default set for keydown, do same for keypress
6457 ::GetMessageW(&msg, mWnd, msg.message, msg.message);
6459 if (msg.message == WM_DEADCHAR) {
6460 if (!PluginHasFocus())
6461 return PR_FALSE;
6463 // We need to send the removed message to focused plug-in.
6464 DispatchPluginEvent(msg);
6465 return noDefault;
6468 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6469 ("%s charCode=%d scanCode=%d\n",
6470 msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6471 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6473 BOOL result = OnChar(msg, aModKeyState, nsnull, extraFlags);
6474 // If a syschar keypress wasn't processed, Windows may want to
6475 // handle it to activate a native menu.
6476 if (!result && msg.message == WM_SYSCHAR)
6477 ::DefWindowProcW(mWnd, msg.message, msg.wParam, msg.lParam);
6478 return result;
6480 #ifndef WINCE
6481 else if (!aModKeyState.mIsControlDown && !aModKeyState.mIsAltDown &&
6482 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode) ||
6483 KeyboardLayout::IsNumpadKey(virtualKeyCode)))
6485 // If this is simple KeyDown event but next message is not WM_CHAR,
6486 // this event may not input text, so we should ignore this event.
6487 // See bug 314130.
6488 return PluginHasFocus() && noDefault;
6491 if (gKbdLayout.IsDeadKey ())
6492 return PluginHasFocus() && noDefault;
6494 PRUint8 shiftStates[5];
6495 PRUnichar uniChars[5];
6496 PRUnichar shiftedChars[5] = {0, 0, 0, 0, 0};
6497 PRUnichar unshiftedChars[5] = {0, 0, 0, 0, 0};
6498 PRUnichar shiftedLatinChar = 0;
6499 PRUnichar unshiftedLatinChar = 0;
6500 PRUint32 numOfUniChars = 0;
6501 PRUint32 numOfShiftedChars = 0;
6502 PRUint32 numOfUnshiftedChars = 0;
6503 PRUint32 numOfShiftStates = 0;
6505 switch (virtualKeyCode) {
6506 // keys to be sent as characters
6507 case VK_ADD: uniChars [0] = '+'; numOfUniChars = 1; break;
6508 case VK_SUBTRACT: uniChars [0] = '-'; numOfUniChars = 1; break;
6509 case VK_DIVIDE: uniChars [0] = '/'; numOfUniChars = 1; break;
6510 case VK_MULTIPLY: uniChars [0] = '*'; numOfUniChars = 1; break;
6511 case VK_NUMPAD0:
6512 case VK_NUMPAD1:
6513 case VK_NUMPAD2:
6514 case VK_NUMPAD3:
6515 case VK_NUMPAD4:
6516 case VK_NUMPAD5:
6517 case VK_NUMPAD6:
6518 case VK_NUMPAD7:
6519 case VK_NUMPAD8:
6520 case VK_NUMPAD9:
6521 uniChars [0] = virtualKeyCode - VK_NUMPAD0 + '0';
6522 numOfUniChars = 1;
6523 break;
6524 default:
6525 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
6526 numOfUniChars = numOfShiftStates =
6527 gKbdLayout.GetUniChars(uniChars, shiftStates,
6528 NS_ARRAY_LENGTH(uniChars));
6531 if (aModKeyState.mIsControlDown ^ aModKeyState.mIsAltDown) {
6532 PRUint8 capsLockState = (::GetKeyState(VK_CAPITAL) & 1) ? eCapsLock : 0;
6533 numOfUnshiftedChars =
6534 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode, capsLockState,
6535 unshiftedChars, NS_ARRAY_LENGTH(unshiftedChars));
6536 numOfShiftedChars =
6537 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode,
6538 capsLockState | eShift,
6539 shiftedChars, NS_ARRAY_LENGTH(shiftedChars));
6541 // The current keyboard cannot input alphabets or numerics,
6542 // we should append them for Shortcut/Access keys.
6543 // E.g., for Cyrillic keyboard layout.
6544 if (NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z) {
6545 shiftedLatinChar = unshiftedLatinChar = DOMKeyCode;
6546 if (capsLockState)
6547 shiftedLatinChar += 0x20;
6548 else
6549 unshiftedLatinChar += 0x20;
6550 if (unshiftedLatinChar == unshiftedChars[0] &&
6551 shiftedLatinChar == shiftedChars[0]) {
6552 shiftedLatinChar = unshiftedLatinChar = 0;
6554 } else {
6555 PRUint16 ch = 0;
6556 if (NS_VK_0 <= DOMKeyCode && DOMKeyCode <= NS_VK_9) {
6557 ch = DOMKeyCode;
6558 } else {
6559 switch (virtualKeyCode) {
6560 case VK_OEM_PLUS: ch = '+'; break;
6561 case VK_OEM_MINUS: ch = '-'; break;
6564 if (ch && unshiftedChars[0] != ch && shiftedChars[0] != ch) {
6565 // Windows has assigned a virtual key code to the key even though
6566 // the character can't be produced with this key. That probably
6567 // means the character can't be produced with any key in the
6568 // current layout and so the assignment is based on a QWERTY
6569 // layout. Append this code so that users can access the shortcut.
6570 unshiftedLatinChar = ch;
6574 // If the charCode is not ASCII character, we should replace the
6575 // charCode with ASCII character only when Ctrl is pressed.
6576 // But don't replace the charCode when the charCode is not same as
6577 // unmodified characters. In such case, Ctrl is sometimes used for a
6578 // part of character inputting key combination like Shift.
6579 if (aModKeyState.mIsControlDown) {
6580 PRUint8 currentState = eCtrl;
6581 if (aModKeyState.mIsShiftDown)
6582 currentState |= eShift;
6584 PRUint32 ch =
6585 aModKeyState.mIsShiftDown ? shiftedLatinChar : unshiftedLatinChar;
6586 if (ch &&
6587 (numOfUniChars == 0 ||
6588 StringCaseInsensitiveEquals(uniChars, numOfUniChars,
6589 aModKeyState.mIsShiftDown ? shiftedChars : unshiftedChars,
6590 aModKeyState.mIsShiftDown ? numOfShiftedChars :
6591 numOfUnshiftedChars))) {
6592 numOfUniChars = numOfShiftStates = 1;
6593 uniChars[0] = ch;
6594 shiftStates[0] = currentState;
6600 if (numOfUniChars > 0 || numOfShiftedChars > 0 || numOfUnshiftedChars > 0) {
6601 PRUint32 num = PR_MAX(numOfUniChars,
6602 PR_MAX(numOfShiftedChars, numOfUnshiftedChars));
6603 PRUint32 skipUniChars = num - numOfUniChars;
6604 PRUint32 skipShiftedChars = num - numOfShiftedChars;
6605 PRUint32 skipUnshiftedChars = num - numOfUnshiftedChars;
6606 UINT keyCode = numOfUniChars == 0 ? DOMKeyCode : 0;
6607 for (PRUint32 cnt = 0; cnt < num; cnt++) {
6608 PRUint16 uniChar, shiftedChar, unshiftedChar;
6609 uniChar = shiftedChar = unshiftedChar = 0;
6610 if (skipUniChars <= cnt) {
6611 if (cnt - skipUniChars < numOfShiftStates) {
6612 // If key in combination with Alt and/or Ctrl produces a different
6613 // character than without them then do not report these flags
6614 // because it is separate keyboard layout shift state. If dead-key
6615 // and base character does not produce a valid composite character
6616 // then both produced dead-key character and following base
6617 // character may have different modifier flags, too.
6618 aModKeyState.mIsShiftDown =
6619 (shiftStates[cnt - skipUniChars] & eShift) != 0;
6620 aModKeyState.mIsControlDown =
6621 (shiftStates[cnt - skipUniChars] & eCtrl) != 0;
6622 aModKeyState.mIsAltDown =
6623 (shiftStates[cnt - skipUniChars] & eAlt) != 0;
6625 uniChar = uniChars[cnt - skipUniChars];
6627 if (skipShiftedChars <= cnt)
6628 shiftedChar = shiftedChars[cnt - skipShiftedChars];
6629 if (skipUnshiftedChars <= cnt)
6630 unshiftedChar = unshiftedChars[cnt - skipUnshiftedChars];
6631 nsAutoTArray<nsAlternativeCharCode, 5> altArray;
6633 if (shiftedChar || unshiftedChar) {
6634 nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
6635 altArray.AppendElement(chars);
6637 if (cnt == num - 1 && (unshiftedLatinChar || shiftedLatinChar)) {
6638 nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
6639 altArray.AppendElement(chars);
6642 DispatchKeyEvent(NS_KEY_PRESS, uniChar, &altArray,
6643 keyCode, nsnull, aModKeyState, extraFlags);
6645 } else {
6646 DispatchKeyEvent(NS_KEY_PRESS, 0, nsnull, DOMKeyCode, nsnull, aModKeyState,
6647 extraFlags);
6649 #else
6651 UINT unichar = ::MapVirtualKey(virtualKeyCode, MAPVK_VK_TO_CHAR);
6652 // Check for dead characters or no mapping
6653 if (unichar & 0x80) {
6654 return noDefault;
6656 DispatchKeyEvent(NS_KEY_PRESS, unichar, nsnull, DOMKeyCode, nsnull, aModKeyState,
6657 extraFlags);
6659 #endif
6661 return noDefault;
6664 // OnKeyUp
6665 LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
6666 nsModifierKeyState &aModKeyState,
6667 PRBool *aEventDispatched)
6669 UINT virtualKeyCode = aMsg.wParam;
6671 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6672 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
6674 if (!nsIMM32Handler::IsComposingOn(this)) {
6675 virtualKeyCode = MapFromNativeToDOM(virtualKeyCode);
6678 if (aEventDispatched)
6679 *aEventDispatched = PR_TRUE;
6680 return DispatchKeyEvent(NS_KEY_UP, 0, nsnull, virtualKeyCode, &aMsg,
6681 aModKeyState);
6684 // OnChar
6685 LRESULT nsWindow::OnChar(const MSG &aMsg, nsModifierKeyState &aModKeyState,
6686 PRBool *aEventDispatched, PRUint32 aFlags)
6688 return OnCharRaw(aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF, aModKeyState,
6689 aFlags, &aMsg, aEventDispatched);
6692 // OnCharRaw
6693 LRESULT nsWindow::OnCharRaw(UINT charCode, UINT aScanCode,
6694 nsModifierKeyState &aModKeyState, PRUint32 aFlags,
6695 const MSG *aMsg, PRBool *aEventDispatched)
6697 // ignore [shift+]alt+space so the OS can handle it
6698 if (aModKeyState.mIsAltDown && !aModKeyState.mIsControlDown &&
6699 IS_VK_DOWN(NS_VK_SPACE)) {
6700 return FALSE;
6703 // Ignore Ctrl+Enter (bug 318235)
6704 if (aModKeyState.mIsControlDown && charCode == 0xA) {
6705 return FALSE;
6708 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
6709 PRBool saveIsAltDown = aModKeyState.mIsAltDown;
6710 PRBool saveIsControlDown = aModKeyState.mIsControlDown;
6711 if (aModKeyState.mIsAltDown && aModKeyState.mIsControlDown)
6712 aModKeyState.mIsAltDown = aModKeyState.mIsControlDown = PR_FALSE;
6714 wchar_t uniChar;
6716 if (nsIMM32Handler::IsComposingOn(this)) {
6717 ResetInputState();
6720 if (aModKeyState.mIsControlDown && charCode <= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
6721 // need to account for shift here. bug 16486
6722 if (aModKeyState.mIsShiftDown)
6723 uniChar = charCode - 1 + 'A';
6724 else
6725 uniChar = charCode - 1 + 'a';
6726 charCode = 0;
6728 else if (aModKeyState.mIsControlDown && charCode <= 0x1F) {
6729 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
6730 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
6731 // for some reason the keypress handler need to have the uniChar code set
6732 // with the addition of a upper case A not the lower case.
6733 uniChar = charCode - 1 + 'A';
6734 charCode = 0;
6735 } else { // 0x20 - SPACE, 0x3D - EQUALS
6736 if (charCode < 0x20 || (charCode == 0x3D && aModKeyState.mIsControlDown)) {
6737 uniChar = 0;
6738 } else {
6739 uniChar = charCode;
6740 charCode = 0;
6744 // Keep the characters unshifted for shortcuts and accesskeys and make sure
6745 // that numbers are always passed as such (among others: bugs 50255 and 351310)
6746 if (uniChar && (aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)) {
6747 UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK,
6748 gKbdLayout.GetLayout());
6749 UINT unshiftedCharCode =
6750 virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
6751 aModKeyState.mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode,
6752 MAPVK_VK_TO_CHAR,
6753 gKbdLayout.GetLayout()) : 0;
6754 // ignore diacritics (top bit set) and key mapping errors (char code 0)
6755 if ((INT)unshiftedCharCode > 0)
6756 uniChar = unshiftedCharCode;
6759 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
6760 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
6761 // pressed too.
6762 if (!aModKeyState.mIsShiftDown && (saveIsAltDown || saveIsControlDown)) {
6763 uniChar = towlower(uniChar);
6766 PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, nsnull,
6767 charCode, aMsg, aModKeyState, aFlags);
6768 if (aEventDispatched)
6769 *aEventDispatched = PR_TRUE;
6770 aModKeyState.mIsAltDown = saveIsAltDown;
6771 aModKeyState.mIsControlDown = saveIsControlDown;
6772 return result;
6775 void
6776 nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers)
6778 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierKeyMap); ++i) {
6779 const PRUint32* map = sModifierKeyMap[i];
6780 if (aModifiers & map[0]) {
6781 aArray->AppendElement(KeyPair(map[1], map[2]));
6786 nsresult
6787 nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
6789 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
6790 // here, if that helps in some situations. So far I haven't seen a
6791 // need.
6792 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
6793 const Configuration& configuration = aConfigurations[i];
6794 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
6795 NS_ASSERTION(w->GetParent() == this,
6796 "Configured widget is not a child");
6797 #ifdef WINCE
6798 // MSDN says we should do on WinCE this before moving or resizing the window
6799 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
6800 // We put the region back just below, anyway.
6801 ::SetWindowRgn(w->mWnd, NULL, TRUE);
6802 #endif
6803 nsIntRect bounds;
6804 w->GetBounds(bounds);
6805 if (bounds.Size() != configuration.mBounds.Size()) {
6806 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
6807 configuration.mBounds.width, configuration.mBounds.height,
6808 PR_TRUE);
6809 } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
6810 w->Move(configuration.mBounds.x, configuration.mBounds.y);
6812 nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_FALSE);
6813 NS_ENSURE_SUCCESS(rv, rv);
6815 return NS_OK;
6818 static HRGN
6819 CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
6821 PRInt32 size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
6822 nsAutoTArray<PRUint8,100> buf;
6823 if (!buf.SetLength(size))
6824 return NULL;
6825 RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
6826 RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
6827 data->rdh.dwSize = sizeof(data->rdh);
6828 data->rdh.iType = RDH_RECTANGLES;
6829 data->rdh.nCount = aRects.Length();
6830 nsIntRect bounds;
6831 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
6832 const nsIntRect& r = aRects[i];
6833 bounds.UnionRect(bounds, r);
6834 ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
6836 ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
6837 return ::ExtCreateRegion(NULL, buf.Length(), data);
6840 nsresult
6841 nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
6842 PRBool aIntersectWithExisting)
6844 if (!aIntersectWithExisting) {
6845 if (!StoreWindowClipRegion(aRects))
6846 return NS_OK;
6849 HRGN dest = CreateHRGNFromArray(aRects);
6850 if (!dest)
6851 return NS_ERROR_OUT_OF_MEMORY;
6853 if (aIntersectWithExisting) {
6854 HRGN current = ::CreateRectRgn(0, 0, 0, 0);
6855 if (current) {
6856 if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
6857 ::CombineRgn(dest, dest, current, RGN_AND);
6859 ::DeleteObject(current);
6863 if (!::SetWindowRgn(mWnd, dest, TRUE)) {
6864 ::DeleteObject(dest);
6865 return NS_ERROR_FAILURE;
6867 return NS_OK;
6870 // WM_DESTROY event handler
6871 void nsWindow::OnDestroy()
6873 mOnDestroyCalled = PR_TRUE;
6875 // Make sure we don't get destroyed in the process of tearing down.
6876 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
6878 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
6879 if (!mInDtor)
6880 DispatchStandardEvent(NS_DESTROY);
6882 // Prevent the widget from sending additional events.
6883 mEventCallback = nsnull;
6885 // Free our subclass and clear |this| stored in the window props. We will no longer
6886 // receive events from Windows after this point.
6887 SubclassWindow(FALSE);
6889 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
6890 // cleared. (It's used in tracking windows for mouse events.)
6891 if (sCurrentWindow == this)
6892 sCurrentWindow = nsnull;
6894 // Disconnects us from our parent, will call our GetParent().
6895 nsBaseWidget::Destroy();
6897 // Release references to children, device context, toolkit, and app shell.
6898 nsBaseWidget::OnDestroy();
6900 // Clear our native parent handle.
6901 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
6902 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
6903 //SetParent(nsnull);
6904 mParent = nsnull;
6906 // We have to destroy the native drag target before we null out our window pointer.
6907 EnableDragDrop(PR_FALSE);
6909 // If we're going away and for some reason we're still the rollup widget, rollup and
6910 // turn off capture.
6911 if ( this == sRollupWidget ) {
6912 if ( sRollupListener )
6913 sRollupListener->Rollup(nsnull, nsnull);
6914 CaptureRollupEvents(nsnull, nsnull, PR_FALSE, PR_TRUE);
6917 // If IME is disabled, restore it.
6918 if (mOldIMC) {
6919 mOldIMC = ::ImmAssociateContext(mWnd, mOldIMC);
6920 NS_ASSERTION(!mOldIMC, "Another IMC was associated");
6923 // Turn off mouse trails if enabled.
6924 MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
6925 if (mtrailer) {
6926 if (mtrailer->GetMouseTrailerWindow() == mWnd)
6927 mtrailer->DestroyTimer();
6929 if (mtrailer->GetCaptureWindow() == mWnd)
6930 mtrailer->SetCaptureWindow(nsnull);
6933 // Free GDI window class objects
6934 if (mBrush) {
6935 VERIFY(::DeleteObject(mBrush));
6936 mBrush = NULL;
6939 // Free app icon resources.
6940 HICON icon;
6941 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM) 0);
6942 if (icon)
6943 ::DestroyIcon(icon);
6945 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM) 0);
6946 if (icon)
6947 ::DestroyIcon(icon);
6949 // Destroy any custom cursor resources.
6950 if (mCursor == -1)
6951 SetCursor(eCursor_standard);
6953 #ifdef MOZ_XUL
6954 // Reset transparency
6955 if (eTransparencyTransparent == mTransparencyMode)
6956 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
6957 #endif
6959 #if defined(WINCE_HAVE_SOFTKB)
6960 // Revert the changes made for the software keyboard settings
6961 nsWindowCE::ResetSoftKB(mWnd);
6962 #endif
6964 #if !defined(WINCE)
6965 // Finalize panning feedback to possibly restore window displacement
6966 mGesture.PanFeedbackFinalize(mWnd, PR_TRUE);
6967 #endif
6969 // Clear the main HWND.
6970 mWnd = NULL;
6973 // OnMove
6974 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
6976 mBounds.x = aX;
6977 mBounds.y = aY;
6979 nsGUIEvent event(PR_TRUE, NS_MOVE, this);
6980 InitEvent(event);
6981 event.refPoint.x = aX;
6982 event.refPoint.y = aY;
6984 return DispatchWindowEvent(&event);
6987 // Send a resize message to the listener
6988 PRBool nsWindow::OnResize(nsIntRect &aWindowRect)
6990 #ifdef CAIRO_HAS_D2D_SURFACE
6991 if (mD2DWindowSurface) {
6992 mD2DWindowSurface = NULL;
6993 Invalidate(PR_FALSE);
6995 #endif
6996 // call the event callback
6997 if (mEventCallback) {
6998 nsSizeEvent event(PR_TRUE, NS_SIZE, this);
6999 InitEvent(event);
7000 event.windowSize = &aWindowRect;
7001 RECT r;
7002 if (::GetWindowRect(mWnd, &r)) {
7003 event.mWinWidth = PRInt32(r.right - r.left);
7004 event.mWinHeight = PRInt32(r.bottom - r.top);
7005 } else {
7006 event.mWinWidth = 0;
7007 event.mWinHeight = 0;
7010 #if 0
7011 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7012 aWindowRect.x, aWindowRect.y, aWindowRect.width, aWindowRect.height,
7013 event.mWinWidth, event.mWinHeight);
7014 #endif
7016 return DispatchWindowEvent(&event);
7019 return PR_FALSE;
7022 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7023 PRBool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
7025 return PR_TRUE;
7027 #endif // !defined(WINCE)
7029 void nsWindow::OnSettingsChange(WPARAM wParam, LPARAM lParam)
7031 if (mWindowType == eWindowType_dialog ||
7032 mWindowType == eWindowType_toplevel )
7033 nsWindowGfx::OnSettingsChangeGfx(wParam);
7036 static PRBool IsOurProcessWindow(HWND aHWND)
7038 DWORD processId = 0;
7039 ::GetWindowThreadProcessId(aHWND, &processId);
7040 return processId == ::GetCurrentProcessId();
7043 static HWND FindOurProcessWindow(HWND aHWND)
7045 for (HWND wnd = ::GetParent(aHWND); wnd; wnd = ::GetParent(wnd)) {
7046 if (IsOurProcessWindow(wnd)) {
7047 return wnd;
7050 return nsnull;
7053 // Scrolling helper function for handling plugins.
7054 // Return value indicates whether the calling function should handle this
7055 // aHandled indicates whether this was handled at all
7056 // aQuitProcessing tells whether or not to continue processing the message
7057 PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
7058 LPARAM aLParam, PRBool& aHandled,
7059 LRESULT* aRetValue,
7060 PRBool& aQuitProcessing)
7062 // The scroll event will be dispatched to the toplevel
7063 // window. We need to give it to the child window
7064 aQuitProcessing = PR_FALSE; // default is to not stop processing
7065 POINT point;
7066 DWORD dwPoints = ::GetMessagePos();
7067 point.x = GET_X_LPARAM(dwPoints);
7068 point.y = GET_Y_LPARAM(dwPoints);
7070 static PRBool sIsProcessing = PR_FALSE;
7071 if (sIsProcessing) {
7072 return PR_TRUE; // the caller should handle this.
7075 static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
7076 if (aMsg == WM_MOUSEHWHEEL) {
7077 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7078 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7079 // message at first time, this time, ::GetMessagePos works fine.
7080 // Then, we will return 0 (0 means we process it) to the message. Then, the
7081 // driver will POST the same messages continuously during the wheel tilted.
7082 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7083 // cursor isn't 0,0. Therefore, we cannot trust the result of
7084 // ::GetMessagePos API if the sender is the driver.
7085 if (!sMayBeUsingLogitechMouse && aLParam == 0 && (DWORD)aLParam != dwPoints &&
7086 ::InSendMessage()) {
7087 sMayBeUsingLogitechMouse = PR_TRUE;
7088 } else if (sMayBeUsingLogitechMouse && aLParam != 0 && ::InSendMessage()) {
7089 // The user has changed the mouse from Logitech's to another one (e.g.,
7090 // the user has changed to the touchpad of the notebook.
7091 sMayBeUsingLogitechMouse = PR_FALSE;
7093 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7094 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7095 // instead.
7096 if (sMayBeUsingLogitechMouse && aLParam == 0 && dwPoints == 0) {
7097 ::GetCursorPos(&point);
7101 HWND destWnd = ::WindowFromPoint(point);
7102 // Since we receive scroll events for as long as
7103 // we are focused, it's entirely possible that there
7104 // is another app's window or no window under the
7105 // pointer.
7107 if (!destWnd) {
7108 // No window is under the pointer
7109 return PR_FALSE; // break, but continue processing
7112 nsWindow* destWindow;
7114 // We don't handle the message if the found window belongs to another
7115 // process's top window. If it belongs window, that is a plug-in's window.
7116 // Then, we need to send the message to the plug-in window.
7117 if (!IsOurProcessWindow(destWnd)) {
7118 HWND ourPluginWnd = FindOurProcessWindow(destWnd);
7119 if (!ourPluginWnd) {
7120 // Somebody elses window
7121 return PR_FALSE; // break, but continue processing
7123 destWindow = GetNSWindowPtr(ourPluginWnd);
7124 } else {
7125 destWindow = GetNSWindowPtr(destWnd);
7128 if (destWindow == this && mWindowType == eWindowType_plugin) {
7129 // If this is plug-in window, the message came from the plug-in window.
7130 // Then, the message should be processed on the parent window.
7131 destWindow = static_cast<nsWindow*>(GetParent());
7132 NS_ENSURE_TRUE(destWindow, PR_FALSE); // break, but continue processing
7133 destWnd = destWindow->mWnd;
7134 NS_ENSURE_TRUE(destWnd, PR_FALSE); // break, but continue processing
7137 if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
7138 // Some other app, or a plugin window.
7139 // Windows directs scrolling messages to the focused window.
7140 // However, Mozilla does not like plugins having focus, so a
7141 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7142 // Therefore, plugins etc _should_ get first grab at the
7143 // message, but this focus vaguary means the plugin misses
7144 // out. If the window is a child of ours, forward it on.
7145 // Determine if a child by walking the parent list until
7146 // we find a parent matching our wndproc.
7147 HWND parentWnd = ::GetParent(destWnd);
7148 while (parentWnd) {
7149 nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
7150 if (parentWindow) {
7151 // We have a child window - quite possibly a plugin window.
7152 // However, not all plugins are created equal - some will handle this
7153 // message themselves, some will forward directly back to us, while
7154 // others will call DefWndProc, which itself still forwards back to us.
7155 // So if we have sent it once, we need to handle it ourself.
7157 #ifdef MOZ_IPC
7158 // XXX The message shouldn't come from the plugin window at here.
7159 // But the message might come from it due to some bugs. If it happens,
7160 // SendMessage causes deadlock. For safety, we should unlock the
7161 // sender here.
7162 ::ReplyMessage(aMsg == WM_MOUSEHWHEEL ? TRUE : 0);
7163 #endif
7165 // First time we have seen this message.
7166 // Call the child - either it will consume it, or
7167 // it will wind it's way back to us,triggering the destWnd case above
7168 // either way,when the call returns,we are all done with the message,
7169 sIsProcessing = PR_TRUE;
7170 ::SendMessageW(destWnd, aMsg, aWParam, aLParam);
7171 sIsProcessing = PR_FALSE;
7172 aHandled = PR_TRUE;
7173 aQuitProcessing = PR_TRUE;
7174 return PR_FALSE; // break, and stop processing
7176 parentWnd = ::GetParent(parentWnd);
7177 } // while parentWnd
7179 if (destWnd == nsnull)
7180 return PR_FALSE;
7181 if (destWnd != mWnd) {
7182 if (destWindow) {
7183 sIsProcessing = PR_TRUE;
7184 aHandled = destWindow->ProcessMessage(aMsg, aWParam, aLParam, aRetValue);
7185 sIsProcessing = PR_FALSE;
7186 aQuitProcessing = PR_TRUE;
7187 return PR_FALSE; // break, and stop processing
7189 #ifdef DEBUG
7190 else
7191 printf("WARNING: couldn't get child window for SCROLL event\n");
7192 #endif
7194 return PR_TRUE; // caller should handle this
7197 PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
7199 static PRInt8 sMouseWheelEmulation = -1;
7200 if (sMouseWheelEmulation < 0) {
7201 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7202 NS_ENSURE_TRUE(prefs, PR_FALSE);
7203 nsCOMPtr<nsIPrefBranch> prefBranch;
7204 prefs->GetBranch(0, getter_AddRefs(prefBranch));
7205 NS_ENSURE_TRUE(prefBranch, PR_FALSE);
7206 PRBool emulate;
7207 nsresult rv =
7208 prefBranch->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate);
7209 NS_ENSURE_SUCCESS(rv, PR_FALSE);
7210 sMouseWheelEmulation = PRInt8(emulate);
7213 if (aLParam || sMouseWheelEmulation) {
7214 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7215 // Treat as a mousewheel message and scroll appropriately
7216 PRBool quit, result;
7217 LRESULT retVal;
7219 if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result, &retVal, quit))
7220 return quit; // Return if it's not our message or has been dispatched
7222 nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
7223 scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
7224 ? nsMouseScrollEvent::kIsVertical
7225 : nsMouseScrollEvent::kIsHorizontal;
7226 switch (LOWORD(aWParam))
7228 case SB_PAGEDOWN:
7229 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7230 case SB_LINEDOWN:
7231 scrollevent.delta = 1;
7232 break;
7233 case SB_PAGEUP:
7234 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7235 case SB_LINEUP:
7236 scrollevent.delta = -1;
7237 break;
7238 default:
7239 return PR_FALSE;
7241 #ifdef MOZ_IPC
7242 // The event may go to a plug-in which already dispatched this message.
7243 // Then, the event can cause deadlock. We should unlock the sender here.
7244 ::ReplyMessage(0);
7245 #endif
7246 scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
7247 scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
7248 scrollevent.isMeta = PR_FALSE;
7249 scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
7250 InitEvent(scrollevent);
7251 if (nsnull != mEventCallback)
7253 DispatchWindowEvent(&scrollevent);
7255 return PR_TRUE;
7258 // Scroll message generated by external application
7259 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_SCROLL, this);
7261 command.mScroll.mIsHorizontal = (aMsg == WM_HSCROLL);
7263 switch (LOWORD(aWParam))
7265 case SB_LINEUP: // SB_LINELEFT
7266 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7267 command.mScroll.mAmount = -1;
7268 break;
7269 case SB_LINEDOWN: // SB_LINERIGHT
7270 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7271 command.mScroll.mAmount = 1;
7272 break;
7273 case SB_PAGEUP: // SB_PAGELEFT
7274 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7275 command.mScroll.mAmount = -1;
7276 break;
7277 case SB_PAGEDOWN: // SB_PAGERIGHT
7278 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7279 command.mScroll.mAmount = 1;
7280 break;
7281 case SB_TOP: // SB_LEFT
7282 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7283 command.mScroll.mAmount = -1;
7284 break;
7285 case SB_BOTTOM: // SB_RIGHT
7286 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7287 command.mScroll.mAmount = 1;
7288 break;
7289 default:
7290 return PR_FALSE;
7292 DispatchWindowEvent(&command);
7293 return PR_TRUE;
7296 // Can be overriden. Controls auto-erase of background.
7297 PRBool nsWindow::AutoErase(HDC dc)
7299 return PR_FALSE;
7302 /**************************************************************
7303 **************************************************************
7305 ** BLOCK: IME management and accessibility
7307 ** Handles managing IME input and accessibility.
7309 **************************************************************
7310 **************************************************************/
7312 NS_IMETHODIMP nsWindow::ResetInputState()
7314 #ifdef DEBUG_KBSTATE
7315 printf("ResetInputState\n");
7316 #endif
7318 #ifdef NS_ENABLE_TSF
7319 nsTextStore::CommitComposition(PR_FALSE);
7320 #endif //NS_ENABLE_TSF
7322 nsIMM32Handler::CommitComposition(this);
7323 return NS_OK;
7326 NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState)
7328 #ifdef DEBUG_KBSTATE
7329 printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
7330 #endif
7332 #ifdef NS_ENABLE_TSF
7333 nsTextStore::SetIMEOpenState(aState);
7334 #endif //NS_ENABLE_TSF
7336 nsIMEContext IMEContext(mWnd);
7337 if (IMEContext.IsValid()) {
7338 ::ImmSetOpenStatus(IMEContext.get(), aState ? TRUE : FALSE);
7340 return NS_OK;
7343 NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState)
7345 nsIMEContext IMEContext(mWnd);
7346 if (IMEContext.IsValid()) {
7347 BOOL isOpen = ::ImmGetOpenStatus(IMEContext.get());
7348 *aState = isOpen ? PR_TRUE : PR_FALSE;
7349 } else
7350 *aState = PR_FALSE;
7352 #ifdef NS_ENABLE_TSF
7353 *aState |= nsTextStore::GetIMEOpenState();
7354 #endif //NS_ENABLE_TSF
7356 return NS_OK;
7359 NS_IMETHODIMP nsWindow::SetIMEEnabled(PRUint32 aState)
7361 #ifdef NS_ENABLE_TSF
7362 nsTextStore::SetIMEEnabled(aState);
7363 #endif //NS_ENABLE_TSF
7364 #ifdef DEBUG_KBSTATE
7365 printf("SetIMEEnabled: %s\n", (aState == nsIWidget::IME_STATUS_ENABLED ||
7366 aState == nsIWidget::IME_STATUS_PLUGIN)?
7367 "Enabled": "Disabled");
7368 #endif
7369 if (nsIMM32Handler::IsComposing()) {
7370 ResetInputState();
7372 mIMEEnabled = aState;
7373 PRBool enable = (aState == nsIWidget::IME_STATUS_ENABLED ||
7374 aState == nsIWidget::IME_STATUS_PLUGIN);
7376 #if defined(WINCE_HAVE_SOFTKB)
7377 sSoftKeyboardState = (aState != nsIWidget::IME_STATUS_DISABLED);
7378 nsWindowCE::ToggleSoftKB(mWnd, sSoftKeyboardState);
7379 #endif
7381 if (!enable != !mOldIMC)
7382 return NS_OK;
7383 mOldIMC = ::ImmAssociateContext(mWnd, enable ? mOldIMC : NULL);
7384 NS_ASSERTION(!enable || !mOldIMC, "Another IMC was associated");
7386 return NS_OK;
7389 NS_IMETHODIMP nsWindow::GetIMEEnabled(PRUint32* aState)
7391 #ifdef DEBUG_KBSTATE
7392 printf("GetIMEEnabled: %s\n", mIMEEnabled? "Enabled": "Disabled");
7393 #endif
7394 *aState = mIMEEnabled;
7395 return NS_OK;
7398 NS_IMETHODIMP nsWindow::CancelIMEComposition()
7400 #ifdef DEBUG_KBSTATE
7401 printf("CancelIMEComposition\n");
7402 #endif
7404 #ifdef NS_ENABLE_TSF
7405 nsTextStore::CommitComposition(PR_TRUE);
7406 #endif //NS_ENABLE_TSF
7408 nsIMM32Handler::CancelComposition(this);
7409 return NS_OK;
7412 NS_IMETHODIMP
7413 nsWindow::GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState)
7415 #ifdef DEBUG_KBSTATE
7416 printf("GetToggledKeyState\n");
7417 #endif
7418 NS_ENSURE_ARG_POINTER(aLEDState);
7419 *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
7420 return NS_OK;
7423 #ifdef NS_ENABLE_TSF
7424 NS_IMETHODIMP
7425 nsWindow::OnIMEFocusChange(PRBool aFocus)
7427 nsresult rv = nsTextStore::OnFocusChange(aFocus, this, mIMEEnabled);
7428 if (rv == NS_ERROR_NOT_AVAILABLE)
7429 rv = NS_ERROR_NOT_IMPLEMENTED; // TSF is not enabled, maybe.
7430 return rv;
7433 NS_IMETHODIMP
7434 nsWindow::OnIMETextChange(PRUint32 aStart,
7435 PRUint32 aOldEnd,
7436 PRUint32 aNewEnd)
7438 return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
7441 NS_IMETHODIMP
7442 nsWindow::OnIMESelectionChange(void)
7444 return nsTextStore::OnSelectionChange();
7446 #endif //NS_ENABLE_TSF
7448 #ifdef ACCESSIBILITY
7450 #ifdef DEBUG_WMGETOBJECT
7451 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
7452 nsAccessible* acc = aWnd ? \
7453 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
7454 printf(" acc: %p", acc); \
7455 if (acc) { \
7456 nsAutoString name; \
7457 acc->GetName(name); \
7458 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
7459 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
7460 void *hwnd = nsnull; \
7461 doc->GetWindowHandle(&hwnd); \
7462 printf(", acc hwnd: %d", hwnd); \
7465 #define NS_LOG_WMGETOBJECT_THISWND \
7467 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
7468 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p, content type: %d,\n",\
7469 mWnd, ::GetParent(mWnd), this, mContentType); \
7470 NS_LOG_WMGETOBJECT_WNDACC(this) \
7471 printf("\n }\n"); \
7474 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
7476 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
7477 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7478 aHwnd, ::GetParent(aHwnd), wnd); \
7479 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
7480 printf("\n }\n"); \
7482 #else
7483 #define NS_LOG_WMGETOBJECT_THISWND
7484 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
7485 #endif // DEBUG_WMGETOBJECT
7487 nsAccessible*
7488 nsWindow::GetRootAccessible()
7490 // We want the ability to forcibly disable a11y on windows, because
7491 // some non-a11y-related components attempt to bring it up. See bug
7492 // 538530 for details; we have a pref here that allows it to be disabled
7493 // for performance and testing resons.
7495 // This pref is checked only once, and the browser needs a restart to
7496 // pick up any changes.
7497 static int accForceDisable = -1;
7499 if (accForceDisable == -1) {
7500 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7501 PRBool b = PR_FALSE;
7502 nsresult rv = prefs->GetBoolPref("accessibility.win32.force_disabled", &b);
7503 if (NS_SUCCEEDED(rv) && b) {
7504 accForceDisable = 1;
7505 } else {
7506 accForceDisable = 0;
7510 // If the pref was true, return null here, disabling a11y.
7511 if (accForceDisable)
7512 return nsnull;
7514 nsWindow::sIsAccessibilityOn = TRUE;
7516 if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) {
7517 return nsnull;
7520 NS_LOG_WMGETOBJECT_THISWND
7522 if (mContentType != eContentTypeInherit) {
7523 // We're on a MozillaContentWindowClass or MozillaUIWindowClass window.
7524 // Search for the correct visible child window to get an accessible
7525 // document from. Make sure to use an active child window. If this window
7526 // doesn't have child windows then return an accessible for it.
7527 HWND accessibleWnd = ::GetTopWindow(mWnd);
7528 NS_LOG_WMGETOBJECT_WND("Top Window", accessibleWnd);
7529 if (!accessibleWnd) {
7530 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
7531 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
7534 nsWindow* accessibleWindow = nsnull;
7535 while (accessibleWnd) {
7536 // Loop through windows and find the first one with accessibility info
7537 accessibleWindow = GetNSWindowPtr(accessibleWnd);
7538 if (accessibleWindow) {
7539 nsAccessible *rootAccessible =
7540 accessibleWindow->DispatchAccessibleEvent(NS_GETACCESSIBLE);
7541 if (rootAccessible) {
7542 // Success, one of the child windows was active.
7543 return rootAccessible;
7546 accessibleWnd = ::GetNextWindow(accessibleWnd, GW_HWNDNEXT);
7547 NS_LOG_WMGETOBJECT_WND("Next Window", accessibleWnd);
7549 return nsnull;
7552 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
7553 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
7556 STDMETHODIMP_(LRESULT)
7557 nsWindow::LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc)
7559 // open the dll dynamically
7560 if (!sAccLib)
7561 sAccLib =::LoadLibraryW(L"OLEACC.DLL");
7563 if (sAccLib) {
7564 if (!sLresultFromObject)
7565 sLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(sAccLib,"LresultFromObject");
7567 if (sLresultFromObject)
7568 return sLresultFromObject(riid,wParam,pAcc);
7571 return 0;
7573 #endif
7575 /**************************************************************
7576 **************************************************************
7578 ** BLOCK: Transparency
7580 ** Window transparency helpers.
7582 **************************************************************
7583 **************************************************************/
7585 #ifdef MOZ_XUL
7587 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force)
7589 if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
7590 return;
7592 #ifdef CAIRO_HAS_D2D_SURFACE
7593 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7594 gfxWindowsPlatform::RENDER_DIRECT2D) {
7595 nsRefPtr<gfxD2DSurface> newSurface =
7596 new gfxD2DSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7597 mTransparentSurface = newSurface;
7598 mMemoryDC = nsnull;
7599 } else
7600 #endif
7602 nsRefPtr<gfxWindowsSurface> newSurface =
7603 new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7604 mTransparentSurface = newSurface;
7605 mMemoryDC = newSurface->GetDC();
7609 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
7611 #ifndef WINCE
7613 if (aMode == mTransparencyMode)
7614 return;
7616 // stop on dialogs and popups!
7617 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7618 nsWindow* parent = GetNSWindowPtr(hWnd);
7620 if (!parent)
7622 NS_WARNING("Trying to use transparent chrome in an embedded context");
7623 return;
7626 if (parent != this) {
7627 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
7630 if (aMode == eTransparencyTransparent) {
7631 // If we're switching to the use of a transparent window, hide the chrome
7632 // on our parent.
7633 HideWindowChrome(PR_TRUE);
7634 } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) {
7635 // if we're switching out of transparent, re-enable our parent's chrome.
7636 HideWindowChrome(PR_FALSE);
7639 LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE),
7640 exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
7642 if (parent->mIsVisible)
7643 style |= WS_VISIBLE;
7644 if (parent->mSizeMode == nsSizeMode_Maximized)
7645 style |= WS_MAXIMIZE;
7646 else if (parent->mSizeMode == nsSizeMode_Minimized)
7647 style |= WS_MINIMIZE;
7649 if (aMode == eTransparencyTransparent)
7650 exStyle |= WS_EX_LAYERED;
7651 else
7652 exStyle &= ~WS_EX_LAYERED;
7654 VERIFY_WINDOW_STYLE(style);
7655 ::SetWindowLongPtrW(hWnd, GWL_STYLE, style);
7656 ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle);
7658 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7659 if (HasGlass())
7660 memset(&mGlassMargins, 0, sizeof mGlassMargins);
7661 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7662 mTransparencyMode = aMode;
7664 SetupTranslucentWindowMemoryBitmap(aMode);
7665 UpdateGlass();
7666 #endif // #ifndef WINCE
7669 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
7671 if (eTransparencyTransparent == aMode) {
7672 ResizeTranslucentWindow(mBounds.width, mBounds.height, PR_TRUE);
7673 } else {
7674 mTransparentSurface = nsnull;
7675 mMemoryDC = NULL;
7679 nsresult nsWindow::UpdateTranslucentWindow()
7681 #ifndef WINCE
7682 if (mBounds.IsEmpty())
7683 return NS_OK;
7685 ::GdiFlush();
7687 BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
7688 SIZE winSize = { mBounds.width, mBounds.height };
7689 POINT srcPos = { 0, 0 };
7690 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7691 RECT winRect;
7692 ::GetWindowRect(hWnd, &winRect);
7694 #ifdef CAIRO_HAS_D2D_SURFACE
7695 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7696 gfxWindowsPlatform::RENDER_DIRECT2D) {
7697 mMemoryDC = static_cast<gfxD2DSurface*>(mTransparentSurface.get())->
7698 GetDC(PR_TRUE);
7700 #endif
7701 // perform the alpha blend
7702 PRBool updateSuccesful =
7703 ::UpdateLayeredWindow(hWnd, NULL, (POINT*)&winRect, &winSize, mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA);
7705 #ifdef CAIRO_HAS_D2D_SURFACE
7706 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7707 gfxWindowsPlatform::RENDER_DIRECT2D) {
7708 nsIntRect r(0, 0, 0, 0);
7709 static_cast<gfxD2DSurface*>(mTransparentSurface.get())->ReleaseDC(&r);
7711 #endif
7713 if (!updateSuccesful) {
7714 return NS_ERROR_FAILURE;
7716 #endif
7718 return NS_OK;
7721 #endif //MOZ_XUL
7723 /**************************************************************
7724 **************************************************************
7726 ** BLOCK: Popup rollup hooks
7728 ** Deals with CaptureRollup on popup windows.
7730 **************************************************************
7731 **************************************************************/
7733 #ifndef WINCE
7734 // Schedules a timer for a window, so we can rollup after processing the hook event
7735 void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId)
7737 // In some cases multiple hooks may be scheduled
7738 // so ignore any other requests once one timer is scheduled
7739 if (sHookTimerId == 0) {
7740 // Remember the window handle and the message ID to be used later
7741 sRollupMsgId = aMsgId;
7742 sRollupMsgWnd = aWnd;
7743 // Schedule native timer for doing the rollup after
7744 // this event is done being processed
7745 sHookTimerId = ::SetTimer(NULL, 0, 0, (TIMERPROC)HookTimerForPopups);
7746 NS_ASSERTION(sHookTimerId, "Timer couldn't be created.");
7750 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7751 int gLastMsgCode = 0;
7752 extern MSGFEventMsgInfo gMSGFEvents[];
7753 #endif
7755 // Process Menu messages, rollup when popup is clicked.
7756 LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam)
7758 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7759 if (sProcessHook) {
7760 MSG* pMsg = (MSG*)lParam;
7762 int inx = 0;
7763 while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != NULL) {
7764 inx++;
7766 if (code != gLastMsgCode) {
7767 if (gMSGFEvents[inx].mId == code) {
7768 #ifdef DEBUG
7769 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code, gMSGFEvents[inx].mStr, pMsg->hwnd);
7770 #endif
7771 } else {
7772 #ifdef DEBUG
7773 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code, gMSGFEvents[inx].mId, pMsg->hwnd);
7774 #endif
7776 gLastMsgCode = code;
7778 PrintEvent(pMsg->message, FALSE, FALSE);
7780 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7782 if (sProcessHook && code == MSGF_MENU) {
7783 MSG* pMsg = (MSG*)lParam;
7784 ScheduleHookTimer( pMsg->hwnd, pMsg->message);
7787 return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
7790 // Process all mouse messages. Roll up when a click is in a native window
7791 // that doesn't have an nsIWidget.
7792 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
7794 if (sProcessHook) {
7795 switch (wParam) {
7796 case WM_LBUTTONDOWN:
7797 case WM_RBUTTONDOWN:
7798 case WM_MBUTTONDOWN:
7799 case WM_MOUSEWHEEL:
7800 case WM_MOUSEHWHEEL:
7802 MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
7803 nsIWidget* mozWin = (nsIWidget*)GetNSWindowPtr(ms->hwnd);
7804 if (mozWin) {
7805 // If this window is windowed plugin window, the mouse events are not
7806 // sent to us.
7807 if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin)
7808 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7809 } else {
7810 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7812 break;
7816 return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam);
7819 // Process all messages. Roll up when the window is moving, or
7820 // is resizing or when maximized or mininized.
7821 LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam)
7823 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7824 if (sProcessHook) {
7825 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7826 PrintEvent(cwpt->message, FALSE, FALSE);
7828 #endif
7830 if (sProcessHook) {
7831 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7832 if (cwpt->message == WM_MOVING ||
7833 cwpt->message == WM_SIZING ||
7834 cwpt->message == WM_GETMINMAXINFO) {
7835 ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message);
7839 return ::CallNextHookEx(sCallProcHook, code, wParam, lParam);
7842 // Register the special "hooks" for dropdown processing.
7843 void nsWindow::RegisterSpecialDropdownHooks()
7845 NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!");
7846 NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!");
7848 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
7850 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
7852 // Install msg hook for moving the window and resizing
7853 if (!sMsgFilterHook) {
7854 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
7855 sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, NULL, GetCurrentThreadId());
7856 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7857 if (!sMsgFilterHook) {
7858 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
7860 #endif
7863 // Install msg hook for menus
7864 if (!sCallProcHook) {
7865 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
7866 sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, NULL, GetCurrentThreadId());
7867 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7868 if (!sCallProcHook) {
7869 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
7871 #endif
7874 // Install msg hook for the mouse
7875 if (!sCallMouseHook) {
7876 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
7877 sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, NULL, GetCurrentThreadId());
7878 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7879 if (!sCallMouseHook) {
7880 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
7882 #endif
7886 // Unhook special message hooks for dropdowns.
7887 void nsWindow::UnregisterSpecialDropdownHooks()
7889 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
7891 if (sCallProcHook) {
7892 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
7893 if (!::UnhookWindowsHookEx(sCallProcHook)) {
7894 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
7896 sCallProcHook = NULL;
7899 if (sMsgFilterHook) {
7900 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
7901 if (!::UnhookWindowsHookEx(sMsgFilterHook)) {
7902 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
7904 sMsgFilterHook = NULL;
7907 if (sCallMouseHook) {
7908 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
7909 if (!::UnhookWindowsHookEx(sCallMouseHook)) {
7910 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
7912 sCallMouseHook = NULL;
7916 // This timer is designed to only fire one time at most each time a "hook" function
7917 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
7918 // hook, but that hook event or a subsequent event may roll up the dropdown before
7919 // this timer function is executed.
7921 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
7922 // before this function fires.
7923 VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
7925 if (sHookTimerId != 0) {
7926 // if the window is NULL then we need to use the ID to kill the timer
7927 BOOL status = ::KillTimer(NULL, sHookTimerId);
7928 NS_ASSERTION(status, "Hook Timer was not killed.");
7929 sHookTimerId = 0;
7932 if (sRollupMsgId != 0) {
7933 // Note: DealWithPopups does the check to make sure that
7934 // sRollupListener and sRollupWidget are not NULL
7935 LRESULT popupHandlingResult;
7936 nsAutoRollup autoRollup;
7937 DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
7938 sRollupMsgId = 0;
7939 sRollupMsgWnd = NULL;
7942 #endif // WinCE
7944 BOOL CALLBACK nsWindow::ClearResourcesCallback(HWND aWnd, LPARAM aMsg)
7946 nsWindow *window = nsWindow::GetNSWindowPtr(aWnd);
7947 if (window) {
7948 window->ClearCachedResources();
7950 return TRUE;
7953 void
7954 nsWindow::ClearCachedResources()
7956 #ifdef CAIRO_HAS_D2D_SURFACE
7957 mD2DWindowSurface = nsnull;
7958 #endif
7959 if (mLayerManager &&
7960 mLayerManager->GetBackendType() == LayerManager::LAYERS_BASIC) {
7961 static_cast<BasicLayerManager*>(mLayerManager.get())->
7962 ClearCachedResources();
7964 ::EnumChildWindows(mWnd, nsWindow::ClearResourcesCallback, NULL);
7967 static PRBool IsDifferentThreadWindow(HWND aWnd)
7969 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, NULL);
7972 PRBool
7973 nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
7975 RECT r;
7977 #ifndef WINCE
7978 if (Msg == WM_ACTIVATEAPP)
7979 // don't care about activation/deactivation
7980 return PR_FALSE;
7981 #else
7982 if (Msg == WM_ACTIVATE)
7983 // but on Windows CE we do care about
7984 // activation/deactivation because there doesn't exist
7985 // cancelable Mouse Activation events
7986 return PR_TRUE;
7987 #endif
7989 ::GetWindowRect(aWindow->mWnd, &r);
7990 DWORD pos = ::GetMessagePos();
7991 POINT mp;
7992 mp.x = GET_X_LPARAM(pos);
7993 mp.y = GET_Y_LPARAM(pos);
7995 // was the event inside this window?
7996 return (PRBool) PtInRect(&r, mp);
7999 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8000 BOOL
8001 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
8003 if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
8005 if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
8006 inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
8007 (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam))
8008 #ifndef WINCE
8010 inMsg == WM_NCRBUTTONDOWN ||
8011 inMsg == WM_MOVING ||
8012 inMsg == WM_SIZING ||
8013 inMsg == WM_NCLBUTTONDOWN ||
8014 inMsg == WM_NCMBUTTONDOWN ||
8015 inMsg == WM_MOUSEACTIVATE ||
8016 inMsg == WM_ACTIVATEAPP ||
8017 inMsg == WM_MENUSELECT
8018 #endif
8021 // Rollup if the event is outside the popup.
8022 PRBool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)sRollupWidget);
8024 if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL))
8026 sRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
8027 *outResult = PR_TRUE;
8030 // If we're dealing with menus, we probably have submenus and we don't
8031 // want to rollup if the click is in a parent menu of the current submenu.
8032 PRUint32 popupsToRollup = PR_UINT32_MAX;
8033 if (rollup) {
8034 if ( sMenuRollup ) {
8035 nsAutoTArray<nsIWidget*, 5> widgetChain;
8036 PRUint32 sameTypeCount = sMenuRollup->GetSubmenuWidgetChain(&widgetChain);
8037 for ( PRUint32 i = 0; i < widgetChain.Length(); ++i ) {
8038 nsIWidget* widget = widgetChain[i];
8039 if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
8040 // don't roll up if the mouse event occurred within a menu of the
8041 // same type. If the mouse event occurred in a menu higher than
8042 // that, roll up, but pass the number of popups to Rollup so
8043 // that only those of the same type close up.
8044 if (i < sameTypeCount) {
8045 rollup = PR_FALSE;
8047 else {
8048 popupsToRollup = sameTypeCount;
8050 break;
8052 } // foreach parent menu widget
8053 } // if rollup listener knows about menus
8056 #ifndef WINCE
8057 if (inMsg == WM_MOUSEACTIVATE && popupsToRollup == PR_UINT32_MAX) {
8058 // Prevent the click inside the popup from causing a change in window
8059 // activation. Since the popup is shown non-activated, we need to eat
8060 // any requests to activate the window while it is displayed. Windows
8061 // will automatically activate the popup on the mousedown otherwise.
8062 if (!rollup) {
8063 *outResult = MA_NOACTIVATE;
8064 return TRUE;
8066 else
8068 UINT uMsg = HIWORD(inLParam);
8069 if (uMsg == WM_MOUSEMOVE)
8071 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8072 // must be enabled in Windows.
8073 sRollupListener->ShouldRollupOnMouseActivate(&rollup);
8074 if (!rollup)
8076 *outResult = MA_NOACTIVATE;
8077 return true;
8082 // if we've still determined that we should still rollup everything, do it.
8083 else
8084 #endif
8085 if ( rollup ) {
8086 // sRollupConsumeEvent may be modified by
8087 // nsIRollupListener::Rollup.
8088 PRBool consumeRollupEvent = sRollupConsumeEvent;
8089 // only need to deal with the last rollup for left mouse down events.
8090 sRollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN ? &mLastRollup : nsnull);
8092 // Tell hook to stop processing messages
8093 sProcessHook = PR_FALSE;
8094 sRollupMsgId = 0;
8095 sRollupMsgWnd = NULL;
8097 // return TRUE tells Windows that the event is consumed,
8098 // false allows the event to be dispatched
8100 // So if we are NOT supposed to be consuming events, let it go through
8101 if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
8102 *outResult = TRUE;
8103 return TRUE;
8105 #ifndef WINCE
8106 // if we are only rolling up some popups, don't activate and don't let
8107 // the event go through. This prevents clicks menus higher in the
8108 // chain from opening when a context menu is open
8109 if (popupsToRollup != PR_UINT32_MAX && inMsg == WM_MOUSEACTIVATE) {
8110 *outResult = MA_NOACTIVATEANDEAT;
8111 return TRUE;
8113 #endif
8115 } // if event that might trigger a popup to rollup
8116 } // if rollup listeners registered
8118 return FALSE;
8121 /**************************************************************
8122 **************************************************************
8124 ** BLOCK: Misc. utility methods and functions.
8126 ** General use.
8128 **************************************************************
8129 **************************************************************/
8131 // nsModifierKeyState used in various character processing.
8132 nsModifierKeyState::nsModifierKeyState()
8134 mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT);
8135 mIsControlDown = IS_VK_DOWN(NS_VK_CONTROL);
8136 mIsAltDown = IS_VK_DOWN(NS_VK_ALT);
8140 PRInt32 nsWindow::GetWindowsVersion()
8142 #ifdef WINCE
8143 return 0x500;
8144 #else
8145 static PRInt32 version = 0;
8146 static PRBool didCheck = PR_FALSE;
8148 if (!didCheck)
8150 didCheck = PR_TRUE;
8151 OSVERSIONINFOEX osInfo;
8152 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
8153 // This cast is safe and supposed to be here, don't worry
8154 ::GetVersionEx((OSVERSIONINFO*)&osInfo);
8155 version = (osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
8157 return version;
8158 #endif
8161 // Note that the result of GetTopLevelWindow method can be different from the
8162 // result of GetTopLevelHWND method. The result can be non-floating window.
8163 // Because our top level window may be contained in another window which is
8164 // not managed by us.
8165 nsWindow* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup)
8167 nsWindow* curWindow = this;
8169 while (PR_TRUE) {
8170 if (aStopOnDialogOrPopup) {
8171 switch (curWindow->mWindowType) {
8172 case eWindowType_dialog:
8173 case eWindowType_popup:
8174 return curWindow;
8175 default:
8176 break;
8180 // Retrieve the top level parent or owner window
8181 nsWindow* parentWindow = curWindow->GetParentWindow(PR_TRUE);
8183 if (!parentWindow)
8184 return curWindow;
8186 curWindow = parentWindow;
8190 // Note that the result of GetTopLevelHWND can be different from the result
8191 // of GetTopLevelWindow method. Because this is checking whether the window
8192 // is top level only in Win32 window system. Therefore, the result window
8193 // may not be managed by us.
8194 HWND nsWindow::GetTopLevelHWND(HWND aWnd, PRBool aStopOnDialogOrPopup)
8196 HWND curWnd = aWnd;
8197 HWND topWnd = NULL;
8198 HWND upWnd = NULL;
8200 while (curWnd) {
8201 topWnd = curWnd;
8203 if (aStopOnDialogOrPopup) {
8204 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8206 VERIFY_WINDOW_STYLE(style);
8208 if (!(style & WS_CHILD)) // first top-level window
8209 break;
8212 upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
8214 #ifdef WINCE
8215 // For dialog windows, we want just the parent, not the owner.
8216 // For other/popup windows, we want to find the first owner/parent
8217 // that's a dialog and/or has an owner.
8218 if (upWnd && ::GetWindow(curWnd, GW_OWNER) == upWnd) {
8219 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8220 if ((style & WS_DLGFRAME) != 0)
8221 break;
8223 #endif
8225 curWnd = upWnd;
8228 return topWnd;
8231 static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam)
8233 DWORD pid;
8234 ::GetWindowThreadProcessId(hwnd, &pid);
8235 if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd))
8237 gWindowsVisible = PR_TRUE;
8238 return FALSE;
8240 return TRUE;
8243 PRBool nsWindow::CanTakeFocus()
8245 gWindowsVisible = PR_FALSE;
8246 EnumWindows(gEnumWindowsProc, 0);
8247 if (!gWindowsVisible) {
8248 return PR_TRUE;
8249 } else {
8250 HWND fgWnd = ::GetForegroundWindow();
8251 if (!fgWnd) {
8252 return PR_TRUE;
8254 DWORD pid;
8255 GetWindowThreadProcessId(fgWnd, &pid);
8256 if (pid == GetCurrentProcessId()) {
8257 return PR_TRUE;
8260 return PR_FALSE;
8263 #if !defined(WINCE)
8264 void nsWindow::InitTrackPointHack()
8266 // Init Trackpoint Hack
8267 nsresult rv;
8268 PRInt32 lHackValue;
8269 long lResult;
8270 const WCHAR wstrKeys[][40] = {L"Software\\Lenovo\\TrackPoint",
8271 L"Software\\Lenovo\\UltraNav",
8272 L"Software\\Alps\\Apoint\\TrackPoint",
8273 L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
8274 L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
8275 // If anything fails turn the hack off
8276 sTrackPointHack = false;
8277 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8278 if(NS_SUCCEEDED(rv) && prefs) {
8279 prefs->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue);
8280 switch (lHackValue) {
8281 // 0 means hack disabled
8282 case 0:
8283 break;
8284 // 1 means hack enabled
8285 case 1:
8286 sTrackPointHack = true;
8287 break;
8288 // -1 means autodetect
8289 case -1:
8290 for(unsigned i = 0; i < NS_ARRAY_LENGTH(wstrKeys); i++) {
8291 HKEY hKey;
8292 lResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, (LPCWSTR)&wstrKeys[i],
8293 0, KEY_READ, &hKey);
8294 ::RegCloseKey(hKey);
8295 if(lResult == ERROR_SUCCESS) {
8296 // If we detected a registry key belonging to a TrackPoint driver
8297 // Turn on the hack
8298 sTrackPointHack = true;
8299 break;
8302 break;
8303 // Shouldn't be any other values, but treat them as disabled
8304 default:
8305 break;
8308 return;
8310 #endif // #if !defined(WINCE)
8312 LPARAM nsWindow::lParamToScreen(LPARAM lParam)
8314 POINT pt;
8315 pt.x = GET_X_LPARAM(lParam);
8316 pt.y = GET_Y_LPARAM(lParam);
8317 ::ClientToScreen(mWnd, &pt);
8318 return MAKELPARAM(pt.x, pt.y);
8321 LPARAM nsWindow::lParamToClient(LPARAM lParam)
8323 POINT pt;
8324 pt.x = GET_X_LPARAM(lParam);
8325 pt.y = GET_Y_LPARAM(lParam);
8326 ::ScreenToClient(mWnd, &pt);
8327 return MAKELPARAM(pt.x, pt.y);
8330 /**************************************************************
8331 **************************************************************
8333 ** BLOCK: ChildWindow impl.
8335 ** Child window overrides.
8337 **************************************************************
8338 **************************************************************/
8340 // return the style for a child nsWindow
8341 DWORD ChildWindow::WindowStyle()
8343 DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle();
8344 if (!(style & WS_POPUP))
8345 style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
8346 VERIFY_WINDOW_STYLE(style);
8347 return style;