// Copyright 2004 Adam Megacz, see the COPYING file for licensing [LGPL] // Authors: Brian Alliet and Evan Jones package org.ibex.plat; import gnu.gcj.RawData; import org.ibex.util.*; import org.ibex.js.*; import org.ibex.graphics.*; import org.ibex.core.*; import org.ibex.net.*; public class Darwin extends POSIX { public static void main(String[] s) throws Exception { org.ibex.core.Main.main(s); } private static final Class openGLClass = OpenGL.class; static Darwin singleton; private CarbonOpenGL openGL; boolean jaguar; // true if we are on OS X >= 10.2 // General Methods protected String _getAltKeyName() { return "Option"; } protected boolean _needsAutoClick() { return false; } protected boolean _needsAutoDoubleClick() { return false; } protected String getDescriptiveName() { return "GCJ Darwin 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 HTTP.Proxy natDetectProxy(); private native void natInit(); 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; } 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; } static void abort(String err) { throw new Error(err); } public Darwin() { synchronized(Darwin.class) { if(singleton != null) abort("Tried to instansiate Darwin more than once"); singleton = this; } } protected synchronized HTTP.Proxy _detectProxy() { return natDetectProxy(); } private static native final boolean isJaguar(); public void postInit() { jaguar = isJaguar(); try { openGL = new CarbonOpenGL(); openGL.init(); } catch(OpenGL.NotSupportedException e) { Log.info(this,"WARNING: OpenGL support not available: " + e); // FEATURE: fall back to quartz 2d throw new Error("No OpenGL support"); } natInit(); } protected Platform.Scheduler _getScheduler() { return new DarwinScheduler(); } protected native void runApplicationEventLoop(); private class DarwinScheduler extends Scheduler { public void run() { new Thread() { public void run() { defaultRun(); } }.start(); runApplicationEventLoop(); } } 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.info(this,"Working around Radeon 7500 bug: maxAglSurfaceTexSize: " + maxAglSurfaceTexSize); } maxSurfaceWidth = maxSurfaceHeight = maxAglSurfaceTexSize; } protected native void activateSharedContext(); } static abstract class CarbonSurface extends Surface { RawData rawWindowRef; int modifiers; int winWidth; int winHeight; boolean pendingResize; 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(); public void setLocation() { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetLocation(); } }); } 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(Darwin.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_); } }); } /* Drawing stuff */ public abstract void blit(PixelBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2); 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 needsReshape() { } protected static native void blitLock(); protected static native void blitUnlock(); protected static native void blitWait(); } static class GLCarbonPixelBuffer extends OpenGL.GLPixelBuffer { RawData rawCTX; RawData rawWindowRef; int textureName; boolean rectTexture; CarbonOpenGL gl; private native void natInit(); 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 GLCarbonPixelBuffer(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() { GLCarbonPixelBuffer.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 needsReshape; private final native void natInit(); private final native void flush(); private final native void clear(); private PixelBuffer pb; public PixelBuffer getPixelBuffer() { return pb; } static class GLCarbonSurfacePixelBuffer extends GLCarbonPixelBuffer { RawData rawCTX; public native void activateContext(); public GLCarbonSurfacePixelBuffer(RawData rawCTX, CarbonOpenGL gl) { super(500, 500, gl); this.rawCTX = rawCTX; } } public GLCarbonSurface(Box root, boolean framed, CarbonOpenGL gl) { super(root,framed); this.gl = gl; natInit(); pb = new GLCarbonSurfacePixelBuffer(rawCTX, gl); } 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 _setSize(int w, int h) { w = Math.min(w,gl.maxSurfaceWidth); h = Math.min(h,gl.maxSurfaceWidth); super._setSize(w,h); } private native void natBlit(GLCarbonPixelBuffer db, int sx, int sy, int dx, int dy, int dx2, int dy2); public void blit(PixelBuffer db, int sx, int sy, int dx, int dy, int dx2, int dy2) { natBlit((GLCarbonPixelBuffer)db,sx,sy,dx,dy,dx2,dy2); } // The blit_lock ensures the window size does not change through the entire blit operation. public void render() { /* blitLock(); while(pendingResize) blitWait(); */ if(needsReshape) { needsReshape = false; reshape(winWidth,winHeight); clear(); dirty(0,0,winWidth,winHeight); } super.render(); flush(); /* blitUnlock(); */ } private native void reshape(int w, int h); // blit_lock is assumed to be held public void needsReshape() { needsReshape = true; } public native void natDispose(); } /*private class QZCarbonPixelBuffer extends PixelBuffer { public QZCarbonPixelBuffer(int width, int height) { } } private class QZCarbonSurface extends CarbonSurface { public QZCarbonSurface(Box root, boolean framed) { super(b,root); } public native void blit(PixelBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2); } private class QZCarbonPicture extends Picture { int width; int height; public final int getWidth() { return width; } public final int getHeight() { return height; } public QZCarbonPicture(int w, int h) { this.width = w; this.height = h; } }*/ protected PixelBuffer _createPixelBuffer(int w, int h, Surface owner) { if(openGL != null) return new GLCarbonPixelBuffer(w,h,openGL); else return /*new QZCarbonPixelBuffer(w,h)*/ null; } 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(JS r) { if(openGL != null) return openGL._createPicture(r, true); else return /*new QZCarbonPicture(data,w,h);*/ null; } protected org.ibex.graphics.Font.Glyph _createGlyph(org.ibex.graphics.Font f, char c) { if(openGL != null) return openGL._createGlyph(f, c); else return super.createGlyph(f, c); } /* 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); } }