1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [LGPL]
2 // Authors: Brian Alliet and Evan Jones
10 #define __private_extern__
11 #include <mach-o/dyld.h>
12 //#include <objc/objc-runtime.h>
13 //#include <objc/hashtable.h>
18 #include <java/lang/Object.h>
19 #include <java/lang/Error.h>
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>
34 #include "DarwinCarbonHeaders.h"
36 #define XWT_CARBON_NO_BUNDLE_HACK
37 #ifdef XWT_CARBON_NO_BUNDLE_HACK
39 OSErr CPSEnableForegroundOperation(ProcessSerialNumber *psn);
40 OSErr CPSSetFrontProcess(ProcessSerialNumber *psn);
44 #include "DarwinWeakSymbols.h"
46 using namespace org::xwt::plat;
47 using gnu::gcj::RawData;
48 using org::xwt::util::Semaphore;
49 using java::lang::Object;
51 namespace org { namespace xwt { namespace plat {
54 using namespace darwin;
56 #pragma mark ------ Darwin Namespace ------
58 // We put everything that isn't in org.xwt.plat.Darwin in
59 // org.xwt.plat.darwin to prevent namespace conflicts
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)>();
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); }
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);
79 #pragma mark ------ SmartCFString ------
83 void release() { if(p) CFRelease(p); }
84 void checkNull() { if(!p) throw new java::lang::Error(JvNewStringLatin1("CFString function failed")); }
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; }
92 ~SmartCFString() { release(); }
94 SmartCFString& operator= (const char *s) {
97 p = CFStringCreateWithCString(kCFAllocatorDefault,s,kCFStringEncodingISOLatin1);
101 SmartCFString& operator= (jstring js) {
102 if(!js) return *this = "(null)";
104 UniChar *buf = (UniChar*) JvGetStringChars(js);
105 CFIndex length = js->length();
106 p = CFStringCreateWithCharacters(kCFAllocatorDefault,buf,length);
110 SmartCFString& operator= (CFStringRef cf) {
111 if(cf == NULL) return *this = "(null)";
116 operator CFStringRef() { return p; }
117 operator jstring() { return getJString(); }
119 jstring getJString() { return cfStringToJString(p); }
121 bool equals(const char *s) {
122 SmartCFString cfs(s);
126 bool equals(CFStringRef cfs) {
127 return CFStringCompare(p,cfs,0) == kCFCompareEqualTo;
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';
136 OSStatus our_carbonMessageEventHandler(EventHandlerCallRef handler, EventRef e, void *userData);
137 void fileDialogEventHandler(NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, void *userData);
141 jboolean Darwin::isJaguar() {
143 OSStatus r = Gestalt(gestaltSystemVersion, &version);
144 checkStatus(r,"Gestalt");
145 return version >= 0x1020;
148 void Darwin::linkMe() {
152 void Darwin$CarbonMessage::natInit() {
155 EventHandlerUPP upp = NewEventHandlerUPP(our_carbonMessageEventHandler);
156 EventTypeSpec eventTypes = { kEventClassCarbonMessage, kEventCarbonMessage };
157 r = InstallEventHandler(GetApplicationEventTarget(),upp,1,&eventTypes,NULL,NULL);
158 checkStatus(r,"InstallEventHandler");
161 void Darwin$CarbonMessage::add(Darwin$CarbonMessage *msg) {
165 GCJ$Retainer::retain(msg);
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");
177 OSStatus our_carbonMessageEventHandler(EventHandlerCallRef handler, EventRef e, void *userData) {
178 UInt32 eKind = GetEventKind(e);
179 UInt32 eClass = GetEventClass(e);
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");
187 GCJ$Retainer::release(msg);
192 #pragma mark ------ Utility Functions ------
194 void funcFailed(char *func,int r){
195 fprintf(stderr,"%s() failed (%d)\n",func,r);
199 #pragma mark ------ CarbonPicture Methods ------
201 #pragma mark ----- Carbon Surface Methods ----
204 void Darwin$CarbonSurface::natSyncCursor(jint n) {
206 // see Carbon.java for what these numbers mean
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;
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);
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");
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");
240 void Darwin$CarbonSurface::natSetTitleBarText(jstring js) {
241 SmartCFString s = js;
242 WindowRef window = (WindowRef) rawWindowRef;
243 SetWindowTitleWithCFString(window,s);
246 void Darwin$CarbonSurface::natToBack() {
247 WindowRef window = (WindowRef) rawWindowRef;
248 SendBehind(window,NULL);
251 void Darwin$CarbonSurface::natToFront() {
252 WindowRef window = (WindowRef) rawWindowRef;
253 fprintf(stderr,"SelectWindow()\n");
254 SelectWindow(window);
257 #pragma mark ---- Window Event Handler ----
259 static const EventTypeSpec eventTypeSpecs[] = {
260 // kEventClassCommand
261 // { kEventClassCommand, ??? },
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 },
274 // kEventClassKeyboard
275 { kEventClassKeyboard, kEventRawKeyDown },
276 { kEventClassKeyboard, kEventRawKeyRepeat },
277 { kEventClassKeyboard, kEventRawKeyUp },
278 { kEventClassKeyboard, kEventRawKeyModifiersChanged },
281 { kEventClassMouse, kEventMouseDown },
282 { kEventClassMouse, kEventMouseUp },
283 { kEventClassMouse, kEventMouseMoved },
284 { kEventClassMouse, kEventMouseDragged },
285 { kEventClassMouse, kEventMouseWheelMoved },
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);
295 case kEventClassCommand:
297 // TODO: handle menu items
300 case kEventClassKeyboard:
302 case kEventRawKeyDown:
303 case kEventRawKeyRepeat:
304 case kEventRawKeyUp: {
308 r = GetEventParameter(e,kEventParamKeyCode,typeUInt32,NULL,sizeof(keyCode),NULL,&keyCode);
309 checkStatus(r,"GetEventParameter");
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
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;
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");
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;
362 if(eKind == kEventRawKeyUp)
363 surface->KeyReleased(js);
365 surface->KeyPressed(js);
368 case kEventRawKeyModifiersChanged: {
369 const static struct {
372 } modifiersTable[] = {
373 { shiftKey, JvNewStringLatin1("shift") },
374 { alphaLock, JvNewStringLatin1("caps_lock") },
375 { controlKey, JvNewStringLatin1("control") },
376 { optionKey, JvNewStringLatin1("alt") },
377 { kEventKeyModifierNumLockMask, JvNewStringLatin1("num_lock") },
381 UInt32 oldModifiers = (UInt32) surface->modifiers;
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;
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);
394 surface->KeyReleased(modifiersTable[i].xwtKey);
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;
407 case kEventMouseMoved:
408 case kEventMouseDragged: {
409 WindowRef window = (WindowRef) surface->rawWindowRef;
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);
420 case kEventMouseDown:
421 case kEventMouseUp: {
422 EventMouseButton button;
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");
431 case kEventMouseButtonPrimary: xwtButton = 1; break;
432 case kEventMouseButtonSecondary: xwtButton = 2; break;
433 case kEventMouseButtonTertiary: xwtButton = 3; break;
434 default: return noErr;
436 if(eKind == kEventMouseDown) {
437 surface->Press(xwtButton);
439 surface->Release(xwtButton);
440 while(clickCount > 1) {
441 surface->DoubleClick(xwtButton);
444 if(clickCount) surface->Click(xwtButton);
448 case kEventMouseWheelMoved: {
449 EventMouseWheelAxis axis;
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
463 case kEventClassWindow: {
465 r = GetEventParameter(e,kEventParamDirectObject,typeWindowRef,NULL,sizeof(window),NULL,&window);
466 checkStatus(r,"kEventClassWindow/GetEventParameter");
468 if((RawData*)window != surface->rawWindowRef) Darwin::abort(JvNewStringLatin1("window != surface->window"));
471 case kEventWindowUpdate: {
472 surface->Dirty(0,0,surface->root->width,surface->root->height);
475 case kEventWindowBoundsChanged: {
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();
492 if(attr & kWindowBoundsChangeOriginChanged) {
493 surface->PosChange(rect.left,rect.top);
497 case kEventWindowActivated:
498 case kEventWindowDeactivated: {
499 surface->Focused(eKind == kEventWindowActivated);
502 case kEventWindowZoomed: {
503 fprintf(stderr,"Zoomed....\n");
504 surface->Maximized(true);
507 case kEventWindowCollapsed: {
508 surface->Minimized(true);
511 case kEventWindowExpanded: {
512 surface->Minimized(false);
515 case kEventWindowClose: {
519 case kEventWindowClosed: {
520 DisposeEventHandlerUPP((EventHandlerUPP)surface->rawEventHandlerUPP);
521 GCJ$Retainer::release(surface);
528 return eventNotHandledErr;
532 void Darwin$CarbonSurface::natInit(jboolean framed) {
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);
542 rect.top = 0; rect.left = 0; rect.bottom = 10; rect.right=10;
543 r = CreateNewWindow(wc,attr,&rect,&window);
544 checkStatus(r,"CreateNewWindow");
548 Class NSWindowClass = NSClassFromString
549 NSWindowClass->methodLists
551 void *iterator = 0; // Method list (category) iterator
552 struct objc_method_list* mlist;
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);
567 GCJ$Retainer::retain(this); // Need to account for the EventHandlers pointer to us
568 EventHandlerUPP upp = NewEventHandlerUPP(our_windowEventHandler);
570 r = InstallWindowEventHandler(window,upp,sizeof(eventTypeSpecs)/sizeof(EventTypeSpec),eventTypeSpecs,this,NULL);
571 checkStatus(r,"InstallWindowEventHandler");
573 rawWindowRef = (RawData*) window;
574 rawEventHandlerUPP = (RawData*) upp;
577 void Darwin$CarbonSurface::natDispose() {
578 WindowRef window = (WindowRef) rawWindowRef;
579 DisposeWindow(window);
582 void Darwin$CarbonSurface::natSetIcon(org::xwt::Picture *_p) {
585 void Darwin$CarbonSurface::natSetLocation(jint x, jint y) {
586 WindowRef window = (WindowRef) rawWindowRef;
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);
594 r = SetWindowBounds(window,kWindowStructureRgn,&rect);
595 checkStatus(r,"SetWindowBounds");
596 r = ConstrainWindowToScreen(window,kWindowStructureRgn,kWindowConstrainMoveRegardlessOfFit,NULL,NULL);
597 checkStatus(r,"ConstrainWindowToScreen");
600 void Darwin$CarbonSurface::natSetSize(jint w, jint h) {
601 WindowRef window = (WindowRef) rawWindowRef;
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");
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;
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");
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;
633 switch(callBackSelector) {
634 case kNavCBUserAction: {
635 NavUserAction action = NavDialogGetUserAction(dialog);
636 if(action == kNavUserActionNone || action == kNavUserActionCancel) {
637 helper->fileName = 0;
639 NavReplyRecord reply;
640 r = NavDialogGetReply(dialog,&reply);
641 checkStatus(r,"NavDialogGetReply");
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");
655 helper->sem->release();
658 case kNavCBTerminate:
659 DisposeNavEventUPP((NavEventUPP)helper->rawUPP);
660 NavDialogDispose(dialog);
665 void Darwin::natFileDialog(Darwin$FileDialogHelper *helper,jstring suggestion_, jboolean write) {
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.");
670 WindowRef window = FrontWindow();
671 NavDialogCreationOptions options;
673 NavEventUPP handler = NewNavEventUPP(fileDialogEventHandler);
675 NavGetDefaultDialogCreationOptions(&options);
676 options.optionFlags =
677 (options.optionFlags|kNavAllFilesInPopup|kNavSelectAllReadableItem|kNavDontUseCustomFrame|kNavDontConfirmReplacement)
678 &~(kNavAllowStationery|kNavAllowMultipleFiles);
679 options.clientName = CFSTR("XWT");
681 options.saveFileName = suggestion;
682 options.message = message;
683 options.modality = window ? kWindowModalityWindowModal : kWindowModalityAppModal;
684 options.parentWindow = window;
687 r = NavCreatePutFileDialog(&options,0,0,handler,helper,&dlg);
689 r = NavCreateGetFileDialog(&options,NULL,handler,NULL,NULL,helper,&dlg);
690 checkStatus(r,"NavCreate(Get/Put)FileDialog");
692 helper->rawUPP = (RawData*)handler;
696 jstring Darwin::natGetClipBoard() {
701 r = GetCurrentScrap(&scrap);
702 checkStatus(r,"GetCurrentScrap");
704 r = GetScrapFlavorSize( scrap, kScrapFlavorTypeUnicode, &size);
705 if(r == scrapFlavorNotFoundErr) return JvNewStringLatin1("");
706 checkStatus(r,"GetScrapFlavorSize");
708 unsigned int length = size/sizeof(UniChar);
710 jstring js = JvAllocString(length);
711 UniChar *buf = (UniChar*) JvGetStringChars(js);
713 r = GetScrapFlavorData(scrap,kScrapFlavorTypeUnicode,&size2,buf);
714 if(r == scrapFlavorNotFoundErr);
715 checkStatus(r,"GetScrapFlavorData");
716 if(size2 != size) return JvNewStringLatin1("");
721 void Darwin::natSetClipBoard(jstring js) {
722 unsigned int length = js->length();
726 r = GetCurrentScrap(&scrap);
727 checkStatus(r,"GetCurrentScrap");
729 r = PutScrapFlavor(scrap,kScrapFlavorTypeUnicode,0,sizeof(UniChar)*length,JvGetStringChars(js));
730 checkStatus(r,"PutScrapFlavor");
733 Proxy *Darwin::natDetectProxy() {
734 using org::xwt::Proxy;
738 SmartCFString smartString;
739 CFArrayRef exceptionList;
742 CFDictionaryRef proxyInfo = SCDynamicStoreCopyProxies(NULL);
743 if(proxyInfo == NULL) return 0;
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; \
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)");
776 CFRelease(proxyInfo);
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];
792 using org::xwt::Proxy;
797 NSArray *exceptionList;
799 NSDictionary *proxyInfo = (NSDictionary*)SCDynamicStoreCopyProxies(NULL);
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];
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];
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];
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];
842 jint Darwin::cgScreenWidth() {
843 return CGDisplayPixelsWide(((CGDirectDisplayID)0));
846 jint Darwin::cgScreenHeight() {
847 return CGDisplayPixelsHigh(((CGDirectDisplayID)0));
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);
859 void Darwin::_exit() {
860 QuitApplicationEventLoop();
863 void Darwin::natInit() {
865 #ifdef XWT_CARBON_NO_BUNDLE_HACK
867 ProcessSerialNumber currentProcess = { 0, kCurrentProcess };
869 ::fprintf(stderr,"Doing XWT_CARBON_NO_BUNDLE_HACK\n");
870 r = GetCurrentProcess(¤tProcess);
871 checkStatus(r,"GetCurrentProcess");
872 r = CPSEnableForegroundOperation( ¤tProcess );
873 checkStatus(r,"CPSEnableForegroundOperation");
874 r = CPSSetFrontProcess(¤tProcess);
875 checkStatus(r,"CPSSetFrontProcess");
880 r = CreateNibReference(CFSTR("MainMenu"), &nib);
881 checkStatus(r,"CreateNibReference");
882 r = SetMenuBarFromNib(nib, CFSTR("MenuBar"));
883 checkStatus(r,"SetMenuBarFromNib");
884 DisposeNibReference(nib);
886 // FIXME: Install menu event handler
891 void Darwin::_running() {
892 RunApplicationEventLoop();
896 #pragma mark ------ OpenGL Functions -----
898 void Darwin$CarbonOpenGL::activateSharedContext() {
899 AGLContext ctx = (AGLContext) rawSharedContext;
900 aglSetCurrentContext(ctx);
903 jboolean Darwin$CarbonOpenGL::initPixelFormat() {
915 rawPixelFormat = (RawData*) aglChoosePixelFormat(NULL,0,attr);
916 return rawPixelFormat != 0;
919 void Darwin$CarbonOpenGL::initSharedContext() {
920 AGLPixelFormat fmt = (AGLPixelFormat) rawPixelFormat;
921 rawSharedContext = (RawData*) aglCreateContext(fmt,NULL);
922 checkStatus(rawSharedContext,"aglCreateContext");
925 void Darwin$GLCarbonDoubleBuffer::natInit() {
926 WindowClass wc = kPlainWindowClass;
927 WindowAttributes attr = 0;
931 AGLContext ctx,shared;
937 rect.top = rect.left = 0;
938 rect.right = width + rect.left;
939 rect.bottom = height + rect.top;
941 r = CreateNewWindow(wc,attr,&rect,&window);
942 checkStatus(r,"CreateNewWindow");
944 shared = (AGLContext) gl->rawSharedContext;
945 fmt = (AGLPixelFormat) gl->rawPixelFormat;
946 ctx = aglCreateContext(fmt,shared);
947 checkStatus(ctx, "aglCreateContext");
949 b = aglSetDrawable(ctx, GetWindowPort(window));
950 checkStatus(b,"aglSetDrawable");
952 aglSetCurrentContext(ctx);
953 aglUpdateContext(ctx);
954 drawableInit(OpenGL::roundToPowerOf2(width),
955 OpenGL::roundToPowerOf2(height));
956 glClear(GL_COLOR_BUFFER_BIT);
958 aglSetCurrentContext(shared);
960 target = rectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D;
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);
969 glCopyTexImage2D(target, 0, GL_RGBA, 0, 0, width, height, 0);
974 //ShowWindow(window);
975 textureName = (jint) tex;
976 rawWindowRef = (RawData*) window;
977 rawCTX = (RawData*) ctx;
980 void Darwin$GLCarbonDoubleBuffer::activateContext() {
981 AGLContext ctx = (AGLContext) rawCTX;
982 aglSetCurrentContext(ctx);
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);
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();
999 aglSetCurrentContext(ctx);
1001 if(db->rectTexture) {
1002 glEnable(GL_TEXTURE_RECTANGLE_EXT);
1004 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, (GLuint)db->textureName);
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);
1017 glDisable(GL_TEXTURE_RECTANGLE_EXT);
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;
1026 glColor4f(1.0f,1.0f,1.0f,1.0f);
1027 glEnable(GL_TEXTURE_2D);
1029 glGenTextures(1, &tname);
1030 glBindTexture(GL_TEXTURE_2D, tname);
1031 aglSurfaceTexture (ctx, GL_TEXTURE_2D, GL_RGBA, (AGLContext)db->rawCTX);
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);
1043 glDisable(GL_TEXTURE_2D);
1049 void Darwin$GLCarbonSurface::natReshape(jint w, jint h) {
1050 AGLContext ctx = (AGLContext) rawCTX;
1052 aglSetCurrentContext (ctx);
1053 aglUpdateContext(ctx);
1055 glViewport(0, 0, w, h);
1056 glMatrixMode(GL_PROJECTION);
1058 glOrtho(0, w, h, 0, -1, 1);
1059 glMatrixMode(GL_MODELVIEW);
1061 glTranslatef (0.375, 0.375, 0.0);
1065 void Darwin$GLCarbonSurface::natInit() {
1066 WindowRef window = (WindowRef) rawWindowRef;
1067 AGLContext ctx,shared;
1071 shared = (AGLContext) gl->rawSharedContext;
1072 fmt = (AGLPixelFormat) gl->rawPixelFormat;
1073 ctx = aglCreateContext(fmt,shared);
1074 checkStatus(ctx, "aglCreateContext");
1076 b = aglSetDrawable(ctx,GetWindowPort(window));
1077 checkStatus(b,"aglSetDrawable");
1079 aglSetCurrentContext(ctx);
1082 rawCTX = (RawData*)ctx;
1086 aglSetCurrentContext(ctx);
1087 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
1090 void Darwin$GLCarbonSurface::natDispose() {
1091 AGLContext ctx = (AGLContext) rawCTX;
1092 aglDestroyContext(ctx);
1093 Darwin$CarbonSurface::natDispose();
1096 } } } // end namepsace org::xwt::plat