Back to index

lightning-sunbird  0.9+nobinonly
nsCocoaWindow.mm
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 #include "nsCocoaWindow.h"
00039 
00040 #include "nsIServiceManager.h"    // for drag and drop
00041 #include "nsWidgetsCID.h"
00042 #include "nsIDragService.h"
00043 #include "nsIDragSession.h"
00044 #include "nsIDragSessionMac.h"
00045 #include "nsIScreen.h"
00046 #include "nsIScreenManager.h"
00047 #include "nsGUIEvent.h"
00048 #include "nsCarbonHelpers.h"
00049 #include "nsGfxUtils.h"
00050 #include "nsMacResources.h"
00051 #include "nsIRollupListener.h"
00052 #import "nsChildView.h"
00053 
00054 #include "nsIEventQueueService.h"
00055 
00056 #if TARGET_CARBON
00057 #include <CFString.h>
00058 #endif
00059 
00060 #include <Quickdraw.h>
00061 
00062 // Define Class IDs -- i hate having to do this
00063 static NS_DEFINE_CID(kCDragServiceCID,  NS_DRAGSERVICE_CID);
00064 
00065 // from MacHeaders.c
00066 #ifndef topLeft
00067   #define topLeft(r)  (((Point *) &(r))[0])
00068 #endif
00069 #ifndef botRight
00070   #define botRight(r) (((Point *) &(r))[1])
00071 #endif
00072 
00073 // externs defined in nsWindow.cpp
00074 extern nsIRollupListener * gRollupListener;
00075 extern nsIWidget         * gRollupWidget;
00076 
00077 #define kWindowPositionSlop 20
00078 
00079 
00080 #if 0
00081 void SetDragActionBasedOnModifiers ( nsIDragService* inDragService, short inModifiers ) ; 
00082 
00083 
00084 //
00085 // SetDragActionsBasedOnModifiers [static]
00086 //
00087 // Examines the MacOS modifier keys and sets the appropriate drag action on the
00088 // drag session to copy/move/etc
00089 //
00090 void
00091 SetDragActionBasedOnModifiers ( nsIDragService* inDragService, short inModifiers ) 
00092 {
00093   nsCOMPtr<nsIDragSession> dragSession;
00094   inDragService->GetCurrentSession ( getter_AddRefs(dragSession) );
00095   if ( dragSession ) {
00096     PRUint32 action = nsIDragService::DRAGDROP_ACTION_MOVE;
00097     
00098     // force copy = option, alias = cmd-option, default is move
00099     if ( inModifiers & optionKey ) {
00100       if ( inModifiers & cmdKey )
00101         action = nsIDragService::DRAGDROP_ACTION_LINK;
00102       else
00103         action = nsIDragService::DRAGDROP_ACTION_COPY;
00104     }
00105 
00106     dragSession->SetDragAction ( action );    
00107   }
00108 
00109 } // SetDragActionBasedOnModifiers
00110 
00111 #pragma mark -
00112 
00113 
00114 //¥¥¥ this should probably go into the drag session as a static
00115 pascal OSErr
00116 nsCocoaWindow::DragTrackingHandler ( DragTrackingMessage theMessage, WindowPtr theWindow, 
00117                     void *handlerRefCon, DragReference theDrag)
00118 {
00119   // holds our drag service across multiple calls to this callback. The reference to
00120   // the service is obtained when the mouse enters the window and is released when
00121   // the mouse leaves the window (or there is a drop). This prevents us from having
00122   // to re-establish the connection to the service manager 15 times a second when
00123   // handling the |kDragTrackingInWindow| message.
00124   static nsIDragService* sDragService = nsnull;
00125 
00126   nsCocoaWindow* geckoWindow = reinterpret_cast<nsCocoaWindow*>(handlerRefCon);
00127   if ( !theWindow || !geckoWindow )
00128     return dragNotAcceptedErr;
00129     
00130   nsresult rv = NS_OK;
00131   switch ( theMessage ) {
00132   
00133     case kDragTrackingEnterHandler:
00134       break;
00135       
00136     case kDragTrackingEnterWindow:
00137     {
00138       // get our drag service for the duration of the drag.
00139       nsresult rv = CallGetService(kCDragServiceCID, &sDragService);
00140             NS_ASSERTION ( sDragService, "Couldn't get a drag service, we're in biiig trouble" );
00141 
00142       // tell the session about this drag
00143       if ( sDragService ) {
00144         sDragService->StartDragSession();
00145         nsCOMPtr<nsIDragSessionMac> macSession ( do_QueryInterface(sDragService) );
00146         if ( macSession )
00147           macSession->SetDragReference ( theDrag );
00148       }
00149       
00150       // let gecko know that the mouse has entered the window so it
00151       // can start tracking and sending enter/exit events to frames.
00152       Point mouseLocGlobal;
00153       ::GetDragMouse ( theDrag, &mouseLocGlobal, nsnull );
00154       geckoWindow->DragEvent ( NS_DRAGDROP_ENTER, mouseLocGlobal, 0L );     
00155       break;
00156     }
00157     
00158     case kDragTrackingInWindow:
00159     {
00160       Point mouseLocGlobal;
00161       ::GetDragMouse ( theDrag, &mouseLocGlobal, nsnull );
00162       short modifiers;
00163       ::GetDragModifiers ( theDrag, &modifiers, nsnull, nsnull );
00164       
00165       NS_ASSERTION ( sDragService, "If we don't have a drag service, we're fucked" );
00166       
00167       // set the drag action on the service so the frames know what is going on
00168       SetDragActionBasedOnModifiers ( sDragService, modifiers );
00169       
00170       // clear out the |canDrop| property of the drag session. If it's meant to
00171       // be, it will be set again.
00172       nsCOMPtr<nsIDragSession> session;
00173       sDragService->GetCurrentSession(getter_AddRefs(session));
00174       NS_ASSERTION ( session, "If we don't have a drag session, we're fucked" );
00175       if ( session )
00176         session->SetCanDrop(PR_FALSE);
00177 
00178       // pass into gecko for handling...
00179       geckoWindow->DragEvent ( NS_DRAGDROP_OVER, mouseLocGlobal, modifiers );
00180       break;
00181     }
00182     
00183     case kDragTrackingLeaveWindow:
00184     {
00185       // tell the drag service that we're done with it.
00186       if ( sDragService ) {
00187         sDragService->EndDragSession();
00188         
00189         // clear out the dragRef in the drag session. We are guaranteed that
00190         // this will be called _after_ the drop has been processed (if there
00191         // is one), so we're not destroying valuable information if the drop
00192         // was in our window.
00193         nsCOMPtr<nsIDragSessionMac> macSession ( do_QueryInterface(sDragService) );
00194         if ( macSession )
00195           macSession->SetDragReference ( 0 );         
00196       }     
00197     
00198       // let gecko know that the mouse has left the window so it
00199       // can stop tracking and sending enter/exit events to frames.
00200       Point mouseLocGlobal;
00201       ::GetDragMouse ( theDrag, &mouseLocGlobal, nsnull );
00202       geckoWindow->DragEvent ( NS_DRAGDROP_EXIT, mouseLocGlobal, 0L );
00203       
00204       ::HideDragHilite ( theDrag );
00205   
00206       // we're _really_ done with it, so let go of the service.
00207       NS_IF_RELEASE( sDragService );
00208       
00209       break;
00210     }
00211     
00212   } // case of each drag message
00213 
00214   return noErr;
00215   
00216 } // DragTrackingHandler
00217 
00218 
00219 //¥¥¥ this should probably go into the drag session as a static
00220 pascal OSErr
00221 nsCocoaWindow::DragReceiveHandler (WindowPtr theWindow, void *handlerRefCon,
00222                   DragReference theDragRef)
00223 {
00224   // get our window back from the refCon
00225   nsCocoaWindow* geckoWindow = reinterpret_cast<nsCocoaWindow*>(handlerRefCon);
00226   if ( !theWindow || !geckoWindow )
00227     return dragNotAcceptedErr;
00228     
00229     // We make the assuption that the dragOver handlers have correctly set
00230     // the |canDrop| property of the Drag Session. Before we dispatch the event
00231     // into Gecko, check that value and either dispatch it or set the result
00232     // code to "spring-back" and show the user the drag failed. 
00233     OSErr result = noErr;
00234   nsCOMPtr<nsIDragService> dragService ( do_GetService(kCDragServiceCID) );
00235   if ( dragService ) {
00236     nsCOMPtr<nsIDragSession> dragSession;
00237     dragService->GetCurrentSession ( getter_AddRefs(dragSession) );
00238     if ( dragSession ) {
00239       // if the target has set that it can accept the drag, pass along
00240       // to gecko, otherwise set phasers for failure.
00241       PRBool canDrop = PR_FALSE;
00242       if ( NS_SUCCEEDED(dragSession->GetCanDrop(&canDrop)) )
00243         if ( canDrop ) {
00244                   // pass the drop event along to Gecko
00245                   Point mouseLocGlobal;
00246                   ::GetDragMouse ( theDragRef, &mouseLocGlobal, nsnull );
00247                   short modifiers;
00248                   ::GetDragModifiers ( theDragRef, &modifiers, nsnull, nsnull );
00249                   geckoWindow->DragEvent ( NS_DRAGDROP_DROP, mouseLocGlobal, modifiers );
00250                 }
00251                 else
00252           result = dragNotAcceptedErr;  
00253     } // if a valid drag session
00254         
00255     // we don't need the drag session anymore, the user has released the
00256     // mouse and the event has already gone to gecko.
00257     dragService->EndDragSession();
00258   }
00259   
00260   return result;
00261   
00262 } // DragReceiveHandler
00263 
00264 #endif
00265 
00266 
00267 NS_IMPL_ISUPPORTS_INHERITED0(nsCocoaWindow, Inherited)
00268 
00269 
00270 //-------------------------------------------------------------------------
00271 //
00272 // nsCocoaWindow constructor
00273 //
00274 //-------------------------------------------------------------------------
00275 nsCocoaWindow::nsCocoaWindow()
00276 #if 0
00277   , mWindowMadeHere(PR_FALSE)
00278   , mIsDialog(PR_FALSE)
00279   , mMacEventHandler(nsnull)
00280   , mAcceptsActivation(PR_TRUE)
00281   , mIsActive(PR_FALSE)
00282   , mZoomOnShow(PR_FALSE)
00283 #endif
00284 : 
00285   mOffsetParent(nsnull)
00286 , mIsDialog(PR_FALSE)
00287 , mIsResizing(PR_FALSE)
00288 , mWindowMadeHere(PR_FALSE)
00289 , mWindow(nil)
00290 {
00291 #if 0
00292   mMacEventHandler.reset(new nsMacEventHandler(this));
00293 
00294   // create handlers for drag&drop
00295   mDragTrackingHandlerUPP = NewDragTrackingHandlerUPP(DragTrackingHandler);
00296   mDragReceiveHandlerUPP = NewDragReceiveHandlerUPP(DragReceiveHandler);
00297 #endif
00298 }
00299 
00300 
00301 //-------------------------------------------------------------------------
00302 //
00303 // nsCocoaWindow destructor
00304 //
00305 //-------------------------------------------------------------------------
00306 nsCocoaWindow::~nsCocoaWindow()
00307 {
00308   if ( mWindow && mWindowMadeHere ) {
00309     [mWindow autorelease];
00310     [mDelegate autorelease];
00311   }
00312   
00313 #if 0
00314   if (mWindowPtr)
00315   {
00316     if (mWindowMadeHere)
00317       ::DisposeWindow(mWindowPtr);
00318       
00319     // clean up DragManager stuff
00320     if ( mDragTrackingHandlerUPP ) {
00321       ::RemoveTrackingHandler ( mDragTrackingHandlerUPP, mWindowPtr );
00322       ::DisposeDragTrackingHandlerUPP ( mDragTrackingHandlerUPP );
00323      }
00324     if ( mDragReceiveHandlerUPP ) {
00325       ::RemoveReceiveHandler ( mDragReceiveHandlerUPP, mWindowPtr );
00326       ::DisposeDragReceiveHandlerUPP ( mDragReceiveHandlerUPP );
00327     }
00328 
00329     nsMacMessageSink::RemoveRaptorWindowFromList(mWindowPtr);
00330     mWindowPtr = nsnull;
00331   }
00332 #endif
00333   
00334 }
00335 
00336 
00337 //-------------------------------------------------------------------------
00338 //
00339 // Utility method for implementing both Create(nsIWidget ...) and
00340 // Create(nsNativeWidget...)
00341 //-------------------------------------------------------------------------
00342 
00343 nsresult nsCocoaWindow::StandardCreate(nsIWidget *aParent,
00344                         const nsRect &aRect,
00345                         EVENT_CALLBACK aHandleEventFunction,
00346                         nsIDeviceContext *aContext,
00347                         nsIAppShell *aAppShell,
00348                         nsIToolkit *aToolkit,
00349                         nsWidgetInitData *aInitData,
00350                         nsNativeWidget aNativeParent)
00351 {
00352   Inherited::BaseCreate ( aParent, aRect, aHandleEventFunction, aContext, aAppShell,
00353                             aToolkit, aInitData );
00354                             
00355   if (!aNativeParent || (aInitData && aInitData->mWindowType == eWindowType_popup))
00356   {
00357     mOffsetParent = aParent;
00358 
00359     nsWindowType windowType = eWindowType_toplevel;
00360     if (aInitData)
00361     {
00362       mWindowType = aInitData->mWindowType;
00363       // if a toplevel window was requested without a titlebar, use a dialog windowproc
00364       if (aInitData->mWindowType == eWindowType_toplevel &&
00365         (aInitData->mBorderStyle == eBorderStyle_none ||
00366          aInitData->mBorderStyle != eBorderStyle_all && !(aInitData->mBorderStyle & eBorderStyle_title)))
00367         windowType = eWindowType_dialog;
00368     } 
00369     else
00370     {
00371       mWindowType = (mIsDialog ? eWindowType_dialog : eWindowType_toplevel);
00372     }
00373     
00374     // create the cocoa window
00375     NSRect rect;
00376     rect.origin.x = rect.origin.y = 1.0;
00377     rect.size.width = rect.size.height = 1.0;
00378     unsigned int features = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask 
00379                               | NSResizableWindowMask;
00380     if ( mWindowType == eWindowType_popup || mWindowType == eWindowType_invisible )
00381       features = 0;
00382 
00383     // XXXdwh Just don't make popup windows yet.  They mess up the world.
00384     if (mWindowType == eWindowType_popup)
00385       return NS_OK;
00386 
00387     mWindow = [[NSWindow alloc] initWithContentRect:rect styleMask:features 
00388                         backing:NSBackingStoreBuffered defer:NO];
00389     
00390     // Popups will receive a "close" message when an app terminates
00391     // that causes an extra release to occur.  Make sure popups
00392     // are set not to release when closed.
00393     if (features == 0)
00394       [mWindow setReleasedWhenClosed: NO];
00395 
00396     // create a quickdraw view as the toplevel content view of the window
00397     NSQuickDrawView* content = [[[NSQuickDrawView alloc] init] autorelease];
00398     [content setFrame:[[mWindow contentView] frame]];
00399     [mWindow setContentView:content];
00400     
00401     // register for mouse-moved events. The default is to ignore them for perf reasons.
00402     [mWindow setAcceptsMouseMovedEvents:YES];
00403     
00404     // setup our notification delegate. Note that setDelegate: does NOT retain.
00405     mDelegate = [[WindowDelegate alloc] initWithGeckoWindow:this];
00406     [mWindow setDelegate:mDelegate];
00407     
00408     mWindowMadeHere = PR_TRUE;    
00409   }
00410 
00411 #if 0
00412   short bottomPinDelta = 0;     // # of pixels to subtract to pin window bottom
00413   nsCOMPtr<nsIToolkit> theToolkit = aToolkit;
00414   
00415   // build the main native window
00416   if (aNativeParent == nsnull)
00417   {
00418     nsWindowType windowType;
00419     if (aInitData)
00420     {
00421       mWindowType = aInitData->mWindowType;
00422       // if a toplevel window was requested without a titlebar, use a dialog windowproc
00423       if (aInitData->mWindowType == eWindowType_toplevel &&
00424         (aInitData->mBorderStyle == eBorderStyle_none ||
00425          aInitData->mBorderStyle != eBorderStyle_all && !(aInitData->mBorderStyle & eBorderStyle_title)))
00426         windowType = eWindowType_dialog;
00427     } else
00428       mWindowType = (mIsDialog ? eWindowType_dialog : eWindowType_toplevel);
00429 
00430     short     wDefProcID = kWindowDocumentProc;
00431     Boolean   goAwayFlag;
00432     short     hOffset;
00433     short     vOffset;
00434 
00435     switch (mWindowType)
00436     {
00437       case eWindowType_popup:
00438         // We're a popup, context menu, etc. Sets
00439         // mAcceptsActivation to false so we don't activate the window
00440         // when we show it.
00441         mOffsetParent = aParent;
00442         if( !aParent )
00443           theToolkit = getter_AddRefs(aParent->GetToolkit());
00444 
00445         mAcceptsActivation = PR_FALSE;
00446         goAwayFlag = false;
00447         hOffset = 0;
00448         vOffset = 0;
00449 #if TARGET_CARBON
00450         wDefProcID = kWindowSimpleProc;
00451 #else
00452         wDefProcID = plainDBox;
00453 #endif
00454         break;
00455 
00456       case eWindowType_child:
00457         wDefProcID = plainDBox;
00458         goAwayFlag = false;
00459         hOffset = 0;
00460         vOffset = 0;
00461         break;
00462 
00463       case eWindowType_dialog:
00464         if (aInitData)
00465         {
00466           // Prior to Carbon, defProcs were solely about appearance. If told to create a dialog,
00467           // we could use, for example, |kWindowMovableModalDialogProc| even if the dialog wasn't
00468           // supposed to be modal. Carbon breaks this assumption, enforcing modality when using these
00469           // particular proc ids. As a result, when compiling under Carbon we have to use the
00470           // standard window proc id's and below, after we have a windowPtr, we'll hide the closebox
00471           // that comes with the standard window proc.
00472           //
00473           // I'm making the assumption here that any dialog created w/out a titlebar is modal and am
00474           // therefore keeping the old modal dialog proc. I'm only special-casing dialogs with a 
00475           // titlebar since those are the only ones that might end up not being modal.
00476           
00477           switch (aInitData->mBorderStyle)
00478           {
00479             case eBorderStyle_none:
00480               wDefProcID = kWindowModalDialogProc;
00481               break;
00482               
00483             case eBorderStyle_all:
00484               #if TARGET_CARBON
00485                 wDefProcID = kWindowGrowDocumentProc;
00486               #else
00487                 wDefProcID = kWindowMovableModalGrowProc;   // should we add a close box (kWindowGrowDocumentProc) ?
00488               #endif
00489               break;
00490               
00491             case eBorderStyle_default:
00492               wDefProcID = kWindowModalDialogProc;
00493               break;
00494             
00495             default:
00496               // we ignore the close flag here, since mac dialogs should never have a close box.
00497               switch(aInitData->mBorderStyle & (eBorderStyle_resizeh | eBorderStyle_title))
00498               {
00499                 // combinations of individual options.
00500                 case eBorderStyle_title:
00501                   #if TARGET_CARBON
00502                     wDefProcID = kWindowDocumentProc;
00503                   #else
00504                     wDefProcID = kWindowMovableModalDialogProc;
00505                   #endif
00506                   break;
00507                                     
00508                 case eBorderStyle_resizeh:
00509                 case (eBorderStyle_title | eBorderStyle_resizeh):
00510                   #if TARGET_CARBON
00511                     wDefProcID = kWindowGrowDocumentProc;
00512                   #else
00513                     wDefProcID = kWindowMovableModalGrowProc;   // this is the only kind of resizable dialog.
00514                   #endif
00515                   break;
00516                                   
00517                 default:
00518                   NS_WARNING("Unhandled combination of window flags");
00519                   break;
00520               }
00521           }
00522         }
00523         else
00524         {
00525           wDefProcID = kWindowModalDialogProc;
00526           goAwayFlag = true; // revisit this below
00527         }
00528                 
00529         hOffset = kDialogMarginWidth;
00530         vOffset = kDialogTitleBarHeight;
00531         break;
00532 
00533       case eWindowType_toplevel:
00534         if (aInitData &&
00535           aInitData->mBorderStyle != eBorderStyle_all &&
00536           aInitData->mBorderStyle != eBorderStyle_default &&
00537           (aInitData->mBorderStyle == eBorderStyle_none ||
00538            !(aInitData->mBorderStyle & eBorderStyle_resizeh)))
00539           wDefProcID = kWindowDocumentProc;
00540         else
00541           wDefProcID = kWindowFullZoomGrowDocumentProc;
00542         goAwayFlag = true;
00543         hOffset = kWindowMarginWidth;
00544         vOffset = kWindowTitleBarHeight;
00545         break;
00546 
00547       case eWindowType_invisible:
00548         // don't do anything
00549         break;
00550     }
00551 
00552     // now turn off some default features if requested by aInitData
00553     if (aInitData && aInitData->mBorderStyle != eBorderStyle_all)
00554     {
00555       if (aInitData->mBorderStyle == eBorderStyle_none ||
00556           aInitData->mBorderStyle == eBorderStyle_default &&
00557           windowType == eWindowType_dialog ||
00558           !(aInitData->mBorderStyle & eBorderStyle_close))
00559         goAwayFlag = false;
00560     }
00561 
00562     Rect wRect;
00563     nsRectToMacRect(aRect, wRect);
00564 
00565     if (eWindowType_popup != mWindowType)
00566       ::OffsetRect(&wRect, hOffset, vOffset + ::GetMBarHeight());
00567     else
00568       ::OffsetRect(&wRect, hOffset, vOffset);
00569 
00570     nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
00571     if (screenmgr) {
00572       nsCOMPtr<nsIScreen> screen;
00573       //screenmgr->GetPrimaryScreen(getter_AddRefs(screen));
00574       screenmgr->ScreenForRect(wRect.left, wRect.top,
00575                                  wRect.right - wRect.left, wRect.bottom - wRect.top,
00576                                  getter_AddRefs(screen));
00577       if (screen) {
00578           PRInt32 left, top, width, height;
00579         screen->GetAvailRect(&left, &top, &width, &height);
00580         if (wRect.bottom > top+height) {
00581           bottomPinDelta = wRect.bottom - (top+height);
00582           wRect.bottom -= bottomPinDelta;
00583         }
00584       }
00585     }
00586     mWindowPtr = ::NewCWindow(nil, &wRect, "\p", false, wDefProcID, (WindowRef)-1, goAwayFlag, (long)nsnull);
00587     mWindowMadeHere = PR_TRUE;
00588   }
00589   else
00590   {
00591     mWindowPtr = (WindowPtr)aNativeParent;
00592     mWindowMadeHere = PR_FALSE;
00593   }
00594 
00595   if (mWindowPtr == nsnull)
00596     return NS_ERROR_OUT_OF_MEMORY;
00597   
00598   nsMacMessageSink::AddRaptorWindowToList(mWindowPtr, this);
00599 
00600   // create the root control
00601   ControlHandle   rootControl = nil;
00602   if (GetRootControl(mWindowPtr, &rootControl) != noErr)
00603   {
00604     OSErr err = CreateRootControl(mWindowPtr, &rootControl);
00605     NS_ASSERTION(err == noErr, "Error creating window root control");
00606   }
00607 
00608   // reset the coordinates to (0,0) because it's the top level widget
00609   // and adjust for any adjustment required to requested window bottom
00610   nsRect bounds(0, 0, aRect.width, aRect.height - bottomPinDelta);
00611 
00612   // init base class
00613   // (note: aParent is ignored. Mac (real) windows don't want parents)
00614   Inherited::StandardCreate(nil, bounds, aHandleEventFunction, aContext, aAppShell, theToolkit, aInitData);
00615 
00616 #if TARGET_CARBON
00617   if ( mWindowType == eWindowType_popup ) {
00618     // OSX enforces window layering so we have to make sure that popups can
00619     // appear over modal dialogs (at the top of the layering chain). Create
00620     // the popup like normal and change its window class to the modal layer.
00621     //
00622     // XXX This needs to use ::SetWindowGroup() when we move to headers that
00623     // XXX support it.
00624     ::SetWindowClass(mWindowPtr, kModalWindowClass);
00625   }
00626   else if ( mWindowType == eWindowType_dialog ) {
00627     // Dialogs on mac don't have a close box, but we probably used a defproc above that
00628     // contains one. Thankfully, carbon lets us turn it off after the window has been 
00629     // created. Do so. We currently leave the collapse widget for all dialogs.
00630     ::ChangeWindowAttributes(mWindowPtr, 0L, kWindowCloseBoxAttribute );
00631   }
00632   
00633   // Setup the live window resizing
00634   if ( mWindowType == eWindowType_toplevel || mWindowType == eWindowType_invisible ) {
00635     WindowAttributes removeAttributes = kWindowNoAttributes;
00636     if ( mWindowType == eWindowType_invisible )
00637       removeAttributes |= kWindowInWindowMenuAttribute;     
00638     ::ChangeWindowAttributes ( mWindowPtr, kWindowLiveResizeAttribute, removeAttributes );
00639     
00640     EventTypeSpec windEventList[] = { {kEventClassWindow, kEventWindowBoundsChanged},
00641                                       {kEventClassWindow, kEventWindowConstrain} };
00642     EventTypeSpec scrollEventList[] = { {kEventClassMouse, kEventMouseWheelMoved} };
00643     OSStatus err1 = ::InstallWindowEventHandler ( mWindowPtr, NewEventHandlerUPP(WindowEventHandler), 2, windEventList, this, NULL );
00644     OSStatus err2 = ::InstallWindowEventHandler ( mWindowPtr, NewEventHandlerUPP(ScrollEventHandler), 1, scrollEventList, this, NULL );
00645       // note, passing NULL as the final param to IWEH() causes the UPP to be disposed automatically
00646       // when the event target (the window) goes away. See CarbonEvents.h for info.
00647     
00648     NS_ASSERTION(err1 == noErr && err2 == noErr, "Couldn't install Carbon Event handlers");
00649   }  
00650 #endif
00651   
00652     
00653   // register tracking and receive handlers with the native Drag Manager
00654   if ( mDragTrackingHandlerUPP ) {
00655     OSErr result = ::InstallTrackingHandler ( mDragTrackingHandlerUPP, mWindowPtr, this );
00656     NS_ASSERTION ( result == noErr, "can't install drag tracking handler");
00657   }
00658   if ( mDragReceiveHandlerUPP ) {
00659     OSErr result = ::InstallReceiveHandler ( mDragReceiveHandlerUPP, mWindowPtr, this );
00660     NS_ASSERTION ( result == noErr, "can't install drag receive handler");
00661   }
00662 
00663   // If we're a popup, we don't want a border (we want CSS to draw it for us). So
00664   // install our own window defProc.
00665   if ( mWindowType == eWindowType_popup )
00666     InstallBorderlessDefProc(mWindowPtr);
00667 
00668 #endif
00669 
00670   return NS_OK;
00671 }
00672 
00673 
00674 #if 0
00675 
00676 pascal OSStatus
00677 nsCocoaWindow::ScrollEventHandler ( EventHandlerCallRef inHandlerChain, EventRef inEvent, void* userData )
00678 {
00679   EventMouseWheelAxis axis = kEventMouseWheelAxisY;
00680   SInt32 delta = 0;
00681   Point mouseLoc;
00682   OSErr err1 = ::GetEventParameter ( inEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis,
00683                         NULL, sizeof(EventMouseWheelAxis), NULL, &axis ); 
00684   OSErr err2 = ::GetEventParameter ( inEvent, kEventParamMouseWheelDelta, typeLongInteger,
00685                         NULL, sizeof(SInt32), NULL, &delta ); 
00686   OSErr err3 = ::GetEventParameter ( inEvent, kEventParamMouseLocation, typeQDPoint,
00687                         NULL, sizeof(Point), NULL, &mouseLoc ); 
00688 
00689   if ( err1 == noErr && err2 == noErr && err3 == noErr ) {
00690     nsCocoaWindow* self = NS_REINTERPRET_CAST(nsCocoaWindow*, userData);
00691     if ( self )
00692       self->mMacEventHandler->Scroll ( axis, delta, mouseLoc );
00693   }
00694   return noErr;
00695   
00696 } // ScrollEventHandler
00697 
00698 
00699 pascal OSStatus
00700 nsCocoaWindow::WindowEventHandler ( EventHandlerCallRef inHandlerChain, EventRef inEvent, void* userData )
00701 {
00702   OSStatus retVal = noErr;
00703   
00704   WindowRef myWind = NULL;
00705   ::GetEventParameter ( inEvent, kEventParamDirectObject, typeWindowRef, NULL, sizeof(myWind), NULL, &myWind );
00706   if ( myWind ) {
00707     UInt32 what = ::GetEventKind ( inEvent );
00708     switch ( what ) {
00709     
00710       case kEventWindowBoundsChanged:
00711       {
00712         // are we moving or resizing the window? we only care about resize.
00713         UInt32 attributes = 0;
00714         ::GetEventParameter ( inEvent, kEventParamAttributes, typeUInt32, NULL, sizeof(attributes), NULL, &attributes );
00715         if ( attributes & kWindowBoundsChangeSizeChanged ) {
00716           Rect bounds;
00717           ::InvalWindowRect(myWind, ::GetWindowPortBounds(myWind, &bounds));
00718           
00719           // resize the window and repaint
00720           nsCocoaWindow* self = NS_REINTERPRET_CAST(nsCocoaWindow*, userData);
00721           if ( self && !self->mResizeIsFromUs ) {
00722             self->mMacEventHandler->ResizeEvent(myWind);
00723             self->mMacEventHandler->UpdateEvent();
00724           }
00725         }
00726         break;
00727       }
00728       
00729       case kEventWindowConstrain:
00730       {
00731         // Ignore this event if we're an invisible window, otherwise pass along the
00732         // chain to ensure it's onscreen.
00733         nsCocoaWindow* self = NS_REINTERPRET_CAST(nsCocoaWindow*, userData);
00734         if ( self ) {
00735           if ( self->mWindowType != eWindowType_invisible )
00736             retVal = ::CallNextEventHandler( inHandlerChain, inEvent );
00737         }
00738         break;
00739       }      
00740         
00741       default:
00742         // do nothing...
00743         break;
00744     
00745     } // case of which event?
00746   }
00747   
00748   return retVal;
00749   
00750 } // WindowEventHandler
00751 
00752 #endif
00753 
00754 
00755 //-------------------------------------------------------------------------
00756 //
00757 // Create a nsCocoaWindow using a native window provided by the application
00758 //
00759 //-------------------------------------------------------------------------
00760 NS_IMETHODIMP nsCocoaWindow::Create(nsNativeWidget aNativeParent,
00761                       const nsRect &aRect,
00762                       EVENT_CALLBACK aHandleEventFunction,
00763                       nsIDeviceContext *aContext,
00764                       nsIAppShell *aAppShell,
00765                       nsIToolkit *aToolkit,
00766                       nsWidgetInitData *aInitData)
00767 {
00768   return(StandardCreate(nsnull, aRect, aHandleEventFunction,
00769                           aContext, aAppShell, aToolkit, aInitData,
00770                             aNativeParent));
00771 }
00772 
00773 
00774 NS_IMETHODIMP nsCocoaWindow::Create(nsIWidget* aParent,
00775                       const nsRect &aRect,
00776                       EVENT_CALLBACK aHandleEventFunction,
00777                       nsIDeviceContext *aContext,
00778                       nsIAppShell *aAppShell,
00779                       nsIToolkit *aToolkit,
00780                       nsWidgetInitData *aInitData)
00781 {
00782   return(StandardCreate(aParent, aRect, aHandleEventFunction,
00783                           aContext, aAppShell, aToolkit, aInitData,
00784                             nsnull));
00785 }
00786 
00787 
00788 void*
00789 nsCocoaWindow::GetNativeData(PRUint32 aDataType)
00790 {
00791   void* retVal = nsnull;
00792   
00793   switch ( aDataType ) {
00794     
00795     // to emulate how windows works, we always have to return a NSView
00796     // for NS_NATIVE_WIDGET
00797     case NS_NATIVE_WIDGET:
00798     case NS_NATIVE_DISPLAY:
00799       retVal = [mWindow contentView];
00800       break;
00801       
00802     case NS_NATIVE_WINDOW:  
00803       retVal = mWindow;
00804       break;
00805       
00806     case NS_NATIVE_GRAPHIC:          // quickdraw port of top view (for now)
00807       retVal = [[mWindow contentView] qdPort];
00808       break;
00809       
00810 #if 0
00811     case NS_NATIVE_REGION:
00812     retVal = (void*)mVisRegion;
00813       break;
00814 
00815     case NS_NATIVE_COLORMAP:
00816       //¥TODO
00817       break;
00818 
00819     case NS_NATIVE_OFFSETX:
00820       point.MoveTo(mBounds.x, mBounds.y);
00821       LocalToWindowCoordinate(point);
00822       retVal = (void*)point.x;
00823       break;
00824 
00825     case NS_NATIVE_OFFSETY:
00826       point.MoveTo(mBounds.x, mBounds.y);
00827       LocalToWindowCoordinate(point);
00828       retVal = (void*)point.y;
00829       break;
00830     
00831     case NS_NATIVE_PLUGIN_PORT:
00832       // this needs to be a combination of the port and the offsets.
00833       if (mPluginPort == nsnull)
00834         mPluginPort = new nsPluginPort;
00835       
00836       point.MoveTo(mBounds.x, mBounds.y);
00837       LocalToWindowCoordinate(point);
00838       
00839       // for compatibility with 4.X, this origin is what you'd pass
00840       // to SetOrigin.
00841       mPluginPort->port = ::GetWindowPort(mWindowPtr);
00842       mPluginPort->portx = -point.x;
00843       mPluginPort->porty = -point.y;
00844     
00845       retVal = (void*)mPluginPort;
00846       break;
00847 #endif
00848   }
00849 
00850   return retVal;
00851 }
00852 
00853 NS_IMETHODIMP
00854 nsCocoaWindow::IsVisible(PRBool & aState)
00855 {
00856   aState = mVisible;
00857   return NS_OK;
00858 }
00859    
00860 //-------------------------------------------------------------------------
00861 //
00862 // Hide or show this window
00863 //
00864 //-------------------------------------------------------------------------
00865 NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
00866 {
00867   if ( bState )
00868     [mWindow orderFront:NULL];
00869   else
00870     [mWindow orderOut:NULL];
00871 
00872   mVisible = bState;
00873 
00874 #if 0
00875   // we need to make sure we call ::Show/HideWindow() to generate the 
00876   // necessary activate/deactivate events. Calling ::ShowHide() is
00877   // not adequate, unless we don't want activation (popups). (pinkerton).
00878   if ( bState && !mBounds.IsEmpty() ) {
00879     if ( mAcceptsActivation )
00880       ::ShowWindow(mWindowPtr);
00881     else {
00882       ::ShowHide(mWindowPtr, true);
00883       ::BringToFront(mWindowPtr); // competes with ComeToFront, but makes popups work
00884     }
00885     if (mZoomOnShow) {
00886       SetSizeMode(nsSizeMode_Maximized);
00887       mZoomOnShow = PR_FALSE;
00888     }
00889     ComeToFront();
00890   }
00891   else {
00892     // when a toplevel window goes away, make sure we rollup any popups that may 
00893     // be lurking. We want to catch this here because we're guaranteed that
00894     // we hide a window before we destroy it, and doing it here more closely
00895     // approximates where we do the same thing on windows.
00896     if ( mWindowType == eWindowType_toplevel ) {
00897       if ( gRollupListener )
00898         gRollupListener->Rollup();
00899       NS_IF_RELEASE(gRollupListener);
00900       NS_IF_RELEASE(gRollupWidget);
00901     }
00902     ::HideWindow(mWindowPtr);
00903   }
00904   
00905 #endif
00906 
00907   return NS_OK;
00908 }
00909 
00910 
00911 NS_IMETHODIMP nsCocoaWindow::Enable(PRBool aState)
00912 {
00913   return NS_OK;
00914 }
00915 
00916 
00917 NS_IMETHODIMP nsCocoaWindow::IsEnabled(PRBool *aState)
00918 {
00919   if (aState)
00920     *aState = PR_TRUE;
00921   return NS_OK;
00922 }
00923 
00924 
00925 /*
00926 NS_METHOD nsWindow::Minimize(void)
00927 {
00928   return NS_OK;
00929 }
00930 
00931 NS_METHOD nsWindow::Maximize(void)
00932 {
00933   return NS_OK;
00934 }
00935 
00936 NS_METHOD nsWindow::Restore(void)
00937 {
00938   return NS_OK;
00939 }
00940 */
00941 
00942 NS_IMETHODIMP nsCocoaWindow::ConstrainPosition(PRBool aAllowSlop,
00943                                                PRInt32 *aX, PRInt32 *aY)
00944 {
00945 #if 0
00946   if (eWindowType_popup == mWindowType || !mWindowMadeHere)
00947     return NS_OK;
00948 
00949   // Sanity check against screen size
00950   // make sure the window stays visible
00951 
00952   // get the window bounds
00953   Rect portBounds;
00954   ::GetWindowPortBounds(mWindowPtr, &portBounds);
00955   short pos;
00956   short windowWidth = portBounds.right - portBounds.left;
00957   short windowHeight = portBounds.bottom - portBounds.top;
00958 
00959   // now get our playing field. use the current screen, or failing that for any reason,
00960   // the GrayRgn (which of course is arguably more correct but has drawbacks as well)
00961   Rect screenRect;
00962   nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
00963   if (screenmgr) {
00964     nsCOMPtr<nsIScreen> screen;
00965     PRInt32 left, top, width, height, fullHeight;
00966 
00967     // zero size rects can happen during window creation, and confuse
00968     // the screen manager
00969     width = windowWidth > 0 ? windowWidth : 1;
00970     height = windowHeight > 0 ? windowHeight : 1;
00971     screenmgr->ScreenForRect(*aX, *aY, width, height,
00972                             getter_AddRefs(screen));
00973     if (screen) {
00974       screen->GetAvailRect(&left, &top, &width, &height);
00975       screen->GetRect(&left, &top, &width, &fullHeight);
00976       screenRect.left = left;
00977       screenRect.right = left+width;
00978       screenRect.top = top;
00979       screenRect.bottom = top+height;
00980     }
00981   } else
00982     ::GetRegionBounds(::GetGrayRgn(), &screenRect);
00983 
00984   pos = screenRect.left;
00985   if (windowWidth > kWindowPositionSlop)
00986     pos -= windowWidth - kWindowPositionSlop;
00987   if (*aX < pos)
00988     *aX = pos;
00989   else if (*aX >= screenRect.right - kWindowPositionSlop)
00990     *aX = screenRect.right - kWindowPositionSlop;
00991 
00992   pos = screenRect.top;
00993   if (windowHeight > kWindowPositionSlop)
00994     pos -= windowHeight - kWindowPositionSlop;
00995   if (*aY < pos)
00996     *aY = pos;
00997   else if (*aY >= screenRect.bottom - kWindowPositionSlop)
00998     *aY = screenRect.bottom - kWindowPositionSlop;
00999 
01000 #endif
01001   return NS_OK;
01002 }
01003 
01004 //-------------------------------------------------------------------------
01005 //
01006 // Move this window
01007 //
01008 //-------------------------------------------------------------------------
01009 //-------------------------------------------------------------------------
01010 // Move
01011 //-------------------------------------------------------------------------
01012 NS_IMETHODIMP nsCocoaWindow::Move(PRInt32 aX, PRInt32 aY)
01013 {  
01014   if ( mWindow ) {  
01015     // if we're a popup, we have to convert from our parent widget's coord
01016     // system to the global coord system first because the (x,y) we're given
01017     // is in its coordinate system.
01018     if ( mWindowType == eWindowType_popup ) {
01019       nsRect localRect, globalRect; 
01020       localRect.x = aX;
01021       localRect.y = aY;  
01022       if ( mOffsetParent ) {
01023         mOffsetParent->WidgetToScreen(localRect,globalRect);
01024         aX=globalRect.x;
01025         aY=globalRect.y;
01026      }
01027     }
01028     
01029     NSPoint coord = {aX, aY};
01030     //coord = [mWindow convertBaseToScreen:coord];
01031 //printf("moving to %d %d. screen coords %f %f\n", aX, aY, coord.x, coord.y);
01032 
01033  //FIXME -- ensure it's on the screen. Cocoa automatically corrects for windows
01034  //   with title bars, but for other windows, we have to do this...
01035  
01036     // the point we have assumes that the screen origin is the top-left. Well,
01037     // it's not. Use the screen object to convert.
01038     //FIXME -- doesn't work on monitors other than primary
01039     NSRect screenRect = [[NSScreen mainScreen] frame];
01040     coord.y = (screenRect.origin.y + screenRect.size.height) - coord.y;
01041 //printf("final coords %f %f\n", coord.x, coord.y);
01042 //printf("- window coords before %f %f\n", [mWindow frame].origin.x, [mWindow frame].origin.y);
01043     [mWindow setFrameTopLeftPoint:coord];
01044 //printf("- window coords after %f %f\n", [mWindow frame].origin.x, [mWindow frame].origin.y);
01045   }
01046   
01047 #if 0
01048   StPortSetter setOurPortForLocalToGlobal ( mWindowPtr );
01049   
01050   if (eWindowType_popup == mWindowType) {
01051     PRInt32 xOffset=0,yOffset=0;
01052     nsRect  localRect,globalRect;
01053 
01054     // convert to screen coordinates
01055     localRect.x = aX;
01056     localRect.y = aY;
01057     localRect.width = 100;
01058     localRect.height = 100; 
01059 
01060     if ( mOffsetParent ) {
01061       mOffsetParent->WidgetToScreen(localRect,globalRect);
01062       aX=globalRect.x;
01063       aY=globalRect.y;
01064       
01065       // there is a bug on OSX where if we call ::MoveWindow() with the same
01066       // coordinates (within a pixel or two) as a window's current location, it will 
01067       // move to (0,0,-1,-1). The fix is to not move the window if we're already
01068       // there. (radar# 2669004)
01069 #if TARGET_CARBON
01070       const PRInt32 kMoveThreshold = 2;
01071 #else
01072       const PRInt32 kMoveThreshold = 0;
01073 #endif
01074       Rect currBounds;
01075       ::GetWindowBounds ( mWindowPtr, kWindowGlobalPortRgn, &currBounds );
01076       if ( abs(currBounds.left-aX) > kMoveThreshold || abs(currBounds.top-aY) > kMoveThreshold ) {
01077         ::MoveWindow(mWindowPtr, aX, aY, false);
01078         
01079         Rect newBounds;
01080         ::GetWindowBounds ( mWindowPtr, kWindowGlobalPortRgn, &newBounds );
01081       }  
01082     }
01083 
01084     return NS_OK;
01085   } else if (mWindowMadeHere) {
01086     Rect portBounds;
01087     ::GetWindowPortBounds(mWindowPtr, &portBounds);
01088 
01089     if (mIsDialog) {
01090       aX += kDialogMarginWidth;
01091       aY += kDialogTitleBarHeight;
01092     } else {
01093       aX += kWindowMarginWidth;
01094       aY += kWindowTitleBarHeight;
01095     }
01096 
01097     nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
01098     if (screenmgr) {
01099       nsCOMPtr<nsIScreen> screen;
01100       PRInt32 left, top, width, height, fullTop;
01101       // adjust for unset bounds, which confuses the screen manager
01102       width = portBounds.right - portBounds.left;
01103       height = portBounds.bottom - portBounds.top;
01104       if (height <= 0) height = 1;
01105       if (width <= 0) width = 1;
01106 
01107       screenmgr->ScreenForRect(aX, aY, width, height,
01108                                getter_AddRefs(screen));
01109       if (screen) {
01110         screen->GetAvailRect(&left, &top, &width, &height);
01111         screen->GetRect(&left, &fullTop, &width, &height);
01112         aY += top-fullTop;
01113       }
01114     }
01115 
01116     // move the window if it has not been moved yet
01117     // (ie. if this function isn't called in response to a DragWindow event)
01118     Point macPoint = topLeft(portBounds);
01119     ::LocalToGlobal(&macPoint);
01120     if (macPoint.h != aX || macPoint.v != aY)
01121       ::MoveWindow(mWindowPtr, aX, aY, false);
01122 
01123     // propagate the event in global coordinates
01124     Inherited::Move(aX, aY);
01125 
01126     // reset the coordinates to (0,0) because it's the top level widget
01127     mBounds.x = 0;
01128     mBounds.y = 0;
01129   }
01130 #endif
01131   return NS_OK;
01132 }
01133 
01134 //-------------------------------------------------------------------------
01135 //
01136 // Position the window behind the given window
01137 //
01138 //-------------------------------------------------------------------------
01139 NS_METHOD nsCocoaWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
01140                                      nsIWidget *aWidget, PRBool aActivate)
01141 {
01142 #if 0
01143   if (aWidget) {
01144     WindowPtr behind = (WindowPtr)aWidget->GetNativeData(NS_NATIVE_DISPLAY);
01145     ::SendBehind(mWindowPtr, behind);
01146     ::HiliteWindow(mWindowPtr, FALSE);
01147   } else {
01148     if (::FrontWindow() != mWindowPtr)
01149       ::SelectWindow(mWindowPtr);
01150   }
01151 #endif
01152   return NS_OK;
01153 }
01154 
01155 //-------------------------------------------------------------------------
01156 //
01157 // zoom/restore
01158 //
01159 //-------------------------------------------------------------------------
01160 NS_METHOD nsCocoaWindow::SetSizeMode(PRInt32 aMode)
01161 {
01162 #if 0
01163   nsresult rv;
01164   PRInt32  currentMode;
01165 
01166   if (aMode == nsSizeMode_Minimized) // unlikely on the Mac
01167     return NS_ERROR_UNEXPECTED;
01168 
01169   // already done? it's bad to rezoom a window, so do nothing
01170   rv = nsBaseWidget::GetSizeMode(&currentMode);
01171   if (NS_SUCCEEDED(rv) && currentMode == aMode)
01172     return NS_OK;
01173 
01174   if (!mVisible) {
01175     /* zooming on the Mac doesn't seem to work until the window is visible.
01176        the rest of the app is structured to zoom before the window is visible
01177        to avoid flashing. here's where we defeat that. */
01178     if (aMode == nsSizeMode_Maximized)
01179       mZoomOnShow = PR_TRUE;
01180   } else {
01181     Rect macRect;
01182     rv = nsBaseWidget::SetSizeMode(aMode);
01183     if (NS_SUCCEEDED(rv)) {
01184       if (aMode == nsSizeMode_Maximized) {
01185         CalculateAndSetZoomedSize();
01186         ::ZoomWindow(mWindowPtr, inZoomOut, ::FrontWindow() == mWindowPtr);
01187       } else
01188         ::ZoomWindow(mWindowPtr, inZoomIn, ::FrontWindow() == mWindowPtr);
01189       ::GetWindowPortBounds(mWindowPtr, &macRect);
01190       Resize(macRect.right - macRect.left, macRect.bottom - macRect.top, PR_FALSE);
01191     }
01192   }
01193 #endif
01194 
01195   return NS_OK;
01196 }
01197 
01198 void nsCocoaWindow::CalculateAndSetZoomedSize()
01199 {
01200 #if 0
01201   StPortSetter setOurPort(mWindowPtr);
01202 
01203   // calculate current window portbounds
01204   Rect windRect;
01205   ::GetWindowPortBounds(mWindowPtr, &windRect);
01206   ::LocalToGlobal((Point *)&windRect.top);
01207   ::LocalToGlobal((Point *)&windRect.bottom);
01208 
01209   // calculate window's borders on each side, these differ in Aqua / Platinum
01210   short wTitleHeight;
01211   short wLeftBorder;
01212   short wRightBorder;
01213   short wBottomBorder;
01214        
01215   RgnHandle structRgn = ::NewRgn();
01216   ::GetWindowRegion(mWindowPtr, kWindowStructureRgn, structRgn);
01217   Rect structRgnBounds;
01218   ::GetRegionBounds(structRgn, &structRgnBounds);
01219   wTitleHeight = windRect.top - structRgnBounds.top;
01220   wLeftBorder = windRect.left - structRgnBounds.left;
01221   wRightBorder =  structRgnBounds.right - windRect.right;
01222   wBottomBorder = structRgnBounds.bottom - windRect.bottom;
01223 
01224   ::DisposeRgn(structRgn);
01225 
01226   windRect.top -= wTitleHeight;
01227   windRect.bottom += wBottomBorder;
01228   windRect.right += wRightBorder;
01229   windRect.left -= wLeftBorder;
01230 
01231   // find which screen the window is (mostly) on and get its rect. GetAvailRect()
01232   // handles subtracting out the menubar and the dock for us. Set the zoom rect
01233   // to the screen rect, less some fudging and room for icons on the primary screen.
01234   nsCOMPtr<nsIScreenManager> screenMgr = do_GetService(sScreenManagerContractID);
01235   if ( screenMgr ) {
01236     nsCOMPtr<nsIScreen> screen;
01237     screenMgr->ScreenForRect ( windRect.left, windRect.top, windRect.right - windRect.left, windRect.bottom - windRect.top,
01238                                 getter_AddRefs(screen) );
01239     if ( screen ) {
01240       nsRect newWindowRect;
01241       screen->GetAvailRect ( &newWindowRect.x, &newWindowRect.y, &newWindowRect.width, &newWindowRect.height );
01242       
01243       // leave room for icons on primary screen
01244       nsCOMPtr<nsIScreen> primaryScreen;
01245       screenMgr->GetPrimaryScreen ( getter_AddRefs(primaryScreen) );
01246       if (screen == primaryScreen) {
01247         int iconSpace = 96;
01248 #if TARGET_CARBON
01249         iconSpace = 128;
01250 #endif
01251         newWindowRect.width -= iconSpace;
01252       }
01253 
01254       Rect zoomRect;
01255       ::SetRect(&zoomRect,
01256                   newWindowRect.x + wLeftBorder,
01257                   newWindowRect.y + wTitleHeight,
01258                   newWindowRect.x + newWindowRect.width - wRightBorder,
01259                   newWindowRect.y + newWindowRect.height - wBottomBorder); 
01260       ::SetWindowStandardState ( mWindowPtr, &zoomRect );
01261     }
01262   }
01263 #endif
01264   
01265 } // CalculateAndSetZoomedSize
01266 
01267 
01268 //-------------------------------------------------------------------------
01269 //
01270 // Resize this window to a point given in global (screen) coordinates. This
01271 // differs from simple Move(): that method makes JavaScript place windows
01272 // like other browsers: it puts the top-left corner of the outer edge of the
01273 // window border at the given coordinates, offset from the menubar.
01274 // MoveToGlobalPoint expects the top-left corner of the portrect, which
01275 // is inside the border, and is not offset by the menubar height.
01276 //
01277 //-------------------------------------------------------------------------
01278 void nsCocoaWindow::MoveToGlobalPoint(PRInt32 aX, PRInt32 aY)
01279 {
01280 #if 0
01281   PRInt32 left, top, width, height, fullTop;
01282   Rect portBounds;
01283 
01284   StPortSetter doThatThingYouDo(mWindowPtr);
01285   ::GetWindowPortBounds(mWindowPtr, &portBounds);
01286 
01287   width = portBounds.right - portBounds.left;
01288   height = portBounds.bottom - portBounds.top;
01289   ::LocalToGlobal(&topLeft(portBounds));
01290 
01291   nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
01292   if (screenmgr) {
01293     nsCOMPtr<nsIScreen> screen;
01294     //screenmgr->GetPrimaryScreen(getter_AddRefs(screen));
01295     screenmgr->ScreenForRect(portBounds.left, portBounds.top, width, height,
01296                              getter_AddRefs(screen));
01297     if (screen) {
01298       screen->GetAvailRect(&left, &top, &width, &height);
01299       screen->GetRect(&left, &fullTop, &width, &height);
01300       aY -= top-fullTop;
01301     }
01302   }
01303 
01304   if (mIsDialog) {
01305     aX -= kDialogMarginWidth;
01306     aY -= kDialogTitleBarHeight;
01307   } else {
01308     aX -= kWindowMarginWidth;
01309     aY -= kWindowTitleBarHeight;
01310   }
01311   Move(aX, aY);
01312 #endif
01313 }
01314 
01315 
01316 NS_IMETHODIMP nsCocoaWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
01317 {
01318   Move(aX, aY);
01319   Resize(aWidth, aHeight, aRepaint);
01320   return NS_OK;
01321 }
01322 
01323 
01324 //-------------------------------------------------------------------------
01325 //
01326 // Resize this window
01327 //
01328 //-------------------------------------------------------------------------
01329 NS_IMETHODIMP nsCocoaWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
01330 {
01331   if ( mWindow ) {
01332     NSRect newBounds = [mWindow frame];
01333     newBounds.size.width = aWidth;
01334     if ( mWindowType == eWindowType_popup )
01335       newBounds.size.height = aHeight;
01336     else
01337       newBounds.size.height = aHeight + kTitleBarHeight;     // add height of title bar
01338     StartResizing();
01339     [mWindow setFrame:newBounds display:NO];
01340     StopResizing();
01341   }
01342 
01343   mBounds.width  = aWidth;
01344   mBounds.height = aHeight;
01345   
01346   // tell gecko to update all the child widgets
01347   ReportSizeEvent();
01348   
01349 #if 0
01350   if (mWindowMadeHere) {
01351       // Sanity check against screen size
01352       Rect screenRect;
01353     ::GetRegionBounds(::GetGrayRgn(), &screenRect);
01354 
01355       // Need to use non-negative coordinates
01356       PRInt32 screenWidth;
01357       if(screenRect.left < 0)
01358         screenWidth = screenRect.right - screenRect.left;
01359       else
01360         screenWidth = screenRect.right;
01361         
01362       PRInt32 screenHeight;
01363       if(screenRect.top < 0)
01364         screenHeight = screenRect.bottom - screenRect.top;
01365       else
01366         screenHeight = screenRect.bottom;
01367           
01368       if(aHeight > screenHeight)
01369         aHeight = screenHeight;
01370         
01371       if(aWidth > screenWidth)
01372         aWidth = screenWidth;      
01373     
01374     Rect macRect;
01375     ::GetWindowPortBounds ( mWindowPtr, &macRect );
01376 
01377     short w = macRect.right - macRect.left;
01378     short h = macRect.bottom - macRect.top;
01379     Boolean needReposition = (w == 1 && h == 1);
01380 
01381     if ((w != aWidth) || (h != aHeight))
01382     {
01383       // make sure that we don't infinitely recurse if live-resize is on
01384       mResizeIsFromUs = PR_TRUE;
01385       ::SizeWindow(mWindowPtr, aWidth, aHeight, aRepaint);
01386       mResizeIsFromUs = PR_FALSE;
01387 
01388 #if defined(XP_MACOSX)
01389       // workaround for bug in MacOSX if windows start life as 1x1.
01390       if (needReposition)
01391         RepositionWindow(mWindowPtr, NULL, kWindowCascadeOnMainScreen);
01392 #endif
01393     }
01394   }
01395 #endif
01396   //Inherited::Resize(aWidth, aHeight, aRepaint);
01397   return NS_OK;
01398 }
01399 
01400 NS_IMETHODIMP nsCocoaWindow::GetScreenBounds(nsRect &aRect) {
01401 #if 0 
01402   nsRect localBounds;
01403   PRInt32 yAdjust = 0;
01404 
01405   GetBounds(localBounds);
01406   // nsCocoaWindow local bounds are always supposed to be local (0,0) but in the middle of a move
01407   // can be global. This next adjustment assures they are in local coordinates, even then.
01408   localBounds.MoveBy(-localBounds.x, -localBounds.y);
01409   WidgetToScreen(localBounds, aRect);
01410 
01411   nsCOMPtr<nsIScreenManager> screenmgr = do_GetService(sScreenManagerContractID);
01412   if (screenmgr) {
01413     nsCOMPtr<nsIScreen> screen;
01414     //screenmgr->GetPrimaryScreen(getter_AddRefs(screen));
01415     screenmgr->ScreenForRect(aRect.x, aRect.y, aRect.width, aRect.height,
01416                              getter_AddRefs(screen));
01417     if (screen) {
01418       PRInt32 left, top, width, height, fullTop;
01419       screen->GetAvailRect(&left, &top, &width, &height);
01420       screen->GetRect(&left, &fullTop, &width, &height);
01421       yAdjust = top-fullTop;
01422     }
01423   }
01424  
01425   if (mIsDialog)
01426     aRect.MoveBy(-kDialogMarginWidth, -kDialogTitleBarHeight-yAdjust);
01427   else
01428     aRect.MoveBy(-kWindowMarginWidth, -kWindowTitleBarHeight-yAdjust);
01429 
01430 #endif
01431   return NS_OK;
01432 }
01433 
01434 //-------------------------------------------------------------------------
01435 //
01436 //
01437 //-------------------------------------------------------------------------
01438 PRBool nsCocoaWindow::OnPaint(nsPaintEvent &event)
01439 {
01440   return PR_TRUE; // don't dispatch the update event
01441 }
01442 
01443 //-------------------------------------------------------------------------
01444 //
01445 // Set this window's title
01446 //
01447 //-------------------------------------------------------------------------
01448 NS_IMETHODIMP nsCocoaWindow::SetTitle(const nsAString& aTitle)
01449 {
01450   const nsString& strTitle = PromiseFlatString(aTitle);
01451   NSString* title = [NSString stringWithCharacters:strTitle.get() length:strTitle.Length()];
01452   [mWindow setTitle:title];
01453 
01454   return NS_OK;
01455 }
01456 
01457 
01458 //-------------------------------------------------------------------------
01459 // Pass notification of some drag event to Gecko
01460 //
01461 // The drag manager has let us know that something related to a drag has
01462 // occurred in this window. It could be any number of things, ranging from 
01463 // a drop, to a drag enter/leave, or a drag over event. The actual event
01464 // is passed in |aMessage| and is passed along to our event hanlder so Gecko
01465 // knows about it.
01466 //-------------------------------------------------------------------------
01467 PRBool nsCocoaWindow::DragEvent ( unsigned int aMessage, Point aMouseGlobal, UInt16 aKeyModifiers )
01468 {
01469 #if 0
01470   PRBool retVal;
01471   if (mMacEventHandler.get())
01472     retVal = mMacEventHandler->DragEvent(aMessage, aMouseGlobal, aKeyModifiers);
01473   else
01474     retVal = PR_FALSE;
01475   return retVal;
01476 #endif
01477   return PR_FALSE;
01478 }
01479 
01480 //-------------------------------------------------------------------------
01481 //
01482 // Like ::BringToFront, but constrains the window to its z-level
01483 //
01484 //-------------------------------------------------------------------------
01485 void nsCocoaWindow::ComeToFront() {
01486 #if 0
01487   nsZLevelEvent  event(PR_TRUE, NS_SETZLEVEL, this);
01488 
01489   event.point.x = mBounds.x;
01490   event.point.y = mBounds.y;
01491   event.time = PR_IntervalNow();
01492 
01493   event.mImmediate = PR_TRUE;
01494 
01495   DispatchWindowEvent(event);
01496 #endif
01497 }
01498 
01499 
01500 NS_IMETHODIMP nsCocoaWindow::ResetInputState()
01501 {
01502 //  return mMacEventHandler->ResetInputState();
01503   return NS_OK;
01504 }
01505 
01506 void nsCocoaWindow::SetIsActive(PRBool aActive)
01507 {
01508 //  mIsActive = aActive;
01509 }
01510 
01511 void nsCocoaWindow::IsActive(PRBool* aActive)
01512 {
01513 //  *aActive = mIsActive;
01514 }
01515 
01516 #if 0
01517 
01518 //
01519 // DispatchEvent
01520 //
01521 // 
01522 NS_IMETHODIMP
01523 nsCocoaWindow::DispatchEvent ( void* anEvent, void* aView, PRBool *_retval )
01524 {
01525   *_retval = PR_FALSE;
01526 
01527 #if 0  
01528   NSEvent* event = NS_REINTERPRET_CAST(NSEvent*, anEvent);
01529   NS_ASSERTION(event, "null event");
01530   
01531   ChildView* view = NS_REINTERPRET_CAST(ChildView*, aView);
01532   
01533   nsMouseEvent geckoEvent(PR_TRUE, 0, view ? [view widget] : this,
01534                           nsMouseEvent::eReal)
01535   
01536   geckoEvent.nativeMsg = anEvent;
01537   geckoEvent.time = PR_IntervalNow();
01538   NSPoint mouseLoc = [event locationInWindow];
01539   geckoEvent.refPoint.x = NS_STATIC_CAST(nscoord, mouseLoc.x);
01540   geckoEvent.refPoint.y = NS_STATIC_CAST(nscoord, mouseLoc.y);
01541 //printf("-- global mouse click at (%ld,%ld)\n", geckoEvent.refPoint.x, geckoEvent.refPoint.y );
01542   if ( view ) {
01543     // convert point to view coordinate system
01544     NSPoint localPoint = [view convertPoint:mouseLoc fromView:nil];
01545     geckoEvent.point.x = NS_STATIC_CAST(nscoord, localPoint.x);
01546     geckoEvent.point.y = NS_STATIC_CAST(nscoord, localPoint.y);
01547 //printf("-- local mouse click at (%ld,%ld) widget = %ld\n", geckoEvent.point.x, geckoEvent.point.y,
01548 //          geckoEvent.widget );
01549   }
01550   else
01551     geckoEvent.point = geckoEvent.refPoint;
01552 
01553   NSEventType type = [event type];
01554   switch ( type ) {
01555     case NSLeftMouseDown:
01556       //printf("left mouse down\n");
01557       geckoEvent.message = NS_MOUSE_LEFT_BUTTON_DOWN;
01558       geckoEvent.clickCount = [event clickCount];
01559       break;
01560     case NSLeftMouseUp:
01561       //printf("left mouse up\n");
01562       break;
01563     case NSMouseMoved:
01564       printf("mouse move\n");
01565       break;
01566     case NSKeyDown:
01567       printf("key down\n");
01568       break;
01569     case NSKeyUp:
01570       printf("key up\n");
01571       break;
01572     case NSScrollWheel:
01573       printf("scroll wheel\n");
01574       break;
01575     case NSLeftMouseDragged:
01576       printf("drag\n");
01577       break;
01578 
01579     default:
01580       printf("other\n");
01581       break;    
01582   }
01583 
01584   nsEventStatus status = nsEventStatus_eIgnore;
01585   DispatchEvent ( &geckoEvent, status );
01586   
01587   *_retval = PR_TRUE;
01588 #endif
01589 
01590   return NS_OK;
01591 }
01592 
01593 #endif
01594 
01595 
01596 //-------------------------------------------------------------------------
01597 //
01598 // Invokes callback and  ProcessEvent method on Event Listener object
01599 //
01600 //-------------------------------------------------------------------------
01601 NS_IMETHODIMP 
01602 nsCocoaWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus& aStatus)
01603 {
01604   aStatus = nsEventStatus_eIgnore;
01605 
01606   nsIWidget* aWidget = event->widget;
01607   NS_IF_ADDREF(aWidget);
01608   
01609   if (nsnull != mMenuListener){
01610     if(NS_MENU_EVENT == event->eventStructType)
01611       aStatus = mMenuListener->MenuSelected( static_cast<nsMenuEvent&>(*event) );
01612   }
01613   if (mEventCallback)
01614     aStatus = (*mEventCallback)(event);
01615 
01616   // Dispatch to event listener if event was not consumed
01617   if ((aStatus != nsEventStatus_eConsumeNoDefault) && (mEventListener != nsnull))
01618     aStatus = mEventListener->ProcessEvent(*event);
01619 
01620   NS_IF_RELEASE(aWidget);
01621 
01622   return NS_OK;
01623 }
01624 
01625 
01626 void
01627 nsCocoaWindow::ReportSizeEvent()
01628 {
01629   // nsEvent
01630   nsSizeEvent sizeEvent(PR_TRUE, NS_SIZE, this);
01631   sizeEvent.time        = PR_IntervalNow();
01632 
01633   // nsSizeEvent
01634   sizeEvent.windowSize  = &mBounds;
01635   sizeEvent.mWinWidth   = mBounds.width;
01636   sizeEvent.mWinHeight  = mBounds.height;
01637   
01638   // dispatch event
01639   nsEventStatus status = nsEventStatus_eIgnore;
01640   DispatchEvent(&sizeEvent, status);
01641 }
01642 
01643 
01644 #if 0
01645 
01646 PRBool
01647 nsCocoaWindow::IsResizing ( ) const 
01648 { 
01649   return mIsResizing;
01650 }
01651 
01652 void StartResizing ( ) 
01653 { 
01654   mIsResizing = PR_TRUE;
01655 }
01656 
01657 void StopResizing ( ) 
01658 { 
01659   mIsResizing = PR_FALSE;
01660 }
01661 
01662 #endif
01663 
01664 
01665 #pragma mark -
01666 
01667 
01668 @implementation WindowDelegate
01669 
01670 
01671 - (id)initWithGeckoWindow:(nsCocoaWindow*)geckoWind
01672 {
01673   [super init];
01674   mGeckoWindow = geckoWind;
01675   return self;
01676 }
01677 
01678 - (void)windowDidResize:(NSNotification *)aNotification
01679 {
01680   if ( !mGeckoWindow->IsResizing() ) {
01681     // must remember to give Gecko top-left, not straight cocoa origin
01682     // and that Gecko already compensates for the title bar, so we have to
01683     // strip it out here.
01684     NSRect frameRect = [[aNotification object] frame];
01685     mGeckoWindow->Resize ( NS_STATIC_CAST(PRInt32,frameRect.size.width),
01686                             NS_STATIC_CAST(PRInt32,frameRect.size.height - nsCocoaWindow::kTitleBarHeight), PR_TRUE );
01687   }
01688 }
01689 
01690 
01691 - (void)windowDidBecomeMain:(NSNotification *)aNotification
01692 {
01693   //printf("got activation\n");
01694 }
01695 
01696 
01697 - (void)windowDidResignMain:(NSNotification *)aNotification
01698 {
01699   //printf("got deactivate\n");
01700 }
01701 
01702 
01703 - (void)windowDidBecomeKey:(NSNotification *)aNotification
01704 {
01705   //printf("we're key window\n");
01706 }
01707 
01708 
01709 - (void)windowDidResignKey:(NSNotification *)aNotification
01710 {
01711   //printf("we're not the key window\n");
01712 }
01713 
01714 
01715 - (void)windowDidMove:(NSNotification *)aNotification
01716 {
01717 }
01718 
01719 @end