aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2009-06-14 18:13:32 +0000
committerSven Gothel <[email protected]>2009-06-14 18:13:32 +0000
commita420720c605b6c7be231d277e858ce8d640ecb83 (patch)
treee3eaf7e3993c92c2cdee1951adc1532f6436d43f
parentca8a9b56532fe4710cc4f3742c385db06dec9252 (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.xml2
-rwxr-xr-xsrc/newt/classes/com/sun/javafx/newt/Window.java96
-rwxr-xr-xsrc/newt/classes/com/sun/javafx/newt/macosx/MacWindow.java159
-rw-r--r--src/newt/classes/com/sun/javafx/newt/util/MainThread.java302
-rw-r--r--src/newt/native/MacWindow.m22
-rw-r--r--src/newt/native/NewtMacWindow.h5
-rw-r--r--src/newt/native/NewtMacWindow.m5
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;
}