2003/09/05 04:28:35
authorbrian <brian@xwt.org>
Fri, 30 Jan 2004 07:04:46 +0000 (07:04 +0000)
committerbrian <brian@xwt.org>
Fri, 30 Jan 2004 07:04:46 +0000 (07:04 +0000)
darcs-hash:20040130070446-aa32f-86fd19d3dca1a438674278e3aa3eac046eaa927a.gz

src/org/xwt/plat/Carbon.cc
src/org/xwt/plat/Carbon.java
src/org/xwt/plat/GCJ.cc
src/org/xwt/plat/GCJ.java
src/org/xwt/plat/OpenGL.cc [new file with mode: 0644]
src/org/xwt/plat/OpenGL.java [new file with mode: 0644]

index 92b2dfc..914ba77 100644 (file)
-// 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 "POSIX.cc"
-#include <org/xwt/plat/Carbon.h>
-#include <org/xwt/plat/Carbon$CarbonSurface.h>
-#include <org/xwt/plat/Carbon$CarbonPicture.h>
-#include <org/xwt/plat/Carbon$CarbonDoubleBuffer.h>
-#include <org/xwt/plat/Carbon$WrappedRawData.h>
-#include <java/lang/System.h>
+#include "OpenGL.cc"
+
+#include <java/lang/Object.h>
 #include <java/lang/Error.h>
 #include <java/lang/Error.h>
-#include <java/io/PrintStream.h>
-
-// Apple's version of GCC automatically defines this symbol.
-// Since XWT is built with a "stock" version of GCC, we need to define
-// this manually to get the system header files to allow us to include them
-#define __APPLE_CPP__ 1
-
-// Standard GCC doesn't support precompiled headers,
-// meaning that it is WAY faster to just include the individual headers
-#include <CoreFoundation/CFString.h>
-#include <HIToolbox/MacWindows.h>
-#include <HIToolbox/MacApplication.h>
-#include <HIToolbox/Scrap.h>
-#include <HIToolbox/Appearance.h>
-#include <HIToolbox/CarbonEvents.h>
-#include <HIToolbox/HIView.h>
-#include <QD/ATSUnicode.h>
-
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#define max(a, b) ((a) < (b) ? (b) : (a))
-
-#define FORMAT_RECT( x ) x.left, x.top, x.right, x.bottom
-#define PRINT_RECT( x ) fprintf( stderr, #x " = (%d, %d) (%d, %d)\n", x.left, x.top, x.right, x.bottom )
-#define PRINT_CGRECT( rect ) fprintf( stderr, #rect " = %f x %f @ (%f, %f)\n", rect.size.width, rect.size.height, rect.origin.x, rect.origin.y );
-
-
-static const EventTypeSpec CarbonSurfaceEventInfo[] = {
-       { kEventClassWindow, kEventWindowUpdate },
-       { kEventClassWindow, kEventWindowBoundsChanged },
-       { kEventClassWindow, kEventWindowActivated },
-       { kEventClassWindow, kEventWindowDeactivated },
-       { kEventClassWindow, kEventWindowClose },
-       { kEventClassWindow, kEventWindowZoomed },
-       { kEventClassWindow, kEventWindowExpanded },
-       { kEventClassWindow, kEventWindowCollapsed },
-
-
-       { kEventClassKeyboard, kEventRawKeyDown },
-       { kEventClassKeyboard, kEventRawKeyRepeat },
-       { kEventClassKeyboard, kEventRawKeyUp },
-       { kEventClassKeyboard, kEventRawKeyModifiersChanged },
-
-       
-       { kEventClassMouse, kEventMouseDown },
-       { kEventClassMouse, kEventMouseUp },
-       { kEventClassMouse, kEventMouseMoved },
-       { kEventClassMouse, kEventMouseDragged },
-       { kEventClassMouse, kEventMouseExited },
-
-       
-};
 
 
-static inline UniChar GetCharacterWithoutModifiers( EventRef rawKeyboardEvent )
-{
-       UInt32 keyCode;
-       // Get the key code from the raw key event
-       GetEventParameter( rawKeyboardEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof( keyCode ), NULL, &keyCode );
-
-       // Get the current keyboard layout
- // TODO: If this is a performance sink, we need to cache these values
-       SInt16 lastKeyLayoutID = GetScriptVariable( /*currentKeyScript*/ GetScriptManagerVariable(smKeyScript), smScriptKeys);
-       Handle uchrHandle = GetResource('uchr', lastKeyLayoutID);
-
-       // Translate the key press ignoring ctrl and option
-       UInt32 ignoredDeadKeys = 0;
-       UInt32 ignoredActualLength = 0;
-       UniChar unicodeKey = 0;
-
-       // We actually want the current shift key value
-       UInt32 modifiers = (GetCurrentEventKeyModifiers() & shiftKey) >> 8;
-       OSStatus err = UCKeyTranslate( reinterpret_cast<UCKeyboardLayout*>( *uchrHandle ), keyCode, kUCKeyActionDown,
-                                                               /* modifierKeyState */ modifiers, LMGetKbdType(), kUCKeyTranslateNoDeadKeysMask, &ignoredDeadKeys,
-                                                               /* buffer length */ 1,
-                                                               /* actual length */ &ignoredActualLength,
-                                                               /* string */ &unicodeKey );
-       assert( err == noErr );
-
-       return unicodeKey;
+#include <org/xwt/plat/Carbon.h>
+#include <org/xwt/plat/Carbon$CarbonSurface.h>
+#include <org/xwt/plat/Carbon$GLCarbonSurface.h>
+#include <org/xwt/plat/Carbon$GLCarbonDoubleBuffer.h>
+#include <org/xwt/plat/Carbon$CarbonMessage.h>
+#include <org/xwt/plat/Carbon$CarbonOpenGL.h>
+#include <org/xwt/plat/Carbon$FileDialogHelper.h>
+#include <org/xwt/plat/GCJ$Retainer.h>
+#include <org/xwt/Proxy.h>
+#include <org/xwt/util/Semaphore.h>
+
+#include <Carbon/Carbon.h>
+#include <CoreFoundation/CoreFoundation.h>
+// For proxy stuff
+#include <SystemConfiguration/SystemConfiguration.h>
+// For LSOpenURLRef
+#include <ApplicationServices/ApplicationServices.h>
+
+#include <AGL/agl.h>
+
+#include <stdlib.h>
+
+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 <bool CHECK> static inline int CompileTimeCheck() { const int something_is_wrong=1; something_is_wrong++; return 0; }
+    template <> static inline int CompileTimeCheck<true>() { return 0; }
+    const static int unichar_check = CompileTimeCheck<sizeof(jchar)==sizeof(UniChar)>();
+
+    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;
 }
 
 }
 
-static CFStringRef JavaToCFString(java::lang::String* s) {
-       int len = min(1024, JvGetStringUTFLength(s));
-
-    char* buffer = (char*) malloc( len );
-    JvGetStringUTFRegion(s, 0, s->length(), buffer);
-
-       // Create a CFString from the UTF8 string
-       CFStringRef string = CFStringCreateWithBytes( NULL, (UInt8*) buffer, len, kCFStringEncodingUTF8, false );
-       assert( string != NULL );
-
-       free( buffer );
-       buffer = NULL;
+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");
+}
 
 
-       return string;
+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);
 }
 
 }
 
-static jstring CFToJavaString( CFStringRef s ) {
-       // TODO: I can probably use CFStringCreateExternalRepresentation
-       // First determine the size of the buffer required
-       const CFRange entireString = CFRangeMake( 0, CFStringGetLength( s ) );
-       CFIndex requiredSize = 0;
-       CFIndex charsConverted = CFStringGetBytes( s, entireString, kCFStringEncodingUTF8, 0, false, NULL, 0, &requiredSize );
-       assert( charsConverted == CFStringGetLength( s ) );
 
 
-       // Allocate the buffer, plus an additional byte for the null byte
-       UInt8* buffer = (UInt8*) malloc( requiredSize + 1 );
-       assert( buffer != NULL );
+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;
+}
 
 
-       // Convert the string
-       charsConverted = CFStringGetBytes( s, entireString, kCFStringEncodingUTF8, 0, false, buffer, requiredSize, NULL );
-       assert( charsConverted == CFStringGetLength( s ) );
 
 
-       buffer[requiredSize] = '\0';
+#pragma mark ------ Utility Functions ------
 
 
-       jstring string = JvNewStringUTF( (char*) buffer );
-       assert( string != NULL );
+void carbon::funcFailed(char *func,int r){
+    fprintf(stderr,"%s() failed (%d)\n",func,r);
+    exit(EXIT_FAILURE);
+} 
 
 
-       free( buffer );
-       buffer = NULL;
+#pragma mark ------ CarbonPicture Methods ------ 
 
 
-       return string;
-}
+#pragma mark ----- Carbon Surface Methods ----
 
 
-static jstring UniCharToXWTString( UniChar character )
-{
-       switch ( character ) {
-               case '\t': return JvNewStringLatin1("tab");
-               case kEscapeCharCode: return JvNewStringLatin1("escape");
-               case '\n':
-               case kEnterCharCode:
-               case kReturnCharCode:
-                       return JvNewStringLatin1("enter");
-               case kBackspaceCharCode: return JvNewStringLatin1("back_space");
-                       // escape == clear
-               //case kClearCharCode: return JvNewStringLatin1("clear");
-               //case VK_PAUSE: return JvNewStringLatin1("pause");
-               case kPageUpCharCode: return JvNewStringLatin1("page_up");
-               case kPageDownCharCode: return JvNewStringLatin1("page_down");
-               case kEndCharCode: return JvNewStringLatin1("end");
-               case kHomeCharCode: return JvNewStringLatin1("home");
-               case kLeftArrowCharCode: return JvNewStringLatin1("left");
-               case kUpArrowCharCode: return JvNewStringLatin1("up");
-               case kRightArrowCharCode: return JvNewStringLatin1("right");
-               case kDownArrowCharCode: return JvNewStringLatin1("down");
-                       // TODO: Is help always the insert key in the mac world? on my keyboard it is
-               case kHelpCharCode: return JvNewStringLatin1("insert");
-               case kDeleteCharCode: return JvNewStringLatin1("delete");
-                       // TODO: How can I determine if a numpad key was pressed?
-               //case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
-               //case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
-               //case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
-               //case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
-               //case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
-               //case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
-               //case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
-               //case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
-               //case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
-               //case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
-                       // TODO: How do I get the function key?
-               case kFunctionKeyCharCode: return JvNewStringLatin1("f1");
-               //case VK_F2: return JvNewStringLatin1("f2");
-               //case VK_F3: return JvNewStringLatin1("f3");
-               //case VK_F4: return JvNewStringLatin1("f4");
-               //case VK_F5: return JvNewStringLatin1("f5");
-               //case VK_F6: return JvNewStringLatin1("f6");
-               //case VK_F7: return JvNewStringLatin1("f7");
-               //case VK_F8: return JvNewStringLatin1("f8");
-               //case VK_F9: return JvNewStringLatin1("f9");
-               //case VK_F10: return JvNewStringLatin1("f10");
-               //case VK_F11: return JvNewStringLatin1("f11");
-               //case VK_F12: return JvNewStringLatin1("f12");
-                       
-               default:
-                       // Convert the character into a CFString, then into a java string
-                       CFStringRef string = CFStringCreateWithCharactersNoCopy( NULL, &character, 1, kCFAllocatorNull );
-                       assert( string != NULL );
-
-                       jstring str = CFToJavaString( string );
-
-                       CFRelease( string );
-                       string = NULL;
-
-                       return str;
-       }
-
-       // We should never get here
-       assert( false );
-       return NULL;
-}
 
 
-static void ModifierKeyTest( org::xwt::plat::Carbon$CarbonSurface* surface, UInt32 changedModifiers, UInt32 currentModifiers, UInt32 keyMask, const char* string )
-{
-       // If the modifier key changed
-       if ( changedModifiers & keyMask ) {
-               jstring str = JvNewStringLatin1( string );
-
-               // And it is currently down, dispatch a keypressed event
-               if ( currentModifiers & keyMask ) surface->KeyPressed( str );
-               // otherwise dispatch a key released event
-               else surface->KeyReleased( str );
-       }
+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);
 }
 }
-
-// TODO: Do I have to make the event handlers "pascal", or use "NewEventHandlerUPP"?
-pascal static OSStatus CarbonSurfaceEventHandler( EventHandlerCallRef handler, EventRef event, void* data ) {
-       UInt32 eventClass = GetEventClass( event );
-       UInt32 eventKind = GetEventKind( event );
-       OSStatus result = eventNotHandledErr;
-       org::xwt::plat::Carbon$CarbonSurface* surface = (org::xwt::plat::Carbon$CarbonSurface*)data;
-
-       //JvSynchronize dummy( surface );
-       
-       switch(eventClass) {
-               case kEventClassWindow:
-                       switch(eventKind)
-                               {
-                               case kEventWindowUpdate:
-                                       {
-                                               //fprintf( stderr, "window update " );
-
-                                               // Create the graphics context
-                                               result = CreateCGContextForPort(GetWindowPort( (WindowRef) surface->window), (CGContextRef*) &surface->gc);
-                                               assert( result == noErr && surface->gc != NULL );
-
-                                               // Quartz uses the bottom left as its origin. Translate to use the top left.
-                                               Rect bounds;
-                                               GetWindowBounds( (WindowRef) surface->window, kWindowContentRgn, &bounds );
-                                               assert( result == noErr );
-                                               CGContextTranslateCTM( (CGContextRef) surface->gc, 0, bounds.bottom - bounds.top );
-                                               CGContextScaleCTM( (CGContextRef) surface->gc, 1, -1 );
-
-                                               // Convert the context to a CGRect with local coordinates
-                                               CGRect contentBounds = CGRectMake( 0, 0, bounds.right - bounds.left, bounds.bottom - bounds.top );
-
-                                               //PRINT_CGRECT( contentBounds );
-
-                                               // Get the invalid region
-                                               Rect globalInvalidRect;
-                                               result = GetWindowBounds( (WindowRef) surface->window, kWindowUpdateRgn, &globalInvalidRect );
-                                               assert( result == noErr );
-
-                                               CGRect invalidRect = CGRectMake( globalInvalidRect.left - bounds.left, globalInvalidRect.top - bounds.top, globalInvalidRect.right - globalInvalidRect.left, globalInvalidRect.bottom - globalInvalidRect.top );
-
-                                               //invalidRect = CGRectIntersection( invalidRect, contentBounds );
-
-                                               //PRINT_CGRECT( invalidRect );
-
-                                               BeginUpdate( (WindowRef) surface->window );
-
-                                               // Erase the region with white
-                                               // TODO: Draw the window background instead
-                                               //result = SetThemeWindowBackground( (WindowRef) surface->window, ThemeBrush inBrush, true );
-                                               CGContextSetRGBFillColor( (CGContextRef) surface->gc, 1.0, 1.0, 1.0, 1.0 );
-                                               CGContextFillRect( (CGContextRef) surface->gc, invalidRect );                   
-
-                                               //CGContextSetRGBFillColor( (CGContextRef) surface->gc, red, green, blue, 0.5 );
-                                               //CGContextFillRect( (CGContextRef) surface->gc, CGRectMake( 0, 0, (bounds.right - bounds.left), (bounds.bottom - bounds.top) ) );
-                                               // Add the invalid region to XWT's dirty regions
-                                               surface->Dirty( (jint) invalidRect.origin.x, (jint) invalidRect.origin.y, (jint) invalidRect.size.width, (jint) invalidRect.size.height );
-                                               // Then tell it to actually do the drawing
-                                               surface->blitDirtyScreenRegions();
-
-                                               EndUpdate( (WindowRef) surface->window );
-
-                                               // Free the context
-                                               CGContextFlush( (CGContextRef) surface->gc );
-                                               CGContextRelease( (CGContextRef) surface->gc );
-                                               surface->gc = NULL;
-                                               result = noErr;
-                                               break;
-                                       }
-
-                               case kEventWindowBoundsChanged:
-                                       {
-                                               // We can't use the event parameter: it is the window bounds, not the content area bounds
-                                               HIRect currentBounds;
-                                               result = GetEventParameter( event, kEventParamCurrentBounds, typeHIRect, NULL, sizeof( currentBounds ), NULL, &currentBounds );
-                                               assert( result == noErr );
-                                               
-                                               // Get the event attributes to determine if size and/or origin have changed
-                                               UInt32 attributes;
-                                               result = GetEventParameter( event, kEventParamAttributes, typeUInt32, NULL, sizeof( attributes ), NULL, &attributes );
-                                               assert( result == noErr );
-
-                                               if ( attributes & kWindowBoundsChangeSizeChanged ) {
-                                                       // If maximize is set, unset it
-                                                       if ( attributes & kWindowBoundsChangeUserResize && surface->maximized ) {
-                                                               //fprintf( stderr, "maximized = 0\n" );
-                                                               surface->Maximized( false );
-                                                       }
-                                                       
-                                                       //fprintf( stderr, "size changed\n" );
-                                                       surface->SizeChange( (jint) currentBounds.size.width, (jint) currentBounds.size.height );
-
-                                                       
-                                               }
-                                               
-                                               if ( attributes & kWindowBoundsChangeOriginChanged ) {
-                                                       //fprintf( stderr, "origin changed\n" );
-                                                       surface->PosChange( (jint) currentBounds.origin.x, (jint) currentBounds.origin.y );
-                                               }
-
-                                               result = noErr;
-                                               break;
-                                       }
-
-                               case kEventWindowActivated:
-                               case kEventWindowDeactivated:
-                                       {
-                                               //fprintf( stderr, "focus = %d\n", (eventKind == kEventWindowActivated) );
-                                               surface->Focused( (eventKind == kEventWindowActivated) );
-                                               result = noErr;
-                                               break;
-                                       }
-
-                               case kEventWindowZoomed:
-                                       {
-                                               // Toggle maximized whenever we recieve this event
-                                               //fprintf( stderr, "maximized: %d\n", ! surface->maximized );
-                                               surface->Maximized( ! surface->maximized );
-                                               result = noErr;
-                                               break;
-                                       }
-                                       
-                               case kEventWindowCollapsed:
-                                       {
-                                               //fprintf( stderr, "minimized true\n" );
-                                               surface->Minimized( true );
-                                               result = noErr;
-                                               break;
-                                       }
-
-                               case kEventWindowExpanded:
-                                       {
-                                               //fprintf( stderr, "minimized false\n" );
-                                               surface->Minimized( false );
-                                               result = noErr;
-                                               break;
-                                       }
-                                       
-                               case kEventWindowClose:
-                                       {
-                                               //fprintf( stderr, "close\n" );
-                                               surface->Close();
-                                               result = noErr;
-                                               break;
-                                       }
-                               default:
-                                       throw new java::lang::Error(JvNewStringLatin1("Unhandled Window Event"));
-                               }
-                       break;
-                       
-               case kEventClassMouse:
-                       {
-                               HIPoint where;
-                               result = GetEventParameter( event, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(where), NULL, &where );
-                               assert( result == noErr );
-
-                               // Create a hit test event to ask the standard window event handler where this press is
-                               EventRef hitTest;
-                               result = CreateEvent( NULL, kEventClassWindow, kEventWindowHitTest, 0, kEventAttributeNone, &hitTest );
-                               assert( result == noErr );
-
-                               result = SetEventParameter( hitTest, kEventParamMouseLocation, typeHIPoint, sizeof(where), &where );
-                               assert( result == noErr );
-
-                               result = SetEventParameter( hitTest, kEventParamDirectObject, typeWindowRef, sizeof(surface->window), &surface->window );
-                               assert( result == noErr );
-
-                               result = SendEventToEventTarget( hitTest, GetWindowEventTarget( (WindowRef) surface->window ) );
-                               assert( result == noErr );
-
-                               WindowDefPartCode part;
-                               result = GetEventParameter( hitTest, kEventParamWindowDefPart, typeWindowDefPartCode, NULL, sizeof(part), NULL, &part );
-                               assert( result == noErr );
-
-                               ReleaseEvent( hitTest );
-                               hitTest = NULL;
-
-                               // ignore the event if it is not in the content region.
-                               if ( part != wInContent )
-                                       {
-                                       return eventNotHandledErr;
-                                       }
-
-                               // TODO: Can I get the content region's bounds as an HIRect?
-                               Rect bounds;
-                               GetWindowBounds( (WindowRef) surface->window, kWindowContentRgn, &bounds );
-                               assert( result == noErr );
-                               // Convert the context to a CGRect with local coordinates
-                               CGRect contentBounds = CGRectMake( bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top );
-
-                               // Now convert the point to content area relative coordinates:
-                               where.x -= contentBounds.origin.x;
-                               where.y -= contentBounds.origin.y;
-                               
-                               switch ( eventKind )
-                                       {
-                                       case kEventMouseDown:
-                                               {
-                                                       //fprintf( stderr, "mouse down (%f, %f)\n", where.x, where.y );
-                                                       EventMouseButton mouseButton;
-                                                       result = GetEventParameter( event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton );
-                                                       assert( result == noErr );
-
-                                                       surface->Press( mouseButton );
-                                                       result = eventNotHandledErr;
-                                                       break;
-                                               }
-
-                                       case kEventMouseUp:
-                                               {
-                                                       //fprintf( stderr, "mouse up (%f, %f)\n", where.x, where.y );
-                                                       EventMouseButton mouseButton;
-                                                       result = GetEventParameter( event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton );
-                                                       assert( result == noErr );
-
-                                                       UInt32 clickCount;
-                                                       result = GetEventParameter( event, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount );
-                                                       assert( result == noErr );
-
-                                                       surface->Release( mouseButton );
-
-                                                       // deliver click/double click events
-                                                       if ( clickCount == 1 ) {
-                                                               //fprintf( stderr, "click (%f, %f)\n", where.x, where.y );
-                                                               surface->Click( mouseButton );
-
-                                                               //result = ActivateWindow( (WindowRef) surface->window, true );
-                                                               //assert( result == noErr );
-
-                                                               //ProcessSerialNumber psn = { 0, kCurrentProcess };
-                                                               //result = SetFrontProcess( &psn );
-                                                               //assert( result == noErr );
-                                                       } else if ( clickCount == 2 ) {
-                                                               //fprintf( stderr, "double click (%f, %f)\n", where.x, where.y );
-                                                               surface->DoubleClick( mouseButton );
-                                                       }
-                                                       
-                                                       result = noErr;
-                                                       break;
-                                               }
-
-                                       case kEventMouseMoved:
-                                       case kEventMouseDragged:
-                                               {
-                                                       surface->Move( (jint) where.x, (jint) where.y );
-                                                       result = noErr;
-                                                       //fprintf( stderr, "mousemoved (%f, %f)\n", where.x, where.y );
-                                                       break;
-                                               }
-
-                                       /*case kEventMouseExited:
-                                               {
-                                                       // Move the mouse to (-1, -1) when it exits the window 
-                                                       surface->Move( -1, -1 );
-                                                       result = noErr;
-                                                       fprintf( stderr, "mouse exited\n" );
-                                                       break;
-                                               }*/
-                                               
-
-                                       /*case kEventMouseWheelMoved:
-                                       {
-                                               EventMouseWheelAxis inAxis;
-                                               result = inEvent.GetParameter<EventMouseWheelAxis>( kEventParamMouseWheelAxis, typeMouseWheelAxis, &inAxis );
-                                               assert( noErr == result );
-
-                                               SInt32 inDelta;
-                                               result = inEvent.GetParameter<SInt32>( kEventParamMouseWheelDelta, typeSInt32, &inDelta );
-                                               assert( noErr == result );
-
-                                               result = MouseWheelMoved( inAxis, inDelta, inKeyModifiers );
-                                               break;
-                                       }
-                                       */
-
-
-                                               // some other kind of Mouse event: This is (in my opinion) an error
-                                       default:
-                                               assert( false );
-                                               break;
-                                       }
-                               break;
-                       }
-
-
-               case kEventClassKeyboard:
-                       switch (eventKind)
-                       {
-                               case kEventRawKeyDown:
-                               case kEventRawKeyRepeat:
-                                       {
-                                               // TODO: This breaks international input
-                                               UniChar character = GetCharacterWithoutModifiers( event );
-                                               surface->KeyPressed( UniCharToXWTString( character ) );
-                                               
-                                               result = noErr;
-                                               break;
-                                       }
-
-                               case kEventRawKeyUp:
-                                       {
-                                               UniChar character = GetCharacterWithoutModifiers( event );
-                                               surface->KeyReleased( UniCharToXWTString( character ) );
-                                               
-                                               result = noErr;
-                                               break;
-                                       }
-
-                               case kEventRawKeyModifiersChanged:
-                                       {
-                                               static UInt32 previousModifiers = 0;
-                                               UInt32 currentModifiers = GetCurrentEventKeyModifiers();
-                                               UInt32 changedModifiers = previousModifiers ^ currentModifiers;
-
-                                               ModifierKeyTest( surface, changedModifiers, currentModifiers, shiftKey, "shift" );
-                                               ModifierKeyTest( surface, changedModifiers, currentModifiers, alphaLock, "caps_lock" );
-                                               ModifierKeyTest( surface, changedModifiers, currentModifiers, controlKey, "control" );
-                                               ModifierKeyTest( surface, changedModifiers, currentModifiers, optionKey, "alt" );
-                                               ModifierKeyTest( surface, changedModifiers, currentModifiers, kEventKeyModifierNumLockMask, "num_lock" );
-                                               
-                                               previousModifiers = currentModifiers;
-                                               result = noErr;
-                                               break;
-                                       }
-                                       
-                               default:
-                                       assert( false );
-                                       break;
-                       }
-                       break;
-                       
-               default:
-                       throw new java::lang::Error(JvNewStringLatin1("Unhandled Window Event"));
-       }
-
-       return result;
+   
+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);
 }
 
 }
 
-/** Creates a next layout from string and style. If unicodeBuffer is not null, the caller is responsable for releasing it. */
-static ATSUTextLayout CreateTextLayout( CFStringRef string, ATSUStyle style, CFStringRef* unicodeBuffer ) {
-       assert( string != NULL && unicodeBuffer != NULL && *unicodeBuffer == NULL && style != NULL );
-
-       // Create layout
-       ATSUTextLayout layout;
-       OSStatus result = ATSUCreateTextLayout( &layout );
-       assert( result == noErr && layout != NULL );
-
-       // Try to get the unicode buffer directly
-       CFIndex unicodeLength = CFStringGetLength( string );
-       assert( unicodeLength != 0 );
-       const UniChar* unicodeString = CFStringGetCharactersPtr( string );
-       if ( unicodeString == NULL )
-               {
-               // That failed. Allocate a buffer using CFAllocator so the CFString can own it
-               UniChar* buffer = (UniChar*) CFAllocatorAllocate( NULL, unicodeLength * sizeof( UniChar ), 0 );
-               assert( buffer != NULL );
-
-               // Get a copy of the text
-               CFStringGetCharacters( string, CFRangeMake( 0, unicodeLength ), buffer );
-
-               // Create a CFString which wraps and takes ownership of the buffer
-               *unicodeBuffer = CFStringCreateWithCharactersNoCopy( NULL, buffer, unicodeLength, NULL );
-               assert( *unicodeBuffer != NULL );
-
-               unicodeString = buffer;
-               }
-               
-       assert( unicodeString != NULL );
-       //UniChar* unicode_string = malloc( sizeof( UniChar ) * unicode_length );
-       //CFStringGetCharacters( string, CFRangeMake( 0, unicode_length ), unicode_string );
-       ATSUSetTextPointerLocation( layout, unicodeString, kATSUFromTextBeginning, kATSUToTextEnd, unicodeLength );
-
-       // Set the style
-       result = ATSUSetRunStyle( layout, style, kATSUFromTextBeginning, kATSUToTextEnd );
-       assert( result == noErr );
-
-       // Using this setting makes rendering match TextEdit's (except for the antialiasing rules)
-       ATSLineLayoutOptions rendering = kATSLineFractDisable; //kATSLineUseDeviceMetrics;
-       ATSUAttributeTag tag = kATSULineLayoutOptionsTag;
-       ByteCount size = sizeof( rendering );
-       ATSUAttributeValuePtr value = &rendering;
-       result = ATSUSetLayoutControls( layout, 1, &tag, &size, &value );
-       assert( noErr == result );
-
-       // Allow ATSUI to use its default font fallbacks for Unicode. This means that the font may not
-       // match exactly, but it will display the characters if it can.
-       result = ATSUSetTransientFontMatching( layout, true );
-       assert( noErr == result );
-
-    return layout;
+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");
 }
 
 }
 
-static void SetARGBFillColor( CGContextRef gc, jint argb )
-{
-       uint8_t* colour = (uint8_t*) &argb;
-       float alpha = colour[0] / 255.0;
-       float red = colour[1] / 255.0;
-       float green = colour[2] / 255.0;
-       float blue = colour[3] / 255.0;
-
-       CGContextSetRGBFillColor( gc, red, green, blue, alpha );
+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");
 }
 
 }
 
-// CarbonDoubleBuffer //////////////////////////////////////////////////////////////////////
-
-void org::xwt::plat::Carbon$CarbonDoubleBuffer::setClip(jint x1, jint y1, jint x2, jint y2) {
-       // Restore the previous graphics state, which should be the initial state as saved in
-       // natInit(). This sets the clipping region to the entire buffer.
-       CGContextRestoreGState( (CGContextRef) gc );
-       // We then immediately save the state again, so the we can reset the clipping area again
-       CGContextSaveGState( (CGContextRef) gc );
-
-       // Set the clipping area to the rectangle
-    CGContextClipToRect( (CGContextRef) gc, CGRectMake( x1, y1, x2 - x1, y2 - y1 ) );
+void Carbon$CarbonSurface::natSetTitleBarText(jstring js) {
+    SmartCFString s = js;
+    WindowRef window = (WindowRef) rawWindowRef;
+    SetWindowTitleWithCFString(window,s);
 }
 
 }
 
-void org::xwt::plat::Carbon$CarbonDoubleBuffer::drawPicture(org::xwt::Picture* s, jint x, jint y) {
-       org::xwt::plat::Carbon$CarbonPicture* source = (org::xwt::plat::Carbon$CarbonPicture*)s;
-
-       CGRect destination = CGRectMake( x, y, source->width, source->height );
-       HIViewDrawCGImage( (CGContextRef) gc, &destination, (CGImageRef) source->image );
+void Carbon$CarbonSurface::natToBack() {
+    WindowRef window = (WindowRef) rawWindowRef;
+    SendBehind(window,NULL);
 }
 
 }
 
-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;
-
-       //fprintf( stderr, "drawing stretched picture\n" );
-       //CGContextSetRGBFillColor( (CGContextRef) gc, 1.0, 0.0, 0.0, 1.0 );
-       //CGContextFillRect( (CGContextRef) gc, CGRectMake( dx1, dy1, dx2 - dx1, dy2 - dy1 ) );
-       //return;
-       
-       // Some fancy clipping work is required here: draw only inside of the destination points
-       CGContextSaveGState( (CGContextRef) gc );
-       CGContextClipToRect( (CGContextRef) gc, CGRectMake( dx1, dy1, dx2 - dx1, dy2 - dy1 ) );
-
-       // Some fancy scaling work is required here as well:
-       // We want to copy a rectangle from the source image to a destination rectangle.
-       // We are clipped to the destination rectangle, so now we must scale the source image
-       // and line it up correctly.
-       float destinationRectWidth = dx2 - dx1;
-       float destinationRectHeight = dy2 - dy1;
-       float sourceRectWidth = sx2 - sx1;
-       float sourceRectHeight = sy2 - sy1;
-       float horizontalScalingFactor = destinationRectWidth / sourceRectWidth;
-       float verticalScalingFactor = destinationRectHeight / sourceRectHeight;
-
-       // TODO: Work out the math for doing this. For now, no scaling is possible.
-       CGRect destinationRect = CGRectMake( dx1 - sx1 * horizontalScalingFactor, dy1 - sy1 * verticalScalingFactor,
-                                                                         source->width * horizontalScalingFactor, source->height * verticalScalingFactor );
-       HIViewDrawCGImage( (CGContextRef) gc, &destinationRect, (CGImageRef) source->image );
-
-       // Undo the clipping fun
-       CGContextRestoreGState( (CGContextRef) gc );
+void Carbon$CarbonSurface::natToFront() {
+    WindowRef window = (WindowRef) rawWindowRef;
+    fprintf(stderr,"SelectWindow()\n");
+    SelectWindow(window);
 }
 
 }
 
-/*void CarbonPictureRelease( void* info, const void* data, size_t size )
-{
-       // TODO: This should release a java reference, which should be
-       // obtained when this is created.
-       // It'll work without it, but that's only by "chance".
-}*/
-
-static CGImageRef CreateCGImageFromData( void* data, int width, int height, CGImageAlphaInfo alphaFormat )
-{
-       // I'm assuming that data is in RGBA format
-       const size_t NUM_COMPONENTS = 4;
-       const size_t BITS_PER_COMPONENT = 8;
-       const size_t BITS_PER_PIXEL = BITS_PER_COMPONENT * NUM_COMPONENTS;
-       const size_t BYTES_PER_PIXEL = BITS_PER_PIXEL / 8;
-       const size_t BYTES_PER_ROW = BYTES_PER_PIXEL * width;
-
-       CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
-       assert( colorSpace != NULL );
-
-       CGDataProviderRef dataProvider = CGDataProviderCreateWithData( NULL, data, width * height * BYTES_PER_PIXEL, NULL /*CarbonPictureRelease*/ );
-       assert( dataProvider != NULL );
-
-       CGImageRef image = CGImageCreate ( width, height, BITS_PER_COMPONENT, BITS_PER_PIXEL, BYTES_PER_ROW,
-                                                                       colorSpace, alphaFormat, dataProvider, NULL, 1, kCGRenderingIntentDefault );
-       assert( image != NULL );
-
-       CGDataProviderRelease( dataProvider );
-       dataProvider = NULL;
-
-       CGColorSpaceRelease( colorSpace );
-       colorSpace = NULL;
-
-       return image;
+#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");
+
+                            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;
 }
 }
-
-void org::xwt::plat::Carbon$CarbonDoubleBuffer::natInit() {
-       // FIRST: We create a CGBitmapContextRef so we can draw on this buffer
-       const int BYTES_PER_PIXEL = 4; // RGBA
-       const int BITS_PER_COMPONENT = 8;
-       
-    // Create a new bitmap context, along with the RAM for the bitmap itself
-       const int bitmapBytesPerRow   = (width * BYTES_PER_PIXEL);
-       const int bitmapByteCount     = (bitmapBytesPerRow * height);
-
-       //fprintf( stderr, "alloced %ld bytes for %d x %d double buffer\n", bitmapByteCount, width, height );
-       
-       // create an RGB color space
-       CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
-       assert( colorSpace != NULL );
-
-       // create the bitmap
-       bitmapData = (gnu::gcj::RawData*) malloc( bitmapByteCount );
-       assert( bitmapData != NULL );
-
-       // create the context
-       // TODO: Use kCGImageAlphaPremultipliedLast for better performance
-       gc = (gnu::gcj::RawData*) CGBitmapContextCreate( bitmapData, width, height, BITS_PER_COMPONENT, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedFirst );
-       assert( gc != NULL );
-
-       // the context retains the color space, so we can release it
-       // OPTIMIZATION: We could pass this colorSpace into CreateCGImageFromData
-       CGColorSpaceRelease( colorSpace );
-       colorSpace = NULL;
-
-       // Clear the double buffer to transparent
-       CGContextClearRect( (CGContextRef) gc, CGRectMake( 0, 0, width, height ) );
-       //CGContextSetRGBFillColor( (CGContextRef) gc, 1.0, 1.0, 1.0, 1.0 );
-       //CGContextFillRect( (CGContextRef) gc, CGRectMake( 0, 0, width, height ) );
-
-       // Shift the coordinate origin to the top left corner (default = bottom right)
-       CGContextTranslateCTM( (CGContextRef) gc, 0, height );
-       CGContextScaleCTM( (CGContextRef) gc, 1, -1 );
-
-
-       // SECOND: We create a CGImageRef that wraps this buffer, so we can copy it to a Surface
-       image = (gnu::gcj::RawData*) CreateCGImageFromData( bitmapData, width, height, kCGImageAlphaPremultipliedFirst );
-       assert( image != NULL );
-
-       // THIRD: Save the current graphics state so we can set and reset the clipping state
-       // We need to do this because the only way to make the clipping region larger is to
-       // restore a previous graphics state. See setClip.
-       CGContextSaveGState( (CGContextRef) gc );
+} // end namespace
+
+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$CarbonDoubleBuffer::finalize() {
-       CGContextRelease( (CGContextRef) gc );
-       CGImageRelease( (CGImageRef) image );
-    free( bitmapData );
-       bitmapData = NULL;
+void Carbon$CarbonSurface::natDispose() {
+    WindowRef window = (WindowRef) rawWindowRef;
+    DisposeWindow(window);
 }
 
 }
 
-void org::xwt::plat::Carbon$CarbonSurface::blit(org::xwt::DoubleBuffer* db, jint sx, jint sy, jint dx1, jint dy1, jint dx2, jint dy2) {
-    org::xwt::plat::Carbon$CarbonDoubleBuffer *xdb = (org::xwt::plat::Carbon$CarbonDoubleBuffer*)db;
-       assert( xdb != NULL && xdb->gc != NULL && xdb->image != NULL );
-
-       // This method is synchronized to prevent crappy threading fun
-       //JvSynchronize dummy(this);
-       
-       /*fprintf( stderr, "reading image data...\n" );
-       uint32_t* data = (uint32_t*) xdb->bitmapData;
-       for ( int i = 0; i < xdb->width * xdb->height; ++ i )
-               {
-               uint32_t temp = data[i];
-               ++ temp;
-               }
-       fprintf( stderr, "DONE\n" );*/
-
-       
-       // If we do not have a graphics context we simply mark this area as dirty and return.
-       // We'll get a WindowPaint event later on.
-       if ( gc == NULL )
-               {
-               Rect area;
-               area.left = dx1;
-               area.top = dy1;
-               area.right = dx2;
-               area.bottom = dy2;
-               // Make the rectangle where we would blit this buffer as invalid
-               OSStatus err = InvalWindowRect( (WindowRef) window, &area );
-               //OSStatus err = QDAddRectToDirtyRegion( GetWindowPort( (WindowRef) window ), &area );
-               assert( err == noErr );
-
-               //fprintf( stderr, "blit: but marking invalid " );
-               //PRINT_RECT( area );
-               return;
-               }
-       assert( gc != NULL );
-
-       //fprintf( stderr, "blit\n" );
-       
-       // Make sure that the CGImage is up to date
-       CGContextFlush( (CGContextRef) xdb->gc );
-
-       // Some fancy clipping work is required here: draw only inside of the destination rectangle
-       CGContextSaveGState( (CGContextRef) gc );
-       CGContextClipToRect( (CGContextRef) gc, CGRectMake( dx1, dy1, dx2 - dx1, dy2 - dy1 ) );
-
-       // Draw the image on the surface
-       CGRect destination = CGRectMake( dx1 - sx, dy1 - sy, xdb->width, xdb->height );
-       HIViewDrawCGImage( (CGContextRef) gc, &destination, (CGImageRef) xdb->image );
-
-       // Undo the clipping fun
-       CGContextRestoreGState( (CGContextRef)gc );     
+void Carbon$CarbonSurface::natSetIcon(org::xwt::Picture *_p) {
 }
 
 }
 
-void org::xwt::plat::Carbon$CarbonDoubleBuffer::fillRect (jint x, jint y, jint x2, jint y2, jint argb) {
-       // Set the Fill color to match
-       SetARGBFillColor( (CGContextRef) gc, argb );
-       CGContextFillRect( (CGContextRef) gc, CGRectMake( x, y, x2 - x, y2 - y ) );
+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$CarbonDoubleBuffer::drawString(::java::lang::String* font, ::java::lang::String* text, jint x, jint y, jint argb) {
-       ATSUStyle style = (ATSUStyle) ((org::xwt::plat::Carbon*)org::xwt::plat::Carbon::platform)->_getATSUStyle( font );
-       CFStringRef string = JavaToCFString( text );
-
-       CFStringRef unicodeBuffer = NULL;
-       ATSUTextLayout layout = CreateTextLayout( string, style, &unicodeBuffer );
-
-       // Associate the graphics context with the text layout object
-       ATSUAttributeTag tag = kATSUCGContextTag;
-       ByteCount size = sizeof( gc );
-       ATSUAttributeValuePtr value = &gc;
-       OSStatus result = ATSUSetLayoutControls( layout, 1, &tag, &size, &value );
-       assert( result == noErr );
-
-    // The Quartz RGB fill color influences the ATSUI color
-       SetARGBFillColor( (CGContextRef) gc, argb );
-
-       // I've flipped the context to "standard" coordinates, but draw text needs it to be flipped back
-       CGContextSaveGState( (CGContextRef) gc );
-       CGContextScaleCTM( (CGContextRef) gc, 1.0, -1.0 );
-       y = -y;
-
-       // Draw text
-       result = ATSUDrawText( layout, kATSUFromTextBeginning, kATSUToTextEnd, X2Fix( x ), X2Fix( y ) );
-       assert( result == noErr );
-
-       CGContextRestoreGState( (CGContextRef) gc );
-
-       result = ATSUDisposeTextLayout( layout );
-       assert( result == noErr );
-       layout = NULL;
-
-       if ( unicodeBuffer != NULL ) {
-               CFRelease( unicodeBuffer );
-               unicodeBuffer = NULL;
-       }
-
-       CFRelease( string );
-       string = NULL;
+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");
 }
 
 }
 
-// CarbonSurface //////////////////////////////////////////////////////////////////////
-
-void org::xwt::plat::Carbon$CarbonSurface::setIcon(org::xwt::Picture* pic) {
-       org::xwt::plat::Carbon$CarbonPicture *picture = (org::xwt::plat::Carbon$CarbonPicture*)pic;
-
-       // TODO: This sets the dock icon. Maybe I should set the document icon (the icon beside the window title)?
-       //       or set the "window preview" that is shown when a window is collapsed?
-       // TODO: This doesn't seem to work. Maybe it is a size problem?
-       OSStatus result = SetApplicationDockTileImage( (CGImageRef) picture->image );
-       assert( result == noErr );
+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::setTitleBarText(java::lang::String* s) {
-       CFStringRef string = JavaToCFString( s );
-       OSStatus result = SetWindowTitleWithCFString( (WindowRef) window, string );
-    assert( result == noErr );
 
 
-       CFRelease( string );
-       string = NULL;
+#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::setSize (jint width, jint height) {
-       Rect bounds;
-       OSStatus result = GetWindowBounds( (WindowRef) window, kWindowContentRgn, &bounds );
-       assert( result == noErr );
-
-       bounds.right = bounds.left + width;
-       bounds.bottom = bounds.top + height;
-       
-    result = SetWindowBounds( (WindowRef) window, kWindowContentRgn, &bounds );
-       assert( result == noErr );
-       result = ConstrainWindowToScreen( (WindowRef) window, kWindowContentRgn, kWindowConstrainStandardOptions, NULL, NULL );
-       assert( result == noErr );
-
-       fprintf( stderr, "set size (%d, %d) (%d, %d)\n", FORMAT_RECT( bounds ) );
-       // TODO: Shouldn't this deliver a "size changed" event automatically?
-       //SizeChange( width, height );
+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::setLocation (jint x, jint y) {
-       Rect bounds;
-       OSStatus result = GetWindowBounds( (WindowRef) window, kWindowStructureRgn, &bounds );
-       assert( result == noErr );
-
-       int temp = bounds.right - bounds.left;
-       bounds.left = x;
-       bounds.right = x + temp;
-       temp = bounds.bottom - bounds.top;
-       bounds.top = y;
-       bounds.bottom = y + temp;
-
-    result = SetWindowBounds( (WindowRef) window, kWindowStructureRgn, &bounds );
-       assert( result == noErr );
-       result = ConstrainWindowToScreen( (WindowRef) window, kWindowStructureRgn, kWindowConstrainStandardOptions, NULL, NULL );
-       assert( result == noErr );
-
-       fprintf( stderr, "set location (%d, %d) (%d, %d)\n", FORMAT_RECT( bounds ) );
+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::natInit (jboolean framed) {
-       // Create a standard window. Maybe I should be using the Appearance Manager ones?
-       OSStatus result = noErr;
-       Rect bounds;
-       bounds.left = 0;
-       bounds.top = 0;
-       bounds.right = 100;
-       bounds.bottom = 100;
-       if ( framed ) {
-               OSStatus result = CreateNewWindow( kDocumentWindowClass,
-                                                                         kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowLiveResizeAttribute,
-                                                                         &bounds,
-                                                                         (WindowRef*) &window
-                                                                         );
-       }
-       else {
-               OSStatus result = CreateNewWindow( kPlainWindowClass,
-                                                                         kWindowStandardHandlerAttribute | kWindowLiveResizeAttribute,
-                                                                         &bounds,
-                                                                         (WindowRef*) &window
-                                                                         );
-       }
-       assert( result == noErr && window != NULL );
-
-       // Install the event handler
-       result = InstallEventHandler( GetWindowEventTarget( (WindowRef) window ),
-                                                          CarbonSurfaceEventHandler,
-                                                          GetEventTypeCount( CarbonSurfaceEventInfo ), CarbonSurfaceEventInfo,
-                                                          this,
-                                                          NULL );
-       assert( result == noErr );
-       
-       // Make sure that this window is NOT visible
-       //HideWindow( (WindowRef) window );
-}
+void Carbon::natSetClipBoard(jstring js) {
+    unsigned int length = js->length();
+    ScrapRef scrap;
+    OSStatus r;
 
 
-void org::xwt::plat::Carbon$CarbonSurface::toFront() {
-    BringToFront( (WindowRef) window );
-       //OSStatus result = ActivateWindow( (WindowRef) window, true );
-       //assert( result == noErr );
-
-       // Using the default "current process" or actually fetching the current process doesn't work
-       ProcessSerialNumber currentProcess = { 0, kCurrentProcess }; 
-       OSStatus result = GetCurrentProcess( &currentProcess );
-       assert( result == noErr );
-       result = SetFrontProcessWithOptions( &currentProcess, kSetFrontProcessFrontWindowOnly );
-       assert( result == noErr );
+    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::toBack() {
-    SendBehind( (WindowRef) window, NULL );
+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<java::lang::String*>*)
+            JvNewObjectArray(count,&java::lang::String::class$,0);
+        for(i=0;i<count;i++) {
+            string = (CFStringRef) CFArrayGetValueAtIndex(exceptionList,i);
+            if(string != NULL && CFGetTypeID(string) != CFStringGetTypeID()) string = NULL;
+            elements(p->excluded)[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<java::lang::String*>*)
+            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<java::lang::String*>*)
+            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;
+*/
 }
 
 }
 
-void org::xwt::plat::Carbon$CarbonSurface::syncCursor() {
-       ThemeCursor curs;
-    if (cursor->equals(JvNewStringLatin1("crosshair"))) curs = kThemeCrossCursor;
-    //else if (cursor->equals(east)) curs = kThemeArrowCursor;
-    else if (cursor->equals(JvNewStringLatin1("hand"))) curs = kThemePointingHandCursor;
-    //else if (cursor->equals(move)) curs = kThemeArrowCursor;
-    //else if (cursor->equals(north)) curs = kThemeArrowCursor;
-    //else if (cursor->equals(northeast)) curs = kThemeArrowCursor;
-    //else if (cursor->equals(northwest)) curs = kThemeArrowCursor;
-    //else if (cursor->equals(south)) curs = kThemeArrowCursor;
-    //else if (cursor->equals(southeast)) curs = kThemeArrowCursor;
-    //else if (cursor->equals(southwest)) curs = kThemeArrowCursor;
-    else if (cursor->equals(JvNewStringLatin1("text"))) curs = kThemeIBeamCursor;
-    //else if (cursor->equals(west)) curs = kThemeArrowCursor;
-    else if (cursor->equals(JvNewStringLatin1("wait_string"))) curs = kThemeSpinningCursor;
-    else curs = kThemeArrowCursor;
-       
-       // TODO: This should PROBABLY be activated/deactivated when over the window using mouse tracking regions
-       SetThemeCursor( curs );
+jint Carbon::cgScreenWidth() {
+    return CGDisplayPixelsWide(kCGDirectMainDisplay);
 }
 
 }
 
-void org::xwt::plat::Carbon$CarbonSurface::_dispose() {
-    ReleaseWindow( (WindowRef) window );
-       window = NULL;
+jint Carbon::cgScreenHeight() {
+    return CGDisplayPixelsHigh(kCGDirectMainDisplay);
 }
 
 }
 
-void org::xwt::plat::Carbon$CarbonSurface::setInvisible(jboolean i) {
-       //fprintf( stderr, "invisible = %d\n", i );
-    if ( i ) {
-               HideWindow( (WindowRef) window );
-       } else {
-               ShowWindow( (WindowRef) window );
-       }
+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);
 }
 
 }
 
-void org::xwt::plat::Carbon$CarbonSurface::_setMaximized(jboolean b) {
-       Point ideal;
-       // TODO: Probably should use the actual screen size here
-       ideal.h = CGDisplayPixelsWide( kCGDirectMainDisplay );
-       ideal.v = CGDisplayPixelsHigh( kCGDirectMainDisplay );
-       //fprintf( stderr, "maximized = %d\n", b );
-    OSStatus result = ZoomWindowIdeal( (WindowRef) window, ( b ? inZoomOut : inZoomIn ), &ideal );
-       // TODO: It seems to work, so why does it return an error? Theory: XWT is not in a bundle.
-       assert( result == noErr );
+void Carbon::_exit() {
+    QuitApplicationEventLoop();
 }
 
 }
 
-void org::xwt::plat::Carbon$CarbonSurface::_setMinimized(jboolean b) {
-    OSStatus result = CollapseWindow( (WindowRef) window, b );
-       // TODO: It seems to work, so why does it return an error? Theory: XWT is not in a bundle.
-       //assert( result == noErr );
+#define XWT_CARBON_NO_BUNDLE_HACK
+#ifdef XWT_CARBON_NO_BUNDLE_HACK
+extern "C" {
+    OSErr CPSEnableForegroundOperation(ProcessSerialNumber *psn);
+    OSErr CPSSetFrontProcess(ProcessSerialNumber *psn);
 }
 }
-
-void org::xwt::plat::Carbon$CarbonPicture::natInit() {
-       assert( data->length == width * height );
-       image = (gnu::gcj::RawData*) CreateCGImageFromData( elements(data), width, height, kCGImageAlphaFirst );
-       assert( image != NULL );
+#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(&currentProcess);
+        checkStatus(r,"GetCurrentProcess");
+        r = CPSEnableForegroundOperation( &currentProcess );
+        checkStatus(r,"CPSEnableForegroundOperation");
+        r = CPSSetFrontProcess(&currentProcess);
+        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
 }
 
 }
 
-void org::xwt::plat::Carbon$CarbonPicture::finalize() {
-       CGImageRelease( (CGImage*) image );
-       image = NULL;
+void Carbon::_running() {
+    RunApplicationEventLoop();
+    ExitToShell();
 }
 
 }
 
-// Carbon ///////////////////////////////////////////////////////////////////
+#pragma mark ------ OpenGL Functions -----
 
 
-jint org::xwt::plat::Carbon::_getScreenWidth() {
-       //fprintf( stderr, "screen width = %d\n", CGDisplayPixelsWide( kCGDirectMainDisplay ) );
-       return CGDisplayPixelsWide( kCGDirectMainDisplay );
+void Carbon$CarbonOpenGL::activateSharedContext() {
+    AGLContext ctx = (AGLContext) rawSharedContext;
+    aglSetCurrentContext(ctx);
 }
 
 }
 
-jint org::xwt::plat::Carbon::_getScreenHeight() {
-       //fprintf( stderr, "screen height = %d\n", CGDisplayPixelsHigh( kCGDirectMainDisplay ) );
-    return CGDisplayPixelsHigh( kCGDirectMainDisplay );
+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;
 }
 
 }
 
-jstring org::xwt::plat::Carbon::_getClipBoard() {
-       // Get the clipboard reference
-       ScrapRef scrap = NULL;
-       OSStatus result = GetCurrentScrap( &scrap );
-       assert( result == noErr );
-
-       ScrapFlavorFlags flavorFlags;
-       result = GetScrapFlavorFlags ( scrap, kScrapFlavorTypeUnicode, &flavorFlags );
-
-       if ( result == noErr ) {
-               // No error, we have unicode data in a Scrap. Find out how many bytes of data it is.
-               Size bytes = 0;
-               result = GetScrapFlavorSize( scrap, kScrapFlavorTypeUnicode, &bytes );
-               assert( result == noErr );
-               const Size numUniChars = bytes / sizeof( UniChar );
-
-               // Allocate a buffer for the text using Core Foundation
-               UniChar* buffer = reinterpret_cast<UniChar*>( CFAllocatorAllocate( NULL, bytes, 0 ) );
-               assert( buffer != NULL );
-
-               // Get a copy of the text
-               Size nextBytes = bytes;
-               result = GetScrapFlavorData( scrap, kScrapFlavorTypeUnicode, &nextBytes, buffer );
-               assert( result == noErr );
-
-               // Create a CFString which wraps and takes ownership of the buffer
-               CFStringRef string = CFStringCreateWithCharactersNoCopy( NULL, buffer, numUniChars, NULL );
-               assert( string != NULL );
-               buffer = NULL; // string now owns this buffer
-
-               jstring ret = CFToJavaString( string );
-
-               // Default allocator releases both the CFString and the UniChar buffer (text)
-               CFRelease( string );
-               string = NULL;
-
-               return ret;
-       } else {
-               return JvNewStringLatin1("");
-       }       
+void Carbon$CarbonOpenGL::initSharedContext() {
+    AGLPixelFormat fmt =  (AGLPixelFormat) rawPixelFormat;
+    rawSharedContext = (RawData*) aglCreateContext(fmt,NULL);
+    checkStatus(rawSharedContext,"aglCreateContext");
 }
 
 }
 
-void org::xwt::plat::Carbon::_setClipBoard(jstring s) {
-       CFStringRef string = JavaToCFString( s );
-
-       OSStatus result = ClearCurrentScrap();
-       assert( result == noErr );
-
-       ScrapRef scrap = NULL;
-       result = GetCurrentScrap( &scrap );
-       assert( result == noErr );
-
-       CFIndex numUniChars = CFStringGetLength( string );
-
-       // Try to get a pointer to the unicode data first, then do the copy if needed
-       const UniChar* buffer = CFStringGetCharactersPtr( string );
-       if ( buffer != NULL )
-               {
-               result = PutScrapFlavor ( scrap, kScrapFlavorTypeUnicode, 0, sizeof( UniChar ) * numUniChars, buffer );
-               assert( result == noErr );
-               }
-       else
-               {
-               UniChar* buffer = (UniChar*) malloc( sizeof( UniChar ) * numUniChars );
-               assert( buffer != NULL );
-               CFStringGetCharacters( string, CFRangeMake( 0, numUniChars ), buffer );
-
-               result = PutScrapFlavor ( scrap, kScrapFlavorTypeUnicode, 0, sizeof( UniChar ) * numUniChars, buffer );
-               assert( result == noErr );
-
-               // Done with the UniChar* buffer
-               free( buffer );
-               buffer = NULL;
-               }
-               
-       // Done with the CFString
-       CFRelease( string );
-       string = NULL;
+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;
 }
 
 }
 
-/*
-JArray<java::lang::String*>* org::xwt::plat::Carbon::listNativeFonts() {
-       ATSFontFamilyIterator iterator;
-       OSStatus result = ATSFontFamilyIteratorCreate( kATSFontContextUnspecified, NULL, NULL, kATSOptionFlagsDefault, &iterator );
-       if ( result != noErr ) throw new java::lang::Error(JvNewStringLatin1("ASSERT"));
-
-       // Iterate over fonts twice: The first time just to count the fonts so we can create the array
-       // The second time gets the font names
-       ATSFontFamilyRef font = NULL;
-       int i = -1;
-       while ( result == noErr )
-               {
-               i ++;
-               result = ATSFontFamilyIteratorNext( iterator, &font );
-               }
-       if ( result != kATSIterationCompleted ) throw new java::lang::Error(JvNewStringLatin1("ASSERT"));
-
-       result = ATSFontFamilyIteratorReset( kATSFontContextUnspecified, NULL, NULL, kATSOptionFlagsDefault, &iterator );
-       if ( result != noErr ) throw new java::lang::Error(JvNewStringLatin1("ASSERT"));
-
-       JArray<jstring>* fonts = (JArray<jstring>*)JvNewObjectArray( i, &(::java::lang::String::class$), NULL);
-
-       ATSFontFamilyRef font = NULL;
-       result = ATSFontFamilyIteratorNext( iterator, &font );
-       while( result == noErr )
-               {
-               CFStringRef name = NULL;
-               result = ATSFontFamilyGetName( font, kATSOptionFlagsDefault, &name );
-               if ( result != noErr || name == NULL ) throw new java::lang::Error(JvNewStringLatin1("ASSERT"));
-
-               //const char* cstring = CFStringGetCStringPtr( name, kCFStringEncodingMacRoman );
-               //if ( cstring != NULL ) fprintf( stderr, "%s\n", cstring );
-               
-               jstring xwtName = CFToJavaString( name );
-
-               // 
-               xwtName = xwtName->replace(' ', '_')->toLowerCase()->concat( "0" ); 
-               CFRelease( name );
-               name = NULL;
-
-               result = ATSFontFamilyIteratorNext( iterator, &font );
-               i ++;
-               }
-       if ( result != kATSIterationCompleted ) throw new java::lang::Error(JvNewStringLatin1("ASSERT"));
-
-       result = ATSFontFamilyIteratorRelease ( &iterator );
-       if ( result != noErr ) throw new java::lang::Error(JvNewStringLatin1("ASSERT"));
-
-    return fonts;
+void Carbon$GLCarbonDoubleBuffer::activateContext() {
+    AGLContext ctx = (AGLContext) rawCTX;
+    aglSetCurrentContext(ctx);
 }
 }
-*/
-
 
 
-/*gnu::gcj::RawData* org::xwt::plat::Carbon::fontStringToStruct(jstring s) {
-    throw new java::lang::Error(JvNewStringLatin1("FIXME"));
-}*/
-
-// HACK: WARNING: Undocumented Hack! This may break in the future
-// For now, however, it allows a non-bundled app to create Windows! Yay!
-extern "C" { OSErr CPSEnableForegroundOperation(ProcessSerialNumber *psn); }
-
-void org::xwt::plat::Carbon::natInit() {
-       // HACK: WARNING: Undocumented Hack! This may break in the future
-       // For now, however, it allows a non-bundled app to create Windows! Yay!
-       ProcessSerialNumber currentProcess = { 0, kCurrentProcess }; // Using the default "current process" doesn't work
-       OSStatus result = GetCurrentProcess( &currentProcess );
-       assert( result == noErr );
-       result = CPSEnableForegroundOperation( &currentProcess );
-       assert( result == noErr );
-
-       // Initiaize the native font hashtable
-       // Get a copy of all available fonts
-       ItemCount numFonts;
-       result = ATSUFontCount( &numFonts );
-       assert( result == noErr );
-
-       ATSFontRef* fonts = (ATSFontRef*) malloc( sizeof(ATSFontRef) * numFonts );
-       assert( fonts != NULL );
-
-       ItemCount currentNumFonts;
-       result = ATSUGetFontIDs( fonts, numFonts, &currentNumFonts );
-       assert( result == noErr );
-       numFonts = min( currentNumFonts, numFonts ); // Just to be safe, maybe the number of fonts changed (unlikely!)
-
-       const ByteCount MAX_NAME_LENGTH = 100;
-       char familyName[MAX_NAME_LENGTH+1];
-       for ( ItemCount i = 0; i < numFonts; i ++ ) {
-               ByteCount actualBytes = 0;
-               result = ATSUFindFontName( fonts[i], kFontFamilyName, (FontPlatformCode) kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
-                                                         MAX_NAME_LENGTH, familyName, &actualBytes, NULL );
-
-               // If we were able to get a macintosh string for the font family name, use it to make a jstring
-               if ( result == noErr && actualBytes > 0 )
-                       {
-                       familyName[actualBytes] = '\0';
-
-                       jstring xwtName = JvNewStringLatin1( familyName, actualBytes );
-
-                       // Convert the font family name to an XWT font name
-                       xwtName = xwtName->replace(' ', '_')->toLowerCase();
-                       // Map the first font we find to this family name. The first font is the "Regular" font.
-                       if ( nativeFontCache->get( xwtName ) == NULL )
-                               nativeFontCache->put( (java::lang::Object*) xwtName, new org::xwt::plat::Carbon$WrappedRawData( (::gnu::gcj::RawData*) fonts[i] ) );
-                       }
-               else
-                       {
-                       //fprintf( stderr, "FONT HAS NO MAC NAME\n" );
-                       }
-       }
-       
-       free( fonts );
-       fonts = NULL;
+void Carbon$GLCarbonDoubleBuffer::natCleanup(RawData* rawWindowRef, RawData* rawCTX) {
+    WindowRef window = (WindowRef) rawWindowRef;
+    AGLContext ctx = (AGLContext) rawCTX;
+    aglDestroyContext(ctx);
+    DisposeWindow(window);
 }
 
 }
 
-jint org::xwt::plat::Carbon::_stringWidth(::java::lang::String* font, ::java::lang::String* text) {
-       // If the string doesn't have any characters, return zero immediately 
-       if ( text->length() == 0 ) return 0;
-       
-       ATSUStyle style = (ATSUStyle) _getATSUStyle( font );
-       CFStringRef string = JavaToCFString( text );
-
-       CFStringRef unicodeBuffer = NULL;
-       ATSUTextLayout layout = CreateTextLayout( string, style, &unicodeBuffer );
-
-       unsigned long actualNumberOfBounds = 0;
-       ATSTrapezoid glyphBounds;
-
-       // We get a single bound, since the text should only require one. If it requires more, there is an issue
-       OSStatus result = ATSUGetGlyphBounds( layout, 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
-       assert( result == noErr && actualNumberOfBounds == 1 );
-
-       ATSUDisposeTextLayout( layout );
-       layout = NULL;
-
-       if ( unicodeBuffer != NULL ) {
-               CFRelease( unicodeBuffer );
-               unicodeBuffer = NULL;
-               }
-
-       CFRelease( string );
-       string = NULL;
-
-       return Fix2Long( glyphBounds.upperRight.x - glyphBounds.upperLeft.x );
+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::_getMaxAscent(::java::lang::String* font) {
-       ATSUStyle style = (ATSUStyle) _getATSUStyle( font );
-       
-       ByteCount actualSize = 0;
-       ATSUTextMeasurement ascent;
-       OSStatus result = ATSUGetAttribute( style, kATSUAscentTag, sizeof( ascent ), &ascent, &actualSize );
-       assert( result == kATSUNotSetErr );
-
-       //fprintf( stderr, "ascent = %ld\n", Fix2Long( ascent ) );
-
-       return Fix2Long( ascent );
+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::_getMaxDescent(::java::lang::String* font) {
-       ATSUStyle style = (ATSUStyle) _getATSUStyle( font );
-
-       ByteCount actualSize = 0;
-       ATSUTextMeasurement descent;
-       OSStatus result = ATSUGetAttribute( style, kATSUDescentTag, sizeof( descent ), &descent, &actualSize );
-       assert( result == kATSUNotSetErr );
-
-       //fprintf( stderr, "descent = %ld\n", Fix2Long( descent ) );
 
 
-       return Fix2Long( descent );
+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);
 }
 
 }
 
-gnu::gcj::RawData* org::xwt::plat::Carbon::_createATSUStyle( gnu::gcj::RawData* fontRef, jint fontSize, jboolean isBold, jboolean isItalic, jboolean isUnderline ) {
-       ATSUStyle style;
-       OSStatus result = ATSUCreateStyle( &style );
-       assert( result == noErr && style != NULL );
-
-    // Font
-    ATSFontRef font = (ATSFontRef) fontRef;
-       Fixed size = X2Fix( fontSize );
-       Boolean bold = isBold;
-       Boolean italic = isItalic;
-       Boolean underline = isUnderline;
-
-       const ATSUAttributeTag tags[] = { kATSUFontTag, kATSUSizeTag, kATSUQDBoldfaceTag, kATSUQDItalicTag, kATSUQDUnderlineTag };
-       ByteCount sizes[] = { sizeof( font ), sizeof( size ), sizeof( bold ), sizeof( italic ), sizeof( underline ) };
-       ATSUAttributeValuePtr values[] = { &font, &size, &bold, &italic, &underline };
-
-       result = ATSUSetAttributes( style, sizeof( tags ) / sizeof( *tags ), tags, sizes, values );
-       assert( result == noErr );
-
-       // TODO: Why do I have to turn this off manually? This shouldn't this be the default?
-       ATSUFontFeatureType featureType = kLigaturesType;
-       ATSUFontFeatureSelector selector = kCommonLigaturesOffSelector;
-       result = ATSUSetFontFeatures( style, 1, &featureType, &selector );
-       assert( result == noErr );
-
-       return (gnu::gcj::RawData*) style;
+void Carbon$GLCarbonSurface::natDispose() {
+    AGLContext ctx = (AGLContext) rawCTX;
+    aglDestroyContext(ctx);
+    Carbon$CarbonSurface::natDispose();
 }
 
 }
 
-
-/** Called once XWT is initialized and the application is running. */
-void org::xwt::plat::Carbon::_running() {
-       // TODO: This is going to be a bit magical:
-       // Let's see what happens when we mix multithreading and OS X applications.
-       // Theory: Bad stuff may happen if events are delivered and other stuff is going on at
-       // the same time. However, I'm going to pray that XWT's Java stuff locks things for me,
-       // So by the time I call into the Java code, i'm the only code path active?
-       RunApplicationEventLoop();
-
-       org::xwt::plat::Carbon::exit(); 
-}
+} } } // end namepsace org::xwt::plat
index 5dc019f..c6ec350 100644 (file)
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [LGPL]
+// Authors: Brian Alliet and Evan Jones
+
 package org.xwt.plat;
 
 import gnu.gcj.RawData;
 package org.xwt.plat;
 
 import gnu.gcj.RawData;
-import java.net.*;
-import java.lang.reflect.*;
-import java.io.*;
-import java.util.*;
 import org.xwt.util.*;
 import org.xwt.*;
 import org.xwt.util.*;
 import org.xwt.*;
+import java.util.*;
 
 
-/** Platform implementation for Carbon UI on a POSIX-compliant OS (ie Mac OS X) */
 public class Carbon extends POSIX {
 public class Carbon extends POSIX {
-
-        /** hashtable of all OS X fonts; key is an XWT font name, value is WrappedRawData which stores an ATSFontRef.
-        *       Initialized by natInit(). */
-        static Hashtable nativeFontCache = new Hashtable();
-
-        /** Cache of ATSUStyle objects; key is an XWT font spec, value is WrappedRawData which stores an ATSUStyle.
-        * According to an Apple technote, caching the style bjects can really increase performance. */
-        static Hashtable atsuStyleCache = new Hashtable();
-
-        /** List of all XWT font specs. Initialized by init(). */
-        static String[] fontList = null;
-
-    // General Methods ///////////////////////////////////////////////////////
-
-    protected String _getAltKeyName() { return "option"; }
-    protected String[] _listFonts() { return fontList; }
-    protected Picture _createPicture(int[] data, int w, int h) { return new CarbonPicture(data, w, h); }
-    protected DoubleBuffer _createDoubleBuffer(int w, int h, Surface owner) { return new CarbonDoubleBuffer(w, h); }
-    protected Surface _createSurface(Box b, boolean framed) { return new CarbonSurface(b, framed); }
+    static Carbon singleton;
+    private CarbonOpenGL openGL;
+    boolean jaguar; // true if we are on OS X >= 10.2
+    
+    // TEMPORARY HACKS (remove these when we ditch platform fonts)
+    protected int _stringWidth(String font, String text) { return (int)Math.round(6.5 * text.length()); }
+    protected int _getMaxAscent(String font) { return 10; }
+    protected int _getMaxDescent(String font) { return 2; }
+    
+    // General Methods
+    protected String _getAltKeyName() { return "Option"; }
     protected boolean _needsAutoClick() { return false; }
     protected boolean _needsAutoClick() { return false; }
-    protected native int _getScreenWidth();
-    protected native int _getScreenHeight();
-    protected native String _getClipBoard();
-    protected native void _setClipBoard(String s);
-        static String defaultFontName = "lucida_grande";
-    protected String _getDefaultFont() { return defaultFontName + "13"; }
-        protected native int _stringWidth(String fontSpec, String text);
-    protected native int _getMaxAscent(String font);
-    protected native int _getMaxDescent(String font);
     protected boolean _needsAutoDoubleClick() { return false; }
     protected boolean _needsAutoDoubleClick() { return false; }
+    protected String getDescriptiveName() { return "GCJ Carbon Binary"; }
+    protected boolean _isCaseSensitive() { return false; /* Well, not always, could be UFS */ }
+    
+    
+    // Native Methods
+    protected int    _getScreenWidth() { return cgScreenWidth(); }
+    protected int    _getScreenHeight() { return cgScreenHeight(); }
+    private native static int cgScreenWidth();
+    private native static int cgScreenHeight();
+    protected native void   _newBrowserWindow(String url);
+    protected native Proxy   natDetectProxy();
+    private   native void    natInit();
+    protected native void   _exit();
+
+    private native String natGetClipBoard();
+    private native void natSetClipBoard(String text);
+    protected void _setClipBoard(final String text) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetClipBoard(text); } }); }
+    protected String _getClipBoard() {
+        final Semaphore sem = new Semaphore();
+        final String[] result = new String[1]; // Kind of like a pointer
+        CarbonMessage.add(new CarbonMessage() { public void perform() { result[0] = natGetClipBoard(); sem.release(); } });
+        sem.block();
+        return result[0];
+    }
+    
+    private static class FileDialogHelper {
+        public FileDialogHelper(boolean save) { this.save = save; }
+        public boolean save;
+        public Semaphore sem = new Semaphore();
+        public String fileName;
+        public String saveName;
+        public RawData rawUPP;
+    }
+    private native void natFileDialog(FileDialogHelper helper, String suggestedFileName, boolean write);
+    protected String _fileDialog(final String fn, final boolean w) {
+        final FileDialogHelper helper = new FileDialogHelper(w);
+        CarbonMessage.add(new CarbonMessage() { public void perform() { natFileDialog(helper,fn,w); } });
+        helper.sem.block();
+        if(w)
+            return helper.fileName + "/" + helper.saveName;
+        else
+            return helper.fileName;
+    }
 
 
-        /** Returns the ATSUStyle associated with the given XWT font spec.
-        *       This method first checks its internal cache before creating the
-        *       ATSUStyle object from scratch. */
-        protected RawData _getATSUStyle( String fontSpec ) {
-                WrappedRawData ret = null;
-                ret = (WrappedRawData) atsuStyleCache.get( fontSpec );
-                if (ret != null) return ret.wrapee;
-
-                Platform.ParsedFont pf = new Platform.ParsedFont( fontSpec );
-
-                // Find the font
-                if (pf.name.equals("serif")) pf.name = "lucida_grande";
-                else if (pf.name.equals("sansserif")) pf.name = "helvetica";
-                else if (pf.name.equals("monospace")) pf.name = "courier";
-                else if (pf.name.equals("dialog")) pf.name = "lucida_grande";
-                else if (pf.name.equals("tty")) pf.name = "courier";
-
-                // Find the ATSFontRef
-                WrappedRawData fontRef = (WrappedRawData) nativeFontCache.get( pf.name );
-                // If we couldn't find the font, use the default font
-                if ( fontRef == null ) fontRef = (WrappedRawData) nativeFontCache.get( defaultFontName );
-                if ( fontRef == null ) throw new Error( "Default font cannot be found" );
-                                
-                // Create the ATSUStyle object
-                ret = new WrappedRawData( _createATSUStyle( fontRef.wrapee, pf.size, pf.bold, pf.italic, pf.underline ) );
-
-                // Map this font spec to the ATSFontRef to optimize future requests
-                atsuStyleCache.put( fontSpec, ret );
-
-        return ret.wrapee;
+    
+    // Called by main thread after initialization, this is the event handler
+    protected native void _running();
+    
+    static void abort(String err) {
+        throw new Error(err);
+    }
+    
+    public Carbon() {
+        synchronized(Carbon.class) {
+            if(singleton != null) abort("Tried to instansiate Carbon more than once");
+            singleton = this;
         }
         }
-
-        /** Creates an ATSUStyle object with the specified attributes. */
-        protected native RawData _createATSUStyle( RawData fontRef, int fontSize, boolean isBold, boolean isItalic, boolean isUnderline );
-
-        /** Called once XWT is initialized and the application is running. On Mac OS X this calls
-        *       RunApplicationEventLoop(). */
-        protected native void _running();
-        
-        /** dumps a list of Mac OS X font strings. TODO: Will this be sufficient? */
-    //private native String[] listNativeFonts();
-        /** translates a font string into an ATSUFontRef? TODO: Will this be sufficient? */
-    //public static native gnu.gcj.RawData fontStringToStruct(String s);
-
-    public Carbon() { }
-
+    }
+    
+    protected synchronized Proxy _detectProxy() {
+        return natDetectProxy();
+    }
+    
+    private static native final boolean isJaguar();
+    
     public void init() {
     public void init() {
-                natInit();
+        super.init();
+        jaguar = isJaguar();
+        try {
+            openGL = new CarbonOpenGL();
+            openGL.init();
+        } catch(OpenGL.NotSupportedException e) {
+            Log.log(this,"WARNING: OpenGL support not available: " + e);
+            // FIXME: We need to fallback to Quartz2D
+            throw new Error("No OpenGL support");
+        }
+        natInit();
+    }
+    
+    private final class CarbonOpenGL extends OpenGL {
+        public RawData rawPixelFormat;
+        public RawData rawSharedContext;
+        public int maxAglSurfaceTexSize;
+        public int maxSurfaceWidth;
+        public int maxSurfaceHeight;
+        
+        private native boolean initPixelFormat();
+        private native void initSharedContext();
+        
+        public CarbonOpenGL() throws NotSupportedException {
+            if(!jaguar)
+                throw new NotSupportedException("OpenGL requires Mac OS X 10.2 or greater");
+            if(!initPixelFormat())
+                throw new NotSupportedException("Couldn't get an acceptable pixel format");
+            initSharedContext();
+        }
+        
+        public void init() throws NotSupportedException {
+            super.init();
+            maxAglSurfaceTexSize = rectangularTextures ? maxRectTexSize : maxTexSize;
+            if(renderer.startsWith("ATI Radeon 7500")) {
+                maxAglSurfaceTexSize = Math.min(rectangularTextures ? 1600 : 1024,maxAglSurfaceTexSize);
+                Log.log(this,"Working around Radeon 7500 bug: maxAglSurfaceTexSize: " + maxAglSurfaceTexSize);
+            }
+            maxSurfaceWidth = maxSurfaceHeight = maxAglSurfaceTexSize;
+        }
+        protected native void activateSharedContext();
+    }
+    
+    static abstract class CarbonSurface extends Surface {  
+        RawData rawWindowRef;
+        RawData rawEventHandlerUPP;
+        int modifiers;
+         
+        private native void natSetInvisible(boolean i);
+        public void setInvisible(final boolean i) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetInvisible(i); } }); }
+        private native void nat_setMaximized(boolean b);
+        public void _setMaximized(final boolean b) { CarbonMessage.add(new CarbonMessage() { public void perform() { nat_setMaximized(b); } }); }
+        private native void nat_setMinimized(boolean b);
+        public void _setMinimized(final boolean b) { CarbonMessage.add(new CarbonMessage() { public void perform() { nat_setMinimized(b); } }); }
+        private native void natSetIcon(Picture p);
+        public void setIcon(final Picture p) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetIcon(p); } }); }
+        private native void natSetTitleBarText(String s);
+        public void setTitleBarText(final String s) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetTitleBarText(s); } }); }
+        private native void natSetSize(int w, int h);
+        public void setSize(final int w, final int h) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetSize(w,h); } }); }
+        private native void natSetLocation(int x, int y);
+        public void setLocation(final int x, final int y) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetLocation(x,y); } }); }
+        private native void natToFront();
+        public void toFront() { CarbonMessage.add(new CarbonMessage() { public void perform() { natToFront(); } }); }
+        private native void natToBack();
+        public void toBack() { CarbonMessage.add(new CarbonMessage() { public void perform() { natToBack(); } }); }
+        private native void natSetLimits(int minWidth, int minHeight, int maxWidth, int maxHeight);
+        public void setLimits(final int mnw, final int mnh, final int mxw, final int mxh) {
+            if(Carbon.singleton.jaguar)
+                CarbonMessage.add(new CarbonMessage() { public void perform() { natSetLimits(mnw,mnh,mxw,mxh); } });
+        }
+        private native void natSyncCursor(int n);
+        public void syncCursor() {
+            int n;
+            if(cursor.equals("default")) n = 0;
+            else if(cursor.equals("wait")) n = 1;
+            else if(cursor.equals("crosshair")) n = 2;
+            else if(cursor.equals("text")) n = 3;
+            else if(cursor.equals("hand")) n = 4;
+            else if(cursor.equals("move")) n = 5;
+            else if(cursor.equals("east") || cursor.equals("west")) n = 6;
+            else n = 0; 
+            final int n_ = n;
+            CarbonMessage.add(new CarbonMessage() { public void perform() { natSyncCursor(n_); } });
+        }
 
 
-                // nativeFontCache contains font NAMES. Each font exists as an outline font
-                // which can be any size, plus can have real or simulated bold or italic
-        fontList = new String[nativeFontCache.size()*4];
-        Enumeration e = nativeFontCache.keys();
-        for(int i=0; e.hasMoreElements(); i+=4) {
-                        String fontName = (String)e.nextElement() + "0";
-                        
-                        fontList[i] = fontName;
-                        fontList[i+1] = fontName + "i";
-                        fontList[i+2] = fontName + "b";
-                        fontList[i+3] = fontName + "bi";
-                }
+        public void _sizeChange(int w, int h) { SizeChange(w,h); }
+        
+        /* Drawing stuff */
+        public abstract void blit(DoubleBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2);
 
 
-                // Make sure that the default font exists
-                if ( _getATSUStyle( _getDefaultFont() ) == null ) throw new Error( "Default font does not exist" );
+        public final void _dispose() { CarbonMessage.add(new CarbonMessage() { public void perform() { natDispose(); } }); }
+        public native void natDispose();
+        
+        public final native void natInit(boolean framed);
+        
+        public CarbonSurface(Box root, final boolean framed) {
+            super(root);
+            final Semaphore sem = new Semaphore();
+            CarbonMessage.add(new CarbonMessage() { public void perform() { CarbonSurface.this.natInit(framed); sem.release(); } });
+            sem.block();
         }
         }
+        
+        public void reshape(int w, int h) { }
+    }
+    
+    static class GLCarbonDoubleBuffer extends OpenGL.GLDoubleBuffer {
+        RawData rawCTX;
+        RawData rawWindowRef;
+        int textureName;
+        boolean rectTexture;
+        CarbonOpenGL gl;
+        
         private native void natInit();
         private native void natInit();
-
-        /** so we can put ATSUStyles and ATSFontRefs into Hashtables */
-    private static class WrappedRawData {
-        public RawData wrapee = null;
-        public WrappedRawData(RawData r) { wrapee = r; }
+        private static native void natCleanup(RawData rawWindowRef, RawData rawCTX);
+        
+        
+        private static final int fixupDimension(CarbonOpenGL gl, int n) {
+            if(!gl.rectangularTextures) n = OpenGL.roundToPowerOf2(n);
+            return Math.min(n,gl.maxAglSurfaceTexSize);
+        }
+        public GLCarbonDoubleBuffer(int w, int h, final CarbonOpenGL gl) {
+            super(fixupDimension(gl,w),fixupDimension(gl,h));
+            this.gl = gl;
+            rectTexture = gl.hasRectangularTextures();
+            final Semaphore sem = new Semaphore();
+            CarbonMessage.add(new CarbonMessage() { public void perform() { GLCarbonDoubleBuffer.this.natInit(); sem.release(); } });
+            sem.block();
+        }
+        public native void activateContext();
+        protected void finalize() {
+            CarbonMessage.add(new CarbonMessage() { public void perform() { natCleanup(rawWindowRef,rawCTX); } });
+            gl.deleteTexture(textureName);
+        }
+    }
+    
+    static class GLCarbonSurface extends CarbonSurface {
+        RawData rawCTX;
+        CarbonOpenGL gl;
+        boolean sizeChange;
+        
+        private final native void natInit();
+        
+        public GLCarbonSurface(Box root, boolean framed, CarbonOpenGL gl) {
+            super(root,framed);
+            this.gl = gl;
+            natInit();
+        }
+        
+        public void setLimits(int mnw,int mnh, int mxw, int mxh) {
+            mxw = Math.min(mxw,gl.maxSurfaceWidth);
+            mxh = Math.min(mxh,gl.maxSurfaceHeight);
+            super.setLimits(mnw,mnh,mxw,mxh);
+        }
+        public void _sizeChange(int w, int h) {
+            sizeChange = true;
+            super._sizeChange(w,h);
+        }
+        
+        public void setSize(int w, int h) {
+            sizeChange = true;
+            w = Math.min(w,gl.maxSurfaceWidth);
+            h = Math.min(h,gl.maxSurfaceWidth);
+            super.setSize(w,h);
+        }
+        
+        private native void natBlit(GLCarbonDoubleBuffer db, int sx, int sy, int dx, int dy, int dx2, int dy2);
+        public synchronized void blit(DoubleBuffer db, int sx, int sy, int dx, int dy, int dx2, int dy2) {
+            natBlit((GLCarbonDoubleBuffer)db,sx,sy,dx,dy,dx2,dy2);
+        }
+        
+        private native void natReshape(int w, int h);
+        public synchronized void reshape(int w, int h) { natReshape(w,h); }
+        
+        public native void natDispose();
     }
 
     }
 
-    // CarbonSurface /////////////////////////////////////////////////////
-
-    /** Implements a Surface as an Carbon Window */
-    public static class CarbonSurface extends Surface {
-
-                /** The WindowRef that implements this Surface. */
-                gnu.gcj.RawData window = null;
-                /** The CGContextRef. TODO: How do we get this??? */
-        gnu.gcj.RawData gc = null;
-        
-        public native void setInvisible(boolean i);
-        public native void _setMaximized(boolean m);
-        public native void setIcon(Picture p);
-        public native void _setMinimized(boolean b);
-        public native void setTitleBarText(String s);
-        public native void setSize(int w, int h);
-        public native void setLocation(int x, int y);
-        public native void natInit(boolean framed);
-        public native void toFront();
-        public native void toBack();
-        public native void syncCursor();
-        public native void _dispose();
-        //public native void setLimits(int minw, int minh, int maxw, int maxh);
+    /*private class QZCarbonDoubleBuffer extends DoubleBuffer {
+        
+        public QZCarbonDoubleBuffer(int width, int height) {
+        }
+    }
+    
+    private class QZCarbonSurface extends CarbonSurface {
+        public QZCarbonSurface(Box root, boolean framed) {
+            super(b,root);
+        }
         public native void blit(DoubleBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2);
         public native void blit(DoubleBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2);
-
-        public CarbonSurface(Box root, boolean framed) { super(root); natInit( framed ); }
-
     }
     }
-
-
-    // Our Subclass of Picture ///////////////////////////////////////////////
-
-    /** Implements a Picture */
-    public static class CarbonPicture extends Picture {
+    
+    private class QZCarbonPicture extends Picture {
         int width;
         int height;
         int width;
         int height;
-        int[] data = null;
-
-                /** A CGImageRef of the picture. */
-                RawData image = null;
-                
-        public int getWidth() { return width; }
-        public int getHeight() { return height; }
-
-                public native void natInit();
-                public native void finalize();
+        
+        public final int getWidth() { return width; }
+        public final int getHeight() { return height; }
                 
                 
-        public CarbonPicture(int[] data, int w, int h) {
-            this.data = data;
+        public QZCarbonPicture(int w, int h) {
             this.width = w;
             this.height = h;
             this.width = w;
             this.height = h;
-                        natInit();
         }
         }
-
+    }*/
+    
+    protected DoubleBuffer _createDoubleBuffer(int w, int h, Surface owner) {
+        if(openGL != null)
+            return new GLCarbonDoubleBuffer(w,h,openGL);
+        else
+            return /*new QZCarbonDoubleBuffer(w,h)*/ null;
     }
     }
-
-    /** A Carbon DoubleBuffer */
-    public static class CarbonDoubleBuffer extends DoubleBuffer {
-        int width;
-        int height;
-
-                /** A pointer to the raw bitmap data. */
-                RawData bitmapData;
-                /** A CGBitmapContextRef. */
-                RawData gc;
-                /** A CGImageRef which represents the CGBitmapContext. */
-                RawData image;
-                
-        public int getWidth() { return width; }
-        public int getHeight() { return height; }
-
-        public CarbonDoubleBuffer(int w, int h) {
-                        this.width = w;
-                        this.height = h;
-                        natInit();
-                }
-
-        public native void setClip(int x, int y, int x2, int y2);
-        public native void drawPicture(Picture source, int x, int y);
-        public native void drawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2);
-        public native void fillRect(int x, int y, int x2, int y2, int color);
-        public native void drawString(String font, String text, int x, int y, int color);
-                public native void natInit();
-        public native void finalize();
+    protected Surface _createSurface(Box b, boolean framed) {
+        if(openGL != null)
+            return new GLCarbonSurface(b,framed, openGL);
+        else
+            return /*new QZCarbonSufrace(b,framed)*/ null;
+    }
+    protected Picture _createPicture(int[] data, int w, int h) {
+        if(openGL != null)
+            return openGL.createPicture(data,w,h);
+        else
+            return /*new QZCarbonPicture(data,w,h);*/ null;
+    }
+    
+    /* A message that is sent through the carbon event queue */
+    private static abstract class CarbonMessage {
+        public abstract void perform();
+        
+        static { natInit(); }
+        public static native void natInit();
+        public static native void add(CarbonMessage m);
     }
     }
-
 }
 }
index c1333e4..fef47a5 100644 (file)
@@ -108,3 +108,8 @@ void org::xwt::plat::GCJ$JPEG::nativeDecompress() {
     jpeg_destroy_decompress(&cinfo);
 }
 
     jpeg_destroy_decompress(&cinfo);
 }
 
+// C++ new/delete operators (JvMalloc never fails)
+void* operator new(size_t size) { return JvMalloc(size); }
+void* operator new[](size_t size) { return JvMalloc(size);}
+void operator delete(void *p) { JvFree(p); }
+void operator delete[](void *p) { JvFree(p); }
index 6f545c0..98f3d9b 100644 (file)
@@ -49,6 +49,33 @@ public abstract class GCJ extends Platform {
         private JPEG(InputStream is) { this.is = is; nativeDecompress(); buffer = null; }
         private native void nativeDecompress();
     }
         private JPEG(InputStream is) { this.is = is; nativeDecompress(); buffer = null; }
         private native void nativeDecompress();
     }
-
+    
+    // FIXME: This could be optimized (a lot) by using a custom hashtable
+    public final static class Retainer {
+        private static Hash table = new Hash();
+        private final static class Key {
+            private Object o;
+            public Key(Object o) { this.o = o; }
+            public int hashCode() { return o == null ? 0 : o.hashCode(); }
+            public boolean equals(Object o2) { return (o2 instanceof Key) && ((Key)o2).o == o; }
+        }
+        private final static class Entry {
+            private int refCount;
+            public Entry() { inc(); }
+            public void inc() { refCount++; }
+            public boolean dec() { return --refCount == 0; }
+        }
+        public static synchronized void retain(Object o) {
+            Key k = new Key(o);
+            Entry r = (Entry) table.get(k);
+            if(r == null) table.put(k,new Entry());
+            else r.inc();
+        }
+        public static synchronized void release(Object o) {
+            Key k = new Key(o);
+            Entry e = (Entry) table.get(k);
+            if(e == null) throw new Error("Retainer::Release on unknown object");
+            if(e.dec()) { table.remove(k); }
+        }
+    }
 }
 }
-
diff --git a/src/org/xwt/plat/OpenGL.cc b/src/org/xwt/plat/OpenGL.cc
new file mode 100644 (file)
index 0000000..f23c179
--- /dev/null
@@ -0,0 +1,269 @@
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [LGPL]
+// Author: Brian Alliet
+
+// IMPROVMENT: use alpha testing? might be faster
+
+#include <org/xwt/plat/OpenGL.h>
+#include <org/xwt/plat/OpenGL$GLDoubleBuffer.h>
+#include <org/xwt/plat/OpenGL$GLPicture.h>
+#include <org/xwt/plat/OpenGL$RectGLPicture.h>
+#include <org/xwt/plat/OpenGL$SquareGLPicture.h>
+#include <org/xwt/plat/OpenGL$MosaicGLPicture.h>
+
+#include <java/lang/Error.h>
+
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#include <OpenGL/glext.h>
+#else
+#warning I am not sure if these is correct
+#include <gl/gl.h>
+#include <gl/glu.h>
+#include <gl/glext.h>
+#endif
+
+#include <stdio.h>
+
+namespace org { namespace xwt { namespace plat {
+
+#define checkGLError() checkGLError2(__FILE__,__LINE__)
+static void checkGLError2(const char *file,int line) {
+    GLenum err = glGetError();
+    if(err == GL_NO_ERROR) return;
+
+    fprintf(stderr,"%s:%d: GL Error: %s",file,line,(char *) gluErrorString(err));
+    exit(EXIT_FAILURE);
+}
+
+void OpenGL::natInit() {
+    GLint i;
+    const GLubyte *s;
+    activateSharedContext();
+    s = glGetString(GL_EXTENSIONS);
+    rectangularTextures = (jboolean) gluCheckExtension((GLubyte*)"GL_EXT_texture_rectangle",s);
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE,&i);
+    maxTexSize = (jint) i;
+    if(rectangularTextures) {
+        glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT,&i);
+        maxRectTexSize = (jint) i;
+    }
+    s = glGetString(GL_VENDOR);
+    vendor = JvNewStringLatin1(s==0 ? "" : (char*)s);
+    s = glGetString(GL_RENDERER);
+    renderer = JvNewStringLatin1(s==0 ? "" : (char*)s);
+    s = glGetString(GL_VERSION);
+    version = JvNewStringLatin1(s==0 ? "" : (char*)s);
+}
+
+void OpenGL$GLDoubleBuffer::drawableInit(jint width, jint height) {
+    glClearColor (0.3f, 0.7f, 1.0f, 1.0f);
+    glClearDepth( 0.0f );
+    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+    glShadeModel(GL_SMOOTH);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    glViewport(0,0,width,height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity(); 
+    glOrtho(0,width,height,0,-1,1);
+    // CHECKME: This causes textures to be blurry, but something like this
+    // (but not this) might be required to draw straight lines   
+    //glMatrixMode(GL_MODELVIEW);
+    //glLoadIdentity(); 
+    //glTranslatef(0.375, 0.375, 0.0);    
+    
+    checkGLError();
+}
+
+void OpenGL$GLDoubleBuffer::setColor(jint argb) {
+    float alpha = ((argb >> 24) & 0xff) / 255.0;
+    float red   = ((argb >> 16) & 0xff) / 255.0;
+    float green = ((argb >>  8) & 0xff) / 255.0;
+    float blue  = ((argb >>  0) & 0xff) / 255.0;
+    glColor4f(red,green,blue,alpha);
+}
+
+void OpenGL$GLDoubleBuffer::fillTrapezoid(jint x1, jint x2, jint y1, jint x3, jint x4, jint y2, jint color) {
+    activateContext();
+    setColor(color);
+    glBegin(GL_QUADS); 
+        glVertex3f(x1,y1,0.0f );   
+        glVertex3f(x3,y2,0.0f );  
+        glVertex3f(x4,y2,0.0f ); 
+        glVertex3f(x2,y1,0.0f ); 
+    glEnd();
+}
+
+void OpenGL$GLDoubleBuffer::fillRect(jint x1, jint y1, jint x2, jint y2,jint color) {
+    activateContext();
+    setColor(color);
+    glBegin(GL_QUADS); 
+        glVertex3f(x1,y2,0.0f );
+        glVertex3f(x2,y2,0.0f );
+        glVertex3f(x2,y1,0.0f );
+        glVertex3f(x1,y1,0.0f );
+    glEnd();
+}
+
+void OpenGL$GLDoubleBuffer::setClip(jint x1, jint y1, jint x2, jint y2) {
+    //fprintf(stderr,"setClip: %d %d %d %d\n",x1,y1,x2,y2);
+    if(x1==0 && y1==0 && x2==width && y2==height) {
+        if(glScissorEnabled) {
+            activateContext();
+            glDisable(GL_SCISSOR_TEST);
+            glScissorEnabled = false;
+        }
+        return;
+    }
+    activateContext();
+    if(!glScissorEnabled) {
+        glEnable(GL_SCISSOR_TEST);
+        glScissorEnabled = true;
+    }
+    if((x1 >= x2) || (y1 >= y2))
+        glScissor(0,0,0,0);
+    else
+        glScissor(x1,height-y2,x2-x1,y2-y1);
+    checkGLError();
+}
+
+void OpenGL$GLDoubleBuffer::resetClip() {
+    activateContext();
+    if(glScissorEnabled) {
+        glDisable(GL_SCISSOR_TEST);
+        glScissorEnabled = false;
+    }    
+}
+
+void OpenGL$RectGLPicture::natInit(JArray<jint> *data_) {
+    unsigned char *buf;
+    int i,j;
+    int size = width*height;
+    jint *data = elements(data_);
+    buf = new unsigned char[size*4];
+    GLuint tex;
+
+    for(i=0,j=0;i<size;i++,j+=4) {
+        jint pixel = data[i];
+        buf[j+0] = (pixel >> 16) & 0xff;
+        buf[j+1] = (pixel >>  8) & 0xff;
+        buf[j+2] = (pixel >>  0) & 0xff;
+        buf[j+3] = (pixel >> 24) & 0xff;
+    }
+    
+    gl->activateSharedContext();
+    glEnable(GL_TEXTURE_RECTANGLE_EXT);
+    glGenTextures(1,&tex);
+    glBindTexture(GL_TEXTURE_RECTANGLE_EXT,tex);
+    glPixelStorei(GL_PACK_ALIGNMENT,1);
+    glTexImage2D(GL_TEXTURE_RECTANGLE_EXT,0,4,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,buf);
+    delete buf;
+
+    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glDisable(GL_TEXTURE_RECTANGLE_EXT);
+    checkGLError();
+  
+    textureName = (jint)tex;
+}
+
+void OpenGL$RectGLPicture::draw(jint dx1, jint dy1, jint dx2, jint dy2,jint sx1, jint sy1, jint sx2, jint sy2) { 
+    glColor4f(1.0f,1.0f,1.0f,1.0f);
+    glEnable(GL_TEXTURE_RECTANGLE_EXT);
+    glBindTexture(GL_TEXTURE_RECTANGLE_EXT, textureName);    
+    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();
+    glDisable(GL_TEXTURE_RECTANGLE_EXT);
+    checkGLError();
+
+}
+
+void OpenGL::natDeleteTexture(jint tex_) {
+    activateSharedContext();
+    GLuint tex = (GLuint) tex_;
+    glDeleteTextures(1,&tex);
+}
+
+void OpenGL$SquareGLPicture::natInit(JArray<jint> *data_) {
+    unsigned char *buf;
+    int row,col,p;
+    jint *data = elements(data_);
+    buf = new unsigned char[texWidth*texHeight*4];
+    GLuint tex;
+
+    p=0;
+    for(row=0;row<height;row++) {
+        for(col=0;col<width;col++) {
+            jint pixel = data[row*width+col];
+            buf[p+0] = (pixel >> 16) & 0xff;
+            buf[p+1] = (pixel >>  8) & 0xff;
+            buf[p+2] = (pixel >>  0) & 0xff;
+            buf[p+3] = (pixel >> 24) & 0xff;
+            p+=4;
+        }
+        for(;col < texWidth;col++,p+=4)
+            buf[p+0] = buf[p+1] = buf[p+2] = buf[p+3] = 0;
+    }
+    for(;row < texHeight;row++) 
+        for(col=0;col<texWidth;col++,p+=4)
+            buf[p+0] = buf[p+1] = buf[p+2] = buf[p+3] = 0;
+    
+    gl->activateSharedContext();
+    glEnable(GL_TEXTURE_2D);
+    glGenTextures(1,&tex);
+    glBindTexture(GL_TEXTURE_2D,tex);
+    glPixelStorei(GL_PACK_ALIGNMENT,1);
+    glTexImage2D(GL_TEXTURE_2D,0,4,texWidth,texHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,buf);
+    checkGLError();    
+    delete buf;
+
+    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glDisable(GL_TEXTURE_2D);
+    checkGLError();
+  
+    textureName = (jint)tex;
+}
+
+void OpenGL$SquareGLPicture::draw(jint dx1, jint dy1, jint dx2, jint dy2,jint sx1, jint sy1, jint sx2, jint sy2) {
+    float tx1,ty1,tx2,ty2; // normalized texture coords
+    tx1 = (float) sx1 / (float) texWidth;
+    ty1 = (float) sy1 / (float) texHeight;
+    tx2 = (float) sx2 / (float) texWidth;
+    ty2 = (float) sy2 / (float) texHeight;
+
+    glColor4f(1.0f,1.0f,1.0f,1.0f);
+    glEnable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, 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();
+}
+
+} } } // end org::xwt::plat
diff --git a/src/org/xwt/plat/OpenGL.java b/src/org/xwt/plat/OpenGL.java
new file mode 100644 (file)
index 0000000..8f25506
--- /dev/null
@@ -0,0 +1,255 @@
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [LGPL]
+// Author: Brian Alliet
+
+package org.xwt.plat;
+import org.xwt.*;
+import org.xwt.util.*;
+
+abstract class OpenGL {
+    static final boolean pretendToBeACrappyVideoCard = false;
+    boolean rectangularTextures;
+    boolean hasRectangularTextures() { return rectangularTextures; }
+    int maxTexSize;
+    int maxRectTexSize;
+    String version;
+    String renderer;
+    String vendor;
+    
+    private native void natInit();
+    
+    private static float parseVersion(String s) {
+        int end = s.indexOf(' ');
+        if(end < 0) end = s.length();
+        try {
+            return Float.parseFloat(s.substring(0,end));
+        } catch(NumberFormatException e) {
+            return 1.1f; // just a guess
+        }
+    }
+    // This MUST be called after OpenGL is instansiated (and activateSharedContext is functioning)
+    public void init() throws NotSupportedException {
+        natInit();
+        float v = parseVersion(version);
+        // If we disable linear filtering (and therefor GL_CLAMP_TO_EDGE) we could probably get by with less
+        if(v < 1.2) throw new NotSupportedException("OpenGL 1.2 or greater is required. (you have: " + version +" - " + v + ")");
+        if(pretendToBeACrappyVideoCard) {
+            maxTexSize = 512;
+            maxRectTexSize = 0;
+            rectangularTextures = false;
+        }
+        Log.log(this,"Renderer: " + renderer);
+        Log.log(this,"Version: " + version);
+        Log.log(this,"Vendor: " + vendor);
+        Log.log(this,"Rectangular textures: " + (rectangularTextures ? "supported" : "unsupported"));
+        Log.log(this,"Max texture size: " + maxTexSize);
+        Log.log(this,"Max rectangular texture size: " + maxRectTexSize);
+    }
+    
+    protected abstract void activateSharedContext();
+
+    public static class NotSupportedException extends Exception {
+        public NotSupportedException(String s) { super(s); }
+    }
+
+    public static abstract class GLDoubleBuffer extends DoubleBuffer {
+        protected int width;
+        protected int height;
+        public int getWidth() { return width; }
+        public int getHeight() { return height; }
+        
+        private boolean glScissorEnabled = false;
+        
+        public GLDoubleBuffer(int width, int height) {
+            this.width = width;
+            this.height = height;
+        }
+        
+        // This should activate the drawing context and prepare the double buffer for drawing
+        protected abstract void activateContext();
+        
+        protected static native void drawableInit(int w, int h);
+        
+        private static native void setColor(int color);
+        
+        public native void setClip(int x, int y, int x2, int y2);
+        public native void resetClip();
+        public native void fillRect(int x, int y, int x2, int y2, int color);
+        public native void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int color);
+            
+        public void drawString(String font, String text, int x, int y, int color) {
+            //System.out.println("drawString(): " + text);
+        }
+        
+        public void drawPicture(org.xwt.Picture source, int x, int y) {
+            activateContext();
+            GLPicture p = (GLPicture) source;
+            p.draw(x,y);
+        }
+        public void drawPicture(org.xwt.Picture source, int dx1, int dy1, int dx2, int dy2,int sx1, int sy1, int sx2, int sy2) {
+            activateContext();
+            GLPicture p = (GLPicture) source;
+            p.draw(dx1,dy1,dx2,dy2,sx1,sy1,sx2,sy2);
+        }
+    }
+    
+    public final static int roundToPowerOf2(int n) {
+        if(((n-1)&n)==0) return n;
+        for(int x=2;x!=0;x<<=1) if(n < x) return x;
+        return 0;
+    }
+        
+    public Picture createPicture(int[] data, int w, int h) {
+        if(w*h != data.length) throw new Error("w*h != data.length");
+        if(rectangularTextures && w <= maxRectTexSize && h <= maxRectTexSize) new RectGLPicture(data,w,h,this);
+        if(w <= maxTexSize && h <= maxTexSize) return new SquareGLPicture(data,w,h,this);
+        return new MosaicGLPicture(data,w,h,this);
+    }
+    
+    private native void natDeleteTexture(int tex);
+    public void deleteTexture(final int tex) {
+        // CHECKME: Is this safe to do from finalize()?
+        // natDeleteTexture MUST be run from the message queue thread
+        MessageQueue.add(new Message() { public void perform() {
+            natDeleteTexture(tex);
+        }});
+    }
+    
+    private static abstract class GLPicture extends Picture {
+        protected int width;
+        protected int height;
+        
+        public final int getWidth() { return width; }
+        public final int getHeight() { return height; }
+                
+        public GLPicture(int w, int h) {
+            this.width = w;
+            this.height = h;
+        }
+        
+        public void draw(int x, int y) { draw(x,y,x+width,y+height,0,0,width,height); }
+        public abstract void draw(int dx1, int dy1, int dx2, int dy2,int sx1, int sy1, int sx2, int sy2);
+        protected abstract void finalize();
+    }
+    
+    private static class RectGLPicture extends GLPicture {
+        private OpenGL gl;
+        public int textureName;
+                
+        public native void natInit(int[] data);
+        
+        public RectGLPicture(int[] data,int w, int h, OpenGL gl) {
+            super(w,h);
+            this.gl = gl;
+            natInit(data);
+        }
+    
+        public native void draw(int dx1, int dy1, int dx2, int dy2,int sx1, int sy1, int sx2, int sy2);  
+        protected void finalize() { gl.deleteTexture(textureName); }
+    }
+    
+    private static class SquareGLPicture extends GLPicture {
+        private int texHeight;
+        private int texWidth;
+        private OpenGL gl;
+        public int textureName;
+                
+        public native void natInit(int[] data);
+                
+        public SquareGLPicture(int[] data,int w, int h, OpenGL gl) {
+            super(w,h);
+            this.gl = gl;
+            if(w > 0x7fffffff || h > 0x7fffffff) throw new Error("insane texture size: " + w + "x" + h);
+            texHeight = roundToPowerOf2(h);
+            texWidth = roundToPowerOf2(w);
+            natInit(data);
+        }
+        
+        public native void draw(int dx1, int dy1, int dx2, int dy2,int sx1, int sy1, int sx2, int sy2); 
+        protected void finalize() { gl.deleteTexture(textureName); }
+    }
+    
+    private static class MosaicGLPicture extends GLPicture {
+        private static final int overlap = 8;
+        
+        int psize;
+        GLPicture[][] pics;
+        
+        private static float wastedSpace(int w,int h,int size) {
+            int w2 = size * ((w+size-1)/size);
+            int h2 = size * ((h+size-1)/size);
+            return 1.0f-(float)(w*h)/(float)(w2*h2);
+        }
+        
+        private static int[] subData(int[] data, int x, int y, int w, int h, int rowSize) {
+            int[] sub = new int[w*h];
+            int row = y;
+            try {
+            for(int i=0;i<h;i++,row++)
+                for(int j=0;j<w;j++)
+                    sub[i*w+j] = data[row*rowSize+j+x];
+            } catch(ArrayIndexOutOfBoundsException e) {
+                Log.log(MosaicGLPicture.class,"subData(data("+data.length+"),"+x+","+y+","+w+","+h+","+rowSize);
+                throw e;
+            }
+            return sub;
+        }
+        
+        public MosaicGLPicture(int[] data,int w, int h, OpenGL gl) {
+            super(w,h);
+            psize = gl.maxTexSize;
+            while(wastedSpace(w,h,psize) > 0.40) psize/=2;
+            Log.log(this,"Using psize: " + psize + " for " + w + "x" + h + " image (wasted space: " + wastedSpace(w,h,psize));
+            
+            int rows = (h+psize-1)/psize;
+            int cols = (w+psize-1)/psize;
+            int tmp,tmp2;
+            
+            pics = new GLPicture[rows][cols];
+            for(int i=0;i<rows-1;i++)
+                for(int j=0;j<cols-1;j++)
+                    pics[i][j] = new SquareGLPicture(subData(data,j*psize,i*psize,psize,psize,w),psize,psize,gl);
+            tmp = (rows-1)*psize;
+            for(int i=0;i<cols-1;i++)
+                pics[rows-1][i] = new SquareGLPicture(subData(data,i*psize,tmp,psize,h-tmp,w),psize,h-tmp,gl);
+            tmp2 = (cols-1)*psize;
+            for(int i=0;i<rows-1;i++)
+                pics[i][cols-1] = new SquareGLPicture(subData(data,tmp2,i*psize,w-tmp2,psize,w),w-tmp2,psize,gl);
+            pics[rows-1][cols-1] = new SquareGLPicture(subData(data,tmp2,tmp,w-tmp2,h-tmp,w),w-tmp2,h-tmp,gl);
+        }
+        protected void finalize() {  }
+        
+        private static final int max(int a, int b) { return a > b ? a : b; }
+        private static final int min(int a, int b) { return a < b ? a : b; }
+        
+        public void draw(int dx1, int dy1, int dx2, int dy2,int sx1, int sy1, int sx2, int sy2) {
+            double xscale = (double)(dx2-dx1)/(double)(sx2-sx1);
+            double yscale = (double)(dy2-dy1)/(double)(sy2-sy1);
+            int totalWidth = width;
+            int totalHeight = height;
+            // *{x,y}{1,2} key: d=dest s=src, p=bounds of this picture, i=intersection of s and p, pd = dest of this pic
+            //System.out.println("Starting draw..." + sx1 + "," + sy1 + " " + sx2 + "," + sy2 + " to " + dx1 +"," + dy1 + " " + dx2 + "," + dy2);
+            for(int i=0;i<pics.length;i++) {
+                for(int j=0;j<pics[i].length;j++) {
+                    int px1 = j*psize;
+                    int py1 = i*psize;
+                    int px2 = min(px1+psize,totalWidth);
+                    int py2 = min(py1+psize,totalHeight);
+                    int ix1 = max(px1,sx1);
+                    int iy1 = max(py1,sy1);
+                    int ix2 = min(px2,sx2);
+                    int iy2 = min(py2,sy2);
+                    if(ix1 >= ix2 || iy1 >= iy2) continue; // no intersection
+                    
+                    int pdx1 = dx1 + (int) (xscale*(ix1-sx1));
+                    int pdy1 = dy1 + (int) (yscale*(iy1-sy1));
+                    int pdx2 = dx2 - (int) (xscale*(sx2-ix2));
+                    int pdy2 = dy2 - (int) (yscale*(sy2-iy2));
+                    
+                    //System.out.println("" + i + "," + j + " is good... drawing from " + (ix1-px1) + "," + (iy1-py1) + " " + (ix2-px1) + "," + (iy2-py1) + " to " + pdx1 + "," + pdy1 + " to " + pdx2 + "," + pdy2);
+                    
+                    pics[i][j].draw(pdx1,pdy1,pdx2,pdy2,ix1-px1,iy1-py1,ix2-px1,iy2-py1);
+                }
+            }
+        }
+    }
+}