From: adam Date: Sun, 16 Jan 2005 05:17:03 +0000 (+0000) Subject: Stream->Fountain, move Scheduler to Platform, HashMap->Hash X-Git-Tag: 01-July-2005~24 X-Git-Url: http://git.megacz.com/?p=org.ibex.core.git;a=commitdiff_plain;h=890000a10a0ccdc49f62946bddf1c0b840495a94 Stream->Fountain, move Scheduler to Platform, HashMap->Hash darcs-hash:20050116051703-5007d-1240d7e546d891f6faf8af2a340607b685092c2c.gz --- diff --git a/src/org/ibex/core/Box.java b/src/org/ibex/core/Box.java index 16bae85..0ccd421 100644 --- a/src/org/ibex/core/Box.java +++ b/src/org/ibex/core/Box.java @@ -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) { diff --git a/src/org/ibex/core/Ibex.java b/src/org/ibex/core/Ibex.java index bd133c7..4110a8d 100644 --- a/src/org/ibex/core/Ibex.java +++ b/src/org/ibex/core/Ibex.java @@ -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; } diff --git a/src/org/ibex/core/Main.java b/src/org/ibex/core/Main.java index a870384..a9c35df 100644 --- a/src/org/ibex/core/Main.java +++ b/src/org/ibex/core/Main.java @@ -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 index 8fdb506..0000000 --- a/src/org/ibex/core/Scheduler.java +++ /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 - 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; } }; diff --git a/src/org/ibex/graphics/MSPack.java b/src/org/ibex/graphics/MSPack.java index 36de110..3135fed 100644 --- a/src/org/ibex/graphics/MSPack.java +++ b/src/org/ibex/graphics/MSPack.java @@ -4,7 +4,6 @@ package org.ibex.graphics; -import org.ibex.core.Main; import org.ibex.util.*; import java.io.*; import org.ibex.nestedvm.*; diff --git a/src/org/ibex/graphics/Picture.java b/src/org/ibex/graphics/Picture.java index c8b5895..ce7b20b 100644 --- a/src/org/ibex/graphics/Picture.java +++ b/src/org/ibex/graphics/Picture.java @@ -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); diff --git a/src/org/ibex/graphics/Surface.java b/src/org/ibex/graphics/Surface.java index 7658ec5..0f29914 100644 --- a/src/org/ibex/graphics/Surface.java +++ b/src/org/ibex/graphics/Surface.java @@ -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) { diff --git a/src/org/ibex/plat/Darwin.java b/src/org/ibex/plat/Darwin.java index c5c7e9c..be54028 100644 --- a/src/org/ibex/plat/Darwin.java +++ b/src/org/ibex/plat/Darwin.java @@ -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(); diff --git a/src/org/ibex/plat/OpenGL.java b/src/org/ibex/plat/OpenGL.java index 5b9590a..b852437 100644 --- a/src/org/ibex/plat/OpenGL.java +++ b/src/org/ibex/plat/OpenGL.java @@ -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 { diff --git a/src/org/ibex/plat/Platform.java b/src/org/ibex/plat/Platform.java index 321a80d..389caa4 100644 --- a/src/org/ibex/plat/Platform.java +++ b/src/org/ibex/plat/Platform.java @@ -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