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