Cocoa port :
[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 #include "GHOST_WindowCocoa.h"
33 #include "GHOST_SystemCocoa.h"
34 #include "GHOST_Debug.h"
35
36
37 // Pixel Format Attributes for the windowed NSOpenGLContext
38 static const NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[] =
39 {
40         NSOpenGLPFADoubleBuffer,
41         NSOpenGLPFAAccelerated,
42         NSOpenGLPFAAllowOfflineRenderers,   // NOTE: Needed to connect to secondary GPUs
43         NSOpenGLPFADepthSize, 32,
44         0
45 };
46
47 #pragma mark Cocoa delegate object
48
49 @interface CocoaWindowDelegate : NSObject
50 {
51         GHOST_SystemCocoa *systemCocoa;
52         GHOST_WindowCocoa *associatedWindow;
53 }
54
55 - (void)setSystemAndWindowCocoa:(const GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa;
56 - (void)windowWillClose:(NSNotification *)notification;
57 - (void)windowDidBecomeKey:(NSNotification *)notification;
58 - (void)windowDidResignKey:(NSNotification *)notification;
59 - (void)windowDidUpdate:(NSNotification *)notification;
60 - (void)windowDidResize:(NSNotification *)notification;
61 @end
62
63 @implementation CocoaWindowDelegate : NSObject
64 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa
65 {
66         systemCocoa = sysCocoa;
67         associatedWindow = winCocoa;
68 }
69
70 - (void)windowWillClose:(NSNotification *)notification
71 {
72         systemCocoa->handleWindowEvent(GHOST_kEventWindowClose, associatedWindow);
73 }
74
75 - (void)windowDidBecomeKey:(NSNotification *)notification
76 {
77         systemCocoa->handleWindowEvent(GHOST_kEventWindowActivate, associatedWindow);
78 }
79
80 - (void)windowDidResignKey:(NSNotification *)notification
81 {
82         //The window is no more key when its own view becomes fullscreen
83         //but ghost doesn't know the view/window difference, so hide this fact
84         if (associatedWindow->getState() != GHOST_kWindowStateFullScreen)
85                 systemCocoa->handleWindowEvent(GHOST_kEventWindowDeactivate, associatedWindow);
86 }
87
88 - (void)windowDidUpdate:(NSNotification *)notification
89 {
90         systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow);
91 }
92
93 - (void)windowDidResize:(NSNotification *)notification
94 {
95         systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, associatedWindow);
96 }
97 @end
98
99 #pragma mark NSOpenGLView subclass
100 //We need to subclass it in order to give Cocoa the feeling key events are trapped
101 @interface CocoaOpenGLView : NSOpenGLView
102 {
103         
104 }
105 @end
106 @implementation CocoaOpenGLView
107
108 - (BOOL)acceptsFirstResponder
109 {
110     return YES;
111 }
112
113 //The trick to prevent Cocoa from complaining (beeping)
114 - (void)keyDown:(NSEvent *)theEvent
115 {}
116
117 - (BOOL)isOpaque
118 {
119     return YES;
120 }
121
122 @end
123
124
125 #pragma mark initialization / finalization
126
127 GHOST_WindowCocoa::GHOST_WindowCocoa(
128         GHOST_SystemCocoa *systemCocoa,
129         const STR_String& title,
130         GHOST_TInt32 left,
131         GHOST_TInt32 top,
132         GHOST_TUns32 width,
133         GHOST_TUns32 height,
134         GHOST_TWindowState state,
135         GHOST_TDrawingContextType type,
136         const bool stereoVisual
137 ) :
138         GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone),
139         m_customCursor(0)
140 {
141         m_systemCocoa = systemCocoa;
142         m_fullScreen = false;
143         
144         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
145         
146
147         //Creates the window
148         NSRect rect;
149         
150         rect.origin.x = left;
151         rect.origin.y = top;
152         rect.size.width = width;
153         rect.size.height = height;
154         
155         m_window = [[NSWindow alloc] initWithContentRect:rect
156                                                                                    styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask
157                                                                                          backing:NSBackingStoreBuffered defer:NO];
158         if (m_window == nil) {
159                 [pool drain];
160                 return;
161         }
162         
163         [m_window setTitle:[NSString stringWithUTF8String:title]];
164         
165                         
166         //Creates the OpenGL View inside the window
167         NSOpenGLPixelFormat *pixelFormat =
168         [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow];
169         
170         m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect
171                                                                                                  pixelFormat:pixelFormat];
172         
173         [pixelFormat release];
174         
175         m_openGLContext = [m_openGLView openGLContext];
176         
177         [m_window setContentView:m_openGLView];
178         [m_window setInitialFirstResponder:m_openGLView];
179         
180         [m_window setReleasedWhenClosed:NO]; //To avoid bad pointer exception in case of user closing the window
181         
182         [m_window makeKeyAndOrderFront:nil];
183         
184         setDrawingContextType(type);
185         updateDrawingContext();
186         activateDrawingContext();
187         
188         m_tablet.Active = GHOST_kTabletModeNone;
189         
190         CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init];
191         [windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
192         [m_window setDelegate:windowDelegate];
193         
194         [m_window setAcceptsMouseMovedEvents:YES];
195         
196         if (state == GHOST_kWindowStateFullScreen)
197                 setState(GHOST_kWindowStateFullScreen);
198                 
199         [pool drain];
200 }
201
202
203 GHOST_WindowCocoa::~GHOST_WindowCocoa()
204 {
205         if (m_customCursor) delete m_customCursor;
206
207         /*if(ugly_hack==m_windowRef) ugly_hack= NULL;
208         
209         if(ugly_hack==NULL) setDrawingContextType(GHOST_kDrawingContextTypeNone);*/
210     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
211         [m_openGLView release];
212         
213         if (m_window) {
214                 [m_window close];
215                 [m_window release];
216                 m_window = nil;
217         }
218         [pool drain];
219 }
220
221 #pragma mark accessors
222
223 bool GHOST_WindowCocoa::getValid() const
224 {
225     bool valid;
226     if (!m_fullScreen) {
227         valid = (m_window != 0); //&& ::IsValidWindowPtr(m_windowRef);
228     }
229     else {
230         valid = true;
231     }
232     return valid;
233 }
234
235
236 void GHOST_WindowCocoa::setTitle(const STR_String& title)
237 {
238     GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid")
239         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
240
241         NSString *windowTitle = [[NSString alloc] initWithUTF8String:title];
242         
243         [m_window setTitle:windowTitle];
244         
245         [windowTitle release];
246         [pool drain];
247 }
248
249
250 void GHOST_WindowCocoa::getTitle(STR_String& title) const
251 {
252     GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid")
253
254         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
255
256         NSString *windowTitle = [m_window title];
257
258         if (windowTitle != nil) {
259                 title = [windowTitle UTF8String];               
260         }
261         
262         [pool drain];
263 }
264
265
266 void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect& bounds) const
267 {
268         NSRect rect;
269         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid")
270
271         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
272         
273         NSRect screenSize = [[m_window screen] visibleFrame];
274
275         rect = [m_window frame];
276
277         bounds.m_b = screenSize.size.height - (rect.origin.y -screenSize.origin.y);
278         bounds.m_l = rect.origin.x -screenSize.origin.x;
279         bounds.m_r = rect.origin.x-screenSize.origin.x + rect.size.width;
280         bounds.m_t = screenSize.size.height - (rect.origin.y + rect.size.height -screenSize.origin.y);
281         
282         [pool drain];
283 }
284
285
286 void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const
287 {
288         NSRect rect;
289         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid")
290         
291         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
292         
293         if (!m_fullScreen)
294         {
295                 NSRect screenSize = [[m_window screen] visibleFrame];
296
297                 //Max window contents as screen size (excluding title bar...)
298                 NSRect contentRect = [NSWindow contentRectForFrameRect:screenSize
299                                                                                                          styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)];
300
301                 rect = [m_window contentRectForFrameRect:[m_window frame]];
302                 
303                 bounds.m_b = contentRect.size.height - (rect.origin.y -contentRect.origin.y);
304                 bounds.m_l = rect.origin.x -contentRect.origin.x;
305                 bounds.m_r = rect.origin.x-contentRect.origin.x + rect.size.width;
306                 bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height -contentRect.origin.y);
307         }
308         else {
309                 NSRect screenSize = [[m_window screen] frame];
310                 
311                 bounds.m_b = screenSize.origin.y + screenSize.size.height;
312                 bounds.m_l = screenSize.origin.x;
313                 bounds.m_r = screenSize.origin.x + screenSize.size.width;
314                 bounds.m_t = screenSize.origin.y;
315         }
316         [pool drain];
317 }
318
319
320 GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width)
321 {
322         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientWidth(): window invalid")
323         GHOST_Rect cBnds, wBnds;
324         getClientBounds(cBnds);
325         if (((GHOST_TUns32)cBnds.getWidth()) != width) {
326                 NSSize size;
327                 size.width=width;
328                 size.height=cBnds.getHeight();
329                 [m_window setContentSize:size];
330         }
331         return GHOST_kSuccess;
332 }
333
334
335 GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height)
336 {
337         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid")
338         GHOST_Rect cBnds, wBnds;
339         getClientBounds(cBnds);
340         if (((GHOST_TUns32)cBnds.getHeight()) != height) {
341                 NSSize size;
342                 size.width=cBnds.getWidth();
343                 size.height=height;
344                 [m_window setContentSize:size];
345         }
346         return GHOST_kSuccess;
347 }
348
349
350 GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
351 {
352         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid")
353         GHOST_Rect cBnds, wBnds;
354         getClientBounds(cBnds);
355         if ((((GHOST_TUns32)cBnds.getWidth()) != width) ||
356             (((GHOST_TUns32)cBnds.getHeight()) != height)) {
357                 NSSize size;
358                 size.width=width;
359                 size.height=height;
360                 [m_window setContentSize:size];
361         }
362         return GHOST_kSuccess;
363 }
364
365
366 GHOST_TWindowState GHOST_WindowCocoa::getState() const
367 {
368         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid")
369         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
370         GHOST_TWindowState state;
371         if (m_fullScreen) {
372                 state = GHOST_kWindowStateFullScreen;
373         } 
374         else if ([m_window isMiniaturized]) {
375                 state = GHOST_kWindowStateMinimized;
376         }
377         else if ([m_window isZoomed]) {
378                 state = GHOST_kWindowStateMaximized;
379         }
380         else {
381                 state = GHOST_kWindowStateNormal;
382         }
383         [pool drain];
384         return state;
385 }
386
387
388 void GHOST_WindowCocoa::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
389 {
390         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::screenToClient(): window invalid")
391         
392         NSPoint screenCoord;
393         NSPoint baseCoord;
394         
395         screenCoord.x = inX;
396         screenCoord.y = inY;
397         
398         baseCoord = [m_window convertScreenToBase:screenCoord];
399         
400         outX = baseCoord.x;
401         outY = baseCoord.y;
402 }
403
404
405 void GHOST_WindowCocoa::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
406 {
407         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::clientToScreen(): window invalid")
408         
409         NSPoint screenCoord;
410         NSPoint baseCoord;
411         
412         baseCoord.x = inX;
413         baseCoord.y = inY;
414         
415         screenCoord = [m_window convertBaseToScreen:baseCoord];
416         
417         outX = screenCoord.x;
418         outY = screenCoord.y;
419 }
420
421
422 GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
423 {
424         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid")
425     switch (state) {
426                 case GHOST_kWindowStateMinimized:
427             [m_window miniaturize:nil];
428             break;
429                 case GHOST_kWindowStateMaximized:
430                         [m_window zoom:nil];
431                         break;
432                 
433                 case GHOST_kWindowStateFullScreen:
434                         if (!m_fullScreen)
435                         {
436                                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
437                         
438                                 //This status change needs to be done before Cocoa call to enter fullscreen mode
439                                 //to give window delegate hint not to forward its deactivation to ghost wm that doesn't know view/window difference
440                                 m_fullScreen = true;
441
442                                 //Only 10.6 API will enable to manage several display in fullscreen mode, and topmenu autoshow
443                                 [m_openGLView enterFullScreenMode:[m_window screen] withOptions:nil];
444                                 
445                                 //Tell WM of view new size
446                                 m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this);
447                                 
448                                 [pool drain];
449                                 }
450                         break;
451                 case GHOST_kWindowStateNormal:
452         default:
453                         if (m_fullScreen)
454                         {
455                                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
456                                 m_fullScreen = false;
457
458                                 //Exit fullscreen
459                                 [m_openGLView exitFullScreenModeWithOptions:nil];
460                                 
461                                 [m_window makeKeyAndOrderFront:nil];
462                                 [m_window makeFirstResponder:m_openGLView];
463                                 
464                                 //Tell WM of view new size
465                                 m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this);
466                                 
467                                 [pool drain];
468                         }
469             else if ([m_window isMiniaturized])
470                                 [m_window deminiaturize:nil];
471                         else if ([m_window isZoomed])
472                                 [m_window zoom:nil];
473             break;
474     }
475     return GHOST_kSuccess;
476 }
477
478 GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges)
479 {
480         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
481         
482         [m_window setDocumentEdited:isUnsavedChanges];
483         
484         [pool drain];
485         return GHOST_Window::setModifiedState(isUnsavedChanges);
486 }
487
488
489
490 GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
491 {
492         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid")
493     if (order == GHOST_kWindowOrderTop) {
494                 [m_window orderFront:nil];
495     }
496     else {
497                 [m_window orderBack:nil];
498     }
499     return GHOST_kSuccess;
500 }
501
502 #pragma mark Drawing context
503
504 /*#define  WAIT_FOR_VSYNC 1*/
505
506 GHOST_TSuccess GHOST_WindowCocoa::swapBuffers()
507 {
508     if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
509         if (m_openGLContext != nil) {
510                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
511                         [m_openGLContext flushBuffer];
512                         [pool drain];
513             return GHOST_kSuccess;
514         }
515     }
516     return GHOST_kFailure;
517 }
518
519 GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext()
520 {
521         if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
522                 if (m_openGLContext != nil) {
523                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
524                         [m_openGLContext update];
525                         [pool drain];
526                         return GHOST_kSuccess;
527                 }
528         }
529         return GHOST_kFailure;
530 }
531
532 GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext()
533 {
534         if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
535                 if (m_openGLContext != nil) {
536                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
537                         
538                         [m_openGLContext makeCurrentContext];
539 #ifdef GHOST_DRAW_CARBON_GUTTER
540                         // Restrict drawing to non-gutter area
541                         ::aglEnable(m_aglCtx, AGL_BUFFER_RECT);
542                         GHOST_Rect bnds;
543                         getClientBounds(bnds);
544                         GLint b[4] =
545                         {
546                                 bnds.m_l,
547                                 bnds.m_t+s_sizeRectSize,
548                                 bnds.m_r-bnds.m_l,
549                                 bnds.m_b-bnds.m_t
550                         };
551                         GLboolean result = ::aglSetInteger(m_aglCtx, AGL_BUFFER_RECT, b);
552 #endif //GHOST_DRAW_CARBON_GUTTER
553                         [pool drain];
554                         return GHOST_kSuccess;
555                 }
556         }
557         return GHOST_kFailure;
558 }
559
560
561 GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextType type)
562 {
563         GHOST_TSuccess success = GHOST_kFailure;
564         
565         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
566         
567         NSOpenGLPixelFormat *pixelFormat;
568         NSOpenGLContext *tmpOpenGLContext;
569         
570         switch (type) {
571                 case GHOST_kDrawingContextTypeOpenGL:
572                         if (!getValid()) break;
573                                         
574                                 pixelFormat = [m_openGLView pixelFormat];
575                                 tmpOpenGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
576                                                                                                                           shareContext:m_openGLContext];
577                                 if (tmpOpenGLContext == nil)
578                                         success = GHOST_kFailure;
579                                         break;
580 #ifdef WAIT_FOR_VSYNC
581                                 /* wait for vsync, to avoid tearing artifacts */
582                                 [tmpOpenGLContext setValues:1 forParameter:NSOpenGLCPSwapInterval];
583 #endif
584                                 [m_openGLView setOpenGLContext:tmpOpenGLContext];
585                                 [tmpOpenGLContext setView:m_openGLView];
586                                 
587                                 [m_openGLContext release];
588                                 m_openGLContext = tmpOpenGLContext;
589                         break;
590                 
591                 case GHOST_kDrawingContextTypeNone:
592                         success = GHOST_kSuccess;
593                         break;
594                 
595                 default:
596                         break;
597         }
598         [pool drain];
599         return success;
600 }
601
602
603 GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext()
604 {
605         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
606         switch (m_drawingContextType) {
607                 case GHOST_kDrawingContextTypeOpenGL:
608                         [m_openGLView clearGLContext];
609                         [pool drain];
610                         return GHOST_kSuccess;
611                 case GHOST_kDrawingContextTypeNone:
612                         [pool drain];
613                         return GHOST_kSuccess;
614                         break;
615                 default:
616                         [pool drain];
617                         return GHOST_kFailure;
618         }
619 }
620
621
622 GHOST_TSuccess GHOST_WindowCocoa::invalidate()
623 {
624         GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid")
625         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
626         [m_openGLView setNeedsDisplay:YES];
627         [pool drain];
628         return GHOST_kSuccess;
629 }
630
631 #pragma mark Cursor handling
632
633 void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
634 {
635         static bool systemCursorVisible = true;
636         
637         NSAutoreleasePool *pool =[[NSAutoreleasePool alloc] init];
638
639         NSCursor *tmpCursor =nil;
640         
641         if (visible != systemCursorVisible) {
642                 if (visible) {
643                         [NSCursor unhide];
644                         systemCursorVisible = true;
645                 }
646                 else {
647                         [NSCursor hide];
648                         systemCursorVisible = false;
649                 }
650         }
651
652         if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
653                 tmpCursor = m_customCursor;
654         } else {
655                 switch (cursor) {
656                         case GHOST_kStandardCursorDestroy:
657                                 tmpCursor = [NSCursor disappearingItemCursor];
658                                 break;
659                         case GHOST_kStandardCursorText:
660                                 tmpCursor = [NSCursor IBeamCursor];
661                                 break;
662                         case GHOST_kStandardCursorCrosshair:
663                                 tmpCursor = [NSCursor crosshairCursor];
664                                 break;
665                         case GHOST_kStandardCursorUpDown:
666                                 tmpCursor = [NSCursor resizeUpDownCursor];
667                                 break;
668                         case GHOST_kStandardCursorLeftRight:
669                                 tmpCursor = [NSCursor resizeLeftRightCursor];
670                                 break;
671                         case GHOST_kStandardCursorTopSide:
672                                 tmpCursor = [NSCursor resizeUpCursor];
673                                 break;
674                         case GHOST_kStandardCursorBottomSide:
675                                 tmpCursor = [NSCursor resizeDownCursor];
676                                 break;
677                         case GHOST_kStandardCursorLeftSide:
678                                 tmpCursor = [NSCursor resizeLeftCursor];
679                                 break;
680                         case GHOST_kStandardCursorRightSide:
681                                 tmpCursor = [NSCursor resizeRightCursor];
682                                 break;
683                         case GHOST_kStandardCursorRightArrow:
684                         case GHOST_kStandardCursorInfo:
685                         case GHOST_kStandardCursorLeftArrow:
686                         case GHOST_kStandardCursorHelp:
687                         case GHOST_kStandardCursorCycle:
688                         case GHOST_kStandardCursorSpray:
689                         case GHOST_kStandardCursorWait:
690                         case GHOST_kStandardCursorTopLeftCorner:
691                         case GHOST_kStandardCursorTopRightCorner:
692                         case GHOST_kStandardCursorBottomRightCorner:
693                         case GHOST_kStandardCursorBottomLeftCorner:
694                         case GHOST_kStandardCursorDefault:
695                         default:
696                                 tmpCursor = [NSCursor arrowCursor];
697                                 break;
698                 };
699         }
700         [tmpCursor set];
701         [pool drain];
702 }
703
704
705
706 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible)
707 {
708         if ([m_window isVisible]) {
709                 loadCursor(visible, getCursorShape());
710         }
711         
712         return GHOST_kSuccess;
713 }
714         
715 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape)
716 {
717         if (m_customCursor) {
718                 [m_customCursor release];
719                 m_customCursor = nil;
720         }
721
722         if ([m_window isVisible]) {
723                 loadCursor(getCursorVisibility(), shape);
724         }
725         
726         return GHOST_kSuccess;
727 }
728
729 #if 0
730 /** Reverse the bits in a GHOST_TUns8 */
731 static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
732 {
733         ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA);
734         ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC);
735         ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0);
736         return ch;
737 }
738 #endif
739
740
741 /** Reverse the bits in a GHOST_TUns16 */
742 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
743 {
744         shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA);
745         shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC);
746         shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0);
747         shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00);
748         return shrt;
749 }
750
751 GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
752                                         int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color)
753 {
754         int y;
755         NSPoint hotSpotPoint;
756         NSImage *cursorImage;
757         
758         if (m_customCursor) {
759                 [m_customCursor release];
760                 m_customCursor = nil;
761         }
762         /*TODO: implement this (but unused inproject at present)
763         cursorImage = [[NSImage alloc] initWithData:bitmap];
764         
765         for (y=0; y<16; y++) {
766 #if !defined(__LITTLE_ENDIAN__)
767                 m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8));
768                 m_customCursor->mask[y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8));
769 #else
770                 m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8));
771                 m_customCursor->mask[y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8));
772 #endif
773                         
774         }
775         
776         
777         hotSpotPoint.x = hotX;
778         hotSpotPoint.y = hotY;
779         
780         m_customCursor = [[NSCursor alloc] initWithImage:cursorImage
781                                                                  foregroundColorHint:<#(NSColor *)fg#>
782                                                                  backgroundColorHint:<#(NSColor *)bg#>
783                                                                                          hotSpot:hotSpotPoint];
784         
785         [cursorImage release];
786         
787         if ([m_window isVisible]) {
788                 loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
789         }
790         */
791         return GHOST_kSuccess;
792 }
793
794 GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], 
795                                                                                                 GHOST_TUns8 mask[16][2], int hotX, int hotY)
796 {
797         return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1);
798 }
799
800 #pragma mark Old carbon stuff to remove
801
802 #if 0
803 void GHOST_WindowCocoa::setMac_windowState(short value)
804 {
805         mac_windowState = value;
806 }
807
808 short GHOST_WindowCocoa::getMac_windowState()
809 {
810         return mac_windowState;
811 }
812
813 void GHOST_WindowCocoa::gen2mac(const STR_String& in, Str255 out) const
814 {
815         STR_String tempStr  = in;
816         int num = tempStr.Length();
817         if (num > 255) num = 255;
818         ::memcpy(out+1, tempStr.Ptr(), num);
819         out[0] = num;
820 }
821
822
823 void GHOST_WindowCocoa::mac2gen(const Str255 in, STR_String& out) const
824 {
825         char tmp[256];
826         ::memcpy(tmp, in+1, in[0]);
827         tmp[in[0]] = '\0';
828         out = tmp;
829 }
830
831 #endif