copy of docs from 2.4x for python modules that have been kept
[blender-staging.git] / intern / ghost / intern / GHOST_WindowCocoa.mm
1 /**
2  * $Id$
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s):      Maarten Gribnau 05/2001
25                                         Damien Plisson 10/2009
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <Cocoa/Cocoa.h>
31
32 #ifndef MAC_OS_X_VERSION_10_6
33 //Use of the SetSystemUIMode function (64bit compatible)
34 #include <Carbon/Carbon.h>
35 #endif
36
37 #include <OpenGL/gl.h>
38 /***** Multithreaded opengl code : uncomment for enabling
39 #include <OpenGL/OpenGL.h>
40 */
41
42  
43 #include "GHOST_WindowCocoa.h"
44 #include "GHOST_SystemCocoa.h"
45 #include "GHOST_Debug.h"
46
47
48 #pragma mark Cocoa window delegate object
49 /* live resize ugly patch
50 extern "C" {
51         struct bContext;
52         typedef struct bContext bContext;
53         bContext* ghostC;
54         extern int wm_window_timer(const bContext *C);
55         extern void wm_window_process_events(const bContext *C);
56         extern void wm_event_do_handlers(bContext *C);
57         extern void wm_event_do_notifiers(bContext *C);
58         extern void wm_draw_update(bContext *C);
59 };*/
60 @interface CocoaWindowDelegate : NSObject
61 #ifdef MAC_OS_X_VERSION_10_6
62 <NSWindowDelegate>
63 #endif
64 {
65         GHOST_SystemCocoa *systemCocoa;
66         GHOST_WindowCocoa *associatedWindow;
67 }
68
69 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa;
70 - (void)windowWillClose:(NSNotification *)notification;
71 - (void)windowDidBecomeKey:(NSNotification *)notification;
72 - (void)windowDidResignKey:(NSNotification *)notification;
73 - (void)windowDidExpose:(NSNotification *)notification;
74 - (void)windowDidResize:(NSNotification *)notification;
75 @end
76
77 @implementation CocoaWindowDelegate : NSObject
78 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa
79 {
80         systemCocoa = sysCocoa;
81         associatedWindow = winCocoa;
82 }
83
84 - (void)windowWillClose:(NSNotification *)notification
85 {
86         systemCocoa->handleWindowEvent(GHOST_kEventWindowClose, associatedWindow);
87 }
88
89 - (void)windowDidBecomeKey:(NSNotification *)notification
90 {
91         systemCocoa->handleWindowEvent(GHOST_kEventWindowActivate, associatedWindow);
92 }
93
94 - (void)windowDidResignKey:(NSNotification *)notification
95 {
96         systemCocoa->handleWindowEvent(GHOST_kEventWindowDeactivate, associatedWindow);
97 }
98
99 - (void)windowDidExpose:(NSNotification *)notification
100 {
101         systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow);
102 }
103
104 - (void)windowDidResize:(NSNotification *)notification
105 {
106 #ifdef MAC_OS_X_VERSION_10_6
107         //if (![[notification object] inLiveResize]) {
108                 //Send event only once, at end of resize operation (when user has released mouse button)
109 #endif
110                 systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, associatedWindow);
111 #ifdef MAC_OS_X_VERSION_10_6
112         //}
113 #endif
114         /* Live resize ugly patch. Needed because live resize runs in a modal loop, not letting main loop run
115          if ([[notification object] inLiveResize]) {
116                 systemCocoa->dispatchEvents();
117                 wm_window_timer(ghostC);
118                 wm_event_do_handlers(ghostC);
119                 wm_event_do_notifiers(ghostC);
120                 wm_draw_update(ghostC);
121         }*/
122 }
123 @end
124
125 #pragma mark NSWindow subclass
126 //We need to subclass it to tell that even borderless (fullscreen), it can become key (receive user events)
127 @interface CocoaWindow: NSWindow
128 {
129         GHOST_SystemCocoa *systemCocoa;
130         GHOST_WindowCocoa *associatedWindow;
131         GHOST_TDragnDropTypes m_draggedObjectType;
132 }
133 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa;
134 @end
135 @implementation CocoaWindow
136 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa
137 {
138         systemCocoa = sysCocoa;
139         associatedWindow = winCocoa;
140 }
141
142 -(BOOL)canBecomeKeyWindow
143 {
144         return YES;
145 }
146
147 //The drag'n'drop dragging destination methods
148 - (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender
149 {
150         NSPoint mouseLocation = [sender draggingLocation];
151         NSPasteboard *draggingPBoard = [sender draggingPasteboard];
152         
153         if ([[draggingPBoard types] containsObject:NSTIFFPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeBitmap;
154         else if ([[draggingPBoard types] containsObject:NSFilenamesPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeFilenames;
155         else if ([[draggingPBoard types] containsObject:NSStringPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeString;
156         else return NSDragOperationNone;
157         
158         associatedWindow->setAcceptDragOperation(FALSE); //Drag operation needs to be accepted explicitly by the event manager
159         systemCocoa->handleDraggingEvent(GHOST_kEventDraggingEntered, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil);
160         return NSDragOperationCopy;
161 }
162
163 - (BOOL)wantsPeriodicDraggingUpdates
164 {
165         return NO; //No need to overflow blender event queue. Events shall be sent only on changes
166 }
167
168 - (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
169 {
170         NSPoint mouseLocation = [sender draggingLocation];
171         
172         systemCocoa->handleDraggingEvent(GHOST_kEventDraggingUpdated, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil);
173         return NSDragOperationCopy;
174 }
175
176 - (void)draggingExited:(id < NSDraggingInfo >)sender
177 {
178         systemCocoa->handleDraggingEvent(GHOST_kEventDraggingExited, m_draggedObjectType, associatedWindow, 0, 0, nil);
179         m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
180 }
181
182 - (BOOL)prepareForDragOperation:(id < NSDraggingInfo >)sender
183 {
184         if (associatedWindow->canAcceptDragOperation())
185                 return YES;
186         else
187                 return NO;
188 }
189
190 - (BOOL)performDragOperation:(id < NSDraggingInfo >)sender
191 {
192         NSPoint mouseLocation = [sender draggingLocation];
193         NSPasteboard *draggingPBoard = [sender draggingPasteboard];
194         id data;
195         
196         switch (m_draggedObjectType) {
197                 case GHOST_kDragnDropTypeBitmap:
198                         data = [draggingPBoard dataForType:NSTIFFPboardType];
199                         break;
200                 case GHOST_kDragnDropTypeFilenames:
201                         data = [draggingPBoard propertyListForType:NSFilenamesPboardType];
202                         break;
203                 case GHOST_kDragnDropTypeString:
204                         data = [draggingPBoard stringForType:NSStringPboardType];
205                         break;
206                 default:
207                         return NO;
208                         break;
209         }
210         systemCocoa->handleDraggingEvent(GHOST_kEventDraggingDropDone, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, (void*)data);
211         return YES;
212 }
213
214 @end
215
216
217
218 #pragma mark NSOpenGLView subclass
219 //We need to subclass it in order to give Cocoa the feeling key events are trapped
220 @interface CocoaOpenGLView : NSOpenGLView
221 {
222 }
223 @end
224 @implementation CocoaOpenGLView
225
226 - (BOOL)acceptsFirstResponder
227 {
228     return YES;
229 }
230
231 //The trick to prevent Cocoa from complaining (beeping)
232 - (void)keyDown:(NSEvent *)theEvent
233 {}
234
235 #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
236 //Cmd+key are handled differently before 10.5
237 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
238 {
239         NSString *chars = [theEvent charactersIgnoringModifiers];
240         
241         if ([chars length] <1) 
242                 return NO;
243         
244         //Let cocoa handle menu shortcuts
245         switch ([chars characterAtIndex:0]) {
246                 case 'q':
247                 case 'w':
248                 case 'h':
249                 case 'm':
250                 case '<':
251                 case '>':
252                 case '~':
253                 case '`':
254                         return NO;
255                 default:
256                         return YES;
257         }
258 }
259 #endif
260
261 - (BOOL)isOpaque
262 {
263     return YES;
264 }
265
266 @end
267
268
269 #pragma mark initialization / finalization
270
271 NSOpenGLContext* GHOST_WindowCocoa::s_firstOpenGLcontext = nil;
272
273 GHOST_WindowCocoa::GHOST_WindowCocoa(
274         GHOST_SystemCocoa *systemCocoa,
275         const STR_String& title,
276         GHOST_TInt32 left,
277         GHOST_TInt32 top,
278         GHOST_TUns32 width,
279         GHOST_TUns32 height,
280         GHOST_TWindowState state,
281         GHOST_TDrawingContextType type,
282         const bool stereoVisual, const GHOST_TUns16 numOfAASamples
283 ) :
284         GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone, stereoVisual, numOfAASamples),
285         m_customCursor(0)
286 {
287         NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[40];
288         NSOpenGLPixelFormat *pixelFormat = nil;
289         int i;
290                 
291         m_systemCocoa = systemCocoa;
292         m_fullScreen = false;
293         
294         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
295         
296
297         //Creates the window
298         NSRect rect;
299         NSSize  minSize;
300         
301         rect.origin.x = left;
302         rect.origin.y = top;
303         rect.size.width = width;
304         rect.size.height = height;
305         
306         m_window = [[CocoaWindow alloc] initWithContentRect:rect
307                                                                                    styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask
308                                                                                          backing:NSBackingStoreBuffered defer:NO];
309         if (m_window == nil) {
310                 [pool drain];
311                 return;
312         }
313         
314         [m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
315         
316         //Forbid to resize the window below the blender defined minimum one
317         minSize.width = 320;
318         minSize.height = 240;
319         [m_window setContentMinSize:minSize];
320         
321         setTitle(title);
322         
323         
324         // Pixel Format Attributes for the windowed NSOpenGLContext
325         i=0;
326         pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer;
327         pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated;
328         //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,;   // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway
329         
330         pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize;
331         pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32;
332         
333         if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo;
334         
335         if (numOfAASamples>0) {
336                 // Multisample anti-aliasing
337                 pixelFormatAttrsWindow[i++] = NSOpenGLPFAMultisample;
338                 
339                 pixelFormatAttrsWindow[i++] = NSOpenGLPFASampleBuffers;
340                 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 1;
341                 
342                 pixelFormatAttrsWindow[i++] = NSOpenGLPFASamples;
343                 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) numOfAASamples;
344                 
345                 pixelFormatAttrsWindow[i++] = NSOpenGLPFANoRecovery;
346         }
347         
348         pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0;
349         
350         pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow];
351         
352         
353         //Fall back to no multisampling if Antialiasing init failed
354         if (pixelFormat == nil) {
355                 i=0;
356                 pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer;
357                 pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated;
358                 //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,;   // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway
359                 
360                 pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize;
361                 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32;
362                 
363                 if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo;
364                 
365                 pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0;
366                 
367                 pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow];
368                 
369         }
370         
371         if (numOfAASamples>0) { //Set m_numOfAASamples to the actual value
372                 GLint gli;
373                 [pixelFormat getValues:&gli forAttribute:NSOpenGLPFASamples forVirtualScreen:0];
374                 if (m_numOfAASamples != (GHOST_TUns16)gli) {
375                         m_numOfAASamples = (GHOST_TUns16)gli;
376                         printf("GHOST_Window could be created with anti-aliasing of only %i samples\n",m_numOfAASamples);
377                 }
378         }
379                 
380         //Creates the OpenGL View inside the window
381         m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect
382                                                                                                  pixelFormat:pixelFormat];
383         
384         [pixelFormat release];
385         
386         m_openGLContext = [m_openGLView openGLContext]; //This context will be replaced by the proper one just after
387         
388         [m_window setContentView:m_openGLView];
389         [m_window setInitialFirstResponder:m_openGLView];
390         
391         [m_window setReleasedWhenClosed:NO]; //To avoid bad pointer exception in case of user closing the window
392         
393         [m_window makeKeyAndOrderFront:nil];
394         
395         setDrawingContextType(type);
396         updateDrawingContext();
397         activateDrawingContext();
398         
399         m_tablet.Active = GHOST_kTabletModeNone;
400         
401         CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init];
402         [windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
403         [m_window setDelegate:windowDelegate];
404         
405         [m_window setAcceptsMouseMovedEvents:YES];
406         
407         [m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
408                                                                                   NSStringPboardType, NSTIFFPboardType, nil]];
409                                                                                   
410         if (state == GHOST_kWindowStateFullScreen)
411                 setState(GHOST_kWindowStateFullScreen);
412                 
413         [pool drain];
414 }
415
416
417 GHOST_WindowCocoa::~GHOST_WindowCocoa()
418 {
419         if (m_customCursor) delete m_customCursor;
420
421     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
422         [m_openGLView release];
423         
424         if (m_window) {
425                 [m_window close];
426                 [[m_window delegate] release];
427                 [m_window release];
428                 m_window = nil;
429         }
430         
431         //Check for other blender opened windows and make the frontmost key
432         NSArray *windowsList = [NSApp orderedWindows];
433         if ([windowsList count]) {
434                 [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
435         }
436         [pool drain];
437 }
438
439 #pragma mark accessors
440
441 bool GHOST_WindowCocoa::getValid() const
442 {
443         return (m_window != 0);
444 }
445
446
447 void GHOST_WindowCocoa::setTitle(const STR_String& title)
448 {
449     GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid")
450         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
451
452         NSString *windowTitle = [[NSString alloc] initWithUTF8String:title];
453         
454         //Set associated file if applicable
455         if ([windowTitle hasPrefix:@"Blender"])
456         {
457                 NSRange fileStrRange;
458                 NSString *associatedFileName;
459                 int len;
460                 
461                 fileStrRange.location = [windowTitle rangeOfString:@"["].location+1;
462                 len = [windowTitle rangeOfString:@"]"].location - fileStrRange.location;
463         
464                 if (len >0)
465                 {
466                         fileStrRange.length = len;
467                         associatedFileName = [windowTitle substringWithRange:fileStrRange];
468                         @try {
469                                 [m_window setRepresentedFilename:associatedFileName];
470                         }
471                         @catch (NSException * e) {
472                                 printf("\nInvalid file path given in window title");
473                         }
474                         [m_window setTitle:[associatedFileName lastPathComponent]];
475                 }
476                 else {
477                         [m_window setTitle:windowTitle];
478                         [m_window setRepresentedFilename:@""];
479                 }
480
481         } else {
482                 [m_window setTitle:windowTitle];
483                 [m_window setRepresentedFilename:@""];
484         }
485
486         
487         [windowTitle release];
488         [pool drain];
489 }
490
491
492 void GHOST_WindowCocoa::getTitle(STR_String& title) const
493 {
494     GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid")
495
496         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
497
498         NSString *windowTitle = [m_window title];
499
500         if (windowTitle != nil) {
501                 title = [windowTitle UTF8String];               
502         }
503         
504         [pool drain];
505 }
506
507
508 void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect& bounds) const
509 {
510         NSRect rect;
511         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid")
512
513         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
514         
515         NSRect screenSize = [[m_window screen] visibleFrame];
516
517         rect = [m_window frame];
518
519         bounds.m_b = screenSize.size.height - (rect.origin.y -screenSize.origin.y);
520         bounds.m_l = rect.origin.x -screenSize.origin.x;
521         bounds.m_r = rect.origin.x-screenSize.origin.x + rect.size.width;
522         bounds.m_t = screenSize.size.height - (rect.origin.y + rect.size.height -screenSize.origin.y);
523         
524         [pool drain];
525 }
526
527
528 void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const
529 {
530         NSRect rect;
531         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid")
532         
533         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
534         
535         if (!m_fullScreen)
536         {
537                 NSRect screenSize = [[m_window screen] visibleFrame];
538
539                 //Max window contents as screen size (excluding title bar...)
540                 NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize
541                                                                                                          styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)];
542
543                 rect = [m_window contentRectForFrameRect:[m_window frame]];
544                 
545                 bounds.m_b = contentRect.size.height - (rect.origin.y -contentRect.origin.y);
546                 bounds.m_l = rect.origin.x -contentRect.origin.x;
547                 bounds.m_r = rect.origin.x-contentRect.origin.x + rect.size.width;
548                 bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height -contentRect.origin.y);
549         }
550         else {
551                 NSRect screenSize = [[m_window screen] frame];
552                 
553                 bounds.m_b = screenSize.origin.y + screenSize.size.height;
554                 bounds.m_l = screenSize.origin.x;
555                 bounds.m_r = screenSize.origin.x + screenSize.size.width;
556                 bounds.m_t = screenSize.origin.y;
557         }
558         [pool drain];
559 }
560
561
562 GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width)
563 {
564         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientWidth(): window invalid")
565         GHOST_Rect cBnds, wBnds;
566         getClientBounds(cBnds);
567         if (((GHOST_TUns32)cBnds.getWidth()) != width) {
568                 NSSize size;
569                 size.width=width;
570                 size.height=cBnds.getHeight();
571                 [m_window setContentSize:size];
572         }
573         return GHOST_kSuccess;
574 }
575
576
577 GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height)
578 {
579         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid")
580         GHOST_Rect cBnds, wBnds;
581         getClientBounds(cBnds);
582         if (((GHOST_TUns32)cBnds.getHeight()) != height) {
583                 NSSize size;
584                 size.width=cBnds.getWidth();
585                 size.height=height;
586                 [m_window setContentSize:size];
587         }
588         return GHOST_kSuccess;
589 }
590
591
592 GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
593 {
594         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid")
595         GHOST_Rect cBnds, wBnds;
596         getClientBounds(cBnds);
597         if ((((GHOST_TUns32)cBnds.getWidth()) != width) ||
598             (((GHOST_TUns32)cBnds.getHeight()) != height)) {
599                 NSSize size;
600                 size.width=width;
601                 size.height=height;
602                 [m_window setContentSize:size];
603         }
604         return GHOST_kSuccess;
605 }
606
607
608 GHOST_TWindowState GHOST_WindowCocoa::getState() const
609 {
610         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid")
611         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
612         GHOST_TWindowState state;
613         if (m_fullScreen) {
614                 state = GHOST_kWindowStateFullScreen;
615         } 
616         else if ([m_window isMiniaturized]) {
617                 state = GHOST_kWindowStateMinimized;
618         }
619         else if ([m_window isZoomed]) {
620                 state = GHOST_kWindowStateMaximized;
621         }
622         else {
623                 state = GHOST_kWindowStateNormal;
624         }
625         [pool drain];
626         return state;
627 }
628
629
630 void GHOST_WindowCocoa::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
631 {
632         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::screenToClient(): window invalid")
633         
634         NSPoint screenCoord;
635         NSPoint baseCoord;
636         
637         screenCoord.x = inX;
638         screenCoord.y = inY;
639         
640         baseCoord = [m_window convertScreenToBase:screenCoord];
641         
642         outX = baseCoord.x;
643         outY = baseCoord.y;
644 }
645
646
647 void GHOST_WindowCocoa::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
648 {
649         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::clientToScreen(): window invalid")
650         
651         NSPoint screenCoord;
652         NSPoint baseCoord;
653         
654         baseCoord.x = inX;
655         baseCoord.y = inY;
656         
657         screenCoord = [m_window convertBaseToScreen:baseCoord];
658         
659         outX = screenCoord.x;
660         outY = screenCoord.y;
661 }
662
663
664 NSScreen* GHOST_WindowCocoa::getScreen()
665 {
666         return [m_window screen];
667 }
668
669
670 /**
671  * @note Fullscreen switch is not actual fullscreen with display capture. As this capture removes all OS X window manager features.
672  * Instead, the menu bar and the dock are hidden, and the window is made borderless and enlarged.
673  * Thus, process switch, exposé, spaces, ... still work in fullscreen mode
674  */
675 GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
676 {
677         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid")
678     switch (state) {
679                 case GHOST_kWindowStateMinimized:
680             [m_window miniaturize:nil];
681             break;
682                 case GHOST_kWindowStateMaximized:
683                         [m_window zoom:nil];
684                         break;
685                 
686                 case GHOST_kWindowStateFullScreen:
687                         if (!m_fullScreen)
688                         {
689                                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
690                         
691                                 //This status change needs to be done before Cocoa call to enter fullscreen mode
692                                 //to give window delegate hint not to forward its deactivation to ghost wm that doesn't know view/window difference
693                                 m_fullScreen = true;
694
695 #ifdef MAC_OS_X_VERSION_10_6
696                                 //10.6 provides Cocoa functions to autoshow menu bar, and to change a window style
697                                 //Hide menu & dock if needed
698                                 if ([[m_window screen] isEqual:[NSScreen mainScreen]])
699                                 {
700                                         [NSApp setPresentationOptions:(NSApplicationPresentationHideDock | NSApplicationPresentationAutoHideMenuBar)];
701                                 }
702                                 //Make window borderless and enlarge it
703                                 [m_window setStyleMask:NSBorderlessWindowMask];
704                                 [m_window setFrame:[[m_window screen] frame] display:YES];
705                                 [m_window makeFirstResponder:m_openGLView];
706 #else
707                                 //With 10.5, we need to create a new window to change its style to borderless
708                                 //Hide menu & dock if needed
709                                 if ([[m_window screen] isEqual:[NSScreen mainScreen]])
710                                 {
711                                         //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:NO];
712                                         //One of the very few 64bit compatible Carbon function
713                                         SetSystemUIMode(kUIModeAllHidden,kUIOptionAutoShowMenuBar);
714                                 }
715                                 //Create a fullscreen borderless window
716                                 CocoaWindow *tmpWindow = [[CocoaWindow alloc]
717                                                                                   initWithContentRect:[[m_window screen] frame]
718                                                                                   styleMask:NSBorderlessWindowMask
719                                                                                   backing:NSBackingStoreBuffered
720                                                                                   defer:YES];
721                                 //Copy current window parameters
722                                 [tmpWindow setTitle:[m_window title]];
723                                 [tmpWindow setRepresentedFilename:[m_window representedFilename]];
724                                 [tmpWindow setReleasedWhenClosed:NO];
725                                 [tmpWindow setAcceptsMouseMovedEvents:YES];
726                                 [tmpWindow setDelegate:[m_window delegate]];
727                                 
728                                 //Assign the openGL view to the new window
729                                 [tmpWindow setContentView:m_openGLView];
730                                 
731                                 //Show the new window
732                                 [tmpWindow makeKeyAndOrderFront:nil];
733                                 //Close and release old window
734                                 [m_window setDelegate:nil]; // To avoid the notification of "window closed" event
735                                 [m_window close];
736                                 [m_window release];
737                                 m_window = tmpWindow;
738 #endif
739                         
740                                 //Tell WM of view new size
741                                 m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this);
742                                 
743                                 [pool drain];
744                                 }
745                         break;
746                 case GHOST_kWindowStateNormal:
747         default:
748                         if (m_fullScreen)
749                         {
750                                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
751                                 m_fullScreen = false;
752
753                                 //Exit fullscreen
754 #ifdef MAC_OS_X_VERSION_10_6
755                                 //Show again menu & dock if needed
756                                 if ([[m_window screen] isEqual:[NSScreen mainScreen]])
757                                 {
758                                         [NSApp setPresentationOptions:NSApplicationPresentationDefault];
759                                 }
760                                 //Make window normal and resize it
761                                 [m_window setStyleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)];
762                                 [m_window setFrame:[[m_window screen] visibleFrame] display:YES];
763                                 //TODO for 10.6 only : window title is forgotten after the style change
764                                 [m_window makeFirstResponder:m_openGLView];
765 #else
766                                 //With 10.5, we need to create a new window to change its style to borderless
767                                 //Show menu & dock if needed
768                                 if ([[m_window screen] isEqual:[NSScreen mainScreen]])
769                                 {
770                                         //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:YES];
771                                         SetSystemUIMode(kUIModeNormal, 0); //One of the very few 64bit compatible Carbon function
772                                 }
773                                 //Create a fullscreen borderless window
774                                 CocoaWindow *tmpWindow = [[CocoaWindow alloc]
775                                                                                   initWithContentRect:[[m_window screen] frame]
776                                                                                                         styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)
777                                                                                                           backing:NSBackingStoreBuffered
778                                                                                                                 defer:YES];
779                                 //Copy current window parameters
780                                 [tmpWindow setTitle:[m_window title]];
781                                 [tmpWindow setRepresentedFilename:[m_window representedFilename]];
782                                 [tmpWindow setReleasedWhenClosed:NO];
783                                 [tmpWindow setAcceptsMouseMovedEvents:YES];
784                                 [tmpWindow setDelegate:[m_window delegate]];
785                                 
786                                 //Assign the openGL view to the new window
787                                 [tmpWindow setContentView:m_openGLView];
788                                 
789                                 //Show the new window
790                                 [tmpWindow makeKeyAndOrderFront:nil];
791                                 //Close and release old window
792                                 [m_window setDelegate:nil]; // To avoid the notification of "window closed" event
793                                 [m_window close];
794                                 [m_window release];
795                                 m_window = tmpWindow;
796 #endif
797                         
798                                 //Tell WM of view new size
799                                 m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this);
800                                 
801                                 [pool drain];
802                         }
803             else if ([m_window isMiniaturized])
804                                 [m_window deminiaturize:nil];
805                         else if ([m_window isZoomed])
806                                 [m_window zoom:nil];
807             break;
808     }
809     return GHOST_kSuccess;
810 }
811
812 GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges)
813 {
814         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
815         
816         [m_window setDocumentEdited:isUnsavedChanges];
817         
818         [pool drain];
819         return GHOST_Window::setModifiedState(isUnsavedChanges);
820 }
821
822
823
824 GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
825 {
826         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid")
827     if (order == GHOST_kWindowOrderTop) {
828                 [m_window makeKeyAndOrderFront:nil];
829     }
830     else {
831                 NSArray *windowsList;
832                 
833                 [m_window orderBack:nil];
834                 
835                 //Check for other blender opened windows and make the frontmost key
836                 windowsList = [NSApp orderedWindows];
837                 if ([windowsList count]) {
838                         [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
839                 }
840     }
841     return GHOST_kSuccess;
842 }
843
844 #pragma mark Drawing context
845
846 /*#define  WAIT_FOR_VSYNC 1*/
847
848 GHOST_TSuccess GHOST_WindowCocoa::swapBuffers()
849 {
850     if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
851         if (m_openGLContext != nil) {
852                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
853                         [m_openGLContext flushBuffer];
854                         [pool drain];
855             return GHOST_kSuccess;
856         }
857     }
858     return GHOST_kFailure;
859 }
860
861 GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext()
862 {
863         if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
864                 if (m_openGLContext != nil) {
865                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
866                         [m_openGLContext update];
867                         [pool drain];
868                         return GHOST_kSuccess;
869                 }
870         }
871         return GHOST_kFailure;
872 }
873
874 GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext()
875 {
876         if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
877                 if (m_openGLContext != nil) {
878                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
879                         [m_openGLContext makeCurrentContext];
880                         
881                         // Disable AA by default
882                         if (m_numOfAASamples > 0) glDisable(GL_MULTISAMPLE_ARB);
883                         [pool drain];
884                         return GHOST_kSuccess;
885                 }
886         }
887         return GHOST_kFailure;
888 }
889
890
891 GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextType type)
892 {
893         GHOST_TSuccess success = GHOST_kFailure;
894         
895         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
896         
897         NSOpenGLPixelFormat *pixelFormat;
898         NSOpenGLContext *tmpOpenGLContext;
899         
900         /***** Multithreaded opengl code : uncomment for enabling
901         CGLContextObj cglCtx;
902         */
903          
904         switch (type) {
905                 case GHOST_kDrawingContextTypeOpenGL:
906                         if (!getValid()) break;
907                                         
908                         pixelFormat = [m_openGLView pixelFormat];
909                         tmpOpenGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
910                                                                                                                           shareContext:s_firstOpenGLcontext];
911                         if (tmpOpenGLContext == nil) {
912                                 success = GHOST_kFailure;
913                                 break;
914                         }
915                         
916                         //Switch openGL to multhreaded mode
917                         /******* Multithreaded opengl code : uncomment for enabling
918                         cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj];
919                         if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError)
920                                 printf("\nSwitched openGL to multithreaded mode");
921                          */
922                         
923                         if (!s_firstOpenGLcontext) s_firstOpenGLcontext = tmpOpenGLContext;
924 #ifdef WAIT_FOR_VSYNC
925                         {
926                                 GLint swapInt = 1;
927                                 /* wait for vsync, to avoid tearing artifacts */
928                                 [tmpOpenGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
929                         }
930 #endif
931                         [m_openGLView setOpenGLContext:tmpOpenGLContext];
932                         [tmpOpenGLContext setView:m_openGLView];
933                         
934                         m_openGLContext = tmpOpenGLContext;
935                         break;
936         
937                 case GHOST_kDrawingContextTypeNone:
938                         success = GHOST_kSuccess;
939                         break;
940                 
941                 default:
942                         break;
943         }
944         [pool drain];
945         return success;
946 }
947
948
949 GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext()
950 {
951         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
952         switch (m_drawingContextType) {
953                 case GHOST_kDrawingContextTypeOpenGL:
954                         if (m_openGLContext)
955                         {
956                                 [m_openGLView clearGLContext];
957                                 if (s_firstOpenGLcontext == m_openGLContext) s_firstOpenGLcontext = nil;
958                                 m_openGLContext = nil;
959                         }
960                         [pool drain];
961                         return GHOST_kSuccess;
962                 case GHOST_kDrawingContextTypeNone:
963                         [pool drain];
964                         return GHOST_kSuccess;
965                         break;
966                 default:
967                         [pool drain];
968                         return GHOST_kFailure;
969         }
970 }
971
972
973 GHOST_TSuccess GHOST_WindowCocoa::invalidate()
974 {
975         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid")
976         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
977         [m_openGLView setNeedsDisplay:YES];
978         [pool drain];
979         return GHOST_kSuccess;
980 }
981
982 #pragma mark Cursor handling
983
984 void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
985 {
986         static bool systemCursorVisible = true;
987         
988         NSAutoreleasePool *pool =[[NSAutoreleasePool alloc] init];
989
990         NSCursor *tmpCursor =nil;
991         
992         if (visible != systemCursorVisible) {
993                 if (visible) {
994                         [NSCursor unhide];
995                         systemCursorVisible = true;
996                 }
997                 else {
998                         [NSCursor hide];
999                         systemCursorVisible = false;
1000                 }
1001         }
1002
1003         if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
1004                 tmpCursor = m_customCursor;
1005         } else {
1006                 switch (cursor) {
1007                         case GHOST_kStandardCursorDestroy:
1008                                 tmpCursor = [NSCursor disappearingItemCursor];
1009                                 break;
1010                         case GHOST_kStandardCursorText:
1011                                 tmpCursor = [NSCursor IBeamCursor];
1012                                 break;
1013                         case GHOST_kStandardCursorCrosshair:
1014                                 tmpCursor = [NSCursor crosshairCursor];
1015                                 break;
1016                         case GHOST_kStandardCursorUpDown:
1017                                 tmpCursor = [NSCursor resizeUpDownCursor];
1018                                 break;
1019                         case GHOST_kStandardCursorLeftRight:
1020                                 tmpCursor = [NSCursor resizeLeftRightCursor];
1021                                 break;
1022                         case GHOST_kStandardCursorTopSide:
1023                                 tmpCursor = [NSCursor resizeUpCursor];
1024                                 break;
1025                         case GHOST_kStandardCursorBottomSide:
1026                                 tmpCursor = [NSCursor resizeDownCursor];
1027                                 break;
1028                         case GHOST_kStandardCursorLeftSide:
1029                                 tmpCursor = [NSCursor resizeLeftCursor];
1030                                 break;
1031                         case GHOST_kStandardCursorRightSide:
1032                                 tmpCursor = [NSCursor resizeRightCursor];
1033                                 break;
1034                         case GHOST_kStandardCursorRightArrow:
1035                         case GHOST_kStandardCursorInfo:
1036                         case GHOST_kStandardCursorLeftArrow:
1037                         case GHOST_kStandardCursorHelp:
1038                         case GHOST_kStandardCursorCycle:
1039                         case GHOST_kStandardCursorSpray:
1040                         case GHOST_kStandardCursorWait:
1041                         case GHOST_kStandardCursorTopLeftCorner:
1042                         case GHOST_kStandardCursorTopRightCorner:
1043                         case GHOST_kStandardCursorBottomRightCorner:
1044                         case GHOST_kStandardCursorBottomLeftCorner:
1045                         case GHOST_kStandardCursorDefault:
1046                         default:
1047                                 tmpCursor = [NSCursor arrowCursor];
1048                                 break;
1049                 };
1050         }
1051         [tmpCursor set];
1052         [pool drain];
1053 }
1054
1055
1056
1057 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible)
1058 {
1059         if ([m_window isVisible]) {
1060                 loadCursor(visible, getCursorShape());
1061         }
1062         
1063         return GHOST_kSuccess;
1064 }
1065
1066
1067 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
1068 {
1069         GHOST_TSuccess err = GHOST_kSuccess;
1070         
1071         if (mode != GHOST_kGrabDisable)
1072         {
1073                 //No need to perform grab without warp as it is always on in OS X
1074                 if(mode != GHOST_kGrabNormal) {
1075                         GHOST_TInt32 x_old,y_old;
1076
1077                         m_systemCocoa->getCursorPosition(x_old,y_old);
1078                         screenToClient(x_old, y_old, m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
1079                         //Warp position is stored in client (window base) coordinates
1080                         setCursorGrabAccum(0, 0);
1081                         
1082                         if(mode == GHOST_kGrabHide) {
1083                                 setWindowCursorVisibility(false);
1084                         }
1085                         
1086                         //Dissociate cursor position even for warp mode, to allow mouse acceleration to work even when warping the cursor
1087                         err = CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
1088                 }
1089         }
1090         else {
1091                 if(m_cursorGrab==GHOST_kGrabHide)
1092                 {
1093                         //No need to set again cursor position, as it has not changed for Cocoa
1094                         setWindowCursorVisibility(true);
1095                 }
1096                 
1097                 err = CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
1098                 /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
1099                 setCursorGrabAccum(0, 0);
1100                 m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */
1101         }
1102         return err;
1103 }
1104         
1105 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape)
1106 {
1107         if (m_customCursor) {
1108                 [m_customCursor release];
1109                 m_customCursor = nil;
1110         }
1111
1112         if ([m_window isVisible]) {
1113                 loadCursor(getCursorVisibility(), shape);
1114         }
1115         
1116         return GHOST_kSuccess;
1117 }
1118
1119 /** Reverse the bits in a GHOST_TUns8
1120 static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
1121 {
1122         ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA);
1123         ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC);
1124         ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0);
1125         return ch;
1126 }
1127 */
1128
1129
1130 /** Reverse the bits in a GHOST_TUns16 */
1131 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
1132 {
1133         shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA);
1134         shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC);
1135         shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0);
1136         shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00);
1137         return shrt;
1138 }
1139
1140 GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
1141                                         int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color)
1142 {
1143         int y,nbUns16;
1144         NSPoint hotSpotPoint;
1145         NSBitmapImageRep *cursorImageRep;
1146         NSImage *cursorImage;
1147         NSSize imSize;
1148         GHOST_TUns16 *cursorBitmap;
1149         
1150         
1151         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1152         
1153         if (m_customCursor) {
1154                 [m_customCursor release];
1155                 m_customCursor = nil;
1156         }
1157         
1158
1159         cursorImageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
1160                                                                                                                          pixelsWide:sizex
1161                                                                                                                          pixelsHigh:sizey
1162                                                                                                                   bitsPerSample:1 
1163                                                                                                                 samplesPerPixel:2
1164                                                                                                                            hasAlpha:YES
1165                                                                                                                            isPlanar:YES
1166                                                                                                                  colorSpaceName:NSDeviceWhiteColorSpace
1167                                                                                                                         bytesPerRow:(sizex/8 + (sizex%8 >0 ?1:0))
1168                                                                                                                    bitsPerPixel:1];
1169         
1170         
1171         cursorBitmap = (GHOST_TUns16*)[cursorImageRep bitmapData];
1172         nbUns16 = [cursorImageRep bytesPerPlane]/2;
1173         
1174         for (y=0; y<nbUns16; y++) {
1175 #if !defined(__LITTLE_ENDIAN__)
1176                 cursorBitmap[y] = ~uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8));
1177                 cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8));
1178 #else
1179                 cursorBitmap[y] = ~uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8));
1180                 cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8));
1181 #endif
1182                 
1183         }
1184         
1185         
1186         imSize.width = sizex;
1187         imSize.height= sizey;
1188         cursorImage = [[NSImage alloc] initWithSize:imSize];
1189         [cursorImage addRepresentation:cursorImageRep];
1190         
1191         hotSpotPoint.x = hotX;
1192         hotSpotPoint.y = hotY;
1193         
1194         //foreground and background color parameter is not handled for now (10.6)
1195         m_customCursor = [[NSCursor alloc] initWithImage:cursorImage
1196                                                                                          hotSpot:hotSpotPoint];
1197         
1198         [cursorImageRep release];
1199         [cursorImage release];
1200         
1201         if ([m_window isVisible]) {
1202                 loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
1203         }
1204         [pool drain];
1205         return GHOST_kSuccess;
1206 }
1207
1208 GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], 
1209                                                                                                 GHOST_TUns8 mask[16][2], int hotX, int hotY)
1210 {
1211         return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1);
1212 }