2003/09/23 08:24:59
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:36:08 +0000 (07:36 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:36:08 +0000 (07:36 +0000)
darcs-hash:20040130073608-2ba56-05ac1025b2fd2a3cd137e51158744c1b53fcea21.gz

23 files changed:
src/org/xwt/Box.java.pp
src/org/xwt/Glyph.java
src/org/xwt/HTTP.java
src/org/xwt/ImageDecoder.java [deleted file]
src/org/xwt/Main.java
src/org/xwt/Message.java
src/org/xwt/MessageQueue.java [deleted file]
src/org/xwt/Picture.java
src/org/xwt/PixelBuffer.java
src/org/xwt/Platform.java
src/org/xwt/Res.java
src/org/xwt/Resources.java [deleted file]
src/org/xwt/SOAP.java
src/org/xwt/Static.java [deleted file]
src/org/xwt/Surface.java
src/org/xwt/Template.java
src/org/xwt/ThreadMessage.java
src/org/xwt/Trap.java
src/org/xwt/XMLRPC.java
src/org/xwt/XWT.java
src/org/xwt/js/CompiledFunctionImpl.java
src/org/xwt/js/JS.java
src/org/xwt/plat/AWT.java

index eb8c0c0..2c25b44 100644 (file)
@@ -6,9 +6,6 @@ package org.xwt;
 // 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
@@ -72,7 +69,7 @@ public final class Box extends JS.Scope {
 
     // Misc instance data ////////////////////////////////////////////////////////////////
 
-    private static int sizePosChangesSinceLastRender = 0;
+    static int sizePosChangesSinceLastRender = 0;
 
 
     // Misc instance data ////////////////////////////////////////////////////////////////
@@ -85,31 +82,16 @@ public final class Box extends JS.Scope {
     Box redirect = this;
     Surface surface = null;               // null on all non-root boxen
 
-    // FEATURE: combine this with the JSObject Hash
-    Hash traps = null;
-
-
     // Flags ///////////////////////////////////////////////////////////////////////////////
+    short flags = 0;
     static int MOUSEINSIDE_FLAG  = 0x00000001;
     static int INVISIBLE_FLAG    = 0x00000002;
     static int ABSOLUTE_FLAG     = 0x00000004;
-    static int HSHRINK_FLAG      = 0x00000010;
-    static int VSHRINK_FLAG      = 0x00000020;
-    static int TILE_FLAG         = 0x00000040;
-
-    /**
-     *  Set when the font changes, cleared during repack.  If set
-     *  during repack, all font==null children are marked for reflow
-     *  and given the font_changed_flag.  We use this flag to avoid
-     *  having to iterate over all descendents of a box when its font
-     *  changes.
-     */
-    static int FONT_CHANGED_FLAG = 0x00000100;
-    static int ISROOT_FLAG       = 0x00000200;
-
-    static int ALIGN_FLAG        = 0x00000000;
-    static int FIXEDASPECT_FLAG  = 0x00000000;
-    int flags = 0;
+    static int HSHRINK_FLAG      = 0x00000008;
+    static int VSHRINK_FLAG      = 0x00000010;
+    static int TILE_FLAG         = 0x00000020;
+    static int FONT_CHANGED_FLAG = 0x00000040;  // set when font changes, cleared during repack
+    static int ISROOT_FLAG       = 0x00000080;
 
 
     // Geometry ////////////////////////////////////////////////////////////////////////////
@@ -139,8 +121,8 @@ public final class Box extends JS.Scope {
     private int colspan = 1;
 
     // computed during reflow
-    LENGTH x = 0;
-    LENGTH y = 0;
+    public LENGTH x = 0;
+    public LENGTH y = 0;
     public LENGTH width = 0;
     public LENGTH height = 0;
     private int row = 0;  // FEATURE use a short
@@ -167,7 +149,6 @@ public final class Box extends JS.Scope {
     /** Adds the intersection of (x,y,w,h) and the node's current actual geometry to the Surface's dirty list */
     public final void dirty() { dirty(0, 0, width, height); }
     public final void dirty(int x, int y, int w, int h) {
-        /*
         for(Box cur = this; cur != null; cur = cur.parent) {
             w = min(x + w, cur.width) - max(x, 0);
             h = min(y + h, cur.height) - max(y, 0);
@@ -178,10 +159,6 @@ public final class Box extends JS.Scope {
             x += cur.x;
             y += cur.y;
         }
-        */
-        Box cur;
-        for(cur = this; cur.parent != null; cur = cur.parent);
-        if (cur.surface != null) cur.surface.dirty(0, 0, cur.width, cur.height);
     }
 
     /**
@@ -200,10 +177,10 @@ public final class Box extends JS.Scope {
 
         if (!wasinside && !isinside) return;
 
-        if (traps == null) { }
-        else if (!wasinside && isinside && traps.get("Enter") != null) put("Enter", Boolean.TRUE);
-        else if (wasinside && !isinside && traps.get("Leave") != null) put("Leave", Boolean.TRUE);
-        else if (wasinside && isinside && (mousex != oldmousex || mousey != oldmousey) && traps.get("Move") != null) put("Move", Boolean.TRUE);
+        if (!wasinside && isinside && get("Enter", Trap.class) != null) put("Enter", Boolean.TRUE);
+        else if (wasinside && !isinside && get("Leave", Trap.class) != null) put("Leave", Boolean.TRUE);
+        else if (wasinside && isinside && (mousex != oldmousex || mousey != oldmousey) && get("Move", Trap.class) != null)
+            put("Move", Boolean.TRUE);
 
         if (isinside && cursor != null) getRoot().cursor = cursor;
 
@@ -300,8 +277,8 @@ public final class Box extends JS.Scope {
         if (x != this.x || y != this.y || width != this.width || height != this.height) {
             (parent == null ? this : parent).dirty(this.x, this.y, this.width, this.height);
             boolean sizechange = false, poschange = false;
-            if (traps != null && (this.width != width || this.height != height) && traps.get("SizeChange") != null) sizechange = true;
-            if (traps != null && (this.x != x || this.y != y) && traps.get("PosChange") != null) poschange = true;
+            if ((this.width != width || this.height != height) && get("SizeChange", Trap.class) != null) sizechange = true;
+            if ((this.x != x || this.y != y) && get("PosChange", Trap.class) != null) poschange = true;
             this.width = width; this.height = height; this.x = x; this.y = y;
             dirty();
             if (sizechange || poschange)
@@ -443,12 +420,8 @@ public final class Box extends JS.Scope {
     }
 
     void renderStretchedImage(int globalx, int globaly, int clipx, int clipy, int clipw, int cliph, PixelBuffer buf) {
-        //buf.setClip(x, y, w + x, h + y);
-        System.out.println("draw " + clipx + " " + clipy + " " + (clipx + clipw) + " " + (clipy + cliph));
-        buf.drawPicture(image,
-                        clipx, clipy, clipx + clipw, clipy + cliph,
-                        0, 0, image.getWidth(), image.getHeight());
-        //buf.setClip(0, 0, buf.getWidth(), buf.getHeight());
+        // FIXME: wrong
+        buf.drawPicture(image, clipx, clipy, clipx + clipw, clipy + cliph, 0, 0, image.getWidth(), image.getHeight());
     }
 
     void renderTiledImage(int globalx, int globaly, int x, int y, int w, int h, PixelBuffer buf) {
@@ -506,31 +479,28 @@ public final class Box extends JS.Scope {
         } else if ("apply".equals(method)) {
             if (checkOnly) return Boolean.TRUE;
             if (args.elementAt(0) instanceof Res) {
-            try {
                 Res res = (Res)args.elementAt(0);
                 //                res = res.addExtension(".xwt");
-                Template t = Template.buildTemplate(res.getInputStream(), "fromResource");
+                Template t = Template.getTemplate(res);
                 if (ThreadMessage.suspendThread()) try {
                     JS.Callable callback = args.length() < 2 ? null : (Callable)args.elementAt(1);
-
+                    
                     // FIXME!!! needs to be xwt.apply(template, box)
-                    t.apply(this, null, null, callback, 0, t.numUnits(), null);
+                    t.apply(this, callback, 0, t.numUnits(), null);
                 } finally {
                     ThreadMessage.resumeThread();
                 }
-            } catch (IOException e) {
-                Log.log(this, e);
-            }
             } else if (args.elementAt(0) instanceof String) {
                 String templatename = (String)args.elementAt(0);
-                Template t = Template.getTemplate(templatename, null);
+                // FIXME
+                Template t = Template.getTemplate(null);
                 if (t == null) {
                     if (Log.on) Log.logJS(this, "template " + templatename + " not found");
                 } else {
                     if (ThreadMessage.suspendThread()) try {
                         JS.Callable callback = args.length() < 2 ? null : (Callable)args.elementAt(1);
                         // FIXME!!! needs to be xwt.apply(template, box)
-                        t.apply(this, null, null, callback, 0, t.numUnits(), null);
+                        t.apply(this, callback, 0, t.numUnits(), null);
                     } finally {
                         ThreadMessage.resumeThread();
                     }
@@ -575,8 +545,6 @@ public final class Box extends JS.Scope {
                 b.remove();
                 put("0", b);
             }
-        } else if (value instanceof RootProxy) {
-            if (Log.on) Log.logJS(this, "attempt to reparent a box via its proxy object");
         } else {
             Box newnode = (Box)value;
 
@@ -643,6 +611,9 @@ public final class Box extends JS.Scope {
         }
     }
     
+    public Object get(Object key, Object key2) { return super.get(key, key2); }
+    public void put(Object key, Object key2, Object val) { super.put(key, key2, val); }
+
     public Object get_(Object name) { return super.get(name); }
     public Object get(Object name) { return get(name, false); }
     public Object get(Object name_, boolean ignoretraps) {
@@ -653,7 +624,7 @@ public final class Box extends JS.Scope {
         if (name.equals("")) return null;
 
         // See if we're triggering a trap
-        Trap t = traps == null || ignoretraps ? null : (Trap)traps.get(name);
+        Trap t = ignoretraps ? (Trap)null : (Trap)get(name, Trap.class);
         if (t != null) return t.perform();
 
         // Check for a special handler
@@ -662,7 +633,8 @@ public final class Box extends JS.Scope {
 
         Object ret = super.get(name);
         if (name.startsWith("$") && ret == null)
-            if (Log.on) Log.logJS(this, "WARNING: attempt to access " + name + ", but no child with id=\"" + name.substring(1) + "\" found");
+            if (Log.on) Log.logJS(this, "WARNING: attempt to access " + name + ", but no child with id=\"" +
+                                  name.substring(1) + "\" found");
         return ret;
     }
 
@@ -682,14 +654,13 @@ public final class Box extends JS.Scope {
      *  @param rp if this put is being performed via a root proxy, rp is the root proxy.
      */
     public void put_(Object name, Object value) { super.put(name, value); }
-    public void put(Object name, Object value) { put(name, value, false, null); }
-    public void put(Object name, Object value, boolean ignoretraps) { put(name, value, ignoretraps, null); }
-    public void put(Object name_, Object value, boolean ignoretraps, RootProxy rp) {
+    public void put(Object name, Object value) { put(name, value, false); }
+    public void put(Object name_, Object value, boolean ignoretraps) {
         if (name_ instanceof Number) { put(((Number)name_).intValue(), value); return; }
         if (!(name_ instanceof String)) { super.put(name_,value); return; }
         String name = name_.toString();
-        if (!ignoretraps && traps != null) {
-            Trap t = (Trap)traps.get(name);
+        if (!ignoretraps) {
+            Trap t = (Trap)get(name, Trap.class);
             if (t != null) {
                 t.perform(value);
                 return;
@@ -843,27 +814,6 @@ public final class Box extends JS.Scope {
     }
 
 
-    // Root Proxy ///////////////////////////////////////////////////////////////////////////////
-
-    // FEATURE: use xwt.graft() here
-    RootProxy myproxy = null;
-    public JS getRootProxy() {
-        if (myproxy == null) myproxy = new RootProxy(this);
-        return myproxy;
-    }
-
-    private static class RootProxy extends JS {
-        Box box;
-        RootProxy(Box b) { this.box = b; }
-        public Object get(Object name) { return box.get(name); }
-        public void put(Object name, Object value) { box.put(name, value, false, this); }
-        public Object[] keys() { return box.keys(); }
-        public Object callMethod(Object method, JS.Array args, boolean justChecking) {
-           return ((Box)box).callMethod(method,args,justChecking);
-       }
-    }
-
-
     // Trivial Helper Methods (should be inlined) /////////////////////////////////////////
 
     static final int min(int a, int b) { if (a<b) return a; else return b; }
@@ -1056,17 +1006,8 @@ public final class Box extends JS.Scope {
                         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() {
@@ -1099,10 +1040,7 @@ public final class Box extends JS.Scope {
                         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();
                     }
@@ -1184,6 +1122,8 @@ public final class Box extends JS.Scope {
                     } });
         
             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) ||
@@ -1201,6 +1141,7 @@ public final class Box extends JS.Scope {
                         }
                         b.dirty();
                     }
+                    */
                 });
 
             //#repeat globalx/globaly x/y
@@ -1334,18 +1275,6 @@ public final class Box extends JS.Scope {
                     }
                 });
 
-            //#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);
@@ -1414,6 +1343,8 @@ public final class Box extends JS.Scope {
                 });
 
             specialBoxProperties.put("icon", new SpecialBoxProperty() {
+                    // FIXME
+                    /*
                     public void put(Box b, Object value) {
                         b.put_("icon", value);
                         if (b.surface == null) return;
@@ -1422,6 +1353,7 @@ public final class Box extends JS.Scope {
                         else if (Log.on) Log.log(this, "unable to load icon " + value);
                     }
                     public Object get(Box b) { return b.get_("icon"); }
+                    */
                 });
         }
     }
index fdde61d..6840f65 100644 (file)
@@ -2,6 +2,7 @@
 package org.xwt;
 import org.xwt.translators.*;
 import org.xwt.util.*;
+import org.xwt.js.*;
 
 public class Glyph {
     public char c;
@@ -19,13 +20,11 @@ public class Glyph {
         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);
     }
 }
index a5c7114..ce94de2 100644 (file)
@@ -771,12 +771,14 @@ public class HTTP {
 
                 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);
+                            */
                         }
                     });
 
diff --git a/src/org/xwt/ImageDecoder.java b/src/org/xwt/ImageDecoder.java
deleted file mode 100644 (file)
index 3a4fb6e..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-// 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();
-
-}
index d55d9bb..590d126 100644 (file)
@@ -59,6 +59,7 @@ public class Main {
                 else break;
                 startargs++;
             }
+            /* FIXME
             final String instancename = args.length > startargs + 1 ? args[startargs + 1] : "main";
 
             Platform.forceLoad();
@@ -66,7 +67,6 @@ public class Main {
 
             InputStream is = Platform.getBuiltinInputStream();
             if (is == null) Platform.criticalAbort("unable to load builtin.xwar");
-            Resources.loadArchive(is);
            
             if (Log.on) Log.log(Main.class, "loading scar image");
             PNG png = PNG.decode(new ByteArrayInputStream(Resources.getResource("org.xwt.builtin.scar.png")), "bundled scar image");
@@ -75,6 +75,7 @@ public class Main {
             String initialTemplate = "main";
             Res initialRR = null;
 
+            // FIXME: after applying initial template, check numsurfaces; if zero, exit
             if (args.length > startargs) {
                 if (args[startargs].startsWith("http://")) {
                     if (Log.on) Log.log(Main.class, "downloading xwar");
@@ -130,7 +131,7 @@ public class Main {
             //if (Log.on) Log.log(Main.class, "main thread blocking on new semaphore");
             //new org.xwt.util.Semaphore().block();
             Platform.running();
-
+            */
         } catch (Throwable e) {
             e.printStackTrace();
             Platform.criticalAbort("exception in Main.main(): " + e);
index 30eec80..ba856cb 100644 (file)
 // 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) { }
+                }
+            }
+        }
+    
+    }
+
 }
 
diff --git a/src/org/xwt/MessageQueue.java b/src/org/xwt/MessageQueue.java
deleted file mode 100644 (file)
index 2f444c8..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.xwt;
-
-import java.util.*;
-import org.xwt.util.*;
-
-/** 
- *  A singleton class (one instance per JVM) that implements a queue
- *  for XWT events and threads; this is the main action-scheduling
- *  loop for the engine.
- *
- *  This <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) { }
-            }
-        }
-    }
-    
-}
-
-
-
index 8cd3c97..88cf65b 100644 (file)
@@ -1,5 +1,9 @@
 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
+import java.io.*;
+import org.xwt.js.*;
+import org.xwt.util.*;
+import org.xwt.translators.*;
 
 /** 
  *    <p>
@@ -15,6 +19,37 @@ package org.xwt;
  *    </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();
+
 }
index 5e78e98..3d6e09a 100644 (file)
@@ -4,8 +4,7 @@ package org.xwt;
 /**
  *  <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>
@@ -14,30 +13,19 @@ package org.xwt;
  *  method. These implementations may choose to use off-screen video
  *  ram for this purpose (for example, a Pixmap on X11).
  *  </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();
+
 }
index 049404e..850e1dc 100644 (file)
@@ -119,95 +119,74 @@ public class Platform {
     /** 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();
@@ -236,77 +215,11 @@ public class Platform {
     }
 
     /** convert a JPEG into an Image */
-    protected ImageDecoder _decodeJPEG(InputStream is, String name) { return null; }
-
-
-    // Static methods -- thunk to the instance /////////////////////////////////////////////////////////////////////////
-
-    /** if true, org.xwt.Surface should generate Click messages automatically when a Release happens after a Press and the mouse has not moved much */
-    public static boolean needsAutoClick() { return platform._needsAutoClick(); }
-
-    /** if true, org.xwt.Surface should generate DoubleClick messages automatically when needed */
-    public static boolean needsAutoDoubleClick() { return platform._needsAutoDoubleClick(); }
-
-    /** should return true if it is safe to supress full-surface dirties immediately after a window resize */
-    public static String getDefaultFont() { return platform._getDefaultFont(); }
-
-    /** should return true if it is safe to supress full-surface dirties immediately after a window resize */
-    public static boolean supressDirtyOnResize() { return platform._supressDirtyOnResize(); }
-
-    /** returns the width of a string in a platform-specific font */
-    public static int stringWidth(String font, String text) { return platform._stringWidth(font, text); }
-
-    /** returns the maximum ascent of all glyphs in a given platform-specific font */
-    public static int getMaxAscent(String font) { return platform._getMaxAscent(font); }
-
-    /** returns the maximum descent of all glyphs in a given platform-specific font. Three pixel minimum ensures space for underline. */
-    public static int getMaxDescent(String font) { return Math.max(3, platform._getMaxDescent(font)); }
-
-    /** returns the maximum number of threads that the XWT engine can create without adversely affecting the host OS */
-    public static int maxThreads() { return platform._maxThreads(); }
-
-    /** returns a list of all platform-specific fonts available */
-    public static String[] listFonts() { return platform._listFonts(); }
-
-    /** opens a connection to the resource identified by URL u, and returns an InputStream */
-    public static InputStream urlToInputStream(URL u) throws IOException { return platform._urlToInputStream(u); }
-
-    /** returns the contents of the clipboard */    
-    public static Object getClipBoard() { return clipboardReadEnabled ? platform._getClipBoard() : null; }
-
-    /** sets the contents of the clipboard */
-    public static void setClipBoard(String s) { platform._setClipBoard(s); }
-
-    /** creates a socket object, with or without ssl encryption */
-    public static Socket getSocket(String host, int port, boolean ssl, boolean negotiate) throws IOException {
-        return platform._getSocket(host, port, ssl, negotiate);
-    }
-
-    /** returns the width of the screen, in pixels */
-    public static int getScreenWidth() { return platform._getScreenWidth(); }
-
-    /** returns the height of the screen, in pixels */
-    public static int getScreenHeight() { return platform._getScreenHeight(); }
-
-    /** creates and returns a doublebuffer 'belonging' to <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 {
@@ -336,22 +249,10 @@ public class Platform {
         if (Log.on) Log.log(Platform.class, "newBrowserWindow, url = " + url);
         platform._newBrowserWindow(url);
     }
-
-        /** Called once XWT is initialized and the application is running. */
-        public static void running() {
-                Log.log(Platform.class, "XWT is running");
-                platform._running();
-        }
-        
-    /** quits XWT */
-    public static void exit() {
-        Log.log(Platform.class, "exiting via Platform.exit()");
-        platform._exit();
+    protected void _newBrowserWindow(String url) {
+        if (Log.on) Log.log(this, "Platform " + platform.getClass().getName() + " cannot open browser windows");
     }
 
-    /** the human-readable name of the key mapped to XWT's 'alt' key */
-    public static String altKeyName() { return platform._altKeyName(); }
-
     /** used to notify the user of very serious failures; usually used when logging is not working or unavailable */
     public static void criticalAbort(String message) {
         if (Log.on) Log.log(Platform.class, "Critical Abort:");
@@ -360,6 +261,7 @@ public class Platform {
     }
 
     /** this method invokes the platform _createSurface() method and then enforces a few post-call invariants */
+    protected Surface _createSurface(Box b, boolean framed) { return null; }
     public static Surface createSurface(Box b, boolean framed, boolean refreshable) {
         Surface ret = platform._createSurface(b, framed);
         b.width = b.height < Surface.scarPicture.getWidth() ? Surface.scarPicture.getWidth() : b.width;
@@ -369,17 +271,18 @@ public class Platform {
         Object titlebar = b.get("titlebar", true);
         if (titlebar != null) ret.setTitleBarText(titlebar.toString());
 
+        /* FIXME
         Object icon = b.get("icon", true);
         if (icon != null && !"".equals(icon)) {
             Picture pic = ImageDecoder.getPicture(icon.toString());
             if (pic != null) ret.setIcon(pic);
             else if (Log.on) Log.log(Platform.class, "unable to load icon " + icon);
         }
+        */
 
         ret.setLimits(b.minwidth, b.minheight, b.maxwidth, b.maxheight);
 
         if (refreshable) {
-            Surface.refreshableSurfaceWasCreated = true;
             Surface.allSurfaces.addElement(ret);
             ret.dirty(0, 0, b.width, b.height);
             ret.Refresh();
@@ -388,6 +291,7 @@ public class Platform {
     }
 
     /** detects proxy settings */
+    protected synchronized HTTP.Proxy _detectProxy() { return null; }
     public static synchronized HTTP.Proxy detectProxy() {
 
         if (cachedProxyInfo != null) return cachedProxyInfo;
@@ -405,65 +309,6 @@ public class Platform {
         return cachedProxyInfo;
     }
 
-    public static synchronized ImageDecoder decodeJPEG(InputStream is, String name) {
-        return platform._decodeJPEG(is, name);
-    }
-
-    // Helpful font parsing stuff //////////////////////////////////////////////////////
-
-    public static class ParsedFont {
-        public ParsedFont() { }
-        public ParsedFont(String s) { parse(s); }
-        public int size = 10;
-        public String name = "";
-
-        public boolean italic = false;
-        public boolean bold = false;
-        public boolean underline = false;
-        public boolean dotted_underline = false;
-
-        private static int stoi(Object o) {
-            if (o == null) return 0;
-            if (o instanceof Integer) return ((Integer)o).intValue();
-            
-            String s = o.toString(); 
-            try { return Integer.parseInt(s.indexOf('.') == -1 ? s : s.substring(0, s.indexOf('.'))); }
-            catch (NumberFormatException e) { return 0; }
-        }
-
-        public void parse(String font) {
-            int i = 0;
-            while(i < font.length() && !Character.isDigit(font.charAt(i)) && font.charAt(i) != '*') i++;
-            name = font.substring(0, i).toLowerCase().replace('_', ' ');
-            size = 10;
-            italic = false;
-            bold = false;
-            underline = false;
-            dotted_underline = false;
-            if (i != font.length()) {
-                if (font.charAt(i) == '*') {
-                    size = 0;
-                    i++;
-                } else {
-                    int j = i;
-                    while (j < font.length() && Character.isDigit(font.charAt(j))) j++;
-                    if (i != j) size = stoi(font.substring(i, j));
-                    i = j;
-                }
-                while(i < font.length()) {
-                    switch (font.charAt(i)) {
-                    case 'b': bold = true; break;
-                    case 'i': italic = true; break;
-                    case 'd': dotted_underline = true; break;
-                    case 'u': underline = true; break;
-                    }
-                    i++;
-                }
-            }
-        }
-
-    }
-
 }
 
 
index 402f2d6..3f70589 100644 (file)
@@ -7,28 +7,33 @@ import java.util.zip.*;
 import org.xwt.js.*;
 import org.xwt.util.*;
 
-// FIXME: ByteStream fileName property
 /** base class for XWT resources */
 public abstract class Res extends JS {
 
-    public final InputStream getInputStream() throws IOException { return getInputStream(""); }
+    public String getDescriptiveName() { return "FIXME"; }
 
-    public Res graft(Object newResource) { throw new JS.Exn("cannot graft onto this resource"); }
+    /** if this Res corresponds to a Template, it is cached here */
+    Template t = null;
 
+    /** cache of subresources so that the equality operator works on them */
     private Hash refCache = null;
+
+    /** returns an InputStream containing the Resource's contents */
+    public InputStream getInputStream() throws IOException { return getInputStream(""); }
+    public abstract InputStream getInputStream(String path) throws IOException;
+
+    /** graft newResource in place of this resource on its parent */
+    public Res graft(Object newResource) { throw new JS.Exn("cannot graft onto this resource"); }
+
+    /** if the path of this resource does not end with extension, return a new one wit it appended */
+    public Res addExtension(String extension) { return new Ref(this, extension); }
+
+    public Object[] keys() { throw new JS.Exn("cannot enumerate a resource"); } 
+    public void put(Object key, Object val) { throw new JS.Exn("cannot put to a resource"); } 
     public Object get(Object key) {
         if ("".equals(key)) {
-            try {
-                Res who = this;
-                //who = addExtension(".xwt");
-                // FIXME: cache templates by the Res that created them, not their nodename
-                Template.buildTemplate(who.getInputStream(), "Resource");
-                // FIXME: return the static here
-                return null;
-            } catch (IOException e) {
-                Log.logJS(this, e);
-                return null;
-            }
+            Template t = Template.getTemplate(addExtension(".xwt"));
+            return t == null ? null : t.getStatic();
         }
         Object ret = refCache == null ? null : refCache.get(key);
         if (ret != null) return ret;
@@ -38,12 +43,6 @@ public abstract class Res extends JS {
         return ret;
     }
 
-    public void put(Object key, Object val) { throw new JS.Exn("cannot put to a resource"); } 
-    public Object[] keys() { throw new JS.Exn("cannot enumerate a resource"); } 
-
-    public abstract InputStream getInputStream(String path) throws IOException;
-    //public abstract Res addExtension(String extension);
-
     public static Res stringToRes(String url) {
         if (url.indexOf('!') != -1)
             return (Res)(new Zip(stringToRes(url.substring(0, url.lastIndexOf('!')))).get(url.substring(url.lastIndexOf('!') + 1)));
@@ -61,12 +60,23 @@ public abstract class Res extends JS {
         public InputStream getInputStream(String path) throws IOException { return new org.xwt.HTTP(url + path).GET(); }
     }
 
+    /** byte arrays */
+    public static class ByteArray extends Res {
+        private byte[] bytes;
+        ByteArray(byte[] bytes) { this.bytes = bytes; }
+        public InputStream getInputStream(String path) throws IOException {
+            if (!"".equals(path)) throw new JS.Exn("can't get subresources of a byte[] resource");
+            return new ByteArrayInputStream(bytes);
+        }
+    }
+
     // FIXME: dangerous
     /** a file */
     public static class File extends Res {
         private String path;
         File(String path) { this.path = path; }
-        public InputStream getInputStream(String rest) throws IOException { return new FileInputStream((path + rest).replace('/', java.io.File.separatorChar)); }
+        public InputStream getInputStream(String rest) throws IOException {
+            return new FileInputStream((path + rest).replace('/', java.io.File.separatorChar)); }
     }
 
     /** wrap a Res around a preexisting InputStream */
@@ -97,6 +107,9 @@ public abstract class Res extends JS {
         Res parent;
         Object key;
         Ref(Res parent, Object key) { this.parent = parent; this.key = key; }
+        public Res addExtension(String extension) {
+            return (key instanceof String && ((String)key).endsWith(extension)) ? this : new Ref(this, extension);
+        }
         public InputStream getInputStream(String path) throws IOException {
             return parent.getInputStream("/" + key + path);
         }
@@ -108,14 +121,11 @@ public abstract class Res extends JS {
         Res graftee;
         Object replaced_key;
         Object replaced_val;
-        Graft(Res graftee, Object key, Object val) {
-            this.graftee = graftee; replaced_key = key; replaced_val = val; }
+        Graft(Res graftee, Object key, Object val) { this.graftee = graftee; replaced_key = key; replaced_val = val; }
         public boolean equals(Object o) { return (this == o || graftee.equals(o)); }
         public int hashCode() { return graftee.hashCode(); }
         public InputStream getInputStream(String s) throws IOException { return graftee.getInputStream(s); }
-        public Object get(Object key) {
-            return replaced_key.equals(key) ? replaced_val : graftee.get(key);
-        }
+        public Object get(Object key) { return replaced_key.equals(key) ? replaced_val : graftee.get(key); }
     }
 
     /** unpacks a Microsoft CAB file (possibly embedded in another file; we scan for 'MSCF' */
diff --git a/src/org/xwt/Resources.java b/src/org/xwt/Resources.java
deleted file mode 100644 (file)
index 230f2fd..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.xwt;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import java.util.zip.*;
-import java.lang.*;
-import org.xwt.js.*;
-import org.xwt.util.*;
-
-/**
- *  A singleton class that acts as a repository for files obtained
- *  from xwar archives or the local filesystem.
- *
- *  All names are converted to resource names (dots instead of
- *  slashes) when they are loaded into this repository; however,
- *  filename extensions are left on, so queries (resolveResource(),
- *  getResource()) should include the extension when querying for
- *  resources.
- */
-public class Resources {
-
-    /** Holds resources added at runtime. Initialized to hold 2000 to work around a NetscapeJVM bug. */
-    private static Hash bytes = new Hash(2000, 3);
-
-    /** keeps track of which archive loaded templates into which package */
-    private static Hash usedPackages = new Hash();
-
-    /** Returns true iff <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;
-    }
-}
-
-
-
index 5b969b4..debbc24 100644 (file)
@@ -90,13 +90,11 @@ class SOAP extends XMLRPC {
                 objects.addElement(new String(content.getBuf(), 0, content.size()).intern());
                 content.reset();
 
-                // FIXME
-                /*
             } else if (me instanceof byte[]) {
                 objects.removeElementAt(objects.size() - 1);
-                objects.addElement(new ByteStream(Base64.decode(new String(content.getBuf(), 0, content.size()))));
+                objects.addElement(new Res.ByteArray(Base64.decode(new String(content.getBuf(), 0, content.size()))));
                 content.reset();                
-                */
+
             } else if (me instanceof Integer) {
                 objects.removeElementAt(objects.size() - 1);
                 objects.addElement(new Integer(new String(content.getBuf(), 0, content.size())));
@@ -179,11 +177,10 @@ class SOAP extends XMLRPC {
             sb.append(((Boolean)o).booleanValue() ? "true" : "false");
             sb.append("</" + 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);
@@ -204,7 +201,7 @@ class SOAP extends XMLRPC {
                 if (Log.on) Log.log(this, e);
                 throw new JS.Exn("caught IOException while attempting to send a ByteStream via SOAP");
             }
-            */
+
         } else if (o instanceof String) {
             sb.append("                <" + name + " xsi:type=\"xsd:string\">");
             String s = (String)o;
diff --git a/src/org/xwt/Static.java b/src/org/xwt/Static.java
deleted file mode 100644 (file)
index f762df3..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.xwt;
-
-import org.xwt.js.*;
-import org.xwt.util.*;
-
-/** implements objects in the xwt.static.* namespace */
-public class Static extends JS.Scope {
-
-    public static Static getStatic(String resourcename) {
-        Template t = Template.getTemplate(resourcename, null);
-        if (t != null) t.link();
-        return (Static)cache.get(resourcename);
-    }
-
-    public static Static createStatic(String resourcename, boolean isPackage) {
-        Static ret = (Static)cache.get(resourcename);
-        if (ret != null) return ret;
-        if (resourcename.indexOf('.') != -1)
-            createStatic(resourcename.substring(0, resourcename.lastIndexOf('.')), true);
-        ret = new Static(resourcename, isPackage);
-        return ret;
-    }
-
-    private static Hash cache = new Hash();
-
-    /** the resource name that this Static object corresponds to */
-    private String resourcename = null;
-
-    /** true iff this represents a directory (rather than an actual xwt) */
-    public boolean ispackage = false;
-
-    private Static(String resourcename, boolean ispackage) {
-        super(null);
-        cache.put(resourcename, this);
-        this.resourcename = resourcename;
-        this.ispackage = ispackage;
-        setSeal(ispackage);
-    }
-    
-    /** creates a new static representing a package */
-    public Static(String resourcename) { this(resourcename, true); }
-
-    public Object get(Object name_) {
-        String name = name_.toString();
-        if (!ispackage) return super.get(name);
-        return getStatic(resourcename + (resourcename.length() == 0 ? "" : ".") + name);
-    }
-
-    static { createStatic("", true); }
-
-}
index 5f44098..e1cb141 100644 (file)
@@ -17,122 +17,65 @@ import java.util.*;
  *  MessageQueue-time (the size/position/state at the time that the
  *  now-executing message was enqueued). This distinction is important.
  */
-public abstract class Surface {
+public abstract class Surface extends PixelBuffer {
 
-    // Static Data ////////////////////////////////////////////////////////////////////////////////
+    /** Dirty regions on the screen which need to be rebuilt using Surface.blit() */
+    DirtyList screenDirtyRegions = new DirtyList();
 
-    /** true iff a user-created surface was created */
-    static boolean refreshableSurfaceWasCreated = false;
+    public int getWidth() { return root == null ? 0 : root.width; }
+    public int getHeight() { return root == null ? 0 : root.height; }
+        
+    // Static Data ////////////////////////////////////////////////////////////////////////////////
 
-    /** a reference to the most recently enqueued Move message; used to throttle the message rate */
+    /**< the most recently enqueued Move message; used to throttle the message rate */
     private static Message lastMoveMessage = null;
 
     /** all instances of Surface which need to be refreshed by the MessageQueue */
     public static Vec allSurfaces = new Vec();
-
-    /** true iff the alt button is pressed down, in real time */
-    public static boolean alt = false;
     
-    /** true iff the control button is pressed down, in real time */
-    public static boolean control = false;
-
-    /** true iff the shift button is pressed down, in real time */
-    public static boolean shift = false;
-
-    /** true iff button 1 is depressed, in MessageQueue-time */
-    public static boolean button1 = false;
-
-    /** true iff button 2 is depressed, in MessageQueue-time */
-    public static boolean button2 = false;
-
-    /** true iff button 3 is depressed, in MessageQueue-time */
-    public static boolean button3 = false;
-
-    /** true iff all surfaces created from now on should be scarred */
-    public static boolean scarAllSurfacesFromNowOn = false;
-
-    /** false if the surface has never been rendered; used to determine if the surface should be repositioned to be centered on the screen */
-    public boolean centerSurfaceOnRender = true;
-
-    /** the x position of the mouse, relative to this Surface, in MessageQueue-time */
-    public int mousex;
+    /** When set to true, render() should abort as soon as possible and restart the rendering process */
+    static volatile boolean abort = false;
 
-    /** the y position of the mouse, relative to this Surface, in MessageQueue-time */
-    public int mousey;
+    public static boolean alt = false;          /**< true iff the alt button is pressed down, in real time */
+    public static boolean control = false;      /**< true iff the control button is pressed down, in real time */
+    public static boolean shift = false;        /**< true iff the shift button is pressed down, in real time */
+    public static boolean button1 = false;      /**< true iff button 1 is depressed, in MessageQueue-time */
+    public static boolean button2 = false;      /**< true iff button 2 is depressed, in MessageQueue-time */
+    public static boolean button3 = false;      /**< true iff button 3 is depressed, in MessageQueue-time */
 
-    /** True iff this surface is minimized, in real time */
-    public boolean minimized = false;
 
-    /** True iff this surface is maximized, in real time */
-    public boolean maximized = false;
+    // Instance Data ///////////////////////////////////////////////////////////////////////
 
-    /** The name of the cursor on this surface -- this value fluctuates during rendering, so it may not be accurate;
-     *  syncCursor() is called once the value is stable, to prevent the "flickering cursor" phenomenon
-     */
+    public Box root;      /**< The Box at the root of this surface */
     public String cursor = "default";
 
-    /** The Box at the root of this surface */
-    public Box root;
-
-    /** The number of SizeChange/PosChange traps triggered since the last successful render -- used to detect infinite loops */
-    public int sizePosChangesSinceLastRender = 0;
+    public int mousex;      /**< the x position of the mouse, relative to this Surface, in MessageQueue-time */
+    public int mousey;      /**< the y position of the mouse, relative to this Surface, in MessageQueue-time */
+    public boolean minimized = false;      /**< True iff this surface is minimized, in real time */
+    public boolean maximized = false;      /**< True iff this surface is maximized, in real time */
 
 
     // Used For Simulating Clicks and DoubleClicks /////////////////////////////////////////////////
 
-    /** the x-position of the mouse the last time a Press message was enqueued */
-    int last_press_x = Integer.MAX_VALUE;
-
-    /** the y-position of the mouse the last time a Press message was enqueued */
-    int last_press_y = Integer.MAX_VALUE;
-
-    /** the last button to recieve a Click message; used for simulating DoubleClick's */
-    static int lastClickButton = 0;
-
-    /** the last time a Click message was processed; used for simulating DoubleClick's */
-    static long lastClickTime = 0;
+    int last_press_x = Integer.MAX_VALUE;      /**< the x-position of the mouse the last time a Press message was enqueued */
+    int last_press_y = Integer.MAX_VALUE;      /**< the y-position of the mouse the last time a Press message was enqueued */
+    static int lastClickButton = 0;            /**< the last button to recieve a Click message; used for simulating DoubleClick's */
+    static long lastClickTime = 0;             /**< the last time a Click message was processed; used for simulating DoubleClick's */
     
     
     // Methods to be overridden by subclasses ///////////////////////////////////////////////////////
 
-    /** when this method is invoked, the surface should push itself to the back of the stacking order */
-    public abstract void toBack();
-
-    /** when this method is invoked, the surface should pull itself to the front of the stacking order */
-    public abstract void toFront();
-
-    /** sets the <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) { }
 
 
@@ -150,7 +93,7 @@ public abstract class Surface {
         else if (button == 2) new SimpleMessage("Press2", Boolean.TRUE, Box.whoIs(root, mousex, mousey));
         else if (button == 3) {
             final Box who = Box.whoIs(root, mousex, mousey);
-            MessageQueue.add(new Message() { public void perform() {
+            Message.Q.add(new Message() { public void perform() {
                 Platform.clipboardReadEnabled = true;
                 root.put("Press3", Boolean.TRUE);
                 Platform.clipboardReadEnabled = false;
@@ -204,7 +147,7 @@ public abstract class Surface {
         else if (control) key = "C-" + key;
 
         final String fkey = key;
-        MessageQueue.add(new KMessage(key));
+        Message.Q.add(new KMessage(key));
     }
 
     // This is implemented as a private static class instead of an anonymous class to work around a GCJ bug
@@ -213,12 +156,14 @@ public abstract class Surface {
         public KMessage(String k) { key = k; }
         public void perform() {
             if (key.equals("C-v") || key.equals("A-v")) Platform.clipboardReadEnabled = true;
+            /* FIXME
             outer: for(int i=0; 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;
         }
     }
@@ -229,13 +174,15 @@ public abstract class Surface {
         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);
             }
+            */
         }});
     }
 
@@ -246,7 +193,7 @@ public abstract class Surface {
      *  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
@@ -271,7 +218,7 @@ public abstract class Surface {
     }
 
     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;
@@ -281,7 +228,7 @@ public abstract class Surface {
     }
 
     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));
         }});
@@ -291,70 +238,19 @@ public abstract class Surface {
     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);
     }
 
@@ -367,23 +263,17 @@ public abstract class Surface {
 
         // quit when all windows are closed
         if (allSurfaces.size() == 0 && quitIfAllSurfacesGone && Main.doneInitializing) {
-            if (Log.on) {
-                if (refreshableSurfaceWasCreated) Log.log(this, "exiting because last remaining surface was disposed");
-                else Log.log(this, "exiting because no surface was ever created");
-            }
-            Platform.exit();
+            if (Log.on) Log.log(this, "exiting because last surface was destroyed");
+            System.exit(0);
         }
     }
 
-    /** Indicates that the backbuffer region x,y,w,h is no longer correct and must be regenerated */
     public void dirty(int x, int y, int w, int h) {
         backbufferDirtyRegions.dirty(x, y, w, h);
         Refresh();
     }
 
     public Surface(Box root) {
-        this.scarred = scarAllSurfacesFromNowOn;
-        scarAllSurfacesFromNowOn = true;
         this.root = root;
         if (root.surface != null && root.surface.root == root) {
             root.surface.dispose(false);
@@ -393,13 +283,7 @@ public abstract class Surface {
         root.surface = this;
 
         // make sure the root is properly sized
-        do {
-            abort = false;
-            root.reflow();
-        } while(abort);
-
-        // this is a bit dangerous since we're passing ourselves to another method before subclasses' ctors have run...        
-        backbuffer = Platform.createPixelBuffer(Platform.getScreenWidth(), Platform.getScreenHeight(), this);
+        do { abort = false; root.reflow(); } while(abort);
 
         root.dirty();
         Refresh();
@@ -419,16 +303,7 @@ public abstract class Surface {
             if (!cursor.equals(oldcursor)) syncCursor();
         } while(abort);
 
-        if (centerSurfaceOnRender) {
-            centerSurfaceOnRender = false;
-            int x = (Platform.getScreenWidth() - root.width) / 2;
-            int y = (Platform.getScreenHeight() - root.height) / 2;
-            setLocation(x, y);
-            root.x = x;
-            root.y = y;
-        }
-
-        sizePosChangesSinceLastRender = 0;
+        Box.sizePosChangesSinceLastRender = 0;
         int[][] dirt = backbufferDirtyRegions.flush();
         for(int i = 0; dirt != null && i < dirt.length; i++) {
             if (dirt[i] == null) continue;
@@ -442,28 +317,27 @@ public abstract class Surface {
             if (y+h > root.height) h = root.height - y;
             if (w <= 0 || h <= 0) continue;
 
-            root.render(0, 0, x, y, w, h, backbuffer);
+            root.render(0, 0, x, y, w, h, this);
             
             // if any area under the scar was repainted, rescar that area
-            if (scarred && x < hscar + scarPicture.getWidth() &&
+            if (x < hscar + scarPicture.getWidth() &&
                 y + h > root.height - scarPicture.getHeight() - vscar) {
                 int _x1 = Math.max(x, hscar);
                 int _x2 = Math.min(x + w, hscar + scarPicture.getWidth());
                 int _y1 = Math.max(y, root.height - scarPicture.getHeight() - vscar);
                 int _y2 = Math.min(y + h, root.height - vscar);
                 
-                backbuffer.drawPicture(scarPicture, _x1, _y1, _x2, _y2,
-                                       _x1 - (hscar),
-                                       _y1 - (root.height - scarPicture.getHeight() - vscar),
-                                       _x2 - (hscar),
-                                       _y2 - (root.height - scarPicture.getHeight() - vscar)
-                                       );
+                drawPicture(scarPicture, _x1, _y1, _x2, _y2,
+                            _x1,
+                            _y1 - (root.height - scarPicture.getHeight()),
+                            _x2,
+                            _y2 - (root.height - scarPicture.getHeight())
+                            );
             }
 
             if (abort) {
 
                 // x,y,w,h is only partially reconstructed, so we must be careful not to re-blit it
-                blitDirtyScreenRegions(x, y, w, h);
                 screenDirtyRegions.dirty(x, y, w, h);
 
                 // put back all the dirty regions we haven't yet processed (including the current one)
@@ -480,67 +354,6 @@ public abstract class Surface {
             screenDirtyRegions.dirty(x, y, w, h);
         }
 
-        // blit out all the areas we've just reconstructed
-        blitDirtyScreenRegions();
-    }
-
-    /** blits from the backbuffer to the screen for all regions of the screen which have become dirty */
-    public synchronized void blitDirtyScreenRegions() { blitDirtyScreenRegions(-1, -1, 0, 0); }
-
-    /** same as blitDirtyScreenRegions(), except that it will skip any regions within a,b,c,d */
-    private synchronized void blitDirtyScreenRegions(int a, int b, int c, int d) {
-
-        int[][] dirt = screenDirtyRegions.flush();
-        if (Main.showRenders && dirt != null && dirt.length > 0 && a == -1)
-            blit(backbuffer, 0, 0, 0, 0, root.width, root.height);
-
-        for(int i = 0; dirt != null && i < dirt.length; i++) {
-            if (dirt[i] == null) continue;
-            int x = dirt[i][0];
-            int y = dirt[i][1];
-            int w = dirt[i][2];
-            int h = dirt[i][3];
-            if (x < 0) x = 0;
-            if (y < 0) y = 0;
-            if (x+w > root.width) w = root.width - x;
-            if (y+h > root.height) h = root.height - y;
-            if (w <= 0 || h <= 0) continue;
-
-            // if any part of this region falls within the "bad region", just skip it
-            boolean hhit = (x >= a && x <= a + c) || (x+w >= a && x+w <= a + c);
-            boolean vhit = (y >= b && y <= b + d) || (y+h >= b && y+h <= b + d);
-            if (hhit && vhit) {
-                screenDirtyRegions.dirty(x, y, w, h);
-                continue;
-            }
-
-            blit(backbuffer, x, y, x, y, w + x, h + y);
-            
-            if (Main.showRenders) {
-                if (showRenderBuf == null) {
-                    showRenderBuf = Platform.createPixelBuffer(10, 10, this);
-                    showRenderBuf.fillRect(0, 0, 10, 10, 0x00FF0000);
-                    showRenderBuf2 = Platform.createPixelBuffer(100, 100, this);
-                    for(int y1 = 0; y1<100; y1++)
-                        for(int x1 = 0; x1<100; x1++)
-                            if ((x1 + y1) % 5 == 0)
-                                showRenderBuf2.fillRect(x1, y1, x1 + 1, y1 + 1, 0x00FF0000);
-                }
-                for(int x1 = x; x1<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
@@ -554,23 +367,93 @@ public abstract class Surface {
             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;
+
 }
index 11bb1fc..363886c 100644 (file)
@@ -10,12 +10,7 @@ import org.xwt.util.*;
 
 /**
  *  Encapsulates a template node (the &lt;template/&gt; 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
  *  &lt;template/&gt; node carries all the header information -- hence
@@ -26,27 +21,23 @@ import org.xwt.util.*;
  *  See the XWT reference for information on the order in which
  *  templates are applied, attributes are put, and scripts are run.
  */
+
+// FIXME imports
 public class Template {
 
     // Instance Members ///////////////////////////////////////////////////////
 
-    /** this instance's nodeName */
-    String nodeName;
+    /** the id of this box */
+    String id = null;
 
     /** the id of the redirect target; only meaningful on a root node */
     String redirect = null;
 
     /** templates that should be preapplied (in the order of application); only meaningful on a root node */
-    private String[] preapply;
-
-    /** 'linked' form of preapply -- the String references have been resolved into instance references */
-    private Template[] _preapply = null;
+    private Template[] preapply;
 
     /** templates that should be postapplied (in the order of application); only meaningful on a root node */
-    private String[] postapply;
-
-    /** 'linked' form of postapply -- the String references have been resolved into instance references */
-    private Template[] _postapply = null;
+    private Template[] postapply;
 
     /** keys to be "put" to instances of this template; elements correspond to those of vals */
     private String[] keys;
@@ -54,23 +45,14 @@ public class Template {
     /** values to be "put" to instances of this template; elements correspond to those of keys */
     private Object[] vals;
 
-    /** array of strings representing the importlist for this template */
-    private String[] importlist;
-
     /** child template objects */
     private Template[] children;
 
-    /** an array of the names of properties to be preserved when retheming; only meaningful on a root node */
-    private String[] preserve = null;
-    
-    /** the <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;
@@ -78,6 +60,12 @@ public class Template {
     /** the script on this node */
     private JS.CompiledFunction script = null;
 
+    /** the filename this node came from; used only for debugging */
+    private String fileName = "unknown";
+
+
+    // Only used during parsing /////////////////////////////////////////////////////////////////
+
     /** during XML parsing, this holds the list of currently-parsed children; null otherwise */
     private Vec childvect = new Vec();
 
@@ -93,44 +81,27 @@ public class Template {
     /** the line number that this element starts on */
     private int startLine = -1;
 
-    // Static data/methods ///////////////////////////////////////////////////////////////////
-
-    /** a template cache so that only one Template object is created for each xwt */
-    private static Hashtable cache = new Hashtable(1000);
-
-    /** The default importlist; in future revisions this will contain "xwt.*" */
-    public static final String[] defaultImportList = new String[] { };
 
-    /** returns the appropriate template, resolving and theming as needed */
-    public static Template getTemplate(String name, String[] importlist) {
-        String resolved = Resources.resolve(name + ".xwt", importlist);
-        Template t = resolved == null ? null : (Template)cache.get(resolved.substring(0, resolved.length() - 4));
-        if (t != null) return t;
-        if (resolved == null) return null;
-
-        // note that Templates in xwar's are instantiated as read in via loadStream() --
-        // the following code only runs when XWT is reading templates from a filesystem.
-        ByteArrayInputStream bais = new ByteArrayInputStream(Resources.getResource(resolved));
-        return buildTemplate(bais, resolved.substring(0, resolved.length() - 4));
-    }
+    // Static data/methods ///////////////////////////////////////////////////////////////////
 
-    public static Template buildTemplate(InputStream is, String nodeName) {
-        return buildTemplate(is, nodeName, new TemplateHelper());
-    }
+    private Template(String fileName) { this.fileName = fileName; }
 
-    public static Template buildTemplate(InputStream is, String nodeName, TemplateHelper t) {
+    public static Template getTemplate(Res r) {
         try {
-            return new Template(is, nodeName, t);
+            if (r.t != null) return r.t;
+            r.t = new Template(r.getDescriptiveName());
+            new TemplateHelper().parseit(r.getInputStream(), r.t);
+            return r.t;
         } catch (XML.SchemaException e) {
-            if (Log.on) Log.log(Template.class, "error parsing template " + nodeName);
+            if (Log.on) Log.log(Template.class, "error parsing template " + r.t.fileName);
             if (Log.on) Log.log(Template.class, e.getMessage());
             return null;
         } catch (XML.XMLException e) {
-            if (Log.on) Log.log(Template.class, "error parsing template at " + nodeName + ":" + e.getLine() + "," + e.getCol());
+            if (Log.on) Log.log(Template.class, "error parsing template at " + r.t.fileName + ":" + e.getLine() + "," + e.getCol());
             if (Log.on) Log.log(Template.class, e.getMessage());
             return null;
         } catch (IOException e) {
-            if (Log.on) Log.log(Template.class, "IOException while parsing template " + nodeName + " -- this should never happen");
+            if (Log.on) Log.log(Template.class, "IOException while parsing template " + r.t.fileName + " -- this should never happen");
             if (Log.on) Log.log(Template.class, e);
             return null;
         }
@@ -139,183 +110,75 @@ public class Template {
 
     // Methods to apply templates ////////////////////////////////////////////////////////
 
-    private Template(String nodeName) {
-        this.nodeName = nodeName;
-        cache.put(nodeName, this);
-    }
-    private Template(InputStream is, String nodeName, TemplateHelper th) throws XML.XMLException, IOException {
-        this(nodeName);
-        th.parseit(is, this);
-    }
-
-    /** calculates, caches, and returns an integer approximation of how long it will take to apply this template, including pre/post and children */
+    /** calculates, caches, and returns an integer approximation of how long it will take to apply this template,
+     *  including pre/post and children */
     int numUnits() {
-        link();
         if (numunits != -1) return numunits;
         numunits = 1;
-        for(int i=0; _preapply != null && i<_preapply.length; i++) if (_preapply[i] != null) numunits += _preapply[i].numUnits();
-        for(int i=0; _postapply != null && i<_postapply.length; i++) if (_postapply[i] != null) numunits += _postapply[i].numUnits();
+        for(int i=0; preapply != null && 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 /////////////////////////////////////////////////////////////////
@@ -334,12 +197,9 @@ public class Template {
             nameOfHeaderNodeBeingProcessed = null;
 
             nodeStack.setSize(0);
-            importlist.setSize(0);
             preapply.setSize(0);
             postapply.setSize(0);
 
-            importlist.fromArray(defaultImportList);
-
             t = root;
             parse(new InputStreamReader(is)); 
         }
@@ -363,9 +223,6 @@ public class Template {
         /** 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();
 
@@ -394,7 +251,6 @@ public class Template {
                         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")) {
@@ -426,24 +282,11 @@ public class Template {
                     staticNodeHasBeenEncountered = true;
                     return;
 
-                } else if (c.localName.equals("preserve")) {
-                    if (c.len != 1 || !c.keys[0].equals("attributes"))
-                        throw new XML.SchemaException("<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 {
@@ -456,11 +299,10 @@ public class Template {
                 // push the last node we were in onto the stack
                 nodeStack.addElement(t);
 
-                // instantiate a new node, and set its nodeName/importlist/preapply
-                Template t2 = new Template(t.nodeName + "." + t.childvect.size());
-                t2.importlist = t.importlist;
+                // instantiate a new node, and set its fileName/importlist/preapply
+                Template t2 = new Template(t.fileName);
                 t2.startLine = getLine();
-                if (!c.localName.equals("box")) t2.preapply = new String[] { c.localName };
+                if (!c.localName.equals("box")) t2.preapply = new Template[] { /*c.localName FIXME */ };
 
                 // make the new node the current node
                 t = t2;
@@ -468,6 +310,8 @@ public class Template {
             }
 
             // TODO: Sort contents straight from one array to another
+            // FIXME: height must come after image
+            // FIXME: use Vec here
             t.keys = new String[c.len];
             t.vals = new Object[c.len];
             System.arraycopy(c.keys, 0, t.keys, 0, c.len);
@@ -569,10 +413,7 @@ public class Template {
         private JS.CompiledFunction genscript(boolean isstatic) {
             JS.CompiledFunction thisscript = null;
             try {
-                thisscript = JS.parse(t.nodeName + (isstatic ? "._" : ""), t.content_start, new StringReader(t.content.toString()));
-            } catch (JS.Exn ee) {
-                if (Log.on) Log.log(this, "  ERROR: " + ee.getMessage());
-                thisscript = null;
+                thisscript = JS.parse(t.fileName + (isstatic ? "._" : ""), t.content_start, new StringReader(t.content.toString()));
             } catch (IOException ioe) {
                 if (Log.on) Log.log(this, "  ERROR: " + ioe.getMessage());
                 thisscript = null;
@@ -587,7 +428,7 @@ public class Template {
         public void characters(char[] ch, int start, int length) throws XML.SchemaException {
             // invoke the no-tab crusade
             for (int i=0; length >i; i++) if (ch[start+i] == '\t') throw new XML.SchemaException(
-                t.nodeName+ ":" + getLine() + "," + getCol() + ": tabs are not allowed in XWT files");
+                t.fileName+ ":" + getLine() + "," + getCol() + ": tabs are not allowed in XWT files");
 
             if ("static".equals(nameOfHeaderNodeBeingProcessed) || templateNodeHasBeenEncountered) {
                 if (t.content == null) {
index 61e8964..d028642 100644 (file)
@@ -25,7 +25,7 @@ public class ThreadMessage extends Thread implements Message {
     /** the ThreadMessage thread blocks on this before executing any JavaScript */
     Semaphore go = new Semaphore();
 
-    /** The MessageQueue (main) thread blocks on this while the ThreadMessage thread is running JavaScript code */
+    /** The Message.Q (main) thread blocks on this while the ThreadMessage thread is running JavaScript code */
     Semaphore done = new Semaphore();
 
     /** used to pool ThreadMessages that are not in use */
@@ -48,7 +48,7 @@ public class ThreadMessage extends Thread implements Message {
             }
         }
         ret.f = f;
-        MessageQueue.add(ret);
+        Message.Q.add(ret);
     }
 
     /** attempts to put this thread into the background to perform a blocking operation; returns false if unable to do so */
@@ -68,7 +68,7 @@ public class ThreadMessage extends Thread implements Message {
     /** re-enqueues this thread */
     public static void resumeThread() {
         ThreadMessage mythread = (ThreadMessage)Thread.currentThread();
-        MessageQueue.add(mythread);
+        Message.Q.add(mythread);
         mythread.setPriority(Thread.NORM_PRIORITY);
         mythread.go.block();        
     }
@@ -87,7 +87,7 @@ public class ThreadMessage extends Thread implements Message {
                 synchronized(waiting) {
                     if (waiting.size() > 0) {
                         f = (JS.Callable)waiting.remove(false);
-                        MessageQueue.add(this);
+                        Message.Q.add(this);
                     } else if (spare.size() < 10) {
                         spare.append(this);
                     } else {
@@ -104,7 +104,7 @@ public class ThreadMessage extends Thread implements Message {
         }
     }
 
-    /** this is invoked in the MessageQueue thread */
+    /** this is invoked in the Message.Q thread */
     public void perform() {
         go.release();
         done.block();
index 3e6302b..c6c6a47 100644 (file)
@@ -19,12 +19,16 @@ public class Trap {
     private static final Hash PROHIBITED = new Hash(120, 3);
 
     static {
+        // FIXME: review
         String[] p = new String[] {
-            "sizetoimage", "shrink", "hshrink", "vshrink", "x", "y", "width", "height",
-            "flex", "hflex", "vflex", /*"cols", "rows",*/ "align", "invisible", "absolute", "globalx", "globaly",
-            "minwidth", "minheight", "height", "width", "maxwidth", "maxheight", 
-            "numchildren", "hpad", "vpad", "doublebuffered", "cursor",
-            "mousex", "mousey", "xwt", "static", "mouseinside", "root", "thisbox", "indexof", "svg"
+            "sizetoimage", "shrink", "hshrink", "vshrink", "x", "y",
+            "width", "height", "flex", "hflex", "vflex", "cols",
+            "rows", "align", "invisible", "absolute", "globalx",
+            "globaly", "minwidth", "minheight", "height", "width",
+            "maxwidth", "maxheight", "numchildren", "hpad", "vpad",
+            "doublebuffered", "cursor", "mousex", "mousey", "xwt",
+            "static", "mouseinside", "root", "thisbox", "indexof",
+            "path"
         };
         for(int i=0; i<p.length; i++) PROHIBITED.put(p[i], Boolean.TRUE);
     };
@@ -54,16 +58,15 @@ public class Trap {
      *  @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;
@@ -77,18 +80,16 @@ public class Trap {
      *  @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");
     }
 
@@ -97,9 +98,6 @@ public class Trap {
 
     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));
index f11413c..40fbb23 100644 (file)
@@ -103,11 +103,8 @@ class XMLRPC extends JS.Callable {
             else if (c.localName.equals("double"))
                 objects.setElementAt(new Double(new String(content.getBuf(), 0, content.size())), objects.size() - 1);
             
-            // FIXME
-            /*
             else if (c.localName.equals("base64"))
-                objects.setElementAt(new ByteStream(Base64.decode(new String(content.getBuf(), 0, content.size()))), objects.size() - 1);
-            */
+                objects.setElementAt(new Res.ByteArray(Base64.decode(new String(content.getBuf(), 0, content.size()))), objects.size() - 1);
 
             else if (c.localName.equals("name"))
                 objects.addElement(new String(content.getBuf(), 0, content.size()));
@@ -199,12 +196,10 @@ class XMLRPC extends JS.Callable {
             sb.append(((Boolean)o).booleanValue() ? "1" : "0");
             sb.append("</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);
@@ -224,7 +219,6 @@ class XMLRPC extends JS.Callable {
                 if (Log.on) Log.log(this, e);
                 throw new JS.Exn("caught IOException while attempting to send a ByteStream via XML-RPC");
             }
-            */
 
         } else if (o instanceof String) {
             sb.append("                <value><string>");
@@ -420,17 +414,17 @@ class XMLRPC extends JS.Callable {
         public Filter(InputStream is) { super(is); }
         public int read() throws IOException {
             java.lang.Thread.yield();
-            while(MessageQueue.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { };
+            while(Message.Q.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { };
             return super.read();
         }
         public int read(byte[] b) throws IOException {
             java.lang.Thread.yield();
-            while(MessageQueue.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { };
+            while(Message.Q.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { };
             return super.read(b);
         }
         public int read(byte[] b, int i, int j) throws IOException {
             java.lang.Thread.yield();
-            while(MessageQueue.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { };
+            while(Message.Q.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { };
             return super.read(b, i, j);
         }
     }
index 7e7e5fe..f3368c4 100644 (file)
@@ -7,6 +7,7 @@ import java.text.*;
 import java.util.*;
 import org.xwt.js.*;
 import org.xwt.util.*;
+import org.xwt.translators.*;
 import org.bouncycastle.util.encoders.Base64;
 
 /** Singleton class that provides all functionality in the xwt.* namespace */
@@ -26,7 +27,21 @@ public final class XWT extends JS.Obj {
         else if (name.equals("control")) return Surface.control ? Boolean.TRUE : Boolean.FALSE;
         else if (name.equals("shift")) return Surface.shift ? Boolean.TRUE : Boolean.FALSE;
         else if (name.equals("clipboard")) return Platform.getClipBoard();
-        else if (name.equals("static")) return Static.getStatic("");
+        /* FIXME
+        else if (name.equals("static")) return .getStatic("");
+        */
+        else if (name.equals("origin")) return Main.origin;
+        else if (name.equals("maxdim")) return new Integer(Short.MAX_VALUE);
+        else if (name.equals("altKeyName")) return Platform.altKeyName();
+        else if (name.equals("screenWidth")) return new Integer(Platform.getScreenWidth());
+        else if (name.equals("screenHeight")) return new Integer(Platform.getScreenHeight());
+        else if (name.equals("fileSeparator")) return File.separator;
+        else if (name.equals("homeDir")) return System.getProperty("user.home");
+        else if (name.equals("tempDir")) return System.getProperty("java.io.tempdir");
+        else if (name.equals("math")) return xwtMath;
+        else if (name.equals("string")) return xwtString;
+        else if (name.equals("parseInt")) return xwtString.get("parseInt");
+        else if (name.equals("parseFloat")) return xwtString.get("parseFloat");
         else if (name.equals("button")) {
             if (Surface.button1 && !Surface.button2 && !Surface.button3) return new Integer(1);
             else if (!Surface.button1 && Surface.button2 && !Surface.button3) return new Integer(1);
@@ -46,125 +61,77 @@ public final class XWT extends JS.Obj {
         } else super.put(name, value);
     }
 
-    private XWT() {
-        super.put("maxdim", new Integer(Short.MAX_VALUE));
-        super.put("origin", Main.origin);
-        super.put("altKeyName", Platform.altKeyName());
-        super.put("screenWidth", new Integer(Platform.getScreenWidth()));
-        super.put("screenHeight", new Integer(Platform.getScreenHeight()));
-        super.put("fileSeparator", File.separator);
-        super.put("homeDir", System.getProperty("user.home"));
-        super.put("tempDir", System.getProperty("java.io.tempdir"));
-        super.put("math", xwtMath);
-        super.put("string", xwtString);
+    public Object callMethod(Object method, JS.Array args, boolean checkOnly) {
 
-        super.put("newBrowserWindow", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+        if (method.equals("newBrowserWindow")) {
+            if (checkOnly) return Boolean.TRUE;
             if (args.length() != 1 || args.elementAt(0) == null) return null;
             Platform.newBrowserWindow(args.elementAt(0).toString());
             return null;
-        }});
 
-        super.put("parseInt",xwtString.get("parseInt"));
-        super.put("parseFloat",xwtString.get("parseFloat"));
-        
-        super.put("yield", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+        } else if (method.equals("yield")) {
+            if (checkOnly) return Boolean.TRUE;
             sleep(0);
             return null;
-        }});
 
-        super.put("load", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+        } else if (method.equals("load")) {
+            if (checkOnly) return Boolean.TRUE;
             return Res.stringToRes(args.elementAt(0).toString());
-        }});
 
-        super.put("println", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+        } else if (method.equals("println")) {
+            if (checkOnly) return Boolean.TRUE;
             if (args.length() != 1) return null;
             if (Log.on) Log.logJS(this, (args.elementAt(0) == null ? "**null**" : args.elementAt(0).toString()));
             return null;
-        }});
 
-        super.put("date", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+        } else if (method.equals("date")) {
+            if (checkOnly) return Boolean.TRUE;
+            // FIXME
             Log.log(XWT.class, "date not implemented");
-            //throw new Error("not implemented");
             return null;
-        }});
 
-        super.put("regexp", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+        } else if (method.equals("regexp")) {
+            if (checkOnly) return Boolean.TRUE;
             return new Regexp(args);
-        }});
-
-        super.put("listfonts", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
-            Object[] fonts = Platform.listFonts();
-            JS.Array ret = new JS.Array();
-            for(int i=0; i<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();
@@ -181,9 +148,12 @@ public final class XWT extends JS.Obj {
                 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();
@@ -198,18 +168,14 @@ public final class XWT extends JS.Obj {
                 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()));
                     }
@@ -218,81 +184,16 @@ public final class XWT extends JS.Obj {
                     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) {
@@ -322,7 +223,6 @@ public final class XWT extends JS.Obj {
         }
     }
 
-
     public static void sleep(int i) {
         java.lang.Thread thread = java.lang.Thread.currentThread();
         if (!(thread instanceof ThreadMessage)) {
@@ -331,7 +231,7 @@ public final class XWT extends JS.Obj {
             ThreadMessage mythread = (ThreadMessage)thread;
             mythread.done.release();
             if (i > 0) try { java.lang.Thread.sleep(i); } catch (Exception e) { }
-            MessageQueue.add(mythread);
+            Message.Q.add(mythread);
             mythread.go.block();
         }
     }
index 83b9b75..9fe5435 100644 (file)
@@ -6,7 +6,7 @@ import java.io.*;
 
 // FIXME: could use some cleaning up
 /** a JavaScript function, compiled into bytecode */
-class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
+class CompiledFunctionImpl extends JS.Callable implements ByteCodes, Tokens {
 
     // Fields and Accessors ///////////////////////////////////////////////
 
index 5104bce..ea12dfb 100644 (file)
@@ -101,18 +101,23 @@ public abstract class JS {
 
     /** A sensible implementation of the abstract methods in the JS class */
     public static class Obj extends JS {
-        private Hash entries = new Hash();
+        private Hash entries = null;
         private boolean sealed = false;
         public Obj() { this(false); }
         public Obj(boolean sealed) { this.sealed = sealed; }
-        /** a sealed object cannot have its properties modified */
-        public void setSeal(boolean sealed) { this.sealed = sealed; }
-        public void put(Object key, Object val) { if (!sealed) entries.put(key, val); }
-        public Object[] keys() { return(entries.keys()); }
-        public Object get(Object key) {
-            if(callMethod((String)key,null,true) == Boolean.TRUE)
-                return new Internal.CallableStub(this,key);
-            return entries.get(key);
+        public void setSeal(boolean sealed) { this.sealed = sealed; }      ///< a sealed object cannot have its properties modified
+        public void put(Object key, Object val) { put(key, null, val); }
+        protected void put(Object key, Object key2, Object val) {
+            if (sealed) return;
+            if (entries == null) entries = new Hash();
+            entries.put(key, key2, val); }
+        public Object[] keys() { return entries == null ? new Object[0] : entries.keys(); }
+        public Object get(Object key) { return get(key, null); }
+        protected Object get(Object key, Object key2) {
+            if (entries == null) return null;
+            if(key2 == null && callMethod((String)key, null, true) == Boolean.TRUE)
+                return new Internal.CallableStub(this, key);
+            return entries.get(key, key2);
         }
     }
 
index c7888a0..6850927 100644 (file)
@@ -20,9 +20,6 @@ public class AWT extends JVM {
     protected int _getScreenWidth() { return Toolkit.getDefaultToolkit().getScreenSize().width; }
     protected int _getScreenHeight() { return Toolkit.getDefaultToolkit().getScreenSize().height; }
     protected Surface _createSurface(Box b, boolean framed) { return new AWTSurface(b, framed); }
-    protected int _stringWidth(String font, String text) { return getFont(font).metrics.stringWidth(text); }
-    protected int _getMaxAscent(String font) { return getFont(font).metrics.getMaxAscent(); }
-    protected int _getMaxDescent(String font) { return getFont(font).metrics.getMaxDescent(); }
     protected boolean _supressDirtyOnResize() { return false; }
 
     protected void postInit() {
@@ -170,13 +167,6 @@ public class AWT extends JVM {
             g.drawImage(((AWTPicture)source).i, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null);
         }
         
-        public void drawString(String font, String text, int x, int y, int argb) {
-            // FEATURE: use an LRU cache for Color objects
-            g.setColor(new Color((argb & 0x00FF0000) >> 16, (argb & 0x0000FF00) >> 8, (argb & 0x000000FF)));
-            g.setFont(getFont(font));
-            g.drawString(text, x, y + 2);
-        }
-        
         public void fillRect(int x, int y, int x2, int y2, int argb) {
             // FEATURE: use an LRU cache for Color objects
             g.setColor(new Color((argb & 0x00FF0000) >> 16, (argb & 0x0000FF00) >> 8, (argb & 0x000000FF)));
@@ -186,7 +176,7 @@ public class AWT extends JVM {
     }
     
     
-    protected static class AWTSurface extends Surface
+    protected static class AWTSurface extends Surface.DoubleBufferedSurface
         implements MouseListener, MouseMotionListener, KeyListener, ComponentListener, WindowListener {
 
         public void blit(PixelBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2) {
@@ -210,7 +200,7 @@ public class AWT extends JVM {
         
         public void toBack() { if (window != null) window.toBack(); }
         public void toFront() { if (window != null) window.toFront(); }
-        public void setLocation(int x, int y) { window.setLocation(x, y); }
+        public void setLocation() { window.setLocation(root.x, root.y); }
         public void setTitleBarText(String s) { if (frame != null) frame.setTitle(s); }
         public void setIcon(Picture i) { if (frame != null) frame.setIconImage(((AWTPicture)i).i); }
         public void setSize(int width, int height) { window.setSize(width + (insets.left + insets.right), height + (insets.top + insets.bottom)); }
@@ -408,9 +398,9 @@ public class AWT extends JVM {
         }
     }
 
-    protected ImageDecoder _decodeJPEG(InputStream is, String name) {
+    protected Picture _decodeJPEG(InputStream is, String name) {
         try {
-            Image i = Toolkit.getDefaultToolkit().createImage(org.xwt.Resources.isToByteArray(is));
+            Image i = Toolkit.getDefaultToolkit().createImage(InputStreamToByteArray.convert(is));
             MediaTracker mediatracker = new MediaTracker(new Canvas());
             mediatracker.addImage(i, 1);
             try { mediatracker.waitForAll(); } catch (InterruptedException e) { }
@@ -424,59 +414,11 @@ public class AWT extends JVM {
                 Log.log(this, "PixelGrabber reported an error while decoding JPEG image " + name);
                 return null;
             }
-            return new ImageDecoder() {
-                    public int getWidth() { return width; }
-                    public int getHeight() { return height; }
-                    public int[] getData() { return data; }
-                };
+            return Platform.createPicture(data, width, height);
         } catch (Exception e) {
             Log.log(this, "Exception caught while decoding JPEG image " + name);
             Log.log(this, e);
             return null;
         }
     }
-
-    // Font Handling Stuff //////////////////////////////////////////////////////////
-
-    protected String[] _listFonts() { return fontList; }
-    private static String[] fontList;
-    static {
-        /*
-        String[] awtfonts = Toolkit.getDefaultToolkit().getFontList();
-        fontList = new String[awtfonts.length * 4];
-        for(int i=0; i<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);
-        }
-    }
-            
 }