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