Bug 629709 - White line of highlight pixels appears above navigation toolbar if the...
[mozilla-central.git] / widget / src / windows / nsWindow.cpp
blob71da7f738963a37b2bc88d93981e17ced6496ead
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 // 2 pixel offset for eTransparencyBorderlessGlass which equals
380 // the size of the default window border Windows paints.
381 static const PRInt32 kGlassMarginAdjustment = 2;
383 /**************************************************************
384 **************************************************************
386 ** BLOCK: nsIWidget impl.
388 ** nsIWidget interface implementation, broken down into
389 ** sections.
391 **************************************************************
392 **************************************************************/
394 /**************************************************************
396 * SECTION: nsWindow construction and destruction
398 **************************************************************/
400 nsWindow::nsWindow() : nsBaseWidget()
402 #ifdef PR_LOGGING
403 if (!gWindowsLog)
404 gWindowsLog = PR_NewLogModule("nsWindowsWidgets");
405 #endif
407 mWnd = nsnull;
408 mPaintDC = nsnull;
409 mPrevWndProc = nsnull;
410 mOldIMC = nsnull;
411 mNativeDragTarget = nsnull;
412 mInDtor = PR_FALSE;
413 mIsVisible = PR_FALSE;
414 mIsTopWidgetWindow = PR_FALSE;
415 mUnicodeWidget = PR_TRUE;
416 mDisplayPanFeedback = PR_FALSE;
417 mTouchWindow = PR_FALSE;
418 mCustomNonClient = PR_FALSE;
419 mHideChrome = PR_FALSE;
420 mFullscreenMode = PR_FALSE;
421 mMousePresent = PR_FALSE;
422 mWindowType = eWindowType_child;
423 mBorderStyle = eBorderStyle_default;
424 mPopupType = ePopupTypeAny;
425 mOldSizeMode = nsSizeMode_Normal;
426 mLastPoint.x = 0;
427 mLastPoint.y = 0;
428 mLastSize.width = 0;
429 mLastSize.height = 0;
430 mOldStyle = 0;
431 mOldExStyle = 0;
432 mPainting = 0;
433 mLastKeyboardLayout = 0;
434 mBlurSuppressLevel = 0;
435 mIMEContext.mStatus = nsIWidget::IME_STATUS_ENABLED;
436 #ifdef MOZ_XUL
437 mTransparentSurface = nsnull;
438 mMemoryDC = nsnull;
439 mTransparencyMode = eTransparencyOpaque;
440 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
441 memset(&mGlassMargins, 0, sizeof mGlassMargins);
442 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
443 #endif
444 mBackground = ::GetSysColor(COLOR_BTNFACE);
445 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
446 mForeground = ::GetSysColor(COLOR_WINDOWTEXT);
448 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
449 mTaskbarPreview = nsnull;
450 mHasTaskbarIconBeenCreated = PR_FALSE;
451 #endif
453 // Global initialization
454 if (!sInstanceCount) {
455 #if !defined(WINCE)
456 gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
457 #endif
459 // Init IME handler
460 nsIMM32Handler::Initialize();
462 #ifdef NS_ENABLE_TSF
463 nsTextStore::Initialize();
464 #endif
466 #if !defined(WINCE)
467 if (SUCCEEDED(::OleInitialize(NULL)))
468 sIsOleInitialized = TRUE;
469 NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
470 #endif
472 #if !defined(WINCE)
473 InitInputHackDefaults();
474 #endif
476 // Init titlebar button info for custom frames.
477 nsUXThemeData::InitTitlebarInfo();
478 // Init theme data
479 nsUXThemeData::UpdateNativeThemeInfo();
481 ForgetRedirectedKeyDownMessage();
482 } // !sInstanceCount
484 mIdleService = nsnull;
486 sInstanceCount++;
489 nsWindow::~nsWindow()
491 mInDtor = PR_TRUE;
493 // If the widget was released without calling Destroy() then the native window still
494 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
496 // XXX How could this happen???
497 if (NULL != mWnd)
498 Destroy();
500 sInstanceCount--;
502 // Global shutdown
503 if (sInstanceCount == 0) {
504 #ifdef NS_ENABLE_TSF
505 nsTextStore::Terminate();
506 #endif
508 #if !defined(WINCE)
509 NS_IF_RELEASE(sCursorImgContainer);
510 if (sIsOleInitialized) {
511 ::OleFlushClipboard();
512 ::OleUninitialize();
513 sIsOleInitialized = FALSE;
515 // delete any of the IME structures that we allocated
516 nsIMM32Handler::Terminate();
517 #endif // !defined(WINCE)
520 #if !defined(WINCE)
521 NS_IF_RELEASE(mNativeDragTarget);
522 #endif // !defined(WINCE)
525 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
527 /**************************************************************
529 * SECTION: nsIWidget::Create, nsIWidget::Destroy
531 * Creating and destroying windows for this widget.
533 **************************************************************/
535 // Allow Derived classes to modify the height that is passed
536 // when the window is created or resized. Also add extra height
537 // if needed (on Windows CE)
538 PRInt32 nsWindow::GetHeight(PRInt32 aProposedHeight)
540 PRInt32 extra = 0;
542 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
543 DWORD style = WindowStyle();
544 if ((style & WS_SYSMENU) && (style & WS_POPUP)) {
545 extra = GetSystemMetrics(SM_CYCAPTION);
547 #endif
549 return aProposedHeight + extra;
552 // Create the proper widget
553 nsresult
554 nsWindow::Create(nsIWidget *aParent,
555 nsNativeWidget aNativeParent,
556 const nsIntRect &aRect,
557 EVENT_CALLBACK aHandleEventFunction,
558 nsIDeviceContext *aContext,
559 nsIAppShell *aAppShell,
560 nsIToolkit *aToolkit,
561 nsWidgetInitData *aInitData)
563 nsWidgetInitData defaultInitData;
564 if (!aInitData)
565 aInitData = &defaultInitData;
567 mUnicodeWidget = aInitData->mUnicode;
569 nsIWidget *baseParent = aInitData->mWindowType == eWindowType_dialog ||
570 aInitData->mWindowType == eWindowType_toplevel ||
571 aInitData->mWindowType == eWindowType_invisible ?
572 nsnull : aParent;
574 mIsTopWidgetWindow = (nsnull == baseParent);
575 mBounds = aRect;
577 BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
578 aAppShell, aToolkit, aInitData);
580 HWND parent;
581 if (aParent) { // has a nsIWidget parent
582 parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : NULL;
583 mParent = aParent;
584 } else { // has a nsNative parent
585 parent = (HWND)aNativeParent;
586 mParent = aNativeParent ? GetNSWindowPtr((HWND)aNativeParent) : nsnull;
589 mPopupType = aInitData->mPopupHint;
590 mIsRTL = aInitData->mRTL;
592 DWORD style = WindowStyle();
593 DWORD extendedStyle = WindowExStyle();
595 if (mWindowType == eWindowType_popup) {
596 if (!aParent)
597 parent = NULL;
598 } else if (mWindowType == eWindowType_invisible) {
599 // Make sure CreateWindowEx succeeds at creating a toplevel window
600 style &= ~0x40000000; // WS_CHILDWINDOW
601 } else {
602 // See if the caller wants to explictly set clip children and clip siblings
603 if (aInitData->clipChildren) {
604 style |= WS_CLIPCHILDREN;
605 } else {
606 style &= ~WS_CLIPCHILDREN;
608 if (aInitData->clipSiblings) {
609 style |= WS_CLIPSIBLINGS;
613 nsAutoString className;
614 if (aInitData->mDropShadow) {
615 GetWindowPopupClass(className);
616 } else {
617 GetWindowClass(className);
619 mWnd = ::CreateWindowExW(extendedStyle,
620 className.get(),
621 L"",
622 style,
623 aRect.x,
624 aRect.y,
625 aRect.width,
626 GetHeight(aRect.height),
627 parent,
628 NULL,
629 nsToolkit::mDllInstance,
630 NULL);
632 if (!mWnd) {
633 NS_WARNING("nsWindow CreateWindowEx failed.");
634 return NS_ERROR_FAILURE;
637 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
638 if (mIsRTL && nsUXThemeData::dwmSetWindowAttributePtr) {
639 DWORD dwAttribute = TRUE;
640 nsUXThemeData::dwmSetWindowAttributePtr(mWnd, DWMWA_NONCLIENT_RTL_LAYOUT, &dwAttribute, sizeof dwAttribute);
642 #endif
644 if (mWindowType != eWindowType_plugin &&
645 mWindowType != eWindowType_invisible &&
646 UseTrackPointHack()) {
647 // Ugly Thinkpad Driver Hack (Bugs 507222 and 594977)
649 // We create two zero-sized windows as descendants of the top-level window,
650 // like so:
652 // Top-level window (MozillaWindowClass)
653 // FAKETRACKPOINTSCROLLCONTAINER (MozillaWindowClass)
654 // FAKETRACKPOINTSCROLLABLE (MozillaWindowClass)
656 // We need to have the middle window, otherwise the Trackpoint driver
657 // will fail to deliver scroll messages. WM_MOUSEWHEEL messages are
658 // sent to the FAKETRACKPOINTSCROLLABLE, which then propagate up the
659 // window hierarchy until they are handled by nsWindow::WindowProc.
660 // WM_HSCROLL messages are also sent to the FAKETRACKPOINTSCROLLABLE,
661 // but these do not propagate automatically, so we have the window
662 // procedure pretend that they were dispatched to the top-level window
663 // instead.
665 // The FAKETRACKPOINTSCROLLABLE needs to have the specific window styles it
666 // is given below so that it catches the Trackpoint driver's heuristics.
667 HWND scrollContainerWnd = ::CreateWindowW
668 (className.get(), L"FAKETRACKPOINTSCROLLCONTAINER",
669 WS_CHILD | WS_VISIBLE,
670 0, 0, 0, 0, mWnd, NULL, nsToolkit::mDllInstance, NULL);
671 HWND scrollableWnd = ::CreateWindowW
672 (className.get(), L"FAKETRACKPOINTSCROLLABLE",
673 WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | 0x30,
674 0, 0, 0, 0, scrollContainerWnd, NULL, nsToolkit::mDllInstance, NULL);
676 // Give the FAKETRACKPOINTSCROLLABLE window a specific ID so that
677 // WindowProcInternal can distinguish it from the top-level window
678 // easily.
679 ::SetWindowLongPtrW(scrollableWnd, GWLP_ID, eFakeTrackPointScrollableID);
681 // Make FAKETRACKPOINTSCROLLABLE use nsWindow::WindowProc, and store the
682 // old window procedure in its "user data".
683 WNDPROC oldWndProc;
684 if (mUnicodeWidget)
685 oldWndProc = (WNDPROC)::SetWindowLongPtrW(scrollableWnd, GWLP_WNDPROC,
686 (LONG_PTR)nsWindow::WindowProc);
687 else
688 oldWndProc = (WNDPROC)::SetWindowLongPtrA(scrollableWnd, GWLP_WNDPROC,
689 (LONG_PTR)nsWindow::WindowProc);
690 ::SetWindowLongPtrW(scrollableWnd, GWLP_USERDATA, (LONG_PTR)oldWndProc);
693 // call the event callback to notify about creation
695 DispatchStandardEvent(NS_CREATE);
696 SubclassWindow(TRUE);
698 if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
699 /* The internal variable set by the config.trim_on_minimize pref
700 has not yet been initialized, and this is the hidden window
701 (conveniently created before any visible windows, and after
702 the profile has been initialized).
704 Default config.trim_on_minimize to false, to fix bug 76831
705 for good. If anyone complains about this new default, saying
706 that a Mozilla app hogs too much memory while minimized, they
707 will have that entire bug tattooed on their backside. */
709 sTrimOnMinimize = 0;
710 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
711 if (prefs) {
712 nsCOMPtr<nsIPrefBranch> prefBranch;
713 prefs->GetBranch(0, getter_AddRefs(prefBranch));
714 if (prefBranch) {
716 PRBool temp;
717 if (NS_SUCCEEDED(prefBranch->GetBoolPref("config.trim_on_minimize",
718 &temp))
719 && temp)
720 sTrimOnMinimize = 1;
722 if (NS_SUCCEEDED(prefBranch->GetBoolPref("intl.keyboard.per_window_layout",
723 &temp)))
724 sSwitchKeyboardLayout = temp;
726 if (NS_SUCCEEDED(prefBranch->GetBoolPref("mozilla.widget.disable-native-theme",
727 &temp)))
728 gDisableNativeTheme = temp;
732 #if defined(WINCE_HAVE_SOFTKB)
733 if (mWindowType == eWindowType_dialog || mWindowType == eWindowType_toplevel )
734 nsWindowCE::CreateSoftKeyMenuBar(mWnd);
735 #endif
737 return NS_OK;
740 // Close this nsWindow
741 NS_METHOD nsWindow::Destroy()
743 // WM_DESTROY has already fired, we're done.
744 if (nsnull == mWnd)
745 return NS_OK;
747 // During the destruction of all of our children, make sure we don't get deleted.
748 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
751 * On windows the LayerManagerOGL destructor wants the widget to be around for
752 * cleanup. It also would like to have the HWND intact, so we NULL it here.
754 if (mLayerManager) {
755 mLayerManager->Destroy();
757 mLayerManager = nsnull;
759 /* We should clear our cached resources now and not wait for the GC to
760 * delete the nsWindow. */
761 ClearCachedResources();
763 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
764 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
765 // from it. The function also destroys the window's menu, flushes the thread message queue,
766 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
767 // the window is at the top of the viewer chain).
769 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
770 // the associated child or owned windows when it destroys the parent or owner window. The
771 // function first destroys child or owned windows, and then it destroys the parent or owner
772 // window.
773 VERIFY(::DestroyWindow(mWnd));
775 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
776 // didn't get called, call it now.
777 if (PR_FALSE == mOnDestroyCalled) {
778 LRESULT result;
779 mWindowHook.Notify(mWnd, WM_DESTROY, 0, 0, &result);
780 OnDestroy();
783 return NS_OK;
786 /**************************************************************
788 * SECTION: Window class utilities
790 * Utilities for calculating the proper window class name for
791 * Create window.
793 **************************************************************/
795 void nsWindow::RegisterWindowClass(const nsString& aClassName, UINT aExtraStyle,
796 LPWSTR aIconID)
798 WNDCLASSW wc;
799 if (::GetClassInfoW(nsToolkit::mDllInstance, aClassName.get(), &wc)) {
800 // already registered
801 return;
804 wc.style = CS_DBLCLKS | aExtraStyle;
805 wc.lpfnWndProc = ::DefWindowProcW;
806 wc.cbClsExtra = 0;
807 wc.cbWndExtra = 0;
808 wc.hInstance = nsToolkit::mDllInstance;
809 wc.hIcon = aIconID ? ::LoadIconW(::GetModuleHandleW(NULL), aIconID) : NULL;
810 wc.hCursor = NULL;
811 wc.hbrBackground = mBrush;
812 wc.lpszMenuName = NULL;
813 wc.lpszClassName = aClassName.get();
815 if (!::RegisterClassW(&wc)) {
816 // For older versions of Win32 (i.e., not XP), the registration may
817 // fail with aExtraStyle, so we have to re-register without it.
818 wc.style = CS_DBLCLKS;
819 ::RegisterClassW(&wc);
823 static LPWSTR const gStockApplicationIcon = MAKEINTRESOURCEW(32512);
825 // Return the proper window class for everything except popups.
826 void nsWindow::GetWindowClass(nsString& aWindowClass)
828 switch (mWindowType) {
829 case eWindowType_invisible:
830 aWindowClass.AssignLiteral(kClassNameHidden);
831 RegisterWindowClass(aWindowClass, 0, gStockApplicationIcon);
832 break;
833 case eWindowType_dialog:
834 aWindowClass.AssignLiteral(kClassNameDialog);
835 RegisterWindowClass(aWindowClass, 0, 0);
836 break;
837 default:
838 GetMainWindowClass(aWindowClass);
839 RegisterWindowClass(aWindowClass, 0, gStockApplicationIcon);
840 break;
844 // Return the proper popup window class
845 void nsWindow::GetWindowPopupClass(nsString& aWindowClass)
847 aWindowClass.AssignLiteral(kClassNameDropShadow);
848 RegisterWindowClass(aWindowClass, CS_XP_DROPSHADOW, gStockApplicationIcon);
851 /**************************************************************
853 * SECTION: Window styles utilities
855 * Return the proper windows styles and extended styles.
857 **************************************************************/
859 // Return nsWindow styles
860 #if !defined(WINCE) // implemented in nsWindowCE.cpp
861 DWORD nsWindow::WindowStyle()
863 DWORD style;
865 switch (mWindowType) {
866 case eWindowType_plugin:
867 case eWindowType_child:
868 style = WS_OVERLAPPED;
869 break;
871 case eWindowType_dialog:
872 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK |
873 DS_MODALFRAME | WS_CLIPCHILDREN;
874 if (mBorderStyle != eBorderStyle_default)
875 style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
876 break;
878 case eWindowType_popup:
879 style = WS_POPUP;
880 if (!HasGlass()) {
881 style |= WS_OVERLAPPED;
883 break;
885 default:
886 NS_ERROR("unknown border style");
887 // fall through
889 case eWindowType_toplevel:
890 case eWindowType_invisible:
891 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU |
892 WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
893 break;
896 if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) {
897 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border))
898 style &= ~WS_BORDER;
900 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) {
901 style &= ~WS_DLGFRAME;
902 style |= WS_POPUP;
903 style &= ~WS_CHILD;
906 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close))
907 style &= ~0;
908 // XXX The close box can only be removed by changing the window class,
909 // as far as I know --- roc+moz@cs.cmu.edu
911 if (mBorderStyle == eBorderStyle_none ||
912 !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
913 style &= ~WS_SYSMENU;
914 // Looks like getting rid of the system menu also does away with the
915 // close box. So, we only get rid of the system menu if you want neither it
916 // nor the close box. How does the Windows "Dialog" window class get just
917 // closebox and no sysmenu? Who knows.
919 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh))
920 style &= ~WS_THICKFRAME;
922 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize))
923 style &= ~WS_MINIMIZEBOX;
925 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize))
926 style &= ~WS_MAXIMIZEBOX;
928 if (IsPopupWithTitleBar()) {
929 style |= WS_CAPTION;
930 if (mBorderStyle & eBorderStyle_close) {
931 style |= WS_SYSMENU;
936 VERIFY_WINDOW_STYLE(style);
937 return style;
939 #endif // !defined(WINCE)
941 // Return nsWindow extended styles
942 DWORD nsWindow::WindowExStyle()
944 switch (mWindowType)
946 case eWindowType_plugin:
947 case eWindowType_child:
948 return 0;
950 case eWindowType_dialog:
951 return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
953 case eWindowType_popup:
955 DWORD extendedStyle =
956 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
957 WS_EX_NOACTIVATE |
958 #endif
959 WS_EX_TOOLWINDOW;
960 if (mPopupLevel == ePopupLevelTop)
961 extendedStyle |= WS_EX_TOPMOST;
962 return extendedStyle;
964 default:
965 NS_ERROR("unknown border style");
966 // fall through
968 case eWindowType_toplevel:
969 case eWindowType_invisible:
970 return WS_EX_WINDOWEDGE;
974 /**************************************************************
976 * SECTION: Window subclassing utilities
978 * Set or clear window subclasses on native windows. Used in
979 * Create and Destroy.
981 **************************************************************/
983 // Subclass (or remove the subclass from) this component's nsWindow
984 void nsWindow::SubclassWindow(BOOL bState)
986 if (NULL != mWnd) {
987 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
988 if (!::IsWindow(mWnd)) {
989 NS_ERROR("Invalid window handle");
992 if (bState) {
993 // change the nsWindow proc
994 if (mUnicodeWidget)
995 mPrevWndProc = (WNDPROC)::SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
996 (LONG_PTR)nsWindow::WindowProc);
997 else
998 mPrevWndProc = (WNDPROC)::SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
999 (LONG_PTR)nsWindow::WindowProc);
1000 NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
1001 // connect the this pointer to the nsWindow handle
1002 SetNSWindowPtr(mWnd, this);
1004 else {
1005 if (mUnicodeWidget)
1006 ::SetWindowLongPtrW(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
1007 else
1008 ::SetWindowLongPtrA(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
1009 SetNSWindowPtr(mWnd, NULL);
1010 mPrevWndProc = NULL;
1015 /**************************************************************
1017 * SECTION: Window properties
1019 * Set and clear native window properties.
1021 **************************************************************/
1023 static PRUnichar sPropName[40] = L"";
1024 static PRUnichar* GetNSWindowPropName()
1026 if (!*sPropName)
1028 _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p", GetCurrentProcessId());
1029 sPropName[39] = '\0';
1031 return sPropName;
1034 nsWindow * nsWindow::GetNSWindowPtr(HWND aWnd)
1036 return (nsWindow *) ::GetPropW(aWnd, GetNSWindowPropName());
1039 BOOL nsWindow::SetNSWindowPtr(HWND aWnd, nsWindow * ptr)
1041 if (ptr == NULL) {
1042 ::RemovePropW(aWnd, GetNSWindowPropName());
1043 return TRUE;
1044 } else {
1045 return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)ptr);
1049 /**************************************************************
1051 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
1053 * Set or clear the parent widgets using window properties, and
1054 * handles calculating native parent handles.
1056 **************************************************************/
1058 // Get and set parent widgets
1059 NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent)
1061 mParent = aNewParent;
1063 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1064 nsIWidget* parent = GetParent();
1065 if (parent) {
1066 parent->RemoveChild(this);
1068 if (aNewParent) {
1069 ReparentNativeWidget(aNewParent);
1070 aNewParent->AddChild(this);
1071 return NS_OK;
1073 if (mWnd) {
1074 // If we have no parent, SetParent should return the desktop.
1075 VERIFY(::SetParent(mWnd, nsnull));
1077 return NS_OK;
1080 NS_IMETHODIMP
1081 nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
1083 NS_PRECONDITION(aNewParent, "");
1085 mParent = aNewParent;
1086 if (mWindowType == eWindowType_popup) {
1087 return NS_OK;
1089 HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
1090 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
1091 if (newParent && mWnd) {
1092 ::SetParent(mWnd, newParent);
1094 return NS_OK;
1097 nsIWidget* nsWindow::GetParent(void)
1099 return GetParentWindow(PR_FALSE);
1102 float nsWindow::GetDPI()
1104 HDC dc = ::GetDC(mWnd);
1105 if (!dc)
1106 return 96.0f;
1108 double heightInches = ::GetDeviceCaps(dc, VERTSIZE)/MM_PER_INCH_FLOAT;
1109 int heightPx = ::GetDeviceCaps(dc, VERTRES);
1110 ::ReleaseDC(mWnd, dc);
1111 if (heightInches < 0.25) {
1112 // Something's broken
1113 return 96.0f;
1115 return float(heightPx/heightInches);
1118 nsWindow* nsWindow::GetParentWindow(PRBool aIncludeOwner)
1120 if (mIsTopWidgetWindow) {
1121 // Must use a flag instead of mWindowType to tell if the window is the
1122 // owned by the topmost widget, because a child window can be embedded inside
1123 // a HWND which is not associated with a nsIWidget.
1124 return nsnull;
1127 // If this widget has already been destroyed, pretend we have no parent.
1128 // This corresponds to code in Destroy which removes the destroyed
1129 // widget from its parent's child list.
1130 if (mInDtor || mOnDestroyCalled)
1131 return nsnull;
1134 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1135 // root owner. aIncludeOwner set to false implies the search will stop at the
1136 // true parent (default).
1137 nsWindow* widget = nsnull;
1138 if (mWnd) {
1139 #ifdef WINCE
1140 HWND parent = ::GetParent(mWnd);
1141 #else
1142 HWND parent = nsnull;
1143 if (aIncludeOwner)
1144 parent = ::GetParent(mWnd);
1145 else
1146 parent = ::GetAncestor(mWnd, GA_PARENT);
1147 #endif
1148 if (parent) {
1149 widget = GetNSWindowPtr(parent);
1150 if (widget) {
1151 // If the widget is in the process of being destroyed then
1152 // do NOT return it
1153 if (widget->mInDtor) {
1154 widget = nsnull;
1160 return widget;
1163 BOOL CALLBACK
1164 nsWindow::EnumAllChildWindProc(HWND aWnd, LPARAM aParam)
1166 nsWindow *wnd = nsWindow::GetNSWindowPtr(aWnd);
1167 if (wnd) {
1168 ((nsWindow::WindowEnumCallback*)aParam)(wnd);
1170 return TRUE;
1173 BOOL CALLBACK
1174 nsWindow::EnumAllThreadWindowProc(HWND aWnd, LPARAM aParam)
1176 nsWindow *wnd = nsWindow::GetNSWindowPtr(aWnd);
1177 if (wnd) {
1178 ((nsWindow::WindowEnumCallback*)aParam)(wnd);
1180 EnumChildWindows(aWnd, EnumAllChildWindProc, aParam);
1181 return TRUE;
1184 void
1185 nsWindow::EnumAllWindows(WindowEnumCallback aCallback)
1187 EnumThreadWindows(GetCurrentThreadId(),
1188 EnumAllThreadWindowProc,
1189 (LPARAM)aCallback);
1192 /**************************************************************
1194 * SECTION: nsIWidget::Show
1196 * Hide or show this component.
1198 **************************************************************/
1200 NS_METHOD nsWindow::Show(PRBool bState)
1202 #if defined(MOZ_SPLASHSCREEN)
1203 // we're about to show the first toplevel window,
1204 // so kill off any splash screen if we had one
1205 nsSplashScreen *splash = nsSplashScreen::Get();
1206 if (splash && splash->IsOpen() && mWnd && bState &&
1207 (mWindowType == eWindowType_toplevel ||
1208 mWindowType == eWindowType_dialog ||
1209 mWindowType == eWindowType_popup))
1211 splash->Close();
1213 #endif
1215 #ifdef NS_FUNCTION_TIMER
1216 static bool firstShow = true;
1217 if (firstShow &&
1218 (mWindowType == eWindowType_toplevel ||
1219 mWindowType == eWindowType_dialog ||
1220 mWindowType == eWindowType_popup))
1222 firstShow = false;
1223 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1225 #endif
1227 PRBool wasVisible = mIsVisible;
1228 // Set the status now so that anyone asking during ShowWindow or
1229 // SetWindowPos would get the correct answer.
1230 mIsVisible = bState;
1232 if (!mIsVisible && wasVisible) {
1233 ClearCachedResources();
1236 if (mWnd) {
1237 if (bState) {
1238 if (!wasVisible && mWindowType == eWindowType_toplevel) {
1239 switch (mSizeMode) {
1240 #ifdef WINCE
1241 case nsSizeMode_Fullscreen:
1242 ::SetForegroundWindow(mWnd);
1243 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1244 MakeFullScreen(TRUE);
1245 break;
1247 case nsSizeMode_Maximized :
1248 ::SetForegroundWindow(mWnd);
1249 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1250 break;
1251 // use default for nsSizeMode_Minimized on Windows CE
1252 #else
1253 case nsSizeMode_Maximized :
1254 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1255 break;
1256 case nsSizeMode_Minimized :
1257 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
1258 break;
1259 #endif
1260 default:
1261 if (CanTakeFocus()) {
1262 #ifdef WINCE
1263 ::SetForegroundWindow(mWnd);
1264 #endif
1265 ::ShowWindow(mWnd, SW_SHOWNORMAL);
1266 } else {
1267 // Place the window behind the foreground window
1268 // (as long as it is not topmost)
1269 HWND wndAfter = ::GetForegroundWindow();
1270 if (!wndAfter)
1271 wndAfter = HWND_BOTTOM;
1272 else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)
1273 wndAfter = HWND_TOP;
1274 ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE |
1275 SWP_NOMOVE | SWP_NOACTIVATE);
1276 GetAttention(2);
1278 break;
1280 } else {
1281 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
1282 if (wasVisible)
1283 flags |= SWP_NOZORDER;
1285 if (mWindowType == eWindowType_popup) {
1286 #ifndef WINCE
1287 // ensure popups are the topmost of the TOPMOST
1288 // layer. Remember not to set the SWP_NOZORDER
1289 // flag as that might allow the taskbar to overlap
1290 // the popup. However on windows ce, we need to
1291 // activate the popup or clicks will not be sent.
1292 flags |= SWP_NOACTIVATE;
1293 #endif
1294 HWND owner = ::GetWindow(mWnd, GW_OWNER);
1295 ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
1296 } else {
1297 #ifndef WINCE
1298 if (mWindowType == eWindowType_dialog && !CanTakeFocus())
1299 flags |= SWP_NOACTIVATE;
1300 #endif
1301 ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
1305 #ifndef WINCE
1306 if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) {
1307 // when a toplevel window or dialog is shown, initialize the UI state
1308 ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
1310 #endif
1311 } else {
1312 if (mWindowType != eWindowType_dialog) {
1313 ::ShowWindow(mWnd, SW_HIDE);
1314 } else {
1315 ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1316 SWP_NOZORDER | SWP_NOACTIVATE);
1321 #ifdef MOZ_XUL
1322 if (!wasVisible && bState)
1323 Invalidate(PR_FALSE);
1324 #endif
1326 return NS_OK;
1329 /**************************************************************
1331 * SECTION: nsIWidget::IsVisible
1333 * Returns the visibility state.
1335 **************************************************************/
1337 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1338 NS_METHOD nsWindow::IsVisible(PRBool & bState)
1340 bState = mIsVisible;
1341 return NS_OK;
1344 /**************************************************************
1346 * SECTION: Window clipping utilities
1348 * Used in Size and Move operations for setting the proper
1349 * window clipping regions for window transparency.
1351 **************************************************************/
1353 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1354 // transparency. These routines are called on size and move operations.
1355 void nsWindow::ClearThemeRegion()
1357 #ifndef WINCE
1358 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1359 (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1360 (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1361 SetWindowRgn(mWnd, NULL, false);
1363 #endif
1366 void nsWindow::SetThemeRegion()
1368 #ifndef WINCE
1369 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1370 // for other window types as needed. The regions are applied generically to the base window
1371 // so default constants are used for part and state. At some point we might need part and
1372 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1373 // change shape based on state haven't come up.
1374 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1375 (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1376 (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1377 HRGN hRgn = nsnull;
1378 RECT rect = {0,0,mBounds.width,mBounds.height};
1380 HDC dc = ::GetDC(mWnd);
1381 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
1382 if (hRgn) {
1383 if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted.
1384 DeleteObject(hRgn);
1386 ::ReleaseDC(mWnd, dc);
1388 #endif
1391 /**************************************************************
1393 * SECTION: nsIWidget::RegisterTouchWindow,
1394 * nsIWidget::UnregisterTouchWindow, and helper functions
1396 * Used to register the native window to receive touch events
1398 **************************************************************/
1400 NS_METHOD nsWindow::RegisterTouchWindow() {
1401 mTouchWindow = PR_TRUE;
1402 #ifndef WINCE
1403 mGesture.RegisterTouchWindow(mWnd);
1404 ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
1405 #endif
1406 return NS_OK;
1409 NS_METHOD nsWindow::UnregisterTouchWindow() {
1410 mTouchWindow = PR_FALSE;
1411 #ifndef WINCE
1412 mGesture.UnregisterTouchWindow(mWnd);
1413 ::EnumChildWindows(mWnd, nsWindow::UnregisterTouchForDescendants, 0);
1414 #endif
1415 return NS_OK;
1418 #ifndef WINCE
1419 BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1420 nsWindow* win = GetNSWindowPtr(aWnd);
1421 if (win)
1422 win->mGesture.RegisterTouchWindow(aWnd);
1423 return TRUE;
1426 BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1427 nsWindow* win = GetNSWindowPtr(aWnd);
1428 if (win)
1429 win->mGesture.UnregisterTouchWindow(aWnd);
1430 return TRUE;
1432 #endif
1434 /**************************************************************
1436 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1437 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1439 * Repositioning and sizing a window.
1441 **************************************************************/
1443 // Move this component
1444 NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
1446 if (mWindowType == eWindowType_toplevel ||
1447 mWindowType == eWindowType_dialog) {
1448 SetSizeMode(nsSizeMode_Normal);
1450 // Check to see if window needs to be moved first
1451 // to avoid a costly call to SetWindowPos. This check
1452 // can not be moved to the calling code in nsView, because
1453 // some platforms do not position child windows correctly
1455 // Only perform this check for non-popup windows, since the positioning can
1456 // in fact change even when the x/y do not. We always need to perform the
1457 // check. See bug #97805 for details.
1458 if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
1460 // Nothing to do, since it is already positioned correctly.
1461 return NS_OK;
1464 mBounds.x = aX;
1465 mBounds.y = aY;
1467 if (mWnd) {
1468 #ifdef DEBUG
1469 // complain if a window is moved offscreen (legal, but potentially worrisome)
1470 if (mIsTopWidgetWindow) { // only a problem for top-level windows
1471 // Make sure this window is actually on the screen before we move it
1472 // XXX: Needs multiple monitor support
1473 HDC dc = ::GetDC(mWnd);
1474 if (dc) {
1475 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1476 RECT workArea;
1477 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1478 // no annoying assertions. just mention the issue.
1479 if (aX < 0 || aX >= workArea.right || aY < 0 || aY >= workArea.bottom)
1480 printf("window moved to offscreen position\n");
1482 ::ReleaseDC(mWnd, dc);
1485 #endif
1486 ClearThemeRegion();
1488 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE;
1489 // Workaround SetWindowPos bug with D3D9. If our window has a clip
1490 // region, some drivers or OSes may incorrectly copy into the clipped-out
1491 // area.
1492 if (mWindowType == eWindowType_plugin &&
1493 (!mLayerManager || mLayerManager->GetBackendType() == LayerManager::LAYERS_D3D9) &&
1494 mClipRects &&
1495 (mClipRectCount != 1 || mClipRects[0] != nsIntRect(0, 0, mBounds.width, mBounds.height))) {
1496 flags |= SWP_NOCOPYBITS;
1498 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0, flags));
1500 SetThemeRegion();
1502 return NS_OK;
1505 // Resize this component
1506 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1508 NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
1509 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1511 // Avoid unnecessary resizing calls
1512 if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1513 return NS_OK;
1515 #ifdef MOZ_XUL
1516 if (eTransparencyTransparent == mTransparencyMode)
1517 ResizeTranslucentWindow(aWidth, aHeight);
1518 #endif
1520 // Set cached value for lightweight and printing
1521 mBounds.width = aWidth;
1522 mBounds.height = aHeight;
1524 if (mWnd) {
1525 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
1527 #ifndef WINCE
1528 if (!aRepaint) {
1529 flags |= SWP_NOREDRAW;
1531 #endif
1533 ClearThemeRegion();
1534 VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
1535 SetThemeRegion();
1538 if (aRepaint)
1539 Invalidate(PR_FALSE);
1541 return NS_OK;
1544 // Resize this component
1545 NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1547 NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize");
1548 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1550 // Avoid unnecessary resizing calls
1551 if (mBounds.x == aX && mBounds.y == aY &&
1552 mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1553 return NS_OK;
1555 #ifdef MOZ_XUL
1556 if (eTransparencyTransparent == mTransparencyMode)
1557 ResizeTranslucentWindow(aWidth, aHeight);
1558 #endif
1560 // Set cached value for lightweight and printing
1561 mBounds.x = aX;
1562 mBounds.y = aY;
1563 mBounds.width = aWidth;
1564 mBounds.height = aHeight;
1566 if (mWnd) {
1567 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
1568 #ifndef WINCE
1569 if (!aRepaint) {
1570 flags |= SWP_NOREDRAW;
1572 #endif
1574 ClearThemeRegion();
1575 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
1576 SetThemeRegion();
1579 if (aRepaint)
1580 Invalidate(PR_FALSE);
1582 return NS_OK;
1585 // Resize the client area and position the widget within it's parent
1586 NS_METHOD nsWindow::ResizeClient(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1588 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1589 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1591 // Adjust our existing window bounds, based on the new client dims.
1592 RECT client;
1593 GetClientRect(mWnd, &client);
1594 nsIntPoint dims(client.right - client.left, client.bottom - client.top);
1595 aWidth = mBounds.width + (aWidth - dims.x);
1596 aHeight = mBounds.height + (aHeight - dims.y);
1598 if (aX || aY) {
1599 // offsets
1600 nsIntRect bounds;
1601 GetScreenBounds(bounds);
1602 aX += bounds.x;
1603 aY += bounds.y;
1604 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1606 return Resize(aWidth, aHeight, aRepaint);
1609 #if !defined(WINCE)
1610 NS_IMETHODIMP
1611 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
1613 NS_ENSURE_ARG_POINTER(aEvent);
1615 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
1616 // you can only begin a resize drag with a mouse event
1617 return NS_ERROR_INVALID_ARG;
1620 nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
1621 if (mouseEvent->button != nsMouseEvent::eLeftButton) {
1622 // you can only begin a resize drag with the left mouse button
1623 return NS_ERROR_INVALID_ARG;
1626 // work out what sizemode we're talking about
1627 WPARAM syscommand;
1628 if (aVertical < 0) {
1629 if (aHorizontal < 0) {
1630 syscommand = SC_SIZE | WMSZ_TOPLEFT;
1631 } else if (aHorizontal == 0) {
1632 syscommand = SC_SIZE | WMSZ_TOP;
1633 } else {
1634 syscommand = SC_SIZE | WMSZ_TOPRIGHT;
1636 } else if (aVertical == 0) {
1637 if (aHorizontal < 0) {
1638 syscommand = SC_SIZE | WMSZ_LEFT;
1639 } else if (aHorizontal == 0) {
1640 return NS_ERROR_INVALID_ARG;
1641 } else {
1642 syscommand = SC_SIZE | WMSZ_RIGHT;
1644 } else {
1645 if (aHorizontal < 0) {
1646 syscommand = SC_SIZE | WMSZ_BOTTOMLEFT;
1647 } else if (aHorizontal == 0) {
1648 syscommand = SC_SIZE | WMSZ_BOTTOM;
1649 } else {
1650 syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT;
1654 // resizing doesn't work if the mouse is already captured
1655 CaptureMouse(PR_FALSE);
1657 // find the top-level window
1658 HWND toplevelWnd = GetTopLevelHWND(mWnd, PR_TRUE);
1660 // tell Windows to start the resize
1661 ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand,
1662 POINTTOPOINTS(aEvent->refPoint));
1664 return NS_OK;
1666 #endif
1667 /**************************************************************
1669 * SECTION: Window Z-order and state.
1671 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1672 * nsIWidget::ConstrainPosition
1674 * Z-order, positioning, restore, minimize, and maximize.
1676 **************************************************************/
1678 // Position the window behind the given window
1679 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1680 nsIWidget *aWidget, PRBool aActivate)
1682 HWND behind = HWND_TOP;
1683 if (aPlacement == eZPlacementBottom)
1684 behind = HWND_BOTTOM;
1685 else if (aPlacement == eZPlacementBelow && aWidget)
1686 behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
1687 UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
1688 if (!aActivate)
1689 flags |= SWP_NOACTIVATE;
1691 if (!CanTakeFocus() && behind == HWND_TOP)
1693 // Can't place the window to top so place it behind the foreground window
1694 // (as long as it is not topmost)
1695 HWND wndAfter = ::GetForegroundWindow();
1696 if (!wndAfter)
1697 behind = HWND_BOTTOM;
1698 else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
1699 behind = wndAfter;
1700 flags |= SWP_NOACTIVATE;
1703 ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
1704 return NS_OK;
1707 // Maximize, minimize or restore the window.
1708 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1709 NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode) {
1711 nsresult rv;
1713 // Let's not try and do anything if we're already in that state.
1714 // (This is needed to prevent problems when calling window.minimize(), which
1715 // calls us directly, and then the OS triggers another call to us.)
1716 if (aMode == mSizeMode)
1717 return NS_OK;
1719 // save the requested state
1720 rv = nsBaseWidget::SetSizeMode(aMode);
1721 if (NS_SUCCEEDED(rv) && mIsVisible) {
1722 int mode;
1724 switch (aMode) {
1725 case nsSizeMode_Fullscreen :
1726 mode = SW_SHOW;
1727 break;
1729 case nsSizeMode_Maximized :
1730 mode = SW_MAXIMIZE;
1731 break;
1733 case nsSizeMode_Minimized :
1734 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1735 // keeps the window active in the tray. So after the window is minimized,
1736 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1737 // we will do some additional processing to get the active window set right.
1738 // If sTrimOnMinimize is set, we let windows handle minimization normally
1739 // using SW_MINIMIZE.
1740 mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED;
1741 break;
1743 default :
1744 mode = SW_RESTORE;
1746 ::ShowWindow(mWnd, mode);
1747 // we dispatch an activate event here to ensure that the right child window
1748 // is focused
1749 if (mode == SW_RESTORE || mode == SW_MAXIMIZE)
1750 DispatchFocusToTopLevelWindow(NS_ACTIVATE);
1752 return rv;
1754 #endif // !defined(WINCE)
1756 // Constrain a potential move to fit onscreen
1757 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop,
1758 PRInt32 *aX, PRInt32 *aY)
1760 if (!mIsTopWidgetWindow) // only a problem for top-level windows
1761 return NS_OK;
1763 PRBool doConstrain = PR_FALSE; // whether we have enough info to do anything
1765 /* get our playing field. use the current screen, or failing that
1766 for any reason, use device caps for the default screen. */
1767 RECT screenRect;
1769 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
1770 if (screenmgr) {
1771 nsCOMPtr<nsIScreen> screen;
1772 PRInt32 left, top, width, height;
1774 // zero size rects confuse the screen manager
1775 width = mBounds.width > 0 ? mBounds.width : 1;
1776 height = mBounds.height > 0 ? mBounds.height : 1;
1777 screenmgr->ScreenForRect(*aX, *aY, width, height,
1778 getter_AddRefs(screen));
1779 if (screen) {
1780 if (mSizeMode != nsSizeMode_Fullscreen) {
1781 // For normalized windows, use the desktop work area.
1782 screen->GetAvailRect(&left, &top, &width, &height);
1783 } else {
1784 // For full screen windows, use the desktop.
1785 screen->GetRect(&left, &top, &width, &height);
1787 screenRect.left = left;
1788 screenRect.right = left+width;
1789 screenRect.top = top;
1790 screenRect.bottom = top+height;
1791 doConstrain = PR_TRUE;
1793 } else {
1794 if (mWnd) {
1795 HDC dc = ::GetDC(mWnd);
1796 if (dc) {
1797 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1798 if (mSizeMode != nsSizeMode_Fullscreen) {
1799 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
1800 } else {
1801 screenRect.left = screenRect.top = 0;
1802 screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN);
1803 screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
1805 doConstrain = PR_TRUE;
1807 ::ReleaseDC(mWnd, dc);
1812 if (aAllowSlop) {
1813 if (*aX < screenRect.left - mBounds.width + kWindowPositionSlop)
1814 *aX = screenRect.left - mBounds.width + kWindowPositionSlop;
1815 else if (*aX >= screenRect.right - kWindowPositionSlop)
1816 *aX = screenRect.right - kWindowPositionSlop;
1818 if (*aY < screenRect.top - mBounds.height + kWindowPositionSlop)
1819 *aY = screenRect.top - mBounds.height + kWindowPositionSlop;
1820 else if (*aY >= screenRect.bottom - kWindowPositionSlop)
1821 *aY = screenRect.bottom - kWindowPositionSlop;
1823 } else {
1825 if (*aX < screenRect.left)
1826 *aX = screenRect.left;
1827 else if (*aX >= screenRect.right - mBounds.width)
1828 *aX = screenRect.right - mBounds.width;
1830 if (*aY < screenRect.top)
1831 *aY = screenRect.top;
1832 else if (*aY >= screenRect.bottom - mBounds.height)
1833 *aY = screenRect.bottom - mBounds.height;
1836 return NS_OK;
1839 /**************************************************************
1841 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1843 * Enabling and disabling the widget.
1845 **************************************************************/
1847 // Enable/disable this component
1848 NS_METHOD nsWindow::Enable(PRBool bState)
1850 if (mWnd) {
1851 ::EnableWindow(mWnd, bState);
1853 return NS_OK;
1856 // Return the current enable state
1857 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
1859 NS_ENSURE_ARG_POINTER(aState);
1861 #ifndef WINCE
1862 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT)));
1863 #else
1864 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(mWnd));
1865 #endif
1867 return NS_OK;
1871 /**************************************************************
1873 * SECTION: nsIWidget::SetFocus
1875 * Give the focus to this widget.
1877 **************************************************************/
1879 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
1881 if (mWnd) {
1882 #ifdef WINSTATE_DEBUG_OUTPUT
1883 if (mWnd == GetTopLevelHWND(mWnd))
1884 printf("*** SetFocus: [ top] raise=%d\n", aRaise);
1885 else
1886 printf("*** SetFocus: [child] raise=%d\n", aRaise);
1887 #endif
1888 // Uniconify, if necessary
1889 HWND toplevelWnd = GetTopLevelHWND(mWnd);
1890 if (aRaise && ::IsIconic(toplevelWnd)) {
1891 ::ShowWindow(toplevelWnd, SW_RESTORE);
1893 ::SetFocus(mWnd);
1895 return NS_OK;
1899 /**************************************************************
1901 * SECTION: Bounds
1903 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1904 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1906 * Bound calculations.
1908 **************************************************************/
1910 // Return the window's full dimensions in screen coordinates.
1911 // If the window has a parent, converts the origin to an offset
1912 // of the parent's screen origin.
1913 NS_METHOD nsWindow::GetBounds(nsIntRect &aRect)
1915 if (mWnd) {
1916 RECT r;
1917 VERIFY(::GetWindowRect(mWnd, &r));
1919 // assign size
1920 aRect.width = r.right - r.left;
1921 aRect.height = r.bottom - r.top;
1923 // chrome on parent:
1924 // ___ 5,5 (chrome start)
1925 // | ____ 10,10 (client start)
1926 // | | ____ 20,20 (child start)
1927 // | | |
1928 // 20,20 - 5,5 = 15,15 (??)
1929 // minus GetClientOffset:
1930 // 15,15 - 5,5 = 10,10
1932 // no chrome on parent:
1933 // ______ 10,10 (win start)
1934 // | ____ 20,20 (child start)
1935 // | |
1936 // 20,20 - 10,10 = 10,10
1938 // walking the chain:
1939 // ___ 5,5 (chrome start)
1940 // | ___ 10,10 (client start)
1941 // | | ___ 20,20 (child start)
1942 // | | | __ 30,30 (child start)
1943 // | | | |
1944 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1945 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1946 // minus GetClientOffset:
1947 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1949 // convert coordinates if parent exists
1950 HWND parent = ::GetParent(mWnd);
1951 if (parent) {
1952 RECT pr;
1953 VERIFY(::GetWindowRect(parent, &pr));
1954 r.left -= pr.left;
1955 r.top -= pr.top;
1956 // adjust for chrome
1957 nsWindow* pWidget = static_cast<nsWindow*>(GetParent());
1958 if (pWidget && pWidget->IsTopLevelWidget()) {
1959 nsIntPoint clientOffset = pWidget->GetClientOffset();
1960 r.left -= clientOffset.x;
1961 r.top -= clientOffset.y;
1964 aRect.x = r.left;
1965 aRect.y = r.top;
1966 } else {
1967 aRect = mBounds;
1970 return NS_OK;
1973 // Get this component dimension
1974 NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect)
1976 if (mWnd) {
1977 RECT r;
1978 VERIFY(::GetClientRect(mWnd, &r));
1980 // assign size
1981 aRect.x = 0;
1982 aRect.y = 0;
1983 aRect.width = r.right - r.left;
1984 aRect.height = r.bottom - r.top;
1986 } else {
1987 aRect.SetRect(0,0,0,0);
1989 return NS_OK;
1992 // Like GetBounds, but don't offset by the parent
1993 NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect)
1995 if (mWnd) {
1996 RECT r;
1997 VERIFY(::GetWindowRect(mWnd, &r));
1999 aRect.width = r.right - r.left;
2000 aRect.height = r.bottom - r.top;
2001 aRect.x = r.left;
2002 aRect.y = r.top;
2003 } else
2004 aRect = mBounds;
2006 return NS_OK;
2009 // return the x,y offset of the client area from the origin
2010 // of the window. If the window is borderless returns (0,0).
2011 nsIntPoint nsWindow::GetClientOffset()
2013 if (!mWnd) {
2014 return nsIntPoint(0, 0);
2017 RECT r1;
2018 GetWindowRect(mWnd, &r1);
2019 nsIntPoint pt = WidgetToScreenOffset();
2020 return nsIntPoint(pt.x - r1.left, pt.y - r1.top);
2023 void
2024 nsWindow::SetDrawsInTitlebar(PRBool aState)
2026 nsWindow * window = GetTopLevelWindow(PR_TRUE);
2027 if (window && window != this) {
2028 return window->SetDrawsInTitlebar(aState);
2031 if (aState) {
2032 // left, top, right, bottom for nsIntMargin
2033 nsIntMargin margins(-1, 0, -1, -1);
2034 SetNonClientMargins(margins);
2036 else {
2037 nsIntMargin margins(-1, -1, -1, -1);
2038 SetNonClientMargins(margins);
2042 NS_IMETHODIMP
2043 nsWindow::GetNonClientMargins(nsIntMargin &margins)
2045 nsWindow * window = GetTopLevelWindow(PR_TRUE);
2046 if (window && window != this) {
2047 return window->GetNonClientMargins(margins);
2050 if (mCustomNonClient) {
2051 margins = mNonClientMargins;
2052 return NS_OK;
2055 margins.top = GetSystemMetrics(SM_CYCAPTION);
2056 margins.bottom = GetSystemMetrics(SM_CYFRAME);
2057 margins.top += margins.bottom;
2058 margins.left = margins.right = GetSystemMetrics(SM_CYFRAME);
2060 return NS_OK;
2063 void
2064 nsWindow::ResetLayout()
2066 // This will trigger a frame changed event, triggering
2067 // nc calc size and a sizemode gecko event.
2068 SetWindowPos(mWnd, 0, 0, 0, 0, 0,
2069 SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|
2070 SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
2072 // If hidden, just send the frame changed event for now.
2073 if (!mIsVisible)
2074 return;
2076 // Send a gecko size event to trigger reflow.
2077 RECT clientRc = {0};
2078 GetClientRect(mWnd, &clientRc);
2079 nsIntRect evRect(nsWindowGfx::ToIntRect(clientRc));
2080 OnResize(evRect);
2082 // Invalidate and update
2083 Invalidate(PR_FALSE);
2086 // Internally track the caption status via a window property. Required
2087 // due to our internal handling of WM_NCACTIVATE when custom client
2088 // margins are set.
2089 static const PRUnichar kManageWindowInfoProperty[] = L"ManageWindowInfoProperty";
2090 typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi);
2091 static GetWindowInfoPtr sGetWindowInfoPtrStub = NULL;
2093 BOOL WINAPI
2094 GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi)
2096 if (!sGetWindowInfoPtrStub) {
2097 NS_ASSERTION(FALSE, "Something is horribly wrong in GetWindowInfoHook!");
2098 return FALSE;
2100 int windowStatus =
2101 reinterpret_cast<LONG_PTR>(GetPropW(hWnd, kManageWindowInfoProperty));
2102 // No property set, return the default data.
2103 if (!windowStatus)
2104 return sGetWindowInfoPtrStub(hWnd, pwi);
2105 // Call GetWindowInfo and update dwWindowStatus with our
2106 // internally tracked value.
2107 BOOL result = sGetWindowInfoPtrStub(hWnd, pwi);
2108 if (result && pwi)
2109 pwi->dwWindowStatus = (windowStatus == 1 ? 0 : WS_ACTIVECAPTION);
2110 return result;
2113 void
2114 nsWindow::UpdateGetWindowInfoCaptionStatus(PRBool aActiveCaption)
2116 if (!mWnd)
2117 return;
2119 if (!sGetWindowInfoPtrStub) {
2120 sUser32Intercept.Init("user32.dll");
2121 if (!sUser32Intercept.AddHook("GetWindowInfo", (void*)GetWindowInfoHook,
2122 (void**) &sGetWindowInfoPtrStub))
2123 return;
2125 // Update our internally tracked caption status
2126 SetPropW(mWnd, kManageWindowInfoProperty,
2127 reinterpret_cast<HANDLE>(static_cast<int>(aActiveCaption) + 1));
2130 // Called when the window layout changes: full screen mode transitions,
2131 // theme changes, and composition changes. Calculates the new non-client
2132 // margins and fires off a frame changed event, which triggers an nc calc
2133 // size windows event, kicking the changes in.
2134 PRBool
2135 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode, PRBool aReflowWindow)
2137 if (!mCustomNonClient)
2138 return PR_FALSE;
2140 mNonClientOffset.top = mNonClientOffset.bottom =
2141 mNonClientOffset.left = mNonClientOffset.right = 0;
2143 if (aSizeMode == -1)
2144 aSizeMode = mSizeMode;
2146 if (aSizeMode == nsSizeMode_Minimized ||
2147 aSizeMode == nsSizeMode_Fullscreen) {
2148 mCaptionHeight = mVertResizeMargin = mHorResizeMargin = 0;
2149 return PR_TRUE;
2152 // Note, for maximized windows, we need to continue to offset the client by
2153 // thick frame margins of a normal window, since windows expects this
2154 // in it's DwmDefWndProc hit testing.
2155 mCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
2156 mHorResizeMargin = GetSystemMetrics(SM_CXFRAME);
2157 mVertResizeMargin = GetSystemMetrics(SM_CYFRAME);
2159 mCaptionHeight += mVertResizeMargin;
2161 // If a margin value is 0, set the offset to the default size of the frame.
2162 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2163 // so that the frame size is equal to the margin value.
2164 if (!mNonClientMargins.top)
2165 mNonClientOffset.top = mCaptionHeight;
2166 else if (mNonClientMargins.top > 0)
2167 mNonClientOffset.top = mCaptionHeight - mNonClientMargins.top;
2169 if (!mNonClientMargins.left)
2170 mNonClientOffset.left = mHorResizeMargin;
2171 else if (mNonClientMargins.left > 0)
2172 mNonClientOffset.left = mHorResizeMargin - mNonClientMargins.left;
2174 if (!mNonClientMargins.right)
2175 mNonClientOffset.right = mHorResizeMargin;
2176 else if (mNonClientMargins.right > 0)
2177 mNonClientOffset.right = mHorResizeMargin - mNonClientMargins.right;
2179 if (!mNonClientMargins.bottom)
2180 mNonClientOffset.bottom = mVertResizeMargin;
2181 else if (mNonClientMargins.bottom > 0)
2182 mNonClientOffset.bottom = mVertResizeMargin - mNonClientMargins.bottom;
2184 #ifndef WINCE
2185 if (aSizeMode == nsSizeMode_Maximized) {
2186 // Address an issue with auto-hide taskbars which fall behind the window.
2187 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2188 // the taskbar works properly.
2189 MONITORINFO info = {sizeof(MONITORINFO)};
2190 if (::GetMonitorInfo(::MonitorFromWindow(mWnd, MONITOR_DEFAULTTOPRIMARY),
2191 &info)) {
2192 RECT r;
2193 if (::GetWindowRect(mWnd, &r)) {
2194 // Adjust window rect to account for non-client margins.
2195 r.top += mVertResizeMargin - mNonClientOffset.top;
2196 r.left += mHorResizeMargin - mNonClientOffset.left;
2197 r.bottom -= mVertResizeMargin - mNonClientOffset.bottom;
2198 r.right -= mHorResizeMargin - mNonClientOffset.right;
2199 // Leave the 1 pixel margin if the window covers the monitor.
2200 if (r.top <= info.rcMonitor.top &&
2201 r.left <= info.rcMonitor.left &&
2202 r.right >= info.rcMonitor.right &&
2203 r.bottom >= info.rcMonitor.bottom)
2204 mNonClientOffset.bottom -= r.bottom - info.rcMonitor.bottom + 1;
2208 #endif
2210 if (aReflowWindow) {
2211 // Force a reflow of content based on the new client
2212 // dimensions.
2213 ResetLayout();
2216 return PR_TRUE;
2219 NS_IMETHODIMP
2220 nsWindow::SetNonClientMargins(nsIntMargin &margins)
2222 if (!mIsTopWidgetWindow ||
2223 mBorderStyle & eBorderStyle_none ||
2224 mHideChrome)
2225 return NS_ERROR_INVALID_ARG;
2227 // Request for a reset
2228 if (margins.top == -1 && margins.left == -1 &&
2229 margins.right == -1 && margins.bottom == -1) {
2230 mCustomNonClient = PR_FALSE;
2231 mNonClientMargins = margins;
2232 RemovePropW(mWnd, kManageWindowInfoProperty);
2233 // Force a reflow of content based on the new client
2234 // dimensions.
2235 ResetLayout();
2236 return NS_OK;
2239 if (margins.top < -1 || margins.bottom < -1 ||
2240 margins.left < -1 || margins.right < -1)
2241 return NS_ERROR_INVALID_ARG;
2243 mNonClientMargins = margins;
2244 mCustomNonClient = PR_TRUE;
2245 if (!UpdateNonClientMargins()) {
2246 NS_WARNING("UpdateNonClientMargins failed!");
2247 return PR_FALSE;
2250 return NS_OK;
2253 void
2254 nsWindow::InvalidateNonClientRegion()
2256 // +-+-----------------------+-+
2257 // | | app non-client chrome | |
2258 // | +-----------------------+ |
2259 // | | app client chrome | | }
2260 // | +-----------------------+ | }
2261 // | | app content | | } area we don't want to invalidate
2262 // | +-----------------------+ | }
2263 // | | app client chrome | | }
2264 // | +-----------------------+ |
2265 // +---------------------------+ <
2266 // ^ ^ windows non-client chrome
2267 // client area = app *
2268 RECT rect;
2269 GetWindowRect(mWnd, &rect);
2270 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2271 HRGN winRgn = CreateRectRgnIndirect(&rect);
2273 // Subtract app client chrome and app content leaving
2274 // windows non-client chrome and app non-client chrome
2275 // in winRgn.
2276 GetWindowRect(mWnd, &rect);
2277 rect.top += mCaptionHeight;
2278 rect.right -= mHorResizeMargin;
2279 rect.bottom -= mHorResizeMargin;
2280 rect.left += mVertResizeMargin;
2281 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2282 HRGN clientRgn = CreateRectRgnIndirect(&rect);
2283 CombineRgn(winRgn, winRgn, clientRgn, RGN_DIFF);
2284 DeleteObject(clientRgn);
2286 // triggers ncpaint and paint events for the two areas
2287 RedrawWindow(mWnd, NULL, winRgn, RDW_FRAME|RDW_INVALIDATE);
2288 DeleteObject(winRgn);
2291 HRGN
2292 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion)
2294 RECT rect;
2295 HRGN rgn = NULL;
2296 if (aRegion == (HRGN)1) { // undocumented value indicating a full refresh
2297 GetWindowRect(mWnd, &rect);
2298 rgn = CreateRectRgnIndirect(&rect);
2299 } else {
2300 rgn = aRegion;
2302 GetClientRect(mWnd, &rect);
2303 MapWindowPoints(mWnd, NULL, (LPPOINT)&rect, 2);
2304 HRGN nonClientRgn = CreateRectRgnIndirect(&rect);
2305 CombineRgn(rgn, rgn, nonClientRgn, RGN_DIFF);
2306 DeleteObject(nonClientRgn);
2307 return rgn;
2310 /**************************************************************
2312 * SECTION: nsIWidget::SetBackgroundColor
2314 * Sets the window background paint color.
2316 **************************************************************/
2318 NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
2320 nsBaseWidget::SetBackgroundColor(aColor);
2322 if (mBrush)
2323 ::DeleteObject(mBrush);
2325 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
2326 #ifndef WINCE
2327 if (mWnd != NULL) {
2328 ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush);
2330 #endif
2331 return NS_OK;
2334 /**************************************************************
2336 * SECTION: nsIWidget::SetCursor
2338 * SetCursor and related utilities for manging cursor state.
2340 **************************************************************/
2342 // Set this component cursor
2343 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
2345 // Only change cursor if it's changing
2347 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2348 //XXX If we want this optimization we need a better way to do it.
2349 //if (aCursor != mCursor) {
2350 HCURSOR newCursor = NULL;
2352 switch (aCursor) {
2353 case eCursor_select:
2354 newCursor = ::LoadCursor(NULL, IDC_IBEAM);
2355 break;
2357 case eCursor_wait:
2358 newCursor = ::LoadCursor(NULL, IDC_WAIT);
2359 break;
2361 case eCursor_hyperlink:
2363 newCursor = ::LoadCursor(NULL, IDC_HAND);
2364 break;
2367 case eCursor_standard:
2368 newCursor = ::LoadCursor(NULL, IDC_ARROW);
2369 break;
2371 case eCursor_n_resize:
2372 case eCursor_s_resize:
2373 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2374 break;
2376 case eCursor_w_resize:
2377 case eCursor_e_resize:
2378 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2379 break;
2381 case eCursor_nw_resize:
2382 case eCursor_se_resize:
2383 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2384 break;
2386 case eCursor_ne_resize:
2387 case eCursor_sw_resize:
2388 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2389 break;
2391 case eCursor_crosshair:
2392 newCursor = ::LoadCursor(NULL, IDC_CROSS);
2393 break;
2395 case eCursor_move:
2396 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2397 break;
2399 case eCursor_help:
2400 newCursor = ::LoadCursor(NULL, IDC_HELP);
2401 break;
2403 case eCursor_copy: // CSS3
2404 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
2405 break;
2407 case eCursor_alias:
2408 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
2409 break;
2411 case eCursor_cell:
2412 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
2413 break;
2415 case eCursor_grab:
2416 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
2417 break;
2419 case eCursor_grabbing:
2420 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
2421 break;
2423 case eCursor_spinning:
2424 newCursor = ::LoadCursor(NULL, IDC_APPSTARTING);
2425 break;
2427 case eCursor_context_menu:
2428 // XXX this CSS3 cursor needs to be implemented
2429 break;
2431 case eCursor_zoom_in:
2432 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
2433 break;
2435 case eCursor_zoom_out:
2436 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
2437 break;
2439 case eCursor_not_allowed:
2440 case eCursor_no_drop:
2441 newCursor = ::LoadCursor(NULL, IDC_NO);
2442 break;
2444 case eCursor_col_resize:
2445 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
2446 break;
2448 case eCursor_row_resize:
2449 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
2450 break;
2452 case eCursor_vertical_text:
2453 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT));
2454 break;
2456 case eCursor_all_scroll:
2457 // XXX not 100% appropriate perhaps
2458 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2459 break;
2461 case eCursor_nesw_resize:
2462 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2463 break;
2465 case eCursor_nwse_resize:
2466 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2467 break;
2469 case eCursor_ns_resize:
2470 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2471 break;
2473 case eCursor_ew_resize:
2474 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2475 break;
2477 case eCursor_none:
2478 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
2479 break;
2481 default:
2482 NS_ERROR("Invalid cursor type");
2483 break;
2486 if (NULL != newCursor) {
2487 mCursor = aCursor;
2488 HCURSOR oldCursor = ::SetCursor(newCursor);
2490 if (sHCursor == oldCursor) {
2491 NS_IF_RELEASE(sCursorImgContainer);
2492 if (sHCursor != NULL)
2493 ::DestroyIcon(sHCursor);
2494 sHCursor = NULL;
2498 return NS_OK;
2501 // Setting the actual cursor
2502 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
2503 PRUint32 aHotspotX, PRUint32 aHotspotY)
2505 if (sCursorImgContainer == aCursor && sHCursor) {
2506 ::SetCursor(sHCursor);
2507 return NS_OK;
2510 PRInt32 width;
2511 PRInt32 height;
2513 nsresult rv;
2514 rv = aCursor->GetWidth(&width);
2515 NS_ENSURE_SUCCESS(rv, rv);
2516 rv = aCursor->GetHeight(&height);
2517 NS_ENSURE_SUCCESS(rv, rv);
2519 // Reject cursors greater than 128 pixels in either direction, to prevent
2520 // spoofing.
2521 // XXX ideally we should rescale. Also, we could modify the API to
2522 // allow trusted content to set larger cursors.
2523 if (width > 128 || height > 128)
2524 return NS_ERROR_NOT_AVAILABLE;
2526 HCURSOR cursor;
2527 rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
2528 NS_ENSURE_SUCCESS(rv, rv);
2530 mCursor = nsCursor(-1);
2531 ::SetCursor(cursor);
2533 NS_IF_RELEASE(sCursorImgContainer);
2534 sCursorImgContainer = aCursor;
2535 NS_ADDREF(sCursorImgContainer);
2537 if (sHCursor != NULL)
2538 ::DestroyIcon(sHCursor);
2539 sHCursor = cursor;
2541 return NS_OK;
2544 /**************************************************************
2546 * SECTION: nsIWidget::Get/SetTransparencyMode
2548 * Manage the transparency mode of the top-level window
2549 * containing this widget.
2551 **************************************************************/
2553 #ifdef MOZ_XUL
2554 nsTransparencyMode nsWindow::GetTransparencyMode()
2556 return GetTopLevelWindow(PR_TRUE)->GetWindowTranslucencyInner();
2559 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
2561 GetTopLevelWindow(PR_TRUE)->SetWindowTranslucencyInner(aMode);
2564 static const nsIntRegion
2565 RegionFromArray(const nsTArray<nsIntRect>& aRects)
2567 nsIntRegion region;
2568 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
2569 region.Or(region, aRects[i]);
2571 return region;
2574 void nsWindow::UpdateTransparentRegion(const nsIntRegion &aTransparentRegion)
2576 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2577 if (!HasGlass() || GetParent())
2578 return;
2580 nsIntRect clientBounds;
2581 GetClientBounds(clientBounds);
2583 // calculate the known fully opaque region by subtracting the transparent
2584 // areas from client bounds. We'll use this to calculate our new glass
2585 // bounds.
2586 nsIntRegion opaqueRegion;
2587 opaqueRegion.Sub(clientBounds, aTransparentRegion);
2589 // If there is no opaque region or hidechrome=true, set margins
2590 // to support a full sheet of glass. Comments in MSDN indicate
2591 // all values must be set to -1 to get a full sheet of glass.
2592 MARGINS margins = { -1, -1, -1, -1 };
2593 bool visiblePlugin = false;
2594 if (!opaqueRegion.IsEmpty() && !mHideChrome) {
2595 nsIntRect pluginBounds;
2596 for (nsIWidget* child = GetFirstChild(); child; child = child->GetNextSibling()) {
2597 nsWindowType type;
2598 child->GetWindowType(type);
2599 if (type == eWindowType_plugin) {
2600 // Collect the bounds of all plugins for GetLargestRectangle.
2601 nsIntRect childBounds;
2602 child->GetBounds(childBounds);
2603 pluginBounds.UnionRect(pluginBounds, childBounds);
2604 // Detect if any region of a plugin is visible.
2605 nsTArray<nsIntRect> currentRects;
2606 child->GetWindowClipRegion(&currentRects);
2607 nsIntRegion currentClipRegion = RegionFromArray(currentRects);
2608 nsIntRect bounds = currentClipRegion.GetBounds();
2609 if (!bounds.IsEmpty()) {
2610 visiblePlugin = true;
2615 // Find the largest rectangle and use that to calculate the inset. Our top
2616 // priority is to include the bounds of all plugins.
2617 // Also don't let MIN_OPAQUE_RECT_HEIGHT_FOR_GLASS_MARGINS override content
2618 // that contains a visible plugin since glass over plugins looks bad.
2619 nsIntRect largest = opaqueRegion.GetLargestRectangle(pluginBounds);
2620 if (visiblePlugin ||
2621 (largest.x <= MAX_HORIZONTAL_GLASS_MARGIN &&
2622 clientBounds.width - largest.XMost() <= MAX_HORIZONTAL_GLASS_MARGIN &&
2623 largest.height >= MIN_OPAQUE_RECT_HEIGHT_FOR_GLASS_MARGINS)) {
2624 margins.cxLeftWidth = largest.x;
2625 margins.cxRightWidth = clientBounds.width - largest.XMost();
2626 margins.cyBottomHeight = clientBounds.height - largest.YMost();
2628 if (mCustomNonClient) {
2629 // The minimum glass height must be the caption buttons height,
2630 // otherwise the buttons are drawn incorrectly.
2631 largest.y = PR_MAX(largest.y,
2632 nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cy);
2634 margins.cyTopHeight = largest.y;
2638 // Only update glass area if there are changes
2639 if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) {
2640 mGlassMargins = margins;
2641 UpdateGlass();
2643 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2646 void nsWindow::UpdateGlass()
2648 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2649 MARGINS margins = mGlassMargins;
2651 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2652 // rendered based on the window style.
2653 // DWMNCRP_ENABLED - The non-client area rendering is
2654 // enabled; the window style is ignored.
2655 DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE;
2656 switch (mTransparencyMode) {
2657 case eTransparencyBorderlessGlass:
2658 // Only adjust if there is some opaque rectangle
2659 if (margins.cxLeftWidth >= 0) {
2660 margins.cxLeftWidth += kGlassMarginAdjustment;
2661 margins.cyTopHeight += kGlassMarginAdjustment;
2662 margins.cxRightWidth += kGlassMarginAdjustment;
2663 margins.cyBottomHeight += kGlassMarginAdjustment;
2665 // Fall through
2666 case eTransparencyGlass:
2667 policy = DWMNCRP_ENABLED;
2668 break;
2671 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
2672 ("glass margins: left:%d top:%d right:%d bottom:%d\n",
2673 margins.cxLeftWidth, margins.cyTopHeight,
2674 margins.cxRightWidth, margins.cyBottomHeight));
2676 // Extends the window frame behind the client area
2677 if(nsUXThemeData::CheckForCompositor()) {
2678 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(mWnd, &margins);
2679 nsUXThemeData::dwmSetWindowAttributePtr(mWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy);
2681 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2683 #endif
2685 /**************************************************************
2687 * SECTION: nsIWidget::HideWindowChrome
2689 * Show or hide window chrome.
2691 **************************************************************/
2693 NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide)
2695 HWND hwnd = GetTopLevelHWND(mWnd, PR_TRUE);
2696 if (!GetNSWindowPtr(hwnd))
2698 NS_WARNING("Trying to hide window decorations in an embedded context");
2699 return NS_ERROR_FAILURE;
2702 if (mHideChrome == aShouldHide)
2703 return NS_OK;
2705 DWORD_PTR style, exStyle;
2706 mHideChrome = aShouldHide;
2707 if (aShouldHide) {
2708 DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2709 DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2711 style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
2712 exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
2713 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
2715 mOldStyle = tempStyle;
2716 mOldExStyle = tempExStyle;
2718 else {
2719 if (!mOldStyle || !mOldExStyle) {
2720 mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2721 mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2724 style = mOldStyle;
2725 exStyle = mOldExStyle;
2728 VERIFY_WINDOW_STYLE(style);
2729 ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
2730 ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
2732 return NS_OK;
2735 /**************************************************************
2737 * SECTION: nsIWidget::Invalidate
2739 * Invalidate an area of the client for painting.
2741 **************************************************************/
2743 // Invalidate this component visible area
2744 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
2746 if (mWnd)
2748 #ifdef WIDGET_DEBUG_OUTPUT
2749 debug_DumpInvalidate(stdout,
2750 this,
2751 nsnull,
2752 aIsSynchronous,
2753 nsCAutoString("noname"),
2754 (PRInt32) mWnd);
2755 #endif // WIDGET_DEBUG_OUTPUT
2757 VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
2759 if (aIsSynchronous) {
2760 VERIFY(::UpdateWindow(mWnd));
2763 return NS_OK;
2766 // Invalidate this component visible area
2767 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, PRBool aIsSynchronous)
2769 if (mWnd)
2771 #ifdef WIDGET_DEBUG_OUTPUT
2772 debug_DumpInvalidate(stdout,
2773 this,
2774 &aRect,
2775 aIsSynchronous,
2776 nsCAutoString("noname"),
2777 (PRInt32) mWnd);
2778 #endif // WIDGET_DEBUG_OUTPUT
2780 RECT rect;
2782 rect.left = aRect.x;
2783 rect.top = aRect.y;
2784 rect.right = aRect.x + aRect.width;
2785 rect.bottom = aRect.y + aRect.height;
2787 VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
2789 if (aIsSynchronous) {
2790 VERIFY(::UpdateWindow(mWnd));
2793 return NS_OK;
2796 NS_IMETHODIMP
2797 nsWindow::MakeFullScreen(PRBool aFullScreen)
2799 #if WINCE_WINDOWS_MOBILE
2800 RECT rc;
2801 if (aFullScreen) {
2802 SetForegroundWindow(mWnd);
2803 if (nsWindowCE::sMenuBarShown) {
2804 SIPINFO sipInfo;
2805 memset(&sipInfo, 0, sizeof(SIPINFO));
2806 sipInfo.cbSize = sizeof(SIPINFO);
2807 if (SipGetInfo(&sipInfo))
2808 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2809 sipInfo.rcVisibleDesktop.bottom);
2810 else
2811 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2812 GetSystemMetrics(SM_CYSCREEN));
2813 RECT menuBarRect;
2814 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle, &menuBarRect) &&
2815 menuBarRect.top < rc.bottom)
2816 rc.bottom = menuBarRect.top;
2817 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_SHOWSIPBUTTON);
2818 } else {
2820 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);
2821 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2824 else {
2825 SHFullScreen(mWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
2826 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
2829 if (aFullScreen)
2830 mSizeMode = nsSizeMode_Fullscreen;
2832 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2833 HideWindowChrome(aFullScreen);
2834 Resize(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PR_TRUE);
2836 return NS_OK;
2838 #else
2840 mFullscreenMode = aFullScreen;
2841 if (aFullScreen) {
2842 if (mSizeMode == nsSizeMode_Fullscreen)
2843 return NS_OK;
2844 mOldSizeMode = mSizeMode;
2845 SetSizeMode(nsSizeMode_Fullscreen);
2846 } else {
2847 SetSizeMode(mOldSizeMode);
2850 UpdateNonClientMargins();
2852 // Prevent window updates during the transition.
2853 DWORD style;
2854 if (nsUXThemeData::CheckForCompositor()) {
2855 style = GetWindowLong(mWnd, GWL_STYLE);
2856 SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
2859 // Will call hide chrome, reposition window. Note this will
2860 // also cache dimensions for restoration, so it should only
2861 // be called once per fullscreen request.
2862 nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen);
2864 if (nsUXThemeData::CheckForCompositor()) {
2865 style = GetWindowLong(mWnd, GWL_STYLE);
2866 SetWindowLong(mWnd, GWL_STYLE, style | WS_VISIBLE);
2867 Invalidate(PR_FALSE);
2870 // Let the dom know via web shell window
2871 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
2872 event.mSizeMode = mSizeMode;
2873 InitEvent(event);
2874 DispatchWindowEvent(&event);
2876 return rv;
2877 #endif
2880 /**************************************************************
2882 * SECTION: nsIWidget::Update
2884 * Force a synchronous repaint of the window.
2886 **************************************************************/
2888 NS_IMETHODIMP nsWindow::Update()
2890 nsresult rv = NS_OK;
2892 // updates can come through for windows no longer holding an mWnd during
2893 // deletes triggered by JavaScript in buttons with mouse feedback
2894 if (mWnd)
2895 VERIFY(::UpdateWindow(mWnd));
2897 return rv;
2900 /**************************************************************
2902 * SECTION: Native data storage
2904 * nsIWidget::GetNativeData
2905 * nsIWidget::FreeNativeData
2907 * Set or clear native data based on a constant.
2909 **************************************************************/
2911 // Return some native data according to aDataType
2912 void* nsWindow::GetNativeData(PRUint32 aDataType)
2914 nsAutoString className;
2915 switch (aDataType) {
2916 case NS_NATIVE_TMP_WINDOW:
2917 GetWindowClass(className);
2918 return (void*)::CreateWindowExW(mIsRTL ? WS_EX_LAYOUTRTL : 0,
2919 className.get(),
2920 L"",
2921 WS_CHILD,
2922 CW_USEDEFAULT,
2923 CW_USEDEFAULT,
2924 CW_USEDEFAULT,
2925 CW_USEDEFAULT,
2926 mWnd,
2927 NULL,
2928 nsToolkit::mDllInstance,
2929 NULL);
2930 case NS_NATIVE_PLUGIN_PORT:
2931 case NS_NATIVE_WIDGET:
2932 case NS_NATIVE_WINDOW:
2933 return (void*)mWnd;
2934 case NS_NATIVE_GRAPHIC:
2935 // XXX: This is sleezy!! Remember to Release the DC after using it!
2936 #ifdef MOZ_XUL
2937 return (void*)(eTransparencyTransparent == mTransparencyMode) ?
2938 mMemoryDC : ::GetDC(mWnd);
2939 #else
2940 return (void*)::GetDC(mWnd);
2941 #endif
2943 #ifdef NS_ENABLE_TSF
2944 case NS_NATIVE_TSF_THREAD_MGR:
2945 return nsTextStore::GetThreadMgr();
2946 case NS_NATIVE_TSF_CATEGORY_MGR:
2947 return nsTextStore::GetCategoryMgr();
2948 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
2949 return nsTextStore::GetDisplayAttrMgr();
2950 #endif //NS_ENABLE_TSF
2952 default:
2953 break;
2956 return NULL;
2959 // Free some native data according to aDataType
2960 void nsWindow::FreeNativeData(void * data, PRUint32 aDataType)
2962 switch (aDataType)
2964 case NS_NATIVE_GRAPHIC:
2965 #ifdef MOZ_XUL
2966 if (eTransparencyTransparent != mTransparencyMode)
2967 ::ReleaseDC(mWnd, (HDC)data);
2968 #else
2969 ::ReleaseDC(mWnd, (HDC)data);
2970 #endif
2971 break;
2972 case NS_NATIVE_WIDGET:
2973 case NS_NATIVE_WINDOW:
2974 case NS_NATIVE_PLUGIN_PORT:
2975 break;
2976 default:
2977 break;
2981 /**************************************************************
2983 * SECTION: nsIWidget::SetTitle
2985 * Set the main windows title text.
2987 **************************************************************/
2989 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
2991 const nsString& strTitle = PromiseFlatString(aTitle);
2992 ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get());
2993 return NS_OK;
2996 /**************************************************************
2998 * SECTION: nsIWidget::SetIcon
3000 * Set the main windows icon.
3002 **************************************************************/
3004 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec)
3006 #ifndef WINCE
3007 // Assume the given string is a local identifier for an icon file.
3009 nsCOMPtr<nsILocalFile> iconFile;
3010 ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
3011 getter_AddRefs(iconFile));
3012 if (!iconFile)
3013 return NS_OK; // not an error if icon is not found
3015 nsAutoString iconPath;
3016 iconFile->GetPath(iconPath);
3018 // XXX this should use MZLU (see bug 239279)
3020 ::SetLastError(0);
3022 HICON bigIcon = (HICON)::LoadImageW(NULL,
3023 (LPCWSTR)iconPath.get(),
3024 IMAGE_ICON,
3025 ::GetSystemMetrics(SM_CXICON),
3026 ::GetSystemMetrics(SM_CYICON),
3027 LR_LOADFROMFILE );
3028 HICON smallIcon = (HICON)::LoadImageW(NULL,
3029 (LPCWSTR)iconPath.get(),
3030 IMAGE_ICON,
3031 ::GetSystemMetrics(SM_CXSMICON),
3032 ::GetSystemMetrics(SM_CYSMICON),
3033 LR_LOADFROMFILE );
3035 if (bigIcon) {
3036 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon);
3037 if (icon)
3038 ::DestroyIcon(icon);
3040 #ifdef DEBUG_SetIcon
3041 else {
3042 NS_LossyConvertUTF16toASCII cPath(iconPath);
3043 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
3045 #endif
3046 if (smallIcon) {
3047 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon);
3048 if (icon)
3049 ::DestroyIcon(icon);
3051 #ifdef DEBUG_SetIcon
3052 else {
3053 NS_LossyConvertUTF16toASCII cPath(iconPath);
3054 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
3056 #endif
3057 #endif // WINCE
3058 return NS_OK;
3061 /**************************************************************
3063 * SECTION: nsIWidget::WidgetToScreenOffset
3065 * Return this widget's origin in screen coordinates.
3067 **************************************************************/
3069 nsIntPoint nsWindow::WidgetToScreenOffset()
3071 POINT point;
3072 point.x = 0;
3073 point.y = 0;
3074 ::ClientToScreen(mWnd, &point);
3075 return nsIntPoint(point.x, point.y);
3078 nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize)
3080 if (!IsPopupWithTitleBar())
3081 return aClientSize;
3083 // just use (200, 200) as the position
3084 RECT r;
3085 r.left = 200;
3086 r.top = 200;
3087 r.right = 200 + aClientSize.width;
3088 r.bottom = 200 + aClientSize.height;
3089 ::AdjustWindowRectEx(&r, WindowStyle(), PR_FALSE, WindowExStyle());
3091 return nsIntSize(r.right - r.left, r.bottom - r.top);
3094 /**************************************************************
3096 * SECTION: nsIWidget::EnableDragDrop
3098 * Enables/Disables drag and drop of files on this widget.
3100 **************************************************************/
3102 #if !defined(WINCE) // implemented in nsWindowCE.cpp
3103 NS_METHOD nsWindow::EnableDragDrop(PRBool aEnable)
3105 NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()");
3107 nsresult rv = NS_ERROR_FAILURE;
3108 if (aEnable) {
3109 if (nsnull == mNativeDragTarget) {
3110 mNativeDragTarget = new nsNativeDragTarget(this);
3111 if (NULL != mNativeDragTarget) {
3112 mNativeDragTarget->AddRef();
3113 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) {
3114 if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) {
3115 rv = NS_OK;
3120 } else {
3121 if (nsnull != mWnd && NULL != mNativeDragTarget) {
3122 ::RevokeDragDrop(mWnd);
3123 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) {
3124 rv = NS_OK;
3126 mNativeDragTarget->DragCancel();
3127 NS_RELEASE(mNativeDragTarget);
3130 return rv;
3132 #endif
3134 /**************************************************************
3136 * SECTION: nsIWidget::CaptureMouse
3138 * Enables/Disables system mouse capture.
3140 **************************************************************/
3142 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
3144 if (!nsToolkit::gMouseTrailer) {
3145 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3146 return NS_OK;
3149 if (aCapture) {
3150 nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd);
3151 ::SetCapture(mWnd);
3152 } else {
3153 nsToolkit::gMouseTrailer->SetCaptureWindow(NULL);
3154 ::ReleaseCapture();
3156 sIsInMouseCapture = aCapture;
3157 return NS_OK;
3160 /**************************************************************
3162 * SECTION: nsIWidget::CaptureRollupEvents
3164 * Dealing with event rollup on destroy for popups. Enables &
3165 * Disables system capture of any and all events that would
3166 * cause a dropdown to be rolled up.
3168 **************************************************************/
3170 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
3171 nsIMenuRollup * aMenuRollup,
3172 PRBool aDoCapture,
3173 PRBool aConsumeRollupEvent)
3175 if (aDoCapture) {
3176 /* we haven't bothered carrying a weak reference to sRollupWidget because
3177 we believe lifespan is properly scoped. this next assertion helps
3178 assure that remains true. */
3179 NS_ASSERTION(!sRollupWidget, "rollup widget reassigned before release");
3180 sRollupConsumeEvent = aConsumeRollupEvent;
3181 NS_IF_RELEASE(sRollupWidget);
3182 NS_IF_RELEASE(sMenuRollup);
3183 sRollupListener = aListener;
3184 sMenuRollup = aMenuRollup;
3185 NS_IF_ADDREF(aMenuRollup);
3186 sRollupWidget = this;
3187 NS_ADDREF(this);
3189 #ifndef WINCE
3190 if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
3191 RegisterSpecialDropdownHooks();
3193 sProcessHook = PR_TRUE;
3194 #endif
3196 } else {
3197 sRollupListener = nsnull;
3198 NS_IF_RELEASE(sMenuRollup);
3199 NS_IF_RELEASE(sRollupWidget);
3201 #ifndef WINCE
3202 sProcessHook = PR_FALSE;
3203 UnregisterSpecialDropdownHooks();
3204 #endif
3207 return NS_OK;
3210 /**************************************************************
3212 * SECTION: nsIWidget::GetAttention
3214 * Bring this window to the user's attention.
3216 **************************************************************/
3218 // Draw user's attention to this window until it comes to foreground.
3219 NS_IMETHODIMP
3220 nsWindow::GetAttention(PRInt32 aCycleCount)
3222 #ifndef WINCE
3223 // Got window?
3224 if (!mWnd)
3225 return NS_ERROR_NOT_INITIALIZED;
3227 // Don't flash if the flash count is 0 or if the
3228 // top level window is already active.
3229 HWND fgWnd = ::GetForegroundWindow();
3230 if (aCycleCount == 0 || fgWnd == GetTopLevelHWND(mWnd))
3231 return NS_OK;
3233 HWND flashWnd = mWnd;
3234 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3235 flashWnd = ownerWnd;
3238 // Don't flash if the owner window is active either.
3239 if (fgWnd == flashWnd)
3240 return NS_OK;
3242 DWORD defaultCycleCount = 0;
3243 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
3245 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3246 FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 };
3247 ::FlashWindowEx(&flashInfo);
3248 #endif
3249 return NS_OK;
3252 void nsWindow::StopFlashing()
3254 #ifndef WINCE
3255 HWND flashWnd = mWnd;
3256 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3257 flashWnd = ownerWnd;
3260 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3261 FLASHW_STOP, 0, 0 };
3262 ::FlashWindowEx(&flashInfo);
3263 #endif
3266 /**************************************************************
3268 * SECTION: nsIWidget::HasPendingInputEvent
3270 * Ask whether there user input events pending. All input events are
3271 * included, including those not targeted at this nsIwidget instance.
3273 **************************************************************/
3275 PRBool
3276 nsWindow::HasPendingInputEvent()
3278 // If there is pending input or the user is currently
3279 // moving the window then return true.
3280 // Note: When the user is moving the window WIN32 spins
3281 // a separate event loop and input events are not
3282 // reported to the application.
3283 if (HIWORD(GetQueueStatus(QS_INPUT)))
3284 return PR_TRUE;
3285 #ifdef WINCE
3286 return PR_FALSE;
3287 #else
3288 GUITHREADINFO guiInfo;
3289 guiInfo.cbSize = sizeof(GUITHREADINFO);
3290 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo))
3291 return PR_FALSE;
3292 return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE);
3293 #endif
3296 /**************************************************************
3298 * SECTION: nsIWidget::GetLayerManager
3300 * Get the layer manager associated with this widget.
3302 **************************************************************/
3304 struct LayerManagerPrefs {
3305 LayerManagerPrefs()
3306 : mAccelerateByDefault(PR_TRUE)
3307 , mDisableAcceleration(PR_FALSE)
3308 , mPreferOpenGL(PR_FALSE)
3309 , mPreferD3D9(PR_FALSE)
3311 PRBool mAccelerateByDefault;
3312 PRBool mDisableAcceleration;
3313 PRBool mForceAcceleration;
3314 PRBool mPreferOpenGL;
3315 PRBool mPreferD3D9;
3318 static void
3319 GetLayerManagerPrefs(LayerManagerPrefs* aManagerPrefs)
3321 nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3322 if (prefs) {
3323 prefs->GetBoolPref("layers.acceleration.disabled",
3324 &aManagerPrefs->mDisableAcceleration);
3325 prefs->GetBoolPref("layers.acceleration.force-enabled",
3326 &aManagerPrefs->mForceAcceleration);
3327 prefs->GetBoolPref("layers.prefer-opengl",
3328 &aManagerPrefs->mPreferOpenGL);
3329 prefs->GetBoolPref("layers.prefer-d3d9",
3330 &aManagerPrefs->mPreferD3D9);
3333 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
3334 aManagerPrefs->mAccelerateByDefault =
3335 aManagerPrefs->mAccelerateByDefault ||
3336 (acceleratedEnv && (*acceleratedEnv != '0'));
3338 PRBool safeMode = PR_FALSE;
3339 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
3340 if (xr)
3341 xr->GetInSafeMode(&safeMode);
3342 aManagerPrefs->mDisableAcceleration =
3343 aManagerPrefs->mDisableAcceleration || safeMode;
3346 mozilla::layers::LayerManager*
3347 nsWindow::GetLayerManager(LayerManagerPersistence aPersistence, bool* aAllowRetaining)
3349 if (aAllowRetaining) {
3350 *aAllowRetaining = true;
3353 #ifndef WINCE
3354 #ifdef MOZ_ENABLE_D3D10_LAYER
3355 if (mLayerManager) {
3356 if (mLayerManager->GetBackendType() ==
3357 mozilla::layers::LayerManager::LAYERS_D3D10)
3359 mozilla::layers::LayerManagerD3D10 *layerManagerD3D10 =
3360 static_cast<mozilla::layers::LayerManagerD3D10*>(mLayerManager.get());
3361 if (layerManagerD3D10->device() !=
3362 gfxWindowsPlatform::GetPlatform()->GetD3D10Device())
3364 mLayerManager->Destroy();
3365 mLayerManager = nsnull;
3369 #endif
3371 if (!mLayerManager ||
3372 (!sAllowD3D9 && aPersistence == LAYER_MANAGER_PERSISTENT &&
3373 mLayerManager->GetBackendType() ==
3374 mozilla::layers::LayerManager::LAYERS_BASIC)) {
3375 // If D3D9 is not currently allowed but the permanent manager is required,
3376 // -and- we're currently using basic layers, run through this check.
3377 LayerManagerPrefs prefs;
3378 GetLayerManagerPrefs(&prefs);
3380 /* We don't currently support using an accelerated layer manager with
3381 * transparent windows so don't even try. I'm also not sure if we even
3382 * want to support this case. See bug #593471 */
3383 if (eTransparencyTransparent == mTransparencyMode ||
3384 prefs.mDisableAcceleration)
3385 mUseAcceleratedRendering = PR_FALSE;
3386 else if (prefs.mAccelerateByDefault)
3387 mUseAcceleratedRendering = PR_TRUE;
3389 if (mUseAcceleratedRendering) {
3390 if (aPersistence == LAYER_MANAGER_PERSISTENT && !sAllowD3D9) {
3391 // This will clear out our existing layer manager if we have one since
3392 // if we hit this with a LayerManager we're always using BasicLayers.
3393 nsToolkit::StartAllowingD3D9();
3396 #ifdef MOZ_ENABLE_D3D10_LAYER
3397 if (!prefs.mPreferD3D9) {
3398 nsRefPtr<mozilla::layers::LayerManagerD3D10> layerManager =
3399 new mozilla::layers::LayerManagerD3D10(this);
3400 if (layerManager->Initialize()) {
3401 mLayerManager = layerManager;
3404 #endif
3405 #ifdef MOZ_ENABLE_D3D9_LAYER
3406 if (!prefs.mPreferOpenGL && !mLayerManager && sAllowD3D9) {
3407 nsRefPtr<mozilla::layers::LayerManagerD3D9> layerManager =
3408 new mozilla::layers::LayerManagerD3D9(this);
3409 if (layerManager->Initialize()) {
3410 mLayerManager = layerManager;
3413 #endif
3414 if (!mLayerManager && prefs.mPreferOpenGL) {
3415 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
3416 PRInt32 status = nsIGfxInfo::FEATURE_NO_INFO;
3418 if (gfxInfo && !prefs.mForceAcceleration) {
3419 gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status);
3422 if (status == nsIGfxInfo::FEATURE_NO_INFO) {
3423 nsRefPtr<mozilla::layers::LayerManagerOGL> layerManager =
3424 new mozilla::layers::LayerManagerOGL(this);
3425 if (layerManager->Initialize()) {
3426 mLayerManager = layerManager;
3429 } else {
3430 NS_WARNING("OpenGL accelerated layers are not supported on this system.");
3435 // Fall back to software if we couldn't use any hardware backends.
3436 if (!mLayerManager)
3437 mLayerManager = CreateBasicLayerManager();
3439 #endif
3441 return mLayerManager;
3444 /**************************************************************
3446 * SECTION: nsIWidget::GetThebesSurface
3448 * Get the Thebes surface associated with this widget.
3450 **************************************************************/
3452 gfxASurface *nsWindow::GetThebesSurface()
3454 #ifdef CAIRO_HAS_D2D_SURFACE
3455 if (mD2DWindowSurface) {
3456 return mD2DWindowSurface;
3458 #endif
3459 if (mPaintDC)
3460 return (new gfxWindowsSurface(mPaintDC));
3462 #ifdef CAIRO_HAS_D2D_SURFACE
3463 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3464 gfxWindowsPlatform::RENDER_DIRECT2D) {
3465 gfxASurface::gfxContentType content = gfxASurface::CONTENT_COLOR;
3466 #if defined(MOZ_XUL)
3467 if (mTransparencyMode != eTransparencyOpaque) {
3468 content = gfxASurface::CONTENT_COLOR_ALPHA;
3470 #endif
3471 return (new gfxD2DSurface(mWnd, content));
3472 } else {
3473 #endif
3474 PRUint32 flags = gfxWindowsSurface::FLAG_TAKE_DC;
3475 if (mTransparencyMode != eTransparencyOpaque) {
3476 flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT;
3478 return (new gfxWindowsSurface(mWnd, flags));
3479 #ifdef CAIRO_HAS_D2D_SURFACE
3481 #endif
3484 /**************************************************************
3486 * SECTION: nsIWidget::OnDefaultButtonLoaded
3488 * Called after the dialog is loaded and it has a default button.
3490 **************************************************************/
3492 NS_IMETHODIMP
3493 nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect)
3495 #ifdef WINCE
3496 return NS_ERROR_NOT_IMPLEMENTED;
3497 #else
3498 if (aButtonRect.IsEmpty())
3499 return NS_OK;
3501 // Don't snap when we are not active.
3502 HWND activeWnd = ::GetActiveWindow();
3503 if (activeWnd != ::GetForegroundWindow() ||
3504 GetTopLevelHWND(mWnd, PR_TRUE) != GetTopLevelHWND(activeWnd, PR_TRUE)) {
3505 return NS_OK;
3508 PRBool isAlwaysSnapCursor = PR_FALSE;
3509 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3510 if (prefs) {
3511 nsCOMPtr<nsIPrefBranch> prefBranch;
3512 prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
3513 if (prefBranch) {
3514 prefBranch->GetBoolPref("ui.cursor_snapping.always_enabled",
3515 &isAlwaysSnapCursor);
3519 if (!isAlwaysSnapCursor) {
3520 BOOL snapDefaultButton;
3521 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0,
3522 &snapDefaultButton, 0) || !snapDefaultButton)
3523 return NS_OK;
3526 nsIntRect widgetRect;
3527 nsresult rv = GetScreenBounds(widgetRect);
3528 NS_ENSURE_SUCCESS(rv, rv);
3529 nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft());
3531 nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2,
3532 buttonRect.y + buttonRect.height / 2);
3533 // The center of the button can be outside of the widget.
3534 // E.g., it could be hidden by scrolling.
3535 if (!widgetRect.Contains(centerOfButton)) {
3536 return NS_OK;
3539 if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) {
3540 NS_ERROR("SetCursorPos failed");
3541 return NS_ERROR_FAILURE;
3543 return NS_OK;
3544 #endif
3547 NS_IMETHODIMP
3548 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta,
3549 PRBool aIsHorizontal,
3550 PRInt32 &aOverriddenDelta)
3552 // The default vertical and horizontal scrolling speed is 3, this is defined
3553 // on the document of SystemParametersInfo in MSDN.
3554 const PRUint32 kSystemDefaultScrollingSpeed = 3;
3556 PRInt32 absOriginDelta = PR_ABS(aOriginalDelta);
3558 // Compute the simple overridden speed.
3559 PRInt32 absComputedOverriddenDelta;
3560 nsresult rv =
3561 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta, aIsHorizontal,
3562 absComputedOverriddenDelta);
3563 NS_ENSURE_SUCCESS(rv, rv);
3565 aOverriddenDelta = aOriginalDelta;
3567 if (absComputedOverriddenDelta == absOriginDelta) {
3568 // We don't override now.
3569 return NS_OK;
3572 // Otherwise, we should check whether the user customized the system settings
3573 // or not. If the user did it, we should respect the will.
3574 UINT systemSpeed;
3575 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) {
3576 return NS_ERROR_FAILURE;
3578 // The default vertical scrolling speed is 3, this is defined on the document
3579 // of SystemParametersInfo in MSDN.
3580 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3581 return NS_OK;
3584 // Only Vista and later, Windows has the system setting of horizontal
3585 // scrolling by the mouse wheel.
3586 if (GetWindowsVersion() >= VISTA_VERSION) {
3587 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) {
3588 return NS_ERROR_FAILURE;
3590 // The default horizontal scrolling speed is 3, this is defined on the
3591 // document of SystemParametersInfo in MSDN.
3592 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3593 return NS_OK;
3597 // Limit the overridden delta value from the system settings. The mouse
3598 // driver might accelerate the scrolling speed already. If so, we shouldn't
3599 // override the scrolling speed for preventing the unexpected high speed
3600 // scrolling.
3601 PRInt32 absDeltaLimit;
3602 rv =
3603 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed,
3604 aIsHorizontal, absDeltaLimit);
3605 NS_ENSURE_SUCCESS(rv, rv);
3607 // If the given delta is larger than our computed limitation value, the delta
3608 // was accelerated by the mouse driver. So, we should do nothing here.
3609 if (absDeltaLimit <= absOriginDelta) {
3610 return NS_OK;
3613 absComputedOverriddenDelta =
3614 PR_MIN(absComputedOverriddenDelta, absDeltaLimit);
3616 aOverriddenDelta = (aOriginalDelta > 0) ? absComputedOverriddenDelta :
3617 -absComputedOverriddenDelta;
3618 return NS_OK;
3621 /**************************************************************
3622 **************************************************************
3624 ** BLOCK: Moz Events
3626 ** Moz GUI event management.
3628 **************************************************************
3629 **************************************************************/
3631 /**************************************************************
3633 * SECTION: Mozilla event initialization
3635 * Helpers for initializing moz events.
3637 **************************************************************/
3639 // Event intialization
3640 MSG nsWindow::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam)
3642 MSG msg;
3643 msg.message = aMessage;
3644 msg.wParam = wParam;
3645 msg.lParam = lParam;
3646 return msg;
3649 void nsWindow::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
3651 if (nsnull == aPoint) { // use the point from the event
3652 // get the message position in client coordinates
3653 if (mWnd != NULL) {
3655 DWORD pos = ::GetMessagePos();
3656 POINT cpos;
3658 cpos.x = GET_X_LPARAM(pos);
3659 cpos.y = GET_Y_LPARAM(pos);
3661 ::ScreenToClient(mWnd, &cpos);
3662 event.refPoint.x = cpos.x;
3663 event.refPoint.y = cpos.y;
3664 } else {
3665 event.refPoint.x = 0;
3666 event.refPoint.y = 0;
3669 else {
3670 // use the point override if provided
3671 event.refPoint.x = aPoint->x;
3672 event.refPoint.y = aPoint->y;
3675 #ifndef WINCE
3676 event.time = ::GetMessageTime();
3677 #else
3678 event.time = PR_Now() / 1000;
3679 #endif
3681 mLastPoint = event.refPoint;
3684 /**************************************************************
3686 * SECTION: Moz event dispatch helpers
3688 * Helpers for dispatching different types of moz events.
3690 **************************************************************/
3692 // Main event dispatch. Invokes callback and ProcessEvent method on
3693 // Event Listener object. Part of nsIWidget.
3694 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
3696 #ifdef WIDGET_DEBUG_OUTPUT
3697 debug_DumpEvent(stdout,
3698 event->widget,
3699 event,
3700 nsCAutoString("something"),
3701 (PRInt32) mWnd);
3702 #endif // WIDGET_DEBUG_OUTPUT
3704 aStatus = nsEventStatus_eIgnore;
3706 // skip processing of suppressed blur events
3707 if (event->message == NS_DEACTIVATE && BlurEventsSuppressed())
3708 return NS_OK;
3710 // Top level windows can have a view attached which requires events be sent
3711 // to the underlying base window and the view. Added when we combined the
3712 // base chrome window with the main content child for nc client area (title
3713 // bar) rendering.
3714 if (mViewCallback) {
3715 // A subset of events are sent to the base xul window first
3716 switch(event->message) {
3717 // send to the base window (view mgr ignores these for the view)
3718 case NS_UISTATECHANGED:
3719 case NS_DESTROY:
3720 case NS_SETZLEVEL:
3721 case NS_XUL_CLOSE:
3722 case NS_MOVE:
3723 (*mEventCallback)(event); // web shell / xul window
3724 return NS_OK;
3726 // sent to the base window, then to the view
3727 case NS_SIZE:
3728 case NS_DEACTIVATE:
3729 case NS_ACTIVATE:
3730 case NS_SIZEMODE:
3731 (*mEventCallback)(event); // web shell / xul window
3732 break;
3734 // attached view events
3735 aStatus = (*mViewCallback)(event);
3737 else if (mEventCallback) {
3738 aStatus = (*mEventCallback)(event);
3741 // the window can be destroyed during processing of seemingly innocuous events like, say,
3742 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3743 // which causes problems with the deleted window. therefore:
3744 if (mOnDestroyCalled)
3745 aStatus = nsEventStatus_eConsumeNoDefault;
3746 return NS_OK;
3749 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
3751 nsGUIEvent event(PR_TRUE, aMsg, this);
3752 InitEvent(event);
3754 PRBool result = DispatchWindowEvent(&event);
3755 return result;
3758 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
3760 nsEventStatus status;
3761 DispatchEvent(event, status);
3762 return ConvertStatus(status);
3765 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event, nsEventStatus &aStatus) {
3766 DispatchEvent(event, aStatus);
3767 return ConvertStatus(aStatus);
3770 PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
3771 const nsTArray<nsAlternativeCharCode>* aAlternativeCharCodes,
3772 UINT aVirtualCharCode, const MSG *aMsg,
3773 const nsModifierKeyState &aModKeyState,
3774 PRUint32 aFlags)
3776 UserActivity();
3778 nsKeyEvent event(PR_TRUE, aEventType, this);
3779 nsIntPoint point(0, 0);
3781 InitEvent(event, &point); // this add ref's event.widget
3783 event.flags |= aFlags;
3784 event.charCode = aCharCode;
3785 if (aAlternativeCharCodes)
3786 event.alternativeCharCodes.AppendElements(*aAlternativeCharCodes);
3787 event.keyCode = aVirtualCharCode;
3789 #ifdef KE_DEBUG
3790 static cnt=0;
3791 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt++,
3792 (NS_KEY_PRESS == aEventType) ? "PRESS" : (aEventType == NS_KEY_UP ? "Up" : "Down"),
3793 event.charCode, event.keyCode);
3794 printf("Shift: %s Control %s Alt: %s \n",
3795 (mIsShiftDown ? "D" : "U"), (mIsControlDown ? "D" : "U"), (mIsAltDown ? "D" : "U"));
3796 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3797 IS_VK_DOWN(NS_VK_SHIFT) ? 'S' : ' ',
3798 IS_VK_DOWN(NS_VK_CONTROL) ? 'C' : ' ',
3799 IS_VK_DOWN(NS_VK_ALT) ? 'A' : ' ',
3800 IS_VK_DOWN(VK_LSHIFT) ? 'S' : ' ',
3801 IS_VK_DOWN(VK_LCONTROL) ? 'C' : ' ',
3802 IS_VK_DOWN(VK_LMENU) ? 'A' : ' ',
3803 IS_VK_DOWN(VK_RMENU) ? 'A' : ' ',
3804 IS_VK_DOWN(VK_RCONTROL) ? 'C' : ' ',
3805 IS_VK_DOWN(VK_RSHIFT) ? 'S' : ' ');
3806 #endif
3808 event.isShift = aModKeyState.mIsShiftDown;
3809 event.isControl = aModKeyState.mIsControlDown;
3810 event.isMeta = PR_FALSE;
3811 event.isAlt = aModKeyState.mIsAltDown;
3813 NPEvent pluginEvent;
3814 if (aMsg && PluginHasFocus()) {
3815 pluginEvent.event = aMsg->message;
3816 pluginEvent.wParam = aMsg->wParam;
3817 pluginEvent.lParam = aMsg->lParam;
3818 event.pluginEvent = (void *)&pluginEvent;
3821 PRBool result = DispatchWindowEvent(&event);
3823 return result;
3826 PRBool nsWindow::DispatchCommandEvent(PRUint32 aEventCommand)
3828 nsCOMPtr<nsIAtom> command;
3829 switch (aEventCommand) {
3830 case APPCOMMAND_BROWSER_BACKWARD:
3831 command = nsWidgetAtoms::Back;
3832 break;
3833 case APPCOMMAND_BROWSER_FORWARD:
3834 command = nsWidgetAtoms::Forward;
3835 break;
3836 case APPCOMMAND_BROWSER_REFRESH:
3837 command = nsWidgetAtoms::Reload;
3838 break;
3839 case APPCOMMAND_BROWSER_STOP:
3840 command = nsWidgetAtoms::Stop;
3841 break;
3842 case APPCOMMAND_BROWSER_SEARCH:
3843 command = nsWidgetAtoms::Search;
3844 break;
3845 case APPCOMMAND_BROWSER_FAVORITES:
3846 command = nsWidgetAtoms::Bookmarks;
3847 break;
3848 case APPCOMMAND_BROWSER_HOME:
3849 command = nsWidgetAtoms::Home;
3850 break;
3851 default:
3852 return PR_FALSE;
3854 nsCommandEvent event(PR_TRUE, nsWidgetAtoms::onAppCommand, command, this);
3856 InitEvent(event);
3857 DispatchWindowEvent(&event);
3859 return PR_TRUE;
3862 // Recursively dispatch synchronous paints for nsIWidget
3863 // descendants with invalidated rectangles.
3864 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
3866 LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
3867 if (proc == (LONG_PTR)&nsWindow::WindowProc) {
3868 // its one of our windows so check to see if it has a
3869 // invalidated rect. If it does. Dispatch a synchronous
3870 // paint.
3871 if (GetUpdateRect(aWnd, NULL, FALSE))
3872 VERIFY(::UpdateWindow(aWnd));
3874 return TRUE;
3877 // Check for pending paints and dispatch any pending paint
3878 // messages for any nsIWidget which is a descendant of the
3879 // top-level window that *this* window is embedded within.
3881 // Note: We do not dispatch pending paint messages for non
3882 // nsIWidget managed windows.
3883 void nsWindow::DispatchPendingEvents()
3885 if (mPainting) {
3886 NS_WARNING("We were asked to dispatch pending events during painting, "
3887 "denying since that's unsafe.");
3888 return;
3891 // We need to ensure that reflow events do not get starved.
3892 // At the same time, we don't want to recurse through here
3893 // as that would prevent us from dispatching starved paints.
3894 static int recursionBlocker = 0;
3895 if (recursionBlocker++ == 0) {
3896 NS_ProcessPendingEvents(nsnull, PR_MillisecondsToInterval(100));
3897 --recursionBlocker;
3900 // Quickly check to see if there are any paint events pending,
3901 // but only dispatch them if it has been long enough since the
3902 // last paint completed.
3903 if (::GetQueueStatus(QS_PAINT) &&
3904 (mLastPaintEndTime.IsNull() ||
3905 (TimeStamp::Now() - mLastPaintEndTime).ToMilliseconds() >= 50)) {
3906 // Find the top level window.
3907 HWND topWnd = GetTopLevelHWND(mWnd);
3909 // Dispatch pending paints for topWnd and all its descendant windows.
3910 // Note: EnumChildWindows enumerates all descendant windows not just
3911 // the children (but not the window itself).
3912 nsWindow::DispatchStarvedPaints(topWnd, 0);
3913 #if !defined(WINCE)
3914 ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, 0);
3915 #else
3916 nsWindowCE::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3917 #endif
3921 // Deal with plugin events
3922 PRBool nsWindow::DispatchPluginEvent(const MSG &aMsg)
3924 if (!PluginHasFocus())
3925 return PR_FALSE;
3927 nsGUIEvent event(PR_TRUE, NS_PLUGIN_EVENT, this);
3928 nsIntPoint point(0, 0);
3929 InitEvent(event, &point);
3930 NPEvent pluginEvent;
3931 pluginEvent.event = aMsg.message;
3932 pluginEvent.wParam = aMsg.wParam;
3933 pluginEvent.lParam = aMsg.lParam;
3934 event.pluginEvent = (void *)&pluginEvent;
3935 return DispatchWindowEvent(&event);
3938 PRBool nsWindow::DispatchPluginEvent(UINT aMessage,
3939 WPARAM aWParam,
3940 LPARAM aLParam,
3941 PRBool aDispatchPendingEvents)
3943 PRBool ret = DispatchPluginEvent(InitMSG(aMessage, aWParam, aLParam));
3944 if (aDispatchPendingEvents) {
3945 DispatchPendingEvents();
3947 return ret;
3950 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
3951 UINT aLastMsg)
3953 MSG msg;
3954 ::GetMessageW(&msg, mWnd, aFirstMsg, aLastMsg);
3955 DispatchPluginEvent(msg);
3958 // Deal with all sort of mouse event
3959 PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
3960 LPARAM lParam, PRBool aIsContextMenuKey,
3961 PRInt16 aButton, PRUint16 aInputSource)
3963 PRBool result = PR_FALSE;
3965 UserActivity();
3967 if (!mEventCallback) {
3968 return result;
3971 switch (aEventType) {
3972 case NS_MOUSE_BUTTON_DOWN:
3973 CaptureMouse(PR_TRUE);
3974 break;
3976 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3977 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3978 case NS_MOUSE_BUTTON_UP:
3979 case NS_MOUSE_MOVE:
3980 case NS_MOUSE_EXIT:
3981 if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && sIsInMouseCapture)
3982 CaptureMouse(PR_FALSE);
3983 break;
3985 default:
3986 break;
3988 } // switch
3990 nsIntPoint eventPoint;
3991 eventPoint.x = GET_X_LPARAM(lParam);
3992 eventPoint.y = GET_Y_LPARAM(lParam);
3994 nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal,
3995 aIsContextMenuKey
3996 ? nsMouseEvent::eContextMenuKey
3997 : nsMouseEvent::eNormal);
3998 if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) {
3999 nsIntPoint zero(0, 0);
4000 InitEvent(event, &zero);
4001 } else {
4002 InitEvent(event, &eventPoint);
4005 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
4006 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
4007 event.isMeta = PR_FALSE;
4008 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
4009 event.button = aButton;
4010 event.inputSource = aInputSource;
4012 nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
4014 // Suppress mouse moves caused by widget creation
4015 if (aEventType == NS_MOUSE_MOVE)
4017 if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y))
4018 return result;
4019 sLastMouseMovePoint.x = mpScreen.x;
4020 sLastMouseMovePoint.y = mpScreen.y;
4023 PRBool insideMovementThreshold = (abs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
4024 (abs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
4026 BYTE eventButton;
4027 switch (aButton) {
4028 case nsMouseEvent::eLeftButton:
4029 eventButton = VK_LBUTTON;
4030 break;
4031 case nsMouseEvent::eMiddleButton:
4032 eventButton = VK_MBUTTON;
4033 break;
4034 case nsMouseEvent::eRightButton:
4035 eventButton = VK_RBUTTON;
4036 break;
4037 default:
4038 eventButton = 0;
4039 break;
4042 // Doubleclicks are used to set the click count, then changed to mousedowns
4043 // We're going to time double-clicks from mouse *up* to next mouse *down*
4044 #ifndef WINCE
4045 LONG curMsgTime = ::GetMessageTime();
4046 #else
4047 LONG curMsgTime = PR_Now() / 1000;
4048 #endif
4050 if (aEventType == NS_MOUSE_DOUBLECLICK) {
4051 event.message = NS_MOUSE_BUTTON_DOWN;
4052 event.button = aButton;
4053 sLastClickCount = 2;
4055 else if (aEventType == NS_MOUSE_BUTTON_UP) {
4056 // remember when this happened for the next mouse down
4057 sLastMousePoint.x = eventPoint.x;
4058 sLastMousePoint.y = eventPoint.y;
4059 sLastMouseButton = eventButton;
4061 else if (aEventType == NS_MOUSE_BUTTON_DOWN) {
4062 // now look to see if we want to convert this to a double- or triple-click
4063 if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold &&
4064 eventButton == sLastMouseButton) {
4065 sLastClickCount ++;
4066 } else {
4067 // reset the click count, to count *this* click
4068 sLastClickCount = 1;
4070 // Set last Click time on MouseDown only
4071 sLastMouseDownTime = curMsgTime;
4073 else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
4074 sLastClickCount = 0;
4076 else if (aEventType == NS_MOUSE_EXIT) {
4077 event.exit = IsTopLevelMouseExit(mWnd) ? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
4079 else if (aEventType == NS_MOUSE_MOZHITTEST)
4081 event.flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
4083 event.clickCount = sLastClickCount;
4085 #ifdef NS_DEBUG_XX
4086 printf("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount);
4087 #endif
4089 NPEvent pluginEvent;
4091 switch (aEventType)
4093 case NS_MOUSE_BUTTON_DOWN:
4094 switch (aButton) {
4095 case nsMouseEvent::eLeftButton:
4096 pluginEvent.event = WM_LBUTTONDOWN;
4097 break;
4098 case nsMouseEvent::eMiddleButton:
4099 pluginEvent.event = WM_MBUTTONDOWN;
4100 break;
4101 case nsMouseEvent::eRightButton:
4102 pluginEvent.event = WM_RBUTTONDOWN;
4103 break;
4104 default:
4105 break;
4107 break;
4108 case NS_MOUSE_BUTTON_UP:
4109 switch (aButton) {
4110 case nsMouseEvent::eLeftButton:
4111 pluginEvent.event = WM_LBUTTONUP;
4112 break;
4113 case nsMouseEvent::eMiddleButton:
4114 pluginEvent.event = WM_MBUTTONUP;
4115 break;
4116 case nsMouseEvent::eRightButton:
4117 pluginEvent.event = WM_RBUTTONUP;
4118 break;
4119 default:
4120 break;
4122 break;
4123 case NS_MOUSE_DOUBLECLICK:
4124 switch (aButton) {
4125 case nsMouseEvent::eLeftButton:
4126 pluginEvent.event = WM_LBUTTONDBLCLK;
4127 break;
4128 case nsMouseEvent::eMiddleButton:
4129 pluginEvent.event = WM_MBUTTONDBLCLK;
4130 break;
4131 case nsMouseEvent::eRightButton:
4132 pluginEvent.event = WM_RBUTTONDBLCLK;
4133 break;
4134 default:
4135 break;
4137 break;
4138 case NS_MOUSE_MOVE:
4139 pluginEvent.event = WM_MOUSEMOVE;
4140 break;
4141 case NS_MOUSE_EXIT:
4142 pluginEvent.event = WM_MOUSELEAVE;
4143 break;
4144 default:
4145 pluginEvent.event = WM_NULL;
4146 break;
4149 pluginEvent.wParam = wParam; // plugins NEED raw OS event flags!
4150 pluginEvent.lParam = lParam;
4152 event.pluginEvent = (void *)&pluginEvent;
4154 // call the event callback
4155 if (nsnull != mEventCallback) {
4156 if (nsToolkit::gMouseTrailer)
4157 nsToolkit::gMouseTrailer->Disable();
4158 if (aEventType == NS_MOUSE_MOVE) {
4159 if (nsToolkit::gMouseTrailer && !sIsInMouseCapture) {
4160 nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd);
4162 nsIntRect rect;
4163 GetBounds(rect);
4164 rect.x = 0;
4165 rect.y = 0;
4167 if (rect.Contains(event.refPoint)) {
4168 if (sCurrentWindow == NULL || sCurrentWindow != this) {
4169 if ((nsnull != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
4170 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
4171 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, PR_FALSE,
4172 nsMouseEvent::eLeftButton, aInputSource);
4174 sCurrentWindow = this;
4175 if (!mInDtor) {
4176 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
4177 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, PR_FALSE,
4178 nsMouseEvent::eLeftButton, aInputSource);
4182 } else if (aEventType == NS_MOUSE_EXIT) {
4183 if (sCurrentWindow == this) {
4184 sCurrentWindow = nsnull;
4188 result = DispatchWindowEvent(&event);
4190 if (nsToolkit::gMouseTrailer)
4191 nsToolkit::gMouseTrailer->Enable();
4193 // Release the widget with NS_IF_RELEASE() just in case
4194 // the context menu key code in nsEventListenerManager::HandleEvent()
4195 // released it already.
4196 return result;
4199 return result;
4202 // Deal with accessibile event
4203 #ifdef ACCESSIBILITY
4204 nsAccessible*
4205 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType)
4207 if (nsnull == mEventCallback) {
4208 return nsnull;
4211 nsAccessibleEvent event(PR_TRUE, aEventType, this);
4212 InitEvent(event, nsnull);
4214 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
4215 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
4216 event.isMeta = PR_FALSE;
4217 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
4219 DispatchWindowEvent(&event);
4221 return event.mAccessible;
4223 #endif
4225 PRBool nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType)
4227 if (aEventType == NS_ACTIVATE)
4228 sJustGotActivate = PR_FALSE;
4229 sJustGotDeactivate = PR_FALSE;
4231 // retrive the toplevel window or dialog
4232 HWND curWnd = mWnd;
4233 HWND toplevelWnd = NULL;
4234 while (curWnd) {
4235 toplevelWnd = curWnd;
4237 nsWindow *win = GetNSWindowPtr(curWnd);
4238 if (win) {
4239 nsWindowType wintype;
4240 win->GetWindowType(wintype);
4241 if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog)
4242 break;
4245 curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
4248 if (toplevelWnd) {
4249 nsWindow *win = GetNSWindowPtr(toplevelWnd);
4250 if (win)
4251 return win->DispatchFocus(aEventType);
4254 return PR_FALSE;
4257 // Deal with focus messages
4258 PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
4260 // call the event callback
4261 if (mEventCallback) {
4262 nsGUIEvent event(PR_TRUE, aEventType, this);
4263 InitEvent(event);
4265 //focus and blur event should go to their base widget loc, not current mouse pos
4266 event.refPoint.x = 0;
4267 event.refPoint.y = 0;
4269 NPEvent pluginEvent;
4271 switch (aEventType)
4273 case NS_ACTIVATE:
4274 pluginEvent.event = WM_SETFOCUS;
4275 break;
4276 case NS_DEACTIVATE:
4277 pluginEvent.event = WM_KILLFOCUS;
4278 break;
4279 case NS_PLUGIN_ACTIVATE:
4280 pluginEvent.event = WM_KILLFOCUS;
4281 break;
4282 default:
4283 break;
4286 event.pluginEvent = (void *)&pluginEvent;
4288 return DispatchWindowEvent(&event);
4290 return PR_FALSE;
4293 PRBool nsWindow::IsTopLevelMouseExit(HWND aWnd)
4295 DWORD pos = ::GetMessagePos();
4296 POINT mp;
4297 mp.x = GET_X_LPARAM(pos);
4298 mp.y = GET_Y_LPARAM(pos);
4299 HWND mouseWnd = ::WindowFromPoint(mp);
4301 // GetTopLevelHWND will return a HWND for the window frame (which includes
4302 // the non-client area). If the mouse has moved into the non-client area,
4303 // we should treat it as a top-level exit.
4304 HWND mouseTopLevel = nsWindow::GetTopLevelHWND(mouseWnd);
4305 if (mouseWnd == mouseTopLevel)
4306 return PR_TRUE;
4308 return nsWindow::GetTopLevelHWND(aWnd) != mouseTopLevel;
4311 PRBool nsWindow::BlurEventsSuppressed()
4313 // are they suppressed in this window?
4314 if (mBlurSuppressLevel > 0)
4315 return PR_TRUE;
4317 // are they suppressed by any container widget?
4318 HWND parentWnd = ::GetParent(mWnd);
4319 if (parentWnd) {
4320 nsWindow *parent = GetNSWindowPtr(parentWnd);
4321 if (parent)
4322 return parent->BlurEventsSuppressed();
4324 return PR_FALSE;
4327 // In some circumstances (opening dependent windows) it makes more sense
4328 // (and fixes a crash bug) to not blur the parent window. Called from
4329 // nsFilePicker.
4330 void nsWindow::SuppressBlurEvents(PRBool aSuppress)
4332 if (aSuppress)
4333 ++mBlurSuppressLevel; // for this widget
4334 else {
4335 NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression");
4336 if (mBlurSuppressLevel > 0)
4337 --mBlurSuppressLevel;
4341 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
4343 return aStatus == nsEventStatus_eConsumeNoDefault;
4346 /**************************************************************
4348 * SECTION: IPC
4350 * IPC related helpers.
4352 **************************************************************/
4354 #ifdef MOZ_IPC
4356 // static
4357 bool
4358 nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult)
4360 switch(aMsg) {
4361 case WM_SETFOCUS:
4362 case WM_KILLFOCUS:
4363 case WM_ENABLE:
4364 case WM_WINDOWPOSCHANGING:
4365 case WM_WINDOWPOSCHANGED:
4366 case WM_PARENTNOTIFY:
4367 case WM_ACTIVATEAPP:
4368 case WM_NCACTIVATE:
4369 case WM_ACTIVATE:
4370 case WM_CHILDACTIVATE:
4371 case WM_IME_SETCONTEXT:
4372 case WM_IME_NOTIFY:
4373 case WM_SHOWWINDOW:
4374 case WM_CANCELMODE:
4375 case WM_MOUSEACTIVATE:
4376 case WM_CONTEXTMENU:
4377 aResult = 0;
4378 return true;
4380 case WM_SETTINGCHANGE:
4381 case WM_SETCURSOR:
4382 return false;
4385 #ifdef DEBUG
4386 char szBuf[200];
4387 sprintf(szBuf,
4388 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg);
4389 NS_WARNING(szBuf);
4390 #endif
4392 return false;
4395 void
4396 nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
4398 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4399 "Failed to prevent a nonqueued message from running!");
4401 // Modal UI being displayed in windowless plugins.
4402 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4403 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4404 LRESULT res;
4405 if (IsAsyncResponseEvent(msg, res)) {
4406 ReplyMessage(res);
4408 return;
4411 // Handle certain sync plugin events sent to the parent which
4412 // trigger ipc calls that result in deadlocks.
4414 DWORD dwResult = 0;
4415 PRBool handled = PR_FALSE;
4417 switch(msg) {
4418 // Windowless flash sending WM_ACTIVATE events to the main window
4419 // via calls to ShowWindow.
4420 case WM_ACTIVATE:
4421 if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE &&
4422 IsWindow((HWND)lParam))
4423 handled = PR_TRUE;
4424 break;
4425 // Wheel events forwarded from the child.
4426 case WM_MOUSEWHEEL:
4427 case WM_MOUSEHWHEEL:
4428 case WM_HSCROLL:
4429 case WM_VSCROLL:
4430 // Plugins taking or losing focus triggering focus app messages.
4431 case WM_SETFOCUS:
4432 case WM_KILLFOCUS:
4433 // Windowed plugins that pass sys key events to defwndproc generate
4434 // WM_SYSCOMMAND events to the main window.
4435 case WM_SYSCOMMAND:
4436 // Windowed plugins that fire context menu selection events to parent
4437 // windows.
4438 case WM_CONTEXTMENU:
4439 // IME events fired as a result of synchronous focus changes
4440 case WM_IME_SETCONTEXT:
4441 handled = PR_TRUE;
4442 break;
4445 if (handled &&
4446 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4447 ReplyMessage(dwResult);
4451 #endif // MOZ_IPC
4453 /**************************************************************
4454 **************************************************************
4456 ** BLOCK: Native events
4458 ** Main Windows message handlers and OnXXX handlers for
4459 ** Windows event handling.
4461 **************************************************************
4462 **************************************************************/
4464 /**************************************************************
4466 * SECTION: Wind proc.
4468 * The main Windows event procedures and associated
4469 * message processing methods.
4471 **************************************************************/
4473 #ifdef _MSC_VER
4474 static int ReportException(EXCEPTION_POINTERS *aExceptionInfo)
4476 #ifdef MOZ_CRASHREPORTER
4477 nsCOMPtr<nsICrashReporter> cr =
4478 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
4479 if (cr)
4480 cr->WriteMinidumpForException(aExceptionInfo);
4481 #endif
4482 return EXCEPTION_EXECUTE_HANDLER;
4484 #endif
4486 static PRBool
4487 DisplaySystemMenu(HWND hWnd, nsSizeMode sizeMode, PRBool isRtl, PRInt32 x, PRInt32 y)
4489 GetSystemMenu(hWnd, TRUE); // reset the system menu
4490 HMENU hMenu = GetSystemMenu(hWnd, FALSE);
4491 if (hMenu) {
4492 // update the options
4493 switch(sizeMode) {
4494 case nsSizeMode_Fullscreen:
4495 EnableMenuItem(hMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED);
4496 // intentional fall through
4497 case nsSizeMode_Maximized:
4498 EnableMenuItem(hMenu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
4499 EnableMenuItem(hMenu, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
4500 EnableMenuItem(hMenu, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
4501 break;
4502 case nsSizeMode_Minimized:
4503 EnableMenuItem(hMenu, SC_MINIMIZE, MF_BYCOMMAND | MF_GRAYED);
4504 break;
4505 case nsSizeMode_Normal:
4506 EnableMenuItem(hMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED);
4507 break;
4509 LPARAM cmd =
4510 TrackPopupMenu(hMenu,
4511 (TPM_LEFTBUTTON|TPM_RIGHTBUTTON|
4512 TPM_RETURNCMD|TPM_TOPALIGN|
4513 (isRtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN)),
4514 x, y, 0, hWnd, NULL);
4515 if (cmd) {
4516 PostMessage(hWnd, WM_SYSCOMMAND, cmd, 0);
4517 return PR_TRUE;
4520 return PR_FALSE;
4523 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
4524 // exceptions and passes the real work to WindowProcInternal. See bug 587406
4525 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
4526 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4528 #ifdef _MSC_VER
4529 __try {
4530 return WindowProcInternal(hWnd, msg, wParam, lParam);
4532 __except(ReportException(GetExceptionInformation())) {
4533 ::TerminateProcess(::GetCurrentProcess(), 253);
4535 #else
4536 return WindowProcInternal(hWnd, msg, wParam, lParam);
4537 #endif
4540 LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4542 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4543 MOZ_FUNCTION_NAME, __LINE__, hWnd, msg,
4544 wParam, lParam);
4546 if (::GetWindowLongPtrW(hWnd, GWLP_ID) == eFakeTrackPointScrollableID) {
4547 // This message was sent to the FAKETRACKPOINTSCROLLABLE.
4548 if (msg == WM_HSCROLL) {
4549 // Route WM_HSCROLL messages to the main window.
4550 hWnd = ::GetParent(::GetParent(hWnd));
4551 } else {
4552 // Handle all other messages with its original window procedure.
4553 WNDPROC prevWindowProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
4554 return ::CallWindowProcW(prevWindowProc, hWnd, msg, wParam, lParam);
4558 // Get the window which caused the event and ask it to process the message
4559 nsWindow *someWindow = GetNSWindowPtr(hWnd);
4561 #ifdef MOZ_IPC
4562 if (someWindow)
4563 someWindow->IPCWindowProcHandler(msg, wParam, lParam);
4564 #endif
4566 // create this here so that we store the last rolled up popup until after
4567 // the event has been processed.
4568 nsAutoRollup autoRollup;
4570 LRESULT popupHandlingResult;
4571 if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult))
4572 return popupHandlingResult;
4574 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4575 // why we are hitting this assert
4576 if (nsnull == someWindow) {
4577 NS_ASSERTION(someWindow, "someWindow is null, cannot call any CallWindowProc");
4578 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
4581 // hold on to the window for the life of this method, in case it gets
4582 // deleted during processing. yes, it's a double hack, since someWindow
4583 // is not really an interface.
4584 nsCOMPtr<nsISupports> kungFuDeathGrip;
4585 if (!someWindow->mInDtor) // not if we're in the destructor!
4586 kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)someWindow);
4588 // Call ProcessMessage
4589 LRESULT retValue;
4590 if (PR_TRUE == someWindow->ProcessMessage(msg, wParam, lParam, &retValue)) {
4591 return retValue;
4594 LRESULT res = ::CallWindowProcW(someWindow->GetPrevWindowProc(),
4595 hWnd, msg, wParam, lParam);
4597 return res;
4600 // The main windows message processing method for plugins.
4601 // The result means whether this method processed the native
4602 // event for plugin. If false, the native event should be
4603 // processed by the caller self.
4604 PRBool
4605 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
4606 LRESULT *aResult,
4607 PRBool &aCallDefWndProc)
4609 NS_PRECONDITION(aResult, "aResult must be non-null.");
4610 *aResult = 0;
4612 aCallDefWndProc = PR_FALSE;
4613 PRBool eventDispatched = PR_FALSE;
4614 switch (aMsg.message) {
4615 case WM_CHAR:
4616 case WM_SYSCHAR:
4617 *aResult = ProcessCharMessage(aMsg, &eventDispatched);
4618 break;
4620 case WM_KEYUP:
4621 case WM_SYSKEYUP:
4622 *aResult = ProcessKeyUpMessage(aMsg, &eventDispatched);
4623 break;
4625 case WM_KEYDOWN:
4626 case WM_SYSKEYDOWN:
4627 *aResult = ProcessKeyDownMessage(aMsg, &eventDispatched);
4628 break;
4630 case WM_DEADCHAR:
4631 case WM_SYSDEADCHAR:
4633 case WM_CUT:
4634 case WM_COPY:
4635 case WM_PASTE:
4636 case WM_CLEAR:
4637 case WM_UNDO:
4638 break;
4640 default:
4641 return PR_FALSE;
4644 if (!eventDispatched)
4645 aCallDefWndProc = !DispatchPluginEvent(aMsg);
4646 DispatchPendingEvents();
4647 return PR_TRUE;
4650 // The main windows message processing method.
4651 PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
4652 LRESULT *aRetValue)
4654 // (Large blocks of code should be broken out into OnEvent handlers.)
4655 if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
4656 return PR_TRUE;
4658 #if defined(EVENT_DEBUG_OUTPUT)
4659 // First param shows all events, second param indicates whether
4660 // to show mouse move events. See nsWindowDbg for details.
4661 PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
4662 #endif
4664 PRBool eatMessage;
4665 if (nsIMM32Handler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
4666 eatMessage)) {
4667 return mWnd ? eatMessage : PR_TRUE;
4670 if (PluginHasFocus()) {
4671 PRBool callDefaultWndProc;
4672 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4673 if (ProcessMessageForPlugin(nativeMsg, aRetValue, callDefaultWndProc)) {
4674 return mWnd ? !callDefaultWndProc : PR_TRUE;
4678 PRBool result = PR_FALSE; // call the default nsWindow proc
4679 *aRetValue = 0;
4681 static PRBool getWheelInfo = PR_TRUE;
4683 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4684 // Glass hit testing w/custom transparent margins
4685 LRESULT dwmHitResult;
4686 if (mCustomNonClient &&
4687 nsUXThemeData::CheckForCompositor() &&
4688 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) {
4689 *aRetValue = dwmHitResult;
4690 return PR_TRUE;
4692 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4694 switch (msg) {
4695 #ifndef WINCE
4696 // WM_QUERYENDSESSION must be handled by all windows.
4697 // Otherwise Windows thinks the window can just be killed at will.
4698 case WM_QUERYENDSESSION:
4699 if (sCanQuit == TRI_UNKNOWN)
4701 // Ask if it's ok to quit, and store the answer until we
4702 // get WM_ENDSESSION signaling the round is complete.
4703 nsCOMPtr<nsIObserverService> obsServ =
4704 mozilla::services::GetObserverService();
4705 nsCOMPtr<nsISupportsPRBool> cancelQuit =
4706 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
4707 cancelQuit->SetData(PR_FALSE);
4708 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
4710 PRBool abortQuit;
4711 cancelQuit->GetData(&abortQuit);
4712 sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
4714 *aRetValue = sCanQuit ? TRUE : FALSE;
4715 result = PR_TRUE;
4716 break;
4717 #endif
4719 #ifndef WINCE
4720 case WM_ENDSESSION:
4721 #endif
4722 case MOZ_WM_APP_QUIT:
4723 if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE))
4725 // Let's fake a shutdown sequence without actually closing windows etc.
4726 // to avoid Windows killing us in the middle. A proper shutdown would
4727 // require having a chance to pump some messages. Unfortunately
4728 // Windows won't let us do that. Bug 212316.
4729 nsCOMPtr<nsIObserverService> obsServ =
4730 mozilla::services::GetObserverService();
4731 NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
4732 obsServ->NotifyObservers(nsnull, "quit-application-granted", nsnull);
4733 obsServ->NotifyObservers(nsnull, "quit-application-forced", nsnull);
4734 obsServ->NotifyObservers(nsnull, "quit-application", nsnull);
4735 obsServ->NotifyObservers(nsnull, "profile-change-net-teardown", context.get());
4736 obsServ->NotifyObservers(nsnull, "profile-change-teardown", context.get());
4737 obsServ->NotifyObservers(nsnull, "profile-before-change", context.get());
4738 // Then a controlled but very quick exit.
4739 _exit(0);
4741 sCanQuit = TRI_UNKNOWN;
4742 result = PR_TRUE;
4743 break;
4745 #ifndef WINCE
4746 case WM_DISPLAYCHANGE:
4747 DispatchStandardEvent(NS_DISPLAYCHANGED);
4748 break;
4749 #endif
4751 case WM_SYSCOLORCHANGE:
4752 // Note: This is sent for child windows as well as top-level windows.
4753 // The Win32 toolkit normally only sends these events to top-level windows.
4754 // But we cycle through all of the childwindows and send it to them as well
4755 // so all presentations get notified properly.
4756 // See nsWindow::GlobalMsgWindowProc.
4757 DispatchStandardEvent(NS_SYSCOLORCHANGED);
4758 break;
4760 case WM_NOTIFY:
4761 // TAB change
4763 LPNMHDR pnmh = (LPNMHDR) lParam;
4765 switch (pnmh->code) {
4766 case TCN_SELCHANGE:
4768 DispatchStandardEvent(NS_TABCHANGE);
4769 result = PR_TRUE;
4771 break;
4774 break;
4776 case WM_THEMECHANGED:
4778 // Update non-client margin offsets
4779 UpdateNonClientMargins();
4780 nsUXThemeData::InitTitlebarInfo();
4781 nsUXThemeData::UpdateNativeThemeInfo();
4783 DispatchStandardEvent(NS_THEMECHANGED);
4785 // Invalidate the window so that the repaint will
4786 // pick up the new theme.
4787 Invalidate(PR_FALSE);
4789 break;
4791 case WM_FONTCHANGE:
4793 nsresult rv;
4794 PRBool didChange = PR_FALSE;
4796 // update the global font list
4797 nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
4798 if (NS_SUCCEEDED(rv)) {
4799 fontEnum->UpdateFontList(&didChange);
4800 //didChange is TRUE only if new font langGroup is added to the list.
4801 if (didChange) {
4802 // update device context font cache
4803 // Dirty but easiest way:
4804 // Changing nsIPrefBranch entry which triggers callbacks
4805 // and flows into calling mDeviceContext->FlushFontCache()
4806 // to update the font cache in all the instance of Browsers
4807 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
4808 if (prefs) {
4809 nsCOMPtr<nsIPrefBranch> fiPrefs;
4810 prefs->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs));
4811 if (fiPrefs) {
4812 PRBool fontInternalChange = PR_FALSE;
4813 fiPrefs->GetBoolPref("changed", &fontInternalChange);
4814 fiPrefs->SetBoolPref("changed", !fontInternalChange);
4818 } //if (NS_SUCCEEDED(rv))
4820 break;
4822 case WM_NCCALCSIZE:
4824 // If wParam is TRUE, it specifies that the application should indicate
4825 // which part of the client area contains valid information. The system
4826 // copies the valid information to the specified area within the new
4827 // client area. If the wParam parameter is FALSE, the application should
4828 // return zero.
4829 if (mCustomNonClient) {
4830 if (!wParam) {
4831 result = PR_TRUE;
4832 *aRetValue = 0;
4833 break;
4836 // before:
4837 // rgrc[0]: the proposed window
4838 // rgrc[1]: the current window
4839 // rgrc[2]: the source client area
4840 // pncsp->lppos: move/size data
4841 // after:
4842 // rgrc[0]: the new client area
4843 // rgrc[1]: the destination window
4844 // rgrc[2]: the source client area
4845 // (all values in screen coordiantes)
4846 NCCALCSIZE_PARAMS *pncsp = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
4847 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd, msg, wParam, lParam);
4848 pncsp->rgrc[0].top -= mNonClientOffset.top;
4849 pncsp->rgrc[0].left -= mNonClientOffset.left;
4850 pncsp->rgrc[0].right += mNonClientOffset.right;
4851 pncsp->rgrc[0].bottom += mNonClientOffset.bottom;
4853 result = PR_TRUE;
4854 *aRetValue = res;
4856 break;
4859 case WM_NCHITTEST:
4862 * If an nc client area margin has been moved, we are responsible
4863 * for calculating where the resize margins are and returning the
4864 * appropriate set of hit test constants. DwmDefWindowProc (above)
4865 * will handle hit testing on it's command buttons if we are on a
4866 * composited desktop.
4869 if (!mCustomNonClient)
4870 break;
4872 *aRetValue =
4873 ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
4874 result = PR_TRUE;
4875 break;
4878 case WM_SETTEXT:
4880 * WM_SETTEXT paints the titlebar area. Avoid this if we have a
4881 * custom titlebar we paint ourselves.
4884 if (!mCustomNonClient || mNonClientMargins.top == -1)
4885 break;
4888 // From msdn, the way around this is to disable the visible state
4889 // temporarily. We need the text to be set but we don't want the
4890 // redraw to occur.
4891 DWORD style = GetWindowLong(mWnd, GWL_STYLE);
4892 SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
4893 *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd,
4894 msg, wParam, lParam);
4895 SetWindowLong(mWnd, GWL_STYLE, style);
4896 return PR_TRUE;
4899 case WM_NCACTIVATE:
4902 * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
4903 * through WM_NCPAINT via InvalidateNonClientRegion.
4906 if (!mCustomNonClient)
4907 break;
4909 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4910 // let the dwm handle nc painting on glass
4911 if(nsUXThemeData::CheckForCompositor())
4912 break;
4913 #endif
4915 if (wParam == TRUE) {
4916 // going active
4917 *aRetValue = FALSE; // ignored
4918 result = PR_TRUE;
4919 UpdateGetWindowInfoCaptionStatus(PR_TRUE);
4920 // invalidate to trigger a paint
4921 InvalidateNonClientRegion();
4922 break;
4923 } else {
4924 // going inactive
4925 *aRetValue = TRUE; // go ahead and deactive
4926 result = PR_TRUE;
4927 UpdateGetWindowInfoCaptionStatus(PR_FALSE);
4928 // invalidate to trigger a paint
4929 InvalidateNonClientRegion();
4930 break;
4934 case WM_NCPAINT:
4937 * Reset the non-client paint region so that it excludes the
4938 * non-client areas we paint manually. Then call defwndproc
4939 * to do the actual painting.
4942 if (!mCustomNonClient)
4943 break;
4945 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4946 // let the dwm handle nc painting on glass
4947 if(nsUXThemeData::CheckForCompositor())
4948 break;
4949 #endif
4951 HRGN paintRgn = ExcludeNonClientFromPaintRegion((HRGN)wParam);
4952 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd,
4953 msg, (WPARAM)paintRgn, lParam);
4954 if (paintRgn != (HRGN)wParam)
4955 DeleteObject(paintRgn);
4956 *aRetValue = res;
4957 result = PR_TRUE;
4959 break;
4961 #ifndef WINCE
4962 case WM_POWERBROADCAST:
4963 // only hidden window handle this
4964 // to prevent duplicate notification
4965 if (mWindowType == eWindowType_invisible) {
4966 switch (wParam)
4968 case PBT_APMSUSPEND:
4969 PostSleepWakeNotification("sleep_notification");
4970 break;
4971 case PBT_APMRESUMEAUTOMATIC:
4972 case PBT_APMRESUMECRITICAL:
4973 case PBT_APMRESUMESUSPEND:
4974 PostSleepWakeNotification("wake_notification");
4975 break;
4978 break;
4979 #endif
4981 case WM_MOVE: // Window moved
4983 RECT rect;
4984 ::GetWindowRect(mWnd, &rect);
4985 result = OnMove(rect.left, rect.top);
4987 break;
4989 case WM_CLOSE: // close request
4990 DispatchStandardEvent(NS_XUL_CLOSE);
4991 result = PR_TRUE; // abort window closure
4992 break;
4994 case WM_DESTROY:
4995 // clean up.
4996 OnDestroy();
4997 result = PR_TRUE;
4998 break;
5000 case WM_PAINT:
5001 *aRetValue = (int) OnPaint(NULL, 0);
5002 result = PR_TRUE;
5003 break;
5005 #ifndef WINCE
5006 case WM_PRINTCLIENT:
5007 result = OnPaint((HDC) wParam, 0);
5008 break;
5009 #endif
5011 case WM_HOTKEY:
5012 result = OnHotKey(wParam, lParam);
5013 break;
5015 case WM_SYSCHAR:
5016 case WM_CHAR:
5018 MSG nativeMsg = InitMSG(msg, wParam, lParam);
5019 result = ProcessCharMessage(nativeMsg, nsnull);
5020 DispatchPendingEvents();
5022 break;
5024 case WM_SYSKEYUP:
5025 case WM_KEYUP:
5027 MSG nativeMsg = InitMSG(msg, wParam, lParam);
5028 result = ProcessKeyUpMessage(nativeMsg, nsnull);
5029 DispatchPendingEvents();
5031 break;
5033 case WM_SYSKEYDOWN:
5034 case WM_KEYDOWN:
5036 MSG nativeMsg = InitMSG(msg, wParam, lParam);
5037 result = ProcessKeyDownMessage(nativeMsg, nsnull);
5038 DispatchPendingEvents();
5040 break;
5042 // say we've dealt with erase background if widget does
5043 // not need auto-erasing
5044 case WM_ERASEBKGND:
5045 if (!AutoErase((HDC)wParam)) {
5046 *aRetValue = 1;
5047 result = PR_TRUE;
5049 break;
5051 case WM_MOUSEMOVE:
5053 #ifdef WINCE_WINDOWS_MOBILE
5054 // Reset the kill timer so that we can continue at this
5055 // priority
5056 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2seconds */, NULL);
5057 #endif
5058 mMousePresent = PR_TRUE;
5060 // Suppress dispatch of pending events
5061 // when mouse moves are generated by widget
5062 // creation instead of user input.
5063 LPARAM lParamScreen = lParamToScreen(lParam);
5064 POINT mp;
5065 mp.x = GET_X_LPARAM(lParamScreen);
5066 mp.y = GET_Y_LPARAM(lParamScreen);
5067 PRBool userMovedMouse = PR_FALSE;
5068 if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) {
5069 userMovedMouse = PR_TRUE;
5072 result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam,
5073 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5074 if (userMovedMouse) {
5075 DispatchPendingEvents();
5078 break;
5080 case WM_NCMOUSEMOVE:
5081 // If we receive a mouse move event on non-client chrome, make sure and
5082 // send an NS_MOUSE_EXIT event as well.
5083 if (mMousePresent && !sIsInMouseCapture)
5084 SendMessage(mWnd, WM_MOUSELEAVE, 0, 0);
5085 break;
5087 #ifdef WINCE_WINDOWS_MOBILE
5088 case WM_TIMER:
5089 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
5090 KillTimer(mWnd, KILL_PRIORITY_ID);
5091 break;
5092 #endif
5094 case WM_LBUTTONDOWN:
5096 #ifdef WINCE_WINDOWS_MOBILE
5097 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
5098 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2 seconds */, NULL);
5099 #endif
5100 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
5101 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5102 DispatchPendingEvents();
5104 break;
5106 case WM_LBUTTONUP:
5108 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam,
5109 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5110 DispatchPendingEvents();
5112 #ifdef WINCE_WINDOWS_MOBILE
5113 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
5114 KillTimer(mWnd, KILL_PRIORITY_ID);
5115 #endif
5117 break;
5119 #ifndef WINCE
5120 case WM_MOUSELEAVE:
5122 if (!mMousePresent)
5123 break;
5124 mMousePresent = PR_FALSE;
5126 // We need to check mouse button states and put them in for
5127 // wParam.
5128 WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
5129 | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
5130 | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
5131 // Synthesize an event position because we don't get one from
5132 // WM_MOUSELEAVE.
5133 LPARAM pos = lParamToClient(::GetMessagePos());
5134 DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, PR_FALSE,
5135 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5137 break;
5138 #endif
5140 case WM_CONTEXTMENU:
5142 // if the context menu is brought up from the keyboard, |lParam|
5143 // will be -1.
5144 LPARAM pos;
5145 PRBool contextMenukey = PR_FALSE;
5146 if (lParam == -1)
5148 contextMenukey = PR_TRUE;
5149 pos = lParamToClient(GetMessagePos());
5151 else
5153 pos = lParamToClient(lParam);
5156 result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey,
5157 contextMenukey ?
5158 nsMouseEvent::eLeftButton :
5159 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5160 if (lParam != -1 && !result && mCustomNonClient &&
5161 DispatchMouseEvent(NS_MOUSE_MOZHITTEST, wParam, pos,
5162 PR_FALSE, nsMouseEvent::eLeftButton,
5163 MOUSE_INPUT_SOURCE())) {
5164 // Blank area hit, throw up the system menu.
5165 DisplaySystemMenu(mWnd, mSizeMode, mIsRTL, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
5166 result = PR_TRUE;
5169 break;
5171 case WM_LBUTTONDBLCLK:
5172 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
5173 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5174 DispatchPendingEvents();
5175 break;
5177 case WM_MBUTTONDOWN:
5178 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
5179 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5180 DispatchPendingEvents();
5181 break;
5183 case WM_MBUTTONUP:
5184 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
5185 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5186 DispatchPendingEvents();
5187 break;
5189 case WM_MBUTTONDBLCLK:
5190 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
5191 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5192 DispatchPendingEvents();
5193 break;
5195 case WM_NCMBUTTONDOWN:
5196 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam), PR_FALSE,
5197 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5198 DispatchPendingEvents();
5199 break;
5201 case WM_NCMBUTTONUP:
5202 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam), PR_FALSE,
5203 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5204 DispatchPendingEvents();
5205 break;
5207 case WM_NCMBUTTONDBLCLK:
5208 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam), PR_FALSE,
5209 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5210 DispatchPendingEvents();
5211 break;
5213 case WM_RBUTTONDOWN:
5214 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
5215 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5216 DispatchPendingEvents();
5217 break;
5219 case WM_RBUTTONUP:
5220 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
5221 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5222 DispatchPendingEvents();
5223 break;
5225 case WM_RBUTTONDBLCLK:
5226 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
5227 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5228 DispatchPendingEvents();
5229 break;
5231 case WM_NCRBUTTONDOWN:
5232 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam),
5233 PR_FALSE, nsMouseEvent::eRightButton,
5234 MOUSE_INPUT_SOURCE());
5235 DispatchPendingEvents();
5236 break;
5238 case WM_NCRBUTTONUP:
5239 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam),
5240 PR_FALSE, nsMouseEvent::eRightButton,
5241 MOUSE_INPUT_SOURCE());
5242 DispatchPendingEvents();
5243 break;
5245 case WM_NCRBUTTONDBLCLK:
5246 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam),
5247 PR_FALSE, nsMouseEvent::eRightButton,
5248 MOUSE_INPUT_SOURCE());
5249 DispatchPendingEvents();
5250 break;
5252 case WM_APPCOMMAND:
5254 PRUint32 appCommand = GET_APPCOMMAND_LPARAM(lParam);
5256 switch (appCommand)
5258 case APPCOMMAND_BROWSER_BACKWARD:
5259 case APPCOMMAND_BROWSER_FORWARD:
5260 case APPCOMMAND_BROWSER_REFRESH:
5261 case APPCOMMAND_BROWSER_STOP:
5262 case APPCOMMAND_BROWSER_SEARCH:
5263 case APPCOMMAND_BROWSER_FAVORITES:
5264 case APPCOMMAND_BROWSER_HOME:
5265 DispatchCommandEvent(appCommand);
5266 // tell the driver that we handled the event
5267 *aRetValue = 1;
5268 result = PR_TRUE;
5269 break;
5271 // default = PR_FALSE - tell the driver that the event was not handled
5273 break;
5275 case WM_HSCROLL:
5276 case WM_VSCROLL:
5277 *aRetValue = 0;
5278 result = OnScroll(msg, wParam, lParam);
5279 break;
5281 // The WM_ACTIVATE event is fired when a window is raised or lowered,
5282 // and the loword of wParam specifies which. But we don't want to tell
5283 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
5284 // events are fired. Instead, set either the sJustGotActivate or
5285 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
5286 // events once the focus events arrive.
5287 case WM_ACTIVATE:
5288 if (mEventCallback) {
5289 PRInt32 fActive = LOWORD(wParam);
5291 #if defined(WINCE_HAVE_SOFTKB)
5292 if (mIsTopWidgetWindow && sSoftKeyboardState)
5293 nsWindowCE::ToggleSoftKB(mWnd, fActive);
5294 if (nsWindowCE::sShowSIPButton == TRI_FALSE && WA_INACTIVE != fActive) {
5295 HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL );
5296 if (hWndSIPB)
5297 ShowWindow(hWndSIPB, SW_HIDE);
5300 #endif
5302 if (WA_INACTIVE == fActive) {
5303 // when minimizing a window, the deactivation and focus events will
5304 // be fired in the reverse order. Instead, just dispatch
5305 // NS_DEACTIVATE right away.
5306 if (HIWORD(wParam))
5307 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5308 else
5309 sJustGotDeactivate = PR_TRUE;
5310 #ifndef WINCE
5311 if (mIsTopWidgetWindow)
5312 mLastKeyboardLayout = gKbdLayout.GetLayout();
5313 #endif
5315 } else {
5316 StopFlashing();
5318 sJustGotActivate = PR_TRUE;
5319 nsMouseEvent event(PR_TRUE, NS_MOUSE_ACTIVATE, this,
5320 nsMouseEvent::eReal);
5321 InitEvent(event);
5322 DispatchWindowEvent(&event);
5323 #ifndef WINCE
5324 if (sSwitchKeyboardLayout && mLastKeyboardLayout)
5325 ActivateKeyboardLayout(mLastKeyboardLayout, 0);
5326 #endif
5329 #ifdef WINCE_WINDOWS_MOBILE
5330 if (!gCheckForHTCApi && gHTCApiNavOpen == nsnull) {
5331 gCheckForHTCApi = PR_TRUE;
5333 HINSTANCE library = LoadLibrary(L"HTCAPI.dll");
5334 gHTCApiNavOpen = (HTCApiNavOpen) GetProcAddress(library, "HTCNavOpen");
5335 gHTCApiNavSetMode = (HTCApiNavSetMode) GetProcAddress(library ,"HTCNavSetMode");
5338 if (gHTCApiNavOpen != nsnull) {
5339 gHTCApiNavOpen(mWnd, 1 /* undocumented value */);
5341 if (gHTCApiNavSetMode != nsnull)
5342 gHTCApiNavSetMode ( mWnd, 4);
5343 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5345 #endif
5346 break;
5348 #ifndef WINCE
5349 case WM_MOUSEACTIVATE:
5350 if (mWindowType == eWindowType_popup) {
5351 // a popup with a parent owner should not be activated when clicked
5352 // but should still allow the mouse event to be fired, so the return
5353 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5354 // window, just use default processing so that the window is activated.
5355 HWND owner = ::GetWindow(mWnd, GW_OWNER);
5356 if (owner && owner == ::GetForegroundWindow()) {
5357 *aRetValue = MA_NOACTIVATE;
5358 result = PR_TRUE;
5361 break;
5363 case WM_WINDOWPOSCHANGING:
5365 LPWINDOWPOS info = (LPWINDOWPOS) lParam;
5366 OnWindowPosChanging(info);
5368 break;
5369 #endif
5371 case WM_SETFOCUS:
5372 // If previous focused window isn't ours, it must have received the
5373 // redirected message. So, we should forget it.
5374 if (!IsOurProcessWindow(HWND(wParam))) {
5375 ForgetRedirectedKeyDownMessage();
5377 if (sJustGotActivate) {
5378 result = DispatchFocusToTopLevelWindow(NS_ACTIVATE);
5381 #ifdef ACCESSIBILITY
5382 if (nsWindow::sIsAccessibilityOn) {
5383 // Create it for the first time so that it can start firing events
5384 nsAccessible *rootAccessible = GetRootAccessible();
5386 #endif
5388 #if defined(WINCE_HAVE_SOFTKB)
5390 // On Windows CE, we have a window that overlaps
5391 // the ISP button. In this case, we should always
5392 // try to hide it when we are activated
5394 nsIMEContext IMEContext(mWnd);
5395 // Open the IME
5396 ImmSetOpenStatus(IMEContext.get(), TRUE);
5398 #endif
5399 break;
5401 case WM_KILLFOCUS:
5402 #if defined(WINCE_HAVE_SOFTKB)
5404 nsIMEContext IMEContext(mWnd);
5405 ImmSetOpenStatus(IMEContext.get(), FALSE);
5407 #endif
5408 if (sJustGotDeactivate) {
5409 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5411 break;
5413 case WM_WINDOWPOSCHANGED:
5415 WINDOWPOS *wp = (LPWINDOWPOS)lParam;
5416 OnWindowPosChanged(wp, result);
5418 break;
5420 case WM_SETTINGCHANGE:
5421 #if !defined (WINCE_WINDOWS_MOBILE)
5422 getWheelInfo = PR_TRUE;
5423 #else
5424 switch (wParam) {
5425 case SPI_SETSIPINFO:
5426 case SPI_SETCURRENTIM:
5427 nsWindowCE::OnSoftKbSettingsChange(mWnd);
5428 break;
5429 case SETTINGCHANGE_RESET:
5430 if (mWindowType == eWindowType_invisible) {
5431 // The OS sees to get confused and think that the invisable window
5432 // is in the foreground after an orientation change. By actually
5433 // setting it to the foreground and hiding it, we set it strait.
5434 // See bug 514007 for details.
5435 SetForegroundWindow(mWnd);
5436 ShowWindow(mWnd, SW_HIDE);
5438 break;
5440 #endif
5441 OnSettingsChange(wParam, lParam);
5442 break;
5444 #ifndef WINCE
5445 case WM_INPUTLANGCHANGEREQUEST:
5446 *aRetValue = TRUE;
5447 result = PR_FALSE;
5448 break;
5450 case WM_INPUTLANGCHANGE:
5451 result = OnInputLangChange((HKL)lParam);
5452 break;
5453 #endif // WINCE
5455 case WM_DESTROYCLIPBOARD:
5457 nsIClipboard* clipboard;
5458 nsresult rv = CallGetService(kCClipboardCID, &clipboard);
5459 if(NS_SUCCEEDED(rv)) {
5460 clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
5461 NS_RELEASE(clipboard);
5464 break;
5466 #ifdef ACCESSIBILITY
5467 case WM_GETOBJECT:
5469 *aRetValue = 0;
5470 if (lParam == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
5471 nsAccessible *rootAccessible = GetRootAccessible(); // Held by a11y cache
5472 if (rootAccessible) {
5473 IAccessible *msaaAccessible = NULL;
5474 rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref
5475 if (msaaAccessible) {
5476 *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref
5477 msaaAccessible->Release(); // release extra addref
5478 result = PR_TRUE; // We handled the WM_GETOBJECT message
5483 #endif
5485 #ifndef WINCE
5486 case WM_SYSCOMMAND:
5488 WPARAM filteredWParam = (wParam &0xFFF0);
5489 // prevent Windows from trimming the working set. bug 76831
5490 if (!sTrimOnMinimize && filteredWParam == SC_MINIMIZE) {
5491 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
5492 result = PR_TRUE;
5495 // Handle the system menu manually when we're in full screen mode
5496 // so we can set the appropriate options.
5497 if (filteredWParam == SC_KEYMENU && lParam == VK_SPACE &&
5498 mSizeMode == nsSizeMode_Fullscreen) {
5499 DisplaySystemMenu(mWnd, mSizeMode, mIsRTL,
5500 MOZ_SYSCONTEXT_X_POS,
5501 MOZ_SYSCONTEXT_Y_POS);
5502 result = PR_TRUE;
5505 break;
5506 #endif
5509 #ifdef WINCE
5510 case WM_HIBERNATE:
5511 nsMemory::HeapMinimize(PR_TRUE);
5512 break;
5513 #endif
5515 case WM_MOUSEWHEEL:
5516 case WM_MOUSEHWHEEL:
5518 // If OnMouseWheel returns true, the event was forwarded directly to another
5519 // mozilla window message handler (ProcessMessage). In this case the return
5520 // value of the forwarded event is in 'result' which we should return immediately.
5521 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5522 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5523 // we should fall through.
5524 if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue))
5525 return result;
5527 break;
5529 #ifndef WINCE
5530 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5531 case WM_DWMCOMPOSITIONCHANGED:
5532 // First, update the compositor state to latest one. All other methods
5533 // should use same state as here for consistency painting.
5534 nsUXThemeData::CheckForCompositor(PR_TRUE);
5536 UpdateNonClientMargins();
5537 RemovePropW(mWnd, kManageWindowInfoProperty);
5538 BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
5539 DispatchStandardEvent(NS_THEMECHANGED);
5540 UpdateGlass();
5541 Invalidate(PR_FALSE);
5542 break;
5543 #endif
5545 case WM_UPDATEUISTATE:
5547 // If the UI state has changed, fire an event so the UI updates the
5548 // keyboard cues based on the system setting and how the window was
5549 // opened. For example, a dialog opened via a keyboard press on a button
5550 // should enable cues, whereas the same dialog opened via a mouse click of
5551 // the button should not.
5552 PRInt32 action = LOWORD(wParam);
5553 if (action == UIS_SET || action == UIS_CLEAR) {
5554 nsUIStateChangeEvent event(PR_TRUE, NS_UISTATECHANGED, this);
5555 PRInt32 flags = HIWORD(wParam);
5556 if (flags & UISF_HIDEACCEL)
5557 event.showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5558 if (flags & UISF_HIDEFOCUS)
5559 event.showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5560 DispatchWindowEvent(&event);
5563 break;
5566 /* Gesture support events */
5567 case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
5568 // According to MS samples, this must be handled to enable
5569 // rotational support in multi-touch drivers.
5570 result = PR_TRUE;
5571 *aRetValue = TABLET_ROTATE_GESTURE_ENABLE;
5572 break;
5574 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5575 case WM_TOUCH:
5576 result = OnTouch(wParam, lParam);
5577 if (result) {
5578 *aRetValue = 0;
5580 break;
5581 #endif
5583 case WM_GESTURE:
5584 result = OnGesture(wParam, lParam);
5585 break;
5587 case WM_GESTURENOTIFY:
5589 if (mWindowType != eWindowType_invisible &&
5590 mWindowType != eWindowType_plugin) {
5591 // A GestureNotify event is dispatched to decide which single-finger panning
5592 // direction should be active (including none) and if pan feedback should
5593 // be displayed. Java and plugin windows can make their own calls.
5594 GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
5595 nsPointWin touchPoint;
5596 touchPoint = gestureinfo->ptsLocation;
5597 touchPoint.ScreenToClient(mWnd);
5598 nsGestureNotifyEvent gestureNotifyEvent(PR_TRUE, NS_GESTURENOTIFY_EVENT_START, this);
5599 gestureNotifyEvent.refPoint = touchPoint;
5600 nsEventStatus status;
5601 DispatchEvent(&gestureNotifyEvent, status);
5602 mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
5603 if (!mTouchWindow)
5604 mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
5606 result = PR_FALSE; //should always bubble to DefWindowProc
5608 break;
5609 #endif // !defined(WINCE)
5611 case WM_CLEAR:
5613 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_DELETE, this);
5614 DispatchWindowEvent(&command);
5615 result = PR_TRUE;
5617 break;
5619 case WM_CUT:
5621 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_CUT, this);
5622 DispatchWindowEvent(&command);
5623 result = PR_TRUE;
5625 break;
5627 case WM_COPY:
5629 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_COPY, this);
5630 DispatchWindowEvent(&command);
5631 result = PR_TRUE;
5633 break;
5635 case WM_PASTE:
5637 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE, this);
5638 DispatchWindowEvent(&command);
5639 result = PR_TRUE;
5641 break;
5643 #ifndef WINCE
5644 case EM_UNDO:
5646 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO, this);
5647 DispatchWindowEvent(&command);
5648 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5649 result = PR_TRUE;
5651 break;
5653 case EM_REDO:
5655 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO, this);
5656 DispatchWindowEvent(&command);
5657 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5658 result = PR_TRUE;
5660 break;
5662 case EM_CANPASTE:
5664 // Support EM_CANPASTE message only when wParam isn't specified or
5665 // is plain text format.
5666 if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
5667 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE,
5668 this, PR_TRUE);
5669 DispatchWindowEvent(&command);
5670 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5671 result = PR_TRUE;
5674 break;
5676 case EM_CANUNDO:
5678 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO,
5679 this, PR_TRUE);
5680 DispatchWindowEvent(&command);
5681 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5682 result = PR_TRUE;
5684 break;
5686 case EM_CANREDO:
5688 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO,
5689 this, PR_TRUE);
5690 DispatchWindowEvent(&command);
5691 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5692 result = PR_TRUE;
5694 break;
5695 #endif
5697 #ifdef WINCE_WINDOWS_MOBILE
5698 //HTC NAVIGATION WHEEL EVENT
5699 case WM_HTCNAV:
5701 int distance = wParam & 0x000000FF;
5702 if ( (wParam & 0x000000100) != 0) // Counter Clockwise
5703 distance *= -1;
5704 if (OnMouseWheel(WM_MOUSEWHEEL, MAKEWPARAM(0, distance),
5705 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN) / 2,
5706 GetSystemMetrics(SM_CYSCREEN) / 2),
5707 getWheelInfo, result, aRetValue))
5708 return result;
5710 break;
5711 #endif
5713 default:
5715 #ifdef NS_ENABLE_TSF
5716 if (msg == WM_USER_TSF_TEXTCHANGE) {
5717 nsTextStore::OnTextChangeMsg();
5719 #endif //NS_ENABLE_TSF
5720 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5721 if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
5722 SetHasTaskbarIconBeenCreated();
5723 #endif
5724 #ifdef MOZ_IPC
5725 if (msg == sOOPPPluginFocusEvent) {
5726 if (wParam == 1) {
5727 // With OOPP, the plugin window exists in another process and is a child of
5728 // this window. This window is a placeholder plugin window for the dom. We
5729 // receive this event when the child window receives focus. (sent from
5730 // PluginInstanceParent.cpp)
5731 ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
5732 } else {
5733 // WM_KILLFOCUS was received by the child process.
5734 if (sJustGotDeactivate) {
5735 DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5739 #endif
5741 break;
5744 //*aRetValue = result;
5745 if (mWnd) {
5746 return result;
5748 else {
5749 //Events which caused mWnd destruction and aren't consumed
5750 //will crash during the Windows default processing.
5751 return PR_TRUE;
5755 /**************************************************************
5757 * SECTION: Broadcast messaging
5759 * Broadcast messages to all windows.
5761 **************************************************************/
5763 // Enumerate all child windows sending aMsg to each of them
5764 BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg)
5766 WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
5767 if (winProc == &nsWindow::WindowProc) {
5768 // it's one of our windows so go ahead and send a message to it
5769 ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0);
5771 return TRUE;
5774 // Enumerate all top level windows specifying that the children of each
5775 // top level window should be enumerated. Do *not* send the message to
5776 // each top level window since it is assumed that the toolkit will send
5777 // aMsg to them directly.
5778 BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg)
5780 // Iterate each of aTopWindows child windows sending the aMsg
5781 // to each of them.
5782 #if !defined(WINCE)
5783 ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5784 #else
5785 nsWindowCE::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5786 #endif
5787 return TRUE;
5790 // This method is called from nsToolkit::WindowProc to forward global
5791 // messages which need to be dispatched to all child windows.
5792 void nsWindow::GlobalMsgWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
5794 switch (msg) {
5795 case WM_SYSCOLORCHANGE:
5796 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5797 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5798 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5799 // all child windows as well. When running in an embedded application
5800 // we may not receive a WM_SYSCOLORCHANGE message because the top
5801 // level window is owned by the embeddor.
5802 // System color changes are posted to top-level windows only.
5803 // The NS_SYSCOLORCHANGE must be dispatched to all child
5804 // windows as well.
5805 #if !defined(WINCE)
5806 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, msg);
5807 #endif
5808 break;
5812 /**************************************************************
5814 * SECTION: Event processing helpers
5816 * Special processing for certain event types and
5817 * synthesized events.
5819 **************************************************************/
5821 PRInt32
5822 nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
5824 // Calculations are done in screen coords
5825 RECT winRect;
5826 GetWindowRect(mWnd, &winRect);
5828 // hit return constants:
5829 // HTBORDER - non-resizable border
5830 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5831 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5832 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5833 // HTCAPTION - general title bar area
5834 // HTCLIENT - area considered the client
5835 // HTCLOSE - hovering over the close button
5836 // HTMAXBUTTON - maximize button
5837 // HTMINBUTTON - minimize button
5839 PRInt32 testResult = HTCLIENT;
5841 PRBool top = PR_FALSE;
5842 PRBool bottom = PR_FALSE;
5843 PRBool left = PR_FALSE;
5844 PRBool right = PR_FALSE;
5846 if (my >= winRect.top && my <
5847 (winRect.top + mVertResizeMargin + (mCaptionHeight - mNonClientOffset.top)))
5848 top = PR_TRUE;
5849 else if (my < winRect.bottom && my >= (winRect.bottom - mVertResizeMargin))
5850 bottom = PR_TRUE;
5852 if (mx >= winRect.left && mx < (winRect.left +
5853 (bottom ? (2*mHorResizeMargin) : mHorResizeMargin)))
5854 left = PR_TRUE;
5855 else if (mx < winRect.right && mx >= (winRect.right -
5856 (bottom ? (2*mHorResizeMargin) : mHorResizeMargin)))
5857 right = PR_TRUE;
5859 if (top) {
5860 testResult = HTTOP;
5861 if (left)
5862 testResult = HTTOPLEFT;
5863 else if (right)
5864 testResult = HTTOPRIGHT;
5865 } else if (bottom) {
5866 testResult = HTBOTTOM;
5867 if (left)
5868 testResult = HTBOTTOMLEFT;
5869 else if (right)
5870 testResult = HTBOTTOMRIGHT;
5871 } else {
5872 if (left)
5873 testResult = HTLEFT;
5874 if (right)
5875 testResult = HTRIGHT;
5878 PRBool contentOverlap = PR_TRUE;
5880 if (mSizeMode == nsSizeMode_Maximized) {
5881 // There's no HTTOP in maximized state (bug 575493)
5882 if (testResult == HTTOP) {
5883 testResult = HTCAPTION;
5885 } else {
5886 PRInt32 leftMargin = mNonClientMargins.left == -1 ? mHorResizeMargin : mNonClientMargins.left;
5887 PRInt32 rightMargin = mNonClientMargins.right == -1 ? mHorResizeMargin : mNonClientMargins.right;
5888 PRInt32 topMargin = mNonClientMargins.top == -1 ? mVertResizeMargin : mNonClientMargins.top;
5889 PRInt32 bottomMargin = mNonClientMargins.bottom == -1 ? mVertResizeMargin : mNonClientMargins.bottom;
5891 contentOverlap = mx >= winRect.left + leftMargin &&
5892 mx <= winRect.right - rightMargin &&
5893 my >= winRect.top + topMargin &&
5894 my <= winRect.bottom - bottomMargin;
5897 if (!sIsInMouseCapture &&
5898 contentOverlap &&
5899 (testResult == HTCLIENT ||
5900 testResult == HTTOP ||
5901 testResult == HTTOPLEFT ||
5902 testResult == HTCAPTION)) {
5903 LPARAM lParam = MAKELPARAM(mx, my);
5904 LPARAM lParamClient = lParamToClient(lParam);
5905 PRBool result = DispatchMouseEvent(NS_MOUSE_MOZHITTEST, 0, lParamClient,
5906 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5907 if (result) {
5908 // The mouse is over a blank area
5909 testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
5911 } else {
5912 // There's content over the mouse pointer. Set HTCLIENT
5913 // to possibly override a resizer border.
5914 testResult = HTCLIENT;
5918 return testResult;
5921 #ifndef WINCE
5922 void nsWindow::PostSleepWakeNotification(const char* aNotification)
5924 nsCOMPtr<nsIObserverService> observerService =
5925 mozilla::services::GetObserverService();
5926 if (observerService)
5927 observerService->NotifyObservers(nsnull, aNotification, nsnull);
5929 #endif
5931 // RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
5932 // message handler. If there is no WM_(SYS)CHAR message for it, this
5933 // method does nothing.
5934 // NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
5935 // called in message loop. So, WM_(SYS)KEYDOWN message should have
5936 // WM_(SYS)CHAR message in the queue if the keydown event causes character
5937 // input.
5939 /* static */
5940 void nsWindow::RemoveNextCharMessage(HWND aWnd)
5942 MSG msg;
5943 if (::PeekMessageW(&msg, aWnd,
5944 WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD) &&
5945 (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) {
5946 ::GetMessageW(&msg, aWnd, msg.message, msg.message);
5950 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, PRBool *aEventDispatched)
5952 NS_PRECONDITION(aMsg.message == WM_CHAR || aMsg.message == WM_SYSCHAR,
5953 "message is not keydown event");
5954 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5955 ("%s charCode=%d scanCode=%d\n",
5956 aMsg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
5957 aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF));
5959 // These must be checked here too as a lone WM_CHAR could be received
5960 // if a child window didn't handle it (for example Alt+Space in a content window)
5961 nsModifierKeyState modKeyState;
5962 return OnChar(aMsg, modKeyState, aEventDispatched);
5965 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, PRBool *aEventDispatched)
5967 NS_PRECONDITION(aMsg.message == WM_KEYUP || aMsg.message == WM_SYSKEYUP,
5968 "message is not keydown event");
5969 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5970 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5971 "WM_SYSKEYUP" : "WM_KEYUP", aMsg.wParam));
5973 nsModifierKeyState modKeyState;
5975 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5976 // scan code. However, this breaks Alt+Num pad input.
5977 // MSDN states the following:
5978 // Typically, ToAscii performs the translation based on the
5979 // virtual-key code. In some cases, however, bit 15 of the
5980 // uScanCode parameter may be used to distinguish between a key
5981 // press and a key release. The scan code is used for
5982 // translating ALT+number key combinations.
5984 // ignore [shift+]alt+space so the OS can handle it
5985 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5986 IS_VK_DOWN(NS_VK_SPACE)) {
5987 return FALSE;
5990 if (!nsIMM32Handler::IsComposingOn(this) &&
5991 (aMsg.message != WM_KEYUP || aMsg.wParam != VK_MENU)) {
5992 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5993 // This helps avoid triggering the menu bar for ALT key accelerators used in
5994 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5995 // to switch back to Mozilla in Windows 95 and Windows 98
5996 return OnKeyUp(aMsg, modKeyState, aEventDispatched);
5999 return 0;
6002 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
6003 PRBool *aEventDispatched)
6005 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6006 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
6007 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg.wParam));
6008 NS_PRECONDITION(aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN,
6009 "message is not keydown event");
6011 // If this method doesn't call OnKeyDown(), this method must clean up the
6012 // redirected message information itself. For more information, see above
6013 // comment of AutoForgetRedirectedKeyDownMessage struct definition in
6014 // nsWindow.h.
6015 AutoForgetRedirectedKeyDownMessage forgetRedirectedMessage(this, aMsg);
6017 nsModifierKeyState modKeyState;
6019 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
6020 // scan code. However, this breaks Alt+Num pad input.
6021 // MSDN states the following:
6022 // Typically, ToAscii performs the translation based on the
6023 // virtual-key code. In some cases, however, bit 15 of the
6024 // uScanCode parameter may be used to distinguish between a key
6025 // press and a key release. The scan code is used for
6026 // translating ALT+number key combinations.
6028 // ignore [shift+]alt+space so the OS can handle it
6029 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
6030 IS_VK_DOWN(NS_VK_SPACE))
6031 return FALSE;
6033 LRESULT result = 0;
6034 if (modKeyState.mIsAltDown && nsIMM32Handler::IsStatusChanged()) {
6035 nsIMM32Handler::NotifyEndStatusChange();
6036 } else if (!nsIMM32Handler::IsComposingOn(this)) {
6037 result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nsnull);
6038 // OnKeyDown cleaned up the redirected message information itself, so,
6039 // we should do nothing.
6040 forgetRedirectedMessage.mCancel = PR_TRUE;
6043 #ifndef WINCE
6044 if (aMsg.wParam == VK_MENU ||
6045 (aMsg.wParam == VK_F10 && !modKeyState.mIsShiftDown)) {
6046 // We need to let Windows handle this keypress,
6047 // by returning PR_FALSE, if there's a native menu
6048 // bar somewhere in our containing window hierarchy.
6049 // Otherwise we handle the keypress and don't pass
6050 // it on to Windows, by returning PR_TRUE.
6051 PRBool hasNativeMenu = PR_FALSE;
6052 HWND hWnd = mWnd;
6053 while (hWnd) {
6054 if (::GetMenu(hWnd)) {
6055 hasNativeMenu = PR_TRUE;
6056 break;
6058 hWnd = ::GetParent(hWnd);
6060 result = !hasNativeMenu;
6062 #endif
6064 return result;
6067 nsresult
6068 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
6069 PRInt32 aNativeKeyCode,
6070 PRUint32 aModifierFlags,
6071 const nsAString& aCharacters,
6072 const nsAString& aUnmodifiedCharacters)
6074 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
6075 nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
6076 HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
6077 if (loadedLayout == NULL)
6078 return NS_ERROR_NOT_AVAILABLE;
6080 // Setup clean key state and load desired layout
6081 BYTE originalKbdState[256];
6082 ::GetKeyboardState(originalKbdState);
6083 BYTE kbdState[256];
6084 memset(kbdState, 0, sizeof(kbdState));
6085 // This changes the state of the keyboard for the current thread only,
6086 // and we'll restore it soon, so this should be OK.
6087 ::SetKeyboardState(kbdState);
6088 HKL oldLayout = gKbdLayout.GetLayout();
6089 gKbdLayout.LoadLayout(loadedLayout);
6091 nsAutoTArray<KeyPair,10> keySequence;
6092 SetupKeyModifiersSequence(&keySequence, aModifierFlags);
6093 NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
6094 "Native VK key code out of range");
6095 keySequence.AppendElement(KeyPair(aNativeKeyCode, 0));
6097 // Simulate the pressing of each modifier key and then the real key
6098 for (PRUint32 i = 0; i < keySequence.Length(); ++i) {
6099 PRUint8 key = keySequence[i].mGeneral;
6100 PRUint8 keySpecific = keySequence[i].mSpecific;
6101 kbdState[key] = 0x81; // key is down and toggled on if appropriate
6102 if (keySpecific) {
6103 kbdState[keySpecific] = 0x81;
6105 ::SetKeyboardState(kbdState);
6106 nsModifierKeyState modKeyState;
6107 MSG msg = InitMSG(WM_KEYDOWN, key, 0);
6108 if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
6109 UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
6110 gKbdLayout.GetLayout());
6111 nsFakeCharMessage fakeMsg = { aCharacters.CharAt(0), scanCode };
6112 OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
6113 } else {
6114 OnKeyDown(msg, modKeyState, nsnull, nsnull);
6117 for (PRUint32 i = keySequence.Length(); i > 0; --i) {
6118 PRUint8 key = keySequence[i - 1].mGeneral;
6119 PRUint8 keySpecific = keySequence[i - 1].mSpecific;
6120 kbdState[key] = 0; // key is up and toggled off if appropriate
6121 if (keySpecific) {
6122 kbdState[keySpecific] = 0;
6124 ::SetKeyboardState(kbdState);
6125 nsModifierKeyState modKeyState;
6126 MSG msg = InitMSG(WM_KEYUP, key, 0);
6127 OnKeyUp(msg, modKeyState, nsnull);
6130 // Restore old key state and layout
6131 ::SetKeyboardState(originalKbdState);
6132 gKbdLayout.LoadLayout(oldLayout);
6134 UnloadKeyboardLayout(loadedLayout);
6135 return NS_OK;
6136 #else //XXX: is there another way to do this?
6137 return NS_ERROR_NOT_IMPLEMENTED;
6138 #endif
6141 nsresult
6142 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
6143 PRUint32 aNativeMessage,
6144 PRUint32 aModifierFlags)
6146 #ifndef WINCE // I don't think WINCE supports SendInput
6147 RECT r;
6148 ::GetWindowRect(mWnd, &r);
6149 ::SetCursorPos(r.left + aPoint.x, r.top + aPoint.y);
6151 INPUT input;
6152 memset(&input, 0, sizeof(input));
6154 input.type = INPUT_MOUSE;
6155 input.mi.dwFlags = aNativeMessage;
6156 ::SendInput(1, &input, sizeof(INPUT));
6158 return NS_OK;
6159 #else
6160 return NS_ERROR_NOT_IMPLEMENTED;
6161 #endif
6164 /**************************************************************
6166 * SECTION: OnXXX message handlers
6168 * For message handlers that need to be broken out or
6169 * implemented in specific platform code.
6171 **************************************************************/
6173 BOOL nsWindow::OnInputLangChange(HKL aHKL)
6175 #ifdef KE_DEBUG
6176 printf("OnInputLanguageChange\n");
6177 #endif
6179 #ifndef WINCE
6180 gKbdLayout.LoadLayout(aHKL);
6181 #endif
6183 return PR_FALSE; // always pass to child window
6186 #if !defined(WINCE) // implemented in nsWindowCE.cpp
6187 void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, PRBool& result)
6189 if (wp == nsnull)
6190 return;
6192 #ifdef WINSTATE_DEBUG_OUTPUT
6193 if (mWnd == GetTopLevelHWND(mWnd))
6194 printf("*** OnWindowPosChanged: [ top] ");
6195 else
6196 printf("*** OnWindowPosChanged: [child] ");
6197 printf("WINDOWPOS flags:");
6198 if (wp->flags & SWP_FRAMECHANGED)
6199 printf("SWP_FRAMECHANGED ");
6200 if (wp->flags & SWP_SHOWWINDOW)
6201 printf("SWP_SHOWWINDOW ");
6202 if (wp->flags & SWP_NOSIZE)
6203 printf("SWP_NOSIZE ");
6204 if (wp->flags & SWP_HIDEWINDOW)
6205 printf("SWP_HIDEWINDOW ");
6206 if (wp->flags & SWP_NOZORDER)
6207 printf("SWP_NOZORDER ");
6208 if (wp->flags & SWP_NOACTIVATE)
6209 printf("SWP_NOACTIVATE ");
6210 printf("\n");
6211 #endif
6213 // Handle window size mode changes
6214 if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
6216 // Bug 566135 - Windows theme code calls show window on SW_SHOWMINIMIZED
6217 // windows when fullscreen games disable desktop composition. If we're
6218 // minimized and not being activated, ignore the event and let windows
6219 // handle it.
6220 if (mSizeMode == nsSizeMode_Minimized && (wp->flags & SWP_NOACTIVATE))
6221 return;
6223 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
6225 WINDOWPLACEMENT pl;
6226 pl.length = sizeof(pl);
6227 ::GetWindowPlacement(mWnd, &pl);
6229 if (pl.showCmd == SW_SHOWMAXIMIZED)
6230 event.mSizeMode = nsSizeMode_Maximized;
6231 else if (pl.showCmd == SW_SHOWMINIMIZED)
6232 event.mSizeMode = nsSizeMode_Minimized;
6233 else if (mFullscreenMode)
6234 event.mSizeMode = nsSizeMode_Fullscreen;
6235 else
6236 event.mSizeMode = nsSizeMode_Normal;
6238 // Windows has just changed the size mode of this window. The following
6239 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
6240 // set the min/max window state again or for nsSizeMode_Normal, call
6241 // SetWindow with a parameter of SW_RESTORE. There's no need however as
6242 // this window's mode has already changed. Updating mSizeMode here
6243 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
6244 // to window docking. (bug 489258)
6245 mSizeMode = event.mSizeMode;
6247 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
6248 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
6249 // prevents the working set from being trimmed but keeps the window active.
6250 // After the window is minimized, we need to do some touch up work on the
6251 // active window. (bugs 76831 & 499816)
6252 if (!sTrimOnMinimize && nsSizeMode_Minimized == event.mSizeMode)
6253 ActivateOtherWindowHelper(mWnd);
6255 #ifdef WINSTATE_DEBUG_OUTPUT
6256 switch (mSizeMode) {
6257 case nsSizeMode_Normal:
6258 printf("*** mSizeMode: nsSizeMode_Normal\n");
6259 break;
6260 case nsSizeMode_Minimized:
6261 printf("*** mSizeMode: nsSizeMode_Minimized\n");
6262 break;
6263 case nsSizeMode_Maximized:
6264 printf("*** mSizeMode: nsSizeMode_Maximized\n");
6265 break;
6266 default:
6267 printf("*** mSizeMode: ??????\n");
6268 break;
6270 #endif
6272 InitEvent(event);
6274 result = DispatchWindowEvent(&event);
6276 // Skip window size change events below on minimization.
6277 if (mSizeMode == nsSizeMode_Minimized)
6278 return;
6281 // Handle window size changes
6282 if (!(wp->flags & SWP_NOSIZE)) {
6283 RECT r;
6284 PRInt32 newWidth, newHeight;
6286 ::GetWindowRect(mWnd, &r);
6288 newWidth = r.right - r.left;
6289 newHeight = r.bottom - r.top;
6290 nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
6292 #ifdef MOZ_XUL
6293 if (eTransparencyTransparent == mTransparencyMode)
6294 ResizeTranslucentWindow(newWidth, newHeight);
6295 #endif
6297 if (newWidth > mLastSize.width)
6299 RECT drect;
6301 // getting wider
6302 drect.left = wp->x + mLastSize.width;
6303 drect.top = wp->y;
6304 drect.right = drect.left + (newWidth - mLastSize.width);
6305 drect.bottom = drect.top + newHeight;
6307 ::RedrawWindow(mWnd, &drect, NULL,
6308 RDW_INVALIDATE |
6309 RDW_NOERASE |
6310 RDW_NOINTERNALPAINT |
6311 RDW_ERASENOW |
6312 RDW_ALLCHILDREN);
6314 if (newHeight > mLastSize.height)
6316 RECT drect;
6318 // getting taller
6319 drect.left = wp->x;
6320 drect.top = wp->y + mLastSize.height;
6321 drect.right = drect.left + newWidth;
6322 drect.bottom = drect.top + (newHeight - mLastSize.height);
6324 ::RedrawWindow(mWnd, &drect, NULL,
6325 RDW_INVALIDATE |
6326 RDW_NOERASE |
6327 RDW_NOINTERNALPAINT |
6328 RDW_ERASENOW |
6329 RDW_ALLCHILDREN);
6332 mBounds.width = newWidth;
6333 mBounds.height = newHeight;
6334 mLastSize.width = newWidth;
6335 mLastSize.height = newHeight;
6337 #ifdef WINSTATE_DEBUG_OUTPUT
6338 printf("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, newWidth, newHeight);
6339 #endif
6341 // If a maximized window is resized, recalculate the non-client margins and
6342 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
6343 // work properly.
6344 if (mSizeMode == nsSizeMode_Maximized) {
6345 if (UpdateNonClientMargins(nsSizeMode_Maximized, PR_TRUE)) {
6346 // gecko resize event already sent by UpdateNonClientMargins.
6347 result = PR_TRUE;
6348 return;
6352 // Recalculate the width and height based on the client area for gecko events.
6353 if (::GetClientRect(mWnd, &r)) {
6354 rect.width = r.right - r.left;
6355 rect.height = r.bottom - r.top;
6358 // Send a gecko resize event
6359 result = OnResize(rect);
6363 // static
6364 void nsWindow::ActivateOtherWindowHelper(HWND aWnd)
6366 // Find the next window that is enabled, visible, and not minimized.
6367 HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT);
6368 while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) ||
6369 ::IsIconic(hwndBelow))) {
6370 hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT);
6373 // Push ourselves to the bottom of the stack, then activate the
6374 // next window.
6375 ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0,
6376 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
6377 if (hwndBelow)
6378 ::SetForegroundWindow(hwndBelow);
6380 // Play the minimize sound while we're here, since that is also
6381 // forgotten when we use SW_SHOWMINIMIZED.
6382 ::PlaySoundW(L"Minimize", nsnull, SND_ALIAS | SND_NODEFAULT | SND_ASYNC);
6384 #endif // !defined(WINCE)
6386 #if !defined(WINCE)
6387 void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info)
6389 // Update non-client margins if the frame size is changing, and let the
6390 // browser know we are changing size modes, so alternative css can kick in.
6391 // If we're going into fullscreen mode, ignore this, since it'll reset
6392 // margins to normal mode.
6393 if ((info->flags & SWP_FRAMECHANGED && !(info->flags & SWP_NOSIZE)) &&
6394 mSizeMode != nsSizeMode_Fullscreen) {
6395 WINDOWPLACEMENT pl;
6396 pl.length = sizeof(pl);
6397 ::GetWindowPlacement(mWnd, &pl);
6398 PRInt32 sizeMode;
6399 if (pl.showCmd == SW_SHOWMAXIMIZED)
6400 sizeMode = nsSizeMode_Maximized;
6401 else if (pl.showCmd == SW_SHOWMINIMIZED)
6402 sizeMode = nsSizeMode_Minimized;
6403 else if (mFullscreenMode)
6404 sizeMode = nsSizeMode_Fullscreen;
6405 else
6406 sizeMode = nsSizeMode_Normal;
6408 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
6410 InitEvent(event);
6411 event.mSizeMode = static_cast<nsSizeMode>(sizeMode);
6412 DispatchWindowEvent(&event);
6414 UpdateNonClientMargins(sizeMode, PR_FALSE);
6417 // enforce local z-order rules
6418 if (!(info->flags & SWP_NOZORDER)) {
6419 HWND hwndAfter = info->hwndInsertAfter;
6421 nsZLevelEvent event(PR_TRUE, NS_SETZLEVEL, this);
6422 nsWindow *aboveWindow = 0;
6424 InitEvent(event);
6426 if (hwndAfter == HWND_BOTTOM)
6427 event.mPlacement = nsWindowZBottom;
6428 else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
6429 event.mPlacement = nsWindowZTop;
6430 else {
6431 event.mPlacement = nsWindowZRelative;
6432 aboveWindow = GetNSWindowPtr(hwndAfter);
6434 event.mReqBelow = aboveWindow;
6435 event.mActualBelow = nsnull;
6437 event.mImmediate = PR_FALSE;
6438 event.mAdjusted = PR_FALSE;
6439 DispatchWindowEvent(&event);
6441 if (event.mAdjusted) {
6442 if (event.mPlacement == nsWindowZBottom)
6443 info->hwndInsertAfter = HWND_BOTTOM;
6444 else if (event.mPlacement == nsWindowZTop)
6445 info->hwndInsertAfter = HWND_TOP;
6446 else {
6447 info->hwndInsertAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
6450 NS_IF_RELEASE(event.mActualBelow);
6452 // prevent rude external programs from making hidden window visible
6453 if (mWindowType == eWindowType_invisible)
6454 info->flags &= ~SWP_SHOWWINDOW;
6456 #endif
6458 void nsWindow::UserActivity()
6460 // Check if we have the idle service, if not we try to get it.
6461 if (!mIdleService) {
6462 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
6465 // Check that we now have the idle service.
6466 if (mIdleService) {
6467 mIdleService->ResetIdleTimeOut();
6471 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6472 PRBool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam)
6474 PRUint32 cInputs = LOWORD(wParam);
6475 PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
6477 if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) {
6478 for (PRUint32 i = 0; i < cInputs; i++) {
6479 PRUint32 msg;
6480 if (pInputs[i].dwFlags & TOUCHEVENTF_MOVE) {
6481 msg = NS_MOZTOUCH_MOVE;
6482 } else if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) {
6483 msg = NS_MOZTOUCH_DOWN;
6484 } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) {
6485 msg = NS_MOZTOUCH_UP;
6486 } else {
6487 continue;
6490 nsPointWin touchPoint;
6491 touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
6492 touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
6493 touchPoint.ScreenToClient(mWnd);
6495 nsMozTouchEvent touchEvent(PR_TRUE, msg, this, pInputs[i].dwID);
6496 touchEvent.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6497 touchEvent.refPoint = touchPoint;
6499 nsEventStatus status;
6500 DispatchEvent(&touchEvent, status);
6504 delete [] pInputs;
6505 mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam);
6506 return PR_TRUE;
6508 #endif
6510 // Gesture event processing. Handles WM_GESTURE events.
6511 #if !defined(WINCE)
6512 PRBool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
6514 // Treatment for pan events which translate into scroll events:
6515 if (mGesture.IsPanEvent(lParam)) {
6516 nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
6518 if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
6519 return PR_FALSE; // ignore
6521 nsEventStatus status;
6523 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6524 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6525 event.isMeta = PR_FALSE;
6526 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6527 event.button = 0;
6528 event.time = ::GetMessageTime();
6529 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6531 PRBool endFeedback = PR_TRUE;
6533 PRInt32 scrollOverflowX = 0;
6534 PRInt32 scrollOverflowY = 0;
6536 if (mGesture.PanDeltaToPixelScrollX(event)) {
6537 DispatchEvent(&event, status);
6538 scrollOverflowX = event.scrollOverflow;
6541 if (mGesture.PanDeltaToPixelScrollY(event)) {
6542 DispatchEvent(&event, status);
6543 scrollOverflowY = event.scrollOverflow;
6546 if (mDisplayPanFeedback) {
6547 mGesture.UpdatePanFeedbackX(mWnd, scrollOverflowX, endFeedback);
6548 mGesture.UpdatePanFeedbackY(mWnd, scrollOverflowY, endFeedback);
6549 mGesture.PanFeedbackFinalize(mWnd, endFeedback);
6552 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6554 return PR_TRUE;
6557 // Other gestures translate into simple gesture events:
6558 nsSimpleGestureEvent event(PR_TRUE, 0, this, 0, 0.0);
6559 if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) {
6560 return PR_FALSE; // fall through to DefWndProc
6563 // Polish up and send off the new event
6564 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6565 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6566 event.isMeta = PR_FALSE;
6567 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6568 event.button = 0;
6569 event.time = ::GetMessageTime();
6570 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6572 nsEventStatus status;
6573 DispatchEvent(&event, status);
6574 if (status == nsEventStatus_eIgnore) {
6575 return PR_FALSE; // Ignored, fall through
6578 // Only close this if we process and return true.
6579 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6581 return PR_TRUE; // Handled
6583 #endif // !defined(WINCE)
6585 #if !defined(WINCE)
6586 PRUint16 nsWindow::GetMouseInputSource()
6588 PRUint16 inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE;
6589 LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
6590 if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
6591 inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ?
6592 PRUint16(nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH) : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN;
6594 return inputSource;
6596 #endif
6598 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6599 * within the message case block. If returning true result should be returned
6600 * immediately (no more processing).
6602 PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue)
6604 // Handle both flavors of mouse wheel events.
6605 static int iDeltaPerLine, iDeltaPerChar;
6606 static ULONG ulScrollLines, ulScrollChars = 1;
6607 static int currentVDelta, currentHDelta;
6608 static HWND currentWindow = 0;
6610 PRBool isVertical = msg == WM_MOUSEWHEEL;
6612 // Get mouse wheel metrics (but only once).
6613 if (getWheelInfo) {
6614 getWheelInfo = PR_FALSE;
6616 SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
6618 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6619 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6621 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6622 // the mouse driver wants a page scroll. The docs state that
6623 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6624 // since some mouse drivers use an arbitrary large number instead,
6625 // we have to handle that as well.
6627 iDeltaPerLine = 0;
6628 if (ulScrollLines) {
6629 if (ulScrollLines <= WHEEL_DELTA) {
6630 iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
6631 } else {
6632 ulScrollLines = WHEEL_PAGESCROLL;
6636 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
6637 &ulScrollChars, 0)) {
6638 // Note that we may always fail to get the value before Win Vista.
6639 ulScrollChars = 1;
6642 iDeltaPerChar = 0;
6643 if (ulScrollChars) {
6644 if (ulScrollChars <= WHEEL_DELTA) {
6645 iDeltaPerChar = WHEEL_DELTA / ulScrollChars;
6646 } else {
6647 ulScrollChars = WHEEL_PAGESCROLL;
6652 if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) ||
6653 (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar))
6654 return PR_FALSE; // break
6656 // The mousewheel event will be dispatched to the toplevel
6657 // window. We need to give it to the child window
6658 PRBool quit;
6659 if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit))
6660 return quit; // return immediately if its not our window
6662 // We should cancel the surplus delta if the current window is not
6663 // same as previous.
6664 if (currentWindow != mWnd) {
6665 currentVDelta = 0;
6666 currentHDelta = 0;
6667 currentWindow = mWnd;
6670 nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
6671 scrollEvent.delta = 0;
6672 if (isVertical) {
6673 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
6674 if (ulScrollLines == WHEEL_PAGESCROLL) {
6675 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6676 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1;
6677 } else {
6678 currentVDelta -= (short) HIWORD (wParam);
6679 if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
6680 scrollEvent.delta = currentVDelta / iDeltaPerLine;
6681 currentVDelta %= iDeltaPerLine;
6684 } else {
6685 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
6686 if (ulScrollChars == WHEEL_PAGESCROLL) {
6687 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6688 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1;
6689 } else {
6690 currentHDelta += (short) HIWORD (wParam);
6691 if (PR_ABS(currentHDelta) >= iDeltaPerChar) {
6692 scrollEvent.delta = currentHDelta / iDeltaPerChar;
6693 currentHDelta %= iDeltaPerChar;
6698 if (!scrollEvent.delta) {
6699 // We store the wheel delta, and it will be used next wheel message, so,
6700 // we consume this message actually. We shouldn't call next wndproc.
6701 result = PR_TRUE;
6702 return PR_FALSE; // break
6705 #ifdef MOZ_IPC
6706 // The event may go to a plug-in which already dispatched this message.
6707 // Then, the event can cause deadlock. We should unlock the sender here.
6708 ::ReplyMessage(isVertical ? 0 : TRUE);
6709 #endif
6711 scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6712 scrollEvent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6713 scrollEvent.isMeta = PR_FALSE;
6714 scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT);
6715 InitEvent(scrollEvent);
6716 if (nsnull != mEventCallback) {
6717 result = DispatchWindowEvent(&scrollEvent);
6719 // Note that we should return zero if we process WM_MOUSEWHEEL.
6720 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6722 if (result)
6723 *aRetValue = isVertical ? 0 : TRUE;
6725 return PR_FALSE; // break;
6728 static PRBool
6729 StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,
6730 const PRUnichar* aChars2, const PRUint32 aNumChars2)
6732 if (aNumChars1 != aNumChars2)
6733 return PR_FALSE;
6735 nsCaseInsensitiveStringComparator comp;
6736 return comp(aChars1, aChars2, aNumChars1, aNumChars2) == 0;
6739 UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
6741 #ifndef WINCE
6742 switch (aNativeKeyCode) {
6743 case VK_OEM_1: return NS_VK_SEMICOLON; // 0xBA, For the US standard keyboard, the ';:' key
6744 case VK_OEM_PLUS: return NS_VK_ADD; // 0xBB, For any country/region, the '+' key
6745 case VK_OEM_MINUS: return NS_VK_SUBTRACT; // 0xBD, For any country/region, the '-' key
6747 #endif
6749 return aNativeKeyCode;
6752 /* static */
6753 PRBool nsWindow::IsRedirectedKeyDownMessage(const MSG &aMsg)
6755 return (aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN) &&
6756 (sRedirectedKeyDown.message == aMsg.message &&
6757 GetScanCode(sRedirectedKeyDown.lParam) == GetScanCode(aMsg.lParam));
6761 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6762 * WM_CHAR messages for processing. During testing we don't want to
6763 * mess with the real message queue. Instead we pass a
6764 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6765 * that as if it was in the message queue, and refrain from actually
6766 * looking at or touching the message queue.
6768 LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
6769 nsModifierKeyState &aModKeyState,
6770 PRBool *aEventDispatched,
6771 nsFakeCharMessage* aFakeCharMessage)
6773 UINT virtualKeyCode =
6774 aMsg.wParam != VK_PROCESSKEY ? aMsg.wParam : ::ImmGetVirtualKey(mWnd);
6776 #ifndef WINCE
6777 gKbdLayout.OnKeyDown(virtualKeyCode);
6778 #endif
6780 // Use only DOMKeyCode for XP processing.
6781 // Use virtualKeyCode for gKbdLayout and native processing.
6782 UINT DOMKeyCode = nsIMM32Handler::IsComposingOn(this) ?
6783 virtualKeyCode : MapFromNativeToDOM(virtualKeyCode);
6785 #ifdef DEBUG
6786 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6787 #endif
6789 static PRBool sRedirectedKeyDownEventPreventedDefault = PR_FALSE;
6790 PRBool noDefault;
6791 if (aFakeCharMessage || !IsRedirectedKeyDownMessage(aMsg)) {
6792 HIMC oldIMC = mOldIMC;
6793 noDefault =
6794 DispatchKeyEvent(NS_KEY_DOWN, 0, nsnull, DOMKeyCode, &aMsg, aModKeyState);
6795 if (aEventDispatched) {
6796 *aEventDispatched = PR_TRUE;
6799 // If IMC wasn't associated to the window but is associated it now (i.e.,
6800 // focus is moved from a non-editable editor to an editor by keydown
6801 // event handler), WM_CHAR and WM_SYSCHAR shouldn't cause first character
6802 // inputting if IME is opened. But then, we should redirect the native
6803 // keydown message to IME.
6804 // However, note that if focus has been already moved to another
6805 // application, we shouldn't redirect the message to it because the keydown
6806 // message is processed by us, so, nobody shouldn't process it.
6807 HWND focusedWnd = ::GetFocus();
6808 if (!noDefault && !aFakeCharMessage && oldIMC && !mOldIMC && focusedWnd &&
6809 !PluginHasFocus()) {
6810 RemoveNextCharMessage(focusedWnd);
6812 INPUT keyinput;
6813 keyinput.type = INPUT_KEYBOARD;
6814 keyinput.ki.wVk = aMsg.wParam;
6815 keyinput.ki.wScan = GetScanCode(aMsg.lParam);
6816 keyinput.ki.dwFlags = KEYEVENTF_SCANCODE;
6817 if (IsExtendedScanCode(aMsg.lParam)) {
6818 keyinput.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
6820 keyinput.ki.time = 0;
6821 keyinput.ki.dwExtraInfo = NULL;
6823 sRedirectedKeyDownEventPreventedDefault = noDefault;
6824 sRedirectedKeyDown = aMsg;
6826 ::SendInput(1, &keyinput, sizeof(keyinput));
6828 // Return here. We shouldn't dispatch keypress event for this WM_KEYDOWN.
6829 // If it's needed, it will be dispatched after next (redirected)
6830 // WM_KEYDOWN.
6831 return PR_TRUE;
6834 if (mOnDestroyCalled) {
6835 // If this was destroyed by the keydown event handler, we shouldn't
6836 // dispatch keypress event on this window.
6837 return PR_TRUE;
6839 } else {
6840 noDefault = sRedirectedKeyDownEventPreventedDefault;
6841 // If this is redirected keydown message, we have dispatched the keydown
6842 // event already.
6843 if (aEventDispatched) {
6844 *aEventDispatched = PR_TRUE;
6848 ForgetRedirectedKeyDownMessage();
6850 // If the key was processed by IME, we shouldn't dispatch keypress event.
6851 if (aMsg.wParam == VK_PROCESSKEY) {
6852 return noDefault;
6855 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6856 // for almost all keys
6857 switch (DOMKeyCode) {
6858 case NS_VK_SHIFT:
6859 case NS_VK_CONTROL:
6860 case NS_VK_ALT:
6861 case NS_VK_CAPS_LOCK:
6862 case NS_VK_NUM_LOCK:
6863 case NS_VK_SCROLL_LOCK: return noDefault;
6866 PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
6867 MSG msg;
6868 BOOL gotMsg = aFakeCharMessage ||
6869 ::PeekMessageW(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6870 // Enter and backspace are always handled here to avoid for example the
6871 // confusion between ctrl-enter and ctrl-J.
6872 if (DOMKeyCode == NS_VK_RETURN || DOMKeyCode == NS_VK_BACK ||
6873 ((aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)
6874 #ifdef WINCE
6876 #else
6877 && !gKbdLayout.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
6878 #endif
6880 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6881 // They can be more than one because of:
6882 // * Dead-keys not pairing with base character
6883 // * Some keyboard layouts may map up to 4 characters to the single key
6884 PRBool anyCharMessagesRemoved = PR_FALSE;
6886 if (aFakeCharMessage) {
6887 anyCharMessagesRemoved = PR_TRUE;
6888 } else {
6889 while (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR))
6891 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6892 ("%s charCode=%d scanCode=%d\n", msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6893 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6894 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST, WM_KEYLAST);
6895 anyCharMessagesRemoved = PR_TRUE;
6897 gotMsg = ::PeekMessageW (&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6901 if (!anyCharMessagesRemoved && DOMKeyCode == NS_VK_BACK &&
6902 nsIMM32Handler::IsDoingKakuteiUndo(mWnd)) {
6903 NS_ASSERTION(!aFakeCharMessage,
6904 "We shouldn't be touching the real msg queue");
6905 RemoveMessageAndDispatchPluginEvent(WM_CHAR, WM_CHAR);
6908 else if (gotMsg &&
6909 (aFakeCharMessage ||
6910 msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
6911 if (aFakeCharMessage)
6912 return OnCharRaw(aFakeCharMessage->mCharCode,
6913 aFakeCharMessage->mScanCode, aModKeyState, extraFlags);
6915 // If prevent default set for keydown, do same for keypress
6916 ::GetMessageW(&msg, mWnd, msg.message, msg.message);
6918 if (msg.message == WM_DEADCHAR) {
6919 if (!PluginHasFocus())
6920 return PR_FALSE;
6922 // We need to send the removed message to focused plug-in.
6923 DispatchPluginEvent(msg);
6924 return noDefault;
6927 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6928 ("%s charCode=%d scanCode=%d\n",
6929 msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6930 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6932 BOOL result = OnChar(msg, aModKeyState, nsnull, extraFlags);
6933 // If a syschar keypress wasn't processed, Windows may want to
6934 // handle it to activate a native menu.
6935 if (!result && msg.message == WM_SYSCHAR)
6936 ::DefWindowProcW(mWnd, msg.message, msg.wParam, msg.lParam);
6937 return result;
6939 #ifndef WINCE
6940 else if (!aModKeyState.mIsControlDown && !aModKeyState.mIsAltDown &&
6941 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode) ||
6942 KeyboardLayout::IsNumpadKey(virtualKeyCode)))
6944 // If this is simple KeyDown event but next message is not WM_CHAR,
6945 // this event may not input text, so we should ignore this event.
6946 // See bug 314130.
6947 return PluginHasFocus() && noDefault;
6950 if (gKbdLayout.IsDeadKey ())
6951 return PluginHasFocus() && noDefault;
6953 PRUint8 shiftStates[5];
6954 PRUnichar uniChars[5];
6955 PRUnichar shiftedChars[5] = {0, 0, 0, 0, 0};
6956 PRUnichar unshiftedChars[5] = {0, 0, 0, 0, 0};
6957 PRUnichar shiftedLatinChar = 0;
6958 PRUnichar unshiftedLatinChar = 0;
6959 PRUint32 numOfUniChars = 0;
6960 PRUint32 numOfShiftedChars = 0;
6961 PRUint32 numOfUnshiftedChars = 0;
6962 PRUint32 numOfShiftStates = 0;
6964 switch (virtualKeyCode) {
6965 // keys to be sent as characters
6966 case VK_ADD: uniChars [0] = '+'; numOfUniChars = 1; break;
6967 case VK_SUBTRACT: uniChars [0] = '-'; numOfUniChars = 1; break;
6968 case VK_DIVIDE: uniChars [0] = '/'; numOfUniChars = 1; break;
6969 case VK_MULTIPLY: uniChars [0] = '*'; numOfUniChars = 1; break;
6970 case VK_NUMPAD0:
6971 case VK_NUMPAD1:
6972 case VK_NUMPAD2:
6973 case VK_NUMPAD3:
6974 case VK_NUMPAD4:
6975 case VK_NUMPAD5:
6976 case VK_NUMPAD6:
6977 case VK_NUMPAD7:
6978 case VK_NUMPAD8:
6979 case VK_NUMPAD9:
6980 uniChars [0] = virtualKeyCode - VK_NUMPAD0 + '0';
6981 numOfUniChars = 1;
6982 break;
6983 default:
6984 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
6985 numOfUniChars = numOfShiftStates =
6986 gKbdLayout.GetUniChars(uniChars, shiftStates,
6987 NS_ARRAY_LENGTH(uniChars));
6990 if (aModKeyState.mIsControlDown ^ aModKeyState.mIsAltDown) {
6991 PRUint8 capsLockState = (::GetKeyState(VK_CAPITAL) & 1) ? eCapsLock : 0;
6992 numOfUnshiftedChars =
6993 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode, capsLockState,
6994 unshiftedChars, NS_ARRAY_LENGTH(unshiftedChars));
6995 numOfShiftedChars =
6996 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode,
6997 capsLockState | eShift,
6998 shiftedChars, NS_ARRAY_LENGTH(shiftedChars));
7000 // The current keyboard cannot input alphabets or numerics,
7001 // we should append them for Shortcut/Access keys.
7002 // E.g., for Cyrillic keyboard layout.
7003 if (NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z) {
7004 shiftedLatinChar = unshiftedLatinChar = DOMKeyCode;
7005 if (capsLockState)
7006 shiftedLatinChar += 0x20;
7007 else
7008 unshiftedLatinChar += 0x20;
7009 if (unshiftedLatinChar == unshiftedChars[0] &&
7010 shiftedLatinChar == shiftedChars[0]) {
7011 shiftedLatinChar = unshiftedLatinChar = 0;
7013 } else {
7014 PRUint16 ch = 0;
7015 if (NS_VK_0 <= DOMKeyCode && DOMKeyCode <= NS_VK_9) {
7016 ch = DOMKeyCode;
7017 } else {
7018 switch (virtualKeyCode) {
7019 case VK_OEM_PLUS: ch = '+'; break;
7020 case VK_OEM_MINUS: ch = '-'; break;
7023 if (ch && unshiftedChars[0] != ch && shiftedChars[0] != ch) {
7024 // Windows has assigned a virtual key code to the key even though
7025 // the character can't be produced with this key. That probably
7026 // means the character can't be produced with any key in the
7027 // current layout and so the assignment is based on a QWERTY
7028 // layout. Append this code so that users can access the shortcut.
7029 unshiftedLatinChar = ch;
7033 // If the charCode is not ASCII character, we should replace the
7034 // charCode with ASCII character only when Ctrl is pressed.
7035 // But don't replace the charCode when the charCode is not same as
7036 // unmodified characters. In such case, Ctrl is sometimes used for a
7037 // part of character inputting key combination like Shift.
7038 if (aModKeyState.mIsControlDown) {
7039 PRUint8 currentState = eCtrl;
7040 if (aModKeyState.mIsShiftDown)
7041 currentState |= eShift;
7043 PRUint32 ch =
7044 aModKeyState.mIsShiftDown ? shiftedLatinChar : unshiftedLatinChar;
7045 if (ch &&
7046 (numOfUniChars == 0 ||
7047 StringCaseInsensitiveEquals(uniChars, numOfUniChars,
7048 aModKeyState.mIsShiftDown ? shiftedChars : unshiftedChars,
7049 aModKeyState.mIsShiftDown ? numOfShiftedChars :
7050 numOfUnshiftedChars))) {
7051 numOfUniChars = numOfShiftStates = 1;
7052 uniChars[0] = ch;
7053 shiftStates[0] = currentState;
7059 if (numOfUniChars > 0 || numOfShiftedChars > 0 || numOfUnshiftedChars > 0) {
7060 PRUint32 num = PR_MAX(numOfUniChars,
7061 PR_MAX(numOfShiftedChars, numOfUnshiftedChars));
7062 PRUint32 skipUniChars = num - numOfUniChars;
7063 PRUint32 skipShiftedChars = num - numOfShiftedChars;
7064 PRUint32 skipUnshiftedChars = num - numOfUnshiftedChars;
7065 UINT keyCode = numOfUniChars == 0 ? DOMKeyCode : 0;
7066 for (PRUint32 cnt = 0; cnt < num; cnt++) {
7067 PRUint16 uniChar, shiftedChar, unshiftedChar;
7068 uniChar = shiftedChar = unshiftedChar = 0;
7069 if (skipUniChars <= cnt) {
7070 if (cnt - skipUniChars < numOfShiftStates) {
7071 // If key in combination with Alt and/or Ctrl produces a different
7072 // character than without them then do not report these flags
7073 // because it is separate keyboard layout shift state. If dead-key
7074 // and base character does not produce a valid composite character
7075 // then both produced dead-key character and following base
7076 // character may have different modifier flags, too.
7077 aModKeyState.mIsShiftDown =
7078 (shiftStates[cnt - skipUniChars] & eShift) != 0;
7079 aModKeyState.mIsControlDown =
7080 (shiftStates[cnt - skipUniChars] & eCtrl) != 0;
7081 aModKeyState.mIsAltDown =
7082 (shiftStates[cnt - skipUniChars] & eAlt) != 0;
7084 uniChar = uniChars[cnt - skipUniChars];
7086 if (skipShiftedChars <= cnt)
7087 shiftedChar = shiftedChars[cnt - skipShiftedChars];
7088 if (skipUnshiftedChars <= cnt)
7089 unshiftedChar = unshiftedChars[cnt - skipUnshiftedChars];
7090 nsAutoTArray<nsAlternativeCharCode, 5> altArray;
7092 if (shiftedChar || unshiftedChar) {
7093 nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
7094 altArray.AppendElement(chars);
7096 if (cnt == num - 1 && (unshiftedLatinChar || shiftedLatinChar)) {
7097 nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
7098 altArray.AppendElement(chars);
7101 DispatchKeyEvent(NS_KEY_PRESS, uniChar, &altArray,
7102 keyCode, nsnull, aModKeyState, extraFlags);
7104 } else {
7105 DispatchKeyEvent(NS_KEY_PRESS, 0, nsnull, DOMKeyCode, nsnull, aModKeyState,
7106 extraFlags);
7108 #else
7110 UINT unichar = ::MapVirtualKey(virtualKeyCode, MAPVK_VK_TO_CHAR);
7111 // Check for dead characters or no mapping
7112 if (unichar & 0x80) {
7113 return noDefault;
7115 DispatchKeyEvent(NS_KEY_PRESS, unichar, nsnull, DOMKeyCode, nsnull, aModKeyState,
7116 extraFlags);
7118 #endif
7120 return noDefault;
7123 // OnKeyUp
7124 LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
7125 nsModifierKeyState &aModKeyState,
7126 PRBool *aEventDispatched)
7128 UINT virtualKeyCode = aMsg.wParam;
7130 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
7131 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
7133 if (!nsIMM32Handler::IsComposingOn(this)) {
7134 virtualKeyCode = MapFromNativeToDOM(virtualKeyCode);
7137 if (aEventDispatched)
7138 *aEventDispatched = PR_TRUE;
7139 return DispatchKeyEvent(NS_KEY_UP, 0, nsnull, virtualKeyCode, &aMsg,
7140 aModKeyState);
7143 // OnChar
7144 LRESULT nsWindow::OnChar(const MSG &aMsg, nsModifierKeyState &aModKeyState,
7145 PRBool *aEventDispatched, PRUint32 aFlags)
7147 return OnCharRaw(aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF, aModKeyState,
7148 aFlags, &aMsg, aEventDispatched);
7151 // OnCharRaw
7152 LRESULT nsWindow::OnCharRaw(UINT charCode, UINT aScanCode,
7153 nsModifierKeyState &aModKeyState, PRUint32 aFlags,
7154 const MSG *aMsg, PRBool *aEventDispatched)
7156 // ignore [shift+]alt+space so the OS can handle it
7157 if (aModKeyState.mIsAltDown && !aModKeyState.mIsControlDown &&
7158 IS_VK_DOWN(NS_VK_SPACE)) {
7159 return FALSE;
7162 // Ignore Ctrl+Enter (bug 318235)
7163 if (aModKeyState.mIsControlDown && charCode == 0xA) {
7164 return FALSE;
7167 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
7168 PRBool saveIsAltDown = aModKeyState.mIsAltDown;
7169 PRBool saveIsControlDown = aModKeyState.mIsControlDown;
7170 if (aModKeyState.mIsAltDown && aModKeyState.mIsControlDown)
7171 aModKeyState.mIsAltDown = aModKeyState.mIsControlDown = PR_FALSE;
7173 wchar_t uniChar;
7175 if (nsIMM32Handler::IsComposingOn(this)) {
7176 ResetInputState();
7179 if (aModKeyState.mIsControlDown && charCode <= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
7180 // need to account for shift here. bug 16486
7181 if (aModKeyState.mIsShiftDown)
7182 uniChar = charCode - 1 + 'A';
7183 else
7184 uniChar = charCode - 1 + 'a';
7185 charCode = 0;
7187 else if (aModKeyState.mIsControlDown && charCode <= 0x1F) {
7188 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
7189 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
7190 // for some reason the keypress handler need to have the uniChar code set
7191 // with the addition of a upper case A not the lower case.
7192 uniChar = charCode - 1 + 'A';
7193 charCode = 0;
7194 } else { // 0x20 - SPACE, 0x3D - EQUALS
7195 if (charCode < 0x20 || (charCode == 0x3D && aModKeyState.mIsControlDown)) {
7196 uniChar = 0;
7197 } else {
7198 uniChar = charCode;
7199 charCode = 0;
7203 // Keep the characters unshifted for shortcuts and accesskeys and make sure
7204 // that numbers are always passed as such (among others: bugs 50255 and 351310)
7205 if (uniChar && (aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)) {
7206 UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK,
7207 gKbdLayout.GetLayout());
7208 UINT unshiftedCharCode =
7209 virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
7210 aModKeyState.mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode,
7211 MAPVK_VK_TO_CHAR,
7212 gKbdLayout.GetLayout()) : 0;
7213 // ignore diacritics (top bit set) and key mapping errors (char code 0)
7214 if ((INT)unshiftedCharCode > 0)
7215 uniChar = unshiftedCharCode;
7218 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
7219 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
7220 // pressed too.
7221 if (!aModKeyState.mIsShiftDown && (saveIsAltDown || saveIsControlDown)) {
7222 uniChar = towlower(uniChar);
7225 PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, nsnull,
7226 charCode, aMsg, aModKeyState, aFlags);
7227 if (aEventDispatched)
7228 *aEventDispatched = PR_TRUE;
7229 aModKeyState.mIsAltDown = saveIsAltDown;
7230 aModKeyState.mIsControlDown = saveIsControlDown;
7231 return result;
7234 void
7235 nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers)
7237 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierKeyMap); ++i) {
7238 const PRUint32* map = sModifierKeyMap[i];
7239 if (aModifiers & map[0]) {
7240 aArray->AppendElement(KeyPair(map[1], map[2]));
7245 nsresult
7246 nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
7248 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
7249 // here, if that helps in some situations. So far I haven't seen a
7250 // need.
7251 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
7252 const Configuration& configuration = aConfigurations[i];
7253 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
7254 NS_ASSERTION(w->GetParent() == this,
7255 "Configured widget is not a child");
7256 #ifdef WINCE
7257 // MSDN says we should do on WinCE this before moving or resizing the window
7258 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
7259 // We put the region back just below, anyway.
7260 ::SetWindowRgn(w->mWnd, NULL, TRUE);
7261 #endif
7262 nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_TRUE);
7263 NS_ENSURE_SUCCESS(rv, rv);
7264 nsIntRect bounds;
7265 w->GetBounds(bounds);
7266 if (bounds.Size() != configuration.mBounds.Size()) {
7267 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
7268 configuration.mBounds.width, configuration.mBounds.height,
7269 PR_TRUE);
7270 } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
7271 w->Move(configuration.mBounds.x, configuration.mBounds.y);
7274 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7275 gfxWindowsPlatform::RENDER_DIRECT2D ||
7276 GetLayerManager()->GetBackendType() != LayerManager::LAYERS_BASIC) {
7277 // XXX - Workaround for Bug 587508. This will invalidate the part of the
7278 // plugin window that might be touched by moving content somehow. The
7279 // underlying problem should be found and fixed!
7280 nsIntRegion r;
7281 r.Sub(bounds, configuration.mBounds);
7282 r.MoveBy(-bounds.x,
7283 -bounds.y);
7284 w->Invalidate(r.GetBounds(), PR_FALSE);
7287 rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_FALSE);
7288 NS_ENSURE_SUCCESS(rv, rv);
7290 return NS_OK;
7293 static HRGN
7294 CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
7296 PRInt32 size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
7297 nsAutoTArray<PRUint8,100> buf;
7298 if (!buf.SetLength(size))
7299 return NULL;
7300 RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
7301 RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
7302 data->rdh.dwSize = sizeof(data->rdh);
7303 data->rdh.iType = RDH_RECTANGLES;
7304 data->rdh.nCount = aRects.Length();
7305 nsIntRect bounds;
7306 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
7307 const nsIntRect& r = aRects[i];
7308 bounds.UnionRect(bounds, r);
7309 ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
7311 ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
7312 return ::ExtCreateRegion(NULL, buf.Length(), data);
7315 static const nsTArray<nsIntRect>
7316 ArrayFromRegion(const nsIntRegion& aRegion)
7318 nsTArray<nsIntRect> rects;
7319 const nsIntRect* r;
7320 for (nsIntRegionRectIterator iter(aRegion); (r = iter.Next());) {
7321 rects.AppendElement(*r);
7323 return rects;
7326 nsresult
7327 nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
7328 PRBool aIntersectWithExisting)
7330 if (!aIntersectWithExisting) {
7331 if (!StoreWindowClipRegion(aRects))
7332 return NS_OK;
7333 } else {
7334 // In this case still early return if nothing changed.
7335 if (mClipRects && mClipRectCount == aRects.Length() &&
7336 memcmp(mClipRects,
7337 aRects.Elements(),
7338 sizeof(nsIntRect)*mClipRectCount) == 0) {
7339 return NS_OK;
7342 // get current rects
7343 nsTArray<nsIntRect> currentRects;
7344 GetWindowClipRegion(&currentRects);
7345 // create region from them
7346 nsIntRegion currentRegion = RegionFromArray(currentRects);
7347 // create region from new rects
7348 nsIntRegion newRegion = RegionFromArray(aRects);
7349 // intersect regions
7350 nsIntRegion intersection;
7351 intersection.And(currentRegion, newRegion);
7352 // create int rect array from intersection
7353 nsTArray<nsIntRect> rects = ArrayFromRegion(intersection);
7354 // store
7355 if (!StoreWindowClipRegion(rects))
7356 return NS_OK;
7359 HRGN dest = CreateHRGNFromArray(aRects);
7360 if (!dest)
7361 return NS_ERROR_OUT_OF_MEMORY;
7363 if (aIntersectWithExisting) {
7364 HRGN current = ::CreateRectRgn(0, 0, 0, 0);
7365 if (current) {
7366 if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
7367 ::CombineRgn(dest, dest, current, RGN_AND);
7369 ::DeleteObject(current);
7373 if (!::SetWindowRgn(mWnd, dest, TRUE)) {
7374 ::DeleteObject(dest);
7375 return NS_ERROR_FAILURE;
7377 return NS_OK;
7380 // WM_DESTROY event handler
7381 void nsWindow::OnDestroy()
7383 mOnDestroyCalled = PR_TRUE;
7385 // Make sure we don't get destroyed in the process of tearing down.
7386 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
7388 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
7389 if (!mInDtor)
7390 DispatchStandardEvent(NS_DESTROY);
7392 // Prevent the widget from sending additional events.
7393 mEventCallback = nsnull;
7395 // Free our subclass and clear |this| stored in the window props. We will no longer
7396 // receive events from Windows after this point.
7397 SubclassWindow(FALSE);
7399 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
7400 // cleared. (It's used in tracking windows for mouse events.)
7401 if (sCurrentWindow == this)
7402 sCurrentWindow = nsnull;
7404 // Disconnects us from our parent, will call our GetParent().
7405 nsBaseWidget::Destroy();
7407 // Release references to children, device context, toolkit, and app shell.
7408 nsBaseWidget::OnDestroy();
7410 // Clear our native parent handle.
7411 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
7412 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
7413 //SetParent(nsnull);
7414 mParent = nsnull;
7416 // We have to destroy the native drag target before we null out our window pointer.
7417 EnableDragDrop(PR_FALSE);
7419 // If we're going away and for some reason we're still the rollup widget, rollup and
7420 // turn off capture.
7421 if ( this == sRollupWidget ) {
7422 if ( sRollupListener )
7423 sRollupListener->Rollup(nsnull, nsnull);
7424 CaptureRollupEvents(nsnull, nsnull, PR_FALSE, PR_TRUE);
7427 // If IME is disabled, restore it.
7428 if (mOldIMC) {
7429 mOldIMC = ::ImmAssociateContext(mWnd, mOldIMC);
7430 NS_ASSERTION(!mOldIMC, "Another IMC was associated");
7433 // Turn off mouse trails if enabled.
7434 MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
7435 if (mtrailer) {
7436 if (mtrailer->GetMouseTrailerWindow() == mWnd)
7437 mtrailer->DestroyTimer();
7439 if (mtrailer->GetCaptureWindow() == mWnd)
7440 mtrailer->SetCaptureWindow(nsnull);
7443 // Free GDI window class objects
7444 if (mBrush) {
7445 VERIFY(::DeleteObject(mBrush));
7446 mBrush = NULL;
7449 // Free app icon resources.
7450 HICON icon;
7451 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM) 0);
7452 if (icon)
7453 ::DestroyIcon(icon);
7455 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM) 0);
7456 if (icon)
7457 ::DestroyIcon(icon);
7459 // Destroy any custom cursor resources.
7460 if (mCursor == -1)
7461 SetCursor(eCursor_standard);
7463 #ifdef MOZ_XUL
7464 // Reset transparency
7465 if (eTransparencyTransparent == mTransparencyMode)
7466 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
7467 #endif
7469 #if defined(WINCE_HAVE_SOFTKB)
7470 // Revert the changes made for the software keyboard settings
7471 nsWindowCE::ResetSoftKB(mWnd);
7472 #endif
7474 #if !defined(WINCE)
7475 // Finalize panning feedback to possibly restore window displacement
7476 mGesture.PanFeedbackFinalize(mWnd, PR_TRUE);
7477 #endif
7479 // Clear the main HWND.
7480 mWnd = NULL;
7483 // OnMove
7484 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
7486 mBounds.x = aX;
7487 mBounds.y = aY;
7489 nsGUIEvent event(PR_TRUE, NS_MOVE, this);
7490 InitEvent(event);
7491 event.refPoint.x = aX;
7492 event.refPoint.y = aY;
7494 return DispatchWindowEvent(&event);
7497 // Send a resize message to the listener
7498 PRBool nsWindow::OnResize(nsIntRect &aWindowRect)
7500 #ifdef CAIRO_HAS_D2D_SURFACE
7501 if (mD2DWindowSurface) {
7502 mD2DWindowSurface = NULL;
7503 Invalidate(PR_FALSE);
7505 #endif
7507 // call the event callback
7508 if (mEventCallback) {
7509 nsSizeEvent event(PR_TRUE, NS_SIZE, this);
7510 InitEvent(event);
7511 event.windowSize = &aWindowRect;
7512 RECT r;
7513 if (::GetWindowRect(mWnd, &r)) {
7514 event.mWinWidth = PRInt32(r.right - r.left);
7515 event.mWinHeight = PRInt32(r.bottom - r.top);
7516 } else {
7517 event.mWinWidth = 0;
7518 event.mWinHeight = 0;
7521 #if 0
7522 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7523 aWindowRect.x, aWindowRect.y, aWindowRect.width, aWindowRect.height,
7524 event.mWinWidth, event.mWinHeight);
7525 #endif
7527 return DispatchWindowEvent(&event);
7530 return PR_FALSE;
7533 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7534 PRBool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
7536 return PR_TRUE;
7538 #endif // !defined(WINCE)
7540 void nsWindow::OnSettingsChange(WPARAM wParam, LPARAM lParam)
7542 if (mWindowType == eWindowType_dialog ||
7543 mWindowType == eWindowType_toplevel )
7544 nsWindowGfx::OnSettingsChangeGfx(wParam);
7547 /* static */
7548 PRBool nsWindow::IsOurProcessWindow(HWND aHWND)
7550 if (!aHWND) {
7551 return PR_FALSE;
7553 DWORD processId = 0;
7554 ::GetWindowThreadProcessId(aHWND, &processId);
7555 return processId == ::GetCurrentProcessId();
7558 /* static */
7559 HWND nsWindow::FindOurProcessWindow(HWND aHWND)
7561 for (HWND wnd = ::GetParent(aHWND); wnd; wnd = ::GetParent(wnd)) {
7562 if (IsOurProcessWindow(wnd)) {
7563 return wnd;
7566 return nsnull;
7569 // Scrolling helper function for handling plugins.
7570 // Return value indicates whether the calling function should handle this
7571 // aHandled indicates whether this was handled at all
7572 // aQuitProcessing tells whether or not to continue processing the message
7573 PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
7574 LPARAM aLParam, PRBool& aHandled,
7575 LRESULT* aRetValue,
7576 PRBool& aQuitProcessing)
7578 // The scroll event will be dispatched to the toplevel
7579 // window. We need to give it to the child window
7580 aQuitProcessing = PR_FALSE; // default is to not stop processing
7581 POINT point;
7582 DWORD dwPoints = ::GetMessagePos();
7583 point.x = GET_X_LPARAM(dwPoints);
7584 point.y = GET_Y_LPARAM(dwPoints);
7586 static PRBool sIsProcessing = PR_FALSE;
7587 if (sIsProcessing) {
7588 return PR_TRUE; // the caller should handle this.
7591 static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
7592 if (aMsg == WM_MOUSEHWHEEL) {
7593 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7594 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7595 // message at first time, this time, ::GetMessagePos works fine.
7596 // Then, we will return 0 (0 means we process it) to the message. Then, the
7597 // driver will POST the same messages continuously during the wheel tilted.
7598 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7599 // cursor isn't 0,0. Therefore, we cannot trust the result of
7600 // ::GetMessagePos API if the sender is the driver.
7601 if (!sMayBeUsingLogitechMouse && aLParam == 0 && (DWORD)aLParam != dwPoints &&
7602 ::InSendMessage()) {
7603 sMayBeUsingLogitechMouse = PR_TRUE;
7604 } else if (sMayBeUsingLogitechMouse && aLParam != 0 && ::InSendMessage()) {
7605 // The user has changed the mouse from Logitech's to another one (e.g.,
7606 // the user has changed to the touchpad of the notebook.
7607 sMayBeUsingLogitechMouse = PR_FALSE;
7609 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7610 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7611 // instead.
7612 if (sMayBeUsingLogitechMouse && aLParam == 0 && dwPoints == 0) {
7613 ::GetCursorPos(&point);
7617 HWND destWnd = ::WindowFromPoint(point);
7618 // Since we receive scroll events for as long as
7619 // we are focused, it's entirely possible that there
7620 // is another app's window or no window under the
7621 // pointer.
7623 if (!destWnd) {
7624 // No window is under the pointer
7625 return PR_FALSE; // break, but continue processing
7628 nsWindow* destWindow;
7630 // We don't handle the message if the found window belongs to another
7631 // process's top window. If it belongs window, that is a plug-in's window.
7632 // Then, we need to send the message to the plug-in window.
7633 if (!IsOurProcessWindow(destWnd)) {
7634 HWND ourPluginWnd = FindOurProcessWindow(destWnd);
7635 if (!ourPluginWnd) {
7636 // Somebody elses window
7637 return PR_FALSE; // break, but continue processing
7639 destWindow = GetNSWindowPtr(ourPluginWnd);
7640 } else {
7641 destWindow = GetNSWindowPtr(destWnd);
7644 if (destWindow == this && mWindowType == eWindowType_plugin) {
7645 // If this is plug-in window, the message came from the plug-in window.
7646 // Then, the message should be processed on the parent window.
7647 destWindow = static_cast<nsWindow*>(GetParent());
7648 NS_ENSURE_TRUE(destWindow, PR_FALSE); // break, but continue processing
7649 destWnd = destWindow->mWnd;
7650 NS_ENSURE_TRUE(destWnd, PR_FALSE); // break, but continue processing
7653 if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
7654 // Some other app, or a plugin window.
7655 // Windows directs scrolling messages to the focused window.
7656 // However, Mozilla does not like plugins having focus, so a
7657 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7658 // Therefore, plugins etc _should_ get first grab at the
7659 // message, but this focus vaguary means the plugin misses
7660 // out. If the window is a child of ours, forward it on.
7661 // Determine if a child by walking the parent list until
7662 // we find a parent matching our wndproc.
7663 HWND parentWnd = ::GetParent(destWnd);
7664 while (parentWnd) {
7665 nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
7666 if (parentWindow) {
7667 // We have a child window - quite possibly a plugin window.
7668 // However, not all plugins are created equal - some will handle this
7669 // message themselves, some will forward directly back to us, while
7670 // others will call DefWndProc, which itself still forwards back to us.
7671 // So if we have sent it once, we need to handle it ourself.
7673 #ifdef MOZ_IPC
7674 // XXX The message shouldn't come from the plugin window at here.
7675 // But the message might come from it due to some bugs. If it happens,
7676 // SendMessage causes deadlock. For safety, we should unlock the
7677 // sender here.
7678 ::ReplyMessage(aMsg == WM_MOUSEHWHEEL ? TRUE : 0);
7679 #endif
7681 // First time we have seen this message.
7682 // Call the child - either it will consume it, or
7683 // it will wind it's way back to us,triggering the destWnd case above
7684 // either way,when the call returns,we are all done with the message,
7685 sIsProcessing = PR_TRUE;
7686 ::SendMessageW(destWnd, aMsg, aWParam, aLParam);
7687 sIsProcessing = PR_FALSE;
7688 aHandled = PR_TRUE;
7689 aQuitProcessing = PR_TRUE;
7690 return PR_FALSE; // break, and stop processing
7692 parentWnd = ::GetParent(parentWnd);
7693 } // while parentWnd
7695 if (destWnd == nsnull)
7696 return PR_FALSE;
7697 if (destWnd != mWnd) {
7698 if (destWindow) {
7699 sIsProcessing = PR_TRUE;
7700 aHandled = destWindow->ProcessMessage(aMsg, aWParam, aLParam, aRetValue);
7701 sIsProcessing = PR_FALSE;
7702 aQuitProcessing = PR_TRUE;
7703 return PR_FALSE; // break, and stop processing
7705 #ifdef DEBUG
7706 else
7707 printf("WARNING: couldn't get child window for SCROLL event\n");
7708 #endif
7710 return PR_TRUE; // caller should handle this
7713 PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
7715 static PRInt8 sMouseWheelEmulation = -1;
7716 if (sMouseWheelEmulation < 0) {
7717 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7718 NS_ENSURE_TRUE(prefs, PR_FALSE);
7719 nsCOMPtr<nsIPrefBranch> prefBranch;
7720 prefs->GetBranch(0, getter_AddRefs(prefBranch));
7721 NS_ENSURE_TRUE(prefBranch, PR_FALSE);
7722 PRBool emulate;
7723 nsresult rv =
7724 prefBranch->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate);
7725 NS_ENSURE_SUCCESS(rv, PR_FALSE);
7726 sMouseWheelEmulation = PRInt8(emulate);
7729 if (aLParam || sMouseWheelEmulation) {
7730 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7731 // Treat as a mousewheel message and scroll appropriately
7732 PRBool quit, result;
7733 LRESULT retVal;
7735 if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result, &retVal, quit))
7736 return quit; // Return if it's not our message or has been dispatched
7738 nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
7739 scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
7740 ? nsMouseScrollEvent::kIsVertical
7741 : nsMouseScrollEvent::kIsHorizontal;
7742 switch (LOWORD(aWParam))
7744 case SB_PAGEDOWN:
7745 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7746 case SB_LINEDOWN:
7747 scrollevent.delta = 1;
7748 break;
7749 case SB_PAGEUP:
7750 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7751 case SB_LINEUP:
7752 scrollevent.delta = -1;
7753 break;
7754 default:
7755 return PR_FALSE;
7757 #ifdef MOZ_IPC
7758 // The event may go to a plug-in which already dispatched this message.
7759 // Then, the event can cause deadlock. We should unlock the sender here.
7760 ::ReplyMessage(0);
7761 #endif
7762 scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
7763 scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
7764 scrollevent.isMeta = PR_FALSE;
7765 scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
7766 InitEvent(scrollevent);
7767 if (nsnull != mEventCallback)
7769 DispatchWindowEvent(&scrollevent);
7771 return PR_TRUE;
7774 // Scroll message generated by external application
7775 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_SCROLL, this);
7777 command.mScroll.mIsHorizontal = (aMsg == WM_HSCROLL);
7779 switch (LOWORD(aWParam))
7781 case SB_LINEUP: // SB_LINELEFT
7782 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7783 command.mScroll.mAmount = -1;
7784 break;
7785 case SB_LINEDOWN: // SB_LINERIGHT
7786 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7787 command.mScroll.mAmount = 1;
7788 break;
7789 case SB_PAGEUP: // SB_PAGELEFT
7790 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7791 command.mScroll.mAmount = -1;
7792 break;
7793 case SB_PAGEDOWN: // SB_PAGERIGHT
7794 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7795 command.mScroll.mAmount = 1;
7796 break;
7797 case SB_TOP: // SB_LEFT
7798 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7799 command.mScroll.mAmount = -1;
7800 break;
7801 case SB_BOTTOM: // SB_RIGHT
7802 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7803 command.mScroll.mAmount = 1;
7804 break;
7805 default:
7806 return PR_FALSE;
7808 DispatchWindowEvent(&command);
7809 return PR_TRUE;
7812 // Can be overriden. Controls auto-erase of background.
7813 PRBool nsWindow::AutoErase(HDC dc)
7815 return PR_FALSE;
7818 void
7819 nsWindow::AllowD3D9Callback(nsWindow *aWindow)
7821 if (aWindow->mLayerManager) {
7822 aWindow->mLayerManager->Destroy();
7823 aWindow->mLayerManager = NULL;
7827 void
7828 nsWindow::AllowD3D9WithReinitializeCallback(nsWindow *aWindow)
7830 if (aWindow->mLayerManager) {
7831 aWindow->mLayerManager->Destroy();
7832 aWindow->mLayerManager = NULL;
7833 (void) aWindow->GetLayerManager();
7837 void
7838 nsWindow::StartAllowingD3D9(bool aReinitialize)
7840 sAllowD3D9 = true;
7842 LayerManagerPrefs prefs;
7843 GetLayerManagerPrefs(&prefs);
7844 if (prefs.mDisableAcceleration) {
7845 // The guarantee here is, if there's *any* chance that after we
7846 // throw out our layer managers we'd create at least one new,
7847 // accelerated one, we *will* throw out all the current layer
7848 // managers. We early-return here because currently, if
7849 // |disableAcceleration|, we will always use basic managers and
7850 // it's a waste to recreate them.
7852 // NB: the above implies that it's eminently possible for us to
7853 // skip this early return but still recreate basic managers.
7854 // That's OK. It's *not* OK to take this early return when we
7855 // *might* have created an accelerated manager.
7856 return;
7859 if (aReinitialize) {
7860 EnumAllWindows(AllowD3D9WithReinitializeCallback);
7861 } else {
7862 EnumAllWindows(AllowD3D9Callback);
7866 /**************************************************************
7867 **************************************************************
7869 ** BLOCK: IME management and accessibility
7871 ** Handles managing IME input and accessibility.
7873 **************************************************************
7874 **************************************************************/
7876 NS_IMETHODIMP nsWindow::ResetInputState()
7878 #ifdef DEBUG_KBSTATE
7879 printf("ResetInputState\n");
7880 #endif
7882 #ifdef NS_ENABLE_TSF
7883 nsTextStore::CommitComposition(PR_FALSE);
7884 #endif //NS_ENABLE_TSF
7886 nsIMM32Handler::CommitComposition(this);
7887 return NS_OK;
7890 NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState)
7892 #ifdef DEBUG_KBSTATE
7893 printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
7894 #endif
7896 #ifdef NS_ENABLE_TSF
7897 nsTextStore::SetIMEOpenState(aState);
7898 #endif //NS_ENABLE_TSF
7900 nsIMEContext IMEContext(mWnd);
7901 if (IMEContext.IsValid()) {
7902 ::ImmSetOpenStatus(IMEContext.get(), aState ? TRUE : FALSE);
7904 return NS_OK;
7907 NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState)
7909 nsIMEContext IMEContext(mWnd);
7910 if (IMEContext.IsValid()) {
7911 BOOL isOpen = ::ImmGetOpenStatus(IMEContext.get());
7912 *aState = isOpen ? PR_TRUE : PR_FALSE;
7913 } else
7914 *aState = PR_FALSE;
7916 #ifdef NS_ENABLE_TSF
7917 *aState |= nsTextStore::GetIMEOpenState();
7918 #endif //NS_ENABLE_TSF
7920 return NS_OK;
7923 NS_IMETHODIMP nsWindow::SetInputMode(const IMEContext& aContext)
7925 PRUint32 status = aContext.mStatus;
7926 #ifdef NS_ENABLE_TSF
7927 nsTextStore::SetInputMode(aContext);
7928 #endif //NS_ENABLE_TSF
7929 #ifdef DEBUG_KBSTATE
7930 printf("SetInputMode: %s\n", (status == nsIWidget::IME_STATUS_ENABLED ||
7931 status == nsIWidget::IME_STATUS_PLUGIN) ?
7932 "Enabled" : "Disabled");
7933 #endif
7934 if (nsIMM32Handler::IsComposing()) {
7935 ResetInputState();
7937 mIMEContext = aContext;
7938 PRBool enable = (status == nsIWidget::IME_STATUS_ENABLED ||
7939 status == nsIWidget::IME_STATUS_PLUGIN);
7941 #if defined(WINCE_HAVE_SOFTKB)
7942 sSoftKeyboardState = (status != nsIWidget::IME_STATUS_DISABLED);
7943 nsWindowCE::ToggleSoftKB(mWnd, sSoftKeyboardState);
7944 #endif
7946 if (!enable != !mOldIMC)
7947 return NS_OK;
7948 mOldIMC = ::ImmAssociateContext(mWnd, enable ? mOldIMC : NULL);
7949 NS_ASSERTION(!enable || !mOldIMC, "Another IMC was associated");
7951 return NS_OK;
7954 NS_IMETHODIMP nsWindow::GetInputMode(IMEContext& aContext)
7956 #ifdef DEBUG_KBSTATE
7957 printf("GetInputMode: %s\n", mIMEContext.mStatus ? "Enabled" : "Disabled");
7958 #endif
7959 aContext = mIMEContext;
7960 return NS_OK;
7963 NS_IMETHODIMP nsWindow::CancelIMEComposition()
7965 #ifdef DEBUG_KBSTATE
7966 printf("CancelIMEComposition\n");
7967 #endif
7969 #ifdef NS_ENABLE_TSF
7970 nsTextStore::CommitComposition(PR_TRUE);
7971 #endif //NS_ENABLE_TSF
7973 nsIMM32Handler::CancelComposition(this);
7974 return NS_OK;
7977 NS_IMETHODIMP
7978 nsWindow::GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState)
7980 #ifdef DEBUG_KBSTATE
7981 printf("GetToggledKeyState\n");
7982 #endif
7983 NS_ENSURE_ARG_POINTER(aLEDState);
7984 *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
7985 return NS_OK;
7988 #ifdef NS_ENABLE_TSF
7989 NS_IMETHODIMP
7990 nsWindow::OnIMEFocusChange(PRBool aFocus)
7992 nsresult rv = nsTextStore::OnFocusChange(aFocus, this, mIMEContext.mStatus);
7993 if (rv == NS_ERROR_NOT_AVAILABLE)
7994 rv = NS_ERROR_NOT_IMPLEMENTED; // TSF is not enabled, maybe.
7995 return rv;
7998 NS_IMETHODIMP
7999 nsWindow::OnIMETextChange(PRUint32 aStart,
8000 PRUint32 aOldEnd,
8001 PRUint32 aNewEnd)
8003 return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
8006 NS_IMETHODIMP
8007 nsWindow::OnIMESelectionChange(void)
8009 return nsTextStore::OnSelectionChange();
8011 #endif //NS_ENABLE_TSF
8013 #ifdef ACCESSIBILITY
8015 #ifdef DEBUG_WMGETOBJECT
8016 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
8017 nsAccessible* acc = aWnd ? \
8018 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
8019 printf(" acc: %p", acc); \
8020 if (acc) { \
8021 nsAutoString name; \
8022 acc->GetName(name); \
8023 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
8024 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
8025 void *hwnd = nsnull; \
8026 doc->GetWindowHandle(&hwnd); \
8027 printf(", acc hwnd: %d", hwnd); \
8030 #define NS_LOG_WMGETOBJECT_THISWND \
8032 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
8033 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
8034 mWnd, ::GetParent(mWnd), this); \
8035 NS_LOG_WMGETOBJECT_WNDACC(this) \
8036 printf("\n }\n"); \
8039 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
8041 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
8042 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
8043 aHwnd, ::GetParent(aHwnd), wnd); \
8044 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
8045 printf("\n }\n"); \
8047 #else
8048 #define NS_LOG_WMGETOBJECT_THISWND
8049 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
8050 #endif // DEBUG_WMGETOBJECT
8052 nsAccessible*
8053 nsWindow::GetRootAccessible()
8055 // We want the ability to forcibly disable a11y on windows, because
8056 // some non-a11y-related components attempt to bring it up. See bug
8057 // 538530 for details; we have a pref here that allows it to be disabled
8058 // for performance and testing resons.
8060 // This pref is checked only once, and the browser needs a restart to
8061 // pick up any changes.
8062 static int accForceDisable = -1;
8064 if (accForceDisable == -1) {
8065 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
8066 PRBool b = PR_FALSE;
8067 nsresult rv = prefs->GetBoolPref("accessibility.win32.force_disabled", &b);
8068 if (NS_SUCCEEDED(rv) && b) {
8069 accForceDisable = 1;
8070 } else {
8071 accForceDisable = 0;
8075 // If the pref was true, return null here, disabling a11y.
8076 if (accForceDisable)
8077 return nsnull;
8079 nsWindow::sIsAccessibilityOn = TRUE;
8081 if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) {
8082 return nsnull;
8085 NS_LOG_WMGETOBJECT_THISWND
8086 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
8088 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
8091 STDMETHODIMP_(LRESULT)
8092 nsWindow::LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc)
8094 // open the dll dynamically
8095 if (!sAccLib)
8096 sAccLib =::LoadLibraryW(L"OLEACC.DLL");
8098 if (sAccLib) {
8099 if (!sLresultFromObject)
8100 sLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(sAccLib,"LresultFromObject");
8102 if (sLresultFromObject)
8103 return sLresultFromObject(riid,wParam,pAcc);
8106 return 0;
8108 #endif
8110 /**************************************************************
8111 **************************************************************
8113 ** BLOCK: Transparency
8115 ** Window transparency helpers.
8117 **************************************************************
8118 **************************************************************/
8120 #ifdef MOZ_XUL
8122 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force)
8124 if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
8125 return;
8127 #ifdef CAIRO_HAS_D2D_SURFACE
8128 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
8129 gfxWindowsPlatform::RENDER_DIRECT2D) {
8130 nsRefPtr<gfxD2DSurface> newSurface =
8131 new gfxD2DSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
8132 mTransparentSurface = newSurface;
8133 mMemoryDC = nsnull;
8134 } else
8135 #endif
8137 nsRefPtr<gfxWindowsSurface> newSurface =
8138 new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
8139 mTransparentSurface = newSurface;
8140 mMemoryDC = newSurface->GetDC();
8144 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
8146 #ifndef WINCE
8148 if (aMode == mTransparencyMode)
8149 return;
8151 // stop on dialogs and popups!
8152 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
8153 nsWindow* parent = GetNSWindowPtr(hWnd);
8155 if (!parent)
8157 NS_WARNING("Trying to use transparent chrome in an embedded context");
8158 return;
8161 if (parent != this) {
8162 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
8165 if (aMode == eTransparencyTransparent) {
8166 // If we're switching to the use of a transparent window, hide the chrome
8167 // on our parent.
8168 HideWindowChrome(PR_TRUE);
8169 } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) {
8170 // if we're switching out of transparent, re-enable our parent's chrome.
8171 HideWindowChrome(PR_FALSE);
8174 LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE),
8175 exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
8177 if (parent->mIsVisible)
8178 style |= WS_VISIBLE;
8179 if (parent->mSizeMode == nsSizeMode_Maximized)
8180 style |= WS_MAXIMIZE;
8181 else if (parent->mSizeMode == nsSizeMode_Minimized)
8182 style |= WS_MINIMIZE;
8184 if (aMode == eTransparencyTransparent)
8185 exStyle |= WS_EX_LAYERED;
8186 else
8187 exStyle &= ~WS_EX_LAYERED;
8189 VERIFY_WINDOW_STYLE(style);
8190 ::SetWindowLongPtrW(hWnd, GWL_STYLE, style);
8191 ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle);
8193 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
8194 if (HasGlass())
8195 memset(&mGlassMargins, 0, sizeof mGlassMargins);
8196 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
8197 mTransparencyMode = aMode;
8199 SetupTranslucentWindowMemoryBitmap(aMode);
8200 UpdateGlass();
8201 #endif // #ifndef WINCE
8204 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
8206 if (eTransparencyTransparent == aMode) {
8207 ResizeTranslucentWindow(mBounds.width, mBounds.height, PR_TRUE);
8208 } else {
8209 mTransparentSurface = nsnull;
8210 mMemoryDC = NULL;
8214 nsresult nsWindow::UpdateTranslucentWindow()
8216 #ifndef WINCE
8217 if (mBounds.IsEmpty())
8218 return NS_OK;
8220 ::GdiFlush();
8222 BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
8223 SIZE winSize = { mBounds.width, mBounds.height };
8224 POINT srcPos = { 0, 0 };
8225 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
8226 RECT winRect;
8227 ::GetWindowRect(hWnd, &winRect);
8229 #ifdef CAIRO_HAS_D2D_SURFACE
8230 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
8231 gfxWindowsPlatform::RENDER_DIRECT2D) {
8232 mMemoryDC = static_cast<gfxD2DSurface*>(mTransparentSurface.get())->
8233 GetDC(PR_TRUE);
8235 #endif
8236 // perform the alpha blend
8237 PRBool updateSuccesful =
8238 ::UpdateLayeredWindow(hWnd, NULL, (POINT*)&winRect, &winSize, mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA);
8240 #ifdef CAIRO_HAS_D2D_SURFACE
8241 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
8242 gfxWindowsPlatform::RENDER_DIRECT2D) {
8243 nsIntRect r(0, 0, 0, 0);
8244 static_cast<gfxD2DSurface*>(mTransparentSurface.get())->ReleaseDC(&r);
8246 #endif
8248 if (!updateSuccesful) {
8249 return NS_ERROR_FAILURE;
8251 #endif
8253 return NS_OK;
8256 #endif //MOZ_XUL
8258 /**************************************************************
8259 **************************************************************
8261 ** BLOCK: Popup rollup hooks
8263 ** Deals with CaptureRollup on popup windows.
8265 **************************************************************
8266 **************************************************************/
8268 #ifndef WINCE
8269 // Schedules a timer for a window, so we can rollup after processing the hook event
8270 void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId)
8272 // In some cases multiple hooks may be scheduled
8273 // so ignore any other requests once one timer is scheduled
8274 if (sHookTimerId == 0) {
8275 // Remember the window handle and the message ID to be used later
8276 sRollupMsgId = aMsgId;
8277 sRollupMsgWnd = aWnd;
8278 // Schedule native timer for doing the rollup after
8279 // this event is done being processed
8280 sHookTimerId = ::SetTimer(NULL, 0, 0, (TIMERPROC)HookTimerForPopups);
8281 NS_ASSERTION(sHookTimerId, "Timer couldn't be created.");
8285 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8286 int gLastMsgCode = 0;
8287 extern MSGFEventMsgInfo gMSGFEvents[];
8288 #endif
8290 // Process Menu messages, rollup when popup is clicked.
8291 LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam)
8293 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8294 if (sProcessHook) {
8295 MSG* pMsg = (MSG*)lParam;
8297 int inx = 0;
8298 while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != NULL) {
8299 inx++;
8301 if (code != gLastMsgCode) {
8302 if (gMSGFEvents[inx].mId == code) {
8303 #ifdef DEBUG
8304 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code, gMSGFEvents[inx].mStr, pMsg->hwnd);
8305 #endif
8306 } else {
8307 #ifdef DEBUG
8308 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code, gMSGFEvents[inx].mId, pMsg->hwnd);
8309 #endif
8311 gLastMsgCode = code;
8313 PrintEvent(pMsg->message, FALSE, FALSE);
8315 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8317 if (sProcessHook && code == MSGF_MENU) {
8318 MSG* pMsg = (MSG*)lParam;
8319 ScheduleHookTimer( pMsg->hwnd, pMsg->message);
8322 return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
8325 // Process all mouse messages. Roll up when a click is in a native window
8326 // that doesn't have an nsIWidget.
8327 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
8329 if (sProcessHook) {
8330 switch (wParam) {
8331 case WM_LBUTTONDOWN:
8332 case WM_RBUTTONDOWN:
8333 case WM_MBUTTONDOWN:
8334 case WM_MOUSEWHEEL:
8335 case WM_MOUSEHWHEEL:
8337 MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
8338 nsIWidget* mozWin = (nsIWidget*)GetNSWindowPtr(ms->hwnd);
8339 if (mozWin) {
8340 // If this window is windowed plugin window, the mouse events are not
8341 // sent to us.
8342 if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin)
8343 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
8344 } else {
8345 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
8347 break;
8351 return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam);
8354 // Process all messages. Roll up when the window is moving, or
8355 // is resizing or when maximized or mininized.
8356 LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam)
8358 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8359 if (sProcessHook) {
8360 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
8361 PrintEvent(cwpt->message, FALSE, FALSE);
8363 #endif
8365 if (sProcessHook) {
8366 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
8367 if (cwpt->message == WM_MOVING ||
8368 cwpt->message == WM_SIZING ||
8369 cwpt->message == WM_GETMINMAXINFO) {
8370 ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message);
8374 return ::CallNextHookEx(sCallProcHook, code, wParam, lParam);
8377 // Register the special "hooks" for dropdown processing.
8378 void nsWindow::RegisterSpecialDropdownHooks()
8380 NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!");
8381 NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!");
8383 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
8385 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
8387 // Install msg hook for moving the window and resizing
8388 if (!sMsgFilterHook) {
8389 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
8390 sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, NULL, GetCurrentThreadId());
8391 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8392 if (!sMsgFilterHook) {
8393 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
8395 #endif
8398 // Install msg hook for menus
8399 if (!sCallProcHook) {
8400 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
8401 sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, NULL, GetCurrentThreadId());
8402 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8403 if (!sCallProcHook) {
8404 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
8406 #endif
8409 // Install msg hook for the mouse
8410 if (!sCallMouseHook) {
8411 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
8412 sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, NULL, GetCurrentThreadId());
8413 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8414 if (!sCallMouseHook) {
8415 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
8417 #endif
8421 // Unhook special message hooks for dropdowns.
8422 void nsWindow::UnregisterSpecialDropdownHooks()
8424 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
8426 if (sCallProcHook) {
8427 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
8428 if (!::UnhookWindowsHookEx(sCallProcHook)) {
8429 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
8431 sCallProcHook = NULL;
8434 if (sMsgFilterHook) {
8435 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
8436 if (!::UnhookWindowsHookEx(sMsgFilterHook)) {
8437 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
8439 sMsgFilterHook = NULL;
8442 if (sCallMouseHook) {
8443 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
8444 if (!::UnhookWindowsHookEx(sCallMouseHook)) {
8445 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
8447 sCallMouseHook = NULL;
8451 // This timer is designed to only fire one time at most each time a "hook" function
8452 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
8453 // hook, but that hook event or a subsequent event may roll up the dropdown before
8454 // this timer function is executed.
8456 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
8457 // before this function fires.
8458 VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
8460 if (sHookTimerId != 0) {
8461 // if the window is NULL then we need to use the ID to kill the timer
8462 BOOL status = ::KillTimer(NULL, sHookTimerId);
8463 NS_ASSERTION(status, "Hook Timer was not killed.");
8464 sHookTimerId = 0;
8467 if (sRollupMsgId != 0) {
8468 // Note: DealWithPopups does the check to make sure that
8469 // sRollupListener and sRollupWidget are not NULL
8470 LRESULT popupHandlingResult;
8471 nsAutoRollup autoRollup;
8472 DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
8473 sRollupMsgId = 0;
8474 sRollupMsgWnd = NULL;
8477 #endif // WinCE
8479 BOOL CALLBACK nsWindow::ClearResourcesCallback(HWND aWnd, LPARAM aMsg)
8481 nsWindow *window = nsWindow::GetNSWindowPtr(aWnd);
8482 if (window) {
8483 window->ClearCachedResources();
8485 return TRUE;
8488 void
8489 nsWindow::ClearCachedResources()
8491 #ifdef CAIRO_HAS_D2D_SURFACE
8492 mD2DWindowSurface = nsnull;
8493 #endif
8494 if (mLayerManager &&
8495 mLayerManager->GetBackendType() == LayerManager::LAYERS_BASIC) {
8496 static_cast<BasicLayerManager*>(mLayerManager.get())->
8497 ClearCachedResources();
8499 ::EnumChildWindows(mWnd, nsWindow::ClearResourcesCallback, 0);
8502 static PRBool IsDifferentThreadWindow(HWND aWnd)
8504 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, NULL);
8507 PRBool
8508 nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
8510 RECT r;
8512 #ifndef WINCE
8513 if (Msg == WM_ACTIVATEAPP)
8514 // don't care about activation/deactivation
8515 return PR_FALSE;
8516 #else
8517 if (Msg == WM_ACTIVATE)
8518 // but on Windows CE we do care about
8519 // activation/deactivation because there doesn't exist
8520 // cancelable Mouse Activation events
8521 return PR_TRUE;
8522 #endif
8524 ::GetWindowRect(aWindow->mWnd, &r);
8525 DWORD pos = ::GetMessagePos();
8526 POINT mp;
8527 mp.x = GET_X_LPARAM(pos);
8528 mp.y = GET_Y_LPARAM(pos);
8530 // was the event inside this window?
8531 return (PRBool) PtInRect(&r, mp);
8534 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8535 BOOL
8536 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
8538 if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
8540 if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
8541 inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
8542 (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam))
8543 #ifndef WINCE
8545 inMsg == WM_NCRBUTTONDOWN ||
8546 inMsg == WM_MOVING ||
8547 inMsg == WM_SIZING ||
8548 inMsg == WM_NCLBUTTONDOWN ||
8549 inMsg == WM_NCMBUTTONDOWN ||
8550 inMsg == WM_MOUSEACTIVATE ||
8551 inMsg == WM_ACTIVATEAPP ||
8552 inMsg == WM_MENUSELECT
8553 #endif
8556 // Rollup if the event is outside the popup.
8557 PRBool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)sRollupWidget);
8559 if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL))
8561 sRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
8562 *outResult = PR_TRUE;
8565 // If we're dealing with menus, we probably have submenus and we don't
8566 // want to rollup if the click is in a parent menu of the current submenu.
8567 PRUint32 popupsToRollup = PR_UINT32_MAX;
8568 if (rollup) {
8569 if ( sMenuRollup ) {
8570 nsAutoTArray<nsIWidget*, 5> widgetChain;
8571 PRUint32 sameTypeCount = sMenuRollup->GetSubmenuWidgetChain(&widgetChain);
8572 for ( PRUint32 i = 0; i < widgetChain.Length(); ++i ) {
8573 nsIWidget* widget = widgetChain[i];
8574 if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
8575 // don't roll up if the mouse event occurred within a menu of the
8576 // same type. If the mouse event occurred in a menu higher than
8577 // that, roll up, but pass the number of popups to Rollup so
8578 // that only those of the same type close up.
8579 if (i < sameTypeCount) {
8580 rollup = PR_FALSE;
8582 else {
8583 popupsToRollup = sameTypeCount;
8585 break;
8587 } // foreach parent menu widget
8588 } // if rollup listener knows about menus
8591 #ifndef WINCE
8592 if (inMsg == WM_MOUSEACTIVATE && popupsToRollup == PR_UINT32_MAX) {
8593 // Prevent the click inside the popup from causing a change in window
8594 // activation. Since the popup is shown non-activated, we need to eat
8595 // any requests to activate the window while it is displayed. Windows
8596 // will automatically activate the popup on the mousedown otherwise.
8597 if (!rollup) {
8598 *outResult = MA_NOACTIVATE;
8599 return TRUE;
8601 else
8603 UINT uMsg = HIWORD(inLParam);
8604 if (uMsg == WM_MOUSEMOVE)
8606 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8607 // must be enabled in Windows.
8608 sRollupListener->ShouldRollupOnMouseActivate(&rollup);
8609 if (!rollup)
8611 *outResult = MA_NOACTIVATE;
8612 return true;
8617 // if we've still determined that we should still rollup everything, do it.
8618 else
8619 #endif
8620 if ( rollup ) {
8621 // sRollupConsumeEvent may be modified by
8622 // nsIRollupListener::Rollup.
8623 PRBool consumeRollupEvent = sRollupConsumeEvent;
8624 // only need to deal with the last rollup for left mouse down events.
8625 sRollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN ? &mLastRollup : nsnull);
8627 // Tell hook to stop processing messages
8628 sProcessHook = PR_FALSE;
8629 sRollupMsgId = 0;
8630 sRollupMsgWnd = NULL;
8632 // return TRUE tells Windows that the event is consumed,
8633 // false allows the event to be dispatched
8635 // So if we are NOT supposed to be consuming events, let it go through
8636 if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
8637 *outResult = MA_ACTIVATE;
8639 // However, don't activate panels
8640 #ifndef WINCE
8641 if (inMsg == WM_MOUSEACTIVATE) {
8642 nsWindow* activateWindow = GetNSWindowPtr(inWnd);
8643 if (activateWindow) {
8644 nsWindowType wintype;
8645 activateWindow->GetWindowType(wintype);
8646 if (wintype == eWindowType_popup && activateWindow->PopupType() == ePopupTypePanel) {
8647 *outResult = MA_NOACTIVATE;
8651 #endif
8653 return TRUE;
8655 #ifndef WINCE
8656 // if we are only rolling up some popups, don't activate and don't let
8657 // the event go through. This prevents clicks menus higher in the
8658 // chain from opening when a context menu is open
8659 if (popupsToRollup != PR_UINT32_MAX && inMsg == WM_MOUSEACTIVATE) {
8660 *outResult = MA_NOACTIVATEANDEAT;
8661 return TRUE;
8663 #endif
8665 } // if event that might trigger a popup to rollup
8666 } // if rollup listeners registered
8668 return FALSE;
8671 /**************************************************************
8672 **************************************************************
8674 ** BLOCK: Misc. utility methods and functions.
8676 ** General use.
8678 **************************************************************
8679 **************************************************************/
8681 // nsModifierKeyState used in various character processing.
8682 nsModifierKeyState::nsModifierKeyState()
8684 mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT);
8685 mIsControlDown = IS_VK_DOWN(NS_VK_CONTROL);
8686 mIsAltDown = IS_VK_DOWN(NS_VK_ALT);
8690 PRInt32 nsWindow::GetWindowsVersion()
8692 #ifdef WINCE
8693 return 0x500;
8694 #else
8695 static PRInt32 version = 0;
8696 static PRBool didCheck = PR_FALSE;
8698 if (!didCheck)
8700 didCheck = PR_TRUE;
8701 OSVERSIONINFOEX osInfo;
8702 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
8703 // This cast is safe and supposed to be here, don't worry
8704 ::GetVersionEx((OSVERSIONINFO*)&osInfo);
8705 version = (osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
8707 return version;
8708 #endif
8711 // Note that the result of GetTopLevelWindow method can be different from the
8712 // result of GetTopLevelHWND method. The result can be non-floating window.
8713 // Because our top level window may be contained in another window which is
8714 // not managed by us.
8715 nsWindow* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup)
8717 nsWindow* curWindow = this;
8719 while (PR_TRUE) {
8720 if (aStopOnDialogOrPopup) {
8721 switch (curWindow->mWindowType) {
8722 case eWindowType_dialog:
8723 case eWindowType_popup:
8724 return curWindow;
8725 default:
8726 break;
8730 // Retrieve the top level parent or owner window
8731 nsWindow* parentWindow = curWindow->GetParentWindow(PR_TRUE);
8733 if (!parentWindow)
8734 return curWindow;
8736 curWindow = parentWindow;
8740 // Note that the result of GetTopLevelHWND can be different from the result
8741 // of GetTopLevelWindow method. Because this is checking whether the window
8742 // is top level only in Win32 window system. Therefore, the result window
8743 // may not be managed by us.
8744 HWND nsWindow::GetTopLevelHWND(HWND aWnd, PRBool aStopOnDialogOrPopup)
8746 HWND curWnd = aWnd;
8747 HWND topWnd = NULL;
8748 HWND upWnd = NULL;
8750 while (curWnd) {
8751 topWnd = curWnd;
8753 if (aStopOnDialogOrPopup) {
8754 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8756 VERIFY_WINDOW_STYLE(style);
8758 if (!(style & WS_CHILD)) // first top-level window
8759 break;
8762 upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
8764 #ifdef WINCE
8765 // For dialog windows, we want just the parent, not the owner.
8766 // For other/popup windows, we want to find the first owner/parent
8767 // that's a dialog and/or has an owner.
8768 if (upWnd && ::GetWindow(curWnd, GW_OWNER) == upWnd) {
8769 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8770 if ((style & WS_DLGFRAME) != 0)
8771 break;
8773 #endif
8775 curWnd = upWnd;
8778 return topWnd;
8781 static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam)
8783 DWORD pid;
8784 ::GetWindowThreadProcessId(hwnd, &pid);
8785 if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd))
8787 gWindowsVisible = PR_TRUE;
8788 return FALSE;
8790 return TRUE;
8793 PRBool nsWindow::CanTakeFocus()
8795 gWindowsVisible = PR_FALSE;
8796 EnumWindows(gEnumWindowsProc, 0);
8797 if (!gWindowsVisible) {
8798 return PR_TRUE;
8799 } else {
8800 HWND fgWnd = ::GetForegroundWindow();
8801 if (!fgWnd) {
8802 return PR_TRUE;
8804 DWORD pid;
8805 GetWindowThreadProcessId(fgWnd, &pid);
8806 if (pid == GetCurrentProcessId()) {
8807 return PR_TRUE;
8810 return PR_FALSE;
8813 void nsWindow::GetMainWindowClass(nsAString& aClass)
8815 nsresult rv;
8816 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8817 if (NS_SUCCEEDED(rv) && prefs) {
8818 nsXPIDLCString name;
8819 rv = prefs->GetCharPref("ui.window_class_override", getter_Copies(name));
8820 if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
8821 aClass.AssignASCII(name.get());
8822 return;
8825 aClass.AssignASCII(sDefaultMainWindowClass);
8828 PRBool nsWindow::UseTrackPointHack()
8830 nsresult rv;
8831 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8832 if (NS_SUCCEEDED(rv) && prefs) {
8833 PRInt32 lHackValue;
8834 rv = prefs->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue);
8835 if (NS_SUCCEEDED(rv)) {
8836 switch (lHackValue) {
8837 case 0: // disabled
8838 return PR_FALSE;
8839 case 1: // enabled
8840 return PR_TRUE;
8841 default: // -1: autodetect
8842 break;
8846 return sDefaultTrackPointHack;
8849 #if !defined(WINCE)
8850 static PRBool
8851 HasRegistryKey(HKEY aRoot, LPCWSTR aName)
8853 HKEY key;
8854 LONG result = ::RegOpenKeyExW(aRoot, aName, 0, KEY_READ, &key);
8855 if (result != ERROR_SUCCESS)
8856 return PR_FALSE;
8857 ::RegCloseKey(key);
8858 return PR_TRUE;
8861 static PRBool
8862 IsObsoleteSynapticsDriver()
8864 HKEY key;
8865 LONG result = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE,
8866 L"Software\\Synaptics\\SynTP\\Install", 0, KEY_READ, &key);
8867 if (result != ERROR_SUCCESS)
8868 return PR_FALSE;
8869 DWORD type;
8870 PRUnichar buf[40];
8871 DWORD buflen = sizeof(buf);
8872 result = ::RegQueryValueExW(key, L"DriverVersion", NULL, &type, (BYTE*)buf, &buflen);
8873 ::RegCloseKey(key);
8874 if (result != ERROR_SUCCESS || type != REG_SZ)
8875 return PR_FALSE;
8876 buf[NS_ARRAY_LENGTH(buf) - 1] = 0;
8878 int majorVersion = wcstol(buf, NULL, 10);
8879 return majorVersion < 15;
8882 void nsWindow::InitInputHackDefaults()
8884 if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Lenovo\\TrackPoint")) {
8885 sDefaultTrackPointHack = PR_TRUE;
8886 } else if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Lenovo\\UltraNav")) {
8887 sDefaultTrackPointHack = PR_TRUE;
8888 } else if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Alps\\Apoint\\TrackPoint")) {
8889 sDefaultTrackPointHack = PR_TRUE;
8890 } else if ((HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB") ||
8891 HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2")) &&
8892 IsObsoleteSynapticsDriver()) {
8893 sDefaultTrackPointHack = PR_TRUE;
8896 #endif // #if !defined(WINCE)
8898 LPARAM nsWindow::lParamToScreen(LPARAM lParam)
8900 POINT pt;
8901 pt.x = GET_X_LPARAM(lParam);
8902 pt.y = GET_Y_LPARAM(lParam);
8903 ::ClientToScreen(mWnd, &pt);
8904 return MAKELPARAM(pt.x, pt.y);
8907 LPARAM nsWindow::lParamToClient(LPARAM lParam)
8909 POINT pt;
8910 pt.x = GET_X_LPARAM(lParam);
8911 pt.y = GET_Y_LPARAM(lParam);
8912 ::ScreenToClient(mWnd, &pt);
8913 return MAKELPARAM(pt.x, pt.y);
8916 /**************************************************************
8917 **************************************************************
8919 ** BLOCK: ChildWindow impl.
8921 ** Child window overrides.
8923 **************************************************************
8924 **************************************************************/
8926 // return the style for a child nsWindow
8927 DWORD ChildWindow::WindowStyle()
8929 DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle();
8930 if (!(style & WS_POPUP))
8931 style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
8932 VERIFY_WINDOW_STYLE(style);
8933 return style;