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 ? |
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); |