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