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  }
322