javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/qt/org/eclipse/swt/internal/qt/UIThreadManager.java
changeset 78 71ad690e91f5
parent 72 1f0034e370aa
child 80 d6dafc5d983f
equal deleted inserted replaced
72:1f0034e370aa 78:71ad690e91f5
     1 /*******************************************************************************
       
     2  * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3  * All rights reserved. This program and the accompanying materials
       
     4  * are made available under the terms of the Eclipse Public License v1.0
       
     5  * which accompanies this distribution, and is available at
       
     6  * http://www.eclipse.org/legal/epl-v10.html
       
     7  *
       
     8  * Contributors:
       
     9  *     Nokia Corporation - initial implementation
       
    10  *******************************************************************************/
       
    11 
       
    12 package org.eclipse.swt.internal.qt;
       
    13 
       
    14 import org.eclipse.swt.internal.qt.ApplicationUIListener;
       
    15 import org.eclipse.swt.internal.qt.midp.UIThreadLauncher;
       
    16 import org.eclipse.swt.widgets.Display;
       
    17 import org.eclipse.swt.widgets.Internal_PackageSupport;
       
    18 import org.eclipse.swt.widgets.Shell;
       
    19 
       
    20 /**
       
    21  * A class that manages the UI thread hand-over from the internal UI event loop
       
    22  * to the application.
       
    23  */
       
    24 public final class UIThreadManager {
       
    25 	private static Object lock = new Object();
       
    26 	private static boolean threadWaitingForApplication;
       
    27 	private static Runnable applicationRunnable;
       
    28 	private static ApplicationUIListener applicationUIListener;
       
    29 		
       
    30 	/**
       
    31 	 * Pass the control of the thread to the application by calling a Runnable
       
    32 	 * provided by the application. If the Runnable has not yet been provided
       
    33 	 * then the thread waits until it becomes available, or the wait is aborted
       
    34 	 * by calling <code>abortWait()</code>. 
       
    35 	 */
       
    36 	public static void runApplicationUI() {
       
    37 		synchronized(lock) {
       
    38 			if(!applicationWaiting()) {
       
    39 				waitForApplication();
       
    40 			}
       
    41 			callback();
       
    42 		}
       
    43 	}
       
    44 
       
    45 	/**
       
    46 	 * If the UI thread is waiting for the application to request the callback
       
    47 	 * in the UI thread then calling this will abort the wait and make the UI
       
    48 	 * thread to return back from the <code>runApplicationUI()</code>.
       
    49 	 */
       
    50 	public static void abortWait() {
       
    51 		synchronized(lock) {
       
    52 			lock.notify();
       
    53 		}
       
    54 	}
       
    55 
       
    56 	/**
       
    57 	 * Called indirectly by the application when it's requesting the UI thread. 
       
    58 	 * Application will pass a Runnable as a parameter and expects it to get called
       
    59 	 * in the UI thread. 
       
    60 	 * 
       
    61 	 * @param runnable
       
    62 	 *            The Runnable to call in the UI thread.
       
    63 	 * @return True if obtaining the UI thread was successful and the runnable
       
    64 	 *         will be called.
       
    65 	 */
       
    66 	public static boolean startInUIThread(Runnable runnable) {
       
    67 		synchronized(lock) {
       
    68 			applicationRunnable = runnable;
       
    69 			if(threadWaitingForApplication) {
       
    70 				lock.notify();
       
    71 			} else {
       
    72 				if(!waitForUIThread()) {
       
    73 					// If the internal UI has not been created then it can't be
       
    74 					// signaled and we can't wait for it. This must mean there's
       
    75 					// no UI thread yet in the process and we can create it here.
       
    76 					if(!UIThreadLauncher.startInUIThread(runnable)) {
       
    77 				    	return false;
       
    78 				    }	
       
    79 				}
       
    80 			}
       
    81 		}
       
    82 		return true;
       
    83 	}
       
    84 	
       
    85 	/**
       
    86 	 * Sets the listener that will be notified of the state of the UI during its
       
    87 	 * life-time.
       
    88 	 */
       
    89 	public static void setApplicationUIListener(ApplicationUIListener listener) {
       
    90 		synchronized(lock) {
       
    91 			applicationUIListener = listener;
       
    92 		}
       
    93 	}
       
    94 	
       
    95 	/*
       
    96 	 * Signal the internal UI loop and wait until it passes the control of the
       
    97 	 * UI thread into runApplicationUI(). Return false if the internal UI can't
       
    98 	 * be signaled. 
       
    99 	 */
       
   100 	private static boolean waitForUIThread() {
       
   101 		if(signalUIThreadRequest()) {
       
   102 			try {
       
   103 				lock.wait();
       
   104 			} catch(InterruptedException e) {
       
   105 				// Nothing to do
       
   106 			}
       
   107 			return true;
       
   108 		}
       
   109 		return false;
       
   110 	}
       
   111 
       
   112 	/*
       
   113 	 * Wait until signaled by the application requesting the callback to its
       
   114 	 * Runnable, or by abortWait().
       
   115 	 */
       
   116 	private static void waitForApplication() {
       
   117 		threadWaitingForApplication = true;
       
   118 		try {
       
   119 			lock.wait();
       
   120 		} catch(InterruptedException e) {
       
   121 			// Nothing to do
       
   122 		} finally {
       
   123 			threadWaitingForApplication = false;
       
   124 		}		
       
   125 	}
       
   126 	
       
   127 	/*
       
   128 	 * Returns true if application has provided the Runnable and is thus waiting
       
   129 	 * for the callback.
       
   130 	 */
       
   131 	private static boolean applicationWaiting() {
       
   132 		return (applicationRunnable != null);
       
   133 	}
       
   134 	
       
   135 	/*
       
   136 	 * Post an event to the internal Display to request the control of the UI
       
   137 	 * thread. After this runApplication() should get called in the UI thread.
       
   138 	 */
       
   139 	private static boolean signalUIThreadRequest() {
       
   140 		Display internalDisplay = Internal_PackageSupport.getInternalDisplayInstance();
       
   141 		if(internalDisplay != null) {
       
   142 			if(applicationUIListener != null) {
       
   143 				applicationUIListener.applicationUIThreadRequest();
       
   144 			}
       
   145 			return true;
       
   146 		}
       
   147 		return false;
       
   148 	}
       
   149 
       
   150 	/*
       
   151 	 * Call back the application's runnable
       
   152 	 */
       
   153 	private static void callback() {
       
   154 		try {
       
   155 			if(applicationRunnable != null) {
       
   156 				flushInternals();
       
   157 				applicationRunnable.run();
       
   158 			}
       
   159 		} finally {
       
   160 			applicationRunnable = null;
       
   161 		}
       
   162 	}
       
   163 	
       
   164 	/*
       
   165 	 * Clear any events or other items possibly left over by any previous usage
       
   166 	 * of the UI resources. There must not be anything that can interfere with
       
   167 	 * the application. It must appear as the application starts with an
       
   168 	 * uninitialized UI.
       
   169 	 */
       
   170 	private static void flushInternals() {
       
   171 		Display internalDisplay = Internal_PackageSupport.getInternalDisplayInstance();
       
   172 		
       
   173 		// Dispose all widgets
       
   174 		Shell[] shells = internalDisplay.getShells();
       
   175 		for(int i = 0; i < shells.length; ++i) {
       
   176 			if(shells[i] != null && !shells[i].isDisposed()) {
       
   177 				shells[i].dispose();
       
   178 			}
       
   179 		}
       
   180 		
       
   181 		// Flush the event queue
       
   182 		while(internalDisplay.readAndDispatch()) {}
       
   183 	}
       
   184 }