From e5ab975727134d8249277f4df707b2b14a7788f3 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sun, 25 Sep 2011 04:38:59 +0200 Subject: NEWT/JOGL: MacOSX Update Feature related: - Added always-on-top - Added translucency - Child Window Position - AWT parent: manual traverse up the tree and calc position on screen (Problem: the parent view rect is not at the proper position, but covers the whole frame) EDTUtil related: - Works now w/ AWT ot headless (again) - OSX native JNI callbacks gathering JNIEnv properly and attaches/detaches thread. - AWT case: using AWT-Event which properly dispatches our cocoa events - MainThread (headless) case: Fork off thread w/ main class and kick off NSApp run(). This leads to same behavior as w/ AWT case. - Using DefaultEDTUtil - Cleanup MainThread (implements EDTUtil) - Currently not used as EDTUtil (osx), just as launcher - Removed EDTUtil impl code, reuse DefaultEDTUtil - Cleanup AWTEDTUtil (implements EDTUtil) - Currently not used as EDTUtil (osx) --- .../classes/com/jogamp/newt/util/MainThread.java | 331 ++++----------------- src/newt/classes/jogamp/newt/DisplayImpl.java | 19 +- src/newt/classes/jogamp/newt/WindowImpl.java | 7 + .../classes/jogamp/newt/driver/awt/AWTEDTUtil.java | 61 +++- .../jogamp/newt/driver/macosx/MacDisplay.java | 36 ++- .../jogamp/newt/driver/macosx/MacWindow.java | 165 ++++++---- src/newt/native/MacWindow.m | 235 ++++++++------- src/newt/native/NewtCommon.c | 27 ++ src/newt/native/NewtCommon.h | 2 + src/newt/native/NewtMacWindow.h | 24 +- src/newt/native/NewtMacWindow.m | 189 ++++++++++-- src/newt/native/X11Window.c | 26 +- 12 files changed, 609 insertions(+), 513 deletions(-) (limited to 'src/newt') diff --git a/src/newt/classes/com/jogamp/newt/util/MainThread.java b/src/newt/classes/com/jogamp/newt/util/MainThread.java index 07c58d731..f74845afc 100644 --- a/src/newt/classes/com/jogamp/newt/util/MainThread.java +++ b/src/newt/classes/com/jogamp/newt/util/MainThread.java @@ -41,22 +41,19 @@ import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.security.AccessControlContext; import java.security.AccessController; -import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; -import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.NativeWindowFactory; +import com.jogamp.common.os.Platform; import com.jogamp.common.util.ReflectionUtil; -import com.jogamp.common.util.RunnableTask; import com.jogamp.newt.Display; + import jogamp.newt.Debug; +import jogamp.newt.DefaultEDTUtil; import jogamp.newt.NEWTJNILibLoader; -import jogamp.newt.driver.awt.AWTEDTUtil; /** * NEWT Utility class MainThread

@@ -92,26 +89,26 @@ import jogamp.newt.driver.awt.AWTEDTUtil; * Which starts 4 threads, each with a window and OpenGL rendering.
*/ public class MainThread implements EDTUtil { - private static final AccessControlContext localACC = AccessController.getContext(); + private static final String MACOSXDisplayClassName = "jogamp.newt.driver.macosx.MacDisplay"; /** if true, use the main thread EDT, otherwise AWT's EDT */ - public static final boolean HINT_USE_MAIN_THREAD = !NativeWindowFactory.isAWTAvailable() || - Debug.getBooleanProperty("newt.MainThread.force", true, localACC); + public static final boolean HINT_USE_MAIN_THREAD; + + static { + final AccessControlContext localACC = AccessController.getContext(); + Platform.initSingleton(); + NativeWindowFactory.initSingleton(true); + NEWTJNILibLoader.loadNEWT(); + HINT_USE_MAIN_THREAD = !NativeWindowFactory.isAWTAvailable() || + Debug.getBooleanProperty("newt.MainThread.force", true, localACC); + } + public static boolean useMainThread = false; protected static final boolean DEBUG = Debug.debug("MainThread"); private static final MainThread singletonMainThread = new MainThread(); // one singleton MainThread - private static boolean isExit=false; - private static volatile boolean isRunning=false; - private static final Object edtLock=new Object(); - private static boolean shouldStop; - private static ArrayList tasks; - private static Thread mainThread; - - private static Timer pumpMessagesTimer=null; - private static TimerTask pumpMessagesTimerTask=null; private static final Map pumpMessageDisplayMap = new HashMap(); static class MainAction extends Thread { @@ -127,11 +124,7 @@ public class MainThread implements EDTUtil { @Override public void run() { - if ( useMainThread ) { - // we have to start first to provide the service .. - singletonMainThread.waitUntilRunning(); - } - + if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" start"); // start user app .. try { Class mainClass = ReflectionUtil.getClass(mainClassName, true, getClass().getClassLoader()); @@ -166,15 +159,20 @@ public class MainThread implements EDTUtil { } private static MainAction mainAction; + private static EDTUtil internalEDT; + /** Your new java application main entry, which pipelines your application */ public static void main(String[] args) { useMainThread = HINT_USE_MAIN_THREAD; + final Platform.OSType osType = Platform.getOSType(); + final boolean isMacOSX = osType == Platform.OSType.MACOS; + if(DEBUG) { System.err.println("MainThread.main(): "+Thread.currentThread().getName()+ ", useMainThread "+ useMainThread + ", HINT_USE_MAIN_THREAD "+ HINT_USE_MAIN_THREAD + - ", isAWTAvailable " + NativeWindowFactory.isAWTAvailable()); + ", isAWTAvailable " + NativeWindowFactory.isAWTAvailable() + ", ostype "+osType+", isMacOSX "+isMacOSX); } if(!useMainThread && !NativeWindowFactory.isAWTAvailable()) { @@ -191,25 +189,34 @@ public class MainThread implements EDTUtil { System.arraycopy(args, 1, mainClassArgs, 0, args.length-1); } - NEWTJNILibLoader.loadNEWT(); - mainAction = new MainAction(mainClassName, mainClassArgs); - if(NativeWindowFactory.TYPE_MACOSX.equals(NativeWindowFactory.getNativeWindowType(false))) { - ReflectionUtil.callStaticMethod("jogamp.newt.macosx.MacDisplay", "initSingleton", + if(isMacOSX) { + ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "initSingleton", null, null, MainThread.class.getClassLoader()); } if ( useMainThread ) { - shouldStop = false; - tasks = new ArrayList(); - mainThread = Thread.currentThread(); + final Thread current = Thread.currentThread(); + internalEDT = new DefaultEDTUtil(current.getThreadGroup(), "MainThread", new Runnable() { + public void run() { dispatchMessages(); } }); + if(DEBUG) System.err.println("MainThread - run: "+internalEDT.toString()); + internalEDT.start(); // forever ! + // dispatch user's main thread .. mainAction.start(); - - // do our main thread task scheduling - singletonMainThread.run(); + + if(isMacOSX) { + try { + if(DEBUG) System.err.println("MainThread - runNSApp"); + ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "runNSApplication", + null, null, MainThread.class.getClassLoader()); + } catch (Exception e) { + e.printStackTrace(); + } + } + if(DEBUG) System.err.println("MainThread - wait until last non daemon thread ends ..."); } else { // run user's main in this thread mainAction.run(); @@ -227,273 +234,49 @@ public class MainThread implements EDTUtil { } public static void addPumpMessage(Display dpy, Runnable pumpMessage) { - if(DEBUG) { - System.err.println("MainThread.addPumpMessage(): "+Thread.currentThread().getName()+ - " - dpy "+dpy+", USE_MAIN_THREAD " + useMainThread + - " - hasAWT " + NativeWindowFactory.isAWTAvailable() ); - } - if(!useMainThread && !NativeWindowFactory.isAWTAvailable()) { - throw new RuntimeException("!USE_MAIN_THREAD and no AWT available"); - } - synchronized (pumpMessageDisplayMap) { - if(!useMainThread && null == pumpMessagesTimer) { - // AWT pump messages .. MAIN_THREAD uses main thread - pumpMessagesTimer = new Timer(); - pumpMessagesTimerTask = new TimerTask() { - public void run() { - synchronized(pumpMessageDisplayMap) { - for(Iterator i = pumpMessageDisplayMap.values().iterator(); i.hasNext(); ) { - i.next().run(); - } - } - } - }; - pumpMessagesTimer.scheduleAtFixedRate(pumpMessagesTimerTask, 0, defaultEDTPollGranularity); - } pumpMessageDisplayMap.put(dpy, pumpMessage); } } - final public void reset() { - if(NativeWindowFactory.isAWTAvailable()) { - AWTEDTUtil.getSingleton().reset(); + private static void dispatchMessages() { + synchronized(pumpMessageDisplayMap) { + for(Iterator i = pumpMessageDisplayMap.values().iterator(); i.hasNext(); ) { + i.next().run(); + } } - // nop + } + + final public void reset() { + // nop: ALWAYS RUNNING } final public void start() { - if(NativeWindowFactory.isAWTAvailable()) { - AWTEDTUtil.getSingleton().start(); - } - // nop + // nop: ALWAYS RUNNING } final public boolean isCurrentThreadEDT() { - if(NativeWindowFactory.isAWTAvailable()) { - return AWTEDTUtil.getSingleton().isCurrentThreadEDT(); - } - return isRunning() && mainThread == Thread.currentThread() ; + return internalEDT.isCurrentThreadEDT(); } final public boolean isRunning() { - if( useMainThread ) { - return isRunning; - } - return true; // AWT is always running + return true; // ALWAYS RUNNING } final public void invokeStop(Runnable r) { - invokeImpl(true, r, true); + internalEDT.invoke(true, r); // ALWAYS RUNNING } final public void invoke(boolean wait, Runnable r) { - invokeImpl(wait, r, false); - } - - private void invokeImpl(boolean wait, Runnable task, boolean stop) { - if(task == null) { - return; - } - - if(NativeWindowFactory.isAWTAvailable()) { - AWTEDTUtil.getSingleton().invokeImpl(wait, task, stop); - return; - } - - // if this main thread is not being used or - // if this is already the main thread .. just execute. - // FIXME: start if not started .. sync logic with DefaultEDTUtil!!! - if( !isRunning() || mainThread == Thread.currentThread() ) { - task.run(); - return; - } - - Throwable throwable = null; - RunnableTask rTask = null; - Object rTaskLock = new Object(); - synchronized(rTaskLock) { - synchronized(edtLock) { - if( shouldStop ) { - // drop task .. - if(DEBUG) { - System.err.println("Warning: EDT about (1) to stop, won't enqueue new task: "+this); - Thread.dumpStack(); - } - return; - } - // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+tasks.size()+", task: "+task); - // Thread.dumpStack(); - if(stop) { - shouldStop = true; - if(DEBUG) System.err.println("MainThread.stop(): "+Thread.currentThread().getName()+" start"); - } - if( isCurrentThreadEDT() ) { - task.run(); - wait = false; // running in same thread (EDT) -> no wait - if(stop && tasks.size()>0) { - System.err.println("Warning: EDT about (2) to stop, having remaining tasks: "+tasks.size()+" - "+this); - if(DEBUG) { - Thread.dumpStack(); - } - } - } else { - synchronized(tasks) { - start(); // start if not started yet and !shouldStop - wait = wait && isRunning(); - rTask = new RunnableTask(task, - wait ? rTaskLock : null, - true /* always catch and report Exceptions, don't disturb EDT */); - if(stop) { - rTask.setAttachment(new Boolean(true)); // mark final task - } - // append task .. - tasks.add(rTask); - tasks.notifyAll(); - } - } - } - if( wait ) { - try { - rTaskLock.wait(); // free lock, allow execution of rTask - } catch (InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rTask.getThrowable(); - } - if(null!=throwable) { - if(throwable instanceof NativeWindowException) { - throw (NativeWindowException)throwable; - } - throw new RuntimeException(throwable); - } - } - } - if(DEBUG && stop) { - System.err.println(Thread.currentThread()+": EDT signal STOP X edt: "+this); - } + internalEDT.invoke(wait, r); } final public void waitUntilIdle() { - if(NativeWindowFactory.isAWTAvailable()) { - AWTEDTUtil.getSingleton().waitUntilIdle(); - } + internalEDT.waitUntilIdle(); } final public void waitUntilStopped() { - if(NativeWindowFactory.isAWTAvailable()) { - AWTEDTUtil.getSingleton().waitUntilStopped(); - } - } - - private void waitUntilRunning() { - synchronized(edtLock) { - if(isExit) return; - - while(!isRunning) { - try { - edtLock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - - public void run() { - if(DEBUG) System.err.println("MainThread.run(): "+Thread.currentThread().getName()); - synchronized(edtLock) { - isRunning = true; - edtLock.notifyAll(); - } - - RuntimeException error = null; - try { - do { - // event dispatch - if(!shouldStop) { - synchronized(pumpMessageDisplayMap) { - for(Iterator i = pumpMessageDisplayMap.values().iterator(); i.hasNext(); ) { - i.next().run(); - } - } - } - // wait for something todo .. - Runnable task = null; - synchronized(tasks) { - // wait for tasks - if(!shouldStop && tasks.size()==0) { - try { - tasks.wait(defaultEDTPollGranularity); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - // execute one task, if available - if(tasks.size()>0) { - task = tasks.remove(0); - tasks.notifyAll(); - } - } - if(null!=task) { - // Exceptions are always catched, see Runnable creation above - task.run(); - } - } while(!shouldStop) ; - } catch (Throwable t) { - // handle errors .. - shouldStop = true; - if(t instanceof RuntimeException) { - error = (RuntimeException) t; - } else { - error = new RuntimeException("Within EDT", t); - } - } finally { - if(DEBUG) { - RunnableTask rt = ( tasks.size() > 0 ) ? tasks.get(0) : null ; - System.err.println(/* getName()+*/"EDT run() END, tasks: "+tasks.size()+", "+rt+", "+error); - } - synchronized(edtLock) { - if(null==error) { - synchronized(tasks) { - // drain remaining tasks (stop not on EDT), - // while having tasks and no previous-task, or previous-task is non final - RunnableTask task = null; - while ( ( null == task || task.getAttachment() == null ) && tasks.size() > 0 ) { - task = tasks.remove(0); - task.run(); - tasks.notifyAll(); - } - if(DEBUG) { - if(null!=task && task.getAttachment()==null) { - System.err.println("Warning: EDT exit: Last task Not Final: "+tasks.size()+", "+task); - } else if(tasks.size()>0) { - System.err.println("Warning: EDT exit: Remaining tasks Post Final: "+tasks.size()); - } - Thread.dumpStack(); - } - } - } - isRunning = !shouldStop; - if(!isRunning) { - edtLock.notifyAll(); - } - } - if(DEBUG) { - System.err.println("EDT run() EXIT "+ error); - } - if(null!=error) { - throw error; - } - } // finally - - if(DEBUG) System.err.println("MainThread.run(): "+Thread.currentThread().getName()+" fin"); - synchronized(edtLock) { - isRunning = false; - isExit = true; - edtLock.notifyAll(); - } + // nop: ALWAYS RUNNING } } diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java index 92add6a4e..ee370029e 100644 --- a/src/newt/classes/jogamp/newt/DisplayImpl.java +++ b/src/newt/classes/jogamp/newt/DisplayImpl.java @@ -39,6 +39,7 @@ import com.jogamp.newt.NewtFactory; import com.jogamp.newt.event.NEWTEvent; import com.jogamp.newt.event.NEWTEventConsumer; +import jogamp.newt.driver.awt.AWTEDTUtil; import jogamp.newt.event.NEWTEventTask; import com.jogamp.newt.util.EDTUtil; import com.jogamp.newt.util.MainThread; @@ -171,12 +172,24 @@ public abstract class DisplayImpl extends Display { protected void createEDTUtil() { if(NewtFactory.useEDT()) { if ( ! DEBUG_TEST_EDT_MAINTHREAD ) { - Thread current = Thread.currentThread(); + final Thread current = Thread.currentThread(); edtUtil = new DefaultEDTUtil(current.getThreadGroup(), "Display-"+getFQName(), dispatchMessagesRunnable); } else { // Begin JAU EDT Test .. - MainThread.addPumpMessage(this, dispatchMessagesRunnable); - edtUtil = MainThread.getSingleton(); + final Display f_dpy = this; + final Runnable dispatchRunner = new Runnable() { + public void run() { + if(null!=f_dpy.getGraphicsDevice()) { + f_dpy.dispatchMessages(); + } } }; + + if(NativeWindowFactory.isAWTAvailable()) { + AWTEDTUtil.addPumpMessage(this, dispatchRunner); + edtUtil = AWTEDTUtil.getSingleton(); + } else { + MainThread.addPumpMessage(this, dispatchRunner); + edtUtil = MainThread.getSingleton(); + } // End JAU EDT Test .. } if(DEBUG) { diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 9d54954b0..77e69fef7 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -478,6 +478,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer sb.append(0 != ( FLAG_IS_UNDECORATED & flags)); sb.append(", "); + if( 0 != ( FLAG_CHANGE_ALWAYSONTOP & flags) ) { + sb.append("*"); + } + sb.append("ALWAYSONTOP_"); + sb.append(0 != ( FLAG_IS_ALWAYSONTOP & flags)); + sb.append(", "); + if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) { sb.append("*"); } diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java index 0737e3281..cca1e321c 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java @@ -29,13 +29,25 @@ package jogamp.newt.driver.awt; import java.awt.EventQueue; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + import javax.media.nativewindow.NativeWindowException; + +import com.jogamp.newt.Display; import com.jogamp.newt.util.EDTUtil; import jogamp.newt.Debug; public class AWTEDTUtil implements EDTUtil { public static final boolean DEBUG = Debug.debug("EDT"); + private static Timer pumpMessagesTimer=null; + private static TimerTask pumpMessagesTimerTask=null; + private static final Map pumpMessageDisplayMap = new HashMap(); private static AWTEDTUtil singletonMainThread = new AWTEDTUtil(); // one singleton MainThread public static AWTEDTUtil getSingleton() { @@ -47,11 +59,11 @@ public class AWTEDTUtil implements EDTUtil { } final public void reset() { - // nop + // nop AWT is always running } final public void start() { - // nop + // nop AWT is always running } final public boolean isCurrentThreadEDT() { @@ -63,20 +75,10 @@ public class AWTEDTUtil implements EDTUtil { } final public void invokeStop(Runnable r) { - invokeImpl(true, r, true); + invoke(true, r); // AWT is always running } final public void invoke(boolean wait, Runnable r) { - invokeImpl(wait, r, false); - } - - /** - * Public access to provide simple dispatching from other EDTUtil implementations - * @param wait true if invokeLater - * @param r the Runnable action - * @param stop true if EDT shall stop (ignored with AWT) - */ - final public void invokeImpl(boolean wait, Runnable r, boolean stop) { if(r == null) { return; } @@ -98,9 +100,42 @@ public class AWTEDTUtil implements EDTUtil { } final public void waitUntilIdle() { + // wait until previous events are processed, at least .. + try { + EventQueue.invokeAndWait( new Runnable() { + public void run() { } + }); + } catch (Exception e) { } } final public void waitUntilStopped() { + // nop: AWT is always running + } + + public static void addPumpMessage(Display dpy, Runnable pumpMessage) { + if(DEBUG) { + System.err.println("AWTEDTUtil.addPumpMessage(): "+Thread.currentThread().getName()+" - dpy "+dpy); + } + + synchronized (pumpMessageDisplayMap) { + if(null == pumpMessagesTimer) { + // AWT pump messages .. MAIN_THREAD uses main thread + pumpMessagesTimer = new Timer(); + pumpMessagesTimerTask = new TimerTask() { + public void run() { + synchronized(pumpMessageDisplayMap) { + for(Iterator i = pumpMessageDisplayMap.values().iterator(); i.hasNext(); ) { + AWTEDTUtil.getSingleton().invoke(true, i.next()); + // AWTEDTUtil.getSingleton().invoke(false, i.next()); + // i.next().run(); + } + } + } + }; + pumpMessagesTimer.scheduleAtFixedRate(pumpMessagesTimerTask, 0, defaultEDTPollGranularity); + } + pumpMessageDisplayMap.put(dpy, pumpMessage); + } } } diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacDisplay.java b/src/newt/classes/jogamp/newt/driver/macosx/MacDisplay.java index db8577562..572d37efe 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/MacDisplay.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacDisplay.java @@ -37,6 +37,8 @@ import javax.media.nativewindow.*; import javax.media.nativewindow.macosx.*; import com.jogamp.newt.*; import jogamp.newt.*; +import jogamp.newt.driver.awt.AWTEDTUtil; + import com.jogamp.newt.util.MainThread; public class MacDisplay extends DisplayImpl { @@ -62,7 +64,7 @@ public class MacDisplay extends DisplayImpl { } protected void dispatchMessagesNative() { - dispatchMessages0(); + // nop } protected void createNativeImpl() { @@ -71,20 +73,26 @@ public class MacDisplay extends DisplayImpl { protected void closeNativeImpl() { } + /** @Override protected void createEDTUtil() { - if(NewtFactory.useEDT()) { + if(NewtFactory.useEDT()) { final Display f_dpy = this; - MainThread.addPumpMessage(this, - new Runnable() { - public void run() { - if(null!=f_dpy.getGraphicsDevice()) { - f_dpy.dispatchMessages(); - } } } ); - edtUtil = MainThread.getSingleton(); - edtUtil.start(); + final Runnable dispatchRunner = new Runnable() { + public void run() { + if(null!=f_dpy.getGraphicsDevice()) { + f_dpy.dispatchMessages(); + } } }; + + if(NativeWindowFactory.isAWTAvailable()) { + AWTEDTUtil.addPumpMessage(this, dispatchRunner); + edtUtil = AWTEDTUtil.getSingleton(); + } else { + MainThread.addPumpMessage(this, dispatchRunner); + edtUtil = MainThread.getSingleton(); + } } - } + } */ protected void releaseEDTUtil() { if(null!=edtUtil) { @@ -93,8 +101,12 @@ public class MacDisplay extends DisplayImpl { edtUtil=null; } } + + public static void runNSApplication() { + runNSApplication0(); + } private static native boolean initNSApplication0(); - protected native void dispatchMessages0(); + private static native void runNSApplication0(); } diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java index 1f471b9b5..3265da1c1 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java @@ -40,10 +40,11 @@ import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.newt.event.*; -import jogamp.nativewindow.jawt.JAWTUtil; +import jogamp.nativewindow.macosx.OSXUtil; import jogamp.newt.*; import javax.media.nativewindow.util.Insets; +import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; public class MacWindow extends WindowImpl { @@ -160,6 +161,7 @@ public class MacWindow extends WindowImpl { try { if(DEBUG_IMPLEMENTATION) { System.err.println("MacWindow.CloseAction "+Thread.currentThread().getName()); } if (getWindowHandle() != 0) { + orderOut0(getWindowHandle()); close0(getWindowHandle()); } } catch (Throwable t) { @@ -182,9 +184,6 @@ public class MacWindow extends WindowImpl { @Override protected int lockSurfaceImpl() { - if(NativeWindowFactory.isAWTAvailable()) { - JAWTUtil.lockToolkit(); - } nsViewLock.lock(); return LOCK_SUCCESS; } @@ -192,9 +191,6 @@ public class MacWindow extends WindowImpl { @Override protected void unlockSurfaceImpl() { nsViewLock.unlock(); - if(NativeWindowFactory.isAWTAvailable()) { - JAWTUtil.unlockToolkit(); - } } @Override @@ -212,7 +208,8 @@ public class MacWindow extends WindowImpl { // FIXME: move nsViewLock up to window lock nsViewLock.lock(); try { - makeKey0(getWindowHandle()); + makeKeyAndOrderFront0(getWindowHandle()); + // makeKey0(getWindowHandle()); } finally { nsViewLock.unlock(); } @@ -221,33 +218,64 @@ public class MacWindow extends WindowImpl { protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) { nsViewLock.lock(); try { + int _x = x, _y = y; + if(0 == ( FLAG_IS_UNDECORATED & flags) && 0<=_x && 0<=_y) { + final InsetsImmutable i = getInsets(); + + // client position -> top-level window position + _x -= i.getLeftWidth() ; + _y -= i.getTopHeight() ; + if( 0 > _x ) { _x = 0; } + if( 0 > _y ) { _y = 0; } + } + final NativeWindow parent = getParent(); + if(null != parent) { + final Point p = parent.getLocationOnScreen(null); + _x += p.getX(); + _y += p.getY(); + } + if(DEBUG_IMPLEMENTATION) { - System.err.println("MacWindow reconfig: "+x+"/"+y+" "+width+"x"+height+", "+ + System.err.println("MacWindow reconfig: "+x+"/"+y+" -> "+_x+"/"+_y+" - "+width+"x"+height+", "+ getReconfigureFlagsAsString(null, flags)); } - if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) { - if (0 != ( FLAG_IS_VISIBLE & flags)) { - createWindow(false, x, y, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); - } else { - if (getWindowHandle() != 0) { + if( getWindowHandle() == 0 ) { + if( 0 != ( FLAG_IS_VISIBLE & flags) ) { + createWindow(false, _x, _y, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); + this.x = x; + this.y = y; + visibleChanged(true); // no native event .. + } /* else { ?? } */ + } else { + if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) { + if( 0 != ( FLAG_IS_VISIBLE & flags) ) { + makeKeyAndOrderFront0(getWindowHandle()); + visibleChanged(true); // no native event .. + enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_GAINED_FOCUS); + } else { orderOut0(getWindowHandle()); + visibleChanged(false); // no native event .. + enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_LOST_FOCUS); } - } - visibleChanged(0 != ( FLAG_IS_VISIBLE & flags)); - } else { - if( 0 != ( FLAG_CHANGE_DECORATION & flags) || - 0 != ( FLAG_CHANGE_PARENTING & flags) || - 0 != ( FLAG_CHANGE_FULLSCREEN & flags) ) { + } else if( 0 != ( FLAG_CHANGE_DECORATION & flags) || + 0 != ( FLAG_CHANGE_PARENTING & flags) || + 0 != ( FLAG_CHANGE_FULLSCREEN & flags) ) { createWindow(true, x, y, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); - } else { - if(x>=0 || y>=0) { - setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), x, y); - } - if(width>0 || height>0) { - setContentSize0(getWindowHandle(), width, height); - } } + if(x>=0 || y>=0) { + setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), _x, _y); + this.x = x; + this.y = y; + enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_MOVED); + } + if(width>0 || height>0) { + setContentSize0(getWindowHandle(), width, height); + this.width = width; + this.height = height; + enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_RESIZED); + } + setAlwaysOnTop0(getWindowHandle(), 0 != ( FLAG_IS_ALWAYSONTOP & flags)); } } finally { nsViewLock.unlock(); @@ -256,7 +284,7 @@ public class MacWindow extends WindowImpl { } protected Point getLocationOnScreenImpl(int x, int y) { - return null; + return OSXUtil.GetLocationOnScreen(getWindowHandle(), x, y); } protected void updateInsetsImpl(Insets insets) { @@ -368,48 +396,60 @@ public class MacWindow extends WindowImpl { width=(width>0)?width:this.width; height=(height>0)?height:this.height; + final NativeWindow parent = getParent(); + if(null != parent) { + final Point p = parent.getLocationOnScreen(null); + x += p.getX(); + y += p.getY(); + } + try { - //runOnEDTIfAvail(true, new Runnable() { - // public void run() { - if(0!=getWindowHandle()) { - // save the view .. close the window - surfaceHandle = changeContentView0(getParentWindowHandle(), getWindowHandle(), 0); - if(recreate && 0==surfaceHandle) { - throw new NativeWindowException("Internal Error - recreate, window but no view"); - } - close0(getWindowHandle()); - setWindowHandle(0); - } else { - surfaceHandle = 0; - } - setWindowHandle(createWindow0(getParentWindowHandle(), - x, y, width, height, fullscreen, - (isUndecorated() ? - NSBorderlessWindowMask : - NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), - NSBackingStoreBuffered, - getScreen().getIndex(), surfaceHandle)); - if (getWindowHandle() == 0) { - throw new NativeWindowException("Could create native window "+Thread.currentThread().getName()+" "+this); - } - surfaceHandle = contentView0(getWindowHandle()); - setTitle0(getWindowHandle(), getTitle()); - makeKeyAndOrderFront0(getWindowHandle()); - // } } ); + if(0!=getWindowHandle()) { + // save the view .. close the window + surfaceHandle = changeContentView0(getParentWindowHandle(), getWindowHandle(), 0); + if(recreate && 0==surfaceHandle) { + throw new NativeWindowException("Internal Error - recreate, window but no view"); + } + orderOut0(getWindowHandle()); + close0(getWindowHandle()); + setWindowHandle(0); + } else { + surfaceHandle = 0; + } + setWindowHandle(createWindow0(getParentWindowHandle(), + x, y, width, height, + config.getChosenCapabilities().isBackgroundOpaque(), + fullscreen, + (isUndecorated() ? + NSBorderlessWindowMask : + NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), + NSBackingStoreBuffered, + getScreen().getIndex(), surfaceHandle)); + if (getWindowHandle() == 0) { + throw new NativeWindowException("Could create native window "+Thread.currentThread().getName()+" "+this); + } + surfaceHandle = contentView0(getWindowHandle()); + setTitle0(getWindowHandle(), getTitle()); + makeKeyAndOrderFront0(getWindowHandle()); } catch (Exception ie) { ie.printStackTrace(); } - - if(recreate) { - enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_MOVED); - enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_RESIZED); - enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_GAINED_FOCUS); + } + + @Override + protected void positionChanged(int newX, int newY) { + final NativeWindow parent = getParent(); + if(null != parent) { + final Point p = parent.getLocationOnScreen(null); + newX -= p.getX(); + newY -= p.getY(); } + super.positionChanged(newX, newY); } protected static native boolean initIDs0(); private native long createWindow0(long parentWindowHandle, int x, int y, int w, int h, - boolean fullscreen, int windowStyle, + boolean opaque, boolean fullscreen, int windowStyle, int backingStoreType, int screen_idx, long view); private native void makeKeyAndOrderFront0(long window); @@ -418,7 +458,8 @@ public class MacWindow extends WindowImpl { private native void close0(long window); private native void setTitle0(long window, String title); private native long contentView0(long window); - private native long changeContentView0(long parentWindowHandle, long window, long view); + private native long changeContentView0(long parentWindowOrViewHandle, long window, long view); private native void setContentSize0(long window, int w, int h); private native void setFrameTopLeftPoint0(long parentWindowHandle, long window, int x, int y); + private native void setAlwaysOnTop0(long window, boolean atop); } diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index 719acc927..946ac489c 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -43,7 +43,7 @@ #import -NSString* jstringToNSString(JNIEnv* env, jstring jstr) +static NSString* jstringToNSString(JNIEnv* env, jstring jstr) { const jchar* jstrChars = (*env)->GetStringChars(env, jstr, NULL); NSString* str = [[NSString alloc] initWithCharacters: jstrChars length: (*env)->GetStringLength(env, jstr)]; @@ -51,45 +51,23 @@ NSString* jstringToNSString(JNIEnv* env, jstring jstr) return str; } -void setFrameTopLeftPoint(NSWindow* pwin, NSWindow* win, jint x, jint y) -{ +static void setFrameTopLeftPoint(NSWindow* pWin, NSWindow* mWin, jint x, jint y) { NSScreen* screen = [NSScreen mainScreen]; + NSRect screenRect = [screen frame]; - // this allows for better compatibility with awt behavior - NSRect visibleRect; // either screen or parent-window - NSPoint pt; - int d_pty=0; // parent titlebar height - int d_ptx=0; - - if(NULL==pwin) { - visibleRect = [screen frame]; - } else { - visibleRect = [pwin frame]; - NSView* pview = [pwin contentView]; - NSRect viewRect = [pview frame]; - d_pty = visibleRect.size.height - viewRect.size.height; - (void) d_ptx; - //d_pty = visibleRect.origin.y - viewRect.size.height; - //d_ptx = visibleRect.size.height - viewRect.size.height; - fprintf(stderr, "pwin %lf/%lf %lfx%lf, pview %lf/%lf %lfx%lf -> %d/%d\n", - visibleRect.origin.x, - visibleRect.origin.y, - visibleRect.size.width, - visibleRect.size.height, - viewRect.origin.x, - viewRect.origin.y, - viewRect.size.width, - viewRect.size.height, - (int)x, (int)y); - - } + DBG_PRINT( "setFrameTopLeftPoint screen %lf/%lf %lfx%lf\n", + screenRect.origin.x, + screenRect.origin.y, + screenRect.size.width, + screenRect.size.height); - pt = NSMakePoint(visibleRect.origin.x + x, visibleRect.origin.y + visibleRect.size.height - y - d_pty); + NSPoint pt = NSMakePoint(screenRect.origin.x + x, screenRect.origin.y + screenRect.size.height - y); - [win setFrameTopLeftPoint: pt]; + DBG_PRINT( "setFrameTopLeftPoint -> %lf/%lf\n", pt.x, pt.y); + [mWin setFrameTopLeftPoint: pt]; } -static NewtView * changeContentView(JNIEnv *env, jobject javaWindowObject, NSWindow *pwin, NSWindow *win, NewtView *newView) { +static NewtView * changeContentView(JNIEnv *env, jobject javaWindowObject, NSWindow *pwin, NSView *pview, NSWindow *win, NewtView *newView) { NSView* oldNSView = [win contentView]; NewtView* oldView = NULL; @@ -107,6 +85,7 @@ NS_ENDHANDLER jobject globJavaWindowObject = [oldView getJavaWindowObject]; (*env)->DeleteGlobalRef(env, globJavaWindowObject); [oldView setJavaWindowObject: NULL]; + [oldView setDestroyNotifySent: false]; } /** FIXME: Tried child window: auto clip or message reception .. if(NULL!=pwin) { @@ -116,12 +95,23 @@ NS_ENDHANDLER if(NULL!=newView) { jobject globJavaWindowObject = (*env)->NewGlobalRef(env, javaWindowObject); [newView setJavaWindowObject: globJavaWindowObject]; - [newView setJNIEnv: env]; + [newView setDestroyNotifySent: false]; + { + JavaVM *jvmHandle = NULL; + int jvmVersion = 0; + + if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { + jvmHandle = NULL; + } else { + jvmVersion = (*env)->GetVersion(env); + } + [newView setJVMHandle: jvmHandle]; + [newView setJVMVersion: jvmVersion]; + } /** FIXME: Tried child window: auto clip or message reception .. if(NULL!=pwin) { - NSView* pview = [pwin contentView]; - [pview addSubview: newView]; + [pview addSubview: newView positioned: NSWindowAbove relativeTo: nil]; } */ } [win setContentView: newView]; @@ -169,40 +159,19 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_MacDisplay_initNSAppli /* * Class: jogamp_newt_driver_macosx_MacDisplay - * Method: dispatchMessages0 + * Method: runNSApplication0 * Signature: ()V */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacDisplay_dispatchMessages0 - (JNIEnv *env, jobject unused) +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacDisplay_runNSApplication0 + (JNIEnv *env, jclass clazz) { - NSEvent* event = NULL; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - -NS_DURING - - int num_events = 0; - - // Periodically take a break - do { - // FIXME: ignoring event mask for the time being - event = [NSApp nextEventMatchingMask: NSAnyEventMask - untilDate: [NSDate distantPast] - inMode: NSDefaultRunLoopMode - dequeue: YES]; - if (event != NULL) { - [NSApp sendEvent: event]; - - num_events++; - } - } while (num_events<100 && event != NULL); - -NS_HANDLER - - // just ignore it .. + // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT( "\nrunNSApplication0.0\n"); -NS_ENDHANDLER + [NSApp run]; - [pool release]; + DBG_PRINT( "\nrunNSApplication0.X\n"); + // [pool release]; } /* @@ -274,84 +243,107 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_MacWindow_initIDs0 * Signature: (JIIIIZIIIJ)J */ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_MacWindow_createWindow0 - (JNIEnv *env, jobject jthis, jlong parent, jint x, jint y, jint w, jint h, jboolean fullscreen, jint styleMask, + (JNIEnv *env, jobject jthis, jlong parent, jint x, jint y, jint w, jint h, jboolean opaque, jboolean fullscreen, jint styleMask, jint bufferingType, jint screen_idx, jlong jview) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSRect rect = NSMakeRect(x, y, w, h); + NewtView* myView = (NewtView*) (intptr_t) jview ; + + DBG_PRINT( "createWindow0 - %p (this), %p (parent), %d/%d %dx%d, opaque %d, fs %d, style %X, buffType %X, screenidx %d, view %p\n", + (void*)(intptr_t)jthis, (void*)(intptr_t)parent, (int)x, (int)y, (int)w, (int)h, (int) opaque, (int)fullscreen, + (int)styleMask, (int)bufferingType, (int)screen_idx, myView); NSArray *screens = [NSScreen screens]; if(screen_idx<0) screen_idx=0; if(screen_idx>=[screens count]) screen_idx=0; - NSScreen *screen = (NSScreen *) [screens objectAtIndex: screen_idx]; + NSScreen *myScreen = (NSScreen *) [screens objectAtIndex: screen_idx]; + NSRect rect; if (fullscreen) { styleMask = NSBorderlessWindowMask; - NSRect rect = [screen frame]; + rect = [myScreen frame]; + x = 0; + y = 0; w = (jint) (rect.size.width); h = (jint) (rect.size.height); + } else { + rect = NSMakeRect(x, y, w, h); } // Allocate the window - NSWindow* window = [[[NewtMacWindow alloc] initWithContentRect: rect + NSWindow* myWindow = [[[NewtMacWindow alloc] initWithContentRect: rect styleMask: (NSUInteger) styleMask backing: (NSBackingStoreType) bufferingType - screen: screen] retain]; + screen: myScreen] retain]; NSObject *nsParentObj = (NSObject*) ((intptr_t) parent); NSWindow* parentWindow = NULL; + NSView* parentView = NULL; if( nsParentObj != NULL && [nsParentObj isKindOfClass:[NSWindow class]] ) { parentWindow = (NSWindow*) nsParentObj; + parentView = [parentWindow contentView]; + DBG_PRINT( "createWindow0 - Parent is NSWindow : %p (view) -> %p (win) \n", parentView, parentWindow); } else if( nsParentObj != NULL && [nsParentObj isKindOfClass:[NSView class]] ) { - NSView* view = (NSView*) nsParentObj; - parentWindow = [view window]; - fprintf(stderr, "createWindow0 - Parent is NSView : %p -> %p (win) \n", nsParentObj, parentWindow); + parentView = (NSView*) nsParentObj; + parentWindow = [parentView window]; + DBG_PRINT( "createWindow0 - Parent is NSView : %p -(view) > %p (win) \n", parentView, parentWindow); } else { - fprintf(stderr, "createWindow0 - Parent is neither NSWindow nor NSView : %p\n", nsParentObj); + DBG_PRINT( "createWindow0 - Parent is neither NSWindow nor NSView : %p\n", nsParentObj); } if(NULL!=parentWindow) { - [parentWindow addChildWindow: window ordered: NSWindowAbove]; - [window setParentWindow: parentWindow]; + [parentWindow addChildWindow: myWindow ordered: NSWindowAbove]; + [myWindow setParentWindow: parentWindow]; + } + + if(opaque) { + [myWindow setOpaque: YES]; + } else { + [myWindow setOpaque: NO]; + [myWindow setBackgroundColor: [NSColor clearColor]]; } + /** if (fullscreen) { - [window setOpaque: YES]; + [myWindow setOpaque: YES]; } else { // If the window is undecorated, assume we want the possibility of // a shaped window, so make it non-opaque and the background color clear if ((styleMask & NSTitledWindowMask) == 0) { - [window setOpaque: NO]; - [window setBackgroundColor: [NSColor clearColor]]; + [myWindow setOpaque: NO]; + [myWindow setBackgroundColor: [NSColor clearColor]]; } - } - - // Immediately re-position the window based on an upper-left coordinate system - setFrameTopLeftPoint(parentWindow, window, x, y); + } */ // specify we want mouse-moved events - [window setAcceptsMouseMovedEvents:YES]; + [myWindow setAcceptsMouseMovedEvents:YES]; // Use given NewtView or allocate an NewtView if NULL - NewtView* view = (0==jview)? [[NewtView alloc] initWithFrame: rect] : (NewtView*) ((intptr_t) jview) ; + if(NULL == myView) { + myView = [[NewtView alloc] initWithFrame: rect] ; + DBG_PRINT( "createWindow0 - new own view: %p\n", myView); + } // Set the content view - (void) changeContentView(env, jthis, parentWindow, window, view); + (void) changeContentView(env, jthis, parentWindow, parentView, myWindow, myView); + + // Immediately re-position the window based on an upper-left coordinate system + setFrameTopLeftPoint(parentWindow, myWindow, x, y); NS_DURING // Available >= 10.5 - Makes the menubar disapear if(fullscreen) { - [view enterFullScreenMode: screen withOptions:NULL]; + [myView enterFullScreenMode: myScreen withOptions:NULL]; } NS_HANDLER NS_ENDHANDLER // Set the next responder to be the window so that we can forward // right mouse button down events - [view setNextResponder: window]; + [myView setNextResponder: myWindow]; [pool release]; - return (jlong) ((intptr_t) window); + return (jlong) ((intptr_t) myWindow); } /* @@ -364,7 +356,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_makeKeyAndOrderF { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* win = (NSWindow*) ((intptr_t) window); - [win makeKeyAndOrderFront: win]; + [win performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:win waitUntilDone:NO]; + // [win makeKeyAndOrderFront: win]; [pool release]; } @@ -378,7 +371,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_makeKey0 { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* win = (NSWindow*) ((intptr_t) window); - [win makeKeyWindow]; + [win performSelectorOnMainThread:@selector(makeKeyWindow:) withObject:nil waitUntilDone:NO]; + // [win makeKeyWindow]; [pool release]; } @@ -392,7 +386,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_orderOut0 { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* win = (NSWindow*) ((intptr_t) window); - [win orderOut: win]; + [win performSelectorOnMainThread:@selector(orderOut:) withObject:win waitUntilDone:NO]; + // [win orderOut: win]; [pool release]; } @@ -407,7 +402,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_close0 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* win = (NSWindow*) ((intptr_t) window); NSView* view = [win contentView]; - [win orderOut: win]; + DBG_PRINT( "*************** windowClose.0: 0x%p\n", (void *)win); NS_DURING if(NULL!=view) { // Available >= 10.5 - Makes the menubar disapear @@ -417,7 +412,12 @@ NS_DURING } NS_HANDLER NS_ENDHANDLER - [win close]; + DBG_PRINT( "*************** windowClose.2: 0x%p\n", (void *)win); + + [win performSelectorOnMainThread:@selector(close:) withObject:nil waitUntilDone:NO]; + // [win close] + + DBG_PRINT( "*************** windowClose.X: 0x%p\n", (void *)win); [pool release]; } @@ -433,7 +433,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_setTitle0 NSWindow* win = (NSWindow*) ((intptr_t) window); NSString* str = jstringToNSString(env, title); [str autorelease]; - [win setTitle: str]; + [win performSelectorOnMainThread:@selector(setTitle:) withObject:str waitUntilDone:NO]; + // [win setTitle: str]; [pool release]; } @@ -458,14 +459,27 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_MacWindow_contentView0 * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_MacWindow_changeContentView0 - (JNIEnv *env, jobject jthis, jlong parent, jlong window, jlong jview) + (JNIEnv *env, jobject jthis, jlong parentWindowOrView, jlong window, jlong jview) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSWindow* pwin = (NewtMacWindow*) ((intptr_t) parent); + + NSObject *nsParentObj = (NSObject*) ((intptr_t) parentWindowOrView); + NSWindow* pWin = NULL; + NSView* pView = NULL; + if( NULL != nsParentObj ) { + if( [nsParentObj isKindOfClass:[NSWindow class]] ) { + pWin = (NSWindow*) nsParentObj; + pView = [pWin contentView]; + } else if( [nsParentObj isKindOfClass:[NSView class]] ) { + pView = (NSView*) nsParentObj; + pWin = [pView window]; + } + } + NSWindow* win = (NewtMacWindow*) ((intptr_t) window); NewtView* newView = (NewtView *) ((intptr_t) jview); - NewtView* oldView = changeContentView(env, jthis, pwin, win, newView); + NewtView* oldView = changeContentView(env, jthis, pWin, pView, win, newView); [pool release]; @@ -490,7 +504,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_setContentSize0 /* * Class: jogamp_newt_driver_macosx_MacWindow * Method: setFrameTopLeftPoint - * Signature: (JII)V + * Signature: (JJII)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_setFrameTopLeftPoint0 (JNIEnv *env, jobject unused, jlong parent, jlong window, jint x, jint y) @@ -502,3 +516,22 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_setFrameTopLeftP [pool release]; } +/* + * Class: jogamp_newt_driver_macosx_MacWindow + * Method: setAlwaysOnTop0 + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_setAlwaysOnTop0 + (JNIEnv *env, jobject unused, jlong window, jboolean atop) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSWindow* win = (NSWindow*) ((intptr_t) window); + if(atop) { + [win setLevel:NSFloatingWindowLevel]; + } else { + [win setLevel:NSNormalWindowLevel]; + } + [pool release]; +} + + diff --git a/src/newt/native/NewtCommon.c b/src/newt/native/NewtCommon.c index f44d71901..3713cfd6c 100644 --- a/src/newt/native/NewtCommon.c +++ b/src/newt/native/NewtCommon.c @@ -53,3 +53,30 @@ jchar* NewtCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) return strChars; } +JNIEnv* NewtCommon_GetJNIEnv(JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached) { + JNIEnv* curEnv = NULL; + JNIEnv* newEnv = NULL; + int envRes; + + // retrieve this thread's JNIEnv curEnv - or detect it's detached + envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ; + if( JNI_EDETACHED == envRes ) { + // detached thread - attach to JVM + if( JNI_OK != ( envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL) ) ) { + fprintf(stderr, "JNIEnv: can't attach thread: %d\n", envRes); + return NULL; + } + curEnv = newEnv; + } else if( JNI_OK != envRes ) { + // oops .. + fprintf(stderr, "can't GetEnv: %d\n", envRes); + return NULL; + } + if (curEnv==NULL) { + fprintf(stderr, "env is NULL\n"); + return NULL; + } + *shallBeDetached = NULL != newEnv; + return curEnv; +} + diff --git a/src/newt/native/NewtCommon.h b/src/newt/native/NewtCommon.h index f5835f7c8..91fceb310 100644 --- a/src/newt/native/NewtCommon.h +++ b/src/newt/native/NewtCommon.h @@ -12,4 +12,6 @@ jchar* NewtCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str); void NewtCommon_FatalError(JNIEnv *env, const char* msg, ...); void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); +JNIEnv* NewtCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached); + #endif diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h index 7f0cd60c6..a8931d6fc 100644 --- a/src/newt/native/NewtMacWindow.h +++ b/src/newt/native/NewtMacWindow.h @@ -34,23 +34,41 @@ #import #import "jni.h" +#include "NewtCommon.h" + +// #define VERBOSE_ON 1 + +#ifdef VERBOSE_ON + #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif + @interface NewtView : NSView { jobject javaWindowObject; // This is set while messages are being dispatched and cleared afterward - JNIEnv* env; + JavaVM *jvmHandle; + int jvmVersion; + + BOOL destroyNotifySent; } /* Set during event dispatching cycle */ -- (void) setJNIEnv: (JNIEnv*) env; -- (JNIEnv*) getJNIEnv; +- (void) setJVMHandle: (JavaVM*) vm; +- (JavaVM*) getJVMHandle; +- (void) setJVMVersion: (int) ver; +- (int) getJVMVersion; /* Register or deregister (NULL) the java Window object, ie, if NULL, no events are send */ - (void) setJavaWindowObject: (jobject) javaWindowObj; - (jobject) getJavaWindowObject; +- (void) setDestroyNotifySent: (BOOL) v; +- (BOOL) getDestroyNotifySent; + - (void) rightMouseDown: (NSEvent*) theEvent; @end diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index cd435eb1d..6125761e3 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -82,13 +82,24 @@ static jmethodID focusChangedID = NULL; static jmethodID windowDestroyNotifyID = NULL; @implementation NewtView -- (void) setJNIEnv: (JNIEnv*) theEnv + +- (void) setJVMHandle: (JavaVM*) vm { - env = theEnv; + jvmHandle = vm; } -- (JNIEnv*) getJNIEnv +- (JavaVM*) getJVMHandle { - return env; + return jvmHandle; +} + +- (void) setJVMVersion: (int) ver +{ + jvmVersion = ver; +} + +- (int) getJVMVersion +{ + return jvmVersion; } - (void) setJavaWindowObject: (jobject) javaWindowObj @@ -101,6 +112,16 @@ static jmethodID windowDestroyNotifyID = NULL; return javaWindowObject; } +- (void) setDestroyNotifySent: (BOOL) v +{ + destroyNotifySent = v; +} + +- (BOOL) getDestroyNotifySent +{ + return destroyNotifySent; +} + - (void) rightMouseDown: (NSEvent*) theEvent { NSResponder* next = [self nextResponder]; @@ -111,19 +132,43 @@ static jmethodID windowDestroyNotifyID = NULL; - (void)viewWillDraw { - fprintf(stderr, "*************** viewWillDraw: 0x%p", javaWindowObject); fflush(stderr); + DBG_PRINT("*************** viewWillDraw: 0x%p\n", javaWindowObject); [super viewWillDraw]; } - (void)viewDidHide { + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + if(NULL==env) { + NSLog(@"viewDidHide: null JNIEnv"); + return; + } + (*env)->CallVoidMethod(env, javaWindowObject, visibleChangedID, JNI_FALSE); + + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } + [super viewDidHide]; } - (void)viewDidUnhide { + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + if(NULL==env) { + NSLog(@"viewDidHide: null JNIEnv"); + return; + } + (*env)->CallVoidMethod(env, javaWindowObject, visibleChangedID, JNI_TRUE); + + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } + [super viewDidUnhide]; } @@ -172,6 +217,8 @@ static jmethodID windowDestroyNotifyID = NULL; jint bottom = (jint)(contentRect.origin.y - frameRect.origin.y); jint right = (jint)(frameRect.size.width - (contentRect.size.width + l)); + DBG_PRINT( "updateInsets: [ l %d, r %d, t %d, b %d ]\n", (int)left, (int)right, (int)top, (int)bottom); + (*env)->CallVoidMethod(env, javaWindowObject, insetsChangedID, left, right, top, bottom); } @@ -225,8 +272,15 @@ static jint mods2JavaMods(NSUInteger mods) } NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; - JNIEnv* env = [view getJNIEnv]; - if (env==NULL || javaWindowObject == NULL) { + if (javaWindowObject == NULL) { + NSLog(@"sendKeyEvent: null javaWindowObject"); + return; + } + int shallBeDetached = 0; + JavaVM *jvmHandle = [view getJVMHandle]; + JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); + if(NULL==env) { + NSLog(@"sendKeyEvent: null JNIEnv"); return; } @@ -243,6 +297,10 @@ static jint mods2JavaMods(NSUInteger mods) (*env)->CallVoidMethod(env, javaWindowObject, sendKeyEventID, evType, javaMods, keyCode, keyChar); } + + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } } - (void) keyDown: (NSEvent*) theEvent @@ -264,8 +322,15 @@ static jint mods2JavaMods(NSUInteger mods) } NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; - JNIEnv* env = [view getJNIEnv]; - if (env==NULL || javaWindowObject == NULL) { + if (javaWindowObject == NULL) { + NSLog(@"sendMouseEvent: null javaWindowObject"); + return; + } + int shallBeDetached = 0; + JavaVM *jvmHandle = [view getJVMHandle]; + JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); + if(NULL==env) { + NSLog(@"sendMouseEvent: null JNIEnv"); return; } @@ -318,6 +383,10 @@ static jint mods2JavaMods(NSUInteger mods) (jint) location.x, (jint) (contentRect.size.height - location.y), javaButtonNum, scrollDeltaY); + + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } } - (void) mouseEntered: (NSEvent*) theEvent @@ -396,8 +465,15 @@ static jint mods2JavaMods(NSUInteger mods) } NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; - JNIEnv* env = [view getJNIEnv]; - if (env==NULL || javaWindowObject == NULL) { + if (javaWindowObject == NULL) { + NSLog(@"windowDidResize: null javaWindowObject"); + return; + } + int shallBeDetached = 0; + JavaVM *jvmHandle = [view getJVMHandle]; + JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); + if(NULL==env) { + NSLog(@"windowDidResize: null JNIEnv"); return; } @@ -410,6 +486,10 @@ static jint mods2JavaMods(NSUInteger mods) (*env)->CallVoidMethod(env, javaWindowObject, sizeChangedID, (jint) contentRect.size.width, (jint) contentRect.size.height, JNI_FALSE); + + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } } - (void)windowDidMove: (NSNotification*) notification @@ -420,8 +500,15 @@ static jint mods2JavaMods(NSUInteger mods) } NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; - JNIEnv* env = [view getJNIEnv]; - if (env==NULL || javaWindowObject == NULL) { + if (javaWindowObject == NULL) { + NSLog(@"windowDidMove: null javaWindowObject"); + return; + } + int shallBeDetached = 0; + JavaVM *jvmHandle = [view getJVMHandle]; + JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); + if(NULL==env) { + NSLog(@"windowDidMove: null JNIEnv"); return; } @@ -437,27 +524,53 @@ static jint mods2JavaMods(NSUInteger mods) (*env)->CallVoidMethod(env, javaWindowObject, positionChangedID, (jint) pt.x, (jint) pt.y); + + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } } - (void)windowWillClose: (NSNotification*) notification { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSView* nsview = [self contentView]; if( ! [nsview isMemberOfClass:[NewtView class]] ) { return; } NewtView* view = (NewtView *) nsview; - jobject javaWindowObject = [view getJavaWindowObject]; - JNIEnv* env = [view getJNIEnv]; - if (env==NULL || javaWindowObject == NULL) { - return; - } - (*env)->CallVoidMethod(env, javaWindowObject, windowDestroyNotifyID); - // Can't issue call here - locked window state, done from Java method + if( false == [view getDestroyNotifySent] ) { + jobject javaWindowObject = [view getJavaWindowObject]; + DBG_PRINT( "*************** windowWillClose.0: 0x%p\n", (void *)(intptr_t)javaWindowObject); + if (javaWindowObject == NULL) { + NSLog(@"windowWillClose: null javaWindowObject"); + return; + } + int shallBeDetached = 0; + JavaVM *jvmHandle = [view getJVMHandle]; + JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); + if(NULL==env) { + NSLog(@"windowWillClose: null JNIEnv"); + return; + } + + [view setDestroyNotifySent: true]; + (*env)->CallVoidMethod(env, javaWindowObject, windowDestroyNotifyID); + // Can't issue call here - locked window state, done from Java method - // EOL .. - (*env)->DeleteGlobalRef(env, javaWindowObject); - [view setJavaWindowObject: NULL]; + // EOL .. + (*env)->DeleteGlobalRef(env, javaWindowObject); + [view setJavaWindowObject: NULL]; + + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } + DBG_PRINT( "*************** windowWillClose.X: 0x%p\n", (void *)(intptr_t)javaWindowObject); + } else { + DBG_PRINT( "*************** windowWillClose (skip)\n"); + } + [pool release]; } - (void) windowDidBecomeKey: (NSNotification *) notification @@ -468,12 +581,23 @@ static jint mods2JavaMods(NSUInteger mods) } NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; - JNIEnv* env = [view getJNIEnv]; - if (env==NULL || javaWindowObject == NULL) { + if (javaWindowObject == NULL) { + NSLog(@"windowDidBecomeKey: null javaWindowObject"); + return; + } + int shallBeDetached = 0; + JavaVM *jvmHandle = [view getJVMHandle]; + JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); + if(NULL==env) { + NSLog(@"windowDidBecomeKey: null JNIEnv"); return; } (*env)->CallVoidMethod(env, javaWindowObject, focusChangedID, JNI_TRUE); + + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } } - (void) windowDidResignKey: (NSNotification *) notification @@ -484,12 +608,23 @@ static jint mods2JavaMods(NSUInteger mods) } NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; - JNIEnv* env = [view getJNIEnv]; - if (env==NULL || javaWindowObject == NULL) { + if (javaWindowObject == NULL) { + NSLog(@"windowDidResignKey: null javaWindowObject"); + return; + } + int shallBeDetached = 0; + JavaVM *jvmHandle = [view getJVMHandle]; + JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); + if(NULL==env) { + NSLog(@"windowDidResignKey: null JNIEnv"); return; } (*env)->CallVoidMethod(env, javaWindowObject, focusChangedID, JNI_FALSE); + + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } } @end diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 30ff7f6f3..e1a0071b5 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -208,32 +208,22 @@ static int displayDispatchErrorHandler(Display *dpy, XErrorEvent *e) } else if (e->error_code == BadWindow) { fprintf(stderr, " BadWindow (%p): Window probably already removed\n", (void*)e->resourceid); } else { - JNIEnv *curEnv = NULL; - JNIEnv *newEnv = NULL; - int envRes ; + int shallBeDetached = 0; + JNIEnv *jniEnv = NULL; const char * errStr = strerror(errno); fprintf(stderr, "Info: NEWT X11 Error: Display %p, Code 0x%X, errno %s\n", dpy, e->error_code, errStr); - // retrieve this thread's JNIEnv curEnv - or detect it's detached - envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ; - if( JNI_EDETACHED == envRes ) { - // detached thread - attach to JVM - if( JNI_OK != ( envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL) ) ) { - fprintf(stderr, "NEWT X11 Error: can't attach thread: %d\n", envRes); - return; - } - curEnv = newEnv; - } else if( JNI_OK != envRes ) { - // oops .. - fprintf(stderr, "NEWT X11 Error: can't GetEnv: %d\n", envRes); + jniEnv = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + if(NULL==jniEnv) { + fprintf(stderr, "NEWT X11 Error: null JNIEnv"); return; } - NewtCommon_throwNewRuntimeException(curEnv, "Info: NEWT X11 Error: Display %p, Code 0x%X, errno %s", + + NewtCommon_throwNewRuntimeException(jniEnv, "Info: NEWT X11 Error: Display %p, Code 0x%X, errno %s", dpy, e->error_code, errStr); - if( NULL != newEnv ) { - // detached attached thread + if (shallBeDetached) { (*jvmHandle)->DetachCurrentThread(jvmHandle); } } -- cgit v1.2.3