X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fxwt%2Fplat%2FCarbon.cc;h=914ba776a5608d01c2a051df57e5b1ae7f4e9d32;hb=63080366bcef40f25ed20462441e8ff2ccad3649;hp=326392a2422c9762d95ed3f7db80ed02707a4419;hpb=35af224a7e474b5b54c338e3cc70ad509b8f56b2;p=org.ibex.core.git diff --git a/src/org/xwt/plat/Carbon.cc b/src/org/xwt/plat/Carbon.cc index 326392a..914ba77 100644 --- a/src/org/xwt/plat/Carbon.cc +++ b/src/org/xwt/plat/Carbon.cc @@ -1,121 +1,1061 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL] -// see below for copyright information on the second portion of this file +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [LGPL] +// Authors: Brian Alliet and Evan Jones +#ifndef __APPLE_CC__ +#define FSF_GCC +#define __APPLE_CC__ +#else +#define APPLE_GCC +#endif #include "POSIX.cc" +#include "OpenGL.cc" + +#include +#include + #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +// For proxy stuff +#include +// For LSOpenURLRef +#include + +#include + +#include + +using namespace org::xwt::plat; +using gnu::gcj::RawData; +using org::xwt::util::Semaphore; +using java::lang::Object; + +namespace org { namespace xwt { namespace plat { + +namespace carbon { } +using namespace carbon; + +#pragma mark ------ Carbon Namespace ------ +namespace carbon { + // We put everything that isn't in org.xwt.plat.Carbon in + // org.xwt.plat.carbon to prevent namespace conflicts + + template static inline int CompileTimeCheck() { const int something_is_wrong=1; something_is_wrong++; return 0; } + template <> static inline int CompileTimeCheck() { return 0; } + const static int unichar_check = CompileTimeCheck(); + + void funcFailed(char *func,int r); + static inline void checkStatus(OSStatus r, char *func) { if(r != noErr) funcFailed(func,r); } + static inline void checkStatus(GLboolean b, char *func) { if(!b) funcFailed(func,-1); } + static inline void checkStatus(void *p, char *func) { if(!p) funcFailed(func,-1); } + + jstring cfStringToJString(CFStringRef s) { + CFIndex length = CFStringGetLength(s); + CFRange range = CFRangeMake(0,length); + jstring js = JvAllocString(length); + UniChar *buf = (UniChar*)JvGetStringChars(js); + CFStringGetCharacters(s,range,buf); + return js; + } + + #pragma mark ------ SmartCFString ------ + class SmartCFString { + private: + CFStringRef p; + void release() { if(p) CFRelease(p); } + void checkNull() { if(!p) throw new java::lang::Error(JvNewStringLatin1("CFString function failed")); } + public: + // Constructors + SmartCFString() : p(0) { } + SmartCFString(const char *s) : p(0) { *this = s; } + SmartCFString(jstring js) : p(0) { *this = js; } + SmartCFString(CFStringRef cf) : p(0) { *this = cf; } + // Destructor + ~SmartCFString() { release(); } + // Assignment + SmartCFString& operator= (const char *s) { + release(); + if(!s) s = "(null)"; + p = CFStringCreateWithCString(kCFAllocatorDefault,s,kCFStringEncodingISOLatin1); + checkNull(); + return *this; + } + SmartCFString& operator= (jstring js) { + if(!js) return *this = "(null)"; + release(); + UniChar *buf = (UniChar*) JvGetStringChars(js); + CFIndex length = js->length(); + p = CFStringCreateWithCharacters(kCFAllocatorDefault,buf,length); + checkNull(); + return *this; + } + SmartCFString& operator= (CFStringRef cf) { + if(cf == NULL) return *this = "(null)"; + release(); + p = cf; + return *this; + } + operator CFStringRef() { return p; } + operator jstring() { return getJString(); } + + jstring getJString() { return cfStringToJString(p); } + + bool equals(const char *s) { + SmartCFString cfs(s); + return equals(cfs); + } + + bool equals(CFStringRef cfs) { + return CFStringCompare(p,cfs,0) == kCFCompareEqualTo; + } + }; + + // CHECKME: Is just making up your own four char codes really correct? + const static UInt32 kEventClassCarbonMessage = 'xwta'; + const static UInt32 kEventCarbonMessage = 'xwtb'; + const static UInt32 kEventParamCarbonMessage = 'xwtc'; + + pascal OSStatus carbon::carbonMessageEventHandler(EventHandlerCallRef handler, EventRef e, void *userData); + void fileDialogEventHandler(NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, void *userData); + +} // end namespace + +jboolean Carbon::isJaguar() { + SInt32 version; + OSStatus r = Gestalt(gestaltSystemVersion, &version); + checkStatus(r,"Gestalt"); + return version >= 0x1020; +} + +void Carbon$CarbonMessage::natInit() { + OSStatus r; + + EventHandlerUPP upp = NewEventHandlerUPP(carbonMessageEventHandler); + EventTypeSpec eventTypes = { kEventClassCarbonMessage, kEventCarbonMessage }; + r = InstallEventHandler(GetApplicationEventTarget(),upp,1,&eventTypes,NULL,NULL); + checkStatus(r,"InstallEventHandler"); +} + +void Carbon$CarbonMessage::add(Carbon$CarbonMessage *msg) { + EventRef event; + OSStatus r; + + GCJ$Retainer::retain(msg); + + r = CreateEvent(kCFAllocatorDefault,kEventClassCarbonMessage,kEventCarbonMessage,0,kEventAttributeNone,&event); + checkStatus(r,"CreateEvent"); + r = SetEventParameter(event,kEventParamCarbonMessage,typeVoidPtr,sizeof(msg),(void*)&msg); + checkStatus(r,"SetEventParameter"); + r = PostEventToQueue(GetMainEventQueue(),event,kEventPriorityHigh); + checkStatus(r,"PostEventToQueue"); + ReleaseEvent(event); +} + + +pascal OSStatus carbon::carbonMessageEventHandler(EventHandlerCallRef handler, EventRef e, void *userData) { + UInt32 eKind = GetEventKind(e); + UInt32 eClass = GetEventClass(e); + OSStatus r; + Carbon$CarbonMessage *msg; + if(eClass != kEventClassCarbonMessage || eKind != kEventCarbonMessage) + return eventNotHandledErr; + r = GetEventParameter(e,kEventParamCarbonMessage,typeVoidPtr,NULL,sizeof(msg),NULL,&msg); + checkStatus(r,"GetEventParameter"); + msg->perform(); + GCJ$Retainer::release(msg); + return noErr; +} + + +#pragma mark ------ Utility Functions ------ + +void carbon::funcFailed(char *func,int r){ + fprintf(stderr,"%s() failed (%d)\n",func,r); + exit(EXIT_FAILURE); +} + +#pragma mark ------ CarbonPicture Methods ------ + +#pragma mark ----- Carbon Surface Methods ---- -// CarbonDoubleBuffer ////////////////////////////////////////////////////////////////////// +void Carbon$CarbonSurface::natSyncCursor(jint n) { + ThemeCursor c; + // see Carbon.java for what these numbers mean + switch(n) { + case 1: c = kThemeWatchCursor; + case 2: c = kThemePlusCursor; + case 3: c = kThemeIBeamCursor; + case 4: c = kThemePointingHandCursor; + case 5: c = kThemeOpenHandCursor; + case 6: c = kThemeResizeLeftRightCursor; + default: c = kThemeArrowCursor; + } + SetThemeCursor(c); +} + +void Carbon$CarbonSurface::natSetInvisible(jboolean b) { + WindowRef window = (WindowRef) rawWindowRef; + fprintf(stderr,"Making window %s\n",b?"invisible":"visible"); + if(b) HideWindow(window); + else ShowWindow(window); +} -void org::xwt::plat::Carbon$CarbonDoubleBuffer::drawPicture(org::xwt::Picture* s, - jint dx1, jint dy1, jint dx2, jint dy2, jint sx1, jint sy1, jint sx2, jint sy2) { - org::xwt::plat::Carbon$CarbonPicture* source = (org::xwt::plat::Carbon$CarbonPicture*)s; - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$CarbonSurface::nat_setMaximized(jboolean b) { + WindowRef window = (WindowRef) rawWindowRef; + Point ideal = { 10000, 10000 }; + OSStatus r = ZoomWindowIdeal(window,(b?inZoomOut:inZoomIn),&ideal); + checkStatus(r,"ZoomWindowIdeal"); } -void org::xwt::plat::Carbon$CarbonDoubleBuffer::finalize() { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$CarbonSurface::nat_setMinimized(jboolean b) { + WindowRef window = (WindowRef) rawWindowRef; + if((IsWindowCollapsed(window) ? 1 : 0) == (b ? 1 : 0)) return; + OSStatus r = CollapseWindow(window,b); + checkStatus(r,"CollapseWindow"); } -void org::xwt::plat::Carbon$CarbonSurface::blit(org::xwt::DoubleBuffer* db, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) { - org::xwt::plat::Carbon$CarbonDoubleBuffer *xdb = (org::xwt::plat::Carbon$CarbonDoubleBuffer*)db; - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$CarbonSurface::natSetTitleBarText(jstring js) { + SmartCFString s = js; + WindowRef window = (WindowRef) rawWindowRef; + SetWindowTitleWithCFString(window,s); } -void org::xwt::plat::Carbon$CarbonDoubleBuffer::fillRect (jint x, jint y, jint x2, jint y2, jint argb) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$CarbonSurface::natToBack() { + WindowRef window = (WindowRef) rawWindowRef; + SendBehind(window,NULL); } -void org::xwt::plat::Carbon$CarbonDoubleBuffer::drawString(::java::lang::String* font, ::java::lang::String* text, jint x, jint y, jint argb) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$CarbonSurface::natToFront() { + WindowRef window = (WindowRef) rawWindowRef; + fprintf(stderr,"SelectWindow()\n"); + SelectWindow(window); } +#pragma mark ---- Window Event Handler ---- +namespace carbon { +static const EventTypeSpec eventTypeSpecs[] = { + // kEventClassCommand + // { kEventClassCommand, ??? }, + + // kEventClassWindow + { kEventClassWindow, kEventWindowUpdate }, + { kEventClassWindow, kEventWindowBoundsChanged }, + { kEventClassWindow, kEventWindowActivated }, + { kEventClassWindow, kEventWindowDeactivated }, + { kEventClassWindow, kEventWindowZoomed }, + { kEventClassWindow, kEventWindowCollapsed }, + { kEventClassWindow, kEventWindowExpanded }, + { kEventClassWindow, kEventWindowClose }, + { kEventClassWindow, kEventWindowClosed }, + + // kEventClassKeyboard + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyRepeat }, + { kEventClassKeyboard, kEventRawKeyUp }, + { kEventClassKeyboard, kEventRawKeyModifiersChanged }, + + // kEventClassMouse + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged }, + { kEventClassMouse, kEventMouseWheelMoved }, +}; + +pascal OSStatus windowEventHandler(EventHandlerCallRef handler, EventRef e, void *userData) { + Carbon$CarbonSurface *surface = (Carbon$CarbonSurface*) userData; + UInt32 eKind = GetEventKind(e); + UInt32 eClass = GetEventClass(e); + OSStatus r; + + switch(eClass) { + case kEventClassCommand: + switch(eKind) { + // TODO: handle menu items + } + break; + case kEventClassKeyboard: + switch(eKind) { + case kEventRawKeyDown: + case kEventRawKeyRepeat: + case kEventRawKeyUp: { + UInt32 keyCode; + jstring js; + + r = GetEventParameter(e,kEventParamKeyCode,typeUInt32,NULL,sizeof(keyCode),NULL,&keyCode); + checkStatus(r,"GetEventParameter"); + + switch(keyCode) { + // These values were obtained by experimentation. I can't find any constants for them + // in the header files + case 126: js = JvNewStringLatin1("up"); break; + case 125: js = JvNewStringLatin1("down"); break; + case 124: js = JvNewStringLatin1("right"); break; + case 123: js = JvNewStringLatin1("left"); break; + case 122: js = JvNewStringLatin1("f1"); break; + case 120: js = JvNewStringLatin1("f2"); break; + case 99: js = JvNewStringLatin1("f3"); break; + case 118: js = JvNewStringLatin1("f4"); break; + case 96: js = JvNewStringLatin1("f5"); break; + case 97: js = JvNewStringLatin1("f6"); break; + case 98: js = JvNewStringLatin1("f7"); break; + case 100: js = JvNewStringLatin1("f8"); break; + case 101: js = JvNewStringLatin1("f9"); break; + case 109: js = JvNewStringLatin1("f10"); break; + case 103: js = JvNewStringLatin1("f11"); break; + case 111: js = JvNewStringLatin1("f12"); break; + case 105: js = JvNewStringLatin1("f13"); break; + case 114: js = JvNewStringLatin1("insert"); break; + case 117: js = JvNewStringLatin1("delete"); break; + case 116: js = JvNewStringLatin1("page_up"); break; + case 121: js = JvNewStringLatin1("page_down"); break; + case 115: js = JvNewStringLatin1("home"); break; + case 119: js = JvNewStringLatin1("end"); break; + case 71: js = JvNewStringLatin1("num_lock"); break; + case 53: js = JvNewStringLatin1("escape"); break; + case 51: js = JvNewStringLatin1("back_space"); break; + case 36: js = JvNewStringLatin1("enter"); break; + case 48: js = JvNewStringLatin1("tab"); break; + case 76: js = JvNewStringLatin1("enter"); break; // number pad enter + default: { + UInt32 size; + UInt32 modifiers = surface->modifiers; + r = GetEventParameter(e,kEventParamKeyUnicodes,typeUnicodeText,NULL,0,&size,NULL); + checkStatus(r,"GetEventParameter"); + if(size == 0 || (modifiers & controlKey && size>sizeof(UniChar))) return eventNotHandledErr; + + js = JvAllocString(size/sizeof(UniChar)); + UniChar *buf = (UniChar*)JvGetStringChars(js); + r = GetEventParameter(e,kEventParamKeyUnicodes,typeUnicodeText,NULL,size,NULL,buf); + checkStatus(r,"GetEventParameter"); -// CarbonSurface ////////////////////////////////////////////////////////////////////// + if(!buf[0]) return eventNotHandledErr; // shouldn't happen + // odd, when the ctrl key is pressed a-"`" become 1-31, this brings them back to the corect values + if(modifiers & controlKey && buf[0] < 32) buf[0] += 0x60; + break; + } + } + + if(eKind == kEventRawKeyUp) + surface->KeyReleased(js); + else + surface->KeyPressed(js); + return noErr; + } + case kEventRawKeyModifiersChanged: { + const static struct { + UInt32 mask; + jstring xwtKey; + } modifiersTable[] = { + { shiftKey, JvNewStringLatin1("shift") }, + { alphaLock, JvNewStringLatin1("caps_lock") }, + { controlKey, JvNewStringLatin1("control") }, + { optionKey, JvNewStringLatin1("alt") }, + { kEventKeyModifierNumLockMask, JvNewStringLatin1("num_lock") }, + { 0, 0 } + }; + + UInt32 oldModifiers = (UInt32) surface->modifiers; + UInt32 newModifiers; + r = GetEventParameter(e,kEventParamKeyModifiers,typeUInt32,NULL,sizeof(newModifiers),NULL,&newModifiers); + checkStatus(r,"GetEventParameter"); + surface->modifiers = (jint) newModifiers; + UInt32 changedModifiers = oldModifiers ^ newModifiers; + + for(int i=0;modifiersTable[i].mask;i++) { + UInt32 mask = modifiersTable[i].mask; + if(!(changedModifiers & mask)) continue; + if(newModifiers & mask) + surface->KeyPressed(modifiersTable[i].xwtKey); + else + surface->KeyReleased(modifiersTable[i].xwtKey); + } + return noErr; + } + } + break; + case kEventClassMouse: + // The default handler gets first dibs on mouse events + // (this catches the titlebar, resize box, etc) + r = CallNextEventHandler(handler, e); + if(r != eventNotHandledErr && eKind != kEventMouseMoved && eKind != kEventMouseDragged) return r; + + switch(eKind) { + case kEventMouseMoved: + case kEventMouseDragged: { + WindowRef window = (WindowRef) surface->rawWindowRef; + Point p; + Rect rect; + + r = GetEventParameter(e,kEventParamMouseLocation,typeQDPoint,NULL,sizeof(p),NULL,&p); + checkStatus(r,"GetEventParameter"); + r = GetWindowBounds(window,kWindowContentRgn,&rect); + checkStatus(r,"GetWindowBounds"); + surface->Move(p.h-rect.left,p.v-rect.top); + return noErr; + } + case kEventMouseDown: + case kEventMouseUp: { + EventMouseButton button; + UInt32 clickCount; + jint xwtButton; + r = GetEventParameter(e,kEventParamMouseButton,typeMouseButton,NULL,sizeof(button),NULL,&button); + checkStatus(r,"GetEventParameter"); + r = GetEventParameter(e,kEventParamClickCount,typeUInt32,NULL,sizeof(clickCount),NULL,&clickCount); + checkStatus(r,"GetEventParameter"); + + switch(button) { + case kEventMouseButtonPrimary: xwtButton = 1; break; + case kEventMouseButtonSecondary: xwtButton = 2; break; + case kEventMouseButtonTertiary: xwtButton = 3; break; + default: return noErr; + } + if(eKind == kEventMouseDown) { + surface->Press(xwtButton); + } else { + surface->Release(xwtButton); + while(clickCount > 1) { + surface->DoubleClick(xwtButton); + clickCount-=2; + } + if(clickCount) surface->Click(xwtButton); + } + return noErr; + } + case kEventMouseWheelMoved: { + EventMouseWheelAxis axis; + SInt32 delta; + r = GetEventParameter(e,kEventParamMouseWheelAxis,typeMouseWheelAxis,NULL,sizeof(axis),NULL,&axis); + checkStatus(r,"GetEventParameter"); + if(axis != kEventMouseWheelAxisY) break; + r = GetEventParameter(e,kEventParamMouseWheelDelta,typeSInt32,NULL,sizeof(delta),NULL,&delta); + checkStatus(r,"GetEventParameter"); + fprintf(stderr,"kEventMouseWheelMoved: delta: %d",delta); + // surface->MouseWheelMoved(...) IMPROVMENT: mouse wheel support in xwt + return noErr; + } + } + break; + + case kEventClassWindow: { + WindowRef window; + r = GetEventParameter(e,kEventParamDirectObject,typeWindowRef,NULL,sizeof(window),NULL,&window); + checkStatus(r,"kEventClassWindow/GetEventParameter"); + + if((RawData*)window != surface->rawWindowRef) Carbon::abort(JvNewStringLatin1("window != surface->window")); + + switch(eKind) { + case kEventWindowUpdate: { + surface->Dirty(0,0,surface->width,surface->height); + return noErr; + } + case kEventWindowBoundsChanged: { + UInt32 attr; + Rect rect; + r = GetEventParameter(e,kEventParamAttributes,typeUInt32,NULL,sizeof(attr),NULL,&attr); + checkStatus(r,"kEventWindowBoundsChanged/GetEventParameter"); + r = GetWindowBounds(window,kWindowContentRgn,&rect); + checkStatus(r,"GetWindowBounds"); + if(attr & kWindowBoundsChangeSizeChanged) { + jint w = rect.right-rect.left; + jint h = rect.bottom-rect.top; + if(attr & kWindowBoundsChangeUserResize && surface->maximized) + surface->Maximized(false); + surface->reshape(w,h); + surface->SizeChange(w,h); + surface->Dirty(0,0,w,h); + surface->blitDirtyScreenRegions(); + } + if(attr & kWindowBoundsChangeOriginChanged) { + surface->PosChange(rect.left,rect.top); + } + return noErr; + } + case kEventWindowActivated: + case kEventWindowDeactivated: { + surface->Focused(eKind == kEventWindowActivated); + return noErr; + } + case kEventWindowZoomed: { + fprintf(stderr,"Zoomed....\n"); + surface->Maximized(true); + return noErr; + } + case kEventWindowCollapsed: { + surface->Minimized(true); + return noErr; + } + case kEventWindowExpanded: { + surface->Minimized(false); + return noErr; + } + case kEventWindowClose: { + surface->Close(); + return noErr; + } + case kEventWindowClosed: { + DisposeEventHandlerUPP((EventHandlerUPP)surface->rawEventHandlerUPP); + GCJ$Retainer::release(surface); + return noErr; + } + } + } + break; + } + return eventNotHandledErr; +} +} // end namespace -void org::xwt::plat::Carbon$CarbonSurface::setIcon(org::xwt::Picture* pic) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$CarbonSurface::natInit(jboolean framed) { + WindowRef window; + Rect rect; + WindowClass wc = framed ? kDocumentWindowClass : kPlainWindowClass; + // FIXME: unframed windows should appear in the window menu + // This probably needs a hack similar to whats in Cocoa.mm + WindowAttributes attr = kWindowStandardHandlerAttribute| + (framed ? kWindowInWindowMenuAttribute|kWindowStandardDocumentAttributes|kWindowLiveResizeAttribute : 0); + OSStatus r; + + rect.top = 0; rect.left = 0; rect.bottom = 10; rect.right=10; + r = CreateNewWindow(wc,attr,&rect,&window); + checkStatus(r,"CreateNewWindow"); + + GCJ$Retainer::retain(this); // Need to account for the EventHandlers pointer to us + EventHandlerUPP upp = NewEventHandlerUPP(windowEventHandler); + + r = InstallWindowEventHandler(window,upp,sizeof(eventTypeSpecs)/sizeof(EventTypeSpec),eventTypeSpecs,this,NULL); + checkStatus(r,"InstallWindowEventHandler"); + + rawWindowRef = (RawData*) window; + rawEventHandlerUPP = (RawData*) upp; } -void org::xwt::plat::Carbon$CarbonSurface::setTitleBarText(java::lang::String* s) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$CarbonSurface::natDispose() { + WindowRef window = (WindowRef) rawWindowRef; + DisposeWindow(window); } -void org::xwt::plat::Carbon$CarbonSurface::setLimits(jint minw, jint minh, jint maxw, jint maxh) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$CarbonSurface::natSetIcon(org::xwt::Picture *_p) { } -void org::xwt::plat::Carbon$CarbonSurface::setSize (jint width, jint height) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$CarbonSurface::natSetLocation(jint x, jint y) { + WindowRef window = (WindowRef) rawWindowRef; + Rect rect; + OSStatus r = GetWindowBounds(window,kWindowStructureRgn,&rect); + checkStatus(r,"GetWindowBounds"); + rect.bottom = y + (rect.bottom - rect.top); + rect.right = x + (rect.right - rect.left); + rect.top = y; + rect.left = x; + r = SetWindowBounds(window,kWindowStructureRgn,&rect); + checkStatus(r,"SetWindowBounds"); + r = ConstrainWindowToScreen(window,kWindowStructureRgn,kWindowConstrainMoveRegardlessOfFit,NULL,NULL); + checkStatus(r,"ConstrainWindowToScreen"); } -void org::xwt::plat::Carbon$CarbonSurface::setLocation (jint x, jint y) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$CarbonSurface::natSetSize(jint w, jint h) { + WindowRef window = (WindowRef) rawWindowRef; + Rect rect; + OSStatus r = GetWindowBounds(window,kWindowStructureRgn,&rect); + checkStatus(r,"GetWindowBounds"); + rect.bottom = rect.top + h; + rect.right = rect.left + w; + r = SetWindowBounds(window,kWindowStructureRgn,&rect); + checkStatus(r,"SetWindowBounds"); + r = ConstrainWindowToScreen(window,kWindowStructureRgn,kWindowConstrainMoveRegardlessOfFit,NULL,NULL); + checkStatus(r,"ConstrainWindowToScreen"); } -void org::xwt::plat::Carbon$CarbonSurface::toFront() { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); + +void Carbon$CarbonSurface::natSetLimits(jint minw, jint minh, jint maxw, jint maxh) { + WindowRef window = (WindowRef) rawWindowRef; + const int maxMax = 32767; + const int minMinW = 80; + const int minMinH = 20; + HISize min,max; + min.width = minw > maxMax ? maxMax : (minw < minMinW ? minMinW : minw); + min.height = minh > maxMax ? maxMax : (minh < minMinH ? minMinH : minh); + max.width = maxw > maxMax ? maxMax : (maxw < minMinW ? minMinW : maxw); + max.height = maxh > maxMax ? maxMax : (maxh < minMinH ? minMinH : maxh); + OSStatus r = SetWindowResizeLimits(window,&min,&max); + checkStatus(r,"SetWindowResizeLimits"); } -void org::xwt::plat::Carbon$CarbonSurface::toBack() { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); + + +#pragma mark ------ Carbon Methods ------ +void carbon::fileDialogEventHandler(NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, void *userData) { + Carbon$FileDialogHelper *helper = (Carbon$FileDialogHelper*) userData; + NavDialogRef dialog = callBackParms->context; + OSStatus r; + switch(callBackSelector) { + case kNavCBUserAction: { + NavUserAction action = NavDialogGetUserAction(dialog); + if(action == kNavUserActionNone || action == kNavUserActionCancel) { + helper->fileName = 0; + } else { + NavReplyRecord reply; + r = NavDialogGetReply(dialog,&reply); + checkStatus(r,"NavDialogGetReply"); + + AEKeyword keyword; + FSRef ref; + char buf[4096]; + r = AEGetNthPtr(&reply.selection,1,typeFSRef,&keyword,NULL,&ref,sizeof(ref),NULL); + checkStatus(r,"AEGetNthPtr"); + r = FSRefMakePath(&ref,(UInt8*)buf,sizeof(buf)-1); + checkStatus(r,"FSRefMakePath"); + helper->fileName = JvNewStringLatin1(buf); + if(helper->save) helper->saveName = cfStringToJString(reply.saveFileName); + r = NavDisposeReply(&reply); + checkStatus(r,"NavDialogGetReply"); + } + helper->sem->release(); + break; + } + case kNavCBTerminate: + DisposeNavEventUPP((NavEventUPP)helper->rawUPP); + NavDialogDispose(dialog); + break; + } } -void org::xwt::plat::Carbon$CarbonSurface::_dispose() { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon::natFileDialog(Carbon$FileDialogHelper *helper,jstring suggestion_, jboolean write) { + NavDialogRef dlg; + SmartCFString suggestion = suggestion_; + CFStringRef message = CFSTR("By selecting a file in this dialog you are giving this XWT application permission to access that file."); + OSStatus r; + WindowRef window = FrontWindow(); + NavDialogCreationOptions options; + + NavEventUPP handler = NewNavEventUPP(carbon::fileDialogEventHandler); + + NavGetDefaultDialogCreationOptions(&options); + options.optionFlags = + (options.optionFlags|kNavAllFilesInPopup|kNavSelectAllReadableItem|kNavDontUseCustomFrame|kNavDontConfirmReplacement) + &~(kNavAllowStationery|kNavAllowMultipleFiles); + options.clientName = CFSTR("XWT"); + if(write) + options.saveFileName = suggestion; + options.message = message; + options.modality = window ? kWindowModalityWindowModal : kWindowModalityAppModal; + options.parentWindow = window; + + if(write) + r = NavCreatePutFileDialog(&options,0,0,handler,helper,&dlg); + else + r = NavCreateGetFileDialog(&options,NULL,handler,NULL,NULL,helper,&dlg); + checkStatus(r,"NavCreate(Get/Put)FileDialog"); + + helper->rawUPP = (RawData*)handler; + NavDialogRun(dlg); } -void org::xwt::plat::Carbon$CarbonSurface::setInvisible(jboolean i) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +jstring Carbon::natGetClipBoard() { + ScrapRef scrap; + OSStatus r; + Size size,size2; + + r = GetCurrentScrap(&scrap); + checkStatus(r,"GetCurrentScrap"); + + r = GetScrapFlavorSize( scrap, kScrapFlavorTypeUnicode, &size); + if(r == scrapFlavorNotFoundErr) return JvNewStringLatin1(""); + checkStatus(r,"GetScrapFlavorSize"); + + unsigned int length = size/sizeof(UniChar); + + jstring js = JvAllocString(length); + UniChar *buf = (UniChar*) JvGetStringChars(js); + size2 = size; + r = GetScrapFlavorData(scrap,kScrapFlavorTypeUnicode,&size2,buf); + if(r == scrapFlavorNotFoundErr); + checkStatus(r,"GetScrapFlavorData"); + if(size2 != size) return JvNewStringLatin1(""); + + return js; } -void org::xwt::plat::Carbon$CarbonSurface::_setMaximized(jboolean b) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon::natSetClipBoard(jstring js) { + unsigned int length = js->length(); + ScrapRef scrap; + OSStatus r; + + r = GetCurrentScrap(&scrap); + checkStatus(r,"GetCurrentScrap"); + + r = PutScrapFlavor(scrap,kScrapFlavorTypeUnicode,0,sizeof(UniChar)*length,JvGetStringChars(js)); + checkStatus(r,"PutScrapFlavor"); } -void org::xwt::plat::Carbon$CarbonSurface::_setMinimized(jboolean b) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +Proxy *Carbon::natDetectProxy() { + using org::xwt::Proxy; + Proxy *p=0; + CFStringRef string; + CFNumberRef number; + SmartCFString smartString; + CFArrayRef exceptionList; + int i; + + CFDictionaryRef proxyInfo = SCDynamicStoreCopyProxies(NULL); + if(proxyInfo == NULL) return 0; + +#define doproto(proto,var) \ + number = (CFNumberRef) CFDictionaryGetValue(proxyInfo,kSCPropNetProxies ## proto ## Enable); \ + if(number != NULL && CFGetTypeID(number) != CFNumberGetTypeID()) number = NULL; \ + if(number && CFNumberGetValue(number,kCFNumberIntType,&i) && i) { \ + string = (CFStringRef) CFDictionaryGetValue(proxyInfo, kSCPropNetProxies ## proto ## Proxy);\ + if(string != NULL && CFGetTypeID(string) != CFStringGetTypeID()) string = NULL; \ + number = (CFNumberRef) CFDictionaryGetValue(proxyInfo, kSCPropNetProxies ## proto ## Port); \ + if(number != NULL && CFGetTypeID(number) != CFNumberGetTypeID()) number = NULL; \ + if(string && number && CFNumberGetValue(number,kCFNumberIntType,&i) && i) { \ + if(!p) p = new Proxy(); \ + p->var ## ProxyHost = cfStringToJString(string); \ + p->var ## ProxyPort = i; \ + } \ + } +doproto(HTTP,http) +doproto(HTTPS,https) +doproto(SOCKS,socks) +#undef doproto + + exceptionList = (CFArrayRef) CFDictionaryGetValue(proxyInfo,kSCPropNetProxiesExceptionsList); + if(exceptionList != NULL && CFGetTypeID(exceptionList) != CFArrayGetTypeID()) exceptionList = NULL; + if(p && exceptionList && CFArrayGetCount(exceptionList)) { + CFIndex count = CFArrayGetCount(exceptionList); + p->excluded = (JArray*) + JvNewObjectArray(count,&java::lang::String::class$,0); + for(i=0;iexcluded)[i] = string ? cfStringToJString(string) : JvNewStringLatin1("(null)"); + } + } + CFRelease(proxyInfo); + + return p; +/* + exceptionList = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesExceptionsList]; + if(p && exceptionList && [exceptionList count]) { + NSLog(@"excl: %@",exceptionList); + p->excluded = (JArray*) + JvNewObjectArray([exceptionList count],&java::lang::String::class$,0); + for(i=0;i<[exceptionList count];i++) + elements(p->excluded)[i] = [[exceptionList objectAtIndex: i] jstring]; + } + return p; + */ + +/* + using org::xwt::Proxy; + AutoARP pool; + Proxy *p=0; + NSString *host; + NSNumber *port; + NSArray *exceptionList; + unsigned int i; + NSDictionary *proxyInfo = (NSDictionary*)SCDynamicStoreCopyProxies(NULL); + + if(proxyInfo == NULL) return 0; + if([[proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPEnable] boolValue]) { + host = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPProxy]; + port = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPPort]; + if(host && [port intValue]) { + if(!p) p = new Proxy(); + p->httpProxyHost = [host jstring]; + p->httpProxyPort = [port intValue]; + } + } + if([[proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPSEnable] boolValue]) { + host = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPSProxy]; + port = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesHTTPSPort]; + if(host && [port intValue]) { + if(!p) p = new Proxy(); + p->httpsProxyHost = [host jstring]; + p->httpsProxyPort = [port intValue]; + } + } + if([[proxyInfo objectForKey: (NSString*) kSCPropNetProxiesSOCKSEnable] boolValue]) { + host = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesSOCKSProxy]; + port = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesSOCKSPort]; + if(host && [port intValue]) { + if(!p) p = new Proxy(); + p->socksProxyHost = [host jstring]; + p->socksProxyPort = [port intValue]; + } + } + + exceptionList = [proxyInfo objectForKey: (NSString*) kSCPropNetProxiesExceptionsList]; + if(p && exceptionList && [exceptionList count]) { + NSLog(@"excl: %@",exceptionList); + p->excluded = (JArray*) + JvNewObjectArray([exceptionList count],&java::lang::String::class$,0); + for(i=0;i<[exceptionList count];i++) + elements(p->excluded)[i] = [[exceptionList objectAtIndex: i] jstring]; + } + return p; +*/ } +jint Carbon::cgScreenWidth() { + return CGDisplayPixelsWide(kCGDirectMainDisplay); +} +jint Carbon::cgScreenHeight() { + return CGDisplayPixelsHigh(kCGDirectMainDisplay); +} +void Carbon::_newBrowserWindow(jstring js) { + SmartCFString cfs = js; + CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault,cfs,NULL); + SmartCFString scheme = CFURLCopyScheme(url); + if(scheme.equals(CFStringRef("http"))) + LSOpenCFURLRef(url,NULL); + CFRelease(url); +} -// Carbon /////////////////////////////////////////////////////////////////// +void Carbon::_exit() { + QuitApplicationEventLoop(); +} -jint org::xwt::plat::Carbon::_getScreenWidth() { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +#define XWT_CARBON_NO_BUNDLE_HACK +#ifdef XWT_CARBON_NO_BUNDLE_HACK +extern "C" { + OSErr CPSEnableForegroundOperation(ProcessSerialNumber *psn); + OSErr CPSSetFrontProcess(ProcessSerialNumber *psn); } -jint org::xwt::plat::Carbon::_getScreenHeight() { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +#endif +void Carbon::natInit() { + OSStatus r; + #ifdef XWT_CARBON_NO_BUNDLE_HACK + { + ProcessSerialNumber currentProcess = { 0, kCurrentProcess }; + + ::fprintf(stderr,"Doing XWT_CARBON_NO_BUNDLE_HACK\n"); + r = GetCurrentProcess(¤tProcess); + checkStatus(r,"GetCurrentProcess"); + r = CPSEnableForegroundOperation( ¤tProcess ); + checkStatus(r,"CPSEnableForegroundOperation"); + r = CPSSetFrontProcess(¤tProcess); + checkStatus(r,"CPSSetFrontProcess"); + } + #else + { + IBNibRef nib; + r = CreateNibReference(CFSTR("MainMenu"), &nib); + checkStatus(r,"CreateNibReference"); + r = SetMenuBarFromNib(nib, CFSTR("MenuBar")); + checkStatus(r,"SetMenuBarFromNib"); + DisposeNibReference(nib); + + // FIXME: Install menu event handler + } + #endif } -jstring org::xwt::plat::Carbon::_getClipBoard() { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon::_running() { + RunApplicationEventLoop(); + ExitToShell(); } -void org::xwt::plat::Carbon::_setClipBoard(jstring s) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +#pragma mark ------ OpenGL Functions ----- + +void Carbon$CarbonOpenGL::activateSharedContext() { + AGLContext ctx = (AGLContext) rawSharedContext; + aglSetCurrentContext(ctx); } -JArray* org::xwt::plat::Carbon::listNativeFonts() { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +jboolean Carbon$CarbonOpenGL::initPixelFormat() { + GLint attr[] = { + AGL_NO_RECOVERY, + AGL_RGBA, + AGL_DEPTH_SIZE, 32, + AGL_RED_SIZE, 8, + AGL_GREEN_SIZE, 8, + AGL_RED_SIZE, 8, + AGL_ALPHA_SIZE, 8, + AGL_NONE + }; + + rawPixelFormat = (RawData*) aglChoosePixelFormat(NULL,0,attr); + return rawPixelFormat != 0; } -gnu::gcj::RawData* org::xwt::plat::Carbon::fontStringToStruct(jstring s) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$CarbonOpenGL::initSharedContext() { + AGLPixelFormat fmt = (AGLPixelFormat) rawPixelFormat; + rawSharedContext = (RawData*) aglCreateContext(fmt,NULL); + checkStatus(rawSharedContext,"aglCreateContext"); } -jint org::xwt::plat::Carbon::_getMaxAscent(::java::lang::String* font) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); +void Carbon$GLCarbonDoubleBuffer::natInit() { + WindowClass wc = kPlainWindowClass; + WindowAttributes attr = 0; + WindowRef window; + Rect rect; + OSStatus r; + AGLContext ctx,shared; + AGLPixelFormat fmt; + GLboolean b; + GLuint tex; + GLuint target; + + rect.top = rect.left = 0; + rect.right = width + rect.left; + rect.bottom = height + rect.top; + + r = CreateNewWindow(wc,attr,&rect,&window); + checkStatus(r,"CreateNewWindow"); + + shared = (AGLContext) gl->rawSharedContext; + fmt = (AGLPixelFormat) gl->rawPixelFormat; + ctx = aglCreateContext(fmt,shared); + checkStatus(ctx, "aglCreateContext"); + + b = aglSetDrawable(ctx,GetWindowPort(window)); + checkStatus(b,"aglSetDrawable"); + + aglSetCurrentContext(ctx); + aglUpdateContext(ctx); + drawableInit(width,height); + glClear(GL_COLOR_BUFFER_BIT); + + aglSetCurrentContext(shared); + target = rectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D; + glEnable(target); + glGenTextures(1,&tex); + glBindTexture(target,tex); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + aglSurfaceTexture (shared, target, GL_RGBA, ctx); + checkGLError(); + glDisable(target); + + //ShowWindow(window); + textureName = (jint) tex; + rawWindowRef = (RawData*) window; + rawCTX = (RawData*) ctx; +} + +void Carbon$GLCarbonDoubleBuffer::activateContext() { + AGLContext ctx = (AGLContext) rawCTX; + aglSetCurrentContext(ctx); +} + +void Carbon$GLCarbonDoubleBuffer::natCleanup(RawData* rawWindowRef, RawData* rawCTX) { + WindowRef window = (WindowRef) rawWindowRef; + AGLContext ctx = (AGLContext) rawCTX; + aglDestroyContext(ctx); + DisposeWindow(window); +} + +void Carbon$GLCarbonSurface::natBlit(Carbon$GLCarbonDoubleBuffer *db, jint sx1, jint sy1, jint dx1, jint dy1, jint dx2, jint dy2) { + AGLContext ctx = (AGLContext) rawCTX; + int sx2 = sx1 + (dx2-dx1); + int sy2 = sy1 + (dy2-dy1); + db->activateContext(); + glFlush(); + checkGLError(); + aglSetCurrentContext(ctx); + checkGLError(); + if(db->rectTexture) { + glEnable(GL_TEXTURE_RECTANGLE_EXT); + checkGLError(); + glBindTexture(GL_TEXTURE_RECTANGLE_EXT, db->textureName); + checkGLError(); + glBegin(GL_QUADS); + glTexCoord2i (sx1, sy1 ); + glVertex3i (dx1, dy1, 0); + glTexCoord2i (sx2, sy1 ); + glVertex3i (dx2, dy1, 0); + glTexCoord2i (sx2, sy2 ); + glVertex3i (dx2, dy2, 0); + glTexCoord2i (sx1, sy2 ); + glVertex3i (dx1, dy2, 0); + glEnd(); + checkGLError(); + glDisable(GL_TEXTURE_RECTANGLE_EXT); + checkGLError(); + } else { + float tx1,ty1,tx2,ty2; // normalized texture coords + tx1 = (float) sx1 / (float) db->width; + ty1 = (float) sy1 / (float) db->height; + tx2 = (float) sx2 / (float) db->width; + ty2 = (float) sy2 / (float) db->height; + + glColor4f(1.0f,1.0f,1.0f,1.0f); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, db->textureName); + checkGLError(); + glBegin(GL_QUADS); + glTexCoord2f (tx1, ty1 ); + glVertex3i (dx1, dy1, 0); + glTexCoord2f (tx2, ty1 ); + glVertex3i (dx2, dy1, 0); + glTexCoord2f (tx2, ty2 ); + glVertex3i (dx2, dy2, 0); + glTexCoord2f (tx1, ty2 ); + glVertex3i (dx1, dy2, 0); + glEnd(); + glDisable(GL_TEXTURE_2D); + checkGLError(); + } + glFlush(); } -jint org::xwt::plat::Carbon::_getMaxDescent(::java::lang::String* font) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); + +void Carbon$GLCarbonSurface::natReshape(jint w, jint h) { + AGLContext ctx = (AGLContext) rawCTX; + + aglSetCurrentContext (ctx); + aglUpdateContext(ctx); + + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, w, h, 0, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef (0.375, 0.375, 0.0); + checkGLError(); } -jint org::xwt::plat::Carbon::_stringWidth(::java::lang::String* font, ::java::lang::String* text) { - throw new java::lang::Error(JvNewStringLatin1("FIXME")); + +void Carbon$GLCarbonSurface::natInit() { + WindowRef window = (WindowRef) rawWindowRef; + AGLContext ctx,shared; + AGLPixelFormat fmt; + GLboolean b; + + shared = (AGLContext) gl->rawSharedContext; + fmt = (AGLPixelFormat) gl->rawPixelFormat; + ctx = aglCreateContext(fmt,shared); + checkStatus(ctx, "aglCreateContext"); + + b = aglSetDrawable(ctx,GetWindowPort(window)); + checkStatus(b,"aglSetDrawable"); + + aglSetCurrentContext(ctx); + checkGLError(); + + rawCTX = (RawData*)ctx; + + reshape(10,10); + + aglSetCurrentContext(ctx); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); +} + +void Carbon$GLCarbonSurface::natDispose() { + AGLContext ctx = (AGLContext) rawCTX; + aglDestroyContext(ctx); + Carbon$CarbonSurface::natDispose(); } +} } } // end namepsace org::xwt::plat