summaryrefslogtreecommitdiff
path: root/gnu/java
diff options
context:
space:
mode:
authorThomas Fitzsimmons <fitzsim@redhat.com>2006-10-17 23:22:55 +0000
committerThomas Fitzsimmons <fitzsim@redhat.com>2006-10-17 23:22:55 +0000
commitbb399a428a72333eb5f74d31084e0c80c002f977 (patch)
tree3812132e7f208560168935c0617946b7a14e7c24 /gnu/java
parenta86ca2a463e3e5e7dc970235836e9158cda50e22 (diff)
downloadclasspath-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')
-rw-r--r--gnu/java/awt/peer/gtk/GtkMainThread.java138
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);
+ }
+}