Bug 574454 - Theme code for caption button box, content padding. r=vlad.
[mozilla-central.git] / widget / src / windows / nsWindow.cpp
blobd98db26b40b269d6cf85a7876ffad5c8906ee908
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sts=2 sw=2 et cin: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Dean Tessman <dean_tessman@hotmail.com>
25 * Ere Maijala <emaijala@kolumbus.fi>
26 * Mark Hammond <markh@activestate.com>
27 * Michael Lowe <michael.lowe@bigfoot.com>
28 * Peter Bajusz <hyp-x@inf.bme.hu>
29 * Pierre Phaneuf <pp@ludusdesign.com>
30 * Robert O'Callahan <roc+moz@cs.cmu.edu>
31 * Roy Yokoyama <yokoyama@netscape.com>
32 * Makoto Kato <m_kato@ga2.so-net.ne.jp>
33 * Masayuki Nakano <masayuki@d-toybox.com>
34 * Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
35 * Christian Biesinger <cbiesinger@web.de>
36 * Mats Palmgren <matspal@gmail.com>
37 * Ningjie Chen <chenn@email.uc.edu>
38 * Jim Mathies <jmathies@mozilla.com>
39 * Kyle Huey <me@kylehuey.com>
41 * Alternatively, the contents of this file may be used under the terms of
42 * either the GNU General Public License Version 2 or later (the "GPL"), or
43 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
44 * in which case the provisions of the GPL or the LGPL are applicable instead
45 * of those above. If you wish to allow use of your version of this file only
46 * under the terms of either the GPL or the LGPL, and not to allow others to
47 * use your version of this file under the terms of the MPL, indicate your
48 * decision by deleting the provisions above and replace them with the notice
49 * and other provisions required by the GPL or the LGPL. If you do not delete
50 * the provisions above, a recipient may use your version of this file under
51 * the terms of any one of the MPL, the GPL or the LGPL.
53 * ***** END LICENSE BLOCK ***** */
56 * nsWindow - Native window management and event handling.
58 * nsWindow is organized into a set of major blocks and
59 * block subsections. The layout is as follows:
61 * Includes
62 * Variables
63 * nsIWidget impl.
64 * nsIWidget methods and utilities
65 * nsSwitchToUIThread impl.
66 * nsSwitchToUIThread methods and utilities
67 * Moz events
68 * Event initialization
69 * Event dispatching
70 * Native events
71 * Wndproc(s)
72 * Event processing
73 * OnEvent event handlers
74 * IME management and accessibility
75 * Transparency
76 * Popup hook handling
77 * Misc. utilities
78 * Child window impl.
80 * Search for "BLOCK:" to find major blocks.
81 * Search for "SECTION:" to find specific sections.
83 * Blocks should be split out into separate files if they
84 * become unmanageable.
86 * Related source:
88 * nsWindowDefs.h - Definitions, macros, structs, enums
89 * and general setup.
90 * nsWindowDbg.h/.cpp - Debug related code and directives.
91 * nsWindowGfx.h/.cpp - Graphics and painting.
92 * nsWindowCE.h/.cpp - WINCE specific code that can be
93 * split out from nsWindow.
97 /**************************************************************
98 **************************************************************
100 ** BLOCK: Includes
102 ** Include headers.
104 **************************************************************
105 **************************************************************/
107 #ifdef MOZ_IPC
108 #include "mozilla/ipc/RPCChannel.h"
109 #endif
111 #include "nsWindow.h"
113 #include <windows.h>
114 #include <process.h>
115 #include <commctrl.h>
116 #include <unknwn.h>
118 #include "prlog.h"
119 #include "prtime.h"
120 #include "prprf.h"
121 #include "prmem.h"
123 #include "nsIAppShell.h"
124 #include "nsISupportsPrimitives.h"
125 #include "nsIDOMNSUIEvent.h"
126 #include "nsITheme.h"
127 #include "nsIPrefBranch.h"
128 #include "nsIPrefBranch2.h"
129 #include "nsIPrefService.h"
130 #include "nsIObserverService.h"
131 #include "nsIScreenManager.h"
132 #include "imgIContainer.h"
133 #include "nsIFile.h"
134 #include "nsIRollupListener.h"
135 #include "nsIMenuRollup.h"
136 #include "nsIRegion.h"
137 #include "nsIServiceManager.h"
138 #include "nsIClipboard.h"
139 #include "nsIMM32Handler.h"
140 #include "nsILocalFile.h"
141 #include "nsIFontMetrics.h"
142 #include "nsIFontEnumerator.h"
143 #include "nsIDeviceContext.h"
144 #include "nsILookAndFeel.h"
145 #include "nsGUIEvent.h"
146 #include "nsFont.h"
147 #include "nsRect.h"
148 #include "nsThreadUtils.h"
149 #include "nsNativeCharsetUtils.h"
150 #include "nsWidgetAtoms.h"
151 #include "nsUnicharUtils.h"
152 #include "nsCRT.h"
153 #include "nsAppDirectoryServiceDefs.h"
154 #include "nsXPIDLString.h"
155 #include "nsWidgetsCID.h"
156 #include "nsTHashtable.h"
157 #include "nsHashKeys.h"
158 #include "nsString.h"
159 #include "mozilla/Services.h"
160 #include "nsNativeThemeWin.h"
162 #if defined(WINCE)
163 #include "nsWindowCE.h"
164 #endif
166 #if defined(WINCE_WINDOWS_MOBILE)
167 #define KILL_PRIORITY_ID 2444
168 #endif
170 #include "nsWindowGfx.h"
171 #include "gfxWindowsPlatform.h"
172 #include "Layers.h"
173 #ifndef WINCE
174 #ifdef MOZ_ENABLE_D3D9_LAYER
175 #include "LayerManagerD3D9.h"
176 #endif
177 #include "LayerManagerOGL.h"
178 #endif
180 #if !defined(WINCE)
181 #include "nsUXThemeConstants.h"
182 #include "KeyboardLayout.h"
183 #include "nsNativeDragTarget.h"
184 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
185 #include <zmouse.h>
186 #include <pbt.h>
187 #include <richedit.h>
188 #endif // !defined(WINCE)
190 #if defined(ACCESSIBILITY)
191 #include "oleidl.h"
192 #include <winuser.h>
193 #include "nsIAccessibleDocument.h"
194 #if !defined(WINABLEAPI)
195 #include <winable.h>
196 #endif // !defined(WINABLEAPI)
197 #endif // defined(ACCESSIBILITY)
199 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
200 #include "nsIWinTaskbar.h"
201 #endif
203 #if defined(NS_ENABLE_TSF)
204 #include "nsTextStore.h"
205 #endif // defined(NS_ENABLE_TSF)
207 #if defined(MOZ_SPLASHSCREEN)
208 #include "nsSplashScreen.h"
209 #endif // defined(MOZ_SPLASHSCREEN)
211 // Windowless plugin support
212 #include "npapi.h"
214 #include "nsWindowDefs.h"
216 #include "mozilla/FunctionTimer.h"
218 #ifdef WINCE_WINDOWS_MOBILE
219 #include "nsGfxCIID.h"
220 #endif
222 #include "mozilla/FunctionTimer.h"
224 using namespace mozilla::widget;
226 /**************************************************************
227 **************************************************************
229 ** BLOCK: Variables
231 ** nsWindow Class static initializations and global variables.
233 **************************************************************
234 **************************************************************/
236 /**************************************************************
238 * SECTION: nsWindow statics
240 **************************************************************/
242 PRUint32 nsWindow::sInstanceCount = 0;
243 PRBool nsWindow::sSwitchKeyboardLayout = PR_FALSE;
244 BOOL nsWindow::sIsRegistered = FALSE;
245 BOOL nsWindow::sIsPopupClassRegistered = FALSE;
246 BOOL nsWindow::sIsOleInitialized = FALSE;
247 HCURSOR nsWindow::sHCursor = NULL;
248 imgIContainer* nsWindow::sCursorImgContainer = nsnull;
249 nsWindow* nsWindow::sCurrentWindow = nsnull;
250 PRBool nsWindow::sJustGotDeactivate = PR_FALSE;
251 PRBool nsWindow::sJustGotActivate = PR_FALSE;
253 // imported in nsWidgetFactory.cpp
254 TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN;
256 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
257 // hook methods whether they should be processing the hook
258 // messages.
259 HHOOK nsWindow::sMsgFilterHook = NULL;
260 HHOOK nsWindow::sCallProcHook = NULL;
261 HHOOK nsWindow::sCallMouseHook = NULL;
262 PRPackedBool nsWindow::sProcessHook = PR_FALSE;
263 UINT nsWindow::sRollupMsgId = 0;
264 HWND nsWindow::sRollupMsgWnd = NULL;
265 UINT nsWindow::sHookTimerId = 0;
267 // Rollup Listener
268 nsIRollupListener* nsWindow::sRollupListener = nsnull;
269 nsIMenuRollup* nsWindow::sMenuRollup = nsnull;
270 nsIWidget* nsWindow::sRollupWidget = nsnull;
271 PRBool nsWindow::sRollupConsumeEvent = PR_FALSE;
273 // Mouse Clicks - static variable definitions for figuring
274 // out 1 - 3 Clicks.
275 POINT nsWindow::sLastMousePoint = {0};
276 POINT nsWindow::sLastMouseMovePoint = {0};
277 LONG nsWindow::sLastMouseDownTime = 0L;
278 LONG nsWindow::sLastClickCount = 0L;
279 BYTE nsWindow::sLastMouseButton = 0;
281 // Trim heap on minimize. (initialized, but still true.)
282 int nsWindow::sTrimOnMinimize = 2;
284 // Default Trackpoint Hack to off
285 PRBool nsWindow::sTrackPointHack = PR_FALSE;
287 #ifdef ACCESSIBILITY
288 BOOL nsWindow::sIsAccessibilityOn = FALSE;
289 // Accessibility wm_getobject handler
290 HINSTANCE nsWindow::sAccLib = 0;
291 LPFNLRESULTFROMOBJECT
292 nsWindow::sLresultFromObject = 0;
293 #endif // ACCESSIBILITY
295 #ifdef MOZ_IPC
296 // Used in OOPP plugin focus processing.
297 const PRUnichar* kOOPPPluginFocusEventId = L"OOPP Plugin Focus Widget Event";
298 PRUint32 nsWindow::sOOPPPluginFocusEvent =
299 RegisterWindowMessageW(kOOPPPluginFocusEventId);
300 #endif
302 /**************************************************************
304 * SECTION: globals variables
306 **************************************************************/
308 static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
310 #ifdef PR_LOGGING
311 PRLogModuleInfo* gWindowsLog = nsnull;
312 #endif
314 #ifndef WINCE
315 // Kbd layout. Used throughout character processing.
316 static KeyboardLayout gKbdLayout;
317 #endif
319 #ifdef WINCE_WINDOWS_MOBILE
320 // HTC Navigation Wheel Event
321 // This is the defined value for Gesture Mode
322 const int WM_HTCNAV = 0x0400 + 200;
324 typedef int (__stdcall * HTCApiNavOpen)(HANDLE, int);
325 typedef int (__stdcall * HTCApiNavSetMode)(HANDLE, unsigned int);
327 HTCApiNavOpen gHTCApiNavOpen = nsnull;
328 HTCApiNavSetMode gHTCApiNavSetMode = nsnull;
329 static PRBool gCheckForHTCApi = PR_FALSE;
330 #endif
332 // Global user preference for disabling native theme. Used
333 // in NativeWindowTheme.
334 PRBool gDisableNativeTheme = PR_FALSE;
336 // Global used in Show window enumerations.
337 static PRBool gWindowsVisible = PR_FALSE;
339 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
340 #ifdef WINCE_WINDOWS_MOBILE
341 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
342 #endif
344 /**************************************************************
345 **************************************************************
347 ** BLOCK: nsIWidget impl.
349 ** nsIWidget interface implementation, broken down into
350 ** sections.
352 **************************************************************
353 **************************************************************/
355 /**************************************************************
357 * SECTION: nsWindow construction and destruction
359 **************************************************************/
361 nsWindow::nsWindow() : nsBaseWidget()
363 #ifdef PR_LOGGING
364 if (!gWindowsLog)
365 gWindowsLog = PR_NewLogModule("nsWindowsWidgets");
366 #endif
368 mWnd = nsnull;
369 mPaintDC = nsnull;
370 mPrevWndProc = nsnull;
371 mOldIMC = nsnull;
372 mNativeDragTarget = nsnull;
373 mInDtor = PR_FALSE;
374 mIsVisible = PR_FALSE;
375 mIsInMouseCapture = PR_FALSE;
376 mIsTopWidgetWindow = PR_FALSE;
377 mUnicodeWidget = PR_TRUE;
378 mDisplayPanFeedback = PR_FALSE;
379 mTouchWindow = PR_FALSE;
380 mCustomNonClient = PR_FALSE;
381 mCompositorFlag = PR_FALSE;
382 mHideChrome = PR_FALSE;
383 mWindowType = eWindowType_child;
384 mBorderStyle = eBorderStyle_default;
385 mPopupType = ePopupTypeAny;
386 mOldSizeMode = nsSizeMode_Normal;
387 mLastPoint.x = 0;
388 mLastPoint.y = 0;
389 mLastSize.width = 0;
390 mLastSize.height = 0;
391 mOldStyle = 0;
392 mOldExStyle = 0;
393 mPainting = 0;
394 mExitToNonClientArea = 0;
395 mLastKeyboardLayout = 0;
396 mBlurSuppressLevel = 0;
397 mIMEEnabled = nsIWidget::IME_STATUS_ENABLED;
398 #ifdef MOZ_XUL
399 mTransparentSurface = nsnull;
400 mMemoryDC = nsnull;
401 mTransparencyMode = eTransparencyOpaque;
402 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
403 memset(&mGlassMargins, 0, sizeof mGlassMargins);
404 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
405 #endif
406 mBackground = ::GetSysColor(COLOR_BTNFACE);
407 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
408 mForeground = ::GetSysColor(COLOR_WINDOWTEXT);
410 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
411 mTaskbarPreview = nsnull;
412 mHasTaskbarIconBeenCreated = PR_FALSE;
413 #endif
415 // Global initialization
416 if (!sInstanceCount) {
417 #if !defined(WINCE)
418 gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
419 #endif
421 // Init IME handler
422 nsIMM32Handler::Initialize();
424 #ifdef NS_ENABLE_TSF
425 nsTextStore::Initialize();
426 #endif
428 #if !defined(WINCE)
429 if (SUCCEEDED(::OleInitialize(NULL)))
430 sIsOleInitialized = TRUE;
431 NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
432 #endif
434 #if defined(HEAP_DUMP_EVENT)
435 InitHeapDump();
436 #endif
438 #if !defined(WINCE)
439 InitTrackPointHack();
440 #endif
442 // Init titlebar button info for custom frames.
443 nsUXThemeData::InitTitlebarInfo();
444 } // !sInstanceCount
446 mIdleService = nsnull;
448 sInstanceCount++;
451 nsWindow::~nsWindow()
453 mInDtor = PR_TRUE;
455 // If the widget was released without calling Destroy() then the native window still
456 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
458 // XXX How could this happen???
459 if (NULL != mWnd)
460 Destroy();
462 sInstanceCount--;
464 // Global shutdown
465 if (sInstanceCount == 0) {
466 #ifdef NS_ENABLE_TSF
467 nsTextStore::Terminate();
468 #endif
470 #if !defined(WINCE)
471 NS_IF_RELEASE(sCursorImgContainer);
472 if (sIsOleInitialized) {
473 ::OleFlushClipboard();
474 ::OleUninitialize();
475 sIsOleInitialized = FALSE;
477 // delete any of the IME structures that we allocated
478 nsIMM32Handler::Terminate();
479 #endif // !defined(WINCE)
482 #if !defined(WINCE)
483 NS_IF_RELEASE(mNativeDragTarget);
484 #endif // !defined(WINCE)
487 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
489 /**************************************************************
491 * SECTION: nsIWidget::Create, nsIWidget::Destroy
493 * Creating and destroying windows for this widget.
495 **************************************************************/
497 // Allow Derived classes to modify the height that is passed
498 // when the window is created or resized. Also add extra height
499 // if needed (on Windows CE)
500 PRInt32 nsWindow::GetHeight(PRInt32 aProposedHeight)
502 PRInt32 extra = 0;
504 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
505 DWORD style = WindowStyle();
506 if ((style & WS_SYSMENU) && (style & WS_POPUP)) {
507 extra = GetSystemMetrics(SM_CYCAPTION);
509 #endif
511 return aProposedHeight + extra;
514 // Create the proper widget
515 nsresult
516 nsWindow::Create(nsIWidget *aParent,
517 nsNativeWidget aNativeParent,
518 const nsIntRect &aRect,
519 EVENT_CALLBACK aHandleEventFunction,
520 nsIDeviceContext *aContext,
521 nsIAppShell *aAppShell,
522 nsIToolkit *aToolkit,
523 nsWidgetInitData *aInitData)
525 if (aInitData)
526 mUnicodeWidget = aInitData->mUnicode;
528 nsIWidget *baseParent = aInitData &&
529 (aInitData->mWindowType == eWindowType_dialog ||
530 aInitData->mWindowType == eWindowType_toplevel ||
531 aInitData->mWindowType == eWindowType_invisible) ?
532 nsnull : aParent;
534 mIsTopWidgetWindow = (nsnull == baseParent);
535 mBounds.width = aRect.width;
536 mBounds.height = aRect.height;
538 BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
539 aAppShell, aToolkit, aInitData);
541 HWND parent;
542 if (aParent) { // has a nsIWidget parent
543 parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : NULL;
544 mParent = aParent;
545 } else { // has a nsNative parent
546 parent = (HWND)aNativeParent;
547 mParent = aNativeParent ? GetNSWindowPtr((HWND)aNativeParent) : nsnull;
550 if (nsnull != aInitData) {
551 mPopupType = aInitData->mPopupHint;
554 mContentType = aInitData ? aInitData->mContentType : eContentTypeInherit;
556 DWORD style = WindowStyle();
557 DWORD extendedStyle = WindowExStyle();
559 if (aInitData->mRTL) {
560 extendedStyle |= WS_EX_LAYOUTRTL | WS_EX_NOINHERITLAYOUT;
563 if (mWindowType == eWindowType_popup) {
564 if (!aParent)
565 parent = NULL;
566 } else if (mWindowType == eWindowType_invisible) {
567 // Make sure CreateWindowEx succeeds at creating a toplevel window
568 style &= ~0x40000000; // WS_CHILDWINDOW
569 } else if (nsnull != aInitData) {
570 // See if the caller wants to explictly set clip children and clip siblings
571 if (aInitData->clipChildren) {
572 style |= WS_CLIPCHILDREN;
573 } else {
574 style &= ~WS_CLIPCHILDREN;
576 if (aInitData->clipSiblings) {
577 style |= WS_CLIPSIBLINGS;
581 mWnd = ::CreateWindowExW(extendedStyle,
582 aInitData && aInitData->mDropShadow ?
583 WindowPopupClass() : WindowClass(),
584 L"",
585 style,
586 aRect.x,
587 aRect.y,
588 aRect.width,
589 GetHeight(aRect.height),
590 parent,
591 NULL,
592 nsToolkit::mDllInstance,
593 NULL);
595 if (!mWnd) {
596 NS_WARNING("nsWindow CreateWindowEx failed.");
597 return NS_ERROR_FAILURE;
600 if (nsWindow::sTrackPointHack &&
601 mWindowType != eWindowType_plugin &&
602 mWindowType != eWindowType_invisible) {
603 // Ugly Thinkpad Driver Hack (Bug 507222)
604 // We create an invisible scrollbar to trick the
605 // Trackpoint driver into sending us scrolling messages
606 ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTSCROLLBAR",
607 WS_CHILD | WS_VISIBLE, 0,0,0,0, mWnd, NULL,
608 nsToolkit::mDllInstance, NULL);
611 // call the event callback to notify about creation
613 DispatchStandardEvent(NS_CREATE);
614 SubclassWindow(TRUE);
616 if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
617 /* The internal variable set by the config.trim_on_minimize pref
618 has not yet been initialized, and this is the hidden window
619 (conveniently created before any visible windows, and after
620 the profile has been initialized).
622 Default config.trim_on_minimize to false, to fix bug 76831
623 for good. If anyone complains about this new default, saying
624 that a Mozilla app hogs too much memory while minimized, they
625 will have that entire bug tattooed on their backside. */
627 sTrimOnMinimize = 0;
628 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
629 if (prefs) {
630 nsCOMPtr<nsIPrefBranch> prefBranch;
631 prefs->GetBranch(0, getter_AddRefs(prefBranch));
632 if (prefBranch) {
634 PRBool temp;
635 if (NS_SUCCEEDED(prefBranch->GetBoolPref("config.trim_on_minimize",
636 &temp))
637 && temp)
638 sTrimOnMinimize = 1;
640 if (NS_SUCCEEDED(prefBranch->GetBoolPref("intl.keyboard.per_window_layout",
641 &temp)))
642 sSwitchKeyboardLayout = temp;
644 if (NS_SUCCEEDED(prefBranch->GetBoolPref("mozilla.widget.disable-native-theme",
645 &temp)))
646 gDisableNativeTheme = temp;
650 #if defined(WINCE_HAVE_SOFTKB)
651 if (mWindowType == eWindowType_dialog || mWindowType == eWindowType_toplevel )
652 nsWindowCE::CreateSoftKeyMenuBar(mWnd);
653 #endif
655 return NS_OK;
658 // Close this nsWindow
659 NS_METHOD nsWindow::Destroy()
661 // WM_DESTROY has already fired, we're done.
662 if (nsnull == mWnd)
663 return NS_OK;
665 // During the destruction of all of our children, make sure we don't get deleted.
666 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
669 * On windows the LayerManagerOGL destructor wants the widget to be around for
670 * cleanup. It also would like to have the HWND intact, so we NULL it here.
672 if (mLayerManager) {
673 mLayerManager->Destroy();
675 mLayerManager = nsnull;
677 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
678 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
679 // from it. The function also destroys the window's menu, flushes the thread message queue,
680 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
681 // the window is at the top of the viewer chain).
683 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
684 // the associated child or owned windows when it destroys the parent or owner window. The
685 // function first destroys child or owned windows, and then it destroys the parent or owner
686 // window.
687 VERIFY(::DestroyWindow(mWnd));
689 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
690 // didn't get called, call it now.
691 if (PR_FALSE == mOnDestroyCalled)
692 OnDestroy();
694 return NS_OK;
697 /**************************************************************
699 * SECTION: Window class utilities
701 * Utilities for calculating the proper window class name for
702 * Create window.
704 **************************************************************/
706 // Return the proper window class for everything except popups.
707 LPCWSTR nsWindow::WindowClass()
709 if (!nsWindow::sIsRegistered) {
710 WNDCLASSW wc;
712 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
713 wc.style = CS_DBLCLKS;
714 wc.lpfnWndProc = ::DefWindowProcW;
715 wc.cbClsExtra = 0;
716 wc.cbWndExtra = 0;
717 wc.hInstance = nsToolkit::mDllInstance;
718 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
719 wc.hCursor = NULL;
720 wc.hbrBackground = mBrush;
721 wc.lpszMenuName = NULL;
722 wc.lpszClassName = kClassNameHidden;
724 BOOL succeeded = ::RegisterClassW(&wc) != 0 &&
725 ERROR_CLASS_ALREADY_EXISTS != GetLastError();
726 nsWindow::sIsRegistered = succeeded;
728 wc.lpszClassName = kClassNameContentFrame;
729 if (!::RegisterClassW(&wc) &&
730 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
731 nsWindow::sIsRegistered = FALSE;
734 wc.lpszClassName = kClassNameContent;
735 if (!::RegisterClassW(&wc) &&
736 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
737 nsWindow::sIsRegistered = FALSE;
740 wc.lpszClassName = kClassNameUI;
741 if (!::RegisterClassW(&wc) &&
742 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
743 nsWindow::sIsRegistered = FALSE;
746 wc.lpszClassName = kClassNameGeneral;
747 ATOM generalClassAtom = ::RegisterClassW(&wc);
748 if (!generalClassAtom &&
749 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
750 nsWindow::sIsRegistered = FALSE;
753 wc.lpszClassName = kClassNameDialog;
754 wc.hIcon = 0;
755 if (!::RegisterClassW(&wc) &&
756 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
757 nsWindow::sIsRegistered = FALSE;
761 if (mWindowType == eWindowType_invisible) {
762 return kClassNameHidden;
764 if (mWindowType == eWindowType_dialog) {
765 return kClassNameDialog;
767 if (mContentType == eContentTypeContent) {
768 return kClassNameContent;
770 if (mContentType == eContentTypeContentFrame) {
771 return kClassNameContentFrame;
773 if (mContentType == eContentTypeUI) {
774 return kClassNameUI;
776 return kClassNameGeneral;
779 // Return the proper popup window class
780 LPCWSTR nsWindow::WindowPopupClass()
782 if (!nsWindow::sIsPopupClassRegistered) {
783 WNDCLASSW wc;
785 wc.style = CS_DBLCLKS | CS_XP_DROPSHADOW;
786 wc.lpfnWndProc = ::DefWindowProcW;
787 wc.cbClsExtra = 0;
788 wc.cbWndExtra = 0;
789 wc.hInstance = nsToolkit::mDllInstance;
790 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
791 wc.hCursor = NULL;
792 wc.hbrBackground = mBrush;
793 wc.lpszMenuName = NULL;
794 wc.lpszClassName = kClassNameDropShadow;
796 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
797 if (!nsWindow::sIsPopupClassRegistered) {
798 // For older versions of Win32 (i.e., not XP), the registration will
799 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
800 wc.style = CS_DBLCLKS;
801 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
805 return kClassNameDropShadow;
808 /**************************************************************
810 * SECTION: Window styles utilities
812 * Return the proper windows styles and extended styles.
814 **************************************************************/
816 // Return nsWindow styles
817 #if !defined(WINCE) // implemented in nsWindowCE.cpp
818 DWORD nsWindow::WindowStyle()
820 DWORD style;
822 switch (mWindowType) {
823 case eWindowType_plugin:
824 case eWindowType_child:
825 style = WS_OVERLAPPED;
826 break;
828 case eWindowType_dialog:
829 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK |
830 DS_MODALFRAME | WS_CLIPCHILDREN;
831 if (mBorderStyle != eBorderStyle_default)
832 style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
833 break;
835 case eWindowType_popup:
836 style = WS_POPUP;
837 if (mTransparencyMode != eTransparencyGlass) {
838 style |= WS_OVERLAPPED;
840 break;
842 default:
843 NS_ERROR("unknown border style");
844 // fall through
846 case eWindowType_toplevel:
847 case eWindowType_invisible:
848 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU |
849 WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
850 break;
853 if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) {
854 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border))
855 style &= ~WS_BORDER;
857 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) {
858 style &= ~WS_DLGFRAME;
859 style |= WS_POPUP;
860 style &= ~WS_CHILD;
863 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close))
864 style &= ~0;
865 // XXX The close box can only be removed by changing the window class,
866 // as far as I know --- roc+moz@cs.cmu.edu
868 if (mBorderStyle == eBorderStyle_none ||
869 !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
870 style &= ~WS_SYSMENU;
871 // Looks like getting rid of the system menu also does away with the
872 // close box. So, we only get rid of the system menu if you want neither it
873 // nor the close box. How does the Windows "Dialog" window class get just
874 // closebox and no sysmenu? Who knows.
876 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh))
877 style &= ~WS_THICKFRAME;
879 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize))
880 style &= ~WS_MINIMIZEBOX;
882 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize))
883 style &= ~WS_MAXIMIZEBOX;
885 if (IsPopupWithTitleBar()) {
886 style |= WS_CAPTION;
887 if (mBorderStyle & eBorderStyle_close) {
888 style |= WS_SYSMENU;
893 VERIFY_WINDOW_STYLE(style);
894 return style;
896 #endif // !defined(WINCE)
898 // Return nsWindow extended styles
899 DWORD nsWindow::WindowExStyle()
901 switch (mWindowType)
903 case eWindowType_plugin:
904 case eWindowType_child:
905 return 0;
907 case eWindowType_dialog:
908 return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
910 case eWindowType_popup:
912 DWORD extendedStyle =
913 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
914 WS_EX_NOACTIVATE |
915 #endif
916 WS_EX_TOOLWINDOW;
917 if (mPopupLevel == ePopupLevelTop)
918 extendedStyle |= WS_EX_TOPMOST;
919 return extendedStyle;
921 default:
922 NS_ERROR("unknown border style");
923 // fall through
925 case eWindowType_toplevel:
926 case eWindowType_invisible:
927 return WS_EX_WINDOWEDGE;
931 /**************************************************************
933 * SECTION: Window subclassing utilities
935 * Set or clear window subclasses on native windows. Used in
936 * Create and Destroy.
938 **************************************************************/
940 // Subclass (or remove the subclass from) this component's nsWindow
941 void nsWindow::SubclassWindow(BOOL bState)
943 if (NULL != mWnd) {
944 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
945 if (!::IsWindow(mWnd)) {
946 NS_ERROR("Invalid window handle");
949 if (bState) {
950 // change the nsWindow proc
951 if (mUnicodeWidget)
952 mPrevWndProc = (WNDPROC)::SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
953 (LONG_PTR)nsWindow::WindowProc);
954 else
955 mPrevWndProc = (WNDPROC)::SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
956 (LONG_PTR)nsWindow::WindowProc);
957 NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
958 // connect the this pointer to the nsWindow handle
959 SetNSWindowPtr(mWnd, this);
961 else {
962 if (mUnicodeWidget)
963 ::SetWindowLongPtrW(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
964 else
965 ::SetWindowLongPtrA(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
966 SetNSWindowPtr(mWnd, NULL);
967 mPrevWndProc = NULL;
972 /**************************************************************
974 * SECTION: Window properties
976 * Set and clear native window properties.
978 **************************************************************/
980 static PRUnichar sPropName[40] = L"";
981 static PRUnichar* GetNSWindowPropName()
983 if (!*sPropName)
985 _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p", GetCurrentProcessId());
986 sPropName[39] = '\0';
988 return sPropName;
991 nsWindow * nsWindow::GetNSWindowPtr(HWND aWnd)
993 return (nsWindow *) ::GetPropW(aWnd, GetNSWindowPropName());
996 BOOL nsWindow::SetNSWindowPtr(HWND aWnd, nsWindow * ptr)
998 if (ptr == NULL) {
999 ::RemovePropW(aWnd, GetNSWindowPropName());
1000 return TRUE;
1001 } else {
1002 return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)ptr);
1006 /**************************************************************
1008 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
1010 * Set or clear the parent widgets using window properties, and
1011 * handles calculating native parent handles.
1013 **************************************************************/
1015 // Get and set parent widgets
1016 NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent)
1018 mParent = aNewParent;
1020 if (aNewParent) {
1021 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1023 nsIWidget* parent = GetParent();
1024 if (parent) {
1025 parent->RemoveChild(this);
1028 HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
1029 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
1030 if (newParent && mWnd) {
1031 ::SetParent(mWnd, newParent);
1034 aNewParent->AddChild(this);
1036 return NS_OK;
1039 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1041 nsIWidget* parent = GetParent();
1043 if (parent) {
1044 parent->RemoveChild(this);
1047 if (mWnd) {
1048 // If we have no parent, SetParent should return the desktop.
1049 VERIFY(::SetParent(mWnd, nsnull));
1052 return NS_OK;
1055 nsIWidget* nsWindow::GetParent(void)
1057 return GetParentWindow(PR_FALSE);
1060 nsWindow* nsWindow::GetParentWindow(PRBool aIncludeOwner)
1062 if (mIsTopWidgetWindow) {
1063 // Must use a flag instead of mWindowType to tell if the window is the
1064 // owned by the topmost widget, because a child window can be embedded inside
1065 // a HWND which is not associated with a nsIWidget.
1066 return nsnull;
1069 // If this widget has already been destroyed, pretend we have no parent.
1070 // This corresponds to code in Destroy which removes the destroyed
1071 // widget from its parent's child list.
1072 if (mInDtor || mOnDestroyCalled)
1073 return nsnull;
1076 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1077 // root owner. aIncludeOwner set to false implies the search will stop at the
1078 // true parent (default).
1079 nsWindow* widget = nsnull;
1080 if (mWnd) {
1081 #ifdef WINCE
1082 HWND parent = ::GetParent(mWnd);
1083 #else
1084 HWND parent = nsnull;
1085 if (aIncludeOwner)
1086 parent = ::GetParent(mWnd);
1087 else
1088 parent = ::GetAncestor(mWnd, GA_PARENT);
1089 #endif
1090 if (parent) {
1091 widget = GetNSWindowPtr(parent);
1092 if (widget) {
1093 // If the widget is in the process of being destroyed then
1094 // do NOT return it
1095 if (widget->mInDtor) {
1096 widget = nsnull;
1102 return widget;
1105 /**************************************************************
1107 * SECTION: nsIWidget::Show
1109 * Hide or show this component.
1111 **************************************************************/
1113 NS_METHOD nsWindow::Show(PRBool bState)
1115 #if defined(MOZ_SPLASHSCREEN)
1116 // we're about to show the first toplevel window,
1117 // so kill off any splash screen if we had one
1118 nsSplashScreen *splash = nsSplashScreen::Get();
1119 if (splash && splash->IsOpen() && mWnd && bState &&
1120 (mWindowType == eWindowType_toplevel ||
1121 mWindowType == eWindowType_dialog ||
1122 mWindowType == eWindowType_popup))
1124 splash->Close();
1126 #endif
1128 #ifdef NS_FUNCTION_TIMER
1129 static bool firstShow = true;
1130 if (firstShow &&
1131 (mWindowType == eWindowType_toplevel ||
1132 mWindowType == eWindowType_dialog ||
1133 mWindowType == eWindowType_popup))
1135 firstShow = false;
1136 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1138 #endif
1140 PRBool wasVisible = mIsVisible;
1141 // Set the status now so that anyone asking during ShowWindow or
1142 // SetWindowPos would get the correct answer.
1143 mIsVisible = bState;
1145 if (mWnd) {
1146 if (bState) {
1147 if (!wasVisible && mWindowType == eWindowType_toplevel) {
1148 switch (mSizeMode) {
1149 #ifdef WINCE
1150 case nsSizeMode_Fullscreen:
1151 ::SetForegroundWindow(mWnd);
1152 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1153 MakeFullScreen(TRUE);
1154 break;
1156 case nsSizeMode_Maximized :
1157 ::SetForegroundWindow(mWnd);
1158 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1159 break;
1160 // use default for nsSizeMode_Minimized on Windows CE
1161 #else
1162 case nsSizeMode_Maximized :
1163 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1164 break;
1165 case nsSizeMode_Minimized :
1166 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
1167 break;
1168 #endif
1169 default:
1170 if (CanTakeFocus()) {
1171 #ifdef WINCE
1172 ::SetForegroundWindow(mWnd);
1173 #endif
1174 ::ShowWindow(mWnd, SW_SHOWNORMAL);
1175 } else {
1176 // Place the window behind the foreground window
1177 // (as long as it is not topmost)
1178 HWND wndAfter = ::GetForegroundWindow();
1179 if (!wndAfter)
1180 wndAfter = HWND_BOTTOM;
1181 else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)
1182 wndAfter = HWND_TOP;
1183 ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE |
1184 SWP_NOMOVE | SWP_NOACTIVATE);
1185 GetAttention(2);
1187 break;
1189 } else {
1190 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
1191 if (wasVisible)
1192 flags |= SWP_NOZORDER;
1194 if (mWindowType == eWindowType_popup) {
1195 #ifndef WINCE
1196 // ensure popups are the topmost of the TOPMOST
1197 // layer. Remember not to set the SWP_NOZORDER
1198 // flag as that might allow the taskbar to overlap
1199 // the popup. However on windows ce, we need to
1200 // activate the popup or clicks will not be sent.
1201 flags |= SWP_NOACTIVATE;
1202 #endif
1203 HWND owner = ::GetWindow(mWnd, GW_OWNER);
1204 ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
1205 } else {
1206 #ifndef WINCE
1207 if (mWindowType == eWindowType_dialog && !CanTakeFocus())
1208 flags |= SWP_NOACTIVATE;
1209 #endif
1210 ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
1214 #ifndef WINCE
1215 if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) {
1216 // when a toplevel window or dialog is shown, initialize the UI state
1217 ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
1219 #endif
1220 } else {
1221 if (mWindowType != eWindowType_dialog) {
1222 ::ShowWindow(mWnd, SW_HIDE);
1223 } else {
1224 ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1225 SWP_NOZORDER | SWP_NOACTIVATE);
1230 #ifdef MOZ_XUL
1231 if (!wasVisible && bState)
1232 Invalidate(PR_FALSE);
1233 #endif
1235 return NS_OK;
1238 /**************************************************************
1240 * SECTION: nsIWidget::IsVisible
1242 * Returns the visibility state.
1244 **************************************************************/
1246 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1247 NS_METHOD nsWindow::IsVisible(PRBool & bState)
1249 bState = mIsVisible;
1250 return NS_OK;
1253 /**************************************************************
1255 * SECTION: Window clipping utilities
1257 * Used in Size and Move operations for setting the proper
1258 * window clipping regions for window transparency.
1260 **************************************************************/
1262 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1263 // transparency. These routines are called on size and move operations.
1264 void nsWindow::ClearThemeRegion()
1266 #ifndef WINCE
1267 if (nsUXThemeData::sIsVistaOrLater && mTransparencyMode != eTransparencyGlass &&
1268 mWindowType == eWindowType_popup && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel)) {
1269 SetWindowRgn(mWnd, NULL, false);
1271 #endif
1274 void nsWindow::SetThemeRegion()
1276 #ifndef WINCE
1277 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1278 // for other window types as needed. The regions are applied generically to the base window
1279 // so default constants are used for part and state. At some point we might need part and
1280 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1281 // change shape based on state haven't come up.
1282 if (nsUXThemeData::sIsVistaOrLater && mTransparencyMode != eTransparencyGlass &&
1283 mWindowType == eWindowType_popup && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel)) {
1284 HRGN hRgn = nsnull;
1285 RECT rect = {0,0,mBounds.width,mBounds.height};
1287 HDC dc = ::GetDC(mWnd);
1288 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
1289 if (hRgn) {
1290 if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted.
1291 DeleteObject(hRgn);
1293 ::ReleaseDC(mWnd, dc);
1295 #endif
1298 /**************************************************************
1300 * SECTION: nsIWidget::RegisterTouchWindow,
1301 * nsIWidget::UnregisterTouchWindow, and helper functions
1303 * Used to register the native window to receive touch events
1305 **************************************************************/
1307 NS_METHOD nsWindow::RegisterTouchWindow() {
1308 mTouchWindow = PR_TRUE;
1309 #ifndef WINCE
1310 mGesture.RegisterTouchWindow(mWnd);
1311 ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, NULL);
1312 #endif
1313 return NS_OK;
1316 NS_METHOD nsWindow::UnregisterTouchWindow() {
1317 mTouchWindow = PR_FALSE;
1318 #ifndef WINCE
1319 mGesture.UnregisterTouchWindow(mWnd);
1320 ::EnumChildWindows(mWnd, nsWindow::UnregisterTouchForDescendants, NULL);
1321 #endif
1322 return NS_OK;
1325 #ifndef WINCE
1326 BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1327 nsWindow* win = GetNSWindowPtr(aWnd);
1328 if (win)
1329 win->mGesture.RegisterTouchWindow(aWnd);
1330 return TRUE;
1333 BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1334 nsWindow* win = GetNSWindowPtr(aWnd);
1335 if (win)
1336 win->mGesture.UnregisterTouchWindow(aWnd);
1337 return TRUE;
1339 #endif
1341 /**************************************************************
1343 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1344 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1346 * Repositioning and sizing a window.
1348 **************************************************************/
1350 // Move this component
1351 NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
1353 if (mWindowType == eWindowType_toplevel ||
1354 mWindowType == eWindowType_dialog) {
1355 SetSizeMode(nsSizeMode_Normal);
1357 // Check to see if window needs to be moved first
1358 // to avoid a costly call to SetWindowPos. This check
1359 // can not be moved to the calling code in nsView, because
1360 // some platforms do not position child windows correctly
1362 // Only perform this check for non-popup windows, since the positioning can
1363 // in fact change even when the x/y do not. We always need to perform the
1364 // check. See bug #97805 for details.
1365 if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
1367 // Nothing to do, since it is already positioned correctly.
1368 return NS_OK;
1371 mBounds.x = aX;
1372 mBounds.y = aY;
1374 if (mWnd) {
1375 #ifdef DEBUG
1376 // complain if a window is moved offscreen (legal, but potentially worrisome)
1377 if (mIsTopWidgetWindow) { // only a problem for top-level windows
1378 // Make sure this window is actually on the screen before we move it
1379 // XXX: Needs multiple monitor support
1380 HDC dc = ::GetDC(mWnd);
1381 if (dc) {
1382 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1383 RECT workArea;
1384 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1385 // no annoying assertions. just mention the issue.
1386 if (aX < 0 || aX >= workArea.right || aY < 0 || aY >= workArea.bottom)
1387 printf("window moved to offscreen position\n");
1389 ::ReleaseDC(mWnd, dc);
1392 #endif
1393 ClearThemeRegion();
1394 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0,
1395 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE));
1396 SetThemeRegion();
1398 return NS_OK;
1401 // Resize this component
1402 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1404 NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
1405 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1407 // Avoid unnecessary resizing calls
1408 if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1409 return NS_OK;
1411 #ifdef MOZ_XUL
1412 if (eTransparencyTransparent == mTransparencyMode)
1413 ResizeTranslucentWindow(aWidth, aHeight);
1414 #endif
1416 // Set cached value for lightweight and printing
1417 mBounds.width = aWidth;
1418 mBounds.height = aHeight;
1420 if (mWnd) {
1421 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
1423 #ifndef WINCE
1424 if (!aRepaint) {
1425 flags |= SWP_NOREDRAW;
1427 #endif
1429 ClearThemeRegion();
1430 VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
1431 SetThemeRegion();
1434 if (aRepaint)
1435 Invalidate(PR_FALSE);
1437 return NS_OK;
1440 // Resize this component
1441 NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1443 NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize");
1444 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1446 // Avoid unnecessary resizing calls
1447 if (mBounds.x == aX && mBounds.y == aY &&
1448 mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1449 return NS_OK;
1451 #ifdef MOZ_XUL
1452 if (eTransparencyTransparent == mTransparencyMode)
1453 ResizeTranslucentWindow(aWidth, aHeight);
1454 #endif
1456 // Set cached value for lightweight and printing
1457 mBounds.x = aX;
1458 mBounds.y = aY;
1459 mBounds.width = aWidth;
1460 mBounds.height = aHeight;
1462 if (mWnd) {
1463 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
1464 #ifndef WINCE
1465 if (!aRepaint) {
1466 flags |= SWP_NOREDRAW;
1468 #endif
1470 ClearThemeRegion();
1471 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
1472 SetThemeRegion();
1475 if (aRepaint)
1476 Invalidate(PR_FALSE);
1478 return NS_OK;
1481 // Resize the client area and position the widget within it's parent
1482 NS_METHOD nsWindow::ResizeClient(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1484 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1485 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1487 // Adjust our existing window bounds, based on the new client dims.
1488 RECT client;
1489 GetClientRect(mWnd, &client);
1490 nsIntPoint dims(client.right - client.left, client.bottom - client.top);
1491 aWidth = mBounds.width + (aWidth - dims.x);
1492 aHeight = mBounds.height + (aHeight - dims.y);
1494 if (aX || aY) {
1495 // offsets
1496 nsIntRect bounds;
1497 GetScreenBounds(bounds);
1498 aX += bounds.x;
1499 aY += bounds.y;
1500 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1502 return Resize(aWidth, aHeight, aRepaint);
1505 #if !defined(WINCE)
1506 NS_IMETHODIMP
1507 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
1509 NS_ENSURE_ARG_POINTER(aEvent);
1511 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
1512 // you can only begin a resize drag with a mouse event
1513 return NS_ERROR_INVALID_ARG;
1516 nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
1517 if (mouseEvent->button != nsMouseEvent::eLeftButton) {
1518 // you can only begin a resize drag with the left mouse button
1519 return NS_ERROR_INVALID_ARG;
1522 // work out what sizemode we're talking about
1523 WPARAM syscommand;
1524 if (aVertical < 0) {
1525 if (aHorizontal < 0) {
1526 syscommand = SC_SIZE | WMSZ_TOPLEFT;
1527 } else if (aHorizontal == 0) {
1528 syscommand = SC_SIZE | WMSZ_TOP;
1529 } else {
1530 syscommand = SC_SIZE | WMSZ_TOPRIGHT;
1532 } else if (aVertical == 0) {
1533 if (aHorizontal < 0) {
1534 syscommand = SC_SIZE | WMSZ_LEFT;
1535 } else if (aHorizontal == 0) {
1536 return NS_ERROR_INVALID_ARG;
1537 } else {
1538 syscommand = SC_SIZE | WMSZ_RIGHT;
1540 } else {
1541 if (aHorizontal < 0) {
1542 syscommand = SC_SIZE | WMSZ_BOTTOMLEFT;
1543 } else if (aHorizontal == 0) {
1544 syscommand = SC_SIZE | WMSZ_BOTTOM;
1545 } else {
1546 syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT;
1550 // resizing doesn't work if the mouse is already captured
1551 CaptureMouse(PR_FALSE);
1553 // find the top-level window
1554 HWND toplevelWnd = GetTopLevelHWND(mWnd, PR_TRUE);
1556 // tell Windows to start the resize
1557 ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand,
1558 POINTTOPOINTS(aEvent->refPoint));
1560 return NS_OK;
1562 #endif
1563 /**************************************************************
1565 * SECTION: Window Z-order and state.
1567 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1568 * nsIWidget::ConstrainPosition
1570 * Z-order, positioning, restore, minimize, and maximize.
1572 **************************************************************/
1574 // Position the window behind the given window
1575 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1576 nsIWidget *aWidget, PRBool aActivate)
1578 HWND behind = HWND_TOP;
1579 if (aPlacement == eZPlacementBottom)
1580 behind = HWND_BOTTOM;
1581 else if (aPlacement == eZPlacementBelow && aWidget)
1582 behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
1583 UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
1584 if (!aActivate)
1585 flags |= SWP_NOACTIVATE;
1587 if (!CanTakeFocus() && behind == HWND_TOP)
1589 // Can't place the window to top so place it behind the foreground window
1590 // (as long as it is not topmost)
1591 HWND wndAfter = ::GetForegroundWindow();
1592 if (!wndAfter)
1593 behind = HWND_BOTTOM;
1594 else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
1595 behind = wndAfter;
1596 flags |= SWP_NOACTIVATE;
1599 ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
1600 return NS_OK;
1603 // Maximize, minimize or restore the window.
1604 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1605 NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode) {
1607 nsresult rv;
1609 // Let's not try and do anything if we're already in that state.
1610 // (This is needed to prevent problems when calling window.minimize(), which
1611 // calls us directly, and then the OS triggers another call to us.)
1612 if (aMode == mSizeMode)
1613 return NS_OK;
1615 // save the requested state
1616 rv = nsBaseWidget::SetSizeMode(aMode);
1617 if (NS_SUCCEEDED(rv) && mIsVisible) {
1618 int mode;
1620 switch (aMode) {
1621 case nsSizeMode_Fullscreen :
1622 mode = SW_SHOW;
1623 break;
1625 case nsSizeMode_Maximized :
1626 mode = SW_MAXIMIZE;
1627 break;
1629 case nsSizeMode_Minimized :
1630 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1631 // keeps the window active in the tray. So after the window is minimized,
1632 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1633 // we will do some additional processing to get the active window set right.
1634 // If sTrimOnMinimize is set, we let windows handle minimization normally
1635 // using SW_MINIMIZE.
1636 mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED;
1637 break;
1639 default :
1640 mode = SW_RESTORE;
1642 ::ShowWindow(mWnd, mode);
1643 // we dispatch an activate event here to ensure that the right child window
1644 // is focused
1645 if (mode == SW_RESTORE || mode == SW_MAXIMIZE)
1646 DispatchFocusToTopLevelWindow(NS_ACTIVATE);
1648 return rv;
1650 #endif // !defined(WINCE)
1652 // Constrain a potential move to fit onscreen
1653 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop,
1654 PRInt32 *aX, PRInt32 *aY)
1656 if (!mIsTopWidgetWindow) // only a problem for top-level windows
1657 return NS_OK;
1659 PRBool doConstrain = PR_FALSE; // whether we have enough info to do anything
1661 /* get our playing field. use the current screen, or failing that
1662 for any reason, use device caps for the default screen. */
1663 RECT screenRect;
1665 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
1666 if (screenmgr) {
1667 nsCOMPtr<nsIScreen> screen;
1668 PRInt32 left, top, width, height;
1670 // zero size rects confuse the screen manager
1671 width = mBounds.width > 0 ? mBounds.width : 1;
1672 height = mBounds.height > 0 ? mBounds.height : 1;
1673 screenmgr->ScreenForRect(*aX, *aY, width, height,
1674 getter_AddRefs(screen));
1675 if (screen) {
1676 if (mSizeMode != nsSizeMode_Fullscreen) {
1677 // For normalized windows, use the desktop work area.
1678 screen->GetAvailRect(&left, &top, &width, &height);
1679 } else {
1680 // For full screen windows, use the desktop.
1681 screen->GetRect(&left, &top, &width, &height);
1683 screenRect.left = left;
1684 screenRect.right = left+width;
1685 screenRect.top = top;
1686 screenRect.bottom = top+height;
1687 doConstrain = PR_TRUE;
1689 } else {
1690 if (mWnd) {
1691 HDC dc = ::GetDC(mWnd);
1692 if (dc) {
1693 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1694 if (mSizeMode != nsSizeMode_Fullscreen) {
1695 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
1696 } else {
1697 screenRect.left = screenRect.top = 0;
1698 screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN);
1699 screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
1701 doConstrain = PR_TRUE;
1703 ::ReleaseDC(mWnd, dc);
1708 if (aAllowSlop) {
1709 if (*aX < screenRect.left - mBounds.width + kWindowPositionSlop)
1710 *aX = screenRect.left - mBounds.width + kWindowPositionSlop;
1711 else if (*aX >= screenRect.right - kWindowPositionSlop)
1712 *aX = screenRect.right - kWindowPositionSlop;
1714 if (*aY < screenRect.top - mBounds.height + kWindowPositionSlop)
1715 *aY = screenRect.top - mBounds.height + kWindowPositionSlop;
1716 else if (*aY >= screenRect.bottom - kWindowPositionSlop)
1717 *aY = screenRect.bottom - kWindowPositionSlop;
1719 } else {
1721 if (*aX < screenRect.left)
1722 *aX = screenRect.left;
1723 else if (*aX >= screenRect.right - mBounds.width)
1724 *aX = screenRect.right - mBounds.width;
1726 if (*aY < screenRect.top)
1727 *aY = screenRect.top;
1728 else if (*aY >= screenRect.bottom - mBounds.height)
1729 *aY = screenRect.bottom - mBounds.height;
1732 return NS_OK;
1735 /**************************************************************
1737 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1739 * Enabling and disabling the widget.
1741 **************************************************************/
1743 // Enable/disable this component
1744 NS_METHOD nsWindow::Enable(PRBool bState)
1746 if (mWnd) {
1747 ::EnableWindow(mWnd, bState);
1749 return NS_OK;
1752 // Return the current enable state
1753 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
1755 NS_ENSURE_ARG_POINTER(aState);
1757 #ifndef WINCE
1758 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT)));
1759 #else
1760 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(mWnd));
1761 #endif
1763 return NS_OK;
1767 /**************************************************************
1769 * SECTION: nsIWidget::SetFocus
1771 * Give the focus to this widget.
1773 **************************************************************/
1775 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
1777 if (mWnd) {
1778 #ifdef WINSTATE_DEBUG_OUTPUT
1779 if (mWnd == GetTopLevelHWND(mWnd))
1780 printf("*** SetFocus: [ top] raise=%d\n", aRaise);
1781 else
1782 printf("*** SetFocus: [child] raise=%d\n", aRaise);
1783 #endif
1784 // Uniconify, if necessary
1785 HWND toplevelWnd = GetTopLevelHWND(mWnd);
1786 if (aRaise && ::IsIconic(toplevelWnd)) {
1787 ::ShowWindow(toplevelWnd, SW_RESTORE);
1789 ::SetFocus(mWnd);
1791 return NS_OK;
1795 /**************************************************************
1797 * SECTION: Bounds
1799 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1800 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1802 * Bound calculations.
1804 **************************************************************/
1806 // Return the window's full dimensions in screen coordinates.
1807 // If the window has a parent, converts the origin to an offset
1808 // of the parent's screen origin.
1809 NS_METHOD nsWindow::GetBounds(nsIntRect &aRect)
1811 if (mWnd) {
1812 RECT r;
1813 VERIFY(::GetWindowRect(mWnd, &r));
1815 // assign size
1816 aRect.width = r.right - r.left;
1817 aRect.height = r.bottom - r.top;
1819 // chrome on parent:
1820 // ___ 5,5 (chrome start)
1821 // | ____ 10,10 (client start)
1822 // | | ____ 20,20 (child start)
1823 // | | |
1824 // 20,20 - 5,5 = 15,15 (??)
1825 // minus GetClientOffset:
1826 // 15,15 - 5,5 = 10,10
1828 // no chrome on parent:
1829 // ______ 10,10 (win start)
1830 // | ____ 20,20 (child start)
1831 // | |
1832 // 20,20 - 10,10 = 10,10
1834 // walking the chain:
1835 // ___ 5,5 (chrome start)
1836 // | ___ 10,10 (client start)
1837 // | | ___ 20,20 (child start)
1838 // | | | __ 30,30 (child start)
1839 // | | | |
1840 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1841 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1842 // minus GetClientOffset:
1843 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1845 // convert coordinates if parent exists
1846 HWND parent = ::GetParent(mWnd);
1847 if (parent) {
1848 RECT pr;
1849 VERIFY(::GetWindowRect(parent, &pr));
1850 r.left -= pr.left;
1851 r.top -= pr.top;
1852 // adjust for chrome
1853 nsWindow* pWidget = static_cast<nsWindow*>(GetParent());
1854 if (pWidget && pWidget->IsTopLevelWidget()) {
1855 nsIntPoint clientOffset = pWidget->GetClientOffset();
1856 r.left -= clientOffset.x;
1857 r.top -= clientOffset.y;
1860 aRect.x = r.left;
1861 aRect.y = r.top;
1862 } else {
1863 aRect = mBounds;
1866 return NS_OK;
1869 // Get this component dimension
1870 NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect)
1872 if (mWnd) {
1873 RECT r;
1874 VERIFY(::GetClientRect(mWnd, &r));
1876 // assign size
1877 aRect.x = 0;
1878 aRect.y = 0;
1879 aRect.width = r.right - r.left;
1880 aRect.height = r.bottom - r.top;
1882 } else {
1883 aRect.SetRect(0,0,0,0);
1885 return NS_OK;
1888 // Like GetBounds, but don't offset by the parent
1889 NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect)
1891 if (mWnd) {
1892 RECT r;
1893 VERIFY(::GetWindowRect(mWnd, &r));
1895 aRect.width = r.right - r.left;
1896 aRect.height = r.bottom - r.top;
1897 aRect.x = r.left;
1898 aRect.y = r.top;
1899 } else
1900 aRect = mBounds;
1902 return NS_OK;
1905 // return the x,y offset of the client area from the origin
1906 // of the window. If the window is borderless returns (0,0).
1907 nsIntPoint nsWindow::GetClientOffset()
1909 if (!mWnd) {
1910 return nsIntPoint(0, 0);
1913 RECT r1;
1914 GetWindowRect(mWnd, &r1);
1915 nsIntPoint pt = WidgetToScreenOffset();
1916 return nsIntPoint(pt.x - r1.left, pt.y - r1.top);
1919 void
1920 nsWindow::SetDrawsInTitlebar(PRBool aState)
1922 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1923 if (window && window != this) {
1924 return window->SetDrawsInTitlebar(aState);
1927 if (aState) {
1928 // left, top, right, bottom for nsIntMargin
1929 nsIntMargin margins(-1, 0, -1, -1);
1930 SetNonClientMargins(margins);
1932 else {
1933 nsIntMargin margins(-1, -1, -1, -1);
1934 SetNonClientMargins(margins);
1938 NS_IMETHODIMP
1939 nsWindow::GetNonClientMargins(nsIntMargin &margins)
1941 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1942 if (window && window != this) {
1943 return window->GetNonClientMargins(margins);
1946 if (mCustomNonClient) {
1947 margins = mNonClientMargins;
1948 return NS_OK;
1951 margins.top = GetSystemMetrics(SM_CYCAPTION);
1952 margins.bottom = GetSystemMetrics(SM_CYFRAME);
1953 margins.top += margins.bottom;
1954 margins.left = margins.right = GetSystemMetrics(SM_CYFRAME);
1956 return NS_OK;
1959 void
1960 nsWindow::ResetLayout()
1962 // This will trigger a frame changed event, triggering
1963 // nc calc size and a sizemode gecko event.
1964 SetWindowPos(mWnd, 0, 0, 0, 0, 0,
1965 SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|
1966 SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
1968 // If hidden, just send the frame changed event for now.
1969 if (!mIsVisible)
1970 return;
1972 // Send a gecko size event to trigger reflow.
1973 RECT clientRc = {0};
1974 GetClientRect(mWnd, &clientRc);
1975 nsIntRect evRect(nsWindowGfx::ToIntRect(clientRc));
1976 OnResize(evRect);
1978 // Invalidate and update
1979 Invalidate(PR_FALSE);
1982 // Called when the window layout changes: full screen mode transitions,
1983 // theme changes, and composition changes. Calculates the new non-client
1984 // margins and fires off a frame changed event, which triggers an nc calc
1985 // size windows event, kicking the changes in.
1986 PRBool
1987 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode, PRBool aReflowWindow)
1989 if (!mCustomNonClient)
1990 return PR_FALSE;
1992 // XXX Temp disable margins until frame rendering is supported
1993 mCompositorFlag = PR_TRUE;
1994 if(!nsUXThemeData::CheckForCompositor()) {
1995 mCompositorFlag = PR_FALSE;
1996 return PR_FALSE;
1999 mNonClientOffset.top = mNonClientOffset.bottom =
2000 mNonClientOffset.left = mNonClientOffset.right = 0;
2002 if (aSizeMode == -1)
2003 aSizeMode = mSizeMode;
2005 if (aSizeMode == nsSizeMode_Minimized ||
2006 aSizeMode == nsSizeMode_Fullscreen) {
2007 mCaptionHeight = mVertResizeMargin = mHorResizeMargin = 0;
2008 return PR_TRUE;
2011 // Note, for maximized windows, we need to continue to offset the client by
2012 // thick frame margins of a normal window, since windows expects this
2013 // in it's DwmDefWndProc hit testing.
2014 mCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
2015 mHorResizeMargin = GetSystemMetrics(SM_CXFRAME);
2016 mVertResizeMargin = GetSystemMetrics(SM_CYFRAME);
2018 mCaptionHeight += mVertResizeMargin;
2020 // If a margin value is 0, set the offset to the default size of the frame.
2021 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2022 // so that the frame size is equal to the margin value.
2023 if (!mNonClientMargins.top)
2024 mNonClientOffset.top = mCaptionHeight;
2025 else if (mNonClientMargins.top > 0)
2026 mNonClientOffset.top = mCaptionHeight - mNonClientMargins.top;
2028 if (!mNonClientMargins.left)
2029 mNonClientOffset.left = mHorResizeMargin;
2030 else if (mNonClientMargins.left > 0)
2031 mNonClientOffset.left = mHorResizeMargin - mNonClientMargins.left;
2033 if (!mNonClientMargins.right)
2034 mNonClientOffset.right = mHorResizeMargin;
2035 else if (mNonClientMargins.right > 0)
2036 mNonClientOffset.right = mHorResizeMargin - mNonClientMargins.right;
2038 if (!mNonClientMargins.bottom)
2039 mNonClientOffset.bottom = mVertResizeMargin;
2040 else if (mNonClientMargins.bottom > 0)
2041 mNonClientOffset.bottom = mVertResizeMargin - mNonClientMargins.bottom;
2043 #ifndef WINCE
2044 if (aSizeMode == nsSizeMode_Maximized) {
2045 // Address an issue with auto-hide taskbars which fall behind the window.
2046 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2047 // the taskbar works properly.
2048 MONITORINFO info = {sizeof(MONITORINFO)};
2049 if (::GetMonitorInfo(::MonitorFromWindow(mWnd, MONITOR_DEFAULTTOPRIMARY),
2050 &info)) {
2051 RECT r;
2052 if (::GetWindowRect(mWnd, &r)) {
2053 // Adjust window rect to account for non-client margins.
2054 r.top += mVertResizeMargin - mNonClientOffset.top;
2055 r.left += mHorResizeMargin - mNonClientOffset.left;
2056 r.bottom -= mVertResizeMargin - mNonClientOffset.bottom;
2057 r.right -= mHorResizeMargin - mNonClientOffset.right;
2058 // Leave the 1 pixel margin if the window covers the monitor.
2059 if (r.top <= info.rcMonitor.top &&
2060 r.left <= info.rcMonitor.left &&
2061 r.right >= info.rcMonitor.right &&
2062 r.bottom >= info.rcMonitor.bottom)
2063 mNonClientOffset.bottom -= r.bottom - info.rcMonitor.bottom + 1;
2067 #endif
2069 if (aReflowWindow) {
2070 // Force a reflow of content based on the new client
2071 // dimensions.
2072 ResetLayout();
2075 return PR_TRUE;
2078 NS_IMETHODIMP
2079 nsWindow::SetNonClientMargins(nsIntMargin &margins)
2081 if (!mIsTopWidgetWindow ||
2082 mBorderStyle & eBorderStyle_none ||
2083 mHideChrome)
2084 return NS_ERROR_INVALID_ARG;
2086 // Request for a reset
2087 if (margins.top == -1 && margins.left == -1 &&
2088 margins.right == -1 && margins.bottom == -1) {
2089 mCustomNonClient = PR_FALSE;
2090 mNonClientMargins = margins;
2091 // Force a reflow of content based on the new client
2092 // dimensions.
2093 ResetLayout();
2094 return NS_OK;
2097 if (margins.top < -1 || margins.bottom < -1 ||
2098 margins.left < -1 || margins.right < -1)
2099 return NS_ERROR_INVALID_ARG;
2101 mNonClientMargins = margins;
2102 mCustomNonClient = PR_TRUE;
2103 if (!UpdateNonClientMargins()) {
2104 NS_WARNING("UpdateNonClientMargins failed!");
2105 return PR_FALSE;
2108 return NS_OK;
2111 /**************************************************************
2113 * SECTION: nsIWidget::SetBackgroundColor
2115 * Sets the window background paint color.
2117 **************************************************************/
2119 NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
2121 nsBaseWidget::SetBackgroundColor(aColor);
2123 if (mBrush)
2124 ::DeleteObject(mBrush);
2126 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
2127 #ifndef WINCE
2128 if (mWnd != NULL) {
2129 ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush);
2131 #endif
2132 return NS_OK;
2135 /**************************************************************
2137 * SECTION: nsIWidget::SetCursor
2139 * SetCursor and related utilities for manging cursor state.
2141 **************************************************************/
2143 // Set this component cursor
2144 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
2146 // Only change cursor if it's changing
2148 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2149 //XXX If we want this optimization we need a better way to do it.
2150 //if (aCursor != mCursor) {
2151 HCURSOR newCursor = NULL;
2153 switch (aCursor) {
2154 case eCursor_select:
2155 newCursor = ::LoadCursor(NULL, IDC_IBEAM);
2156 break;
2158 case eCursor_wait:
2159 newCursor = ::LoadCursor(NULL, IDC_WAIT);
2160 break;
2162 case eCursor_hyperlink:
2164 newCursor = ::LoadCursor(NULL, IDC_HAND);
2165 break;
2168 case eCursor_standard:
2169 newCursor = ::LoadCursor(NULL, IDC_ARROW);
2170 break;
2172 case eCursor_n_resize:
2173 case eCursor_s_resize:
2174 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2175 break;
2177 case eCursor_w_resize:
2178 case eCursor_e_resize:
2179 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2180 break;
2182 case eCursor_nw_resize:
2183 case eCursor_se_resize:
2184 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2185 break;
2187 case eCursor_ne_resize:
2188 case eCursor_sw_resize:
2189 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2190 break;
2192 case eCursor_crosshair:
2193 newCursor = ::LoadCursor(NULL, IDC_CROSS);
2194 break;
2196 case eCursor_move:
2197 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2198 break;
2200 case eCursor_help:
2201 newCursor = ::LoadCursor(NULL, IDC_HELP);
2202 break;
2204 case eCursor_copy: // CSS3
2205 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
2206 break;
2208 case eCursor_alias:
2209 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
2210 break;
2212 case eCursor_cell:
2213 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
2214 break;
2216 case eCursor_grab:
2217 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
2218 break;
2220 case eCursor_grabbing:
2221 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
2222 break;
2224 case eCursor_spinning:
2225 newCursor = ::LoadCursor(NULL, IDC_APPSTARTING);
2226 break;
2228 case eCursor_context_menu:
2229 // XXX this CSS3 cursor needs to be implemented
2230 break;
2232 case eCursor_zoom_in:
2233 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
2234 break;
2236 case eCursor_zoom_out:
2237 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
2238 break;
2240 case eCursor_not_allowed:
2241 case eCursor_no_drop:
2242 newCursor = ::LoadCursor(NULL, IDC_NO);
2243 break;
2245 case eCursor_col_resize:
2246 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
2247 break;
2249 case eCursor_row_resize:
2250 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
2251 break;
2253 case eCursor_vertical_text:
2254 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT));
2255 break;
2257 case eCursor_all_scroll:
2258 // XXX not 100% appropriate perhaps
2259 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2260 break;
2262 case eCursor_nesw_resize:
2263 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2264 break;
2266 case eCursor_nwse_resize:
2267 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2268 break;
2270 case eCursor_ns_resize:
2271 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2272 break;
2274 case eCursor_ew_resize:
2275 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2276 break;
2278 case eCursor_none:
2279 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
2280 break;
2282 default:
2283 NS_ERROR("Invalid cursor type");
2284 break;
2287 if (NULL != newCursor) {
2288 mCursor = aCursor;
2289 HCURSOR oldCursor = ::SetCursor(newCursor);
2291 if (sHCursor == oldCursor) {
2292 NS_IF_RELEASE(sCursorImgContainer);
2293 if (sHCursor != NULL)
2294 ::DestroyIcon(sHCursor);
2295 sHCursor = NULL;
2299 return NS_OK;
2302 // Setting the actual cursor
2303 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
2304 PRUint32 aHotspotX, PRUint32 aHotspotY)
2306 if (sCursorImgContainer == aCursor && sHCursor) {
2307 ::SetCursor(sHCursor);
2308 return NS_OK;
2311 PRInt32 width;
2312 PRInt32 height;
2314 nsresult rv;
2315 rv = aCursor->GetWidth(&width);
2316 NS_ENSURE_SUCCESS(rv, rv);
2317 rv = aCursor->GetHeight(&height);
2318 NS_ENSURE_SUCCESS(rv, rv);
2320 // Reject cursors greater than 128 pixels in either direction, to prevent
2321 // spoofing.
2322 // XXX ideally we should rescale. Also, we could modify the API to
2323 // allow trusted content to set larger cursors.
2324 if (width > 128 || height > 128)
2325 return NS_ERROR_NOT_AVAILABLE;
2327 HCURSOR cursor;
2328 rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
2329 NS_ENSURE_SUCCESS(rv, rv);
2331 mCursor = nsCursor(-1);
2332 ::SetCursor(cursor);
2334 NS_IF_RELEASE(sCursorImgContainer);
2335 sCursorImgContainer = aCursor;
2336 NS_ADDREF(sCursorImgContainer);
2338 if (sHCursor != NULL)
2339 ::DestroyIcon(sHCursor);
2340 sHCursor = cursor;
2342 return NS_OK;
2345 /**************************************************************
2347 * SECTION: nsIWidget::Get/SetTransparencyMode
2349 * Manage the transparency mode of the top-level window
2350 * containing this widget.
2352 **************************************************************/
2354 #ifdef MOZ_XUL
2355 nsTransparencyMode nsWindow::GetTransparencyMode()
2357 return GetTopLevelWindow(PR_TRUE)->GetWindowTranslucencyInner();
2360 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
2362 GetTopLevelWindow(PR_TRUE)->SetWindowTranslucencyInner(aMode);
2365 namespace {
2366 BOOL CALLBACK AddClientAreaToRegion(HWND hWnd, LPARAM lParam) {
2367 nsIntRegion *region = reinterpret_cast<nsIntRegion*>(lParam);
2369 RECT clientRect;
2370 ::GetWindowRect(hWnd, &clientRect);
2371 nsIntRect clientArea(clientRect.left, clientRect.top,
2372 clientRect.right - clientRect.left,
2373 clientRect.bottom - clientRect.top);
2374 region->Or(*region, clientArea);
2375 return TRUE;
2379 void nsWindow::UpdatePossiblyTransparentRegion(const nsIntRegion &aDirtyRegion,
2380 const nsIntRegion &aPossiblyTransparentRegion) {
2381 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2382 if (mTransparencyMode != eTransparencyGlass)
2383 return;
2385 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2386 nsWindow* topWindow = GetNSWindowPtr(hWnd);
2388 if (GetParent())
2389 return;
2391 mPossiblyTransparentRegion.Sub(mPossiblyTransparentRegion, aDirtyRegion);
2392 mPossiblyTransparentRegion.Or(mPossiblyTransparentRegion, aPossiblyTransparentRegion);
2394 nsIntRegion childWindowRegion;
2396 ::EnumChildWindows(mWnd, AddClientAreaToRegion, reinterpret_cast<LPARAM>(&childWindowRegion));
2398 nsIntPoint clientOffset = GetClientOffset();
2399 childWindowRegion.MoveBy(-clientOffset);
2401 RECT r;
2402 ::GetWindowRect(mWnd, &r);
2403 childWindowRegion.MoveBy(-r.left, -r.top);
2405 nsIntRect clientBounds;
2406 topWindow->GetClientBounds(clientBounds);
2407 nsIntRegion opaqueRegion;
2408 opaqueRegion.Sub(clientBounds, mPossiblyTransparentRegion);
2409 opaqueRegion.Or(opaqueRegion, childWindowRegion);
2410 // Sometimes child windows overlap our bounds
2411 opaqueRegion.And(opaqueRegion, clientBounds);
2413 MARGINS margins = { 0, 0, 0, 0 };
2414 DWORD_PTR dwStyle = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
2416 // If there is no opaque region or hidechrome=true, set margins
2417 // to support a full sheet of glass.
2418 if (opaqueRegion.IsEmpty() || mHideChrome) {
2419 // Comments in MSDN indicate all values must be set to -1
2420 margins.cxLeftWidth = margins.cxRightWidth =
2421 margins.cyTopHeight = margins.cyBottomHeight = -1;
2422 } else {
2423 // Find the largest rectangle and use that to calculate the inset
2424 nsIntRect largest = opaqueRegion.GetLargestRectangle();
2425 margins.cxLeftWidth = largest.x;
2426 margins.cxRightWidth = clientBounds.width - largest.XMost();
2427 margins.cyTopHeight = largest.y;
2428 margins.cyBottomHeight = clientBounds.height - largest.YMost();
2431 // Only update glass area if there are changes
2432 if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) {
2433 mGlassMargins = margins;
2434 UpdateGlass();
2436 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2439 void nsWindow::UpdateGlass()
2441 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2442 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2444 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2445 // rendered based on the window style.
2446 // DWMNCRP_ENABLED - The non-client area rendering is
2447 // enabled; the window style is ignored.
2448 DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE;
2449 if (mTransparencyMode == eTransparencyGlass) {
2450 policy = DWMNCRP_ENABLED;
2453 // Extends the window frame behind the client area
2454 if(nsUXThemeData::CheckForCompositor()) {
2455 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd, &mGlassMargins);
2456 nsUXThemeData::dwmSetWindowAttributePtr(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy);
2458 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2460 #endif
2462 /**************************************************************
2464 * SECTION: nsIWidget::HideWindowChrome
2466 * Show or hide window chrome.
2468 **************************************************************/
2470 NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide)
2472 HWND hwnd = GetTopLevelHWND(mWnd, PR_TRUE);
2473 if (!GetNSWindowPtr(hwnd))
2475 NS_WARNING("Trying to hide window decorations in an embedded context");
2476 return NS_ERROR_FAILURE;
2479 if (mHideChrome == aShouldHide)
2480 return NS_OK;
2482 DWORD_PTR style, exStyle;
2483 mHideChrome = aShouldHide;
2484 if (aShouldHide) {
2485 DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2486 DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2488 style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
2489 exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
2490 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
2492 mOldStyle = tempStyle;
2493 mOldExStyle = tempExStyle;
2495 else {
2496 if (!mOldStyle || !mOldExStyle) {
2497 mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2498 mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2501 style = mOldStyle;
2502 exStyle = mOldExStyle;
2505 VERIFY_WINDOW_STYLE(style);
2506 ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
2507 ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
2509 return NS_OK;
2512 /**************************************************************
2514 * SECTION: nsIWidget::Invalidate
2516 * Invalidate an area of the client for painting.
2518 **************************************************************/
2520 // Invalidate this component visible area
2521 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
2523 if (mWnd)
2525 #ifdef WIDGET_DEBUG_OUTPUT
2526 debug_DumpInvalidate(stdout,
2527 this,
2528 nsnull,
2529 aIsSynchronous,
2530 nsCAutoString("noname"),
2531 (PRInt32) mWnd);
2532 #endif // WIDGET_DEBUG_OUTPUT
2534 VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
2536 if (aIsSynchronous) {
2537 VERIFY(::UpdateWindow(mWnd));
2540 return NS_OK;
2543 // Invalidate this component visible area
2544 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, PRBool aIsSynchronous)
2546 if (mWnd)
2548 #ifdef WIDGET_DEBUG_OUTPUT
2549 debug_DumpInvalidate(stdout,
2550 this,
2551 &aRect,
2552 aIsSynchronous,
2553 nsCAutoString("noname"),
2554 (PRInt32) mWnd);
2555 #endif // WIDGET_DEBUG_OUTPUT
2557 RECT rect;
2559 rect.left = aRect.x;
2560 rect.top = aRect.y;
2561 rect.right = aRect.x + aRect.width;
2562 rect.bottom = aRect.y + aRect.height;
2564 VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
2566 if (aIsSynchronous) {
2567 VERIFY(::UpdateWindow(mWnd));
2570 return NS_OK;
2573 NS_IMETHODIMP
2574 nsWindow::MakeFullScreen(PRBool aFullScreen)
2576 #if WINCE_WINDOWS_MOBILE
2577 RECT rc;
2578 if (aFullScreen) {
2579 SetForegroundWindow(mWnd);
2580 if (nsWindowCE::sMenuBarShown) {
2581 SIPINFO sipInfo;
2582 memset(&sipInfo, 0, sizeof(SIPINFO));
2583 sipInfo.cbSize = sizeof(SIPINFO);
2584 if (SipGetInfo(&sipInfo))
2585 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2586 sipInfo.rcVisibleDesktop.bottom);
2587 else
2588 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2589 GetSystemMetrics(SM_CYSCREEN));
2590 RECT menuBarRect;
2591 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle, &menuBarRect) &&
2592 menuBarRect.top < rc.bottom)
2593 rc.bottom = menuBarRect.top;
2594 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_SHOWSIPBUTTON);
2595 } else {
2597 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);
2598 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2601 else {
2602 SHFullScreen(mWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
2603 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
2606 if (aFullScreen)
2607 mSizeMode = nsSizeMode_Fullscreen;
2609 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2610 HideWindowChrome(aFullScreen);
2611 Resize(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PR_TRUE);
2613 return NS_OK;
2615 #else
2617 if (aFullScreen) {
2618 if (mSizeMode != nsSizeMode_Fullscreen)
2619 mOldSizeMode = mSizeMode;
2620 SetSizeMode(nsSizeMode_Fullscreen);
2621 } else {
2622 SetSizeMode(mOldSizeMode);
2625 UpdateNonClientMargins();
2627 // Will call hide chrome, reposition window. Note this will
2628 // also cache dimensions for restoration, so it should only
2629 // be called once per fullscreen request.
2630 return nsBaseWidget::MakeFullScreen(aFullScreen);
2631 #endif
2634 /**************************************************************
2636 * SECTION: nsIWidget::Update
2638 * Force a synchronous repaint of the window.
2640 **************************************************************/
2642 NS_IMETHODIMP nsWindow::Update()
2644 nsresult rv = NS_OK;
2646 // updates can come through for windows no longer holding an mWnd during
2647 // deletes triggered by JavaScript in buttons with mouse feedback
2648 if (mWnd)
2649 VERIFY(::UpdateWindow(mWnd));
2651 return rv;
2654 /**************************************************************
2656 * SECTION: nsIWidget::Scroll
2658 * Scroll this widget.
2660 **************************************************************/
2662 static PRBool
2663 ClipRegionContainedInRect(const nsTArray<nsIntRect>& aClipRects,
2664 const nsIntRect& aRect)
2666 for (PRUint32 i = 0; i < aClipRects.Length(); ++i) {
2667 if (!aRect.Contains(aClipRects[i]))
2668 return PR_FALSE;
2670 return PR_TRUE;
2673 // This function determines whether the given window has a descendant that
2674 // does not intersect the given aScreenRect. If we encounter a window owned
2675 // by another thread (which includes another process, since thread IDs
2676 // are unique system-wide), then we give up and conservatively return true.
2677 static PRBool
2678 HasDescendantWindowOutsideRect(DWORD aThisThreadID, HWND aWnd,
2679 const RECT& aScreenRect)
2681 // If the window is owned by another thread, give up now, don't try to
2682 // look at its children since they could change asynchronously.
2683 // XXX should we try harder here for out-of-process plugins?
2684 if (GetWindowThreadProcessId(aWnd, NULL) != aThisThreadID) {
2685 return PR_TRUE;
2687 for (HWND child = ::GetWindow(aWnd, GW_CHILD); child;
2688 child = ::GetWindow(child, GW_HWNDNEXT)) {
2689 RECT childScreenRect;
2690 ::GetWindowRect(child, &childScreenRect);
2691 RECT result;
2692 if (!::IntersectRect(&result, &childScreenRect, &aScreenRect)) {
2693 return PR_TRUE;
2696 if (HasDescendantWindowOutsideRect(aThisThreadID, child, aScreenRect)) {
2697 return PR_TRUE;
2701 return PR_FALSE;
2704 static void
2705 InvalidateRgnInWindowSubtree(HWND aWnd, HRGN aRgn, HRGN aTmpRgn)
2707 RECT clientRect;
2708 ::GetClientRect(aWnd, &clientRect);
2709 ::SetRectRgn(aTmpRgn, clientRect.left, clientRect.top,
2710 clientRect.right, clientRect.bottom);
2711 if (::CombineRgn(aTmpRgn, aTmpRgn, aRgn, RGN_AND) == NULLREGION) {
2712 return;
2715 ::InvalidateRgn(aWnd, aTmpRgn, FALSE);
2717 for (HWND child = ::GetWindow(aWnd, GW_CHILD); child;
2718 child = ::GetWindow(child, GW_HWNDNEXT)) {
2719 POINT pt = { 0, 0 };
2720 ::MapWindowPoints(child, aWnd, &pt, 1);
2721 ::OffsetRgn(aRgn, -pt.x, -pt.y);
2722 InvalidateRgnInWindowSubtree(child, aRgn, aTmpRgn);
2723 ::OffsetRgn(aRgn, pt.x, pt.y);
2727 void
2728 nsWindow::Scroll(const nsIntPoint& aDelta,
2729 const nsTArray<nsIntRect>& aDestRects,
2730 const nsTArray<Configuration>& aConfigurations)
2732 // We use SW_SCROLLCHILDREN if all the windows that intersect the
2733 // affected area are moving by the scroll amount.
2734 // First, build the set of widgets that are to be moved by the scroll
2735 // amount.
2736 // At the same time, set the clip region of all changed windows to the
2737 // intersection of the current and new regions.
2738 nsTHashtable<nsPtrHashKey<nsWindow> > scrolledWidgets;
2739 scrolledWidgets.Init();
2740 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
2741 const Configuration& configuration = aConfigurations[i];
2742 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
2743 NS_ASSERTION(w->GetParent() == this,
2744 "Configured widget is not a child");
2745 if (configuration.mBounds == w->mBounds + aDelta) {
2746 scrolledWidgets.PutEntry(w);
2748 w->SetWindowClipRegion(configuration.mClipRegion, PR_TRUE);
2751 // Create temporary regions
2752 HRGN updateRgn = ::CreateRectRgn(0, 0, 0, 0);
2753 if (!updateRgn) {
2754 // OOM?
2755 return;
2757 HRGN destRgn = ::CreateRectRgn(0, 0, 0, 0);
2758 if (!destRgn) {
2759 // OOM?
2760 ::DeleteObject((HGDIOBJ)updateRgn);
2761 return;
2764 DWORD ourThreadID = GetWindowThreadProcessId(mWnd, NULL);
2766 for (BlitRectIter iter(aDelta, aDestRects); !iter.IsDone(); ++iter) {
2767 const nsIntRect& destRect = iter.Rect();
2768 nsIntRect affectedRect;
2769 affectedRect.UnionRect(destRect, destRect - aDelta);
2770 UINT flags = SW_SCROLLCHILDREN;
2771 // Now check if any of our children would be affected by
2772 // SW_SCROLLCHILDREN but not supposed to scroll.
2773 for (nsWindow* w = static_cast<nsWindow*>(GetFirstChild()); w;
2774 w = static_cast<nsWindow*>(w->GetNextSibling())) {
2775 if (w->mBounds.Intersects(affectedRect)) {
2776 // This child will be affected
2777 nsPtrHashKey<nsWindow>* entry = scrolledWidgets.GetEntry(w);
2778 if (entry) {
2779 // It's supposed to be scrolled, so we can still use
2780 // SW_SCROLLCHILDREN. But don't allow SW_SCROLLCHILDREN to be
2781 // used on it again by a later rectangle; we don't want it to
2782 // move twice!
2783 scrolledWidgets.RawRemoveEntry(entry);
2785 nsIntPoint screenOffset = WidgetToScreenOffset();
2786 RECT screenAffectedRect = {
2787 screenOffset.x + affectedRect.x,
2788 screenOffset.y + affectedRect.y,
2789 screenOffset.x + affectedRect.XMost(),
2790 screenOffset.y + affectedRect.YMost()
2792 if (HasDescendantWindowOutsideRect(ourThreadID, w->mWnd,
2793 screenAffectedRect)) {
2794 // SW_SCROLLCHILDREN seems to not move descendant windows
2795 // that don't intersect the scrolled rectangle, *even if* the
2796 // immediate child window of the scrolled window *does* intersect
2797 // the scrolled window. So if w has a descendant window
2798 // that would not be moved, SW_SCROLLCHILDREN will hopelessly mess
2799 // things up and we must not use it.
2800 flags &= ~SW_SCROLLCHILDREN;
2802 } else {
2803 flags &= ~SW_SCROLLCHILDREN;
2804 // We may have removed some children from scrolledWidgets even
2805 // though we decide here to not use SW_SCROLLCHILDREN. That's OK,
2806 // it just means that we might not use SW_SCROLLCHILDREN
2807 // for a later rectangle when we could have.
2808 break;
2813 if (flags & SW_SCROLLCHILDREN
2814 #ifdef CAIRO_HAS_D2D_SURFACE
2815 && !mD2DWindowSurface
2816 #endif
2818 // ScrollWindowEx will send WM_MOVE to each moved window to tell it
2819 // its new position. Unfortunately those messages don't reach our
2820 // WM_MOVE handler for some plugins, so we have to update their
2821 // mBounds here. For windows that do receive WM_MOVE, this is OK,
2822 // they'll just overwrite mBounds again with the correct value.
2823 for (nsWindow* w = static_cast<nsWindow*>(GetFirstChild()); w;
2824 w = static_cast<nsWindow*>(w->GetNextSibling())) {
2825 if (w->mBounds.Intersects(affectedRect)) {
2826 w->mBounds += aDelta;
2831 RECT clip = { affectedRect.x, affectedRect.y, affectedRect.XMost(), affectedRect.YMost() };
2832 #ifdef CAIRO_HAS_D2D_SURFACE
2833 if (mD2DWindowSurface) {
2834 mD2DWindowSurface->Scroll(aDelta, affectedRect);
2836 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
2837 const Configuration& configuration = aConfigurations[i];
2838 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
2839 w->Invalidate(PR_FALSE);
2842 // Get the system clip twice, offset one by the delta. This will make
2843 // systemClip contain the area of the systemClip, and movedSystemClip
2844 // contain the area after scrolling that was covered by the systemClip.
2845 HRGN systemClip = ::CreateRectRgn(0, 0, 0, 0);
2846 HRGN movedSystemClip = ::CreateRectRgn(0, 0, 0, 0);
2847 HDC dc = ::GetDC(mWnd);
2848 ::GetRandomRgn(dc, systemClip, SYSRGN);
2849 ::GetRandomRgn(dc, movedSystemClip, SYSRGN);
2850 ::OffsetRgn(movedSystemClip, aDelta.x, aDelta.y);
2852 // RGN_DIFF will return the parts inside 'systemClip' but -not- inside
2853 // movedSystemClip. This is the area that was clipped (and possibly not
2854 // properly updated) before.
2855 ::CombineRgn(systemClip, systemClip, movedSystemClip, RGN_DIFF);
2857 // The systemClip is in screen coordinates, we need client coordinates.
2858 POINT p = { 0, 0 };
2859 ::ClientToScreen(mWnd, &p);
2860 ::OffsetRgn(systemClip, -p.x, -p.y);
2862 ::GetUpdateRgn(mWnd, updateRgn, FALSE);
2863 ::OffsetRgn(updateRgn, aDelta.x, aDelta.y);
2864 ::CombineRgn(updateRgn, updateRgn, systemClip, RGN_OR);
2866 ::DeleteObject((HGDIOBJ)systemClip);
2867 ::DeleteObject((HGDIOBJ)movedSystemClip);
2868 ::ReleaseDC(mWnd, dc);
2869 } else {
2870 #endif
2871 ::ScrollWindowEx(mWnd, aDelta.x, aDelta.y, &clip, &clip, updateRgn, NULL, flags);
2872 #ifdef CAIRO_HAS_D2D_SURFACE
2874 #endif
2875 ::SetRectRgn(destRgn, destRect.x, destRect.y, destRect.XMost(), destRect.YMost());
2876 ::CombineRgn(updateRgn, updateRgn, destRgn, RGN_AND);
2877 if (flags & SW_SCROLLCHILDREN) {
2878 for (nsWindow* w = static_cast<nsWindow*>(GetFirstChild()); w;
2879 w = static_cast<nsWindow*>(w->GetNextSibling())) {
2880 if ((w->mBounds - aDelta).Intersects(affectedRect)) {
2881 // Widgets that have been scrolled by SW_SCROLLCHILDREN but which
2882 // were, or are, partly outside the scroll area must be invalidated
2883 // because SW_SCROLLCHILDREN doesn't update parts of widgets outside
2884 // the area it scrolled, even if it moved them.
2885 nsAutoTArray<nsIntRect,1> clipRegion;
2886 w->GetWindowClipRegion(&clipRegion);
2887 if (!ClipRegionContainedInRect(clipRegion,
2888 destRect - w->mBounds.TopLeft()) ||
2889 !ClipRegionContainedInRect(clipRegion,
2890 destRect - (w->mBounds.TopLeft() - aDelta))) {
2891 ::SetRectRgn(destRgn, w->mBounds.x, w->mBounds.y, w->mBounds.XMost(), w->mBounds.YMost());
2892 ::CombineRgn(updateRgn, updateRgn, destRgn, RGN_OR);
2897 InvalidateRgnInWindowSubtree(mWnd, updateRgn, destRgn);
2898 } else {
2899 ::InvalidateRgn(mWnd, updateRgn, FALSE);
2903 ::DeleteObject((HGDIOBJ)updateRgn);
2904 ::DeleteObject((HGDIOBJ)destRgn);
2906 // Now make sure all children actually get positioned, sized and clipped
2907 // correctly. If SW_SCROLLCHILDREN already moved widgets to their correct
2908 // locations, then the SetWindowPos calls this triggers will just be
2909 // no-ops.
2910 ConfigureChildren(aConfigurations);
2913 /**************************************************************
2915 * SECTION: Native data storage
2917 * nsIWidget::GetNativeData
2918 * nsIWidget::FreeNativeData
2920 * Set or clear native data based on a constant.
2922 **************************************************************/
2924 // Return some native data according to aDataType
2925 void* nsWindow::GetNativeData(PRUint32 aDataType)
2927 switch (aDataType) {
2928 case NS_NATIVE_PLUGIN_PORT:
2929 case NS_NATIVE_WIDGET:
2930 case NS_NATIVE_WINDOW:
2931 return (void*)mWnd;
2932 case NS_NATIVE_GRAPHIC:
2933 // XXX: This is sleezy!! Remember to Release the DC after using it!
2934 #ifdef MOZ_XUL
2935 return (void*)(eTransparencyTransparent == mTransparencyMode) ?
2936 mMemoryDC : ::GetDC(mWnd);
2937 #else
2938 return (void*)::GetDC(mWnd);
2939 #endif
2941 #ifdef NS_ENABLE_TSF
2942 case NS_NATIVE_TSF_THREAD_MGR:
2943 return nsTextStore::GetThreadMgr();
2944 case NS_NATIVE_TSF_CATEGORY_MGR:
2945 return nsTextStore::GetCategoryMgr();
2946 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
2947 return nsTextStore::GetDisplayAttrMgr();
2948 #endif //NS_ENABLE_TSF
2950 default:
2951 break;
2954 return NULL;
2957 // Free some native data according to aDataType
2958 void nsWindow::FreeNativeData(void * data, PRUint32 aDataType)
2960 switch (aDataType)
2962 case NS_NATIVE_GRAPHIC:
2963 #ifdef MOZ_XUL
2964 if (eTransparencyTransparent != mTransparencyMode)
2965 ::ReleaseDC(mWnd, (HDC)data);
2966 #else
2967 ::ReleaseDC(mWnd, (HDC)data);
2968 #endif
2969 break;
2970 case NS_NATIVE_WIDGET:
2971 case NS_NATIVE_WINDOW:
2972 case NS_NATIVE_PLUGIN_PORT:
2973 break;
2974 default:
2975 break;
2979 /**************************************************************
2981 * SECTION: nsIWidget::SetTitle
2983 * Set the main windows title text.
2985 **************************************************************/
2987 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
2989 const nsString& strTitle = PromiseFlatString(aTitle);
2990 ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get());
2991 return NS_OK;
2994 /**************************************************************
2996 * SECTION: nsIWidget::SetIcon
2998 * Set the main windows icon.
3000 **************************************************************/
3002 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec)
3004 #ifndef WINCE
3005 // Assume the given string is a local identifier for an icon file.
3007 nsCOMPtr<nsILocalFile> iconFile;
3008 ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
3009 getter_AddRefs(iconFile));
3010 if (!iconFile)
3011 return NS_OK; // not an error if icon is not found
3013 nsAutoString iconPath;
3014 iconFile->GetPath(iconPath);
3016 // XXX this should use MZLU (see bug 239279)
3018 ::SetLastError(0);
3020 HICON bigIcon = (HICON)::LoadImageW(NULL,
3021 (LPCWSTR)iconPath.get(),
3022 IMAGE_ICON,
3023 ::GetSystemMetrics(SM_CXICON),
3024 ::GetSystemMetrics(SM_CYICON),
3025 LR_LOADFROMFILE );
3026 HICON smallIcon = (HICON)::LoadImageW(NULL,
3027 (LPCWSTR)iconPath.get(),
3028 IMAGE_ICON,
3029 ::GetSystemMetrics(SM_CXSMICON),
3030 ::GetSystemMetrics(SM_CYSMICON),
3031 LR_LOADFROMFILE );
3033 if (bigIcon) {
3034 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon);
3035 if (icon)
3036 ::DestroyIcon(icon);
3038 #ifdef DEBUG_SetIcon
3039 else {
3040 NS_LossyConvertUTF16toASCII cPath(iconPath);
3041 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
3043 #endif
3044 if (smallIcon) {
3045 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon);
3046 if (icon)
3047 ::DestroyIcon(icon);
3049 #ifdef DEBUG_SetIcon
3050 else {
3051 NS_LossyConvertUTF16toASCII cPath(iconPath);
3052 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
3054 #endif
3055 #endif // WINCE
3056 return NS_OK;
3059 /**************************************************************
3061 * SECTION: nsIWidget::WidgetToScreenOffset
3063 * Return this widget's origin in screen coordinates.
3065 **************************************************************/
3067 nsIntPoint nsWindow::WidgetToScreenOffset()
3069 POINT point;
3070 point.x = 0;
3071 point.y = 0;
3072 ::ClientToScreen(mWnd, &point);
3073 return nsIntPoint(point.x, point.y);
3076 nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize)
3078 if (!IsPopupWithTitleBar())
3079 return aClientSize;
3081 // just use (200, 200) as the position
3082 RECT r;
3083 r.left = 200;
3084 r.top = 200;
3085 r.right = 200 + aClientSize.width;
3086 r.bottom = 200 + aClientSize.height;
3087 ::AdjustWindowRectEx(&r, WindowStyle(), PR_FALSE, WindowExStyle());
3089 return nsIntSize(r.right - r.left, r.bottom - r.top);
3092 /**************************************************************
3094 * SECTION: nsIWidget::EnableDragDrop
3096 * Enables/Disables drag and drop of files on this widget.
3098 **************************************************************/
3100 #if !defined(WINCE) // implemented in nsWindowCE.cpp
3101 NS_METHOD nsWindow::EnableDragDrop(PRBool aEnable)
3103 NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()");
3105 nsresult rv = NS_ERROR_FAILURE;
3106 if (aEnable) {
3107 if (nsnull == mNativeDragTarget) {
3108 mNativeDragTarget = new nsNativeDragTarget(this);
3109 if (NULL != mNativeDragTarget) {
3110 mNativeDragTarget->AddRef();
3111 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) {
3112 if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) {
3113 rv = NS_OK;
3118 } else {
3119 if (nsnull != mWnd && NULL != mNativeDragTarget) {
3120 ::RevokeDragDrop(mWnd);
3121 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) {
3122 rv = NS_OK;
3124 mNativeDragTarget->DragCancel();
3125 NS_RELEASE(mNativeDragTarget);
3128 return rv;
3130 #endif
3132 /**************************************************************
3134 * SECTION: nsIWidget::CaptureMouse
3136 * Enables/Disables system mouse capture.
3138 **************************************************************/
3140 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
3142 if (!nsToolkit::gMouseTrailer) {
3143 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3144 return NS_OK;
3147 if (aCapture) {
3148 nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd);
3149 ::SetCapture(mWnd);
3150 } else {
3151 nsToolkit::gMouseTrailer->SetCaptureWindow(NULL);
3152 ::ReleaseCapture();
3154 mIsInMouseCapture = aCapture;
3155 return NS_OK;
3158 /**************************************************************
3160 * SECTION: nsIWidget::CaptureRollupEvents
3162 * Dealing with event rollup on destroy for popups. Enables &
3163 * Disables system capture of any and all events that would
3164 * cause a dropdown to be rolled up.
3166 **************************************************************/
3168 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
3169 nsIMenuRollup * aMenuRollup,
3170 PRBool aDoCapture,
3171 PRBool aConsumeRollupEvent)
3173 if (aDoCapture) {
3174 /* we haven't bothered carrying a weak reference to sRollupWidget because
3175 we believe lifespan is properly scoped. this next assertion helps
3176 assure that remains true. */
3177 NS_ASSERTION(!sRollupWidget, "rollup widget reassigned before release");
3178 sRollupConsumeEvent = aConsumeRollupEvent;
3179 NS_IF_RELEASE(sRollupWidget);
3180 NS_IF_RELEASE(sMenuRollup);
3181 sRollupListener = aListener;
3182 sMenuRollup = aMenuRollup;
3183 NS_IF_ADDREF(aMenuRollup);
3184 sRollupWidget = this;
3185 NS_ADDREF(this);
3187 #ifndef WINCE
3188 if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
3189 RegisterSpecialDropdownHooks();
3191 sProcessHook = PR_TRUE;
3192 #endif
3194 } else {
3195 sRollupListener = nsnull;
3196 NS_IF_RELEASE(sMenuRollup);
3197 NS_IF_RELEASE(sRollupWidget);
3199 #ifndef WINCE
3200 sProcessHook = PR_FALSE;
3201 UnregisterSpecialDropdownHooks();
3202 #endif
3205 return NS_OK;
3208 /**************************************************************
3210 * SECTION: nsIWidget::GetAttention
3212 * Bring this window to the user's attention.
3214 **************************************************************/
3216 // Draw user's attention to this window until it comes to foreground.
3217 NS_IMETHODIMP
3218 nsWindow::GetAttention(PRInt32 aCycleCount)
3220 #ifndef WINCE
3221 // Got window?
3222 if (!mWnd)
3223 return NS_ERROR_NOT_INITIALIZED;
3225 // Don't flash if the flash count is 0 or if the
3226 // top level window is already active.
3227 HWND fgWnd = ::GetForegroundWindow();
3228 if (aCycleCount == 0 || fgWnd == GetTopLevelHWND(mWnd))
3229 return NS_OK;
3231 HWND flashWnd = mWnd;
3232 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3233 flashWnd = ownerWnd;
3236 // Don't flash if the owner window is active either.
3237 if (fgWnd == flashWnd)
3238 return NS_OK;
3240 DWORD defaultCycleCount = 0;
3241 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
3243 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3244 FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 };
3245 ::FlashWindowEx(&flashInfo);
3246 #endif
3247 return NS_OK;
3250 void nsWindow::StopFlashing()
3252 #ifndef WINCE
3253 HWND flashWnd = mWnd;
3254 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3255 flashWnd = ownerWnd;
3258 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3259 FLASHW_STOP, 0, 0 };
3260 ::FlashWindowEx(&flashInfo);
3261 #endif
3264 /**************************************************************
3266 * SECTION: nsIWidget::HasPendingInputEvent
3268 * Ask whether there user input events pending. All input events are
3269 * included, including those not targeted at this nsIwidget instance.
3271 **************************************************************/
3273 PRBool
3274 nsWindow::HasPendingInputEvent()
3276 // If there is pending input or the user is currently
3277 // moving the window then return true.
3278 // Note: When the user is moving the window WIN32 spins
3279 // a separate event loop and input events are not
3280 // reported to the application.
3281 if (HIWORD(GetQueueStatus(QS_INPUT)))
3282 return PR_TRUE;
3283 #ifdef WINCE
3284 return PR_FALSE;
3285 #else
3286 GUITHREADINFO guiInfo;
3287 guiInfo.cbSize = sizeof(GUITHREADINFO);
3288 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo))
3289 return PR_FALSE;
3290 return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE);
3291 #endif
3294 /**************************************************************
3296 * SECTION: nsIWidget::GetLayerManager
3298 * Get the layer manager associated with this widget.
3300 **************************************************************/
3302 mozilla::layers::LayerManager*
3303 nsWindow::GetLayerManager()
3305 nsWindow *topWindow = GetNSWindowPtr(GetTopLevelHWND(mWnd, PR_TRUE));
3307 if (!topWindow) {
3308 return nsBaseWidget::GetLayerManager();
3311 if (topWindow->GetAcceleratedRendering() != mUseAcceleratedRendering) {
3312 mLayerManager = NULL;
3313 mUseAcceleratedRendering = topWindow->GetAcceleratedRendering();
3316 #ifndef WINCE
3317 if (!mLayerManager) {
3318 if (mUseAcceleratedRendering) {
3319 nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3321 PRBool allowAcceleration = PR_TRUE;
3322 PRBool preferOpenGL = PR_FALSE;
3323 if (prefs) {
3324 prefs->GetBoolPref("mozilla.widget.accelerated-layers",
3325 &allowAcceleration);
3326 prefs->GetBoolPref("mozilla.layers.prefer-opengl",
3327 &preferOpenGL);
3330 if (allowAcceleration) {
3331 #ifdef MOZ_ENABLE_D3D9_LAYER
3332 if (!preferOpenGL) {
3333 nsRefPtr<mozilla::layers::LayerManagerD3D9> layerManager =
3334 new mozilla::layers::LayerManagerD3D9(this);
3335 if (layerManager->Initialize()) {
3336 mLayerManager = layerManager;
3339 #endif
3340 if (!mLayerManager) {
3341 nsRefPtr<mozilla::layers::LayerManagerOGL> layerManager =
3342 new mozilla::layers::LayerManagerOGL(this);
3343 if (layerManager->Initialize()) {
3344 mLayerManager = layerManager;
3350 #endif
3352 return nsBaseWidget::GetLayerManager();
3355 /**************************************************************
3357 * SECTION: nsIWidget::GetThebesSurface
3359 * Get the Thebes surface associated with this widget.
3361 **************************************************************/
3363 gfxASurface *nsWindow::GetThebesSurface()
3365 #ifdef CAIRO_HAS_D2D_SURFACE
3366 if (mD2DWindowSurface) {
3367 return mD2DWindowSurface;
3369 #endif
3370 if (mPaintDC)
3371 return (new gfxWindowsSurface(mPaintDC));
3373 #ifdef CAIRO_HAS_D2D_SURFACE
3374 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3375 gfxWindowsPlatform::RENDER_DIRECT2D) {
3376 gfxASurface::gfxContentType content = gfxASurface::CONTENT_COLOR;
3377 #if defined(MOZ_XUL)
3378 if (mTransparencyMode != eTransparencyOpaque) {
3379 content = gfxASurface::CONTENT_COLOR_ALPHA;
3381 #endif
3382 return (new gfxD2DSurface(mWnd, content));
3383 } else {
3384 #endif
3385 PRUint32 flags = gfxWindowsSurface::FLAG_TAKE_DC;
3386 if (mTransparencyMode != eTransparencyOpaque) {
3387 flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT;
3389 return (new gfxWindowsSurface(mWnd, flags));
3390 #ifdef CAIRO_HAS_D2D_SURFACE
3392 #endif
3395 /**************************************************************
3397 * SECTION: nsIWidget::OnDefaultButtonLoaded
3399 * Called after the dialog is loaded and it has a default button.
3401 **************************************************************/
3403 NS_IMETHODIMP
3404 nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect)
3406 #ifdef WINCE
3407 return NS_ERROR_NOT_IMPLEMENTED;
3408 #else
3409 if (aButtonRect.IsEmpty())
3410 return NS_OK;
3412 // Don't snap when we are not active.
3413 HWND activeWnd = ::GetActiveWindow();
3414 if (activeWnd != ::GetForegroundWindow() ||
3415 GetTopLevelHWND(mWnd, PR_TRUE) != GetTopLevelHWND(activeWnd, PR_TRUE)) {
3416 return NS_OK;
3419 PRBool isAlwaysSnapCursor = PR_FALSE;
3420 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3421 if (prefs) {
3422 nsCOMPtr<nsIPrefBranch> prefBranch;
3423 prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
3424 if (prefBranch) {
3425 prefBranch->GetBoolPref("ui.cursor_snapping.always_enabled",
3426 &isAlwaysSnapCursor);
3430 if (!isAlwaysSnapCursor) {
3431 BOOL snapDefaultButton;
3432 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0,
3433 &snapDefaultButton, 0) || !snapDefaultButton)
3434 return NS_OK;
3437 nsIntRect widgetRect;
3438 nsresult rv = GetScreenBounds(widgetRect);
3439 NS_ENSURE_SUCCESS(rv, rv);
3440 nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft());
3442 nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2,
3443 buttonRect.y + buttonRect.height / 2);
3444 // The center of the button can be outside of the widget.
3445 // E.g., it could be hidden by scrolling.
3446 if (!widgetRect.Contains(centerOfButton)) {
3447 return NS_OK;
3450 if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) {
3451 NS_ERROR("SetCursorPos failed");
3452 return NS_ERROR_FAILURE;
3454 return NS_OK;
3455 #endif
3458 NS_IMETHODIMP
3459 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta,
3460 PRBool aIsHorizontal,
3461 PRInt32 &aOverriddenDelta)
3463 // The default vertical and horizontal scrolling speed is 3, this is defined
3464 // on the document of SystemParametersInfo in MSDN.
3465 const PRInt32 kSystemDefaultScrollingSpeed = 3;
3467 PRInt32 absOriginDelta = PR_ABS(aOriginalDelta);
3469 // Compute the simple overridden speed.
3470 PRInt32 absComputedOverriddenDelta;
3471 nsresult rv =
3472 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta, aIsHorizontal,
3473 absComputedOverriddenDelta);
3474 NS_ENSURE_SUCCESS(rv, rv);
3476 aOverriddenDelta = aOriginalDelta;
3478 if (absComputedOverriddenDelta == absOriginDelta) {
3479 // We don't override now.
3480 return NS_OK;
3483 // Otherwise, we should check whether the user customized the system settings
3484 // or not. If the user did it, we should respect the will.
3485 UINT systemSpeed;
3486 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) {
3487 return NS_ERROR_FAILURE;
3489 // The default vertical scrolling speed is 3, this is defined on the document
3490 // of SystemParametersInfo in MSDN.
3491 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3492 return NS_OK;
3495 // Only Vista and later, Windows has the system setting of horizontal
3496 // scrolling by the mouse wheel.
3497 if (GetWindowsVersion() >= VISTA_VERSION) {
3498 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) {
3499 return NS_ERROR_FAILURE;
3501 // The default horizontal scrolling speed is 3, this is defined on the
3502 // document of SystemParametersInfo in MSDN.
3503 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3504 return NS_OK;
3508 // Limit the overridden delta value from the system settings. The mouse
3509 // driver might accelerate the scrolling speed already. If so, we shouldn't
3510 // override the scrolling speed for preventing the unexpected high speed
3511 // scrolling.
3512 PRInt32 absDeltaLimit;
3513 rv =
3514 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed,
3515 aIsHorizontal, absDeltaLimit);
3516 NS_ENSURE_SUCCESS(rv, rv);
3518 // If the given delta is larger than our computed limitation value, the delta
3519 // was accelerated by the mouse driver. So, we should do nothing here.
3520 if (absDeltaLimit <= absOriginDelta) {
3521 return NS_OK;
3524 absComputedOverriddenDelta =
3525 PR_MIN(absComputedOverriddenDelta, absDeltaLimit);
3527 aOverriddenDelta = (aOriginalDelta > 0) ? absComputedOverriddenDelta :
3528 -absComputedOverriddenDelta;
3529 return NS_OK;
3532 /**************************************************************
3533 **************************************************************
3535 ** BLOCK: Moz Events
3537 ** Moz GUI event management.
3539 **************************************************************
3540 **************************************************************/
3542 /**************************************************************
3544 * SECTION: Mozilla event initialization
3546 * Helpers for initializing moz events.
3548 **************************************************************/
3550 // Event intialization
3551 MSG nsWindow::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam)
3553 MSG msg;
3554 msg.message = aMessage;
3555 msg.wParam = wParam;
3556 msg.lParam = lParam;
3557 return msg;
3560 void nsWindow::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
3562 if (nsnull == aPoint) { // use the point from the event
3563 // get the message position in client coordinates
3564 if (mWnd != NULL) {
3566 DWORD pos = ::GetMessagePos();
3567 POINT cpos;
3569 cpos.x = GET_X_LPARAM(pos);
3570 cpos.y = GET_Y_LPARAM(pos);
3572 ::ScreenToClient(mWnd, &cpos);
3573 event.refPoint.x = cpos.x;
3574 event.refPoint.y = cpos.y;
3575 } else {
3576 event.refPoint.x = 0;
3577 event.refPoint.y = 0;
3580 else {
3581 // use the point override if provided
3582 event.refPoint.x = aPoint->x;
3583 event.refPoint.y = aPoint->y;
3586 #ifndef WINCE
3587 event.time = ::GetMessageTime();
3588 #else
3589 event.time = PR_Now() / 1000;
3590 #endif
3592 mLastPoint = event.refPoint;
3595 /**************************************************************
3597 * SECTION: Moz event dispatch helpers
3599 * Helpers for dispatching different types of moz events.
3601 **************************************************************/
3603 // Main event dispatch. Invokes callback and ProcessEvent method on
3604 // Event Listener object. Part of nsIWidget.
3605 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
3607 #ifdef WIDGET_DEBUG_OUTPUT
3608 debug_DumpEvent(stdout,
3609 event->widget,
3610 event,
3611 nsCAutoString("something"),
3612 (PRInt32) mWnd);
3613 #endif // WIDGET_DEBUG_OUTPUT
3615 aStatus = nsEventStatus_eIgnore;
3617 // skip processing of suppressed blur events
3618 if (event->message == NS_DEACTIVATE && BlurEventsSuppressed())
3619 return NS_OK;
3621 // Top level windows can have a view attached which requires events be sent
3622 // to the underlying base window and the view. Added when we combined the
3623 // base chrome window with the main content child for nc client area (title
3624 // bar) rendering.
3625 if (mViewCallback) {
3626 // A subset of events are sent to the base xul window first
3627 switch(event->message) {
3628 // send to the base window (view mgr ignores these for the view)
3629 case NS_UISTATECHANGED:
3630 case NS_DESTROY:
3631 case NS_SETZLEVEL:
3632 case NS_XUL_CLOSE:
3633 case NS_MOVE:
3634 (*mEventCallback)(event); // web shell / xul window
3635 return NS_OK;
3637 // sent to the base window, then to the view
3638 case NS_SIZE:
3639 case NS_DEACTIVATE:
3640 case NS_ACTIVATE:
3641 case NS_SIZEMODE:
3642 (*mEventCallback)(event); // web shell / xul window
3643 break;
3645 // attached view events
3646 aStatus = (*mViewCallback)(event);
3648 else if (mEventCallback) {
3649 aStatus = (*mEventCallback)(event);
3652 // the window can be destroyed during processing of seemingly innocuous events like, say,
3653 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3654 // which causes problems with the deleted window. therefore:
3655 if (mOnDestroyCalled)
3656 aStatus = nsEventStatus_eConsumeNoDefault;
3657 return NS_OK;
3660 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
3662 nsGUIEvent event(PR_TRUE, aMsg, this);
3663 InitEvent(event);
3665 PRBool result = DispatchWindowEvent(&event);
3666 return result;
3669 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
3671 nsEventStatus status;
3672 DispatchEvent(event, status);
3673 return ConvertStatus(status);
3676 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event, nsEventStatus &aStatus) {
3677 DispatchEvent(event, aStatus);
3678 return ConvertStatus(aStatus);
3681 PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
3682 const nsTArray<nsAlternativeCharCode>* aAlternativeCharCodes,
3683 UINT aVirtualCharCode, const MSG *aMsg,
3684 const nsModifierKeyState &aModKeyState,
3685 PRUint32 aFlags)
3687 UserActivity();
3689 nsKeyEvent event(PR_TRUE, aEventType, this);
3690 nsIntPoint point(0, 0);
3692 InitEvent(event, &point); // this add ref's event.widget
3694 event.flags |= aFlags;
3695 event.charCode = aCharCode;
3696 if (aAlternativeCharCodes)
3697 event.alternativeCharCodes.AppendElements(*aAlternativeCharCodes);
3698 event.keyCode = aVirtualCharCode;
3700 #ifdef KE_DEBUG
3701 static cnt=0;
3702 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt++,
3703 (NS_KEY_PRESS == aEventType) ? "PRESS" : (aEventType == NS_KEY_UP ? "Up" : "Down"),
3704 event.charCode, event.keyCode);
3705 printf("Shift: %s Control %s Alt: %s \n",
3706 (mIsShiftDown ? "D" : "U"), (mIsControlDown ? "D" : "U"), (mIsAltDown ? "D" : "U"));
3707 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3708 IS_VK_DOWN(NS_VK_SHIFT) ? 'S' : ' ',
3709 IS_VK_DOWN(NS_VK_CONTROL) ? 'C' : ' ',
3710 IS_VK_DOWN(NS_VK_ALT) ? 'A' : ' ',
3711 IS_VK_DOWN(VK_LSHIFT) ? 'S' : ' ',
3712 IS_VK_DOWN(VK_LCONTROL) ? 'C' : ' ',
3713 IS_VK_DOWN(VK_LMENU) ? 'A' : ' ',
3714 IS_VK_DOWN(VK_RMENU) ? 'A' : ' ',
3715 IS_VK_DOWN(VK_RCONTROL) ? 'C' : ' ',
3716 IS_VK_DOWN(VK_RSHIFT) ? 'S' : ' ');
3717 #endif
3719 event.isShift = aModKeyState.mIsShiftDown;
3720 event.isControl = aModKeyState.mIsControlDown;
3721 event.isMeta = PR_FALSE;
3722 event.isAlt = aModKeyState.mIsAltDown;
3724 NPEvent pluginEvent;
3725 if (aMsg && PluginHasFocus()) {
3726 pluginEvent.event = aMsg->message;
3727 pluginEvent.wParam = aMsg->wParam;
3728 pluginEvent.lParam = aMsg->lParam;
3729 event.pluginEvent = (void *)&pluginEvent;
3732 PRBool result = DispatchWindowEvent(&event);
3734 return result;
3737 PRBool nsWindow::DispatchCommandEvent(PRUint32 aEventCommand)
3739 nsCOMPtr<nsIAtom> command;
3740 switch (aEventCommand) {
3741 case APPCOMMAND_BROWSER_BACKWARD:
3742 command = nsWidgetAtoms::Back;
3743 break;
3744 case APPCOMMAND_BROWSER_FORWARD:
3745 command = nsWidgetAtoms::Forward;
3746 break;
3747 case APPCOMMAND_BROWSER_REFRESH:
3748 command = nsWidgetAtoms::Reload;
3749 break;
3750 case APPCOMMAND_BROWSER_STOP:
3751 command = nsWidgetAtoms::Stop;
3752 break;
3753 case APPCOMMAND_BROWSER_SEARCH:
3754 command = nsWidgetAtoms::Search;
3755 break;
3756 case APPCOMMAND_BROWSER_FAVORITES:
3757 command = nsWidgetAtoms::Bookmarks;
3758 break;
3759 case APPCOMMAND_BROWSER_HOME:
3760 command = nsWidgetAtoms::Home;
3761 break;
3762 default:
3763 return PR_FALSE;
3765 nsCommandEvent event(PR_TRUE, nsWidgetAtoms::onAppCommand, command, this);
3767 InitEvent(event);
3768 DispatchWindowEvent(&event);
3770 return PR_TRUE;
3773 // Recursively dispatch synchronous paints for nsIWidget
3774 // descendants with invalidated rectangles.
3775 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
3777 LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
3778 if (proc == (LONG_PTR)&nsWindow::WindowProc) {
3779 // its one of our windows so check to see if it has a
3780 // invalidated rect. If it does. Dispatch a synchronous
3781 // paint.
3782 if (GetUpdateRect(aWnd, NULL, FALSE))
3783 VERIFY(::UpdateWindow(aWnd));
3785 return TRUE;
3788 // Check for pending paints and dispatch any pending paint
3789 // messages for any nsIWidget which is a descendant of the
3790 // top-level window that *this* window is embedded within.
3792 // Note: We do not dispatch pending paint messages for non
3793 // nsIWidget managed windows.
3794 void nsWindow::DispatchPendingEvents()
3796 if (mPainting) {
3797 NS_WARNING("We were asked to dispatch pending events during painting, "
3798 "denying since that's unsafe.");
3799 return;
3802 // We need to ensure that reflow events do not get starved.
3803 // At the same time, we don't want to recurse through here
3804 // as that would prevent us from dispatching starved paints.
3805 static int recursionBlocker = 0;
3806 if (recursionBlocker++ == 0) {
3807 NS_ProcessPendingEvents(nsnull, PR_MillisecondsToInterval(100));
3808 --recursionBlocker;
3811 // Quickly check to see if there are any
3812 // paint events pending.
3813 if (::GetQueueStatus(QS_PAINT)) {
3814 // Find the top level window.
3815 HWND topWnd = GetTopLevelHWND(mWnd);
3817 // Dispatch pending paints for all topWnd's descendant windows.
3818 // Note: EnumChildWindows enumerates all descendant windows not just
3819 // it's children.
3820 #if !defined(WINCE)
3821 ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3822 #else
3823 nsWindowCE::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3824 #endif
3828 // Deal with plugin events
3829 PRBool nsWindow::DispatchPluginEvent(const MSG &aMsg)
3831 if (!PluginHasFocus())
3832 return PR_FALSE;
3834 nsGUIEvent event(PR_TRUE, NS_PLUGIN_EVENT, this);
3835 nsIntPoint point(0, 0);
3836 InitEvent(event, &point);
3837 NPEvent pluginEvent;
3838 pluginEvent.event = aMsg.message;
3839 pluginEvent.wParam = aMsg.wParam;
3840 pluginEvent.lParam = aMsg.lParam;
3841 event.pluginEvent = (void *)&pluginEvent;
3842 return DispatchWindowEvent(&event);
3845 PRBool nsWindow::DispatchPluginEvent(UINT aMessage,
3846 WPARAM aWParam,
3847 LPARAM aLParam,
3848 PRBool aDispatchPendingEvents)
3850 PRBool ret = DispatchPluginEvent(InitMSG(aMessage, aWParam, aLParam));
3851 if (aDispatchPendingEvents) {
3852 DispatchPendingEvents();
3854 return ret;
3857 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
3858 UINT aLastMsg)
3860 MSG msg;
3861 ::GetMessageW(&msg, mWnd, aFirstMsg, aLastMsg);
3862 DispatchPluginEvent(msg);
3865 // Deal with all sort of mouse event
3866 PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
3867 LPARAM lParam, PRBool aIsContextMenuKey,
3868 PRInt16 aButton, PRUint16 aInputSource)
3870 PRBool result = PR_FALSE;
3872 UserActivity();
3874 if (!mEventCallback) {
3875 return result;
3878 switch (aEventType) {
3879 case NS_MOUSE_BUTTON_DOWN:
3880 CaptureMouse(PR_TRUE);
3881 break;
3883 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3884 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3885 case NS_MOUSE_BUTTON_UP:
3886 case NS_MOUSE_MOVE:
3887 case NS_MOUSE_EXIT:
3888 if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && mIsInMouseCapture)
3889 CaptureMouse(PR_FALSE);
3890 break;
3892 default:
3893 break;
3895 } // switch
3897 nsIntPoint eventPoint;
3898 eventPoint.x = GET_X_LPARAM(lParam);
3899 eventPoint.y = GET_Y_LPARAM(lParam);
3901 nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal,
3902 aIsContextMenuKey
3903 ? nsMouseEvent::eContextMenuKey
3904 : nsMouseEvent::eNormal);
3905 if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) {
3906 nsIntPoint zero(0, 0);
3907 InitEvent(event, &zero);
3908 } else {
3909 InitEvent(event, &eventPoint);
3912 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
3913 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
3914 event.isMeta = PR_FALSE;
3915 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
3916 event.button = aButton;
3917 event.inputSource = aInputSource;
3919 nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
3921 // Suppress mouse moves caused by widget creation
3922 if (aEventType == NS_MOUSE_MOVE)
3924 if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y))
3925 return result;
3926 sLastMouseMovePoint.x = mpScreen.x;
3927 sLastMouseMovePoint.y = mpScreen.y;
3930 PRBool insideMovementThreshold = (abs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
3931 (abs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
3933 BYTE eventButton;
3934 switch (aButton) {
3935 case nsMouseEvent::eLeftButton:
3936 eventButton = VK_LBUTTON;
3937 break;
3938 case nsMouseEvent::eMiddleButton:
3939 eventButton = VK_MBUTTON;
3940 break;
3941 case nsMouseEvent::eRightButton:
3942 eventButton = VK_RBUTTON;
3943 break;
3944 default:
3945 eventButton = 0;
3946 break;
3949 // Doubleclicks are used to set the click count, then changed to mousedowns
3950 // We're going to time double-clicks from mouse *up* to next mouse *down*
3951 #ifndef WINCE
3952 LONG curMsgTime = ::GetMessageTime();
3953 #else
3954 LONG curMsgTime = PR_Now() / 1000;
3955 #endif
3957 if (aEventType == NS_MOUSE_DOUBLECLICK) {
3958 event.message = NS_MOUSE_BUTTON_DOWN;
3959 event.button = aButton;
3960 sLastClickCount = 2;
3962 else if (aEventType == NS_MOUSE_BUTTON_UP) {
3963 // remember when this happened for the next mouse down
3964 sLastMousePoint.x = eventPoint.x;
3965 sLastMousePoint.y = eventPoint.y;
3966 sLastMouseButton = eventButton;
3968 else if (aEventType == NS_MOUSE_BUTTON_DOWN) {
3969 // now look to see if we want to convert this to a double- or triple-click
3970 if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold &&
3971 eventButton == sLastMouseButton) {
3972 sLastClickCount ++;
3973 } else {
3974 // reset the click count, to count *this* click
3975 sLastClickCount = 1;
3977 // Set last Click time on MouseDown only
3978 sLastMouseDownTime = curMsgTime;
3980 else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
3981 sLastClickCount = 0;
3983 else if (aEventType == NS_MOUSE_EXIT) {
3984 event.exit = IsTopLevelMouseExit(mWnd) ? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
3986 else if (aEventType == NS_MOUSE_MOZHITTEST)
3988 event.flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
3990 event.clickCount = sLastClickCount;
3992 #ifdef NS_DEBUG_XX
3993 printf("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount);
3994 #endif
3996 NPEvent pluginEvent;
3998 switch (aEventType)
4000 case NS_MOUSE_BUTTON_DOWN:
4001 switch (aButton) {
4002 case nsMouseEvent::eLeftButton:
4003 pluginEvent.event = WM_LBUTTONDOWN;
4004 break;
4005 case nsMouseEvent::eMiddleButton:
4006 pluginEvent.event = WM_MBUTTONDOWN;
4007 break;
4008 case nsMouseEvent::eRightButton:
4009 pluginEvent.event = WM_RBUTTONDOWN;
4010 break;
4011 default:
4012 break;
4014 break;
4015 case NS_MOUSE_BUTTON_UP:
4016 switch (aButton) {
4017 case nsMouseEvent::eLeftButton:
4018 pluginEvent.event = WM_LBUTTONUP;
4019 break;
4020 case nsMouseEvent::eMiddleButton:
4021 pluginEvent.event = WM_MBUTTONUP;
4022 break;
4023 case nsMouseEvent::eRightButton:
4024 pluginEvent.event = WM_RBUTTONUP;
4025 break;
4026 default:
4027 break;
4029 break;
4030 case NS_MOUSE_DOUBLECLICK:
4031 switch (aButton) {
4032 case nsMouseEvent::eLeftButton:
4033 pluginEvent.event = WM_LBUTTONDBLCLK;
4034 break;
4035 case nsMouseEvent::eMiddleButton:
4036 pluginEvent.event = WM_MBUTTONDBLCLK;
4037 break;
4038 case nsMouseEvent::eRightButton:
4039 pluginEvent.event = WM_RBUTTONDBLCLK;
4040 break;
4041 default:
4042 break;
4044 break;
4045 case NS_MOUSE_MOVE:
4046 pluginEvent.event = WM_MOUSEMOVE;
4047 break;
4048 case NS_MOUSE_EXIT:
4049 pluginEvent.event = WM_MOUSELEAVE;
4050 break;
4051 default:
4052 pluginEvent.event = WM_NULL;
4053 break;
4056 pluginEvent.wParam = wParam; // plugins NEED raw OS event flags!
4057 pluginEvent.lParam = lParam;
4059 event.pluginEvent = (void *)&pluginEvent;
4061 // call the event callback
4062 if (nsnull != mEventCallback) {
4063 if (nsToolkit::gMouseTrailer)
4064 nsToolkit::gMouseTrailer->Disable();
4065 if (aEventType == NS_MOUSE_MOVE) {
4066 if (nsToolkit::gMouseTrailer && !mIsInMouseCapture) {
4067 nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd);
4069 nsIntRect rect;
4070 GetBounds(rect);
4071 rect.x = 0;
4072 rect.y = 0;
4074 if (rect.Contains(event.refPoint)) {
4075 if (sCurrentWindow == NULL || sCurrentWindow != this) {
4076 if ((nsnull != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
4077 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
4078 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, PR_FALSE,
4079 nsMouseEvent::eLeftButton, aInputSource);
4081 sCurrentWindow = this;
4082 if (!mInDtor) {
4083 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
4084 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, PR_FALSE,
4085 nsMouseEvent::eLeftButton, aInputSource);
4089 } else if (aEventType == NS_MOUSE_EXIT) {
4090 if (sCurrentWindow == this) {
4091 sCurrentWindow = nsnull;
4095 result = DispatchWindowEvent(&event);
4097 if (nsToolkit::gMouseTrailer)
4098 nsToolkit::gMouseTrailer->Enable();
4100 // Release the widget with NS_IF_RELEASE() just in case
4101 // the context menu key code in nsEventListenerManager::HandleEvent()
4102 // released it already.
4103 return result;
4106 return result;
4109 // Deal with accessibile event
4110 #ifdef ACCESSIBILITY
4111 nsAccessible*
4112 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType)
4114 if (nsnull == mEventCallback) {
4115 return nsnull;
4118 nsAccessibleEvent event(PR_TRUE, aEventType, this);
4119 InitEvent(event, nsnull);
4121 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
4122 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
4123 event.isMeta = PR_FALSE;
4124 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
4126 DispatchWindowEvent(&event);
4128 return event.mAccessible;
4130 #endif
4132 PRBool nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType)
4134 if (aEventType == NS_ACTIVATE)
4135 sJustGotActivate = PR_FALSE;
4136 sJustGotDeactivate = PR_FALSE;
4138 // retrive the toplevel window or dialog
4139 HWND curWnd = mWnd;
4140 HWND toplevelWnd = NULL;
4141 while (curWnd) {
4142 toplevelWnd = curWnd;
4144 nsWindow *win = GetNSWindowPtr(curWnd);
4145 if (win) {
4146 nsWindowType wintype;
4147 win->GetWindowType(wintype);
4148 if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog)
4149 break;
4152 curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
4155 if (toplevelWnd) {
4156 nsWindow *win = GetNSWindowPtr(toplevelWnd);
4157 if (win)
4158 return win->DispatchFocus(aEventType);
4161 return PR_FALSE;
4164 // Deal with focus messages
4165 PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
4167 // call the event callback
4168 if (mEventCallback) {
4169 nsGUIEvent event(PR_TRUE, aEventType, this);
4170 InitEvent(event);
4172 //focus and blur event should go to their base widget loc, not current mouse pos
4173 event.refPoint.x = 0;
4174 event.refPoint.y = 0;
4176 NPEvent pluginEvent;
4178 switch (aEventType)
4180 case NS_ACTIVATE:
4181 pluginEvent.event = WM_SETFOCUS;
4182 break;
4183 case NS_DEACTIVATE:
4184 pluginEvent.event = WM_KILLFOCUS;
4185 break;
4186 case NS_PLUGIN_ACTIVATE:
4187 pluginEvent.event = WM_KILLFOCUS;
4188 break;
4189 default:
4190 break;
4193 event.pluginEvent = (void *)&pluginEvent;
4195 return DispatchWindowEvent(&event);
4197 return PR_FALSE;
4200 PRBool nsWindow::IsTopLevelMouseExit(HWND aWnd)
4202 DWORD pos = ::GetMessagePos();
4203 POINT mp;
4204 mp.x = GET_X_LPARAM(pos);
4205 mp.y = GET_Y_LPARAM(pos);
4206 HWND mouseWnd = ::WindowFromPoint(mp);
4208 // GetTopLevelHWND will return a HWND for the window frame (which includes
4209 // the non-client area). If the mouse has moved into the non-client area,
4210 // we should treat it as a top-level exit.
4211 HWND mouseTopLevel = nsWindow::GetTopLevelHWND(mouseWnd);
4212 if (mouseWnd == mouseTopLevel)
4213 return PR_TRUE;
4215 return nsWindow::GetTopLevelHWND(aWnd) != mouseTopLevel;
4218 PRBool nsWindow::BlurEventsSuppressed()
4220 // are they suppressed in this window?
4221 if (mBlurSuppressLevel > 0)
4222 return PR_TRUE;
4224 // are they suppressed by any container widget?
4225 HWND parentWnd = ::GetParent(mWnd);
4226 if (parentWnd) {
4227 nsWindow *parent = GetNSWindowPtr(parentWnd);
4228 if (parent)
4229 return parent->BlurEventsSuppressed();
4231 return PR_FALSE;
4234 // In some circumstances (opening dependent windows) it makes more sense
4235 // (and fixes a crash bug) to not blur the parent window. Called from
4236 // nsFilePicker.
4237 void nsWindow::SuppressBlurEvents(PRBool aSuppress)
4239 if (aSuppress)
4240 ++mBlurSuppressLevel; // for this widget
4241 else {
4242 NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression");
4243 if (mBlurSuppressLevel > 0)
4244 --mBlurSuppressLevel;
4248 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
4250 return aStatus == nsEventStatus_eConsumeNoDefault;
4253 /**************************************************************
4255 * SECTION: IPC
4257 * IPC related helpers.
4259 **************************************************************/
4261 #ifdef MOZ_IPC
4263 // static
4264 bool
4265 nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult)
4267 switch(aMsg) {
4268 case WM_SETFOCUS:
4269 case WM_KILLFOCUS:
4270 case WM_ENABLE:
4271 case WM_WINDOWPOSCHANGING:
4272 case WM_WINDOWPOSCHANGED:
4273 case WM_PARENTNOTIFY:
4274 case WM_ACTIVATEAPP:
4275 case WM_NCACTIVATE:
4276 case WM_ACTIVATE:
4277 case WM_CHILDACTIVATE:
4278 case WM_IME_SETCONTEXT:
4279 case WM_IME_NOTIFY:
4280 case WM_SHOWWINDOW:
4281 case WM_CANCELMODE:
4282 case WM_MOUSEACTIVATE:
4283 case WM_CONTEXTMENU:
4284 aResult = 0;
4285 return true;
4287 case WM_SETTINGCHANGE:
4288 case WM_SETCURSOR:
4289 return false;
4292 #ifdef DEBUG
4293 char szBuf[200];
4294 sprintf(szBuf,
4295 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg);
4296 NS_WARNING(szBuf);
4297 #endif
4299 return false;
4302 void
4303 nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
4305 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4306 "Failed to prevent a nonqueued message from running!");
4308 // Modal UI being displayed in windowless plugins.
4309 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4310 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4311 LRESULT res;
4312 if (IsAsyncResponseEvent(msg, res)) {
4313 ReplyMessage(res);
4315 return;
4318 // Handle certain sync plugin events sent to the parent which
4319 // trigger ipc calls that result in deadlocks.
4321 DWORD dwResult = 0;
4322 PRBool handled = PR_FALSE;
4324 switch(msg) {
4325 // Windowless flash sending WM_ACTIVATE events to the main window
4326 // via calls to ShowWindow.
4327 case WM_ACTIVATE:
4328 if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE &&
4329 IsWindow((HWND)lParam))
4330 handled = PR_TRUE;
4331 break;
4332 // Wheel events forwarded from the child.
4333 case WM_MOUSEWHEEL:
4334 case WM_MOUSEHWHEEL:
4335 case WM_HSCROLL:
4336 case WM_VSCROLL:
4337 // Plugins taking or losing focus triggering focus app messages.
4338 case WM_SETFOCUS:
4339 case WM_KILLFOCUS:
4340 // Windowed plugins that pass sys key events to defwndproc generate
4341 // WM_SYSCOMMAND events to the main window.
4342 case WM_SYSCOMMAND:
4343 // Windowed plugins that fire context menu selection events to parent
4344 // windows.
4345 case WM_CONTEXTMENU:
4346 // IME events fired as a result of synchronous focus changes
4347 case WM_IME_SETCONTEXT:
4348 handled = PR_TRUE;
4349 break;
4352 if (handled &&
4353 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4354 ReplyMessage(dwResult);
4358 #endif // MOZ_IPC
4360 /**************************************************************
4361 **************************************************************
4363 ** BLOCK: Native events
4365 ** Main Windows message handlers and OnXXX handlers for
4366 ** Windows event handling.
4368 **************************************************************
4369 **************************************************************/
4371 /**************************************************************
4373 * SECTION: Wind proc.
4375 * The main Windows event procedures and associated
4376 * message processing methods.
4378 **************************************************************/
4380 // The WndProc procedure for all nsWindows in this toolkit
4381 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4383 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4384 MOZ_FUNCTION_NAME, __LINE__, hWnd, msg,
4385 wParam, lParam);
4387 // Get the window which caused the event and ask it to process the message
4388 nsWindow *someWindow = GetNSWindowPtr(hWnd);
4390 #ifdef MOZ_IPC
4391 if (someWindow)
4392 someWindow->IPCWindowProcHandler(msg, wParam, lParam);
4393 #endif
4395 // create this here so that we store the last rolled up popup until after
4396 // the event has been processed.
4397 nsAutoRollup autoRollup;
4399 LRESULT popupHandlingResult;
4400 if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult))
4401 return popupHandlingResult;
4403 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4404 // why we are hitting this assert
4405 if (nsnull == someWindow) {
4406 NS_ASSERTION(someWindow, "someWindow is null, cannot call any CallWindowProc");
4407 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
4410 // hold on to the window for the life of this method, in case it gets
4411 // deleted during processing. yes, it's a double hack, since someWindow
4412 // is not really an interface.
4413 nsCOMPtr<nsISupports> kungFuDeathGrip;
4414 if (!someWindow->mInDtor) // not if we're in the destructor!
4415 kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)someWindow);
4417 // Call ProcessMessage
4418 LRESULT retValue;
4419 if (PR_TRUE == someWindow->ProcessMessage(msg, wParam, lParam, &retValue)) {
4420 return retValue;
4423 LRESULT res = ::CallWindowProcW(someWindow->GetPrevWindowProc(),
4424 hWnd, msg, wParam, lParam);
4426 return res;
4429 // The main windows message processing method for plugins.
4430 // The result means whether this method processed the native
4431 // event for plugin. If false, the native event should be
4432 // processed by the caller self.
4433 PRBool
4434 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
4435 LRESULT *aResult,
4436 PRBool &aCallDefWndProc)
4438 NS_PRECONDITION(aResult, "aResult must be non-null.");
4439 *aResult = 0;
4441 aCallDefWndProc = PR_FALSE;
4442 PRBool eventDispatched = PR_FALSE;
4443 switch (aMsg.message) {
4444 case WM_CHAR:
4445 case WM_SYSCHAR:
4446 *aResult = ProcessCharMessage(aMsg, &eventDispatched);
4447 break;
4449 case WM_KEYUP:
4450 case WM_SYSKEYUP:
4451 *aResult = ProcessKeyUpMessage(aMsg, &eventDispatched);
4452 break;
4454 case WM_KEYDOWN:
4455 case WM_SYSKEYDOWN:
4456 *aResult = ProcessKeyDownMessage(aMsg, &eventDispatched);
4457 break;
4459 case WM_DEADCHAR:
4460 case WM_SYSDEADCHAR:
4461 case WM_CONTEXTMENU:
4463 case WM_CUT:
4464 case WM_COPY:
4465 case WM_PASTE:
4466 case WM_CLEAR:
4467 case WM_UNDO:
4468 break;
4470 default:
4471 return PR_FALSE;
4474 if (!eventDispatched)
4475 aCallDefWndProc = !DispatchPluginEvent(aMsg);
4476 DispatchPendingEvents();
4477 return PR_TRUE;
4480 // The main windows message processing method.
4481 PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
4482 LRESULT *aRetValue)
4484 // (Large blocks of code should be broken out into OnEvent handlers.)
4485 if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
4486 return PR_TRUE;
4488 #if defined(EVENT_DEBUG_OUTPUT)
4489 // First param shows all events, second param indicates whether
4490 // to show mouse move events. See nsWindowDbg for details.
4491 PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
4492 #endif
4494 PRBool eatMessage;
4495 if (nsIMM32Handler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
4496 eatMessage)) {
4497 return mWnd ? eatMessage : PR_TRUE;
4500 if (PluginHasFocus()) {
4501 PRBool callDefaultWndProc;
4502 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4503 if (ProcessMessageForPlugin(nativeMsg, aRetValue, callDefaultWndProc)) {
4504 return mWnd ? !callDefaultWndProc : PR_TRUE;
4508 static UINT vkKeyCached = 0; // caches VK code fon WM_KEYDOWN
4509 PRBool result = PR_FALSE; // call the default nsWindow proc
4510 *aRetValue = 0;
4512 static PRBool getWheelInfo = PR_TRUE;
4514 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4515 // Glass hit testing w/custom transparent margins
4516 LRESULT dwmHitResult;
4517 if (mCustomNonClient &&
4518 mCompositorFlag &&
4519 nsUXThemeData::CheckForCompositor() &&
4520 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) {
4521 *aRetValue = dwmHitResult;
4522 return PR_TRUE;
4524 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4526 switch (msg) {
4527 #ifndef WINCE
4528 // WM_QUERYENDSESSION must be handled by all windows.
4529 // Otherwise Windows thinks the window can just be killed at will.
4530 case WM_QUERYENDSESSION:
4531 if (sCanQuit == TRI_UNKNOWN)
4533 // Ask if it's ok to quit, and store the answer until we
4534 // get WM_ENDSESSION signaling the round is complete.
4535 nsCOMPtr<nsIObserverService> obsServ =
4536 mozilla::services::GetObserverService();
4537 nsCOMPtr<nsISupportsPRBool> cancelQuit =
4538 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
4539 cancelQuit->SetData(PR_FALSE);
4540 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
4542 PRBool abortQuit;
4543 cancelQuit->GetData(&abortQuit);
4544 sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
4546 *aRetValue = sCanQuit ? TRUE : FALSE;
4547 result = PR_TRUE;
4548 break;
4549 #endif
4551 #ifndef WINCE
4552 case WM_ENDSESSION:
4553 #endif
4554 case MOZ_WM_APP_QUIT:
4555 if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE))
4557 // Let's fake a shutdown sequence without actually closing windows etc.
4558 // to avoid Windows killing us in the middle. A proper shutdown would
4559 // require having a chance to pump some messages. Unfortunately
4560 // Windows won't let us do that. Bug 212316.
4561 nsCOMPtr<nsIObserverService> obsServ =
4562 mozilla::services::GetObserverService();
4563 NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
4564 obsServ->NotifyObservers(nsnull, "quit-application-granted", nsnull);
4565 obsServ->NotifyObservers(nsnull, "quit-application-forced", nsnull);
4566 obsServ->NotifyObservers(nsnull, "quit-application", nsnull);
4567 obsServ->NotifyObservers(nsnull, "profile-change-net-teardown", context.get());
4568 obsServ->NotifyObservers(nsnull, "profile-change-teardown", context.get());
4569 obsServ->NotifyObservers(nsnull, "profile-before-change", context.get());
4570 // Then a controlled but very quick exit.
4571 _exit(0);
4573 sCanQuit = TRI_UNKNOWN;
4574 result = PR_TRUE;
4575 break;
4577 #ifndef WINCE
4578 case WM_DISPLAYCHANGE:
4579 DispatchStandardEvent(NS_DISPLAYCHANGED);
4580 break;
4581 #endif
4583 case WM_SYSCOLORCHANGE:
4584 // Note: This is sent for child windows as well as top-level windows.
4585 // The Win32 toolkit normally only sends these events to top-level windows.
4586 // But we cycle through all of the childwindows and send it to them as well
4587 // so all presentations get notified properly.
4588 // See nsWindow::GlobalMsgWindowProc.
4589 DispatchStandardEvent(NS_SYSCOLORCHANGED);
4590 break;
4592 case WM_NOTIFY:
4593 // TAB change
4595 LPNMHDR pnmh = (LPNMHDR) lParam;
4597 switch (pnmh->code) {
4598 case TCN_SELCHANGE:
4600 DispatchStandardEvent(NS_TABCHANGE);
4601 result = PR_TRUE;
4603 break;
4606 break;
4608 case WM_XP_THEMECHANGED:
4610 // Update non-client margin offsets
4611 UpdateNonClientMargins();
4613 DispatchStandardEvent(NS_THEMECHANGED);
4615 // Invalidate the window so that the repaint will
4616 // pick up the new theme.
4617 Invalidate(PR_FALSE);
4619 break;
4621 case WM_FONTCHANGE:
4623 nsresult rv;
4624 PRBool didChange = PR_FALSE;
4626 // update the global font list
4627 nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
4628 if (NS_SUCCEEDED(rv)) {
4629 fontEnum->UpdateFontList(&didChange);
4630 //didChange is TRUE only if new font langGroup is added to the list.
4631 if (didChange) {
4632 // update device context font cache
4633 // Dirty but easiest way:
4634 // Changing nsIPrefBranch entry which triggers callbacks
4635 // and flows into calling mDeviceContext->FlushFontCache()
4636 // to update the font cache in all the instance of Browsers
4637 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
4638 if (prefs) {
4639 nsCOMPtr<nsIPrefBranch> fiPrefs;
4640 prefs->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs));
4641 if (fiPrefs) {
4642 PRBool fontInternalChange = PR_FALSE;
4643 fiPrefs->GetBoolPref("changed", &fontInternalChange);
4644 fiPrefs->SetBoolPref("changed", !fontInternalChange);
4648 } //if (NS_SUCCEEDED(rv))
4650 break;
4652 case WM_NCCALCSIZE:
4654 // If wParam is TRUE, it specifies that the application should indicate
4655 // which part of the client area contains valid information. The system
4656 // copies the valid information to the specified area within the new
4657 // client area. If the wParam parameter is FALSE, the application should
4658 // return zero.
4659 if (mCustomNonClient && mCompositorFlag) {
4660 if (!wParam) {
4661 result = PR_TRUE;
4662 *aRetValue = 0;
4663 break;
4666 // before:
4667 // rgrc[0]: the proposed window
4668 // rgrc[1]: the current window
4669 // rgrc[2]: the source client area
4670 // pncsp->lppos: move/size data
4671 // after:
4672 // rgrc[0]: the new client area
4673 // rgrc[1]: the destination window
4674 // rgrc[2]: the source client area
4675 // (all values in screen coordiantes)
4676 NCCALCSIZE_PARAMS *pncsp = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
4677 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd, msg, wParam, lParam);
4678 pncsp->rgrc[0].top -= mNonClientOffset.top;
4679 pncsp->rgrc[0].left -= mNonClientOffset.left;
4680 pncsp->rgrc[0].right += mNonClientOffset.right;
4681 pncsp->rgrc[0].bottom += mNonClientOffset.bottom;
4683 result = PR_TRUE;
4684 *aRetValue = res;
4686 break;
4689 case WM_NCHITTEST:
4692 * If an nc client area margin has been moved, we are responsible
4693 * for calculating where the resize margins are and returning the
4694 * appropriate set of hit test constants. DwmDefWindowProc (above)
4695 * will handle hit testing on it's command buttons if we are on a
4696 * composited desktop.
4699 if (!mCustomNonClient || !mCompositorFlag)
4700 break;
4702 *aRetValue =
4703 ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
4704 result = PR_TRUE;
4705 break;
4708 #ifndef WINCE
4709 case WM_POWERBROADCAST:
4710 // only hidden window handle this
4711 // to prevent duplicate notification
4712 if (mWindowType == eWindowType_invisible) {
4713 switch (wParam)
4715 case PBT_APMSUSPEND:
4716 PostSleepWakeNotification("sleep_notification");
4717 break;
4718 case PBT_APMRESUMEAUTOMATIC:
4719 case PBT_APMRESUMECRITICAL:
4720 case PBT_APMRESUMESUSPEND:
4721 PostSleepWakeNotification("wake_notification");
4722 break;
4725 break;
4726 #endif
4728 case WM_MOVE: // Window moved
4730 RECT rect;
4731 ::GetWindowRect(mWnd, &rect);
4732 result = OnMove(rect.left, rect.top);
4734 break;
4736 case WM_CLOSE: // close request
4737 DispatchStandardEvent(NS_XUL_CLOSE);
4738 result = PR_TRUE; // abort window closure
4739 break;
4741 case WM_DESTROY:
4742 // clean up.
4743 OnDestroy();
4744 result = PR_TRUE;
4745 break;
4747 case WM_PAINT:
4748 *aRetValue = (int) OnPaint(NULL, 0);
4749 result = PR_TRUE;
4750 break;
4752 #ifndef WINCE
4753 case WM_PRINTCLIENT:
4754 result = OnPaint((HDC) wParam, 0);
4755 break;
4756 #endif
4758 case WM_HOTKEY:
4759 result = OnHotKey(wParam, lParam);
4760 break;
4762 case WM_SYSCHAR:
4763 case WM_CHAR:
4765 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4766 result = ProcessCharMessage(nativeMsg, nsnull);
4767 DispatchPendingEvents();
4769 break;
4771 case WM_SYSKEYUP:
4772 case WM_KEYUP:
4774 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4775 result = ProcessKeyUpMessage(nativeMsg, nsnull);
4776 DispatchPendingEvents();
4778 break;
4780 case WM_SYSKEYDOWN:
4781 case WM_KEYDOWN:
4783 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4784 result = ProcessKeyDownMessage(nativeMsg, nsnull);
4785 DispatchPendingEvents();
4787 break;
4789 // say we've dealt with erase background if widget does
4790 // not need auto-erasing
4791 case WM_ERASEBKGND:
4792 if (!AutoErase((HDC)wParam)) {
4793 *aRetValue = 1;
4794 result = PR_TRUE;
4796 break;
4798 case WM_MOUSEMOVE:
4800 #ifdef WINCE_WINDOWS_MOBILE
4801 // Reset the kill timer so that we can continue at this
4802 // priority
4803 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2seconds */, NULL);
4804 #endif
4805 // Suppress dispatch of pending events
4806 // when mouse moves are generated by widget
4807 // creation instead of user input.
4808 LPARAM lParamScreen = lParamToScreen(lParam);
4809 POINT mp;
4810 mp.x = GET_X_LPARAM(lParamScreen);
4811 mp.y = GET_Y_LPARAM(lParamScreen);
4812 PRBool userMovedMouse = PR_FALSE;
4813 if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) {
4814 userMovedMouse = PR_TRUE;
4816 mExitToNonClientArea = PR_FALSE;
4818 result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam,
4819 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4820 if (userMovedMouse) {
4821 DispatchPendingEvents();
4824 break;
4826 #ifdef WINCE_WINDOWS_MOBILE
4827 case WM_TIMER:
4828 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4829 KillTimer(mWnd, KILL_PRIORITY_ID);
4830 break;
4831 #endif
4833 case WM_LBUTTONDOWN:
4835 #ifdef WINCE_WINDOWS_MOBILE
4836 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
4837 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2 seconds */, NULL);
4838 #endif
4839 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
4840 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4841 DispatchPendingEvents();
4843 break;
4845 case WM_LBUTTONUP:
4847 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam,
4848 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4849 DispatchPendingEvents();
4851 #ifdef WINCE_WINDOWS_MOBILE
4852 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4853 KillTimer(mWnd, KILL_PRIORITY_ID);
4854 #endif
4856 break;
4858 #ifndef WINCE
4859 case WM_MOUSELEAVE:
4861 // We need to check mouse button states and put them in for
4862 // wParam.
4863 WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
4864 | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
4865 | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
4866 // Synthesize an event position because we don't get one from
4867 // WM_MOUSELEAVE.
4868 LPARAM pos = lParamToClient(::GetMessagePos());
4869 DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, PR_FALSE,
4870 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4872 break;
4873 #endif
4875 case WM_CONTEXTMENU:
4877 // if the context menu is brought up from the keyboard, |lParam|
4878 // will be -1.
4879 LPARAM pos;
4880 PRBool contextMenukey = PR_FALSE;
4881 if (lParam == -1)
4883 contextMenukey = PR_TRUE;
4884 pos = lParamToClient(GetMessagePos());
4886 else
4888 pos = lParamToClient(lParam);
4891 result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey,
4892 contextMenukey ?
4893 nsMouseEvent::eLeftButton :
4894 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4896 break;
4898 case WM_LBUTTONDBLCLK:
4899 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4900 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4901 break;
4903 case WM_MBUTTONDOWN:
4905 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4906 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4907 DispatchPendingEvents();
4909 break;
4911 case WM_MBUTTONUP:
4912 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4913 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4914 DispatchPendingEvents();
4915 break;
4917 case WM_MBUTTONDBLCLK:
4918 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4919 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4920 break;
4922 case WM_RBUTTONDOWN:
4924 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4925 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4926 DispatchPendingEvents();
4928 break;
4930 case WM_RBUTTONUP:
4931 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4932 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4933 DispatchPendingEvents();
4934 break;
4936 case WM_RBUTTONDBLCLK:
4937 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4938 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4939 break;
4941 case WM_NCRBUTTONDOWN:
4942 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam),
4943 PR_FALSE, nsMouseEvent::eRightButton,
4944 MOUSE_INPUT_SOURCE());
4945 DispatchPendingEvents();
4946 break;
4948 case WM_NCRBUTTONUP:
4949 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam),
4950 PR_FALSE, nsMouseEvent::eRightButton,
4951 MOUSE_INPUT_SOURCE());
4952 DispatchPendingEvents();
4953 break;
4955 case WM_NCRBUTTONDBLCLK:
4956 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam),
4957 PR_FALSE, nsMouseEvent::eRightButton,
4958 MOUSE_INPUT_SOURCE());
4960 case WM_APPCOMMAND:
4962 PRUint32 appCommand = GET_APPCOMMAND_LPARAM(lParam);
4964 switch (appCommand)
4966 case APPCOMMAND_BROWSER_BACKWARD:
4967 case APPCOMMAND_BROWSER_FORWARD:
4968 case APPCOMMAND_BROWSER_REFRESH:
4969 case APPCOMMAND_BROWSER_STOP:
4970 case APPCOMMAND_BROWSER_SEARCH:
4971 case APPCOMMAND_BROWSER_FAVORITES:
4972 case APPCOMMAND_BROWSER_HOME:
4973 DispatchCommandEvent(appCommand);
4974 // tell the driver that we handled the event
4975 *aRetValue = 1;
4976 result = PR_TRUE;
4977 break;
4979 // default = PR_FALSE - tell the driver that the event was not handled
4981 break;
4983 case WM_HSCROLL:
4984 case WM_VSCROLL:
4985 *aRetValue = 0;
4986 result = OnScroll(msg, wParam, lParam);
4987 break;
4989 // The WM_ACTIVATE event is fired when a window is raised or lowered,
4990 // and the loword of wParam specifies which. But we don't want to tell
4991 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
4992 // events are fired. Instead, set either the sJustGotActivate or
4993 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
4994 // events once the focus events arrive.
4995 case WM_ACTIVATE:
4996 if (mEventCallback) {
4997 PRInt32 fActive = LOWORD(wParam);
4999 #if defined(WINCE_HAVE_SOFTKB)
5000 if (mIsTopWidgetWindow && sSoftKeyboardState)
5001 nsWindowCE::ToggleSoftKB(mWnd, fActive);
5002 if (nsWindowCE::sShowSIPButton == TRI_FALSE && WA_INACTIVE != fActive) {
5003 HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL );
5004 if (hWndSIPB)
5005 ShowWindow(hWndSIPB, SW_HIDE);
5008 #endif
5010 if (WA_INACTIVE == fActive) {
5011 // when minimizing a window, the deactivation and focus events will
5012 // be fired in the reverse order. Instead, just dispatch
5013 // NS_DEACTIVATE right away.
5014 if (HIWORD(wParam))
5015 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5016 else
5017 sJustGotDeactivate = PR_TRUE;
5018 #ifndef WINCE
5019 if (mIsTopWidgetWindow)
5020 mLastKeyboardLayout = gKbdLayout.GetLayout();
5021 #endif
5023 } else {
5024 StopFlashing();
5026 sJustGotActivate = PR_TRUE;
5027 nsMouseEvent event(PR_TRUE, NS_MOUSE_ACTIVATE, this,
5028 nsMouseEvent::eReal);
5029 InitEvent(event);
5031 event.acceptActivation = PR_TRUE;
5033 PRBool result = DispatchWindowEvent(&event);
5034 #ifndef WINCE
5035 if (event.acceptActivation)
5036 *aRetValue = MA_ACTIVATE;
5037 else
5038 *aRetValue = MA_NOACTIVATE;
5040 if (sSwitchKeyboardLayout && mLastKeyboardLayout)
5041 ActivateKeyboardLayout(mLastKeyboardLayout, 0);
5042 #else
5043 *aRetValue = 0;
5044 #endif
5047 #ifdef WINCE_WINDOWS_MOBILE
5048 if (!gCheckForHTCApi && gHTCApiNavOpen == nsnull) {
5049 gCheckForHTCApi = PR_TRUE;
5051 HINSTANCE library = LoadLibrary(L"HTCAPI.dll");
5052 gHTCApiNavOpen = (HTCApiNavOpen) GetProcAddress(library, "HTCNavOpen");
5053 gHTCApiNavSetMode = (HTCApiNavSetMode) GetProcAddress(library ,"HTCNavSetMode");
5056 if (gHTCApiNavOpen != nsnull) {
5057 gHTCApiNavOpen(mWnd, 1 /* undocumented value */);
5059 if (gHTCApiNavSetMode != nsnull)
5060 gHTCApiNavSetMode ( mWnd, 4);
5061 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5063 #endif
5064 break;
5066 #ifndef WINCE
5067 case WM_MOUSEACTIVATE:
5068 if (mWindowType == eWindowType_popup) {
5069 // a popup with a parent owner should not be activated when clicked
5070 // but should still allow the mouse event to be fired, so the return
5071 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5072 // window, just use default processing so that the window is activated.
5073 HWND owner = ::GetWindow(mWnd, GW_OWNER);
5074 if (owner && owner == ::GetForegroundWindow()) {
5075 *aRetValue = MA_NOACTIVATE;
5076 result = PR_TRUE;
5079 break;
5081 case WM_WINDOWPOSCHANGING:
5083 LPWINDOWPOS info = (LPWINDOWPOS) lParam;
5084 OnWindowPosChanging(info);
5086 break;
5087 #endif
5089 case WM_SETFOCUS:
5090 if (sJustGotActivate) {
5091 result = DispatchFocusToTopLevelWindow(NS_ACTIVATE);
5094 #ifdef ACCESSIBILITY
5095 if (nsWindow::sIsAccessibilityOn) {
5096 // Create it for the first time so that it can start firing events
5097 nsAccessible *rootAccessible = GetRootAccessible();
5099 #endif
5101 #if defined(WINCE_HAVE_SOFTKB)
5103 // On Windows CE, we have a window that overlaps
5104 // the ISP button. In this case, we should always
5105 // try to hide it when we are activated
5107 nsIMEContext IMEContext(mWnd);
5108 // Open the IME
5109 ImmSetOpenStatus(IMEContext.get(), TRUE);
5111 #endif
5112 break;
5114 case WM_KILLFOCUS:
5115 #if defined(WINCE_HAVE_SOFTKB)
5117 nsIMEContext IMEContext(mWnd);
5118 ImmSetOpenStatus(IMEContext.get(), FALSE);
5120 #endif
5121 if (sJustGotDeactivate) {
5122 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5124 break;
5126 case WM_WINDOWPOSCHANGED:
5128 WINDOWPOS *wp = (LPWINDOWPOS)lParam;
5129 OnWindowPosChanged(wp, result);
5131 break;
5133 case WM_SETTINGCHANGE:
5134 #if !defined (WINCE_WINDOWS_MOBILE)
5135 getWheelInfo = PR_TRUE;
5136 #else
5137 switch (wParam) {
5138 case SPI_SETSIPINFO:
5139 case SPI_SETCURRENTIM:
5140 nsWindowCE::OnSoftKbSettingsChange(mWnd);
5141 break;
5142 case SETTINGCHANGE_RESET:
5143 if (mWindowType == eWindowType_invisible) {
5144 // The OS sees to get confused and think that the invisable window
5145 // is in the foreground after an orientation change. By actually
5146 // setting it to the foreground and hiding it, we set it strait.
5147 // See bug 514007 for details.
5148 SetForegroundWindow(mWnd);
5149 ShowWindow(mWnd, SW_HIDE);
5151 break;
5153 #endif
5154 OnSettingsChange(wParam, lParam);
5155 break;
5157 #ifndef WINCE
5158 case WM_INPUTLANGCHANGEREQUEST:
5159 *aRetValue = TRUE;
5160 result = PR_FALSE;
5161 break;
5163 case WM_INPUTLANGCHANGE:
5164 result = OnInputLangChange((HKL)lParam);
5165 break;
5166 #endif // WINCE
5168 case WM_DESTROYCLIPBOARD:
5170 nsIClipboard* clipboard;
5171 nsresult rv = CallGetService(kCClipboardCID, &clipboard);
5172 clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
5173 NS_RELEASE(clipboard);
5175 break;
5177 #ifdef ACCESSIBILITY
5178 case WM_GETOBJECT:
5180 *aRetValue = 0;
5181 if (lParam == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
5182 nsAccessible *rootAccessible = GetRootAccessible(); // Held by a11y cache
5183 if (rootAccessible) {
5184 IAccessible *msaaAccessible = NULL;
5185 rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref
5186 if (msaaAccessible) {
5187 *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref
5188 msaaAccessible->Release(); // release extra addref
5189 result = PR_TRUE; // We handled the WM_GETOBJECT message
5194 #endif
5196 #ifndef WINCE
5197 case WM_SYSCOMMAND:
5198 // prevent Windows from trimming the working set. bug 76831
5199 if (!sTrimOnMinimize && wParam == SC_MINIMIZE) {
5200 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
5201 result = PR_TRUE;
5203 break;
5204 #endif
5207 #ifdef WINCE
5208 case WM_HIBERNATE:
5209 nsMemory::HeapMinimize(PR_TRUE);
5210 break;
5211 #endif
5213 case WM_MOUSEWHEEL:
5214 case WM_MOUSEHWHEEL:
5216 // If OnMouseWheel returns true, the event was forwarded directly to another
5217 // mozilla window message handler (ProcessMessage). In this case the return
5218 // value of the forwarded event is in 'result' which we should return immediately.
5219 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5220 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5221 // we should fall through.
5222 if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue))
5223 return result;
5225 break;
5227 #ifndef WINCE
5228 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5229 case WM_DWMCOMPOSITIONCHANGED:
5230 UpdateNonClientMargins();
5231 BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
5232 DispatchStandardEvent(NS_THEMECHANGED);
5233 UpdateGlass();
5234 Invalidate(PR_FALSE);
5235 break;
5236 #endif
5238 case WM_UPDATEUISTATE:
5240 // If the UI state has changed, fire an event so the UI updates the
5241 // keyboard cues based on the system setting and how the window was
5242 // opened. For example, a dialog opened via a keyboard press on a button
5243 // should enable cues, whereas the same dialog opened via a mouse click of
5244 // the button should not.
5245 PRInt32 action = LOWORD(wParam);
5246 if (action == UIS_SET || action == UIS_CLEAR) {
5247 nsUIStateChangeEvent event(PR_TRUE, NS_UISTATECHANGED, this);
5248 PRInt32 flags = HIWORD(wParam);
5249 if (flags & UISF_HIDEACCEL)
5250 event.showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5251 if (flags & UISF_HIDEFOCUS)
5252 event.showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5253 DispatchWindowEvent(&event);
5256 break;
5259 /* Gesture support events */
5260 case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
5261 // According to MS samples, this must be handled to enable
5262 // rotational support in multi-touch drivers.
5263 result = PR_TRUE;
5264 *aRetValue = TABLET_ROTATE_GESTURE_ENABLE;
5265 break;
5267 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5268 case WM_TOUCH:
5269 result = OnTouch(wParam, lParam);
5270 if (result) {
5271 *aRetValue = 0;
5273 break;
5274 #endif
5276 case WM_GESTURE:
5277 result = OnGesture(wParam, lParam);
5278 break;
5280 case WM_GESTURENOTIFY:
5282 if (mWindowType != eWindowType_invisible &&
5283 mWindowType != eWindowType_plugin &&
5284 mWindowType != eWindowType_toplevel) {
5285 // eWindowType_toplevel is the top level main frame window. Gesture support
5286 // there prevents the user from interacting with the title bar or nc
5287 // areas using a single finger. Java and plugin windows can make their
5288 // own calls.
5289 GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
5290 nsPointWin touchPoint;
5291 touchPoint = gestureinfo->ptsLocation;
5292 touchPoint.ScreenToClient(mWnd);
5293 nsGestureNotifyEvent gestureNotifyEvent(PR_TRUE, NS_GESTURENOTIFY_EVENT_START, this);
5294 gestureNotifyEvent.refPoint = touchPoint;
5295 nsEventStatus status;
5296 DispatchEvent(&gestureNotifyEvent, status);
5297 mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
5298 if (!mTouchWindow)
5299 mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
5301 result = PR_FALSE; //should always bubble to DefWindowProc
5303 break;
5304 #endif // !defined(WINCE)
5306 case WM_CLEAR:
5308 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_DELETE, this);
5309 DispatchWindowEvent(&command);
5310 result = PR_TRUE;
5312 break;
5314 case WM_CUT:
5316 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_CUT, this);
5317 DispatchWindowEvent(&command);
5318 result = PR_TRUE;
5320 break;
5322 case WM_COPY:
5324 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_COPY, this);
5325 DispatchWindowEvent(&command);
5326 result = PR_TRUE;
5328 break;
5330 case WM_PASTE:
5332 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE, this);
5333 DispatchWindowEvent(&command);
5334 result = PR_TRUE;
5336 break;
5338 #ifndef WINCE
5339 case EM_UNDO:
5341 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO, this);
5342 DispatchWindowEvent(&command);
5343 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5344 result = PR_TRUE;
5346 break;
5348 case EM_REDO:
5350 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO, this);
5351 DispatchWindowEvent(&command);
5352 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5353 result = PR_TRUE;
5355 break;
5357 case EM_CANPASTE:
5359 // Support EM_CANPASTE message only when wParam isn't specified or
5360 // is plain text format.
5361 if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
5362 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE,
5363 this, PR_TRUE);
5364 DispatchWindowEvent(&command);
5365 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5366 result = PR_TRUE;
5369 break;
5371 case EM_CANUNDO:
5373 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO,
5374 this, PR_TRUE);
5375 DispatchWindowEvent(&command);
5376 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5377 result = PR_TRUE;
5379 break;
5381 case EM_CANREDO:
5383 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO,
5384 this, PR_TRUE);
5385 DispatchWindowEvent(&command);
5386 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5387 result = PR_TRUE;
5389 break;
5390 #endif
5392 #ifdef WINCE_WINDOWS_MOBILE
5393 //HTC NAVIGATION WHEEL EVENT
5394 case WM_HTCNAV:
5396 int distance = wParam & 0x000000FF;
5397 if ( (wParam & 0x000000100) != 0) // Counter Clockwise
5398 distance *= -1;
5399 if (OnMouseWheel(WM_MOUSEWHEEL, MAKEWPARAM(0, distance),
5400 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN) / 2,
5401 GetSystemMetrics(SM_CYSCREEN) / 2),
5402 getWheelInfo, result, aRetValue))
5403 return result;
5405 break;
5406 #endif
5408 default:
5410 #ifdef NS_ENABLE_TSF
5411 if (msg == WM_USER_TSF_TEXTCHANGE) {
5412 nsTextStore::OnTextChangeMsg();
5414 #endif //NS_ENABLE_TSF
5415 #if defined(HEAP_DUMP_EVENT)
5416 if (msg == GetHeapMsg()) {
5417 HeapDump(msg, wParam, lParam);
5418 result = PR_TRUE;
5420 #endif
5421 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5422 if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
5423 SetHasTaskbarIconBeenCreated();
5424 #endif
5425 #ifdef MOZ_IPC
5426 if (msg == sOOPPPluginFocusEvent) {
5427 if (wParam == 1) {
5428 // With OOPP, the plugin window exists in another process and is a child of
5429 // this window. This window is a placeholder plugin window for the dom. We
5430 // receive this event when the child window receives focus. (sent from
5431 // PluginInstanceParent.cpp)
5432 ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
5433 } else {
5434 // WM_KILLFOCUS was received by the child process.
5435 if (sJustGotDeactivate) {
5436 DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5440 #endif
5442 break;
5445 //*aRetValue = result;
5446 if (mWnd) {
5447 return result;
5449 else {
5450 //Events which caused mWnd destruction and aren't consumed
5451 //will crash during the Windows default processing.
5452 return PR_TRUE;
5456 /**************************************************************
5458 * SECTION: Broadcast messaging
5460 * Broadcast messages to all windows.
5462 **************************************************************/
5464 // Enumerate all child windows sending aMsg to each of them
5465 BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg)
5467 WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
5468 if (winProc == &nsWindow::WindowProc) {
5469 // it's one of our windows so go ahead and send a message to it
5470 ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0);
5472 return TRUE;
5475 // Enumerate all top level windows specifying that the children of each
5476 // top level window should be enumerated. Do *not* send the message to
5477 // each top level window since it is assumed that the toolkit will send
5478 // aMsg to them directly.
5479 BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg)
5481 // Iterate each of aTopWindows child windows sending the aMsg
5482 // to each of them.
5483 #if !defined(WINCE)
5484 ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5485 #else
5486 nsWindowCE::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5487 #endif
5488 return TRUE;
5491 // This method is called from nsToolkit::WindowProc to forward global
5492 // messages which need to be dispatched to all child windows.
5493 void nsWindow::GlobalMsgWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
5495 switch (msg) {
5496 case WM_SYSCOLORCHANGE:
5497 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5498 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5499 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5500 // all child windows as well. When running in an embedded application
5501 // we may not receive a WM_SYSCOLORCHANGE message because the top
5502 // level window is owned by the embeddor.
5503 // System color changes are posted to top-level windows only.
5504 // The NS_SYSCOLORCHANGE must be dispatched to all child
5505 // windows as well.
5506 #if !defined(WINCE)
5507 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, msg);
5508 #endif
5509 break;
5513 /**************************************************************
5515 * SECTION: Event processing helpers
5517 * Special processing for certain event types and
5518 * synthesized events.
5520 **************************************************************/
5522 PRInt32
5523 nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
5525 // Calculations are done in screen coords
5526 RECT winRect;
5527 GetWindowRect(mWnd, &winRect);
5529 // hit return constants:
5530 // HTBORDER - non-resizable border
5531 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5532 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5533 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5534 // HTCAPTION - general title bar area
5535 // HTCLIENT - area considered the client
5536 // HTCLOSE - hovering over the close button
5537 // HTMAXBUTTON - maximize button
5538 // HTMINBUTTON - minimize button
5540 PRInt32 testResult = HTCLIENT;
5542 PRBool top = PR_FALSE;
5543 PRBool bottom = PR_FALSE;
5544 PRBool left = PR_FALSE;
5545 PRBool right = PR_FALSE;
5547 if (my >= winRect.top && my <=
5548 (winRect.top + mVertResizeMargin + (mCaptionHeight - mNonClientOffset.top)))
5549 top = PR_TRUE;
5550 else if (my <= winRect.bottom && my >= (winRect.bottom - mVertResizeMargin))
5551 bottom = PR_TRUE;
5553 if (mx >= winRect.left && mx <= (winRect.left + mHorResizeMargin))
5554 left = PR_TRUE;
5555 else if (mx <= winRect.right && mx >= (winRect.right - mHorResizeMargin))
5556 right = PR_TRUE;
5558 if (top) {
5559 testResult = HTTOP;
5560 if (left)
5561 testResult = HTTOPLEFT;
5562 else if (right)
5563 testResult = HTTOPRIGHT;
5564 } else if (bottom) {
5565 testResult = HTBOTTOM;
5566 if (left)
5567 testResult = HTBOTTOMLEFT;
5568 else if (right)
5569 testResult = HTBOTTOMRIGHT;
5570 } else {
5571 if (left)
5572 testResult = HTLEFT;
5573 if (right)
5574 testResult = HTRIGHT;
5577 PRBool contentOverlap = PR_TRUE;
5579 if (mSizeMode == nsSizeMode_Maximized) {
5580 // There's no HTTOP in maximized state (bug 575493)
5581 if (testResult == HTTOP) {
5582 testResult = HTCAPTION;
5584 } else {
5585 PRInt32 leftMargin = mNonClientMargins.left == -1 ? mHorResizeMargin : mNonClientMargins.left;
5586 PRInt32 rightMargin = mNonClientMargins.right == -1 ? mHorResizeMargin : mNonClientMargins.right;
5587 PRInt32 topMargin = mNonClientMargins.top == -1 ? mVertResizeMargin : mNonClientMargins.top;
5588 PRInt32 bottomMargin = mNonClientMargins.bottom == -1 ? mVertResizeMargin : mNonClientMargins.bottom;
5590 contentOverlap = mx >= winRect.left + leftMargin &&
5591 mx <= winRect.right - rightMargin &&
5592 my >= winRect.top + topMargin &&
5593 my <= winRect.bottom - bottomMargin;
5596 if (!mIsInMouseCapture &&
5597 contentOverlap &&
5598 (testResult == HTCLIENT ||
5599 testResult == HTTOP ||
5600 testResult == HTTOPLEFT ||
5601 testResult == HTCAPTION)) {
5602 LPARAM lParam = MAKELPARAM(mx, my);
5603 LPARAM lParamClient = lParamToClient(lParam);
5604 PRBool result = DispatchMouseEvent(NS_MOUSE_MOZHITTEST, 0, lParamClient,
5605 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5606 if (result) {
5607 // The mouse is over a blank area
5608 testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
5610 if (!mExitToNonClientArea) {
5611 // The first time the mouse pointer goes from client area to non-client area,
5612 // we don't want to miss that movement so we can interpret mouseout input.
5613 ::SendMessage(mWnd, WM_MOUSEMOVE, 0, lParamClient);
5614 mExitToNonClientArea = PR_TRUE;
5616 } else {
5617 // There's content over the mouse pointer. Set HTCLIENT
5618 // to possibly override a resizer border.
5619 testResult = HTCLIENT;
5623 return testResult;
5627 #ifndef WINCE
5628 void nsWindow::PostSleepWakeNotification(const char* aNotification)
5630 nsCOMPtr<nsIObserverService> observerService =
5631 mozilla::services::GetObserverService();
5632 if (observerService)
5633 observerService->NotifyObservers(nsnull, aNotification, nsnull);
5635 #endif
5637 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, PRBool *aEventDispatched)
5639 NS_PRECONDITION(aMsg.message == WM_CHAR || aMsg.message == WM_SYSCHAR,
5640 "message is not keydown event");
5641 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5642 ("%s charCode=%d scanCode=%d\n",
5643 aMsg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
5644 aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF));
5646 // These must be checked here too as a lone WM_CHAR could be received
5647 // if a child window didn't handle it (for example Alt+Space in a content window)
5648 nsModifierKeyState modKeyState;
5649 return OnChar(aMsg, modKeyState, aEventDispatched);
5652 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, PRBool *aEventDispatched)
5654 NS_PRECONDITION(aMsg.message == WM_KEYUP || aMsg.message == WM_SYSKEYUP,
5655 "message is not keydown event");
5656 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5657 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5658 "WM_SYSKEYUP" : "WM_KEYUP", aMsg.wParam));
5660 nsModifierKeyState modKeyState;
5662 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5663 // scan code. However, this breaks Alt+Num pad input.
5664 // MSDN states the following:
5665 // Typically, ToAscii performs the translation based on the
5666 // virtual-key code. In some cases, however, bit 15 of the
5667 // uScanCode parameter may be used to distinguish between a key
5668 // press and a key release. The scan code is used for
5669 // translating ALT+number key combinations.
5671 // ignore [shift+]alt+space so the OS can handle it
5672 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5673 IS_VK_DOWN(NS_VK_SPACE)) {
5674 return FALSE;
5677 if (!nsIMM32Handler::IsComposingOn(this) &&
5678 (aMsg.message != WM_KEYUP || aMsg.wParam != VK_MENU)) {
5679 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5680 // This helps avoid triggering the menu bar for ALT key accelerators used in
5681 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5682 // to switch back to Mozilla in Windows 95 and Windows 98
5683 return OnKeyUp(aMsg, modKeyState, aEventDispatched);
5686 return 0;
5689 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
5690 PRBool *aEventDispatched)
5692 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5693 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5694 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg.wParam));
5695 NS_PRECONDITION(aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN,
5696 "message is not keydown event");
5698 nsModifierKeyState modKeyState;
5700 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
5701 // scan code. However, this breaks Alt+Num pad input.
5702 // MSDN states the following:
5703 // Typically, ToAscii performs the translation based on the
5704 // virtual-key code. In some cases, however, bit 15 of the
5705 // uScanCode parameter may be used to distinguish between a key
5706 // press and a key release. The scan code is used for
5707 // translating ALT+number key combinations.
5709 // ignore [shift+]alt+space so the OS can handle it
5710 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5711 IS_VK_DOWN(NS_VK_SPACE))
5712 return FALSE;
5714 LRESULT result = 0;
5715 if (modKeyState.mIsAltDown && nsIMM32Handler::IsStatusChanged()) {
5716 nsIMM32Handler::NotifyEndStatusChange();
5717 } else if (!nsIMM32Handler::IsComposingOn(this)) {
5718 result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nsnull);
5721 #ifndef WINCE
5722 if (aMsg.wParam == VK_MENU ||
5723 (aMsg.wParam == VK_F10 && !modKeyState.mIsShiftDown)) {
5724 // We need to let Windows handle this keypress,
5725 // by returning PR_FALSE, if there's a native menu
5726 // bar somewhere in our containing window hierarchy.
5727 // Otherwise we handle the keypress and don't pass
5728 // it on to Windows, by returning PR_TRUE.
5729 PRBool hasNativeMenu = PR_FALSE;
5730 HWND hWnd = mWnd;
5731 while (hWnd) {
5732 if (::GetMenu(hWnd)) {
5733 hasNativeMenu = PR_TRUE;
5734 break;
5736 hWnd = ::GetParent(hWnd);
5738 result = !hasNativeMenu;
5740 #endif
5742 return result;
5745 nsresult
5746 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
5747 PRInt32 aNativeKeyCode,
5748 PRUint32 aModifierFlags,
5749 const nsAString& aCharacters,
5750 const nsAString& aUnmodifiedCharacters)
5752 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
5753 nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
5754 HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
5755 if (loadedLayout == NULL)
5756 return NS_ERROR_NOT_AVAILABLE;
5758 // Setup clean key state and load desired layout
5759 BYTE originalKbdState[256];
5760 ::GetKeyboardState(originalKbdState);
5761 BYTE kbdState[256];
5762 memset(kbdState, 0, sizeof(kbdState));
5763 // This changes the state of the keyboard for the current thread only,
5764 // and we'll restore it soon, so this should be OK.
5765 ::SetKeyboardState(kbdState);
5766 HKL oldLayout = gKbdLayout.GetLayout();
5767 gKbdLayout.LoadLayout(loadedLayout);
5769 nsAutoTArray<KeyPair,10> keySequence;
5770 SetupKeyModifiersSequence(&keySequence, aModifierFlags);
5771 NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
5772 "Native VK key code out of range");
5773 keySequence.AppendElement(KeyPair(aNativeKeyCode, 0));
5775 // Simulate the pressing of each modifier key and then the real key
5776 for (PRUint32 i = 0; i < keySequence.Length(); ++i) {
5777 PRUint8 key = keySequence[i].mGeneral;
5778 PRUint8 keySpecific = keySequence[i].mSpecific;
5779 kbdState[key] = 0x81; // key is down and toggled on if appropriate
5780 if (keySpecific) {
5781 kbdState[keySpecific] = 0x81;
5783 ::SetKeyboardState(kbdState);
5784 nsModifierKeyState modKeyState;
5785 MSG msg = InitMSG(WM_KEYDOWN, key, 0);
5786 if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
5787 UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
5788 gKbdLayout.GetLayout());
5789 nsFakeCharMessage fakeMsg = { aCharacters.CharAt(0), scanCode };
5790 OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
5791 } else {
5792 OnKeyDown(msg, modKeyState, nsnull, nsnull);
5795 for (PRUint32 i = keySequence.Length(); i > 0; --i) {
5796 PRUint8 key = keySequence[i - 1].mGeneral;
5797 PRUint8 keySpecific = keySequence[i - 1].mSpecific;
5798 kbdState[key] = 0; // key is up and toggled off if appropriate
5799 if (keySpecific) {
5800 kbdState[keySpecific] = 0;
5802 ::SetKeyboardState(kbdState);
5803 nsModifierKeyState modKeyState;
5804 MSG msg = InitMSG(WM_KEYUP, key, 0);
5805 OnKeyUp(msg, modKeyState, nsnull);
5808 // Restore old key state and layout
5809 ::SetKeyboardState(originalKbdState);
5810 gKbdLayout.LoadLayout(oldLayout);
5812 UnloadKeyboardLayout(loadedLayout);
5813 return NS_OK;
5814 #else //XXX: is there another way to do this?
5815 return NS_ERROR_NOT_IMPLEMENTED;
5816 #endif
5819 nsresult
5820 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
5821 PRUint32 aNativeMessage,
5822 PRUint32 aModifierFlags)
5824 #ifndef WINCE // I don't think WINCE supports SendInput
5825 RECT r;
5826 ::GetWindowRect(mWnd, &r);
5827 ::SetCursorPos(r.left + aPoint.x, r.top + aPoint.y);
5829 INPUT input;
5830 memset(&input, 0, sizeof(input));
5832 input.type = INPUT_MOUSE;
5833 input.mi.dwFlags = aNativeMessage;
5834 ::SendInput(1, &input, sizeof(INPUT));
5836 return NS_OK;
5837 #else
5838 return NS_ERROR_NOT_IMPLEMENTED;
5839 #endif
5842 /**************************************************************
5844 * SECTION: OnXXX message handlers
5846 * For message handlers that need to be broken out or
5847 * implemented in specific platform code.
5849 **************************************************************/
5851 BOOL nsWindow::OnInputLangChange(HKL aHKL)
5853 #ifdef KE_DEBUG
5854 printf("OnInputLanguageChange\n");
5855 #endif
5857 #ifndef WINCE
5858 gKbdLayout.LoadLayout(aHKL);
5859 #endif
5861 return PR_FALSE; // always pass to child window
5864 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5865 void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, PRBool& result)
5867 if (wp == nsnull)
5868 return;
5870 #ifdef WINSTATE_DEBUG_OUTPUT
5871 if (mWnd == GetTopLevelHWND(mWnd))
5872 printf("*** OnWindowPosChanged: [ top] ");
5873 else
5874 printf("*** OnWindowPosChanged: [child] ");
5875 printf("WINDOWPOS flags:");
5876 if (wp->flags & SWP_FRAMECHANGED)
5877 printf("SWP_FRAMECHANGED ");
5878 if (wp->flags & SWP_SHOWWINDOW)
5879 printf("SWP_SHOWWINDOW ");
5880 if (wp->flags & SWP_NOSIZE)
5881 printf("SWP_NOSIZE ");
5882 if (wp->flags & SWP_HIDEWINDOW)
5883 printf("SWP_HIDEWINDOW ");
5884 printf("\n");
5885 #endif
5887 // Handle window size mode changes
5888 if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
5889 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
5891 WINDOWPLACEMENT pl;
5892 pl.length = sizeof(pl);
5893 ::GetWindowPlacement(mWnd, &pl);
5895 if (pl.showCmd == SW_SHOWMAXIMIZED)
5896 event.mSizeMode = nsSizeMode_Maximized;
5897 else if (pl.showCmd == SW_SHOWMINIMIZED)
5898 event.mSizeMode = nsSizeMode_Minimized;
5899 else
5900 event.mSizeMode = nsSizeMode_Normal;
5902 // Windows has just changed the size mode of this window. The following
5903 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
5904 // set the min/max window state again or for nsSizeMode_Normal, call
5905 // SetWindow with a parameter of SW_RESTORE. There's no need however as
5906 // this window's mode has already changed. Updating mSizeMode here
5907 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
5908 // to window docking. (bug 489258)
5909 mSizeMode = event.mSizeMode;
5911 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
5912 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
5913 // prevents the working set from being trimmed but keeps the window active.
5914 // After the window is minimized, we need to do some touch up work on the
5915 // active window. (bugs 76831 & 499816)
5916 if (!sTrimOnMinimize && nsSizeMode_Minimized == event.mSizeMode)
5917 ActivateOtherWindowHelper(mWnd);
5919 #ifdef WINSTATE_DEBUG_OUTPUT
5920 switch (mSizeMode) {
5921 case nsSizeMode_Normal:
5922 printf("*** mSizeMode: nsSizeMode_Normal\n");
5923 break;
5924 case nsSizeMode_Minimized:
5925 printf("*** mSizeMode: nsSizeMode_Minimized\n");
5926 break;
5927 case nsSizeMode_Maximized:
5928 printf("*** mSizeMode: nsSizeMode_Maximized\n");
5929 break;
5930 default:
5931 printf("*** mSizeMode: ??????\n");
5932 break;
5934 #endif
5936 InitEvent(event);
5938 result = DispatchWindowEvent(&event);
5940 // Skip window size change events below on minimization.
5941 if (mSizeMode == nsSizeMode_Minimized)
5942 return;
5945 // Handle window size changes
5946 if (0 == (wp->flags & SWP_NOSIZE)) {
5947 RECT r;
5948 PRInt32 newWidth, newHeight;
5950 ::GetWindowRect(mWnd, &r);
5952 newWidth = r.right - r.left;
5953 newHeight = r.bottom - r.top;
5954 nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
5956 #ifdef MOZ_XUL
5957 if (eTransparencyTransparent == mTransparencyMode)
5958 ResizeTranslucentWindow(newWidth, newHeight);
5959 #endif
5961 if (newWidth > mLastSize.width)
5963 RECT drect;
5965 // getting wider
5966 drect.left = wp->x + mLastSize.width;
5967 drect.top = wp->y;
5968 drect.right = drect.left + (newWidth - mLastSize.width);
5969 drect.bottom = drect.top + newHeight;
5971 ::RedrawWindow(mWnd, &drect, NULL,
5972 RDW_INVALIDATE |
5973 RDW_NOERASE |
5974 RDW_NOINTERNALPAINT |
5975 RDW_ERASENOW |
5976 RDW_ALLCHILDREN);
5978 if (newHeight > mLastSize.height)
5980 RECT drect;
5982 // getting taller
5983 drect.left = wp->x;
5984 drect.top = wp->y + mLastSize.height;
5985 drect.right = drect.left + newWidth;
5986 drect.bottom = drect.top + (newHeight - mLastSize.height);
5988 ::RedrawWindow(mWnd, &drect, NULL,
5989 RDW_INVALIDATE |
5990 RDW_NOERASE |
5991 RDW_NOINTERNALPAINT |
5992 RDW_ERASENOW |
5993 RDW_ALLCHILDREN);
5996 mBounds.width = newWidth;
5997 mBounds.height = newHeight;
5998 mLastSize.width = newWidth;
5999 mLastSize.height = newHeight;
6001 #ifdef WINSTATE_DEBUG_OUTPUT
6002 printf("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, newWidth, newHeight);
6003 #endif
6005 // If a maximized window is resized, recalculate the non-client margins and
6006 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
6007 // work properly.
6008 if (mSizeMode == nsSizeMode_Maximized) {
6009 if (UpdateNonClientMargins(nsSizeMode_Maximized, PR_TRUE)) {
6010 // gecko resize event already sent by UpdateNonClientMargins.
6011 result = PR_TRUE;
6012 return;
6016 // Recalculate the width and height based on the client area for gecko events.
6017 if (::GetClientRect(mWnd, &r)) {
6018 rect.width = r.right - r.left;
6019 rect.height = r.bottom - r.top;
6022 // Send a gecko resize event
6023 result = OnResize(rect);
6027 // static
6028 void nsWindow::ActivateOtherWindowHelper(HWND aWnd)
6030 // Find the next window that is enabled, visible, and not minimized.
6031 HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT);
6032 while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) ||
6033 ::IsIconic(hwndBelow))) {
6034 hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT);
6037 // Push ourselves to the bottom of the stack, then activate the
6038 // next window.
6039 ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0,
6040 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
6041 if (hwndBelow)
6042 ::SetForegroundWindow(hwndBelow);
6044 // Play the minimize sound while we're here, since that is also
6045 // forgotten when we use SW_SHOWMINIMIZED.
6046 ::PlaySoundW(L"Minimize", nsnull, SND_ALIAS | SND_NODEFAULT | SND_ASYNC);
6048 #endif // !defined(WINCE)
6050 #if !defined(WINCE)
6051 void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info)
6053 // Update non-client margins if the frame size is changing, and let the
6054 // browser know we are changing size modes, so alternative css can kick in.
6055 // If we're going into fullscreen mode, ignore this, since it'll reset
6056 // margins to normal mode.
6057 if (info->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
6058 WINDOWPLACEMENT pl;
6059 pl.length = sizeof(pl);
6060 ::GetWindowPlacement(mWnd, &pl);
6061 PRInt32 sizeMode;
6062 if (pl.showCmd == SW_SHOWMAXIMIZED)
6063 sizeMode = nsSizeMode_Maximized;
6064 else if (pl.showCmd == SW_SHOWMINIMIZED)
6065 sizeMode = nsSizeMode_Minimized;
6066 else
6067 sizeMode = nsSizeMode_Normal;
6069 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
6071 InitEvent(event);
6072 event.mSizeMode = static_cast<nsSizeMode>(sizeMode);
6073 DispatchWindowEvent(&event);
6075 UpdateNonClientMargins(sizeMode, PR_FALSE);
6078 // enforce local z-order rules
6079 if (!(info->flags & SWP_NOZORDER)) {
6080 HWND hwndAfter = info->hwndInsertAfter;
6082 nsZLevelEvent event(PR_TRUE, NS_SETZLEVEL, this);
6083 nsWindow *aboveWindow = 0;
6085 InitEvent(event);
6087 if (hwndAfter == HWND_BOTTOM)
6088 event.mPlacement = nsWindowZBottom;
6089 else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
6090 event.mPlacement = nsWindowZTop;
6091 else {
6092 event.mPlacement = nsWindowZRelative;
6093 aboveWindow = GetNSWindowPtr(hwndAfter);
6095 event.mReqBelow = aboveWindow;
6096 event.mActualBelow = nsnull;
6098 event.mImmediate = PR_FALSE;
6099 event.mAdjusted = PR_FALSE;
6100 DispatchWindowEvent(&event);
6102 if (event.mAdjusted) {
6103 if (event.mPlacement == nsWindowZBottom)
6104 info->hwndInsertAfter = HWND_BOTTOM;
6105 else if (event.mPlacement == nsWindowZTop)
6106 info->hwndInsertAfter = HWND_TOP;
6107 else {
6108 info->hwndInsertAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
6111 NS_IF_RELEASE(event.mActualBelow);
6113 // prevent rude external programs from making hidden window visible
6114 if (mWindowType == eWindowType_invisible)
6115 info->flags &= ~SWP_SHOWWINDOW;
6117 #endif
6119 void nsWindow::UserActivity()
6121 // Check if we have the idle service, if not we try to get it.
6122 if (!mIdleService) {
6123 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
6126 // Check that we now have the idle service.
6127 if (mIdleService) {
6128 mIdleService->ResetIdleTimeOut();
6132 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6133 PRBool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam)
6135 PRUint32 cInputs = LOWORD(wParam);
6136 PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
6138 if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) {
6139 for (PRUint32 i = 0; i < cInputs; i++) {
6140 PRUint32 msg;
6141 if (pInputs[i].dwFlags & TOUCHEVENTF_MOVE) {
6142 msg = NS_MOZTOUCH_MOVE;
6143 } else if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) {
6144 msg = NS_MOZTOUCH_DOWN;
6145 } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) {
6146 msg = NS_MOZTOUCH_UP;
6147 } else {
6148 continue;
6151 nsPointWin touchPoint;
6152 touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
6153 touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
6154 touchPoint.ScreenToClient(mWnd);
6156 nsMozTouchEvent touchEvent(PR_TRUE, msg, this, pInputs[i].dwID);
6157 touchEvent.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6158 touchEvent.refPoint = touchPoint;
6160 nsEventStatus status;
6161 DispatchEvent(&touchEvent, status);
6165 delete [] pInputs;
6166 mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam);
6167 return PR_TRUE;
6169 #endif
6171 // Gesture event processing. Handles WM_GESTURE events.
6172 #if !defined(WINCE)
6173 PRBool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
6175 // Treatment for pan events which translate into scroll events:
6176 if (mGesture.IsPanEvent(lParam)) {
6177 nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
6179 if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
6180 return PR_FALSE; // ignore
6182 nsEventStatus status;
6184 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6185 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6186 event.isMeta = PR_FALSE;
6187 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6188 event.button = 0;
6189 event.time = ::GetMessageTime();
6190 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6192 PRBool endFeedback = PR_TRUE;
6194 PRInt32 scrollOverflowX = 0;
6195 PRInt32 scrollOverflowY = 0;
6197 if (mGesture.PanDeltaToPixelScrollX(event)) {
6198 DispatchEvent(&event, status);
6199 scrollOverflowX = event.scrollOverflow;
6202 if (mGesture.PanDeltaToPixelScrollY(event)) {
6203 DispatchEvent(&event, status);
6204 scrollOverflowY = event.scrollOverflow;
6207 if (mDisplayPanFeedback) {
6208 mGesture.UpdatePanFeedbackX(mWnd, scrollOverflowX, endFeedback);
6209 mGesture.UpdatePanFeedbackY(mWnd, scrollOverflowY, endFeedback);
6210 mGesture.PanFeedbackFinalize(mWnd, endFeedback);
6213 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6215 return PR_TRUE;
6218 // Other gestures translate into simple gesture events:
6219 nsSimpleGestureEvent event(PR_TRUE, 0, this, 0, 0.0);
6220 if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) {
6221 return PR_FALSE; // fall through to DefWndProc
6224 // Polish up and send off the new event
6225 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6226 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6227 event.isMeta = PR_FALSE;
6228 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6229 event.button = 0;
6230 event.time = ::GetMessageTime();
6231 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6233 nsEventStatus status;
6234 DispatchEvent(&event, status);
6235 if (status == nsEventStatus_eIgnore) {
6236 return PR_FALSE; // Ignored, fall through
6239 // Only close this if we process and return true.
6240 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6242 return PR_TRUE; // Handled
6244 #endif // !defined(WINCE)
6246 #if !defined(WINCE)
6247 PRUint16 nsWindow::GetMouseInputSource()
6249 PRUint16 inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE;
6250 LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
6251 if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
6252 inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ?
6253 nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN;
6255 return inputSource;
6257 #endif
6259 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6260 * within the message case block. If returning true result should be returned
6261 * immediately (no more processing).
6263 PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue)
6265 // Handle both flavors of mouse wheel events.
6266 static int iDeltaPerLine, iDeltaPerChar;
6267 static ULONG ulScrollLines, ulScrollChars = 1;
6268 static int currentVDelta, currentHDelta;
6269 static HWND currentWindow = 0;
6271 PRBool isVertical = msg == WM_MOUSEWHEEL;
6273 // Get mouse wheel metrics (but only once).
6274 if (getWheelInfo) {
6275 getWheelInfo = PR_FALSE;
6277 SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
6279 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6280 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6282 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6283 // the mouse driver wants a page scroll. The docs state that
6284 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6285 // since some mouse drivers use an arbitrary large number instead,
6286 // we have to handle that as well.
6288 iDeltaPerLine = 0;
6289 if (ulScrollLines) {
6290 if (ulScrollLines <= WHEEL_DELTA) {
6291 iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
6292 } else {
6293 ulScrollLines = WHEEL_PAGESCROLL;
6297 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
6298 &ulScrollChars, 0)) {
6299 // Note that we may always fail to get the value before Win Vista.
6300 ulScrollChars = 1;
6303 iDeltaPerChar = 0;
6304 if (ulScrollChars) {
6305 if (ulScrollChars <= WHEEL_DELTA) {
6306 iDeltaPerChar = WHEEL_DELTA / ulScrollChars;
6307 } else {
6308 ulScrollChars = WHEEL_PAGESCROLL;
6313 if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) ||
6314 (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar))
6315 return PR_FALSE; // break
6317 // The mousewheel event will be dispatched to the toplevel
6318 // window. We need to give it to the child window
6319 PRBool quit;
6320 if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit))
6321 return quit; // return immediately if its not our window
6323 // We should cancel the surplus delta if the current window is not
6324 // same as previous.
6325 if (currentWindow != mWnd) {
6326 currentVDelta = 0;
6327 currentHDelta = 0;
6328 currentWindow = mWnd;
6331 nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
6332 scrollEvent.delta = 0;
6333 if (isVertical) {
6334 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
6335 if (ulScrollLines == WHEEL_PAGESCROLL) {
6336 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6337 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1;
6338 } else {
6339 currentVDelta -= (short) HIWORD (wParam);
6340 if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
6341 scrollEvent.delta = currentVDelta / iDeltaPerLine;
6342 currentVDelta %= iDeltaPerLine;
6345 } else {
6346 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
6347 if (ulScrollChars == WHEEL_PAGESCROLL) {
6348 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6349 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1;
6350 } else {
6351 currentHDelta += (short) HIWORD (wParam);
6352 if (PR_ABS(currentHDelta) >= iDeltaPerChar) {
6353 scrollEvent.delta = currentHDelta / iDeltaPerChar;
6354 currentHDelta %= iDeltaPerChar;
6359 if (!scrollEvent.delta) {
6360 // We store the wheel delta, and it will be used next wheel message, so,
6361 // we consume this message actually. We shouldn't call next wndproc.
6362 result = PR_TRUE;
6363 return PR_FALSE; // break
6366 #ifdef MOZ_IPC
6367 // The event may go to a plug-in which already dispatched this message.
6368 // Then, the event can cause deadlock. We should unlock the sender here.
6369 ::ReplyMessage(isVertical ? 0 : TRUE);
6370 #endif
6372 scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6373 scrollEvent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6374 scrollEvent.isMeta = PR_FALSE;
6375 scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT);
6376 InitEvent(scrollEvent);
6377 if (nsnull != mEventCallback) {
6378 result = DispatchWindowEvent(&scrollEvent);
6380 // Note that we should return zero if we process WM_MOUSEWHEEL.
6381 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6383 if (result)
6384 *aRetValue = isVertical ? 0 : TRUE;
6386 return PR_FALSE; // break;
6389 static PRBool
6390 StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,
6391 const PRUnichar* aChars2, const PRUint32 aNumChars2)
6393 if (aNumChars1 != aNumChars2)
6394 return PR_FALSE;
6396 nsCaseInsensitiveStringComparator comp;
6397 return comp(aChars1, aChars2, aNumChars1) == 0;
6400 UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
6402 #ifndef WINCE
6403 switch (aNativeKeyCode) {
6404 case VK_OEM_1: return NS_VK_SEMICOLON; // 0xBA, For the US standard keyboard, the ';:' key
6405 case VK_OEM_PLUS: return NS_VK_ADD; // 0xBB, For any country/region, the '+' key
6406 case VK_OEM_MINUS: return NS_VK_SUBTRACT; // 0xBD, For any country/region, the '-' key
6408 #endif
6410 return aNativeKeyCode;
6414 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6415 * WM_CHAR messages for processing. During testing we don't want to
6416 * mess with the real message queue. Instead we pass a
6417 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6418 * that as if it was in the message queue, and refrain from actually
6419 * looking at or touching the message queue.
6421 LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
6422 nsModifierKeyState &aModKeyState,
6423 PRBool *aEventDispatched,
6424 nsFakeCharMessage* aFakeCharMessage)
6426 UINT virtualKeyCode = aMsg.wParam;
6428 #ifndef WINCE
6429 gKbdLayout.OnKeyDown (virtualKeyCode);
6430 #endif
6432 // Use only DOMKeyCode for XP processing.
6433 // Use aVirtualKeyCode for gKbdLayout and native processing.
6434 UINT DOMKeyCode = nsIMM32Handler::IsComposingOn(this) ?
6435 virtualKeyCode : MapFromNativeToDOM(virtualKeyCode);
6437 #ifdef DEBUG
6438 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6439 #endif
6441 PRBool noDefault =
6442 DispatchKeyEvent(NS_KEY_DOWN, 0, nsnull, DOMKeyCode, &aMsg, aModKeyState);
6443 if (aEventDispatched)
6444 *aEventDispatched = PR_TRUE;
6446 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6447 // for almost all keys
6448 switch (DOMKeyCode) {
6449 case NS_VK_SHIFT:
6450 case NS_VK_CONTROL:
6451 case NS_VK_ALT:
6452 case NS_VK_CAPS_LOCK:
6453 case NS_VK_NUM_LOCK:
6454 case NS_VK_SCROLL_LOCK: return noDefault;
6457 PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
6458 MSG msg;
6459 BOOL gotMsg = aFakeCharMessage ||
6460 ::PeekMessageW(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6461 // Enter and backspace are always handled here to avoid for example the
6462 // confusion between ctrl-enter and ctrl-J.
6463 if (DOMKeyCode == NS_VK_RETURN || DOMKeyCode == NS_VK_BACK ||
6464 ((aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)
6465 #ifdef WINCE
6467 #else
6468 && !gKbdLayout.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
6469 #endif
6471 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6472 // They can be more than one because of:
6473 // * Dead-keys not pairing with base character
6474 // * Some keyboard layouts may map up to 4 characters to the single key
6475 PRBool anyCharMessagesRemoved = PR_FALSE;
6477 if (aFakeCharMessage) {
6478 anyCharMessagesRemoved = PR_TRUE;
6479 } else {
6480 while (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR))
6482 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6483 ("%s charCode=%d scanCode=%d\n", msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6484 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6485 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST, WM_KEYLAST);
6486 anyCharMessagesRemoved = PR_TRUE;
6488 gotMsg = ::PeekMessageW (&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6492 if (!anyCharMessagesRemoved && DOMKeyCode == NS_VK_BACK &&
6493 nsIMM32Handler::IsDoingKakuteiUndo(mWnd)) {
6494 NS_ASSERTION(!aFakeCharMessage,
6495 "We shouldn't be touching the real msg queue");
6496 RemoveMessageAndDispatchPluginEvent(WM_CHAR, WM_CHAR);
6499 else if (gotMsg &&
6500 (aFakeCharMessage ||
6501 msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
6502 if (aFakeCharMessage)
6503 return OnCharRaw(aFakeCharMessage->mCharCode,
6504 aFakeCharMessage->mScanCode, aModKeyState, extraFlags);
6506 // If prevent default set for keydown, do same for keypress
6507 ::GetMessageW(&msg, mWnd, msg.message, msg.message);
6509 if (msg.message == WM_DEADCHAR) {
6510 if (!PluginHasFocus())
6511 return PR_FALSE;
6513 // We need to send the removed message to focused plug-in.
6514 DispatchPluginEvent(msg);
6515 return noDefault;
6518 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6519 ("%s charCode=%d scanCode=%d\n",
6520 msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6521 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6523 BOOL result = OnChar(msg, aModKeyState, nsnull, extraFlags);
6524 // If a syschar keypress wasn't processed, Windows may want to
6525 // handle it to activate a native menu.
6526 if (!result && msg.message == WM_SYSCHAR)
6527 ::DefWindowProcW(mWnd, msg.message, msg.wParam, msg.lParam);
6528 return result;
6530 #ifndef WINCE
6531 else if (!aModKeyState.mIsControlDown && !aModKeyState.mIsAltDown &&
6532 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode) ||
6533 KeyboardLayout::IsNumpadKey(virtualKeyCode)))
6535 // If this is simple KeyDown event but next message is not WM_CHAR,
6536 // this event may not input text, so we should ignore this event.
6537 // See bug 314130.
6538 return PluginHasFocus() && noDefault;
6541 if (gKbdLayout.IsDeadKey ())
6542 return PluginHasFocus() && noDefault;
6544 PRUint8 shiftStates[5];
6545 PRUnichar uniChars[5];
6546 PRUnichar shiftedChars[5] = {0, 0, 0, 0, 0};
6547 PRUnichar unshiftedChars[5] = {0, 0, 0, 0, 0};
6548 PRUnichar shiftedLatinChar = 0;
6549 PRUnichar unshiftedLatinChar = 0;
6550 PRUint32 numOfUniChars = 0;
6551 PRUint32 numOfShiftedChars = 0;
6552 PRUint32 numOfUnshiftedChars = 0;
6553 PRUint32 numOfShiftStates = 0;
6555 switch (virtualKeyCode) {
6556 // keys to be sent as characters
6557 case VK_ADD: uniChars [0] = '+'; numOfUniChars = 1; break;
6558 case VK_SUBTRACT: uniChars [0] = '-'; numOfUniChars = 1; break;
6559 case VK_DIVIDE: uniChars [0] = '/'; numOfUniChars = 1; break;
6560 case VK_MULTIPLY: uniChars [0] = '*'; numOfUniChars = 1; break;
6561 case VK_NUMPAD0:
6562 case VK_NUMPAD1:
6563 case VK_NUMPAD2:
6564 case VK_NUMPAD3:
6565 case VK_NUMPAD4:
6566 case VK_NUMPAD5:
6567 case VK_NUMPAD6:
6568 case VK_NUMPAD7:
6569 case VK_NUMPAD8:
6570 case VK_NUMPAD9:
6571 uniChars [0] = virtualKeyCode - VK_NUMPAD0 + '0';
6572 numOfUniChars = 1;
6573 break;
6574 default:
6575 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
6576 numOfUniChars = numOfShiftStates =
6577 gKbdLayout.GetUniChars(uniChars, shiftStates,
6578 NS_ARRAY_LENGTH(uniChars));
6581 if (aModKeyState.mIsControlDown ^ aModKeyState.mIsAltDown) {
6582 PRUint8 capsLockState = (::GetKeyState(VK_CAPITAL) & 1) ? eCapsLock : 0;
6583 numOfUnshiftedChars =
6584 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode, capsLockState,
6585 unshiftedChars, NS_ARRAY_LENGTH(unshiftedChars));
6586 numOfShiftedChars =
6587 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode,
6588 capsLockState | eShift,
6589 shiftedChars, NS_ARRAY_LENGTH(shiftedChars));
6591 // The current keyboard cannot input alphabets or numerics,
6592 // we should append them for Shortcut/Access keys.
6593 // E.g., for Cyrillic keyboard layout.
6594 if (NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z) {
6595 shiftedLatinChar = unshiftedLatinChar = DOMKeyCode;
6596 if (capsLockState)
6597 shiftedLatinChar += 0x20;
6598 else
6599 unshiftedLatinChar += 0x20;
6600 if (unshiftedLatinChar == unshiftedChars[0] &&
6601 shiftedLatinChar == shiftedChars[0]) {
6602 shiftedLatinChar = unshiftedLatinChar = 0;
6604 } else {
6605 PRUint16 ch = 0;
6606 if (NS_VK_0 <= DOMKeyCode && DOMKeyCode <= NS_VK_9) {
6607 ch = DOMKeyCode;
6608 } else {
6609 switch (virtualKeyCode) {
6610 case VK_OEM_PLUS: ch = '+'; break;
6611 case VK_OEM_MINUS: ch = '-'; break;
6614 if (ch && unshiftedChars[0] != ch && shiftedChars[0] != ch) {
6615 // Windows has assigned a virtual key code to the key even though
6616 // the character can't be produced with this key. That probably
6617 // means the character can't be produced with any key in the
6618 // current layout and so the assignment is based on a QWERTY
6619 // layout. Append this code so that users can access the shortcut.
6620 unshiftedLatinChar = ch;
6624 // If the charCode is not ASCII character, we should replace the
6625 // charCode with ASCII character only when Ctrl is pressed.
6626 // But don't replace the charCode when the charCode is not same as
6627 // unmodified characters. In such case, Ctrl is sometimes used for a
6628 // part of character inputting key combination like Shift.
6629 if (aModKeyState.mIsControlDown) {
6630 PRUint8 currentState = eCtrl;
6631 if (aModKeyState.mIsShiftDown)
6632 currentState |= eShift;
6634 PRUint32 ch =
6635 aModKeyState.mIsShiftDown ? shiftedLatinChar : unshiftedLatinChar;
6636 if (ch &&
6637 (numOfUniChars == 0 ||
6638 StringCaseInsensitiveEquals(uniChars, numOfUniChars,
6639 aModKeyState.mIsShiftDown ? shiftedChars : unshiftedChars,
6640 aModKeyState.mIsShiftDown ? numOfShiftedChars :
6641 numOfUnshiftedChars))) {
6642 numOfUniChars = numOfShiftStates = 1;
6643 uniChars[0] = ch;
6644 shiftStates[0] = currentState;
6650 if (numOfUniChars > 0 || numOfShiftedChars > 0 || numOfUnshiftedChars > 0) {
6651 PRUint32 num = PR_MAX(numOfUniChars,
6652 PR_MAX(numOfShiftedChars, numOfUnshiftedChars));
6653 PRUint32 skipUniChars = num - numOfUniChars;
6654 PRUint32 skipShiftedChars = num - numOfShiftedChars;
6655 PRUint32 skipUnshiftedChars = num - numOfUnshiftedChars;
6656 UINT keyCode = numOfUniChars == 0 ? DOMKeyCode : 0;
6657 for (PRUint32 cnt = 0; cnt < num; cnt++) {
6658 PRUint16 uniChar, shiftedChar, unshiftedChar;
6659 uniChar = shiftedChar = unshiftedChar = 0;
6660 if (skipUniChars <= cnt) {
6661 if (cnt - skipUniChars < numOfShiftStates) {
6662 // If key in combination with Alt and/or Ctrl produces a different
6663 // character than without them then do not report these flags
6664 // because it is separate keyboard layout shift state. If dead-key
6665 // and base character does not produce a valid composite character
6666 // then both produced dead-key character and following base
6667 // character may have different modifier flags, too.
6668 aModKeyState.mIsShiftDown =
6669 (shiftStates[cnt - skipUniChars] & eShift) != 0;
6670 aModKeyState.mIsControlDown =
6671 (shiftStates[cnt - skipUniChars] & eCtrl) != 0;
6672 aModKeyState.mIsAltDown =
6673 (shiftStates[cnt - skipUniChars] & eAlt) != 0;
6675 uniChar = uniChars[cnt - skipUniChars];
6677 if (skipShiftedChars <= cnt)
6678 shiftedChar = shiftedChars[cnt - skipShiftedChars];
6679 if (skipUnshiftedChars <= cnt)
6680 unshiftedChar = unshiftedChars[cnt - skipUnshiftedChars];
6681 nsAutoTArray<nsAlternativeCharCode, 5> altArray;
6683 if (shiftedChar || unshiftedChar) {
6684 nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
6685 altArray.AppendElement(chars);
6687 if (cnt == num - 1 && (unshiftedLatinChar || shiftedLatinChar)) {
6688 nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
6689 altArray.AppendElement(chars);
6692 DispatchKeyEvent(NS_KEY_PRESS, uniChar, &altArray,
6693 keyCode, nsnull, aModKeyState, extraFlags);
6695 } else {
6696 DispatchKeyEvent(NS_KEY_PRESS, 0, nsnull, DOMKeyCode, nsnull, aModKeyState,
6697 extraFlags);
6699 #else
6701 UINT unichar = ::MapVirtualKey(virtualKeyCode, MAPVK_VK_TO_CHAR);
6702 // Check for dead characters or no mapping
6703 if (unichar & 0x80) {
6704 return noDefault;
6706 DispatchKeyEvent(NS_KEY_PRESS, unichar, nsnull, DOMKeyCode, nsnull, aModKeyState,
6707 extraFlags);
6709 #endif
6711 return noDefault;
6714 // OnKeyUp
6715 LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
6716 nsModifierKeyState &aModKeyState,
6717 PRBool *aEventDispatched)
6719 UINT virtualKeyCode = aMsg.wParam;
6721 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6722 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
6724 if (!nsIMM32Handler::IsComposingOn(this)) {
6725 virtualKeyCode = MapFromNativeToDOM(virtualKeyCode);
6728 if (aEventDispatched)
6729 *aEventDispatched = PR_TRUE;
6730 return DispatchKeyEvent(NS_KEY_UP, 0, nsnull, virtualKeyCode, &aMsg,
6731 aModKeyState);
6734 // OnChar
6735 LRESULT nsWindow::OnChar(const MSG &aMsg, nsModifierKeyState &aModKeyState,
6736 PRBool *aEventDispatched, PRUint32 aFlags)
6738 return OnCharRaw(aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF, aModKeyState,
6739 aFlags, &aMsg, aEventDispatched);
6742 // OnCharRaw
6743 LRESULT nsWindow::OnCharRaw(UINT charCode, UINT aScanCode,
6744 nsModifierKeyState &aModKeyState, PRUint32 aFlags,
6745 const MSG *aMsg, PRBool *aEventDispatched)
6747 // ignore [shift+]alt+space so the OS can handle it
6748 if (aModKeyState.mIsAltDown && !aModKeyState.mIsControlDown &&
6749 IS_VK_DOWN(NS_VK_SPACE)) {
6750 return FALSE;
6753 // Ignore Ctrl+Enter (bug 318235)
6754 if (aModKeyState.mIsControlDown && charCode == 0xA) {
6755 return FALSE;
6758 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
6759 PRBool saveIsAltDown = aModKeyState.mIsAltDown;
6760 PRBool saveIsControlDown = aModKeyState.mIsControlDown;
6761 if (aModKeyState.mIsAltDown && aModKeyState.mIsControlDown)
6762 aModKeyState.mIsAltDown = aModKeyState.mIsControlDown = PR_FALSE;
6764 wchar_t uniChar;
6766 if (nsIMM32Handler::IsComposingOn(this)) {
6767 ResetInputState();
6770 if (aModKeyState.mIsControlDown && charCode <= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
6771 // need to account for shift here. bug 16486
6772 if (aModKeyState.mIsShiftDown)
6773 uniChar = charCode - 1 + 'A';
6774 else
6775 uniChar = charCode - 1 + 'a';
6776 charCode = 0;
6778 else if (aModKeyState.mIsControlDown && charCode <= 0x1F) {
6779 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
6780 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
6781 // for some reason the keypress handler need to have the uniChar code set
6782 // with the addition of a upper case A not the lower case.
6783 uniChar = charCode - 1 + 'A';
6784 charCode = 0;
6785 } else { // 0x20 - SPACE, 0x3D - EQUALS
6786 if (charCode < 0x20 || (charCode == 0x3D && aModKeyState.mIsControlDown)) {
6787 uniChar = 0;
6788 } else {
6789 uniChar = charCode;
6790 charCode = 0;
6794 // Keep the characters unshifted for shortcuts and accesskeys and make sure
6795 // that numbers are always passed as such (among others: bugs 50255 and 351310)
6796 if (uniChar && (aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)) {
6797 UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK,
6798 gKbdLayout.GetLayout());
6799 UINT unshiftedCharCode =
6800 virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
6801 aModKeyState.mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode,
6802 MAPVK_VK_TO_CHAR,
6803 gKbdLayout.GetLayout()) : 0;
6804 // ignore diacritics (top bit set) and key mapping errors (char code 0)
6805 if ((INT)unshiftedCharCode > 0)
6806 uniChar = unshiftedCharCode;
6809 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
6810 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
6811 // pressed too.
6812 if (!aModKeyState.mIsShiftDown && (saveIsAltDown || saveIsControlDown)) {
6813 uniChar = towlower(uniChar);
6816 PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, nsnull,
6817 charCode, aMsg, aModKeyState, aFlags);
6818 if (aEventDispatched)
6819 *aEventDispatched = PR_TRUE;
6820 aModKeyState.mIsAltDown = saveIsAltDown;
6821 aModKeyState.mIsControlDown = saveIsControlDown;
6822 return result;
6825 void
6826 nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers)
6828 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierKeyMap); ++i) {
6829 const PRUint32* map = sModifierKeyMap[i];
6830 if (aModifiers & map[0]) {
6831 aArray->AppendElement(KeyPair(map[1], map[2]));
6836 nsresult
6837 nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
6839 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
6840 // here, if that helps in some situations. So far I haven't seen a
6841 // need.
6842 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
6843 const Configuration& configuration = aConfigurations[i];
6844 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
6845 NS_ASSERTION(w->GetParent() == this,
6846 "Configured widget is not a child");
6847 #ifdef WINCE
6848 // MSDN says we should do on WinCE this before moving or resizing the window
6849 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
6850 // We put the region back just below, anyway.
6851 ::SetWindowRgn(w->mWnd, NULL, TRUE);
6852 #endif
6853 nsIntRect bounds;
6854 w->GetBounds(bounds);
6855 if (bounds.Size() != configuration.mBounds.Size()) {
6856 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
6857 configuration.mBounds.width, configuration.mBounds.height,
6858 PR_TRUE);
6859 } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
6860 w->Move(configuration.mBounds.x, configuration.mBounds.y);
6862 nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_FALSE);
6863 NS_ENSURE_SUCCESS(rv, rv);
6865 return NS_OK;
6868 static HRGN
6869 CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
6871 PRInt32 size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
6872 nsAutoTArray<PRUint8,100> buf;
6873 if (!buf.SetLength(size))
6874 return NULL;
6875 RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
6876 RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
6877 data->rdh.dwSize = sizeof(data->rdh);
6878 data->rdh.iType = RDH_RECTANGLES;
6879 data->rdh.nCount = aRects.Length();
6880 nsIntRect bounds;
6881 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
6882 const nsIntRect& r = aRects[i];
6883 bounds.UnionRect(bounds, r);
6884 ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
6886 ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
6887 return ::ExtCreateRegion(NULL, buf.Length(), data);
6890 nsresult
6891 nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
6892 PRBool aIntersectWithExisting)
6894 if (!aIntersectWithExisting) {
6895 if (!StoreWindowClipRegion(aRects))
6896 return NS_OK;
6899 HRGN dest = CreateHRGNFromArray(aRects);
6900 if (!dest)
6901 return NS_ERROR_OUT_OF_MEMORY;
6903 if (aIntersectWithExisting) {
6904 HRGN current = ::CreateRectRgn(0, 0, 0, 0);
6905 if (current) {
6906 if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
6907 ::CombineRgn(dest, dest, current, RGN_AND);
6909 ::DeleteObject(current);
6913 if (!::SetWindowRgn(mWnd, dest, TRUE)) {
6914 ::DeleteObject(dest);
6915 return NS_ERROR_FAILURE;
6917 return NS_OK;
6920 // WM_DESTROY event handler
6921 void nsWindow::OnDestroy()
6923 mOnDestroyCalled = PR_TRUE;
6925 // Make sure we don't get destroyed in the process of tearing down.
6926 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
6928 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
6929 if (!mInDtor)
6930 DispatchStandardEvent(NS_DESTROY);
6932 // Prevent the widget from sending additional events.
6933 mEventCallback = nsnull;
6935 // Free our subclass and clear |this| stored in the window props. We will no longer
6936 // receive events from Windows after this point.
6937 SubclassWindow(FALSE);
6939 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
6940 // cleared. (It's used in tracking windows for mouse events.)
6941 if (sCurrentWindow == this)
6942 sCurrentWindow = nsnull;
6944 // Disconnects us from our parent, will call our GetParent().
6945 nsBaseWidget::Destroy();
6947 // Release references to children, device context, toolkit, and app shell.
6948 nsBaseWidget::OnDestroy();
6950 // Clear our native parent handle.
6951 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
6952 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
6953 //SetParent(nsnull);
6954 mParent = nsnull;
6956 // We have to destroy the native drag target before we null out our window pointer.
6957 EnableDragDrop(PR_FALSE);
6959 // If we're going away and for some reason we're still the rollup widget, rollup and
6960 // turn off capture.
6961 if ( this == sRollupWidget ) {
6962 if ( sRollupListener )
6963 sRollupListener->Rollup(nsnull, nsnull);
6964 CaptureRollupEvents(nsnull, nsnull, PR_FALSE, PR_TRUE);
6967 // If IME is disabled, restore it.
6968 if (mOldIMC) {
6969 mOldIMC = ::ImmAssociateContext(mWnd, mOldIMC);
6970 NS_ASSERTION(!mOldIMC, "Another IMC was associated");
6973 // Turn off mouse trails if enabled.
6974 MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
6975 if (mtrailer) {
6976 if (mtrailer->GetMouseTrailerWindow() == mWnd)
6977 mtrailer->DestroyTimer();
6979 if (mtrailer->GetCaptureWindow() == mWnd)
6980 mtrailer->SetCaptureWindow(nsnull);
6983 // Free GDI window class objects
6984 if (mBrush) {
6985 VERIFY(::DeleteObject(mBrush));
6986 mBrush = NULL;
6989 // Free app icon resources.
6990 HICON icon;
6991 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM) 0);
6992 if (icon)
6993 ::DestroyIcon(icon);
6995 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM) 0);
6996 if (icon)
6997 ::DestroyIcon(icon);
6999 // Destroy any custom cursor resources.
7000 if (mCursor == -1)
7001 SetCursor(eCursor_standard);
7003 #ifdef MOZ_XUL
7004 // Reset transparency
7005 if (eTransparencyTransparent == mTransparencyMode)
7006 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
7007 #endif
7009 #if defined(WINCE_HAVE_SOFTKB)
7010 // Revert the changes made for the software keyboard settings
7011 nsWindowCE::ResetSoftKB(mWnd);
7012 #endif
7014 #if !defined(WINCE)
7015 // Finalize panning feedback to possibly restore window displacement
7016 mGesture.PanFeedbackFinalize(mWnd, PR_TRUE);
7017 #endif
7019 // Clear the main HWND.
7020 mWnd = NULL;
7023 // OnMove
7024 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
7026 mBounds.x = aX;
7027 mBounds.y = aY;
7029 nsGUIEvent event(PR_TRUE, NS_MOVE, this);
7030 InitEvent(event);
7031 event.refPoint.x = aX;
7032 event.refPoint.y = aY;
7034 return DispatchWindowEvent(&event);
7037 // Send a resize message to the listener
7038 PRBool nsWindow::OnResize(nsIntRect &aWindowRect)
7040 #ifdef CAIRO_HAS_D2D_SURFACE
7041 if (mD2DWindowSurface) {
7042 mD2DWindowSurface = NULL;
7043 Invalidate(PR_FALSE);
7045 #endif
7046 // call the event callback
7047 if (mEventCallback) {
7048 nsSizeEvent event(PR_TRUE, NS_SIZE, this);
7049 InitEvent(event);
7050 event.windowSize = &aWindowRect;
7051 RECT r;
7052 if (::GetWindowRect(mWnd, &r)) {
7053 event.mWinWidth = PRInt32(r.right - r.left);
7054 event.mWinHeight = PRInt32(r.bottom - r.top);
7055 } else {
7056 event.mWinWidth = 0;
7057 event.mWinHeight = 0;
7060 #if 0
7061 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7062 aWindowRect.x, aWindowRect.y, aWindowRect.width, aWindowRect.height,
7063 event.mWinWidth, event.mWinHeight);
7064 #endif
7066 return DispatchWindowEvent(&event);
7069 return PR_FALSE;
7072 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7073 PRBool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
7075 return PR_TRUE;
7077 #endif // !defined(WINCE)
7079 void nsWindow::OnSettingsChange(WPARAM wParam, LPARAM lParam)
7081 if (mWindowType == eWindowType_dialog ||
7082 mWindowType == eWindowType_toplevel )
7083 nsWindowGfx::OnSettingsChangeGfx(wParam);
7086 static PRBool IsOurProcessWindow(HWND aHWND)
7088 DWORD processId = 0;
7089 ::GetWindowThreadProcessId(aHWND, &processId);
7090 return processId == ::GetCurrentProcessId();
7093 static HWND FindOurProcessWindow(HWND aHWND)
7095 for (HWND wnd = ::GetParent(aHWND); wnd; wnd = ::GetParent(wnd)) {
7096 if (IsOurProcessWindow(wnd)) {
7097 return wnd;
7100 return nsnull;
7103 // Scrolling helper function for handling plugins.
7104 // Return value indicates whether the calling function should handle this
7105 // aHandled indicates whether this was handled at all
7106 // aQuitProcessing tells whether or not to continue processing the message
7107 PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
7108 LPARAM aLParam, PRBool& aHandled,
7109 LRESULT* aRetValue,
7110 PRBool& aQuitProcessing)
7112 // The scroll event will be dispatched to the toplevel
7113 // window. We need to give it to the child window
7114 aQuitProcessing = PR_FALSE; // default is to not stop processing
7115 POINT point;
7116 DWORD dwPoints = ::GetMessagePos();
7117 point.x = GET_X_LPARAM(dwPoints);
7118 point.y = GET_Y_LPARAM(dwPoints);
7120 static PRBool sIsProcessing = PR_FALSE;
7121 if (sIsProcessing) {
7122 return PR_TRUE; // the caller should handle this.
7125 static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
7126 if (aMsg == WM_MOUSEHWHEEL) {
7127 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7128 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7129 // message at first time, this time, ::GetMessagePos works fine.
7130 // Then, we will return 0 (0 means we process it) to the message. Then, the
7131 // driver will POST the same messages continuously during the wheel tilted.
7132 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7133 // cursor isn't 0,0. Therefore, we cannot trust the result of
7134 // ::GetMessagePos API if the sender is the driver.
7135 if (!sMayBeUsingLogitechMouse && aLParam == 0 && aLParam != dwPoints &&
7136 ::InSendMessage()) {
7137 sMayBeUsingLogitechMouse = PR_TRUE;
7138 } else if (sMayBeUsingLogitechMouse && aLParam != 0 && ::InSendMessage()) {
7139 // The user has changed the mouse from Logitech's to another one (e.g.,
7140 // the user has changed to the touchpad of the notebook.
7141 sMayBeUsingLogitechMouse = PR_FALSE;
7143 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7144 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7145 // instead.
7146 if (sMayBeUsingLogitechMouse && aLParam == 0 && dwPoints == 0) {
7147 ::GetCursorPos(&point);
7151 HWND destWnd = ::WindowFromPoint(point);
7152 // Since we receive scroll events for as long as
7153 // we are focused, it's entirely possible that there
7154 // is another app's window or no window under the
7155 // pointer.
7157 if (!destWnd) {
7158 // No window is under the pointer
7159 return PR_FALSE; // break, but continue processing
7162 nsWindow* destWindow;
7164 // We don't handle the message if the found window belongs to another
7165 // process's top window. If it belongs window, that is a plug-in's window.
7166 // Then, we need to send the message to the plug-in window.
7167 if (!IsOurProcessWindow(destWnd)) {
7168 HWND ourPluginWnd = FindOurProcessWindow(destWnd);
7169 if (!ourPluginWnd) {
7170 // Somebody elses window
7171 return PR_FALSE; // break, but continue processing
7173 destWindow = GetNSWindowPtr(ourPluginWnd);
7174 } else {
7175 destWindow = GetNSWindowPtr(destWnd);
7178 if (destWindow == this && mWindowType == eWindowType_plugin) {
7179 // If this is plug-in window, the message came from the plug-in window.
7180 // Then, the message should be processed on the parent window.
7181 destWindow = static_cast<nsWindow*>(GetParent());
7182 NS_ENSURE_TRUE(destWindow, PR_FALSE); // break, but continue processing
7183 destWnd = destWindow->mWnd;
7184 NS_ENSURE_TRUE(destWnd, PR_FALSE); // break, but continue processing
7187 if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
7188 // Some other app, or a plugin window.
7189 // Windows directs scrolling messages to the focused window.
7190 // However, Mozilla does not like plugins having focus, so a
7191 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7192 // Therefore, plugins etc _should_ get first grab at the
7193 // message, but this focus vaguary means the plugin misses
7194 // out. If the window is a child of ours, forward it on.
7195 // Determine if a child by walking the parent list until
7196 // we find a parent matching our wndproc.
7197 HWND parentWnd = ::GetParent(destWnd);
7198 while (parentWnd) {
7199 nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
7200 if (parentWindow) {
7201 // We have a child window - quite possibly a plugin window.
7202 // However, not all plugins are created equal - some will handle this
7203 // message themselves, some will forward directly back to us, while
7204 // others will call DefWndProc, which itself still forwards back to us.
7205 // So if we have sent it once, we need to handle it ourself.
7207 #ifdef MOZ_IPC
7208 // XXX The message shouldn't come from the plugin window at here.
7209 // But the message might come from it due to some bugs. If it happens,
7210 // SendMessage causes deadlock. For safety, we should unlock the
7211 // sender here.
7212 ::ReplyMessage(aMsg == WM_MOUSEHWHEEL ? TRUE : 0);
7213 #endif
7215 // First time we have seen this message.
7216 // Call the child - either it will consume it, or
7217 // it will wind it's way back to us,triggering the destWnd case above
7218 // either way,when the call returns,we are all done with the message,
7219 sIsProcessing = PR_TRUE;
7220 ::SendMessageW(destWnd, aMsg, aWParam, aLParam);
7221 sIsProcessing = PR_FALSE;
7222 aHandled = PR_TRUE;
7223 aQuitProcessing = PR_TRUE;
7224 return PR_FALSE; // break, and stop processing
7226 parentWnd = ::GetParent(parentWnd);
7227 } // while parentWnd
7229 if (destWnd == nsnull)
7230 return PR_FALSE;
7231 if (destWnd != mWnd) {
7232 if (destWindow) {
7233 sIsProcessing = PR_TRUE;
7234 aHandled = destWindow->ProcessMessage(aMsg, aWParam, aLParam, aRetValue);
7235 sIsProcessing = PR_FALSE;
7236 aQuitProcessing = PR_TRUE;
7237 return PR_FALSE; // break, and stop processing
7239 #ifdef DEBUG
7240 else
7241 printf("WARNING: couldn't get child window for SCROLL event\n");
7242 #endif
7244 return PR_TRUE; // caller should handle this
7247 PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
7249 static PRInt8 sMouseWheelEmulation = -1;
7250 if (sMouseWheelEmulation < 0) {
7251 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7252 NS_ENSURE_TRUE(prefs, PR_FALSE);
7253 nsCOMPtr<nsIPrefBranch> prefBranch;
7254 prefs->GetBranch(0, getter_AddRefs(prefBranch));
7255 NS_ENSURE_TRUE(prefBranch, PR_FALSE);
7256 PRBool emulate;
7257 nsresult rv =
7258 prefBranch->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate);
7259 NS_ENSURE_SUCCESS(rv, PR_FALSE);
7260 sMouseWheelEmulation = PRInt8(emulate);
7263 if (aLParam || sMouseWheelEmulation) {
7264 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7265 // Treat as a mousewheel message and scroll appropriately
7266 PRBool quit, result;
7267 LRESULT retVal;
7269 if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result, &retVal, quit))
7270 return quit; // Return if it's not our message or has been dispatched
7272 nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
7273 scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
7274 ? nsMouseScrollEvent::kIsVertical
7275 : nsMouseScrollEvent::kIsHorizontal;
7276 switch (LOWORD(aWParam))
7278 case SB_PAGEDOWN:
7279 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7280 case SB_LINEDOWN:
7281 scrollevent.delta = 1;
7282 break;
7283 case SB_PAGEUP:
7284 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7285 case SB_LINEUP:
7286 scrollevent.delta = -1;
7287 break;
7288 default:
7289 return PR_FALSE;
7291 #ifdef MOZ_IPC
7292 // The event may go to a plug-in which already dispatched this message.
7293 // Then, the event can cause deadlock. We should unlock the sender here.
7294 ::ReplyMessage(0);
7295 #endif
7296 scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
7297 scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
7298 scrollevent.isMeta = PR_FALSE;
7299 scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
7300 InitEvent(scrollevent);
7301 if (nsnull != mEventCallback)
7303 DispatchWindowEvent(&scrollevent);
7305 return PR_TRUE;
7308 // Scroll message generated by external application
7309 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_SCROLL, this);
7311 command.mScroll.mIsHorizontal = (aMsg == WM_HSCROLL);
7313 switch (LOWORD(aWParam))
7315 case SB_LINEUP: // SB_LINELEFT
7316 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7317 command.mScroll.mAmount = -1;
7318 break;
7319 case SB_LINEDOWN: // SB_LINERIGHT
7320 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7321 command.mScroll.mAmount = 1;
7322 break;
7323 case SB_PAGEUP: // SB_PAGELEFT
7324 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7325 command.mScroll.mAmount = -1;
7326 break;
7327 case SB_PAGEDOWN: // SB_PAGERIGHT
7328 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7329 command.mScroll.mAmount = 1;
7330 break;
7331 case SB_TOP: // SB_LEFT
7332 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7333 command.mScroll.mAmount = -1;
7334 break;
7335 case SB_BOTTOM: // SB_RIGHT
7336 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7337 command.mScroll.mAmount = 1;
7338 break;
7339 default:
7340 return PR_FALSE;
7342 DispatchWindowEvent(&command);
7343 return PR_TRUE;
7346 // Can be overriden. Controls auto-erase of background.
7347 PRBool nsWindow::AutoErase(HDC dc)
7349 return PR_FALSE;
7352 /**************************************************************
7353 **************************************************************
7355 ** BLOCK: IME management and accessibility
7357 ** Handles managing IME input and accessibility.
7359 **************************************************************
7360 **************************************************************/
7362 NS_IMETHODIMP nsWindow::ResetInputState()
7364 #ifdef DEBUG_KBSTATE
7365 printf("ResetInputState\n");
7366 #endif
7368 #ifdef NS_ENABLE_TSF
7369 nsTextStore::CommitComposition(PR_FALSE);
7370 #endif //NS_ENABLE_TSF
7372 nsIMM32Handler::CommitComposition(this);
7373 return NS_OK;
7376 NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState)
7378 #ifdef DEBUG_KBSTATE
7379 printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
7380 #endif
7382 #ifdef NS_ENABLE_TSF
7383 nsTextStore::SetIMEOpenState(aState);
7384 #endif //NS_ENABLE_TSF
7386 nsIMEContext IMEContext(mWnd);
7387 if (IMEContext.IsValid()) {
7388 ::ImmSetOpenStatus(IMEContext.get(), aState ? TRUE : FALSE);
7390 return NS_OK;
7393 NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState)
7395 nsIMEContext IMEContext(mWnd);
7396 if (IMEContext.IsValid()) {
7397 BOOL isOpen = ::ImmGetOpenStatus(IMEContext.get());
7398 *aState = isOpen ? PR_TRUE : PR_FALSE;
7399 } else
7400 *aState = PR_FALSE;
7402 #ifdef NS_ENABLE_TSF
7403 *aState |= nsTextStore::GetIMEOpenState();
7404 #endif //NS_ENABLE_TSF
7406 return NS_OK;
7409 NS_IMETHODIMP nsWindow::SetIMEEnabled(PRUint32 aState)
7411 #ifdef NS_ENABLE_TSF
7412 nsTextStore::SetIMEEnabled(aState);
7413 #endif //NS_ENABLE_TSF
7414 #ifdef DEBUG_KBSTATE
7415 printf("SetIMEEnabled: %s\n", (aState == nsIWidget::IME_STATUS_ENABLED ||
7416 aState == nsIWidget::IME_STATUS_PLUGIN)?
7417 "Enabled": "Disabled");
7418 #endif
7419 if (nsIMM32Handler::IsComposing()) {
7420 ResetInputState();
7422 mIMEEnabled = aState;
7423 PRBool enable = (aState == nsIWidget::IME_STATUS_ENABLED ||
7424 aState == nsIWidget::IME_STATUS_PLUGIN);
7426 #if defined(WINCE_HAVE_SOFTKB)
7427 sSoftKeyboardState = (aState != nsIWidget::IME_STATUS_DISABLED);
7428 nsWindowCE::ToggleSoftKB(mWnd, sSoftKeyboardState);
7429 #endif
7431 if (!enable != !mOldIMC)
7432 return NS_OK;
7433 mOldIMC = ::ImmAssociateContext(mWnd, enable ? mOldIMC : NULL);
7434 NS_ASSERTION(!enable || !mOldIMC, "Another IMC was associated");
7436 return NS_OK;
7439 NS_IMETHODIMP nsWindow::GetIMEEnabled(PRUint32* aState)
7441 #ifdef DEBUG_KBSTATE
7442 printf("GetIMEEnabled: %s\n", mIMEEnabled? "Enabled": "Disabled");
7443 #endif
7444 *aState = mIMEEnabled;
7445 return NS_OK;
7448 NS_IMETHODIMP nsWindow::CancelIMEComposition()
7450 #ifdef DEBUG_KBSTATE
7451 printf("CancelIMEComposition\n");
7452 #endif
7454 #ifdef NS_ENABLE_TSF
7455 nsTextStore::CommitComposition(PR_TRUE);
7456 #endif //NS_ENABLE_TSF
7458 nsIMM32Handler::CancelComposition(this);
7459 return NS_OK;
7462 NS_IMETHODIMP
7463 nsWindow::GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState)
7465 #ifdef DEBUG_KBSTATE
7466 printf("GetToggledKeyState\n");
7467 #endif
7468 NS_ENSURE_ARG_POINTER(aLEDState);
7469 *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
7470 return NS_OK;
7473 #ifdef NS_ENABLE_TSF
7474 NS_IMETHODIMP
7475 nsWindow::OnIMEFocusChange(PRBool aFocus)
7477 nsresult rv = nsTextStore::OnFocusChange(aFocus, this, mIMEEnabled);
7478 if (rv == NS_ERROR_NOT_AVAILABLE)
7479 rv = NS_ERROR_NOT_IMPLEMENTED; // TSF is not enabled, maybe.
7480 return rv;
7483 NS_IMETHODIMP
7484 nsWindow::OnIMETextChange(PRUint32 aStart,
7485 PRUint32 aOldEnd,
7486 PRUint32 aNewEnd)
7488 return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
7491 NS_IMETHODIMP
7492 nsWindow::OnIMESelectionChange(void)
7494 return nsTextStore::OnSelectionChange();
7496 #endif //NS_ENABLE_TSF
7498 #ifdef ACCESSIBILITY
7500 #ifdef DEBUG_WMGETOBJECT
7501 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
7502 nsAccessible* acc = aWnd ? \
7503 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
7504 printf(" acc: %p", acc); \
7505 if (acc) { \
7506 nsAutoString name; \
7507 acc->GetName(name); \
7508 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
7509 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
7510 void *hwnd = nsnull; \
7511 doc->GetWindowHandle(&hwnd); \
7512 printf(", acc hwnd: %d", hwnd); \
7515 #define NS_LOG_WMGETOBJECT_THISWND \
7517 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
7518 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p, content type: %d,\n",\
7519 mWnd, ::GetParent(mWnd), this, mContentType); \
7520 NS_LOG_WMGETOBJECT_WNDACC(this) \
7521 printf("\n }\n"); \
7524 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
7526 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
7527 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7528 aHwnd, ::GetParent(aHwnd), wnd); \
7529 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
7530 printf("\n }\n"); \
7532 #else
7533 #define NS_LOG_WMGETOBJECT_THISWND
7534 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
7535 #endif // DEBUG_WMGETOBJECT
7537 nsAccessible*
7538 nsWindow::GetRootAccessible()
7540 // We want the ability to forcibly disable a11y on windows, because
7541 // some non-a11y-related components attempt to bring it up. See bug
7542 // 538530 for details; we have a pref here that allows it to be disabled
7543 // for performance and testing resons.
7545 // This pref is checked only once, and the browser needs a restart to
7546 // pick up any changes.
7547 static int accForceDisable = -1;
7549 if (accForceDisable == -1) {
7550 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7551 PRBool b = PR_FALSE;
7552 nsresult rv = prefs->GetBoolPref("accessibility.win32.force_disabled", &b);
7553 if (NS_SUCCEEDED(rv) && b) {
7554 accForceDisable = 1;
7555 } else {
7556 accForceDisable = 0;
7560 // If the pref was true, return null here, disabling a11y.
7561 if (accForceDisable)
7562 return nsnull;
7564 nsWindow::sIsAccessibilityOn = TRUE;
7566 if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) {
7567 return nsnull;
7570 NS_LOG_WMGETOBJECT_THISWND
7572 if (mContentType != eContentTypeInherit) {
7573 // We're on a MozillaContentWindowClass or MozillaUIWindowClass window.
7574 // Search for the correct visible child window to get an accessible
7575 // document from. Make sure to use an active child window. If this window
7576 // doesn't have child windows then return an accessible for it.
7577 HWND accessibleWnd = ::GetTopWindow(mWnd);
7578 NS_LOG_WMGETOBJECT_WND("Top Window", accessibleWnd);
7579 if (!accessibleWnd) {
7580 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
7581 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
7584 nsWindow* accessibleWindow = nsnull;
7585 while (accessibleWnd) {
7586 // Loop through windows and find the first one with accessibility info
7587 accessibleWindow = GetNSWindowPtr(accessibleWnd);
7588 if (accessibleWindow) {
7589 nsAccessible *rootAccessible =
7590 accessibleWindow->DispatchAccessibleEvent(NS_GETACCESSIBLE);
7591 if (rootAccessible) {
7592 // Success, one of the child windows was active.
7593 return rootAccessible;
7596 accessibleWnd = ::GetNextWindow(accessibleWnd, GW_HWNDNEXT);
7597 NS_LOG_WMGETOBJECT_WND("Next Window", accessibleWnd);
7599 return nsnull;
7602 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
7603 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
7606 STDMETHODIMP_(LRESULT)
7607 nsWindow::LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc)
7609 // open the dll dynamically
7610 if (!sAccLib)
7611 sAccLib =::LoadLibraryW(L"OLEACC.DLL");
7613 if (sAccLib) {
7614 if (!sLresultFromObject)
7615 sLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(sAccLib,"LresultFromObject");
7617 if (sLresultFromObject)
7618 return sLresultFromObject(riid,wParam,pAcc);
7621 return 0;
7623 #endif
7625 /**************************************************************
7626 **************************************************************
7628 ** BLOCK: Transparency
7630 ** Window transparency helpers.
7632 **************************************************************
7633 **************************************************************/
7635 #ifdef MOZ_XUL
7637 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force)
7639 if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
7640 return;
7642 #ifdef CAIRO_HAS_D2D_SURFACE
7643 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7644 gfxWindowsPlatform::RENDER_DIRECT2D) {
7645 nsRefPtr<gfxD2DSurface> newSurface =
7646 new gfxD2DSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7647 mTransparentSurface = newSurface;
7648 mMemoryDC = nsnull;
7649 } else
7650 #endif
7652 nsRefPtr<gfxWindowsSurface> newSurface =
7653 new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7654 mTransparentSurface = newSurface;
7655 mMemoryDC = newSurface->GetDC();
7659 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
7661 #ifndef WINCE
7663 if (aMode == mTransparencyMode)
7664 return;
7666 // stop on dialogs and popups!
7667 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7668 nsWindow* parent = GetNSWindowPtr(hWnd);
7670 if (!parent)
7672 NS_WARNING("Trying to use transparent chrome in an embedded context");
7673 return;
7676 if (parent != this) {
7677 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
7680 if (aMode == eTransparencyTransparent) {
7681 // If we're switching to the use of a transparent window, hide the chrome
7682 // on our parent.
7683 HideWindowChrome(PR_TRUE);
7684 } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) {
7685 // if we're switching out of transparent, re-enable our parent's chrome.
7686 HideWindowChrome(PR_FALSE);
7689 LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE),
7690 exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
7692 if (parent->mIsVisible)
7693 style |= WS_VISIBLE;
7694 if (parent->mSizeMode == nsSizeMode_Maximized)
7695 style |= WS_MAXIMIZE;
7696 else if (parent->mSizeMode == nsSizeMode_Minimized)
7697 style |= WS_MINIMIZE;
7699 if (aMode == eTransparencyTransparent)
7700 exStyle |= WS_EX_LAYERED;
7701 else
7702 exStyle &= ~WS_EX_LAYERED;
7704 VERIFY_WINDOW_STYLE(style);
7705 ::SetWindowLongPtrW(hWnd, GWL_STYLE, style);
7706 ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle);
7708 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7709 if (mTransparencyMode == eTransparencyGlass)
7710 memset(&mGlassMargins, 0, sizeof mGlassMargins);
7711 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7712 mTransparencyMode = aMode;
7714 SetupTranslucentWindowMemoryBitmap(aMode);
7715 UpdateGlass();
7716 #endif // #ifndef WINCE
7719 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
7721 if (eTransparencyTransparent == aMode) {
7722 ResizeTranslucentWindow(mBounds.width, mBounds.height, PR_TRUE);
7723 } else {
7724 mTransparentSurface = nsnull;
7725 mMemoryDC = NULL;
7729 nsresult nsWindow::UpdateTranslucentWindow()
7731 #ifndef WINCE
7732 if (mBounds.IsEmpty())
7733 return NS_OK;
7735 ::GdiFlush();
7737 BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
7738 SIZE winSize = { mBounds.width, mBounds.height };
7739 POINT srcPos = { 0, 0 };
7740 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7741 RECT winRect;
7742 ::GetWindowRect(hWnd, &winRect);
7744 #ifdef CAIRO_HAS_D2D_SURFACE
7745 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7746 gfxWindowsPlatform::RENDER_DIRECT2D) {
7747 mMemoryDC = static_cast<gfxD2DSurface*>(mTransparentSurface.get())->
7748 GetDC(PR_TRUE);
7750 #endif
7751 // perform the alpha blend
7752 PRBool updateSuccesful =
7753 ::UpdateLayeredWindow(hWnd, NULL, (POINT*)&winRect, &winSize, mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA);
7755 #ifdef CAIRO_HAS_D2D_SURFACE
7756 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7757 gfxWindowsPlatform::RENDER_DIRECT2D) {
7758 nsIntRect r(0, 0, 0, 0);
7759 static_cast<gfxD2DSurface*>(mTransparentSurface.get())->ReleaseDC(&r);
7761 #endif
7763 if (!updateSuccesful) {
7764 return NS_ERROR_FAILURE;
7766 #endif
7768 return NS_OK;
7771 #endif //MOZ_XUL
7773 /**************************************************************
7774 **************************************************************
7776 ** BLOCK: Popup rollup hooks
7778 ** Deals with CaptureRollup on popup windows.
7780 **************************************************************
7781 **************************************************************/
7783 #ifndef WINCE
7784 // Schedules a timer for a window, so we can rollup after processing the hook event
7785 void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId)
7787 // In some cases multiple hooks may be scheduled
7788 // so ignore any other requests once one timer is scheduled
7789 if (sHookTimerId == 0) {
7790 // Remember the window handle and the message ID to be used later
7791 sRollupMsgId = aMsgId;
7792 sRollupMsgWnd = aWnd;
7793 // Schedule native timer for doing the rollup after
7794 // this event is done being processed
7795 sHookTimerId = ::SetTimer(NULL, 0, 0, (TIMERPROC)HookTimerForPopups);
7796 NS_ASSERTION(sHookTimerId, "Timer couldn't be created.");
7800 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7801 int gLastMsgCode = 0;
7802 extern MSGFEventMsgInfo gMSGFEvents[];
7803 #endif
7805 // Process Menu messages, rollup when popup is clicked.
7806 LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam)
7808 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7809 if (sProcessHook) {
7810 MSG* pMsg = (MSG*)lParam;
7812 int inx = 0;
7813 while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != NULL) {
7814 inx++;
7816 if (code != gLastMsgCode) {
7817 if (gMSGFEvents[inx].mId == code) {
7818 #ifdef DEBUG
7819 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code, gMSGFEvents[inx].mStr, pMsg->hwnd);
7820 #endif
7821 } else {
7822 #ifdef DEBUG
7823 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code, gMSGFEvents[inx].mId, pMsg->hwnd);
7824 #endif
7826 gLastMsgCode = code;
7828 PrintEvent(pMsg->message, FALSE, FALSE);
7830 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7832 if (sProcessHook && code == MSGF_MENU) {
7833 MSG* pMsg = (MSG*)lParam;
7834 ScheduleHookTimer( pMsg->hwnd, pMsg->message);
7837 return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
7840 // Process all mouse messages. Roll up when a click is in a native window
7841 // that doesn't have an nsIWidget.
7842 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
7844 if (sProcessHook) {
7845 switch (wParam) {
7846 case WM_LBUTTONDOWN:
7847 case WM_RBUTTONDOWN:
7848 case WM_MBUTTONDOWN:
7849 case WM_MOUSEWHEEL:
7850 case WM_MOUSEHWHEEL:
7852 MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
7853 nsIWidget* mozWin = (nsIWidget*)GetNSWindowPtr(ms->hwnd);
7854 if (mozWin) {
7855 // If this window is windowed plugin window, the mouse events are not
7856 // sent to us.
7857 if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin)
7858 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7859 } else {
7860 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7862 break;
7866 return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam);
7869 // Process all messages. Roll up when the window is moving, or
7870 // is resizing or when maximized or mininized.
7871 LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam)
7873 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7874 if (sProcessHook) {
7875 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7876 PrintEvent(cwpt->message, FALSE, FALSE);
7878 #endif
7880 if (sProcessHook) {
7881 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7882 if (cwpt->message == WM_MOVING ||
7883 cwpt->message == WM_SIZING ||
7884 cwpt->message == WM_GETMINMAXINFO) {
7885 ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message);
7889 return ::CallNextHookEx(sCallProcHook, code, wParam, lParam);
7892 // Register the special "hooks" for dropdown processing.
7893 void nsWindow::RegisterSpecialDropdownHooks()
7895 NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!");
7896 NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!");
7898 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
7900 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
7902 // Install msg hook for moving the window and resizing
7903 if (!sMsgFilterHook) {
7904 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
7905 sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, NULL, GetCurrentThreadId());
7906 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7907 if (!sMsgFilterHook) {
7908 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
7910 #endif
7913 // Install msg hook for menus
7914 if (!sCallProcHook) {
7915 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
7916 sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, NULL, GetCurrentThreadId());
7917 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7918 if (!sCallProcHook) {
7919 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
7921 #endif
7924 // Install msg hook for the mouse
7925 if (!sCallMouseHook) {
7926 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
7927 sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, NULL, GetCurrentThreadId());
7928 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7929 if (!sCallMouseHook) {
7930 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
7932 #endif
7936 // Unhook special message hooks for dropdowns.
7937 void nsWindow::UnregisterSpecialDropdownHooks()
7939 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
7941 if (sCallProcHook) {
7942 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
7943 if (!::UnhookWindowsHookEx(sCallProcHook)) {
7944 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
7946 sCallProcHook = NULL;
7949 if (sMsgFilterHook) {
7950 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
7951 if (!::UnhookWindowsHookEx(sMsgFilterHook)) {
7952 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
7954 sMsgFilterHook = NULL;
7957 if (sCallMouseHook) {
7958 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
7959 if (!::UnhookWindowsHookEx(sCallMouseHook)) {
7960 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
7962 sCallMouseHook = NULL;
7966 // This timer is designed to only fire one time at most each time a "hook" function
7967 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
7968 // hook, but that hook event or a subsequent event may roll up the dropdown before
7969 // this timer function is executed.
7971 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
7972 // before this function fires.
7973 VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
7975 if (sHookTimerId != 0) {
7976 // if the window is NULL then we need to use the ID to kill the timer
7977 BOOL status = ::KillTimer(NULL, sHookTimerId);
7978 NS_ASSERTION(status, "Hook Timer was not killed.");
7979 sHookTimerId = 0;
7982 if (sRollupMsgId != 0) {
7983 // Note: DealWithPopups does the check to make sure that
7984 // sRollupListener and sRollupWidget are not NULL
7985 LRESULT popupHandlingResult;
7986 nsAutoRollup autoRollup;
7987 DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
7988 sRollupMsgId = 0;
7989 sRollupMsgWnd = NULL;
7992 #endif // WinCE
7994 static PRBool IsDifferentThreadWindow(HWND aWnd)
7996 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, NULL);
7999 PRBool
8000 nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
8002 RECT r;
8004 #ifndef WINCE
8005 if (Msg == WM_ACTIVATEAPP)
8006 // don't care about activation/deactivation
8007 return PR_FALSE;
8008 #else
8009 if (Msg == WM_ACTIVATE)
8010 // but on Windows CE we do care about
8011 // activation/deactivation because there doesn't exist
8012 // cancelable Mouse Activation events
8013 return PR_TRUE;
8014 #endif
8016 ::GetWindowRect(aWindow->mWnd, &r);
8017 DWORD pos = ::GetMessagePos();
8018 POINT mp;
8019 mp.x = GET_X_LPARAM(pos);
8020 mp.y = GET_Y_LPARAM(pos);
8022 // was the event inside this window?
8023 return (PRBool) PtInRect(&r, mp);
8026 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8027 BOOL
8028 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
8030 if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
8032 if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
8033 inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
8034 (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam))
8035 #ifndef WINCE
8037 inMsg == WM_NCRBUTTONDOWN ||
8038 inMsg == WM_MOVING ||
8039 inMsg == WM_SIZING ||
8040 inMsg == WM_NCLBUTTONDOWN ||
8041 inMsg == WM_NCMBUTTONDOWN ||
8042 inMsg == WM_MOUSEACTIVATE ||
8043 inMsg == WM_ACTIVATEAPP ||
8044 inMsg == WM_MENUSELECT
8045 #endif
8048 // Rollup if the event is outside the popup.
8049 PRBool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)sRollupWidget);
8051 if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL))
8053 sRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
8054 *outResult = PR_TRUE;
8057 // If we're dealing with menus, we probably have submenus and we don't
8058 // want to rollup if the click is in a parent menu of the current submenu.
8059 PRUint32 popupsToRollup = PR_UINT32_MAX;
8060 if (rollup) {
8061 if ( sMenuRollup ) {
8062 nsAutoTArray<nsIWidget*, 5> widgetChain;
8063 PRUint32 sameTypeCount = sMenuRollup->GetSubmenuWidgetChain(&widgetChain);
8064 for ( PRUint32 i = 0; i < widgetChain.Length(); ++i ) {
8065 nsIWidget* widget = widgetChain[i];
8066 if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
8067 // don't roll up if the mouse event occurred within a menu of the
8068 // same type. If the mouse event occurred in a menu higher than
8069 // that, roll up, but pass the number of popups to Rollup so
8070 // that only those of the same type close up.
8071 if (i < sameTypeCount) {
8072 rollup = PR_FALSE;
8074 else {
8075 popupsToRollup = sameTypeCount;
8077 break;
8079 } // foreach parent menu widget
8080 } // if rollup listener knows about menus
8083 #ifndef WINCE
8084 if (inMsg == WM_MOUSEACTIVATE && popupsToRollup == PR_UINT32_MAX) {
8085 // Prevent the click inside the popup from causing a change in window
8086 // activation. Since the popup is shown non-activated, we need to eat
8087 // any requests to activate the window while it is displayed. Windows
8088 // will automatically activate the popup on the mousedown otherwise.
8089 if (!rollup) {
8090 *outResult = MA_NOACTIVATE;
8091 return TRUE;
8093 else
8095 UINT uMsg = HIWORD(inLParam);
8096 if (uMsg == WM_MOUSEMOVE)
8098 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8099 // must be enabled in Windows.
8100 sRollupListener->ShouldRollupOnMouseActivate(&rollup);
8101 if (!rollup)
8103 *outResult = MA_NOACTIVATE;
8104 return true;
8109 // if we've still determined that we should still rollup everything, do it.
8110 else
8111 #endif
8112 if ( rollup ) {
8113 // sRollupConsumeEvent may be modified by
8114 // nsIRollupListener::Rollup.
8115 PRBool consumeRollupEvent = sRollupConsumeEvent;
8116 // only need to deal with the last rollup for left mouse down events.
8117 sRollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN ? &mLastRollup : nsnull);
8119 // Tell hook to stop processing messages
8120 sProcessHook = PR_FALSE;
8121 sRollupMsgId = 0;
8122 sRollupMsgWnd = NULL;
8124 // return TRUE tells Windows that the event is consumed,
8125 // false allows the event to be dispatched
8127 // So if we are NOT supposed to be consuming events, let it go through
8128 if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
8129 *outResult = TRUE;
8130 return TRUE;
8132 #ifndef WINCE
8133 // if we are only rolling up some popups, don't activate and don't let
8134 // the event go through. This prevents clicks menus higher in the
8135 // chain from opening when a context menu is open
8136 if (popupsToRollup != PR_UINT32_MAX && inMsg == WM_MOUSEACTIVATE) {
8137 *outResult = MA_NOACTIVATEANDEAT;
8138 return TRUE;
8140 #endif
8142 } // if event that might trigger a popup to rollup
8143 } // if rollup listeners registered
8145 return FALSE;
8148 /**************************************************************
8149 **************************************************************
8151 ** BLOCK: Misc. utility methods and functions.
8153 ** General use.
8155 **************************************************************
8156 **************************************************************/
8158 // nsModifierKeyState used in various character processing.
8159 nsModifierKeyState::nsModifierKeyState()
8161 mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT);
8162 mIsControlDown = IS_VK_DOWN(NS_VK_CONTROL);
8163 mIsAltDown = IS_VK_DOWN(NS_VK_ALT);
8167 PRInt32 nsWindow::GetWindowsVersion()
8169 #ifdef WINCE
8170 return 0x500;
8171 #else
8172 static PRInt32 version = 0;
8173 static PRBool didCheck = PR_FALSE;
8175 if (!didCheck)
8177 didCheck = PR_TRUE;
8178 OSVERSIONINFOEX osInfo;
8179 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
8180 // This cast is safe and supposed to be here, don't worry
8181 ::GetVersionEx((OSVERSIONINFO*)&osInfo);
8182 version = (osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
8184 return version;
8185 #endif
8188 // Note that the result of GetTopLevelWindow method can be different from the
8189 // result of GetTopLevelHWND method. The result can be non-floating window.
8190 // Because our top level window may be contained in another window which is
8191 // not managed by us.
8192 nsWindow* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup)
8194 nsWindow* curWindow = this;
8196 while (PR_TRUE) {
8197 if (aStopOnDialogOrPopup) {
8198 switch (curWindow->mWindowType) {
8199 case eWindowType_dialog:
8200 case eWindowType_popup:
8201 return curWindow;
8205 // Retrieve the top level parent or owner window
8206 nsWindow* parentWindow = curWindow->GetParentWindow(PR_TRUE);
8208 if (!parentWindow)
8209 return curWindow;
8211 curWindow = parentWindow;
8215 // Note that the result of GetTopLevelHWND can be different from the result
8216 // of GetTopLevelWindow method. Because this is checking whether the window
8217 // is top level only in Win32 window system. Therefore, the result window
8218 // may not be managed by us.
8219 HWND nsWindow::GetTopLevelHWND(HWND aWnd, PRBool aStopOnDialogOrPopup)
8221 HWND curWnd = aWnd;
8222 HWND topWnd = NULL;
8223 HWND upWnd = NULL;
8225 while (curWnd) {
8226 topWnd = curWnd;
8228 if (aStopOnDialogOrPopup) {
8229 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8231 VERIFY_WINDOW_STYLE(style);
8233 if (!(style & WS_CHILD)) // first top-level window
8234 break;
8237 upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
8239 #ifdef WINCE
8240 // For dialog windows, we want just the parent, not the owner.
8241 // For other/popup windows, we want to find the first owner/parent
8242 // that's a dialog and/or has an owner.
8243 if (upWnd && ::GetWindow(curWnd, GW_OWNER) == upWnd) {
8244 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8245 if ((style & WS_DLGFRAME) != 0)
8246 break;
8248 #endif
8250 curWnd = upWnd;
8253 return topWnd;
8256 static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam)
8258 DWORD pid;
8259 ::GetWindowThreadProcessId(hwnd, &pid);
8260 if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd))
8262 gWindowsVisible = PR_TRUE;
8263 return FALSE;
8265 return TRUE;
8268 PRBool nsWindow::CanTakeFocus()
8270 gWindowsVisible = PR_FALSE;
8271 EnumWindows(gEnumWindowsProc, 0);
8272 if (!gWindowsVisible) {
8273 return PR_TRUE;
8274 } else {
8275 HWND fgWnd = ::GetForegroundWindow();
8276 if (!fgWnd) {
8277 return PR_TRUE;
8279 DWORD pid;
8280 GetWindowThreadProcessId(fgWnd, &pid);
8281 if (pid == GetCurrentProcessId()) {
8282 return PR_TRUE;
8285 return PR_FALSE;
8288 #if !defined(WINCE)
8289 void nsWindow::InitTrackPointHack()
8291 // Init Trackpoint Hack
8292 nsresult rv;
8293 PRInt32 lHackValue;
8294 long lResult;
8295 const WCHAR wstrKeys[][40] = {L"Software\\Lenovo\\TrackPoint",
8296 L"Software\\Lenovo\\UltraNav",
8297 L"Software\\Alps\\Apoint\\TrackPoint",
8298 L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
8299 L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
8300 // If anything fails turn the hack off
8301 sTrackPointHack = false;
8302 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8303 if(NS_SUCCEEDED(rv) && prefs) {
8304 prefs->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue);
8305 switch (lHackValue) {
8306 // 0 means hack disabled
8307 case 0:
8308 break;
8309 // 1 means hack enabled
8310 case 1:
8311 sTrackPointHack = true;
8312 break;
8313 // -1 means autodetect
8314 case -1:
8315 for(int i = 0; i < NS_ARRAY_LENGTH(wstrKeys); i++) {
8316 HKEY hKey;
8317 lResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, (LPCWSTR)&wstrKeys[i],
8318 0, KEY_READ, &hKey);
8319 ::RegCloseKey(hKey);
8320 if(lResult == ERROR_SUCCESS) {
8321 // If we detected a registry key belonging to a TrackPoint driver
8322 // Turn on the hack
8323 sTrackPointHack = true;
8324 break;
8327 break;
8328 // Shouldn't be any other values, but treat them as disabled
8329 default:
8330 break;
8333 return;
8335 #endif // #if !defined(WINCE)
8337 LPARAM nsWindow::lParamToScreen(LPARAM lParam)
8339 POINT pt;
8340 pt.x = GET_X_LPARAM(lParam);
8341 pt.y = GET_Y_LPARAM(lParam);
8342 ::ClientToScreen(mWnd, &pt);
8343 return MAKELPARAM(pt.x, pt.y);
8346 LPARAM nsWindow::lParamToClient(LPARAM lParam)
8348 POINT pt;
8349 pt.x = GET_X_LPARAM(lParam);
8350 pt.y = GET_Y_LPARAM(lParam);
8351 ::ScreenToClient(mWnd, &pt);
8352 return MAKELPARAM(pt.x, pt.y);
8355 /**************************************************************
8356 **************************************************************
8358 ** BLOCK: ChildWindow impl.
8360 ** Child window overrides.
8362 **************************************************************
8363 **************************************************************/
8365 // return the style for a child nsWindow
8366 DWORD ChildWindow::WindowStyle()
8368 DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle();
8369 if (!(style & WS_POPUP))
8370 style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
8371 VERIFY_WINDOW_STYLE(style);
8372 return style;