javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/common_j2me/org/eclipse/swt/internal/qt/UIThreadHandOverManager.java
changeset 78 71ad690e91f5
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 
       
    22  * loop to the application. 
       
    23  */
       
    24 public final class UIThreadHandOverManager {
       
    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             } else {
       
    41                 // Release the waiting application thread
       
    42                 lock.notify();
       
    43             }
       
    44         }
       
    45         callback();
       
    46     }
       
    47 
       
    48     /**
       
    49      * If the UI thread is waiting for the application to request the callback
       
    50      * in the UI thread then calling this will abort the wait and make the UI
       
    51      * thread to return back from the <code>runApplicationUI()</code>.
       
    52      */
       
    53     public static void abortWait() {
       
    54         synchronized(lock) {
       
    55             if(threadWaitingForApplication) {
       
    56                 lock.notify();
       
    57             }
       
    58         }
       
    59     }
       
    60 
       
    61     /**
       
    62      * Called indirectly by the application when it's requesting the UI thread. 
       
    63      * Application will pass a Runnable as a parameter and expects it to get called
       
    64      * in the UI thread. 
       
    65      * 
       
    66      * @param runnable
       
    67      *            The Runnable to call in the UI thread.
       
    68      * @return True if obtaining the UI thread was successful and the runnable
       
    69      *         will be called.
       
    70      */
       
    71     public static boolean startInUIThread(Runnable runnable) {
       
    72         // Make sure that the internal event loop is started. 
       
    73         EventLoop.getInternalDisplay();
       
    74         
       
    75         synchronized(lock) {
       
    76             applicationRunnable = runnable;
       
    77             if(threadWaitingForApplication) {
       
    78                 lock.notify();
       
    79             } else {
       
    80                 if(!waitForUIThread()) {
       
    81                     // If the internal UI has not been created then it can't be
       
    82                     // signaled and we can't wait for it. This must mean there's
       
    83                     // no UI thread yet in the process and we can create it here.
       
    84                     if(!UIThreadLauncher.startInUIThread(runnable)) {
       
    85                         return false;
       
    86                     }   
       
    87                 }
       
    88             }
       
    89         }
       
    90         return true;
       
    91     }
       
    92     
       
    93     /**
       
    94      * Sets the listener that will be notified of the state of the UI during its
       
    95      * life-time.
       
    96      */
       
    97     public static void setApplicationUIListener(ApplicationUIListener listener) {
       
    98         synchronized(lock) {
       
    99             applicationUIListener = listener;
       
   100         }
       
   101     }
       
   102     
       
   103     /*
       
   104      * Signal the internal UI loop and wait until it passes the control of the
       
   105      * UI thread into runApplicationUI(). Return false if the internal UI can't
       
   106      * be signaled. 
       
   107      */
       
   108     private static boolean waitForUIThread() {
       
   109         if(signalUIThreadRequest()) {
       
   110             try {
       
   111                 lock.wait();
       
   112             } catch(InterruptedException e) {
       
   113                 // Nothing to do
       
   114             }
       
   115             return true;
       
   116         }
       
   117         return false;
       
   118     }
       
   119 
       
   120     /*
       
   121      * Wait until signaled by the application requesting the callback to its
       
   122      * Runnable, or by abortWait().
       
   123      */
       
   124     private static void waitForApplication() {
       
   125         threadWaitingForApplication = true;
       
   126         try {
       
   127             lock.wait();
       
   128         } catch(InterruptedException e) {
       
   129             // Nothing to do
       
   130         } finally {
       
   131             threadWaitingForApplication = false;
       
   132         }       
       
   133     }
       
   134     
       
   135     /*
       
   136      * Returns true if application has provided the Runnable and is thus waiting
       
   137      * for the callback.
       
   138      */
       
   139     private static boolean applicationWaiting() {
       
   140         return (applicationRunnable != null);
       
   141     }
       
   142     
       
   143     /*
       
   144      * Post an event to the internal Display to request the control of the UI
       
   145      * thread. After this runApplication() should get called in the UI thread.
       
   146      */
       
   147     private static boolean signalUIThreadRequest() {
       
   148         Display internalDisplay = Internal_PackageSupport.getInternalDisplayInstance();
       
   149         if(internalDisplay != null) {
       
   150             if(applicationUIListener != null) {
       
   151                 applicationUIListener.applicationUIThreadRequest();
       
   152             }
       
   153             return true;
       
   154         }
       
   155         return false;
       
   156     }
       
   157 
       
   158     /*
       
   159      * Call back the application's runnable
       
   160      */
       
   161     private static void callback() {
       
   162         try {
       
   163             boolean runnableOk;
       
   164             synchronized(lock) {
       
   165                 runnableOk = (applicationRunnable != null);
       
   166             }
       
   167             if(runnableOk) {
       
   168                 flushInternals();
       
   169                 applicationRunnable.run();
       
   170             }
       
   171         } finally {
       
   172             synchronized(lock) {
       
   173                 applicationRunnable = null;
       
   174             }
       
   175         }
       
   176     }
       
   177     
       
   178     /*
       
   179      * Clear any events or other items possibly left over by any previous usage
       
   180      * of the UI resources. There must not be anything that can interfere with
       
   181      * the application. It must appear as the application starts with an
       
   182      * uninitialized UI.
       
   183      */
       
   184     private static void flushInternals() {
       
   185         Display internalDisplay = Internal_PackageSupport.getInternalDisplayInstance();
       
   186         
       
   187         // Dispose all widgets
       
   188         Shell[] shells = internalDisplay.getShells();
       
   189         for(int i = 0; i < shells.length; ++i) {
       
   190             if(shells[i] != null && !shells[i].isDisposed()) {
       
   191                 shells[i].dispose();
       
   192             }
       
   193         }
       
   194         
       
   195         // Flush the event queue
       
   196         while(internalDisplay.readAndDispatch()) {}
       
   197     }
       
   198 }