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