From: megacz Date: Fri, 30 Jan 2004 07:36:08 +0000 (+0000) Subject: 2003/09/23 08:24:59 X-Git-Tag: RC3~589 X-Git-Url: http://git.megacz.com/?p=org.ibex.core.git;a=commitdiff_plain;h=a81a151e639664cb340cf3726f9e8b9c77d125fb 2003/09/23 08:24:59 darcs-hash:20040130073608-2ba56-05ac1025b2fd2a3cd137e51158744c1b53fcea21.gz --- diff --git a/src/org/xwt/Box.java.pp b/src/org/xwt/Box.java.pp index eb8c0c0..2c25b44 100644 --- a/src/org/xwt/Box.java.pp +++ b/src/org/xwt/Box.java.pp @@ -6,9 +6,6 @@ package org.xwt; // RULE: coordinates on non-static methods are ALWAYS relative to the // upper-left hand corner of this -// FIXME: font color, italicization, bolding, and underlining -// FIXME: align -// FIXME: fixed aspect // FEATURE: reflow before allowing js to read from width/height // FEATURE: fastpath for rows=1/cols=1 // FEATURE: reflow starting with a certain child @@ -72,7 +69,7 @@ public final class Box extends JS.Scope { // Misc instance data //////////////////////////////////////////////////////////////// - private static int sizePosChangesSinceLastRender = 0; + static int sizePosChangesSinceLastRender = 0; // Misc instance data //////////////////////////////////////////////////////////////// @@ -85,31 +82,16 @@ public final class Box extends JS.Scope { Box redirect = this; Surface surface = null; // null on all non-root boxen - // FEATURE: combine this with the JSObject Hash - Hash traps = null; - - // Flags /////////////////////////////////////////////////////////////////////////////// + short flags = 0; static int MOUSEINSIDE_FLAG = 0x00000001; static int INVISIBLE_FLAG = 0x00000002; static int ABSOLUTE_FLAG = 0x00000004; - static int HSHRINK_FLAG = 0x00000010; - static int VSHRINK_FLAG = 0x00000020; - static int TILE_FLAG = 0x00000040; - - /** - * Set when the font changes, cleared during repack. If set - * during repack, all font==null children are marked for reflow - * and given the font_changed_flag. We use this flag to avoid - * having to iterate over all descendents of a box when its font - * changes. - */ - static int FONT_CHANGED_FLAG = 0x00000100; - static int ISROOT_FLAG = 0x00000200; - - static int ALIGN_FLAG = 0x00000000; - static int FIXEDASPECT_FLAG = 0x00000000; - int flags = 0; + static int HSHRINK_FLAG = 0x00000008; + static int VSHRINK_FLAG = 0x00000010; + static int TILE_FLAG = 0x00000020; + static int FONT_CHANGED_FLAG = 0x00000040; // set when font changes, cleared during repack + static int ISROOT_FLAG = 0x00000080; // Geometry //////////////////////////////////////////////////////////////////////////// @@ -139,8 +121,8 @@ public final class Box extends JS.Scope { private int colspan = 1; // computed during reflow - LENGTH x = 0; - LENGTH y = 0; + public LENGTH x = 0; + public LENGTH y = 0; public LENGTH width = 0; public LENGTH height = 0; private int row = 0; // FEATURE use a short @@ -167,7 +149,6 @@ public final class Box extends JS.Scope { /** Adds the intersection of (x,y,w,h) and the node's current actual geometry to the Surface's dirty list */ public final void dirty() { dirty(0, 0, width, height); } public final void dirty(int x, int y, int w, int h) { - /* for(Box cur = this; cur != null; cur = cur.parent) { w = min(x + w, cur.width) - max(x, 0); h = min(y + h, cur.height) - max(y, 0); @@ -178,10 +159,6 @@ public final class Box extends JS.Scope { x += cur.x; y += cur.y; } - */ - Box cur; - for(cur = this; cur.parent != null; cur = cur.parent); - if (cur.surface != null) cur.surface.dirty(0, 0, cur.width, cur.height); } /** @@ -200,10 +177,10 @@ public final class Box extends JS.Scope { if (!wasinside && !isinside) return; - if (traps == null) { } - else if (!wasinside && isinside && traps.get("Enter") != null) put("Enter", Boolean.TRUE); - else if (wasinside && !isinside && traps.get("Leave") != null) put("Leave", Boolean.TRUE); - else if (wasinside && isinside && (mousex != oldmousex || mousey != oldmousey) && traps.get("Move") != null) put("Move", Boolean.TRUE); + if (!wasinside && isinside && get("Enter", Trap.class) != null) put("Enter", Boolean.TRUE); + else if (wasinside && !isinside && get("Leave", Trap.class) != null) put("Leave", Boolean.TRUE); + else if (wasinside && isinside && (mousex != oldmousex || mousey != oldmousey) && get("Move", Trap.class) != null) + put("Move", Boolean.TRUE); if (isinside && cursor != null) getRoot().cursor = cursor; @@ -300,8 +277,8 @@ public final class Box extends JS.Scope { if (x != this.x || y != this.y || width != this.width || height != this.height) { (parent == null ? this : parent).dirty(this.x, this.y, this.width, this.height); boolean sizechange = false, poschange = false; - if (traps != null && (this.width != width || this.height != height) && traps.get("SizeChange") != null) sizechange = true; - if (traps != null && (this.x != x || this.y != y) && traps.get("PosChange") != null) poschange = true; + if ((this.width != width || this.height != height) && get("SizeChange", Trap.class) != null) sizechange = true; + if ((this.x != x || this.y != y) && get("PosChange", Trap.class) != null) poschange = true; this.width = width; this.height = height; this.x = x; this.y = y; dirty(); if (sizechange || poschange) @@ -443,12 +420,8 @@ public final class Box extends JS.Scope { } void renderStretchedImage(int globalx, int globaly, int clipx, int clipy, int clipw, int cliph, PixelBuffer buf) { - //buf.setClip(x, y, w + x, h + y); - System.out.println("draw " + clipx + " " + clipy + " " + (clipx + clipw) + " " + (clipy + cliph)); - buf.drawPicture(image, - clipx, clipy, clipx + clipw, clipy + cliph, - 0, 0, image.getWidth(), image.getHeight()); - //buf.setClip(0, 0, buf.getWidth(), buf.getHeight()); + // FIXME: wrong + buf.drawPicture(image, clipx, clipy, clipx + clipw, clipy + cliph, 0, 0, image.getWidth(), image.getHeight()); } void renderTiledImage(int globalx, int globaly, int x, int y, int w, int h, PixelBuffer buf) { @@ -506,31 +479,28 @@ public final class Box extends JS.Scope { } else if ("apply".equals(method)) { if (checkOnly) return Boolean.TRUE; if (args.elementAt(0) instanceof Res) { - try { Res res = (Res)args.elementAt(0); // res = res.addExtension(".xwt"); - Template t = Template.buildTemplate(res.getInputStream(), "fromResource"); + Template t = Template.getTemplate(res); if (ThreadMessage.suspendThread()) try { JS.Callable callback = args.length() < 2 ? null : (Callable)args.elementAt(1); - + // FIXME!!! needs to be xwt.apply(template, box) - t.apply(this, null, null, callback, 0, t.numUnits(), null); + t.apply(this, callback, 0, t.numUnits(), null); } finally { ThreadMessage.resumeThread(); } - } catch (IOException e) { - Log.log(this, e); - } } else if (args.elementAt(0) instanceof String) { String templatename = (String)args.elementAt(0); - Template t = Template.getTemplate(templatename, null); + // FIXME + Template t = Template.getTemplate(null); if (t == null) { if (Log.on) Log.logJS(this, "template " + templatename + " not found"); } else { if (ThreadMessage.suspendThread()) try { JS.Callable callback = args.length() < 2 ? null : (Callable)args.elementAt(1); // FIXME!!! needs to be xwt.apply(template, box) - t.apply(this, null, null, callback, 0, t.numUnits(), null); + t.apply(this, callback, 0, t.numUnits(), null); } finally { ThreadMessage.resumeThread(); } @@ -575,8 +545,6 @@ public final class Box extends JS.Scope { b.remove(); put("0", b); } - } else if (value instanceof RootProxy) { - if (Log.on) Log.logJS(this, "attempt to reparent a box via its proxy object"); } else { Box newnode = (Box)value; @@ -643,6 +611,9 @@ public final class Box extends JS.Scope { } } + public Object get(Object key, Object key2) { return super.get(key, key2); } + public void put(Object key, Object key2, Object val) { super.put(key, key2, val); } + public Object get_(Object name) { return super.get(name); } public Object get(Object name) { return get(name, false); } public Object get(Object name_, boolean ignoretraps) { @@ -653,7 +624,7 @@ public final class Box extends JS.Scope { if (name.equals("")) return null; // See if we're triggering a trap - Trap t = traps == null || ignoretraps ? null : (Trap)traps.get(name); + Trap t = ignoretraps ? (Trap)null : (Trap)get(name, Trap.class); if (t != null) return t.perform(); // Check for a special handler @@ -662,7 +633,8 @@ public final class Box extends JS.Scope { Object ret = super.get(name); if (name.startsWith("$") && ret == null) - if (Log.on) Log.logJS(this, "WARNING: attempt to access " + name + ", but no child with id=\"" + name.substring(1) + "\" found"); + if (Log.on) Log.logJS(this, "WARNING: attempt to access " + name + ", but no child with id=\"" + + name.substring(1) + "\" found"); return ret; } @@ -682,14 +654,13 @@ public final class Box extends JS.Scope { * @param rp if this put is being performed via a root proxy, rp is the root proxy. */ public void put_(Object name, Object value) { super.put(name, value); } - public void put(Object name, Object value) { put(name, value, false, null); } - public void put(Object name, Object value, boolean ignoretraps) { put(name, value, ignoretraps, null); } - public void put(Object name_, Object value, boolean ignoretraps, RootProxy rp) { + public void put(Object name, Object value) { put(name, value, false); } + public void put(Object name_, Object value, boolean ignoretraps) { if (name_ instanceof Number) { put(((Number)name_).intValue(), value); return; } if (!(name_ instanceof String)) { super.put(name_,value); return; } String name = name_.toString(); - if (!ignoretraps && traps != null) { - Trap t = (Trap)traps.get(name); + if (!ignoretraps) { + Trap t = (Trap)get(name, Trap.class); if (t != null) { t.perform(value); return; @@ -843,27 +814,6 @@ public final class Box extends JS.Scope { } - // Root Proxy /////////////////////////////////////////////////////////////////////////////// - - // FEATURE: use xwt.graft() here - RootProxy myproxy = null; - public JS getRootProxy() { - if (myproxy == null) myproxy = new RootProxy(this); - return myproxy; - } - - private static class RootProxy extends JS { - Box box; - RootProxy(Box b) { this.box = b; } - public Object get(Object name) { return box.get(name); } - public void put(Object name, Object value) { box.put(name, value, false, this); } - public Object[] keys() { return box.keys(); } - public Object callMethod(Object method, JS.Array args, boolean justChecking) { - return ((Box)box).callMethod(method,args,justChecking); - } - } - - // Trivial Helper Methods (should be inlined) ///////////////////////////////////////// static final int min(int a, int b) { if (a startargs + 1 ? args[startargs + 1] : "main"; Platform.forceLoad(); @@ -66,7 +67,6 @@ public class Main { InputStream is = Platform.getBuiltinInputStream(); if (is == null) Platform.criticalAbort("unable to load builtin.xwar"); - Resources.loadArchive(is); if (Log.on) Log.log(Main.class, "loading scar image"); PNG png = PNG.decode(new ByteArrayInputStream(Resources.getResource("org.xwt.builtin.scar.png")), "bundled scar image"); @@ -75,6 +75,7 @@ public class Main { String initialTemplate = "main"; Res initialRR = null; + // FIXME: after applying initial template, check numsurfaces; if zero, exit if (args.length > startargs) { if (args[startargs].startsWith("http://")) { if (Log.on) Log.log(Main.class, "downloading xwar"); @@ -130,7 +131,7 @@ public class Main { //if (Log.on) Log.log(Main.class, "main thread blocking on new semaphore"); //new org.xwt.util.Semaphore().block(); Platform.running(); - + */ } catch (Throwable e) { e.printStackTrace(); Platform.criticalAbort("exception in Main.main(): " + e); diff --git a/src/org/xwt/Message.java b/src/org/xwt/Message.java index 30eec80..ba856cb 100644 --- a/src/org/xwt/Message.java +++ b/src/org/xwt/Message.java @@ -1,11 +1,138 @@ // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; +import java.util.*; +import org.xwt.util.*; + + /** A simple interface that must be supported by any object inserted into the MessageQueue. */ public interface Message { /** Invoked when the Message is dequeued. */ public void perform(); + + /** + * A singleton class (one instance per JVM) that implements a queue + * for XWT events and threads; this is the main action-scheduling + * loop for the engine. + * + * This is the foreground thread -- it + * dequeues Messages when they arrive in the queue. Using this + * thread ensures that the messages are executed in a synchronous, + * in-order fashion. + */ + public static class Q extends Thread { + + /** a do-nothing message enqueued to trigger Surfaces to refresh themselves */ + private static Message refreshMessage = new Message() { public void perform() { } }; + + /** enqueues a do-nothing message to get the Surfaces to refresh themselves */ + public static void refresh() { add(refreshMessage); } + + /** true iff latency-sensitive UI work is being done; signals the networking code to yield */ + public static volatile boolean working = false; + + private Q() { start(); } + + /** pending events */ + private static Queue events = new Queue(50); + + /** the number of objects in the queue that are not subclasses of ThreadMessage */ + public static volatile int nonThreadEventsInQueue = 0; + + /** the message currently being performed */ + static Message currentlyPerforming = null; + + private static Q singleton = new Q(); + private static Watcher watcher = new Watcher(); + + /** + * The message loop. Note that non-ThreadMessage Messages get + * priority, and that the queue is emptied in passes -- first we + * look at how many events are in the queue, then perform that + * many events, then render. This has the effect of throttling + * render requests to the appropriate frequency -- when many + * messages are in the queue, refreshes happen less frequently. + */ + public void run() { + Thread.currentThread().setPriority(Thread.MAX_PRIORITY); + while(true) { + try { + int size = events.size(); + for(int i=0; i 0) { + add(e); + i--; + continue; + } + if (!(e instanceof Thread)) working = true; + currentlyPerforming = e; + e.perform(); + currentlyPerforming = null; + working = false; + } + working = true; + for(int i=0; i= 5) + if (Log.on) Log.log(this, "note: executing same " + what + " for " + howlong + "s" + " at " + where); + } else { + m = Q.currentlyPerforming; + t = System.currentTimeMillis(); + } + try { Thread.sleep(1000); } catch (Exception e) { } + } + } + } + + } + } diff --git a/src/org/xwt/MessageQueue.java b/src/org/xwt/MessageQueue.java deleted file mode 100644 index 2f444c8..0000000 --- a/src/org/xwt/MessageQueue.java +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] -package org.xwt; - -import java.util.*; -import org.xwt.util.*; - -/** - * A singleton class (one instance per JVM) that implements a queue - * for XWT events and threads; this is the main action-scheduling - * loop for the engine. - * - * This is the foreground thread -- it - * dequeues Messages when they arrive in the queue. Using this - * thread ensures that the messages are executed in a synchronous, - * in-order fashion. - */ -public class MessageQueue extends Thread { - - /** a do-nothing message enqueued to trigger Surfaces to refresh themselves */ - private static Message refreshMessage = new Message() { public void perform() { } }; - - /** enqueues a do-nothing message to get the Surfaces to refresh themselves */ - public static void refresh() { add(refreshMessage); } - - /** true iff latency-sensitive UI work is being done; signals the networking code to yield */ - public static volatile boolean working = false; - - private MessageQueue() { start(); } - - /** pending events */ - private static Queue events = new Queue(50); - - /** the number of objects in the queue that are not subclasses of ThreadMessage */ - public static volatile int nonThreadEventsInQueue = 0; - - /** the message currently being performed */ - static Message currentlyPerforming = null; - - private static MessageQueue singleton = new MessageQueue(); - private static MessageQueueWatcher watcher = new MessageQueueWatcher(); - - // HACK for debugging purposes - Object lastfunc = null; - Message lastmessage = null; - - /** - * The message loop. Note that non-ThreadMessage Messages get - * priority, and that the queue is emptied in passes -- first we - * look at how many events are in the queue, then perform that - * many events, then render. This has the effect of throttling - * render requests to the appropriate frequency -- when many - * messages are in the queue, refreshes happen less frequently. - */ - public void run() { - Thread.currentThread().setPriority(Thread.MAX_PRIORITY); - while(true) { - try { - int size = events.size(); - for(int i=0; i 0) { - add(e); - i--; - continue; - } - if (!(e instanceof Thread)) working = true; - currentlyPerforming = e; - - // for debugging purposes - lastmessage = e; - if (e != null && e instanceof ThreadMessage) lastfunc = ((ThreadMessage)e).f; - - e.perform(); - currentlyPerforming = null; - working = false; - } - working = true; - for(int i=0; i= 5) - if (Log.on) Log.log(this, "note: executing same " + what + " for " + howlong + "s" + " at " + where); - } else { - m = MessageQueue.currentlyPerforming; - t = System.currentTimeMillis(); - } - try { Thread.sleep(1000); } catch (Exception e) { } - } - } - } - -} - - - diff --git a/src/org/xwt/Picture.java b/src/org/xwt/Picture.java index 8cd3c97..88cf65b 100644 --- a/src/org/xwt/Picture.java +++ b/src/org/xwt/Picture.java @@ -1,5 +1,9 @@ // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; +import java.io.*; +import org.xwt.js.*; +import org.xwt.util.*; +import org.xwt.translators.*; /** *

@@ -15,6 +19,37 @@ package org.xwt; *

*/ public abstract class Picture { + + /** Pictures, cached by Res */ + private static Cache cache = new Cache(); + + /** turns a resource into a Picture.Source */ + public static Picture fromRes(Res r) { + // FIXME: put self in background thread if needed + Picture ret = (Picture)cache.get(r); + if (ret == null) { + try { + PushbackInputStream pbis = new PushbackInputStream(r.getInputStream()); + int c = pbis.read(); + pbis.unread(c); + // FEATURE: cache GIF/PNG objects, reuse int[]'s? + if (c == 'G') ret = new GIF().fromInputStream(pbis, "FIXME"); + else if (c == 137) ret = new PNG().fromInputStream(pbis, "FIXME"); + else if (c == 0xff) ret = Platform.decodeJPEG(pbis, "FIXME"); + else throw new JS.Exn("couldn't figure out image type from first byte"); + cache.put(r, ret); + } catch (IOException e) { + Log.logJS(Picture.class, e); + return null; + } + } + return ret; + } + + /** the height of the picture */ public abstract int getHeight(); + + /** the width of the picture */ public abstract int getWidth(); + } diff --git a/src/org/xwt/PixelBuffer.java b/src/org/xwt/PixelBuffer.java index 5e78e98..3d6e09a 100644 --- a/src/org/xwt/PixelBuffer.java +++ b/src/org/xwt/PixelBuffer.java @@ -4,8 +4,7 @@ package org.xwt; /** *

* A block of pixels which can be drawn on and rapidly copied to the - * screen. Drawing operations are performed on this class; it is - * then rendered to the screen with Surface.blit(). + * screen. *

* *

@@ -14,30 +13,19 @@ package org.xwt; * method. These implementations may choose to use off-screen video * ram for this purpose (for example, a Pixmap on X11). *

- * - *

- * A note on coordinates: all members on PixelBuffer specify - * coordinates in terms of x1,y1,x2,y2 even though the Box class - * represents regions internally as x,y,w,h. - *

*/ public abstract class PixelBuffer { - /** Draw the region of source within (sx1, sy1, sx2, sy2) onto the region of this PixelBuffer within (dx1, dy1, dx2, dy2), scaling as needed. */ + /** Draw the region of source within s onto the region d on this PixelBuffer, scaling as needed */ public abstract void drawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2); - /** Draw source onto this PixelBuffer at (x,y) */ - public abstract void drawPicture(Picture source, int x, int y); - - /** Draw text in font and color on this PixelBuffer, with the upper left corner of the text at (x, y) */ - public abstract void drawString(String font, String text, int x, int y, int color); - /** Fill the region (x1, y1, x2, y2) with color (AARRGGBB format); the alpha channel component is ignored */ public abstract void fillRect(int x1, int y1, int x2, int y2, int color); - /** Sets the clip region for this PixelBuffer to (x,y,x2,y2) */ - public abstract void setClip(int x, int y, int x2, int y2); - + /** returns the height of the PixelBuffer */ public abstract int getHeight(); + + /** returns the width of the PixelBuffer */ public abstract int getWidth(); + } diff --git a/src/org/xwt/Platform.java b/src/org/xwt/Platform.java index 049404e..850e1dc 100644 --- a/src/org/xwt/Platform.java +++ b/src/org/xwt/Platform.java @@ -119,95 +119,74 @@ public class Platform { /** creates and returns a doublebuffer 'belonging' to owner; we need to associate PixelBuffers to surfaces * due to AWT 1.1 requirements (definately for Navigator, possibly also for MSJVM). */ + public static PixelBuffer createPixelBuffer(int w, int h, Surface s) { return platform._createPixelBuffer(w, h, s); } protected PixelBuffer _createPixelBuffer(int w, int h, Surface owner) { return null; } - /** creates and returns a new surface */ - protected Surface _createSurface(Box b, boolean framed) { return null; } + /** creates and returns a picture */ + public static Picture createPicture(int[] data, int w, int h) { return platform._createPicture(data, w, h); } + protected Picture _createPicture(int[] b, int w, int h) { return null; } /** creates a socket object */ + public static Socket getSocket(String host, int port, boolean ssl, boolean negotiate) throws IOException { + return platform._getSocket(host, port, ssl, negotiate); + } protected Socket _getSocket(String host, int port, boolean ssl, boolean negotiate) throws IOException { Socket ret = ssl ? new TinySSL(host, port, negotiate) : new Socket(java.net.InetAddress.getByName(host), port); ret.setTcpNoDelay(true); return ret; } - - /** creates and returns a picture */ - protected Picture _createPicture(int[] b, int w, int h) { return null; } /** should return true if it is safe to supress full-surface dirties immediately after a window resize */ + public static boolean supressDirtyOnResize() { return platform._supressDirtyOnResize(); } protected boolean _supressDirtyOnResize() { return false; } /** the human-readable name of the key mapped to XWT's 'alt' key */ + public static String altKeyName() { return platform._altKeyName(); } protected String _altKeyName() { return "alt"; } - /** opens a connection to the resource identified by URL u, and returns an InputStream */ - protected InputStream _urlToInputStream(URL u) throws IOException { return u.openStream(); } - /** returns the contents of the clipboard */ + public static Object getClipBoard() { return clipboardReadEnabled ? platform._getClipBoard() : null; } protected String _getClipBoard() { return null; } /** sets the contents of the clipboard */ + public static void setClipBoard(String s) { platform._setClipBoard(s); } protected void _setClipBoard(String s) { } /** returns the width of the screen, in pixels */ + public static int getScreenWidth() { return platform._getScreenWidth(); } protected int _getScreenWidth() { return 640; } /** returns the height of the screen, in pixels */ + public static int getScreenHeight() { return platform._getScreenHeight(); } protected int _getScreenHeight() { return 480; } - /** returns the width of a string in a platform-specific font */ - protected int _stringWidth(String font, String text) { return 10 * text.length(); } - - /** returns the maximum ascent of all glyphs in a given platform-specific font */ - protected int _getMaxAscent(String font) { return 10; } - - /** returns the maximum descent of all glyphs in a given platform-specific font */ - protected int _getMaxDescent(String font) { return 2; } - - /** returns a list of all platform-specific fonts available */ - protected String[] _listFonts() { return new String[] { }; } - /** returns the maximum number of threads that the XWT engine can create without adversely affecting the host OS */ + public static int maxThreads() { return platform._maxThreads(); } protected int _maxThreads() { return 25; } - /** Called once XWT is initialized and the application is running. */ - protected void _running() {} - - /** quits XWT */ - protected void _exit() { System.exit(0); } - /** used to notify the user of very serious failures; usually used when logging is not working or unavailable */ - protected void _criticalAbort(String message) { _exit(); } - - /** used to notify the user of very serious failures; usually used when logging is not working or unavailable */ - protected String _getDefaultFont() { return "sansserif10"; } + protected void _criticalAbort(String message) { System.exit(-1); } /** if true, org.xwt.Surface will generate a Click automatically after a press and a release */ + public static boolean needsAutoClick() { return platform._needsAutoClick(); } protected boolean _needsAutoClick() { return false; } /** if true, org.xwt.Surface will generate a DoubleClick automatically after recieving two clicks in a short period of time */ + public static boolean needsAutoDoubleClick() { return platform._needsAutoDoubleClick(); } protected boolean _needsAutoDoubleClick() { return false; } - protected void _newBrowserWindow(String url) { - if (Log.on) Log.log(this, "Platform " + platform.getClass().getName() + " cannot open browser windows"); - return; - } - - /** Returns null if XWT should always use direct connection; otherwise returns a ProxyInfo object with proxy settings */ - protected synchronized HTTP.Proxy _detectProxy() { return null; } - - /** displays a platform-specific "open file" dialog and returns the chosen filename, or null if the user hit cancel */ - protected String _fileDialog(String suggestedFileName, boolean write) { return null; } - /** returns true iff the platform has a case-sensitive filesystem */ + public static boolean isCaseSensitive() { return platform._isCaseSensitive(); } protected boolean _isCaseSensitive() { return true; } /** returns an InputStream to the builtin xwar */ + public static InputStream getBuiltinInputStream() { return platform._getBuiltinInputStream(); } protected InputStream _getBuiltinInputStream() { return this.getClass().getClassLoader().getResourceAsStream("org/xwt/builtin.jar"); } /** returns the value of the environment variable key, or null if no such key exists */ + public static String getEnv(String key) { return platform._getEnv(key); } protected String _getEnv(String key) { try { String os = System.getProperty("os.name").toLowerCase(); @@ -236,77 +215,11 @@ public class Platform { } /** convert a JPEG into an Image */ - protected ImageDecoder _decodeJPEG(InputStream is, String name) { return null; } - - - // Static methods -- thunk to the instance ///////////////////////////////////////////////////////////////////////// - - /** if true, org.xwt.Surface should generate Click messages automatically when a Release happens after a Press and the mouse has not moved much */ - public static boolean needsAutoClick() { return platform._needsAutoClick(); } - - /** if true, org.xwt.Surface should generate DoubleClick messages automatically when needed */ - public static boolean needsAutoDoubleClick() { return platform._needsAutoDoubleClick(); } - - /** should return true if it is safe to supress full-surface dirties immediately after a window resize */ - public static String getDefaultFont() { return platform._getDefaultFont(); } - - /** should return true if it is safe to supress full-surface dirties immediately after a window resize */ - public static boolean supressDirtyOnResize() { return platform._supressDirtyOnResize(); } - - /** returns the width of a string in a platform-specific font */ - public static int stringWidth(String font, String text) { return platform._stringWidth(font, text); } - - /** returns the maximum ascent of all glyphs in a given platform-specific font */ - public static int getMaxAscent(String font) { return platform._getMaxAscent(font); } - - /** returns the maximum descent of all glyphs in a given platform-specific font. Three pixel minimum ensures space for underline. */ - public static int getMaxDescent(String font) { return Math.max(3, platform._getMaxDescent(font)); } - - /** returns the maximum number of threads that the XWT engine can create without adversely affecting the host OS */ - public static int maxThreads() { return platform._maxThreads(); } - - /** returns a list of all platform-specific fonts available */ - public static String[] listFonts() { return platform._listFonts(); } - - /** opens a connection to the resource identified by URL u, and returns an InputStream */ - public static InputStream urlToInputStream(URL u) throws IOException { return platform._urlToInputStream(u); } - - /** returns the contents of the clipboard */ - public static Object getClipBoard() { return clipboardReadEnabled ? platform._getClipBoard() : null; } - - /** sets the contents of the clipboard */ - public static void setClipBoard(String s) { platform._setClipBoard(s); } - - /** creates a socket object, with or without ssl encryption */ - public static Socket getSocket(String host, int port, boolean ssl, boolean negotiate) throws IOException { - return platform._getSocket(host, port, ssl, negotiate); - } - - /** returns the width of the screen, in pixels */ - public static int getScreenWidth() { return platform._getScreenWidth(); } - - /** returns the height of the screen, in pixels */ - public static int getScreenHeight() { return platform._getScreenHeight(); } - - /** creates and returns a doublebuffer 'belonging' to owner */ - public static PixelBuffer createPixelBuffer(int w, int h, Surface s) { return platform._createPixelBuffer(w, h, s); } - - /** creates and returns a picture */ - public static Picture createPicture(int[] data, int w, int h) { return platform._createPicture(data, w, h); } - - /** returns an InputStream to the builtin xwar */ - public static InputStream getBuiltinInputStream() { return platform._getBuiltinInputStream(); } - - /** creates and returns a picture */ - public static Picture createPicture(ImageDecoder i) { return platform._createPicture(i.getData(), i.getWidth(), i.getHeight()); } - - /** returns true iff the platform has a case-sensitive filesystem */ - public static boolean isCaseSensitive() { return platform._isCaseSensitive(); } - - /** returns the value of the environment variable key, or null if no such key exists */ - public static String getEnv(String key) { return platform._getEnv(key); } + public static synchronized Picture decodeJPEG(InputStream is, String name) { return platform._decodeJPEG(is, name); } + protected Picture _decodeJPEG(InputStream is, String name) { return null; } /** displays a platform-specific "open file" dialog and returns the chosen filename, or null if the user hit cancel */ + protected String _fileDialog(String suggestedFileName, boolean write) { return null; } public static String fileDialog(String suggestedFileName, boolean write) { if (!ThreadMessage.suspendThread()) return null; try { @@ -336,22 +249,10 @@ public class Platform { if (Log.on) Log.log(Platform.class, "newBrowserWindow, url = " + url); platform._newBrowserWindow(url); } - - /** Called once XWT is initialized and the application is running. */ - public static void running() { - Log.log(Platform.class, "XWT is running"); - platform._running(); - } - - /** quits XWT */ - public static void exit() { - Log.log(Platform.class, "exiting via Platform.exit()"); - platform._exit(); + protected void _newBrowserWindow(String url) { + if (Log.on) Log.log(this, "Platform " + platform.getClass().getName() + " cannot open browser windows"); } - /** the human-readable name of the key mapped to XWT's 'alt' key */ - public static String altKeyName() { return platform._altKeyName(); } - /** used to notify the user of very serious failures; usually used when logging is not working or unavailable */ public static void criticalAbort(String message) { if (Log.on) Log.log(Platform.class, "Critical Abort:"); @@ -360,6 +261,7 @@ public class Platform { } /** this method invokes the platform _createSurface() method and then enforces a few post-call invariants */ + protected Surface _createSurface(Box b, boolean framed) { return null; } public static Surface createSurface(Box b, boolean framed, boolean refreshable) { Surface ret = platform._createSurface(b, framed); b.width = b.height < Surface.scarPicture.getWidth() ? Surface.scarPicture.getWidth() : b.width; @@ -369,17 +271,18 @@ public class Platform { Object titlebar = b.get("titlebar", true); if (titlebar != null) ret.setTitleBarText(titlebar.toString()); + /* FIXME Object icon = b.get("icon", true); if (icon != null && !"".equals(icon)) { Picture pic = ImageDecoder.getPicture(icon.toString()); if (pic != null) ret.setIcon(pic); else if (Log.on) Log.log(Platform.class, "unable to load icon " + icon); } + */ ret.setLimits(b.minwidth, b.minheight, b.maxwidth, b.maxheight); if (refreshable) { - Surface.refreshableSurfaceWasCreated = true; Surface.allSurfaces.addElement(ret); ret.dirty(0, 0, b.width, b.height); ret.Refresh(); @@ -388,6 +291,7 @@ public class Platform { } /** detects proxy settings */ + protected synchronized HTTP.Proxy _detectProxy() { return null; } public static synchronized HTTP.Proxy detectProxy() { if (cachedProxyInfo != null) return cachedProxyInfo; @@ -405,65 +309,6 @@ public class Platform { return cachedProxyInfo; } - public static synchronized ImageDecoder decodeJPEG(InputStream is, String name) { - return platform._decodeJPEG(is, name); - } - - // Helpful font parsing stuff ////////////////////////////////////////////////////// - - public static class ParsedFont { - public ParsedFont() { } - public ParsedFont(String s) { parse(s); } - public int size = 10; - public String name = ""; - - public boolean italic = false; - public boolean bold = false; - public boolean underline = false; - public boolean dotted_underline = false; - - private static int stoi(Object o) { - if (o == null) return 0; - if (o instanceof Integer) return ((Integer)o).intValue(); - - String s = o.toString(); - try { return Integer.parseInt(s.indexOf('.') == -1 ? s : s.substring(0, s.indexOf('.'))); } - catch (NumberFormatException e) { return 0; } - } - - public void parse(String font) { - int i = 0; - while(i < font.length() && !Character.isDigit(font.charAt(i)) && font.charAt(i) != '*') i++; - name = font.substring(0, i).toLowerCase().replace('_', ' '); - size = 10; - italic = false; - bold = false; - underline = false; - dotted_underline = false; - if (i != font.length()) { - if (font.charAt(i) == '*') { - size = 0; - i++; - } else { - int j = i; - while (j < font.length() && Character.isDigit(font.charAt(j))) j++; - if (i != j) size = stoi(font.substring(i, j)); - i = j; - } - while(i < font.length()) { - switch (font.charAt(i)) { - case 'b': bold = true; break; - case 'i': italic = true; break; - case 'd': dotted_underline = true; break; - case 'u': underline = true; break; - } - i++; - } - } - } - - } - } diff --git a/src/org/xwt/Res.java b/src/org/xwt/Res.java index 402f2d6..3f70589 100644 --- a/src/org/xwt/Res.java +++ b/src/org/xwt/Res.java @@ -7,28 +7,33 @@ import java.util.zip.*; import org.xwt.js.*; import org.xwt.util.*; -// FIXME: ByteStream fileName property /** base class for XWT resources */ public abstract class Res extends JS { - public final InputStream getInputStream() throws IOException { return getInputStream(""); } + public String getDescriptiveName() { return "FIXME"; } - public Res graft(Object newResource) { throw new JS.Exn("cannot graft onto this resource"); } + /** if this Res corresponds to a Template, it is cached here */ + Template t = null; + /** cache of subresources so that the equality operator works on them */ private Hash refCache = null; + + /** returns an InputStream containing the Resource's contents */ + public InputStream getInputStream() throws IOException { return getInputStream(""); } + public abstract InputStream getInputStream(String path) throws IOException; + + /** graft newResource in place of this resource on its parent */ + public Res graft(Object newResource) { throw new JS.Exn("cannot graft onto this resource"); } + + /** if the path of this resource does not end with extension, return a new one wit it appended */ + public Res addExtension(String extension) { return new Ref(this, extension); } + + public Object[] keys() { throw new JS.Exn("cannot enumerate a resource"); } + public void put(Object key, Object val) { throw new JS.Exn("cannot put to a resource"); } public Object get(Object key) { if ("".equals(key)) { - try { - Res who = this; - //who = addExtension(".xwt"); - // FIXME: cache templates by the Res that created them, not their nodename - Template.buildTemplate(who.getInputStream(), "Resource"); - // FIXME: return the static here - return null; - } catch (IOException e) { - Log.logJS(this, e); - return null; - } + Template t = Template.getTemplate(addExtension(".xwt")); + return t == null ? null : t.getStatic(); } Object ret = refCache == null ? null : refCache.get(key); if (ret != null) return ret; @@ -38,12 +43,6 @@ public abstract class Res extends JS { return ret; } - public void put(Object key, Object val) { throw new JS.Exn("cannot put to a resource"); } - public Object[] keys() { throw new JS.Exn("cannot enumerate a resource"); } - - public abstract InputStream getInputStream(String path) throws IOException; - //public abstract Res addExtension(String extension); - public static Res stringToRes(String url) { if (url.indexOf('!') != -1) return (Res)(new Zip(stringToRes(url.substring(0, url.lastIndexOf('!')))).get(url.substring(url.lastIndexOf('!') + 1))); @@ -61,12 +60,23 @@ public abstract class Res extends JS { public InputStream getInputStream(String path) throws IOException { return new org.xwt.HTTP(url + path).GET(); } } + /** byte arrays */ + public static class ByteArray extends Res { + private byte[] bytes; + ByteArray(byte[] bytes) { this.bytes = bytes; } + public InputStream getInputStream(String path) throws IOException { + if (!"".equals(path)) throw new JS.Exn("can't get subresources of a byte[] resource"); + return new ByteArrayInputStream(bytes); + } + } + // FIXME: dangerous /** a file */ public static class File extends Res { private String path; File(String path) { this.path = path; } - public InputStream getInputStream(String rest) throws IOException { return new FileInputStream((path + rest).replace('/', java.io.File.separatorChar)); } + public InputStream getInputStream(String rest) throws IOException { + return new FileInputStream((path + rest).replace('/', java.io.File.separatorChar)); } } /** wrap a Res around a preexisting InputStream */ @@ -97,6 +107,9 @@ public abstract class Res extends JS { Res parent; Object key; Ref(Res parent, Object key) { this.parent = parent; this.key = key; } + public Res addExtension(String extension) { + return (key instanceof String && ((String)key).endsWith(extension)) ? this : new Ref(this, extension); + } public InputStream getInputStream(String path) throws IOException { return parent.getInputStream("/" + key + path); } @@ -108,14 +121,11 @@ public abstract class Res extends JS { Res graftee; Object replaced_key; Object replaced_val; - Graft(Res graftee, Object key, Object val) { - this.graftee = graftee; replaced_key = key; replaced_val = val; } + Graft(Res graftee, Object key, Object val) { this.graftee = graftee; replaced_key = key; replaced_val = val; } public boolean equals(Object o) { return (this == o || graftee.equals(o)); } public int hashCode() { return graftee.hashCode(); } public InputStream getInputStream(String s) throws IOException { return graftee.getInputStream(s); } - public Object get(Object key) { - return replaced_key.equals(key) ? replaced_val : graftee.get(key); - } + public Object get(Object key) { return replaced_key.equals(key) ? replaced_val : graftee.get(key); } } /** unpacks a Microsoft CAB file (possibly embedded in another file; we scan for 'MSCF' */ diff --git a/src/org/xwt/Resources.java b/src/org/xwt/Resources.java deleted file mode 100644 index 230f2fd..0000000 --- a/src/org/xwt/Resources.java +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] -package org.xwt; - -import java.io.*; -import java.net.*; -import java.util.*; -import java.util.zip.*; -import java.lang.*; -import org.xwt.js.*; -import org.xwt.util.*; - -/** - * A singleton class that acts as a repository for files obtained - * from xwar archives or the local filesystem. - * - * All names are converted to resource names (dots instead of - * slashes) when they are loaded into this repository; however, - * filename extensions are left on, so queries (resolveResource(), - * getResource()) should include the extension when querying for - * resources. - */ -public class Resources { - - /** Holds resources added at runtime. Initialized to hold 2000 to work around a NetscapeJVM bug. */ - private static Hash bytes = new Hash(2000, 3); - - /** keeps track of which archive loaded templates into which package */ - private static Hash usedPackages = new Hash(); - - /** Returns true iff name is a valid resource name */ - private static boolean validResourceName(String name) { - if (name == null || name.equals("")) return true; - if (name.endsWith("/box.xwt") || name.endsWith("/svg.xwt")) return false; - if (name.equals("box.xwt") || name.equals("svg.xwt")) return false; - if (!((name.charAt(0) >= 'A' && name.charAt(0) <= 'Z') || - (name.charAt(0) >= 'a' && name.charAt(0) <= 'z'))) return false; - for(int i=1; i= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - c == '_' || c == '.' || - (c >= '0' && c <= '9'))) return false; - } - return true; - } - - /** Load a directory as if it were an archive */ - public static synchronized void loadDirectory(File dir) throws IOException { loadDirectory(dir, ""); } - private static synchronized void loadDirectory(File dir, String prefix) throws IOException { - String n = prefix.replace(File.separatorChar, '.'); - if (n.endsWith(".")) n = n.substring(0, n.length() - 1); - new Static(n); - String[] subfiles = dir.list(); - for(int i=0; iname to a fully - * resolved resource name, using importlist as a search - * list, or null if no resource was found. - * - * Both the arguments and return values from this function SHOULD - * include extensions (".xwt", ".xwf", etc) and SHOULD use dots - * (".") instead of slashes ("/"). - */ - public static String resolve(String name, String[] importlist) { - final int imax = importlist == null ? 0 : importlist.length; - for(int i=-1; i < imax; i++) { - String resolved = i == -1 ? name : (importlist[i] + '.' + name); - for(int j=mapFrom.size() - 1; j>=0; j--) { - String from = mapFrom.elementAt(j).toString(); - if (resolved.startsWith(from) && (resolved.endsWith(".xwt") || resolved.endsWith(".xwf"))) { - String tryme = mapTo.elementAt(j) + resolved.substring(from.length()); - if (bytes.get(tryme) != null) return tryme; - } - } - if (bytes.get(resolved) != null) return resolved; - } - return null; - } - - /** Returns the named resource as a byte[]. - * @param name A fully resolved resource name, using slashes - * instead of periods. If it is null, this function - * will return null. - */ - public static byte[] getResource(String name) { - if (name == null) return null; - synchronized(bytes) { - Object o = bytes.get(name); - if (o == null) return null; - if (o instanceof byte[]) return ((byte[])o); - if (o instanceof File) { - try { - FileInputStream fi = new FileInputStream((File)o); - byte[] b = isToByteArray(fi); - bytes.put(name, b); - return b; - } catch (Exception e) { - if (Log.on) Log.log(Resources.class, "Exception while reading from file " + o); - if (Log.on) Log.log(Resources.class, e); - return null; - } - } - return null; - } - } - - /** scratch space for isToByteArray() */ - private static byte[] workspace = new byte[16 * 1024]; - - /** Trivial method to completely read an InputStream */ - public static synchronized byte[] isToByteArray(InputStream is) throws IOException { - int pos = 0; - while (true) { - int numread = is.read(workspace, pos, workspace.length - pos); - if (numread == -1) break; - else if (pos + numread < workspace.length) pos += numread; - else { - pos += numread; - byte[] temp = new byte[workspace.length * 2]; - System.arraycopy(workspace, 0, temp, 0, workspace.length); - workspace = temp; - } - } - byte[] ret = new byte[pos]; - System.arraycopy(workspace, 0, ret, 0, pos); - return ret; - } -} - - - diff --git a/src/org/xwt/SOAP.java b/src/org/xwt/SOAP.java index 5b969b4..debbc24 100644 --- a/src/org/xwt/SOAP.java +++ b/src/org/xwt/SOAP.java @@ -90,13 +90,11 @@ class SOAP extends XMLRPC { objects.addElement(new String(content.getBuf(), 0, content.size()).intern()); content.reset(); - // FIXME - /* } else if (me instanceof byte[]) { objects.removeElementAt(objects.size() - 1); - objects.addElement(new ByteStream(Base64.decode(new String(content.getBuf(), 0, content.size())))); + objects.addElement(new Res.ByteArray(Base64.decode(new String(content.getBuf(), 0, content.size())))); content.reset(); - */ + } else if (me instanceof Integer) { objects.removeElementAt(objects.size() - 1); objects.addElement(new Integer(new String(content.getBuf(), 0, content.size()))); @@ -179,11 +177,10 @@ class SOAP extends XMLRPC { sb.append(((Boolean)o).booleanValue() ? "true" : "false"); sb.append("\r\n"); - /* FIXME - } else if (o instanceof ByteStream) { + } else if (o instanceof Res) { try { sb.append(" <" + name + " xsi:type=\"SOAP-ENC:base64\">\r\n"); - InputStream is = ((ByteStream)o).getInputStream(); + InputStream is = ((Res)o).getInputStream(); byte[] buf = new byte[54]; while(true) { int numread = is.read(buf, 0, 54); @@ -204,7 +201,7 @@ class SOAP extends XMLRPC { if (Log.on) Log.log(this, e); throw new JS.Exn("caught IOException while attempting to send a ByteStream via SOAP"); } - */ + } else if (o instanceof String) { sb.append(" <" + name + " xsi:type=\"xsd:string\">"); String s = (String)o; diff --git a/src/org/xwt/Static.java b/src/org/xwt/Static.java deleted file mode 100644 index f762df3..0000000 --- a/src/org/xwt/Static.java +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] -package org.xwt; - -import org.xwt.js.*; -import org.xwt.util.*; - -/** implements objects in the xwt.static.* namespace */ -public class Static extends JS.Scope { - - public static Static getStatic(String resourcename) { - Template t = Template.getTemplate(resourcename, null); - if (t != null) t.link(); - return (Static)cache.get(resourcename); - } - - public static Static createStatic(String resourcename, boolean isPackage) { - Static ret = (Static)cache.get(resourcename); - if (ret != null) return ret; - if (resourcename.indexOf('.') != -1) - createStatic(resourcename.substring(0, resourcename.lastIndexOf('.')), true); - ret = new Static(resourcename, isPackage); - return ret; - } - - private static Hash cache = new Hash(); - - /** the resource name that this Static object corresponds to */ - private String resourcename = null; - - /** true iff this represents a directory (rather than an actual xwt) */ - public boolean ispackage = false; - - private Static(String resourcename, boolean ispackage) { - super(null); - cache.put(resourcename, this); - this.resourcename = resourcename; - this.ispackage = ispackage; - setSeal(ispackage); - } - - /** creates a new static representing a package */ - public Static(String resourcename) { this(resourcename, true); } - - public Object get(Object name_) { - String name = name_.toString(); - if (!ispackage) return super.get(name); - return getStatic(resourcename + (resourcename.length() == 0 ? "" : ".") + name); - } - - static { createStatic("", true); } - -} diff --git a/src/org/xwt/Surface.java b/src/org/xwt/Surface.java index 5f44098..e1cb141 100644 --- a/src/org/xwt/Surface.java +++ b/src/org/xwt/Surface.java @@ -17,122 +17,65 @@ import java.util.*; * MessageQueue-time (the size/position/state at the time that the * now-executing message was enqueued). This distinction is important. */ -public abstract class Surface { +public abstract class Surface extends PixelBuffer { - // Static Data //////////////////////////////////////////////////////////////////////////////// + /** Dirty regions on the screen which need to be rebuilt using Surface.blit() */ + DirtyList screenDirtyRegions = new DirtyList(); - /** true iff a user-created surface was created */ - static boolean refreshableSurfaceWasCreated = false; + public int getWidth() { return root == null ? 0 : root.width; } + public int getHeight() { return root == null ? 0 : root.height; } + + // Static Data //////////////////////////////////////////////////////////////////////////////// - /** a reference to the most recently enqueued Move message; used to throttle the message rate */ + /**< the most recently enqueued Move message; used to throttle the message rate */ private static Message lastMoveMessage = null; /** all instances of Surface which need to be refreshed by the MessageQueue */ public static Vec allSurfaces = new Vec(); - - /** true iff the alt button is pressed down, in real time */ - public static boolean alt = false; - /** true iff the control button is pressed down, in real time */ - public static boolean control = false; - - /** true iff the shift button is pressed down, in real time */ - public static boolean shift = false; - - /** true iff button 1 is depressed, in MessageQueue-time */ - public static boolean button1 = false; - - /** true iff button 2 is depressed, in MessageQueue-time */ - public static boolean button2 = false; - - /** true iff button 3 is depressed, in MessageQueue-time */ - public static boolean button3 = false; - - /** true iff all surfaces created from now on should be scarred */ - public static boolean scarAllSurfacesFromNowOn = false; - - /** false if the surface has never been rendered; used to determine if the surface should be repositioned to be centered on the screen */ - public boolean centerSurfaceOnRender = true; - - /** the x position of the mouse, relative to this Surface, in MessageQueue-time */ - public int mousex; + /** When set to true, render() should abort as soon as possible and restart the rendering process */ + static volatile boolean abort = false; - /** the y position of the mouse, relative to this Surface, in MessageQueue-time */ - public int mousey; + public static boolean alt = false; /**< true iff the alt button is pressed down, in real time */ + public static boolean control = false; /**< true iff the control button is pressed down, in real time */ + public static boolean shift = false; /**< true iff the shift button is pressed down, in real time */ + public static boolean button1 = false; /**< true iff button 1 is depressed, in MessageQueue-time */ + public static boolean button2 = false; /**< true iff button 2 is depressed, in MessageQueue-time */ + public static boolean button3 = false; /**< true iff button 3 is depressed, in MessageQueue-time */ - /** True iff this surface is minimized, in real time */ - public boolean minimized = false; - /** True iff this surface is maximized, in real time */ - public boolean maximized = false; + // Instance Data /////////////////////////////////////////////////////////////////////// - /** The name of the cursor on this surface -- this value fluctuates during rendering, so it may not be accurate; - * syncCursor() is called once the value is stable, to prevent the "flickering cursor" phenomenon - */ + public Box root; /**< The Box at the root of this surface */ public String cursor = "default"; - /** The Box at the root of this surface */ - public Box root; - - /** The number of SizeChange/PosChange traps triggered since the last successful render -- used to detect infinite loops */ - public int sizePosChangesSinceLastRender = 0; + public int mousex; /**< the x position of the mouse, relative to this Surface, in MessageQueue-time */ + public int mousey; /**< the y position of the mouse, relative to this Surface, in MessageQueue-time */ + public boolean minimized = false; /**< True iff this surface is minimized, in real time */ + public boolean maximized = false; /**< True iff this surface is maximized, in real time */ // Used For Simulating Clicks and DoubleClicks ///////////////////////////////////////////////// - /** the x-position of the mouse the last time a Press message was enqueued */ - int last_press_x = Integer.MAX_VALUE; - - /** the y-position of the mouse the last time a Press message was enqueued */ - int last_press_y = Integer.MAX_VALUE; - - /** the last button to recieve a Click message; used for simulating DoubleClick's */ - static int lastClickButton = 0; - - /** the last time a Click message was processed; used for simulating DoubleClick's */ - static long lastClickTime = 0; + int last_press_x = Integer.MAX_VALUE; /**< the x-position of the mouse the last time a Press message was enqueued */ + int last_press_y = Integer.MAX_VALUE; /**< the y-position of the mouse the last time a Press message was enqueued */ + static int lastClickButton = 0; /**< the last button to recieve a Click message; used for simulating DoubleClick's */ + static long lastClickTime = 0; /**< the last time a Click message was processed; used for simulating DoubleClick's */ // Methods to be overridden by subclasses /////////////////////////////////////////////////////// - /** when this method is invoked, the surface should push itself to the back of the stacking order */ - public abstract void toBack(); - - /** when this method is invoked, the surface should pull itself to the front of the stacking order */ - public abstract void toFront(); - - /** sets the actual cursor for this surface to the cursor referenced by cursor */ - public abstract void syncCursor(); - - /** If b == true, make the window invisible; otherwise, make it non-invisible. */ - public abstract void setInvisible(boolean b); - - /** If b == true, maximize the surface; otherwise, un-maximize it. */ - protected abstract void _setMaximized(boolean b); - - /** If b == true, minimize the surface; otherwise, un-minimize it. */ - protected abstract void _setMinimized(boolean b); - - /** Sets the surface's width and height. */ - protected abstract void setSize(int width, int height); - - /** Sets the surface's x and y position. */ - public abstract void setLocation(int x, int y); - public void setLocation() { setLocation(root.x, root.y); } - - /** Sets the surface's title bar text, if applicable */ - public abstract void setTitleBarText(String s); - - /** Sets the surface's title bar text, if applicable */ - public abstract void setIcon(Picture i); - - /** copies a region from the doublebuffer to this surface */ - public abstract void blit(PixelBuffer source, int sx, int sy, int dx, int dy, int dx2, int dy2); - - /** Destroy the surface */ - public abstract void _dispose(); - - /** Notifies the surface that limits have been imposed on the surface's size */ + public abstract void toBack(); /**< when invoked, the surface should push itself to the back of the stacking order */ + public abstract void toFront(); /**< when invoked, the surface should pull itself to the front of the stacking order */ + public abstract void syncCursor(); /**< the actual cursor for this surface to the cursor referenced by cursor */ + public abstract void setInvisible(boolean b); /**< If b, make window invisible; otherwise, make it non-invisible. */ + protected abstract void _setMaximized(boolean b); /**< If b, maximize the surface; otherwise, un-maximize it. */ + protected abstract void _setMinimized(boolean b); /**< If b, minimize the surface; otherwise, un-minimize it. */ + protected abstract void setSize(int width, int height); /**< Sets the surface's width and height. */ + public abstract void setLocation(); /**< Set the surface's x/y position to that of the root box */ + public abstract void setTitleBarText(String s); /**< Sets the surface's title bar text, if applicable */ + public abstract void setIcon(Picture i); /**< Sets the surface's title bar text, if applicable */ + public abstract void _dispose(); /**< Destroy the surface */ public void setLimits(int min_width, int min_height, int max_width, int max_height) { } @@ -150,7 +93,7 @@ public abstract class Surface { else if (button == 2) new SimpleMessage("Press2", Boolean.TRUE, Box.whoIs(root, mousex, mousey)); else if (button == 3) { final Box who = Box.whoIs(root, mousex, mousey); - MessageQueue.add(new Message() { public void perform() { + Message.Q.add(new Message() { public void perform() { Platform.clipboardReadEnabled = true; root.put("Press3", Boolean.TRUE); Platform.clipboardReadEnabled = false; @@ -204,7 +147,7 @@ public abstract class Surface { else if (control) key = "C-" + key; final String fkey = key; - MessageQueue.add(new KMessage(key)); + Message.Q.add(new KMessage(key)); } // This is implemented as a private static class instead of an anonymous class to work around a GCJ bug @@ -213,12 +156,14 @@ public abstract class Surface { public KMessage(String k) { key = k; } public void perform() { if (key.equals("C-v") || key.equals("A-v")) Platform.clipboardReadEnabled = true; + /* FIXME outer: for(int i=0; ib == true, maximize the surface; otherwise, un-maximize it. */ - public final void setMaximized(boolean b) { - if (b == maximized) return; - _setMaximized(b); - maximized = b; - } - - /** If b == true, minimize the surface; otherwise, un-minimize it. */ - public final void setMinimized(boolean b) { - if (b == minimized) return; - _setMinimized(b); - minimized = b; - } + public final void setMaximized(boolean b) { if (b != maximized) _setMaximized(maximized = b); } + public final void setMinimized(boolean b) { if (b != minimized) _setMinimized(minimized = b); } /** wrapper for setSize() which makes sure to dirty the place where the scar used to be */ void setSize() { - if (scarred) { - root.width = Math.max(root.width, scarPicture.getWidth()); - root.height = Math.max(root.height, scarPicture.getHeight()); - dirty(hscar, - root.height - vscar - scarPicture.getHeight(), - scarPicture.getWidth(), - scarPicture.getHeight()); - } + root.width = Math.max(root.width, scarPicture.getWidth()); + root.height = Math.max(root.height, scarPicture.getHeight()); + dirty(hscar, root.height - vscar - scarPicture.getHeight(), scarPicture.getWidth(), scarPicture.getHeight()); setSize(root.width, root.height); } @@ -367,23 +263,17 @@ public abstract class Surface { // quit when all windows are closed if (allSurfaces.size() == 0 && quitIfAllSurfacesGone && Main.doneInitializing) { - if (Log.on) { - if (refreshableSurfaceWasCreated) Log.log(this, "exiting because last remaining surface was disposed"); - else Log.log(this, "exiting because no surface was ever created"); - } - Platform.exit(); + if (Log.on) Log.log(this, "exiting because last surface was destroyed"); + System.exit(0); } } - /** Indicates that the backbuffer region x,y,w,h is no longer correct and must be regenerated */ public void dirty(int x, int y, int w, int h) { backbufferDirtyRegions.dirty(x, y, w, h); Refresh(); } public Surface(Box root) { - this.scarred = scarAllSurfacesFromNowOn; - scarAllSurfacesFromNowOn = true; this.root = root; if (root.surface != null && root.surface.root == root) { root.surface.dispose(false); @@ -393,13 +283,7 @@ public abstract class Surface { root.surface = this; // make sure the root is properly sized - do { - abort = false; - root.reflow(); - } while(abort); - - // this is a bit dangerous since we're passing ourselves to another method before subclasses' ctors have run... - backbuffer = Platform.createPixelBuffer(Platform.getScreenWidth(), Platform.getScreenHeight(), this); + do { abort = false; root.reflow(); } while(abort); root.dirty(); Refresh(); @@ -419,16 +303,7 @@ public abstract class Surface { if (!cursor.equals(oldcursor)) syncCursor(); } while(abort); - if (centerSurfaceOnRender) { - centerSurfaceOnRender = false; - int x = (Platform.getScreenWidth() - root.width) / 2; - int y = (Platform.getScreenHeight() - root.height) / 2; - setLocation(x, y); - root.x = x; - root.y = y; - } - - sizePosChangesSinceLastRender = 0; + Box.sizePosChangesSinceLastRender = 0; int[][] dirt = backbufferDirtyRegions.flush(); for(int i = 0; dirt != null && i < dirt.length; i++) { if (dirt[i] == null) continue; @@ -442,28 +317,27 @@ public abstract class Surface { if (y+h > root.height) h = root.height - y; if (w <= 0 || h <= 0) continue; - root.render(0, 0, x, y, w, h, backbuffer); + root.render(0, 0, x, y, w, h, this); // if any area under the scar was repainted, rescar that area - if (scarred && x < hscar + scarPicture.getWidth() && + if (x < hscar + scarPicture.getWidth() && y + h > root.height - scarPicture.getHeight() - vscar) { int _x1 = Math.max(x, hscar); int _x2 = Math.min(x + w, hscar + scarPicture.getWidth()); int _y1 = Math.max(y, root.height - scarPicture.getHeight() - vscar); int _y2 = Math.min(y + h, root.height - vscar); - backbuffer.drawPicture(scarPicture, _x1, _y1, _x2, _y2, - _x1 - (hscar), - _y1 - (root.height - scarPicture.getHeight() - vscar), - _x2 - (hscar), - _y2 - (root.height - scarPicture.getHeight() - vscar) - ); + drawPicture(scarPicture, _x1, _y1, _x2, _y2, + _x1, + _y1 - (root.height - scarPicture.getHeight()), + _x2, + _y2 - (root.height - scarPicture.getHeight()) + ); } if (abort) { // x,y,w,h is only partially reconstructed, so we must be careful not to re-blit it - blitDirtyScreenRegions(x, y, w, h); screenDirtyRegions.dirty(x, y, w, h); // put back all the dirty regions we haven't yet processed (including the current one) @@ -480,67 +354,6 @@ public abstract class Surface { screenDirtyRegions.dirty(x, y, w, h); } - // blit out all the areas we've just reconstructed - blitDirtyScreenRegions(); - } - - /** blits from the backbuffer to the screen for all regions of the screen which have become dirty */ - public synchronized void blitDirtyScreenRegions() { blitDirtyScreenRegions(-1, -1, 0, 0); } - - /** same as blitDirtyScreenRegions(), except that it will skip any regions within a,b,c,d */ - private synchronized void blitDirtyScreenRegions(int a, int b, int c, int d) { - - int[][] dirt = screenDirtyRegions.flush(); - if (Main.showRenders && dirt != null && dirt.length > 0 && a == -1) - blit(backbuffer, 0, 0, 0, 0, root.width, root.height); - - for(int i = 0; dirt != null && i < dirt.length; i++) { - if (dirt[i] == null) continue; - int x = dirt[i][0]; - int y = dirt[i][1]; - int w = dirt[i][2]; - int h = dirt[i][3]; - if (x < 0) x = 0; - if (y < 0) y = 0; - if (x+w > root.width) w = root.width - x; - if (y+h > root.height) h = root.height - y; - if (w <= 0 || h <= 0) continue; - - // if any part of this region falls within the "bad region", just skip it - boolean hhit = (x >= a && x <= a + c) || (x+w >= a && x+w <= a + c); - boolean vhit = (y >= b && y <= b + d) || (y+h >= b && y+h <= b + d); - if (hhit && vhit) { - screenDirtyRegions.dirty(x, y, w, h); - continue; - } - - blit(backbuffer, x, y, x, y, w + x, h + y); - - if (Main.showRenders) { - if (showRenderBuf == null) { - showRenderBuf = Platform.createPixelBuffer(10, 10, this); - showRenderBuf.fillRect(0, 0, 10, 10, 0x00FF0000); - showRenderBuf2 = Platform.createPixelBuffer(100, 100, this); - for(int y1 = 0; y1<100; y1++) - for(int x1 = 0; x1<100; x1++) - if ((x1 + y1) % 5 == 0) - showRenderBuf2.fillRect(x1, y1, x1 + 1, y1 + 1, 0x00FF0000); - } - for(int x1 = x; x1 0 && a == -1) + blit(backbuffer, 0, 0, 0, 0, root.width, root.height); + + for(int i = 0; dirt != null && i < dirt.length; i++) { + if (dirt[i] == null) continue; + int x = dirt[i][0]; + int y = dirt[i][1]; + int w = dirt[i][2]; + int h = dirt[i][3]; + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x+w > root.width) w = root.width - x; + if (y+h > root.height) h = root.height - y; + if (w <= 0 || h <= 0) continue; + + // if any part of this region falls within the "bad region", just skip it + boolean hhit = (x >= a && x <= a + c) || (x+w >= a && x+w <= a + c); + boolean vhit = (y >= b && y <= b + d) || (y+h >= b && y+h <= b + d); + if (hhit && vhit) { + screenDirtyRegions.dirty(x, y, w, h); + continue; + } + + blit(backbuffer, x, y, x, y, w + x, h + y); + + } + + } + } + + public static final int hscar = 0; + public static final int vscar = 0; + } diff --git a/src/org/xwt/Template.java b/src/org/xwt/Template.java index 11bb1fc..363886c 100644 --- a/src/org/xwt/Template.java +++ b/src/org/xwt/Template.java @@ -10,12 +10,7 @@ import org.xwt.util.*; /** * Encapsulates a template node (the <template/> element of a - * .xwt file, or any child element thereof). Each instance of - * Template has a nodeName -- this is the resource name of - * the file that the template node occurs in, concatenated with the - * path from the root element to this node, each step of which is in - * the form .n for some integer n. Static nodes use the string "._" - * as a path. + * .xwt file, or any child element thereof). * * Note that the Template instance corresponding to the * <template/> node carries all the header information -- hence @@ -26,27 +21,23 @@ import org.xwt.util.*; * See the XWT reference for information on the order in which * templates are applied, attributes are put, and scripts are run. */ + +// FIXME imports public class Template { // Instance Members /////////////////////////////////////////////////////// - /** this instance's nodeName */ - String nodeName; + /** the id of this box */ + String id = null; /** the id of the redirect target; only meaningful on a root node */ String redirect = null; /** templates that should be preapplied (in the order of application); only meaningful on a root node */ - private String[] preapply; - - /** 'linked' form of preapply -- the String references have been resolved into instance references */ - private Template[] _preapply = null; + private Template[] preapply; /** templates that should be postapplied (in the order of application); only meaningful on a root node */ - private String[] postapply; - - /** 'linked' form of postapply -- the String references have been resolved into instance references */ - private Template[] _postapply = null; + private Template[] postapply; /** keys to be "put" to instances of this template; elements correspond to those of vals */ private String[] keys; @@ -54,23 +45,14 @@ public class Template { /** values to be "put" to instances of this template; elements correspond to those of keys */ private Object[] vals; - /** array of strings representing the importlist for this template */ - private String[] importlist; - /** child template objects */ private Template[] children; - /** an array of the names of properties to be preserved when retheming; only meaningful on a root node */ - private String[] preserve = null; - - /** the id attribute on this node */ - private String id = ""; - /** see numUnits(); -1 means that this value has not yet been computed */ private int numunits = -1; - /** true iff the resolution of this template's preapply/postapply sets changed as a result of the most recent call to retheme() */ - private boolean changed = false; + /** the scope in which the static block is executed */ + private JS.Scope staticScope = null; /** the script on the static node of this template, null if it has already been executed */ private JS.CompiledFunction staticscript = null; @@ -78,6 +60,12 @@ public class Template { /** the script on this node */ private JS.CompiledFunction script = null; + /** the filename this node came from; used only for debugging */ + private String fileName = "unknown"; + + + // Only used during parsing ///////////////////////////////////////////////////////////////// + /** during XML parsing, this holds the list of currently-parsed children; null otherwise */ private Vec childvect = new Vec(); @@ -93,44 +81,27 @@ public class Template { /** the line number that this element starts on */ private int startLine = -1; - // Static data/methods /////////////////////////////////////////////////////////////////// - - /** a template cache so that only one Template object is created for each xwt */ - private static Hashtable cache = new Hashtable(1000); - - /** The default importlist; in future revisions this will contain "xwt.*" */ - public static final String[] defaultImportList = new String[] { }; - /** returns the appropriate template, resolving and theming as needed */ - public static Template getTemplate(String name, String[] importlist) { - String resolved = Resources.resolve(name + ".xwt", importlist); - Template t = resolved == null ? null : (Template)cache.get(resolved.substring(0, resolved.length() - 4)); - if (t != null) return t; - if (resolved == null) return null; - - // note that Templates in xwar's are instantiated as read in via loadStream() -- - // the following code only runs when XWT is reading templates from a filesystem. - ByteArrayInputStream bais = new ByteArrayInputStream(Resources.getResource(resolved)); - return buildTemplate(bais, resolved.substring(0, resolved.length() - 4)); - } + // Static data/methods /////////////////////////////////////////////////////////////////// - public static Template buildTemplate(InputStream is, String nodeName) { - return buildTemplate(is, nodeName, new TemplateHelper()); - } + private Template(String fileName) { this.fileName = fileName; } - public static Template buildTemplate(InputStream is, String nodeName, TemplateHelper t) { + public static Template getTemplate(Res r) { try { - return new Template(is, nodeName, t); + if (r.t != null) return r.t; + r.t = new Template(r.getDescriptiveName()); + new TemplateHelper().parseit(r.getInputStream(), r.t); + return r.t; } catch (XML.SchemaException e) { - if (Log.on) Log.log(Template.class, "error parsing template " + nodeName); + if (Log.on) Log.log(Template.class, "error parsing template " + r.t.fileName); if (Log.on) Log.log(Template.class, e.getMessage()); return null; } catch (XML.XMLException e) { - if (Log.on) Log.log(Template.class, "error parsing template at " + nodeName + ":" + e.getLine() + "," + e.getCol()); + if (Log.on) Log.log(Template.class, "error parsing template at " + r.t.fileName + ":" + e.getLine() + "," + e.getCol()); if (Log.on) Log.log(Template.class, e.getMessage()); return null; } catch (IOException e) { - if (Log.on) Log.log(Template.class, "IOException while parsing template " + nodeName + " -- this should never happen"); + if (Log.on) Log.log(Template.class, "IOException while parsing template " + r.t.fileName + " -- this should never happen"); if (Log.on) Log.log(Template.class, e); return null; } @@ -139,183 +110,75 @@ public class Template { // Methods to apply templates //////////////////////////////////////////////////////// - private Template(String nodeName) { - this.nodeName = nodeName; - cache.put(nodeName, this); - } - private Template(InputStream is, String nodeName, TemplateHelper th) throws XML.XMLException, IOException { - this(nodeName); - th.parseit(is, this); - } - - /** calculates, caches, and returns an integer approximation of how long it will take to apply this template, including pre/post and children */ + /** calculates, caches, and returns an integer approximation of how long it will take to apply this template, + * including pre/post and children */ int numUnits() { - link(); if (numunits != -1) return numunits; numunits = 1; - for(int i=0; _preapply != null && i<_preapply.length; i++) if (_preapply[i] != null) numunits += _preapply[i].numUnits(); - for(int i=0; _postapply != null && i<_postapply.length; i++) if (_postapply[i] != null) numunits += _postapply[i].numUnits(); + for(int i=0; preapply != null && ichange as needed */ - void link() { link(false); } - - /** same as link(), except that with a true value, it will force a re-link */ - private void link(boolean force) { - - if (staticscript != null) try { - JS.Scope s = Static.createStatic(nodeName, false); - if (staticscript != null) { - JS.CompiledFunction temp = staticscript; - staticscript = null; - - // we layer a transparent scope over the Static so that we can catch requests for the xwt object - // yet not screw up paths that include a package called xwt (ie xwt.static.org.xwt.foo) - JS.Scope varScope = new JS.Scope(s) { - public boolean isTransparent() { return true; } - public Object get(Object key) { - if ("xwt".equals(key)) return XWT.singleton; else return super.get(key); - } }; - - temp.call(new JS.Array(), varScope); - } - } catch (JS.Exn e) { - if (Log.on) Log.log(this, "WARNING: uncaught ecmascript exception: " + e.getMessage()); - } - - if (!(force || (preapply != null && _preapply == null) || (postapply != null && _postapply == null))) return; - - if (preapply != null) { - if (_preapply == null) _preapply = new Template[preapply.length]; - for(int i=0; i<_preapply.length; i++) { - Template t = getTemplate(preapply[i], importlist); - if (t != _preapply[i]) changed = true; - _preapply[i] = t; - } - } - if (postapply != null) { - if (_postapply == null) _postapply = new Template[postapply.length]; - for(int i=0; i<_postapply.length; i++) { - Template t = getTemplate(postapply[i], importlist); - if (t != _postapply[i]) changed = true; - _postapply[i] = t; - } - } - - for(int i=0; children != null && i node must have exactly one attribute, which must be called 'name'"); String importpackage = c.vals[0].toString(); if (importpackage.endsWith(".*")) importpackage = importpackage.substring(0, importpackage.length() - 2); - importlist.addElement(importpackage); return; } else if (c.localName.equals("redirect")) { @@ -426,24 +282,11 @@ public class Template { staticNodeHasBeenEncountered = true; return; - } else if (c.localName.equals("preserve")) { - if (c.len != 1 || !c.keys[0].equals("attributes")) - throw new XML.SchemaException(" node must have exactly one attribute, which must be called 'attributes'"); - if (t.preserve != null) - throw new XML.SchemaException(" header element may not appear more than once"); - - StringTokenizer tok = new StringTokenizer(c.vals[0].toString(), ",", false); - t.preserve = new String[tok.countTokens()]; - for(int i=0; i 0) preapply.copyInto(t.preapply = new String[preapply.size()]); - if (postapply.size() > 0) postapply.copyInto(t.postapply = new String[postapply.size()]); - importlist.setSize(0); preapply.setSize(0); postapply.setSize(0); + if (preapply.size() > 0) preapply.copyInto(t.preapply = new Template[preapply.size()]); + if (postapply.size() > 0) postapply.copyInto(t.postapply = new Template[postapply.size()]); templateNodeHasBeenEncountered = true; } else { @@ -456,11 +299,10 @@ public class Template { // push the last node we were in onto the stack nodeStack.addElement(t); - // instantiate a new node, and set its nodeName/importlist/preapply - Template t2 = new Template(t.nodeName + "." + t.childvect.size()); - t2.importlist = t.importlist; + // instantiate a new node, and set its fileName/importlist/preapply + Template t2 = new Template(t.fileName); t2.startLine = getLine(); - if (!c.localName.equals("box")) t2.preapply = new String[] { c.localName }; + if (!c.localName.equals("box")) t2.preapply = new Template[] { /*c.localName FIXME */ }; // make the new node the current node t = t2; @@ -468,6 +310,8 @@ public class Template { } // TODO: Sort contents straight from one array to another + // FIXME: height must come after image + // FIXME: use Vec here t.keys = new String[c.len]; t.vals = new Object[c.len]; System.arraycopy(c.keys, 0, t.keys, 0, c.len); @@ -569,10 +413,7 @@ public class Template { private JS.CompiledFunction genscript(boolean isstatic) { JS.CompiledFunction thisscript = null; try { - thisscript = JS.parse(t.nodeName + (isstatic ? "._" : ""), t.content_start, new StringReader(t.content.toString())); - } catch (JS.Exn ee) { - if (Log.on) Log.log(this, " ERROR: " + ee.getMessage()); - thisscript = null; + thisscript = JS.parse(t.fileName + (isstatic ? "._" : ""), t.content_start, new StringReader(t.content.toString())); } catch (IOException ioe) { if (Log.on) Log.log(this, " ERROR: " + ioe.getMessage()); thisscript = null; @@ -587,7 +428,7 @@ public class Template { public void characters(char[] ch, int start, int length) throws XML.SchemaException { // invoke the no-tab crusade for (int i=0; length >i; i++) if (ch[start+i] == '\t') throw new XML.SchemaException( - t.nodeName+ ":" + getLine() + "," + getCol() + ": tabs are not allowed in XWT files"); + t.fileName+ ":" + getLine() + "," + getCol() + ": tabs are not allowed in XWT files"); if ("static".equals(nameOfHeaderNodeBeingProcessed) || templateNodeHasBeenEncountered) { if (t.content == null) { diff --git a/src/org/xwt/ThreadMessage.java b/src/org/xwt/ThreadMessage.java index 61e8964..d028642 100644 --- a/src/org/xwt/ThreadMessage.java +++ b/src/org/xwt/ThreadMessage.java @@ -25,7 +25,7 @@ public class ThreadMessage extends Thread implements Message { /** the ThreadMessage thread blocks on this before executing any JavaScript */ Semaphore go = new Semaphore(); - /** The MessageQueue (main) thread blocks on this while the ThreadMessage thread is running JavaScript code */ + /** The Message.Q (main) thread blocks on this while the ThreadMessage thread is running JavaScript code */ Semaphore done = new Semaphore(); /** used to pool ThreadMessages that are not in use */ @@ -48,7 +48,7 @@ public class ThreadMessage extends Thread implements Message { } } ret.f = f; - MessageQueue.add(ret); + Message.Q.add(ret); } /** attempts to put this thread into the background to perform a blocking operation; returns false if unable to do so */ @@ -68,7 +68,7 @@ public class ThreadMessage extends Thread implements Message { /** re-enqueues this thread */ public static void resumeThread() { ThreadMessage mythread = (ThreadMessage)Thread.currentThread(); - MessageQueue.add(mythread); + Message.Q.add(mythread); mythread.setPriority(Thread.NORM_PRIORITY); mythread.go.block(); } @@ -87,7 +87,7 @@ public class ThreadMessage extends Thread implements Message { synchronized(waiting) { if (waiting.size() > 0) { f = (JS.Callable)waiting.remove(false); - MessageQueue.add(this); + Message.Q.add(this); } else if (spare.size() < 10) { spare.append(this); } else { @@ -104,7 +104,7 @@ public class ThreadMessage extends Thread implements Message { } } - /** this is invoked in the MessageQueue thread */ + /** this is invoked in the Message.Q thread */ public void perform() { go.release(); done.block(); diff --git a/src/org/xwt/Trap.java b/src/org/xwt/Trap.java index 3e6302b..c6c6a47 100644 --- a/src/org/xwt/Trap.java +++ b/src/org/xwt/Trap.java @@ -19,12 +19,16 @@ public class Trap { private static final Hash PROHIBITED = new Hash(120, 3); static { + // FIXME: review String[] p = new String[] { - "sizetoimage", "shrink", "hshrink", "vshrink", "x", "y", "width", "height", - "flex", "hflex", "vflex", /*"cols", "rows",*/ "align", "invisible", "absolute", "globalx", "globaly", - "minwidth", "minheight", "height", "width", "maxwidth", "maxheight", - "numchildren", "hpad", "vpad", "doublebuffered", "cursor", - "mousex", "mousey", "xwt", "static", "mouseinside", "root", "thisbox", "indexof", "svg" + "sizetoimage", "shrink", "hshrink", "vshrink", "x", "y", + "width", "height", "flex", "hflex", "vflex", "cols", + "rows", "align", "invisible", "absolute", "globalx", + "globaly", "minwidth", "minheight", "height", "width", + "maxwidth", "maxheight", "numchildren", "hpad", "vpad", + "doublebuffered", "cursor", "mousex", "mousey", "xwt", + "static", "mouseinside", "root", "thisbox", "indexof", + "path" }; for(int i=0; i 0) return cascade(); return f.call(new TrapArgs(this)); diff --git a/src/org/xwt/XMLRPC.java b/src/org/xwt/XMLRPC.java index f11413c..40fbb23 100644 --- a/src/org/xwt/XMLRPC.java +++ b/src/org/xwt/XMLRPC.java @@ -103,11 +103,8 @@ class XMLRPC extends JS.Callable { else if (c.localName.equals("double")) objects.setElementAt(new Double(new String(content.getBuf(), 0, content.size())), objects.size() - 1); - // FIXME - /* else if (c.localName.equals("base64")) - objects.setElementAt(new ByteStream(Base64.decode(new String(content.getBuf(), 0, content.size()))), objects.size() - 1); - */ + objects.setElementAt(new Res.ByteArray(Base64.decode(new String(content.getBuf(), 0, content.size()))), objects.size() - 1); else if (c.localName.equals("name")) objects.addElement(new String(content.getBuf(), 0, content.size())); @@ -199,12 +196,10 @@ class XMLRPC extends JS.Callable { sb.append(((Boolean)o).booleanValue() ? "1" : "0"); sb.append("\n"); - //FIXME - /* - } else if (o instanceof ByteStream) { + } else if (o instanceof Res) { try { sb.append(" \n"); - InputStream is = ((ByteStream)o).getInputStream(); + InputStream is = ((Res)o).getInputStream(); byte[] buf = new byte[54]; while(true) { int numread = is.read(buf, 0, 54); @@ -224,7 +219,6 @@ class XMLRPC extends JS.Callable { if (Log.on) Log.log(this, e); throw new JS.Exn("caught IOException while attempting to send a ByteStream via XML-RPC"); } - */ } else if (o instanceof String) { sb.append(" "); @@ -420,17 +414,17 @@ class XMLRPC extends JS.Callable { public Filter(InputStream is) { super(is); } public int read() throws IOException { java.lang.Thread.yield(); - while(MessageQueue.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { }; + while(Message.Q.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { }; return super.read(); } public int read(byte[] b) throws IOException { java.lang.Thread.yield(); - while(MessageQueue.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { }; + while(Message.Q.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { }; return super.read(b); } public int read(byte[] b, int i, int j) throws IOException { java.lang.Thread.yield(); - while(MessageQueue.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { }; + while(Message.Q.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { }; return super.read(b, i, j); } } diff --git a/src/org/xwt/XWT.java b/src/org/xwt/XWT.java index 7e7e5fe..f3368c4 100644 --- a/src/org/xwt/XWT.java +++ b/src/org/xwt/XWT.java @@ -7,6 +7,7 @@ import java.text.*; import java.util.*; import org.xwt.js.*; import org.xwt.util.*; +import org.xwt.translators.*; import org.bouncycastle.util.encoders.Base64; /** Singleton class that provides all functionality in the xwt.* namespace */ @@ -26,7 +27,21 @@ public final class XWT extends JS.Obj { else if (name.equals("control")) return Surface.control ? Boolean.TRUE : Boolean.FALSE; else if (name.equals("shift")) return Surface.shift ? Boolean.TRUE : Boolean.FALSE; else if (name.equals("clipboard")) return Platform.getClipBoard(); - else if (name.equals("static")) return Static.getStatic(""); + /* FIXME + else if (name.equals("static")) return .getStatic(""); + */ + else if (name.equals("origin")) return Main.origin; + else if (name.equals("maxdim")) return new Integer(Short.MAX_VALUE); + else if (name.equals("altKeyName")) return Platform.altKeyName(); + else if (name.equals("screenWidth")) return new Integer(Platform.getScreenWidth()); + else if (name.equals("screenHeight")) return new Integer(Platform.getScreenHeight()); + else if (name.equals("fileSeparator")) return File.separator; + else if (name.equals("homeDir")) return System.getProperty("user.home"); + else if (name.equals("tempDir")) return System.getProperty("java.io.tempdir"); + else if (name.equals("math")) return xwtMath; + else if (name.equals("string")) return xwtString; + else if (name.equals("parseInt")) return xwtString.get("parseInt"); + else if (name.equals("parseFloat")) return xwtString.get("parseFloat"); else if (name.equals("button")) { if (Surface.button1 && !Surface.button2 && !Surface.button3) return new Integer(1); else if (!Surface.button1 && Surface.button2 && !Surface.button3) return new Integer(1); @@ -46,125 +61,77 @@ public final class XWT extends JS.Obj { } else super.put(name, value); } - private XWT() { - super.put("maxdim", new Integer(Short.MAX_VALUE)); - super.put("origin", Main.origin); - super.put("altKeyName", Platform.altKeyName()); - super.put("screenWidth", new Integer(Platform.getScreenWidth())); - super.put("screenHeight", new Integer(Platform.getScreenHeight())); - super.put("fileSeparator", File.separator); - super.put("homeDir", System.getProperty("user.home")); - super.put("tempDir", System.getProperty("java.io.tempdir")); - super.put("math", xwtMath); - super.put("string", xwtString); + public Object callMethod(Object method, JS.Array args, boolean checkOnly) { - super.put("newBrowserWindow", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn { + if (method.equals("newBrowserWindow")) { + if (checkOnly) return Boolean.TRUE; if (args.length() != 1 || args.elementAt(0) == null) return null; Platform.newBrowserWindow(args.elementAt(0).toString()); return null; - }}); - super.put("parseInt",xwtString.get("parseInt")); - super.put("parseFloat",xwtString.get("parseFloat")); - - super.put("yield", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn { + } else if (method.equals("yield")) { + if (checkOnly) return Boolean.TRUE; sleep(0); return null; - }}); - super.put("load", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn { + } else if (method.equals("load")) { + if (checkOnly) return Boolean.TRUE; return Res.stringToRes(args.elementAt(0).toString()); - }}); - super.put("println", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn { + } else if (method.equals("println")) { + if (checkOnly) return Boolean.TRUE; if (args.length() != 1) return null; if (Log.on) Log.logJS(this, (args.elementAt(0) == null ? "**null**" : args.elementAt(0).toString())); return null; - }}); - super.put("date", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn { + } else if (method.equals("date")) { + if (checkOnly) return Boolean.TRUE; + // FIXME Log.log(XWT.class, "date not implemented"); - //throw new Error("not implemented"); return null; - }}); - super.put("regexp", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn { + } else if (method.equals("regexp")) { + if (checkOnly) return Boolean.TRUE; return new Regexp(args); - }}); - - super.put("listfonts", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn { - Object[] fonts = Platform.listFonts(); - JS.Array ret = new JS.Array(); - for(int i=0; i 2) return null; - if (args.elementAt(0) == null || (args.length() == 2 && args.elementAt(1) == null)) return null; - String font = args.length() == 1 ? Platform.getDefaultFont() : args.elementAt(0).toString(); - String text = args.length() == 1 ? args.elementAt(0).toString() : args.elementAt(1).toString(); - return new Integer(Platform.stringWidth(font, text)); - }}); + } else if (method.equals("newBox")) { + if (checkOnly) return Boolean.TRUE; + return new Box(); - super.put("textheight", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn { - if (args.length() > 1) return null; - if (args.length() == 1 && args.elementAt(0) == null) return null; - String font = args.length() == 0 || args.elementAt(0) == null ? Platform.getDefaultFont() : args.elementAt(0).toString(); - return new Integer(Platform.getMaxAscent(font) + Platform.getMaxDescent(font)); - }}); - - super.put("newBox", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn { - if (args.length() > 0) Log.log(XWT.class, "DEPRECATED: xwt.newBox() with multiple arguments is deprecated; use xwt.newBox().apply()"); - JS.Callable callback = null; - for(int i=1; i 1 && args.elementAt(1) instanceof JS.Callable ? (JS.Callable)args.elementAt(1) : null); - return null; - }}); } private static void recurse(String indent, String name, Object o) { @@ -322,7 +223,6 @@ public final class XWT extends JS.Obj { } } - public static void sleep(int i) { java.lang.Thread thread = java.lang.Thread.currentThread(); if (!(thread instanceof ThreadMessage)) { @@ -331,7 +231,7 @@ public final class XWT extends JS.Obj { ThreadMessage mythread = (ThreadMessage)thread; mythread.done.release(); if (i > 0) try { java.lang.Thread.sleep(i); } catch (Exception e) { } - MessageQueue.add(mythread); + Message.Q.add(mythread); mythread.go.block(); } } diff --git a/src/org/xwt/js/CompiledFunctionImpl.java b/src/org/xwt/js/CompiledFunctionImpl.java index 83b9b75..9fe5435 100644 --- a/src/org/xwt/js/CompiledFunctionImpl.java +++ b/src/org/xwt/js/CompiledFunctionImpl.java @@ -6,7 +6,7 @@ import java.io.*; // FIXME: could use some cleaning up /** a JavaScript function, compiled into bytecode */ -class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens { +class CompiledFunctionImpl extends JS.Callable implements ByteCodes, Tokens { // Fields and Accessors /////////////////////////////////////////////// diff --git a/src/org/xwt/js/JS.java b/src/org/xwt/js/JS.java index 5104bce..ea12dfb 100644 --- a/src/org/xwt/js/JS.java +++ b/src/org/xwt/js/JS.java @@ -101,18 +101,23 @@ public abstract class JS { /** A sensible implementation of the abstract methods in the JS class */ public static class Obj extends JS { - private Hash entries = new Hash(); + private Hash entries = null; private boolean sealed = false; public Obj() { this(false); } public Obj(boolean sealed) { this.sealed = sealed; } - /** a sealed object cannot have its properties modified */ - public void setSeal(boolean sealed) { this.sealed = sealed; } - public void put(Object key, Object val) { if (!sealed) entries.put(key, val); } - public Object[] keys() { return(entries.keys()); } - public Object get(Object key) { - if(callMethod((String)key,null,true) == Boolean.TRUE) - return new Internal.CallableStub(this,key); - return entries.get(key); + public void setSeal(boolean sealed) { this.sealed = sealed; } ///< a sealed object cannot have its properties modified + public void put(Object key, Object val) { put(key, null, val); } + protected void put(Object key, Object key2, Object val) { + if (sealed) return; + if (entries == null) entries = new Hash(); + entries.put(key, key2, val); } + public Object[] keys() { return entries == null ? new Object[0] : entries.keys(); } + public Object get(Object key) { return get(key, null); } + protected Object get(Object key, Object key2) { + if (entries == null) return null; + if(key2 == null && callMethod((String)key, null, true) == Boolean.TRUE) + return new Internal.CallableStub(this, key); + return entries.get(key, key2); } } diff --git a/src/org/xwt/plat/AWT.java b/src/org/xwt/plat/AWT.java index c7888a0..6850927 100644 --- a/src/org/xwt/plat/AWT.java +++ b/src/org/xwt/plat/AWT.java @@ -20,9 +20,6 @@ public class AWT extends JVM { protected int _getScreenWidth() { return Toolkit.getDefaultToolkit().getScreenSize().width; } protected int _getScreenHeight() { return Toolkit.getDefaultToolkit().getScreenSize().height; } protected Surface _createSurface(Box b, boolean framed) { return new AWTSurface(b, framed); } - protected int _stringWidth(String font, String text) { return getFont(font).metrics.stringWidth(text); } - protected int _getMaxAscent(String font) { return getFont(font).metrics.getMaxAscent(); } - protected int _getMaxDescent(String font) { return getFont(font).metrics.getMaxDescent(); } protected boolean _supressDirtyOnResize() { return false; } protected void postInit() { @@ -170,13 +167,6 @@ public class AWT extends JVM { g.drawImage(((AWTPicture)source).i, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null); } - public void drawString(String font, String text, int x, int y, int argb) { - // FEATURE: use an LRU cache for Color objects - g.setColor(new Color((argb & 0x00FF0000) >> 16, (argb & 0x0000FF00) >> 8, (argb & 0x000000FF))); - g.setFont(getFont(font)); - g.drawString(text, x, y + 2); - } - public void fillRect(int x, int y, int x2, int y2, int argb) { // FEATURE: use an LRU cache for Color objects g.setColor(new Color((argb & 0x00FF0000) >> 16, (argb & 0x0000FF00) >> 8, (argb & 0x000000FF))); @@ -186,7 +176,7 @@ public class AWT extends JVM { } - protected static class AWTSurface extends Surface + protected static class AWTSurface extends Surface.DoubleBufferedSurface implements MouseListener, MouseMotionListener, KeyListener, ComponentListener, WindowListener { public void blit(PixelBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2) { @@ -210,7 +200,7 @@ public class AWT extends JVM { public void toBack() { if (window != null) window.toBack(); } public void toFront() { if (window != null) window.toFront(); } - public void setLocation(int x, int y) { window.setLocation(x, y); } + public void setLocation() { window.setLocation(root.x, root.y); } public void setTitleBarText(String s) { if (frame != null) frame.setTitle(s); } public void setIcon(Picture i) { if (frame != null) frame.setIconImage(((AWTPicture)i).i); } public void setSize(int width, int height) { window.setSize(width + (insets.left + insets.right), height + (insets.top + insets.bottom)); } @@ -408,9 +398,9 @@ public class AWT extends JVM { } } - protected ImageDecoder _decodeJPEG(InputStream is, String name) { + protected Picture _decodeJPEG(InputStream is, String name) { try { - Image i = Toolkit.getDefaultToolkit().createImage(org.xwt.Resources.isToByteArray(is)); + Image i = Toolkit.getDefaultToolkit().createImage(InputStreamToByteArray.convert(is)); MediaTracker mediatracker = new MediaTracker(new Canvas()); mediatracker.addImage(i, 1); try { mediatracker.waitForAll(); } catch (InterruptedException e) { } @@ -424,59 +414,11 @@ public class AWT extends JVM { Log.log(this, "PixelGrabber reported an error while decoding JPEG image " + name); return null; } - return new ImageDecoder() { - public int getWidth() { return width; } - public int getHeight() { return height; } - public int[] getData() { return data; } - }; + return Platform.createPicture(data, width, height); } catch (Exception e) { Log.log(this, "Exception caught while decoding JPEG image " + name); Log.log(this, e); return null; } } - - // Font Handling Stuff ////////////////////////////////////////////////////////// - - protected String[] _listFonts() { return fontList; } - private static String[] fontList; - static { - /* - String[] awtfonts = Toolkit.getDefaultToolkit().getFontList(); - fontList = new String[awtfonts.length * 4]; - for(int i=0; i