javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/common_j2me/org/eclipse/swt/internal/qt/UIThreadHandOverManager.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/UIThreadHandOverManager.java	Mon Oct 04 11:29:25 2010 +0300
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * 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.ApplicationUIListener;
+import org.eclipse.swt.internal.qt.midp.UIThreadLauncher;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Internal_PackageSupport;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A class that manages the UI thread hand-over from the internal UI event 
+ * loop to the application. 
+ */
+public final class UIThreadHandOverManager {
+    private static Object lock = new Object();
+    private static boolean threadWaitingForApplication;
+    private static Runnable applicationRunnable;
+    private static ApplicationUIListener applicationUIListener;
+    
+    /**
+     * Pass the control of the thread to the application by calling a Runnable
+     * provided by the application. If the Runnable has not yet been provided
+     * then the thread waits until it becomes available, or the wait is aborted
+     * by calling <code>abortWait()</code>. 
+     */
+    public static void runApplicationUI() {
+        synchronized(lock) {
+            if(!applicationWaiting()) {
+                waitForApplication();
+            } else {
+                // Release the waiting application thread
+                lock.notify();
+            }
+        }
+        callback();
+    }
+
+    /**
+     * If the UI thread is waiting for the application to request the callback
+     * in the UI thread then calling this will abort the wait and make the UI
+     * thread to return back from the <code>runApplicationUI()</code>.
+     */
+    public static void abortWait() {
+        synchronized(lock) {
+            if(threadWaitingForApplication) {
+                lock.notify();
+            }
+        }
+    }
+
+    /**
+     * Called indirectly by the application when it's requesting the UI thread. 
+     * Application will pass a Runnable as a parameter and expects it to get called
+     * in the UI thread. 
+     * 
+     * @param runnable
+     *            The Runnable to call in the UI thread.
+     * @return True if obtaining the UI thread was successful and the runnable
+     *         will be called.
+     */
+    public static boolean startInUIThread(Runnable runnable) {
+        // Make sure that the internal event loop is started. 
+        EventLoop.getInternalDisplay();
+        
+        synchronized(lock) {
+            applicationRunnable = runnable;
+            if(threadWaitingForApplication) {
+                lock.notify();
+            } else {
+                if(!waitForUIThread()) {
+                    // If the internal UI has not been created then it can't be
+                    // signaled and we can't wait for it. This must mean there's
+                    // no UI thread yet in the process and we can create it here.
+                    if(!UIThreadLauncher.startInUIThread(runnable)) {
+                        return false;
+                    }   
+                }
+            }
+        }
+        return true;
+    }
+    
+    /**
+     * Sets the listener that will be notified of the state of the UI during its
+     * life-time.
+     */
+    public static void setApplicationUIListener(ApplicationUIListener listener) {
+        synchronized(lock) {
+            applicationUIListener = listener;
+        }
+    }
+    
+    /*
+     * Signal the internal UI loop and wait until it passes the control of the
+     * UI thread into runApplicationUI(). Return false if the internal UI can't
+     * be signaled. 
+     */
+    private static boolean waitForUIThread() {
+        if(signalUIThreadRequest()) {
+            try {
+                lock.wait();
+            } catch(InterruptedException e) {
+                // Nothing to do
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /*
+     * Wait until signaled by the application requesting the callback to its
+     * Runnable, or by abortWait().
+     */
+    private static void waitForApplication() {
+        threadWaitingForApplication = true;
+        try {
+            lock.wait();
+        } catch(InterruptedException e) {
+            // Nothing to do
+        } finally {
+            threadWaitingForApplication = false;
+        }       
+    }
+    
+    /*
+     * Returns true if application has provided the Runnable and is thus waiting
+     * for the callback.
+     */
+    private static boolean applicationWaiting() {
+        return (applicationRunnable != null);
+    }
+    
+    /*
+     * Post an event to the internal Display to request the control of the UI
+     * thread. After this runApplication() should get called in the UI thread.
+     */
+    private static boolean signalUIThreadRequest() {
+        Display internalDisplay = Internal_PackageSupport.getInternalDisplayInstance();
+        if(internalDisplay != null) {
+            if(applicationUIListener != null) {
+                applicationUIListener.applicationUIThreadRequest();
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /*
+     * Call back the application's runnable
+     */
+    private static void callback() {
+        try {
+            boolean runnableOk;
+            synchronized(lock) {
+                runnableOk = (applicationRunnable != null);
+            }
+            if(runnableOk) {
+                flushInternals();
+                applicationRunnable.run();
+            }
+        } finally {
+            synchronized(lock) {
+                applicationRunnable = null;
+            }
+        }
+    }
+    
+    /*
+     * Clear any events or other items possibly left over by any previous usage
+     * of the UI resources. There must not be anything that can interfere with
+     * the application. It must appear as the application starts with an
+     * uninitialized UI.
+     */
+    private static void flushInternals() {
+        Display internalDisplay = Internal_PackageSupport.getInternalDisplayInstance();
+        
+        // Dispose all widgets
+        Shell[] shells = internalDisplay.getShells();
+        for(int i = 0; i < shells.length; ++i) {
+            if(shells[i] != null && !shells[i].isDisposed()) {
+                shells[i].dispose();
+            }
+        }
+        
+        // Flush the event queue
+        while(internalDisplay.readAndDispatch()) {}
+    }
+}