diff options
author | Sven Gothel <[email protected]> | 2014-01-04 17:15:04 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-01-04 17:15:04 +0100 |
commit | fcc0e7397bb6f3ceb1fe143667f8c59b5bf63874 (patch) | |
tree | fbb8225c6408cfe6bf17cccdfeafbc293d126e39 /src/newt | |
parent | e3cf96249f4c722f8b2a7d0e052e19165cef171e (diff) |
Bug 935: NEWT PointerIcon: Refine Spec and Implementation / Fix OSX Crash and Issues
- Refine Display.PointerIcon: Complete type allowing re-creation
- Add associated Display reference
- Add used IOUtil.ClassResources reference
- Add isValid()/validate() methods for recreation
- Refine API doc
- Move Display.destroyPointerIcon(PointerIcon) -> PointerIcon.destroy()
- Move DisplayImpl.PointerIconImpl -> PointerIconImpl (own source file)
- Creation/Destruction and setting of PointerIcon happens on EDT
- DisplayImpl.shutdownAll() and Display.destroy() calls destroyAllPointerIconFromList
- WindowDriver.setPointerIconImpl: Validates PointerIconImpl (i.e. re-creates if required)
- Fix 'initial' window.setPointerIcon(..) before createNative(..),
tested w/ TestGearsES2NEWT
- OSX Native Code:
- Move mouse and pointer-state handling from NewtMacWindow -> NewtView class
to retain states (pointer handle, pointer visibility, etc) when reparenting.
Reparenting will move an exisiting NewtView into a new NewtMacWindow.
- Enable all mouse move events:
- NewtView::mouseEnter [nsWin makeFirstResponder: nsView];
- NewtView::mouseExited if( !mouseConfined ) { [nsView resignFirstResponder]; }
- NewtView::mouseMoved issued [myCurser set] if required, fixing
OSX issue not updating NSCursor properly.
- MacWindow:
- Test NewtMacWindow, NewtView and NSCursor handles before usage
- Fix DBG_PRINT(..) warnings
Diffstat (limited to 'src/newt')
-rw-r--r-- | src/newt/classes/com/jogamp/newt/Display.java | 67 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/DisplayImpl.java | 91 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/PointerIconImpl.java | 126 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/WindowImpl.java | 9 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java | 11 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java | 34 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java | 11 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java | 4 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java | 22 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java | 14 | ||||
-rw-r--r-- | src/newt/native/MacWindow.m | 113 | ||||
-rw-r--r-- | src/newt/native/NewtMacWindow.h | 86 | ||||
-rw-r--r-- | src/newt/native/NewtMacWindow.m | 1017 |
13 files changed, 924 insertions, 681 deletions
diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index cf1099c85..8d1445f80 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -66,16 +66,60 @@ public abstract class Display { /** * Native PointerIcon handle. * <p> - * Instances can be created via {@link Display#createPointerIcon(com.jogamp.common.util.IOUtil.ClassResources, int, int)} - * and released via {@link Display#destroyPointerIcon(PointerIcon)}. + * Instances can be created via {@link Display}'s {@link Display#createPointerIcon(com.jogamp.common.util.IOUtil.ClassResources, int, int) createPointerIcon(..)}. + * </p> + * <p> + * Instance is {@link #destroy()}'ed automatically if it's {@link #getDisplay() associated Display} is destroyed. + * </p> + * <p> + * Instance can be re-validated after destruction via {@link #validate()}. + * </p> + * <p> + * {@link PointerIcon} may be {@link #destroy() destroyed} manually after use, + * i.e. when no {@link Window} {@link Window#setPointerIcon(PointerIcon) uses them} anymore. * </p> * <p> * PointerIcons can be used via {@link Window#setPointerIcon(PointerIcon)}. * </p> */ public static interface PointerIcon { + /** + * @return the associated Display + */ + Display getDisplay(); + + /** + * @return the single {@link IOUtil.ClassResources}. + */ + IOUtil.ClassResources getResource(); + + /** + * Returns true if valid, otherwise false. + * <p> + * A PointerIcon instance becomes invalid if it's {@link #getDisplay() associated Display} is destroyed. + * </p> + */ + boolean isValid(); + + /** + * Returns true if instance {@link #isValid()} or validation was successful, otherwise false. + * <p> + * Validation, i.e. recreation, is required if instance became invalid, see {@link #isValid()}. + * </p> + */ + boolean validate(); + + /** + * Destroys this instance. + * <p> + * Will be called automatically if it's {@link #getDisplay() associated Display} is destroyed. + * </p> + */ + void destroy(); + /** Returns the size, i.e. width and height. */ DimensionImmutable getSize(); + /** Returns the hotspot. */ PointImmutable getHotspot(); @@ -84,28 +128,23 @@ public abstract class Display { } /** - * Returns the created {@link PointerIcon} or <code>null</code> if not implemented on platform. + * Returns the newly created {@link PointerIcon} or <code>null</code> if not implemented on platform. + * <p> + * See {@link PointerIcon} for lifecycle semantics. + * </p> * - * @param pngResource PNG resource + * @param pngResource single PNG resource, only the first entry of {@link IOUtil.ClassResources#resourcePaths} is used. * @param hotX pointer hotspot x-coord, origin is upper-left corner * @param hotY pointer hotspot y-coord, origin is upper-left corner + * @throws IllegalStateException if this Display instance is not {@link #isNativeValid() valid yet}. * @throws MalformedURLException * @throws InterruptedException * @throws IOException * * @see PointerIcon - * @see #destroyPointerIcon(PointerIcon) * @see Window#setPointerIcon(PointerIcon) */ - - public abstract PointerIcon createPointerIcon(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException; - - /** - * @param pi - * - * @see #createPointerIcon(com.jogamp.common.util.IOUtil.ClassResources, int, int) - */ - public abstract void destroyPointerIcon(PointerIcon pi); + public abstract PointerIcon createPointerIcon(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws IllegalStateException, MalformedURLException, InterruptedException, IOException; /** * Manual trigger the native creation, if it is not done yet.<br> diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java index dc3705daa..346c03b15 100644 --- a/src/newt/classes/jogamp/newt/DisplayImpl.java +++ b/src/newt/classes/jogamp/newt/DisplayImpl.java @@ -51,8 +51,6 @@ import java.util.ArrayList; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.NativeWindowFactory; -import javax.media.nativewindow.util.DimensionImmutable; -import javax.media.nativewindow.util.PointImmutable; public abstract class DisplayImpl extends Display { private static int serialno = 1; @@ -68,49 +66,19 @@ public abstract class DisplayImpl extends Display { }); } - public static class PointerIconImpl implements PointerIcon { - public final long handle; - private final DimensionImmutable size; - private final PointImmutable hotspot; - public PointerIconImpl(final long handle, final DimensionImmutable size, final PointImmutable hotspot) { - this.handle=handle; - this.size = size; - this.hotspot = hotspot; - } - @Override - public final DimensionImmutable getSize() { - return size; - } - @Override - public final PointImmutable getHotspot() { - return hotspot; - } - @Override - public final String toString() { - return "PointerIcon[0x"+Long.toHexString(handle)+", "+size+", "+hotspot+"]"; - } - } - - private void addPointerIconToList(final PointerIcon pi) { - synchronized(pointerIconList) { - pointerIconList.add(pi); - } - } - private void delPointerIconFromList(final PointerIcon pi) { - synchronized(pointerIconList) { - pointerIconList.remove(pi); - } - } - private final ArrayList<PointerIcon> pointerIconList = new ArrayList<PointerIcon>(); + final ArrayList<PointerIconImpl> pointerIconList = new ArrayList<PointerIconImpl>(); /** Executed from EDT! */ private void destroyAllPointerIconFromList(final long dpy) { synchronized(pointerIconList) { - for( int i=0; i < pointerIconList.size(); i++ ) { - final PointerIcon item = pointerIconList.get(i); - if( null != item ) { - // destroy! - destroyPointerIconImpl(dpy, item); + final int count = pointerIconList.size(); + for( int i=0; i < count; i++ ) { + final PointerIconImpl item = pointerIconList.get(i); + if(DEBUG) { + System.err.println("destroyAllPointerIconFromList: dpy "+toHexString(dpy)+", # "+i+"/"+count+": "+item+" @ "+getThreadName()); + } + if( null != item && item.isValid() ) { + item.destroyOnEDT(dpy); } } pointerIconList.clear(); @@ -119,31 +87,37 @@ public abstract class DisplayImpl extends Display { @Override public final PointerIcon createPointerIcon(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { - final PointerIcon res = createPointerIconImpl(pngResource, hotX, hotY); - addPointerIconToList(res); - return res; - } - protected PointerIcon createPointerIconImpl(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { - return null; + return createPointerIcon(false /* isTemp */, pngResource, hotX, hotY); } - - @Override - public final void destroyPointerIcon(final PointerIcon pi) { - delPointerIconFromList(pi); - runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() { - @Override - public Object run(long dpy) { + PointerIcon createPointerIcon(final boolean isTemp, final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { + if( !isNativeValid() ) { + throw new IllegalStateException("Display.createPointerIcon(1): Display invalid "+this); + } + final PointerIconImpl[] res = { null }; + runOnEDTIfAvail(true, new Runnable() { + public void run() { try { - destroyPointerIconImpl(dpy, pi); + if( !DisplayImpl.this.isNativeValid() ) { + throw new IllegalStateException("Display.createPointerIcon(2): Display invalid "+DisplayImpl.this); + } + res[0] = createPointerIconImpl(pngResource, hotX, hotY); } catch (Exception e) { e.printStackTrace(); } - return null; + } } ); + if( !isTemp ) { + synchronized(pointerIconList) { + pointerIconList.add(res[0]); } - }); + } + return res[0]; + } + /** Executed from EDT! */ + protected PointerIconImpl createPointerIconImpl(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { + return null; } /** Executed from EDT! */ - protected void destroyPointerIconImpl(final long displayHandle, final PointerIcon pi) { } + protected void destroyPointerIconImpl(final long displayHandle, long piHandle) { } /** Ensure static init has been run. */ /* pp */static void initSingleton() { } @@ -399,6 +373,7 @@ public abstract class DisplayImpl extends Display { @Override public void run() { if ( null != d.getGraphicsDevice() ) { + d.destroyAllPointerIconFromList(f_aDevice.getHandle()); d.closeNativeImpl(f_aDevice); } } diff --git a/src/newt/classes/jogamp/newt/PointerIconImpl.java b/src/newt/classes/jogamp/newt/PointerIconImpl.java new file mode 100644 index 000000000..e2388be67 --- /dev/null +++ b/src/newt/classes/jogamp/newt/PointerIconImpl.java @@ -0,0 +1,126 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.newt; + +import javax.media.nativewindow.util.DimensionImmutable; +import javax.media.nativewindow.util.PointImmutable; + +import com.jogamp.common.util.IOUtil; +import com.jogamp.common.util.IOUtil.ClassResources; +import com.jogamp.newt.Display; +import com.jogamp.newt.Display.PointerIcon; + +public class PointerIconImpl implements PointerIcon { + private final DisplayImpl display; + private final IOUtil.ClassResources resource; + private final DimensionImmutable size; + private final PointImmutable hotspot; + private long handle; + public PointerIconImpl(DisplayImpl display, ClassResources resource, final DimensionImmutable size, final PointImmutable hotspot, final long handle) { + this.display = display; + this.resource = resource; + this.size = size; + this.hotspot = hotspot; + this.handle=handle; + } + public synchronized final long getHandle() { return handle; } + public synchronized final long validatedHandle() { + synchronized(display.pointerIconList) { + if( !display.pointerIconList.contains(this) ) { + display.pointerIconList.add(this); + } + } + if( 0 == handle ) { + try { + final PointerIconImpl temp = (PointerIconImpl) display.createPointerIcon(true /* isTemp */, resource, hotspot.getX(), hotspot.getY()); + handle = temp.handle; + return handle; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } else { + return handle; + } + } + @Override + public final Display getDisplay() { return display; } + @Override + public final IOUtil.ClassResources getResource() { return resource; } + @Override + public synchronized final boolean isValid() { return 0 != handle; } + @Override + public synchronized final boolean validate() { + if( 0 == handle ) { + return 0 != validatedHandle(); + } + return true; + } + + @Override + public synchronized void destroy() { + if(DisplayImpl.DEBUG) { + System.err.println("PointerIcon.destroy: "+this+", "+display+", "+DisplayImpl.getThreadName()); + } + if( 0 != handle ) { + synchronized(display.pointerIconList) { + display.pointerIconList.remove(this); + } + display.runOnEDTIfAvail(false, new Runnable() { + public void run() { + if( display.isNativeValid() ) { + destroyOnEDT(display.getHandle()); + } + } } ); + } + } + + /** No checks, assume execution on EDT */ + synchronized void destroyOnEDT(final long dpy) { + final long h = handle; + handle = 0; + try { + display.destroyPointerIconImpl(dpy, h); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public final DimensionImmutable getSize() { + return size; + } + @Override + public final PointImmutable getHotspot() { + return hotspot; + } + @Override + public final String toString() { + return "PointerIcon["+DisplayImpl.toHexString(super.hashCode())+", "+display.getFQName()+", "+resource.resourcePaths[0]+", 0x"+Long.toHexString(handle)+", "+size+", "+hotspot+"]"; + } +}
\ No newline at end of file diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index d078caa3b..8d9fb8d7e 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -84,7 +84,6 @@ import javax.media.nativewindow.util.Rectangle; import javax.media.nativewindow.util.RectangleImmutable; import jogamp.nativewindow.SurfaceUpdatedHelper; -import jogamp.newt.DisplayImpl.PointerIconImpl; public abstract class WindowImpl implements Window, NEWTEventConsumer { @@ -440,7 +439,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer screen.addMonitorModeListener(monitorModeListenerImpl); setTitleImpl(title); if( null != pointerIcon ) { - setPointerIcon(pointerIcon); + setPointerIconImpl((PointerIconImpl)pointerIcon); } setPointerVisibleImpl(pointerVisible); confinePointerImpl(pointerConfined); @@ -1689,9 +1688,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @Override public final void setPointerIcon(final PointerIcon pi) { if( this.pointerIcon != pi ) { - setPointerIcon(pointerIcon); if( isNativeValid() ) { - setPointerIconImpl((PointerIconImpl)pi); + runOnEDTIfAvail(true, new Runnable() { + public void run() { + setPointerIconImpl((PointerIconImpl)pi); + } } ); } this.pointerIcon = pi; } diff --git a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java index f0f0a955a..30583c48c 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java @@ -50,6 +50,7 @@ import com.jogamp.newt.NewtFactory; import jogamp.newt.DisplayImpl; import jogamp.newt.NEWTJNILibLoader; +import jogamp.newt.PointerIconImpl; import jogamp.newt.driver.PNGIcon; public class DisplayDriver extends DisplayImpl { @@ -112,21 +113,21 @@ public class DisplayDriver extends DisplayImpl { } @Override - protected PointerIcon createPointerIconImpl(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { + protected PointerIconImpl createPointerIconImpl(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { if( PNGIcon.isAvailable() ) { final int[] width = { 0 }, height = { 0 }, data_size = { 0 }; if( null != pngResource && 0 < pngResource.resourceCount() ) { - return new PointerIconImpl( createPointerIcon0(data, width[0], height[0], hotX, hotY), - new Dimension(width[0], height[0]), new Point(hotX, hotY)); final ByteBuffer data = PNGIcon.singleToRGBAImage(pngResource, 0, true /* toBGRA */, width, height, data_size); + return new PointerIconImpl( this, pngResource, new Dimension(width[0], height[0]), + new Point(hotX, hotY), createPointerIcon0(data, width[0], height[0], hotX, hotY)); } } return null; } @Override - protected final void destroyPointerIconImpl(final long displayHandle, final PointerIcon pi) { - destroyPointerIcon0(((PointerIconImpl)pi).handle); + protected final void destroyPointerIconImpl(final long displayHandle, long piHandle) { + destroyPointerIcon0(piHandle); } public static void runNSApplication() { diff --git a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java index a55fa915a..6f3c95570 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java @@ -45,8 +45,8 @@ import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.PointImmutable; import jogamp.nativewindow.macosx.OSXUtil; +import jogamp.newt.PointerIconImpl; import jogamp.newt.WindowImpl; -import jogamp.newt.DisplayImpl.PointerIconImpl; import jogamp.newt.driver.DriverClearFocus; import jogamp.newt.driver.DriverUpdatePosition; @@ -394,17 +394,29 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl @Override protected void setPointerIconImpl(final PointerIconImpl pi) { - OSXUtil.RunOnMainThread(false, new Runnable() { - @Override - public void run() { - setPointerIcon0(getWindowHandle(), null != pi ? pi.handle : 0); - } } ); + if( !isOffscreenInstance ) { + final long piHandle = null != pi ? pi.validatedHandle() : 0; + OSXUtil.RunOnMainThread(true, new Runnable() { // waitUntildone due to PointerIconImpl's Lifecycle ! + @Override + public void run() { + if( !setPointerIcon0(getWindowHandle(), piHandle) ) { + throw new RuntimeException("Failed: "+pi+", "+WindowDriver.this); + } + } } ); + } // else may need offscreen solution ? FIXME } @Override protected boolean setPointerVisibleImpl(final boolean pointerVisible) { if( !isOffscreenInstance ) { - return setPointerVisible0(getWindowHandle(), hasFocus(), pointerVisible); + OSXUtil.RunOnMainThread(false, new Runnable() { + @Override + public void run() { + if( !setPointerVisible0(getWindowHandle(), hasFocus(), pointerVisible) ) { + throw new RuntimeException("Failed"); + } + } } ); + return true; // setPointerVisible0 always returns true .. } // else may need offscreen solution ? FIXME return false; } @@ -420,7 +432,9 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl @Override protected void warpPointerImpl(final int x, final int y) { if( !isOffscreenInstance ) { - warpPointer0(getWindowHandle(), x, y); + if( !warpPointer0(getWindowHandle(), x, y) ) { + throw new RuntimeException("Failed"); + } } // else may need offscreen solution ? FIXME } @@ -575,10 +589,10 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl /** Must be called on Main-Thread */ private native void setAlwaysOnTop0(long window, boolean atop); private static native Object getLocationOnScreen0(long windowHandle, int src_x, int src_y); + private static native boolean setPointerIcon0(long windowHandle, long handle); private static native boolean setPointerVisible0(long windowHandle, boolean hasFocus, boolean visible); private static native boolean confinePointer0(long windowHandle, boolean confine); - private static native void warpPointer0(long windowHandle, int x, int y); - private static native void setPointerIcon0(long windowHandle, long handle); + private static native boolean warpPointer0(long windowHandle, int x, int y); // Window styles private static final int NSBorderlessWindowMask = 0; diff --git a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java index 39b2efd15..1e9c78a5d 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java @@ -43,6 +43,7 @@ import jogamp.nativewindow.windows.RegisteredClass; import jogamp.nativewindow.windows.RegisteredClassFactory; import jogamp.newt.DisplayImpl; import jogamp.newt.NEWTJNILibLoader; +import jogamp.newt.PointerIconImpl; import jogamp.newt.driver.PNGIcon; import javax.media.nativewindow.AbstractGraphicsDevice; @@ -104,21 +105,21 @@ public class DisplayDriver extends DisplayImpl { } @Override - protected PointerIcon createPointerIconImpl(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { + protected PointerIconImpl createPointerIconImpl(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { if( PNGIcon.isAvailable() ) { final int[] width = { 0 }, height = { 0 }, data_size = { 0 }; if( null != pngResource && 0 < pngResource.resourceCount() ) { - return new PointerIconImpl( createBGRA8888Icon0(data, width[0], height[0], true, hotX, hotY), - new Dimension(width[0], height[0]), new Point(hotX, hotY)); final ByteBuffer data = PNGIcon.singleToRGBAImage(pngResource, 0, true /* toBGRA */, width, height, data_size); + return new PointerIconImpl( this, pngResource, new Dimension(width[0], height[0]), + new Point(hotX, hotY), createBGRA8888Icon0(data, width[0], height[0], true, hotX, hotY)); } } return null; } @Override - protected final void destroyPointerIconImpl(final long displayHandle, final PointerIcon pi) { - destroyIcon0(((PointerIconImpl)pi).handle); + protected final void destroyPointerIconImpl(final long displayHandle, long piHandle) { + destroyIcon0(piHandle); } //---------------------------------------------------------------------- diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java index 764d4fdab..c8d7c65cc 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java @@ -38,8 +38,8 @@ import java.nio.ByteBuffer; import jogamp.nativewindow.windows.GDI; import jogamp.nativewindow.windows.GDIUtil; +import jogamp.newt.PointerIconImpl; import jogamp.newt.WindowImpl; -import jogamp.newt.DisplayImpl.PointerIconImpl; import jogamp.newt.driver.PNGIcon; import javax.media.nativewindow.AbstractGraphicsConfiguration; @@ -252,7 +252,7 @@ public class WindowDriver extends WindowImpl { @Override protected void setPointerIconImpl(final PointerIconImpl pi) { - setPointerIcon0(getWindowHandle(), null != pi ? pi.handle : 0); + setPointerIcon0(getWindowHandle(), null != pi ? pi.validatedHandle() : 0); } @Override diff --git a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java index c377e7f85..150337df4 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java @@ -51,6 +51,7 @@ import com.jogamp.nativewindow.x11.X11GraphicsDevice; import jogamp.nativewindow.x11.X11Util; import jogamp.newt.DisplayImpl; import jogamp.newt.NEWTJNILibLoader; +import jogamp.newt.PointerIconImpl; import jogamp.newt.driver.PNGIcon; public class DisplayDriver extends DisplayImpl { @@ -131,32 +132,21 @@ public class DisplayDriver extends DisplayImpl { protected Boolean isXineramaEnabled() { return isNativeValid() ? Boolean.valueOf(((X11GraphicsDevice)aDevice).isXineramaEnabled()) : null; } @Override - protected PointerIcon createPointerIconImpl(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { + protected PointerIconImpl createPointerIconImpl(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { if( PNGIcon.isAvailable() ) { final int[] width = { 0 }, height = { 0 }, data_size = { 0 }; if( null != pngResource && 0 < pngResource.resourceCount() ) { final ByteBuffer data = PNGIcon.singleToRGBAImage(pngResource, 0, false /* toBGRA */, width, height, data_size); - final long handle = runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Long>() { - @Override - public Long run(long dpy) { - long h = 0; - try { - h = createPointerIcon0(dpy, data, width[0], height[0], hotX, hotY); - } catch (Exception e) { - e.printStackTrace(); - } - return Long.valueOf(h); - } - }).longValue(); - return new PointerIconImpl(handle, new Dimension(width[0], height[0]), new Point(hotX, hotY)); + final long handle = createPointerIcon0(getHandle(), data, width[0], height[0], hotX, hotY); + return new PointerIconImpl(DisplayDriver.this, pngResource, new Dimension(width[0], height[0]), new Point(hotX, hotY), handle); } } return null; } @Override - protected final void destroyPointerIconImpl(final long displayHandle, final PointerIcon pi) { - destroyPointerIcon0(displayHandle, ((PointerIconImpl)pi).handle); + protected final void destroyPointerIconImpl(final long displayHandle, long piHandle) { + destroyPointerIcon0(displayHandle, piHandle); } //---------------------------------------------------------------------- diff --git a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java index 0ea2c5358..ad1744f2e 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java @@ -40,7 +40,7 @@ import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; import jogamp.newt.DisplayImpl; import jogamp.newt.DisplayImpl.DisplayRunnable; -import jogamp.newt.DisplayImpl.PointerIconImpl; +import jogamp.newt.PointerIconImpl; import jogamp.newt.WindowImpl; import jogamp.newt.driver.PNGIcon; @@ -279,7 +279,7 @@ public class WindowDriver extends WindowImpl { @Override public Object run(long dpy) { try { - setPointerIcon0(dpy, getWindowHandle(), null != pi ? pi.handle : 0); + setPointerIcon0(dpy, getWindowHandle(), null != pi ? pi.validatedHandle() : 0); } catch (Exception e) { e.printStackTrace(); } @@ -293,7 +293,15 @@ public class WindowDriver extends WindowImpl { return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Boolean>() { @Override public Boolean run(long dpy) { - return Boolean.valueOf(setPointerVisible0(dpy, getWindowHandle(), pointerVisible)); + final PointerIconImpl pi = (PointerIconImpl)getPointerIcon(); + final boolean res; + if( pointerVisible && null != pi ) { + setPointerIcon0(dpy, getWindowHandle(), null != pi ? pi.validatedHandle() : 0); + res = true; + } else { + res = setPointerVisible0(dpy, getWindowHandle(), pointerVisible); + } + return Boolean.valueOf(res); } }).booleanValue(); } diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index 1be3a6ed5..eb5913706 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -347,30 +347,14 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_createPoint JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_destroyPointerIcon0 (JNIEnv *env, jobject unused, jlong handle) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSCursor * c = (NSCursor*) (intptr_t) handle ; - if( NULL != c ) { - if ( NO == [c isKindOfClass:[NSCursor class]] ) { - DBG_PRINT( "destroyPointerIcon0 NSCursor %p - is of invalid type\n", c); - } else { - DBG_PRINT( "destroyPointerIcon0 %p\n", c); - [c release]; - } + if( NULL != c && NO == [c isKindOfClass:[NSCursor class]] ) { + DBG_PRINT( "Not a NSCursor %p\n", c); + return; } - [pool release]; -} - -JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointerIcon0 - (JNIEnv *env, jobject unused, jlong window, jlong handle) -{ + DBG_PRINT( "destroyPointerIcon0 %p\n", c); NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NewtMacWindow *mWin = (NewtMacWindow*) (intptr_t) window; - NSCursor * c = (NSCursor*) (intptr_t) handle ; - if ( NULL != c && NO == [c isKindOfClass:[NSCursor class]] ) { - DBG_PRINT( "setPointerIcon0 NSCursor %p - is of invalid type (1)\n", c); - } else { - [mWin setPointerIcon: c]; - } + [c release]; [pool release]; } @@ -717,7 +701,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createView0 NSRect rectView = NSMakeRect(0, 0, w, h); NewtView *myView = [[NewtView alloc] initWithFrame: rectView] ; - DBG_PRINT( "createView0.X.%d - new view: %p\n", myView); + DBG_PRINT( "createView0.X - new view: %p\n", myView); [pool release]; @@ -738,7 +722,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createWindow NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtView* myView = (NewtView*) (intptr_t) jview ; - DBG_PRINT( "createWindow0 - %p (this), %d/%d %dx%d, fs %d, style %X, buffType %X, screenidx %d, view %p (START)\n", + DBG_PRINT( "createWindow0 - %p (this), %d/%d %dx%d, fs %d, style %X, buffType %X, view %p (START)\n", (void*)(intptr_t)jthis, (int)x, (int)y, (int)w, (int)h, (int)fullscreen, (int)styleMask, (int)bufferingType, myView); (void)myView; @@ -865,6 +849,7 @@ NS_ENDHANDLER // Set the content view changeContentView(env, jthis, parentView, myWindow, myView, NO); + [myWindow setInitialFirstResponder: myView]; DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", dbgIdx++, myWindow, myView, [myWindow isVisible]); @@ -965,7 +950,6 @@ NS_ENDHANDLER JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_close0 (JNIEnv *env, jobject unused, jlong window) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtMacWindow* mWin = (NewtMacWindow*) ((intptr_t) window); if( NULL == mWin ) { DBG_PRINT( "windowClose.0 - NULL NEWT win - abort\n"); @@ -979,6 +963,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_close0 DBG_PRINT( "windowClose.0 - Not a NEWT win - abort\n"); return; } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtView* mView = (NewtView *)[mWin contentView]; BOOL fullscreen = mWin->isFullscreenWindow; BOOL destroyNotifySent, isNSView, isNewtView; @@ -1093,6 +1078,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_requestFocus0 #endif DBG_PRINT( "requestFocus - window: %p, force %d, hasFocus %d (START)\n", mWin, force, hasFocus); + [mWin setAcceptsMouseMovedEvents: YES]; [mWin makeFirstResponder: nil]; [mWin orderFrontRegardless]; [mWin makeKeyWindow]; @@ -1331,18 +1317,39 @@ JNIEXPORT jobject JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_getLocatio (JNIEnv *env, jclass unused, jlong win, jint src_x, jint src_y) { NSObject *nsObj = (NSObject*) ((intptr_t) win); - NewtMacWindow * mWin = NULL; - - if( [nsObj isKindOfClass:[NewtMacWindow class]] ) { - mWin = (NewtMacWindow*) nsObj; - } else { - NewtCommon_throwNewRuntimeException(env, "not NewtMacWindow %p\n", nsObj); + NewtMacWindow * mWin = (NewtMacWindow*) nsObj; + if( ![mWin isKindOfClass:[NewtMacWindow class]] ) { + DBG_PRINT("Not a NewtMacWindow %p\n", nsObj); + return NULL; } - NSPoint p0 = [mWin getLocationOnScreen: NSMakePoint(src_x, src_y)]; return (*env)->NewObject(env, pointClz, pointCstr, (jint)p0.x, (jint)p0.y); } +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointerIcon0 + (JNIEnv *env, jobject unused, jlong window, jlong handle) +{ + NSCursor *c = (NSCursor*) (intptr_t) handle ; + if ( NULL != c && NO == [c isKindOfClass:[NSCursor class]] ) { + DBG_PRINT("Not a NSCursor %p\n", c); + return JNI_FALSE; + } + NewtMacWindow *mWin = (NewtMacWindow*) (intptr_t) window; + if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { + DBG_PRINT("Not a NewtMacWindow %p\n", mWin); + return JNI_FALSE; + } + NewtView* nView = (NewtView *) [mWin contentView]; + if( ! [nView isKindOfClass:[NewtView class]] ) { + DBG_PRINT("Not a NewtView %p\n", nView); + return JNI_FALSE; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nView setPointerIcon: c]; + [pool release]; + return JNI_TRUE; +} + /* * Class: Java_jogamp_newt_driver_macosx_WindowDriver * Method: setPointerVisible0 @@ -1351,10 +1358,19 @@ JNIEXPORT jobject JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_getLocatio JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointerVisible0 (JNIEnv *env, jclass clazz, jlong window, jboolean hasFocus, jboolean mouseVisible) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); - [mWin setMouseVisible: ( JNI_TRUE == mouseVisible ) ? YES : NO - hasFocus: ( JNI_TRUE == hasFocus ) ? YES : NO]; + if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { + DBG_PRINT("Not a NewtMacWindow %p\n", mWin); + return JNI_FALSE; + } + NewtView* nView = (NewtView *) [mWin contentView]; + if( ! [nView isKindOfClass:[NewtView class]] ) { + DBG_PRINT("Not a NewtView %p\n", nView); + return JNI_FALSE; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nView setMouseVisible: ( JNI_TRUE == mouseVisible ) ? YES : NO + hasFocus: ( JNI_TRUE == hasFocus ) ? YES : NO]; [pool release]; return JNI_TRUE; } @@ -1367,9 +1383,18 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointe JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_confinePointer0 (JNIEnv *env, jclass clazz, jlong window, jboolean confine) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); - [mWin setMouseConfined: ( JNI_TRUE == confine ) ? YES : NO]; + if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { + DBG_PRINT("Not a NewtMacWindow %p\n", mWin); + return JNI_FALSE; + } + NewtView* nView = (NewtView *) [mWin contentView]; + if( ! [nView isKindOfClass:[NewtView class]] ) { + DBG_PRINT("Not a NewtView %p\n", nView); + return JNI_FALSE; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nView setMouseConfined: ( JNI_TRUE == confine ) ? YES : NO]; [pool release]; return JNI_TRUE; } @@ -1379,12 +1404,22 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_confinePo * Method: warpPointer0 * Signature: (JJII)V */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_warpPointer0 +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_warpPointer0 (JNIEnv *env, jclass clazz, jlong window, jint x, jint y) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); - [mWin setMousePosition: [mWin newtRelClientTLWinPos2AbsBLScreenPos: NSMakePoint(x, y)]]; + if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { + DBG_PRINT("Not a NewtMacWindow %p\n", mWin); + return JNI_FALSE; + } + NewtView* nView = (NewtView *) [mWin contentView]; + if( ! [nView isKindOfClass:[NewtView class]] ) { + DBG_PRINT("Not a NewtView %p\n", nView); + return JNI_FALSE; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nView setMousePosition: [mWin newtRelClientTLWinPos2AbsBLScreenPos: NSMakePoint(x, y)]]; [pool release]; + return JNI_TRUE; } diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h index 2728c2201..daf75bec7 100644 --- a/src/newt/native/NewtMacWindow.h +++ b/src/newt/native/NewtMacWindow.h @@ -63,6 +63,14 @@ volatile NSTrackingRectTag ptrTrackingTag; NSRect ptrRect; + NSCursor * myCursor; + BOOL modsDown[4]; // shift, ctrl, alt/option, win/command + + BOOL mouseConfined; + BOOL mouseInside; + BOOL mouseVisible; + BOOL cursorIsHidden; + NSPoint lastInsideMousePosition; } - (id)initWithFrame:(NSRect)frameRect; @@ -83,9 +91,6 @@ - (void) setJavaWindowObject: (jobject) javaWindowObj; - (jobject) getJavaWindowObject; -- (void) rightMouseDown: (NSEvent*) theEvent; -- (void) resetCursorRects; - - (void) setDestroyNotifySent: (BOOL) v; - (BOOL) getDestroyNotifySent; @@ -99,6 +104,41 @@ - (void) viewDidHide; - (void) viewDidUnhide; - (BOOL) acceptsFirstResponder; +- (BOOL) becomeFirstResponder; +- (BOOL) resignFirstResponder; + +- (void) removeCursorRects; +- (void) addCursorRects; +- (void) removeMyCursor; +- (void) resetCursorRects; +- (void) setPointerIcon: (NSCursor*)c; +- (void) mouseEntered: (NSEvent*) theEvent; +- (void) mouseExited: (NSEvent*) theEvent; +- (BOOL) updateMouseInside; +- (void) cursorHide:(BOOL)v enter:(int)enterState; +- (void) setPointerIcon:(NSCursor*)c; +- (void) setMouseVisible:(BOOL)v hasFocus:(BOOL)focus; +- (BOOL) isMouseVisible; +- (void) setMouseConfined:(BOOL)v; +- (void) setMousePosition:(NSPoint)p; +- (void) mouseMoved: (NSEvent*) theEvent; +- (void) scrollWheel: (NSEvent*) theEvent; +- (void) mouseDown: (NSEvent*) theEvent; +- (void) mouseDragged: (NSEvent*) theEvent; +- (void) mouseUp: (NSEvent*) theEvent; +- (void) rightMouseDown: (NSEvent*) theEvent; +- (void) rightMouseDragged: (NSEvent*) theEvent; +- (void) rightMouseUp: (NSEvent*) theEvent; +- (void) otherMouseDown: (NSEvent*) theEvent; +- (void) otherMouseDragged: (NSEvent*) theEvent; +- (void) otherMouseUp: (NSEvent*) theEvent; +- (void) sendMouseEvent: (NSEvent*) event eventType: (jshort) evType; +- (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p; + +- (void) handleFlagsChanged:(NSUInteger) mods; +- (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods; +- (void) sendKeyEvent: (NSEvent*) event eventType: (jshort) evType; +- (void) sendKeyEvent: (jshort) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jshort) evType; @end @@ -108,14 +148,7 @@ @interface NewtMacWindow : NSWindow #endif { - BOOL mouseConfined; - BOOL mouseVisible; - BOOL mouseInside; - BOOL cursorIsHidden; - NSCursor * customCursor; BOOL realized; - BOOL modsDown[4]; // shift, ctrl, alt/option, win/command - NSPoint lastInsideMousePosition; @public BOOL hasPresentationSwitch; NSUInteger defaultPresentationOptions; @@ -147,20 +180,14 @@ - (NSPoint) newtRelClientTLWinPos2AbsBLScreenPos: (NSPoint) p; - (NSSize) newtClientSize2TLSize: (NSSize) nsz; - (NSPoint) getLocationOnScreen: (NSPoint) p; -- (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p; -- (BOOL) isMouseInside; -- (void) cursorHide:(BOOL)v enter:(int)enterState; -- (void) setPointerIcon:(NSCursor*)c; -- (void) setMouseVisible:(BOOL)v hasFocus:(BOOL)focus; -- (void) setMouseConfined:(BOOL)v; -- (void) setMousePosition:(NSPoint)p; - -- (void) sendKeyEvent: (NSEvent*) event eventType: (jshort) evType; -- (void) sendKeyEvent: (jshort) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jshort) evType; -- (void) sendMouseEvent: (NSEvent*) event eventType: (jshort) evType; - (void) focusChanged: (BOOL) gained; +- (void) keyDown: (NSEvent*) theEvent; +- (void) keyUp: (NSEvent*) theEvent; +- (void) flagsChanged: (NSEvent *) theEvent; +- (BOOL) acceptsMouseMovedEvents; +- (BOOL) acceptsFirstResponder; - (BOOL) becomeFirstResponder; - (BOOL) resignFirstResponder; - (BOOL) canBecomeKeyWindow; @@ -168,22 +195,7 @@ - (void) resignKeyWindow; - (void) windowDidBecomeKey: (NSNotification *) notification; - (void) windowDidResignKey: (NSNotification *) notification; -- (void) keyDown: (NSEvent*) theEvent; -- (void) keyUp: (NSEvent*) theEvent; -- (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods; -- (void) flagsChanged: (NSEvent *) theEvent; -- (void) mouseEntered: (NSEvent*) theEvent; -- (void) mouseExited: (NSEvent*) theEvent; -- (void) mouseMoved: (NSEvent*) theEvent; -- (void) scrollWheel: (NSEvent*) theEvent; -- (void) mouseDown: (NSEvent*) theEvent; -- (void) mouseDragged: (NSEvent*) theEvent; -- (void) mouseUp: (NSEvent*) theEvent; -- (void) rightMouseDown: (NSEvent*) theEvent; -- (void) rightMouseDragged: (NSEvent*) theEvent; -- (void) rightMouseUp: (NSEvent*) theEvent; -- (void) otherMouseDown: (NSEvent*) theEvent; -- (void) otherMouseUp: (NSEvent*) theEvent; + - (void) windowDidResize: (NSNotification*) notification; - (void) windowDidMove: (NSNotification*) notification; - (BOOL) windowClosingImpl: (BOOL) force; diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index 96965b67a..5ccd9c658 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -86,6 +86,88 @@ static jfloat GetDelta(NSEvent *event, jint javaMods[]) { return (jfloat) delta; } +#define kVK_Shift 0x38 +#define kVK_Option 0x3A +#define kVK_Control 0x3B +#define kVK_Command 0x37 + +static jint mods2JavaMods(NSUInteger mods) +{ + int javaMods = 0; + if (mods & NSShiftKeyMask) { + javaMods |= EVENT_SHIFT_MASK; + } + if (mods & NSControlKeyMask) { + javaMods |= EVENT_CTRL_MASK; + } + if (mods & NSCommandKeyMask) { + javaMods |= EVENT_META_MASK; + } + if (mods & NSAlternateKeyMask) { + javaMods |= EVENT_ALT_MASK; + } + return javaMods; +} + +static CFStringRef CKCH_CreateStringForKey(CGKeyCode keyCode, const UCKeyboardLayout *keyboardLayout) { + UInt32 keysDown = 0; + UniChar chars[4]; + UniCharCount realLength; + + UCKeyTranslate(keyboardLayout, keyCode, + kUCKeyActionDisplay, 0, + LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, + &keysDown, sizeof(chars) / sizeof(chars[0]), &realLength, chars); + + return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1); +} + +static CFMutableDictionaryRef CKCH_CreateCodeToCharDict(TISInputSourceRef keyboard) { + CFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData); + const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); + + CFMutableDictionaryRef codeToCharDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 128, NULL, NULL); + if ( NULL != codeToCharDict ) { + intptr_t i; + for (i = 0; i < 128; ++i) { + CFStringRef string = CKCH_CreateStringForKey((CGKeyCode)i, keyboardLayout); + if( NULL != string ) { + CFIndex stringLen = CFStringGetLength (string); + if ( 0 < stringLen ) { + UniChar character = CFStringGetCharacterAtIndex(string, 0); + DBG_PRINT("CKCH: MAP 0x%X -> %c\n", (int)i, character); + CFDictionaryAddValue(codeToCharDict, (const void *)i, (const void *)(intptr_t)character); + } + CFRelease(string); + } + } + } + return codeToCharDict; +} + +static CFMutableDictionaryRef CKCH_USCodeToNNChar = NULL; + +static void CKCH_CreateDictionaries() { + TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); + CKCH_USCodeToNNChar = CKCH_CreateCodeToCharDict(currentKeyboard); + CFRelease(currentKeyboard); +} + +static UniChar CKCH_CharForKeyCode(jshort keyCode) { + UniChar rChar = 0; + + if ( NULL != CKCH_USCodeToNNChar ) { + intptr_t code = (intptr_t) keyCode; + intptr_t character = 0; + + if ( CFDictionaryGetValueIfPresent(CKCH_USCodeToNNChar, (void *)code, (const void **)&character) ) { + rChar = (UniChar) character; + DBG_PRINT("CKCH: OK 0x%X -> 0x%X\n", (int)keyCode, (int)rChar); + } + } + return rChar; +} + static jmethodID enqueueMouseEventID = NULL; static jmethodID enqueueKeyEventID = NULL; static jmethodID requestFocusID = NULL; @@ -122,6 +204,16 @@ static jmethodID windowRepaintID = NULL; pthread_mutex_init(&softLockSync, &softLockSyncAttr); // recursive ptrTrackingTag = 0; + myCursor = NULL; + + modsDown[0] = NO; // shift + modsDown[1] = NO; // ctrl + modsDown[2] = NO; // alt + modsDown[3] = NO; // win + mouseConfined = NO; + mouseVisible = YES; + mouseInside = NO; + cursorIsHidden = NO; DBG_PRINT("NewtView::create: %p (refcnt %d)\n", res, (int)[res retainCount]); return res; @@ -144,10 +236,9 @@ static jmethodID windowRepaintID = NULL; if( 0 < softLockCount ) { NSLog(@"NewtView::dealloc: softLock still hold @ dealloc!\n"); } - if(0 != ptrTrackingTag) { - [self removeTrackingRect: ptrTrackingTag]; - ptrTrackingTag = 0; - } + [self removeCursorRects]; + [self removeMyCursor]; + pthread_mutex_destroy(&softLockSync); DBG_PRINT("NewtView::dealloc.X: %p\n", self); [super dealloc]; @@ -182,26 +273,6 @@ static jmethodID windowRepaintID = NULL; return javaWindowObject; } -- (void) rightMouseDown: (NSEvent*) theEvent -{ - NSResponder* next = [self nextResponder]; - if (next != nil) { - [next rightMouseDown: theEvent]; - } -} - -- (void) resetCursorRects -{ - [super resetCursorRects]; - - if(0 != ptrTrackingTag) { - [self removeTrackingRect: ptrTrackingTag]; - ptrTrackingTag = 0; - } - ptrRect = [self bounds]; - ptrTrackingTag = [self addTrackingRect: ptrRect owner: self userData: nil assumeInside: NO]; -} - - (void) setDestroyNotifySent: (BOOL) v { destroyNotifySent = v; @@ -337,67 +408,397 @@ static jmethodID windowRepaintID = NULL; return YES; } -@end +- (BOOL) becomeFirstResponder +{ + DBG_PRINT( "*************** View.becomeFirstResponder\n"); + return [super becomeFirstResponder]; +} -static CFStringRef CKCH_CreateStringForKey(CGKeyCode keyCode, const UCKeyboardLayout *keyboardLayout) { - UInt32 keysDown = 0; - UniChar chars[4]; - UniCharCount realLength; +- (BOOL) resignFirstResponder +{ + DBG_PRINT( "*************** View.resignFirstResponder\n"); + return [super resignFirstResponder]; +} - UCKeyTranslate(keyboardLayout, keyCode, - kUCKeyActionDisplay, 0, - LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, - &keysDown, sizeof(chars) / sizeof(chars[0]), &realLength, chars); +- (void) removeCursorRects +{ + if(0 != ptrTrackingTag) { + if(NULL != myCursor) { + [self removeCursorRect: ptrRect cursor: myCursor]; + } + [self removeTrackingRect: ptrTrackingTag]; + ptrTrackingTag = 0; + } +} - return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1); +- (void) addCursorRects +{ + ptrRect = [self bounds]; + if(NULL != myCursor) { + [self addCursorRect: ptrRect cursor: myCursor]; + } + ptrTrackingTag = [self addTrackingRect: ptrRect owner: self userData: nil assumeInside: NO]; } -static CFMutableDictionaryRef CKCH_CreateCodeToCharDict(TISInputSourceRef keyboard) { - CFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData); - const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); +- (void) removeMyCursor +{ + if(NULL != myCursor) { + [myCursor release]; + myCursor = NULL; + } +} - CFMutableDictionaryRef codeToCharDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 128, NULL, NULL); - if ( NULL != codeToCharDict ) { - intptr_t i; - for (i = 0; i < 128; ++i) { - CFStringRef string = CKCH_CreateStringForKey((CGKeyCode)i, keyboardLayout); - if( NULL != string ) { - CFIndex stringLen = CFStringGetLength (string); - if ( 0 < stringLen ) { - UniChar character = CFStringGetCharacterAtIndex(string, 0); - DBG_PRINT("CKCH: MAP 0x%X -> %c\n", (int)i, character); - CFDictionaryAddValue(codeToCharDict, (const void *)i, (const void *)(intptr_t)character); - } - CFRelease(string); - } +- (void) resetCursorRects +{ + [super resetCursorRects]; + + [self removeCursorRects]; + [self addCursorRects]; +} + +- (void) setPointerIcon: (NSCursor*)c +{ + DBG_PRINT( "setPointerIcon: %p -> %p, top %p, mouseInside %d\n", myCursor, c, [NSCursor currentCursor], (int)mouseInside); + if( c != myCursor ) { + [self removeCursorRects]; + [self removeMyCursor]; + myCursor = c; + if( NULL != myCursor ) { + [myCursor retain]; } } - return codeToCharDict; + NSWindow* nsWin = [self window]; + if( NULL != nsWin ) { + [nsWin invalidateCursorRectsForView: self]; + } } -static CFMutableDictionaryRef CKCH_USCodeToNNChar = NULL; +- (void) mouseEntered: (NSEvent*) theEvent +{ + DBG_PRINT( "mouseEntered: confined %d, visible %d, PointerIcon %p, top %p\n", mouseConfined, mouseVisible, myCursor, [NSCursor currentCursor]); + mouseInside = YES; + [self cursorHide: !mouseVisible enter: 1]; + if(NO == mouseConfined) { + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_ENTERED]; + } + NSWindow* nsWin = [self window]; + if( NULL != nsWin ) { + [nsWin makeFirstResponder: self]; + } +} -static void CKCH_CreateDictionaries() { - TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); - CKCH_USCodeToNNChar = CKCH_CreateCodeToCharDict(currentKeyboard); - CFRelease(currentKeyboard); +- (void) mouseExited: (NSEvent*) theEvent +{ + DBG_PRINT( "mouseExited: confined %d, visible %d, PointerIcon %p, top %p\n", mouseConfined, mouseVisible, myCursor, [NSCursor currentCursor]); + if(NO == mouseConfined) { + mouseInside = NO; + [self cursorHide: NO enter: -1]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_EXITED]; + [self resignFirstResponder]; + } else { + [self setMousePosition: lastInsideMousePosition]; + } } -static UniChar CKCH_CharForKeyCode(jshort keyCode) { - UniChar rChar = 0; +- (void) setMousePosition:(NSPoint)p +{ + NSWindow* nsWin = [self window]; + if( NULL != nsWin ) { + NSScreen* screen = [nsWin screen]; + NSRect screenRect = [screen frame]; - if ( NULL != CKCH_USCodeToNNChar ) { - intptr_t code = (intptr_t) keyCode; - intptr_t character = 0; + CGPoint pt = { p.x, screenRect.size.height - p.y }; // y-flip (CG is top-left origin) + CGEventRef ev = CGEventCreateMouseEvent (NULL, kCGEventMouseMoved, pt, kCGMouseButtonLeft); + CGEventPost (kCGHIDEventTap, ev); + } +} - if ( CFDictionaryGetValueIfPresent(CKCH_USCodeToNNChar, (void *)code, (const void **)&character) ) { - rChar = (UniChar) character; - DBG_PRINT("CKCH: OK 0x%X -> 0x%X\n", (int)keyCode, (int)rChar); +- (BOOL) updateMouseInside +{ + NSRect viewFrame = [self frame]; + NSPoint l1 = [NSEvent mouseLocation]; + NSPoint l0 = [self screenPos2NewtClientWinPos: l1]; + mouseInside = viewFrame.origin.x <= l0.x && l0.x < (viewFrame.origin.x+viewFrame.size.width) && + viewFrame.origin.y <= l0.y && l0.y < (viewFrame.origin.y+viewFrame.size.height) ; + return mouseInside; +} + +- (void) setMouseVisible:(BOOL)v hasFocus:(BOOL)focus +{ + mouseVisible = v; + [self updateMouseInside]; + DBG_PRINT( "setMouseVisible: confined %d, visible %d (current: %d), mouseInside %d, hasFocus %d\n", + mouseConfined, mouseVisible, !cursorIsHidden, mouseInside, focus); + if(YES == focus && YES == mouseInside) { + [self cursorHide: !mouseVisible enter: 0]; + } +} +- (BOOL) isMouseVisible +{ + return mouseVisible; +} + +- (void) cursorHide:(BOOL)v enter:(int)enterState +{ + DBG_PRINT( "cursorHide: %d -> %d, enter %d; PointerIcon: %p, top %p\n", + cursorIsHidden, v, enterState, myCursor, [NSCursor currentCursor]); + if(v) { + if(!cursorIsHidden) { + [NSCursor hide]; + cursorIsHidden = YES; + } + } else { + if(cursorIsHidden) { + [NSCursor unhide]; + cursorIsHidden = NO; } } - return rChar; } +- (void) setMouseConfined:(BOOL)v +{ + mouseConfined = v; + DBG_PRINT( "setMouseConfined: confined %d, visible %d\n", mouseConfined, mouseVisible); +} + +- (void) mouseMoved: (NSEvent*) theEvent +{ + if( mouseInside ) { + NSCursor * currentCursor = [NSCursor currentCursor]; + BOOL setCursor = NULL != myCursor && NO == cursorIsHidden && currentCursor != myCursor; + DBG_PRINT( "mouseMoved.set: %d; mouseInside %d, CursorHidden %d, PointerIcon: %p, top %p\n", + setCursor, mouseInside, cursorIsHidden, myCursor, currentCursor); + if( setCursor ) { + // FIXME: Workaround missing NSCursor update for 'fast moving' pointer + [myCursor set]; + } + lastInsideMousePosition = [NSEvent mouseLocation]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; + } +} + +- (void) scrollWheel: (NSEvent*) theEvent +{ + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_WHEEL_MOVED]; +} + +- (void) mouseDown: (NSEvent*) theEvent +{ + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; +} + +- (void) mouseDragged: (NSEvent*) theEvent +{ + lastInsideMousePosition = [NSEvent mouseLocation]; + // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; +} + +- (void) mouseUp: (NSEvent*) theEvent +{ + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; +} + +- (void) rightMouseDown: (NSEvent*) theEvent +{ + NSResponder* next = [self nextResponder]; + if (next != nil) { + [next rightMouseDown: theEvent]; + } + // FIXME: ^^ OR [super rightMouseDown: theEvent] ? + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; +} + +- (void) rightMouseDragged: (NSEvent*) theEvent +{ + lastInsideMousePosition = [NSEvent mouseLocation]; + // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; +} + +- (void) rightMouseUp: (NSEvent*) theEvent +{ + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; +} + +- (void) otherMouseDown: (NSEvent*) theEvent +{ + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; +} + +- (void) otherMouseDragged: (NSEvent*) theEvent +{ + lastInsideMousePosition = [NSEvent mouseLocation]; + // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; +} + +- (void) otherMouseUp: (NSEvent*) theEvent +{ + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; +} + +- (void) sendMouseEvent: (NSEvent*) event eventType: (jshort) evType +{ + if (javaWindowObject == NULL) { + DBG_PRINT("sendMouseEvent: null javaWindowObject\n"); + return; + } + int shallBeDetached = 0; + JNIEnv* env; + if( NULL != jvmHandle ) { + env = NewtCommon_GetJNIEnv(jvmHandle, [self getJVMVersion], 1 /* asDaemon */, &shallBeDetached); + } else { + env = NULL; + } + if(NULL==env) { + DBG_PRINT("sendMouseEvent: JVM %p JNIEnv %p\n", jvmHandle, env); + return; + } + jint javaMods[] = { 0 } ; + javaMods[0] = mods2JavaMods([event modifierFlags]); + + // convert to 1-based button number (or use zero if no button is involved) + // TODO: detect mouse button when mouse wheel scrolled + jshort javaButtonNum = 0; + jfloat scrollDeltaY = 0.0f; + switch ([event type]) { + case NSScrollWheel: { + scrollDeltaY = GetDelta(event, javaMods); + javaButtonNum = 1; + break; + } + case NSLeftMouseDown: + case NSLeftMouseUp: + case NSLeftMouseDragged: + javaButtonNum = 1; + break; + case NSRightMouseDown: + case NSRightMouseUp: + case NSRightMouseDragged: + javaButtonNum = 3; + break; + case NSOtherMouseDown: + case NSOtherMouseUp: + case NSOtherMouseDragged: + javaButtonNum = 2; + break; + } + + if (evType == EVENT_MOUSE_WHEEL_MOVED && scrollDeltaY == 0) { + // ignore 0 increment wheel scroll events + return; + } + if (evType == EVENT_MOUSE_PRESSED) { + (*env)->CallVoidMethod(env, javaWindowObject, requestFocusID, JNI_FALSE); + } + + NSPoint location = [self screenPos2NewtClientWinPos: [NSEvent mouseLocation]]; + + (*env)->CallVoidMethod(env, javaWindowObject, enqueueMouseEventID, JNI_FALSE, + evType, javaMods[0], + (jint) location.x, (jint) location.y, + javaButtonNum, scrollDeltaY); + + /* if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } */ +} + +- (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p +{ + NSRect viewFrame = [self frame]; + + NSRect r; + r.origin.x = p.x; + r.origin.y = p.y; + r.size.width = 0; + r.size.height = 0; + // NSRect rS = [[self window] convertRectFromScreen: r]; // 10.7 + NSPoint oS = [[self window] convertScreenToBase: r.origin]; + oS.y = viewFrame.size.height - oS.y; // y-flip + return oS; +} + +- (void) handleFlagsChanged:(NSUInteger) mods +{ + [self handleFlagsChanged: NSShiftKeyMask keyIndex: 0 keyCode: kVK_Shift modifiers: mods]; + [self handleFlagsChanged: NSControlKeyMask keyIndex: 1 keyCode: kVK_Control modifiers: mods]; + [self handleFlagsChanged: NSAlternateKeyMask keyIndex: 2 keyCode: kVK_Option modifiers: mods]; + [self handleFlagsChanged: NSCommandKeyMask keyIndex: 3 keyCode: kVK_Command modifiers: mods]; +} + +- (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods +{ + if ( NO == modsDown[keyIdx] && 0 != ( mods & keyMask ) ) { + modsDown[keyIdx] = YES; + [self sendKeyEvent: (jshort)keyCode characters: NULL modifiers: mods|keyMask eventType: (jshort)EVENT_KEY_PRESSED]; + } else if ( YES == modsDown[keyIdx] && 0 == ( mods & keyMask ) ) { + modsDown[keyIdx] = NO; + [self sendKeyEvent: (jshort)keyCode characters: NULL modifiers: mods|keyMask eventType: (jshort)EVENT_KEY_RELEASED]; + } +} + +- (void) sendKeyEvent: (NSEvent*) event eventType: (jshort) evType +{ + jshort keyCode = (jshort) [event keyCode]; + NSString* chars = [event charactersIgnoringModifiers]; + NSUInteger mods = [event modifierFlags]; + [self sendKeyEvent: keyCode characters: chars modifiers: mods eventType: evType]; +} + +- (void) sendKeyEvent: (jshort) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jshort) evType +{ + if (javaWindowObject == NULL) { + DBG_PRINT("sendKeyEvent: null javaWindowObject\n"); + return; + } + int shallBeDetached = 0; + JNIEnv* env; + if( NULL != jvmHandle ) { + env = NewtCommon_GetJNIEnv(jvmHandle, [self getJVMVersion], 1 /* asDaemon */, &shallBeDetached); + } else { + env = NULL; + } + if(NULL==env) { + DBG_PRINT("sendKeyEvent: JVM %p JNIEnv %p\n", jvmHandle, env); + return; + } + + int i; + int len = NULL != chars ? [chars length] : 0; + jint javaMods = mods2JavaMods(mods); + + if(len > 0) { + // printable chars + for (i = 0; i < len; i++) { + // Note: the key code in the NSEvent does not map to anything we can use + UniChar keyChar = (UniChar) [chars characterAtIndex: i]; + UniChar keySymChar = CKCH_CharForKeyCode(keyCode); + + DBG_PRINT("sendKeyEvent: %d/%d code 0x%X, char 0x%X, mods 0x%X/0x%X -> keySymChar 0x%X\n", i, len, (int)keyCode, (int)keyChar, + (int)mods, (int)javaMods, (int)keySymChar); + + (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE, + evType, javaMods, keyCode, (jchar)keyChar, (jchar)keySymChar); + } + } else { + // non-printable chars + jchar keyChar = (jchar) 0; + + DBG_PRINT("sendKeyEvent: code 0x%X\n", (int)keyCode); + + (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE, + evType, javaMods, keyCode, keyChar, keyChar); + } + + /* if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } */ +} + +@end + @implementation NewtMacWindow + (BOOL) initNatives: (JNIEnv*) env forClass: (jclass) clazz @@ -463,15 +864,6 @@ static UniChar CKCH_CharForKeyCode(jshort keyCode) { cachedInsets[1] = 0; // r cachedInsets[2] = 0; // t cachedInsets[3] = 0; // b - modsDown[0] = NO; // shift - modsDown[1] = NO; // ctrl - modsDown[2] = NO; // alt - modsDown[3] = NO; // win - mouseConfined = NO; - mouseVisible = YES; - mouseInside = NO; - cursorIsHidden = NO; - customCursor = NULL; realized = YES; DBG_PRINT("NewtWindow::create: %p, realized %d, hasPresentationSwitch %d[defaultOptions 0x%X, fullscreenOptions 0x%X], (refcnt %d)\n", res, realized, (int)hasPresentationSwitch, (int)defaultPresentationOptions, (int)fullscreenPresentationOptions, (int)[res retainCount]); @@ -633,311 +1025,82 @@ static UniChar CKCH_CharForKeyCode(jshort keyCode) { return oS; } -- (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p -{ - NSView* view = [self contentView]; - NSRect viewFrame = [view frame]; - - NSRect r; - r.origin.x = p.x; - r.origin.y = p.y; - r.size.width = 0; - r.size.height = 0; - // NSRect rS = [win convertRectFromScreen: r]; // 10.7 - NSPoint oS = [self convertScreenToBase: r.origin]; - oS.y = viewFrame.size.height - oS.y; // y-flip - return oS; -} - -- (BOOL) isMouseInside -{ - NSView* view = [self contentView]; - NSRect viewFrame = [view frame]; - NSPoint l1 = [NSEvent mouseLocation]; - NSPoint l0 = [self screenPos2NewtClientWinPos: l1]; - return viewFrame.origin.x <= l0.x && l0.x < (viewFrame.origin.x+viewFrame.size.width) && - viewFrame.origin.y <= l0.y && l0.y < (viewFrame.origin.y+viewFrame.size.height) ; -} - -- (void) setMouseVisible:(BOOL)v hasFocus:(BOOL)focus -{ - mouseVisible = v; - mouseInside = [self isMouseInside]; - DBG_PRINT( "setMouseVisible: confined %d, visible %d (current: %d), mouseInside %d, hasFocus %d\n", - mouseConfined, mouseVisible, !cursorIsHidden, mouseInside, focus); - if(YES == focus && YES == mouseInside) { - [self cursorHide: !mouseVisible enter: 0]; - } -} - -- (void) setPointerIcon:(NSCursor*)c -{ - DBG_PRINT( "setPointerIcon: mouseInside cursor: %p -> %p (glob %p), mouseInside %d\n", customCursor, c, [NSCursor currentCursor], (int)mouseInside); - if(YES == mouseInside) { - if( NULL != c ) { - DBG_PRINT( "setPointerIcon push: %p\n", c); - [c push]; - } else if( NULL != customCursor ) { - if ( NO == [customCursor isKindOfClass:[NSCursor class]] ) { - DBG_PRINT( "setPointerIcon0 NSCursor %p - is of invalid type (2)\n", customCursor); - if( [NSCursor currentCursor] == customCursor ) { - [NSCursor pop]; - } - } else if( [NSCursor currentCursor] == customCursor ) { - DBG_PRINT( "setPointerIcon pop: %p\n", customCursor); - [customCursor pop]; - } - } - } - customCursor = c; -} - -- (void) cursorHide:(BOOL)v enter:(int)enterState -{ - DBG_PRINT( "cursorHide: %d -> %d, enter %d\n", cursorIsHidden, v, enterState); - if( NULL != customCursor ) { - if ( NO == [customCursor isKindOfClass:[NSCursor class]] ) { - DBG_PRINT( "setPointerIcon0 NSCursor %p - is of invalid type (3)\n", customCursor); - if( [NSCursor currentCursor] == customCursor ) { - [NSCursor pop]; - } - } else { - if( 1 == enterState && [NSCursor currentCursor] != customCursor ) { - DBG_PRINT( "cursorHide.PointerIcon push: %p\n", customCursor); - [customCursor push]; - } else if( -1 == enterState && [NSCursor currentCursor] == customCursor ) { - DBG_PRINT( "cursorHide.PointerIcon pop: %p\n", customCursor); - [customCursor pop]; - } - } - } - if(v) { - if(!cursorIsHidden) { - [NSCursor hide]; - cursorIsHidden = YES; - } - } else { - if(cursorIsHidden) { - [NSCursor unhide]; - cursorIsHidden = NO; - } - } -} - -- (void) setMouseConfined:(BOOL)v -{ - mouseConfined = v; - DBG_PRINT( "setMouseConfined: confined %d, visible %d\n", mouseConfined, mouseVisible); -} - -- (void) setMousePosition:(NSPoint)p -{ - NSScreen* screen = [self screen]; - NSRect screenRect = [screen frame]; - - CGPoint pt = { p.x, screenRect.size.height - p.y }; // y-flip (CG is top-left origin) - CGEventRef ev = CGEventCreateMouseEvent (NULL, kCGEventMouseMoved, pt, kCGMouseButtonLeft); - CGEventPost (kCGHIDEventTap, ev); -} - -static jint mods2JavaMods(NSUInteger mods) -{ - int javaMods = 0; - if (mods & NSShiftKeyMask) { - javaMods |= EVENT_SHIFT_MASK; - } - if (mods & NSControlKeyMask) { - javaMods |= EVENT_CTRL_MASK; - } - if (mods & NSCommandKeyMask) { - javaMods |= EVENT_META_MASK; - } - if (mods & NSAlternateKeyMask) { - javaMods |= EVENT_ALT_MASK; - } - return javaMods; -} - -- (void) sendKeyEvent: (NSEvent*) event eventType: (jshort) evType -{ - jshort keyCode = (jshort) [event keyCode]; - NSString* chars = [event charactersIgnoringModifiers]; - NSUInteger mods = [event modifierFlags]; - [self sendKeyEvent: keyCode characters: chars modifiers: mods eventType: evType]; -} - -- (void) sendKeyEvent: (jshort) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jshort) evType +- (void) focusChanged: (BOOL) gained { - NSView* nsview = [self contentView]; - if( ! [nsview isKindOfClass:[NewtView class]] ) { + DBG_PRINT( "focusChanged: gained %d\n", gained); + NewtView* newtView = (NewtView *) [self contentView]; + if( ! [newtView isKindOfClass:[NewtView class]] ) { return; } - NewtView* view = (NewtView *) nsview; - jobject javaWindowObject = [view getJavaWindowObject]; + jobject javaWindowObject = [newtView getJavaWindowObject]; if (javaWindowObject == NULL) { - DBG_PRINT("sendKeyEvent: null javaWindowObject\n"); + DBG_PRINT("focusChanged: null javaWindowObject\n"); return; } int shallBeDetached = 0; - JavaVM *jvmHandle = [view getJVMHandle]; + JavaVM *jvmHandle = [newtView getJVMHandle]; JNIEnv* env; if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], 1 /* asDaemon */, &shallBeDetached); + env = NewtCommon_GetJNIEnv(jvmHandle, [newtView getJVMVersion], 1 /* asDaemon */, &shallBeDetached); } else { env = NULL; } if(NULL==env) { - DBG_PRINT("sendKeyEvent: JVM %p JNIEnv %p\n", jvmHandle, env); + DBG_PRINT("focusChanged: JVM %p JNIEnv %p\n", jvmHandle, env); return; } - int i; - int len = NULL != chars ? [chars length] : 0; - jint javaMods = mods2JavaMods(mods); - - if(len > 0) { - // printable chars - for (i = 0; i < len; i++) { - // Note: the key code in the NSEvent does not map to anything we can use - UniChar keyChar = (UniChar) [chars characterAtIndex: i]; - UniChar keySymChar = CKCH_CharForKeyCode(keyCode); - - DBG_PRINT("sendKeyEvent: %d/%d code 0x%X, char 0x%X -> keySymChar 0x%X\n", i, len, (int)keyCode, (int)keyChar, (int)keySymChar); - - (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE, - evType, javaMods, keyCode, (jchar)keyChar, (jchar)keySymChar); - } - } else { - // non-printable chars - jchar keyChar = (jchar) 0; - - DBG_PRINT("sendKeyEvent: code 0x%X\n", (int)keyCode); - - (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE, - evType, javaMods, keyCode, keyChar, keyChar); - } + (*env)->CallVoidMethod(env, javaWindowObject, focusChangedID, JNI_FALSE, (gained == YES) ? JNI_TRUE : JNI_FALSE); /* if (shallBeDetached) { (*jvmHandle)->DetachCurrentThread(jvmHandle); } */ } -- (void) sendMouseEvent: (NSEvent*) event eventType: (jshort) evType +- (void) keyDown: (NSEvent*) theEvent { - NSView* nsview = [self contentView]; - if( ! [nsview isKindOfClass:[NewtView class]] ) { - return; - } - NewtView* view = (NewtView *) nsview; - jobject javaWindowObject = [view getJavaWindowObject]; - if (javaWindowObject == NULL) { - DBG_PRINT("sendMouseEvent: null javaWindowObject\n"); - return; - } - int shallBeDetached = 0; - JavaVM *jvmHandle = [view getJVMHandle]; - JNIEnv* env; - if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], 1 /* asDaemon */, &shallBeDetached); - } else { - env = NULL; - } - if(NULL==env) { - DBG_PRINT("sendMouseEvent: JVM %p JNIEnv %p\n", jvmHandle, env); - return; - } - jint javaMods[] = { 0 } ; - javaMods[0] = mods2JavaMods([event modifierFlags]); - - // convert to 1-based button number (or use zero if no button is involved) - // TODO: detect mouse button when mouse wheel scrolled - jshort javaButtonNum = 0; - jfloat scrollDeltaY = 0.0f; - switch ([event type]) { - case NSScrollWheel: { - scrollDeltaY = GetDelta(event, javaMods); - javaButtonNum = 1; - break; - } - case NSLeftMouseDown: - case NSLeftMouseUp: - case NSLeftMouseDragged: - javaButtonNum = 1; - break; - case NSRightMouseDown: - case NSRightMouseUp: - case NSRightMouseDragged: - javaButtonNum = 3; - break; - case NSOtherMouseDown: - case NSOtherMouseUp: - case NSOtherMouseDragged: - javaButtonNum = 2; - break; + NewtView* newtView = (NewtView *) [self contentView]; + if( [newtView isKindOfClass:[NewtView class]] ) { + [newtView sendKeyEvent: theEvent eventType: (jshort)EVENT_KEY_PRESSED]; } +} - if (evType == EVENT_MOUSE_WHEEL_MOVED && scrollDeltaY == 0) { - // ignore 0 increment wheel scroll events - return; - } - if (evType == EVENT_MOUSE_PRESSED) { - (*env)->CallVoidMethod(env, javaWindowObject, requestFocusID, JNI_FALSE); +- (void) keyUp: (NSEvent*) theEvent +{ + NewtView* newtView = (NewtView *) [self contentView]; + if( [newtView isKindOfClass:[NewtView class]] ) { + [newtView sendKeyEvent: theEvent eventType: (jshort)EVENT_KEY_RELEASED]; } - - NSPoint location = [self screenPos2NewtClientWinPos: [NSEvent mouseLocation]]; - - (*env)->CallVoidMethod(env, javaWindowObject, enqueueMouseEventID, JNI_FALSE, - evType, javaMods[0], - (jint) location.x, (jint) location.y, - javaButtonNum, scrollDeltaY); - - /* if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } */ } -- (void) focusChanged: (BOOL) gained +- (void) flagsChanged:(NSEvent *) theEvent { - DBG_PRINT( "focusChanged: gained %d\n", gained); - NSView* nsview = [self contentView]; - if( ! [nsview isKindOfClass:[NewtView class]] ) { - return; - } - NewtView* view = (NewtView *) nsview; - jobject javaWindowObject = [view getJavaWindowObject]; - if (javaWindowObject == NULL) { - DBG_PRINT("focusChanged: null javaWindowObject\n"); - return; - } - int shallBeDetached = 0; - JavaVM *jvmHandle = [view getJVMHandle]; - JNIEnv* env; - if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], 1 /* asDaemon */, &shallBeDetached); - } else { - env = NULL; - } - if(NULL==env) { - DBG_PRINT("focusChanged: JVM %p JNIEnv %p\n", jvmHandle, env); - return; + NSUInteger mods = [theEvent modifierFlags]; + NewtView* newtView = (NewtView *) [self contentView]; + if( [newtView isKindOfClass:[NewtView class]] ) { + [newtView handleFlagsChanged: mods]; } +} - (*env)->CallVoidMethod(env, javaWindowObject, focusChangedID, JNI_FALSE, (gained == YES) ? JNI_TRUE : JNI_FALSE); +- (BOOL) acceptsMouseMovedEvents +{ + return YES; +} - /* if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } */ +- (BOOL) acceptsFirstResponder +{ + return YES; } - (BOOL) becomeFirstResponder { - DBG_PRINT( "*************** becomeFirstResponder\n"); + DBG_PRINT( "*************** Win.becomeFirstResponder\n"); return [super becomeFirstResponder]; } - (BOOL) resignFirstResponder { - DBG_PRINT( "*************** resignFirstResponder\n"); + DBG_PRINT( "*************** Win.resignFirstResponder\n"); return [super resignFirstResponder]; } @@ -965,9 +1128,12 @@ static jint mods2JavaMods(NSUInteger mods) - (void) windowDidBecomeKey: (NSNotification *) notification { DBG_PRINT( "*************** windowDidBecomeKey\n"); - mouseInside = [self isMouseInside]; - if(YES == mouseInside) { - [self cursorHide: !mouseVisible enter: 0]; + NewtView* newtView = (NewtView *) [self contentView]; + if( [newtView isKindOfClass:[NewtView class]] ) { + BOOL mouseInside = [newtView updateMouseInside]; + if(YES == mouseInside) { + [newtView cursorHide: ![newtView isMouseVisible] enter: 1]; + } } [self focusChanged: YES]; } @@ -979,128 +1145,6 @@ static jint mods2JavaMods(NSUInteger mods) [self focusChanged: NO]; } -- (void) keyDown: (NSEvent*) theEvent -{ - [self sendKeyEvent: theEvent eventType: (jshort)EVENT_KEY_PRESSED]; -} - -- (void) keyUp: (NSEvent*) theEvent -{ - [self sendKeyEvent: theEvent eventType: (jshort)EVENT_KEY_RELEASED]; -} - -#define kVK_Shift 0x38 -#define kVK_Option 0x3A -#define kVK_Control 0x3B -#define kVK_Command 0x37 - -- (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods -{ - if ( NO == modsDown[keyIdx] && 0 != ( mods & keyMask ) ) { - modsDown[keyIdx] = YES; - [self sendKeyEvent: (jshort)keyCode characters: NULL modifiers: mods|keyMask eventType: (jshort)EVENT_KEY_PRESSED]; - } else if ( YES == modsDown[keyIdx] && 0 == ( mods & keyMask ) ) { - modsDown[keyIdx] = NO; - [self sendKeyEvent: (jshort)keyCode characters: NULL modifiers: mods|keyMask eventType: (jshort)EVENT_KEY_RELEASED]; - } -} - -- (void) flagsChanged:(NSEvent *) theEvent -{ - NSUInteger mods = [theEvent modifierFlags]; - - // BOOL modsDown[4]; // shift, ctrl, alt/option, win/command - - [self handleFlagsChanged: NSShiftKeyMask keyIndex: 0 keyCode: kVK_Shift modifiers: mods]; - [self handleFlagsChanged: NSControlKeyMask keyIndex: 1 keyCode: kVK_Control modifiers: mods]; - [self handleFlagsChanged: NSAlternateKeyMask keyIndex: 2 keyCode: kVK_Option modifiers: mods]; - [self handleFlagsChanged: NSCommandKeyMask keyIndex: 3 keyCode: kVK_Command modifiers: mods]; -} - -- (void) mouseEntered: (NSEvent*) theEvent -{ - DBG_PRINT( "mouseEntered: confined %d, visible %d\n", mouseConfined, mouseVisible); - mouseInside = YES; - [self cursorHide: !mouseVisible enter: 1]; - if(NO == mouseConfined) { - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_ENTERED]; - } -} - -- (void) mouseExited: (NSEvent*) theEvent -{ - DBG_PRINT( "mouseExited: confined %d, visible %d\n", mouseConfined, mouseVisible); - if(NO == mouseConfined) { - mouseInside = NO; - [self cursorHide: NO enter: -1]; - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_EXITED]; - } else { - [self setMousePosition: lastInsideMousePosition]; - } -} - -- (void) mouseMoved: (NSEvent*) theEvent -{ - lastInsideMousePosition = [NSEvent mouseLocation]; - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; -} - -- (void) scrollWheel: (NSEvent*) theEvent -{ - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_WHEEL_MOVED]; -} - -- (void) mouseDown: (NSEvent*) theEvent -{ - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; -} - -- (void) mouseDragged: (NSEvent*) theEvent -{ - lastInsideMousePosition = [NSEvent mouseLocation]; - // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; -} - -- (void) mouseUp: (NSEvent*) theEvent -{ - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; -} - -- (void) rightMouseDown: (NSEvent*) theEvent -{ - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; -} - -- (void) rightMouseDragged: (NSEvent*) theEvent -{ - lastInsideMousePosition = [NSEvent mouseLocation]; - // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; -} - -- (void) rightMouseUp: (NSEvent*) theEvent -{ - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; -} - -- (void) otherMouseDown: (NSEvent*) theEvent -{ - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; -} - -- (void) otherMouseDragged: (NSEvent*) theEvent -{ - lastInsideMousePosition = [NSEvent mouseLocation]; - // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; -} - -- (void) otherMouseUp: (NSEvent*) theEvent -{ - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; -} - - (void)windowDidResize: (NSNotification*) notification { JNIEnv* env = NULL; @@ -1108,14 +1152,13 @@ static jint mods2JavaMods(NSUInteger mods) int shallBeDetached = 0; JavaVM *jvmHandle = NULL; - NSView* nsview = [self contentView]; - if( [nsview isKindOfClass:[NewtView class]] ) { - NewtView* view = (NewtView *) nsview; - javaWindowObject = [view getJavaWindowObject]; + NewtView* newtView = (NewtView *) [self contentView]; + if( [newtView isKindOfClass:[NewtView class]] ) { + javaWindowObject = [newtView getJavaWindowObject]; if (javaWindowObject != NULL) { - jvmHandle = [view getJVMHandle]; + jvmHandle = [newtView getJVMHandle]; if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], 1 /* asDaemon */, &shallBeDetached); + env = NewtCommon_GetJNIEnv(jvmHandle, [newtView getJVMVersion], 1 /* asDaemon */, &shallBeDetached); } } } @@ -1139,21 +1182,20 @@ static jint mods2JavaMods(NSUInteger mods) - (void)windowDidMove: (NSNotification*) notification { - NSView* nsview = [self contentView]; - if( ! [nsview isKindOfClass:[NewtView class]] ) { + NewtView* newtView = (NewtView *) [self contentView]; + if( ! [newtView isKindOfClass:[NewtView class]] ) { return; } - NewtView* view = (NewtView *) nsview; - jobject javaWindowObject = [view getJavaWindowObject]; + jobject javaWindowObject = [newtView getJavaWindowObject]; if (javaWindowObject == NULL) { DBG_PRINT("windowDidMove: null javaWindowObject\n"); return; } int shallBeDetached = 0; - JavaVM *jvmHandle = [view getJVMHandle]; + JavaVM *jvmHandle = [newtView getJVMHandle]; JNIEnv* env; if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], 1 /* asDaemon */, &shallBeDetached); + env = NewtCommon_GetJNIEnv(jvmHandle, [newtView getJVMVersion], 1 /* asDaemon */, &shallBeDetached); } else { env = NULL; } @@ -1186,32 +1228,31 @@ static jint mods2JavaMods(NSUInteger mods) jboolean closed = JNI_FALSE; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [self cursorHide: NO enter: -1]; - - NSView* nsview = [self contentView]; - if( ! [nsview isKindOfClass:[NewtView class]] ) { + NewtView* newtView = (NewtView *) [self contentView]; + if( ! [newtView isKindOfClass:[NewtView class]] ) { return NO; } - NewtView* view = (NewtView *) nsview; - if( false == [view getDestroyNotifySent] ) { - jobject javaWindowObject = [view getJavaWindowObject]; + [newtView cursorHide: NO enter: -1]; + + if( false == [newtView getDestroyNotifySent] ) { + jobject javaWindowObject = [newtView getJavaWindowObject]; DBG_PRINT( "*************** windowWillClose.0: %p\n", (void *)(intptr_t)javaWindowObject); if (javaWindowObject == NULL) { DBG_PRINT("windowWillClose: null javaWindowObject\n"); return NO; } int shallBeDetached = 0; - JavaVM *jvmHandle = [view getJVMHandle]; + JavaVM *jvmHandle = [newtView getJVMHandle]; JNIEnv* env = NULL; NS_DURING if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], 1 /* asDaemon */, &shallBeDetached); + env = NewtCommon_GetJNIEnv(jvmHandle, [newtView getJVMVersion], 1 /* asDaemon */, &shallBeDetached); } NS_HANDLER jvmHandle = NULL; env = NULL; - [view setJVMHandle: NULL]; + [newtView setJVMHandle: NULL]; DBG_PRINT("windowWillClose: JVMHandler Exception\n"); NS_ENDHANDLER DBG_PRINT("windowWillClose: JVM %p JNIEnv %p\n", jvmHandle, env); @@ -1219,11 +1260,11 @@ NS_ENDHANDLER return NO; } - [view setDestroyNotifySent: true]; // earmark assumption of being closed + [newtView setDestroyNotifySent: true]; // earmark assumption of being closed closed = (*env)->CallBooleanMethod(env, javaWindowObject, windowDestroyNotifyID, force ? JNI_TRUE : JNI_FALSE); if(!force && !closed) { // not closed on java side, not force -> clear flag - [view setDestroyNotifySent: false]; + [newtView setDestroyNotifySent: false]; } /* if (shallBeDetached) { |