javauis/lcdui_qt/src/javax/microedition/lcdui/EventDispatcher.java
changeset 23 98ccebc37403
parent 21 2a9601315dfc
child 78 71ad690e91f5
--- a/javauis/lcdui_qt/src/javax/microedition/lcdui/EventDispatcher.java	Mon May 03 12:27:20 2010 +0300
+++ b/javauis/lcdui_qt/src/javax/microedition/lcdui/EventDispatcher.java	Fri May 14 15:47:24 2010 +0300
@@ -11,7 +11,7 @@
 *
 * Contributors:
 *
-* Description: 
+* Description:
 *
 */
 
@@ -22,337 +22,387 @@
 
 /*
  * Event dispatcher singleton class. Takes care of dispatching the UI callbacks
- * to the MIDlet in a dedicated dispatcher thread. Owns and encapsulates an 
- * event queue of callback events. 
+ * to the MIDlet in a dedicated dispatcher thread. Owns and encapsulates an
+ * event queue of callback events.
  */
-final class EventDispatcher {
+final class EventDispatcher
+{
+
+    private static EventDispatcher singleton;
+    private static EventQueue eventQueue;
+    private static Thread dispatcherThread;
+    private static boolean terminated;
+    private static Object wakeLock;
+    private static Object callbackLock;
+    private static boolean pendingWake;
+    private static Runnable terminatedNotification;
+    private final static String logName = "LCDUI event dispatcher: ";
+
+    /*
+     * LCDUI-internal event class for callback events.
+     */
+    static final class LCDUIEvent
+    {
+        /*
+         * High bits of the event event type identifier are used to group the
+         * events that are handled the same way in the Event Dispatcher.
+         */
+        static final int CANVASBIT = 0x80000000;
+        static final int CUSTOMITEMBIT = 0x40000000;
+        static final int DISPLAYABLEBIT = 0x20000000;
+        static final int EVENTTYPEMASK = CANVASBIT|CUSTOMITEMBIT|DISPLAYABLEBIT;
 
-	private static EventDispatcher singleton;
-	private static EventQueue eventQueue;
-	private static Thread dispatcherThread;
-	private static boolean terminated;
-	private static Object wakeLock;
-	private static Object callbackLock;
-	private static boolean pendingWake;
-	private static Runnable terminatedNotification;
-	private final static String logName = "LCDUI event dispatcher: ";
+        /*
+         * Event type identifiers.
+         */
+        static final int CANVAS_HIDENOTIFY = 1|CANVASBIT;
+        static final int CANVAS_KEYPRESSED = 2|CANVASBIT;
+        static final int CANVAS_KEYREPEATED = 3|CANVASBIT;
+        static final int CANVAS_KEYRELEASED = 4|CANVASBIT;
+        static final int CANVAS_PAINT_NATIVE_REQUEST = 5|CANVASBIT;
+        static final int CANVAS_PAINT_MIDLET_REQUEST = 6|CANVASBIT;
+        static final int CANVAS_POINTERDRAGGED = 7|CANVASBIT;
+        static final int CANVAS_POINTERPRESSED = 8|CANVASBIT;
+        static final int CANVAS_POINTERRELEASED = 9|CANVASBIT;
+        static final int CANVAS_SHOWNOTIFY = 10|CANVASBIT;
+        static final int DISPLAYABLE_SIZECHANGED = 11|DISPLAYABLEBIT;
+        static final int DISPLAYABLE_COMMANDACTION = 12|DISPLAYABLEBIT;
+        static final int CUSTOMITEM_HIDENOTIFY = 13|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_KEYPRESSED = 14|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_KEYREPEATED = 15|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_KEYRELEASED = 16|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_PAINT_NATIVE_REQUEST = 17|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_PAINT_MIDLET_REQUEST = 18|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_POINTERDRAGGED = 19|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_POINTERPRESSED = 20|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_POINTERRELEASED = 21|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_SHOWNOTIFY = 22|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_SIZECHANGED = 23|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_TRAVERSE = 24|CUSTOMITEMBIT;
+        static final int CUSTOMITEM_TRAVERSEOUT = 25|CUSTOMITEMBIT;
+        static final int ITEM_COMMANDACTION = 26;
+        static final int ITEMSTATELISTENER_ITEMSTATECHANGED = 27;
+        static final int RUNNABLE_CALLSERIALLY = 28;
 
-	/*
-	 * LCDUI-internal event class for callback events. 
-	 */
-	static final class LCDUIEvent {
-		/*
-		 * High bits of the event event type identifier are used to group the
-		 * events that are handled the same way in the Event Dispatcher.
-		 */
-		static final int CANVASBIT = 0x80000000;
-		static final int CUSTOMITEMBIT = 0x40000000;
-		static final int DISPLAYABLEBIT = 0x20000000;
-		static final int EVENTTYPEMASK = CANVASBIT|CUSTOMITEMBIT|DISPLAYABLEBIT;
-		
-		/*
-		 * Event type identifiers. 
-		 */
-		static final int CANVAS_HIDENOTIFY = 1|CANVASBIT;
-		static final int CANVAS_KEYPRESSED = 2|CANVASBIT;
-		static final int CANVAS_KEYREPEATED = 3|CANVASBIT;
-		static final int CANVAS_KEYRELEASED = 4|CANVASBIT;
-		static final int CANVAS_PAINT_NATIVE_REQUEST = 5|CANVASBIT;
-		static final int CANVAS_PAINT_MIDLET_REQUEST = 6|CANVASBIT;
-		static final int CANVAS_POINTERDRAGGED = 7|CANVASBIT;
-		static final int CANVAS_POINTERPRESSED = 8|CANVASBIT;
-		static final int CANVAS_POINTERRELEASED = 9|CANVASBIT;
-		static final int CANVAS_SHOWNOTIFY = 10|CANVASBIT;
-		static final int DISPLAYABLE_SIZECHANGED = 11|DISPLAYABLEBIT;
-		static final int DISPLAYABLE_COMMANDACTION = 12|DISPLAYABLEBIT;
-		static final int CUSTOMITEM_HIDENOTIFY = 13|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_KEYPRESSED = 14|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_KEYREPEATED = 15|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_KEYRELEASED = 16|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_PAINT_NATIVE_REQUEST = 17|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_PAINT_MIDLET_REQUEST = 18|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_POINTERDRAGGED = 19|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_POINTERPRESSED = 20|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_POINTERRELEASED = 21|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_SHOWNOTIFY = 22|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_SIZECHANGED = 23|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_TRAVERSE = 24|CUSTOMITEMBIT;
-		static final int CUSTOMITEM_TRAVERSEOUT = 25|CUSTOMITEMBIT;
-		static final int ITEM_COMMANDACTION = 26;
-		static final int ITEMSTATELISTENER_ITEMSTATECHANGED = 27;
-		static final int RUNNABLE_CALLSERIALLY = 28;
-		
-		/*
-		 * Event parameters. 
-		 */
-		int type;
-		int x;
-		int y;
-		int width;
-		int height;
-		int keyCode;
-		Runnable runnable;
-		Command command;
-		CommandListener commandListener;
-		ItemCommandListener itemCommandListener;
-		Item item;
+        /*
+         * Event parameters.
+         */
+        int type;
+        int x;
+        int y;
+        int width;
+        int height;
+        int keyCode;
+        Runnable runnable;
+        Command command;
+        CommandListener commandListener;
+        ItemCommandListener itemCommandListener;
+        Item item;
+
+        /*
+         * Handler object. The object that the LCDUIEvent will be passed to
+         * when the event is dispatched. Based on the event type it's known
+         * what type of an object it must be. The handler object will
+         * implement how to do the actual callback.
+         */
+        Object handlerObject;
+
+        /*
+         * The associated eSWT widget. Used to store the eSWT widget which
+         * the original eSWT event was for. E.g. in Form the CustomItem's
+         * widget may change while the event is in the queue.
+         */
+        Widget widget;
+
+        /*
+         * Used by EventQueue.
+         */
+        LCDUIEvent next;
 
-		/*
-		 * Handler object. The object that the LCDUIEvent will be passed to 
-		 * when the event is dispatched. Based on the event type it's known 
-		 * what type of an object it must be. The handler object will 
-		 * implement how to do the actual callback. 
-		 */
-		Object handlerObject;
-		
-		/*
-		 * The associated eSWT widget. Used to store the eSWT widget which 
-		 * the original eSWT event was for. E.g. in Form the CustomItem's 
-		 * widget may change while the event is in the queue. 
-		 */
-		Widget widget;
-		
-		/*
-		 * Used by EventQueue. 
-		 */
-		LCDUIEvent next;
+        private LCDUIEvent()
+        {
+        }
+    }
+
+    /*
+     * The event loop executed in a dedicated dispatcher thread. Events are
+     * popped from the queue and dispatched oldest first until there are no
+     * more events. Then the thread sleeps until new events are posted or
+     * termination is requested. Any exceptions thrown from the event handlers
+     * are let through to the runtime which should lead into termination of
+     * all threads in the process.
+     */
+    private static class EventLoop implements Runnable
+    {
+        private boolean noException;
+        public void run()
+        {
+            try
+            {
+                Logger.info(logName + "Dispatcher thread started");
+                while(true)
+                {
+                    LCDUIEvent event;
+                    do
+                    {
+                        synchronized(wakeLock)
+                        {
+                            if(terminated)
+                            {
+                                cleanup();
+                                noException = true;
+                                return;
+                            }
+                            event = eventQueue.pop();
+                            pendingWake = false;
+                        }
 
-		private LCDUIEvent() {	
-		}
-	}
-	
-	/*
-	 * The event loop executed in a dedicated dispatcher thread. Events are 
-	 * popped from the queue and dispatched oldest first until there are no 
-	 * more events. Then the thread sleeps until new events are posted or 
-	 * termination is requested. Any exceptions thrown from the event handlers
-	 * are let through to the runtime which should lead into termination of
-	 * all threads in the process. 
-	 */
-	private static class EventLoop implements Runnable {
-		private boolean noException;
-		public void run() {
-			try {
-				Logger.info(logName + "Dispatcher thread started");
-				while(true) {
-					LCDUIEvent event;
-					do {
-						synchronized(wakeLock) {
-							if(terminated) {
-								cleanup();
-								noException = true;
-								return;
-							}
-							event = eventQueue.pop();
-							pendingWake = false;
-						}
-						
-						if(event != null) {
-							synchronized(callbackLock) {
-								// No callbacks are sent if already terminating
-								if(!terminated) {
-									handleEvent(event);
-								}
-							}
-						}
-					} while(event != null);
-					
-					// No more events 
-					waitForWake();
-				}
-			} finally {
-				if(noException) {
-					Logger.info(logName + "Dispatcher thread exiting normally");
-				} else {
-					Logger.error(logName + "Dispatcher thread exiting abnormally");					
-				}
-				if(terminatedNotification != null) {
-					terminatedNotification.run();
-					terminatedNotification = null;
-				}
-			}
-		}
-	}
+                        if(event != null)
+                        {
+                            synchronized(callbackLock)
+                            {
+                                // No callbacks are sent if already terminating
+                                if(!terminated)
+                                {
+                                    handleEvent(event);
+                                }
+                            }
+                        }
+                    }
+                    while(event != null);
 
-	private EventDispatcher() {
-		wakeLock = new Object();
-		callbackLock = new Object();
-		eventQueue = new EventQueue();
-		dispatcherThread = new Thread(new EventLoop(), this.toString());
-		dispatcherThread.start();
-	}
+                    // No more events
+                    waitForWake();
+                }
+            }
+            finally
+            {
+                if(noException)
+                {
+                    Logger.info(logName + "Dispatcher thread exiting normally");
+                }
+                else
+                {
+                    Logger.error(logName + "Dispatcher thread exiting abnormally");
+                }
+                if(terminatedNotification != null)
+                {
+                    terminatedNotification.run();
+                    terminatedNotification = null;
+                }
+            }
+        }
+    }
 
-	/*
-	 * Cleanup that is done when closing down in a controlled way. 
-	 */
-	private static void cleanup() {
-		eventQueue = null;
-		dispatcherThread = null;
-	}
+    private EventDispatcher()
+    {
+        wakeLock = new Object();
+        callbackLock = new Object();
+        eventQueue = new EventQueue();
+        dispatcherThread = new Thread(new EventLoop(), this.toString());
+        dispatcherThread.start();
+    }
+
+    /*
+     * Cleanup that is done when closing down in a controlled way.
+     */
+    private static void cleanup()
+    {
+        eventQueue = null;
+        dispatcherThread = null;
+    }
+
+    /*
+     * Synchronized to the EventDispatcher class to synchronize with multiple
+     * clients requesting the instance concurrently.
+     */
+    static synchronized EventDispatcher instance()
+    {
+        if(singleton == null)
+        {
+            singleton = new EventDispatcher();
+        }
+        return singleton;
+    }
 
-	/*
-	 * Synchronized to the EventDispatcher class to synchronize with multiple
-	 * clients requesting the instance concurrently.
-	 */
-	static synchronized EventDispatcher instance() {
-		if(singleton == null) {
-			singleton = new EventDispatcher();
-		}
-		return singleton;
-	}
-	
-	/*
-	 * LCDUIEvent factory. 
-	 */
-	LCDUIEvent newEvent(int type, Object handlerObject) {
-		LCDUIEvent event = new LCDUIEvent();
-		event.type = type;
-		event.handlerObject = handlerObject;
-		return event;
-	}
+    /*
+     * LCDUIEvent factory.
+     */
+    LCDUIEvent newEvent(int type, Object handlerObject)
+    {
+        LCDUIEvent event = new LCDUIEvent();
+        event.type = type;
+        event.handlerObject = handlerObject;
+        return event;
+    }
+
+    /*
+     * UI thread and the application threads call to add an event to the queue.
+     * Synchronized to the EventDispatcher instance to synchronize with queries about
+     * the queue content.
+     */
+    synchronized void postEvent(LCDUIEvent event)
+    {
+        // New events ignored after terminate() has been called.
+        if(terminated)
+        {
+            return;
+        }
+        eventQueue.push(event);
+        wake();
+    }
 
-	/*
-	 * UI thread and the application threads call to add an event to the queue.
-	 * Synchronized to the EventDispatcher instance to synchronize with queries about
-	 * the queue content.
-	 */
-	synchronized void postEvent(LCDUIEvent event) {
-		// New events ignored after terminate() has been called. 
-		if(terminated) {
-			return;
-		}
-		eventQueue.push(event);
-		wake();
-	}
-	
-	/*
-	 * Asynchronously terminates the event dispatcher. If it's currently 
-	 * executing a callback it will finish it but not execute any callbacks 
-	 * after it. Events possibly remaining in the queue are discarded. The 
-	 * method is synchronized to the EventDispatcher instance to synchronize 
-	 * with queue content manipulation and query operations.
-	 * 
-	 * @param runnable Called when dispatcher is out of the final callback and 
-	 * is going to die. 
-	 */
-	synchronized void terminate(Runnable runnable) {
-		synchronized(wakeLock) {
-			wake();
-			terminatedNotification = runnable;
-			terminated = true;
-		}
-	}
-		
-	/*
-	 * Canvas.serviceRepaints support is implemented in EventDispatcher so that
-	 * it's possible to synchronize properly with termination and other 
-	 * callbacks without exposing the event dispatcher's internal 
-	 * implementation details to other classes. This method must be called 
-	 * directly in the application thread calling Canvas.serviceRepaints(). It 
-	 * can be either the dispatcher thread or any application thread. Never 
-	 * the UI thread. 
-	 */
-	void serviceRepaints(Canvas canvas) {
-		// Synchronizing to callbackLock guarantees that dispatcher thread is
-		// not in a callback and is not going to make a callback until the lock
-		// is freed from here. If this is the dispatcher thread then it already 
-		// holds the lock. 
-		synchronized(callbackLock) {
-			// Synchronized to the EventDispatcher instance to synchronize with
-			// terminate() calls. Lock is freed before the callback so that
-			// it's possible to complete a terminate() call during the 
-			// callback. Event loop is going to check after acquiring the
-			// callbackLock if terminate() was called during this callback. 
-			synchronized(this) {
-				if(terminated) {
-					return;
-				}
-			}
-			// Canvas.paint() is called back directly in the thread that called
-			// serviceRepaints(). Event is not really needed but is created so
-			// that the same APIs can be used. 
+    /*
+     * Asynchronously terminates the event dispatcher. If it's currently
+     * executing a callback it will finish it but not execute any callbacks
+     * after it. Events possibly remaining in the queue are discarded. The
+     * method is synchronized to the EventDispatcher instance to synchronize
+     * with queue content manipulation and query operations.
+     *
+     * @param runnable Called when dispatcher is out of the final callback and
+     * is going to die.
+     */
+    synchronized void terminate(Runnable runnable)
+    {
+        synchronized(wakeLock)
+        {
+            wake();
+            terminatedNotification = runnable;
+            terminated = true;
+        }
+    }
+
+    /*
+     * Canvas.serviceRepaints support is implemented in EventDispatcher so that
+     * it's possible to synchronize properly with termination and other
+     * callbacks without exposing the event dispatcher's internal
+     * implementation details to other classes. This method must be called
+     * directly in the application thread calling Canvas.serviceRepaints(). It
+     * can be either the dispatcher thread or any application thread. Never
+     * the UI thread.
+     */
+    void serviceRepaints(Canvas canvas)
+    {
+        // Synchronizing to callbackLock guarantees that dispatcher thread is
+        // not in a callback and is not going to make a callback until the lock
+        // is freed from here. If this is the dispatcher thread then it already
+        // holds the lock.
+        synchronized(callbackLock)
+        {
+            // Synchronized to the EventDispatcher instance to synchronize with
+            // terminate() calls. Lock is freed before the callback so that
+            // it's possible to complete a terminate() call during the
+            // callback. Event loop is going to check after acquiring the
+            // callbackLock if terminate() was called during this callback.
+            synchronized(this)
+            {
+                if(terminated)
+                {
+                    return;
+                }
+            }
+            // Canvas.paint() is called back directly in the thread that called
+            // serviceRepaints(). Event is not really needed but is created so
+            // that the same APIs can be used.
             LCDUIEvent event = newEvent(LCDUIEvent.CANVAS_PAINT_MIDLET_REQUEST, canvas);
             event.widget = canvas.getContentComp();
-    		canvas.doCallback(event);
-		}
-	}
-	
-	private static void wake() {
-		synchronized(wakeLock) {
-			wakeLock.notify();
-			pendingWake = true;
-		}
-	}
-	
-	private static void waitForWake() {
-		try {
-			synchronized(wakeLock) {
-				// If there has been a call to wake() then one more iteration
-				// must be executed before entering wait(). 
-				if(!pendingWake) {
-					wakeLock.wait();
-				}
-			}
-		} catch(InterruptedException interruptedException) {
-		}
-	}
-	
-	private static void handleEvent(LCDUIEvent event) {
-		switch(event.type & LCDUIEvent.EVENTTYPEMASK) {
-		case LCDUIEvent.CANVASBIT:
-			handleCanvasEvent(event);
-			break;
-		case LCDUIEvent.CUSTOMITEMBIT:
-			handleCustomItemEvent(event);
-			break;
-		case LCDUIEvent.DISPLAYABLEBIT:
-			handleDisplayableEvent(event);
-			break;
-		default:
-			handleOtherEvent(event);
-			break;
-		}
-		// When returning from here all the references to the event have been 
-		// lost and the objects referenced by the event can be gc'd. No need 
-		// to set the fields to null. 
-	}
-	
-	private static void handleCanvasEvent(LCDUIEvent event) {
-		Canvas canvas = (Canvas)event.handlerObject;
-		canvas.doCallback(event);
-	}	
-	
-	private static void handleCustomItemEvent(LCDUIEvent event) {
-		Form form = (Form)event.handlerObject;
-		form.doCallback(event);
-	}
-	
-	private static void handleDisplayableEvent(LCDUIEvent event) {
-		Displayable displayable = (Displayable)event.handlerObject;
-		displayable.doCallback(event);
-	}
-	
-	private static void handleOtherEvent(LCDUIEvent event) {
-		switch(event.type) {
-		case LCDUIEvent.RUNNABLE_CALLSERIALLY:
-			handleCallSerially(event);
-			break;
-		case LCDUIEvent.ITEM_COMMANDACTION:
-			handleItemCommandListenerCommandAction(event);
-			break;
-		default:
-			Logger.error(logName + "Unknown event type: " + event.type);
-			break;
-		}		
-	}
-	
-	private static void handleCallSerially(LCDUIEvent event) {
-		Display display = (Display)event.handlerObject;
-		display.doCallback(event);
-	}
-		
-	private static void handleItemCommandListenerCommandAction(LCDUIEvent event) {
-		Item item = (Item)event.handlerObject;
-		item.doCallback(event);
-	}
+            canvas.doCallback(event);
+        }
+    }
+
+    private static void wake()
+    {
+        synchronized(wakeLock)
+        {
+            wakeLock.notify();
+            pendingWake = true;
+        }
+    }
+
+    private static void waitForWake()
+    {
+        try
+        {
+            synchronized(wakeLock)
+            {
+                // If there has been a call to wake() then one more iteration
+                // must be executed before entering wait().
+                if(!pendingWake)
+                {
+                    wakeLock.wait();
+                }
+            }
+        }
+        catch(InterruptedException interruptedException)
+        {
+        }
+    }
+
+    private static void handleEvent(LCDUIEvent event)
+    {
+        switch(event.type & LCDUIEvent.EVENTTYPEMASK)
+        {
+        case LCDUIEvent.CANVASBIT:
+            handleCanvasEvent(event);
+            break;
+        case LCDUIEvent.CUSTOMITEMBIT:
+            handleCustomItemEvent(event);
+            break;
+        case LCDUIEvent.DISPLAYABLEBIT:
+            handleDisplayableEvent(event);
+            break;
+        default:
+            handleOtherEvent(event);
+            break;
+        }
+        // When returning from here all the references to the event have been
+        // lost and the objects referenced by the event can be gc'd. No need
+        // to set the fields to null.
+    }
+
+    private static void handleCanvasEvent(LCDUIEvent event)
+    {
+        Canvas canvas = (Canvas)event.handlerObject;
+        canvas.doCallback(event);
+    }
+
+    private static void handleCustomItemEvent(LCDUIEvent event)
+    {
+        Form form = (Form)event.handlerObject;
+        form.doCallback(event);
+    }
+
+    private static void handleDisplayableEvent(LCDUIEvent event)
+    {
+        Displayable displayable = (Displayable)event.handlerObject;
+        displayable.doCallback(event);
+    }
+
+    private static void handleOtherEvent(LCDUIEvent event)
+    {
+        switch(event.type)
+        {
+        case LCDUIEvent.RUNNABLE_CALLSERIALLY:
+            handleCallSerially(event);
+            break;
+        case LCDUIEvent.ITEM_COMMANDACTION:
+            handleItemCommandListenerCommandAction(event);
+            break;
+        default:
+            Logger.error(logName + "Unknown event type: " + event.type);
+            break;
+        }
+    }
+
+    private static void handleCallSerially(LCDUIEvent event)
+    {
+        Display display = (Display)event.handlerObject;
+        display.doCallback(event);
+    }
+
+    private static void handleItemCommandListenerCommandAction(LCDUIEvent event)
+    {
+        Item item = (Item)event.handlerObject;
+        item.doCallback(event);
+    }
 }