Blender  V2.59
GHOST_WindowCocoa.mm
Go to the documentation of this file.
00001 
00030 #include <Cocoa/Cocoa.h>
00031 
00032 #ifndef MAC_OS_X_VERSION_10_6
00033 //Use of the SetSystemUIMode function (64bit compatible)
00034 #include <Carbon/Carbon.h>
00035 #endif
00036 
00037 #include <OpenGL/gl.h>
00038 /***** Multithreaded opengl code : uncomment for enabling
00039 #include <OpenGL/OpenGL.h>
00040 */
00041 
00042  
00043 #include "GHOST_WindowCocoa.h"
00044 #include "GHOST_SystemCocoa.h"
00045 #include "GHOST_Debug.h"
00046 
00047 
00048 #pragma mark Cocoa window delegate object
00049 /* live resize ugly patch
00050 extern "C" {
00051         struct bContext;
00052         typedef struct bContext bContext;
00053         bContext* ghostC;
00054         extern int wm_window_timer(const bContext *C);
00055         extern void wm_window_process_events(const bContext *C);
00056         extern void wm_event_do_handlers(bContext *C);
00057         extern void wm_event_do_notifiers(bContext *C);
00058         extern void wm_draw_update(bContext *C);
00059 };*/
00060 @interface CocoaWindowDelegate : NSObject
00061 #ifdef MAC_OS_X_VERSION_10_6
00062 <NSWindowDelegate>
00063 #endif
00064 {
00065         GHOST_SystemCocoa *systemCocoa;
00066         GHOST_WindowCocoa *associatedWindow;
00067 }
00068 
00069 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa;
00070 - (void)windowWillClose:(NSNotification *)notification;
00071 - (void)windowDidBecomeKey:(NSNotification *)notification;
00072 - (void)windowDidResignKey:(NSNotification *)notification;
00073 - (void)windowDidExpose:(NSNotification *)notification;
00074 - (void)windowDidResize:(NSNotification *)notification;
00075 - (void)windowDidMove:(NSNotification *)notification;
00076 - (void)windowWillMove:(NSNotification *)notification;
00077 @end
00078 
00079 @implementation CocoaWindowDelegate : NSObject
00080 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa
00081 {
00082         systemCocoa = sysCocoa;
00083         associatedWindow = winCocoa;
00084 }
00085 
00086 - (void)windowWillClose:(NSNotification *)notification
00087 {
00088         systemCocoa->handleWindowEvent(GHOST_kEventWindowClose, associatedWindow);
00089 }
00090 
00091 - (void)windowDidBecomeKey:(NSNotification *)notification
00092 {
00093         systemCocoa->handleWindowEvent(GHOST_kEventWindowActivate, associatedWindow);
00094 }
00095 
00096 - (void)windowDidResignKey:(NSNotification *)notification
00097 {
00098         systemCocoa->handleWindowEvent(GHOST_kEventWindowDeactivate, associatedWindow);
00099 }
00100 
00101 - (void)windowDidExpose:(NSNotification *)notification
00102 {
00103         systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow);
00104 }
00105 
00106 - (void)windowDidMove:(NSNotification *)notification
00107 {
00108         systemCocoa->handleWindowEvent(GHOST_kEventWindowMove, associatedWindow);
00109 }
00110 
00111 - (void)windowWillMove:(NSNotification *)notification
00112 {
00113         systemCocoa->handleWindowEvent(GHOST_kEventWindowMove, associatedWindow);
00114 }
00115 
00116 - (void)windowDidResize:(NSNotification *)notification
00117 {
00118 #ifdef MAC_OS_X_VERSION_10_6
00119         //if (![[notification object] inLiveResize]) {
00120                 //Send event only once, at end of resize operation (when user has released mouse button)
00121 #endif
00122                 systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, associatedWindow);
00123 #ifdef MAC_OS_X_VERSION_10_6
00124         //}
00125 #endif
00126         /* Live resize ugly patch. Needed because live resize runs in a modal loop, not letting main loop run
00127          if ([[notification object] inLiveResize]) {
00128                 systemCocoa->dispatchEvents();
00129                 wm_window_timer(ghostC);
00130                 wm_event_do_handlers(ghostC);
00131                 wm_event_do_notifiers(ghostC);
00132                 wm_draw_update(ghostC);
00133         }*/
00134 }
00135 @end
00136 
00137 #pragma mark NSWindow subclass
00138 //We need to subclass it to tell that even borderless (fullscreen), it can become key (receive user events)
00139 @interface CocoaWindow: NSWindow
00140 {
00141         GHOST_SystemCocoa *systemCocoa;
00142         GHOST_WindowCocoa *associatedWindow;
00143         GHOST_TDragnDropTypes m_draggedObjectType;
00144 }
00145 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa;
00146 - (GHOST_SystemCocoa*)systemCocoa;
00147 @end
00148 @implementation CocoaWindow
00149 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa
00150 {
00151         systemCocoa = sysCocoa;
00152         associatedWindow = winCocoa;
00153 }
00154 - (GHOST_SystemCocoa*)systemCocoa
00155 {
00156         return systemCocoa;
00157 }
00158 
00159 -(BOOL)canBecomeKeyWindow
00160 {
00161         return YES;
00162 }
00163 
00164 //The drag'n'drop dragging destination methods
00165 - (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender
00166 {
00167         NSPoint mouseLocation = [sender draggingLocation];
00168         NSPasteboard *draggingPBoard = [sender draggingPasteboard];
00169         
00170         if ([[draggingPBoard types] containsObject:NSTIFFPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeBitmap;
00171         else if ([[draggingPBoard types] containsObject:NSFilenamesPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeFilenames;
00172         else if ([[draggingPBoard types] containsObject:NSStringPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeString;
00173         else return NSDragOperationNone;
00174         
00175         associatedWindow->setAcceptDragOperation(TRUE); //Drag operation is accepted by default
00176         systemCocoa->handleDraggingEvent(GHOST_kEventDraggingEntered, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil);
00177         return NSDragOperationCopy;
00178 }
00179 
00180 - (BOOL)wantsPeriodicDraggingUpdates
00181 {
00182         return NO; //No need to overflow blender event queue. Events shall be sent only on changes
00183 }
00184 
00185 - (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
00186 {
00187         NSPoint mouseLocation = [sender draggingLocation];
00188         
00189         systemCocoa->handleDraggingEvent(GHOST_kEventDraggingUpdated, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil);
00190         return associatedWindow->canAcceptDragOperation()?NSDragOperationCopy:NSDragOperationNone;
00191 }
00192 
00193 - (void)draggingExited:(id < NSDraggingInfo >)sender
00194 {
00195         systemCocoa->handleDraggingEvent(GHOST_kEventDraggingExited, m_draggedObjectType, associatedWindow, 0, 0, nil);
00196         m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
00197 }
00198 
00199 - (BOOL)prepareForDragOperation:(id < NSDraggingInfo >)sender
00200 {
00201         if (associatedWindow->canAcceptDragOperation())
00202                 return YES;
00203         else
00204                 return NO;
00205 }
00206 
00207 - (BOOL)performDragOperation:(id < NSDraggingInfo >)sender
00208 {
00209         NSPoint mouseLocation = [sender draggingLocation];
00210         NSPasteboard *draggingPBoard = [sender draggingPasteboard];
00211         NSImage *droppedImg;
00212         id data;
00213         
00214         switch (m_draggedObjectType) {
00215                 case GHOST_kDragnDropTypeBitmap:
00216                         if([NSImage canInitWithPasteboard:draggingPBoard]) {
00217                                 droppedImg = [[NSImage alloc]initWithPasteboard:draggingPBoard];
00218                                 data = droppedImg; //[draggingPBoard dataForType:NSTIFFPboardType];
00219                         }
00220                         else return NO;
00221                         break;
00222                 case GHOST_kDragnDropTypeFilenames:
00223                         data = [draggingPBoard propertyListForType:NSFilenamesPboardType];
00224                         break;
00225                 case GHOST_kDragnDropTypeString:
00226                         data = [draggingPBoard stringForType:NSStringPboardType];
00227                         break;
00228                 default:
00229                         return NO;
00230                         break;
00231         }
00232         systemCocoa->handleDraggingEvent(GHOST_kEventDraggingDropDone, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, (void*)data);
00233         return YES;
00234 }
00235 
00236 @end
00237 
00238 
00239 
00240 #pragma mark NSOpenGLView subclass
00241 //We need to subclass it in order to give Cocoa the feeling key events are trapped
00242 @interface CocoaOpenGLView : NSOpenGLView
00243 {
00244         GHOST_SystemCocoa *systemCocoa;
00245         GHOST_WindowCocoa *associatedWindow;
00246 }
00247 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa;
00248 @end
00249 @implementation CocoaOpenGLView
00250 
00251 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa
00252 {
00253         systemCocoa = sysCocoa;
00254         associatedWindow = winCocoa;
00255 }
00256 
00257 - (BOOL)acceptsFirstResponder
00258 {
00259     return YES;
00260 }
00261 
00262 //The trick to prevent Cocoa from complaining (beeping)
00263 - (void)keyDown:(NSEvent *)theEvent
00264 {}
00265 
00266 #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
00267 //Cmd+key are handled differently before 10.5
00268 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
00269 {
00270         NSString *chars = [theEvent charactersIgnoringModifiers];
00271         
00272         if ([chars length] <1) 
00273                 return NO;
00274         
00275         //Let cocoa handle menu shortcuts
00276         switch ([chars characterAtIndex:0]) {
00277                 case 'q':
00278                 case 'w':
00279                 case 'h':
00280                 case 'm':
00281                 case '<':
00282                 case '>':
00283                 case '~':
00284                 case '`':
00285                         return NO;
00286                 default:
00287                         return YES;
00288         }
00289 }
00290 #endif
00291 
00292 - (BOOL)isOpaque
00293 {
00294     return YES;
00295 }
00296 
00297 - (void) drawRect:(NSRect)rect
00298 {
00299     if ([self inLiveResize])
00300     {
00301         //Don't redraw while in live resize
00302     }
00303     else
00304     {
00305         [super drawRect:rect];
00306         systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow);
00307     }
00308 }
00309 
00310 @end
00311 
00312 
00313 #pragma mark initialization / finalization
00314 
00315 NSOpenGLContext* GHOST_WindowCocoa::s_firstOpenGLcontext = nil;
00316 
00317 GHOST_WindowCocoa::GHOST_WindowCocoa(
00318         GHOST_SystemCocoa *systemCocoa,
00319         const STR_String& title,
00320         GHOST_TInt32 left,
00321         GHOST_TInt32 bottom,
00322         GHOST_TUns32 width,
00323         GHOST_TUns32 height,
00324         GHOST_TWindowState state,
00325         GHOST_TDrawingContextType type,
00326         const bool stereoVisual, const GHOST_TUns16 numOfAASamples
00327 ) :
00328         GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone, stereoVisual, numOfAASamples),
00329         m_customCursor(0)
00330 {
00331         NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[40];
00332         NSOpenGLPixelFormat *pixelFormat = nil;
00333         int i;
00334                 
00335         m_systemCocoa = systemCocoa;
00336         m_fullScreen = false;
00337         
00338         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00339         
00340         //Creates the window
00341         NSRect rect;
00342         NSSize  minSize;
00343         
00344         rect.origin.x = left;
00345         rect.origin.y = bottom;
00346         rect.size.width = width;
00347         rect.size.height = height;
00348         
00349         m_window = [[CocoaWindow alloc] initWithContentRect:rect
00350                                                                                    styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask
00351                                                                                          backing:NSBackingStoreBuffered defer:NO];
00352         if (m_window == nil) {
00353                 [pool drain];
00354                 return;
00355         }
00356         
00357         [m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
00358         
00359         //Forbid to resize the window below the blender defined minimum one
00360         minSize.width = 320;
00361         minSize.height = 240;
00362         [m_window setContentMinSize:minSize];
00363         
00364         setTitle(title);
00365         
00366         
00367         // Pixel Format Attributes for the windowed NSOpenGLContext
00368         i=0;
00369         pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer;
00370         
00371         // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object’s flushBuffer
00372         // needed for 'Draw Overlap' drawing method
00373         pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore; 
00374         
00375         pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated;
00376         //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,;   // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway
00377 
00378         pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize;
00379         pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32;
00380         
00381         
00382         if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo;
00383         
00384         if (numOfAASamples>0) {
00385                 // Multisample anti-aliasing
00386                 pixelFormatAttrsWindow[i++] = NSOpenGLPFAMultisample;
00387                 
00388                 pixelFormatAttrsWindow[i++] = NSOpenGLPFASampleBuffers;
00389                 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 1;
00390                 
00391                 pixelFormatAttrsWindow[i++] = NSOpenGLPFASamples;
00392                 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) numOfAASamples;
00393                 
00394                 pixelFormatAttrsWindow[i++] = NSOpenGLPFANoRecovery;
00395         }
00396         
00397         pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0;
00398         
00399         pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow];
00400         
00401         
00402         //Fall back to no multisampling if Antialiasing init failed
00403         if (pixelFormat == nil) {
00404                 i=0;
00405                 pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer;
00406                 
00407                 // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object’s flushBuffer
00408                 // needed for 'Draw Overlap' drawing method
00409                 pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore;
00410                 
00411                 pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated;
00412                 //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,;   // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway
00413                 
00414                 pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize;
00415                 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32;
00416                 
00417                 if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo;
00418                 
00419                 pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0;
00420                 
00421                 pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow];
00422                 
00423         }
00424         
00425         if (numOfAASamples>0) { //Set m_numOfAASamples to the actual value
00426                 GLint gli;
00427                 [pixelFormat getValues:&gli forAttribute:NSOpenGLPFASamples forVirtualScreen:0];
00428                 if (m_numOfAASamples != (GHOST_TUns16)gli) {
00429                         m_numOfAASamples = (GHOST_TUns16)gli;
00430                         printf("GHOST_Window could be created with anti-aliasing of only %i samples\n",m_numOfAASamples);
00431                 }
00432         }
00433                 
00434         //Creates the OpenGL View inside the window
00435         m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect
00436                                                                                                  pixelFormat:pixelFormat];
00437 
00438         [m_openGLView setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
00439         
00440         [pixelFormat release];
00441         
00442         m_openGLContext = [m_openGLView openGLContext]; //This context will be replaced by the proper one just after
00443         
00444         [m_window setContentView:m_openGLView];
00445         [m_window setInitialFirstResponder:m_openGLView];
00446         
00447         [m_window setReleasedWhenClosed:NO]; //To avoid bad pointer exception in case of user closing the window
00448         
00449         [m_window makeKeyAndOrderFront:nil];
00450         
00451         setDrawingContextType(type);
00452         updateDrawingContext();
00453         activateDrawingContext();
00454         
00455         m_tablet.Active = GHOST_kTabletModeNone;
00456         
00457         CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init];
00458         [windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
00459         [m_window setDelegate:windowDelegate];
00460         
00461         [m_window setAcceptsMouseMovedEvents:YES];
00462         
00463         [m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
00464                                                                                   NSStringPboardType, NSTIFFPboardType, nil]];
00465                                                                                   
00466         if (state == GHOST_kWindowStateFullScreen)
00467                 setState(GHOST_kWindowStateFullScreen);
00468                 
00469         [pool drain];
00470 }
00471 
00472 
00473 GHOST_WindowCocoa::~GHOST_WindowCocoa()
00474 {
00475     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00476 
00477         if (m_customCursor) {
00478                 [m_customCursor release];
00479                 m_customCursor = nil;
00480         }
00481 
00482         [m_openGLView release];
00483         
00484         if (m_window) {
00485                 [m_window close];
00486                 [[m_window delegate] release];
00487                 [m_window release];
00488                 m_window = nil;
00489         }
00490         
00491         //Check for other blender opened windows and make the frontmost key
00492         NSArray *windowsList = [NSApp orderedWindows];
00493         if ([windowsList count]) {
00494                 [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
00495         }
00496         [pool drain];
00497 }
00498 
00499 #pragma mark accessors
00500 
00501 bool GHOST_WindowCocoa::getValid() const
00502 {
00503         return (m_window != 0);
00504 }
00505 
00506 void* GHOST_WindowCocoa::getOSWindow() const
00507 {
00508         return (void*)m_window;
00509 }
00510 
00511 void GHOST_WindowCocoa::setTitle(const STR_String& title)
00512 {
00513     GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid")
00514         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00515 
00516         NSString *windowTitle = [[NSString alloc] initWithCString:title encoding:NSUTF8StringEncoding];
00517         
00518         //Set associated file if applicable
00519         if (windowTitle && [windowTitle hasPrefix:@"Blender"])
00520         {
00521                 NSRange fileStrRange;
00522                 NSString *associatedFileName;
00523                 int len;
00524                 
00525                 fileStrRange.location = [windowTitle rangeOfString:@"["].location+1;
00526                 len = [windowTitle rangeOfString:@"]"].location - fileStrRange.location;
00527         
00528                 if (len >0)
00529                 {
00530                         fileStrRange.length = len;
00531                         associatedFileName = [windowTitle substringWithRange:fileStrRange];
00532                         [m_window setTitle:[associatedFileName lastPathComponent]];
00533 
00534                         //Blender used file open/save functions converte file names into legal URL ones
00535                         associatedFileName = [associatedFileName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
00536                         @try {
00537                                 [m_window setRepresentedFilename:associatedFileName];
00538                         }
00539                         @catch (NSException * e) {
00540                                 printf("\nInvalid file path given in window title");
00541                         }
00542                 }
00543                 else {
00544                         [m_window setTitle:windowTitle];
00545                         [m_window setRepresentedFilename:@""];
00546                 }
00547 
00548         } else {
00549                 [m_window setTitle:windowTitle];
00550                 [m_window setRepresentedFilename:@""];
00551         }
00552 
00553         
00554         [windowTitle release];
00555         [pool drain];
00556 }
00557 
00558 
00559 void GHOST_WindowCocoa::getTitle(STR_String& title) const
00560 {
00561     GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid")
00562 
00563         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00564 
00565         NSString *windowTitle = [m_window title];
00566 
00567         if (windowTitle != nil) {
00568                 title = [windowTitle UTF8String];               
00569         }
00570         
00571         [pool drain];
00572 }
00573 
00574 
00575 void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect& bounds) const
00576 {
00577         NSRect rect;
00578         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid")
00579 
00580         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00581         
00582         NSRect screenSize = [[m_window screen] visibleFrame];
00583 
00584         rect = [m_window frame];
00585 
00586         bounds.m_b = screenSize.size.height - (rect.origin.y -screenSize.origin.y);
00587         bounds.m_l = rect.origin.x -screenSize.origin.x;
00588         bounds.m_r = rect.origin.x-screenSize.origin.x + rect.size.width;
00589         bounds.m_t = screenSize.size.height - (rect.origin.y + rect.size.height -screenSize.origin.y);
00590         
00591         [pool drain];
00592 }
00593 
00594 
00595 void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const
00596 {
00597         NSRect rect;
00598         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid")
00599         
00600         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00601         
00602         if (!m_fullScreen)
00603         {
00604                 NSRect screenSize = [[m_window screen] visibleFrame];
00605 
00606                 //Max window contents as screen size (excluding title bar...)
00607                 NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize
00608                                                                                                          styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)];
00609 
00610                 rect = [m_window contentRectForFrameRect:[m_window frame]];
00611                 
00612                 bounds.m_b = contentRect.size.height - (rect.origin.y -contentRect.origin.y);
00613                 bounds.m_l = rect.origin.x -contentRect.origin.x;
00614                 bounds.m_r = rect.origin.x-contentRect.origin.x + rect.size.width;
00615                 bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height -contentRect.origin.y);
00616         }
00617         else {
00618                 NSRect screenSize = [[m_window screen] frame];
00619                 
00620                 bounds.m_b = screenSize.origin.y + screenSize.size.height;
00621                 bounds.m_l = screenSize.origin.x;
00622                 bounds.m_r = screenSize.origin.x + screenSize.size.width;
00623                 bounds.m_t = screenSize.origin.y;
00624         }
00625         [pool drain];
00626 }
00627 
00628 
00629 GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width)
00630 {
00631         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientWidth(): window invalid")
00632         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00633         GHOST_Rect cBnds, wBnds;
00634         getClientBounds(cBnds);
00635         if (((GHOST_TUns32)cBnds.getWidth()) != width) {
00636                 NSSize size;
00637                 size.width=width;
00638                 size.height=cBnds.getHeight();
00639                 [m_window setContentSize:size];
00640         }
00641         [pool drain];
00642         return GHOST_kSuccess;
00643 }
00644 
00645 
00646 GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height)
00647 {
00648         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid")
00649         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00650         GHOST_Rect cBnds, wBnds;
00651         getClientBounds(cBnds);
00652         if (((GHOST_TUns32)cBnds.getHeight()) != height) {
00653                 NSSize size;
00654                 size.width=cBnds.getWidth();
00655                 size.height=height;
00656                 [m_window setContentSize:size];
00657         }
00658         [pool drain];
00659         return GHOST_kSuccess;
00660 }
00661 
00662 
00663 GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
00664 {
00665         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid")
00666         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00667         GHOST_Rect cBnds, wBnds;
00668         getClientBounds(cBnds);
00669         if ((((GHOST_TUns32)cBnds.getWidth()) != width) ||
00670             (((GHOST_TUns32)cBnds.getHeight()) != height)) {
00671                 NSSize size;
00672                 size.width=width;
00673                 size.height=height;
00674                 [m_window setContentSize:size];
00675         }
00676         [pool drain];
00677         return GHOST_kSuccess;
00678 }
00679 
00680 
00681 GHOST_TWindowState GHOST_WindowCocoa::getState() const
00682 {
00683         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid")
00684         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00685         GHOST_TWindowState state;
00686         if (m_fullScreen) {
00687                 state = GHOST_kWindowStateFullScreen;
00688         } 
00689         else if ([m_window isMiniaturized]) {
00690                 state = GHOST_kWindowStateMinimized;
00691         }
00692         else if ([m_window isZoomed]) {
00693                 state = GHOST_kWindowStateMaximized;
00694         }
00695         else {
00696                 state = GHOST_kWindowStateNormal;
00697         }
00698         [pool drain];
00699         return state;
00700 }
00701 
00702 
00703 void GHOST_WindowCocoa::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
00704 {
00705         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::screenToClient(): window invalid")
00706 
00707         screenToClientIntern(inX, inY, outX, outY);
00708 
00709         /* switch y to match ghost convention */
00710         GHOST_Rect cBnds;
00711         getClientBounds(cBnds);
00712         outY = (cBnds.getHeight() - 1) - outY;
00713 }
00714 
00715 
00716 void GHOST_WindowCocoa::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
00717 {
00718         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::clientToScreen(): window invalid")
00719 
00720         /* switch y to match ghost convention */
00721         GHOST_Rect cBnds;
00722         getClientBounds(cBnds);
00723         inY = (cBnds.getHeight() - 1) - inY;
00724 
00725         clientToScreenIntern(inX, inY, outX, outY);
00726 }
00727 
00728 void GHOST_WindowCocoa::screenToClientIntern(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
00729 {
00730         NSPoint screenCoord;
00731         NSPoint baseCoord;
00732         
00733         screenCoord.x = inX;
00734         screenCoord.y = inY;
00735         
00736         baseCoord = [m_window convertScreenToBase:screenCoord];
00737         
00738         outX = baseCoord.x;
00739         outY = baseCoord.y;
00740 }
00741 
00742 void GHOST_WindowCocoa::clientToScreenIntern(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
00743 {
00744         NSPoint screenCoord;
00745         NSPoint baseCoord;
00746         
00747         baseCoord.x = inX;
00748         baseCoord.y = inY;
00749         
00750         screenCoord = [m_window convertBaseToScreen:baseCoord];
00751         
00752         outX = screenCoord.x;
00753         outY = screenCoord.y;
00754 }
00755 
00756 
00757 NSScreen* GHOST_WindowCocoa::getScreen()
00758 {
00759         return [m_window screen];
00760 }
00761 
00762 
00768 GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
00769 {
00770         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid")
00771     switch (state) {
00772                 case GHOST_kWindowStateMinimized:
00773             [m_window miniaturize:nil];
00774             break;
00775                 case GHOST_kWindowStateMaximized:
00776                         [m_window zoom:nil];
00777                         break;
00778                 
00779                 case GHOST_kWindowStateFullScreen:
00780                         if (!m_fullScreen)
00781                         {
00782                                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00783                         
00784                                 //This status change needs to be done before Cocoa call to enter fullscreen mode
00785                                 //to give window delegate hint not to forward its deactivation to ghost wm that doesn't know view/window difference
00786                                 m_fullScreen = true;
00787 
00788 #ifdef MAC_OS_X_VERSION_10_6
00789                                 //10.6 provides Cocoa functions to autoshow menu bar, and to change a window style
00790                                 //Hide menu & dock if needed
00791                                 if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]])
00792                                 {
00793                                         [NSApp setPresentationOptions:(NSApplicationPresentationHideDock | NSApplicationPresentationAutoHideMenuBar)];
00794                                 }
00795                                 //Make window borderless and enlarge it
00796                                 [m_window setStyleMask:NSBorderlessWindowMask];
00797                                 [m_window setFrame:[[m_window screen] frame] display:YES];
00798                                 [m_window makeFirstResponder:m_openGLView];
00799 #else
00800                                 //With 10.5, we need to create a new window to change its style to borderless
00801                                 //Hide menu & dock if needed
00802                                 if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]])
00803                                 {
00804                                         //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:NO];
00805                                         //One of the very few 64bit compatible Carbon function
00806                                         SetSystemUIMode(kUIModeAllHidden,kUIOptionAutoShowMenuBar);
00807                                 }
00808                                 //Create a fullscreen borderless window
00809                                 CocoaWindow *tmpWindow = [[CocoaWindow alloc]
00810                                                                                   initWithContentRect:[[m_window screen] frame]
00811                                                                                   styleMask:NSBorderlessWindowMask
00812                                                                                   backing:NSBackingStoreBuffered
00813                                                                                   defer:YES];
00814                                 //Copy current window parameters
00815                                 [tmpWindow setTitle:[m_window title]];
00816                                 [tmpWindow setRepresentedFilename:[m_window representedFilename]];
00817                                 [tmpWindow setReleasedWhenClosed:NO];
00818                                 [tmpWindow setAcceptsMouseMovedEvents:YES];
00819                                 [tmpWindow setDelegate:[m_window delegate]];
00820                                 [tmpWindow setSystemAndWindowCocoa:[m_window systemCocoa] windowCocoa:this];
00821                                 [tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
00822                                                                                                    NSStringPboardType, NSTIFFPboardType, nil]];
00823                                 
00824                                 //Assign the openGL view to the new window
00825                                 [tmpWindow setContentView:m_openGLView];
00826                                 
00827                                 //Show the new window
00828                                 [tmpWindow makeKeyAndOrderFront:m_openGLView];
00829                                 //Close and release old window
00830                                 [m_window setDelegate:nil]; // To avoid the notification of "window closed" event
00831                                 [m_window close];
00832                                 [m_window release];
00833                                 m_window = tmpWindow;
00834 #endif
00835                         
00836                                 //Tell WM of view new size
00837                                 m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this);
00838                                 
00839                                 [pool drain];
00840                                 }
00841                         break;
00842                 case GHOST_kWindowStateNormal:
00843         default:
00844                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00845                         if (m_fullScreen)
00846                         {
00847                                 m_fullScreen = false;
00848 
00849                                 //Exit fullscreen
00850 #ifdef MAC_OS_X_VERSION_10_6
00851                                 //Show again menu & dock if needed
00852                                 if ([[m_window screen] isEqual:[NSScreen mainScreen]])
00853                                 {
00854                                         [NSApp setPresentationOptions:NSApplicationPresentationDefault];
00855                                 }
00856                                 //Make window normal and resize it
00857                                 [m_window setStyleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)];
00858                                 [m_window setFrame:[[m_window screen] visibleFrame] display:YES];
00859                                 //TODO for 10.6 only : window title is forgotten after the style change
00860                                 [m_window makeFirstResponder:m_openGLView];
00861 #else
00862                                 //With 10.5, we need to create a new window to change its style to borderless
00863                                 //Show menu & dock if needed
00864                                 if ([[m_window screen] isEqual:[NSScreen mainScreen]])
00865                                 {
00866                                         //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:YES];
00867                                         SetSystemUIMode(kUIModeNormal, 0); //One of the very few 64bit compatible Carbon function
00868                                 }
00869                                 //Create a fullscreen borderless window
00870                                 CocoaWindow *tmpWindow = [[CocoaWindow alloc]
00871                                                                                   initWithContentRect:[[m_window screen] frame]
00872                                                                                                         styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)
00873                                                                                                           backing:NSBackingStoreBuffered
00874                                                                                                                 defer:YES];
00875                                 //Copy current window parameters
00876                                 [tmpWindow setTitle:[m_window title]];
00877                                 [tmpWindow setRepresentedFilename:[m_window representedFilename]];
00878                                 [tmpWindow setReleasedWhenClosed:NO];
00879                                 [tmpWindow setAcceptsMouseMovedEvents:YES];
00880                                 [tmpWindow setDelegate:[m_window delegate]];
00881                                 [tmpWindow setSystemAndWindowCocoa:[m_window systemCocoa] windowCocoa:this];
00882                                 [tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
00883                                                                                                    NSStringPboardType, NSTIFFPboardType, nil]];
00884                                 //Forbid to resize the window below the blender defined minimum one
00885                                 [tmpWindow setContentMinSize:NSMakeSize(320, 240)];
00886                                 
00887                                 //Assign the openGL view to the new window
00888                                 [tmpWindow setContentView:m_openGLView];
00889                                 
00890                                 //Show the new window
00891                                 [tmpWindow makeKeyAndOrderFront:nil];
00892                                 //Close and release old window
00893                                 [m_window setDelegate:nil]; // To avoid the notification of "window closed" event
00894                                 [m_window close];
00895                                 [m_window release];
00896                                 m_window = tmpWindow;
00897 #endif
00898                         
00899                                 //Tell WM of view new size
00900                                 m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this);
00901                         }
00902             else if ([m_window isMiniaturized])
00903                                 [m_window deminiaturize:nil];
00904                         else if ([m_window isZoomed])
00905                                 [m_window zoom:nil];
00906                         [pool drain];
00907             break;
00908     }
00909 
00910     return GHOST_kSuccess;
00911 }
00912 
00913 GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges)
00914 {
00915         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00916         
00917         [m_window setDocumentEdited:isUnsavedChanges];
00918         
00919         [pool drain];
00920         return GHOST_Window::setModifiedState(isUnsavedChanges);
00921 }
00922 
00923 
00924 
00925 GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
00926 {
00927         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00928         
00929         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid")
00930     if (order == GHOST_kWindowOrderTop) {
00931                 [m_window makeKeyAndOrderFront:nil];
00932     }
00933     else {
00934                 NSArray *windowsList;
00935                 
00936                 [m_window orderBack:nil];
00937                 
00938                 //Check for other blender opened windows and make the frontmost key
00939                 windowsList = [NSApp orderedWindows];
00940                 if ([windowsList count]) {
00941                         [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
00942                 }
00943     }
00944         
00945         [pool drain];
00946     return GHOST_kSuccess;
00947 }
00948 
00949 #pragma mark Drawing context
00950 
00951 /*#define  WAIT_FOR_VSYNC 1*/
00952 
00953 GHOST_TSuccess GHOST_WindowCocoa::swapBuffers()
00954 {
00955     if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
00956         if (m_openGLContext != nil) {
00957                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00958                         [m_openGLContext flushBuffer];
00959                         [pool drain];
00960             return GHOST_kSuccess;
00961         }
00962     }
00963     return GHOST_kFailure;
00964 }
00965 
00966 GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext()
00967 {
00968         if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
00969                 if (m_openGLContext != nil) {
00970                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00971                         [m_openGLContext update];
00972                         [pool drain];
00973                         return GHOST_kSuccess;
00974                 }
00975         }
00976         return GHOST_kFailure;
00977 }
00978 
00979 GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext()
00980 {
00981         if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
00982                 if (m_openGLContext != nil) {
00983                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00984                         [m_openGLContext makeCurrentContext];
00985                         
00986                         // Disable AA by default
00987                         if (m_numOfAASamples > 0) glDisable(GL_MULTISAMPLE_ARB);
00988                         [pool drain];
00989                         return GHOST_kSuccess;
00990                 }
00991         }
00992         return GHOST_kFailure;
00993 }
00994 
00995 
00996 GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextType type)
00997 {
00998         GHOST_TSuccess success = GHOST_kFailure;
00999         
01000         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
01001         
01002         NSOpenGLPixelFormat *pixelFormat;
01003         NSOpenGLContext *tmpOpenGLContext;
01004         
01005         /***** Multithreaded opengl code : uncomment for enabling
01006         CGLContextObj cglCtx;
01007         */
01008          
01009         switch (type) {
01010                 case GHOST_kDrawingContextTypeOpenGL:
01011                         if (!getValid()) break;
01012                                         
01013                         pixelFormat = [m_openGLView pixelFormat];
01014                         tmpOpenGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
01015                                                                                                                           shareContext:s_firstOpenGLcontext];
01016                         if (tmpOpenGLContext == nil) {
01017                                 success = GHOST_kFailure;
01018                                 break;
01019                         }
01020                         
01021                         //Switch openGL to multhreaded mode
01022                         /******* Multithreaded opengl code : uncomment for enabling
01023                         cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj];
01024                         if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError)
01025                                 printf("\nSwitched openGL to multithreaded mode");
01026                          */
01027                         
01028                         if (!s_firstOpenGLcontext) s_firstOpenGLcontext = tmpOpenGLContext;
01029 #ifdef WAIT_FOR_VSYNC
01030                         {
01031                                 GLint swapInt = 1;
01032                                 /* wait for vsync, to avoid tearing artifacts */
01033                                 [tmpOpenGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
01034                         }
01035 #endif
01036                         [m_openGLView setOpenGLContext:tmpOpenGLContext];
01037                         [tmpOpenGLContext setView:m_openGLView];
01038                         
01039                         m_openGLContext = tmpOpenGLContext;
01040                         break;
01041         
01042                 case GHOST_kDrawingContextTypeNone:
01043                         success = GHOST_kSuccess;
01044                         break;
01045                 
01046                 default:
01047                         break;
01048         }
01049         [pool drain];
01050         return success;
01051 }
01052 
01053 
01054 GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext()
01055 {
01056         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
01057         switch (m_drawingContextType) {
01058                 case GHOST_kDrawingContextTypeOpenGL:
01059                         if (m_openGLContext)
01060                         {
01061                                 [m_openGLView clearGLContext];
01062                                 if (s_firstOpenGLcontext == m_openGLContext) s_firstOpenGLcontext = nil;
01063                                 m_openGLContext = nil;
01064                         }
01065                         [pool drain];
01066                         return GHOST_kSuccess;
01067                 case GHOST_kDrawingContextTypeNone:
01068                         [pool drain];
01069                         return GHOST_kSuccess;
01070                         break;
01071                 default:
01072                         [pool drain];
01073                         return GHOST_kFailure;
01074         }
01075 }
01076 
01077 
01078 GHOST_TSuccess GHOST_WindowCocoa::invalidate()
01079 {
01080         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid")
01081         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
01082         [m_openGLView setNeedsDisplay:YES];
01083         [pool drain];
01084         return GHOST_kSuccess;
01085 }
01086 
01087 #pragma mark Progress bar
01088 
01089 GHOST_TSuccess GHOST_WindowCocoa::setProgressBar(float progress)
01090 {
01091         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
01092         
01093         if ((progress >=0.0) && (progress <=1.0)) {
01094                 NSImage* dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128,128)];
01095                 
01096                 [dockIcon lockFocus];
01097         NSRect progressBox = {{4, 4}, {120, 16}};
01098 
01099         [[NSImage imageNamed:@"NSApplicationIcon"] dissolveToPoint:NSZeroPoint fraction:1.0];
01100         
01101         // Track & Outline
01102         [[NSColor blackColor] setFill];
01103         NSRectFill(progressBox);
01104         
01105         [[NSColor whiteColor] set];
01106         NSFrameRect(progressBox);
01107         
01108         // Progress fill
01109         progressBox = NSInsetRect(progressBox, 1, 1);
01110         [[NSColor knobColor] setFill];
01111         progressBox.size.width = progressBox.size.width * progress;
01112                 NSRectFill(progressBox);
01113                 
01114                 [dockIcon unlockFocus];
01115                 
01116                 [NSApp setApplicationIconImage:dockIcon];
01117                 [dockIcon release];
01118                 
01119                 m_progressBarVisible = true;
01120         }
01121         
01122         [pool drain];
01123         return GHOST_kSuccess;
01124 }
01125 
01126 
01127 GHOST_TSuccess GHOST_WindowCocoa::endProgressBar()
01128 {
01129         if (!m_progressBarVisible) return GHOST_kFailure;
01130         m_progressBarVisible = false;
01131         
01132         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
01133         
01134         NSImage* dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128,128)];
01135         [dockIcon lockFocus];
01136         [[NSImage imageNamed:@"NSApplicationIcon"] dissolveToPoint:NSZeroPoint fraction:1.0];
01137         [dockIcon unlockFocus];
01138         [NSApp setApplicationIconImage:dockIcon];
01139         [dockIcon release];
01140         
01141         [pool drain];
01142         return GHOST_kSuccess;
01143 }
01144 
01145 
01146 
01147 #pragma mark Cursor handling
01148 
01149 void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
01150 {
01151         static bool systemCursorVisible = true;
01152         
01153         NSCursor *tmpCursor =nil;
01154         
01155         if (visible != systemCursorVisible) {
01156                 if (visible) {
01157                         [NSCursor unhide];
01158                         systemCursorVisible = true;
01159                 }
01160                 else {
01161                         [NSCursor hide];
01162                         systemCursorVisible = false;
01163                 }
01164         }
01165 
01166         if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
01167                 tmpCursor = m_customCursor;
01168         } else {
01169                 switch (cursor) {
01170                         case GHOST_kStandardCursorDestroy:
01171                                 tmpCursor = [NSCursor disappearingItemCursor];
01172                                 break;
01173                         case GHOST_kStandardCursorText:
01174                                 tmpCursor = [NSCursor IBeamCursor];
01175                                 break;
01176                         case GHOST_kStandardCursorCrosshair:
01177                                 tmpCursor = [NSCursor crosshairCursor];
01178                                 break;
01179                         case GHOST_kStandardCursorUpDown:
01180                                 tmpCursor = [NSCursor resizeUpDownCursor];
01181                                 break;
01182                         case GHOST_kStandardCursorLeftRight:
01183                                 tmpCursor = [NSCursor resizeLeftRightCursor];
01184                                 break;
01185                         case GHOST_kStandardCursorTopSide:
01186                                 tmpCursor = [NSCursor resizeUpCursor];
01187                                 break;
01188                         case GHOST_kStandardCursorBottomSide:
01189                                 tmpCursor = [NSCursor resizeDownCursor];
01190                                 break;
01191                         case GHOST_kStandardCursorLeftSide:
01192                                 tmpCursor = [NSCursor resizeLeftCursor];
01193                                 break;
01194                         case GHOST_kStandardCursorRightSide:
01195                                 tmpCursor = [NSCursor resizeRightCursor];
01196                                 break;
01197                         case GHOST_kStandardCursorRightArrow:
01198                         case GHOST_kStandardCursorInfo:
01199                         case GHOST_kStandardCursorLeftArrow:
01200                         case GHOST_kStandardCursorHelp:
01201                         case GHOST_kStandardCursorCycle:
01202                         case GHOST_kStandardCursorSpray:
01203                         case GHOST_kStandardCursorWait:
01204                         case GHOST_kStandardCursorTopLeftCorner:
01205                         case GHOST_kStandardCursorTopRightCorner:
01206                         case GHOST_kStandardCursorBottomRightCorner:
01207                         case GHOST_kStandardCursorBottomLeftCorner:
01208                         case GHOST_kStandardCursorCopy:
01209                         case GHOST_kStandardCursorDefault:
01210                         default:
01211                                 tmpCursor = [NSCursor arrowCursor];
01212                                 break;
01213                 };
01214         }
01215         [tmpCursor set];
01216 }
01217 
01218 
01219 
01220 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible)
01221 {
01222         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
01223         
01224         if ([m_window isVisible]) {
01225                 loadCursor(visible, getCursorShape());
01226         }
01227         
01228         [pool drain];
01229         return GHOST_kSuccess;
01230 }
01231 
01232 
01233 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
01234 {
01235         GHOST_TSuccess err = GHOST_kSuccess;
01236         
01237         if (mode != GHOST_kGrabDisable)
01238         {
01239                 //No need to perform grab without warp as it is always on in OS X
01240                 if(mode != GHOST_kGrabNormal) {
01241                         GHOST_TInt32 x_old,y_old;
01242                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
01243 
01244                         m_systemCocoa->getCursorPosition(x_old,y_old);
01245                         screenToClientIntern(x_old, y_old, m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
01246                         //Warp position is stored in client (window base) coordinates
01247                         setCursorGrabAccum(0, 0);
01248                         
01249                         if(mode == GHOST_kGrabHide) {
01250                                 setWindowCursorVisibility(false);
01251                         }
01252                         
01253                         //Make window key if it wasn't to get the mouse move events
01254                         [m_window makeKeyWindow];
01255                         
01256                         //Dissociate cursor position even for warp mode, to allow mouse acceleration to work even when warping the cursor
01257                         err = CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
01258                         
01259                         [pool drain];
01260                 }
01261         }
01262         else {
01263                 if(m_cursorGrab==GHOST_kGrabHide)
01264                 {
01265                         //No need to set again cursor position, as it has not changed for Cocoa
01266                         setWindowCursorVisibility(true);
01267                 }
01268                 
01269                 err = CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
01270                 /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
01271                 setCursorGrabAccum(0, 0);
01272                 m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */
01273         }
01274         return err;
01275 }
01276         
01277 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape)
01278 {
01279         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
01280 
01281         if (m_customCursor) {
01282                 [m_customCursor release];
01283                 m_customCursor = nil;
01284         }
01285 
01286         if ([m_window isVisible]) {
01287                 loadCursor(getCursorVisibility(), shape);
01288         }
01289         
01290         [pool drain];
01291         return GHOST_kSuccess;
01292 }
01293 
01306 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
01307 {
01308         shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA);
01309         shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC);
01310         shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0);
01311         shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00);
01312         return shrt;
01313 }
01314 
01315 GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
01316                                         int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color)
01317 {
01318         int y,nbUns16;
01319         NSPoint hotSpotPoint;
01320         NSBitmapImageRep *cursorImageRep;
01321         NSImage *cursorImage;
01322         NSSize imSize;
01323         GHOST_TUns16 *cursorBitmap;
01324         
01325         
01326         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
01327         
01328         if (m_customCursor) {
01329                 [m_customCursor release];
01330                 m_customCursor = nil;
01331         }
01332         
01333 
01334         cursorImageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
01335                                                                                                                          pixelsWide:sizex
01336                                                                                                                          pixelsHigh:sizey
01337                                                                                                                   bitsPerSample:1 
01338                                                                                                                 samplesPerPixel:2
01339                                                                                                                            hasAlpha:YES
01340                                                                                                                            isPlanar:YES
01341                                                                                                                  colorSpaceName:NSDeviceWhiteColorSpace
01342                                                                                                                         bytesPerRow:(sizex/8 + (sizex%8 >0 ?1:0))
01343                                                                                                                    bitsPerPixel:1];
01344         
01345         
01346         cursorBitmap = (GHOST_TUns16*)[cursorImageRep bitmapData];
01347         nbUns16 = [cursorImageRep bytesPerPlane]/2;
01348         
01349         for (y=0; y<nbUns16; y++) {
01350 #if !defined(__LITTLE_ENDIAN__)
01351                 cursorBitmap[y] = ~uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8));
01352                 cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8));
01353 #else
01354                 cursorBitmap[y] = ~uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8));
01355                 cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8));
01356 #endif
01357                 
01358         }
01359         
01360         
01361         imSize.width = sizex;
01362         imSize.height= sizey;
01363         cursorImage = [[NSImage alloc] initWithSize:imSize];
01364         [cursorImage addRepresentation:cursorImageRep];
01365         
01366         hotSpotPoint.x = hotX;
01367         hotSpotPoint.y = hotY;
01368         
01369         //foreground and background color parameter is not handled for now (10.6)
01370         m_customCursor = [[NSCursor alloc] initWithImage:cursorImage
01371                                                                                          hotSpot:hotSpotPoint];
01372         
01373         [cursorImageRep release];
01374         [cursorImage release];
01375         
01376         if ([m_window isVisible]) {
01377                 loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
01378         }
01379         [pool drain];
01380         return GHOST_kSuccess;
01381 }
01382 
01383 GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], 
01384                                                                                                 GHOST_TUns8 mask[16][2], int hotX, int hotY)
01385 {
01386         return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1);
01387 }