merge backout. a=backout
[mozilla-central.git] / widget / src / windows / nsWindow.cpp
blob9c833c99b0098db86be166824e1be529b0982ce7
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sts=2 sw=2 et cin: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Dean Tessman <dean_tessman@hotmail.com>
25 * Ere Maijala <emaijala@kolumbus.fi>
26 * Mark Hammond <markh@activestate.com>
27 * Michael Lowe <michael.lowe@bigfoot.com>
28 * Peter Bajusz <hyp-x@inf.bme.hu>
29 * Pierre Phaneuf <pp@ludusdesign.com>
30 * Robert O'Callahan <roc+moz@cs.cmu.edu>
31 * Roy Yokoyama <yokoyama@netscape.com>
32 * Makoto Kato <m_kato@ga2.so-net.ne.jp>
33 * Masayuki Nakano <masayuki@d-toybox.com>
34 * Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
35 * Christian Biesinger <cbiesinger@web.de>
36 * Mats Palmgren <matspal@gmail.com>
37 * Ningjie Chen <chenn@email.uc.edu>
38 * Jim Mathies <jmathies@mozilla.com>
39 * Kyle Huey <me@kylehuey.com>
41 * Alternatively, the contents of this file may be used under the terms of
42 * either the GNU General Public License Version 2 or later (the "GPL"), or
43 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
44 * in which case the provisions of the GPL or the LGPL are applicable instead
45 * of those above. If you wish to allow use of your version of this file only
46 * under the terms of either the GPL or the LGPL, and not to allow others to
47 * use your version of this file under the terms of the MPL, indicate your
48 * decision by deleting the provisions above and replace them with the notice
49 * and other provisions required by the GPL or the LGPL. If you do not delete
50 * the provisions above, a recipient may use your version of this file under
51 * the terms of any one of the MPL, the GPL or the LGPL.
53 * ***** END LICENSE BLOCK ***** */
56 * nsWindow - Native window management and event handling.
58 * nsWindow is organized into a set of major blocks and
59 * block subsections. The layout is as follows:
61 * Includes
62 * Variables
63 * nsIWidget impl.
64 * nsIWidget methods and utilities
65 * nsSwitchToUIThread impl.
66 * nsSwitchToUIThread methods and utilities
67 * Moz events
68 * Event initialization
69 * Event dispatching
70 * Native events
71 * Wndproc(s)
72 * Event processing
73 * OnEvent event handlers
74 * IME management and accessibility
75 * Transparency
76 * Popup hook handling
77 * Misc. utilities
78 * Child window impl.
80 * Search for "BLOCK:" to find major blocks.
81 * Search for "SECTION:" to find specific sections.
83 * Blocks should be split out into separate files if they
84 * become unmanageable.
86 * Related source:
88 * nsWindowDefs.h - Definitions, macros, structs, enums
89 * and general setup.
90 * nsWindowDbg.h/.cpp - Debug related code and directives.
91 * nsWindowGfx.h/.cpp - Graphics and painting.
92 * nsWindowCE.h/.cpp - WINCE specific code that can be
93 * split out from nsWindow.
97 /**************************************************************
98 **************************************************************
100 ** BLOCK: Includes
102 ** Include headers.
104 **************************************************************
105 **************************************************************/
107 #ifdef MOZ_IPC
108 #include "mozilla/ipc/RPCChannel.h"
109 #endif
111 #include "nsWindow.h"
113 #include <windows.h>
114 #include <process.h>
115 #include <commctrl.h>
116 #include <unknwn.h>
118 #include "prlog.h"
119 #include "prtime.h"
120 #include "prprf.h"
121 #include "prmem.h"
123 #include "nsIAppShell.h"
124 #include "nsISupportsPrimitives.h"
125 #include "nsIDOMNSUIEvent.h"
126 #include "nsITheme.h"
127 #include "nsIPrefBranch.h"
128 #include "nsIPrefBranch2.h"
129 #include "nsIPrefService.h"
130 #include "nsIObserverService.h"
131 #include "nsIScreenManager.h"
132 #include "imgIContainer.h"
133 #include "nsIFile.h"
134 #include "nsIRollupListener.h"
135 #include "nsIMenuRollup.h"
136 #include "nsIRegion.h"
137 #include "nsIServiceManager.h"
138 #include "nsIClipboard.h"
139 #include "nsIMM32Handler.h"
140 #include "nsILocalFile.h"
141 #include "nsIFontMetrics.h"
142 #include "nsIFontEnumerator.h"
143 #include "nsIDeviceContext.h"
144 #include "nsILookAndFeel.h"
145 #include "nsGUIEvent.h"
146 #include "nsFont.h"
147 #include "nsRect.h"
148 #include "nsThreadUtils.h"
149 #include "nsNativeCharsetUtils.h"
150 #include "nsWidgetAtoms.h"
151 #include "nsUnicharUtils.h"
152 #include "nsCRT.h"
153 #include "nsAppDirectoryServiceDefs.h"
154 #include "nsXPIDLString.h"
155 #include "nsWidgetsCID.h"
156 #include "nsTHashtable.h"
157 #include "nsHashKeys.h"
158 #include "nsString.h"
159 #include "mozilla/Services.h"
160 #include "nsNativeThemeWin.h"
162 #if defined(WINCE)
163 #include "nsWindowCE.h"
164 #endif
166 #if defined(WINCE_WINDOWS_MOBILE)
167 #define KILL_PRIORITY_ID 2444
168 #endif
170 #include "nsWindowGfx.h"
171 #include "gfxWindowsPlatform.h"
172 #include "Layers.h"
173 #ifndef WINCE
174 #ifdef MOZ_ENABLE_D3D9_LAYER
175 #include "LayerManagerD3D9.h"
176 #endif
177 #include "LayerManagerOGL.h"
178 #endif
179 #include "BasicLayers.h"
181 #if !defined(WINCE)
182 #include "nsUXThemeConstants.h"
183 #include "KeyboardLayout.h"
184 #include "nsNativeDragTarget.h"
185 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
186 #include <zmouse.h>
187 #include <pbt.h>
188 #include <richedit.h>
189 #endif // !defined(WINCE)
191 #if defined(ACCESSIBILITY)
192 #include "oleidl.h"
193 #include <winuser.h>
194 #include "nsIAccessibleDocument.h"
195 #if !defined(WINABLEAPI)
196 #include <winable.h>
197 #endif // !defined(WINABLEAPI)
198 #endif // defined(ACCESSIBILITY)
200 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
201 #include "nsIWinTaskbar.h"
202 #endif
204 #if defined(NS_ENABLE_TSF)
205 #include "nsTextStore.h"
206 #endif // defined(NS_ENABLE_TSF)
208 #if defined(MOZ_SPLASHSCREEN)
209 #include "nsSplashScreen.h"
210 #endif // defined(MOZ_SPLASHSCREEN)
212 // Windowless plugin support
213 #include "npapi.h"
215 #include "nsWindowDefs.h"
217 #include "mozilla/FunctionTimer.h"
219 #ifdef WINCE_WINDOWS_MOBILE
220 #include "nsGfxCIID.h"
221 #endif
223 #include "mozilla/FunctionTimer.h"
225 #ifdef MOZ_CRASHREPORTER
226 #include "nsICrashReporter.h"
227 #endif
229 #include "nsIXULRuntime.h"
231 using namespace mozilla::widget;
233 /**************************************************************
234 **************************************************************
236 ** BLOCK: Variables
238 ** nsWindow Class static initializations and global variables.
240 **************************************************************
241 **************************************************************/
243 /**************************************************************
245 * SECTION: nsWindow statics
247 **************************************************************/
249 PRUint32 nsWindow::sInstanceCount = 0;
250 PRBool nsWindow::sSwitchKeyboardLayout = PR_FALSE;
251 BOOL nsWindow::sIsRegistered = FALSE;
252 BOOL nsWindow::sIsPopupClassRegistered = FALSE;
253 BOOL nsWindow::sIsOleInitialized = FALSE;
254 HCURSOR nsWindow::sHCursor = NULL;
255 imgIContainer* nsWindow::sCursorImgContainer = nsnull;
256 nsWindow* nsWindow::sCurrentWindow = nsnull;
257 PRBool nsWindow::sJustGotDeactivate = PR_FALSE;
258 PRBool nsWindow::sJustGotActivate = PR_FALSE;
260 // imported in nsWidgetFactory.cpp
261 TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN;
263 // Hook Data Memebers for Dropdowns. sProcessHook Tells the
264 // hook methods whether they should be processing the hook
265 // messages.
266 HHOOK nsWindow::sMsgFilterHook = NULL;
267 HHOOK nsWindow::sCallProcHook = NULL;
268 HHOOK nsWindow::sCallMouseHook = NULL;
269 PRPackedBool nsWindow::sProcessHook = PR_FALSE;
270 UINT nsWindow::sRollupMsgId = 0;
271 HWND nsWindow::sRollupMsgWnd = NULL;
272 UINT nsWindow::sHookTimerId = 0;
274 // Rollup Listener
275 nsIRollupListener* nsWindow::sRollupListener = nsnull;
276 nsIMenuRollup* nsWindow::sMenuRollup = nsnull;
277 nsIWidget* nsWindow::sRollupWidget = nsnull;
278 PRBool nsWindow::sRollupConsumeEvent = PR_FALSE;
280 // Mouse Clicks - static variable definitions for figuring
281 // out 1 - 3 Clicks.
282 POINT nsWindow::sLastMousePoint = {0};
283 POINT nsWindow::sLastMouseMovePoint = {0};
284 LONG nsWindow::sLastMouseDownTime = 0L;
285 LONG nsWindow::sLastClickCount = 0L;
286 BYTE nsWindow::sLastMouseButton = 0;
288 // Trim heap on minimize. (initialized, but still true.)
289 int nsWindow::sTrimOnMinimize = 2;
291 // Default Trackpoint Hack to off
292 PRBool nsWindow::sTrackPointHack = PR_FALSE;
294 #ifdef ACCESSIBILITY
295 BOOL nsWindow::sIsAccessibilityOn = FALSE;
296 // Accessibility wm_getobject handler
297 HINSTANCE nsWindow::sAccLib = 0;
298 LPFNLRESULTFROMOBJECT
299 nsWindow::sLresultFromObject = 0;
300 #endif // ACCESSIBILITY
302 #ifdef MOZ_IPC
303 // Used in OOPP plugin focus processing.
304 const PRUnichar* kOOPPPluginFocusEventId = L"OOPP Plugin Focus Widget Event";
305 PRUint32 nsWindow::sOOPPPluginFocusEvent =
306 RegisterWindowMessageW(kOOPPPluginFocusEventId);
307 #endif
309 /**************************************************************
311 * SECTION: globals variables
313 **************************************************************/
315 static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
317 #ifdef PR_LOGGING
318 PRLogModuleInfo* gWindowsLog = nsnull;
319 #endif
321 #ifndef WINCE
322 // Kbd layout. Used throughout character processing.
323 static KeyboardLayout gKbdLayout;
324 #endif
326 #ifdef WINCE_WINDOWS_MOBILE
327 // HTC Navigation Wheel Event
328 // This is the defined value for Gesture Mode
329 const int WM_HTCNAV = 0x0400 + 200;
331 typedef int (__stdcall * HTCApiNavOpen)(HANDLE, int);
332 typedef int (__stdcall * HTCApiNavSetMode)(HANDLE, unsigned int);
334 HTCApiNavOpen gHTCApiNavOpen = nsnull;
335 HTCApiNavSetMode gHTCApiNavSetMode = nsnull;
336 static PRBool gCheckForHTCApi = PR_FALSE;
337 #endif
339 // Global user preference for disabling native theme. Used
340 // in NativeWindowTheme.
341 PRBool gDisableNativeTheme = PR_FALSE;
343 // Global used in Show window enumerations.
344 static PRBool gWindowsVisible = PR_FALSE;
346 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
347 #ifdef WINCE_WINDOWS_MOBILE
348 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
349 #endif
351 /**************************************************************
352 **************************************************************
354 ** BLOCK: nsIWidget impl.
356 ** nsIWidget interface implementation, broken down into
357 ** sections.
359 **************************************************************
360 **************************************************************/
362 /**************************************************************
364 * SECTION: nsWindow construction and destruction
366 **************************************************************/
368 nsWindow::nsWindow() : nsBaseWidget()
370 #ifdef PR_LOGGING
371 if (!gWindowsLog)
372 gWindowsLog = PR_NewLogModule("nsWindowsWidgets");
373 #endif
375 mWnd = nsnull;
376 mPaintDC = nsnull;
377 mPrevWndProc = nsnull;
378 mOldIMC = nsnull;
379 mNativeDragTarget = nsnull;
380 mInDtor = PR_FALSE;
381 mIsVisible = PR_FALSE;
382 mIsInMouseCapture = PR_FALSE;
383 mIsTopWidgetWindow = PR_FALSE;
384 mUnicodeWidget = PR_TRUE;
385 mDisplayPanFeedback = PR_FALSE;
386 mTouchWindow = PR_FALSE;
387 mCustomNonClient = PR_FALSE;
388 mHideChrome = PR_FALSE;
389 mFullscreenMode = PR_FALSE;
390 mWindowType = eWindowType_child;
391 mBorderStyle = eBorderStyle_default;
392 mPopupType = ePopupTypeAny;
393 mOldSizeMode = nsSizeMode_Normal;
394 mLastPoint.x = 0;
395 mLastPoint.y = 0;
396 mLastSize.width = 0;
397 mLastSize.height = 0;
398 mOldStyle = 0;
399 mOldExStyle = 0;
400 mPainting = 0;
401 mExitToNonClientArea = 0;
402 mLastKeyboardLayout = 0;
403 mBlurSuppressLevel = 0;
404 mIMEEnabled = nsIWidget::IME_STATUS_ENABLED;
405 #ifdef MOZ_XUL
406 mTransparentSurface = nsnull;
407 mMemoryDC = nsnull;
408 mTransparencyMode = eTransparencyOpaque;
409 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
410 memset(&mGlassMargins, 0, sizeof mGlassMargins);
411 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
412 #endif
413 mBackground = ::GetSysColor(COLOR_BTNFACE);
414 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
415 mForeground = ::GetSysColor(COLOR_WINDOWTEXT);
417 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
418 mTaskbarPreview = nsnull;
419 mHasTaskbarIconBeenCreated = PR_FALSE;
420 #endif
422 // Global initialization
423 if (!sInstanceCount) {
424 #if !defined(WINCE)
425 gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
426 #endif
428 // Init IME handler
429 nsIMM32Handler::Initialize();
431 #ifdef NS_ENABLE_TSF
432 nsTextStore::Initialize();
433 #endif
435 #if !defined(WINCE)
436 if (SUCCEEDED(::OleInitialize(NULL)))
437 sIsOleInitialized = TRUE;
438 NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
439 #endif
441 #if !defined(WINCE)
442 InitTrackPointHack();
443 #endif
445 // Init titlebar button info for custom frames.
446 nsUXThemeData::InitTitlebarInfo();
447 } // !sInstanceCount
449 mIdleService = nsnull;
451 sInstanceCount++;
454 nsWindow::~nsWindow()
456 mInDtor = PR_TRUE;
458 // If the widget was released without calling Destroy() then the native window still
459 // exists, and we need to destroy it. This will also result in a call to OnDestroy.
461 // XXX How could this happen???
462 if (NULL != mWnd)
463 Destroy();
465 sInstanceCount--;
467 // Global shutdown
468 if (sInstanceCount == 0) {
469 #ifdef NS_ENABLE_TSF
470 nsTextStore::Terminate();
471 #endif
473 #if !defined(WINCE)
474 NS_IF_RELEASE(sCursorImgContainer);
475 if (sIsOleInitialized) {
476 ::OleFlushClipboard();
477 ::OleUninitialize();
478 sIsOleInitialized = FALSE;
480 // delete any of the IME structures that we allocated
481 nsIMM32Handler::Terminate();
482 #endif // !defined(WINCE)
485 #if !defined(WINCE)
486 NS_IF_RELEASE(mNativeDragTarget);
487 #endif // !defined(WINCE)
490 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
492 /**************************************************************
494 * SECTION: nsIWidget::Create, nsIWidget::Destroy
496 * Creating and destroying windows for this widget.
498 **************************************************************/
500 // Allow Derived classes to modify the height that is passed
501 // when the window is created or resized. Also add extra height
502 // if needed (on Windows CE)
503 PRInt32 nsWindow::GetHeight(PRInt32 aProposedHeight)
505 PRInt32 extra = 0;
507 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
508 DWORD style = WindowStyle();
509 if ((style & WS_SYSMENU) && (style & WS_POPUP)) {
510 extra = GetSystemMetrics(SM_CYCAPTION);
512 #endif
514 return aProposedHeight + extra;
517 // Create the proper widget
518 nsresult
519 nsWindow::Create(nsIWidget *aParent,
520 nsNativeWidget aNativeParent,
521 const nsIntRect &aRect,
522 EVENT_CALLBACK aHandleEventFunction,
523 nsIDeviceContext *aContext,
524 nsIAppShell *aAppShell,
525 nsIToolkit *aToolkit,
526 nsWidgetInitData *aInitData)
528 nsWidgetInitData defaultInitData;
529 if (!aInitData)
530 aInitData = &defaultInitData;
532 mUnicodeWidget = aInitData->mUnicode;
534 nsIWidget *baseParent = aInitData->mWindowType == eWindowType_dialog ||
535 aInitData->mWindowType == eWindowType_toplevel ||
536 aInitData->mWindowType == eWindowType_invisible ?
537 nsnull : aParent;
539 mIsTopWidgetWindow = (nsnull == baseParent);
540 mBounds.width = aRect.width;
541 mBounds.height = aRect.height;
543 BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
544 aAppShell, aToolkit, aInitData);
546 HWND parent;
547 if (aParent) { // has a nsIWidget parent
548 parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : NULL;
549 mParent = aParent;
550 } else { // has a nsNative parent
551 parent = (HWND)aNativeParent;
552 mParent = aNativeParent ? GetNSWindowPtr((HWND)aNativeParent) : nsnull;
555 mPopupType = aInitData->mPopupHint;
556 mContentType = aInitData->mContentType;
557 mIsRTL = aInitData->mRTL;
559 DWORD style = WindowStyle();
560 DWORD extendedStyle = WindowExStyle();
562 if (mWindowType == eWindowType_popup) {
563 if (!aParent)
564 parent = NULL;
565 } else if (mWindowType == eWindowType_invisible) {
566 // Make sure CreateWindowEx succeeds at creating a toplevel window
567 style &= ~0x40000000; // WS_CHILDWINDOW
568 } else {
569 // See if the caller wants to explictly set clip children and clip siblings
570 if (aInitData->clipChildren) {
571 style |= WS_CLIPCHILDREN;
572 } else {
573 style &= ~WS_CLIPCHILDREN;
575 if (aInitData->clipSiblings) {
576 style |= WS_CLIPSIBLINGS;
580 mWnd = ::CreateWindowExW(extendedStyle,
581 aInitData->mDropShadow ?
582 WindowPopupClass() : WindowClass(),
583 L"",
584 style,
585 aRect.x,
586 aRect.y,
587 aRect.width,
588 GetHeight(aRect.height),
589 parent,
590 NULL,
591 nsToolkit::mDllInstance,
592 NULL);
594 if (!mWnd) {
595 NS_WARNING("nsWindow CreateWindowEx failed.");
596 return NS_ERROR_FAILURE;
599 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
600 if (mIsRTL && nsUXThemeData::dwmSetWindowAttributePtr) {
601 DWORD dwAttribute = TRUE;
602 nsUXThemeData::dwmSetWindowAttributePtr(mWnd, DWMWA_NONCLIENT_RTL_LAYOUT, &dwAttribute, sizeof dwAttribute);
604 #endif
606 if (nsWindow::sTrackPointHack &&
607 mWindowType != eWindowType_plugin &&
608 mWindowType != eWindowType_invisible) {
609 // Ugly Thinkpad Driver Hack (Bug 507222)
610 // We create an invisible scrollbar to trick the
611 // Trackpoint driver into sending us scrolling messages
612 ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTSCROLLBAR",
613 WS_CHILD | WS_VISIBLE, 0,0,0,0, mWnd, NULL,
614 nsToolkit::mDllInstance, NULL);
617 // call the event callback to notify about creation
619 DispatchStandardEvent(NS_CREATE);
620 SubclassWindow(TRUE);
622 if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
623 /* The internal variable set by the config.trim_on_minimize pref
624 has not yet been initialized, and this is the hidden window
625 (conveniently created before any visible windows, and after
626 the profile has been initialized).
628 Default config.trim_on_minimize to false, to fix bug 76831
629 for good. If anyone complains about this new default, saying
630 that a Mozilla app hogs too much memory while minimized, they
631 will have that entire bug tattooed on their backside. */
633 sTrimOnMinimize = 0;
634 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
635 if (prefs) {
636 nsCOMPtr<nsIPrefBranch> prefBranch;
637 prefs->GetBranch(0, getter_AddRefs(prefBranch));
638 if (prefBranch) {
640 PRBool temp;
641 if (NS_SUCCEEDED(prefBranch->GetBoolPref("config.trim_on_minimize",
642 &temp))
643 && temp)
644 sTrimOnMinimize = 1;
646 if (NS_SUCCEEDED(prefBranch->GetBoolPref("intl.keyboard.per_window_layout",
647 &temp)))
648 sSwitchKeyboardLayout = temp;
650 if (NS_SUCCEEDED(prefBranch->GetBoolPref("mozilla.widget.disable-native-theme",
651 &temp)))
652 gDisableNativeTheme = temp;
656 #if defined(WINCE_HAVE_SOFTKB)
657 if (mWindowType == eWindowType_dialog || mWindowType == eWindowType_toplevel )
658 nsWindowCE::CreateSoftKeyMenuBar(mWnd);
659 #endif
661 return NS_OK;
664 // Close this nsWindow
665 NS_METHOD nsWindow::Destroy()
667 // WM_DESTROY has already fired, we're done.
668 if (nsnull == mWnd)
669 return NS_OK;
671 // During the destruction of all of our children, make sure we don't get deleted.
672 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
675 * On windows the LayerManagerOGL destructor wants the widget to be around for
676 * cleanup. It also would like to have the HWND intact, so we NULL it here.
678 if (mLayerManager) {
679 mLayerManager->Destroy();
681 mLayerManager = nsnull;
683 /* We should clear our cached resources now and not wait for the GC to
684 * delete the nsWindow. */
685 ClearCachedResources();
687 // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
688 // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus
689 // from it. The function also destroys the window's menu, flushes the thread message queue,
690 // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if
691 // the window is at the top of the viewer chain).
693 // If the specified window is a parent or owner window, DestroyWindow automatically destroys
694 // the associated child or owned windows when it destroys the parent or owner window. The
695 // function first destroys child or owned windows, and then it destroys the parent or owner
696 // window.
697 VERIFY(::DestroyWindow(mWnd));
699 // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy()
700 // didn't get called, call it now.
701 if (PR_FALSE == mOnDestroyCalled)
702 OnDestroy();
704 return NS_OK;
707 /**************************************************************
709 * SECTION: Window class utilities
711 * Utilities for calculating the proper window class name for
712 * Create window.
714 **************************************************************/
716 // Return the proper window class for everything except popups.
717 LPCWSTR nsWindow::WindowClass()
719 if (!nsWindow::sIsRegistered) {
720 WNDCLASSW wc;
722 // wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
723 wc.style = CS_DBLCLKS;
724 wc.lpfnWndProc = ::DefWindowProcW;
725 wc.cbClsExtra = 0;
726 wc.cbWndExtra = 0;
727 wc.hInstance = nsToolkit::mDllInstance;
728 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
729 wc.hCursor = NULL;
730 wc.hbrBackground = mBrush;
731 wc.lpszMenuName = NULL;
732 wc.lpszClassName = kClassNameHidden;
734 BOOL succeeded = ::RegisterClassW(&wc) != 0 &&
735 ERROR_CLASS_ALREADY_EXISTS != GetLastError();
736 nsWindow::sIsRegistered = succeeded;
738 wc.lpszClassName = kClassNameContentFrame;
739 if (!::RegisterClassW(&wc) &&
740 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
741 nsWindow::sIsRegistered = FALSE;
744 wc.lpszClassName = kClassNameContent;
745 if (!::RegisterClassW(&wc) &&
746 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
747 nsWindow::sIsRegistered = FALSE;
750 wc.lpszClassName = kClassNameGeneral;
751 ATOM generalClassAtom = ::RegisterClassW(&wc);
752 if (!generalClassAtom &&
753 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
754 nsWindow::sIsRegistered = FALSE;
757 wc.lpszClassName = kClassNameDialog;
758 wc.hIcon = 0;
759 if (!::RegisterClassW(&wc) &&
760 ERROR_CLASS_ALREADY_EXISTS != GetLastError()) {
761 nsWindow::sIsRegistered = FALSE;
765 if (mWindowType == eWindowType_invisible) {
766 return kClassNameHidden;
768 if (mWindowType == eWindowType_dialog) {
769 return kClassNameDialog;
771 if (mContentType == eContentTypeContent) {
772 return kClassNameContent;
774 if (mContentType == eContentTypeContentFrame) {
775 return kClassNameContentFrame;
777 return kClassNameGeneral;
780 // Return the proper popup window class
781 LPCWSTR nsWindow::WindowPopupClass()
783 if (!nsWindow::sIsPopupClassRegistered) {
784 WNDCLASSW wc;
786 wc.style = CS_DBLCLKS | CS_XP_DROPSHADOW;
787 wc.lpfnWndProc = ::DefWindowProcW;
788 wc.cbClsExtra = 0;
789 wc.cbWndExtra = 0;
790 wc.hInstance = nsToolkit::mDllInstance;
791 wc.hIcon = ::LoadIconW(::GetModuleHandleW(NULL), (LPWSTR)IDI_APPLICATION);
792 wc.hCursor = NULL;
793 wc.hbrBackground = mBrush;
794 wc.lpszMenuName = NULL;
795 wc.lpszClassName = kClassNameDropShadow;
797 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
798 if (!nsWindow::sIsPopupClassRegistered) {
799 // For older versions of Win32 (i.e., not XP), the registration will
800 // fail, so we have to re-register without the CS_XP_DROPSHADOW flag.
801 wc.style = CS_DBLCLKS;
802 nsWindow::sIsPopupClassRegistered = ::RegisterClassW(&wc);
806 return kClassNameDropShadow;
809 /**************************************************************
811 * SECTION: Window styles utilities
813 * Return the proper windows styles and extended styles.
815 **************************************************************/
817 // Return nsWindow styles
818 #if !defined(WINCE) // implemented in nsWindowCE.cpp
819 DWORD nsWindow::WindowStyle()
821 DWORD style;
823 switch (mWindowType) {
824 case eWindowType_plugin:
825 case eWindowType_child:
826 style = WS_OVERLAPPED;
827 break;
829 case eWindowType_dialog:
830 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK |
831 DS_MODALFRAME | WS_CLIPCHILDREN;
832 if (mBorderStyle != eBorderStyle_default)
833 style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
834 break;
836 case eWindowType_popup:
837 style = WS_POPUP;
838 if (!HasGlass()) {
839 style |= WS_OVERLAPPED;
841 break;
843 default:
844 NS_ERROR("unknown border style");
845 // fall through
847 case eWindowType_toplevel:
848 case eWindowType_invisible:
849 style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU |
850 WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
851 break;
854 if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) {
855 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border))
856 style &= ~WS_BORDER;
858 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) {
859 style &= ~WS_DLGFRAME;
860 style |= WS_POPUP;
861 style &= ~WS_CHILD;
864 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close))
865 style &= ~0;
866 // XXX The close box can only be removed by changing the window class,
867 // as far as I know --- roc+moz@cs.cmu.edu
869 if (mBorderStyle == eBorderStyle_none ||
870 !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
871 style &= ~WS_SYSMENU;
872 // Looks like getting rid of the system menu also does away with the
873 // close box. So, we only get rid of the system menu if you want neither it
874 // nor the close box. How does the Windows "Dialog" window class get just
875 // closebox and no sysmenu? Who knows.
877 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh))
878 style &= ~WS_THICKFRAME;
880 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize))
881 style &= ~WS_MINIMIZEBOX;
883 if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize))
884 style &= ~WS_MAXIMIZEBOX;
886 if (IsPopupWithTitleBar()) {
887 style |= WS_CAPTION;
888 if (mBorderStyle & eBorderStyle_close) {
889 style |= WS_SYSMENU;
894 VERIFY_WINDOW_STYLE(style);
895 return style;
897 #endif // !defined(WINCE)
899 // Return nsWindow extended styles
900 DWORD nsWindow::WindowExStyle()
902 switch (mWindowType)
904 case eWindowType_plugin:
905 case eWindowType_child:
906 return 0;
908 case eWindowType_dialog:
909 return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
911 case eWindowType_popup:
913 DWORD extendedStyle =
914 #if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
915 WS_EX_NOACTIVATE |
916 #endif
917 WS_EX_TOOLWINDOW;
918 if (mPopupLevel == ePopupLevelTop)
919 extendedStyle |= WS_EX_TOPMOST;
920 return extendedStyle;
922 default:
923 NS_ERROR("unknown border style");
924 // fall through
926 case eWindowType_toplevel:
927 case eWindowType_invisible:
928 return WS_EX_WINDOWEDGE;
932 /**************************************************************
934 * SECTION: Window subclassing utilities
936 * Set or clear window subclasses on native windows. Used in
937 * Create and Destroy.
939 **************************************************************/
941 // Subclass (or remove the subclass from) this component's nsWindow
942 void nsWindow::SubclassWindow(BOOL bState)
944 if (NULL != mWnd) {
945 //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
946 if (!::IsWindow(mWnd)) {
947 NS_ERROR("Invalid window handle");
950 if (bState) {
951 // change the nsWindow proc
952 if (mUnicodeWidget)
953 mPrevWndProc = (WNDPROC)::SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
954 (LONG_PTR)nsWindow::WindowProc);
955 else
956 mPrevWndProc = (WNDPROC)::SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
957 (LONG_PTR)nsWindow::WindowProc);
958 NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
959 // connect the this pointer to the nsWindow handle
960 SetNSWindowPtr(mWnd, this);
962 else {
963 if (mUnicodeWidget)
964 ::SetWindowLongPtrW(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
965 else
966 ::SetWindowLongPtrA(mWnd, GWLP_WNDPROC, (LONG_PTR)mPrevWndProc);
967 SetNSWindowPtr(mWnd, NULL);
968 mPrevWndProc = NULL;
973 /**************************************************************
975 * SECTION: Window properties
977 * Set and clear native window properties.
979 **************************************************************/
981 static PRUnichar sPropName[40] = L"";
982 static PRUnichar* GetNSWindowPropName()
984 if (!*sPropName)
986 _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p", GetCurrentProcessId());
987 sPropName[39] = '\0';
989 return sPropName;
992 nsWindow * nsWindow::GetNSWindowPtr(HWND aWnd)
994 return (nsWindow *) ::GetPropW(aWnd, GetNSWindowPropName());
997 BOOL nsWindow::SetNSWindowPtr(HWND aWnd, nsWindow * ptr)
999 if (ptr == NULL) {
1000 ::RemovePropW(aWnd, GetNSWindowPropName());
1001 return TRUE;
1002 } else {
1003 return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)ptr);
1007 /**************************************************************
1009 * SECTION: nsIWidget::SetParent, nsIWidget::GetParent
1011 * Set or clear the parent widgets using window properties, and
1012 * handles calculating native parent handles.
1014 **************************************************************/
1016 // Get and set parent widgets
1017 NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent)
1019 mParent = aNewParent;
1021 if (aNewParent) {
1022 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1024 nsIWidget* parent = GetParent();
1025 if (parent) {
1026 parent->RemoveChild(this);
1029 HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
1030 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
1031 if (newParent && mWnd) {
1032 ::SetParent(mWnd, newParent);
1035 aNewParent->AddChild(this);
1037 return NS_OK;
1040 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1042 nsIWidget* parent = GetParent();
1044 if (parent) {
1045 parent->RemoveChild(this);
1048 if (mWnd) {
1049 // If we have no parent, SetParent should return the desktop.
1050 VERIFY(::SetParent(mWnd, nsnull));
1053 return NS_OK;
1056 nsIWidget* nsWindow::GetParent(void)
1058 return GetParentWindow(PR_FALSE);
1061 float nsWindow::GetDPI()
1063 HDC dc = ::GetDC(mWnd);
1064 if (!dc)
1065 return 96.0f;
1067 double heightInches = ::GetDeviceCaps(dc, VERTSIZE)/MM_PER_INCH_FLOAT;
1068 int heightPx = ::GetDeviceCaps(dc, VERTRES);
1069 ::ReleaseDC(mWnd, dc);
1070 if (heightInches < 0.25) {
1071 // Something's broken
1072 return 96.0f;
1074 return float(heightPx/heightInches);
1077 nsWindow* nsWindow::GetParentWindow(PRBool aIncludeOwner)
1079 if (mIsTopWidgetWindow) {
1080 // Must use a flag instead of mWindowType to tell if the window is the
1081 // owned by the topmost widget, because a child window can be embedded inside
1082 // a HWND which is not associated with a nsIWidget.
1083 return nsnull;
1086 // If this widget has already been destroyed, pretend we have no parent.
1087 // This corresponds to code in Destroy which removes the destroyed
1088 // widget from its parent's child list.
1089 if (mInDtor || mOnDestroyCalled)
1090 return nsnull;
1093 // aIncludeOwner set to true implies walking the parent chain to retrieve the
1094 // root owner. aIncludeOwner set to false implies the search will stop at the
1095 // true parent (default).
1096 nsWindow* widget = nsnull;
1097 if (mWnd) {
1098 #ifdef WINCE
1099 HWND parent = ::GetParent(mWnd);
1100 #else
1101 HWND parent = nsnull;
1102 if (aIncludeOwner)
1103 parent = ::GetParent(mWnd);
1104 else
1105 parent = ::GetAncestor(mWnd, GA_PARENT);
1106 #endif
1107 if (parent) {
1108 widget = GetNSWindowPtr(parent);
1109 if (widget) {
1110 // If the widget is in the process of being destroyed then
1111 // do NOT return it
1112 if (widget->mInDtor) {
1113 widget = nsnull;
1119 return widget;
1122 /**************************************************************
1124 * SECTION: nsIWidget::Show
1126 * Hide or show this component.
1128 **************************************************************/
1130 NS_METHOD nsWindow::Show(PRBool bState)
1132 #if defined(MOZ_SPLASHSCREEN)
1133 // we're about to show the first toplevel window,
1134 // so kill off any splash screen if we had one
1135 nsSplashScreen *splash = nsSplashScreen::Get();
1136 if (splash && splash->IsOpen() && mWnd && bState &&
1137 (mWindowType == eWindowType_toplevel ||
1138 mWindowType == eWindowType_dialog ||
1139 mWindowType == eWindowType_popup))
1141 splash->Close();
1143 #endif
1145 #ifdef NS_FUNCTION_TIMER
1146 static bool firstShow = true;
1147 if (firstShow &&
1148 (mWindowType == eWindowType_toplevel ||
1149 mWindowType == eWindowType_dialog ||
1150 mWindowType == eWindowType_popup))
1152 firstShow = false;
1153 mozilla::FunctionTimer::LogMessage("@ First toplevel/dialog/popup showing");
1155 #endif
1157 PRBool wasVisible = mIsVisible;
1158 // Set the status now so that anyone asking during ShowWindow or
1159 // SetWindowPos would get the correct answer.
1160 mIsVisible = bState;
1162 if (!mIsVisible && wasVisible) {
1163 ClearCachedResources();
1166 if (mWnd) {
1167 if (bState) {
1168 if (!wasVisible && mWindowType == eWindowType_toplevel) {
1169 switch (mSizeMode) {
1170 #ifdef WINCE
1171 case nsSizeMode_Fullscreen:
1172 ::SetForegroundWindow(mWnd);
1173 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1174 MakeFullScreen(TRUE);
1175 break;
1177 case nsSizeMode_Maximized :
1178 ::SetForegroundWindow(mWnd);
1179 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1180 break;
1181 // use default for nsSizeMode_Minimized on Windows CE
1182 #else
1183 case nsSizeMode_Maximized :
1184 ::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1185 break;
1186 case nsSizeMode_Minimized :
1187 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
1188 break;
1189 #endif
1190 default:
1191 if (CanTakeFocus()) {
1192 #ifdef WINCE
1193 ::SetForegroundWindow(mWnd);
1194 #endif
1195 ::ShowWindow(mWnd, SW_SHOWNORMAL);
1196 } else {
1197 // Place the window behind the foreground window
1198 // (as long as it is not topmost)
1199 HWND wndAfter = ::GetForegroundWindow();
1200 if (!wndAfter)
1201 wndAfter = HWND_BOTTOM;
1202 else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)
1203 wndAfter = HWND_TOP;
1204 ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE |
1205 SWP_NOMOVE | SWP_NOACTIVATE);
1206 GetAttention(2);
1208 break;
1210 } else {
1211 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
1212 if (wasVisible)
1213 flags |= SWP_NOZORDER;
1215 if (mWindowType == eWindowType_popup) {
1216 #ifndef WINCE
1217 // ensure popups are the topmost of the TOPMOST
1218 // layer. Remember not to set the SWP_NOZORDER
1219 // flag as that might allow the taskbar to overlap
1220 // the popup. However on windows ce, we need to
1221 // activate the popup or clicks will not be sent.
1222 flags |= SWP_NOACTIVATE;
1223 #endif
1224 HWND owner = ::GetWindow(mWnd, GW_OWNER);
1225 ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
1226 } else {
1227 #ifndef WINCE
1228 if (mWindowType == eWindowType_dialog && !CanTakeFocus())
1229 flags |= SWP_NOACTIVATE;
1230 #endif
1231 ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
1235 #ifndef WINCE
1236 if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) {
1237 // when a toplevel window or dialog is shown, initialize the UI state
1238 ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
1240 #endif
1241 } else {
1242 if (mWindowType != eWindowType_dialog) {
1243 ::ShowWindow(mWnd, SW_HIDE);
1244 } else {
1245 ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1246 SWP_NOZORDER | SWP_NOACTIVATE);
1251 #ifdef MOZ_XUL
1252 if (!wasVisible && bState)
1253 Invalidate(PR_FALSE);
1254 #endif
1256 return NS_OK;
1259 /**************************************************************
1261 * SECTION: nsIWidget::IsVisible
1263 * Returns the visibility state.
1265 **************************************************************/
1267 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1268 NS_METHOD nsWindow::IsVisible(PRBool & bState)
1270 bState = mIsVisible;
1271 return NS_OK;
1274 /**************************************************************
1276 * SECTION: Window clipping utilities
1278 * Used in Size and Move operations for setting the proper
1279 * window clipping regions for window transparency.
1281 **************************************************************/
1283 // XP and Vista visual styles sometimes require window clipping regions to be applied for proper
1284 // transparency. These routines are called on size and move operations.
1285 void nsWindow::ClearThemeRegion()
1287 #ifndef WINCE
1288 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1289 (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1290 (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1291 SetWindowRgn(mWnd, NULL, false);
1293 #endif
1296 void nsWindow::SetThemeRegion()
1298 #ifndef WINCE
1299 // Popup types that have a visual styles region applied (bug 376408). This can be expanded
1300 // for other window types as needed. The regions are applied generically to the base window
1301 // so default constants are used for part and state. At some point we might need part and
1302 // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that
1303 // change shape based on state haven't come up.
1304 if (nsUXThemeData::sIsVistaOrLater && !HasGlass() &&
1305 (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1306 (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1307 HRGN hRgn = nsnull;
1308 RECT rect = {0,0,mBounds.width,mBounds.height};
1310 HDC dc = ::GetDC(mWnd);
1311 nsUXThemeData::getThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
1312 if (hRgn) {
1313 if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted.
1314 DeleteObject(hRgn);
1316 ::ReleaseDC(mWnd, dc);
1318 #endif
1321 /**************************************************************
1323 * SECTION: nsIWidget::RegisterTouchWindow,
1324 * nsIWidget::UnregisterTouchWindow, and helper functions
1326 * Used to register the native window to receive touch events
1328 **************************************************************/
1330 NS_METHOD nsWindow::RegisterTouchWindow() {
1331 mTouchWindow = PR_TRUE;
1332 #ifndef WINCE
1333 mGesture.RegisterTouchWindow(mWnd);
1334 ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
1335 #endif
1336 return NS_OK;
1339 NS_METHOD nsWindow::UnregisterTouchWindow() {
1340 mTouchWindow = PR_FALSE;
1341 #ifndef WINCE
1342 mGesture.UnregisterTouchWindow(mWnd);
1343 ::EnumChildWindows(mWnd, nsWindow::UnregisterTouchForDescendants, 0);
1344 #endif
1345 return NS_OK;
1348 #ifndef WINCE
1349 BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1350 nsWindow* win = GetNSWindowPtr(aWnd);
1351 if (win)
1352 win->mGesture.RegisterTouchWindow(aWnd);
1353 return TRUE;
1356 BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1357 nsWindow* win = GetNSWindowPtr(aWnd);
1358 if (win)
1359 win->mGesture.UnregisterTouchWindow(aWnd);
1360 return TRUE;
1362 #endif
1364 /**************************************************************
1366 * SECTION: nsIWidget::Move, nsIWidget::Resize,
1367 * nsIWidget::Size, nsIWidget::BeginResizeDrag
1369 * Repositioning and sizing a window.
1371 **************************************************************/
1373 // Move this component
1374 NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
1376 if (mWindowType == eWindowType_toplevel ||
1377 mWindowType == eWindowType_dialog) {
1378 SetSizeMode(nsSizeMode_Normal);
1380 // Check to see if window needs to be moved first
1381 // to avoid a costly call to SetWindowPos. This check
1382 // can not be moved to the calling code in nsView, because
1383 // some platforms do not position child windows correctly
1385 // Only perform this check for non-popup windows, since the positioning can
1386 // in fact change even when the x/y do not. We always need to perform the
1387 // check. See bug #97805 for details.
1388 if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
1390 // Nothing to do, since it is already positioned correctly.
1391 return NS_OK;
1394 mBounds.x = aX;
1395 mBounds.y = aY;
1397 if (mWnd) {
1398 #ifdef DEBUG
1399 // complain if a window is moved offscreen (legal, but potentially worrisome)
1400 if (mIsTopWidgetWindow) { // only a problem for top-level windows
1401 // Make sure this window is actually on the screen before we move it
1402 // XXX: Needs multiple monitor support
1403 HDC dc = ::GetDC(mWnd);
1404 if (dc) {
1405 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1406 RECT workArea;
1407 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1408 // no annoying assertions. just mention the issue.
1409 if (aX < 0 || aX >= workArea.right || aY < 0 || aY >= workArea.bottom)
1410 printf("window moved to offscreen position\n");
1412 ::ReleaseDC(mWnd, dc);
1415 #endif
1416 ClearThemeRegion();
1417 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0,
1418 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE));
1419 SetThemeRegion();
1421 return NS_OK;
1424 // Resize this component
1425 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1427 NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
1428 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1430 // Avoid unnecessary resizing calls
1431 if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1432 return NS_OK;
1434 #ifdef MOZ_XUL
1435 if (eTransparencyTransparent == mTransparencyMode)
1436 ResizeTranslucentWindow(aWidth, aHeight);
1437 #endif
1439 // Set cached value for lightweight and printing
1440 mBounds.width = aWidth;
1441 mBounds.height = aHeight;
1443 if (mWnd) {
1444 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
1446 #ifndef WINCE
1447 if (!aRepaint) {
1448 flags |= SWP_NOREDRAW;
1450 #endif
1452 ClearThemeRegion();
1453 VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
1454 SetThemeRegion();
1457 if (aRepaint)
1458 Invalidate(PR_FALSE);
1460 return NS_OK;
1463 // Resize this component
1464 NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1466 NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize");
1467 NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
1469 // Avoid unnecessary resizing calls
1470 if (mBounds.x == aX && mBounds.y == aY &&
1471 mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
1472 return NS_OK;
1474 #ifdef MOZ_XUL
1475 if (eTransparencyTransparent == mTransparencyMode)
1476 ResizeTranslucentWindow(aWidth, aHeight);
1477 #endif
1479 // Set cached value for lightweight and printing
1480 mBounds.x = aX;
1481 mBounds.y = aY;
1482 mBounds.width = aWidth;
1483 mBounds.height = aHeight;
1485 if (mWnd) {
1486 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
1487 #ifndef WINCE
1488 if (!aRepaint) {
1489 flags |= SWP_NOREDRAW;
1491 #endif
1493 ClearThemeRegion();
1494 VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
1495 SetThemeRegion();
1498 if (aRepaint)
1499 Invalidate(PR_FALSE);
1501 return NS_OK;
1504 // Resize the client area and position the widget within it's parent
1505 NS_METHOD nsWindow::ResizeClient(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1507 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1508 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1510 // Adjust our existing window bounds, based on the new client dims.
1511 RECT client;
1512 GetClientRect(mWnd, &client);
1513 nsIntPoint dims(client.right - client.left, client.bottom - client.top);
1514 aWidth = mBounds.width + (aWidth - dims.x);
1515 aHeight = mBounds.height + (aHeight - dims.y);
1517 if (aX || aY) {
1518 // offsets
1519 nsIntRect bounds;
1520 GetScreenBounds(bounds);
1521 aX += bounds.x;
1522 aY += bounds.y;
1523 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1525 return Resize(aWidth, aHeight, aRepaint);
1528 #if !defined(WINCE)
1529 NS_IMETHODIMP
1530 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
1532 NS_ENSURE_ARG_POINTER(aEvent);
1534 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
1535 // you can only begin a resize drag with a mouse event
1536 return NS_ERROR_INVALID_ARG;
1539 nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
1540 if (mouseEvent->button != nsMouseEvent::eLeftButton) {
1541 // you can only begin a resize drag with the left mouse button
1542 return NS_ERROR_INVALID_ARG;
1545 // work out what sizemode we're talking about
1546 WPARAM syscommand;
1547 if (aVertical < 0) {
1548 if (aHorizontal < 0) {
1549 syscommand = SC_SIZE | WMSZ_TOPLEFT;
1550 } else if (aHorizontal == 0) {
1551 syscommand = SC_SIZE | WMSZ_TOP;
1552 } else {
1553 syscommand = SC_SIZE | WMSZ_TOPRIGHT;
1555 } else if (aVertical == 0) {
1556 if (aHorizontal < 0) {
1557 syscommand = SC_SIZE | WMSZ_LEFT;
1558 } else if (aHorizontal == 0) {
1559 return NS_ERROR_INVALID_ARG;
1560 } else {
1561 syscommand = SC_SIZE | WMSZ_RIGHT;
1563 } else {
1564 if (aHorizontal < 0) {
1565 syscommand = SC_SIZE | WMSZ_BOTTOMLEFT;
1566 } else if (aHorizontal == 0) {
1567 syscommand = SC_SIZE | WMSZ_BOTTOM;
1568 } else {
1569 syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT;
1573 // resizing doesn't work if the mouse is already captured
1574 CaptureMouse(PR_FALSE);
1576 // find the top-level window
1577 HWND toplevelWnd = GetTopLevelHWND(mWnd, PR_TRUE);
1579 // tell Windows to start the resize
1580 ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand,
1581 POINTTOPOINTS(aEvent->refPoint));
1583 return NS_OK;
1585 #endif
1586 /**************************************************************
1588 * SECTION: Window Z-order and state.
1590 * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
1591 * nsIWidget::ConstrainPosition
1593 * Z-order, positioning, restore, minimize, and maximize.
1595 **************************************************************/
1597 // Position the window behind the given window
1598 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1599 nsIWidget *aWidget, PRBool aActivate)
1601 HWND behind = HWND_TOP;
1602 if (aPlacement == eZPlacementBottom)
1603 behind = HWND_BOTTOM;
1604 else if (aPlacement == eZPlacementBelow && aWidget)
1605 behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
1606 UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
1607 if (!aActivate)
1608 flags |= SWP_NOACTIVATE;
1610 if (!CanTakeFocus() && behind == HWND_TOP)
1612 // Can't place the window to top so place it behind the foreground window
1613 // (as long as it is not topmost)
1614 HWND wndAfter = ::GetForegroundWindow();
1615 if (!wndAfter)
1616 behind = HWND_BOTTOM;
1617 else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
1618 behind = wndAfter;
1619 flags |= SWP_NOACTIVATE;
1622 ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
1623 return NS_OK;
1626 // Maximize, minimize or restore the window.
1627 #if !defined(WINCE) // implemented in nsWindowCE.cpp
1628 NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode) {
1630 nsresult rv;
1632 // Let's not try and do anything if we're already in that state.
1633 // (This is needed to prevent problems when calling window.minimize(), which
1634 // calls us directly, and then the OS triggers another call to us.)
1635 if (aMode == mSizeMode)
1636 return NS_OK;
1638 // save the requested state
1639 rv = nsBaseWidget::SetSizeMode(aMode);
1640 if (NS_SUCCEEDED(rv) && mIsVisible) {
1641 int mode;
1643 switch (aMode) {
1644 case nsSizeMode_Fullscreen :
1645 mode = SW_SHOW;
1646 break;
1648 case nsSizeMode_Maximized :
1649 mode = SW_MAXIMIZE;
1650 break;
1652 case nsSizeMode_Minimized :
1653 // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but
1654 // keeps the window active in the tray. So after the window is minimized,
1655 // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point
1656 // we will do some additional processing to get the active window set right.
1657 // If sTrimOnMinimize is set, we let windows handle minimization normally
1658 // using SW_MINIMIZE.
1659 mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED;
1660 break;
1662 default :
1663 mode = SW_RESTORE;
1665 ::ShowWindow(mWnd, mode);
1666 // we dispatch an activate event here to ensure that the right child window
1667 // is focused
1668 if (mode == SW_RESTORE || mode == SW_MAXIMIZE)
1669 DispatchFocusToTopLevelWindow(NS_ACTIVATE);
1671 return rv;
1673 #endif // !defined(WINCE)
1675 // Constrain a potential move to fit onscreen
1676 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop,
1677 PRInt32 *aX, PRInt32 *aY)
1679 if (!mIsTopWidgetWindow) // only a problem for top-level windows
1680 return NS_OK;
1682 PRBool doConstrain = PR_FALSE; // whether we have enough info to do anything
1684 /* get our playing field. use the current screen, or failing that
1685 for any reason, use device caps for the default screen. */
1686 RECT screenRect;
1688 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
1689 if (screenmgr) {
1690 nsCOMPtr<nsIScreen> screen;
1691 PRInt32 left, top, width, height;
1693 // zero size rects confuse the screen manager
1694 width = mBounds.width > 0 ? mBounds.width : 1;
1695 height = mBounds.height > 0 ? mBounds.height : 1;
1696 screenmgr->ScreenForRect(*aX, *aY, width, height,
1697 getter_AddRefs(screen));
1698 if (screen) {
1699 if (mSizeMode != nsSizeMode_Fullscreen) {
1700 // For normalized windows, use the desktop work area.
1701 screen->GetAvailRect(&left, &top, &width, &height);
1702 } else {
1703 // For full screen windows, use the desktop.
1704 screen->GetRect(&left, &top, &width, &height);
1706 screenRect.left = left;
1707 screenRect.right = left+width;
1708 screenRect.top = top;
1709 screenRect.bottom = top+height;
1710 doConstrain = PR_TRUE;
1712 } else {
1713 if (mWnd) {
1714 HDC dc = ::GetDC(mWnd);
1715 if (dc) {
1716 if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1717 if (mSizeMode != nsSizeMode_Fullscreen) {
1718 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
1719 } else {
1720 screenRect.left = screenRect.top = 0;
1721 screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN);
1722 screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
1724 doConstrain = PR_TRUE;
1726 ::ReleaseDC(mWnd, dc);
1731 if (aAllowSlop) {
1732 if (*aX < screenRect.left - mBounds.width + kWindowPositionSlop)
1733 *aX = screenRect.left - mBounds.width + kWindowPositionSlop;
1734 else if (*aX >= screenRect.right - kWindowPositionSlop)
1735 *aX = screenRect.right - kWindowPositionSlop;
1737 if (*aY < screenRect.top - mBounds.height + kWindowPositionSlop)
1738 *aY = screenRect.top - mBounds.height + kWindowPositionSlop;
1739 else if (*aY >= screenRect.bottom - kWindowPositionSlop)
1740 *aY = screenRect.bottom - kWindowPositionSlop;
1742 } else {
1744 if (*aX < screenRect.left)
1745 *aX = screenRect.left;
1746 else if (*aX >= screenRect.right - mBounds.width)
1747 *aX = screenRect.right - mBounds.width;
1749 if (*aY < screenRect.top)
1750 *aY = screenRect.top;
1751 else if (*aY >= screenRect.bottom - mBounds.height)
1752 *aY = screenRect.bottom - mBounds.height;
1755 return NS_OK;
1758 /**************************************************************
1760 * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled
1762 * Enabling and disabling the widget.
1764 **************************************************************/
1766 // Enable/disable this component
1767 NS_METHOD nsWindow::Enable(PRBool bState)
1769 if (mWnd) {
1770 ::EnableWindow(mWnd, bState);
1772 return NS_OK;
1775 // Return the current enable state
1776 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
1778 NS_ENSURE_ARG_POINTER(aState);
1780 #ifndef WINCE
1781 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT)));
1782 #else
1783 *aState = !mWnd || (::IsWindowEnabled(mWnd) && ::IsWindowEnabled(mWnd));
1784 #endif
1786 return NS_OK;
1790 /**************************************************************
1792 * SECTION: nsIWidget::SetFocus
1794 * Give the focus to this widget.
1796 **************************************************************/
1798 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
1800 if (mWnd) {
1801 #ifdef WINSTATE_DEBUG_OUTPUT
1802 if (mWnd == GetTopLevelHWND(mWnd))
1803 printf("*** SetFocus: [ top] raise=%d\n", aRaise);
1804 else
1805 printf("*** SetFocus: [child] raise=%d\n", aRaise);
1806 #endif
1807 // Uniconify, if necessary
1808 HWND toplevelWnd = GetTopLevelHWND(mWnd);
1809 if (aRaise && ::IsIconic(toplevelWnd)) {
1810 ::ShowWindow(toplevelWnd, SW_RESTORE);
1812 ::SetFocus(mWnd);
1814 return NS_OK;
1818 /**************************************************************
1820 * SECTION: Bounds
1822 * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset
1823 * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins
1825 * Bound calculations.
1827 **************************************************************/
1829 // Return the window's full dimensions in screen coordinates.
1830 // If the window has a parent, converts the origin to an offset
1831 // of the parent's screen origin.
1832 NS_METHOD nsWindow::GetBounds(nsIntRect &aRect)
1834 if (mWnd) {
1835 RECT r;
1836 VERIFY(::GetWindowRect(mWnd, &r));
1838 // assign size
1839 aRect.width = r.right - r.left;
1840 aRect.height = r.bottom - r.top;
1842 // chrome on parent:
1843 // ___ 5,5 (chrome start)
1844 // | ____ 10,10 (client start)
1845 // | | ____ 20,20 (child start)
1846 // | | |
1847 // 20,20 - 5,5 = 15,15 (??)
1848 // minus GetClientOffset:
1849 // 15,15 - 5,5 = 10,10
1851 // no chrome on parent:
1852 // ______ 10,10 (win start)
1853 // | ____ 20,20 (child start)
1854 // | |
1855 // 20,20 - 10,10 = 10,10
1857 // walking the chain:
1858 // ___ 5,5 (chrome start)
1859 // | ___ 10,10 (client start)
1860 // | | ___ 20,20 (child start)
1861 // | | | __ 30,30 (child start)
1862 // | | | |
1863 // 30,30 - 20,20 = 10,10 (offset from second child to first)
1864 // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??)
1865 // minus GetClientOffset:
1866 // 25,25 - 5,5 = 20,20 (offset from second child to parent client)
1868 // convert coordinates if parent exists
1869 HWND parent = ::GetParent(mWnd);
1870 if (parent) {
1871 RECT pr;
1872 VERIFY(::GetWindowRect(parent, &pr));
1873 r.left -= pr.left;
1874 r.top -= pr.top;
1875 // adjust for chrome
1876 nsWindow* pWidget = static_cast<nsWindow*>(GetParent());
1877 if (pWidget && pWidget->IsTopLevelWidget()) {
1878 nsIntPoint clientOffset = pWidget->GetClientOffset();
1879 r.left -= clientOffset.x;
1880 r.top -= clientOffset.y;
1883 aRect.x = r.left;
1884 aRect.y = r.top;
1885 } else {
1886 aRect = mBounds;
1889 return NS_OK;
1892 // Get this component dimension
1893 NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect)
1895 if (mWnd) {
1896 RECT r;
1897 VERIFY(::GetClientRect(mWnd, &r));
1899 // assign size
1900 aRect.x = 0;
1901 aRect.y = 0;
1902 aRect.width = r.right - r.left;
1903 aRect.height = r.bottom - r.top;
1905 } else {
1906 aRect.SetRect(0,0,0,0);
1908 return NS_OK;
1911 // Like GetBounds, but don't offset by the parent
1912 NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect)
1914 if (mWnd) {
1915 RECT r;
1916 VERIFY(::GetWindowRect(mWnd, &r));
1918 aRect.width = r.right - r.left;
1919 aRect.height = r.bottom - r.top;
1920 aRect.x = r.left;
1921 aRect.y = r.top;
1922 } else
1923 aRect = mBounds;
1925 return NS_OK;
1928 // return the x,y offset of the client area from the origin
1929 // of the window. If the window is borderless returns (0,0).
1930 nsIntPoint nsWindow::GetClientOffset()
1932 if (!mWnd) {
1933 return nsIntPoint(0, 0);
1936 RECT r1;
1937 GetWindowRect(mWnd, &r1);
1938 nsIntPoint pt = WidgetToScreenOffset();
1939 return nsIntPoint(pt.x - r1.left, pt.y - r1.top);
1942 void
1943 nsWindow::SetDrawsInTitlebar(PRBool aState)
1945 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1946 if (window && window != this) {
1947 return window->SetDrawsInTitlebar(aState);
1950 if (aState) {
1951 // left, top, right, bottom for nsIntMargin
1952 nsIntMargin margins(-1, 0, -1, -1);
1953 SetNonClientMargins(margins);
1955 else {
1956 nsIntMargin margins(-1, -1, -1, -1);
1957 SetNonClientMargins(margins);
1961 NS_IMETHODIMP
1962 nsWindow::GetNonClientMargins(nsIntMargin &margins)
1964 nsWindow * window = GetTopLevelWindow(PR_TRUE);
1965 if (window && window != this) {
1966 return window->GetNonClientMargins(margins);
1969 if (mCustomNonClient) {
1970 margins = mNonClientMargins;
1971 return NS_OK;
1974 margins.top = GetSystemMetrics(SM_CYCAPTION);
1975 margins.bottom = GetSystemMetrics(SM_CYFRAME);
1976 margins.top += margins.bottom;
1977 margins.left = margins.right = GetSystemMetrics(SM_CYFRAME);
1979 return NS_OK;
1982 void
1983 nsWindow::ResetLayout()
1985 // This will trigger a frame changed event, triggering
1986 // nc calc size and a sizemode gecko event.
1987 SetWindowPos(mWnd, 0, 0, 0, 0, 0,
1988 SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|
1989 SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
1991 // If hidden, just send the frame changed event for now.
1992 if (!mIsVisible)
1993 return;
1995 // Send a gecko size event to trigger reflow.
1996 RECT clientRc = {0};
1997 GetClientRect(mWnd, &clientRc);
1998 nsIntRect evRect(nsWindowGfx::ToIntRect(clientRc));
1999 OnResize(evRect);
2001 // Invalidate and update
2002 Invalidate(PR_FALSE);
2005 // Called when the window layout changes: full screen mode transitions,
2006 // theme changes, and composition changes. Calculates the new non-client
2007 // margins and fires off a frame changed event, which triggers an nc calc
2008 // size windows event, kicking the changes in.
2009 PRBool
2010 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode, PRBool aReflowWindow)
2012 if (!mCustomNonClient)
2013 return PR_FALSE;
2015 mNonClientOffset.top = mNonClientOffset.bottom =
2016 mNonClientOffset.left = mNonClientOffset.right = 0;
2018 if (aSizeMode == -1)
2019 aSizeMode = mSizeMode;
2021 if (aSizeMode == nsSizeMode_Minimized ||
2022 aSizeMode == nsSizeMode_Fullscreen) {
2023 mCaptionHeight = mVertResizeMargin = mHorResizeMargin = 0;
2024 return PR_TRUE;
2027 // Note, for maximized windows, we need to continue to offset the client by
2028 // thick frame margins of a normal window, since windows expects this
2029 // in it's DwmDefWndProc hit testing.
2030 mCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
2031 mHorResizeMargin = GetSystemMetrics(SM_CXFRAME);
2032 mVertResizeMargin = GetSystemMetrics(SM_CYFRAME);
2034 mCaptionHeight += mVertResizeMargin;
2036 // If a margin value is 0, set the offset to the default size of the frame.
2037 // If a margin is -1, leave as default, and if a margin > 0, set the offset
2038 // so that the frame size is equal to the margin value.
2039 if (!mNonClientMargins.top)
2040 mNonClientOffset.top = mCaptionHeight;
2041 else if (mNonClientMargins.top > 0)
2042 mNonClientOffset.top = mCaptionHeight - mNonClientMargins.top;
2044 if (!mNonClientMargins.left)
2045 mNonClientOffset.left = mHorResizeMargin;
2046 else if (mNonClientMargins.left > 0)
2047 mNonClientOffset.left = mHorResizeMargin - mNonClientMargins.left;
2049 if (!mNonClientMargins.right)
2050 mNonClientOffset.right = mHorResizeMargin;
2051 else if (mNonClientMargins.right > 0)
2052 mNonClientOffset.right = mHorResizeMargin - mNonClientMargins.right;
2054 if (!mNonClientMargins.bottom)
2055 mNonClientOffset.bottom = mVertResizeMargin;
2056 else if (mNonClientMargins.bottom > 0)
2057 mNonClientOffset.bottom = mVertResizeMargin - mNonClientMargins.bottom;
2059 #ifndef WINCE
2060 if (aSizeMode == nsSizeMode_Maximized) {
2061 // Address an issue with auto-hide taskbars which fall behind the window.
2062 // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
2063 // the taskbar works properly.
2064 MONITORINFO info = {sizeof(MONITORINFO)};
2065 if (::GetMonitorInfo(::MonitorFromWindow(mWnd, MONITOR_DEFAULTTOPRIMARY),
2066 &info)) {
2067 RECT r;
2068 if (::GetWindowRect(mWnd, &r)) {
2069 // Adjust window rect to account for non-client margins.
2070 r.top += mVertResizeMargin - mNonClientOffset.top;
2071 r.left += mHorResizeMargin - mNonClientOffset.left;
2072 r.bottom -= mVertResizeMargin - mNonClientOffset.bottom;
2073 r.right -= mHorResizeMargin - mNonClientOffset.right;
2074 // Leave the 1 pixel margin if the window covers the monitor.
2075 if (r.top <= info.rcMonitor.top &&
2076 r.left <= info.rcMonitor.left &&
2077 r.right >= info.rcMonitor.right &&
2078 r.bottom >= info.rcMonitor.bottom)
2079 mNonClientOffset.bottom -= r.bottom - info.rcMonitor.bottom + 1;
2083 #endif
2085 if (aReflowWindow) {
2086 // Force a reflow of content based on the new client
2087 // dimensions.
2088 ResetLayout();
2091 return PR_TRUE;
2094 NS_IMETHODIMP
2095 nsWindow::SetNonClientMargins(nsIntMargin &margins)
2097 if (!mIsTopWidgetWindow ||
2098 mBorderStyle & eBorderStyle_none ||
2099 mHideChrome)
2100 return NS_ERROR_INVALID_ARG;
2102 // Request for a reset
2103 if (margins.top == -1 && margins.left == -1 &&
2104 margins.right == -1 && margins.bottom == -1) {
2105 mCustomNonClient = PR_FALSE;
2106 mNonClientMargins = margins;
2107 // Force a reflow of content based on the new client
2108 // dimensions.
2109 ResetLayout();
2110 return NS_OK;
2113 if (margins.top < -1 || margins.bottom < -1 ||
2114 margins.left < -1 || margins.right < -1)
2115 return NS_ERROR_INVALID_ARG;
2117 mNonClientMargins = margins;
2118 mCustomNonClient = PR_TRUE;
2119 if (!UpdateNonClientMargins()) {
2120 NS_WARNING("UpdateNonClientMargins failed!");
2121 return PR_FALSE;
2124 return NS_OK;
2127 void
2128 nsWindow::InvalidateNonClientRegion()
2130 // +-+-----------------------+-+
2131 // | | app non-client chrome | |
2132 // | +-----------------------+ |
2133 // | | app client chrome | | }
2134 // | +-----------------------+ | }
2135 // | | app content | | } area we don't want to invalidate
2136 // | +-----------------------+ | }
2137 // | | app client chrome | | }
2138 // | +-----------------------+ |
2139 // +---------------------------+ <
2140 // ^ ^ windows non-client chrome
2141 // client area = app *
2142 RECT rect;
2143 GetWindowRect(mWnd, &rect);
2144 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2145 HRGN winRgn = CreateRectRgnIndirect(&rect);
2147 // Subtract app client chrome and app content leaving
2148 // windows non-client chrome and app non-client chrome
2149 // in winRgn.
2150 GetWindowRect(mWnd, &rect);
2151 rect.top += mCaptionHeight;
2152 rect.right -= mHorResizeMargin;
2153 rect.bottom -= mHorResizeMargin;
2154 rect.left += mVertResizeMargin;
2155 MapWindowPoints(NULL, mWnd, (LPPOINT)&rect, 2);
2156 HRGN clientRgn = CreateRectRgnIndirect(&rect);
2157 CombineRgn(winRgn, winRgn, clientRgn, RGN_DIFF);
2158 DeleteObject(clientRgn);
2160 // triggers ncpaint and paint events for the two areas
2161 RedrawWindow(mWnd, NULL, winRgn, RDW_FRAME|RDW_INVALIDATE);
2162 DeleteObject(winRgn);
2165 HRGN
2166 nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion)
2168 RECT rect;
2169 HRGN rgn = NULL;
2170 if (aRegion == (HRGN)1) { // undocumented value indicating a full refresh
2171 GetWindowRect(mWnd, &rect);
2172 rgn = CreateRectRgnIndirect(&rect);
2173 } else {
2174 rgn = aRegion;
2176 GetClientRect(mWnd, &rect);
2177 MapWindowPoints(mWnd, NULL, (LPPOINT)&rect, 2);
2178 HRGN nonClientRgn = CreateRectRgnIndirect(&rect);
2179 CombineRgn(rgn, rgn, nonClientRgn, RGN_DIFF);
2180 DeleteObject(nonClientRgn);
2181 return rgn;
2184 /**************************************************************
2186 * SECTION: nsIWidget::SetBackgroundColor
2188 * Sets the window background paint color.
2190 **************************************************************/
2192 NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
2194 nsBaseWidget::SetBackgroundColor(aColor);
2196 if (mBrush)
2197 ::DeleteObject(mBrush);
2199 mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
2200 #ifndef WINCE
2201 if (mWnd != NULL) {
2202 ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush);
2204 #endif
2205 return NS_OK;
2208 /**************************************************************
2210 * SECTION: nsIWidget::SetCursor
2212 * SetCursor and related utilities for manging cursor state.
2214 **************************************************************/
2216 // Set this component cursor
2217 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
2219 // Only change cursor if it's changing
2221 //XXX mCursor isn't always right. Scrollbars and others change it, too.
2222 //XXX If we want this optimization we need a better way to do it.
2223 //if (aCursor != mCursor) {
2224 HCURSOR newCursor = NULL;
2226 switch (aCursor) {
2227 case eCursor_select:
2228 newCursor = ::LoadCursor(NULL, IDC_IBEAM);
2229 break;
2231 case eCursor_wait:
2232 newCursor = ::LoadCursor(NULL, IDC_WAIT);
2233 break;
2235 case eCursor_hyperlink:
2237 newCursor = ::LoadCursor(NULL, IDC_HAND);
2238 break;
2241 case eCursor_standard:
2242 newCursor = ::LoadCursor(NULL, IDC_ARROW);
2243 break;
2245 case eCursor_n_resize:
2246 case eCursor_s_resize:
2247 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2248 break;
2250 case eCursor_w_resize:
2251 case eCursor_e_resize:
2252 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2253 break;
2255 case eCursor_nw_resize:
2256 case eCursor_se_resize:
2257 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2258 break;
2260 case eCursor_ne_resize:
2261 case eCursor_sw_resize:
2262 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2263 break;
2265 case eCursor_crosshair:
2266 newCursor = ::LoadCursor(NULL, IDC_CROSS);
2267 break;
2269 case eCursor_move:
2270 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2271 break;
2273 case eCursor_help:
2274 newCursor = ::LoadCursor(NULL, IDC_HELP);
2275 break;
2277 case eCursor_copy: // CSS3
2278 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
2279 break;
2281 case eCursor_alias:
2282 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
2283 break;
2285 case eCursor_cell:
2286 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
2287 break;
2289 case eCursor_grab:
2290 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
2291 break;
2293 case eCursor_grabbing:
2294 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
2295 break;
2297 case eCursor_spinning:
2298 newCursor = ::LoadCursor(NULL, IDC_APPSTARTING);
2299 break;
2301 case eCursor_context_menu:
2302 // XXX this CSS3 cursor needs to be implemented
2303 break;
2305 case eCursor_zoom_in:
2306 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
2307 break;
2309 case eCursor_zoom_out:
2310 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
2311 break;
2313 case eCursor_not_allowed:
2314 case eCursor_no_drop:
2315 newCursor = ::LoadCursor(NULL, IDC_NO);
2316 break;
2318 case eCursor_col_resize:
2319 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
2320 break;
2322 case eCursor_row_resize:
2323 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
2324 break;
2326 case eCursor_vertical_text:
2327 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT));
2328 break;
2330 case eCursor_all_scroll:
2331 // XXX not 100% appropriate perhaps
2332 newCursor = ::LoadCursor(NULL, IDC_SIZEALL);
2333 break;
2335 case eCursor_nesw_resize:
2336 newCursor = ::LoadCursor(NULL, IDC_SIZENESW);
2337 break;
2339 case eCursor_nwse_resize:
2340 newCursor = ::LoadCursor(NULL, IDC_SIZENWSE);
2341 break;
2343 case eCursor_ns_resize:
2344 newCursor = ::LoadCursor(NULL, IDC_SIZENS);
2345 break;
2347 case eCursor_ew_resize:
2348 newCursor = ::LoadCursor(NULL, IDC_SIZEWE);
2349 break;
2351 case eCursor_none:
2352 newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
2353 break;
2355 default:
2356 NS_ERROR("Invalid cursor type");
2357 break;
2360 if (NULL != newCursor) {
2361 mCursor = aCursor;
2362 HCURSOR oldCursor = ::SetCursor(newCursor);
2364 if (sHCursor == oldCursor) {
2365 NS_IF_RELEASE(sCursorImgContainer);
2366 if (sHCursor != NULL)
2367 ::DestroyIcon(sHCursor);
2368 sHCursor = NULL;
2372 return NS_OK;
2375 // Setting the actual cursor
2376 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
2377 PRUint32 aHotspotX, PRUint32 aHotspotY)
2379 if (sCursorImgContainer == aCursor && sHCursor) {
2380 ::SetCursor(sHCursor);
2381 return NS_OK;
2384 PRInt32 width;
2385 PRInt32 height;
2387 nsresult rv;
2388 rv = aCursor->GetWidth(&width);
2389 NS_ENSURE_SUCCESS(rv, rv);
2390 rv = aCursor->GetHeight(&height);
2391 NS_ENSURE_SUCCESS(rv, rv);
2393 // Reject cursors greater than 128 pixels in either direction, to prevent
2394 // spoofing.
2395 // XXX ideally we should rescale. Also, we could modify the API to
2396 // allow trusted content to set larger cursors.
2397 if (width > 128 || height > 128)
2398 return NS_ERROR_NOT_AVAILABLE;
2400 HCURSOR cursor;
2401 rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
2402 NS_ENSURE_SUCCESS(rv, rv);
2404 mCursor = nsCursor(-1);
2405 ::SetCursor(cursor);
2407 NS_IF_RELEASE(sCursorImgContainer);
2408 sCursorImgContainer = aCursor;
2409 NS_ADDREF(sCursorImgContainer);
2411 if (sHCursor != NULL)
2412 ::DestroyIcon(sHCursor);
2413 sHCursor = cursor;
2415 return NS_OK;
2418 /**************************************************************
2420 * SECTION: nsIWidget::Get/SetTransparencyMode
2422 * Manage the transparency mode of the top-level window
2423 * containing this widget.
2425 **************************************************************/
2427 #ifdef MOZ_XUL
2428 nsTransparencyMode nsWindow::GetTransparencyMode()
2430 return GetTopLevelWindow(PR_TRUE)->GetWindowTranslucencyInner();
2433 void nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
2435 GetTopLevelWindow(PR_TRUE)->SetWindowTranslucencyInner(aMode);
2438 void nsWindow::UpdatePossiblyTransparentRegion(const nsIntRegion &aDirtyRegion,
2439 const nsIntRegion &aPossiblyTransparentRegion) {
2440 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2441 if (!HasGlass())
2442 return;
2444 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2445 nsWindow* topWindow = GetNSWindowPtr(hWnd);
2447 if (GetParent())
2448 return;
2450 mPossiblyTransparentRegion.Sub(mPossiblyTransparentRegion, aDirtyRegion);
2451 mPossiblyTransparentRegion.Or(mPossiblyTransparentRegion, aPossiblyTransparentRegion);
2453 nsIntRect clientBounds;
2454 topWindow->GetClientBounds(clientBounds);
2455 nsIntRegion opaqueRegion;
2456 opaqueRegion.Sub(clientBounds, mPossiblyTransparentRegion);
2458 MARGINS margins = { 0, 0, 0, 0 };
2459 DWORD_PTR dwStyle = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
2461 // If there is no opaque region or hidechrome=true, set margins
2462 // to support a full sheet of glass.
2463 if (opaqueRegion.IsEmpty() || mHideChrome) {
2464 // Comments in MSDN indicate all values must be set to -1
2465 margins.cxLeftWidth = margins.cxRightWidth =
2466 margins.cyTopHeight = margins.cyBottomHeight = -1;
2467 } else {
2468 // Find the largest rectangle and use that to calculate the inset
2469 nsIntRect largest = opaqueRegion.GetLargestRectangle();
2470 margins.cxLeftWidth = largest.x;
2471 margins.cxRightWidth = clientBounds.width - largest.XMost();
2472 margins.cyBottomHeight = clientBounds.height - largest.YMost();
2474 // The minimum glass height must be the caption buttons height,
2475 // otherwise the buttons are drawn incorrectly.
2476 margins.cyTopHeight = PR_MAX(largest.y, mCaptionButtons.height);
2479 // Only update glass area if there are changes
2480 if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) {
2481 mGlassMargins = margins;
2482 UpdateGlass();
2484 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2487 void nsWindow::UpdateGlass()
2489 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2490 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
2491 MARGINS margins = mGlassMargins;
2493 // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is
2494 // rendered based on the window style.
2495 // DWMNCRP_ENABLED - The non-client area rendering is
2496 // enabled; the window style is ignored.
2497 DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE;
2498 switch (mTransparencyMode) {
2499 case eTransparencyBorderlessGlass:
2500 // Only adjust if there is some opaque rectangle
2501 if (margins.cxLeftWidth >= 0) {
2502 const PRInt32 kGlassMarginAdjustment = 2;
2503 margins.cxLeftWidth += kGlassMarginAdjustment;
2504 margins.cyTopHeight += kGlassMarginAdjustment;
2505 margins.cxRightWidth += kGlassMarginAdjustment;
2506 margins.cyBottomHeight += kGlassMarginAdjustment;
2508 // Fall through
2509 case eTransparencyGlass:
2510 policy = DWMNCRP_ENABLED;
2511 break;
2514 // Extends the window frame behind the client area
2515 if(nsUXThemeData::CheckForCompositor()) {
2516 nsUXThemeData::dwmExtendFrameIntoClientAreaPtr(hWnd, &margins);
2517 nsUXThemeData::dwmSetWindowAttributePtr(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy);
2519 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2521 #endif
2523 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
2524 void nsWindow::UpdateCaptionButtonsClippingRect()
2526 NS_ASSERTION(mWnd, "UpdateCaptionButtonsClippingRect called with invalid mWnd.");
2528 RECT captionButtons;
2529 mCaptionButtonsRoundedRegion.SetEmpty();
2530 mCaptionButtons.Empty();
2532 if (!mCustomNonClient ||
2533 mSizeMode == nsSizeMode_Fullscreen ||
2534 mSizeMode == nsSizeMode_Minimized ||
2535 !nsUXThemeData::CheckForCompositor() ||
2536 FAILED(nsUXThemeData::dwmGetWindowAttributePtr(mWnd,
2537 DWMWA_CAPTION_BUTTON_BOUNDS,
2538 &captionButtons,
2539 sizeof(captionButtons)))) {
2540 return;
2543 mCaptionButtons = nsWindowGfx::ToIntRect(captionButtons);
2545 // Adjustments to reported area
2546 PRInt32 leftMargin = (mNonClientMargins.left == -1) ? mHorResizeMargin : mNonClientMargins.left;
2548 // "leftMargin - 1" represents the resizer border and an
2549 // one pixel adjustment to hide the semi-transparent highlight.
2550 // The extra width is already excluded when the window is maximized.
2551 mCaptionButtons.x -= leftMargin - 1;
2553 if (mSizeMode != nsSizeMode_Maximized) {
2554 mCaptionButtons.width += leftMargin - 1;
2555 mCaptionButtons.height -= mVertResizeMargin + 1;
2556 } else {
2557 // Adjustments to the buttons' shift from the edge of the screen,
2558 // plus some apparently transparent drop shadow below them.
2559 mCaptionButtons.width -= 2;
2560 mCaptionButtons.height -= 3;
2563 // Create a rounded region by shrinking the 2 bottommost pixel rows from
2564 // the rect by 1 and 2 pixels.
2565 // mCaptionButtons: mCaptionButtonsRoundedRegion:
2566 // +-----------+ +-----------+
2567 // | | | |
2568 // | | | |
2569 // +-----------+ +-------+
2570 nsIntRect round1(mCaptionButtons.x, mCaptionButtons.y,
2571 mCaptionButtons.width, mCaptionButtons.height - 2);
2572 nsIntRect round2(mCaptionButtons.x + 1, mCaptionButtons.YMost() - 2,
2573 mCaptionButtons.width - 2, 1);
2574 nsIntRect round3(mCaptionButtons.x + 2, mCaptionButtons.YMost() - 1,
2575 mCaptionButtons.width - 4, 1);
2576 mCaptionButtonsRoundedRegion.Or(mCaptionButtonsRoundedRegion, round1);
2577 mCaptionButtonsRoundedRegion.Or(mCaptionButtonsRoundedRegion, round2);
2578 mCaptionButtonsRoundedRegion.Or(mCaptionButtonsRoundedRegion, round3);
2580 #endif
2582 /**************************************************************
2584 * SECTION: nsIWidget::HideWindowChrome
2586 * Show or hide window chrome.
2588 **************************************************************/
2590 NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide)
2592 HWND hwnd = GetTopLevelHWND(mWnd, PR_TRUE);
2593 if (!GetNSWindowPtr(hwnd))
2595 NS_WARNING("Trying to hide window decorations in an embedded context");
2596 return NS_ERROR_FAILURE;
2599 if (mHideChrome == aShouldHide)
2600 return NS_OK;
2602 DWORD_PTR style, exStyle;
2603 mHideChrome = aShouldHide;
2604 if (aShouldHide) {
2605 DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2606 DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2608 style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
2609 exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
2610 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
2612 mOldStyle = tempStyle;
2613 mOldExStyle = tempExStyle;
2615 else {
2616 if (!mOldStyle || !mOldExStyle) {
2617 mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
2618 mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
2621 style = mOldStyle;
2622 exStyle = mOldExStyle;
2625 VERIFY_WINDOW_STYLE(style);
2626 ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
2627 ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
2629 return NS_OK;
2632 /**************************************************************
2634 * SECTION: nsIWidget::Invalidate
2636 * Invalidate an area of the client for painting.
2638 **************************************************************/
2640 // Invalidate this component visible area
2641 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
2643 if (mWnd)
2645 #ifdef WIDGET_DEBUG_OUTPUT
2646 debug_DumpInvalidate(stdout,
2647 this,
2648 nsnull,
2649 aIsSynchronous,
2650 nsCAutoString("noname"),
2651 (PRInt32) mWnd);
2652 #endif // WIDGET_DEBUG_OUTPUT
2654 VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
2656 if (aIsSynchronous) {
2657 VERIFY(::UpdateWindow(mWnd));
2660 return NS_OK;
2663 // Invalidate this component visible area
2664 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, PRBool aIsSynchronous)
2666 if (mWnd)
2668 #ifdef WIDGET_DEBUG_OUTPUT
2669 debug_DumpInvalidate(stdout,
2670 this,
2671 &aRect,
2672 aIsSynchronous,
2673 nsCAutoString("noname"),
2674 (PRInt32) mWnd);
2675 #endif // WIDGET_DEBUG_OUTPUT
2677 RECT rect;
2679 rect.left = aRect.x;
2680 rect.top = aRect.y;
2681 rect.right = aRect.x + aRect.width;
2682 rect.bottom = aRect.y + aRect.height;
2684 VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
2686 if (aIsSynchronous) {
2687 VERIFY(::UpdateWindow(mWnd));
2690 return NS_OK;
2693 NS_IMETHODIMP
2694 nsWindow::MakeFullScreen(PRBool aFullScreen)
2696 #if WINCE_WINDOWS_MOBILE
2697 RECT rc;
2698 if (aFullScreen) {
2699 SetForegroundWindow(mWnd);
2700 if (nsWindowCE::sMenuBarShown) {
2701 SIPINFO sipInfo;
2702 memset(&sipInfo, 0, sizeof(SIPINFO));
2703 sipInfo.cbSize = sizeof(SIPINFO);
2704 if (SipGetInfo(&sipInfo))
2705 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2706 sipInfo.rcVisibleDesktop.bottom);
2707 else
2708 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN),
2709 GetSystemMetrics(SM_CYSCREEN));
2710 RECT menuBarRect;
2711 if (GetWindowRect(nsWindowCE::sSoftKeyMenuBarHandle, &menuBarRect) &&
2712 menuBarRect.top < rc.bottom)
2713 rc.bottom = menuBarRect.top;
2714 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_SHOWSIPBUTTON);
2715 } else {
2717 SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);
2718 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2721 else {
2722 SHFullScreen(mWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
2723 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
2726 if (aFullScreen)
2727 mSizeMode = nsSizeMode_Fullscreen;
2729 // nsBaseWidget hides the chrome and resizes the window, replicate that here
2730 HideWindowChrome(aFullScreen);
2731 Resize(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PR_TRUE);
2733 return NS_OK;
2735 #else
2737 mFullscreenMode = aFullScreen;
2738 if (aFullScreen) {
2739 if (mSizeMode == nsSizeMode_Fullscreen)
2740 return NS_OK;
2741 mOldSizeMode = mSizeMode;
2742 SetSizeMode(nsSizeMode_Fullscreen);
2743 } else {
2744 SetSizeMode(mOldSizeMode);
2747 UpdateNonClientMargins();
2749 // Will call hide chrome, reposition window. Note this will
2750 // also cache dimensions for restoration, so it should only
2751 // be called once per fullscreen request.
2752 nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen);
2754 // Let the dom know via web shell window
2755 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
2756 event.mSizeMode = mSizeMode;
2757 InitEvent(event);
2758 DispatchWindowEvent(&event);
2760 return rv;
2761 #endif
2764 /**************************************************************
2766 * SECTION: nsIWidget::Update
2768 * Force a synchronous repaint of the window.
2770 **************************************************************/
2772 NS_IMETHODIMP nsWindow::Update()
2774 nsresult rv = NS_OK;
2776 // updates can come through for windows no longer holding an mWnd during
2777 // deletes triggered by JavaScript in buttons with mouse feedback
2778 if (mWnd)
2779 VERIFY(::UpdateWindow(mWnd));
2781 return rv;
2784 /**************************************************************
2786 * SECTION: Native data storage
2788 * nsIWidget::GetNativeData
2789 * nsIWidget::FreeNativeData
2791 * Set or clear native data based on a constant.
2793 **************************************************************/
2795 // Return some native data according to aDataType
2796 void* nsWindow::GetNativeData(PRUint32 aDataType)
2798 switch (aDataType) {
2799 case NS_NATIVE_TMP_WINDOW:
2800 return (void*)::CreateWindowExW(WS_EX_NOACTIVATE |
2801 mIsRTL ? WS_EX_LAYOUTRTL : 0,
2802 WindowClass(),
2803 L"",
2804 WS_CHILD,
2805 CW_USEDEFAULT,
2806 CW_USEDEFAULT,
2807 CW_USEDEFAULT,
2808 CW_USEDEFAULT,
2809 mWnd,
2810 NULL,
2811 nsToolkit::mDllInstance,
2812 NULL);
2813 case NS_NATIVE_PLUGIN_PORT:
2814 case NS_NATIVE_WIDGET:
2815 case NS_NATIVE_WINDOW:
2816 return (void*)mWnd;
2817 case NS_NATIVE_GRAPHIC:
2818 // XXX: This is sleezy!! Remember to Release the DC after using it!
2819 #ifdef MOZ_XUL
2820 return (void*)(eTransparencyTransparent == mTransparencyMode) ?
2821 mMemoryDC : ::GetDC(mWnd);
2822 #else
2823 return (void*)::GetDC(mWnd);
2824 #endif
2826 #ifdef NS_ENABLE_TSF
2827 case NS_NATIVE_TSF_THREAD_MGR:
2828 return nsTextStore::GetThreadMgr();
2829 case NS_NATIVE_TSF_CATEGORY_MGR:
2830 return nsTextStore::GetCategoryMgr();
2831 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
2832 return nsTextStore::GetDisplayAttrMgr();
2833 #endif //NS_ENABLE_TSF
2835 default:
2836 break;
2839 return NULL;
2842 // Free some native data according to aDataType
2843 void nsWindow::FreeNativeData(void * data, PRUint32 aDataType)
2845 switch (aDataType)
2847 case NS_NATIVE_GRAPHIC:
2848 #ifdef MOZ_XUL
2849 if (eTransparencyTransparent != mTransparencyMode)
2850 ::ReleaseDC(mWnd, (HDC)data);
2851 #else
2852 ::ReleaseDC(mWnd, (HDC)data);
2853 #endif
2854 break;
2855 case NS_NATIVE_WIDGET:
2856 case NS_NATIVE_WINDOW:
2857 case NS_NATIVE_PLUGIN_PORT:
2858 break;
2859 default:
2860 break;
2864 /**************************************************************
2866 * SECTION: nsIWidget::SetTitle
2868 * Set the main windows title text.
2870 **************************************************************/
2872 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
2874 const nsString& strTitle = PromiseFlatString(aTitle);
2875 ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get());
2876 return NS_OK;
2879 /**************************************************************
2881 * SECTION: nsIWidget::SetIcon
2883 * Set the main windows icon.
2885 **************************************************************/
2887 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec)
2889 #ifndef WINCE
2890 // Assume the given string is a local identifier for an icon file.
2892 nsCOMPtr<nsILocalFile> iconFile;
2893 ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
2894 getter_AddRefs(iconFile));
2895 if (!iconFile)
2896 return NS_OK; // not an error if icon is not found
2898 nsAutoString iconPath;
2899 iconFile->GetPath(iconPath);
2901 // XXX this should use MZLU (see bug 239279)
2903 ::SetLastError(0);
2905 HICON bigIcon = (HICON)::LoadImageW(NULL,
2906 (LPCWSTR)iconPath.get(),
2907 IMAGE_ICON,
2908 ::GetSystemMetrics(SM_CXICON),
2909 ::GetSystemMetrics(SM_CYICON),
2910 LR_LOADFROMFILE );
2911 HICON smallIcon = (HICON)::LoadImageW(NULL,
2912 (LPCWSTR)iconPath.get(),
2913 IMAGE_ICON,
2914 ::GetSystemMetrics(SM_CXSMICON),
2915 ::GetSystemMetrics(SM_CYSMICON),
2916 LR_LOADFROMFILE );
2918 if (bigIcon) {
2919 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon);
2920 if (icon)
2921 ::DestroyIcon(icon);
2923 #ifdef DEBUG_SetIcon
2924 else {
2925 NS_LossyConvertUTF16toASCII cPath(iconPath);
2926 printf( "\nIcon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2928 #endif
2929 if (smallIcon) {
2930 HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon);
2931 if (icon)
2932 ::DestroyIcon(icon);
2934 #ifdef DEBUG_SetIcon
2935 else {
2936 NS_LossyConvertUTF16toASCII cPath(iconPath);
2937 printf( "\nSmall icon load error; icon=%s, rc=0x%08X\n\n", cPath.get(), ::GetLastError() );
2939 #endif
2940 #endif // WINCE
2941 return NS_OK;
2944 /**************************************************************
2946 * SECTION: nsIWidget::WidgetToScreenOffset
2948 * Return this widget's origin in screen coordinates.
2950 **************************************************************/
2952 nsIntPoint nsWindow::WidgetToScreenOffset()
2954 POINT point;
2955 point.x = 0;
2956 point.y = 0;
2957 ::ClientToScreen(mWnd, &point);
2958 return nsIntPoint(point.x, point.y);
2961 nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize)
2963 if (!IsPopupWithTitleBar())
2964 return aClientSize;
2966 // just use (200, 200) as the position
2967 RECT r;
2968 r.left = 200;
2969 r.top = 200;
2970 r.right = 200 + aClientSize.width;
2971 r.bottom = 200 + aClientSize.height;
2972 ::AdjustWindowRectEx(&r, WindowStyle(), PR_FALSE, WindowExStyle());
2974 return nsIntSize(r.right - r.left, r.bottom - r.top);
2977 /**************************************************************
2979 * SECTION: nsIWidget::EnableDragDrop
2981 * Enables/Disables drag and drop of files on this widget.
2983 **************************************************************/
2985 #if !defined(WINCE) // implemented in nsWindowCE.cpp
2986 NS_METHOD nsWindow::EnableDragDrop(PRBool aEnable)
2988 NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()");
2990 nsresult rv = NS_ERROR_FAILURE;
2991 if (aEnable) {
2992 if (nsnull == mNativeDragTarget) {
2993 mNativeDragTarget = new nsNativeDragTarget(this);
2994 if (NULL != mNativeDragTarget) {
2995 mNativeDragTarget->AddRef();
2996 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) {
2997 if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) {
2998 rv = NS_OK;
3003 } else {
3004 if (nsnull != mWnd && NULL != mNativeDragTarget) {
3005 ::RevokeDragDrop(mWnd);
3006 if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) {
3007 rv = NS_OK;
3009 mNativeDragTarget->DragCancel();
3010 NS_RELEASE(mNativeDragTarget);
3013 return rv;
3015 #endif
3017 /**************************************************************
3019 * SECTION: nsIWidget::CaptureMouse
3021 * Enables/Disables system mouse capture.
3023 **************************************************************/
3025 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
3027 if (!nsToolkit::gMouseTrailer) {
3028 NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed");
3029 return NS_OK;
3032 if (aCapture) {
3033 nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd);
3034 ::SetCapture(mWnd);
3035 } else {
3036 nsToolkit::gMouseTrailer->SetCaptureWindow(NULL);
3037 ::ReleaseCapture();
3039 mIsInMouseCapture = aCapture;
3040 return NS_OK;
3043 /**************************************************************
3045 * SECTION: nsIWidget::CaptureRollupEvents
3047 * Dealing with event rollup on destroy for popups. Enables &
3048 * Disables system capture of any and all events that would
3049 * cause a dropdown to be rolled up.
3051 **************************************************************/
3053 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
3054 nsIMenuRollup * aMenuRollup,
3055 PRBool aDoCapture,
3056 PRBool aConsumeRollupEvent)
3058 if (aDoCapture) {
3059 /* we haven't bothered carrying a weak reference to sRollupWidget because
3060 we believe lifespan is properly scoped. this next assertion helps
3061 assure that remains true. */
3062 NS_ASSERTION(!sRollupWidget, "rollup widget reassigned before release");
3063 sRollupConsumeEvent = aConsumeRollupEvent;
3064 NS_IF_RELEASE(sRollupWidget);
3065 NS_IF_RELEASE(sMenuRollup);
3066 sRollupListener = aListener;
3067 sMenuRollup = aMenuRollup;
3068 NS_IF_ADDREF(aMenuRollup);
3069 sRollupWidget = this;
3070 NS_ADDREF(this);
3072 #ifndef WINCE
3073 if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
3074 RegisterSpecialDropdownHooks();
3076 sProcessHook = PR_TRUE;
3077 #endif
3079 } else {
3080 sRollupListener = nsnull;
3081 NS_IF_RELEASE(sMenuRollup);
3082 NS_IF_RELEASE(sRollupWidget);
3084 #ifndef WINCE
3085 sProcessHook = PR_FALSE;
3086 UnregisterSpecialDropdownHooks();
3087 #endif
3090 return NS_OK;
3093 /**************************************************************
3095 * SECTION: nsIWidget::GetAttention
3097 * Bring this window to the user's attention.
3099 **************************************************************/
3101 // Draw user's attention to this window until it comes to foreground.
3102 NS_IMETHODIMP
3103 nsWindow::GetAttention(PRInt32 aCycleCount)
3105 #ifndef WINCE
3106 // Got window?
3107 if (!mWnd)
3108 return NS_ERROR_NOT_INITIALIZED;
3110 // Don't flash if the flash count is 0 or if the
3111 // top level window is already active.
3112 HWND fgWnd = ::GetForegroundWindow();
3113 if (aCycleCount == 0 || fgWnd == GetTopLevelHWND(mWnd))
3114 return NS_OK;
3116 HWND flashWnd = mWnd;
3117 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3118 flashWnd = ownerWnd;
3121 // Don't flash if the owner window is active either.
3122 if (fgWnd == flashWnd)
3123 return NS_OK;
3125 DWORD defaultCycleCount = 0;
3126 ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
3128 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3129 FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 };
3130 ::FlashWindowEx(&flashInfo);
3131 #endif
3132 return NS_OK;
3135 void nsWindow::StopFlashing()
3137 #ifndef WINCE
3138 HWND flashWnd = mWnd;
3139 while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) {
3140 flashWnd = ownerWnd;
3143 FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd,
3144 FLASHW_STOP, 0, 0 };
3145 ::FlashWindowEx(&flashInfo);
3146 #endif
3149 /**************************************************************
3151 * SECTION: nsIWidget::HasPendingInputEvent
3153 * Ask whether there user input events pending. All input events are
3154 * included, including those not targeted at this nsIwidget instance.
3156 **************************************************************/
3158 PRBool
3159 nsWindow::HasPendingInputEvent()
3161 // If there is pending input or the user is currently
3162 // moving the window then return true.
3163 // Note: When the user is moving the window WIN32 spins
3164 // a separate event loop and input events are not
3165 // reported to the application.
3166 if (HIWORD(GetQueueStatus(QS_INPUT)))
3167 return PR_TRUE;
3168 #ifdef WINCE
3169 return PR_FALSE;
3170 #else
3171 GUITHREADINFO guiInfo;
3172 guiInfo.cbSize = sizeof(GUITHREADINFO);
3173 if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo))
3174 return PR_FALSE;
3175 return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE);
3176 #endif
3179 /**************************************************************
3181 * SECTION: nsIWidget::GetLayerManager
3183 * Get the layer manager associated with this widget.
3185 **************************************************************/
3187 mozilla::layers::LayerManager*
3188 nsWindow::GetLayerManager()
3190 #ifndef WINCE
3191 if (!mLayerManager) {
3192 nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3194 PRBool accelerateByDefault = PR_TRUE;
3195 PRBool disableAcceleration = PR_FALSE;
3196 PRBool preferOpenGL = PR_FALSE;
3197 if (prefs) {
3198 prefs->GetBoolPref("layers.accelerate-all",
3199 &accelerateByDefault);
3200 prefs->GetBoolPref("layers.accelerate-none",
3201 &disableAcceleration);
3202 prefs->GetBoolPref("layers.prefer-opengl",
3203 &preferOpenGL);
3206 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
3207 accelerateByDefault = accelerateByDefault ||
3208 (acceleratedEnv && (*acceleratedEnv != '0'));
3210 /* We don't currently support using an accelerated layer manager with
3211 * transparent windows so don't even try. I'm also not sure if we even
3212 * want to support this case. See bug #593471 */
3213 disableAcceleration = disableAcceleration ||
3214 eTransparencyTransparent == mTransparencyMode;
3216 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
3217 PRBool safeMode = PR_FALSE;
3218 if (xr)
3219 xr->GetInSafeMode(&safeMode);
3221 if (disableAcceleration || safeMode)
3222 mUseAcceleratedRendering = PR_FALSE;
3223 else if (accelerateByDefault)
3224 mUseAcceleratedRendering = PR_TRUE;
3226 if (mUseAcceleratedRendering) {
3227 #ifdef MOZ_ENABLE_D3D9_LAYER
3228 if (!preferOpenGL) {
3229 nsRefPtr<mozilla::layers::LayerManagerD3D9> layerManager =
3230 new mozilla::layers::LayerManagerD3D9(this);
3231 if (layerManager->Initialize()) {
3232 mLayerManager = layerManager;
3235 #endif
3236 if (!mLayerManager && preferOpenGL) {
3237 nsRefPtr<mozilla::layers::LayerManagerOGL> layerManager =
3238 new mozilla::layers::LayerManagerOGL(this);
3239 if (layerManager->Initialize()) {
3240 mLayerManager = layerManager;
3245 // Fall back to software if we couldn't use any hardware backends.
3246 if (!mLayerManager)
3247 mLayerManager = new BasicLayerManager(this);
3249 #endif
3251 return mLayerManager;
3254 /**************************************************************
3256 * SECTION: nsIWidget::GetThebesSurface
3258 * Get the Thebes surface associated with this widget.
3260 **************************************************************/
3262 gfxASurface *nsWindow::GetThebesSurface()
3264 #ifdef CAIRO_HAS_D2D_SURFACE
3265 if (mD2DWindowSurface) {
3266 return mD2DWindowSurface;
3268 #endif
3269 if (mPaintDC)
3270 return (new gfxWindowsSurface(mPaintDC));
3272 #ifdef CAIRO_HAS_D2D_SURFACE
3273 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
3274 gfxWindowsPlatform::RENDER_DIRECT2D) {
3275 gfxASurface::gfxContentType content = gfxASurface::CONTENT_COLOR;
3276 #if defined(MOZ_XUL)
3277 if (mTransparencyMode != eTransparencyOpaque) {
3278 content = gfxASurface::CONTENT_COLOR_ALPHA;
3280 #endif
3281 return (new gfxD2DSurface(mWnd, content));
3282 } else {
3283 #endif
3284 PRUint32 flags = gfxWindowsSurface::FLAG_TAKE_DC;
3285 if (mTransparencyMode != eTransparencyOpaque) {
3286 flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT;
3288 return (new gfxWindowsSurface(mWnd, flags));
3289 #ifdef CAIRO_HAS_D2D_SURFACE
3291 #endif
3294 /**************************************************************
3296 * SECTION: nsIWidget::OnDefaultButtonLoaded
3298 * Called after the dialog is loaded and it has a default button.
3300 **************************************************************/
3302 NS_IMETHODIMP
3303 nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect)
3305 #ifdef WINCE
3306 return NS_ERROR_NOT_IMPLEMENTED;
3307 #else
3308 if (aButtonRect.IsEmpty())
3309 return NS_OK;
3311 // Don't snap when we are not active.
3312 HWND activeWnd = ::GetActiveWindow();
3313 if (activeWnd != ::GetForegroundWindow() ||
3314 GetTopLevelHWND(mWnd, PR_TRUE) != GetTopLevelHWND(activeWnd, PR_TRUE)) {
3315 return NS_OK;
3318 PRBool isAlwaysSnapCursor = PR_FALSE;
3319 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
3320 if (prefs) {
3321 nsCOMPtr<nsIPrefBranch> prefBranch;
3322 prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
3323 if (prefBranch) {
3324 prefBranch->GetBoolPref("ui.cursor_snapping.always_enabled",
3325 &isAlwaysSnapCursor);
3329 if (!isAlwaysSnapCursor) {
3330 BOOL snapDefaultButton;
3331 if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0,
3332 &snapDefaultButton, 0) || !snapDefaultButton)
3333 return NS_OK;
3336 nsIntRect widgetRect;
3337 nsresult rv = GetScreenBounds(widgetRect);
3338 NS_ENSURE_SUCCESS(rv, rv);
3339 nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft());
3341 nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2,
3342 buttonRect.y + buttonRect.height / 2);
3343 // The center of the button can be outside of the widget.
3344 // E.g., it could be hidden by scrolling.
3345 if (!widgetRect.Contains(centerOfButton)) {
3346 return NS_OK;
3349 if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) {
3350 NS_ERROR("SetCursorPos failed");
3351 return NS_ERROR_FAILURE;
3353 return NS_OK;
3354 #endif
3357 NS_IMETHODIMP
3358 nsWindow::OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta,
3359 PRBool aIsHorizontal,
3360 PRInt32 &aOverriddenDelta)
3362 // The default vertical and horizontal scrolling speed is 3, this is defined
3363 // on the document of SystemParametersInfo in MSDN.
3364 const PRUint32 kSystemDefaultScrollingSpeed = 3;
3366 PRInt32 absOriginDelta = PR_ABS(aOriginalDelta);
3368 // Compute the simple overridden speed.
3369 PRInt32 absComputedOverriddenDelta;
3370 nsresult rv =
3371 nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDelta, aIsHorizontal,
3372 absComputedOverriddenDelta);
3373 NS_ENSURE_SUCCESS(rv, rv);
3375 aOverriddenDelta = aOriginalDelta;
3377 if (absComputedOverriddenDelta == absOriginDelta) {
3378 // We don't override now.
3379 return NS_OK;
3382 // Otherwise, we should check whether the user customized the system settings
3383 // or not. If the user did it, we should respect the will.
3384 UINT systemSpeed;
3385 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) {
3386 return NS_ERROR_FAILURE;
3388 // The default vertical scrolling speed is 3, this is defined on the document
3389 // of SystemParametersInfo in MSDN.
3390 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3391 return NS_OK;
3394 // Only Vista and later, Windows has the system setting of horizontal
3395 // scrolling by the mouse wheel.
3396 if (GetWindowsVersion() >= VISTA_VERSION) {
3397 if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) {
3398 return NS_ERROR_FAILURE;
3400 // The default horizontal scrolling speed is 3, this is defined on the
3401 // document of SystemParametersInfo in MSDN.
3402 if (systemSpeed != kSystemDefaultScrollingSpeed) {
3403 return NS_OK;
3407 // Limit the overridden delta value from the system settings. The mouse
3408 // driver might accelerate the scrolling speed already. If so, we shouldn't
3409 // override the scrolling speed for preventing the unexpected high speed
3410 // scrolling.
3411 PRInt32 absDeltaLimit;
3412 rv =
3413 nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed,
3414 aIsHorizontal, absDeltaLimit);
3415 NS_ENSURE_SUCCESS(rv, rv);
3417 // If the given delta is larger than our computed limitation value, the delta
3418 // was accelerated by the mouse driver. So, we should do nothing here.
3419 if (absDeltaLimit <= absOriginDelta) {
3420 return NS_OK;
3423 absComputedOverriddenDelta =
3424 PR_MIN(absComputedOverriddenDelta, absDeltaLimit);
3426 aOverriddenDelta = (aOriginalDelta > 0) ? absComputedOverriddenDelta :
3427 -absComputedOverriddenDelta;
3428 return NS_OK;
3431 /**************************************************************
3432 **************************************************************
3434 ** BLOCK: Moz Events
3436 ** Moz GUI event management.
3438 **************************************************************
3439 **************************************************************/
3441 /**************************************************************
3443 * SECTION: Mozilla event initialization
3445 * Helpers for initializing moz events.
3447 **************************************************************/
3449 // Event intialization
3450 MSG nsWindow::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam)
3452 MSG msg;
3453 msg.message = aMessage;
3454 msg.wParam = wParam;
3455 msg.lParam = lParam;
3456 return msg;
3459 void nsWindow::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
3461 if (nsnull == aPoint) { // use the point from the event
3462 // get the message position in client coordinates
3463 if (mWnd != NULL) {
3465 DWORD pos = ::GetMessagePos();
3466 POINT cpos;
3468 cpos.x = GET_X_LPARAM(pos);
3469 cpos.y = GET_Y_LPARAM(pos);
3471 ::ScreenToClient(mWnd, &cpos);
3472 event.refPoint.x = cpos.x;
3473 event.refPoint.y = cpos.y;
3474 } else {
3475 event.refPoint.x = 0;
3476 event.refPoint.y = 0;
3479 else {
3480 // use the point override if provided
3481 event.refPoint.x = aPoint->x;
3482 event.refPoint.y = aPoint->y;
3485 #ifndef WINCE
3486 event.time = ::GetMessageTime();
3487 #else
3488 event.time = PR_Now() / 1000;
3489 #endif
3491 mLastPoint = event.refPoint;
3494 /**************************************************************
3496 * SECTION: Moz event dispatch helpers
3498 * Helpers for dispatching different types of moz events.
3500 **************************************************************/
3502 // Main event dispatch. Invokes callback and ProcessEvent method on
3503 // Event Listener object. Part of nsIWidget.
3504 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
3506 #ifdef WIDGET_DEBUG_OUTPUT
3507 debug_DumpEvent(stdout,
3508 event->widget,
3509 event,
3510 nsCAutoString("something"),
3511 (PRInt32) mWnd);
3512 #endif // WIDGET_DEBUG_OUTPUT
3514 aStatus = nsEventStatus_eIgnore;
3516 // skip processing of suppressed blur events
3517 if (event->message == NS_DEACTIVATE && BlurEventsSuppressed())
3518 return NS_OK;
3520 // Top level windows can have a view attached which requires events be sent
3521 // to the underlying base window and the view. Added when we combined the
3522 // base chrome window with the main content child for nc client area (title
3523 // bar) rendering.
3524 if (mViewCallback) {
3525 // A subset of events are sent to the base xul window first
3526 switch(event->message) {
3527 // send to the base window (view mgr ignores these for the view)
3528 case NS_UISTATECHANGED:
3529 case NS_DESTROY:
3530 case NS_SETZLEVEL:
3531 case NS_XUL_CLOSE:
3532 case NS_MOVE:
3533 (*mEventCallback)(event); // web shell / xul window
3534 return NS_OK;
3536 // sent to the base window, then to the view
3537 case NS_SIZE:
3538 case NS_DEACTIVATE:
3539 case NS_ACTIVATE:
3540 case NS_SIZEMODE:
3541 (*mEventCallback)(event); // web shell / xul window
3542 break;
3544 // attached view events
3545 aStatus = (*mViewCallback)(event);
3547 else if (mEventCallback) {
3548 aStatus = (*mEventCallback)(event);
3551 // the window can be destroyed during processing of seemingly innocuous events like, say,
3552 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
3553 // which causes problems with the deleted window. therefore:
3554 if (mOnDestroyCalled)
3555 aStatus = nsEventStatus_eConsumeNoDefault;
3556 return NS_OK;
3559 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
3561 nsGUIEvent event(PR_TRUE, aMsg, this);
3562 InitEvent(event);
3564 PRBool result = DispatchWindowEvent(&event);
3565 return result;
3568 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
3570 nsEventStatus status;
3571 DispatchEvent(event, status);
3572 return ConvertStatus(status);
3575 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event, nsEventStatus &aStatus) {
3576 DispatchEvent(event, aStatus);
3577 return ConvertStatus(aStatus);
3580 PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
3581 const nsTArray<nsAlternativeCharCode>* aAlternativeCharCodes,
3582 UINT aVirtualCharCode, const MSG *aMsg,
3583 const nsModifierKeyState &aModKeyState,
3584 PRUint32 aFlags)
3586 UserActivity();
3588 nsKeyEvent event(PR_TRUE, aEventType, this);
3589 nsIntPoint point(0, 0);
3591 InitEvent(event, &point); // this add ref's event.widget
3593 event.flags |= aFlags;
3594 event.charCode = aCharCode;
3595 if (aAlternativeCharCodes)
3596 event.alternativeCharCodes.AppendElements(*aAlternativeCharCodes);
3597 event.keyCode = aVirtualCharCode;
3599 #ifdef KE_DEBUG
3600 static cnt=0;
3601 printf("%d DispatchKE Type: %s charCode %d keyCode %d ", cnt++,
3602 (NS_KEY_PRESS == aEventType) ? "PRESS" : (aEventType == NS_KEY_UP ? "Up" : "Down"),
3603 event.charCode, event.keyCode);
3604 printf("Shift: %s Control %s Alt: %s \n",
3605 (mIsShiftDown ? "D" : "U"), (mIsControlDown ? "D" : "U"), (mIsAltDown ? "D" : "U"));
3606 printf("[%c][%c][%c] <== [%c][%c][%c][ space bar ][%c][%c][%c]\n",
3607 IS_VK_DOWN(NS_VK_SHIFT) ? 'S' : ' ',
3608 IS_VK_DOWN(NS_VK_CONTROL) ? 'C' : ' ',
3609 IS_VK_DOWN(NS_VK_ALT) ? 'A' : ' ',
3610 IS_VK_DOWN(VK_LSHIFT) ? 'S' : ' ',
3611 IS_VK_DOWN(VK_LCONTROL) ? 'C' : ' ',
3612 IS_VK_DOWN(VK_LMENU) ? 'A' : ' ',
3613 IS_VK_DOWN(VK_RMENU) ? 'A' : ' ',
3614 IS_VK_DOWN(VK_RCONTROL) ? 'C' : ' ',
3615 IS_VK_DOWN(VK_RSHIFT) ? 'S' : ' ');
3616 #endif
3618 event.isShift = aModKeyState.mIsShiftDown;
3619 event.isControl = aModKeyState.mIsControlDown;
3620 event.isMeta = PR_FALSE;
3621 event.isAlt = aModKeyState.mIsAltDown;
3623 NPEvent pluginEvent;
3624 if (aMsg && PluginHasFocus()) {
3625 pluginEvent.event = aMsg->message;
3626 pluginEvent.wParam = aMsg->wParam;
3627 pluginEvent.lParam = aMsg->lParam;
3628 event.pluginEvent = (void *)&pluginEvent;
3631 PRBool result = DispatchWindowEvent(&event);
3633 return result;
3636 PRBool nsWindow::DispatchCommandEvent(PRUint32 aEventCommand)
3638 nsCOMPtr<nsIAtom> command;
3639 switch (aEventCommand) {
3640 case APPCOMMAND_BROWSER_BACKWARD:
3641 command = nsWidgetAtoms::Back;
3642 break;
3643 case APPCOMMAND_BROWSER_FORWARD:
3644 command = nsWidgetAtoms::Forward;
3645 break;
3646 case APPCOMMAND_BROWSER_REFRESH:
3647 command = nsWidgetAtoms::Reload;
3648 break;
3649 case APPCOMMAND_BROWSER_STOP:
3650 command = nsWidgetAtoms::Stop;
3651 break;
3652 case APPCOMMAND_BROWSER_SEARCH:
3653 command = nsWidgetAtoms::Search;
3654 break;
3655 case APPCOMMAND_BROWSER_FAVORITES:
3656 command = nsWidgetAtoms::Bookmarks;
3657 break;
3658 case APPCOMMAND_BROWSER_HOME:
3659 command = nsWidgetAtoms::Home;
3660 break;
3661 default:
3662 return PR_FALSE;
3664 nsCommandEvent event(PR_TRUE, nsWidgetAtoms::onAppCommand, command, this);
3666 InitEvent(event);
3667 DispatchWindowEvent(&event);
3669 return PR_TRUE;
3672 // Recursively dispatch synchronous paints for nsIWidget
3673 // descendants with invalidated rectangles.
3674 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
3676 LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
3677 if (proc == (LONG_PTR)&nsWindow::WindowProc) {
3678 // its one of our windows so check to see if it has a
3679 // invalidated rect. If it does. Dispatch a synchronous
3680 // paint.
3681 if (GetUpdateRect(aWnd, NULL, FALSE))
3682 VERIFY(::UpdateWindow(aWnd));
3684 return TRUE;
3687 // Check for pending paints and dispatch any pending paint
3688 // messages for any nsIWidget which is a descendant of the
3689 // top-level window that *this* window is embedded within.
3691 // Note: We do not dispatch pending paint messages for non
3692 // nsIWidget managed windows.
3693 void nsWindow::DispatchPendingEvents()
3695 if (mPainting) {
3696 NS_WARNING("We were asked to dispatch pending events during painting, "
3697 "denying since that's unsafe.");
3698 return;
3701 // We need to ensure that reflow events do not get starved.
3702 // At the same time, we don't want to recurse through here
3703 // as that would prevent us from dispatching starved paints.
3704 static int recursionBlocker = 0;
3705 if (recursionBlocker++ == 0) {
3706 NS_ProcessPendingEvents(nsnull, PR_MillisecondsToInterval(100));
3707 --recursionBlocker;
3710 // Quickly check to see if there are any
3711 // paint events pending.
3712 if (::GetQueueStatus(QS_PAINT)) {
3713 // Find the top level window.
3714 HWND topWnd = GetTopLevelHWND(mWnd);
3716 // Dispatch pending paints for all topWnd's descendant windows.
3717 // Note: EnumChildWindows enumerates all descendant windows not just
3718 // it's children.
3719 #if !defined(WINCE)
3720 ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, 0);
3721 #else
3722 nsWindowCE::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, NULL);
3723 #endif
3727 // Deal with plugin events
3728 PRBool nsWindow::DispatchPluginEvent(const MSG &aMsg)
3730 if (!PluginHasFocus())
3731 return PR_FALSE;
3733 nsGUIEvent event(PR_TRUE, NS_PLUGIN_EVENT, this);
3734 nsIntPoint point(0, 0);
3735 InitEvent(event, &point);
3736 NPEvent pluginEvent;
3737 pluginEvent.event = aMsg.message;
3738 pluginEvent.wParam = aMsg.wParam;
3739 pluginEvent.lParam = aMsg.lParam;
3740 event.pluginEvent = (void *)&pluginEvent;
3741 return DispatchWindowEvent(&event);
3744 PRBool nsWindow::DispatchPluginEvent(UINT aMessage,
3745 WPARAM aWParam,
3746 LPARAM aLParam,
3747 PRBool aDispatchPendingEvents)
3749 PRBool ret = DispatchPluginEvent(InitMSG(aMessage, aWParam, aLParam));
3750 if (aDispatchPendingEvents) {
3751 DispatchPendingEvents();
3753 return ret;
3756 void nsWindow::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
3757 UINT aLastMsg)
3759 MSG msg;
3760 ::GetMessageW(&msg, mWnd, aFirstMsg, aLastMsg);
3761 DispatchPluginEvent(msg);
3764 // Deal with all sort of mouse event
3765 PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
3766 LPARAM lParam, PRBool aIsContextMenuKey,
3767 PRInt16 aButton, PRUint16 aInputSource)
3769 PRBool result = PR_FALSE;
3771 UserActivity();
3773 if (!mEventCallback) {
3774 return result;
3777 switch (aEventType) {
3778 case NS_MOUSE_BUTTON_DOWN:
3779 CaptureMouse(PR_TRUE);
3780 break;
3782 // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
3783 // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
3784 case NS_MOUSE_BUTTON_UP:
3785 case NS_MOUSE_MOVE:
3786 case NS_MOUSE_EXIT:
3787 if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && mIsInMouseCapture)
3788 CaptureMouse(PR_FALSE);
3789 break;
3791 default:
3792 break;
3794 } // switch
3796 nsIntPoint eventPoint;
3797 eventPoint.x = GET_X_LPARAM(lParam);
3798 eventPoint.y = GET_Y_LPARAM(lParam);
3800 nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal,
3801 aIsContextMenuKey
3802 ? nsMouseEvent::eContextMenuKey
3803 : nsMouseEvent::eNormal);
3804 if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) {
3805 nsIntPoint zero(0, 0);
3806 InitEvent(event, &zero);
3807 } else {
3808 InitEvent(event, &eventPoint);
3811 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
3812 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
3813 event.isMeta = PR_FALSE;
3814 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
3815 event.button = aButton;
3816 event.inputSource = aInputSource;
3818 nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
3820 // Suppress mouse moves caused by widget creation
3821 if (aEventType == NS_MOUSE_MOVE)
3823 if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y))
3824 return result;
3825 sLastMouseMovePoint.x = mpScreen.x;
3826 sLastMouseMovePoint.y = mpScreen.y;
3829 PRBool insideMovementThreshold = (abs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
3830 (abs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
3832 BYTE eventButton;
3833 switch (aButton) {
3834 case nsMouseEvent::eLeftButton:
3835 eventButton = VK_LBUTTON;
3836 break;
3837 case nsMouseEvent::eMiddleButton:
3838 eventButton = VK_MBUTTON;
3839 break;
3840 case nsMouseEvent::eRightButton:
3841 eventButton = VK_RBUTTON;
3842 break;
3843 default:
3844 eventButton = 0;
3845 break;
3848 // Doubleclicks are used to set the click count, then changed to mousedowns
3849 // We're going to time double-clicks from mouse *up* to next mouse *down*
3850 #ifndef WINCE
3851 LONG curMsgTime = ::GetMessageTime();
3852 #else
3853 LONG curMsgTime = PR_Now() / 1000;
3854 #endif
3856 if (aEventType == NS_MOUSE_DOUBLECLICK) {
3857 event.message = NS_MOUSE_BUTTON_DOWN;
3858 event.button = aButton;
3859 sLastClickCount = 2;
3861 else if (aEventType == NS_MOUSE_BUTTON_UP) {
3862 // remember when this happened for the next mouse down
3863 sLastMousePoint.x = eventPoint.x;
3864 sLastMousePoint.y = eventPoint.y;
3865 sLastMouseButton = eventButton;
3867 else if (aEventType == NS_MOUSE_BUTTON_DOWN) {
3868 // now look to see if we want to convert this to a double- or triple-click
3869 if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold &&
3870 eventButton == sLastMouseButton) {
3871 sLastClickCount ++;
3872 } else {
3873 // reset the click count, to count *this* click
3874 sLastClickCount = 1;
3876 // Set last Click time on MouseDown only
3877 sLastMouseDownTime = curMsgTime;
3879 else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
3880 sLastClickCount = 0;
3882 else if (aEventType == NS_MOUSE_EXIT) {
3883 event.exit = IsTopLevelMouseExit(mWnd) ? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
3885 else if (aEventType == NS_MOUSE_MOZHITTEST)
3887 event.flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
3889 event.clickCount = sLastClickCount;
3891 #ifdef NS_DEBUG_XX
3892 printf("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount);
3893 #endif
3895 NPEvent pluginEvent;
3897 switch (aEventType)
3899 case NS_MOUSE_BUTTON_DOWN:
3900 switch (aButton) {
3901 case nsMouseEvent::eLeftButton:
3902 pluginEvent.event = WM_LBUTTONDOWN;
3903 break;
3904 case nsMouseEvent::eMiddleButton:
3905 pluginEvent.event = WM_MBUTTONDOWN;
3906 break;
3907 case nsMouseEvent::eRightButton:
3908 pluginEvent.event = WM_RBUTTONDOWN;
3909 break;
3910 default:
3911 break;
3913 break;
3914 case NS_MOUSE_BUTTON_UP:
3915 switch (aButton) {
3916 case nsMouseEvent::eLeftButton:
3917 pluginEvent.event = WM_LBUTTONUP;
3918 break;
3919 case nsMouseEvent::eMiddleButton:
3920 pluginEvent.event = WM_MBUTTONUP;
3921 break;
3922 case nsMouseEvent::eRightButton:
3923 pluginEvent.event = WM_RBUTTONUP;
3924 break;
3925 default:
3926 break;
3928 break;
3929 case NS_MOUSE_DOUBLECLICK:
3930 switch (aButton) {
3931 case nsMouseEvent::eLeftButton:
3932 pluginEvent.event = WM_LBUTTONDBLCLK;
3933 break;
3934 case nsMouseEvent::eMiddleButton:
3935 pluginEvent.event = WM_MBUTTONDBLCLK;
3936 break;
3937 case nsMouseEvent::eRightButton:
3938 pluginEvent.event = WM_RBUTTONDBLCLK;
3939 break;
3940 default:
3941 break;
3943 break;
3944 case NS_MOUSE_MOVE:
3945 pluginEvent.event = WM_MOUSEMOVE;
3946 break;
3947 case NS_MOUSE_EXIT:
3948 pluginEvent.event = WM_MOUSELEAVE;
3949 break;
3950 default:
3951 pluginEvent.event = WM_NULL;
3952 break;
3955 pluginEvent.wParam = wParam; // plugins NEED raw OS event flags!
3956 pluginEvent.lParam = lParam;
3958 event.pluginEvent = (void *)&pluginEvent;
3960 // call the event callback
3961 if (nsnull != mEventCallback) {
3962 if (nsToolkit::gMouseTrailer)
3963 nsToolkit::gMouseTrailer->Disable();
3964 if (aEventType == NS_MOUSE_MOVE) {
3965 if (nsToolkit::gMouseTrailer && !mIsInMouseCapture) {
3966 nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd);
3968 nsIntRect rect;
3969 GetBounds(rect);
3970 rect.x = 0;
3971 rect.y = 0;
3973 if (rect.Contains(event.refPoint)) {
3974 if (sCurrentWindow == NULL || sCurrentWindow != this) {
3975 if ((nsnull != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
3976 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3977 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, PR_FALSE,
3978 nsMouseEvent::eLeftButton, aInputSource);
3980 sCurrentWindow = this;
3981 if (!mInDtor) {
3982 LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
3983 sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, PR_FALSE,
3984 nsMouseEvent::eLeftButton, aInputSource);
3988 } else if (aEventType == NS_MOUSE_EXIT) {
3989 if (sCurrentWindow == this) {
3990 sCurrentWindow = nsnull;
3994 result = DispatchWindowEvent(&event);
3996 if (nsToolkit::gMouseTrailer)
3997 nsToolkit::gMouseTrailer->Enable();
3999 // Release the widget with NS_IF_RELEASE() just in case
4000 // the context menu key code in nsEventListenerManager::HandleEvent()
4001 // released it already.
4002 return result;
4005 return result;
4008 // Deal with accessibile event
4009 #ifdef ACCESSIBILITY
4010 nsAccessible*
4011 nsWindow::DispatchAccessibleEvent(PRUint32 aEventType)
4013 if (nsnull == mEventCallback) {
4014 return nsnull;
4017 nsAccessibleEvent event(PR_TRUE, aEventType, this);
4018 InitEvent(event, nsnull);
4020 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
4021 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
4022 event.isMeta = PR_FALSE;
4023 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
4025 DispatchWindowEvent(&event);
4027 return event.mAccessible;
4029 #endif
4031 PRBool nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType)
4033 if (aEventType == NS_ACTIVATE)
4034 sJustGotActivate = PR_FALSE;
4035 sJustGotDeactivate = PR_FALSE;
4037 // retrive the toplevel window or dialog
4038 HWND curWnd = mWnd;
4039 HWND toplevelWnd = NULL;
4040 while (curWnd) {
4041 toplevelWnd = curWnd;
4043 nsWindow *win = GetNSWindowPtr(curWnd);
4044 if (win) {
4045 nsWindowType wintype;
4046 win->GetWindowType(wintype);
4047 if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog)
4048 break;
4051 curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
4054 if (toplevelWnd) {
4055 nsWindow *win = GetNSWindowPtr(toplevelWnd);
4056 if (win)
4057 return win->DispatchFocus(aEventType);
4060 return PR_FALSE;
4063 // Deal with focus messages
4064 PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
4066 // call the event callback
4067 if (mEventCallback) {
4068 nsGUIEvent event(PR_TRUE, aEventType, this);
4069 InitEvent(event);
4071 //focus and blur event should go to their base widget loc, not current mouse pos
4072 event.refPoint.x = 0;
4073 event.refPoint.y = 0;
4075 NPEvent pluginEvent;
4077 switch (aEventType)
4079 case NS_ACTIVATE:
4080 pluginEvent.event = WM_SETFOCUS;
4081 break;
4082 case NS_DEACTIVATE:
4083 pluginEvent.event = WM_KILLFOCUS;
4084 break;
4085 case NS_PLUGIN_ACTIVATE:
4086 pluginEvent.event = WM_KILLFOCUS;
4087 break;
4088 default:
4089 break;
4092 event.pluginEvent = (void *)&pluginEvent;
4094 return DispatchWindowEvent(&event);
4096 return PR_FALSE;
4099 PRBool nsWindow::IsTopLevelMouseExit(HWND aWnd)
4101 DWORD pos = ::GetMessagePos();
4102 POINT mp;
4103 mp.x = GET_X_LPARAM(pos);
4104 mp.y = GET_Y_LPARAM(pos);
4105 HWND mouseWnd = ::WindowFromPoint(mp);
4107 // GetTopLevelHWND will return a HWND for the window frame (which includes
4108 // the non-client area). If the mouse has moved into the non-client area,
4109 // we should treat it as a top-level exit.
4110 HWND mouseTopLevel = nsWindow::GetTopLevelHWND(mouseWnd);
4111 if (mouseWnd == mouseTopLevel)
4112 return PR_TRUE;
4114 return nsWindow::GetTopLevelHWND(aWnd) != mouseTopLevel;
4117 PRBool nsWindow::BlurEventsSuppressed()
4119 // are they suppressed in this window?
4120 if (mBlurSuppressLevel > 0)
4121 return PR_TRUE;
4123 // are they suppressed by any container widget?
4124 HWND parentWnd = ::GetParent(mWnd);
4125 if (parentWnd) {
4126 nsWindow *parent = GetNSWindowPtr(parentWnd);
4127 if (parent)
4128 return parent->BlurEventsSuppressed();
4130 return PR_FALSE;
4133 // In some circumstances (opening dependent windows) it makes more sense
4134 // (and fixes a crash bug) to not blur the parent window. Called from
4135 // nsFilePicker.
4136 void nsWindow::SuppressBlurEvents(PRBool aSuppress)
4138 if (aSuppress)
4139 ++mBlurSuppressLevel; // for this widget
4140 else {
4141 NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression");
4142 if (mBlurSuppressLevel > 0)
4143 --mBlurSuppressLevel;
4147 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
4149 return aStatus == nsEventStatus_eConsumeNoDefault;
4152 /**************************************************************
4154 * SECTION: IPC
4156 * IPC related helpers.
4158 **************************************************************/
4160 #ifdef MOZ_IPC
4162 // static
4163 bool
4164 nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult)
4166 switch(aMsg) {
4167 case WM_SETFOCUS:
4168 case WM_KILLFOCUS:
4169 case WM_ENABLE:
4170 case WM_WINDOWPOSCHANGING:
4171 case WM_WINDOWPOSCHANGED:
4172 case WM_PARENTNOTIFY:
4173 case WM_ACTIVATEAPP:
4174 case WM_NCACTIVATE:
4175 case WM_ACTIVATE:
4176 case WM_CHILDACTIVATE:
4177 case WM_IME_SETCONTEXT:
4178 case WM_IME_NOTIFY:
4179 case WM_SHOWWINDOW:
4180 case WM_CANCELMODE:
4181 case WM_MOUSEACTIVATE:
4182 case WM_CONTEXTMENU:
4183 aResult = 0;
4184 return true;
4186 case WM_SETTINGCHANGE:
4187 case WM_SETCURSOR:
4188 return false;
4191 #ifdef DEBUG
4192 char szBuf[200];
4193 sprintf(szBuf,
4194 "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg);
4195 NS_WARNING(szBuf);
4196 #endif
4198 return false;
4201 void
4202 nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
4204 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
4205 "Failed to prevent a nonqueued message from running!");
4207 // Modal UI being displayed in windowless plugins.
4208 if (mozilla::ipc::RPCChannel::IsSpinLoopActive() &&
4209 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4210 LRESULT res;
4211 if (IsAsyncResponseEvent(msg, res)) {
4212 ReplyMessage(res);
4214 return;
4217 // Handle certain sync plugin events sent to the parent which
4218 // trigger ipc calls that result in deadlocks.
4220 DWORD dwResult = 0;
4221 PRBool handled = PR_FALSE;
4223 switch(msg) {
4224 // Windowless flash sending WM_ACTIVATE events to the main window
4225 // via calls to ShowWindow.
4226 case WM_ACTIVATE:
4227 if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE &&
4228 IsWindow((HWND)lParam))
4229 handled = PR_TRUE;
4230 break;
4231 // Wheel events forwarded from the child.
4232 case WM_MOUSEWHEEL:
4233 case WM_MOUSEHWHEEL:
4234 case WM_HSCROLL:
4235 case WM_VSCROLL:
4236 // Plugins taking or losing focus triggering focus app messages.
4237 case WM_SETFOCUS:
4238 case WM_KILLFOCUS:
4239 // Windowed plugins that pass sys key events to defwndproc generate
4240 // WM_SYSCOMMAND events to the main window.
4241 case WM_SYSCOMMAND:
4242 // Windowed plugins that fire context menu selection events to parent
4243 // windows.
4244 case WM_CONTEXTMENU:
4245 // IME events fired as a result of synchronous focus changes
4246 case WM_IME_SETCONTEXT:
4247 handled = PR_TRUE;
4248 break;
4251 if (handled &&
4252 (InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
4253 ReplyMessage(dwResult);
4257 #endif // MOZ_IPC
4259 /**************************************************************
4260 **************************************************************
4262 ** BLOCK: Native events
4264 ** Main Windows message handlers and OnXXX handlers for
4265 ** Windows event handling.
4267 **************************************************************
4268 **************************************************************/
4270 /**************************************************************
4272 * SECTION: Wind proc.
4274 * The main Windows event procedures and associated
4275 * message processing methods.
4277 **************************************************************/
4279 #ifdef _MSC_VER
4280 static int ReportException(EXCEPTION_POINTERS *aExceptionInfo)
4282 #ifdef MOZ_CRASHREPORTER
4283 nsCOMPtr<nsICrashReporter> cr =
4284 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
4285 if (cr)
4286 cr->WriteMinidumpForException(aExceptionInfo);
4287 #endif
4288 return EXCEPTION_EXECUTE_HANDLER;
4290 #endif
4292 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
4293 // exceptions and passes the real work to WindowProcInternal. See bug 587406
4294 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
4295 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4297 #ifdef _MSC_VER
4298 __try {
4299 return WindowProcInternal(hWnd, msg, wParam, lParam);
4301 __except(ReportException(GetExceptionInformation())) {
4302 ::TerminateProcess(::GetCurrentProcess(), 253);
4304 #else
4305 return WindowProcInternal(hWnd, msg, wParam, lParam);
4306 #endif
4309 LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4311 NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
4312 MOZ_FUNCTION_NAME, __LINE__, hWnd, msg,
4313 wParam, lParam);
4315 // Get the window which caused the event and ask it to process the message
4316 nsWindow *someWindow = GetNSWindowPtr(hWnd);
4318 #ifdef MOZ_IPC
4319 if (someWindow)
4320 someWindow->IPCWindowProcHandler(msg, wParam, lParam);
4321 #endif
4323 // create this here so that we store the last rolled up popup until after
4324 // the event has been processed.
4325 nsAutoRollup autoRollup;
4327 LRESULT popupHandlingResult;
4328 if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult))
4329 return popupHandlingResult;
4331 // XXX This fixes 50208 and we are leaving 51174 open to further investigate
4332 // why we are hitting this assert
4333 if (nsnull == someWindow) {
4334 NS_ASSERTION(someWindow, "someWindow is null, cannot call any CallWindowProc");
4335 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
4338 // hold on to the window for the life of this method, in case it gets
4339 // deleted during processing. yes, it's a double hack, since someWindow
4340 // is not really an interface.
4341 nsCOMPtr<nsISupports> kungFuDeathGrip;
4342 if (!someWindow->mInDtor) // not if we're in the destructor!
4343 kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)someWindow);
4345 // Call ProcessMessage
4346 LRESULT retValue;
4347 if (PR_TRUE == someWindow->ProcessMessage(msg, wParam, lParam, &retValue)) {
4348 return retValue;
4351 LRESULT res = ::CallWindowProcW(someWindow->GetPrevWindowProc(),
4352 hWnd, msg, wParam, lParam);
4354 return res;
4357 // The main windows message processing method for plugins.
4358 // The result means whether this method processed the native
4359 // event for plugin. If false, the native event should be
4360 // processed by the caller self.
4361 PRBool
4362 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
4363 LRESULT *aResult,
4364 PRBool &aCallDefWndProc)
4366 NS_PRECONDITION(aResult, "aResult must be non-null.");
4367 *aResult = 0;
4369 aCallDefWndProc = PR_FALSE;
4370 PRBool eventDispatched = PR_FALSE;
4371 switch (aMsg.message) {
4372 case WM_CHAR:
4373 case WM_SYSCHAR:
4374 *aResult = ProcessCharMessage(aMsg, &eventDispatched);
4375 break;
4377 case WM_KEYUP:
4378 case WM_SYSKEYUP:
4379 *aResult = ProcessKeyUpMessage(aMsg, &eventDispatched);
4380 break;
4382 case WM_KEYDOWN:
4383 case WM_SYSKEYDOWN:
4384 *aResult = ProcessKeyDownMessage(aMsg, &eventDispatched);
4385 break;
4387 case WM_DEADCHAR:
4388 case WM_SYSDEADCHAR:
4389 case WM_CONTEXTMENU:
4391 case WM_CUT:
4392 case WM_COPY:
4393 case WM_PASTE:
4394 case WM_CLEAR:
4395 case WM_UNDO:
4396 break;
4398 default:
4399 return PR_FALSE;
4402 if (!eventDispatched)
4403 aCallDefWndProc = !DispatchPluginEvent(aMsg);
4404 DispatchPendingEvents();
4405 return PR_TRUE;
4408 // The main windows message processing method.
4409 PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
4410 LRESULT *aRetValue)
4412 // (Large blocks of code should be broken out into OnEvent handlers.)
4413 if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
4414 return PR_TRUE;
4416 #if defined(EVENT_DEBUG_OUTPUT)
4417 // First param shows all events, second param indicates whether
4418 // to show mouse move events. See nsWindowDbg for details.
4419 PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
4420 #endif
4422 PRBool eatMessage;
4423 if (nsIMM32Handler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
4424 eatMessage)) {
4425 return mWnd ? eatMessage : PR_TRUE;
4428 if (PluginHasFocus()) {
4429 PRBool callDefaultWndProc;
4430 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4431 if (ProcessMessageForPlugin(nativeMsg, aRetValue, callDefaultWndProc)) {
4432 return mWnd ? !callDefaultWndProc : PR_TRUE;
4436 PRBool result = PR_FALSE; // call the default nsWindow proc
4437 *aRetValue = 0;
4439 static PRBool getWheelInfo = PR_TRUE;
4441 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4442 // Glass hit testing w/custom transparent margins
4443 LRESULT dwmHitResult;
4444 if (mCustomNonClient &&
4445 nsUXThemeData::CheckForCompositor() &&
4446 nsUXThemeData::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) {
4447 *aRetValue = dwmHitResult;
4448 return PR_TRUE;
4450 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4452 switch (msg) {
4453 #ifndef WINCE
4454 // WM_QUERYENDSESSION must be handled by all windows.
4455 // Otherwise Windows thinks the window can just be killed at will.
4456 case WM_QUERYENDSESSION:
4457 if (sCanQuit == TRI_UNKNOWN)
4459 // Ask if it's ok to quit, and store the answer until we
4460 // get WM_ENDSESSION signaling the round is complete.
4461 nsCOMPtr<nsIObserverService> obsServ =
4462 mozilla::services::GetObserverService();
4463 nsCOMPtr<nsISupportsPRBool> cancelQuit =
4464 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
4465 cancelQuit->SetData(PR_FALSE);
4466 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
4468 PRBool abortQuit;
4469 cancelQuit->GetData(&abortQuit);
4470 sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
4472 *aRetValue = sCanQuit ? TRUE : FALSE;
4473 result = PR_TRUE;
4474 break;
4475 #endif
4477 #ifndef WINCE
4478 case WM_ENDSESSION:
4479 #endif
4480 case MOZ_WM_APP_QUIT:
4481 if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE))
4483 // Let's fake a shutdown sequence without actually closing windows etc.
4484 // to avoid Windows killing us in the middle. A proper shutdown would
4485 // require having a chance to pump some messages. Unfortunately
4486 // Windows won't let us do that. Bug 212316.
4487 nsCOMPtr<nsIObserverService> obsServ =
4488 mozilla::services::GetObserverService();
4489 NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
4490 obsServ->NotifyObservers(nsnull, "quit-application-granted", nsnull);
4491 obsServ->NotifyObservers(nsnull, "quit-application-forced", nsnull);
4492 obsServ->NotifyObservers(nsnull, "quit-application", nsnull);
4493 obsServ->NotifyObservers(nsnull, "profile-change-net-teardown", context.get());
4494 obsServ->NotifyObservers(nsnull, "profile-change-teardown", context.get());
4495 obsServ->NotifyObservers(nsnull, "profile-before-change", context.get());
4496 // Then a controlled but very quick exit.
4497 _exit(0);
4499 sCanQuit = TRI_UNKNOWN;
4500 result = PR_TRUE;
4501 break;
4503 #ifndef WINCE
4504 case WM_DISPLAYCHANGE:
4505 DispatchStandardEvent(NS_DISPLAYCHANGED);
4506 break;
4507 #endif
4509 case WM_SYSCOLORCHANGE:
4510 // Note: This is sent for child windows as well as top-level windows.
4511 // The Win32 toolkit normally only sends these events to top-level windows.
4512 // But we cycle through all of the childwindows and send it to them as well
4513 // so all presentations get notified properly.
4514 // See nsWindow::GlobalMsgWindowProc.
4515 DispatchStandardEvent(NS_SYSCOLORCHANGED);
4516 break;
4518 case WM_NOTIFY:
4519 // TAB change
4521 LPNMHDR pnmh = (LPNMHDR) lParam;
4523 switch (pnmh->code) {
4524 case TCN_SELCHANGE:
4526 DispatchStandardEvent(NS_TABCHANGE);
4527 result = PR_TRUE;
4529 break;
4532 break;
4534 case WM_XP_THEMECHANGED:
4536 // Update non-client margin offsets
4537 UpdateNonClientMargins();
4539 DispatchStandardEvent(NS_THEMECHANGED);
4541 // Invalidate the window so that the repaint will
4542 // pick up the new theme.
4543 Invalidate(PR_FALSE);
4545 break;
4547 case WM_FONTCHANGE:
4549 nsresult rv;
4550 PRBool didChange = PR_FALSE;
4552 // update the global font list
4553 nsCOMPtr<nsIFontEnumerator> fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
4554 if (NS_SUCCEEDED(rv)) {
4555 fontEnum->UpdateFontList(&didChange);
4556 //didChange is TRUE only if new font langGroup is added to the list.
4557 if (didChange) {
4558 // update device context font cache
4559 // Dirty but easiest way:
4560 // Changing nsIPrefBranch entry which triggers callbacks
4561 // and flows into calling mDeviceContext->FlushFontCache()
4562 // to update the font cache in all the instance of Browsers
4563 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
4564 if (prefs) {
4565 nsCOMPtr<nsIPrefBranch> fiPrefs;
4566 prefs->GetBranch("font.internaluseonly.", getter_AddRefs(fiPrefs));
4567 if (fiPrefs) {
4568 PRBool fontInternalChange = PR_FALSE;
4569 fiPrefs->GetBoolPref("changed", &fontInternalChange);
4570 fiPrefs->SetBoolPref("changed", !fontInternalChange);
4574 } //if (NS_SUCCEEDED(rv))
4576 break;
4578 case WM_NCCALCSIZE:
4580 // If wParam is TRUE, it specifies that the application should indicate
4581 // which part of the client area contains valid information. The system
4582 // copies the valid information to the specified area within the new
4583 // client area. If the wParam parameter is FALSE, the application should
4584 // return zero.
4585 if (mCustomNonClient) {
4586 if (!wParam) {
4587 result = PR_TRUE;
4588 *aRetValue = 0;
4589 break;
4592 // before:
4593 // rgrc[0]: the proposed window
4594 // rgrc[1]: the current window
4595 // rgrc[2]: the source client area
4596 // pncsp->lppos: move/size data
4597 // after:
4598 // rgrc[0]: the new client area
4599 // rgrc[1]: the destination window
4600 // rgrc[2]: the source client area
4601 // (all values in screen coordiantes)
4602 NCCALCSIZE_PARAMS *pncsp = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
4603 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd, msg, wParam, lParam);
4604 pncsp->rgrc[0].top -= mNonClientOffset.top;
4605 pncsp->rgrc[0].left -= mNonClientOffset.left;
4606 pncsp->rgrc[0].right += mNonClientOffset.right;
4607 pncsp->rgrc[0].bottom += mNonClientOffset.bottom;
4609 result = PR_TRUE;
4610 *aRetValue = res;
4612 break;
4615 case WM_NCHITTEST:
4618 * If an nc client area margin has been moved, we are responsible
4619 * for calculating where the resize margins are and returning the
4620 * appropriate set of hit test constants. DwmDefWindowProc (above)
4621 * will handle hit testing on it's command buttons if we are on a
4622 * composited desktop.
4625 if (!mCustomNonClient)
4626 break;
4628 *aRetValue =
4629 ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
4630 result = PR_TRUE;
4631 break;
4634 case WM_SETTEXT:
4636 * WM_SETTEXT paints the titlebar area. Avoid this if we have a
4637 * custom titlebar we paint ourselves.
4640 if (!mCustomNonClient || mNonClientMargins.top == -1)
4641 break;
4644 // From msdn, the way around this is to disable the visible state
4645 // temporarily. We need the text to be set but we don't want the
4646 // redraw to occur.
4647 DWORD style = GetWindowLong(mWnd, GWL_STYLE);
4648 SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
4649 *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd,
4650 msg, wParam, lParam);
4651 SetWindowLong(mWnd, GWL_STYLE, style);
4652 return PR_TRUE;
4655 case WM_NCACTIVATE:
4658 * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
4659 * through WM_NCPAINT via InvalidateNonClientRegion.
4662 if (!mCustomNonClient)
4663 break;
4665 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4666 // let the dwm handle nc painting on glass
4667 if(nsUXThemeData::CheckForCompositor())
4668 break;
4669 #endif
4671 if (wParam == TRUE) {
4672 // going active
4673 *aRetValue = FALSE; // ignored
4674 result = PR_TRUE;
4675 // invalidate to trigger a paint
4676 InvalidateNonClientRegion();
4677 break;
4678 } else {
4679 // going inactive
4680 *aRetValue = TRUE; // go ahead and deactive
4681 result = PR_TRUE;
4682 // invalidate to trigger a paint
4683 InvalidateNonClientRegion();
4684 break;
4688 case WM_NCPAINT:
4691 * Reset the non-client paint region so that it excludes the
4692 * non-client areas we paint manually. Then call defwndproc
4693 * to do the actual painting.
4696 if (!mCustomNonClient)
4697 break;
4699 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
4700 // let the dwm handle nc painting on glass
4701 if(nsUXThemeData::CheckForCompositor())
4702 break;
4703 #endif
4705 HRGN paintRgn = ExcludeNonClientFromPaintRegion((HRGN)wParam);
4706 LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd,
4707 msg, (WPARAM)paintRgn, lParam);
4708 if (paintRgn != (HRGN)wParam)
4709 DeleteObject(paintRgn);
4710 *aRetValue = res;
4711 result = PR_TRUE;
4713 break;
4715 #ifndef WINCE
4716 case WM_POWERBROADCAST:
4717 // only hidden window handle this
4718 // to prevent duplicate notification
4719 if (mWindowType == eWindowType_invisible) {
4720 switch (wParam)
4722 case PBT_APMSUSPEND:
4723 PostSleepWakeNotification("sleep_notification");
4724 break;
4725 case PBT_APMRESUMEAUTOMATIC:
4726 case PBT_APMRESUMECRITICAL:
4727 case PBT_APMRESUMESUSPEND:
4728 PostSleepWakeNotification("wake_notification");
4729 break;
4732 break;
4733 #endif
4735 case WM_MOVE: // Window moved
4737 RECT rect;
4738 ::GetWindowRect(mWnd, &rect);
4739 result = OnMove(rect.left, rect.top);
4741 break;
4743 case WM_CLOSE: // close request
4744 DispatchStandardEvent(NS_XUL_CLOSE);
4745 result = PR_TRUE; // abort window closure
4746 break;
4748 case WM_DESTROY:
4749 // clean up.
4750 OnDestroy();
4751 result = PR_TRUE;
4752 break;
4754 case WM_PAINT:
4755 *aRetValue = (int) OnPaint(NULL, 0);
4756 result = PR_TRUE;
4757 break;
4759 #ifndef WINCE
4760 case WM_PRINTCLIENT:
4761 result = OnPaint((HDC) wParam, 0);
4762 break;
4763 #endif
4765 case WM_HOTKEY:
4766 result = OnHotKey(wParam, lParam);
4767 break;
4769 case WM_SYSCHAR:
4770 case WM_CHAR:
4772 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4773 result = ProcessCharMessage(nativeMsg, nsnull);
4774 DispatchPendingEvents();
4776 break;
4778 case WM_SYSKEYUP:
4779 case WM_KEYUP:
4781 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4782 result = ProcessKeyUpMessage(nativeMsg, nsnull);
4783 DispatchPendingEvents();
4785 break;
4787 case WM_SYSKEYDOWN:
4788 case WM_KEYDOWN:
4790 MSG nativeMsg = InitMSG(msg, wParam, lParam);
4791 result = ProcessKeyDownMessage(nativeMsg, nsnull);
4792 DispatchPendingEvents();
4794 break;
4796 // say we've dealt with erase background if widget does
4797 // not need auto-erasing
4798 case WM_ERASEBKGND:
4799 if (!AutoErase((HDC)wParam)) {
4800 *aRetValue = 1;
4801 result = PR_TRUE;
4803 break;
4805 case WM_MOUSEMOVE:
4807 #ifdef WINCE_WINDOWS_MOBILE
4808 // Reset the kill timer so that we can continue at this
4809 // priority
4810 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2seconds */, NULL);
4811 #endif
4812 // Suppress dispatch of pending events
4813 // when mouse moves are generated by widget
4814 // creation instead of user input.
4815 LPARAM lParamScreen = lParamToScreen(lParam);
4816 POINT mp;
4817 mp.x = GET_X_LPARAM(lParamScreen);
4818 mp.y = GET_Y_LPARAM(lParamScreen);
4819 PRBool userMovedMouse = PR_FALSE;
4820 if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) {
4821 userMovedMouse = PR_TRUE;
4823 mExitToNonClientArea = PR_FALSE;
4825 result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam,
4826 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4827 if (userMovedMouse) {
4828 DispatchPendingEvents();
4831 break;
4833 #ifdef WINCE_WINDOWS_MOBILE
4834 case WM_TIMER:
4835 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4836 KillTimer(mWnd, KILL_PRIORITY_ID);
4837 break;
4838 #endif
4840 case WM_LBUTTONDOWN:
4842 #ifdef WINCE_WINDOWS_MOBILE
4843 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
4844 SetTimer(mWnd, KILL_PRIORITY_ID, 2000 /* 2 seconds */, NULL);
4845 #endif
4846 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
4847 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4848 DispatchPendingEvents();
4850 break;
4852 case WM_LBUTTONUP:
4854 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam,
4855 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4856 DispatchPendingEvents();
4858 #ifdef WINCE_WINDOWS_MOBILE
4859 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
4860 KillTimer(mWnd, KILL_PRIORITY_ID);
4861 #endif
4863 break;
4865 #ifndef WINCE
4866 case WM_MOUSELEAVE:
4868 // We need to check mouse button states and put them in for
4869 // wParam.
4870 WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
4871 | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
4872 | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
4873 // Synthesize an event position because we don't get one from
4874 // WM_MOUSELEAVE.
4875 LPARAM pos = lParamToClient(::GetMessagePos());
4876 DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, PR_FALSE,
4877 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4879 break;
4880 #endif
4882 case WM_CONTEXTMENU:
4884 // if the context menu is brought up from the keyboard, |lParam|
4885 // will be -1.
4886 LPARAM pos;
4887 PRBool contextMenukey = PR_FALSE;
4888 if (lParam == -1)
4890 contextMenukey = PR_TRUE;
4891 pos = lParamToClient(GetMessagePos());
4893 else
4895 pos = lParamToClient(lParam);
4898 result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey,
4899 contextMenukey ?
4900 nsMouseEvent::eLeftButton :
4901 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4903 break;
4905 case WM_LBUTTONDBLCLK:
4906 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4907 nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
4908 break;
4910 case WM_MBUTTONDOWN:
4912 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4913 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4914 DispatchPendingEvents();
4916 break;
4918 case WM_MBUTTONUP:
4919 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4920 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4921 DispatchPendingEvents();
4922 break;
4924 case WM_MBUTTONDBLCLK:
4925 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4926 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4927 break;
4929 case WM_NCMBUTTONDOWN:
4930 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam), PR_FALSE,
4931 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4932 DispatchPendingEvents();
4933 break;
4935 case WM_NCMBUTTONUP:
4936 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam), PR_FALSE,
4937 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4938 DispatchPendingEvents();
4939 break;
4941 case WM_NCMBUTTONDBLCLK:
4942 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam), PR_FALSE,
4943 nsMouseEvent::eMiddleButton, MOUSE_INPUT_SOURCE());
4944 DispatchPendingEvents();
4945 break;
4947 case WM_RBUTTONDOWN:
4949 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, PR_FALSE,
4950 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4951 DispatchPendingEvents();
4953 break;
4955 case WM_RBUTTONUP:
4956 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, PR_FALSE,
4957 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4958 DispatchPendingEvents();
4959 break;
4961 case WM_RBUTTONDBLCLK:
4962 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, lParam, PR_FALSE,
4963 nsMouseEvent::eRightButton, MOUSE_INPUT_SOURCE());
4964 break;
4966 case WM_NCRBUTTONDOWN:
4967 result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, lParamToClient(lParam),
4968 PR_FALSE, nsMouseEvent::eRightButton,
4969 MOUSE_INPUT_SOURCE());
4970 DispatchPendingEvents();
4971 break;
4973 case WM_NCRBUTTONUP:
4974 result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam),
4975 PR_FALSE, nsMouseEvent::eRightButton,
4976 MOUSE_INPUT_SOURCE());
4977 DispatchPendingEvents();
4978 break;
4980 case WM_NCRBUTTONDBLCLK:
4981 result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam),
4982 PR_FALSE, nsMouseEvent::eRightButton,
4983 MOUSE_INPUT_SOURCE());
4985 case WM_APPCOMMAND:
4987 PRUint32 appCommand = GET_APPCOMMAND_LPARAM(lParam);
4989 switch (appCommand)
4991 case APPCOMMAND_BROWSER_BACKWARD:
4992 case APPCOMMAND_BROWSER_FORWARD:
4993 case APPCOMMAND_BROWSER_REFRESH:
4994 case APPCOMMAND_BROWSER_STOP:
4995 case APPCOMMAND_BROWSER_SEARCH:
4996 case APPCOMMAND_BROWSER_FAVORITES:
4997 case APPCOMMAND_BROWSER_HOME:
4998 DispatchCommandEvent(appCommand);
4999 // tell the driver that we handled the event
5000 *aRetValue = 1;
5001 result = PR_TRUE;
5002 break;
5004 // default = PR_FALSE - tell the driver that the event was not handled
5006 break;
5008 case WM_HSCROLL:
5009 case WM_VSCROLL:
5010 *aRetValue = 0;
5011 result = OnScroll(msg, wParam, lParam);
5012 break;
5014 // The WM_ACTIVATE event is fired when a window is raised or lowered,
5015 // and the loword of wParam specifies which. But we don't want to tell
5016 // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
5017 // events are fired. Instead, set either the sJustGotActivate or
5018 // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
5019 // events once the focus events arrive.
5020 case WM_ACTIVATE:
5021 if (mEventCallback) {
5022 PRInt32 fActive = LOWORD(wParam);
5024 #if defined(WINCE_HAVE_SOFTKB)
5025 if (mIsTopWidgetWindow && sSoftKeyboardState)
5026 nsWindowCE::ToggleSoftKB(mWnd, fActive);
5027 if (nsWindowCE::sShowSIPButton == TRI_FALSE && WA_INACTIVE != fActive) {
5028 HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL );
5029 if (hWndSIPB)
5030 ShowWindow(hWndSIPB, SW_HIDE);
5033 #endif
5035 if (WA_INACTIVE == fActive) {
5036 // when minimizing a window, the deactivation and focus events will
5037 // be fired in the reverse order. Instead, just dispatch
5038 // NS_DEACTIVATE right away.
5039 if (HIWORD(wParam))
5040 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5041 else
5042 sJustGotDeactivate = PR_TRUE;
5043 #ifndef WINCE
5044 if (mIsTopWidgetWindow)
5045 mLastKeyboardLayout = gKbdLayout.GetLayout();
5046 #endif
5048 } else {
5049 StopFlashing();
5051 sJustGotActivate = PR_TRUE;
5052 nsMouseEvent event(PR_TRUE, NS_MOUSE_ACTIVATE, this,
5053 nsMouseEvent::eReal);
5054 InitEvent(event);
5056 event.acceptActivation = PR_TRUE;
5058 DispatchWindowEvent(&event);
5059 #ifndef WINCE
5060 if (event.acceptActivation)
5061 *aRetValue = MA_ACTIVATE;
5062 else
5063 *aRetValue = MA_NOACTIVATE;
5065 if (sSwitchKeyboardLayout && mLastKeyboardLayout)
5066 ActivateKeyboardLayout(mLastKeyboardLayout, 0);
5067 #else
5068 *aRetValue = 0;
5069 #endif
5072 #ifdef WINCE_WINDOWS_MOBILE
5073 if (!gCheckForHTCApi && gHTCApiNavOpen == nsnull) {
5074 gCheckForHTCApi = PR_TRUE;
5076 HINSTANCE library = LoadLibrary(L"HTCAPI.dll");
5077 gHTCApiNavOpen = (HTCApiNavOpen) GetProcAddress(library, "HTCNavOpen");
5078 gHTCApiNavSetMode = (HTCApiNavSetMode) GetProcAddress(library ,"HTCNavSetMode");
5081 if (gHTCApiNavOpen != nsnull) {
5082 gHTCApiNavOpen(mWnd, 1 /* undocumented value */);
5084 if (gHTCApiNavSetMode != nsnull)
5085 gHTCApiNavSetMode ( mWnd, 4);
5086 // 4 is Gesture Mode. This will generate WM_HTCNAV events to the window
5088 #endif
5089 break;
5091 #ifndef WINCE
5092 case WM_MOUSEACTIVATE:
5093 if (mWindowType == eWindowType_popup) {
5094 // a popup with a parent owner should not be activated when clicked
5095 // but should still allow the mouse event to be fired, so the return
5096 // value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
5097 // window, just use default processing so that the window is activated.
5098 HWND owner = ::GetWindow(mWnd, GW_OWNER);
5099 if (owner && owner == ::GetForegroundWindow()) {
5100 *aRetValue = MA_NOACTIVATE;
5101 result = PR_TRUE;
5104 break;
5106 case WM_WINDOWPOSCHANGING:
5108 LPWINDOWPOS info = (LPWINDOWPOS) lParam;
5109 OnWindowPosChanging(info);
5111 break;
5112 #endif
5114 case WM_SETFOCUS:
5115 if (sJustGotActivate) {
5116 result = DispatchFocusToTopLevelWindow(NS_ACTIVATE);
5119 #ifdef ACCESSIBILITY
5120 if (nsWindow::sIsAccessibilityOn) {
5121 // Create it for the first time so that it can start firing events
5122 nsAccessible *rootAccessible = GetRootAccessible();
5124 #endif
5126 #if defined(WINCE_HAVE_SOFTKB)
5128 // On Windows CE, we have a window that overlaps
5129 // the ISP button. In this case, we should always
5130 // try to hide it when we are activated
5132 nsIMEContext IMEContext(mWnd);
5133 // Open the IME
5134 ImmSetOpenStatus(IMEContext.get(), TRUE);
5136 #endif
5137 break;
5139 case WM_KILLFOCUS:
5140 #if defined(WINCE_HAVE_SOFTKB)
5142 nsIMEContext IMEContext(mWnd);
5143 ImmSetOpenStatus(IMEContext.get(), FALSE);
5145 #endif
5146 if (sJustGotDeactivate) {
5147 result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5149 break;
5151 case WM_WINDOWPOSCHANGED:
5153 WINDOWPOS *wp = (LPWINDOWPOS)lParam;
5154 OnWindowPosChanged(wp, result);
5156 break;
5158 case WM_SETTINGCHANGE:
5159 #if !defined (WINCE_WINDOWS_MOBILE)
5160 getWheelInfo = PR_TRUE;
5161 #else
5162 switch (wParam) {
5163 case SPI_SETSIPINFO:
5164 case SPI_SETCURRENTIM:
5165 nsWindowCE::OnSoftKbSettingsChange(mWnd);
5166 break;
5167 case SETTINGCHANGE_RESET:
5168 if (mWindowType == eWindowType_invisible) {
5169 // The OS sees to get confused and think that the invisable window
5170 // is in the foreground after an orientation change. By actually
5171 // setting it to the foreground and hiding it, we set it strait.
5172 // See bug 514007 for details.
5173 SetForegroundWindow(mWnd);
5174 ShowWindow(mWnd, SW_HIDE);
5176 break;
5178 #endif
5179 OnSettingsChange(wParam, lParam);
5180 break;
5182 #ifndef WINCE
5183 case WM_INPUTLANGCHANGEREQUEST:
5184 *aRetValue = TRUE;
5185 result = PR_FALSE;
5186 break;
5188 case WM_INPUTLANGCHANGE:
5189 result = OnInputLangChange((HKL)lParam);
5190 break;
5191 #endif // WINCE
5193 case WM_DESTROYCLIPBOARD:
5195 nsIClipboard* clipboard;
5196 nsresult rv = CallGetService(kCClipboardCID, &clipboard);
5197 if(NS_SUCCEEDED(rv)) {
5198 clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
5199 NS_RELEASE(clipboard);
5202 break;
5204 #ifdef ACCESSIBILITY
5205 case WM_GETOBJECT:
5207 *aRetValue = 0;
5208 if (lParam == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
5209 nsAccessible *rootAccessible = GetRootAccessible(); // Held by a11y cache
5210 if (rootAccessible) {
5211 IAccessible *msaaAccessible = NULL;
5212 rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref
5213 if (msaaAccessible) {
5214 *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref
5215 msaaAccessible->Release(); // release extra addref
5216 result = PR_TRUE; // We handled the WM_GETOBJECT message
5221 #endif
5223 #ifndef WINCE
5224 case WM_SYSCOMMAND:
5225 // prevent Windows from trimming the working set. bug 76831
5226 if (!sTrimOnMinimize && wParam == SC_MINIMIZE) {
5227 ::ShowWindow(mWnd, SW_SHOWMINIMIZED);
5228 result = PR_TRUE;
5230 break;
5231 #endif
5234 #ifdef WINCE
5235 case WM_HIBERNATE:
5236 nsMemory::HeapMinimize(PR_TRUE);
5237 break;
5238 #endif
5240 case WM_MOUSEWHEEL:
5241 case WM_MOUSEHWHEEL:
5243 // If OnMouseWheel returns true, the event was forwarded directly to another
5244 // mozilla window message handler (ProcessMessage). In this case the return
5245 // value of the forwarded event is in 'result' which we should return immediately.
5246 // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
5247 // 'result' and 'aRetValue' will be set based on what we did with the event, so
5248 // we should fall through.
5249 if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue))
5250 return result;
5252 break;
5254 #ifndef WINCE
5255 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
5256 case WM_DWMCOMPOSITIONCHANGED:
5257 UpdateNonClientMargins();
5258 BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
5259 DispatchStandardEvent(NS_THEMECHANGED);
5260 UpdateGlass();
5261 Invalidate(PR_FALSE);
5262 break;
5263 #endif
5265 case WM_UPDATEUISTATE:
5267 // If the UI state has changed, fire an event so the UI updates the
5268 // keyboard cues based on the system setting and how the window was
5269 // opened. For example, a dialog opened via a keyboard press on a button
5270 // should enable cues, whereas the same dialog opened via a mouse click of
5271 // the button should not.
5272 PRInt32 action = LOWORD(wParam);
5273 if (action == UIS_SET || action == UIS_CLEAR) {
5274 nsUIStateChangeEvent event(PR_TRUE, NS_UISTATECHANGED, this);
5275 PRInt32 flags = HIWORD(wParam);
5276 if (flags & UISF_HIDEACCEL)
5277 event.showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5278 if (flags & UISF_HIDEFOCUS)
5279 event.showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set;
5280 DispatchWindowEvent(&event);
5283 break;
5286 /* Gesture support events */
5287 case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
5288 // According to MS samples, this must be handled to enable
5289 // rotational support in multi-touch drivers.
5290 result = PR_TRUE;
5291 *aRetValue = TABLET_ROTATE_GESTURE_ENABLE;
5292 break;
5294 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5295 case WM_TOUCH:
5296 result = OnTouch(wParam, lParam);
5297 if (result) {
5298 *aRetValue = 0;
5300 break;
5301 #endif
5303 case WM_GESTURE:
5304 result = OnGesture(wParam, lParam);
5305 break;
5307 case WM_GESTURENOTIFY:
5309 if (mWindowType != eWindowType_invisible &&
5310 mWindowType != eWindowType_plugin) {
5311 // A GestureNotify event is dispatched to decide which single-finger panning
5312 // direction should be active (including none) and if pan feedback should
5313 // be displayed. Java and plugin windows can make their own calls.
5314 GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
5315 nsPointWin touchPoint;
5316 touchPoint = gestureinfo->ptsLocation;
5317 touchPoint.ScreenToClient(mWnd);
5318 nsGestureNotifyEvent gestureNotifyEvent(PR_TRUE, NS_GESTURENOTIFY_EVENT_START, this);
5319 gestureNotifyEvent.refPoint = touchPoint;
5320 nsEventStatus status;
5321 DispatchEvent(&gestureNotifyEvent, status);
5322 mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
5323 if (!mTouchWindow)
5324 mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
5326 result = PR_FALSE; //should always bubble to DefWindowProc
5328 break;
5329 #endif // !defined(WINCE)
5331 case WM_CLEAR:
5333 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_DELETE, this);
5334 DispatchWindowEvent(&command);
5335 result = PR_TRUE;
5337 break;
5339 case WM_CUT:
5341 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_CUT, this);
5342 DispatchWindowEvent(&command);
5343 result = PR_TRUE;
5345 break;
5347 case WM_COPY:
5349 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_COPY, this);
5350 DispatchWindowEvent(&command);
5351 result = PR_TRUE;
5353 break;
5355 case WM_PASTE:
5357 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE, this);
5358 DispatchWindowEvent(&command);
5359 result = PR_TRUE;
5361 break;
5363 #ifndef WINCE
5364 case EM_UNDO:
5366 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO, this);
5367 DispatchWindowEvent(&command);
5368 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5369 result = PR_TRUE;
5371 break;
5373 case EM_REDO:
5375 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO, this);
5376 DispatchWindowEvent(&command);
5377 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5378 result = PR_TRUE;
5380 break;
5382 case EM_CANPASTE:
5384 // Support EM_CANPASTE message only when wParam isn't specified or
5385 // is plain text format.
5386 if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
5387 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE,
5388 this, PR_TRUE);
5389 DispatchWindowEvent(&command);
5390 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5391 result = PR_TRUE;
5394 break;
5396 case EM_CANUNDO:
5398 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO,
5399 this, PR_TRUE);
5400 DispatchWindowEvent(&command);
5401 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5402 result = PR_TRUE;
5404 break;
5406 case EM_CANREDO:
5408 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO,
5409 this, PR_TRUE);
5410 DispatchWindowEvent(&command);
5411 *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
5412 result = PR_TRUE;
5414 break;
5415 #endif
5417 #ifdef WINCE_WINDOWS_MOBILE
5418 //HTC NAVIGATION WHEEL EVENT
5419 case WM_HTCNAV:
5421 int distance = wParam & 0x000000FF;
5422 if ( (wParam & 0x000000100) != 0) // Counter Clockwise
5423 distance *= -1;
5424 if (OnMouseWheel(WM_MOUSEWHEEL, MAKEWPARAM(0, distance),
5425 MAKELPARAM(GetSystemMetrics(SM_CXSCREEN) / 2,
5426 GetSystemMetrics(SM_CYSCREEN) / 2),
5427 getWheelInfo, result, aRetValue))
5428 return result;
5430 break;
5431 #endif
5433 default:
5435 #ifdef NS_ENABLE_TSF
5436 if (msg == WM_USER_TSF_TEXTCHANGE) {
5437 nsTextStore::OnTextChangeMsg();
5439 #endif //NS_ENABLE_TSF
5440 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
5441 if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
5442 SetHasTaskbarIconBeenCreated();
5443 #endif
5444 #ifdef MOZ_IPC
5445 if (msg == sOOPPPluginFocusEvent) {
5446 if (wParam == 1) {
5447 // With OOPP, the plugin window exists in another process and is a child of
5448 // this window. This window is a placeholder plugin window for the dom. We
5449 // receive this event when the child window receives focus. (sent from
5450 // PluginInstanceParent.cpp)
5451 ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
5452 } else {
5453 // WM_KILLFOCUS was received by the child process.
5454 if (sJustGotDeactivate) {
5455 DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
5459 #endif
5461 break;
5464 //*aRetValue = result;
5465 if (mWnd) {
5466 return result;
5468 else {
5469 //Events which caused mWnd destruction and aren't consumed
5470 //will crash during the Windows default processing.
5471 return PR_TRUE;
5475 /**************************************************************
5477 * SECTION: Broadcast messaging
5479 * Broadcast messages to all windows.
5481 **************************************************************/
5483 // Enumerate all child windows sending aMsg to each of them
5484 BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg)
5486 WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
5487 if (winProc == &nsWindow::WindowProc) {
5488 // it's one of our windows so go ahead and send a message to it
5489 ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0);
5491 return TRUE;
5494 // Enumerate all top level windows specifying that the children of each
5495 // top level window should be enumerated. Do *not* send the message to
5496 // each top level window since it is assumed that the toolkit will send
5497 // aMsg to them directly.
5498 BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg)
5500 // Iterate each of aTopWindows child windows sending the aMsg
5501 // to each of them.
5502 #if !defined(WINCE)
5503 ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5504 #else
5505 nsWindowCE::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg);
5506 #endif
5507 return TRUE;
5510 // This method is called from nsToolkit::WindowProc to forward global
5511 // messages which need to be dispatched to all child windows.
5512 void nsWindow::GlobalMsgWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
5514 switch (msg) {
5515 case WM_SYSCOLORCHANGE:
5516 // Code to dispatch WM_SYSCOLORCHANGE message to all child windows.
5517 // WM_SYSCOLORCHANGE is only sent to top-level windows, but the
5518 // cross platform API requires that NS_SYSCOLORCHANGE message be sent to
5519 // all child windows as well. When running in an embedded application
5520 // we may not receive a WM_SYSCOLORCHANGE message because the top
5521 // level window is owned by the embeddor.
5522 // System color changes are posted to top-level windows only.
5523 // The NS_SYSCOLORCHANGE must be dispatched to all child
5524 // windows as well.
5525 #if !defined(WINCE)
5526 ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, msg);
5527 #endif
5528 break;
5532 /**************************************************************
5534 * SECTION: Event processing helpers
5536 * Special processing for certain event types and
5537 * synthesized events.
5539 **************************************************************/
5541 PRInt32
5542 nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
5544 // Calculations are done in screen coords
5545 RECT winRect;
5546 GetWindowRect(mWnd, &winRect);
5548 // hit return constants:
5549 // HTBORDER - non-resizable border
5550 // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
5551 // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner
5552 // HTTOPLEFT, HTTOPRIGHT - resizable corner
5553 // HTCAPTION - general title bar area
5554 // HTCLIENT - area considered the client
5555 // HTCLOSE - hovering over the close button
5556 // HTMAXBUTTON - maximize button
5557 // HTMINBUTTON - minimize button
5559 PRInt32 testResult = HTCLIENT;
5561 PRBool top = PR_FALSE;
5562 PRBool bottom = PR_FALSE;
5563 PRBool left = PR_FALSE;
5564 PRBool right = PR_FALSE;
5566 if (my >= winRect.top && my <=
5567 (winRect.top + mVertResizeMargin + (mCaptionHeight - mNonClientOffset.top)))
5568 top = PR_TRUE;
5569 else if (my <= winRect.bottom && my >= (winRect.bottom - mVertResizeMargin))
5570 bottom = PR_TRUE;
5572 if (mx >= winRect.left && mx <= (winRect.left + mHorResizeMargin))
5573 left = PR_TRUE;
5574 else if (mx <= winRect.right && mx >= (winRect.right - mHorResizeMargin))
5575 right = PR_TRUE;
5577 if (top) {
5578 testResult = HTTOP;
5579 if (left)
5580 testResult = HTTOPLEFT;
5581 else if (right)
5582 testResult = HTTOPRIGHT;
5583 } else if (bottom) {
5584 testResult = HTBOTTOM;
5585 if (left)
5586 testResult = HTBOTTOMLEFT;
5587 else if (right)
5588 testResult = HTBOTTOMRIGHT;
5589 } else {
5590 if (left)
5591 testResult = HTLEFT;
5592 if (right)
5593 testResult = HTRIGHT;
5596 PRBool contentOverlap = PR_TRUE;
5598 if (mSizeMode == nsSizeMode_Maximized) {
5599 // There's no HTTOP in maximized state (bug 575493)
5600 if (testResult == HTTOP) {
5601 testResult = HTCAPTION;
5603 } else {
5604 PRInt32 leftMargin = mNonClientMargins.left == -1 ? mHorResizeMargin : mNonClientMargins.left;
5605 PRInt32 rightMargin = mNonClientMargins.right == -1 ? mHorResizeMargin : mNonClientMargins.right;
5606 PRInt32 topMargin = mNonClientMargins.top == -1 ? mVertResizeMargin : mNonClientMargins.top;
5607 PRInt32 bottomMargin = mNonClientMargins.bottom == -1 ? mVertResizeMargin : mNonClientMargins.bottom;
5609 contentOverlap = mx >= winRect.left + leftMargin &&
5610 mx <= winRect.right - rightMargin &&
5611 my >= winRect.top + topMargin &&
5612 my <= winRect.bottom - bottomMargin;
5615 if (!mIsInMouseCapture &&
5616 contentOverlap &&
5617 (testResult == HTCLIENT ||
5618 testResult == HTTOP ||
5619 testResult == HTTOPLEFT ||
5620 testResult == HTCAPTION)) {
5621 LPARAM lParam = MAKELPARAM(mx, my);
5622 LPARAM lParamClient = lParamToClient(lParam);
5623 PRBool result = DispatchMouseEvent(NS_MOUSE_MOZHITTEST, 0, lParamClient,
5624 PR_FALSE, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
5625 if (result) {
5626 // The mouse is over a blank area
5627 testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
5629 if (!mExitToNonClientArea) {
5630 // The first time the mouse pointer goes from client area to non-client area,
5631 // we don't want to miss that movement so we can interpret mouseout input.
5632 ::SendMessage(mWnd, WM_MOUSEMOVE, 0, lParamClient);
5633 mExitToNonClientArea = PR_TRUE;
5635 } else {
5636 // There's content over the mouse pointer. Set HTCLIENT
5637 // to possibly override a resizer border.
5638 testResult = HTCLIENT;
5642 return testResult;
5646 #ifndef WINCE
5647 void nsWindow::PostSleepWakeNotification(const char* aNotification)
5649 nsCOMPtr<nsIObserverService> observerService =
5650 mozilla::services::GetObserverService();
5651 if (observerService)
5652 observerService->NotifyObservers(nsnull, aNotification, nsnull);
5654 #endif
5656 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, PRBool *aEventDispatched)
5658 NS_PRECONDITION(aMsg.message == WM_CHAR || aMsg.message == WM_SYSCHAR,
5659 "message is not keydown event");
5660 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5661 ("%s charCode=%d scanCode=%d\n",
5662 aMsg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
5663 aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF));
5665 // These must be checked here too as a lone WM_CHAR could be received
5666 // if a child window didn't handle it (for example Alt+Space in a content window)
5667 nsModifierKeyState modKeyState;
5668 return OnChar(aMsg, modKeyState, aEventDispatched);
5671 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, PRBool *aEventDispatched)
5673 NS_PRECONDITION(aMsg.message == WM_KEYUP || aMsg.message == WM_SYSKEYUP,
5674 "message is not keydown event");
5675 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5676 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5677 "WM_SYSKEYUP" : "WM_KEYUP", aMsg.wParam));
5679 nsModifierKeyState modKeyState;
5681 // Note: the original code passed (HIWORD(lParam)) to OnKeyUp as
5682 // scan code. However, this breaks Alt+Num pad input.
5683 // MSDN states the following:
5684 // Typically, ToAscii performs the translation based on the
5685 // virtual-key code. In some cases, however, bit 15 of the
5686 // uScanCode parameter may be used to distinguish between a key
5687 // press and a key release. The scan code is used for
5688 // translating ALT+number key combinations.
5690 // ignore [shift+]alt+space so the OS can handle it
5691 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5692 IS_VK_DOWN(NS_VK_SPACE)) {
5693 return FALSE;
5696 if (!nsIMM32Handler::IsComposingOn(this) &&
5697 (aMsg.message != WM_KEYUP || aMsg.wParam != VK_MENU)) {
5698 // Ignore VK_MENU if it's not a system key release, so that the menu bar does not trigger
5699 // This helps avoid triggering the menu bar for ALT key accelerators used in
5700 // assistive technologies such as Window-Eyes and ZoomText, and when using Alt+Tab
5701 // to switch back to Mozilla in Windows 95 and Windows 98
5702 return OnKeyUp(aMsg, modKeyState, aEventDispatched);
5705 return 0;
5708 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
5709 PRBool *aEventDispatched)
5711 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
5712 ("%s VK=%d\n", aMsg.message == WM_SYSKEYDOWN ?
5713 "WM_SYSKEYDOWN" : "WM_KEYDOWN", aMsg.wParam));
5714 NS_PRECONDITION(aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN,
5715 "message is not keydown event");
5717 nsModifierKeyState modKeyState;
5719 // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
5720 // scan code. However, this breaks Alt+Num pad input.
5721 // MSDN states the following:
5722 // Typically, ToAscii performs the translation based on the
5723 // virtual-key code. In some cases, however, bit 15 of the
5724 // uScanCode parameter may be used to distinguish between a key
5725 // press and a key release. The scan code is used for
5726 // translating ALT+number key combinations.
5728 // ignore [shift+]alt+space so the OS can handle it
5729 if (modKeyState.mIsAltDown && !modKeyState.mIsControlDown &&
5730 IS_VK_DOWN(NS_VK_SPACE))
5731 return FALSE;
5733 LRESULT result = 0;
5734 if (modKeyState.mIsAltDown && nsIMM32Handler::IsStatusChanged()) {
5735 nsIMM32Handler::NotifyEndStatusChange();
5736 } else if (!nsIMM32Handler::IsComposingOn(this)) {
5737 result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nsnull);
5740 #ifndef WINCE
5741 if (aMsg.wParam == VK_MENU ||
5742 (aMsg.wParam == VK_F10 && !modKeyState.mIsShiftDown)) {
5743 // We need to let Windows handle this keypress,
5744 // by returning PR_FALSE, if there's a native menu
5745 // bar somewhere in our containing window hierarchy.
5746 // Otherwise we handle the keypress and don't pass
5747 // it on to Windows, by returning PR_TRUE.
5748 PRBool hasNativeMenu = PR_FALSE;
5749 HWND hWnd = mWnd;
5750 while (hWnd) {
5751 if (::GetMenu(hWnd)) {
5752 hasNativeMenu = PR_TRUE;
5753 break;
5755 hWnd = ::GetParent(hWnd);
5757 result = !hasNativeMenu;
5759 #endif
5761 return result;
5764 nsresult
5765 nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
5766 PRInt32 aNativeKeyCode,
5767 PRUint32 aModifierFlags,
5768 const nsAString& aCharacters,
5769 const nsAString& aUnmodifiedCharacters)
5771 #ifndef WINCE //Win CE doesn't support many of the calls used in this method, perhaps theres another way
5772 nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
5773 HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
5774 if (loadedLayout == NULL)
5775 return NS_ERROR_NOT_AVAILABLE;
5777 // Setup clean key state and load desired layout
5778 BYTE originalKbdState[256];
5779 ::GetKeyboardState(originalKbdState);
5780 BYTE kbdState[256];
5781 memset(kbdState, 0, sizeof(kbdState));
5782 // This changes the state of the keyboard for the current thread only,
5783 // and we'll restore it soon, so this should be OK.
5784 ::SetKeyboardState(kbdState);
5785 HKL oldLayout = gKbdLayout.GetLayout();
5786 gKbdLayout.LoadLayout(loadedLayout);
5788 nsAutoTArray<KeyPair,10> keySequence;
5789 SetupKeyModifiersSequence(&keySequence, aModifierFlags);
5790 NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
5791 "Native VK key code out of range");
5792 keySequence.AppendElement(KeyPair(aNativeKeyCode, 0));
5794 // Simulate the pressing of each modifier key and then the real key
5795 for (PRUint32 i = 0; i < keySequence.Length(); ++i) {
5796 PRUint8 key = keySequence[i].mGeneral;
5797 PRUint8 keySpecific = keySequence[i].mSpecific;
5798 kbdState[key] = 0x81; // key is down and toggled on if appropriate
5799 if (keySpecific) {
5800 kbdState[keySpecific] = 0x81;
5802 ::SetKeyboardState(kbdState);
5803 nsModifierKeyState modKeyState;
5804 MSG msg = InitMSG(WM_KEYDOWN, key, 0);
5805 if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
5806 UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
5807 gKbdLayout.GetLayout());
5808 nsFakeCharMessage fakeMsg = { aCharacters.CharAt(0), scanCode };
5809 OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
5810 } else {
5811 OnKeyDown(msg, modKeyState, nsnull, nsnull);
5814 for (PRUint32 i = keySequence.Length(); i > 0; --i) {
5815 PRUint8 key = keySequence[i - 1].mGeneral;
5816 PRUint8 keySpecific = keySequence[i - 1].mSpecific;
5817 kbdState[key] = 0; // key is up and toggled off if appropriate
5818 if (keySpecific) {
5819 kbdState[keySpecific] = 0;
5821 ::SetKeyboardState(kbdState);
5822 nsModifierKeyState modKeyState;
5823 MSG msg = InitMSG(WM_KEYUP, key, 0);
5824 OnKeyUp(msg, modKeyState, nsnull);
5827 // Restore old key state and layout
5828 ::SetKeyboardState(originalKbdState);
5829 gKbdLayout.LoadLayout(oldLayout);
5831 UnloadKeyboardLayout(loadedLayout);
5832 return NS_OK;
5833 #else //XXX: is there another way to do this?
5834 return NS_ERROR_NOT_IMPLEMENTED;
5835 #endif
5838 nsresult
5839 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
5840 PRUint32 aNativeMessage,
5841 PRUint32 aModifierFlags)
5843 #ifndef WINCE // I don't think WINCE supports SendInput
5844 RECT r;
5845 ::GetWindowRect(mWnd, &r);
5846 ::SetCursorPos(r.left + aPoint.x, r.top + aPoint.y);
5848 INPUT input;
5849 memset(&input, 0, sizeof(input));
5851 input.type = INPUT_MOUSE;
5852 input.mi.dwFlags = aNativeMessage;
5853 ::SendInput(1, &input, sizeof(INPUT));
5855 return NS_OK;
5856 #else
5857 return NS_ERROR_NOT_IMPLEMENTED;
5858 #endif
5861 /**************************************************************
5863 * SECTION: OnXXX message handlers
5865 * For message handlers that need to be broken out or
5866 * implemented in specific platform code.
5868 **************************************************************/
5870 BOOL nsWindow::OnInputLangChange(HKL aHKL)
5872 #ifdef KE_DEBUG
5873 printf("OnInputLanguageChange\n");
5874 #endif
5876 #ifndef WINCE
5877 gKbdLayout.LoadLayout(aHKL);
5878 #endif
5880 return PR_FALSE; // always pass to child window
5883 #if !defined(WINCE) // implemented in nsWindowCE.cpp
5884 void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, PRBool& result)
5886 if (wp == nsnull)
5887 return;
5889 #ifdef WINSTATE_DEBUG_OUTPUT
5890 if (mWnd == GetTopLevelHWND(mWnd))
5891 printf("*** OnWindowPosChanged: [ top] ");
5892 else
5893 printf("*** OnWindowPosChanged: [child] ");
5894 printf("WINDOWPOS flags:");
5895 if (wp->flags & SWP_FRAMECHANGED)
5896 printf("SWP_FRAMECHANGED ");
5897 if (wp->flags & SWP_SHOWWINDOW)
5898 printf("SWP_SHOWWINDOW ");
5899 if (wp->flags & SWP_NOSIZE)
5900 printf("SWP_NOSIZE ");
5901 if (wp->flags & SWP_HIDEWINDOW)
5902 printf("SWP_HIDEWINDOW ");
5903 printf("\n");
5904 #endif
5906 // Handle window size mode changes
5907 if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
5908 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
5910 WINDOWPLACEMENT pl;
5911 pl.length = sizeof(pl);
5912 ::GetWindowPlacement(mWnd, &pl);
5914 if (pl.showCmd == SW_SHOWMAXIMIZED)
5915 event.mSizeMode = nsSizeMode_Maximized;
5916 else if (pl.showCmd == SW_SHOWMINIMIZED)
5917 event.mSizeMode = nsSizeMode_Minimized;
5918 else if (mFullscreenMode)
5919 event.mSizeMode = nsSizeMode_Fullscreen;
5920 else
5921 event.mSizeMode = nsSizeMode_Normal;
5923 // Windows has just changed the size mode of this window. The following
5924 // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
5925 // set the min/max window state again or for nsSizeMode_Normal, call
5926 // SetWindow with a parameter of SW_RESTORE. There's no need however as
5927 // this window's mode has already changed. Updating mSizeMode here
5928 // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
5929 // to window docking. (bug 489258)
5930 mSizeMode = event.mSizeMode;
5932 // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
5933 // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
5934 // prevents the working set from being trimmed but keeps the window active.
5935 // After the window is minimized, we need to do some touch up work on the
5936 // active window. (bugs 76831 & 499816)
5937 if (!sTrimOnMinimize && nsSizeMode_Minimized == event.mSizeMode)
5938 ActivateOtherWindowHelper(mWnd);
5940 #ifdef WINSTATE_DEBUG_OUTPUT
5941 switch (mSizeMode) {
5942 case nsSizeMode_Normal:
5943 printf("*** mSizeMode: nsSizeMode_Normal\n");
5944 break;
5945 case nsSizeMode_Minimized:
5946 printf("*** mSizeMode: nsSizeMode_Minimized\n");
5947 break;
5948 case nsSizeMode_Maximized:
5949 printf("*** mSizeMode: nsSizeMode_Maximized\n");
5950 break;
5951 default:
5952 printf("*** mSizeMode: ??????\n");
5953 break;
5955 #endif
5957 InitEvent(event);
5959 result = DispatchWindowEvent(&event);
5961 // Skip window size change events below on minimization.
5962 if (mSizeMode == nsSizeMode_Minimized)
5963 return;
5966 // Handle window size changes
5967 if (0 == (wp->flags & SWP_NOSIZE)) {
5968 RECT r;
5969 PRInt32 newWidth, newHeight;
5971 ::GetWindowRect(mWnd, &r);
5973 newWidth = r.right - r.left;
5974 newHeight = r.bottom - r.top;
5975 nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
5977 #ifdef MOZ_XUL
5978 if (eTransparencyTransparent == mTransparencyMode)
5979 ResizeTranslucentWindow(newWidth, newHeight);
5980 #endif
5982 if (newWidth > mLastSize.width)
5984 RECT drect;
5986 // getting wider
5987 drect.left = wp->x + mLastSize.width;
5988 drect.top = wp->y;
5989 drect.right = drect.left + (newWidth - mLastSize.width);
5990 drect.bottom = drect.top + newHeight;
5992 ::RedrawWindow(mWnd, &drect, NULL,
5993 RDW_INVALIDATE |
5994 RDW_NOERASE |
5995 RDW_NOINTERNALPAINT |
5996 RDW_ERASENOW |
5997 RDW_ALLCHILDREN);
5999 if (newHeight > mLastSize.height)
6001 RECT drect;
6003 // getting taller
6004 drect.left = wp->x;
6005 drect.top = wp->y + mLastSize.height;
6006 drect.right = drect.left + newWidth;
6007 drect.bottom = drect.top + (newHeight - mLastSize.height);
6009 ::RedrawWindow(mWnd, &drect, NULL,
6010 RDW_INVALIDATE |
6011 RDW_NOERASE |
6012 RDW_NOINTERNALPAINT |
6013 RDW_ERASENOW |
6014 RDW_ALLCHILDREN);
6017 mBounds.width = newWidth;
6018 mBounds.height = newHeight;
6019 mLastSize.width = newWidth;
6020 mLastSize.height = newHeight;
6022 #ifdef WINSTATE_DEBUG_OUTPUT
6023 printf("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, newWidth, newHeight);
6024 #endif
6026 // If a maximized window is resized, recalculate the non-client margins and
6027 // ensure a 1 pixel margin at screen bottom to allow taskbar unhiding to
6028 // work properly.
6029 if (mSizeMode == nsSizeMode_Maximized) {
6030 if (UpdateNonClientMargins(nsSizeMode_Maximized, PR_TRUE)) {
6031 // gecko resize event already sent by UpdateNonClientMargins.
6032 result = PR_TRUE;
6033 return;
6037 // Recalculate the width and height based on the client area for gecko events.
6038 if (::GetClientRect(mWnd, &r)) {
6039 rect.width = r.right - r.left;
6040 rect.height = r.bottom - r.top;
6043 // Send a gecko resize event
6044 result = OnResize(rect);
6048 // static
6049 void nsWindow::ActivateOtherWindowHelper(HWND aWnd)
6051 // Find the next window that is enabled, visible, and not minimized.
6052 HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT);
6053 while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) ||
6054 ::IsIconic(hwndBelow))) {
6055 hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT);
6058 // Push ourselves to the bottom of the stack, then activate the
6059 // next window.
6060 ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0,
6061 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
6062 if (hwndBelow)
6063 ::SetForegroundWindow(hwndBelow);
6065 // Play the minimize sound while we're here, since that is also
6066 // forgotten when we use SW_SHOWMINIMIZED.
6067 ::PlaySoundW(L"Minimize", nsnull, SND_ALIAS | SND_NODEFAULT | SND_ASYNC);
6069 #endif // !defined(WINCE)
6071 #if !defined(WINCE)
6072 void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info)
6074 // Update non-client margins if the frame size is changing, and let the
6075 // browser know we are changing size modes, so alternative css can kick in.
6076 // If we're going into fullscreen mode, ignore this, since it'll reset
6077 // margins to normal mode.
6078 if (info->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) {
6079 WINDOWPLACEMENT pl;
6080 pl.length = sizeof(pl);
6081 ::GetWindowPlacement(mWnd, &pl);
6082 PRInt32 sizeMode;
6083 if (pl.showCmd == SW_SHOWMAXIMIZED)
6084 sizeMode = nsSizeMode_Maximized;
6085 else if (pl.showCmd == SW_SHOWMINIMIZED)
6086 sizeMode = nsSizeMode_Minimized;
6087 else if (mFullscreenMode)
6088 sizeMode = nsSizeMode_Fullscreen;
6089 else
6090 sizeMode = nsSizeMode_Normal;
6092 nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
6094 InitEvent(event);
6095 event.mSizeMode = static_cast<nsSizeMode>(sizeMode);
6096 DispatchWindowEvent(&event);
6098 UpdateNonClientMargins(sizeMode, PR_FALSE);
6101 // enforce local z-order rules
6102 if (!(info->flags & SWP_NOZORDER)) {
6103 HWND hwndAfter = info->hwndInsertAfter;
6105 nsZLevelEvent event(PR_TRUE, NS_SETZLEVEL, this);
6106 nsWindow *aboveWindow = 0;
6108 InitEvent(event);
6110 if (hwndAfter == HWND_BOTTOM)
6111 event.mPlacement = nsWindowZBottom;
6112 else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
6113 event.mPlacement = nsWindowZTop;
6114 else {
6115 event.mPlacement = nsWindowZRelative;
6116 aboveWindow = GetNSWindowPtr(hwndAfter);
6118 event.mReqBelow = aboveWindow;
6119 event.mActualBelow = nsnull;
6121 event.mImmediate = PR_FALSE;
6122 event.mAdjusted = PR_FALSE;
6123 DispatchWindowEvent(&event);
6125 if (event.mAdjusted) {
6126 if (event.mPlacement == nsWindowZBottom)
6127 info->hwndInsertAfter = HWND_BOTTOM;
6128 else if (event.mPlacement == nsWindowZTop)
6129 info->hwndInsertAfter = HWND_TOP;
6130 else {
6131 info->hwndInsertAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
6134 NS_IF_RELEASE(event.mActualBelow);
6136 // prevent rude external programs from making hidden window visible
6137 if (mWindowType == eWindowType_invisible)
6138 info->flags &= ~SWP_SHOWWINDOW;
6140 #endif
6142 void nsWindow::UserActivity()
6144 // Check if we have the idle service, if not we try to get it.
6145 if (!mIdleService) {
6146 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
6149 // Check that we now have the idle service.
6150 if (mIdleService) {
6151 mIdleService->ResetIdleTimeOut();
6155 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
6156 PRBool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam)
6158 PRUint32 cInputs = LOWORD(wParam);
6159 PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
6161 if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) {
6162 for (PRUint32 i = 0; i < cInputs; i++) {
6163 PRUint32 msg;
6164 if (pInputs[i].dwFlags & TOUCHEVENTF_MOVE) {
6165 msg = NS_MOZTOUCH_MOVE;
6166 } else if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) {
6167 msg = NS_MOZTOUCH_DOWN;
6168 } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) {
6169 msg = NS_MOZTOUCH_UP;
6170 } else {
6171 continue;
6174 nsPointWin touchPoint;
6175 touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
6176 touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
6177 touchPoint.ScreenToClient(mWnd);
6179 nsMozTouchEvent touchEvent(PR_TRUE, msg, this, pInputs[i].dwID);
6180 touchEvent.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6181 touchEvent.refPoint = touchPoint;
6183 nsEventStatus status;
6184 DispatchEvent(&touchEvent, status);
6188 delete [] pInputs;
6189 mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam);
6190 return PR_TRUE;
6192 #endif
6194 // Gesture event processing. Handles WM_GESTURE events.
6195 #if !defined(WINCE)
6196 PRBool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
6198 // Treatment for pan events which translate into scroll events:
6199 if (mGesture.IsPanEvent(lParam)) {
6200 nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
6202 if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
6203 return PR_FALSE; // ignore
6205 nsEventStatus status;
6207 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6208 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6209 event.isMeta = PR_FALSE;
6210 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6211 event.button = 0;
6212 event.time = ::GetMessageTime();
6213 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6215 PRBool endFeedback = PR_TRUE;
6217 PRInt32 scrollOverflowX = 0;
6218 PRInt32 scrollOverflowY = 0;
6220 if (mGesture.PanDeltaToPixelScrollX(event)) {
6221 DispatchEvent(&event, status);
6222 scrollOverflowX = event.scrollOverflow;
6225 if (mGesture.PanDeltaToPixelScrollY(event)) {
6226 DispatchEvent(&event, status);
6227 scrollOverflowY = event.scrollOverflow;
6230 if (mDisplayPanFeedback) {
6231 mGesture.UpdatePanFeedbackX(mWnd, scrollOverflowX, endFeedback);
6232 mGesture.UpdatePanFeedbackY(mWnd, scrollOverflowY, endFeedback);
6233 mGesture.PanFeedbackFinalize(mWnd, endFeedback);
6236 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6238 return PR_TRUE;
6241 // Other gestures translate into simple gesture events:
6242 nsSimpleGestureEvent event(PR_TRUE, 0, this, 0, 0.0);
6243 if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) {
6244 return PR_FALSE; // fall through to DefWndProc
6247 // Polish up and send off the new event
6248 event.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6249 event.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6250 event.isMeta = PR_FALSE;
6251 event.isAlt = IS_VK_DOWN(NS_VK_ALT);
6252 event.button = 0;
6253 event.time = ::GetMessageTime();
6254 event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH;
6256 nsEventStatus status;
6257 DispatchEvent(&event, status);
6258 if (status == nsEventStatus_eIgnore) {
6259 return PR_FALSE; // Ignored, fall through
6262 // Only close this if we process and return true.
6263 mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
6265 return PR_TRUE; // Handled
6267 #endif // !defined(WINCE)
6269 #if !defined(WINCE)
6270 PRUint16 nsWindow::GetMouseInputSource()
6272 PRUint16 inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE;
6273 LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
6274 if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
6275 inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ?
6276 PRUint16(nsIDOMNSMouseEvent::MOZ_SOURCE_TOUCH) : nsIDOMNSMouseEvent::MOZ_SOURCE_PEN;
6278 return inputSource;
6280 #endif
6282 * OnMouseWheel - mouse wheele event processing. This was originally embedded
6283 * within the message case block. If returning true result should be returned
6284 * immediately (no more processing).
6286 PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue)
6288 // Handle both flavors of mouse wheel events.
6289 static int iDeltaPerLine, iDeltaPerChar;
6290 static ULONG ulScrollLines, ulScrollChars = 1;
6291 static int currentVDelta, currentHDelta;
6292 static HWND currentWindow = 0;
6294 PRBool isVertical = msg == WM_MOUSEWHEEL;
6296 // Get mouse wheel metrics (but only once).
6297 if (getWheelInfo) {
6298 getWheelInfo = PR_FALSE;
6300 SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
6302 // ulScrollLines usually equals 3 or 0 (for no scrolling)
6303 // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
6305 // However, if ulScrollLines > WHEEL_DELTA, we assume that
6306 // the mouse driver wants a page scroll. The docs state that
6307 // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
6308 // since some mouse drivers use an arbitrary large number instead,
6309 // we have to handle that as well.
6311 iDeltaPerLine = 0;
6312 if (ulScrollLines) {
6313 if (ulScrollLines <= WHEEL_DELTA) {
6314 iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
6315 } else {
6316 ulScrollLines = WHEEL_PAGESCROLL;
6320 if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
6321 &ulScrollChars, 0)) {
6322 // Note that we may always fail to get the value before Win Vista.
6323 ulScrollChars = 1;
6326 iDeltaPerChar = 0;
6327 if (ulScrollChars) {
6328 if (ulScrollChars <= WHEEL_DELTA) {
6329 iDeltaPerChar = WHEEL_DELTA / ulScrollChars;
6330 } else {
6331 ulScrollChars = WHEEL_PAGESCROLL;
6336 if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) ||
6337 (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar))
6338 return PR_FALSE; // break
6340 // The mousewheel event will be dispatched to the toplevel
6341 // window. We need to give it to the child window
6342 PRBool quit;
6343 if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit))
6344 return quit; // return immediately if its not our window
6346 // We should cancel the surplus delta if the current window is not
6347 // same as previous.
6348 if (currentWindow != mWnd) {
6349 currentVDelta = 0;
6350 currentHDelta = 0;
6351 currentWindow = mWnd;
6354 nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
6355 scrollEvent.delta = 0;
6356 if (isVertical) {
6357 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
6358 if (ulScrollLines == WHEEL_PAGESCROLL) {
6359 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6360 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1;
6361 } else {
6362 currentVDelta -= (short) HIWORD (wParam);
6363 if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
6364 scrollEvent.delta = currentVDelta / iDeltaPerLine;
6365 currentVDelta %= iDeltaPerLine;
6368 } else {
6369 scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
6370 if (ulScrollChars == WHEEL_PAGESCROLL) {
6371 scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
6372 scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1;
6373 } else {
6374 currentHDelta += (short) HIWORD (wParam);
6375 if (PR_ABS(currentHDelta) >= iDeltaPerChar) {
6376 scrollEvent.delta = currentHDelta / iDeltaPerChar;
6377 currentHDelta %= iDeltaPerChar;
6382 if (!scrollEvent.delta) {
6383 // We store the wheel delta, and it will be used next wheel message, so,
6384 // we consume this message actually. We shouldn't call next wndproc.
6385 result = PR_TRUE;
6386 return PR_FALSE; // break
6389 #ifdef MOZ_IPC
6390 // The event may go to a plug-in which already dispatched this message.
6391 // Then, the event can cause deadlock. We should unlock the sender here.
6392 ::ReplyMessage(isVertical ? 0 : TRUE);
6393 #endif
6395 scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
6396 scrollEvent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
6397 scrollEvent.isMeta = PR_FALSE;
6398 scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT);
6399 InitEvent(scrollEvent);
6400 if (nsnull != mEventCallback) {
6401 result = DispatchWindowEvent(&scrollEvent);
6403 // Note that we should return zero if we process WM_MOUSEWHEEL.
6404 // But if we process WM_MOUSEHWHEEL, we should return non-zero.
6406 if (result)
6407 *aRetValue = isVertical ? 0 : TRUE;
6409 return PR_FALSE; // break;
6412 static PRBool
6413 StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,
6414 const PRUnichar* aChars2, const PRUint32 aNumChars2)
6416 if (aNumChars1 != aNumChars2)
6417 return PR_FALSE;
6419 nsCaseInsensitiveStringComparator comp;
6420 return comp(aChars1, aChars2, aNumChars1) == 0;
6423 UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
6425 #ifndef WINCE
6426 switch (aNativeKeyCode) {
6427 case VK_OEM_1: return NS_VK_SEMICOLON; // 0xBA, For the US standard keyboard, the ';:' key
6428 case VK_OEM_PLUS: return NS_VK_ADD; // 0xBB, For any country/region, the '+' key
6429 case VK_OEM_MINUS: return NS_VK_SUBTRACT; // 0xBD, For any country/region, the '-' key
6431 #endif
6433 return aNativeKeyCode;
6437 * nsWindow::OnKeyDown peeks into the message queue and pulls out
6438 * WM_CHAR messages for processing. During testing we don't want to
6439 * mess with the real message queue. Instead we pass a
6440 * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
6441 * that as if it was in the message queue, and refrain from actually
6442 * looking at or touching the message queue.
6444 LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
6445 nsModifierKeyState &aModKeyState,
6446 PRBool *aEventDispatched,
6447 nsFakeCharMessage* aFakeCharMessage)
6449 UINT virtualKeyCode = aMsg.wParam;
6451 #ifndef WINCE
6452 gKbdLayout.OnKeyDown (virtualKeyCode);
6453 #endif
6455 // Use only DOMKeyCode for XP processing.
6456 // Use aVirtualKeyCode for gKbdLayout and native processing.
6457 UINT DOMKeyCode = nsIMM32Handler::IsComposingOn(this) ?
6458 virtualKeyCode : MapFromNativeToDOM(virtualKeyCode);
6460 #ifdef DEBUG
6461 //printf("In OnKeyDown virt: %d\n", DOMKeyCode);
6462 #endif
6464 PRBool noDefault =
6465 DispatchKeyEvent(NS_KEY_DOWN, 0, nsnull, DOMKeyCode, &aMsg, aModKeyState);
6466 if (aEventDispatched)
6467 *aEventDispatched = PR_TRUE;
6469 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
6470 // for almost all keys
6471 switch (DOMKeyCode) {
6472 case NS_VK_SHIFT:
6473 case NS_VK_CONTROL:
6474 case NS_VK_ALT:
6475 case NS_VK_CAPS_LOCK:
6476 case NS_VK_NUM_LOCK:
6477 case NS_VK_SCROLL_LOCK: return noDefault;
6480 PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
6481 MSG msg;
6482 BOOL gotMsg = aFakeCharMessage ||
6483 ::PeekMessageW(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6484 // Enter and backspace are always handled here to avoid for example the
6485 // confusion between ctrl-enter and ctrl-J.
6486 if (DOMKeyCode == NS_VK_RETURN || DOMKeyCode == NS_VK_BACK ||
6487 ((aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)
6488 #ifdef WINCE
6490 #else
6491 && !gKbdLayout.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
6492 #endif
6494 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
6495 // They can be more than one because of:
6496 // * Dead-keys not pairing with base character
6497 // * Some keyboard layouts may map up to 4 characters to the single key
6498 PRBool anyCharMessagesRemoved = PR_FALSE;
6500 if (aFakeCharMessage) {
6501 anyCharMessagesRemoved = PR_TRUE;
6502 } else {
6503 while (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR))
6505 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6506 ("%s charCode=%d scanCode=%d\n", msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6507 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6508 RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST, WM_KEYLAST);
6509 anyCharMessagesRemoved = PR_TRUE;
6511 gotMsg = ::PeekMessageW (&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
6515 if (!anyCharMessagesRemoved && DOMKeyCode == NS_VK_BACK &&
6516 nsIMM32Handler::IsDoingKakuteiUndo(mWnd)) {
6517 NS_ASSERTION(!aFakeCharMessage,
6518 "We shouldn't be touching the real msg queue");
6519 RemoveMessageAndDispatchPluginEvent(WM_CHAR, WM_CHAR);
6522 else if (gotMsg &&
6523 (aFakeCharMessage ||
6524 msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
6525 if (aFakeCharMessage)
6526 return OnCharRaw(aFakeCharMessage->mCharCode,
6527 aFakeCharMessage->mScanCode, aModKeyState, extraFlags);
6529 // If prevent default set for keydown, do same for keypress
6530 ::GetMessageW(&msg, mWnd, msg.message, msg.message);
6532 if (msg.message == WM_DEADCHAR) {
6533 if (!PluginHasFocus())
6534 return PR_FALSE;
6536 // We need to send the removed message to focused plug-in.
6537 DispatchPluginEvent(msg);
6538 return noDefault;
6541 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6542 ("%s charCode=%d scanCode=%d\n",
6543 msg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
6544 msg.wParam, HIWORD(msg.lParam) & 0xFF));
6546 BOOL result = OnChar(msg, aModKeyState, nsnull, extraFlags);
6547 // If a syschar keypress wasn't processed, Windows may want to
6548 // handle it to activate a native menu.
6549 if (!result && msg.message == WM_SYSCHAR)
6550 ::DefWindowProcW(mWnd, msg.message, msg.wParam, msg.lParam);
6551 return result;
6553 #ifndef WINCE
6554 else if (!aModKeyState.mIsControlDown && !aModKeyState.mIsAltDown &&
6555 (KeyboardLayout::IsPrintableCharKey(virtualKeyCode) ||
6556 KeyboardLayout::IsNumpadKey(virtualKeyCode)))
6558 // If this is simple KeyDown event but next message is not WM_CHAR,
6559 // this event may not input text, so we should ignore this event.
6560 // See bug 314130.
6561 return PluginHasFocus() && noDefault;
6564 if (gKbdLayout.IsDeadKey ())
6565 return PluginHasFocus() && noDefault;
6567 PRUint8 shiftStates[5];
6568 PRUnichar uniChars[5];
6569 PRUnichar shiftedChars[5] = {0, 0, 0, 0, 0};
6570 PRUnichar unshiftedChars[5] = {0, 0, 0, 0, 0};
6571 PRUnichar shiftedLatinChar = 0;
6572 PRUnichar unshiftedLatinChar = 0;
6573 PRUint32 numOfUniChars = 0;
6574 PRUint32 numOfShiftedChars = 0;
6575 PRUint32 numOfUnshiftedChars = 0;
6576 PRUint32 numOfShiftStates = 0;
6578 switch (virtualKeyCode) {
6579 // keys to be sent as characters
6580 case VK_ADD: uniChars [0] = '+'; numOfUniChars = 1; break;
6581 case VK_SUBTRACT: uniChars [0] = '-'; numOfUniChars = 1; break;
6582 case VK_DIVIDE: uniChars [0] = '/'; numOfUniChars = 1; break;
6583 case VK_MULTIPLY: uniChars [0] = '*'; numOfUniChars = 1; break;
6584 case VK_NUMPAD0:
6585 case VK_NUMPAD1:
6586 case VK_NUMPAD2:
6587 case VK_NUMPAD3:
6588 case VK_NUMPAD4:
6589 case VK_NUMPAD5:
6590 case VK_NUMPAD6:
6591 case VK_NUMPAD7:
6592 case VK_NUMPAD8:
6593 case VK_NUMPAD9:
6594 uniChars [0] = virtualKeyCode - VK_NUMPAD0 + '0';
6595 numOfUniChars = 1;
6596 break;
6597 default:
6598 if (KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
6599 numOfUniChars = numOfShiftStates =
6600 gKbdLayout.GetUniChars(uniChars, shiftStates,
6601 NS_ARRAY_LENGTH(uniChars));
6604 if (aModKeyState.mIsControlDown ^ aModKeyState.mIsAltDown) {
6605 PRUint8 capsLockState = (::GetKeyState(VK_CAPITAL) & 1) ? eCapsLock : 0;
6606 numOfUnshiftedChars =
6607 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode, capsLockState,
6608 unshiftedChars, NS_ARRAY_LENGTH(unshiftedChars));
6609 numOfShiftedChars =
6610 gKbdLayout.GetUniCharsWithShiftState(virtualKeyCode,
6611 capsLockState | eShift,
6612 shiftedChars, NS_ARRAY_LENGTH(shiftedChars));
6614 // The current keyboard cannot input alphabets or numerics,
6615 // we should append them for Shortcut/Access keys.
6616 // E.g., for Cyrillic keyboard layout.
6617 if (NS_VK_A <= DOMKeyCode && DOMKeyCode <= NS_VK_Z) {
6618 shiftedLatinChar = unshiftedLatinChar = DOMKeyCode;
6619 if (capsLockState)
6620 shiftedLatinChar += 0x20;
6621 else
6622 unshiftedLatinChar += 0x20;
6623 if (unshiftedLatinChar == unshiftedChars[0] &&
6624 shiftedLatinChar == shiftedChars[0]) {
6625 shiftedLatinChar = unshiftedLatinChar = 0;
6627 } else {
6628 PRUint16 ch = 0;
6629 if (NS_VK_0 <= DOMKeyCode && DOMKeyCode <= NS_VK_9) {
6630 ch = DOMKeyCode;
6631 } else {
6632 switch (virtualKeyCode) {
6633 case VK_OEM_PLUS: ch = '+'; break;
6634 case VK_OEM_MINUS: ch = '-'; break;
6637 if (ch && unshiftedChars[0] != ch && shiftedChars[0] != ch) {
6638 // Windows has assigned a virtual key code to the key even though
6639 // the character can't be produced with this key. That probably
6640 // means the character can't be produced with any key in the
6641 // current layout and so the assignment is based on a QWERTY
6642 // layout. Append this code so that users can access the shortcut.
6643 unshiftedLatinChar = ch;
6647 // If the charCode is not ASCII character, we should replace the
6648 // charCode with ASCII character only when Ctrl is pressed.
6649 // But don't replace the charCode when the charCode is not same as
6650 // unmodified characters. In such case, Ctrl is sometimes used for a
6651 // part of character inputting key combination like Shift.
6652 if (aModKeyState.mIsControlDown) {
6653 PRUint8 currentState = eCtrl;
6654 if (aModKeyState.mIsShiftDown)
6655 currentState |= eShift;
6657 PRUint32 ch =
6658 aModKeyState.mIsShiftDown ? shiftedLatinChar : unshiftedLatinChar;
6659 if (ch &&
6660 (numOfUniChars == 0 ||
6661 StringCaseInsensitiveEquals(uniChars, numOfUniChars,
6662 aModKeyState.mIsShiftDown ? shiftedChars : unshiftedChars,
6663 aModKeyState.mIsShiftDown ? numOfShiftedChars :
6664 numOfUnshiftedChars))) {
6665 numOfUniChars = numOfShiftStates = 1;
6666 uniChars[0] = ch;
6667 shiftStates[0] = currentState;
6673 if (numOfUniChars > 0 || numOfShiftedChars > 0 || numOfUnshiftedChars > 0) {
6674 PRUint32 num = PR_MAX(numOfUniChars,
6675 PR_MAX(numOfShiftedChars, numOfUnshiftedChars));
6676 PRUint32 skipUniChars = num - numOfUniChars;
6677 PRUint32 skipShiftedChars = num - numOfShiftedChars;
6678 PRUint32 skipUnshiftedChars = num - numOfUnshiftedChars;
6679 UINT keyCode = numOfUniChars == 0 ? DOMKeyCode : 0;
6680 for (PRUint32 cnt = 0; cnt < num; cnt++) {
6681 PRUint16 uniChar, shiftedChar, unshiftedChar;
6682 uniChar = shiftedChar = unshiftedChar = 0;
6683 if (skipUniChars <= cnt) {
6684 if (cnt - skipUniChars < numOfShiftStates) {
6685 // If key in combination with Alt and/or Ctrl produces a different
6686 // character than without them then do not report these flags
6687 // because it is separate keyboard layout shift state. If dead-key
6688 // and base character does not produce a valid composite character
6689 // then both produced dead-key character and following base
6690 // character may have different modifier flags, too.
6691 aModKeyState.mIsShiftDown =
6692 (shiftStates[cnt - skipUniChars] & eShift) != 0;
6693 aModKeyState.mIsControlDown =
6694 (shiftStates[cnt - skipUniChars] & eCtrl) != 0;
6695 aModKeyState.mIsAltDown =
6696 (shiftStates[cnt - skipUniChars] & eAlt) != 0;
6698 uniChar = uniChars[cnt - skipUniChars];
6700 if (skipShiftedChars <= cnt)
6701 shiftedChar = shiftedChars[cnt - skipShiftedChars];
6702 if (skipUnshiftedChars <= cnt)
6703 unshiftedChar = unshiftedChars[cnt - skipUnshiftedChars];
6704 nsAutoTArray<nsAlternativeCharCode, 5> altArray;
6706 if (shiftedChar || unshiftedChar) {
6707 nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
6708 altArray.AppendElement(chars);
6710 if (cnt == num - 1 && (unshiftedLatinChar || shiftedLatinChar)) {
6711 nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
6712 altArray.AppendElement(chars);
6715 DispatchKeyEvent(NS_KEY_PRESS, uniChar, &altArray,
6716 keyCode, nsnull, aModKeyState, extraFlags);
6718 } else {
6719 DispatchKeyEvent(NS_KEY_PRESS, 0, nsnull, DOMKeyCode, nsnull, aModKeyState,
6720 extraFlags);
6722 #else
6724 UINT unichar = ::MapVirtualKey(virtualKeyCode, MAPVK_VK_TO_CHAR);
6725 // Check for dead characters or no mapping
6726 if (unichar & 0x80) {
6727 return noDefault;
6729 DispatchKeyEvent(NS_KEY_PRESS, unichar, nsnull, DOMKeyCode, nsnull, aModKeyState,
6730 extraFlags);
6732 #endif
6734 return noDefault;
6737 // OnKeyUp
6738 LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
6739 nsModifierKeyState &aModKeyState,
6740 PRBool *aEventDispatched)
6742 UINT virtualKeyCode = aMsg.wParam;
6744 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
6745 ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
6747 if (!nsIMM32Handler::IsComposingOn(this)) {
6748 virtualKeyCode = MapFromNativeToDOM(virtualKeyCode);
6751 if (aEventDispatched)
6752 *aEventDispatched = PR_TRUE;
6753 return DispatchKeyEvent(NS_KEY_UP, 0, nsnull, virtualKeyCode, &aMsg,
6754 aModKeyState);
6757 // OnChar
6758 LRESULT nsWindow::OnChar(const MSG &aMsg, nsModifierKeyState &aModKeyState,
6759 PRBool *aEventDispatched, PRUint32 aFlags)
6761 return OnCharRaw(aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF, aModKeyState,
6762 aFlags, &aMsg, aEventDispatched);
6765 // OnCharRaw
6766 LRESULT nsWindow::OnCharRaw(UINT charCode, UINT aScanCode,
6767 nsModifierKeyState &aModKeyState, PRUint32 aFlags,
6768 const MSG *aMsg, PRBool *aEventDispatched)
6770 // ignore [shift+]alt+space so the OS can handle it
6771 if (aModKeyState.mIsAltDown && !aModKeyState.mIsControlDown &&
6772 IS_VK_DOWN(NS_VK_SPACE)) {
6773 return FALSE;
6776 // Ignore Ctrl+Enter (bug 318235)
6777 if (aModKeyState.mIsControlDown && charCode == 0xA) {
6778 return FALSE;
6781 // WM_CHAR with Control and Alt (== AltGr) down really means a normal character
6782 PRBool saveIsAltDown = aModKeyState.mIsAltDown;
6783 PRBool saveIsControlDown = aModKeyState.mIsControlDown;
6784 if (aModKeyState.mIsAltDown && aModKeyState.mIsControlDown)
6785 aModKeyState.mIsAltDown = aModKeyState.mIsControlDown = PR_FALSE;
6787 wchar_t uniChar;
6789 if (nsIMM32Handler::IsComposingOn(this)) {
6790 ResetInputState();
6793 if (aModKeyState.mIsControlDown && charCode <= 0x1A) { // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
6794 // need to account for shift here. bug 16486
6795 if (aModKeyState.mIsShiftDown)
6796 uniChar = charCode - 1 + 'A';
6797 else
6798 uniChar = charCode - 1 + 'a';
6799 charCode = 0;
6801 else if (aModKeyState.mIsControlDown && charCode <= 0x1F) {
6802 // Fix for 50255 - <ctrl><[> and <ctrl><]> are not being processed.
6803 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
6804 // for some reason the keypress handler need to have the uniChar code set
6805 // with the addition of a upper case A not the lower case.
6806 uniChar = charCode - 1 + 'A';
6807 charCode = 0;
6808 } else { // 0x20 - SPACE, 0x3D - EQUALS
6809 if (charCode < 0x20 || (charCode == 0x3D && aModKeyState.mIsControlDown)) {
6810 uniChar = 0;
6811 } else {
6812 uniChar = charCode;
6813 charCode = 0;
6817 // Keep the characters unshifted for shortcuts and accesskeys and make sure
6818 // that numbers are always passed as such (among others: bugs 50255 and 351310)
6819 if (uniChar && (aModKeyState.mIsControlDown || aModKeyState.mIsAltDown)) {
6820 UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK,
6821 gKbdLayout.GetLayout());
6822 UINT unshiftedCharCode =
6823 virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
6824 aModKeyState.mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode,
6825 MAPVK_VK_TO_CHAR,
6826 gKbdLayout.GetLayout()) : 0;
6827 // ignore diacritics (top bit set) and key mapping errors (char code 0)
6828 if ((INT)unshiftedCharCode > 0)
6829 uniChar = unshiftedCharCode;
6832 // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
6833 // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
6834 // pressed too.
6835 if (!aModKeyState.mIsShiftDown && (saveIsAltDown || saveIsControlDown)) {
6836 uniChar = towlower(uniChar);
6839 PRBool result = DispatchKeyEvent(NS_KEY_PRESS, uniChar, nsnull,
6840 charCode, aMsg, aModKeyState, aFlags);
6841 if (aEventDispatched)
6842 *aEventDispatched = PR_TRUE;
6843 aModKeyState.mIsAltDown = saveIsAltDown;
6844 aModKeyState.mIsControlDown = saveIsControlDown;
6845 return result;
6848 void
6849 nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers)
6851 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierKeyMap); ++i) {
6852 const PRUint32* map = sModifierKeyMap[i];
6853 if (aModifiers & map[0]) {
6854 aArray->AppendElement(KeyPair(map[1], map[2]));
6859 nsresult
6860 nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
6862 // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
6863 // here, if that helps in some situations. So far I haven't seen a
6864 // need.
6865 for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
6866 const Configuration& configuration = aConfigurations[i];
6867 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
6868 NS_ASSERTION(w->GetParent() == this,
6869 "Configured widget is not a child");
6870 #ifdef WINCE
6871 // MSDN says we should do on WinCE this before moving or resizing the window
6872 // See http://msdn.microsoft.com/en-us/library/aa930600.aspx
6873 // We put the region back just below, anyway.
6874 ::SetWindowRgn(w->mWnd, NULL, TRUE);
6875 #endif
6876 nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_TRUE);
6877 NS_ENSURE_SUCCESS(rv, rv);
6878 nsIntRect bounds;
6879 w->GetBounds(bounds);
6880 if (bounds.Size() != configuration.mBounds.Size()) {
6881 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
6882 configuration.mBounds.width, configuration.mBounds.height,
6883 PR_TRUE);
6884 } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
6885 w->Move(configuration.mBounds.x, configuration.mBounds.y);
6887 rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_FALSE);
6888 NS_ENSURE_SUCCESS(rv, rv);
6890 return NS_OK;
6893 static HRGN
6894 CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
6896 PRInt32 size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
6897 nsAutoTArray<PRUint8,100> buf;
6898 if (!buf.SetLength(size))
6899 return NULL;
6900 RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
6901 RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
6902 data->rdh.dwSize = sizeof(data->rdh);
6903 data->rdh.iType = RDH_RECTANGLES;
6904 data->rdh.nCount = aRects.Length();
6905 nsIntRect bounds;
6906 for (PRUint32 i = 0; i < aRects.Length(); ++i) {
6907 const nsIntRect& r = aRects[i];
6908 bounds.UnionRect(bounds, r);
6909 ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
6911 ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
6912 return ::ExtCreateRegion(NULL, buf.Length(), data);
6915 nsresult
6916 nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
6917 PRBool aIntersectWithExisting)
6919 if (!aIntersectWithExisting) {
6920 if (!StoreWindowClipRegion(aRects))
6921 return NS_OK;
6922 } else {
6923 // In this case still early return if nothing changed.
6924 if (mClipRects && mClipRectCount == aRects.Length() &&
6925 memcmp(mClipRects,
6926 aRects.Elements(),
6927 sizeof(nsIntRect)*mClipRectCount) == 0) {
6928 return NS_OK;
6932 HRGN dest = CreateHRGNFromArray(aRects);
6933 if (!dest)
6934 return NS_ERROR_OUT_OF_MEMORY;
6936 if (aIntersectWithExisting) {
6937 HRGN current = ::CreateRectRgn(0, 0, 0, 0);
6938 if (current) {
6939 if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
6940 ::CombineRgn(dest, dest, current, RGN_AND);
6942 ::DeleteObject(current);
6946 if (!::SetWindowRgn(mWnd, dest, TRUE)) {
6947 ::DeleteObject(dest);
6948 return NS_ERROR_FAILURE;
6950 return NS_OK;
6953 // WM_DESTROY event handler
6954 void nsWindow::OnDestroy()
6956 mOnDestroyCalled = PR_TRUE;
6958 // Make sure we don't get destroyed in the process of tearing down.
6959 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
6961 // Dispatch the NS_DESTROY event. Must be called before mEventCallback is cleared.
6962 if (!mInDtor)
6963 DispatchStandardEvent(NS_DESTROY);
6965 // Prevent the widget from sending additional events.
6966 mEventCallback = nsnull;
6968 // Free our subclass and clear |this| stored in the window props. We will no longer
6969 // receive events from Windows after this point.
6970 SubclassWindow(FALSE);
6972 // Once mEventCallback is cleared and the subclass is reset, sCurrentWindow can be
6973 // cleared. (It's used in tracking windows for mouse events.)
6974 if (sCurrentWindow == this)
6975 sCurrentWindow = nsnull;
6977 // Disconnects us from our parent, will call our GetParent().
6978 nsBaseWidget::Destroy();
6980 // Release references to children, device context, toolkit, and app shell.
6981 nsBaseWidget::OnDestroy();
6983 // Clear our native parent handle.
6984 // XXX Windows will take care of this in the proper order, and SetParent(nsnull)'s
6985 // remove child on the parent already took place in nsBaseWidget's Destroy call above.
6986 //SetParent(nsnull);
6987 mParent = nsnull;
6989 // We have to destroy the native drag target before we null out our window pointer.
6990 EnableDragDrop(PR_FALSE);
6992 // If we're going away and for some reason we're still the rollup widget, rollup and
6993 // turn off capture.
6994 if ( this == sRollupWidget ) {
6995 if ( sRollupListener )
6996 sRollupListener->Rollup(nsnull, nsnull);
6997 CaptureRollupEvents(nsnull, nsnull, PR_FALSE, PR_TRUE);
7000 // If IME is disabled, restore it.
7001 if (mOldIMC) {
7002 mOldIMC = ::ImmAssociateContext(mWnd, mOldIMC);
7003 NS_ASSERTION(!mOldIMC, "Another IMC was associated");
7006 // Turn off mouse trails if enabled.
7007 MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
7008 if (mtrailer) {
7009 if (mtrailer->GetMouseTrailerWindow() == mWnd)
7010 mtrailer->DestroyTimer();
7012 if (mtrailer->GetCaptureWindow() == mWnd)
7013 mtrailer->SetCaptureWindow(nsnull);
7016 // Free GDI window class objects
7017 if (mBrush) {
7018 VERIFY(::DeleteObject(mBrush));
7019 mBrush = NULL;
7022 // Free app icon resources.
7023 HICON icon;
7024 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM) 0);
7025 if (icon)
7026 ::DestroyIcon(icon);
7028 icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM) 0);
7029 if (icon)
7030 ::DestroyIcon(icon);
7032 // Destroy any custom cursor resources.
7033 if (mCursor == -1)
7034 SetCursor(eCursor_standard);
7036 #ifdef MOZ_XUL
7037 // Reset transparency
7038 if (eTransparencyTransparent == mTransparencyMode)
7039 SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
7040 #endif
7042 #if defined(WINCE_HAVE_SOFTKB)
7043 // Revert the changes made for the software keyboard settings
7044 nsWindowCE::ResetSoftKB(mWnd);
7045 #endif
7047 #if !defined(WINCE)
7048 // Finalize panning feedback to possibly restore window displacement
7049 mGesture.PanFeedbackFinalize(mWnd, PR_TRUE);
7050 #endif
7052 // Clear the main HWND.
7053 mWnd = NULL;
7056 // OnMove
7057 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
7059 mBounds.x = aX;
7060 mBounds.y = aY;
7062 nsGUIEvent event(PR_TRUE, NS_MOVE, this);
7063 InitEvent(event);
7064 event.refPoint.x = aX;
7065 event.refPoint.y = aY;
7067 return DispatchWindowEvent(&event);
7070 // Send a resize message to the listener
7071 PRBool nsWindow::OnResize(nsIntRect &aWindowRect)
7073 #ifdef CAIRO_HAS_D2D_SURFACE
7074 if (mD2DWindowSurface) {
7075 mD2DWindowSurface = NULL;
7076 Invalidate(PR_FALSE);
7078 #endif
7080 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7081 UpdateCaptionButtonsClippingRect();
7082 #endif
7084 // call the event callback
7085 if (mEventCallback) {
7086 nsSizeEvent event(PR_TRUE, NS_SIZE, this);
7087 InitEvent(event);
7088 event.windowSize = &aWindowRect;
7089 RECT r;
7090 if (::GetWindowRect(mWnd, &r)) {
7091 event.mWinWidth = PRInt32(r.right - r.left);
7092 event.mWinHeight = PRInt32(r.bottom - r.top);
7093 } else {
7094 event.mWinWidth = 0;
7095 event.mWinHeight = 0;
7098 #if 0
7099 printf("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
7100 aWindowRect.x, aWindowRect.y, aWindowRect.width, aWindowRect.height,
7101 event.mWinWidth, event.mWinHeight);
7102 #endif
7104 return DispatchWindowEvent(&event);
7107 return PR_FALSE;
7110 #if !defined(WINCE) // implemented in nsWindowCE.cpp
7111 PRBool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
7113 return PR_TRUE;
7115 #endif // !defined(WINCE)
7117 void nsWindow::OnSettingsChange(WPARAM wParam, LPARAM lParam)
7119 if (mWindowType == eWindowType_dialog ||
7120 mWindowType == eWindowType_toplevel )
7121 nsWindowGfx::OnSettingsChangeGfx(wParam);
7124 static PRBool IsOurProcessWindow(HWND aHWND)
7126 DWORD processId = 0;
7127 ::GetWindowThreadProcessId(aHWND, &processId);
7128 return processId == ::GetCurrentProcessId();
7131 static HWND FindOurProcessWindow(HWND aHWND)
7133 for (HWND wnd = ::GetParent(aHWND); wnd; wnd = ::GetParent(wnd)) {
7134 if (IsOurProcessWindow(wnd)) {
7135 return wnd;
7138 return nsnull;
7141 // Scrolling helper function for handling plugins.
7142 // Return value indicates whether the calling function should handle this
7143 // aHandled indicates whether this was handled at all
7144 // aQuitProcessing tells whether or not to continue processing the message
7145 PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
7146 LPARAM aLParam, PRBool& aHandled,
7147 LRESULT* aRetValue,
7148 PRBool& aQuitProcessing)
7150 // The scroll event will be dispatched to the toplevel
7151 // window. We need to give it to the child window
7152 aQuitProcessing = PR_FALSE; // default is to not stop processing
7153 POINT point;
7154 DWORD dwPoints = ::GetMessagePos();
7155 point.x = GET_X_LPARAM(dwPoints);
7156 point.y = GET_Y_LPARAM(dwPoints);
7158 static PRBool sIsProcessing = PR_FALSE;
7159 if (sIsProcessing) {
7160 return PR_TRUE; // the caller should handle this.
7163 static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
7164 if (aMsg == WM_MOUSEHWHEEL) {
7165 // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
7166 // always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs one
7167 // message at first time, this time, ::GetMessagePos works fine.
7168 // Then, we will return 0 (0 means we process it) to the message. Then, the
7169 // driver will POST the same messages continuously during the wheel tilted.
7170 // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
7171 // cursor isn't 0,0. Therefore, we cannot trust the result of
7172 // ::GetMessagePos API if the sender is the driver.
7173 if (!sMayBeUsingLogitechMouse && aLParam == 0 && (DWORD)aLParam != dwPoints &&
7174 ::InSendMessage()) {
7175 sMayBeUsingLogitechMouse = PR_TRUE;
7176 } else if (sMayBeUsingLogitechMouse && aLParam != 0 && ::InSendMessage()) {
7177 // The user has changed the mouse from Logitech's to another one (e.g.,
7178 // the user has changed to the touchpad of the notebook.
7179 sMayBeUsingLogitechMouse = PR_FALSE;
7181 // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
7182 // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
7183 // instead.
7184 if (sMayBeUsingLogitechMouse && aLParam == 0 && dwPoints == 0) {
7185 ::GetCursorPos(&point);
7189 HWND destWnd = ::WindowFromPoint(point);
7190 // Since we receive scroll events for as long as
7191 // we are focused, it's entirely possible that there
7192 // is another app's window or no window under the
7193 // pointer.
7195 if (!destWnd) {
7196 // No window is under the pointer
7197 return PR_FALSE; // break, but continue processing
7200 nsWindow* destWindow;
7202 // We don't handle the message if the found window belongs to another
7203 // process's top window. If it belongs window, that is a plug-in's window.
7204 // Then, we need to send the message to the plug-in window.
7205 if (!IsOurProcessWindow(destWnd)) {
7206 HWND ourPluginWnd = FindOurProcessWindow(destWnd);
7207 if (!ourPluginWnd) {
7208 // Somebody elses window
7209 return PR_FALSE; // break, but continue processing
7211 destWindow = GetNSWindowPtr(ourPluginWnd);
7212 } else {
7213 destWindow = GetNSWindowPtr(destWnd);
7216 if (destWindow == this && mWindowType == eWindowType_plugin) {
7217 // If this is plug-in window, the message came from the plug-in window.
7218 // Then, the message should be processed on the parent window.
7219 destWindow = static_cast<nsWindow*>(GetParent());
7220 NS_ENSURE_TRUE(destWindow, PR_FALSE); // break, but continue processing
7221 destWnd = destWindow->mWnd;
7222 NS_ENSURE_TRUE(destWnd, PR_FALSE); // break, but continue processing
7225 if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
7226 // Some other app, or a plugin window.
7227 // Windows directs scrolling messages to the focused window.
7228 // However, Mozilla does not like plugins having focus, so a
7229 // Mozilla window (ie, the plugin's parent (us!) has focus.)
7230 // Therefore, plugins etc _should_ get first grab at the
7231 // message, but this focus vaguary means the plugin misses
7232 // out. If the window is a child of ours, forward it on.
7233 // Determine if a child by walking the parent list until
7234 // we find a parent matching our wndproc.
7235 HWND parentWnd = ::GetParent(destWnd);
7236 while (parentWnd) {
7237 nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
7238 if (parentWindow) {
7239 // We have a child window - quite possibly a plugin window.
7240 // However, not all plugins are created equal - some will handle this
7241 // message themselves, some will forward directly back to us, while
7242 // others will call DefWndProc, which itself still forwards back to us.
7243 // So if we have sent it once, we need to handle it ourself.
7245 #ifdef MOZ_IPC
7246 // XXX The message shouldn't come from the plugin window at here.
7247 // But the message might come from it due to some bugs. If it happens,
7248 // SendMessage causes deadlock. For safety, we should unlock the
7249 // sender here.
7250 ::ReplyMessage(aMsg == WM_MOUSEHWHEEL ? TRUE : 0);
7251 #endif
7253 // First time we have seen this message.
7254 // Call the child - either it will consume it, or
7255 // it will wind it's way back to us,triggering the destWnd case above
7256 // either way,when the call returns,we are all done with the message,
7257 sIsProcessing = PR_TRUE;
7258 ::SendMessageW(destWnd, aMsg, aWParam, aLParam);
7259 sIsProcessing = PR_FALSE;
7260 aHandled = PR_TRUE;
7261 aQuitProcessing = PR_TRUE;
7262 return PR_FALSE; // break, and stop processing
7264 parentWnd = ::GetParent(parentWnd);
7265 } // while parentWnd
7267 if (destWnd == nsnull)
7268 return PR_FALSE;
7269 if (destWnd != mWnd) {
7270 if (destWindow) {
7271 sIsProcessing = PR_TRUE;
7272 aHandled = destWindow->ProcessMessage(aMsg, aWParam, aLParam, aRetValue);
7273 sIsProcessing = PR_FALSE;
7274 aQuitProcessing = PR_TRUE;
7275 return PR_FALSE; // break, and stop processing
7277 #ifdef DEBUG
7278 else
7279 printf("WARNING: couldn't get child window for SCROLL event\n");
7280 #endif
7282 return PR_TRUE; // caller should handle this
7285 PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
7287 static PRInt8 sMouseWheelEmulation = -1;
7288 if (sMouseWheelEmulation < 0) {
7289 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7290 NS_ENSURE_TRUE(prefs, PR_FALSE);
7291 nsCOMPtr<nsIPrefBranch> prefBranch;
7292 prefs->GetBranch(0, getter_AddRefs(prefBranch));
7293 NS_ENSURE_TRUE(prefBranch, PR_FALSE);
7294 PRBool emulate;
7295 nsresult rv =
7296 prefBranch->GetBoolPref("mousewheel.emulate_at_wm_scroll", &emulate);
7297 NS_ENSURE_SUCCESS(rv, PR_FALSE);
7298 sMouseWheelEmulation = PRInt8(emulate);
7301 if (aLParam || sMouseWheelEmulation) {
7302 // Scroll message generated by Thinkpad Trackpoint Driver or similar
7303 // Treat as a mousewheel message and scroll appropriately
7304 PRBool quit, result;
7305 LRESULT retVal;
7307 if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result, &retVal, quit))
7308 return quit; // Return if it's not our message or has been dispatched
7310 nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
7311 scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
7312 ? nsMouseScrollEvent::kIsVertical
7313 : nsMouseScrollEvent::kIsHorizontal;
7314 switch (LOWORD(aWParam))
7316 case SB_PAGEDOWN:
7317 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7318 case SB_LINEDOWN:
7319 scrollevent.delta = 1;
7320 break;
7321 case SB_PAGEUP:
7322 scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
7323 case SB_LINEUP:
7324 scrollevent.delta = -1;
7325 break;
7326 default:
7327 return PR_FALSE;
7329 #ifdef MOZ_IPC
7330 // The event may go to a plug-in which already dispatched this message.
7331 // Then, the event can cause deadlock. We should unlock the sender here.
7332 ::ReplyMessage(0);
7333 #endif
7334 scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
7335 scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
7336 scrollevent.isMeta = PR_FALSE;
7337 scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
7338 InitEvent(scrollevent);
7339 if (nsnull != mEventCallback)
7341 DispatchWindowEvent(&scrollevent);
7343 return PR_TRUE;
7346 // Scroll message generated by external application
7347 nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_SCROLL, this);
7349 command.mScroll.mIsHorizontal = (aMsg == WM_HSCROLL);
7351 switch (LOWORD(aWParam))
7353 case SB_LINEUP: // SB_LINELEFT
7354 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7355 command.mScroll.mAmount = -1;
7356 break;
7357 case SB_LINEDOWN: // SB_LINERIGHT
7358 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
7359 command.mScroll.mAmount = 1;
7360 break;
7361 case SB_PAGEUP: // SB_PAGELEFT
7362 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7363 command.mScroll.mAmount = -1;
7364 break;
7365 case SB_PAGEDOWN: // SB_PAGERIGHT
7366 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
7367 command.mScroll.mAmount = 1;
7368 break;
7369 case SB_TOP: // SB_LEFT
7370 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7371 command.mScroll.mAmount = -1;
7372 break;
7373 case SB_BOTTOM: // SB_RIGHT
7374 command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
7375 command.mScroll.mAmount = 1;
7376 break;
7377 default:
7378 return PR_FALSE;
7380 DispatchWindowEvent(&command);
7381 return PR_TRUE;
7384 // Can be overriden. Controls auto-erase of background.
7385 PRBool nsWindow::AutoErase(HDC dc)
7387 return PR_FALSE;
7390 /**************************************************************
7391 **************************************************************
7393 ** BLOCK: IME management and accessibility
7395 ** Handles managing IME input and accessibility.
7397 **************************************************************
7398 **************************************************************/
7400 NS_IMETHODIMP nsWindow::ResetInputState()
7402 #ifdef DEBUG_KBSTATE
7403 printf("ResetInputState\n");
7404 #endif
7406 #ifdef NS_ENABLE_TSF
7407 nsTextStore::CommitComposition(PR_FALSE);
7408 #endif //NS_ENABLE_TSF
7410 nsIMM32Handler::CommitComposition(this);
7411 return NS_OK;
7414 NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState)
7416 #ifdef DEBUG_KBSTATE
7417 printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
7418 #endif
7420 #ifdef NS_ENABLE_TSF
7421 nsTextStore::SetIMEOpenState(aState);
7422 #endif //NS_ENABLE_TSF
7424 nsIMEContext IMEContext(mWnd);
7425 if (IMEContext.IsValid()) {
7426 ::ImmSetOpenStatus(IMEContext.get(), aState ? TRUE : FALSE);
7428 return NS_OK;
7431 NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState)
7433 nsIMEContext IMEContext(mWnd);
7434 if (IMEContext.IsValid()) {
7435 BOOL isOpen = ::ImmGetOpenStatus(IMEContext.get());
7436 *aState = isOpen ? PR_TRUE : PR_FALSE;
7437 } else
7438 *aState = PR_FALSE;
7440 #ifdef NS_ENABLE_TSF
7441 *aState |= nsTextStore::GetIMEOpenState();
7442 #endif //NS_ENABLE_TSF
7444 return NS_OK;
7447 NS_IMETHODIMP nsWindow::SetIMEEnabled(PRUint32 aState)
7449 #ifdef NS_ENABLE_TSF
7450 nsTextStore::SetIMEEnabled(aState);
7451 #endif //NS_ENABLE_TSF
7452 #ifdef DEBUG_KBSTATE
7453 printf("SetIMEEnabled: %s\n", (aState == nsIWidget::IME_STATUS_ENABLED ||
7454 aState == nsIWidget::IME_STATUS_PLUGIN)?
7455 "Enabled": "Disabled");
7456 #endif
7457 if (nsIMM32Handler::IsComposing()) {
7458 ResetInputState();
7460 mIMEEnabled = aState;
7461 PRBool enable = (aState == nsIWidget::IME_STATUS_ENABLED ||
7462 aState == nsIWidget::IME_STATUS_PLUGIN);
7464 #if defined(WINCE_HAVE_SOFTKB)
7465 sSoftKeyboardState = (aState != nsIWidget::IME_STATUS_DISABLED);
7466 nsWindowCE::ToggleSoftKB(mWnd, sSoftKeyboardState);
7467 #endif
7469 if (!enable != !mOldIMC)
7470 return NS_OK;
7471 mOldIMC = ::ImmAssociateContext(mWnd, enable ? mOldIMC : NULL);
7472 NS_ASSERTION(!enable || !mOldIMC, "Another IMC was associated");
7474 return NS_OK;
7477 NS_IMETHODIMP nsWindow::GetIMEEnabled(PRUint32* aState)
7479 #ifdef DEBUG_KBSTATE
7480 printf("GetIMEEnabled: %s\n", mIMEEnabled? "Enabled": "Disabled");
7481 #endif
7482 *aState = mIMEEnabled;
7483 return NS_OK;
7486 NS_IMETHODIMP nsWindow::CancelIMEComposition()
7488 #ifdef DEBUG_KBSTATE
7489 printf("CancelIMEComposition\n");
7490 #endif
7492 #ifdef NS_ENABLE_TSF
7493 nsTextStore::CommitComposition(PR_TRUE);
7494 #endif //NS_ENABLE_TSF
7496 nsIMM32Handler::CancelComposition(this);
7497 return NS_OK;
7500 NS_IMETHODIMP
7501 nsWindow::GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState)
7503 #ifdef DEBUG_KBSTATE
7504 printf("GetToggledKeyState\n");
7505 #endif
7506 NS_ENSURE_ARG_POINTER(aLEDState);
7507 *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
7508 return NS_OK;
7511 #ifdef NS_ENABLE_TSF
7512 NS_IMETHODIMP
7513 nsWindow::OnIMEFocusChange(PRBool aFocus)
7515 nsresult rv = nsTextStore::OnFocusChange(aFocus, this, mIMEEnabled);
7516 if (rv == NS_ERROR_NOT_AVAILABLE)
7517 rv = NS_ERROR_NOT_IMPLEMENTED; // TSF is not enabled, maybe.
7518 return rv;
7521 NS_IMETHODIMP
7522 nsWindow::OnIMETextChange(PRUint32 aStart,
7523 PRUint32 aOldEnd,
7524 PRUint32 aNewEnd)
7526 return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
7529 NS_IMETHODIMP
7530 nsWindow::OnIMESelectionChange(void)
7532 return nsTextStore::OnSelectionChange();
7534 #endif //NS_ENABLE_TSF
7536 #ifdef ACCESSIBILITY
7538 #ifdef DEBUG_WMGETOBJECT
7539 #define NS_LOG_WMGETOBJECT_WNDACC(aWnd) \
7540 nsAccessible* acc = aWnd ? \
7541 aWnd->DispatchAccessibleEvent(NS_GETACCESSIBLE) : nsnull; \
7542 printf(" acc: %p", acc); \
7543 if (acc) { \
7544 nsAutoString name; \
7545 acc->GetName(name); \
7546 printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \
7547 nsCOMPtr<nsIAccessibleDocument> doc = do_QueryObject(acc); \
7548 void *hwnd = nsnull; \
7549 doc->GetWindowHandle(&hwnd); \
7550 printf(", acc hwnd: %d", hwnd); \
7553 #define NS_LOG_WMGETOBJECT_THISWND \
7555 printf("\n*******Get Doc Accessible*******\nOrig Window: "); \
7556 printf("\n {\n HWND: %d, parent HWND: %d, wndobj: %p, content type: %d,\n",\
7557 mWnd, ::GetParent(mWnd), this, mContentType); \
7558 NS_LOG_WMGETOBJECT_WNDACC(this) \
7559 printf("\n }\n"); \
7562 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd) \
7564 nsWindow* wnd = GetNSWindowPtr(aHwnd); \
7565 printf("Get " aMsg ":\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n", \
7566 aHwnd, ::GetParent(aHwnd), wnd); \
7567 NS_LOG_WMGETOBJECT_WNDACC(wnd); \
7568 printf("\n }\n"); \
7570 #else
7571 #define NS_LOG_WMGETOBJECT_THISWND
7572 #define NS_LOG_WMGETOBJECT_WND(aMsg, aHwnd)
7573 #endif // DEBUG_WMGETOBJECT
7575 nsAccessible*
7576 nsWindow::GetRootAccessible()
7578 // We want the ability to forcibly disable a11y on windows, because
7579 // some non-a11y-related components attempt to bring it up. See bug
7580 // 538530 for details; we have a pref here that allows it to be disabled
7581 // for performance and testing resons.
7583 // This pref is checked only once, and the browser needs a restart to
7584 // pick up any changes.
7585 static int accForceDisable = -1;
7587 if (accForceDisable == -1) {
7588 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
7589 PRBool b = PR_FALSE;
7590 nsresult rv = prefs->GetBoolPref("accessibility.win32.force_disabled", &b);
7591 if (NS_SUCCEEDED(rv) && b) {
7592 accForceDisable = 1;
7593 } else {
7594 accForceDisable = 0;
7598 // If the pref was true, return null here, disabling a11y.
7599 if (accForceDisable)
7600 return nsnull;
7602 nsWindow::sIsAccessibilityOn = TRUE;
7604 if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) {
7605 return nsnull;
7608 NS_LOG_WMGETOBJECT_THISWND
7610 if (mContentType != eContentTypeInherit) {
7611 // We're on a MozillaContentWindowClass or MozillaUIWindowClass window.
7612 // Search for the correct visible child window to get an accessible
7613 // document from. Make sure to use an active child window. If this window
7614 // doesn't have child windows then return an accessible for it.
7615 HWND accessibleWnd = ::GetTopWindow(mWnd);
7616 NS_LOG_WMGETOBJECT_WND("Top Window", accessibleWnd);
7617 if (!accessibleWnd) {
7618 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
7619 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
7622 nsWindow* accessibleWindow = nsnull;
7623 while (accessibleWnd) {
7624 // Loop through windows and find the first one with accessibility info
7625 accessibleWindow = GetNSWindowPtr(accessibleWnd);
7626 if (accessibleWindow) {
7627 nsAccessible *rootAccessible =
7628 accessibleWindow->DispatchAccessibleEvent(NS_GETACCESSIBLE);
7629 if (rootAccessible) {
7630 // Success, one of the child windows was active.
7631 return rootAccessible;
7634 accessibleWnd = ::GetNextWindow(accessibleWnd, GW_HWNDNEXT);
7635 NS_LOG_WMGETOBJECT_WND("Next Window", accessibleWnd);
7637 return nsnull;
7640 NS_LOG_WMGETOBJECT_WND("This Window", mWnd);
7641 return DispatchAccessibleEvent(NS_GETACCESSIBLE);
7644 STDMETHODIMP_(LRESULT)
7645 nsWindow::LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc)
7647 // open the dll dynamically
7648 if (!sAccLib)
7649 sAccLib =::LoadLibraryW(L"OLEACC.DLL");
7651 if (sAccLib) {
7652 if (!sLresultFromObject)
7653 sLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(sAccLib,"LresultFromObject");
7655 if (sLresultFromObject)
7656 return sLresultFromObject(riid,wParam,pAcc);
7659 return 0;
7661 #endif
7663 /**************************************************************
7664 **************************************************************
7666 ** BLOCK: Transparency
7668 ** Window transparency helpers.
7670 **************************************************************
7671 **************************************************************/
7673 #ifdef MOZ_XUL
7675 void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force)
7677 if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
7678 return;
7680 #ifdef CAIRO_HAS_D2D_SURFACE
7681 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7682 gfxWindowsPlatform::RENDER_DIRECT2D) {
7683 nsRefPtr<gfxD2DSurface> newSurface =
7684 new gfxD2DSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7685 mTransparentSurface = newSurface;
7686 mMemoryDC = nsnull;
7687 } else
7688 #endif
7690 nsRefPtr<gfxWindowsSurface> newSurface =
7691 new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxASurface::ImageFormatARGB32);
7692 mTransparentSurface = newSurface;
7693 mMemoryDC = newSurface->GetDC();
7697 void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
7699 #ifndef WINCE
7701 if (aMode == mTransparencyMode)
7702 return;
7704 // stop on dialogs and popups!
7705 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7706 nsWindow* parent = GetNSWindowPtr(hWnd);
7708 if (!parent)
7710 NS_WARNING("Trying to use transparent chrome in an embedded context");
7711 return;
7714 if (parent != this) {
7715 NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!");
7718 if (aMode == eTransparencyTransparent) {
7719 // If we're switching to the use of a transparent window, hide the chrome
7720 // on our parent.
7721 HideWindowChrome(PR_TRUE);
7722 } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) {
7723 // if we're switching out of transparent, re-enable our parent's chrome.
7724 HideWindowChrome(PR_FALSE);
7727 LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE),
7728 exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
7730 if (parent->mIsVisible)
7731 style |= WS_VISIBLE;
7732 if (parent->mSizeMode == nsSizeMode_Maximized)
7733 style |= WS_MAXIMIZE;
7734 else if (parent->mSizeMode == nsSizeMode_Minimized)
7735 style |= WS_MINIMIZE;
7737 if (aMode == eTransparencyTransparent)
7738 exStyle |= WS_EX_LAYERED;
7739 else
7740 exStyle &= ~WS_EX_LAYERED;
7742 VERIFY_WINDOW_STYLE(style);
7743 ::SetWindowLongPtrW(hWnd, GWL_STYLE, style);
7744 ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle);
7746 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7747 if (HasGlass())
7748 memset(&mGlassMargins, 0, sizeof mGlassMargins);
7749 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
7750 mTransparencyMode = aMode;
7752 SetupTranslucentWindowMemoryBitmap(aMode);
7753 UpdateGlass();
7754 #endif // #ifndef WINCE
7757 void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
7759 if (eTransparencyTransparent == aMode) {
7760 ResizeTranslucentWindow(mBounds.width, mBounds.height, PR_TRUE);
7761 } else {
7762 mTransparentSurface = nsnull;
7763 mMemoryDC = NULL;
7767 nsresult nsWindow::UpdateTranslucentWindow()
7769 #ifndef WINCE
7770 if (mBounds.IsEmpty())
7771 return NS_OK;
7773 ::GdiFlush();
7775 BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
7776 SIZE winSize = { mBounds.width, mBounds.height };
7777 POINT srcPos = { 0, 0 };
7778 HWND hWnd = GetTopLevelHWND(mWnd, PR_TRUE);
7779 RECT winRect;
7780 ::GetWindowRect(hWnd, &winRect);
7782 #ifdef CAIRO_HAS_D2D_SURFACE
7783 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7784 gfxWindowsPlatform::RENDER_DIRECT2D) {
7785 mMemoryDC = static_cast<gfxD2DSurface*>(mTransparentSurface.get())->
7786 GetDC(PR_TRUE);
7788 #endif
7789 // perform the alpha blend
7790 PRBool updateSuccesful =
7791 ::UpdateLayeredWindow(hWnd, NULL, (POINT*)&winRect, &winSize, mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA);
7793 #ifdef CAIRO_HAS_D2D_SURFACE
7794 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
7795 gfxWindowsPlatform::RENDER_DIRECT2D) {
7796 nsIntRect r(0, 0, 0, 0);
7797 static_cast<gfxD2DSurface*>(mTransparentSurface.get())->ReleaseDC(&r);
7799 #endif
7801 if (!updateSuccesful) {
7802 return NS_ERROR_FAILURE;
7804 #endif
7806 return NS_OK;
7809 #endif //MOZ_XUL
7811 /**************************************************************
7812 **************************************************************
7814 ** BLOCK: Popup rollup hooks
7816 ** Deals with CaptureRollup on popup windows.
7818 **************************************************************
7819 **************************************************************/
7821 #ifndef WINCE
7822 // Schedules a timer for a window, so we can rollup after processing the hook event
7823 void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId)
7825 // In some cases multiple hooks may be scheduled
7826 // so ignore any other requests once one timer is scheduled
7827 if (sHookTimerId == 0) {
7828 // Remember the window handle and the message ID to be used later
7829 sRollupMsgId = aMsgId;
7830 sRollupMsgWnd = aWnd;
7831 // Schedule native timer for doing the rollup after
7832 // this event is done being processed
7833 sHookTimerId = ::SetTimer(NULL, 0, 0, (TIMERPROC)HookTimerForPopups);
7834 NS_ASSERTION(sHookTimerId, "Timer couldn't be created.");
7838 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7839 int gLastMsgCode = 0;
7840 extern MSGFEventMsgInfo gMSGFEvents[];
7841 #endif
7843 // Process Menu messages, rollup when popup is clicked.
7844 LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam)
7846 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7847 if (sProcessHook) {
7848 MSG* pMsg = (MSG*)lParam;
7850 int inx = 0;
7851 while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != NULL) {
7852 inx++;
7854 if (code != gLastMsgCode) {
7855 if (gMSGFEvents[inx].mId == code) {
7856 #ifdef DEBUG
7857 printf("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", code, gMSGFEvents[inx].mStr, pMsg->hwnd);
7858 #endif
7859 } else {
7860 #ifdef DEBUG
7861 printf("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", code, gMSGFEvents[inx].mId, pMsg->hwnd);
7862 #endif
7864 gLastMsgCode = code;
7866 PrintEvent(pMsg->message, FALSE, FALSE);
7868 #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7870 if (sProcessHook && code == MSGF_MENU) {
7871 MSG* pMsg = (MSG*)lParam;
7872 ScheduleHookTimer( pMsg->hwnd, pMsg->message);
7875 return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
7878 // Process all mouse messages. Roll up when a click is in a native window
7879 // that doesn't have an nsIWidget.
7880 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
7882 if (sProcessHook) {
7883 switch (wParam) {
7884 case WM_LBUTTONDOWN:
7885 case WM_RBUTTONDOWN:
7886 case WM_MBUTTONDOWN:
7887 case WM_MOUSEWHEEL:
7888 case WM_MOUSEHWHEEL:
7890 MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
7891 nsIWidget* mozWin = (nsIWidget*)GetNSWindowPtr(ms->hwnd);
7892 if (mozWin) {
7893 // If this window is windowed plugin window, the mouse events are not
7894 // sent to us.
7895 if (static_cast<nsWindow*>(mozWin)->mWindowType == eWindowType_plugin)
7896 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7897 } else {
7898 ScheduleHookTimer(ms->hwnd, (UINT)wParam);
7900 break;
7904 return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam);
7907 // Process all messages. Roll up when the window is moving, or
7908 // is resizing or when maximized or mininized.
7909 LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam)
7911 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7912 if (sProcessHook) {
7913 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7914 PrintEvent(cwpt->message, FALSE, FALSE);
7916 #endif
7918 if (sProcessHook) {
7919 CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam;
7920 if (cwpt->message == WM_MOVING ||
7921 cwpt->message == WM_SIZING ||
7922 cwpt->message == WM_GETMINMAXINFO) {
7923 ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message);
7927 return ::CallNextHookEx(sCallProcHook, code, wParam, lParam);
7930 // Register the special "hooks" for dropdown processing.
7931 void nsWindow::RegisterSpecialDropdownHooks()
7933 NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!");
7934 NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!");
7936 DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n");
7938 //HMODULE hMod = GetModuleHandle("gkwidget.dll");
7940 // Install msg hook for moving the window and resizing
7941 if (!sMsgFilterHook) {
7942 DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n");
7943 sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, NULL, GetCurrentThreadId());
7944 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7945 if (!sMsgFilterHook) {
7946 printf("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n");
7948 #endif
7951 // Install msg hook for menus
7952 if (!sCallProcHook) {
7953 DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n");
7954 sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, NULL, GetCurrentThreadId());
7955 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7956 if (!sCallProcHook) {
7957 printf("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n");
7959 #endif
7962 // Install msg hook for the mouse
7963 if (!sCallMouseHook) {
7964 DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n");
7965 sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, NULL, GetCurrentThreadId());
7966 #ifdef POPUP_ROLLUP_DEBUG_OUTPUT
7967 if (!sCallMouseHook) {
7968 printf("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n");
7970 #endif
7974 // Unhook special message hooks for dropdowns.
7975 void nsWindow::UnregisterSpecialDropdownHooks()
7977 DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n");
7979 if (sCallProcHook) {
7980 DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n");
7981 if (!::UnhookWindowsHookEx(sCallProcHook)) {
7982 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n");
7984 sCallProcHook = NULL;
7987 if (sMsgFilterHook) {
7988 DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n");
7989 if (!::UnhookWindowsHookEx(sMsgFilterHook)) {
7990 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n");
7992 sMsgFilterHook = NULL;
7995 if (sCallMouseHook) {
7996 DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n");
7997 if (!::UnhookWindowsHookEx(sCallMouseHook)) {
7998 DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n");
8000 sCallMouseHook = NULL;
8004 // This timer is designed to only fire one time at most each time a "hook" function
8005 // is used to rollup the dropdown. In some cases, the timer may be scheduled from the
8006 // hook, but that hook event or a subsequent event may roll up the dropdown before
8007 // this timer function is executed.
8009 // For example, if an MFC control takes focus, the combobox will lose focus and rollup
8010 // before this function fires.
8011 VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
8013 if (sHookTimerId != 0) {
8014 // if the window is NULL then we need to use the ID to kill the timer
8015 BOOL status = ::KillTimer(NULL, sHookTimerId);
8016 NS_ASSERTION(status, "Hook Timer was not killed.");
8017 sHookTimerId = 0;
8020 if (sRollupMsgId != 0) {
8021 // Note: DealWithPopups does the check to make sure that
8022 // sRollupListener and sRollupWidget are not NULL
8023 LRESULT popupHandlingResult;
8024 nsAutoRollup autoRollup;
8025 DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
8026 sRollupMsgId = 0;
8027 sRollupMsgWnd = NULL;
8030 #endif // WinCE
8032 BOOL CALLBACK nsWindow::ClearResourcesCallback(HWND aWnd, LPARAM aMsg)
8034 nsWindow *window = nsWindow::GetNSWindowPtr(aWnd);
8035 if (window) {
8036 window->ClearCachedResources();
8038 return TRUE;
8041 void
8042 nsWindow::ClearCachedResources()
8044 #ifdef CAIRO_HAS_D2D_SURFACE
8045 mD2DWindowSurface = nsnull;
8046 #endif
8047 if (mLayerManager &&
8048 mLayerManager->GetBackendType() == LayerManager::LAYERS_BASIC) {
8049 static_cast<BasicLayerManager*>(mLayerManager.get())->
8050 ClearCachedResources();
8052 ::EnumChildWindows(mWnd, nsWindow::ClearResourcesCallback, NULL);
8055 static PRBool IsDifferentThreadWindow(HWND aWnd)
8057 return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, NULL);
8060 PRBool
8061 nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
8063 RECT r;
8065 #ifndef WINCE
8066 if (Msg == WM_ACTIVATEAPP)
8067 // don't care about activation/deactivation
8068 return PR_FALSE;
8069 #else
8070 if (Msg == WM_ACTIVATE)
8071 // but on Windows CE we do care about
8072 // activation/deactivation because there doesn't exist
8073 // cancelable Mouse Activation events
8074 return PR_TRUE;
8075 #endif
8077 ::GetWindowRect(aWindow->mWnd, &r);
8078 DWORD pos = ::GetMessagePos();
8079 POINT mp;
8080 mp.x = GET_X_LPARAM(pos);
8081 mp.y = GET_Y_LPARAM(pos);
8083 // was the event inside this window?
8084 return (PRBool) PtInRect(&r, mp);
8087 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
8088 BOOL
8089 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
8091 if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
8093 if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
8094 inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
8095 (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam))
8096 #ifndef WINCE
8098 inMsg == WM_NCRBUTTONDOWN ||
8099 inMsg == WM_MOVING ||
8100 inMsg == WM_SIZING ||
8101 inMsg == WM_NCLBUTTONDOWN ||
8102 inMsg == WM_NCMBUTTONDOWN ||
8103 inMsg == WM_MOUSEACTIVATE ||
8104 inMsg == WM_ACTIVATEAPP ||
8105 inMsg == WM_MENUSELECT
8106 #endif
8109 // Rollup if the event is outside the popup.
8110 PRBool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)sRollupWidget);
8112 if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL))
8114 sRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
8115 *outResult = PR_TRUE;
8118 // If we're dealing with menus, we probably have submenus and we don't
8119 // want to rollup if the click is in a parent menu of the current submenu.
8120 PRUint32 popupsToRollup = PR_UINT32_MAX;
8121 if (rollup) {
8122 if ( sMenuRollup ) {
8123 nsAutoTArray<nsIWidget*, 5> widgetChain;
8124 PRUint32 sameTypeCount = sMenuRollup->GetSubmenuWidgetChain(&widgetChain);
8125 for ( PRUint32 i = 0; i < widgetChain.Length(); ++i ) {
8126 nsIWidget* widget = widgetChain[i];
8127 if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
8128 // don't roll up if the mouse event occurred within a menu of the
8129 // same type. If the mouse event occurred in a menu higher than
8130 // that, roll up, but pass the number of popups to Rollup so
8131 // that only those of the same type close up.
8132 if (i < sameTypeCount) {
8133 rollup = PR_FALSE;
8135 else {
8136 popupsToRollup = sameTypeCount;
8138 break;
8140 } // foreach parent menu widget
8141 } // if rollup listener knows about menus
8144 #ifndef WINCE
8145 if (inMsg == WM_MOUSEACTIVATE && popupsToRollup == PR_UINT32_MAX) {
8146 // Prevent the click inside the popup from causing a change in window
8147 // activation. Since the popup is shown non-activated, we need to eat
8148 // any requests to activate the window while it is displayed. Windows
8149 // will automatically activate the popup on the mousedown otherwise.
8150 if (!rollup) {
8151 *outResult = MA_NOACTIVATE;
8152 return TRUE;
8154 else
8156 UINT uMsg = HIWORD(inLParam);
8157 if (uMsg == WM_MOUSEMOVE)
8159 // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
8160 // must be enabled in Windows.
8161 sRollupListener->ShouldRollupOnMouseActivate(&rollup);
8162 if (!rollup)
8164 *outResult = MA_NOACTIVATE;
8165 return true;
8170 // if we've still determined that we should still rollup everything, do it.
8171 else
8172 #endif
8173 if ( rollup ) {
8174 // sRollupConsumeEvent may be modified by
8175 // nsIRollupListener::Rollup.
8176 PRBool consumeRollupEvent = sRollupConsumeEvent;
8177 // only need to deal with the last rollup for left mouse down events.
8178 sRollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN ? &mLastRollup : nsnull);
8180 // Tell hook to stop processing messages
8181 sProcessHook = PR_FALSE;
8182 sRollupMsgId = 0;
8183 sRollupMsgWnd = NULL;
8185 // return TRUE tells Windows that the event is consumed,
8186 // false allows the event to be dispatched
8188 // So if we are NOT supposed to be consuming events, let it go through
8189 if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
8190 *outResult = TRUE;
8191 return TRUE;
8193 #ifndef WINCE
8194 // if we are only rolling up some popups, don't activate and don't let
8195 // the event go through. This prevents clicks menus higher in the
8196 // chain from opening when a context menu is open
8197 if (popupsToRollup != PR_UINT32_MAX && inMsg == WM_MOUSEACTIVATE) {
8198 *outResult = MA_NOACTIVATEANDEAT;
8199 return TRUE;
8201 #endif
8203 } // if event that might trigger a popup to rollup
8204 } // if rollup listeners registered
8206 return FALSE;
8209 /**************************************************************
8210 **************************************************************
8212 ** BLOCK: Misc. utility methods and functions.
8214 ** General use.
8216 **************************************************************
8217 **************************************************************/
8219 // nsModifierKeyState used in various character processing.
8220 nsModifierKeyState::nsModifierKeyState()
8222 mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT);
8223 mIsControlDown = IS_VK_DOWN(NS_VK_CONTROL);
8224 mIsAltDown = IS_VK_DOWN(NS_VK_ALT);
8228 PRInt32 nsWindow::GetWindowsVersion()
8230 #ifdef WINCE
8231 return 0x500;
8232 #else
8233 static PRInt32 version = 0;
8234 static PRBool didCheck = PR_FALSE;
8236 if (!didCheck)
8238 didCheck = PR_TRUE;
8239 OSVERSIONINFOEX osInfo;
8240 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
8241 // This cast is safe and supposed to be here, don't worry
8242 ::GetVersionEx((OSVERSIONINFO*)&osInfo);
8243 version = (osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
8245 return version;
8246 #endif
8249 // Note that the result of GetTopLevelWindow method can be different from the
8250 // result of GetTopLevelHWND method. The result can be non-floating window.
8251 // Because our top level window may be contained in another window which is
8252 // not managed by us.
8253 nsWindow* nsWindow::GetTopLevelWindow(PRBool aStopOnDialogOrPopup)
8255 nsWindow* curWindow = this;
8257 while (PR_TRUE) {
8258 if (aStopOnDialogOrPopup) {
8259 switch (curWindow->mWindowType) {
8260 case eWindowType_dialog:
8261 case eWindowType_popup:
8262 return curWindow;
8263 default:
8264 break;
8268 // Retrieve the top level parent or owner window
8269 nsWindow* parentWindow = curWindow->GetParentWindow(PR_TRUE);
8271 if (!parentWindow)
8272 return curWindow;
8274 curWindow = parentWindow;
8278 // Note that the result of GetTopLevelHWND can be different from the result
8279 // of GetTopLevelWindow method. Because this is checking whether the window
8280 // is top level only in Win32 window system. Therefore, the result window
8281 // may not be managed by us.
8282 HWND nsWindow::GetTopLevelHWND(HWND aWnd, PRBool aStopOnDialogOrPopup)
8284 HWND curWnd = aWnd;
8285 HWND topWnd = NULL;
8286 HWND upWnd = NULL;
8288 while (curWnd) {
8289 topWnd = curWnd;
8291 if (aStopOnDialogOrPopup) {
8292 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8294 VERIFY_WINDOW_STYLE(style);
8296 if (!(style & WS_CHILD)) // first top-level window
8297 break;
8300 upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
8302 #ifdef WINCE
8303 // For dialog windows, we want just the parent, not the owner.
8304 // For other/popup windows, we want to find the first owner/parent
8305 // that's a dialog and/or has an owner.
8306 if (upWnd && ::GetWindow(curWnd, GW_OWNER) == upWnd) {
8307 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
8308 if ((style & WS_DLGFRAME) != 0)
8309 break;
8311 #endif
8313 curWnd = upWnd;
8316 return topWnd;
8319 static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam)
8321 DWORD pid;
8322 ::GetWindowThreadProcessId(hwnd, &pid);
8323 if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd))
8325 gWindowsVisible = PR_TRUE;
8326 return FALSE;
8328 return TRUE;
8331 PRBool nsWindow::CanTakeFocus()
8333 gWindowsVisible = PR_FALSE;
8334 EnumWindows(gEnumWindowsProc, 0);
8335 if (!gWindowsVisible) {
8336 return PR_TRUE;
8337 } else {
8338 HWND fgWnd = ::GetForegroundWindow();
8339 if (!fgWnd) {
8340 return PR_TRUE;
8342 DWORD pid;
8343 GetWindowThreadProcessId(fgWnd, &pid);
8344 if (pid == GetCurrentProcessId()) {
8345 return PR_TRUE;
8348 return PR_FALSE;
8351 #if !defined(WINCE)
8352 void nsWindow::InitTrackPointHack()
8354 // Init Trackpoint Hack
8355 nsresult rv;
8356 PRInt32 lHackValue;
8357 long lResult;
8358 const WCHAR wstrKeys[][40] = {L"Software\\Lenovo\\TrackPoint",
8359 L"Software\\Lenovo\\UltraNav",
8360 L"Software\\Alps\\Apoint\\TrackPoint",
8361 L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
8362 L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"};
8363 // If anything fails turn the hack off
8364 sTrackPointHack = false;
8365 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
8366 if(NS_SUCCEEDED(rv) && prefs) {
8367 prefs->GetIntPref("ui.trackpoint_hack.enabled", &lHackValue);
8368 switch (lHackValue) {
8369 // 0 means hack disabled
8370 case 0:
8371 break;
8372 // 1 means hack enabled
8373 case 1:
8374 sTrackPointHack = true;
8375 break;
8376 // -1 means autodetect
8377 case -1:
8378 for(unsigned i = 0; i < NS_ARRAY_LENGTH(wstrKeys); i++) {
8379 HKEY hKey;
8380 lResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, (LPCWSTR)&wstrKeys[i],
8381 0, KEY_READ, &hKey);
8382 ::RegCloseKey(hKey);
8383 if(lResult == ERROR_SUCCESS) {
8384 // If we detected a registry key belonging to a TrackPoint driver
8385 // Turn on the hack
8386 sTrackPointHack = true;
8387 break;
8390 break;
8391 // Shouldn't be any other values, but treat them as disabled
8392 default:
8393 break;
8396 return;
8398 #endif // #if !defined(WINCE)
8400 LPARAM nsWindow::lParamToScreen(LPARAM lParam)
8402 POINT pt;
8403 pt.x = GET_X_LPARAM(lParam);
8404 pt.y = GET_Y_LPARAM(lParam);
8405 ::ClientToScreen(mWnd, &pt);
8406 return MAKELPARAM(pt.x, pt.y);
8409 LPARAM nsWindow::lParamToClient(LPARAM lParam)
8411 POINT pt;
8412 pt.x = GET_X_LPARAM(lParam);
8413 pt.y = GET_Y_LPARAM(lParam);
8414 ::ScreenToClient(mWnd, &pt);
8415 return MAKELPARAM(pt.x, pt.y);
8418 /**************************************************************
8419 **************************************************************
8421 ** BLOCK: ChildWindow impl.
8423 ** Child window overrides.
8425 **************************************************************
8426 **************************************************************/
8428 // return the style for a child nsWindow
8429 DWORD ChildWindow::WindowStyle()
8431 DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle();
8432 if (!(style & WS_POPUP))
8433 style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
8434 VERIFY_WINDOW_STYLE(style);
8435 return style;