Bug 594821 - Sync update top level windows when they are first shown. r=roc, a=final.
[mozilla-central.git] / widget / src / windows / nsWindow.cpp
bloba83f0ee8e61a8fa8b08f5667be5f9c77f9ff3cfe
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 syncInvalidate = PR_FALSE;
1229 PRBool wasVisible = mIsVisible;
1230 // Set the status now so that anyone asking during ShowWindow or
1231 // SetWindowPos would get the correct answer.
1232 mIsVisible = bState;
1234 if (!mIsVisible && wasVisible) {
1235 ClearCachedResources();
1238 if (mWnd) {
1239 if (bState) {
1240 if (!wasVisible && mWindowType == eWindowType_toplevel) {
1241 // speed up the initial paint after show for
1242 // top level windows:
1243 syncInvalidate = PR_TRUE;
1244 switch (mSizeMode) {
1245 #ifdef WINCE
1246 case nsSizeMode_Fullscreen:
1247 ::SetForegroundWindow(mWnd);
1248 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1249 MakeFullScreen(TRUE);
1250 break;
1252 case nsSizeMode_Maximized :
1253 ::SetForegroundWindow(mWnd);
1254 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1255 break;
1256 // use default for nsSizeMode_Minimized on Windows CE
1257 #else
1258 case nsSizeMode_Maximized :
1259 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1260 break;
1261 case nsSizeMode_Minimized :
1262 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
1263 break;
1264 #endif
1265 default:
1266 if (CanTakeFocus()) {
1267 #ifdef WINCE
1268 ::SetForegroundWindow(mWnd);
1269 #endif
1270 ::ShowWindow(mWnd, SW_SHOWNORMAL);
1271 } else {
1272 // Place the window behind the foreground window
1273 // (as long as it is not topmost)
1274 HWND wndAfter = ::GetForegroundWindow();
1275 if (!wndAfter)
1276 wndAfter = HWND_BOTTOM;
1277 else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)
1278 wndAfter = HWND_TOP;
1279 ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE |
1280 SWP_NOMOVE | SWP_NOACTIVATE);
1281 GetAttention(2);
1283 break;
1285 } else {
1286 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
1287 if (wasVisible)
1288 flags |= SWP_NOZORDER;
1290 if (mWindowType == eWindowType_popup) {
1291 #ifndef WINCE
1292 // ensure popups are the topmost of the TOPMOST
1293 // layer. Remember not to set the SWP_NOZORDER
1294 // flag as that might allow the taskbar to overlap
1295 // the popup. However on windows ce, we need to
1296 // activate the popup or clicks will not be sent.
1297 flags |= SWP_NOACTIVATE;
1298 #endif
1299 HWND owner = ::GetWindow(mWnd, GW_OWNER);
1300 ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
1301 } else {
1302 #ifndef WINCE
1303 if (mWindowType == eWindowType_dialog && !CanTakeFocus())
1304 flags |= SWP_NOACTIVATE;
1305 #endif
1306 ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
1310 #ifndef WINCE
1311 if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) {
1312 // when a toplevel window or dialog is shown, initialize the UI state
1313 ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
1315 #endif
1316 } else {
1317 if (mWindowType != eWindowType_dialog) {
1318 ::ShowWindow(mWnd, SW_HIDE);
1319 } else {
1320 ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1321 SWP_NOZORDER | SWP_NOACTIVATE);
1326 #ifdef MOZ_XUL
1327 if (!wasVisible && bState)
1328 Invalidate(syncInvalidate);
1329 #endif
1331 return NS_OK;
1334 /**************************************************************
1336 * SECTION: nsIWidget::IsVisible
1338 * Returns the visibility state.
1340 **************************************************************/
1342 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1343 NS_METHOD nsWindow::IsVisible(PRBool & bState)
1345 bState = mIsVisible;
1346 return NS_OK;
1349 /**************************************************************
1351 * SECTION: Window clipping utilities
1353 * Used in Size and Move operations for setting the proper
1354 * window clipping regions for window transparency.
1356 **************************************************************/
1358 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1359 // transparency. These routines are called on size and move operations.
1360 void nsWindow::ClearThemeRegion()
1362 #ifndef WINCE
1363 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1364 (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1365 (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1366 SetWindowRgn(mWnd, NULL, false);
1368 #endif
1371 void nsWindow::SetThemeRegion()
1373 #ifndef WINCE
1374 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1375 // for other window types as needed. The regions are applied generically to the base window
1376 // so default constants are used for part and state. At some point we might need part and
1377 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1378 // change shape based on state haven't come up.
1379 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1380 (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1381 (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1382 HRGN hRgn = nsnull;
1383 RECT rect = {0,0,mBounds.width,mBounds.height};
1385 HDC dc = ::GetDC(mWnd);
1386 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
1387 if (hRgn) {
1388 if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted.
1389 DeleteObject(hRgn);
1391 ::ReleaseDC(mWnd, dc);
1393 #endif
1396 /**************************************************************
1398 * SECTION: nsIWidget::RegisterTouchWindow,
1399 * nsIWidget::UnregisterTouchWindow, and helper functions
1401 * Used to register the native window to receive touch events
1403 **************************************************************/
1405 NS_METHOD nsWindow::RegisterTouchWindow() {
1406 mTouchWindow = PR_TRUE;
1407 #ifndef WINCE
1408 mGesture.RegisterTouchWindow(mWnd);
1409 ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
1410 #endif
1411 return NS_OK;
1414 NS_METHOD nsWindow::UnregisterTouchWindow() {
1415 mTouchWindow = PR_FALSE;
1416 #ifndef WINCE
1417 mGesture.UnregisterTouchWindow(mWnd);
1418 ::EnumChildWindows(mWnd, nsWindow::UnregisterTouchForDescendants, 0);
1419 #endif
1420 return NS_OK;
1423 #ifndef WINCE
1424 BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1425 nsWindow* win = GetNSWindowPtr(aWnd);
1426 if (win)
1427 win->mGesture.RegisterTouchWindow(aWnd);
1428 return TRUE;
1431 BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1432 nsWindow* win = GetNSWindowPtr(aWnd);
1433 if (win)
1434 win->mGesture.UnregisterTouchWindow(aWnd);
1435 return TRUE;
1437 #endif
1439 /**************************************************************
1441 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1442 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1444 * Repositioning and sizing a window.
1446 **************************************************************/
1448 // Move this component
1449 NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
1451 if (mWindowType == eWindowType_toplevel ||
1452 mWindowType == eWindowType_dialog) {
1453 SetSizeMode(nsSizeMode_Normal);
1455 // Check to see if window needs to be moved first
1456 // to avoid a costly call to SetWindowPos. This check
1457 // can not be moved to the calling code in nsView, because
1458 // some platforms do not position child windows correctly
1460 // Only perform this check for non-popup windows, since the positioning can
1461 // in fact change even when the x/y do not. We always need to perform the
1462 // check. See bug #97805 for details.
1463 if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
1465 // Nothing to do, since it is already positioned correctly.
1466 return NS_OK;
1469 mBounds.x = aX;
1470 mBounds.y = aY;
1472 if (mWnd) {
1473 #ifdef DEBUG
1474 // complain if a window is moved offscreen (legal, but potentially worrisome)
1475 if (mIsTopWidgetWindow) { // only a problem for top-level windows
1476 // Make sure this window is actually on the screen before we move it
1477 // XXX: Needs multiple monitor support
1478 HDC dc = ::GetDC(mWnd);
1479 if (dc) {
1480 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1481 RECT workArea;
1482 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1483 // no annoying assertions. just mention the issue.
1484 if (aX < 0 || aX >= workArea.right || aY < 0 || aY >= workArea.bottom)
1485 printf("window moved to offscreen position\n");
1487 ::ReleaseDC(mWnd, dc);
1490 #endif
1491 ClearThemeRegion();
1493 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE;
1494 // Workaround SetWindowPos bug with D3D9. If our window has a clip
1495 // region, some drivers or OSes may incorrectly copy into the clipped-out
1496 // area.
1497 if (mWindowType == eWindowType_plugin &&
1498 (!mLayerManager || mLayerManager->GetBackendType() == LayerManager::LAYERS_D3D9) &&
1499 mClipRects &&
1500 (mClipRectCount != 1 || mClipRects[0] != nsIntRect(0, 0, mBounds.width, mBounds.height))) {
1501 flags |= SWP_NOCOPYBITS;
1503 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0, flags));
1505 SetThemeRegion();
1507 return NS_OK;
1510 // Resize this component
1511 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1513 NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
1514 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1516 // Avoid unnecessary resizing calls
1517 if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1518 return NS_OK;
1520 #ifdef MOZ_XUL
1521 if (eTransparencyTransparent == mTransparencyMode)
1522 ResizeTranslucentWindow(aWidth, aHeight);
1523 #endif
1525 // Set cached value for lightweight and printing
1526 mBounds.width = aWidth;
1527 mBounds.height = aHeight;
1529 if (mWnd) {
1530 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
1532 #ifndef WINCE
1533 if (!aRepaint) {
1534 flags |= SWP_NOREDRAW;
1536 #endif
1538 ClearThemeRegion();
1539 VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
1540 SetThemeRegion();
1543 if (aRepaint)
1544 Invalidate(PR_FALSE);
1546 return NS_OK;
1549 // Resize this component
1550 NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1552 NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize");
1553 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1555 // Avoid unnecessary resizing calls
1556 if (mBounds.x == aX && mBounds.y == aY &&
1557 mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1558 return NS_OK;
1560 #ifdef MOZ_XUL
1561 if (eTransparencyTransparent == mTransparencyMode)
1562 ResizeTranslucentWindow(aWidth, aHeight);
1563 #endif
1565 // Set cached value for lightweight and printing
1566 mBounds.x = aX;
1567 mBounds.y = aY;
1568 mBounds.width = aWidth;
1569 mBounds.height = aHeight;
1571 if (mWnd) {
1572 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
1573 #ifndef WINCE
1574 if (!aRepaint) {
1575 flags |= SWP_NOREDRAW;
1577 #endif
1579 ClearThemeRegion();
1580 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
1581 SetThemeRegion();
1584 if (aRepaint)
1585 Invalidate(PR_FALSE);
1587 return NS_OK;
1590 // Resize the client area and position the widget within it's parent
1591 NS_METHOD nsWindow::ResizeClient(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1593 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1594 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1596 // Adjust our existing window bounds, based on the new client dims.
1597 RECT client;
1598 GetClientRect(mWnd, &client);
1599 nsIntPoint dims(client.right - client.left, client.bottom - client.top);
1600 aWidth = mBounds.width + (aWidth - dims.x);
1601 aHeight = mBounds.height + (aHeight - dims.y);
1603 if (aX || aY) {
1604 // offsets
1605 nsIntRect bounds;
1606 GetScreenBounds(bounds);
1607 aX += bounds.x;
1608 aY += bounds.y;
1609 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1611 return Resize(aWidth, aHeight, aRepaint);
1614 #if !defined(WINCE)
1615 NS_IMETHODIMP
1616 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
1618 NS_ENSURE_ARG_POINTER(aEvent);
1620 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
1621 // you can only begin a resize drag with a mouse event
1622 return NS_ERROR_INVALID_ARG;
1625 nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
1626 if (mouseEvent->button != nsMouseEvent::eLeftButton) {
1627 // you can only begin a resize drag with the left mouse button
1628 return NS_ERROR_INVALID_ARG;
1631 // work out what sizemode we're talking about
1632 WPARAM syscommand;
1633 if (aVertical < 0) {
1634 if (aHorizontal < 0) {
1635 syscommand = SC_SIZE | WMSZ_TOPLEFT;
1636 } else if (aHorizontal == 0) {
1637 syscommand = SC_SIZE | WMSZ_TOP;
1638 } else {
1639 syscommand = SC_SIZE | WMSZ_TOPRIGHT;
1641 } else if (aVertical == 0) {
1642 if (aHorizontal < 0) {
1643 syscommand = SC_SIZE | WMSZ_LEFT;
1644 } else if (aHorizontal == 0) {
1645 return NS_ERROR_INVALID_ARG;
1646 } else {
1647 syscommand = SC_SIZE | WMSZ_RIGHT;
1649 } else {
1650 if (aHorizontal < 0) {
1651 syscommand = SC_SIZE | WMSZ_BOTTOMLEFT;
1652 } else if (aHorizontal == 0) {
1653 syscommand = SC_SIZE | WMSZ_BOTTOM;
1654 } else {
1655 syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT;
1659 // resizing doesn't work if the mouse is already captured
1660 CaptureMouse(PR_FALSE);
1662 // find the top-level window
1663 HWND toplevelWnd = GetTopLevelHWND(mWnd, PR_TRUE);
1665 // tell Windows to start the resize
1666 ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand,
1667 POINTTOPOINTS(aEvent->refPoint));
1669 return NS_OK;
1671 #endif
1672 /**************************************************************
1674 * SECTION: Window Z-order and state.
1676 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1677 * nsIWidget::ConstrainPosition
1679 * Z-order, positioning, restore, minimize, and maximize.
1681 **************************************************************/
1683 // Position the window behind the given window
1684 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1685 nsIWidget *aWidget, PRBool aActivate)
1687 HWND behind = HWND_TOP;
1688 if (aPlacement == eZPlacementBottom)
1689 behind = HWND_BOTTOM;
1690 else if (aPlacement == eZPlacementBelow && aWidget)
1691 behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
1692 UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
1693 if (!aActivate)
1694 flags |= SWP_NOACTIVATE;
1696 if (!CanTakeFocus() && behind == HWND_TOP)
1698 // Can't place the window to top so place it behind the foreground window
1699 // (as long as it is not topmost)
1700 HWND wndAfter = ::GetForegroundWindow();
1701 if (!wndAfter)
1702 behind = HWND_BOTTOM;
1703 else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
1704 behind = wndAfter;
1705 flags |= SWP_NOACTIVATE;
1708 ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
1709 return NS_OK;
1712 // Maximize, minimize or restore the window.
1713 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1714 NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode) {
1716 nsresult rv;
1718 // Let's not try and do anything if we're already in that state.
1719 // (This is needed to prevent problems when calling window.minimize(), which
1720 // calls us directly, and then the OS triggers another call to us.)
1721 if (aMode == mSizeMode)
1722 return NS_OK;
1724 // save the requested state
1725 rv = nsBaseWidget::SetSizeMode(aMode);
1726 if (NS_SUCCEEDED(rv) && mIsVisible) {
1727 int mode;
1729 switch (aMode) {
1730 case nsSizeMode_Fullscreen :
1731 mode = SW_SHOW;
1732 break;
1734 case nsSizeMode_Maximized :
1735 mode = SW_MAXIMIZE;
1736 break;
1738 case nsSizeMode_Minimized :
1739 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1740 // keeps the window active in the tray. So after the window is minimized,
1741 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1742 // we will do some additional processing to get the active window set right.
1743 // If sTrimOnMinimize is set, we let windows handle minimization normally
1744 // using SW_MINIMIZE.
1745 mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED;
1746 break;
1748 default :
1749 mode = SW_RESTORE;
1751 ::ShowWindow(mWnd, mode);
1752 // we dispatch an activate event here to ensure that the right child window
1753 // is focused
1754 if (mode == SW_RESTORE || mode == SW_MAXIMIZE)
1755 DispatchFocusToTopLevelWindow(NS_ACTIVATE);
1757 return rv;
1759 #endif // !defined(WINCE)
1761 // Constrain a potential move to fit onscreen
1762 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop,
1763 PRInt32 *aX, PRInt32 *aY)
1765 if (!mIsTopWidgetWindow) // only a problem for top-level windows
1766 return NS_OK;
1768 PRBool doConstrain = PR_FALSE; // whether we have enough info to do anything
1770 /* get our playing field. use the current screen, or failing that
1771 for any reason, use device caps for the default screen. */
1772 RECT screenRect;
1774 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
1775 if (screenmgr) {
1776 nsCOMPtr<nsIScreen> screen;
1777 PRInt32 left, top, width, height;
1779 // zero size rects confuse the screen manager
1780 width = mBounds.width > 0 ? mBounds.width : 1;
1781 height = mBounds.height > 0 ? mBounds.height : 1;
1782 screenmgr->ScreenForRect(*aX, *aY, width, height,
1783 getter_AddRefs(screen));
1784 if (screen) {
1785 if (mSizeMode != nsSizeMode_Fullscreen) {
1786 // For normalized windows, use the desktop work area.
1787 screen->GetAvailRect(&left, &top, &width, &height);
1788 } else {
1789 // For full screen windows, use the desktop.
1790 screen->GetRect(&left, &top, &width, &height);
1792 screenRect.left = left;
1793 screenRect.right = left+width;
1794 screenRect.top = top;
1795 screenRect.bottom = top+height;
1796 doConstrain = PR_TRUE;
1798 } else {
1799 if (mWnd) {
1800 HDC dc = ::GetDC(mWnd);
1801 if (dc) {
1802 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1803 if (mSizeMode != nsSizeMode_Fullscreen) {
1804 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
1805 } else {
1806 screenRect.left = screenRect.top = 0;
1807 screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN);
1808 screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
1810 doConstrain = PR_TRUE;
1812 ::ReleaseDC(mWnd, dc);
1817 if (aAllowSlop) {
1818 if (*aX < screenRect.left - mBounds.width + kWindowPositionSlop)
1819 *aX = screenRect.left - mBounds.width + kWindowPositionSlop;
1820 else if (*aX >= screenRect.right - kWindowPositionSlop)
1821 *aX = screenRect.right - kWindowPositionSlop;
1823 if (*aY < screenRect.top - mBounds.height + kWindowPositionSlop)
1824 *aY = screenRect.top - mBounds.height + kWindowPositionSlop;
1825 else if (*aY >= screenRect.bottom - kWindowPositionSlop)
1826 *aY = screenRect.bottom - kWindowPositionSlop;
1828 } else {
1830 if (*aX < screenRect.left)
1831 *aX = screenRect.left;
1832 else if (*aX >= screenRect.right - mBounds.width)
1833 *aX = screenRect.right - mBounds.width;
1835 if (*aY < screenRect.top)
1836 *aY = screenRect.top;
1837 else if (*aY >= screenRect.bottom - mBounds.height)
1838 *aY = screenRect.bottom - mBounds.height;
1841 return NS_OK;
1844 /**************************************************************
1846 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1848 * Enabling and disabling the widget.
1850 **************************************************************/
1852 // Enable/disable this component
1853 NS_METHOD nsWindow::Enable(PRBool bState)
1855 if (mWnd) {
1856 ::EnableWindow(mWnd, bState);
1858 return NS_OK;
1861 // Return the current enable state
1862 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
1864 NS_ENSURE_ARG_POINTER(aState);
1866 #ifndef WINCE
1867 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT)));
1868 #else
1869 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(mWnd));
1870 #endif
1872 return NS_OK;
1876 /**************************************************************
1878 * SECTION: nsIWidget::SetFocus
1880 * Give the focus to this widget.
1882 **************************************************************/
1884 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
1886 if (mWnd) {
1887 #ifdef WINSTATE_DEBUG_OUTPUT
1888 if (mWnd == GetTopLevelHWND(mWnd))
1889 printf("*** SetFocus: [ top] raise=%d\n", aRaise);
1890 else
1891 printf("*** SetFocus: [child] raise=%d\n", aRaise);
1892 #endif
1893 // Uniconify, if necessary
1894 HWND toplevelWnd = GetTopLevelHWND(mWnd);
1895 if (aRaise && ::IsIconic(toplevelWnd)) {
1896 ::ShowWindow(toplevelWnd, SW_RESTORE);
1898 ::SetFocus(mWnd);
1900 return NS_OK;
1904 /**************************************************************
1906 * SECTION: Bounds
1908 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1909 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1911 * Bound calculations.
1913 **************************************************************/
1915 // Return the window's full dimensions in screen coordinates.
1916 // If the window has a parent, converts the origin to an offset
1917 // of the parent's screen origin.
1918 NS_METHOD nsWindow::GetBounds(nsIntRect &aRect)
1920 if (mWnd) {
1921 RECT r;
1922 VERIFY(::GetWindowRect(mWnd, &r));
1924 // assign size
1925 aRect.width = r.right - r.left;
1926 aRect.height = r.bottom - r.top;
1928 // chrome on parent:
1929 // ___ 5,5 (chrome start)
1930 // | ____ 10,10 (client start)
1931 // | | ____ 20,20 (child start)
1932 // | | |
1933 // 20,20 - 5,5 = 15,15 (??)
1934 // minus GetClientOffset:
1935 // 15,15 - 5,5 = 10,10
1937 // no chrome on parent:
1938 // ______ 10,10 (win start)
1939 // | ____ 20,20 (child start)
1940 // | |
1941 // 20,20 - 10,10 = 10,10
1943 // walking the chain:
1944 // ___ 5,5 (chrome start)
1945 // | ___ 10,10 (client start)
1946 // | | ___ 20,20 (child start)
1947 // | | | __ 30,30 (child start)
1948 // | | | |
1949 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1950 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1951 // minus GetClientOffset:
1952 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1954 // convert coordinates if parent exists
1955 HWND parent = ::GetParent(mWnd);
1956 if (parent) {
1957 RECT pr;
1958 VERIFY(::GetWindowRect(parent, &pr));
1959 r.left -= pr.left;
1960 r.top -= pr.top;
1961 // adjust for chrome
1962 nsWindow* pWidget = static_cast<nsWindow*>(GetParent());
1963 if (pWidget && pWidget->IsTopLevelWidget()) {
1964 nsIntPoint clientOffset = pWidget->GetClientOffset();
1965 r.left -= clientOffset.x;
1966 r.top -= clientOffset.y;
1969 aRect.x = r.left;
1970 aRect.y = r.top;
1971 } else {
1972 aRect = mBounds;
1975 return NS_OK;
1978 // Get this component dimension
1979 NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect)
1981 if (mWnd) {
1982 RECT r;
1983 VERIFY(::GetClientRect(mWnd, &r));
1985 // assign size
1986 aRect.x = 0;
1987 aRect.y = 0;
1988 aRect.width = r.right - r.left;
1989 aRect.height = r.bottom - r.top;
1991 } else {
1992 aRect.SetRect(0,0,0,0);
1994 return NS_OK;
1997 // Like GetBounds, but don't offset by the parent
1998 NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect)
2000 if (mWnd) {
2001 RECT r;
2002 VERIFY(::GetWindowRect(mWnd, &r));
2004 aRect.width = r.right - r.left;
2005 aRect.height = r.bottom - r.top;
2006 aRect.x = r.left;
2007 aRect.y = r.top;
2008 } else
2009 aRect = mBounds;
2011 return NS_OK;
2014 // return the x,y offset of the client area from the origin
2015 // of the window. If the window is borderless returns (0,0).
2016 nsIntPoint nsWindow::GetClientOffset()
2018 if (!mWnd) {
2019 return nsIntPoint(0, 0);
2022 RECT r1;
2023 GetWindowRect(mWnd, &r1);
2024 nsIntPoint pt = WidgetToScreenOffset();
2025 return nsIntPoint(pt.x - r1.left, pt.y - r1.top);
2028 void
2029 nsWindow::SetDrawsInTitlebar(PRBool aState)
2031 nsWindow * window = GetTopLevelWindow(PR_TRUE);
2032 if (window && window != this) {
2033 return window->SetDrawsInTitlebar(aState);
2036 if (aState) {
2037 // left, top, right, bottom for nsIntMargin
2038 nsIntMargin margins(-1, 0, -1, -1);
2039 SetNonClientMargins(margins);
2041 else {
2042 nsIntMargin margins(-1, -1, -1, -1);
2043 SetNonClientMargins(margins);
2047 NS_IMETHODIMP
2048 nsWindow::GetNonClientMargins(nsIntMargin &margins)
2050 nsWindow * window = GetTopLevelWindow(PR_TRUE);
2051 if (window && window != this) {
2052 return window->GetNonClientMargins(margins);
2055 if (mCustomNonClient) {
2056 margins = mNonClientMargins;
2057 return NS_OK;
2060 margins.top = GetSystemMetrics(SM_CYCAPTION);
2061 margins.bottom = GetSystemMetrics(SM_CYFRAME);
2062 margins.top += margins.bottom;
2063 margins.left = margins.right = GetSystemMetrics(SM_CYFRAME);
2065 return NS_OK;
2068 void
2069 nsWindow::ResetLayout()
2071 // This will trigger a frame changed event, triggering
2072 // nc calc size and a sizemode gecko event.
2073 SetWindowPos(mWnd, 0, 0, 0, 0, 0,
2074 SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|
2075 SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
2077 // If hidden, just send the frame changed event for now.
2078 if (!mIsVisible)
2079 return;
2081 // Send a gecko size event to trigger reflow.
2082 RECT clientRc = {0};
2083 GetClientRect(mWnd, &clientRc);
2084 nsIntRect evRect(nsWindowGfx::ToIntRect(clientRc));
2085 OnResize(evRect);
2087 // Invalidate and update
2088 Invalidate(PR_FALSE);
2091 // Internally track the caption status via a window property. Required
2092 // due to our internal handling of WM_NCACTIVATE when custom client
2093 // margins are set.
2094 static const PRUnichar kManageWindowInfoProperty[] = L"ManageWindowInfoProperty";
2095 typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi);
2096 static GetWindowInfoPtr sGetWindowInfoPtrStub = NULL;
2098 BOOL WINAPI
2099 GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi)
2101 if (!sGetWindowInfoPtrStub) {
2102 NS_ASSERTION(FALSE, "Something is horribly wrong in GetWindowInfoHook!");
2103 return FALSE;
2105 int windowStatus =
2106 reinterpret_cast<LONG_PTR>(GetPropW(hWnd, kManageWindowInfoProperty));
2107 // No property set, return the default data.
2108 if (!windowStatus)
2109 return sGetWindowInfoPtrStub(hWnd, pwi);
2110 // Call GetWindowInfo and update dwWindowStatus with our
2111 // internally tracked value.
2112 BOOL result = sGetWindowInfoPtrStub(hWnd, pwi);
2113 if (result && pwi)
2114 pwi->dwWindowStatus = (windowStatus == 1 ? 0 : WS_ACTIVECAPTION);
2115 return result;
2118 void
2119 nsWindow::UpdateGetWindowInfoCaptionStatus(PRBool aActiveCaption)
2121 if (!mWnd)
2122 return;
2124 if (!sGetWindowInfoPtrStub) {
2125 sUser32Intercept.Init("user32.dll");
2126 if (!sUser32Intercept.AddHook("GetWindowInfo", (void*)GetWindowInfoHook,
2127 (void**) &sGetWindowInfoPtrStub))
2128 return;
2130 // Update our internally tracked caption status
2131 SetPropW(mWnd, kManageWindowInfoProperty,
2132 reinterpret_cast<HANDLE>(static_cast<int>(aActiveCaption) + 1));
2135 // Called when the window layout changes: full screen mode transitions,
2136 // theme changes, and composition changes. Calculates the new non-client
2137 // margins and fires off a frame changed event, which triggers an nc calc
2138 // size windows event, kicking the changes in.
2139 PRBool
2140 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode, PRBool aReflowWindow)
2142 if (!mCustomNonClient)
2143 return PR_FALSE;
2145 mNonClientOffset.top = mNonClientOffset.bottom =
2146 mNonClientOffset.left = mNonClientOffset.right = 0;
2148 if (aSizeMode == -1)
2149 aSizeMode = mSizeMode;
2151 if (aSizeMode == nsSizeMode_Minimized ||
2152 aSizeMode == nsSizeMode_Fullscreen) {
2153 mCaptionHeight = mVertResizeMargin = mHorResizeMargin = 0;
2154 return PR_TRUE;
2157 // Note, for maximized windows, we need to continue to offset the client by
2158 // thick frame margins of a normal window, since windows expects this
2159 // in it's DwmDefWndProc hit testing.
2160 mCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
2161 mHorResizeMargin = GetSystemMetrics(SM_CXFRAME);
2162 mVertResizeMargin = GetSystemMetrics(SM_CYFRAME);
2164 mCaptionHeight += mVertResizeMargin;
2166 // If a margin value is 0, set the offset to the default size of the frame.
2167 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2168 // so that the frame size is equal to the margin value.
2169 if (!mNonClientMargins.top)
2170 mNonClientOffset.top = mCaptionHeight;
2171 else if (mNonClientMargins.top > 0)
2172 mNonClientOffset.top = mCaptionHeight - mNonClientMargins.top;
2174 if (!mNonClientMargins.left)
2175 mNonClientOffset.left = mHorResizeMargin;
2176 else if (mNonClientMargins.left > 0)
2177 mNonClientOffset.left = mHorResizeMargin - mNonClientMargins.left;
2179 if (!mNonClientMargins.right)
2180 mNonClientOffset.right = mHorResizeMargin;
2181 else if (mNonClientMargins.right > 0)
2182 mNonClientOffset.right = mHorResizeMargin - mNonClientMargins.right;
2184 if (!mNonClientMargins.bottom)
2185 mNonClientOffset.bottom = mVertResizeMargin;
2186 else if (mNonClientMargins.bottom > 0)
2187 mNonClientOffset.bottom = mVertResizeMargin - mNonClientMargins.bottom;
2189 #ifndef WINCE
2190 if (aSizeMode == nsSizeMode_Maximized) {
2191 // Address an issue with auto-hide taskbars which fall behind the window.
2192 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2193 // the taskbar works properly.
2194 MONITORINFO info = {sizeof(MONITORINFO)};
2195 if (::GetMonitorInfo(::MonitorFromWindow(mWnd, MONITOR_DEFAULTTOPRIMARY),
2196 &info)) {
2197 RECT r;
2198 if (::GetWindowRect(mWnd, &r)) {
2199 // Adjust window rect to account for non-client margins.
2200 r.top += mVertResizeMargin - mNonClientOffset.top;
2201 r.left += mHorResizeMargin - mNonClientOffset.left;
2202 r.bottom -= mVertResizeMargin - mNonClientOffset.bottom;
2203 r.right -= mHorResizeMargin - mNonClientOffset.right;
2204 // Leave the 1 pixel margin if the window covers the monitor.
2205 if (r.top <= info.rcMonitor.top &&
2206 r.left <= info.rcMonitor.left &&
2207 r.right >= info.rcMonitor.right &&
2208 r.bottom >= info.rcMonitor.bottom)
2209 mNonClientOffset.bottom -= r.bottom - info.rcMonitor.bottom + 1;
2213 #endif
2215 if (aReflowWindow) {
2216 // Force a reflow of content based on the new client
2217 // dimensions.
2218 ResetLayout();
2221 return PR_TRUE;
2224 NS_IMETHODIMP
2225 nsWindow::SetNonClientMargins(nsIntMargin &margins)
2227 if (!mIsTopWidgetWindow ||
2228 mBorderStyle & eBorderStyle_none ||
2229 mHideChrome)
2230 return NS_ERROR_INVALID_ARG;
2232 // Request for a reset
2233 if (margins.top == -1 && margins.left == -1 &&
2234 margins.right == -1 && margins.bottom == -1) {
2235 mCustomNonClient = PR_FALSE;
2236 mNonClientMargins = margins;
2237 RemovePropW(mWnd, kManageWindowInfoProperty);
2238 // Force a reflow of content based on the new client
2239 // dimensions.
2240 ResetLayout();
2241 return NS_OK;
2244 if (margins.top < -1 || margins.bottom < -1 ||
2245 margins.left < -1 || margins.right < -1)
2246 return NS_ERROR_INVALID_ARG;
2248 mNonClientMargins = margins;
2249 mCustomNonClient = PR_TRUE;
2250 if (!UpdateNonClientMargins()) {
2251 NS_WARNING("UpdateNonClientMargins failed!");
2252 return PR_FALSE;
2255 return NS_OK;
2258 void
2259 nsWindow::InvalidateNonClientRegion()
2261 // +-+-----------------------+-+
2262 // | | app non-client chrome | |
2263 // | +-----------------------+ |
2264 // | | app client chrome | | }
2265 // | +-----------------------+ | }
2266 // | | app content | | } area we don't want to invalidate
2267 // | +-----------------------+ | }
2268 // | | app client chrome | | }
2269 // | +-----------------------+ |
2270 // +---------------------------+ <
2271 // ^ ^ windows non-client chrome
2272 // client area = app *
2273 RECT rect;
2274 GetWindowRect(mWnd, &rect);
2275 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2276 HRGN winRgn = CreateRectRgnIndirect(&rect);
2278 // Subtract app client chrome and app content leaving
2279 // windows non-client chrome and app non-client chrome
2280 // in winRgn.
2281 GetWindowRect(mWnd, &rect);
2282 rect.top += mCaptionHeight;
2283 rect.right -= mHorResizeMargin;
2284 rect.bottom -= mHorResizeMargin;
2285 rect.left += mVertResizeMargin;
2286 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2287 HRGN clientRgn = CreateRectRgnIndirect(&rect);
2288 CombineRgn(winRgn, winRgn, clientRgn, RGN_DIFF);
2289 DeleteObject(clientRgn);
2291 // triggers ncpaint and paint events for the two areas
2292 RedrawWindow(mWnd, NULL, winRgn, RDW_FRAME|RDW_INVALIDATE);
2293 DeleteObject(winRgn);
2296 HRGN
2297 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion)
2299 RECT rect;
2300 HRGN rgn = NULL;
2301 if (aRegion == (HRGN)1) { // undocumented value indicating a full refresh
2302 GetWindowRect(mWnd, &rect);
2303 rgn = CreateRectRgnIndirect(&rect);
2304 } else {
2305 rgn = aRegion;
2307 GetClientRect(mWnd, &rect);
2308 MapWindowPoints(mWnd, NULL, (LPPOINT)&rect, 2);
2309 HRGN nonClientRgn = CreateRectRgnIndirect(&rect);
2310 CombineRgn(rgn, rgn, nonClientRgn, RGN_DIFF);
2311 DeleteObject(nonClientRgn);
2312 return rgn;
2315 /**************************************************************
2317 * SECTION: nsIWidget::SetBackgroundColor
2319 * Sets the window background paint color.
2321 **************************************************************/
2323 NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
2325 nsBaseWidget::SetBackgroundColor(aColor);
2327 if (mBrush)
2328 ::DeleteObject(mBrush);
2330 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
2331 #ifndef WINCE
2332 if (mWnd != NULL) {
2333 ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush);
2335 #endif
2336 return NS_OK;
2339 /**************************************************************
2341 * SECTION: nsIWidget::SetCursor
2343 * SetCursor and related utilities for manging cursor state.
2345 **************************************************************/
2347 // Set this component cursor
2348 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
2350 // Only change cursor if it's changing
2352 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2353 //XXX If we want this optimization we need a better way to do it.
2354 //if (aCursor != mCursor) {
2355 HCURSOR newCursor = NULL;
2357 switch (aCursor) {
2358 case eCursor_select:
2359 newCursor = ::LoadCursor(NULL, IDC_IBEAM);
2360 break;
2362 case eCursor_wait:
2363 newCursor = ::LoadCursor(NULL, IDC_WAIT);
2364 break;
2366 case eCursor_hyperlink:
2368 newCursor = ::LoadCursor(NULL, IDC_HAND);
2369 break;
2372 case eCursor_standard:
2373 newCursor = ::LoadCursor(NULL, IDC_ARROW);
2374 break;
2376 case eCursor_n_resize:
2377 case eCursor_s_resize:
2378 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2379 break;
2381 case eCursor_w_resize:
2382 case eCursor_e_resize:
2383 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2384 break;
2386 case eCursor_nw_resize:
2387 case eCursor_se_resize:
2388 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2389 break;
2391 case eCursor_ne_resize:
2392 case eCursor_sw_resize:
2393 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2394 break;
2396 case eCursor_crosshair:
2397 newCursor = ::LoadCursor(NULL, IDC_CROSS);
2398 break;
2400 case eCursor_move:
2401 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2402 break;
2404 case eCursor_help:
2405 newCursor = ::LoadCursor(NULL, IDC_HELP);
2406 break;
2408 case eCursor_copy: // CSS3
2409 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
2410 break;
2412 case eCursor_alias:
2413 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
2414 break;
2416 case eCursor_cell:
2417 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
2418 break;
2420 case eCursor_grab:
2421 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
2422 break;
2424 case eCursor_grabbing:
2425 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
2426 break;
2428 case eCursor_spinning:
2429 newCursor = ::LoadCursor(NULL, IDC_APPSTARTING);
2430 break;
2432 case eCursor_context_menu:
2433 // XXX this CSS3 cursor needs to be implemented
2434 break;
2436 case eCursor_zoom_in:
2437 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
2438 break;
2440 case eCursor_zoom_out:
2441 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
2442 break;
2444 case eCursor_not_allowed:
2445 case eCursor_no_drop:
2446 newCursor = ::LoadCursor(NULL, IDC_NO);
2447 break;
2449 case eCursor_col_resize:
2450 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
2451 break;
2453 case eCursor_row_resize:
2454 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
2455 break;
2457 case eCursor_vertical_text:
2458 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT));
2459 break;
2461 case eCursor_all_scroll:
2462 // XXX not 100% appropriate perhaps
2463 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2464 break;
2466 case eCursor_nesw_resize:
2467 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2468 break;
2470 case eCursor_nwse_resize:
2471 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2472 break;
2474 case eCursor_ns_resize:
2475 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2476 break;
2478 case eCursor_ew_resize:
2479 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2480 break;
2482 case eCursor_none:
2483 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
2484 break;
2486 default:
2487 NS_ERROR("Invalid cursor type");
2488 break;
2491 if (NULL != newCursor) {
2492 mCursor = aCursor;
2493 HCURSOR oldCursor = ::SetCursor(newCursor);
2495 if (sHCursor == oldCursor) {
2496 NS_IF_RELEASE(sCursorImgContainer);
2497 if (sHCursor != NULL)
2498 ::DestroyIcon(sHCursor);
2499 sHCursor = NULL;
2503 return NS_OK;
2506 // Setting the actual cursor
2507 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
2508 PRUint32 aHotspotX, PRUint32 aHotspotY)
2510 if (sCursorImgContainer == aCursor && sHCursor) {
2511 ::SetCursor(sHCursor);
2512 return NS_OK;
2515 PRInt32 width;
2516 PRInt32 height;
2518 nsresult rv;
2519 rv = aCursor->GetWidth(&width);
2520 NS_ENSURE_SUCCESS(rv, rv);
2521 rv = aCursor->GetHeight(&height);
2522 NS_ENSURE_SUCCESS(rv, rv);
2524 // Reject cursors greater than 128 pixels in either direction, to prevent
2525 // spoofing.
2526 // XXX ideally we should rescale. Also, we could modify the API to
2527 // allow trusted content to set larger cursors.
2528 if (width > 128 || height > 128)
2529 return NS_ERROR_NOT_AVAILABLE;
2531 HCURSOR cursor;
2532 rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
2533 NS_ENSURE_SUCCESS(rv, rv);
2535 mCursor = nsCursor(-1);
2536 ::SetCursor(cursor);
2538 NS_IF_RELEASE(sCursorImgContainer);
2539 sCursorImgContainer = aCursor;
2540 NS_ADDREF(sCursorImgContainer);
2542 if (sHCursor != NULL)
2543 ::DestroyIcon(sHCursor);
2544 sHCursor = cursor;
2546 return NS_OK;
2549 /**************************************************************
2551 * SECTION: nsIWidget::Get/SetTransparencyMode
2553 * Manage the transparency mode of the top-level window
2554 * containing this widget.
2556 **************************************************************/
2558 #ifdef MOZ_XUL
2559 nsTransparencyMode nsWindow::GetTransparencyMode()
2561 return GetTopLevelWindow(PR_TRUE)->GetWindowTranslucencyInner();
2564 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
2566 GetTopLevelWindow(PR_TRUE)->SetWindowTranslucencyInner(aMode);
2569 static const nsIntRegion
2570 RegionFromArray(const nsTArray<nsIntRect>& aRects)
2572 nsIntRegion region;
2573 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
2574 region.Or(region, aRects[i]);
2576 return region;
2579 void nsWindow::UpdateTransparentRegion(const nsIntRegion &aTransparentRegion)
2581 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2582 if (!HasGlass() || GetParent())
2583 return;
2585 nsIntRect clientBounds;
2586 GetClientBounds(clientBounds);
2588 // calculate the known fully opaque region by subtracting the transparent
2589 // areas from client bounds. We'll use this to calculate our new glass
2590 // bounds.
2591 nsIntRegion opaqueRegion;
2592 opaqueRegion.Sub(clientBounds, aTransparentRegion);
2594 // If there is no opaque region or hidechrome=true, set margins
2595 // to support a full sheet of glass. Comments in MSDN indicate
2596 // all values must be set to -1 to get a full sheet of glass.
2597 MARGINS margins = { -1, -1, -1, -1 };
2598 bool visiblePlugin = false;
2599 if (!opaqueRegion.IsEmpty() && !mHideChrome) {
2600 nsIntRect pluginBounds;
2601 for (nsIWidget* child = GetFirstChild(); child; child = child->GetNextSibling()) {
2602 nsWindowType type;
2603 child->GetWindowType(type);
2604 if (type == eWindowType_plugin) {
2605 // Collect the bounds of all plugins for GetLargestRectangle.
2606 nsIntRect childBounds;
2607 child->GetBounds(childBounds);
2608 pluginBounds.UnionRect(pluginBounds, childBounds);
2609 // Detect if any region of a plugin is visible.
2610 nsTArray<nsIntRect> currentRects;
2611 child->GetWindowClipRegion(&currentRects);
2612 nsIntRegion currentClipRegion = RegionFromArray(currentRects);
2613 nsIntRect bounds = currentClipRegion.GetBounds();
2614 if (!bounds.IsEmpty()) {
2615 visiblePlugin = true;
2620 // Find the largest rectangle and use that to calculate the inset. Our top
2621 // priority is to include the bounds of all plugins.
2622 // Also don't let MIN_OPAQUE_RECT_HEIGHT_FOR_GLASS_MARGINS override content
2623 // that contains a visible plugin since glass over plugins looks bad.
2624 nsIntRect largest = opaqueRegion.GetLargestRectangle(pluginBounds);
2625 if (visiblePlugin ||
2626 (largest.x <= MAX_HORIZONTAL_GLASS_MARGIN &&
2627 clientBounds.width - largest.XMost() <= MAX_HORIZONTAL_GLASS_MARGIN &&
2628 largest.height >= MIN_OPAQUE_RECT_HEIGHT_FOR_GLASS_MARGINS)) {
2629 margins.cxLeftWidth = largest.x;
2630 margins.cxRightWidth = clientBounds.width - largest.XMost();
2631 margins.cyBottomHeight = clientBounds.height - largest.YMost();
2633 if (mCustomNonClient) {
2634 // The minimum glass height must be the caption buttons height,
2635 // otherwise the buttons are drawn incorrectly.
2636 largest.y = PR_MAX(largest.y,
2637 nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cy);
2639 margins.cyTopHeight = largest.y;
2643 // Only update glass area if there are changes
2644 if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) {
2645 mGlassMargins = margins;
2646 UpdateGlass();
2648 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2651 void nsWindow::UpdateGlass()
2653 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2654 MARGINS margins = mGlassMargins;
2656 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2657 // rendered based on the window style.
2658 // DWMNCRP_ENABLED - The non-client area rendering is
2659 // enabled; the window style is ignored.
2660 DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE;
2661 switch (mTransparencyMode) {
2662 case eTransparencyBorderlessGlass:
2663 // Only adjust if there is some opaque rectangle
2664 if (margins.cxLeftWidth >= 0) {
2665 margins.cxLeftWidth += kGlassMarginAdjustment;
2666 margins.cyTopHeight += kGlassMarginAdjustment;
2667 margins.cxRightWidth += kGlassMarginAdjustment;
2668 margins.cyBottomHeight += kGlassMarginAdjustment;
2670 // Fall through
2671 case eTransparencyGlass:
2672 policy = DWMNCRP_ENABLED;
2673 break;
2676 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
2677 ("glass margins: left:%d top:%d right:%d bottom:%d\n",
2678 margins.cxLeftWidth, margins.cyTopHeight,
2679 margins.cxRightWidth, margins.cyBottomHeight));
2681 // Extends the window frame behind the client area
2682 if(nsUXThemeData::CheckForCompositor()) {
2683 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(mWnd, &margins);
2684 nsUXThemeData::dwmSetWindowAttributePtr(mWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy);
2686 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2688 #endif
2690 /**************************************************************
2692 * SECTION: nsIWidget::HideWindowChrome
2694 * Show or hide window chrome.
2696 **************************************************************/
2698 NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide)
2700 HWND hwnd = GetTopLevelHWND(mWnd, PR_TRUE);
2701 if (!GetNSWindowPtr(hwnd))
2703 NS_WARNING("Trying to hide window decorations in an embedded context");
2704 return NS_ERROR_FAILURE;
2707 if (mHideChrome == aShouldHide)
2708 return NS_OK;
2710 DWORD_PTR style, exStyle;
2711 mHideChrome = aShouldHide;
2712 if (aShouldHide) {
2713 DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2714 DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2716 style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
2717 exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
2718 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
2720 mOldStyle = tempStyle;
2721 mOldExStyle = tempExStyle;
2723 else {
2724 if (!mOldStyle || !mOldExStyle) {
2725 mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2726 mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2729 style = mOldStyle;
2730 exStyle = mOldExStyle;
2733 VERIFY_WINDOW_STYLE(style);
2734 ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
2735 ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
2737 return NS_OK;
2740 /**************************************************************
2742 * SECTION: nsIWidget::Invalidate
2744 * Invalidate an area of the client for painting.
2746 **************************************************************/
2748 // Invalidate this component visible area
2749 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
2751 if (mWnd)
2753 #ifdef WIDGET_DEBUG_OUTPUT
2754 debug_DumpInvalidate(stdout,
2755 this,
2756 nsnull,
2757 aIsSynchronous,
2758 nsCAutoString("noname"),
2759 (PRInt32) mWnd);
2760 #endif // WIDGET_DEBUG_OUTPUT
2762 VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
2764 if (aIsSynchronous) {
2765 VERIFY(::UpdateWindow(mWnd));
2768 return NS_OK;
2771 // Invalidate this component visible area
2772 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, PRBool aIsSynchronous)
2774 if (mWnd)
2776 #ifdef WIDGET_DEBUG_OUTPUT
2777 debug_DumpInvalidate(stdout,
2778 this,
2779 &aRect,
2780 aIsSynchronous,
2781 nsCAutoString("noname"),
2782 (PRInt32) mWnd);
2783 #endif // WIDGET_DEBUG_OUTPUT
2785 RECT rect;
2787 rect.left = aRect.x;
2788 rect.top = aRect.y;
2789 rect.right = aRect.x + aRect.width;
2790 rect.bottom = aRect.y + aRect.height;
2792 VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
2794 if (aIsSynchronous) {
2795 VERIFY(::UpdateWindow(mWnd));
2798 return NS_OK;
2801 NS_IMETHODIMP
2802 nsWindow::MakeFullScreen(PRBool aFullScreen)
2804 #if WINCE_WINDOWS_MOBILE
2805 RECT rc;
2806 if (aFullScreen) {
2807 SetForegroundWindow(mWnd);
2808 if (nsWindowCE::sMenuBarShown) {
2809 SIPINFO sipInfo;
2810 memset(&sipInfo, 0, sizeof(SIPINFO));
2811 sipInfo.cbSize = sizeof(SIPINFO);
2812 if (SipGetInfo(&sipInfo))
2813 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2814 sipInfo.rcVisibleDesktop.bottom);
2815 else
2816 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2817 GetSystemMetrics(SM_CYSCREEN));
2818 RECT menuBarRect;
2819 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle, &menuBarRect) &&
2820 menuBarRect.top < rc.bottom)
2821 rc.bottom = menuBarRect.top;
2822 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_SHOWSIPBUTTON);
2823 } else {
2825 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);
2826 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2829 else {
2830 SHFullScreen(mWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
2831 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
2834 if (aFullScreen)
2835 mSizeMode = nsSizeMode_Fullscreen;
2837 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2838 HideWindowChrome(aFullScreen);
2839 Resize(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PR_TRUE);
2841 return NS_OK;
2843 #else
2845 mFullscreenMode = aFullScreen;
2846 if (aFullScreen) {
2847 if (mSizeMode == nsSizeMode_Fullscreen)
2848 return NS_OK;
2849 mOldSizeMode = mSizeMode;
2850 SetSizeMode(nsSizeMode_Fullscreen);
2851 } else {
2852 SetSizeMode(mOldSizeMode);
2855 UpdateNonClientMargins();
2857 // Prevent window updates during the transition.
2858 DWORD style;
2859 if (nsUXThemeData::CheckForCompositor()) {
2860 style = GetWindowLong(mWnd, GWL_STYLE);
2861 SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
2864 // Will call hide chrome, reposition window. Note this will
2865 // also cache dimensions for restoration, so it should only
2866 // be called once per fullscreen request.
2867 nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen);
2869 if (nsUXThemeData::CheckForCompositor()) {
2870 style = GetWindowLong(mWnd, GWL_STYLE);
2871 SetWindowLong(mWnd, GWL_STYLE, style | WS_VISIBLE);
2872 Invalidate(PR_FALSE);
2875 // Let the dom know via web shell window
2876 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
2877 event.mSizeMode = mSizeMode;
2878 InitEvent(event);
2879 DispatchWindowEvent(&event);
2881 return rv;
2882 #endif
2885 /**************************************************************
2887 * SECTION: nsIWidget::Update
2889 * Force a synchronous repaint of the window.
2891 **************************************************************/
2893 NS_IMETHODIMP nsWindow::Update()
2895 nsresult rv = NS_OK;
2897 // updates can come through for windows no longer holding an mWnd during
2898 // deletes triggered by JavaScript in buttons with mouse feedback
2899 if (mWnd)
2900 VERIFY(::UpdateWindow(mWnd));
2902 return rv;
2905 /**************************************************************
2907 * SECTION: Native data storage
2909 * nsIWidget::GetNativeData
2910 * nsIWidget::FreeNativeData
2912 * Set or clear native data based on a constant.
2914 **************************************************************/
2916 // Return some native data according to aDataType
2917 void* nsWindow::GetNativeData(PRUint32 aDataType)
2919 nsAutoString className;
2920 switch (aDataType) {
2921 case NS_NATIVE_TMP_WINDOW:
2922 GetWindowClass(className);
2923 return (void*)::CreateWindowExW(mIsRTL ? WS_EX_LAYOUTRTL : 0,
2924 className.get(),
2925 L"",
2926 WS_CHILD,
2927 CW_USEDEFAULT,
2928 CW_USEDEFAULT,
2929 CW_USEDEFAULT,
2930 CW_USEDEFAULT,
2931 mWnd,
2932 NULL,
2933 nsToolkit::mDllInstance,
2934 NULL);
2935 case NS_NATIVE_PLUGIN_PORT:
2936 case NS_NATIVE_WIDGET:
2937 case NS_NATIVE_WINDOW:
2938 return (void*)mWnd;
2939 case NS_NATIVE_GRAPHIC:
2940 // XXX: This is sleezy!! Remember to Release the DC after using it!
2941 #ifdef MOZ_XUL
2942 return (void*)(eTransparencyTransparent == mTransparencyMode) ?
2943 mMemoryDC : ::GetDC(mWnd);
2944 #else
2945 return (void*)::GetDC(mWnd);
2946 #endif
2948 #ifdef NS_ENABLE_TSF
2949 case NS_NATIVE_TSF_THREAD_MGR:
2950 return nsTextStore::GetThreadMgr();
2951 case NS_NATIVE_TSF_CATEGORY_MGR:
2952 return nsTextStore::GetCategoryMgr();
2953 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
2954 return nsTextStore::GetDisplayAttrMgr();
2955 #endif //NS_ENABLE_TSF
2957 default:
2958 break;
2961 return NULL;
2964 // Free some native data according to aDataType
2965 void nsWindow::FreeNativeData(void * data, PRUint32 aDataType)
2967 switch (aDataType)
2969 case NS_NATIVE_GRAPHIC:
2970 #ifdef MOZ_XUL
2971 if (eTransparencyTransparent != mTransparencyMode)
2972 ::ReleaseDC(mWnd, (HDC)data);
2973 #else
2974 ::ReleaseDC(mWnd, (HDC)data);
2975 #endif
2976 break;
2977 case NS_NATIVE_WIDGET:
2978 case NS_NATIVE_WINDOW:
2979 case NS_NATIVE_PLUGIN_PORT:
2980 break;
2981 default:
2982 break;
2986 /**************************************************************
2988 * SECTION: nsIWidget::SetTitle
2990 * Set the main windows title text.
2992 **************************************************************/
2994 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
2996 const nsString& strTitle = PromiseFlatString(aTitle);
2997 ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get());
2998 return NS_OK;
3001 /**************************************************************
3003 * SECTION: nsIWidget::SetIcon
3005 * Set the main windows icon.
3007 **************************************************************/
3009 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec)
3011 #ifndef WINCE
3012 // Assume the given string is a local identifier for an icon file.
3014 nsCOMPtr<nsILocalFile> iconFile;
3015 ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
3016 getter_AddRefs(iconFile));
3017 if (!iconFile)
3018 return NS_OK; // not an error if icon is not found
3020 nsAutoString iconPath;
3021 iconFile->GetPath(iconPath);
3023 // XXX this should use MZLU (see bug 239279)
3025 ::SetLastError(0);
3027 HICON bigIcon = (HICON)::LoadImageW(NULL,
3028 (LPCWSTR)iconPath.get(),
3029 IMAGE_ICON,
3030 ::GetSystemMetrics(SM_CXICON),
3031 ::GetSystemMetrics(SM_CYICON),
3032 LR_LOADFROMFILE );
3033 HICON smallIcon = (HICON)::LoadImageW(NULL,
3034 (LPCWSTR)iconPath.get(),
3035 IMAGE_ICON,
3036 ::GetSystemMetrics(SM_CXSMICON),
3037 ::GetSystemMetrics(SM_CYSMICON),
3038 LR_LOADFROMFILE );
3040 if (bigIcon) {
3041 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon);
3042 if (icon)
3043 ::DestroyIcon(icon);
3045 #ifdef DEBUG_SetIcon
3046 else {
3047 NS_LossyConvertUTF16toASCII cPath(iconPath);
3048 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
3050 #endif
3051 if (smallIcon) {
3052 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon);
3053 if (icon)
3054 ::DestroyIcon(icon);
3056 #ifdef DEBUG_SetIcon
3057 else {
3058 NS_LossyConvertUTF16toASCII cPath(iconPath);
3059 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
3061 #endif
3062 #endif // WINCE
3063 return NS_OK;
3066 /**************************************************************
3068 * SECTION: nsIWidget::WidgetToScreenOffset
3070 * Return this widget's origin in screen coordinates.
3072 **************************************************************/
3074 nsIntPoint nsWindow::WidgetToScreenOffset()
3076 POINT point;
3077 point.x = 0;
3078 point.y = 0;
3079 ::ClientToScreen(mWnd, &point);
3080 return nsIntPoint(point.x, point.y);
3083 nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize)
3085 if (!IsPopupWithTitleBar())
3086 return aClientSize;
3088 // just use (200, 200) as the position
3089 RECT r;
3090 r.left = 200;
3091 r.top = 200;
3092 r.right = 200 + aClientSize.width;
3093 r.bottom = 200 + aClientSize.height;
3094 ::AdjustWindowRectEx(&r, WindowStyle(), PR_FALSE, WindowExStyle());
3096 return nsIntSize(r.right - r.left, r.bottom - r.top);
3099 /**************************************************************
3101 * SECTION: nsIWidget::EnableDragDrop
3103 * Enables/Disables drag and drop of files on this widget.
3105 **************************************************************/
3107 #if !defined(WINCE) // implemented in nsWindowCE.cpp
3108 NS_METHOD nsWindow::EnableDragDrop(PRBool aEnable)
3110 NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()");
3112 nsresult rv = NS_ERROR_FAILURE;
3113 if (aEnable) {
3114 if (nsnull == mNativeDragTarget) {
3115 mNativeDragTarget = new nsNativeDragTarget(this);
3116 if (NULL != mNativeDragTarget) {
3117 mNativeDragTarget->AddRef();
3118 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) {
3119 if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) {
3120 rv = NS_OK;
3125 } else {
3126 if (nsnull != mWnd && NULL != mNativeDragTarget) {
3127 ::RevokeDragDrop(mWnd);
3128 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) {
3129 rv = NS_OK;
3131 mNativeDragTarget->DragCancel();
3132 NS_RELEASE(mNativeDragTarget);
3135 return rv;
3137 #endif
3139 /**************************************************************
3141 * SECTION: nsIWidget::CaptureMouse
3143 * Enables/Disables system mouse capture.
3145 **************************************************************/
3147 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
3149 if (!nsToolkit::gMouseTrailer) {
3150 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3151 return NS_OK;
3154 if (aCapture) {
3155 nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd);
3156 ::SetCapture(mWnd);
3157 } else {
3158 nsToolkit::gMouseTrailer->SetCaptureWindow(NULL);
3159 ::ReleaseCapture();
3161 sIsInMouseCapture = aCapture;
3162 return NS_OK;
3165 /**************************************************************
3167 * SECTION: nsIWidget::CaptureRollupEvents
3169 * Dealing with event rollup on destroy for popups. Enables &
3170 * Disables system capture of any and all events that would
3171 * cause a dropdown to be rolled up.
3173 **************************************************************/
3175 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
3176 nsIMenuRollup * aMenuRollup,
3177 PRBool aDoCapture,
3178 PRBool aConsumeRollupEvent)
3180 if (aDoCapture) {
3181 /* we haven't bothered carrying a weak reference to sRollupWidget because
3182 we believe lifespan is properly scoped. this next assertion helps
3183 assure that remains true. */
3184 NS_ASSERTION(!sRollupWidget, "rollup widget reassigned before release");
3185 sRollupConsumeEvent = aConsumeRollupEvent;
3186 NS_IF_RELEASE(sRollupWidget);
3187 NS_IF_RELEASE(sMenuRollup);
3188 sRollupListener = aListener;
3189 sMenuRollup = aMenuRollup;
3190 NS_IF_ADDREF(aMenuRollup);
3191 sRollupWidget = this;
3192 NS_ADDREF(this);
3194 #ifndef WINCE
3195 if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
3196 RegisterSpecialDropdownHooks();
3198 sProcessHook = PR_TRUE;
3199 #endif
3201 } else {
3202 sRollupListener = nsnull;
3203 NS_IF_RELEASE(sMenuRollup);
3204 NS_IF_RELEASE(sRollupWidget);
3206 #ifndef WINCE
3207 sProcessHook = PR_FALSE;
3208 UnregisterSpecialDropdownHooks();
3209 #endif
3212 return NS_OK;
3215 /**************************************************************
3217 * SECTION: nsIWidget::GetAttention
3219 * Bring this window to the user's attention.
3221 **************************************************************/
3223 // Draw user's attention to this window until it comes to foreground.
3224 NS_IMETHODIMP
3225 nsWindow::GetAttention(PRInt32 aCycleCount)
3227 #ifndef WINCE
3228 // Got window?
3229 if (!mWnd)
3230 return NS_ERROR_NOT_INITIALIZED;
3232 // Don't flash if the flash count is 0 or if the
3233 // top level window is already active.
3234 HWND fgWnd = ::GetForegroundWindow();
3235 if (aCycleCount == 0 || fgWnd == GetTopLevelHWND(mWnd))
3236 return NS_OK;
3238 HWND flashWnd = mWnd;
3239 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3240 flashWnd = ownerWnd;
3243 // Don't flash if the owner window is active either.
3244 if (fgWnd == flashWnd)
3245 return NS_OK;
3247 DWORD defaultCycleCount = 0;
3248 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
3250 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3251 FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 };
3252 ::FlashWindowEx(&flashInfo);
3253 #endif
3254 return NS_OK;
3257 void nsWindow::StopFlashing()
3259 #ifndef WINCE
3260 HWND flashWnd = mWnd;
3261 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3262 flashWnd = ownerWnd;
3265 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3266 FLASHW_STOP, 0, 0 };
3267 ::FlashWindowEx(&flashInfo);
3268 #endif
3271 /**************************************************************
3273 * SECTION: nsIWidget::HasPendingInputEvent
3275 * Ask whether there user input events pending. All input events are
3276 * included, including those not targeted at this nsIwidget instance.
3278 **************************************************************/
3280 PRBool
3281 nsWindow::HasPendingInputEvent()
3283 // If there is pending input or the user is currently
3284 // moving the window then return true.
3285 // Note: When the user is moving the window WIN32 spins
3286 // a separate event loop and input events are not
3287 // reported to the application.
3288 if (HIWORD(GetQueueStatus(QS_INPUT)))
3289 return PR_TRUE;
3290 #ifdef WINCE
3291 return PR_FALSE;
3292 #else
3293 GUITHREADINFO guiInfo;
3294 guiInfo.cbSize = sizeof(GUITHREADINFO);
3295 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo))
3296 return PR_FALSE;
3297 return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE);
3298 #endif
3301 /**************************************************************
3303 * SECTION: nsIWidget::GetLayerManager
3305 * Get the layer manager associated with this widget.
3307 **************************************************************/
3309 struct LayerManagerPrefs {
3310 LayerManagerPrefs()
3311 : mAccelerateByDefault(PR_TRUE)
3312 , mDisableAcceleration(PR_FALSE)
3313 , mPreferOpenGL(PR_FALSE)
3314 , mPreferD3D9(PR_FALSE)
3316 PRBool mAccelerateByDefault;
3317 PRBool mDisableAcceleration;
3318 PRBool mForceAcceleration;
3319 PRBool mPreferOpenGL;
3320 PRBool mPreferD3D9;
3323 static void
3324 GetLayerManagerPrefs(LayerManagerPrefs* aManagerPrefs)
3326 nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3327 if (prefs) {
3328 prefs->GetBoolPref("layers.acceleration.disabled",
3329 &aManagerPrefs->mDisableAcceleration);
3330 prefs->GetBoolPref("layers.acceleration.force-enabled",
3331 &aManagerPrefs->mForceAcceleration);
3332 prefs->GetBoolPref("layers.prefer-opengl",
3333 &aManagerPrefs->mPreferOpenGL);
3334 prefs->GetBoolPref("layers.prefer-d3d9",
3335 &aManagerPrefs->mPreferD3D9);
3338 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
3339 aManagerPrefs->mAccelerateByDefault =
3340 aManagerPrefs->mAccelerateByDefault ||
3341 (acceleratedEnv && (*acceleratedEnv != '0'));
3343 PRBool safeMode = PR_FALSE;
3344 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
3345 if (xr)
3346 xr->GetInSafeMode(&safeMode);
3347 aManagerPrefs->mDisableAcceleration =
3348 aManagerPrefs->mDisableAcceleration || safeMode;
3351 mozilla::layers::LayerManager*
3352 nsWindow::GetLayerManager(LayerManagerPersistence aPersistence, bool* aAllowRetaining)
3354 if (aAllowRetaining) {
3355 *aAllowRetaining = true;
3358 #ifndef WINCE
3359 #ifdef MOZ_ENABLE_D3D10_LAYER
3360 if (mLayerManager) {
3361 if (mLayerManager->GetBackendType() ==
3362 mozilla::layers::LayerManager::LAYERS_D3D10)
3364 mozilla::layers::LayerManagerD3D10 *layerManagerD3D10 =
3365 static_cast<mozilla::layers::LayerManagerD3D10*>(mLayerManager.get());
3366 if (layerManagerD3D10->device() !=
3367 gfxWindowsPlatform::GetPlatform()->GetD3D10Device())
3369 mLayerManager->Destroy();
3370 mLayerManager = nsnull;
3374 #endif
3376 if (!mLayerManager ||
3377 (!sAllowD3D9 && aPersistence == LAYER_MANAGER_PERSISTENT &&
3378 mLayerManager->GetBackendType() ==
3379 mozilla::layers::LayerManager::LAYERS_BASIC)) {
3380 // If D3D9 is not currently allowed but the permanent manager is required,
3381 // -and- we're currently using basic layers, run through this check.
3382 LayerManagerPrefs prefs;
3383 GetLayerManagerPrefs(&prefs);
3385 /* We don't currently support using an accelerated layer manager with
3386 * transparent windows so don't even try. I'm also not sure if we even
3387 * want to support this case. See bug #593471 */
3388 if (eTransparencyTransparent == mTransparencyMode ||
3389 prefs.mDisableAcceleration)
3390 mUseAcceleratedRendering = PR_FALSE;
3391 else if (prefs.mAccelerateByDefault)
3392 mUseAcceleratedRendering = PR_TRUE;
3394 if (mUseAcceleratedRendering) {
3395 if (aPersistence == LAYER_MANAGER_PERSISTENT && !sAllowD3D9) {
3396 // This will clear out our existing layer manager if we have one since
3397 // if we hit this with a LayerManager we're always using BasicLayers.
3398 nsToolkit::StartAllowingD3D9();
3401 #ifdef MOZ_ENABLE_D3D10_LAYER
3402 if (!prefs.mPreferD3D9) {
3403 nsRefPtr<mozilla::layers::LayerManagerD3D10> layerManager =
3404 new mozilla::layers::LayerManagerD3D10(this);
3405 if (layerManager->Initialize()) {
3406 mLayerManager = layerManager;
3409 #endif
3410 #ifdef MOZ_ENABLE_D3D9_LAYER
3411 if (!prefs.mPreferOpenGL && !mLayerManager && sAllowD3D9) {
3412 nsRefPtr<mozilla::layers::LayerManagerD3D9> layerManager =
3413 new mozilla::layers::LayerManagerD3D9(this);
3414 if (layerManager->Initialize()) {
3415 mLayerManager = layerManager;
3418 #endif
3419 if (!mLayerManager && prefs.mPreferOpenGL) {
3420 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
3421 PRInt32 status = nsIGfxInfo::FEATURE_NO_INFO;
3423 if (gfxInfo && !prefs.mForceAcceleration) {
3424 gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status);
3427 if (status == nsIGfxInfo::FEATURE_NO_INFO) {
3428 nsRefPtr<mozilla::layers::LayerManagerOGL> layerManager =
3429 new mozilla::layers::LayerManagerOGL(this);
3430 if (layerManager->Initialize()) {
3431 mLayerManager = layerManager;
3434 } else {
3435 NS_WARNING("OpenGL accelerated layers are not supported on this system.");
3440 // Fall back to software if we couldn't use any hardware backends.
3441 if (!mLayerManager)
3442 mLayerManager = CreateBasicLayerManager();
3444 #endif
3446 return mLayerManager;
3449 /**************************************************************
3451 * SECTION: nsIWidget::GetThebesSurface
3453 * Get the Thebes surface associated with this widget.
3455 **************************************************************/
3457 gfxASurface *nsWindow::GetThebesSurface()
3459 #ifdef CAIRO_HAS_D2D_SURFACE
3460 if (mD2DWindowSurface) {
3461 return mD2DWindowSurface;
3463 #endif
3464 if (mPaintDC)
3465 return (new gfxWindowsSurface(mPaintDC));
3467 #ifdef CAIRO_HAS_D2D_SURFACE
3468 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3469 gfxWindowsPlatform::RENDER_DIRECT2D) {
3470 gfxASurface::gfxContentType content = gfxASurface::CONTENT_COLOR;
3471 #if defined(MOZ_XUL)
3472 if (mTransparencyMode != eTransparencyOpaque) {
3473 content = gfxASurface::CONTENT_COLOR_ALPHA;
3475 #endif
3476 return (new gfxD2DSurface(mWnd, content));
3477 } else {
3478 #endif
3479 PRUint32 flags = gfxWindowsSurface::FLAG_TAKE_DC;
3480 if (mTransparencyMode != eTransparencyOpaque) {
3481 flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT;
3483 return (new gfxWindowsSurface(mWnd, flags));
3484 #ifdef CAIRO_HAS_D2D_SURFACE
3486 #endif
3489 /**************************************************************
3491 * SECTION: nsIWidget::OnDefaultButtonLoaded
3493 * Called after the dialog is loaded and it has a default button.
3495 **************************************************************/
3497 NS_IMETHODIMP
3498 nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect)
3500 #ifdef WINCE
3501 return NS_ERROR_NOT_IMPLEMENTED;
3502 #else
3503 if (aButtonRect.IsEmpty())
3504 return NS_OK;
3506 // Don't snap when we are not active.
3507 HWND activeWnd = ::GetActiveWindow();
3508 if (activeWnd != ::GetForegroundWindow() ||
3509 GetTopLevelHWND(mWnd, PR_TRUE) != GetTopLevelHWND(activeWnd, PR_TRUE)) {
3510 return NS_OK;
3513 PRBool isAlwaysSnapCursor = PR_FALSE;
3514 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3515 if (prefs) {
3516 nsCOMPtr<nsIPrefBranch> prefBranch;
3517 prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
3518 if (prefBranch) {
3519 prefBranch->GetBoolPref("ui.cursor_snapping.always_enabled",
3520 &isAlwaysSnapCursor);
3524 if (!isAlwaysSnapCursor) {
3525 BOOL snapDefaultButton;
3526 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0,
3527 &snapDefaultButton, 0) || !snapDefaultButton)
3528 return NS_OK;
3531 nsIntRect widgetRect;
3532 nsresult rv = GetScreenBounds(widgetRect);
3533 NS_ENSURE_SUCCESS(rv, rv);
3534 nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft());
3536 nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2,
3537 buttonRect.y + buttonRect.height / 2);
3538 // The center of the button can be outside of the widget.
3539 // E.g., it could be hidden by scrolling.
3540 if (!widgetRect.Contains(centerOfButton)) {
3541 return NS_OK;
3544 if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) {
3545 NS_ERROR("SetCursorPos failed");
3546 return NS_ERROR_FAILURE;
3548 return NS_OK;
3549 #endif
3552 NS_IMETHODIMP
3553 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta,
3554 PRBool aIsHorizontal,
3555 PRInt32 &aOverriddenDelta)
3557 // The default vertical and horizontal scrolling speed is 3, this is defined
3558 // on the document of SystemParametersInfo in MSDN.
3559 const PRUint32 kSystemDefaultScrollingSpeed = 3;
3561 PRInt32 absOriginDelta = PR_ABS(aOriginalDelta);
3563 // Compute the simple overridden speed.
3564 PRInt32 absComputedOverriddenDelta;
3565 nsresult rv =
3566 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta, aIsHorizontal,
3567 absComputedOverriddenDelta);
3568 NS_ENSURE_SUCCESS(rv, rv);
3570 aOverriddenDelta = aOriginalDelta;
3572 if (absComputedOverriddenDelta == absOriginDelta) {
3573 // We don't override now.
3574 return NS_OK;
3577 // Otherwise, we should check whether the user customized the system settings
3578 // or not. If the user did it, we should respect the will.
3579 UINT systemSpeed;
3580 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) {
3581 return NS_ERROR_FAILURE;
3583 // The default vertical scrolling speed is 3, this is defined on the document
3584 // of SystemParametersInfo in MSDN.
3585 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3586 return NS_OK;
3589 // Only Vista and later, Windows has the system setting of horizontal
3590 // scrolling by the mouse wheel.
3591 if (GetWindowsVersion() >= VISTA_VERSION) {
3592 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) {
3593 return NS_ERROR_FAILURE;
3595 // The default horizontal scrolling speed is 3, this is defined on the
3596 // document of SystemParametersInfo in MSDN.
3597 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3598 return NS_OK;
3602 // Limit the overridden delta value from the system settings. The mouse
3603 // driver might accelerate the scrolling speed already. If so, we shouldn't
3604 // override the scrolling speed for preventing the unexpected high speed
3605 // scrolling.
3606 PRInt32 absDeltaLimit;
3607 rv =
3608 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed,
3609 aIsHorizontal, absDeltaLimit);
3610 NS_ENSURE_SUCCESS(rv, rv);
3612 // If the given delta is larger than our computed limitation value, the delta
3613 // was accelerated by the mouse driver. So, we should do nothing here.
3614 if (absDeltaLimit <= absOriginDelta) {
3615 return NS_OK;
3618 absComputedOverriddenDelta =
3619 PR_MIN(absComputedOverriddenDelta, absDeltaLimit);
3621 aOverriddenDelta = (aOriginalDelta > 0) ? absComputedOverriddenDelta :
3622 -absComputedOverriddenDelta;
3623 return NS_OK;
3626 /**************************************************************
3627 **************************************************************
3629 ** BLOCK: Moz Events
3631 ** Moz GUI event management.
3633 **************************************************************
3634 **************************************************************/
3636 /**************************************************************
3638 * SECTION: Mozilla event initialization
3640 * Helpers for initializing moz events.
3642 **************************************************************/
3644 // Event intialization
3645 MSG nsWindow::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam)
3647 MSG msg;
3648 msg.message = aMessage;
3649 msg.wParam = wParam;
3650 msg.lParam = lParam;
3651 return msg;
3654 void nsWindow::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
3656 if (nsnull == aPoint) { // use the point from the event
3657 // get the message position in client coordinates
3658 if (mWnd != NULL) {
3660 DWORD pos = ::GetMessagePos();
3661 POINT cpos;
3663 cpos.x = GET_X_LPARAM(pos);
3664 cpos.y = GET_Y_LPARAM(pos);
3666 ::ScreenToClient(mWnd, &cpos);
3667 event.refPoint.x = cpos.x;
3668 event.refPoint.y = cpos.y;
3669 } else {
3670 event.refPoint.x = 0;
3671 event.refPoint.y = 0;
3674 else {
3675 // use the point override if provided
3676 event.refPoint.x = aPoint->x;
3677 event.refPoint.y = aPoint->y;
3680 #ifndef WINCE
3681 event.time = ::GetMessageTime();
3682 #else
3683 event.time = PR_Now() / 1000;
3684 #endif
3686 mLastPoint = event.refPoint;
3689 /**************************************************************
3691 * SECTION: Moz event dispatch helpers
3693 * Helpers for dispatching different types of moz events.
3695 **************************************************************/
3697 // Main event dispatch. Invokes callback and ProcessEvent method on
3698 // Event Listener object. Part of nsIWidget.
3699 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
3701 #ifdef WIDGET_DEBUG_OUTPUT
3702 debug_DumpEvent(stdout,
3703 event->widget,
3704 event,
3705 nsCAutoString("something"),
3706 (PRInt32) mWnd);
3707 #endif // WIDGET_DEBUG_OUTPUT
3709 aStatus = nsEventStatus_eIgnore;
3711 // skip processing of suppressed blur events
3712 if (event->message == NS_DEACTIVATE && BlurEventsSuppressed())
3713 return NS_OK;
3715 // Top level windows can have a view attached which requires events be sent
3716 // to the underlying base window and the view. Added when we combined the
3717 // base chrome window with the main content child for nc client area (title
3718 // bar) rendering.
3719 if (mViewCallback) {
3720 // A subset of events are sent to the base xul window first
3721 switch(event->message) {
3722 // send to the base window (view mgr ignores these for the view)
3723 case NS_UISTATECHANGED:
3724 case NS_DESTROY:
3725 case NS_SETZLEVEL:
3726 case NS_XUL_CLOSE:
3727 case NS_MOVE:
3728 (*mEventCallback)(event); // web shell / xul window
3729 return NS_OK;
3731 // sent to the base window, then to the view
3732 case NS_SIZE:
3733 case NS_DEACTIVATE:
3734 case NS_ACTIVATE:
3735 case NS_SIZEMODE:
3736 (*mEventCallback)(event); // web shell / xul window
3737 break;
3739 // attached view events
3740 aStatus = (*mViewCallback)(event);
3742 else if (mEventCallback) {
3743 aStatus = (*mEventCallback)(event);
3746 // the window can be destroyed during processing of seemingly innocuous events like, say,
3747 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3748 // which causes problems with the deleted window. therefore:
3749 if (mOnDestroyCalled)
3750 aStatus = nsEventStatus_eConsumeNoDefault;
3751 return NS_OK;
3754 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
3756 nsGUIEvent event(PR_TRUE, aMsg, this);
3757 InitEvent(event);
3759 PRBool result = DispatchWindowEvent(&event);
3760 return result;
3763 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
3765 nsEventStatus status;
3766 DispatchEvent(event, status);
3767 return ConvertStatus(status);
3770 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event, nsEventStatus &aStatus) {
3771 DispatchEvent(event, aStatus);
3772 return ConvertStatus(aStatus);
3775 PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
3776 const nsTArray<nsAlternativeCharCode>* aAlternativeCharCodes,
3777 UINT aVirtualCharCode, const MSG *aMsg,
3778 const nsModifierKeyState &aModKeyState,
3779 PRUint32 aFlags)
3781 UserActivity();
3783 nsKeyEvent event(PR_TRUE, aEventType, this);
3784 nsIntPoint point(0, 0);
3786 InitEvent(event, &point); // this add ref's event.widget
3788 event.flags |= aFlags;
3789 event.charCode = aCharCode;
3790 if (aAlternativeCharCodes)
3791 event.alternativeCharCodes.AppendElements(*aAlternativeCharCodes);
3792 event.keyCode = aVirtualCharCode;
3794 #ifdef KE_DEBUG
3795 static cnt=0;
3796 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt++,
3797 (NS_KEY_PRESS == aEventType) ? "PRESS" : (aEventType == NS_KEY_UP ? "Up" : "Down"),
3798 event.charCode, event.keyCode);
3799 printf("Shift: %s Control %s Alt: %s \n",
3800 (mIsShiftDown ? "D" : "U"), (mIsControlDown ? "D" : "U"), (mIsAltDown ? "D" : "U"));
3801 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3802 IS_VK_DOWN(NS_VK_SHIFT) ? 'S' : ' ',
3803 IS_VK_DOWN(NS_VK_CONTROL) ? 'C' : ' ',
3804 IS_VK_DOWN(NS_VK_ALT) ? 'A' : ' ',
3805 IS_VK_DOWN(VK_LSHIFT) ? 'S' : ' ',
3806 IS_VK_DOWN(VK_LCONTROL) ? 'C' : ' ',
3807 IS_VK_DOWN(VK_LMENU) ? 'A' : ' ',
3808 IS_VK_DOWN(VK_RMENU) ? 'A' : ' ',
3809 IS_VK_DOWN(VK_RCONTROL) ? 'C' : ' ',
3810 IS_VK_DOWN(VK_RSHIFT) ? 'S' : ' ');
3811 #endif
3813 event.isShift = aModKeyState.mIsShiftDown;
3814 event.isControl = aModKeyState.mIsControlDown;
3815 event.isMeta = PR_FALSE;
3816 event.isAlt = aModKeyState.mIsAltDown;
3818 NPEvent pluginEvent;
3819 if (aMsg && PluginHasFocus()) {
3820 pluginEvent.event = aMsg->message;
3821 pluginEvent.wParam = aMsg->wParam;
3822 pluginEvent.lParam = aMsg->lParam;
3823 event.pluginEvent = (void *)&pluginEvent;
3826 PRBool result = DispatchWindowEvent(&event);
3828 return result;
3831 PRBool nsWindow::DispatchCommandEvent(PRUint32 aEventCommand)
3833 nsCOMPtr<nsIAtom> command;
3834 switch (aEventCommand) {
3835 case APPCOMMAND_BROWSER_BACKWARD:
3836 command = nsWidgetAtoms::Back;
3837 break;
3838 case APPCOMMAND_BROWSER_FORWARD:
3839 command = nsWidgetAtoms::Forward;
3840 break;
3841 case APPCOMMAND_BROWSER_REFRESH:
3842 command = nsWidgetAtoms::Reload;
3843 break;
3844 case APPCOMMAND_BROWSER_STOP:
3845 command = nsWidgetAtoms::Stop;
3846 break;
3847 case APPCOMMAND_BROWSER_SEARCH:
3848 command = nsWidgetAtoms::Search;
3849 break;
3850 case APPCOMMAND_BROWSER_FAVORITES:
3851 command = nsWidgetAtoms::Bookmarks;
3852 break;
3853 case APPCOMMAND_BROWSER_HOME:
3854 command = nsWidgetAtoms::Home;
3855 break;
3856 default:
3857 return PR_FALSE;
3859 nsCommandEvent event(PR_TRUE, nsWidgetAtoms::onAppCommand, command, this);
3861 InitEvent(event);
3862 DispatchWindowEvent(&event);
3864 return PR_TRUE;
3867 // Recursively dispatch synchronous paints for nsIWidget
3868 // descendants with invalidated rectangles.
3869 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
3871 LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
3872 if (proc == (LONG_PTR)&nsWindow::WindowProc) {
3873 // its one of our windows so check to see if it has a
3874 // invalidated rect. If it does. Dispatch a synchronous
3875 // paint.
3876 if (GetUpdateRect(aWnd, NULL, FALSE))
3877 VERIFY(::UpdateWindow(aWnd));
3879 return TRUE;
3882 // Check for pending paints and dispatch any pending paint
3883 // messages for any nsIWidget which is a descendant of the
3884 // top-level window that *this* window is embedded within.
3886 // Note: We do not dispatch pending paint messages for non
3887 // nsIWidget managed windows.
3888 void nsWindow::DispatchPendingEvents()
3890 if (mPainting) {
3891 NS_WARNING("We were asked to dispatch pending events during painting, "
3892 "denying since that's unsafe.");
3893 return;
3896 // We need to ensure that reflow events do not get starved.
3897 // At the same time, we don't want to recurse through here
3898 // as that would prevent us from dispatching starved paints.
3899 static int recursionBlocker = 0;
3900 if (recursionBlocker++ == 0) {
3901 NS_ProcessPendingEvents(nsnull, PR_MillisecondsToInterval(100));
3902 --recursionBlocker;
3905 // Quickly check to see if there are any paint events pending,
3906 // but only dispatch them if it has been long enough since the
3907 // last paint completed.
3908 if (::GetQueueStatus(QS_PAINT) &&
3909 (mLastPaintEndTime.IsNull() ||
3910 (TimeStamp::Now() - mLastPaintEndTime).ToMilliseconds() >= 50)) {
3911 // Find the top level window.
3912 HWND topWnd = GetTopLevelHWND(mWnd);
3914 // Dispatch pending paints for topWnd and all its descendant windows.
3915 // Note: EnumChildWindows enumerates all descendant windows not just
3916 // the children (but not the window itself).
3917 nsWindow::DispatchStarvedPaints(topWnd, 0);
3918 #if !defined(WINCE)
3919 ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, 0);
3920 #else
3921 nsWindowCE::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3922 #endif
3926 // Deal with plugin events
3927 PRBool nsWindow::DispatchPluginEvent(const MSG &aMsg)
3929 if (!PluginHasFocus())
3930 return PR_FALSE;
3932 nsGUIEvent event(PR_TRUE, NS_PLUGIN_EVENT, this);
3933 nsIntPoint point(0, 0);
3934 InitEvent(event, &point);
3935 NPEvent pluginEvent;
3936 pluginEvent.event = aMsg.message;
3937 pluginEvent.wParam = aMsg.wParam;
3938 pluginEvent.lParam = aMsg.lParam;
3939 event.pluginEvent = (void *)&pluginEvent;
3940 return DispatchWindowEvent(&event);
3943 PRBool nsWindow::DispatchPluginEvent(UINT aMessage,
3944 WPARAM aWParam,
3945 LPARAM aLParam,
3946 PRBool aDispatchPendingEvents)
3948 PRBool ret = DispatchPluginEvent(InitMSG(aMessage, aWParam, aLParam));
3949 if (aDispatchPendingEvents) {
3950 DispatchPendingEvents();
3952 return ret;
3955 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
3956 UINT aLastMsg)
3958 MSG msg;
3959 ::GetMessageW(&msg, mWnd, aFirstMsg, aLastMsg);
3960 DispatchPluginEvent(msg);
3963 // Deal with all sort of mouse event
3964 PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
3965 LPARAM lParam, PRBool aIsContextMenuKey,
3966 PRInt16 aButton, PRUint16 aInputSource)
3968 PRBool result = PR_FALSE;
3970 UserActivity();
3972 if (!mEventCallback) {
3973 return result;
3976 switch (aEventType) {
3977 case NS_MOUSE_BUTTON_DOWN:
3978 CaptureMouse(PR_TRUE);
3979 break;
3981 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3982 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3983 case NS_MOUSE_BUTTON_UP:
3984 case NS_MOUSE_MOVE:
3985 case NS_MOUSE_EXIT:
3986 if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && sIsInMouseCapture)
3987 CaptureMouse(PR_FALSE);
3988 break;
3990 default:
3991 break;
3993 } // switch
3995 nsIntPoint eventPoint;
3996 eventPoint.x = GET_X_LPARAM(lParam);
3997 eventPoint.y = GET_Y_LPARAM(lParam);
3999 nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal,
4000 aIsContextMenuKey
4001 ? nsMouseEvent::eContextMenuKey
4002 : nsMouseEvent::eNormal);
4003 if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) {
4004 nsIntPoint zero(0, 0);
4005 InitEvent(event, &zero);
4006 } else {
4007 InitEvent(event, &eventPoint);
4010 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
4011 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
4012 event.isMeta = PR_FALSE;
4013 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
4014 event.button = aButton;
4015 event.inputSource = aInputSource;
4017 nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
4019 // Suppress mouse moves caused by widget creation
4020 if (aEventType == NS_MOUSE_MOVE)
4022 if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y))
4023 return result;
4024 sLastMouseMovePoint.x = mpScreen.x;
4025 sLastMouseMovePoint.y = mpScreen.y;
4028 PRBool insideMovementThreshold = (abs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
4029 (abs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
4031 BYTE eventButton;
4032 switch (aButton) {
4033 case nsMouseEvent::eLeftButton:
4034 eventButton = VK_LBUTTON;
4035 break;
4036 case nsMouseEvent::eMiddleButton:
4037 eventButton = VK_MBUTTON;
4038 break;
4039 case nsMouseEvent::eRightButton:
4040 eventButton = VK_RBUTTON;
4041 break;
4042 default:
4043 eventButton = 0;
4044 break;
4047 // Doubleclicks are used to set the click count, then changed to mousedowns
4048 // We're going to time double-clicks from mouse *up* to next mouse *down*
4049 #ifndef WINCE
4050 LONG curMsgTime = ::GetMessageTime();
4051 #else
4052 LONG curMsgTime = PR_Now() / 1000;
4053 #endif
4055 if (aEventType == NS_MOUSE_DOUBLECLICK) {
4056 event.message = NS_MOUSE_BUTTON_DOWN;
4057 event.button = aButton;
4058 sLastClickCount = 2;
4060 else if (aEventType == NS_MOUSE_BUTTON_UP) {
4061 // remember when this happened for the next mouse down
4062 sLastMousePoint.x = eventPoint.x;
4063 sLastMousePoint.y = eventPoint.y;
4064 sLastMouseButton = eventButton;
4066 else if (aEventType == NS_MOUSE_BUTTON_DOWN) {
4067 // now look to see if we want to convert this to a double- or triple-click
4068 if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold &&
4069 eventButton == sLastMouseButton) {
4070 sLastClickCount ++;
4071 } else {
4072 // reset the click count, to count *this* click
4073 sLastClickCount = 1;
4075 // Set last Click time on MouseDown only
4076 sLastMouseDownTime = curMsgTime;
4078 else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
4079 sLastClickCount = 0;
4081 else if (aEventType == NS_MOUSE_EXIT) {
4082 event.exit = IsTopLevelMouseExit(mWnd) ? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
4084 else if (aEventType == NS_MOUSE_MOZHITTEST)
4086 event.flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
4088 event.clickCount = sLastClickCount;
4090 #ifdef NS_DEBUG_XX
4091 printf("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount);
4092 #endif
4094 NPEvent pluginEvent;
4096 switch (aEventType)
4098 case NS_MOUSE_BUTTON_DOWN:
4099 switch (aButton) {
4100 case nsMouseEvent::eLeftButton:
4101 pluginEvent.event = WM_LBUTTONDOWN;
4102 break;
4103 case nsMouseEvent::eMiddleButton:
4104 pluginEvent.event = WM_MBUTTONDOWN;
4105 break;
4106 case nsMouseEvent::eRightButton:
4107 pluginEvent.event = WM_RBUTTONDOWN;
4108 break;
4109 default:
4110 break;
4112 break;
4113 case NS_MOUSE_BUTTON_UP:
4114 switch (aButton) {
4115 case nsMouseEvent::eLeftButton:
4116 pluginEvent.event = WM_LBUTTONUP;
4117 break;
4118 case nsMouseEvent::eMiddleButton:
4119 pluginEvent.event = WM_MBUTTONUP;
4120 break;
4121 case nsMouseEvent::eRightButton:
4122 pluginEvent.event = WM_RBUTTONUP;
4123 break;
4124 default:
4125 break;
4127 break;
4128 case NS_MOUSE_DOUBLECLICK:
4129 switch (aButton) {
4130 case nsMouseEvent::eLeftButton:
4131 pluginEvent.event = WM_LBUTTONDBLCLK;
4132 break;
4133 case nsMouseEvent::eMiddleButton:
4134 pluginEvent.event = WM_MBUTTONDBLCLK;
4135 break;
4136 case nsMouseEvent::eRightButton:
4137 pluginEvent.event = WM_RBUTTONDBLCLK;
4138 break;
4139 default:
4140 break;
4142 break;
4143 case NS_MOUSE_MOVE:
4144 pluginEvent.event = WM_MOUSEMOVE;
4145 break;
4146 case NS_MOUSE_EXIT:
4147 pluginEvent.event = WM_MOUSELEAVE;
4148 break;
4149 default:
4150 pluginEvent.event = WM_NULL;
4151 break;
4154 pluginEvent.wParam = wParam; // plugins NEED raw OS event flags!
4155 pluginEvent.lParam = lParam;
4157 event.pluginEvent = (void *)&pluginEvent;
4159 // call the event callback
4160 if (nsnull != mEventCallback) {
4161 if (nsToolkit::gMouseTrailer)
4162 nsToolkit::gMouseTrailer->Disable();
4163 if (aEventType == NS_MOUSE_MOVE) {
4164 if (nsToolkit::gMouseTrailer && !sIsInMouseCapture) {
4165 nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd);
4167 nsIntRect rect;
4168 GetBounds(rect);
4169 rect.x = 0;
4170 rect.y = 0;
4172 if (rect.Contains(event.refPoint)) {
4173 if (sCurrentWindow == NULL || sCurrentWindow != this) {
4174 if ((nsnull != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
4175 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
4176 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, PR_FALSE,
4177 nsMouseEvent::eLeftButton, aInputSource);
4179 sCurrentWindow = this;
4180 if (!mInDtor) {
4181 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
4182 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, PR_FALSE,
4183 nsMouseEvent::eLeftButton, aInputSource);
4187 } else if (aEventType == NS_MOUSE_EXIT) {
4188 if (sCurrentWindow == this) {
4189 sCurrentWindow = nsnull;
4193 result = DispatchWindowEvent(&event);
4195 if (nsToolkit::gMouseTrailer)
4196 nsToolkit::gMouseTrailer->Enable();
4198 // Release the widget with NS_IF_RELEASE() just in case
4199 // the context menu key code in nsEventListenerManager::HandleEvent()
4200 // released it already.
4201 return result;
4204 return result;
4207 // Deal with accessibile event
4208 #ifdef ACCESSIBILITY
4209 nsAccessible*
4210 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType)
4212 if (nsnull == mEventCallback) {
4213 return nsnull;
4216 nsAccessibleEvent event(PR_TRUE, aEventType, this);
4217 InitEvent(event, nsnull);
4219 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
4220 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
4221 event.isMeta = PR_FALSE;
4222 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
4224 DispatchWindowEvent(&event);
4226 return event.mAccessible;
4228 #endif
4230 PRBool nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType)
4232 if (aEventType == NS_ACTIVATE)
4233 sJustGotActivate = PR_FALSE;
4234 sJustGotDeactivate = PR_FALSE;
4236 // retrive the toplevel window or dialog
4237 HWND curWnd = mWnd;
4238 HWND toplevelWnd = NULL;
4239 while (curWnd) {
4240 toplevelWnd = curWnd;
4242 nsWindow *win = GetNSWindowPtr(curWnd);
4243 if (win) {
4244 nsWindowType wintype;
4245 win->GetWindowType(wintype);
4246 if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog)
4247 break;
4250 curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
4253 if (toplevelWnd) {
4254 nsWindow *win = GetNSWindowPtr(toplevelWnd);
4255 if (win)
4256 return win->DispatchFocus(aEventType);
4259 return PR_FALSE;
4262 // Deal with focus messages
4263 PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
4265 // call the event callback
4266 if (mEventCallback) {
4267 nsGUIEvent event(PR_TRUE, aEventType, this);
4268 InitEvent(event);
4270 //focus and blur event should go to their base widget loc, not current mouse pos
4271 event.refPoint.x = 0;
4272 event.refPoint.y = 0;
4274 NPEvent pluginEvent;
4276 switch (aEventType)
4278 case NS_ACTIVATE:
4279 pluginEvent.event = WM_SETFOCUS;
4280 break;
4281 case NS_DEACTIVATE:
4282 pluginEvent.event = WM_KILLFOCUS;
4283 break;
4284 case NS_PLUGIN_ACTIVATE:
4285 pluginEvent.event = WM_KILLFOCUS;
4286 break;
4287 default:
4288 break;
4291 event.pluginEvent = (void *)&pluginEvent;
4293 return DispatchWindowEvent(&event);
4295 return PR_FALSE;
4298 PRBool nsWindow::IsTopLevelMouseExit(HWND aWnd)
4300 DWORD pos = ::GetMessagePos();
4301 POINT mp;
4302 mp.x = GET_X_LPARAM(pos);
4303 mp.y = GET_Y_LPARAM(pos);
4304 HWND mouseWnd = ::WindowFromPoint(mp);
4306 // GetTopLevelHWND will return a HWND for the window frame (which includes
4307 // the non-client area). If the mouse has moved into the non-client area,
4308 // we should treat it as a top-level exit.
4309 HWND mouseTopLevel = nsWindow::GetTopLevelHWND(mouseWnd);
4310 if (mouseWnd == mouseTopLevel)
4311 return PR_TRUE;
4313 return nsWindow::GetTopLevelHWND(aWnd) != mouseTopLevel;
4316 PRBool nsWindow::BlurEventsSuppressed()
4318 // are they suppressed in this window?
4319 if (mBlurSuppressLevel > 0)
4320 return PR_TRUE;
4322 // are they suppressed by any container widget?
4323 HWND parentWnd = ::GetParent(mWnd);
4324 if (parentWnd) {
4325 nsWindow *parent = GetNSWindowPtr(parentWnd);
4326 if (parent)
4327 return parent->BlurEventsSuppressed();
4329 return PR_FALSE;
4332 // In some circumstances (opening dependent windows) it makes more sense
4333 // (and fixes a crash bug) to not blur the parent window. Called from
4334 // nsFilePicker.
4335 void nsWindow::SuppressBlurEvents(PRBool aSuppress)
4337 if (aSuppress)
4338 ++mBlurSuppressLevel; // for this widget
4339 else {
4340 NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression");
4341 if (mBlurSuppressLevel > 0)
4342 --mBlurSuppressLevel;
4346 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
4348 return aStatus == nsEventStatus_eConsumeNoDefault;
4351 /**************************************************************
4353 * SECTION: IPC
4355 * IPC related helpers.
4357 **************************************************************/
4359 #ifdef MOZ_IPC
4361 // static
4362 bool
4363 nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult)
4365 switch(aMsg) {
4366 case WM_SETFOCUS:
4367 case WM_KILLFOCUS:
4368 case WM_ENABLE:
4369 case WM_WINDOWPOSCHANGING:
4370 case WM_WINDOWPOSCHANGED:
4371 case WM_PARENTNOTIFY:
4372 case WM_ACTIVATEAPP:
4373 case WM_NCACTIVATE:
4374 case WM_ACTIVATE:
4375 case WM_CHILDACTIVATE:
4376 case WM_IME_SETCONTEXT:
4377 case WM_IME_NOTIFY:
4378 case WM_SHOWWINDOW:
4379 case WM_CANCELMODE:
4380 case WM_MOUSEACTIVATE:
4381 case WM_CONTEXTMENU:
4382 aResult = 0;
4383 return true;
4385 case WM_SETTINGCHANGE:
4386 case WM_SETCURSOR:
4387 return false;
4390 #ifdef DEBUG
4391 char szBuf[200];
4392 sprintf(szBuf,
4393 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg);
4394 NS_WARNING(szBuf);
4395 #endif
4397 return false;
4400 void
4401 nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
4403 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4404 "Failed to prevent a nonqueued message from running!");
4406 // Modal UI being displayed in windowless plugins.
4407 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4408 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4409 LRESULT res;
4410 if (IsAsyncResponseEvent(msg, res)) {
4411 ReplyMessage(res);
4413 return;
4416 // Handle certain sync plugin events sent to the parent which
4417 // trigger ipc calls that result in deadlocks.
4419 DWORD dwResult = 0;
4420 PRBool handled = PR_FALSE;
4422 switch(msg) {
4423 // Windowless flash sending WM_ACTIVATE events to the main window
4424 // via calls to ShowWindow.
4425 case WM_ACTIVATE:
4426 if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE &&
4427 IsWindow((HWND)lParam))
4428 handled = PR_TRUE;
4429 break;
4430 // Wheel events forwarded from the child.
4431 case WM_MOUSEWHEEL:
4432 case WM_MOUSEHWHEEL:
4433 case WM_HSCROLL:
4434 case WM_VSCROLL:
4435 // Plugins taking or losing focus triggering focus app messages.
4436 case WM_SETFOCUS:
4437 case WM_KILLFOCUS:
4438 // Windowed plugins that pass sys key events to defwndproc generate
4439 // WM_SYSCOMMAND events to the main window.
4440 case WM_SYSCOMMAND:
4441 // Windowed plugins that fire context menu selection events to parent
4442 // windows.
4443 case WM_CONTEXTMENU:
4444 // IME events fired as a result of synchronous focus changes
4445 case WM_IME_SETCONTEXT:
4446 handled = PR_TRUE;
4447 break;
4450 if (handled &&
4451 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4452 ReplyMessage(dwResult);
4456 #endif // MOZ_IPC
4458 /**************************************************************
4459 **************************************************************
4461 ** BLOCK: Native events
4463 ** Main Windows message handlers and OnXXX handlers for
4464 ** Windows event handling.
4466 **************************************************************
4467 **************************************************************/
4469 /**************************************************************
4471 * SECTION: Wind proc.
4473 * The main Windows event procedures and associated
4474 * message processing methods.
4476 **************************************************************/
4478 #ifdef _MSC_VER
4479 static int ReportException(EXCEPTION_POINTERS *aExceptionInfo)
4481 #ifdef MOZ_CRASHREPORTER
4482 nsCOMPtr<nsICrashReporter> cr =
4483 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
4484 if (cr)
4485 cr->WriteMinidumpForException(aExceptionInfo);
4486 #endif
4487 return EXCEPTION_EXECUTE_HANDLER;
4489 #endif
4491 static PRBool
4492 DisplaySystemMenu(HWND hWnd, nsSizeMode sizeMode, PRBool isRtl, PRInt32 x, PRInt32 y)
4494 GetSystemMenu(hWnd, TRUE); // reset the system menu
4495 HMENU hMenu = GetSystemMenu(hWnd, FALSE);
4496 if (hMenu) {
4497 // update the options
4498 switch(sizeMode) {
4499 case nsSizeMode_Fullscreen:
4500 EnableMenuItem(hMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED);
4501 // intentional fall through
4502 case nsSizeMode_Maximized:
4503 EnableMenuItem(hMenu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
4504 EnableMenuItem(hMenu, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
4505 EnableMenuItem(hMenu, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
4506 break;
4507 case nsSizeMode_Minimized:
4508 EnableMenuItem(hMenu, SC_MINIMIZE, MF_BYCOMMAND | MF_GRAYED);
4509 break;
4510 case nsSizeMode_Normal:
4511 EnableMenuItem(hMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED);
4512 break;
4514 LPARAM cmd =
4515 TrackPopupMenu(hMenu,
4516 (TPM_LEFTBUTTON|TPM_RIGHTBUTTON|
4517 TPM_RETURNCMD|TPM_TOPALIGN|
4518 (isRtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN)),
4519 x, y, 0, hWnd, NULL);
4520 if (cmd) {
4521 PostMessage(hWnd, WM_SYSCOMMAND, cmd, 0);
4522 return PR_TRUE;
4525 return PR_FALSE;
4528 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
4529 // exceptions and passes the real work to WindowProcInternal. See bug 587406
4530 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
4531 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4533 #ifdef _MSC_VER
4534 __try {
4535 return WindowProcInternal(hWnd, msg, wParam, lParam);
4537 __except(ReportException(GetExceptionInformation())) {
4538 ::TerminateProcess(::GetCurrentProcess(), 253);
4540 #else
4541 return WindowProcInternal(hWnd, msg, wParam, lParam);
4542 #endif
4545 LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4547 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4548 MOZ_FUNCTION_NAME, __LINE__, hWnd, msg,
4549 wParam, lParam);
4551 if (::GetWindowLongPtrW(hWnd, GWLP_ID) == eFakeTrackPointScrollableID) {
4552 // This message was sent to the FAKETRACKPOINTSCROLLABLE.
4553 if (msg == WM_HSCROLL) {
4554 // Route WM_HSCROLL messages to the main window.
4555 hWnd = ::GetParent(::GetParent(hWnd));
4556 } else {
4557 // Handle all other messages with its original window procedure.
4558 WNDPROC prevWindowProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
4559 return ::CallWindowProcW(prevWindowProc, hWnd, msg, wParam, lParam);
4563 // Get the window which caused the event and ask it to process the message
4564 nsWindow *someWindow = GetNSWindowPtr(hWnd);
4566 #ifdef MOZ_IPC
4567 if (someWindow)
4568 someWindow->IPCWindowProcHandler(msg, wParam, lParam);
4569 #endif
4571 // create this here so that we store the last rolled up popup until after
4572 // the event has been processed.
4573 nsAutoRollup autoRollup;
4575 LRESULT popupHandlingResult;
4576 if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult))
4577 return popupHandlingResult;
4579 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4580 // why we are hitting this assert
4581 if (nsnull == someWindow) {
4582 NS_ASSERTION(someWindow, "someWindow is null, cannot call any CallWindowProc");
4583 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
4586 // hold on to the window for the life of this method, in case it gets
4587 // deleted during processing. yes, it's a double hack, since someWindow
4588 // is not really an interface.
4589 nsCOMPtr<nsISupports> kungFuDeathGrip;
4590 if (!someWindow->mInDtor) // not if we're in the destructor!
4591 kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)someWindow);
4593 // Call ProcessMessage
4594 LRESULT retValue;
4595 if (PR_TRUE == someWindow->ProcessMessage(msg, wParam, lParam, &retValue)) {
4596 return retValue;
4599 LRESULT res = ::CallWindowProcW(someWindow->GetPrevWindowProc(),
4600 hWnd, msg, wParam, lParam);
4602 return res;
4605 // The main windows message processing method for plugins.
4606 // The result means whether this method processed the native
4607 // event for plugin. If false, the native event should be
4608 // processed by the caller self.
4609 PRBool
4610 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
4611 LRESULT *aResult,
4612 PRBool &aCallDefWndProc)
4614 NS_PRECONDITION(aResult, "aResult must be non-null.");
4615 *aResult = 0;
4617 aCallDefWndProc = PR_FALSE;
4618 PRBool eventDispatched = PR_FALSE;
4619 switch (aMsg.message) {
4620 case WM_CHAR:
4621 case WM_SYSCHAR:
4622 *aResult = ProcessCharMessage(aMsg, &eventDispatched);
4623 break;
4625 case WM_KEYUP:
4626 case WM_SYSKEYUP:
4627 *aResult = ProcessKeyUpMessage(aMsg, &eventDispatched);
4628 break;
4630 case WM_KEYDOWN:
4631 case WM_SYSKEYDOWN:
4632 *aResult = ProcessKeyDownMessage(aMsg, &eventDispatched);
4633 break;
4635 case WM_DEADCHAR:
4636 case WM_SYSDEADCHAR:
4638 case WM_CUT:
4639 case WM_COPY:
4640 case WM_PASTE:
4641 case WM_CLEAR:
4642 case WM_UNDO:
4643 break;
4645 default:
4646 return PR_FALSE;
4649 if (!eventDispatched)
4650 aCallDefWndProc = !DispatchPluginEvent(aMsg);
4651 DispatchPendingEvents();
4652 return PR_TRUE;
4655 // The main windows message processing method.
4656 PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
4657 LRESULT *aRetValue)
4659 // (Large blocks of code should be broken out into OnEvent handlers.)
4660 if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
4661 return PR_TRUE;
4663 #if defined(EVENT_DEBUG_OUTPUT)
4664 // First param shows all events, second param indicates whether
4665 // to show mouse move events. See nsWindowDbg for details.
4666 PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
4667 #endif
4669 PRBool eatMessage;
4670 if (nsIMM32Handler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
4671 eatMessage)) {
4672 return mWnd ? eatMessage : PR_TRUE;
4675 if (PluginHasFocus()) {
4676 PRBool callDefaultWndProc;
4677 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4678 if (ProcessMessageForPlugin(nativeMsg, aRetValue, callDefaultWndProc)) {
4679 return mWnd ? !callDefaultWndProc : PR_TRUE;
4683 PRBool result = PR_FALSE; // call the default nsWindow proc
4684 *aRetValue = 0;
4686 static PRBool getWheelInfo = PR_TRUE;
4688 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4689 // Glass hit testing w/custom transparent margins
4690 LRESULT dwmHitResult;
4691 if (mCustomNonClient &&
4692 nsUXThemeData::CheckForCompositor() &&
4693 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) {
4694 *aRetValue = dwmHitResult;
4695 return PR_TRUE;
4697 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4699 switch (msg) {
4700 #ifndef WINCE
4701 // WM_QUERYENDSESSION must be handled by all windows.
4702 // Otherwise Windows thinks the window can just be killed at will.
4703 case WM_QUERYENDSESSION:
4704 if (sCanQuit == TRI_UNKNOWN)
4706 // Ask if it's ok to quit, and store the answer until we
4707 // get WM_ENDSESSION signaling the round is complete.
4708 nsCOMPtr<nsIObserverService> obsServ =
4709 mozilla::services::GetObserverService();
4710 nsCOMPtr<nsISupportsPRBool> cancelQuit =
4711 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
4712 cancelQuit->SetData(PR_FALSE);
4713 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
4715 PRBool abortQuit;
4716 cancelQuit->GetData(&abortQuit);
4717 sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
4719 *aRetValue = sCanQuit ? TRUE : FALSE;
4720 result = PR_TRUE;
4721 break;
4722 #endif
4724 #ifndef WINCE
4725 case WM_ENDSESSION:
4726 #endif
4727 case MOZ_WM_APP_QUIT:
4728 if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE))
4730 // Let's fake a shutdown sequence without actually closing windows etc.
4731 // to avoid Windows killing us in the middle. A proper shutdown would
4732 // require having a chance to pump some messages. Unfortunately
4733 // Windows won't let us do that. Bug 212316.
4734 nsCOMPtr<nsIObserverService> obsServ =
4735 mozilla::services::GetObserverService();
4736 NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
4737 obsServ->NotifyObservers(nsnull, "quit-application-granted", nsnull);
4738 obsServ->NotifyObservers(nsnull, "quit-application-forced", nsnull);
4739 obsServ->NotifyObservers(nsnull, "quit-application", nsnull);
4740 obsServ->NotifyObservers(nsnull, "profile-change-net-teardown", context.get());
4741 obsServ->NotifyObservers(nsnull, "profile-change-teardown", context.get());
4742 obsServ->NotifyObservers(nsnull, "profile-before-change", context.get());
4743 // Then a controlled but very quick exit.
4744 _exit(0);
4746 sCanQuit = TRI_UNKNOWN;
4747 result = PR_TRUE;
4748 break;
4750 #ifndef WINCE
4751 case WM_DISPLAYCHANGE:
4752 DispatchStandardEvent(NS_DISPLAYCHANGED);
4753 break;
4754 #endif
4756 case WM_SYSCOLORCHANGE:
4757 // Note: This is sent for child windows as well as top-level windows.
4758 // The Win32 toolkit normally only sends these events to top-level windows.
4759 // But we cycle through all of the childwindows and send it to them as well
4760 // so all presentations get notified properly.
4761 // See nsWindow::GlobalMsgWindowProc.
4762 DispatchStandardEvent(NS_SYSCOLORCHANGED);
4763 break;
4765 case WM_NOTIFY:
4766 // TAB change
4768 LPNMHDR pnmh = (LPNMHDR) lParam;
4770 switch (pnmh->code) {
4771 case TCN_SELCHANGE:
4773 DispatchStandardEvent(NS_TABCHANGE);
4774 result = PR_TRUE;
4776 break;
4779 break;
4781 case WM_THEMECHANGED:
4783 // Update non-client margin offsets
4784 UpdateNonClientMargins();
4785 nsUXThemeData::InitTitlebarInfo();
4786 nsUXThemeData::UpdateNativeThemeInfo();
4788 DispatchStandardEvent(NS_THEMECHANGED);
4790 // Invalidate the window so that the repaint will
4791 // pick up the new theme.
4792 Invalidate(PR_FALSE);
4794 break;
4796 case WM_FONTCHANGE:
4798 nsresult rv;
4799 PRBool didChange = PR_FALSE;
4801 // update the global font list
4802 nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
4803 if (NS_SUCCEEDED(rv)) {
4804 fontEnum->UpdateFontList(&didChange);
4805 //didChange is TRUE only if new font langGroup is added to the list.
4806 if (didChange) {
4807 // update device context font cache
4808 // Dirty but easiest way:
4809 // Changing nsIPrefBranch entry which triggers callbacks
4810 // and flows into calling mDeviceContext->FlushFontCache()
4811 // to update the font cache in all the instance of Browsers
4812 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
4813 if (prefs) {
4814 nsCOMPtr<nsIPrefBranch> fiPrefs;
4815 prefs->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs));
4816 if (fiPrefs) {
4817 PRBool fontInternalChange = PR_FALSE;
4818 fiPrefs->GetBoolPref("changed", &fontInternalChange);
4819 fiPrefs->SetBoolPref("changed", !fontInternalChange);
4823 } //if (NS_SUCCEEDED(rv))
4825 break;
4827 case WM_NCCALCSIZE:
4829 // If wParam is TRUE, it specifies that the application should indicate
4830 // which part of the client area contains valid information. The system
4831 // copies the valid information to the specified area within the new
4832 // client area. If the wParam parameter is FALSE, the application should
4833 // return zero.
4834 if (mCustomNonClient) {
4835 if (!wParam) {
4836 result = PR_TRUE;
4837 *aRetValue = 0;
4838 break;
4841 // before:
4842 // rgrc[0]: the proposed window
4843 // rgrc[1]: the current window
4844 // rgrc[2]: the source client area
4845 // pncsp->lppos: move/size data
4846 // after:
4847 // rgrc[0]: the new client area
4848 // rgrc[1]: the destination window
4849 // rgrc[2]: the source client area
4850 // (all values in screen coordiantes)
4851 NCCALCSIZE_PARAMS *pncsp = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
4852 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd, msg, wParam, lParam);
4853 pncsp->rgrc[0].top -= mNonClientOffset.top;
4854 pncsp->rgrc[0].left -= mNonClientOffset.left;
4855 pncsp->rgrc[0].right += mNonClientOffset.right;
4856 pncsp->rgrc[0].bottom += mNonClientOffset.bottom;
4858 result = PR_TRUE;
4859 *aRetValue = res;
4861 break;
4864 case WM_NCHITTEST:
4867 * If an nc client area margin has been moved, we are responsible
4868 * for calculating where the resize margins are and returning the
4869 * appropriate set of hit test constants. DwmDefWindowProc (above)
4870 * will handle hit testing on it's command buttons if we are on a
4871 * composited desktop.
4874 if (!mCustomNonClient)
4875 break;
4877 *aRetValue =
4878 ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
4879 result = PR_TRUE;
4880 break;
4883 case WM_SETTEXT:
4885 * WM_SETTEXT paints the titlebar area. Avoid this if we have a
4886 * custom titlebar we paint ourselves.
4889 if (!mCustomNonClient || mNonClientMargins.top == -1)
4890 break;
4893 // From msdn, the way around this is to disable the visible state
4894 // temporarily. We need the text to be set but we don't want the
4895 // redraw to occur.
4896 DWORD style = GetWindowLong(mWnd, GWL_STYLE);
4897 SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
4898 *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd,
4899 msg, wParam, lParam);
4900 SetWindowLong(mWnd, GWL_STYLE, style);
4901 return PR_TRUE;
4904 case WM_NCACTIVATE:
4907 * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
4908 * through WM_NCPAINT via InvalidateNonClientRegion.
4911 if (!mCustomNonClient)
4912 break;
4914 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4915 // let the dwm handle nc painting on glass
4916 if(nsUXThemeData::CheckForCompositor())
4917 break;
4918 #endif
4920 if (wParam == TRUE) {
4921 // going active
4922 *aRetValue = FALSE; // ignored
4923 result = PR_TRUE;
4924 UpdateGetWindowInfoCaptionStatus(PR_TRUE);
4925 // invalidate to trigger a paint
4926 InvalidateNonClientRegion();
4927 break;
4928 } else {
4929 // going inactive
4930 *aRetValue = TRUE; // go ahead and deactive
4931 result = PR_TRUE;
4932 UpdateGetWindowInfoCaptionStatus(PR_FALSE);
4933 // invalidate to trigger a paint
4934 InvalidateNonClientRegion();
4935 break;
4939 case WM_NCPAINT:
4942 * Reset the non-client paint region so that it excludes the
4943 * non-client areas we paint manually. Then call defwndproc
4944 * to do the actual painting.
4947 if (!mCustomNonClient)
4948 break;
4950 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4951 // let the dwm handle nc painting on glass
4952 if(nsUXThemeData::CheckForCompositor())
4953 break;
4954 #endif
4956 HRGN paintRgn = ExcludeNonClientFromPaintRegion((HRGN)wParam);
4957 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd,
4958 msg, (WPARAM)paintRgn, lParam);
4959 if (paintRgn != (HRGN)wParam)
4960 DeleteObject(paintRgn);
4961 *aRetValue = res;
4962 result = PR_TRUE;
4964 break;
4966 #ifndef WINCE
4967 case WM_POWERBROADCAST:
4968 // only hidden window handle this
4969 // to prevent duplicate notification
4970 if (mWindowType == eWindowType_invisible) {
4971 switch (wParam)
4973 case PBT_APMSUSPEND:
4974 PostSleepWakeNotification("sleep_notification");
4975 break;
4976 case PBT_APMRESUMEAUTOMATIC:
4977 case PBT_APMRESUMECRITICAL:
4978 case PBT_APMRESUMESUSPEND:
4979 PostSleepWakeNotification("wake_notification");
4980 break;
4983 break;
4984 #endif
4986 case WM_MOVE: // Window moved
4988 RECT rect;
4989 ::GetWindowRect(mWnd, &rect);
4990 result = OnMove(rect.left, rect.top);
4992 break;
4994 case WM_CLOSE: // close request
4995 DispatchStandardEvent(NS_XUL_CLOSE);
4996 result = PR_TRUE; // abort window closure
4997 break;
4999 case WM_DESTROY:
5000 // clean up.
5001 OnDestroy();
5002 result = PR_TRUE;
5003 break;
5005 case WM_PAINT:
5006 *aRetValue = (int) OnPaint(NULL, 0);
5007 result = PR_TRUE;
5008 break;
5010 #ifndef WINCE
5011 case WM_PRINTCLIENT:
5012 result = OnPaint((HDC) wParam, 0);
5013 break;
5014 #endif
5016 case WM_HOTKEY:
5017 result = OnHotKey(wParam, lParam);
5018 break;
5020 case WM_SYSCHAR:
5021 case WM_CHAR:
5023 MSG nativeMsg = InitMSG(msg, wParam, lParam);
5024 result = ProcessCharMessage(nativeMsg, nsnull);
5025 DispatchPendingEvents();
5027 break;
5029 case WM_SYSKEYUP:
5030 case WM_KEYUP:
5032 MSG nativeMsg = InitMSG(msg, wParam, lParam);
5033 result = ProcessKeyUpMessage(nativeMsg, nsnull);
5034 DispatchPendingEvents();
5036 break;
5038 case WM_SYSKEYDOWN:
5039 case WM_KEYDOWN:
5041 MSG nativeMsg = InitMSG(msg, wParam, lParam);
5042 result = ProcessKeyDownMessage(nativeMsg, nsnull);
5043 DispatchPendingEvents();
5045 break;
5047 // say we've dealt with erase background if widget does
5048 // not need auto-erasing
5049 case WM_ERASEBKGND:
5050 if (!AutoErase((HDC)wParam)) {
5051 *aRetValue = 1;
5052 result = PR_TRUE;
5054 break;
5056 case WM_MOUSEMOVE:
5058 #ifdef WINCE_WINDOWS_MOBILE
5059 // Reset the kill timer so that we can continue at this
5060 // priority
5061 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2seconds */, NULL);
5062 #endif
5063 mMousePresent = PR_TRUE;
5065 // Suppress dispatch of pending events
5066 // when mouse moves are generated by widget
5067 // creation instead of user input.
5068 LPARAM lParamScreen = lParamToScreen(lParam);
5069 POINT mp;
5070 mp.x = GET_X_LPARAM(lParamScreen);
5071 mp.y = GET_Y_LPARAM(lParamScreen);
5072 PRBool userMovedMouse = PR_FALSE;
5073 if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) {
5074 userMovedMouse = PR_TRUE;
5077 result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam,
5078 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5079 if (userMovedMouse) {
5080 DispatchPendingEvents();
5083 break;
5085 case WM_NCMOUSEMOVE:
5086 // If we receive a mouse move event on non-client chrome, make sure and
5087 // send an NS_MOUSE_EXIT event as well.
5088 if (mMousePresent && !sIsInMouseCapture)
5089 SendMessage(mWnd, WM_MOUSELEAVE, 0, 0);
5090 break;
5092 #ifdef WINCE_WINDOWS_MOBILE
5093 case WM_TIMER:
5094 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
5095 KillTimer(mWnd, KILL_PRIORITY_ID);
5096 break;
5097 #endif
5099 case WM_LBUTTONDOWN:
5101 #ifdef WINCE_WINDOWS_MOBILE
5102 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
5103 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2 seconds */, NULL);
5104 #endif
5105 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
5106 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5107 DispatchPendingEvents();
5109 break;
5111 case WM_LBUTTONUP:
5113 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam,
5114 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5115 DispatchPendingEvents();
5117 #ifdef WINCE_WINDOWS_MOBILE
5118 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
5119 KillTimer(mWnd, KILL_PRIORITY_ID);
5120 #endif
5122 break;
5124 #ifndef WINCE
5125 case WM_MOUSELEAVE:
5127 if (!mMousePresent)
5128 break;
5129 mMousePresent = PR_FALSE;
5131 // We need to check mouse button states and put them in for
5132 // wParam.
5133 WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
5134 | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
5135 | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
5136 // Synthesize an event position because we don't get one from
5137 // WM_MOUSELEAVE.
5138 LPARAM pos = lParamToClient(::GetMessagePos());
5139 DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, PR_FALSE,
5140 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5142 break;
5143 #endif
5145 case WM_CONTEXTMENU:
5147 // if the context menu is brought up from the keyboard, |lParam|
5148 // will be -1.
5149 LPARAM pos;
5150 PRBool contextMenukey = PR_FALSE;
5151 if (lParam == -1)
5153 contextMenukey = PR_TRUE;
5154 pos = lParamToClient(GetMessagePos());
5156 else
5158 pos = lParamToClient(lParam);
5161 result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey,
5162 contextMenukey ?
5163 nsMouseEvent::eLeftButton :
5164 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5165 if (lParam != -1 && !result && mCustomNonClient &&
5166 DispatchMouseEvent(NS_MOUSE_MOZHITTEST, wParam, pos,
5167 PR_FALSE, nsMouseEvent::eLeftButton,
5168 MOUSE_INPUT_SOURCE())) {
5169 // Blank area hit, throw up the system menu.
5170 DisplaySystemMenu(mWnd, mSizeMode, mIsRTL, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
5171 result = PR_TRUE;
5174 break;
5176 case WM_LBUTTONDBLCLK:
5177 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
5178 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5179 DispatchPendingEvents();
5180 break;
5182 case WM_MBUTTONDOWN:
5183 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
5184 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5185 DispatchPendingEvents();
5186 break;
5188 case WM_MBUTTONUP:
5189 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
5190 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5191 DispatchPendingEvents();
5192 break;
5194 case WM_MBUTTONDBLCLK:
5195 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
5196 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5197 DispatchPendingEvents();
5198 break;
5200 case WM_NCMBUTTONDOWN:
5201 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam), PR_FALSE,
5202 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5203 DispatchPendingEvents();
5204 break;
5206 case WM_NCMBUTTONUP:
5207 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam), PR_FALSE,
5208 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5209 DispatchPendingEvents();
5210 break;
5212 case WM_NCMBUTTONDBLCLK:
5213 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam), PR_FALSE,
5214 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
5215 DispatchPendingEvents();
5216 break;
5218 case WM_RBUTTONDOWN:
5219 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
5220 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5221 DispatchPendingEvents();
5222 break;
5224 case WM_RBUTTONUP:
5225 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
5226 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5227 DispatchPendingEvents();
5228 break;
5230 case WM_RBUTTONDBLCLK:
5231 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
5232 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
5233 DispatchPendingEvents();
5234 break;
5236 case WM_NCRBUTTONDOWN:
5237 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam),
5238 PR_FALSE, nsMouseEvent::eRightButton,
5239 MOUSE_INPUT_SOURCE());
5240 DispatchPendingEvents();
5241 break;
5243 case WM_NCRBUTTONUP:
5244 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam),
5245 PR_FALSE, nsMouseEvent::eRightButton,
5246 MOUSE_INPUT_SOURCE());
5247 DispatchPendingEvents();
5248 break;
5250 case WM_NCRBUTTONDBLCLK:
5251 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam),
5252 PR_FALSE, nsMouseEvent::eRightButton,
5253 MOUSE_INPUT_SOURCE());
5254 DispatchPendingEvents();
5255 break;
5257 case WM_APPCOMMAND:
5259 PRUint32 appCommand = GET_APPCOMMAND_LPARAM(lParam);
5261 switch (appCommand)
5263 case APPCOMMAND_BROWSER_BACKWARD:
5264 case APPCOMMAND_BROWSER_FORWARD:
5265 case APPCOMMAND_BROWSER_REFRESH:
5266 case APPCOMMAND_BROWSER_STOP:
5267 case APPCOMMAND_BROWSER_SEARCH:
5268 case APPCOMMAND_BROWSER_FAVORITES:
5269 case APPCOMMAND_BROWSER_HOME:
5270 DispatchCommandEvent(appCommand);
5271 // tell the driver that we handled the event
5272 *aRetValue = 1;
5273 result = PR_TRUE;
5274 break;
5276 // default = PR_FALSE - tell the driver that the event was not handled
5278 break;
5280 case WM_HSCROLL:
5281 case WM_VSCROLL:
5282 *aRetValue = 0;
5283 result = OnScroll(msg, wParam, lParam);
5284 break;
5286 // The WM_ACTIVATE event is fired when a window is raised or lowered,
5287 // and the loword of wParam specifies which. But we don't want to tell
5288 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
5289 // events are fired. Instead, set either the sJustGotActivate or
5290 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
5291 // events once the focus events arrive.
5292 case WM_ACTIVATE:
5293 if (mEventCallback) {
5294 PRInt32 fActive = LOWORD(wParam);
5296 #if defined(WINCE_HAVE_SOFTKB)
5297 if (mIsTopWidgetWindow && sSoftKeyboardState)
5298 nsWindowCE::ToggleSoftKB(mWnd, fActive);
5299 if (nsWindowCE::sShowSIPButton == TRI_FALSE && WA_INACTIVE != fActive) {
5300 HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL );
5301 if (hWndSIPB)
5302 ShowWindow(hWndSIPB, SW_HIDE);
5305 #endif
5307 if (WA_INACTIVE == fActive) {
5308 // when minimizing a window, the deactivation and focus events will
5309 // be fired in the reverse order. Instead, just dispatch
5310 // NS_DEACTIVATE right away.
5311 if (HIWORD(wParam))
5312 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5313 else
5314 sJustGotDeactivate = PR_TRUE;
5315 #ifndef WINCE
5316 if (mIsTopWidgetWindow)
5317 mLastKeyboardLayout = gKbdLayout.GetLayout();
5318 #endif
5320 } else {
5321 StopFlashing();
5323 sJustGotActivate = PR_TRUE;
5324 nsMouseEvent event(PR_TRUE, NS_MOUSE_ACTIVATE, this,
5325 nsMouseEvent::eReal);
5326 InitEvent(event);
5327 DispatchWindowEvent(&event);
5328 #ifndef WINCE
5329 if (sSwitchKeyboardLayout && mLastKeyboardLayout)
5330 ActivateKeyboardLayout(mLastKeyboardLayout, 0);
5331 #endif
5334 #ifdef WINCE_WINDOWS_MOBILE
5335 if (!gCheckForHTCApi && gHTCApiNavOpen == nsnull) {
5336 gCheckForHTCApi = PR_TRUE;
5338 HINSTANCE library = LoadLibrary(L"HTCAPI.dll");
5339 gHTCApiNavOpen = (HTCApiNavOpen) GetProcAddress(library, "HTCNavOpen");
5340 gHTCApiNavSetMode = (HTCApiNavSetMode) GetProcAddress(library ,"HTCNavSetMode");
5343 if (gHTCApiNavOpen != nsnull) {
5344 gHTCApiNavOpen(mWnd, 1 /* undocumented value */);
5346 if (gHTCApiNavSetMode != nsnull)
5347 gHTCApiNavSetMode ( mWnd, 4);
5348 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5350 #endif
5351 break;
5353 #ifndef WINCE
5354 case WM_MOUSEACTIVATE:
5355 if (mWindowType == eWindowType_popup) {
5356 // a popup with a parent owner should not be activated when clicked
5357 // but should still allow the mouse event to be fired, so the return
5358 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5359 // window, just use default processing so that the window is activated.
5360 HWND owner = ::GetWindow(mWnd, GW_OWNER);
5361 if (owner && owner == ::GetForegroundWindow()) {
5362 *aRetValue = MA_NOACTIVATE;
5363 result = PR_TRUE;
5366 break;
5368 case WM_WINDOWPOSCHANGING:
5370 LPWINDOWPOS info = (LPWINDOWPOS) lParam;
5371 OnWindowPosChanging(info);
5373 break;
5374 #endif
5376 case WM_SETFOCUS:
5377 // If previous focused window isn't ours, it must have received the
5378 // redirected message. So, we should forget it.
5379 if (!IsOurProcessWindow(HWND(wParam))) {
5380 ForgetRedirectedKeyDownMessage();
5382 if (sJustGotActivate) {
5383 result = DispatchFocusToTopLevelWindow(NS_ACTIVATE);
5386 #ifdef ACCESSIBILITY
5387 if (nsWindow::sIsAccessibilityOn) {
5388 // Create it for the first time so that it can start firing events
5389 nsAccessible *rootAccessible = GetRootAccessible();
5391 #endif
5393 #if defined(WINCE_HAVE_SOFTKB)
5395 // On Windows CE, we have a window that overlaps
5396 // the ISP button. In this case, we should always
5397 // try to hide it when we are activated
5399 nsIMEContext IMEContext(mWnd);
5400 // Open the IME
5401 ImmSetOpenStatus(IMEContext.get(), TRUE);
5403 #endif
5404 break;
5406 case WM_KILLFOCUS:
5407 #if defined(WINCE_HAVE_SOFTKB)
5409 nsIMEContext IMEContext(mWnd);
5410 ImmSetOpenStatus(IMEContext.get(), FALSE);
5412 #endif
5413 if (sJustGotDeactivate) {
5414 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5416 break;
5418 case WM_WINDOWPOSCHANGED:
5420 WINDOWPOS *wp = (LPWINDOWPOS)lParam;
5421 OnWindowPosChanged(wp, result);
5423 break;
5425 case WM_SETTINGCHANGE:
5426 #if !defined (WINCE_WINDOWS_MOBILE)
5427 getWheelInfo = PR_TRUE;
5428 #else
5429 switch (wParam) {
5430 case SPI_SETSIPINFO:
5431 case SPI_SETCURRENTIM:
5432 nsWindowCE::OnSoftKbSettingsChange(mWnd);
5433 break;
5434 case SETTINGCHANGE_RESET:
5435 if (mWindowType == eWindowType_invisible) {
5436 // The OS sees to get confused and think that the invisable window
5437 // is in the foreground after an orientation change. By actually
5438 // setting it to the foreground and hiding it, we set it strait.
5439 // See bug 514007 for details.
5440 SetForegroundWindow(mWnd);
5441 ShowWindow(mWnd, SW_HIDE);
5443 break;
5445 #endif
5446 OnSettingsChange(wParam, lParam);
5447 break;
5449 #ifndef WINCE
5450 case WM_INPUTLANGCHANGEREQUEST:
5451 *aRetValue = TRUE;
5452 result = PR_FALSE;
5453 break;
5455 case WM_INPUTLANGCHANGE:
5456 result = OnInputLangChange((HKL)lParam);
5457 break;
5458 #endif // WINCE
5460 case WM_DESTROYCLIPBOARD:
5462 nsIClipboard* clipboard;
5463 nsresult rv = CallGetService(kCClipboardCID, &clipboard);
5464 if(NS_SUCCEEDED(rv)) {
5465 clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
5466 NS_RELEASE(clipboard);
5469 break;
5471 #ifdef ACCESSIBILITY
5472 case WM_GETOBJECT:
5474 *aRetValue = 0;
5475 if (lParam == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
5476 nsAccessible *rootAccessible = GetRootAccessible(); // Held by a11y cache
5477 if (rootAccessible) {
5478 IAccessible *msaaAccessible = NULL;
5479 rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref
5480 if (msaaAccessible) {
5481 *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref
5482 msaaAccessible->Release(); // release extra addref
5483 result = PR_TRUE; // We handled the WM_GETOBJECT message
5488 #endif
5490 #ifndef WINCE
5491 case WM_SYSCOMMAND:
5493 WPARAM filteredWParam = (wParam &0xFFF0);
5494 // prevent Windows from trimming the working set. bug 76831
5495 if (!sTrimOnMinimize && filteredWParam == SC_MINIMIZE) {
5496 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
5497 result = PR_TRUE;
5500 // Handle the system menu manually when we're in full screen mode
5501 // so we can set the appropriate options.
5502 if (filteredWParam == SC_KEYMENU && lParam == VK_SPACE &&
5503 mSizeMode == nsSizeMode_Fullscreen) {
5504 DisplaySystemMenu(mWnd, mSizeMode, mIsRTL,
5505 MOZ_SYSCONTEXT_X_POS,
5506 MOZ_SYSCONTEXT_Y_POS);
5507 result = PR_TRUE;
5510 break;
5511 #endif
5514 #ifdef WINCE
5515 case WM_HIBERNATE:
5516 nsMemory::HeapMinimize(PR_TRUE);
5517 break;
5518 #endif
5520 case WM_MOUSEWHEEL:
5521 case WM_MOUSEHWHEEL:
5523 // If OnMouseWheel returns true, the event was forwarded directly to another
5524 // mozilla window message handler (ProcessMessage). In this case the return
5525 // value of the forwarded event is in 'result' which we should return immediately.
5526 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5527 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5528 // we should fall through.
5529 if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue))
5530 return result;
5532 break;
5534 #ifndef WINCE
5535 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5536 case WM_DWMCOMPOSITIONCHANGED:
5537 // First, update the compositor state to latest one. All other methods
5538 // should use same state as here for consistency painting.
5539 nsUXThemeData::CheckForCompositor(PR_TRUE);
5541 UpdateNonClientMargins();
5542 RemovePropW(mWnd, kManageWindowInfoProperty);
5543 BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
5544 DispatchStandardEvent(NS_THEMECHANGED);
5545 UpdateGlass();
5546 Invalidate(PR_FALSE);
5547 break;
5548 #endif
5550 case WM_UPDATEUISTATE:
5552 // If the UI state has changed, fire an event so the UI updates the
5553 // keyboard cues based on the system setting and how the window was
5554 // opened. For example, a dialog opened via a keyboard press on a button
5555 // should enable cues, whereas the same dialog opened via a mouse click of
5556 // the button should not.
5557 PRInt32 action = LOWORD(wParam);
5558 if (action == UIS_SET || action == UIS_CLEAR) {
5559 nsUIStateChangeEvent event(PR_TRUE, NS_UISTATECHANGED, this);
5560 PRInt32 flags = HIWORD(wParam);
5561 if (flags & UISF_HIDEACCEL)
5562 event.showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5563 if (flags & UISF_HIDEFOCUS)
5564 event.showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5565 DispatchWindowEvent(&event);
5568 break;
5571 /* Gesture support events */
5572 case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
5573 // According to MS samples, this must be handled to enable
5574 // rotational support in multi-touch drivers.
5575 result = PR_TRUE;
5576 *aRetValue = TABLET_ROTATE_GESTURE_ENABLE;
5577 break;
5579 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5580 case WM_TOUCH:
5581 result = OnTouch(wParam, lParam);
5582 if (result) {
5583 *aRetValue = 0;
5585 break;
5586 #endif
5588 case WM_GESTURE:
5589 result = OnGesture(wParam, lParam);
5590 break;
5592 case WM_GESTURENOTIFY:
5594 if (mWindowType != eWindowType_invisible &&
5595 mWindowType != eWindowType_plugin) {
5596 // A GestureNotify event is dispatched to decide which single-finger panning
5597 // direction should be active (including none) and if pan feedback should
5598 // be displayed. Java and plugin windows can make their own calls.
5599 GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
5600 nsPointWin touchPoint;
5601 touchPoint = gestureinfo->ptsLocation;
5602 touchPoint.ScreenToClient(mWnd);
5603 nsGestureNotifyEvent gestureNotifyEvent(PR_TRUE, NS_GESTURENOTIFY_EVENT_START, this);
5604 gestureNotifyEvent.refPoint = touchPoint;
5605 nsEventStatus status;
5606 DispatchEvent(&gestureNotifyEvent, status);
5607 mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
5608 if (!mTouchWindow)
5609 mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
5611 result = PR_FALSE; //should always bubble to DefWindowProc
5613 break;
5614 #endif // !defined(WINCE)
5616 case WM_CLEAR:
5618 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_DELETE, this);
5619 DispatchWindowEvent(&command);
5620 result = PR_TRUE;
5622 break;
5624 case WM_CUT:
5626 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_CUT, this);
5627 DispatchWindowEvent(&command);
5628 result = PR_TRUE;
5630 break;
5632 case WM_COPY:
5634 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_COPY, this);
5635 DispatchWindowEvent(&command);
5636 result = PR_TRUE;
5638 break;
5640 case WM_PASTE:
5642 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE, this);
5643 DispatchWindowEvent(&command);
5644 result = PR_TRUE;
5646 break;
5648 #ifndef WINCE
5649 case EM_UNDO:
5651 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO, this);
5652 DispatchWindowEvent(&command);
5653 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5654 result = PR_TRUE;
5656 break;
5658 case EM_REDO:
5660 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO, this);
5661 DispatchWindowEvent(&command);
5662 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5663 result = PR_TRUE;
5665 break;
5667 case EM_CANPASTE:
5669 // Support EM_CANPASTE message only when wParam isn't specified or
5670 // is plain text format.
5671 if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
5672 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE,
5673 this, PR_TRUE);
5674 DispatchWindowEvent(&command);
5675 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5676 result = PR_TRUE;
5679 break;
5681 case EM_CANUNDO:
5683 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO,
5684 this, PR_TRUE);
5685 DispatchWindowEvent(&command);
5686 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5687 result = PR_TRUE;
5689 break;
5691 case EM_CANREDO:
5693 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO,
5694 this, PR_TRUE);
5695 DispatchWindowEvent(&command);
5696 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5697 result = PR_TRUE;
5699 break;
5700 #endif
5702 #ifdef WINCE_WINDOWS_MOBILE
5703 //HTC NAVIGATION WHEEL EVENT
5704 case WM_HTCNAV:
5706 int distance = wParam & 0x000000FF;
5707 if ( (wParam & 0x000000100) != 0) // Counter Clockwise
5708 distance *= -1;
5709 if (OnMouseWheel(WM_MOUSEWHEEL, MAKEWPARAM(0, distance),
5710 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN) / 2,
5711 GetSystemMetrics(SM_CYSCREEN) / 2),
5712 getWheelInfo, result, aRetValue))
5713 return result;
5715 break;
5716 #endif
5718 default:
5720 #ifdef NS_ENABLE_TSF
5721 if (msg == WM_USER_TSF_TEXTCHANGE) {
5722 nsTextStore::OnTextChangeMsg();
5724 #endif //NS_ENABLE_TSF
5725 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5726 if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
5727 SetHasTaskbarIconBeenCreated();
5728 #endif
5729 #ifdef MOZ_IPC
5730 if (msg == sOOPPPluginFocusEvent) {
5731 if (wParam == 1) {
5732 // With OOPP, the plugin window exists in another process and is a child of
5733 // this window. This window is a placeholder plugin window for the dom. We
5734 // receive this event when the child window receives focus. (sent from
5735 // PluginInstanceParent.cpp)
5736 ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
5737 } else {
5738 // WM_KILLFOCUS was received by the child process.
5739 if (sJustGotDeactivate) {
5740 DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5744 #endif
5746 break;
5749 //*aRetValue = result;
5750 if (mWnd) {
5751 return result;
5753 else {
5754 //Events which caused mWnd destruction and aren't consumed
5755 //will crash during the Windows default processing.
5756 return PR_TRUE;
5760 /**************************************************************
5762 * SECTION: Broadcast messaging
5764 * Broadcast messages to all windows.
5766 **************************************************************/
5768 // Enumerate all child windows sending aMsg to each of them
5769 BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg)
5771 WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
5772 if (winProc == &nsWindow::WindowProc) {
5773 // it's one of our windows so go ahead and send a message to it
5774 ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0);
5776 return TRUE;
5779 // Enumerate all top level windows specifying that the children of each
5780 // top level window should be enumerated. Do *not* send the message to
5781 // each top level window since it is assumed that the toolkit will send
5782 // aMsg to them directly.
5783 BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg)
5785 // Iterate each of aTopWindows child windows sending the aMsg
5786 // to each of them.
5787 #if !defined(WINCE)
5788 ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5789 #else
5790 nsWindowCE::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5791 #endif
5792 return TRUE;
5795 // This method is called from nsToolkit::WindowProc to forward global
5796 // messages which need to be dispatched to all child windows.
5797 void nsWindow::GlobalMsgWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
5799 switch (msg) {
5800 case WM_SYSCOLORCHANGE:
5801 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5802 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5803 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5804 // all child windows as well. When running in an embedded application
5805 // we may not receive a WM_SYSCOLORCHANGE message because the top
5806 // level window is owned by the embeddor.
5807 // System color changes are posted to top-level windows only.
5808 // The NS_SYSCOLORCHANGE must be dispatched to all child
5809 // windows as well.
5810 #if !defined(WINCE)
5811 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, msg);
5812 #endif
5813 break;
5817 /**************************************************************
5819 * SECTION: Event processing helpers
5821 * Special processing for certain event types and
5822 * synthesized events.
5824 **************************************************************/
5826 PRInt32
5827 nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
5829 // Calculations are done in screen coords
5830 RECT winRect;
5831 GetWindowRect(mWnd, &winRect);
5833 // hit return constants:
5834 // HTBORDER - non-resizable border
5835 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5836 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5837 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5838 // HTCAPTION - general title bar area
5839 // HTCLIENT - area considered the client
5840 // HTCLOSE - hovering over the close button
5841 // HTMAXBUTTON - maximize button
5842 // HTMINBUTTON - minimize button
5844 PRInt32 testResult = HTCLIENT;
5846 PRBool top = PR_FALSE;
5847 PRBool bottom = PR_FALSE;
5848 PRBool left = PR_FALSE;
5849 PRBool right = PR_FALSE;
5851 if (my >= winRect.top && my <
5852 (winRect.top + mVertResizeMargin + (mCaptionHeight - mNonClientOffset.top)))
5853 top = PR_TRUE;
5854 else if (my < winRect.bottom && my >= (winRect.bottom - mVertResizeMargin))
5855 bottom = PR_TRUE;
5857 if (mx >= winRect.left && mx < (winRect.left +
5858 (bottom ? (2*mHorResizeMargin) : mHorResizeMargin)))
5859 left = PR_TRUE;
5860 else if (mx < winRect.right && mx >= (winRect.right -
5861 (bottom ? (2*mHorResizeMargin) : mHorResizeMargin)))
5862 right = PR_TRUE;
5864 if (top) {
5865 testResult = HTTOP;
5866 if (left)
5867 testResult = HTTOPLEFT;
5868 else if (right)
5869 testResult = HTTOPRIGHT;
5870 } else if (bottom) {
5871 testResult = HTBOTTOM;
5872 if (left)
5873 testResult = HTBOTTOMLEFT;
5874 else if (right)
5875 testResult = HTBOTTOMRIGHT;
5876 } else {
5877 if (left)
5878 testResult = HTLEFT;
5879 if (right)
5880 testResult = HTRIGHT;
5883 PRBool contentOverlap = PR_TRUE;
5885 if (mSizeMode == nsSizeMode_Maximized) {
5886 // There's no HTTOP in maximized state (bug 575493)
5887 if (testResult == HTTOP) {
5888 testResult = HTCAPTION;
5890 } else {
5891 PRInt32 leftMargin = mNonClientMargins.left == -1 ? mHorResizeMargin : mNonClientMargins.left;
5892 PRInt32 rightMargin = mNonClientMargins.right == -1 ? mHorResizeMargin : mNonClientMargins.right;
5893 PRInt32 topMargin = mNonClientMargins.top == -1 ? mVertResizeMargin : mNonClientMargins.top;
5894 PRInt32 bottomMargin = mNonClientMargins.bottom == -1 ? mVertResizeMargin : mNonClientMargins.bottom;
5896 contentOverlap = mx >= winRect.left + leftMargin &&
5897 mx <= winRect.right - rightMargin &&
5898 my >= winRect.top + topMargin &&
5899 my <= winRect.bottom - bottomMargin;
5902 if (!sIsInMouseCapture &&
5903 contentOverlap &&
5904 (testResult == HTCLIENT ||
5905 testResult == HTTOP ||
5906 testResult == HTTOPLEFT ||
5907 testResult == HTCAPTION)) {
5908 LPARAM lParam = MAKELPARAM(mx, my);
5909 LPARAM lParamClient = lParamToClient(lParam);
5910 PRBool result = DispatchMouseEvent(NS_MOUSE_MOZHITTEST, 0, lParamClient,
5911 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5912 if (result) {
5913 // The mouse is over a blank area
5914 testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
5916 } else {
5917 // There's content over the mouse pointer. Set HTCLIENT
5918 // to possibly override a resizer border.
5919 testResult = HTCLIENT;
5923 return testResult;
5926 #ifndef WINCE
5927 void nsWindow::PostSleepWakeNotification(const char* aNotification)
5929 nsCOMPtr<nsIObserverService> observerService =
5930 mozilla::services::GetObserverService();
5931 if (observerService)
5932 observerService->NotifyObservers(nsnull, aNotification, nsnull);
5934 #endif
5936 // RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
5937 // message handler. If there is no WM_(SYS)CHAR message for it, this
5938 // method does nothing.
5939 // NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
5940 // called in message loop. So, WM_(SYS)KEYDOWN message should have
5941 // WM_(SYS)CHAR message in the queue if the keydown event causes character
5942 // input.
5944 /* static */
5945 void nsWindow::RemoveNextCharMessage(HWND aWnd)
5947 MSG msg;
5948 if (::PeekMessageW(&msg, aWnd,
5949 WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD) &&
5950 (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) {
5951 ::GetMessageW(&msg, aWnd, msg.message, msg.message);
5955 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, PRBool *aEventDispatched)
5957 NS_PRECONDITION(aMsg.message == WM_CHAR || aMsg.message == WM_SYSCHAR,
5958 "message is not keydown event");
5959 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5960 ("%s charCode=%d scanCode=%d\n",
5961 aMsg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
5962 aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF));
5964 // These must be checked here too as a lone WM_CHAR could be received
5965 // if a child window didn't handle it (for example Alt+Space in a content window)
5966 nsModifierKeyState modKeyState;
5967 return OnChar(aMsg, modKeyState, aEventDispatched);
5970 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, PRBool *aEventDispatched)
5972 NS_PRECONDITION(aMsg.message == WM_KEYUP || aMsg.message == WM_SYSKEYUP,
5973 "message is not keydown event");
5974 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5975 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5976 "WM_SYSKEYUP" : "WM_KEYUP", aMsg.wParam));
5978 nsModifierKeyState modKeyState;
5980 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5981 // scan code. However, this breaks Alt+Num pad input.
5982 // MSDN states the following:
5983 // Typically, ToAscii performs the translation based on the
5984 // virtual-key code. In some cases, however, bit 15 of the
5985 // uScanCode parameter may be used to distinguish between a key
5986 // press and a key release. The scan code is used for
5987 // translating ALT+number key combinations.
5989 // ignore [shift+]alt+space so the OS can handle it
5990 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5991 IS_VK_DOWN(NS_VK_SPACE)) {
5992 return FALSE;
5995 if (!nsIMM32Handler::IsComposingOn(this) &&
5996 (aMsg.message != WM_KEYUP || aMsg.wParam != VK_MENU)) {
5997 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5998 // This helps avoid triggering the menu bar for ALT key accelerators used in
5999 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
6000 // to switch back to Mozilla in Windows 95 and Windows 98
6001 return OnKeyUp(aMsg, modKeyState, aEventDispatched);
6004 return 0;
6007 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
6008 PRBool *aEventDispatched)
6010 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6011 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
6012 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg.wParam));
6013 NS_PRECONDITION(aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN,
6014 "message is not keydown event");
6016 // If this method doesn't call OnKeyDown(), this method must clean up the
6017 // redirected message information itself. For more information, see above
6018 // comment of AutoForgetRedirectedKeyDownMessage struct definition in
6019 // nsWindow.h.
6020 AutoForgetRedirectedKeyDownMessage forgetRedirectedMessage(this, aMsg);
6022 nsModifierKeyState modKeyState;
6024 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
6025 // scan code. However, this breaks Alt+Num pad input.
6026 // MSDN states the following:
6027 // Typically, ToAscii performs the translation based on the
6028 // virtual-key code. In some cases, however, bit 15 of the
6029 // uScanCode parameter may be used to distinguish between a key
6030 // press and a key release. The scan code is used for
6031 // translating ALT+number key combinations.
6033 // ignore [shift+]alt+space so the OS can handle it
6034 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
6035 IS_VK_DOWN(NS_VK_SPACE))
6036 return FALSE;
6038 LRESULT result = 0;
6039 if (modKeyState.mIsAltDown && nsIMM32Handler::IsStatusChanged()) {
6040 nsIMM32Handler::NotifyEndStatusChange();
6041 } else if (!nsIMM32Handler::IsComposingOn(this)) {
6042 result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nsnull);
6043 // OnKeyDown cleaned up the redirected message information itself, so,
6044 // we should do nothing.
6045 forgetRedirectedMessage.mCancel = PR_TRUE;
6048 #ifndef WINCE
6049 if (aMsg.wParam == VK_MENU ||
6050 (aMsg.wParam == VK_F10 && !modKeyState.mIsShiftDown)) {
6051 // We need to let Windows handle this keypress,
6052 // by returning PR_FALSE, if there's a native menu
6053 // bar somewhere in our containing window hierarchy.
6054 // Otherwise we handle the keypress and don't pass
6055 // it on to Windows, by returning PR_TRUE.
6056 PRBool hasNativeMenu = PR_FALSE;
6057 HWND hWnd = mWnd;
6058 while (hWnd) {
6059 if (::GetMenu(hWnd)) {
6060 hasNativeMenu = PR_TRUE;
6061 break;
6063 hWnd = ::GetParent(hWnd);
6065 result = !hasNativeMenu;
6067 #endif
6069 return result;
6072 nsresult
6073 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
6074 PRInt32 aNativeKeyCode,
6075 PRUint32 aModifierFlags,
6076 const nsAString& aCharacters,
6077 const nsAString& aUnmodifiedCharacters)
6079 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
6080 nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
6081 HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
6082 if (loadedLayout == NULL)
6083 return NS_ERROR_NOT_AVAILABLE;
6085 // Setup clean key state and load desired layout
6086 BYTE originalKbdState[256];
6087 ::GetKeyboardState(originalKbdState);
6088 BYTE kbdState[256];
6089 memset(kbdState, 0, sizeof(kbdState));
6090 // This changes the state of the keyboard for the current thread only,
6091 // and we'll restore it soon, so this should be OK.
6092 ::SetKeyboardState(kbdState);
6093 HKL oldLayout = gKbdLayout.GetLayout();
6094 gKbdLayout.LoadLayout(loadedLayout);
6096 nsAutoTArray<KeyPair,10> keySequence;
6097 SetupKeyModifiersSequence(&keySequence, aModifierFlags);
6098 NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
6099 "Native VK key code out of range");
6100 keySequence.AppendElement(KeyPair(aNativeKeyCode, 0));
6102 // Simulate the pressing of each modifier key and then the real key
6103 for (PRUint32 i = 0; i < keySequence.Length(); ++i) {
6104 PRUint8 key = keySequence[i].mGeneral;
6105 PRUint8 keySpecific = keySequence[i].mSpecific;
6106 kbdState[key] = 0x81; // key is down and toggled on if appropriate
6107 if (keySpecific) {
6108 kbdState[keySpecific] = 0x81;
6110 ::SetKeyboardState(kbdState);
6111 nsModifierKeyState modKeyState;
6112 MSG msg = InitMSG(WM_KEYDOWN, key, 0);
6113 if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
6114 UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
6115 gKbdLayout.GetLayout());
6116 nsFakeCharMessage fakeMsg = { aCharacters.CharAt(0), scanCode };
6117 OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
6118 } else {
6119 OnKeyDown(msg, modKeyState, nsnull, nsnull);
6122 for (PRUint32 i = keySequence.Length(); i > 0; --i) {
6123 PRUint8 key = keySequence[i - 1].mGeneral;
6124 PRUint8 keySpecific = keySequence[i - 1].mSpecific;
6125 kbdState[key] = 0; // key is up and toggled off if appropriate
6126 if (keySpecific) {
6127 kbdState[keySpecific] = 0;
6129 ::SetKeyboardState(kbdState);
6130 nsModifierKeyState modKeyState;
6131 MSG msg = InitMSG(WM_KEYUP, key, 0);
6132 OnKeyUp(msg, modKeyState, nsnull);
6135 // Restore old key state and layout
6136 ::SetKeyboardState(originalKbdState);
6137 gKbdLayout.LoadLayout(oldLayout);
6139 UnloadKeyboardLayout(loadedLayout);
6140 return NS_OK;
6141 #else //XXX: is there another way to do this?
6142 return NS_ERROR_NOT_IMPLEMENTED;
6143 #endif
6146 nsresult
6147 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
6148 PRUint32 aNativeMessage,
6149 PRUint32 aModifierFlags)
6151 #ifndef WINCE // I don't think WINCE supports SendInput
6152 RECT r;
6153 ::GetWindowRect(mWnd, &r);
6154 ::SetCursorPos(r.left + aPoint.x, r.top + aPoint.y);
6156 INPUT input;
6157 memset(&input, 0, sizeof(input));
6159 input.type = INPUT_MOUSE;
6160 input.mi.dwFlags = aNativeMessage;
6161 ::SendInput(1, &input, sizeof(INPUT));
6163 return NS_OK;
6164 #else
6165 return NS_ERROR_NOT_IMPLEMENTED;
6166 #endif
6169 /**************************************************************
6171 * SECTION: OnXXX message handlers
6173 * For message handlers that need to be broken out or
6174 * implemented in specific platform code.
6176 **************************************************************/
6178 BOOL nsWindow::OnInputLangChange(HKL aHKL)
6180 #ifdef KE_DEBUG
6181 printf("OnInputLanguageChange\n");
6182 #endif
6184 #ifndef WINCE
6185 gKbdLayout.LoadLayout(aHKL);
6186 #endif
6188 return PR_FALSE; // always pass to child window
6191 #if !defined(WINCE) // implemented in nsWindowCE.cpp
6192 void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, PRBool& result)
6194 if (wp == nsnull)
6195 return;
6197 #ifdef WINSTATE_DEBUG_OUTPUT
6198 if (mWnd == GetTopLevelHWND(mWnd))
6199 printf("*** OnWindowPosChanged: [ top] ");
6200 else
6201 printf("*** OnWindowPosChanged: [child] ");
6202 printf("WINDOWPOS flags:");
6203 if (wp->flags & SWP_FRAMECHANGED)
6204 printf("SWP_FRAMECHANGED ");
6205 if (wp->flags & SWP_SHOWWINDOW)
6206 printf("SWP_SHOWWINDOW ");
6207 if (wp->flags & SWP_NOSIZE)
6208 printf("SWP_NOSIZE ");
6209 if (wp->flags & SWP_HIDEWINDOW)
6210 printf("SWP_HIDEWINDOW ");
6211 if (wp->flags & SWP_NOZORDER)
6212 printf("SWP_NOZORDER ");
6213 if (wp->flags & SWP_NOACTIVATE)
6214 printf("SWP_NOACTIVATE ");
6215 printf("\n");
6216 #endif
6218 // Handle window size mode changes
6219 if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
6221 // Bug 566135 - Windows theme code calls show window on SW_SHOWMINIMIZED
6222 // windows when fullscreen games disable desktop composition. If we're
6223 // minimized and not being activated, ignore the event and let windows
6224 // handle it.
6225 if (mSizeMode == nsSizeMode_Minimized && (wp->flags & SWP_NOACTIVATE))
6226 return;
6228 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
6230 WINDOWPLACEMENT pl;
6231 pl.length = sizeof(pl);
6232 ::GetWindowPlacement(mWnd, &pl);
6234 if (pl.showCmd == SW_SHOWMAXIMIZED)
6235 event.mSizeMode = (mFullscreenMode ? nsSizeMode_Fullscreen : nsSizeMode_Maximized);
6236 else if (pl.showCmd == SW_SHOWMINIMIZED)
6237 event.mSizeMode = nsSizeMode_Minimized;
6238 else
6239 event.mSizeMode = nsSizeMode_Normal;
6241 // Windows has just changed the size mode of this window. The following
6242 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
6243 // set the min/max window state again or for nsSizeMode_Normal, call
6244 // SetWindow with a parameter of SW_RESTORE. There's no need however as
6245 // this window's mode has already changed. Updating mSizeMode here
6246 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
6247 // to window docking. (bug 489258)
6248 mSizeMode = event.mSizeMode;
6250 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
6251 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
6252 // prevents the working set from being trimmed but keeps the window active.
6253 // After the window is minimized, we need to do some touch up work on the
6254 // active window. (bugs 76831 & 499816)
6255 if (!sTrimOnMinimize && nsSizeMode_Minimized == event.mSizeMode)
6256 ActivateOtherWindowHelper(mWnd);
6258 #ifdef WINSTATE_DEBUG_OUTPUT
6259 switch (mSizeMode) {
6260 case nsSizeMode_Normal:
6261 printf("*** mSizeMode: nsSizeMode_Normal\n");
6262 break;
6263 case nsSizeMode_Minimized:
6264 printf("*** mSizeMode: nsSizeMode_Minimized\n");
6265 break;
6266 case nsSizeMode_Maximized:
6267 printf("*** mSizeMode: nsSizeMode_Maximized\n");
6268 break;
6269 default:
6270 printf("*** mSizeMode: ??????\n");
6271 break;
6273 #endif
6275 InitEvent(event);
6277 result = DispatchWindowEvent(&event);
6279 // Skip window size change events below on minimization.
6280 if (mSizeMode == nsSizeMode_Minimized)
6281 return;
6284 // Handle window size changes
6285 if (!(wp->flags & SWP_NOSIZE)) {
6286 RECT r;
6287 PRInt32 newWidth, newHeight;
6289 ::GetWindowRect(mWnd, &r);
6291 newWidth = r.right - r.left;
6292 newHeight = r.bottom - r.top;
6293 nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
6295 #ifdef MOZ_XUL
6296 if (eTransparencyTransparent == mTransparencyMode)
6297 ResizeTranslucentWindow(newWidth, newHeight);
6298 #endif
6300 if (newWidth > mLastSize.width)
6302 RECT drect;
6304 // getting wider
6305 drect.left = wp->x + mLastSize.width;
6306 drect.top = wp->y;
6307 drect.right = drect.left + (newWidth - mLastSize.width);
6308 drect.bottom = drect.top + newHeight;
6310 ::RedrawWindow(mWnd, &drect, NULL,
6311 RDW_INVALIDATE |
6312 RDW_NOERASE |
6313 RDW_NOINTERNALPAINT |
6314 RDW_ERASENOW |
6315 RDW_ALLCHILDREN);
6317 if (newHeight > mLastSize.height)
6319 RECT drect;
6321 // getting taller
6322 drect.left = wp->x;
6323 drect.top = wp->y + mLastSize.height;
6324 drect.right = drect.left + newWidth;
6325 drect.bottom = drect.top + (newHeight - mLastSize.height);
6327 ::RedrawWindow(mWnd, &drect, NULL,
6328 RDW_INVALIDATE |
6329 RDW_NOERASE |
6330 RDW_NOINTERNALPAINT |
6331 RDW_ERASENOW |
6332 RDW_ALLCHILDREN);
6335 mBounds.width = newWidth;
6336 mBounds.height = newHeight;
6337 mLastSize.width = newWidth;
6338 mLastSize.height = newHeight;
6340 #ifdef WINSTATE_DEBUG_OUTPUT
6341 printf("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, newWidth, newHeight);
6342 #endif
6344 // If a maximized window is resized, recalculate the non-client margins and
6345 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
6346 // work properly.
6347 if (mSizeMode == nsSizeMode_Maximized) {
6348 if (UpdateNonClientMargins(nsSizeMode_Maximized, PR_TRUE)) {
6349 // gecko resize event already sent by UpdateNonClientMargins.
6350 result = PR_TRUE;
6351 return;
6355 // Recalculate the width and height based on the client area for gecko events.
6356 if (::GetClientRect(mWnd, &r)) {
6357 rect.width = r.right - r.left;
6358 rect.height = r.bottom - r.top;
6361 // Send a gecko resize event
6362 result = OnResize(rect);
6366 // static
6367 void nsWindow::ActivateOtherWindowHelper(HWND aWnd)
6369 // Find the next window that is enabled, visible, and not minimized.
6370 HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT);
6371 while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) ||
6372 ::IsIconic(hwndBelow))) {
6373 hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT);
6376 // Push ourselves to the bottom of the stack, then activate the
6377 // next window.
6378 ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0,
6379 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
6380 if (hwndBelow)
6381 ::SetForegroundWindow(hwndBelow);
6383 // Play the minimize sound while we're here, since that is also
6384 // forgotten when we use SW_SHOWMINIMIZED.
6385 ::PlaySoundW(L"Minimize", nsnull, SND_ALIAS | SND_NODEFAULT | SND_ASYNC);
6387 #endif // !defined(WINCE)
6389 #if !defined(WINCE)
6390 void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info)
6392 // Update non-client margins if the frame size is changing, and let the
6393 // browser know we are changing size modes, so alternative css can kick in.
6394 // If we're going into fullscreen mode, ignore this, since it'll reset
6395 // margins to normal mode.
6396 if ((info->flags & SWP_FRAMECHANGED && !(info->flags & SWP_NOSIZE)) &&
6397 mSizeMode != nsSizeMode_Fullscreen) {
6398 WINDOWPLACEMENT pl;
6399 pl.length = sizeof(pl);
6400 ::GetWindowPlacement(mWnd, &pl);
6401 PRInt32 sizeMode;
6402 if (pl.showCmd == SW_SHOWMAXIMIZED)
6403 sizeMode = (mFullscreenMode ? nsSizeMode_Fullscreen : nsSizeMode_Maximized);
6404 else if (pl.showCmd == SW_SHOWMINIMIZED)
6405 sizeMode = nsSizeMode_Minimized;
6406 else
6407 sizeMode = nsSizeMode_Normal;
6409 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
6411 InitEvent(event);
6412 event.mSizeMode = static_cast<nsSizeMode>(sizeMode);
6413 DispatchWindowEvent(&event);
6415 UpdateNonClientMargins(sizeMode, PR_FALSE);
6418 // enforce local z-order rules
6419 if (!(info->flags & SWP_NOZORDER)) {
6420 HWND hwndAfter = info->hwndInsertAfter;
6422 nsZLevelEvent event(PR_TRUE, NS_SETZLEVEL, this);
6423 nsWindow *aboveWindow = 0;
6425 InitEvent(event);
6427 if (hwndAfter == HWND_BOTTOM)
6428 event.mPlacement = nsWindowZBottom;
6429 else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
6430 event.mPlacement = nsWindowZTop;
6431 else {
6432 event.mPlacement = nsWindowZRelative;
6433 aboveWindow = GetNSWindowPtr(hwndAfter);
6435 event.mReqBelow = aboveWindow;
6436 event.mActualBelow = nsnull;
6438 event.mImmediate = PR_FALSE;
6439 event.mAdjusted = PR_FALSE;
6440 DispatchWindowEvent(&event);
6442 if (event.mAdjusted) {
6443 if (event.mPlacement == nsWindowZBottom)
6444 info->hwndInsertAfter = HWND_BOTTOM;
6445 else if (event.mPlacement == nsWindowZTop)
6446 info->hwndInsertAfter = HWND_TOP;
6447 else {
6448 info->hwndInsertAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
6451 NS_IF_RELEASE(event.mActualBelow);
6453 // prevent rude external programs from making hidden window visible
6454 if (mWindowType == eWindowType_invisible)
6455 info->flags &= ~SWP_SHOWWINDOW;
6457 #endif
6459 void nsWindow::UserActivity()
6461 // Check if we have the idle service, if not we try to get it.
6462 if (!mIdleService) {
6463 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
6466 // Check that we now have the idle service.
6467 if (mIdleService) {
6468 mIdleService->ResetIdleTimeOut();
6472 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6473 PRBool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam)
6475 PRUint32 cInputs = LOWORD(wParam);
6476 PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
6478 if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) {
6479 for (PRUint32 i = 0; i < cInputs; i++) {
6480 PRUint32 msg;
6481 if (pInputs[i].dwFlags & TOUCHEVENTF_MOVE) {
6482 msg = NS_MOZTOUCH_MOVE;
6483 } else if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) {
6484 msg = NS_MOZTOUCH_DOWN;
6485 } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) {
6486 msg = NS_MOZTOUCH_UP;
6487 } else {
6488 continue;
6491 nsPointWin touchPoint;
6492 touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
6493 touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
6494 touchPoint.ScreenToClient(mWnd);
6496 nsMozTouchEvent touchEvent(PR_TRUE, msg, this, pInputs[i].dwID);
6497 touchEvent.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6498 touchEvent.refPoint = touchPoint;
6500 nsEventStatus status;
6501 DispatchEvent(&touchEvent, status);
6505 delete [] pInputs;
6506 mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam);
6507 return PR_TRUE;
6509 #endif
6511 // Gesture event processing. Handles WM_GESTURE events.
6512 #if !defined(WINCE)
6513 PRBool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
6515 // Treatment for pan events which translate into scroll events:
6516 if (mGesture.IsPanEvent(lParam)) {
6517 nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
6519 if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
6520 return PR_FALSE; // ignore
6522 nsEventStatus status;
6524 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6525 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6526 event.isMeta = PR_FALSE;
6527 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6528 event.button = 0;
6529 event.time = ::GetMessageTime();
6530 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6532 PRBool endFeedback = PR_TRUE;
6534 PRInt32 scrollOverflowX = 0;
6535 PRInt32 scrollOverflowY = 0;
6537 if (mGesture.PanDeltaToPixelScrollX(event)) {
6538 DispatchEvent(&event, status);
6539 scrollOverflowX = event.scrollOverflow;
6542 if (mGesture.PanDeltaToPixelScrollY(event)) {
6543 DispatchEvent(&event, status);
6544 scrollOverflowY = event.scrollOverflow;
6547 if (mDisplayPanFeedback) {
6548 mGesture.UpdatePanFeedbackX(mWnd, scrollOverflowX, endFeedback);
6549 mGesture.UpdatePanFeedbackY(mWnd, scrollOverflowY, endFeedback);
6550 mGesture.PanFeedbackFinalize(mWnd, endFeedback);
6553 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6555 return PR_TRUE;
6558 // Other gestures translate into simple gesture events:
6559 nsSimpleGestureEvent event(PR_TRUE, 0, this, 0, 0.0);
6560 if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) {
6561 return PR_FALSE; // fall through to DefWndProc
6564 // Polish up and send off the new event
6565 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6566 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6567 event.isMeta = PR_FALSE;
6568 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6569 event.button = 0;
6570 event.time = ::GetMessageTime();
6571 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6573 nsEventStatus status;
6574 DispatchEvent(&event, status);
6575 if (status == nsEventStatus_eIgnore) {
6576 return PR_FALSE; // Ignored, fall through
6579 // Only close this if we process and return true.
6580 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6582 return PR_TRUE; // Handled
6584 #endif // !defined(WINCE)
6586 #if !defined(WINCE)
6587 PRUint16 nsWindow::GetMouseInputSource()
6589 PRUint16 inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE;
6590 LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
6591 if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
6592 inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ?
6593 PRUint16(nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH) : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN;
6595 return inputSource;
6597 #endif
6599 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6600 * within the message case block. If returning true result should be returned
6601 * immediately (no more processing).
6603 PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue)
6605 // Handle both flavors of mouse wheel events.
6606 static int iDeltaPerLine, iDeltaPerChar;
6607 static ULONG ulScrollLines, ulScrollChars = 1;
6608 static int currentVDelta, currentHDelta;
6609 static HWND currentWindow = 0;
6611 PRBool isVertical = msg == WM_MOUSEWHEEL;
6613 // Get mouse wheel metrics (but only once).
6614 if (getWheelInfo) {
6615 getWheelInfo = PR_FALSE;
6617 SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
6619 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6620 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6622 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6623 // the mouse driver wants a page scroll. The docs state that
6624 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6625 // since some mouse drivers use an arbitrary large number instead,
6626 // we have to handle that as well.
6628 iDeltaPerLine = 0;
6629 if (ulScrollLines) {
6630 if (ulScrollLines <= WHEEL_DELTA) {
6631 iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
6632 } else {
6633 ulScrollLines = WHEEL_PAGESCROLL;
6637 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
6638 &ulScrollChars, 0)) {
6639 // Note that we may always fail to get the value before Win Vista.
6640 ulScrollChars = 1;
6643 iDeltaPerChar = 0;
6644 if (ulScrollChars) {
6645 if (ulScrollChars <= WHEEL_DELTA) {
6646 iDeltaPerChar = WHEEL_DELTA / ulScrollChars;
6647 } else {
6648 ulScrollChars = WHEEL_PAGESCROLL;
6653 if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) ||
6654 (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar))
6655 return PR_FALSE; // break
6657 // The mousewheel event will be dispatched to the toplevel
6658 // window. We need to give it to the child window
6659 PRBool quit;
6660 if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit))
6661 return quit; // return immediately if its not our window
6663 // We should cancel the surplus delta if the current window is not
6664 // same as previous.
6665 if (currentWindow != mWnd) {
6666 currentVDelta = 0;
6667 currentHDelta = 0;
6668 currentWindow = mWnd;
6671 nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
6672 scrollEvent.delta = 0;
6673 if (isVertical) {
6674 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
6675 if (ulScrollLines == WHEEL_PAGESCROLL) {
6676 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6677 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1;
6678 } else {
6679 currentVDelta -= (short) HIWORD (wParam);
6680 if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
6681 scrollEvent.delta = currentVDelta / iDeltaPerLine;
6682 currentVDelta %= iDeltaPerLine;
6685 } else {
6686 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
6687 if (ulScrollChars == WHEEL_PAGESCROLL) {
6688 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6689 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1;
6690 } else {
6691 currentHDelta += (short) HIWORD (wParam);
6692 if (PR_ABS(currentHDelta) >= iDeltaPerChar) {
6693 scrollEvent.delta = currentHDelta / iDeltaPerChar;
6694 currentHDelta %= iDeltaPerChar;
6699 if (!scrollEvent.delta) {
6700 // We store the wheel delta, and it will be used next wheel message, so,
6701 // we consume this message actually. We shouldn't call next wndproc.
6702 result = PR_TRUE;
6703 return PR_FALSE; // break
6706 #ifdef MOZ_IPC
6707 // The event may go to a plug-in which already dispatched this message.
6708 // Then, the event can cause deadlock. We should unlock the sender here.
6709 ::ReplyMessage(isVertical ? 0 : TRUE);
6710 #endif
6712 scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6713 scrollEvent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6714 scrollEvent.isMeta = PR_FALSE;
6715 scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT);
6716 InitEvent(scrollEvent);
6717 if (nsnull != mEventCallback) {
6718 result = DispatchWindowEvent(&scrollEvent);
6720 // Note that we should return zero if we process WM_MOUSEWHEEL.
6721 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6723 if (result)
6724 *aRetValue = isVertical ? 0 : TRUE;
6726 return PR_FALSE; // break;
6729 static PRBool
6730 StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,
6731 const PRUnichar* aChars2, const PRUint32 aNumChars2)
6733 if (aNumChars1 != aNumChars2)
6734 return PR_FALSE;
6736 nsCaseInsensitiveStringComparator comp;
6737 return comp(aChars1, aChars2, aNumChars1, aNumChars2) == 0;
6740 UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
6742 #ifndef WINCE
6743 switch (aNativeKeyCode) {
6744 case VK_OEM_1: return NS_VK_SEMICOLON; // 0xBA, For the US standard keyboard, the ';:' key
6745 case VK_OEM_PLUS: return NS_VK_ADD; // 0xBB, For any country/region, the '+' key
6746 case VK_OEM_MINUS: return NS_VK_SUBTRACT; // 0xBD, For any country/region, the '-' key
6748 #endif
6750 return aNativeKeyCode;
6753 /* static */
6754 PRBool nsWindow::IsRedirectedKeyDownMessage(const MSG &aMsg)
6756 return (aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN) &&
6757 (sRedirectedKeyDown.message == aMsg.message &&
6758 GetScanCode(sRedirectedKeyDown.lParam) == GetScanCode(aMsg.lParam));
6762 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6763 * WM_CHAR messages for processing. During testing we don't want to
6764 * mess with the real message queue. Instead we pass a
6765 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6766 * that as if it was in the message queue, and refrain from actually
6767 * looking at or touching the message queue.
6769 LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
6770 nsModifierKeyState &aModKeyState,
6771 PRBool *aEventDispatched,
6772 nsFakeCharMessage* aFakeCharMessage)
6774 UINT virtualKeyCode =
6775 aMsg.wParam != VK_PROCESSKEY ? aMsg.wParam : ::ImmGetVirtualKey(mWnd);
6777 #ifndef WINCE
6778 gKbdLayout.OnKeyDown(virtualKeyCode);
6779 #endif
6781 // Use only DOMKeyCode for XP processing.
6782 // Use virtualKeyCode for gKbdLayout and native processing.
6783 UINT DOMKeyCode = nsIMM32Handler::IsComposingOn(this) ?
6784 virtualKeyCode : MapFromNativeToDOM(virtualKeyCode);
6786 #ifdef DEBUG
6787 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6788 #endif
6790 static PRBool sRedirectedKeyDownEventPreventedDefault = PR_FALSE;
6791 PRBool noDefault;
6792 if (aFakeCharMessage || !IsRedirectedKeyDownMessage(aMsg)) {
6793 HIMC oldIMC = mOldIMC;
6794 noDefault =
6795 DispatchKeyEvent(NS_KEY_DOWN, 0, nsnull, DOMKeyCode, &aMsg, aModKeyState);
6796 if (aEventDispatched) {
6797 *aEventDispatched = PR_TRUE;
6800 // If IMC wasn't associated to the window but is associated it now (i.e.,
6801 // focus is moved from a non-editable editor to an editor by keydown
6802 // event handler), WM_CHAR and WM_SYSCHAR shouldn't cause first character
6803 // inputting if IME is opened. But then, we should redirect the native
6804 // keydown message to IME.
6805 // However, note that if focus has been already moved to another
6806 // application, we shouldn't redirect the message to it because the keydown
6807 // message is processed by us, so, nobody shouldn't process it.
6808 HWND focusedWnd = ::GetFocus();
6809 if (!noDefault && !aFakeCharMessage && oldIMC && !mOldIMC && focusedWnd &&
6810 !PluginHasFocus()) {
6811 RemoveNextCharMessage(focusedWnd);
6813 INPUT keyinput;
6814 keyinput.type = INPUT_KEYBOARD;
6815 keyinput.ki.wVk = aMsg.wParam;
6816 keyinput.ki.wScan = GetScanCode(aMsg.lParam);
6817 keyinput.ki.dwFlags = KEYEVENTF_SCANCODE;
6818 if (IsExtendedScanCode(aMsg.lParam)) {
6819 keyinput.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
6821 keyinput.ki.time = 0;
6822 keyinput.ki.dwExtraInfo = NULL;
6824 sRedirectedKeyDownEventPreventedDefault = noDefault;
6825 sRedirectedKeyDown = aMsg;
6827 ::SendInput(1, &keyinput, sizeof(keyinput));
6829 // Return here. We shouldn't dispatch keypress event for this WM_KEYDOWN.
6830 // If it's needed, it will be dispatched after next (redirected)
6831 // WM_KEYDOWN.
6832 return PR_TRUE;
6835 if (mOnDestroyCalled) {
6836 // If this was destroyed by the keydown event handler, we shouldn't
6837 // dispatch keypress event on this window.
6838 return PR_TRUE;
6840 } else {
6841 noDefault = sRedirectedKeyDownEventPreventedDefault;
6842 // If this is redirected keydown message, we have dispatched the keydown
6843 // event already.
6844 if (aEventDispatched) {
6845 *aEventDispatched = PR_TRUE;
6849 ForgetRedirectedKeyDownMessage();
6851 // If the key was processed by IME, we shouldn't dispatch keypress event.
6852 if (aMsg.wParam == VK_PROCESSKEY) {
6853 return noDefault;
6856 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6857 // for almost all keys
6858 switch (DOMKeyCode) {
6859 case NS_VK_SHIFT:
6860 case NS_VK_CONTROL:
6861 case NS_VK_ALT:
6862 case NS_VK_CAPS_LOCK:
6863 case NS_VK_NUM_LOCK:
6864 case NS_VK_SCROLL_LOCK: return noDefault;
6867 PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
6868 MSG msg;
6869 BOOL gotMsg = aFakeCharMessage ||
6870 ::PeekMessageW(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6871 // Enter and backspace are always handled here to avoid for example the
6872 // confusion between ctrl-enter and ctrl-J.
6873 if (DOMKeyCode == NS_VK_RETURN || DOMKeyCode == NS_VK_BACK ||
6874 ((aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)
6875 #ifdef WINCE
6877 #else
6878 && !gKbdLayout.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
6879 #endif
6881 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6882 // They can be more than one because of:
6883 // * Dead-keys not pairing with base character
6884 // * Some keyboard layouts may map up to 4 characters to the single key
6885 PRBool anyCharMessagesRemoved = PR_FALSE;
6887 if (aFakeCharMessage) {
6888 anyCharMessagesRemoved = PR_TRUE;
6889 } else {
6890 while (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR))
6892 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6893 ("%s charCode=%d scanCode=%d\n", msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6894 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6895 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST, WM_KEYLAST);
6896 anyCharMessagesRemoved = PR_TRUE;
6898 gotMsg = ::PeekMessageW (&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6902 if (!anyCharMessagesRemoved && DOMKeyCode == NS_VK_BACK &&
6903 nsIMM32Handler::IsDoingKakuteiUndo(mWnd)) {
6904 NS_ASSERTION(!aFakeCharMessage,
6905 "We shouldn't be touching the real msg queue");
6906 RemoveMessageAndDispatchPluginEvent(WM_CHAR, WM_CHAR);
6909 else if (gotMsg &&
6910 (aFakeCharMessage ||
6911 msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
6912 if (aFakeCharMessage)
6913 return OnCharRaw(aFakeCharMessage->mCharCode,
6914 aFakeCharMessage->mScanCode, aModKeyState, extraFlags);
6916 // If prevent default set for keydown, do same for keypress
6917 ::GetMessageW(&msg, mWnd, msg.message, msg.message);
6919 if (msg.message == WM_DEADCHAR) {
6920 if (!PluginHasFocus())
6921 return PR_FALSE;
6923 // We need to send the removed message to focused plug-in.
6924 DispatchPluginEvent(msg);
6925 return noDefault;
6928 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6929 ("%s charCode=%d scanCode=%d\n",
6930 msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6931 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6933 BOOL result = OnChar(msg, aModKeyState, nsnull, extraFlags);
6934 // If a syschar keypress wasn't processed, Windows may want to
6935 // handle it to activate a native menu.
6936 if (!result && msg.message == WM_SYSCHAR)
6937 ::DefWindowProcW(mWnd, msg.message, msg.wParam, msg.lParam);
6938 return result;
6940 #ifndef WINCE
6941 else if (!aModKeyState.mIsControlDown && !aModKeyState.mIsAltDown &&
6942 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode) ||
6943 KeyboardLayout::IsNumpadKey(virtualKeyCode)))
6945 // If this is simple KeyDown event but next message is not WM_CHAR,
6946 // this event may not input text, so we should ignore this event.
6947 // See bug 314130.
6948 return PluginHasFocus() && noDefault;
6951 if (gKbdLayout.IsDeadKey ())
6952 return PluginHasFocus() && noDefault;
6954 PRUint8 shiftStates[5];
6955 PRUnichar uniChars[5];
6956 PRUnichar shiftedChars[5] = {0, 0, 0, 0, 0};
6957 PRUnichar unshiftedChars[5] = {0, 0, 0, 0, 0};
6958 PRUnichar shiftedLatinChar = 0;
6959 PRUnichar unshiftedLatinChar = 0;
6960 PRUint32 numOfUniChars = 0;
6961 PRUint32 numOfShiftedChars = 0;
6962 PRUint32 numOfUnshiftedChars = 0;
6963 PRUint32 numOfShiftStates = 0;
6965 switch (virtualKeyCode) {
6966 // keys to be sent as characters
6967 case VK_ADD: uniChars [0] = '+'; numOfUniChars = 1; break;
6968 case VK_SUBTRACT: uniChars [0] = '-'; numOfUniChars = 1; break;
6969 case VK_DIVIDE: uniChars [0] = '/'; numOfUniChars = 1; break;
6970 case VK_MULTIPLY: uniChars [0] = '*'; numOfUniChars = 1; break;
6971 case VK_NUMPAD0:
6972 case VK_NUMPAD1:
6973 case VK_NUMPAD2:
6974 case VK_NUMPAD3:
6975 case VK_NUMPAD4:
6976 case VK_NUMPAD5:
6977 case VK_NUMPAD6:
6978 case VK_NUMPAD7:
6979 case VK_NUMPAD8:
6980 case VK_NUMPAD9:
6981 uniChars [0] = virtualKeyCode - VK_NUMPAD0 + '0';
6982 numOfUniChars = 1;
6983 break;
6984 default:
6985 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
6986 numOfUniChars = numOfShiftStates =
6987 gKbdLayout.GetUniChars(uniChars, shiftStates,
6988 NS_ARRAY_LENGTH(uniChars));
6991 if (aModKeyState.mIsControlDown ^ aModKeyState.mIsAltDown) {
6992 PRUint8 capsLockState = (::GetKeyState(VK_CAPITAL) & 1) ? eCapsLock : 0;
6993 numOfUnshiftedChars =
6994 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode, capsLockState,
6995 unshiftedChars, NS_ARRAY_LENGTH(unshiftedChars));
6996 numOfShiftedChars =
6997 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode,
6998 capsLockState | eShift,
6999 shiftedChars, NS_ARRAY_LENGTH(shiftedChars));
7001 // The current keyboard cannot input alphabets or numerics,
7002 // we should append them for Shortcut/Access keys.
7003 // E.g., for Cyrillic keyboard layout.
7004 if (NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z) {
7005 shiftedLatinChar = unshiftedLatinChar = DOMKeyCode;
7006 if (capsLockState)
7007 shiftedLatinChar += 0x20;
7008 else
7009 unshiftedLatinChar += 0x20;
7010 if (unshiftedLatinChar == unshiftedChars[0] &&
7011 shiftedLatinChar == shiftedChars[0]) {
7012 shiftedLatinChar = unshiftedLatinChar = 0;
7014 } else {
7015 PRUint16 ch = 0;
7016 if (NS_VK_0 <= DOMKeyCode && DOMKeyCode <= NS_VK_9) {
7017 ch = DOMKeyCode;
7018 } else {
7019 switch (virtualKeyCode) {
7020 case VK_OEM_PLUS: ch = '+'; break;
7021 case VK_OEM_MINUS: ch = '-'; break;
7024 if (ch && unshiftedChars[0] != ch && shiftedChars[0] != ch) {
7025 // Windows has assigned a virtual key code to the key even though
7026 // the character can't be produced with this key. That probably
7027 // means the character can't be produced with any key in the
7028 // current layout and so the assignment is based on a QWERTY
7029 // layout. Append this code so that users can access the shortcut.
7030 unshiftedLatinChar = ch;
7034 // If the charCode is not ASCII character, we should replace the
7035 // charCode with ASCII character only when Ctrl is pressed.
7036 // But don't replace the charCode when the charCode is not same as
7037 // unmodified characters. In such case, Ctrl is sometimes used for a
7038 // part of character inputting key combination like Shift.
7039 if (aModKeyState.mIsControlDown) {
7040 PRUint8 currentState = eCtrl;
7041 if (aModKeyState.mIsShiftDown)
7042 currentState |= eShift;
7044 PRUint32 ch =
7045 aModKeyState.mIsShiftDown ? shiftedLatinChar : unshiftedLatinChar;
7046 if (ch &&
7047 (numOfUniChars == 0 ||
7048 StringCaseInsensitiveEquals(uniChars, numOfUniChars,
7049 aModKeyState.mIsShiftDown ? shiftedChars : unshiftedChars,
7050 aModKeyState.mIsShiftDown ? numOfShiftedChars :
7051 numOfUnshiftedChars))) {
7052 numOfUniChars = numOfShiftStates = 1;
7053 uniChars[0] = ch;
7054 shiftStates[0] = currentState;
7060 if (numOfUniChars > 0 || numOfShiftedChars > 0 || numOfUnshiftedChars > 0) {
7061 PRUint32 num = PR_MAX(numOfUniChars,
7062 PR_MAX(numOfShiftedChars, numOfUnshiftedChars));
7063 PRUint32 skipUniChars = num - numOfUniChars;
7064 PRUint32 skipShiftedChars = num - numOfShiftedChars;
7065 PRUint32 skipUnshiftedChars = num - numOfUnshiftedChars;
7066 UINT keyCode = numOfUniChars == 0 ? DOMKeyCode : 0;
7067 for (PRUint32 cnt = 0; cnt < num; cnt++) {
7068 PRUint16 uniChar, shiftedChar, unshiftedChar;
7069 uniChar = shiftedChar = unshiftedChar = 0;
7070 if (skipUniChars <= cnt) {
7071 if (cnt - skipUniChars < numOfShiftStates) {
7072 // If key in combination with Alt and/or Ctrl produces a different
7073 // character than without them then do not report these flags
7074 // because it is separate keyboard layout shift state. If dead-key
7075 // and base character does not produce a valid composite character
7076 // then both produced dead-key character and following base
7077 // character may have different modifier flags, too.
7078 aModKeyState.mIsShiftDown =
7079 (shiftStates[cnt - skipUniChars] & eShift) != 0;
7080 aModKeyState.mIsControlDown =
7081 (shiftStates[cnt - skipUniChars] & eCtrl) != 0;
7082 aModKeyState.mIsAltDown =
7083 (shiftStates[cnt - skipUniChars] & eAlt) != 0;
7085 uniChar = uniChars[cnt - skipUniChars];
7087 if (skipShiftedChars <= cnt)
7088 shiftedChar = shiftedChars[cnt - skipShiftedChars];
7089 if (skipUnshiftedChars <= cnt)
7090 unshiftedChar = unshiftedChars[cnt - skipUnshiftedChars];
7091 nsAutoTArray<nsAlternativeCharCode, 5> altArray;
7093 if (shiftedChar || unshiftedChar) {
7094 nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
7095 altArray.AppendElement(chars);
7097 if (cnt == num - 1 && (unshiftedLatinChar || shiftedLatinChar)) {
7098 nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
7099 altArray.AppendElement(chars);
7102 DispatchKeyEvent(NS_KEY_PRESS, uniChar, &altArray,
7103 keyCode, nsnull, aModKeyState, extraFlags);
7105 } else {
7106 DispatchKeyEvent(NS_KEY_PRESS, 0, nsnull, DOMKeyCode, nsnull, aModKeyState,
7107 extraFlags);
7109 #else
7111 UINT unichar = ::MapVirtualKey(virtualKeyCode, MAPVK_VK_TO_CHAR);
7112 // Check for dead characters or no mapping
7113 if (unichar & 0x80) {
7114 return noDefault;
7116 DispatchKeyEvent(NS_KEY_PRESS, unichar, nsnull, DOMKeyCode, nsnull, aModKeyState,
7117 extraFlags);
7119 #endif
7121 return noDefault;
7124 // OnKeyUp
7125 LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
7126 nsModifierKeyState &aModKeyState,
7127 PRBool *aEventDispatched)
7129 UINT virtualKeyCode = aMsg.wParam;
7131 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
7132 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
7134 if (!nsIMM32Handler::IsComposingOn(this)) {
7135 virtualKeyCode = MapFromNativeToDOM(virtualKeyCode);
7138 if (aEventDispatched)
7139 *aEventDispatched = PR_TRUE;
7140 return DispatchKeyEvent(NS_KEY_UP, 0, nsnull, virtualKeyCode, &aMsg,
7141 aModKeyState);
7144 // OnChar
7145 LRESULT nsWindow::OnChar(const MSG &aMsg, nsModifierKeyState &aModKeyState,
7146 PRBool *aEventDispatched, PRUint32 aFlags)
7148 return OnCharRaw(aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF, aModKeyState,
7149 aFlags, &aMsg, aEventDispatched);
7152 // OnCharRaw
7153 LRESULT nsWindow::OnCharRaw(UINT charCode, UINT aScanCode,
7154 nsModifierKeyState &aModKeyState, PRUint32 aFlags,
7155 const MSG *aMsg, PRBool *aEventDispatched)
7157 // ignore [shift+]alt+space so the OS can handle it
7158 if (aModKeyState.mIsAltDown && !aModKeyState.mIsControlDown &&
7159 IS_VK_DOWN(NS_VK_SPACE)) {
7160 return FALSE;
7163 // Ignore Ctrl+Enter (bug 318235)
7164 if (aModKeyState.mIsControlDown && charCode == 0xA) {
7165 return FALSE;
7168 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
7169 PRBool saveIsAltDown = aModKeyState.mIsAltDown;
7170 PRBool saveIsControlDown = aModKeyState.mIsControlDown;
7171 if (aModKeyState.mIsAltDown && aModKeyState.mIsControlDown)
7172 aModKeyState.mIsAltDown = aModKeyState.mIsControlDown = PR_FALSE;
7174 wchar_t uniChar;
7176 if (nsIMM32Handler::IsComposingOn(this)) {
7177 ResetInputState();
7180 if (aModKeyState.mIsControlDown && charCode <= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
7181 // need to account for shift here. bug 16486
7182 if (aModKeyState.mIsShiftDown)
7183 uniChar = charCode - 1 + 'A';
7184 else
7185 uniChar = charCode - 1 + 'a';
7186 charCode = 0;
7188 else if (aModKeyState.mIsControlDown && charCode <= 0x1F) {
7189 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
7190 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
7191 // for some reason the keypress handler need to have the uniChar code set
7192 // with the addition of a upper case A not the lower case.
7193 uniChar = charCode - 1 + 'A';
7194 charCode = 0;
7195 } else { // 0x20 - SPACE, 0x3D - EQUALS
7196 if (charCode < 0x20 || (charCode == 0x3D && aModKeyState.mIsControlDown)) {
7197 uniChar = 0;
7198 } else {
7199 uniChar = charCode;
7200 charCode = 0;
7204 // Keep the characters unshifted for shortcuts and accesskeys and make sure
7205 // that numbers are always passed as such (among others: bugs 50255 and 351310)
7206 if (uniChar && (aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)) {
7207 UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK,
7208 gKbdLayout.GetLayout());
7209 UINT unshiftedCharCode =
7210 virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
7211 aModKeyState.mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode,
7212 MAPVK_VK_TO_CHAR,
7213 gKbdLayout.GetLayout()) : 0;
7214 // ignore diacritics (top bit set) and key mapping errors (char code 0)
7215 if ((INT)unshiftedCharCode > 0)
7216 uniChar = unshiftedCharCode;
7219 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
7220 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
7221 // pressed too.
7222 if (!aModKeyState.mIsShiftDown && (saveIsAltDown || saveIsControlDown)) {
7223 uniChar = towlower(uniChar);
7226 PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, nsnull,
7227 charCode, aMsg, aModKeyState, aFlags);
7228 if (aEventDispatched)
7229 *aEventDispatched = PR_TRUE;
7230 aModKeyState.mIsAltDown = saveIsAltDown;
7231 aModKeyState.mIsControlDown = saveIsControlDown;
7232 return result;
7235 void
7236 nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers)
7238 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierKeyMap); ++i) {
7239 const PRUint32* map = sModifierKeyMap[i];
7240 if (aModifiers & map[0]) {
7241 aArray->AppendElement(KeyPair(map[1], map[2]));
7246 nsresult
7247 nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
7249 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
7250 // here, if that helps in some situations. So far I haven't seen a
7251 // need.
7252 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
7253 const Configuration& configuration = aConfigurations[i];
7254 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
7255 NS_ASSERTION(w->GetParent() == this,
7256 "Configured widget is not a child");
7257 #ifdef WINCE
7258 // MSDN says we should do on WinCE this before moving or resizing the window
7259 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
7260 // We put the region back just below, anyway.
7261 ::SetWindowRgn(w->mWnd, NULL, TRUE);
7262 #endif
7263 nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_TRUE);
7264 NS_ENSURE_SUCCESS(rv, rv);
7265 nsIntRect bounds;
7266 w->GetBounds(bounds);
7267 if (bounds.Size() != configuration.mBounds.Size()) {
7268 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
7269 configuration.mBounds.width, configuration.mBounds.height,
7270 PR_TRUE);
7271 } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
7272 w->Move(configuration.mBounds.x, configuration.mBounds.y);
7275 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7276 gfxWindowsPlatform::RENDER_DIRECT2D ||
7277 GetLayerManager()->GetBackendType() != LayerManager::LAYERS_BASIC) {
7278 // XXX - Workaround for Bug 587508. This will invalidate the part of the
7279 // plugin window that might be touched by moving content somehow. The
7280 // underlying problem should be found and fixed!
7281 nsIntRegion r;
7282 r.Sub(bounds, configuration.mBounds);
7283 r.MoveBy(-bounds.x,
7284 -bounds.y);
7285 w->Invalidate(r.GetBounds(), PR_FALSE);
7288 rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_FALSE);
7289 NS_ENSURE_SUCCESS(rv, rv);
7291 return NS_OK;
7294 static HRGN
7295 CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
7297 PRInt32 size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
7298 nsAutoTArray<PRUint8,100> buf;
7299 if (!buf.SetLength(size))
7300 return NULL;
7301 RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
7302 RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
7303 data->rdh.dwSize = sizeof(data->rdh);
7304 data->rdh.iType = RDH_RECTANGLES;
7305 data->rdh.nCount = aRects.Length();
7306 nsIntRect bounds;
7307 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
7308 const nsIntRect& r = aRects[i];
7309 bounds.UnionRect(bounds, r);
7310 ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
7312 ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
7313 return ::ExtCreateRegion(NULL, buf.Length(), data);
7316 static const nsTArray<nsIntRect>
7317 ArrayFromRegion(const nsIntRegion& aRegion)
7319 nsTArray<nsIntRect> rects;
7320 const nsIntRect* r;
7321 for (nsIntRegionRectIterator iter(aRegion); (r = iter.Next());) {
7322 rects.AppendElement(*r);
7324 return rects;
7327 nsresult
7328 nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
7329 PRBool aIntersectWithExisting)
7331 if (!aIntersectWithExisting) {
7332 if (!StoreWindowClipRegion(aRects))
7333 return NS_OK;
7334 } else {
7335 // In this case still early return if nothing changed.
7336 if (mClipRects && mClipRectCount == aRects.Length() &&
7337 memcmp(mClipRects,
7338 aRects.Elements(),
7339 sizeof(nsIntRect)*mClipRectCount) == 0) {
7340 return NS_OK;
7343 // get current rects
7344 nsTArray<nsIntRect> currentRects;
7345 GetWindowClipRegion(&currentRects);
7346 // create region from them
7347 nsIntRegion currentRegion = RegionFromArray(currentRects);
7348 // create region from new rects
7349 nsIntRegion newRegion = RegionFromArray(aRects);
7350 // intersect regions
7351 nsIntRegion intersection;
7352 intersection.And(currentRegion, newRegion);
7353 // create int rect array from intersection
7354 nsTArray<nsIntRect> rects = ArrayFromRegion(intersection);
7355 // store
7356 if (!StoreWindowClipRegion(rects))
7357 return NS_OK;
7360 HRGN dest = CreateHRGNFromArray(aRects);
7361 if (!dest)
7362 return NS_ERROR_OUT_OF_MEMORY;
7364 if (aIntersectWithExisting) {
7365 HRGN current = ::CreateRectRgn(0, 0, 0, 0);
7366 if (current) {
7367 if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
7368 ::CombineRgn(dest, dest, current, RGN_AND);
7370 ::DeleteObject(current);
7374 if (!::SetWindowRgn(mWnd, dest, TRUE)) {
7375 ::DeleteObject(dest);
7376 return NS_ERROR_FAILURE;
7378 return NS_OK;
7381 // WM_DESTROY event handler
7382 void nsWindow::OnDestroy()
7384 mOnDestroyCalled = PR_TRUE;
7386 // Make sure we don't get destroyed in the process of tearing down.
7387 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
7389 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
7390 if (!mInDtor)
7391 DispatchStandardEvent(NS_DESTROY);
7393 // Prevent the widget from sending additional events.
7394 mEventCallback = nsnull;
7396 // Free our subclass and clear |this| stored in the window props. We will no longer
7397 // receive events from Windows after this point.
7398 SubclassWindow(FALSE);
7400 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
7401 // cleared. (It's used in tracking windows for mouse events.)
7402 if (sCurrentWindow == this)
7403 sCurrentWindow = nsnull;
7405 // Disconnects us from our parent, will call our GetParent().
7406 nsBaseWidget::Destroy();
7408 // Release references to children, device context, toolkit, and app shell.
7409 nsBaseWidget::OnDestroy();
7411 // Clear our native parent handle.
7412 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
7413 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
7414 //SetParent(nsnull);
7415 mParent = nsnull;
7417 // We have to destroy the native drag target before we null out our window pointer.
7418 EnableDragDrop(PR_FALSE);
7420 // If we're going away and for some reason we're still the rollup widget, rollup and
7421 // turn off capture.
7422 if ( this == sRollupWidget ) {
7423 if ( sRollupListener )
7424 sRollupListener->Rollup(nsnull, nsnull);
7425 CaptureRollupEvents(nsnull, nsnull, PR_FALSE, PR_TRUE);
7428 // If IME is disabled, restore it.
7429 if (mOldIMC) {
7430 mOldIMC = ::ImmAssociateContext(mWnd, mOldIMC);
7431 NS_ASSERTION(!mOldIMC, "Another IMC was associated");
7434 // Turn off mouse trails if enabled.
7435 MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
7436 if (mtrailer) {
7437 if (mtrailer->GetMouseTrailerWindow() == mWnd)
7438 mtrailer->DestroyTimer();
7440 if (mtrailer->GetCaptureWindow() == mWnd)
7441 mtrailer->SetCaptureWindow(nsnull);
7444 // Free GDI window class objects
7445 if (mBrush) {
7446 VERIFY(::DeleteObject(mBrush));
7447 mBrush = NULL;
7450 // Free app icon resources.
7451 HICON icon;
7452 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM) 0);
7453 if (icon)
7454 ::DestroyIcon(icon);
7456 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM) 0);
7457 if (icon)
7458 ::DestroyIcon(icon);
7460 // Destroy any custom cursor resources.
7461 if (mCursor == -1)
7462 SetCursor(eCursor_standard);
7464 #ifdef MOZ_XUL
7465 // Reset transparency
7466 if (eTransparencyTransparent == mTransparencyMode)
7467 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
7468 #endif
7470 #if defined(WINCE_HAVE_SOFTKB)
7471 // Revert the changes made for the software keyboard settings
7472 nsWindowCE::ResetSoftKB(mWnd);
7473 #endif
7475 #if !defined(WINCE)
7476 // Finalize panning feedback to possibly restore window displacement
7477 mGesture.PanFeedbackFinalize(mWnd, PR_TRUE);
7478 #endif
7480 // Clear the main HWND.
7481 mWnd = NULL;
7484 // OnMove
7485 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
7487 mBounds.x = aX;
7488 mBounds.y = aY;
7490 nsGUIEvent event(PR_TRUE, NS_MOVE, this);
7491 InitEvent(event);
7492 event.refPoint.x = aX;
7493 event.refPoint.y = aY;
7495 return DispatchWindowEvent(&event);
7498 // Send a resize message to the listener
7499 PRBool nsWindow::OnResize(nsIntRect &aWindowRect)
7501 #ifdef CAIRO_HAS_D2D_SURFACE
7502 if (mD2DWindowSurface) {
7503 mD2DWindowSurface = NULL;
7504 Invalidate(PR_FALSE);
7506 #endif
7508 // call the event callback
7509 if (mEventCallback) {
7510 nsSizeEvent event(PR_TRUE, NS_SIZE, this);
7511 InitEvent(event);
7512 event.windowSize = &aWindowRect;
7513 RECT r;
7514 if (::GetWindowRect(mWnd, &r)) {
7515 event.mWinWidth = PRInt32(r.right - r.left);
7516 event.mWinHeight = PRInt32(r.bottom - r.top);
7517 } else {
7518 event.mWinWidth = 0;
7519 event.mWinHeight = 0;
7522 #if 0
7523 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7524 aWindowRect.x, aWindowRect.y, aWindowRect.width, aWindowRect.height,
7525 event.mWinWidth, event.mWinHeight);
7526 #endif
7528 return DispatchWindowEvent(&event);
7531 return PR_FALSE;
7534 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7535 PRBool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
7537 return PR_TRUE;
7539 #endif // !defined(WINCE)
7541 void nsWindow::OnSettingsChange(WPARAM wParam, LPARAM lParam)
7543 if (mWindowType == eWindowType_dialog ||
7544 mWindowType == eWindowType_toplevel )
7545 nsWindowGfx::OnSettingsChangeGfx(wParam);
7548 /* static */
7549 PRBool nsWindow::IsOurProcessWindow(HWND aHWND)
7551 if (!aHWND) {
7552 return PR_FALSE;
7554 DWORD processId = 0;
7555 ::GetWindowThreadProcessId(aHWND, &processId);
7556 return processId == ::GetCurrentProcessId();
7559 /* static */
7560 HWND nsWindow::FindOurProcessWindow(HWND aHWND)
7562 for (HWND wnd = ::GetParent(aHWND); wnd; wnd = ::GetParent(wnd)) {
7563 if (IsOurProcessWindow(wnd)) {
7564 return wnd;
7567 return nsnull;
7570 // Scrolling helper function for handling plugins.
7571 // Return value indicates whether the calling function should handle this
7572 // aHandled indicates whether this was handled at all
7573 // aQuitProcessing tells whether or not to continue processing the message
7574 PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
7575 LPARAM aLParam, PRBool& aHandled,
7576 LRESULT* aRetValue,
7577 PRBool& aQuitProcessing)
7579 // The scroll event will be dispatched to the toplevel
7580 // window. We need to give it to the child window
7581 aQuitProcessing = PR_FALSE; // default is to not stop processing
7582 POINT point;
7583 DWORD dwPoints = ::GetMessagePos();
7584 point.x = GET_X_LPARAM(dwPoints);
7585 point.y = GET_Y_LPARAM(dwPoints);
7587 static PRBool sIsProcessing = PR_FALSE;
7588 if (sIsProcessing) {
7589 return PR_TRUE; // the caller should handle this.
7592 static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
7593 if (aMsg == WM_MOUSEHWHEEL) {
7594 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7595 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7596 // message at first time, this time, ::GetMessagePos works fine.
7597 // Then, we will return 0 (0 means we process it) to the message. Then, the
7598 // driver will POST the same messages continuously during the wheel tilted.
7599 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7600 // cursor isn't 0,0. Therefore, we cannot trust the result of
7601 // ::GetMessagePos API if the sender is the driver.
7602 if (!sMayBeUsingLogitechMouse && aLParam == 0 && (DWORD)aLParam != dwPoints &&
7603 ::InSendMessage()) {
7604 sMayBeUsingLogitechMouse = PR_TRUE;
7605 } else if (sMayBeUsingLogitechMouse && aLParam != 0 && ::InSendMessage()) {
7606 // The user has changed the mouse from Logitech's to another one (e.g.,
7607 // the user has changed to the touchpad of the notebook.
7608 sMayBeUsingLogitechMouse = PR_FALSE;
7610 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7611 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7612 // instead.
7613 if (sMayBeUsingLogitechMouse && aLParam == 0 && dwPoints == 0) {
7614 ::GetCursorPos(&point);
7618 HWND destWnd = ::WindowFromPoint(point);
7619 // Since we receive scroll events for as long as
7620 // we are focused, it's entirely possible that there
7621 // is another app's window or no window under the
7622 // pointer.
7624 if (!destWnd) {
7625 // No window is under the pointer
7626 return PR_FALSE; // break, but continue processing
7629 nsWindow* destWindow;
7631 // We don't handle the message if the found window belongs to another
7632 // process's top window. If it belongs window, that is a plug-in's window.
7633 // Then, we need to send the message to the plug-in window.
7634 if (!IsOurProcessWindow(destWnd)) {
7635 HWND ourPluginWnd = FindOurProcessWindow(destWnd);
7636 if (!ourPluginWnd) {
7637 // Somebody elses window
7638 return PR_FALSE; // break, but continue processing
7640 destWindow = GetNSWindowPtr(ourPluginWnd);
7641 } else {
7642 destWindow = GetNSWindowPtr(destWnd);
7645 if (destWindow == this && mWindowType == eWindowType_plugin) {
7646 // If this is plug-in window, the message came from the plug-in window.
7647 // Then, the message should be processed on the parent window.
7648 destWindow = static_cast<nsWindow*>(GetParent());
7649 NS_ENSURE_TRUE(destWindow, PR_FALSE); // break, but continue processing
7650 destWnd = destWindow->mWnd;
7651 NS_ENSURE_TRUE(destWnd, PR_FALSE); // break, but continue processing
7654 if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
7655 // Some other app, or a plugin window.
7656 // Windows directs scrolling messages to the focused window.
7657 // However, Mozilla does not like plugins having focus, so a
7658 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7659 // Therefore, plugins etc _should_ get first grab at the
7660 // message, but this focus vaguary means the plugin misses
7661 // out. If the window is a child of ours, forward it on.
7662 // Determine if a child by walking the parent list until
7663 // we find a parent matching our wndproc.
7664 HWND parentWnd = ::GetParent(destWnd);
7665 while (parentWnd) {
7666 nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
7667 if (parentWindow) {
7668 // We have a child window - quite possibly a plugin window.
7669 // However, not all plugins are created equal - some will handle this
7670 // message themselves, some will forward directly back to us, while
7671 // others will call DefWndProc, which itself still forwards back to us.
7672 // So if we have sent it once, we need to handle it ourself.
7674 #ifdef MOZ_IPC
7675 // XXX The message shouldn't come from the plugin window at here.
7676 // But the message might come from it due to some bugs. If it happens,
7677 // SendMessage causes deadlock. For safety, we should unlock the
7678 // sender here.
7679 ::ReplyMessage(aMsg == WM_MOUSEHWHEEL ? TRUE : 0);
7680 #endif
7682 // First time we have seen this message.
7683 // Call the child - either it will consume it, or
7684 // it will wind it's way back to us,triggering the destWnd case above
7685 // either way,when the call returns,we are all done with the message,
7686 sIsProcessing = PR_TRUE;
7687 ::SendMessageW(destWnd, aMsg, aWParam, aLParam);
7688 sIsProcessing = PR_FALSE;
7689 aHandled = PR_TRUE;
7690 aQuitProcessing = PR_TRUE;
7691 return PR_FALSE; // break, and stop processing
7693 parentWnd = ::GetParent(parentWnd);
7694 } // while parentWnd
7696 if (destWnd == nsnull)
7697 return PR_FALSE;
7698 if (destWnd != mWnd) {
7699 if (destWindow) {
7700 sIsProcessing = PR_TRUE;
7701 aHandled = destWindow->ProcessMessage(aMsg, aWParam, aLParam, aRetValue);
7702 sIsProcessing = PR_FALSE;
7703 aQuitProcessing = PR_TRUE;
7704 return PR_FALSE; // break, and stop processing
7706 #ifdef DEBUG
7707 else
7708 printf("WARNING: couldn't get child window for SCROLL event\n");
7709 #endif
7711 return PR_TRUE; // caller should handle this
7714 PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
7716 static PRInt8 sMouseWheelEmulation = -1;
7717 if (sMouseWheelEmulation < 0) {
7718 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7719 NS_ENSURE_TRUE(prefs, PR_FALSE);
7720 nsCOMPtr<nsIPrefBranch> prefBranch;
7721 prefs->GetBranch(0, getter_AddRefs(prefBranch));
7722 NS_ENSURE_TRUE(prefBranch, PR_FALSE);
7723 PRBool emulate;
7724 nsresult rv =
7725 prefBranch->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate);
7726 NS_ENSURE_SUCCESS(rv, PR_FALSE);
7727 sMouseWheelEmulation = PRInt8(emulate);
7730 if (aLParam || sMouseWheelEmulation) {
7731 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7732 // Treat as a mousewheel message and scroll appropriately
7733 PRBool quit, result;
7734 LRESULT retVal;
7736 if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result, &retVal, quit))
7737 return quit; // Return if it's not our message or has been dispatched
7739 nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
7740 scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
7741 ? nsMouseScrollEvent::kIsVertical
7742 : nsMouseScrollEvent::kIsHorizontal;
7743 switch (LOWORD(aWParam))
7745 case SB_PAGEDOWN:
7746 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7747 case SB_LINEDOWN:
7748 scrollevent.delta = 1;
7749 break;
7750 case SB_PAGEUP:
7751 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7752 case SB_LINEUP:
7753 scrollevent.delta = -1;
7754 break;
7755 default:
7756 return PR_FALSE;
7758 #ifdef MOZ_IPC
7759 // The event may go to a plug-in which already dispatched this message.
7760 // Then, the event can cause deadlock. We should unlock the sender here.
7761 ::ReplyMessage(0);
7762 #endif
7763 scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
7764 scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
7765 scrollevent.isMeta = PR_FALSE;
7766 scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
7767 InitEvent(scrollevent);
7768 if (nsnull != mEventCallback)
7770 DispatchWindowEvent(&scrollevent);
7772 return PR_TRUE;
7775 // Scroll message generated by external application
7776 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_SCROLL, this);
7778 command.mScroll.mIsHorizontal = (aMsg == WM_HSCROLL);
7780 switch (LOWORD(aWParam))
7782 case SB_LINEUP: // SB_LINELEFT
7783 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7784 command.mScroll.mAmount = -1;
7785 break;
7786 case SB_LINEDOWN: // SB_LINERIGHT
7787 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7788 command.mScroll.mAmount = 1;
7789 break;
7790 case SB_PAGEUP: // SB_PAGELEFT
7791 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7792 command.mScroll.mAmount = -1;
7793 break;
7794 case SB_PAGEDOWN: // SB_PAGERIGHT
7795 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7796 command.mScroll.mAmount = 1;
7797 break;
7798 case SB_TOP: // SB_LEFT
7799 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7800 command.mScroll.mAmount = -1;
7801 break;
7802 case SB_BOTTOM: // SB_RIGHT
7803 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7804 command.mScroll.mAmount = 1;
7805 break;
7806 default:
7807 return PR_FALSE;
7809 DispatchWindowEvent(&command);
7810 return PR_TRUE;
7813 // Can be overriden. Controls auto-erase of background.
7814 PRBool nsWindow::AutoErase(HDC dc)
7816 return PR_FALSE;
7819 void
7820 nsWindow::AllowD3D9Callback(nsWindow *aWindow)
7822 if (aWindow->mLayerManager) {
7823 aWindow->mLayerManager->Destroy();
7824 aWindow->mLayerManager = NULL;
7828 void
7829 nsWindow::AllowD3D9WithReinitializeCallback(nsWindow *aWindow)
7831 if (aWindow->mLayerManager) {
7832 aWindow->mLayerManager->Destroy();
7833 aWindow->mLayerManager = NULL;
7834 (void) aWindow->GetLayerManager();
7838 void
7839 nsWindow::StartAllowingD3D9(bool aReinitialize)
7841 sAllowD3D9 = true;
7843 LayerManagerPrefs prefs;
7844 GetLayerManagerPrefs(&prefs);
7845 if (prefs.mDisableAcceleration) {
7846 // The guarantee here is, if there's *any* chance that after we
7847 // throw out our layer managers we'd create at least one new,
7848 // accelerated one, we *will* throw out all the current layer
7849 // managers. We early-return here because currently, if
7850 // |disableAcceleration|, we will always use basic managers and
7851 // it's a waste to recreate them.
7853 // NB: the above implies that it's eminently possible for us to
7854 // skip this early return but still recreate basic managers.
7855 // That's OK. It's *not* OK to take this early return when we
7856 // *might* have created an accelerated manager.
7857 return;
7860 if (aReinitialize) {
7861 EnumAllWindows(AllowD3D9WithReinitializeCallback);
7862 } else {
7863 EnumAllWindows(AllowD3D9Callback);
7867 /**************************************************************
7868 **************************************************************
7870 ** BLOCK: IME management and accessibility
7872 ** Handles managing IME input and accessibility.
7874 **************************************************************
7875 **************************************************************/
7877 NS_IMETHODIMP nsWindow::ResetInputState()
7879 #ifdef DEBUG_KBSTATE
7880 printf("ResetInputState\n");
7881 #endif
7883 #ifdef NS_ENABLE_TSF
7884 nsTextStore::CommitComposition(PR_FALSE);
7885 #endif //NS_ENABLE_TSF
7887 nsIMM32Handler::CommitComposition(this);
7888 return NS_OK;
7891 NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState)
7893 #ifdef DEBUG_KBSTATE
7894 printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
7895 #endif
7897 #ifdef NS_ENABLE_TSF
7898 nsTextStore::SetIMEOpenState(aState);
7899 #endif //NS_ENABLE_TSF
7901 nsIMEContext IMEContext(mWnd);
7902 if (IMEContext.IsValid()) {
7903 ::ImmSetOpenStatus(IMEContext.get(), aState ? TRUE : FALSE);
7905 return NS_OK;
7908 NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState)
7910 nsIMEContext IMEContext(mWnd);
7911 if (IMEContext.IsValid()) {
7912 BOOL isOpen = ::ImmGetOpenStatus(IMEContext.get());
7913 *aState = isOpen ? PR_TRUE : PR_FALSE;
7914 } else
7915 *aState = PR_FALSE;
7917 #ifdef NS_ENABLE_TSF
7918 *aState |= nsTextStore::GetIMEOpenState();
7919 #endif //NS_ENABLE_TSF
7921 return NS_OK;
7924 NS_IMETHODIMP nsWindow::SetInputMode(const IMEContext& aContext)
7926 PRUint32 status = aContext.mStatus;
7927 #ifdef NS_ENABLE_TSF
7928 nsTextStore::SetInputMode(aContext);
7929 #endif //NS_ENABLE_TSF
7930 #ifdef DEBUG_KBSTATE
7931 printf("SetInputMode: %s\n", (status == nsIWidget::IME_STATUS_ENABLED ||
7932 status == nsIWidget::IME_STATUS_PLUGIN) ?
7933 "Enabled" : "Disabled");
7934 #endif
7935 if (nsIMM32Handler::IsComposing()) {
7936 ResetInputState();
7938 mIMEContext = aContext;
7939 PRBool enable = (status == nsIWidget::IME_STATUS_ENABLED ||
7940 status == nsIWidget::IME_STATUS_PLUGIN);
7942 #if defined(WINCE_HAVE_SOFTKB)
7943 sSoftKeyboardState = (status != nsIWidget::IME_STATUS_DISABLED);
7944 nsWindowCE::ToggleSoftKB(mWnd, sSoftKeyboardState);
7945 #endif
7947 if (!enable != !mOldIMC)
7948 return NS_OK;
7949 mOldIMC = ::ImmAssociateContext(mWnd, enable ? mOldIMC : NULL);
7950 NS_ASSERTION(!enable || !mOldIMC, "Another IMC was associated");
7952 return NS_OK;
7955 NS_IMETHODIMP nsWindow::GetInputMode(IMEContext& aContext)
7957 #ifdef DEBUG_KBSTATE
7958 printf("GetInputMode: %s\n", mIMEContext.mStatus ? "Enabled" : "Disabled");
7959 #endif
7960 aContext = mIMEContext;
7961 return NS_OK;
7964 NS_IMETHODIMP nsWindow::CancelIMEComposition()
7966 #ifdef DEBUG_KBSTATE
7967 printf("CancelIMEComposition\n");
7968 #endif
7970 #ifdef NS_ENABLE_TSF
7971 nsTextStore::CommitComposition(PR_TRUE);
7972 #endif //NS_ENABLE_TSF
7974 nsIMM32Handler::CancelComposition(this);
7975 return NS_OK;
7978 NS_IMETHODIMP
7979 nsWindow::GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState)
7981 #ifdef DEBUG_KBSTATE
7982 printf("GetToggledKeyState\n");
7983 #endif
7984 NS_ENSURE_ARG_POINTER(aLEDState);
7985 *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
7986 return NS_OK;
7989 #ifdef NS_ENABLE_TSF
7990 NS_IMETHODIMP
7991 nsWindow::OnIMEFocusChange(PRBool aFocus)
7993 nsresult rv = nsTextStore::OnFocusChange(aFocus, this, mIMEContext.mStatus);
7994 if (rv == NS_ERROR_NOT_AVAILABLE)
7995 rv = NS_ERROR_NOT_IMPLEMENTED; // TSF is not enabled, maybe.
7996 return rv;
7999 NS_IMETHODIMP
8000 nsWindow::OnIMETextChange(PRUint32 aStart,
8001 PRUint32 aOldEnd,
8002 PRUint32 aNewEnd)
8004 return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
8007 NS_IMETHODIMP
8008 nsWindow::OnIMESelectionChange(void)
8010 return nsTextStore::OnSelectionChange();
8012 #endif //NS_ENABLE_TSF
8014 #ifdef ACCESSIBILITY
8016 #ifdef DEBUG_WMGETOBJECT
8017 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
8018 nsAccessible* acc = aWnd ? \
8019 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
8020 printf(" acc: %p", acc); \
8021 if (acc) { \
8022 nsAutoString name; \
8023 acc->GetName(name); \
8024 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
8025 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
8026 void *hwnd = nsnull; \
8027 doc->GetWindowHandle(&hwnd); \
8028 printf(", acc hwnd: %d", hwnd); \
8031 #define NS_LOG_WMGETOBJECT_THISWND \
8033 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
8034 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
8035 mWnd, ::GetParent(mWnd), this); \
8036 NS_LOG_WMGETOBJECT_WNDACC(this) \
8037 printf("\n }\n"); \
8040 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
8042 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
8043 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
8044 aHwnd, ::GetParent(aHwnd), wnd); \
8045 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
8046 printf("\n }\n"); \
8048 #else
8049 #define NS_LOG_WMGETOBJECT_THISWND
8050 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
8051 #endif // DEBUG_WMGETOBJECT
8053 nsAccessible*
8054 nsWindow::GetRootAccessible()
8056 // We want the ability to forcibly disable a11y on windows, because
8057 // some non-a11y-related components attempt to bring it up. See bug
8058 // 538530 for details; we have a pref here that allows it to be disabled
8059 // for performance and testing resons.
8061 // This pref is checked only once, and the browser needs a restart to
8062 // pick up any changes.
8063 static int accForceDisable = -1;
8065 if (accForceDisable == -1) {
8066 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
8067 PRBool b = PR_FALSE;
8068 nsresult rv = prefs->GetBoolPref("accessibility.win32.force_disabled", &b);
8069 if (NS_SUCCEEDED(rv) && b) {
8070 accForceDisable = 1;
8071 } else {
8072 accForceDisable = 0;
8076 // If the pref was true, return null here, disabling a11y.
8077 if (accForceDisable)
8078 return nsnull;
8080 nsWindow::sIsAccessibilityOn = TRUE;
8082 if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) {
8083 return nsnull;
8086 NS_LOG_WMGETOBJECT_THISWND
8087 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
8089 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
8092 STDMETHODIMP_(LRESULT)
8093 nsWindow::LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc)
8095 // open the dll dynamically
8096 if (!sAccLib)
8097 sAccLib =::LoadLibraryW(L"OLEACC.DLL");
8099 if (sAccLib) {
8100 if (!sLresultFromObject)
8101 sLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(sAccLib,"LresultFromObject");
8103 if (sLresultFromObject)
8104 return sLresultFromObject(riid,wParam,pAcc);
8107 return 0;
8109 #endif
8111 /**************************************************************
8112 **************************************************************
8114 ** BLOCK: Transparency
8116 ** Window transparency helpers.
8118 **************************************************************
8119 **************************************************************/
8121 #ifdef MOZ_XUL
8123 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force)
8125 if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
8126 return;
8128 #ifdef CAIRO_HAS_D2D_SURFACE
8129 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
8130 gfxWindowsPlatform::RENDER_DIRECT2D) {
8131 nsRefPtr<gfxD2DSurface> newSurface =
8132 new gfxD2DSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
8133 mTransparentSurface = newSurface;
8134 mMemoryDC = nsnull;
8135 } else
8136 #endif
8138 nsRefPtr<gfxWindowsSurface> newSurface =
8139 new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
8140 mTransparentSurface = newSurface;
8141 mMemoryDC = newSurface->GetDC();
8145 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
8147 #ifndef WINCE
8149 if (aMode == mTransparencyMode)
8150 return;
8152 // stop on dialogs and popups!
8153 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
8154 nsWindow* parent = GetNSWindowPtr(hWnd);
8156 if (!parent)
8158 NS_WARNING("Trying to use transparent chrome in an embedded context");
8159 return;
8162 if (parent != this) {
8163 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
8166 if (aMode == eTransparencyTransparent) {
8167 // If we're switching to the use of a transparent window, hide the chrome
8168 // on our parent.
8169 HideWindowChrome(PR_TRUE);
8170 } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) {
8171 // if we're switching out of transparent, re-enable our parent's chrome.
8172 HideWindowChrome(PR_FALSE);
8175 LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE),
8176 exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
8178 if (parent->mIsVisible)
8179 style |= WS_VISIBLE;
8180 if (parent->mSizeMode == nsSizeMode_Maximized)
8181 style |= WS_MAXIMIZE;
8182 else if (parent->mSizeMode == nsSizeMode_Minimized)
8183 style |= WS_MINIMIZE;
8185 if (aMode == eTransparencyTransparent)
8186 exStyle |= WS_EX_LAYERED;
8187 else
8188 exStyle &= ~WS_EX_LAYERED;
8190 VERIFY_WINDOW_STYLE(style);
8191 ::SetWindowLongPtrW(hWnd, GWL_STYLE, style);
8192 ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle);
8194 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
8195 if (HasGlass())
8196 memset(&mGlassMargins, 0, sizeof mGlassMargins);
8197 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
8198 mTransparencyMode = aMode;
8200 SetupTranslucentWindowMemoryBitmap(aMode);
8201 UpdateGlass();
8202 #endif // #ifndef WINCE
8205 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
8207 if (eTransparencyTransparent == aMode) {
8208 ResizeTranslucentWindow(mBounds.width, mBounds.height, PR_TRUE);
8209 } else {
8210 mTransparentSurface = nsnull;
8211 mMemoryDC = NULL;
8215 nsresult nsWindow::UpdateTranslucentWindow()
8217 #ifndef WINCE
8218 if (mBounds.IsEmpty())
8219 return NS_OK;
8221 ::GdiFlush();
8223 BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
8224 SIZE winSize = { mBounds.width, mBounds.height };
8225 POINT srcPos = { 0, 0 };
8226 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
8227 RECT winRect;
8228 ::GetWindowRect(hWnd, &winRect);
8230 #ifdef CAIRO_HAS_D2D_SURFACE
8231 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
8232 gfxWindowsPlatform::RENDER_DIRECT2D) {
8233 mMemoryDC = static_cast<gfxD2DSurface*>(mTransparentSurface.get())->
8234 GetDC(PR_TRUE);
8236 #endif
8237 // perform the alpha blend
8238 PRBool updateSuccesful =
8239 ::UpdateLayeredWindow(hWnd, NULL, (POINT*)&winRect, &winSize, mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA);
8241 #ifdef CAIRO_HAS_D2D_SURFACE
8242 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
8243 gfxWindowsPlatform::RENDER_DIRECT2D) {
8244 nsIntRect r(0, 0, 0, 0);
8245 static_cast<gfxD2DSurface*>(mTransparentSurface.get())->ReleaseDC(&r);
8247 #endif
8249 if (!updateSuccesful) {
8250 return NS_ERROR_FAILURE;
8252 #endif
8254 return NS_OK;
8257 #endif //MOZ_XUL
8259 /**************************************************************
8260 **************************************************************
8262 ** BLOCK: Popup rollup hooks
8264 ** Deals with CaptureRollup on popup windows.
8266 **************************************************************
8267 **************************************************************/
8269 #ifndef WINCE
8270 // Schedules a timer for a window, so we can rollup after processing the hook event
8271 void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId)
8273 // In some cases multiple hooks may be scheduled
8274 // so ignore any other requests once one timer is scheduled
8275 if (sHookTimerId == 0) {
8276 // Remember the window handle and the message ID to be used later
8277 sRollupMsgId = aMsgId;
8278 sRollupMsgWnd = aWnd;
8279 // Schedule native timer for doing the rollup after
8280 // this event is done being processed
8281 sHookTimerId = ::SetTimer(NULL, 0, 0, (TIMERPROC)HookTimerForPopups);
8282 NS_ASSERTION(sHookTimerId, "Timer couldn't be created.");
8286 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8287 int gLastMsgCode = 0;
8288 extern MSGFEventMsgInfo gMSGFEvents[];
8289 #endif
8291 // Process Menu messages, rollup when popup is clicked.
8292 LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam)
8294 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8295 if (sProcessHook) {
8296 MSG* pMsg = (MSG*)lParam;
8298 int inx = 0;
8299 while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != NULL) {
8300 inx++;
8302 if (code != gLastMsgCode) {
8303 if (gMSGFEvents[inx].mId == code) {
8304 #ifdef DEBUG
8305 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code, gMSGFEvents[inx].mStr, pMsg->hwnd);
8306 #endif
8307 } else {
8308 #ifdef DEBUG
8309 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code, gMSGFEvents[inx].mId, pMsg->hwnd);
8310 #endif
8312 gLastMsgCode = code;
8314 PrintEvent(pMsg->message, FALSE, FALSE);
8316 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8318 if (sProcessHook && code == MSGF_MENU) {
8319 MSG* pMsg = (MSG*)lParam;
8320 ScheduleHookTimer( pMsg->hwnd, pMsg->message);
8323 return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
8326 // Process all mouse messages. Roll up when a click is in a native window
8327 // that doesn't have an nsIWidget.
8328 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
8330 if (sProcessHook) {
8331 switch (wParam) {
8332 case WM_LBUTTONDOWN:
8333 case WM_RBUTTONDOWN:
8334 case WM_MBUTTONDOWN:
8335 case WM_MOUSEWHEEL:
8336 case WM_MOUSEHWHEEL:
8338 MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
8339 nsIWidget* mozWin = (nsIWidget*)GetNSWindowPtr(ms->hwnd);
8340 if (mozWin) {
8341 // If this window is windowed plugin window, the mouse events are not
8342 // sent to us.
8343 if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin)
8344 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
8345 } else {
8346 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
8348 break;
8352 return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam);
8355 // Process all messages. Roll up when the window is moving, or
8356 // is resizing or when maximized or mininized.
8357 LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam)
8359 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8360 if (sProcessHook) {
8361 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
8362 PrintEvent(cwpt->message, FALSE, FALSE);
8364 #endif
8366 if (sProcessHook) {
8367 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
8368 if (cwpt->message == WM_MOVING ||
8369 cwpt->message == WM_SIZING ||
8370 cwpt->message == WM_GETMINMAXINFO) {
8371 ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message);
8375 return ::CallNextHookEx(sCallProcHook, code, wParam, lParam);
8378 // Register the special "hooks" for dropdown processing.
8379 void nsWindow::RegisterSpecialDropdownHooks()
8381 NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!");
8382 NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!");
8384 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
8386 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
8388 // Install msg hook for moving the window and resizing
8389 if (!sMsgFilterHook) {
8390 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
8391 sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, NULL, GetCurrentThreadId());
8392 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8393 if (!sMsgFilterHook) {
8394 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
8396 #endif
8399 // Install msg hook for menus
8400 if (!sCallProcHook) {
8401 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
8402 sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, NULL, GetCurrentThreadId());
8403 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8404 if (!sCallProcHook) {
8405 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
8407 #endif
8410 // Install msg hook for the mouse
8411 if (!sCallMouseHook) {
8412 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
8413 sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, NULL, GetCurrentThreadId());
8414 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
8415 if (!sCallMouseHook) {
8416 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
8418 #endif
8422 // Unhook special message hooks for dropdowns.
8423 void nsWindow::UnregisterSpecialDropdownHooks()
8425 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
8427 if (sCallProcHook) {
8428 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
8429 if (!::UnhookWindowsHookEx(sCallProcHook)) {
8430 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
8432 sCallProcHook = NULL;
8435 if (sMsgFilterHook) {
8436 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
8437 if (!::UnhookWindowsHookEx(sMsgFilterHook)) {
8438 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
8440 sMsgFilterHook = NULL;
8443 if (sCallMouseHook) {
8444 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
8445 if (!::UnhookWindowsHookEx(sCallMouseHook)) {
8446 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
8448 sCallMouseHook = NULL;
8452 // This timer is designed to only fire one time at most each time a "hook" function
8453 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
8454 // hook, but that hook event or a subsequent event may roll up the dropdown before
8455 // this timer function is executed.
8457 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
8458 // before this function fires.
8459 VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
8461 if (sHookTimerId != 0) {
8462 // if the window is NULL then we need to use the ID to kill the timer
8463 BOOL status = ::KillTimer(NULL, sHookTimerId);
8464 NS_ASSERTION(status, "Hook Timer was not killed.");
8465 sHookTimerId = 0;
8468 if (sRollupMsgId != 0) {
8469 // Note: DealWithPopups does the check to make sure that
8470 // sRollupListener and sRollupWidget are not NULL
8471 LRESULT popupHandlingResult;
8472 nsAutoRollup autoRollup;
8473 DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
8474 sRollupMsgId = 0;
8475 sRollupMsgWnd = NULL;
8478 #endif // WinCE
8480 BOOL CALLBACK nsWindow::ClearResourcesCallback(HWND aWnd, LPARAM aMsg)
8482 nsWindow *window = nsWindow::GetNSWindowPtr(aWnd);
8483 if (window) {
8484 window->ClearCachedResources();
8486 return TRUE;
8489 void
8490 nsWindow::ClearCachedResources()
8492 #ifdef CAIRO_HAS_D2D_SURFACE
8493 mD2DWindowSurface = nsnull;
8494 #endif
8495 if (mLayerManager &&
8496 mLayerManager->GetBackendType() == LayerManager::LAYERS_BASIC) {
8497 static_cast<BasicLayerManager*>(mLayerManager.get())->
8498 ClearCachedResources();
8500 ::EnumChildWindows(mWnd, nsWindow::ClearResourcesCallback, 0);
8503 static PRBool IsDifferentThreadWindow(HWND aWnd)
8505 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, NULL);
8508 PRBool
8509 nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
8511 RECT r;
8513 #ifndef WINCE
8514 if (Msg == WM_ACTIVATEAPP)
8515 // don't care about activation/deactivation
8516 return PR_FALSE;
8517 #else
8518 if (Msg == WM_ACTIVATE)
8519 // but on Windows CE we do care about
8520 // activation/deactivation because there doesn't exist
8521 // cancelable Mouse Activation events
8522 return PR_TRUE;
8523 #endif
8525 ::GetWindowRect(aWindow->mWnd, &r);
8526 DWORD pos = ::GetMessagePos();
8527 POINT mp;
8528 mp.x = GET_X_LPARAM(pos);
8529 mp.y = GET_Y_LPARAM(pos);
8531 // was the event inside this window?
8532 return (PRBool) PtInRect(&r, mp);
8535 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8536 BOOL
8537 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
8539 if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
8541 if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
8542 inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
8543 (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam))
8544 #ifndef WINCE
8546 inMsg == WM_NCRBUTTONDOWN ||
8547 inMsg == WM_MOVING ||
8548 inMsg == WM_SIZING ||
8549 inMsg == WM_NCLBUTTONDOWN ||
8550 inMsg == WM_NCMBUTTONDOWN ||
8551 inMsg == WM_MOUSEACTIVATE ||
8552 inMsg == WM_ACTIVATEAPP ||
8553 inMsg == WM_MENUSELECT
8554 #endif
8557 // Rollup if the event is outside the popup.
8558 PRBool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)sRollupWidget);
8560 if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL))
8562 sRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
8563 *outResult = PR_TRUE;
8566 // If we're dealing with menus, we probably have submenus and we don't
8567 // want to rollup if the click is in a parent menu of the current submenu.
8568 PRUint32 popupsToRollup = PR_UINT32_MAX;
8569 if (rollup) {
8570 if ( sMenuRollup ) {
8571 nsAutoTArray<nsIWidget*, 5> widgetChain;
8572 PRUint32 sameTypeCount = sMenuRollup->GetSubmenuWidgetChain(&widgetChain);
8573 for ( PRUint32 i = 0; i < widgetChain.Length(); ++i ) {
8574 nsIWidget* widget = widgetChain[i];
8575 if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
8576 // don't roll up if the mouse event occurred within a menu of the
8577 // same type. If the mouse event occurred in a menu higher than
8578 // that, roll up, but pass the number of popups to Rollup so
8579 // that only those of the same type close up.
8580 if (i < sameTypeCount) {
8581 rollup = PR_FALSE;
8583 else {
8584 popupsToRollup = sameTypeCount;
8586 break;
8588 } // foreach parent menu widget
8589 } // if rollup listener knows about menus
8592 #ifndef WINCE
8593 if (inMsg == WM_MOUSEACTIVATE && popupsToRollup == PR_UINT32_MAX) {
8594 // Prevent the click inside the popup from causing a change in window
8595 // activation. Since the popup is shown non-activated, we need to eat
8596 // any requests to activate the window while it is displayed. Windows
8597 // will automatically activate the popup on the mousedown otherwise.
8598 if (!rollup) {
8599 *outResult = MA_NOACTIVATE;
8600 return TRUE;
8602 else
8604 UINT uMsg = HIWORD(inLParam);
8605 if (uMsg == WM_MOUSEMOVE)
8607 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8608 // must be enabled in Windows.
8609 sRollupListener->ShouldRollupOnMouseActivate(&rollup);
8610 if (!rollup)
8612 *outResult = MA_NOACTIVATE;
8613 return true;
8618 // if we've still determined that we should still rollup everything, do it.
8619 else
8620 #endif
8621 if ( rollup ) {
8622 // sRollupConsumeEvent may be modified by
8623 // nsIRollupListener::Rollup.
8624 PRBool consumeRollupEvent = sRollupConsumeEvent;
8625 // only need to deal with the last rollup for left mouse down events.
8626 sRollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN ? &mLastRollup : nsnull);
8628 // Tell hook to stop processing messages
8629 sProcessHook = PR_FALSE;
8630 sRollupMsgId = 0;
8631 sRollupMsgWnd = NULL;
8633 // return TRUE tells Windows that the event is consumed,
8634 // false allows the event to be dispatched
8636 // So if we are NOT supposed to be consuming events, let it go through
8637 if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
8638 *outResult = MA_ACTIVATE;
8640 // However, don't activate panels
8641 #ifndef WINCE
8642 if (inMsg == WM_MOUSEACTIVATE) {
8643 nsWindow* activateWindow = GetNSWindowPtr(inWnd);
8644 if (activateWindow) {
8645 nsWindowType wintype;
8646 activateWindow->GetWindowType(wintype);
8647 if (wintype == eWindowType_popup && activateWindow->PopupType() == ePopupTypePanel) {
8648 *outResult = MA_NOACTIVATE;
8652 #endif
8654 return TRUE;
8656 #ifndef WINCE
8657 // if we are only rolling up some popups, don't activate and don't let
8658 // the event go through. This prevents clicks menus higher in the
8659 // chain from opening when a context menu is open
8660 if (popupsToRollup != PR_UINT32_MAX && inMsg == WM_MOUSEACTIVATE) {
8661 *outResult = MA_NOACTIVATEANDEAT;
8662 return TRUE;
8664 #endif
8666 } // if event that might trigger a popup to rollup
8667 } // if rollup listeners registered
8669 return FALSE;
8672 /**************************************************************
8673 **************************************************************
8675 ** BLOCK: Misc. utility methods and functions.
8677 ** General use.
8679 **************************************************************
8680 **************************************************************/
8682 // nsModifierKeyState used in various character processing.
8683 nsModifierKeyState::nsModifierKeyState()
8685 mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT);
8686 mIsControlDown = IS_VK_DOWN(NS_VK_CONTROL);
8687 mIsAltDown = IS_VK_DOWN(NS_VK_ALT);
8691 PRInt32 nsWindow::GetWindowsVersion()
8693 #ifdef WINCE
8694 return 0x500;
8695 #else
8696 static PRInt32 version = 0;
8697 static PRBool didCheck = PR_FALSE;
8699 if (!didCheck)
8701 didCheck = PR_TRUE;
8702 OSVERSIONINFOEX osInfo;
8703 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
8704 // This cast is safe and supposed to be here, don't worry
8705 ::GetVersionEx((OSVERSIONINFO*)&osInfo);
8706 version = (osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
8708 return version;
8709 #endif
8712 // Note that the result of GetTopLevelWindow method can be different from the
8713 // result of GetTopLevelHWND method. The result can be non-floating window.
8714 // Because our top level window may be contained in another window which is
8715 // not managed by us.
8716 nsWindow* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup)
8718 nsWindow* curWindow = this;
8720 while (PR_TRUE) {
8721 if (aStopOnDialogOrPopup) {
8722 switch (curWindow->mWindowType) {
8723 case eWindowType_dialog:
8724 case eWindowType_popup:
8725 return curWindow;
8726 default:
8727 break;
8731 // Retrieve the top level parent or owner window
8732 nsWindow* parentWindow = curWindow->GetParentWindow(PR_TRUE);
8734 if (!parentWindow)
8735 return curWindow;
8737 curWindow = parentWindow;
8741 // Note that the result of GetTopLevelHWND can be different from the result
8742 // of GetTopLevelWindow method. Because this is checking whether the window
8743 // is top level only in Win32 window system. Therefore, the result window
8744 // may not be managed by us.
8745 HWND nsWindow::GetTopLevelHWND(HWND aWnd, PRBool aStopOnDialogOrPopup)
8747 HWND curWnd = aWnd;
8748 HWND topWnd = NULL;
8749 HWND upWnd = NULL;
8751 while (curWnd) {
8752 topWnd = curWnd;
8754 if (aStopOnDialogOrPopup) {
8755 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8757 VERIFY_WINDOW_STYLE(style);
8759 if (!(style & WS_CHILD)) // first top-level window
8760 break;
8763 upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
8765 #ifdef WINCE
8766 // For dialog windows, we want just the parent, not the owner.
8767 // For other/popup windows, we want to find the first owner/parent
8768 // that's a dialog and/or has an owner.
8769 if (upWnd && ::GetWindow(curWnd, GW_OWNER) == upWnd) {
8770 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8771 if ((style & WS_DLGFRAME) != 0)
8772 break;
8774 #endif
8776 curWnd = upWnd;
8779 return topWnd;
8782 static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam)
8784 DWORD pid;
8785 ::GetWindowThreadProcessId(hwnd, &pid);
8786 if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd))
8788 gWindowsVisible = PR_TRUE;
8789 return FALSE;
8791 return TRUE;
8794 PRBool nsWindow::CanTakeFocus()
8796 gWindowsVisible = PR_FALSE;
8797 EnumWindows(gEnumWindowsProc, 0);
8798 if (!gWindowsVisible) {
8799 return PR_TRUE;
8800 } else {
8801 HWND fgWnd = ::GetForegroundWindow();
8802 if (!fgWnd) {
8803 return PR_TRUE;
8805 DWORD pid;
8806 GetWindowThreadProcessId(fgWnd, &pid);
8807 if (pid == GetCurrentProcessId()) {
8808 return PR_TRUE;
8811 return PR_FALSE;
8814 void nsWindow::GetMainWindowClass(nsAString& aClass)
8816 nsresult rv;
8817 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8818 if (NS_SUCCEEDED(rv) && prefs) {
8819 nsXPIDLCString name;
8820 rv = prefs->GetCharPref("ui.window_class_override", getter_Copies(name));
8821 if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
8822 aClass.AssignASCII(name.get());
8823 return;
8826 aClass.AssignASCII(sDefaultMainWindowClass);
8829 PRBool nsWindow::UseTrackPointHack()
8831 nsresult rv;
8832 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8833 if (NS_SUCCEEDED(rv) && prefs) {
8834 PRInt32 lHackValue;
8835 rv = prefs->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue);
8836 if (NS_SUCCEEDED(rv)) {
8837 switch (lHackValue) {
8838 case 0: // disabled
8839 return PR_FALSE;
8840 case 1: // enabled
8841 return PR_TRUE;
8842 default: // -1: autodetect
8843 break;
8847 return sDefaultTrackPointHack;
8850 #if !defined(WINCE)
8851 static PRBool
8852 HasRegistryKey(HKEY aRoot, LPCWSTR aName)
8854 HKEY key;
8855 LONG result = ::RegOpenKeyExW(aRoot, aName, 0, KEY_READ, &key);
8856 if (result != ERROR_SUCCESS)
8857 return PR_FALSE;
8858 ::RegCloseKey(key);
8859 return PR_TRUE;
8862 static PRBool
8863 IsObsoleteSynapticsDriver()
8865 HKEY key;
8866 LONG result = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE,
8867 L"Software\\Synaptics\\SynTP\\Install", 0, KEY_READ, &key);
8868 if (result != ERROR_SUCCESS)
8869 return PR_FALSE;
8870 DWORD type;
8871 PRUnichar buf[40];
8872 DWORD buflen = sizeof(buf);
8873 result = ::RegQueryValueExW(key, L"DriverVersion", NULL, &type, (BYTE*)buf, &buflen);
8874 ::RegCloseKey(key);
8875 if (result != ERROR_SUCCESS || type != REG_SZ)
8876 return PR_FALSE;
8877 buf[NS_ARRAY_LENGTH(buf) - 1] = 0;
8879 int majorVersion = wcstol(buf, NULL, 10);
8880 return majorVersion < 15;
8883 void nsWindow::InitInputHackDefaults()
8885 if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Lenovo\\TrackPoint")) {
8886 sDefaultTrackPointHack = PR_TRUE;
8887 } else if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Lenovo\\UltraNav")) {
8888 sDefaultTrackPointHack = PR_TRUE;
8889 } else if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Alps\\Apoint\\TrackPoint")) {
8890 sDefaultTrackPointHack = PR_TRUE;
8891 } else if ((HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB") ||
8892 HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2")) &&
8893 IsObsoleteSynapticsDriver()) {
8894 sDefaultTrackPointHack = PR_TRUE;
8897 #endif // #if !defined(WINCE)
8899 LPARAM nsWindow::lParamToScreen(LPARAM lParam)
8901 POINT pt;
8902 pt.x = GET_X_LPARAM(lParam);
8903 pt.y = GET_Y_LPARAM(lParam);
8904 ::ClientToScreen(mWnd, &pt);
8905 return MAKELPARAM(pt.x, pt.y);
8908 LPARAM nsWindow::lParamToClient(LPARAM lParam)
8910 POINT pt;
8911 pt.x = GET_X_LPARAM(lParam);
8912 pt.y = GET_Y_LPARAM(lParam);
8913 ::ScreenToClient(mWnd, &pt);
8914 return MAKELPARAM(pt.x, pt.y);
8917 /**************************************************************
8918 **************************************************************
8920 ** BLOCK: ChildWindow impl.
8922 ** Child window overrides.
8924 **************************************************************
8925 **************************************************************/
8927 // return the style for a child nsWindow
8928 DWORD ChildWindow::WindowStyle()
8930 DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle();
8931 if (!(style & WS_POPUP))
8932 style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
8933 VERIFY_WINDOW_STYLE(style);
8934 return style;