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