2.5
[blender-staging.git] / intern / ghost / intern / GHOST_WindowCarbon.cpp
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): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /**
30
31  * $Id$
32  * Copyright (C) 2001 NaN Technologies B.V.
33  * @author      Maarten Gribnau
34  * @date        May 10, 2001
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include "GHOST_WindowCarbon.h"
42 #include "GHOST_Debug.h"
43
44 AGLContext GHOST_WindowCarbon::s_firstaglCtx = NULL;
45 #ifdef GHOST_DRAW_CARBON_GUTTER
46 const GHOST_TInt32 GHOST_WindowCarbon::s_sizeRectSize = 16;
47 #endif //GHOST_DRAW_CARBON_GUTTER
48
49 static const GLint sPreferredFormatWindow[8] = {
50 AGL_RGBA,
51 AGL_DOUBLEBUFFER,       
52 AGL_ACCELERATED,
53 AGL_DEPTH_SIZE,         32,
54 AGL_NONE,
55 };
56
57 static const GLint sPreferredFormatFullScreen[9] = {
58 AGL_RGBA,
59 AGL_DOUBLEBUFFER,
60 AGL_ACCELERATED,
61 AGL_FULLSCREEN,
62 AGL_DEPTH_SIZE,         32,
63 AGL_NONE,
64 };
65
66
67
68 WindowRef ugly_hack=NULL;
69
70 const EventTypeSpec     kWEvents[] = {
71         { kEventClassWindow, kEventWindowZoom },  /* for new zoom behaviour */ 
72 };
73
74 static OSStatus myWEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData) {
75         WindowRef mywindow;
76         GHOST_WindowCarbon *ghost_window;
77         OSStatus err;
78         int theState;
79         
80         if (::GetEventKind(event) == kEventWindowZoom) {
81                 err =  ::GetEventParameter (event,kEventParamDirectObject,typeWindowRef,NULL,sizeof(mywindow),NULL, &mywindow);
82                 ghost_window = (GHOST_WindowCarbon *) GetWRefCon(mywindow);
83                 theState = ghost_window->getMac_windowState();
84                 if (theState == 1) 
85                         ghost_window->setMac_windowState(2);
86                 else if (theState == 2)
87                         ghost_window->setMac_windowState(1);
88
89         }
90         return eventNotHandledErr;
91 }
92
93 GHOST_WindowCarbon::GHOST_WindowCarbon(
94         const STR_String& title,
95         GHOST_TInt32 left,
96         GHOST_TInt32 top,
97         GHOST_TUns32 width,
98         GHOST_TUns32 height,
99         GHOST_TWindowState state,
100         GHOST_TDrawingContextType type,
101         const bool stereoVisual
102 ) :
103         GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone),
104         m_windowRef(0),
105         m_grafPtr(0),
106         m_aglCtx(0),
107         m_customCursor(0),
108         m_fullScreenDirty(false)
109 {
110     Str255 title255;
111         OSStatus err;
112         
113         //fprintf(stderr," main screen top %i left %i height %i width %i\n", top, left, height, width);
114         
115         if (state >= GHOST_kWindowState8Normal ) {
116                 if(state == GHOST_kWindowState8Normal) state= GHOST_kWindowStateNormal;
117                 else if(state == GHOST_kWindowState8Maximized) state= GHOST_kWindowStateMaximized;
118                 else if(state == GHOST_kWindowState8Minimized) state= GHOST_kWindowStateMinimized;
119                 else if(state == GHOST_kWindowState8FullScreen) state= GHOST_kWindowStateFullScreen;
120                 
121                 // state = state - 8;   this was the simple version of above code, doesnt work in gcc 4.0
122                 
123                 setMac_windowState(1);
124         } else 
125                 setMac_windowState(0);
126
127         if (state != GHOST_kWindowStateFullScreen) {
128         Rect bnds = { top, left, top+height, left+width };
129         // Boolean visible = (state == GHOST_kWindowStateNormal) || (state == GHOST_kWindowStateMaximized); /*unused*/
130         gen2mac(title, title255);
131         
132                 err =  ::CreateNewWindow( kDocumentWindowClass,
133                                                                  kWindowStandardDocumentAttributes+kWindowLiveResizeAttribute,
134                                                                  &bnds,
135                                                                  &m_windowRef);
136                 
137                 if ( err != noErr) {
138                         fprintf(stderr," error creating window %i \n",err);
139                 } else {
140                         
141                         ::SetWRefCon(m_windowRef,(SInt32)this);
142                         setTitle(title);
143                         err = InstallWindowEventHandler (m_windowRef, myWEventHandlerProc, GetEventTypeCount(kWEvents), kWEvents,NULL,NULL); 
144                         if ( err != noErr) {
145                                 fprintf(stderr," error creating handler %i \n",err);
146                         } else {
147                                 //      ::TransitionWindow (m_windowRef,kWindowZoomTransitionEffect,kWindowShowTransitionAction,NULL);
148                                 ::ShowWindow(m_windowRef);
149                                 ::MoveWindow (m_windowRef, left, top,true);
150                                 
151                         }
152                 }
153         if (m_windowRef) {
154             m_grafPtr = ::GetWindowPort(m_windowRef);
155             setDrawingContextType(type);
156             updateDrawingContext();
157             activateDrawingContext();
158         }
159                 if(ugly_hack==NULL) {
160                         ugly_hack= m_windowRef;
161                         // when started from commandline, window remains in the back... also for play anim
162                         ProcessSerialNumber psn;
163                         GetCurrentProcess(&psn);
164                         SetFrontProcess(&psn);
165                 }
166     }
167     else {
168     /*
169         Rect bnds = { top, left, top+height, left+width };
170         gen2mac("", title255);
171         m_windowRef = ::NewCWindow(
172             nil,                                                        // Storage 
173             &bnds,                                                      // Bounding rectangle of the window
174             title255,                                           // Title of the window
175             0,                                                          // Window initially visible
176             plainDBox,                                          // procID
177             (WindowRef)-1L,                                     // Put window before all other windows
178             0,                                                          // Window has minimize box
179             (SInt32)this);                                      // Store a pointer to the class in the refCon
180     */
181         //GHOST_PRINT("GHOST_WindowCarbon::GHOST_WindowCarbon(): creating full-screen OpenGL context\n");
182         setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);;installDrawingContext(GHOST_kDrawingContextTypeOpenGL);
183         updateDrawingContext();
184         activateDrawingContext();        
185
186         m_tablet.Active = 0;
187     }
188 }
189
190
191 GHOST_WindowCarbon::~GHOST_WindowCarbon()
192 {
193         if (m_customCursor) delete m_customCursor;
194
195         if(ugly_hack==m_windowRef) ugly_hack= NULL;
196         
197         // printf("GHOST_WindowCarbon::~GHOST_WindowCarbon(): removing drawing context\n");
198         if(ugly_hack==NULL) setDrawingContextType(GHOST_kDrawingContextTypeNone);
199     if (m_windowRef) {
200         ::DisposeWindow(m_windowRef);
201                 m_windowRef = 0;
202         }
203 }
204
205 bool GHOST_WindowCarbon::getValid() const
206 {
207     bool valid;
208     if (!m_fullScreen) {
209         valid = (m_windowRef != 0) && (m_grafPtr != 0) && ::IsValidWindowPtr(m_windowRef);
210     }
211     else {
212         valid = true;
213     }
214     return valid;
215 }
216
217
218 void GHOST_WindowCarbon::setTitle(const STR_String& title)
219 {
220     GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setTitle(): window invalid")
221     Str255 title255;
222     gen2mac(title, title255);
223         ::SetWTitle(m_windowRef, title255);
224 }
225
226
227 void GHOST_WindowCarbon::getTitle(STR_String& title) const
228 {
229     GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getTitle(): window invalid")
230     Str255 title255;
231     ::GetWTitle(m_windowRef, title255);
232     mac2gen(title255, title);
233 }
234
235
236 void GHOST_WindowCarbon::getWindowBounds(GHOST_Rect& bounds) const
237 {
238         OSStatus success;
239         Rect rect;
240         GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getWindowBounds(): window invalid")
241         success = ::GetWindowBounds(m_windowRef, kWindowStructureRgn, &rect);
242         bounds.m_b = rect.bottom;
243         bounds.m_l = rect.left;
244         bounds.m_r = rect.right;
245         bounds.m_t = rect.top;
246 }
247
248
249 void GHOST_WindowCarbon::getClientBounds(GHOST_Rect& bounds) const
250 {
251         Rect rect;
252         GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getClientBounds(): window invalid")
253         //::GetPortBounds(m_grafPtr, &rect);
254         ::GetWindowBounds(m_windowRef, kWindowContentRgn, &rect);
255
256         bounds.m_b = rect.bottom;
257         bounds.m_l = rect.left;
258         bounds.m_r = rect.right;
259         bounds.m_t = rect.top;
260
261         // Subtract gutter height from bottom
262 #ifdef GHOST_DRAW_CARBON_GUTTER
263         if ((bounds.m_b - bounds.m_t) > s_sizeRectSize)
264         {
265                 bounds.m_b -= s_sizeRectSize;
266         }
267         else
268         {
269                 bounds.m_t = bounds.m_b;
270         }
271 #endif //GHOST_DRAW_CARBON_GUTTER
272 }
273
274
275 GHOST_TSuccess GHOST_WindowCarbon::setClientWidth(GHOST_TUns32 width)
276 {
277         GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientWidth(): window invalid")
278         GHOST_Rect cBnds, wBnds;
279         getClientBounds(cBnds);
280         if (((GHOST_TUns32)cBnds.getWidth()) != width) {
281                 ::SizeWindow(m_windowRef, width, cBnds.getHeight(), true);
282         }
283         return GHOST_kSuccess;
284 }
285
286
287 GHOST_TSuccess GHOST_WindowCarbon::setClientHeight(GHOST_TUns32 height)
288 {
289         GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientHeight(): window invalid")
290         GHOST_Rect cBnds, wBnds;
291         getClientBounds(cBnds);
292 #ifdef GHOST_DRAW_CARBON_GUTTER
293         if (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize) {
294                 ::SizeWindow(m_windowRef, cBnds.getWidth(), height+s_sizeRectSize, true);
295         }
296 #else //GHOST_DRAW_CARBON_GUTTER
297         if (((GHOST_TUns32)cBnds.getHeight()) != height) {
298                 ::SizeWindow(m_windowRef, cBnds.getWidth(), height, true);
299         }
300 #endif //GHOST_DRAW_CARBON_GUTTER
301         return GHOST_kSuccess;
302 }
303
304
305 GHOST_TSuccess GHOST_WindowCarbon::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
306 {
307         GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientSize(): window invalid")
308         GHOST_Rect cBnds, wBnds;
309         getClientBounds(cBnds);
310 #ifdef GHOST_DRAW_CARBON_GUTTER
311         if ((((GHOST_TUns32)cBnds.getWidth()) != width) ||
312             (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize)) {
313                 ::SizeWindow(m_windowRef, width, height+s_sizeRectSize, true);
314         }
315 #else //GHOST_DRAW_CARBON_GUTTER
316         if ((((GHOST_TUns32)cBnds.getWidth()) != width) ||
317             (((GHOST_TUns32)cBnds.getHeight()) != height)) {
318                 ::SizeWindow(m_windowRef, width, height, true);
319         }
320 #endif //GHOST_DRAW_CARBON_GUTTER
321         return GHOST_kSuccess;
322 }
323
324
325 GHOST_TWindowState GHOST_WindowCarbon::getState() const
326 {
327         GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getState(): window invalid")
328         GHOST_TWindowState state;
329         if (::IsWindowVisible(m_windowRef)) {
330                 state = GHOST_kWindowStateMinimized;
331         }
332         else if (::IsWindowInStandardState(m_windowRef, nil, nil)) {
333                 state = GHOST_kWindowStateMaximized;
334         }
335         else {
336                 state = GHOST_kWindowStateNormal;
337         }
338         return state;
339 }
340
341
342 void GHOST_WindowCarbon::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
343 {
344         GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::screenToClient(): window invalid")
345         Point point;
346         point.h = inX;
347         point.v = inY;
348     GrafPtr oldPort;
349     ::GetPort(&oldPort);
350     ::SetPort(m_grafPtr);
351         ::GlobalToLocal(&point);
352     ::SetPort(oldPort);
353         outX = point.h;
354         outY = point.v;
355 }
356
357
358 void GHOST_WindowCarbon::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
359 {
360         GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::clientToScreen(): window invalid")
361         Point point;
362         point.h = inX;
363         point.v = inY;
364     GrafPtr oldPort;
365     ::GetPort(&oldPort);
366     ::SetPort(m_grafPtr);
367         ::LocalToGlobal(&point);
368     ::SetPort(oldPort);
369         outX = point.h;
370         outY = point.v;
371 }
372
373
374 GHOST_TSuccess GHOST_WindowCarbon::setState(GHOST_TWindowState state)
375 {
376         GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setState(): window invalid")
377     switch (state) {
378         case GHOST_kWindowStateMinimized:
379             ::HideWindow(m_windowRef);
380             break;
381         case GHOST_kWindowStateMaximized:
382         case GHOST_kWindowStateNormal:
383         default:
384             ::ShowWindow(m_windowRef);
385             break;
386     }
387     return GHOST_kSuccess;
388 }
389
390
391 GHOST_TSuccess GHOST_WindowCarbon::setOrder(GHOST_TWindowOrder order)
392 {
393         GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setOrder(): window invalid")
394     if (order == GHOST_kWindowOrderTop) {
395         //::BringToFront(m_windowRef); is wrong, front window should be active for input too
396                 ::SelectWindow(m_windowRef);
397     }
398     else {
399                 /* doesnt work if you do this with a mouseclick */
400         ::SendBehind(m_windowRef, nil);
401     }
402     return GHOST_kSuccess;
403 }
404
405 /*#define  WAIT_FOR_VSYNC 1*/
406 #ifdef WAIT_FOR_VSYNC
407 #include <OpenGL/OpenGL.h>
408 #endif
409
410 GHOST_TSuccess GHOST_WindowCarbon::swapBuffers()
411 {
412 #ifdef WAIT_FOR_VSYNC
413 /* wait for vsync, to avoid tearing artifacts */
414 long VBL = 1;
415 CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL);
416 #endif
417
418     GHOST_TSuccess succeeded = GHOST_kSuccess;
419     if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
420         if (m_aglCtx) {
421             ::aglSwapBuffers(m_aglCtx);
422         }
423         else {
424             succeeded = GHOST_kFailure;
425         }
426     }
427     return succeeded;
428 }
429
430 GHOST_TSuccess GHOST_WindowCarbon::updateDrawingContext()
431 {
432         GHOST_TSuccess succeeded = GHOST_kSuccess;
433         if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
434                 if (m_aglCtx) {
435                         ::aglUpdateContext(m_aglCtx);
436                 }
437                 else {
438                         succeeded = GHOST_kFailure;
439                 }
440         }
441         return succeeded;
442 }
443
444 GHOST_TSuccess GHOST_WindowCarbon::activateDrawingContext()
445 {
446         GHOST_TSuccess succeeded = GHOST_kSuccess;
447         if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
448                 if (m_aglCtx) {
449                         ::aglSetCurrentContext(m_aglCtx);
450 #ifdef GHOST_DRAW_CARBON_GUTTER
451                         // Restrict drawing to non-gutter area
452                         ::aglEnable(m_aglCtx, AGL_BUFFER_RECT);
453                         GHOST_Rect bnds;
454                         getClientBounds(bnds);
455                         GLint b[4] =
456                         {
457                                 bnds.m_l,
458                                 bnds.m_t+s_sizeRectSize,
459                                 bnds.m_r-bnds.m_l,
460                                 bnds.m_b-bnds.m_t
461                         };
462                         GLboolean result = ::aglSetInteger(m_aglCtx, AGL_BUFFER_RECT, b);
463 #endif //GHOST_DRAW_CARBON_GUTTER
464                 }
465                 else {
466                         succeeded = GHOST_kFailure;
467                 }
468         }
469         return succeeded;
470 }
471
472
473 GHOST_TSuccess GHOST_WindowCarbon::installDrawingContext(GHOST_TDrawingContextType type)
474 {
475         GHOST_TSuccess success = GHOST_kFailure;
476         switch (type) {
477                 case GHOST_kDrawingContextTypeOpenGL:
478                         {
479                         if (!getValid()) break;
480             
481             AGLPixelFormat pixelFormat;
482             if (!m_fullScreen) {
483                 pixelFormat = ::aglChoosePixelFormat(0, 0, sPreferredFormatWindow);
484                 m_aglCtx = ::aglCreateContext(pixelFormat, s_firstaglCtx);
485                 if (!m_aglCtx) break;
486                                 if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx;
487                  success = ::aglSetDrawable(m_aglCtx, m_grafPtr) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure;
488             }
489             else {
490                 //GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL\n");
491 GDHandle device=::GetMainDevice();pixelFormat=::aglChoosePixelFormat(&device,1,sPreferredFormatFullScreen);
492                 m_aglCtx = ::aglCreateContext(pixelFormat, 0);
493                 if (!m_aglCtx) break;
494                                 if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx;
495                 //GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): created OpenGL context\n");
496                 //::CGGetActiveDisplayList(0, NULL, &m_numDisplays)
497                 success = ::aglSetFullScreen(m_aglCtx, m_fullScreenWidth, m_fullScreenHeight, 75, 0) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure;
498                 /*
499                 if (success == GHOST_kSuccess) {
500                     GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL succeeded\n");
501                 }
502                 else {
503                     GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL failed\n");
504                 }
505                 */
506             }
507             ::aglDestroyPixelFormat(pixelFormat);
508                         }
509                         break;
510                 
511                 case GHOST_kDrawingContextTypeNone:
512                         success = GHOST_kSuccess;
513                         break;
514                 
515                 default:
516                         break;
517         }
518         return success;
519 }
520
521
522 GHOST_TSuccess GHOST_WindowCarbon::removeDrawingContext()
523 {
524         GHOST_TSuccess success = GHOST_kFailure;
525         switch (m_drawingContextType) {
526                 case GHOST_kDrawingContextTypeOpenGL:
527                         if (m_aglCtx) {
528                 aglSetCurrentContext(NULL);
529                 aglSetDrawable(m_aglCtx, NULL);
530                 //aglDestroyContext(m_aglCtx);
531                                 if (s_firstaglCtx == m_aglCtx) s_firstaglCtx = NULL;
532                                 success = ::aglDestroyContext(m_aglCtx) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure;
533                                 m_aglCtx = 0;
534                         }
535                         break;
536                 case GHOST_kDrawingContextTypeNone:
537                         success = GHOST_kSuccess;
538                         break;
539                 default:
540                         break;
541         }
542         return success;
543 }
544
545
546 GHOST_TSuccess GHOST_WindowCarbon::invalidate()
547 {
548         GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::invalidate(): window invalid")
549     if (!m_fullScreen) {
550         Rect rect;
551         ::GetPortBounds(m_grafPtr, &rect);
552         ::InvalWindowRect(m_windowRef, &rect);
553     }
554     else {
555         //EventRef event;
556         //OSStatus status = ::CreateEvent(NULL, kEventClassWindow, kEventWindowUpdate, 0, 0, &event);
557         //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): created event " << status << " \n");
558         //status = ::SetEventParameter(event, kEventParamDirectObject, typeWindowRef, sizeof(WindowRef), this);
559         //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): set event parameter " << status << " \n");
560         //status = ::PostEventToQueue(::GetMainEventQueue(), event, kEventPriorityStandard);
561         //status = ::SendEventToEventTarget(event, ::GetApplicationEventTarget());
562         //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): added event to queue " << status << " \n");
563         m_fullScreenDirty = true;
564     }
565         return GHOST_kSuccess;
566 }
567
568
569 void GHOST_WindowCarbon::gen2mac(const STR_String& in, Str255 out) const
570 {
571         STR_String tempStr  = in;
572         int num = tempStr.Length();
573         if (num > 255) num = 255;
574         ::memcpy(out+1, tempStr.Ptr(), num);
575         out[0] = num;
576 }
577
578
579 void GHOST_WindowCarbon::mac2gen(const Str255 in, STR_String& out) const
580 {
581         char tmp[256];
582         ::memcpy(tmp, in+1, in[0]);
583         tmp[in[0]] = '\0';
584         out = tmp;
585 }
586
587 void GHOST_WindowCarbon::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
588 {
589         static bool systemCursorVisible = true;
590         
591         if (visible != systemCursorVisible) {
592                 if (visible) {
593                         ::ShowCursor();
594                         systemCursorVisible = true;
595                 }
596                 else {
597                         ::HideCursor();
598                         systemCursorVisible = false;
599                 }
600         }
601
602         if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
603                 ::SetCursor( m_customCursor );
604         } else {
605                 int carbon_cursor;
606         
607 #define GCMAP(ghostCursor, carbonCursor)        case ghostCursor: carbon_cursor = carbonCursor; break
608                 switch (cursor) {
609                 default:
610                 GCMAP( GHOST_kStandardCursorDefault,                            kThemeArrowCursor);
611                 GCMAP( GHOST_kStandardCursorRightArrow,                         kThemeAliasArrowCursor);
612                 GCMAP( GHOST_kStandardCursorLeftArrow,                          kThemeArrowCursor);
613                 GCMAP( GHOST_kStandardCursorInfo,                                       kThemeArrowCursor);
614                 GCMAP( GHOST_kStandardCursorDestroy,                            kThemeArrowCursor);
615                 GCMAP( GHOST_kStandardCursorHelp,                               kThemeArrowCursor);
616                 GCMAP( GHOST_kStandardCursorCycle,                                      kThemeArrowCursor);
617                 GCMAP( GHOST_kStandardCursorSpray,                                      kThemeArrowCursor);
618                 GCMAP( GHOST_kStandardCursorWait,                                       kThemeWatchCursor);
619                 GCMAP( GHOST_kStandardCursorText,                                       kThemeIBeamCursor);
620                 GCMAP( GHOST_kStandardCursorCrosshair,                          kThemeCrossCursor);
621                 GCMAP( GHOST_kStandardCursorUpDown,                                     kThemeClosedHandCursor);
622                 GCMAP( GHOST_kStandardCursorLeftRight,                          kThemeClosedHandCursor);
623                 GCMAP( GHOST_kStandardCursorTopSide,                            kThemeArrowCursor);
624                 GCMAP( GHOST_kStandardCursorBottomSide,                         kThemeArrowCursor);
625                 GCMAP( GHOST_kStandardCursorLeftSide,                           kThemeResizeLeftCursor);
626                 GCMAP( GHOST_kStandardCursorRightSide,                          kThemeResizeRightCursor);
627                 GCMAP( GHOST_kStandardCursorTopLeftCorner,                      kThemeArrowCursor);
628                 GCMAP( GHOST_kStandardCursorTopRightCorner,                     kThemeArrowCursor);
629                 GCMAP( GHOST_kStandardCursorBottomRightCorner,          kThemeArrowCursor);
630                 GCMAP( GHOST_kStandardCursorBottomLeftCorner,           kThemeArrowCursor);
631                 };
632 #undef GCMAP
633
634                 ::SetThemeCursor(carbon_cursor);
635         }
636 }
637
638
639 bool GHOST_WindowCarbon::getFullScreenDirty()
640 {
641     return m_fullScreen && m_fullScreenDirty;
642 }
643
644
645 GHOST_TSuccess GHOST_WindowCarbon::setWindowCursorVisibility(bool visible)
646 {
647         if (::FrontWindow() == m_windowRef) {
648                 loadCursor(visible, getCursorShape());
649         }
650         
651         return GHOST_kSuccess;
652 }
653         
654 GHOST_TSuccess GHOST_WindowCarbon::setWindowCursorShape(GHOST_TStandardCursor shape)
655 {
656         if (m_customCursor) {
657                 delete m_customCursor;
658                 m_customCursor = 0;
659         }
660
661         if (::FrontWindow() == m_windowRef) {
662                 loadCursor(getCursorVisibility(), shape);
663         }
664         
665         return GHOST_kSuccess;
666 }
667
668 #if 0
669 /** Reverse the bits in a GHOST_TUns8 */
670 static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
671 {
672         ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA);
673         ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC);
674         ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0);
675         return ch;
676 }
677 #endif
678
679
680 /** Reverse the bits in a GHOST_TUns16 */
681 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
682 {
683         shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA);
684         shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC);
685         shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0);
686         shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00);
687         return shrt;
688 }
689
690 GHOST_TSuccess GHOST_WindowCarbon::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
691                                         int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color)
692 {
693         int y;
694         
695         if (m_customCursor) {
696                 delete m_customCursor;
697                 m_customCursor = 0;
698         }
699         
700         m_customCursor = new Cursor;
701         if (!m_customCursor) return GHOST_kFailure;
702         
703         for (y=0; y<16; y++) {
704 #if !defined(__LITTLE_ENDIAN__)
705                 m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8));
706                 m_customCursor->mask[y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8));
707 #else
708                 m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8));
709                 m_customCursor->mask[y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8));
710 #endif
711                         
712         }
713         
714         m_customCursor->hotSpot.h = hotX;
715         m_customCursor->hotSpot.v = hotY;
716         
717         if (::FrontWindow() == m_windowRef) {
718                 loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
719         }
720         
721         return GHOST_kSuccess;
722 }
723
724 GHOST_TSuccess GHOST_WindowCarbon::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], 
725                                                                                                 GHOST_TUns8 mask[16][2], int hotX, int hotY)
726 {
727         return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1);
728 }
729
730
731 void GHOST_WindowCarbon::setMac_windowState(short value)
732 {
733         mac_windowState = value;
734 }
735
736 short GHOST_WindowCarbon::getMac_windowState()
737 {
738         return mac_windowState;
739 }