From 6a96430e10e27fc1de5754cb5add705f929dd109 Mon Sep 17 00:00:00 2001 From: megacz Date: Fri, 30 Jan 2004 07:40:39 +0000 Subject: [PATCH] 2003/10/31 09:50:08 darcs-hash:20040130074039-2ba56-175e5323ee263057ec5dd652ea85c488c66e3cf7.gz --- src/org/xwt/Box.java.pp | 156 ++++++++++------------------------------ src/org/xwt/Glyph.java | 101 +++++++++++++++++++++----- src/org/xwt/HTTP.java | 23 +++--- src/org/xwt/Main.java | 26 +++---- src/org/xwt/Message.java | 140 ------------------------------------ src/org/xwt/Picture.java | 55 +++++++------- src/org/xwt/Platform.java | 11 ++- src/org/xwt/Res.java | 12 ++-- src/org/xwt/Scheduler.java | 34 +++++++++ src/org/xwt/Surface.java | 45 +++++++----- src/org/xwt/Template.java | 10 ++- src/org/xwt/ThreadMessage.java | 113 ----------------------------- src/org/xwt/Trap.java | 14 ++-- src/org/xwt/XMLRPC.java | 30 +------- src/org/xwt/XWT.java | 38 +++++----- src/org/xwt/builtin/splash.xwt | 8 ++- 16 files changed, 287 insertions(+), 529 deletions(-) delete mode 100644 src/org/xwt/Message.java create mode 100644 src/org/xwt/Scheduler.java delete mode 100644 src/org/xwt/ThreadMessage.java diff --git a/src/org/xwt/Box.java.pp b/src/org/xwt/Box.java.pp index 21cc5bf..c58eebc 100644 --- a/src/org/xwt/Box.java.pp +++ b/src/org/xwt/Box.java.pp @@ -89,7 +89,6 @@ public final class Box extends JS.Scope { static final int NOTPACKED_FLAG = 0x00000004; static final int HSHRINK_FLAG = 0x00000008; static final int VSHRINK_FLAG = 0x00000010; - static final int TILE_FLAG = 0x00000020; static final int FONT_CHANGED_FLAG = 0x00000040; // set when font changes, cleared during repack static final int ISROOT_FLAG = 0x00000080; static final int NOCLIP_FLAG = 0x00000100; @@ -436,6 +435,7 @@ public final class Box extends JS.Scope { int globaly = parenty + (parent == null ? 0 : y); // intersect the x,y,w,h rendering window with ourselves; quit if it's empty + if ((flags & NOCLIP_FLAG) == 0) { clipw = min(max(clipx, parent == null ? 0 : globalx) + clipw, (parent == null ? 0 : globalx) + width) - globalx; cliph = min(max(clipy, parent == null ? 0 : globaly) + cliph, (parent == null ? 0 : globaly) + height) - globaly; @@ -450,11 +450,19 @@ public final class Box extends JS.Scope { } if (image != null) - if ((flags & TILE_FLAG) != 0) renderTiledImage(globalx, globaly, clipx, clipy, clipw, cliph, buf); - else buf.drawPicture(image, globalx, globaly, clipx, clipy, clipx + clipw, clipy + cliph); + for(int x = globalx; x < clipx + clipw; x += image.getWidth()) + for(int y = globaly; y < clipy + cliph; y += image.getHeight()) + buf.drawPicture(image, x, y, clipx, clipy, clipx + clipw, clipy + cliph); if (text != null && !text.equals("")) - renderText(globalx, globaly, clipx, clipy, clipw, cliph, buf); + Glyph.rasterizeGlyphs(font, fontsize, text, buf, textcolor, globalx, globaly, clipx, clipy, clipw + clipx, clipy + cliph, + new Callback() { public Object call(Object arg) { + Box.this.dirty(); + Box b = Box.this; + MARK_FOR_REFLOW_b; + b.dirty(); + return null; + }}); if (path != null) { if (rtransform == null) rpath = null; @@ -480,57 +488,6 @@ public final class Box extends JS.Scope { } } - void renderTiledImage(int globalx, int globaly, int x, int y, int w, int h, PixelBuffer buf) { - /* - FIXME - int iw = image.getWidth(); - int ih = image.getHeight(); - for(int i=(x - x)/iw; i <= (x + w - x)/iw; i++) { - for(int j=(y - y)/ih; j<= (y + h - y)/ih; j++) { - - int dx1 = max(i * iw + x, x); - int dy1 = max(j * ih + y, y); - int dx2 = min((i+1) * iw + x, x + w); - int dy2 = min((j+1) * ih + y, y + h); - - int sx1 = dx1 - (i*iw) - x; - int sy1 = dy1 - (j*ih) - y; - int sx2 = dx2 - (i*iw) - x; - int sy2 = dy2 - (j*ih) - y; - - if (dx2 - dx1 > 0 && dy2 - dy1 > 0 && sx2 - sx1 > 0 && sy2 - sy1 > 0) - buf.drawPicture(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2); - } - } - */ - } - - void renderText(int x, int y, int clipx, int clipy, int clipw, int cliph, PixelBuffer buf) { - for(int i=0; i> 16); + textheight = (int)(widthheight & 0x0000ffff); + MARK_FOR_REFLOW_this; } - // Trivial Helper Methods (should be inlined) ///////////////////////////////////////// + // Trivial Helper Method s(should be inlined) ///////////////////////////////////////// static final int min(int a, int b) { if (a= 32 && c < 127) Freetype.renderGlyphs(res, pointsize, 32, 126, glyphCache); - else Freetype.renderGlyphs(res, pointsize, (int)c, (int)c, glyphCache); - if ((Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize)) == null) - throw new JS.Exn("error rendering glyph " + c + "; glyph is null"); - Log.log(Freetype.class, " done rendering glyphs for font " + res.getDescriptiveName()); - } - ThreadMessage.resumeThread(); + private static Queue glyphsToBeRendered = new Queue(255); + private static Freetype freetype = new Freetype(); + + private static Scheduler.Task glyphRenderingTask = new Scheduler.Task() { + public Object call(Object arg) { + Glyph g = (Glyph)glyphsToBeRendered.remove(false); + if (g == null) return null; + if (g.p != null) return null; + Log.log(Glyph.class, "rendering glyph " + g.c); + freetype.renderGlyph(g.res, g); + g.rendered = true; + Scheduler.add(this); + return null; + } + }; + + /** + + * If the glyphs of text are not yet loaded, spawn a + * Task to load them and invoke callback. + * + + * returns the width (in the high-order int) and height (in the + * low-order int) of the string's rasterization, or -1 if some + * glyphs are not loaded. + + */ + public static long rasterizeGlyphs(final Res res, final int pointsize, final String text, PixelBuffer pb, int textcolor, + int x, int y, int cx1, int cy1, int cx2, int cy2, final Callback callback) { + boolean ret = true; + int width = 0; + int height = 0; + for(int i=0; iis 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() { } - - /** invoked by Main */ - public static void startQ() { singleton.start(); } - - /** pending events */ - private static Queue events = new Queue(50); - - /** the number of objects in the queue that are not subclasses of ThreadMessage */ - public static volatile int nonThreadEventsInQueue = 0; - - /** the message currently being performed */ - static Message currentlyPerforming = null; - - private static Q singleton = new Q(); - private static Watcher watcher = new Watcher(); - - /** - * The message loop. Note that non-ThreadMessage Messages get - * priority, and that the queue is emptied in passes -- first we - * look at how many events are in the queue, then perform that - * many events, then render. This has the effect of throttling - * render requests to the appropriate frequency -- when many - * messages are in the queue, refreshes happen less frequently. - */ - public void run() { - Thread.currentThread().setPriority(Thread.MAX_PRIORITY); - while(true) { - try { - int size = events.size(); - for(int i=0; i 0) { - add(e); - i--; - continue; - } - if (!(e instanceof Thread)) working = true; - currentlyPerforming = e; - e.perform(); - currentlyPerforming = null; - working = false; - } - working = true; - for(int i=0; i= 5) - if (Log.on) Log.log(this, "note: executing same " + what + " for " + howlong + "s" + " at " + where); - } else { - m = Q.currentlyPerforming; - t = System.currentTimeMillis(); - } - try { Thread.sleep(1000); } catch (Exception e) { } - } - } - } - - } - -} - diff --git a/src/org/xwt/Picture.java b/src/org/xwt/Picture.java index da65368..a4cc602 100644 --- a/src/org/xwt/Picture.java +++ b/src/org/xwt/Picture.java @@ -20,33 +20,6 @@ import org.xwt.translators.*; */ public abstract class Picture { - /** Pictures, cached by Res */ - private static Cache cache = new Cache(); - - private static GIF gif = new GIF(); - - /** turns a resource into a Picture.Source */ - public static Picture fromRes(Res r) { - Picture ret = (Picture)cache.get(r); - if (ret == null) { - try { - PushbackInputStream pbis = new PushbackInputStream(r.getInputStream()); - int c = pbis.read(); - pbis.unread(c); - if (c == 'G') ret = gif.fromInputStream(pbis, r.getDescriptiveName()); - else if (c == 137) ret = new PNG().fromInputStream(pbis, r.getDescriptiveName()); - else if (c == 0xff) ret = Platform.decodeJPEG(pbis, r.getDescriptiveName()); - else throw new JS.Exn("couldn't figure out image type from first byte"); - cache.put(r, ret); - ret.res = r; - } catch (IOException e) { - Log.logJS(Picture.class, e); - return null; - } - } - return ret; - } - /** the resource that created this Picture */ public Res res = null; @@ -56,4 +29,32 @@ public abstract class Picture { /** the width of the picture */ public abstract int getWidth(); + /** Pictures, cache keyed by Res instance */ + private static Cache cache = new Cache(); + private static GIF gif = new GIF(); + + /** turns a resource into a Picture.Source and passes it to the callback */ + public static void fromRes(final Res r, final Callback callback) { + Picture ret = (Picture)cache.get(r); + if (ret != null) { + callback.call(ret); + return; + } + + try { + // FIXME: put self in background + PushbackInputStream pbis = new PushbackInputStream(r.getInputStream()); + int c = pbis.read(); + pbis.unread(c); + if (c == 'G') ret = gif.fromInputStream(pbis, r.getDescriptiveName()); + else if (c == 137) ret = new PNG().fromInputStream(pbis, r.getDescriptiveName()); + else if (c == 0xff) ret = Platform.decodeJPEG(pbis, r.getDescriptiveName()); + else throw new JS.Exn("couldn't figure out image type from first byte"); + cache.put(r, ret); + ret.res = r; + callback.call(ret); + } catch (Exception e) { + Log.log(Picture.class, e); + } + } } diff --git a/src/org/xwt/Platform.java b/src/org/xwt/Platform.java index 8e77b87..5b1f0ac 100644 --- a/src/org/xwt/Platform.java +++ b/src/org/xwt/Platform.java @@ -227,12 +227,8 @@ public class Platform { /** 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 { - return platform._fileDialog(suggestedFileName, write); - } finally { - ThreadMessage.resumeThread(); - } + // FIXME: put self in background + return platform._fileDialog(suggestedFileName, write); } /** default implementation is Eric Albert's BrowserLauncher.java */ @@ -285,9 +281,12 @@ public class Platform { Object icon = b.get("icon", true); if (icon != null && icon instanceof Res) { + /* + FIXME Picture pic = Picture.fromRes((Res)icon); 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); diff --git a/src/org/xwt/Res.java b/src/org/xwt/Res.java index 6bf79a3..196bb2c 100644 --- a/src/org/xwt/Res.java +++ b/src/org/xwt/Res.java @@ -22,8 +22,10 @@ public abstract class Res extends JS { public Res getParent() { return null; } /** an InputStream that makes sure it is not in the MessageQueue when blocked on a read */ + // FIXME private static class BackgroundInputStream extends FilterInputStream { BackgroundInputStream(InputStream i) { super(i); } + /* private void suspend() throws IOException { if (!ThreadMessage.suspendThread()) throw new IOException("attempt to perform background-only operation in a foreground thread"); @@ -41,6 +43,7 @@ public abstract class Res extends JS { try { return super.read(b, off, len); } finally { resume(); } } + */ } /** returns an InputStream containing the Resource's contents */ @@ -201,8 +204,8 @@ public abstract class Res extends JS { /** shadow resource which replaces the graft */ public static class ProgressWatcher extends Res { final Res watchee; - JS.Callable callback; - ProgressWatcher(Res watchee, JS.Callable callback) { this.watchee = watchee; this.callback = callback; } + JS.CompiledFunction callback; + ProgressWatcher(Res watchee, JS.CompiledFunction callback) { this.watchee = watchee; this.callback = callback; } public String getDescriptiveName() { return watchee.getDescriptiveName(); } public InputStream getInputStream(String s) throws IOException { final InputStream is = watchee.getInputStream(s); @@ -216,11 +219,12 @@ public abstract class Res extends JS { public int read(byte[] b, int off, int len) throws IOException { int ret = super.read(b, off, len); if (ret != 1) bytesDownloaded += ret; - ThreadMessage.newthread(new JS.Callable() { public Object call(JS.Array a) { + Scheduler.add(new Scheduler.Task() { public Object call(Object arg) { JS.Array args = new JS.Array(); args.addElement(new Integer(bytesDownloaded)); args.addElement(new Integer(is instanceof KnownLength ? ((KnownLength)is).getLength() : 0)); - callback.call(args); + // FIXME + // new JS.Thread(callback, callbackScope).resume(); return null; } }); return ret; diff --git a/src/org/xwt/Scheduler.java b/src/org/xwt/Scheduler.java new file mode 100644 index 0000000..95fd6bf --- /dev/null +++ b/src/org/xwt/Scheduler.java @@ -0,0 +1,34 @@ +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] +package org.xwt; + +import java.util.*; +import org.xwt.js.*; +import org.xwt.util.*; + +// FEATURE: reimplement Watcher +/** Implements cooperative multitasking */ +public class Scheduler { + + private static Scheduler singleton = new Scheduler(); + public static void run() { singleton.do_run(); } + protected Scheduler() { } + + public static abstract class Task implements Callback { public abstract Object call(Object o); } + + private static Queue runnable = new Queue(50); + + public static void add(Task t) { singleton.runnable.append(t); } + public void do_run() { + while(true) { + Task t = (Task)runnable.remove(true); + try { + t.call(null); + for(int i=0; ixwt.thread - * are instances of this class. ThreadMessage objects can be enqueued - * in MessageQueue. - * - * INVARIANT: only one thread can be executing JavaScript scripts or - * accessing Box instances at any given time. For - * performance reasons, no locks are employed to enforce - * this invariant. - */ -public class ThreadMessage extends Thread implements Message { - - private volatile static int threadcount = 0; - - /** the JavaScript function that we are executing */ - volatile JS.Callable f; - - /** the ThreadMessage thread blocks on this before executing any JavaScript */ - Semaphore go = new Semaphore(); - - /** 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 */ - private static Queue spare = new Queue(50); - - /** queue of functions waiting to be spawned; used if threadcount == Platform.maxThreads() */ - private static Queue waiting = new Queue(50); - - private ThreadMessage() { start(); } - private static Object[] emptyobj = new Object[] { }; - - /** creates a new thread to execute function f */ - public static synchronized void newthread(JS.Callable f) { - ThreadMessage ret = (ThreadMessage)spare.remove(false); - if (ret == null) { - if (threadcount < Platform.maxThreads()) ret = new ThreadMessage(); - else { - waiting.append(f); - return; - } - } - ret.f = f; - Message.Q.add(ret); - } - - /** attempts to put this thread into the background to perform a blocking operation; returns false if unable to do so */ - public static boolean suspendThread() { - // put ourselves in the background - Thread thread = Thread.currentThread(); - if (!(thread instanceof ThreadMessage)) { - if (Log.on) Log.logJS(ThreadMessage.class, "attempt to perform background-only operation in a foreground thread"); - return false; - } - ThreadMessage mythread = (ThreadMessage)thread; - mythread.setPriority(Thread.MIN_PRIORITY); - mythread.done.release(); - return true; - } - - /** re-enqueues this thread */ - public static void resumeThread() { - ThreadMessage mythread = (ThreadMessage)Thread.currentThread(); - Message.Q.add(mythread); - mythread.setPriority(Thread.NORM_PRIORITY); - mythread.go.block(); - } - - public void run() { - try { - threadcount++; - while (true) { - try { - go.block(); - f.call(new JS.Array()); - } catch (JS.Exn e) { - if (Log.on) Log.log(this, "WARNING: uncaught ecmascript exception: " + e); - } - done.release(); - synchronized(waiting) { - if (waiting.size() > 0) { - f = (JS.Callable)waiting.remove(false); - Message.Q.add(this); - } else if (spare.size() < 10) { - spare.append(this); - } else { - threadcount--; - return; - } - } - } - } catch (Throwable t) { - if (Log.on) Log.log(this, "caught throwable at thread entry point; this should never happen"); - if (Log.on) Log.log(this, t); - if (Log.on) Log.log(this, "reaping thread"); - return; - } - } - - /** this is invoked in the Message.Q thread */ - public void perform() { - go.release(); - done.block(); - } - -} diff --git a/src/org/xwt/Trap.java b/src/org/xwt/Trap.java index df51b53..2895d9f 100644 --- a/src/org/xwt/Trap.java +++ b/src/org/xwt/Trap.java @@ -96,29 +96,31 @@ public class Trap { private Trap() { } - public Object perform() throws JS.Exn { + public Object perform() { try { if (f.getNumFormalArgs() > 0) return cascade(); - return f.call(new TrapArgs(this)); + JS.Thread.current().setTailCall(f, new TrapArgs(this)); + return null; } catch (Exception e) { Log.log(this, "Exception thrown from within trap: " + e); return null; } } - public void perform(Object val) throws JS.Exn { + public void perform(Object val) { try { if (f.getNumFormalArgs() == 0) cascade(val); TrapArgs ta = new TrapArgs(this, val); - Object ret = f.call(ta); - if (ret != Boolean.FALSE && !ta.cascadeHappened) cascade(val); + JS.Thread.current().setTailCall(f, ta); + // FIXME: re-add autocascades + //if (ret != Boolean.FALSE && !ta.cascadeHappened) cascade(val); } catch (Exception e) { Log.log(this, "Exception thrown from within trap: " + e); } } public Object cascade() { - if (next != null) return next.perform(); + if (next != null) { next.perform(); return null; } return trapee.get(name, true); } diff --git a/src/org/xwt/XMLRPC.java b/src/org/xwt/XMLRPC.java index 7325476..ac83249 100644 --- a/src/org/xwt/XMLRPC.java +++ b/src/org/xwt/XMLRPC.java @@ -304,8 +304,8 @@ class XMLRPC extends JS.Callable { InputStream is = http.POST("text/xml", content); try { BufferedReader br = !Log.verbose ? - new BufferedReader(new InputStreamReader(new Filter(is))) : - new BufferedReader(new FilterReader(new InputStreamReader(new Filter(is))) { + new BufferedReader(new InputStreamReader(is)) : + new BufferedReader(new FilterReader(new InputStreamReader(is)) { public int read() throws IOException { int i = super.read(); if (Log.on) Log.log(this, "recv: " + ((char)i)); @@ -360,9 +360,6 @@ class XMLRPC extends JS.Callable { } public final Object call(JS.Array args) throws JS.Exn { - - if (!ThreadMessage.suspendThread()) return null; - try { return call2(args); } catch (IOException se) { @@ -372,10 +369,7 @@ class XMLRPC extends JS.Callable { } catch (JS.Exn jse) { if (Log.on) Log.log(this, jse.toString()); throw jse; - } finally { - ThreadMessage.resumeThread(); } - } /** When you get a property from an XMLRPC, it just returns another XMLRPC with the property name tacked onto methodname. */ @@ -402,24 +396,4 @@ class XMLRPC extends JS.Callable { public AccessibleCharArrayWriter(int i) { super(i); } } - /** private filter class to make sure that network transfers don't interfere with UI responsiveness */ - private static class Filter extends FilterInputStream { - public Filter(InputStream is) { super(is); } - public int read() throws IOException { - java.lang.Thread.yield(); - 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(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(Message.Q.nonThreadEventsInQueue > 0) try { java.lang.Thread.sleep(100); } catch (Exception e) { }; - return super.read(b, i, j); - } - } - } diff --git a/src/org/xwt/XWT.java b/src/org/xwt/XWT.java index 2d4ef45..c5f7a13 100644 --- a/src/org/xwt/XWT.java +++ b/src/org/xwt/XWT.java @@ -50,9 +50,13 @@ public final class XWT extends JS.Obj { else return rr.get(name); } - public void put(Object name, Object value) { - if (name.equals("thread") && value != null && value instanceof JS.Callable) ThreadMessage.newthread((JS.Callable)value); - else if (name.equals("clipboard")) Platform.setClipBoard(value.toString()); + public void put(Object name, final Object value) { + if (name.equals("thread") && value != null && (value instanceof JS.Callable || value instanceof JS.CompiledFunction)) { + Scheduler.add(new Scheduler.Task() { public Object call(Object arg) { + new JS.Thread((CompiledFunction)value).resume(); + return null; + } }); + } else if (name.equals("clipboard")) Platform.setClipBoard(value.toString()); else if (name.equals("frame")) Platform.createSurface((Box)value, true, true); else if (name.equals("window")) Platform.createSurface((Box)value, false, true); else if (name.equals("proxyAuthorization")) { @@ -88,7 +92,7 @@ public final class XWT extends JS.Obj { } else if (method.equals("watchProgress")) { if (checkOnly) return Boolean.TRUE; - return new Res.ProgressWatcher((Res)args.elementAt(0), (JS.Callable)args.elementAt(1)); + return new Res.ProgressWatcher((Res)args.elementAt(0), (JS.CompiledFunction)args.elementAt(1)); } else if (method.equals("yield")) { if (checkOnly) return Boolean.TRUE; @@ -231,20 +235,22 @@ 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)) { - if (Log.on) Log.log(XWT.class, "cannot sleep() or yield() in the foreground thread"); - } else { - ThreadMessage mythread = (ThreadMessage)thread; - mythread.done.release(); - if (i > 0) try { java.lang.Thread.sleep(i); } catch (Exception e) { } - Message.Q.add(mythread); - mythread.go.block(); - } + public static void sleep(final int i) { + final JS.Thread jsthread = JS.Thread.current(); + final long currentTime = System.currentTimeMillis(); + final Scheduler.Task task = new Scheduler.Task() { public Object call(Object arg) { + if (System.currentTimeMillis() - currentTime < i) { + Scheduler.add(this); + } else { + jsthread.resume(); + } + return null; + } }; + jsthread.pause(); + Scheduler.add(task); } - private static class XWTMath extends JS.Obj { + private static class XWTMath extends org.xwt.js.Math { public XWTMath() { JS gs = new JS.GlobalScope(); put("isNaN",gs.get("isNaN")); diff --git a/src/org/xwt/builtin/splash.xwt b/src/org/xwt/builtin/splash.xwt index fa07d95..6f44cca 100644 --- a/src/org/xwt/builtin/splash.xwt +++ b/src/org/xwt/builtin/splash.xwt @@ -27,14 +27,16 @@ var new_xwt = xwt.clone(new_rr); xwt.thread = function() { -for(var i=0; 100>i; i++) { progress(i, 100); xwt.sleep(100); } - xwt.yield(); +for(var i=0; 100>i; i++) { +progress(i, 100); +xwt.yield(); +} new_xwt.apply(xwt.box, new_xwt["main.xwt"]); thisbox = null; } } - + -- 1.7.10.4