1 /* vim: set sw=2 sts=2 et cin: */
2 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is the Mozilla OS/2 libraries.
19 * The Initial Developer of the Original Code is
20 * John Fairhurst, <john_fairhurst@iname.com>.
21 * Portions created by the Initial Developer are Copyright (C) 1999
22 * the Initial Developer. All Rights Reserved.
25 * Pierre Phaneuf <pp@ludusdesign.com>
27 * Rich Walsh <dragtext@e-vertise.com>
28 * Dan Rosen <dr@netscape.com>
29 * Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
30 * Peter Weilbacher <mozilla@Weilbacher.org>
32 * Alternatively, the contents of this file may be used under the terms of
33 * either the GNU General Public License Version 2 or later (the "GPL"), or
34 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 * in which case the provisions of the GPL or the LGPL are applicable instead
36 * of those above. If you wish to allow use of your version of this file only
37 * under the terms of either the GPL or the LGPL, and not to allow others to
38 * use your version of this file under the terms of the MPL, indicate your
39 * decision by deleting the provisions above and replace them with the notice
40 * and other provisions required by the GPL or the LGPL. If you do not delete
41 * the provisions above, a recipient may use your version of this file under
42 * the terms of any one of the MPL, the GPL or the LGPL.
44 * ***** END LICENSE BLOCK *****/
46 //=============================================================================
48 * This file is divided into the following major sections:
51 * - Variables & Forward declarations
52 * - nsWindow Create / Destroy
53 * - Standard Window Operations
54 * - Window Positioning
56 * - Top-level (frame window) Operations
58 * - Rollup Event Handlers
59 * - nsWindow's Window Procedure
60 * - Window Message Handlers
61 * - Drag & Drop - Target methods
66 //=============================================================================
69 #include "os2FrameWindow.h"
70 #include "gfxContext.h"
71 #include "gfxOS2Surface.h"
72 #include "imgIContainer.h"
74 #include "nsDragService.h"
75 #include "nsGfxCIID.h"
76 #include "nsHashKeys.h"
77 #include "nsIDeviceContext.h"
78 #include "nsIMenuRollup.h"
79 #include "nsIPrefService.h"
80 #include "nsIRollupListener.h"
81 #include "nsIScreenManager.h"
83 #include "nsTHashtable.h"
84 #include "nsToolkit.h"
85 #include "nsWidgetAtoms.h"
86 #include "wdgtos2rc.h"
88 //=============================================================================
90 //=============================================================================
94 // d&d flags - actions that might cause problems during d&d
95 #define ACTION_PAINT 1
97 #define ACTION_SCROLL 3
99 #define ACTION_PTRPOS 5
101 // d&d status - shorten these references a bit
102 #define DND_None (nsIDragSessionOS2::DND_NONE)
103 #define DND_NativeDrag (nsIDragSessionOS2::DND_NATIVEDRAG)
104 #define DND_MozDrag (nsIDragSessionOS2::DND_MOZDRAG)
105 #define DND_InDrop (nsIDragSessionOS2::DND_INDROP)
106 #define DND_DragStatus (nsIDragSessionOS2::DND_DRAGSTATUS)
107 #define DND_DispatchEnterEvent (nsIDragSessionOS2::DND_DISPATCHENTEREVENT)
108 #define DND_DispatchEvent (nsIDragSessionOS2::DND_DISPATCHEVENT)
109 #define DND_GetDragoverResult (nsIDragSessionOS2::DND_GETDRAGOVERRESULT)
110 #define DND_ExitSession (nsIDragSessionOS2::DND_EXITSESSION)
112 //-----------------------------------------------------------------------------
113 // App Command messages for IntelliMouse and Natural Keyboard Pro
115 #define WM_APPCOMMAND 0x0319
117 #define APPCOMMAND_BROWSER_BACKWARD 1
118 #define APPCOMMAND_BROWSER_FORWARD 2
119 #define APPCOMMAND_BROWSER_REFRESH 3
120 #define APPCOMMAND_BROWSER_STOP 4
122 //-----------------------------------------------------------------------------
123 // Keyboard-related macros
125 // Used for character-to-keycode translation
126 #define PMSCAN_PADMULT 0x37
127 #define PMSCAN_PAD7 0x47
128 #define PMSCAN_PAD8 0x48
129 #define PMSCAN_PAD9 0x49
130 #define PMSCAN_PADMINUS 0x4A
131 #define PMSCAN_PAD4 0x4B
132 #define PMSCAN_PAD5 0x4C
133 #define PMSCAN_PAD6 0x4D
134 #define PMSCAN_PADPLUS 0x4E
135 #define PMSCAN_PAD1 0x4F
136 #define PMSCAN_PAD2 0x50
137 #define PMSCAN_PAD3 0x51
138 #define PMSCAN_PAD0 0x52
139 #define PMSCAN_PADPERIOD 0x53
140 #define PMSCAN_PADDIV 0x5c
142 #define isNumPadScanCode(scanCode) !((scanCode < PMSCAN_PAD7) || \
143 (scanCode > PMSCAN_PADPERIOD) || \
144 (scanCode == PMSCAN_PADMULT) || \
145 (scanCode == PMSCAN_PADDIV) || \
146 (scanCode == PMSCAN_PADMINUS) || \
147 (scanCode == PMSCAN_PADPLUS))
149 #define isNumlockOn (WinGetKeyState(HWND_DESKTOP, VK_NUMLOCK) & 0x0001)
150 #define isKeyDown(vk) ((WinGetKeyState(HWND_DESKTOP,vk) & 0x8000) == 0x8000)
152 //-----------------------------------------------------------------------------
155 // extract X & Y from a mouse msg mparam
156 #define XFROMMP(m) (SHORT(LOUSHORT(m)))
157 #define YFROMMP(m) (SHORT(HIUSHORT(m)))
159 // make these methods seem more appropriate in context
160 #define PM2NS_PARENT NS2PM_PARENT
163 // used to identify plugin widgets (copied from nsPluginNativeWindowOS2.cpp)
164 #define NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION \
165 "MozillaPluginWindowPropertyAssociation"
167 // name of the window class used to clip plugins
168 #define kClipWndClass "nsClipWnd"
170 //-----------------------------------------------------------------------------
174 #define DEBUGFOCUS(what) fprintf(stderr, "[%8x] %8lx (%02d) "#what"\n", \
175 (int)this, mWnd, mWindowIdentifier)
177 #define DEBUGFOCUS(what)
180 //=============================================================================
181 // Variables & Forward declarations
182 //=============================================================================
184 // Rollup Listener - used by nsWindow & os2FrameWindow
185 nsIRollupListener
* gRollupListener
= 0;
186 nsIMenuRollup
* gMenuRollup
= 0;
187 nsIWidget
* gRollupWidget
= 0;
188 PRBool gRollupConsumeRollupEvent
= PR_FALSE
;
190 // Miscellaneous global flags
191 PRUint32 gOS2Flags
= 0;
194 static HPOINTER sPtrArray
[IDC_COUNT
];
196 // location of last MB1 down - used for mouse-based copy/paste
197 static POINTS sLastButton1Down
= {0,0};
199 // set when any nsWindow is being dragged over
200 static PRUint32 sDragStatus
= 0;
203 int currentWindowIdentifier
= 0;
206 //-----------------------------------------------------------------------------
208 static PRUint32
WMChar2KeyCode(MPARAM mp1
, MPARAM mp2
);
210 //=============================================================================
211 // nsWindow Create / Destroy
212 //=============================================================================
214 nsWindow::nsWindow() : nsBaseWidget()
219 mWindowType
= eWindowType_toplevel
;
220 mBorderStyle
= eBorderStyle_default
;
221 mWindowState
= nsWindowState_ePrecreate
;
222 mOnDestroyCalled
= PR_FALSE
;
223 mIsDestroying
= PR_FALSE
;
224 mInSetFocus
= PR_FALSE
;
237 //-----------------------------------------------------------------------------
239 nsWindow::~nsWindow()
241 // How destruction works: A call of Destroy() destroys the PM window. This
242 // triggers an OnDestroy(), which frees resources. If not Destroy'd at
243 // delete time, Destroy() gets called anyway.
245 // NOTE: Calling virtual functions from destructors is bad; they always
246 // bind in the current object (ie. as if they weren't virtual). It
247 // may even be illegal to call them from here.
249 mIsDestroying
= PR_TRUE
;
251 if (mCssCursorHPtr
) {
252 WinDestroyPointer(mCssCursorHPtr
);
256 // If the widget was released without calling Destroy() then
257 // the native window still exists, and we need to destroy it
258 if (!(mWindowState
& nsWindowState_eDead
)) {
259 mWindowState
|= nsWindowState_eDoingDelete
;
260 mWindowState
&= ~(nsWindowState_eLive
| nsWindowState_ePrecreate
|
261 nsWindowState_eInCreate
);
265 // Once a plugin window has been destroyed,
266 // its parent, the clipping window, can be destroyed.
268 WinDestroyWindow(mClipWnd
);
272 // If it exists, destroy our os2FrameWindow helper object.
279 //-----------------------------------------------------------------------------
280 // Init Module-level variables.
283 void nsWindow::InitGlobals()
285 gOS2Flags
= kIsInitialized
;
287 // Register the MozillaWindowClass with PM.
288 WinRegisterClass(0, kWindowClassName
, fnwpNSWindow
, 0, 8);
290 // Register the dummy window class used to clip plugins.
291 WinRegisterClass(0, kClipWndClass
, WinDefWindowProc
, 0, 4);
293 // Load the mouse pointers from the dll containing 'gOS2Flags'.
294 HMODULE hModResources
= 0;
295 DosQueryModFromEIP(&hModResources
, 0, 0, 0, 0, (ULONG
)&gOS2Flags
);
296 for (int i
= 0; i
< IDC_COUNT
; i
++) {
297 sPtrArray
[i
] = WinLoadPointer(HWND_DESKTOP
, hModResources
, IDC_BASE
+i
);
300 // Work out if the system is DBCS.
302 COUNTRYCODE cc
= { 0 };
303 DosQueryDBCSEnv(sizeof(buffer
), &cc
, buffer
);
304 if (buffer
[0] || buffer
[1]) {
305 gOS2Flags
|= kIsDBCS
;
308 // This is ugly. The Thinkpad TrackPoint driver checks to see whether
309 // or not a window actually has a scroll bar as a child before sending
310 // it scroll messages. Needless to say, no Mozilla window has real scroll
311 // bars. So if you have the "os2.trackpoint" preference set, we put an
312 // invisible scroll bar on every child window so we can scroll.
314 nsCOMPtr
<nsIPrefBranch
> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
));
315 if (NS_SUCCEEDED(rv
) && prefs
) {
316 PRBool isTrackPoint
= PR_FALSE
;
317 prefs
->GetBoolPref("os2.trackpoint", &isTrackPoint
);
319 gOS2Flags
|= kIsTrackPoint
;
324 //-----------------------------------------------------------------------------
325 // Release Module-level variables.
328 void nsWindow::ReleaseGlobals()
330 for (int i
= 0; i
< IDC_COUNT
; i
++) {
331 WinDestroyPointer(sPtrArray
[i
]);
335 //-----------------------------------------------------------------------------
336 // Init an nsWindow & create the appropriate native window.
338 NS_METHOD
nsWindow::Create(nsIWidget
* aParent
,
339 nsNativeWidget aNativeParent
,
340 const nsIntRect
& aRect
,
341 EVENT_CALLBACK aHandleEventFunction
,
342 nsIDeviceContext
* aContext
,
343 nsIAppShell
* aAppShell
,
344 nsIToolkit
* aToolkit
,
345 nsWidgetInitData
* aInitData
)
347 mWindowState
= nsWindowState_eInCreate
;
349 // Identify the parent's nsWindow & native window. Only one of these
350 // should be supplied. Note: only nsWindow saves pParent as mParent;
351 // os2FrameWindow discards it since toplevel widgets have no parent.
355 hParent
= (HWND
)aParent
->GetNativeData(NS_NATIVE_WINDOW
);
356 pParent
= (nsWindow
*)aParent
;
358 if (aNativeParent
&& (HWND
)aNativeParent
!= HWND_DESKTOP
) {
359 hParent
= (HWND
)aNativeParent
;
360 pParent
= GetNSWindowPtr(hParent
);
362 hParent
= HWND_DESKTOP
;
367 // Save the event callback function.
368 mEventCallback
= aHandleEventFunction
;
370 // Make sure a device context exists.
375 static NS_DEFINE_IID(kDeviceContextCID
, NS_DEVICE_CONTEXT_CID
);
376 nsresult rv
= CallCreateInstance(kDeviceContextCID
, &mContext
);
377 NS_ENSURE_SUCCESS(rv
, rv
);
378 mContext
->Init(nsnull
);
381 // XXX Toolkit is obsolete & will be removed.
385 } else if (pParent
) {
386 mToolkit
= pParent
->GetToolkit();
388 mToolkit
= new nsToolkit
;
389 mToolkit
->Init(PR_GetCurrentThread());
395 mWindowIdentifier
= currentWindowIdentifier
;
396 currentWindowIdentifier
++;
399 // Some basic initialization.
401 mWindowType
= aInitData
->mWindowType
;
402 mBorderStyle
= aInitData
->mBorderStyle
;
404 // Suppress creation of a Thebes surface for windows that will never
405 // be painted because they're always covered by another window.
406 if (mWindowType
== eWindowType_toplevel
||
407 mWindowType
== eWindowType_invisible
) {
410 // Popup windows should not have an nsWindow parent.
411 else if (mWindowType
== eWindowType_popup
) {
416 // For toplevel windows, create an instance of our helper class,
417 // then have it create a frame & client window; otherwise,
418 // call our own CreateWindow() method to create a child window.
419 if (mWindowType
== eWindowType_toplevel
||
420 mWindowType
== eWindowType_dialog
||
421 mWindowType
== eWindowType_invisible
) {
422 mFrame
= new os2FrameWindow(this);
423 NS_ENSURE_TRUE(mFrame
, NS_ERROR_FAILURE
);
424 mWnd
= mFrame
->CreateFrameWindow(pParent
, hParent
, aRect
,
425 mWindowType
, mBorderStyle
);
426 NS_ENSURE_TRUE(mWnd
, NS_ERROR_FAILURE
);
428 nsresult rv
= CreateWindow(pParent
, hParent
, aRect
, aInitData
);
429 NS_ENSURE_SUCCESS(rv
, rv
);
432 // Store a pointer to this object in the window's extra bytes.
433 SetNSWindowPtr(mWnd
, this);
435 // Finalize the widget creation process.
436 nsGUIEvent
event(PR_TRUE
, NS_CREATE
, this);
438 DispatchWindowEvent(&event
);
440 mWindowState
= nsWindowState_eLive
;
444 //-----------------------------------------------------------------------------
445 // Create a native window for an nsWindow object.
447 nsresult
nsWindow::CreateWindow(nsWindow
* aParent
,
449 const nsIntRect
& aRect
,
450 nsWidgetInitData
* aInitData
)
452 // For pop-ups, the Desktop is the parent and aParentWnd is the owner.
454 if (mWindowType
== eWindowType_popup
&& aParentWnd
!= HWND_DESKTOP
) {
456 aParentWnd
= HWND_DESKTOP
;
459 // While we comply with the clipSiblings flag, we always set
460 // clipChildren regardless of the flag for performance reasons.
461 PRUint32 style
= WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
;
462 if (aInitData
&& !aInitData
->clipSiblings
) {
463 style
&= ~WS_CLIPSIBLINGS
;
466 // Create the window hidden; it will be resized below.
467 mWnd
= WinCreateWindow(aParentWnd
,
476 NS_ENSURE_TRUE(mWnd
, NS_ERROR_FAILURE
);
478 // If a TrackPoint is in use, create dummy scrollbars.
479 // XXX Popups may need this also to scroll comboboxes.
480 if ((gOS2Flags
& kIsTrackPoint
) && mWindowType
== eWindowType_child
) {
481 WinCreateWindow(mWnd
, WC_SCROLLBAR
, 0, SBS_VERT
,
482 0, 0, 0, 0, mWnd
, HWND_TOP
,
483 FID_VERTSCROLL
, 0, 0);
486 // Store the window's dimensions, then resize accordingly.
490 aParent
->GetBounds(parRect
);
492 parRect
.height
= WinQuerySysValue(HWND_DESKTOP
, SV_CYSCREEN
);
494 WinSetWindowPos(mWnd
, 0,
495 aRect
.x
, parRect
.height
- aRect
.y
- aRect
.height
,
496 aRect
.width
, aRect
.height
, SWP_SIZE
| SWP_MOVE
);
498 // Store the widget's parent and add it to the parent's list of children.
499 // Don't ADDREF mParent because AddChild() ADDREFs us.
502 mParent
->AddChild(this);
505 DEBUGFOCUS(Create nsWindow
);
509 //-----------------------------------------------------------------------------
510 // Close this nsWindow.
512 NS_METHOD
nsWindow::Destroy()
514 // avoid calling into other objects if we're being deleted, 'cos
515 // they must have no references to us.
516 if ((mWindowState
& nsWindowState_eLive
) && mParent
) {
517 nsBaseWidget::Destroy();
520 // just to be safe. If we're going away and for some reason we're still
521 // the rollup widget, rollup and turn off capture.
522 if (this == gRollupWidget
) {
523 if (gRollupListener
) {
524 gRollupListener
->Rollup(PR_UINT32_MAX
, nsnull
);
526 CaptureRollupEvents(nsnull
, nsnull
, PR_FALSE
, PR_TRUE
);
529 HWND hMain
= GetMainWindow();
532 if (hMain
== WinQueryFocus(HWND_DESKTOP
)) {
533 WinSetFocus(HWND_DESKTOP
, WinQueryWindow(hMain
, QW_PARENT
));
535 WinDestroyWindow(hMain
);
540 //=============================================================================
541 // Standard Window Operations
542 //=============================================================================
544 // This can't be inlined in nsWindow.h because it doesn't know about
547 inline HWND
nsWindow::GetMainWindow()
549 return mFrame
? mFrame
->GetFrameWnd() : mWnd
;
552 //-----------------------------------------------------------------------------
553 // Inline this here for consistency (and a cleaner looking .h).
556 inline nsWindow
* nsWindow::GetNSWindowPtr(HWND aWnd
)
558 return (nsWindow
*)WinQueryWindowPtr(aWnd
, QWL_NSWINDOWPTR
);
561 //-----------------------------------------------------------------------------
564 inline PRBool
nsWindow::SetNSWindowPtr(HWND aWnd
, nsWindow
* aPtr
)
566 return WinSetWindowPtr(aWnd
, QWL_NSWINDOWPTR
, aPtr
);
569 //-----------------------------------------------------------------------------
571 nsIWidget
* nsWindow::GetParent()
573 // if this window isn't supposed to have a parent or it doesn't have
574 // a parent, or if it or its parent is being destroyed, return null
575 if (mFrame
|| mIsDestroying
|| mOnDestroyCalled
||
576 !mParent
|| mParent
->mIsDestroying
) {
583 //-----------------------------------------------------------------------------
585 NS_METHOD
nsWindow::Enable(PRBool aState
)
587 HWND hMain
= GetMainWindow();
589 WinEnableWindow(hMain
, aState
);
594 //-----------------------------------------------------------------------------
596 NS_METHOD
nsWindow::IsEnabled(PRBool
* aState
)
598 NS_ENSURE_ARG_POINTER(aState
);
599 HWND hMain
= GetMainWindow();
600 *aState
= !hMain
|| WinIsWindowEnabled(hMain
);
604 //-----------------------------------------------------------------------------
606 NS_METHOD
nsWindow::Show(PRBool aState
)
609 return mFrame
->Show(aState
);
613 // don't try to show new windows (e.g. the Bookmark menu)
614 // during a native dragover because they'll remain invisible;
615 if (CheckDragStatus(ACTION_SHOW
, 0)) {
617 IsVisible(isVisible
);
619 PlaceBehind(eZPlacementTop
, 0, PR_FALSE
);
621 WinShowWindow(mWnd
, PR_TRUE
);
624 WinShowWindow(mWnd
, PR_FALSE
);
631 //-----------------------------------------------------------------------------
633 NS_METHOD
nsWindow::IsVisible(PRBool
& aState
)
635 aState
= WinIsWindowVisible(GetMainWindow()) ? PR_TRUE
: PR_FALSE
;
639 //-----------------------------------------------------------------------------
641 NS_METHOD
nsWindow::SetFocus(PRBool aRaise
)
643 // for toplevel windows, this is directed to the client (i.e. mWnd)
646 DEBUGFOCUS(SetFocus
);
647 mInSetFocus
= PR_TRUE
;
648 WinSetFocus(HWND_DESKTOP
, mWnd
);
649 mInSetFocus
= PR_FALSE
;
655 //-----------------------------------------------------------------------------
657 NS_METHOD
nsWindow::Invalidate(const nsIntRect
& aRect
, PRBool aIsSynchronous
)
660 RECTL rcl
= {aRect
.x
, aRect
.y
, aRect
.x
+ aRect
.width
, aRect
.y
+ aRect
.height
};
662 WinInvalidateRect(mWnd
, &rcl
, PR_FALSE
);
664 if (aIsSynchronous
) {
672 //-----------------------------------------------------------------------------
673 // Force a synchronous repaint of the window.
675 NS_IMETHODIMP
nsWindow::Update()
678 WinUpdateWindow(mWnd
);
683 //-----------------------------------------------------------------------------
684 // Create a Thebes surface using the current window handle.
686 gfxASurface
* nsWindow::GetThebesSurface()
688 if (mWnd
&& !mThebesSurface
) {
689 mThebesSurface
= new gfxOS2Surface(mWnd
);
691 return mThebesSurface
;
694 //-----------------------------------------------------------------------------
695 // Internal-only method that suppresses creation of a Thebes surface
696 // for windows that aren't supposed to be visible. If one was created
697 // by an external call to GetThebesSurface(), it will be returned.
699 gfxASurface
* nsWindow::ConfirmThebesSurface()
701 if (!mThebesSurface
&& !mNoPaint
&& mWnd
) {
702 mThebesSurface
= new gfxOS2Surface(mWnd
);
704 return mThebesSurface
;
707 //-----------------------------------------------------------------------------
709 float nsWindow::GetDPI()
711 static PRInt32 sDPI
= 0;
713 // Create DC compatible with the screen, then query the DPI setting.
714 // If this fails, fall back to something sensible.
716 HDC dc
= DevOpenDC(0, OD_MEMORY
,"*",0L, 0, 0);
719 if (DevQueryCaps(dc
, CAPS_VERTICAL_FONT_RES
, 1, &lDPI
))
730 //-----------------------------------------------------------------------------
731 // Return some native data according to aDataType.
733 void* nsWindow::GetNativeData(PRUint32 aDataType
)
736 case NS_NATIVE_WIDGET
:
737 case NS_NATIVE_WINDOW
:
738 case NS_NATIVE_PLUGIN_PORT
:
741 // during a native drag over the current window or any drag
742 // originating in Moz, return a drag HPS to avoid screen corruption;
743 case NS_NATIVE_GRAPHIC
: {
745 CheckDragStatus(ACTION_DRAW
, &hps
);
747 hps
= WinGetPS(mWnd
);
756 //-----------------------------------------------------------------------------
758 void nsWindow::FreeNativeData(void* data
, PRUint32 aDataType
)
760 // an HPS is the only native data that needs to be freed
761 if (aDataType
== NS_NATIVE_GRAPHIC
&&
763 !ReleaseIfDragHPS((HPS
)data
)) {
764 WinReleasePS((HPS
)data
);
768 //-----------------------------------------------------------------------------
770 NS_METHOD
nsWindow::CaptureMouse(PRBool aCapture
)
773 WinSetCapture(HWND_DESKTOP
, mWnd
);
775 WinSetCapture(HWND_DESKTOP
, 0);
780 //-----------------------------------------------------------------------------
782 PRBool
nsWindow::HasPendingInputEvent()
784 return (WinQueryQueueStatus(HWND_DESKTOP
) & (QS_KEY
| QS_MOUSE
)) != 0;
787 //=============================================================================
788 // Window Positioning
789 //=============================================================================
791 // For toplevel windows, mBounds contains the dimensions of the client
792 // window. os2FrameWindow's "override" returns the size of the frame.
794 NS_METHOD
nsWindow::GetBounds(nsIntRect
& aRect
)
797 return mFrame
->GetBounds(aRect
);
803 //-----------------------------------------------------------------------------
804 // Since mBounds contains the dimensions of the client, os2FrameWindow
805 // doesn't have to provide any special handling for this method.
807 NS_METHOD
nsWindow::GetClientBounds(nsIntRect
& aRect
)
811 aRect
.width
= mBounds
.width
;
812 aRect
.height
= mBounds
.height
;
816 //-----------------------------------------------------------------------------
818 nsIntPoint
nsWindow::WidgetToScreenOffset()
820 POINTL point
= { 0, 0 };
823 WinMapWindowPoints(mWnd
, HWND_DESKTOP
, &point
, 1);
824 return nsIntPoint(point
.x
,
825 WinQuerySysValue(HWND_DESKTOP
, SV_CYSCREEN
) - point
.y
- 1);
828 //-----------------------------------------------------------------------------
829 // Transform Y values between PM & XP coordinate systems.
831 // ptl is in this window's space
832 void nsWindow::NS2PM(POINTL
& ptl
)
834 ptl
.y
= mBounds
.height
- ptl
.y
- 1;
837 // rcl is in this window's space
838 void nsWindow::NS2PM(RECTL
& rcl
)
840 LONG height
= rcl
.yTop
- rcl
.yBottom
;
841 rcl
.yTop
= mBounds
.height
- rcl
.yBottom
;
842 rcl
.yBottom
= rcl
.yTop
- height
;
845 // ptl is in parent's space
846 void nsWindow::NS2PM_PARENT(POINTL
& ptl
)
851 HWND hParent
= WinQueryWindow(mWnd
, QW_PARENT
);
853 WinQueryWindowPos(hParent
, &swp
);
854 ptl
.y
= swp
.cy
- ptl
.y
- 1;
858 //-----------------------------------------------------------------------------
860 NS_METHOD
nsWindow::Move(PRInt32 aX
, PRInt32 aY
)
863 return mFrame
->Move(aX
, aY
);
865 Resize(aX
, aY
, mBounds
.width
, mBounds
.height
, PR_FALSE
);
869 //-----------------------------------------------------------------------------
871 NS_METHOD
nsWindow::Resize(PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
874 return mFrame
->Resize(aWidth
, aHeight
, aRepaint
);
876 Resize(mBounds
.x
, mBounds
.y
, aWidth
, aHeight
, aRepaint
);
880 //-----------------------------------------------------------------------------
882 NS_METHOD
nsWindow::Resize(PRInt32 aX
, PRInt32 aY
,
883 PRInt32 aWidth
, PRInt32 aHeight
, PRBool aRepaint
)
886 return mFrame
->Resize(aX
, aY
, aWidth
, aHeight
, aRepaint
);
889 // For mWnd & eWindowType_child set the cached values upfront, see bug 286555.
890 // For other mWnd types we defer transfer of values to mBounds to
891 // WinSetWindowPos(), see bug 391421.
894 mWindowType
== eWindowType_child
||
895 mWindowType
== eWindowType_plugin
) {
898 mBounds
.width
= aWidth
;
899 mBounds
.height
= aHeight
;
902 // To keep top-left corner in the same place, use the new height
903 // to calculate the coordinates for the top & bottom left corners.
905 POINTL ptl
= { aX
, aY
};
907 ptl
.y
-= aHeight
- 1;
909 // For popups, aX already gives the correct position.
910 if (mWindowType
== eWindowType_popup
) {
911 ptl
.y
= WinQuerySysValue(HWND_DESKTOP
, SV_CYSCREEN
) - aHeight
- 1 - aY
;
914 WinMapWindowPoints(mParent
->mWnd
, WinQueryWindow(mWnd
, QW_PARENT
),
918 if (!WinSetWindowPos(mWnd
, 0, ptl
.x
, ptl
.y
, aWidth
, aHeight
,
919 SWP_MOVE
| SWP_SIZE
) && aRepaint
) {
920 WinInvalidateRect(mWnd
, 0, FALSE
);
927 //-----------------------------------------------------------------------------
929 NS_METHOD
nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement
,
930 nsIWidget
* aWidget
, PRBool aActivate
)
932 HWND hBehind
= HWND_TOP
;
934 if (aPlacement
== eZPlacementBottom
) {
935 hBehind
= HWND_BOTTOM
;
937 if (aPlacement
== eZPlacementBelow
&& aWidget
) {
938 hBehind
= (static_cast<nsWindow
*>(aWidget
))->GetMainWindow();
941 PRUint32 flags
= SWP_ZORDER
;
943 flags
|= SWP_ACTIVATE
;
946 WinSetWindowPos(GetMainWindow(), hBehind
, 0, 0, 0, 0, flags
);
950 //-----------------------------------------------------------------------------
951 // Set widget's position within its parent child list.
953 NS_METHOD
nsWindow::SetZIndex(PRInt32 aZIndex
)
955 // nsBaseWidget::SetZIndex() never has done anything sensible but
956 // has randomly placed widgets behind others (see bug 117730#c25).
957 // To get bug #353011 solved simply override it here to do nothing.
961 //=============================================================================
963 //=============================================================================
965 // Fire an NS_PLUGIN_ACTIVATE event whenever a window associated
966 // with a plugin widget get the focus.
968 void nsWindow::ActivatePlugin(HWND aWnd
)
970 // avoid acting on recursive WM_FOCUSCHANGED msgs
971 static PRBool inPluginActivate
= FALSE
;
972 if (inPluginActivate
) {
976 // This property is used by the plugin window to store a pointer
977 // to its plugin object. We just use it as a convenient marker.
978 if (!WinQueryProperty(mWnd
, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION
)) {
982 // Fire a plugin activation event on the plugin widget.
983 inPluginActivate
= TRUE
;
984 DEBUGFOCUS(NS_PLUGIN_ACTIVATE
);
985 DispatchActivationEvent(NS_PLUGIN_ACTIVATE
);
987 // Activating the plugin moves the focus off the child that had it,
988 // so try to restore it. If the WM_FOCUSCHANGED msg was synthesized
989 // by the plugin, then mp1 contains the child window that lost focus.
990 // Otherwise, just move it to the plugin's first child unless this
991 // is the mplayer plugin - doing so will put us into an endless loop.
992 // Since its children belong to another process, use the PID as a test.
994 if (WinIsChild(aWnd
, mWnd
)) {
997 hFocus
= WinQueryWindow(mWnd
, QW_TOP
);
999 PID pidFocus
, pidThis
;
1001 WinQueryWindowProcess(hFocus
, &pidFocus
, &tid
);
1002 WinQueryWindowProcess(mWnd
, &pidThis
, &tid
);
1003 if (pidFocus
!= pidThis
) {
1009 WinSetFocus(HWND_DESKTOP
, hFocus
);
1012 inPluginActivate
= FALSE
;
1016 //-----------------------------------------------------------------------------
1017 // This is invoked on a window that has plugin widget children
1018 // to resize and clip those child windows.
1020 nsresult
nsWindow::ConfigureChildren(const nsTArray
<Configuration
>& aConfigurations
)
1022 for (PRUint32 i
= 0; i
< aConfigurations
.Length(); ++i
) {
1023 const Configuration
& configuration
= aConfigurations
[i
];
1024 nsWindow
* w
= static_cast<nsWindow
*>(configuration
.mChild
);
1025 NS_ASSERTION(w
->GetParent() == this,
1026 "Configured widget is not a child");
1027 w
->SetPluginClipRegion(configuration
);
1032 //-----------------------------------------------------------------------------
1033 // This is invoked on a plugin window to resize it and set a persistent
1034 // clipping region for it. Since the latter isn't possible on OS/2, it
1035 // inserts a dummy window between the plugin widget and its parent to
1036 // act as a clipping rectangle. The dummy window's dimensions and the
1037 // plugin widget's position within the window are adjusted to correspond
1038 // to the bounding box of the supplied array of clipping rectangles.
1039 // Note: this uses PM calls rather than existing methods like Resize()
1040 // and Update() because none of them support the options needed here.
1042 void nsWindow::SetPluginClipRegion(const Configuration
& aConfiguration
)
1044 NS_ASSERTION((mParent
&& mParent
->mWnd
), "Child window has no parent");
1046 // If nothing has changed, exit.
1047 if (!StoreWindowClipRegion(aConfiguration
.mClipRegion
) &&
1048 mBounds
== aConfiguration
.mBounds
) {
1052 // Set the widget's x/y to its nominal unclipped value. It doesn't
1053 // affect our calculations but other code relies on it being correct.
1054 mBounds
.MoveTo(aConfiguration
.mBounds
.TopLeft());
1056 // Get or create the PM window we use as a clipping rectangle.
1057 HWND hClip
= GetPluginClipWindow(mParent
->mWnd
);
1058 NS_ASSERTION(hClip
, "No clipping window for plugin");
1063 // Create the bounding box for the clip region.
1064 const nsTArray
<nsIntRect
>& rects
= aConfiguration
.mClipRegion
;
1066 for (PRUint32 i
= 0; i
< rects
.Length(); ++i
) {
1067 r
.UnionRect(r
, rects
[i
]);
1070 // Size and position hClip to match the bounding box.
1073 WinQueryWindowPos(hClip
, &swp
);
1074 ptl
.x
= aConfiguration
.mBounds
.x
+ r
.x
;
1075 ptl
.y
= mParent
->mBounds
.height
1076 - (aConfiguration
.mBounds
.y
+ r
.y
+ r
.height
);
1078 ULONG clipFlags
= 0;
1079 if (swp
.x
!= ptl
.x
|| swp
.y
!= ptl
.y
) {
1080 clipFlags
|= SWP_MOVE
;
1082 if (swp
.cx
!= r
.width
|| swp
.cy
!= r
.height
) {
1083 clipFlags
|= SWP_SIZE
;
1086 WinSetWindowPos(hClip
, 0, ptl
.x
, ptl
.y
, r
.width
, r
.height
, clipFlags
);
1089 // Reducing the size of hClip clips the right & top sides of the
1090 // plugin widget. To clip the left & bottom sides, we have to move
1091 // the widget so its origin's x and/or y is negative wrt hClip.
1092 WinQueryWindowPos(mWnd
, &swp
);
1094 ptl
.y
= r
.height
+ r
.y
- aConfiguration
.mBounds
.height
;
1097 if (swp
.x
!= ptl
.x
|| swp
.y
!= ptl
.y
) {
1098 wndFlags
|= SWP_MOVE
;
1100 if (mBounds
.Size() != aConfiguration
.mBounds
.Size()) {
1101 wndFlags
|= SWP_SIZE
;
1104 WinSetWindowPos(mWnd
, 0, ptl
.x
, ptl
.y
,
1105 aConfiguration
.mBounds
.width
,
1106 aConfiguration
.mBounds
.height
, wndFlags
);
1109 // Some plugins don't resize themselves when the plugin widget changes
1110 // size, so help them out by resizing the first child (usually a frame).
1111 if (wndFlags
& SWP_SIZE
) {
1112 HWND hChild
= WinQueryWindow(mWnd
, QW_TOP
);
1114 WinSetWindowPos(hChild
, 0, 0, 0,
1115 aConfiguration
.mBounds
.width
,
1116 aConfiguration
.mBounds
.height
,
1117 SWP_MOVE
| SWP_SIZE
);
1121 // When hClip is resized, mWnd and its children may not get updated
1122 // automatically, so invalidate & repaint them
1123 if (clipFlags
& SWP_SIZE
) {
1124 WinInvalidateRect(mWnd
, 0, TRUE
);
1125 WinUpdateWindow(mWnd
);
1129 //-----------------------------------------------------------------------------
1130 // This gets or creates a window that's inserted between the main window
1131 // and its plugin children. This window does nothing except act as a
1132 // clipping rectangle for the plugin widget.
1134 HWND
nsWindow::GetPluginClipWindow(HWND aParentWnd
)
1140 // Insert a new clip window in the hierarchy between mWnd & aParentWnd.
1141 mClipWnd
= WinCreateWindow(aParentWnd
, kClipWndClass
, "",
1142 WS_VISIBLE
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
,
1143 0, 0, 0, 0, 0, mWnd
, 0, 0, 0);
1145 if (!WinSetParent(mWnd
, mClipWnd
, FALSE
)) {
1146 WinDestroyWindow(mClipWnd
);
1154 //=============================================================================
1155 // Top-level (frame window) Operations
1156 //=============================================================================
1158 // When a window gets the focus, call os2FrameWindow's version of this
1159 // method. It will fire an NS_ACTIVATE event on the top-level widget
1162 void nsWindow::ActivateTopLevelWidget()
1165 mFrame
->ActivateTopLevelWidget();
1167 nsWindow
* top
= static_cast<nsWindow
*>(GetTopLevelWidget());
1168 if (top
&& top
->mFrame
) {
1169 top
->mFrame
->ActivateTopLevelWidget();
1175 //-----------------------------------------------------------------------------
1176 // All of these methods are inherently toplevel-only, and are in fact
1177 // only invoked on toplevel widgets. If they're invoked on a child
1178 // window, there's an error upstream.
1180 NS_IMETHODIMP
nsWindow::SetSizeMode(PRInt32 aMode
)
1182 NS_ENSURE_TRUE(mFrame
, NS_ERROR_UNEXPECTED
);
1183 return mFrame
->SetSizeMode(aMode
);
1186 NS_IMETHODIMP
nsWindow::HideWindowChrome(PRBool aShouldHide
)
1188 NS_ENSURE_TRUE(mFrame
, NS_ERROR_UNEXPECTED
);
1189 return mFrame
->HideWindowChrome(aShouldHide
);
1192 NS_METHOD
nsWindow::SetTitle(const nsAString
& aTitle
)
1194 NS_ENSURE_TRUE(mFrame
, NS_ERROR_UNEXPECTED
);
1195 return mFrame
->SetTitle(aTitle
);
1198 NS_METHOD
nsWindow::SetIcon(const nsAString
& aIconSpec
)
1200 NS_ENSURE_TRUE(mFrame
, NS_ERROR_UNEXPECTED
);
1201 return mFrame
->SetIcon(aIconSpec
);
1204 NS_METHOD
nsWindow::ConstrainPosition(PRBool aAllowSlop
,
1205 PRInt32
* aX
, PRInt32
* aY
)
1207 NS_ENSURE_TRUE(mFrame
, NS_ERROR_UNEXPECTED
);
1208 return mFrame
->ConstrainPosition(aAllowSlop
, aX
, aY
);
1211 //=============================================================================
1213 //=============================================================================
1215 // Set one of the standard mouse pointers.
1217 NS_METHOD
nsWindow::SetCursor(nsCursor aCursor
)
1219 HPOINTER newPointer
= 0;
1222 case eCursor_select
:
1223 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_TEXT
, FALSE
);
1227 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_WAIT
, FALSE
);
1230 case eCursor_hyperlink
:
1231 newPointer
= sPtrArray
[IDC_SELECTANCHOR
-IDC_BASE
];
1234 case eCursor_standard
:
1235 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_ARROW
, FALSE
);
1238 case eCursor_n_resize
:
1239 case eCursor_s_resize
:
1240 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_SIZENS
, FALSE
);
1243 case eCursor_w_resize
:
1244 case eCursor_e_resize
:
1245 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_SIZEWE
, FALSE
);
1248 case eCursor_nw_resize
:
1249 case eCursor_se_resize
:
1250 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_SIZENWSE
, FALSE
);
1253 case eCursor_ne_resize
:
1254 case eCursor_sw_resize
:
1255 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_SIZENESW
, FALSE
);
1258 case eCursor_crosshair
:
1259 newPointer
= sPtrArray
[IDC_CROSS
-IDC_BASE
];
1263 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_MOVE
, FALSE
);
1267 newPointer
= sPtrArray
[IDC_HELP
-IDC_BASE
];
1270 case eCursor_copy
: // CSS3
1271 newPointer
= sPtrArray
[IDC_COPY
-IDC_BASE
];
1275 newPointer
= sPtrArray
[IDC_ALIAS
-IDC_BASE
];
1279 newPointer
= sPtrArray
[IDC_CELL
-IDC_BASE
];
1283 newPointer
= sPtrArray
[IDC_GRAB
-IDC_BASE
];
1286 case eCursor_grabbing
:
1287 newPointer
= sPtrArray
[IDC_GRABBING
-IDC_BASE
];
1290 case eCursor_spinning
:
1291 newPointer
= sPtrArray
[IDC_ARROWWAIT
-IDC_BASE
];
1294 case eCursor_context_menu
:
1295 // XXX this CSS3 cursor needs to be implemented
1298 case eCursor_zoom_in
:
1299 newPointer
= sPtrArray
[IDC_ZOOMIN
-IDC_BASE
];
1302 case eCursor_zoom_out
:
1303 newPointer
= sPtrArray
[IDC_ZOOMOUT
-IDC_BASE
];
1306 case eCursor_not_allowed
:
1307 case eCursor_no_drop
:
1308 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_ILLEGAL
, FALSE
);
1311 case eCursor_col_resize
:
1312 newPointer
= sPtrArray
[IDC_COLRESIZE
-IDC_BASE
];
1315 case eCursor_row_resize
:
1316 newPointer
= sPtrArray
[IDC_ROWRESIZE
-IDC_BASE
];
1319 case eCursor_vertical_text
:
1320 newPointer
= sPtrArray
[IDC_VERTICALTEXT
-IDC_BASE
];
1323 case eCursor_all_scroll
:
1324 // XXX not 100% appropriate perhaps
1325 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_MOVE
, FALSE
);
1328 case eCursor_nesw_resize
:
1329 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_SIZENESW
, FALSE
);
1332 case eCursor_nwse_resize
:
1333 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_SIZENWSE
, FALSE
);
1336 case eCursor_ns_resize
:
1337 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_SIZENS
, FALSE
);
1340 case eCursor_ew_resize
:
1341 newPointer
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_SIZEWE
, FALSE
);
1345 newPointer
= sPtrArray
[IDC_NONE
-IDC_BASE
];
1349 NS_ERROR("Invalid cursor type");
1354 WinSetPointer(HWND_DESKTOP
, newPointer
);
1360 //-----------------------------------------------------------------------------
1361 // Create a mouse pointer on the fly to support the CSS 'cursor' style.
1362 // This code is based on the Win version by C. Biesinger but has been
1363 // substantially modified to accommodate platform differences and to
1364 // improve efficiency.
1366 NS_IMETHODIMP
nsWindow::SetCursor(imgIContainer
* aCursor
,
1367 PRUint32 aHotspotX
, PRUint32 aHotspotY
)
1370 // if this is the same image as last time, reuse the saved hptr;
1371 // it will be destroyed when we create a new one or when the
1372 // current window is destroyed
1373 if (mCssCursorImg
== aCursor
&& mCssCursorHPtr
) {
1374 WinSetPointer(HWND_DESKTOP
, mCssCursorHPtr
);
1378 nsRefPtr
<gfxImageSurface
> frame
;
1379 aCursor
->CopyFrame(imgIContainer::FRAME_CURRENT
,
1380 imgIContainer::FLAG_SYNC_DECODE
,
1381 getter_AddRefs(frame
));
1382 NS_ENSURE_TRUE(frame
, NS_ERROR_NOT_AVAILABLE
);
1384 // if the image is ridiculously large, exit because
1385 // it will be unrecognizable when shrunk to 32x32
1386 PRInt32 width
= frame
->Width();
1387 PRInt32 height
= frame
->Height();
1388 NS_ENSURE_TRUE(width
<= 128 && height
<= 128, NS_ERROR_FAILURE
);
1390 PRUint8
* data
= frame
->Data();
1392 // create the color bitmap
1393 HBITMAP hBmp
= CreateBitmapRGB(data
, width
, height
);
1394 NS_ENSURE_TRUE(hBmp
, NS_ERROR_FAILURE
);
1396 // create a transparency mask from the alpha bytes
1397 HBITMAP hAlpha
= CreateTransparencyMask(frame
->Format(), data
, width
, height
);
1399 GpiDeleteBitmap(hBmp
);
1400 return NS_ERROR_FAILURE
;
1403 POINTERINFO info
= {0};
1404 info
.fPointer
= TRUE
;
1405 info
.xHotspot
= aHotspotX
;
1406 info
.yHotspot
= height
- aHotspotY
- 1;
1407 info
.hbmPointer
= hAlpha
;
1408 info
.hbmColor
= hBmp
;
1410 // create the pointer
1411 HPOINTER cursor
= WinCreatePointerIndirect(HWND_DESKTOP
, &info
);
1412 GpiDeleteBitmap(hBmp
);
1413 GpiDeleteBitmap(hAlpha
);
1414 NS_ENSURE_TRUE(cursor
, NS_ERROR_FAILURE
);
1417 WinSetPointer(HWND_DESKTOP
, cursor
);
1419 // destroy the previous hptr; this has to be done after the
1420 // new pointer is set or else WinDestroyPointer() will fail
1421 if (mCssCursorHPtr
) {
1422 WinDestroyPointer(mCssCursorHPtr
);
1425 // save the hptr and a reference to the image for next time
1426 mCssCursorHPtr
= cursor
;
1427 mCssCursorImg
= aCursor
;
1432 //-----------------------------------------------------------------------------
1433 // Render image or modified alpha data as a native bitmap.
1435 // aligned bytes per row, rounded up to next dword bounday
1436 #define ALIGNEDBPR(cx,bits) ( ( ( ((cx)*(bits)) + 31) / 32) * 4)
1438 HBITMAP
nsWindow::DataToBitmap(PRUint8
* aImageData
, PRUint32 aWidth
,
1439 PRUint32 aHeight
, PRUint32 aDepth
)
1441 // get a presentation space for this window
1442 HPS hps
= (HPS
)GetNativeData(NS_NATIVE_GRAPHIC
);
1447 // a handy structure that does double duty
1448 // as both BITMAPINFOHEADER2 & BITMAPINFO2
1450 BITMAPINFOHEADER2 head
;
1455 memset(&bi
, 0, sizeof(bi
));
1456 bi
.white
.bBlue
= (BYTE
)255;
1457 bi
.white
.bGreen
= (BYTE
)255;
1458 bi
.white
.bRed
= (BYTE
)255;
1460 // fill in the particulars
1461 bi
.head
.cbFix
= sizeof(bi
.head
);
1462 bi
.head
.cx
= aWidth
;
1463 bi
.head
.cy
= aHeight
;
1464 bi
.head
.cPlanes
= 1;
1465 bi
.head
.cBitCount
= aDepth
;
1466 bi
.head
.ulCompression
= BCA_UNCOMP
;
1467 bi
.head
.cbImage
= ALIGNEDBPR(aWidth
, aDepth
) * aHeight
;
1468 bi
.head
.cclrUsed
= (aDepth
== 1 ? 2 : 0);
1470 // create a bitmap from the image data
1471 HBITMAP hBmp
= GpiCreateBitmap(hps
, &bi
.head
, CBM_INIT
,
1472 reinterpret_cast<BYTE
*>(aImageData
),
1475 // free the hps, then return the bitmap
1476 FreeNativeData((void*)hps
, NS_NATIVE_GRAPHIC
);
1480 //-----------------------------------------------------------------------------
1481 // Create an RGB24 bitmap from Cairo image data.
1483 HBITMAP
nsWindow::CreateBitmapRGB(PRUint8
* aImageData
,
1487 // calc width in bytes, rounding up to a dword boundary
1488 const PRUint32 bpr
= ALIGNEDBPR(aWidth
, 24);
1489 PRUint8
* bmp
= (PRUint8
*)malloc(bpr
* aHeight
);
1494 PRUint32
* pSrc
= (PRUint32
*)aImageData
;
1495 for (PRUint32 row
= aHeight
; row
> 0; --row
) {
1496 PRUint8
* pDst
= bmp
+ bpr
* (row
- 1);
1498 for (PRUint32 col
= aWidth
; col
> 0; --col
) {
1499 // In Cairo a color is encoded as ARGB in a DWORD
1500 // stored in machine endianess.
1501 PRUint32 color
= *pSrc
++;
1502 *pDst
++ = color
; // Blue
1503 *pDst
++ = color
>> 8; // Green
1504 *pDst
++ = color
>> 16; // Red
1508 // create the bitmap
1509 HBITMAP hAlpha
= DataToBitmap(bmp
, aWidth
, aHeight
, 24);
1511 // free the buffer, then return the bitmap
1516 //-----------------------------------------------------------------------------
1517 // Create a monochrome AND/XOR bitmap from 0, 1, or 8-bit alpha data.
1519 HBITMAP
nsWindow::CreateTransparencyMask(gfxASurface::gfxImageFormat format
,
1520 PRUint8
* aImageData
,
1524 // calc width in bytes, rounding up to a dword boundary
1525 PRUint32 abpr
= ALIGNEDBPR(aWidth
, 1);
1526 PRUint32 cbData
= abpr
* aHeight
;
1528 // alloc and clear space to hold both the AND & XOR bitmaps
1529 PRUint8
* mono
= (PRUint8
*)calloc(cbData
, 2);
1534 // Non-alpha formats are already taken care of
1535 // by initializing the XOR and AND masks to zero
1536 if (format
== gfxASurface::ImageFormatARGB32
) {
1538 // make the AND mask the inverse of the 8-bit alpha data
1539 PRInt32
* pSrc
= (PRInt32
*)aImageData
;
1540 for (PRUint32 row
= aHeight
; row
> 0; --row
) {
1541 // Point to the right row in the AND mask
1542 PRUint8
* pDst
= mono
+ cbData
+ abpr
* (row
- 1);
1543 PRUint8 mask
= 0x80;
1544 for (PRUint32 col
= aWidth
; col
> 0; --col
) {
1545 // Use the sign bit to test for transparency, as the alpha byte
1546 // is highest byte. Positive means, alpha < 128, so consider it
1547 // as transparent and set the AND mask.
1561 // create the bitmap
1562 HBITMAP hAlpha
= DataToBitmap(mono
, aWidth
, aHeight
* 2, 1);
1564 // free the buffer, then return the bitmap
1569 //=============================================================================
1570 // Rollup Event Handlers
1571 //=============================================================================
1573 NS_IMETHODIMP
nsWindow::CaptureRollupEvents(nsIRollupListener
* aListener
,
1574 nsIMenuRollup
* aMenuRollup
,
1576 PRBool aConsumeRollupEvent
)
1578 // We haven't bothered carrying a weak reference to gRollupWidget
1579 // because we believe lifespan is properly scoped. The first
1580 // assertion helps assure that remains true.
1582 NS_ASSERTION(!gRollupWidget
, "rollup widget reassigned before release");
1583 gRollupConsumeRollupEvent
= aConsumeRollupEvent
;
1584 NS_IF_RELEASE(gRollupWidget
);
1585 gRollupListener
= aListener
;
1586 NS_IF_RELEASE(gMenuRollup
);
1587 gMenuRollup
= aMenuRollup
;
1588 NS_IF_ADDREF(aMenuRollup
);
1589 gRollupWidget
= this;
1592 gRollupListener
= nsnull
;
1593 NS_IF_RELEASE(gMenuRollup
);
1594 NS_IF_RELEASE(gRollupWidget
);
1600 //-----------------------------------------------------------------------------
1603 PRBool
nsWindow::EventIsInsideWindow(nsWindow
* aWindow
)
1608 if (WinQueryMsgPos(0, &ptl
)) {
1609 WinMapWindowPoints(HWND_DESKTOP
, aWindow
->mWnd
, &ptl
, 1);
1610 WinQueryWindowRect(aWindow
->mWnd
, &rcl
);
1612 // now make sure that it wasn't one of our children
1613 if (ptl
.x
< rcl
.xLeft
|| ptl
.x
> rcl
.xRight
||
1614 ptl
.y
> rcl
.yTop
|| ptl
.y
< rcl
.yBottom
) {
1622 //-----------------------------------------------------------------------------
1623 // Handle events that would cause a popup (combobox, menu, etc) to rollup.
1626 PRBool
nsWindow::RollupOnButtonDown(ULONG aMsg
)
1628 // Exit if the event is inside the most recent popup.
1629 if (EventIsInsideWindow((nsWindow
*)gRollupWidget
)) {
1633 // See if we're dealing with a menu. If so, exit if the
1634 // event was inside a parent of the current submenu.
1635 PRUint32 popupsToRollup
= PR_UINT32_MAX
;
1638 nsAutoTArray
<nsIWidget
*, 5> widgetChain
;
1639 PRUint32 sameTypeCount
= gMenuRollup
->GetSubmenuWidgetChain(&widgetChain
);
1640 for (PRUint32 i
= 0; i
< widgetChain
.Length(); ++i
) {
1641 nsIWidget
* widget
= widgetChain
[i
];
1642 if (EventIsInsideWindow((nsWindow
*)widget
)) {
1643 if (i
< sameTypeCount
) {
1646 popupsToRollup
= sameTypeCount
;
1649 } // for each parent menu widget
1650 } // if rollup listener knows about menus
1652 // We only need to deal with the last rollup for left mouse down events.
1653 gRollupListener
->Rollup(popupsToRollup
,
1654 aMsg
== WM_BUTTON1DOWN
? &mLastRollup
: nsnull
);
1656 // If true, the buttondown event won't be passed on to the wndproc.
1657 return gRollupConsumeRollupEvent
;
1660 //-----------------------------------------------------------------------------
1663 void nsWindow::RollupOnFocusLost(HWND aFocus
)
1665 HWND hRollup
= ((nsWindow
*)gRollupWidget
)->mWnd
;
1667 // Exit if focus was lost to the most recent popup.
1668 if (hRollup
== aFocus
) {
1672 // Exit if focus was lost to a parent of the current submenu.
1674 nsAutoTArray
<nsIWidget
*, 5> widgetChain
;
1675 gMenuRollup
->GetSubmenuWidgetChain(&widgetChain
);
1676 for (PRUint32 i
= 0; i
< widgetChain
.Length(); ++i
) {
1677 if (((nsWindow
*)widgetChain
[i
])->mWnd
== aFocus
) {
1683 // Rollup all popups.
1684 gRollupListener
->Rollup(PR_UINT32_MAX
, nsnull
);
1688 //=============================================================================
1689 // nsWindow's Window Procedure
1690 //=============================================================================
1692 // This is the actual wndproc; it does some preprocessing then passes
1693 // the msgs to the ProcessMessage() method which does most of the work.
1695 MRESULT EXPENTRY
fnwpNSWindow(HWND hwnd
, ULONG msg
, MPARAM mp1
, MPARAM mp2
)
1697 nsAutoRollup autoRollup
;
1699 // If this window doesn't have an object ptr,
1700 // send the msg to the default wndproc.
1701 nsWindow
* wnd
= nsWindow::GetNSWindowPtr(hwnd
);
1703 return WinDefWindowProc(hwnd
, msg
, mp1
, mp2
);
1706 // If we're not in the destructor, hold on to the object for the
1707 // life of this method, in case it gets deleted during processing.
1708 // Yes, it's a double hack since someWindow is not really an interface.
1709 nsCOMPtr
<nsISupports
> kungFuDeathGrip
;
1710 if (!wnd
->mIsDestroying
) {
1711 kungFuDeathGrip
= do_QueryInterface((nsBaseWidget
*)wnd
);
1714 // Pre-process msgs that may cause a rollup.
1715 if (gRollupListener
&& gRollupWidget
) {
1717 case WM_BUTTON1DOWN
:
1718 case WM_BUTTON2DOWN
:
1719 case WM_BUTTON3DOWN
:
1720 if (nsWindow::RollupOnButtonDown(msg
)) {
1721 return (MRESULT
)PR_TRUE
;
1727 nsWindow::RollupOnFocusLost((HWND
)mp1
);
1733 return wnd
->ProcessMessage(msg
, mp1
, mp2
);
1736 //-----------------------------------------------------------------------------
1737 // In effect, nsWindow's real wndproc.
1739 MRESULT
nsWindow::ProcessMessage(ULONG msg
, MPARAM mp1
, MPARAM mp2
)
1741 PRBool isDone
= PR_FALSE
;
1742 MRESULT mresult
= 0;
1746 // Interpret WM_QUIT as a close request so that
1747 // windows can be closed from the Window List
1750 mWindowState
|= nsWindowState_eClosing
;
1751 nsGUIEvent
event(PR_TRUE
, NS_XUL_CLOSE
, this);
1753 DispatchWindowEvent(&event
);
1754 // abort window closure
1768 case WM_TRANSLATEACCEL
:
1769 isDone
= OnTranslateAccelerator((PQMSG
)mp1
);
1773 isDone
= DispatchKeyEvent(mp1
, mp2
);
1776 // Mouseclicks: we don't dispatch CLICK events because they just cause
1777 // trouble: gecko seems to expect EITHER buttondown/up OR click events
1778 // and so that's what we give it.
1780 case WM_BUTTON1DOWN
:
1781 WinSetCapture(HWND_DESKTOP
, mWnd
);
1782 DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, mp1
, mp2
);
1783 // there's no need to clear this on button-up
1784 sLastButton1Down
.x
= XFROMMP(mp1
);
1785 sLastButton1Down
.y
= YFROMMP(mp1
);
1789 WinSetCapture(HWND_DESKTOP
, 0);
1790 isDone
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, mp1
, mp2
);
1793 case WM_BUTTON1DBLCLK
:
1794 isDone
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, mp1
, mp2
);
1797 case WM_BUTTON2DOWN
:
1798 WinSetCapture(HWND_DESKTOP
, mWnd
);
1799 isDone
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, mp1
, mp2
, PR_FALSE
,
1800 nsMouseEvent::eRightButton
);
1804 WinSetCapture(HWND_DESKTOP
, 0);
1805 isDone
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, mp1
, mp2
, PR_FALSE
,
1806 nsMouseEvent::eRightButton
);
1809 case WM_BUTTON2DBLCLK
:
1810 isDone
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, mp1
, mp2
,
1811 PR_FALSE
, nsMouseEvent::eRightButton
);
1814 case WM_BUTTON3DOWN
:
1815 WinSetCapture(HWND_DESKTOP
, mWnd
);
1816 isDone
= DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN
, mp1
, mp2
, PR_FALSE
,
1817 nsMouseEvent::eMiddleButton
);
1821 WinSetCapture(HWND_DESKTOP
, 0);
1822 isDone
= DispatchMouseEvent(NS_MOUSE_BUTTON_UP
, mp1
, mp2
, PR_FALSE
,
1823 nsMouseEvent::eMiddleButton
);
1826 case WM_BUTTON3DBLCLK
:
1827 isDone
= DispatchMouseEvent(NS_MOUSE_DOUBLECLICK
, mp1
, mp2
, PR_FALSE
,
1828 nsMouseEvent::eMiddleButton
);
1831 case WM_CONTEXTMENU
:
1832 if (SHORT2FROMMP(mp2
)) {
1833 HWND hFocus
= WinQueryFocus(HWND_DESKTOP
);
1834 if (hFocus
!= mWnd
) {
1835 WinSendMsg(hFocus
, msg
, mp1
, mp2
);
1837 isDone
= DispatchMouseEvent(NS_CONTEXTMENU
, mp1
, mp2
, PR_TRUE
,
1838 nsMouseEvent::eLeftButton
);
1841 isDone
= DispatchMouseEvent(NS_CONTEXTMENU
, mp1
, mp2
, PR_FALSE
,
1842 nsMouseEvent::eRightButton
);
1846 // If MB1 & MB2 are both pressed, perform a copy or paste.
1848 isDone
= OnMouseChord(mp1
, mp2
);
1851 case WM_MOUSEMOVE
: {
1852 static POINTL ptlLastPos
= { -1, -1 };
1854 // If mouse has actually moved, remember the new position,
1855 // then dispatch the event.
1856 if (ptlLastPos
.x
!= (SHORT
)SHORT1FROMMP(mp1
) ||
1857 ptlLastPos
.y
!= (SHORT
)SHORT2FROMMP(mp1
)) {
1858 ptlLastPos
.x
= (SHORT
)SHORT1FROMMP(mp1
);
1859 ptlLastPos
.y
= (SHORT
)SHORT2FROMMP(mp1
);
1860 DispatchMouseEvent(NS_MOUSE_MOVE
, mp1
, mp2
);
1863 // don't propagate mouse move or the OS will change the pointer
1869 isDone
= DispatchMouseEvent(NS_MOUSE_ENTER
, mp1
, mp2
);
1873 isDone
= DispatchMouseEvent(NS_MOUSE_EXIT
, mp1
, mp2
);
1876 case WM_APPCOMMAND
: {
1877 PRUint32 appCommand
= SHORT2FROMMP(mp2
) & 0xfff;
1879 switch (appCommand
) {
1880 case APPCOMMAND_BROWSER_BACKWARD
:
1881 case APPCOMMAND_BROWSER_FORWARD
:
1882 case APPCOMMAND_BROWSER_REFRESH
:
1883 case APPCOMMAND_BROWSER_STOP
:
1884 DispatchCommandEvent(appCommand
);
1885 // tell the driver that we handled the event
1886 mresult
= (MRESULT
)1;
1895 isDone
= DispatchScrollEvent(msg
, mp1
, mp2
);
1898 // Do not act on WM_ACTIVATE - it is handled by os2FrameWindow.
1899 // case WM_ACTIVATE:
1902 // This msg is used to activate top-level and plugin widgets
1903 // after PM is done changing the focus. We're only interested
1904 // in windows gaining focus, not in those losing it.
1905 case WM_FOCUSCHANGED
:
1906 DEBUGFOCUS(WM_FOCUSCHANGED
);
1907 if (SHORT1FROMMP(mp2
)) {
1908 ActivateTopLevelWidget();
1909 ActivatePlugin(HWNDFROMMP(mp1
));
1913 case WM_WINDOWPOSCHANGED
:
1914 isDone
= OnReposition((PSWP
) mp1
);
1917 // all msgs that occur when this window is the target of a drag
1921 case DM_RENDERCOMPLETE
:
1923 OnDragDropMsg(msg
, mp1
, mp2
, mresult
);
1928 // If an event handler signalled that we should consume the event,
1929 // return. Otherwise, pass it on to the default wndproc.
1931 mresult
= WinDefWindowProc(mWnd
, msg
, mp1
, mp2
);
1937 //=============================================================================
1938 // Window Message Handlers
1939 //=============================================================================
1941 // WM_DESTROY has been called.
1943 void nsWindow::OnDestroy()
1945 mOnDestroyCalled
= PR_TRUE
;
1947 SetNSWindowPtr(mWnd
, 0);
1950 // release references to context, toolkit, appshell, children
1951 nsBaseWidget::OnDestroy();
1953 // dispatching of the event may cause the reference count to drop to 0
1954 // and result in this object being deleted. To avoid that, add a
1955 // reference and then release it after dispatching the event.
1957 // It's important *not* to do this if we're being called from the
1958 // destructor -- this would result in our destructor being called *again*
1959 // from the Release() below. This is very bad...
1960 if (!(nsWindowState_eDoingDelete
& mWindowState
)) {
1962 nsGUIEvent
event(PR_TRUE
, NS_DESTROY
, this);
1964 DispatchWindowEvent(&event
);
1969 mWindowState
|= nsWindowState_eDead
;
1970 mWindowState
&= ~(nsWindowState_eLive
|nsWindowState_ePrecreate
|
1971 nsWindowState_eInCreate
);
1974 //-----------------------------------------------------------------------------
1976 PRBool
nsWindow::OnReposition(PSWP pSwp
)
1978 PRBool result
= PR_FALSE
;
1980 if (pSwp
->fl
& SWP_MOVE
&& !(pSwp
->fl
& SWP_MINIMIZE
)) {
1981 HWND hParent
= mParent
? mParent
->mWnd
: WinQueryWindow(mWnd
, QW_PARENT
);
1983 // need screen coords.
1984 POINTL ptl
= { pSwp
->x
, pSwp
->y
+ pSwp
->cy
- 1 };
1985 // XXX - this is peculiar...
1986 WinMapWindowPoints(WinQueryWindow(mWnd
, QW_PARENT
), hParent
, &ptl
, 1);
1990 WinMapWindowPoints(hParent
, HWND_DESKTOP
, &ptl
, 1);
1992 result
= DispatchMoveEvent(ptl
.x
, ptl
.y
);
1995 if (pSwp
->fl
& SWP_SIZE
&& !(pSwp
->fl
& SWP_MINIMIZE
)) {
1996 mBounds
.width
= pSwp
->cx
;
1997 mBounds
.height
= pSwp
->cy
;
1999 // If the window is supposed to have a thebes surface, resize it.
2000 if (ConfirmThebesSurface()) {
2001 mThebesSurface
->Resize(gfxIntSize(mBounds
.width
, mBounds
.height
));
2004 result
= DispatchResizeEvent(mBounds
.width
, mBounds
.height
);
2010 //-----------------------------------------------------------------------------
2012 PRBool
nsWindow::OnPaint()
2017 nsEventStatus eventStatus
= nsEventStatus_eIgnore
;
2020 HRGN debugPaintFlashRegion
= 0;
2021 HPS debugPaintFlashPS
= 0;
2023 if (debug_WantPaintFlashing()) {
2024 debugPaintFlashPS
= WinGetPS(mWnd
);
2025 debugPaintFlashRegion
= GpiCreateRegion(debugPaintFlashPS
, 0, 0);
2026 WinQueryUpdateRegion(mWnd
, debugPaintFlashRegion
);
2030 // Use a dummy do..while(0) loop to facilitate error handling & early-outs.
2033 // Get the current drag status. If we're in a Moz-originated drag,
2034 // it will return a special drag HPS to pass to WinBeginPaint().
2035 // Oherwise, get a cached micro PS.
2036 CheckDragStatus(ACTION_PAINT
, &hpsDrag
);
2037 hPS
= hpsDrag
? hpsDrag
: WinGetPS(mWnd
);
2039 // If we can't get an HPS, validate the window so we don't
2040 // keep getting the same WM_PAINT msg over & over again.
2043 WinQueryWindowRect(mWnd
, &rcl
);
2044 WinValidateRect(mWnd
, &rcl
, FALSE
);
2048 // Get the update region before WinBeginPaint() resets it.
2049 hrgn
= GpiCreateRegion(hPS
, 0, 0);
2050 WinQueryUpdateRegion(mWnd
, hrgn
);
2051 WinBeginPaint(mWnd
, hPS
, &rcl
);
2053 // Exit if the update rect is empty.
2054 if (WinIsRectEmpty(0, &rcl
)) {
2058 // Exit if a thebes surface can not/should not be created,
2059 // but first fill the area with the default background color
2060 // to erase any visual artifacts.
2061 if (!ConfirmThebesSurface()) {
2062 WinDrawBorder(hPS
, &rcl
, 0, 0, 0, 0, DB_INTERIOR
| DB_AREAATTRS
);
2066 // Even if there is no callback to update the content (unlikely)
2067 // we still want to update the screen with whatever's available.
2068 if (!mEventCallback
) {
2069 mThebesSurface
->Refresh(&rcl
, hPS
);
2073 // Create an event & a Thebes context.
2074 nsPaintEvent
event(PR_TRUE
, NS_PAINT
, this);
2076 nsRefPtr
<gfxContext
> thebesContext
= new gfxContext(mThebesSurface
);
2078 // Intersect the update region with the paint rectangle to clip areas
2079 // that aren't visible (e.g. offscreen or covered by another window).
2081 hrgnPaint
= GpiCreateRegion(hPS
, 1, &rcl
);
2083 GpiCombineRegion(hPS
, hrgn
, hrgn
, hrgnPaint
, CRGN_AND
);
2084 GpiDestroyRegion(hPS
, hrgnPaint
);
2087 // See how many rects comprise the update region. If there are 8
2088 // or fewer, update them individually. If there are more or the call
2089 // failed, update the bounding rectangle returned by WinBeginPaint().
2090 #define MAX_CLIPRECTS 8
2091 RGNRECT rgnrect
= { 1, MAX_CLIPRECTS
, 0, RECTDIR_LFRT_TOPBOT
};
2092 RECTL arect
[MAX_CLIPRECTS
];
2095 if (!GpiQueryRegionRects(hPS
, hrgn
, 0, &rgnrect
, 0) ||
2096 rgnrect
.crcReturned
> MAX_CLIPRECTS
) {
2097 rgnrect
.crcReturned
= 1;
2100 GpiQueryRegionRects(hPS
, hrgn
, 0, &rgnrect
, arect
);
2103 // Create clipping regions for the event & the Thebes context.
2104 thebesContext
->NewPath();
2105 for (PRUint32 i
= 0; i
< rgnrect
.crcReturned
; i
++, pr
++) {
2106 event
.region
.Or(event
.region
,
2107 nsIntRect(pr
->xLeft
,
2108 mBounds
.height
- pr
->yTop
,
2109 pr
->xRight
- pr
->xLeft
,
2110 pr
->yTop
- pr
->yBottom
));
2112 thebesContext
->Rectangle(gfxRect(pr
->xLeft
,
2113 mBounds
.height
- pr
->yTop
,
2114 pr
->xRight
- pr
->xLeft
,
2115 pr
->yTop
- pr
->yBottom
));
2117 thebesContext
->Clip();
2120 debug_DumpPaintEvent(stdout
, this, &event
, nsCAutoString("noname"),
2124 // Init the Layers manager then dispatch the event.
2125 // If it returns false there's nothing to paint, so exit.
2126 AutoLayerManagerSetup
2127 setupLayerManager(this, thebesContext
, BasicLayerManager::BUFFER_NONE
);
2128 if (!DispatchWindowEvent(&event
, eventStatus
)) {
2132 // Paint the surface, then use Refresh() to blit each rect to the screen.
2133 thebesContext
->PopGroupToSource();
2134 thebesContext
->SetOperator(gfxContext::OPERATOR_SOURCE
);
2135 thebesContext
->Paint();
2137 for (PRUint32 i
= 0; i
< rgnrect
.crcReturned
; i
++, pr
++) {
2138 mThebesSurface
->Refresh(pr
, hPS
);
2147 GpiDestroyRegion(hPS
, hrgn
);
2149 if (!hpsDrag
|| !ReleaseIfDragHPS(hpsDrag
)) {
2155 if (debug_WantPaintFlashing()) {
2156 // Only flash paint events which have not ignored the paint message.
2157 // Those that ignore the paint message aren't painting anything so there
2158 // is only the overhead of the dispatching the paint event.
2159 if (eventStatus
!= nsEventStatus_eIgnore
) {
2160 LONG CurMix
= GpiQueryMix(debugPaintFlashPS
);
2161 GpiSetMix(debugPaintFlashPS
, FM_INVERT
);
2163 GpiPaintRegion(debugPaintFlashPS
, debugPaintFlashRegion
);
2164 PR_Sleep(PR_MillisecondsToInterval(30));
2165 GpiPaintRegion(debugPaintFlashPS
, debugPaintFlashRegion
);
2166 PR_Sleep(PR_MillisecondsToInterval(30));
2168 GpiSetMix(debugPaintFlashPS
, CurMix
);
2170 GpiDestroyRegion(debugPaintFlashPS
, debugPaintFlashRegion
);
2171 WinReleasePS(debugPaintFlashPS
);
2178 //-----------------------------------------------------------------------------
2179 // If MB1 & MB2 are both pressed, perform a copy or paste.
2181 PRBool
nsWindow::OnMouseChord(MPARAM mp1
, MPARAM mp2
)
2183 if (!isKeyDown(VK_BUTTON1
) || !isKeyDown(VK_BUTTON2
)) {
2187 // See how far the mouse has moved since MB1-down to determine
2188 // the operation (this really ought to look for selected content).
2189 PRBool isCopy
= PR_FALSE
;
2190 if (abs(XFROMMP(mp1
) - sLastButton1Down
.x
) >
2191 (WinQuerySysValue(HWND_DESKTOP
, SV_CXMOTIONSTART
) / 2) ||
2192 abs(YFROMMP(mp1
) - sLastButton1Down
.y
) >
2193 (WinQuerySysValue(HWND_DESKTOP
, SV_CYMOTIONSTART
) / 2)) {
2197 nsKeyEvent
event(PR_TRUE
, NS_KEY_PRESS
, this);
2198 nsIntPoint
point(0,0);
2199 InitEvent(event
, &point
);
2201 event
.keyCode
= NS_VK_INSERT
;
2203 event
.isShift
= PR_FALSE
;
2204 event
.isControl
= PR_TRUE
;
2206 event
.isShift
= PR_TRUE
;
2207 event
.isControl
= PR_FALSE
;
2209 event
.isAlt
= PR_FALSE
;
2210 event
.isMeta
= PR_FALSE
;
2211 event
.eventStructType
= NS_KEY_EVENT
;
2214 // OS/2 does not set the Shift, Ctrl, or Alt on keyup
2215 if (SHORT1FROMMP(mp1
) & (KC_VIRTUALKEY
| KC_KEYUP
| KC_LONEKEY
)) {
2216 USHORT usVKey
= SHORT2FROMMP(mp2
);
2217 if (usVKey
== VK_SHIFT
) {
2218 event
.isShift
= PR_TRUE
;
2220 if (usVKey
== VK_CTRL
) {
2221 event
.isControl
= PR_TRUE
;
2223 if (usVKey
== VK_ALTGRAF
|| usVKey
== VK_ALT
) {
2224 event
.isAlt
= PR_TRUE
;
2228 return DispatchWindowEvent(&event
);
2231 //=============================================================================
2232 // Drag & Drop - Target methods
2233 //=============================================================================
2235 // nsWindow knows almost nothing about d&d except that it can cause
2236 // video corruption if the screen is updated during a drag. It relies
2237 // on nsIDragSessionOS2 to handle native d&d messages and to return
2238 // the status flags it uses to control screen updates.
2240 // OnDragDropMsg() handles all of the DM_* messages messages nsWindow
2241 // should ever receive. CheckDragStatus() determines if a screen update
2242 // is safe and may return a drag HPS if doing so will avoid corruption.
2243 // As far as its author (R.Walsh) can tell, every use is required.
2245 // For Moz drags, all while-you-drag features should be fully enabled &
2246 // corruption free; for native drags, popups & scrolling are suppressed
2247 // but some niceties, e.g. moving the cursor in text fields, are enabled.
2249 //-----------------------------------------------------------------------------
2251 // This method was designed to be totally ignorant of drag and drop.
2252 // It gives nsIDragSessionOS2 (near) complete control over handling.
2254 PRBool
nsWindow::OnDragDropMsg(ULONG msg
, MPARAM mp1
, MPARAM mp2
, MRESULT
& mr
)
2257 PRUint32 eventType
= 0;
2258 PRUint32 dragFlags
= 0;
2261 nsCOMPtr
<nsIDragService
> dragService
=
2262 do_GetService("@mozilla.org/widget/dragservice;1", &rv
);
2264 nsCOMPtr
<nsIDragSessionOS2
> dragSession(
2265 do_QueryInterface(dragService
, &rv
));
2268 // handle all possible input without regard to outcome
2272 dragService
->FireDragEventAtSource(NS_DRAGDROP_DRAG
);
2273 rv
= dragSession
->DragOverMsg((PDRAGINFO
)mp1
, mr
, &dragFlags
);
2274 eventType
= NS_DRAGDROP_OVER
;
2278 rv
= dragSession
->DragLeaveMsg((PDRAGINFO
)mp1
, &dragFlags
);
2279 eventType
= NS_DRAGDROP_EXIT
;
2283 rv
= dragSession
->DropMsg((PDRAGINFO
)mp1
, mWnd
, &dragFlags
);
2284 eventType
= NS_DRAGDROP_DROP
;
2288 rv
= dragSession
->DropHelpMsg((PDRAGINFO
)mp1
, &dragFlags
);
2289 eventType
= NS_DRAGDROP_EXIT
;
2292 case DM_RENDERCOMPLETE
:
2293 rv
= dragSession
->RenderCompleteMsg((PDRAGTRANSFER
)mp1
,
2294 SHORT1FROMMP(mp2
), &dragFlags
);
2295 eventType
= NS_DRAGDROP_DROP
;
2299 rv
= NS_ERROR_FAILURE
;
2302 // handle all possible outcomes without regard to their source
2303 if (NS_SUCCEEDED(rv
)) {
2304 mDragStatus
= sDragStatus
= (dragFlags
& DND_DragStatus
);
2306 if (dragFlags
& DND_DispatchEnterEvent
) {
2307 DispatchDragDropEvent(NS_DRAGDROP_ENTER
);
2309 if (dragFlags
& DND_DispatchEvent
) {
2310 DispatchDragDropEvent(eventType
);
2312 if (dragFlags
& DND_GetDragoverResult
) {
2313 dragSession
->GetDragoverResult(mr
);
2315 if (dragFlags
& DND_ExitSession
) {
2316 dragSession
->ExitSession(&dragFlags
);
2321 // save final drag status
2322 sDragStatus
= mDragStatus
= (dragFlags
& DND_DragStatus
);
2327 //-----------------------------------------------------------------------------
2328 // CheckDragStatus() concentrates all the hacks needed to avoid video
2329 // corruption during d&d into one place. The caller specifies an action
2330 // that might be a problem; the method tells it whether to proceed and
2331 // provides a Drg HPS if the situation calls for one.
2333 PRBool
nsWindow::CheckDragStatus(PRUint32 aAction
, HPS
* aHps
)
2335 PRBool rtn
= PR_TRUE
;
2336 PRBool getHps
= PR_FALSE
;
2340 // OnPaint() & Scroll..() - only Moz drags get a Drg hps
2343 if (sDragStatus
& DND_MozDrag
) {
2348 // GetNativeData() - Moz drags + native drags over this nsWindow
2350 if ((sDragStatus
& DND_MozDrag
) ||
2351 (mDragStatus
& DND_NativeDrag
)) {
2356 // Show() - don't show popups during a native dragover
2358 if ((sDragStatus
& (DND_NativeDrag
| DND_InDrop
)) == DND_NativeDrag
) {
2363 // InitEvent() - use PtrPos while in drag, MsgPos otherwise
2374 // If the caller wants an HPS, and the current drag status
2375 // calls for one, *and* a drag hps hasn't already been requested
2376 // for this window, get the hps; otherwise, return zero;
2377 // (if we provide a 2nd hps for a window, the cursor in text
2378 // fields won't be erased when it's moved to another position)
2380 if (getHps
&& !mDragHps
) {
2381 mDragHps
= DrgGetPS(mWnd
);
2391 //-----------------------------------------------------------------------------
2392 // If there's an outstanding drag hps & it matches the one passed in,
2395 PRBool
nsWindow::ReleaseIfDragHPS(HPS aHps
)
2397 if (mDragHps
&& aHps
== mDragHps
) {
2398 DrgReleasePS(mDragHps
);
2406 //=============================================================================
2407 // Keyboard Handlers
2408 //=============================================================================
2410 // Figure out which keyboard LEDs are on.
2412 NS_IMETHODIMP
nsWindow::GetToggledKeyState(PRUint32 aKeyCode
, PRBool
* aLEDState
)
2416 NS_ENSURE_ARG_POINTER(aLEDState
);
2419 case NS_VK_CAPS_LOCK
:
2422 case NS_VK_NUM_LOCK
:
2425 case NS_VK_SCROLL_LOCK
:
2429 *aLEDState
= PR_FALSE
;
2433 *aLEDState
= (WinGetKeyState(HWND_DESKTOP
, vkey
) & 1) != 0;
2437 //-----------------------------------------------------------------------------
2438 // Prevent PM from translating some keys & key-combos into accelerators.
2440 PRBool
nsWindow::OnTranslateAccelerator(PQMSG pQmsg
)
2442 if (pQmsg
->msg
!= WM_CHAR
) {
2446 LONG mp1
= (LONG
)pQmsg
->mp1
;
2447 LONG mp2
= (LONG
)pQmsg
->mp2
;
2448 LONG sca
= SHORT1FROMMP(mp1
) & (KC_SHIFT
| KC_CTRL
| KC_ALT
);
2450 if (SHORT1FROMMP(mp1
) & KC_VIRTUALKEY
) {
2452 // standalone F1 & F10
2453 if (SHORT2FROMMP(mp2
) == VK_F1
|| SHORT2FROMMP(mp2
) == VK_F10
) {
2454 return (!sca
? PR_TRUE
: PR_FALSE
);
2458 if (SHORT2FROMMP(mp2
) == VK_ENTER
) {
2459 return (sca
== KC_SHIFT
? PR_TRUE
: PR_FALSE
);
2463 if (SHORT2FROMMP(mp2
) == VK_NEWLINE
) {
2464 return (sca
== KC_ALT
? PR_TRUE
: PR_FALSE
);
2467 // standalone Alt & AltGraf
2468 if ((SHORT2FROMMP(mp2
) == VK_ALT
|| SHORT2FROMMP(mp2
) == VK_ALTGRAF
) &&
2469 (SHORT1FROMMP(mp1
) & (KC_KEYUP
| KC_LONEKEY
))
2470 == (KC_KEYUP
| KC_LONEKEY
)) {
2478 //-----------------------------------------------------------------------------
2479 // Key handler. Specs for the various text messages are really confused;
2480 // see other platforms for best results of how things are supposed to work.
2482 // Perhaps more importantly, the main man listening to these events
2483 // (besides random bits of javascript) is ender -- see
2484 // mozilla/editor/base/nsEditorEventListeners.cpp.
2486 PRBool
nsWindow::DispatchKeyEvent(MPARAM mp1
, MPARAM mp2
)
2488 nsKeyEvent
pressEvent(PR_TRUE
, 0, nsnull
);
2489 USHORT fsFlags
= SHORT1FROMMP(mp1
);
2490 USHORT usVKey
= SHORT2FROMMP(mp2
);
2491 USHORT usChar
= SHORT1FROMMP(mp2
);
2492 UCHAR uchScan
= CHAR4FROMMP(mp1
);
2494 // It appears we're not supposed to transmit shift,
2495 // control, & alt events to gecko.
2496 if (fsFlags
& KC_VIRTUALKEY
&& !(fsFlags
& KC_KEYUP
) &&
2497 (usVKey
== VK_SHIFT
|| usVKey
== VK_CTRL
|| usVKey
== VK_ALTGRAF
)) {
2501 // Workaround bug where using Alt+Esc let an Alt key creep through
2502 // Only handle alt by itself if the LONEKEY bit is set
2503 if ((fsFlags
& KC_VIRTUALKEY
) && (usVKey
== VK_ALT
) && !usChar
&&
2504 (!(fsFlags
& KC_LONEKEY
)) && (fsFlags
& KC_KEYUP
)) {
2508 // Now check if it's a dead-key
2509 if (fsFlags
& KC_DEADKEY
) {
2513 // Now dispatch a keyup/keydown event. This one is *not* meant to
2514 // have the unicode charcode in.
2515 nsIntPoint
point(0,0);
2516 nsKeyEvent
event(PR_TRUE
, (fsFlags
& KC_KEYUP
) ? NS_KEY_UP
: NS_KEY_DOWN
,
2518 InitEvent(event
, &point
);
2519 event
.keyCode
= WMChar2KeyCode(mp1
, mp2
);
2520 event
.isShift
= (fsFlags
& KC_SHIFT
) ? PR_TRUE
: PR_FALSE
;
2521 event
.isControl
= (fsFlags
& KC_CTRL
) ? PR_TRUE
: PR_FALSE
;
2522 event
.isAlt
= (fsFlags
& KC_ALT
) ? PR_TRUE
: PR_FALSE
;
2523 event
.isMeta
= PR_FALSE
;
2526 // Check for a scroll mouse event vs. a keyboard event. The way we know
2527 // this is that the repeat count is 0 and the key is not physically down.
2528 // Unfortunately, there is an exception here - if alt or ctrl are held
2529 // down, repeat count is set so we have to add special checks for them.
2530 if (((event
.keyCode
== NS_VK_UP
) || (event
.keyCode
== NS_VK_DOWN
)) &&
2531 !(fsFlags
& KC_KEYUP
) &&
2532 (!CHAR3FROMMP(mp1
) || fsFlags
& KC_CTRL
|| fsFlags
& KC_ALT
)) {
2533 if (!(WinGetPhysKeyState(HWND_DESKTOP
, uchScan
) & 0x8000)) {
2535 if (event
.keyCode
== NS_VK_UP
) {
2536 mp2
= MPFROM2SHORT(0, SB_LINEUP
);
2538 mp2
= MPFROM2SHORT(0, SB_LINEDOWN
);
2540 WinSendMsg(mWnd
, WM_VSCROLL
, 0, mp2
);
2546 PRBool rc
= DispatchWindowEvent(&event
);
2548 // Break off now if this was a key-up.
2549 if (fsFlags
& KC_KEYUP
) {
2553 // Break off if we've got an "invalid composition" -- that is,
2554 // the user typed a deadkey last time, but has now typed something
2555 // that doesn't make sense in that context.
2556 if (fsFlags
& KC_INVALIDCOMP
) {
2557 // actually, not sure whether we're supposed to abort the keypress
2558 // or process it as though the dead key has been pressed.
2562 // Now we need to dispatch a keypress event which has the unicode char.
2563 // If keydown default was prevented, do same for keypress
2564 pressEvent
.message
= NS_KEY_PRESS
;
2566 pressEvent
.flags
|= NS_EVENT_FLAG_NO_DEFAULT
;
2574 nsAutoChar16Buffer outbuf
;
2576 MultiByteToWideChar(0, (const char*)inbuf
, 2, outbuf
, bufLength
);
2578 pressEvent
.charCode
= outbuf
[0];
2580 if (pressEvent
.isControl
&& !(fsFlags
& (KC_VIRTUALKEY
| KC_DEADKEY
))) {
2581 if (!pressEvent
.isShift
&& (pressEvent
.charCode
>= 'A' && pressEvent
.charCode
<= 'Z')) {
2582 pressEvent
.charCode
= tolower(pressEvent
.charCode
);
2584 if (pressEvent
.isShift
&& (pressEvent
.charCode
>= 'a' && pressEvent
.charCode
<= 'z')) {
2585 pressEvent
.charCode
= toupper(pressEvent
.charCode
);
2587 pressEvent
.keyCode
= 0;
2588 } else if (!pressEvent
.isControl
&& !pressEvent
.isAlt
&& pressEvent
.charCode
!= 0) {
2589 if (!(fsFlags
& KC_VIRTUALKEY
) || // not virtual key
2590 ((fsFlags
& KC_CHAR
) && !pressEvent
.keyCode
)) {
2591 pressEvent
.keyCode
= 0;
2592 } else if (usVKey
== VK_SPACE
) {
2593 // space key, do nothing here
2594 } else if ((fsFlags
& KC_VIRTUALKEY
) &&
2595 isNumPadScanCode(uchScan
) && pressEvent
.keyCode
!= 0 && isNumlockOn
) {
2596 // this is NumLock+Numpad (no Alt), handle this like a normal number
2597 pressEvent
.keyCode
= 0;
2598 } else { // Real virtual key
2599 pressEvent
.charCode
= 0;
2602 rc
= DispatchWindowEvent(&pressEvent
);
2608 //-----------------------------------------------------------------------------
2609 // Helper function to translate from a WM_CHAR to an NS_VK_ constant.
2612 PRUint32
WMChar2KeyCode(MPARAM mp1
, MPARAM mp2
)
2614 PRUint32 rc
= SHORT1FROMMP(mp2
); // character code
2615 PRUint32 rcmask
= rc
& 0x00FF; // masked character code for key up events
2616 USHORT sc
= CHAR4FROMMP(mp1
); // scan code
2617 USHORT flags
= SHORT1FROMMP(mp1
); // flag word
2619 // First check for characters.
2620 // This is complicated by keystrokes such as Ctrl+K not having the KC_CHAR
2621 // bit set, but thankfully they do have the character actually there.
2623 // Assume that `if not vkey or deadkey or valid number then char'
2624 if (!(flags
& (KC_VIRTUALKEY
| KC_DEADKEY
)) ||
2625 (rcmask
>= '0' && rcmask
<= '9' && // handle keys on Numpad, too,
2626 (isNumPadScanCode(sc
) ? isNumlockOn
: 1))) { // if NumLock is on
2627 if (flags
& KC_KEYUP
) { // On OS/2 the scancode is in the upper byte of
2628 // usChar when KC_KEYUP is set so mask it off
2630 } else { // not KC_KEYUP
2631 if (!(flags
& KC_CHAR
)) {
2632 if ((flags
& KC_ALT
) || (flags
& KC_CTRL
)) {
2641 if (rc
>= 'a' && rc
<= 'z') { // The DOM_VK are for upper case only so
2642 // if rc is lower case upper case it.
2643 rc
= rc
- 'a' + NS_VK_A
;
2644 } else if (rc
>= 'A' && rc
<= 'Z') { // Upper case
2645 rc
= rc
- 'A' + NS_VK_A
;
2646 } else if (rc
>= '0' && rc
<= '9') {
2647 // Number keys, including Numpad if NumLock is not set
2648 rc
= rc
- '0' + NS_VK_0
;
2650 // For some characters, map the scan code to the NS_VK value
2651 // This only happens in the char case NOT the VK case!
2653 case 0x02: rc
= NS_VK_1
; break;
2654 case 0x03: rc
= NS_VK_2
; break;
2655 case 0x04: rc
= NS_VK_3
; break;
2656 case 0x05: rc
= NS_VK_4
; break;
2657 case 0x06: rc
= NS_VK_5
; break;
2658 case 0x07: rc
= NS_VK_6
; break;
2659 case 0x08: rc
= NS_VK_7
; break;
2660 case 0x09: rc
= NS_VK_8
; break;
2661 case 0x0A: rc
= NS_VK_9
; break;
2662 case 0x0B: rc
= NS_VK_0
; break;
2663 case 0x0D: rc
= NS_VK_EQUALS
; break;
2664 case 0x1A: rc
= NS_VK_OPEN_BRACKET
; break;
2665 case 0x1B: rc
= NS_VK_CLOSE_BRACKET
; break;
2666 case 0x27: rc
= NS_VK_SEMICOLON
; break;
2667 case 0x28: rc
= NS_VK_QUOTE
; break;
2668 case 0x29: rc
= NS_VK_BACK_QUOTE
; break;
2669 case 0x2B: rc
= NS_VK_BACK_SLASH
; break;
2670 case 0x33: rc
= NS_VK_COMMA
; break;
2671 case 0x34: rc
= NS_VK_PERIOD
; break;
2672 case 0x35: rc
= NS_VK_SLASH
; break;
2673 case 0x37: rc
= NS_VK_MULTIPLY
; break;
2674 case 0x4A: rc
= NS_VK_SUBTRACT
; break;
2675 case 0x4C: rc
= NS_VK_CLEAR
; break; // numeric case is handled above
2676 case 0x4E: rc
= NS_VK_ADD
; break;
2677 case 0x5C: rc
= NS_VK_DIVIDE
; break;
2682 } else if (flags
& KC_VIRTUALKEY
) {
2683 USHORT vk
= SHORT2FROMMP(mp2
);
2684 if (flags
& KC_KEYUP
) { // On OS/2 there are extraneous bits in the upper byte of
2685 // usChar when KC_KEYUP is set so mask them off
2688 if (isNumPadScanCode(sc
) &&
2689 (((flags
& KC_ALT
) && (sc
!= PMSCAN_PADPERIOD
)) ||
2690 ((flags
& (KC_CHAR
| KC_SHIFT
)) == KC_CHAR
) ||
2691 ((flags
& KC_KEYUP
) && rc
!= 0))) {
2692 CHAR numpadMap
[] = {NS_VK_NUMPAD7
, NS_VK_NUMPAD8
, NS_VK_NUMPAD9
, 0,
2693 NS_VK_NUMPAD4
, NS_VK_NUMPAD5
, NS_VK_NUMPAD6
, 0,
2694 NS_VK_NUMPAD1
, NS_VK_NUMPAD2
, NS_VK_NUMPAD3
,
2695 NS_VK_NUMPAD0
, NS_VK_DECIMAL
};
2696 // If this is the Numpad must not return VK for ALT+Numpad or ALT+NumLock+Numpad
2697 // NumLock+Numpad is OK
2698 if (numpadMap
[sc
- PMSCAN_PAD7
] != 0) { // not plus or minus on Numpad
2699 if (flags
& KC_ALT
) { // do not react on Alt plus ASCII-code sequences
2702 rc
= numpadMap
[sc
- PMSCAN_PAD7
];
2704 } else { // plus or minus of Numpad
2705 rc
= 0; // No virtual key for Alt+Numpad or NumLock+Numpad
2707 } else if (!(flags
& KC_CHAR
) || isNumPadScanCode(sc
) ||
2708 (vk
== VK_BACKSPACE
) || (vk
== VK_TAB
) || (vk
== VK_BACKTAB
) ||
2709 (vk
== VK_ENTER
) || (vk
== VK_NEWLINE
) || (vk
== VK_SPACE
)) {
2710 if (vk
>= VK_F1
&& vk
<= VK_F24
) {
2711 rc
= NS_VK_F1
+ (vk
- VK_F1
);
2714 case VK_NUMLOCK
: rc
= NS_VK_NUM_LOCK
; break;
2715 case VK_SCRLLOCK
: rc
= NS_VK_SCROLL_LOCK
; break;
2716 case VK_ESC
: rc
= NS_VK_ESCAPE
; break; // NS_VK_CANCEL
2717 case VK_BACKSPACE
: rc
= NS_VK_BACK
; break;
2718 case VK_TAB
: rc
= NS_VK_TAB
; break;
2719 case VK_BACKTAB
: rc
= NS_VK_TAB
; break; // layout tests for isShift
2720 case VK_CLEAR
: rc
= NS_VK_CLEAR
; break;
2721 case VK_NEWLINE
: rc
= NS_VK_RETURN
; break;
2722 case VK_ENTER
: rc
= NS_VK_RETURN
; break;
2723 case VK_SHIFT
: rc
= NS_VK_SHIFT
; break;
2724 case VK_CTRL
: rc
= NS_VK_CONTROL
; break;
2725 case VK_ALT
: rc
= NS_VK_ALT
; break;
2726 case VK_PAUSE
: rc
= NS_VK_PAUSE
; break;
2727 case VK_CAPSLOCK
: rc
= NS_VK_CAPS_LOCK
; break;
2728 case VK_SPACE
: rc
= NS_VK_SPACE
; break;
2729 case VK_PAGEUP
: rc
= NS_VK_PAGE_UP
; break;
2730 case VK_PAGEDOWN
: rc
= NS_VK_PAGE_DOWN
; break;
2731 case VK_END
: rc
= NS_VK_END
; break;
2732 case VK_HOME
: rc
= NS_VK_HOME
; break;
2733 case VK_LEFT
: rc
= NS_VK_LEFT
; break;
2734 case VK_UP
: rc
= NS_VK_UP
; break;
2735 case VK_RIGHT
: rc
= NS_VK_RIGHT
; break;
2736 case VK_DOWN
: rc
= NS_VK_DOWN
; break;
2737 case VK_PRINTSCRN
: rc
= NS_VK_PRINTSCREEN
; break;
2738 case VK_INSERT
: rc
= NS_VK_INSERT
; break;
2739 case VK_DELETE
: rc
= NS_VK_DELETE
; break;
2747 //=============================================================================
2749 //=============================================================================
2751 // Initialize an event to dispatch.
2753 void nsWindow::InitEvent(nsGUIEvent
& event
, nsIntPoint
* aPoint
)
2755 // if no point was supplied, calculate it
2757 // for most events, get the message position; for drag events,
2758 // msg position may be incorrect, so get the current position instead
2760 if (CheckDragStatus(ACTION_PTRPOS
, 0)) {
2761 WinQueryPointerPos(HWND_DESKTOP
, &ptl
);
2763 WinQueryMsgPos(0, &ptl
);
2766 WinMapWindowPoints(HWND_DESKTOP
, mWnd
, &ptl
, 1);
2768 event
.refPoint
.x
= ptl
.x
;
2769 event
.refPoint
.y
= ptl
.y
;
2771 // use the point override if provided
2772 event
.refPoint
.x
= aPoint
->x
;
2773 event
.refPoint
.y
= aPoint
->y
;
2776 event
.time
= WinQueryMsgTime(0);
2780 //-----------------------------------------------------------------------------
2781 // Invoke the Event Listener object's callback.
2783 NS_IMETHODIMP
nsWindow::DispatchEvent(nsGUIEvent
* event
, nsEventStatus
& aStatus
)
2785 aStatus
= nsEventStatus_eIgnore
;
2787 if (!mEventCallback
) {
2791 // if state is eInCreate, only send out NS_CREATE
2792 // if state is eDoingDelete, don't send out anything
2793 if ((mWindowState
& nsWindowState_eLive
) ||
2794 (mWindowState
== nsWindowState_eInCreate
&& event
->message
== NS_CREATE
)) {
2795 aStatus
= (*mEventCallback
)(event
);
2800 //-----------------------------------------------------------------------------
2802 NS_IMETHODIMP
nsWindow::ReparentNativeWidget(nsIWidget
* aNewParent
)
2804 NS_PRECONDITION(aNewParent
, "");
2805 return NS_ERROR_NOT_IMPLEMENTED
;
2808 //-----------------------------------------------------------------------------
2810 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
* event
)
2812 nsEventStatus status
;
2813 DispatchEvent(event
, status
);
2814 return (status
== nsEventStatus_eConsumeNoDefault
);
2817 PRBool
nsWindow::DispatchWindowEvent(nsGUIEvent
*event
, nsEventStatus
&aStatus
) {
2818 DispatchEvent(event
, aStatus
);
2819 return (aStatus
== nsEventStatus_eConsumeNoDefault
);
2822 //-----------------------------------------------------------------------------
2824 PRBool
nsWindow::DispatchCommandEvent(PRUint32 aEventCommand
)
2826 nsCOMPtr
<nsIAtom
> command
;
2828 switch (aEventCommand
) {
2829 case APPCOMMAND_BROWSER_BACKWARD
:
2830 command
= nsWidgetAtoms::Back
;
2832 case APPCOMMAND_BROWSER_FORWARD
:
2833 command
= nsWidgetAtoms::Forward
;
2835 case APPCOMMAND_BROWSER_REFRESH
:
2836 command
= nsWidgetAtoms::Reload
;
2838 case APPCOMMAND_BROWSER_STOP
:
2839 command
= nsWidgetAtoms::Stop
;
2845 nsCommandEvent
event(PR_TRUE
, nsWidgetAtoms::onAppCommand
, command
, this);
2847 return DispatchWindowEvent(&event
);
2850 //-----------------------------------------------------------------------------
2852 PRBool
nsWindow::DispatchDragDropEvent(PRUint32 aMsg
)
2854 nsDragEvent
event(PR_TRUE
, aMsg
, this);
2857 event
.isShift
= isKeyDown(VK_SHIFT
);
2858 event
.isControl
= isKeyDown(VK_CTRL
);
2859 event
.isAlt
= isKeyDown(VK_ALT
) || isKeyDown(VK_ALTGRAF
);
2860 event
.isMeta
= PR_FALSE
;
2862 return DispatchWindowEvent(&event
);
2865 //-----------------------------------------------------------------------------
2867 PRBool
nsWindow::DispatchMoveEvent(PRInt32 aX
, PRInt32 aY
)
2869 // Params here are in XP-space for the desktop
2870 nsGUIEvent
event(PR_TRUE
, NS_MOVE
, this);
2871 nsIntPoint
point(aX
, aY
);
2872 InitEvent(event
, &point
);
2873 return DispatchWindowEvent(&event
);
2876 //-----------------------------------------------------------------------------
2878 PRBool
nsWindow::DispatchResizeEvent(PRInt32 aX
, PRInt32 aY
)
2880 nsSizeEvent
event(PR_TRUE
, NS_SIZE
, this);
2881 nsIntRect
rect(0, 0, aX
, aY
);
2884 event
.windowSize
= &rect
; // this is the *client* rectangle
2885 event
.mWinWidth
= mBounds
.width
;
2886 event
.mWinHeight
= mBounds
.height
;
2888 return DispatchWindowEvent(&event
);
2891 //-----------------------------------------------------------------------------
2892 // Deal with all sorts of mouse events.
2894 PRBool
nsWindow::DispatchMouseEvent(PRUint32 aEventType
, MPARAM mp1
, MPARAM mp2
,
2895 PRBool aIsContextMenuKey
, PRInt16 aButton
)
2897 NS_ENSURE_TRUE(aEventType
, PR_FALSE
);
2899 nsMouseEvent
event(PR_TRUE
, aEventType
, this, nsMouseEvent::eReal
,
2901 ? nsMouseEvent::eContextMenuKey
2902 : nsMouseEvent::eNormal
);
2903 event
.button
= aButton
;
2905 if (aEventType
== NS_MOUSE_ENTER
|| aEventType
== NS_MOUSE_EXIT
) {
2906 // Ignore enter/leave msgs forwarded from the frame to FID_CLIENT
2907 // because we're only interested msgs involving the content area.
2908 if (HWNDFROMMP(mp1
) != mWnd
) {
2912 // If the mouse has exited the content area and entered either an
2913 // unrelated window or what Windows would call the nonclient area
2914 // (i.e. frame, titlebar, etc.), mark this as a toplevel exit.
2915 // Note: exits to and from menus will also be marked toplevel.
2916 if (aEventType
== NS_MOUSE_EXIT
) {
2919 HWND hDesk
= WinQueryDesktopWindow(0, 0);
2920 while (hCur
&& hCur
!= hDesk
) {
2922 hCur
= WinQueryWindow(hCur
, QW_PARENT
);
2925 // event.exit was init'ed to eChild, so we don't need an 'else'
2926 hTop
= WinWindowFromID(hTop
, FID_CLIENT
);
2927 if (!hTop
|| !WinIsChild(HWNDFROMMP(mp2
), hTop
)) {
2928 event
.exit
= nsMouseEvent::eTopLevel
;
2932 InitEvent(event
, nsnull
);
2933 event
.isShift
= isKeyDown(VK_SHIFT
);
2934 event
.isControl
= isKeyDown(VK_CTRL
);
2935 event
.isAlt
= isKeyDown(VK_ALT
) || isKeyDown(VK_ALTGRAF
);
2938 if (aEventType
== NS_CONTEXTMENU
&& aIsContextMenuKey
) {
2939 WinQueryPointerPos(HWND_DESKTOP
, &ptl
);
2940 WinMapWindowPoints(HWND_DESKTOP
, mWnd
, &ptl
, 1);
2942 ptl
.x
= (SHORT
)SHORT1FROMMP(mp1
);
2943 ptl
.y
= (SHORT
)SHORT2FROMMP(mp1
);
2946 nsIntPoint
pt(ptl
.x
, ptl
.y
);
2947 InitEvent(event
, &pt
);
2949 USHORT usFlags
= SHORT2FROMMP(mp2
);
2950 event
.isShift
= (usFlags
& KC_SHIFT
) ? PR_TRUE
: PR_FALSE
;
2951 event
.isControl
= (usFlags
& KC_CTRL
) ? PR_TRUE
: PR_FALSE
;
2952 event
.isAlt
= (usFlags
& KC_ALT
) ? PR_TRUE
: PR_FALSE
;
2954 event
.isMeta
= PR_FALSE
;
2956 // Dblclicks are used to set the click count, then changed to mousedowns
2957 if (aEventType
== NS_MOUSE_DOUBLECLICK
&&
2958 (aButton
== nsMouseEvent::eLeftButton
||
2959 aButton
== nsMouseEvent::eRightButton
)) {
2960 event
.message
= NS_MOUSE_BUTTON_DOWN
;
2961 event
.button
= (aButton
== nsMouseEvent::eLeftButton
) ?
2962 nsMouseEvent::eLeftButton
: nsMouseEvent::eRightButton
;
2963 event
.clickCount
= 2;
2965 event
.clickCount
= 1;
2968 NPEvent pluginEvent
;
2969 switch (aEventType
) {
2971 case NS_MOUSE_BUTTON_DOWN
:
2973 case nsMouseEvent::eLeftButton
:
2974 pluginEvent
.event
= WM_BUTTON1DOWN
;
2976 case nsMouseEvent::eMiddleButton
:
2977 pluginEvent
.event
= WM_BUTTON3DOWN
;
2979 case nsMouseEvent::eRightButton
:
2980 pluginEvent
.event
= WM_BUTTON2DOWN
;
2987 case NS_MOUSE_BUTTON_UP
:
2989 case nsMouseEvent::eLeftButton
:
2990 pluginEvent
.event
= WM_BUTTON1UP
;
2992 case nsMouseEvent::eMiddleButton
:
2993 pluginEvent
.event
= WM_BUTTON3UP
;
2995 case nsMouseEvent::eRightButton
:
2996 pluginEvent
.event
= WM_BUTTON2UP
;
3003 case NS_MOUSE_DOUBLECLICK
:
3005 case nsMouseEvent::eLeftButton
:
3006 pluginEvent
.event
= WM_BUTTON1DBLCLK
;
3008 case nsMouseEvent::eMiddleButton
:
3009 pluginEvent
.event
= WM_BUTTON3DBLCLK
;
3011 case nsMouseEvent::eRightButton
:
3012 pluginEvent
.event
= WM_BUTTON2DBLCLK
;
3020 pluginEvent
.event
= WM_MOUSEMOVE
;
3024 pluginEvent
.wParam
= 0;
3025 pluginEvent
.lParam
= MAKELONG(event
.refPoint
.x
, event
.refPoint
.y
);
3027 event
.pluginEvent
= (void*)&pluginEvent
;
3029 return DispatchWindowEvent(&event
);
3032 //-----------------------------------------------------------------------------
3033 // Signal plugin & top-level window activation.
3035 PRBool
nsWindow::DispatchActivationEvent(PRUint32 aEventType
)
3037 nsGUIEvent
event(PR_TRUE
, aEventType
, this);
3039 // These events should go to their base widget location,
3040 // not current mouse position.
3041 nsIntPoint
point(0, 0);
3042 InitEvent(event
, &point
);
3044 NPEvent pluginEvent
;
3045 switch (aEventType
) {
3047 pluginEvent
.event
= WM_SETFOCUS
;
3050 pluginEvent
.event
= WM_FOCUSCHANGED
;
3052 case NS_PLUGIN_ACTIVATE
:
3053 pluginEvent
.event
= WM_FOCUSCHANGED
;
3056 event
.pluginEvent
= (void*)&pluginEvent
;
3058 return DispatchWindowEvent(&event
);
3061 //-----------------------------------------------------------------------------
3063 PRBool
nsWindow::DispatchScrollEvent(ULONG msg
, MPARAM mp1
, MPARAM mp2
)
3065 nsMouseScrollEvent
scrollEvent(PR_TRUE
, NS_MOUSE_SCROLL
, this);
3066 InitEvent(scrollEvent
);
3068 scrollEvent
.isShift
= isKeyDown(VK_SHIFT
);
3069 scrollEvent
.isControl
= isKeyDown(VK_CTRL
);
3070 scrollEvent
.isAlt
= isKeyDown(VK_ALT
) || isKeyDown(VK_ALTGRAF
);
3071 scrollEvent
.isMeta
= PR_FALSE
;
3072 scrollEvent
.scrollFlags
= (msg
== WM_HSCROLL
) ?
3073 nsMouseScrollEvent::kIsHorizontal
:
3074 nsMouseScrollEvent::kIsVertical
;
3076 // The SB_* constants for analogous vertical & horizontal ops have the
3077 // the same values, so only use the verticals to avoid compiler errors.
3078 switch (SHORT2FROMMP(mp2
)) {
3081 scrollEvent
.delta
= -1;
3086 scrollEvent
.delta
= 1;
3091 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
3092 scrollEvent
.delta
= -1;
3097 scrollEvent
.scrollFlags
|= nsMouseScrollEvent::kIsFullPage
;
3098 scrollEvent
.delta
= 1;
3102 scrollEvent
.delta
= 0;
3105 DispatchWindowEvent(&scrollEvent
);
3110 //=============================================================================