Bug 575693 - Download Manager and Page Info no longer have an accessible tree, r...
[mozilla-central.git] / widget / src / windows / nsWindow.cpp
blob16e7c4009bb1ae5992e23f187f8900f5dce19b0f
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"
161 #if defined(WINCE)
162 #include "nsWindowCE.h"
163 #endif
165 #if defined(WINCE_WINDOWS_MOBILE)
166 #define KILL_PRIORITY_ID 2444
167 #endif
169 #include "nsWindowGfx.h"
170 #include "gfxWindowsPlatform.h"
171 #include "Layers.h"
172 #ifndef WINCE
173 #ifdef MOZ_ENABLE_D3D9_LAYER
174 #include "LayerManagerD3D9.h"
175 #endif
176 #include "LayerManagerOGL.h"
177 #endif
179 #if !defined(WINCE)
180 #include "nsUXThemeConstants.h"
181 #include "nsKeyboardLayout.h"
182 #include "nsNativeDragTarget.h"
183 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
184 #include <zmouse.h>
185 #include <pbt.h>
186 #include <richedit.h>
187 #endif // !defined(WINCE)
189 #if defined(ACCESSIBILITY)
190 #include "oleidl.h"
191 #include <winuser.h>
192 #include "nsIAccessibleDocument.h"
193 #if !defined(WINABLEAPI)
194 #include <winable.h>
195 #endif // !defined(WINABLEAPI)
196 #endif // defined(ACCESSIBILITY)
198 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
199 #include "nsIWinTaskbar.h"
200 #endif
202 #if defined(NS_ENABLE_TSF)
203 #include "nsTextStore.h"
204 #endif // defined(NS_ENABLE_TSF)
206 #if defined(MOZ_SPLASHSCREEN)
207 #include "nsSplashScreen.h"
208 #endif // defined(MOZ_SPLASHSCREEN)
210 // Windowless plugin support
211 #include "npapi.h"
213 #include "nsWindowDefs.h"
215 #include "mozilla/FunctionTimer.h"
217 #ifdef WINCE_WINDOWS_MOBILE
218 #include "nsGfxCIID.h"
219 #endif
221 #include "mozilla/FunctionTimer.h"
223 /**************************************************************
224 **************************************************************
226 ** BLOCK: Variables
228 ** nsWindow Class static initializations and global variables.
230 **************************************************************
231 **************************************************************/
233 /**************************************************************
235 * SECTION: nsWindow statics
237 **************************************************************/
239 PRUint32 nsWindow::sInstanceCount = 0;
240 PRBool nsWindow::sSwitchKeyboardLayout = PR_FALSE;
241 BOOL nsWindow::sIsRegistered = FALSE;
242 BOOL nsWindow::sIsPopupClassRegistered = FALSE;
243 BOOL nsWindow::sIsOleInitialized = FALSE;
244 HCURSOR nsWindow::sHCursor = NULL;
245 imgIContainer* nsWindow::sCursorImgContainer = nsnull;
246 nsWindow* nsWindow::sCurrentWindow = nsnull;
247 PRBool nsWindow::sJustGotDeactivate = PR_FALSE;
248 PRBool nsWindow::sJustGotActivate = PR_FALSE;
250 // imported in nsWidgetFactory.cpp
251 TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN;
253 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
254 // hook methods whether they should be processing the hook
255 // messages.
256 HHOOK nsWindow::sMsgFilterHook = NULL;
257 HHOOK nsWindow::sCallProcHook = NULL;
258 HHOOK nsWindow::sCallMouseHook = NULL;
259 PRPackedBool nsWindow::sProcessHook = PR_FALSE;
260 UINT nsWindow::sRollupMsgId = 0;
261 HWND nsWindow::sRollupMsgWnd = NULL;
262 UINT nsWindow::sHookTimerId = 0;
264 // Rollup Listener
265 nsIRollupListener* nsWindow::sRollupListener = nsnull;
266 nsIMenuRollup* nsWindow::sMenuRollup = nsnull;
267 nsIWidget* nsWindow::sRollupWidget = nsnull;
268 PRBool nsWindow::sRollupConsumeEvent = PR_FALSE;
270 // Mouse Clicks - static variable definitions for figuring
271 // out 1 - 3 Clicks.
272 POINT nsWindow::sLastMousePoint = {0};
273 POINT nsWindow::sLastMouseMovePoint = {0};
274 LONG nsWindow::sLastMouseDownTime = 0L;
275 LONG nsWindow::sLastClickCount = 0L;
276 BYTE nsWindow::sLastMouseButton = 0;
278 // Trim heap on minimize. (initialized, but still true.)
279 int nsWindow::sTrimOnMinimize = 2;
281 // Default Trackpoint Hack to off
282 PRBool nsWindow::sTrackPointHack = PR_FALSE;
284 #ifdef ACCESSIBILITY
285 BOOL nsWindow::sIsAccessibilityOn = FALSE;
286 // Accessibility wm_getobject handler
287 HINSTANCE nsWindow::sAccLib = 0;
288 LPFNLRESULTFROMOBJECT
289 nsWindow::sLresultFromObject = 0;
290 #endif // ACCESSIBILITY
292 #ifdef MOZ_IPC
293 // Used in OOPP plugin focus processing.
294 const PRUnichar* kOOPPPluginFocusEventId = L"OOPP Plugin Focus Widget Event";
295 PRUint32 nsWindow::sOOPPPluginFocusEvent =
296 RegisterWindowMessageW(kOOPPPluginFocusEventId);
297 #endif
299 /**************************************************************
301 * SECTION: globals variables
303 **************************************************************/
305 static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
307 #ifdef PR_LOGGING
308 PRLogModuleInfo* gWindowsLog = nsnull;
309 #endif
311 #ifndef WINCE
312 // Kbd layout. Used throughout character processing.
313 static KeyboardLayout gKbdLayout;
314 #endif
316 #ifdef WINCE_WINDOWS_MOBILE
317 // HTC Navigation Wheel Event
318 // This is the defined value for Gesture Mode
319 const int WM_HTCNAV = 0x0400 + 200;
321 typedef int (__stdcall * HTCApiNavOpen)(HANDLE, int);
322 typedef int (__stdcall * HTCApiNavSetMode)(HANDLE, unsigned int);
324 HTCApiNavOpen gHTCApiNavOpen = nsnull;
325 HTCApiNavSetMode gHTCApiNavSetMode = nsnull;
326 static PRBool gCheckForHTCApi = PR_FALSE;
327 #endif
329 // Global user preference for disabling native theme. Used
330 // in NativeWindowTheme.
331 PRBool gDisableNativeTheme = PR_FALSE;
333 // Global used in Show window enumerations.
334 static PRBool gWindowsVisible = PR_FALSE;
336 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
337 #ifdef WINCE_WINDOWS_MOBILE
338 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
339 #endif
341 /**************************************************************
342 **************************************************************
344 ** BLOCK: nsIWidget impl.
346 ** nsIWidget interface implementation, broken down into
347 ** sections.
349 **************************************************************
350 **************************************************************/
352 /**************************************************************
354 * SECTION: nsWindow construction and destruction
356 **************************************************************/
358 nsWindow::nsWindow() : nsBaseWidget()
360 #ifdef PR_LOGGING
361 if (!gWindowsLog)
362 gWindowsLog = PR_NewLogModule("nsWindowsWidgets");
363 #endif
365 mWnd = nsnull;
366 mPaintDC = nsnull;
367 mPrevWndProc = nsnull;
368 mOldIMC = nsnull;
369 mNativeDragTarget = nsnull;
370 mInDtor = PR_FALSE;
371 mIsVisible = PR_FALSE;
372 mIsInMouseCapture = PR_FALSE;
373 mIsTopWidgetWindow = PR_FALSE;
374 mUnicodeWidget = PR_TRUE;
375 mDisplayPanFeedback = PR_FALSE;
376 mCustomNonClient = PR_FALSE;
377 mCompositorFlag = PR_FALSE;
378 mHideChrome = PR_FALSE;
379 mWindowType = eWindowType_child;
380 mBorderStyle = eBorderStyle_default;
381 mPopupType = ePopupTypeAny;
382 mOldSizeMode = nsSizeMode_Normal;
383 mLastPoint.x = 0;
384 mLastPoint.y = 0;
385 mLastSize.width = 0;
386 mLastSize.height = 0;
387 mOldStyle = 0;
388 mOldExStyle = 0;
389 mPainting = 0;
390 mExitToNonClientArea = 0;
391 mLastKeyboardLayout = 0;
392 mBlurSuppressLevel = 0;
393 mIMEEnabled = nsIWidget::IME_STATUS_ENABLED;
394 #ifdef MOZ_XUL
395 mTransparentSurface = nsnull;
396 mMemoryDC = nsnull;
397 mTransparencyMode = eTransparencyOpaque;
398 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
399 memset(&mGlassMargins, 0, sizeof mGlassMargins);
400 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
401 #endif
402 mBackground = ::GetSysColor(COLOR_BTNFACE);
403 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
404 mForeground = ::GetSysColor(COLOR_WINDOWTEXT);
406 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
407 mTaskbarPreview = nsnull;
408 mHasTaskbarIconBeenCreated = PR_FALSE;
409 #endif
411 // Global initialization
412 if (!sInstanceCount) {
413 #if !defined(WINCE)
414 gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
415 #endif
417 // Init IME handler
418 nsIMM32Handler::Initialize();
420 #ifdef NS_ENABLE_TSF
421 nsTextStore::Initialize();
422 #endif
424 #if !defined(WINCE)
425 if (SUCCEEDED(::OleInitialize(NULL)))
426 sIsOleInitialized = TRUE;
427 NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
428 #endif
430 #if defined(HEAP_DUMP_EVENT)
431 InitHeapDump();
432 #endif
434 #if !defined(WINCE)
435 InitTrackPointHack();
436 #endif
437 } // !sInstanceCount
439 mIdleService = nsnull;
441 sInstanceCount++;
444 nsWindow::~nsWindow()
446 mInDtor = PR_TRUE;
448 // If the widget was released without calling Destroy() then the native window still
449 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
451 // XXX How could this happen???
452 if (NULL != mWnd)
453 Destroy();
455 sInstanceCount--;
457 // Global shutdown
458 if (sInstanceCount == 0) {
459 #ifdef NS_ENABLE_TSF
460 nsTextStore::Terminate();
461 #endif
463 #if !defined(WINCE)
464 NS_IF_RELEASE(sCursorImgContainer);
465 if (sIsOleInitialized) {
466 ::OleFlushClipboard();
467 ::OleUninitialize();
468 sIsOleInitialized = FALSE;
470 // delete any of the IME structures that we allocated
471 nsIMM32Handler::Terminate();
472 #endif // !defined(WINCE)
475 #if !defined(WINCE)
476 NS_IF_RELEASE(mNativeDragTarget);
477 #endif // !defined(WINCE)
480 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
482 /**************************************************************
484 * SECTION: nsIWidget::Create, nsIWidget::Destroy
486 * Creating and destroying windows for this widget.
488 **************************************************************/
490 // Allow Derived classes to modify the height that is passed
491 // when the window is created or resized. Also add extra height
492 // if needed (on Windows CE)
493 PRInt32 nsWindow::GetHeight(PRInt32 aProposedHeight)
495 PRInt32 extra = 0;
497 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
498 DWORD style = WindowStyle();
499 if ((style & WS_SYSMENU) && (style & WS_POPUP)) {
500 extra = GetSystemMetrics(SM_CYCAPTION);
502 #endif
504 return aProposedHeight + extra;
507 // Create the proper widget
508 nsresult
509 nsWindow::Create(nsIWidget *aParent,
510 nsNativeWidget aNativeParent,
511 const nsIntRect &aRect,
512 EVENT_CALLBACK aHandleEventFunction,
513 nsIDeviceContext *aContext,
514 nsIAppShell *aAppShell,
515 nsIToolkit *aToolkit,
516 nsWidgetInitData *aInitData)
518 if (aInitData)
519 mUnicodeWidget = aInitData->mUnicode;
521 nsIWidget *baseParent = aInitData &&
522 (aInitData->mWindowType == eWindowType_dialog ||
523 aInitData->mWindowType == eWindowType_toplevel ||
524 aInitData->mWindowType == eWindowType_invisible) ?
525 nsnull : aParent;
527 mIsTopWidgetWindow = (nsnull == baseParent);
528 mBounds.width = aRect.width;
529 mBounds.height = aRect.height;
531 BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
532 aAppShell, aToolkit, aInitData);
534 HWND parent;
535 if (aParent) { // has a nsIWidget parent
536 parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : NULL;
537 mParent = aParent;
538 } else { // has a nsNative parent
539 parent = (HWND)aNativeParent;
540 mParent = aNativeParent ? GetNSWindowPtr((HWND)aNativeParent) : nsnull;
543 if (nsnull != aInitData) {
544 mPopupType = aInitData->mPopupHint;
547 mContentType = aInitData ? aInitData->mContentType : eContentTypeInherit;
549 DWORD style = WindowStyle();
550 DWORD extendedStyle = WindowExStyle();
552 if (aInitData->mRTL) {
553 extendedStyle |= WS_EX_LAYOUTRTL | WS_EX_NOINHERITLAYOUT;
556 if (mWindowType == eWindowType_popup) {
557 // if a parent was specified, don't use WS_EX_TOPMOST so that the popup
558 // only appears above the parent, instead of all windows
559 if (aParent)
560 extendedStyle = WS_EX_TOOLWINDOW;
561 else
562 parent = NULL;
563 } else if (mWindowType == eWindowType_invisible) {
564 // Make sure CreateWindowEx succeeds at creating a toplevel window
565 style &= ~0x40000000; // WS_CHILDWINDOW
566 } else if (nsnull != aInitData) {
567 // See if the caller wants to explictly set clip children and clip siblings
568 if (aInitData->clipChildren) {
569 style |= WS_CLIPCHILDREN;
570 } else {
571 style &= ~WS_CLIPCHILDREN;
573 if (aInitData->clipSiblings) {
574 style |= WS_CLIPSIBLINGS;
578 mWnd = ::CreateWindowExW(extendedStyle,
579 aInitData && aInitData->mDropShadow ?
580 WindowPopupClass() : WindowClass(),
581 L"",
582 style,
583 aRect.x,
584 aRect.y,
585 aRect.width,
586 GetHeight(aRect.height),
587 parent,
588 NULL,
589 nsToolkit::mDllInstance,
590 NULL);
592 if (!mWnd) {
593 NS_WARNING("nsWindow CreateWindowEx failed.");
594 return NS_ERROR_FAILURE;
597 if (nsWindow::sTrackPointHack &&
598 mWindowType != eWindowType_plugin &&
599 mWindowType != eWindowType_invisible) {
600 // Ugly Thinkpad Driver Hack (Bug 507222)
601 // We create an invisible scrollbar to trick the
602 // Trackpoint driver into sending us scrolling messages
603 ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTSCROLLBAR",
604 WS_CHILD | WS_VISIBLE, 0,0,0,0, mWnd, NULL,
605 nsToolkit::mDllInstance, NULL);
608 // call the event callback to notify about creation
610 DispatchStandardEvent(NS_CREATE);
611 SubclassWindow(TRUE);
613 if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
614 /* The internal variable set by the config.trim_on_minimize pref
615 has not yet been initialized, and this is the hidden window
616 (conveniently created before any visible windows, and after
617 the profile has been initialized).
619 Default config.trim_on_minimize to false, to fix bug 76831
620 for good. If anyone complains about this new default, saying
621 that a Mozilla app hogs too much memory while minimized, they
622 will have that entire bug tattooed on their backside. */
624 sTrimOnMinimize = 0;
625 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
626 if (prefs) {
627 nsCOMPtr<nsIPrefBranch> prefBranch;
628 prefs->GetBranch(0, getter_AddRefs(prefBranch));
629 if (prefBranch) {
631 PRBool temp;
632 if (NS_SUCCEEDED(prefBranch->GetBoolPref("config.trim_on_minimize",
633 &temp))
634 && temp)
635 sTrimOnMinimize = 1;
637 if (NS_SUCCEEDED(prefBranch->GetBoolPref("intl.keyboard.per_window_layout",
638 &temp)))
639 sSwitchKeyboardLayout = temp;
641 if (NS_SUCCEEDED(prefBranch->GetBoolPref("mozilla.widget.disable-native-theme",
642 &temp)))
643 gDisableNativeTheme = temp;
647 #if defined(WINCE_HAVE_SOFTKB)
648 if (mWindowType == eWindowType_dialog || mWindowType == eWindowType_toplevel )
649 nsWindowCE::CreateSoftKeyMenuBar(mWnd);
650 #endif
652 return NS_OK;
655 // Close this nsWindow
656 NS_METHOD nsWindow::Destroy()
658 // WM_DESTROY has already fired, we're done.
659 if (nsnull == mWnd)
660 return NS_OK;
662 // During the destruction of all of our children, make sure we don't get deleted.
663 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
666 * On windows the LayerManagerOGL destructor wants the widget to be around for
667 * cleanup. It also would like to have the HWND intact, so we NULL it here.
669 mLayerManager = NULL;
671 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
672 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
673 // from it. The function also destroys the window's menu, flushes the thread message queue,
674 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
675 // the window is at the top of the viewer chain).
677 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
678 // the associated child or owned windows when it destroys the parent or owner window. The
679 // function first destroys child or owned windows, and then it destroys the parent or owner
680 // window.
681 VERIFY(::DestroyWindow(mWnd));
683 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
684 // didn't get called, call it now.
685 if (PR_FALSE == mOnDestroyCalled)
686 OnDestroy();
688 return NS_OK;
691 /**************************************************************
693 * SECTION: Window class utilities
695 * Utilities for calculating the proper window class name for
696 * Create window.
698 **************************************************************/
700 // Return the proper window class for everything except popups.
701 LPCWSTR nsWindow::WindowClass()
703 if (!nsWindow::sIsRegistered) {
704 WNDCLASSW wc;
706 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
707 wc.style = CS_DBLCLKS;
708 wc.lpfnWndProc = ::DefWindowProcW;
709 wc.cbClsExtra = 0;
710 wc.cbWndExtra = 0;
711 wc.hInstance = nsToolkit::mDllInstance;
712 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
713 wc.hCursor = NULL;
714 wc.hbrBackground = mBrush;
715 wc.lpszMenuName = NULL;
716 wc.lpszClassName = kClassNameHidden;
718 BOOL succeeded = ::RegisterClassW(&wc) != 0 &&
719 ERROR_CLASS_ALREADY_EXISTS != GetLastError();
720 nsWindow::sIsRegistered = succeeded;
722 wc.lpszClassName = kClassNameContentFrame;
723 if (!::RegisterClassW(&wc) &&
724 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
725 nsWindow::sIsRegistered = FALSE;
728 wc.lpszClassName = kClassNameContent;
729 if (!::RegisterClassW(&wc) &&
730 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
731 nsWindow::sIsRegistered = FALSE;
734 wc.lpszClassName = kClassNameUI;
735 if (!::RegisterClassW(&wc) &&
736 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
737 nsWindow::sIsRegistered = FALSE;
740 wc.lpszClassName = kClassNameGeneral;
741 ATOM generalClassAtom = ::RegisterClassW(&wc);
742 if (!generalClassAtom &&
743 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
744 nsWindow::sIsRegistered = FALSE;
747 wc.lpszClassName = kClassNameDialog;
748 wc.hIcon = 0;
749 if (!::RegisterClassW(&wc) &&
750 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
751 nsWindow::sIsRegistered = FALSE;
755 if (mWindowType == eWindowType_invisible) {
756 return kClassNameHidden;
758 if (mWindowType == eWindowType_dialog) {
759 return kClassNameDialog;
761 if (mContentType == eContentTypeContent) {
762 return kClassNameContent;
764 if (mContentType == eContentTypeContentFrame) {
765 return kClassNameContentFrame;
767 if (mContentType == eContentTypeUI) {
768 return kClassNameUI;
770 return kClassNameGeneral;
773 // Return the proper popup window class
774 LPCWSTR nsWindow::WindowPopupClass()
776 if (!nsWindow::sIsPopupClassRegistered) {
777 WNDCLASSW wc;
779 wc.style = CS_DBLCLKS | CS_XP_DROPSHADOW;
780 wc.lpfnWndProc = ::DefWindowProcW;
781 wc.cbClsExtra = 0;
782 wc.cbWndExtra = 0;
783 wc.hInstance = nsToolkit::mDllInstance;
784 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
785 wc.hCursor = NULL;
786 wc.hbrBackground = mBrush;
787 wc.lpszMenuName = NULL;
788 wc.lpszClassName = kClassNameDropShadow;
790 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
791 if (!nsWindow::sIsPopupClassRegistered) {
792 // For older versions of Win32 (i.e., not XP), the registration will
793 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
794 wc.style = CS_DBLCLKS;
795 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
799 return kClassNameDropShadow;
802 /**************************************************************
804 * SECTION: Window styles utilities
806 * Return the proper windows styles and extended styles.
808 **************************************************************/
810 // Return nsWindow styles
811 #if !defined(WINCE) // implemented in nsWindowCE.cpp
812 DWORD nsWindow::WindowStyle()
814 DWORD style;
816 switch (mWindowType) {
817 case eWindowType_plugin:
818 case eWindowType_child:
819 style = WS_OVERLAPPED;
820 break;
822 case eWindowType_dialog:
823 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK |
824 DS_MODALFRAME | WS_CLIPCHILDREN;
825 if (mBorderStyle != eBorderStyle_default)
826 style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
827 break;
829 case eWindowType_popup:
830 style = WS_POPUP;
831 if (mTransparencyMode != eTransparencyGlass) {
832 style |= WS_OVERLAPPED;
834 break;
836 default:
837 NS_ERROR("unknown border style");
838 // fall through
840 case eWindowType_toplevel:
841 case eWindowType_invisible:
842 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU |
843 WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
844 break;
847 if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) {
848 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border))
849 style &= ~WS_BORDER;
851 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) {
852 style &= ~WS_DLGFRAME;
853 style |= WS_POPUP;
854 style &= ~WS_CHILD;
857 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close))
858 style &= ~0;
859 // XXX The close box can only be removed by changing the window class,
860 // as far as I know --- roc+moz@cs.cmu.edu
862 if (mBorderStyle == eBorderStyle_none ||
863 !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
864 style &= ~WS_SYSMENU;
865 // Looks like getting rid of the system menu also does away with the
866 // close box. So, we only get rid of the system menu if you want neither it
867 // nor the close box. How does the Windows "Dialog" window class get just
868 // closebox and no sysmenu? Who knows.
870 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh))
871 style &= ~WS_THICKFRAME;
873 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize))
874 style &= ~WS_MINIMIZEBOX;
876 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize))
877 style &= ~WS_MAXIMIZEBOX;
879 VERIFY_WINDOW_STYLE(style);
880 return style;
882 #endif // !defined(WINCE)
884 // Return nsWindow extended styles
885 DWORD nsWindow::WindowExStyle()
887 switch (mWindowType)
889 case eWindowType_plugin:
890 case eWindowType_child:
891 return 0;
893 case eWindowType_dialog:
894 return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
896 case eWindowType_popup:
897 return
898 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
899 WS_EX_NOACTIVATE |
900 #endif
901 WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
903 default:
904 NS_ERROR("unknown border style");
905 // fall through
907 case eWindowType_toplevel:
908 case eWindowType_invisible:
909 return WS_EX_WINDOWEDGE;
913 /**************************************************************
915 * SECTION: Window subclassing utilities
917 * Set or clear window subclasses on native windows. Used in
918 * Create and Destroy.
920 **************************************************************/
922 // Subclass (or remove the subclass from) this component's nsWindow
923 void nsWindow::SubclassWindow(BOOL bState)
925 if (NULL != mWnd) {
926 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
927 if (!::IsWindow(mWnd)) {
928 NS_ERROR("Invalid window handle");
931 if (bState) {
932 // change the nsWindow proc
933 if (mUnicodeWidget)
934 mPrevWndProc = (WNDPROC)::SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
935 (LONG_PTR)nsWindow::WindowProc);
936 else
937 mPrevWndProc = (WNDPROC)::SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
938 (LONG_PTR)nsWindow::WindowProc);
939 NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
940 // connect the this pointer to the nsWindow handle
941 SetNSWindowPtr(mWnd, this);
943 else {
944 if (mUnicodeWidget)
945 ::SetWindowLongPtrW(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
946 else
947 ::SetWindowLongPtrA(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
948 SetNSWindowPtr(mWnd, NULL);
949 mPrevWndProc = NULL;
954 /**************************************************************
956 * SECTION: Window properties
958 * Set and clear native window properties.
960 **************************************************************/
962 static PRUnichar sPropName[40] = L"";
963 static PRUnichar* GetNSWindowPropName()
965 if (!*sPropName)
967 _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p", GetCurrentProcessId());
968 sPropName[39] = '\0';
970 return sPropName;
973 nsWindow * nsWindow::GetNSWindowPtr(HWND aWnd)
975 return (nsWindow *) ::GetPropW(aWnd, GetNSWindowPropName());
978 BOOL nsWindow::SetNSWindowPtr(HWND aWnd, nsWindow * ptr)
980 if (ptr == NULL) {
981 ::RemovePropW(aWnd, GetNSWindowPropName());
982 return TRUE;
983 } else {
984 return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)ptr);
988 /**************************************************************
990 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
992 * Set or clear the parent widgets using window properties, and
993 * handles calculating native parent handles.
995 **************************************************************/
997 // Get and set parent widgets
998 NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent)
1000 mParent = aNewParent;
1002 if (aNewParent) {
1003 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1005 nsIWidget* parent = GetParent();
1006 if (parent) {
1007 parent->RemoveChild(this);
1010 HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
1011 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
1012 if (newParent && mWnd) {
1013 ::SetParent(mWnd, newParent);
1016 aNewParent->AddChild(this);
1018 return NS_OK;
1021 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1023 nsIWidget* parent = GetParent();
1025 if (parent) {
1026 parent->RemoveChild(this);
1029 if (mWnd) {
1030 // If we have no parent, SetParent should return the desktop.
1031 VERIFY(::SetParent(mWnd, nsnull));
1034 return NS_OK;
1037 nsIWidget* nsWindow::GetParent(void)
1039 return GetParentWindow(PR_FALSE);
1042 nsWindow* nsWindow::GetParentWindow(PRBool aIncludeOwner)
1044 if (mIsTopWidgetWindow) {
1045 // Must use a flag instead of mWindowType to tell if the window is the
1046 // owned by the topmost widget, because a child window can be embedded inside
1047 // a HWND which is not associated with a nsIWidget.
1048 return nsnull;
1051 // If this widget has already been destroyed, pretend we have no parent.
1052 // This corresponds to code in Destroy which removes the destroyed
1053 // widget from its parent's child list.
1054 if (mInDtor || mOnDestroyCalled)
1055 return nsnull;
1058 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1059 // root owner. aIncludeOwner set to false implies the search will stop at the
1060 // true parent (default).
1061 nsWindow* widget = nsnull;
1062 if (mWnd) {
1063 #ifdef WINCE
1064 HWND parent = ::GetParent(mWnd);
1065 #else
1066 HWND parent = nsnull;
1067 if (aIncludeOwner)
1068 parent = ::GetParent(mWnd);
1069 else
1070 parent = ::GetAncestor(mWnd, GA_PARENT);
1071 #endif
1072 if (parent) {
1073 widget = GetNSWindowPtr(parent);
1074 if (widget) {
1075 // If the widget is in the process of being destroyed then
1076 // do NOT return it
1077 if (widget->mInDtor) {
1078 widget = nsnull;
1084 return widget;
1087 /**************************************************************
1089 * SECTION: nsIWidget::Show
1091 * Hide or show this component.
1093 **************************************************************/
1095 NS_METHOD nsWindow::Show(PRBool bState)
1097 #if defined(MOZ_SPLASHSCREEN)
1098 // we're about to show the first toplevel window,
1099 // so kill off any splash screen if we had one
1100 nsSplashScreen *splash = nsSplashScreen::Get();
1101 if (splash && splash->IsOpen() && mWnd && bState &&
1102 (mWindowType == eWindowType_toplevel ||
1103 mWindowType == eWindowType_dialog ||
1104 mWindowType == eWindowType_popup))
1106 splash->Close();
1108 #endif
1110 #ifdef NS_FUNCTION_TIMER
1111 static bool firstShow = true;
1112 if (firstShow &&
1113 (mWindowType == eWindowType_toplevel ||
1114 mWindowType == eWindowType_dialog ||
1115 mWindowType == eWindowType_popup))
1117 firstShow = false;
1118 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1120 #endif
1122 PRBool wasVisible = mIsVisible;
1123 // Set the status now so that anyone asking during ShowWindow or
1124 // SetWindowPos would get the correct answer.
1125 mIsVisible = bState;
1127 if (mWnd) {
1128 if (bState) {
1129 if (!wasVisible && mWindowType == eWindowType_toplevel) {
1130 switch (mSizeMode) {
1131 #ifdef WINCE
1132 case nsSizeMode_Fullscreen:
1133 ::SetForegroundWindow(mWnd);
1134 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1135 MakeFullScreen(TRUE);
1136 break;
1138 case nsSizeMode_Maximized :
1139 ::SetForegroundWindow(mWnd);
1140 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1141 break;
1142 // use default for nsSizeMode_Minimized on Windows CE
1143 #else
1144 case nsSizeMode_Maximized :
1145 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1146 break;
1147 case nsSizeMode_Minimized :
1148 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
1149 break;
1150 #endif
1151 default:
1152 if (CanTakeFocus()) {
1153 #ifdef WINCE
1154 ::SetForegroundWindow(mWnd);
1155 #endif
1156 ::ShowWindow(mWnd, SW_SHOWNORMAL);
1157 } else {
1158 // Place the window behind the foreground window
1159 // (as long as it is not topmost)
1160 HWND wndAfter = ::GetForegroundWindow();
1161 if (!wndAfter)
1162 wndAfter = HWND_BOTTOM;
1163 else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)
1164 wndAfter = HWND_TOP;
1165 ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE |
1166 SWP_NOMOVE | SWP_NOACTIVATE);
1167 GetAttention(2);
1169 break;
1171 } else {
1172 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
1173 if (wasVisible)
1174 flags |= SWP_NOZORDER;
1176 if (mWindowType == eWindowType_popup) {
1177 #ifndef WINCE
1178 // ensure popups are the topmost of the TOPMOST
1179 // layer. Remember not to set the SWP_NOZORDER
1180 // flag as that might allow the taskbar to overlap
1181 // the popup. However on windows ce, we need to
1182 // activate the popup or clicks will not be sent.
1183 flags |= SWP_NOACTIVATE;
1184 #endif
1185 HWND owner = ::GetWindow(mWnd, GW_OWNER);
1186 ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
1187 } else {
1188 #ifndef WINCE
1189 if (mWindowType == eWindowType_dialog && !CanTakeFocus())
1190 flags |= SWP_NOACTIVATE;
1191 #endif
1192 ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
1196 #ifndef WINCE
1197 if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) {
1198 // when a toplevel window or dialog is shown, initialize the UI state
1199 ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
1201 #endif
1202 } else {
1203 if (mWindowType != eWindowType_dialog) {
1204 ::ShowWindow(mWnd, SW_HIDE);
1205 } else {
1206 ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1207 SWP_NOZORDER | SWP_NOACTIVATE);
1212 #ifdef MOZ_XUL
1213 if (!wasVisible && bState)
1214 Invalidate(PR_FALSE);
1215 #endif
1217 return NS_OK;
1220 /**************************************************************
1222 * SECTION: nsIWidget::IsVisible
1224 * Returns the visibility state.
1226 **************************************************************/
1228 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1229 NS_METHOD nsWindow::IsVisible(PRBool & bState)
1231 bState = mIsVisible;
1232 return NS_OK;
1235 /**************************************************************
1237 * SECTION: Window clipping utilities
1239 * Used in Size and Move operations for setting the proper
1240 * window clipping regions for window transparency.
1242 **************************************************************/
1244 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1245 // transparency. These routines are called on size and move operations.
1246 void nsWindow::ClearThemeRegion()
1248 #ifndef WINCE
1249 if (nsUXThemeData::sIsVistaOrLater && mTransparencyMode != eTransparencyGlass &&
1250 mWindowType == eWindowType_popup && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel)) {
1251 SetWindowRgn(mWnd, NULL, false);
1253 #endif
1256 void nsWindow::SetThemeRegion()
1258 #ifndef WINCE
1259 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1260 // for other window types as needed. The regions are applied generically to the base window
1261 // so default constants are used for part and state. At some point we might need part and
1262 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1263 // change shape based on state haven't come up.
1264 if (nsUXThemeData::sIsVistaOrLater && mTransparencyMode != eTransparencyGlass &&
1265 mWindowType == eWindowType_popup && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel)) {
1266 HRGN hRgn = nsnull;
1267 RECT rect = {0,0,mBounds.width,mBounds.height};
1269 HDC dc = ::GetDC(mWnd);
1270 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
1271 if (hRgn) {
1272 if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted.
1273 DeleteObject(hRgn);
1275 ::ReleaseDC(mWnd, dc);
1277 #endif
1280 /**************************************************************
1282 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1283 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1285 * Repositioning and sizing a window.
1287 **************************************************************/
1289 // Move this component
1290 NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
1292 if (mWindowType == eWindowType_toplevel ||
1293 mWindowType == eWindowType_dialog) {
1294 SetSizeMode(nsSizeMode_Normal);
1296 // Check to see if window needs to be moved first
1297 // to avoid a costly call to SetWindowPos. This check
1298 // can not be moved to the calling code in nsView, because
1299 // some platforms do not position child windows correctly
1301 // Only perform this check for non-popup windows, since the positioning can
1302 // in fact change even when the x/y do not. We always need to perform the
1303 // check. See bug #97805 for details.
1304 if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
1306 // Nothing to do, since it is already positioned correctly.
1307 return NS_OK;
1310 mBounds.x = aX;
1311 mBounds.y = aY;
1313 if (mWnd) {
1314 #ifdef DEBUG
1315 // complain if a window is moved offscreen (legal, but potentially worrisome)
1316 if (mIsTopWidgetWindow) { // only a problem for top-level windows
1317 // Make sure this window is actually on the screen before we move it
1318 // XXX: Needs multiple monitor support
1319 HDC dc = ::GetDC(mWnd);
1320 if (dc) {
1321 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1322 RECT workArea;
1323 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1324 // no annoying assertions. just mention the issue.
1325 if (aX < 0 || aX >= workArea.right || aY < 0 || aY >= workArea.bottom)
1326 printf("window moved to offscreen position\n");
1328 ::ReleaseDC(mWnd, dc);
1331 #endif
1332 ClearThemeRegion();
1333 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0,
1334 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE));
1335 SetThemeRegion();
1337 return NS_OK;
1340 // Resize this component
1341 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1343 NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
1344 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1346 // Avoid unnecessary resizing calls
1347 if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1348 return NS_OK;
1350 #ifdef MOZ_XUL
1351 if (eTransparencyTransparent == mTransparencyMode)
1352 ResizeTranslucentWindow(aWidth, aHeight);
1353 #endif
1355 // Set cached value for lightweight and printing
1356 mBounds.width = aWidth;
1357 mBounds.height = aHeight;
1359 if (mWnd) {
1360 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
1362 #ifndef WINCE
1363 if (!aRepaint) {
1364 flags |= SWP_NOREDRAW;
1366 #endif
1368 ClearThemeRegion();
1369 VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
1370 SetThemeRegion();
1373 if (aRepaint)
1374 Invalidate(PR_FALSE);
1376 return NS_OK;
1379 // Resize this component
1380 NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1382 NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize");
1383 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1385 // Avoid unnecessary resizing calls
1386 if (mBounds.x == aX && mBounds.y == aY &&
1387 mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1388 return NS_OK;
1390 #ifdef MOZ_XUL
1391 if (eTransparencyTransparent == mTransparencyMode)
1392 ResizeTranslucentWindow(aWidth, aHeight);
1393 #endif
1395 // Set cached value for lightweight and printing
1396 mBounds.x = aX;
1397 mBounds.y = aY;
1398 mBounds.width = aWidth;
1399 mBounds.height = aHeight;
1401 if (mWnd) {
1402 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
1403 #ifndef WINCE
1404 if (!aRepaint) {
1405 flags |= SWP_NOREDRAW;
1407 #endif
1409 ClearThemeRegion();
1410 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
1411 SetThemeRegion();
1414 if (aRepaint)
1415 Invalidate(PR_FALSE);
1417 return NS_OK;
1420 // Resize the client area and position the widget within it's parent
1421 NS_METHOD nsWindow::ResizeClient(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1423 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1424 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1426 // Adjust our existing window bounds, based on the new client dims.
1427 RECT client;
1428 GetClientRect(mWnd, &client);
1429 nsIntPoint dims(client.right - client.left, client.bottom - client.top);
1430 aWidth = mBounds.width + (aWidth - dims.x);
1431 aHeight = mBounds.height + (aHeight - dims.y);
1433 if (aX || aY) {
1434 // offsets
1435 nsIntRect bounds;
1436 GetScreenBounds(bounds);
1437 aX += bounds.x;
1438 aY += bounds.y;
1439 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1441 return Resize(aWidth, aHeight, aRepaint);
1444 #if !defined(WINCE)
1445 NS_IMETHODIMP
1446 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
1448 NS_ENSURE_ARG_POINTER(aEvent);
1450 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
1451 // you can only begin a resize drag with a mouse event
1452 return NS_ERROR_INVALID_ARG;
1455 nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
1456 if (mouseEvent->button != nsMouseEvent::eLeftButton) {
1457 // you can only begin a resize drag with the left mouse button
1458 return NS_ERROR_INVALID_ARG;
1461 // work out what sizemode we're talking about
1462 WPARAM syscommand;
1463 if (aVertical < 0) {
1464 if (aHorizontal < 0) {
1465 syscommand = SC_SIZE | WMSZ_TOPLEFT;
1466 } else if (aHorizontal == 0) {
1467 syscommand = SC_SIZE | WMSZ_TOP;
1468 } else {
1469 syscommand = SC_SIZE | WMSZ_TOPRIGHT;
1471 } else if (aVertical == 0) {
1472 if (aHorizontal < 0) {
1473 syscommand = SC_SIZE | WMSZ_LEFT;
1474 } else if (aHorizontal == 0) {
1475 return NS_ERROR_INVALID_ARG;
1476 } else {
1477 syscommand = SC_SIZE | WMSZ_RIGHT;
1479 } else {
1480 if (aHorizontal < 0) {
1481 syscommand = SC_SIZE | WMSZ_BOTTOMLEFT;
1482 } else if (aHorizontal == 0) {
1483 syscommand = SC_SIZE | WMSZ_BOTTOM;
1484 } else {
1485 syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT;
1489 // resizing doesn't work if the mouse is already captured
1490 CaptureMouse(PR_FALSE);
1492 // find the top-level window
1493 HWND toplevelWnd = GetTopLevelHWND(mWnd, PR_TRUE);
1495 // tell Windows to start the resize
1496 ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand,
1497 POINTTOPOINTS(aEvent->refPoint));
1499 return NS_OK;
1501 #endif
1502 /**************************************************************
1504 * SECTION: Window Z-order and state.
1506 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1507 * nsIWidget::ConstrainPosition
1509 * Z-order, positioning, restore, minimize, and maximize.
1511 **************************************************************/
1513 // Position the window behind the given window
1514 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1515 nsIWidget *aWidget, PRBool aActivate)
1517 HWND behind = HWND_TOP;
1518 if (aPlacement == eZPlacementBottom)
1519 behind = HWND_BOTTOM;
1520 else if (aPlacement == eZPlacementBelow && aWidget)
1521 behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
1522 UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
1523 if (!aActivate)
1524 flags |= SWP_NOACTIVATE;
1526 if (!CanTakeFocus() && behind == HWND_TOP)
1528 // Can't place the window to top so place it behind the foreground window
1529 // (as long as it is not topmost)
1530 HWND wndAfter = ::GetForegroundWindow();
1531 if (!wndAfter)
1532 behind = HWND_BOTTOM;
1533 else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
1534 behind = wndAfter;
1535 flags |= SWP_NOACTIVATE;
1538 ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
1539 return NS_OK;
1542 // Maximize, minimize or restore the window.
1543 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1544 NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode) {
1546 nsresult rv;
1548 // Let's not try and do anything if we're already in that state.
1549 // (This is needed to prevent problems when calling window.minimize(), which
1550 // calls us directly, and then the OS triggers another call to us.)
1551 if (aMode == mSizeMode)
1552 return NS_OK;
1554 // save the requested state
1555 rv = nsBaseWidget::SetSizeMode(aMode);
1556 if (NS_SUCCEEDED(rv) && mIsVisible) {
1557 int mode;
1559 switch (aMode) {
1560 case nsSizeMode_Fullscreen :
1561 mode = SW_SHOW;
1562 break;
1564 case nsSizeMode_Maximized :
1565 mode = SW_MAXIMIZE;
1566 break;
1568 case nsSizeMode_Minimized :
1569 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1570 // keeps the window active in the tray. So after the window is minimized,
1571 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1572 // we will do some additional processing to get the active window set right.
1573 // If sTrimOnMinimize is set, we let windows handle minimization normally
1574 // using SW_MINIMIZE.
1575 mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED;
1576 break;
1578 default :
1579 mode = SW_RESTORE;
1581 ::ShowWindow(mWnd, mode);
1582 // we dispatch an activate event here to ensure that the right child window
1583 // is focused
1584 if (mode == SW_RESTORE || mode == SW_MAXIMIZE)
1585 DispatchFocusToTopLevelWindow(NS_ACTIVATE);
1587 return rv;
1589 #endif // !defined(WINCE)
1591 // Constrain a potential move to fit onscreen
1592 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop,
1593 PRInt32 *aX, PRInt32 *aY)
1595 if (!mIsTopWidgetWindow) // only a problem for top-level windows
1596 return NS_OK;
1598 PRBool doConstrain = PR_FALSE; // whether we have enough info to do anything
1600 /* get our playing field. use the current screen, or failing that
1601 for any reason, use device caps for the default screen. */
1602 RECT screenRect;
1604 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
1605 if (screenmgr) {
1606 nsCOMPtr<nsIScreen> screen;
1607 PRInt32 left, top, width, height;
1609 // zero size rects confuse the screen manager
1610 width = mBounds.width > 0 ? mBounds.width : 1;
1611 height = mBounds.height > 0 ? mBounds.height : 1;
1612 screenmgr->ScreenForRect(*aX, *aY, width, height,
1613 getter_AddRefs(screen));
1614 if (screen) {
1615 if (mSizeMode != nsSizeMode_Fullscreen) {
1616 // For normalized windows, use the desktop work area.
1617 screen->GetAvailRect(&left, &top, &width, &height);
1618 } else {
1619 // For full screen windows, use the desktop.
1620 screen->GetRect(&left, &top, &width, &height);
1622 screenRect.left = left;
1623 screenRect.right = left+width;
1624 screenRect.top = top;
1625 screenRect.bottom = top+height;
1626 doConstrain = PR_TRUE;
1628 } else {
1629 if (mWnd) {
1630 HDC dc = ::GetDC(mWnd);
1631 if (dc) {
1632 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1633 if (mSizeMode != nsSizeMode_Fullscreen) {
1634 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
1635 } else {
1636 screenRect.left = screenRect.top = 0;
1637 screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN);
1638 screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
1640 doConstrain = PR_TRUE;
1642 ::ReleaseDC(mWnd, dc);
1647 if (aAllowSlop) {
1648 if (*aX < screenRect.left - mBounds.width + kWindowPositionSlop)
1649 *aX = screenRect.left - mBounds.width + kWindowPositionSlop;
1650 else if (*aX >= screenRect.right - kWindowPositionSlop)
1651 *aX = screenRect.right - kWindowPositionSlop;
1653 if (*aY < screenRect.top - mBounds.height + kWindowPositionSlop)
1654 *aY = screenRect.top - mBounds.height + kWindowPositionSlop;
1655 else if (*aY >= screenRect.bottom - kWindowPositionSlop)
1656 *aY = screenRect.bottom - kWindowPositionSlop;
1658 } else {
1660 if (*aX < screenRect.left)
1661 *aX = screenRect.left;
1662 else if (*aX >= screenRect.right - mBounds.width)
1663 *aX = screenRect.right - mBounds.width;
1665 if (*aY < screenRect.top)
1666 *aY = screenRect.top;
1667 else if (*aY >= screenRect.bottom - mBounds.height)
1668 *aY = screenRect.bottom - mBounds.height;
1671 return NS_OK;
1674 /**************************************************************
1676 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1678 * Enabling and disabling the widget.
1680 **************************************************************/
1682 // Enable/disable this component
1683 NS_METHOD nsWindow::Enable(PRBool bState)
1685 if (mWnd) {
1686 ::EnableWindow(mWnd, bState);
1688 return NS_OK;
1691 // Return the current enable state
1692 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
1694 NS_ENSURE_ARG_POINTER(aState);
1696 #ifndef WINCE
1697 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT)));
1698 #else
1699 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(mWnd));
1700 #endif
1702 return NS_OK;
1706 /**************************************************************
1708 * SECTION: nsIWidget::SetFocus
1710 * Give the focus to this widget.
1712 **************************************************************/
1714 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
1716 if (mWnd) {
1717 #ifdef WINSTATE_DEBUG_OUTPUT
1718 if (mWnd == GetTopLevelHWND(mWnd))
1719 printf("*** SetFocus: [ top] raise=%d\n", aRaise);
1720 else
1721 printf("*** SetFocus: [child] raise=%d\n", aRaise);
1722 #endif
1723 // Uniconify, if necessary
1724 HWND toplevelWnd = GetTopLevelHWND(mWnd);
1725 if (aRaise && ::IsIconic(toplevelWnd)) {
1726 ::ShowWindow(toplevelWnd, SW_RESTORE);
1728 ::SetFocus(mWnd);
1730 return NS_OK;
1734 /**************************************************************
1736 * SECTION: Bounds
1738 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1739 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1741 * Bound calculations.
1743 **************************************************************/
1745 // Return the window's full dimensions in screen coordinates.
1746 // If the window has a parent, converts the origin to an offset
1747 // of the parent's screen origin.
1748 NS_METHOD nsWindow::GetBounds(nsIntRect &aRect)
1750 if (mWnd) {
1751 RECT r;
1752 VERIFY(::GetWindowRect(mWnd, &r));
1754 // assign size
1755 aRect.width = r.right - r.left;
1756 aRect.height = r.bottom - r.top;
1758 // chrome on parent:
1759 // ___ 5,5 (chrome start)
1760 // | ____ 10,10 (client start)
1761 // | | ____ 20,20 (child start)
1762 // | | |
1763 // 20,20 - 5,5 = 15,15 (??)
1764 // minus GetClientOffset:
1765 // 15,15 - 5,5 = 10,10
1767 // no chrome on parent:
1768 // ______ 10,10 (win start)
1769 // | ____ 20,20 (child start)
1770 // | |
1771 // 20,20 - 10,10 = 10,10
1773 // walking the chain:
1774 // ___ 5,5 (chrome start)
1775 // | ___ 10,10 (client start)
1776 // | | ___ 20,20 (child start)
1777 // | | | __ 30,30 (child start)
1778 // | | | |
1779 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1780 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1781 // minus GetClientOffset:
1782 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1784 // convert coordinates if parent exists
1785 HWND parent = ::GetParent(mWnd);
1786 if (parent) {
1787 RECT pr;
1788 VERIFY(::GetWindowRect(parent, &pr));
1789 r.left -= pr.left;
1790 r.top -= pr.top;
1791 // adjust for chrome
1792 nsWindow* pWidget = static_cast<nsWindow*>(GetParent());
1793 if (pWidget && pWidget->IsTopLevelWidget()) {
1794 nsIntPoint clientOffset;
1795 pWidget->GetClientOffset(clientOffset);
1796 r.left -= clientOffset.x;
1797 r.top -= clientOffset.y;
1800 aRect.x = r.left;
1801 aRect.y = r.top;
1802 } else {
1803 aRect = mBounds;
1806 return NS_OK;
1809 // Get this component dimension
1810 NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect)
1812 if (mWnd) {
1813 RECT r;
1814 VERIFY(::GetClientRect(mWnd, &r));
1816 // assign size
1817 aRect.x = 0;
1818 aRect.y = 0;
1819 aRect.width = r.right - r.left;
1820 aRect.height = r.bottom - r.top;
1822 } else {
1823 aRect.SetRect(0,0,0,0);
1825 return NS_OK;
1828 // Like GetBounds, but don't offset by the parent
1829 NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect)
1831 if (mWnd) {
1832 RECT r;
1833 VERIFY(::GetWindowRect(mWnd, &r));
1835 aRect.width = r.right - r.left;
1836 aRect.height = r.bottom - r.top;
1837 aRect.x = r.left;
1838 aRect.y = r.top;
1839 } else
1840 aRect = mBounds;
1842 return NS_OK;
1845 // return the x,y offset of the client area from the origin
1846 // of the window. If the window is borderless returns (0,0).
1847 NS_METHOD nsWindow::GetClientOffset(nsIntPoint &aPt)
1849 if (!mWnd) {
1850 aPt.x = aPt.y = 0;
1851 return NS_OK;
1854 RECT r1;
1855 GetWindowRect(mWnd, &r1);
1856 nsIntPoint pt = WidgetToScreenOffset();
1857 aPt.x = pt.x - r1.left;
1858 aPt.y = pt.y - r1.top;
1859 return NS_OK;
1862 void
1863 nsWindow::SetDrawsInTitlebar(PRBool aState)
1865 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1866 if (window && window != this) {
1867 return window->SetDrawsInTitlebar(aState);
1870 if (aState) {
1871 // left, top, right, bottom for nsIntMargin
1872 nsIntMargin margins(-1, 0, -1, -1);
1873 SetNonClientMargins(margins);
1875 else {
1876 nsIntMargin margins(-1, -1, -1, -1);
1877 SetNonClientMargins(margins);
1881 NS_IMETHODIMP
1882 nsWindow::GetNonClientMargins(nsIntMargin &margins)
1884 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1885 if (window && window != this) {
1886 return window->GetNonClientMargins(margins);
1889 if (mCustomNonClient) {
1890 margins = mNonClientMargins;
1891 return NS_OK;
1894 margins.top = GetSystemMetrics(SM_CYCAPTION);
1895 margins.bottom = GetSystemMetrics(SM_CYFRAME);
1896 margins.top += margins.bottom;
1897 margins.left = margins.right = GetSystemMetrics(SM_CYFRAME);
1899 return NS_OK;
1902 void
1903 nsWindow::ResetLayout()
1905 // This will trigger a frame changed event, triggering
1906 // nc calc size and a sizemode gecko event.
1907 SetWindowPos(mWnd, 0, 0, 0, 0, 0,
1908 SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|
1909 SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
1911 // If hidden, just send the frame changed event for now.
1912 if (!mIsVisible)
1913 return;
1915 // Send a gecko size event to trigger reflow.
1916 RECT clientRc = {0};
1917 GetClientRect(mWnd, &clientRc);
1918 nsIntRect evRect(nsWindowGfx::ToIntRect(clientRc));
1919 OnResize(evRect);
1921 // Invalidate and update
1922 Invalidate(PR_FALSE);
1925 // Called when the window layout changes: full screen mode transitions,
1926 // theme changes, and composition changes. Calculates the new non-client
1927 // margins and fires off a frame changed event, which triggers an nc calc
1928 // size windows event, kicking the changes in.
1929 PRBool
1930 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode, PRBool aReflowWindow)
1932 if (!mCustomNonClient)
1933 return PR_FALSE;
1935 // XXX Temp disable margins until frame rendering is supported
1936 mCompositorFlag = PR_TRUE;
1937 if(!nsUXThemeData::CheckForCompositor()) {
1938 mCompositorFlag = PR_FALSE;
1939 return PR_FALSE;
1942 mNonClientOffset.top = mNonClientOffset.bottom =
1943 mNonClientOffset.left = mNonClientOffset.right = 0;
1945 if (aSizeMode == -1)
1946 aSizeMode = mSizeMode;
1948 if (aSizeMode == nsSizeMode_Minimized ||
1949 aSizeMode == nsSizeMode_Fullscreen) {
1950 mCaptionHeight = mVertResizeMargin = mHorResizeMargin = 0;
1951 return PR_TRUE;
1954 // Note, for maximized windows, we need to continue to offset the client by
1955 // thick frame margins of a normal window, since windows expects this
1956 // in it's DwmDefWndProc hit testing.
1957 mCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
1958 mHorResizeMargin = GetSystemMetrics(SM_CXFRAME);
1959 mVertResizeMargin = GetSystemMetrics(SM_CYFRAME);
1961 mCaptionHeight += mVertResizeMargin;
1963 // If a margin value is 0, set the offset to the default size of the frame.
1964 // If a margin is -1, leave as default, and if a margin > 0, set the offset
1965 // so that the frame size is equal to the margin value.
1966 if (!mNonClientMargins.top)
1967 mNonClientOffset.top = mCaptionHeight;
1968 else if (mNonClientMargins.top > 0)
1969 mNonClientOffset.top = mCaptionHeight - mNonClientMargins.top;
1971 if (!mNonClientMargins.left)
1972 mNonClientOffset.left = mHorResizeMargin;
1973 else if (mNonClientMargins.left > 0)
1974 mNonClientOffset.left = mHorResizeMargin - mNonClientMargins.left;
1976 if (!mNonClientMargins.right)
1977 mNonClientOffset.right = mHorResizeMargin;
1978 else if (mNonClientMargins.right > 0)
1979 mNonClientOffset.right = mHorResizeMargin - mNonClientMargins.right;
1981 if (!mNonClientMargins.bottom)
1982 mNonClientOffset.bottom = mVertResizeMargin;
1983 else if (mNonClientMargins.bottom > 0)
1984 mNonClientOffset.bottom = mVertResizeMargin - mNonClientMargins.bottom;
1986 NS_ASSERTION(mNonClientOffset.top >= 0, "non-client top margin is negative!");
1987 NS_ASSERTION(mNonClientOffset.left >= 0, "non-client left margin is negative!");
1988 NS_ASSERTION(mNonClientOffset.right >= 0, "non-client right margin is negative!");
1989 NS_ASSERTION(mNonClientOffset.bottom >= 0, "non-client bottom margin is negative!");
1991 if (mNonClientOffset.top < 0)
1992 mNonClientOffset.top = 0;
1993 if (mNonClientOffset.left < 0)
1994 mNonClientOffset.left = 0;
1995 if (mNonClientOffset.right < 0)
1996 mNonClientOffset.right = 0;
1997 if (mNonClientOffset.bottom < 0)
1998 mNonClientOffset.bottom = 0;
2000 if (aReflowWindow) {
2001 // Force a reflow of content based on the new client
2002 // dimensions.
2003 ResetLayout();
2006 return PR_TRUE;
2009 NS_IMETHODIMP
2010 nsWindow::SetNonClientMargins(nsIntMargin &margins)
2012 if (!mIsTopWidgetWindow ||
2013 mBorderStyle & eBorderStyle_none ||
2014 mHideChrome)
2015 return NS_ERROR_INVALID_ARG;
2017 // Request for a reset
2018 if (margins.top == -1 && margins.left == -1 &&
2019 margins.right == -1 && margins.bottom == -1) {
2020 mCustomNonClient = PR_FALSE;
2021 mNonClientMargins = margins;
2022 // Force a reflow of content based on the new client
2023 // dimensions.
2024 ResetLayout();
2025 return NS_OK;
2028 if (margins.top < -1 || margins.bottom < -1 ||
2029 margins.left < -1 || margins.right < -1)
2030 return NS_ERROR_INVALID_ARG;
2032 mNonClientMargins = margins;
2033 mCustomNonClient = PR_TRUE;
2034 if (!UpdateNonClientMargins()) {
2035 NS_WARNING("UpdateNonClientMargins failed!");
2036 return PR_FALSE;
2039 return NS_OK;
2042 /**************************************************************
2044 * SECTION: nsIWidget::SetBackgroundColor
2046 * Sets the window background paint color.
2048 **************************************************************/
2050 NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
2052 nsBaseWidget::SetBackgroundColor(aColor);
2054 if (mBrush)
2055 ::DeleteObject(mBrush);
2057 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
2058 #ifndef WINCE
2059 if (mWnd != NULL) {
2060 ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush);
2062 #endif
2063 return NS_OK;
2066 /**************************************************************
2068 * SECTION: nsIWidget::SetCursor
2070 * SetCursor and related utilities for manging cursor state.
2072 **************************************************************/
2074 // Set this component cursor
2075 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
2077 // Only change cursor if it's changing
2079 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2080 //XXX If we want this optimization we need a better way to do it.
2081 //if (aCursor != mCursor) {
2082 HCURSOR newCursor = NULL;
2084 switch (aCursor) {
2085 case eCursor_select:
2086 newCursor = ::LoadCursor(NULL, IDC_IBEAM);
2087 break;
2089 case eCursor_wait:
2090 newCursor = ::LoadCursor(NULL, IDC_WAIT);
2091 break;
2093 case eCursor_hyperlink:
2095 newCursor = ::LoadCursor(NULL, IDC_HAND);
2096 break;
2099 case eCursor_standard:
2100 newCursor = ::LoadCursor(NULL, IDC_ARROW);
2101 break;
2103 case eCursor_n_resize:
2104 case eCursor_s_resize:
2105 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2106 break;
2108 case eCursor_w_resize:
2109 case eCursor_e_resize:
2110 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2111 break;
2113 case eCursor_nw_resize:
2114 case eCursor_se_resize:
2115 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2116 break;
2118 case eCursor_ne_resize:
2119 case eCursor_sw_resize:
2120 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2121 break;
2123 case eCursor_crosshair:
2124 newCursor = ::LoadCursor(NULL, IDC_CROSS);
2125 break;
2127 case eCursor_move:
2128 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2129 break;
2131 case eCursor_help:
2132 newCursor = ::LoadCursor(NULL, IDC_HELP);
2133 break;
2135 case eCursor_copy: // CSS3
2136 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
2137 break;
2139 case eCursor_alias:
2140 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
2141 break;
2143 case eCursor_cell:
2144 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
2145 break;
2147 case eCursor_grab:
2148 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
2149 break;
2151 case eCursor_grabbing:
2152 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
2153 break;
2155 case eCursor_spinning:
2156 newCursor = ::LoadCursor(NULL, IDC_APPSTARTING);
2157 break;
2159 case eCursor_context_menu:
2160 // XXX this CSS3 cursor needs to be implemented
2161 break;
2163 case eCursor_zoom_in:
2164 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
2165 break;
2167 case eCursor_zoom_out:
2168 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
2169 break;
2171 case eCursor_not_allowed:
2172 case eCursor_no_drop:
2173 newCursor = ::LoadCursor(NULL, IDC_NO);
2174 break;
2176 case eCursor_col_resize:
2177 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
2178 break;
2180 case eCursor_row_resize:
2181 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
2182 break;
2184 case eCursor_vertical_text:
2185 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT));
2186 break;
2188 case eCursor_all_scroll:
2189 // XXX not 100% appropriate perhaps
2190 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2191 break;
2193 case eCursor_nesw_resize:
2194 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2195 break;
2197 case eCursor_nwse_resize:
2198 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2199 break;
2201 case eCursor_ns_resize:
2202 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2203 break;
2205 case eCursor_ew_resize:
2206 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2207 break;
2209 case eCursor_none:
2210 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
2211 break;
2213 default:
2214 NS_ERROR("Invalid cursor type");
2215 break;
2218 if (NULL != newCursor) {
2219 mCursor = aCursor;
2220 HCURSOR oldCursor = ::SetCursor(newCursor);
2222 if (sHCursor == oldCursor) {
2223 NS_IF_RELEASE(sCursorImgContainer);
2224 if (sHCursor != NULL)
2225 ::DestroyIcon(sHCursor);
2226 sHCursor = NULL;
2230 return NS_OK;
2233 // Setting the actual cursor
2234 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
2235 PRUint32 aHotspotX, PRUint32 aHotspotY)
2237 if (sCursorImgContainer == aCursor && sHCursor) {
2238 ::SetCursor(sHCursor);
2239 return NS_OK;
2242 PRInt32 width;
2243 PRInt32 height;
2245 nsresult rv;
2246 rv = aCursor->GetWidth(&width);
2247 NS_ENSURE_SUCCESS(rv, rv);
2248 rv = aCursor->GetHeight(&height);
2249 NS_ENSURE_SUCCESS(rv, rv);
2251 // Reject cursors greater than 128 pixels in either direction, to prevent
2252 // spoofing.
2253 // XXX ideally we should rescale. Also, we could modify the API to
2254 // allow trusted content to set larger cursors.
2255 if (width > 128 || height > 128)
2256 return NS_ERROR_NOT_AVAILABLE;
2258 HCURSOR cursor;
2259 rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
2260 NS_ENSURE_SUCCESS(rv, rv);
2262 mCursor = nsCursor(-1);
2263 ::SetCursor(cursor);
2265 NS_IF_RELEASE(sCursorImgContainer);
2266 sCursorImgContainer = aCursor;
2267 NS_ADDREF(sCursorImgContainer);
2269 if (sHCursor != NULL)
2270 ::DestroyIcon(sHCursor);
2271 sHCursor = cursor;
2273 return NS_OK;
2276 /**************************************************************
2278 * SECTION: nsIWidget::Get/SetTransparencyMode
2280 * Manage the transparency mode of the top-level window
2281 * containing this widget.
2283 **************************************************************/
2285 #ifdef MOZ_XUL
2286 nsTransparencyMode nsWindow::GetTransparencyMode()
2288 return GetTopLevelWindow(PR_TRUE)->GetWindowTranslucencyInner();
2291 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
2293 GetTopLevelWindow(PR_TRUE)->SetWindowTranslucencyInner(aMode);
2296 namespace {
2297 BOOL CALLBACK AddClientAreaToRegion(HWND hWnd, LPARAM lParam) {
2298 nsIntRegion *region = reinterpret_cast<nsIntRegion*>(lParam);
2300 RECT clientRect;
2301 ::GetWindowRect(hWnd, &clientRect);
2302 nsIntRect clientArea(clientRect.left, clientRect.top,
2303 clientRect.right - clientRect.left,
2304 clientRect.bottom - clientRect.top);
2305 region->Or(*region, clientArea);
2306 return TRUE;
2310 void nsWindow::UpdatePossiblyTransparentRegion(const nsIntRegion &aDirtyRegion,
2311 const nsIntRegion &aPossiblyTransparentRegion) {
2312 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2313 if (mTransparencyMode != eTransparencyGlass)
2314 return;
2316 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2317 nsWindow* topWindow = GetNSWindowPtr(hWnd);
2319 if (GetParent())
2320 return;
2322 mPossiblyTransparentRegion.Sub(mPossiblyTransparentRegion, aDirtyRegion);
2323 mPossiblyTransparentRegion.Or(mPossiblyTransparentRegion, aPossiblyTransparentRegion);
2325 nsIntRegion childWindowRegion;
2327 ::EnumChildWindows(mWnd, AddClientAreaToRegion, reinterpret_cast<LPARAM>(&childWindowRegion));
2329 nsIntPoint clientOffset;
2330 GetClientOffset(clientOffset);
2331 childWindowRegion.MoveBy(-clientOffset);
2333 RECT r;
2334 ::GetWindowRect(mWnd, &r);
2335 childWindowRegion.MoveBy(-r.left, -r.top);
2337 nsIntRect clientBounds;
2338 topWindow->GetClientBounds(clientBounds);
2339 nsIntRegion opaqueRegion;
2340 opaqueRegion.Sub(clientBounds, mPossiblyTransparentRegion);
2341 opaqueRegion.Or(opaqueRegion, childWindowRegion);
2342 // Sometimes child windows overlap our bounds
2343 opaqueRegion.And(opaqueRegion, clientBounds);
2345 MARGINS margins = { 0, 0, 0, 0 };
2346 DWORD_PTR dwStyle = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
2348 // If there is no opaque region or hidechrome=true, set margins
2349 // to support a full sheet of glass.
2350 if (opaqueRegion.IsEmpty() || mHideChrome) {
2351 // Comments in MSDN indicate all values must be set to -1
2352 margins.cxLeftWidth = margins.cxRightWidth =
2353 margins.cyTopHeight = margins.cyBottomHeight = -1;
2354 } else {
2355 // Find the largest rectangle and use that to calculate the inset
2356 nsIntRect largest = opaqueRegion.GetLargestRectangle();
2357 margins.cxLeftWidth = largest.x;
2358 margins.cxRightWidth = clientBounds.width - largest.XMost();
2359 margins.cyTopHeight = largest.y;
2360 margins.cyBottomHeight = clientBounds.height - largest.YMost();
2363 // Only update glass area if there are changes
2364 if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) {
2365 mGlassMargins = margins;
2366 UpdateGlass();
2368 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2371 void nsWindow::UpdateGlass()
2373 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2374 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2376 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2377 // rendered based on the window style.
2378 // DWMNCRP_ENABLED - The non-client area rendering is
2379 // enabled; the window style is ignored.
2380 DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE;
2381 if (mTransparencyMode == eTransparencyGlass) {
2382 policy = DWMNCRP_ENABLED;
2385 // Extends the window frame behind the client area
2386 if(nsUXThemeData::CheckForCompositor()) {
2387 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd, &mGlassMargins);
2388 nsUXThemeData::dwmSetWindowAttributePtr(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy);
2390 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2392 #endif
2394 /**************************************************************
2396 * SECTION: nsIWidget::HideWindowChrome
2398 * Show or hide window chrome.
2400 **************************************************************/
2402 NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide)
2404 HWND hwnd = GetTopLevelHWND(mWnd, PR_TRUE);
2405 if (!GetNSWindowPtr(hwnd))
2407 NS_WARNING("Trying to hide window decorations in an embedded context");
2408 return NS_ERROR_FAILURE;
2411 if (mHideChrome == aShouldHide)
2412 return NS_OK;
2414 DWORD_PTR style, exStyle;
2415 mHideChrome = aShouldHide;
2416 if (aShouldHide) {
2417 DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2418 DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2420 style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
2421 exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
2422 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
2424 mOldStyle = tempStyle;
2425 mOldExStyle = tempExStyle;
2427 else {
2428 if (!mOldStyle || !mOldExStyle) {
2429 mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2430 mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2433 style = mOldStyle;
2434 exStyle = mOldExStyle;
2437 VERIFY_WINDOW_STYLE(style);
2438 ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
2439 ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
2441 return NS_OK;
2444 /**************************************************************
2446 * SECTION: nsIWidget::Invalidate
2448 * Invalidate an area of the client for painting.
2450 **************************************************************/
2452 // Invalidate this component visible area
2453 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
2455 if (mWnd)
2457 #ifdef WIDGET_DEBUG_OUTPUT
2458 debug_DumpInvalidate(stdout,
2459 this,
2460 nsnull,
2461 aIsSynchronous,
2462 nsCAutoString("noname"),
2463 (PRInt32) mWnd);
2464 #endif // WIDGET_DEBUG_OUTPUT
2466 VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
2468 if (aIsSynchronous) {
2469 VERIFY(::UpdateWindow(mWnd));
2472 return NS_OK;
2475 // Invalidate this component visible area
2476 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, PRBool aIsSynchronous)
2478 if (mWnd)
2480 #ifdef WIDGET_DEBUG_OUTPUT
2481 debug_DumpInvalidate(stdout,
2482 this,
2483 &aRect,
2484 aIsSynchronous,
2485 nsCAutoString("noname"),
2486 (PRInt32) mWnd);
2487 #endif // WIDGET_DEBUG_OUTPUT
2489 RECT rect;
2491 rect.left = aRect.x;
2492 rect.top = aRect.y;
2493 rect.right = aRect.x + aRect.width;
2494 rect.bottom = aRect.y + aRect.height;
2496 VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
2498 if (aIsSynchronous) {
2499 VERIFY(::UpdateWindow(mWnd));
2502 return NS_OK;
2505 NS_IMETHODIMP
2506 nsWindow::MakeFullScreen(PRBool aFullScreen)
2508 #if WINCE_WINDOWS_MOBILE
2509 RECT rc;
2510 if (aFullScreen) {
2511 SetForegroundWindow(mWnd);
2512 if (nsWindowCE::sMenuBarShown) {
2513 SIPINFO sipInfo;
2514 memset(&sipInfo, 0, sizeof(SIPINFO));
2515 sipInfo.cbSize = sizeof(SIPINFO);
2516 if (SipGetInfo(&sipInfo))
2517 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2518 sipInfo.rcVisibleDesktop.bottom);
2519 else
2520 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2521 GetSystemMetrics(SM_CYSCREEN));
2522 RECT menuBarRect;
2523 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle, &menuBarRect) &&
2524 menuBarRect.top < rc.bottom)
2525 rc.bottom = menuBarRect.top;
2526 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_SHOWSIPBUTTON);
2527 } else {
2529 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);
2530 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2533 else {
2534 SHFullScreen(mWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
2535 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
2538 if (aFullScreen)
2539 mSizeMode = nsSizeMode_Fullscreen;
2541 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2542 HideWindowChrome(aFullScreen);
2543 Resize(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PR_TRUE);
2545 return NS_OK;
2547 #else
2549 if (aFullScreen) {
2550 if (mSizeMode != nsSizeMode_Fullscreen)
2551 mOldSizeMode = mSizeMode;
2552 SetSizeMode(nsSizeMode_Fullscreen);
2553 } else {
2554 SetSizeMode(mOldSizeMode);
2557 UpdateNonClientMargins();
2559 // Will call hide chrome, reposition window. Note this will
2560 // also cache dimensions for restoration, so it should only
2561 // be called once per fullscreen request.
2562 return nsBaseWidget::MakeFullScreen(aFullScreen);
2563 #endif
2566 /**************************************************************
2568 * SECTION: nsIWidget::Update
2570 * Force a synchronous repaint of the window.
2572 **************************************************************/
2574 NS_IMETHODIMP nsWindow::Update()
2576 nsresult rv = NS_OK;
2578 // updates can come through for windows no longer holding an mWnd during
2579 // deletes triggered by JavaScript in buttons with mouse feedback
2580 if (mWnd)
2581 VERIFY(::UpdateWindow(mWnd));
2583 return rv;
2586 /**************************************************************
2588 * SECTION: nsIWidget::Scroll
2590 * Scroll this widget.
2592 **************************************************************/
2594 static PRBool
2595 ClipRegionContainedInRect(const nsTArray<nsIntRect>& aClipRects,
2596 const nsIntRect& aRect)
2598 for (PRUint32 i = 0; i < aClipRects.Length(); ++i) {
2599 if (!aRect.Contains(aClipRects[i]))
2600 return PR_FALSE;
2602 return PR_TRUE;
2605 // This function determines whether the given window has a descendant that
2606 // does not intersect the given aScreenRect. If we encounter a window owned
2607 // by another thread (which includes another process, since thread IDs
2608 // are unique system-wide), then we give up and conservatively return true.
2609 static PRBool
2610 HasDescendantWindowOutsideRect(DWORD aThisThreadID, HWND aWnd,
2611 const RECT& aScreenRect)
2613 // If the window is owned by another thread, give up now, don't try to
2614 // look at its children since they could change asynchronously.
2615 // XXX should we try harder here for out-of-process plugins?
2616 if (GetWindowThreadProcessId(aWnd, NULL) != aThisThreadID) {
2617 return PR_TRUE;
2619 for (HWND child = ::GetWindow(aWnd, GW_CHILD); child;
2620 child = ::GetWindow(child, GW_HWNDNEXT)) {
2621 RECT childScreenRect;
2622 ::GetWindowRect(child, &childScreenRect);
2623 RECT result;
2624 if (!::IntersectRect(&result, &childScreenRect, &aScreenRect)) {
2625 return PR_TRUE;
2628 if (HasDescendantWindowOutsideRect(aThisThreadID, child, aScreenRect)) {
2629 return PR_TRUE;
2633 return PR_FALSE;
2636 static void
2637 InvalidateRgnInWindowSubtree(HWND aWnd, HRGN aRgn, HRGN aTmpRgn)
2639 RECT clientRect;
2640 ::GetClientRect(aWnd, &clientRect);
2641 ::SetRectRgn(aTmpRgn, clientRect.left, clientRect.top,
2642 clientRect.right, clientRect.bottom);
2643 if (::CombineRgn(aTmpRgn, aTmpRgn, aRgn, RGN_AND) == NULLREGION) {
2644 return;
2647 ::InvalidateRgn(aWnd, aTmpRgn, FALSE);
2649 for (HWND child = ::GetWindow(aWnd, GW_CHILD); child;
2650 child = ::GetWindow(child, GW_HWNDNEXT)) {
2651 POINT pt = { 0, 0 };
2652 ::MapWindowPoints(child, aWnd, &pt, 1);
2653 ::OffsetRgn(aRgn, -pt.x, -pt.y);
2654 InvalidateRgnInWindowSubtree(child, aRgn, aTmpRgn);
2655 ::OffsetRgn(aRgn, pt.x, pt.y);
2659 void
2660 nsWindow::Scroll(const nsIntPoint& aDelta,
2661 const nsTArray<nsIntRect>& aDestRects,
2662 const nsTArray<Configuration>& aConfigurations)
2664 // We use SW_SCROLLCHILDREN if all the windows that intersect the
2665 // affected area are moving by the scroll amount.
2666 // First, build the set of widgets that are to be moved by the scroll
2667 // amount.
2668 // At the same time, set the clip region of all changed windows to the
2669 // intersection of the current and new regions.
2670 nsTHashtable<nsPtrHashKey<nsWindow> > scrolledWidgets;
2671 scrolledWidgets.Init();
2672 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
2673 const Configuration& configuration = aConfigurations[i];
2674 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
2675 NS_ASSERTION(w->GetParent() == this,
2676 "Configured widget is not a child");
2677 if (configuration.mBounds == w->mBounds + aDelta) {
2678 scrolledWidgets.PutEntry(w);
2680 w->SetWindowClipRegion(configuration.mClipRegion, PR_TRUE);
2683 // Create temporary regions
2684 HRGN updateRgn = ::CreateRectRgn(0, 0, 0, 0);
2685 if (!updateRgn) {
2686 // OOM?
2687 return;
2689 HRGN destRgn = ::CreateRectRgn(0, 0, 0, 0);
2690 if (!destRgn) {
2691 // OOM?
2692 ::DeleteObject((HGDIOBJ)updateRgn);
2693 return;
2696 DWORD ourThreadID = GetWindowThreadProcessId(mWnd, NULL);
2698 for (BlitRectIter iter(aDelta, aDestRects); !iter.IsDone(); ++iter) {
2699 const nsIntRect& destRect = iter.Rect();
2700 nsIntRect affectedRect;
2701 affectedRect.UnionRect(destRect, destRect - aDelta);
2702 UINT flags = SW_SCROLLCHILDREN;
2703 // Now check if any of our children would be affected by
2704 // SW_SCROLLCHILDREN but not supposed to scroll.
2705 for (nsWindow* w = static_cast<nsWindow*>(GetFirstChild()); w;
2706 w = static_cast<nsWindow*>(w->GetNextSibling())) {
2707 if (w->mBounds.Intersects(affectedRect)) {
2708 // This child will be affected
2709 nsPtrHashKey<nsWindow>* entry = scrolledWidgets.GetEntry(w);
2710 if (entry) {
2711 // It's supposed to be scrolled, so we can still use
2712 // SW_SCROLLCHILDREN. But don't allow SW_SCROLLCHILDREN to be
2713 // used on it again by a later rectangle; we don't want it to
2714 // move twice!
2715 scrolledWidgets.RawRemoveEntry(entry);
2717 nsIntPoint screenOffset = WidgetToScreenOffset();
2718 RECT screenAffectedRect = {
2719 screenOffset.x + affectedRect.x,
2720 screenOffset.y + affectedRect.y,
2721 screenOffset.x + affectedRect.XMost(),
2722 screenOffset.y + affectedRect.YMost()
2724 if (HasDescendantWindowOutsideRect(ourThreadID, w->mWnd,
2725 screenAffectedRect)) {
2726 // SW_SCROLLCHILDREN seems to not move descendant windows
2727 // that don't intersect the scrolled rectangle, *even if* the
2728 // immediate child window of the scrolled window *does* intersect
2729 // the scrolled window. So if w has a descendant window
2730 // that would not be moved, SW_SCROLLCHILDREN will hopelessly mess
2731 // things up and we must not use it.
2732 flags &= ~SW_SCROLLCHILDREN;
2734 } else {
2735 flags &= ~SW_SCROLLCHILDREN;
2736 // We may have removed some children from scrolledWidgets even
2737 // though we decide here to not use SW_SCROLLCHILDREN. That's OK,
2738 // it just means that we might not use SW_SCROLLCHILDREN
2739 // for a later rectangle when we could have.
2740 break;
2745 if (flags & SW_SCROLLCHILDREN
2746 #ifdef CAIRO_HAS_D2D_SURFACE
2747 && !mD2DWindowSurface
2748 #endif
2750 // ScrollWindowEx will send WM_MOVE to each moved window to tell it
2751 // its new position. Unfortunately those messages don't reach our
2752 // WM_MOVE handler for some plugins, so we have to update their
2753 // mBounds here. For windows that do receive WM_MOVE, this is OK,
2754 // they'll just overwrite mBounds again with the correct value.
2755 for (nsWindow* w = static_cast<nsWindow*>(GetFirstChild()); w;
2756 w = static_cast<nsWindow*>(w->GetNextSibling())) {
2757 if (w->mBounds.Intersects(affectedRect)) {
2758 w->mBounds += aDelta;
2763 RECT clip = { affectedRect.x, affectedRect.y, affectedRect.XMost(), affectedRect.YMost() };
2764 #ifdef CAIRO_HAS_D2D_SURFACE
2765 if (mD2DWindowSurface) {
2766 mD2DWindowSurface->Scroll(aDelta, affectedRect);
2768 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
2769 const Configuration& configuration = aConfigurations[i];
2770 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
2771 w->Invalidate(PR_FALSE);
2774 // Get the system clip twice, offset one by the delta. This will make
2775 // systemClip contain the area of the systemClip, and movedSystemClip
2776 // contain the area after scrolling that was covered by the systemClip.
2777 HRGN systemClip = ::CreateRectRgn(0, 0, 0, 0);
2778 HRGN movedSystemClip = ::CreateRectRgn(0, 0, 0, 0);
2779 HDC dc = ::GetDC(mWnd);
2780 ::GetRandomRgn(dc, systemClip, SYSRGN);
2781 ::GetRandomRgn(dc, movedSystemClip, SYSRGN);
2782 ::OffsetRgn(movedSystemClip, aDelta.x, aDelta.y);
2784 // RGN_DIFF will return the parts inside 'systemClip' but -not- inside
2785 // movedSystemClip. This is the area that was clipped (and possibly not
2786 // properly updated) before.
2787 ::CombineRgn(systemClip, systemClip, movedSystemClip, RGN_DIFF);
2789 // The systemClip is in screen coordinates, we need client coordinates.
2790 POINT p = { 0, 0 };
2791 ::ClientToScreen(mWnd, &p);
2792 ::OffsetRgn(systemClip, -p.x, -p.y);
2794 ::GetUpdateRgn(mWnd, updateRgn, FALSE);
2795 ::OffsetRgn(updateRgn, aDelta.x, aDelta.y);
2796 ::CombineRgn(updateRgn, updateRgn, systemClip, RGN_OR);
2798 ::DeleteObject((HGDIOBJ)systemClip);
2799 ::DeleteObject((HGDIOBJ)movedSystemClip);
2800 ::ReleaseDC(mWnd, dc);
2801 } else {
2802 #endif
2803 ::ScrollWindowEx(mWnd, aDelta.x, aDelta.y, &clip, &clip, updateRgn, NULL, flags);
2804 #ifdef CAIRO_HAS_D2D_SURFACE
2806 #endif
2807 ::SetRectRgn(destRgn, destRect.x, destRect.y, destRect.XMost(), destRect.YMost());
2808 ::CombineRgn(updateRgn, updateRgn, destRgn, RGN_AND);
2809 if (flags & SW_SCROLLCHILDREN) {
2810 for (nsWindow* w = static_cast<nsWindow*>(GetFirstChild()); w;
2811 w = static_cast<nsWindow*>(w->GetNextSibling())) {
2812 if ((w->mBounds - aDelta).Intersects(affectedRect)) {
2813 // Widgets that have been scrolled by SW_SCROLLCHILDREN but which
2814 // were, or are, partly outside the scroll area must be invalidated
2815 // because SW_SCROLLCHILDREN doesn't update parts of widgets outside
2816 // the area it scrolled, even if it moved them.
2817 nsAutoTArray<nsIntRect,1> clipRegion;
2818 w->GetWindowClipRegion(&clipRegion);
2819 if (!ClipRegionContainedInRect(clipRegion,
2820 destRect - w->mBounds.TopLeft()) ||
2821 !ClipRegionContainedInRect(clipRegion,
2822 destRect - (w->mBounds.TopLeft() - aDelta))) {
2823 ::SetRectRgn(destRgn, w->mBounds.x, w->mBounds.y, w->mBounds.XMost(), w->mBounds.YMost());
2824 ::CombineRgn(updateRgn, updateRgn, destRgn, RGN_OR);
2829 InvalidateRgnInWindowSubtree(mWnd, updateRgn, destRgn);
2830 } else {
2831 ::InvalidateRgn(mWnd, updateRgn, FALSE);
2835 ::DeleteObject((HGDIOBJ)updateRgn);
2836 ::DeleteObject((HGDIOBJ)destRgn);
2838 // Now make sure all children actually get positioned, sized and clipped
2839 // correctly. If SW_SCROLLCHILDREN already moved widgets to their correct
2840 // locations, then the SetWindowPos calls this triggers will just be
2841 // no-ops.
2842 ConfigureChildren(aConfigurations);
2845 /**************************************************************
2847 * SECTION: Native data storage
2849 * nsIWidget::GetNativeData
2850 * nsIWidget::FreeNativeData
2852 * Set or clear native data based on a constant.
2854 **************************************************************/
2856 // Return some native data according to aDataType
2857 void* nsWindow::GetNativeData(PRUint32 aDataType)
2859 switch (aDataType) {
2860 case NS_NATIVE_PLUGIN_PORT:
2861 case NS_NATIVE_WIDGET:
2862 case NS_NATIVE_WINDOW:
2863 return (void*)mWnd;
2864 case NS_NATIVE_GRAPHIC:
2865 // XXX: This is sleezy!! Remember to Release the DC after using it!
2866 #ifdef MOZ_XUL
2867 return (void*)(eTransparencyTransparent == mTransparencyMode) ?
2868 mMemoryDC : ::GetDC(mWnd);
2869 #else
2870 return (void*)::GetDC(mWnd);
2871 #endif
2873 #ifdef NS_ENABLE_TSF
2874 case NS_NATIVE_TSF_THREAD_MGR:
2875 return nsTextStore::GetThreadMgr();
2876 case NS_NATIVE_TSF_CATEGORY_MGR:
2877 return nsTextStore::GetCategoryMgr();
2878 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
2879 return nsTextStore::GetDisplayAttrMgr();
2880 #endif //NS_ENABLE_TSF
2882 default:
2883 break;
2886 return NULL;
2889 // Free some native data according to aDataType
2890 void nsWindow::FreeNativeData(void * data, PRUint32 aDataType)
2892 switch (aDataType)
2894 case NS_NATIVE_GRAPHIC:
2895 #ifdef MOZ_XUL
2896 if (eTransparencyTransparent != mTransparencyMode)
2897 ::ReleaseDC(mWnd, (HDC)data);
2898 #else
2899 ::ReleaseDC(mWnd, (HDC)data);
2900 #endif
2901 break;
2902 case NS_NATIVE_WIDGET:
2903 case NS_NATIVE_WINDOW:
2904 case NS_NATIVE_PLUGIN_PORT:
2905 break;
2906 default:
2907 break;
2911 /**************************************************************
2913 * SECTION: nsIWidget::SetTitle
2915 * Set the main windows title text.
2917 **************************************************************/
2919 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
2921 const nsString& strTitle = PromiseFlatString(aTitle);
2922 ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get());
2923 return NS_OK;
2926 /**************************************************************
2928 * SECTION: nsIWidget::SetIcon
2930 * Set the main windows icon.
2932 **************************************************************/
2934 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec)
2936 #ifndef WINCE
2937 // Assume the given string is a local identifier for an icon file.
2939 nsCOMPtr<nsILocalFile> iconFile;
2940 ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
2941 getter_AddRefs(iconFile));
2942 if (!iconFile)
2943 return NS_OK; // not an error if icon is not found
2945 nsAutoString iconPath;
2946 iconFile->GetPath(iconPath);
2948 // XXX this should use MZLU (see bug 239279)
2950 ::SetLastError(0);
2952 HICON bigIcon = (HICON)::LoadImageW(NULL,
2953 (LPCWSTR)iconPath.get(),
2954 IMAGE_ICON,
2955 ::GetSystemMetrics(SM_CXICON),
2956 ::GetSystemMetrics(SM_CYICON),
2957 LR_LOADFROMFILE );
2958 HICON smallIcon = (HICON)::LoadImageW(NULL,
2959 (LPCWSTR)iconPath.get(),
2960 IMAGE_ICON,
2961 ::GetSystemMetrics(SM_CXSMICON),
2962 ::GetSystemMetrics(SM_CYSMICON),
2963 LR_LOADFROMFILE );
2965 if (bigIcon) {
2966 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon);
2967 if (icon)
2968 ::DestroyIcon(icon);
2970 #ifdef DEBUG_SetIcon
2971 else {
2972 NS_LossyConvertUTF16toASCII cPath(iconPath);
2973 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2975 #endif
2976 if (smallIcon) {
2977 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon);
2978 if (icon)
2979 ::DestroyIcon(icon);
2981 #ifdef DEBUG_SetIcon
2982 else {
2983 NS_LossyConvertUTF16toASCII cPath(iconPath);
2984 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2986 #endif
2987 #endif // WINCE
2988 return NS_OK;
2991 /**************************************************************
2993 * SECTION: nsIWidget::WidgetToScreenOffset
2995 * Return this widget's origin in screen coordinates.
2997 **************************************************************/
2999 nsIntPoint nsWindow::WidgetToScreenOffset()
3001 POINT point;
3002 point.x = 0;
3003 point.y = 0;
3004 ::ClientToScreen(mWnd, &point);
3005 return nsIntPoint(point.x, point.y);
3008 /**************************************************************
3010 * SECTION: nsIWidget::EnableDragDrop
3012 * Enables/Disables drag and drop of files on this widget.
3014 **************************************************************/
3016 #if !defined(WINCE) // implemented in nsWindowCE.cpp
3017 NS_METHOD nsWindow::EnableDragDrop(PRBool aEnable)
3019 NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()");
3021 nsresult rv = NS_ERROR_FAILURE;
3022 if (aEnable) {
3023 if (nsnull == mNativeDragTarget) {
3024 mNativeDragTarget = new nsNativeDragTarget(this);
3025 if (NULL != mNativeDragTarget) {
3026 mNativeDragTarget->AddRef();
3027 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) {
3028 if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) {
3029 rv = NS_OK;
3034 } else {
3035 if (nsnull != mWnd && NULL != mNativeDragTarget) {
3036 ::RevokeDragDrop(mWnd);
3037 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) {
3038 rv = NS_OK;
3040 mNativeDragTarget->DragCancel();
3041 NS_RELEASE(mNativeDragTarget);
3044 return rv;
3046 #endif
3048 /**************************************************************
3050 * SECTION: nsIWidget::CaptureMouse
3052 * Enables/Disables system mouse capture.
3054 **************************************************************/
3056 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
3058 if (!nsToolkit::gMouseTrailer) {
3059 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3060 return NS_OK;
3063 if (aCapture) {
3064 nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd);
3065 ::SetCapture(mWnd);
3066 } else {
3067 nsToolkit::gMouseTrailer->SetCaptureWindow(NULL);
3068 ::ReleaseCapture();
3070 mIsInMouseCapture = aCapture;
3071 return NS_OK;
3074 /**************************************************************
3076 * SECTION: nsIWidget::CaptureRollupEvents
3078 * Dealing with event rollup on destroy for popups. Enables &
3079 * Disables system capture of any and all events that would
3080 * cause a dropdown to be rolled up.
3082 **************************************************************/
3084 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
3085 nsIMenuRollup * aMenuRollup,
3086 PRBool aDoCapture,
3087 PRBool aConsumeRollupEvent)
3089 if (aDoCapture) {
3090 /* we haven't bothered carrying a weak reference to sRollupWidget because
3091 we believe lifespan is properly scoped. this next assertion helps
3092 assure that remains true. */
3093 NS_ASSERTION(!sRollupWidget, "rollup widget reassigned before release");
3094 sRollupConsumeEvent = aConsumeRollupEvent;
3095 NS_IF_RELEASE(sRollupWidget);
3096 NS_IF_RELEASE(sMenuRollup);
3097 sRollupListener = aListener;
3098 sMenuRollup = aMenuRollup;
3099 NS_IF_ADDREF(aMenuRollup);
3100 sRollupWidget = this;
3101 NS_ADDREF(this);
3103 #ifndef WINCE
3104 if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
3105 RegisterSpecialDropdownHooks();
3107 sProcessHook = PR_TRUE;
3108 #endif
3110 } else {
3111 sRollupListener = nsnull;
3112 NS_IF_RELEASE(sMenuRollup);
3113 NS_IF_RELEASE(sRollupWidget);
3115 #ifndef WINCE
3116 sProcessHook = PR_FALSE;
3117 UnregisterSpecialDropdownHooks();
3118 #endif
3121 return NS_OK;
3124 /**************************************************************
3126 * SECTION: nsIWidget::GetAttention
3128 * Bring this window to the user's attention.
3130 **************************************************************/
3132 // Draw user's attention to this window until it comes to foreground.
3133 NS_IMETHODIMP
3134 nsWindow::GetAttention(PRInt32 aCycleCount)
3136 #ifndef WINCE
3137 // Got window?
3138 if (!mWnd)
3139 return NS_ERROR_NOT_INITIALIZED;
3141 // Don't flash if the flash count is 0 or if the
3142 // top level window is already active.
3143 HWND fgWnd = ::GetForegroundWindow();
3144 if (aCycleCount == 0 || fgWnd == GetTopLevelHWND(mWnd))
3145 return NS_OK;
3147 HWND flashWnd = mWnd;
3148 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3149 flashWnd = ownerWnd;
3152 // Don't flash if the owner window is active either.
3153 if (fgWnd == flashWnd)
3154 return NS_OK;
3156 DWORD defaultCycleCount = 0;
3157 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
3159 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3160 FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 };
3161 ::FlashWindowEx(&flashInfo);
3162 #endif
3163 return NS_OK;
3166 void nsWindow::StopFlashing()
3168 #ifndef WINCE
3169 HWND flashWnd = mWnd;
3170 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3171 flashWnd = ownerWnd;
3174 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3175 FLASHW_STOP, 0, 0 };
3176 ::FlashWindowEx(&flashInfo);
3177 #endif
3180 /**************************************************************
3182 * SECTION: nsIWidget::HasPendingInputEvent
3184 * Ask whether there user input events pending. All input events are
3185 * included, including those not targeted at this nsIwidget instance.
3187 **************************************************************/
3189 PRBool
3190 nsWindow::HasPendingInputEvent()
3192 // If there is pending input or the user is currently
3193 // moving the window then return true.
3194 // Note: When the user is moving the window WIN32 spins
3195 // a separate event loop and input events are not
3196 // reported to the application.
3197 if (HIWORD(GetQueueStatus(QS_INPUT)))
3198 return PR_TRUE;
3199 #ifdef WINCE
3200 return PR_FALSE;
3201 #else
3202 GUITHREADINFO guiInfo;
3203 guiInfo.cbSize = sizeof(GUITHREADINFO);
3204 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo))
3205 return PR_FALSE;
3206 return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE);
3207 #endif
3210 /**************************************************************
3212 * SECTION: nsIWidget::GetLayerManager
3214 * Get the layer manager associated with this widget.
3216 **************************************************************/
3218 mozilla::layers::LayerManager*
3219 nsWindow::GetLayerManager()
3221 nsWindow *topWindow = GetNSWindowPtr(GetTopLevelHWND(mWnd, PR_TRUE));
3223 if (!topWindow) {
3224 return nsBaseWidget::GetLayerManager();
3227 if (topWindow->GetAcceleratedRendering() != mUseAcceleratedRendering) {
3228 mLayerManager = NULL;
3229 mUseAcceleratedRendering = topWindow->GetAcceleratedRendering();
3232 #ifndef WINCE
3233 if (!mLayerManager) {
3234 if (mUseAcceleratedRendering) {
3235 nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3237 PRBool allowAcceleration = PR_TRUE;
3238 PRBool preferOpenGL = PR_FALSE;
3239 if (prefs) {
3240 prefs->GetBoolPref("mozilla.widget.accelerated-layers",
3241 &allowAcceleration);
3242 prefs->GetBoolPref("mozilla.layers.prefer-opengl",
3243 &preferOpenGL);
3246 if (allowAcceleration) {
3247 #ifdef MOZ_ENABLE_D3D9_LAYER
3248 if (!preferOpenGL) {
3249 nsRefPtr<mozilla::layers::LayerManagerD3D9> layerManager =
3250 new mozilla::layers::LayerManagerD3D9(this);
3251 if (layerManager->Initialize()) {
3252 mLayerManager = layerManager;
3255 #endif
3256 if (!mLayerManager) {
3257 nsRefPtr<mozilla::layers::LayerManagerOGL> layerManager =
3258 new mozilla::layers::LayerManagerOGL(this);
3259 if (layerManager->Initialize()) {
3260 mLayerManager = layerManager;
3266 #endif
3268 return nsBaseWidget::GetLayerManager();
3271 /**************************************************************
3273 * SECTION: nsIWidget::GetThebesSurface
3275 * Get the Thebes surface associated with this widget.
3277 **************************************************************/
3279 gfxASurface *nsWindow::GetThebesSurface()
3281 #ifdef CAIRO_HAS_D2D_SURFACE
3282 if (mD2DWindowSurface) {
3283 return mD2DWindowSurface;
3285 #endif
3286 if (mPaintDC)
3287 return (new gfxWindowsSurface(mPaintDC));
3289 #ifdef CAIRO_HAS_D2D_SURFACE
3290 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3291 gfxWindowsPlatform::RENDER_DIRECT2D) {
3292 gfxASurface::gfxContentType content = gfxASurface::CONTENT_COLOR;
3293 #if defined(MOZ_XUL)
3294 if (mTransparencyMode != eTransparencyOpaque) {
3295 content = gfxASurface::CONTENT_COLOR_ALPHA;
3297 #endif
3298 return (new gfxD2DSurface(mWnd, content));
3299 } else {
3300 #endif
3301 PRUint32 flags = gfxWindowsSurface::FLAG_TAKE_DC;
3302 if (mTransparencyMode != eTransparencyOpaque) {
3303 flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT;
3305 return (new gfxWindowsSurface(mWnd, flags));
3306 #ifdef CAIRO_HAS_D2D_SURFACE
3308 #endif
3311 /**************************************************************
3313 * SECTION: nsIWidget::OnDefaultButtonLoaded
3315 * Called after the dialog is loaded and it has a default button.
3317 **************************************************************/
3319 NS_IMETHODIMP
3320 nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect)
3322 #ifdef WINCE
3323 return NS_ERROR_NOT_IMPLEMENTED;
3324 #else
3325 if (aButtonRect.IsEmpty())
3326 return NS_OK;
3328 // Don't snap when we are not active.
3329 HWND activeWnd = ::GetActiveWindow();
3330 if (activeWnd != ::GetForegroundWindow() ||
3331 GetTopLevelHWND(mWnd, PR_TRUE) != GetTopLevelHWND(activeWnd, PR_TRUE)) {
3332 return NS_OK;
3335 PRBool isAlwaysSnapCursor = PR_FALSE;
3336 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3337 if (prefs) {
3338 nsCOMPtr<nsIPrefBranch> prefBranch;
3339 prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
3340 if (prefBranch) {
3341 prefBranch->GetBoolPref("ui.cursor_snapping.always_enabled",
3342 &isAlwaysSnapCursor);
3346 if (!isAlwaysSnapCursor) {
3347 BOOL snapDefaultButton;
3348 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0,
3349 &snapDefaultButton, 0) || !snapDefaultButton)
3350 return NS_OK;
3353 nsIntRect widgetRect;
3354 nsresult rv = GetScreenBounds(widgetRect);
3355 NS_ENSURE_SUCCESS(rv, rv);
3356 nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft());
3358 nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2,
3359 buttonRect.y + buttonRect.height / 2);
3360 // The center of the button can be outside of the widget.
3361 // E.g., it could be hidden by scrolling.
3362 if (!widgetRect.Contains(centerOfButton)) {
3363 return NS_OK;
3366 if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) {
3367 NS_ERROR("SetCursorPos failed");
3368 return NS_ERROR_FAILURE;
3370 return NS_OK;
3371 #endif
3374 NS_IMETHODIMP
3375 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta,
3376 PRBool aIsHorizontal,
3377 PRInt32 &aOverriddenDelta)
3379 // The default vertical and horizontal scrolling speed is 3, this is defined
3380 // on the document of SystemParametersInfo in MSDN.
3381 const PRInt32 kSystemDefaultScrollingSpeed = 3;
3383 PRInt32 absOriginDelta = PR_ABS(aOriginalDelta);
3385 // Compute the simple overridden speed.
3386 PRInt32 absComputedOverriddenDelta;
3387 nsresult rv =
3388 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta, aIsHorizontal,
3389 absComputedOverriddenDelta);
3390 NS_ENSURE_SUCCESS(rv, rv);
3392 aOverriddenDelta = aOriginalDelta;
3394 if (absComputedOverriddenDelta == absOriginDelta) {
3395 // We don't override now.
3396 return NS_OK;
3399 // Otherwise, we should check whether the user customized the system settings
3400 // or not. If the user did it, we should respect the will.
3401 UINT systemSpeed;
3402 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) {
3403 return NS_ERROR_FAILURE;
3405 // The default vertical scrolling speed is 3, this is defined on the document
3406 // of SystemParametersInfo in MSDN.
3407 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3408 return NS_OK;
3411 // Only Vista and later, Windows has the system setting of horizontal
3412 // scrolling by the mouse wheel.
3413 if (GetWindowsVersion() >= VISTA_VERSION) {
3414 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) {
3415 return NS_ERROR_FAILURE;
3417 // The default horizontal scrolling speed is 3, this is defined on the
3418 // document of SystemParametersInfo in MSDN.
3419 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3420 return NS_OK;
3424 // Limit the overridden delta value from the system settings. The mouse
3425 // driver might accelerate the scrolling speed already. If so, we shouldn't
3426 // override the scrolling speed for preventing the unexpected high speed
3427 // scrolling.
3428 PRInt32 absDeltaLimit;
3429 rv =
3430 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed,
3431 aIsHorizontal, absDeltaLimit);
3432 NS_ENSURE_SUCCESS(rv, rv);
3434 // If the given delta is larger than our computed limitation value, the delta
3435 // was accelerated by the mouse driver. So, we should do nothing here.
3436 if (absDeltaLimit <= absOriginDelta) {
3437 return NS_OK;
3440 absComputedOverriddenDelta =
3441 PR_MIN(absComputedOverriddenDelta, absDeltaLimit);
3443 aOverriddenDelta = (aOriginalDelta > 0) ? absComputedOverriddenDelta :
3444 -absComputedOverriddenDelta;
3445 return NS_OK;
3448 /**************************************************************
3449 **************************************************************
3451 ** BLOCK: Moz Events
3453 ** Moz GUI event management.
3455 **************************************************************
3456 **************************************************************/
3458 /**************************************************************
3460 * SECTION: Mozilla event initialization
3462 * Helpers for initializing moz events.
3464 **************************************************************/
3466 // Event intialization
3467 MSG nsWindow::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam)
3469 MSG msg;
3470 msg.message = aMessage;
3471 msg.wParam = wParam;
3472 msg.lParam = lParam;
3473 return msg;
3476 void nsWindow::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
3478 if (nsnull == aPoint) { // use the point from the event
3479 // get the message position in client coordinates
3480 if (mWnd != NULL) {
3482 DWORD pos = ::GetMessagePos();
3483 POINT cpos;
3485 cpos.x = GET_X_LPARAM(pos);
3486 cpos.y = GET_Y_LPARAM(pos);
3488 ::ScreenToClient(mWnd, &cpos);
3489 event.refPoint.x = cpos.x;
3490 event.refPoint.y = cpos.y;
3491 } else {
3492 event.refPoint.x = 0;
3493 event.refPoint.y = 0;
3496 else {
3497 // use the point override if provided
3498 event.refPoint.x = aPoint->x;
3499 event.refPoint.y = aPoint->y;
3502 #ifndef WINCE
3503 event.time = ::GetMessageTime();
3504 #else
3505 event.time = PR_Now() / 1000;
3506 #endif
3508 mLastPoint = event.refPoint;
3511 /**************************************************************
3513 * SECTION: Moz event dispatch helpers
3515 * Helpers for dispatching different types of moz events.
3517 **************************************************************/
3519 // Main event dispatch. Invokes callback and ProcessEvent method on
3520 // Event Listener object. Part of nsIWidget.
3521 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
3523 #ifdef WIDGET_DEBUG_OUTPUT
3524 debug_DumpEvent(stdout,
3525 event->widget,
3526 event,
3527 nsCAutoString("something"),
3528 (PRInt32) mWnd);
3529 #endif // WIDGET_DEBUG_OUTPUT
3531 aStatus = nsEventStatus_eIgnore;
3533 // skip processing of suppressed blur events
3534 if (event->message == NS_DEACTIVATE && BlurEventsSuppressed())
3535 return NS_OK;
3537 // Top level windows can have a view attached which requires events be sent
3538 // to the underlying base window and the view. Added when we combined the
3539 // base chrome window with the main content child for nc client area (title
3540 // bar) rendering.
3541 if (mViewCallback) {
3542 // A subset of events are sent to the base xul window first
3543 switch(event->message) {
3544 // send to the base window (view mgr ignores these for the view)
3545 case NS_UISTATECHANGED:
3546 case NS_DESTROY:
3547 case NS_SETZLEVEL:
3548 case NS_XUL_CLOSE:
3549 case NS_MOVE:
3550 (*mEventCallback)(event); // web shell / xul window
3551 return NS_OK;
3553 // sent to the base window, then to the view
3554 case NS_SIZE:
3555 case NS_DEACTIVATE:
3556 case NS_ACTIVATE:
3557 case NS_SIZEMODE:
3558 (*mEventCallback)(event); // web shell / xul window
3559 break;
3561 // attached view events
3562 aStatus = (*mViewCallback)(event);
3564 else if (mEventCallback) {
3565 aStatus = (*mEventCallback)(event);
3568 // the window can be destroyed during processing of seemingly innocuous events like, say,
3569 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3570 // which causes problems with the deleted window. therefore:
3571 if (mOnDestroyCalled)
3572 aStatus = nsEventStatus_eConsumeNoDefault;
3573 return NS_OK;
3576 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
3578 nsGUIEvent event(PR_TRUE, aMsg, this);
3579 InitEvent(event);
3581 PRBool result = DispatchWindowEvent(&event);
3582 return result;
3585 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
3587 nsEventStatus status;
3588 DispatchEvent(event, status);
3589 return ConvertStatus(status);
3592 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event, nsEventStatus &aStatus) {
3593 DispatchEvent(event, aStatus);
3594 return ConvertStatus(aStatus);
3597 PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
3598 const nsTArray<nsAlternativeCharCode>* aAlternativeCharCodes,
3599 UINT aVirtualCharCode, const MSG *aMsg,
3600 const nsModifierKeyState &aModKeyState,
3601 PRUint32 aFlags)
3603 UserActivity();
3605 nsKeyEvent event(PR_TRUE, aEventType, this);
3606 nsIntPoint point(0, 0);
3608 InitEvent(event, &point); // this add ref's event.widget
3610 event.flags |= aFlags;
3611 event.charCode = aCharCode;
3612 if (aAlternativeCharCodes)
3613 event.alternativeCharCodes.AppendElements(*aAlternativeCharCodes);
3614 event.keyCode = aVirtualCharCode;
3616 #ifdef KE_DEBUG
3617 static cnt=0;
3618 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt++,
3619 (NS_KEY_PRESS == aEventType) ? "PRESS" : (aEventType == NS_KEY_UP ? "Up" : "Down"),
3620 event.charCode, event.keyCode);
3621 printf("Shift: %s Control %s Alt: %s \n",
3622 (mIsShiftDown ? "D" : "U"), (mIsControlDown ? "D" : "U"), (mIsAltDown ? "D" : "U"));
3623 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3624 IS_VK_DOWN(NS_VK_SHIFT) ? 'S' : ' ',
3625 IS_VK_DOWN(NS_VK_CONTROL) ? 'C' : ' ',
3626 IS_VK_DOWN(NS_VK_ALT) ? 'A' : ' ',
3627 IS_VK_DOWN(VK_LSHIFT) ? 'S' : ' ',
3628 IS_VK_DOWN(VK_LCONTROL) ? 'C' : ' ',
3629 IS_VK_DOWN(VK_LMENU) ? 'A' : ' ',
3630 IS_VK_DOWN(VK_RMENU) ? 'A' : ' ',
3631 IS_VK_DOWN(VK_RCONTROL) ? 'C' : ' ',
3632 IS_VK_DOWN(VK_RSHIFT) ? 'S' : ' ');
3633 #endif
3635 event.isShift = aModKeyState.mIsShiftDown;
3636 event.isControl = aModKeyState.mIsControlDown;
3637 event.isMeta = PR_FALSE;
3638 event.isAlt = aModKeyState.mIsAltDown;
3640 NPEvent pluginEvent;
3641 if (aMsg && PluginHasFocus()) {
3642 pluginEvent.event = aMsg->message;
3643 pluginEvent.wParam = aMsg->wParam;
3644 pluginEvent.lParam = aMsg->lParam;
3645 event.pluginEvent = (void *)&pluginEvent;
3648 PRBool result = DispatchWindowEvent(&event);
3650 return result;
3653 PRBool nsWindow::DispatchCommandEvent(PRUint32 aEventCommand)
3655 nsCOMPtr<nsIAtom> command;
3656 switch (aEventCommand) {
3657 case APPCOMMAND_BROWSER_BACKWARD:
3658 command = nsWidgetAtoms::Back;
3659 break;
3660 case APPCOMMAND_BROWSER_FORWARD:
3661 command = nsWidgetAtoms::Forward;
3662 break;
3663 case APPCOMMAND_BROWSER_REFRESH:
3664 command = nsWidgetAtoms::Reload;
3665 break;
3666 case APPCOMMAND_BROWSER_STOP:
3667 command = nsWidgetAtoms::Stop;
3668 break;
3669 case APPCOMMAND_BROWSER_SEARCH:
3670 command = nsWidgetAtoms::Search;
3671 break;
3672 case APPCOMMAND_BROWSER_FAVORITES:
3673 command = nsWidgetAtoms::Bookmarks;
3674 break;
3675 case APPCOMMAND_BROWSER_HOME:
3676 command = nsWidgetAtoms::Home;
3677 break;
3678 default:
3679 return PR_FALSE;
3681 nsCommandEvent event(PR_TRUE, nsWidgetAtoms::onAppCommand, command, this);
3683 InitEvent(event);
3684 DispatchWindowEvent(&event);
3686 return PR_TRUE;
3689 // Recursively dispatch synchronous paints for nsIWidget
3690 // descendants with invalidated rectangles.
3691 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
3693 LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
3694 if (proc == (LONG_PTR)&nsWindow::WindowProc) {
3695 // its one of our windows so check to see if it has a
3696 // invalidated rect. If it does. Dispatch a synchronous
3697 // paint.
3698 if (GetUpdateRect(aWnd, NULL, FALSE))
3699 VERIFY(::UpdateWindow(aWnd));
3701 return TRUE;
3704 // Check for pending paints and dispatch any pending paint
3705 // messages for any nsIWidget which is a descendant of the
3706 // top-level window that *this* window is embedded within.
3708 // Note: We do not dispatch pending paint messages for non
3709 // nsIWidget managed windows.
3710 void nsWindow::DispatchPendingEvents()
3712 if (mPainting) {
3713 NS_WARNING("We were asked to dispatch pending events during painting, "
3714 "denying since that's unsafe.");
3715 return;
3718 // We need to ensure that reflow events do not get starved.
3719 // At the same time, we don't want to recurse through here
3720 // as that would prevent us from dispatching starved paints.
3721 static int recursionBlocker = 0;
3722 if (recursionBlocker++ == 0) {
3723 NS_ProcessPendingEvents(nsnull, PR_MillisecondsToInterval(100));
3724 --recursionBlocker;
3727 // Quickly check to see if there are any
3728 // paint events pending.
3729 if (::GetQueueStatus(QS_PAINT)) {
3730 // Find the top level window.
3731 HWND topWnd = GetTopLevelHWND(mWnd);
3733 // Dispatch pending paints for all topWnd's descendant windows.
3734 // Note: EnumChildWindows enumerates all descendant windows not just
3735 // it's children.
3736 #if !defined(WINCE)
3737 ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3738 #else
3739 nsWindowCE::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3740 #endif
3744 // Deal with plugin events
3745 PRBool nsWindow::DispatchPluginEvent(const MSG &aMsg)
3747 if (!PluginHasFocus())
3748 return PR_FALSE;
3750 nsGUIEvent event(PR_TRUE, NS_PLUGIN_EVENT, this);
3751 nsIntPoint point(0, 0);
3752 InitEvent(event, &point);
3753 NPEvent pluginEvent;
3754 pluginEvent.event = aMsg.message;
3755 pluginEvent.wParam = aMsg.wParam;
3756 pluginEvent.lParam = aMsg.lParam;
3757 event.pluginEvent = (void *)&pluginEvent;
3758 return DispatchWindowEvent(&event);
3761 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
3762 UINT aLastMsg)
3764 MSG msg;
3765 ::GetMessageW(&msg, mWnd, aFirstMsg, aLastMsg);
3766 DispatchPluginEvent(msg);
3769 // Deal with all sort of mouse event
3770 PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
3771 LPARAM lParam, PRBool aIsContextMenuKey,
3772 PRInt16 aButton, PRUint16 aInputSource)
3774 PRBool result = PR_FALSE;
3776 UserActivity();
3778 if (!mEventCallback) {
3779 return result;
3782 switch (aEventType) {
3783 case NS_MOUSE_BUTTON_DOWN:
3784 CaptureMouse(PR_TRUE);
3785 break;
3787 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3788 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3789 case NS_MOUSE_BUTTON_UP:
3790 case NS_MOUSE_MOVE:
3791 case NS_MOUSE_EXIT:
3792 if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && mIsInMouseCapture)
3793 CaptureMouse(PR_FALSE);
3794 break;
3796 default:
3797 break;
3799 } // switch
3801 nsIntPoint eventPoint;
3802 eventPoint.x = GET_X_LPARAM(lParam);
3803 eventPoint.y = GET_Y_LPARAM(lParam);
3805 nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal,
3806 aIsContextMenuKey
3807 ? nsMouseEvent::eContextMenuKey
3808 : nsMouseEvent::eNormal);
3809 if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) {
3810 nsIntPoint zero(0, 0);
3811 InitEvent(event, &zero);
3812 } else {
3813 InitEvent(event, &eventPoint);
3816 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
3817 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
3818 event.isMeta = PR_FALSE;
3819 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
3820 event.button = aButton;
3821 event.inputSource = aInputSource;
3823 nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
3825 // Suppress mouse moves caused by widget creation
3826 if (aEventType == NS_MOUSE_MOVE)
3828 if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y))
3829 return result;
3830 sLastMouseMovePoint.x = mpScreen.x;
3831 sLastMouseMovePoint.y = mpScreen.y;
3834 PRBool insideMovementThreshold = (abs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
3835 (abs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
3837 BYTE eventButton;
3838 switch (aButton) {
3839 case nsMouseEvent::eLeftButton:
3840 eventButton = VK_LBUTTON;
3841 break;
3842 case nsMouseEvent::eMiddleButton:
3843 eventButton = VK_MBUTTON;
3844 break;
3845 case nsMouseEvent::eRightButton:
3846 eventButton = VK_RBUTTON;
3847 break;
3848 default:
3849 eventButton = 0;
3850 break;
3853 // Doubleclicks are used to set the click count, then changed to mousedowns
3854 // We're going to time double-clicks from mouse *up* to next mouse *down*
3855 #ifndef WINCE
3856 LONG curMsgTime = ::GetMessageTime();
3857 #else
3858 LONG curMsgTime = PR_Now() / 1000;
3859 #endif
3861 if (aEventType == NS_MOUSE_DOUBLECLICK) {
3862 event.message = NS_MOUSE_BUTTON_DOWN;
3863 event.button = aButton;
3864 sLastClickCount = 2;
3866 else if (aEventType == NS_MOUSE_BUTTON_UP) {
3867 // remember when this happened for the next mouse down
3868 sLastMousePoint.x = eventPoint.x;
3869 sLastMousePoint.y = eventPoint.y;
3870 sLastMouseButton = eventButton;
3872 else if (aEventType == NS_MOUSE_BUTTON_DOWN) {
3873 // now look to see if we want to convert this to a double- or triple-click
3874 if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold &&
3875 eventButton == sLastMouseButton) {
3876 sLastClickCount ++;
3877 } else {
3878 // reset the click count, to count *this* click
3879 sLastClickCount = 1;
3881 // Set last Click time on MouseDown only
3882 sLastMouseDownTime = curMsgTime;
3884 else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
3885 sLastClickCount = 0;
3887 else if (aEventType == NS_MOUSE_EXIT) {
3888 event.exit = IsTopLevelMouseExit(mWnd) ? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
3890 else if (aEventType == NS_MOUSE_MOZHITTEST)
3892 event.flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
3894 event.clickCount = sLastClickCount;
3896 #ifdef NS_DEBUG_XX
3897 printf("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount);
3898 #endif
3900 NPEvent pluginEvent;
3902 switch (aEventType)
3904 case NS_MOUSE_BUTTON_DOWN:
3905 switch (aButton) {
3906 case nsMouseEvent::eLeftButton:
3907 pluginEvent.event = WM_LBUTTONDOWN;
3908 break;
3909 case nsMouseEvent::eMiddleButton:
3910 pluginEvent.event = WM_MBUTTONDOWN;
3911 break;
3912 case nsMouseEvent::eRightButton:
3913 pluginEvent.event = WM_RBUTTONDOWN;
3914 break;
3915 default:
3916 break;
3918 break;
3919 case NS_MOUSE_BUTTON_UP:
3920 switch (aButton) {
3921 case nsMouseEvent::eLeftButton:
3922 pluginEvent.event = WM_LBUTTONUP;
3923 break;
3924 case nsMouseEvent::eMiddleButton:
3925 pluginEvent.event = WM_MBUTTONUP;
3926 break;
3927 case nsMouseEvent::eRightButton:
3928 pluginEvent.event = WM_RBUTTONUP;
3929 break;
3930 default:
3931 break;
3933 break;
3934 case NS_MOUSE_DOUBLECLICK:
3935 switch (aButton) {
3936 case nsMouseEvent::eLeftButton:
3937 pluginEvent.event = WM_LBUTTONDBLCLK;
3938 break;
3939 case nsMouseEvent::eMiddleButton:
3940 pluginEvent.event = WM_MBUTTONDBLCLK;
3941 break;
3942 case nsMouseEvent::eRightButton:
3943 pluginEvent.event = WM_RBUTTONDBLCLK;
3944 break;
3945 default:
3946 break;
3948 break;
3949 case NS_MOUSE_MOVE:
3950 pluginEvent.event = WM_MOUSEMOVE;
3951 break;
3952 case NS_MOUSE_EXIT:
3953 pluginEvent.event = WM_MOUSELEAVE;
3954 break;
3955 default:
3956 pluginEvent.event = WM_NULL;
3957 break;
3960 pluginEvent.wParam = wParam; // plugins NEED raw OS event flags!
3961 pluginEvent.lParam = lParam;
3963 event.pluginEvent = (void *)&pluginEvent;
3965 // call the event callback
3966 if (nsnull != mEventCallback) {
3967 if (nsToolkit::gMouseTrailer)
3968 nsToolkit::gMouseTrailer->Disable();
3969 if (aEventType == NS_MOUSE_MOVE) {
3970 if (nsToolkit::gMouseTrailer && !mIsInMouseCapture) {
3971 nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd);
3973 nsIntRect rect;
3974 GetBounds(rect);
3975 rect.x = 0;
3976 rect.y = 0;
3978 if (rect.Contains(event.refPoint)) {
3979 if (sCurrentWindow == NULL || sCurrentWindow != this) {
3980 if ((nsnull != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
3981 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3982 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, PR_FALSE,
3983 nsMouseEvent::eLeftButton, aInputSource);
3985 sCurrentWindow = this;
3986 if (!mInDtor) {
3987 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3988 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, PR_FALSE,
3989 nsMouseEvent::eLeftButton, aInputSource);
3993 } else if (aEventType == NS_MOUSE_EXIT) {
3994 if (sCurrentWindow == this) {
3995 sCurrentWindow = nsnull;
3999 result = DispatchWindowEvent(&event);
4001 if (nsToolkit::gMouseTrailer)
4002 nsToolkit::gMouseTrailer->Enable();
4004 // Release the widget with NS_IF_RELEASE() just in case
4005 // the context menu key code in nsEventListenerManager::HandleEvent()
4006 // released it already.
4007 return result;
4010 return result;
4013 // Deal with accessibile event
4014 #ifdef ACCESSIBILITY
4015 nsAccessible*
4016 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType)
4018 if (nsnull == mEventCallback) {
4019 return nsnull;
4022 nsAccessibleEvent event(PR_TRUE, aEventType, this);
4023 InitEvent(event, nsnull);
4025 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
4026 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
4027 event.isMeta = PR_FALSE;
4028 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
4030 DispatchWindowEvent(&event);
4032 return event.mAccessible;
4034 #endif
4036 PRBool nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType)
4038 if (aEventType == NS_ACTIVATE)
4039 sJustGotActivate = PR_FALSE;
4040 sJustGotDeactivate = PR_FALSE;
4042 // retrive the toplevel window or dialog
4043 HWND curWnd = mWnd;
4044 HWND toplevelWnd = NULL;
4045 while (curWnd) {
4046 toplevelWnd = curWnd;
4048 nsWindow *win = GetNSWindowPtr(curWnd);
4049 if (win) {
4050 nsWindowType wintype;
4051 win->GetWindowType(wintype);
4052 if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog)
4053 break;
4056 curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
4059 if (toplevelWnd) {
4060 nsWindow *win = GetNSWindowPtr(toplevelWnd);
4061 if (win)
4062 return win->DispatchFocus(aEventType);
4065 return PR_FALSE;
4068 // Deal with focus messages
4069 PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
4071 // call the event callback
4072 if (mEventCallback) {
4073 nsGUIEvent event(PR_TRUE, aEventType, this);
4074 InitEvent(event);
4076 //focus and blur event should go to their base widget loc, not current mouse pos
4077 event.refPoint.x = 0;
4078 event.refPoint.y = 0;
4080 NPEvent pluginEvent;
4082 switch (aEventType)
4084 case NS_ACTIVATE:
4085 pluginEvent.event = WM_SETFOCUS;
4086 break;
4087 case NS_DEACTIVATE:
4088 pluginEvent.event = WM_KILLFOCUS;
4089 break;
4090 case NS_PLUGIN_ACTIVATE:
4091 pluginEvent.event = WM_KILLFOCUS;
4092 break;
4093 default:
4094 break;
4097 event.pluginEvent = (void *)&pluginEvent;
4099 return DispatchWindowEvent(&event);
4101 return PR_FALSE;
4104 PRBool nsWindow::IsTopLevelMouseExit(HWND aWnd)
4106 DWORD pos = ::GetMessagePos();
4107 POINT mp;
4108 mp.x = GET_X_LPARAM(pos);
4109 mp.y = GET_Y_LPARAM(pos);
4110 HWND mouseWnd = ::WindowFromPoint(mp);
4112 // GetTopLevelHWND will return a HWND for the window frame (which includes
4113 // the non-client area). If the mouse has moved into the non-client area,
4114 // we should treat it as a top-level exit.
4115 HWND mouseTopLevel = nsWindow::GetTopLevelHWND(mouseWnd);
4116 if (mouseWnd == mouseTopLevel)
4117 return PR_TRUE;
4119 return nsWindow::GetTopLevelHWND(aWnd) != mouseTopLevel;
4122 PRBool nsWindow::BlurEventsSuppressed()
4124 // are they suppressed in this window?
4125 if (mBlurSuppressLevel > 0)
4126 return PR_TRUE;
4128 // are they suppressed by any container widget?
4129 HWND parentWnd = ::GetParent(mWnd);
4130 if (parentWnd) {
4131 nsWindow *parent = GetNSWindowPtr(parentWnd);
4132 if (parent)
4133 return parent->BlurEventsSuppressed();
4135 return PR_FALSE;
4138 // In some circumstances (opening dependent windows) it makes more sense
4139 // (and fixes a crash bug) to not blur the parent window. Called from
4140 // nsFilePicker.
4141 void nsWindow::SuppressBlurEvents(PRBool aSuppress)
4143 if (aSuppress)
4144 ++mBlurSuppressLevel; // for this widget
4145 else {
4146 NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression");
4147 if (mBlurSuppressLevel > 0)
4148 --mBlurSuppressLevel;
4152 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
4154 return aStatus == nsEventStatus_eConsumeNoDefault;
4157 /**************************************************************
4159 * SECTION: IPC
4161 * IPC related helpers.
4163 **************************************************************/
4165 #ifdef MOZ_IPC
4167 // static
4168 bool
4169 nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult)
4171 switch(aMsg) {
4172 case WM_SETFOCUS:
4173 case WM_KILLFOCUS:
4174 case WM_ENABLE:
4175 case WM_WINDOWPOSCHANGING:
4176 case WM_WINDOWPOSCHANGED:
4177 case WM_PARENTNOTIFY:
4178 case WM_ACTIVATEAPP:
4179 case WM_NCACTIVATE:
4180 case WM_ACTIVATE:
4181 case WM_CHILDACTIVATE:
4182 case WM_IME_SETCONTEXT:
4183 case WM_IME_NOTIFY:
4184 case WM_SHOWWINDOW:
4185 case WM_CANCELMODE:
4186 case WM_MOUSEACTIVATE:
4187 case WM_CONTEXTMENU:
4188 aResult = 0;
4189 return true;
4191 case WM_SETTINGCHANGE:
4192 case WM_SETCURSOR:
4193 return false;
4196 #ifdef DEBUG
4197 char szBuf[200];
4198 sprintf(szBuf,
4199 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg);
4200 NS_WARNING(szBuf);
4201 #endif
4203 return false;
4206 void
4207 nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
4209 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4210 "Failed to prevent a nonqueued message from running!");
4212 // Modal UI being displayed in windowless plugins.
4213 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4214 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4215 LRESULT res;
4216 if (IsAsyncResponseEvent(msg, res)) {
4217 ReplyMessage(res);
4219 return;
4222 // Handle certain sync plugin events sent to the parent which
4223 // trigger ipc calls that result in deadlocks.
4225 DWORD dwResult = 0;
4226 PRBool handled = PR_FALSE;
4228 switch(msg) {
4229 // Windowless flash sending WM_ACTIVATE events to the main window
4230 // via calls to ShowWindow.
4231 case WM_ACTIVATE:
4232 if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE &&
4233 IsWindow((HWND)lParam))
4234 handled = PR_TRUE;
4235 break;
4236 // Wheel events forwarded from the child.
4237 case WM_MOUSEWHEEL:
4238 case WM_MOUSEHWHEEL:
4239 case WM_HSCROLL:
4240 case WM_VSCROLL:
4241 // Plugins taking or losing focus triggering focus app messages.
4242 case WM_SETFOCUS:
4243 case WM_KILLFOCUS:
4244 // Windowed plugins that pass sys key events to defwndproc generate
4245 // WM_SYSCOMMAND events to the main window.
4246 case WM_SYSCOMMAND:
4247 // Windowed plugins that fire context menu selection events to parent
4248 // windows.
4249 case WM_CONTEXTMENU:
4250 // IME events fired as a result of synchronous focus changes
4251 case WM_IME_SETCONTEXT:
4252 handled = PR_TRUE;
4253 break;
4256 if (handled &&
4257 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4258 ReplyMessage(dwResult);
4262 #endif // MOZ_IPC
4264 /**************************************************************
4265 **************************************************************
4267 ** BLOCK: Native events
4269 ** Main Windows message handlers and OnXXX handlers for
4270 ** Windows event handling.
4272 **************************************************************
4273 **************************************************************/
4275 /**************************************************************
4277 * SECTION: Wind proc.
4279 * The main Windows event procedures and associated
4280 * message processing methods.
4282 **************************************************************/
4284 // The WndProc procedure for all nsWindows in this toolkit
4285 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4287 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4288 MOZ_FUNCTION_NAME, __LINE__, hWnd, msg,
4289 wParam, lParam);
4291 // Get the window which caused the event and ask it to process the message
4292 nsWindow *someWindow = GetNSWindowPtr(hWnd);
4294 #ifdef MOZ_IPC
4295 if (someWindow)
4296 someWindow->IPCWindowProcHandler(msg, wParam, lParam);
4297 #endif
4299 // create this here so that we store the last rolled up popup until after
4300 // the event has been processed.
4301 nsAutoRollup autoRollup;
4303 LRESULT popupHandlingResult;
4304 if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult))
4305 return popupHandlingResult;
4307 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4308 // why we are hitting this assert
4309 if (nsnull == someWindow) {
4310 NS_ASSERTION(someWindow, "someWindow is null, cannot call any CallWindowProc");
4311 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
4314 // hold on to the window for the life of this method, in case it gets
4315 // deleted during processing. yes, it's a double hack, since someWindow
4316 // is not really an interface.
4317 nsCOMPtr<nsISupports> kungFuDeathGrip;
4318 if (!someWindow->mInDtor) // not if we're in the destructor!
4319 kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)someWindow);
4321 // Call ProcessMessage
4322 LRESULT retValue;
4323 if (PR_TRUE == someWindow->ProcessMessage(msg, wParam, lParam, &retValue)) {
4324 return retValue;
4327 LRESULT res = ::CallWindowProcW(someWindow->GetPrevWindowProc(),
4328 hWnd, msg, wParam, lParam);
4330 return res;
4333 // The main windows message processing method for plugins.
4334 // The result means whether this method processed the native
4335 // event for plugin. If false, the native event should be
4336 // processed by the caller self.
4337 PRBool
4338 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
4339 LRESULT *aResult,
4340 PRBool &aCallDefWndProc)
4342 NS_PRECONDITION(aResult, "aResult must be non-null.");
4343 *aResult = 0;
4345 aCallDefWndProc = PR_FALSE;
4346 PRBool fallBackToNonPluginProcess = PR_FALSE;
4347 PRBool eventDispatched = PR_FALSE;
4348 PRBool dispatchPendingEvents = PR_TRUE;
4349 switch (aMsg.message) {
4350 case WM_INPUTLANGCHANGEREQUEST:
4351 case WM_INPUTLANGCHANGE:
4352 DispatchPluginEvent(aMsg);
4353 return PR_FALSE; // go to non-plug-ins processing
4355 case WM_CHAR:
4356 case WM_SYSCHAR:
4357 *aResult = ProcessCharMessage(aMsg, &eventDispatched);
4358 break;
4360 case WM_KEYUP:
4361 case WM_SYSKEYUP:
4362 *aResult = ProcessKeyUpMessage(aMsg, &eventDispatched);
4363 break;
4365 case WM_KEYDOWN:
4366 case WM_SYSKEYDOWN:
4367 *aResult = ProcessKeyDownMessage(aMsg, &eventDispatched);
4368 break;
4370 case WM_DEADCHAR:
4371 case WM_SYSDEADCHAR:
4372 case WM_CONTEXTMENU:
4374 case WM_CUT:
4375 case WM_COPY:
4376 case WM_PASTE:
4377 case WM_CLEAR:
4378 case WM_UNDO:
4380 case WM_IME_STARTCOMPOSITION:
4381 case WM_IME_COMPOSITION:
4382 case WM_IME_ENDCOMPOSITION:
4383 case WM_IME_CHAR:
4384 case WM_IME_COMPOSITIONFULL:
4385 case WM_IME_CONTROL:
4386 case WM_IME_KEYDOWN:
4387 case WM_IME_KEYUP:
4388 case WM_IME_NOTIFY:
4389 case WM_IME_REQUEST:
4390 case WM_IME_SELECT:
4391 break;
4393 case WM_IME_SETCONTEXT:
4394 // Don't synchronously dispatch when we receive WM_IME_SETCONTEXT
4395 // because we get it during plugin destruction. (bug 491848)
4396 dispatchPendingEvents = PR_FALSE;
4397 break;
4399 default:
4400 return PR_FALSE;
4403 if (!eventDispatched)
4404 aCallDefWndProc = !DispatchPluginEvent(aMsg);
4405 if (dispatchPendingEvents)
4406 DispatchPendingEvents();
4407 return PR_TRUE;
4410 // The main windows message processing method.
4411 PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
4412 LRESULT *aRetValue)
4414 // (Large blocks of code should be broken out into OnEvent handlers.)
4415 if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
4416 return PR_TRUE;
4418 #if defined(EVENT_DEBUG_OUTPUT)
4419 // First param shows all events, second param indicates whether
4420 // to show mouse move events. See nsWindowDbg for details.
4421 PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
4422 #endif
4424 PRBool eatMessage;
4425 if (nsIMM32Handler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
4426 eatMessage)) {
4427 return mWnd ? eatMessage : PR_TRUE;
4430 if (PluginHasFocus()) {
4431 PRBool callDefaultWndProc;
4432 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4433 if (ProcessMessageForPlugin(nativeMsg, aRetValue, callDefaultWndProc)) {
4434 return mWnd ? !callDefaultWndProc : PR_TRUE;
4438 static UINT vkKeyCached = 0; // caches VK code fon WM_KEYDOWN
4439 PRBool result = PR_FALSE; // call the default nsWindow proc
4440 *aRetValue = 0;
4442 static PRBool getWheelInfo = PR_TRUE;
4444 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4445 // Glass hit testing w/custom transparent margins
4446 LRESULT dwmHitResult;
4447 if (mCustomNonClient &&
4448 mCompositorFlag &&
4449 nsUXThemeData::CheckForCompositor() &&
4450 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) {
4451 *aRetValue = dwmHitResult;
4452 return PR_TRUE;
4454 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4456 switch (msg) {
4457 #ifndef WINCE
4458 // WM_QUERYENDSESSION must be handled by all windows.
4459 // Otherwise Windows thinks the window can just be killed at will.
4460 case WM_QUERYENDSESSION:
4461 if (sCanQuit == TRI_UNKNOWN)
4463 // Ask if it's ok to quit, and store the answer until we
4464 // get WM_ENDSESSION signaling the round is complete.
4465 nsCOMPtr<nsIObserverService> obsServ =
4466 mozilla::services::GetObserverService();
4467 nsCOMPtr<nsISupportsPRBool> cancelQuit =
4468 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
4469 cancelQuit->SetData(PR_FALSE);
4470 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
4472 PRBool abortQuit;
4473 cancelQuit->GetData(&abortQuit);
4474 sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
4476 *aRetValue = sCanQuit ? TRUE : FALSE;
4477 result = PR_TRUE;
4478 break;
4479 #endif
4481 #ifndef WINCE
4482 case WM_ENDSESSION:
4483 #endif
4484 case MOZ_WM_APP_QUIT:
4485 if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE))
4487 // Let's fake a shutdown sequence without actually closing windows etc.
4488 // to avoid Windows killing us in the middle. A proper shutdown would
4489 // require having a chance to pump some messages. Unfortunately
4490 // Windows won't let us do that. Bug 212316.
4491 nsCOMPtr<nsIObserverService> obsServ =
4492 mozilla::services::GetObserverService();
4493 NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
4494 obsServ->NotifyObservers(nsnull, "quit-application-granted", nsnull);
4495 obsServ->NotifyObservers(nsnull, "quit-application-forced", nsnull);
4496 obsServ->NotifyObservers(nsnull, "quit-application", nsnull);
4497 obsServ->NotifyObservers(nsnull, "profile-change-net-teardown", context.get());
4498 obsServ->NotifyObservers(nsnull, "profile-change-teardown", context.get());
4499 obsServ->NotifyObservers(nsnull, "profile-before-change", context.get());
4500 // Then a controlled but very quick exit.
4501 _exit(0);
4503 sCanQuit = TRI_UNKNOWN;
4504 result = PR_TRUE;
4505 break;
4507 #ifndef WINCE
4508 case WM_DISPLAYCHANGE:
4509 DispatchStandardEvent(NS_DISPLAYCHANGED);
4510 break;
4511 #endif
4513 case WM_SYSCOLORCHANGE:
4514 // Note: This is sent for child windows as well as top-level windows.
4515 // The Win32 toolkit normally only sends these events to top-level windows.
4516 // But we cycle through all of the childwindows and send it to them as well
4517 // so all presentations get notified properly.
4518 // See nsWindow::GlobalMsgWindowProc.
4519 DispatchStandardEvent(NS_SYSCOLORCHANGED);
4520 break;
4522 case WM_NOTIFY:
4523 // TAB change
4525 LPNMHDR pnmh = (LPNMHDR) lParam;
4527 switch (pnmh->code) {
4528 case TCN_SELCHANGE:
4530 DispatchStandardEvent(NS_TABCHANGE);
4531 result = PR_TRUE;
4533 break;
4536 break;
4538 case WM_XP_THEMECHANGED:
4540 // Update non-client margin offsets
4541 UpdateNonClientMargins();
4543 DispatchStandardEvent(NS_THEMECHANGED);
4545 // Invalidate the window so that the repaint will
4546 // pick up the new theme.
4547 Invalidate(PR_FALSE);
4549 break;
4551 case WM_FONTCHANGE:
4553 nsresult rv;
4554 PRBool didChange = PR_FALSE;
4556 // update the global font list
4557 nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
4558 if (NS_SUCCEEDED(rv)) {
4559 fontEnum->UpdateFontList(&didChange);
4560 //didChange is TRUE only if new font langGroup is added to the list.
4561 if (didChange) {
4562 // update device context font cache
4563 // Dirty but easiest way:
4564 // Changing nsIPrefBranch entry which triggers callbacks
4565 // and flows into calling mDeviceContext->FlushFontCache()
4566 // to update the font cache in all the instance of Browsers
4567 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
4568 if (prefs) {
4569 nsCOMPtr<nsIPrefBranch> fiPrefs;
4570 prefs->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs));
4571 if (fiPrefs) {
4572 PRBool fontInternalChange = PR_FALSE;
4573 fiPrefs->GetBoolPref("changed", &fontInternalChange);
4574 fiPrefs->SetBoolPref("changed", !fontInternalChange);
4578 } //if (NS_SUCCEEDED(rv))
4580 break;
4582 case WM_NCCALCSIZE:
4584 // If wParam is TRUE, it specifies that the application should indicate
4585 // which part of the client area contains valid information. The system
4586 // copies the valid information to the specified area within the new
4587 // client area. If the wParam parameter is FALSE, the application should
4588 // return zero.
4589 if (mCustomNonClient && mCompositorFlag) {
4590 if (!wParam) {
4591 result = PR_TRUE;
4592 *aRetValue = 0;
4593 break;
4596 // before:
4597 // rgrc[0]: the proposed window
4598 // rgrc[1]: the current window
4599 // rgrc[2]: the source client area
4600 // pncsp->lppos: move/size data
4601 // after:
4602 // rgrc[0]: the new client area
4603 // rgrc[1]: the destination window
4604 // rgrc[2]: the source client area
4605 // (all values in screen coordiantes)
4606 NCCALCSIZE_PARAMS *pncsp = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
4607 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd, msg, wParam, lParam);
4608 pncsp->rgrc[0].top -= mNonClientOffset.top;
4609 pncsp->rgrc[0].left -= mNonClientOffset.left;
4610 pncsp->rgrc[0].right += mNonClientOffset.right;
4611 pncsp->rgrc[0].bottom += mNonClientOffset.bottom;
4613 result = PR_TRUE;
4614 *aRetValue = res;
4616 break;
4619 case WM_NCHITTEST:
4622 * If an nc client area margin has been moved, we are responsible
4623 * for calculating where the resize margins are and returning the
4624 * appropriate set of hit test constants. DwmDefWindowProc (above)
4625 * will handle hit testing on it's command buttons if we are on a
4626 * composited desktop.
4629 if (!mCustomNonClient || !mCompositorFlag)
4630 break;
4632 *aRetValue =
4633 ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
4634 result = PR_TRUE;
4635 break;
4638 #ifndef WINCE
4639 case WM_POWERBROADCAST:
4640 // only hidden window handle this
4641 // to prevent duplicate notification
4642 if (mWindowType == eWindowType_invisible) {
4643 switch (wParam)
4645 case PBT_APMSUSPEND:
4646 PostSleepWakeNotification("sleep_notification");
4647 break;
4648 case PBT_APMRESUMEAUTOMATIC:
4649 case PBT_APMRESUMECRITICAL:
4650 case PBT_APMRESUMESUSPEND:
4651 PostSleepWakeNotification("wake_notification");
4652 break;
4655 break;
4656 #endif
4658 case WM_MOVE: // Window moved
4660 PRInt32 x = GET_X_LPARAM(lParam); // horizontal position in screen coordinates
4661 PRInt32 y = GET_Y_LPARAM(lParam); // vertical position in screen coordinates
4662 result = OnMove(x, y);
4664 break;
4666 case WM_CLOSE: // close request
4667 DispatchStandardEvent(NS_XUL_CLOSE);
4668 result = PR_TRUE; // abort window closure
4669 break;
4671 case WM_DESTROY:
4672 // clean up.
4673 OnDestroy();
4674 result = PR_TRUE;
4675 break;
4677 case WM_PAINT:
4678 *aRetValue = (int) OnPaint(NULL, 0);
4679 result = PR_TRUE;
4680 break;
4682 #ifndef WINCE
4683 case WM_PRINTCLIENT:
4684 result = OnPaint((HDC) wParam, 0);
4685 break;
4686 #endif
4688 case WM_HOTKEY:
4689 result = OnHotKey(wParam, lParam);
4690 break;
4692 case WM_SYSCHAR:
4693 case WM_CHAR:
4695 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4696 result = ProcessCharMessage(nativeMsg, nsnull);
4697 DispatchPendingEvents();
4699 break;
4701 case WM_SYSKEYUP:
4702 case WM_KEYUP:
4704 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4705 result = ProcessKeyUpMessage(nativeMsg, nsnull);
4706 DispatchPendingEvents();
4708 break;
4710 case WM_SYSKEYDOWN:
4711 case WM_KEYDOWN:
4713 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4714 result = ProcessKeyDownMessage(nativeMsg, nsnull);
4715 DispatchPendingEvents();
4717 break;
4719 // say we've dealt with erase background if widget does
4720 // not need auto-erasing
4721 case WM_ERASEBKGND:
4722 if (!AutoErase((HDC)wParam)) {
4723 *aRetValue = 1;
4724 result = PR_TRUE;
4726 break;
4728 case WM_MOUSEMOVE:
4730 #ifdef WINCE_WINDOWS_MOBILE
4731 // Reset the kill timer so that we can continue at this
4732 // priority
4733 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2seconds */, NULL);
4734 #endif
4735 // Suppress dispatch of pending events
4736 // when mouse moves are generated by widget
4737 // creation instead of user input.
4738 LPARAM lParamScreen = lParamToScreen(lParam);
4739 POINT mp;
4740 mp.x = GET_X_LPARAM(lParamScreen);
4741 mp.y = GET_Y_LPARAM(lParamScreen);
4742 PRBool userMovedMouse = PR_FALSE;
4743 if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) {
4744 userMovedMouse = PR_TRUE;
4746 mExitToNonClientArea = PR_FALSE;
4748 result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam,
4749 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4750 if (userMovedMouse) {
4751 DispatchPendingEvents();
4754 break;
4756 #ifdef WINCE_WINDOWS_MOBILE
4757 case WM_TIMER:
4758 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4759 KillTimer(mWnd, KILL_PRIORITY_ID);
4760 break;
4761 #endif
4763 case WM_LBUTTONDOWN:
4765 #ifdef WINCE_WINDOWS_MOBILE
4766 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
4767 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2 seconds */, NULL);
4768 #endif
4769 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
4770 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4771 DispatchPendingEvents();
4773 break;
4775 case WM_LBUTTONUP:
4777 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam,
4778 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4779 DispatchPendingEvents();
4781 #ifdef WINCE_WINDOWS_MOBILE
4782 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4783 KillTimer(mWnd, KILL_PRIORITY_ID);
4784 #endif
4786 break;
4788 #ifndef WINCE
4789 case WM_MOUSELEAVE:
4791 // We need to check mouse button states and put them in for
4792 // wParam.
4793 WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
4794 | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
4795 | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
4796 // Synthesize an event position because we don't get one from
4797 // WM_MOUSELEAVE.
4798 LPARAM pos = lParamToClient(::GetMessagePos());
4799 DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, PR_FALSE,
4800 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4802 break;
4803 #endif
4805 case WM_CONTEXTMENU:
4807 // if the context menu is brought up from the keyboard, |lParam|
4808 // will be maxlong.
4809 LPARAM pos;
4810 PRBool contextMenukey = PR_FALSE;
4811 if (lParam == 0xFFFFFFFF)
4813 contextMenukey = PR_TRUE;
4814 pos = lParamToClient(GetMessagePos());
4816 else
4818 pos = lParamToClient(lParam);
4821 result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey,
4822 contextMenukey ?
4823 nsMouseEvent::eLeftButton :
4824 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4826 break;
4828 case WM_LBUTTONDBLCLK:
4829 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4830 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4831 break;
4833 case WM_MBUTTONDOWN:
4835 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4836 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4837 DispatchPendingEvents();
4839 break;
4841 case WM_MBUTTONUP:
4842 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4843 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4844 DispatchPendingEvents();
4845 break;
4847 case WM_MBUTTONDBLCLK:
4848 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4849 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4850 break;
4852 case WM_RBUTTONDOWN:
4854 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4855 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4856 DispatchPendingEvents();
4858 break;
4860 case WM_RBUTTONUP:
4861 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4862 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4863 DispatchPendingEvents();
4864 break;
4866 case WM_RBUTTONDBLCLK:
4867 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4868 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4869 break;
4871 case WM_NCRBUTTONDOWN:
4872 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam),
4873 PR_FALSE, nsMouseEvent::eRightButton,
4874 MOUSE_INPUT_SOURCE());
4875 DispatchPendingEvents();
4876 break;
4878 case WM_NCRBUTTONUP:
4879 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam),
4880 PR_FALSE, nsMouseEvent::eRightButton,
4881 MOUSE_INPUT_SOURCE());
4882 DispatchPendingEvents();
4883 break;
4885 case WM_NCRBUTTONDBLCLK:
4886 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam),
4887 PR_FALSE, nsMouseEvent::eRightButton,
4888 MOUSE_INPUT_SOURCE());
4890 case WM_APPCOMMAND:
4892 PRUint32 appCommand = GET_APPCOMMAND_LPARAM(lParam);
4894 switch (appCommand)
4896 case APPCOMMAND_BROWSER_BACKWARD:
4897 case APPCOMMAND_BROWSER_FORWARD:
4898 case APPCOMMAND_BROWSER_REFRESH:
4899 case APPCOMMAND_BROWSER_STOP:
4900 case APPCOMMAND_BROWSER_SEARCH:
4901 case APPCOMMAND_BROWSER_FAVORITES:
4902 case APPCOMMAND_BROWSER_HOME:
4903 DispatchCommandEvent(appCommand);
4904 // tell the driver that we handled the event
4905 *aRetValue = 1;
4906 result = PR_TRUE;
4907 break;
4909 // default = PR_FALSE - tell the driver that the event was not handled
4911 break;
4913 case WM_HSCROLL:
4914 case WM_VSCROLL:
4915 *aRetValue = 0;
4916 result = OnScroll(msg, wParam, lParam);
4917 break;
4919 // The WM_ACTIVATE event is fired when a window is raised or lowered,
4920 // and the loword of wParam specifies which. But we don't want to tell
4921 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
4922 // events are fired. Instead, set either the sJustGotActivate or
4923 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
4924 // events once the focus events arrive.
4925 case WM_ACTIVATE:
4926 if (mEventCallback) {
4927 PRInt32 fActive = LOWORD(wParam);
4929 #if defined(WINCE_HAVE_SOFTKB)
4930 if (mIsTopWidgetWindow && sSoftKeyboardState)
4931 nsWindowCE::ToggleSoftKB(mWnd, fActive);
4932 if (nsWindowCE::sShowSIPButton == TRI_FALSE && WA_INACTIVE != fActive) {
4933 HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL );
4934 if (hWndSIPB)
4935 ShowWindow(hWndSIPB, SW_HIDE);
4938 #endif
4940 if (WA_INACTIVE == fActive) {
4941 // when minimizing a window, the deactivation and focus events will
4942 // be fired in the reverse order. Instead, just dispatch
4943 // NS_DEACTIVATE right away.
4944 if (HIWORD(wParam))
4945 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
4946 else
4947 sJustGotDeactivate = PR_TRUE;
4948 #ifndef WINCE
4949 if (mIsTopWidgetWindow)
4950 mLastKeyboardLayout = gKbdLayout.GetLayout();
4951 #endif
4953 } else {
4954 StopFlashing();
4956 sJustGotActivate = PR_TRUE;
4957 nsMouseEvent event(PR_TRUE, NS_MOUSE_ACTIVATE, this,
4958 nsMouseEvent::eReal);
4959 InitEvent(event);
4961 event.acceptActivation = PR_TRUE;
4963 PRBool result = DispatchWindowEvent(&event);
4964 #ifndef WINCE
4965 if (event.acceptActivation)
4966 *aRetValue = MA_ACTIVATE;
4967 else
4968 *aRetValue = MA_NOACTIVATE;
4970 if (sSwitchKeyboardLayout && mLastKeyboardLayout)
4971 ActivateKeyboardLayout(mLastKeyboardLayout, 0);
4972 #else
4973 *aRetValue = 0;
4974 #endif
4977 #ifdef WINCE_WINDOWS_MOBILE
4978 if (!gCheckForHTCApi && gHTCApiNavOpen == nsnull) {
4979 gCheckForHTCApi = PR_TRUE;
4981 HINSTANCE library = LoadLibrary(L"HTCAPI.dll");
4982 gHTCApiNavOpen = (HTCApiNavOpen) GetProcAddress(library, "HTCNavOpen");
4983 gHTCApiNavSetMode = (HTCApiNavSetMode) GetProcAddress(library ,"HTCNavSetMode");
4986 if (gHTCApiNavOpen != nsnull) {
4987 gHTCApiNavOpen(mWnd, 1 /* undocumented value */);
4989 if (gHTCApiNavSetMode != nsnull)
4990 gHTCApiNavSetMode ( mWnd, 4);
4991 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
4993 #endif
4994 break;
4996 #ifndef WINCE
4997 case WM_MOUSEACTIVATE:
4998 if (mWindowType == eWindowType_popup) {
4999 // a popup with a parent owner should not be activated when clicked
5000 // but should still allow the mouse event to be fired, so the return
5001 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5002 // window, just use default processing so that the window is activated.
5003 HWND owner = ::GetWindow(mWnd, GW_OWNER);
5004 if (owner && owner == ::GetForegroundWindow()) {
5005 *aRetValue = MA_NOACTIVATE;
5006 result = PR_TRUE;
5009 break;
5011 case WM_WINDOWPOSCHANGING:
5013 LPWINDOWPOS info = (LPWINDOWPOS) lParam;
5014 OnWindowPosChanging(info);
5016 break;
5017 #endif
5019 case WM_SETFOCUS:
5020 if (sJustGotActivate) {
5021 result = DispatchFocusToTopLevelWindow(NS_ACTIVATE);
5024 #ifdef ACCESSIBILITY
5025 if (nsWindow::sIsAccessibilityOn) {
5026 // Create it for the first time so that it can start firing events
5027 nsAccessible *rootAccessible = GetRootAccessible();
5029 #endif
5031 #if defined(WINCE_HAVE_SOFTKB)
5033 // On Windows CE, we have a window that overlaps
5034 // the ISP button. In this case, we should always
5035 // try to hide it when we are activated
5037 nsIMEContext IMEContext(mWnd);
5038 // Open the IME
5039 ImmSetOpenStatus(IMEContext.get(), TRUE);
5041 #endif
5042 break;
5044 case WM_KILLFOCUS:
5045 #if defined(WINCE_HAVE_SOFTKB)
5047 nsIMEContext IMEContext(mWnd);
5048 ImmSetOpenStatus(IMEContext.get(), FALSE);
5050 #endif
5051 if (sJustGotDeactivate) {
5052 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5054 break;
5056 case WM_WINDOWPOSCHANGED:
5058 WINDOWPOS *wp = (LPWINDOWPOS)lParam;
5059 OnWindowPosChanged(wp, result);
5061 break;
5063 case WM_SETTINGCHANGE:
5064 #if !defined (WINCE_WINDOWS_MOBILE)
5065 getWheelInfo = PR_TRUE;
5066 #else
5067 switch (wParam) {
5068 case SPI_SETSIPINFO:
5069 case SPI_SETCURRENTIM:
5070 nsWindowCE::OnSoftKbSettingsChange(mWnd);
5071 break;
5072 case SETTINGCHANGE_RESET:
5073 if (mWindowType == eWindowType_invisible) {
5074 // The OS sees to get confused and think that the invisable window
5075 // is in the foreground after an orientation change. By actually
5076 // setting it to the foreground and hiding it, we set it strait.
5077 // See bug 514007 for details.
5078 SetForegroundWindow(mWnd);
5079 ShowWindow(mWnd, SW_HIDE);
5081 break;
5083 #endif
5084 OnSettingsChange(wParam, lParam);
5085 break;
5087 #ifndef WINCE
5088 case WM_INPUTLANGCHANGEREQUEST:
5089 *aRetValue = TRUE;
5090 result = PR_FALSE;
5091 break;
5093 case WM_INPUTLANGCHANGE:
5094 result = OnInputLangChange((HKL)lParam);
5095 break;
5096 #endif // WINCE
5098 case WM_DESTROYCLIPBOARD:
5100 nsIClipboard* clipboard;
5101 nsresult rv = CallGetService(kCClipboardCID, &clipboard);
5102 clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
5103 NS_RELEASE(clipboard);
5105 break;
5107 #ifdef ACCESSIBILITY
5108 case WM_GETOBJECT:
5110 *aRetValue = 0;
5111 if (lParam == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
5112 nsAccessible *rootAccessible = GetRootAccessible(); // Held by a11y cache
5113 if (rootAccessible) {
5114 IAccessible *msaaAccessible = NULL;
5115 rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref
5116 if (msaaAccessible) {
5117 *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref
5118 msaaAccessible->Release(); // release extra addref
5119 result = PR_TRUE; // We handled the WM_GETOBJECT message
5124 #endif
5126 #ifndef WINCE
5127 case WM_SYSCOMMAND:
5128 // prevent Windows from trimming the working set. bug 76831
5129 if (!sTrimOnMinimize && wParam == SC_MINIMIZE) {
5130 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
5131 result = PR_TRUE;
5133 break;
5134 #endif
5137 #ifdef WINCE
5138 case WM_HIBERNATE:
5139 nsMemory::HeapMinimize(PR_TRUE);
5140 break;
5141 #endif
5143 case WM_MOUSEWHEEL:
5144 case WM_MOUSEHWHEEL:
5146 // If OnMouseWheel returns true, the event was forwarded directly to another
5147 // mozilla window message handler (ProcessMessage). In this case the return
5148 // value of the forwarded event is in 'result' which we should return immediately.
5149 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5150 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5151 // we should fall through.
5152 if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue))
5153 return result;
5155 break;
5157 #ifndef WINCE
5158 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5159 case WM_DWMCOMPOSITIONCHANGED:
5160 UpdateNonClientMargins();
5161 BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
5162 DispatchStandardEvent(NS_THEMECHANGED);
5163 UpdateGlass();
5164 Invalidate(PR_FALSE);
5165 break;
5166 #endif
5168 case WM_UPDATEUISTATE:
5170 // If the UI state has changed, fire an event so the UI updates the
5171 // keyboard cues based on the system setting and how the window was
5172 // opened. For example, a dialog opened via a keyboard press on a button
5173 // should enable cues, whereas the same dialog opened via a mouse click of
5174 // the button should not.
5175 PRInt32 action = LOWORD(wParam);
5176 if (action == UIS_SET || action == UIS_CLEAR) {
5177 nsUIStateChangeEvent event(PR_TRUE, NS_UISTATECHANGED, this);
5178 PRInt32 flags = HIWORD(wParam);
5179 if (flags & UISF_HIDEACCEL)
5180 event.showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5181 if (flags & UISF_HIDEFOCUS)
5182 event.showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5183 DispatchWindowEvent(&event);
5186 break;
5189 /* Gesture support events */
5190 case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
5191 // According to MS samples, this must be handled to enable
5192 // rotational support in multi-touch drivers.
5193 result = PR_TRUE;
5194 *aRetValue = TABLET_ROTATE_GESTURE_ENABLE;
5195 break;
5197 case WM_GESTURE:
5198 result = OnGesture(wParam, lParam);
5199 break;
5201 case WM_GESTURENOTIFY:
5203 if (mWindowType != eWindowType_invisible &&
5204 mWindowType != eWindowType_plugin &&
5205 mWindowType != eWindowType_toplevel) {
5206 // eWindowType_toplevel is the top level main frame window. Gesture support
5207 // there prevents the user from interacting with the title bar or nc
5208 // areas using a single finger. Java and plugin windows can make their
5209 // own calls.
5210 GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
5211 nsPointWin touchPoint;
5212 touchPoint = gestureinfo->ptsLocation;
5213 touchPoint.ScreenToClient(mWnd);
5214 nsGestureNotifyEvent gestureNotifyEvent(PR_TRUE, NS_GESTURENOTIFY_EVENT_START, this);
5215 gestureNotifyEvent.refPoint = touchPoint;
5216 nsEventStatus status;
5217 DispatchEvent(&gestureNotifyEvent, status);
5218 mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
5219 mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
5221 result = PR_FALSE; //should always bubble to DefWindowProc
5223 break;
5224 #endif // !defined(WINCE)
5226 case WM_CLEAR:
5228 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_DELETE, this);
5229 DispatchWindowEvent(&command);
5230 result = PR_TRUE;
5232 break;
5234 case WM_CUT:
5236 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_CUT, this);
5237 DispatchWindowEvent(&command);
5238 result = PR_TRUE;
5240 break;
5242 case WM_COPY:
5244 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_COPY, this);
5245 DispatchWindowEvent(&command);
5246 result = PR_TRUE;
5248 break;
5250 case WM_PASTE:
5252 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE, this);
5253 DispatchWindowEvent(&command);
5254 result = PR_TRUE;
5256 break;
5258 #ifndef WINCE
5259 case EM_UNDO:
5261 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO, this);
5262 DispatchWindowEvent(&command);
5263 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5264 result = PR_TRUE;
5266 break;
5268 case EM_REDO:
5270 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO, this);
5271 DispatchWindowEvent(&command);
5272 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5273 result = PR_TRUE;
5275 break;
5277 case EM_CANPASTE:
5279 // Support EM_CANPASTE message only when wParam isn't specified or
5280 // is plain text format.
5281 if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
5282 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE,
5283 this, PR_TRUE);
5284 DispatchWindowEvent(&command);
5285 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5286 result = PR_TRUE;
5289 break;
5291 case EM_CANUNDO:
5293 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO,
5294 this, PR_TRUE);
5295 DispatchWindowEvent(&command);
5296 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5297 result = PR_TRUE;
5299 break;
5301 case EM_CANREDO:
5303 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO,
5304 this, PR_TRUE);
5305 DispatchWindowEvent(&command);
5306 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5307 result = PR_TRUE;
5309 break;
5310 #endif
5312 #ifdef WINCE_WINDOWS_MOBILE
5313 //HTC NAVIGATION WHEEL EVENT
5314 case WM_HTCNAV:
5316 int distance = wParam & 0x000000FF;
5317 if ( (wParam & 0x000000100) != 0) // Counter Clockwise
5318 distance *= -1;
5319 if (OnMouseWheel(WM_MOUSEWHEEL, MAKEWPARAM(0, distance),
5320 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN) / 2,
5321 GetSystemMetrics(SM_CYSCREEN) / 2),
5322 getWheelInfo, result, aRetValue))
5323 return result;
5325 break;
5326 #endif
5328 default:
5330 #ifdef NS_ENABLE_TSF
5331 if (msg == WM_USER_TSF_TEXTCHANGE) {
5332 nsTextStore::OnTextChangeMsg();
5334 #endif //NS_ENABLE_TSF
5335 #if defined(HEAP_DUMP_EVENT)
5336 if (msg == GetHeapMsg()) {
5337 HeapDump(msg, wParam, lParam);
5338 result = PR_TRUE;
5340 #endif
5341 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5342 if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
5343 SetHasTaskbarIconBeenCreated();
5344 #endif
5345 #ifdef MOZ_IPC
5346 if (msg == sOOPPPluginFocusEvent) {
5347 if (wParam == 1) {
5348 // With OOPP, the plugin window exists in another process and is a child of
5349 // this window. This window is a placeholder plugin window for the dom. We
5350 // receive this event when the child window receives focus. (sent from
5351 // PluginInstanceParent.cpp)
5352 ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
5353 } else {
5354 // WM_KILLFOCUS was received by the child process.
5355 if (sJustGotDeactivate) {
5356 DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5360 #endif
5362 break;
5365 //*aRetValue = result;
5366 if (mWnd) {
5367 return result;
5369 else {
5370 //Events which caused mWnd destruction and aren't consumed
5371 //will crash during the Windows default processing.
5372 return PR_TRUE;
5376 /**************************************************************
5378 * SECTION: Broadcast messaging
5380 * Broadcast messages to all windows.
5382 **************************************************************/
5384 // Enumerate all child windows sending aMsg to each of them
5385 BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg)
5387 WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
5388 if (winProc == &nsWindow::WindowProc) {
5389 // it's one of our windows so go ahead and send a message to it
5390 ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0);
5392 return TRUE;
5395 // Enumerate all top level windows specifying that the children of each
5396 // top level window should be enumerated. Do *not* send the message to
5397 // each top level window since it is assumed that the toolkit will send
5398 // aMsg to them directly.
5399 BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg)
5401 // Iterate each of aTopWindows child windows sending the aMsg
5402 // to each of them.
5403 #if !defined(WINCE)
5404 ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5405 #else
5406 nsWindowCE::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5407 #endif
5408 return TRUE;
5411 // This method is called from nsToolkit::WindowProc to forward global
5412 // messages which need to be dispatched to all child windows.
5413 void nsWindow::GlobalMsgWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
5415 switch (msg) {
5416 case WM_SYSCOLORCHANGE:
5417 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5418 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5419 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5420 // all child windows as well. When running in an embedded application
5421 // we may not receive a WM_SYSCOLORCHANGE message because the top
5422 // level window is owned by the embeddor.
5423 // System color changes are posted to top-level windows only.
5424 // The NS_SYSCOLORCHANGE must be dispatched to all child
5425 // windows as well.
5426 #if !defined(WINCE)
5427 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, msg);
5428 #endif
5429 break;
5433 /**************************************************************
5435 * SECTION: Event processing helpers
5437 * Special processing for certain event types and
5438 * synthesized events.
5440 **************************************************************/
5442 PRInt32
5443 nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
5445 // Calculations are done in screen coords
5446 RECT winRect;
5447 GetWindowRect(mWnd, &winRect);
5449 // hit return constants:
5450 // HTBORDER - non-resizable border
5451 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5452 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5453 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5454 // HTCAPTION - general title bar area
5455 // HTCLIENT - area considered the client
5456 // HTCLOSE - hovering over the close button
5457 // HTMAXBUTTON - maximize button
5458 // HTMINBUTTON - minimize button
5460 PRInt32 testResult = HTCLIENT;
5462 PRBool top = PR_FALSE;
5463 PRBool bottom = PR_FALSE;
5464 PRBool left = PR_FALSE;
5465 PRBool right = PR_FALSE;
5467 if (my >= winRect.top && my <=
5468 (winRect.top + mVertResizeMargin + (mCaptionHeight - mNonClientOffset.top)))
5469 top = PR_TRUE;
5470 else if (my <= winRect.bottom && my >= (winRect.bottom - mVertResizeMargin))
5471 bottom = PR_TRUE;
5473 if (mx >= winRect.left && mx <= (winRect.left + mHorResizeMargin))
5474 left = PR_TRUE;
5475 else if (mx <= winRect.right && mx >= (winRect.right - mHorResizeMargin))
5476 right = PR_TRUE;
5478 if (top) {
5479 testResult = HTTOP;
5480 if (left)
5481 testResult = HTTOPLEFT;
5482 else if (right)
5483 testResult = HTTOPRIGHT;
5484 } else if (bottom) {
5485 testResult = HTBOTTOM;
5486 if (left)
5487 testResult = HTBOTTOMLEFT;
5488 else if (right)
5489 testResult = HTBOTTOMRIGHT;
5490 } else {
5491 if (left)
5492 testResult = HTLEFT;
5493 if (right)
5494 testResult = HTRIGHT;
5497 // There's no HTTOP in maximized state (bug 575493)
5498 if (mSizeMode == nsSizeMode_Maximized && testResult == HTTOP)
5499 testResult = HTCAPTION;
5501 if (!mIsInMouseCapture &&
5502 (testResult == HTCLIENT ||
5503 testResult == HTTOP ||
5504 testResult == HTTOPLEFT ||
5505 testResult == HTCAPTION)) {
5506 LPARAM lParam = MAKELPARAM(mx, my);
5507 LPARAM lParamClient = lParamToClient(lParam);
5508 PRBool result = DispatchMouseEvent(NS_MOUSE_MOZHITTEST, 0, lParamClient,
5509 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5510 if (result) {
5511 // The mouse is over a blank area
5512 testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
5514 if (!mExitToNonClientArea) {
5515 // The first time the mouse pointer goes from client area to non-client area,
5516 // we don't want to miss that movement so we can interpret mouseout input.
5517 ::SendMessage(mWnd, WM_MOUSEMOVE, 0, lParamClient);
5518 mExitToNonClientArea = PR_TRUE;
5520 } else {
5521 // There's content over the mouse pointer. Set HTCLIENT
5522 // to possibly override a resizer border.
5523 testResult = HTCLIENT;
5527 return testResult;
5531 #ifndef WINCE
5532 void nsWindow::PostSleepWakeNotification(const char* aNotification)
5534 nsCOMPtr<nsIObserverService> observerService =
5535 mozilla::services::GetObserverService();
5536 if (observerService)
5537 observerService->NotifyObservers(nsnull, aNotification, nsnull);
5539 #endif
5541 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, PRBool *aEventDispatched)
5543 NS_PRECONDITION(aMsg.message == WM_CHAR || aMsg.message == WM_SYSCHAR,
5544 "message is not keydown event");
5545 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5546 ("%s charCode=%d scanCode=%d\n",
5547 aMsg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
5548 aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF));
5550 // These must be checked here too as a lone WM_CHAR could be received
5551 // if a child window didn't handle it (for example Alt+Space in a content window)
5552 nsModifierKeyState modKeyState;
5553 return OnChar(aMsg, modKeyState, aEventDispatched);
5556 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, PRBool *aEventDispatched)
5558 NS_PRECONDITION(aMsg.message == WM_KEYUP || aMsg.message == WM_SYSKEYUP,
5559 "message is not keydown event");
5560 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5561 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5562 "WM_SYSKEYUP" : "WM_KEYUP", aMsg.wParam));
5564 nsModifierKeyState modKeyState;
5566 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5567 // scan code. However, this breaks Alt+Num pad input.
5568 // MSDN states the following:
5569 // Typically, ToAscii performs the translation based on the
5570 // virtual-key code. In some cases, however, bit 15 of the
5571 // uScanCode parameter may be used to distinguish between a key
5572 // press and a key release. The scan code is used for
5573 // translating ALT+number key combinations.
5575 // ignore [shift+]alt+space so the OS can handle it
5576 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5577 IS_VK_DOWN(NS_VK_SPACE)) {
5578 return FALSE;
5581 if (!nsIMM32Handler::IsComposing(this) &&
5582 (aMsg.message != WM_KEYUP || aMsg.wParam != VK_MENU)) {
5583 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5584 // This helps avoid triggering the menu bar for ALT key accelerators used in
5585 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5586 // to switch back to Mozilla in Windows 95 and Windows 98
5587 return OnKeyUp(aMsg, modKeyState, aEventDispatched);
5590 return 0;
5593 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
5594 PRBool *aEventDispatched)
5596 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5597 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5598 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg.wParam));
5599 NS_PRECONDITION(aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN,
5600 "message is not keydown event");
5602 nsModifierKeyState modKeyState;
5604 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
5605 // scan code. However, this breaks Alt+Num pad input.
5606 // MSDN states the following:
5607 // Typically, ToAscii performs the translation based on the
5608 // virtual-key code. In some cases, however, bit 15 of the
5609 // uScanCode parameter may be used to distinguish between a key
5610 // press and a key release. The scan code is used for
5611 // translating ALT+number key combinations.
5613 // ignore [shift+]alt+space so the OS can handle it
5614 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5615 IS_VK_DOWN(NS_VK_SPACE))
5616 return FALSE;
5618 LRESULT result = 0;
5619 if (modKeyState.mIsAltDown && nsIMM32Handler::IsStatusChanged()) {
5620 nsIMM32Handler::NotifyEndStatusChange();
5621 } else if (!nsIMM32Handler::IsComposing(this)) {
5622 result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nsnull);
5625 #ifndef WINCE
5626 if (aMsg.wParam == VK_MENU ||
5627 (aMsg.wParam == VK_F10 && !modKeyState.mIsShiftDown)) {
5628 // We need to let Windows handle this keypress,
5629 // by returning PR_FALSE, if there's a native menu
5630 // bar somewhere in our containing window hierarchy.
5631 // Otherwise we handle the keypress and don't pass
5632 // it on to Windows, by returning PR_TRUE.
5633 PRBool hasNativeMenu = PR_FALSE;
5634 HWND hWnd = mWnd;
5635 while (hWnd) {
5636 if (::GetMenu(hWnd)) {
5637 hasNativeMenu = PR_TRUE;
5638 break;
5640 hWnd = ::GetParent(hWnd);
5642 result = !hasNativeMenu;
5644 #endif
5646 return result;
5649 nsresult
5650 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
5651 PRInt32 aNativeKeyCode,
5652 PRUint32 aModifierFlags,
5653 const nsAString& aCharacters,
5654 const nsAString& aUnmodifiedCharacters)
5656 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
5657 nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
5658 HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
5659 if (loadedLayout == NULL)
5660 return NS_ERROR_NOT_AVAILABLE;
5662 // Setup clean key state and load desired layout
5663 BYTE originalKbdState[256];
5664 ::GetKeyboardState(originalKbdState);
5665 BYTE kbdState[256];
5666 memset(kbdState, 0, sizeof(kbdState));
5667 // This changes the state of the keyboard for the current thread only,
5668 // and we'll restore it soon, so this should be OK.
5669 ::SetKeyboardState(kbdState);
5670 HKL oldLayout = gKbdLayout.GetLayout();
5671 gKbdLayout.LoadLayout(loadedLayout);
5673 nsAutoTArray<KeyPair,10> keySequence;
5674 SetupKeyModifiersSequence(&keySequence, aModifierFlags);
5675 NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
5676 "Native VK key code out of range");
5677 keySequence.AppendElement(KeyPair(aNativeKeyCode, 0));
5679 // Simulate the pressing of each modifier key and then the real key
5680 for (PRUint32 i = 0; i < keySequence.Length(); ++i) {
5681 PRUint8 key = keySequence[i].mGeneral;
5682 PRUint8 keySpecific = keySequence[i].mSpecific;
5683 kbdState[key] = 0x81; // key is down and toggled on if appropriate
5684 if (keySpecific) {
5685 kbdState[keySpecific] = 0x81;
5687 ::SetKeyboardState(kbdState);
5688 nsModifierKeyState modKeyState;
5689 MSG msg = InitMSG(WM_KEYDOWN, key, 0);
5690 if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
5691 UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
5692 gKbdLayout.GetLayout());
5693 nsFakeCharMessage fakeMsg = { aCharacters.CharAt(0), scanCode };
5694 OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
5695 } else {
5696 OnKeyDown(msg, modKeyState, nsnull, nsnull);
5699 for (PRUint32 i = keySequence.Length(); i > 0; --i) {
5700 PRUint8 key = keySequence[i - 1].mGeneral;
5701 PRUint8 keySpecific = keySequence[i - 1].mSpecific;
5702 kbdState[key] = 0; // key is up and toggled off if appropriate
5703 if (keySpecific) {
5704 kbdState[keySpecific] = 0;
5706 ::SetKeyboardState(kbdState);
5707 nsModifierKeyState modKeyState;
5708 MSG msg = InitMSG(WM_KEYUP, key, 0);
5709 OnKeyUp(msg, modKeyState, nsnull);
5712 // Restore old key state and layout
5713 ::SetKeyboardState(originalKbdState);
5714 gKbdLayout.LoadLayout(oldLayout);
5716 UnloadKeyboardLayout(loadedLayout);
5717 return NS_OK;
5718 #else //XXX: is there another way to do this?
5719 return NS_ERROR_NOT_IMPLEMENTED;
5720 #endif
5723 nsresult
5724 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
5725 PRUint32 aNativeMessage,
5726 PRUint32 aModifierFlags)
5728 #ifndef WINCE // I don't think WINCE supports SendInput
5729 RECT r;
5730 ::GetWindowRect(mWnd, &r);
5731 ::SetCursorPos(r.left + aPoint.x, r.top + aPoint.y);
5733 INPUT input;
5734 memset(&input, 0, sizeof(input));
5736 input.type = INPUT_MOUSE;
5737 input.mi.dwFlags = aNativeMessage;
5738 ::SendInput(1, &input, sizeof(INPUT));
5740 return NS_OK;
5741 #else
5742 return NS_ERROR_NOT_IMPLEMENTED;
5743 #endif
5746 /**************************************************************
5748 * SECTION: OnXXX message handlers
5750 * For message handlers that need to be broken out or
5751 * implemented in specific platform code.
5753 **************************************************************/
5755 BOOL nsWindow::OnInputLangChange(HKL aHKL)
5757 #ifdef KE_DEBUG
5758 printf("OnInputLanguageChange\n");
5759 #endif
5761 #ifndef WINCE
5762 gKbdLayout.LoadLayout(aHKL);
5763 #endif
5765 return PR_FALSE; // always pass to child window
5768 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5769 void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, PRBool& result)
5771 if (wp == nsnull)
5772 return;
5774 #ifdef WINSTATE_DEBUG_OUTPUT
5775 if (mWnd == GetTopLevelHWND(mWnd))
5776 printf("*** OnWindowPosChanged: [ top] ");
5777 else
5778 printf("*** OnWindowPosChanged: [child] ");
5779 printf("WINDOWPOS flags:");
5780 if (wp->flags & SWP_FRAMECHANGED)
5781 printf("SWP_FRAMECHANGED ");
5782 if (wp->flags & SWP_SHOWWINDOW)
5783 printf("SWP_SHOWWINDOW ");
5784 if (wp->flags & SWP_NOSIZE)
5785 printf("SWP_NOSIZE ");
5786 if (wp->flags & SWP_HIDEWINDOW)
5787 printf("SWP_HIDEWINDOW ");
5788 printf("\n");
5789 #endif
5791 // Handle window size mode changes
5792 if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
5793 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
5795 WINDOWPLACEMENT pl;
5796 pl.length = sizeof(pl);
5797 ::GetWindowPlacement(mWnd, &pl);
5799 if (pl.showCmd == SW_SHOWMAXIMIZED)
5800 event.mSizeMode = nsSizeMode_Maximized;
5801 else if (pl.showCmd == SW_SHOWMINIMIZED)
5802 event.mSizeMode = nsSizeMode_Minimized;
5803 else
5804 event.mSizeMode = nsSizeMode_Normal;
5806 // Windows has just changed the size mode of this window. The following
5807 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
5808 // set the min/max window state again or for nsSizeMode_Normal, call
5809 // SetWindow with a parameter of SW_RESTORE. There's no need however as
5810 // this window's mode has already changed. Updating mSizeMode here
5811 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
5812 // to window docking. (bug 489258)
5813 mSizeMode = event.mSizeMode;
5815 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
5816 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
5817 // prevents the working set from being trimmed but keeps the window active.
5818 // After the window is minimized, we need to do some touch up work on the
5819 // active window. (bugs 76831 & 499816)
5820 if (!sTrimOnMinimize && nsSizeMode_Minimized == event.mSizeMode)
5821 ActivateOtherWindowHelper(mWnd);
5823 #ifdef WINSTATE_DEBUG_OUTPUT
5824 switch (mSizeMode) {
5825 case nsSizeMode_Normal:
5826 printf("*** mSizeMode: nsSizeMode_Normal\n");
5827 break;
5828 case nsSizeMode_Minimized:
5829 printf("*** mSizeMode: nsSizeMode_Minimized\n");
5830 break;
5831 case nsSizeMode_Maximized:
5832 printf("*** mSizeMode: nsSizeMode_Maximized\n");
5833 break;
5834 default:
5835 printf("*** mSizeMode: ??????\n");
5836 break;
5838 #endif
5840 InitEvent(event);
5842 result = DispatchWindowEvent(&event);
5844 // Skip window size change events below on minimization.
5845 if (mSizeMode == nsSizeMode_Minimized)
5846 return;
5849 // Handle window size changes
5850 if (0 == (wp->flags & SWP_NOSIZE)) {
5851 RECT r;
5852 PRInt32 newWidth, newHeight;
5854 ::GetWindowRect(mWnd, &r);
5856 newWidth = r.right - r.left;
5857 newHeight = r.bottom - r.top;
5858 nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
5860 #ifdef MOZ_XUL
5861 if (eTransparencyTransparent == mTransparencyMode)
5862 ResizeTranslucentWindow(newWidth, newHeight);
5863 #endif
5865 if (newWidth > mLastSize.width)
5867 RECT drect;
5869 // getting wider
5870 drect.left = wp->x + mLastSize.width;
5871 drect.top = wp->y;
5872 drect.right = drect.left + (newWidth - mLastSize.width);
5873 drect.bottom = drect.top + newHeight;
5875 ::RedrawWindow(mWnd, &drect, NULL,
5876 RDW_INVALIDATE |
5877 RDW_NOERASE |
5878 RDW_NOINTERNALPAINT |
5879 RDW_ERASENOW |
5880 RDW_ALLCHILDREN);
5882 if (newHeight > mLastSize.height)
5884 RECT drect;
5886 // getting taller
5887 drect.left = wp->x;
5888 drect.top = wp->y + mLastSize.height;
5889 drect.right = drect.left + newWidth;
5890 drect.bottom = drect.top + (newHeight - mLastSize.height);
5892 ::RedrawWindow(mWnd, &drect, NULL,
5893 RDW_INVALIDATE |
5894 RDW_NOERASE |
5895 RDW_NOINTERNALPAINT |
5896 RDW_ERASENOW |
5897 RDW_ALLCHILDREN);
5900 mBounds.width = newWidth;
5901 mBounds.height = newHeight;
5902 mLastSize.width = newWidth;
5903 mLastSize.height = newHeight;
5905 #ifdef WINSTATE_DEBUG_OUTPUT
5906 printf("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, newWidth, newHeight);
5907 #endif
5909 // Recalculate the width and height based on the client area for gecko events.
5910 if (::GetClientRect(mWnd, &r)) {
5911 rect.width = r.right - r.left;
5912 rect.height = r.bottom - r.top;
5915 // Send a gecko resize event
5916 result = OnResize(rect);
5920 // static
5921 void nsWindow::ActivateOtherWindowHelper(HWND aWnd)
5923 // Find the next window that is enabled, visible, and not minimized.
5924 HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT);
5925 while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) ||
5926 ::IsIconic(hwndBelow))) {
5927 hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT);
5930 // Push ourselves to the bottom of the stack, then activate the
5931 // next window.
5932 ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0,
5933 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
5934 if (hwndBelow)
5935 ::SetForegroundWindow(hwndBelow);
5937 // Play the minimize sound while we're here, since that is also
5938 // forgotten when we use SW_SHOWMINIMIZED.
5939 ::PlaySoundW(L"Minimize", nsnull, SND_ALIAS | SND_NODEFAULT | SND_ASYNC);
5941 #endif // !defined(WINCE)
5943 #if !defined(WINCE)
5944 void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info)
5946 // Update non-client margins if the frame size is changing, and let the
5947 // browser know we are changing size modes, so alternative css can kick in.
5948 // If we're going into fullscreen mode, ignore this, since it'll reset
5949 // margins to normal mode.
5950 if (info->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
5951 WINDOWPLACEMENT pl;
5952 pl.length = sizeof(pl);
5953 ::GetWindowPlacement(mWnd, &pl);
5954 PRInt32 sizeMode;
5955 if (pl.showCmd == SW_SHOWMAXIMIZED)
5956 sizeMode = nsSizeMode_Maximized;
5957 else if (pl.showCmd == SW_SHOWMINIMIZED)
5958 sizeMode = nsSizeMode_Minimized;
5959 else
5960 sizeMode = nsSizeMode_Normal;
5962 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
5964 InitEvent(event);
5965 event.mSizeMode = static_cast<nsSizeMode>(sizeMode);
5966 DispatchWindowEvent(&event);
5968 UpdateNonClientMargins(sizeMode, PR_FALSE);
5971 // enforce local z-order rules
5972 if (!(info->flags & SWP_NOZORDER)) {
5973 HWND hwndAfter = info->hwndInsertAfter;
5975 nsZLevelEvent event(PR_TRUE, NS_SETZLEVEL, this);
5976 nsWindow *aboveWindow = 0;
5978 InitEvent(event);
5980 if (hwndAfter == HWND_BOTTOM)
5981 event.mPlacement = nsWindowZBottom;
5982 else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
5983 event.mPlacement = nsWindowZTop;
5984 else {
5985 event.mPlacement = nsWindowZRelative;
5986 aboveWindow = GetNSWindowPtr(hwndAfter);
5988 event.mReqBelow = aboveWindow;
5989 event.mActualBelow = nsnull;
5991 event.mImmediate = PR_FALSE;
5992 event.mAdjusted = PR_FALSE;
5993 DispatchWindowEvent(&event);
5995 if (event.mAdjusted) {
5996 if (event.mPlacement == nsWindowZBottom)
5997 info->hwndInsertAfter = HWND_BOTTOM;
5998 else if (event.mPlacement == nsWindowZTop)
5999 info->hwndInsertAfter = HWND_TOP;
6000 else {
6001 info->hwndInsertAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
6004 NS_IF_RELEASE(event.mActualBelow);
6006 // prevent rude external programs from making hidden window visible
6007 if (mWindowType == eWindowType_invisible)
6008 info->flags &= ~SWP_SHOWWINDOW;
6010 #endif
6012 void nsWindow::UserActivity()
6014 // Check if we have the idle service, if not we try to get it.
6015 if (!mIdleService) {
6016 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
6019 // Check that we now have the idle service.
6020 if (mIdleService) {
6021 mIdleService->ResetIdleTimeOut();
6025 // Gesture event processing. Handles WM_GESTURE events.
6026 #if !defined(WINCE)
6027 PRBool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
6029 // Treatment for pan events which translate into scroll events:
6030 if (mGesture.IsPanEvent(lParam)) {
6031 nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
6033 if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
6034 return PR_FALSE; // ignore
6036 nsEventStatus status;
6038 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6039 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6040 event.isMeta = PR_FALSE;
6041 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6042 event.button = 0;
6043 event.time = ::GetMessageTime();
6044 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6046 PRBool endFeedback = PR_TRUE;
6048 PRInt32 scrollOverflowX = 0;
6049 PRInt32 scrollOverflowY = 0;
6051 if (mGesture.PanDeltaToPixelScrollX(event)) {
6052 DispatchEvent(&event, status);
6053 scrollOverflowX = event.scrollOverflow;
6056 if (mGesture.PanDeltaToPixelScrollY(event)) {
6057 DispatchEvent(&event, status);
6058 scrollOverflowY = event.scrollOverflow;
6061 if (mDisplayPanFeedback) {
6062 mGesture.UpdatePanFeedbackX(mWnd, scrollOverflowX, endFeedback);
6063 mGesture.UpdatePanFeedbackY(mWnd, scrollOverflowY, endFeedback);
6064 mGesture.PanFeedbackFinalize(mWnd, endFeedback);
6067 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6069 return PR_TRUE;
6072 // Other gestures translate into simple gesture events:
6073 nsSimpleGestureEvent event(PR_TRUE, 0, this, 0, 0.0);
6074 if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) {
6075 return PR_FALSE; // fall through to DefWndProc
6078 // Polish up and send off the new event
6079 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6080 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6081 event.isMeta = PR_FALSE;
6082 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6083 event.button = 0;
6084 event.time = ::GetMessageTime();
6085 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6087 nsEventStatus status;
6088 DispatchEvent(&event, status);
6089 if (status == nsEventStatus_eIgnore) {
6090 return PR_FALSE; // Ignored, fall through
6093 // Only close this if we process and return true.
6094 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6096 return PR_TRUE; // Handled
6098 #endif // !defined(WINCE)
6100 #if !defined(WINCE)
6101 PRUint16 nsWindow::GetMouseInputSource()
6103 PRUint16 inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE;
6104 LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
6105 if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
6106 inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ?
6107 nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN;
6109 return inputSource;
6111 #endif
6113 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6114 * within the message case block. If returning true result should be returned
6115 * immediately (no more processing).
6117 PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue)
6119 // Handle both flavors of mouse wheel events.
6120 static int iDeltaPerLine, iDeltaPerChar;
6121 static ULONG ulScrollLines, ulScrollChars = 1;
6122 static int currentVDelta, currentHDelta;
6123 static HWND currentWindow = 0;
6125 PRBool isVertical = msg == WM_MOUSEWHEEL;
6127 // Get mouse wheel metrics (but only once).
6128 if (getWheelInfo) {
6129 getWheelInfo = PR_FALSE;
6131 SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
6133 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6134 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6136 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6137 // the mouse driver wants a page scroll. The docs state that
6138 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6139 // since some mouse drivers use an arbitrary large number instead,
6140 // we have to handle that as well.
6142 iDeltaPerLine = 0;
6143 if (ulScrollLines) {
6144 if (ulScrollLines <= WHEEL_DELTA) {
6145 iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
6146 } else {
6147 ulScrollLines = WHEEL_PAGESCROLL;
6151 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
6152 &ulScrollChars, 0)) {
6153 // Note that we may always fail to get the value before Win Vista.
6154 ulScrollChars = 1;
6157 iDeltaPerChar = 0;
6158 if (ulScrollChars) {
6159 if (ulScrollChars <= WHEEL_DELTA) {
6160 iDeltaPerChar = WHEEL_DELTA / ulScrollChars;
6161 } else {
6162 ulScrollChars = WHEEL_PAGESCROLL;
6167 if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) ||
6168 (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar))
6169 return PR_FALSE; // break
6171 // The mousewheel event will be dispatched to the toplevel
6172 // window. We need to give it to the child window
6173 PRBool quit;
6174 if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit))
6175 return quit; // return immediately if its not our window
6177 // We should cancel the surplus delta if the current window is not
6178 // same as previous.
6179 if (currentWindow != mWnd) {
6180 currentVDelta = 0;
6181 currentHDelta = 0;
6182 currentWindow = mWnd;
6185 nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
6186 scrollEvent.delta = 0;
6187 if (isVertical) {
6188 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
6189 if (ulScrollLines == WHEEL_PAGESCROLL) {
6190 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6191 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1;
6192 } else {
6193 currentVDelta -= (short) HIWORD (wParam);
6194 if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
6195 scrollEvent.delta = currentVDelta / iDeltaPerLine;
6196 currentVDelta %= iDeltaPerLine;
6199 } else {
6200 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
6201 if (ulScrollChars == WHEEL_PAGESCROLL) {
6202 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6203 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1;
6204 } else {
6205 currentHDelta += (short) HIWORD (wParam);
6206 if (PR_ABS(currentHDelta) >= iDeltaPerChar) {
6207 scrollEvent.delta = currentHDelta / iDeltaPerChar;
6208 currentHDelta %= iDeltaPerChar;
6213 if (!scrollEvent.delta) {
6214 // We store the wheel delta, and it will be used next wheel message, so,
6215 // we consume this message actually. We shouldn't call next wndproc.
6216 result = PR_TRUE;
6217 return PR_FALSE; // break
6220 #ifdef MOZ_IPC
6221 // The event may go to a plug-in which already dispatched this message.
6222 // Then, the event can cause deadlock. We should unlock the sender here.
6223 ::ReplyMessage(isVertical ? 0 : TRUE);
6224 #endif
6226 scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6227 scrollEvent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6228 scrollEvent.isMeta = PR_FALSE;
6229 scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT);
6230 InitEvent(scrollEvent);
6231 if (nsnull != mEventCallback) {
6232 result = DispatchWindowEvent(&scrollEvent);
6234 // Note that we should return zero if we process WM_MOUSEWHEEL.
6235 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6237 if (result)
6238 *aRetValue = isVertical ? 0 : TRUE;
6240 return PR_FALSE; // break;
6243 static PRBool
6244 StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,
6245 const PRUnichar* aChars2, const PRUint32 aNumChars2)
6247 if (aNumChars1 != aNumChars2)
6248 return PR_FALSE;
6250 nsCaseInsensitiveStringComparator comp;
6251 return comp(aChars1, aChars2, aNumChars1) == 0;
6254 UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
6256 #ifndef WINCE
6257 switch (aNativeKeyCode) {
6258 case VK_OEM_1: return NS_VK_SEMICOLON; // 0xBA, For the US standard keyboard, the ';:' key
6259 case VK_OEM_PLUS: return NS_VK_ADD; // 0xBB, For any country/region, the '+' key
6260 case VK_OEM_MINUS: return NS_VK_SUBTRACT; // 0xBD, For any country/region, the '-' key
6262 #endif
6264 return aNativeKeyCode;
6268 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6269 * WM_CHAR messages for processing. During testing we don't want to
6270 * mess with the real message queue. Instead we pass a
6271 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6272 * that as if it was in the message queue, and refrain from actually
6273 * looking at or touching the message queue.
6275 LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
6276 nsModifierKeyState &aModKeyState,
6277 PRBool *aEventDispatched,
6278 nsFakeCharMessage* aFakeCharMessage)
6280 UINT virtualKeyCode = aMsg.wParam;
6282 #ifndef WINCE
6283 gKbdLayout.OnKeyDown (virtualKeyCode);
6284 #endif
6286 // Use only DOMKeyCode for XP processing.
6287 // Use aVirtualKeyCode for gKbdLayout and native processing.
6288 UINT DOMKeyCode = nsIMM32Handler::IsComposing(this) ?
6289 virtualKeyCode : MapFromNativeToDOM(virtualKeyCode);
6291 #ifdef DEBUG
6292 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6293 #endif
6295 PRBool noDefault =
6296 DispatchKeyEvent(NS_KEY_DOWN, 0, nsnull, DOMKeyCode, &aMsg, aModKeyState);
6297 if (aEventDispatched)
6298 *aEventDispatched = PR_TRUE;
6300 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6301 // for almost all keys
6302 switch (DOMKeyCode) {
6303 case NS_VK_SHIFT:
6304 case NS_VK_CONTROL:
6305 case NS_VK_ALT:
6306 case NS_VK_CAPS_LOCK:
6307 case NS_VK_NUM_LOCK:
6308 case NS_VK_SCROLL_LOCK: return noDefault;
6311 PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
6312 MSG msg;
6313 BOOL gotMsg = aFakeCharMessage ||
6314 ::PeekMessageW(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6315 // Enter and backspace are always handled here to avoid for example the
6316 // confusion between ctrl-enter and ctrl-J.
6317 if (DOMKeyCode == NS_VK_RETURN || DOMKeyCode == NS_VK_BACK ||
6318 ((aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)
6319 #ifdef WINCE
6321 #else
6322 && !gKbdLayout.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
6323 #endif
6325 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6326 // They can be more than one because of:
6327 // * Dead-keys not pairing with base character
6328 // * Some keyboard layouts may map up to 4 characters to the single key
6329 PRBool anyCharMessagesRemoved = PR_FALSE;
6331 if (aFakeCharMessage) {
6332 anyCharMessagesRemoved = PR_TRUE;
6333 } else {
6334 while (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR))
6336 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6337 ("%s charCode=%d scanCode=%d\n", msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6338 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6339 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST, WM_KEYLAST);
6340 anyCharMessagesRemoved = PR_TRUE;
6342 gotMsg = ::PeekMessageW (&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6346 if (!anyCharMessagesRemoved && DOMKeyCode == NS_VK_BACK &&
6347 nsIMM32Handler::IsDoingKakuteiUndo(mWnd)) {
6348 NS_ASSERTION(!aFakeCharMessage,
6349 "We shouldn't be touching the real msg queue");
6350 RemoveMessageAndDispatchPluginEvent(WM_CHAR, WM_CHAR);
6353 else if (gotMsg &&
6354 (aFakeCharMessage ||
6355 msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
6356 if (aFakeCharMessage)
6357 return OnCharRaw(aFakeCharMessage->mCharCode,
6358 aFakeCharMessage->mScanCode, aModKeyState, extraFlags);
6360 // If prevent default set for keydown, do same for keypress
6361 ::GetMessageW(&msg, mWnd, msg.message, msg.message);
6363 if (msg.message == WM_DEADCHAR) {
6364 if (!PluginHasFocus())
6365 return PR_FALSE;
6367 // We need to send the removed message to focused plug-in.
6368 DispatchPluginEvent(msg);
6369 return noDefault;
6372 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6373 ("%s charCode=%d scanCode=%d\n",
6374 msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6375 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6377 BOOL result = OnChar(msg, aModKeyState, nsnull, extraFlags);
6378 // If a syschar keypress wasn't processed, Windows may want to
6379 // handle it to activate a native menu.
6380 if (!result && msg.message == WM_SYSCHAR)
6381 ::DefWindowProcW(mWnd, msg.message, msg.wParam, msg.lParam);
6382 return result;
6384 #ifndef WINCE
6385 else if (!aModKeyState.mIsControlDown && !aModKeyState.mIsAltDown &&
6386 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode) ||
6387 KeyboardLayout::IsNumpadKey(virtualKeyCode)))
6389 // If this is simple KeyDown event but next message is not WM_CHAR,
6390 // this event may not input text, so we should ignore this event.
6391 // See bug 314130.
6392 return PluginHasFocus() && noDefault;
6395 if (gKbdLayout.IsDeadKey ())
6396 return PluginHasFocus() && noDefault;
6398 PRUint8 shiftStates[5];
6399 PRUnichar uniChars[5];
6400 PRUnichar shiftedChars[5] = {0, 0, 0, 0, 0};
6401 PRUnichar unshiftedChars[5] = {0, 0, 0, 0, 0};
6402 PRUnichar shiftedLatinChar = 0;
6403 PRUnichar unshiftedLatinChar = 0;
6404 PRUint32 numOfUniChars = 0;
6405 PRUint32 numOfShiftedChars = 0;
6406 PRUint32 numOfUnshiftedChars = 0;
6407 PRUint32 numOfShiftStates = 0;
6409 switch (virtualKeyCode) {
6410 // keys to be sent as characters
6411 case VK_ADD: uniChars [0] = '+'; numOfUniChars = 1; break;
6412 case VK_SUBTRACT: uniChars [0] = '-'; numOfUniChars = 1; break;
6413 case VK_DIVIDE: uniChars [0] = '/'; numOfUniChars = 1; break;
6414 case VK_MULTIPLY: uniChars [0] = '*'; numOfUniChars = 1; break;
6415 case VK_NUMPAD0:
6416 case VK_NUMPAD1:
6417 case VK_NUMPAD2:
6418 case VK_NUMPAD3:
6419 case VK_NUMPAD4:
6420 case VK_NUMPAD5:
6421 case VK_NUMPAD6:
6422 case VK_NUMPAD7:
6423 case VK_NUMPAD8:
6424 case VK_NUMPAD9:
6425 uniChars [0] = virtualKeyCode - VK_NUMPAD0 + '0';
6426 numOfUniChars = 1;
6427 break;
6428 default:
6429 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
6430 numOfUniChars = numOfShiftStates =
6431 gKbdLayout.GetUniChars(uniChars, shiftStates,
6432 NS_ARRAY_LENGTH(uniChars));
6435 if (aModKeyState.mIsControlDown ^ aModKeyState.mIsAltDown) {
6436 PRUint8 capsLockState = (::GetKeyState(VK_CAPITAL) & 1) ? eCapsLock : 0;
6437 numOfUnshiftedChars =
6438 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode, capsLockState,
6439 unshiftedChars, NS_ARRAY_LENGTH(unshiftedChars));
6440 numOfShiftedChars =
6441 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode,
6442 capsLockState | eShift,
6443 shiftedChars, NS_ARRAY_LENGTH(shiftedChars));
6445 // The current keyboard cannot input alphabets or numerics,
6446 // we should append them for Shortcut/Access keys.
6447 // E.g., for Cyrillic keyboard layout.
6448 if (NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z) {
6449 shiftedLatinChar = unshiftedLatinChar = DOMKeyCode;
6450 if (capsLockState)
6451 shiftedLatinChar += 0x20;
6452 else
6453 unshiftedLatinChar += 0x20;
6454 if (unshiftedLatinChar == unshiftedChars[0] &&
6455 shiftedLatinChar == shiftedChars[0]) {
6456 shiftedLatinChar = unshiftedLatinChar = 0;
6458 } else {
6459 PRUint16 ch = 0;
6460 if (NS_VK_0 <= DOMKeyCode && DOMKeyCode <= NS_VK_9) {
6461 ch = DOMKeyCode;
6462 } else {
6463 switch (virtualKeyCode) {
6464 case VK_OEM_PLUS: ch = '+'; break;
6465 case VK_OEM_MINUS: ch = '-'; break;
6468 if (ch && unshiftedChars[0] != ch && shiftedChars[0] != ch) {
6469 // Windows has assigned a virtual key code to the key even though
6470 // the character can't be produced with this key. That probably
6471 // means the character can't be produced with any key in the
6472 // current layout and so the assignment is based on a QWERTY
6473 // layout. Append this code so that users can access the shortcut.
6474 unshiftedLatinChar = ch;
6478 // If the charCode is not ASCII character, we should replace the
6479 // charCode with ASCII character only when Ctrl is pressed.
6480 // But don't replace the charCode when the charCode is not same as
6481 // unmodified characters. In such case, Ctrl is sometimes used for a
6482 // part of character inputting key combination like Shift.
6483 if (aModKeyState.mIsControlDown) {
6484 PRUint8 currentState = eCtrl;
6485 if (aModKeyState.mIsShiftDown)
6486 currentState |= eShift;
6488 PRUint32 ch =
6489 aModKeyState.mIsShiftDown ? shiftedLatinChar : unshiftedLatinChar;
6490 if (ch &&
6491 (numOfUniChars == 0 ||
6492 StringCaseInsensitiveEquals(uniChars, numOfUniChars,
6493 aModKeyState.mIsShiftDown ? shiftedChars : unshiftedChars,
6494 aModKeyState.mIsShiftDown ? numOfShiftedChars :
6495 numOfUnshiftedChars))) {
6496 numOfUniChars = numOfShiftStates = 1;
6497 uniChars[0] = ch;
6498 shiftStates[0] = currentState;
6504 if (numOfUniChars > 0 || numOfShiftedChars > 0 || numOfUnshiftedChars > 0) {
6505 PRUint32 num = PR_MAX(numOfUniChars,
6506 PR_MAX(numOfShiftedChars, numOfUnshiftedChars));
6507 PRUint32 skipUniChars = num - numOfUniChars;
6508 PRUint32 skipShiftedChars = num - numOfShiftedChars;
6509 PRUint32 skipUnshiftedChars = num - numOfUnshiftedChars;
6510 UINT keyCode = numOfUniChars == 0 ? DOMKeyCode : 0;
6511 for (PRUint32 cnt = 0; cnt < num; cnt++) {
6512 PRUint16 uniChar, shiftedChar, unshiftedChar;
6513 uniChar = shiftedChar = unshiftedChar = 0;
6514 if (skipUniChars <= cnt) {
6515 if (cnt - skipUniChars < numOfShiftStates) {
6516 // If key in combination with Alt and/or Ctrl produces a different
6517 // character than without them then do not report these flags
6518 // because it is separate keyboard layout shift state. If dead-key
6519 // and base character does not produce a valid composite character
6520 // then both produced dead-key character and following base
6521 // character may have different modifier flags, too.
6522 aModKeyState.mIsShiftDown =
6523 (shiftStates[cnt - skipUniChars] & eShift) != 0;
6524 aModKeyState.mIsControlDown =
6525 (shiftStates[cnt - skipUniChars] & eCtrl) != 0;
6526 aModKeyState.mIsAltDown =
6527 (shiftStates[cnt - skipUniChars] & eAlt) != 0;
6529 uniChar = uniChars[cnt - skipUniChars];
6531 if (skipShiftedChars <= cnt)
6532 shiftedChar = shiftedChars[cnt - skipShiftedChars];
6533 if (skipUnshiftedChars <= cnt)
6534 unshiftedChar = unshiftedChars[cnt - skipUnshiftedChars];
6535 nsAutoTArray<nsAlternativeCharCode, 5> altArray;
6537 if (shiftedChar || unshiftedChar) {
6538 nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
6539 altArray.AppendElement(chars);
6541 if (cnt == num - 1 && (unshiftedLatinChar || shiftedLatinChar)) {
6542 nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
6543 altArray.AppendElement(chars);
6546 DispatchKeyEvent(NS_KEY_PRESS, uniChar, &altArray,
6547 keyCode, nsnull, aModKeyState, extraFlags);
6549 } else {
6550 DispatchKeyEvent(NS_KEY_PRESS, 0, nsnull, DOMKeyCode, nsnull, aModKeyState,
6551 extraFlags);
6553 #else
6555 UINT unichar = ::MapVirtualKey(virtualKeyCode, MAPVK_VK_TO_CHAR);
6556 // Check for dead characters or no mapping
6557 if (unichar & 0x80) {
6558 return noDefault;
6560 DispatchKeyEvent(NS_KEY_PRESS, unichar, nsnull, DOMKeyCode, nsnull, aModKeyState,
6561 extraFlags);
6563 #endif
6565 return noDefault;
6568 // OnKeyUp
6569 LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
6570 nsModifierKeyState &aModKeyState,
6571 PRBool *aEventDispatched)
6573 UINT virtualKeyCode = aMsg.wParam;
6575 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6576 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
6578 if (!nsIMM32Handler::IsComposing(this)) {
6579 virtualKeyCode = MapFromNativeToDOM(virtualKeyCode);
6582 if (aEventDispatched)
6583 *aEventDispatched = PR_TRUE;
6584 return DispatchKeyEvent(NS_KEY_UP, 0, nsnull, virtualKeyCode, &aMsg,
6585 aModKeyState);
6588 // OnChar
6589 LRESULT nsWindow::OnChar(const MSG &aMsg, nsModifierKeyState &aModKeyState,
6590 PRBool *aEventDispatched, PRUint32 aFlags)
6592 return OnCharRaw(aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF, aModKeyState,
6593 aFlags, &aMsg, aEventDispatched);
6596 // OnCharRaw
6597 LRESULT nsWindow::OnCharRaw(UINT charCode, UINT aScanCode,
6598 nsModifierKeyState &aModKeyState, PRUint32 aFlags,
6599 const MSG *aMsg, PRBool *aEventDispatched)
6601 // ignore [shift+]alt+space so the OS can handle it
6602 if (aModKeyState.mIsAltDown && !aModKeyState.mIsControlDown &&
6603 IS_VK_DOWN(NS_VK_SPACE)) {
6604 return FALSE;
6607 // Ignore Ctrl+Enter (bug 318235)
6608 if (aModKeyState.mIsControlDown && charCode == 0xA) {
6609 return FALSE;
6612 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
6613 PRBool saveIsAltDown = aModKeyState.mIsAltDown;
6614 PRBool saveIsControlDown = aModKeyState.mIsControlDown;
6615 if (aModKeyState.mIsAltDown && aModKeyState.mIsControlDown)
6616 aModKeyState.mIsAltDown = aModKeyState.mIsControlDown = PR_FALSE;
6618 wchar_t uniChar;
6620 if (nsIMM32Handler::IsComposing(this)) {
6621 ResetInputState();
6624 if (aModKeyState.mIsControlDown && charCode <= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
6625 // need to account for shift here. bug 16486
6626 if (aModKeyState.mIsShiftDown)
6627 uniChar = charCode - 1 + 'A';
6628 else
6629 uniChar = charCode - 1 + 'a';
6630 charCode = 0;
6632 else if (aModKeyState.mIsControlDown && charCode <= 0x1F) {
6633 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
6634 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
6635 // for some reason the keypress handler need to have the uniChar code set
6636 // with the addition of a upper case A not the lower case.
6637 uniChar = charCode - 1 + 'A';
6638 charCode = 0;
6639 } else { // 0x20 - SPACE, 0x3D - EQUALS
6640 if (charCode < 0x20 || (charCode == 0x3D && aModKeyState.mIsControlDown)) {
6641 uniChar = 0;
6642 } else {
6643 uniChar = charCode;
6644 charCode = 0;
6648 // Keep the characters unshifted for shortcuts and accesskeys and make sure
6649 // that numbers are always passed as such (among others: bugs 50255 and 351310)
6650 if (uniChar && (aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)) {
6651 UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK,
6652 gKbdLayout.GetLayout());
6653 UINT unshiftedCharCode =
6654 virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
6655 aModKeyState.mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode,
6656 MAPVK_VK_TO_CHAR,
6657 gKbdLayout.GetLayout()) : 0;
6658 // ignore diacritics (top bit set) and key mapping errors (char code 0)
6659 if ((INT)unshiftedCharCode > 0)
6660 uniChar = unshiftedCharCode;
6663 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
6664 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
6665 // pressed too.
6666 if (!aModKeyState.mIsShiftDown && (saveIsAltDown || saveIsControlDown)) {
6667 uniChar = towlower(uniChar);
6670 PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, nsnull,
6671 charCode, aMsg, aModKeyState, aFlags);
6672 if (aEventDispatched)
6673 *aEventDispatched = PR_TRUE;
6674 aModKeyState.mIsAltDown = saveIsAltDown;
6675 aModKeyState.mIsControlDown = saveIsControlDown;
6676 return result;
6679 void
6680 nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers)
6682 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierKeyMap); ++i) {
6683 const PRUint32* map = sModifierKeyMap[i];
6684 if (aModifiers & map[0]) {
6685 aArray->AppendElement(KeyPair(map[1], map[2]));
6690 nsresult
6691 nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
6693 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
6694 // here, if that helps in some situations. So far I haven't seen a
6695 // need.
6696 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
6697 const Configuration& configuration = aConfigurations[i];
6698 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
6699 NS_ASSERTION(w->GetParent() == this,
6700 "Configured widget is not a child");
6701 #ifdef WINCE
6702 // MSDN says we should do on WinCE this before moving or resizing the window
6703 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
6704 // We put the region back just below, anyway.
6705 ::SetWindowRgn(w->mWnd, NULL, TRUE);
6706 #endif
6707 nsIntRect bounds;
6708 w->GetBounds(bounds);
6709 if (bounds.Size() != configuration.mBounds.Size()) {
6710 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
6711 configuration.mBounds.width, configuration.mBounds.height,
6712 PR_TRUE);
6713 } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
6714 w->Move(configuration.mBounds.x, configuration.mBounds.y);
6716 nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_FALSE);
6717 NS_ENSURE_SUCCESS(rv, rv);
6719 return NS_OK;
6722 static HRGN
6723 CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
6725 PRInt32 size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
6726 nsAutoTArray<PRUint8,100> buf;
6727 if (!buf.SetLength(size))
6728 return NULL;
6729 RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
6730 RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
6731 data->rdh.dwSize = sizeof(data->rdh);
6732 data->rdh.iType = RDH_RECTANGLES;
6733 data->rdh.nCount = aRects.Length();
6734 nsIntRect bounds;
6735 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
6736 const nsIntRect& r = aRects[i];
6737 bounds.UnionRect(bounds, r);
6738 ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
6740 ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
6741 return ::ExtCreateRegion(NULL, buf.Length(), data);
6744 nsresult
6745 nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
6746 PRBool aIntersectWithExisting)
6748 if (!aIntersectWithExisting) {
6749 if (!StoreWindowClipRegion(aRects))
6750 return NS_OK;
6753 HRGN dest = CreateHRGNFromArray(aRects);
6754 if (!dest)
6755 return NS_ERROR_OUT_OF_MEMORY;
6757 if (aIntersectWithExisting) {
6758 HRGN current = ::CreateRectRgn(0, 0, 0, 0);
6759 if (current) {
6760 if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
6761 ::CombineRgn(dest, dest, current, RGN_AND);
6763 ::DeleteObject(current);
6767 if (!::SetWindowRgn(mWnd, dest, TRUE)) {
6768 ::DeleteObject(dest);
6769 return NS_ERROR_FAILURE;
6771 return NS_OK;
6774 // WM_DESTROY event handler
6775 void nsWindow::OnDestroy()
6777 mOnDestroyCalled = PR_TRUE;
6779 // Make sure we don't get destroyed in the process of tearing down.
6780 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
6782 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
6783 if (!mInDtor)
6784 DispatchStandardEvent(NS_DESTROY);
6786 // Prevent the widget from sending additional events.
6787 mEventCallback = nsnull;
6789 // Free our subclass and clear |this| stored in the window props. We will no longer
6790 // receive events from Windows after this point.
6791 SubclassWindow(FALSE);
6793 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
6794 // cleared. (It's used in tracking windows for mouse events.)
6795 if (sCurrentWindow == this)
6796 sCurrentWindow = nsnull;
6798 // Disconnects us from our parent, will call our GetParent().
6799 nsBaseWidget::Destroy();
6801 // Release references to children, device context, toolkit, and app shell.
6802 nsBaseWidget::OnDestroy();
6804 // Clear our native parent handle.
6805 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
6806 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
6807 //SetParent(nsnull);
6808 mParent = nsnull;
6810 // We have to destroy the native drag target before we null out our window pointer.
6811 EnableDragDrop(PR_FALSE);
6813 // If we're going away and for some reason we're still the rollup widget, rollup and
6814 // turn off capture.
6815 if ( this == sRollupWidget ) {
6816 if ( sRollupListener )
6817 sRollupListener->Rollup(nsnull, nsnull);
6818 CaptureRollupEvents(nsnull, nsnull, PR_FALSE, PR_TRUE);
6821 // If IME is disabled, restore it.
6822 if (mOldIMC) {
6823 mOldIMC = ::ImmAssociateContext(mWnd, mOldIMC);
6824 NS_ASSERTION(!mOldIMC, "Another IMC was associated");
6827 // Turn off mouse trails if enabled.
6828 MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
6829 if (mtrailer) {
6830 if (mtrailer->GetMouseTrailerWindow() == mWnd)
6831 mtrailer->DestroyTimer();
6833 if (mtrailer->GetCaptureWindow() == mWnd)
6834 mtrailer->SetCaptureWindow(nsnull);
6837 // Free GDI window class objects
6838 if (mBrush) {
6839 VERIFY(::DeleteObject(mBrush));
6840 mBrush = NULL;
6843 // Free app icon resources.
6844 HICON icon;
6845 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM) 0);
6846 if (icon)
6847 ::DestroyIcon(icon);
6849 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM) 0);
6850 if (icon)
6851 ::DestroyIcon(icon);
6853 // Destroy any custom cursor resources.
6854 if (mCursor == -1)
6855 SetCursor(eCursor_standard);
6857 #ifdef MOZ_XUL
6858 // Reset transparency
6859 if (eTransparencyTransparent == mTransparencyMode)
6860 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
6861 #endif
6863 #if defined(WINCE_HAVE_SOFTKB)
6864 // Revert the changes made for the software keyboard settings
6865 nsWindowCE::ResetSoftKB(mWnd);
6866 #endif
6868 #if !defined(WINCE)
6869 // Finalize panning feedback to possibly restore window displacement
6870 mGesture.PanFeedbackFinalize(mWnd, PR_TRUE);
6871 #endif
6873 // Clear the main HWND.
6874 mWnd = NULL;
6877 // OnMove
6878 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
6880 mBounds.x = aX;
6881 mBounds.y = aY;
6883 nsGUIEvent event(PR_TRUE, NS_MOVE, this);
6884 InitEvent(event);
6885 event.refPoint.x = aX;
6886 event.refPoint.y = aY;
6888 return DispatchWindowEvent(&event);
6891 // Send a resize message to the listener
6892 PRBool nsWindow::OnResize(nsIntRect &aWindowRect)
6894 #ifdef CAIRO_HAS_D2D_SURFACE
6895 if (mD2DWindowSurface) {
6896 mD2DWindowSurface = NULL;
6897 Invalidate(PR_FALSE);
6899 #endif
6900 // call the event callback
6901 if (mEventCallback) {
6902 nsSizeEvent event(PR_TRUE, NS_SIZE, this);
6903 InitEvent(event);
6904 event.windowSize = &aWindowRect;
6905 RECT r;
6906 if (::GetWindowRect(mWnd, &r)) {
6907 event.mWinWidth = PRInt32(r.right - r.left);
6908 event.mWinHeight = PRInt32(r.bottom - r.top);
6909 } else {
6910 event.mWinWidth = 0;
6911 event.mWinHeight = 0;
6914 #if 0
6915 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
6916 aWindowRect.x, aWindowRect.y, aWindowRect.width, aWindowRect.height,
6917 event.mWinWidth, event.mWinHeight);
6918 #endif
6920 return DispatchWindowEvent(&event);
6923 return PR_FALSE;
6926 #if !defined(WINCE) // implemented in nsWindowCE.cpp
6927 PRBool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
6929 return PR_TRUE;
6931 #endif // !defined(WINCE)
6933 void nsWindow::OnSettingsChange(WPARAM wParam, LPARAM lParam)
6935 if (mWindowType == eWindowType_dialog ||
6936 mWindowType == eWindowType_toplevel )
6937 nsWindowGfx::OnSettingsChangeGfx(wParam);
6940 static PRBool IsOurProcessWindow(HWND aHWND)
6942 DWORD processId = 0;
6943 ::GetWindowThreadProcessId(aHWND, &processId);
6944 return processId == ::GetCurrentProcessId();
6947 static HWND FindOurProcessWindow(HWND aHWND)
6949 for (HWND wnd = ::GetParent(aHWND); wnd; wnd = ::GetParent(wnd)) {
6950 if (IsOurProcessWindow(wnd)) {
6951 return wnd;
6954 return nsnull;
6957 // Scrolling helper function for handling plugins.
6958 // Return value indicates whether the calling function should handle this
6959 // aHandled indicates whether this was handled at all
6960 // aQuitProcessing tells whether or not to continue processing the message
6961 PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
6962 LPARAM aLParam, PRBool& aHandled,
6963 LRESULT* aRetValue,
6964 PRBool& aQuitProcessing)
6966 // The scroll event will be dispatched to the toplevel
6967 // window. We need to give it to the child window
6968 aQuitProcessing = PR_FALSE; // default is to not stop processing
6969 POINT point;
6970 DWORD dwPoints = ::GetMessagePos();
6971 point.x = GET_X_LPARAM(dwPoints);
6972 point.y = GET_Y_LPARAM(dwPoints);
6974 static PRBool sIsProcessing = PR_FALSE;
6975 if (sIsProcessing) {
6976 return PR_TRUE; // the caller should handle this.
6979 static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
6980 if (aMsg == WM_MOUSEHWHEEL) {
6981 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
6982 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
6983 // message at first time, this time, ::GetMessagePos works fine.
6984 // Then, we will return 0 (0 means we process it) to the message. Then, the
6985 // driver will POST the same messages continuously during the wheel tilted.
6986 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
6987 // cursor isn't 0,0. Therefore, we cannot trust the result of
6988 // ::GetMessagePos API if the sender is the driver.
6989 if (!sMayBeUsingLogitechMouse && aLParam == 0 && aLParam != dwPoints &&
6990 ::InSendMessage()) {
6991 sMayBeUsingLogitechMouse = PR_TRUE;
6992 } else if (sMayBeUsingLogitechMouse && aLParam != 0 && ::InSendMessage()) {
6993 // The user has changed the mouse from Logitech's to another one (e.g.,
6994 // the user has changed to the touchpad of the notebook.
6995 sMayBeUsingLogitechMouse = PR_FALSE;
6997 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
6998 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
6999 // instead.
7000 if (sMayBeUsingLogitechMouse && aLParam == 0 && dwPoints == 0) {
7001 ::GetCursorPos(&point);
7005 HWND destWnd = ::WindowFromPoint(point);
7006 // Since we receive scroll events for as long as
7007 // we are focused, it's entirely possible that there
7008 // is another app's window or no window under the
7009 // pointer.
7011 if (!destWnd) {
7012 // No window is under the pointer
7013 return PR_FALSE; // break, but continue processing
7016 nsWindow* destWindow;
7018 // We don't handle the message if the found window belongs to another
7019 // process's top window. If it belongs window, that is a plug-in's window.
7020 // Then, we need to send the message to the plug-in window.
7021 if (!IsOurProcessWindow(destWnd)) {
7022 HWND ourPluginWnd = FindOurProcessWindow(destWnd);
7023 if (!ourPluginWnd) {
7024 // Somebody elses window
7025 return PR_FALSE; // break, but continue processing
7027 destWindow = GetNSWindowPtr(ourPluginWnd);
7028 } else {
7029 destWindow = GetNSWindowPtr(destWnd);
7032 if (destWindow == this && mWindowType == eWindowType_plugin) {
7033 // If this is plug-in window, the message came from the plug-in window.
7034 // Then, the message should be processed on the parent window.
7035 destWindow = static_cast<nsWindow*>(GetParent());
7036 NS_ENSURE_TRUE(destWindow, PR_FALSE); // break, but continue processing
7037 destWnd = destWindow->mWnd;
7038 NS_ENSURE_TRUE(destWnd, PR_FALSE); // break, but continue processing
7041 if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
7042 // Some other app, or a plugin window.
7043 // Windows directs scrolling messages to the focused window.
7044 // However, Mozilla does not like plugins having focus, so a
7045 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7046 // Therefore, plugins etc _should_ get first grab at the
7047 // message, but this focus vaguary means the plugin misses
7048 // out. If the window is a child of ours, forward it on.
7049 // Determine if a child by walking the parent list until
7050 // we find a parent matching our wndproc.
7051 HWND parentWnd = ::GetParent(destWnd);
7052 while (parentWnd) {
7053 nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
7054 if (parentWindow) {
7055 // We have a child window - quite possibly a plugin window.
7056 // However, not all plugins are created equal - some will handle this
7057 // message themselves, some will forward directly back to us, while
7058 // others will call DefWndProc, which itself still forwards back to us.
7059 // So if we have sent it once, we need to handle it ourself.
7061 #ifdef MOZ_IPC
7062 // XXX The message shouldn't come from the plugin window at here.
7063 // But the message might come from it due to some bugs. If it happens,
7064 // SendMessage causes deadlock. For safety, we should unlock the
7065 // sender here.
7066 ::ReplyMessage(aMsg == WM_MOUSEHWHEEL ? TRUE : 0);
7067 #endif
7069 // First time we have seen this message.
7070 // Call the child - either it will consume it, or
7071 // it will wind it's way back to us,triggering the destWnd case above
7072 // either way,when the call returns,we are all done with the message,
7073 sIsProcessing = PR_TRUE;
7074 ::SendMessageW(destWnd, aMsg, aWParam, aLParam);
7075 sIsProcessing = PR_FALSE;
7076 aHandled = PR_TRUE;
7077 aQuitProcessing = PR_TRUE;
7078 return PR_FALSE; // break, and stop processing
7080 parentWnd = ::GetParent(parentWnd);
7081 } // while parentWnd
7083 if (destWnd == nsnull)
7084 return PR_FALSE;
7085 if (destWnd != mWnd) {
7086 if (destWindow) {
7087 sIsProcessing = PR_TRUE;
7088 aHandled = destWindow->ProcessMessage(aMsg, aWParam, aLParam, aRetValue);
7089 sIsProcessing = PR_FALSE;
7090 aQuitProcessing = PR_TRUE;
7091 return PR_FALSE; // break, and stop processing
7093 #ifdef DEBUG
7094 else
7095 printf("WARNING: couldn't get child window for SCROLL event\n");
7096 #endif
7098 return PR_TRUE; // caller should handle this
7101 PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
7103 static PRInt8 sMouseWheelEmulation = -1;
7104 if (sMouseWheelEmulation < 0) {
7105 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7106 NS_ENSURE_TRUE(prefs, PR_FALSE);
7107 nsCOMPtr<nsIPrefBranch> prefBranch;
7108 prefs->GetBranch(0, getter_AddRefs(prefBranch));
7109 NS_ENSURE_TRUE(prefBranch, PR_FALSE);
7110 PRBool emulate;
7111 nsresult rv =
7112 prefBranch->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate);
7113 NS_ENSURE_SUCCESS(rv, PR_FALSE);
7114 sMouseWheelEmulation = PRInt8(emulate);
7117 if (aLParam || sMouseWheelEmulation) {
7118 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7119 // Treat as a mousewheel message and scroll appropriately
7120 PRBool quit, result;
7121 LRESULT retVal;
7123 if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result, &retVal, quit))
7124 return quit; // Return if it's not our message or has been dispatched
7126 nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
7127 scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
7128 ? nsMouseScrollEvent::kIsVertical
7129 : nsMouseScrollEvent::kIsHorizontal;
7130 switch (LOWORD(aWParam))
7132 case SB_PAGEDOWN:
7133 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7134 case SB_LINEDOWN:
7135 scrollevent.delta = 1;
7136 break;
7137 case SB_PAGEUP:
7138 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7139 case SB_LINEUP:
7140 scrollevent.delta = -1;
7141 break;
7142 default:
7143 return PR_FALSE;
7145 #ifdef MOZ_IPC
7146 // The event may go to a plug-in which already dispatched this message.
7147 // Then, the event can cause deadlock. We should unlock the sender here.
7148 ::ReplyMessage(0);
7149 #endif
7150 scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
7151 scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
7152 scrollevent.isMeta = PR_FALSE;
7153 scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
7154 InitEvent(scrollevent);
7155 if (nsnull != mEventCallback)
7157 DispatchWindowEvent(&scrollevent);
7159 return PR_TRUE;
7162 // Scroll message generated by external application
7163 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_SCROLL, this);
7165 command.mScroll.mIsHorizontal = (aMsg == WM_HSCROLL);
7167 switch (LOWORD(aWParam))
7169 case SB_LINEUP: // SB_LINELEFT
7170 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7171 command.mScroll.mAmount = -1;
7172 break;
7173 case SB_LINEDOWN: // SB_LINERIGHT
7174 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7175 command.mScroll.mAmount = 1;
7176 break;
7177 case SB_PAGEUP: // SB_PAGELEFT
7178 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7179 command.mScroll.mAmount = -1;
7180 break;
7181 case SB_PAGEDOWN: // SB_PAGERIGHT
7182 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7183 command.mScroll.mAmount = 1;
7184 break;
7185 case SB_TOP: // SB_LEFT
7186 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7187 command.mScroll.mAmount = -1;
7188 break;
7189 case SB_BOTTOM: // SB_RIGHT
7190 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7191 command.mScroll.mAmount = 1;
7192 break;
7193 default:
7194 return PR_FALSE;
7196 DispatchWindowEvent(&command);
7197 return PR_TRUE;
7200 // Can be overriden. Controls auto-erase of background.
7201 PRBool nsWindow::AutoErase(HDC dc)
7203 return PR_FALSE;
7206 /**************************************************************
7207 **************************************************************
7209 ** BLOCK: IME management and accessibility
7211 ** Handles managing IME input and accessibility.
7213 **************************************************************
7214 **************************************************************/
7216 NS_IMETHODIMP nsWindow::ResetInputState()
7218 #ifdef DEBUG_KBSTATE
7219 printf("ResetInputState\n");
7220 #endif
7222 #ifdef NS_ENABLE_TSF
7223 nsTextStore::CommitComposition(PR_FALSE);
7224 #endif //NS_ENABLE_TSF
7226 nsIMEContext IMEContext(mWnd);
7227 if (IMEContext.IsValid()) {
7228 ::ImmNotifyIME(IMEContext.get(), NI_COMPOSITIONSTR, CPS_COMPLETE, NULL);
7229 ::ImmNotifyIME(IMEContext.get(), NI_COMPOSITIONSTR, CPS_CANCEL, NULL);
7231 return NS_OK;
7234 NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState)
7236 #ifdef DEBUG_KBSTATE
7237 printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
7238 #endif
7240 #ifdef NS_ENABLE_TSF
7241 nsTextStore::SetIMEOpenState(aState);
7242 #endif //NS_ENABLE_TSF
7244 nsIMEContext IMEContext(mWnd);
7245 if (IMEContext.IsValid()) {
7246 ::ImmSetOpenStatus(IMEContext.get(), aState ? TRUE : FALSE);
7248 return NS_OK;
7251 NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState)
7253 nsIMEContext IMEContext(mWnd);
7254 if (IMEContext.IsValid()) {
7255 BOOL isOpen = ::ImmGetOpenStatus(IMEContext.get());
7256 *aState = isOpen ? PR_TRUE : PR_FALSE;
7257 } else
7258 *aState = PR_FALSE;
7260 #ifdef NS_ENABLE_TSF
7261 *aState |= nsTextStore::GetIMEOpenState();
7262 #endif //NS_ENABLE_TSF
7264 return NS_OK;
7267 NS_IMETHODIMP nsWindow::SetIMEEnabled(PRUint32 aState)
7269 #ifdef NS_ENABLE_TSF
7270 nsTextStore::SetIMEEnabled(aState);
7271 #endif //NS_ENABLE_TSF
7272 #ifdef DEBUG_KBSTATE
7273 printf("SetIMEEnabled: %s\n", (aState == nsIWidget::IME_STATUS_ENABLED ||
7274 aState == nsIWidget::IME_STATUS_PLUGIN)?
7275 "Enabled": "Disabled");
7276 #endif
7277 if (nsIMM32Handler::IsComposing(this))
7278 ResetInputState();
7279 mIMEEnabled = aState;
7280 PRBool enable = (aState == nsIWidget::IME_STATUS_ENABLED ||
7281 aState == nsIWidget::IME_STATUS_PLUGIN);
7283 #if defined(WINCE_HAVE_SOFTKB)
7284 sSoftKeyboardState = (aState != nsIWidget::IME_STATUS_DISABLED);
7285 nsWindowCE::ToggleSoftKB(mWnd, sSoftKeyboardState);
7286 #endif
7288 if (!enable != !mOldIMC)
7289 return NS_OK;
7290 mOldIMC = ::ImmAssociateContext(mWnd, enable ? mOldIMC : NULL);
7291 NS_ASSERTION(!enable || !mOldIMC, "Another IMC was associated");
7293 return NS_OK;
7296 NS_IMETHODIMP nsWindow::GetIMEEnabled(PRUint32* aState)
7298 #ifdef DEBUG_KBSTATE
7299 printf("GetIMEEnabled: %s\n", mIMEEnabled? "Enabled": "Disabled");
7300 #endif
7301 *aState = mIMEEnabled;
7302 return NS_OK;
7305 NS_IMETHODIMP nsWindow::CancelIMEComposition()
7307 #ifdef DEBUG_KBSTATE
7308 printf("CancelIMEComposition\n");
7309 #endif
7311 #ifdef NS_ENABLE_TSF
7312 nsTextStore::CommitComposition(PR_TRUE);
7313 #endif //NS_ENABLE_TSF
7315 nsIMEContext IMEContext(mWnd);
7316 if (IMEContext.IsValid()) {
7317 ::ImmNotifyIME(IMEContext.get(), NI_COMPOSITIONSTR, CPS_CANCEL, NULL);
7319 return NS_OK;
7322 NS_IMETHODIMP
7323 nsWindow::GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState)
7325 #ifdef DEBUG_KBSTATE
7326 printf("GetToggledKeyState\n");
7327 #endif
7328 NS_ENSURE_ARG_POINTER(aLEDState);
7329 *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
7330 return NS_OK;
7333 #ifdef NS_ENABLE_TSF
7334 NS_IMETHODIMP
7335 nsWindow::OnIMEFocusChange(PRBool aFocus)
7337 nsresult rv = nsTextStore::OnFocusChange(aFocus, this, mIMEEnabled);
7338 if (rv == NS_ERROR_NOT_AVAILABLE)
7339 rv = NS_ERROR_NOT_IMPLEMENTED; // TSF is not enabled, maybe.
7340 return rv;
7343 NS_IMETHODIMP
7344 nsWindow::OnIMETextChange(PRUint32 aStart,
7345 PRUint32 aOldEnd,
7346 PRUint32 aNewEnd)
7348 return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
7351 NS_IMETHODIMP
7352 nsWindow::OnIMESelectionChange(void)
7354 return nsTextStore::OnSelectionChange();
7356 #endif //NS_ENABLE_TSF
7358 #ifdef ACCESSIBILITY
7360 #ifdef DEBUG_WMGETOBJECT
7361 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
7362 nsAccessible* acc = aWnd ? \
7363 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
7364 printf(" acc: %p", acc); \
7365 if (acc) { \
7366 nsAutoString name; \
7367 acc->GetName(name); \
7368 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
7369 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
7370 void *hwnd = nsnull; \
7371 doc->GetWindowHandle(&hwnd); \
7372 printf(", acc hwnd: %d", hwnd); \
7375 #define NS_LOG_WMGETOBJECT_THISWND \
7377 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
7378 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p, content type: %d,\n",\
7379 mWnd, ::GetParent(mWnd), this, mContentType); \
7380 NS_LOG_WMGETOBJECT_WNDACC(this) \
7381 printf("\n }\n"); \
7384 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
7386 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
7387 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7388 aHwnd, ::GetParent(aHwnd), wnd); \
7389 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
7390 printf("\n }\n"); \
7392 #else
7393 #define NS_LOG_WMGETOBJECT_THISWND
7394 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
7395 #endif // DEBUG_WMGETOBJECT
7397 nsAccessible*
7398 nsWindow::GetRootAccessible()
7400 // We want the ability to forcibly disable a11y on windows, because
7401 // some non-a11y-related components attempt to bring it up. See bug
7402 // 538530 for details; we have a pref here that allows it to be disabled
7403 // for performance and testing resons.
7405 // This pref is checked only once, and the browser needs a restart to
7406 // pick up any changes.
7407 static int accForceDisable = -1;
7409 if (accForceDisable == -1) {
7410 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7411 PRBool b = PR_FALSE;
7412 nsresult rv = prefs->GetBoolPref("accessibility.win32.force_disabled", &b);
7413 if (NS_SUCCEEDED(rv) && b) {
7414 accForceDisable = 1;
7415 } else {
7416 accForceDisable = 0;
7420 // If the pref was true, return null here, disabling a11y.
7421 if (accForceDisable)
7422 return nsnull;
7424 nsWindow::sIsAccessibilityOn = TRUE;
7426 if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) {
7427 return nsnull;
7430 NS_LOG_WMGETOBJECT_THISWND
7432 if (mContentType != eContentTypeInherit) {
7433 // We're on a MozillaContentWindowClass or MozillaUIWindowClass window.
7434 // Search for the correct visible child window to get an accessible
7435 // document from. Make sure to use an active child window. If this window
7436 // doesn't have child windows then return an accessible for it.
7437 HWND accessibleWnd = ::GetTopWindow(mWnd);
7438 NS_LOG_WMGETOBJECT_WND("Top Window", accessibleWnd);
7439 if (!accessibleWnd) {
7440 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
7441 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
7444 nsWindow* accessibleWindow = nsnull;
7445 while (accessibleWnd) {
7446 // Loop through windows and find the first one with accessibility info
7447 accessibleWindow = GetNSWindowPtr(accessibleWnd);
7448 if (accessibleWindow) {
7449 nsAccessible *rootAccessible =
7450 accessibleWindow->DispatchAccessibleEvent(NS_GETACCESSIBLE);
7451 if (rootAccessible) {
7452 // Success, one of the child windows was active.
7453 return rootAccessible;
7456 accessibleWnd = ::GetNextWindow(accessibleWnd, GW_HWNDNEXT);
7457 NS_LOG_WMGETOBJECT_WND("Next Window", accessibleWnd);
7459 return nsnull;
7462 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
7463 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
7466 STDMETHODIMP_(LRESULT)
7467 nsWindow::LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc)
7469 // open the dll dynamically
7470 if (!sAccLib)
7471 sAccLib =::LoadLibraryW(L"OLEACC.DLL");
7473 if (sAccLib) {
7474 if (!sLresultFromObject)
7475 sLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(sAccLib,"LresultFromObject");
7477 if (sLresultFromObject)
7478 return sLresultFromObject(riid,wParam,pAcc);
7481 return 0;
7483 #endif
7485 /**************************************************************
7486 **************************************************************
7488 ** BLOCK: Transparency
7490 ** Window transparency helpers.
7492 **************************************************************
7493 **************************************************************/
7495 #ifdef MOZ_XUL
7497 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force)
7499 if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
7500 return;
7502 #ifdef CAIRO_HAS_D2D_SURFACE
7503 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7504 gfxWindowsPlatform::RENDER_DIRECT2D) {
7505 nsRefPtr<gfxD2DSurface> newSurface =
7506 new gfxD2DSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7507 mTransparentSurface = newSurface;
7508 mMemoryDC = nsnull;
7509 } else
7510 #endif
7512 nsRefPtr<gfxWindowsSurface> newSurface =
7513 new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7514 mTransparentSurface = newSurface;
7515 mMemoryDC = newSurface->GetDC();
7519 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
7521 #ifndef WINCE
7523 if (aMode == mTransparencyMode)
7524 return;
7526 // stop on dialogs and popups!
7527 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7528 nsWindow* parent = GetNSWindowPtr(hWnd);
7530 if (!parent)
7532 NS_WARNING("Trying to use transparent chrome in an embedded context");
7533 return;
7536 if (parent != this) {
7537 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
7540 if (aMode == eTransparencyTransparent) {
7541 // If we're switching to the use of a transparent window, hide the chrome
7542 // on our parent.
7543 HideWindowChrome(PR_TRUE);
7544 } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) {
7545 // if we're switching out of transparent, re-enable our parent's chrome.
7546 HideWindowChrome(PR_FALSE);
7549 LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE),
7550 exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
7552 if (parent->mIsVisible)
7553 style |= WS_VISIBLE;
7554 if (parent->mSizeMode == nsSizeMode_Maximized)
7555 style |= WS_MAXIMIZE;
7556 else if (parent->mSizeMode == nsSizeMode_Minimized)
7557 style |= WS_MINIMIZE;
7559 if (aMode == eTransparencyTransparent)
7560 exStyle |= WS_EX_LAYERED;
7561 else
7562 exStyle &= ~WS_EX_LAYERED;
7564 VERIFY_WINDOW_STYLE(style);
7565 ::SetWindowLongPtrW(hWnd, GWL_STYLE, style);
7566 ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle);
7568 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7569 if (mTransparencyMode == eTransparencyGlass)
7570 memset(&mGlassMargins, 0, sizeof mGlassMargins);
7571 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7572 mTransparencyMode = aMode;
7574 SetupTranslucentWindowMemoryBitmap(aMode);
7575 UpdateGlass();
7576 #endif // #ifndef WINCE
7579 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
7581 if (eTransparencyTransparent == aMode) {
7582 ResizeTranslucentWindow(mBounds.width, mBounds.height, PR_TRUE);
7583 } else {
7584 mTransparentSurface = nsnull;
7585 mMemoryDC = NULL;
7589 nsresult nsWindow::UpdateTranslucentWindow()
7591 #ifndef WINCE
7592 if (mBounds.IsEmpty())
7593 return NS_OK;
7595 ::GdiFlush();
7597 BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
7598 SIZE winSize = { mBounds.width, mBounds.height };
7599 POINT srcPos = { 0, 0 };
7600 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7601 RECT winRect;
7602 ::GetWindowRect(hWnd, &winRect);
7604 #ifdef CAIRO_HAS_D2D_SURFACE
7605 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7606 gfxWindowsPlatform::RENDER_DIRECT2D) {
7607 mMemoryDC = static_cast<gfxD2DSurface*>(mTransparentSurface.get())->
7608 GetDC(PR_TRUE);
7610 #endif
7611 // perform the alpha blend
7612 PRBool updateSuccesful =
7613 ::UpdateLayeredWindow(hWnd, NULL, (POINT*)&winRect, &winSize, mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA);
7615 #ifdef CAIRO_HAS_D2D_SURFACE
7616 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7617 gfxWindowsPlatform::RENDER_DIRECT2D) {
7618 nsIntRect r(0, 0, 0, 0);
7619 static_cast<gfxD2DSurface*>(mTransparentSurface.get())->ReleaseDC(&r);
7621 #endif
7623 if (!updateSuccesful) {
7624 return NS_ERROR_FAILURE;
7626 #endif
7628 return NS_OK;
7631 #endif //MOZ_XUL
7633 /**************************************************************
7634 **************************************************************
7636 ** BLOCK: Popup rollup hooks
7638 ** Deals with CaptureRollup on popup windows.
7640 **************************************************************
7641 **************************************************************/
7643 #ifndef WINCE
7644 // Schedules a timer for a window, so we can rollup after processing the hook event
7645 void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId)
7647 // In some cases multiple hooks may be scheduled
7648 // so ignore any other requests once one timer is scheduled
7649 if (sHookTimerId == 0) {
7650 // Remember the window handle and the message ID to be used later
7651 sRollupMsgId = aMsgId;
7652 sRollupMsgWnd = aWnd;
7653 // Schedule native timer for doing the rollup after
7654 // this event is done being processed
7655 sHookTimerId = ::SetTimer(NULL, 0, 0, (TIMERPROC)HookTimerForPopups);
7656 NS_ASSERTION(sHookTimerId, "Timer couldn't be created.");
7660 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7661 int gLastMsgCode = 0;
7662 extern MSGFEventMsgInfo gMSGFEvents[];
7663 #endif
7665 // Process Menu messages, rollup when popup is clicked.
7666 LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam)
7668 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7669 if (sProcessHook) {
7670 MSG* pMsg = (MSG*)lParam;
7672 int inx = 0;
7673 while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != NULL) {
7674 inx++;
7676 if (code != gLastMsgCode) {
7677 if (gMSGFEvents[inx].mId == code) {
7678 #ifdef DEBUG
7679 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code, gMSGFEvents[inx].mStr, pMsg->hwnd);
7680 #endif
7681 } else {
7682 #ifdef DEBUG
7683 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code, gMSGFEvents[inx].mId, pMsg->hwnd);
7684 #endif
7686 gLastMsgCode = code;
7688 PrintEvent(pMsg->message, FALSE, FALSE);
7690 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7692 if (sProcessHook && code == MSGF_MENU) {
7693 MSG* pMsg = (MSG*)lParam;
7694 ScheduleHookTimer( pMsg->hwnd, pMsg->message);
7697 return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
7700 // Process all mouse messages. Roll up when a click is in a native window
7701 // that doesn't have an nsIWidget.
7702 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
7704 if (sProcessHook) {
7705 switch (wParam) {
7706 case WM_LBUTTONDOWN:
7707 case WM_RBUTTONDOWN:
7708 case WM_MBUTTONDOWN:
7709 case WM_MOUSEWHEEL:
7710 case WM_MOUSEHWHEEL:
7712 MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
7713 nsIWidget* mozWin = (nsIWidget*)GetNSWindowPtr(ms->hwnd);
7714 if (mozWin) {
7715 // If this window is windowed plugin window, the mouse events are not
7716 // sent to us.
7717 if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin)
7718 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7719 } else {
7720 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7722 break;
7726 return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam);
7729 // Process all messages. Roll up when the window is moving, or
7730 // is resizing or when maximized or mininized.
7731 LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam)
7733 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7734 if (sProcessHook) {
7735 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7736 PrintEvent(cwpt->message, FALSE, FALSE);
7738 #endif
7740 if (sProcessHook) {
7741 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7742 if (cwpt->message == WM_MOVING ||
7743 cwpt->message == WM_SIZING ||
7744 cwpt->message == WM_GETMINMAXINFO) {
7745 ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message);
7749 return ::CallNextHookEx(sCallProcHook, code, wParam, lParam);
7752 // Register the special "hooks" for dropdown processing.
7753 void nsWindow::RegisterSpecialDropdownHooks()
7755 NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!");
7756 NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!");
7758 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
7760 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
7762 // Install msg hook for moving the window and resizing
7763 if (!sMsgFilterHook) {
7764 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
7765 sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, NULL, GetCurrentThreadId());
7766 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7767 if (!sMsgFilterHook) {
7768 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
7770 #endif
7773 // Install msg hook for menus
7774 if (!sCallProcHook) {
7775 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
7776 sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, NULL, GetCurrentThreadId());
7777 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7778 if (!sCallProcHook) {
7779 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
7781 #endif
7784 // Install msg hook for the mouse
7785 if (!sCallMouseHook) {
7786 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
7787 sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, NULL, GetCurrentThreadId());
7788 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7789 if (!sCallMouseHook) {
7790 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
7792 #endif
7796 // Unhook special message hooks for dropdowns.
7797 void nsWindow::UnregisterSpecialDropdownHooks()
7799 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
7801 if (sCallProcHook) {
7802 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
7803 if (!::UnhookWindowsHookEx(sCallProcHook)) {
7804 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
7806 sCallProcHook = NULL;
7809 if (sMsgFilterHook) {
7810 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
7811 if (!::UnhookWindowsHookEx(sMsgFilterHook)) {
7812 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
7814 sMsgFilterHook = NULL;
7817 if (sCallMouseHook) {
7818 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
7819 if (!::UnhookWindowsHookEx(sCallMouseHook)) {
7820 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
7822 sCallMouseHook = NULL;
7826 // This timer is designed to only fire one time at most each time a "hook" function
7827 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
7828 // hook, but that hook event or a subsequent event may roll up the dropdown before
7829 // this timer function is executed.
7831 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
7832 // before this function fires.
7833 VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
7835 if (sHookTimerId != 0) {
7836 // if the window is NULL then we need to use the ID to kill the timer
7837 BOOL status = ::KillTimer(NULL, sHookTimerId);
7838 NS_ASSERTION(status, "Hook Timer was not killed.");
7839 sHookTimerId = 0;
7842 if (sRollupMsgId != 0) {
7843 // Note: DealWithPopups does the check to make sure that
7844 // sRollupListener and sRollupWidget are not NULL
7845 LRESULT popupHandlingResult;
7846 nsAutoRollup autoRollup;
7847 DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
7848 sRollupMsgId = 0;
7849 sRollupMsgWnd = NULL;
7852 #endif // WinCE
7854 static PRBool IsDifferentThreadWindow(HWND aWnd)
7856 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, NULL);
7859 PRBool
7860 nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
7862 RECT r;
7864 #ifndef WINCE
7865 if (Msg == WM_ACTIVATEAPP)
7866 // don't care about activation/deactivation
7867 return PR_FALSE;
7868 #else
7869 if (Msg == WM_ACTIVATE)
7870 // but on Windows CE we do care about
7871 // activation/deactivation because there doesn't exist
7872 // cancelable Mouse Activation events
7873 return PR_TRUE;
7874 #endif
7876 ::GetWindowRect(aWindow->mWnd, &r);
7877 DWORD pos = ::GetMessagePos();
7878 POINT mp;
7879 mp.x = GET_X_LPARAM(pos);
7880 mp.y = GET_Y_LPARAM(pos);
7882 // was the event inside this window?
7883 return (PRBool) PtInRect(&r, mp);
7886 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
7887 BOOL
7888 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
7890 if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
7892 if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
7893 inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
7894 (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam))
7895 #ifndef WINCE
7897 inMsg == WM_NCRBUTTONDOWN ||
7898 inMsg == WM_MOVING ||
7899 inMsg == WM_SIZING ||
7900 inMsg == WM_NCLBUTTONDOWN ||
7901 inMsg == WM_NCMBUTTONDOWN ||
7902 inMsg == WM_MOUSEACTIVATE ||
7903 inMsg == WM_ACTIVATEAPP ||
7904 inMsg == WM_MENUSELECT
7905 #endif
7908 // Rollup if the event is outside the popup.
7909 PRBool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)sRollupWidget);
7911 if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL))
7913 sRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
7914 *outResult = PR_TRUE;
7917 // If we're dealing with menus, we probably have submenus and we don't
7918 // want to rollup if the click is in a parent menu of the current submenu.
7919 PRUint32 popupsToRollup = PR_UINT32_MAX;
7920 if (rollup) {
7921 if ( sMenuRollup ) {
7922 nsAutoTArray<nsIWidget*, 5> widgetChain;
7923 PRUint32 sameTypeCount = sMenuRollup->GetSubmenuWidgetChain(&widgetChain);
7924 for ( PRUint32 i = 0; i < widgetChain.Length(); ++i ) {
7925 nsIWidget* widget = widgetChain[i];
7926 if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
7927 // don't roll up if the mouse event occurred within a menu of the
7928 // same type. If the mouse event occurred in a menu higher than
7929 // that, roll up, but pass the number of popups to Rollup so
7930 // that only those of the same type close up.
7931 if (i < sameTypeCount) {
7932 rollup = PR_FALSE;
7934 else {
7935 popupsToRollup = sameTypeCount;
7937 break;
7939 } // foreach parent menu widget
7940 } // if rollup listener knows about menus
7943 #ifndef WINCE
7944 if (inMsg == WM_MOUSEACTIVATE && popupsToRollup == PR_UINT32_MAX) {
7945 // Prevent the click inside the popup from causing a change in window
7946 // activation. Since the popup is shown non-activated, we need to eat
7947 // any requests to activate the window while it is displayed. Windows
7948 // will automatically activate the popup on the mousedown otherwise.
7949 if (!rollup) {
7950 *outResult = MA_NOACTIVATE;
7951 return TRUE;
7953 else
7955 UINT uMsg = HIWORD(inLParam);
7956 if (uMsg == WM_MOUSEMOVE)
7958 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
7959 // must be enabled in Windows.
7960 sRollupListener->ShouldRollupOnMouseActivate(&rollup);
7961 if (!rollup)
7963 *outResult = MA_NOACTIVATE;
7964 return true;
7969 // if we've still determined that we should still rollup everything, do it.
7970 else
7971 #endif
7972 if ( rollup ) {
7973 // sRollupConsumeEvent may be modified by
7974 // nsIRollupListener::Rollup.
7975 PRBool consumeRollupEvent = sRollupConsumeEvent;
7976 // only need to deal with the last rollup for left mouse down events.
7977 sRollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN ? &mLastRollup : nsnull);
7979 // Tell hook to stop processing messages
7980 sProcessHook = PR_FALSE;
7981 sRollupMsgId = 0;
7982 sRollupMsgWnd = NULL;
7984 // return TRUE tells Windows that the event is consumed,
7985 // false allows the event to be dispatched
7987 // So if we are NOT supposed to be consuming events, let it go through
7988 if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
7989 *outResult = TRUE;
7990 return TRUE;
7992 #ifndef WINCE
7993 // if we are only rolling up some popups, don't activate and don't let
7994 // the event go through. This prevents clicks menus higher in the
7995 // chain from opening when a context menu is open
7996 if (popupsToRollup != PR_UINT32_MAX && inMsg == WM_MOUSEACTIVATE) {
7997 *outResult = MA_NOACTIVATEANDEAT;
7998 return TRUE;
8000 #endif
8002 } // if event that might trigger a popup to rollup
8003 } // if rollup listeners registered
8005 return FALSE;
8008 /**************************************************************
8009 **************************************************************
8011 ** BLOCK: Misc. utility methods and functions.
8013 ** General use.
8015 **************************************************************
8016 **************************************************************/
8018 // nsModifierKeyState used in various character processing.
8019 nsModifierKeyState::nsModifierKeyState()
8021 mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT);
8022 mIsControlDown = IS_VK_DOWN(NS_VK_CONTROL);
8023 mIsAltDown = IS_VK_DOWN(NS_VK_ALT);
8027 PRInt32 nsWindow::GetWindowsVersion()
8029 #ifdef WINCE
8030 return 0x500;
8031 #else
8032 static PRInt32 version = 0;
8033 static PRBool didCheck = PR_FALSE;
8035 if (!didCheck)
8037 didCheck = PR_TRUE;
8038 OSVERSIONINFOEX osInfo;
8039 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
8040 // This cast is safe and supposed to be here, don't worry
8041 ::GetVersionEx((OSVERSIONINFO*)&osInfo);
8042 version = (osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
8044 return version;
8045 #endif
8048 // Note that the result of GetTopLevelWindow method can be different from the
8049 // result of GetTopLevelHWND method. The result can be non-floating window.
8050 // Because our top level window may be contained in another window which is
8051 // not managed by us.
8052 nsWindow* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup)
8054 nsWindow* curWindow = this;
8056 while (PR_TRUE) {
8057 if (aStopOnDialogOrPopup) {
8058 switch (curWindow->mWindowType) {
8059 case eWindowType_dialog:
8060 case eWindowType_popup:
8061 return curWindow;
8065 // Retrieve the top level parent or owner window
8066 nsWindow* parentWindow = curWindow->GetParentWindow(PR_TRUE);
8068 if (!parentWindow)
8069 return curWindow;
8071 curWindow = parentWindow;
8075 // Note that the result of GetTopLevelHWND can be different from the result
8076 // of GetTopLevelWindow method. Because this is checking whether the window
8077 // is top level only in Win32 window system. Therefore, the result window
8078 // may not be managed by us.
8079 HWND nsWindow::GetTopLevelHWND(HWND aWnd, PRBool aStopOnDialogOrPopup)
8081 HWND curWnd = aWnd;
8082 HWND topWnd = NULL;
8083 HWND upWnd = NULL;
8085 while (curWnd) {
8086 topWnd = curWnd;
8088 if (aStopOnDialogOrPopup) {
8089 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8091 VERIFY_WINDOW_STYLE(style);
8093 if (!(style & WS_CHILD)) // first top-level window
8094 break;
8097 upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
8099 #ifdef WINCE
8100 // For dialog windows, we want just the parent, not the owner.
8101 // For other/popup windows, we want to find the first owner/parent
8102 // that's a dialog and/or has an owner.
8103 if (upWnd && ::GetWindow(curWnd, GW_OWNER) == upWnd) {
8104 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8105 if ((style & WS_DLGFRAME) != 0)
8106 break;
8108 #endif
8110 curWnd = upWnd;
8113 return topWnd;
8116 static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam)
8118 DWORD pid;
8119 ::GetWindowThreadProcessId(hwnd, &pid);
8120 if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd))
8122 gWindowsVisible = PR_TRUE;
8123 return FALSE;
8125 return TRUE;
8128 PRBool nsWindow::CanTakeFocus()
8130 gWindowsVisible = PR_FALSE;
8131 EnumWindows(gEnumWindowsProc, 0);
8132 if (!gWindowsVisible) {
8133 return PR_TRUE;
8134 } else {
8135 HWND fgWnd = ::GetForegroundWindow();
8136 if (!fgWnd) {
8137 return PR_TRUE;
8139 DWORD pid;
8140 GetWindowThreadProcessId(fgWnd, &pid);
8141 if (pid == GetCurrentProcessId()) {
8142 return PR_TRUE;
8145 return PR_FALSE;
8148 #if !defined(WINCE)
8149 void nsWindow::InitTrackPointHack()
8151 // Init Trackpoint Hack
8152 nsresult rv;
8153 PRInt32 lHackValue;
8154 long lResult;
8155 const WCHAR wstrKeys[][40] = {L"Software\\Lenovo\\TrackPoint",
8156 L"Software\\Lenovo\\UltraNav",
8157 L"Software\\Alps\\Apoint\\TrackPoint",
8158 L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
8159 L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
8160 // If anything fails turn the hack off
8161 sTrackPointHack = false;
8162 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8163 if(NS_SUCCEEDED(rv) && prefs) {
8164 prefs->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue);
8165 switch (lHackValue) {
8166 // 0 means hack disabled
8167 case 0:
8168 break;
8169 // 1 means hack enabled
8170 case 1:
8171 sTrackPointHack = true;
8172 break;
8173 // -1 means autodetect
8174 case -1:
8175 for(int i = 0; i < NS_ARRAY_LENGTH(wstrKeys); i++) {
8176 HKEY hKey;
8177 lResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, (LPCWSTR)&wstrKeys[i],
8178 0, KEY_READ, &hKey);
8179 ::RegCloseKey(hKey);
8180 if(lResult == ERROR_SUCCESS) {
8181 // If we detected a registry key belonging to a TrackPoint driver
8182 // Turn on the hack
8183 sTrackPointHack = true;
8184 break;
8187 break;
8188 // Shouldn't be any other values, but treat them as disabled
8189 default:
8190 break;
8193 return;
8195 #endif // #if !defined(WINCE)
8197 LPARAM nsWindow::lParamToScreen(LPARAM lParam)
8199 POINT pt;
8200 pt.x = GET_X_LPARAM(lParam);
8201 pt.y = GET_Y_LPARAM(lParam);
8202 ::ClientToScreen(mWnd, &pt);
8203 return MAKELPARAM(pt.x, pt.y);
8206 LPARAM nsWindow::lParamToClient(LPARAM lParam)
8208 POINT pt;
8209 pt.x = GET_X_LPARAM(lParam);
8210 pt.y = GET_Y_LPARAM(lParam);
8211 ::ScreenToClient(mWnd, &pt);
8212 return MAKELPARAM(pt.x, pt.y);
8215 /**************************************************************
8216 **************************************************************
8218 ** BLOCK: ChildWindow impl.
8220 ** Child window overrides.
8222 **************************************************************
8223 **************************************************************/
8225 // return the style for a child nsWindow
8226 DWORD ChildWindow::WindowStyle()
8228 DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle();
8229 if (!(style & WS_POPUP))
8230 style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
8231 VERIFY_WINDOW_STYLE(style);
8232 return style;