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