Back to index

lightning-sunbird  0.9+nobinonly
nsWindow.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim: set sw=2 sts=2 et cin: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla OS/2 libraries.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * John Fairhurst, <john_fairhurst@iname.com>.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Pierre Phaneuf <pp@ludusdesign.com>
00025  *   IBM Corp.
00026  *   Rich Walsh <dragtext@e-vertise.com>
00027  *   Dan Rosen <dr@netscape.com>
00028  *   Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
00029  *   Peter Weilbacher <mozilla@Weilbacher.org>
00030  *
00031  * Alternatively, the contents of this file may be used under the terms of
00032  * either the GNU General Public License Version 2 or later (the "GPL"), or
00033  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00034  * in which case the provisions of the GPL or the LGPL are applicable instead
00035  * of those above. If you wish to allow use of your version of this file only
00036  * under the terms of either the GPL or the LGPL, and not to allow others to
00037  * use your version of this file under the terms of the MPL, indicate your
00038  * decision by deleting the provisions above and replace them with the notice
00039  * and other provisions required by the GPL or the LGPL. If you do not delete
00040  * the provisions above, a recipient may use your version of this file under
00041  * the terms of any one of the MPL, the GPL or the LGPL.
00042  *
00043  * ***** END LICENSE BLOCK ***** */
00044 
00045 #include "nsWindow.h"
00046 #include "nsIAppShell.h"
00047 #include "nsIFontMetrics.h"
00048 #include "nsFont.h"
00049 #include "nsGUIEvent.h"
00050 #include "nsIRenderingContext.h"
00051 #include "nsIRenderingContextOS2.h"
00052 #include "nsIDeviceContext.h"
00053 #include "nsIScreenManager.h"
00054 #include "nsRect.h"
00055 #include "nsTransform2D.h"
00056 #include "nsGfxCIID.h"
00057 #include "prtime.h"
00058 // #include "nsTooltipManager.h"
00059 #include "nsISupportsArray.h"
00060 #include "nsIMenuBar.h"
00061 //#include "nsIMenuItem.h"
00062 #include "nsHashtable.h"
00063 //#include "nsMenu.h"
00064 #include "nsDragService.h"
00065 #include "nsILocalFile.h"
00066 #include "nsNetUtil.h"
00067 
00068 #include "nsIRollupListener.h"
00069 #include "nsIMenuRollup.h"
00070 #include "nsIRegion.h"
00071 #include "nsIPref.h"
00072 
00073 //~~~ windowless plugin support
00074 #include "nsplugindefs.h"
00075 
00076 #include "nsITimer.h"
00077 #include "nsIServiceManager.h"
00078 
00079 // For SetIcon
00080 #include "nsAppDirectoryServiceDefs.h"
00081 #include "nsXPIDLString.h"
00082 #include "nsIFile.h"
00083 
00084 #include "nsOS2Uni.h"
00085 #include "nsPaletteOS2.h"
00086 
00087 #include "imgIContainer.h"
00088 #include "gfxIImageFrame.h"
00089 
00090 #include <stdlib.h>
00091 #include <ctype.h>
00092 
00093 #include "nsdefs.h"
00094 #include "wdgtos2rc.h"
00095 
00096 #ifdef DEBUG_sobotka
00097 static int WINDOWCOUNT = 0;
00098 #endif
00099 
00100 static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
00101 
00102 // The subclass proc (fnwpNSWindow) calls ProcessMessage() in the object.
00103 // Decisions are taken here about what to do - the purpose of the OnFoo()
00104 // methods is to generate an NS event to the various people who are
00105 // listening, or not.
00106 //
00107 // OS/2 things: remember supplied coords are in the XP space.  There are
00108 // NS2PM methods for conversion of points & rectangles; position is a bit
00109 // different in that it's the *parent* window whose height must be used.
00110 //
00111 // Deferred window positioning is emulated using WinSetMultWindowPos in
00112 // the hopes that there was a good reason for adding it to nsIWidget.
00113 //
00114 // SetColorSpace() is not implemented on purpose.  So there.
00115 //
00116 // John Fairhurst 17-09-98 first version
00117 //        Revised 01-12-98 to inherit from nsBaseWidget.
00118 //        Revised 24-01-99 to use hashtable
00119 //        Revised 15-03-99 for new menu classes
00120 //        Revised 05-06-99 to use pres-params
00121 //        Revised 19-06-99 drag'n'drop, etc.
00122 
00123 
00124 nsWindow* nsWindow::gCurrentWindow = nsnull;
00125 BOOL nsWindow::sIsRegistered       = FALSE;
00126 
00128 // Rollup Listener - global variable defintions
00130 nsIRollupListener * gRollupListener           = nsnull;
00131 nsIWidget         * gRollupWidget             = nsnull;
00132 PRBool              gRollupConsumeRollupEvent = PR_FALSE;
00134 
00135 PRBool gJustGotActivate = PR_FALSE;
00136 PRBool gJustGotDeactivate = PR_FALSE;
00137 
00139 // Mouse Clicks - static variable defintions 
00140 // for figuring out 1 - 3 Clicks
00142 static POINTS gLastButton1Down = {0,0};
00143 
00144 #define XFROMMP(m)    (SHORT(LOUSHORT(m)))
00145 #define YFROMMP(m)    (SHORT(HIUSHORT(m)))
00146 
00147 
00148 static PRBool gGlobalsInitialized = PR_FALSE;
00149 static HPOINTER gPtrArray[IDC_COUNT];
00150 static PRBool gIsTrackPoint = PR_FALSE;
00151 static PRBool gIsDBCS = PR_FALSE;
00152 
00153 // The last user input event time in milliseconds. If there are any pending
00154 // native toolkit input events it returns the current time. The value is
00155 // compatible with PR_IntervalToMicroseconds(PR_IntervalNow()).
00156 static PRUint32 gLastInputEventTime = 0;
00157 
00158 #ifdef DEBUG_FOCUS
00159   int currentWindowIdentifier = 0;
00160 #endif
00161 
00162 //-------------------------------------------------------------------------
00163 // Drag and Drop flags and global data
00164 // see the D&D section toward the end of this file for additional info
00165 
00166 // actions that might cause problems during d&d
00167 #define ACTION_PAINT    1
00168 #define ACTION_DRAW     2
00169 #define ACTION_SCROLL   3
00170 #define ACTION_SHOW     4
00171 #define ACTION_PTRPOS   5
00172 
00173 // shorten these references a bit
00174 #define DND_None                (nsIDragSessionOS2::DND_NONE)               
00175 #define DND_NativeDrag          (nsIDragSessionOS2::DND_NATIVEDRAG)         
00176 #define DND_MozDrag             (nsIDragSessionOS2::DND_MOZDRAG)            
00177 #define DND_InDrop              (nsIDragSessionOS2::DND_INDROP)             
00178 #define DND_DragStatus          (nsIDragSessionOS2::DND_DRAGSTATUS)         
00179 #define DND_DispatchEnterEvent  (nsIDragSessionOS2::DND_DISPATCHENTEREVENT) 
00180 #define DND_DispatchEvent       (nsIDragSessionOS2::DND_DISPATCHEVENT)      
00181 #define DND_GetDragoverResult   (nsIDragSessionOS2::DND_GETDRAGOVERRESULT)  
00182 #define DND_ExitSession         (nsIDragSessionOS2::DND_EXITSESSION)        
00183 
00184 // set when any nsWindow is being dragged over
00185 static PRUint32  gDragStatus = 0;
00186 
00187 
00188 //
00189 // App Command messages for IntelliMouse and Natural Keyboard Pro
00190 //
00191 #define WM_APPCOMMAND  0x0319
00192 
00193 #define APPCOMMAND_BROWSER_BACKWARD       1
00194 #define APPCOMMAND_BROWSER_FORWARD        2
00195 #define APPCOMMAND_BROWSER_REFRESH        3
00196 #define APPCOMMAND_BROWSER_STOP           4
00197 
00198 #define FAPPCOMMAND_MASK  0xF000
00199 #define GET_APPCOMMAND_LPARAM(lParam) ((USHORT)(HIUSHORT(lParam) & ~FAPPCOMMAND_MASK))
00200 
00201 //-------------------------------------------------------------------------
00202 //
00203 // nsWindow constructor
00204 //
00205 //-------------------------------------------------------------------------
00206 nsWindow::nsWindow() : nsBaseWidget()
00207 {
00208     mWnd                = 0;
00209     mFrameWnd           = 0;
00210     mPrevWndProc        = NULL;
00211     mParent             = 0;
00212     mNextID             = 1;
00213     mSWPs               = 0;
00214     mlHave              = 0;
00215     mlUsed              = 0;
00216     mFrameIcon          = 0;
00217     mDeadKey            = 0;
00218     mHaveDeadKey        = FALSE;
00219     mIsDestroying       = PR_FALSE;
00220     mOnDestroyCalled    = PR_FALSE;
00221     mIsVisible          = FALSE;
00222 
00223     mPreferredWidth     = 0;
00224     mPreferredHeight    = 0;
00225     mWindowState        = nsWindowState_ePrecreate;
00226     mWindowType         = eWindowType_child;
00227     mBorderStyle        = eBorderStyle_default;
00228     mFont               = nsnull;
00229     mOS2Toolkit         = nsnull;
00230     mIsScrollBar         = FALSE;
00231     mInSetFocus         = FALSE;
00232     mChromeHidden       = FALSE;
00233     mDragHps            = 0;
00234     mDragStatus         = 0;
00235     mCssCursorHPtr      = 0;
00236 
00237     mIsTopWidgetWindow = PR_FALSE;
00238 
00239     if (!gGlobalsInitialized) {
00240       gGlobalsInitialized = PR_TRUE;
00241       HMODULE hModResources = NULLHANDLE;
00242       DosQueryModFromEIP(&hModResources, NULL, 0, NULL, NULL, (ULONG) &gGlobalsInitialized);
00243       for (int i = 0; i < IDC_COUNT; i++) {
00244         gPtrArray[i] = ::WinLoadPointer(HWND_DESKTOP, hModResources, IDC_BASE+i);
00245       }
00246 
00247       // Work out if the system is DBCS
00248       char buffer[CCHMAXPATH];
00249       COUNTRYCODE cc = { 0 };
00250       DosQueryDBCSEnv( CCHMAXPATH, &cc, buffer);
00251       gIsDBCS = buffer[0] || buffer[1];
00252 
00253       // This is ugly. The Thinkpad TrackPoint driver checks to see whether or not a window
00254       // actually has a scroll bar as a child before sending it scroll messages. Needless to
00255       // say, no Mozilla window has real scroll bars. So if you have the "os2.trackpoint"
00256       // preference set, we put an invisible scroll bar on every child window so we can
00257       // scroll. Woohoo!
00258       nsresult rv;
00259       nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID, &rv));
00260       if (NS_SUCCEEDED(rv) && prefs)
00261          prefs->GetBoolPref("os2.trackpoint", &gIsTrackPoint);
00262     }
00263 }
00264 
00265 //-------------------------------------------------------------------------
00266 //
00267 // nsWindow destructor
00268 //
00269 //-------------------------------------------------------------------------
00270 nsWindow::~nsWindow()
00271 {
00272   // How destruction works: A call of Destroy() destroys the PM window.  This
00273   // triggers an OnDestroy(), which frees resources.  If not Destroy'd at
00274   // delete time, Destroy() gets called anyway.
00275   
00276   // NOTE: Calling virtual functions from destructors is bad; they always
00277   //       bind in the current object (ie. as if they weren't virtual).  It
00278   //       may even be illegal to call them from here.
00279   //
00280   mIsDestroying = PR_TRUE;
00281   if (gCurrentWindow == this) {
00282     gCurrentWindow = nsnull;
00283   }
00284   if (mFrameIcon) {
00285      WinFreeFileIcon(mFrameIcon);
00286      mFrameIcon = NULLHANDLE;
00287   }
00288 
00289   if (mCssCursorHPtr) {
00290     WinDestroyPointer(mCssCursorHPtr);
00291     mCssCursorHPtr = 0;
00292   }
00293 
00294   // If the widget was released without calling Destroy() then the native
00295   // window still exists, and we need to destroy it
00296   if( !(mWindowState & nsWindowState_eDead) )
00297   {
00298     mWindowState |= nsWindowState_eDoingDelete;
00299     mWindowState &= ~(nsWindowState_eLive|nsWindowState_ePrecreate|
00300                       nsWindowState_eInCreate);
00301 //    if( mWnd)
00302       Destroy();
00303   }
00304 
00305 }
00306 
00307 /* static */ void
00308 nsWindow::ReleaseGlobals()
00309 {
00310   for (int i = 0; i < IDC_COUNT; i++) {
00311     WinDestroyPointer(gPtrArray[i]);
00312   }
00313 }
00314 
00315 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
00316 {
00317   if (PR_TRUE == aCapture) { 
00318     WinSetCapture( HWND_DESKTOP, mWnd);
00319   } else {
00320     WinSetCapture( HWND_DESKTOP, NULLHANDLE);
00321   }
00322 //  mIsInMouseCapture = aCapture;
00323   return NS_OK;
00324 }
00325 
00326 
00327 //-------------------------------------------------------------------------
00328 //
00329 // Deferred Window positioning
00330 //
00331 //-------------------------------------------------------------------------
00332 
00333 NS_METHOD nsWindow::BeginResizingChildren(void)
00334 {
00335    if( !mSWPs)
00336    {
00337       mlHave = 10;
00338       mlUsed = 0;
00339       mSWPs = (PSWP) malloc( 10 * sizeof( SWP));
00340    }
00341    return NS_OK;
00342 }
00343 
00344 void nsWindow::DeferPosition( HWND hwnd, HWND hwndInsertBehind,
00345                               long x, long y, long cx, long cy, ULONG flags)
00346 {
00347    if( mSWPs)
00348    {
00349       if( mlHave == mlUsed) // need more swps
00350       {
00351          mlHave += 10;
00352          mSWPs = (PSWP) realloc( mSWPs, mlHave * sizeof( SWP));
00353       }
00354       mSWPs[ mlUsed].hwnd = hwnd;
00355       mSWPs[ mlUsed].hwndInsertBehind = hwndInsertBehind;
00356       mSWPs[ mlUsed].x = x;
00357       mSWPs[ mlUsed].y = y;
00358       mSWPs[ mlUsed].cx = cx;
00359       mSWPs[ mlUsed].cy = cy;
00360       mSWPs[ mlUsed].fl = flags;
00361       mSWPs[ mlUsed].ulReserved1 = 0;
00362       mSWPs[ mlUsed].ulReserved2 = 0;
00363       mlUsed++;
00364    }
00365 }
00366 
00367 NS_METHOD nsWindow::EndResizingChildren(void)
00368 {
00369    if( nsnull != mSWPs)
00370    {
00371       WinSetMultWindowPos( 0/*hab*/, mSWPs, mlUsed);
00372       free( mSWPs);
00373       mSWPs = nsnull;
00374       mlUsed = mlHave = 0;
00375    }
00376    return NS_OK;
00377 }
00378 
00379 NS_METHOD nsWindow::WidgetToScreen(const nsRect &aOldRect, nsRect &aNewRect)
00380 {
00381   POINTL point = { aOldRect.x, aOldRect.y };
00382   NS2PM( point);
00383 
00384   WinMapWindowPoints( mWnd, HWND_DESKTOP, &point, 1);
00385 
00386   aNewRect.x = point.x;
00387   aNewRect.y = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN) - point.y - 1;
00388   aNewRect.width = aOldRect.width;
00389   aNewRect.height = aOldRect.height;
00390   return NS_OK;
00391 }
00392 
00393 NS_METHOD nsWindow::ScreenToWidget( const nsRect &aOldRect, nsRect &aNewRect)
00394 {
00395   POINTL point = { aOldRect.x,
00396                    WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN) - aOldRect.y - 1 };
00397   WinMapWindowPoints( HWND_DESKTOP, mWnd, &point, 1);
00398 
00399   PM2NS( point);
00400 
00401   aNewRect.x = point.x;
00402   aNewRect.y = point.y;
00403   aNewRect.width = aOldRect.width;
00404   aNewRect.height = aOldRect.height;
00405   return NS_OK;
00406 }
00407 
00408 //-------------------------------------------------------------------------
00409 //
00410 // Convert nsEventStatus value to a windows boolean
00411 //
00412 //-------------------------------------------------------------------------
00413 
00414 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
00415 {
00416   switch(aStatus) {
00417   case nsEventStatus_eIgnore:
00418     return PR_FALSE;
00419   case nsEventStatus_eConsumeNoDefault:
00420     return PR_TRUE;
00421   case nsEventStatus_eConsumeDoDefault:
00422     return PR_FALSE;
00423   default:
00424     NS_ASSERTION(0, "Illegal nsEventStatus enumeration value");
00425     break;
00426   }
00427   return PR_FALSE;
00428 }
00429 
00430 //-------------------------------------------------------------------------
00431 //
00432 // Initialize an event to dispatch
00433 //
00434 //-------------------------------------------------------------------------
00435 void nsWindow::InitEvent(nsGUIEvent& event, nsPoint* aPoint)
00436 {
00437     NS_ADDREF(event.widget);
00438 
00439     if (nsnull == aPoint) {     // use the point from the event
00440       // for most events, get the message position;  for drag events,
00441       // msg position may be incorrect, so get the current position instead
00442       POINTL ptl;
00443       if (CheckDragStatus(ACTION_PTRPOS, 0))
00444         WinQueryPointerPos( HWND_DESKTOP, &ptl);
00445       else
00446         WinQueryMsgPos( 0/*hab*/, &ptl);
00447       WinMapWindowPoints( HWND_DESKTOP, mWnd, &ptl, 1);
00448 
00449 #if 0
00450       printf("++++++++++nsWindow::InitEvent (!pt) mapped point = %ld, %ld\n", ptl.x, ptl.y);
00451 #endif
00452 
00453       PM2NS( ptl);
00454 
00455       event.point.x = ptl.x;
00456       event.point.y = ptl.y;
00457 
00458 #if 0
00459       printf("++++++++++nsWindow::InitEvent (!pt) converted point = %ld, %ld\n", ptl.x, ptl.y);
00460 #endif
00461    }
00462    else
00463    {                     // use the point override if provided
00464       event.point.x = aPoint->x;
00465       event.point.y = aPoint->y;
00466 
00467 #if 0
00468       printf("++++++++++nsWindow::InitEvent point = %ld, %ld\n", aPoint->x, aPoint->y);
00469 #endif
00470    }
00471 
00472    event.time = WinQueryMsgTime( 0/*hab*/);
00473 
00474    /* OS2TODO
00475    mLastPoint.x = event.point.x;
00476    mLastPoint.y = event.point.y;
00477    */
00478 }
00479 
00480 //-------------------------------------------------------------------------
00481 //
00482 // Invokes callback and  ProcessEvent method on Event Listener object
00483 //
00484 //-------------------------------------------------------------------------
00485 
00486 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
00487 {
00488 #if defined(TRACE_EVENTS) && defined(DEBUG_sobotka)
00489   DebugPrintEvent(*event, mWnd);
00490 #endif
00491 
00492   aStatus = nsEventStatus_eIgnore;
00493 
00494   // Filters: if state is eInCreate, only send out NS_CREATE
00495   //          if state is eDoingDelete, don't send out anything because,
00496   //                                    well, the object's being deleted...
00497   if( ((mWindowState == nsWindowState_eInCreate) && event->message == NS_CREATE)
00498       || (mWindowState & nsWindowState_eLive) )
00499   {
00500     if (nsnull != mEventCallback) {
00501       aStatus = (*mEventCallback)( event);
00502     }
00503    
00504     // Dispatch to event listener if event was not consumed
00505     if ((aStatus != nsEventStatus_eIgnore) && (nsnull != mEventListener)) {
00506       aStatus = mEventListener->ProcessEvent(*event);
00507     }
00508   }
00509 
00510   return NS_OK;
00511 }
00512 
00513 //-------------------------------------------------------------------------
00514 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
00515 {
00516   nsEventStatus status;
00517   DispatchEvent(event, status);
00518   return ConvertStatus(status);
00519 }
00520 
00521 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent*event, nsEventStatus &aStatus) {
00522   DispatchEvent(event, aStatus);
00523   return ConvertStatus(aStatus);
00524 }
00525 
00526 //-------------------------------------------------------------------------
00527 //
00528 // Dispatch standard event
00529 //
00530 //-------------------------------------------------------------------------
00531 
00532 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
00533 {
00534   nsGUIEvent event(PR_TRUE, aMsg, this);
00535   InitEvent(event);
00536 
00537   PRBool result = DispatchWindowEvent(&event);
00538   NS_RELEASE(event.widget);
00539   return result;
00540 }
00541 
00542 //-------------------------------------------------------------------------
00543 //
00544 // Dispatch app command event
00545 //
00546 //-------------------------------------------------------------------------
00547 PRBool nsWindow::DispatchAppCommandEvent(PRUint32 aEventCommand)
00548 {
00549   nsAppCommandEvent event(PR_TRUE, NS_APPCOMMAND_START, this);
00550 
00551   InitEvent(event);
00552   event.appCommand = NS_APPCOMMAND_START + aEventCommand;
00553 
00554   DispatchWindowEvent(&event);
00555   NS_RELEASE(event.widget);
00556 
00557   return NS_OK;
00558 }
00559 
00560 //-------------------------------------------------------------------------
00561 //
00562 // Dispatch DragDrop (target) event
00563 //
00564 //-------------------------------------------------------------------------
00565 PRBool nsWindow::DispatchDragDropEvent(PRUint32 aMsg)
00566 {
00567   nsMouseEvent event(PR_TRUE, aMsg, this, nsMouseEvent::eReal);
00568   InitEvent(event);
00569 
00570   event.isShift   = WinIsKeyDown(VK_SHIFT);
00571   event.isControl = WinIsKeyDown(VK_CTRL);
00572   event.isAlt     = WinIsKeyDown(VK_ALT) || WinIsKeyDown(VK_ALTGRAF);
00573   event.isMeta    = PR_FALSE;
00574 
00575   PRBool result = DispatchWindowEvent(&event);
00576   NS_RELEASE(event.widget);
00577 
00578   return result;
00579 }
00580 
00581 //-------------------------------------------------------------------------
00582 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener, 
00583                                             PRBool aDoCapture, 
00584                                             PRBool aConsumeRollupEvent)
00585 {
00586   if (aDoCapture) {
00587     /* we haven't bothered carrying a weak reference to gRollupWidget because
00588        we believe lifespan is properly scoped. this next assertion helps
00589        assure that remains true. */
00590     NS_ASSERTION(!gRollupWidget, "rollup widget reassigned before release");
00591     gRollupConsumeRollupEvent = aConsumeRollupEvent;
00592     NS_IF_RELEASE(gRollupListener);
00593     NS_IF_RELEASE(gRollupWidget);
00594     gRollupListener = aListener;
00595     NS_ADDREF(aListener);
00596     gRollupWidget = this;
00597     NS_ADDREF(this);
00598   } else {
00599     NS_IF_RELEASE(gRollupListener);
00600     //gRollupListener = nsnull;
00601     NS_IF_RELEASE(gRollupWidget);
00602   }
00603 
00604   return NS_OK;
00605 }
00606 
00607 PRBool 
00608 nsWindow::EventIsInsideWindow(nsWindow* aWindow) 
00609 {
00610   RECTL r;
00611   POINTL mp;
00612   if (WinQueryMsgPos( 0/*hab*/, &mp)) {
00613     WinMapWindowPoints( HWND_DESKTOP, aWindow->mWnd, &mp, 1);
00614     WinQueryWindowRect( aWindow->mWnd, &r);
00615     // now make sure that it wasn't one of our children
00616     if (mp.x < r.xLeft || mp.x > r.xRight ||
00617        mp.y > r.yTop || mp.y < r.yBottom) {
00618       return PR_FALSE;
00619     }
00620   } 
00621 
00622   return PR_TRUE;
00623 }
00624 
00625 
00626 static PCSZ GetNSWindowPropName() {
00627   static ATOM atom = 0;
00628 
00629   // this is threadsafe, even without locking;
00630   // even if there's a race, GlobalAddAtom("nsWindowPtr")
00631   // will just return the same value
00632   if (!atom) {
00633     atom = WinAddAtom(WinQuerySystemAtomTable(), "nsWindowPtr");
00634   }
00635   return (PCSZ)atom;
00636 }
00637 
00638 nsWindow * nsWindow::GetNSWindowPtr(HWND aWnd) {
00639   return (nsWindow *) ::WinQueryProperty(aWnd, GetNSWindowPropName());
00640 }
00641 
00642 BOOL nsWindow::SetNSWindowPtr(HWND aWnd, nsWindow * ptr) {
00643   if (ptr == NULL) {
00644     ::WinRemoveProperty(aWnd, GetNSWindowPropName());
00645     return TRUE;
00646   } else {
00647     return ::WinSetProperty(aWnd, GetNSWindowPropName(), (PVOID)ptr, 0);
00648   }
00649 }
00650 
00651 //
00652 // DealWithPopups
00653 //
00654 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
00655 //
00656 BOOL
00657 nsWindow :: DealWithPopups ( ULONG inMsg, MRESULT* outResult )
00658 {
00659   if ( gRollupListener && gRollupWidget) {
00660     if(inMsg == WM_BUTTON1DOWN ||
00661         inMsg == WM_BUTTON2DOWN || inMsg == WM_BUTTON3DOWN) {
00662       // Rollup if the event is outside the popup.
00663       PRBool rollup = !nsWindow::EventIsInsideWindow((nsWindow*)gRollupWidget);
00664       
00665       // If we're dealing with menus, we probably have submenus and we don't
00666       // want to rollup if the click is in a parent menu of the current submenu.
00667       if (rollup) {
00668         nsCOMPtr<nsIMenuRollup> menuRollup ( do_QueryInterface(gRollupListener) );
00669         if ( menuRollup ) {
00670           nsCOMPtr<nsISupportsArray> widgetChain;
00671           menuRollup->GetSubmenuWidgetChain ( getter_AddRefs(widgetChain) );
00672           if ( widgetChain ) {
00673             PRUint32 count = 0;
00674             widgetChain->Count(&count);
00675             for ( PRUint32 i = 0; i < count; ++i ) {
00676               nsCOMPtr<nsISupports> genericWidget;
00677               widgetChain->GetElementAt ( i, getter_AddRefs(genericWidget) );
00678               nsCOMPtr<nsIWidget> widget ( do_QueryInterface(genericWidget) );
00679               if ( widget ) {
00680                 nsIWidget* temp = widget.get();
00681                 if ( nsWindow::EventIsInsideWindow((nsWindow*)temp) ) {
00682                   rollup = PR_FALSE;
00683                   break;
00684                 }
00685               }
00686             } // foreach parent menu widget
00687           }
00688         } // if rollup listener knows about menus
00689       }
00690 
00691       // if we've determined that we should still rollup everything, do it.
00692       if ( rollup ) {
00693         gRollupListener->Rollup();
00694 
00695         // return TRUE tells Windows that the event is consumed, 
00696         // false allows the event to be dispatched
00697         //
00698         // So if we are NOT supposed to be consuming events, let it go through
00699         if (gRollupConsumeRollupEvent) {
00700           *outResult = (MRESULT)TRUE;
00701           return TRUE;
00702         } 
00703       }
00704     } // if event that might trigger a popup to rollup    
00705   } // if rollup listeners registered
00706 
00707   return FALSE;
00708 
00709 } // DealWithPopups
00710 
00711 
00712 
00713 // Are both windows from this app?
00714 BOOL bothFromSameWindow( HWND hwnd1, HWND hwnd2 )
00715 {
00716   HWND hwnd1Chain = WinQueryWindow( hwnd1, QW_OWNER );
00717   if (!hwnd1Chain)
00718     hwnd1Chain = WinQueryWindow( hwnd1, QW_PARENT );
00719   HWND hwnd1GChain = WinQueryWindow( hwnd1Chain, QW_OWNER );
00720   if (!hwnd1GChain)
00721     hwnd1GChain = WinQueryWindow( hwnd1Chain, QW_PARENT );
00722   HWND hwnd2Chain = WinQueryWindow( hwnd2, QW_OWNER );
00723   if (!hwnd2Chain)
00724     hwnd2Chain = WinQueryWindow( hwnd2, QW_PARENT );
00725   HWND hwnd2GChain = WinQueryWindow( hwnd2Chain, QW_OWNER );
00726   if (!hwnd2GChain)
00727     hwnd2GChain = WinQueryWindow( hwnd2Chain, QW_PARENT );
00728   while( hwnd1GChain) {
00729     hwnd1 = hwnd1Chain;
00730     hwnd1Chain = hwnd1GChain;
00731     hwnd1GChain = WinQueryWindow( hwnd1Chain, QW_OWNER );
00732     if (!hwnd1GChain)
00733       hwnd1GChain = WinQueryWindow( hwnd1Chain, QW_PARENT );
00734   }
00735   while( hwnd2GChain) {
00736     hwnd2 = hwnd2Chain;
00737     hwnd2Chain = hwnd2GChain;
00738     hwnd2GChain = WinQueryWindow( hwnd2Chain, QW_OWNER );
00739     if (!hwnd2GChain)
00740       hwnd2GChain = WinQueryWindow( hwnd2Chain, QW_PARENT );
00741   }
00742   return (hwnd1 == hwnd2);
00743 }
00744 
00745 //-------------------------------------------------------------------------
00746 //
00747 // the nsWindow procedure for all nsWindows in this toolkit
00748 //
00749 //-------------------------------------------------------------------------
00750 MRESULT EXPENTRY fnwpNSWindow( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
00751 {
00752    MRESULT popupHandlingResult;
00753    if( nsWindow::DealWithPopups(msg, &popupHandlingResult) )
00754       return popupHandlingResult;
00755 
00756    // Get the nsWindow for this hwnd
00757    nsWindow *wnd = nsWindow::GetNSWindowPtr(hwnd);
00758 
00759    // check to see if we have a rollup listener registered
00760    if( nsnull != gRollupListener && nsnull != gRollupWidget) {
00761       if( msg == WM_ACTIVATE || msg == WM_BUTTON1DOWN ||
00762           msg == WM_BUTTON2DOWN || msg == WM_BUTTON3DOWN) {
00763       // Rollup if the event is outside the popup.
00764       PRBool rollup = !nsWindow::EventIsInsideWindow((nsWindow*)gRollupWidget);
00765       
00766       // If we're dealing with menus, we probably have submenus and we don't
00767       // want to rollup if the click is in a parent menu of the current submenu.
00768       if (rollup) {
00769         nsCOMPtr<nsIMenuRollup> menuRollup ( do_QueryInterface(gRollupListener) );
00770         if ( menuRollup ) {
00771           nsCOMPtr<nsISupportsArray> widgetChain;
00772           menuRollup->GetSubmenuWidgetChain ( getter_AddRefs(widgetChain) );
00773           if ( widgetChain ) {
00774             PRUint32 count = 0;
00775             widgetChain->Count(&count);
00776             for ( PRUint32 i = 0; i < count; ++i ) {
00777               nsCOMPtr<nsISupports> genericWidget;
00778               widgetChain->GetElementAt ( i, getter_AddRefs(genericWidget) );
00779               nsCOMPtr<nsIWidget> widget ( do_QueryInterface(genericWidget) );
00780               if ( widget ) {
00781                 nsIWidget* temp = widget.get();
00782                 if ( nsWindow::EventIsInsideWindow((nsWindow*)temp) ) {
00783                   rollup = PR_FALSE;
00784                   break;
00785                 }
00786               }
00787             } // foreach parent menu widget
00788           }
00789         } // if rollup listener knows about menus
00790       }
00791       }
00792       else if( msg == WM_SETFOCUS) {
00793          if( !mp2 && 
00794              !bothFromSameWindow( ((nsWindow*)gRollupWidget)->GetMainWindow(), 
00795                                   (HWND)mp1) ) {
00796             gRollupListener->Rollup();
00797          }
00798       }
00799    }
00800 
00801    // Messages which get re-routed if their source was an nsWindow
00802    // (it's very bad to reroute messages whose source isn't an nsWindow,
00803    // listboxes with scrollbars for example would break)
00804    switch( msg)
00805    {
00806       case WM_CONTROL:
00807       case WM_HSCROLL:
00808       case WM_VSCROLL: // !! potential problems here if canvas children
00809       {
00810          // assume parent == owner, true for our creations
00811          HWND hwndChild = WinWindowFromID( hwnd, SHORT1FROMMP( mp1));
00812          if( hwndChild)
00813          {
00814             nsWindow *w = nsWindow::GetNSWindowPtr(hwndChild);
00815             if( w)
00816                wnd = w;
00817          }
00818          break;
00819       }
00820    }
00821 
00822     // hold on to the window for the life of this method, in case it gets
00823     // deleted during processing. yes, it's a double hack, since someWindow
00824     // is not really an interface.
00825     nsCOMPtr<nsISupports> kungFuDeathGrip;
00826     if (!wnd->mIsDestroying) // not if we're in the destructor!
00827       kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)wnd);
00828 
00829    MRESULT mresult = 0;
00830 
00831    if (wnd)
00832    {
00833       if( PR_FALSE == wnd->ProcessMessage( msg, mp1, mp2, mresult) &&
00834           WinIsWindow( (HAB)0, hwnd) && wnd->GetPrevWP())
00835       {
00836          mresult = (wnd->GetPrevWP())( hwnd, msg, mp1, mp2);
00837 
00838       }
00839    }
00840    else
00841       /* erm */ mresult = WinDefWindowProc( hwnd, msg, mp1, mp2);
00842 
00843    return mresult;
00844 }
00845 
00846 //-------------------------------------------------------------------------
00847 //
00848 // Utility method for implementing both Create(nsIWidget ...) and
00849 // Create(nsNativeWidget...)
00850 //-------------------------------------------------------------------------
00851 void nsWindow::DoCreate( HWND hwndP, nsWindow *aParent,
00852                       const nsRect &aRect,
00853                       EVENT_CALLBACK aHandleEventFunction,
00854                       nsIDeviceContext *aContext,
00855                       nsIAppShell *aAppShell,
00856                       nsIToolkit *aToolkit,
00857                       nsWidgetInitData *aInitData)
00858 {
00859    mWindowState = nsWindowState_eInCreate;
00860 
00861   if( aInitData && (aInitData->mWindowType == eWindowType_dialog ||
00862                     aInitData->mWindowType == eWindowType_toplevel ||
00863                     aInitData->mWindowType == eWindowType_invisible))
00864     mIsTopWidgetWindow = PR_TRUE;
00865   else
00866     mIsTopWidgetWindow = PR_FALSE;
00867 
00868    if( aInitData != nsnull) {
00869      SetWindowType(aInitData->mWindowType);
00870      SetBorderStyle(aInitData->mBorderStyle);
00871    }
00872 
00873    // Must ensure toolkit before attempting to thread-switch!
00874    if( !mToolkit)
00875    {
00876       if( aToolkit)
00877       {
00878          mToolkit = aToolkit;
00879          NS_ADDREF(mToolkit);
00880       }
00881       else if( aParent)
00882          mToolkit = aParent->GetToolkit();
00883       else
00884       {
00885          // it's some top level window with no toolkit passed in.
00886          // Create a default toolkit with the current thread
00887          mToolkit = new nsToolkit;
00888          NS_ADDREF(mToolkit);
00889          mToolkit->Init( PR_GetCurrentThread());
00890       }
00891       mOS2Toolkit = (nsToolkit*) mToolkit;
00892    }
00893 
00894    // Switch to the PM thread if necessary...
00895    if(mOS2Toolkit && !mOS2Toolkit->IsGuiThread())
00896    {
00897       ULONG args[7] = { hwndP, (ULONG) aParent, (ULONG) &aRect,
00898                         (ULONG) aHandleEventFunction,
00899                         (ULONG) aContext, (ULONG) aAppShell,
00900                         (ULONG) aInitData };
00901       MethodInfo info( this, nsWindow::CREATE, 7, args);
00902       mOS2Toolkit->CallMethod( &info);
00903    }
00904    else
00905       // This is potentially virtual; overridden in nsFrameWindow
00906       RealDoCreate( hwndP, aParent, aRect, aHandleEventFunction,
00907                     aContext, aAppShell, aInitData);
00908 
00909    mWindowState = nsWindowState_eLive;
00910 }
00911 
00912 void nsWindow::RealDoCreate( HWND              hwndP,
00913                              nsWindow         *aParent,
00914                              const nsRect     &aRect,
00915                              EVENT_CALLBACK    aHandleEventFunction,
00916                              nsIDeviceContext *aContext,
00917                              nsIAppShell      *aAppShell,
00918                              nsWidgetInitData *aInitData,
00919                              HWND              hwndOwner)
00920 {
00921 
00922   // XXXX TEST HACK to get rid of window bunnies
00923   //  if (!(aRect.height > 1) && !(aRect.width > 1))
00924   //    return;
00925 
00926    // Set up parent data - don't addref to avoid circularity
00927    mParent = aParent;
00928 
00929    ULONG style = WindowStyle();
00930    if( aInitData)
00931    {
00932       if( aInitData->clipChildren)
00933          style |= WS_CLIPCHILDREN;
00934 #if 0
00935       //
00936       // Windows has a slightly different idea of what the implications are
00937       // of a window having or not having the CLIPSIBLINGS style.
00938       // All 'canvas' components we create must have clipsiblings, or
00939       // strange things happen & performance actually degrades.
00940       //
00941       else
00942         style &= ~WS_CLIPCHILDREN;
00943 #endif
00944 
00945       if( aInitData->clipSiblings)
00946          style |= WS_CLIPSIBLINGS;
00947       else
00948          style &= ~WS_CLIPSIBLINGS;
00949    }
00950 
00951    mIsScrollBar = (!(strcmp( WindowClass(), WC_SCROLLBAR_STRING )));
00952 
00953    if( hwndP != HWND_DESKTOP)
00954    {
00955       // For pop-up menus, the parent is the desktop, but use the "parent" as owner
00956       if( aInitData && aInitData->mWindowType == eWindowType_popup)
00957       {
00958          if( !hwndOwner)
00959          {
00960             hwndOwner = hwndP;
00961          }
00962          hwndP = HWND_DESKTOP;
00963       }
00964       // For scrollbars, the parent is the owner, for notification purposes
00965       else if(!hwndOwner )
00966       {
00967          if( mIsScrollBar )
00968          {
00969             hwndOwner = hwndP;
00970          }
00971       }
00972    }
00973 
00974 #ifdef DEBUG_FOCUS
00975    mWindowIdentifier = currentWindowIdentifier;
00976    currentWindowIdentifier++;
00977    if (aInitData && (aInitData->mWindowType == eWindowType_toplevel))
00978      DEBUGFOCUS(Create Frame Window);
00979    else
00980      DEBUGFOCUS(Create Window);
00981 #endif
00982 
00983    // Create a window: create hidden & then size to avoid swp_noadjust problems
00984    // owner == parent except for 'borderless top-level' -- see nsCanvas.cpp
00985    mWnd = WinCreateWindow( hwndP,
00986                            WindowClass(),
00987                            0,          // text
00988                            style,
00989                            0, 0, 0, 0, // pos/size
00990                            hwndOwner,
00991                            HWND_TOP,
00992                            mParent ? mParent->GetNextID() : 0,
00993                            0, 0);      // ctldata, presparams
00994 
00995    NS_ASSERTION( mWnd, "Couldn't create window");
00996 
00997    if (gIsTrackPoint && mWindowType == eWindowType_child && !mIsScrollBar) {
00998      WinCreateWindow(mWnd, WC_SCROLLBAR, 0, SBS_VERT,
00999                      0, 0, 0, 0, mWnd, HWND_TOP,
01000                      FID_VERTSCROLL, NULL, NULL);
01001    }
01002 
01003 #if DEBUG_sobotka
01004    printf("\n+++++++++++In nsWindow::RealDoCreate created 0x%lx, %d x %d\n",
01005          mWnd, aRect.width, aRect.height);
01006    printf("+++++++++++Location =  %d x %d\n", aRect.x, aRect.y);
01007    printf("+++++++++++Parent = 0x%lx\n", GetParentHWND());
01008    printf("+++++++++++WINDOWCOUNT+ = %d\n", ++WINDOWCOUNT);
01009 #endif
01010 
01011    // Make sure we have a device context from somewhere
01012    if( aContext)
01013    {
01014       mContext = aContext;
01015       NS_ADDREF(mContext);
01016    }
01017    else
01018    {
01019       nsresult rc;
01020       static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID);
01021 
01022       rc = CallCreateInstance(kDeviceContextCID, &mContext);
01023       if( NS_SUCCEEDED(rc))
01024          mContext->Init( (nsNativeWidget) mWnd);
01025 #ifdef DEBUG
01026       else
01027          printf( "Couldn't find DC instance for nsWindow\n");
01028 #endif
01029    }
01030 
01031    Resize( aRect.x, aRect.y, aRect.width, aRect.height, PR_FALSE);
01032 
01033    // Record bounds.  This is XP, the rect of the entire main window in
01034    // parent space.  Returned by GetBounds().
01035    // NB: We haven't subclassed yet, so callbacks to change mBounds won't
01036    //     have happened!
01037    mBounds = aRect;
01038    mBounds.height = aRect.height;
01039 
01040    // Record passed in things
01041    mAppShell = aAppShell;
01042 
01043 //   NS_IF_ADDREF( mAppShell);
01044    GetAppShell();  // Let the base widget class update the refcount for us....
01045    mEventCallback = aHandleEventFunction;
01046 
01047    if( mParent)
01048       mParent->AddChild( this);
01049 
01050    mContentType = aInitData? aInitData->mContentType : eContentTypeInherit;
01051    if (mContentType == eContentTypeInherit && aParent) {
01052       mContentType = aParent->mContentType;
01053    }
01054 
01055    // call the event callback to notify about creation
01056 
01057    DispatchStandardEvent( NS_CREATE );
01058    SubclassWindow(TRUE);
01059    PostCreateWidget();
01060 }
01061 
01062 //-------------------------------------------------------------------------
01063 //
01064 // Create the proper widget
01065 //
01066 //-------------------------------------------------------------------------
01067 NS_METHOD nsWindow::Create(nsIWidget *aParent,
01068                       const nsRect &aRect,
01069                       EVENT_CALLBACK aHandleEventFunction,
01070                       nsIDeviceContext *aContext,
01071                       nsIAppShell *aAppShell,
01072                       nsIToolkit *aToolkit,
01073                       nsWidgetInitData *aInitData)
01074 {
01075    HWND hwndP = aParent ? (HWND)aParent->GetNativeData( NS_NATIVE_WINDOW)
01076                         : HWND_DESKTOP;
01077 
01078    DoCreate( hwndP, (nsWindow*) aParent, aRect, aHandleEventFunction,
01079              aContext, aAppShell, aToolkit, aInitData);
01080 
01081    return NS_OK;
01082 }
01083 
01084 
01085 //-------------------------------------------------------------------------
01086 //
01087 // create with a native parent
01088 //
01089 //-------------------------------------------------------------------------
01090 
01091 NS_METHOD nsWindow::Create(nsNativeWidget aParent,
01092                          const nsRect &aRect,
01093                          EVENT_CALLBACK aHandleEventFunction,
01094                          nsIDeviceContext *aContext,
01095                          nsIAppShell *aAppShell,
01096                          nsIToolkit *aToolkit,
01097                          nsWidgetInitData *aInitData)
01098 {
01099    // We need to find the nsWindow that goes with the native window, or controls
01100    // all get the ID of 0, and a zillion toolkits get created.
01101    //
01102    nsWindow *pParent = nsnull;
01103    HWND      hwndP = (HWND) aParent;
01104 
01105    if( hwndP && hwndP != HWND_DESKTOP)
01106       pParent = GetNSWindowPtr(hwndP);
01107 
01108    // XXX WC_MOZILLA will probably need a change here
01109    //
01110    if( !hwndP)
01111      hwndP = HWND_DESKTOP;
01112 
01113    DoCreate( hwndP, pParent, aRect, aHandleEventFunction, aContext,
01114              aAppShell, aToolkit, aInitData);
01115 
01116    return NS_OK;
01117 }
01118 
01119 //-------------------------------------------------------------------------
01120 //
01121 // Close this nsWindow
01122 //
01123 //-------------------------------------------------------------------------
01124 NS_METHOD nsWindow::Destroy()
01125 {
01126   // Switch to the "main gui thread" if necessary... This method must
01127   // be executed on the "gui thread"...
01128    // Switch to the PM thread if necessary...
01129    if( mToolkit && !mOS2Toolkit->IsGuiThread())
01130    {
01131       MethodInfo info( this, nsWindow::DESTROY);
01132       mOS2Toolkit->CallMethod( &info);
01133    }
01134    else
01135    {
01136       // avoid calling into other objects if we're being deleted, 'cos
01137       // they must have no references to us.
01138       if( (mWindowState & nsWindowState_eLive) && mParent )
01139          nsBaseWidget::Destroy();
01140 
01141       // just to be safe. If we're going away and for some reason we're still
01142       // the rollup widget, rollup and turn off capture.
01143       if (this == gRollupWidget) {
01144          if (gRollupListener)
01145             gRollupListener->Rollup();
01146          CaptureRollupEvents(nsnull, PR_FALSE, PR_TRUE);
01147       }
01148 
01149       if( mWnd)
01150       {
01151          HWND hwndBeingDestroyed = mFrameWnd ? mFrameWnd : mWnd;
01152          DEBUGFOCUS(Destroy);
01153          if (hwndBeingDestroyed == WinQueryFocus(HWND_DESKTOP)) {
01154            WinSetFocus(HWND_DESKTOP, WinQueryWindow(hwndBeingDestroyed, QW_PARENT));
01155          }
01156          WinDestroyWindow(hwndBeingDestroyed);
01157       }
01158    }
01159    return NS_OK;
01160 }
01161 
01162 //-------------------------------------------------------------------------
01163 //
01164 // Get this nsWindow parent
01165 //
01166 //-------------------------------------------------------------------------
01167 nsIWidget* nsWindow::GetParent(void)
01168 {
01169     if (mIsTopWidgetWindow) {
01170        // Must use a flag instead of mWindowType to tell if the window is the 
01171        // owned by the topmost widget, because a child window can be embedded inside
01172        // a HWND which is not associated with a nsIWidget.
01173       return nsnull;
01174     }
01175     /* If this widget has already been destroyed, pretend we have no parent.
01176        This corresponds to code in Destroy which removes the destroyed
01177        widget from its parent's child list. */
01178     if (mIsDestroying || mOnDestroyCalled)
01179       return nsnull;
01180 
01181    nsWindow *widget = nsnull;
01182    if ((nsnull != mParent) && (!mParent->mIsDestroying))
01183    {
01184       NS_ADDREF(mParent);
01185       widget = mParent;
01186    }
01187 
01188    return widget;
01189 }
01190 
01191 // Now, OS/2 methods
01192 HWND nsWindow::GetParentHWND() const
01193 {
01194    HWND hwnd = 0;
01195    if( nsnull != mParent)
01196       hwnd = mParent->mWnd;
01197    else
01198       hwnd = WinQueryWindow( GetMainWindow(), QW_PARENT);
01199    return hwnd;
01200 }
01201 
01202 // ptl is in parent's space
01203 void nsWindow::NS2PM_PARENT( POINTL &ptl)
01204 {
01205    if( mParent)
01206       mParent->NS2PM( ptl);
01207    else
01208    {
01209       HWND hwndp = WinQueryWindow( GetMainWindow(), QW_PARENT);
01210       SWP  swp = { 0 };
01211       WinQueryWindowPos( hwndp, &swp);
01212       ptl.y = swp.cy - ptl.y - 1;
01213    }
01214 }
01215 
01216 // ptl is in this window's space
01217 void nsWindow::NS2PM( POINTL &ptl)
01218 {
01219    ptl.y = GetClientHeight() - ptl.y - 1;
01220 #if 0
01221    printf("+++++++++In NS2PM client height = %d\n", GetClientHeight());
01222 #endif
01223 }
01224 
01225 // rcl is in this window's space
01226 void nsWindow::NS2PM( RECTL &rcl)
01227 {
01228    LONG height = rcl.yTop - rcl.yBottom;
01229    rcl.yTop = GetClientHeight() - rcl.yBottom;
01230    rcl.yBottom = rcl.yTop - height;
01231 }
01232 
01233 //-------------------------------------------------------------------------
01234 //
01235 // Hide or show this component
01236 //
01237 //-------------------------------------------------------------------------
01238 NS_METHOD nsWindow::Show(PRBool bState)
01239 {
01240    // doesn't seem to require a message queue.
01241    if( mWnd)
01242    {
01243       HWND hwnd = GetMainWindow();
01244       if( bState == PR_TRUE)
01245       {
01246         // don't try to show new windows (e.g. the Bookmark menu)
01247         // during a native dragover because they'll remain invisible;
01248       if (CheckDragStatus(ACTION_SHOW, 0))
01249           WinShowWindow( hwnd, TRUE);
01250       }
01251       else
01252          WinShowWindow( hwnd, FALSE);
01253    }
01254    mIsVisible = bState;
01255 
01256    return NS_OK;
01257 }
01258 
01259 //-------------------------------------------------------------------------
01260 //
01261 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
01262 //
01263 //-------------------------------------------------------------------------
01264 NS_METHOD nsWindow::IsVisible(PRBool & bState)
01265 {
01266    // I guess this means visible & not showing...
01267    bState = WinIsWindowVisible( mWnd) ? PR_TRUE : PR_FALSE;
01268    mIsVisible = bState;
01269    return NS_OK;
01270 }
01271 
01272 //-------------------------------------------------------------------------
01273 //
01274 // Return the last value passed to Show.
01275 //
01276 //-------------------------------------------------------------------------
01277 PRBool nsWindow::IsShown()
01278 {
01279   return mIsVisible;
01280 }
01281 
01282 //-------------------------------------------------------------------------
01283 //
01284 // Position the window behind the given window
01285 //
01286 //-------------------------------------------------------------------------
01287 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
01288                                 nsIWidget *aWidget, PRBool aActivate)
01289 {
01290   HWND behind = aWidget ? (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW) : HWND_TOP;
01291   UINT flags = SWP_ZORDER;
01292   if (aActivate)
01293     flags |= SWP_ACTIVATE;
01294 
01295   WinSetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
01296   return NS_OK;
01297 }
01298 
01299 //-------------------------------------------------------------------------
01300 //
01301 // Maximize, minimize or restore the window.
01302 //
01303 //-------------------------------------------------------------------------
01304 
01305 // when the frame has its controls, this method is advisory because
01306 // the min/max/restore has already occurred;  only when the frame is
01307 // in kiosk/fullscreen mode does it perform the minimize or restore
01308 
01309 NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode)
01310 {
01311   nsresult rv;
01312 
01313   // save the requested state
01314   rv = nsBaseWidget::SetSizeMode(aMode);
01315 
01316   // this is part of a kludge to keep minimized windows from getting
01317   // restored when they get the focus - we defer the activation event
01318   // until the window has actually been restored;  see WM_FOCUSCHANGED
01319   if (gJustGotActivate) {
01320     DEBUGFOCUS(deferred NS_ACTIVATE);
01321     gJustGotActivate = PR_FALSE;
01322     gJustGotDeactivate = PR_FALSE;
01323     DispatchFocus(NS_ACTIVATE, TRUE);
01324   }
01325 
01326   // nothing to do in these cases
01327   if (!NS_SUCCEEDED(rv) || !mChromeHidden || aMode == nsSizeMode_Maximized)
01328     return rv;
01329 
01330   HWND  hFrame = GetMainWindow();
01331   ULONG ulStyle = WinQueryWindowULong( hFrame, QWL_STYLE);
01332 
01333   // act on the request if the frame isn't already in the requested state
01334   if (aMode == nsSizeMode_Minimized) {
01335     if (!(ulStyle & WS_MINIMIZED))
01336       WinSetWindowPos(hFrame, 0, 0, 0, 0, 0, SWP_MINIMIZE | SWP_DEACTIVATE);
01337   }
01338   else
01339     if (ulStyle & (WS_MAXIMIZED | WS_MINIMIZED))
01340       WinSetWindowPos(hFrame, 0, 0, 0, 0, 0, SWP_RESTORE);
01341 
01342   return NS_OK;
01343 }
01344 
01345 //-------------------------------------------------------------------------
01346 // Return PR_TRUE in aForWindow if the given event should be processed
01347 // assuming this is a modal window.
01348 //-------------------------------------------------------------------------
01349 NS_METHOD nsWindow::ModalEventFilter(PRBool aRealEvent, void *aEvent,
01350                                      PRBool *aForWindow)
01351 {
01352   if( PR_FALSE == aRealEvent) {
01353     *aForWindow = PR_FALSE;
01354     return NS_OK;
01355   }
01356 #if 0
01357   // Set aForWindow if either:
01358   //   * the message is for a descendent of the given window
01359   //   * the message is for another window, but is a message which
01360   //     should be allowed for a disabled window.
01361  
01362   PRBool isMouseEvent = PR_FALSE;
01363   PRBool isInWindow = PR_FALSE;
01364  
01365   // Examine the target window & find the frame
01366   // XXX should GetNativeData() use GetMainWindow() ?
01367   HWND hwnd = (HWND)GetNativeData(NS_NATIVE_WINDOW);
01368   hwnd = WinQueryWindow(hwnd, QW_PARENT);
01369  
01370   if( hwnd == mQmsg.hwnd || WinIsChild( mQmsg.hwnd, hwnd))
01371      isInWindow = PR_TRUE;
01372   else if (!isInWindow && gRollupWidget &&
01373            EventIsInsideWindow((nsWindow*)gRollupWidget))
01374      // include for consideration any popup menu which may be active at the moment
01375      isInWindow = PR_TRUE;
01376  
01377   // XXX really ought to do something about focus here
01378  
01379   if( !isInWindow)
01380   {
01381      // Block mouse messages for non-modal windows
01382      if( mQmsg.msg >= WM_MOUSEFIRST && mQmsg.msg <= WM_MOUSELAST)
01383         isMouseEvent = PR_TRUE;
01384      else if( mQmsg.msg >= WM_MOUSETRANSLATEFIRST &&
01385               mQmsg.msg <= WM_MOUSETRANSLATELAST)
01386         isMouseEvent = PR_TRUE;
01387      else if( mQmsg.msg == WM_MOUSEENTER || mQmsg.msg == WM_MOUSELEAVE)
01388         isMouseEvent = PR_TRUE;
01389   }
01390  
01391   // set dispatch indicator
01392   *aForWindow = isInWindow || !isMouseEvent;
01393 #else
01394   *aForWindow = PR_TRUE;
01395 #endif
01396 
01397   return NS_OK;
01398 }
01399 
01400 //-------------------------------------------------------------------------
01401 //
01402 // Constrain a potential move to fit onscreen
01403 //
01404 //-------------------------------------------------------------------------
01405 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop,
01406                                       PRInt32 *aX, PRInt32 *aY)
01407 {
01408   if (!mIsTopWidgetWindow) // only a problem for top-level windows
01409     return NS_OK;
01410 
01411   PRBool doConstrain = PR_FALSE; // whether we have enough info to do anything
01412 
01413   /* get our playing field. use the current screen, or failing that
01414     for any reason, use device caps for the default screen. */
01415   RECTL screenRect;
01416 
01417   nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
01418   if (screenmgr) {
01419     nsCOMPtr<nsIScreen> screen;
01420     PRInt32 left, top, width, height;
01421 
01422     // zero size rects confuse the screen manager
01423     width = mBounds.width > 0 ? mBounds.width : 1;
01424     height = mBounds.height > 0 ? mBounds.height : 1;
01425     screenmgr->ScreenForRect(*aX, *aY, width, height,
01426                             getter_AddRefs(screen));
01427     if (screen) {
01428       screen->GetAvailRect(&left, &top, &width, &height);
01429       screenRect.xLeft = left;
01430       screenRect.xRight = left+width;
01431       screenRect.yTop = top;
01432       screenRect.yBottom = top+height;
01433       doConstrain = PR_TRUE;
01434     }
01435   }
01436 
01437 #define kWindowPositionSlop 100
01438 
01439   if (doConstrain) {
01440     if (aAllowSlop) {
01441       if (*aX < screenRect.xLeft - mBounds.width + kWindowPositionSlop)
01442         *aX = screenRect.xLeft - mBounds.width + kWindowPositionSlop;
01443       else if (*aX >= screenRect.xRight - kWindowPositionSlop)
01444         *aX = screenRect.xRight - kWindowPositionSlop;
01445   
01446       if (*aY < screenRect.yTop)
01447         *aY = screenRect.yTop;
01448       else if (*aY >= screenRect.yBottom - kWindowPositionSlop)
01449         *aY = screenRect.yBottom - kWindowPositionSlop;
01450   
01451     } else {
01452   
01453       if (*aX < screenRect.xLeft)
01454         *aX = screenRect.xLeft;
01455       else if (*aX >= screenRect.xRight - mBounds.width)
01456         *aX = screenRect.xRight - mBounds.width;
01457   
01458       if (*aY < screenRect.yTop)
01459         *aY = screenRect.yTop;
01460       else if (*aY >= screenRect.yBottom - mBounds.height)
01461         *aY = screenRect.yBottom - mBounds.height;
01462     }
01463   }
01464 
01465   return NS_OK;
01466 }
01467 
01468 //-------------------------------------------------------------------------
01469 //
01470 // Move this component
01471 //
01472 //-------------------------------------------------------------------------
01473 NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
01474 {
01475    Resize( aX, aY, mBounds.width, mBounds.height, PR_FALSE);
01476    return NS_OK;
01477 }
01478 
01479 //-------------------------------------------------------------------------
01480 //
01481 // Resize this component
01482 //
01483 //-------------------------------------------------------------------------
01484 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
01485 {
01486    Resize( mBounds.x, mBounds.y, aWidth, aHeight, aRepaint);
01487    return NS_OK;
01488 }
01489 
01490 //-------------------------------------------------------------------------
01491 //
01492 // Resize this component
01493 //
01494 //-------------------------------------------------------------------------
01495 NS_METHOD nsWindow::Resize(PRInt32 aX,
01496                       PRInt32 aY,
01497                       PRInt32 w,
01498                       PRInt32 h,
01499                       PRBool   aRepaint)
01500 {
01501   //   NS_ASSERTION((w >=0 ), "Negative width passed to nsWindow::Resize");
01502   //   NS_ASSERTION((h >=0 ), "Negative height passed to nsWindow::Resize");
01503 
01504    // Set cached value for lightweight and printing
01505    mBounds.x      = aX;
01506    mBounds.y      = aY;
01507    mBounds.width  = w;
01508    mBounds.height = h;
01509 
01510    // WinSetWindowPos() appears not to require a msgq
01511    if( mWnd)
01512    {
01513       // need to keep top-left corner in the same place
01514       // work out real coords of top left
01515       POINTL ptl = { aX, aY };
01516       NS2PM_PARENT( ptl);
01517       // work out real coords of bottom left
01518       ptl.y -= h - 1;
01519       if( mParent && mWindowType != eWindowType_popup)
01520       {
01521          WinMapWindowPoints( mParent->mWnd, WinQueryWindow(mWnd, QW_PARENT), &ptl, 1);
01522       }
01523       else if (mWindowType == eWindowType_popup ) {
01524          // aX already gives the right position, just transform aY by hand:
01525          ptl.y = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN) - h - 1 - aY;
01526       }
01527 
01528       if( !SetWindowPos( 0, ptl.x, ptl.y, w, h, SWP_MOVE | SWP_SIZE))
01529          if( aRepaint)
01530             Invalidate(PR_FALSE);
01531 
01532 #if DEBUG_sobotka
01533    printf("+++++++++++Resized 0x%lx at %ld, %ld to %d x %d (%d,%d)\n", mWnd, ptl.x, ptl.y, w, h, aX, aY);
01534 #endif
01535 
01536    }
01537    return NS_OK;
01538 }
01539 
01540 //-------------------------------------------------------------------------
01541 //
01542 // Enable/disable this component
01543 //
01544 //-------------------------------------------------------------------------
01545 NS_METHOD nsWindow::Enable(PRBool bState)
01546 {
01547    if (mWnd) {
01548       WinEnableWindow( GetMainWindow(), !!bState);
01549    }
01550    return NS_OK;
01551 }
01552 
01553 
01554 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
01555 {
01556    NS_ENSURE_ARG_POINTER(aState);
01557    *aState = !mWnd || ::WinIsWindowEnabled(mWnd);
01558    return NS_OK;
01559 }
01560 
01561 
01562 
01563 //-------------------------------------------------------------------------
01564 //
01565 // Give the focus to this component
01566 //
01567 //-------------------------------------------------------------------------
01568 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
01569 {
01570     //
01571     // Switch to the "main gui thread" if necessary... This method must
01572     // be executed on the "gui thread"...
01573     //
01574     // Switch to the PM thread if necessary...
01575     if( !mOS2Toolkit->IsGuiThread())
01576     {
01577         MethodInfo info(this, nsWindow::SET_FOCUS);
01578         mOS2Toolkit->CallMethod(&info);
01579     }
01580     else
01581     if (mWnd) {
01582         if (!mInSetFocus) {
01583            DEBUGFOCUS(SetFocus);
01584            mInSetFocus = TRUE;
01585            WinSetFocus( HWND_DESKTOP, mWnd);
01586            mInSetFocus = FALSE;
01587         }
01588 
01589     }
01590     return NS_OK;
01591 }
01592 
01593 //-------------------------------------------------------------------------
01594 //
01595 // Get this component dimension
01596 //
01597 //-------------------------------------------------------------------------
01598 NS_METHOD nsWindow::GetBounds(nsRect &aRect)
01599 {
01600   if (mFrameWnd) {
01601     SWP swp;
01602     WinQueryWindowPos(mFrameWnd, &swp);
01603     aRect.width = swp.cx;
01604     aRect.height = swp.cy;
01605     aRect.x = swp.x;
01606     aRect.y = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN) - (swp.y+swp.cy);
01607   } else {
01608     aRect = mBounds;
01609   }
01610 
01611   return NS_OK;
01612 }
01613 
01614 //-------------------------------------------------------------------------
01615 //
01616 // Get this component dimension
01617 //
01618 //-------------------------------------------------------------------------
01619 NS_METHOD nsWindow::GetClientBounds(nsRect &aRect)
01620 {
01621 
01622    // nsFrameWindow overrides this...
01623    aRect.x = 0;
01624    aRect.y = 0;
01625    aRect.width = mBounds.width;
01626    aRect.height = mBounds.height;
01627    return NS_OK;
01628 }
01629 
01630 //get the bounds, but don't take into account the client size
01631 
01632 void nsWindow::GetNonClientBounds(nsRect &aRect)
01633 {
01634   if (mWnd) {
01635       RECTL r;
01636       WinQueryWindowRect(mWnd, &r);
01637 
01638       // assign size
01639       aRect.width = r.xRight - r.xLeft;
01640       aRect.height = r.yBottom - r.yTop;
01641 
01642       // convert coordinates if parent exists
01643       HWND parent = WinQueryWindow(mWnd, QW_PARENT);
01644       if (parent) {
01645         RECTL pr;
01646         WinQueryWindowRect(parent, &pr);
01647         r.xLeft -= pr.xLeft;
01648         r.yTop -= pr.yTop;
01649       }
01650       aRect.x = r.xLeft;
01651       aRect.y = r.yTop;
01652   } else {
01653       aRect.SetRect(0,0,0,0);
01654   }
01655 }
01656 
01657 //-------------------------------------------------------------------------
01658 //
01659 // Get this component font
01660 //
01661 //-------------------------------------------------------------------------
01662 nsIFontMetrics *nsWindow::GetFont(void)
01663 {
01664    nsIFontMetrics *metrics = nsnull;
01665 
01666    if( mToolkit)
01667    {
01668       char buf[2][128];
01669       int  ptSize;
01670    
01671       WinQueryPresParam( mWnd, PP_FONTNAMESIZE, 0, 0, 128, buf[0], 0);
01672    
01673       if( 2 == sscanf( buf[0], "%d.%s", &ptSize, buf[1])) // mmm, scanf()...
01674       {
01675          float twip2dev, twip2app;
01676          twip2dev = mContext->TwipsToDevUnits();
01677          twip2app = mContext->DevUnitsToAppUnits();
01678          twip2app *= twip2dev;
01679    
01680          nscoord appSize = (nscoord) (twip2app * ptSize * 20);
01681    
01682          nsFont font( buf[1], NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
01683                       NS_FONT_WEIGHT_NORMAL, 0 /*decoration*/, appSize);
01684    
01685          mContext->GetMetricsFor( font, metrics);
01686       }
01687    }
01688 
01689    return metrics;
01690 }
01691 
01692 //-------------------------------------------------------------------------
01693 //
01694 // Set this component font
01695 //
01696 //-------------------------------------------------------------------------
01697 NS_METHOD nsWindow::SetFont(const nsFont &aFont)
01698 {
01699    if( mToolkit) // called from print-routine (XXX check)
01700    {
01701       // jump through hoops to convert the size in the font (in app units)
01702       // into points. 
01703       float dev2twip, app2twip;
01704       dev2twip = mContext->DevUnitsToTwips();
01705       app2twip = mContext->AppUnitsToDevUnits();
01706       app2twip *= dev2twip;
01707       int points = NSTwipsToFloorIntPoints( nscoord( aFont.size * app2twip));
01708 
01709       nsAutoCharBuffer fontname;
01710       PRInt32 fontnameLength;
01711       WideCharToMultiByte(0, aFont.name.get(), aFont.name.Length(),
01712                           fontname, fontnameLength);
01713 
01714       char *buffer = new char[fontnameLength + 6];
01715       if (buffer) {
01716         sprintf(buffer, "%d.%s", points, fontname.get());
01717         ::WinSetPresParam(mWnd, PP_FONTNAMESIZE,
01718                           strlen(buffer) + 1, buffer);
01719         delete [] buffer;
01720       }
01721    }
01722 
01723    if( !mFont)
01724       mFont = new nsFont( aFont);
01725    else
01726       *mFont = aFont;
01727 
01728    return NS_OK;
01729 }
01730 
01731 //-------------------------------------------------------------------------
01732 //
01733 // Set this component cursor
01734 //
01735 //-------------------------------------------------------------------------
01736 
01737 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
01738 {
01739   HPOINTER newPointer = NULLHANDLE;
01740 
01741   switch (aCursor) {
01742     case eCursor_select:
01743       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_TEXT, FALSE);
01744       break;
01745       
01746     case eCursor_wait:
01747       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE);
01748       break;
01749   
01750     case eCursor_hyperlink:
01751       newPointer = gPtrArray[IDC_SELECTANCHOR-IDC_BASE];
01752       break;
01753   
01754     case eCursor_standard:
01755       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE);
01756       break;
01757   
01758     case eCursor_n_resize:
01759     case eCursor_s_resize:
01760       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_SIZENS, FALSE);
01761       break;
01762   
01763     case eCursor_w_resize:
01764     case eCursor_e_resize:
01765       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_SIZEWE, FALSE);
01766       break;
01767   
01768     case eCursor_nw_resize:
01769     case eCursor_se_resize:
01770       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_SIZENWSE, FALSE);
01771       break;
01772   
01773     case eCursor_ne_resize:
01774     case eCursor_sw_resize:
01775       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_SIZENESW, FALSE);
01776       break;
01777   
01778     case eCursor_crosshair:
01779       newPointer = gPtrArray[IDC_CROSS-IDC_BASE];
01780       break;
01781                
01782     case eCursor_move:
01783       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_MOVE, FALSE);
01784       break;
01785   
01786     case eCursor_help:
01787       newPointer = gPtrArray[IDC_HELP-IDC_BASE];
01788       break;
01789   
01790     case eCursor_copy: // CSS3
01791       newPointer = gPtrArray[IDC_COPY-IDC_BASE];
01792       break;
01793   
01794     case eCursor_alias:
01795       newPointer = gPtrArray[IDC_ALIAS-IDC_BASE];
01796       break;
01797   
01798     case eCursor_cell:
01799       newPointer = gPtrArray[IDC_CELL-IDC_BASE];
01800       break;
01801   
01802     case eCursor_grab:
01803       newPointer = gPtrArray[IDC_GRAB-IDC_BASE];
01804       break;
01805   
01806     case eCursor_grabbing:
01807       newPointer = gPtrArray[IDC_GRABBING-IDC_BASE];
01808       break;
01809   
01810     case eCursor_spinning:
01811       newPointer = gPtrArray[IDC_ARROWWAIT-IDC_BASE];
01812       break;
01813   
01814     case eCursor_context_menu:
01815       // XXX this CSS3 cursor needs to be implemented
01816       break;
01817   
01818     case eCursor_zoom_in:
01819       newPointer = gPtrArray[IDC_ZOOMIN-IDC_BASE];
01820       break;
01821   
01822     case eCursor_zoom_out:
01823       newPointer = gPtrArray[IDC_ZOOMOUT-IDC_BASE];
01824       break;
01825   
01826     case eCursor_not_allowed:
01827     case eCursor_no_drop:
01828       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_ILLEGAL, FALSE);
01829       break;
01830   
01831     case eCursor_col_resize:
01832       newPointer = gPtrArray[IDC_COLRESIZE-IDC_BASE];
01833       break;
01834   
01835     case eCursor_row_resize:
01836       newPointer = gPtrArray[IDC_ROWRESIZE-IDC_BASE];
01837       break;
01838   
01839     case eCursor_vertical_text:
01840       newPointer = gPtrArray[IDC_VERTICALTEXT-IDC_BASE];
01841       break;
01842   
01843     case eCursor_all_scroll:
01844       // XXX not 100% appropriate perhaps
01845       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_MOVE, FALSE);
01846       break;
01847   
01848     case eCursor_nesw_resize:
01849       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_SIZENESW, FALSE);
01850       break;
01851   
01852     case eCursor_nwse_resize:
01853       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_SIZENWSE, FALSE);
01854       break;
01855   
01856     case eCursor_ns_resize:
01857       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_SIZENS, FALSE);
01858       break;
01859   
01860     case eCursor_ew_resize:
01861       newPointer = ::WinQuerySysPointer(HWND_DESKTOP, SPTR_SIZEWE, FALSE);
01862       break;
01863   
01864     default:
01865       NS_ASSERTION(0, "Invalid cursor type");
01866       break;
01867   }
01868 
01869   if (newPointer) {
01870     WinSetPointer(HWND_DESKTOP, newPointer);
01871   }
01872 
01873   return NS_OK;
01874 }
01875 
01876 //-------------------------------------------------------------------------
01877 
01878 // create a mouse pointer on the fly to support the CSS 'cursor' style;
01879 // this code is based on the Win version by C. Biesinger but has been
01880 // substantially modified to accommodate platform differences and to
01881 // improve efficiency
01882 
01883 NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
01884                                   PRUint32 aHotspotX, PRUint32 aHotspotY)
01885 {
01886 
01887   // if this is the same image as last time, reuse the saved hptr;
01888   // it will be destroyed when we create a new one or when the
01889   // current window is destroyed
01890   if (mCssCursorImg == aCursor && mCssCursorHPtr) {
01891     WinSetPointer(HWND_DESKTOP, mCssCursorHPtr);
01892     return NS_OK;
01893   }
01894 
01895   nsCOMPtr<gfxIImageFrame> frame;
01896   aCursor->GetFrameAt(0, getter_AddRefs(frame));
01897   if (!frame)
01898     return NS_ERROR_NOT_AVAILABLE;
01899 
01900   // if the image is ridiculously large, exit because
01901   // it will be unrecognizable when shrunk to 32x32
01902   PRInt32 width, height;
01903   frame->GetWidth(&width);
01904   frame->GetHeight(&height);
01905   if (width > 128 || height > 128)
01906     return NS_ERROR_FAILURE;
01907 
01908   gfx_format format;
01909   nsresult rv = frame->GetFormat(&format);
01910   if (NS_FAILED(rv))
01911     return rv;
01912 
01913   // only 24-bit images with 0, 1, or 8-bit alpha data are supported
01914   if (format != gfxIFormats::BGR_A1 && format != gfxIFormats::BGR_A8 &&
01915       format != gfxIFormats::BGR)
01916     return NS_ERROR_UNEXPECTED;
01917 
01918   frame->LockImageData();
01919   PRUint32 dataLen;
01920   PRUint8* data;
01921   rv = frame->GetImageData(&data, &dataLen);
01922   if (NS_FAILED(rv)) {
01923     frame->UnlockImageData();
01924     return rv;
01925   }
01926 
01927   // create the color bitmap
01928   HBITMAP hBmp = 0;
01929   hBmp = DataToBitmap(data, width, height, 24);
01930   frame->UnlockImageData();
01931   if (!hBmp)
01932     return NS_ERROR_FAILURE;
01933 
01934   // create a transparency mask from the alpha data;
01935   HBITMAP hAlpha = 0;
01936 
01937   // image has no alpha data - make the pointer opaque
01938   if (format == gfxIFormats::BGR) {
01939     hAlpha = CreateTransparencyMask(format, 0, width, height);
01940     if (!hAlpha) {
01941       GpiDeleteBitmap(hBmp);
01942       return NS_ERROR_FAILURE;
01943     }
01944   }
01945   // image has either 1 or 8 bits of alpha data
01946   else {
01947     PRUint8* adata;
01948     frame->LockAlphaData();
01949     rv = frame->GetAlphaData(&adata, &dataLen);
01950     if (NS_FAILED(rv)) {
01951       GpiDeleteBitmap(hBmp);
01952       frame->UnlockAlphaData();
01953       return rv;
01954     }
01955 
01956     // create the bitmap
01957     hAlpha = CreateTransparencyMask(format, adata, width, height);
01958     frame->UnlockAlphaData();
01959     if (!hAlpha) {
01960       GpiDeleteBitmap(hBmp);
01961       return NS_ERROR_FAILURE;
01962     }
01963   }
01964 
01965   POINTERINFO info = {0};
01966   info.fPointer = TRUE;
01967   info.xHotspot = aHotspotX;
01968   info.yHotspot = height - aHotspotY - 1;
01969   info.hbmPointer = hAlpha;
01970   info.hbmColor = hBmp;
01971 
01972   // create the pointer
01973   HPOINTER cursor = WinCreatePointerIndirect(HWND_DESKTOP, &info);
01974   GpiDeleteBitmap(hBmp);
01975   GpiDeleteBitmap(hAlpha);
01976   if (cursor == NULL)
01977     return NS_ERROR_FAILURE;
01978 
01979   // use it
01980   WinSetPointer(HWND_DESKTOP, cursor);
01981 
01982   // destroy the previous hptr;  this has to be done after the
01983   // new pointer is set or else WinDestroyPointer() will fail
01984   if (mCssCursorHPtr)
01985     WinDestroyPointer(mCssCursorHPtr);
01986 
01987   // save the hptr and a reference to the image for next time
01988   mCssCursorHPtr = cursor;
01989   mCssCursorImg = aCursor;
01990 
01991   return NS_OK;
01992 }
01993 
01994 //-------------------------------------------------------------------------
01995 
01996 // render image or modified alpha data as a native bitmap
01997 
01998 // aligned bytes per row, rounded up to next dword bounday
01999 #define ALIGNEDBPR(cx,bits) ( ( ( ((cx)*(bits)) + 31) / 32) * 4)
02000 
02001 HBITMAP nsWindow::DataToBitmap(PRUint8* aImageData, PRUint32 aWidth,
02002                                PRUint32 aHeight, PRUint32 aDepth)
02003 {
02004   // get a presentation space for this window
02005   HPS hps = (HPS)GetNativeData(NS_NATIVE_GRAPHIC);
02006   if (!hps)
02007     return 0;
02008 
02009   // a handy structure that does double duty
02010   // as both BITMAPINFOHEADER2 & BITMAPINFO2
02011   struct {
02012     BITMAPINFOHEADER2 head;
02013     RGB2 black;
02014     RGB2 white;
02015   } bi;
02016 
02017   memset( &bi, 0, sizeof(bi));
02018   bi.white.bBlue = 255;
02019   bi.white.bGreen = 255;
02020   bi.white.bRed = 255;
02021 
02022   // fill in the particulars
02023   bi.head.cbFix = sizeof(bi.head);
02024   bi.head.cx = aWidth;
02025   bi.head.cy = aHeight;
02026   bi.head.cPlanes = 1;
02027   bi.head.cBitCount = aDepth;
02028   bi.head.ulCompression = BCA_UNCOMP;
02029   bi.head.cbImage = ALIGNEDBPR(aWidth, aDepth) * aHeight;
02030   bi.head.cclrUsed = (aDepth == 1 ? 2 : 0);
02031 
02032   // create a bitmap from the image data
02033   HBITMAP hBmp = GpiCreateBitmap(hps, &bi.head, CBM_INIT,
02034                  NS_REINTERPRET_CAST(const BYTE*, aImageData),
02035                  (BITMAPINFO2*)&bi);
02036 
02037   // free the hps, then return the bitmap
02038   FreeNativeData((void*)hps, NS_NATIVE_GRAPHIC);
02039   return hBmp;
02040 }
02041 
02042 //-------------------------------------------------------------------------
02043 
02044 // create a monochrome AND/XOR bitmap from 0, 1, or 8-bit alpha data
02045 
02046 HBITMAP nsWindow::CreateTransparencyMask(gfx_format format,
02047                                          PRUint8* aImageData,
02048                                          PRUint32 aWidth,
02049                                          PRUint32 aHeight)
02050 {
02051   // calc width in bytes, rounding up to a dword boundary
02052   PRUint32 abpr = ALIGNEDBPR(aWidth, 1);
02053   PRUint32 cbData = abpr * aHeight;
02054 
02055   // alloc space to hold both the AND & XOR bitmaps
02056   PRUint8* mono = (PRUint8*)malloc(cbData * 2);
02057   if (!mono)
02058     return NULL;
02059 
02060   // init the XOR bitmap to produce either black or transparent pixels
02061   memset(mono, 0x00, cbData);
02062 
02063   switch (format) {
02064 
02065     // make the AND mask opaque
02066     case gfxIFormats::BGR:
02067       memset(&mono[cbData], 0x00, cbData);
02068       break;
02069 
02070     // make the AND mask the inverse of the 1-bit alpha data
02071     case gfxIFormats::BGR_A1: {
02072       PRUint32* pSrc = (PRUint32*)aImageData;
02073       PRUint32* pAnd = (PRUint32*)&mono[cbData];
02074 
02075       for (PRUint32 dataNdx = 0; dataNdx < cbData; dataNdx += 4)
02076         *pAnd++ = ~(*pSrc++);
02077 
02078       break;
02079     }
02080 
02081     // make the AND mask the inverse of the 8-bit alpha data
02082     case gfxIFormats::BGR_A8: {
02083       PRUint8*  pSrc = aImageData;
02084       PRUint32* pAnd = (PRUint32*)&mono[cbData];
02085 
02086       // if aWidth isn't a multiple of 4, the input contains byte padding;
02087       // if aWidth isn't a multiple of 32, the output contains bit padding
02088       for (PRUint32 dataNdx = 0; dataNdx < cbData; dataNdx += 4) {
02089         PRUint32 dst = 0;
02090         PRUint32 colNdx = 0;
02091 
02092         // construct an output dword, then save
02093         for (PRUint32 byteNdx = 0; byteNdx < 4; byteNdx++) {
02094           PRUint32 mask = 0x80 << (byteNdx * 8);
02095 
02096           // construct an output byte from 8 input bytes
02097           for (PRUint32 bitNdx = 0; bitNdx < 8; bitNdx++) {
02098             if (*pSrc++ < 128)
02099               dst |= mask;
02100             mask >>= 1;
02101 
02102             // at the end of a row, skip over any padding in the
02103             // input, then break out of the byte & dword loops
02104             if (++colNdx >= aWidth) {
02105               pSrc += (4 - (aWidth & 3)) & 3;
02106               break;
02107             }
02108           }
02109           if (colNdx >= aWidth)
02110             break;
02111         }
02112         *pAnd++ = dst;
02113       }
02114 
02115       break;
02116     }
02117   }
02118 
02119   // create the bitmap
02120   HBITMAP hAlpha = DataToBitmap(mono, aWidth, aHeight * 2, 1);
02121 
02122   // free the buffer, then return the bitmap
02123   free(mono);
02124   return hAlpha;
02125 }
02126 
02127 //-------------------------------------------------------------------------
02128 
02129 NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide) 
02130 {
02131   HWND hwndFrame = NULLHANDLE;
02132   HWND hwndTitleBar = NULLHANDLE;
02133   HWND hwndSysMenu = NULLHANDLE;
02134   HWND hwndMinMax = NULLHANDLE;
02135   HWND hwndParent;
02136   ULONG ulStyle;
02137   char className[19];
02138 
02139   HWND hwnd = (HWND)GetNativeData(NS_NATIVE_WINDOW);
02140   for ( ; hwnd != NULLHANDLE; hwnd = WinQueryWindow(hwnd, QW_PARENT)) {
02141     ::WinQueryClassName(hwnd, 19, className);
02142     if (strcmp(className, WC_FRAME_STRING) == 0)
02143     {
02144       hwndFrame = hwnd;
02145       break;
02146     }
02147   }
02148 
02149 
02150   if (aShouldHide) {
02151     hwndParent = HWND_OBJECT;
02152     mChromeHidden = TRUE;
02153   } else {
02154     hwndParent = hwndFrame;
02155     mChromeHidden = FALSE;
02156   }
02157   hwndTitleBar = (HWND)WinQueryProperty(hwndFrame, "hwndTitleBar");
02158   if (hwndTitleBar)
02159     WinSetParent(hwndTitleBar, hwndParent, TRUE);
02160   hwndSysMenu = (HWND)WinQueryProperty(hwndFrame, "hwndSysMenu");
02161   if (hwndSysMenu)
02162     WinSetParent(hwndSysMenu, hwndParent, TRUE);
02163   hwndMinMax = (HWND)WinQueryProperty(hwndFrame, "hwndMinMax");
02164   if (hwndMinMax)
02165     WinSetParent(hwndMinMax, hwndParent, TRUE);
02166   if (aShouldHide) {
02167     ulStyle = (ULONG)WinQueryWindowULong(hwndFrame, QWL_STYLE);
02168     WinSetWindowULong(hwndFrame, QWL_STYLE, ulStyle & ~FS_SIZEBORDER);
02169     WinSetProperty(hwndFrame, "ulStyle", (PVOID)ulStyle, 0);
02170     WinSendMsg(hwndFrame, WM_UPDATEFRAME, 0, 0);
02171   } else {
02172     ulStyle = (ULONG)WinQueryProperty(hwndFrame, "ulStyle");
02173     WinSetWindowULong(hwndFrame, QWL_STYLE, ulStyle);
02174     WinSendMsg(hwndFrame, WM_UPDATEFRAME, MPFROMLONG(FCF_TITLEBAR | FCF_SYSMENU | FCF_MINMAX), 0);
02175   }
02176 
02177   return NS_OK;
02178 }
02179 
02180 //-------------------------------------------------------------------------
02181 //
02182 // Invalidate this component visible area
02183 //
02184 //-------------------------------------------------------------------------
02185 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
02186 {
02187     if (mWnd)
02188     {
02189       WinInvalidateRect( mWnd, 0, FALSE);
02190 #if 0
02191       if( PR_TRUE == aIsSynchronous) {
02192          Update();
02193       }
02194 #endif
02195     }
02196 
02197     return NS_OK;
02198 }
02199 
02200 //-------------------------------------------------------------------------
02201 //
02202 // Invalidate this component visible area
02203 //
02204 //-------------------------------------------------------------------------
02205 NS_METHOD nsWindow::Invalidate(const nsRect &aRect, PRBool aIsSynchronous)
02206 {
02207   if (mWnd)
02208   {
02209     RECTL rcl = { aRect.x, aRect.y, aRect.x + aRect.width, aRect.y + aRect.height };
02210     NS2PM( rcl);
02211 
02212     WinInvalidateRect( mWnd, &rcl, FALSE);
02213 #if 0
02214     if( PR_TRUE == aIsSynchronous) {
02215       Update();
02216     }
02217 #endif
02218   }
02219   return NS_OK;
02220 }
02221 
02222 NS_IMETHODIMP 
02223 nsWindow::InvalidateRegion(const nsIRegion *aRegion, PRBool aIsSynchronous)
02224 
02225 {
02226   nsresult rv = NS_OK;
02227   if (mWnd) {
02228     PRInt32 aX, aY, aWidth, aHeight;
02229     ((nsIRegion*)aRegion)->GetBoundingBox (&aX, &aY, &aWidth, &aHeight);
02230 
02231     RECTL rcl = { aX, aY, aX + aWidth, aY + aHeight };
02232     NS2PM (rcl);
02233     WinInvalidateRect (mWnd, &rcl, FALSE);
02234 
02235 #if 0
02236         if( PR_TRUE == aIsSynchronous) {
02237           Update();
02238         }
02239 #endif
02240 
02241   }
02242   return rv;  
02243 }
02244 
02245 //-------------------------------------------------------------------------
02246 //
02247 // Force a synchronous repaint of the window
02248 //
02249 //-------------------------------------------------------------------------
02250 NS_IMETHODIMP nsWindow::Update()
02251 {
02252   // Switch to the PM thread if necessary...
02253   if( !mOS2Toolkit->IsGuiThread())
02254   {
02255     MethodInfo info(this, nsWindow::UPDATE_WINDOW);
02256     mOS2Toolkit->CallMethod(&info);
02257   }
02258   else 
02259   if (mWnd)
02260     WinUpdateWindow( mWnd);
02261   return NS_OK;
02262 }
02263 
02264 //-------------------------------------------------------------------------
02265 //
02266 // Return some native data according to aDataType
02267 //
02268 //-------------------------------------------------------------------------
02269 void* nsWindow::GetNativeData(PRUint32 aDataType)
02270 {
02271     switch(aDataType) {
02272         case NS_NATIVE_WIDGET:
02273         case NS_NATIVE_WINDOW:
02274         case NS_NATIVE_PLUGIN_PORT:
02275             return (void*)mWnd;
02276 
02277         case NS_NATIVE_GRAPHIC: {
02278         // during a native drag over the current window or any drag
02279         // originating in Moz, return a drag HPS to avoid screen corruption;
02280             HPS hps = 0;
02281             CheckDragStatus(ACTION_DRAW, &hps);
02282             if (!hps)
02283               hps = WinGetPS(mWnd);
02284             nsPaletteOS2::SelectGlobalPalette(hps, mWnd);
02285             return (void*)hps;
02286         }
02287 
02288         case NS_NATIVE_COLORMAP:
02289         default: 
02290             break;
02291     }
02292 
02293     return NULL;
02294 }
02295 
02296 //~~~
02297 void nsWindow::FreeNativeData(void * data, PRUint32 aDataType)
02298 {
02299   switch(aDataType)
02300   {
02301     case NS_NATIVE_GRAPHIC:
02302       if (data) {
02303         if (!ReleaseIfDragHPS((HPS)data))
02304           WinReleasePS((HPS)data);
02305       }
02306       break;
02307     case NS_NATIVE_WIDGET:
02308     case NS_NATIVE_WINDOW:
02309     case NS_NATIVE_PLUGIN_PORT:
02310     case NS_NATIVE_COLORMAP:
02311       break;
02312     default: 
02313       break;
02314   }
02315 }
02316 
02317 //-------------------------------------------------------------------------
02318 //
02319 // Set the colormap of the window
02320 //
02321 //-------------------------------------------------------------------------
02322 NS_METHOD nsWindow::SetColorMap(nsColorMap *aColorMap)
02323 {
02324    // SetColorMap - not implemented.
02325    // Any palette lives in the device context & should be altered there.
02326    // And shouldn't be altered at all, once libimg has decided what should
02327    // be in it.  So my opinion is this method shouldn't be called.
02328    return NS_ERROR_NOT_IMPLEMENTED;
02329 }
02330 
02331 //-------------------------------------------------------------------------
02332 //
02333 // Notify a child window of a coming move by sending it a WM_VRNDISABLED
02334 // message. Only do that if it's not one of ours like e.g. plugin windows.
02335 //
02336 //-------------------------------------------------------------------------
02337 BOOL nsWindow::NotifyForeignChildWindows(HWND aWnd)
02338 {
02339   HENUM hEnum = WinBeginEnumWindows(aWnd);
02340   HWND hwnd;
02341 
02342   while ((hwnd = WinGetNextWindow(hEnum)) != NULLHANDLE) {
02343     char className[19];
02344     WinQueryClassName(hwnd, 19, className);
02345     if (strcmp(className, WindowClass()) != 0) {
02346       // This window is not one of our windows so notify it (and wait for
02347       // the call to return so that the plugin has time to react)
02348       WinSendMsg(hwnd, WM_VRNDISABLED, MPVOID, MPVOID);
02349     } else {
02350       // Recurse starting at this Mozilla child window.
02351       NotifyForeignChildWindows(hwnd);
02352     }
02353   }
02354   return WinEndEnumWindows(hEnum);
02355 }
02356 
02357 //-------------------------------------------------------------------------
02358 //
02359 // Scroll the bits of a window
02360 //
02361 //-------------------------------------------------------------------------
02362 //XXX Scroll is obsolete and should go away soon
02363 NS_METHOD nsWindow::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect)
02364 {
02365   RECTL rcl;
02366 
02367   if (nsnull != aClipRect)
02368   {
02369     rcl.xLeft = aClipRect->x;
02370     rcl.yBottom = aClipRect->y + aClipRect->height;
02371     rcl.xRight = rcl.xLeft + aClipRect->width;
02372     rcl.yTop = rcl.yBottom + aClipRect->height;
02373     NS2PM( rcl);
02374     // this rect is inex
02375   }
02376 
02377     // this prevents screen corruption while scrolling during a
02378     // Moz-originated drag - during a native drag, the screen
02379     // isn't updated until the drag ends. so there's no corruption
02380   HPS hps = 0;
02381   CheckDragStatus(ACTION_SCROLL, &hps);
02382 
02383   NotifyForeignChildWindows(mWnd);
02384   WinScrollWindow( mWnd, aDx, -aDy, aClipRect ? &rcl : 0, 0, 0,
02385                    0, SW_SCROLLCHILDREN | SW_INVALIDATERGN);
02386   Update();
02387 
02388   if (hps)
02389     ReleaseIfDragHPS(hps);
02390 
02391   return NS_OK;
02392 }
02393 
02394 NS_IMETHODIMP nsWindow::ScrollWidgets(PRInt32 aDx, PRInt32 aDy)
02395 {
02396     // this prevents screen corruption while scrolling during a
02397     // Moz-originated drag - during a native drag, the screen
02398     // isn't updated until the drag ends. so there's no corruption
02399   HPS hps = 0;
02400   CheckDragStatus(ACTION_SCROLL, &hps);
02401 
02402     // Scroll the entire contents of the window + change the offset of any child windows
02403   WinScrollWindow( mWnd, aDx, -aDy, 0, 0, 0, 0,
02404                    SW_INVALIDATERGN | SW_SCROLLCHILDREN);
02405   Update(); // Force synchronous generation of NS_PAINT
02406 
02407   if (hps)
02408     ReleaseIfDragHPS(hps);
02409 
02410   return NS_OK;
02411 }
02412 
02413 NS_IMETHODIMP nsWindow::ScrollRect(nsRect &aRect, PRInt32 aDx, PRInt32 aDy)
02414 {
02415   RECTL rcl;
02416 
02417   rcl.xLeft = aRect.x;
02418   rcl.yBottom = aRect.y + aRect.height;
02419   rcl.xRight = rcl.xLeft + aRect.width;
02420   rcl.yTop = rcl.yBottom + aRect.height;
02421   NS2PM( rcl);
02422 
02423     // this prevents screen corruption while scrolling during a
02424     // Moz-originated drag - during a native drag, the screen
02425     // isn't updated until the drag ends. so there's no corruption
02426   HPS hps = 0;
02427   CheckDragStatus(ACTION_SCROLL, &hps);
02428 
02429     // Scroll the bits in the window defined by trect. 
02430     // Child windows are not scrolled.
02431   WinScrollWindow(mWnd, aDx, -aDy, &rcl, 0, 0, 0, SW_INVALIDATERGN);
02432   Update(); // Force synchronous generation of NS_PAINT
02433 
02434   if (hps)
02435     ReleaseIfDragHPS(hps);
02436 
02437   return NS_OK;
02438 }
02439 
02440 
02441 //-------------------------------------------------------------------------
02442 //
02443 // Every function that needs a thread switch goes through this function
02444 // by calling SendMessage (..WM_CALLMETHOD..) in nsToolkit::CallMethod.
02445 //
02446 //-------------------------------------------------------------------------
02447 BOOL nsWindow::CallMethod(MethodInfo *info)
02448 {
02449     BOOL bRet = TRUE;
02450 
02451     switch (info->methodId) {
02452         case nsWindow::CREATE:
02453             NS_ASSERTION(info->nArgs == 7, "Wrong number of arguments to CallMethod Create");
02454             DoCreate( (HWND)               info->args[0],
02455                       (nsWindow*)          info->args[1],
02456                       (const nsRect&)*(nsRect*) (info->args[2]),
02457                       (EVENT_CALLBACK)    (info->args[3]), 
02458                       (nsIDeviceContext*) (info->args[4]),
02459                       (nsIAppShell*)      (info->args[5]),
02460                       nsnull, /* toolkit */
02461                       (nsWidgetInitData*) (info->args[6]));
02462             break;
02463 
02464         case nsWindow::DESTROY:
02465             NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod Destroy");
02466             Destroy();
02467             break;
02468 
02469         case nsWindow::SET_FOCUS:
02470             NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod SetFocus");
02471             SetFocus(PR_FALSE);
02472             break;
02473 
02474         case nsWindow::UPDATE_WINDOW:
02475             NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod UpdateWindow");
02476             Update();
02477             break;
02478 
02479         case nsWindow::SET_TITLE:
02480             NS_ASSERTION(info->nArgs == 1, "Wrong number of arguments to CallMethod SetTitle");
02481             SetTitle( (const nsAString &) info->args[0]);
02482             break;
02483 
02484         case nsWindow::GET_TITLE:
02485             NS_ASSERTION(info->nArgs == 2, "Wrong number of arguments to CallMethod GetTitle");
02486             GetWindowText( *((nsString*) info->args[0]),
02487                            (PRUint32*)info->args[1]);
02488             break;
02489 
02490         default:
02491             bRet = FALSE;
02492             break;
02493     }
02494 
02495     return bRet;
02496 }
02497 
02498 //-------------------------------------------------------------------------
02499 // OnKey
02500 //-------------------------------------------------------------------------
02501 // Key handler.  Specs for the various text messages are really confused;
02502 // see other platforms for best results of how things are supposed to work.
02503 //
02504 // Perhaps more importantly, the main man listening to these events (besides
02505 // random bits of javascript) is ender -- see 
02506 // mozilla/editor/base/nsEditorEventListeners.cpp.
02507 PRBool nsWindow::OnKey(MPARAM mp1, MPARAM mp2)
02508 {
02509   nsKeyEvent pressEvent(PR_TRUE, 0, nsnull);
02510   USHORT fsFlags = SHORT1FROMMP(mp1);
02511   USHORT usVKey = SHORT2FROMMP(mp2);
02512   USHORT usChar = SHORT1FROMMP(mp2);
02513   UCHAR uchScan = CHAR4FROMMP(mp1);
02514 
02515   // It appears we're not supposed to transmit shift, control & alt events
02516   // to gecko.  Shrug.
02517   //
02518   // this is what gtk is doing...
02519   if (fsFlags & KC_VIRTUALKEY && !(fsFlags & KC_KEYUP) &&
02520       (usVKey == VK_SHIFT || usVKey == VK_CTRL || usVKey == VK_ALTGRAF) ) {
02521     return PR_FALSE;
02522   }
02523 
02524   // My gosh this is ugly
02525   // Workaround bug where using Alt+Esc let an Alt key creep through
02526   // Only handle alt by itself if the LONEKEY bit is set
02527   if ((fsFlags & KC_VIRTUALKEY) && (usVKey == VK_ALT) && !usChar &&
02528       ((fsFlags & KC_LONEKEY) == 0) && (fsFlags & KC_KEYUP)) {
02529     return PR_FALSE;
02530   }
02531 
02532   // Now check if it's a dead-key
02533   if (fsFlags & KC_DEADKEY) {
02534     // CUA says we're supposed to give some kind of feedback `display
02535     // the dead key glyph'.  I'm not sure if we can use the COMPOSE
02536     // messagesto do this -- it should really be done by someone who can
02537     // test it & has some idea what `ought' to happen...
02538     return PR_TRUE;
02539   }
02540 
02541   // Now dispatch a keyup/keydown event.  This one is *not* meant to
02542   // have the unicode charcode in.
02543   nsPoint point(0,0);
02544   nsKeyEvent event(PR_TRUE, (fsFlags & KC_KEYUP) ? NS_KEY_UP : NS_KEY_DOWN,
02545                    this);
02546   InitEvent(event, &point);
02547   event.keyCode = WMChar2KeyCode(mp1, mp2);
02548   event.isShift = (fsFlags & KC_SHIFT) ? PR_TRUE : PR_FALSE;
02549   event.isControl = (fsFlags & KC_CTRL) ? PR_TRUE : PR_FALSE;
02550   event.isAlt = (fsFlags & KC_ALT) ? PR_TRUE : PR_FALSE;
02551   event.isMeta = PR_FALSE;
02552   event.charCode = 0;
02553 
02554   // Checking for a scroll mouse event vs. a keyboard event
02555   // The way we know this is that the repeat count is 0 and
02556   // the key is not physically down
02557   // unfortunately, there is an exception here - if alt or ctrl are
02558   // held down, repeat count is set so we have to add special checks for them
02559   if (((event.keyCode == NS_VK_UP) || (event.keyCode == NS_VK_DOWN)) &&
02560       !(fsFlags & KC_KEYUP) &&
02561       ((CHAR3FROMMP(mp1) == 0) || fsFlags & KC_CTRL || fsFlags & KC_ALT) ) {
02562     if (!(WinGetPhysKeyState(HWND_DESKTOP, uchScan) & 0x8000)) {
02563       MPARAM mp2;
02564       if (event.keyCode == NS_VK_UP)
02565         mp2 = MPFROM2SHORT(0, SB_LINEUP);
02566       else
02567         mp2 = MPFROM2SHORT(0, SB_LINEDOWN);
02568       WinSendMsg(mWnd, WM_VSCROLL, 0, mp2);
02569       return FALSE;
02570     }
02571   }
02572 
02573   pressEvent = event;
02574   PRBool rc = DispatchWindowEvent(&event);
02575 
02576   // Break off now if this was a key-up.
02577   if (fsFlags & KC_KEYUP) {
02578     NS_RELEASE(event.widget);
02579     return rc;
02580   }
02581 
02582   // Break off if we've got an "invalid composition" -- that is, the user
02583   // typed a deadkey last time, but has now typed something that doesn't
02584   // make sense in that context.
02585   if (fsFlags & KC_INVALIDCOMP) {
02586     mHaveDeadKey = FALSE;
02587     // actually, not sure whether we're supposed to abort the keypress
02588     // or process it as though the dead key has been pressed.
02589     NS_RELEASE(event.widget);
02590     return rc;
02591   }
02592 
02593   // Now we need to dispatch a keypress event which has the unicode char.
02594   pressEvent.message = NS_KEY_PRESS;
02595   if (rc) { // If keydown default was prevented, do same for keypress
02596     pressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
02597   }
02598 
02599   if (usChar) {
02600     USHORT inbuf[2];
02601     inbuf[0] = usChar;
02602     inbuf[1] = '\0';
02603 
02604     nsAutoChar16Buffer outbuf;
02605     PRInt32 bufLength;
02606     MultiByteToWideChar(0, (const char*)inbuf, 2, outbuf, bufLength);
02607 
02608     pressEvent.charCode = outbuf.get()[0];
02609 
02610     if (pressEvent.isControl && !(fsFlags & (KC_VIRTUALKEY | KC_DEADKEY))) {
02611       if (!pressEvent.isShift && (pressEvent.charCode >= 'A' && pressEvent.charCode <= 'Z')) {
02612         pressEvent.charCode = tolower(pressEvent.charCode);
02613       }
02614       if (pressEvent.isShift && (pressEvent.charCode >= 'a' && pressEvent.charCode <= 'z')) {
02615         pressEvent.charCode = toupper(pressEvent.charCode);
02616       }
02617       pressEvent.keyCode = 0;
02618     } else if (!pressEvent.isControl && !pressEvent.isAlt && pressEvent.charCode != 0) {
02619       if (!(fsFlags & KC_VIRTUALKEY) || // not virtual key
02620           ((fsFlags & KC_CHAR) && (pressEvent.keyCode == 0)) ) { //
02621         pressEvent.keyCode = 0;
02622       } else if (usVKey == VK_SPACE) {
02623         // space key, do nothing here
02624       } else if ((fsFlags & KC_VIRTUALKEY) &&
02625                  isNumPadScanCode(uchScan) && pressEvent.keyCode != 0 && isNumlockOn) {
02626         // this is NumLock+Numpad (no Alt), handle this like a normal number
02627         pressEvent.keyCode = 0;
02628       } else { // Real virtual key
02629         pressEvent.charCode = 0;
02630       }
02631     }
02632     rc = DispatchWindowEvent(&pressEvent);
02633   }
02634 
02635   NS_RELEASE(pressEvent.widget);
02636   return rc;
02637 }
02638 
02639 void nsWindow::ConstrainZLevel(HWND *aAfter) {
02640 
02641   nsZLevelEvent  event(PR_TRUE, NS_SETZLEVEL, this);
02642   nsWindow      *aboveWindow = 0;
02643 
02644   InitEvent(event);
02645 
02646   if (*aAfter == HWND_BOTTOM)
02647     event.mPlacement = nsWindowZBottom;
02648   else if (*aAfter == HWND_TOP)
02649     event.mPlacement = nsWindowZTop;
02650   else {
02651     event.mPlacement = nsWindowZRelative;
02652     aboveWindow = GetNSWindowPtr(*aAfter);
02653   }
02654   event.mReqBelow = aboveWindow;
02655   event.mActualBelow = nsnull;
02656 
02657   event.mImmediate = PR_FALSE;
02658   event.mAdjusted = PR_FALSE;
02659   DispatchWindowEvent(&event);
02660 
02661   if (event.mAdjusted) {
02662     if (event.mPlacement == nsWindowZBottom)
02663       *aAfter = HWND_BOTTOM;
02664     else if (event.mPlacement == nsWindowZTop)
02665       *aAfter = HWND_TOP;
02666     else {
02667       *aAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
02668       /* If we have a client window, use the frame */
02669       if (WinQueryWindowUShort(*aAfter, QWS_ID) == FID_CLIENT) {
02670         *aAfter = WinQueryWindow(*aAfter, QW_PARENT);
02671       }
02672     }
02673   }
02674   NS_IF_RELEASE(event.mActualBelow);
02675   NS_RELEASE(event.widget);
02676 }
02677 
02678 
02679 // 'Window procedure'
02680 PRBool nsWindow::ProcessMessage(ULONG msg, MPARAM mp1, MPARAM mp2, MRESULT &rc)
02681 {
02682   PRBool result = PR_FALSE; // call the default window procedure
02683 
02684   switch (msg) {
02685     case WM_COMMAND: // fire off menu selections
02686       {
02687         nsMenuEvent event(PR_TRUE, NS_MENU_SELECTED, this);
02688         event.mCommand = SHORT1FROMMP(mp1);
02689         InitEvent(event);
02690         result = DispatchWindowEvent(&event);
02691         NS_RELEASE(event.widget);
02692       }
02693 
02694     case WM_CONTROL: // remember this is resent to the orginator...
02695       result = OnControl(mp1, mp2);
02696       break;
02697 
02698     case WM_CLOSE:  // close request
02699       mWindowState |= nsWindowState_eClosing;
02700       DispatchStandardEvent(NS_XUL_CLOSE );
02701       result = PR_TRUE; // abort window closure
02702       break;
02703 
02704     case WM_DESTROY: // clean up.
02705       OnDestroy();
02706       result = PR_TRUE;
02707       break;
02708 
02709     case WM_PAINT:
02710       result = OnPaint();
02711       break;
02712 
02713     case WM_TRANSLATEACCEL:
02714       {
02715         PQMSG pQmsg = (PQMSG)mp1;
02716         if (pQmsg->msg == WM_CHAR) {
02717           LONG mp1 = (LONG)pQmsg->mp1;
02718           LONG mp2 = (LONG)pQmsg->mp2;
02719 
02720           // If we have a shift+enter combination, return false
02721           // immediately.  OS/2 considers the shift+enter
02722           // combination an accelerator and will translate it into
02723           // a WM_OPEN message.  When this happens we do not get a
02724           // WM_CHAR for the down transition of the enter key when
02725           // shift is also pressed and OnKeyDown will not be called.
02726           if (((SHORT1FROMMP(mp1) & (KC_VIRTUALKEY | KC_SHIFT)) &&
02727                (SHORT2FROMMP(mp2) == VK_ENTER)) ||
02728               // Let Mozilla handle standalone F10, not the OS
02729               ((SHORT1FROMMP(mp1) & KC_VIRTUALKEY) &&
02730                ((SHORT1FROMMP(mp1) & (KC_SHIFT | KC_ALT | KC_CTRL)) == 0) &&
02731                (SHORT2FROMMP(mp2) == VK_F10)) ||
02732               // Let Mozilla handle standalone F1, not the OS
02733               ((SHORT1FROMMP(mp1) & KC_VIRTUALKEY) &&
02734                ((SHORT1FROMMP(mp1) & (KC_SHIFT | KC_ALT | KC_CTRL)) == 0) &&
02735                (SHORT2FROMMP(mp2) == VK_F1)) ||
02736               // Let Mozilla handle standalone Alt, not the OS
02737               ((SHORT1FROMMP(mp1) & KC_KEYUP) && (SHORT1FROMMP(mp1) & KC_LONEKEY) &&
02738                (SHORT2FROMMP(mp2) == VK_ALT)) ||
02739               // Let Mozilla handle Alt+Enter, not the OS
02740               ((SHORT1FROMMP(mp1) & (KC_VIRTUALKEY | KC_ALT)) &&
02741                (SHORT2FROMMP(mp2) == VK_NEWLINE))
02742              ) {
02743             return(PR_TRUE);
02744           }
02745         }
02746       }
02747       break;
02748 
02749     case WM_CHAR:
02750       result = OnKey(mp1, mp2);
02751       break;
02752 
02753     case WM_QUERYCONVERTPOS:
02754       {
02755         PRECTL pCursorRect = (PRECTL)mp1;
02756         nsCompositionEvent event(PR_TRUE, NS_COMPOSITION_QUERY, this);
02757         nsPoint point;
02758         point.x = 0;
02759         point.y = 0;
02760         InitEvent(event,&point);
02761         DispatchWindowEvent(&event);
02762         if ((event.theReply.mCursorPosition.x) ||
02763             (event.theReply.mCursorPosition.y)) {
02764           pCursorRect->xLeft = event.theReply.mCursorPosition.x + 1;
02765           pCursorRect->xRight = pCursorRect->xLeft + event.theReply.mCursorPosition.width - 1;
02766           pCursorRect->yTop = GetClientHeight() - event.theReply.mCursorPosition.y;
02767           pCursorRect->yBottom = pCursorRect->yTop - event.theReply.mCursorPosition.height;
02768 
02769           point.x = 0;
02770           point.y = 0;
02771           rc = (MRESULT)QCP_CONVERT;
02772         } else {
02773           rc = (MRESULT)QCP_NOCONVERT;
02774         }
02775       }
02776       result = PR_TRUE;
02777       break;
02778 
02779     // Mouseclicks: we don't dispatch CLICK events because they just cause
02780     // trouble: gecko seems to expect EITHER buttondown/up OR click events
02781     // and so that's what we give it.
02782 
02783     case WM_BUTTON1DOWN:
02784       if (!mIsScrollBar)
02785         WinSetCapture(HWND_DESKTOP, mWnd);
02786       result = DispatchMouseEvent(NS_MOUSE_LEFT_BUTTON_DOWN, mp1, mp2);
02787       // there's no need to clear this on button-up
02788       gLastButton1Down.x = XFROMMP(mp1);
02789       gLastButton1Down.y = YFROMMP(mp1);
02790       WinSetActiveWindow(HWND_DESKTOP, mWnd);
02791       result = PR_TRUE;
02792       break;
02793     case WM_BUTTON1UP:
02794       if (!mIsScrollBar)
02795         WinSetCapture(HWND_DESKTOP, 0); // release
02796       result = DispatchMouseEvent(NS_MOUSE_LEFT_BUTTON_UP, mp1, mp2);
02797       break;
02798     case WM_BUTTON1DBLCLK:
02799       result = DispatchMouseEvent(NS_MOUSE_LEFT_DOUBLECLICK, mp1, mp2);
02800       break;
02801 
02802     case WM_BUTTON2DOWN:
02803       if (!mIsScrollBar)
02804         WinSetCapture(HWND_DESKTOP, mWnd);
02805       result = DispatchMouseEvent(NS_MOUSE_RIGHT_BUTTON_DOWN, mp1, mp2);
02806       break;
02807     case WM_BUTTON2UP:
02808       if (!mIsScrollBar)
02809         WinSetCapture(HWND_DESKTOP, 0); // release
02810       result = DispatchMouseEvent(NS_MOUSE_RIGHT_BUTTON_UP, mp1, mp2);
02811       break;
02812     case WM_BUTTON2DBLCLK:
02813       result = DispatchMouseEvent(NS_MOUSE_RIGHT_DOUBLECLICK, mp1, mp2);
02814       break;
02815 
02816     case WM_CONTEXTMENU:
02817       if (SHORT2FROMMP(mp2) == TRUE) {
02818         HWND hwndCurrFocus = WinQueryFocus(HWND_DESKTOP);
02819         if (hwndCurrFocus != mWnd) {
02820           WinSendMsg(hwndCurrFocus, msg, mp1, mp2);
02821         } else {
02822           result = DispatchMouseEvent(NS_CONTEXTMENU_KEY, mp1, mp2);
02823         }
02824       } else {
02825         result = DispatchMouseEvent(NS_CONTEXTMENU, mp1, mp2);
02826       }
02827       break;
02828 
02829       // if MB1 & MB2 are both pressed, perform a copy or paste;
02830       // see how far the mouse has moved since MB1-down to determine
02831       // the operation (this really ought to look for selected content)
02832     case WM_CHORD:
02833       if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) &
02834           WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) &
02835           0x8000) {
02836         PRBool isCopy = PR_FALSE;
02837         if (abs(XFROMMP(mp1) - gLastButton1Down.x) >
02838               (WinQuerySysValue(HWND_DESKTOP, SV_CXMOTIONSTART) / 2) ||
02839             abs(YFROMMP(mp1) - gLastButton1Down.y) >
02840               (WinQuerySysValue(HWND_DESKTOP, SV_CYMOTIONSTART) / 2))
02841           isCopy = PR_TRUE;
02842 
02843         nsKeyEvent event(PR_TRUE, NS_KEY_PRESS, this);
02844         nsPoint point(0,0);
02845         InitEvent(event, &point);
02846 
02847         event.keyCode = NS_VK_INSERT;
02848         if (isCopy) {
02849           event.isShift = PR_FALSE;
02850           event.isControl = PR_TRUE;
02851         } else {
02852           event.isShift = PR_TRUE;
02853           event.isControl = PR_FALSE;
02854         }
02855         event.isAlt = PR_FALSE;
02856         event.isMeta = PR_FALSE;
02857         event.eventStructType = NS_KEY_EVENT;
02858         event.charCode = 0;
02859         // OS/2 does not set the Shift, Ctrl, or Alt on keyup
02860         if (SHORT1FROMMP(mp1) & (KC_VIRTUALKEY|KC_KEYUP|KC_LONEKEY)) {
02861           USHORT usVKey = SHORT2FROMMP(mp2);
02862           if (usVKey == VK_SHIFT)
02863             event.isShift = PR_TRUE;
02864           if (usVKey == VK_CTRL)
02865             event.isControl = PR_TRUE;
02866           if (usVKey == VK_ALTGRAF || usVKey == VK_ALT)
02867             event.isAlt = PR_TRUE;
02868         }
02869         result = DispatchWindowEvent(&event);
02870       }
02871       break;
02872 
02873     case WM_BUTTON3DOWN:
02874       if (!mIsScrollBar)
02875         WinSetCapture( HWND_DESKTOP, mWnd);
02876       result = DispatchMouseEvent(NS_MOUSE_MIDDLE_BUTTON_DOWN, mp1, mp2);
02877       break;
02878     case WM_BUTTON3UP:
02879       if (!mIsScrollBar)
02880         WinSetCapture( HWND_DESKTOP, 0); // release
02881       result = DispatchMouseEvent(NS_MOUSE_MIDDLE_BUTTON_UP, mp1, mp2);
02882       break;
02883     case WM_BUTTON3DBLCLK:
02884       result = DispatchMouseEvent(NS_MOUSE_MIDDLE_DOUBLECLICK, mp1, mp2);
02885       break;
02886 
02887     case WM_MOUSEMOVE:
02888       {
02889         static POINTL ptlLastPos = { -1, -1 };
02890         // See if mouse has actually moved.
02891         if (ptlLastPos.x == (SHORT)SHORT1FROMMP(mp1) &&
02892             ptlLastPos.y == (SHORT)SHORT2FROMMP(mp1)) {
02893           return PR_TRUE;
02894         } else {
02895           // Yes, remember new position.
02896           ptlLastPos.x = (SHORT)SHORT1FROMMP(mp1);
02897           ptlLastPos.y = (SHORT)SHORT2FROMMP(mp1);
02898         }
02899       }
02900       result = DispatchMouseEvent(NS_MOUSE_MOVE, mp1, mp2);
02901       // don't propogate mouse move or the OS will change the pointer
02902       if (!mIsScrollBar)
02903         result = PR_TRUE;
02904       break;
02905     case WM_MOUSEENTER:
02906       result = DispatchMouseEvent(NS_MOUSE_ENTER, mp1, mp2);
02907       break;
02908     case WM_MOUSELEAVE:
02909       result = DispatchMouseEvent(NS_MOUSE_EXIT, mp1, mp2);
02910       break;
02911 
02912     case WM_APPCOMMAND:
02913       {
02914         PRUint32 appCommand = GET_APPCOMMAND_LPARAM(mp2);
02915         switch (appCommand) {
02916           case APPCOMMAND_BROWSER_BACKWARD:
02917           case APPCOMMAND_BROWSER_FORWARD:
02918           case APPCOMMAND_BROWSER_REFRESH:
02919           case APPCOMMAND_BROWSER_STOP:
02920             DispatchAppCommandEvent(appCommand);
02921             // tell the driver that we handled the event
02922             rc = (MRESULT)1;
02923             result = PR_TRUE;
02924             break;
02925 
02926           default:
02927             rc = (MRESULT)0;
02928             result = PR_FALSE;
02929             break;
02930         }
02931         break;
02932       }
02933 
02934     case WM_HSCROLL:
02935     case WM_VSCROLL:
02936       result = OnScroll(msg, mp1, mp2);
02937       break;
02938 
02939     case WM_ACTIVATE:
02940       DEBUGFOCUS(WM_ACTIVATE);
02941       if (mp1)
02942         gJustGotActivate = PR_TRUE;
02943       else
02944         gJustGotDeactivate = PR_TRUE;
02945       break;
02946 
02947     case WM_FOCUSCHANGED:
02948       {
02949         PRBool isMozWindowTakingFocus = PR_TRUE;
02950         DEBUGFOCUS(WM_FOCUSCHANGED);
02951 
02952         // If the frame was activated earlier or mp1 is 0, dispatch
02953         // focus & activation events.  However, if the frame is minimized,
02954         // defer activation and let SetSizeMode() dispatch it after the
02955         // window has been restored by the user - otherwise, Show() will
02956         // restore it involuntarily.
02957 
02958         if (SHORT1FROMMP(mp2)) {
02959           DEBUGFOCUS(NS_GOTFOCUS);
02960           result = DispatchFocus(NS_GOTFOCUS, isMozWindowTakingFocus);
02961 
02962           if (gJustGotActivate || mp1 == 0) {
02963             HWND hActive = WinQueryActiveWindow(HWND_DESKTOP);
02964             if (!(WinQueryWindowULong(hActive, QWL_STYLE) & WS_MINIMIZED)) {
02965               DEBUGFOCUS(NS_ACTIVATE);
02966               gJustGotActivate = PR_FALSE;
02967               gJustGotDeactivate = PR_FALSE;
02968               result = DispatchFocus(NS_ACTIVATE, isMozWindowTakingFocus);
02969             }
02970           }
02971 
02972           if (WinIsChild(mWnd, HWNDFROMMP(mp1)) && mNextID == 1) {
02973             DEBUGFOCUS(NS_PLUGIN_ACTIVATE);
02974             result = DispatchFocus(NS_PLUGIN_ACTIVATE, isMozWindowTakingFocus);
02975             WinSetFocus(HWND_DESKTOP, mWnd);
02976           }
02977         }
02978         // We are losing focus
02979         else {
02980           char className[19];
02981           ::WinQueryClassName((HWND)mp1, 19, className);
02982           if (strcmp(className, WindowClass()) != 0 &&
02983               strcmp(className, WC_SCROLLBAR_STRING) != 0) {
02984             isMozWindowTakingFocus = PR_FALSE;
02985           }
02986 
02987           if (gJustGotDeactivate) {
02988             DEBUGFOCUS(NS_DEACTIVATE);
02989             gJustGotDeactivate = PR_FALSE;
02990             result = DispatchFocus(NS_DEACTIVATE, isMozWindowTakingFocus);
02991           }
02992 
02993           DEBUGFOCUS(NS_LOSTFOCUS);
02994           result = DispatchFocus(NS_LOSTFOCUS, isMozWindowTakingFocus);
02995         }
02996 
02997         break;
02998       }
02999 
03000     case WM_WINDOWPOSCHANGED:
03001       result = OnReposition((PSWP)mp1);
03002       break;
03003 
03004 
03005     case WM_REALIZEPALETTE:          // hopefully only nsCanvas & nsFrame
03006       result = OnRealizePalette();   // will need this
03007       break;
03008 
03009     case WM_PRESPARAMCHANGED:
03010       // This is really for font-change notifies.  Do that first.
03011       rc = GetPrevWP()(mWnd, msg, mp1, mp2);
03012       OnPresParamChanged(mp1, mp2);
03013       result = PR_TRUE;
03014       break;
03015 
03016       // all msgs that occur when this window is the target of a drag
03017     case DM_DRAGOVER:
03018     case DM_DRAGLEAVE:
03019     case DM_DROP:
03020     case DM_RENDERCOMPLETE:
03021     case DM_DROPHELP:
03022       OnDragDropMsg(msg, mp1, mp2, rc);
03023       result = PR_TRUE;
03024       break;
03025   }
03026 
03027   return result;
03028 }
03029 
03030 
03031 // -----------------------------------------------------------------------
03032 //
03033 // Subclass (or remove the subclass from) this component's nsWindow
03034 //
03035 // -----------------------------------------------------------------------
03036 void nsWindow::SubclassWindow(BOOL bState)
03037 {
03038   if (NULL != mWnd) {
03039     NS_PRECONDITION(::WinIsWindow(0, mWnd), "Invalid window handle");
03040     
03041     if (bState) {
03042         // change the nsWindow proc
03043         mPrevWndProc = WinSubclassWindow(mWnd, fnwpNSWindow);
03044         NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
03045         // connect the this pointer to the nsWindow handle
03046         SetNSWindowPtr(mWnd, this);
03047     } 
03048     else {
03049         WinSubclassWindow(mWnd, mPrevWndProc);
03050         SetNSWindowPtr(mWnd, NULL);
03051         mPrevWndProc = NULL;
03052     }
03053   }
03054 }
03055 
03056 // Overridable OnMessage() methods ------------------------------------------
03057 
03058 PRBool nsWindow::OnReposition( PSWP pSwp)
03059 {
03060    PRBool result = PR_FALSE;
03061  
03062    if( pSwp->fl & SWP_MOVE && !(pSwp->fl & SWP_MINIMIZE))
03063    {
03064       // need screen coords.
03065       POINTL ptl = { pSwp->x, pSwp->y + pSwp->cy - 1 };
03066       WinMapWindowPoints( WinQueryWindow( mWnd, QW_PARENT), GetParentHWND(), &ptl, 1);
03067       PM2NS_PARENT( ptl);
03068       mBounds.x = ptl.x;
03069       mBounds.y = ptl.y;
03070  
03071       WinMapWindowPoints( GetParentHWND(), HWND_DESKTOP, &ptl, 1);
03072       result = OnMove( ptl.x, ptl.y);
03073    }
03074    if( pSwp->fl & SWP_SIZE && !(pSwp->fl & SWP_MINIMIZE))
03075       result = OnResize( pSwp->cx, pSwp->cy);
03076 
03077    return result;
03078 }
03079 
03080 PRBool nsWindow::OnRealizePalette()
03081 {
03082   if (WinQueryWindowUShort(mWnd, QWS_ID) == FID_CLIENT) {
03083     HWND hwndFocus = WinQueryFocus(HWND_DESKTOP);
03084     if (WinIsChild(hwndFocus, mWnd)) {
03085       /* We are getting the focus */
03086       HPS hps = WinGetPS(hwndFocus);
03087       nsPaletteOS2::SelectGlobalPalette(hps, hwndFocus);
03088       WinReleasePS(hps);
03089       WinInvalidateRect( mWnd, 0, TRUE);
03090     } else {
03091       /* We are losing the focus */
03092       WinInvalidateRect( mWnd, 0, TRUE);
03093     }
03094   }
03095 
03096   // Always call the default window procedure
03097   return PR_TRUE;
03098 }
03099 
03100 PRBool nsWindow::OnPresParamChanged( MPARAM mp1, MPARAM mp2)
03101 {
03102    return PR_FALSE;
03103 }
03104 
03105 // This is necessary because notification codes are defined from 1 for each
03106 // control: thus we cannot tell the difference between an EN_SELECT and
03107 // a TABN_SELECT, etc.
03108 // So delegate to those classes who actually want to handle the thing.
03109 PRBool nsWindow::OnControl( MPARAM mp1, MPARAM mp2)
03110 {
03111    return PR_TRUE; // default to speed things up a bit...
03112 }
03113 
03114 
03115 //-------------------------------------------------------------------------
03116 //
03117 // WM_DESTROY has been called
03118 //
03119 //-------------------------------------------------------------------------
03120 void nsWindow::OnDestroy()
03121 {
03122    mOnDestroyCalled = PR_TRUE;
03123 
03124    SubclassWindow( PR_FALSE);
03125    mWnd = 0;
03126 
03127    // if we were in the middle of deferred window positioning then free up
03128    if( mSWPs) free( mSWPs);
03129    mSWPs = 0;
03130    mlHave = mlUsed = 0;
03131 
03132    // release references to context, toolkit, appshell, children
03133    nsBaseWidget::OnDestroy();
03134 
03135    // kill font
03136    delete mFont;
03137 
03138    // dispatching of the event may cause the reference count to drop to 0
03139    // and result in this object being deleted. To avoid that, add a
03140    // reference and then release it after dispatching the event.
03141    //
03142    // It's important *not* to do this if we're being called from the
03143    // destructor -- this would result in our destructor being called *again*
03144    // from the Release() below.  This is very bad...
03145    if( !(nsWindowState_eDoingDelete & mWindowState) )
03146    {
03147       AddRef();
03148       DispatchStandardEvent( NS_DESTROY );
03149       Release();
03150    }
03151 
03152    // dead widget
03153    mWindowState |= nsWindowState_eDead;
03154    mWindowState &= ~(nsWindowState_eLive|nsWindowState_ePrecreate|
03155                      nsWindowState_eInCreate);
03156 }
03157 
03158 //-------------------------------------------------------------------------
03159 //
03160 // Move
03161 //
03162 //-------------------------------------------------------------------------
03163 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
03164 {            
03165   // Params here are in XP-space for the desktop
03166   nsGUIEvent event(PR_TRUE, NS_MOVE, this);
03167   InitEvent( event);
03168   event.point.x = aX;
03169   event.point.y = aY;
03170 
03171   PRBool result = DispatchWindowEvent( &event);
03172   NS_RELEASE(event.widget);
03173   return result;
03174 }
03175 
03176 //-------------------------------------------------------------------------
03177 //
03178 // Paint
03179 //
03180 //-------------------------------------------------------------------------
03181 PRBool nsWindow::OnPaint()
03182 {
03183    PRBool rc = PR_FALSE;
03184    nsEventStatus eventStatus = nsEventStatus_eIgnore;
03185 
03186 #ifdef NS_DEBUG
03187    HRGN debugPaintFlashRegion = NULL;
03188    HPS debugPaintFlashPS = NULL;
03189 
03190    if (debug_WantPaintFlashing())
03191    {
03192       debugPaintFlashPS = ::WinGetPS(mWnd);
03193       debugPaintFlashRegion = ::GpiCreateRegion(debugPaintFlashPS, 0, NULL);
03194       ::WinQueryUpdateRegion(mWnd, debugPaintFlashRegion);
03195    }
03196 #endif
03197 
03198    if( mContext && (mEventCallback || mEventListener))
03199    {
03200       // Get rect to redraw and validate window
03201       RECTL rcl = { 0 };
03202 
03203       // get the current drag status;  if we're currently in a Moz-originated
03204       // drag, get the special drag HPS then pass it to WinBeginPaint();
03205       // if there is no hpsDrag, WinBeginPaint() will return a normal HPS
03206       HPS hpsDrag = 0;
03207       CheckDragStatus(ACTION_PAINT, &hpsDrag);
03208       HPS hPS = WinBeginPaint(mWnd, hpsDrag, &rcl);
03209       nsPaletteOS2::SelectGlobalPalette(hPS, mWnd);
03210 
03211       // if the update rect is empty, suppress the paint event
03212       if (!WinIsRectEmpty(0, &rcl))
03213       {
03214           // call the event callback 
03215           if (mEventCallback) 
03216           {
03217               nsPaintEvent event(PR_TRUE, NS_PAINT, this);
03218               InitEvent(event);
03219      
03220               // build XP rect from in-ex window rect
03221               nsRect rect;
03222               rect.x = rcl.xLeft;
03223               rect.y = GetClientHeight() - rcl.yTop;
03224               rect.width = rcl.xRight - rcl.xLeft;
03225               rect.height = rcl.yTop - rcl.yBottom;
03226               event.rect = &rect;
03227               event.region = nsnull;
03228      
03229 #ifdef NS_DEBUG
03230           debug_DumpPaintEvent(stdout,
03231                                this,
03232                                &event,
03233                                nsCAutoString("noname"),
03234                                (PRInt32) mWnd);
03235 #endif // NS_DEBUG
03236 
03237               //nsresult  res;
03238              
03239               static NS_DEFINE_CID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID);
03240              
03241               if (NS_SUCCEEDED(CallCreateInstance(kRenderingContextCID, &event.renderingContext)))
03242               {
03243                  nsIRenderingContextOS2 *winrc;
03244 
03245                  if (NS_OK == event.renderingContext->QueryInterface(NS_GET_IID(nsIRenderingContextOS2), (void **)&winrc))
03246                  {
03247                     nsIDrawingSurface* surf;
03248                    
03249                     //i know all of this seems a little backwards. i'll fix it, i swear. MMP
03250                    
03251                     if (NS_OK == winrc->CreateDrawingSurface(hPS, surf, event.widget))
03252                     {
03253                       event.renderingContext->Init(mContext, surf);
03254                       rc = DispatchWindowEvent(&event, eventStatus);
03255                       event.renderingContext->DestroyDrawingSurface(surf);
03256                     }
03257 
03258                     NS_RELEASE(winrc);
03259                  }
03260               }
03261      
03262               NS_RELEASE(event.renderingContext);
03263               NS_RELEASE(event.widget);
03264           }
03265       }
03266      
03267       WinEndPaint(hPS);
03268       if (hpsDrag)
03269         ReleaseIfDragHPS(hpsDrag);
03270    }
03271 
03272 #ifdef NS_DEBUG
03273   if (debug_WantPaintFlashing())
03274   {
03275      // Only flash paint events which have not ignored the paint message.
03276      // Those that ignore the paint message aren't painting anything so there
03277      // is only the overhead of the dispatching the paint event.
03278      if (nsEventStatus_eIgnore != eventStatus)
03279      {
03280         LONG CurMix = ::GpiQueryMix(debugPaintFlashPS);
03281         ::GpiSetMix(debugPaintFlashPS, FM_INVERT);
03282 
03283         ::GpiPaintRegion(debugPaintFlashPS, debugPaintFlashRegion);
03284         PR_Sleep(PR_MillisecondsToInterval(30));
03285         ::GpiPaintRegion(debugPaintFlashPS, debugPaintFlashRegion);
03286         PR_Sleep(PR_MillisecondsToInterval(30));
03287 
03288         ::GpiSetMix (debugPaintFlashPS, CurMix);
03289      }
03290      ::GpiDestroyRegion(debugPaintFlashPS, debugPaintFlashRegion);
03291      ::WinReleasePS(debugPaintFlashPS);
03292   }
03293 #endif
03294 
03295    return rc;
03296 }
03297 
03298 
03299 //-------------------------------------------------------------------------
03300 //
03301 // Send a resize message to the listener
03302 //
03303 //-------------------------------------------------------------------------
03304 PRBool nsWindow::OnResize(PRInt32 aX, PRInt32 aY)
03305 {
03306    mBounds.width = aX;
03307    mBounds.height = aY;
03308    return DispatchResizeEvent( aX, aY);
03309 }
03310 
03311 PRBool nsWindow::DispatchResizeEvent( PRInt32 aX, PRInt32 aY)
03312 {
03313    PRBool result;
03314    // call the event callback 
03315    nsSizeEvent event(PR_TRUE, NS_SIZE, this);
03316    nsRect      rect( 0, 0, aX, aY);
03317 
03318    InitEvent( event);
03319    event.windowSize = &rect;             // this is the *client* rectangle
03320    event.mWinWidth = mBounds.width;
03321    event.mWinHeight = mBounds.height;
03322 
03323    result = DispatchWindowEvent( &event);
03324    NS_RELEASE(event.widget);
03325    return result;
03326 }                                           
03327 
03328 //-------------------------------------------------------------------------
03329 //
03330 // Deal with all sort of mouse event
03331 //
03332 //-------------------------------------------------------------------------
03333 PRBool nsWindow::DispatchMouseEvent( PRUint32 aEventType, MPARAM mp1, MPARAM mp2)
03334 {
03335   PRBool result = PR_FALSE;
03336 
03337   if (nsnull == mEventCallback && nsnull == mMouseListener) {
03338     return result;
03339   }
03340 
03341   nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal);
03342 
03343   // Mouse leave & enter messages don't seem to have position built in.
03344   if( aEventType && aEventType != NS_MOUSE_ENTER && aEventType != NS_MOUSE_EXIT)
03345   {
03346     POINTL ptl;
03347     if (aEventType == NS_CONTEXTMENU_KEY) {
03348       WinQueryPointerPos(HWND_DESKTOP, &ptl);
03349       WinMapWindowPoints( HWND_DESKTOP, mWnd, &ptl, 1 );
03350     } else {
03351       ptl.x = (SHORT)SHORT1FROMMP(mp1);
03352       ptl.y = (SHORT)SHORT2FROMMP(mp1);
03353     }
03354     PM2NS(ptl);
03355     nsPoint pt( ptl.x, ptl.y);
03356     InitEvent( event, &pt);
03357 
03358     USHORT usFlags = SHORT2FROMMP( mp2);
03359     event.isShift = (usFlags & KC_SHIFT) ? PR_TRUE : PR_FALSE;
03360     event.isControl = (usFlags & KC_CTRL) ? PR_TRUE : PR_FALSE;
03361     event.isAlt = (usFlags & KC_ALT) ? PR_TRUE : PR_FALSE;
03362   }
03363   else
03364   {
03365     InitEvent( event, nsnull);
03366     event.isShift = WinIsKeyDown( VK_SHIFT);
03367     event.isControl = WinIsKeyDown( VK_CTRL);
03368     event.isAlt = WinIsKeyDown( VK_ALT) || WinIsKeyDown( VK_ALTGRAF);
03369   }
03370 
03371   event.isMeta    = PR_FALSE;
03372 
03373   //Dblclicks are used to set the click count, then changed to mousedowns
03374   if (aEventType == NS_MOUSE_LEFT_DOUBLECLICK ||
03375       aEventType == NS_MOUSE_RIGHT_DOUBLECLICK) {
03376     event.message = (aEventType == NS_MOUSE_LEFT_DOUBLECLICK) ? 
03377                     NS_MOUSE_LEFT_BUTTON_DOWN : NS_MOUSE_RIGHT_BUTTON_DOWN;
03378     event.clickCount = 2;
03379   }
03380   else {
03381     event.clickCount = 1;
03382   }
03383 
03384   nsPluginEvent pluginEvent;
03385 
03386   switch (aEventType)//~~~
03387   {
03388     case NS_MOUSE_LEFT_BUTTON_DOWN:
03389       pluginEvent.event = WM_BUTTON1DOWN;
03390       break;
03391     case NS_MOUSE_LEFT_BUTTON_UP:
03392       pluginEvent.event = WM_BUTTON1UP;
03393       break;
03394     case NS_MOUSE_LEFT_DOUBLECLICK:
03395       pluginEvent.event = WM_BUTTON1DBLCLK;
03396       break;
03397     case NS_MOUSE_RIGHT_BUTTON_DOWN:
03398       pluginEvent.event = WM_BUTTON2DOWN;
03399       break;
03400     case NS_MOUSE_RIGHT_BUTTON_UP:
03401       pluginEvent.event = WM_BUTTON2UP;
03402       break;
03403     case NS_MOUSE_RIGHT_DOUBLECLICK:
03404       pluginEvent.event = WM_BUTTON2DBLCLK;
03405       break;
03406     case NS_MOUSE_MIDDLE_BUTTON_DOWN:
03407       pluginEvent.event = WM_BUTTON3DOWN;
03408       break;
03409     case NS_MOUSE_MIDDLE_BUTTON_UP:
03410       pluginEvent.event = WM_BUTTON3UP;
03411       break;
03412     case NS_MOUSE_MIDDLE_DOUBLECLICK:
03413       pluginEvent.event = WM_BUTTON3DBLCLK;
03414       break;
03415     case NS_MOUSE_MOVE:
03416       pluginEvent.event = WM_MOUSEMOVE;
03417       break;
03418     default:
03419       break;
03420   }
03421 
03422   pluginEvent.wParam = 0;
03423 /* OS2TODO
03424   pluginEvent.wParam |= (event.isShift) ? MK_SHIFT : 0;
03425   pluginEvent.wParam |= (event.isControl) ? MK_CONTROL : 0;
03426 */
03427   pluginEvent.lParam = MAKELONG(event.point.x, event.point.y);
03428 
03429   event.nativeMsg = (void *)&pluginEvent;
03430 
03431   // call the event callback 
03432   if (nsnull != mEventCallback) {
03433 
03434     result = DispatchWindowEvent(&event);
03435 
03436 #if 0  // OS2TODO
03437     if (aEventType == NS_MOUSE_MOVE) {
03438 
03439       // if we are not in mouse capture mode (mouse down and hold)
03440       // then use "this" window
03441       // if we are in mouse capture, then all events are being directed
03442       // back to the nsWindow doing the capture. So therefore, the detection
03443       // of whether we are in a new nsWindow is wrong. Meaning this MOUSE_MOVE
03444       // event hold the captured windows pointer not the one the mouse is over.
03445       //
03446       // So we use "WindowFromPoint" to find what window we are over and 
03447       // set that window into the mouse trailer timer.
03448       if (!mIsInMouseCapture) {
03449         MouseTrailer * mouseTrailer = MouseTrailer::GetMouseTrailer(0);
03450         MouseTrailer::SetMouseTrailerWindow(this);
03451         mouseTrailer->CreateTimer();
03452       } else {
03453         POINT mp;
03454         DWORD pos = ::GetMessagePos();
03455         mp.x      = LOWORD(pos);
03456         mp.y      = HIWORD(pos);
03457 
03458         // OK, now find out if we are still inside
03459         // the captured native window
03460         POINT cpos;
03461         cpos.x = LOWORD(pos);
03462         cpos.y = HIWORD(pos);
03463 
03464         nsWindow * someWindow = NULL;
03465         HWND hWnd = ::WindowFromPoint(mp);
03466         if (hWnd != NULL) {
03467           ::ScreenToClient(hWnd, &cpos);
03468           RECT r;
03469           VERIFY(::GetWindowRect(hWnd, &r));
03470           if (cpos.x >= r.left && cpos.x <= r.right &&
03471               cpos.y >= r.top && cpos.y <= r.bottom) {
03472             // yes we are so we should be able to get a valid window
03473             // although, strangley enough when we are on the frame part of the
03474             // window we get right here when in capture mode
03475             // but this window won't match the capture mode window so
03476             // we are ok
03477             someWindow = (nsWindow*)::GetWindowLong(hWnd, GWL_USERDATA);
03478           } 
03479         }
03480         // only set the window into the mouse trailer if we have a good window
03481         if (nsnull != someWindow)  {
03482           MouseTrailer * mouseTrailer = MouseTrailer::GetMouseTrailer(0);
03483           MouseTrailer::SetMouseTrailerWindow(someWindow);
03484           mouseTrailer->CreateTimer();
03485         }
03486       }
03487 
03488       nsRect rect;
03489       GetBounds(rect);
03490       rect.x = 0;
03491       rect.y = 0;
03492 
03493       if (rect.Contains(event.point.x, event.point.y)) {
03494         if (gCurrentWindow == NULL || gCurrentWindow != this) {
03495           if ((nsnull != gCurrentWindow) && (!gCurrentWindow->mIsDestroying)) {
03496             MouseTrailer::IgnoreNextCycle();
03497             gCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, gCurrentWindow->GetLastPoint());
03498           }
03499           gCurrentWindow = this;
03500           if (!mIsDestroying) {
03501             gCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER);
03502           }
03503         }
03504       } 
03505     } else if (aEventType == NS_MOUSE_EXIT) {
03506       if (gCurrentWindow == this) {
03507         gCurrentWindow = nsnull;
03508       }
03509     }
03510 #endif //OS2TODO
03511 
03512     // Release the widget with NS_IF_RELEASE() just in case
03513     // the context menu key code in nsEventListenerManager::HandleEvent()
03514     // released it already.
03515     NS_IF_RELEASE(event.widget);
03516     return result;
03517   }
03518 
03519   if (nsnull != mMouseListener) {
03520     switch (aEventType) {
03521       case NS_MOUSE_MOVE: {
03522         result = ConvertStatus(mMouseListener->MouseMoved(event));
03523         nsRect rect;
03524         GetBounds(rect);
03525         if (rect.Contains(event.point.x, event.point.y)) {
03526           if (gCurrentWindow == NULL || gCurrentWindow != this) {
03527             gCurrentWindow = this;
03528           }
03529         } else {
03530           //printf("Mouse exit");
03531         }
03532 
03533       } break;
03534 
03535       case NS_MOUSE_LEFT_BUTTON_DOWN:
03536       case NS_MOUSE_MIDDLE_BUTTON_DOWN:
03537       case NS_MOUSE_RIGHT_BUTTON_DOWN:
03538         result = ConvertStatus(mMouseListener->MousePressed(event));
03539         break;
03540 
03541       case NS_MOUSE_LEFT_BUTTON_UP:
03542       case NS_MOUSE_MIDDLE_BUTTON_UP:
03543       case NS_MOUSE_RIGHT_BUTTON_UP:
03544         result = ConvertStatus(mMouseListener->MouseReleased(event));
03545 //        result = ConvertStatus(mMouseListener->MouseClicked(event));
03546         break;
03547 
03548       case NS_MOUSE_LEFT_CLICK:
03549       case NS_MOUSE_MIDDLE_CLICK:
03550       case NS_MOUSE_RIGHT_CLICK:
03551         result = ConvertStatus(mMouseListener->MouseClicked(event));
03552         break;
03553     } // switch
03554   } 
03555 
03556   NS_RELEASE(event.widget);
03557   return result;
03558 }
03559 
03560 
03561 //-------------------------------------------------------------------------
03562 //
03563 // Deal with focus messages
03564 //
03565 //-------------------------------------------------------------------------
03566 PRBool nsWindow::DispatchFocus(PRUint32 aEventType, PRBool isMozWindowTakingFocus)
03567 {
03568   // call the event callback 
03569   if (mEventCallback) {
03570     nsFocusEvent event(PR_TRUE, aEventType, this);
03571     InitEvent(event);
03572 
03573     //focus and blur event should go to their base widget loc, not current mouse pos
03574     event.point.x = 0;
03575     event.point.y = 0;
03576 
03577     event.isMozWindowTakingFocus = isMozWindowTakingFocus;
03578 
03579     nsPluginEvent pluginEvent;
03580 
03581     switch (aEventType)//~~~
03582     {
03583       case NS_GOTFOCUS:
03584         pluginEvent.event = WM_SETFOCUS;
03585         break;
03586       case NS_LOSTFOCUS:
03587         pluginEvent.event = WM_FOCUSCHANGED;
03588         break;
03589       case NS_PLUGIN_ACTIVATE:
03590         pluginEvent.event = WM_FOCUSCHANGED;
03591         break;
03592       default:
03593         break;
03594     }
03595 
03596     event.nativeMsg = (void *)&pluginEvent;
03597 
03598     PRBool result = DispatchWindowEvent(&event);
03599     NS_RELEASE(event.widget);
03600     return result;
03601   }
03602   return PR_FALSE;
03603 }
03604 
03605 
03606 //-------------------------------------------------------------------------
03607 //
03608 // Deal with scrollbar messages
03609 //
03610 //-------------------------------------------------------------------------
03611 PRBool nsWindow::OnScroll( ULONG msgid, MPARAM mp1, MPARAM mp2)
03612 {
03613    return( (msgid == WM_HSCROLL) ? OnHScroll(mp1, mp2) : OnVScroll(mp1, mp2) );
03614 }
03615 
03616 PRBool nsWindow::OnVScroll( MPARAM mp1, MPARAM mp2)
03617 {
03618     if (nsnull != mEventCallback) {
03619         nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
03620         InitEvent(scrollEvent);
03621         scrollEvent.isShift = WinIsKeyDown( VK_SHIFT);
03622         scrollEvent.isControl = WinIsKeyDown( VK_CTRL);
03623         scrollEvent.isAlt = WinIsKeyDown( VK_ALT) || WinIsKeyDown( VK_ALTGRAF);
03624         scrollEvent.isMeta = PR_FALSE;
03625         scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
03626         switch (SHORT2FROMMP(mp2)) {
03627           case SB_LINEUP:
03628             scrollEvent.delta = -1;
03629             break;
03630           case SB_LINEDOWN:
03631             scrollEvent.delta = 1;
03632             break;
03633           case SB_PAGEUP:
03634             scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
03635             scrollEvent.delta = -1;
03636             break;
03637           case SB_PAGEDOWN:
03638             scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
03639             scrollEvent.delta = 1;
03640             break;
03641           default:
03642             scrollEvent.delta = 0;
03643             break;
03644         }
03645         DispatchWindowEvent(&scrollEvent);
03646         NS_RELEASE(scrollEvent.widget);
03647     }
03648     return PR_FALSE;
03649 }
03650 
03651 PRBool nsWindow::OnHScroll( MPARAM mp1, MPARAM mp2)
03652 {
03653     if (nsnull != mEventCallback) {
03654         nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
03655         InitEvent(scrollEvent);
03656         scrollEvent.isShift = WinIsKeyDown( VK_SHIFT);
03657         scrollEvent.isControl = WinIsKeyDown( VK_CTRL);
03658         scrollEvent.isAlt = WinIsKeyDown( VK_ALT) || WinIsKeyDown( VK_ALTGRAF);
03659         scrollEvent.isMeta = PR_FALSE;
03660         scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
03661         switch (SHORT2FROMMP(mp2)) {
03662           case SB_LINELEFT:
03663             scrollEvent.delta = -1;
03664             break;
03665           case SB_LINERIGHT:
03666             scrollEvent.delta = 1;
03667             break;
03668           case SB_PAGELEFT:
03669             scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
03670             scrollEvent.delta = -1;
03671             break;
03672           case SB_PAGERIGHT:
03673             scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
03674             scrollEvent.delta = 1;
03675             break;
03676           default:
03677             scrollEvent.delta = 0;
03678             break;
03679         }
03680         DispatchWindowEvent(&scrollEvent);
03681         NS_RELEASE(scrollEvent.widget);
03682     }
03683     return PR_FALSE;
03684 }
03685 
03686 /* On OS/2, if you pass a titlebar > 512 characters, it doesn't display at all. */
03687 /* We are going to limit our titlebars to 256 just to be on the safe side */
03688 #define MAX_TITLEBAR_LENGTH 256
03689 
03690 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle) 
03691 {
03692    // Switch to the PM thread if necessary...
03693    if( mOS2Toolkit && !mOS2Toolkit->IsGuiThread())
03694    {
03695       ULONG ulong = (ULONG) &aTitle;
03696       MethodInfo info( this, nsWindow::SET_TITLE, 1, &ulong);
03697       mOS2Toolkit->CallMethod( &info);
03698    }
03699    else if (mWnd)
03700    {
03701       PRUnichar* uchtemp = ToNewUnicode(aTitle);
03702       for (PRUint32 i=0;i<aTitle.Length();i++) {
03703        switch (uchtemp[i]) {
03704          case 0x2018:
03705          case 0x2019:
03706            uchtemp[i] = 0x0027;
03707            break;
03708          case 0x201C:
03709          case 0x201D:
03710            uchtemp[i] = 0x0022;
03711            break;
03712          case 0x2014:
03713            uchtemp[i] = 0x002D;
03714            break;
03715        }
03716       }
03717 
03718       nsAutoCharBuffer title;
03719       PRInt32 titleLength;
03720       WideCharToMultiByte(0, uchtemp, aTitle.Length(), title, titleLength);
03721       if (titleLength > MAX_TITLEBAR_LENGTH) {
03722         title.get()[MAX_TITLEBAR_LENGTH] = '\0';
03723       }
03724       ::WinSetWindowText(GetMainWindow(), title.get());
03725       if (mChromeHidden) {
03726          /* If the chrome is hidden, set the text of the titlebar directly */
03727          if (mFrameWnd) {
03728             HWND hwndTitleBar = (HWND)::WinQueryProperty(mFrameWnd,
03729                                                          "hwndTitleBar");
03730             ::WinSetWindowText(hwndTitleBar, title.get());
03731          }
03732       }
03733       nsMemory::Free(uchtemp);
03734    }
03735    return NS_OK;
03736 } 
03737 
03738 // this implementation guarantees that sysmenus & minimized windows
03739 // will always have some icon other than the sysmenu default
03740 
03741 NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec) 
03742 {
03743   static HPOINTER hDefaultIcon = 0;
03744   HPOINTER        hWorkingIcon = 0;
03745 
03746   // Assume the given string is a local identifier for an icon file.
03747   nsCOMPtr<nsILocalFile> iconFile;
03748   ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"),
03749                   getter_AddRefs(iconFile));
03750 
03751   // if the file was found, try to use it
03752   if (iconFile) {
03753     nsCAutoString path;
03754     iconFile->GetNativePath(path);
03755 
03756     if (mFrameIcon)
03757       WinFreeFileIcon(mFrameIcon);
03758 
03759     mFrameIcon = WinLoadFileIcon(path.get(), FALSE);
03760     hWorkingIcon = mFrameIcon;
03761   }
03762 
03763   // if that doesn't work, use the app's icon (let's hope it can be
03764   // loaded because nobody should have to look at SPTR_APPICON - ugggh!)
03765   if (hWorkingIcon == 0) {
03766     if (hDefaultIcon == 0) {
03767       hDefaultIcon = WinLoadPointer(HWND_DESKTOP, 0, 1);
03768       if (hDefaultIcon == 0)
03769         hDefaultIcon =  WinQuerySysPointer(HWND_DESKTOP, SPTR_APPICON, FALSE);
03770     }
03771     hWorkingIcon = hDefaultIcon;
03772   }
03773 
03774   WinSendMsg(mFrameWnd, WM_SETICON, (MPARAM)hWorkingIcon, (MPARAM)0);
03775   return NS_OK;
03776 }
03777 
03778 NS_METHOD nsWindow::GetPreferredSize(PRInt32& aWidth, PRInt32& aHeight)
03779 {
03780   aWidth = mPreferredWidth;
03781   aHeight = mPreferredHeight;
03782   return NS_OK;
03783 }
03784 
03785 NS_METHOD nsWindow::SetPreferredSize(PRInt32 aWidth, PRInt32 aHeight)
03786 {
03787   mPreferredWidth = aWidth;
03788   mPreferredHeight = aHeight;
03789   return NS_OK;
03790 }
03791 
03792 NS_IMETHODIMP
03793 nsWindow::GetLastInputEventTime(PRUint32& aTime)
03794 {
03795    ULONG ulStatus = WinQueryQueueStatus(HWND_DESKTOP);
03796 
03797    // If there is pending input then return the current time.
03798    if (ulStatus & (QS_KEY | QS_MOUSE)) {
03799      gLastInputEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
03800    }
03801 
03802    aTime = gLastInputEventTime;
03803 
03804    return NS_OK;
03805 }
03806 
03807 // --------------------------------------------------------------------------
03808 // OS2-specific routines to emulate Windows behaviors
03809 // --------------------------------------------------------------------------
03810 
03811 BOOL nsWindow::SetWindowPos( HWND ib, long x, long y, long cx, long cy, ULONG flags)
03812 {
03813    BOOL bDeferred = FALSE;
03814 
03815    if( mParent && mParent->mSWPs) // XXX bit implicit...
03816    {
03817       mParent->DeferPosition( GetMainWindow(), ib, x, y, cx, cy, flags);
03818       bDeferred = TRUE;
03819    }
03820    else // WinSetWindowPos appears not to need msgq (hmm)
03821       WinSetWindowPos( GetMainWindow(), ib, x, y, cx, cy, GetSWPFlags(flags));
03822 
03823    // When the window is actually sized, mBounds will be updated in the fnwp.
03824 
03825    return bDeferred;
03826 }
03827 
03828 nsresult nsWindow::GetWindowText( nsString &aStr, PRUint32 *rc)
03829 {
03830    // Switch to the PM thread if necessary...
03831    if( !mOS2Toolkit->IsGuiThread())
03832    {
03833       ULONG args[] = { (ULONG) &aStr, (ULONG) rc };
03834       MethodInfo info( this, nsWindow::GET_TITLE, 2, args);
03835       mOS2Toolkit->CallMethod( &info);
03836    }
03837    else if( mWnd)
03838    {
03839       // XXX there must be some way to query the text straight into the string!
03840       int length = WinQueryWindowTextLength( mWnd);
03841       char *tmp = new char [ length + 1 ];
03842       WinQueryWindowText( mWnd, length + 1, tmp);
03843       aStr.AssignWithConversion( tmp);
03844       delete [] tmp;
03845    }
03846    return NS_OK;
03847 }
03848 
03849 // --------------------------------------------------------------------------
03850 // Misc helpers -------------------------------------------------------------
03851 
03852 // May need to thread-switch these...
03853 void nsWindow::AddToStyle( ULONG style)
03854 {
03855    if( mWnd)
03856       WinSetWindowBits( mWnd, QWL_STYLE, style, style);
03857 }
03858 
03859 void nsWindow::RemoveFromStyle( ULONG style)
03860 {
03861    if( mWnd)
03862    {
03863       ULONG oldStyle = WinQueryWindowULong( mWnd, QWL_STYLE);
03864       oldStyle &= ~style;
03865       WinSetWindowULong( mWnd, QWL_STYLE, oldStyle);
03866    }
03867 }
03868 
03869 // --------------------------------------------------------------------------
03870 // Drag & Drop - Target methods
03871 // --------------------------------------------------------------------------
03872 //
03873 // nsWindow knows almost nothing about d&d except that it can cause
03874 // video corruption if the screen is updated during a drag. It relies
03875 // on nsIDragSessionOS2 to handle native d&d messages and to return
03876 // the status flags it uses to control screen updates.
03877 //
03878 // OnDragDropMsg() handles all of the DM_* messages messages nsWindow
03879 // should ever receive.  CheckDragStatus() determines if a screen update
03880 // is safe and may return a drag HPS if doing so will avoid corruption.
03881 // As far as its author (R.Walsh) can tell, every use is required.
03882 //
03883 // For Moz drags, all while-you-drag features should be fully enabled &
03884 // corruption free;  for native drags, popups & scrolling are suppressed
03885 // but some niceties, e.g. moving the cursor in text fields, are enabled.
03886 //
03887 // --------------------------------------------------------------------------
03888 
03889 // This method was designed to be totally ignorant of drag and drop.
03890 // It gives nsIDragSessionOS2 (near) complete control over handling.
03891 
03892 PRBool nsWindow::OnDragDropMsg(ULONG msg, MPARAM mp1, MPARAM mp2, MRESULT &mr)
03893 {
03894   nsresult rv;
03895   PRUint32 eventType = 0;
03896   PRUint32 dragFlags = 0;
03897 
03898   mr = 0;
03899   nsCOMPtr<nsIDragService> dragService =
03900                     do_GetService("@mozilla.org/widget/dragservice;1", &rv);
03901   if (dragService) {
03902     nsCOMPtr<nsIDragSessionOS2> dragSession(
03903                         do_QueryInterface(dragService, &rv));
03904     if (dragSession) {
03905 
03906         // handle all possible input without regard to outcome
03907       switch (msg) {
03908 
03909         case DM_DRAGOVER:
03910           rv = dragSession->DragOverMsg((PDRAGINFO)mp1, mr, &dragFlags);
03911           eventType = NS_DRAGDROP_OVER;
03912           break;
03913 
03914         case DM_DRAGLEAVE:
03915           rv = dragSession->DragLeaveMsg((PDRAGINFO)mp1, &dragFlags);
03916           eventType = NS_DRAGDROP_EXIT;
03917           break;
03918 
03919         case DM_DROP:
03920           rv = dragSession->DropMsg((PDRAGINFO)mp1, mWnd, &dragFlags);
03921           eventType = NS_DRAGDROP_DROP;
03922           break;
03923 
03924         case DM_DROPHELP:
03925           rv = dragSession->DropHelpMsg((PDRAGINFO)mp1, &dragFlags);
03926           eventType = NS_DRAGDROP_EXIT;
03927           break;
03928 
03929         case DM_RENDERCOMPLETE:
03930           rv = dragSession->RenderCompleteMsg((PDRAGTRANSFER)mp1,
03931                                               SHORT1FROMMP(mp2), &dragFlags);
03932           eventType = NS_DRAGDROP_DROP;
03933           break;
03934 
03935         default:
03936           rv = NS_ERROR_FAILURE;
03937       }
03938 
03939         // handle all possible outcomes without regard to their source
03940       if NS_SUCCEEDED(rv) {
03941         mDragStatus = gDragStatus = (dragFlags & DND_DragStatus);
03942 
03943         if (dragFlags & DND_DispatchEnterEvent)
03944           DispatchDragDropEvent(NS_DRAGDROP_ENTER);
03945 
03946         if (dragFlags & DND_DispatchEvent)
03947           DispatchDragDropEvent(eventType);
03948 
03949         if (dragFlags & DND_GetDragoverResult)
03950           dragSession->GetDragoverResult(mr);
03951 
03952         if (dragFlags & DND_ExitSession)
03953           dragSession->ExitSession(&dragFlags);
03954       }
03955     }
03956   }
03957     // save final drag status
03958   gDragStatus = mDragStatus = (dragFlags & DND_DragStatus);
03959 
03960   return PR_TRUE;
03961 }
03962 
03963 // --------------------------------------------------------------------------
03964 
03965 // CheckDragStatus() concentrates all the hacks needed to avoid video
03966 // corruption during d&d into one place.  The caller specifies an action
03967 // that might be a problem;  the method tells it whether to proceed and
03968 // provides a Drg HPS if the situation calls for one.
03969 
03970 PRBool nsWindow::CheckDragStatus(PRUint32 aAction, HPS * oHps)
03971 {
03972   PRBool rtn    = PR_TRUE;
03973   PRBool getHps = PR_FALSE;
03974 
03975   switch (aAction) {
03976 
03977       // OnPaint() & Scroll..() - only Moz drags get a Drg hps
03978     case ACTION_PAINT:
03979     case ACTION_SCROLL:
03980       if (gDragStatus & DND_MozDrag)
03981         getHps = PR_TRUE;
03982       break;
03983 
03984       // GetNativeData() - Moz drags + native drags over this nsWindow
03985     case ACTION_DRAW:
03986       if ((gDragStatus & DND_MozDrag) ||
03987           (mDragStatus & DND_NativeDrag))
03988         getHps = PR_TRUE;
03989       break;
03990 
03991       // Show() - don't show popups during a native dragover
03992     case ACTION_SHOW:
03993       if ((gDragStatus & (DND_NativeDrag | DND_InDrop)) == DND_NativeDrag)
03994         rtn = PR_FALSE;
03995       break;
03996 
03997       // InitEvent() - use PtrPos while in drag, MsgPos otherwise
03998     case ACTION_PTRPOS:
03999       if (!gDragStatus)
04000         rtn = PR_FALSE;
04001       break;
04002 
04003     default:
04004       rtn = PR_FALSE;
04005   }
04006 
04007     // if the caller wants an HPS, and the current drag status
04008     // calls for one, *and* a drag hps hasn't already been requested
04009     // for this window, get the hps;  otherwise, return zero;
04010     // (if we provide a 2nd hps for a window, the cursor in text
04011     // fields won't be erased when it's moved to another position)
04012   if (oHps)
04013     if (getHps && !mDragHps) {
04014       mDragHps = DrgGetPS(mWnd);
04015       *oHps = mDragHps;
04016     }
04017     else
04018       *oHps = 0;
04019 
04020   return rtn;
04021 }
04022 
04023 //-------------------------------------------------------------------------
04024 
04025 // if there's an outstanding drag hps & it matches the one
04026 // passed in, release it
04027 
04028 PRBool nsWindow::ReleaseIfDragHPS(HPS aHps)
04029 {
04030 
04031   if (mDragHps && aHps == mDragHps) {
04032     DrgReleasePS(mDragHps);
04033     mDragHps = 0;
04034     return PR_TRUE;
04035   }
04036 
04037   return PR_FALSE;
04038 }
04039 
04040 // --------------------------------------------------------------------------
04041 // Raptor object access
04042 // --------------------------------------------------------------------------
04043 
04044 // 'Native data'
04045 // function to translate from a WM_CHAR to an NS_VK_ constant ---------------
04046 PRUint32 WMChar2KeyCode(MPARAM mp1, MPARAM mp2)
04047 {
04048   PRUint32 rc = SHORT1FROMMP(mp2);  // character code
04049   PRUint32 rcmask = rc & 0x00FF;    // masked character code for key up events
04050   USHORT sc = CHAR4FROMMP(mp1);     // scan code
04051   USHORT flags = SHORT1FROMMP(mp1); // flag word
04052 
04053   // First check for characters.
04054   // This is complicated by keystrokes such as Ctrl+K not having the KC_CHAR
04055   // bit set, but thankfully they do have the character actually there.
04056   //
04057   // Assume that `if not vkey or deadkey or valid number then char'
04058   if (!(flags & (KC_VIRTUALKEY | KC_DEADKEY)) ||
04059       (rcmask >= '0' && rcmask <= '9' &&             // handle keys on Numpad, too,
04060        (isNumPadScanCode(sc) ? isNumlockOn : 1)) ) { // if NumLock is on
04061     if (flags & KC_KEYUP) { // On OS/2 the scancode is in the upper byte of
04062                             // usChar when KC_KEYUP is set so mask it off
04063       rc = rcmask;
04064     } else { // not KC_KEYUP
04065       if (! (flags & KC_CHAR)) {
04066         if ((flags & KC_ALT) || (flags & KC_CTRL))
04067           rc = rcmask;
04068         else
04069           rc = 0;
04070       }
04071     }
04072 
04073     if (rc < 0xFF) {
04074       if (rc >= 'a' && rc <= 'z') { // The DOM_VK are for upper case only so
04075                                     // if rc is lower case upper case it.
04076         rc = rc - 'a' + NS_VK_A;
04077       } else if (rc >= 'A' && rc <= 'Z') { // Upper case
04078         rc = rc - 'A' + NS_VK_A;
04079       } else if (rc >= '0' && rc <= '9') {
04080         // Number keys, including Numpad if NumLock is not set
04081         rc = rc - '0' + NS_VK_0;
04082       } else {
04083         /* For some characters, map the scan code to the NS_VK value */
04084         /* This only happens in the char case NOT the VK case! */
04085         switch (sc) {
04086           case 0x02: rc = NS_VK_1;             break;
04087           case 0x03: rc = NS_VK_2;             break;
04088           case 0x04: rc = NS_VK_3;             break;
04089           case 0x05: rc = NS_VK_4;             break;
04090           case 0x06: rc = NS_VK_5;             break;
04091           case 0x07: rc = NS_VK_6;             break;
04092           case 0x08: rc = NS_VK_7;             break;
04093           case 0x09: rc = NS_VK_8;             break;
04094           case 0x0A: rc = NS_VK_9;             break;
04095           case 0x0B: rc = NS_VK_0;             break;
04096           case 0x0D: rc = NS_VK_EQUALS;        break;
04097           case 0x1A: rc = NS_VK_OPEN_BRACKET;  break;
04098           case 0x1B: rc = NS_VK_CLOSE_BRACKET; break;
04099           case 0x27: rc = NS_VK_SEMICOLON;     break;
04100           case 0x28: rc = NS_VK_QUOTE;         break;
04101           case 0x29: rc = NS_VK_BACK_QUOTE;    break;
04102           case 0x2B: rc = NS_VK_BACK_SLASH;    break;
04103           case 0x33: rc = NS_VK_COMMA;         break;
04104           case 0x34: rc = NS_VK_PERIOD;        break;
04105           case 0x35: rc = NS_VK_SLASH;         break;
04106           case 0x37: rc = NS_VK_MULTIPLY;      break;
04107           case 0x4A: rc = NS_VK_SUBTRACT;      break;
04108           case 0x4C: rc = NS_VK_CLEAR;         break; // numeric case is handled above
04109           case 0x4E: rc = NS_VK_ADD;           break;
04110           case 0x5C: rc = NS_VK_DIVIDE;        break;
04111           default: break;
04112         } // switch
04113       } // else
04114     } // if (rc < 0xFF)
04115   } else if (flags & KC_VIRTUALKEY) {
04116     USHORT vk = SHORT2FROMMP(mp2);
04117     if (flags & KC_KEYUP) { // On OS/2 there are extraneous bits in the upper byte of
04118                             // usChar when KC_KEYUP is set so mask them off
04119       rc = rcmask;
04120     }
04121     if (isNumPadScanCode(sc) &&
04122         (((flags & KC_ALT) && (sc != PMSCAN_PADPERIOD)) ||
04123           ((flags & (KC_CHAR | KC_SHIFT)) == KC_CHAR)  ||
04124           ((flags & KC_KEYUP) && rc != 0) )) {
04125       CHAR numpadMap[] = {NS_VK_NUMPAD7, NS_VK_NUMPAD8, NS_VK_NUMPAD9, 0,
04126                           NS_VK_NUMPAD4, NS_VK_NUMPAD5, NS_VK_NUMPAD6, 0,
04127                           NS_VK_NUMPAD1, NS_VK_NUMPAD2, NS_VK_NUMPAD3,
04128                           NS_VK_NUMPAD0, NS_VK_DECIMAL};
04129       // If this is the Numpad must not return VK for ALT+Numpad or ALT+NumLock+Numpad
04130       // NumLock+Numpad is OK
04131       if (numpadMap[sc - PMSCAN_PAD7] != 0) { // not plus or minus on Numpad
04132         if (flags & KC_ALT ) // do not react on Alt plus ASCII-code sequences
04133           rc = 0;
04134         else
04135           rc = numpadMap[sc - PMSCAN_PAD7];
04136       } else {                                // plus or minus of Numpad
04137         rc = 0; // No virtual key for Alt+Numpad or NumLock+Numpad
04138       }
04139     } else if (!(flags & KC_CHAR) || isNumPadScanCode(sc) ||
04140                (vk == VK_BACKSPACE) || (vk == VK_TAB) || (vk == VK_BACKTAB) ||
04141                (vk == VK_ENTER) || (vk == VK_NEWLINE) || (vk == VK_SPACE)) {
04142       if (vk >= VK_F1 && vk <= VK_F24)
04143         rc = NS_VK_F1 + (vk - VK_F1);
04144       else switch (vk) {
04145         case VK_NUMLOCK:   rc = NS_VK_NUM_LOCK;    break;
04146         case VK_SCRLLOCK:  rc = NS_VK_SCROLL_LOCK; break;
04147         case VK_ESC:       rc = NS_VK_ESCAPE;      break; // NS_VK_CANCEL
04148         case VK_BACKSPACE: rc = NS_VK_BACK;        break;
04149         case VK_TAB:       rc = NS_VK_TAB;         break;
04150         case VK_BACKTAB:   rc = NS_VK_TAB;         break; // layout tests for isShift
04151         case VK_CLEAR:     rc = NS_VK_CLEAR;       break;
04152         case VK_NEWLINE:   rc = NS_VK_RETURN;      break;
04153         case VK_ENTER:     rc = NS_VK_RETURN;      break;
04154         case VK_SHIFT:     rc = NS_VK_SHIFT;       break;
04155         case VK_CTRL:      rc = NS_VK_CONTROL;     break;
04156         case VK_ALT:       rc = NS_VK_ALT;         break;
04157         case VK_PAUSE:     rc = NS_VK_PAUSE;       break;
04158         case VK_CAPSLOCK:  rc = NS_VK_CAPS_LOCK;   break;
04159         case VK_SPACE:     rc = NS_VK_SPACE;       break;
04160         case VK_PAGEUP:    rc = NS_VK_PAGE_UP;     break;
04161         case VK_PAGEDOWN:  rc = NS_VK_PAGE_DOWN;   break;
04162         case VK_END:       rc = NS_VK_END;         break;
04163         case VK_HOME:      rc = NS_VK_HOME;        break;
04164         case VK_LEFT:      rc = NS_VK_LEFT;        break;
04165         case VK_UP:        rc = NS_VK_UP;          break;
04166         case VK_RIGHT:     rc = NS_VK_RIGHT;       break;
04167         case VK_DOWN:      rc = NS_VK_DOWN;        break;
04168         case VK_PRINTSCRN: rc = NS_VK_PRINTSCREEN; break;
04169         case VK_INSERT:    rc = NS_VK_INSERT;      break;
04170         case VK_DELETE:    rc = NS_VK_DELETE;      break;
04171       } // switch
04172     }
04173   }
04174 
04175   return rc;
04176 }
04177 
04178 PCSZ nsWindow::WindowClass()
04179 {
04180     const PCSZ className = "MozillaWindowClass";
04181 
04182     if (!nsWindow::sIsRegistered)
04183     {
04184         nsWindow::sIsRegistered = WinRegisterClass((HAB)0, className,
04185                                                    WinDefWindowProc, 0, 4);
04186     }
04187 
04188     return className;
04189 }
04190 
04191 ULONG nsWindow::WindowStyle()
04192 {
04193    return BASE_CONTROL_STYLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
04194 }
04195 
04196 ULONG nsWindow::GetFCFlags()
04197 {
04198   ULONG style = FCF_TITLEBAR | FCF_SYSMENU | FCF_TASKLIST |
04199                 FCF_CLOSEBUTTON | FCF_NOBYTEALIGN | FCF_AUTOICON |
04200                 (gIsDBCS ? FCF_DBE_APPSTAT : 0);
04201 
04202   if (mWindowType == eWindowType_dialog) {
04203     style |= FCF_DIALOGBOX;
04204     if (mBorderStyle == eBorderStyle_default) {
04205       style |= FCF_DLGBORDER;
04206     } else {
04207       style |= FCF_SIZEBORDER | FCF_MINMAX;
04208     }
04209   }
04210   else {
04211     style |= FCF_SIZEBORDER | FCF_MINMAX;
04212   }
04213 
04214   if (mWindowType == eWindowType_invisible) {
04215     style &= ~FCF_TASKLIST;
04216   }
04217 
04218   if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) {
04219     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh)) {
04220       style &= ~FCF_SIZEBORDER;
04221       style |= FCF_DLGBORDER;
04222     }
04223     
04224     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border))
04225       style &= ~(FCF_DLGBORDER | FCF_SIZEBORDER);
04226     
04227     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) {
04228       style &= ~(FCF_TITLEBAR | FCF_TASKLIST);
04229     }
04230 
04231     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close))
04232       style &= ~FCF_CLOSEBUTTON;
04233 
04234     if (mBorderStyle == eBorderStyle_none ||
04235       !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
04236       style &= ~FCF_SYSMENU;
04237     // Looks like getting rid of the system menu also does away with the
04238     // close box. So, we only get rid of the system menu if you want neither it
04239     // nor the close box. How does the Windows "Dialog" window class get just
04240     // closebox and no sysmenu? Who knows.
04241     
04242     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize))
04243       style &= ~FCF_MINBUTTON;
04244     
04245     if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize))
04246       style &= ~FCF_MAXBUTTON;
04247   }
04248 
04249   return style;
04250 }