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