2003/09/07 03:04:31
[org.ibex.core.git] / src / org / xwt / plat / Carbon.java
1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [LGPL]
2 // Authors: Brian Alliet and Evan Jones
3
4 package org.xwt.plat;
5
6 import gnu.gcj.RawData;
7 import org.xwt.util.*;
8 import org.xwt.*;
9 import java.util.*;
10
11 public class Carbon extends POSIX {
12     static Carbon singleton;
13     private CarbonOpenGL openGL;
14     boolean jaguar; // true if we are on OS X >= 10.2
15     
16     // TEMPORARY HACKS (remove these when we ditch platform fonts)
17     protected int _stringWidth(String font, String text) { return (int)Math.round(6.5 * text.length()); }
18     protected int _getMaxAscent(String font) { return 10; }
19     protected int _getMaxDescent(String font) { return 2; }
20     
21     // General Methods
22     protected String _getAltKeyName() { return "Option"; }
23     protected boolean _needsAutoClick() { return false; }
24     protected boolean _needsAutoDoubleClick() { return false; }
25     protected String getDescriptiveName() { return "GCJ Carbon Binary"; }
26     protected boolean _isCaseSensitive() { return false; /* Well, not always, could be UFS */ }
27     
28     
29     // Native Methods
30     protected int    _getScreenWidth() { return cgScreenWidth(); }
31     protected int    _getScreenHeight() { return cgScreenHeight(); }
32     private native static int cgScreenWidth();
33     private native static int cgScreenHeight();
34     protected native void   _newBrowserWindow(String url);
35     protected native Proxy   natDetectProxy();
36     private   native void    natInit();
37     protected native void   _exit();
38
39     private native String natGetClipBoard();
40     private native void natSetClipBoard(String text);
41     protected void _setClipBoard(final String text) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetClipBoard(text); } }); }
42     protected String _getClipBoard() {
43         final Semaphore sem = new Semaphore();
44         final String[] result = new String[1]; // Kind of like a pointer
45         CarbonMessage.add(new CarbonMessage() { public void perform() { result[0] = natGetClipBoard(); sem.release(); } });
46         sem.block();
47         return result[0];
48     }
49     
50     private static class FileDialogHelper {
51         public FileDialogHelper(boolean save) { this.save = save; }
52         public boolean save;
53         public Semaphore sem = new Semaphore();
54         public String fileName;
55         public String saveName;
56         public RawData rawUPP;
57     }
58     private native void natFileDialog(FileDialogHelper helper, String suggestedFileName, boolean write);
59     protected String _fileDialog(final String fn, final boolean w) {
60         final FileDialogHelper helper = new FileDialogHelper(w);
61         CarbonMessage.add(new CarbonMessage() { public void perform() { natFileDialog(helper,fn,w); } });
62         helper.sem.block();
63         if(w)
64             return helper.fileName + "/" + helper.saveName;
65         else
66             return helper.fileName;
67     }
68
69     
70     // Called by main thread after initialization, this is the event handler
71     protected native void _running();
72     
73     static void abort(String err) {
74         throw new Error(err);
75     }
76     
77     public Carbon() {
78         synchronized(Carbon.class) {
79             if(singleton != null) abort("Tried to instansiate Carbon more than once");
80             singleton = this;
81         }
82     }
83     
84     protected synchronized Proxy _detectProxy() {
85         return natDetectProxy();
86     }
87     
88     private static native final boolean isJaguar();
89     
90     public void init() {
91         super.init();
92         jaguar = isJaguar();
93         try {
94             openGL = new CarbonOpenGL();
95             openGL.init();
96         } catch(OpenGL.NotSupportedException e) {
97             Log.log(this,"WARNING: OpenGL support not available: " + e);
98             // FIXME: We need to fallback to Quartz2D
99             throw new Error("No OpenGL support");
100         }
101         natInit();
102     }
103     
104     private final class CarbonOpenGL extends OpenGL {
105         public RawData rawPixelFormat;
106         public RawData rawSharedContext;
107         public int maxAglSurfaceTexSize;
108         public int maxSurfaceWidth;
109         public int maxSurfaceHeight;
110         
111         private native boolean initPixelFormat();
112         private native void initSharedContext();
113         
114         public CarbonOpenGL() throws NotSupportedException {
115             if(!jaguar)
116                 throw new NotSupportedException("OpenGL requires Mac OS X 10.2 or greater");
117             if(!initPixelFormat())
118                 throw new NotSupportedException("Couldn't get an acceptable pixel format");
119             initSharedContext();
120         }
121         
122         public void init() throws NotSupportedException {
123             super.init();
124             maxAglSurfaceTexSize = rectangularTextures ? maxRectTexSize : maxTexSize;
125             if(renderer.startsWith("ATI Radeon 7500")) {
126                 maxAglSurfaceTexSize = Math.min(rectangularTextures ? 1600 : 1024,maxAglSurfaceTexSize);
127                 Log.log(this,"Working around Radeon 7500 bug: maxAglSurfaceTexSize: " + maxAglSurfaceTexSize);
128             }
129             maxSurfaceWidth = maxSurfaceHeight = maxAglSurfaceTexSize;
130         }
131         protected native void activateSharedContext();
132     }
133     
134     static abstract class CarbonSurface extends Surface {  
135         RawData rawWindowRef;
136         RawData rawEventHandlerUPP;
137         int modifiers;
138          
139         private native void natSetInvisible(boolean i);
140         public void setInvisible(final boolean i) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetInvisible(i); } }); }
141         private native void nat_setMaximized(boolean b);
142         public void _setMaximized(final boolean b) { CarbonMessage.add(new CarbonMessage() { public void perform() { nat_setMaximized(b); } }); }
143         private native void nat_setMinimized(boolean b);
144         public void _setMinimized(final boolean b) { CarbonMessage.add(new CarbonMessage() { public void perform() { nat_setMinimized(b); } }); }
145         private native void natSetIcon(Picture p);
146         public void setIcon(final Picture p) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetIcon(p); } }); }
147         private native void natSetTitleBarText(String s);
148         public void setTitleBarText(final String s) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetTitleBarText(s); } }); }
149         private native void natSetSize(int w, int h);
150         public void setSize(final int w, final int h) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetSize(w,h); } }); }
151         private native void natSetLocation(int x, int y);
152         public void setLocation(final int x, final int y) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetLocation(x,y); } }); }
153         private native void natToFront();
154         public void toFront() { CarbonMessage.add(new CarbonMessage() { public void perform() { natToFront(); } }); }
155         private native void natToBack();
156         public void toBack() { CarbonMessage.add(new CarbonMessage() { public void perform() { natToBack(); } }); }
157         private native void natSetLimits(int minWidth, int minHeight, int maxWidth, int maxHeight);
158         public void setLimits(final int mnw, final int mnh, final int mxw, final int mxh) {
159             if(Carbon.singleton.jaguar)
160                 CarbonMessage.add(new CarbonMessage() { public void perform() { natSetLimits(mnw,mnh,mxw,mxh); } });
161         }
162         private native void natSyncCursor(int n);
163         public void syncCursor() {
164             int n;
165             if(cursor.equals("default")) n = 0;
166             else if(cursor.equals("wait")) n = 1;
167             else if(cursor.equals("crosshair")) n = 2;
168             else if(cursor.equals("text")) n = 3;
169             else if(cursor.equals("hand")) n = 4;
170             else if(cursor.equals("move")) n = 5;
171             else if(cursor.equals("east") || cursor.equals("west")) n = 6;
172             else n = 0; 
173             final int n_ = n;
174             CarbonMessage.add(new CarbonMessage() { public void perform() { natSyncCursor(n_); } });
175         }
176
177         public void _sizeChange(int w, int h) { SizeChange(w,h); }
178         
179         /* Drawing stuff */
180         public abstract void blit(DoubleBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2);
181
182         public final void _dispose() { CarbonMessage.add(new CarbonMessage() { public void perform() { natDispose(); } }); }
183         public native void natDispose();
184         
185         public final native void natInit(boolean framed);
186         
187         public CarbonSurface(Box root, final boolean framed) {
188             super(root);
189             final Semaphore sem = new Semaphore();
190             CarbonMessage.add(new CarbonMessage() { public void perform() { CarbonSurface.this.natInit(framed); sem.release(); } });
191             sem.block();
192         }
193         
194         public void reshape(int w, int h) { }
195     }
196     
197     static class GLCarbonDoubleBuffer extends OpenGL.GLDoubleBuffer {
198         RawData rawCTX;
199         RawData rawWindowRef;
200         int textureName;
201         boolean rectTexture;
202         CarbonOpenGL gl;
203         
204         private native void natInit();
205         private static native void natCleanup(RawData rawWindowRef, RawData rawCTX);
206         
207         
208         private static final int fixupDimension(CarbonOpenGL gl, int n) {
209             if(!gl.rectangularTextures) n = OpenGL.roundToPowerOf2(n);
210             return Math.min(n,gl.maxAglSurfaceTexSize);
211         }
212         public GLCarbonDoubleBuffer(int w, int h, final CarbonOpenGL gl) {
213             super(fixupDimension(gl,w),fixupDimension(gl,h));
214             this.gl = gl;
215             rectTexture = gl.hasRectangularTextures();
216             final Semaphore sem = new Semaphore();
217             CarbonMessage.add(new CarbonMessage() { public void perform() { GLCarbonDoubleBuffer.this.natInit(); sem.release(); } });
218             sem.block();
219         }
220         public native void activateContext();
221         protected void finalize() {
222             CarbonMessage.add(new CarbonMessage() { public void perform() { natCleanup(rawWindowRef,rawCTX); } });
223             gl.deleteTexture(textureName);
224         }
225     }
226     
227     static class GLCarbonSurface extends CarbonSurface {
228         RawData rawCTX;
229         CarbonOpenGL gl;
230         boolean sizeChange;
231         
232         private final native void natInit();
233         
234         public GLCarbonSurface(Box root, boolean framed, CarbonOpenGL gl) {
235             super(root,framed);
236             this.gl = gl;
237             natInit();
238         }
239         
240         public void setLimits(int mnw,int mnh, int mxw, int mxh) {
241             mxw = Math.min(mxw,gl.maxSurfaceWidth);
242             mxh = Math.min(mxh,gl.maxSurfaceHeight);
243             super.setLimits(mnw,mnh,mxw,mxh);
244         }
245         public void _sizeChange(int w, int h) {
246             sizeChange = true;
247             super._sizeChange(w,h);
248         }
249         
250         public void setSize(int w, int h) {
251             sizeChange = true;
252             w = Math.min(w,gl.maxSurfaceWidth);
253             h = Math.min(h,gl.maxSurfaceWidth);
254             super.setSize(w,h);
255         }
256         
257         private native void natBlit(GLCarbonDoubleBuffer db, int sx, int sy, int dx, int dy, int dx2, int dy2);
258         public synchronized void blit(DoubleBuffer db, int sx, int sy, int dx, int dy, int dx2, int dy2) {
259             natBlit((GLCarbonDoubleBuffer)db,sx,sy,dx,dy,dx2,dy2);
260         }
261         
262         private native void natReshape(int w, int h);
263         public synchronized void reshape(int w, int h) { natReshape(w,h); }
264         
265         public native void natDispose();
266     }
267
268     /*private class QZCarbonDoubleBuffer extends DoubleBuffer {
269         
270         public QZCarbonDoubleBuffer(int width, int height) {
271         }
272     }
273     
274     private class QZCarbonSurface extends CarbonSurface {
275         public QZCarbonSurface(Box root, boolean framed) {
276             super(b,root);
277         }
278         public native void blit(DoubleBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2);
279     }
280     
281     private class QZCarbonPicture extends Picture {
282         int width;
283         int height;
284         
285         public final int getWidth() { return width; }
286         public final int getHeight() { return height; }
287                 
288         public QZCarbonPicture(int w, int h) {
289             this.width = w;
290             this.height = h;
291         }
292     }*/
293     
294     protected DoubleBuffer _createDoubleBuffer(int w, int h, Surface owner) {
295         if(openGL != null)
296             return new GLCarbonDoubleBuffer(w,h,openGL);
297         else
298             return /*new QZCarbonDoubleBuffer(w,h)*/ null;
299     }
300     protected Surface _createSurface(Box b, boolean framed) {
301         if(openGL != null)
302             return new GLCarbonSurface(b,framed, openGL);
303         else
304             return /*new QZCarbonSufrace(b,framed)*/ null;
305     }
306     protected Picture _createPicture(int[] data, int w, int h) {
307         if(openGL != null)
308             return openGL.createPicture(data,w,h);
309         else
310             return /*new QZCarbonPicture(data,w,h);*/ null;
311     }
312     
313     /* A message that is sent through the carbon event queue */
314     private static abstract class CarbonMessage {
315         public abstract void perform();
316         
317         static { natInit(); }
318         public static native void natInit();
319         public static native void add(CarbonMessage m);
320     }
321 }