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