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