// RULE: coordinates on non-static methods are ALWAYS relative to the
// upper-left hand corner of <tt>this</tt>
-// 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
// Misc instance data ////////////////////////////////////////////////////////////////
- private static int sizePosChangesSinceLastRender = 0;
+ static int sizePosChangesSinceLastRender = 0;
// Misc instance data ////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////////////
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
/** 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);
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);
}
/**
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;
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)
}
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) {
} 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();
}
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;
}
}
+ 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) {
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
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;
}
* @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;
}
- // 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<b) return a; else return b; }
MARK_FOR_REFLOW_b;
} });
+ //FIXME
specialBoxProperties.put("static", new SpecialBoxProperty() {
- public Object get(Box b) {
- String cfsn =
- JS.Thread.fromJavaThread(java.lang.Thread.currentThread()).getCurrentCompiledFunction().getSourceName();
- for(int i=0; i<cfsn.length() - 1; i++)
- if (cfsn.charAt(i) == '.' && (cfsn.charAt(i+1) == '_' || Character.isDigit(cfsn.charAt(i+1)))) {
- cfsn = cfsn.substring(0, i);
- break;
- }
- return Static.getStatic(cfsn);
- }
});
specialBoxProperties.put("shrink", new SpecialBoxProperty() {
if (x == b.x) return;
b.dirty();
b.x = x;
- if (b.parent == null && b.surface != null) {
- b.surface.setLocation();
- b.surface.centerSurfaceOnRender = false;
- }
+ if (b.parent == null && b.surface != null) b.surface.setLocation();
MARK_FOR_REFLOW_b;
b.dirty();
}
} });
specialBoxProperties.put("image", new SpecialBoxProperty() {
+ // FIXME
+ /*
public Object get(Box b) { return b.image == null ? null : ImageDecoder.imageToNameMap.get(b.image); }
public void put(Box b, Object value) {
if ((value == null && b.image == null) ||
}
b.dirty();
}
+ */
});
//#repeat globalx/globaly x/y
}
});
- //#repeat hscar/vscar
- specialBoxProperties.put("hscar", new SpecialBoxProperty() {
- public void put(Box b, Object value) {
- if (b.parent == null && b.surface != null) {
- b.surface.hscar = stoi(value);
- b.surface.dirty(0, 0, b.width, b.height);
- b.surface.Refresh();
- }
- }
- });
- //#end
-
specialBoxProperties.put("Close", new SpecialBoxProperty() {
public void put(Box b, Object value) {
if (b.parent == null && b.surface != null) b.surface.dispose(true);
});
specialBoxProperties.put("icon", new SpecialBoxProperty() {
+ // FIXME
+ /*
public void put(Box b, Object value) {
b.put_("icon", value);
if (b.surface == null) return;
else if (Log.on) Log.log(this, "unable to load icon " + value);
}
public Object get(Box b) { return b.get_("icon"); }
+ */
});
}
}
package org.xwt;
import org.xwt.translators.*;
import org.xwt.util.*;
+import org.xwt.js.*;
public class Glyph {
public char c;
if (ret != null) return ret;
// FEATURE: be smarter here
- if (c < 256)
- Font.renderGlyphs(res, pointsize, 0, 255, glyphCache);
- else
- Font.renderGlyphs(res, pointsize, (int)c, (int)c, glyphCache);
+ if (c < 256) Font.renderGlyphs(res, pointsize, 0, 255, glyphCache);
+ else Font.renderGlyphs(res, pointsize, (int)c, (int)c, glyphCache);
ret = (Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize));
if (ret != null) return ret;
- throw new RuntimeException("renderGlyphs didn't create the glyph we wanted");
+ throw new JS.Exn("error rendering glyph " + c);
}
}
if (authorization != oldAuth) return;
if (Log.on) Log.log(Authorization.class, "displaying proxy authorization dialog");
- MessageQueue.add(new Message() {
+ Message.Q.add(new Message() {
public void perform() {
Box b = new Box();
+ /* FIXME
Template.getTemplate("org.xwt.builtin.proxy_authorization", null).apply(b, null, null, null, 0, 0, null);
b.put("realm", realm);
b.put("proxyIP", proxyIP);
+ */
}
});
+++ /dev/null
-// 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.*;
-
-/** Interface implemented by classes capable of decoding an image file into an int[] */
-public abstract class ImageDecoder {
-
- /** returns the width of the image */
- public abstract int getWidth();
-
- /** returns the height of the image */
- public abstract int getHeight();
-
- /** returns the data of the image, as an array of 32-bit AARRGGBB samples */
- public abstract int[] getData();
-
- /** loads the image described by string str, possibly blocking for a network load */
- public static ImageDecoder getImageDecoder(String str, final JS.Callable callback) {
-
- if (str.indexOf(':') == -1) {
- String s = str;
- byte[] b = Resources.getResource(Resources.resolve(s + ".png", null));
- if (b != null) return PNG.decode(new ByteArrayInputStream(b), str);
- b = Resources.getResource(Resources.resolve(s + ".jpeg", null));
- if (b != null) return Platform.decodeJPEG(new ByteArrayInputStream(b), str);
- return null;
-
- } else {
- java.lang.Thread thread = java.lang.Thread.currentThread();
- if (!(thread instanceof ThreadMessage)) {
- if (Log.on) Log.log(Box.class, "HTTP images can not be loaded from the foreground thread");
- return null;
- }
- // FIXME: use primitives here
- ThreadMessage mythread = (ThreadMessage)thread;
- mythread.setPriority(java.lang.Thread.MIN_PRIORITY);
- mythread.done.release();
- try {
- HTTP http = new HTTP(str);
- final HTTP.HTTPInputStream in = http.GET();
- final int contentLength = in.getContentLength();
- InputStream is = new FilterInputStream(in) {
- int bytesDownloaded = 0;
- boolean clear = true;
- public int read() throws IOException {
- bytesDownloaded++;
- return super.read();
- }
- public int read(byte[] b, int off, int len) throws IOException {
- int ret = super.read(b, off, len);
- if (ret != -1) bytesDownloaded += ret;
- if (clear && callback != null) {
- clear = false;
- ThreadMessage.newthread(new JS.Callable() {
- public Object call(JS.Array args_) throws JS.Exn {
- try {
- JS.Array args = new JS.Array();
- args.addElement(new Double(bytesDownloaded));
- args.addElement(new Double(contentLength));
- callback.call(args);
- } finally {
- clear = true;
- }
- return null;
- }
- });
- }
- return ret;
- }
- };
-
- if (str.endsWith(".gif")) return GIF.decode(is, str);
- else if (str.endsWith(".jpeg") || str.endsWith(".jpg")) return Platform.decodeJPEG(is, str);
- else return PNG.decode(is, str);
-
- } catch (IOException e) {
- if (Log.on) Log.log(Box.class, "error while trying to load an image from " + str);
- if (Log.on) Log.log(Box.class, e);
- return null;
-
- } finally {
- MessageQueue.add(mythread);
- mythread.setPriority(java.lang.Thread.NORM_PRIORITY);
- mythread.go.block();
- }
- }
- }
-
- /** gets an Image using getImage(), adds it to the cache, and creates a Picture from it */
- public static Picture getPicture(String os) {
- Picture ret = null;
- ret = (Picture)pictureCache.get(os);
- if (ret != null) return ret;
- ImageDecoder id = ImageDecoder.getImageDecoder(os, null);
- if (id == null) return null;
- ret = Platform.createPicture(id);
- pictureCache.put(os, ret);
- imageToNameMap.put(ret, os);
- return ret;
- }
-
- /** caches images, keyed on resource name or url */
- public static Hash pictureCache = new Hash();
-
- /** stores image names, keyed on image object */
- static Hash imageToNameMap = new Hash();
-
-}
else break;
startargs++;
}
+ /* FIXME
final String instancename = args.length > startargs + 1 ? args[startargs + 1] : "main";
Platform.forceLoad();
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");
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");
//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);
// 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 <i>is</i> 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<Math.max(1, size); i++) {
+ Message e = (Message)events.remove();
+
+ // if there are non-ThreadMessage events, perform them first
+ // we check against Thread instead of ThreadMessage so we don't get link failures in the Shoehorn
+ if (!(e instanceof Thread)) nonThreadEventsInQueue--;
+ else if (nonThreadEventsInQueue > 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<Surface.allSurfaces.size(); i++)
+ ((Surface)Surface.allSurfaces.elementAt(i)).render();
+ working = false;
+
+ } catch (Throwable t) {
+ if (Log.on) Log.log(this, "caught throwable in Q.run(); this should never happen");
+ if (Log.on) Log.log(this, " currentlyPerforming == " + currentlyPerforming);
+ if (Log.on) Log.log(this, " working == " + working);
+ // FIXME - this currently calls compiledfunction.toString which gives more info than we need
+ if (Log.on) Log.log(this, t);
+ if (Log.on) Log.log(this, "resuming Q loop");
+ }
+ }
+ }
+
+ /** Adds an event to the queue */
+ public static void add(Message e) {
+ // Even though we don't synchronize around these two statements, it is not a race condition. In the worst case,
+ // nonThreadEventsInQueue undercounts -- it never overcounts.
+ events.append(e);
+ if (!(e instanceof Thread)) nonThreadEventsInQueue++;
+ }
+
+ /** a simple thread that logs a warning if too much time is spent in any given message -- helpful for debugging infinite loops */
+ private static class Watcher extends Thread {
+ long t = System.currentTimeMillis();
+ Message m = null;
+ public Watcher() { start(); }
+ public void run() {
+ while(true) {
+ if ((m != null && m == Q.currentlyPerforming) || Q.working) {
+ String what, where;
+ if (m != null && m instanceof ThreadMessage) {
+ where = org.xwt.js.JS.Thread.fromJavaThread((ThreadMessage)m).getSourceName();
+ what = "background thread";
+ } else if (m != null) {
+ where = org.xwt.js.JS.Thread.fromJavaThread(Q.singleton).getSourceName();
+ what = "event trap";
+ } else {
+ where = org.xwt.js.JS.Thread.fromJavaThread(Q.singleton).getSourceName();
+ what = "script";
+ }
+ long howlong = (System.currentTimeMillis() - t) / 1000;
+ if (howlong >= 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) { }
+ }
+ }
+ }
+
+ }
+
}
+++ /dev/null
-// 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 <i>is</i> 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<Math.max(1, size); i++) {
- Message e = (Message)events.remove();
-
- // if there are non-ThreadMessage events, perform them first
- // we check against Thread instead of ThreadMessage so we don't get link failures in the Shoehorn
- if (!(e instanceof Thread)) nonThreadEventsInQueue--;
- else if (nonThreadEventsInQueue > 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<Surface.allSurfaces.size(); i++)
- ((Surface)Surface.allSurfaces.elementAt(i)).render();
- working = false;
-
- } catch (Throwable t) {
- if (Log.on) Log.log(this, "caught throwable in MessageQueue.run(); this should never happen");
- if (Log.on) Log.log(this, " currentlyPerforming == " + currentlyPerforming);
- if (Log.on) Log.log(this, " working == " + working);
- // FIXME - this currently calls compiledfunction.toString which gives more info than we need
- // if (Log.on) Log.log(this, " lastfunc == " + lastfunc.getDescription());
- if (Log.on) Log.log(this, " lastmessage == " + lastmessage);
- if (Log.on) Log.log(this, t);
- if (Log.on) Log.log(this, "resuming MessageQueue loop");
- }
- }
- }
-
- /** Adds an event to the queue */
- public static void add(Message e) {
-
- // Even though we don't synchronize around these two
- // statements, it is not a race condition. In the worst case,
- // nonThreadEventsInQueue undercounts -- it never
- // overcounts.
-
- events.append(e);
- if (!(e instanceof Thread)) nonThreadEventsInQueue++;
- }
-
- /** a simple thread that logs a warning if too much time is spent in any given message -- helpful for debugging infinite loops */
- private static class MessageQueueWatcher extends Thread {
- long t = System.currentTimeMillis();
- Message m = null;
- public MessageQueueWatcher() { start(); }
- public void run() {
- while(true) {
- if ((m != null && m == MessageQueue.currentlyPerforming) || MessageQueue.working) {
- String what, where;
- if (m != null && m instanceof ThreadMessage) {
- where = org.xwt.js.JS.Thread.fromJavaThread((ThreadMessage)m).getSourceName();
- what = "background thread";
- } else if (m != null) {
- where = org.xwt.js.JS.Thread.fromJavaThread(MessageQueue.singleton).getSourceName();
- what = "event trap";
- } else {
- where = org.xwt.js.JS.Thread.fromJavaThread(MessageQueue.singleton).getSourceName();
- what = "script";
- }
- long howlong = (System.currentTimeMillis() - t) / 1000;
- if (howlong >= 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) { }
- }
- }
- }
-
-}
-
-
-
// 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.*;
/**
* <p>
* </p>
*/
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();
+
}
/**
* <p>
* 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.
* </p>
*
* <p>
* method. These implementations may choose to use off-screen video
* ram for this purpose (for example, a Pixmap on X11).
* </p>
- *
- * <p>
- * 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.
- * </p>
*/
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 <tt>text</tt> in <tt>font</tt> and <tt>color</tt> 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 <tt>color</tt> (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();
+
}
/** creates and returns a doublebuffer 'belonging' to <tt>owner</tt>; 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();
}
/** 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 <tt>owner</tt> */
- 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 {
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:");
}
/** 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;
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();
}
/** detects proxy settings */
+ protected synchronized HTTP.Proxy _detectProxy() { return null; }
public static synchronized HTTP.Proxy detectProxy() {
if (cachedProxyInfo != null) return cachedProxyInfo;
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++;
- }
- }
- }
-
- }
-
}
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;
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)));
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 */
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);
}
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' */
+++ /dev/null
-// 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 <tt>name</tt> 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<name.length(); i++) {
- char c = name.charAt(i);
- if (!((c >= '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; i<subfiles.length; i++) {
- if (subfiles[i].equals("CVS") || !validResourceName(subfiles[i])) continue;
- String name = prefix + subfiles[i];
- File file = new File(dir.getPath() + File.separatorChar + subfiles[i]);
- if (file.isDirectory()) {
- loadDirectory(file, name + File.separatorChar);
- } else {
- if (name.endsWith(".xwt")) {
- String name2 = name.substring(0, name.length() - 4);
- Static.createStatic(name2.replace(File.separatorChar, '.'), false);
- }
- bytes.put(name.replace(File.separatorChar, '.'), file);
- }
- }
- }
-
- /** Load an archive from an inputstream. */
- public static synchronized void loadArchive(InputStream is) throws IOException { loadArchive(is, 0, null); }
- public static synchronized void loadArchive(InputStream is, final int length, final JS.Callable callback) throws IOException {
-
- // random placeholder
- Object thisArchive = new Object();
-
- ZipInputStream zis = new ZipInputStream(new FilterInputStream(is) {
- int bytesDownloaded = 0;
- boolean clear = true;
- public int read() throws IOException {
- bytesDownloaded++;
- return super.read();
- }
- public int read(byte[] b, int off, int len) throws IOException {
- int ret = super.read(b, off, len);
- if (clear && callback != null) {
- clear = false;
- ThreadMessage.newthread(new JS.Callable() {
- public Object call(JS.Array args_) throws JS.Exn {
- try {
- JS.Array args = new JS.Array();
- args.addElement(new Double(bytesDownloaded));
- args.addElement(new Double(length));
- callback.call(args);
- } finally {
- clear = true;
- }
- return null;
- }
- });
- }
- bytesDownloaded += ret;
- return ret;
- }
- });
-
- Template.TemplateHelper t = new Template.TemplateHelper();
-
- for(ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry()) {
- String name = ze.getName();
- if (!validResourceName(name.substring(name.lastIndexOf('/') + 1))) {
- if (Log.on) Log.log(Resources.class, "WARNING: ignoring xwar entry with invalid name: " + name);
- continue;
- }
-
- if (name.endsWith(".xwt")) {
- // placeholder so resolveResource() works properly
- bytes.put(name.replace('/', '.'), new byte[] { });
- name = name.substring(0, name.length() - 4);
- Static.createStatic(name.replace('/', '.'), false);
- Template.buildTemplate(zis, name.replace('/', '.'), t);
-
- } else {
- bytes.put(name.replace('/', '.'), isToByteArray(zis));
- }
- }
- if (Log.verbose) Log.log(Resources.class, "done loading archive");
- }
-
- /** holds the current theme mappings */
- static Vector mapFrom = new Vector();
-
- /** holds the current theme mappings */
- static Vector mapTo = new Vector();
- static {
- mapFrom.addElement("xwt.standard");
- mapTo.addElement("org.xwt.themes.monopoly");
- }
-
- /**
- * Resolves the partial resource name <tt>name</tt> to a fully
- * resolved resource name, using <tt>importlist</tt> 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;
- }
-}
-
-
-
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())));
sb.append(((Boolean)o).booleanValue() ? "true" : "false");
sb.append("</" + name + ">\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);
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;
+++ /dev/null
-// 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); }
-
-}
* 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 <i>actual</i> cursor for this surface to the cursor referenced by <tt>cursor</tt> */
- public abstract void syncCursor();
-
- /** If <tt>b == true</tt>, make the window invisible; otherwise, make it non-invisible. */
- public abstract void setInvisible(boolean b);
-
- /** If <tt>b == true</tt>, maximize the surface; otherwise, un-maximize it. */
- protected abstract void _setMaximized(boolean b);
-
- /** If <tt>b == true</tt>, 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 <i>actual</i> cursor for this surface to the cursor referenced by <tt>cursor</tt> */
+ public abstract void setInvisible(boolean b); /**< If <tt>b</tt>, make window invisible; otherwise, make it non-invisible. */
+ protected abstract void _setMaximized(boolean b); /**< If <tt>b</tt>, maximize the surface; otherwise, un-maximize it. */
+ protected abstract void _setMinimized(boolean b); /**< If <tt>b</tt>, 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) { }
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;
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
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; i<keywatchers.size(); i++) {
Box b = (Box)keywatchers.elementAt(i);
for(Box cur = b; cur != null; cur = cur.getParent())
if ((cur.flags & cur.INVISIBLE_FLAG) != 0) continue outer;
b.put("KeyPressed", key);
}
+ */
Platform.clipboardReadEnabled = false;
}
}
if (key.toLowerCase().equals("alt")) alt = false;
else if (key.toLowerCase().equals("control")) control = false;
else if (key.toLowerCase().equals("shift")) shift = false;
- MessageQueue.add(new Message() { public void perform() {
+ Message.Q.add(new Message() { public void perform() {
+ /* FIXME
outer: for(int i=0; i<keywatchers.size(); i++) {
Box b = (Box)keywatchers.elementAt(i);
for(Box cur = b; cur != null; cur = cur.getParent())
if ((cur.flags & cur.INVISIBLE_FLAG) != 0) continue outer;
b.put("KeyReleased", key);
}
+ */
}});
}
* message), the subclass should use (-1,-1).
*/
protected final void Move(final int newmousex, final int newmousey) {
- MessageQueue.add(lastMoveMessage = new Message() { public void perform() {
+ Message.Q.add(lastMoveMessage = new Message() { public void perform() {
synchronized(Surface.this) {
// if move messages are arriving faster than we can process them, we just start ignoring them
}
protected final void SizeChange(final int width, final int height) {
- MessageQueue.add(new Message() { public void perform() {
+ Message.Q.add(new Message() { public void perform() {
if (width == root.width && height == root.height) return;
root.width = width;
root.height = height;
}
protected final void PosChange(final int x, final int y) {
- MessageQueue.add(new Message() { public void perform() {
+ Message.Q.add(new Message() { public void perform() {
root.put("x", new Integer(x));
root.put("y", new Integer(y));
}});
protected final void Minimized(boolean b) { minimized = b; new SimpleMessage("Minimized", b ? Boolean.TRUE : Boolean.FALSE, root); }
protected final void Maximized(boolean b) { maximized = b; new SimpleMessage("Maximized", b ? Boolean.TRUE : Boolean.FALSE, root); }
protected final void Focused(boolean b) { new SimpleMessage("Focused", b ? Boolean.TRUE : Boolean.FALSE, root); }
- public static void Refresh() { MessageQueue.refresh(); }
-
- // the following value is split into two int's to work around GCJ bug java/6393
-
- /** This is how subclasses signal a 'shallow dirty', indicating that although the backbuffer is valid, the screen is not */
- public final void Dirty(int x, int y, int w, int h) {
- screenDirtyRegions.dirty(x, y, w, h);
- Refresh();
- }
-
-
- // Private Instance Data /////////////////////////////////////////////////////////////////////////////////////////////
-
- /** The automatic double buffer for the root box */
- PixelBuffer backbuffer = null;
-
- /** Dirty regions on the backbuffer which need to be rebuilt using Box.render() */
- private DirtyList backbufferDirtyRegions = new DirtyList();
-
- /** Dirty regions on the screen which need to be rebuilt using Surface.blit() */
- private DirtyList screenDirtyRegions = new DirtyList();
-
- /** A list of all the Boxes on this Surface that should be notified of keyboard events */
- Vec keywatchers = new Vec();
-
- /** When set to true, render() should abort as soon as possible and restart the rendering process */
- static volatile boolean abort = false;
-
- /** a solid red 10x10 double buffer */
- private PixelBuffer showRenderBuf = null;
-
- /** a striped 100x100 double buffer */
- private PixelBuffer showRenderBuf2 = null;
-
- /** true iff this window should be scarred */
- private boolean scarred = true;
+ public static void Refresh() { Message.Q.refresh(); }
// Other Methods ///////////////////////////////////////////////////////////////////////////////
- /** If <tt>b == true</tt>, maximize the surface; otherwise, un-maximize it. */
- public final void setMaximized(boolean b) {
- if (b == maximized) return;
- _setMaximized(b);
- maximized = b;
- }
-
- /** If <tt>b == true</tt>, 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);
}
// 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);
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();
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;
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)
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<x + w; x1 += 100)
- for(int y1 = y; y1< y + h; y1 += 100) {
- blit(showRenderBuf2, 0, 0, x1, y1, Math.min(x1 + 100, x + w), Math.min(y1 + 100, y + h));
- }
- for(int j=x; j<x + w; j += 10) {
- blit(showRenderBuf, 0, 0, j, y, Math.min(j+ 10, x + w), y + 1);
- blit(showRenderBuf, 0, 0, j, y + h, Math.min(j + 10, x + w), y + h + 1);
- }
- for(int j=y; j<y + h; j += 10) {
- blit(showRenderBuf, 0, 0, x, j, x + 1, Math.min(j + 10, y + h));
- blit(showRenderBuf, 0, 0, x + w, j, x + w + 1, Math.min(j + 10, y + h));
- }
- }
-
- }
}
// FEATURE: reinstate recycler
this.boxContainingMouse = boxContainingMouse;
this.name = name;
this.value = value;
- MessageQueue.add(this);
+ Message.Q.add(this);
}
public void perform() { boxContainingMouse.put(name, value); }
public String toString() { return "SimpleMessage [name=" + name + ", value=" + value + "]"; }
-
+
}
+ /** Dirty regions on the backbuffer which need to be rebuilt using Box.render() */
+ private DirtyList backbufferDirtyRegions = new DirtyList();
+
// Scar-Related Stuff ////////////////////////////////////////////////////////////////////
- /** The scar's horizontal offset */
- int hscar = 0;
-
- /** The scar's vertical offset */
- int vscar = 0;
-
/** the scar image drawn on the bottom right hand corner */
static Picture scarPicture = null;
+
+ // Default PixelBuffer implementation /////////////////////////////////////////////////////////
+
+ public static abstract class DoubleBufferedSurface extends Surface {
+
+ public DoubleBufferedSurface(Box root) {
+ super(root);
+
+ // 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);
+ }
+
+ /** The automatic double buffer for the root box */
+ PixelBuffer backbuffer = null;
+
+ public void drawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2) {
+ backbuffer.drawPicture(source, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2);
+ }
+
+ public void fillRect(int x1, int y1, int x2, int y2, int color) {
+ backbuffer.fillRect(x1, y1, x2, y2, color);
+ }
+
+ /** This is how subclasses signal a 'shallow dirty', indicating that although the backbuffer is valid, the screen is not */
+ public final void Dirty(int x, int y, int w, int h) {
+ screenDirtyRegions.dirty(x, y, w, h);
+ Refresh();
+ }
+
+ /** 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);
+
+
+ /** 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);
+
+ }
+
+ }
+ }
+
+ public static final int hscar = 0;
+ public static final int vscar = 0;
+
}
/**
* Encapsulates a template node (the <template/> element of a
- * .xwt file, or any child element thereof). Each instance of
- * Template has a <tt>nodeName</tt> -- 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
* 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;
/** 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 <tt>id</tt> 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;
/** 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();
/** 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;
}
// 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 && i<preapply.length; i++) numunits += preapply[i].numUnits();
+ for(int i=0; postapply != null && i<postapply.length; i++) numunits += postapply[i].numUnits();
if (script != null) numunits += 10;
numunits += keys == null ? 0 : keys.length;
for(int i=0; children != null && i<children.length; i++) numunits += children[i].numUnits();
return numunits;
}
+
+ /** called before this template is applied or its static object can be externally referenced */
+ JS.Scope getStatic() {
+ if (staticScope == null) staticScope = new JS.Scope(null);
+ if (staticscript == null) return staticScope;
+ JS.CompiledFunction temp = staticscript;
+ staticscript = null;
+ temp.call(new JS.Array(), staticScope);
+ return staticScope;
+ }
/** Applies the template to Box b
* @param pboxes a vector of all box parents on which to put $-references
- * @param ptemplates a vector of the nodeNames to recieve private references on the pboxes
+ * @param ptemplates a vector of the fileNames to recieve private references on the pboxes
*/
- void apply(Box b, Vec pboxes, Vec ptemplates, JS.Callable callback, int numerator, int denominator, Res resourceRoot) {
+ // FIXME: $-vars not dealt with
+ void apply(Box b, JS.Callable callback, int numerator, int denominator, Res resourceRoot) {
+ getStatic();
int original_numerator = numerator;
- if (pboxes == null) {
- pboxes = new Vec();
- ptemplates = new Vec();
- }
-
- if (id != null && !id.equals(""))
- for(int i=0; i<pboxes.size(); i++) {
- Box parent = (Box)pboxes.elementAt(i);
- String parentNodeName = (String)ptemplates.elementAt(i);
- parent.put("$" + id, b);
- }
-
- if (script != null || (redirect != null && !"self".equals(redirect))) {
- pboxes.addElement(b);
- ptemplates.addElement(nodeName);
+ for(int i=0; preapply != null && i<preapply.length; i++) {
+ preapply[i].apply(b, callback, numerator, denominator, resourceRoot);
+ numerator += preapply[i].numUnits();
}
- int numids = pboxes.size();
-
- link();
-
- for(int i=0; _preapply != null && i<_preapply.length; i++)
- if (_preapply[i] != null) {
- _preapply[i].apply(b, null, null, callback, numerator, denominator, resourceRoot);
- numerator += _preapply[i].numUnits();
- }
-
for (int i=0; children != null && i<children.length; i++) {
- Box newkid = new Box();
- children[i].apply(newkid, pboxes, ptemplates, callback, numerator, denominator, resourceRoot);
- b.put(Integer.MAX_VALUE, newkid);
+ children[i].apply(new Box(), callback, numerator, denominator, resourceRoot);
numerator += children[i].numUnits();
}
// whom to redirect to; doesn't take effect until after script runs
- Box redir = null;
- if (redirect != null && !"self".equals(redirect)) redir = (Box)b.get("$" + redirect);
+ Box redir = (redirect != null && !"self".equals(redirect)) ? (Box)b.get("$" + redirect) : null;
- if (script != null) try {
- script.call(new JS.Array(), new PerInstantiationScope(b, resourceRoot));
- } catch (JS.Exn e) {
- if (Log.on) Log.log(this, "WARNING: uncaught ecmascript exception: " + e.getMessage());
- }
+ if (script != null) script.call(new JS.Array(), new PerInstantiationScope(b, resourceRoot));
- for(int i=0; keys != null && i<keys.length; i++) {
- try {
- if (keys[i] == null) { }
- else if (keys[i].equals("border") || keys[i].equals("image") &&
- !vals[i].toString().startsWith("http://") && !vals[i].toString().startsWith("https://")) {
- String s = Resources.resolve(vals[i].toString() + ".png", importlist);
- if (s != null) b.put(keys[i], s.substring(0, s.length() - 4));
- else if (Log.on) Log.log(this, "unable to resolve image " + vals[i].toString() + " referenced in attributes of " + nodeName);
- }
- else b.put(keys[i], vals[i]);
- } catch(JS.Exn e) {
- if(Log.on) Log.log(this,"WARNING: uncaught ecmascript exception while putting attr \"" + keys[i] +
- "\" of " + nodeName + " : " + e.getMessage());
- }
- }
+ for(int i=0; keys != null && i<keys.length; i++) b.put(keys[i], vals[i]);
if (redirect != null && !"self".equals(redirect)) b.redirect = redir;
- for(int i=0; _postapply != null && i<_postapply.length; i++)
- if (_postapply[i] != null) {
- _postapply[i].apply(b, null, null, callback, numerator, denominator, resourceRoot);
- numerator += _postapply[i].numUnits();
- }
-
- pboxes.setSize(numids);
- ptemplates.setSize(numids);
-
- numerator = original_numerator + numUnits();
-
- if (callback != null)
- try {
- JS.Array args = new JS.Array();
- args.addElement(new Double(numerator));
- args.addElement(new Double(denominator));
- callback.call(args);
- } catch (JS.Exn e) {
- if (Log.on) Log.log(this, "WARNING: uncaught ecmascript exception: " + e);
- }
-
- if (Thread.currentThread() instanceof ThreadMessage) try {
- XWT.sleep(0);
- } catch (JS.Exn e) {
- if (Log.on) Log.log(this, "WARNING: uncaught ecmascript exception: " + e);
+ for(int i=0; postapply != null && i<postapply.length; i++) {
+ postapply[i].apply(b, callback, numerator, denominator, resourceRoot);
+ numerator += postapply[i].numUnits();
}
- }
+ numerator = original_numerator + numUnits();
- // Theming Logic ////////////////////////////////////////////////////////////
+ if (callback != null) try {
+ JS.Array args = new JS.Array();
+ args.addElement(new Double(numerator));
+ args.addElement(new Double(denominator));
+ callback.call(args);
+ } catch (JS.Exn e) { if (Log.on) Log.log(this, "WARNING: uncaught ecmascript exception: " + e); }
- /** helper method to recursively gather up the list of keys to be preserved */
- private void gatherPreserves(Vec v) {
- for(int i=0; preserve != null && i<preserve.length; i++) v.addElement(preserve[i]);
- for(int i=0; _preapply != null && i<_preapply.length; i++) if (_preapply[i] != null) _preapply[i].gatherPreserves(v);
- for(int i=0; _postapply != null && i<_postapply.length; i++) if (_postapply[i] != null) _postapply[i].gatherPreserves(v);
+ if (Thread.currentThread() instanceof ThreadMessage) XWT.sleep(0);
}
- /** runs statics, resolves string references to other templates into actual Template instance references, and sets <tt>change</tt> 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<children.length; i++) children[i].link(force);
- }
// XML Parsing /////////////////////////////////////////////////////////////////
nameOfHeaderNodeBeingProcessed = null;
nodeStack.setSize(0);
- importlist.setSize(0);
preapply.setSize(0);
postapply.setSize(0);
- importlist.fromArray(defaultImportList);
-
t = root;
parse(new InputStreamReader(is));
}
/** stack of Templates whose XML elements we have seen open-tags for but not close-tags */
Vec nodeStack = new Vec();
- /** builds up the list of imports */
- Vec importlist = new Vec();
-
/** builds up the list of preapplies */
Vec preapply = new Vec();
throw new XML.SchemaException("<import> 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")) {
staticNodeHasBeenEncountered = true;
return;
- } else if (c.localName.equals("preserve")) {
- if (c.len != 1 || !c.keys[0].equals("attributes"))
- throw new XML.SchemaException("<preserve> node must have exactly one attribute, which must be called 'attributes'");
- if (t.preserve != null)
- throw new XML.SchemaException("<preserve> 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<t.preserve.length; i++) t.preserve[i] = tok.nextToken();
- return;
-
} else if (c.localName.equals("template")) {
// finalize importlist/preapply/postapply, since they can't change from here on
t.startLine = getLine();
- importlist.toArray(t.importlist = new String[importlist.size()]);
- if (preapply.size() > 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 {
// 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;
}
// 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);
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;
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) {
/** 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 */
}
}
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 */
/** 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();
}
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 {
}
}
- /** this is invoked in the MessageQueue thread */
+ /** this is invoked in the Message.Q thread */
public void perform() {
go.release();
done.block();
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<p.length; i++) PROHIBITED.put(p[i], Boolean.TRUE);
};
* @param f the function to place as a trap
*/
static void addTrap(Box trapee, Object name, JS.CompiledFunction f) {
- if (trapee.traps == null) trapee.traps = new Hash(10, 3);
// check if this script has already placed a trap on this property
- for(Trap t = (Trap)trapee.traps.get(name); t != null; t = t.next)
+ for(Trap t = (Trap)trapee.get(name, Trap.class); t != null; t = t.next)
if (t.f == f) return;
// actually place the trap
Trap t = new Trap();
- t.next = (Trap)trapee.traps.get(name);
- trapee.traps.put(name, t);
+ t.next = (Trap)trapee.get(name, Trap.class);
+ trapee.put(name, Trap.class, t);
t.trapee = trapee;
t.name = name;
t.f = f;
* @param f the function to remove
*/
static void delTrap(Box trapee, Object name, JS.CompiledFunction f) {
- if (trapee.traps != null) {
- Trap t = (Trap)trapee.traps.get(name);
- if (t.f == f) {
- trapee.traps.put(name, t.next);
+ Trap t = (Trap)trapee.get(name, Trap.class);
+ if (t.f == f) {
+ trapee.put(name, Trap.class, t.next);
+ return;
+ }
+ for(; t.next != null; t = t.next)
+ if (t.next.f == f) {
+ t.next = t.next.next;
return;
}
- for(; t.next != null; t = t.next)
- if (t.next.f == f) {
- t.next = t.next.next;
- return;
- }
- }
Log.logJS("warning: tried to remove a trap that had not been placed");
}
private Trap() { }
- /** the empty object, used for get-traps */
- public static JS.Array emptyargs = new JS.Array();
-
public Object perform() throws JS.Exn {
if (f.getNumFormalArgs() > 0) return cascade();
return f.call(new TrapArgs(this));
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()));
sb.append(((Boolean)o).booleanValue() ? "1" : "0");
sb.append("</boolean></value>\n");
- //FIXME
- /*
- } else if (o instanceof ByteStream) {
+ } else if (o instanceof Res) {
try {
sb.append(" <value><base64>\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);
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(" <value><string>");
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);
}
}
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 */
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);
} 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<fonts.length; i++) ret.addElement(fonts[i]);
- return ret;
- }});
- super.put("xmlrpc", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+ } else if (method.equals("xmlrpc")) {
+ if (checkOnly) return Boolean.TRUE;
if (args.length() != 1 || args.elementAt(0) == null) return null;
return new XMLRPC(args.elementAt(0).toString(), "");
- }});
- super.put("soap", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+ } else if (method.equals("soap")) {
+ if (checkOnly) return Boolean.TRUE;
if (args.length() == 1 && args.elementAt(0) != null) return new SOAP(args.elementAt(0).toString(), "", null, null);
else if (args.length() == 2 && args.elementAt(0) != null && args.elementAt(1) != null)
return new SOAP(args.elementAt(0).toString(), "", args.elementAt(1).toString(), null);
else if (args.length() == 3 && args.elementAt(0) != null && args.elementAt(1) != null && args.elementAt(2) != null)
return new SOAP(args.elementAt(0).toString(), "", args.elementAt(1).toString(), args.elementAt(2).toString());
else return null;
- }});
- super.put("textwidth", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
- if (args.length() < 1 || args.length() > 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<args.length(); i++)
- if (args.elementAt(i) instanceof JS.Callable && callback == null)
- callback = (JS.Callable)args.elementAt(i);
- Box ret = new Box();
- if (!(args.length() == 0 || args.elementAt(0) == null))
- Template.getTemplate(args.elementAt(0).toString(),
- Template.defaultImportList).apply(ret, null, null, callback, 0, 1, resourceRoot);
- for(int i=1; i<args.length(); i++)
- if (args.elementAt(i) instanceof Box)
- ret.put(ret.numChildren(), (Box)args.elementAt(i));
- for(int i=1; i<args.length(); i++)
- if (args.elementAt(i) instanceof JS && !(args.elementAt(i) instanceof Box) && !(args.elementAt(i) instanceof JS.Callable)) {
- JS s = (JS)args.elementAt(i);
- Object[] keys = s.keys();
- for(int j=0; j<keys.length; j++) ret.put(keys[j].toString(), s.get(keys[j].toString()));
- }
- return ret;
- }});
-
- super.put("sleep", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+ } else if (method.equals("sleep")) {
+ if (checkOnly) return Boolean.TRUE;
if (args != null && (args.length() != 1 || args.elementAt(0) == null)) return null;
int i = args == null ? 0 : Box.stoi(args.elementAt(0).toString());
sleep(i);
return null;
- }});
- /* FIXME
- super.put("openFile", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+ } else if (method.equals("openFile")) {
+ //FIXME
+ /*
+ if (checkOnly) return Boolean.TRUE;
if (args.length() != 1) return null;
String file = Platform.fileDialog(args.elementAt(0).toString(), false);
return file == null ? null : new ByteStream(file);
- }});
+ */
- super.put("saveFile", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+ } else if (method.equals("saveFile")) {
+ if (checkOnly) return Boolean.TRUE;
+ // FIXME
+ /*
if (args.length() != 2) return null;
if (!(args.elementAt(1) instanceof ByteStream)) return null;
String file = args.elementAt(0).toString();
if (Log.on) Log.log(ByteStream.class, e);
throw new JS.Exn("error while writing a ByteStream to a file");
}
- }});
+ */
- super.put("saveFileAs", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+ } else if (method.equals("saveFileAs")) {
+ // FIXME
+ /*
+ if (checkOnly) return Boolean.TRUE;
if (args.length() != 2) return null;
if (!(args.elementAt(1) instanceof ByteStream)) return null;
String file = args.elementAt(0).toString();
if (Log.on) Log.log(ByteStream.class, e);
throw new JS.Exn("error while writing a ByteStream to a file");
}
- }});
+ */
- super.put("utfEncode", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
- if (args == null || args.length() != 1) return null;
- return new ByteStream(args.elementAt(0).toString().getBytes());
- }});
-
- super.put("parseHTML", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+ } else if (method.equals("parseHTML")) {
+ if (checkOnly) return Boolean.TRUE;
if (args == null || args.length() != 1 || args.elementAt(0) == null) return null;
try {
- if (args.elementAt(0) instanceof ByteStream) {
- return HTML.parseReader(new InputStreamReader(((ByteStream)args.elementAt(0)).getInputStream()));
+ if (args.elementAt(0) instanceof Res) {
+ return HTML.parseReader(new InputStreamReader(((Res)args.elementAt(0)).getInputStream()));
} else {
return HTML.parseReader(new StringReader(args.elementAt(0).toString()));
}
if (Log.on) Log.log(HTML.class, e);
throw new JS.Exn("error while parsing HTML");
}
- }
- });
- */
- super.put("recursivePrintObject", new JS.Callable() { public Object call(JS.Array args) {
- if (args.length() != 1) return null;
- recurse("", "", args.elementAt(0));
- return null;
- }});
- super.put("loadArchive", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
- if (!ThreadMessage.suspendThread()) return null;
- try {
- if (args == null || args.length() < 1 || args.elementAt(0) == null) return null;
- URL u = new URL(args.elementAt(0).toString());
-
- JS.Callable callback = null;
- if (args.length() == 2 && args.elementAt(1) != null && args.elementAt(1) instanceof JS.Callable)
- callback = (JS.Callable)args.elementAt(1);
-
- if (!u.getFile().endsWith(".xwar")) {
- if (Log.on) Log.log(this, "Error: archive names must end with .xwar: " + u.getFile());
- throw new JS.Exn("Error: archive names must end with .xwar: " + u.getFile());
- }
-
- if (u.getProtocol().equals("http")) {
- HTTP http = new HTTP(u.toString());
- if (Main.originAddr == null) {
- try {
- Main.originHost = u.getHost();
- Main.originAddr = InetAddress.getByName(Main.originHost);
- } catch (UnknownHostException e) {
- if (Log.on) Log.log(this, "couldn't resolve " + u.getHost() + "; proceeding without permissions");
- Main.originAddr = InetAddress.getByName("0.0.0.0");
- }
- } else {
- Main.originAddr = InetAddress.getByName("0.0.0.0");
- }
- HTTP.HTTPInputStream in = http.GET();
- Resources.loadArchive(in, in.getContentLength(), callback);
-
- } else if (u.getProtocol().equals("file")) {
- if (Main.originAddr != null) {
- if (Log.on) Log.log(this, "scripts downloaded from the network may not load xwars from the local filesystem");
- throw new JS.Exn("scripts downloaded from the network may not load xwars from the local filesystem");
- }
- Resources.loadArchive(new FileInputStream(u.getFile()), (int)new File(u.getFile()).length(), callback);
-
- } else {
- if (Log.on) Log.log(this, "unknown protocol \"" + u.getProtocol() + "\"");
- throw new JS.Exn("unknown protocol \"" + u.getProtocol() + "\"");
- }
-
- } catch (MalformedURLException me) {
- if (Log.on) Log.log(this, "Malformed URL: " + args.elementAt(0));
- if (Log.on) Log.log(this, me);
- throw new JS.Exn(me.toString());
-
- } catch (IOException ioe) {
- if (Log.on) Log.log(this, "IOException while loading archive:");
- if (Log.on) Log.log(this, ioe);
- throw new JS.Exn(ioe.toString());
-
- } finally {
- ThreadMessage.resumeThread();
-
+ } else if (method.equals("recursivePrintObject")) {
+ if (checkOnly) return Boolean.TRUE;
+ if (args.length() != 1) return null;
+ recurse("", "", args.elementAt(0));
+ return null;
}
+
+ if (checkOnly) return Boolean.FALSE;
return null;
- }});
-
- super.put("prefetchImage", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
- if (args == null || args.length() < 1 || args.elementAt(0) == null) return null;
- ImageDecoder.getImageDecoder(args.elementAt(0).toString(),
- args.length() > 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) {
}
}
-
public static void sleep(int i) {
java.lang.Thread thread = java.lang.Thread.currentThread();
if (!(thread instanceof ThreadMessage)) {
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();
}
}
// 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 ///////////////////////////////////////////////
/** 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);
}
}
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() {
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)));
}
- 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) {
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)); }
}
}
- 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) { }
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<awtfonts.length; i++) {
- fontList[i * 4] = awtfonts[i] + "*";
- fontList[i * 4 + 1] = awtfonts[i] + "*b";
- fontList[i * 4 + 2] = awtfonts[i] + "*i";
- fontList[i * 4 + 3] = awtfonts[i] + "*bi";
- }
- */
- fontList = new String[] { };
- }
-
- private static Hash fontCache = new Hash();
- private static ParsedFont pf = new ParsedFont();
- private static MetricatedFont getFont(String font) {
- MetricatedFont ret = (MetricatedFont)fontCache.get(font);
- if (ret == null) {
- pf.parse(font);
- if (pf.name.equals("tty")) pf.name = "monospace";
-
- // Java's fonts tend to be, on average, two points smaller than Win32/X11 fonts. This is most acute in
- // the proxy password dialog on Linux
- ret = new MetricatedFont(pf.name, (pf.bold ? Font.BOLD : 0) | (pf.italic ? Font.ITALIC : 0), pf.size + 2);
-
- fontCache.put(font, ret);
- }
- return ret;
- }
-
- private static class MetricatedFont extends Font {
- public FontMetrics metrics = null;
- public MetricatedFont(String name, int size, int style) {
- super(name, size, style);
- metrics = Toolkit.getDefaultToolkit().getFontMetrics(this);
- }
- }
-
}