diff options
| author | Thomas Fitzsimmons <fitzsim@redhat.com> | 2006-10-17 23:22:55 +0000 |
|---|---|---|
| committer | Thomas Fitzsimmons <fitzsim@redhat.com> | 2006-10-17 23:22:55 +0000 |
| commit | bb399a428a72333eb5f74d31084e0c80c002f977 (patch) | |
| tree | 3812132e7f208560168935c0617946b7a14e7c24 /gnu/java/awt/peer/gtk/GtkMainThread.java | |
| parent | a86ca2a463e3e5e7dc970235836e9158cda50e22 (diff) | |
| download | classpath-bb399a428a72333eb5f74d31084e0c80c002f977.tar.gz | |
2006-10-17 Thomas Fitzsimmons <fitzsim@redhat.com>
* gnu/java/awt/peer/gtk/GtkMainThread.java: Introduce running flag
to track native GTK event loop status.
* native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c: Set and
clear running flag when native GTK event loop starts and stops.
Diffstat (limited to 'gnu/java/awt/peer/gtk/GtkMainThread.java')
| -rw-r--r-- | gnu/java/awt/peer/gtk/GtkMainThread.java | 138 |
1 files changed, 128 insertions, 10 deletions
diff --git a/gnu/java/awt/peer/gtk/GtkMainThread.java b/gnu/java/awt/peer/gtk/GtkMainThread.java index 19d3f1d0b..fe374bd9d 100644 --- a/gnu/java/awt/peer/gtk/GtkMainThread.java +++ b/gnu/java/awt/peer/gtk/GtkMainThread.java @@ -38,6 +38,53 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; +import java.awt.AWTEvent; + +/** + * This class implements the AWT exit conditions listed here: + * + * http://java.sun.com/j2se/1.5.0/docs/api/java/awt/doc-files/AWTThreadIssues.html + * + * The Java thread representing the native GTK main loop, that is, + * GtkMainThread.mainThread, terminates when GtkToolkit.gtkMain() + * returns. That happens in response to the last window peer being + * disposed (see GtkWindowPeer.dispose). + * + * When GtkMainThread.destroyWindow is called for the last window, it + * in turn calls GtkMainThread.endMainThread, which calls gtk_quit. + * gtk_quit signals gtk_main to return, which causes GtkMainThread.run + * to return. + * + * There should only be one native GTK main loop running at any given + * time. In order to safely start and stop the GTK main loop, we use + * a running flag and corresponding runningLock. startMainThread will + * not return until the native GTK main loop has started, as confirmed + * by the native set_running_flag callback setting the running flag to + * true. Without this protection, gtk_quit could be called before the + * main loop has actually started, which causes GTK assertion + * failures. Likewise endMainThread will not return until the native + * GTK main loop has ended. + * + * post_running_flag_callback is called during gtk_main initialization + * and no window can be created before startMainThread returns. This + * ensures that calling post_running_flag_callback is the first action + * taken by the native GTK main loop. + * + * GtkMainThread.mainThread is started when the window count goes from + * zero to one. + * + * The three exit conditions in the above document are satisfied by + * GtkMainThread alone: 1) no displayable AWT or Swing components: if + * no window peers exist then no AWT or Swing component is + * displayable; 2) no native events in the native event queue: when + * the last window is disposed of, the native GTK main loop is + * terminated, which means that there is no native event queue let + * alone native events therein; 3) no AWT events in the AWT event + * queue: endMainThread posts a dummy event to the AWT event queue, + * which if the other exit conditions are satisfied, becomes the last + * event posted to the AWT event queue before the AWT event dispatch + * thread terminates. + */ public class GtkMainThread extends Thread { /** Count of the number of open windows */ @@ -46,6 +93,12 @@ public class GtkMainThread extends Thread /** Lock for the above */ private static Object nWindowsLock = new Object(); + /** Indicates whether or not the GTK main loop is running. */ + private static boolean running = false; + + /** Lock for the above. */ + private static Object runningLock = new Object(); + /** The main thread instance (singleton) */ public static GtkMainThread mainThread; @@ -60,26 +113,82 @@ public class GtkMainThread extends Thread GtkToolkit.gtkMain (); } + private static void setRunning(boolean running) + { + synchronized (runningLock) + { + GtkMainThread.running = running; + runningLock.notifyAll(); + } + } + private static void startMainThread() { - if( mainThread == null ) + synchronized (runningLock) { - mainThread = new GtkMainThread(); - mainThread.start(); + if (!running) + { + mainThread = new GtkMainThread(); + mainThread.start(); + + while (!running) + { + try + { + runningLock.wait(); + } + catch (InterruptedException e) + { + System.err.println ("GtkMainThread.startMainThread:" + + " interrupted while waiting " + + " for GTK main loop to start"); + } + } + } } } private static void endMainThread() { - if( mainThread != null ) - GtkToolkit.gtkQuit(); + synchronized (runningLock) + { + if (running) + { + GtkToolkit.gtkQuit(); + + while (running) + { + try + { + runningLock.wait(); + } + catch (InterruptedException e) + { + System.err.println ("GtkMainThread.endMainThread:" + + " interrupted while waiting " + + " for GTK main loop to stop"); + } + } + // Post a dummy event to wake up the AWT event dispatch + // thread. EventQueue.getNextEvent first checks the + // shutdown condition, then waits indefinitely for the + // next event to be posted. There is a possibility that + // the native GTK main loop will end between the + // isShutdown check and the wait call. Posting a dummy + // event here causes the AWT event dispatch thread to wake + // up, giving it a chance to check the shutdown condition + // again and terminate cleanly. + GtkGenericPeer.q() + .postEvent(new WakeupEventDispatchThreadEvent (mainThread)); + } + } } public static void createWindow() { - synchronized( nWindowsLock ) + synchronized (nWindowsLock) { - if( numberOfWindows == 0 ) + if (numberOfWindows == 0) startMainThread(); numberOfWindows++; } @@ -87,11 +196,20 @@ public class GtkMainThread extends Thread public static void destroyWindow() { - synchronized( nWindowsLock ) + synchronized (nWindowsLock) { numberOfWindows--; - if( numberOfWindows == 0 ) + if (numberOfWindows == 0) endMainThread(); } } -}
\ No newline at end of file +} + +class WakeupEventDispatchThreadEvent + extends AWTEvent +{ + WakeupEventDispatchThreadEvent(Object o) + { + super (o, 2000); + } +} |
