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