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