1    // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
2    package org.xwt;
3    
4    import java.util.*;
5    import org.xwt.js.*;
6    import org.xwt.util.*;
7    
8    /** Implements cooperative multitasking */
9    public class Scheduler {
10   
11       // Public API Exposed to org.xwt /////////////////////////////////////////////////
12   
13       private static Scheduler singleton;
14       public static interface Task { public abstract void perform() throws Exception; }
15       public static void add(Task t) { singleton.runnable.append(t); }
16       public static void init() { if (singleton == null) (singleton = Platform.getScheduler()).run(); }
17   
18       private static Task current = null;
19   
20       private static volatile boolean rendering = false;
21       private static volatile boolean again = false;
22   
23       /** synchronizd so that we can safely call it from an event-delivery thread, in-context */
24       public static void renderAll() {
25           if (rendering) { again = true; return; }
26           synchronized(Scheduler.class) {
27               try {
28                   rendering = true;
29                   do {
30                       // FEATURE: this could be cleaner
31                       again = false;
32                       for(int i=0; i<Surface.allSurfaces.size(); i++) {
33                           Surface s = ((Surface)Surface.allSurfaces.elementAt(i));
34                           do { s.render(); } while(s.abort);
35                       }
36                   } while(again);
37               } finally {
38                   rendering = false;
39               }
40           }
41       }
42   
43       
44   
45       // API which must be supported by subclasses /////////////////////////////////////
46   
47       /**
48        *  SCHEDULER INVARIANT: all scheduler implementations MUST invoke
49        *  Surface.renderAll() after performing a Task if no tasks remain
50        *  in the queue.  A scheduler may choose to invoke
51        *  Surface.renderAll() more often than that if it so chooses.
52        */
53       public void run() { defaultRun(); }
54       protected Scheduler() { }
55   
56   
57       // Default Implementation //////////////////////////////////////////////////////
58   
59       protected static Queue runnable = new Queue(50);
60       public void defaultRun() {
61           while(true) {
62               current = (Task)runnable.remove(true);
63               try {
64                   // FIXME hideous
65                   synchronized(this) {
66                       for(int i=0; i<Surface.allSurfaces.size(); i++) {
67                           Surface s = (Surface)Surface.allSurfaces.elementAt(i);
68                           if (current instanceof JS) {
69                               s._mousex = Integer.MAX_VALUE;
70                               s._mousey = Integer.MAX_VALUE;
71                           } else {
72                               s._mousex = s.mousex;
73                               s._mousey = s.mousey;
74                           }
75                       }
76                       current.perform();
77                   }
78                   renderAll();
79               } catch (JSExn e) {
80                   Log.info(Scheduler.class, "a JavaScript thread spawned with xwt.thread() threw an exception:");
81                   Log.info(Scheduler.class, "JS Exception: " + e.getObject() + "\n" + e.backtrace());
82                   Log.info(Scheduler.class,e);
83               } catch (Exception e) {
84                   Log.info(Scheduler.class, "a Task threw an exception which was caught by the scheduler:");
85                   Log.info(Scheduler.class, e);
86               }
87               // if an Error is thrown it will cause the engine to quit
88           }
89       }
90   }
91