/* * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The Original Code is the Mozilla OS/2 libraries. * * The Initial Developer of the Original Code is John Fairhurst, * . Portions created by John Fairhurst are * Copyright (C) 1999 John Fairhurst. All Rights Reserved. * * Contributor(s): * Pierre Phaneuf * * This Original Code has been modified by IBM Corporation. * Modifications made by IBM described herein are * Copyright (c) International Business Machines * Corporation, 2000 * * Modifications to Mozilla code or documentation * identified per MPL Section 3.3 * * Date Modified by Description of modification * 03/23/2000 IBM Corp. Added InvalidateRegion method; keyboard (OnKey) handling; and * fixed uninitialized event.isMeta. * 04/12/2000 IBM Corp. DispatchMouseEvent changes. * 04/14/2000 IBM Corp. Ported CaptureRollupEvents changes from Windows. * 06/09/2000 IBM Corp. Added cases for more cursors in SetCursor. * 06/14/2000 IBM Corp. Removed dead menu code to fix build break. * 06/15/2000 IBM Corp. Created NS2PM for rectangles. * 06/21/2000 IBM Corp. Corrected menu parentage; added CaptureMouse. * 06/22/2000 IBM Corp. Corrected menu ownership * */ #include "nsWindow.h" #include "nsIAppShell.h" #include "nsIFontMetrics.h" #include "nsGUIEvent.h" #include "nsIRenderingContext.h" #include "nsIDeviceContext.h" #include "nsTransform2D.h" #include "nsGfxCIID.h" #include "prtime.h" #include "nsFont.h" // #include "nsTooltipManager.h" #include "nsISupportsArray.h" #include "nsITimer.h" #include "nsIMenuBar.h" //#include "nsIMenuItem.h" #include "nsHashtable.h" //#include "nsMenu.h" #include "nsDragService.h" //#include "nsContextMenu.h" #include "nsIRollupListener.h" #include "nsIRegion.h" //~~~ windowless plugin support #include "nsplugindefs.h" #include "tabapi.h" // !! TAB-FIX #include #include #include #ifdef DEBUG_sobotka static int WINDOWCOUNT = 0; #endif // HWNDs are mapped to nsWindow objects using a custom presentation parameter, // which is registered in nsModule -- thanks to Cindy Ross for explaining how // to do this. // // The subclass proc (fnwpNSWindow) calls ProcessMessage() in the object. // Decisions are taken here about what to do - the purpose of the OnFoo() // methods is to generate an NS event to the various people who are // listening, or not. // // OS/2 things: remember supplied coords are in the XP space. There are // NS2PM methods for conversion of points & rectangles; position is a bit // different in that it's the *parent* window whose height must be used. // // Deferred window positioning is emulated using WinSetMultWindowPos in // the hopes that there was a good reason for adding it to nsIWidget. // // SetColorSpace() is not implemented on purpose. So there. // // John Fairhurst 17-09-98 first version // Revised 01-12-98 to inherit from nsBaseWidget. // Revised 24-01-99 to use hashtable // Revised 15-03-99 for new menu classes // Revised 05-06-99 to use pres-params // Revised 19-06-99 drag'n'drop, etc. // XXX don't deliver click-events to obscured parents BOOL g_bHandlingMouseClick = FALSE; nsWindow* nsWindow::gCurrentWindow = nsnull; nsIRollupListener * gRollupListener = nsnull; nsIWidget * gRollupWidget = nsnull; PRBool gRollupConsumeRollupEvent = PR_FALSE; // -------------------------------------------------------------------------- // HWND -> (nsWindow *) conversion ------------------------------------------ nsWindow *NS_HWNDToWindow( HWND hwnd) { nsWindow *pWnd = nsnull; WinQueryPresParam( hwnd, gModuleData.ppMozilla, 0, NULL, sizeof pWnd, &pWnd, QPF_NOINHERIT); return pWnd; } // -------------------------------------------------------------------------- // NSWindow create / destroy ------------------------------------------------ nsWindow::nsWindow() : nsBaseWidget() { NS_INIT_REFCNT(); mWnd = 0; mFnWP = 0; mParent = 0; mNextID = 1; mNextCmdID = 1; mSWPs = 0; mlHave = 0; mlUsed = 0; mPointer = 0; mPS = 0; mPSRefs = 0; mDragInside = FALSE; mDeadKey = 0; mHaveDeadKey = FALSE; // This is so that frame windows can be destroyed from their destructors. mHackDestroyWnd = 0; mPreferredWidth = 0; mPreferredHeight = 0; mWindowState = nsWindowState_ePrecreate; mFont = nsnull; mOS2Toolkit = nsnull; mMenuBar = nsnull; // mActiveMenu = nsnull; } // Do a little work in both create methods & call on to a common DoCreate() nsresult nsWindow::Create( nsIWidget *aParent, const nsRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsIDeviceContext *aContext, nsIAppShell *aAppShell, nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { HWND hwndP = aParent ? (HWND)aParent->GetNativeData( NS_NATIVE_WINDOW) : HWND_DESKTOP; DoCreate( hwndP, (nsWindow*) aParent, aRect, aHandleEventFunction, aContext, aAppShell, aToolkit, aInitData); return NS_OK; } nsresult nsWindow::Create( nsNativeWidget aParent, const nsRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsIDeviceContext *aContext, nsIAppShell *aAppShell, nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { // We need to find the nsWindow that goes with the native window, or controls // all get the ID of 0, and a zillion toolkits get created. // nsWindow *pParent = nsnull; HWND hwndP = (HWND) aParent; if( hwndP && hwndP != HWND_DESKTOP) pParent = NS_HWNDToWindow( hwndP); // XXX WC_MOZILLA will probably need a change here // if( !hwndP) hwndP = HWND_DESKTOP; DoCreate( hwndP, pParent, aRect, aHandleEventFunction, aContext, aAppShell, aToolkit, aInitData); return NS_OK; } void nsWindow::DoCreate( HWND hwndP, nsWindow *aParent, const nsRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsIDeviceContext *aContext, nsIAppShell *aAppShell, nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { mWindowState = nsWindowState_eInCreate; // Must ensure toolkit before attempting to thread-switch! if( !mToolkit) { if( aToolkit) { mToolkit = aToolkit; NS_ADDREF(mToolkit); } else if( aParent) mToolkit = aParent->GetToolkit(); else { // it's some top level window with no toolkit passed in. // Create a default toolkit with the current thread mToolkit = new nsToolkit; NS_ADDREF(mToolkit); mToolkit->Init( PR_GetCurrentThread()); } mOS2Toolkit = (nsToolkit*) mToolkit; } // Switch to the PM thread if necessary... if( !mOS2Toolkit->IsPMThread()) { ULONG args[7] = { hwndP, (ULONG) aParent, (ULONG) &aRect, (ULONG) aHandleEventFunction, (ULONG) aContext, (ULONG) aAppShell, (ULONG) aInitData }; MethodInfo info( this, nsWindow::W_CREATE, 7, args); mOS2Toolkit->CallMethod( &info); } else // This is potentially virtual; overridden in nsFrameWindow RealDoCreate( hwndP, aParent, aRect, aHandleEventFunction, aContext, aAppShell, aInitData); mWindowState = nsWindowState_eLive; } void nsWindow::RealDoCreate( HWND hwndP, nsWindow *aParent, const nsRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsIDeviceContext *aContext, nsIAppShell *aAppShell, nsWidgetInitData *aInitData, HWND hwndOwner) { // XXXX TEST HACK to get rid of window bunnies // if (!(aRect.height > 1) && !(aRect.width > 1)) // return; // Set up parent data - don't addref to avoid circularity mParent = aParent; // Set up window style: first give subclass a chance to prepare if( aInitData) PreCreateWidget( aInitData); ULONG style = WindowStyle(); if( aInitData) { if( aInitData->clipChildren) style |= WS_CLIPCHILDREN; #if 0 // // Windows has a slightly different idea of what the implications are // of a window having or not having the CLIPSIBLINGS style. // All 'canvas' components we create must have clipsiblings, or // strange things happen & performance actually degrades. // else style &= ~WS_CLIPCHILDREN; #endif if( aInitData->clipSiblings) style |= WS_CLIPSIBLINGS; else style &= ~WS_CLIPSIBLINGS; } // For pop-up menus, the parent is the desktop, but use the "parent" as owner if( hwndP != HWND_DESKTOP && aInitData && aInitData->mWindowType == eWindowType_popup) { if( !hwndOwner) { hwndOwner = hwndP; } hwndP = HWND_DESKTOP; } // Create a window: create hidden & then size to avoid swp_noadjust problems // owner == parent except for 'borderless top-level' -- see nsCanvas.cpp mWnd = WinCreateWindow( hwndP, WindowClass(), 0, // text style, 0, 0, 0, 0, // pos/size hwndOwner ? hwndOwner : hwndP, HWND_TOP, mParent ? mParent->GetNextID() : 0, 0, 0); // ctldata, presparams NS_ASSERTION( mWnd, "Couldn't create window"); #if DEBUG_sobotka printf("\n+++++++++++In nsWindow::RealDoCreate created 0x%lx, %d x %d\n", mWnd, aRect.width, aRect.height); printf("+++++++++++Location = %d x %d\n", aRect.x, aRect.y); printf("+++++++++++Parent = 0x%lx\n", GetParentHWND()); printf("+++++++++++WINDOWCOUNT+ = %d\n", ++WINDOWCOUNT); #endif // Make sure we have a device context from somewhere if( aContext) { mContext = aContext; NS_ADDREF(mContext); } else { nsresult rc = NS_OK; static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID); rc = nsComponentManager::CreateInstance( kDeviceContextCID, nsnull, NS_GET_IID(nsIDeviceContext), (void **)&mContext); if( NS_SUCCEEDED(rc)) mContext->Init( (nsNativeWidget) mWnd); #ifdef DEBUG else printf( "Couldn't find DC instance for nsWindow\n"); #endif } WinSetPresParam( mWnd, PP_FONTNAMESIZE, strlen( gModuleData.pszFontNameSize) + 1, gModuleData.pszFontNameSize); Resize( aRect.x, aRect.y, aRect.width, aRect.height, PR_FALSE); // Record bounds. This is XP, the rect of the entire main window in // parent space. Returned by GetBounds(). // NB: We haven't subclassed yet, so callbacks to change mBounds won't // have happened! mBounds = aRect; mBounds.height = GetHeight( aRect.height); // Record passed in things mAppShell = aAppShell; // NS_IF_ADDREF( mAppShell); GetAppShell(); // Let the base widget class update the refcount for us.... mEventCallback = aHandleEventFunction; if( mParent) mParent->AddChild( this); // call the event callback to notify about creation DispatchStandardEvent( NS_CREATE); SubclassWindow( PR_TRUE); PostCreateWidget(); } // How destruction works: A call of Destroy() destroys the PM window. This // triggers an OnDestroy(), which frees resources. If not Destroy'd at // delete time, Destroy() gets called anyway. // NOTE: Calling virtual functions from destructors is bad; they always bind // in the current object (ie. as if they weren't virtual). It may even // be illegal to call them from here. // nsWindow::~nsWindow() { if (gCurrentWindow == this) { gCurrentWindow = nsnull; } // If the widget was released without calling Destroy() then the native // window still exists, and we need to destroy it. if( mWindowState != nsWindowState_eDead) { mWindowState = nsWindowState_eDoingDelete; if( mWnd); Destroy(); } } // Close this nsWindow nsresult nsWindow::Destroy() { // Switch to the PM thread if necessary... if( mToolkit && !mOS2Toolkit->IsPMThread()) { MethodInfo info( this, nsWindow::W_DESTROY); mOS2Toolkit->CallMethod( &info); } else { #if DEBUG_sobotka printf("\n++++++++++nsWindow::Destroy trashing 0x%lx\n\n", mHackDestroyWnd ? mHackDestroyWnd : mWnd); printf("+++++++++++WINDOWCOUNT- = %d\n\n", --WINDOWCOUNT); #endif // avoid calling into other objects if we're being deleted, 'cos // they must have no references to us. if( mWindowState == nsWindowState_eLive && mParent) nsBaseWidget::Destroy(); if( mWnd) WinDestroyWindow( mHackDestroyWnd ? mHackDestroyWnd : mWnd); } return NS_OK; } // WM_DESTROY has been received void nsWindow::OnDestroy() { SubclassWindow( PR_FALSE); mWnd = 0; // if we were in the middle of deferred window positioning then free up if( mSWPs) free( mSWPs); mSWPs = 0; mlHave = mlUsed = 0; // release any ps (erm, probably an error if this is necessary) if( mPS) WinReleasePS( mPS); mPS = 0; // release references to context, toolkit, appshell, children nsBaseWidget::OnDestroy(); // kill font delete mFont; // release menubar // NS_IF_RELEASE(mMenuBar); // dispatching of the event may cause the reference count to drop to 0 // and result in this object being deleted. To avoid that, add a // reference and then release it after dispatching the event. // // It's important *not* to do this if we're being called from the // destructor -- this would result in our destructor being called *again* // from the Release() below. This is very bad... if( nsWindowState_eDoingDelete != mWindowState) { AddRef(); DispatchStandardEvent( NS_DESTROY); Release(); } // dead widget mWindowState = nsWindowState_eDead; } PRBool nsWindow::EventIsInsideWindow(nsWindow* aWindow) { RECTL r; POINTL ptl; if (WinQueryMsgPos( 0/*hab*/, &ptl)) { WinMapWindowPoints( HWND_DESKTOP, aWindow->mWnd, &ptl, 1); WinQueryWindowRect( aWindow->mWnd, &r); // now make sure that it wasn't one of our children if (ptl.x < r.xLeft || ptl.x > r.xRight || ptl.y > r.yTop || ptl.y < r.yBottom) { return PR_FALSE; } } return PR_TRUE; } NS_METHOD nsWindow::CaptureMouse(PRBool aCapture) { if (PR_TRUE == aCapture) { WinSetCapture( HWND_DESKTOP, mWnd); } else { WinSetCapture( HWND_DESKTOP, NULLHANDLE); } // mIsInMouseCapture = aCapture; return NS_OK; } // -------------------------------------------------------------------------- // PM messaging layer - wndproc, subclasser, default handler ---------------- // the nsWindow procedure for all nsWindows in this toolkit MRESULT EXPENTRY fnwpNSWindow( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { #if DEBUG_sobotka if (msg == WM_BUTTON1DOWN || msg == WM_BUTTON1DBLCLK) printf("\n++++++++++fnwpNSWindow processing click for 0x%lx <-------CLICK\n", hwnd); #endif // Get the nsWindow for this hwnd nsWindow *wnd = NS_HWNDToWindow( hwnd); // check to see if we have a rollup listener registered if (nsnull != gRollupListener && nsnull != gRollupWidget) { if (msg == WM_ACTIVATE || msg == WM_BUTTON1DOWN || msg == WM_BUTTON2DOWN || msg == WM_BUTTON3DOWN) { // Rollup if the event is outside the popup if (PR_FALSE == nsWindow::EventIsInsideWindow((nsWindow*)gRollupWidget)) { gRollupListener->Rollup(); // if we are supposed to be consuming events and it is // a Mouse Button down, let it go through // if (gRollupConsumeRollupEvent && msg != WM_BUTTON1DOWN) { // return FALSE; // } } } else if (msg == WM_SETFOCUS) { if (!mp2 && hwnd != WinQueryWindow((HWND)mp1, QW_OWNER)) { gRollupListener->Rollup(); } } } // Messages which get re-routed if their source was an nsWindow // (it's very bad to reroute messages whose source isn't an nsWindow, // listboxes with scrollbars for example would break) switch( msg) { case WM_CONTROL: case WM_HSCROLL: case WM_VSCROLL: // !! potential problems here if canvas children { // assume parent == owner, true for our creations HWND hwndChild = WinWindowFromID( hwnd, SHORT1FROMMP( mp1)); if( hwndChild) { nsWindow *w = NS_HWNDToWindow( hwndChild); if( w) wnd = w; } break; } } MRESULT mRC = 0; if( wnd) { BOOL bPreHandling = g_bHandlingMouseClick; if( PR_FALSE == wnd->ProcessMessage( msg, mp1, mp2, mRC) && wnd->GetPrevWP()) { mRC = (wnd->GetPrevWP())( hwnd, msg, mp1, mp2); } if( !bPreHandling) g_bHandlingMouseClick = FALSE; } else /* erm */ mRC = WinDefWindowProc( hwnd, msg, mp1, mp2); return mRC; } // Subclass (or remove the subclass) void nsWindow::SubclassWindow( PRBool bState) { NS_PRECONDITION(WinIsWindow( 0/*hab*/, mWnd), "Invalid window handle"); if( PR_TRUE == bState) { mFnWP = WinSubclassWindow( mWnd, fnwpNSWindow); // connect the this pointer to the window handle nsWindow *pWin = this; // learn something new about C++ every day... WinSetPresParam( mWnd, gModuleData.ppMozilla, sizeof pWin, &pWin); } else { WinSubclassWindow( mWnd, mFnWP); WinRemovePresParam( mWnd, gModuleData.ppMozilla); mFnWP = nsnull; } } // 'Window procedure' PRBool nsWindow::ProcessMessage( ULONG msg, MPARAM mp1, MPARAM mp2, MRESULT &rc) { PRBool result = PR_FALSE; // call the default window procedure switch( msg) { #if 0 case WM_COMMAND: // fire off menu selections { USHORT usSrc = SHORT1FROMMP( mp2); if( usSrc == CMDSRC_MENU || usSrc == CMDSRC_ACCELERATOR) result = OnMenuClick( SHORT1FROMMP(mp1)); break; } case WM_INITMENU: result = OnActivateMenu( HWNDFROMMP(mp2), TRUE); break; case WM_MENUEND: result = OnActivateMenu( HWNDFROMMP(mp2), FALSE); break; #endif #if 0 // Tooltips appear to be gone case WMU_SHOW_TOOLTIP: { nsTooltipEvent event; InitEvent( event, NS_SHOW_TOOLTIP); event.tipIndex = LONGFROMMP(mp1); event.eventStructType = NS_TOOLTIP_EVENT; result = DispatchEventInternal(&event); // NS_RELEASE(event.widget); break; } case WMU_HIDE_TOOLTIP: result = DispatchStandardEvent( NS_HIDE_TOOLTIP); break; #endif case WM_CONTROL: // remember this is resent to the orginator... result = OnControl( mp1, mp2); break; case WM_HSCROLL: case WM_VSCROLL: result = OnScroll( mp1, mp2); break; case WM_DESTROY: // clean up object OnDestroy(); break; case WM_CLOSE: { // for now... eventually there'll be an nsIFrameWindow which will // generate 'close' events which will be veto-able. Hopefully. // (that'll be `re-write the hierarchy' time for us...) Destroy(); result = PR_TRUE; break; } case WM_PAINT: result = OnPaint(); break; case WM_CHAR: result = OnKey( mp1, mp2); break; // Mouseclicks: we don't dispatch CLICK events because they just cause // trouble: gecko seems to expect EITHER buttondown/up OR click events // and so that's what we give it. // // Plus we make WM_CHORD do a button3down in order to get warp-4 paste // behaviour (see nsEditorEventListeners.cpp) case WM_BUTTON1DOWN: result = DispatchMouseEvent( NS_MOUSE_LEFT_BUTTON_DOWN, mp1, mp2); break; case WM_BUTTON1UP: result = DispatchMouseEvent( NS_MOUSE_LEFT_BUTTON_UP, mp1, mp2); break; case WM_BUTTON1DBLCLK: result = DispatchMouseEvent( NS_MOUSE_LEFT_DOUBLECLICK, mp1, mp2); break; case WM_BUTTON2DOWN: result = DispatchMouseEvent( NS_MOUSE_RIGHT_BUTTON_DOWN, mp1, mp2); break; case WM_BUTTON2UP: result = DispatchMouseEvent( NS_MOUSE_RIGHT_BUTTON_UP, mp1, mp2); break; case WM_BUTTON2DBLCLK: result = DispatchMouseEvent( NS_MOUSE_RIGHT_DOUBLECLICK, mp1, mp2); break; case WM_CHORD: result = DispatchMouseEvent( 0, mp1, mp2); break; case WM_BUTTON3DOWN: result = DispatchMouseEvent( NS_MOUSE_MIDDLE_BUTTON_DOWN, mp1, mp2); break; case WM_BUTTON3UP: result = DispatchMouseEvent( NS_MOUSE_MIDDLE_BUTTON_UP, mp1, mp2); break; case WM_BUTTON3DBLCLK: result = DispatchMouseEvent( NS_MOUSE_MIDDLE_DOUBLECLICK, mp1, mp2); break; case WM_MOUSEMOVE: result = DispatchMouseEvent( NS_MOUSE_MOVE, mp1, mp2); break; case WMU_MOUSEENTER: result = DispatchMouseEvent( NS_MOUSE_ENTER, mp1, mp2); break; case WMU_MOUSELEAVE: result = DispatchMouseEvent( NS_MOUSE_EXIT, mp1, mp2); break; case WM_SETFOCUS: result = DispatchStandardEvent( SHORT1FROMMP( mp2) ? NS_GOTFOCUS : NS_LOSTFOCUS); break; case WM_WINDOWPOSCHANGED: result = OnReposition( (PSWP) mp1); break; case WM_REALIZEPALETTE: // hopefully only nsCanvas & nsFrame result = OnRealizePalette(); // will need this break; case WM_PRESPARAMCHANGED: // This is really for font-change notifies. Do that first. rc = GetPrevWP()( mWnd, msg, mp1, mp2); OnPresParamChanged( mp1, mp2); result = PR_TRUE; break; case DM_DRAGOVER: result = OnDragOver( mp1, mp2, rc); break; case DM_DRAGLEAVE: result = OnDragLeave( mp1, mp2); break; case DM_DROP: result = OnDrop( mp1, mp2); break; // Need to handle this method in order to keep track of whether there // is a drag inside the window; we need to do *this* so that we can // generate DRAGENTER messages [which os/2 doesn't provide]. case DM_DROPHELP: mDragInside = FALSE; break; } return result; } // -------------------------------------------------------------------------- // Local methods to dispatch NS events -------------------------------------- // Convert nsEventStatus value to a ProcessEvents() return code PRBool nsWindow::ConvertStatus( nsEventStatus aStatus) { PRBool rc = PR_FALSE; switch( aStatus) { case nsEventStatus_eIgnore: case nsEventStatus_eConsumeDoDefault: break; case nsEventStatus_eConsumeNoDefault: rc = PR_TRUE; break; default: NS_ASSERTION(0, "Illegal nsEventStatus enumeration value"); break; } return rc; } //------------------------------------------------------------------------- // // Initialize an event to dispatch // //------------------------------------------------------------------------- void nsWindow::InitEvent( nsGUIEvent &event, PRUint32 aEventType, nsPoint * aPoint) { event.widget = this; // OS2TODO NS_ADDREF(event.widget); event.nativeMsg = nsnull; if (nsnull == aPoint) // use the point from the event { // get the message position in client coordinates POINTL ptl; WinQueryMsgPos( 0/*hab*/, &ptl); WinMapWindowPoints( HWND_DESKTOP, mWnd, &ptl, 1); #if 0 printf("++++++++++nsWindow::InitEvent (!pt) mapped point = %ld, %ld\n", ptl.x, ptl.y); #endif PM2NS( ptl); event.point.x = ptl.x; event.point.y = ptl.y; #if 0 printf("++++++++++nsWindow::InitEvent (!pt) converted point = %ld, %ld\n", ptl.x, ptl.y); #endif } else { // use the point override if provided event.point.x = aPoint->x; event.point.y = aPoint->y; #if 0 printf("++++++++++nsWindow::InitEvent point = %ld, %ld\n", aPoint->x, aPoint->y); #endif } event.time = WinQueryMsgTime( 0/*hab*/); event.message = aEventType; /* OS2TODO mLastPoint.x = event.point.x; mLastPoint.y = event.point.y; */ } // Invokes callback and ProcessEvent method on Event Listener object PRBool nsWindow::DispatchEventInternal( nsGUIEvent *event) { PRBool result = PR_FALSE; nsEventStatus status; DispatchEvent( event, status); result = ConvertStatus( status); return result; } // NOTE that this is now part of the nsIWidget interface... NS_IMETHODIMP nsWindow::DispatchEvent( nsGUIEvent *event, nsEventStatus &aStatus) { #if defined(TRACE_EVENTS) && defined(DEBUG_sobotka) DebugPrintEvent(*event, mWnd); #endif aStatus = nsEventStatus_eIgnore; // Filters: if state is eInCreate, only send out NS_CREATE // if state is eDoingDelete, don't send out anything because, // well, the object's being deleted... if( (mWindowState == nsWindowState_eInCreate && event->message == NS_CREATE) || (mWindowState == nsWindowState_eLive)) { if( mEventCallback) aStatus = (*mEventCallback)( event); // Dispatch to event listener if event was not consumed if( (aStatus != nsEventStatus_eIgnore) && mEventListener) aStatus = mEventListener->ProcessEvent(*event); } return NS_OK; } // Dispatch a standard event PRBool nsWindow::DispatchStandardEvent( PRUint32 aMsg, PRUint8 aEST) { PRBool result; nsGUIEvent event; event.eventStructType = aEST; InitEvent( event, aMsg); result = DispatchEventInternal( &event); // NS_RELEASE(event.widget); return result; } //------------------------------------------------------------------------- // // Deal with all sort of mouse event // //------------------------------------------------------------------------- PRBool nsWindow::DispatchMouseEvent( PRUint32 aEventType, MPARAM mp1, MPARAM mp2) { PRBool result = PR_FALSE; if (nsnull == mEventCallback && nsnull == mMouseListener) { return result; } nsMouseEvent event; // Stop multiple messages for the same PM action if( g_bHandlingMouseClick) return result; // Mouse leave & enter messages don't seem to have position built in. if( aEventType && aEventType != NS_MOUSE_ENTER && aEventType != NS_MOUSE_EXIT) { POINTL ptl = { SHORT1FROMMP( mp1), SHORT2FROMMP( mp1) }; PM2NS( ptl); nsPoint pt( ptl.x, ptl.y); InitEvent( event, aEventType, &pt); USHORT usFlags = SHORT2FROMMP( mp2); event.isShift = (usFlags & KC_SHIFT) ? PR_TRUE : PR_FALSE; event.isControl = (usFlags & KC_CTRL) ? PR_TRUE : PR_FALSE; event.isAlt = (usFlags & KC_ALT) ? PR_TRUE : PR_FALSE; } else { if( !aEventType) aEventType = NS_MOUSE_MIDDLE_BUTTON_DOWN; // WM_CHORD hack InitEvent( event, aEventType, nsnull); event.isShift = WinIsKeyDown( VK_SHIFT); event.isControl = WinIsKeyDown( VK_CTRL); event.isAlt = WinIsKeyDown( VK_ALT) || WinIsKeyDown( VK_ALTGRAF); } event.isMeta = PR_FALSE; event.eventStructType = NS_MOUSE_EVENT; //Dblclicks are used to set the click count, then changed to mousedowns if (aEventType == NS_MOUSE_LEFT_DOUBLECLICK || aEventType == NS_MOUSE_RIGHT_DOUBLECLICK) { event.message = (aEventType == NS_MOUSE_LEFT_DOUBLECLICK) ? NS_MOUSE_LEFT_BUTTON_DOWN : NS_MOUSE_RIGHT_BUTTON_DOWN; event.clickCount = 2; } else { event.clickCount = 1; } nsPluginEvent pluginEvent; switch (aEventType)//~~~ { case NS_MOUSE_LEFT_BUTTON_DOWN: pluginEvent.event = WM_BUTTON1DOWN; break; case NS_MOUSE_LEFT_BUTTON_UP: pluginEvent.event = WM_BUTTON1UP; break; case NS_MOUSE_LEFT_DOUBLECLICK: pluginEvent.event = WM_BUTTON1DBLCLK; break; case NS_MOUSE_RIGHT_BUTTON_DOWN: pluginEvent.event = WM_BUTTON2DOWN; break; case NS_MOUSE_RIGHT_BUTTON_UP: pluginEvent.event = WM_BUTTON2UP; break; case NS_MOUSE_RIGHT_DOUBLECLICK: pluginEvent.event = WM_BUTTON2DBLCLK; break; case NS_MOUSE_MIDDLE_BUTTON_DOWN: pluginEvent.event = WM_BUTTON3DOWN; break; case NS_MOUSE_MIDDLE_BUTTON_UP: pluginEvent.event = WM_BUTTON3UP; break; case NS_MOUSE_MIDDLE_DOUBLECLICK: pluginEvent.event = WM_BUTTON3DBLCLK; break; case NS_MOUSE_MOVE: pluginEvent.event = WM_MOUSEMOVE; break; default: break; } pluginEvent.wParam = 0; /* OS2TODO pluginEvent.wParam |= (event.isShift) ? MK_SHIFT : 0; pluginEvent.wParam |= (event.isControl) ? MK_CONTROL : 0; */ pluginEvent.lParam = MAKELONG(event.point.x, event.point.y); event.nativeMsg = (void *)&pluginEvent; // call the event callback if (nsnull != mEventCallback) { // result = DispatchWindowEvent(&event); result = DispatchEventInternal(&event); // OS2TODO change to DispatchWindowEvent #if 0 // OS2TODO if (aEventType == NS_MOUSE_MOVE) { // if we are not in mouse capture mode (mouse down and hold) // then use "this" window // if we are in mouse capture, then all events are being directed // back to the nsWindow doing the capture. So therefore, the detection // of whether we are in a new nsWindow is wrong. Meaning this MOUSE_MOVE // event hold the captured windows pointer not the one the mouse is over. // // So we use "WindowFromPoint" to find what window we are over and // set that window into the mouse trailer timer. if (!mIsInMouseCapture) { MouseTrailer * mouseTrailer = MouseTrailer::GetMouseTrailer(0); MouseTrailer::SetMouseTrailerWindow(this); mouseTrailer->CreateTimer(); } else { POINT mp; DWORD pos = ::GetMessagePos(); mp.x = LOWORD(pos); mp.y = HIWORD(pos); // OK, now find out if we are still inside // the captured native window POINT cpos; cpos.x = LOWORD(pos); cpos.y = HIWORD(pos); nsWindow * someWindow = NULL; HWND hWnd = ::WindowFromPoint(mp); if (hWnd != NULL) { ::ScreenToClient(hWnd, &cpos); RECT r; VERIFY(::GetWindowRect(hWnd, &r)); if (cpos.x >= r.left && cpos.x <= r.right && cpos.y >= r.top && cpos.y <= r.bottom) { // yes we are so we should be able to get a valid window // although, strangley enough when we are on the frame part of the // window we get right here when in capture mode // but this window won't match the capture mode window so // we are ok someWindow = (nsWindow*)::GetWindowLong(hWnd, GWL_USERDATA); } } // only set the window into the mouse trailer if we have a good window if (nsnull != someWindow) { MouseTrailer * mouseTrailer = MouseTrailer::GetMouseTrailer(0); MouseTrailer::SetMouseTrailerWindow(someWindow); mouseTrailer->CreateTimer(); } } nsRect rect; GetBounds(rect); rect.x = 0; rect.y = 0; if (rect.Contains(event.point.x, event.point.y)) { if (gCurrentWindow == NULL || gCurrentWindow != this) { if ((nsnull != gCurrentWindow) && (!gCurrentWindow->mIsDestroying)) { MouseTrailer::IgnoreNextCycle(); gCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, gCurrentWindow->GetLastPoint()); } gCurrentWindow = this; if (!mIsDestroying) { gCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER); } } } } else if (aEventType == NS_MOUSE_EXIT) { if (gCurrentWindow == this) { gCurrentWindow = nsnull; } } #endif //OS2TODO g_bHandlingMouseClick = TRUE; // NS_RELEASE(event.widget); return result; } if (nsnull != mMouseListener) { switch (aEventType) { case NS_MOUSE_MOVE: { result = ConvertStatus( mMouseListener->MouseMoved( event)); nsRect rect; GetBounds(rect); if (rect.Contains(event.point.x, event.point.y)) { if (gCurrentWindow == NULL || gCurrentWindow != this) { gCurrentWindow = this; } } else { //printf("Mouse exit"); } } break; case NS_MOUSE_LEFT_BUTTON_DOWN: case NS_MOUSE_MIDDLE_BUTTON_DOWN: case NS_MOUSE_RIGHT_BUTTON_DOWN: result = ConvertStatus( mMouseListener->MousePressed( event)); break; case NS_MOUSE_LEFT_BUTTON_UP: case NS_MOUSE_MIDDLE_BUTTON_UP: case NS_MOUSE_RIGHT_BUTTON_UP: result = ConvertStatus( mMouseListener->MouseReleased( event)); // result = ConvertStatus( mMouseListener->MouseClicked( event)); break; case NS_MOUSE_LEFT_CLICK: case NS_MOUSE_MIDDLE_CLICK: case NS_MOUSE_RIGHT_CLICK: result = ConvertStatus( mMouseListener->MouseClicked( event)); break; } // switch } g_bHandlingMouseClick = TRUE; // NS_RELEASE(event.widget); return result; } // -------------------------------------------------------------------------- // Overridable OnMessage() methods ------------------------------------------ // Key handler. Specs for the various text messages are really confused; // see other platforms for best results of how things are supposed to work. // // Perhaps more importantly, the main man listening to these events (besides // random bits of javascript) is ender -- see // mozilla/editor/base/nsEditorEventListeners.cpp. // PRBool nsWindow::OnKey( MPARAM mp1, MPARAM mp2) { nsKeyEvent event; USHORT fsFlags = SHORT1FROMMP(mp1); USHORT usVKey = SHORT2FROMMP(mp2); UCHAR uchScan = CHAR4FROMMP(mp1); int unirc = ULS_SUCCESS; // It appears we're not supposed to transmit shift, control & alt events // to gecko. Shrug. // // XXX this may be wrong, but is what gtk is doing... if( fsFlags & KC_VIRTUALKEY && (usVKey == VK_SHIFT || usVKey == VK_CTRL || usVKey == VK_ALT || usVKey == VK_ALTGRAF)) return PR_FALSE; // Now check if it's a dead-key if( fsFlags & KC_DEADKEY) { UniChar tmp; unirc = gModuleData.TranslateKey( uchScan, &tmp, &mDeadKey); if( unirc == ULS_SUCCESS) mHaveDeadKey = TRUE; else printf( "Couldn't translate dead key\n"); // XXX CUA says we're supposed to give some kind of feedback `display the // dead key glyph'. I'm not sure if we can use the COMPOSE messages // to do this -- it should really be done by someone who can test it // & has some idea what `ought' to happen... return PR_TRUE; } // Now dispatch a keyup/keydown event. This one is *not* meant to // have the unicode charcode in. nsPoint point(0,0); InitEvent( event, (fsFlags & KC_KEYUP) ? NS_KEY_UP : NS_KEY_DOWN, &point); event.keyCode = WMChar2KeyCode( mp1, mp2); event.isShift = (fsFlags & KC_SHIFT) ? PR_TRUE : PR_FALSE; event.isControl = (fsFlags & KC_CTRL) ? PR_TRUE : PR_FALSE; event.isAlt = (fsFlags & KC_ALT) ? PR_TRUE : PR_FALSE; event.isMeta = PR_FALSE; event.eventStructType = NS_KEY_EVENT; event.charCode = 0; PRBool rc = DispatchEventInternal( &event); // NS_RELEASE(event.widget); // Break off now if this was a key-up. if( fsFlags & KC_KEYUP) return rc; // Break off if we've got an "invalid composition" -- that is, the user // typed a deadkey last time, but has now typed something that doesn't // make sense in that context. if( fsFlags & KC_INVALIDCOMP) { mHaveDeadKey = FALSE; // XXX actually, not sure whether we're supposed to abort the keypress // or process it as though the dead key has been pressed. return rc; } // Now we need to dispatch a keypress event which has the unicode char. event.message = NS_KEY_PRESS; VDKEY vdkeyTmp; unirc = gModuleData.TranslateKey( uchScan, (UniChar*) &event.charCode, &vdkeyTmp); if( mHaveDeadKey && (fsFlags & KC_COMPOSITE) && unirc == ULS_SUCCESS) { unirc = UniTranslateDeadkey( gModuleData.hKeyboard, #ifdef XP_OS2_VACPP mDeadKey, #else &mDeadKey, #endif (UniChar) event.charCode, (UniChar*) &event.charCode, &mDeadKey); mHaveDeadKey = FALSE; } if( unirc != ULS_SUCCESS) { printf( "UniTranslate[Dead]Key returned %u\n", unirc); event.charCode = CHAR2FROMMP(mp2); } if( !event.isControl && !event.isAlt && event.charCode != 0) { if (!(fsFlags & KC_VIRTUALKEY)) { event.isShift = PR_FALSE; event.keyCode = 0; } } return DispatchEventInternal( &event); } PRBool nsWindow::OnReposition( PSWP pSwp) { PRBool result = PR_FALSE; if( pSwp->fl & SWP_MOVE && !(pSwp->fl & SWP_MINIMIZE)) { // need screen coords. POINTL ptl = { pSwp->x, pSwp->y + pSwp->cy - 1 }; WinMapWindowPoints( WinQueryWindow( mWnd, QW_PARENT), GetParentHWND(), &ptl, 1); PM2NS_PARENT( ptl); mBounds.x = ptl.x; mBounds.y = ptl.y; WinMapWindowPoints( GetParentHWND(), HWND_DESKTOP, &ptl, 1); result = OnMove( ptl.x, ptl.y); } if( pSwp->fl & SWP_SIZE && !(pSwp->fl & SWP_MINIMIZE)) result = OnResize( pSwp->cx, pSwp->cy); return result; } // Params here are in XP-space for the desktop PRBool nsWindow::OnMove( PRInt32 aX, PRInt32 aY) { PRBool result; nsGUIEvent event; InitEvent( event, NS_MOVE); event.point.x = aX; event.point.y = aY; event.eventStructType = NS_GUI_EVENT; result = DispatchEventInternal( &event); // NS_RELEASE(event.widget); return result; } PRBool nsWindow::OnPaint() { return PR_FALSE; } PRBool nsWindow::OnResize( PRInt32 aX, PRInt32 aY) { mBounds.width = aX; mBounds.height = aY; return DispatchResizeEvent( aX, aY); } PRBool nsWindow::DispatchResizeEvent( PRInt32 aX, PRInt32 aY) { PRBool result; // call the event callback nsSizeEvent event; nsRect rect( 0, 0, aX, aY); InitEvent( event, NS_SIZE); event.eventStructType = NS_SIZE_EVENT; event.windowSize = ▭ // this is the *client* rectangle event.mWinWidth = mBounds.width; event.mWinHeight = mBounds.height; result = DispatchEventInternal( &event); // NS_RELEASE(event.widget); return result; } PRBool nsWindow::OnScroll( MPARAM mp1, MPARAM mp2) { return PR_FALSE; } PRBool nsWindow::OnRealizePalette() { return PR_FALSE; } PRBool nsWindow::OnPresParamChanged( MPARAM mp1, MPARAM mp2) { return PR_FALSE; } // This is necessary because notification codes are defined from 1 for each // control: thus we cannot tell the difference between an EN_SELECT and // a TABN_SELECT, etc. // So delegate to those classes who actually want to handle the thing. PRBool nsWindow::OnControl( MPARAM mp1, MPARAM mp2) { return PR_TRUE; // default to speed things up a bit... } // -------------------------------------------------------------------------- // Menus -------------------------------------------------------------------- // wm_commands generated from menus // XXX should this only be in nsFrameWindow? // Probably worth trying for abstraction reasons. // #if 0 PRBool nsWindow::OnMenuClick( USHORT aCmd) { PRBool result = PR_TRUE; // find if this is a menuitem being clicked or a submenu // (actually I don't think submenu items generate wm_commands...) MENUITEM mI = { 0 }; #ifdef SUPPORT_NON_XPFE if( mMenuBar || mActiveMenu) #endif { void *hwndMenu = 0; // context menu takes precedence over menubar if( mActiveMenu) { mActiveMenu->GetNativeData( &hwndMenu); mActiveMenu = 0; // now forget it } else mMenuBar->GetNativeData( hwndMenu); mOS2Toolkit->SendMsg( (HWND) hwndMenu, MM_QUERYITEM, MPFROM2SHORT(aCmd,TRUE), MPFROMP(&mI)); } if( !(mI.afStyle & MIS_SUBMENU)) { // Find the nsIMenuItem for this selection nsISupports *aThing = (nsISupports*) mI.hItem; nsIMenuItem *aItem = nsnull; nsIMenuListener *aListener = nsnull; #ifndef SUPPORT_NON_XPFE NS_ASSERTION( aThing, "Disconnected menuitem"); #else // viewer.exe uses pure native menus, and so aThing will be null there. if( aThing) #endif { aThing->QueryInterface( NS_GET_IID(nsIMenuItem), (void**) &aItem); } // Fill out a menu event nsMenuEvent event; event.eventStructType = NS_MENU_EVENT; InitEvent(event, NS_MENU_SELECTED); event.mMenuItem = aItem; #ifdef SUPPORT_NON_XPFE if( !aItem) event.mCommand = aCmd; else #endif aItem->GetCommand( event.mCommand); #ifdef SUPPORT_NON_XPFE // Notify those interested result = DispatchEventInternal( &event); // XXX just for viewer.exe if( aThing) #endif { aThing->QueryInterface( NS_GET_IID(nsIMenuListener), (void**) &aListener); result = ConvertStatus( aListener->MenuItemSelected( event)); } // Clean up NS_IF_RELEASE(aItem); NS_IF_RELEASE(aListener); // NS_RELEASE(event.widget); } return result; } PRBool nsWindow::OnActivateMenu( HWND hwndMenu, BOOL aActivate) { nsMenuBase *pBase = (nsMenuBase*) WinQueryWindowPtr( hwndMenu, QWL_USER); PRBool result = PR_FALSE; if( nsnull != pBase) { nsMenu *aMenu = (nsMenu*) pBase; // XXX yeargh // Fill out a menu event nsMenuEvent event; event.eventStructType = NS_MENU_EVENT; // even if this is a deselect, same event type. InitEvent( event, NS_MENU_SELECTED); event.mMenuItem = nsnull; // XXX I guess event.mCommand = 0; // XXX I guess #ifdef SUPPORT_NON_XPFE // not sure if this is necessary, but can't do any harm. DispatchEventInternal( &event); #endif // dispatch to listener nsEventStatus es; if( aActivate) es = aMenu->MenuSelected( event); else es = aMenu->MenuDeselected( event); result = ConvertStatus( es); // NS_RELEASE(event.widget); } return result; } #endif #if 0 // (there needs to be a distinct nsTopLevelWindow class) nsresult nsWindow::SetMenuBar( nsIMenuBar *aMenuBar) { NS_IF_RELEASE(mMenuBar); mMenuBar = aMenuBar; NS_ADDREF(mMenuBar); return NS_OK; } nsresult nsWindow::ShowMenuBar( PRBool bShow) { if( mMenuBar) { HWND hwndMenu = 0; mMenuBar->GetNativeData( (void*&)hwndMenu); if( WinIsWindowVisible(hwndMenu) != (BOOL)bShow) { WinSetWindowUShort( mWnd, QWS_ID, bShow ? FID_MENU : 0); mOS2Toolkit->SendMsg( GetMainWindow(), WM_UPDATEFRAME, MPFROMLONG(FCF_MENU)); } } return NS_OK; } void nsWindow::SetContextMenu( nsContextMenu *aMenu) { mActiveMenu = aMenu; } #endif // -------------------------------------------------------------------------- // Hierarchy - children & parent -------------------------------------------- // We keep a pointer to our parent because we need parent a lot for doing // positioning things. We don't hold a reference to it, though. This should // be okay 'cos there's no scope for reparenting in this library and we // can't live longer than it. // First, nsIWidget methods nsIWidget* nsWindow::GetParent() { nsWindow *widget = nsnull; if( nsnull != mParent) { NS_ADDREF(mParent); widget = mParent; } return widget; } // Now, OS/2 methods HWND nsWindow::GetParentHWND() const { HWND hwnd = 0; if( nsnull != mParent) hwnd = mParent->mWnd; else hwnd = WinQueryWindow( GetMainWindow(), QW_PARENT); return hwnd; } // ptl is in parent's space void nsWindow::NS2PM_PARENT( POINTL &ptl) { if( mParent) mParent->NS2PM( ptl); else { HWND hwndp = WinQueryWindow( GetMainWindow(), QW_PARENT); SWP swp = { 0 }; WinQueryWindowPos( hwndp, &swp); ptl.y = swp.cy - ptl.y - 1; } } // ptl is in this window's space void nsWindow::NS2PM( POINTL &ptl) { ptl.y = GetClientHeight() - ptl.y - 1; #if 0 printf("+++++++++In NS2PM client height = %ld\n", GetClientHeight()); #endif } // rcl is in this window's space void nsWindow::NS2PM( RECTL &rcl) { LONG height = rcl.yTop - rcl.yBottom; rcl.yTop = GetClientHeight() - rcl.yBottom; rcl.yBottom = rcl.yTop - height; } // -------------------------------------------------------------------------- // Physical properties - size, position, visibility // Hide or show this window nsresult nsWindow::Show( PRBool bState) { // doesn't seem to require a message queue. if( mWnd) WinShowWindow( GetMainWindow(), !!bState); return NS_OK; } // Move this component (WinSetWindowPos() appears not to require a msgq) nsresult nsWindow::Move( PRInt32 aX, PRInt32 aY) { Resize( aX, aY, mBounds.width, mBounds.height, PR_FALSE); return NS_OK; } // Resize this component: need to keep top-left corner in the same place nsresult nsWindow::Resize( PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint) { Resize( mBounds.x, mBounds.y, aWidth, aHeight, aRepaint); return NS_OK; } // Resize this component nsresult nsWindow::Resize( PRInt32 aX, PRInt32 aY, PRInt32 w, PRInt32 h, PRBool aRepaint) { // NS_ASSERTION((w >=0 ), "Negative width passed to nsWindow::Resize"); // NS_ASSERTION((h >=0 ), "Negative height passed to nsWindow::Resize"); if( mWnd) { // work out real coords of top left POINTL ptl= { aX, aY }; NS2PM_PARENT( ptl); // work out real coords of bottom left ptl.y -= GetHeight( h) - 1; if( mParent) { WinMapWindowPoints( mParent->mWnd, WinQueryWindow(mWnd, QW_PARENT), &ptl, 1); } if( !SetWindowPos( 0, ptl.x, ptl.y, w, GetHeight(h), SWP_MOVE | SWP_SIZE)) if( aRepaint) Update(); #if DEBUG_sobotka printf("+++++++++++Resized 0x%lx at %ld, %ld to %ld x %ld\n\n", mWnd, ptl.x, ptl.y, w, GetHeight(h)); #endif } else { mBounds.x = aX; mBounds.y = aY; mBounds.width = w; mBounds.height = h; } return NS_OK; } BOOL nsWindow::SetWindowPos( HWND ib, long x, long y, long cx, long cy, ULONG flags) { BOOL bDeferred = FALSE; if( mParent && mParent->mSWPs) // XXX bit implicit... { mParent->DeferPosition( GetMainWindow(), ib, x, y, cx, cy, flags); bDeferred = TRUE; } else // WinSetWindowPos appears not to need msgq (hmm) WinSetWindowPos( GetMainWindow(), ib, x, y, cx, cy, GetSWPFlags(flags)); // When the window is actually sized, mBounds will be updated in the fnwp. return bDeferred; } // Enable/disable this window nsresult nsWindow::Enable( PRBool bState) { if( mWnd) WinEnableWindow( GetMainWindow(), !!bState); return NS_OK; } // Give the focus to this component nsresult nsWindow::SetFocus() { // Switch to the PM thread if necessary... if( !mOS2Toolkit->IsPMThread()) { MethodInfo info(this, nsWindow::W_SET_FOCUS); mOS2Toolkit->CallMethod(&info); } else if( mWnd) WinSetFocus( HWND_DESKTOP, mWnd); return NS_OK; } nsresult nsWindow::IsVisible( PRBool &aState) { // I guess this means visible & not showing... BOOL b = WinIsWindowVisible( mWnd); aState = b ? PR_TRUE : PR_FALSE; return NS_OK; } nsresult nsWindow::ModalEventFilter( PRBool aRealEvent, void */*aEvent*/, PRBool *aForWindow ) { if( PR_FALSE == aRealEvent) *aForWindow = PR_FALSE; else { // Set aForWindow if either: // * the message is for a descendent of the given window // * the message is for another window, but is a message which // should be allowed for a disabled window. PRBool isMouseEvent = PR_FALSE; PRBool isInWindow = PR_FALSE; // Examine the target window & find the frame // XXX should GetNativeData() use GetMainWindow() ? HWND hwnd = (HWND)GetNativeData(NS_NATIVE_WINDOW); hwnd = WinQueryWindow(hwnd, QW_PARENT); if( hwnd == mQmsg.hwnd || WinIsChild( mQmsg.hwnd, hwnd)) isInWindow = PR_TRUE; else if (!isInWindow && gRollupWidget && EventIsInsideWindow((nsWindow*)gRollupWidget)) // include for consideration any popup menu which may be active at the moment isInWindow = PR_TRUE; // XXX really ought to do something about focus here if( !isInWindow) { // Block mouse messages for non-modal windows if( mQmsg.msg >= WM_MOUSEFIRST && mQmsg.msg <= WM_MOUSELAST) isMouseEvent = PR_TRUE; else if( mQmsg.msg >= WM_MOUSETRANSLATEFIRST && mQmsg.msg <= WM_MOUSETRANSLATELAST) isMouseEvent = PR_TRUE; else if( mQmsg.msg == WMU_MOUSEENTER || mQmsg.msg == WMU_MOUSELEAVE) isMouseEvent = PR_TRUE; } // set dispatch indicator *aForWindow = isInWindow || !isMouseEvent; } return NS_OK; } // nsFrameWindow overrides this... nsresult nsWindow::GetClientBounds( nsRect &aRect) { aRect.x = 0; aRect.y = 0; aRect.width = mBounds.width; aRect.height = mBounds.height; return NS_OK; } // We don' wan' no steekin' borda! nsresult nsWindow::GetBorderSize( PRInt32 &aWidth, PRInt32 &aHeight) { aWidth = 0; aHeight = 0; return NS_OK; } // Preferred size; default here. nsresult nsWindow::GetPreferredSize( PRInt32 &aWidth, PRInt32 &aHeight) { aWidth = mPreferredWidth; aHeight = mPreferredHeight; return NS_OK; } nsresult nsWindow::SetPreferredSize( PRInt32 aWidth, PRInt32 aHeight) { mPreferredWidth = aWidth; mPreferredHeight = aHeight; return NS_OK; } // Deferred window positioning nsresult nsWindow::BeginResizingChildren() { if( !mSWPs) { mlHave = 10; mlUsed = 0; mSWPs = (PSWP) malloc( 10 * sizeof( SWP)); } return NS_OK; } void nsWindow::DeferPosition( HWND hwnd, HWND hwndInsertBehind, long x, long y, long cx, long cy, ULONG flags) { if( mSWPs) { if( mlHave == mlUsed) // need more swps { mlHave += 10; mSWPs = (PSWP) realloc( mSWPs, mlHave * sizeof( SWP)); } mSWPs[ mlUsed].hwnd = hwnd; mSWPs[ mlUsed].hwndInsertBehind = hwndInsertBehind; mSWPs[ mlUsed].x = x; mSWPs[ mlUsed].y = y; mSWPs[ mlUsed].cx = cx; mSWPs[ mlUsed].cy = cy; mSWPs[ mlUsed].fl = flags; mSWPs[ mlUsed].ulReserved1 = 0; mSWPs[ mlUsed].ulReserved2 = 0; mlUsed++; } } nsresult nsWindow::EndResizingChildren() { if( nsnull != mSWPs) { WinSetMultWindowPos( 0/*hab*/, mSWPs, mlUsed); free( mSWPs); mSWPs = nsnull; mlUsed = mlHave = 0; } return NS_OK; } // Screen <--> window coordinate conversion nsresult nsWindow::WidgetToScreen( const nsRect &aOldRect, nsRect &aNewRect) { POINTL pt = { aOldRect.x, aOldRect.y }; NS2PM( pt); WinMapWindowPoints( mWnd, HWND_DESKTOP, &pt, 1); aNewRect.x = pt.x; aNewRect.y = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN) - pt.y - 1; aNewRect.width = aOldRect.width; aNewRect.height = aOldRect.height; return NS_OK; } nsresult nsWindow::ScreenToWidget( const nsRect &aOldRect, nsRect &aNewRect) { POINTL pt = { aOldRect.x, WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN) - aOldRect.y - 1 }; WinMapWindowPoints( HWND_DESKTOP, mWnd, &pt, 1); PM2NS( pt); aNewRect.x = pt.x; aNewRect.y = pt.y; aNewRect.width = aOldRect.width; aNewRect.height = aOldRect.height; return NS_OK; } // -------------------------------------------------------------------------- // Colours, fonts, painting ------------------------------------------------- nsresult nsWindow::Paint( nsIRenderingContext &aRenderingContext, const nsRect &aDirtyRect) { printf( "Yikes - nsWindow::Paint called. Run for the hills...\n"); #if 0 // XXX This is thankfully done in XP-land now. // Get a proxy window HWND hwndProxy = gModuleData.GetWindowForPrinting( WindowClass(), WindowStyle()); // Size it correctly WinSetWindowPos( hwndProxy, HWND_TOP, 0, 0, mBounds.width, mBounds.height, SWP_SIZE | SWP_ZORDER); // Set pres-params: colors.. // ..and font // Subclass specific bits SetupForPrint( hwndProxy); // now get a HPS from the rc & do the WM_DRAW thing // (via drawingsurface, QI/cast) #endif return NS_OK; } nscolor nsWindow::QueryPresParam( ULONG ppID) { nscolor col = 0; RGB2 rgb; ULONG found = 0; WinQueryPresParam( mWnd, ppID, 0, &found, sizeof( RGB2), &rgb, QPF_PURERGBCOLOR); if( found == ppID) col = NS_RGB( rgb.bRed, rgb.bGreen, rgb.bBlue); return col; } void nsWindow::SetPresParam( ULONG ppID, const nscolor &c) { RGB2 rgb = { NS_GET_B( c), NS_GET_G( c), NS_GET_R( c), 0 }; WinSetPresParam( mWnd, ppID, sizeof( RGB2), &rgb); } nscolor nsWindow::GetForegroundColor() { return (mWnd ? QueryPresParam( PP_FOREGROUNDCOLOR) : mForeground); } nsresult nsWindow::SetForegroundColor( const nscolor &aColor) { if( mWnd) SetPresParam( PP_FOREGROUNDCOLOR, aColor); mForeground = aColor; return NS_OK; } nscolor nsWindow::GetBackgroundColor() { return (mWnd ? QueryPresParam( PP_BACKGROUNDCOLOR) : mBackground); } nsresult nsWindow::SetBackgroundColor(const nscolor &aColor) { if( mWnd) SetPresParam( PP_BACKGROUNDCOLOR, aColor); mBackground = aColor; return NS_OK; } // Well this should be interesting... nsIFontMetrics *nsWindow::GetFont() { nsIFontMetrics *metrics = nsnull; if( mToolkit) { char buf[2][128]; int ptSize; WinQueryPresParam( mWnd, PP_FONTNAMESIZE, 0, 0, 128, buf[0], 0); if( 2 == sscanf( buf[0], "%d.%s", &ptSize, buf[1])) // mmm, scanf()... { float twip2dev, twip2app; mContext->GetTwipsToDevUnits( twip2dev); mContext->GetDevUnitsToAppUnits( twip2app); twip2app *= twip2dev; nscoord appSize = (nscoord) (twip2app * ptSize * 20); nsFont font( buf[1], NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL, 0 /*decoration*/, appSize); mContext->GetMetricsFor( font, metrics); } } return metrics; } nsresult nsWindow::SetFont( const nsFont &aFont) { if( mToolkit) // called from print-routine (XXX check) { const char *fontname = gModuleData.ConvertFromUcs( aFont.name); // jump through hoops to convert the size in the font (in app units) // into points. float dev2twip, app2twip; mContext->GetDevUnitsToTwips( dev2twip); mContext->GetAppUnitsToDevUnits( app2twip); app2twip *= dev2twip; int points = NSTwipsToFloorIntPoints( nscoord( aFont.size * app2twip)); char *buffer = new char [ strlen( fontname) + 6]; sprintf( buffer, "%d.%s", points, fontname); BOOL rc = WinSetPresParam( mWnd, PP_FONTNAMESIZE, strlen( buffer) + 1, buffer); if( !rc) printf( "WinSetPresParam PP_FONTNAMESIZE %s failed\n", buffer); delete [] buffer; } if( !mFont) mFont = new nsFont( aFont); else *mFont = aFont; return NS_OK; } // SetColorMap - not implemented. // Any palette lives in the device context & should be altered there. // And shouldn't be altered at all, once libimg has decided what should // be in it. So my opinion is this method shouldn't be called. nsresult nsWindow::SetColorMap( nsColorMap *aColorMap) { return NS_ERROR_NOT_IMPLEMENTED; } // Cursor - more bizarre types not implemented yet nsresult nsWindow::SetCursor( nsCursor aCursor) { ULONG sptr = 0; switch( aCursor) { // builtins case eCursor_standard: sptr = SPTR_ARROW; break; case eCursor_wait: sptr = SPTR_WAIT; break; case eCursor_select: sptr = SPTR_TEXT; break; case eCursor_sizeWE: sptr = SPTR_SIZEWE; break; case eCursor_sizeNS: sptr = SPTR_SIZENS; break; case eCursor_sizeNW: sptr = SPTR_SIZENWSE; break; case eCursor_sizeSE: sptr = SPTR_SIZENWSE; break; case eCursor_sizeNE: sptr = SPTR_SIZENESW; break; case eCursor_sizeSW: sptr = SPTR_SIZENESW; break; case eCursor_move: sptr = SPTR_MOVE; break; // custom case eCursor_hyperlink: case eCursor_arrow_north: case eCursor_arrow_north_plus: case eCursor_arrow_south: case eCursor_arrow_south_plus: case eCursor_arrow_west: case eCursor_arrow_west_plus: case eCursor_arrow_east: case eCursor_arrow_east_plus: case eCursor_crosshair: case eCursor_help: case eCursor_copy: case eCursor_alias: case eCursor_context_menu: case eCursor_cell: case eCursor_grab: case eCursor_grabbing: case eCursor_spinning: case eCursor_count_up: case eCursor_count_down: case eCursor_count_up_down: break; default: NS_ASSERTION( 0, "Unknown cursor type"); break; } if( sptr) mPointer = WinQuerySysPointer( HWND_DESKTOP, sptr, FALSE); else mPointer = gModuleData.GetPointer( aCursor); WinSetPointer( HWND_DESKTOP, mPointer); mCursor = aCursor; return NS_OK; } // Invalidate and force a redraw nsresult nsWindow::Invalidate( PRBool aIsSynchronous) { if( mWnd) { WinInvalidateRect( mWnd, 0, FALSE); #if 0 if( PR_TRUE == aIsSynchronous) Update(); #endif } return NS_OK; } nsresult nsWindow::Invalidate( const nsRect &aRect, PRBool aIsSynchronous) { if( mWnd) { RECTL rcl = { aRect.x, aRect.y, aRect.x + aRect.width, aRect.y + aRect.height }; NS2PM( rcl); WinInvalidateRect( mWnd, &rcl, FALSE); #if 0 if( PR_TRUE == aIsSynchronous) Update(); #endif } return NS_OK; } nsresult nsWindow::InvalidateRegion(const nsIRegion *aRegion, PRBool aIsSynchronous) { nsresult rv = NS_OK; if( mWnd) { HRGN nativeRegion; rv = aRegion->GetNativeRegion( (void *&)nativeRegion); if( nativeRegion) { if( NS_SUCCEEDED(rv)) { RECTL rcl; HPS hps = WinGetScreenPS( HWND_DESKTOP); /* LONG lComplexity = */ GpiQueryRegionBox( hps, nativeRegion, &rcl); WinReleasePS( hps); NS2PM( rcl); WinInvalidateRect( mWnd, &rcl, FALSE); // WinInvalidateRegion( mWnd, nativeRegion, TRUE); #if 0 if( PR_TRUE == aIsSynchronous) Update(); #endif } } else { rv = NS_ERROR_FAILURE; } } return rv; } // force invalid areas to be updated nsresult nsWindow::Update() { // Switch to the PM thread if necessary... if( !mOS2Toolkit->IsPMThread()) { MethodInfo info(this, nsWindow::W_UPDATE_WINDOW); mOS2Toolkit->CallMethod(&info); } else if( mWnd) WinUpdateWindow( mWnd); return NS_OK; } nsresult nsWindow::SetTitle( const nsString &aTitle) { // Switch to the PM thread if necessary... if( mOS2Toolkit && !mOS2Toolkit->IsPMThread()) { ULONG ulong = (ULONG) &aTitle; MethodInfo info( this, nsWindow::W_SET_TITLE, 1, &ulong); mOS2Toolkit->CallMethod( &info); } else if( mWnd) { WinSetWindowText( GetMainWindow(), gModuleData.ConvertFromUcs( aTitle)); } return NS_OK; } nsresult nsWindow::GetWindowText( nsString &aStr, PRUint32 *rc) { // Switch to the PM thread if necessary... if( !mOS2Toolkit->IsPMThread()) { ULONG args[] = { (ULONG) &aStr, (ULONG) rc }; MethodInfo info( this, nsWindow::W_GET_TITLE, 2, args); mOS2Toolkit->CallMethod( &info); } else if( mWnd) { // XXX there must be some way to query the text straight into the string! int length = WinQueryWindowTextLength( mWnd); char *tmp = new char [ length + 1 ]; WinQueryWindowText( mWnd, length + 1, tmp); aStr.AssignWithConversion( tmp); delete [] tmp; } return NS_OK; } // Scroll the bits of a window - this may need to bye thread-switched nsresult nsWindow::Scroll( PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect) { RECTL rcl; if( aClipRect) { rcl.xLeft = aClipRect->x; rcl.yBottom = aClipRect->y + aClipRect->height; rcl.xRight = rcl.xLeft + aClipRect->width; rcl.yTop = rcl.yBottom + aClipRect->height; NS2PM( rcl); // this rect is inex } WinScrollWindow( mWnd, aDx, -aDy, aClipRect ? &rcl : 0, 0, 0, 0, SW_SCROLLCHILDREN | SW_INVALIDATERGN); Update(); return NS_OK; } // -------------------------------------------------------------------------- // Misc helpers ------------------------------------------------------------- // May need to thread-switch these... void nsWindow::AddToStyle( ULONG style) { if( mWnd) WinSetWindowBits( mWnd, QWL_STYLE, style, style); } void nsWindow::RemoveFromStyle( ULONG style) { if( mWnd) { ULONG oldStyle = WinQueryWindowULong( mWnd, QWL_STYLE); oldStyle &= ~style; WinSetWindowULong( mWnd, QWL_STYLE, oldStyle); } } void nsWindow::GetStyle( ULONG &out) { if( mWnd) out = WinQueryWindowULong( mWnd, QWL_STYLE); } #if 0 // Handled by XP code now // -------------------------------------------------------------------------- // Tooltips ----------------------------------------------------------------- nsresult nsWindow::SetTooltips( PRUint32 cTips, nsRect *areas[]) { nsTooltipManager::GetManager()->SetTooltips( this, cTips, areas); return NS_OK; } nsresult nsWindow::UpdateTooltips( nsRect *aNewTips[]) { nsTooltipManager::GetManager()->UpdateTooltips( this, aNewTips); return NS_OK; } nsresult nsWindow::RemoveTooltips() { nsTooltipManager::GetManager()->RemoveTooltips( this); return NS_OK; } #endif // -------------------------------------------------------------------------- // Drag'n'drop -------------------------------------------------------------- #define DispatchDragDropEvent(msg) DispatchStandardEvent(msg,NS_DRAGDROP_EVENT) // XXXX KNOCKED OUT UNTIL nsDragService.cpp is fixed PRBool nsWindow::OnDragOver( MPARAM mp1, MPARAM mp2, MRESULT &mr) { // Drawing drop feedback should be fun, have to get DrgGetPS() involved // somehow. // Tell drag service about the drag // gModuleData.dragService->InitDragOver( (PDRAGINFO) mp1); // Invoke gecko for enter if appropriate // if( !mDragInside) // { // DispatchDragDropEvent( NS_DRAGDROP_ENTER); // mDragInside = TRUE; // } // Invoke for 'over' to set candrop flag // DispatchDragDropEvent( NS_DRAGDROP_OVER); // Get action back from drag service // mr = gModuleData.dragService->TermDragOver(); return PR_TRUE; } PRBool nsWindow::OnDragLeave( MPARAM mp1, MPARAM mp2) { // gModuleData.dragService->InitDragExit( (PDRAGINFO) mp1); // DispatchDragDropEvent( NS_DRAGDROP_EXIT); // gModuleData.dragService->TermDragExit(); // mDragInside = FALSE; return PR_TRUE; } PRBool nsWindow::OnDrop( MPARAM mp1, MPARAM mp2) { // gModuleData.dragService->InitDrop( (PDRAGINFO) mp1); // DispatchDragDropEvent( NS_DRAGDROP_DROP); // gModuleData.dragService->TermDrop(); mDragInside = FALSE; return PR_TRUE; } // -------------------------------------------------------------------------- // Raptor object access // 'Native data' void *nsWindow::GetNativeData( PRUint32 aDataType) { void *rc = 0; switch( aDataType) { case NS_NATIVE_WIDGET: case NS_NATIVE_WINDOW: case NS_NATIVE_PLUGIN_PORT: rc = (void*) mWnd; break; case NS_NATIVE_GRAPHIC: if( !mPS) { if( mDragInside) mPS = DrgGetPS( mWnd); else mPS = WinGetPS( mWnd); } mPSRefs++; rc = (void*) mPS; break; case NS_NATIVE_COLORMAP: case NS_NATIVE_DISPLAY: case NS_NATIVE_REGION: case NS_NATIVE_OFFSETX: case NS_NATIVE_OFFSETY: // could do this, I suppose; but why? // OTOH, this might make plugins work! break; default: #ifdef DEBUG printf( "*** Someone's added a new NS_NATIVE value...\n"); #endif break; } return rc; } void nsWindow::FreeNativeData( void *aDatum, PRUint32 aDataType) { switch( aDataType) { case NS_NATIVE_GRAPHIC: mPSRefs--; if( !mPSRefs) { BOOL rc; if( mDragInside) rc = DrgReleasePS( mPS); else rc = WinReleasePS( mPS); if( !rc) printf( "Error from {Win/Drg}ReleasePS()\n"); mPS = 0; } break; case NS_NATIVE_COLORMAP: case NS_NATIVE_DISPLAY: case NS_NATIVE_REGION: case NS_NATIVE_OFFSETX: case NS_NATIVE_OFFSETY: case NS_NATIVE_WIDGET: case NS_NATIVE_WINDOW: case NS_NATIVE_PLUGIN_PORT: break; default: #ifdef DEBUG printf( "*** Someone's added a new NS_NATIVE value...\n"); #endif break; } } // Thread switch callback nsresult nsWindow::CallMethod(MethodInfo *info) { nsresult rc = NS_ERROR_FAILURE; switch( info->methodId) { case nsWindow::W_CREATE: NS_ASSERTION(info->nArgs == 7, "Bad args to Create"); DoCreate( (HWND) info->args[0], (nsWindow*) info->args[1], (const nsRect&)*(nsRect*) (info->args[2]), (EVENT_CALLBACK) (info->args[3]), (nsIDeviceContext*) (info->args[4]), (nsIAppShell*) (info->args[5]), nsnull, /* toolkit */ (nsWidgetInitData*) (info->args[6])); rc = NS_OK; break; #if 0 case nsWindow::W_CREATE: Create((nsIWidget*)(info->args[0]), (nsRect&)*(nsRect*)(info->args[1]), (EVENT_CALLBACK)(info->args[2]), (nsIDeviceContext*)(info->args[3]), (nsIAppShell *)(info->args[4]), (nsIToolkit*)(info->args[5]), (nsWidgetInitData*)(info->args[6])); rc = NS_OK; break; case nsWindow::W_CREATE_NATIVE: Create((nsNativeWidget)(info->args[0]), (nsRect&)*(nsRect*)(info->args[1]), (EVENT_CALLBACK)(info->args[2]), (nsIDeviceContext*)(info->args[3]), (nsIAppShell *)(info->args[4]), (nsIToolkit*)(info->args[5]), (nsWidgetInitData*)(info->args[6])); rc = NS_OK; break; #endif case nsWindow::W_DESTROY: NS_ASSERTION(info->nArgs == 0, "Bad args to Destroy"); Destroy(); rc = NS_OK; break; case nsWindow::W_SET_FOCUS: NS_ASSERTION(info->nArgs == 0, "Bad args to SetFocus"); SetFocus(); rc = NS_OK; break; case nsWindow::W_UPDATE_WINDOW: NS_ASSERTION(info->nArgs == 0, "Bad args to UpdateWindow"); Update(); rc = NS_OK; break; case nsWindow::W_SET_TITLE: NS_ASSERTION(info->nArgs == 1, "Bad args to SetTitle"); SetTitle( (const nsString &) info->args[0]); rc = NS_OK; break; case nsWindow::W_GET_TITLE: NS_ASSERTION(info->nArgs == 2, "Bad args to GetTitle"); rc = GetWindowText( *((nsString*) info->args[0]), (PRUint32*)info->args[1]); break; default: break; } return rc; } // function to translate from a WM_CHAR to an NS VK_ constant --------------- PRUint32 WMChar2KeyCode( MPARAM mp1, MPARAM mp2) { PRUint32 rc = 0; USHORT flags = SHORT1FROMMP( mp1); // First check for characters. // This is complicated by keystrokes such as Ctrl+K not having the KC_CHAR // bit set, but thankfully they do have the character actually there. // // So go on the assumption that `if not vkey or deadkey then char' // if( !(flags & (KC_VIRTUALKEY | KC_DEADKEY))) { rc = SHORT1FROMMP(mp2); if( rc < 0xFF) { // Need nls-correct way of doing this... if( isalnum( rc)) rc = toupper( rc); // no lower case else switch( rc) { case ';': rc = NS_VK_SEMICOLON; break; case '=': rc = NS_VK_EQUALS; break; case '*': rc = NS_VK_MULTIPLY; break; case '+': rc = NS_VK_ADD; break; case '-': rc = NS_VK_SUBTRACT; break; case '.': rc = NS_VK_PERIOD; break; // NS_VK_DECIMAL ? case '|': rc = NS_VK_SEPARATOR; break; case ',': rc = NS_VK_COMMA; break; case '/': rc = NS_VK_SLASH; break; // NS_VK_DIVIDE ? case '`': rc = NS_VK_BACK_QUOTE; break; case '(': rc = NS_VK_OPEN_BRACKET; break; case '\\': rc = NS_VK_BACK_SLASH; break; case ')': rc = NS_VK_CLOSE_BRACKET; break; case '\'': rc = NS_VK_QUOTE; break; } } } else if( flags & KC_VIRTUALKEY) { USHORT vk = SHORT2FROMMP( mp2); if( vk >= VK_F1 && vk <= VK_F24) rc = NS_VK_F1 + (vk - VK_F1); else switch( vk) { case VK_NUMLOCK: rc = NS_VK_NUM_LOCK; break; case VK_SCRLLOCK: rc = NS_VK_SCROLL_LOCK; break; case VK_ESC: rc = NS_VK_ESCAPE; break; // NS_VK_CANCEL case VK_BACKSPACE: rc = NS_VK_BACK; break; case VK_TAB: rc = NS_VK_TAB; break; case VK_BACKTAB: rc = NS_VK_TAB; break; // layout tests for isShift case VK_CLEAR: rc = NS_VK_CLEAR; break; case VK_NEWLINE: rc = NS_VK_RETURN; break; case VK_ENTER: rc = NS_VK_ENTER; break; case VK_SHIFT: rc = NS_VK_SHIFT; break; case VK_CTRL: rc = NS_VK_CONTROL; break; case VK_ALT: rc = NS_VK_ALT; break; case VK_PAUSE: rc = NS_VK_PAUSE; break; case VK_CAPSLOCK: rc = NS_VK_CAPS_LOCK; break; case VK_SPACE: rc = NS_VK_SPACE; break; case VK_PAGEUP: rc = NS_VK_PAGE_UP; break; case VK_PAGEDOWN: rc = NS_VK_PAGE_DOWN; break; case VK_END: rc = NS_VK_END; break; case VK_HOME: rc = NS_VK_HOME; break; case VK_LEFT: rc = NS_VK_LEFT; break; case VK_UP: rc = NS_VK_UP; break; case VK_RIGHT: rc = NS_VK_RIGHT; break; case VK_DOWN: rc = NS_VK_DOWN; break; case VK_PRINTSCRN: rc = NS_VK_PRINTSCREEN; break; case VK_INSERT: rc = NS_VK_INSERT; break; case VK_DELETE: rc = NS_VK_DELETE; break; } } return rc; } NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent) { if (aDoCapture) { /* we haven't bothered carrying a weak reference to gRollupWidget because we believe lifespan is properly scoped. this next assertion helps assure that remains true. */ NS_ASSERTION(!gRollupWidget, "rollup widget reassigned before release"); gRollupConsumeRollupEvent = aConsumeRollupEvent; NS_IF_RELEASE(gRollupListener); NS_IF_RELEASE(gRollupWidget); gRollupListener = aListener; NS_ADDREF(aListener); gRollupWidget = this; NS_ADDREF(this); } else { NS_IF_RELEASE(gRollupListener); //gRollupListener = nsnull; NS_IF_RELEASE(gRollupWidget); } return NS_OK; }