1    // Copyright 2004 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.js.*;
9    import org.xwt.*;
10   import java.util.*;
11   
12   public class Darwin extends POSIX {
13       private static final Class openGLClass = OpenGL.class;
14       static Darwin singleton;
15       private CarbonOpenGL openGL;
16       boolean jaguar; // true if we are on OS X >= 10.2
17       
18       // General Methods
19       protected String _getAltKeyName() { return "Option"; }
20       protected boolean _needsAutoClick() { return false; }
21       protected boolean _needsAutoDoubleClick() { return false; }
22       protected String getDescriptiveName() { return "GCJ Darwin Binary"; }
23       protected boolean _isCaseSensitive() { return false; /* Well, not always, could be UFS */ }
24       
25       
26       // Native Methods
27       protected int    _getScreenWidth() { return cgScreenWidth(); }
28       protected int    _getScreenHeight() { return cgScreenHeight(); }
29       private native static int cgScreenWidth();
30       private native static int cgScreenHeight();
31       protected native void   _newBrowserWindow(String url);
32       protected native HTTP.Proxy   natDetectProxy();
33       private   native void    natInit();
34   
35       private native String natGetClipBoard();
36       private native void natSetClipBoard(String text);
37       protected void _setClipBoard(final String text) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetClipBoard(text); } }); }
38       protected String _getClipBoard() {
39           final Semaphore sem = new Semaphore();
40           final String[] result = new String[1]; // Kind of like a pointer
41           CarbonMessage.add(new CarbonMessage() { public void perform() { result[0] = natGetClipBoard(); sem.release(); } });
42           sem.block();
43           return result[0];
44       }
45       
46       private static class FileDialogHelper {
47           public FileDialogHelper(boolean save) { this.save = save; }
48           public boolean save;
49           public Semaphore sem = new Semaphore();
50           public String fileName;
51           public String saveName;
52       }
53       private native void natFileDialog(FileDialogHelper helper, String suggestedFileName, boolean write);
54       protected String _fileDialog(final String fn, final boolean w) {
55           final FileDialogHelper helper = new FileDialogHelper(w);
56           CarbonMessage.add(new CarbonMessage() { public void perform() { natFileDialog(helper,fn,w); } });
57           helper.sem.block();
58           if(w)
59               return helper.fileName + "/" + helper.saveName;
60           else
61               return helper.fileName;
62       }
63   
64       
65       static void abort(String err) {
66           throw new Error(err);
67       }
68       
69       public Darwin() {
70           synchronized(Darwin.class) {
71               if(singleton != null) abort("Tried to instansiate Darwin more than once");
72               singleton = this;
73           }
74       }
75       
76       protected synchronized HTTP.Proxy _detectProxy() {
77           return natDetectProxy();
78       }
79       
80       private static native final boolean isJaguar();
81       
82       public void postInit() {
83           jaguar = isJaguar();
84           try {
85               openGL = new CarbonOpenGL();
86               openGL.init();
87           } catch(OpenGL.NotSupportedException e) {
88               Log.info(this,"WARNING: OpenGL support not available: " + e);
89               // FEATURE: fall back to quartz 2d
90               throw new Error("No OpenGL support");
91           }
92           natInit();
93       }
94       
95       protected Scheduler _getScheduler() { return new DarwinScheduler(); }
96       protected native void runApplicationEventLoop();
97       private class DarwinScheduler extends org.xwt.Scheduler {
98           public void run() {
99               new Thread() { public void run() { defaultRun(); } }.start();
100              runApplicationEventLoop();
101          }
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.info(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.DoubleBufferedSurface {  
135          RawData rawWindowRef;
136          int modifiers;
137          int winWidth;
138          int winHeight;
139          
140          boolean pendingResize;
141           
142          private native void natSetInvisible(boolean i);
143          public void setInvisible(final boolean i) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetInvisible(i); } }); }
144          private native void nat_setMaximized(boolean b);
145          public void _setMaximized(final boolean b) { CarbonMessage.add(new CarbonMessage() { public void perform() { nat_setMaximized(b); } }); }
146          private native void nat_setMinimized(boolean b);
147          public void _setMinimized(final boolean b) { CarbonMessage.add(new CarbonMessage() { public void perform() { nat_setMinimized(b); } }); }
148          private native void natSetIcon(Picture p);
149          public void setIcon(final Picture p) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetIcon(p); } }); }
150          private native void natSetTitleBarText(String s);
151          public void setTitleBarText(final String s) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetTitleBarText(s); } }); }
152          private native void natSetSize(int w, int h);
153          public void _setSize(final int w, final int h) { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetSize(w,h); } }); }
154          private native void natSetLocation();
155          public void setLocation() { CarbonMessage.add(new CarbonMessage() { public void perform() { natSetLocation(); } }); }
156          private native void natToFront();
157          public void toFront() { CarbonMessage.add(new CarbonMessage() { public void perform() { natToFront(); } }); }
158          private native void natToBack();
159          public void toBack() { CarbonMessage.add(new CarbonMessage() { public void perform() { natToBack(); } }); }
160          private native void natSetLimits(int minWidth, int minHeight, int maxWidth, int maxHeight);
161          public void setLimits(final int mnw, final int mnh, final int mxw, final int mxh) {
162              if(Darwin.singleton.jaguar)
163                  CarbonMessage.add(new CarbonMessage() { public void perform() { natSetLimits(mnw,mnh,mxw,mxh); } });
164          }
165          private native void natSyncCursor(int n);
166          public void syncCursor() {
167              int n;
168              if(cursor.equals("default")) n = 0;
169              else if(cursor.equals("wait")) n = 1;
170              else if(cursor.equals("crosshair")) n = 2;
171              else if(cursor.equals("text")) n = 3;
172              else if(cursor.equals("hand")) n = 4;
173              else if(cursor.equals("move")) n = 5;
174              else if(cursor.equals("east") || cursor.equals("west")) n = 6;
175              else n = 0; 
176              final int n_ = n;
177              CarbonMessage.add(new CarbonMessage() { public void perform() { natSyncCursor(n_); } });
178          }
179         
180          /* Drawing stuff */
181          public abstract void blit(PixelBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2);
182  
183          public final void _dispose() { CarbonMessage.add(new CarbonMessage() { public void perform() { natDispose(); } }); }
184          public native void natDispose();
185          
186          public final native void natInit(boolean framed);
187          
188          public CarbonSurface(Box root, final boolean framed) {
189              super(root);
190              final Semaphore sem = new Semaphore();
191              CarbonMessage.add(new CarbonMessage() { public void perform() { CarbonSurface.this.natInit(framed); sem.release(); } });
192              sem.block();
193          }
194          
195          public void needsReshape() { }
196          protected static native void blitLock();
197          protected static native void blitUnlock();
198          protected static native void blitWait();
199      }
200      
201      static class GLCarbonPixelBuffer extends OpenGL.GLPixelBuffer {
202          RawData rawCTX;
203          RawData rawWindowRef;
204          int textureName;
205          boolean rectTexture;
206          CarbonOpenGL gl;
207          
208          private native void natInit();
209          private static native void natCleanup(RawData rawWindowRef, RawData rawCTX);
210          
211          
212          private static final int fixupDimension(CarbonOpenGL gl, int n) {
213              if(!gl.rectangularTextures) n = OpenGL.roundToPowerOf2(n);
214              return Math.min(n,gl.maxAglSurfaceTexSize);
215          }
216          public GLCarbonPixelBuffer(int w, int h, final CarbonOpenGL gl) {
217              super(fixupDimension(gl,w),fixupDimension(gl,h));
218              this.gl = gl;
219              rectTexture = gl.hasRectangularTextures();
220              final Semaphore sem = new Semaphore();
221              CarbonMessage.add(new CarbonMessage() { public void perform() { GLCarbonPixelBuffer.this.natInit(); sem.release(); } });
222              sem.block();
223          }
224          public native void activateContext();
225          protected void finalize() {
226              CarbonMessage.add(new CarbonMessage() { public void perform() { natCleanup(rawWindowRef,rawCTX); } });
227              gl.deleteTexture(textureName);
228          }
229      }
230      
231      static class GLCarbonSurface extends CarbonSurface {
232          RawData rawCTX;
233          CarbonOpenGL gl;
234          boolean needsReshape;
235                  
236          private final native void natInit();
237          private final native void flush();
238          private final native void clear();
239          
240          public GLCarbonSurface(Box root, boolean framed, CarbonOpenGL gl) {
241              super(root,framed);
242              this.gl = gl;
243              natInit();
244          }
245          
246          public void setLimits(int mnw,int mnh, int mxw, int mxh) {
247              mxw = Math.min(mxw,gl.maxSurfaceWidth);
248              mxh = Math.min(mxh,gl.maxSurfaceHeight);
249              super.setLimits(mnw,mnh,mxw,mxh);
250          }
251          
252          public void _setSize(int w, int h) {
253              w = Math.min(w,gl.maxSurfaceWidth);
254              h = Math.min(h,gl.maxSurfaceWidth);
255              super._setSize(w,h);
256          }
257          
258          private native void natBlit(GLCarbonPixelBuffer db, int sx, int sy, int dx, int dy, int dx2, int dy2);
259          public void blit(PixelBuffer db, int sx, int sy, int dx, int dy, int dx2, int dy2) {
260              natBlit((GLCarbonPixelBuffer)db,sx,sy,dx,dy,dx2,dy2);
261          }
262          
263          
264          // The blit_lock ensures the window size does not change through the entire blit operation.
265          public void render() {
266              /*
267              blitLock();
268              while(pendingResize) blitWait();
269              */
270              if(needsReshape) {
271                  needsReshape = false;
272                  
273                  reshape(winWidth,winHeight);
274                  clear();
275                  Dirty(0,0,winWidth,winHeight);
276              }
277              super.render();
278              flush();
279              /*
280              blitUnlock();
281              */
282          }
283          
284          private native void reshape(int w, int h);
285          // blit_lock is assumed to be held
286          public void needsReshape() { needsReshape = true; }
287  
288          public native void natDispose();
289      }
290  
291      /*private class QZCarbonPixelBuffer extends PixelBuffer {
292          
293          public QZCarbonPixelBuffer(int width, int height) {
294          }
295      }
296         private class QZCarbonSurface extends CarbonSurface {
297          public QZCarbonSurface(Box root, boolean framed) {
298              super(b,root);
299          }
300          public native void blit(PixelBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2);
301      }
302      
303      private class QZCarbonPicture extends Picture {
304          int width;
305          int height;
306          
307          public final int getWidth() { return width; }
308          public final int getHeight() { return height; }
309                  
310          public QZCarbonPicture(int w, int h) {
311              this.width = w;
312              this.height = h;
313          }
314      }*/
315      
316      protected PixelBuffer _createPixelBuffer(int w, int h, Surface owner) {
317          if(openGL != null)
318              return new GLCarbonPixelBuffer(w,h,openGL);
319          else
320              return /*new QZCarbonPixelBuffer(w,h)*/ null;
321      }
322      protected Surface _createSurface(Box b, boolean framed) {
323          if(openGL != null)
324              return new GLCarbonSurface(b,framed, openGL);
325          else
326              return /*new QZCarbonSufrace(b,framed)*/ null;
327      }
328      protected Picture _createPicture(JS r) {
329          if(openGL != null)
330              return openGL._createPicture(r, true);
331          else
332              return /*new QZCarbonPicture(data,w,h);*/ null;
333      }
334      protected org.xwt.Font.Glyph  _createGlyph(org.xwt.Font f, char c) {
335          if(openGL != null)
336              return openGL._createGlyph(f, c);
337          else
338              return super.createGlyph(f, c);
339      }
340      
341      /* A message that is sent through the carbon event queue */
342      private static abstract class CarbonMessage {
343          public abstract void perform();
344          
345          static { natInit(); }
346          public static native void natInit();
347          public static native void add(CarbonMessage m);
348      }
349  }
350