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