licensing cleanup (GPLv2)
[org.ibex.core.git] / src / org / ibex / plat / Darwin.cc
1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the GNU General Public License version 2 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 // Authors: Brian Alliet and Evan Jones
6 #ifndef __APPLE_CC__
7 #define FSF_GCC
8 #define __APPLE_CC__
9 #else
10 #define APPLE_GCC
11 #endif
12
13 #define __private_extern__
14 #include <mach-o/dyld.h>
15
16 #include "POSIX.cc"
17 #include "OpenGL.cc"
18
19 #include <java/lang/Object.h>
20 #include <java/lang/Error.h>
21
22 #include <org/ibex/plat/Darwin.h>
23 #include <org/ibex/plat/Darwin$CarbonSurface.h>
24 #include <org/ibex/plat/Darwin$GLCarbonSurface.h>
25 #include <org/ibex/plat/Darwin$GLCarbonPixelBuffer.h>
26 #include <org/ibex/plat/Darwin$CarbonMessage.h>
27 #include <org/ibex/plat/Darwin$CarbonOpenGL.h>
28 #include <org/ibex/plat/Darwin$FileDialogHelper.h>
29 #include <org/ibex/plat/GCJ$Retainer.h>
30 #include <org/ibex/net/HTTP$Proxy.h>
31 #include <org/ibex/util/Semaphore.h>
32
33 #include <stdlib.h>
34 #include <pthread.h>
35
36 #include "DarwinCarbonHeaders.h"
37
38 #define Ibex_CARBON_NO_BUNDLE_HACK
39 #ifdef Ibex_CARBON_NO_BUNDLE_HACK
40 extern "C" {
41     OSErr CPSEnableForegroundOperation(ProcessSerialNumber *psn);
42     OSErr CPSSetFrontProcess(ProcessSerialNumber *psn);
43 }
44 #endif
45
46 static const mach_header* CarbonHandle = NULL;
47 static const mach_header* AGLHandle = NULL;
48 static const mach_header* SCHandle = NULL;
49 #define CARBON_LIBRARY_PATH "/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon"
50 #define AGL_LIBRARY_PATH "/System/Library/Frameworks/AGL.framework/Versions/A/AGL"
51 #define SC_LIBRARY_PATH "/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration"
52
53 static void* dlsym(char* symbol) {
54   if (CarbonHandle == NULL) CarbonHandle = NSAddImage(CARBON_LIBRARY_PATH, NSADDIMAGE_OPTION_NONE);
55   if (AGLHandle == NULL) AGLHandle = NSAddImage(AGL_LIBRARY_PATH, NSADDIMAGE_OPTION_NONE);
56   if (SCHandle == NULL) SCHandle = NSAddImage(SC_LIBRARY_PATH, NSADDIMAGE_OPTION_NONE);
57   void* ret = NSAddressOfSymbol(NSLookupSymbolInImage(CarbonHandle, symbol,
58                                                       NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
59   if (ret == NULL) ret = NSAddressOfSymbol(NSLookupSymbolInImage(AGLHandle, symbol,
60                                                                  NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
61   if (ret == NULL) ret = NSAddressOfSymbol(NSLookupSymbolInImage(SCHandle, symbol,
62                                                                  NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
63   /*printf("linking symbol %s to address %x\n", symbol, ret);
64   fflush(stdout);*/
65   return ret;
66 }
67
68 #define declare_weak(symbol) typeof(symbol) *symbol##_weak = NULL
69 #define WC(func) \
70     (*((func##_weak != NULL) ? func##_weak : func##_weak = (typeof(func##_weak))dlsym("_" #func)))
71
72 declare_weak(GetRegionBounds);
73 declare_weak(RegisterToolboxObjectClass);
74 declare_weak(GetWindowProperty);
75 declare_weak(SetWindowProperty);
76 declare_weak(CreateCustomWindow);
77 declare_weak(InstallWindowContentPaintProc);
78 declare_weak(AEGetNthPtr);
79 declare_weak(CFArrayGetCount);
80 declare_weak(CFArrayGetTypeID);
81 declare_weak(CFArrayGetValueAtIndex);
82 declare_weak(CFDictionaryGetValue);
83 declare_weak(CFGetTypeID);
84 declare_weak(CFNumberGetTypeID);
85 declare_weak(CFNumberGetValue);
86 declare_weak(CFRelease);
87 declare_weak(CFStringCompare);
88 declare_weak(CFStringCreateWithCString);
89 declare_weak(CFStringCreateWithCharacters);
90 declare_weak(CFStringGetCharacters);
91 declare_weak(CFStringGetLength);
92 declare_weak(CFStringGetTypeID);
93 declare_weak(CFURLCopyScheme);
94 declare_weak(CFURLCreateWithString);
95 declare_weak(CGDisplayPixelsHigh);
96 declare_weak(CGDisplayPixelsWide);
97 declare_weak(CallNextEventHandler);
98 declare_weak(CollapseWindow);
99 declare_weak(ConstrainWindowToScreen);
100 declare_weak(CreateEvent);
101 declare_weak(CreateNewWindow);
102 declare_weak(DisposeEventHandlerUPP);
103 declare_weak(DisposeNavEventUPP);
104 declare_weak(DisposeWindow);
105 declare_weak(ExitToShell);
106 declare_weak(FSRefMakePath);
107 declare_weak(FrontWindow);
108 declare_weak(Gestalt);
109 declare_weak(GetApplicationEventTarget);
110 declare_weak(GetCurrentProcess);
111 declare_weak(GetCurrentScrap);
112 declare_weak(GetEventClass);
113 declare_weak(GetEventKind);
114 declare_weak(GetEventParameter);
115 declare_weak(GetMainEventQueue);
116 declare_weak(GetScrapFlavorData);
117 declare_weak(GetScrapFlavorSize);
118 declare_weak(GetWindowBounds);
119 declare_weak(GetWindowEventTarget);
120 declare_weak(GetWindowPort);
121 declare_weak(HideWindow);
122 declare_weak(InstallEventHandler);
123 declare_weak(IsWindowCollapsed);
124 declare_weak(LSOpenCFURLRef);
125 declare_weak(NavCreateGetFileDialog);
126 declare_weak(NavCreatePutFileDialog);
127 declare_weak(NavDialogDispose);
128 declare_weak(NavDialogGetReply);
129 declare_weak(NavDialogGetUserAction);
130 declare_weak(NavDialogRun);
131 declare_weak(NavDisposeReply);
132 declare_weak(NavGetDefaultDialogCreationOptions);
133 declare_weak(NewEventHandlerUPP);
134 declare_weak(NewNavEventUPP);
135 declare_weak(PostEventToQueue);
136 declare_weak(PutScrapFlavor);
137 declare_weak(QuitApplicationEventLoop);
138 declare_weak(ReleaseEvent);
139 declare_weak(RunApplicationEventLoop);
140 declare_weak(SCDynamicStoreCopyProxies);
141 declare_weak(SelectWindow);
142 declare_weak(SendBehind);
143 declare_weak(SetEventParameter);
144 declare_weak(SetThemeCursor);
145 declare_weak(SetWindowBounds);
146 declare_weak(SetWindowResizeLimits);
147 declare_weak(SetWindowTitleWithCFString);
148 declare_weak(ShowWindow);
149 declare_weak(ZoomWindowIdeal);
150 declare_weak(__CFStringMakeConstantString);
151 declare_weak(aglChoosePixelFormat);
152 declare_weak(aglCreateContext);
153 declare_weak(aglDestroyContext);
154 declare_weak(aglSetCurrentContext);
155 declare_weak(aglSetDrawable);
156 declare_weak(aglSurfaceTexture);
157 declare_weak(aglUpdateContext);
158 declare_weak(CPSEnableForegroundOperation);
159 declare_weak(CPSSetFrontProcess);
160 declare_weak(kCFAllocatorDefault);
161 declare_weak(NewWindowPaintUPP);
162
163 #define GetWindowEventTarget WC(GetWindowEventTarget)
164 #define InstallEventHandler WC(InstallEventHandler)
165 #define __CFStringMakeConstantString WC(__CFStringMakeConstantString)
166
167 using namespace org::ibex::plat;
168 using gnu::gcj::RawData;
169 using org::ibex::util::Semaphore;
170 using java::lang::Object;
171
172 namespace org { namespace ibex { namespace plat {
173
174
175 #pragma mark ----- Blit Locks ------
176 static pthread_mutex_t blit_mutex;
177 static pthread_cond_t blit_cond;
178
179 static inline void blit_lock() { if(pthread_mutex_lock(&blit_mutex) != 0) abort(); }
180 static inline void blit_unlock() { if(pthread_mutex_unlock(&blit_mutex) != 0) abort(); }
181 static inline void blit_wait() { if(pthread_cond_wait(&blit_cond,&blit_mutex) != 0) abort(); }
182 static inline void blit_signal() { if(pthread_cond_signal(&blit_cond) != 0) abort(); }
183
184 void Darwin$CarbonSurface::blitLock() { blit_lock(); }
185 void Darwin$CarbonSurface::blitUnlock() { blit_unlock(); }
186 void Darwin$CarbonSurface::blitWait() { blit_wait(); }
187
188
189 template <bool CHECK> static inline int CompileTimeCheck() { const int something_is_wrong=1; something_is_wrong++; return 0; }
190 template <> static inline int CompileTimeCheck<true>() { return 0; }
191 const static int unichar_check = CompileTimeCheck<sizeof(jchar)==sizeof(UniChar)>();
192
193 static void funcFailed(const char *func,int r);
194 static inline void funcFailed(const char *func) { funcFailed(func,-1); }
195
196 static inline void checkStatus(OSStatus r, char *func) { if(r != noErr) funcFailed(func,r); }
197 static inline void checkStatus(GLboolean b, char *func) { if(!b) funcFailed(func,-1); }
198 static inline void checkStatus(void *p, char *func) { if(!p) funcFailed(func,-1); }
199
200 jstring cfStringToJString(CFStringRef s) {
201     CFIndex length = WC(CFStringGetLength)(s);
202     CFRange range = CFRangeMake(0,length);
203     jstring js = JvAllocString(length);
204     UniChar *buf = (UniChar*)JvGetStringChars(js);
205     WC(CFStringGetCharacters)(s,range,buf);
206     return js;
207 }
208
209 #pragma mark ------ SmartCFString ------
210 class SmartCFString {
211     private:
212         CFStringRef p;
213         void release() { if(p) WC(CFRelease)(p); }
214         void checkNull() { if(!p) funcFailed("CFString function"); }
215     public:
216         // Constructors
217         SmartCFString() : p(0) { }
218         SmartCFString(const char *s) : p(0) { *this = s; }
219         SmartCFString(jstring js) : p(0) { *this = js; }
220         SmartCFString(CFStringRef cf) : p(0) { *this = cf; }
221         // Destructor
222         ~SmartCFString() { release(); }
223         // Assignment
224         SmartCFString& operator= (const char *s) {
225             release();
226             if(!s) s = "(null)";
227             p = WC(CFStringCreateWithCString)(WC(kCFAllocatorDefault),s,kCFStringEncodingISOLatin1);
228             checkNull();
229             return *this;
230         }
231         SmartCFString& operator= (jstring js) {
232             if(!js) return *this = "(null)";
233             release();
234             UniChar *buf = (UniChar*) JvGetStringChars(js);
235             CFIndex length = js->length();
236             p = WC(CFStringCreateWithCharacters)(WC(kCFAllocatorDefault),buf,length);
237             checkNull();
238             return *this;
239         }
240         SmartCFString& operator= (CFStringRef cf) {
241             if(cf == NULL) return *this = "(null)";
242             release();
243             p = cf;
244             return *this;
245         }
246         operator CFStringRef() { return p; }
247         operator jstring() { return getJString(); }
248         
249         jstring getJString() { return cfStringToJString(p); }
250         
251         bool equals(const char *s) {
252             SmartCFString cfs(s);
253             return equals(cfs);
254         }
255         
256         bool equals(CFStringRef cfs) {
257             return WC(CFStringCompare)(p,cfs,0) == kCFCompareEqualTo;
258         }
259 };
260
261 // CHECKME: Is just making up your own four char codes really correct?
262 const static UInt32 kEventClassCarbonMessage = 'ibexa';
263 const static UInt32 kEventCarbonMessage = 'ibexb';
264 const static UInt32 kEventParamCarbonMessage = 'ibexc';
265
266 static OSStatus carbonMessageEventHandler(EventHandlerCallRef handler, EventRef e, void *userData);
267 static EventHandlerUPP carbonMessageEventHandlerUPP;
268
269 static void fileDialogEventHandler(NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, void *userData);
270 static NavEventUPP fileDialogEventHandlerUPP;
271
272 static OSStatus windowEventHandler(EventHandlerCallRef handler, EventRef e, void *userData);
273 static EventHandlerUPP windowEventHandlerUPP;
274
275 static OSStatus paintProc(GDHandle device,GrafPtr qdContext,WindowRef window,RgnHandle inClientPaintRgn,RgnHandle outSystemPaintRgn,void *userData);
276 static WindowPaintUPP paintProcUPP;
277
278 jboolean Darwin::isJaguar() {
279     SInt32 version;
280     OSStatus r = WC(Gestalt)(gestaltSystemVersion, &version);
281     checkStatus(r,"Gestalt");
282     return version >= 0x1020;
283 }
284
285 void Darwin$CarbonMessage::natInit() {
286     OSStatus r;
287     
288     EventTypeSpec eventTypes = { kEventClassCarbonMessage, kEventCarbonMessage };
289     r = InstallEventHandler(WC(GetApplicationEventTarget)(),carbonMessageEventHandlerUPP,1,&eventTypes,NULL,NULL);
290     checkStatus(r,"InstallEventHandler");
291 }
292
293 void Darwin$CarbonMessage::add(Darwin$CarbonMessage *msg) {
294     EventRef event;
295     OSStatus r;
296     
297     GCJ$Retainer::retain(msg);
298
299     r = WC(CreateEvent)(WC(kCFAllocatorDefault),kEventClassCarbonMessage,kEventCarbonMessage,0,kEventAttributeNone,&event);
300     checkStatus(r,"CreateEvent");
301     r = WC(SetEventParameter)(event,kEventParamCarbonMessage,typeVoidPtr,sizeof(msg),(void*)&msg);
302     checkStatus(r,"SetEventParameter");
303     r = WC(PostEventToQueue)(WC(GetMainEventQueue)(),event,kEventPriorityHigh);
304     checkStatus(r,"PostEventToQueue");
305     WC(ReleaseEvent)(event);
306 }
307
308
309 static OSStatus carbonMessageEventHandler(EventHandlerCallRef handler, EventRef e, void *userData) {
310     UInt32 eKind = WC(GetEventKind)(e);
311     UInt32 eClass = WC(GetEventClass)(e);
312     OSStatus r;
313     Darwin$CarbonMessage *msg;
314     if(eClass != kEventClassCarbonMessage || eKind != kEventCarbonMessage)
315         return eventNotHandledErr;
316     r = WC(GetEventParameter)(e,kEventParamCarbonMessage,typeVoidPtr,NULL,sizeof(msg),NULL,&msg);
317     checkStatus(r,"GetEventParameter");
318     msg->perform();
319     GCJ$Retainer::release(msg);
320     return noErr;
321 }
322
323
324 #pragma mark ------ Utility Functions ------
325
326 static void funcFailed(const char *func,int r){
327     fprintf(stderr,"%s() failed (%d)\n",func,r);
328     exit(EXIT_FAILURE);
329
330
331 #pragma mark ------ CarbonPicture Methods ------ 
332
333 #pragma mark ----- Carbon Surface Methods ----
334
335
336 void Darwin$CarbonSurface::natSyncCursor(jint n) {
337     ThemeCursor c;
338     // see Carbon.java for what these numbers mean
339     switch(n) {
340         case 1: c = kThemeWatchCursor;
341         case 2: c = kThemePlusCursor;
342         case 3: c = kThemeIBeamCursor;
343         case 4: c = kThemePointingHandCursor;
344         case 5: c = kThemeOpenHandCursor;
345         case 6: c = kThemeResizeLeftRightCursor;
346         default: c = kThemeArrowCursor;
347     }
348     WC(SetThemeCursor)(c);
349 }
350    
351 void Darwin$CarbonSurface::natSetInvisible(jboolean b) {
352     WindowRef window = (WindowRef) rawWindowRef;
353     fprintf(stderr,"Making window %s\n",b?"invisible":"visible");
354     if(b) WC(HideWindow)(window);
355     else WC(ShowWindow)(window);
356 }
357
358 void Darwin$CarbonSurface::nat_setMaximized(jboolean b) {
359     WindowRef window = (WindowRef) rawWindowRef;
360     Point ideal = { 10000, 10000 };
361     OSStatus r = WC(ZoomWindowIdeal)(window,(b?inZoomOut:inZoomIn),&ideal);
362     checkStatus(r,"ZoomWindowIdeal");
363 }
364
365 void Darwin$CarbonSurface::nat_setMinimized(jboolean b) {
366     WindowRef window = (WindowRef) rawWindowRef;
367     if((WC(IsWindowCollapsed)(window) ? 1 : 0) == (b ? 1 : 0)) return;
368     OSStatus r = WC(CollapseWindow)(window,b);
369     checkStatus(r,"CollapseWindow");
370 }
371
372 void Darwin$CarbonSurface::natSetTitleBarText(jstring js) {
373     SmartCFString s = js;
374     WindowRef window = (WindowRef) rawWindowRef;
375     WC(SetWindowTitleWithCFString)(window,s);
376 }
377
378 void Darwin$CarbonSurface::natToBack() {
379     WindowRef window = (WindowRef) rawWindowRef;
380     WC(SendBehind)(window,NULL);
381 }
382
383 void Darwin$CarbonSurface::natToFront() {
384     WindowRef window = (WindowRef) rawWindowRef;
385     fprintf(stderr,"SelectWindow)()\n");
386     WC(SelectWindow)(window);
387 }
388
389 #pragma mark ---- Window Event Handler ----
390 static const EventTypeSpec eventTypeSpecs[] = {
391     // kEventClassCommand
392     // { kEventClassCommand, ??? },
393     
394     // kEventClassWindow
395     { kEventClassWindow, kEventWindowUpdate },
396     { kEventClassWindow, kEventWindowBoundsChanged },
397     { kEventClassWindow, kEventWindowBoundsChanging },
398     { kEventClassWindow, kEventWindowActivated },
399     { kEventClassWindow, kEventWindowDeactivated },
400     { kEventClassWindow, kEventWindowZoomed },
401     { kEventClassWindow, kEventWindowCollapsed },
402     { kEventClassWindow, kEventWindowExpanded },
403     { kEventClassWindow, kEventWindowClose },
404     { kEventClassWindow, kEventWindowClosed },
405     { kEventClassWindow, kEventWindowDrawFrame },
406     { kEventClassWindow, kEventWindowDrawPart },
407
408     // kEventClassControl
409     { kEventClassControl, kEventControlApplyBackground },
410     
411     // kEventClassKeyboard
412     { kEventClassKeyboard, kEventRawKeyDown },
413     { kEventClassKeyboard, kEventRawKeyRepeat },
414     { kEventClassKeyboard, kEventRawKeyUp },
415     { kEventClassKeyboard, kEventRawKeyModifiersChanged },
416     
417     // kEventClassMouse
418     { kEventClassMouse, kEventMouseDown },
419     { kEventClassMouse, kEventMouseUp },
420     { kEventClassMouse, kEventMouseMoved },
421     { kEventClassMouse, kEventMouseDragged },
422     { kEventClassMouse, kEventMouseWheelMoved },
423 };
424     
425 static OSStatus windowEventHandler(EventHandlerCallRef handler, EventRef e, void *userData) {
426   Darwin$CarbonSurface *surface = (Darwin$CarbonSurface*)userData;
427   UInt32 eKind = WC(GetEventKind)(e);
428   UInt32 eClass = WC(GetEventClass)(e);
429   OSStatus r;
430   char* ec = (char*)&eClass;
431   if (surface == NULL) return eventNotHandledErr;
432     
433
434     switch(eClass) {
435         case kEventClassCommand:
436             switch(eKind) {
437                 // TODO: handle menu items
438             }
439             break;
440         case kEventClassKeyboard:
441             switch(eKind) {
442                 case kEventRawKeyDown:
443                 case kEventRawKeyRepeat: 
444                 case kEventRawKeyUp: {
445                     UInt32 keyCode;
446                     jstring js;
447                     
448                     r = WC(GetEventParameter)(e,kEventParamKeyCode,typeUInt32,NULL,sizeof(keyCode),NULL,&keyCode);
449                     checkStatus(r,"GetEventParameter");
450                     
451                     switch(keyCode) {
452                         // These values were obtained by experimentation. I can't find any constants for them
453                         // in the header files
454                         case 126: js = JvNewStringLatin1("up"); break;
455                         case 125: js = JvNewStringLatin1("down"); break;
456                         case 124: js = JvNewStringLatin1("right"); break;
457                         case 123: js = JvNewStringLatin1("left"); break;
458                         case 122: js = JvNewStringLatin1("f1"); break;
459                         case 120: js = JvNewStringLatin1("f2"); break;
460                         case 99:  js = JvNewStringLatin1("f3"); break;
461                         case 118: js = JvNewStringLatin1("f4"); break;
462                         case 96:  js = JvNewStringLatin1("f5"); break;
463                         case 97:  js = JvNewStringLatin1("f6"); break;
464                         case 98:  js = JvNewStringLatin1("f7"); break;
465                         case 100: js = JvNewStringLatin1("f8"); break;
466                         case 101: js = JvNewStringLatin1("f9"); break;
467                         case 109: js = JvNewStringLatin1("f10"); break;
468                         case 103: js = JvNewStringLatin1("f11"); break;
469                         case 111: js = JvNewStringLatin1("f12"); break;
470                         case 105: js = JvNewStringLatin1("f13"); break;
471                         case 114: js = JvNewStringLatin1("insert"); break;
472                         case 117: js = JvNewStringLatin1("delete"); break;
473                         case 116: js = JvNewStringLatin1("page_up"); break;
474                         case 121: js = JvNewStringLatin1("page_down"); break;
475                         case 115: js = JvNewStringLatin1("home"); break;
476                         case 119: js = JvNewStringLatin1("end"); break;
477                         case 71:  js = JvNewStringLatin1("num_lock"); break;
478                         case 53:  js = JvNewStringLatin1("escape"); break;
479                         case 51:  js = JvNewStringLatin1("back_space"); break;
480                         case 36:  js = JvNewStringLatin1("enter"); break;
481                         case 48:  js = JvNewStringLatin1("tab"); break;
482                         case 76:  js = JvNewStringLatin1("enter"); break; // number pad enter
483                         default: {                            
484                             UInt32 size;
485                             UInt32 modifiers = surface->modifiers;
486                             r = WC(GetEventParameter)(e,kEventParamKeyUnicodes,typeUnicodeText,NULL,0,&size,NULL);
487                             checkStatus(r,"GetEventParameter");
488                             if(size == 0 || (modifiers & controlKey && size>sizeof(UniChar))) return eventNotHandledErr;
489                             
490                             js = JvAllocString(size/sizeof(UniChar));
491                             UniChar *buf = (UniChar*)JvGetStringChars(js);
492                             r = WC(GetEventParameter)(e,kEventParamKeyUnicodes,typeUnicodeText,NULL,size,NULL,buf);
493                             checkStatus(r,"GetEventParameter");
494
495                             if(!buf[0]) return eventNotHandledErr; // shouldn't happen
496                             // odd, when the ctrl key is pressed a-"`" become 1-31, this brings them back to the corect values
497                             if(modifiers & controlKey && buf[0] < 32) buf[0] += 0x60;
498                             break;
499                         }
500                     }
501                     
502                     if(eKind == kEventRawKeyUp)
503                         surface->KeyReleased(js);
504                     else
505                         surface->KeyPressed(js);
506                     return noErr;
507                 }
508                 case kEventRawKeyModifiersChanged: {
509                     const static struct {
510                         UInt32 mask;
511                         jstring ibexKey;
512                     } modifiersTable[] = {
513                         { shiftKey,  JvNewStringLatin1("shift")     },
514                         { alphaLock, JvNewStringLatin1("caps_lock") },
515                         { controlKey,  JvNewStringLatin1("control")   },
516                         { optionKey,  JvNewStringLatin1("alt")       },
517                         { kEventKeyModifierNumLockMask,  JvNewStringLatin1("num_lock")  },
518                         { 0, 0 }                    
519                     };
520                     
521                     UInt32 oldModifiers = (UInt32) surface->modifiers;
522                     UInt32 newModifiers;
523                     r = WC(GetEventParameter)(e,kEventParamKeyModifiers,typeUInt32,NULL,sizeof(newModifiers),NULL,&newModifiers);
524                     checkStatus(r,"GetEventParameter");
525                     surface->modifiers = (jint) newModifiers;
526                     UInt32 changedModifiers = oldModifiers ^ newModifiers;
527                     
528                     for(int i=0;modifiersTable[i].mask;i++) {
529                         UInt32 mask = modifiersTable[i].mask;
530                         if(!(changedModifiers & mask)) continue;
531                         if(newModifiers & mask)
532                             surface->KeyPressed(modifiersTable[i].ibexKey);
533                         else
534                             surface->KeyReleased(modifiersTable[i].ibexKey);
535                     }
536                     return noErr;
537                 }
538             }
539             break;
540         case kEventClassMouse:
541             // The default handler gets first dibs on mouse events
542             // (this catches the titlebar, resize box, etc)
543             r = WC(CallNextEventHandler)(handler, e);
544             if(r != eventNotHandledErr && eKind != kEventMouseMoved && eKind != kEventMouseDragged) return r;
545             
546             switch(eKind) {
547                 case kEventMouseMoved:
548                 case kEventMouseDragged: {
549                     WindowRef window = (WindowRef) surface->rawWindowRef;
550                     Point p;
551                     Rect rect;
552                     
553                     r = WC(GetEventParameter)(e,kEventParamMouseLocation,typeQDPoint,NULL,sizeof(p),NULL,&p);
554                     checkStatus(r,"GetEventParameter");
555                     r = WC(GetWindowBounds)(window,kWindowContentRgn,&rect);
556                     checkStatus(r,"GetWindowBounds");
557                     surface->Move(p.h-rect.left,p.v-rect.top);
558                     return noErr;
559                 }
560                 case kEventMouseDown: 
561                 case kEventMouseUp: {
562                     EventMouseButton button;
563                     UInt32 clickCount;
564                     jint ibexButton;
565                     r = WC(GetEventParameter)(e,kEventParamMouseButton,typeMouseButton,NULL,sizeof(button),NULL,&button);
566                     checkStatus(r,"GetEventParameter");
567                     r = WC(GetEventParameter)(e,kEventParamClickCount,typeUInt32,NULL,sizeof(clickCount),NULL,&clickCount);
568                     checkStatus(r,"GetEventParameter");
569                     
570                     switch(button) {
571                         case kEventMouseButtonPrimary:   ibexButton = 1; break;
572                         case kEventMouseButtonSecondary: ibexButton = 2; break;
573                         case kEventMouseButtonTertiary:  ibexButton = 3; break;
574                         default: return noErr;
575                     }
576                     if(eKind == kEventMouseDown) {
577                         surface->Press(ibexButton);
578                     } else {
579                         surface->Release(ibexButton);
580                         while(clickCount > 1) {
581                             surface->DoubleClick(ibexButton);
582                             clickCount-=2;
583                         }
584                         if(clickCount) surface->Click(ibexButton);
585                     }
586                     return noErr;
587                 }
588                 case kEventMouseWheelMoved: {
589                     EventMouseWheelAxis axis;
590                     SInt32 delta;
591                     r = WC(GetEventParameter)(e,kEventParamMouseWheelAxis,typeMouseWheelAxis,NULL,sizeof(axis),NULL,&axis);
592                     checkStatus(r,"GetEventParameter");
593                     r = WC(GetEventParameter)(e,kEventParamMouseWheelDelta,typeSInt32,NULL,sizeof(delta),NULL,&delta);
594                     checkStatus(r,"GetEventParameter");
595                     switch(axis) {
596                       case kEventMouseWheelAxisX: surface->HScroll((jint)(40 * delta)); break;
597                       case kEventMouseWheelAxisY: surface->VScroll((jint)(40 * delta)); break;
598                     }
599                     return noErr;
600                 }
601             }
602             break;
603         
604         case kEventClassWindow: {
605             WindowRef window;
606             r = WC(GetEventParameter)(e,kEventParamDirectObject,typeWindowRef,NULL,sizeof(window),NULL,&window);
607             checkStatus(r,"kEventClassWindow/WC(GetEventParameter");
608             
609             if((RawData*)window != surface->rawWindowRef) Darwin::abort(JvNewStringLatin1("window != surface->window"));
610             
611             switch(eKind) {
612                 case kEventWindowBoundsChanging: {
613                     UInt32 attr;
614                     Rect rect;
615                     
616                     r = WC(GetEventParameter)(e,kEventParamAttributes,typeUInt32,NULL,sizeof(attr),NULL,&attr);
617                     checkStatus(r,"kEventWindowBoundsChanged/GetEventParameter");
618                     
619                     r = WC(GetEventParameter)(e,kEventParamCurrentBounds,typeQDRectangle,NULL,sizeof(rect),NULL,&rect);
620                     checkStatus(r,"kEventWindowBoundsChanging/GetEventParameter"); 
621                     
622                     if(attr & kWindowBoundsChangeSizeChanged) {
623                         jint w = rect.right-rect.left;
624                         jint h = rect.bottom-rect.top;
625                             
626                         blit_lock();
627                         
628                         surface->winWidth = w;
629                         surface->winHeight = h;
630                         surface->pendingResize = true;
631                         surface->needsReshape();
632                             
633                         blit_unlock();
634     
635                         surface->SizeChange(w,h);
636                         if(attr & kWindowBoundsChangeUserResize && surface->maximized)
637                                 surface->Maximized(false);
638                     }
639                     
640                     if(attr & kWindowBoundsChangeOriginChanged) {
641                         surface->PosChange(rect.left,rect.top);
642                     }
643                     
644                     return noErr;
645                 }
646                 case kEventWindowBoundsChanged: {
647                     UInt32 attr;
648                     r = WC(GetEventParameter)(e,kEventParamAttributes,typeUInt32,NULL,sizeof(attr),NULL,&attr);
649                     checkStatus(r,"kEventWindowBoundsChanged/GetEventParameter");
650                     
651                     if(attr & kWindowBoundsChangeSizeChanged) {
652                         blit_lock();
653
654                         surface->pendingResize = false;
655                         
656                         blit_signal();
657                         blit_unlock();
658                     }
659                     return noErr;
660                 }
661                 case kEventWindowActivated:
662                 case kEventWindowDeactivated: {
663                     surface->Focused(eKind == kEventWindowActivated);
664                     return noErr;
665                 }
666                 case kEventWindowZoomed: {
667                     surface->Maximized(true);
668                     return noErr;
669                 }
670                 case kEventWindowCollapsed: {
671                     surface->Minimized(true);
672                     return noErr;
673                 }
674                 case kEventWindowExpanded: {
675                     surface->Minimized(false);
676                     return noErr;
677                 }
678                 case kEventWindowClose: {
679                     surface->Close();
680                     return noErr;
681                 }
682                 case kEventWindowClosed: {
683                     GCJ$Retainer::release(surface);
684                     return noErr;
685                 }
686                 case kEventWindowUpdate: {
687                     fprintf(stderr,"kEventWindowUpdate: Should not be here\n");
688                     abort();
689                 }
690             }
691         }
692         break;
693     }
694     return eventNotHandledErr;
695 }
696
697 static OSStatus paintProc (
698    GDHandle device,
699    GrafPtr qdContext,
700    WindowRef window,
701    RgnHandle inClientPaintRgn,
702    RgnHandle outSystemPaintRgn,
703    void *userData
704 ) {
705     Darwin$CarbonSurface *surface = (Darwin$CarbonSurface*) userData;
706     Rect rect;
707     WC(GetRegionBounds)(inClientPaintRgn, &rect);
708     surface->Dirty(rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top);
709     return noErr;
710 }
711
712 void Darwin$CarbonSurface::natInit(jboolean framed) {
713     WindowRef window;
714     Rect rect;
715     WindowClass wc = framed ? kDocumentWindowClass : kPlainWindowClass;
716     // FIXME: unframed windows should appear in the window menu
717     // This probably needs a hack similar to whats in Cocoa.mm
718     WindowAttributes attr =  kWindowStandardHandlerAttribute|
719       (framed ? kWindowInWindowMenuAttribute|kWindowStandardDocumentAttributes|kWindowLiveResizeAttribute : 0);
720     OSStatus r;
721     rect.top = rect.left = 0;
722     rect.bottom = rect.right = 10;
723     winWidth = winHeight = 10;
724     
725     r = WC(CreateNewWindow)(wc, attr, &rect, &window);
726     checkStatus(r,"CreateNewWindow");
727
728     rawWindowRef = (RawData*) window;
729
730     GCJ$Retainer::retain(this); // Need to account for the EventHandlers pointer to us
731     
732     r = InstallWindowEventHandler(window,windowEventHandlerUPP,sizeof(eventTypeSpecs)/sizeof(EventTypeSpec),eventTypeSpecs,this,NULL);
733     checkStatus(r,"InstallWindowEventHandler");
734
735     r = WC(InstallWindowContentPaintProc)(window,paintProcUPP,kWindowPaintProcOptionsNone,this);
736     checkStatus(r,"InstallWindowContentPaintProc");
737     
738     WC(ShowWindow)(window);        
739 }
740
741 void Darwin$CarbonSurface::natDispose() {
742     WindowRef window = (WindowRef) rawWindowRef;
743     WC(DisposeWindow)(window);
744 }
745
746 void Darwin$CarbonSurface::natSetIcon(org::ibex::graphics::Picture *_p) {
747 }
748
749 void Darwin$CarbonSurface::natSetLocation() {
750     WindowRef window = (WindowRef) rawWindowRef;
751     Rect rect;
752     jint x = root->x;
753     jint y = root->y;
754     OSStatus r = WC(GetWindowBounds)(window,kWindowStructureRgn,&rect);
755     checkStatus(r,"GetWindowBounds");
756     rect.bottom = y + (rect.bottom - rect.top);
757     rect.right = x + (rect.right - rect.left);
758     rect.top = y;
759     rect.left = x;
760     r = WC(SetWindowBounds)(window,kWindowStructureRgn,&rect);
761     checkStatus(r,"SetWindowBounds");
762     r = WC(ConstrainWindowToScreen)(window,kWindowStructureRgn,kWindowConstrainMoveRegardlessOfFit,NULL,NULL);
763     checkStatus(r,"ConstrainWindowToScreen");
764 }
765
766 void Darwin$CarbonSurface::natSetSize(jint w, jint h) {
767     WindowRef window = (WindowRef) rawWindowRef;
768     Rect rect;
769     OSStatus r = WC(GetWindowBounds)(window,kWindowContentRgn,&rect);
770     checkStatus(r,"GetWindowBounds");
771     rect.bottom = rect.top + h;
772     rect.right = rect.left + w;
773     r = WC(SetWindowBounds)(window,kWindowContentRgn,&rect);
774     checkStatus(r,"SetWindowBounds");
775     r = WC(ConstrainWindowToScreen)(window,kWindowStructureRgn,kWindowConstrainMoveRegardlessOfFit,NULL,NULL);
776     checkStatus(r,"ConstrainWindowToScreen");
777 }
778
779 void Darwin$CarbonSurface::natSetLimits(jint minw, jint minh, jint maxw, jint maxh) {
780     WindowRef window = (WindowRef) rawWindowRef;
781     const int maxMax = 32767;
782     const int minMinW = 80;
783     const int minMinH = 20;
784     HISize min,max;
785     min.width  = minw > maxMax ? maxMax : (minw < minMinW ? minMinW : minw);
786     min.height = minh > maxMax ? maxMax : (minh < minMinH ? minMinH : minh);
787     max.width  = maxw > maxMax ? maxMax : (maxw < minMinW ? minMinW : maxw);
788     max.height = maxh > maxMax ? maxMax : (maxh < minMinH ? minMinH : maxh);
789     OSStatus r = WC(SetWindowResizeLimits)(window,&min,&max);
790     checkStatus(r,"SetWindowResizeLimits");
791 }
792
793
794 #pragma mark ------ Carbon Methods ------
795 void fileDialogEventHandler(NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, void *userData) {
796     Darwin$FileDialogHelper *helper = (Darwin$FileDialogHelper*) userData;
797     NavDialogRef dialog = callBackParms->context;
798     OSStatus r;
799     switch(callBackSelector) {
800         case kNavCBUserAction: {
801             NavUserAction action = WC(NavDialogGetUserAction)(dialog);
802             if(action == kNavUserActionNone || action == kNavUserActionCancel) {
803                 helper->fileName = 0;
804             } else {
805                 NavReplyRecord reply;
806                 r = WC(NavDialogGetReply)(dialog,&reply);
807                 checkStatus(r,"NavDialogGetReply");
808
809                 AEKeyword keyword;
810                 FSRef ref;
811                 char buf[4096];
812                 r = WC(AEGetNthPtr)(&reply.selection,1,typeFSRef,&keyword,NULL,&ref,sizeof(ref),NULL);
813                 checkStatus(r,"AEGetNthPtr");
814                 r = WC(FSRefMakePath)(&ref,(UInt8*)buf,sizeof(buf)-1);
815                 checkStatus(r,"FSRefMakePath");
816                 helper->fileName = JvNewStringLatin1(buf);
817                 if(helper->save) helper->saveName = cfStringToJString(reply.saveFileName);
818                 r = WC(NavDisposeReply)(&reply);
819                 checkStatus(r,"NavDialogGetReply");
820             }
821             helper->sem->release();
822             break;
823         }
824         case kNavCBTerminate:
825             WC(NavDialogDispose)(dialog);
826             break;
827     }
828 }
829
830 void Darwin::natFileDialog(Darwin$FileDialogHelper *helper,jstring suggestion_, jboolean write) {
831     NavDialogRef dlg;
832     SmartCFString suggestion = suggestion_;
833     CFStringRef message = CFSTR("By selecting a file in this dialog you are giving this Ibex application permission to access that file.");
834     OSStatus r;
835     WindowRef window = WC(FrontWindow)();
836     NavDialogCreationOptions options;
837     
838     WC(NavGetDefaultDialogCreationOptions)(&options);
839     options.optionFlags =
840         (options.optionFlags|kNavAllFilesInPopup|kNavSelectAllReadableItem|kNavDontUseCustomFrame|kNavDontConfirmReplacement)
841         &~(kNavAllowStationery|kNavAllowMultipleFiles);
842     options.clientName = CFSTR("Ibex");
843     if(write)
844         options.saveFileName  = suggestion;
845     options.message = message;
846     options.modality = window ? kWindowModalityWindowModal : kWindowModalityAppModal;
847     options.parentWindow = window;
848     
849     if(write)
850         r = WC(NavCreatePutFileDialog)(&options,0,0,fileDialogEventHandlerUPP,helper,&dlg);
851     else
852         r = WC(NavCreateGetFileDialog)(&options,NULL,fileDialogEventHandlerUPP,NULL,NULL,helper,&dlg);
853     checkStatus(r,"NavCreate(Get/Put)FileDialog");
854     
855     WC(NavDialogRun)(dlg);
856 }
857
858 jstring Darwin::natGetClipBoard() {
859     ScrapRef scrap;
860     OSStatus r;
861     Size size,size2;
862
863     r = WC(GetCurrentScrap)(&scrap);
864     checkStatus(r,"GetCurrentScrap");
865     
866     r = WC(GetScrapFlavorSize)( scrap, kScrapFlavorTypeUnicode, &size);
867     if(r == scrapFlavorNotFoundErr) return JvNewStringLatin1("");
868     checkStatus(r,"GetScrapFlavorSize");
869     
870     unsigned int length = size/sizeof(UniChar);
871     
872     jstring js = JvAllocString(length);
873     UniChar *buf = (UniChar*) JvGetStringChars(js);
874     size2 = size;
875     r = WC(GetScrapFlavorData)(scrap,kScrapFlavorTypeUnicode,&size2,buf);
876     if(r == scrapFlavorNotFoundErr);
877     checkStatus(r,"GetScrapFlavorData");
878     if(size2 != size) return JvNewStringLatin1("");
879     
880     return js;
881 }
882
883 void Darwin::natSetClipBoard(jstring js) {
884     unsigned int length = js->length();
885     ScrapRef scrap;
886     OSStatus r;
887
888     r = WC(GetCurrentScrap)(&scrap);
889     checkStatus(r,"GetCurrentScrap");
890     
891     r = WC(PutScrapFlavor)(scrap,kScrapFlavorTypeUnicode,0,sizeof(UniChar)*length,JvGetStringChars(js));
892     checkStatus(r,"PutScrapFlavor");
893 }
894
895 org::ibex::net::HTTP$Proxy *Darwin::natDetectProxy() {
896     org::ibex::net::HTTP$Proxy *p=0;
897     CFStringRef string;
898     CFNumberRef number;
899     SmartCFString smartString;
900     CFArrayRef exceptionList;
901     int i;
902     
903     CFDictionaryRef proxyInfo = WC(SCDynamicStoreCopyProxies)(NULL);
904     if(proxyInfo == NULL) return 0;
905     
906 #define doproto(proto,var) \
907     number = (CFNumberRef) WC(CFDictionaryGetValue)(proxyInfo,kSCPropNetProxies ## proto ## Enable);    \
908     if(number != NULL && WC(CFGetTypeID)(number) != WC(CFNumberGetTypeID)()) number = NULL;                 \
909     if(number && WC(CFNumberGetValue)(number,kCFNumberIntType,&i) && i) {                               \
910         string = (CFStringRef) WC(CFDictionaryGetValue)(proxyInfo, kSCPropNetProxies ## proto ## Proxy);\
911         if(string != NULL && WC(CFGetTypeID)(string) != WC(CFStringGetTypeID)()) string = NULL;             \
912         number = (CFNumberRef) WC(CFDictionaryGetValue)(proxyInfo, kSCPropNetProxies ## proto ## Port); \
913         if(number != NULL && WC(CFGetTypeID)(number) != WC(CFNumberGetTypeID)()) number = NULL;    \
914         if(string && number && WC(CFNumberGetValue)(number,kCFNumberIntType,&i) && i) {        \
915             if(!p) p = new org::ibex::net::HTTP$Proxy();                                                        \
916             p->var ## ProxyHost = cfStringToJString(string);                           \
917             p->var ## ProxyPort = i;                                                   \
918         }                                                                                  \
919     }                                                                                      
920 doproto(HTTP,http)
921 doproto(HTTPS,https)
922 doproto(SOCKS,socks)
923 #undef doproto
924
925     exceptionList = (CFArrayRef) WC(CFDictionaryGetValue)(proxyInfo,kSCPropNetProxiesExceptionsList);
926     if(exceptionList != NULL && WC(CFGetTypeID)(exceptionList) != WC(CFArrayGetTypeID)()) exceptionList = NULL;
927     if(p && exceptionList && WC(CFArrayGetCount)(exceptionList)) {
928         CFIndex count = WC(CFArrayGetCount)(exceptionList);
929         p->excluded = (JArray<java::lang::String*>*)
930             JvNewObjectArray(count,&java::lang::String::class$,0);
931         for(i=0;i<count;i++) {
932             string = (CFStringRef) WC(CFArrayGetValueAtIndex)(exceptionList,i);
933             if(string != NULL && WC(CFGetTypeID)(string) != WC(CFStringGetTypeID)()) string = NULL;
934             elements(p->excluded)[i] = string ? cfStringToJString(string) : JvNewStringLatin1("(null)");
935         }
936     }
937     WC(CFRelease)(proxyInfo);
938     
939     return p;
940 /*
941     exceptionList = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesExceptionsList];
942     if(p && exceptionList && [exceptionList count]) {
943         NSLog(@"excl: %@",exceptionList);
944         p->excluded = (JArray<java::lang::String*>*)
945             JvNewObjectArray([exceptionList count],&java::lang::String::class$,0);
946         for(i=0;i<[exceptionList count];i++)
947             elements(p->excluded)[i] = [[exceptionList objectAtIndex: i] jstring];
948     }
949     return p;
950     */    
951             
952 /*
953     using org::ibex::Proxy;
954     AutoARP pool;
955     Proxy *p=0;
956     NSString *host;
957     NSNumber *port;
958     NSArray *exceptionList;
959     unsigned int i;
960     NSDictionary *proxyInfo = (NSDictionary*)WC(SCDynamicStoreCopyProxies)(NULL);
961     
962     if(proxyInfo == NULL) return 0;
963     if([[proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPEnable] boolValue]) {
964         host = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPProxy];
965         port = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPPort];
966         if(host && [port intValue]) {
967             if(!p) p = new Proxy();
968             p->httpProxyHost = [host jstring];
969             p->httpProxyPort = [port intValue];
970         }
971     }
972     if([[proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPSEnable] boolValue]) {
973         host = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPSProxy];
974         port = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPSPort];
975         if(host && [port intValue]) {
976             if(!p) p = new Proxy();
977             p->httpsProxyHost = [host jstring];
978             p->httpsProxyPort = [port intValue];
979         }
980     }
981     if([[proxyInfo objectForKey: (NSString*) kSCPropNetProxiesSOCKSEnable] boolValue]) {
982         host = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesSOCKSProxy];
983         port = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesSOCKSPort];
984         if(host && [port intValue]) {
985             if(!p) p = new Proxy();
986             p->socksProxyHost = [host jstring];
987             p->socksProxyPort = [port intValue];
988         }
989     }
990    
991     exceptionList = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesExceptionsList];
992     if(p && exceptionList && [exceptionList count]) {
993         NSLog(@"excl: %@",exceptionList);
994         p->excluded = (JArray<java::lang::String*>*)
995             JvNewObjectArray([exceptionList count],&java::lang::String::class$,0);
996         for(i=0;i<[exceptionList count];i++)
997             elements(p->excluded)[i] = [[exceptionList objectAtIndex: i] jstring];
998     }
999     return p;
1000 */
1001 }
1002
1003 jint Darwin::cgScreenWidth() {
1004     return WC(CGDisplayPixelsWide)(((CGDirectDisplayID)0));
1005 }
1006
1007 jint Darwin::cgScreenHeight() {
1008     return WC(CGDisplayPixelsHigh)(((CGDirectDisplayID)0));
1009 }
1010
1011 void Darwin::_newBrowserWindow(jstring js) {
1012     SmartCFString cfs = js;
1013     CFURLRef url = WC(CFURLCreateWithString)(WC(kCFAllocatorDefault),cfs,NULL);
1014     SmartCFString scheme = WC(CFURLCopyScheme)(url);
1015     if(scheme.equals(CFStringRef("http")))
1016         WC(LSOpenCFURLRef)(url,NULL);
1017     WC(CFRelease)(url);
1018 }
1019
1020 void Darwin::natInit() {     
1021     OSStatus r;
1022     
1023     if(pthread_mutex_init(&blit_mutex,NULL) != 0) funcFailed("pthread_mutex_init");
1024     if(pthread_cond_init(&blit_cond,NULL) != 0) funcFailed("pthread_cond_init");
1025     
1026     carbonMessageEventHandlerUPP = WC(NewEventHandlerUPP)(carbonMessageEventHandler);
1027     windowEventHandlerUPP = WC(NewEventHandlerUPP)(windowEventHandler);
1028     fileDialogEventHandlerUPP = WC(NewNavEventUPP)(fileDialogEventHandler);
1029     paintProcUPP = WC(NewWindowPaintUPP)(paintProc);
1030
1031     #ifdef Ibex_CARBON_NO_BUNDLE_HACK
1032     {        
1033         ProcessSerialNumber currentProcess = { 0, kCurrentProcess };
1034         
1035         ::fprintf(stderr,"Doing Ibex_CARBON_NO_BUNDLE_HACK\n");
1036         r = WC(GetCurrentProcess)(&currentProcess);
1037         checkStatus(r,"GetCurrentProcess");
1038         r = WC(CPSEnableForegroundOperation)( &currentProcess );
1039         checkStatus(r,"CPSEnableForegroundOperation");
1040         r = WC(CPSSetFrontProcess)(&currentProcess);
1041         checkStatus(r,"CPSSetFrontProcess");        
1042     }
1043     #else
1044     {
1045         IBNibRef nib;
1046         r = CreateNibReference(CFSTR("MainMenu"), &nib);
1047         checkStatus(r,"CreateNibReference");
1048         r = SetMenuBarFromNib(nib, CFSTR("MenuBar"));
1049         checkStatus(r,"SetMenuBarFromNib");
1050         DisposeNibReference(nib);
1051         
1052         // FEATURE: Install menu event handler
1053     }
1054     #endif
1055 }
1056
1057 void Darwin::runApplicationEventLoop() {
1058     WC(RunApplicationEventLoop)();
1059     WC(ExitToShell)();
1060 }
1061
1062 #pragma mark ------ OpenGL Functions -----
1063
1064 void Darwin$CarbonOpenGL::activateSharedContext() {
1065     AGLContext ctx = (AGLContext) rawSharedContext;
1066     WC(aglSetCurrentContext)(ctx);
1067 }
1068
1069 jboolean Darwin$CarbonOpenGL::initPixelFormat() {
1070     GLint attr[] = {
1071         AGL_NO_RECOVERY,
1072         AGL_RGBA,
1073         AGL_DEPTH_SIZE, 32,
1074         AGL_RED_SIZE, 8,
1075         AGL_GREEN_SIZE, 8,
1076         AGL_RED_SIZE, 8,
1077         AGL_ALPHA_SIZE, 8,
1078         AGL_NONE
1079     };
1080     
1081     rawPixelFormat = (RawData*) WC(aglChoosePixelFormat)(NULL,0,attr);
1082     return rawPixelFormat != 0;
1083 }
1084
1085 void Darwin$CarbonOpenGL::initSharedContext() {
1086     AGLPixelFormat fmt =  (AGLPixelFormat) rawPixelFormat;
1087     rawSharedContext = (RawData*) WC(aglCreateContext)(fmt,NULL);
1088     checkStatus(rawSharedContext,"aglCreateContext");
1089 }
1090
1091 void Darwin$GLCarbonPixelBuffer::natInit() {
1092     WindowClass wc = kPlainWindowClass;
1093     WindowAttributes attr = 0;
1094     WindowRef window;
1095     Rect rect;
1096     OSStatus r;
1097     AGLContext ctx,shared;
1098     AGLPixelFormat fmt;
1099     GLboolean b;
1100     GLuint tex;
1101     GLuint target;
1102     
1103     rect.top = rect.left = 0;
1104     rect.right = width + rect.left;
1105     rect.bottom = height + rect.top; 
1106     
1107     r = WC(CreateNewWindow)(wc,attr,&rect,&window);
1108     checkStatus(r,"CreateNewWindow");
1109         
1110     shared = (AGLContext) gl->rawSharedContext;
1111     fmt = (AGLPixelFormat) gl->rawPixelFormat;
1112     ctx = WC(aglCreateContext)(fmt,shared);
1113     checkStatus(ctx, "aglCreateContext");
1114     
1115     b = WC(aglSetDrawable)(ctx,WC(GetWindowPort)(window));
1116     checkStatus(b,"aglSetDrawable");
1117     
1118     WC(aglSetCurrentContext)(ctx);
1119     WC(aglUpdateContext)(ctx);
1120     drawableInit(width,height);
1121     glClear(GL_COLOR_BUFFER_BIT);
1122
1123     WC(aglSetCurrentContext)(shared);
1124     target = rectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D;
1125     glEnable(target);
1126     glGenTextures(1,&tex);
1127     glBindTexture(target,tex);
1128     glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1129     glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1130     WC(aglSurfaceTexture) (shared, target, GL_RGBA, ctx);
1131     checkGLError();
1132     glDisable(target);
1133     
1134     //WC(ShowWindow)(window);
1135     textureName = (jint) tex;
1136     rawWindowRef = (RawData*) window;
1137     rawCTX = (RawData*) ctx;
1138 }
1139
1140 void Darwin$GLCarbonPixelBuffer::activateContext() {
1141     AGLContext ctx = (AGLContext) rawCTX;
1142     WC(aglSetCurrentContext)(ctx);
1143 }
1144
1145 void Darwin$GLCarbonPixelBuffer::natCleanup(RawData* rawWindowRef, RawData* rawCTX) {
1146     WindowRef window = (WindowRef) rawWindowRef;
1147     AGLContext ctx = (AGLContext) rawCTX;
1148     WC(aglDestroyContext)(ctx);
1149     WC(DisposeWindow)(window);
1150 }
1151
1152 void Darwin$GLCarbonSurface::clear() {
1153     AGLContext ctx = (AGLContext) rawCTX;
1154     WC(aglSetCurrentContext)(ctx);
1155     glColor4f(1.0f,1.0f,1.0f,1.0f);
1156
1157     glMatrixMode (GL_MODELVIEW);
1158     glPushMatrix ();
1159     glLoadIdentity ();
1160     glMatrixMode (GL_PROJECTION);
1161     glPushMatrix ();
1162     glLoadIdentity ();
1163     glBegin (GL_QUADS);
1164     glVertex3i (-1, -1, -1);
1165     glVertex3i (1, -1, -1);
1166     glVertex3i (1, 1, -1);
1167     glVertex3i (-1, 1, -1);
1168     glEnd ();
1169     glPopMatrix ();
1170     glMatrixMode (GL_MODELVIEW);
1171     glPopMatrix ();
1172 }
1173
1174 void Darwin$GLCarbonSurface::flush() {
1175     AGLContext ctx = (AGLContext) rawCTX;
1176     WC(aglSetCurrentContext)(ctx);
1177     glFlush();
1178 }
1179
1180 // blit_lock is assumed to be held
1181 void Darwin$GLCarbonSurface::reshape(jint w, jint h) {
1182     AGLContext ctx = (AGLContext) rawCTX;
1183     WC(aglSetCurrentContext)(ctx);
1184     WC(aglUpdateContext)(ctx);
1185     
1186     glViewport(0,0,w,h);
1187     glMatrixMode(GL_PROJECTION);
1188     glLoadIdentity(); 
1189     glOrtho(0,w,h,0,-1,1);   
1190     glMatrixMode(GL_MODELVIEW);
1191     glLoadIdentity();
1192     glTranslatef (0.375f, 0.375f, 0.0f);
1193     checkGLError();
1194 }
1195
1196 // blit_lock is assumed to be held
1197 void Darwin$GLCarbonSurface::natBlit(Darwin$GLCarbonPixelBuffer *db, jint sx1, jint sy1, jint dx1, jint dy1, jint dx2, jint dy2) {
1198     AGLContext ctx = (AGLContext) rawCTX;
1199     int sx2 = sx1 + (dx2-dx1);
1200     int sy2 = sy1 + (dy2-dy1);
1201     jint w, h;
1202     db->activateContext();
1203     glFlush();
1204     checkGLError();
1205
1206     WC(aglSetCurrentContext)(ctx);
1207     checkGLError();
1208         
1209     if(db->rectTexture) {
1210         glEnable(GL_TEXTURE_RECTANGLE_EXT);
1211         checkGLError();
1212         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, db->textureName);
1213         checkGLError();
1214         glBegin(GL_QUADS); 
1215             glTexCoord2i (sx1, sy1   );
1216             glVertex3i   (dx1, dy1, 0);   
1217             glTexCoord2i (sx2, sy1   ); 
1218             glVertex3i   (dx2, dy1, 0);
1219             glTexCoord2i (sx2, sy2   ); 
1220             glVertex3i   (dx2, dy2, 0);
1221             glTexCoord2i (sx1, sy2   );
1222             glVertex3i   (dx1, dy2, 0);
1223         glEnd();
1224         checkGLError();
1225         glDisable(GL_TEXTURE_RECTANGLE_EXT);
1226         checkGLError();
1227     } else {
1228         float tx1,ty1,tx2,ty2; // normalized texture coords
1229         tx1 = (float) sx1 / (float) db->width;
1230         ty1 = (float) sy1 / (float) db->height;
1231         tx2 = (float) sx2 / (float) db->width;
1232         ty2 = (float) sy2 / (float) db->height;
1233
1234         glColor4f(1.0f,1.0f,1.0f,1.0f);
1235         glEnable(GL_TEXTURE_2D);
1236         glBindTexture(GL_TEXTURE_2D, db->textureName);    
1237         checkGLError();
1238         glBegin(GL_QUADS); 
1239             glTexCoord2f (tx1, ty1   );
1240             glVertex3i   (dx1, dy1, 0);
1241             glTexCoord2f (tx2, ty1   ); 
1242             glVertex3i   (dx2, dy1, 0);
1243             glTexCoord2f (tx2, ty2   ); 
1244             glVertex3i   (dx2, dy2, 0);
1245             glTexCoord2f (tx1, ty2   );
1246             glVertex3i   (dx1, dy2, 0);
1247         glEnd();
1248         glDisable(GL_TEXTURE_2D);
1249         checkGLError();
1250     }
1251 }
1252
1253 void Darwin$GLCarbonSurface::natInit() {
1254     WindowRef window = (WindowRef) rawWindowRef;
1255     AGLContext ctx,shared;
1256     AGLPixelFormat fmt;
1257     GLboolean b;
1258     
1259     shared = (AGLContext) gl->rawSharedContext;
1260     fmt = (AGLPixelFormat) gl->rawPixelFormat;
1261     ctx = WC(aglCreateContext)(fmt,shared);
1262     checkStatus(ctx, "aglCreateContext");
1263     
1264     b = WC(aglSetDrawable)(ctx,WC(GetWindowPort)(window));
1265     checkStatus(b,"aglSetDrawable");    
1266
1267     WC(aglSetCurrentContext)(ctx);
1268     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
1269     
1270     glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
1271     glClearDepth( 0.0f );
1272     
1273     needsReshape();
1274     
1275     rawCTX = (RawData*)ctx;
1276 }
1277
1278 void Darwin$GLCarbonSurface::natDispose() {
1279     AGLContext ctx = (AGLContext) rawCTX;
1280     WC(aglDestroyContext)(ctx);
1281     Darwin$CarbonSurface::natDispose();
1282 }
1283
1284 } } } // end namepsace org::ibex::plat
1285
1286
1287