diff options
author | Sven Gothel <[email protected]> | 2009-06-14 18:13:32 +0000 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2009-06-14 18:13:32 +0000 |
commit | a420720c605b6c7be231d277e858ce8d640ecb83 (patch) | |
tree | e3eaf7e3993c92c2cdee1951adc1532f6436d43f | |
parent | ca8a9b56532fe4710cc4f3742c385db06dec9252 (diff) |
NEWT Mac OS X - Adding support for multithreading:
See documentation in com.sun.javafx.newt.util.MainThread.
A platform independent java user application launch toolkit,
which by default just invokes the passed user class's main method.
In case of Mac OS X, it spawns a new thread to run the user app,
and uses it's own thread to handle tasks, here all windowing tasks
from the MacWindow.
Now you can run a multithreaded native NEWT application on Mac OS X,
just pipeline this new class on your commandline, ie
java -XstartOnFirstThread com.sun.javafx.newt.util.MainThread demos.es1.RedSquare -GL2 -GL2 -GL2 -GL2
All these changes are backward compatible, of course.
NEWT Window
Finer locking granularity of event handling methods,
to prevent deadlocks with the new MainThread serialization.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/branches/JOGL_2_SANDBOX@1947 232f8b59-042b-4e1e-8c03-345bb8c30851
-rw-r--r-- | make/build-newt.xml | 2 | ||||
-rwxr-xr-x | src/newt/classes/com/sun/javafx/newt/Window.java | 96 | ||||
-rwxr-xr-x | src/newt/classes/com/sun/javafx/newt/macosx/MacWindow.java | 159 | ||||
-rw-r--r-- | src/newt/classes/com/sun/javafx/newt/util/MainThread.java | 302 | ||||
-rw-r--r-- | src/newt/native/MacWindow.m | 22 | ||||
-rw-r--r-- | src/newt/native/NewtMacWindow.h | 5 | ||||
-rw-r--r-- | src/newt/native/NewtMacWindow.m | 5 |
7 files changed, 497 insertions, 94 deletions
diff --git a/make/build-newt.xml b/make/build-newt.xml index e13e9618e..a1b1baaea 100644 --- a/make/build-newt.xml +++ b/make/build-newt.xml @@ -96,7 +96,7 @@ <!-- partitioning --> <property name="java.part.core" - value="com/sun/javafx/newt/*, com/sun/javafx/newt/x11/*, com/sun/javafx/newt/windows/*, com/sun/javafx/newt/macosx/*, com/sun/javafx/newt/impl/*"/> + value="com/sun/javafx/newt/*, com/sun/javafx/newt/util/*, com/sun/javafx/newt/x11/*, com/sun/javafx/newt/windows/*, com/sun/javafx/newt/macosx/*, com/sun/javafx/newt/impl/*"/> <property name="java.part.opengl" value="com/sun/javafx/newt/opengl/*, com/sun/javafx/newt/opengl/kd/*"/> diff --git a/src/newt/classes/com/sun/javafx/newt/Window.java b/src/newt/classes/com/sun/javafx/newt/Window.java index ea4e22162..68cb97834 100755 --- a/src/newt/classes/com/sun/javafx/newt/Window.java +++ b/src/newt/classes/com/sun/javafx/newt/Window.java @@ -254,9 +254,15 @@ public abstract class Window implements NativeWindow if(DEBUG_WINDOW_EVENT) { System.out.println("Window.destroy() start "+Thread.currentThread().getName()); } - windowListeners = new ArrayList(); - mouseListeners = new ArrayList(); - keyListeners = new ArrayList(); + synchronized(windowListeners) { + windowListeners = new ArrayList(); + } + synchronized(mouseListeners) { + mouseListeners = new ArrayList(); + } + synchronized(keyListeners) { + keyListeners = new ArrayList(); + } closeNative(); invalidate(); if(DEBUG_WINDOW_EVENT) { @@ -396,26 +402,32 @@ public abstract class Window implements NativeWindow // MouseListener Support // - public synchronized void addMouseListener(MouseListener l) { + public void addMouseListener(MouseListener l) { if(l == null) { return; } - ArrayList newMouseListeners = (ArrayList) mouseListeners.clone(); - newMouseListeners.add(l); - mouseListeners = newMouseListeners; + synchronized(mouseListeners) { + ArrayList newMouseListeners = (ArrayList) mouseListeners.clone(); + newMouseListeners.add(l); + mouseListeners = newMouseListeners; + } } - public synchronized void removeMouseListener(MouseListener l) { + public void removeMouseListener(MouseListener l) { if (l == null) { return; } - ArrayList newMouseListeners = (ArrayList) mouseListeners.clone(); - newMouseListeners.remove(l); - mouseListeners = newMouseListeners; + synchronized(mouseListeners) { + ArrayList newMouseListeners = (ArrayList) mouseListeners.clone(); + newMouseListeners.remove(l); + mouseListeners = newMouseListeners; + } } - public synchronized MouseListener[] getMouseListeners() { - return (MouseListener[]) mouseListeners.toArray(); + public MouseListener[] getMouseListeners() { + synchronized(mouseListeners) { + return (MouseListener[]) mouseListeners.toArray(); + } } private ArrayList mouseListeners = new ArrayList(); @@ -480,7 +492,7 @@ public abstract class Window implements NativeWindow } ArrayList listeners = null; - synchronized(this) { + synchronized(mouseListeners) { listeners = mouseListeners; } for(Iterator i = listeners.iterator(); i.hasNext(); ) { @@ -523,26 +535,32 @@ public abstract class Window implements NativeWindow // KeyListener Support // - public synchronized void addKeyListener(KeyListener l) { + public void addKeyListener(KeyListener l) { if(l == null) { return; } - ArrayList newKeyListeners = (ArrayList) keyListeners.clone(); - newKeyListeners.add(l); - keyListeners = newKeyListeners; + synchronized(keyListeners) { + ArrayList newKeyListeners = (ArrayList) keyListeners.clone(); + newKeyListeners.add(l); + keyListeners = newKeyListeners; + } } - public synchronized void removeKeyListener(KeyListener l) { + public void removeKeyListener(KeyListener l) { if (l == null) { return; } - ArrayList newKeyListeners = (ArrayList) keyListeners.clone(); - newKeyListeners.remove(l); - keyListeners = newKeyListeners; + synchronized(keyListeners) { + ArrayList newKeyListeners = (ArrayList) keyListeners.clone(); + newKeyListeners.remove(l); + keyListeners = newKeyListeners; + } } - public synchronized KeyListener[] getKeyListeners() { - return (KeyListener[]) keyListeners.toArray(); + public KeyListener[] getKeyListeners() { + synchronized(keyListeners) { + return (KeyListener[]) keyListeners.toArray(); + } } private ArrayList keyListeners = new ArrayList(); @@ -554,7 +572,7 @@ public abstract class Window implements NativeWindow System.out.println("sendKeyEvent: "+e); } ArrayList listeners = null; - synchronized(this) { + synchronized(keyListeners) { listeners = keyListeners; } for(Iterator i = listeners.iterator(); i.hasNext(); ) { @@ -581,26 +599,32 @@ public abstract class Window implements NativeWindow private ArrayList windowListeners = new ArrayList(); - public synchronized void addWindowListener(WindowListener l) { + public void addWindowListener(WindowListener l) { if(l == null) { return; } - ArrayList newWindowListeners = (ArrayList) windowListeners.clone(); - newWindowListeners.add(l); - windowListeners = newWindowListeners; + synchronized(windowListeners) { + ArrayList newWindowListeners = (ArrayList) windowListeners.clone(); + newWindowListeners.add(l); + windowListeners = newWindowListeners; + } } - public synchronized void removeWindowListener(WindowListener l) { + public void removeWindowListener(WindowListener l) { if (l == null) { return; } - ArrayList newWindowListeners = (ArrayList) windowListeners.clone(); - newWindowListeners.remove(l); - windowListeners = newWindowListeners; + synchronized(windowListeners) { + ArrayList newWindowListeners = (ArrayList) windowListeners.clone(); + newWindowListeners.remove(l); + windowListeners = newWindowListeners; + } } - public synchronized WindowListener[] getWindowListeners() { - return (WindowListener[]) windowListeners.toArray(); + public WindowListener[] getWindowListeners() { + synchronized(windowListeners) { + return (WindowListener[]) windowListeners.toArray(); + } } protected void sendWindowEvent(int eventType) { @@ -609,7 +633,7 @@ public abstract class Window implements NativeWindow System.out.println("sendWindowEvent: "+e); } ArrayList listeners = null; - synchronized(this) { + synchronized(windowListeners) { listeners = windowListeners; } for(Iterator i = listeners.iterator(); i.hasNext(); ) { diff --git a/src/newt/classes/com/sun/javafx/newt/macosx/MacWindow.java b/src/newt/classes/com/sun/javafx/newt/macosx/MacWindow.java index 49cc84cba..f19c44341 100755 --- a/src/newt/classes/com/sun/javafx/newt/macosx/MacWindow.java +++ b/src/newt/classes/com/sun/javafx/newt/macosx/MacWindow.java @@ -35,6 +35,7 @@ package com.sun.javafx.newt.macosx; import javax.media.nativewindow.*; +import com.sun.javafx.newt.util.MainThread; import com.sun.javafx.newt.*; import com.sun.javafx.newt.impl.*; @@ -131,15 +132,22 @@ public class MacWindow extends Window { private long nativeWindow; - static { + private static volatile boolean isInit = false; + + public static synchronized void initSingleton() { + if(isInit) return; + isInit=true; + NativeLibLoader.loadNEWT(); - - if (!initIDs()) { + + if(!initIDs()) { throw new NativeWindowException("Failed to initialize jmethodIDs"); } + if(DEBUG) System.out.println("MacWindow.initIDs OK "+Thread.currentThread().getName()); } public MacWindow() { + initSingleton(); } protected void createNative(Capabilities caps) { @@ -149,12 +157,21 @@ public class MacWindow extends Window { } } - protected void closeNative() { - if (nativeWindow != 0) { - close0(nativeWindow); - nativeWindow = 0; + class CloseAction implements Runnable { + public void run() { + if(DEBUG) System.out.println("MacWindow.CloseAction "+Thread.currentThread().getName()); + if (nativeWindow != 0) { + close0(nativeWindow); + nativeWindow = 0; + } } } + private CloseAction closeAction = new CloseAction(); + + protected void closeNative() { + if(DEBUG) System.out.println("MacWindow.closeNative "+Thread.currentThread().getName()); + MainThread.invoke(true, this, closeAction); + } public long getSurfaceHandle() { if (nativeWindow == 0) { @@ -163,63 +180,112 @@ public class MacWindow extends Window { return contentView(nativeWindow); } - public void setVisible(boolean visible) { - if (visible) { - boolean created = false; - if (nativeWindow == 0) { - nativeWindow = createWindow(getX(), getY(), getWidth(), getHeight(), - (isUndecorated() ? - NSBorderlessWindowMask : - NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), - NSBackingStoreBuffered, - true); - setTitle0(nativeWindow, getTitle()); - created = true; - } - makeKeyAndOrderFront(nativeWindow); - if (created) { - sendWindowEvent(WindowEvent.EVENT_WINDOW_MOVED); - sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); - sendWindowEvent(WindowEvent.EVENT_WINDOW_GAINED_FOCUS); - } - } else { - if (nativeWindow != 0) { - orderOut(nativeWindow); + class VisibleAction implements Runnable { + public void run() { + if(DEBUG) System.out.println("MacWindow.VisibleAction "+visible+" "+Thread.currentThread().getName()); + if (visible) { + boolean created = false; + if (nativeWindow == 0) { + nativeWindow = createWindow(getX(), getY(), getWidth(), getHeight(), + (isUndecorated() ? + NSBorderlessWindowMask : + NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), + NSBackingStoreBuffered, + true); + setTitle0(nativeWindow, getTitle()); + created = true; + } + makeKeyAndOrderFront(nativeWindow); + if (created) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_MOVED); + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); + sendWindowEvent(WindowEvent.EVENT_WINDOW_GAINED_FOCUS); + } + } else { + if (nativeWindow != 0) { + orderOut(nativeWindow); + } } } + } + private VisibleAction visibleAction = new VisibleAction(); + public void setVisible(boolean visible) { this.visible = visible; + if(DEBUG) System.out.println("MacWindow.setVisible "+visible+" "+Thread.currentThread().getName()); + MainThread.invoke(true, this, visibleAction); + } + + class TitleAction implements Runnable { + public void run() { + if (nativeWindow != 0) { + setTitle0(nativeWindow, title); + } + } } + private TitleAction titleAction = new TitleAction(); public void setTitle(String title) { super.setTitle(title); - if (nativeWindow != 0) { - setTitle0(nativeWindow, title); + MainThread.invoke(true, this, titleAction); + } + + class FocusAction implements Runnable { + public void run() { + if (nativeWindow != 0) { + makeKey(nativeWindow); + } } } + private FocusAction focusAction = new FocusAction(); public void requestFocus() { super.requestFocus(); - if (nativeWindow != 0) { - makeKey(nativeWindow); - } + MainThread.invoke(true, this, focusAction); } - public void setSize(int width, int height) { - this.width = width; - this.height = height; - if (nativeWindow != 0) { - setContentSize(nativeWindow, width, height); + class SizeAction implements Runnable { + public void run() { + if (nativeWindow != 0) { + setContentSize(nativeWindow, width, height); + } } } + private SizeAction sizeAction = new SizeAction(); + + public void setSize(int width, int height) { + this.width=width; + this.height=height; + MainThread.invoke(true, this, sizeAction); + } + class PositionAction implements Runnable { + public void run() { + if (nativeWindow != 0) { + setFrameTopLeftPoint(nativeWindow, x, y); + } + } + } + private PositionAction positionAction = new PositionAction(); + public void setPosition(int x, int y) { - this.x = x; - this.y = y; - if (nativeWindow != 0) { - setFrameTopLeftPoint(nativeWindow, x, y); + this.x=x; + this.y=y; + MainThread.invoke(true, this, positionAction); + } + + class DispatchAction implements Runnable { + public void run() { + dispatchMessages0(nativeWindow, eventMask); } } + private DispatchAction dispatchAction = new DispatchAction(); + private int eventMask; + + public void dispatchMessages(int eventMask) { + this.eventMask=eventMask; + MainThread.invoke(false, this, dispatchAction); + } public boolean setFullscreen(boolean fullscreen) { // FIXME: implement this @@ -228,7 +294,7 @@ public class MacWindow extends Window { private void sizeChanged(int newWidth, int newHeight) { if (DEBUG) { - System.out.println("Size changed to " + newWidth + ", " + newHeight); + System.out.println(Thread.currentThread().getName()+" Size changed to " + newWidth + ", " + newHeight); } if (width != newWidth || height != newHeight) { width = newWidth; @@ -242,7 +308,7 @@ public class MacWindow extends Window { private void positionChanged(int newX, int newY) { if (DEBUG) { - System.out.println("Position changed to " + newX + ", " + newY); + System.out.println(Thread.currentThread().getName()+" Position changed to " + newX + ", " + newY); } if (x != newX || y != newY) { x = newX; @@ -347,6 +413,7 @@ public class MacWindow extends Window { protected void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { int key = convertKeyChar(keyChar); + if(DEBUG) System.out.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName()); // Note that we send the key char for the key code on this // platform -- we do not get any useful key codes out of the system super.sendKeyEvent(eventType, modifiers, key, keyChar); @@ -361,7 +428,7 @@ public class MacWindow extends Window { private native void orderOut(long window); private native void close0(long window); private native void setTitle0(long window, String title); - protected native void dispatchMessages(int eventMask); + protected native void dispatchMessages0(long window, int eventMask); private native long contentView(long window); private native void setContentSize(long window, int w, int h); private native void setFrameTopLeftPoint(long window, int x, int y); diff --git a/src/newt/classes/com/sun/javafx/newt/util/MainThread.java b/src/newt/classes/com/sun/javafx/newt/util/MainThread.java new file mode 100644 index 000000000..4c4d98e46 --- /dev/null +++ b/src/newt/classes/com/sun/javafx/newt/util/MainThread.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + */ + +package com.sun.javafx.newt.util; + +import java.util.*; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; + +import javax.media.nativewindow.*; + +import com.sun.javafx.newt.*; +import com.sun.javafx.newt.impl.*; +import com.sun.javafx.newt.macosx.MacWindow; +import com.sun.nativewindow.impl.NWReflection; + +/** + * NEWT Utility class MainThread<P> + * + * This class provides a startup singleton <i>main thread</i>, + * from which a new thread with the users main class is launched.<br> + * + * Such behavior is necessary for native windowing toolkits, + * where the windowing management must happen on the so called + * <i>main thread</i> e.g. for Mac OS X !<br> + * + * Utilizing this class as a launchpad, now you are able to + * use a NEWT multithreaded application with window handling within the different threads, + * even on these restricted platforms.<br> + * + * To support your NEWT Window platform, + * you have to pass your <i>main thread</i> actions to {@link #invoke invoke(..)}, + * have a look at the {@link com.sun.javafx.newt.macosx.MacWindow MacWindow} implementation.<br> + * <i>TODO</i>: Some hardcoded dependencies exist in this implementation, + * where you have to patch this code or factor it out. <P> + * + * If your platform is not Mac OS X, but you want to test your code without modifying + * this class, you have to set the system property <code>newt.MainThread.force</code> to <code>true</code>.<P> + * + * The code is compatible with all other platform, which support multithreaded windowing handling. + * Since those platforms won't trigger the <i>main thread</i> serialization, the main method + * will be simply executed, in case you haven't set <code>newt.MainThread.force</code> to <code>true</code>.<P> + * + * Test case on Mac OS X (or any other platform): + <PRE> + java -XstartOnFirstThread com.sun.javafx.newt.util.MainThread demos.es1.RedSquare -GL2 -GL2 -GL2 -GL2 + </PRE> + * Which starts 4 threads, each with a window and OpenGL rendering.<br> + */ +public class MainThread { + public static final boolean USE_MAIN_THREAD = NativeWindowFactory.getNativeWindowType(false)==NativeWindowFactory.TYPE_MACOSX || + Boolean.getBoolean("newt.MainThread.force"); + + private static final boolean DEBUG = false; + private static boolean isExit=false; + private static volatile boolean isRunning=false; + private static Object taskWorkerLock=new Object(); + private static boolean shouldStop; + private static ArrayList tasks; + private static ArrayList tasksBlock; + + static class MainAction extends Thread { + private String mainClassName; + private String[] mainClassArgs; + + private Class mainClass; + private Method mainClassMain; + + public MainAction(String mainClassName, String[] mainClassArgs) { + this.mainClassName=mainClassName; + this.mainClassArgs=mainClassArgs; + } + + public void run() { + if ( USE_MAIN_THREAD ) { + // we have to start first to provide the service .. + MainThread.waitUntilRunning(); + } + + // start user app .. + try { + Class mainClass = NWReflection.getClass(mainClassName); + if(null==mainClass) { + throw new RuntimeException(new ClassNotFoundException("MainThread couldn't find main class "+mainClassName)); + } + try { + mainClassMain = mainClass.getDeclaredMethod("main", new Class[] { String[].class }); + mainClassMain.setAccessible(true); + } catch (Throwable t) { + throw new RuntimeException(t); + } + if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" invoke "+mainClassName); + mainClassMain.invoke(null, new Object[] { mainClassArgs } ); + } catch (InvocationTargetException ite) { + ite.getTargetException().printStackTrace(); + } catch (Throwable t) { + t.printStackTrace(); + } + + if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" user app fin"); + + if ( USE_MAIN_THREAD ) { + MainThread.exit(); + if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainThread fin - exit"); + System.exit(0); + } + } + } + private static MainAction mainAction; + + /** Your new java application main entry, which pipelines your application */ + public static void main(String[] args) { + if(DEBUG) System.err.println("MainThread.main(): "+Thread.currentThread().getName()+" USE_MAIN_THREAD "+ USE_MAIN_THREAD ); + + if(args.length==0) { + return; + } + + String mainClassName=args[0]; + String[] mainClassArgs=new String[args.length-1]; + if(args.length>1) { + System.arraycopy(args, 1, mainClassArgs, 0, args.length-1); + } + + NativeLibLoader.loadNEWT(); + + shouldStop = false; + tasks = new ArrayList(); + tasksBlock = new ArrayList(); + + mainAction = new MainAction(mainClassName, mainClassArgs); + + if(NativeWindowFactory.getNativeWindowType(false)==NativeWindowFactory.TYPE_MACOSX) { + MacWindow.initSingleton(); + } + + if ( USE_MAIN_THREAD ) { + // dispatch user's main thread .. + mainAction.start(); + + // do our main thread task scheduling + run(); + } else { + // run user's main in this thread + mainAction.run(); + } + } + + /** invokes the given Runnable */ + public static void invoke(boolean wait, Object owner, Runnable r) { + if(r == null) { + return; + } + + // if this main thread is not being used, + // let them run it on their own thread .. + if(!isRunning()) { + r.run(); + return; + } + + synchronized(taskWorkerLock) { + tasks.add(r); + if(wait) { + tasksBlock.add(r); + } + taskWorkerLock.notifyAll(); + if(wait) { + while(tasksBlock.size()>0) { + try { + taskWorkerLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + } + + public static void exit() { + if(DEBUG) System.err.println("MainThread.exit(): "+Thread.currentThread().getName()+" start"); + synchronized(taskWorkerLock) { + if(isRunning) { + shouldStop = true; + } + taskWorkerLock.notifyAll(); + } + if(DEBUG) System.err.println("MainThread.exit(): "+Thread.currentThread().getName()+" end"); + } + + public static boolean isRunning() { + synchronized(taskWorkerLock) { + return isRunning; + } + } + + private static void waitUntilRunning() { + synchronized(taskWorkerLock) { + if(isExit) return; + + while(!isRunning) { + try { + taskWorkerLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + public static void run() { + if(DEBUG) System.err.println("MainThread.run(): "+Thread.currentThread().getName()); + synchronized(taskWorkerLock) { + isRunning = true; + taskWorkerLock.notifyAll(); + } + while(!shouldStop) { + try { + ArrayList localTasks=null; + + // wait for something todo .. + synchronized(taskWorkerLock) { + while(!shouldStop && tasks.size()==0) { + try { + taskWorkerLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + // seq. process all tasks until no blocking one exists in the list + for(Iterator i = tasks.iterator(); tasksBlock.size()>0 && i.hasNext(); ) { + Runnable task = (Runnable) i.next(); + task.run(); + i.remove(); + tasksBlock.remove(task); + } + + // take over the tasks .. + if(tasks.size()>0) { + localTasks = tasks; + tasks = new ArrayList(); + } + taskWorkerLock.notifyAll(); + } + + // seq. process all unblocking tasks .. + if(null!=localTasks) { + for(Iterator i = localTasks.iterator(); i.hasNext(); ) { + Runnable task = (Runnable) i.next(); + task.run(); + } + } + } catch (Throwable t) { + // handle errors .. + t.printStackTrace(); + } finally { + // epilog - unlock locked stuff + } + } + if(DEBUG) System.err.println("MainThread.run(): "+Thread.currentThread().getName()+" fin"); + synchronized(taskWorkerLock) { + isRunning = false; + isExit = true; + taskWorkerLock.notifyAll(); + } + } +} + + diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index 20190ae58..4634b0289 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -89,6 +89,11 @@ void setFrameTopLeftPoint(NSWindow* win, jint x, jint y) JNIEXPORT jboolean JNICALL Java_com_sun_javafx_newt_macosx_MacWindow_initIDs (JNIEnv *env, jclass clazz) { + static int initialized = 0; + + if(initialized) return JNI_TRUE; + initialized = 1; + // This little bit of magic is needed in order to receive mouse // motion events and allow key focus to be properly transferred. // FIXME: are these Carbon APIs? They come from the @@ -231,16 +236,18 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_macosx_MacWindow_setTitle0 /* * Class: com_sun_javafx_newt_macosx_MacWindow - * Method: dispatchMessages - * Signature: (I)V + * Method: dispatchMessages0 + * Signature: (JI)V */ -JNIEXPORT void JNICALL Java_com_sun_javafx_newt_macosx_MacWindow_dispatchMessages - (JNIEnv *env, jobject unused, jint eventMask) +JNIEXPORT void JNICALL Java_com_sun_javafx_newt_macosx_MacWindow_dispatchMessages0 + (JNIEnv *env, jobject unused, jlong window, jint eventMask) { NSEvent* event = NULL; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [NewtMacWindow setJNIEnv: env]; + NewtMacWindow* nwwin = (NewtMacWindow*) ((intptr_t) window); + [nwwin setJNIEnv: env]; + do { // FIXME: ignoring event mask for the time being event = [NSApp nextEventMatchingMask: NSAnyEventMask @@ -248,10 +255,13 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_macosx_MacWindow_dispatchMessage inMode: NSDefaultRunLoopMode dequeue: YES]; if (event != NULL) { + NewtMacWindow* nwwin = (NewtMacWindow*) [event window]; + [nwwin setJNIEnv: env]; + [NSApp sendEvent: event]; } } while (event != NULL); - [NewtMacWindow setJNIEnv: NULL]; + // [nwwin setJNIEnv: NULL]; [pool release]; } diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h index 971661ebf..fc8a1e4f3 100644 --- a/src/newt/native/NewtMacWindow.h +++ b/src/newt/native/NewtMacWindow.h @@ -37,12 +37,15 @@ @interface NewtMacWindow : NSWindow { jobject javaWindowObject; + + // This is set while messages are being dispatched and cleared afterward + JNIEnv* env; } + (BOOL) initNatives: (JNIEnv*) env forClass: (jobject) clazz; /* Set and cleared during event dispatching cycle */ -+ (void) setJNIEnv: (JNIEnv*) env; +- (void) setJNIEnv: (JNIEnv*) env; - (id) initWithContentRect: (NSRect) contentRect styleMask: (NSUInteger) windowStyle diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index d225381d4..94837359d 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -44,9 +44,6 @@ static jmethodID focusChangedID = NULL; static jmethodID windowDestroyNotifyID = NULL; static jmethodID windowDestroyedID = NULL; -// This is set while messages are being dispatched and cleared afterward -static JNIEnv* env = NULL; - @implementation NewtMacWindow + (BOOL) initNatives: (JNIEnv*) env forClass: (jclass) clazz @@ -64,7 +61,7 @@ static JNIEnv* env = NULL; return NO; } -+ (void) setJNIEnv: (JNIEnv*) theEnv +- (void) setJNIEnv: (JNIEnv*) theEnv { env = theEnv; } |