Stream->Fountain, move Scheduler to Platform, HashMap->Hash
authoradam <adam@megacz.com>
Sun, 16 Jan 2005 05:17:03 +0000 (05:17 +0000)
committeradam <adam@megacz.com>
Sun, 16 Jan 2005 05:17:03 +0000 (05:17 +0000)
darcs-hash:20050116051703-5007d-1240d7e546d891f6faf8af2a340607b685092c2c.gz

12 files changed:
src/org/ibex/core/Box.java
src/org/ibex/core/Ibex.java
src/org/ibex/core/Main.java
src/org/ibex/core/Scheduler.java [deleted file]
src/org/ibex/core/Stream.java [deleted file]
src/org/ibex/graphics/Font.java
src/org/ibex/graphics/MSPack.java
src/org/ibex/graphics/Picture.java
src/org/ibex/graphics/Surface.java
src/org/ibex/plat/Darwin.java
src/org/ibex/plat/OpenGL.java
src/org/ibex/plat/Platform.java

index 16bae85..0ccd421 100644 (file)
@@ -58,7 +58,7 @@ public final class Box extends JS.Obj implements Callable {
     //#define CHECKSET_STRING(prop) if ((value==null&&prop==null)||(value!=null&&JSU.toString(value).equals(prop))) break; prop=JSU.toString(value);
 
     // FIXME memory leak
-    static Basket.Map boxToCursor = new Basket.HashMap(500, 3);
+    static Basket.Map boxToCursor = new Basket.Hash(500, 3);
 
     static final Font DEFAULT_FONT;
     static {
@@ -608,9 +608,9 @@ public final class Box extends JS.Obj implements Callable {
             JSU.error("redirect can only be set to a descendant of its current value");
         case "fontsize": font = Font.getFont(font == null ? null : font.stream, JSU.toInt(value)); RECONSTRAIN(); dirty();
         case "font":
-            if(!(value instanceof Stream)) throw new JSExn("You can only put streams to the font property");
+            if(!(value instanceof Fountain)) throw new JSExn("You can only put streams to the font property");
             //FIXME: if (font == value) return;  // FIXME: unclone()
-            font = value == null ? null : Font.getFont((Stream)value, font == null ? 10 : font.pointsize);
+            font = value == null ? null : Font.getFont((Fountain)value, font == null ? 10 : font.pointsize);
             RECONSTRAIN();
             dirty();
         case "x": if (parent==null && Surface.fromBox(this)!=null) {
index bd133c7..4110a8d 100644 (file)
@@ -19,7 +19,7 @@ public final class Ibex extends JS.Obj implements JS.Cloneable {
     private final JS rr;
     private static final JS.Method METHOD = new JS.Method();
 
-    public Ibex(Stream rr) { try { this.rr = bless(rr);} catch(JSExn e) { throw new Error("should never happen: " + e); } }
+    public Ibex(Fountain rr) { try { this.rr = bless(rr);} catch(JSExn e) { throw new Error("should never happen: " + e); } }
 
     public JS resolveString(String str, boolean permitAbsolute) throws JSExn {
         if (str.indexOf("://") != -1) {
@@ -132,7 +132,7 @@ public final class Ibex extends JS.Obj implements JS.Cloneable {
 
     public void put(JS name, JS value) throws JSExn {
         //#switch(JSU.toString(name))
-        case "thread": Scheduler.add((Callable)value); return;
+        case "thread": Platform.Scheduler.add((Callable)value); return;
         case "ui.clipboard": Platform.setClipBoard(JSU.toString(value)); return;
         case "ui.frame": Platform.createSurface((Box)value, true, true); return;
         case "ui.window": Platform.createSurface((Box)value, false, true); return;
@@ -173,17 +173,17 @@ public final class Ibex extends JS.Obj implements JS.Cloneable {
                         return new JS.Clone((JS)args[0]);
                     case "bless": return bless((JS)args[0]);
                     case "ui.browser": Platform.newBrowserWindow(JSU.toString(args[0])); return null;
-                    case "stream.unzip": return args[0] == null ? null : new Stream.Zip((Stream)args[0]);
+                    case "stream.unzip": return args[0] == null ? null : new Fountain.Zip((Fountain)args[0]);
                        //case "stream.uncab": return a == null ? null : new Stream.Cab(a);
                     case "stream.cache":
-                        try { return args[0] == null ? null : new Stream.CachedStream((Stream)args[0], "resources", true); }
-                        catch (Stream.NotCacheableException e) { throw new JSExn("this resource cannot be cached"); }
+                        //try { return args[0] == null ? null : new Fountain.CachedStream((Stream)args[0], "resources", true); }
+                        //catch (Stream.NotCacheableException e) { throw new JSExn("this resource cannot be cached"); }
                     case "stream.url": {
                         String url = JSU.toString(args[0]);
-                        if (url.startsWith("http://")) return new Stream.HTTP(url);
-                        else if (url.startsWith("https://")) return new Stream.HTTP(url);
-                        else if (url.startsWith("data:")) return new Stream.ByteArray(Encode.fromBase64(url.substring(5)), null);
-                        else if (url.startsWith("utf8:")) return new Stream.ByteArray(url.substring(5).getBytes(), null);
+                        if (url.startsWith("http://")) return new Fountain.HTTP(url);
+                        else if (url.startsWith("https://")) return new Fountain.HTTP(url);
+                        else if (url.startsWith("data:")) return new Fountain.ByteArray(Encode.fromBase64(url.substring(5)), null);
+                        else if (url.startsWith("utf8:")) return new Fountain.ByteArray(url.substring(5).getBytes(), null);
                         else if (url.startsWith("file:")) {
                             // FIXME
                             Platform.fileDialog(url.substring(5), false);
@@ -207,7 +207,15 @@ public final class Ibex extends JS.Obj implements JS.Cloneable {
                     break;
                 case 2:
                     //#switch(JSU.toString(method))
-                    case "stream.watch": return new Stream.ProgressWatcher((Stream)args[0], args[1]);
+                    case "stream.watch":
+                        final JS func = args[1];
+                        return new Fountain.ProgressWatcher((Fountain)args[0],
+                                                            new Callable() {
+                                                                public Object run(Object o) throws Exception {
+                                                                    JS[] args = (JS[])o;
+                                                                    return func.call(null, args);
+                                                                }
+                                                            });
                     case "regexp": return new JSRegexp(args[0], args[1]);
                     //#end
                 case 3:
@@ -228,10 +236,10 @@ public final class Ibex extends JS.Obj implements JS.Cloneable {
     }
 
     public JS url2res(String url) throws JSExn {
-        if (url.startsWith("http://")) return new Stream.HTTP(url);
-        else if (url.startsWith("https://")) return new Stream.HTTP(url);
-        else if (url.startsWith("data:")) return new Stream.ByteArray(Encode.fromBase64(url.substring(5)), null);
-        else if (url.startsWith("utf8:")) return new Stream.ByteArray(url.substring(5).getBytes(), null);
+        if (url.startsWith("http://")) return new Fountain.HTTP(url);
+        else if (url.startsWith("https://")) return new Fountain.HTTP(url);
+        else if (url.startsWith("data:")) return new Fountain.ByteArray(Encode.fromBase64(url.substring(5)), null);
+        else if (url.startsWith("utf8:")) return new Fountain.ByteArray(url.substring(5).getBytes(), null);
         else throw new JSExn("invalid resource specifier " + url);
         // FIXME support file:// via dialog boxes
     }
@@ -242,7 +250,7 @@ public final class Ibex extends JS.Obj implements JS.Cloneable {
             // FEATURE use a single sleeper thread
             new Thread() { public void run() {
                 try { Thread.sleep(i); } catch (InterruptedException e) { }
-                Scheduler.add(callback);
+                Platform.Scheduler.add(callback);
             } }.start();
         } catch (Pausable.NotPausableException npe) {
             throw new JSExn("you cannot sleep or yield in the foreground thread");
@@ -368,7 +376,7 @@ public final class Ibex extends JS.Obj implements JS.Cloneable {
         public JS parentkey = null;
         public Blessing parent = null;
         public JS clonee;
-        private Basket.Map cache = new Basket.HashMap(); 
+        private Basket.Map cache = new Basket.Hash(); 
         public Blessing(JS clonee, Ibex ibex, Blessing parent, JS parentkey) throws JSExn {
             this.clonee = clonee; this.ibex = ibex; this.parentkey = parentkey; this.parent = parent; }
         public JS get(JS key) throws JSExn {
@@ -386,16 +394,16 @@ public final class Ibex extends JS.Obj implements JS.Cloneable {
         }
         // FEATURE: This is a gross hack
         public InputStream getImage() throws JSExn {
-            //try {
+            try {
                 InputStream in = JSU.getInputStream(this);
                 if (in != null) return in;
-                //} catch (IOException e) { /* DELIBERATE */ }
+            } catch (IOException e) { /* DELIBERATE */ }
             String[] exts = new String[] { ".png", ".jpeg", ".gif" };
             for (int i=0; i < exts.length; i++) {
-                //try {
-                in = JSU.getInputStream(parent.get(JSU.S(JSU.toString(parentkey) + exts[i])));
+                try {
+                    InputStream in = JSU.getInputStream(parent.get(JSU.S(JSU.toString(parentkey) + exts[i])));
                     if (in != null) return in;
-                    //} catch (IOException f) { /* DELIBERATE */ }
+                } catch (IOException f) { /* DELIBERATE */ }
             }
             return null;
         }
index a870384..a9c35df 100644 (file)
@@ -29,7 +29,7 @@ public class Main {
     public static String origin = null;
     public static String initialTemplate = null;
     
-    public static final Stream builtin = new Stream.Zip(new Stream.Builtin());
+    public static final Fountain builtin = new Fountain.Zip(new Fountain.FromInputStream(Platform.getBuiltinInputStream()));
 
     public static void printUsage() {
         System.err.println("Usage: ibex [-lawp] [ url | file | directory ]");
@@ -79,7 +79,7 @@ public class Main {
         initialTemplate = args.length > startargs + 1 ? args[startargs + 1] : "main";
         origin = args[startargs];
 
-        Stream rr;
+        Fountain rr;
         final String startupTemplate;
         if (origin.startsWith("http://") || origin.startsWith("https://")) {
             originHost = origin.substring(origin.indexOf('/') + 2);
@@ -88,11 +88,11 @@ public class Main {
             originAddr = InetAddress.getByName(originHost);
             //rr = builtin;
             //startupTemplate = "org.ibex.builtin.splash";
-            rr = new Stream.HTTP(origin);
+            rr = new Fountain.HTTP(origin);
             startupTemplate = initialTemplate;
         } else {
-            rr = new Stream.File(origin);
-            if (!new File(origin).isDirectory()) rr = new Stream.Zip(rr);
+            rr = new Fountain.File(origin);
+            if (!new File(origin).isDirectory()) rr = new Fountain.Zip(rr);
             startupTemplate = initialTemplate;
         }
 
@@ -100,7 +100,7 @@ public class Main {
         final Ibex ibex = new Ibex(rr);
 
         org.ibex.graphics.Surface.scarImage =
-            Picture.load(new Stream.FromInputStream(Encode.JavaSourceCode.decode(Scar.data)),
+            Picture.load(new Fountain.FromInputStream(Encode.JavaSourceCode.decode(Scar.data)),
                          new Callable() {
                              private final JS[] callargs = new JS[1];
                              public Object run(Object o) throws JSExn,UnknownHostException {
@@ -112,6 +112,6 @@ public class Main {
                                  return null;
                          } });
 
-        Scheduler.init();
+        Platform.Scheduler.init();
     }
 }
diff --git a/src/org/ibex/core/Scheduler.java b/src/org/ibex/core/Scheduler.java
deleted file mode 100644 (file)
index 8fdb506..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2000-2005 the Contributors, as shown in the revision logs.
-// Licensed under the GNU General Public License version 2 ("the License").
-// You may not use this file except in compliance with the License.
-
-package org.ibex.core;
-
-import java.io.IOException;
-
-import org.ibex.js.*;
-import org.ibex.util.*;
-import org.ibex.graphics.*;
-import org.ibex.plat.*;
-
-/** Implements cooperative multitasking */
-public class Scheduler {
-
-    // Public API Exposed to org.ibex /////////////////////////////////////////////////
-
-    private static Scheduler singleton;
-    public static void add(Callable t) { Log.debug(Scheduler.class, "scheduling " + t); Scheduler.runnable.append(t); }
-    public static void init() { if (singleton == null) (singleton = Platform.getScheduler()).run(); }
-
-    private static Callable current = null;
-
-    private static volatile boolean rendering = false;
-    private static volatile boolean again = false;
-
-    /** synchronizd so that we can safely call it from an event-delivery thread, in-context */
-    public static void renderAll() {
-        if (rendering) { again = true; return; }
-        synchronized(Scheduler.class) {
-            try {
-                rendering = true;
-                do {
-                    // FEATURE: this could be cleaner
-                    again = false;
-                    for(int i=0; i<Surface.allSurfaces.size(); i++) {
-                        Surface s = ((Surface)Surface.allSurfaces.elementAt(i));
-                        do { s.render(); } while(s.abort);
-                    }
-                } while(again);
-            } finally {
-                rendering = false;
-            }
-        }
-    }
-
-    
-
-    // API which must be supported by subclasses /////////////////////////////////////
-
-    /**
-     *  SCHEDULER INVARIANT: all scheduler implementations MUST invoke
-     *  Surface.renderAll() after performing a Callable if no tasks remain
-     *  in the queue.  A scheduler may choose to invoke
-     *  Surface.renderAll() more often than that if it so chooses.
-     */
-    public void run() { defaultRun(); }
-    public Scheduler() { }
-
-
-    // Default Implementation //////////////////////////////////////////////////////
-
-    protected static Queue runnable = new Queue(50);
-    public void defaultRun() {
-        while(true) {
-            current = (Callable)runnable.remove(true);
-            try {
-                // FIXME hideous
-                synchronized(this) {
-                    for(int i=0; i<Surface.allSurfaces.size(); i++) {
-                        Surface s = (Surface)Surface.allSurfaces.elementAt(i);
-                        if (current instanceof JS) {
-                            s._mousex = Integer.MAX_VALUE;
-                            s._mousey = Integer.MAX_VALUE;
-                        } else {
-                            s._mousex = s.mousex;
-                            s._mousey = s.mousey;
-                        }
-                    }
-                    Log.debug(Scheduler.class, "performing " + current);
-                    current.run(null);
-                }
-                renderAll();
-            } catch (JSExn e) {
-                Log.info(Scheduler.class, "a JavaScript thread spawned with ibex.thread() threw an exception:");
-                Log.info(Scheduler.class,e);
-            } catch (Exception e) {
-                Log.info(Scheduler.class, "a Callable threw an exception which was caught by the scheduler:");
-                Log.info(Scheduler.class, e);
-            } catch (Throwable t) {
-                t.printStackTrace();
-            }
-            // if an Error is thrown it will cause the engine to quit
-        }
-    }
-}
diff --git a/src/org/ibex/core/Stream.java b/src/org/ibex/core/Stream.java
deleted file mode 100644 (file)
index c3f9ca0..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright 2000-2005 the Contributors, as shown in the revision logs.
-// Licensed under the GNU General Public License version 2 ("the License").
-// You may not use this file except in compliance with the License.
-
-package org.ibex.core;
-
-import java.io.*;
-import java.util.zip.*;
-import org.ibex.js.*;
-import org.ibex.util.*;
-import org.ibex.plat.*;
-import org.ibex.net.*;
-
-/**
- *   Essentiall an InputStream "factory".  You can repeatedly ask a
- *   Stream for an InputStream, and each InputStream you get back will
- *   be totally independent of the others (ie separate stream position
- *   and state) although they draw from the same data source.
- */
-public abstract class Stream extends JS.Obj implements JS.Cloneable {
-
-    // Public Interface //////////////////////////////////////////////////////////////////////////////
-
-    public static InputStream getInputStream(Object js) throws IOException { return ((Stream)((JS)js).unclone()).getInputStream();}
-    public static class NotCacheableException extends Exception { }
-
-    // streams are "sealed" by default to prevent accidental object leakage
-    private Cache getCache = new Cache(100, true);
-    protected JS _get(JS key) throws JSExn { return null; }
-    public final JS get(JS key) throws JSExn {
-        JS ret = (JS)getCache.get(key);
-        if (ret == null) getCache.put(key, ret = _get(key));
-        return ret;
-    }
-
-    // Private Interface //////////////////////////////////////////////////////////////////////////////
-
-    public abstract InputStream getInputStream() throws IOException;
-    protected String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); }
-
-    /** HTTP or HTTPS resource */
-    public static class HTTP extends Stream {
-        private String url;
-        //public String toString() { return "Stream.HTTP:" + url; }
-        public HTTP(String url) { while (url.endsWith("/")) url = url.substring(0, url.length() - 1); this.url = url; }
-        public JS _get(JS key) throws JSExn { return new HTTP(url + "/" + JSU.toString(key)); }
-        public String getCacheKey(Vec path) throws NotCacheableException { return url; }
-        public InputStream getInputStream() throws IOException { return new org.ibex.net.HTTP(url).GET(null, null); }
-    }
-
-    /** byte arrays */
-    public static class ByteArray extends Stream {
-        private byte[] bytes;
-        private String cacheKey;
-        public ByteArray(byte[] bytes, String cacheKey) { this.bytes = bytes; this.cacheKey = cacheKey; }
-        public String getCacheKey() throws NotCacheableException {
-            if (cacheKey == null) throw new NotCacheableException(); return cacheKey; }
-        public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(bytes); }
-    }
-
-    /** a file */
-    public static class File extends Stream {
-        private String path;
-        public File(String path) { this.path = path; }
-        //public String toString() { return "file:" + path; }
-        public String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); /* already on disk */ }
-        public InputStream getInputStream() throws IOException { return new FileInputStream(path); }
-        public JS _get(JS key) throws JSExn {
-            System.out.println("get: " + JSU.str(key));
-            return new File(path + java.io.File.separatorChar + JSU.toString(key)); }
-    }
-
-    /** "unwrap" a Zip archive */
-    public static class Zip extends Stream {
-        private Stream parent;
-        private String path;
-        public Zip(Stream parent) { this(parent, null); }
-        public Zip(Stream parent, String path) {
-            while(path != null && path.startsWith("/")) path = path.substring(1);
-            this.parent = parent;
-            this.path = path;
-        }
-        public String getCacheKey() throws NotCacheableException { return parent.getCacheKey() + "!zip:"; }
-        public JS _get(JS key) throws JSExn { return new Zip(parent, path==null?JSU.toString(key):path+'/'+JSU.toString(key)); }
-        public InputStream getInputStream() throws IOException {
-            InputStream pis = parent.getInputStream();
-            ZipInputStream zis = new ZipInputStream(pis);
-            ZipEntry ze = zis.getNextEntry();
-            while(ze != null && !ze.getName().equals(path)) ze = zis.getNextEntry();
-            if (ze == null) throw new IOException("requested file (" + path + ") not found in archive");
-            return new KnownLength.KnownLengthInputStream(zis, (int)ze.getSize());
-        }
-    }
-
-    /** "unwrap" a Cab archive */
-    /*
-    public static class Cab extends Stream {
-        private Stream parent;
-        private String path;
-        public Cab(Stream parent) { this(parent, null); }
-        public Cab(Stream parent, String path) { this.parent = parent; this.path = path; }
-        public String getCacheKey() throws NotCacheableException { return parent.getCacheKey() + "!cab:"; }
-        public JS _get(JS key) throws JSExn { return new Cab(parent, path==null?(String)key:path+'/'+(String)key); }
-        public InputStream getInputStream() throws IOException { return new MSPack(parent.getInputStream()).getInputStream(path); }
-    }
-    */
-
-    /** the Builtin resource */
-    public static class Builtin extends Stream {
-        public String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); }
-        public InputStream getInputStream() throws IOException { return Platform.getBuiltinInputStream(); }
-    }
-
-    /** the Builtin resource */
-    public static class FromInputStream extends Stream {
-        private final InputStream is;
-        public FromInputStream(InputStream is) { this.is = is; }
-        public String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); }
-        public InputStream getInputStream() throws IOException { return is; }
-    }
-
-    /** shadow resource which replaces the graft */
-    public static class ProgressWatcher extends Stream {
-        private final JS[] callargs = new JS[2];
-        final Stream watchee;
-        JS callback;
-        public ProgressWatcher(Stream watchee, JS callback) { this.watchee = watchee; this.callback = callback; }
-        public String getCacheKey() throws NotCacheableException { return watchee.getCacheKey(); }
-        public InputStream getInputStream() throws IOException {
-            final InputStream is = watchee.getInputStream();
-            return new FilterInputStream(is) {
-                    int bytesDownloaded = 0;
-                    public int read() throws IOException {
-                        int ret = super.read();
-                        if (ret != -1) bytesDownloaded++;
-                        return ret;
-                    }
-                    public int read(byte[] b, int off, int len) throws IOException {
-                        int ret = super.read(b, off, len);
-                        if (ret != 1) bytesDownloaded += ret;
-                        Scheduler.add(new Callable() {
-                            public Object run(Object o) throws IOException, JSExn {
-                                try {
-                                    int len = is instanceof KnownLength.KnownLengthInputStream ?
-                                                ((KnownLength.KnownLengthInputStream)is).getLength() : 0;
-                                    callargs[0] = JSU.N(bytesDownloaded);
-                                    callargs[1] = JSU.N(len);
-                                    callback.call(null, callargs);
-                                } finally { callargs[0] = callargs[1] = null; }
-                                return null;
-                        } });
-                        return ret;
-                    }
-                };
-        }
-    }
-
-    /** subclass from this if you want a CachedInputStream for each path */
-    public static class CachedStream extends Stream {
-        private Stream parent;
-        private boolean disk = false;
-        private String key;
-        public String getCacheKey() throws NotCacheableException { return key; }
-        CachedInputStream cis = null;
-        public CachedStream(Stream p, String s, boolean d) throws NotCacheableException {
-            this.parent = p; this.disk = d; this.key = p.getCacheKey();
-        }
-        public InputStream getInputStream() throws IOException {
-            if (cis != null) return cis.getInputStream();
-            if (!disk) {
-                cis = new CachedInputStream(parent.getInputStream());
-            } else {
-                java.io.File f = org.ibex.core.LocalStorage.Cache.getCacheFileForKey(key);
-                if (f.exists()) return new FileInputStream(f);
-                cis = new CachedInputStream(parent.getInputStream(), f);
-            }
-            return cis.getInputStream();
-        }
-    }
-}
index 8b80439..99c9bdc 100644 (file)
@@ -7,7 +7,6 @@ import org.ibex.util.*;
 import java.io.*;
 import java.util.Hashtable;
 import org.ibex.js.*;
-import org.ibex.core.*;
 import org.ibex.nestedvm.*;
 import org.ibex.plat.*;
 import org.ibex.nestedvm.Runtime;
@@ -50,12 +49,12 @@ public class Font {
     static final Hashtable glyphsToBeCached = new Hashtable();
     static final Hashtable glyphsToBeDisplayed = new Hashtable();
     // HACK: replace with Cache<JS, int>
-    private static Basket.Map fonts = new Basket.HashMap();
+    private static Basket.Map fonts = new Basket.Hash();
     public static Font getFont(JS stream, int pointsize) {
         Basket.Map m = (Basket.Map)fonts.get(stream);
         Font ret = null;
         if (m != null) ret = (Font)m.get(new Integer(pointsize));
-        else fonts.put(stream, m = new Basket.HashMap());
+        else fonts.put(stream, m = new Basket.Hash());
         if (ret == null) m.put(new Integer(pointsize), ret = new Font(stream, pointsize));
         return ret;
     }
@@ -77,7 +76,7 @@ public class Font {
             for(int i=32; i<47; i++) if (glyphs[i]==null) glyphsToBeCached.put(glyphs[i]=Platform.createGlyph(this, (char)i),"");
             for(int i=57; i<128; i++) if (glyphs[i]==null) glyphsToBeCached.put(glyphs[i]=Platform.createGlyph(this, (char)i),"");
             if (!glyphRenderingTaskIsScheduled) {
-                Scheduler.add(glyphRenderingTask);
+                Platform.Scheduler.add(glyphRenderingTask);
                 glyphRenderingTaskIsScheduled = true;
             }
             latinCharsPreloaded = true;
@@ -131,7 +130,7 @@ public class Font {
         g.render();
         Log.debug(Glyph.class, "   done rendering glyph " + g.c);
         glyphRenderingTaskIsScheduled = true;
-        Scheduler.add(this);
+        Platform.Scheduler.add(this);
         return null;
     } };
 
index 36de110..3135fed 100644 (file)
@@ -4,7 +4,6 @@
 
 package org.ibex.graphics;
 
-import org.ibex.core.Main;
 import org.ibex.util.*;
 import java.io.*;
 import org.ibex.nestedvm.*;
index c8b5895..ce7b20b 100644 (file)
@@ -7,7 +7,6 @@ import java.io.*;
 import org.ibex.js.*;
 import org.ibex.plat.*;
 import org.ibex.util.*;
-import org.ibex.core.*;
 
 /** 
  *    The in-memory representation of a PNG or GIF image. It is
@@ -44,14 +43,12 @@ public class Picture {
         }
         final Picture p = ret;
         if (!ret.isLoaded && callback != null) {
-            // FEATURE: This is kind of ugly - shouldn't need a blessing
-            final Ibex.Blessing b = Ibex.Blessing.getBlessing(stream);
             new java.lang.Thread() { public void run() {
                 InputStream in = null;
                 try {
-                    in = b == null ? JSU.getInputStream(stream) : b.getImage();
-                //} catch (IOException e) { Log.error(Picture.class, e);
-                } catch (JSExn e) { Log.error(Picture.class, e);
+                    in = JSU.getInputStream(stream);
+                } catch (IOException e) { Log.error(Picture.class, e);
+                //} catch (JSExn e) { Log.error(Picture.class, e);
                 }
                 if (in == null) { Log.warn(Picture.class, "couldn't load image for stream " + stream.unclone()); return; }
                 try {
@@ -64,7 +61,7 @@ public class Picture {
                     else if ((firstByte & 0xff) == 0xff) Platform.decodeJPEG(pbis, p);
                     else throw new JSExn("couldn't figure out image type from first byte");
                     p.loaded();
-                    Scheduler.add(callback);
+                    Platform.Scheduler.add(callback);
                 } catch (Exception e) {
                     Log.info(this, "exception while loading image");
                     Log.info(this, e);
index 7658ec5..0f29914 100644 (file)
@@ -7,8 +7,7 @@ package org.ibex.graphics;
 import org.ibex.js.*;
 import org.ibex.util.*;
 import org.ibex.plat.*;
-
-import org.ibex.core.*;  // FIXME
+import org.ibex.core.*;
 
 /** 
  *  A Surface, as described in the Ibex Reference.
@@ -23,7 +22,7 @@ public abstract class Surface implements Callable {
     private static final JS T = JSU.T;
     private static final JS F = JSU.F;
 
-    /** all instances of Surface which need to be refreshed by the Scheduler */
+    /** all instances of Surface which need to be refreshed by the Platform.Scheduler */
     public static Vec allSurfaces = new Vec();
     
     /** When set to true, render() should abort as soon as possible and restart the rendering process */
@@ -97,7 +96,7 @@ public abstract class Surface implements Callable {
         if (button == 1) new Message("_Press1", T, root);
         else if (button == 2) new Message("_Press2", T, root);
         else if (button == 3) {
-            Scheduler.add(new Callable() { public Object run(Object o) throws JSExn {
+            Platform.Scheduler.add(new Callable() { public Object run(Object o) throws JSExn {
                 Platform.clipboardReadEnabled = true;
                 try {
                     root.putAndTriggerTraps(JSU.S("_Press3"), T);
@@ -136,7 +135,7 @@ public abstract class Surface implements Callable {
     }
 
     private final static JS MOVE = JSU.S("_Move");
-    /** we enqueue ourselves in the Scheduler when we have a Move message to deal with */
+    /** we enqueue ourselves in the Platform.Scheduler when we have a Move message to deal with */
     private Callable mover = new Callable() {
         public Object run(Object o) {
                 if (mousex == newmousex && mousey == newmousey) return null;
@@ -159,7 +158,7 @@ public abstract class Surface implements Callable {
     protected final void Move(final int newmousex, final int newmousey) {
         this.newmousex = newmousex;
         this.newmousey = newmousey;
-        Scheduler.add(mover);
+        Platform.Scheduler.add(mover);
     }
 
     protected final void HScroll(int pixels) { new Message("_HScroll", JSU.N(pixels), root); }
@@ -174,12 +173,12 @@ public abstract class Surface implements Callable {
         pendingHeight = height;
         syncRootBoxToSurface = true;
         abort = true;
-        Scheduler.renderAll();
+        Platform.Scheduler.renderAll();
     }
 
     // FEATURE: can we avoid creating objects here?
     protected final void PosChange(final int x, final int y) {
-        Scheduler.add(new Callable() { public Object run(Object o) throws JSExn {
+        Platform.Scheduler.add(new Callable() { public Object run(Object o) throws JSExn {
             root.x = x;
             root.y = y;
             root.putAndTriggerTrapsAndCatchExceptions(JSU.S("PosChange"), T);
@@ -197,8 +196,8 @@ public abstract class Surface implements Callable {
     protected final void Focused(boolean b) { new Message("Focused", b ? T : F, root); }
 
     private boolean scheduled = false;
-    public void Refresh() { if (!scheduled) Scheduler.add(this); scheduled = true; }
-    public Object run(Object o) { scheduled = false; Scheduler.renderAll(); return null; }
+    public void Refresh() { if (!scheduled) Platform.Scheduler.add(this); scheduled = true; }
+    public Object run(Object o) { scheduled = false; Platform.Scheduler.renderAll(); return null; }
 
     public final void setMaximized(boolean b) { if (b != maximized) _setMaximized(maximized = b); }
     public final void setMinimized(boolean b) { if (b != minimized) _setMinimized(minimized = b); }
@@ -318,7 +317,7 @@ public abstract class Surface implements Callable {
             this.boxContainingMouse = boxContainingMouse;
             this.name = name;
             this.value = value;
-            Scheduler.add(this);
+            Platform.Scheduler.add(this);
         }
         
         public Object run(Object o) throws JSExn {
@@ -414,7 +413,7 @@ public abstract class Surface implements Callable {
         // 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);
-            Scheduler.renderAll();
+            Platform.Scheduler.renderAll();
         }
 
         public void dirty(int x, int y, int w, int h) {
index c5c7e9c..be54028 100644 (file)
@@ -94,9 +94,9 @@ public class Darwin extends POSIX {
         natInit();
     }
     
-    protected Scheduler _getScheduler() { return new DarwinScheduler(); }
+    protected Platform.Scheduler _getScheduler() { return new DarwinScheduler(); }
     protected native void runApplicationEventLoop();
-    private class DarwinScheduler extends org.ibex.core.Scheduler {
+    private class DarwinScheduler extends Scheduler {
         public void run() {
             new Thread() { public void run() { defaultRun(); } }.start();
             runApplicationEventLoop();
index 5b9590a..b852437 100644 (file)
@@ -143,7 +143,7 @@ abstract class OpenGL {
     public void deleteTexture(final int tex) {
         // CHECKME: Is this safe to do from finalize()?
         // natDeleteTexture MUST be run from the message queue thread
-        Scheduler.add(new Callable() { public Object run(Object o) { natDeleteTexture(tex); return null; }});
+        Platform.Scheduler.add(new Callable() { public Object run(Object o) { natDeleteTexture(tex); return null; }});
     }
     
     private static abstract class GLPicture {
index 321a80d..389caa4 100644 (file)
@@ -293,6 +293,91 @@ public abstract class Platform {
             return p;
         }
     }
+
+    /** Implements cooperative multitasking */
+    public static class Scheduler {
+
+    // Public API Exposed to org.ibex /////////////////////////////////////////////////
+
+    private static Scheduler singleton;
+    public static void add(Callable t) { Log.debug(Scheduler.class, "scheduling " + t); Scheduler.runnable.append(t); }
+    public static void init() { if (singleton == null) (singleton = Platform.getScheduler()).run(); }
+
+    private static Callable current = null;
+
+    private static volatile boolean rendering = false;
+    private static volatile boolean again = false;
+
+    /** synchronizd so that we can safely call it from an event-delivery thread, in-context */
+    public static void renderAll() {
+        if (rendering) { again = true; return; }
+        synchronized(Scheduler.class) {
+            try {
+                rendering = true;
+                do {
+                    // FEATURE: this could be cleaner
+                    again = false;
+                    for(int i=0; i<Surface.allSurfaces.size(); i++) {
+                        Surface s = ((Surface)Surface.allSurfaces.elementAt(i));
+                        do { s.render(); } while(s.abort);
+                    }
+                } while(again);
+            } finally {
+                rendering = false;
+            }
+        }
+    }
+
+    
+
+        // API which must be supported by subclasses /////////////////////////////////////
+
+        /**
+         *  SCHEDULER INVARIANT: all scheduler implementations MUST invoke
+         *  Surface.renderAll() after performing a Callable if no tasks remain
+         *  in the queue.  A scheduler may choose to invoke
+         *  Surface.renderAll() more often than that if it so chooses.
+         */
+        public void run() { defaultRun(); }
+        public Scheduler() { }
+
+
+        // Default Implementation //////////////////////////////////////////////////////
+
+        protected static Queue runnable = new Queue(50);
+        public void defaultRun() {
+            while(true) {
+                current = (Callable)runnable.remove(true);
+                try {
+                    // FIXME hideous
+                    synchronized(this) {
+                        for(int i=0; i<Surface.allSurfaces.size(); i++) {
+                            Surface s = (Surface)Surface.allSurfaces.elementAt(i);
+                            if (current instanceof JS) {
+                                s._mousex = Integer.MAX_VALUE;
+                                s._mousey = Integer.MAX_VALUE;
+                            } else {
+                                s._mousex = s.mousex;
+                                s._mousey = s.mousey;
+                            }
+                        }
+                        Log.debug(Scheduler.class, "performing " + current);
+                        current.run(null);
+                    }
+                    renderAll();
+                } catch (JSExn e) {
+                    Log.info(Scheduler.class, "a JavaScript thread spawned with ibex.thread() threw an exception:");
+                    Log.info(Scheduler.class,e);
+                } catch (Exception e) {
+                    Log.info(Scheduler.class, "a Callable threw an exception which was caught by the scheduler:");
+                    Log.info(Scheduler.class, e);
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                }
+                // if an Error is thrown it will cause the engine to quit
+            }
+        }
+    }
 }