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