javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/common_j2me/org/eclipse/swt/internal/qt/EventLoop.java
changeset 78 71ad690e91f5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/common_j2me/org/eclipse/swt/internal/qt/EventLoop.java	Mon Oct 04 11:29:25 2010 +0300
@@ -0,0 +1,287 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia Corporation - initial implementation
+ *******************************************************************************/
+
+package org.eclipse.swt.internal.qt;
+
+import org.eclipse.swt.internal.qt.midp.UIThreadLauncher;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Internal_PackageSupport;
+
+import com.nokia.mj.impl.rt.support.ApplicationUtils;
+import com.nokia.mj.impl.rt.support.ShutdownListener;
+
+/**
+ * The internal event loop which will run until the application requests the UI 
+ * thread. Then UI thread is handed over to the application which will continue
+ * running the loop as it pleases. If the application exits cleanly the UI 
+ * thread will return back to here and the event loop can continue to run
+ * until the runtime signals shutdown. 
+ * 
+ * This class is the owner of the internal Display instance. 
+ */
+public final class EventLoop {
+
+    /*
+     * The internal Display instance. Owned by this class. 
+     */
+    private static Display internalDisplay;
+
+    /*
+     * Event loop can run here before the application's loop and after the UI
+     * thread exits from the application's loop. These states are identifying
+     * which of the two loops is currently running. 
+     */
+    private static final int PRE_APPLICATION = 0;
+    private static final int POST_APPLICATION = 1;
+    
+    /*
+     * Boolean used to detect when application has requested the UI thread and
+     * the hand-over must begin. 
+     */
+    private static volatile boolean applicationRequestedUIThread;
+
+    /*
+     * Boolean used to detect when the runtime wants to bring the UI down and
+     * the event loop must come down also. 
+     */
+    private static volatile boolean shuttingDownReceived;
+
+    /*
+     * Boolean used to store if starting has been attempted already. 
+     */
+    private static boolean started;
+    
+    /*
+     * Runnable that gets called in the UI thread when starting up. Named 
+     * class declared to be able to make it static. 
+     */
+    private static final class LoopRunner implements Runnable {
+        public void run() {
+            EventLoop.run();
+        }       
+    }
+    
+    /*
+     * Not to be instantiated. 
+     */
+    private EventLoop() {
+    }
+    
+    /**
+     * Returns the internal Display owned by the EventLoop class. Caller must 
+     * not dispose it. 
+     * @return The internal Display instance
+     * @throws RuntimeException
+     */
+    public static Display getInternalDisplay() {
+        synchronized(EventLoop.class) {
+            ensureStartedOrThrow();
+            return internalDisplay;
+        }
+    }
+
+    /*
+     * Starts the event loop. If this returns without throwing then the 
+     * internal Display instance has been successfully created and can be 
+     * asked with getInternalDisplay().
+     * 
+     * Any calls after the first successful call are ignored. Any calls after
+     * the first failed call will not retry but will throw.
+     */
+    private static void ensureStartedOrThrow() {
+        // This is called synchronized with the Display creation that takes 
+        // place in the UI thread. 
+        
+        if(!started) {
+            started = true;
+            
+            // Start the UI thread
+            if(!UIThreadLauncher.startInUIThread(new LoopRunner())) {
+                // Failed to create the UI thread, release the starting thread
+                EventLoop.class.notify();
+            }
+            
+            // Wait until the Display gets created in the UI thread
+            try {
+                EventLoop.class.wait();
+            } catch(InterruptedException e) {
+                // Nothing to do
+            }
+        }
+        
+        // Check Display creation status
+        if(internalDisplay == null) {
+            throw new RuntimeException("Failed to start");
+        }
+    }
+    
+    /*
+     * Start listening for the application requesting the UI thread via the
+     * eSWT's UIThreadSupport API. 
+     */
+    private static void listenApplicationUIThreadRequest() {
+        UIThreadHandOverManager.setApplicationUIListener(new ApplicationUIListener() {
+            /*
+             * Can get called in any thread but the UI thread. 
+             */
+            public void applicationUIThreadRequest() {
+                // Synchronized with the Display creation and destruction
+                synchronized(EventLoop.class) {
+                    applicationRequestedUIThread = true;
+                    // It's ok to skip wake if Display has not been created yet
+                    if(internalDisplay != null && !internalDisplay.isDisposed()) {
+                        internalDisplay.wake();
+                    }
+                }
+            }
+        });
+    }
+    
+    /*
+     * Start listening for the runtime's shutting down message. 
+     */
+    private static void listenRuntimeShutdownRequest() {
+        ApplicationUtils.getInstance().addShutdownListener(
+            /*
+             * Can get called in any thread but the UI thread. 
+             */
+            new ShutdownListener() {
+                public void shuttingDown() {
+                    // Synchronized with the Display creation and destruction
+                    synchronized(EventLoop.class) {
+                        shuttingDownReceived = true;
+                        // It's ok to skip wake if Display has not been created yet
+                        if(internalDisplay != null && !internalDisplay.isDisposed()) {
+                            internalDisplay.wake();
+                        }       
+                    }
+                }
+            });
+    }
+    
+    /*
+     * Creates the internal Display and runs the event loop. Called in the UI 
+     * thread. 
+     */
+    private static void run() {
+        try {
+            // Add the appropriate listeners. 
+            listenRuntimeShutdownRequest();
+            listenApplicationUIThreadRequest();
+            
+            // Create the internal Display. 
+            createInternalDisplay();
+    
+            // Run event loop until the application wants to take over or the 
+            // runtime signals shutdown. In the latter case exit from the UI 
+            // thread immediately. 
+            loop(PRE_APPLICATION);
+            if(shuttingDownReceived) {
+                return;
+            }
+            
+            // Hand over the UI thread to the application. The application is
+            // responsible of the event loop until it allows the UI thread to
+            // return back here. 
+            UIThreadHandOverManager.runApplicationUI();
+            
+            // Application allowed its event loop to exit. Continue 
+            // dispatching the events until the runtime wants to shut down. 
+            loop(POST_APPLICATION);
+            
+        } finally {
+            destroy();
+        }
+    }
+    
+    /* 
+     * Creates the Display. Synchronized with the starting thread that 
+     * waits until the Display has been created. 
+     */
+    private static void createInternalDisplay() {
+        synchronized(EventLoop.class) {
+            try {
+                // Will throw if fails
+                internalDisplay = Internal_PackageSupport.internalInstance();
+            } finally {
+                // Release the starting thread
+                EventLoop.class.notify();
+            }
+        }
+    }
+    
+    /*
+     * Frees all the owned resources when shutting down. Ideally this would be
+     * executed only after all the application's threads have been finalized. 
+     * If the application's threads are still running it's possible that 
+     * someone would try to access the internal Display after this. This would 
+     * cause an exception with "device is disposed".
+     */
+    private static void destroy() {
+        // Synchronized with the shutting down message and the application UI 
+        // thread request. 
+        synchronized(EventLoop.class) {
+            if(internalDisplay != null) {
+                // If this throws then Display.dispose() was called on the 
+                // internal Display by someone who doesn't own it. 
+                if(internalDisplay.isDisposed()) {
+                    throw new RuntimeException(
+                            "Internal Display has been disposed by someone who " +
+                            "doesn't own it");
+                }
+                
+                // If the application's Display has been disposed then 
+                // disposing also the internal Display here would destroy the 
+                // QApplication and all the UI resources tied to it. Disposing 
+                // is not done but the resources are allowed to leak on 
+                // purpose:
+                //
+                // In MIDP many of the related APIs are thread-safe and are 
+                // exclusively using garbage collection for memory management. 
+                // Disposing the UI resources of API objects that still may be 
+                // referenced would create a deviation from the pattern and 
+                // that would need special handling all around the API 
+                // implementations. That handling is not attempted but instead 
+                // the internal Display instance is allowed to live until the 
+                // process terminates. 
+            }
+        }
+    }
+    
+    /*
+     * The event loop that can run before and after the application's loop. 
+     * State parameter tells which one of the two this is. The exit 
+     * condition depends on the state. 
+     */
+    private static void loop(final int state) {
+        while(!loopExitCondition(state)) {
+            if(!internalDisplay.readAndDispatch()) {
+                internalDisplay.sleep();
+            }
+        }
+    }
+    
+    /*
+     * Checks if the loop exit condition is met. The condition is different
+     * depending on if the loop is running before or after the application's
+     * loop.
+     */
+    private static boolean loopExitCondition(final int state) {
+        switch(state) {
+        case PRE_APPLICATION:
+            return shuttingDownReceived || applicationRequestedUIThread;
+        case POST_APPLICATION:
+            return shuttingDownReceived;
+        default:
+            return true;
+        }
+    }
+}