javauis/lcdui_qt/src/javax/microedition/lcdui/ESWTUIThreadRunner.java
changeset 50 023eef975703
parent 23 98ccebc37403
equal deleted inserted replaced
49:35baca0e7a2e 50:023eef975703
     1 /*
     1 /*
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
     2 * Copyright (c) 2009, 2010 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     4 * This component and the accompanying materials are made available
     5 * under the terms of "Eclipse Public License v1.0"
     5 * under the terms of "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
    28 import com.nokia.mj.impl.rt.support.*;
    28 import com.nokia.mj.impl.rt.support.*;
    29 
    29 
    30 /**
    30 /**
    31  * Singleton class which is responsible to run the eSWT UI thread. This class is
    31  * Singleton class which is responsible to run the eSWT UI thread. This class is
    32  * also access-point to eSWT's Display-class.<br>
    32  * also access-point to eSWT's Display-class.<br>
    33  * <br>
       
    34  * UI thread is started in static initialization block. If another UI Thread is
       
    35  * created before that the run()-method will fail and this class won't try to
       
    36  * run UI thread anymore. Instead, existing UI-thread will be used to run LCDUI.
       
    37  * <br>
       
    38  * <br>
       
    39  * Note that the method getDisplay() will still work normally.<br>
       
    40  * <br>
       
    41  * Also note that if the other thread which is running eSWT stops executing then
       
    42  * this class stops working too.
       
    43  */
    33  */
    44 final class ESWTUIThreadRunner implements Listener, ShutdownListener, Runnable
    34 final class ESWTUIThreadRunner implements Listener, ShutdownListener, Runnable
    45 {
    35 {
    46 
    36     // States of the UI event loop
    47     private static final int NONE = 1;
    37     private static final int NONE = 1;
    48     private static final int CREATING = 2;
    38     private static final int CREATING = 2;
    49     private static final int RUNNING = 4;
    39     private static final int RUNNING = 4;
    50     private static final int EXITING = 8;
    40     private static final int EXITING = 8;
    51     private static final int ALL = NONE | CREATING | RUNNING | EXITING;
    41     private static final int ALL = NONE | CREATING | RUNNING | EXITING;
    52 
    42 
       
    43     // Singleton instance
    53     private static ESWTUIThreadRunner instance;
    44     private static ESWTUIThreadRunner instance;
       
    45 
    54     private static int lastKeyScancode;
    46     private static int lastKeyScancode;
    55     private static int lastKeyModifier;
    47     private static int lastKeyModifier;
    56     private static int keyRepeatCount;
    48     private static int keyRepeatCount;
    57 
    49 
    58     static DisposeStorage ds;
    50     static DisposeStorage ds;
    59     private static Hashtable finalizers = new Hashtable();
    51     private static Hashtable finalizers = new Hashtable();
    60 
    52 
    61     private Object lock = new Object();
    53     private Object lock = new Object();
    62 
    54 
       
    55     // For synchronously shutting down
       
    56     private Object uiThreadShutdownLock = new Object();
       
    57     private boolean uiThreadStarted;
       
    58     private boolean uiThreadShutdownRequested;
       
    59     private boolean uiThreadExitNotified;
       
    60 
    63     private Display display;
    61     private Display display;
    64     private int state = NONE;
    62     private int state = NONE;
    65 
    63 
    66     static
    64     static
    67     {
    65     {
    68         // Create LCDUIInvoker for MMAPI to access underlying eSWT widgets
    66         // Create LCDUIInvoker for MMAPI to access underlying eSWT widgets
    69         LCDUIInvokerImpl.createInvoker();
    67         LCDUIInvokerImpl.createInvoker();
    70 
    68 
    71         // Create dispose storage to clean up newly created Fonts and Images.
    69         // Create dispose storage to clean up newly created Fonts and Images.
    72         ds = new DisposeStorage();
    70         ds = new DisposeStorage();
    73 
       
    74         // Starting thread here makes sure that eSWT services
       
    75         // are always available when they are needed.
       
    76 
       
    77         // uiThread = new Thread(getInstance(), UI_THREAD_NAME);
       
    78         // uiThread.start();
       
    79     }
    71     }
    80 
    72 
    81     /**
    73     /**
    82      * Private Constructor. Singleton.
    74      * Private Constructor. Singleton.
    83      */
    75      */
    84     private ESWTUIThreadRunner()
    76     private ESWTUIThreadRunner()
    85     {
    77     {
    86         Logger.info("Starting up");
    78         Logger.info("ESWTUIThreadRunner: Starting up");
    87 
    79 
    88         // TODO: check if the startUI throws RuntimeException on already
    80         // TODO: check if the startUI throws RuntimeException on already
    89         // existing UI thread
    81         // existing UI thread
    90 
    82 
    91         // launch UI thread - TODO: also check return value/catch possible exceptions - what to do ?
    83         // launch UI thread - TODO: also check return value/catch possible exceptions - what to do ?
   257     {
   249     {
   258         switch(e.type)
   250         switch(e.type)
   259         {
   251         {
   260         case SWT.Close:
   252         case SWT.Close:
   261         {
   253         {
   262             Logger.info("Close event");
   254             Logger.info("ESWTUIThreadRunner: Close event");
   263             // Check if the No-Exit attribute is set
   255             // Check if the No-Exit attribute is set
   264             if(JadAttributeUtil.isValue(JadAttributeUtil.ATTRIB_NOKIA_MIDLET_NO_EXIT, JadAttributeUtil.VALUE_TRUE))
   256             if(JadAttributeUtil.isValue(JadAttributeUtil.ATTRIB_NOKIA_MIDLET_NO_EXIT, JadAttributeUtil.VALUE_TRUE))
   265             {
   257             {
   266                 // don't exit
   258                 // don't exit
   267                 e.doit = false;
   259                 e.doit = false;
   300     /* (non-Javadoc)
   292     /* (non-Javadoc)
   301      * @see com.nokia.mj.impl.rt.support.ShutdownListener#shuttingDown()
   293      * @see com.nokia.mj.impl.rt.support.ShutdownListener#shuttingDown()
   302      */
   294      */
   303     public void shuttingDown()
   295     public void shuttingDown()
   304     {
   296     {
   305         Logger.info("Shutting Down");
   297         Logger.info("ESWTUIThreadRunner: Shutdown requested, performing synchronous shutdown");
   306         EventDispatcher.instance().terminate(new Runnable()
   298 
   307         {
   299         synchronized(uiThreadShutdownLock)
   308             public void run()
   300         {
   309             {
   301             // Set a flag that prevents the UI thread from starting the event
   310                 changeState(EXITING);
   302             // loop if it hasn't done that yet.
   311             }
   303             uiThreadShutdownRequested = true;
   312         });
   304 
   313     }
   305             Logger.info("ESWTUIThreadRunner: Asynchronously signalling LCDUI event dispatcher to exit");
   314 
   306             EventDispatcher.instance().terminate(new Runnable()
   315     /**
   307             {
   316      * Creates new eSWT Display and runs eSWT UI-thread.
   308                 public void run()
   317      */
   309                 {
   318     public void run()
   310                     Logger.info("ESWTUIThreadRunner: LCDUI event dispatcher signalled having completed its exit procedure, initiating UI event loop exit");
       
   311                     changeState(EXITING);
       
   312                 }
       
   313             });
       
   314 
       
   315             // Wait until UI cleanup completes.
       
   316             try {
       
   317                 // Don't wait if the UI thread hasn't started.
       
   318                 if(!uiThreadStarted)
       
   319                 {
       
   320                     Logger.info("ESWTUIThreadRunner: The UI thread has not been started, shutdown complete");
       
   321                     return;
       
   322                 }
       
   323                 // Don't wait if the UI thread already went past the exit
       
   324                 // notification phase.
       
   325                 if(uiThreadExitNotified)
       
   326                 {
       
   327                     Logger.info("ESWTUIThreadRunner: The UI thread has notified having exited, no need to wait, shutdown complete");
       
   328                     return;
       
   329                 }
       
   330 
       
   331                 // The UI thread is running, wait for it to exit
       
   332                 Logger.info("ESWTUIThreadRunner: Waiting for the UI thread to exit");
       
   333                 uiThreadShutdownLock.wait(3000);
       
   334 
       
   335                 if(uiThreadExitNotified)
       
   336                 {
       
   337                     Logger.info("ESWTUIThreadRunner: The UI thread notified having completed its exit procedure");
       
   338                 }
       
   339                 else
       
   340                 {
       
   341                     Logger.error("ESWTUIThreadRunner: UI thread exit wait timed out");
       
   342                     return;
       
   343                 }
       
   344             }
       
   345             catch(InterruptedException e)
       
   346             {
       
   347                 Logger.error("ESWTUIThreadRunner: The wait for the UI thread to exit was interrupted");
       
   348             }
       
   349         }
       
   350         Logger.info("ESWTUIThreadRunner: Synchronous UI shutdown is complete");
       
   351     }
       
   352 
       
   353     /*
       
   354      * The entry point of the UI thread.
       
   355      */
       
   356     public void run() {
       
   357         try {
       
   358             synchronized(uiThreadShutdownLock)
       
   359             {
       
   360                 uiThreadStarted = true;
       
   361                 if(uiThreadShutdownRequested)
       
   362                 {
       
   363                     return;
       
   364                 }
       
   365             }
       
   366             runEventLoop();
       
   367         }
       
   368         finally
       
   369         {
       
   370             synchronized(uiThreadShutdownLock)
       
   371             {
       
   372                 uiThreadExitNotified = true;
       
   373                 uiThreadShutdownLock.notifyAll();
       
   374             }
       
   375         }
       
   376     }
       
   377 
       
   378     /**
       
   379      * Creates new eSWT Display and runs eSWT UI event loop.
       
   380      */
       
   381     private void runEventLoop()
   319     {
   382     {
   320         changeState(CREATING);
   383         changeState(CREATING);
   321         onStartup();
   384         onStartup();
   322         while(isState(ALL - EXITING))
   385         while(isState(ALL - EXITING))
   323         {
   386         {
   338                 {
   401                 {
   339                     Throwable t = ((SWTException) ex).getCause();
   402                     Throwable t = ((SWTException) ex).getCause();
   340                     if(t != null && t instanceof RuntimeException)
   403                     if(t != null && t instanceof RuntimeException)
   341                     {
   404                     {
   342                         // this might be an expected exception of safeSyncExec
   405                         // this might be an expected exception of safeSyncExec
   343                         Logger.warning("eSWT Thread Exception: " + ex);
   406                         Logger.warning("ESWTUIThreadRunner: eSWT Thread Exception: " + ex);
   344                         // t.printStackTrace();
   407                         // t.printStackTrace();
   345                     }
   408                     }
   346                 }
   409                 }
   347                 else
   410                 else
   348                 {
   411                 {
   349                     Logger.error("eSWT Thread Exception: " + ex);
   412                     Logger.error("ESWTUIThreadRunner: eSWT Thread Exception: " + ex);
   350                     ex.printStackTrace();
   413                     ex.printStackTrace();
   351                 }
   414                 }
   352             }
   415             }
   353             catch(Error er)
   416             catch(Error er)
   354             {
   417             {
   355                 Logger.error("eSWT Thread Error" + er);
   418                 Logger.error("ESWTUIThreadRunner: eSWT Thread Error" + er);
   356                 er.printStackTrace();
   419                 er.printStackTrace();
   357             }
   420             }
   358         }
   421         }
   359         onShutdown();
   422         onShutdown();
   360         changeState(NONE);
   423         changeState(NONE);
   368         }
   431         }
   369     }
   432     }
   370 
   433 
   371     private void changeState(int newstate)
   434     private void changeState(int newstate)
   372     {
   435     {
   373         Logger.info(getStateString(state) + " --> " + getStateString(newstate));
   436         Logger.info("ESWTUIThreadRunner: Event loop state: " + getStateString(state) + " --> " + getStateString(newstate));
   374         if(display != null)
   437         if(display != null)
   375         {
   438         {
   376             try
   439             try
   377             {
   440             {
   378                 display.wake();
   441                 display.wake();
   452             String key = (String) e.nextElement();
   515             String key = (String) e.nextElement();
   453             Logger.info(key + " : " + (finalizers.get(key)));
   516             Logger.info(key + " : " + (finalizers.get(key)));
   454         }
   517         }
   455         finalizers.clear();
   518         finalizers.clear();
   456     }
   519     }
   457 
       
   458 
       
   459 }
   520 }