Bug 618420 - increase the size of the lower border resizer area on windows. r=felipe...
[mozilla-central.git] / widget / src / windows / nsWindow.cpp
blob9d85c4a773f7e095a1730041934e504844519664
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"
161 #include "nsWindowsDllInterceptor.h"
162 #include "nsIWindowMediator.h"
163 #include "nsIServiceManager.h"
165 #if defined(WINCE)
166 #include "nsWindowCE.h"
167 #endif
169 #if defined(WINCE_WINDOWS_MOBILE)
170 #define KILL_PRIORITY_ID 2444
171 #endif
173 #include "nsWindowGfx.h"
174 #include "gfxWindowsPlatform.h"
175 #include "Layers.h"
176 #ifndef WINCE
177 #ifdef MOZ_ENABLE_D3D9_LAYER
178 #include "LayerManagerD3D9.h"
179 #endif
180 #ifdef MOZ_ENABLE_D3D10_LAYER
181 #include "LayerManagerD3D10.h"
182 #endif
183 #include "LayerManagerOGL.h"
184 #include "nsIGfxInfo.h"
185 #endif
186 #include "BasicLayers.h"
188 #if !defined(WINCE)
189 #include "nsUXThemeConstants.h"
190 #include "KeyboardLayout.h"
191 #include "nsNativeDragTarget.h"
192 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
193 #include <zmouse.h>
194 #include <pbt.h>
195 #include <richedit.h>
196 #endif // !defined(WINCE)
198 #if defined(ACCESSIBILITY)
199 #include "oleidl.h"
200 #include <winuser.h>
201 #include "nsIAccessibleDocument.h"
202 #if !defined(WINABLEAPI)
203 #include <winable.h>
204 #endif // !defined(WINABLEAPI)
205 #endif // defined(ACCESSIBILITY)
207 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
208 #include "nsIWinTaskbar.h"
209 #endif
211 #if defined(NS_ENABLE_TSF)
212 #include "nsTextStore.h"
213 #endif // defined(NS_ENABLE_TSF)
215 #if defined(MOZ_SPLASHSCREEN)
216 #include "nsSplashScreen.h"
217 #endif // defined(MOZ_SPLASHSCREEN)
219 // Windowless plugin support
220 #include "npapi.h"
222 #include "nsWindowDefs.h"
224 #include "mozilla/FunctionTimer.h"
226 #ifdef WINCE_WINDOWS_MOBILE
227 #include "nsGfxCIID.h"
228 #endif
230 #include "mozilla/FunctionTimer.h"
232 #ifdef MOZ_CRASHREPORTER
233 #include "nsICrashReporter.h"
234 #endif
236 #include "nsIXULRuntime.h"
238 using namespace mozilla::widget;
239 using namespace mozilla::layers;
241 /**************************************************************
242 **************************************************************
244 ** BLOCK: Variables
246 ** nsWindow Class static initializations and global variables.
248 **************************************************************
249 **************************************************************/
251 /**************************************************************
253 * SECTION: nsWindow statics
255 **************************************************************/
257 PRUint32 nsWindow::sInstanceCount = 0;
258 PRBool nsWindow::sSwitchKeyboardLayout = PR_FALSE;
259 BOOL nsWindow::sIsOleInitialized = FALSE;
260 HCURSOR nsWindow::sHCursor = NULL;
261 imgIContainer* nsWindow::sCursorImgContainer = nsnull;
262 nsWindow* nsWindow::sCurrentWindow = nsnull;
263 PRBool nsWindow::sJustGotDeactivate = PR_FALSE;
264 PRBool nsWindow::sJustGotActivate = PR_FALSE;
265 PRBool nsWindow::sIsInMouseCapture = PR_FALSE;
267 // imported in nsWidgetFactory.cpp
268 TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN;
270 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
271 // hook methods whether they should be processing the hook
272 // messages.
273 HHOOK nsWindow::sMsgFilterHook = NULL;
274 HHOOK nsWindow::sCallProcHook = NULL;
275 HHOOK nsWindow::sCallMouseHook = NULL;
276 PRPackedBool nsWindow::sProcessHook = PR_FALSE;
277 UINT nsWindow::sRollupMsgId = 0;
278 HWND nsWindow::sRollupMsgWnd = NULL;
279 UINT nsWindow::sHookTimerId = 0;
281 // Rollup Listener
282 nsIRollupListener* nsWindow::sRollupListener = nsnull;
283 nsIMenuRollup* nsWindow::sMenuRollup = nsnull;
284 nsIWidget* nsWindow::sRollupWidget = nsnull;
285 PRBool nsWindow::sRollupConsumeEvent = PR_FALSE;
287 // Mouse Clicks - static variable definitions for figuring
288 // out 1 - 3 Clicks.
289 POINT nsWindow::sLastMousePoint = {0};
290 POINT nsWindow::sLastMouseMovePoint = {0};
291 LONG nsWindow::sLastMouseDownTime = 0L;
292 LONG nsWindow::sLastClickCount = 0L;
293 BYTE nsWindow::sLastMouseButton = 0;
295 // Trim heap on minimize. (initialized, but still true.)
296 int nsWindow::sTrimOnMinimize = 2;
298 // Default value for Trackpoint hack (used when the pref is set to -1).
299 PRBool nsWindow::sDefaultTrackPointHack = PR_FALSE;
300 // Default value for general window class (used when the pref is the empty string).
301 const char* nsWindow::sDefaultMainWindowClass = kClassNameGeneral;
303 // If we're using D3D9, this will not be allowed during initial 5 seconds.
304 bool nsWindow::sAllowD3D9 = false;
306 #ifdef ACCESSIBILITY
307 BOOL nsWindow::sIsAccessibilityOn = FALSE;
308 // Accessibility wm_getobject handler
309 HINSTANCE nsWindow::sAccLib = 0;
310 LPFNLRESULTFROMOBJECT
311 nsWindow::sLresultFromObject = 0;
312 #endif // ACCESSIBILITY
314 #ifdef MOZ_IPC
315 // Used in OOPP plugin focus processing.
316 const PRUnichar* kOOPPPluginFocusEventId = L"OOPP Plugin Focus Widget Event";
317 PRUint32 nsWindow::sOOPPPluginFocusEvent =
318 RegisterWindowMessageW(kOOPPPluginFocusEventId);
319 #endif
321 MSG nsWindow::sRedirectedKeyDown;
323 /**************************************************************
325 * SECTION: globals variables
327 **************************************************************/
329 static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
331 #ifdef PR_LOGGING
332 PRLogModuleInfo* gWindowsLog = nsnull;
333 #endif
335 #ifndef WINCE
336 // Kbd layout. Used throughout character processing.
337 static KeyboardLayout gKbdLayout;
338 #endif
340 #ifdef WINCE_WINDOWS_MOBILE
341 // HTC Navigation Wheel Event
342 // This is the defined value for Gesture Mode
343 const int WM_HTCNAV = 0x0400 + 200;
345 typedef int (__stdcall * HTCApiNavOpen)(HANDLE, int);
346 typedef int (__stdcall * HTCApiNavSetMode)(HANDLE, unsigned int);
348 HTCApiNavOpen gHTCApiNavOpen = nsnull;
349 HTCApiNavSetMode gHTCApiNavSetMode = nsnull;
350 static PRBool gCheckForHTCApi = PR_FALSE;
351 #endif
353 // Global user preference for disabling native theme. Used
354 // in NativeWindowTheme.
355 PRBool gDisableNativeTheme = PR_FALSE;
357 // Global used in Show window enumerations.
358 static PRBool gWindowsVisible = PR_FALSE;
360 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
361 #ifdef WINCE_WINDOWS_MOBILE
362 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
363 #endif
365 // General purpose user32.dll hook object
366 static WindowsDllInterceptor sUser32Intercept;
368 // A glass window's opaque rectangle must be at least this height
369 // before we use glass margins. Shorter opaque rectangles lead to
370 // stupid-looking visual effects because Windows (foolishly) makes the
371 // window edge rendering dependent on the opaque rect height.
372 static const int MIN_OPAQUE_RECT_HEIGHT_FOR_GLASS_MARGINS = 50;
374 // Maximum number of pixels for the left and right horizontal glass margins.
375 // If the margins are bigger than this, we won't use margins at all because
376 // Windows' glaze effect will start to look stupid.
377 static const int MAX_HORIZONTAL_GLASS_MARGIN = 5;
379 /**************************************************************
380 **************************************************************
382 ** BLOCK: nsIWidget impl.
384 ** nsIWidget interface implementation, broken down into
385 ** sections.
387 **************************************************************
388 **************************************************************/
390 /**************************************************************
392 * SECTION: nsWindow construction and destruction
394 **************************************************************/
396 nsWindow::nsWindow() : nsBaseWidget()
398 #ifdef PR_LOGGING
399 if (!gWindowsLog)
400 gWindowsLog = PR_NewLogModule("nsWindowsWidgets");
401 #endif
403 mWnd = nsnull;
404 mPaintDC = nsnull;
405 mPrevWndProc = nsnull;
406 mOldIMC = nsnull;
407 mNativeDragTarget = nsnull;
408 mInDtor = PR_FALSE;
409 mIsVisible = PR_FALSE;
410 mIsTopWidgetWindow = PR_FALSE;
411 mUnicodeWidget = PR_TRUE;
412 mDisplayPanFeedback = PR_FALSE;
413 mTouchWindow = PR_FALSE;
414 mCustomNonClient = PR_FALSE;
415 mHideChrome = PR_FALSE;
416 mFullscreenMode = PR_FALSE;
417 mMousePresent = PR_FALSE;
418 mWindowType = eWindowType_child;
419 mBorderStyle = eBorderStyle_default;
420 mPopupType = ePopupTypeAny;
421 mOldSizeMode = nsSizeMode_Normal;
422 mLastPoint.x = 0;
423 mLastPoint.y = 0;
424 mLastSize.width = 0;
425 mLastSize.height = 0;
426 mOldStyle = 0;
427 mOldExStyle = 0;
428 mPainting = 0;
429 mLastKeyboardLayout = 0;
430 mBlurSuppressLevel = 0;
431 mIMEContext.mStatus = nsIWidget::IME_STATUS_ENABLED;
432 #ifdef MOZ_XUL
433 mTransparentSurface = nsnull;
434 mMemoryDC = nsnull;
435 mTransparencyMode = eTransparencyOpaque;
436 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
437 memset(&mGlassMargins, 0, sizeof mGlassMargins);
438 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
439 #endif
440 mBackground = ::GetSysColor(COLOR_BTNFACE);
441 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
442 mForeground = ::GetSysColor(COLOR_WINDOWTEXT);
444 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
445 mTaskbarPreview = nsnull;
446 mHasTaskbarIconBeenCreated = PR_FALSE;
447 #endif
449 // Global initialization
450 if (!sInstanceCount) {
451 #if !defined(WINCE)
452 gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
453 #endif
455 // Init IME handler
456 nsIMM32Handler::Initialize();
458 #ifdef NS_ENABLE_TSF
459 nsTextStore::Initialize();
460 #endif
462 #if !defined(WINCE)
463 if (SUCCEEDED(::OleInitialize(NULL)))
464 sIsOleInitialized = TRUE;
465 NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
466 #endif
468 #if !defined(WINCE)
469 InitInputHackDefaults();
470 #endif
472 // Init titlebar button info for custom frames.
473 nsUXThemeData::InitTitlebarInfo();
474 // Init theme data
475 nsUXThemeData::UpdateNativeThemeInfo();
477 ForgetRedirectedKeyDownMessage();
478 } // !sInstanceCount
480 mIdleService = nsnull;
482 sInstanceCount++;
485 nsWindow::~nsWindow()
487 mInDtor = PR_TRUE;
489 // If the widget was released without calling Destroy() then the native window still
490 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
492 // XXX How could this happen???
493 if (NULL != mWnd)
494 Destroy();
496 sInstanceCount--;
498 // Global shutdown
499 if (sInstanceCount == 0) {
500 #ifdef NS_ENABLE_TSF
501 nsTextStore::Terminate();
502 #endif
504 #if !defined(WINCE)
505 NS_IF_RELEASE(sCursorImgContainer);
506 if (sIsOleInitialized) {
507 ::OleFlushClipboard();
508 ::OleUninitialize();
509 sIsOleInitialized = FALSE;
511 // delete any of the IME structures that we allocated
512 nsIMM32Handler::Terminate();
513 #endif // !defined(WINCE)
516 #if !defined(WINCE)
517 NS_IF_RELEASE(mNativeDragTarget);
518 #endif // !defined(WINCE)
521 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
523 /**************************************************************
525 * SECTION: nsIWidget::Create, nsIWidget::Destroy
527 * Creating and destroying windows for this widget.
529 **************************************************************/
531 // Allow Derived classes to modify the height that is passed
532 // when the window is created or resized. Also add extra height
533 // if needed (on Windows CE)
534 PRInt32 nsWindow::GetHeight(PRInt32 aProposedHeight)
536 PRInt32 extra = 0;
538 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
539 DWORD style = WindowStyle();
540 if ((style & WS_SYSMENU) && (style & WS_POPUP)) {
541 extra = GetSystemMetrics(SM_CYCAPTION);
543 #endif
545 return aProposedHeight + extra;
548 // Create the proper widget
549 nsresult
550 nsWindow::Create(nsIWidget *aParent,
551 nsNativeWidget aNativeParent,
552 const nsIntRect &aRect,
553 EVENT_CALLBACK aHandleEventFunction,
554 nsIDeviceContext *aContext,
555 nsIAppShell *aAppShell,
556 nsIToolkit *aToolkit,
557 nsWidgetInitData *aInitData)
559 nsWidgetInitData defaultInitData;
560 if (!aInitData)
561 aInitData = &defaultInitData;
563 mUnicodeWidget = aInitData->mUnicode;
565 nsIWidget *baseParent = aInitData->mWindowType == eWindowType_dialog ||
566 aInitData->mWindowType == eWindowType_toplevel ||
567 aInitData->mWindowType == eWindowType_invisible ?
568 nsnull : aParent;
570 mIsTopWidgetWindow = (nsnull == baseParent);
571 mBounds = aRect;
573 BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
574 aAppShell, aToolkit, aInitData);
576 HWND parent;
577 if (aParent) { // has a nsIWidget parent
578 parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : NULL;
579 mParent = aParent;
580 } else { // has a nsNative parent
581 parent = (HWND)aNativeParent;
582 mParent = aNativeParent ? GetNSWindowPtr((HWND)aNativeParent) : nsnull;
585 mPopupType = aInitData->mPopupHint;
586 mIsRTL = aInitData->mRTL;
588 DWORD style = WindowStyle();
589 DWORD extendedStyle = WindowExStyle();
591 if (mWindowType == eWindowType_popup) {
592 if (!aParent)
593 parent = NULL;
594 } else if (mWindowType == eWindowType_invisible) {
595 // Make sure CreateWindowEx succeeds at creating a toplevel window
596 style &= ~0x40000000; // WS_CHILDWINDOW
597 } else {
598 // See if the caller wants to explictly set clip children and clip siblings
599 if (aInitData->clipChildren) {
600 style |= WS_CLIPCHILDREN;
601 } else {
602 style &= ~WS_CLIPCHILDREN;
604 if (aInitData->clipSiblings) {
605 style |= WS_CLIPSIBLINGS;
609 nsAutoString className;
610 if (aInitData->mDropShadow) {
611 GetWindowPopupClass(className);
612 } else {
613 GetWindowClass(className);
615 mWnd = ::CreateWindowExW(extendedStyle,
616 className.get(),
617 L"",
618 style,
619 aRect.x,
620 aRect.y,
621 aRect.width,
622 GetHeight(aRect.height),
623 parent,
624 NULL,
625 nsToolkit::mDllInstance,
626 NULL);
628 if (!mWnd) {
629 NS_WARNING("nsWindow CreateWindowEx failed.");
630 return NS_ERROR_FAILURE;
633 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
634 if (mIsRTL && nsUXThemeData::dwmSetWindowAttributePtr) {
635 DWORD dwAttribute = TRUE;
636 nsUXThemeData::dwmSetWindowAttributePtr(mWnd, DWMWA_NONCLIENT_RTL_LAYOUT, &dwAttribute, sizeof dwAttribute);
638 #endif
640 if (mWindowType != eWindowType_plugin &&
641 mWindowType != eWindowType_invisible &&
642 UseTrackPointHack()) {
643 // Ugly Thinkpad Driver Hack (Bugs 507222 and 594977)
645 // We create two zero-sized windows as descendants of the top-level window,
646 // like so:
648 // Top-level window (MozillaWindowClass)
649 // FAKETRACKPOINTSCROLLCONTAINER (MozillaWindowClass)
650 // FAKETRACKPOINTSCROLLABLE (MozillaWindowClass)
652 // We need to have the middle window, otherwise the Trackpoint driver
653 // will fail to deliver scroll messages. WM_MOUSEWHEEL messages are
654 // sent to the FAKETRACKPOINTSCROLLABLE, which then propagate up the
655 // window hierarchy until they are handled by nsWindow::WindowProc.
656 // WM_HSCROLL messages are also sent to the FAKETRACKPOINTSCROLLABLE,
657 // but these do not propagate automatically, so we have the window
658 // procedure pretend that they were dispatched to the top-level window
659 // instead.
661 // The FAKETRACKPOINTSCROLLABLE needs to have the specific window styles it
662 // is given below so that it catches the Trackpoint driver's heuristics.
663 HWND scrollContainerWnd = ::CreateWindowW
664 (className.get(), L"FAKETRACKPOINTSCROLLCONTAINER",
665 WS_CHILD | WS_VISIBLE,
666 0, 0, 0, 0, mWnd, NULL, nsToolkit::mDllInstance, NULL);
667 HWND scrollableWnd = ::CreateWindowW
668 (className.get(), L"FAKETRACKPOINTSCROLLABLE",
669 WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | 0x30,
670 0, 0, 0, 0, scrollContainerWnd, NULL, nsToolkit::mDllInstance, NULL);
672 // Give the FAKETRACKPOINTSCROLLABLE window a specific ID so that
673 // WindowProcInternal can distinguish it from the top-level window
674 // easily.
675 ::SetWindowLongPtrW(scrollableWnd, GWLP_ID, eFakeTrackPointScrollableID);
677 // Make FAKETRACKPOINTSCROLLABLE use nsWindow::WindowProc, and store the
678 // old window procedure in its "user data".
679 WNDPROC oldWndProc;
680 if (mUnicodeWidget)
681 oldWndProc = (WNDPROC)::SetWindowLongPtrW(scrollableWnd, GWLP_WNDPROC,
682 (LONG_PTR)nsWindow::WindowProc);
683 else
684 oldWndProc = (WNDPROC)::SetWindowLongPtrA(scrollableWnd, GWLP_WNDPROC,
685 (LONG_PTR)nsWindow::WindowProc);
686 ::SetWindowLongPtrW(scrollableWnd, GWLP_USERDATA, (LONG_PTR)oldWndProc);
689 // call the event callback to notify about creation
691 DispatchStandardEvent(NS_CREATE);
692 SubclassWindow(TRUE);
694 if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
695 /* The internal variable set by the config.trim_on_minimize pref
696 has not yet been initialized, and this is the hidden window
697 (conveniently created before any visible windows, and after
698 the profile has been initialized).
700 Default config.trim_on_minimize to false, to fix bug 76831
701 for good. If anyone complains about this new default, saying
702 that a Mozilla app hogs too much memory while minimized, they
703 will have that entire bug tattooed on their backside. */
705 sTrimOnMinimize = 0;
706 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
707 if (prefs) {
708 nsCOMPtr<nsIPrefBranch> prefBranch;
709 prefs->GetBranch(0, getter_AddRefs(prefBranch));
710 if (prefBranch) {
712 PRBool temp;
713 if (NS_SUCCEEDED(prefBranch->GetBoolPref("config.trim_on_minimize",
714 &temp))
715 && temp)
716 sTrimOnMinimize = 1;
718 if (NS_SUCCEEDED(prefBranch->GetBoolPref("intl.keyboard.per_window_layout",
719 &temp)))
720 sSwitchKeyboardLayout = temp;
722 if (NS_SUCCEEDED(prefBranch->GetBoolPref("mozilla.widget.disable-native-theme",
723 &temp)))
724 gDisableNativeTheme = temp;
728 #if defined(WINCE_HAVE_SOFTKB)
729 if (mWindowType == eWindowType_dialog || mWindowType == eWindowType_toplevel )
730 nsWindowCE::CreateSoftKeyMenuBar(mWnd);
731 #endif
733 return NS_OK;
736 // Close this nsWindow
737 NS_METHOD nsWindow::Destroy()
739 // WM_DESTROY has already fired, we're done.
740 if (nsnull == mWnd)
741 return NS_OK;
743 // During the destruction of all of our children, make sure we don't get deleted.
744 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
747 * On windows the LayerManagerOGL destructor wants the widget to be around for
748 * cleanup. It also would like to have the HWND intact, so we NULL it here.
750 if (mLayerManager) {
751 mLayerManager->Destroy();
753 mLayerManager = nsnull;
755 /* We should clear our cached resources now and not wait for the GC to
756 * delete the nsWindow. */
757 ClearCachedResources();
759 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
760 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
761 // from it. The function also destroys the window's menu, flushes the thread message queue,
762 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
763 // the window is at the top of the viewer chain).
765 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
766 // the associated child or owned windows when it destroys the parent or owner window. The
767 // function first destroys child or owned windows, and then it destroys the parent or owner
768 // window.
769 VERIFY(::DestroyWindow(mWnd));
771 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
772 // didn't get called, call it now.
773 if (PR_FALSE == mOnDestroyCalled) {
774 LRESULT result;
775 mWindowHook.Notify(mWnd, WM_DESTROY, 0, 0, &result);
776 OnDestroy();
779 return NS_OK;
782 /**************************************************************
784 * SECTION: Window class utilities
786 * Utilities for calculating the proper window class name for
787 * Create window.
789 **************************************************************/
791 void nsWindow::RegisterWindowClass(const nsString& aClassName, UINT aExtraStyle,
792 LPWSTR aIconID)
794 WNDCLASSW wc;
795 if (::GetClassInfoW(nsToolkit::mDllInstance, aClassName.get(), &wc)) {
796 // already registered
797 return;
800 wc.style = CS_DBLCLKS | aExtraStyle;
801 wc.lpfnWndProc = ::DefWindowProcW;
802 wc.cbClsExtra = 0;
803 wc.cbWndExtra = 0;
804 wc.hInstance = nsToolkit::mDllInstance;
805 wc.hIcon = aIconID ? ::LoadIconW(::GetModuleHandleW(NULL), aIconID) : NULL;
806 wc.hCursor = NULL;
807 wc.hbrBackground = mBrush;
808 wc.lpszMenuName = NULL;
809 wc.lpszClassName = aClassName.get();
811 if (!::RegisterClassW(&wc)) {
812 // For older versions of Win32 (i.e., not XP), the registration may
813 // fail with aExtraStyle, so we have to re-register without it.
814 wc.style = CS_DBLCLKS;
815 ::RegisterClassW(&wc);
819 static LPWSTR const gStockApplicationIcon = MAKEINTRESOURCEW(32512);
821 // Return the proper window class for everything except popups.
822 void nsWindow::GetWindowClass(nsString& aWindowClass)
824 switch (mWindowType) {
825 case eWindowType_invisible:
826 aWindowClass.AssignLiteral(kClassNameHidden);
827 RegisterWindowClass(aWindowClass, 0, gStockApplicationIcon);
828 break;
829 case eWindowType_dialog:
830 aWindowClass.AssignLiteral(kClassNameDialog);
831 RegisterWindowClass(aWindowClass, 0, 0);
832 break;
833 default:
834 GetMainWindowClass(aWindowClass);
835 RegisterWindowClass(aWindowClass, 0, gStockApplicationIcon);
836 break;
840 // Return the proper popup window class
841 void nsWindow::GetWindowPopupClass(nsString& aWindowClass)
843 aWindowClass.AssignLiteral(kClassNameDropShadow);
844 RegisterWindowClass(aWindowClass, CS_XP_DROPSHADOW, gStockApplicationIcon);
847 /**************************************************************
849 * SECTION: Window styles utilities
851 * Return the proper windows styles and extended styles.
853 **************************************************************/
855 // Return nsWindow styles
856 #if !defined(WINCE) // implemented in nsWindowCE.cpp
857 DWORD nsWindow::WindowStyle()
859 DWORD style;
861 switch (mWindowType) {
862 case eWindowType_plugin:
863 case eWindowType_child:
864 style = WS_OVERLAPPED;
865 break;
867 case eWindowType_dialog:
868 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK |
869 DS_MODALFRAME | WS_CLIPCHILDREN;
870 if (mBorderStyle != eBorderStyle_default)
871 style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
872 break;
874 case eWindowType_popup:
875 style = WS_POPUP;
876 if (!HasGlass()) {
877 style |= WS_OVERLAPPED;
879 break;
881 default:
882 NS_ERROR("unknown border style");
883 // fall through
885 case eWindowType_toplevel:
886 case eWindowType_invisible:
887 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU |
888 WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
889 break;
892 if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) {
893 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border))
894 style &= ~WS_BORDER;
896 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) {
897 style &= ~WS_DLGFRAME;
898 style |= WS_POPUP;
899 style &= ~WS_CHILD;
902 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close))
903 style &= ~0;
904 // XXX The close box can only be removed by changing the window class,
905 // as far as I know --- roc+moz@cs.cmu.edu
907 if (mBorderStyle == eBorderStyle_none ||
908 !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
909 style &= ~WS_SYSMENU;
910 // Looks like getting rid of the system menu also does away with the
911 // close box. So, we only get rid of the system menu if you want neither it
912 // nor the close box. How does the Windows "Dialog" window class get just
913 // closebox and no sysmenu? Who knows.
915 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh))
916 style &= ~WS_THICKFRAME;
918 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize))
919 style &= ~WS_MINIMIZEBOX;
921 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize))
922 style &= ~WS_MAXIMIZEBOX;
924 if (IsPopupWithTitleBar()) {
925 style |= WS_CAPTION;
926 if (mBorderStyle & eBorderStyle_close) {
927 style |= WS_SYSMENU;
932 VERIFY_WINDOW_STYLE(style);
933 return style;
935 #endif // !defined(WINCE)
937 // Return nsWindow extended styles
938 DWORD nsWindow::WindowExStyle()
940 switch (mWindowType)
942 case eWindowType_plugin:
943 case eWindowType_child:
944 return 0;
946 case eWindowType_dialog:
947 return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
949 case eWindowType_popup:
951 DWORD extendedStyle =
952 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
953 WS_EX_NOACTIVATE |
954 #endif
955 WS_EX_TOOLWINDOW;
956 if (mPopupLevel == ePopupLevelTop)
957 extendedStyle |= WS_EX_TOPMOST;
958 return extendedStyle;
960 default:
961 NS_ERROR("unknown border style");
962 // fall through
964 case eWindowType_toplevel:
965 case eWindowType_invisible:
966 return WS_EX_WINDOWEDGE;
970 /**************************************************************
972 * SECTION: Window subclassing utilities
974 * Set or clear window subclasses on native windows. Used in
975 * Create and Destroy.
977 **************************************************************/
979 // Subclass (or remove the subclass from) this component's nsWindow
980 void nsWindow::SubclassWindow(BOOL bState)
982 if (NULL != mWnd) {
983 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
984 if (!::IsWindow(mWnd)) {
985 NS_ERROR("Invalid window handle");
988 if (bState) {
989 // change the nsWindow proc
990 if (mUnicodeWidget)
991 mPrevWndProc = (WNDPROC)::SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
992 (LONG_PTR)nsWindow::WindowProc);
993 else
994 mPrevWndProc = (WNDPROC)::SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
995 (LONG_PTR)nsWindow::WindowProc);
996 NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
997 // connect the this pointer to the nsWindow handle
998 SetNSWindowPtr(mWnd, this);
1000 else {
1001 if (mUnicodeWidget)
1002 ::SetWindowLongPtrW(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
1003 else
1004 ::SetWindowLongPtrA(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
1005 SetNSWindowPtr(mWnd, NULL);
1006 mPrevWndProc = NULL;
1011 /**************************************************************
1013 * SECTION: Window properties
1015 * Set and clear native window properties.
1017 **************************************************************/
1019 static PRUnichar sPropName[40] = L"";
1020 static PRUnichar* GetNSWindowPropName()
1022 if (!*sPropName)
1024 _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p", GetCurrentProcessId());
1025 sPropName[39] = '\0';
1027 return sPropName;
1030 nsWindow * nsWindow::GetNSWindowPtr(HWND aWnd)
1032 return (nsWindow *) ::GetPropW(aWnd, GetNSWindowPropName());
1035 BOOL nsWindow::SetNSWindowPtr(HWND aWnd, nsWindow * ptr)
1037 if (ptr == NULL) {
1038 ::RemovePropW(aWnd, GetNSWindowPropName());
1039 return TRUE;
1040 } else {
1041 return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)ptr);
1045 /**************************************************************
1047 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
1049 * Set or clear the parent widgets using window properties, and
1050 * handles calculating native parent handles.
1052 **************************************************************/
1054 // Get and set parent widgets
1055 NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent)
1057 mParent = aNewParent;
1059 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1060 nsIWidget* parent = GetParent();
1061 if (parent) {
1062 parent->RemoveChild(this);
1064 if (aNewParent) {
1065 ReparentNativeWidget(aNewParent);
1066 aNewParent->AddChild(this);
1067 return NS_OK;
1069 if (mWnd) {
1070 // If we have no parent, SetParent should return the desktop.
1071 VERIFY(::SetParent(mWnd, nsnull));
1073 return NS_OK;
1076 NS_IMETHODIMP
1077 nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
1079 NS_PRECONDITION(aNewParent, "");
1081 mParent = aNewParent;
1082 if (mWindowType == eWindowType_popup) {
1083 return NS_OK;
1085 HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
1086 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
1087 if (newParent && mWnd) {
1088 ::SetParent(mWnd, newParent);
1090 return NS_OK;
1093 nsIWidget* nsWindow::GetParent(void)
1095 return GetParentWindow(PR_FALSE);
1098 float nsWindow::GetDPI()
1100 HDC dc = ::GetDC(mWnd);
1101 if (!dc)
1102 return 96.0f;
1104 double heightInches = ::GetDeviceCaps(dc, VERTSIZE)/MM_PER_INCH_FLOAT;
1105 int heightPx = ::GetDeviceCaps(dc, VERTRES);
1106 ::ReleaseDC(mWnd, dc);
1107 if (heightInches < 0.25) {
1108 // Something's broken
1109 return 96.0f;
1111 return float(heightPx/heightInches);
1114 nsWindow* nsWindow::GetParentWindow(PRBool aIncludeOwner)
1116 if (mIsTopWidgetWindow) {
1117 // Must use a flag instead of mWindowType to tell if the window is the
1118 // owned by the topmost widget, because a child window can be embedded inside
1119 // a HWND which is not associated with a nsIWidget.
1120 return nsnull;
1123 // If this widget has already been destroyed, pretend we have no parent.
1124 // This corresponds to code in Destroy which removes the destroyed
1125 // widget from its parent's child list.
1126 if (mInDtor || mOnDestroyCalled)
1127 return nsnull;
1130 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1131 // root owner. aIncludeOwner set to false implies the search will stop at the
1132 // true parent (default).
1133 nsWindow* widget = nsnull;
1134 if (mWnd) {
1135 #ifdef WINCE
1136 HWND parent = ::GetParent(mWnd);
1137 #else
1138 HWND parent = nsnull;
1139 if (aIncludeOwner)
1140 parent = ::GetParent(mWnd);
1141 else
1142 parent = ::GetAncestor(mWnd, GA_PARENT);
1143 #endif
1144 if (parent) {
1145 widget = GetNSWindowPtr(parent);
1146 if (widget) {
1147 // If the widget is in the process of being destroyed then
1148 // do NOT return it
1149 if (widget->mInDtor) {
1150 widget = nsnull;
1156 return widget;
1159 BOOL CALLBACK
1160 nsWindow::EnumAllChildWindProc(HWND aWnd, LPARAM aParam)
1162 nsWindow *wnd = nsWindow::GetNSWindowPtr(aWnd);
1163 if (wnd) {
1164 ((nsWindow::WindowEnumCallback*)aParam)(wnd);
1166 return TRUE;
1169 BOOL CALLBACK
1170 nsWindow::EnumAllThreadWindowProc(HWND aWnd, LPARAM aParam)
1172 nsWindow *wnd = nsWindow::GetNSWindowPtr(aWnd);
1173 if (wnd) {
1174 ((nsWindow::WindowEnumCallback*)aParam)(wnd);
1176 EnumChildWindows(aWnd, EnumAllChildWindProc, aParam);
1177 return TRUE;
1180 void
1181 nsWindow::EnumAllWindows(WindowEnumCallback aCallback)
1183 EnumThreadWindows(GetCurrentThreadId(),
1184 EnumAllThreadWindowProc,
1185 (LPARAM)&aCallback);
1188 /**************************************************************
1190 * SECTION: nsIWidget::Show
1192 * Hide or show this component.
1194 **************************************************************/
1196 NS_METHOD nsWindow::Show(PRBool bState)
1198 #if defined(MOZ_SPLASHSCREEN)
1199 // we're about to show the first toplevel window,
1200 // so kill off any splash screen if we had one
1201 nsSplashScreen *splash = nsSplashScreen::Get();
1202 if (splash && splash->IsOpen() && mWnd && bState &&
1203 (mWindowType == eWindowType_toplevel ||
1204 mWindowType == eWindowType_dialog ||
1205 mWindowType == eWindowType_popup))
1207 splash->Close();
1209 #endif
1211 #ifdef NS_FUNCTION_TIMER
1212 static bool firstShow = true;
1213 if (firstShow &&
1214 (mWindowType == eWindowType_toplevel ||
1215 mWindowType == eWindowType_dialog ||
1216 mWindowType == eWindowType_popup))
1218 firstShow = false;
1219 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1221 #endif
1223 PRBool wasVisible = mIsVisible;
1224 // Set the status now so that anyone asking during ShowWindow or
1225 // SetWindowPos would get the correct answer.
1226 mIsVisible = bState;
1228 if (!mIsVisible && wasVisible) {
1229 ClearCachedResources();
1232 if (mWnd) {
1233 if (bState) {
1234 if (!wasVisible && mWindowType == eWindowType_toplevel) {
1235 switch (mSizeMode) {
1236 #ifdef WINCE
1237 case nsSizeMode_Fullscreen:
1238 ::SetForegroundWindow(mWnd);
1239 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1240 MakeFullScreen(TRUE);
1241 break;
1243 case nsSizeMode_Maximized :
1244 ::SetForegroundWindow(mWnd);
1245 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1246 break;
1247 // use default for nsSizeMode_Minimized on Windows CE
1248 #else
1249 case nsSizeMode_Maximized :
1250 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1251 break;
1252 case nsSizeMode_Minimized :
1253 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
1254 break;
1255 #endif
1256 default:
1257 if (CanTakeFocus()) {
1258 #ifdef WINCE
1259 ::SetForegroundWindow(mWnd);
1260 #endif
1261 ::ShowWindow(mWnd, SW_SHOWNORMAL);
1262 } else {
1263 // Place the window behind the foreground window
1264 // (as long as it is not topmost)
1265 HWND wndAfter = ::GetForegroundWindow();
1266 if (!wndAfter)
1267 wndAfter = HWND_BOTTOM;
1268 else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)
1269 wndAfter = HWND_TOP;
1270 ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE |
1271 SWP_NOMOVE | SWP_NOACTIVATE);
1272 GetAttention(2);
1274 break;
1276 } else {
1277 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
1278 if (wasVisible)
1279 flags |= SWP_NOZORDER;
1281 if (mWindowType == eWindowType_popup) {
1282 #ifndef WINCE
1283 // ensure popups are the topmost of the TOPMOST
1284 // layer. Remember not to set the SWP_NOZORDER
1285 // flag as that might allow the taskbar to overlap
1286 // the popup. However on windows ce, we need to
1287 // activate the popup or clicks will not be sent.
1288 flags |= SWP_NOACTIVATE;
1289 #endif
1290 HWND owner = ::GetWindow(mWnd, GW_OWNER);
1291 ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
1292 } else {
1293 #ifndef WINCE
1294 if (mWindowType == eWindowType_dialog && !CanTakeFocus())
1295 flags |= SWP_NOACTIVATE;
1296 #endif
1297 ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
1301 #ifndef WINCE
1302 if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) {
1303 // when a toplevel window or dialog is shown, initialize the UI state
1304 ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
1306 #endif
1307 } else {
1308 if (mWindowType != eWindowType_dialog) {
1309 ::ShowWindow(mWnd, SW_HIDE);
1310 } else {
1311 ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1312 SWP_NOZORDER | SWP_NOACTIVATE);
1317 #ifdef MOZ_XUL
1318 if (!wasVisible && bState)
1319 Invalidate(PR_FALSE);
1320 #endif
1322 return NS_OK;
1325 /**************************************************************
1327 * SECTION: nsIWidget::IsVisible
1329 * Returns the visibility state.
1331 **************************************************************/
1333 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1334 NS_METHOD nsWindow::IsVisible(PRBool & bState)
1336 bState = mIsVisible;
1337 return NS_OK;
1340 /**************************************************************
1342 * SECTION: Window clipping utilities
1344 * Used in Size and Move operations for setting the proper
1345 * window clipping regions for window transparency.
1347 **************************************************************/
1349 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1350 // transparency. These routines are called on size and move operations.
1351 void nsWindow::ClearThemeRegion()
1353 #ifndef WINCE
1354 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1355 (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1356 (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1357 SetWindowRgn(mWnd, NULL, false);
1359 #endif
1362 void nsWindow::SetThemeRegion()
1364 #ifndef WINCE
1365 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1366 // for other window types as needed. The regions are applied generically to the base window
1367 // so default constants are used for part and state. At some point we might need part and
1368 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1369 // change shape based on state haven't come up.
1370 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1371 (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1372 (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1373 HRGN hRgn = nsnull;
1374 RECT rect = {0,0,mBounds.width,mBounds.height};
1376 HDC dc = ::GetDC(mWnd);
1377 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
1378 if (hRgn) {
1379 if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted.
1380 DeleteObject(hRgn);
1382 ::ReleaseDC(mWnd, dc);
1384 #endif
1387 /**************************************************************
1389 * SECTION: nsIWidget::RegisterTouchWindow,
1390 * nsIWidget::UnregisterTouchWindow, and helper functions
1392 * Used to register the native window to receive touch events
1394 **************************************************************/
1396 NS_METHOD nsWindow::RegisterTouchWindow() {
1397 mTouchWindow = PR_TRUE;
1398 #ifndef WINCE
1399 mGesture.RegisterTouchWindow(mWnd);
1400 ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
1401 #endif
1402 return NS_OK;
1405 NS_METHOD nsWindow::UnregisterTouchWindow() {
1406 mTouchWindow = PR_FALSE;
1407 #ifndef WINCE
1408 mGesture.UnregisterTouchWindow(mWnd);
1409 ::EnumChildWindows(mWnd, nsWindow::UnregisterTouchForDescendants, 0);
1410 #endif
1411 return NS_OK;
1414 #ifndef WINCE
1415 BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1416 nsWindow* win = GetNSWindowPtr(aWnd);
1417 if (win)
1418 win->mGesture.RegisterTouchWindow(aWnd);
1419 return TRUE;
1422 BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1423 nsWindow* win = GetNSWindowPtr(aWnd);
1424 if (win)
1425 win->mGesture.UnregisterTouchWindow(aWnd);
1426 return TRUE;
1428 #endif
1430 /**************************************************************
1432 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1433 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1435 * Repositioning and sizing a window.
1437 **************************************************************/
1439 // Move this component
1440 NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
1442 if (mWindowType == eWindowType_toplevel ||
1443 mWindowType == eWindowType_dialog) {
1444 SetSizeMode(nsSizeMode_Normal);
1446 // Check to see if window needs to be moved first
1447 // to avoid a costly call to SetWindowPos. This check
1448 // can not be moved to the calling code in nsView, because
1449 // some platforms do not position child windows correctly
1451 // Only perform this check for non-popup windows, since the positioning can
1452 // in fact change even when the x/y do not. We always need to perform the
1453 // check. See bug #97805 for details.
1454 if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
1456 // Nothing to do, since it is already positioned correctly.
1457 return NS_OK;
1460 mBounds.x = aX;
1461 mBounds.y = aY;
1463 if (mWnd) {
1464 #ifdef DEBUG
1465 // complain if a window is moved offscreen (legal, but potentially worrisome)
1466 if (mIsTopWidgetWindow) { // only a problem for top-level windows
1467 // Make sure this window is actually on the screen before we move it
1468 // XXX: Needs multiple monitor support
1469 HDC dc = ::GetDC(mWnd);
1470 if (dc) {
1471 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1472 RECT workArea;
1473 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1474 // no annoying assertions. just mention the issue.
1475 if (aX < 0 || aX >= workArea.right || aY < 0 || aY >= workArea.bottom)
1476 printf("window moved to offscreen position\n");
1478 ::ReleaseDC(mWnd, dc);
1481 #endif
1482 ClearThemeRegion();
1484 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE;
1485 // Workaround SetWindowPos bug with D3D9. If our window has a clip
1486 // region, some drivers or OSes may incorrectly copy into the clipped-out
1487 // area.
1488 if (mWindowType == eWindowType_plugin &&
1489 (!mLayerManager || mLayerManager->GetBackendType() == LayerManager::LAYERS_D3D9) &&
1490 mClipRects &&
1491 (mClipRectCount != 1 || mClipRects[0] != nsIntRect(0, 0, mBounds.width, mBounds.height))) {
1492 flags |= SWP_NOCOPYBITS;
1494 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0, flags));
1496 SetThemeRegion();
1498 return NS_OK;
1501 // Resize this component
1502 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1504 NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
1505 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1507 // Avoid unnecessary resizing calls
1508 if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1509 return NS_OK;
1511 #ifdef MOZ_XUL
1512 if (eTransparencyTransparent == mTransparencyMode)
1513 ResizeTranslucentWindow(aWidth, aHeight);
1514 #endif
1516 // Set cached value for lightweight and printing
1517 mBounds.width = aWidth;
1518 mBounds.height = aHeight;
1520 if (mWnd) {
1521 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
1523 #ifndef WINCE
1524 if (!aRepaint) {
1525 flags |= SWP_NOREDRAW;
1527 #endif
1529 ClearThemeRegion();
1530 VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
1531 SetThemeRegion();
1534 if (aRepaint)
1535 Invalidate(PR_FALSE);
1537 return NS_OK;
1540 // Resize this component
1541 NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1543 NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize");
1544 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1546 // Avoid unnecessary resizing calls
1547 if (mBounds.x == aX && mBounds.y == aY &&
1548 mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1549 return NS_OK;
1551 #ifdef MOZ_XUL
1552 if (eTransparencyTransparent == mTransparencyMode)
1553 ResizeTranslucentWindow(aWidth, aHeight);
1554 #endif
1556 // Set cached value for lightweight and printing
1557 mBounds.x = aX;
1558 mBounds.y = aY;
1559 mBounds.width = aWidth;
1560 mBounds.height = aHeight;
1562 if (mWnd) {
1563 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
1564 #ifndef WINCE
1565 if (!aRepaint) {
1566 flags |= SWP_NOREDRAW;
1568 #endif
1570 ClearThemeRegion();
1571 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
1572 SetThemeRegion();
1575 if (aRepaint)
1576 Invalidate(PR_FALSE);
1578 return NS_OK;
1581 // Resize the client area and position the widget within it's parent
1582 NS_METHOD nsWindow::ResizeClient(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1584 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1585 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1587 // Adjust our existing window bounds, based on the new client dims.
1588 RECT client;
1589 GetClientRect(mWnd, &client);
1590 nsIntPoint dims(client.right - client.left, client.bottom - client.top);
1591 aWidth = mBounds.width + (aWidth - dims.x);
1592 aHeight = mBounds.height + (aHeight - dims.y);
1594 if (aX || aY) {
1595 // offsets
1596 nsIntRect bounds;
1597 GetScreenBounds(bounds);
1598 aX += bounds.x;
1599 aY += bounds.y;
1600 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1602 return Resize(aWidth, aHeight, aRepaint);
1605 #if !defined(WINCE)
1606 NS_IMETHODIMP
1607 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
1609 NS_ENSURE_ARG_POINTER(aEvent);
1611 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
1612 // you can only begin a resize drag with a mouse event
1613 return NS_ERROR_INVALID_ARG;
1616 nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
1617 if (mouseEvent->button != nsMouseEvent::eLeftButton) {
1618 // you can only begin a resize drag with the left mouse button
1619 return NS_ERROR_INVALID_ARG;
1622 // work out what sizemode we're talking about
1623 WPARAM syscommand;
1624 if (aVertical < 0) {
1625 if (aHorizontal < 0) {
1626 syscommand = SC_SIZE | WMSZ_TOPLEFT;
1627 } else if (aHorizontal == 0) {
1628 syscommand = SC_SIZE | WMSZ_TOP;
1629 } else {
1630 syscommand = SC_SIZE | WMSZ_TOPRIGHT;
1632 } else if (aVertical == 0) {
1633 if (aHorizontal < 0) {
1634 syscommand = SC_SIZE | WMSZ_LEFT;
1635 } else if (aHorizontal == 0) {
1636 return NS_ERROR_INVALID_ARG;
1637 } else {
1638 syscommand = SC_SIZE | WMSZ_RIGHT;
1640 } else {
1641 if (aHorizontal < 0) {
1642 syscommand = SC_SIZE | WMSZ_BOTTOMLEFT;
1643 } else if (aHorizontal == 0) {
1644 syscommand = SC_SIZE | WMSZ_BOTTOM;
1645 } else {
1646 syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT;
1650 // resizing doesn't work if the mouse is already captured
1651 CaptureMouse(PR_FALSE);
1653 // find the top-level window
1654 HWND toplevelWnd = GetTopLevelHWND(mWnd, PR_TRUE);
1656 // tell Windows to start the resize
1657 ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand,
1658 POINTTOPOINTS(aEvent->refPoint));
1660 return NS_OK;
1662 #endif
1663 /**************************************************************
1665 * SECTION: Window Z-order and state.
1667 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1668 * nsIWidget::ConstrainPosition
1670 * Z-order, positioning, restore, minimize, and maximize.
1672 **************************************************************/
1674 // Position the window behind the given window
1675 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1676 nsIWidget *aWidget, PRBool aActivate)
1678 HWND behind = HWND_TOP;
1679 if (aPlacement == eZPlacementBottom)
1680 behind = HWND_BOTTOM;
1681 else if (aPlacement == eZPlacementBelow && aWidget)
1682 behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
1683 UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
1684 if (!aActivate)
1685 flags |= SWP_NOACTIVATE;
1687 if (!CanTakeFocus() && behind == HWND_TOP)
1689 // Can't place the window to top so place it behind the foreground window
1690 // (as long as it is not topmost)
1691 HWND wndAfter = ::GetForegroundWindow();
1692 if (!wndAfter)
1693 behind = HWND_BOTTOM;
1694 else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
1695 behind = wndAfter;
1696 flags |= SWP_NOACTIVATE;
1699 ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
1700 return NS_OK;
1703 // Maximize, minimize or restore the window.
1704 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1705 NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode) {
1707 nsresult rv;
1709 // Let's not try and do anything if we're already in that state.
1710 // (This is needed to prevent problems when calling window.minimize(), which
1711 // calls us directly, and then the OS triggers another call to us.)
1712 if (aMode == mSizeMode)
1713 return NS_OK;
1715 // save the requested state
1716 rv = nsBaseWidget::SetSizeMode(aMode);
1717 if (NS_SUCCEEDED(rv) && mIsVisible) {
1718 int mode;
1720 switch (aMode) {
1721 case nsSizeMode_Fullscreen :
1722 mode = SW_SHOW;
1723 break;
1725 case nsSizeMode_Maximized :
1726 mode = SW_MAXIMIZE;
1727 break;
1729 case nsSizeMode_Minimized :
1730 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1731 // keeps the window active in the tray. So after the window is minimized,
1732 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1733 // we will do some additional processing to get the active window set right.
1734 // If sTrimOnMinimize is set, we let windows handle minimization normally
1735 // using SW_MINIMIZE.
1736 mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED;
1737 break;
1739 default :
1740 mode = SW_RESTORE;
1742 ::ShowWindow(mWnd, mode);
1743 // we dispatch an activate event here to ensure that the right child window
1744 // is focused
1745 if (mode == SW_RESTORE || mode == SW_MAXIMIZE)
1746 DispatchFocusToTopLevelWindow(NS_ACTIVATE);
1748 return rv;
1750 #endif // !defined(WINCE)
1752 // Constrain a potential move to fit onscreen
1753 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop,
1754 PRInt32 *aX, PRInt32 *aY)
1756 if (!mIsTopWidgetWindow) // only a problem for top-level windows
1757 return NS_OK;
1759 PRBool doConstrain = PR_FALSE; // whether we have enough info to do anything
1761 /* get our playing field. use the current screen, or failing that
1762 for any reason, use device caps for the default screen. */
1763 RECT screenRect;
1765 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
1766 if (screenmgr) {
1767 nsCOMPtr<nsIScreen> screen;
1768 PRInt32 left, top, width, height;
1770 // zero size rects confuse the screen manager
1771 width = mBounds.width > 0 ? mBounds.width : 1;
1772 height = mBounds.height > 0 ? mBounds.height : 1;
1773 screenmgr->ScreenForRect(*aX, *aY, width, height,
1774 getter_AddRefs(screen));
1775 if (screen) {
1776 if (mSizeMode != nsSizeMode_Fullscreen) {
1777 // For normalized windows, use the desktop work area.
1778 screen->GetAvailRect(&left, &top, &width, &height);
1779 } else {
1780 // For full screen windows, use the desktop.
1781 screen->GetRect(&left, &top, &width, &height);
1783 screenRect.left = left;
1784 screenRect.right = left+width;
1785 screenRect.top = top;
1786 screenRect.bottom = top+height;
1787 doConstrain = PR_TRUE;
1789 } else {
1790 if (mWnd) {
1791 HDC dc = ::GetDC(mWnd);
1792 if (dc) {
1793 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1794 if (mSizeMode != nsSizeMode_Fullscreen) {
1795 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
1796 } else {
1797 screenRect.left = screenRect.top = 0;
1798 screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN);
1799 screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
1801 doConstrain = PR_TRUE;
1803 ::ReleaseDC(mWnd, dc);
1808 if (aAllowSlop) {
1809 if (*aX < screenRect.left - mBounds.width + kWindowPositionSlop)
1810 *aX = screenRect.left - mBounds.width + kWindowPositionSlop;
1811 else if (*aX >= screenRect.right - kWindowPositionSlop)
1812 *aX = screenRect.right - kWindowPositionSlop;
1814 if (*aY < screenRect.top - mBounds.height + kWindowPositionSlop)
1815 *aY = screenRect.top - mBounds.height + kWindowPositionSlop;
1816 else if (*aY >= screenRect.bottom - kWindowPositionSlop)
1817 *aY = screenRect.bottom - kWindowPositionSlop;
1819 } else {
1821 if (*aX < screenRect.left)
1822 *aX = screenRect.left;
1823 else if (*aX >= screenRect.right - mBounds.width)
1824 *aX = screenRect.right - mBounds.width;
1826 if (*aY < screenRect.top)
1827 *aY = screenRect.top;
1828 else if (*aY >= screenRect.bottom - mBounds.height)
1829 *aY = screenRect.bottom - mBounds.height;
1832 return NS_OK;
1835 /**************************************************************
1837 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1839 * Enabling and disabling the widget.
1841 **************************************************************/
1843 // Enable/disable this component
1844 NS_METHOD nsWindow::Enable(PRBool bState)
1846 if (mWnd) {
1847 ::EnableWindow(mWnd, bState);
1849 return NS_OK;
1852 // Return the current enable state
1853 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
1855 NS_ENSURE_ARG_POINTER(aState);
1857 #ifndef WINCE
1858 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT)));
1859 #else
1860 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(mWnd));
1861 #endif
1863 return NS_OK;
1867 /**************************************************************
1869 * SECTION: nsIWidget::SetFocus
1871 * Give the focus to this widget.
1873 **************************************************************/
1875 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
1877 if (mWnd) {
1878 #ifdef WINSTATE_DEBUG_OUTPUT
1879 if (mWnd == GetTopLevelHWND(mWnd))
1880 printf("*** SetFocus: [ top] raise=%d\n", aRaise);
1881 else
1882 printf("*** SetFocus: [child] raise=%d\n", aRaise);
1883 #endif
1884 // Uniconify, if necessary
1885 HWND toplevelWnd = GetTopLevelHWND(mWnd);
1886 if (aRaise && ::IsIconic(toplevelWnd)) {
1887 ::ShowWindow(toplevelWnd, SW_RESTORE);
1889 ::SetFocus(mWnd);
1891 return NS_OK;
1895 /**************************************************************
1897 * SECTION: Bounds
1899 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1900 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1902 * Bound calculations.
1904 **************************************************************/
1906 // Return the window's full dimensions in screen coordinates.
1907 // If the window has a parent, converts the origin to an offset
1908 // of the parent's screen origin.
1909 NS_METHOD nsWindow::GetBounds(nsIntRect &aRect)
1911 if (mWnd) {
1912 RECT r;
1913 VERIFY(::GetWindowRect(mWnd, &r));
1915 // assign size
1916 aRect.width = r.right - r.left;
1917 aRect.height = r.bottom - r.top;
1919 // chrome on parent:
1920 // ___ 5,5 (chrome start)
1921 // | ____ 10,10 (client start)
1922 // | | ____ 20,20 (child start)
1923 // | | |
1924 // 20,20 - 5,5 = 15,15 (??)
1925 // minus GetClientOffset:
1926 // 15,15 - 5,5 = 10,10
1928 // no chrome on parent:
1929 // ______ 10,10 (win start)
1930 // | ____ 20,20 (child start)
1931 // | |
1932 // 20,20 - 10,10 = 10,10
1934 // walking the chain:
1935 // ___ 5,5 (chrome start)
1936 // | ___ 10,10 (client start)
1937 // | | ___ 20,20 (child start)
1938 // | | | __ 30,30 (child start)
1939 // | | | |
1940 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1941 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1942 // minus GetClientOffset:
1943 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1945 // convert coordinates if parent exists
1946 HWND parent = ::GetParent(mWnd);
1947 if (parent) {
1948 RECT pr;
1949 VERIFY(::GetWindowRect(parent, &pr));
1950 r.left -= pr.left;
1951 r.top -= pr.top;
1952 // adjust for chrome
1953 nsWindow* pWidget = static_cast<nsWindow*>(GetParent());
1954 if (pWidget && pWidget->IsTopLevelWidget()) {
1955 nsIntPoint clientOffset = pWidget->GetClientOffset();
1956 r.left -= clientOffset.x;
1957 r.top -= clientOffset.y;
1960 aRect.x = r.left;
1961 aRect.y = r.top;
1962 } else {
1963 aRect = mBounds;
1966 return NS_OK;
1969 // Get this component dimension
1970 NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect)
1972 if (mWnd) {
1973 RECT r;
1974 VERIFY(::GetClientRect(mWnd, &r));
1976 // assign size
1977 aRect.x = 0;
1978 aRect.y = 0;
1979 aRect.width = r.right - r.left;
1980 aRect.height = r.bottom - r.top;
1982 } else {
1983 aRect.SetRect(0,0,0,0);
1985 return NS_OK;
1988 // Like GetBounds, but don't offset by the parent
1989 NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect)
1991 if (mWnd) {
1992 RECT r;
1993 VERIFY(::GetWindowRect(mWnd, &r));
1995 aRect.width = r.right - r.left;
1996 aRect.height = r.bottom - r.top;
1997 aRect.x = r.left;
1998 aRect.y = r.top;
1999 } else
2000 aRect = mBounds;
2002 return NS_OK;
2005 // return the x,y offset of the client area from the origin
2006 // of the window. If the window is borderless returns (0,0).
2007 nsIntPoint nsWindow::GetClientOffset()
2009 if (!mWnd) {
2010 return nsIntPoint(0, 0);
2013 RECT r1;
2014 GetWindowRect(mWnd, &r1);
2015 nsIntPoint pt = WidgetToScreenOffset();
2016 return nsIntPoint(pt.x - r1.left, pt.y - r1.top);
2019 void
2020 nsWindow::SetDrawsInTitlebar(PRBool aState)
2022 nsWindow * window = GetTopLevelWindow(PR_TRUE);
2023 if (window && window != this) {
2024 return window->SetDrawsInTitlebar(aState);
2027 if (aState) {
2028 // left, top, right, bottom for nsIntMargin
2029 nsIntMargin margins(-1, 0, -1, -1);
2030 SetNonClientMargins(margins);
2032 else {
2033 nsIntMargin margins(-1, -1, -1, -1);
2034 SetNonClientMargins(margins);
2038 NS_IMETHODIMP
2039 nsWindow::GetNonClientMargins(nsIntMargin &margins)
2041 nsWindow * window = GetTopLevelWindow(PR_TRUE);
2042 if (window && window != this) {
2043 return window->GetNonClientMargins(margins);
2046 if (mCustomNonClient) {
2047 margins = mNonClientMargins;
2048 return NS_OK;
2051 margins.top = GetSystemMetrics(SM_CYCAPTION);
2052 margins.bottom = GetSystemMetrics(SM_CYFRAME);
2053 margins.top += margins.bottom;
2054 margins.left = margins.right = GetSystemMetrics(SM_CYFRAME);
2056 return NS_OK;
2059 void
2060 nsWindow::ResetLayout()
2062 // This will trigger a frame changed event, triggering
2063 // nc calc size and a sizemode gecko event.
2064 SetWindowPos(mWnd, 0, 0, 0, 0, 0,
2065 SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|
2066 SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
2068 // If hidden, just send the frame changed event for now.
2069 if (!mIsVisible)
2070 return;
2072 // Send a gecko size event to trigger reflow.
2073 RECT clientRc = {0};
2074 GetClientRect(mWnd, &clientRc);
2075 nsIntRect evRect(nsWindowGfx::ToIntRect(clientRc));
2076 OnResize(evRect);
2078 // Invalidate and update
2079 Invalidate(PR_FALSE);
2082 // Internally track the caption status via a window property. Required
2083 // due to our internal handling of WM_NCACTIVATE when custom client
2084 // margins are set.
2085 static const PRUnichar kManageWindowInfoProperty[] = L"ManageWindowInfoProperty";
2086 typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi);
2087 static GetWindowInfoPtr sGetWindowInfoPtrStub = NULL;
2089 BOOL WINAPI
2090 GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi)
2092 if (!sGetWindowInfoPtrStub) {
2093 NS_ASSERTION(FALSE, "Something is horribly wrong in GetWindowInfoHook!");
2094 return FALSE;
2096 int windowStatus =
2097 reinterpret_cast<int>(GetPropW(hWnd, kManageWindowInfoProperty));
2098 // No property set, return the default data.
2099 if (!windowStatus)
2100 return sGetWindowInfoPtrStub(hWnd, pwi);
2101 // Call GetWindowInfo and update dwWindowStatus with our
2102 // internally tracked value.
2103 BOOL result = sGetWindowInfoPtrStub(hWnd, pwi);
2104 if (result && pwi)
2105 pwi->dwWindowStatus = (windowStatus == 1 ? 0 : WS_ACTIVECAPTION);
2106 return result;
2109 void
2110 nsWindow::UpdateGetWindowInfoCaptionStatus(PRBool aActiveCaption)
2112 if (!mWnd)
2113 return;
2115 if (!sGetWindowInfoPtrStub) {
2116 sUser32Intercept.Init("user32.dll");
2117 if (!sUser32Intercept.AddHook("GetWindowInfo", GetWindowInfoHook,
2118 (void**) &sGetWindowInfoPtrStub))
2119 return;
2121 // Update our internally tracked caption status
2122 SetPropW(mWnd, kManageWindowInfoProperty,
2123 reinterpret_cast<HANDLE>(static_cast<int>(aActiveCaption) + 1));
2126 // Called when the window layout changes: full screen mode transitions,
2127 // theme changes, and composition changes. Calculates the new non-client
2128 // margins and fires off a frame changed event, which triggers an nc calc
2129 // size windows event, kicking the changes in.
2130 PRBool
2131 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode, PRBool aReflowWindow)
2133 if (!mCustomNonClient)
2134 return PR_FALSE;
2136 mNonClientOffset.top = mNonClientOffset.bottom =
2137 mNonClientOffset.left = mNonClientOffset.right = 0;
2139 if (aSizeMode == -1)
2140 aSizeMode = mSizeMode;
2142 if (aSizeMode == nsSizeMode_Minimized ||
2143 aSizeMode == nsSizeMode_Fullscreen) {
2144 mCaptionHeight = mVertResizeMargin = mHorResizeMargin = 0;
2145 return PR_TRUE;
2148 // Note, for maximized windows, we need to continue to offset the client by
2149 // thick frame margins of a normal window, since windows expects this
2150 // in it's DwmDefWndProc hit testing.
2151 mCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
2152 mHorResizeMargin = GetSystemMetrics(SM_CXFRAME);
2153 mVertResizeMargin = GetSystemMetrics(SM_CYFRAME);
2155 mCaptionHeight += mVertResizeMargin;
2157 // If a margin value is 0, set the offset to the default size of the frame.
2158 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2159 // so that the frame size is equal to the margin value.
2160 if (!mNonClientMargins.top)
2161 mNonClientOffset.top = mCaptionHeight;
2162 else if (mNonClientMargins.top > 0)
2163 mNonClientOffset.top = mCaptionHeight - mNonClientMargins.top;
2165 if (!mNonClientMargins.left)
2166 mNonClientOffset.left = mHorResizeMargin;
2167 else if (mNonClientMargins.left > 0)
2168 mNonClientOffset.left = mHorResizeMargin - mNonClientMargins.left;
2170 if (!mNonClientMargins.right)
2171 mNonClientOffset.right = mHorResizeMargin;
2172 else if (mNonClientMargins.right > 0)
2173 mNonClientOffset.right = mHorResizeMargin - mNonClientMargins.right;
2175 if (!mNonClientMargins.bottom)
2176 mNonClientOffset.bottom = mVertResizeMargin;
2177 else if (mNonClientMargins.bottom > 0)
2178 mNonClientOffset.bottom = mVertResizeMargin - mNonClientMargins.bottom;
2180 #ifndef WINCE
2181 if (aSizeMode == nsSizeMode_Maximized) {
2182 // Address an issue with auto-hide taskbars which fall behind the window.
2183 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2184 // the taskbar works properly.
2185 MONITORINFO info = {sizeof(MONITORINFO)};
2186 if (::GetMonitorInfo(::MonitorFromWindow(mWnd, MONITOR_DEFAULTTOPRIMARY),
2187 &info)) {
2188 RECT r;
2189 if (::GetWindowRect(mWnd, &r)) {
2190 // Adjust window rect to account for non-client margins.
2191 r.top += mVertResizeMargin - mNonClientOffset.top;
2192 r.left += mHorResizeMargin - mNonClientOffset.left;
2193 r.bottom -= mVertResizeMargin - mNonClientOffset.bottom;
2194 r.right -= mHorResizeMargin - mNonClientOffset.right;
2195 // Leave the 1 pixel margin if the window covers the monitor.
2196 if (r.top <= info.rcMonitor.top &&
2197 r.left <= info.rcMonitor.left &&
2198 r.right >= info.rcMonitor.right &&
2199 r.bottom >= info.rcMonitor.bottom)
2200 mNonClientOffset.bottom -= r.bottom - info.rcMonitor.bottom + 1;
2204 #endif
2206 if (aReflowWindow) {
2207 // Force a reflow of content based on the new client
2208 // dimensions.
2209 ResetLayout();
2212 return PR_TRUE;
2215 NS_IMETHODIMP
2216 nsWindow::SetNonClientMargins(nsIntMargin &margins)
2218 if (!mIsTopWidgetWindow ||
2219 mBorderStyle & eBorderStyle_none ||
2220 mHideChrome)
2221 return NS_ERROR_INVALID_ARG;
2223 // Request for a reset
2224 if (margins.top == -1 && margins.left == -1 &&
2225 margins.right == -1 && margins.bottom == -1) {
2226 mCustomNonClient = PR_FALSE;
2227 mNonClientMargins = margins;
2228 RemovePropW(mWnd, kManageWindowInfoProperty);
2229 // Force a reflow of content based on the new client
2230 // dimensions.
2231 ResetLayout();
2232 return NS_OK;
2235 if (margins.top < -1 || margins.bottom < -1 ||
2236 margins.left < -1 || margins.right < -1)
2237 return NS_ERROR_INVALID_ARG;
2239 mNonClientMargins = margins;
2240 mCustomNonClient = PR_TRUE;
2241 if (!UpdateNonClientMargins()) {
2242 NS_WARNING("UpdateNonClientMargins failed!");
2243 return PR_FALSE;
2246 return NS_OK;
2249 void
2250 nsWindow::InvalidateNonClientRegion()
2252 // +-+-----------------------+-+
2253 // | | app non-client chrome | |
2254 // | +-----------------------+ |
2255 // | | app client chrome | | }
2256 // | +-----------------------+ | }
2257 // | | app content | | } area we don't want to invalidate
2258 // | +-----------------------+ | }
2259 // | | app client chrome | | }
2260 // | +-----------------------+ |
2261 // +---------------------------+ <
2262 // ^ ^ windows non-client chrome
2263 // client area = app *
2264 RECT rect;
2265 GetWindowRect(mWnd, &rect);
2266 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2267 HRGN winRgn = CreateRectRgnIndirect(&rect);
2269 // Subtract app client chrome and app content leaving
2270 // windows non-client chrome and app non-client chrome
2271 // in winRgn.
2272 GetWindowRect(mWnd, &rect);
2273 rect.top += mCaptionHeight;
2274 rect.right -= mHorResizeMargin;
2275 rect.bottom -= mHorResizeMargin;
2276 rect.left += mVertResizeMargin;
2277 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2278 HRGN clientRgn = CreateRectRgnIndirect(&rect);
2279 CombineRgn(winRgn, winRgn, clientRgn, RGN_DIFF);
2280 DeleteObject(clientRgn);
2282 // triggers ncpaint and paint events for the two areas
2283 RedrawWindow(mWnd, NULL, winRgn, RDW_FRAME|RDW_INVALIDATE);
2284 DeleteObject(winRgn);
2287 HRGN
2288 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion)
2290 RECT rect;
2291 HRGN rgn = NULL;
2292 if (aRegion == (HRGN)1) { // undocumented value indicating a full refresh
2293 GetWindowRect(mWnd, &rect);
2294 rgn = CreateRectRgnIndirect(&rect);
2295 } else {
2296 rgn = aRegion;
2298 GetClientRect(mWnd, &rect);
2299 MapWindowPoints(mWnd, NULL, (LPPOINT)&rect, 2);
2300 HRGN nonClientRgn = CreateRectRgnIndirect(&rect);
2301 CombineRgn(rgn, rgn, nonClientRgn, RGN_DIFF);
2302 DeleteObject(nonClientRgn);
2303 return rgn;
2306 /**************************************************************
2308 * SECTION: nsIWidget::SetBackgroundColor
2310 * Sets the window background paint color.
2312 **************************************************************/
2314 NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
2316 nsBaseWidget::SetBackgroundColor(aColor);
2318 if (mBrush)
2319 ::DeleteObject(mBrush);
2321 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
2322 #ifndef WINCE
2323 if (mWnd != NULL) {
2324 ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush);
2326 #endif
2327 return NS_OK;
2330 /**************************************************************
2332 * SECTION: nsIWidget::SetCursor
2334 * SetCursor and related utilities for manging cursor state.
2336 **************************************************************/
2338 // Set this component cursor
2339 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
2341 // Only change cursor if it's changing
2343 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2344 //XXX If we want this optimization we need a better way to do it.
2345 //if (aCursor != mCursor) {
2346 HCURSOR newCursor = NULL;
2348 switch (aCursor) {
2349 case eCursor_select:
2350 newCursor = ::LoadCursor(NULL, IDC_IBEAM);
2351 break;
2353 case eCursor_wait:
2354 newCursor = ::LoadCursor(NULL, IDC_WAIT);
2355 break;
2357 case eCursor_hyperlink:
2359 newCursor = ::LoadCursor(NULL, IDC_HAND);
2360 break;
2363 case eCursor_standard:
2364 newCursor = ::LoadCursor(NULL, IDC_ARROW);
2365 break;
2367 case eCursor_n_resize:
2368 case eCursor_s_resize:
2369 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2370 break;
2372 case eCursor_w_resize:
2373 case eCursor_e_resize:
2374 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2375 break;
2377 case eCursor_nw_resize:
2378 case eCursor_se_resize:
2379 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2380 break;
2382 case eCursor_ne_resize:
2383 case eCursor_sw_resize:
2384 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2385 break;
2387 case eCursor_crosshair:
2388 newCursor = ::LoadCursor(NULL, IDC_CROSS);
2389 break;
2391 case eCursor_move:
2392 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2393 break;
2395 case eCursor_help:
2396 newCursor = ::LoadCursor(NULL, IDC_HELP);
2397 break;
2399 case eCursor_copy: // CSS3
2400 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
2401 break;
2403 case eCursor_alias:
2404 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
2405 break;
2407 case eCursor_cell:
2408 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
2409 break;
2411 case eCursor_grab:
2412 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
2413 break;
2415 case eCursor_grabbing:
2416 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
2417 break;
2419 case eCursor_spinning:
2420 newCursor = ::LoadCursor(NULL, IDC_APPSTARTING);
2421 break;
2423 case eCursor_context_menu:
2424 // XXX this CSS3 cursor needs to be implemented
2425 break;
2427 case eCursor_zoom_in:
2428 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
2429 break;
2431 case eCursor_zoom_out:
2432 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
2433 break;
2435 case eCursor_not_allowed:
2436 case eCursor_no_drop:
2437 newCursor = ::LoadCursor(NULL, IDC_NO);
2438 break;
2440 case eCursor_col_resize:
2441 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
2442 break;
2444 case eCursor_row_resize:
2445 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
2446 break;
2448 case eCursor_vertical_text:
2449 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT));
2450 break;
2452 case eCursor_all_scroll:
2453 // XXX not 100% appropriate perhaps
2454 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2455 break;
2457 case eCursor_nesw_resize:
2458 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2459 break;
2461 case eCursor_nwse_resize:
2462 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2463 break;
2465 case eCursor_ns_resize:
2466 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2467 break;
2469 case eCursor_ew_resize:
2470 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2471 break;
2473 case eCursor_none:
2474 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
2475 break;
2477 default:
2478 NS_ERROR("Invalid cursor type");
2479 break;
2482 if (NULL != newCursor) {
2483 mCursor = aCursor;
2484 HCURSOR oldCursor = ::SetCursor(newCursor);
2486 if (sHCursor == oldCursor) {
2487 NS_IF_RELEASE(sCursorImgContainer);
2488 if (sHCursor != NULL)
2489 ::DestroyIcon(sHCursor);
2490 sHCursor = NULL;
2494 return NS_OK;
2497 // Setting the actual cursor
2498 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
2499 PRUint32 aHotspotX, PRUint32 aHotspotY)
2501 if (sCursorImgContainer == aCursor && sHCursor) {
2502 ::SetCursor(sHCursor);
2503 return NS_OK;
2506 PRInt32 width;
2507 PRInt32 height;
2509 nsresult rv;
2510 rv = aCursor->GetWidth(&width);
2511 NS_ENSURE_SUCCESS(rv, rv);
2512 rv = aCursor->GetHeight(&height);
2513 NS_ENSURE_SUCCESS(rv, rv);
2515 // Reject cursors greater than 128 pixels in either direction, to prevent
2516 // spoofing.
2517 // XXX ideally we should rescale. Also, we could modify the API to
2518 // allow trusted content to set larger cursors.
2519 if (width > 128 || height > 128)
2520 return NS_ERROR_NOT_AVAILABLE;
2522 HCURSOR cursor;
2523 rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
2524 NS_ENSURE_SUCCESS(rv, rv);
2526 mCursor = nsCursor(-1);
2527 ::SetCursor(cursor);
2529 NS_IF_RELEASE(sCursorImgContainer);
2530 sCursorImgContainer = aCursor;
2531 NS_ADDREF(sCursorImgContainer);
2533 if (sHCursor != NULL)
2534 ::DestroyIcon(sHCursor);
2535 sHCursor = cursor;
2537 return NS_OK;
2540 /**************************************************************
2542 * SECTION: nsIWidget::Get/SetTransparencyMode
2544 * Manage the transparency mode of the top-level window
2545 * containing this widget.
2547 **************************************************************/
2549 #ifdef MOZ_XUL
2550 nsTransparencyMode nsWindow::GetTransparencyMode()
2552 return GetTopLevelWindow(PR_TRUE)->GetWindowTranslucencyInner();
2555 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
2557 GetTopLevelWindow(PR_TRUE)->SetWindowTranslucencyInner(aMode);
2560 static const PRInt32 kGlassMarginAdjustment = 2;
2562 void nsWindow::UpdatePossiblyTransparentRegion(const nsIntRegion &aDirtyRegion,
2563 const nsIntRegion &aPossiblyTransparentRegion) {
2564 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2565 if (!HasGlass())
2566 return;
2568 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2569 nsWindow* topWindow = GetNSWindowPtr(hWnd);
2571 if (GetParent())
2572 return;
2574 mPossiblyTransparentRegion.Sub(mPossiblyTransparentRegion, aDirtyRegion);
2575 mPossiblyTransparentRegion.Or(mPossiblyTransparentRegion, aPossiblyTransparentRegion);
2577 nsIntRect clientBounds;
2578 topWindow->GetClientBounds(clientBounds);
2579 nsIntRegion opaqueRegion;
2580 opaqueRegion.Sub(clientBounds, mPossiblyTransparentRegion);
2582 MARGINS margins = { 0, 0, 0, 0 };
2583 DWORD_PTR dwStyle = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
2585 // If there is no opaque region or hidechrome=true, set margins
2586 // to support a full sheet of glass.
2587 // Comments in MSDN indicate all values must be set to -1 to get a full
2588 // sheet of glass.
2589 margins.cxLeftWidth = margins.cxRightWidth =
2590 margins.cyTopHeight = margins.cyBottomHeight = -1;
2591 if (!opaqueRegion.IsEmpty() && !mHideChrome) {
2592 nsIntRect pluginBounds;
2593 for (nsIWidget* child = GetFirstChild(); child; child = child->GetNextSibling()) {
2594 nsWindowType type;
2595 child->GetWindowType(type);
2596 if (type == eWindowType_plugin) {
2597 nsIntRect childBounds;
2598 child->GetBounds(childBounds);
2599 if (mTransparencyMode == eTransparencyBorderlessGlass) {
2600 // We shrink the margins by kGlassMarginAdjustment in UpdateGlass.
2601 // So here, try to ensure that the shrunk margin will still contain
2602 // the plugin bounds. Of course there's no guarantee that we'll
2603 // find an opaque rectangle including this enlarged area, for example
2604 // if the plugin is already at the edge of the window.
2605 childBounds.Inflate(kGlassMarginAdjustment, kGlassMarginAdjustment);
2607 pluginBounds.UnionRect(pluginBounds, childBounds);
2611 // Find the largest rectangle and use that to calculate the inset. Our top
2612 // priority is to include the bounds of all plugins.
2613 nsIntRect largest = opaqueRegion.GetLargestRectangle(pluginBounds);
2614 if (largest.x <= MAX_HORIZONTAL_GLASS_MARGIN &&
2615 clientBounds.width - largest.XMost() <= MAX_HORIZONTAL_GLASS_MARGIN &&
2616 largest.height >= MIN_OPAQUE_RECT_HEIGHT_FOR_GLASS_MARGINS) {
2617 margins.cxLeftWidth = largest.x;
2618 margins.cxRightWidth = clientBounds.width - largest.XMost();
2619 margins.cyBottomHeight = clientBounds.height - largest.YMost();
2621 if (mCustomNonClient) {
2622 // The minimum glass height must be the caption buttons height,
2623 // otherwise the buttons are drawn incorrectly.
2624 largest.y = PR_MAX(largest.y,
2625 nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cy);
2627 margins.cyTopHeight = largest.y;
2631 // Only update glass area if there are changes
2632 if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) {
2633 mGlassMargins = margins;
2634 UpdateGlass();
2636 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2639 void nsWindow::UpdateGlass()
2641 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2642 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2643 MARGINS margins = mGlassMargins;
2645 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2646 // rendered based on the window style.
2647 // DWMNCRP_ENABLED - The non-client area rendering is
2648 // enabled; the window style is ignored.
2649 DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE;
2650 switch (mTransparencyMode) {
2651 case eTransparencyBorderlessGlass:
2652 // Only adjust if there is some opaque rectangle
2653 if (margins.cxLeftWidth >= 0) {
2654 margins.cxLeftWidth += kGlassMarginAdjustment;
2655 margins.cyTopHeight += kGlassMarginAdjustment;
2656 margins.cxRightWidth += kGlassMarginAdjustment;
2657 margins.cyBottomHeight += kGlassMarginAdjustment;
2659 // Fall through
2660 case eTransparencyGlass:
2661 policy = DWMNCRP_ENABLED;
2662 break;
2665 // Extends the window frame behind the client area
2666 if(nsUXThemeData::CheckForCompositor()) {
2667 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd, &margins);
2668 nsUXThemeData::dwmSetWindowAttributePtr(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy);
2670 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2672 #endif
2674 /**************************************************************
2676 * SECTION: nsIWidget::HideWindowChrome
2678 * Show or hide window chrome.
2680 **************************************************************/
2682 NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide)
2684 HWND hwnd = GetTopLevelHWND(mWnd, PR_TRUE);
2685 if (!GetNSWindowPtr(hwnd))
2687 NS_WARNING("Trying to hide window decorations in an embedded context");
2688 return NS_ERROR_FAILURE;
2691 if (mHideChrome == aShouldHide)
2692 return NS_OK;
2694 DWORD_PTR style, exStyle;
2695 mHideChrome = aShouldHide;
2696 if (aShouldHide) {
2697 DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2698 DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2700 style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
2701 exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
2702 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
2704 mOldStyle = tempStyle;
2705 mOldExStyle = tempExStyle;
2707 else {
2708 if (!mOldStyle || !mOldExStyle) {
2709 mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2710 mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2713 style = mOldStyle;
2714 exStyle = mOldExStyle;
2717 VERIFY_WINDOW_STYLE(style);
2718 ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
2719 ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
2721 return NS_OK;
2724 /**************************************************************
2726 * SECTION: nsIWidget::Invalidate
2728 * Invalidate an area of the client for painting.
2730 **************************************************************/
2732 // Invalidate this component visible area
2733 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
2735 if (mWnd)
2737 #ifdef WIDGET_DEBUG_OUTPUT
2738 debug_DumpInvalidate(stdout,
2739 this,
2740 nsnull,
2741 aIsSynchronous,
2742 nsCAutoString("noname"),
2743 (PRInt32) mWnd);
2744 #endif // WIDGET_DEBUG_OUTPUT
2746 VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
2748 if (aIsSynchronous) {
2749 VERIFY(::UpdateWindow(mWnd));
2752 return NS_OK;
2755 // Invalidate this component visible area
2756 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, PRBool aIsSynchronous)
2758 if (mWnd)
2760 #ifdef WIDGET_DEBUG_OUTPUT
2761 debug_DumpInvalidate(stdout,
2762 this,
2763 &aRect,
2764 aIsSynchronous,
2765 nsCAutoString("noname"),
2766 (PRInt32) mWnd);
2767 #endif // WIDGET_DEBUG_OUTPUT
2769 RECT rect;
2771 rect.left = aRect.x;
2772 rect.top = aRect.y;
2773 rect.right = aRect.x + aRect.width;
2774 rect.bottom = aRect.y + aRect.height;
2776 VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
2778 if (aIsSynchronous) {
2779 VERIFY(::UpdateWindow(mWnd));
2782 return NS_OK;
2785 NS_IMETHODIMP
2786 nsWindow::MakeFullScreen(PRBool aFullScreen)
2788 #if WINCE_WINDOWS_MOBILE
2789 RECT rc;
2790 if (aFullScreen) {
2791 SetForegroundWindow(mWnd);
2792 if (nsWindowCE::sMenuBarShown) {
2793 SIPINFO sipInfo;
2794 memset(&sipInfo, 0, sizeof(SIPINFO));
2795 sipInfo.cbSize = sizeof(SIPINFO);
2796 if (SipGetInfo(&sipInfo))
2797 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2798 sipInfo.rcVisibleDesktop.bottom);
2799 else
2800 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2801 GetSystemMetrics(SM_CYSCREEN));
2802 RECT menuBarRect;
2803 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle, &menuBarRect) &&
2804 menuBarRect.top < rc.bottom)
2805 rc.bottom = menuBarRect.top;
2806 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_SHOWSIPBUTTON);
2807 } else {
2809 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);
2810 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2813 else {
2814 SHFullScreen(mWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
2815 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
2818 if (aFullScreen)
2819 mSizeMode = nsSizeMode_Fullscreen;
2821 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2822 HideWindowChrome(aFullScreen);
2823 Resize(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PR_TRUE);
2825 return NS_OK;
2827 #else
2829 mFullscreenMode = aFullScreen;
2830 if (aFullScreen) {
2831 if (mSizeMode == nsSizeMode_Fullscreen)
2832 return NS_OK;
2833 mOldSizeMode = mSizeMode;
2834 SetSizeMode(nsSizeMode_Fullscreen);
2835 } else {
2836 SetSizeMode(mOldSizeMode);
2839 UpdateNonClientMargins();
2841 // Prevent window updates during the transition.
2842 DWORD style;
2843 if (nsUXThemeData::CheckForCompositor()) {
2844 style = GetWindowLong(mWnd, GWL_STYLE);
2845 SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
2848 // Will call hide chrome, reposition window. Note this will
2849 // also cache dimensions for restoration, so it should only
2850 // be called once per fullscreen request.
2851 nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen);
2853 if (nsUXThemeData::CheckForCompositor()) {
2854 style = GetWindowLong(mWnd, GWL_STYLE);
2855 SetWindowLong(mWnd, GWL_STYLE, style | WS_VISIBLE);
2856 Invalidate(PR_FALSE);
2859 // Let the dom know via web shell window
2860 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
2861 event.mSizeMode = mSizeMode;
2862 InitEvent(event);
2863 DispatchWindowEvent(&event);
2865 return rv;
2866 #endif
2869 /**************************************************************
2871 * SECTION: nsIWidget::Update
2873 * Force a synchronous repaint of the window.
2875 **************************************************************/
2877 NS_IMETHODIMP nsWindow::Update()
2879 nsresult rv = NS_OK;
2881 // updates can come through for windows no longer holding an mWnd during
2882 // deletes triggered by JavaScript in buttons with mouse feedback
2883 if (mWnd)
2884 VERIFY(::UpdateWindow(mWnd));
2886 return rv;
2889 /**************************************************************
2891 * SECTION: Native data storage
2893 * nsIWidget::GetNativeData
2894 * nsIWidget::FreeNativeData
2896 * Set or clear native data based on a constant.
2898 **************************************************************/
2900 // Return some native data according to aDataType
2901 void* nsWindow::GetNativeData(PRUint32 aDataType)
2903 nsAutoString className;
2904 switch (aDataType) {
2905 case NS_NATIVE_TMP_WINDOW:
2906 GetWindowClass(className);
2907 return (void*)::CreateWindowExW(mIsRTL ? WS_EX_LAYOUTRTL : 0,
2908 className.get(),
2909 L"",
2910 WS_CHILD,
2911 CW_USEDEFAULT,
2912 CW_USEDEFAULT,
2913 CW_USEDEFAULT,
2914 CW_USEDEFAULT,
2915 mWnd,
2916 NULL,
2917 nsToolkit::mDllInstance,
2918 NULL);
2919 case NS_NATIVE_PLUGIN_PORT:
2920 case NS_NATIVE_WIDGET:
2921 case NS_NATIVE_WINDOW:
2922 return (void*)mWnd;
2923 case NS_NATIVE_GRAPHIC:
2924 // XXX: This is sleezy!! Remember to Release the DC after using it!
2925 #ifdef MOZ_XUL
2926 return (void*)(eTransparencyTransparent == mTransparencyMode) ?
2927 mMemoryDC : ::GetDC(mWnd);
2928 #else
2929 return (void*)::GetDC(mWnd);
2930 #endif
2932 #ifdef NS_ENABLE_TSF
2933 case NS_NATIVE_TSF_THREAD_MGR:
2934 return nsTextStore::GetThreadMgr();
2935 case NS_NATIVE_TSF_CATEGORY_MGR:
2936 return nsTextStore::GetCategoryMgr();
2937 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
2938 return nsTextStore::GetDisplayAttrMgr();
2939 #endif //NS_ENABLE_TSF
2941 default:
2942 break;
2945 return NULL;
2948 // Free some native data according to aDataType
2949 void nsWindow::FreeNativeData(void * data, PRUint32 aDataType)
2951 switch (aDataType)
2953 case NS_NATIVE_GRAPHIC:
2954 #ifdef MOZ_XUL
2955 if (eTransparencyTransparent != mTransparencyMode)
2956 ::ReleaseDC(mWnd, (HDC)data);
2957 #else
2958 ::ReleaseDC(mWnd, (HDC)data);
2959 #endif
2960 break;
2961 case NS_NATIVE_WIDGET:
2962 case NS_NATIVE_WINDOW:
2963 case NS_NATIVE_PLUGIN_PORT:
2964 break;
2965 default:
2966 break;
2970 /**************************************************************
2972 * SECTION: nsIWidget::SetTitle
2974 * Set the main windows title text.
2976 **************************************************************/
2978 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
2980 const nsString& strTitle = PromiseFlatString(aTitle);
2981 ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get());
2982 return NS_OK;
2985 /**************************************************************
2987 * SECTION: nsIWidget::SetIcon
2989 * Set the main windows icon.
2991 **************************************************************/
2993 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec)
2995 #ifndef WINCE
2996 // Assume the given string is a local identifier for an icon file.
2998 nsCOMPtr<nsILocalFile> iconFile;
2999 ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
3000 getter_AddRefs(iconFile));
3001 if (!iconFile)
3002 return NS_OK; // not an error if icon is not found
3004 nsAutoString iconPath;
3005 iconFile->GetPath(iconPath);
3007 // XXX this should use MZLU (see bug 239279)
3009 ::SetLastError(0);
3011 HICON bigIcon = (HICON)::LoadImageW(NULL,
3012 (LPCWSTR)iconPath.get(),
3013 IMAGE_ICON,
3014 ::GetSystemMetrics(SM_CXICON),
3015 ::GetSystemMetrics(SM_CYICON),
3016 LR_LOADFROMFILE );
3017 HICON smallIcon = (HICON)::LoadImageW(NULL,
3018 (LPCWSTR)iconPath.get(),
3019 IMAGE_ICON,
3020 ::GetSystemMetrics(SM_CXSMICON),
3021 ::GetSystemMetrics(SM_CYSMICON),
3022 LR_LOADFROMFILE );
3024 if (bigIcon) {
3025 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon);
3026 if (icon)
3027 ::DestroyIcon(icon);
3029 #ifdef DEBUG_SetIcon
3030 else {
3031 NS_LossyConvertUTF16toASCII cPath(iconPath);
3032 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
3034 #endif
3035 if (smallIcon) {
3036 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon);
3037 if (icon)
3038 ::DestroyIcon(icon);
3040 #ifdef DEBUG_SetIcon
3041 else {
3042 NS_LossyConvertUTF16toASCII cPath(iconPath);
3043 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
3045 #endif
3046 #endif // WINCE
3047 return NS_OK;
3050 /**************************************************************
3052 * SECTION: nsIWidget::WidgetToScreenOffset
3054 * Return this widget's origin in screen coordinates.
3056 **************************************************************/
3058 nsIntPoint nsWindow::WidgetToScreenOffset()
3060 POINT point;
3061 point.x = 0;
3062 point.y = 0;
3063 ::ClientToScreen(mWnd, &point);
3064 return nsIntPoint(point.x, point.y);
3067 nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize)
3069 if (!IsPopupWithTitleBar())
3070 return aClientSize;
3072 // just use (200, 200) as the position
3073 RECT r;
3074 r.left = 200;
3075 r.top = 200;
3076 r.right = 200 + aClientSize.width;
3077 r.bottom = 200 + aClientSize.height;
3078 ::AdjustWindowRectEx(&r, WindowStyle(), PR_FALSE, WindowExStyle());
3080 return nsIntSize(r.right - r.left, r.bottom - r.top);
3083 /**************************************************************
3085 * SECTION: nsIWidget::EnableDragDrop
3087 * Enables/Disables drag and drop of files on this widget.
3089 **************************************************************/
3091 #if !defined(WINCE) // implemented in nsWindowCE.cpp
3092 NS_METHOD nsWindow::EnableDragDrop(PRBool aEnable)
3094 NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()");
3096 nsresult rv = NS_ERROR_FAILURE;
3097 if (aEnable) {
3098 if (nsnull == mNativeDragTarget) {
3099 mNativeDragTarget = new nsNativeDragTarget(this);
3100 if (NULL != mNativeDragTarget) {
3101 mNativeDragTarget->AddRef();
3102 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) {
3103 if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) {
3104 rv = NS_OK;
3109 } else {
3110 if (nsnull != mWnd && NULL != mNativeDragTarget) {
3111 ::RevokeDragDrop(mWnd);
3112 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) {
3113 rv = NS_OK;
3115 mNativeDragTarget->DragCancel();
3116 NS_RELEASE(mNativeDragTarget);
3119 return rv;
3121 #endif
3123 /**************************************************************
3125 * SECTION: nsIWidget::CaptureMouse
3127 * Enables/Disables system mouse capture.
3129 **************************************************************/
3131 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
3133 if (!nsToolkit::gMouseTrailer) {
3134 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3135 return NS_OK;
3138 if (aCapture) {
3139 nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd);
3140 ::SetCapture(mWnd);
3141 } else {
3142 nsToolkit::gMouseTrailer->SetCaptureWindow(NULL);
3143 ::ReleaseCapture();
3145 sIsInMouseCapture = aCapture;
3146 return NS_OK;
3149 /**************************************************************
3151 * SECTION: nsIWidget::CaptureRollupEvents
3153 * Dealing with event rollup on destroy for popups. Enables &
3154 * Disables system capture of any and all events that would
3155 * cause a dropdown to be rolled up.
3157 **************************************************************/
3159 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
3160 nsIMenuRollup * aMenuRollup,
3161 PRBool aDoCapture,
3162 PRBool aConsumeRollupEvent)
3164 if (aDoCapture) {
3165 /* we haven't bothered carrying a weak reference to sRollupWidget because
3166 we believe lifespan is properly scoped. this next assertion helps
3167 assure that remains true. */
3168 NS_ASSERTION(!sRollupWidget, "rollup widget reassigned before release");
3169 sRollupConsumeEvent = aConsumeRollupEvent;
3170 NS_IF_RELEASE(sRollupWidget);
3171 NS_IF_RELEASE(sMenuRollup);
3172 sRollupListener = aListener;
3173 sMenuRollup = aMenuRollup;
3174 NS_IF_ADDREF(aMenuRollup);
3175 sRollupWidget = this;
3176 NS_ADDREF(this);
3178 #ifndef WINCE
3179 if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
3180 RegisterSpecialDropdownHooks();
3182 sProcessHook = PR_TRUE;
3183 #endif
3185 } else {
3186 sRollupListener = nsnull;
3187 NS_IF_RELEASE(sMenuRollup);
3188 NS_IF_RELEASE(sRollupWidget);
3190 #ifndef WINCE
3191 sProcessHook = PR_FALSE;
3192 UnregisterSpecialDropdownHooks();
3193 #endif
3196 return NS_OK;
3199 /**************************************************************
3201 * SECTION: nsIWidget::GetAttention
3203 * Bring this window to the user's attention.
3205 **************************************************************/
3207 // Draw user's attention to this window until it comes to foreground.
3208 NS_IMETHODIMP
3209 nsWindow::GetAttention(PRInt32 aCycleCount)
3211 #ifndef WINCE
3212 // Got window?
3213 if (!mWnd)
3214 return NS_ERROR_NOT_INITIALIZED;
3216 // Don't flash if the flash count is 0 or if the
3217 // top level window is already active.
3218 HWND fgWnd = ::GetForegroundWindow();
3219 if (aCycleCount == 0 || fgWnd == GetTopLevelHWND(mWnd))
3220 return NS_OK;
3222 HWND flashWnd = mWnd;
3223 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3224 flashWnd = ownerWnd;
3227 // Don't flash if the owner window is active either.
3228 if (fgWnd == flashWnd)
3229 return NS_OK;
3231 DWORD defaultCycleCount = 0;
3232 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
3234 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3235 FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 };
3236 ::FlashWindowEx(&flashInfo);
3237 #endif
3238 return NS_OK;
3241 void nsWindow::StopFlashing()
3243 #ifndef WINCE
3244 HWND flashWnd = mWnd;
3245 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3246 flashWnd = ownerWnd;
3249 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3250 FLASHW_STOP, 0, 0 };
3251 ::FlashWindowEx(&flashInfo);
3252 #endif
3255 /**************************************************************
3257 * SECTION: nsIWidget::HasPendingInputEvent
3259 * Ask whether there user input events pending. All input events are
3260 * included, including those not targeted at this nsIwidget instance.
3262 **************************************************************/
3264 PRBool
3265 nsWindow::HasPendingInputEvent()
3267 // If there is pending input or the user is currently
3268 // moving the window then return true.
3269 // Note: When the user is moving the window WIN32 spins
3270 // a separate event loop and input events are not
3271 // reported to the application.
3272 if (HIWORD(GetQueueStatus(QS_INPUT)))
3273 return PR_TRUE;
3274 #ifdef WINCE
3275 return PR_FALSE;
3276 #else
3277 GUITHREADINFO guiInfo;
3278 guiInfo.cbSize = sizeof(GUITHREADINFO);
3279 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo))
3280 return PR_FALSE;
3281 return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE);
3282 #endif
3285 /**************************************************************
3287 * SECTION: nsIWidget::GetLayerManager
3289 * Get the layer manager associated with this widget.
3291 **************************************************************/
3293 struct LayerManagerPrefs {
3294 LayerManagerPrefs()
3295 : mAccelerateByDefault(PR_TRUE)
3296 , mDisableAcceleration(PR_FALSE)
3297 , mPreferOpenGL(PR_FALSE)
3298 , mPreferD3D9(PR_FALSE)
3300 PRBool mAccelerateByDefault;
3301 PRBool mDisableAcceleration;
3302 PRBool mForceAcceleration;
3303 PRBool mPreferOpenGL;
3304 PRBool mPreferD3D9;
3307 static void
3308 GetLayerManagerPrefs(LayerManagerPrefs* aManagerPrefs)
3310 nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3311 if (prefs) {
3312 prefs->GetBoolPref("layers.acceleration.disabled",
3313 &aManagerPrefs->mDisableAcceleration);
3314 prefs->GetBoolPref("layers.acceleration.force-enabled",
3315 &aManagerPrefs->mForceAcceleration);
3316 prefs->GetBoolPref("layers.prefer-opengl",
3317 &aManagerPrefs->mPreferOpenGL);
3318 prefs->GetBoolPref("layers.prefer-d3d9",
3319 &aManagerPrefs->mPreferD3D9);
3322 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
3323 aManagerPrefs->mAccelerateByDefault =
3324 aManagerPrefs->mAccelerateByDefault ||
3325 (acceleratedEnv && (*acceleratedEnv != '0'));
3327 PRBool safeMode = PR_FALSE;
3328 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
3329 if (xr)
3330 xr->GetInSafeMode(&safeMode);
3331 aManagerPrefs->mDisableAcceleration =
3332 aManagerPrefs->mDisableAcceleration || safeMode;
3335 mozilla::layers::LayerManager*
3336 nsWindow::GetLayerManager(LayerManagerPersistence aPersistence, bool* aAllowRetaining)
3338 if (aAllowRetaining) {
3339 *aAllowRetaining = true;
3342 #ifndef WINCE
3343 #ifdef MOZ_ENABLE_D3D10_LAYER
3344 if (mLayerManager) {
3345 if (mLayerManager->GetBackendType() ==
3346 mozilla::layers::LayerManager::LAYERS_D3D10)
3348 mozilla::layers::LayerManagerD3D10 *layerManagerD3D10 =
3349 static_cast<mozilla::layers::LayerManagerD3D10*>(mLayerManager.get());
3350 if (layerManagerD3D10->device() !=
3351 gfxWindowsPlatform::GetPlatform()->GetD3D10Device())
3353 mLayerManager->Destroy();
3354 mLayerManager = nsnull;
3358 #endif
3360 if (!mLayerManager ||
3361 (!sAllowD3D9 && aPersistence == LAYER_MANAGER_PERSISTENT &&
3362 mLayerManager->GetBackendType() ==
3363 mozilla::layers::LayerManager::LAYERS_BASIC)) {
3364 // If D3D9 is not currently allowed but the permanent manager is required,
3365 // -and- we're currently using basic layers, run through this check.
3366 LayerManagerPrefs prefs;
3367 GetLayerManagerPrefs(&prefs);
3369 /* We don't currently support using an accelerated layer manager with
3370 * transparent windows so don't even try. I'm also not sure if we even
3371 * want to support this case. See bug #593471 */
3372 if (eTransparencyTransparent == mTransparencyMode ||
3373 prefs.mDisableAcceleration)
3374 mUseAcceleratedRendering = PR_FALSE;
3375 else if (prefs.mAccelerateByDefault)
3376 mUseAcceleratedRendering = PR_TRUE;
3378 if (mUseAcceleratedRendering) {
3379 if (aPersistence == LAYER_MANAGER_PERSISTENT && !sAllowD3D9) {
3380 // This will clear out our existing layer manager if we have one since
3381 // if we hit this with a LayerManager we're always using BasicLayers.
3382 nsToolkit::StartAllowingD3D9();
3385 #ifdef MOZ_ENABLE_D3D10_LAYER
3386 if (!prefs.mPreferD3D9) {
3387 nsRefPtr<mozilla::layers::LayerManagerD3D10> layerManager =
3388 new mozilla::layers::LayerManagerD3D10(this);
3389 if (layerManager->Initialize()) {
3390 mLayerManager = layerManager;
3393 #endif
3394 #ifdef MOZ_ENABLE_D3D9_LAYER
3395 if (!prefs.mPreferOpenGL && !mLayerManager && sAllowD3D9) {
3396 nsRefPtr<mozilla::layers::LayerManagerD3D9> layerManager =
3397 new mozilla::layers::LayerManagerD3D9(this);
3398 if (layerManager->Initialize()) {
3399 mLayerManager = layerManager;
3402 #endif
3403 if (!mLayerManager && prefs.mPreferOpenGL) {
3404 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
3405 PRInt32 status = nsIGfxInfo::FEATURE_NO_INFO;
3407 if (gfxInfo && !prefs.mForceAcceleration) {
3408 gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status);
3411 if (status == nsIGfxInfo::FEATURE_NO_INFO) {
3412 nsRefPtr<mozilla::layers::LayerManagerOGL> layerManager =
3413 new mozilla::layers::LayerManagerOGL(this);
3414 if (layerManager->Initialize()) {
3415 mLayerManager = layerManager;
3418 } else {
3419 NS_WARNING("OpenGL accelerated layers are not supported on this system.");
3424 // Fall back to software if we couldn't use any hardware backends.
3425 if (!mLayerManager)
3426 mLayerManager = CreateBasicLayerManager();
3428 #endif
3430 return mLayerManager;
3433 /**************************************************************
3435 * SECTION: nsIWidget::GetThebesSurface
3437 * Get the Thebes surface associated with this widget.
3439 **************************************************************/
3441 gfxASurface *nsWindow::GetThebesSurface()
3443 #ifdef CAIRO_HAS_D2D_SURFACE
3444 if (mD2DWindowSurface) {
3445 return mD2DWindowSurface;
3447 #endif
3448 if (mPaintDC)
3449 return (new gfxWindowsSurface(mPaintDC));
3451 #ifdef CAIRO_HAS_D2D_SURFACE
3452 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3453 gfxWindowsPlatform::RENDER_DIRECT2D) {
3454 gfxASurface::gfxContentType content = gfxASurface::CONTENT_COLOR;
3455 #if defined(MOZ_XUL)
3456 if (mTransparencyMode != eTransparencyOpaque) {
3457 content = gfxASurface::CONTENT_COLOR_ALPHA;
3459 #endif
3460 return (new gfxD2DSurface(mWnd, content));
3461 } else {
3462 #endif
3463 PRUint32 flags = gfxWindowsSurface::FLAG_TAKE_DC;
3464 if (mTransparencyMode != eTransparencyOpaque) {
3465 flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT;
3467 return (new gfxWindowsSurface(mWnd, flags));
3468 #ifdef CAIRO_HAS_D2D_SURFACE
3470 #endif
3473 /**************************************************************
3475 * SECTION: nsIWidget::OnDefaultButtonLoaded
3477 * Called after the dialog is loaded and it has a default button.
3479 **************************************************************/
3481 NS_IMETHODIMP
3482 nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect)
3484 #ifdef WINCE
3485 return NS_ERROR_NOT_IMPLEMENTED;
3486 #else
3487 if (aButtonRect.IsEmpty())
3488 return NS_OK;
3490 // Don't snap when we are not active.
3491 HWND activeWnd = ::GetActiveWindow();
3492 if (activeWnd != ::GetForegroundWindow() ||
3493 GetTopLevelHWND(mWnd, PR_TRUE) != GetTopLevelHWND(activeWnd, PR_TRUE)) {
3494 return NS_OK;
3497 PRBool isAlwaysSnapCursor = PR_FALSE;
3498 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3499 if (prefs) {
3500 nsCOMPtr<nsIPrefBranch> prefBranch;
3501 prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
3502 if (prefBranch) {
3503 prefBranch->GetBoolPref("ui.cursor_snapping.always_enabled",
3504 &isAlwaysSnapCursor);
3508 if (!isAlwaysSnapCursor) {
3509 BOOL snapDefaultButton;
3510 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0,
3511 &snapDefaultButton, 0) || !snapDefaultButton)
3512 return NS_OK;
3515 nsIntRect widgetRect;
3516 nsresult rv = GetScreenBounds(widgetRect);
3517 NS_ENSURE_SUCCESS(rv, rv);
3518 nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft());
3520 nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2,
3521 buttonRect.y + buttonRect.height / 2);
3522 // The center of the button can be outside of the widget.
3523 // E.g., it could be hidden by scrolling.
3524 if (!widgetRect.Contains(centerOfButton)) {
3525 return NS_OK;
3528 if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) {
3529 NS_ERROR("SetCursorPos failed");
3530 return NS_ERROR_FAILURE;
3532 return NS_OK;
3533 #endif
3536 NS_IMETHODIMP
3537 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta,
3538 PRBool aIsHorizontal,
3539 PRInt32 &aOverriddenDelta)
3541 // The default vertical and horizontal scrolling speed is 3, this is defined
3542 // on the document of SystemParametersInfo in MSDN.
3543 const PRUint32 kSystemDefaultScrollingSpeed = 3;
3545 PRInt32 absOriginDelta = PR_ABS(aOriginalDelta);
3547 // Compute the simple overridden speed.
3548 PRInt32 absComputedOverriddenDelta;
3549 nsresult rv =
3550 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta, aIsHorizontal,
3551 absComputedOverriddenDelta);
3552 NS_ENSURE_SUCCESS(rv, rv);
3554 aOverriddenDelta = aOriginalDelta;
3556 if (absComputedOverriddenDelta == absOriginDelta) {
3557 // We don't override now.
3558 return NS_OK;
3561 // Otherwise, we should check whether the user customized the system settings
3562 // or not. If the user did it, we should respect the will.
3563 UINT systemSpeed;
3564 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) {
3565 return NS_ERROR_FAILURE;
3567 // The default vertical scrolling speed is 3, this is defined on the document
3568 // of SystemParametersInfo in MSDN.
3569 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3570 return NS_OK;
3573 // Only Vista and later, Windows has the system setting of horizontal
3574 // scrolling by the mouse wheel.
3575 if (GetWindowsVersion() >= VISTA_VERSION) {
3576 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) {
3577 return NS_ERROR_FAILURE;
3579 // The default horizontal scrolling speed is 3, this is defined on the
3580 // document of SystemParametersInfo in MSDN.
3581 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3582 return NS_OK;
3586 // Limit the overridden delta value from the system settings. The mouse
3587 // driver might accelerate the scrolling speed already. If so, we shouldn't
3588 // override the scrolling speed for preventing the unexpected high speed
3589 // scrolling.
3590 PRInt32 absDeltaLimit;
3591 rv =
3592 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed,
3593 aIsHorizontal, absDeltaLimit);
3594 NS_ENSURE_SUCCESS(rv, rv);
3596 // If the given delta is larger than our computed limitation value, the delta
3597 // was accelerated by the mouse driver. So, we should do nothing here.
3598 if (absDeltaLimit <= absOriginDelta) {
3599 return NS_OK;
3602 absComputedOverriddenDelta =
3603 PR_MIN(absComputedOverriddenDelta, absDeltaLimit);
3605 aOverriddenDelta = (aOriginalDelta > 0) ? absComputedOverriddenDelta :
3606 -absComputedOverriddenDelta;
3607 return NS_OK;
3610 /**************************************************************
3611 **************************************************************
3613 ** BLOCK: Moz Events
3615 ** Moz GUI event management.
3617 **************************************************************
3618 **************************************************************/
3620 /**************************************************************
3622 * SECTION: Mozilla event initialization
3624 * Helpers for initializing moz events.
3626 **************************************************************/
3628 // Event intialization
3629 MSG nsWindow::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam)
3631 MSG msg;
3632 msg.message = aMessage;
3633 msg.wParam = wParam;
3634 msg.lParam = lParam;
3635 return msg;
3638 void nsWindow::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
3640 if (nsnull == aPoint) { // use the point from the event
3641 // get the message position in client coordinates
3642 if (mWnd != NULL) {
3644 DWORD pos = ::GetMessagePos();
3645 POINT cpos;
3647 cpos.x = GET_X_LPARAM(pos);
3648 cpos.y = GET_Y_LPARAM(pos);
3650 ::ScreenToClient(mWnd, &cpos);
3651 event.refPoint.x = cpos.x;
3652 event.refPoint.y = cpos.y;
3653 } else {
3654 event.refPoint.x = 0;
3655 event.refPoint.y = 0;
3658 else {
3659 // use the point override if provided
3660 event.refPoint.x = aPoint->x;
3661 event.refPoint.y = aPoint->y;
3664 #ifndef WINCE
3665 event.time = ::GetMessageTime();
3666 #else
3667 event.time = PR_Now() / 1000;
3668 #endif
3670 mLastPoint = event.refPoint;
3673 /**************************************************************
3675 * SECTION: Moz event dispatch helpers
3677 * Helpers for dispatching different types of moz events.
3679 **************************************************************/
3681 // Main event dispatch. Invokes callback and ProcessEvent method on
3682 // Event Listener object. Part of nsIWidget.
3683 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
3685 #ifdef WIDGET_DEBUG_OUTPUT
3686 debug_DumpEvent(stdout,
3687 event->widget,
3688 event,
3689 nsCAutoString("something"),
3690 (PRInt32) mWnd);
3691 #endif // WIDGET_DEBUG_OUTPUT
3693 aStatus = nsEventStatus_eIgnore;
3695 // skip processing of suppressed blur events
3696 if (event->message == NS_DEACTIVATE && BlurEventsSuppressed())
3697 return NS_OK;
3699 // Top level windows can have a view attached which requires events be sent
3700 // to the underlying base window and the view. Added when we combined the
3701 // base chrome window with the main content child for nc client area (title
3702 // bar) rendering.
3703 if (mViewCallback) {
3704 // A subset of events are sent to the base xul window first
3705 switch(event->message) {
3706 // send to the base window (view mgr ignores these for the view)
3707 case NS_UISTATECHANGED:
3708 case NS_DESTROY:
3709 case NS_SETZLEVEL:
3710 case NS_XUL_CLOSE:
3711 case NS_MOVE:
3712 (*mEventCallback)(event); // web shell / xul window
3713 return NS_OK;
3715 // sent to the base window, then to the view
3716 case NS_SIZE:
3717 case NS_DEACTIVATE:
3718 case NS_ACTIVATE:
3719 case NS_SIZEMODE:
3720 (*mEventCallback)(event); // web shell / xul window
3721 break;
3723 // attached view events
3724 aStatus = (*mViewCallback)(event);
3726 else if (mEventCallback) {
3727 aStatus = (*mEventCallback)(event);
3730 // the window can be destroyed during processing of seemingly innocuous events like, say,
3731 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3732 // which causes problems with the deleted window. therefore:
3733 if (mOnDestroyCalled)
3734 aStatus = nsEventStatus_eConsumeNoDefault;
3735 return NS_OK;
3738 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
3740 nsGUIEvent event(PR_TRUE, aMsg, this);
3741 InitEvent(event);
3743 PRBool result = DispatchWindowEvent(&event);
3744 return result;
3747 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
3749 nsEventStatus status;
3750 DispatchEvent(event, status);
3751 return ConvertStatus(status);
3754 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event, nsEventStatus &aStatus) {
3755 DispatchEvent(event, aStatus);
3756 return ConvertStatus(aStatus);
3759 PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
3760 const nsTArray<nsAlternativeCharCode>* aAlternativeCharCodes,
3761 UINT aVirtualCharCode, const MSG *aMsg,
3762 const nsModifierKeyState &aModKeyState,
3763 PRUint32 aFlags)
3765 UserActivity();
3767 nsKeyEvent event(PR_TRUE, aEventType, this);
3768 nsIntPoint point(0, 0);
3770 InitEvent(event, &point); // this add ref's event.widget
3772 event.flags |= aFlags;
3773 event.charCode = aCharCode;
3774 if (aAlternativeCharCodes)
3775 event.alternativeCharCodes.AppendElements(*aAlternativeCharCodes);
3776 event.keyCode = aVirtualCharCode;
3778 #ifdef KE_DEBUG
3779 static cnt=0;
3780 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt++,
3781 (NS_KEY_PRESS == aEventType) ? "PRESS" : (aEventType == NS_KEY_UP ? "Up" : "Down"),
3782 event.charCode, event.keyCode);
3783 printf("Shift: %s Control %s Alt: %s \n",
3784 (mIsShiftDown ? "D" : "U"), (mIsControlDown ? "D" : "U"), (mIsAltDown ? "D" : "U"));
3785 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3786 IS_VK_DOWN(NS_VK_SHIFT) ? 'S' : ' ',
3787 IS_VK_DOWN(NS_VK_CONTROL) ? 'C' : ' ',
3788 IS_VK_DOWN(NS_VK_ALT) ? 'A' : ' ',
3789 IS_VK_DOWN(VK_LSHIFT) ? 'S' : ' ',
3790 IS_VK_DOWN(VK_LCONTROL) ? 'C' : ' ',
3791 IS_VK_DOWN(VK_LMENU) ? 'A' : ' ',
3792 IS_VK_DOWN(VK_RMENU) ? 'A' : ' ',
3793 IS_VK_DOWN(VK_RCONTROL) ? 'C' : ' ',
3794 IS_VK_DOWN(VK_RSHIFT) ? 'S' : ' ');
3795 #endif
3797 event.isShift = aModKeyState.mIsShiftDown;
3798 event.isControl = aModKeyState.mIsControlDown;
3799 event.isMeta = PR_FALSE;
3800 event.isAlt = aModKeyState.mIsAltDown;
3802 NPEvent pluginEvent;
3803 if (aMsg && PluginHasFocus()) {
3804 pluginEvent.event = aMsg->message;
3805 pluginEvent.wParam = aMsg->wParam;
3806 pluginEvent.lParam = aMsg->lParam;
3807 event.pluginEvent = (void *)&pluginEvent;
3810 PRBool result = DispatchWindowEvent(&event);
3812 return result;
3815 PRBool nsWindow::DispatchCommandEvent(PRUint32 aEventCommand)
3817 nsCOMPtr<nsIAtom> command;
3818 switch (aEventCommand) {
3819 case APPCOMMAND_BROWSER_BACKWARD:
3820 command = nsWidgetAtoms::Back;
3821 break;
3822 case APPCOMMAND_BROWSER_FORWARD:
3823 command = nsWidgetAtoms::Forward;
3824 break;
3825 case APPCOMMAND_BROWSER_REFRESH:
3826 command = nsWidgetAtoms::Reload;
3827 break;
3828 case APPCOMMAND_BROWSER_STOP:
3829 command = nsWidgetAtoms::Stop;
3830 break;
3831 case APPCOMMAND_BROWSER_SEARCH:
3832 command = nsWidgetAtoms::Search;
3833 break;
3834 case APPCOMMAND_BROWSER_FAVORITES:
3835 command = nsWidgetAtoms::Bookmarks;
3836 break;
3837 case APPCOMMAND_BROWSER_HOME:
3838 command = nsWidgetAtoms::Home;
3839 break;
3840 default:
3841 return PR_FALSE;
3843 nsCommandEvent event(PR_TRUE, nsWidgetAtoms::onAppCommand, command, this);
3845 InitEvent(event);
3846 DispatchWindowEvent(&event);
3848 return PR_TRUE;
3851 // Recursively dispatch synchronous paints for nsIWidget
3852 // descendants with invalidated rectangles.
3853 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
3855 LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
3856 if (proc == (LONG_PTR)&nsWindow::WindowProc) {
3857 // its one of our windows so check to see if it has a
3858 // invalidated rect. If it does. Dispatch a synchronous
3859 // paint.
3860 if (GetUpdateRect(aWnd, NULL, FALSE))
3861 VERIFY(::UpdateWindow(aWnd));
3863 return TRUE;
3866 // Check for pending paints and dispatch any pending paint
3867 // messages for any nsIWidget which is a descendant of the
3868 // top-level window that *this* window is embedded within.
3870 // Note: We do not dispatch pending paint messages for non
3871 // nsIWidget managed windows.
3872 void nsWindow::DispatchPendingEvents()
3874 if (mPainting) {
3875 NS_WARNING("We were asked to dispatch pending events during painting, "
3876 "denying since that's unsafe.");
3877 return;
3880 // We need to ensure that reflow events do not get starved.
3881 // At the same time, we don't want to recurse through here
3882 // as that would prevent us from dispatching starved paints.
3883 static int recursionBlocker = 0;
3884 if (recursionBlocker++ == 0) {
3885 NS_ProcessPendingEvents(nsnull, PR_MillisecondsToInterval(100));
3886 --recursionBlocker;
3889 // Quickly check to see if there are any
3890 // paint events pending.
3891 if (::GetQueueStatus(QS_PAINT)) {
3892 // Find the top level window.
3893 HWND topWnd = GetTopLevelHWND(mWnd);
3895 // Dispatch pending paints for topWnd and all its descendant windows.
3896 // Note: EnumChildWindows enumerates all descendant windows not just
3897 // the children (but not the window itself).
3898 nsWindow::DispatchStarvedPaints(topWnd, 0);
3899 #if !defined(WINCE)
3900 ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, 0);
3901 #else
3902 nsWindowCE::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3903 #endif
3907 // Deal with plugin events
3908 PRBool nsWindow::DispatchPluginEvent(const MSG &aMsg)
3910 if (!PluginHasFocus())
3911 return PR_FALSE;
3913 nsGUIEvent event(PR_TRUE, NS_PLUGIN_EVENT, this);
3914 nsIntPoint point(0, 0);
3915 InitEvent(event, &point);
3916 NPEvent pluginEvent;
3917 pluginEvent.event = aMsg.message;
3918 pluginEvent.wParam = aMsg.wParam;
3919 pluginEvent.lParam = aMsg.lParam;
3920 event.pluginEvent = (void *)&pluginEvent;
3921 return DispatchWindowEvent(&event);
3924 PRBool nsWindow::DispatchPluginEvent(UINT aMessage,
3925 WPARAM aWParam,
3926 LPARAM aLParam,
3927 PRBool aDispatchPendingEvents)
3929 PRBool ret = DispatchPluginEvent(InitMSG(aMessage, aWParam, aLParam));
3930 if (aDispatchPendingEvents) {
3931 DispatchPendingEvents();
3933 return ret;
3936 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
3937 UINT aLastMsg)
3939 MSG msg;
3940 ::GetMessageW(&msg, mWnd, aFirstMsg, aLastMsg);
3941 DispatchPluginEvent(msg);
3944 // Deal with all sort of mouse event
3945 PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
3946 LPARAM lParam, PRBool aIsContextMenuKey,
3947 PRInt16 aButton, PRUint16 aInputSource)
3949 PRBool result = PR_FALSE;
3951 UserActivity();
3953 if (!mEventCallback) {
3954 return result;
3957 switch (aEventType) {
3958 case NS_MOUSE_BUTTON_DOWN:
3959 CaptureMouse(PR_TRUE);
3960 break;
3962 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3963 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3964 case NS_MOUSE_BUTTON_UP:
3965 case NS_MOUSE_MOVE:
3966 case NS_MOUSE_EXIT:
3967 if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && sIsInMouseCapture)
3968 CaptureMouse(PR_FALSE);
3969 break;
3971 default:
3972 break;
3974 } // switch
3976 nsIntPoint eventPoint;
3977 eventPoint.x = GET_X_LPARAM(lParam);
3978 eventPoint.y = GET_Y_LPARAM(lParam);
3980 nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal,
3981 aIsContextMenuKey
3982 ? nsMouseEvent::eContextMenuKey
3983 : nsMouseEvent::eNormal);
3984 if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) {
3985 nsIntPoint zero(0, 0);
3986 InitEvent(event, &zero);
3987 } else {
3988 InitEvent(event, &eventPoint);
3991 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
3992 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
3993 event.isMeta = PR_FALSE;
3994 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
3995 event.button = aButton;
3996 event.inputSource = aInputSource;
3998 nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
4000 // Suppress mouse moves caused by widget creation
4001 if (aEventType == NS_MOUSE_MOVE)
4003 if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y))
4004 return result;
4005 sLastMouseMovePoint.x = mpScreen.x;
4006 sLastMouseMovePoint.y = mpScreen.y;
4009 PRBool insideMovementThreshold = (abs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
4010 (abs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
4012 BYTE eventButton;
4013 switch (aButton) {
4014 case nsMouseEvent::eLeftButton:
4015 eventButton = VK_LBUTTON;
4016 break;
4017 case nsMouseEvent::eMiddleButton:
4018 eventButton = VK_MBUTTON;
4019 break;
4020 case nsMouseEvent::eRightButton:
4021 eventButton = VK_RBUTTON;
4022 break;
4023 default:
4024 eventButton = 0;
4025 break;
4028 // Doubleclicks are used to set the click count, then changed to mousedowns
4029 // We're going to time double-clicks from mouse *up* to next mouse *down*
4030 #ifndef WINCE
4031 LONG curMsgTime = ::GetMessageTime();
4032 #else
4033 LONG curMsgTime = PR_Now() / 1000;
4034 #endif
4036 if (aEventType == NS_MOUSE_DOUBLECLICK) {
4037 event.message = NS_MOUSE_BUTTON_DOWN;
4038 event.button = aButton;
4039 sLastClickCount = 2;
4041 else if (aEventType == NS_MOUSE_BUTTON_UP) {
4042 // remember when this happened for the next mouse down
4043 sLastMousePoint.x = eventPoint.x;
4044 sLastMousePoint.y = eventPoint.y;
4045 sLastMouseButton = eventButton;
4047 else if (aEventType == NS_MOUSE_BUTTON_DOWN) {
4048 // now look to see if we want to convert this to a double- or triple-click
4049 if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold &&
4050 eventButton == sLastMouseButton) {
4051 sLastClickCount ++;
4052 } else {
4053 // reset the click count, to count *this* click
4054 sLastClickCount = 1;
4056 // Set last Click time on MouseDown only
4057 sLastMouseDownTime = curMsgTime;
4059 else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
4060 sLastClickCount = 0;
4062 else if (aEventType == NS_MOUSE_EXIT) {
4063 event.exit = IsTopLevelMouseExit(mWnd) ? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
4065 else if (aEventType == NS_MOUSE_MOZHITTEST)
4067 event.flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
4069 event.clickCount = sLastClickCount;
4071 #ifdef NS_DEBUG_XX
4072 printf("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount);
4073 #endif
4075 NPEvent pluginEvent;
4077 switch (aEventType)
4079 case NS_MOUSE_BUTTON_DOWN:
4080 switch (aButton) {
4081 case nsMouseEvent::eLeftButton:
4082 pluginEvent.event = WM_LBUTTONDOWN;
4083 break;
4084 case nsMouseEvent::eMiddleButton:
4085 pluginEvent.event = WM_MBUTTONDOWN;
4086 break;
4087 case nsMouseEvent::eRightButton:
4088 pluginEvent.event = WM_RBUTTONDOWN;
4089 break;
4090 default:
4091 break;
4093 break;
4094 case NS_MOUSE_BUTTON_UP:
4095 switch (aButton) {
4096 case nsMouseEvent::eLeftButton:
4097 pluginEvent.event = WM_LBUTTONUP;
4098 break;
4099 case nsMouseEvent::eMiddleButton:
4100 pluginEvent.event = WM_MBUTTONUP;
4101 break;
4102 case nsMouseEvent::eRightButton:
4103 pluginEvent.event = WM_RBUTTONUP;
4104 break;
4105 default:
4106 break;
4108 break;
4109 case NS_MOUSE_DOUBLECLICK:
4110 switch (aButton) {
4111 case nsMouseEvent::eLeftButton:
4112 pluginEvent.event = WM_LBUTTONDBLCLK;
4113 break;
4114 case nsMouseEvent::eMiddleButton:
4115 pluginEvent.event = WM_MBUTTONDBLCLK;
4116 break;
4117 case nsMouseEvent::eRightButton:
4118 pluginEvent.event = WM_RBUTTONDBLCLK;
4119 break;
4120 default:
4121 break;
4123 break;
4124 case NS_MOUSE_MOVE:
4125 pluginEvent.event = WM_MOUSEMOVE;
4126 break;
4127 case NS_MOUSE_EXIT:
4128 pluginEvent.event = WM_MOUSELEAVE;
4129 break;
4130 default:
4131 pluginEvent.event = WM_NULL;
4132 break;
4135 pluginEvent.wParam = wParam; // plugins NEED raw OS event flags!
4136 pluginEvent.lParam = lParam;
4138 event.pluginEvent = (void *)&pluginEvent;
4140 // call the event callback
4141 if (nsnull != mEventCallback) {
4142 if (nsToolkit::gMouseTrailer)
4143 nsToolkit::gMouseTrailer->Disable();
4144 if (aEventType == NS_MOUSE_MOVE) {
4145 if (nsToolkit::gMouseTrailer && !sIsInMouseCapture) {
4146 nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd);
4148 nsIntRect rect;
4149 GetBounds(rect);
4150 rect.x = 0;
4151 rect.y = 0;
4153 if (rect.Contains(event.refPoint)) {
4154 if (sCurrentWindow == NULL || sCurrentWindow != this) {
4155 if ((nsnull != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
4156 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
4157 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, PR_FALSE,
4158 nsMouseEvent::eLeftButton, aInputSource);
4160 sCurrentWindow = this;
4161 if (!mInDtor) {
4162 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
4163 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, PR_FALSE,
4164 nsMouseEvent::eLeftButton, aInputSource);
4168 } else if (aEventType == NS_MOUSE_EXIT) {
4169 if (sCurrentWindow == this) {
4170 sCurrentWindow = nsnull;
4174 result = DispatchWindowEvent(&event);
4176 if (nsToolkit::gMouseTrailer)
4177 nsToolkit::gMouseTrailer->Enable();
4179 // Release the widget with NS_IF_RELEASE() just in case
4180 // the context menu key code in nsEventListenerManager::HandleEvent()
4181 // released it already.
4182 return result;
4185 return result;
4188 // Deal with accessibile event
4189 #ifdef ACCESSIBILITY
4190 nsAccessible*
4191 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType)
4193 if (nsnull == mEventCallback) {
4194 return nsnull;
4197 nsAccessibleEvent event(PR_TRUE, aEventType, this);
4198 InitEvent(event, nsnull);
4200 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
4201 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
4202 event.isMeta = PR_FALSE;
4203 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
4205 DispatchWindowEvent(&event);
4207 return event.mAccessible;
4209 #endif
4211 PRBool nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType)
4213 if (aEventType == NS_ACTIVATE)
4214 sJustGotActivate = PR_FALSE;
4215 sJustGotDeactivate = PR_FALSE;
4217 // retrive the toplevel window or dialog
4218 HWND curWnd = mWnd;
4219 HWND toplevelWnd = NULL;
4220 while (curWnd) {
4221 toplevelWnd = curWnd;
4223 nsWindow *win = GetNSWindowPtr(curWnd);
4224 if (win) {
4225 nsWindowType wintype;
4226 win->GetWindowType(wintype);
4227 if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog)
4228 break;
4231 curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
4234 if (toplevelWnd) {
4235 nsWindow *win = GetNSWindowPtr(toplevelWnd);
4236 if (win)
4237 return win->DispatchFocus(aEventType);
4240 return PR_FALSE;
4243 // Deal with focus messages
4244 PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
4246 // call the event callback
4247 if (mEventCallback) {
4248 nsGUIEvent event(PR_TRUE, aEventType, this);
4249 InitEvent(event);
4251 //focus and blur event should go to their base widget loc, not current mouse pos
4252 event.refPoint.x = 0;
4253 event.refPoint.y = 0;
4255 NPEvent pluginEvent;
4257 switch (aEventType)
4259 case NS_ACTIVATE:
4260 pluginEvent.event = WM_SETFOCUS;
4261 break;
4262 case NS_DEACTIVATE:
4263 pluginEvent.event = WM_KILLFOCUS;
4264 break;
4265 case NS_PLUGIN_ACTIVATE:
4266 pluginEvent.event = WM_KILLFOCUS;
4267 break;
4268 default:
4269 break;
4272 event.pluginEvent = (void *)&pluginEvent;
4274 return DispatchWindowEvent(&event);
4276 return PR_FALSE;
4279 PRBool nsWindow::IsTopLevelMouseExit(HWND aWnd)
4281 DWORD pos = ::GetMessagePos();
4282 POINT mp;
4283 mp.x = GET_X_LPARAM(pos);
4284 mp.y = GET_Y_LPARAM(pos);
4285 HWND mouseWnd = ::WindowFromPoint(mp);
4287 // GetTopLevelHWND will return a HWND for the window frame (which includes
4288 // the non-client area). If the mouse has moved into the non-client area,
4289 // we should treat it as a top-level exit.
4290 HWND mouseTopLevel = nsWindow::GetTopLevelHWND(mouseWnd);
4291 if (mouseWnd == mouseTopLevel)
4292 return PR_TRUE;
4294 return nsWindow::GetTopLevelHWND(aWnd) != mouseTopLevel;
4297 PRBool nsWindow::BlurEventsSuppressed()
4299 // are they suppressed in this window?
4300 if (mBlurSuppressLevel > 0)
4301 return PR_TRUE;
4303 // are they suppressed by any container widget?
4304 HWND parentWnd = ::GetParent(mWnd);
4305 if (parentWnd) {
4306 nsWindow *parent = GetNSWindowPtr(parentWnd);
4307 if (parent)
4308 return parent->BlurEventsSuppressed();
4310 return PR_FALSE;
4313 // In some circumstances (opening dependent windows) it makes more sense
4314 // (and fixes a crash bug) to not blur the parent window. Called from
4315 // nsFilePicker.
4316 void nsWindow::SuppressBlurEvents(PRBool aSuppress)
4318 if (aSuppress)
4319 ++mBlurSuppressLevel; // for this widget
4320 else {
4321 NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression");
4322 if (mBlurSuppressLevel > 0)
4323 --mBlurSuppressLevel;
4327 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
4329 return aStatus == nsEventStatus_eConsumeNoDefault;
4332 /**************************************************************
4334 * SECTION: IPC
4336 * IPC related helpers.
4338 **************************************************************/
4340 #ifdef MOZ_IPC
4342 // static
4343 bool
4344 nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult)
4346 switch(aMsg) {
4347 case WM_SETFOCUS:
4348 case WM_KILLFOCUS:
4349 case WM_ENABLE:
4350 case WM_WINDOWPOSCHANGING:
4351 case WM_WINDOWPOSCHANGED:
4352 case WM_PARENTNOTIFY:
4353 case WM_ACTIVATEAPP:
4354 case WM_NCACTIVATE:
4355 case WM_ACTIVATE:
4356 case WM_CHILDACTIVATE:
4357 case WM_IME_SETCONTEXT:
4358 case WM_IME_NOTIFY:
4359 case WM_SHOWWINDOW:
4360 case WM_CANCELMODE:
4361 case WM_MOUSEACTIVATE:
4362 case WM_CONTEXTMENU:
4363 aResult = 0;
4364 return true;
4366 case WM_SETTINGCHANGE:
4367 case WM_SETCURSOR:
4368 return false;
4371 #ifdef DEBUG
4372 char szBuf[200];
4373 sprintf(szBuf,
4374 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg);
4375 NS_WARNING(szBuf);
4376 #endif
4378 return false;
4381 void
4382 nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
4384 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4385 "Failed to prevent a nonqueued message from running!");
4387 // Modal UI being displayed in windowless plugins.
4388 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4389 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4390 LRESULT res;
4391 if (IsAsyncResponseEvent(msg, res)) {
4392 ReplyMessage(res);
4394 return;
4397 // Handle certain sync plugin events sent to the parent which
4398 // trigger ipc calls that result in deadlocks.
4400 DWORD dwResult = 0;
4401 PRBool handled = PR_FALSE;
4403 switch(msg) {
4404 // Windowless flash sending WM_ACTIVATE events to the main window
4405 // via calls to ShowWindow.
4406 case WM_ACTIVATE:
4407 if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE &&
4408 IsWindow((HWND)lParam))
4409 handled = PR_TRUE;
4410 break;
4411 // Wheel events forwarded from the child.
4412 case WM_MOUSEWHEEL:
4413 case WM_MOUSEHWHEEL:
4414 case WM_HSCROLL:
4415 case WM_VSCROLL:
4416 // Plugins taking or losing focus triggering focus app messages.
4417 case WM_SETFOCUS:
4418 case WM_KILLFOCUS:
4419 // Windowed plugins that pass sys key events to defwndproc generate
4420 // WM_SYSCOMMAND events to the main window.
4421 case WM_SYSCOMMAND:
4422 // Windowed plugins that fire context menu selection events to parent
4423 // windows.
4424 case WM_CONTEXTMENU:
4425 // IME events fired as a result of synchronous focus changes
4426 case WM_IME_SETCONTEXT:
4427 handled = PR_TRUE;
4428 break;
4431 if (handled &&
4432 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4433 ReplyMessage(dwResult);
4437 #endif // MOZ_IPC
4439 /**************************************************************
4440 **************************************************************
4442 ** BLOCK: Native events
4444 ** Main Windows message handlers and OnXXX handlers for
4445 ** Windows event handling.
4447 **************************************************************
4448 **************************************************************/
4450 /**************************************************************
4452 * SECTION: Wind proc.
4454 * The main Windows event procedures and associated
4455 * message processing methods.
4457 **************************************************************/
4459 #ifdef _MSC_VER
4460 static int ReportException(EXCEPTION_POINTERS *aExceptionInfo)
4462 #ifdef MOZ_CRASHREPORTER
4463 nsCOMPtr<nsICrashReporter> cr =
4464 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
4465 if (cr)
4466 cr->WriteMinidumpForException(aExceptionInfo);
4467 #endif
4468 return EXCEPTION_EXECUTE_HANDLER;
4470 #endif
4472 static PRBool
4473 DisplaySystemMenu(HWND hWnd, nsSizeMode sizeMode, PRBool isRtl, PRInt32 x, PRInt32 y)
4475 GetSystemMenu(hWnd, TRUE); // reset the system menu
4476 HMENU hMenu = GetSystemMenu(hWnd, FALSE);
4477 if (hMenu) {
4478 // update the options
4479 switch(sizeMode) {
4480 case nsSizeMode_Fullscreen:
4481 EnableMenuItem(hMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED);
4482 // intentional fall through
4483 case nsSizeMode_Maximized:
4484 EnableMenuItem(hMenu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
4485 EnableMenuItem(hMenu, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
4486 EnableMenuItem(hMenu, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
4487 break;
4488 case nsSizeMode_Minimized:
4489 EnableMenuItem(hMenu, SC_MINIMIZE, MF_BYCOMMAND | MF_GRAYED);
4490 break;
4491 case nsSizeMode_Normal:
4492 EnableMenuItem(hMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED);
4493 break;
4495 LPARAM cmd =
4496 TrackPopupMenu(hMenu,
4497 (TPM_LEFTBUTTON|TPM_RIGHTBUTTON|
4498 TPM_RETURNCMD|TPM_TOPALIGN|
4499 (isRtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN)),
4500 x, y, 0, hWnd, NULL);
4501 if (cmd) {
4502 PostMessage(hWnd, WM_SYSCOMMAND, cmd, 0);
4503 return PR_TRUE;
4506 return PR_FALSE;
4509 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
4510 // exceptions and passes the real work to WindowProcInternal. See bug 587406
4511 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
4512 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4514 #ifdef _MSC_VER
4515 __try {
4516 return WindowProcInternal(hWnd, msg, wParam, lParam);
4518 __except(ReportException(GetExceptionInformation())) {
4519 ::TerminateProcess(::GetCurrentProcess(), 253);
4521 #else
4522 return WindowProcInternal(hWnd, msg, wParam, lParam);
4523 #endif
4526 LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4528 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4529 MOZ_FUNCTION_NAME, __LINE__, hWnd, msg,
4530 wParam, lParam);
4532 if (::GetWindowLongPtrW(hWnd, GWLP_ID) == eFakeTrackPointScrollableID) {
4533 // This message was sent to the FAKETRACKPOINTSCROLLABLE.
4534 if (msg == WM_HSCROLL) {
4535 // Route WM_HSCROLL messages to the main window.
4536 hWnd = ::GetParent(::GetParent(hWnd));
4537 } else {
4538 // Handle all other messages with its original window procedure.
4539 WNDPROC prevWindowProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
4540 return ::CallWindowProcW(prevWindowProc, hWnd, msg, wParam, lParam);
4544 // Get the window which caused the event and ask it to process the message
4545 nsWindow *someWindow = GetNSWindowPtr(hWnd);
4547 #ifdef MOZ_IPC
4548 if (someWindow)
4549 someWindow->IPCWindowProcHandler(msg, wParam, lParam);
4550 #endif
4552 // create this here so that we store the last rolled up popup until after
4553 // the event has been processed.
4554 nsAutoRollup autoRollup;
4556 LRESULT popupHandlingResult;
4557 if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult))
4558 return popupHandlingResult;
4560 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4561 // why we are hitting this assert
4562 if (nsnull == someWindow) {
4563 NS_ASSERTION(someWindow, "someWindow is null, cannot call any CallWindowProc");
4564 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
4567 // hold on to the window for the life of this method, in case it gets
4568 // deleted during processing. yes, it's a double hack, since someWindow
4569 // is not really an interface.
4570 nsCOMPtr<nsISupports> kungFuDeathGrip;
4571 if (!someWindow->mInDtor) // not if we're in the destructor!
4572 kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)someWindow);
4574 // Call ProcessMessage
4575 LRESULT retValue;
4576 if (PR_TRUE == someWindow->ProcessMessage(msg, wParam, lParam, &retValue)) {
4577 return retValue;
4580 LRESULT res = ::CallWindowProcW(someWindow->GetPrevWindowProc(),
4581 hWnd, msg, wParam, lParam);
4583 return res;
4586 // The main windows message processing method for plugins.
4587 // The result means whether this method processed the native
4588 // event for plugin. If false, the native event should be
4589 // processed by the caller self.
4590 PRBool
4591 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
4592 LRESULT *aResult,
4593 PRBool &aCallDefWndProc)
4595 NS_PRECONDITION(aResult, "aResult must be non-null.");
4596 *aResult = 0;
4598 aCallDefWndProc = PR_FALSE;
4599 PRBool eventDispatched = PR_FALSE;
4600 switch (aMsg.message) {
4601 case WM_CHAR:
4602 case WM_SYSCHAR:
4603 *aResult = ProcessCharMessage(aMsg, &eventDispatched);
4604 break;
4606 case WM_KEYUP:
4607 case WM_SYSKEYUP:
4608 *aResult = ProcessKeyUpMessage(aMsg, &eventDispatched);
4609 break;
4611 case WM_KEYDOWN:
4612 case WM_SYSKEYDOWN:
4613 *aResult = ProcessKeyDownMessage(aMsg, &eventDispatched);
4614 break;
4616 case WM_DEADCHAR:
4617 case WM_SYSDEADCHAR:
4619 case WM_CUT:
4620 case WM_COPY:
4621 case WM_PASTE:
4622 case WM_CLEAR:
4623 case WM_UNDO:
4624 break;
4626 default:
4627 return PR_FALSE;
4630 if (!eventDispatched)
4631 aCallDefWndProc = !DispatchPluginEvent(aMsg);
4632 DispatchPendingEvents();
4633 return PR_TRUE;
4636 // The main windows message processing method.
4637 PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
4638 LRESULT *aRetValue)
4640 // (Large blocks of code should be broken out into OnEvent handlers.)
4641 if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
4642 return PR_TRUE;
4644 #if defined(EVENT_DEBUG_OUTPUT)
4645 // First param shows all events, second param indicates whether
4646 // to show mouse move events. See nsWindowDbg for details.
4647 PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
4648 #endif
4650 PRBool eatMessage;
4651 if (nsIMM32Handler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
4652 eatMessage)) {
4653 return mWnd ? eatMessage : PR_TRUE;
4656 if (PluginHasFocus()) {
4657 PRBool callDefaultWndProc;
4658 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4659 if (ProcessMessageForPlugin(nativeMsg, aRetValue, callDefaultWndProc)) {
4660 return mWnd ? !callDefaultWndProc : PR_TRUE;
4664 PRBool result = PR_FALSE; // call the default nsWindow proc
4665 *aRetValue = 0;
4667 static PRBool getWheelInfo = PR_TRUE;
4669 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4670 // Glass hit testing w/custom transparent margins
4671 LRESULT dwmHitResult;
4672 if (mCustomNonClient &&
4673 nsUXThemeData::CheckForCompositor() &&
4674 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) {
4675 *aRetValue = dwmHitResult;
4676 return PR_TRUE;
4678 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4680 switch (msg) {
4681 #ifndef WINCE
4682 // WM_QUERYENDSESSION must be handled by all windows.
4683 // Otherwise Windows thinks the window can just be killed at will.
4684 case WM_QUERYENDSESSION:
4685 if (sCanQuit == TRI_UNKNOWN)
4687 // Ask if it's ok to quit, and store the answer until we
4688 // get WM_ENDSESSION signaling the round is complete.
4689 nsCOMPtr<nsIObserverService> obsServ =
4690 mozilla::services::GetObserverService();
4691 nsCOMPtr<nsISupportsPRBool> cancelQuit =
4692 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
4693 cancelQuit->SetData(PR_FALSE);
4694 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
4696 PRBool abortQuit;
4697 cancelQuit->GetData(&abortQuit);
4698 sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
4700 *aRetValue = sCanQuit ? TRUE : FALSE;
4701 result = PR_TRUE;
4702 break;
4703 #endif
4705 #ifndef WINCE
4706 case WM_ENDSESSION:
4707 #endif
4708 case MOZ_WM_APP_QUIT:
4709 if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE))
4711 // Let's fake a shutdown sequence without actually closing windows etc.
4712 // to avoid Windows killing us in the middle. A proper shutdown would
4713 // require having a chance to pump some messages. Unfortunately
4714 // Windows won't let us do that. Bug 212316.
4715 nsCOMPtr<nsIObserverService> obsServ =
4716 mozilla::services::GetObserverService();
4717 NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
4718 obsServ->NotifyObservers(nsnull, "quit-application-granted", nsnull);
4719 obsServ->NotifyObservers(nsnull, "quit-application-forced", nsnull);
4720 obsServ->NotifyObservers(nsnull, "quit-application", nsnull);
4721 obsServ->NotifyObservers(nsnull, "profile-change-net-teardown", context.get());
4722 obsServ->NotifyObservers(nsnull, "profile-change-teardown", context.get());
4723 obsServ->NotifyObservers(nsnull, "profile-before-change", context.get());
4724 // Then a controlled but very quick exit.
4725 _exit(0);
4727 sCanQuit = TRI_UNKNOWN;
4728 result = PR_TRUE;
4729 break;
4731 #ifndef WINCE
4732 case WM_DISPLAYCHANGE:
4733 DispatchStandardEvent(NS_DISPLAYCHANGED);
4734 break;
4735 #endif
4737 case WM_SYSCOLORCHANGE:
4738 // Note: This is sent for child windows as well as top-level windows.
4739 // The Win32 toolkit normally only sends these events to top-level windows.
4740 // But we cycle through all of the childwindows and send it to them as well
4741 // so all presentations get notified properly.
4742 // See nsWindow::GlobalMsgWindowProc.
4743 DispatchStandardEvent(NS_SYSCOLORCHANGED);
4744 break;
4746 case WM_NOTIFY:
4747 // TAB change
4749 LPNMHDR pnmh = (LPNMHDR) lParam;
4751 switch (pnmh->code) {
4752 case TCN_SELCHANGE:
4754 DispatchStandardEvent(NS_TABCHANGE);
4755 result = PR_TRUE;
4757 break;
4760 break;
4762 case WM_THEMECHANGED:
4764 // Update non-client margin offsets
4765 UpdateNonClientMargins();
4766 nsUXThemeData::InitTitlebarInfo();
4767 nsUXThemeData::UpdateNativeThemeInfo();
4769 DispatchStandardEvent(NS_THEMECHANGED);
4771 // Invalidate the window so that the repaint will
4772 // pick up the new theme.
4773 Invalidate(PR_FALSE);
4775 break;
4777 case WM_FONTCHANGE:
4779 nsresult rv;
4780 PRBool didChange = PR_FALSE;
4782 // update the global font list
4783 nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
4784 if (NS_SUCCEEDED(rv)) {
4785 fontEnum->UpdateFontList(&didChange);
4786 //didChange is TRUE only if new font langGroup is added to the list.
4787 if (didChange) {
4788 // update device context font cache
4789 // Dirty but easiest way:
4790 // Changing nsIPrefBranch entry which triggers callbacks
4791 // and flows into calling mDeviceContext->FlushFontCache()
4792 // to update the font cache in all the instance of Browsers
4793 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
4794 if (prefs) {
4795 nsCOMPtr<nsIPrefBranch> fiPrefs;
4796 prefs->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs));
4797 if (fiPrefs) {
4798 PRBool fontInternalChange = PR_FALSE;
4799 fiPrefs->GetBoolPref("changed", &fontInternalChange);
4800 fiPrefs->SetBoolPref("changed", !fontInternalChange);
4804 } //if (NS_SUCCEEDED(rv))
4806 break;
4808 case WM_NCCALCSIZE:
4810 // If wParam is TRUE, it specifies that the application should indicate
4811 // which part of the client area contains valid information. The system
4812 // copies the valid information to the specified area within the new
4813 // client area. If the wParam parameter is FALSE, the application should
4814 // return zero.
4815 if (mCustomNonClient) {
4816 if (!wParam) {
4817 result = PR_TRUE;
4818 *aRetValue = 0;
4819 break;
4822 // before:
4823 // rgrc[0]: the proposed window
4824 // rgrc[1]: the current window
4825 // rgrc[2]: the source client area
4826 // pncsp->lppos: move/size data
4827 // after:
4828 // rgrc[0]: the new client area
4829 // rgrc[1]: the destination window
4830 // rgrc[2]: the source client area
4831 // (all values in screen coordiantes)
4832 NCCALCSIZE_PARAMS *pncsp = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
4833 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd, msg, wParam, lParam);
4834 pncsp->rgrc[0].top -= mNonClientOffset.top;
4835 pncsp->rgrc[0].left -= mNonClientOffset.left;
4836 pncsp->rgrc[0].right += mNonClientOffset.right;
4837 pncsp->rgrc[0].bottom += mNonClientOffset.bottom;
4839 result = PR_TRUE;
4840 *aRetValue = res;
4842 break;
4845 case WM_NCHITTEST:
4848 * If an nc client area margin has been moved, we are responsible
4849 * for calculating where the resize margins are and returning the
4850 * appropriate set of hit test constants. DwmDefWindowProc (above)
4851 * will handle hit testing on it's command buttons if we are on a
4852 * composited desktop.
4855 if (!mCustomNonClient)
4856 break;
4858 *aRetValue =
4859 ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
4860 result = PR_TRUE;
4861 break;
4864 case WM_SETTEXT:
4866 * WM_SETTEXT paints the titlebar area. Avoid this if we have a
4867 * custom titlebar we paint ourselves.
4870 if (!mCustomNonClient || mNonClientMargins.top == -1)
4871 break;
4874 // From msdn, the way around this is to disable the visible state
4875 // temporarily. We need the text to be set but we don't want the
4876 // redraw to occur.
4877 DWORD style = GetWindowLong(mWnd, GWL_STYLE);
4878 SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
4879 *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd,
4880 msg, wParam, lParam);
4881 SetWindowLong(mWnd, GWL_STYLE, style);
4882 return PR_TRUE;
4885 case WM_NCACTIVATE:
4888 * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
4889 * through WM_NCPAINT via InvalidateNonClientRegion.
4892 if (!mCustomNonClient)
4893 break;
4895 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4896 // let the dwm handle nc painting on glass
4897 if(nsUXThemeData::CheckForCompositor())
4898 break;
4899 #endif
4901 if (wParam == TRUE) {
4902 // going active
4903 *aRetValue = FALSE; // ignored
4904 result = PR_TRUE;
4905 UpdateGetWindowInfoCaptionStatus(PR_TRUE);
4906 // invalidate to trigger a paint
4907 InvalidateNonClientRegion();
4908 break;
4909 } else {
4910 // going inactive
4911 *aRetValue = TRUE; // go ahead and deactive
4912 result = PR_TRUE;
4913 UpdateGetWindowInfoCaptionStatus(PR_FALSE);
4914 // invalidate to trigger a paint
4915 InvalidateNonClientRegion();
4916 break;
4920 case WM_NCPAINT:
4923 * Reset the non-client paint region so that it excludes the
4924 * non-client areas we paint manually. Then call defwndproc
4925 * to do the actual painting.
4928 if (!mCustomNonClient)
4929 break;
4931 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4932 // let the dwm handle nc painting on glass
4933 if(nsUXThemeData::CheckForCompositor())
4934 break;
4935 #endif
4937 HRGN paintRgn = ExcludeNonClientFromPaintRegion((HRGN)wParam);
4938 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd,
4939 msg, (WPARAM)paintRgn, lParam);
4940 if (paintRgn != (HRGN)wParam)
4941 DeleteObject(paintRgn);
4942 *aRetValue = res;
4943 result = PR_TRUE;
4945 break;
4947 #ifndef WINCE
4948 case WM_POWERBROADCAST:
4949 // only hidden window handle this
4950 // to prevent duplicate notification
4951 if (mWindowType == eWindowType_invisible) {
4952 switch (wParam)
4954 case PBT_APMSUSPEND:
4955 PostSleepWakeNotification("sleep_notification");
4956 break;
4957 case PBT_APMRESUMEAUTOMATIC:
4958 case PBT_APMRESUMECRITICAL:
4959 case PBT_APMRESUMESUSPEND:
4960 PostSleepWakeNotification("wake_notification");
4961 break;
4964 break;
4965 #endif
4967 case WM_MOVE: // Window moved
4969 RECT rect;
4970 ::GetWindowRect(mWnd, &rect);
4971 result = OnMove(rect.left, rect.top);
4973 break;
4975 case WM_CLOSE: // close request
4976 DispatchStandardEvent(NS_XUL_CLOSE);
4977 result = PR_TRUE; // abort window closure
4978 break;
4980 case WM_DESTROY:
4981 // clean up.
4982 OnDestroy();
4983 result = PR_TRUE;
4984 break;
4986 case WM_PAINT:
4987 *aRetValue = (int) OnPaint(NULL, 0);
4988 result = PR_TRUE;
4989 break;
4991 #ifndef WINCE
4992 case WM_PRINTCLIENT:
4993 result = OnPaint((HDC) wParam, 0);
4994 break;
4995 #endif
4997 case WM_HOTKEY:
4998 result = OnHotKey(wParam, lParam);
4999 break;
5001 case WM_SYSCHAR:
5002 case WM_CHAR:
5004 MSG nativeMsg = InitMSG(msg, wParam, lParam);
5005 result = ProcessCharMessage(nativeMsg, nsnull);
5006 DispatchPendingEvents();
5008 break;
5010 case WM_SYSKEYUP:
5011 case WM_KEYUP:
5013 MSG nativeMsg = InitMSG(msg, wParam, lParam);
5014 result = ProcessKeyUpMessage(nativeMsg, nsnull);
5015 DispatchPendingEvents();
5017 break;
5019 case WM_SYSKEYDOWN:
5020 case WM_KEYDOWN:
5022 MSG nativeMsg = InitMSG(msg, wParam, lParam);
5023 result = ProcessKeyDownMessage(nativeMsg, nsnull);
5024 DispatchPendingEvents();
5026 break;
5028 // say we've dealt with erase background if widget does
5029 // not need auto-erasing
5030 case WM_ERASEBKGND:
5031 if (!AutoErase((HDC)wParam)) {
5032 *aRetValue = 1;
5033 result = PR_TRUE;
5035 break;
5037 case WM_MOUSEMOVE:
5039 #ifdef WINCE_WINDOWS_MOBILE
5040 // Reset the kill timer so that we can continue at this
5041 // priority
5042 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2seconds */, NULL);
5043 #endif
5044 mMousePresent = PR_TRUE;
5046 // Suppress dispatch of pending events
5047 // when mouse moves are generated by widget
5048 // creation instead of user input.
5049 LPARAM lParamScreen = lParamToScreen(lParam);
5050 POINT mp;
5051 mp.x = GET_X_LPARAM(lParamScreen);
5052 mp.y = GET_Y_LPARAM(lParamScreen);
5053 PRBool userMovedMouse = PR_FALSE;
5054 if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) {
5055 userMovedMouse = PR_TRUE;
5058 result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam,
5059 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5060 if (userMovedMouse) {
5061 DispatchPendingEvents();
5064 break;
5066 case WM_NCMOUSEMOVE:
5067 // If we receive a mouse move event on non-client chrome, make sure and
5068 // send an NS_MOUSE_EXIT event as well.
5069 if (mMousePresent && !sIsInMouseCapture)
5070 SendMessage(mWnd, WM_MOUSELEAVE, 0, 0);
5071 break;
5073 #ifdef WINCE_WINDOWS_MOBILE
5074 case WM_TIMER:
5075 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
5076 KillTimer(mWnd, KILL_PRIORITY_ID);
5077 break;
5078 #endif
5080 case WM_LBUTTONDOWN:
5082 #ifdef WINCE_WINDOWS_MOBILE
5083 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
5084 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2 seconds */, NULL);
5085 #endif
5086 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
5087 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5088 DispatchPendingEvents();
5090 break;
5092 case WM_LBUTTONUP:
5094 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam,
5095 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5096 DispatchPendingEvents();
5098 #ifdef WINCE_WINDOWS_MOBILE
5099 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
5100 KillTimer(mWnd, KILL_PRIORITY_ID);
5101 #endif
5103 break;
5105 #ifndef WINCE
5106 case WM_MOUSELEAVE:
5108 if (!mMousePresent)
5109 break;
5110 mMousePresent = PR_FALSE;
5112 // We need to check mouse button states and put them in for
5113 // wParam.
5114 WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
5115 | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
5116 | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
5117 // Synthesize an event position because we don't get one from
5118 // WM_MOUSELEAVE.
5119 LPARAM pos = lParamToClient(::GetMessagePos());
5120 DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, PR_FALSE,
5121 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5123 break;
5124 #endif
5126 case WM_CONTEXTMENU:
5128 // if the context menu is brought up from the keyboard, |lParam|
5129 // will be -1.
5130 LPARAM pos;
5131 PRBool contextMenukey = PR_FALSE;
5132 if (lParam == -1)
5134 contextMenukey = PR_TRUE;
5135 pos = lParamToClient(GetMessagePos());
5137 else
5139 pos = lParamToClient(lParam);
5142 result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey,
5143 contextMenukey ?
5144 nsMouseEvent::eLeftButton :
5145 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5146 if (lParam != -1 && !result && mCustomNonClient &&
5147 DispatchMouseEvent(NS_MOUSE_MOZHITTEST, wParam, pos,
5148 PR_FALSE, nsMouseEvent::eLeftButton,
5149 MOUSE_INPUT_SOURCE())) {
5150 // Blank area hit, throw up the system menu.
5151 DisplaySystemMenu(mWnd, mSizeMode, mIsRTL, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
5152 result = PR_TRUE;
5155 break;
5157 case WM_LBUTTONDBLCLK:
5158 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
5159 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5160 DispatchPendingEvents();
5161 break;
5163 case WM_MBUTTONDOWN:
5164 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
5165 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5166 DispatchPendingEvents();
5167 break;
5169 case WM_MBUTTONUP:
5170 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
5171 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5172 DispatchPendingEvents();
5173 break;
5175 case WM_MBUTTONDBLCLK:
5176 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
5177 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5178 DispatchPendingEvents();
5179 break;
5181 case WM_NCMBUTTONDOWN:
5182 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam), PR_FALSE,
5183 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5184 DispatchPendingEvents();
5185 break;
5187 case WM_NCMBUTTONUP:
5188 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam), PR_FALSE,
5189 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5190 DispatchPendingEvents();
5191 break;
5193 case WM_NCMBUTTONDBLCLK:
5194 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam), PR_FALSE,
5195 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5196 DispatchPendingEvents();
5197 break;
5199 case WM_RBUTTONDOWN:
5200 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
5201 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5202 DispatchPendingEvents();
5203 break;
5205 case WM_RBUTTONUP:
5206 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
5207 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5208 DispatchPendingEvents();
5209 break;
5211 case WM_RBUTTONDBLCLK:
5212 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
5213 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5214 DispatchPendingEvents();
5215 break;
5217 case WM_NCRBUTTONDOWN:
5218 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam),
5219 PR_FALSE, nsMouseEvent::eRightButton,
5220 MOUSE_INPUT_SOURCE());
5221 DispatchPendingEvents();
5222 break;
5224 case WM_NCRBUTTONUP:
5225 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam),
5226 PR_FALSE, nsMouseEvent::eRightButton,
5227 MOUSE_INPUT_SOURCE());
5228 DispatchPendingEvents();
5229 break;
5231 case WM_NCRBUTTONDBLCLK:
5232 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam),
5233 PR_FALSE, nsMouseEvent::eRightButton,
5234 MOUSE_INPUT_SOURCE());
5235 DispatchPendingEvents();
5236 break;
5238 case WM_APPCOMMAND:
5240 PRUint32 appCommand = GET_APPCOMMAND_LPARAM(lParam);
5242 switch (appCommand)
5244 case APPCOMMAND_BROWSER_BACKWARD:
5245 case APPCOMMAND_BROWSER_FORWARD:
5246 case APPCOMMAND_BROWSER_REFRESH:
5247 case APPCOMMAND_BROWSER_STOP:
5248 case APPCOMMAND_BROWSER_SEARCH:
5249 case APPCOMMAND_BROWSER_FAVORITES:
5250 case APPCOMMAND_BROWSER_HOME:
5251 DispatchCommandEvent(appCommand);
5252 // tell the driver that we handled the event
5253 *aRetValue = 1;
5254 result = PR_TRUE;
5255 break;
5257 // default = PR_FALSE - tell the driver that the event was not handled
5259 break;
5261 case WM_HSCROLL:
5262 case WM_VSCROLL:
5263 *aRetValue = 0;
5264 result = OnScroll(msg, wParam, lParam);
5265 break;
5267 // The WM_ACTIVATE event is fired when a window is raised or lowered,
5268 // and the loword of wParam specifies which. But we don't want to tell
5269 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
5270 // events are fired. Instead, set either the sJustGotActivate or
5271 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
5272 // events once the focus events arrive.
5273 case WM_ACTIVATE:
5274 if (mEventCallback) {
5275 PRInt32 fActive = LOWORD(wParam);
5277 #if defined(WINCE_HAVE_SOFTKB)
5278 if (mIsTopWidgetWindow && sSoftKeyboardState)
5279 nsWindowCE::ToggleSoftKB(mWnd, fActive);
5280 if (nsWindowCE::sShowSIPButton == TRI_FALSE && WA_INACTIVE != fActive) {
5281 HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL );
5282 if (hWndSIPB)
5283 ShowWindow(hWndSIPB, SW_HIDE);
5286 #endif
5288 if (WA_INACTIVE == fActive) {
5289 // when minimizing a window, the deactivation and focus events will
5290 // be fired in the reverse order. Instead, just dispatch
5291 // NS_DEACTIVATE right away.
5292 if (HIWORD(wParam))
5293 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5294 else
5295 sJustGotDeactivate = PR_TRUE;
5296 #ifndef WINCE
5297 if (mIsTopWidgetWindow)
5298 mLastKeyboardLayout = gKbdLayout.GetLayout();
5299 #endif
5301 } else {
5302 StopFlashing();
5304 sJustGotActivate = PR_TRUE;
5305 nsMouseEvent event(PR_TRUE, NS_MOUSE_ACTIVATE, this,
5306 nsMouseEvent::eReal);
5307 InitEvent(event);
5308 DispatchWindowEvent(&event);
5309 #ifndef WINCE
5310 if (sSwitchKeyboardLayout && mLastKeyboardLayout)
5311 ActivateKeyboardLayout(mLastKeyboardLayout, 0);
5312 #endif
5315 #ifdef WINCE_WINDOWS_MOBILE
5316 if (!gCheckForHTCApi && gHTCApiNavOpen == nsnull) {
5317 gCheckForHTCApi = PR_TRUE;
5319 HINSTANCE library = LoadLibrary(L"HTCAPI.dll");
5320 gHTCApiNavOpen = (HTCApiNavOpen) GetProcAddress(library, "HTCNavOpen");
5321 gHTCApiNavSetMode = (HTCApiNavSetMode) GetProcAddress(library ,"HTCNavSetMode");
5324 if (gHTCApiNavOpen != nsnull) {
5325 gHTCApiNavOpen(mWnd, 1 /* undocumented value */);
5327 if (gHTCApiNavSetMode != nsnull)
5328 gHTCApiNavSetMode ( mWnd, 4);
5329 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5331 #endif
5332 break;
5334 #ifndef WINCE
5335 case WM_MOUSEACTIVATE:
5336 if (mWindowType == eWindowType_popup) {
5337 // a popup with a parent owner should not be activated when clicked
5338 // but should still allow the mouse event to be fired, so the return
5339 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5340 // window, just use default processing so that the window is activated.
5341 HWND owner = ::GetWindow(mWnd, GW_OWNER);
5342 if (owner && owner == ::GetForegroundWindow()) {
5343 *aRetValue = MA_NOACTIVATE;
5344 result = PR_TRUE;
5347 break;
5349 case WM_WINDOWPOSCHANGING:
5351 LPWINDOWPOS info = (LPWINDOWPOS) lParam;
5352 OnWindowPosChanging(info);
5354 break;
5355 #endif
5357 case WM_SETFOCUS:
5358 // If previous focused window isn't ours, it must have received the
5359 // redirected message. So, we should forget it.
5360 if (!IsOurProcessWindow(HWND(wParam))) {
5361 ForgetRedirectedKeyDownMessage();
5363 if (sJustGotActivate) {
5364 result = DispatchFocusToTopLevelWindow(NS_ACTIVATE);
5367 #ifdef ACCESSIBILITY
5368 if (nsWindow::sIsAccessibilityOn) {
5369 // Create it for the first time so that it can start firing events
5370 nsAccessible *rootAccessible = GetRootAccessible();
5372 #endif
5374 #if defined(WINCE_HAVE_SOFTKB)
5376 // On Windows CE, we have a window that overlaps
5377 // the ISP button. In this case, we should always
5378 // try to hide it when we are activated
5380 nsIMEContext IMEContext(mWnd);
5381 // Open the IME
5382 ImmSetOpenStatus(IMEContext.get(), TRUE);
5384 #endif
5385 break;
5387 case WM_KILLFOCUS:
5388 #if defined(WINCE_HAVE_SOFTKB)
5390 nsIMEContext IMEContext(mWnd);
5391 ImmSetOpenStatus(IMEContext.get(), FALSE);
5393 #endif
5394 if (sJustGotDeactivate) {
5395 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5397 break;
5399 case WM_WINDOWPOSCHANGED:
5401 WINDOWPOS *wp = (LPWINDOWPOS)lParam;
5402 OnWindowPosChanged(wp, result);
5404 break;
5406 case WM_SETTINGCHANGE:
5407 #if !defined (WINCE_WINDOWS_MOBILE)
5408 getWheelInfo = PR_TRUE;
5409 #else
5410 switch (wParam) {
5411 case SPI_SETSIPINFO:
5412 case SPI_SETCURRENTIM:
5413 nsWindowCE::OnSoftKbSettingsChange(mWnd);
5414 break;
5415 case SETTINGCHANGE_RESET:
5416 if (mWindowType == eWindowType_invisible) {
5417 // The OS sees to get confused and think that the invisable window
5418 // is in the foreground after an orientation change. By actually
5419 // setting it to the foreground and hiding it, we set it strait.
5420 // See bug 514007 for details.
5421 SetForegroundWindow(mWnd);
5422 ShowWindow(mWnd, SW_HIDE);
5424 break;
5426 #endif
5427 OnSettingsChange(wParam, lParam);
5428 break;
5430 #ifndef WINCE
5431 case WM_INPUTLANGCHANGEREQUEST:
5432 *aRetValue = TRUE;
5433 result = PR_FALSE;
5434 break;
5436 case WM_INPUTLANGCHANGE:
5437 result = OnInputLangChange((HKL)lParam);
5438 break;
5439 #endif // WINCE
5441 case WM_DESTROYCLIPBOARD:
5443 nsIClipboard* clipboard;
5444 nsresult rv = CallGetService(kCClipboardCID, &clipboard);
5445 if(NS_SUCCEEDED(rv)) {
5446 clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
5447 NS_RELEASE(clipboard);
5450 break;
5452 #ifdef ACCESSIBILITY
5453 case WM_GETOBJECT:
5455 *aRetValue = 0;
5456 if (lParam == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
5457 nsAccessible *rootAccessible = GetRootAccessible(); // Held by a11y cache
5458 if (rootAccessible) {
5459 IAccessible *msaaAccessible = NULL;
5460 rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref
5461 if (msaaAccessible) {
5462 *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref
5463 msaaAccessible->Release(); // release extra addref
5464 result = PR_TRUE; // We handled the WM_GETOBJECT message
5469 #endif
5471 #ifndef WINCE
5472 case WM_SYSCOMMAND:
5474 WPARAM filteredWParam = (wParam &0xFFF0);
5475 // prevent Windows from trimming the working set. bug 76831
5476 if (!sTrimOnMinimize && filteredWParam == SC_MINIMIZE) {
5477 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
5478 result = PR_TRUE;
5481 // Handle the system menu manually when we're in full screen mode
5482 // so we can set the appropriate options.
5483 if (filteredWParam == SC_KEYMENU && lParam == VK_SPACE &&
5484 mSizeMode == nsSizeMode_Fullscreen) {
5485 DisplaySystemMenu(mWnd, mSizeMode, mIsRTL,
5486 MOZ_SYSCONTEXT_X_POS,
5487 MOZ_SYSCONTEXT_Y_POS);
5488 result = PR_TRUE;
5491 break;
5492 #endif
5495 #ifdef WINCE
5496 case WM_HIBERNATE:
5497 nsMemory::HeapMinimize(PR_TRUE);
5498 break;
5499 #endif
5501 case WM_MOUSEWHEEL:
5502 case WM_MOUSEHWHEEL:
5504 // If OnMouseWheel returns true, the event was forwarded directly to another
5505 // mozilla window message handler (ProcessMessage). In this case the return
5506 // value of the forwarded event is in 'result' which we should return immediately.
5507 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5508 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5509 // we should fall through.
5510 if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue))
5511 return result;
5513 break;
5515 #ifndef WINCE
5516 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5517 case WM_DWMCOMPOSITIONCHANGED:
5518 // First, update the compositor state to latest one. All other methods
5519 // should use same state as here for consistency painting.
5520 nsUXThemeData::CheckForCompositor(PR_TRUE);
5522 UpdateNonClientMargins();
5523 RemovePropW(mWnd, kManageWindowInfoProperty);
5524 BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
5525 DispatchStandardEvent(NS_THEMECHANGED);
5526 UpdateGlass();
5527 Invalidate(PR_FALSE);
5528 break;
5529 #endif
5531 case WM_UPDATEUISTATE:
5533 // If the UI state has changed, fire an event so the UI updates the
5534 // keyboard cues based on the system setting and how the window was
5535 // opened. For example, a dialog opened via a keyboard press on a button
5536 // should enable cues, whereas the same dialog opened via a mouse click of
5537 // the button should not.
5538 PRInt32 action = LOWORD(wParam);
5539 if (action == UIS_SET || action == UIS_CLEAR) {
5540 nsUIStateChangeEvent event(PR_TRUE, NS_UISTATECHANGED, this);
5541 PRInt32 flags = HIWORD(wParam);
5542 if (flags & UISF_HIDEACCEL)
5543 event.showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5544 if (flags & UISF_HIDEFOCUS)
5545 event.showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5546 DispatchWindowEvent(&event);
5549 break;
5552 /* Gesture support events */
5553 case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
5554 // According to MS samples, this must be handled to enable
5555 // rotational support in multi-touch drivers.
5556 result = PR_TRUE;
5557 *aRetValue = TABLET_ROTATE_GESTURE_ENABLE;
5558 break;
5560 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5561 case WM_TOUCH:
5562 result = OnTouch(wParam, lParam);
5563 if (result) {
5564 *aRetValue = 0;
5566 break;
5567 #endif
5569 case WM_GESTURE:
5570 result = OnGesture(wParam, lParam);
5571 break;
5573 case WM_GESTURENOTIFY:
5575 if (mWindowType != eWindowType_invisible &&
5576 mWindowType != eWindowType_plugin) {
5577 // A GestureNotify event is dispatched to decide which single-finger panning
5578 // direction should be active (including none) and if pan feedback should
5579 // be displayed. Java and plugin windows can make their own calls.
5580 GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
5581 nsPointWin touchPoint;
5582 touchPoint = gestureinfo->ptsLocation;
5583 touchPoint.ScreenToClient(mWnd);
5584 nsGestureNotifyEvent gestureNotifyEvent(PR_TRUE, NS_GESTURENOTIFY_EVENT_START, this);
5585 gestureNotifyEvent.refPoint = touchPoint;
5586 nsEventStatus status;
5587 DispatchEvent(&gestureNotifyEvent, status);
5588 mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
5589 if (!mTouchWindow)
5590 mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
5592 result = PR_FALSE; //should always bubble to DefWindowProc
5594 break;
5595 #endif // !defined(WINCE)
5597 case WM_CLEAR:
5599 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_DELETE, this);
5600 DispatchWindowEvent(&command);
5601 result = PR_TRUE;
5603 break;
5605 case WM_CUT:
5607 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_CUT, this);
5608 DispatchWindowEvent(&command);
5609 result = PR_TRUE;
5611 break;
5613 case WM_COPY:
5615 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_COPY, this);
5616 DispatchWindowEvent(&command);
5617 result = PR_TRUE;
5619 break;
5621 case WM_PASTE:
5623 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE, this);
5624 DispatchWindowEvent(&command);
5625 result = PR_TRUE;
5627 break;
5629 #ifndef WINCE
5630 case EM_UNDO:
5632 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO, this);
5633 DispatchWindowEvent(&command);
5634 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5635 result = PR_TRUE;
5637 break;
5639 case EM_REDO:
5641 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO, this);
5642 DispatchWindowEvent(&command);
5643 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5644 result = PR_TRUE;
5646 break;
5648 case EM_CANPASTE:
5650 // Support EM_CANPASTE message only when wParam isn't specified or
5651 // is plain text format.
5652 if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
5653 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE,
5654 this, PR_TRUE);
5655 DispatchWindowEvent(&command);
5656 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5657 result = PR_TRUE;
5660 break;
5662 case EM_CANUNDO:
5664 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO,
5665 this, PR_TRUE);
5666 DispatchWindowEvent(&command);
5667 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5668 result = PR_TRUE;
5670 break;
5672 case EM_CANREDO:
5674 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO,
5675 this, PR_TRUE);
5676 DispatchWindowEvent(&command);
5677 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5678 result = PR_TRUE;
5680 break;
5681 #endif
5683 #ifdef WINCE_WINDOWS_MOBILE
5684 //HTC NAVIGATION WHEEL EVENT
5685 case WM_HTCNAV:
5687 int distance = wParam & 0x000000FF;
5688 if ( (wParam & 0x000000100) != 0) // Counter Clockwise
5689 distance *= -1;
5690 if (OnMouseWheel(WM_MOUSEWHEEL, MAKEWPARAM(0, distance),
5691 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN) / 2,
5692 GetSystemMetrics(SM_CYSCREEN) / 2),
5693 getWheelInfo, result, aRetValue))
5694 return result;
5696 break;
5697 #endif
5699 default:
5701 #ifdef NS_ENABLE_TSF
5702 if (msg == WM_USER_TSF_TEXTCHANGE) {
5703 nsTextStore::OnTextChangeMsg();
5705 #endif //NS_ENABLE_TSF
5706 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5707 if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
5708 SetHasTaskbarIconBeenCreated();
5709 #endif
5710 #ifdef MOZ_IPC
5711 if (msg == sOOPPPluginFocusEvent) {
5712 if (wParam == 1) {
5713 // With OOPP, the plugin window exists in another process and is a child of
5714 // this window. This window is a placeholder plugin window for the dom. We
5715 // receive this event when the child window receives focus. (sent from
5716 // PluginInstanceParent.cpp)
5717 ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
5718 } else {
5719 // WM_KILLFOCUS was received by the child process.
5720 if (sJustGotDeactivate) {
5721 DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5725 #endif
5727 break;
5730 //*aRetValue = result;
5731 if (mWnd) {
5732 return result;
5734 else {
5735 //Events which caused mWnd destruction and aren't consumed
5736 //will crash during the Windows default processing.
5737 return PR_TRUE;
5741 /**************************************************************
5743 * SECTION: Broadcast messaging
5745 * Broadcast messages to all windows.
5747 **************************************************************/
5749 // Enumerate all child windows sending aMsg to each of them
5750 BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg)
5752 WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
5753 if (winProc == &nsWindow::WindowProc) {
5754 // it's one of our windows so go ahead and send a message to it
5755 ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0);
5757 return TRUE;
5760 // Enumerate all top level windows specifying that the children of each
5761 // top level window should be enumerated. Do *not* send the message to
5762 // each top level window since it is assumed that the toolkit will send
5763 // aMsg to them directly.
5764 BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg)
5766 // Iterate each of aTopWindows child windows sending the aMsg
5767 // to each of them.
5768 #if !defined(WINCE)
5769 ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5770 #else
5771 nsWindowCE::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5772 #endif
5773 return TRUE;
5776 // This method is called from nsToolkit::WindowProc to forward global
5777 // messages which need to be dispatched to all child windows.
5778 void nsWindow::GlobalMsgWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
5780 switch (msg) {
5781 case WM_SYSCOLORCHANGE:
5782 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5783 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5784 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5785 // all child windows as well. When running in an embedded application
5786 // we may not receive a WM_SYSCOLORCHANGE message because the top
5787 // level window is owned by the embeddor.
5788 // System color changes are posted to top-level windows only.
5789 // The NS_SYSCOLORCHANGE must be dispatched to all child
5790 // windows as well.
5791 #if !defined(WINCE)
5792 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, msg);
5793 #endif
5794 break;
5798 /**************************************************************
5800 * SECTION: Event processing helpers
5802 * Special processing for certain event types and
5803 * synthesized events.
5805 **************************************************************/
5807 PRInt32
5808 nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
5810 // Calculations are done in screen coords
5811 RECT winRect;
5812 GetWindowRect(mWnd, &winRect);
5814 // hit return constants:
5815 // HTBORDER - non-resizable border
5816 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5817 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5818 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5819 // HTCAPTION - general title bar area
5820 // HTCLIENT - area considered the client
5821 // HTCLOSE - hovering over the close button
5822 // HTMAXBUTTON - maximize button
5823 // HTMINBUTTON - minimize button
5825 PRInt32 testResult = HTCLIENT;
5827 PRBool top = PR_FALSE;
5828 PRBool bottom = PR_FALSE;
5829 PRBool left = PR_FALSE;
5830 PRBool right = PR_FALSE;
5832 if (my >= winRect.top && my <
5833 (winRect.top + mVertResizeMargin + (mCaptionHeight - mNonClientOffset.top)))
5834 top = PR_TRUE;
5835 else if (my < winRect.bottom && my >= (winRect.bottom - mVertResizeMargin))
5836 bottom = PR_TRUE;
5838 if (mx >= winRect.left && mx < (winRect.left +
5839 (bottom ? (2*mHorResizeMargin) : mHorResizeMargin)))
5840 left = PR_TRUE;
5841 else if (mx < winRect.right && mx >= (winRect.right -
5842 (bottom ? (2*mHorResizeMargin) : mHorResizeMargin)))
5843 right = PR_TRUE;
5845 if (top) {
5846 testResult = HTTOP;
5847 if (left)
5848 testResult = HTTOPLEFT;
5849 else if (right)
5850 testResult = HTTOPRIGHT;
5851 } else if (bottom) {
5852 testResult = HTBOTTOM;
5853 if (left)
5854 testResult = HTBOTTOMLEFT;
5855 else if (right)
5856 testResult = HTBOTTOMRIGHT;
5857 } else {
5858 if (left)
5859 testResult = HTLEFT;
5860 if (right)
5861 testResult = HTRIGHT;
5864 PRBool contentOverlap = PR_TRUE;
5866 if (mSizeMode == nsSizeMode_Maximized) {
5867 // There's no HTTOP in maximized state (bug 575493)
5868 if (testResult == HTTOP) {
5869 testResult = HTCAPTION;
5871 } else {
5872 PRInt32 leftMargin = mNonClientMargins.left == -1 ? mHorResizeMargin : mNonClientMargins.left;
5873 PRInt32 rightMargin = mNonClientMargins.right == -1 ? mHorResizeMargin : mNonClientMargins.right;
5874 PRInt32 topMargin = mNonClientMargins.top == -1 ? mVertResizeMargin : mNonClientMargins.top;
5875 PRInt32 bottomMargin = mNonClientMargins.bottom == -1 ? mVertResizeMargin : mNonClientMargins.bottom;
5877 contentOverlap = mx >= winRect.left + leftMargin &&
5878 mx <= winRect.right - rightMargin &&
5879 my >= winRect.top + topMargin &&
5880 my <= winRect.bottom - bottomMargin;
5883 if (!sIsInMouseCapture &&
5884 contentOverlap &&
5885 (testResult == HTCLIENT ||
5886 testResult == HTTOP ||
5887 testResult == HTTOPLEFT ||
5888 testResult == HTCAPTION)) {
5889 LPARAM lParam = MAKELPARAM(mx, my);
5890 LPARAM lParamClient = lParamToClient(lParam);
5891 PRBool result = DispatchMouseEvent(NS_MOUSE_MOZHITTEST, 0, lParamClient,
5892 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5893 if (result) {
5894 // The mouse is over a blank area
5895 testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
5897 } else {
5898 // There's content over the mouse pointer. Set HTCLIENT
5899 // to possibly override a resizer border.
5900 testResult = HTCLIENT;
5904 return testResult;
5907 #ifndef WINCE
5908 void nsWindow::PostSleepWakeNotification(const char* aNotification)
5910 nsCOMPtr<nsIObserverService> observerService =
5911 mozilla::services::GetObserverService();
5912 if (observerService)
5913 observerService->NotifyObservers(nsnull, aNotification, nsnull);
5915 #endif
5917 // RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
5918 // message handler. If there is no WM_(SYS)CHAR message for it, this
5919 // method does nothing.
5920 // NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
5921 // called in message loop. So, WM_(SYS)KEYDOWN message should have
5922 // WM_(SYS)CHAR message in the queue if the keydown event causes character
5923 // input.
5925 /* static */
5926 void nsWindow::RemoveNextCharMessage(HWND aWnd)
5928 MSG msg;
5929 if (::PeekMessageW(&msg, aWnd,
5930 WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD) &&
5931 (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) {
5932 ::GetMessageW(&msg, aWnd, msg.message, msg.message);
5936 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, PRBool *aEventDispatched)
5938 NS_PRECONDITION(aMsg.message == WM_CHAR || aMsg.message == WM_SYSCHAR,
5939 "message is not keydown event");
5940 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5941 ("%s charCode=%d scanCode=%d\n",
5942 aMsg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
5943 aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF));
5945 // These must be checked here too as a lone WM_CHAR could be received
5946 // if a child window didn't handle it (for example Alt+Space in a content window)
5947 nsModifierKeyState modKeyState;
5948 return OnChar(aMsg, modKeyState, aEventDispatched);
5951 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, PRBool *aEventDispatched)
5953 NS_PRECONDITION(aMsg.message == WM_KEYUP || aMsg.message == WM_SYSKEYUP,
5954 "message is not keydown event");
5955 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5956 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5957 "WM_SYSKEYUP" : "WM_KEYUP", aMsg.wParam));
5959 nsModifierKeyState modKeyState;
5961 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5962 // scan code. However, this breaks Alt+Num pad input.
5963 // MSDN states the following:
5964 // Typically, ToAscii performs the translation based on the
5965 // virtual-key code. In some cases, however, bit 15 of the
5966 // uScanCode parameter may be used to distinguish between a key
5967 // press and a key release. The scan code is used for
5968 // translating ALT+number key combinations.
5970 // ignore [shift+]alt+space so the OS can handle it
5971 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5972 IS_VK_DOWN(NS_VK_SPACE)) {
5973 return FALSE;
5976 if (!nsIMM32Handler::IsComposingOn(this) &&
5977 (aMsg.message != WM_KEYUP || aMsg.wParam != VK_MENU)) {
5978 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5979 // This helps avoid triggering the menu bar for ALT key accelerators used in
5980 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5981 // to switch back to Mozilla in Windows 95 and Windows 98
5982 return OnKeyUp(aMsg, modKeyState, aEventDispatched);
5985 return 0;
5988 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
5989 PRBool *aEventDispatched)
5991 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5992 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5993 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg.wParam));
5994 NS_PRECONDITION(aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN,
5995 "message is not keydown event");
5997 // If this method doesn't call OnKeyDown(), this method must clean up the
5998 // redirected message information itself. For more information, see above
5999 // comment of AutoForgetRedirectedKeyDownMessage struct definition in
6000 // nsWindow.h.
6001 AutoForgetRedirectedKeyDownMessage forgetRedirectedMessage(this, aMsg);
6003 nsModifierKeyState modKeyState;
6005 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
6006 // scan code. However, this breaks Alt+Num pad input.
6007 // MSDN states the following:
6008 // Typically, ToAscii performs the translation based on the
6009 // virtual-key code. In some cases, however, bit 15 of the
6010 // uScanCode parameter may be used to distinguish between a key
6011 // press and a key release. The scan code is used for
6012 // translating ALT+number key combinations.
6014 // ignore [shift+]alt+space so the OS can handle it
6015 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
6016 IS_VK_DOWN(NS_VK_SPACE))
6017 return FALSE;
6019 LRESULT result = 0;
6020 if (modKeyState.mIsAltDown && nsIMM32Handler::IsStatusChanged()) {
6021 nsIMM32Handler::NotifyEndStatusChange();
6022 } else if (!nsIMM32Handler::IsComposingOn(this)) {
6023 result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nsnull);
6024 // OnKeyDown cleaned up the redirected message information itself, so,
6025 // we should do nothing.
6026 forgetRedirectedMessage.mCancel = PR_TRUE;
6029 #ifndef WINCE
6030 if (aMsg.wParam == VK_MENU ||
6031 (aMsg.wParam == VK_F10 && !modKeyState.mIsShiftDown)) {
6032 // We need to let Windows handle this keypress,
6033 // by returning PR_FALSE, if there's a native menu
6034 // bar somewhere in our containing window hierarchy.
6035 // Otherwise we handle the keypress and don't pass
6036 // it on to Windows, by returning PR_TRUE.
6037 PRBool hasNativeMenu = PR_FALSE;
6038 HWND hWnd = mWnd;
6039 while (hWnd) {
6040 if (::GetMenu(hWnd)) {
6041 hasNativeMenu = PR_TRUE;
6042 break;
6044 hWnd = ::GetParent(hWnd);
6046 result = !hasNativeMenu;
6048 #endif
6050 return result;
6053 nsresult
6054 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
6055 PRInt32 aNativeKeyCode,
6056 PRUint32 aModifierFlags,
6057 const nsAString& aCharacters,
6058 const nsAString& aUnmodifiedCharacters)
6060 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
6061 nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
6062 HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
6063 if (loadedLayout == NULL)
6064 return NS_ERROR_NOT_AVAILABLE;
6066 // Setup clean key state and load desired layout
6067 BYTE originalKbdState[256];
6068 ::GetKeyboardState(originalKbdState);
6069 BYTE kbdState[256];
6070 memset(kbdState, 0, sizeof(kbdState));
6071 // This changes the state of the keyboard for the current thread only,
6072 // and we'll restore it soon, so this should be OK.
6073 ::SetKeyboardState(kbdState);
6074 HKL oldLayout = gKbdLayout.GetLayout();
6075 gKbdLayout.LoadLayout(loadedLayout);
6077 nsAutoTArray<KeyPair,10> keySequence;
6078 SetupKeyModifiersSequence(&keySequence, aModifierFlags);
6079 NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
6080 "Native VK key code out of range");
6081 keySequence.AppendElement(KeyPair(aNativeKeyCode, 0));
6083 // Simulate the pressing of each modifier key and then the real key
6084 for (PRUint32 i = 0; i < keySequence.Length(); ++i) {
6085 PRUint8 key = keySequence[i].mGeneral;
6086 PRUint8 keySpecific = keySequence[i].mSpecific;
6087 kbdState[key] = 0x81; // key is down and toggled on if appropriate
6088 if (keySpecific) {
6089 kbdState[keySpecific] = 0x81;
6091 ::SetKeyboardState(kbdState);
6092 nsModifierKeyState modKeyState;
6093 MSG msg = InitMSG(WM_KEYDOWN, key, 0);
6094 if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
6095 UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
6096 gKbdLayout.GetLayout());
6097 nsFakeCharMessage fakeMsg = { aCharacters.CharAt(0), scanCode };
6098 OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
6099 } else {
6100 OnKeyDown(msg, modKeyState, nsnull, nsnull);
6103 for (PRUint32 i = keySequence.Length(); i > 0; --i) {
6104 PRUint8 key = keySequence[i - 1].mGeneral;
6105 PRUint8 keySpecific = keySequence[i - 1].mSpecific;
6106 kbdState[key] = 0; // key is up and toggled off if appropriate
6107 if (keySpecific) {
6108 kbdState[keySpecific] = 0;
6110 ::SetKeyboardState(kbdState);
6111 nsModifierKeyState modKeyState;
6112 MSG msg = InitMSG(WM_KEYUP, key, 0);
6113 OnKeyUp(msg, modKeyState, nsnull);
6116 // Restore old key state and layout
6117 ::SetKeyboardState(originalKbdState);
6118 gKbdLayout.LoadLayout(oldLayout);
6120 UnloadKeyboardLayout(loadedLayout);
6121 return NS_OK;
6122 #else //XXX: is there another way to do this?
6123 return NS_ERROR_NOT_IMPLEMENTED;
6124 #endif
6127 nsresult
6128 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
6129 PRUint32 aNativeMessage,
6130 PRUint32 aModifierFlags)
6132 #ifndef WINCE // I don't think WINCE supports SendInput
6133 RECT r;
6134 ::GetWindowRect(mWnd, &r);
6135 ::SetCursorPos(r.left + aPoint.x, r.top + aPoint.y);
6137 INPUT input;
6138 memset(&input, 0, sizeof(input));
6140 input.type = INPUT_MOUSE;
6141 input.mi.dwFlags = aNativeMessage;
6142 ::SendInput(1, &input, sizeof(INPUT));
6144 return NS_OK;
6145 #else
6146 return NS_ERROR_NOT_IMPLEMENTED;
6147 #endif
6150 /**************************************************************
6152 * SECTION: OnXXX message handlers
6154 * For message handlers that need to be broken out or
6155 * implemented in specific platform code.
6157 **************************************************************/
6159 BOOL nsWindow::OnInputLangChange(HKL aHKL)
6161 #ifdef KE_DEBUG
6162 printf("OnInputLanguageChange\n");
6163 #endif
6165 #ifndef WINCE
6166 gKbdLayout.LoadLayout(aHKL);
6167 #endif
6169 return PR_FALSE; // always pass to child window
6172 #if !defined(WINCE) // implemented in nsWindowCE.cpp
6173 void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, PRBool& result)
6175 if (wp == nsnull)
6176 return;
6178 #ifdef WINSTATE_DEBUG_OUTPUT
6179 if (mWnd == GetTopLevelHWND(mWnd))
6180 printf("*** OnWindowPosChanged: [ top] ");
6181 else
6182 printf("*** OnWindowPosChanged: [child] ");
6183 printf("WINDOWPOS flags:");
6184 if (wp->flags & SWP_FRAMECHANGED)
6185 printf("SWP_FRAMECHANGED ");
6186 if (wp->flags & SWP_SHOWWINDOW)
6187 printf("SWP_SHOWWINDOW ");
6188 if (wp->flags & SWP_NOSIZE)
6189 printf("SWP_NOSIZE ");
6190 if (wp->flags & SWP_HIDEWINDOW)
6191 printf("SWP_HIDEWINDOW ");
6192 if (wp->flags & SWP_NOZORDER)
6193 printf("SWP_NOZORDER ");
6194 if (wp->flags & SWP_NOACTIVATE)
6195 printf("SWP_NOACTIVATE ");
6196 printf("\n");
6197 #endif
6199 // Handle window size mode changes
6200 if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
6202 // Bug 566135 - Windows theme code calls show window on SW_SHOWMINIMIZED
6203 // windows when fullscreen games disable desktop composition. If we're
6204 // minimized and not being activated, ignore the event and let windows
6205 // handle it.
6206 if (mSizeMode == nsSizeMode_Minimized && (wp->flags & SWP_NOACTIVATE))
6207 return;
6209 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
6211 WINDOWPLACEMENT pl;
6212 pl.length = sizeof(pl);
6213 ::GetWindowPlacement(mWnd, &pl);
6215 if (pl.showCmd == SW_SHOWMAXIMIZED)
6216 event.mSizeMode = nsSizeMode_Maximized;
6217 else if (pl.showCmd == SW_SHOWMINIMIZED)
6218 event.mSizeMode = nsSizeMode_Minimized;
6219 else if (mFullscreenMode)
6220 event.mSizeMode = nsSizeMode_Fullscreen;
6221 else
6222 event.mSizeMode = nsSizeMode_Normal;
6224 // Windows has just changed the size mode of this window. The following
6225 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
6226 // set the min/max window state again or for nsSizeMode_Normal, call
6227 // SetWindow with a parameter of SW_RESTORE. There's no need however as
6228 // this window's mode has already changed. Updating mSizeMode here
6229 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
6230 // to window docking. (bug 489258)
6231 mSizeMode = event.mSizeMode;
6233 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
6234 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
6235 // prevents the working set from being trimmed but keeps the window active.
6236 // After the window is minimized, we need to do some touch up work on the
6237 // active window. (bugs 76831 & 499816)
6238 if (!sTrimOnMinimize && nsSizeMode_Minimized == event.mSizeMode)
6239 ActivateOtherWindowHelper(mWnd);
6241 #ifdef WINSTATE_DEBUG_OUTPUT
6242 switch (mSizeMode) {
6243 case nsSizeMode_Normal:
6244 printf("*** mSizeMode: nsSizeMode_Normal\n");
6245 break;
6246 case nsSizeMode_Minimized:
6247 printf("*** mSizeMode: nsSizeMode_Minimized\n");
6248 break;
6249 case nsSizeMode_Maximized:
6250 printf("*** mSizeMode: nsSizeMode_Maximized\n");
6251 break;
6252 default:
6253 printf("*** mSizeMode: ??????\n");
6254 break;
6256 #endif
6258 InitEvent(event);
6260 result = DispatchWindowEvent(&event);
6262 // Skip window size change events below on minimization.
6263 if (mSizeMode == nsSizeMode_Minimized)
6264 return;
6267 // Handle window size changes
6268 if (!(wp->flags & SWP_NOSIZE)) {
6269 RECT r;
6270 PRInt32 newWidth, newHeight;
6272 ::GetWindowRect(mWnd, &r);
6274 newWidth = r.right - r.left;
6275 newHeight = r.bottom - r.top;
6276 nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
6278 #ifdef MOZ_XUL
6279 if (eTransparencyTransparent == mTransparencyMode)
6280 ResizeTranslucentWindow(newWidth, newHeight);
6281 #endif
6283 if (newWidth > mLastSize.width)
6285 RECT drect;
6287 // getting wider
6288 drect.left = wp->x + mLastSize.width;
6289 drect.top = wp->y;
6290 drect.right = drect.left + (newWidth - mLastSize.width);
6291 drect.bottom = drect.top + newHeight;
6293 ::RedrawWindow(mWnd, &drect, NULL,
6294 RDW_INVALIDATE |
6295 RDW_NOERASE |
6296 RDW_NOINTERNALPAINT |
6297 RDW_ERASENOW |
6298 RDW_ALLCHILDREN);
6300 if (newHeight > mLastSize.height)
6302 RECT drect;
6304 // getting taller
6305 drect.left = wp->x;
6306 drect.top = wp->y + mLastSize.height;
6307 drect.right = drect.left + newWidth;
6308 drect.bottom = drect.top + (newHeight - mLastSize.height);
6310 ::RedrawWindow(mWnd, &drect, NULL,
6311 RDW_INVALIDATE |
6312 RDW_NOERASE |
6313 RDW_NOINTERNALPAINT |
6314 RDW_ERASENOW |
6315 RDW_ALLCHILDREN);
6318 mBounds.width = newWidth;
6319 mBounds.height = newHeight;
6320 mLastSize.width = newWidth;
6321 mLastSize.height = newHeight;
6323 #ifdef WINSTATE_DEBUG_OUTPUT
6324 printf("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, newWidth, newHeight);
6325 #endif
6327 // If a maximized window is resized, recalculate the non-client margins and
6328 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
6329 // work properly.
6330 if (mSizeMode == nsSizeMode_Maximized) {
6331 if (UpdateNonClientMargins(nsSizeMode_Maximized, PR_TRUE)) {
6332 // gecko resize event already sent by UpdateNonClientMargins.
6333 result = PR_TRUE;
6334 return;
6338 // Recalculate the width and height based on the client area for gecko events.
6339 if (::GetClientRect(mWnd, &r)) {
6340 rect.width = r.right - r.left;
6341 rect.height = r.bottom - r.top;
6344 // Send a gecko resize event
6345 result = OnResize(rect);
6349 // static
6350 void nsWindow::ActivateOtherWindowHelper(HWND aWnd)
6352 // Find the next window that is enabled, visible, and not minimized.
6353 HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT);
6354 while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) ||
6355 ::IsIconic(hwndBelow))) {
6356 hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT);
6359 // Push ourselves to the bottom of the stack, then activate the
6360 // next window.
6361 ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0,
6362 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
6363 if (hwndBelow)
6364 ::SetForegroundWindow(hwndBelow);
6366 // Play the minimize sound while we're here, since that is also
6367 // forgotten when we use SW_SHOWMINIMIZED.
6368 ::PlaySoundW(L"Minimize", nsnull, SND_ALIAS | SND_NODEFAULT | SND_ASYNC);
6370 #endif // !defined(WINCE)
6372 #if !defined(WINCE)
6373 void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info)
6375 // Update non-client margins if the frame size is changing, and let the
6376 // browser know we are changing size modes, so alternative css can kick in.
6377 // If we're going into fullscreen mode, ignore this, since it'll reset
6378 // margins to normal mode.
6379 if ((info->flags & SWP_FRAMECHANGED && !(info->flags & SWP_NOSIZE)) &&
6380 mSizeMode != nsSizeMode_Fullscreen) {
6381 WINDOWPLACEMENT pl;
6382 pl.length = sizeof(pl);
6383 ::GetWindowPlacement(mWnd, &pl);
6384 PRInt32 sizeMode;
6385 if (pl.showCmd == SW_SHOWMAXIMIZED)
6386 sizeMode = nsSizeMode_Maximized;
6387 else if (pl.showCmd == SW_SHOWMINIMIZED)
6388 sizeMode = nsSizeMode_Minimized;
6389 else if (mFullscreenMode)
6390 sizeMode = nsSizeMode_Fullscreen;
6391 else
6392 sizeMode = nsSizeMode_Normal;
6394 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
6396 InitEvent(event);
6397 event.mSizeMode = static_cast<nsSizeMode>(sizeMode);
6398 DispatchWindowEvent(&event);
6400 UpdateNonClientMargins(sizeMode, PR_FALSE);
6403 // enforce local z-order rules
6404 if (!(info->flags & SWP_NOZORDER)) {
6405 HWND hwndAfter = info->hwndInsertAfter;
6407 nsZLevelEvent event(PR_TRUE, NS_SETZLEVEL, this);
6408 nsWindow *aboveWindow = 0;
6410 InitEvent(event);
6412 if (hwndAfter == HWND_BOTTOM)
6413 event.mPlacement = nsWindowZBottom;
6414 else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
6415 event.mPlacement = nsWindowZTop;
6416 else {
6417 event.mPlacement = nsWindowZRelative;
6418 aboveWindow = GetNSWindowPtr(hwndAfter);
6420 event.mReqBelow = aboveWindow;
6421 event.mActualBelow = nsnull;
6423 event.mImmediate = PR_FALSE;
6424 event.mAdjusted = PR_FALSE;
6425 DispatchWindowEvent(&event);
6427 if (event.mAdjusted) {
6428 if (event.mPlacement == nsWindowZBottom)
6429 info->hwndInsertAfter = HWND_BOTTOM;
6430 else if (event.mPlacement == nsWindowZTop)
6431 info->hwndInsertAfter = HWND_TOP;
6432 else {
6433 info->hwndInsertAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
6436 NS_IF_RELEASE(event.mActualBelow);
6438 // prevent rude external programs from making hidden window visible
6439 if (mWindowType == eWindowType_invisible)
6440 info->flags &= ~SWP_SHOWWINDOW;
6442 #endif
6444 void nsWindow::UserActivity()
6446 // Check if we have the idle service, if not we try to get it.
6447 if (!mIdleService) {
6448 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
6451 // Check that we now have the idle service.
6452 if (mIdleService) {
6453 mIdleService->ResetIdleTimeOut();
6457 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6458 PRBool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam)
6460 PRUint32 cInputs = LOWORD(wParam);
6461 PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
6463 if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) {
6464 for (PRUint32 i = 0; i < cInputs; i++) {
6465 PRUint32 msg;
6466 if (pInputs[i].dwFlags & TOUCHEVENTF_MOVE) {
6467 msg = NS_MOZTOUCH_MOVE;
6468 } else if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) {
6469 msg = NS_MOZTOUCH_DOWN;
6470 } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) {
6471 msg = NS_MOZTOUCH_UP;
6472 } else {
6473 continue;
6476 nsPointWin touchPoint;
6477 touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
6478 touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
6479 touchPoint.ScreenToClient(mWnd);
6481 nsMozTouchEvent touchEvent(PR_TRUE, msg, this, pInputs[i].dwID);
6482 touchEvent.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6483 touchEvent.refPoint = touchPoint;
6485 nsEventStatus status;
6486 DispatchEvent(&touchEvent, status);
6490 delete [] pInputs;
6491 mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam);
6492 return PR_TRUE;
6494 #endif
6496 // Gesture event processing. Handles WM_GESTURE events.
6497 #if !defined(WINCE)
6498 PRBool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
6500 // Treatment for pan events which translate into scroll events:
6501 if (mGesture.IsPanEvent(lParam)) {
6502 nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
6504 if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
6505 return PR_FALSE; // ignore
6507 nsEventStatus status;
6509 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6510 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6511 event.isMeta = PR_FALSE;
6512 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6513 event.button = 0;
6514 event.time = ::GetMessageTime();
6515 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6517 PRBool endFeedback = PR_TRUE;
6519 PRInt32 scrollOverflowX = 0;
6520 PRInt32 scrollOverflowY = 0;
6522 if (mGesture.PanDeltaToPixelScrollX(event)) {
6523 DispatchEvent(&event, status);
6524 scrollOverflowX = event.scrollOverflow;
6527 if (mGesture.PanDeltaToPixelScrollY(event)) {
6528 DispatchEvent(&event, status);
6529 scrollOverflowY = event.scrollOverflow;
6532 if (mDisplayPanFeedback) {
6533 mGesture.UpdatePanFeedbackX(mWnd, scrollOverflowX, endFeedback);
6534 mGesture.UpdatePanFeedbackY(mWnd, scrollOverflowY, endFeedback);
6535 mGesture.PanFeedbackFinalize(mWnd, endFeedback);
6538 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6540 return PR_TRUE;
6543 // Other gestures translate into simple gesture events:
6544 nsSimpleGestureEvent event(PR_TRUE, 0, this, 0, 0.0);
6545 if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) {
6546 return PR_FALSE; // fall through to DefWndProc
6549 // Polish up and send off the new event
6550 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6551 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6552 event.isMeta = PR_FALSE;
6553 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6554 event.button = 0;
6555 event.time = ::GetMessageTime();
6556 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6558 nsEventStatus status;
6559 DispatchEvent(&event, status);
6560 if (status == nsEventStatus_eIgnore) {
6561 return PR_FALSE; // Ignored, fall through
6564 // Only close this if we process and return true.
6565 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6567 return PR_TRUE; // Handled
6569 #endif // !defined(WINCE)
6571 #if !defined(WINCE)
6572 PRUint16 nsWindow::GetMouseInputSource()
6574 PRUint16 inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE;
6575 LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
6576 if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
6577 inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ?
6578 PRUint16(nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH) : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN;
6580 return inputSource;
6582 #endif
6584 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6585 * within the message case block. If returning true result should be returned
6586 * immediately (no more processing).
6588 PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue)
6590 // Handle both flavors of mouse wheel events.
6591 static int iDeltaPerLine, iDeltaPerChar;
6592 static ULONG ulScrollLines, ulScrollChars = 1;
6593 static int currentVDelta, currentHDelta;
6594 static HWND currentWindow = 0;
6596 PRBool isVertical = msg == WM_MOUSEWHEEL;
6598 // Get mouse wheel metrics (but only once).
6599 if (getWheelInfo) {
6600 getWheelInfo = PR_FALSE;
6602 SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
6604 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6605 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6607 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6608 // the mouse driver wants a page scroll. The docs state that
6609 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6610 // since some mouse drivers use an arbitrary large number instead,
6611 // we have to handle that as well.
6613 iDeltaPerLine = 0;
6614 if (ulScrollLines) {
6615 if (ulScrollLines <= WHEEL_DELTA) {
6616 iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
6617 } else {
6618 ulScrollLines = WHEEL_PAGESCROLL;
6622 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
6623 &ulScrollChars, 0)) {
6624 // Note that we may always fail to get the value before Win Vista.
6625 ulScrollChars = 1;
6628 iDeltaPerChar = 0;
6629 if (ulScrollChars) {
6630 if (ulScrollChars <= WHEEL_DELTA) {
6631 iDeltaPerChar = WHEEL_DELTA / ulScrollChars;
6632 } else {
6633 ulScrollChars = WHEEL_PAGESCROLL;
6638 if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) ||
6639 (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar))
6640 return PR_FALSE; // break
6642 // The mousewheel event will be dispatched to the toplevel
6643 // window. We need to give it to the child window
6644 PRBool quit;
6645 if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit))
6646 return quit; // return immediately if its not our window
6648 // We should cancel the surplus delta if the current window is not
6649 // same as previous.
6650 if (currentWindow != mWnd) {
6651 currentVDelta = 0;
6652 currentHDelta = 0;
6653 currentWindow = mWnd;
6656 nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
6657 scrollEvent.delta = 0;
6658 if (isVertical) {
6659 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
6660 if (ulScrollLines == WHEEL_PAGESCROLL) {
6661 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6662 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1;
6663 } else {
6664 currentVDelta -= (short) HIWORD (wParam);
6665 if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
6666 scrollEvent.delta = currentVDelta / iDeltaPerLine;
6667 currentVDelta %= iDeltaPerLine;
6670 } else {
6671 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
6672 if (ulScrollChars == WHEEL_PAGESCROLL) {
6673 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6674 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1;
6675 } else {
6676 currentHDelta += (short) HIWORD (wParam);
6677 if (PR_ABS(currentHDelta) >= iDeltaPerChar) {
6678 scrollEvent.delta = currentHDelta / iDeltaPerChar;
6679 currentHDelta %= iDeltaPerChar;
6684 if (!scrollEvent.delta) {
6685 // We store the wheel delta, and it will be used next wheel message, so,
6686 // we consume this message actually. We shouldn't call next wndproc.
6687 result = PR_TRUE;
6688 return PR_FALSE; // break
6691 #ifdef MOZ_IPC
6692 // The event may go to a plug-in which already dispatched this message.
6693 // Then, the event can cause deadlock. We should unlock the sender here.
6694 ::ReplyMessage(isVertical ? 0 : TRUE);
6695 #endif
6697 scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6698 scrollEvent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6699 scrollEvent.isMeta = PR_FALSE;
6700 scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT);
6701 InitEvent(scrollEvent);
6702 if (nsnull != mEventCallback) {
6703 result = DispatchWindowEvent(&scrollEvent);
6705 // Note that we should return zero if we process WM_MOUSEWHEEL.
6706 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6708 if (result)
6709 *aRetValue = isVertical ? 0 : TRUE;
6711 return PR_FALSE; // break;
6714 static PRBool
6715 StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,
6716 const PRUnichar* aChars2, const PRUint32 aNumChars2)
6718 if (aNumChars1 != aNumChars2)
6719 return PR_FALSE;
6721 nsCaseInsensitiveStringComparator comp;
6722 return comp(aChars1, aChars2, aNumChars1, aNumChars2) == 0;
6725 UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
6727 #ifndef WINCE
6728 switch (aNativeKeyCode) {
6729 case VK_OEM_1: return NS_VK_SEMICOLON; // 0xBA, For the US standard keyboard, the ';:' key
6730 case VK_OEM_PLUS: return NS_VK_ADD; // 0xBB, For any country/region, the '+' key
6731 case VK_OEM_MINUS: return NS_VK_SUBTRACT; // 0xBD, For any country/region, the '-' key
6733 #endif
6735 return aNativeKeyCode;
6738 /* static */
6739 PRBool nsWindow::IsRedirectedKeyDownMessage(const MSG &aMsg)
6741 return (aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN) &&
6742 (sRedirectedKeyDown.message == aMsg.message &&
6743 GetScanCode(sRedirectedKeyDown.lParam) == GetScanCode(aMsg.lParam));
6747 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6748 * WM_CHAR messages for processing. During testing we don't want to
6749 * mess with the real message queue. Instead we pass a
6750 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6751 * that as if it was in the message queue, and refrain from actually
6752 * looking at or touching the message queue.
6754 LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
6755 nsModifierKeyState &aModKeyState,
6756 PRBool *aEventDispatched,
6757 nsFakeCharMessage* aFakeCharMessage)
6759 UINT virtualKeyCode =
6760 aMsg.wParam != VK_PROCESSKEY ? aMsg.wParam : ::ImmGetVirtualKey(mWnd);
6762 #ifndef WINCE
6763 gKbdLayout.OnKeyDown(virtualKeyCode);
6764 #endif
6766 // Use only DOMKeyCode for XP processing.
6767 // Use virtualKeyCode for gKbdLayout and native processing.
6768 UINT DOMKeyCode = nsIMM32Handler::IsComposingOn(this) ?
6769 virtualKeyCode : MapFromNativeToDOM(virtualKeyCode);
6771 #ifdef DEBUG
6772 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6773 #endif
6775 static PRBool sRedirectedKeyDownEventPreventedDefault = PR_FALSE;
6776 PRBool noDefault;
6777 if (aFakeCharMessage || !IsRedirectedKeyDownMessage(aMsg)) {
6778 HIMC oldIMC = mOldIMC;
6779 noDefault =
6780 DispatchKeyEvent(NS_KEY_DOWN, 0, nsnull, DOMKeyCode, &aMsg, aModKeyState);
6781 if (aEventDispatched) {
6782 *aEventDispatched = PR_TRUE;
6785 // If IMC wasn't associated to the window but is associated it now (i.e.,
6786 // focus is moved from a non-editable editor to an editor by keydown
6787 // event handler), WM_CHAR and WM_SYSCHAR shouldn't cause first character
6788 // inputting if IME is opened. But then, we should redirect the native
6789 // keydown message to IME.
6790 // However, note that if focus has been already moved to another
6791 // application, we shouldn't redirect the message to it because the keydown
6792 // message is processed by us, so, nobody shouldn't process it.
6793 HWND focusedWnd = ::GetFocus();
6794 if (!noDefault && !aFakeCharMessage && oldIMC && !mOldIMC && focusedWnd &&
6795 !PluginHasFocus()) {
6796 RemoveNextCharMessage(focusedWnd);
6798 INPUT keyinput;
6799 keyinput.type = INPUT_KEYBOARD;
6800 keyinput.ki.wVk = aMsg.wParam;
6801 keyinput.ki.wScan = GetScanCode(aMsg.lParam);
6802 keyinput.ki.dwFlags = KEYEVENTF_SCANCODE;
6803 if (IsExtendedScanCode(aMsg.lParam)) {
6804 keyinput.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
6806 keyinput.ki.time = 0;
6807 keyinput.ki.dwExtraInfo = NULL;
6809 sRedirectedKeyDownEventPreventedDefault = noDefault;
6810 sRedirectedKeyDown = aMsg;
6812 ::SendInput(1, &keyinput, sizeof(keyinput));
6814 // Return here. We shouldn't dispatch keypress event for this WM_KEYDOWN.
6815 // If it's needed, it will be dispatched after next (redirected)
6816 // WM_KEYDOWN.
6817 return PR_TRUE;
6820 if (mOnDestroyCalled) {
6821 // If this was destroyed by the keydown event handler, we shouldn't
6822 // dispatch keypress event on this window.
6823 return PR_TRUE;
6825 } else {
6826 noDefault = sRedirectedKeyDownEventPreventedDefault;
6827 // If this is redirected keydown message, we have dispatched the keydown
6828 // event already.
6829 if (aEventDispatched) {
6830 *aEventDispatched = PR_TRUE;
6834 ForgetRedirectedKeyDownMessage();
6836 // If the key was processed by IME, we shouldn't dispatch keypress event.
6837 if (aMsg.wParam == VK_PROCESSKEY) {
6838 return noDefault;
6841 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6842 // for almost all keys
6843 switch (DOMKeyCode) {
6844 case NS_VK_SHIFT:
6845 case NS_VK_CONTROL:
6846 case NS_VK_ALT:
6847 case NS_VK_CAPS_LOCK:
6848 case NS_VK_NUM_LOCK:
6849 case NS_VK_SCROLL_LOCK: return noDefault;
6852 PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
6853 MSG msg;
6854 BOOL gotMsg = aFakeCharMessage ||
6855 ::PeekMessageW(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6856 // Enter and backspace are always handled here to avoid for example the
6857 // confusion between ctrl-enter and ctrl-J.
6858 if (DOMKeyCode == NS_VK_RETURN || DOMKeyCode == NS_VK_BACK ||
6859 ((aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)
6860 #ifdef WINCE
6862 #else
6863 && !gKbdLayout.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
6864 #endif
6866 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6867 // They can be more than one because of:
6868 // * Dead-keys not pairing with base character
6869 // * Some keyboard layouts may map up to 4 characters to the single key
6870 PRBool anyCharMessagesRemoved = PR_FALSE;
6872 if (aFakeCharMessage) {
6873 anyCharMessagesRemoved = PR_TRUE;
6874 } else {
6875 while (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR))
6877 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6878 ("%s charCode=%d scanCode=%d\n", msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6879 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6880 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST, WM_KEYLAST);
6881 anyCharMessagesRemoved = PR_TRUE;
6883 gotMsg = ::PeekMessageW (&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6887 if (!anyCharMessagesRemoved && DOMKeyCode == NS_VK_BACK &&
6888 nsIMM32Handler::IsDoingKakuteiUndo(mWnd)) {
6889 NS_ASSERTION(!aFakeCharMessage,
6890 "We shouldn't be touching the real msg queue");
6891 RemoveMessageAndDispatchPluginEvent(WM_CHAR, WM_CHAR);
6894 else if (gotMsg &&
6895 (aFakeCharMessage ||
6896 msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
6897 if (aFakeCharMessage)
6898 return OnCharRaw(aFakeCharMessage->mCharCode,
6899 aFakeCharMessage->mScanCode, aModKeyState, extraFlags);
6901 // If prevent default set for keydown, do same for keypress
6902 ::GetMessageW(&msg, mWnd, msg.message, msg.message);
6904 if (msg.message == WM_DEADCHAR) {
6905 if (!PluginHasFocus())
6906 return PR_FALSE;
6908 // We need to send the removed message to focused plug-in.
6909 DispatchPluginEvent(msg);
6910 return noDefault;
6913 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6914 ("%s charCode=%d scanCode=%d\n",
6915 msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6916 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6918 BOOL result = OnChar(msg, aModKeyState, nsnull, extraFlags);
6919 // If a syschar keypress wasn't processed, Windows may want to
6920 // handle it to activate a native menu.
6921 if (!result && msg.message == WM_SYSCHAR)
6922 ::DefWindowProcW(mWnd, msg.message, msg.wParam, msg.lParam);
6923 return result;
6925 #ifndef WINCE
6926 else if (!aModKeyState.mIsControlDown && !aModKeyState.mIsAltDown &&
6927 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode) ||
6928 KeyboardLayout::IsNumpadKey(virtualKeyCode)))
6930 // If this is simple KeyDown event but next message is not WM_CHAR,
6931 // this event may not input text, so we should ignore this event.
6932 // See bug 314130.
6933 return PluginHasFocus() && noDefault;
6936 if (gKbdLayout.IsDeadKey ())
6937 return PluginHasFocus() && noDefault;
6939 PRUint8 shiftStates[5];
6940 PRUnichar uniChars[5];
6941 PRUnichar shiftedChars[5] = {0, 0, 0, 0, 0};
6942 PRUnichar unshiftedChars[5] = {0, 0, 0, 0, 0};
6943 PRUnichar shiftedLatinChar = 0;
6944 PRUnichar unshiftedLatinChar = 0;
6945 PRUint32 numOfUniChars = 0;
6946 PRUint32 numOfShiftedChars = 0;
6947 PRUint32 numOfUnshiftedChars = 0;
6948 PRUint32 numOfShiftStates = 0;
6950 switch (virtualKeyCode) {
6951 // keys to be sent as characters
6952 case VK_ADD: uniChars [0] = '+'; numOfUniChars = 1; break;
6953 case VK_SUBTRACT: uniChars [0] = '-'; numOfUniChars = 1; break;
6954 case VK_DIVIDE: uniChars [0] = '/'; numOfUniChars = 1; break;
6955 case VK_MULTIPLY: uniChars [0] = '*'; numOfUniChars = 1; break;
6956 case VK_NUMPAD0:
6957 case VK_NUMPAD1:
6958 case VK_NUMPAD2:
6959 case VK_NUMPAD3:
6960 case VK_NUMPAD4:
6961 case VK_NUMPAD5:
6962 case VK_NUMPAD6:
6963 case VK_NUMPAD7:
6964 case VK_NUMPAD8:
6965 case VK_NUMPAD9:
6966 uniChars [0] = virtualKeyCode - VK_NUMPAD0 + '0';
6967 numOfUniChars = 1;
6968 break;
6969 default:
6970 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
6971 numOfUniChars = numOfShiftStates =
6972 gKbdLayout.GetUniChars(uniChars, shiftStates,
6973 NS_ARRAY_LENGTH(uniChars));
6976 if (aModKeyState.mIsControlDown ^ aModKeyState.mIsAltDown) {
6977 PRUint8 capsLockState = (::GetKeyState(VK_CAPITAL) & 1) ? eCapsLock : 0;
6978 numOfUnshiftedChars =
6979 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode, capsLockState,
6980 unshiftedChars, NS_ARRAY_LENGTH(unshiftedChars));
6981 numOfShiftedChars =
6982 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode,
6983 capsLockState | eShift,
6984 shiftedChars, NS_ARRAY_LENGTH(shiftedChars));
6986 // The current keyboard cannot input alphabets or numerics,
6987 // we should append them for Shortcut/Access keys.
6988 // E.g., for Cyrillic keyboard layout.
6989 if (NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z) {
6990 shiftedLatinChar = unshiftedLatinChar = DOMKeyCode;
6991 if (capsLockState)
6992 shiftedLatinChar += 0x20;
6993 else
6994 unshiftedLatinChar += 0x20;
6995 if (unshiftedLatinChar == unshiftedChars[0] &&
6996 shiftedLatinChar == shiftedChars[0]) {
6997 shiftedLatinChar = unshiftedLatinChar = 0;
6999 } else {
7000 PRUint16 ch = 0;
7001 if (NS_VK_0 <= DOMKeyCode && DOMKeyCode <= NS_VK_9) {
7002 ch = DOMKeyCode;
7003 } else {
7004 switch (virtualKeyCode) {
7005 case VK_OEM_PLUS: ch = '+'; break;
7006 case VK_OEM_MINUS: ch = '-'; break;
7009 if (ch && unshiftedChars[0] != ch && shiftedChars[0] != ch) {
7010 // Windows has assigned a virtual key code to the key even though
7011 // the character can't be produced with this key. That probably
7012 // means the character can't be produced with any key in the
7013 // current layout and so the assignment is based on a QWERTY
7014 // layout. Append this code so that users can access the shortcut.
7015 unshiftedLatinChar = ch;
7019 // If the charCode is not ASCII character, we should replace the
7020 // charCode with ASCII character only when Ctrl is pressed.
7021 // But don't replace the charCode when the charCode is not same as
7022 // unmodified characters. In such case, Ctrl is sometimes used for a
7023 // part of character inputting key combination like Shift.
7024 if (aModKeyState.mIsControlDown) {
7025 PRUint8 currentState = eCtrl;
7026 if (aModKeyState.mIsShiftDown)
7027 currentState |= eShift;
7029 PRUint32 ch =
7030 aModKeyState.mIsShiftDown ? shiftedLatinChar : unshiftedLatinChar;
7031 if (ch &&
7032 (numOfUniChars == 0 ||
7033 StringCaseInsensitiveEquals(uniChars, numOfUniChars,
7034 aModKeyState.mIsShiftDown ? shiftedChars : unshiftedChars,
7035 aModKeyState.mIsShiftDown ? numOfShiftedChars :
7036 numOfUnshiftedChars))) {
7037 numOfUniChars = numOfShiftStates = 1;
7038 uniChars[0] = ch;
7039 shiftStates[0] = currentState;
7045 if (numOfUniChars > 0 || numOfShiftedChars > 0 || numOfUnshiftedChars > 0) {
7046 PRUint32 num = PR_MAX(numOfUniChars,
7047 PR_MAX(numOfShiftedChars, numOfUnshiftedChars));
7048 PRUint32 skipUniChars = num - numOfUniChars;
7049 PRUint32 skipShiftedChars = num - numOfShiftedChars;
7050 PRUint32 skipUnshiftedChars = num - numOfUnshiftedChars;
7051 UINT keyCode = numOfUniChars == 0 ? DOMKeyCode : 0;
7052 for (PRUint32 cnt = 0; cnt < num; cnt++) {
7053 PRUint16 uniChar, shiftedChar, unshiftedChar;
7054 uniChar = shiftedChar = unshiftedChar = 0;
7055 if (skipUniChars <= cnt) {
7056 if (cnt - skipUniChars < numOfShiftStates) {
7057 // If key in combination with Alt and/or Ctrl produces a different
7058 // character than without them then do not report these flags
7059 // because it is separate keyboard layout shift state. If dead-key
7060 // and base character does not produce a valid composite character
7061 // then both produced dead-key character and following base
7062 // character may have different modifier flags, too.
7063 aModKeyState.mIsShiftDown =
7064 (shiftStates[cnt - skipUniChars] & eShift) != 0;
7065 aModKeyState.mIsControlDown =
7066 (shiftStates[cnt - skipUniChars] & eCtrl) != 0;
7067 aModKeyState.mIsAltDown =
7068 (shiftStates[cnt - skipUniChars] & eAlt) != 0;
7070 uniChar = uniChars[cnt - skipUniChars];
7072 if (skipShiftedChars <= cnt)
7073 shiftedChar = shiftedChars[cnt - skipShiftedChars];
7074 if (skipUnshiftedChars <= cnt)
7075 unshiftedChar = unshiftedChars[cnt - skipUnshiftedChars];
7076 nsAutoTArray<nsAlternativeCharCode, 5> altArray;
7078 if (shiftedChar || unshiftedChar) {
7079 nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
7080 altArray.AppendElement(chars);
7082 if (cnt == num - 1 && (unshiftedLatinChar || shiftedLatinChar)) {
7083 nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
7084 altArray.AppendElement(chars);
7087 DispatchKeyEvent(NS_KEY_PRESS, uniChar, &altArray,
7088 keyCode, nsnull, aModKeyState, extraFlags);
7090 } else {
7091 DispatchKeyEvent(NS_KEY_PRESS, 0, nsnull, DOMKeyCode, nsnull, aModKeyState,
7092 extraFlags);
7094 #else
7096 UINT unichar = ::MapVirtualKey(virtualKeyCode, MAPVK_VK_TO_CHAR);
7097 // Check for dead characters or no mapping
7098 if (unichar & 0x80) {
7099 return noDefault;
7101 DispatchKeyEvent(NS_KEY_PRESS, unichar, nsnull, DOMKeyCode, nsnull, aModKeyState,
7102 extraFlags);
7104 #endif
7106 return noDefault;
7109 // OnKeyUp
7110 LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
7111 nsModifierKeyState &aModKeyState,
7112 PRBool *aEventDispatched)
7114 UINT virtualKeyCode = aMsg.wParam;
7116 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
7117 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
7119 if (!nsIMM32Handler::IsComposingOn(this)) {
7120 virtualKeyCode = MapFromNativeToDOM(virtualKeyCode);
7123 if (aEventDispatched)
7124 *aEventDispatched = PR_TRUE;
7125 return DispatchKeyEvent(NS_KEY_UP, 0, nsnull, virtualKeyCode, &aMsg,
7126 aModKeyState);
7129 // OnChar
7130 LRESULT nsWindow::OnChar(const MSG &aMsg, nsModifierKeyState &aModKeyState,
7131 PRBool *aEventDispatched, PRUint32 aFlags)
7133 return OnCharRaw(aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF, aModKeyState,
7134 aFlags, &aMsg, aEventDispatched);
7137 // OnCharRaw
7138 LRESULT nsWindow::OnCharRaw(UINT charCode, UINT aScanCode,
7139 nsModifierKeyState &aModKeyState, PRUint32 aFlags,
7140 const MSG *aMsg, PRBool *aEventDispatched)
7142 // ignore [shift+]alt+space so the OS can handle it
7143 if (aModKeyState.mIsAltDown && !aModKeyState.mIsControlDown &&
7144 IS_VK_DOWN(NS_VK_SPACE)) {
7145 return FALSE;
7148 // Ignore Ctrl+Enter (bug 318235)
7149 if (aModKeyState.mIsControlDown && charCode == 0xA) {
7150 return FALSE;
7153 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
7154 PRBool saveIsAltDown = aModKeyState.mIsAltDown;
7155 PRBool saveIsControlDown = aModKeyState.mIsControlDown;
7156 if (aModKeyState.mIsAltDown && aModKeyState.mIsControlDown)
7157 aModKeyState.mIsAltDown = aModKeyState.mIsControlDown = PR_FALSE;
7159 wchar_t uniChar;
7161 if (nsIMM32Handler::IsComposingOn(this)) {
7162 ResetInputState();
7165 if (aModKeyState.mIsControlDown && charCode <= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
7166 // need to account for shift here. bug 16486
7167 if (aModKeyState.mIsShiftDown)
7168 uniChar = charCode - 1 + 'A';
7169 else
7170 uniChar = charCode - 1 + 'a';
7171 charCode = 0;
7173 else if (aModKeyState.mIsControlDown && charCode <= 0x1F) {
7174 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
7175 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
7176 // for some reason the keypress handler need to have the uniChar code set
7177 // with the addition of a upper case A not the lower case.
7178 uniChar = charCode - 1 + 'A';
7179 charCode = 0;
7180 } else { // 0x20 - SPACE, 0x3D - EQUALS
7181 if (charCode < 0x20 || (charCode == 0x3D && aModKeyState.mIsControlDown)) {
7182 uniChar = 0;
7183 } else {
7184 uniChar = charCode;
7185 charCode = 0;
7189 // Keep the characters unshifted for shortcuts and accesskeys and make sure
7190 // that numbers are always passed as such (among others: bugs 50255 and 351310)
7191 if (uniChar && (aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)) {
7192 UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK,
7193 gKbdLayout.GetLayout());
7194 UINT unshiftedCharCode =
7195 virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
7196 aModKeyState.mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode,
7197 MAPVK_VK_TO_CHAR,
7198 gKbdLayout.GetLayout()) : 0;
7199 // ignore diacritics (top bit set) and key mapping errors (char code 0)
7200 if ((INT)unshiftedCharCode > 0)
7201 uniChar = unshiftedCharCode;
7204 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
7205 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
7206 // pressed too.
7207 if (!aModKeyState.mIsShiftDown && (saveIsAltDown || saveIsControlDown)) {
7208 uniChar = towlower(uniChar);
7211 PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, nsnull,
7212 charCode, aMsg, aModKeyState, aFlags);
7213 if (aEventDispatched)
7214 *aEventDispatched = PR_TRUE;
7215 aModKeyState.mIsAltDown = saveIsAltDown;
7216 aModKeyState.mIsControlDown = saveIsControlDown;
7217 return result;
7220 void
7221 nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers)
7223 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierKeyMap); ++i) {
7224 const PRUint32* map = sModifierKeyMap[i];
7225 if (aModifiers & map[0]) {
7226 aArray->AppendElement(KeyPair(map[1], map[2]));
7231 nsresult
7232 nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
7234 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
7235 // here, if that helps in some situations. So far I haven't seen a
7236 // need.
7237 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
7238 const Configuration& configuration = aConfigurations[i];
7239 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
7240 NS_ASSERTION(w->GetParent() == this,
7241 "Configured widget is not a child");
7242 #ifdef WINCE
7243 // MSDN says we should do on WinCE this before moving or resizing the window
7244 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
7245 // We put the region back just below, anyway.
7246 ::SetWindowRgn(w->mWnd, NULL, TRUE);
7247 #endif
7248 nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_TRUE);
7249 NS_ENSURE_SUCCESS(rv, rv);
7250 nsIntRect bounds;
7251 w->GetBounds(bounds);
7252 if (bounds.Size() != configuration.mBounds.Size()) {
7253 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
7254 configuration.mBounds.width, configuration.mBounds.height,
7255 PR_TRUE);
7256 } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
7257 w->Move(configuration.mBounds.x, configuration.mBounds.y);
7260 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7261 gfxWindowsPlatform::RENDER_DIRECT2D ||
7262 GetLayerManager()->GetBackendType() != LayerManager::LAYERS_BASIC) {
7263 // XXX - Workaround for Bug 587508. This will invalidate the part of the
7264 // plugin window that might be touched by moving content somehow. The
7265 // underlying problem should be found and fixed!
7266 nsIntRegion r;
7267 r.Sub(bounds, configuration.mBounds);
7268 r.MoveBy(-bounds.x,
7269 -bounds.y);
7270 w->Invalidate(r.GetBounds(), PR_FALSE);
7273 rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_FALSE);
7274 NS_ENSURE_SUCCESS(rv, rv);
7276 return NS_OK;
7279 static HRGN
7280 CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
7282 PRInt32 size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
7283 nsAutoTArray<PRUint8,100> buf;
7284 if (!buf.SetLength(size))
7285 return NULL;
7286 RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
7287 RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
7288 data->rdh.dwSize = sizeof(data->rdh);
7289 data->rdh.iType = RDH_RECTANGLES;
7290 data->rdh.nCount = aRects.Length();
7291 nsIntRect bounds;
7292 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
7293 const nsIntRect& r = aRects[i];
7294 bounds.UnionRect(bounds, r);
7295 ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
7297 ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
7298 return ::ExtCreateRegion(NULL, buf.Length(), data);
7301 static const nsIntRegion
7302 RegionFromArray(const nsTArray<nsIntRect>& aRects)
7304 nsIntRegion region;
7305 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
7306 region.Or(region, aRects[i]);
7308 return region;
7311 static const nsTArray<nsIntRect>
7312 ArrayFromRegion(const nsIntRegion& aRegion)
7314 nsTArray<nsIntRect> rects;
7315 const nsIntRect* r;
7316 for (nsIntRegionRectIterator iter(aRegion); (r = iter.Next());) {
7317 rects.AppendElement(*r);
7319 return rects;
7322 nsresult
7323 nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
7324 PRBool aIntersectWithExisting)
7326 if (!aIntersectWithExisting) {
7327 if (!StoreWindowClipRegion(aRects))
7328 return NS_OK;
7329 } else {
7330 // In this case still early return if nothing changed.
7331 if (mClipRects && mClipRectCount == aRects.Length() &&
7332 memcmp(mClipRects,
7333 aRects.Elements(),
7334 sizeof(nsIntRect)*mClipRectCount) == 0) {
7335 return NS_OK;
7338 // get current rects
7339 nsTArray<nsIntRect> currentRects;
7340 GetWindowClipRegion(&currentRects);
7341 // create region from them
7342 nsIntRegion currentRegion = RegionFromArray(currentRects);
7343 // create region from new rects
7344 nsIntRegion newRegion = RegionFromArray(aRects);
7345 // intersect regions
7346 nsIntRegion intersection;
7347 intersection.And(currentRegion, newRegion);
7348 // create int rect array from intersection
7349 nsTArray<nsIntRect> rects = ArrayFromRegion(intersection);
7350 // store
7351 if (!StoreWindowClipRegion(rects))
7352 return NS_OK;
7355 HRGN dest = CreateHRGNFromArray(aRects);
7356 if (!dest)
7357 return NS_ERROR_OUT_OF_MEMORY;
7359 if (aIntersectWithExisting) {
7360 HRGN current = ::CreateRectRgn(0, 0, 0, 0);
7361 if (current) {
7362 if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
7363 ::CombineRgn(dest, dest, current, RGN_AND);
7365 ::DeleteObject(current);
7369 if (!::SetWindowRgn(mWnd, dest, TRUE)) {
7370 ::DeleteObject(dest);
7371 return NS_ERROR_FAILURE;
7373 return NS_OK;
7376 // WM_DESTROY event handler
7377 void nsWindow::OnDestroy()
7379 mOnDestroyCalled = PR_TRUE;
7381 // Make sure we don't get destroyed in the process of tearing down.
7382 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
7384 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
7385 if (!mInDtor)
7386 DispatchStandardEvent(NS_DESTROY);
7388 // Prevent the widget from sending additional events.
7389 mEventCallback = nsnull;
7391 // Free our subclass and clear |this| stored in the window props. We will no longer
7392 // receive events from Windows after this point.
7393 SubclassWindow(FALSE);
7395 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
7396 // cleared. (It's used in tracking windows for mouse events.)
7397 if (sCurrentWindow == this)
7398 sCurrentWindow = nsnull;
7400 // Disconnects us from our parent, will call our GetParent().
7401 nsBaseWidget::Destroy();
7403 // Release references to children, device context, toolkit, and app shell.
7404 nsBaseWidget::OnDestroy();
7406 // Clear our native parent handle.
7407 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
7408 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
7409 //SetParent(nsnull);
7410 mParent = nsnull;
7412 // We have to destroy the native drag target before we null out our window pointer.
7413 EnableDragDrop(PR_FALSE);
7415 // If we're going away and for some reason we're still the rollup widget, rollup and
7416 // turn off capture.
7417 if ( this == sRollupWidget ) {
7418 if ( sRollupListener )
7419 sRollupListener->Rollup(nsnull, nsnull);
7420 CaptureRollupEvents(nsnull, nsnull, PR_FALSE, PR_TRUE);
7423 // If IME is disabled, restore it.
7424 if (mOldIMC) {
7425 mOldIMC = ::ImmAssociateContext(mWnd, mOldIMC);
7426 NS_ASSERTION(!mOldIMC, "Another IMC was associated");
7429 // Turn off mouse trails if enabled.
7430 MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
7431 if (mtrailer) {
7432 if (mtrailer->GetMouseTrailerWindow() == mWnd)
7433 mtrailer->DestroyTimer();
7435 if (mtrailer->GetCaptureWindow() == mWnd)
7436 mtrailer->SetCaptureWindow(nsnull);
7439 // Free GDI window class objects
7440 if (mBrush) {
7441 VERIFY(::DeleteObject(mBrush));
7442 mBrush = NULL;
7445 // Free app icon resources.
7446 HICON icon;
7447 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM) 0);
7448 if (icon)
7449 ::DestroyIcon(icon);
7451 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM) 0);
7452 if (icon)
7453 ::DestroyIcon(icon);
7455 // Destroy any custom cursor resources.
7456 if (mCursor == -1)
7457 SetCursor(eCursor_standard);
7459 #ifdef MOZ_XUL
7460 // Reset transparency
7461 if (eTransparencyTransparent == mTransparencyMode)
7462 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
7463 #endif
7465 #if defined(WINCE_HAVE_SOFTKB)
7466 // Revert the changes made for the software keyboard settings
7467 nsWindowCE::ResetSoftKB(mWnd);
7468 #endif
7470 #if !defined(WINCE)
7471 // Finalize panning feedback to possibly restore window displacement
7472 mGesture.PanFeedbackFinalize(mWnd, PR_TRUE);
7473 #endif
7475 // Clear the main HWND.
7476 mWnd = NULL;
7479 // OnMove
7480 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
7482 mBounds.x = aX;
7483 mBounds.y = aY;
7485 nsGUIEvent event(PR_TRUE, NS_MOVE, this);
7486 InitEvent(event);
7487 event.refPoint.x = aX;
7488 event.refPoint.y = aY;
7490 return DispatchWindowEvent(&event);
7493 // Send a resize message to the listener
7494 PRBool nsWindow::OnResize(nsIntRect &aWindowRect)
7496 #ifdef CAIRO_HAS_D2D_SURFACE
7497 if (mD2DWindowSurface) {
7498 mD2DWindowSurface = NULL;
7499 Invalidate(PR_FALSE);
7501 #endif
7503 // call the event callback
7504 if (mEventCallback) {
7505 nsSizeEvent event(PR_TRUE, NS_SIZE, this);
7506 InitEvent(event);
7507 event.windowSize = &aWindowRect;
7508 RECT r;
7509 if (::GetWindowRect(mWnd, &r)) {
7510 event.mWinWidth = PRInt32(r.right - r.left);
7511 event.mWinHeight = PRInt32(r.bottom - r.top);
7512 } else {
7513 event.mWinWidth = 0;
7514 event.mWinHeight = 0;
7517 #if 0
7518 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7519 aWindowRect.x, aWindowRect.y, aWindowRect.width, aWindowRect.height,
7520 event.mWinWidth, event.mWinHeight);
7521 #endif
7523 return DispatchWindowEvent(&event);
7526 return PR_FALSE;
7529 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7530 PRBool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
7532 return PR_TRUE;
7534 #endif // !defined(WINCE)
7536 void nsWindow::OnSettingsChange(WPARAM wParam, LPARAM lParam)
7538 if (mWindowType == eWindowType_dialog ||
7539 mWindowType == eWindowType_toplevel )
7540 nsWindowGfx::OnSettingsChangeGfx(wParam);
7543 /* static */
7544 PRBool nsWindow::IsOurProcessWindow(HWND aHWND)
7546 if (!aHWND) {
7547 return PR_FALSE;
7549 DWORD processId = 0;
7550 ::GetWindowThreadProcessId(aHWND, &processId);
7551 return processId == ::GetCurrentProcessId();
7554 /* static */
7555 HWND nsWindow::FindOurProcessWindow(HWND aHWND)
7557 for (HWND wnd = ::GetParent(aHWND); wnd; wnd = ::GetParent(wnd)) {
7558 if (IsOurProcessWindow(wnd)) {
7559 return wnd;
7562 return nsnull;
7565 // Scrolling helper function for handling plugins.
7566 // Return value indicates whether the calling function should handle this
7567 // aHandled indicates whether this was handled at all
7568 // aQuitProcessing tells whether or not to continue processing the message
7569 PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
7570 LPARAM aLParam, PRBool& aHandled,
7571 LRESULT* aRetValue,
7572 PRBool& aQuitProcessing)
7574 // The scroll event will be dispatched to the toplevel
7575 // window. We need to give it to the child window
7576 aQuitProcessing = PR_FALSE; // default is to not stop processing
7577 POINT point;
7578 DWORD dwPoints = ::GetMessagePos();
7579 point.x = GET_X_LPARAM(dwPoints);
7580 point.y = GET_Y_LPARAM(dwPoints);
7582 static PRBool sIsProcessing = PR_FALSE;
7583 if (sIsProcessing) {
7584 return PR_TRUE; // the caller should handle this.
7587 static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
7588 if (aMsg == WM_MOUSEHWHEEL) {
7589 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7590 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7591 // message at first time, this time, ::GetMessagePos works fine.
7592 // Then, we will return 0 (0 means we process it) to the message. Then, the
7593 // driver will POST the same messages continuously during the wheel tilted.
7594 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7595 // cursor isn't 0,0. Therefore, we cannot trust the result of
7596 // ::GetMessagePos API if the sender is the driver.
7597 if (!sMayBeUsingLogitechMouse && aLParam == 0 && (DWORD)aLParam != dwPoints &&
7598 ::InSendMessage()) {
7599 sMayBeUsingLogitechMouse = PR_TRUE;
7600 } else if (sMayBeUsingLogitechMouse && aLParam != 0 && ::InSendMessage()) {
7601 // The user has changed the mouse from Logitech's to another one (e.g.,
7602 // the user has changed to the touchpad of the notebook.
7603 sMayBeUsingLogitechMouse = PR_FALSE;
7605 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7606 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7607 // instead.
7608 if (sMayBeUsingLogitechMouse && aLParam == 0 && dwPoints == 0) {
7609 ::GetCursorPos(&point);
7613 HWND destWnd = ::WindowFromPoint(point);
7614 // Since we receive scroll events for as long as
7615 // we are focused, it's entirely possible that there
7616 // is another app's window or no window under the
7617 // pointer.
7619 if (!destWnd) {
7620 // No window is under the pointer
7621 return PR_FALSE; // break, but continue processing
7624 nsWindow* destWindow;
7626 // We don't handle the message if the found window belongs to another
7627 // process's top window. If it belongs window, that is a plug-in's window.
7628 // Then, we need to send the message to the plug-in window.
7629 if (!IsOurProcessWindow(destWnd)) {
7630 HWND ourPluginWnd = FindOurProcessWindow(destWnd);
7631 if (!ourPluginWnd) {
7632 // Somebody elses window
7633 return PR_FALSE; // break, but continue processing
7635 destWindow = GetNSWindowPtr(ourPluginWnd);
7636 } else {
7637 destWindow = GetNSWindowPtr(destWnd);
7640 if (destWindow == this && mWindowType == eWindowType_plugin) {
7641 // If this is plug-in window, the message came from the plug-in window.
7642 // Then, the message should be processed on the parent window.
7643 destWindow = static_cast<nsWindow*>(GetParent());
7644 NS_ENSURE_TRUE(destWindow, PR_FALSE); // break, but continue processing
7645 destWnd = destWindow->mWnd;
7646 NS_ENSURE_TRUE(destWnd, PR_FALSE); // break, but continue processing
7649 if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
7650 // Some other app, or a plugin window.
7651 // Windows directs scrolling messages to the focused window.
7652 // However, Mozilla does not like plugins having focus, so a
7653 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7654 // Therefore, plugins etc _should_ get first grab at the
7655 // message, but this focus vaguary means the plugin misses
7656 // out. If the window is a child of ours, forward it on.
7657 // Determine if a child by walking the parent list until
7658 // we find a parent matching our wndproc.
7659 HWND parentWnd = ::GetParent(destWnd);
7660 while (parentWnd) {
7661 nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
7662 if (parentWindow) {
7663 // We have a child window - quite possibly a plugin window.
7664 // However, not all plugins are created equal - some will handle this
7665 // message themselves, some will forward directly back to us, while
7666 // others will call DefWndProc, which itself still forwards back to us.
7667 // So if we have sent it once, we need to handle it ourself.
7669 #ifdef MOZ_IPC
7670 // XXX The message shouldn't come from the plugin window at here.
7671 // But the message might come from it due to some bugs. If it happens,
7672 // SendMessage causes deadlock. For safety, we should unlock the
7673 // sender here.
7674 ::ReplyMessage(aMsg == WM_MOUSEHWHEEL ? TRUE : 0);
7675 #endif
7677 // First time we have seen this message.
7678 // Call the child - either it will consume it, or
7679 // it will wind it's way back to us,triggering the destWnd case above
7680 // either way,when the call returns,we are all done with the message,
7681 sIsProcessing = PR_TRUE;
7682 ::SendMessageW(destWnd, aMsg, aWParam, aLParam);
7683 sIsProcessing = PR_FALSE;
7684 aHandled = PR_TRUE;
7685 aQuitProcessing = PR_TRUE;
7686 return PR_FALSE; // break, and stop processing
7688 parentWnd = ::GetParent(parentWnd);
7689 } // while parentWnd
7691 if (destWnd == nsnull)
7692 return PR_FALSE;
7693 if (destWnd != mWnd) {
7694 if (destWindow) {
7695 sIsProcessing = PR_TRUE;
7696 aHandled = destWindow->ProcessMessage(aMsg, aWParam, aLParam, aRetValue);
7697 sIsProcessing = PR_FALSE;
7698 aQuitProcessing = PR_TRUE;
7699 return PR_FALSE; // break, and stop processing
7701 #ifdef DEBUG
7702 else
7703 printf("WARNING: couldn't get child window for SCROLL event\n");
7704 #endif
7706 return PR_TRUE; // caller should handle this
7709 PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
7711 static PRInt8 sMouseWheelEmulation = -1;
7712 if (sMouseWheelEmulation < 0) {
7713 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7714 NS_ENSURE_TRUE(prefs, PR_FALSE);
7715 nsCOMPtr<nsIPrefBranch> prefBranch;
7716 prefs->GetBranch(0, getter_AddRefs(prefBranch));
7717 NS_ENSURE_TRUE(prefBranch, PR_FALSE);
7718 PRBool emulate;
7719 nsresult rv =
7720 prefBranch->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate);
7721 NS_ENSURE_SUCCESS(rv, PR_FALSE);
7722 sMouseWheelEmulation = PRInt8(emulate);
7725 if (aLParam || sMouseWheelEmulation) {
7726 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7727 // Treat as a mousewheel message and scroll appropriately
7728 PRBool quit, result;
7729 LRESULT retVal;
7731 if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result, &retVal, quit))
7732 return quit; // Return if it's not our message or has been dispatched
7734 nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
7735 scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
7736 ? nsMouseScrollEvent::kIsVertical
7737 : nsMouseScrollEvent::kIsHorizontal;
7738 switch (LOWORD(aWParam))
7740 case SB_PAGEDOWN:
7741 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7742 case SB_LINEDOWN:
7743 scrollevent.delta = 1;
7744 break;
7745 case SB_PAGEUP:
7746 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7747 case SB_LINEUP:
7748 scrollevent.delta = -1;
7749 break;
7750 default:
7751 return PR_FALSE;
7753 #ifdef MOZ_IPC
7754 // The event may go to a plug-in which already dispatched this message.
7755 // Then, the event can cause deadlock. We should unlock the sender here.
7756 ::ReplyMessage(0);
7757 #endif
7758 scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
7759 scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
7760 scrollevent.isMeta = PR_FALSE;
7761 scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
7762 InitEvent(scrollevent);
7763 if (nsnull != mEventCallback)
7765 DispatchWindowEvent(&scrollevent);
7767 return PR_TRUE;
7770 // Scroll message generated by external application
7771 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_SCROLL, this);
7773 command.mScroll.mIsHorizontal = (aMsg == WM_HSCROLL);
7775 switch (LOWORD(aWParam))
7777 case SB_LINEUP: // SB_LINELEFT
7778 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7779 command.mScroll.mAmount = -1;
7780 break;
7781 case SB_LINEDOWN: // SB_LINERIGHT
7782 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7783 command.mScroll.mAmount = 1;
7784 break;
7785 case SB_PAGEUP: // SB_PAGELEFT
7786 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7787 command.mScroll.mAmount = -1;
7788 break;
7789 case SB_PAGEDOWN: // SB_PAGERIGHT
7790 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7791 command.mScroll.mAmount = 1;
7792 break;
7793 case SB_TOP: // SB_LEFT
7794 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7795 command.mScroll.mAmount = -1;
7796 break;
7797 case SB_BOTTOM: // SB_RIGHT
7798 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7799 command.mScroll.mAmount = 1;
7800 break;
7801 default:
7802 return PR_FALSE;
7804 DispatchWindowEvent(&command);
7805 return PR_TRUE;
7808 // Can be overriden. Controls auto-erase of background.
7809 PRBool nsWindow::AutoErase(HDC dc)
7811 return PR_FALSE;
7814 void
7815 nsWindow::AllowD3D9Callback(nsWindow *aWindow)
7817 if (aWindow->mLayerManager) {
7818 aWindow->mLayerManager->Destroy();
7819 aWindow->mLayerManager = NULL;
7823 void
7824 nsWindow::AllowD3D9WithReinitializeCallback(nsWindow *aWindow)
7826 if (aWindow->mLayerManager) {
7827 aWindow->mLayerManager->Destroy();
7828 aWindow->mLayerManager = NULL;
7829 (void) aWindow->GetLayerManager();
7833 void
7834 nsWindow::StartAllowingD3D9(bool aReinitialize)
7836 sAllowD3D9 = true;
7838 LayerManagerPrefs prefs;
7839 GetLayerManagerPrefs(&prefs);
7840 if (prefs.mDisableAcceleration) {
7841 // The guarantee here is, if there's *any* chance that after we
7842 // throw out our layer managers we'd create at least one new,
7843 // accelerated one, we *will* throw out all the current layer
7844 // managers. We early-return here because currently, if
7845 // |disableAcceleration|, we will always use basic managers and
7846 // it's a waste to recreate them.
7848 // NB: the above implies that it's eminently possible for us to
7849 // skip this early return but still recreate basic managers.
7850 // That's OK. It's *not* OK to take this early return when we
7851 // *might* have created an accelerated manager.
7852 return;
7855 if (aReinitialize) {
7856 EnumAllWindows(AllowD3D9WithReinitializeCallback);
7857 } else {
7858 EnumAllWindows(AllowD3D9Callback);
7862 /**************************************************************
7863 **************************************************************
7865 ** BLOCK: IME management and accessibility
7867 ** Handles managing IME input and accessibility.
7869 **************************************************************
7870 **************************************************************/
7872 NS_IMETHODIMP nsWindow::ResetInputState()
7874 #ifdef DEBUG_KBSTATE
7875 printf("ResetInputState\n");
7876 #endif
7878 #ifdef NS_ENABLE_TSF
7879 nsTextStore::CommitComposition(PR_FALSE);
7880 #endif //NS_ENABLE_TSF
7882 nsIMM32Handler::CommitComposition(this);
7883 return NS_OK;
7886 NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState)
7888 #ifdef DEBUG_KBSTATE
7889 printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
7890 #endif
7892 #ifdef NS_ENABLE_TSF
7893 nsTextStore::SetIMEOpenState(aState);
7894 #endif //NS_ENABLE_TSF
7896 nsIMEContext IMEContext(mWnd);
7897 if (IMEContext.IsValid()) {
7898 ::ImmSetOpenStatus(IMEContext.get(), aState ? TRUE : FALSE);
7900 return NS_OK;
7903 NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState)
7905 nsIMEContext IMEContext(mWnd);
7906 if (IMEContext.IsValid()) {
7907 BOOL isOpen = ::ImmGetOpenStatus(IMEContext.get());
7908 *aState = isOpen ? PR_TRUE : PR_FALSE;
7909 } else
7910 *aState = PR_FALSE;
7912 #ifdef NS_ENABLE_TSF
7913 *aState |= nsTextStore::GetIMEOpenState();
7914 #endif //NS_ENABLE_TSF
7916 return NS_OK;
7919 NS_IMETHODIMP nsWindow::SetInputMode(const IMEContext& aContext)
7921 PRUint32 status = aContext.mStatus;
7922 #ifdef NS_ENABLE_TSF
7923 nsTextStore::SetInputMode(aContext);
7924 #endif //NS_ENABLE_TSF
7925 #ifdef DEBUG_KBSTATE
7926 printf("SetInputMode: %s\n", (status == nsIWidget::IME_STATUS_ENABLED ||
7927 status == nsIWidget::IME_STATUS_PLUGIN) ?
7928 "Enabled" : "Disabled");
7929 #endif
7930 if (nsIMM32Handler::IsComposing()) {
7931 ResetInputState();
7933 mIMEContext = aContext;
7934 PRBool enable = (status == nsIWidget::IME_STATUS_ENABLED ||
7935 status == nsIWidget::IME_STATUS_PLUGIN);
7937 #if defined(WINCE_HAVE_SOFTKB)
7938 sSoftKeyboardState = (status != nsIWidget::IME_STATUS_DISABLED);
7939 nsWindowCE::ToggleSoftKB(mWnd, sSoftKeyboardState);
7940 #endif
7942 if (!enable != !mOldIMC)
7943 return NS_OK;
7944 mOldIMC = ::ImmAssociateContext(mWnd, enable ? mOldIMC : NULL);
7945 NS_ASSERTION(!enable || !mOldIMC, "Another IMC was associated");
7947 return NS_OK;
7950 NS_IMETHODIMP nsWindow::GetInputMode(IMEContext& aContext)
7952 #ifdef DEBUG_KBSTATE
7953 printf("GetInputMode: %s\n", mIMEContext.mStatus ? "Enabled" : "Disabled");
7954 #endif
7955 aContext = mIMEContext;
7956 return NS_OK;
7959 NS_IMETHODIMP nsWindow::CancelIMEComposition()
7961 #ifdef DEBUG_KBSTATE
7962 printf("CancelIMEComposition\n");
7963 #endif
7965 #ifdef NS_ENABLE_TSF
7966 nsTextStore::CommitComposition(PR_TRUE);
7967 #endif //NS_ENABLE_TSF
7969 nsIMM32Handler::CancelComposition(this);
7970 return NS_OK;
7973 NS_IMETHODIMP
7974 nsWindow::GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState)
7976 #ifdef DEBUG_KBSTATE
7977 printf("GetToggledKeyState\n");
7978 #endif
7979 NS_ENSURE_ARG_POINTER(aLEDState);
7980 *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
7981 return NS_OK;
7984 #ifdef NS_ENABLE_TSF
7985 NS_IMETHODIMP
7986 nsWindow::OnIMEFocusChange(PRBool aFocus)
7988 nsresult rv = nsTextStore::OnFocusChange(aFocus, this, mIMEContext.mStatus);
7989 if (rv == NS_ERROR_NOT_AVAILABLE)
7990 rv = NS_ERROR_NOT_IMPLEMENTED; // TSF is not enabled, maybe.
7991 return rv;
7994 NS_IMETHODIMP
7995 nsWindow::OnIMETextChange(PRUint32 aStart,
7996 PRUint32 aOldEnd,
7997 PRUint32 aNewEnd)
7999 return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
8002 NS_IMETHODIMP
8003 nsWindow::OnIMESelectionChange(void)
8005 return nsTextStore::OnSelectionChange();
8007 #endif //NS_ENABLE_TSF
8009 #ifdef ACCESSIBILITY
8011 #ifdef DEBUG_WMGETOBJECT
8012 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
8013 nsAccessible* acc = aWnd ? \
8014 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
8015 printf(" acc: %p", acc); \
8016 if (acc) { \
8017 nsAutoString name; \
8018 acc->GetName(name); \
8019 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
8020 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
8021 void *hwnd = nsnull; \
8022 doc->GetWindowHandle(&hwnd); \
8023 printf(", acc hwnd: %d", hwnd); \
8026 #define NS_LOG_WMGETOBJECT_THISWND \
8028 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
8029 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
8030 mWnd, ::GetParent(mWnd), this); \
8031 NS_LOG_WMGETOBJECT_WNDACC(this) \
8032 printf("\n }\n"); \
8035 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
8037 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
8038 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
8039 aHwnd, ::GetParent(aHwnd), wnd); \
8040 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
8041 printf("\n }\n"); \
8043 #else
8044 #define NS_LOG_WMGETOBJECT_THISWND
8045 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
8046 #endif // DEBUG_WMGETOBJECT
8048 nsAccessible*
8049 nsWindow::GetRootAccessible()
8051 // We want the ability to forcibly disable a11y on windows, because
8052 // some non-a11y-related components attempt to bring it up. See bug
8053 // 538530 for details; we have a pref here that allows it to be disabled
8054 // for performance and testing resons.
8056 // This pref is checked only once, and the browser needs a restart to
8057 // pick up any changes.
8058 static int accForceDisable = -1;
8060 if (accForceDisable == -1) {
8061 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
8062 PRBool b = PR_FALSE;
8063 nsresult rv = prefs->GetBoolPref("accessibility.win32.force_disabled", &b);
8064 if (NS_SUCCEEDED(rv) && b) {
8065 accForceDisable = 1;
8066 } else {
8067 accForceDisable = 0;
8071 // If the pref was true, return null here, disabling a11y.
8072 if (accForceDisable)
8073 return nsnull;
8075 nsWindow::sIsAccessibilityOn = TRUE;
8077 if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) {
8078 return nsnull;
8081 NS_LOG_WMGETOBJECT_THISWND
8082 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
8084 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
8087 STDMETHODIMP_(LRESULT)
8088 nsWindow::LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc)
8090 // open the dll dynamically
8091 if (!sAccLib)
8092 sAccLib =::LoadLibraryW(L"OLEACC.DLL");
8094 if (sAccLib) {
8095 if (!sLresultFromObject)
8096 sLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(sAccLib,"LresultFromObject");
8098 if (sLresultFromObject)
8099 return sLresultFromObject(riid,wParam,pAcc);
8102 return 0;
8104 #endif
8106 /**************************************************************
8107 **************************************************************
8109 ** BLOCK: Transparency
8111 ** Window transparency helpers.
8113 **************************************************************
8114 **************************************************************/
8116 #ifdef MOZ_XUL
8118 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force)
8120 if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
8121 return;
8123 #ifdef CAIRO_HAS_D2D_SURFACE
8124 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
8125 gfxWindowsPlatform::RENDER_DIRECT2D) {
8126 nsRefPtr<gfxD2DSurface> newSurface =
8127 new gfxD2DSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
8128 mTransparentSurface = newSurface;
8129 mMemoryDC = nsnull;
8130 } else
8131 #endif
8133 nsRefPtr<gfxWindowsSurface> newSurface =
8134 new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
8135 mTransparentSurface = newSurface;
8136 mMemoryDC = newSurface->GetDC();
8140 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
8142 #ifndef WINCE
8144 if (aMode == mTransparencyMode)
8145 return;
8147 // stop on dialogs and popups!
8148 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
8149 nsWindow* parent = GetNSWindowPtr(hWnd);
8151 if (!parent)
8153 NS_WARNING("Trying to use transparent chrome in an embedded context");
8154 return;
8157 if (parent != this) {
8158 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
8161 if (aMode == eTransparencyTransparent) {
8162 // If we're switching to the use of a transparent window, hide the chrome
8163 // on our parent.
8164 HideWindowChrome(PR_TRUE);
8165 } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) {
8166 // if we're switching out of transparent, re-enable our parent's chrome.
8167 HideWindowChrome(PR_FALSE);
8170 LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE),
8171 exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
8173 if (parent->mIsVisible)
8174 style |= WS_VISIBLE;
8175 if (parent->mSizeMode == nsSizeMode_Maximized)
8176 style |= WS_MAXIMIZE;
8177 else if (parent->mSizeMode == nsSizeMode_Minimized)
8178 style |= WS_MINIMIZE;
8180 if (aMode == eTransparencyTransparent)
8181 exStyle |= WS_EX_LAYERED;
8182 else
8183 exStyle &= ~WS_EX_LAYERED;
8185 VERIFY_WINDOW_STYLE(style);
8186 ::SetWindowLongPtrW(hWnd, GWL_STYLE, style);
8187 ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle);
8189 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
8190 if (HasGlass())
8191 memset(&mGlassMargins, 0, sizeof mGlassMargins);
8192 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
8193 mTransparencyMode = aMode;
8195 SetupTranslucentWindowMemoryBitmap(aMode);
8196 UpdateGlass();
8197 #endif // #ifndef WINCE
8200 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
8202 if (eTransparencyTransparent == aMode) {
8203 ResizeTranslucentWindow(mBounds.width, mBounds.height, PR_TRUE);
8204 } else {
8205 mTransparentSurface = nsnull;
8206 mMemoryDC = NULL;
8210 nsresult nsWindow::UpdateTranslucentWindow()
8212 #ifndef WINCE
8213 if (mBounds.IsEmpty())
8214 return NS_OK;
8216 ::GdiFlush();
8218 BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
8219 SIZE winSize = { mBounds.width, mBounds.height };
8220 POINT srcPos = { 0, 0 };
8221 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
8222 RECT winRect;
8223 ::GetWindowRect(hWnd, &winRect);
8225 #ifdef CAIRO_HAS_D2D_SURFACE
8226 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
8227 gfxWindowsPlatform::RENDER_DIRECT2D) {
8228 mMemoryDC = static_cast<gfxD2DSurface*>(mTransparentSurface.get())->
8229 GetDC(PR_TRUE);
8231 #endif
8232 // perform the alpha blend
8233 PRBool updateSuccesful =
8234 ::UpdateLayeredWindow(hWnd, NULL, (POINT*)&winRect, &winSize, mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA);
8236 #ifdef CAIRO_HAS_D2D_SURFACE
8237 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
8238 gfxWindowsPlatform::RENDER_DIRECT2D) {
8239 nsIntRect r(0, 0, 0, 0);
8240 static_cast<gfxD2DSurface*>(mTransparentSurface.get())->ReleaseDC(&r);
8242 #endif
8244 if (!updateSuccesful) {
8245 return NS_ERROR_FAILURE;
8247 #endif
8249 return NS_OK;
8252 #endif //MOZ_XUL
8254 /**************************************************************
8255 **************************************************************
8257 ** BLOCK: Popup rollup hooks
8259 ** Deals with CaptureRollup on popup windows.
8261 **************************************************************
8262 **************************************************************/
8264 #ifndef WINCE
8265 // Schedules a timer for a window, so we can rollup after processing the hook event
8266 void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId)
8268 // In some cases multiple hooks may be scheduled
8269 // so ignore any other requests once one timer is scheduled
8270 if (sHookTimerId == 0) {
8271 // Remember the window handle and the message ID to be used later
8272 sRollupMsgId = aMsgId;
8273 sRollupMsgWnd = aWnd;
8274 // Schedule native timer for doing the rollup after
8275 // this event is done being processed
8276 sHookTimerId = ::SetTimer(NULL, 0, 0, (TIMERPROC)HookTimerForPopups);
8277 NS_ASSERTION(sHookTimerId, "Timer couldn't be created.");
8281 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8282 int gLastMsgCode = 0;
8283 extern MSGFEventMsgInfo gMSGFEvents[];
8284 #endif
8286 // Process Menu messages, rollup when popup is clicked.
8287 LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam)
8289 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8290 if (sProcessHook) {
8291 MSG* pMsg = (MSG*)lParam;
8293 int inx = 0;
8294 while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != NULL) {
8295 inx++;
8297 if (code != gLastMsgCode) {
8298 if (gMSGFEvents[inx].mId == code) {
8299 #ifdef DEBUG
8300 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code, gMSGFEvents[inx].mStr, pMsg->hwnd);
8301 #endif
8302 } else {
8303 #ifdef DEBUG
8304 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code, gMSGFEvents[inx].mId, pMsg->hwnd);
8305 #endif
8307 gLastMsgCode = code;
8309 PrintEvent(pMsg->message, FALSE, FALSE);
8311 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8313 if (sProcessHook && code == MSGF_MENU) {
8314 MSG* pMsg = (MSG*)lParam;
8315 ScheduleHookTimer( pMsg->hwnd, pMsg->message);
8318 return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
8321 // Process all mouse messages. Roll up when a click is in a native window
8322 // that doesn't have an nsIWidget.
8323 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
8325 if (sProcessHook) {
8326 switch (wParam) {
8327 case WM_LBUTTONDOWN:
8328 case WM_RBUTTONDOWN:
8329 case WM_MBUTTONDOWN:
8330 case WM_MOUSEWHEEL:
8331 case WM_MOUSEHWHEEL:
8333 MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
8334 nsIWidget* mozWin = (nsIWidget*)GetNSWindowPtr(ms->hwnd);
8335 if (mozWin) {
8336 // If this window is windowed plugin window, the mouse events are not
8337 // sent to us.
8338 if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin)
8339 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
8340 } else {
8341 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
8343 break;
8347 return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam);
8350 // Process all messages. Roll up when the window is moving, or
8351 // is resizing or when maximized or mininized.
8352 LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam)
8354 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8355 if (sProcessHook) {
8356 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
8357 PrintEvent(cwpt->message, FALSE, FALSE);
8359 #endif
8361 if (sProcessHook) {
8362 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
8363 if (cwpt->message == WM_MOVING ||
8364 cwpt->message == WM_SIZING ||
8365 cwpt->message == WM_GETMINMAXINFO) {
8366 ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message);
8370 return ::CallNextHookEx(sCallProcHook, code, wParam, lParam);
8373 // Register the special "hooks" for dropdown processing.
8374 void nsWindow::RegisterSpecialDropdownHooks()
8376 NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!");
8377 NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!");
8379 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
8381 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
8383 // Install msg hook for moving the window and resizing
8384 if (!sMsgFilterHook) {
8385 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
8386 sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, NULL, GetCurrentThreadId());
8387 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8388 if (!sMsgFilterHook) {
8389 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
8391 #endif
8394 // Install msg hook for menus
8395 if (!sCallProcHook) {
8396 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
8397 sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, NULL, GetCurrentThreadId());
8398 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8399 if (!sCallProcHook) {
8400 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
8402 #endif
8405 // Install msg hook for the mouse
8406 if (!sCallMouseHook) {
8407 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
8408 sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, NULL, GetCurrentThreadId());
8409 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8410 if (!sCallMouseHook) {
8411 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
8413 #endif
8417 // Unhook special message hooks for dropdowns.
8418 void nsWindow::UnregisterSpecialDropdownHooks()
8420 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
8422 if (sCallProcHook) {
8423 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
8424 if (!::UnhookWindowsHookEx(sCallProcHook)) {
8425 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
8427 sCallProcHook = NULL;
8430 if (sMsgFilterHook) {
8431 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
8432 if (!::UnhookWindowsHookEx(sMsgFilterHook)) {
8433 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
8435 sMsgFilterHook = NULL;
8438 if (sCallMouseHook) {
8439 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
8440 if (!::UnhookWindowsHookEx(sCallMouseHook)) {
8441 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
8443 sCallMouseHook = NULL;
8447 // This timer is designed to only fire one time at most each time a "hook" function
8448 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
8449 // hook, but that hook event or a subsequent event may roll up the dropdown before
8450 // this timer function is executed.
8452 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
8453 // before this function fires.
8454 VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
8456 if (sHookTimerId != 0) {
8457 // if the window is NULL then we need to use the ID to kill the timer
8458 BOOL status = ::KillTimer(NULL, sHookTimerId);
8459 NS_ASSERTION(status, "Hook Timer was not killed.");
8460 sHookTimerId = 0;
8463 if (sRollupMsgId != 0) {
8464 // Note: DealWithPopups does the check to make sure that
8465 // sRollupListener and sRollupWidget are not NULL
8466 LRESULT popupHandlingResult;
8467 nsAutoRollup autoRollup;
8468 DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
8469 sRollupMsgId = 0;
8470 sRollupMsgWnd = NULL;
8473 #endif // WinCE
8475 BOOL CALLBACK nsWindow::ClearResourcesCallback(HWND aWnd, LPARAM aMsg)
8477 nsWindow *window = nsWindow::GetNSWindowPtr(aWnd);
8478 if (window) {
8479 window->ClearCachedResources();
8481 return TRUE;
8484 void
8485 nsWindow::ClearCachedResources()
8487 #ifdef CAIRO_HAS_D2D_SURFACE
8488 mD2DWindowSurface = nsnull;
8489 #endif
8490 if (mLayerManager &&
8491 mLayerManager->GetBackendType() == LayerManager::LAYERS_BASIC) {
8492 static_cast<BasicLayerManager*>(mLayerManager.get())->
8493 ClearCachedResources();
8495 ::EnumChildWindows(mWnd, nsWindow::ClearResourcesCallback, NULL);
8498 static PRBool IsDifferentThreadWindow(HWND aWnd)
8500 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, NULL);
8503 PRBool
8504 nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
8506 RECT r;
8508 #ifndef WINCE
8509 if (Msg == WM_ACTIVATEAPP)
8510 // don't care about activation/deactivation
8511 return PR_FALSE;
8512 #else
8513 if (Msg == WM_ACTIVATE)
8514 // but on Windows CE we do care about
8515 // activation/deactivation because there doesn't exist
8516 // cancelable Mouse Activation events
8517 return PR_TRUE;
8518 #endif
8520 ::GetWindowRect(aWindow->mWnd, &r);
8521 DWORD pos = ::GetMessagePos();
8522 POINT mp;
8523 mp.x = GET_X_LPARAM(pos);
8524 mp.y = GET_Y_LPARAM(pos);
8526 // was the event inside this window?
8527 return (PRBool) PtInRect(&r, mp);
8530 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8531 BOOL
8532 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
8534 if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
8536 if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
8537 inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
8538 (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam))
8539 #ifndef WINCE
8541 inMsg == WM_NCRBUTTONDOWN ||
8542 inMsg == WM_MOVING ||
8543 inMsg == WM_SIZING ||
8544 inMsg == WM_NCLBUTTONDOWN ||
8545 inMsg == WM_NCMBUTTONDOWN ||
8546 inMsg == WM_MOUSEACTIVATE ||
8547 inMsg == WM_ACTIVATEAPP ||
8548 inMsg == WM_MENUSELECT
8549 #endif
8552 // Rollup if the event is outside the popup.
8553 PRBool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)sRollupWidget);
8555 if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL))
8557 sRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
8558 *outResult = PR_TRUE;
8561 // If we're dealing with menus, we probably have submenus and we don't
8562 // want to rollup if the click is in a parent menu of the current submenu.
8563 PRUint32 popupsToRollup = PR_UINT32_MAX;
8564 if (rollup) {
8565 if ( sMenuRollup ) {
8566 nsAutoTArray<nsIWidget*, 5> widgetChain;
8567 PRUint32 sameTypeCount = sMenuRollup->GetSubmenuWidgetChain(&widgetChain);
8568 for ( PRUint32 i = 0; i < widgetChain.Length(); ++i ) {
8569 nsIWidget* widget = widgetChain[i];
8570 if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
8571 // don't roll up if the mouse event occurred within a menu of the
8572 // same type. If the mouse event occurred in a menu higher than
8573 // that, roll up, but pass the number of popups to Rollup so
8574 // that only those of the same type close up.
8575 if (i < sameTypeCount) {
8576 rollup = PR_FALSE;
8578 else {
8579 popupsToRollup = sameTypeCount;
8581 break;
8583 } // foreach parent menu widget
8584 } // if rollup listener knows about menus
8587 #ifndef WINCE
8588 if (inMsg == WM_MOUSEACTIVATE && popupsToRollup == PR_UINT32_MAX) {
8589 // Prevent the click inside the popup from causing a change in window
8590 // activation. Since the popup is shown non-activated, we need to eat
8591 // any requests to activate the window while it is displayed. Windows
8592 // will automatically activate the popup on the mousedown otherwise.
8593 if (!rollup) {
8594 *outResult = MA_NOACTIVATE;
8595 return TRUE;
8597 else
8599 UINT uMsg = HIWORD(inLParam);
8600 if (uMsg == WM_MOUSEMOVE)
8602 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8603 // must be enabled in Windows.
8604 sRollupListener->ShouldRollupOnMouseActivate(&rollup);
8605 if (!rollup)
8607 *outResult = MA_NOACTIVATE;
8608 return true;
8613 // if we've still determined that we should still rollup everything, do it.
8614 else
8615 #endif
8616 if ( rollup ) {
8617 // sRollupConsumeEvent may be modified by
8618 // nsIRollupListener::Rollup.
8619 PRBool consumeRollupEvent = sRollupConsumeEvent;
8620 // only need to deal with the last rollup for left mouse down events.
8621 sRollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN ? &mLastRollup : nsnull);
8623 // Tell hook to stop processing messages
8624 sProcessHook = PR_FALSE;
8625 sRollupMsgId = 0;
8626 sRollupMsgWnd = NULL;
8628 // return TRUE tells Windows that the event is consumed,
8629 // false allows the event to be dispatched
8631 // So if we are NOT supposed to be consuming events, let it go through
8632 if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
8633 *outResult = MA_ACTIVATE;
8635 // However, don't activate panels
8636 #ifndef WINCE
8637 if (inMsg == WM_MOUSEACTIVATE) {
8638 nsWindow* activateWindow = GetNSWindowPtr(inWnd);
8639 if (activateWindow) {
8640 nsWindowType wintype;
8641 activateWindow->GetWindowType(wintype);
8642 if (wintype == eWindowType_popup && activateWindow->PopupType() == ePopupTypePanel) {
8643 *outResult = MA_NOACTIVATE;
8647 #endif
8649 return TRUE;
8651 #ifndef WINCE
8652 // if we are only rolling up some popups, don't activate and don't let
8653 // the event go through. This prevents clicks menus higher in the
8654 // chain from opening when a context menu is open
8655 if (popupsToRollup != PR_UINT32_MAX && inMsg == WM_MOUSEACTIVATE) {
8656 *outResult = MA_NOACTIVATEANDEAT;
8657 return TRUE;
8659 #endif
8661 } // if event that might trigger a popup to rollup
8662 } // if rollup listeners registered
8664 return FALSE;
8667 /**************************************************************
8668 **************************************************************
8670 ** BLOCK: Misc. utility methods and functions.
8672 ** General use.
8674 **************************************************************
8675 **************************************************************/
8677 // nsModifierKeyState used in various character processing.
8678 nsModifierKeyState::nsModifierKeyState()
8680 mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT);
8681 mIsControlDown = IS_VK_DOWN(NS_VK_CONTROL);
8682 mIsAltDown = IS_VK_DOWN(NS_VK_ALT);
8686 PRInt32 nsWindow::GetWindowsVersion()
8688 #ifdef WINCE
8689 return 0x500;
8690 #else
8691 static PRInt32 version = 0;
8692 static PRBool didCheck = PR_FALSE;
8694 if (!didCheck)
8696 didCheck = PR_TRUE;
8697 OSVERSIONINFOEX osInfo;
8698 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
8699 // This cast is safe and supposed to be here, don't worry
8700 ::GetVersionEx((OSVERSIONINFO*)&osInfo);
8701 version = (osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
8703 return version;
8704 #endif
8707 // Note that the result of GetTopLevelWindow method can be different from the
8708 // result of GetTopLevelHWND method. The result can be non-floating window.
8709 // Because our top level window may be contained in another window which is
8710 // not managed by us.
8711 nsWindow* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup)
8713 nsWindow* curWindow = this;
8715 while (PR_TRUE) {
8716 if (aStopOnDialogOrPopup) {
8717 switch (curWindow->mWindowType) {
8718 case eWindowType_dialog:
8719 case eWindowType_popup:
8720 return curWindow;
8721 default:
8722 break;
8726 // Retrieve the top level parent or owner window
8727 nsWindow* parentWindow = curWindow->GetParentWindow(PR_TRUE);
8729 if (!parentWindow)
8730 return curWindow;
8732 curWindow = parentWindow;
8736 // Note that the result of GetTopLevelHWND can be different from the result
8737 // of GetTopLevelWindow method. Because this is checking whether the window
8738 // is top level only in Win32 window system. Therefore, the result window
8739 // may not be managed by us.
8740 HWND nsWindow::GetTopLevelHWND(HWND aWnd, PRBool aStopOnDialogOrPopup)
8742 HWND curWnd = aWnd;
8743 HWND topWnd = NULL;
8744 HWND upWnd = NULL;
8746 while (curWnd) {
8747 topWnd = curWnd;
8749 if (aStopOnDialogOrPopup) {
8750 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8752 VERIFY_WINDOW_STYLE(style);
8754 if (!(style & WS_CHILD)) // first top-level window
8755 break;
8758 upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
8760 #ifdef WINCE
8761 // For dialog windows, we want just the parent, not the owner.
8762 // For other/popup windows, we want to find the first owner/parent
8763 // that's a dialog and/or has an owner.
8764 if (upWnd && ::GetWindow(curWnd, GW_OWNER) == upWnd) {
8765 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8766 if ((style & WS_DLGFRAME) != 0)
8767 break;
8769 #endif
8771 curWnd = upWnd;
8774 return topWnd;
8777 static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam)
8779 DWORD pid;
8780 ::GetWindowThreadProcessId(hwnd, &pid);
8781 if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd))
8783 gWindowsVisible = PR_TRUE;
8784 return FALSE;
8786 return TRUE;
8789 PRBool nsWindow::CanTakeFocus()
8791 gWindowsVisible = PR_FALSE;
8792 EnumWindows(gEnumWindowsProc, 0);
8793 if (!gWindowsVisible) {
8794 return PR_TRUE;
8795 } else {
8796 HWND fgWnd = ::GetForegroundWindow();
8797 if (!fgWnd) {
8798 return PR_TRUE;
8800 DWORD pid;
8801 GetWindowThreadProcessId(fgWnd, &pid);
8802 if (pid == GetCurrentProcessId()) {
8803 return PR_TRUE;
8806 return PR_FALSE;
8809 void nsWindow::GetMainWindowClass(nsAString& aClass)
8811 nsresult rv;
8812 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8813 if (NS_SUCCEEDED(rv) && prefs) {
8814 nsXPIDLCString name;
8815 rv = prefs->GetCharPref("ui.window_class_override", getter_Copies(name));
8816 if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
8817 aClass.AssignASCII(name.get());
8818 return;
8821 aClass.AssignASCII(sDefaultMainWindowClass);
8824 PRBool nsWindow::UseTrackPointHack()
8826 nsresult rv;
8827 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8828 if (NS_SUCCEEDED(rv) && prefs) {
8829 PRInt32 lHackValue;
8830 rv = prefs->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue);
8831 if (NS_SUCCEEDED(rv)) {
8832 switch (lHackValue) {
8833 case 0: // disabled
8834 return PR_FALSE;
8835 case 1: // enabled
8836 return PR_TRUE;
8837 default: // -1: autodetect
8838 break;
8842 return sDefaultTrackPointHack;
8845 #if !defined(WINCE)
8846 static PRBool
8847 HasRegistryKey(HKEY aRoot, LPCWSTR aName)
8849 HKEY key;
8850 LONG result = ::RegOpenKeyExW(aRoot, aName, 0, KEY_READ, &key);
8851 if (result != ERROR_SUCCESS)
8852 return PR_FALSE;
8853 ::RegCloseKey(key);
8854 return PR_TRUE;
8857 static PRBool
8858 IsObsoleteSynapticsDriver()
8860 HKEY key;
8861 LONG result = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE,
8862 L"Software\\Synaptics\\SynTP\\Install", 0, KEY_READ, &key);
8863 if (result != ERROR_SUCCESS)
8864 return PR_FALSE;
8865 DWORD type;
8866 PRUnichar buf[40];
8867 DWORD buflen = sizeof(buf);
8868 result = ::RegQueryValueExW(key, L"DriverVersion", NULL, &type, (BYTE*)buf, &buflen);
8869 ::RegCloseKey(key);
8870 if (result != ERROR_SUCCESS || type != REG_SZ)
8871 return PR_FALSE;
8872 buf[NS_ARRAY_LENGTH(buf) - 1] = 0;
8874 int majorVersion = wcstol(buf, NULL, 10);
8875 return majorVersion < 15;
8878 void nsWindow::InitInputHackDefaults()
8880 if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Lenovo\\TrackPoint")) {
8881 sDefaultTrackPointHack = PR_TRUE;
8882 } else if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Lenovo\\UltraNav")) {
8883 sDefaultTrackPointHack = PR_TRUE;
8884 } else if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Alps\\Apoint\\TrackPoint")) {
8885 sDefaultTrackPointHack = PR_TRUE;
8886 } else if ((HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB") ||
8887 HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2")) &&
8888 IsObsoleteSynapticsDriver()) {
8889 sDefaultTrackPointHack = PR_TRUE;
8892 #endif // #if !defined(WINCE)
8894 LPARAM nsWindow::lParamToScreen(LPARAM lParam)
8896 POINT pt;
8897 pt.x = GET_X_LPARAM(lParam);
8898 pt.y = GET_Y_LPARAM(lParam);
8899 ::ClientToScreen(mWnd, &pt);
8900 return MAKELPARAM(pt.x, pt.y);
8903 LPARAM nsWindow::lParamToClient(LPARAM lParam)
8905 POINT pt;
8906 pt.x = GET_X_LPARAM(lParam);
8907 pt.y = GET_Y_LPARAM(lParam);
8908 ::ScreenToClient(mWnd, &pt);
8909 return MAKELPARAM(pt.x, pt.y);
8912 /**************************************************************
8913 **************************************************************
8915 ** BLOCK: ChildWindow impl.
8917 ** Child window overrides.
8919 **************************************************************
8920 **************************************************************/
8922 // return the style for a child nsWindow
8923 DWORD ChildWindow::WindowStyle()
8925 DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle();
8926 if (!(style & WS_POPUP))
8927 style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
8928 VERIFY_WINDOW_STYLE(style);
8929 return style;