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 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 
00039 // ***IMPORTANT***
00040 // On all platforms, we are assuming in places that the implementation of |nsIWidget|
00041 // is really |nsWindow| and then calling methods specific to nsWindow to finish the job.
00042 // This is by design and the assumption is safe because an nsIWidget can only be created through
00043 // our Widget factory where all our widgets, including the XP widgets, inherit from nsWindow.
00044 // Still, in the places (or most of them) where this assumption is done, a |static_cast| has been used.
00045 // A similar warning is in nsWidgetFactory.cpp.
00046 
00047 
00048 #include "nsWindow.h"
00049 #include "nsIFontMetrics.h"
00050 #include "nsIDeviceContext.h"
00051 #include "nsCOMPtr.h"
00052 #include "nsToolkit.h"
00053 #include "nsIEnumerator.h"
00054 #include "prmem.h"
00055 
00056 #include <Appearance.h>
00057 #include <Timer.h>
00058 #include <Icons.h>
00059 #include <Errors.h>
00060 
00061 #include "nsplugindefs.h"
00062 #include "nsMacEventHandler.h"
00063 #include "nsMacResources.h"
00064 #include "nsIRegion.h"
00065 #include "nsIRollupListener.h"
00066 #include "nsPIWidgetMac.h"
00067 
00068 #include "nsCarbonHelpers.h"
00069 #include "nsGfxUtils.h"
00070 #include "nsRegionPool.h"
00071 
00072 #include <Gestalt.h>
00073 
00074 #ifdef MAC_OS_X_VERSION_10_3
00075 const short PANTHER_RESIZE_UP_CURSOR     = 19;
00076 const short PANTHER_RESIZE_DOWN_CURSOR   = 20;
00077 const short PANTHER_RESIZE_UPDOWN_CURSOR = 21;
00078 #else
00079 //19, 20, 21 from Appearance.h in 10.3
00080 const short PANTHER_RESIZE_UP_CURSOR     = 19; // kThemeResizeUpCursor
00081 const short PANTHER_RESIZE_DOWN_CURSOR   = 20; // kThemeResizeDownCursor
00082 const short PANTHER_RESIZE_UPDOWN_CURSOR = 21; // kThemeResizeUpDownCursor
00083 #endif
00084 
00085 const short JAGUAR_RESIZE_UP_CURSOR      = 135;
00086 const short JAGUAR_RESIZE_DOWN_CURSOR    = 136;
00087 const short JAGUAR_RESIZE_UPDOWN_CURSOR  = 141;
00088 
00090 nsIRollupListener * gRollupListener = nsnull;
00091 nsIWidget         * gRollupWidget   = nsnull;
00092 
00093 // Since we only want a single notification pending for the app we'll declare
00094 // these static
00095 static NMRec  gNMRec;
00096 static Boolean       gNotificationInstalled = false;
00097 
00098 //used to animate the Arrow + Beachball cursor
00099 static CursorSpinner *gCursorSpinner = nsnull;
00100 static const int kSpinCursorFirstFrame = 200;
00101 
00102 // Iterates over the rects of a region.
00103 static RegionToRectsUPP sAddRectToArrayProc = nsnull;
00104 
00105 #pragma mark -
00106 
00107 
00108 //#define PAINT_DEBUGGING         // flash areas as they are painted
00109 //#define INVALIDATE_DEBUGGING    // flash areas as they are invalidated
00110 
00111 #if defined(INVALIDATE_DEBUGGING) || defined(PAINT_DEBUGGING)
00112 static void blinkRect(const Rect* r, PRBool isPaint);
00113 static void blinkRgn(RgnHandle rgn, PRBool isPaint);
00114 #endif
00115 
00116 #if defined(INVALIDATE_DEBUGGING) || defined(PAINT_DEBUGGING) || defined (PINK_PROFILING)
00117 static Boolean KeyDown(const UInt8 theKey)
00118 {
00119        KeyMap map;
00120        GetKeys(map);
00121        return ((*((UInt8 *)map + (theKey >> 3)) >> (theKey & 7)) & 1) != 0;
00122 }
00123 #endif
00124 
00125 #if defined(INVALIDATE_DEBUGGING) || defined(PAINT_DEBUGGING)
00126 
00127 static Boolean caps_lock()
00128 {
00129   return KeyDown(0x39);
00130 }
00131 
00132 
00133 static void FlushCurPortBuffer()
00134 {
00135     CGrafPtr    curPort;
00136     ::GetPort((GrafPtr*)&curPort);
00137     ::QDFlushPortBuffer(curPort, nil);      // OK to call on 9/carbon (does nothing)
00138 }
00139 
00140 static void blinkRect(const Rect* r, PRBool isPaint)
00141 {
00142        StRegionFromPool oldClip;
00143        UInt32 endTicks;
00144 
00145     if (oldClip != NULL)
00146     ::GetClip(oldClip);
00147 
00148     ::ClipRect(r);
00149 
00150     if (isPaint)
00151     {
00152         Pattern grayPattern;
00153 
00154         ::GetQDGlobalsGray(&grayPattern);
00155 
00156         ::ForeColor(blackColor);
00157         ::BackColor(whiteColor);
00158 
00159         ::PenMode(patXor);
00160         ::PenPat(&grayPattern);
00161         ::PaintRect(r);
00162         FlushCurPortBuffer();
00163         ::Delay(5, &endTicks);
00164         ::PaintRect(r);
00165         FlushCurPortBuffer();
00166         ::PenNormal();
00167     }
00168     else
00169     {
00170         ::InvertRect(r);
00171         FlushCurPortBuffer();
00172         ::Delay(5, &endTicks);
00173         ::InvertRect(r);
00174         FlushCurPortBuffer();
00175     }
00176 
00177        if (oldClip != NULL)
00178               ::SetClip(oldClip);
00179 }
00180 
00181 static void blinkRgn(RgnHandle rgn, PRBool isPaint)
00182 {
00183     StRegionFromPool oldClip;
00184     UInt32 endTicks;
00185 
00186     if (oldClip != NULL)
00187         ::GetClip(oldClip);
00188 
00189     ::SetClip(rgn);
00190 
00191     if (isPaint)
00192     {
00193         Pattern grayPattern;
00194 
00195         ::GetQDGlobalsGray(&grayPattern);
00196 
00197         ::ForeColor(blackColor);
00198         ::BackColor(whiteColor);
00199 
00200         ::PenMode(patXor);
00201         ::PenPat(&grayPattern);
00202         ::PaintRgn(rgn);
00203         FlushCurPortBuffer();
00204 
00205         ::Delay(5, &endTicks);
00206         ::PaintRgn(rgn);
00207         FlushCurPortBuffer();
00208         ::PenNormal();
00209     }
00210     else
00211     {
00212         ::InvertRgn(rgn);
00213         FlushCurPortBuffer();
00214         ::Delay(5, &endTicks);
00215         ::InvertRgn(rgn);
00216         FlushCurPortBuffer();
00217     }
00218 
00219     if (oldClip != NULL)
00220         ::SetClip(oldClip);
00221 }
00222 
00223 #endif
00224 
00225 struct TRectArray
00226 {
00227   TRectArray(Rect* aRectList, PRUint32 aCapacity)
00228   : mRectList(aRectList)
00229   , mNumRects(0)
00230   , mCapacity(aCapacity) { }
00231 
00232   Rect*    mRectList;
00233   PRUint32 mNumRects;
00234   PRUint32 mCapacity;
00235 };
00236 
00237 #pragma mark -
00238 
00239 //-------------------------------------------------------------------------
00240 //
00241 // nsWindow constructor
00242 //
00243 //-------------------------------------------------------------------------
00244 nsWindow::nsWindow() : nsBaseWidget() , nsDeleteObserved(this), nsIKBStateControl()
00245 {
00246        WIDGET_SET_CLASSNAME("nsWindow");
00247 
00248   mParent = nsnull;
00249   mIsTopWidgetWindow = PR_FALSE;
00250   mBounds.SetRect(0,0,0,0);
00251 
00252   mResizingChildren = PR_FALSE;
00253   mVisible = PR_FALSE;
00254   mEnabled = PR_TRUE;
00255   SetPreferredSize(0,0);
00256 
00257   mFontMetrics = nsnull;
00258   mMenuBar = nsnull;
00259   mTempRenderingContext = nsnull;
00260 
00261   mWindowRegion = nsnull;
00262   mVisRegion = nsnull;
00263   mWindowPtr = nsnull;
00264   mDrawing = PR_FALSE;
00265   mInUpdate = PR_FALSE;
00266   mDestructorCalled = PR_FALSE;
00267 
00268   SetBackgroundColor(NS_RGB(255, 255, 255));
00269   SetForegroundColor(NS_RGB(0, 0, 0));
00270 
00271   mPluginPort = nsnull;
00272 
00273   AcceptFocusOnClick(PR_TRUE);
00274   
00275   if (!sAddRectToArrayProc)
00276     sAddRectToArrayProc = ::NewRegionToRectsUPP(AddRectToArrayProc);
00277 }
00278 
00279 
00280 //-------------------------------------------------------------------------
00281 //
00282 // nsWindow destructor
00283 //
00284 //-------------------------------------------------------------------------
00285 nsWindow::~nsWindow()
00286 {
00287        // notify the children that we're gone
00288        for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
00289               nsWindow* childWindow = NS_STATIC_CAST(nsWindow*, kid);
00290               childWindow->mParent = nsnull;
00291        }
00292 
00293        mDestructorCalled = PR_TRUE;
00294 
00295        //Destroy();
00296 
00297        if (mWindowRegion)
00298        {
00299               ::DisposeRgn(mWindowRegion);
00300               mWindowRegion = nsnull;     
00301        }
00302 
00303        if (mVisRegion)
00304        {
00305               ::DisposeRgn(mVisRegion);
00306               mVisRegion = nsnull; 
00307        }
00308                      
00309        NS_IF_RELEASE(mTempRenderingContext);
00310        
00311        NS_IF_RELEASE(mFontMetrics);
00312        NS_IF_RELEASE(mMenuBar);
00313        NS_IF_RELEASE(mMenuListener);
00314        
00315        if (mPluginPort) {
00316               delete mPluginPort;
00317        }
00318 }
00319 
00320 NS_IMPL_ISUPPORTS_INHERITED2(nsWindow, nsBaseWidget, nsIKBStateControl, nsIPluginWidget)
00321 
00322 //-------------------------------------------------------------------------
00323 //
00324 // Utility method for implementing both Create(nsIWidget ...) and
00325 // Create(nsNativeWidget...)
00326 //-------------------------------------------------------------------------
00327 
00328 nsresult nsWindow::StandardCreate(nsIWidget *aParent,
00329                       const nsRect &aRect,
00330                       EVENT_CALLBACK aHandleEventFunction,
00331                       nsIDeviceContext *aContext,
00332                       nsIAppShell *aAppShell,
00333                       nsIToolkit *aToolkit,
00334                       nsWidgetInitData *aInitData,
00335                       nsNativeWidget aNativeParent)     // should always be nil here
00336 {
00337        mParent = aParent;
00338        mBounds = aRect;
00339        CalcWindowRegions();
00340 
00341        BaseCreate(aParent, aRect, aHandleEventFunction, 
00342                                                  aContext, aAppShell, aToolkit, aInitData);
00343 
00344        if (mParent)
00345        {
00346               SetBackgroundColor(mParent->GetBackgroundColor());
00347               SetForegroundColor(mParent->GetForegroundColor());
00348        }
00349 
00350        if (mWindowPtr == nsnull) {
00351               if (aParent)
00352                      mWindowPtr = (WindowPtr)aParent->GetNativeData(NS_NATIVE_DISPLAY);
00353 /* this is always null
00354               else if (aAppShell)
00355                      mWindowPtr = (WindowPtr)aAppShell->GetNativeData(NS_NATIVE_SHELL);
00356 */
00357        }
00358        return NS_OK;
00359 }
00360 
00361 //-------------------------------------------------------------------------
00362 //
00363 // create a nswindow
00364 //
00365 //-------------------------------------------------------------------------
00366 NS_IMETHODIMP nsWindow::Create(nsIWidget *aParent,
00367                       const nsRect &aRect,
00368                       EVENT_CALLBACK aHandleEventFunction,
00369                       nsIDeviceContext *aContext,
00370                       nsIAppShell *aAppShell,
00371                       nsIToolkit *aToolkit,
00372                       nsWidgetInitData *aInitData)
00373 {       
00374        return(StandardCreate(aParent, aRect, aHandleEventFunction,
00375                                                                                            aContext, aAppShell, aToolkit, aInitData,
00376                                                                                                   nsnull));
00377 }
00378 
00379 //-------------------------------------------------------------------------
00380 //
00381 // Creates a main nsWindow using a native widget
00382 //
00383 //-------------------------------------------------------------------------
00384 NS_IMETHODIMP nsWindow::Create(nsNativeWidget aNativeParent,          // this is a nsWindow*
00385                       const nsRect &aRect,
00386                       EVENT_CALLBACK aHandleEventFunction,
00387                       nsIDeviceContext *aContext,
00388                       nsIAppShell *aAppShell,
00389                       nsIToolkit *aToolkit,
00390                       nsWidgetInitData *aInitData)
00391 {
00392        // On Mac, a native widget is a nsWindow* because 
00393        // nsWindow::GetNativeData(NS_NATIVE_WIDGET) returns 'this'
00394        nsIWidget* aParent = (nsIWidget*)aNativeParent;
00395        
00396        return(Create(aParent, aRect, aHandleEventFunction,
00397                                                                aContext, aAppShell, aToolkit, aInitData));
00398 }
00399 
00400 //-------------------------------------------------------------------------
00401 //
00402 // Close this nsWindow
00403 //
00404 //-------------------------------------------------------------------------
00405 NS_IMETHODIMP nsWindow::Destroy()
00406 {
00407        if (mOnDestroyCalled)
00408               return NS_OK;
00409        mOnDestroyCalled = PR_TRUE;
00410 
00411        nsBaseWidget::OnDestroy();
00412        nsBaseWidget::Destroy();
00413        mParent = 0;
00414 
00415   // just to be safe. If we're going away and for some reason we're still
00416   // the rollup widget, rollup and turn off capture.
00417   if ( this == gRollupWidget ) {
00418     if ( gRollupListener )
00419       gRollupListener->Rollup();
00420     CaptureRollupEvents(nsnull, PR_FALSE, PR_TRUE);
00421   }
00422 
00423        NS_IF_RELEASE(mMenuBar);
00424        SetMenuBar(nsnull);
00425 
00426        ReportDestroyEvent();       // beard: this seems to cause the window to be deleted. moved all release code to destructor.
00427 
00428        return NS_OK;
00429 }
00430 
00431 #pragma mark -
00432 
00433 //-------------------------------------------------------------------------
00434 //
00435 // Get this nsWindow parent
00436 //
00437 //-------------------------------------------------------------------------
00438 nsIWidget* nsWindow::GetParent(void)
00439 {
00440   if (mIsTopWidgetWindow) return nsnull;
00441   NS_IF_ADDREF(mParent);
00442   return  mParent;
00443 }
00444 
00445 //-------------------------------------------------------------------------
00446 //
00447 // Return some native data according to aDataType
00448 //
00449 //-------------------------------------------------------------------------
00450 void* nsWindow::GetNativeData(PRUint32 aDataType)
00451 {
00452        NS_ASSERTION(mWindowPtr, "GetNativeData was called after the window was destroyed?");
00453   
00454        nsPoint              point;
00455        void*         retVal = nsnull;
00456 
00457   switch (aDataType) 
00458        {
00459        case NS_NATIVE_WIDGET:
00460     case NS_NATIVE_WINDOW:
00461        retVal = (void*)this;
00462        break;
00463 
00464     case NS_NATIVE_GRAPHIC:
00465     // pinkerton
00466     // Windows and GrafPorts are VERY different under Carbon, and we can no
00467     // longer pass them interchagably. When we ask for a GrafPort, we cannot
00468     // return a window or vice versa.
00469       retVal = (void*)::GetWindowPort(mWindowPtr);
00470       break;
00471       
00472     case NS_NATIVE_DISPLAY:
00473       retVal = (void*)mWindowPtr;
00474        break;
00475 
00476     case NS_NATIVE_REGION:
00477               retVal = (void*)mVisRegion;
00478        break;
00479 
00480     case NS_NATIVE_COLORMAP:
00481        //•TODO
00482        break;
00483 
00484     case NS_NATIVE_OFFSETX:
00485        point.MoveTo(mBounds.x, mBounds.y);
00486        LocalToWindowCoordinate(point);
00487        retVal = (void*)point.x;
00488        break;
00489 
00490     case NS_NATIVE_OFFSETY:
00491        point.MoveTo(mBounds.x, mBounds.y);
00492        LocalToWindowCoordinate(point);
00493        retVal = (void*)point.y;
00494        break;
00495     
00496     case NS_NATIVE_PLUGIN_PORT:
00497        // this needs to be a combination of the port and the offsets.
00498        if (mPluginPort == nsnull)
00499               mPluginPort = new nsPluginPort;
00500               
00501               point.MoveTo(mBounds.x, mBounds.y);
00502               LocalToWindowCoordinate(point);
00503 
00504               // for compatibility with 4.X, this origin is what you'd pass
00505               // to SetOrigin.
00506               mPluginPort->port = ::GetWindowPort(mWindowPtr);
00507               mPluginPort->portx = -point.x;
00508               mPluginPort->porty = -point.y;
00509               
00510        retVal = (void*)mPluginPort;
00511        }
00512 
00513   return retVal;
00514 }
00515 
00516 #pragma mark -
00517 //-------------------------------------------------------------------------
00518 //
00519 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
00520 //
00521 //-------------------------------------------------------------------------
00522 NS_METHOD nsWindow::IsVisible(PRBool & bState)
00523 {
00524   bState = mVisible;
00525   return NS_OK;
00526 }
00527 
00528 //-------------------------------------------------------------------------
00529 //
00530 // Hide or show this component
00531 //
00532 //-------------------------------------------------------------------------
00533 NS_IMETHODIMP nsWindow::Show(PRBool bState)
00534 {
00535   mVisible = bState;
00536   return NS_OK;
00537 }
00538 
00539     
00540 NS_IMETHODIMP nsWindow::ModalEventFilter(PRBool aRealEvent, void *aEvent,
00541                                          PRBool *aForWindow)
00542 {
00543   *aForWindow = PR_TRUE;
00544   return NS_OK;
00545 }
00546 
00547 //-------------------------------------------------------------------------
00548 //
00549 // Enable/disable this component
00550 //
00551 //-------------------------------------------------------------------------
00552 NS_IMETHODIMP nsWindow::Enable(PRBool aState)
00553 {
00554        mEnabled = aState;
00555        return NS_OK;
00556 }
00557 
00558     
00559 NS_IMETHODIMP nsWindow::IsEnabled(PRBool *aState)
00560 {
00561        NS_ENSURE_ARG_POINTER(aState);
00562        *aState = mEnabled;
00563        return NS_OK;
00564 }
00565 
00566 static Boolean we_are_front_process()
00567 {
00568        ProcessSerialNumber  thisPSN;
00569        ProcessSerialNumber  frontPSN;
00570        (void)::GetCurrentProcess(&thisPSN);
00571        if (::GetFrontProcess(&frontPSN) == noErr)
00572        {
00573               if ((frontPSN.highLongOfPSN == thisPSN.highLongOfPSN) &&
00574                      (frontPSN.lowLongOfPSN == thisPSN.lowLongOfPSN))
00575                      return true;
00576        }
00577        return false;
00578 }
00579 
00580 //-------------------------------------------------------------------------
00581 //
00582 // Set the focus on this component
00583 //
00584 //-------------------------------------------------------------------------
00585 NS_IMETHODIMP nsWindow::SetFocus(PRBool aRaise)
00586 {
00587   nsCOMPtr<nsIWidget> top;
00588   nsToolkit::GetTopWidget(mWindowPtr, getter_AddRefs(top));
00589 
00590   if (top) {
00591     nsCOMPtr<nsPIWidgetMac_MOZILLA_1_8_BRANCH> topMac = do_QueryInterface(top);
00592 
00593     if (topMac) {
00594       nsMacEventDispatchHandler* eventDispatchHandler = nsnull;
00595       topMac->GetEventDispatchHandler(&eventDispatchHandler);
00596 
00597       if (eventDispatchHandler)
00598         eventDispatchHandler->SetFocus(this);
00599     }
00600   }
00601        
00602        // Here's where we see if there's a notification we need to remove
00603        if (gNotificationInstalled && we_are_front_process())
00604        {
00605               (void)::NMRemove(&gNMRec);
00606               gNotificationInstalled = false;
00607        }
00608        
00609        return NS_OK;
00610 }
00611 
00612 //-------------------------------------------------------------------------
00613 //
00614 // Get this component font
00615 //
00616 //-------------------------------------------------------------------------
00617 nsIFontMetrics* nsWindow::GetFont(void)
00618 {
00619        return mFontMetrics;
00620 }
00621 
00622     
00623 //-------------------------------------------------------------------------
00624 //
00625 // Set this component font
00626 //
00627 //-------------------------------------------------------------------------
00628 NS_IMETHODIMP nsWindow::SetFont(const nsFont &aFont)
00629 {
00630        NS_IF_RELEASE(mFontMetrics);
00631        if (mContext)
00632               mContext->GetMetricsFor(aFont, mFontMetrics);
00633        return NS_OK;
00634 }
00635 
00636 
00637 //-------------------------------------------------------------------------
00638 //
00639 // Set the colormap of the window
00640 //
00641 //-------------------------------------------------------------------------
00642 NS_IMETHODIMP nsWindow::SetColorMap(nsColorMap *aColorMap)
00643 {
00644        //•TODO
00645        // We may need to move this to nsMacWindow:
00646        // I'm not sure all the individual widgets
00647        // can have each their own colorMap on Mac.
00648        return NS_OK;
00649 }
00650 
00651 //-------------------------------------------------------------------------
00652 //
00653 // Set the widget's MenuBar.
00654 // Must be called after Create.
00655 // Releases a previously set nsIMenuBar
00656 // AddRefs the passed in nsIMenuBar
00657 // @param aMenuBar a pointer to an nsIMenuBar interface on an object
00658 //
00659 //-------------------------------------------------------------------------
00660 NS_IMETHODIMP nsWindow::SetMenuBar(nsIMenuBar * aMenuBar)
00661 {
00662   if (mMenuBar)
00663     mMenuBar->SetParent(nsnull);
00664   NS_IF_RELEASE(mMenuBar);
00665   NS_IF_ADDREF(aMenuBar);
00666   mMenuBar = aMenuBar;
00667   return NS_OK;
00668 }
00669 
00670 NS_IMETHODIMP nsWindow::ShowMenuBar(PRBool aShow)
00671 {
00672   // this may never be implemented on the Mac
00673   return NS_ERROR_FAILURE;
00674 }
00675 
00676 //-------------------------------------------------------------------------
00677 //
00678 // Get the widget's MenuBar.
00679 //
00680 //-------------------------------------------------------------------------
00681 nsIMenuBar* nsWindow::GetMenuBar()
00682 {
00683   return mMenuBar;
00684 }
00685 
00686 
00687 PRBool OnPantherOrLater() // Return true if we are on Mac OS X 10.3 or later
00688 {
00689     static PRBool gInitVer1030 = PR_FALSE;
00690     static PRBool gOnPantherOrLater = PR_FALSE;
00691     if(!gInitVer1030)
00692     {
00693         gOnPantherOrLater =
00694             (nsToolkit::OSXVersion() >= MAC_OS_X_VERSION_10_3_HEX);
00695         gInitVer1030 = PR_TRUE;
00696     }
00697     return gOnPantherOrLater;
00698 }
00699 
00700 //
00701 // SetCursor
00702 //
00703 // Override to set the cursor on the mac
00704 //
00705 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
00706 {
00707   nsBaseWidget::SetCursor(aCursor);
00708        
00709   if ( gCursorSpinner == nsnull )
00710   {
00711       gCursorSpinner = new CursorSpinner();
00712   }
00713   
00714   // mac specific cursor manipulation
00715   short cursor = -1;
00716   switch (aCursor)
00717   {
00718     case eCursor_standard:            cursor = kThemeArrowCursor; break;
00719     case eCursor_wait:                cursor = kThemeWatchCursor; break;
00720     case eCursor_select:              cursor = kThemeIBeamCursor; break;
00721     case eCursor_hyperlink:           cursor = kThemePointingHandCursor; break;
00722     case eCursor_crosshair:           cursor = kThemeCrossCursor; break;
00723     case eCursor_move:                cursor = kThemeOpenHandCursor; break;
00724     case eCursor_help:                cursor = 128; break;
00725     case eCursor_copy:                cursor = kThemeCopyArrowCursor; break;
00726     case eCursor_alias:               cursor = kThemeAliasArrowCursor; break;
00727     case eCursor_context_menu:        cursor = kThemeContextualMenuArrowCursor; break;
00728     case eCursor_cell:                cursor = kThemePlusCursor; break;
00729     case eCursor_grab:                cursor = kThemeOpenHandCursor; break;
00730     case eCursor_grabbing:            cursor = kThemeClosedHandCursor; break;
00731     case eCursor_spinning:            cursor = kSpinCursorFirstFrame; break; // better than kThemeSpinningCursor
00732     case eCursor_zoom_in:             cursor = 129; break;
00733     case eCursor_zoom_out:            cursor = 130; break;
00734     case eCursor_not_allowed:
00735     case eCursor_no_drop:             cursor = kThemeNotAllowedCursor; break;  
00736     case eCursor_col_resize:          cursor = 132; break; 
00737     case eCursor_row_resize:          cursor = 133; break;
00738     case eCursor_vertical_text:       cursor = 134; break;   
00739     case eCursor_all_scroll:          cursor = kThemeOpenHandCursor; break;
00740     case eCursor_n_resize:            cursor = OnPantherOrLater() ? PANTHER_RESIZE_UP_CURSOR : JAGUAR_RESIZE_UP_CURSOR; break;
00741     case eCursor_s_resize:            cursor = OnPantherOrLater() ? PANTHER_RESIZE_DOWN_CURSOR : JAGUAR_RESIZE_DOWN_CURSOR; break;
00742     case eCursor_w_resize:            cursor = kThemeResizeLeftCursor; break; 
00743     case eCursor_e_resize:            cursor = kThemeResizeRightCursor; break;
00744     case eCursor_nw_resize:           cursor = 137; break;
00745     case eCursor_se_resize:           cursor = 138; break;
00746     case eCursor_ne_resize:           cursor = 139; break;
00747     case eCursor_sw_resize:           cursor = 140; break;
00748     case eCursor_ew_resize:           cursor = kThemeResizeLeftRightCursor; break;
00749     case eCursor_ns_resize:           cursor = OnPantherOrLater() ? PANTHER_RESIZE_UPDOWN_CURSOR : JAGUAR_RESIZE_UPDOWN_CURSOR; break;
00750     case eCursor_nesw_resize:         cursor = 142; break;
00751     case eCursor_nwse_resize:         cursor = 143; break;        
00752     default:                          
00753       cursor = kThemeArrowCursor; 
00754       break;
00755   }
00756 
00757 
00758   if (aCursor == eCursor_spinning)
00759   {
00760     gCursorSpinner->StartSpinCursor();
00761   }
00762   else
00763   {
00764     gCursorSpinner->StopSpinCursor();
00765     nsWindow::SetCursorResource(cursor);
00766   }
00767 
00768   return NS_OK;
00769   
00770 } // nsWindow::SetCursor
00771 
00772 void nsWindow::SetCursorResource(short aCursorResourceNum)
00773 {
00774     if (aCursorResourceNum >= 0)
00775     {
00776         if (aCursorResourceNum >= 128)
00777         {
00778             nsMacResources::OpenLocalResourceFile();
00779             CursHandle cursHandle = ::GetCursor(aCursorResourceNum);
00780             NS_ASSERTION (cursHandle, "Can't load cursor, is the resource file installed correctly?");
00781             if (cursHandle)
00782             {
00783                 ::SetCursor(*cursHandle);
00784             }
00785             nsMacResources::CloseLocalResourceFile();            
00786         }
00787         else
00788         {
00789             ::SetThemeCursor(aCursorResourceNum);
00790         }
00791     }    
00792 }
00793 
00794 CursorSpinner::CursorSpinner() :
00795     mSpinCursorFrame(0), mTimerUPP(nsnull), mTimerRef(nsnull)
00796 {
00797    mTimerUPP = NewEventLoopTimerUPP(SpinCursor);
00798 }
00799 
00800 CursorSpinner::~CursorSpinner()
00801 {
00802     if (mTimerRef) ::RemoveEventLoopTimer(mTimerRef);
00803     if (mTimerUPP) ::DisposeEventLoopTimerUPP(mTimerUPP);
00804 }
00805 
00806 short CursorSpinner::GetNextCursorFrame()
00807 {
00808     int result = kSpinCursorFirstFrame + mSpinCursorFrame;
00809     mSpinCursorFrame = (mSpinCursorFrame + 1) % 4;
00810     return (short) result;
00811 }
00812 
00813 void CursorSpinner::StartSpinCursor()
00814 {
00815     OSStatus result = noErr;
00816     if (mTimerRef == nsnull)
00817     {
00818         result = ::InstallEventLoopTimer(::GetMainEventLoop(), 0, 0.25 * kEventDurationSecond,
00819                                          mTimerUPP, this, &mTimerRef);
00820         if (result != noErr)
00821         {
00822             mTimerRef = nsnull;
00823             nsWindow::SetCursorResource(kSpinCursorFirstFrame);
00824         }
00825     }
00826 }
00827 
00828 void CursorSpinner::StopSpinCursor()
00829 {
00830     if (mTimerRef)
00831     {
00832         ::RemoveEventLoopTimer(mTimerRef);
00833         mTimerRef = nsnull;
00834     }
00835 }
00836 
00837 pascal void CursorSpinner::SpinCursor(EventLoopTimerRef inTimer, void *inUserData)
00838 {
00839     CursorSpinner* cs = reinterpret_cast<CursorSpinner*>(inUserData);
00840     nsWindow::SetCursorResource(cs->GetNextCursorFrame());
00841 }
00842 
00843 #pragma mark -
00844 //-------------------------------------------------------------------------
00845 //
00846 // Get this component dimension
00847 //
00848 //-------------------------------------------------------------------------
00849 NS_IMETHODIMP nsWindow::GetBounds(nsRect &aRect)
00850 {
00851   aRect = mBounds;
00852   return NS_OK;
00853 }
00854 
00855 
00856 NS_METHOD nsWindow::SetBounds(const nsRect &aRect)
00857 {
00858   nsresult rv = Inherited::SetBounds(aRect);
00859   if ( NS_SUCCEEDED(rv) )
00860     CalcWindowRegions();
00861 
00862   return rv;
00863 }
00864 
00865 
00866 NS_IMETHODIMP nsWindow::ConstrainPosition(PRBool aAllowSlop,
00867                                           PRInt32 *aX, PRInt32 *aY)
00868 {
00869        return NS_OK;
00870 }
00871 
00872 //-------------------------------------------------------------------------
00873 //
00874 // Move this component
00875 // aX and aY are in the parent widget coordinate system
00876 //-------------------------------------------------------------------------
00877 NS_IMETHODIMP nsWindow::Move(PRInt32 aX, PRInt32 aY)
00878 {
00879        if ((mBounds.x != aX) || (mBounds.y != aY))
00880        {
00881               // Invalidate the current location (unless it's the top-level window)
00882               if ((mParent != nsnull) && (!mIsTopWidgetWindow))
00883                      Invalidate(PR_FALSE);
00884               
00885               // Set the bounds
00886               mBounds.x = aX;
00887               mBounds.y = aY;
00888 
00889               // Recalculate the regions
00890               CalcWindowRegions();
00891 
00892               // Report the event
00893               ReportMoveEvent();
00894        }
00895        return NS_OK;
00896 }
00897 
00898 //-------------------------------------------------------------------------
00899 //
00900 // Resize this component
00901 //
00902 //-------------------------------------------------------------------------
00903 NS_IMETHODIMP nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
00904 {
00905   if ((mBounds.width != aWidth) || (mBounds.height != aHeight))
00906   {
00907     // Set the bounds
00908     mBounds.width  = aWidth;
00909     mBounds.height = aHeight;
00910 
00911        // Recalculate the regions
00912        CalcWindowRegions();
00913        
00914     // Invalidate the new location
00915     if (aRepaint)
00916       Invalidate(PR_FALSE);
00917 
00918     // Report the event
00919     ReportSizeEvent();
00920   }
00921   else {
00922     // Recalculate the regions. We always need to do this, our parents may have
00923     // changed, hence changing our notion of visibility. We then also should make
00924     // sure that we invalidate ourselves correctly. Fixes bug 18240 (pinkerton).
00925     CalcWindowRegions();
00926     if (aRepaint)
00927       Invalidate(PR_FALSE);
00928   }
00929 
00930   return NS_OK;
00931 }
00932 
00933 //-------------------------------------------------------------------------
00934 //
00935 // Resize this component
00936 //
00937 //-------------------------------------------------------------------------
00938 NS_IMETHODIMP nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
00939 {
00940        Move(aX, aY);
00941        Resize(aWidth, aHeight, aRepaint);
00942        return NS_OK;
00943 }
00944 
00945 
00946 NS_METHOD nsWindow::GetPreferredSize(PRInt32& aWidth, PRInt32& aHeight)
00947 {
00948   aWidth  = mPreferredWidth;
00949   aHeight = mPreferredHeight;
00950   return NS_ERROR_FAILURE;
00951 }
00952 
00953 NS_METHOD nsWindow::SetPreferredSize(PRInt32 aWidth, PRInt32 aHeight)
00954 {
00955   mPreferredWidth  = aWidth;
00956   mPreferredHeight = aHeight;
00957   return NS_OK;
00958 }
00959 
00960 //-------------------------------------------------------------------------
00961 // 
00962 //
00963 //-------------------------------------------------------------------------
00964 NS_IMETHODIMP nsWindow::BeginResizingChildren(void)
00965 {
00966        mResizingChildren = PR_TRUE;
00967        mSaveVisible = mVisible;
00968        mVisible = PR_FALSE;
00969 
00970        return NS_OK;
00971 }
00972 
00973 //-------------------------------------------------------------------------
00974 // 
00975 //
00976 //-------------------------------------------------------------------------
00977 NS_IMETHODIMP nsWindow::EndResizingChildren(void)
00978 {
00979        mResizingChildren = PR_FALSE;
00980        mVisible = mSaveVisible;
00981 
00982        CalcWindowRegions();
00983        return NS_OK;
00984 }
00985 
00986 
00987 //-------------------------------------------------------------------------
00988 //
00989 // Validate this component's visible area
00990 //
00991 //-------------------------------------------------------------------------
00992 NS_IMETHODIMP nsWindow::Validate()
00993 {
00994        if (!mWindowPtr || !mVisible || !ContainerHierarchyIsVisible())
00995               return NS_OK;
00996 
00997        nsRect wRect = mBounds;
00998        LocalToWindowCoordinate(wRect);
00999        Rect macRect;
01000        nsRectToMacRect(wRect, macRect);
01001 
01002        StPortSetter    portSetter(mWindowPtr);
01003        StOriginSetter  originSetter(mWindowPtr);
01004 
01005        ::ValidWindowRect(mWindowPtr, &macRect);
01006 
01007        return NS_OK;
01008 }
01009 
01010 //-------------------------------------------------------------------------
01011 //
01012 // Invalidate this component's visible area
01013 //
01014 //-------------------------------------------------------------------------
01015 NS_IMETHODIMP nsWindow::Invalidate(PRBool aIsSynchronous)
01016 {
01017        nsRect area = mBounds;
01018        area.x = area.y = 0;
01019        Invalidate(area, aIsSynchronous);
01020        return NS_OK;
01021 }
01022 
01023 //-------------------------------------------------------------------------
01024 //
01025 // Invalidate this component's visible area
01026 //
01027 //-------------------------------------------------------------------------
01028 NS_IMETHODIMP nsWindow::Invalidate(const nsRect &aRect, PRBool aIsSynchronous)
01029 {
01030        if (!mWindowPtr)
01031               return NS_OK;
01032 
01033   if (!mVisible || !ContainerHierarchyIsVisible())
01034     return NS_OK;
01035 
01036        nsRect wRect = aRect;
01037        wRect.MoveBy(mBounds.x, mBounds.y);                            // beard:  this is required, see GetNativeData(NS_NATIVE_OFFSETX).
01038        LocalToWindowCoordinate(wRect);
01039        Rect macRect;
01040        nsRectToMacRect(wRect, macRect);
01041 
01042        StPortSetter portSetter(mWindowPtr);
01043        StOriginSetter  originSetter(mWindowPtr);
01044 
01045 #ifdef INVALIDATE_DEBUGGING
01046        if (caps_lock())
01047               ::blinkRect(&macRect, PR_FALSE);
01048 #endif
01049 
01050        ::InvalWindowRect(mWindowPtr, &macRect);
01051        if ( aIsSynchronous )
01052          Update();
01053 
01054        return NS_OK;
01055 }
01056 
01057 //-------------------------------------------------------------------------
01058 //
01059 // Invalidate this component's visible area
01060 //
01061 //-------------------------------------------------------------------------
01062 
01063 NS_IMETHODIMP nsWindow::InvalidateRegion(const nsIRegion *aRegion, PRBool aIsSynchronous)
01064 {
01065        if (!mWindowPtr)
01066               return NS_OK;
01067 
01068   if (!mVisible || !ContainerHierarchyIsVisible())
01069     return NS_OK;
01070     
01071        // copy invalid region into a working region.
01072        void* nativeRgn;
01073        aRegion->GetNativeRegion(nativeRgn);
01074        StRegionFromPool windowRgn;
01075        ::CopyRgn(RgnHandle(nativeRgn), windowRgn);
01076 
01077        // translate this region into window coordinates.
01078        PRInt32       offX, offY;
01079        CalcOffset(offX, offY);
01080        ::OffsetRgn(windowRgn, mBounds.x + offX, mBounds.y + offY);
01081        
01082        StPortSetter    portSetter(mWindowPtr);
01083     StOriginSetter  originSetter(mWindowPtr);
01084 
01085 #ifdef INVALIDATE_DEBUGGING
01086        if (caps_lock())
01087               ::blinkRgn(windowRgn, PR_FALSE);
01088 #endif
01089 
01090        ::InvalWindowRgn(mWindowPtr, windowRgn);
01091        if ( aIsSynchronous )
01092          Update();
01093 
01094        return NS_OK;
01095 }
01096 
01097 inline PRUint16 COLOR8TOCOLOR16(PRUint8 color8)
01098 {
01099        // return (color8 == 0xFF ? 0xFFFF : (color8 << 8));
01100        return (color8 << 8) | color8;     /* (color8 * 257) == (color8 * 0x0101) */
01101 }
01102 
01103 //-------------------------------------------------------------------------
01104 //     StartDraw
01105 //
01106 //-------------------------------------------------------------------------
01107 void nsWindow::StartDraw(nsIRenderingContext* aRenderingContext)
01108 {
01109        if (mDrawing || mOnDestroyCalled)
01110               return;
01111        mDrawing = PR_TRUE;
01112 
01113        CalcWindowRegions(); //•REVISIT
01114 
01115        if (aRenderingContext == nsnull)
01116        {
01117               // make sure we have a rendering context
01118               mTempRenderingContext = GetRenderingContext();
01119               mTempRenderingContextMadeHere = PR_TRUE;
01120        }
01121        else
01122        {
01123               // if we already have a rendering context, save its state
01124               NS_IF_ADDREF(aRenderingContext);
01125               mTempRenderingContext = aRenderingContext;
01126               mTempRenderingContextMadeHere = PR_FALSE;
01127 
01128               // set the environment to the current widget
01129               mTempRenderingContext->Init(mContext, this);
01130        }
01131 
01132        // set the widget font. nsMacControl implements SetFont, which is where
01133        // the font should get set.
01134        if (mFontMetrics)
01135        {
01136               mTempRenderingContext->SetFont(mFontMetrics);
01137        }
01138 
01139        // set the widget background and foreground colors
01140        nscolor color = GetBackgroundColor();
01141        RGBColor macColor;
01142        macColor.red   = COLOR8TOCOLOR16(NS_GET_R(color));
01143        macColor.green = COLOR8TOCOLOR16(NS_GET_G(color));
01144        macColor.blue  = COLOR8TOCOLOR16(NS_GET_B(color));
01145        ::RGBBackColor(&macColor);
01146 
01147        color = GetForegroundColor();
01148        macColor.red   = COLOR8TOCOLOR16(NS_GET_R(color));
01149        macColor.green = COLOR8TOCOLOR16(NS_GET_G(color));
01150        macColor.blue  = COLOR8TOCOLOR16(NS_GET_B(color));
01151        ::RGBForeColor(&macColor);
01152 
01153        mTempRenderingContext->SetColor(color);                        // just in case, set the rendering context color too
01154        mTempRenderingContext->PushState();           // push the state so we can pop it later
01155 }
01156 
01157 
01158 //-------------------------------------------------------------------------
01159 //     EndDraw
01160 //
01161 //-------------------------------------------------------------------------
01162 void nsWindow::EndDraw()
01163 {
01164        if (! mDrawing || mOnDestroyCalled)
01165               return;
01166        mDrawing = PR_FALSE;
01167 
01168        mTempRenderingContext->PopState();
01169 
01170        NS_RELEASE(mTempRenderingContext);
01171        
01172        // note that we may leave the window origin in an unspecified state here
01173 }
01174 
01175 
01176 //-------------------------------------------------------------------------
01177 //
01178 //
01179 //-------------------------------------------------------------------------
01180 void
01181 nsWindow::Flash(nsPaintEvent       &aEvent)
01182 {
01183 #ifdef NS_DEBUG
01184        Rect flashRect;
01185        if (debug_WantPaintFlashing() && aEvent.rect ) {
01186               ::SetRect ( &flashRect, aEvent.rect->x, aEvent.rect->y, aEvent.rect->x + aEvent.rect->width,
01187                  aEvent.rect->y + aEvent.rect->height );
01188               StPortSetter portSetter(mWindowPtr);
01189               unsigned long endTicks;
01190               ::InvertRect ( &flashRect );
01191               ::Delay(10, &endTicks);
01192               ::InvertRect ( &flashRect );
01193        }
01194 #endif
01195 }
01196 
01197 
01198 //
01199 // OnPaint
01200 //
01201 // Dummy impl, meant to be overridden
01202 //
01203 PRBool
01204 nsWindow::OnPaint(nsPaintEvent &event)
01205 {
01206        return PR_TRUE;
01207 }
01208 
01209 
01210 //-------------------------------------------------------------------------
01211 //     Update
01212 //
01213 //            Redraw this widget.
01214 //
01215 //            We draw the widget between BeginUpdate and EndUpdate because some
01216 //            operations go much faster when the visRgn contains what needs to be
01217 //            painted. Then we restore the original updateRgn and validate this
01218 //            widget's rectangle.
01219 //-------------------------------------------------------------------------
01220 NS_IMETHODIMP nsWindow::Update()
01221 {
01222   if (! mVisible || !mWindowPtr || !ContainerHierarchyIsVisible())
01223     return NS_OK;
01224 
01225   static PRBool  reentrant = PR_FALSE;
01226 
01227   if (reentrant)
01228     HandleUpdateEvent(nil);
01229   else
01230   {
01231     reentrant = PR_TRUE;
01232     
01233     StRegionFromPool redrawnRegion;
01234     if (!redrawnRegion)
01235       return NS_ERROR_OUT_OF_MEMORY;
01236 
01237     // make a copy of the window update rgn (which is in global coords)
01238     StRegionFromPool saveUpdateRgn;
01239     if (!saveUpdateRgn)
01240       return NS_ERROR_OUT_OF_MEMORY;
01241     ::GetWindowRegion(mWindowPtr, kWindowUpdateRgn, saveUpdateRgn);
01242 
01243     // Sometimes, the window update region will be larger than the window
01244     // itself.  Because we obviously don't redraw anything outside of the
01245     // window, redrawnRegion won't include that larger area, and the
01246     // larger area will be re-invalidated.  That triggers an endless
01247     // sequence of kEventWindowUpdate events.  Avoid that condition by
01248     // restricting the update region to the content region.
01249     StRegionFromPool windowContentRgn;
01250     if (!windowContentRgn)
01251       return NS_ERROR_OUT_OF_MEMORY;
01252 
01253     ::GetWindowRegion(mWindowPtr, kWindowContentRgn, windowContentRgn);
01254 
01255     ::SectRgn(saveUpdateRgn, windowContentRgn, saveUpdateRgn);
01256 
01257     // draw the widget
01258     StPortSetter portSetter(mWindowPtr);
01259     StOriginSetter originSetter(mWindowPtr);
01260 
01261     // BeginUpate replaces the visRgn with the intersection of the
01262     // visRgn and the updateRgn.
01263     ::BeginUpdate(mWindowPtr);
01264     mInUpdate = PR_TRUE;
01265 
01266     HandleUpdateEvent(redrawnRegion);
01267 
01268     // EndUpdate replaces the normal visRgn
01269     ::EndUpdate(mWindowPtr);
01270     mInUpdate = PR_FALSE;
01271     
01272     // Restore the parts of the window update rgn that we didn't draw,
01273     // taking care to maintain any bits that got invalidated during the
01274     // paint (yes, this can happen). We do this because gecko might not own
01275     // the entire window (think: embedding).
01276 
01277     Point origin = {0, 0};
01278     ::GlobalToLocal(&origin);
01279     // saveUpdateRgn is in global coords, so we need to shift it to local coords
01280     ::OffsetRgn(saveUpdateRgn, origin.h, origin.v);
01281     
01282     // figure out the difference between the old update region
01283     // and what we redrew
01284     ::DiffRgn(saveUpdateRgn, redrawnRegion, saveUpdateRgn);
01285 
01286     // and invalidate it
01287     ::InvalWindowRgn(mWindowPtr, saveUpdateRgn);
01288 
01289     reentrant = PR_FALSE;
01290   }
01291 
01292   return NS_OK;
01293 }
01294 
01295 
01296 #pragma mark -
01297 
01298 
01299 
01300 
01301 //
01302 // AddRectToArrayProc
01303 //
01304 // Add each rect to an array so we can post-process them. |inArray| is a
01305 // pointer to the TRectArray we're adding to.
01306 //
01307 OSStatus
01308 nsWindow::AddRectToArrayProc(UInt16 message, RgnHandle rgn,
01309                              const Rect* inDirtyRect, void* inArray)
01310 {
01311   if (message == kQDRegionToRectsMsgParse) {
01312     NS_ASSERTION(inArray, "You better pass an array!");
01313     TRectArray* rectArray = NS_REINTERPRET_CAST(TRectArray*, inArray);
01314 
01315     if (rectArray->mNumRects == rectArray->mCapacity) {
01316       // This should not happen - returning memFullErr below should have
01317       // prevented it.
01318       return memFullErr;
01319     }
01320 
01321     rectArray->mRectList[rectArray->mNumRects++] = *inDirtyRect;
01322 
01323     if (rectArray->mNumRects == rectArray->mCapacity) {
01324       // Signal that the array is full and QDRegionToRects should stop.
01325       // After returning memFullErr, this proc should not be called with
01326       // the same |message| again.
01327       return memFullErr;
01328     }
01329   }
01330 
01331   return noErr;
01332 }
01333 
01334 
01335 //
01336 // PaintUpdateRect
01337 //
01338 // Called once for every rect in the update region. Send a paint event to Gecko to handle
01339 // this. |inData| contains the |nsWindow| being updated. 
01340 //
01341 void 
01342 nsWindow::PaintUpdateRect(Rect *inDirtyRect, void* inData)
01343 {
01344   nsWindow* self = NS_REINTERPRET_CAST(nsWindow*, inData);
01345   Rect dirtyRect = *inDirtyRect;
01346    
01347        nsCOMPtr<nsIRenderingContext> renderingContext ( dont_AddRef(self->GetRenderingContext()) );
01348        if (renderingContext)
01349        {
01350         nsRect bounds = self->mBounds;
01351         self->LocalToWindowCoordinate(bounds);
01352 
01353         // determine the rect to draw
01354         ::OffsetRect(&dirtyRect, -bounds.x, -bounds.y);
01355         nsRect rect ( dirtyRect.left, dirtyRect.top, dirtyRect.right - dirtyRect.left,
01356                         dirtyRect.bottom - dirtyRect.top );
01357 
01358         // update the widget
01359         self->UpdateWidget(rect, renderingContext);
01360   }
01361 
01362 } // PaintUpdateRect
01363 
01364 
01365 //-------------------------------------------------------------------------
01366 //     HandleUpdateEvent
01367 //
01368 //            Called by the event handler to redraw the top-level widget.
01369 //            Must be called between BeginUpdate/EndUpdate: the window visRgn
01370 //            is expected to be set to whatever needs to be drawn.
01371 //-------------------------------------------------------------------------
01372 nsresult nsWindow::HandleUpdateEvent(RgnHandle regionToValidate)
01373 {
01374   if (! mVisible || !ContainerHierarchyIsVisible())
01375     return NS_OK;
01376 
01377   // make sure the port is set and origin is (0, 0).
01378   StPortSetter    portSetter(mWindowPtr);
01379   // zero the origin, and set it back after drawing widgets
01380   StOriginSetter  originSetter(mWindowPtr);
01381   
01382   // get the damaged region from the OS
01383   StRegionFromPool damagedRgn;
01384   if (!damagedRgn)
01385     return NS_ERROR_OUT_OF_MEMORY;
01386   ::GetPortVisibleRegion(::GetWindowPort(mWindowPtr), damagedRgn);
01387 
01388 /*
01389 #ifdef PAINT_DEBUGGING  
01390   if (caps_lock())
01391     blinkRgn(damagedRgn, PR_TRUE);
01392 #endif
01393 */
01394   // calculate the update region relatively to the window port rect
01395   // (at this point, the grafPort origin should always be 0,0
01396   // so mWindowRegion has to be converted to window coordinates)
01397   StRegionFromPool updateRgn;
01398   if (!updateRgn)
01399     return NS_ERROR_OUT_OF_MEMORY;
01400   ::CopyRgn(mWindowRegion, updateRgn);
01401 
01402   nsRect bounds = mBounds;
01403   LocalToWindowCoordinate(bounds);
01404   ::OffsetRgn(updateRgn, bounds.x, bounds.y);
01405 
01406   // check if the update region is visible
01407   ::SectRgn(damagedRgn, updateRgn, updateRgn);
01408 
01409 #ifdef PAINT_DEBUGGING
01410   if (caps_lock())
01411     blinkRgn(updateRgn, PR_TRUE);
01412 #endif
01413 
01414   if (!::EmptyRgn(updateRgn)) {
01415     // Iterate over each rect in the region, sending a paint event for each.
01416     // If the region is very complicated (more than 15 pieces), just use a
01417     // bounding box.
01418 
01419     // The most rects we'll try to deal with:
01420     const PRUint32 kMaxUpdateRects = 15;
01421     
01422     // If, after combining rects, there are still more than this, just do
01423     // a bounding box:
01424     const PRUint32 kRectsBeforeBoundingBox = 10;
01425 
01426     // Leave one extra slot in rectList to give AddRectToArrayProc a way to
01427     // signal that kMaxUpdateRects has been exceeded.
01428     const PRUint32 kRectCapacity = kMaxUpdateRects + 1;
01429 
01430     Rect rectList[kRectCapacity];
01431     TRectArray rectWrapper(rectList, kRectCapacity);
01432     ::QDRegionToRects(updateRgn, kQDParseRegionFromTopLeft,
01433                       sAddRectToArrayProc, &rectWrapper);
01434     PRUint32 numRects = rectWrapper.mNumRects;
01435 
01436     PRBool painted = PR_FALSE;
01437 
01438     if (numRects <= kMaxUpdateRects) {
01439       if (numRects > 1) {
01440         // amalgamate adjoining rects into a single rect. This 
01441         // may over-draw a little, but will prevent us from going down into
01442         // the layout engine for lots of little 1-pixel wide rects.
01443         CombineRects(rectWrapper);
01444 
01445         // |numRects| may be invalid now, so check count again.
01446         numRects = rectWrapper.mNumRects;
01447       }
01448 
01449       // Now paint 'em!
01450       // If we're above a certain threshold, just bail and do bounding box.
01451       if (numRects < kRectsBeforeBoundingBox) {
01452         painted = PR_TRUE;
01453         for (PRUint32 i = 0 ; i < numRects ; i++)
01454           PaintUpdateRect(&rectList[i], this);
01455       }
01456     }
01457 
01458     if (!painted) {
01459       // There were too many rects.  Do a bounding box.
01460       Rect boundingBox;
01461       ::GetRegionBounds(updateRgn, &boundingBox);
01462       PaintUpdateRect(&boundingBox, this);
01463     }
01464 
01465     // Copy updateRgn to regionToValidate
01466     if (regionToValidate)
01467       ::CopyRgn(updateRgn, regionToValidate);
01468   }
01469 
01470   NS_ASSERTION(ValidateDrawingState(), "Bad drawing state");
01471 
01472   return NS_OK;
01473 }
01474 
01475 
01476 //
01477 // SortRectsLeftToRight
01478 //
01479 // |inRectArray| is an array of mac |Rect|s, sort them by increasing |left|
01480 // values (so they are sorted left to right). I feel so dirty for using a
01481 // bubble sort, but darn if it isn't simple and we're only going to have 
01482 // about 10 of these rects at maximum (that's a fairly compilicated update
01483 // region).
01484 //
01485 void
01486 nsWindow::SortRectsLeftToRight ( TRectArray & inRectArray )
01487 {
01488   PRInt32 numRects = inRectArray.mNumRects;
01489   
01490   for ( int i = 0; i < numRects - 1; ++i ) {
01491     for ( int j = i+1; j < numRects; ++j ) {
01492       if ( inRectArray.mRectList[j].left < inRectArray.mRectList[i].left ) {
01493         Rect temp = inRectArray.mRectList[i];
01494         inRectArray.mRectList[i] = inRectArray.mRectList[j];
01495         inRectArray.mRectList[j] = temp;
01496       }
01497     }
01498   }
01499 
01500 } // SortRectsLeftToRight
01501 
01502 
01503 //
01504 // CombineRects
01505 //
01506 // When breaking up our update region into rects, invariably we end up with lots
01507 // of tall, thin rectangles that are right next to each other (the drop
01508 // shadow of windows are an extreme case). Combine adjacent rectangles if the 
01509 // wasted area (the difference between area of the two rects and the bounding
01510 // box of the two joined rects) is small enough.
01511 //
01512 // As a side effect, the rects will be sorted left->right.
01513 //
01514 void
01515 nsWindow::CombineRects ( TRectArray & rectArray )
01516 {
01517   const float kCombineThresholdRatio = 0.50;      // 50%
01518   
01519   // We assume the rects are sorted left to right below, so sort 'em.
01520   SortRectsLeftToRight ( rectArray );
01521   
01522   // Here's basically what we're doing:
01523   //
01524   // compute the area of X and X+1
01525   // compute area of the bounding rect (topLeft of X and bottomRight of X+1)
01526   // if ( ratio of combined areas to bounding box is > 50% )
01527   //   make bottomRight of X be bottomRight of X+1
01528   //   delete X+1 from array and don't advance X, 
01529   //    otherwise move along to X+1
01530   
01531   PRUint32 i = 0;
01532   while (i < rectArray.mNumRects - 1) {
01533     Rect* curr = &rectArray.mRectList[i];
01534     Rect* next = &rectArray.mRectList[i+1];
01535   
01536     // compute areas of current and next rects
01537     int currArea = (curr->right - curr->left) * (curr->bottom - curr->top);
01538     int nextArea = (next->right - next->left) * (next->bottom - next->top);
01539 
01540     // compute the bounding box and its area
01541     Rect boundingBox;
01542     ::UnionRect ( curr, next, &boundingBox );
01543     int boundingRectArea = (boundingBox.right - boundingBox.left) * 
01544                               (boundingBox.bottom - boundingBox.top);
01545     
01546     // determine if we should combine the rects, based on if the ratio of the
01547     // combined areas to the bounding rect's area is above some threshold.
01548     if ( (currArea + nextArea) / (float)boundingRectArea > kCombineThresholdRatio ) {
01549       // we're combining, so combine the rects, delete the next rect (i+1), remove it from
01550       // the array, and _don't_ advance to the next rect.
01551       
01552       // make the current rectangle the bounding box and shift everything from 
01553       // i+2 over.
01554       *curr = boundingBox;
01555       for (PRUint32 j = i + 1 ; j < rectArray.mNumRects - 1 ; ++j)
01556         rectArray.mRectList[j] = rectArray.mRectList[j+1];
01557       --rectArray.mNumRects;
01558       
01559     } // if we should combine
01560     else
01561       ++i;
01562   } // foreach rect
01563   
01564 } // CombineRects
01565 
01566 
01567 #pragma mark -
01568 
01569 
01570 //-------------------------------------------------------------------------
01571 //
01572 //
01573 //-------------------------------------------------------------------------
01574 void nsWindow::UpdateWidget(nsRect& aRect, nsIRenderingContext* aContext)
01575 {
01576        if (! mVisible || !ContainerHierarchyIsVisible())
01577               return;
01578 
01579        // initialize the paint event
01580        nsPaintEvent paintEvent(PR_TRUE, NS_PAINT, this);
01581        paintEvent.renderingContext = aContext;         // nsPaintEvent
01582        paintEvent.rect             = &aRect;
01583 
01584        // draw the widget
01585        StartDraw(aContext);
01586 
01587        if ( OnPaint(paintEvent) ) {
01588               nsEventStatus eventStatus;
01589               DispatchWindowEvent(paintEvent,eventStatus);
01590               if(eventStatus != nsEventStatus_eIgnore)
01591                      Flash(paintEvent);
01592        }
01593 
01594        EndDraw();
01595 
01596        // beard:  Since we clip so aggressively, drawing from front to back should work,
01597        // and it does for the most part. However; certain cases, such as overlapping
01598        // areas that are handled by different view managers, don't properly clip siblings.
01599 #ifdef FRONT_TO_BACK
01600 #      define FIRST_CHILD() (mLastChild)
01601 #      define NEXT_CHILD(child) ((child)->GetPrevSibling())
01602 #else
01603 #      define FIRST_CHILD() (mFirstChild)
01604 #      define NEXT_CHILD(child) ((child)->GetNextSibling())
01605 #endif
01606 
01607        // recursively draw the children
01608        for (nsIWidget* kid = FIRST_CHILD(); kid; kid = NEXT_CHILD(kid)) {
01609               nsWindow* childWindow = NS_STATIC_CAST(nsWindow*, kid);
01610 
01611               nsRect childBounds;
01612               childWindow->GetBounds(childBounds);
01613 
01614               // redraw only the intersection of the child rect and the update rect
01615               nsRect intersection;
01616               if (intersection.IntersectRect(aRect, childBounds))
01617               {
01618                      intersection.MoveBy(-childBounds.x, -childBounds.y);
01619                      childWindow->UpdateWidget(intersection, aContext);
01620               }
01621        }
01622 
01623 #undef FIRST_CHILD
01624 #undef NEXT_CHILD
01625 
01626        NS_ASSERTION(ValidateDrawingState(), "Bad drawing state");
01627 }
01628 
01629 
01630 
01631 //
01632 // ScrollBits
01633 //
01634 // ::ScrollRect() unfortunately paints the invalidated area with the 
01635 // background pattern. This causes lots of ugly flashing and makes us look 
01636 // pretty bad. Instead, we roll our own ::ScrollRect() by using ::CopyBits() 
01637 // to scroll the image in the view and then set the update
01638 // rgn appropriately so that the compositor can blit it to the screen.
01639 //
01640 // This will also work with system floating windows over the area that is
01641 // scrolling.
01642 //
01643 // Under Carbon, this whole routine is basically moot as Apple has answered
01644 // our prayers with ::ScrollWindowRect().
01645 //
01646 void
01647 nsWindow::ScrollBits ( Rect & inRectToScroll, PRInt32 inLeftDelta, PRInt32 inTopDelta )
01648 {
01649   ::ScrollWindowRect ( mWindowPtr, &inRectToScroll, inLeftDelta, inTopDelta, 
01650                         kScrollWindowInvalidate, NULL );
01651 }
01652 
01653 
01654 //-------------------------------------------------------------------------
01655 //
01656 // Scroll the bits of a window
01657 //
01658 //-------------------------------------------------------------------------
01659 NS_IMETHODIMP nsWindow::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect)
01660 {
01661   if (mVisible && ContainerHierarchyIsVisible())
01662   {
01663     // If the clipping region is non-rectangular, just force a full update.
01664     // Happens when scrolling pages with absolutely-positioned divs
01665     // (see bug 289353 for examples).
01666     if (!IsRegionRectangular(mWindowRegion))
01667     {
01668       Invalidate(PR_FALSE);
01669       goto scrollChildren;
01670     }
01671 
01672     //--------
01673     // Scroll this widget
01674     nsRect scrollRect;  
01675     if (aClipRect)
01676       scrollRect = *aClipRect;
01677     else
01678     {
01679       scrollRect = mBounds;
01680       scrollRect.x = scrollRect.y = 0;
01681     }
01682 
01683     // If we're scrolling by an amount that is larger than the height or
01684     // width, just invalidate the entire area.
01685     if (aDx >= scrollRect.width || aDy >= scrollRect.height)
01686     {
01687       Invalidate(scrollRect, PR_FALSE);
01688     }
01689     else
01690     {
01691       Rect macRect;
01692       nsRectToMacRect(scrollRect, macRect);
01693 
01694       StartDraw();
01695 
01696       // Clip to the windowRegion instead of the visRegion (note: the visRegion
01697       // is equal to the windowRegion minus the children). The result is that
01698       // ScrollRect() scrolls the visible bits of this widget as well as its children.
01699       ::SetClip(mWindowRegion);
01700 
01701       // Scroll the bits now. We've rolled our own because ::ScrollRect looks ugly
01702       ScrollBits(macRect,aDx,aDy);
01703 
01704       EndDraw();
01705     }
01706   }
01707 
01708 scrollChildren:
01709   //--------
01710   // Scroll the children
01711   for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
01712     nsWindow* childWindow = NS_STATIC_CAST(nsWindow*, kid);
01713 
01714     nsRect bounds;
01715     childWindow->GetBounds(bounds);
01716     bounds.x += aDx;
01717     bounds.y += aDy;
01718     childWindow->SetBounds(bounds);
01719   }
01720 
01721   // recalculate the window regions
01722   CalcWindowRegions();
01723 
01724   return NS_OK;
01725 }
01726 
01727 //-------------------------------------------------------------------------
01728 //
01729 //
01730 //-------------------------------------------------------------------------
01731 
01732 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
01733 {
01734   switch (aStatus)
01735   {
01736     case nsEventStatus_eIgnore:                                              return(PR_FALSE);
01737     case nsEventStatus_eConsumeNoDefault:        return(PR_TRUE);     // don't do default processing
01738     case nsEventStatus_eConsumeDoDefault:        return(PR_FALSE);
01739     default:
01740       NS_ERROR("Illegal nsEventStatus enumeration value");
01741       break;
01742   }
01743   return(PR_FALSE);
01744 }
01745 
01746 //-------------------------------------------------------------------------
01747 //
01748 // Invokes callback and  ProcessEvent method on Event Listener object
01749 //
01750 //-------------------------------------------------------------------------
01751 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus& aStatus)
01752 {
01753   aStatus = nsEventStatus_eIgnore;
01754        if (mEnabled && !mDestructorCalled)
01755        {
01756               nsIWidget* aWidget = event->widget;
01757               NS_IF_ADDREF(aWidget);
01758          
01759          if (nsnull != mMenuListener){
01760            if(NS_MENU_EVENT == event->eventStructType)
01761                 aStatus = mMenuListener->MenuSelected( static_cast<nsMenuEvent&>(*event) );
01762          }
01763          if (mEventCallback)
01764            aStatus = (*mEventCallback)(event);
01765 
01766               // Dispatch to event listener if event was not consumed
01767          if ((aStatus != nsEventStatus_eConsumeNoDefault) && (mEventListener != nsnull))
01768            aStatus = mEventListener->ProcessEvent(*event);
01769 
01770               NS_IF_RELEASE(aWidget);
01771        }
01772   return NS_OK;
01773 }
01774 
01775 //-------------------------------------------------------------------------
01776 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent &event)
01777 {
01778   nsEventStatus status;
01779   DispatchEvent(&event, status);
01780   return ConvertStatus(status);
01781 }
01782 
01783 //-------------------------------------------------------------------------
01784 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent &event,nsEventStatus &aStatus)
01785 {
01786   DispatchEvent(&event, aStatus);
01787   return ConvertStatus(aStatus);
01788 }
01789 
01790 //-------------------------------------------------------------------------
01791 //
01792 // Deal with all sort of mouse event
01793 //
01794 //-------------------------------------------------------------------------
01795 PRBool nsWindow::DispatchMouseEvent(nsMouseEvent &aEvent)
01796 {
01797 
01798   PRBool result = PR_FALSE;
01799   if (nsnull == mEventCallback && nsnull == mMouseListener) {
01800     return result;
01801   }
01802 
01803   // call the event callback 
01804   if (mEventCallback && (mEnabled || aEvent.message == NS_MOUSE_EXIT)) {
01805     result = (DispatchWindowEvent(aEvent));
01806     return result;
01807   }
01808 
01809   if (nsnull != mMouseListener) {
01810     switch (aEvent.message) {
01811       case NS_MOUSE_MOVE: {
01812         result = ConvertStatus(mMouseListener->MouseMoved(aEvent));
01813         nsRect rect;
01814         GetBounds(rect);
01815         if (rect.Contains(aEvent.point.x, aEvent.point.y)) 
01816               {
01817           //if (mWindowPtr == NULL || mWindowPtr != this) 
01818               //{
01819             // printf("Mouse enter");
01820             //mCurrentWindow = this;
01821               //}
01822               } 
01823         else 
01824               {
01825           // printf("Mouse exit");
01826               }
01827 
01828       } break;
01829 
01830       case NS_MOUSE_LEFT_BUTTON_DOWN:
01831       case NS_MOUSE_MIDDLE_BUTTON_DOWN:
01832       case NS_MOUSE_RIGHT_BUTTON_DOWN:
01833         result = ConvertStatus(mMouseListener->MousePressed(aEvent));
01834         break;
01835 
01836       case NS_MOUSE_LEFT_BUTTON_UP:
01837       case NS_MOUSE_MIDDLE_BUTTON_UP:
01838       case NS_MOUSE_RIGHT_BUTTON_UP:
01839         result = ConvertStatus(mMouseListener->MouseReleased(aEvent));
01840         result = ConvertStatus(mMouseListener->MouseClicked(aEvent));
01841         break;
01842     } // switch
01843   } 
01844   return result;
01845 }
01846 
01847 #pragma mark -
01848 
01849 //-------------------------------------------------------------------------
01850 //
01851 //
01852 //-------------------------------------------------------------------------
01853 PRBool nsWindow::ReportDestroyEvent()
01854 {
01855        // nsEvent
01856        nsGUIEvent moveEvent(PR_TRUE, NS_DESTROY, this);
01857        moveEvent.message                  = NS_DESTROY;
01858        moveEvent.time                            = PR_IntervalNow();
01859 
01860        // dispatch event
01861        return (DispatchWindowEvent(moveEvent));
01862 }
01863 
01864 //-------------------------------------------------------------------------
01865 //
01866 //
01867 //-------------------------------------------------------------------------
01868 PRBool nsWindow::ReportMoveEvent()
01869 {
01870        // nsEvent
01871        nsGUIEvent moveEvent(PR_TRUE, NS_MOVE, this);
01872        moveEvent.point.x                  = mBounds.x;
01873        moveEvent.point.y                  = mBounds.y;
01874        moveEvent.time                            = PR_IntervalNow();
01875 
01876        // dispatch event
01877        return (DispatchWindowEvent(moveEvent));
01878 }
01879 
01880 //-------------------------------------------------------------------------
01881 //
01882 //
01883 //-------------------------------------------------------------------------
01884 PRBool nsWindow::ReportSizeEvent()
01885 {
01886        // nsEvent
01887        nsSizeEvent sizeEvent(PR_TRUE, NS_SIZE, this);
01888        sizeEvent.time                            = PR_IntervalNow();
01889 
01890        // nsSizeEvent
01891        sizeEvent.windowSize = &mBounds;
01892        sizeEvent.mWinWidth         = mBounds.width;
01893        sizeEvent.mWinHeight = mBounds.height;
01894   
01895        // dispatch event
01896        return(DispatchWindowEvent(sizeEvent));
01897 }
01898 
01899 
01900 
01901 #pragma mark -
01902 
01903 //-------------------------------------------------------------------------
01904 //
01905 //
01906 //-------------------------------------------------------------------------
01907 void nsWindow::CalcWindowRegions()
01908 {
01909        //------
01910        // calculate the window region
01911        if (mWindowRegion == nsnull)
01912        {
01913               mWindowRegion = ::NewRgn();
01914               if (mWindowRegion == nsnull)
01915                      return;
01916        }
01917        ::SetRectRgn(mWindowRegion, 0, 0, mBounds.width, mBounds.height);
01918 
01919        // intersect with all the parents
01920        nsWindow* parent = (nsWindow*)mParent;
01921        nsPoint origin(-mBounds.x, -mBounds.y);
01922 
01923        // must stop enumerating when hitting a native window boundary
01924        if (!mIsTopWidgetWindow)
01925        {
01926               while (parent && (!parent->mIsTopWidgetWindow))
01927        {
01928     if (parent->mWindowRegion)
01929     {
01930       // Under 10.2, if we offset a region beyond the coordinate space,
01931       // OffsetRgn() will silently fail and restoring it will then cause the
01932       // widget to be out of place (visible as 'shearing' when scrolling).
01933       // To prevent that, we copy the original region and work on that. (bug 162885)
01934       StRegionFromPool shiftedParentWindowRgn;
01935       if ( !shiftedParentWindowRgn )
01936         return;
01937       ::CopyRgn(parent->mWindowRegion, shiftedParentWindowRgn); 
01938       ::OffsetRgn(shiftedParentWindowRgn, origin.x, origin.y);
01939       ::SectRgn(mWindowRegion, shiftedParentWindowRgn, mWindowRegion);
01940     }
01941               origin.x -= parent->mBounds.x;
01942               origin.y -= parent->mBounds.y;
01943               parent = (nsWindow*)parent->mParent;
01944               }
01945        }
01946 
01947        //------
01948        // calculate the visible region
01949        if (mVisRegion == nsnull)
01950        {
01951               mVisRegion = ::NewRgn();
01952               if (mVisRegion == nsnull)
01953                      return;
01954        }
01955        ::CopyRgn(mWindowRegion, mVisRegion);
01956 
01957        // clip the children out of the visRegion
01958        if (mFirstChild)
01959        {
01960               StRegionFromPool childRgn;
01961               if (childRgn != nsnull) {
01962                      nsIWidget* child = mFirstChild;
01963                      do
01964                      {
01965                             nsWindow* childWindow = NS_STATIC_CAST(nsWindow*, child);
01966                                    
01967                             PRBool visible;
01968                             childWindow->IsVisible(visible);
01969                             if (visible) {
01970                                    nsRect childRect;
01971                                    childWindow->GetBounds(childRect);
01972 
01973                                    Rect macRect;
01974                                    ::SetRect(&macRect, childRect.x, childRect.y, childRect.XMost(), childRect.YMost());
01975                                    ::RectRgn(childRgn, &macRect);
01976                                    ::DiffRgn(mVisRegion, childRgn, mVisRegion);
01977                             }
01978                             
01979                             child = child->GetNextSibling();
01980                      } while (child);
01981               }
01982        }
01983 }
01984 
01985 //-------------------------------------------------------------------------
01986 /*
01987  *  @update  dc 08/28/98
01988  *  @param   aTheRegion -- The region to intersect with for this widget
01989  *  @return  PR_TRUE if the these regions intersect
01990  */
01991 
01992 PRBool nsWindow::RgnIntersects(RgnHandle aTheRegion, RgnHandle aIntersectRgn)
01993 {
01994        ::SectRgn(aTheRegion, this->mWindowRegion, aIntersectRgn);
01995        return (::EmptyRgn(aIntersectRgn) != false);
01996 }
01997 
01998 
01999 
02000 //-------------------------------------------------------------------------
02001 /*  Calculate the x and y offsets for this particular widget
02002  *  @update  ps 09/22/98
02003  *  @param   aX -- x offset amount
02004  *  @param   aY -- y offset amount 
02005  *  @return  NOTHING
02006  */
02007  
02008 void
02009 nsWindow::CalcOffset(PRInt32 &aX, PRInt32 &aY)
02010 {
02011   aX = aY = 0;
02012 
02013   nsCOMPtr<nsIWidget> theParent = dont_AddRef(GetParent());
02014   while (theParent)
02015   {
02016     nsRect theRect;
02017     theParent->GetBounds(theRect);
02018     aX += theRect.x;
02019     aY += theRect.y;
02020 
02021     nsIWidget* grandparent = theParent->GetParent();
02022     theParent = dont_AddRef(grandparent);
02023   }
02024 }
02025 
02026 
02027 PRBool
02028 nsWindow::ContainerHierarchyIsVisible()
02029 {
02030   nsCOMPtr<nsIWidget> theParent = dont_AddRef(GetParent());
02031   
02032   while (theParent)
02033   {
02034     PRBool  visible;
02035     theParent->IsVisible(visible);
02036     if (!visible)
02037       return PR_FALSE;
02038     
02039     nsIWidget* grandparent = theParent->GetParent();
02040     theParent = dont_AddRef(grandparent);
02041   }
02042   
02043   return PR_TRUE;
02044 }
02045 
02046 
02047 //-------------------------------------------------------------------------
02048 // PointInWidget
02049 //            Find if a point in local coordinates is inside this object
02050 //-------------------------------------------------------------------------
02051 PRBool nsWindow::PointInWidget(Point aThePoint)
02052 {
02053        // get the origin in local coordinates
02054        nsPoint widgetOrigin(0, 0);
02055        LocalToWindowCoordinate(widgetOrigin);
02056 
02057        // get rectangle relatively to the parent
02058        nsRect widgetRect;
02059        GetBounds(widgetRect);
02060 
02061        // convert the topLeft corner to local coordinates
02062        widgetRect.MoveBy(widgetOrigin.x, widgetOrigin.y);
02063 
02064        // finally tell whether it's a hit
02065        return(widgetRect.Contains(aThePoint.h, aThePoint.v));
02066 }
02067 
02068 
02069 //-------------------------------------------------------------------------
02070 // FindWidgetHit
02071 //            Recursively look for the widget hit
02072 //            @param aParent   -- parent widget. 
02073 //            @param aThePoint -- a point in local coordinates to test for the hit. 
02074 //-------------------------------------------------------------------------
02075 nsWindow*  nsWindow::FindWidgetHit(Point aThePoint)
02076 {
02077        if (!mVisible || !ContainerHierarchyIsVisible() || !PointInWidget(aThePoint))
02078               return nsnull;
02079 
02080        nsWindow* widgetHit = this;
02081 
02082        // traverse through all the nsWindows to find out who got hit, lowest level of course
02083        for (nsIWidget* kid = mLastChild; kid; kid = kid->GetPrevSibling()) {
02084               nsWindow* childWindow = NS_STATIC_CAST(nsWindow*, kid);
02085               
02086               nsWindow* deeperHit = childWindow->FindWidgetHit(aThePoint);
02087               if (deeperHit)
02088               {
02089                      widgetHit = deeperHit;
02090                      break;
02091               }
02092        }
02093 
02094        return widgetHit;
02095 }
02096 
02097 #pragma mark -
02098 
02099 
02100 //-------------------------------------------------------------------------
02101 // WidgetToScreen
02102 //            Walk up the parent tree, converting the given rect to global coordinates.
02103 //      This is similar to CalcOffset() but we can't use GetBounds() because it
02104 //      only knows how to give us local coordinates.
02105 //            @param aLocalRect  -- rect in local coordinates of this widget
02106 //            @param aGlobalRect -- |aLocalRect| in global coordinates
02107 //-------------------------------------------------------------------------
02108 NS_IMETHODIMP nsWindow::WidgetToScreen(const nsRect& aLocalRect, nsRect& aGlobalRect)
02109 {      
02110        aGlobalRect = aLocalRect;
02111        nsIWidget* theParent = this->GetParent();
02112        if ( theParent ) {
02113               // Recursive case
02114               //
02115               // Convert the local rect to global, except for this level.
02116               theParent->WidgetToScreen(aLocalRect, aGlobalRect);
02117          NS_RELEASE(theParent);
02118 
02119               // the offset from our parent is in the x/y of our bounding rect
02120               nsRect myBounds;
02121               GetBounds(myBounds);
02122               aGlobalRect.MoveBy(myBounds.x, myBounds.y);
02123        }
02124        else {
02125               // Base case of recursion
02126               //
02127               // When there is no parent, we're at the top level window. Use
02128               // the origin (shifted into global coordinates) to find the offset.
02129               StPortSetter  portSetter(mWindowPtr);
02130               StOriginSetter       originSetter(mWindowPtr);
02131               
02132               // convert origin into global coords and shift output rect by that ammount
02133               Point origin = {0, 0};
02134               ::LocalToGlobal ( &origin );
02135               aGlobalRect.MoveBy ( origin.h, origin.v );
02136        }
02137        
02138        return NS_OK;
02139 }
02140 
02141 
02142 
02143 //-------------------------------------------------------------------------
02144 // ScreenToWidget
02145 //            Walk up the parent tree, converting the given rect to local coordinates.
02146 //            @param aGlobalRect  -- rect in screen coordinates 
02147 //            @param aLocalRect -- |aGlobalRect| in coordinates of this widget
02148 //-------------------------------------------------------------------------
02149 NS_IMETHODIMP nsWindow::ScreenToWidget(const nsRect& aGlobalRect, nsRect& aLocalRect)
02150 {
02151        aLocalRect = aGlobalRect;
02152        nsIWidget* theParent = GetParent();
02153        if ( theParent ) {
02154               // Recursive case
02155               //
02156               // Convert the local rect to global, except for this level.
02157               theParent->WidgetToScreen(aGlobalRect, aLocalRect);
02158          NS_RELEASE(theParent);
02159          
02160               // the offset from our parent is in the x/y of our bounding rect
02161               nsRect myBounds;
02162               GetBounds(myBounds);
02163               aLocalRect.MoveBy(myBounds.x, myBounds.y);
02164        }
02165        else {
02166               // Base case of recursion
02167               //
02168               // When there is no parent, we're at the top level window. Use
02169               // the origin (shifted into local coordinates) to find the offset.
02170               StPortSetter  portSetter(mWindowPtr);
02171               StOriginSetter       originSetter(mWindowPtr);
02172               
02173               // convert origin into local coords and shift output rect by that ammount
02174               Point origin = {0, 0};
02175               ::GlobalToLocal ( &origin );
02176               aLocalRect.MoveBy ( origin.h, origin.v );
02177        }
02178        
02179        return NS_OK;
02180 } 
02181 
02182 
02183 /*
02184  *  Set a Mac Rect to the value of an nsRect 
02185  *  The source rect is assumed to be in pixels not TWIPS
02186  *  @update  gpk 08/27/98
02187  *  @param   aRect -- The nsRect that is the source
02188  *  @param   aMacRect -- The Mac Rect destination
02189  */
02190 void nsWindow::nsRectToMacRect(const nsRect& aRect, Rect& aMacRect)
02191 {
02192               aMacRect.left = aRect.x;
02193               aMacRect.top = aRect.y;
02194               aMacRect.right = aRect.x + aRect.width;
02195               aMacRect.bottom = aRect.y + aRect.height;
02196 }
02197 
02198 
02199 //=================================================================
02200 /*  Convert the coordinates to some device coordinates so GFX can draw.
02201  *  @update  dc 09/16/98
02202  *  @param   nscoord -- X coordinate to convert
02203  *  @param   nscoord -- Y coordinate to convert
02204  *  @return  NONE
02205  */
02206 void
02207 nsWindow::ConvertToDeviceCoordinates(nscoord &aX, nscoord &aY)
02208 {
02209        PRInt32       offX, offY;
02210        CalcOffset(offX,offY);
02211 
02212        aX += offX;
02213        aY += offY;
02214 }
02215 
02216 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener, 
02217                                             PRBool aDoCapture, 
02218                                             PRBool aConsumeRollupEvent)
02219 {
02220   if (aDoCapture) {
02221     NS_IF_RELEASE(gRollupListener);
02222     NS_IF_RELEASE(gRollupWidget);
02223     gRollupListener = aListener;
02224     NS_ADDREF(aListener);
02225     gRollupWidget = this;
02226     NS_ADDREF(this);
02227   } else {
02228     NS_IF_RELEASE(gRollupListener);
02229     //gRollupListener = nsnull;
02230     NS_IF_RELEASE(gRollupWidget);
02231   }
02232 
02233   return NS_OK;
02234 }
02235 
02236 NS_IMETHODIMP nsWindow::SetTitle(const nsAString& title)
02237 {
02238   NS_ERROR("Would some Mac person please implement me? Thanks.");
02239   return NS_OK;
02240 }
02241 
02242 NS_IMETHODIMP nsWindow::GetAttention(PRInt32 aCycleCount)
02243 {
02244         // Since the Mac doesn't consider each window a separate process this call functions
02245        // slightly different than on other platforms.  We first check to see if we're the
02246        // foreground process and, if so, ignore the call.  We also check to see if a notification
02247        // is already pending and, if so, remove it since we only have one notification per process.
02248        // After all that checking we install a notification manager request to mark the app's icon
02249        // in the process menu and play the default alert sound
02250   
02251   OSErr err;
02252     
02253        if (we_are_front_process())
02254               return NS_OK;
02255   
02256        if (gNotificationInstalled)
02257        {
02258               (void)::NMRemove(&gNMRec);
02259               gNotificationInstalled = false;
02260        }
02261        
02262        err = GetIconSuite( &gNMRec.nmIcon, 128, svAllSmallData );
02263        if ( err != noErr )
02264               gNMRec.nmIcon = NULL;
02265               
02266        // Setup and install the notification manager rec
02267        gNMRec.qType    = nmType;
02268        gNMRec.nmMark   = 1;      // Make the dock icon bounce
02269        gNMRec.nmSound  = NULL;   // No alert sound, see bug 307323
02270        gNMRec.nmStr    = NULL;   // No alert/window so no text
02271        gNMRec.nmResp   = NULL;   // No response proc, use the default behavior
02272        gNMRec.nmRefCon = 0;
02273        if (::NMInstall(&gNMRec) == noErr)
02274               gNotificationInstalled = true;
02275 
02276        return NS_OK;
02277 }
02278 
02279 #pragma mark -
02280 
02281 
02282 NS_IMETHODIMP nsWindow::GetPluginClipRect(nsRect& outClipRect, nsPoint& outOrigin, PRBool& outWidgetVisible)
02283 {
02284   PRBool isVisible = mVisible;
02285 
02286   nsRect widgetClipRect = mBounds;
02287   // absX and absY are top-level window-relative coordinates
02288   nscoord absX = widgetClipRect.x;
02289   nscoord absY = widgetClipRect.y;
02290 
02291   nscoord ancestorX = -widgetClipRect.x;
02292   nscoord ancestorY = -widgetClipRect.y;
02293 
02294   // Calculate clipping relative to this widget
02295   widgetClipRect.x = 0;
02296   widgetClipRect.y = 0;
02297 
02298   // Gather up the absolute position of the widget, clip window, and visibilty
02299   nsCOMPtr<nsIWidget> widget = getter_AddRefs(GetParent());
02300   while (widget)
02301   {
02302     if (isVisible)
02303       widget->IsVisible(isVisible);
02304 
02305     nsRect widgetRect;
02306     widget->GetClientBounds(widgetRect);
02307     nscoord wx = widgetRect.x;
02308     nscoord wy = widgetRect.y;
02309 
02310     widgetRect.x = ancestorX;
02311     widgetRect.y = ancestorY;
02312 
02313     widgetClipRect.IntersectRect(widgetClipRect, widgetRect);
02314     absX += wx;
02315     absY += wy;
02316     widget = getter_AddRefs(widget->GetParent());
02317     if (!widget)
02318     {
02319       // Don't include the top-level windows offset
02320       // printf("Top level window offset %d %d\n", wx, wy);
02321       absX -= wx;
02322       absY -= wy;
02323     }
02324     ancestorX -= wx;
02325     ancestorY -= wy;
02326   }
02327 
02328   widgetClipRect.x += absX;
02329   widgetClipRect.y += absY;
02330 
02331   outClipRect = widgetClipRect;
02332   outOrigin.x = absX;
02333   outOrigin.y = absY;
02334   
02335   outWidgetVisible = isVisible;
02336   return NS_OK;
02337 }
02338 
02339 
02340 NS_IMETHODIMP nsWindow::StartDrawPlugin(void)
02341 {
02342   // setup the port background color for the plugin
02343   GrafPtr savePort;
02344   ::GetPort(&savePort);  // save our current port
02345   ::SetPortWindowPort(mWindowPtr);
02346   
02347   RGBColor macColor;
02348   macColor.red   = COLOR8TOCOLOR16(NS_GET_R(mBackground));  // convert to Mac color
02349   macColor.green = COLOR8TOCOLOR16(NS_GET_G(mBackground));
02350   macColor.blue  = COLOR8TOCOLOR16(NS_GET_B(mBackground));
02351   ::RGBBackColor(&macColor);
02352 
02353   ::SetPort(savePort);  // restore port
02354 
02355   return NS_OK;
02356 }
02357 
02358 NS_IMETHODIMP nsWindow::EndDrawPlugin(void)
02359 {
02360   GrafPtr savePort;
02361   ::GetPort(&savePort);  // save our current port
02362   ::SetPortWindowPort(mWindowPtr);
02363 
02364   RGBColor rgbWhite = { 0xFFFF, 0xFFFF, 0xFFFF };
02365   ::RGBBackColor(&rgbWhite);
02366 
02367   ::SetPort(savePort);  // restore port
02368   return NS_OK;
02369 }
02370 
02371 
02372 #pragma mark -
02373 
02374 
02375 NS_IMETHODIMP nsWindow::ResetInputState()
02376 {
02377        // currently, the nsMacEventHandler is owned by nsMacWindow, which is the top level window
02378        // we delegate this call to its parent
02379   nsCOMPtr<nsIWidget> parent = getter_AddRefs(GetParent());
02380   NS_WARN_IF_FALSE(parent, "cannot get parent");
02381   if (parent)
02382   {
02383     nsCOMPtr<nsIKBStateControl> kb = do_QueryInterface(parent);
02384     NS_WARN_IF_FALSE(kb, "cannot get parent");
02385        if (kb) {
02386               return kb->ResetInputState();
02387        }
02388   }
02389        return NS_ERROR_ABORT;
02390 }
02391 
02392 NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState) {
02393   return NS_ERROR_NOT_IMPLEMENTED;
02394 }
02395 
02396 NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState) {
02397   return NS_ERROR_NOT_IMPLEMENTED;
02398 }
02399 
02400 NS_IMETHODIMP nsWindow::CancelIMEComposition() {
02401   return NS_ERROR_NOT_IMPLEMENTED;
02402 }
02403