aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-12-31 08:14:21 +0100
committerSven Gothel <[email protected]>2013-12-31 08:14:21 +0100
commite7ffa68bce9bb707005be72530b207c732f62c31 (patch)
treedb1d2e73c89da355c8ff319febcf3c2cc2637a16
parente7032ae9ca4b754bd9737f86d9496211e9155db4 (diff)
Bug 934, Bug 935: NEWT: Add support for custom Application/Window and Pointer Icons
- Utilizing JOGL's PNG decoder for all icons, if available. - Application/window icons: - Providing default application/window icons in 16x16 and 32x32 size - NewtFactory.setWindowIcons(..) or property 'newt.window.icons' maybe used to override default icons. - Using icons at application/window instantiation - Display.PointerIcons: - NativeWindow Win32 WindowClass no more references a default cursor in favor of fine grained cursor control [in NEWT] - Display provides create/destroy methods, where display destruction also releases open PointerIcon references. - Window.setPointerIcon(..) sets custom PointerIcon - Implemented Platforms - X11 - Windows - OSX - Manual Test: TestGearsES2NEWT (Press 'c')
-rw-r--r--make/build-jogl.xml2
-rw-r--r--make/build-newt.xml12
-rw-r--r--make/resources/assets-test/jogamp-pointer-64x64.pngbin0 -> 2843 bytes
-rw-r--r--make/resources/assets/newt/data/jogamp-16x16.pngbin0 -> 549 bytes
-rw-r--r--make/resources/assets/newt/data/jogamp-32x32.pngbin0 -> 1020 bytes
-rw-r--r--make/resources/misc/jogamp-48x48.pngbin0 -> 1278 bytes
-rw-r--r--make/resources/misc/jogamp-64x64.pngbin0 -> 1833 bytes
-rwxr-xr-xmake/scripts/tests-win.bat4
-rwxr-xr-xmake/scripts/tests-x64-dbg.bat3
-rw-r--r--make/scripts/tests.sh5
-rw-r--r--src/nativewindow/native/win32/GDImisc.c2
-rw-r--r--src/newt/classes/com/jogamp/newt/Display.java50
-rw-r--r--src/newt/classes/com/jogamp/newt/NewtFactory.java33
-rw-r--r--src/newt/classes/com/jogamp/newt/Window.java15
-rw-r--r--src/newt/classes/com/jogamp/newt/opengl/GLWindow.java11
-rw-r--r--src/newt/classes/jogamp/newt/DisplayImpl.java68
-rw-r--r--src/newt/classes/jogamp/newt/WindowImpl.java22
-rw-r--r--src/newt/classes/jogamp/newt/driver/PNGIcon.java102
-rw-r--r--src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java51
-rw-r--r--src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java11
-rw-r--r--src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java139
-rw-r--r--src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java38
-rw-r--r--src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java56
-rw-r--r--src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java46
-rw-r--r--src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java51
-rw-r--r--src/newt/native/MacWindow.m73
-rw-r--r--src/newt/native/NewtMacWindow.h4
-rw-r--r--src/newt/native/NewtMacWindow.m41
-rw-r--r--src/newt/native/WindowsWindow.c115
-rw-r--r--src/newt/native/X11Display.c52
-rw-r--r--src/newt/native/X11Window.c35
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java29
32 files changed, 1027 insertions, 43 deletions
diff --git a/make/build-jogl.xml b/make/build-jogl.xml
index 28b738b10..4cdb93f4d 100644
--- a/make/build-jogl.xml
+++ b/make/build-jogl.xml
@@ -1833,7 +1833,7 @@
<fileset dir="${classes}"
includes="${java.part.util} ${java.part.util.glsl} ${java.part.openal}"
excludes="${java.part.util.awt} ${java.part.util.gldesktop} ${java.part.util.fixedfuncemu} ${java.part.util.graph}"/>
- <fileset dir="resources/assets" includes="jogl/util/**" />
+ <fileset dir="resources/assets" includes="jogl/util/data/**" />
</jar>
<jar manifest="${build.jogl}/manifest.mf" destfile="${jogl-util-graph.jar}" filesonly="true">
<fileset dir="${classes}"
diff --git a/make/build-newt.xml b/make/build-newt.xml
index 960c7b533..9bc2e0e83 100644
--- a/make/build-newt.xml
+++ b/make/build-newt.xml
@@ -103,7 +103,7 @@
value="com/jogamp/newt/* com/jogamp/newt/event/* com/jogamp/newt/util/* jogamp/newt/* jogamp/newt/event/* jogamp/newt/driver/*"/>
<property name="java.part.opengl"
- value="com/jogamp/newt/opengl/**"/>
+ value="com/jogamp/newt/opengl/** jogamp/newt/driver/opengl/**"/>
<property name="java.part.driver.awt"
value="jogamp/newt/driver/awt/**"/>
@@ -277,12 +277,14 @@
<linkerarg value="-L/usr/local/lib"/>
<syslibset libs="X11"/>
<syslibset libs="Xrandr"/>
+ <syslibset libs="Xcursor"/>
</linker>
<linker id="linker.cfg.freebsd.amd64.newt.x11" extends="linker.cfg.freebsd.amd64">
<linkerarg value="-L/usr/local/lib"/>
<syslibset libs="X11"/>
<syslibset libs="Xrandr"/>
+ <syslibset libs="Xcursor"/>
</linker>
<linker id="linker.cfg.linux.newt.bcm_egl" extends="linker.cfg.linux">
@@ -302,6 +304,7 @@
<linker id="linker.cfg.linux.newt.x11" extends="linker.cfg.linux">
<syslibset libs="X11"/>
<syslibset libs="Xrandr"/>
+ <syslibset libs="Xcursor"/>
<!--syslibset libs="xcb" /-->
<!--syslibset libs="X11-xcb" /-->
</linker>
@@ -309,6 +312,7 @@
<linker id="linker.cfg.linux.x86.newt.x11" extends="linker.cfg.linux.x86">
<syslibset libs="X11"/>
<syslibset libs="Xrandr"/>
+ <syslibset libs="Xcursor"/>
<!--syslibset libs="xcb" /-->
<!--syslibset libs="X11-xcb" /-->
</linker>
@@ -316,6 +320,7 @@
<linker id="linker.cfg.linux.amd64.newt.x11" extends="linker.cfg.linux.amd64">
<syslibset libs="X11"/>
<syslibset libs="Xrandr"/>
+ <syslibset libs="Xcursor"/>
<!--syslibset libs="xcb" /-->
<!--syslibset libs="X11-xcb" /-->
</linker>
@@ -323,6 +328,7 @@
<linker id="linker.cfg.linux.armv6.newt.x11" extends="linker.cfg.linux.armv6">
<syslibset dir="${env.TARGET_PLATFORM_ROOT}/usr/lib" libs="X11" />
<syslibset dir="${env.TARGET_PLATFORM_ROOT}/usr/lib" libs="Xrandr" />
+ <syslibset dir="${env.TARGET_PLATFORM_ROOT}/usr/lib" libs="Xcursor" />
</linker>
<linker id="linker.cfg.android.newt" extends="linker.cfg.android">
@@ -332,18 +338,21 @@
<linker id="linker.cfg.solaris.newt.x11" extends="linker.cfg.solaris">
<syslibset libs="X11"/>
<syslibset libs="Xrandr"/>
+ <syslibset libs="Xcursor"/>
</linker>
<linker id="linker.cfg.solaris.sparcv9.newt.x11" extends="linker.cfg.solaris.sparcv9">
<linkerarg value="-L/usr/lib/sparcv9"/>
<syslibset libs="X11"/>
<syslibset libs="Xrandr"/>
+ <syslibset libs="Xcursor"/>
</linker>
<linker id="linker.cfg.solaris.amd64.newt.x11" extends="linker.cfg.solaris.amd64">
<linkerarg value="-L/usr/lib/amd64"/>
<syslibset libs="X11"/>
<syslibset libs="Xrandr"/>
+ <syslibset libs="Xcursor"/>
</linker>
<linker id="linker.cfg.win32.mingw.newt" extends="linker.cfg.win32.mingw">
@@ -798,6 +807,7 @@
<jar manifest="${build.newt}/manifest.mf" destfile="${newt-core.jar}" filesonly="true">
<fileset dir="${classes}"
includes="${java.part.core}"/>
+ <fileset dir="resources/assets" includes="newt/data/**" />
</jar>
<jar manifest="${build.newt}/manifest.mf" destfile="${newt-event.jar}" filesonly="true">
<fileset dir="${classes}">
diff --git a/make/resources/assets-test/jogamp-pointer-64x64.png b/make/resources/assets-test/jogamp-pointer-64x64.png
new file mode 100644
index 000000000..a965dcab1
--- /dev/null
+++ b/make/resources/assets-test/jogamp-pointer-64x64.png
Binary files differ
diff --git a/make/resources/assets/newt/data/jogamp-16x16.png b/make/resources/assets/newt/data/jogamp-16x16.png
new file mode 100644
index 000000000..02df8997f
--- /dev/null
+++ b/make/resources/assets/newt/data/jogamp-16x16.png
Binary files differ
diff --git a/make/resources/assets/newt/data/jogamp-32x32.png b/make/resources/assets/newt/data/jogamp-32x32.png
new file mode 100644
index 000000000..ab21c6e1b
--- /dev/null
+++ b/make/resources/assets/newt/data/jogamp-32x32.png
Binary files differ
diff --git a/make/resources/misc/jogamp-48x48.png b/make/resources/misc/jogamp-48x48.png
new file mode 100644
index 000000000..216f8c0b7
--- /dev/null
+++ b/make/resources/misc/jogamp-48x48.png
Binary files differ
diff --git a/make/resources/misc/jogamp-64x64.png b/make/resources/misc/jogamp-64x64.png
new file mode 100644
index 000000000..9936616ca
--- /dev/null
+++ b/make/resources/misc/jogamp-64x64.png
Binary files differ
diff --git a/make/scripts/tests-win.bat b/make/scripts/tests-win.bat
index f5417bf7a..d95b0025f 100755
--- a/make/scripts/tests-win.bat
+++ b/make/scripts/tests-win.bat
@@ -6,7 +6,7 @@ REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestMainVersion
REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNewtAWTWrapper %*
REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNEWT -time 30000
REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es1.newt.TestGearsES1NEWT %*
-REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT %*
+scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT %*
REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT -vsync -time 4000 -x 10 -y 10 -width 100 -height 100 -screen 0
REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT -vsync -time 40000 -width 100 -height 100 -screen 0 %*
REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsAWT -time 5000
@@ -39,7 +39,7 @@ REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.tile.TestTiledPrintin
REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLCapabilities01NEWT %*
REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestShutdownCompleteNEWT %*
-scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestShutdownCompleteAWT %*
+REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestShutdownCompleteAWT %*
REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.offscreen.TestOffscreen01GLPBufferNEWT -time 5000
REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT %*
diff --git a/make/scripts/tests-x64-dbg.bat b/make/scripts/tests-x64-dbg.bat
index 6e8407f3e..ce2df922c 100755
--- a/make/scripts/tests-x64-dbg.bat
+++ b/make/scripts/tests-x64-dbg.bat
@@ -55,9 +55,10 @@ REM set D_ARGS="-Djogl.debug.GLCanvas" "-Djogl.debug.Animator" "-Djogl.debug.GLC
REM set D_ARGS="-Djogl.debug.GLCanvas" "-Djogl.debug.GLJPanel" "-Djogl.debug.TileRenderer" "-Djogl.debug.TileRenderer.PNG"
REM set D_ARGS="-Djogl.debug.GLCanvas" "-Djogl.debug.GLJPanel" "-Djogl.debug.TileRenderer"
REM set D_ARGS="-Djogl.gljpanel.noverticalflip"
+set D_ARGS="-Dnewt.debug=all"
REM set D_ARGS="-Dnewt.debug.Window"
REM set D_ARGS="-Dnewt.debug.Window.KeyEvent"
-set D_ARGS="-Dnewt.debug.Window" "-Dnewt.debug.Window.KeyEvent" "-Dnewt.debug.EDT"
+REM set D_ARGS="-Dnewt.debug.Window" "-Dnewt.debug.Window.KeyEvent" "-Dnewt.debug.EDT"
REM set D_ARGS="-Dnewt.debug.Window.MouseEvent"
REM set D_ARGS="-Dnewt.debug.Window.MouseEvent" "-Dnewt.debug.Window.KeyEvent"
REM set D_ARGS="-Dnewt.debug.Window" "-Dnewt.debug.Display"
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index 6cb1966d1..4c084d705 100644
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -312,7 +312,7 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestMainVersionGLWindowNEWT $*
#testawt com.jogamp.opengl.test.junit.jogl.acore.TestMainVersionGLCanvasAWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile00NEWT $*
-testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $*
#
# demos (any TK, more user driven tests)
@@ -325,7 +325,7 @@ testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelsAWT $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasAWT $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestLandscapeES2NewtCanvasAWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
+testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestLandscapeES2NEWT $*
#testawtswt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasSWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestElektronenMultipliziererNEWT $*
@@ -636,6 +636,7 @@ testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGTextureFromFileNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGImage00NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGImage01NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.ToolPNG2CSource $*
#testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGTextureFromFileAWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGTextureFromFileNEWT $*
#testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestGLReadBufferUtilTextureIOWrite01AWT $*
diff --git a/src/nativewindow/native/win32/GDImisc.c b/src/nativewindow/native/win32/GDImisc.c
index b55988c11..25b98acf3 100644
--- a/src/nativewindow/native/win32/GDImisc.c
+++ b/src/nativewindow/native/win32/GDImisc.c
@@ -263,7 +263,7 @@ Java_jogamp_nativewindow_windows_GDIUtil_CreateWindowClass0
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
- wc.hCursor = LoadCursor( NULL, IDC_ARROW);
+ wc.hCursor = NULL;
wc.hbrBackground = NULL; // no background paint - GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = clazzName;
diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java
index 4469189a8..ee6dfd080 100644
--- a/src/newt/classes/com/jogamp/newt/Display.java
+++ b/src/newt/classes/com/jogamp/newt/Display.java
@@ -28,15 +28,21 @@
package com.jogamp.newt;
-import com.jogamp.newt.util.EDTUtil;
-import jogamp.newt.Debug;
-
+import java.io.IOException;
import java.lang.ref.WeakReference;
-import java.util.*;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
+import jogamp.newt.Debug;
+
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.newt.util.EDTUtil;
+
public abstract class Display {
public static final boolean DEBUG = Debug.debug("Display");
@@ -56,6 +62,42 @@ 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)}.
+ * </p>
+ * <p>
+ * PointerIcons can be used via {@link Window#setPointerIcon(PointerIcon)}.
+ * </p>
+ */
+ public static interface PointerIcon { }
+
+ /**
+ * Returns the created {@link PointerIcon} or <code>null</code> if not implemented on platform.
+ *
+ * @param pngResource PNG resource
+ * @param hotX pointer hotspot x-coord, origin is upper-left corner
+ * @param hotY pointer hotspot y-coord, origin is upper-left corner
+ * @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);
+
+ /**
* Manual trigger the native creation, if it is not done yet.<br>
* This is useful to be able to request the {@link javax.media.nativewindow.AbstractGraphicsDevice}, via
* {@link #getGraphicsDevice()}.<br>
diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java
index 157e2bb3c..92339ea73 100644
--- a/src/newt/classes/com/jogamp/newt/NewtFactory.java
+++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java
@@ -36,6 +36,7 @@ package com.jogamp.newt;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.Arrays;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
import javax.media.nativewindow.AbstractGraphicsDevice;
@@ -44,6 +45,8 @@ import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.NativeWindowFactory;
+import com.jogamp.common.util.IOUtil;
+
import jogamp.newt.Debug;
import jogamp.newt.DisplayImpl;
import jogamp.newt.ScreenImpl;
@@ -54,15 +57,45 @@ public class NewtFactory {
public static final String DRIVER_DEFAULT_ROOT_PACKAGE = "jogamp.newt.driver";
+ private static IOUtil.ClassResources defaultWindowIcons;
+
static {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
NativeWindowFactory.initSingleton(); // last resort ..
+ {
+ final String[] paths = Debug.getProperty("newt.window.icons", true, "newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png").split("\\s");
+ if( paths.length < 2 ) {
+ throw new IllegalArgumentException("Property 'newt.window.icons' did not specify at least two PNG icons, but "+Arrays.toString(paths));
+ }
+ final Class<?> clazz = NewtFactory.class;
+ defaultWindowIcons = new IOUtil.ClassResources(clazz, paths);
+ }
return null;
} } );
}
+ /**
+ * Returns the application window icon resources to be used.
+ * <p>
+ * Property <code>newt.window.icons</code> may define a list of PNG icons separated by a whitespace character.
+ * Shall reference at least two PNG icons, from lower (16x16) to higher (>= 32x32) resolution.
+ * </p>
+ * <p>
+ * Users may also specify application window icons using {@link #setWindowIcons(com.jogamp.common.util.IOUtil.ClassResources)}.
+ * </p>
+ */
+ public static IOUtil.ClassResources getWindowIcons() { return defaultWindowIcons; }
+
+ /**
+ * Allow user to set custom window icons, only applicable at application start before creating any NEWT instance.
+ * <p>
+ * Shall reference at least two PNG icons, from lower (16x16) to higher (>= 32x32) resolution.
+ * </p>
+ */
+ public static void setWindowIcons(IOUtil.ClassResources cres) { defaultWindowIcons = cres; }
+
public static Class<?> getCustomClass(String packageName, String classBaseName) {
Class<?> clazz = null;
if(packageName!=null && classBaseName!=null) {
diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java
index 5c3bb7889..8e73ba1d2 100644
--- a/src/newt/classes/com/jogamp/newt/Window.java
+++ b/src/newt/classes/com/jogamp/newt/Window.java
@@ -30,6 +30,7 @@ package com.jogamp.newt;
import java.util.List;
+import com.jogamp.newt.Display.PointerIcon;
import com.jogamp.newt.event.GestureHandler;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.event.WindowListener;
@@ -307,6 +308,20 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
*/
void setPointerVisible(boolean pointerVisible);
+ /**
+ * Returns the current {@link PointerIcon}, which maybe <code>null</code> for the default.
+ * @see #setPointerIcon(PointerIcon)
+ */
+ PointerIcon getPointerIcon();
+
+ /**
+ * @param pi Valid {@link PointerIcon} reference or <code>null</code> to reset the pointer icon to default.
+ *
+ * @see PointerIcon
+ * @see Display#createPointerIcon(com.jogamp.common.util.IOUtil.ClassResources, int, int)
+ */
+ void setPointerIcon(final PointerIcon pi);
+
/** @see #confinePointer(boolean) */
boolean isPointerConfined();
diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
index 208602aa1..ca8ab6733 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
@@ -77,6 +77,7 @@ import com.jogamp.newt.MonitorDevice;
import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.Screen;
import com.jogamp.newt.Window;
+import com.jogamp.newt.Display.PointerIcon;
import com.jogamp.newt.event.GestureHandler;
import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.MouseListener;
@@ -268,6 +269,16 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
+ public final PointerIcon getPointerIcon() {
+ return window.getPointerIcon();
+ }
+
+ @Override
+ public final void setPointerIcon(final PointerIcon pi) {
+ window.setPointerIcon(pi);
+ }
+
+ @Override
public final boolean isPointerConfined() {
return window.isPointerConfined();
}
diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java
index 0c29d772a..4e9b8b441 100644
--- a/src/newt/classes/jogamp/newt/DisplayImpl.java
+++ b/src/newt/classes/jogamp/newt/DisplayImpl.java
@@ -34,14 +34,18 @@
package jogamp.newt;
+import com.jogamp.common.util.IOUtil;
import com.jogamp.newt.Display;
import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.event.NEWTEvent;
import com.jogamp.newt.event.NEWTEventConsumer;
import jogamp.newt.event.NEWTEventTask;
+
import com.jogamp.newt.util.EDTUtil;
+import java.io.IOException;
+import java.net.MalformedURLException;
import java.util.ArrayList;
import javax.media.nativewindow.AbstractGraphicsDevice;
@@ -62,6 +66,67 @@ public abstract class DisplayImpl extends Display {
});
}
+ public static class PointerIconImpl implements PointerIcon {
+ public final long handle;
+ public PointerIconImpl(long handle) {
+ this.handle=handle;
+ }
+ }
+
+ 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>();
+
+ /** 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);
+ }
+ }
+ pointerIconList.clear();
+ }
+ }
+
+ @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;
+ }
+
+ @Override
+ public final void destroyPointerIcon(final PointerIcon pi) {
+ delPointerIconFromList(pi);
+ runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() {
+ @Override
+ public Object run(long dpy) {
+ try {
+ destroyPointerIconImpl(dpy, pi);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+ });
+ }
+ /** Executed from EDT! */
+ protected void destroyPointerIconImpl(final long displayHandle, final PointerIcon pi) { }
+
/** Ensure static init has been run. */
/* pp */static void initSingleton() { }
@@ -283,6 +348,7 @@ public abstract class DisplayImpl extends Display {
@Override
public void run() {
if ( null != f_aDevice ) {
+ f_dpy.destroyAllPointerIconFromList(f_aDevice.getHandle());
f_dpy.closeNativeImpl(f_aDevice);
}
}
@@ -453,7 +519,7 @@ public abstract class DisplayImpl extends Display {
/** Dispatch native Toolkit messageges */
protected abstract void dispatchMessagesNative();
- private Object eventsLock = new Object();
+ private final Object eventsLock = new Object();
private ArrayList<NEWTEventTask> events = new ArrayList<NEWTEventTask>();
private volatile boolean haveEvents = false;
diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java
index 7a7e69e48..d078caa3b 100644
--- a/src/newt/classes/jogamp/newt/WindowImpl.java
+++ b/src/newt/classes/jogamp/newt/WindowImpl.java
@@ -42,6 +42,7 @@ import java.lang.reflect.Method;
import com.jogamp.common.util.ArrayHashSet;
import com.jogamp.common.util.IntBitfield;
import com.jogamp.common.util.ReflectionUtil;
+import com.jogamp.newt.Display.PointerIcon;
import com.jogamp.newt.MonitorDevice;
import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.Display;
@@ -83,6 +84,7 @@ 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
{
@@ -170,6 +172,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
private String title = "Newt Window";
private boolean undecorated = false;
private boolean alwaysOnTop = false;
+ private PointerIcon pointerIcon = null;
private boolean pointerVisible = true;
private boolean pointerConfined = false;
private LifecycleHook lifecycleHook = null;
@@ -436,6 +439,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
createNativeImpl();
screen.addMonitorModeListener(monitorModeListenerImpl);
setTitleImpl(title);
+ if( null != pointerIcon ) {
+ setPointerIcon(pointerIcon);
+ }
setPointerVisibleImpl(pointerVisible);
confinePointerImpl(pointerConfined);
setKeyboardVisible(keyboardVisible);
@@ -725,6 +731,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
protected boolean setPointerVisibleImpl(boolean pointerVisible) { return false; }
protected boolean confinePointerImpl(boolean confine) { return false; }
protected void warpPointerImpl(int x, int y) { }
+ protected void setPointerIconImpl(final PointerIconImpl pi) { }
//----------------------------------------------------------------------
// NativeSurface
@@ -1675,6 +1682,21 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
}
+
+ @Override
+ public final PointerIcon getPointerIcon() { return pointerIcon; }
+
+ @Override
+ public final void setPointerIcon(final PointerIcon pi) {
+ if( this.pointerIcon != pi ) {
+ setPointerIcon(pointerIcon);
+ if( isNativeValid() ) {
+ setPointerIconImpl((PointerIconImpl)pi);
+ }
+ this.pointerIcon = pi;
+ }
+ }
+
@Override
public final boolean isPointerConfined() {
return pointerConfined;
diff --git a/src/newt/classes/jogamp/newt/driver/PNGIcon.java b/src/newt/classes/jogamp/newt/driver/PNGIcon.java
new file mode 100644
index 000000000..c958f6ec2
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/driver/PNGIcon.java
@@ -0,0 +1,102 @@
+/**
+ * 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.driver;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.nio.ByteBuffer;
+
+import jogamp.newt.Debug;
+
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.ReflectionUtil;
+
+public class PNGIcon {
+ private static final String err0 = "PNG decoder not implemented.";
+
+ private static final boolean avail;
+
+ static {
+ Debug.initSingleton();
+
+ final ClassLoader cl = PNGIcon.class.getClassLoader();
+ avail = ReflectionUtil.isClassAvailable("jogamp.newt.driver.opengl.JoglUtilPNGIcon", cl) &&
+ ReflectionUtil.isClassAvailable("com.jogamp.opengl.util.texture.spi.PNGImage", cl);
+ }
+
+ /** Returns true if PNG decoder is available. */
+ public static boolean isAvailable() {
+ return avail;
+ }
+
+ /**
+ * Implemented for X11.
+ * @param resources
+ * @param data_size
+ * @param elem_bytesize
+ *
+ * @return BGRA8888 bytes with origin at upper-left corner where component B is located on the lowest 8-bit and component A is located on the highest 8-bit.
+ *
+ * @throws UnsupportedOperationException if not implemented
+ * @throws InterruptedException
+ * @throws IOException
+ * @throws MalformedURLException
+ */
+ public static ByteBuffer arrayToX11BGRAImages(IOUtil.ClassResources resources, int[] data_size, int[] elem_bytesize) throws UnsupportedOperationException, InterruptedException, IOException, MalformedURLException {
+ if( avail ) {
+ return jogamp.newt.driver.opengl.JoglUtilPNGIcon.arrayToX11BGRAImages(resources, data_size, elem_bytesize);
+ }
+ throw new UnsupportedOperationException(err0);
+ }
+
+ /**
+ * Implemented for Windows.
+ * @param resources
+ * @param toBGRA if true, arranges stores in BGRA888 order, otherwise RGBA888
+ * @param width
+ * @param height
+ * @param data_size
+ * @param elem_bytesize
+ * @param resourcesIdx
+ * @return pixels with origin at upper-left corner.
+ * If storing RGBA8888, component R is located on the lowest 8-bit.
+ * If storing BGRA8888, component B is located on the lowest 8-bit.
+ * Component A is located on the highest 8-bit.
+ *
+ * @throws UnsupportedOperationException if not implemented
+ * @throws InterruptedException
+ * @throws IOException
+ * @throws MalformedURLException
+ */
+ public static ByteBuffer singleToRGBAImage(IOUtil.ClassResources resources, int resourceIdx, boolean toBGRA, int[] width, int[] height, int[] data_size, int[] elem_bytesize) throws UnsupportedOperationException, InterruptedException, IOException, MalformedURLException {
+ if( avail ) {
+ return jogamp.newt.driver.opengl.JoglUtilPNGIcon.singleToRGBAImage(resources, resourceIdx, toBGRA, width, height, data_size, elem_bytesize);
+ }
+ throw new UnsupportedOperationException(err0);
+ }
+}
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java
index c44685dc8..86c8464a8 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java
@@ -34,15 +34,26 @@
package jogamp.newt.driver.macosx;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
+import com.jogamp.common.util.IOUtil;
import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice;
+import com.jogamp.newt.NewtFactory;
import jogamp.newt.DisplayImpl;
import jogamp.newt.NEWTJNILibLoader;
+import jogamp.newt.driver.PNGIcon;
public class DisplayDriver extends DisplayImpl {
+ private static final int defaultIconWidth, defaultIconHeight;
+ private static final Buffer defaultIconData;
+
static {
NEWTJNILibLoader.loadNEWT();
@@ -52,6 +63,25 @@ public class DisplayDriver extends DisplayImpl {
if(!WindowDriver.initIDs0()) {
throw new NativeWindowException("Failed to initialize jmethodIDs");
}
+ {
+ final int[] width = { 0 }, height = { 0 }, data_size = { 0 }, elem_bytesize = { 0 };
+ Buffer data=null;
+ if( PNGIcon.isAvailable() ) {
+ try {
+ final IOUtil.ClassResources iconRes = NewtFactory.getWindowIcons();
+ data = PNGIcon.singleToRGBAImage(iconRes, iconRes.resourceCount()-1, false /* toBGRA */, width, height, data_size, elem_bytesize);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ defaultIconWidth = width[0];
+ defaultIconHeight = height[0];
+ defaultIconData = data;
+ if( null != defaultIconData ) {
+ DisplayDriver.setAppIcon0(defaultIconData, defaultIconWidth, defaultIconHeight);
+ }
+ }
+
if(DEBUG) {
System.err.println("MacDisplay.init App and IDs OK "+Thread.currentThread().getName());
}
@@ -79,6 +109,23 @@ public class DisplayDriver extends DisplayImpl {
aDevice.close();
}
+ @Override
+ protected PointerIcon 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 }, elem_bytesize = { 0 };
+ if( null != pngResource && 0 < pngResource.resourceCount() ) {
+ final ByteBuffer data = PNGIcon.singleToRGBAImage(pngResource, 0, true /* toBGRA */, width, height, data_size, elem_bytesize);
+ return new PointerIconImpl( 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);
+ }
+
public static void runNSApplication() {
runNSApplication0();
}
@@ -89,5 +136,9 @@ public class DisplayDriver extends DisplayImpl {
private static native boolean initNSApplication0();
private static native void runNSApplication0();
private static native void stopNSApplication0();
+ /* pp */ static native void setAppIcon0(Object iconData, int iconWidth, int iconHeight);
+ private static native long createPointerIcon0(Object iconData, int iconWidth, int iconHeight, int hotX, int hotY);
+ private static native long destroyPointerIcon0(long handle);
+
}
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
index 641d7437c..a55fa915a 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
@@ -46,6 +46,7 @@ import javax.media.nativewindow.util.PointImmutable;
import jogamp.nativewindow.macosx.OSXUtil;
import jogamp.newt.WindowImpl;
+import jogamp.newt.DisplayImpl.PointerIconImpl;
import jogamp.newt.driver.DriverClearFocus;
import jogamp.newt.driver.DriverUpdatePosition;
@@ -392,6 +393,15 @@ 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);
+ } } );
+ }
+
+ @Override
protected boolean setPointerVisibleImpl(final boolean pointerVisible) {
if( !isOffscreenInstance ) {
return setPointerVisible0(getWindowHandle(), hasFocus(), pointerVisible);
@@ -568,6 +578,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
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);
// Window styles
private static final int NSBorderlessWindowMask = 0;
diff --git a/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java b/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java
new file mode 100644
index 000000000..ea9029006
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java
@@ -0,0 +1,139 @@
+/**
+ * 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.driver.opengl;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URLConnection;
+import java.nio.ByteBuffer;
+
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.opengl.util.texture.spi.PNGImage;
+
+public class JoglUtilPNGIcon {
+
+ public static ByteBuffer arrayToX11BGRAImages(IOUtil.ClassResources resources, int[] data_size, int[] elem_bytesize) throws UnsupportedOperationException, InterruptedException, IOException, MalformedURLException {
+ final PNGImage[] images = new PNGImage[resources.resourceCount()];
+ data_size[0] = 0;
+ for(int i=0; i<resources.resourceCount(); i++) {
+ final URLConnection urlConn = resources.resolve(i);
+ final PNGImage image = PNGImage.read(urlConn.getInputStream());
+ data_size[0] += 2 + image.getWidth() * image.getHeight();
+ images[i] = image;
+ }
+ final boolean is64Bit = Platform.is64Bit();
+ elem_bytesize[0] = is64Bit ? Buffers.SIZEOF_LONG : Buffers.SIZEOF_INT;
+ final ByteBuffer buffer = Buffers.newDirectByteBuffer( data_size[0] * elem_bytesize[0] );
+
+ for(int i=0; i<images.length; i++) {
+ final PNGImage image1 = images[i];
+ if( is64Bit ) {
+ buffer.putLong(image1.getWidth());
+ buffer.putLong(image1.getHeight());
+ } else {
+ buffer.putInt(image1.getWidth());
+ buffer.putInt(image1.getHeight());
+ }
+ final ByteBuffer bb = image1.getData();
+ final int bpp = image1.getBytesPerPixel();
+ final int stride = image1.getWidth() * bpp;
+ for(int y=0; y<image1.getHeight(); y++) {
+ int bbOff = image1.isGLOriented() ? ( image1.getHeight() - 1 - y ) * stride : y * stride;
+ for(int x=0; x<image1.getWidth(); x++) {
+ // Source: R G B A
+ // Dest: B G R A
+ long pixel;
+ pixel = ( 0xffL & bb.get(bbOff++) ) << 16; // R
+ pixel |= ( 0xffL & bb.get(bbOff++) ) << 8; // G
+ pixel |= ( 0xffL & bb.get(bbOff++) ); // B
+ if( 4 == bpp ) {
+ pixel |= ( 0xffL & bb.get(bbOff++) ) << 24;
+ } else {
+ pixel |= 0x00000000ff000000L;
+ }
+ if( is64Bit ) {
+ buffer.putLong(pixel);
+ } else {
+ buffer.putInt((int)pixel);
+ }
+ }
+ }
+ }
+ buffer.rewind();
+ return buffer;
+ }
+
+ public static ByteBuffer singleToRGBAImage(IOUtil.ClassResources resources, int resourceIdx, boolean toBGRA, int[] width, int[] height, int[] data_size, int[] elem_bytesize) throws UnsupportedOperationException, InterruptedException, IOException, MalformedURLException {
+ width[0] = 0;
+ height[0] = 0;
+ data_size[0] = 0;
+ final URLConnection urlConn = resources.resolve(resourceIdx);
+ final PNGImage image = PNGImage.read(urlConn.getInputStream());
+ width[0] = image.getWidth();
+ height[0] = image.getHeight();
+ data_size[0] = image.getWidth() * image.getHeight();
+
+ elem_bytesize[0] = 4; // BGRA
+ final ByteBuffer buffer = Buffers.newDirectByteBuffer( data_size[0] * elem_bytesize[0] );
+
+ final ByteBuffer bb = image.getData();
+ final int bpp = image.getBytesPerPixel();
+ final int stride = image.getWidth() * bpp;
+ for(int y=0; y<image.getHeight(); y++) {
+ int bbOff = image.isGLOriented() ? ( image.getHeight() - 1 - y ) * stride : y * stride;
+ for(int x=0; x<image.getWidth(); x++) {
+ // Source: R G B A
+ final byte r, g, b, a;
+ r = bb.get(bbOff++); // R
+ g = bb.get(bbOff++); // G
+ b = bb.get(bbOff++); // B
+ if( 4 == bpp ) {
+ a = bb.get(bbOff++); // A
+ } else {
+ a = (byte)0xff; // A
+ }
+ if( toBGRA ) {
+ // Dest: B G R A
+ buffer.put(b);
+ buffer.put(g);
+ buffer.put(r);
+ } else {
+ // Dest: R G B A
+ buffer.put(r);
+ buffer.put(g);
+ buffer.put(b);
+ }
+ buffer.put(a);
+ }
+ }
+ buffer.rewind();
+ return buffer;
+ }
+}
diff --git a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java
index c4cfd98b3..8d4d8972b 100644
--- a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java
@@ -34,13 +34,22 @@
package jogamp.newt.driver.windows;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+
import jogamp.nativewindow.windows.RegisteredClass;
import jogamp.nativewindow.windows.RegisteredClassFactory;
import jogamp.newt.DisplayImpl;
import jogamp.newt.NEWTJNILibLoader;
+import jogamp.newt.driver.PNGIcon;
+
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.util.IOUtil;
import com.jogamp.nativewindow.windows.WindowsGraphicsDevice;
public class DisplayDriver extends DisplayImpl {
@@ -92,9 +101,38 @@ public class DisplayDriver extends DisplayImpl {
return sharedClass.getName();
}
+ @Override
+ protected PointerIcon 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 }, elem_bytesize = { 0 };
+ if( null != pngResource && 0 < pngResource.resourceCount() ) {
+ final ByteBuffer data = PNGIcon.singleToRGBAImage(pngResource, 0, true /* toBGRA */, width, height, data_size, elem_bytesize);
+ return new PointerIconImpl( 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);
+ }
+
//----------------------------------------------------------------------
// Internals only
//
private static native void DispatchMessages0();
+
+ static long createBGRA8888Icon0(Buffer data, int width, int height, boolean isCursor, int hotX, int hotY) {
+ if( null == data ) {
+ throw new IllegalArgumentException("data buffer/size");
+ }
+ if( !Buffers.isDirect(data) ) {
+ throw new IllegalArgumentException("data buffer is not direct "+data);
+ }
+ return createBGRA8888Icon0(data, Buffers.getDirectBufferByteOffset(data), width, height, isCursor, hotX, hotY);
+ }
+ private static native long createBGRA8888Icon0(Object data, int data_offset, int width, int height, boolean isCursor, int hotX, int hotY);
+ private static native void destroyIcon0(long handle);
}
diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
index 6e8ac3efa..3239aab5b 100644
--- a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
@@ -34,9 +34,13 @@
package jogamp.newt.driver.windows;
+import java.nio.ByteBuffer;
+
import jogamp.nativewindow.windows.GDI;
import jogamp.nativewindow.windows.GDIUtil;
import jogamp.newt.WindowImpl;
+import jogamp.newt.DisplayImpl.PointerIconImpl;
+import jogamp.newt.driver.PNGIcon;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
import javax.media.nativewindow.GraphicsConfigurationFactory;
@@ -47,23 +51,46 @@ import javax.media.nativewindow.util.InsetsImmutable;
import javax.media.nativewindow.util.Point;
import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.IOUtil;
import com.jogamp.common.util.VersionNumber;
+import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseEvent.PointerType;
public class WindowDriver extends WindowImpl {
+ private static final long[] defaultIconHandles;
+
+ static {
+ DisplayDriver.initSingleton();
+ {
+ long[] _defaultIconHandle = { 0, 0 };
+ if( PNGIcon.isAvailable() ) {
+ try {
+ final int[] width = { 0 }, height = { 0 }, data_size = { 0 }, elem_bytesize = { 0 };
+ final IOUtil.ClassResources iconRes = NewtFactory.getWindowIcons();
+ {
+ final ByteBuffer icon_data_small = PNGIcon.singleToRGBAImage(iconRes, 0, true /* toBGRA */, width, height, data_size, elem_bytesize);
+ _defaultIconHandle[0] = DisplayDriver.createBGRA8888Icon0(icon_data_small, width[0], height[0], false, 0, 0);
+ }
+ {
+ final ByteBuffer icon_data_big = PNGIcon.singleToRGBAImage(iconRes, iconRes.resourceCount()-1, true /* toBGRA */, width, height, data_size, elem_bytesize);
+ _defaultIconHandle[1] = DisplayDriver.createBGRA8888Icon0(icon_data_big, width[0], height[0], false, 0, 0);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ defaultIconHandles = _defaultIconHandle;
+ }
+ }
private long hmon;
private long hdc;
private long hdc_old;
private long windowHandleClose;
- static {
- DisplayDriver.initSingleton();
- }
-
public WindowDriver() {
}
@@ -142,7 +169,8 @@ public class WindowDriver extends WindowImpl {
( FLAG_IS_ALWAYSONTOP | FLAG_IS_UNDECORATED ) ;
final long _windowHandle = CreateWindow0(DisplayDriver.getHInstance(), display.getWindowClassName(), display.getWindowClassName(),
winVer.getMajor(), winVer.getMinor(),
- getParentWindowHandle(), getX(), getY(), getWidth(), getHeight(), autoPosition(), flags);
+ getParentWindowHandle(), getX(), getY(), getWidth(), getHeight(), autoPosition(), flags,
+ defaultIconHandles[0], defaultIconHandles[1]);
if ( 0 == _windowHandle ) {
throw new NativeWindowException("Error creating window");
}
@@ -159,8 +187,8 @@ public class WindowDriver extends WindowImpl {
@Override
protected void closeNativeImpl() {
- if(windowHandleClose != 0) {
- if (hdc != 0) {
+ if( 0 != windowHandleClose ) {
+ if ( 0 != hdc ) {
try {
GDI.ReleaseDC(windowHandleClose, hdc);
} catch (Throwable t) {
@@ -177,10 +205,9 @@ public class WindowDriver extends WindowImpl {
Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t);
e.printStackTrace();
}
- } finally {
- windowHandleClose = 0;
}
}
+ windowHandleClose = 0;
hdc = 0;
hdc_old = 0;
}
@@ -224,6 +251,11 @@ public class WindowDriver extends WindowImpl {
}
@Override
+ protected void setPointerIconImpl(final PointerIconImpl pi) {
+ setPointerIcon0(getWindowHandle(), null != pi ? pi.handle : 0);
+ }
+
+ @Override
protected boolean setPointerVisibleImpl(final boolean pointerVisible) {
final boolean[] res = new boolean[] { false };
@@ -361,7 +393,8 @@ public class WindowDriver extends WindowImpl {
protected static native boolean initIDs0(long hInstance);
private native long CreateWindow0(long hInstance, String wndClassName, String wndName, int winMajor, int winMinor,
- long parentWindowHandle, int x, int y, int width, int height, boolean autoPosition, int flags);
+ long parentWindowHandle, int x, int y, int width, int height, boolean autoPosition, int flags,
+ long iconSmallHandle, long iconBigHandle);
private native long MonitorFromWindow0(long windowHandle);
private native void reconfigureWindow0(long parentWindowHandle, long windowHandle,
int x, int y, int width, int height, int flags);
@@ -371,4 +404,7 @@ public class WindowDriver extends WindowImpl {
private static native boolean setPointerVisible0(long windowHandle, boolean visible);
private static native boolean confinePointer0(long windowHandle, boolean grab, int l, int t, int r, int b);
private static native void warpPointer0(long windowHandle, int x, int y);
+ private static native ByteBuffer newDirectByteBuffer(long addr, long capacity);
+
+ private static native void setPointerIcon0(long windowHandle, long iconHandle);
}
diff --git a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java
index 504839797..8170c2e3d 100644
--- a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java
@@ -34,14 +34,22 @@
package jogamp.newt.driver.x11;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.util.IOUtil;
import com.jogamp.nativewindow.x11.X11GraphicsDevice;
import jogamp.nativewindow.x11.X11Util;
import jogamp.newt.DisplayImpl;
import jogamp.newt.NEWTJNILibLoader;
+import jogamp.newt.driver.PNGIcon;
public class DisplayDriver extends DisplayImpl {
@@ -120,6 +128,35 @@ public class DisplayDriver extends DisplayImpl {
/** Returns <code>null</code> if !{@link #isNativeValid()}, otherwise the Boolean value of {@link X11GraphicsDevice#isXineramaEnabled()}. */
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 {
+ if( PNGIcon.isAvailable() ) {
+ final int[] width = { 0 }, height = { 0 }, data_size = { 0 }, elem_bytesize = { 0 };
+ if( null != pngResource && 0 < pngResource.resourceCount() ) {
+ final ByteBuffer data = PNGIcon.singleToRGBAImage(pngResource, 0, false /* toBGRA */, width, height, data_size, elem_bytesize);
+ 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);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected final void destroyPointerIconImpl(final long displayHandle, final PointerIcon pi) {
+ destroyPointerIcon0(displayHandle, ((PointerIconImpl)pi).handle);
+ }
+
//----------------------------------------------------------------------
// Internals only
//
@@ -137,6 +174,15 @@ public class DisplayDriver extends DisplayImpl {
private native void DispatchMessages0(long display, long javaObjectAtom, long windowDeleteAtom /* , long kbdHandle */); // XKB disabled for now
+ static long createPointerIcon0(long display, Buffer data, int width, int height, int hotX, int hotY) {
+ if( !Buffers.isDirect(data) ) {
+ throw new IllegalArgumentException("data buffer is not direct "+data);
+ }
+ return createPointerIcon0(display, data, Buffers.getDirectBufferByteOffset(data), width, height, hotX, hotY);
+ }
+ private static native long createPointerIcon0(long display, Object data, int data_offset, int width, int height, int hotX, int hotY);
+ static native void destroyPointerIcon0(long display, long handle);
+
/** X11 Window delete atom marker used on EDT */
private long windowDeleteAtom;
diff --git a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java
index f2a27b0c9..0ea2c5358 100644
--- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java
@@ -34,11 +34,16 @@
package jogamp.newt.driver.x11;
+import java.nio.Buffer;
+
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.WindowImpl;
+import jogamp.newt.driver.PNGIcon;
+
import javax.media.nativewindow.*;
import javax.media.nativewindow.VisualIDHolder.VIDType;
import javax.media.nativewindow.util.Insets;
@@ -47,6 +52,7 @@ import javax.media.nativewindow.util.Point;
import com.jogamp.nativewindow.x11.X11GraphicsDevice;
import com.jogamp.nativewindow.x11.X11GraphicsScreen;
+import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.MouseEvent;
@@ -58,8 +64,29 @@ public class WindowDriver extends WindowImpl {
private static final int X11_WHEEL_TWO_UP_BUTTON = 6;
private static final int X11_WHEEL_TWO_DOWN_BUTTON = 7;
+ private static final int defaultIconDataSize;
+ private static final Buffer defaultIconData;
+
static {
ScreenDriver.initSingleton();
+
+ int _icon_data_size=0, _icon_elem_bytesize=0;
+ Buffer _icon_data=null;
+ if( PNGIcon.isAvailable() ) {
+ try {
+ final int[] data_size = { 0 }, elem_bytesize = { 0 };
+ _icon_data = PNGIcon.arrayToX11BGRAImages(NewtFactory.getWindowIcons(), data_size, elem_bytesize);
+ _icon_data_size = data_size[0];
+ _icon_elem_bytesize = elem_bytesize[0];
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ defaultIconDataSize = _icon_data_size;
+ defaultIconData = _icon_data;
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("Def. Icon: data_size "+defaultIconDataSize+" * elem_size "+_icon_elem_bytesize+" = data "+defaultIconData);
+ }
}
public WindowDriver() {
@@ -100,7 +127,8 @@ public class WindowDriver extends WindowImpl {
setWindowHandle(CreateWindow0(getParentWindowHandle(),
edtDevice.getHandle(), screen.getIndex(), visualID,
display.getJavaObjectAtom(), display.getWindowDeleteAtom(),
- getX(), getY(), getWidth(), getHeight(), autoPosition(), flags));
+ getX(), getY(), getWidth(), getHeight(), autoPosition(), flags,
+ defaultIconDataSize, defaultIconData));
} finally {
edtDevice.unlock();
}
@@ -246,6 +274,21 @@ public class WindowDriver extends WindowImpl {
}
@Override
+ protected void setPointerIconImpl(final PointerIconImpl pi) {
+ runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() {
+ @Override
+ public Object run(long dpy) {
+ try {
+ setPointerIcon0(dpy, getWindowHandle(), null != pi ? pi.handle : 0);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+ });
+ }
+
+ @Override
protected boolean setPointerVisibleImpl(final boolean pointerVisible) {
return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Boolean>() {
@Override
@@ -381,13 +424,17 @@ public class WindowDriver extends WindowImpl {
private native long CreateWindow0(long parentWindowHandle, long display, int screen_index,
int visualID, long javaObjectAtom, long windowDeleteAtom,
- int x, int y, int width, int height, boolean autoPosition, int flags);
+ int x, int y, int width, int height, boolean autoPosition, int flags,
+ int iconDataSize, Object iconData);
private native void CloseWindow0(long display, long windowHandle, long javaObjectAtom, long windowDeleteAtom /*, long kbdHandle*/ ); // XKB disabled for now
private native void reconfigureWindow0(long display, int screen_index, long parentWindowHandle, long windowHandle,
long windowDeleteAtom, int x, int y, int width, int height, int flags);
private native void requestFocus0(long display, long windowHandle, boolean force);
private static native void setTitle0(long display, long windowHandle, String title);
+
+ private static native void setPointerIcon0(long display, long windowHandle, long handle);
+
private static native long getParentWindow0(long display, long windowHandle);
private static native boolean setPointerVisible0(long display, long windowHandle, boolean visible);
private static native boolean confinePointer0(long display, long windowHandle, boolean grab);
diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m
index 30d3458ad..16e9814ef 100644
--- a/src/newt/native/MacWindow.m
+++ b/src/newt/native/MacWindow.m
@@ -285,6 +285,76 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_stopNSApplic
[pool release];
}
+static NSImage * createNSImageFromData(JNIEnv *env, jobject jiconData, jint jiconWidth, jint jiconHeight) {
+ if( NULL != jiconData ) {
+ unsigned char * iconData = (unsigned char *) (*env)->GetDirectBufferAddress(env, jiconData);
+ NSInteger iconWidth = (NSInteger) jiconWidth;
+ NSInteger iconHeight = (NSInteger) jiconHeight;
+ const NSInteger bpc = 8 /* bits per component */, spp=4 /* RGBA */, bpp = bpc * spp;
+ const NSBitmapFormat bfmt = NSAlphaNonpremultipliedBitmapFormat;
+ const BOOL hasAlpha = YES;
+
+ NSBitmapImageRep* bir = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: &iconData
+ pixelsWide: iconWidth
+ pixelsHigh: iconHeight
+ bitsPerSample: bpc
+ samplesPerPixel: spp
+ hasAlpha: hasAlpha
+ isPlanar: NO
+ colorSpaceName: NSCalibratedRGBColorSpace
+ bitmapFormat: bfmt
+ bytesPerRow: iconWidth*4
+ bitsPerPixel: bpp];
+ [bir autorelease];
+ NSImage* nsImage = [[NSImage alloc] initWithCGImage: [bir CGImage] size:NSZeroSize];
+ return nsImage;
+ }
+ return NULL;
+}
+
+/*
+ * Class: jogamp_newt_driver_macosx_DisplayDriver
+ * Method: setAppIcon0
+ */
+JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_setAppIcon0
+ (JNIEnv *env, jobject unused, jobject jiconData, jint jiconWidth, jint jiconHeight)
+{
+ NSImage * nsImage = createNSImageFromData(env, jiconData, jiconWidth, jiconHeight);
+ if( NULL != nsImage ) {
+ [nsImage autorelease];
+ [NSApp setApplicationIconImage: nsImage];
+ }
+}
+
+JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_createPointerIcon0
+ (JNIEnv *env, jobject unused, jobject jiconData, jint jiconWidth, jint jiconHeight, jint hotX, jint hotY)
+{
+ NSImage * nsImage = createNSImageFromData(env, jiconData, jiconWidth, jiconHeight);
+ if( NULL != nsImage ) {
+ [nsImage autorelease];
+ NSPoint hotP = { hotX, hotY };
+ NSCursor * c = [[NSCursor alloc] initWithImage: nsImage hotSpot: hotP];
+ return (jlong) (intptr_t) c;
+ }
+ return 0;
+}
+
+JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_destroyPointerIcon0
+ (JNIEnv *env, jobject unused, jlong handle)
+{
+ NSCursor * c = (NSCursor*) (intptr_t) handle ;
+ [c release];
+}
+
+JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointerIcon0
+ (JNIEnv *env, jobject unused, jlong window, jlong handle)
+{
+ NewtMacWindow *mWin = (NewtMacWindow*) (intptr_t) window;
+ NSCursor * c = (NSCursor*) (intptr_t) handle ;
+
+ [mWin setCustomCursor: c];
+}
+
static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx, BOOL cap) {
NSArray *screens = [NSScreen screens];
if( screen_idx<0 || screen_idx>=[screens count] ) {
@@ -632,7 +702,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createView0
[pool release];
- return (jlong) ((intptr_t) myView);
+ return (jlong) (intptr_t) myView;
}
/**
@@ -674,7 +744,6 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createWindow
backing: (NSBackingStoreType) bufferingType
defer: YES
isFullscreenWindow: fullscreen];
-
// DBG_PRINT( "createWindow0.1 - %p, isVisible %d\n", myWindow, [myWindow isVisible]);
DBG_PRINT( "createWindow0.X - %p, isVisible %d\n", myWindow, [myWindow isVisible]);
diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h
index ba60b5665..1f907f30e 100644
--- a/src/newt/native/NewtMacWindow.h
+++ b/src/newt/native/NewtMacWindow.h
@@ -114,6 +114,7 @@
BOOL mouseVisible;
BOOL mouseInside;
BOOL cursorIsHidden;
+ NSCursor * customCursor;
BOOL realized;
BOOL modsDown[4]; // shift, ctrl, alt/option, win/command
NSPoint lastInsideMousePosition;
@@ -151,7 +152,8 @@
- (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p;
- (BOOL) isMouseInside;
-- (void) cursorHide:(BOOL)v;
+- (void) cursorHide:(BOOL)v enter:(int)enterState;
+- (void) setCustomCursor:(NSCursor*)c;
- (void) setMouseVisible:(BOOL)v hasFocus:(BOOL)focus;
- (void) setMouseConfined:(BOOL)v;
- (void) setMousePosition:(NSPoint)p;
diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m
index 4b0198c7e..a7bab9b9d 100644
--- a/src/newt/native/NewtMacWindow.m
+++ b/src/newt/native/NewtMacWindow.m
@@ -41,6 +41,8 @@
#include <math.h>
+#define PRINTF(...) NSLog(@ __VA_ARGS__)
+
static jfloat GetDelta(NSEvent *event, jint javaMods[]) {
CGEventRef cgEvent = [event CGEvent];
CGFloat deltaY = 0.0;
@@ -468,6 +470,7 @@ static UniChar CKCH_CharForKeyCode(jshort keyCode) {
defaultPresentationOptions = 0;
fullscreenPresentationOptions = 0;
}
+
isFullscreenWindow = isfs;
// Why is this necessary? Without it we don't get any of the
// delegate methods like resizing and window movement.
@@ -484,6 +487,7 @@ static UniChar CKCH_CharForKeyCode(jshort keyCode) {
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]);
@@ -678,13 +682,36 @@ static UniChar CKCH_CharForKeyCode(jshort keyCode) {
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];
+ [self cursorHide: !mouseVisible enter: 0];
+ }
+}
+
+- (void) setCustomCursor:(NSCursor*)c
+{
+ if(YES == mouseInside) {
+ if( NULL != c ) {
+ DBG_PRINT( "setCustomCursor push: %p\n", c);
+ [c push];
+ } else if( NULL != customCursor && [NSCursor currentCursor] == customCursor ) {
+ DBG_PRINT( "setCustomCursor pop: %p\n", customCursor);
+ [customCursor pop];
+ }
}
+ customCursor = c;
}
-- (void) cursorHide:(BOOL)v
+- (void) cursorHide:(BOOL)v enter:(int)enterState
{
- DBG_PRINT( "cursorHide: %d -> %d\n", cursorIsHidden, v);
+ DBG_PRINT( "cursorHide: %d -> %d, enter %d\n", cursorIsHidden, v, enterState);
+ if( NULL != customCursor ) {
+ if( 1 == enterState && [NSCursor currentCursor] != customCursor ) {
+ DBG_PRINT( "cursorHide.customCursor push: %p\n", customCursor);
+ [customCursor push];
+ } else if( -1 == enterState && [NSCursor currentCursor] == customCursor ) {
+ DBG_PRINT( "cursorHide.customCursor pop: %p\n", customCursor);
+ [customCursor pop];
+ }
+ }
if(v) {
if(!cursorIsHidden) {
[NSCursor hide];
@@ -941,7 +968,7 @@ static jint mods2JavaMods(NSUInteger mods)
DBG_PRINT( "*************** windowDidBecomeKey\n");
mouseInside = [self isMouseInside];
if(YES == mouseInside) {
- [self cursorHide: !mouseVisible];
+ [self cursorHide: !mouseVisible enter: 0];
}
[self focusChanged: YES];
}
@@ -995,7 +1022,7 @@ static jint mods2JavaMods(NSUInteger mods)
{
DBG_PRINT( "mouseEntered: confined %d, visible %d\n", mouseConfined, mouseVisible);
mouseInside = YES;
- [self cursorHide: !mouseVisible];
+ [self cursorHide: !mouseVisible enter: 1];
if(NO == mouseConfined) {
[self sendMouseEvent: theEvent eventType: EVENT_MOUSE_ENTERED];
}
@@ -1006,7 +1033,7 @@ static jint mods2JavaMods(NSUInteger mods)
DBG_PRINT( "mouseExited: confined %d, visible %d\n", mouseConfined, mouseVisible);
if(NO == mouseConfined) {
mouseInside = NO;
- [self cursorHide: NO];
+ [self cursorHide: NO enter: -1];
[self sendMouseEvent: theEvent eventType: EVENT_MOUSE_EXITED];
} else {
[self setMousePosition: lastInsideMousePosition];
@@ -1160,7 +1187,7 @@ static jint mods2JavaMods(NSUInteger mods)
jboolean closed = JNI_FALSE;
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
- [self cursorHide: NO];
+ [self cursorHide: NO enter: -1];
NSView* nsview = [self contentView];
if( ! [nsview isKindOfClass:[NewtView class]] ) {
diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c
index dd0150e78..2a16dce57 100644
--- a/src/newt/native/WindowsWindow.c
+++ b/src/newt/native/WindowsWindow.c
@@ -139,7 +139,7 @@
#include "NewtCommon.h"
-// #define VERBOSE_ON 1
+#define VERBOSE_ON 1
// #define DEBUG_KEYS 1
#ifdef VERBOSE_ON
@@ -186,6 +186,10 @@ typedef struct {
int height;
/** Tristate: -1 HIDE, 0 NOP, 1 SHOW */
int setPointerVisible;
+ /** Tristate: -1 RESET, 0 NOP, 1 SET-NEW */
+ int setPointerAction;
+ HCURSOR setPointerHandle;
+ HCURSOR defPointerHandle;
/** Bool: 0 NOP, 1 FULLSCREEN */
int setFullscreen;
int pointerCaptured;
@@ -1023,10 +1027,22 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP
} else /* -1 == wud->setPointerVisible */ {
visibilityChangeSuccessful = SafeShowCursor(FALSE);
}
- useDefWindowProc = visibilityChangeSuccessful ? 1 : 0;
DBG_PRINT("*** WindowsWindow: WM_SETCURSOR requested visibility: %d success: %d\n", wud->setPointerVisible, visibilityChangeSuccessful);
wud->setPointerVisible = 0;
- // own signal, consumed
+ // own signal, consumed, no further processing
+ useDefWindowProc = 0;
+ res = 1;
+ } else if( 0 != wud->setPointerAction ) {
+ if( -1 == wud->setPointerAction ) {
+ wud->setPointerHandle = wud->defPointerHandle;
+ }
+ HCURSOR preHandle = SetCursor(wud->setPointerHandle);
+ DBG_PRINT("*** WindowsWindow: WM_SETCURSOR requested change %d: pre %p -> set %p, def %p\n",
+ wud->setPointerAction, (void*)preHandle, (void*)wud->setPointerHandle, (void*)wud->defPointerHandle);
+ wud->setPointerAction = 0;
+ // own signal, consumed, no further processing
+ useDefWindowProc = 0;
+ res = 1;
} else {
useDefWindowProc = 1; // NOP for us, allow parent to act
}
@@ -1246,6 +1262,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP
if( 0 == wud->pointerInside ) {
wud->pointerInside = 1;
NewtWindows_trackPointerLeave(wnd);
+ SetCursor(wud->setPointerHandle);
}
(*env)->CallVoidMethod(env, window, sendMouseEventID,
(jshort) EVENT_MOUSE_MOVED,
@@ -1997,7 +2014,8 @@ static void NewtWindow_setVisiblePosSize(HWND hwnd, BOOL atop, BOOL visible,
JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindow0
(JNIEnv *env, jobject obj,
jlong hInstance, jstring jWndClassName, jstring jWndName, jint winMajor, jint winMinor,
- jlong parent, jint jx, jint jy, jint defaultWidth, jint defaultHeight, jboolean autoPosition, jint flags)
+ jlong parent, jint jx, jint jy, jint defaultWidth, jint defaultHeight, jboolean autoPosition, jint flags,
+ jlong iconSmallHandle, jlong iconBigHandle)
{
HWND parentWindow = (HWND) (intptr_t) parent;
const TCHAR* wndClassName = NULL;
@@ -2054,6 +2072,9 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindo
wud->width = width;
wud->height = height;
wud->setPointerVisible = 0;
+ wud->setPointerAction = 0;
+ wud->defPointerHandle = LoadCursor( NULL, IDC_ARROW);
+ wud->setPointerHandle = wud->defPointerHandle;
wud->setFullscreen = 0;
wud->pointerCaptured = 0;
wud->pointerInside = 0;
@@ -2083,6 +2104,12 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindo
RECT rc;
RECT * insets;
+ if( 0 != iconSmallHandle ) {
+ SendMessage(window, WM_SETICON, ICON_SMALL, (LPARAM) iconSmallHandle );
+ }
+ if( 0 != iconBigHandle ) {
+ SendMessage(window, WM_SETICON, ICON_BIG, (LPARAM) iconBigHandle );
+ }
ShowWindow(window, SW_SHOW);
// send insets before visibility, allowing java code a proper sync point!
@@ -2321,3 +2348,83 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_warpPointer0
SetCursorPos(x, y);
}
+JNIEXPORT jlong JNICALL
+Java_jogamp_newt_driver_windows_DisplayDriver_createBGRA8888Icon0(JNIEnv *env, jobject _unused,
+ jobject data, jint data_offset, jint width, jint height, jboolean isCursor, jint hotX, jint hotY) {
+
+ const unsigned char * data_ptr = (const unsigned char *) (*env)->GetDirectBufferAddress(env, data) + data_offset;
+ const int bytes = 4 * width * height; // BGRA8888
+
+ DWORD dwWidth, dwHeight;
+ BITMAPV5HEADER bi;
+ HBITMAP hBitmap;
+ void *lpBits;
+ HICON handle = NULL;
+
+ dwWidth = width; // width of cursor
+ dwHeight = height; // height of cursor
+
+ ZeroMemory(&bi,sizeof(BITMAPV5HEADER));
+ bi.bV5Size = sizeof(BITMAPV5HEADER);
+ bi.bV5Width = dwWidth;
+ bi.bV5Height = -1 * dwHeight;
+ bi.bV5Planes = 1;
+ bi.bV5BitCount = 32;
+ bi.bV5Compression = BI_BITFIELDS;
+ // The following mask specification specifies a supported 32 BPP
+ // alpha format for Windows XP.
+ bi.bV5RedMask = 0x00FF0000;
+ bi.bV5GreenMask = 0x0000FF00;
+ bi.bV5BlueMask = 0x000000FF;
+ bi.bV5AlphaMask = 0xFF000000;
+
+ HDC hdc;
+ hdc = GetDC(NULL);
+
+ // Create the DIB section with an alpha channel.
+ hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS,
+ (void **)&lpBits, NULL, (DWORD)0);
+
+ memcpy(lpBits, data_ptr, bytes);
+
+ ReleaseDC(NULL,hdc);
+
+ // Create an empty mask bitmap.
+ HBITMAP hMonoBitmap = CreateBitmap(dwWidth,dwHeight,1,1,NULL);
+
+ ICONINFO ii;
+ ii.fIcon = isCursor ? FALSE : TRUE;
+ ii.xHotspot = hotX;
+ ii.yHotspot = hotY;
+ ii.hbmMask = hMonoBitmap;
+ ii.hbmColor = hBitmap;
+
+ // Create the alpha cursor with the alpha DIB section.
+ handle = CreateIconIndirect(&ii);
+
+ DeleteObject(hBitmap);
+ DeleteObject(hMonoBitmap);
+
+ return (jlong) (intptr_t) handle;
+}
+
+JNIEXPORT void JNICALL
+Java_jogamp_newt_driver_windows_DisplayDriver_destroyIcon0(JNIEnv *env, jobject _unused, jlong jhandle) {
+ HICON handle = (HICON) (intptr_t) jhandle;
+ DestroyIcon(handle);
+}
+
+JNIEXPORT void JNICALL
+Java_jogamp_newt_driver_windows_WindowDriver_setPointerIcon0(JNIEnv *env, jobject _unused, jlong window, jlong iconHandle) {
+ HWND hwnd = (HWND) (intptr_t) window;
+ WindowUserData * wud;
+#if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 )
+ wud = (WindowUserData *) GetWindowLong(hwnd, GWL_USERDATA);
+#else
+ wud = (WindowUserData *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
+#endif
+ wud->setPointerAction = 0 != iconHandle ? 1 : -1;
+ wud->setPointerHandle = (HCURSOR) (intptr_t) iconHandle;
+ SendMessage(hwnd, WM_SETCURSOR, 0, 0);
+}
+
diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c
index e2392a113..19e733111 100644
--- a/src/newt/native/X11Display.c
+++ b/src/newt/native/X11Display.c
@@ -28,6 +28,8 @@
#include "X11Common.h"
+#include <X11/Xcursor/Xcursor.h>
+
// #include <X11/XKBlib.h> // XKB disabled for now
jclass X11NewtWindowClazz = NULL;
@@ -670,4 +672,54 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage
}
}
+/*
+ * Class: Java_jogamp_newt_driver_x11_DisplayDriver
+ * Method: createPointerIcon0
+ * Signature: (JJILjava/lang/Object;I)V
+ */
+JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_createPointerIcon0
+ (JNIEnv *env, jclass clazz, jlong display, jobject data, jint data_offset, jint width, jint height, jint hotX, jint hotY)
+{
+ Cursor c;
+
+ if( 0 != data ) {
+ Display * dpy = (Display *) (intptr_t) display;
+ char * data_ptr = (char *) (*env)->GetDirectBufferAddress(env, data) + data_offset;
+ XcursorImage ci;
+ ci.version = 1; // XCURSOR_IMAGE_VERSION;
+ ci.size = width; // nominal size (assume square ..)
+ ci.width = width;
+ ci.height = height;
+ ci.xhot = hotX;
+ ci.yhot = hotY;
+ ci.delay = 0;
+ ci.pixels = (XcursorPixel *)(intptr_t)data_ptr;
+
+ c = XcursorImageLoadCursor (dpy, &ci);
+
+ DBG_PRINT( "X11: createPointerIcon0: %p %dx%d %d/%d -> %p\n", data_ptr, width, height, hotX, hotY, (void *)c);
+
+ } else {
+ c = 0;
+ }
+ return (jlong) (intptr_t) c;
+}
+
+/*
+ * Class: Java_jogamp_newt_driver_x11_DisplayDriver
+ * Method: destroyPointerIcon0
+ * Signature: (JJILjava/lang/Object;I)V
+ */
+JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_destroyPointerIcon0
+ (JNIEnv *env, jclass clazz, jlong display, jlong handle)
+{
+ Display * dpy = (Display *) (intptr_t) display;
+
+ if( 0 != handle ) {
+ Cursor c = (Cursor) (intptr_t) handle;
+ DBG_PRINT( "X11: destroyPointerIcon0: %p\n", (void *)c);
+ XFreeCursor(dpy, c);
+ }
+}
+
diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c
index 5f5dddbe0..da2778004 100644
--- a/src/newt/native/X11Window.c
+++ b/src/newt/native/X11Window.c
@@ -497,6 +497,12 @@ static void NewtWindows_setPosSize(Display *dpy, Window w, jint x, jint y, jint
}
}
+static void NewtWindows_setIcon(Display *dpy, Window w, int data_size, const unsigned char * data_ptr) {
+ Atom _NET_WM_ICON = XInternAtom(dpy, "_NET_WM_ICON", False);
+ Atom CARDINAL = XInternAtom(dpy, "CARDINAL", False);
+ XChangeProperty(dpy, w, _NET_WM_ICON, CARDINAL, 32, PropModeReplace, data_ptr, data_size);
+}
+
/*
* Class: jogamp_newt_driver_x11_WindowDriver
* Method: CreateWindow
@@ -505,7 +511,8 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWindow0
(JNIEnv *env, jobject obj, jlong parent, jlong display, jint screen_index,
jint visualID,
jlong javaObjectAtom, jlong windowDeleteAtom,
- jint x, jint y, jint width, jint height, jboolean autoPosition, int flags)
+ jint x, jint y, jint width, jint height, jboolean autoPosition, int flags,
+ jint iconDataSize, jobject iconData)
{
Display * dpy = (Display *)(intptr_t)display;
Atom wm_delete_atom = (Atom)windowDeleteAtom;
@@ -626,6 +633,11 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWindow0
XEvent event;
int left=0, right=0, top=0, bottom=0;
+ if( 0 < iconDataSize && NULL != iconData ) {
+ const unsigned char * iconDataPtr = (const unsigned char *) (*env)->GetDirectBufferAddress(env, iconData);
+ NewtWindows_setIcon(dpy, window, (int)iconDataSize, iconDataPtr);
+ }
+
XMapWindow(dpy, window);
XIfEvent( dpy, &event, WaitForMapNotify, (XPointer) window ); // wait to get proper insets values
@@ -946,6 +958,27 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_setTitle0
/*
* Class: Java_jogamp_newt_driver_x11_WindowDriver
+ * Method: setPointerIcon0
+ * Signature: (JJILjava/lang/Object;I)V
+ */
+JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_setPointerIcon0
+ (JNIEnv *env, jclass clazz, jlong display, jlong window, jlong handle)
+{
+ Display * dpy = (Display *) (intptr_t) display;
+ Window w = (Window)window;
+
+ if( 0 == handle ) {
+ DBG_PRINT( "X11: setPointerIcon0: reset\n");
+ XUndefineCursor(dpy, w);
+ } else {
+ Cursor c = (Cursor) (intptr_t) handle;
+ DBG_PRINT( "X11: setPointerIcon0: %p\n", (void*)c);
+ XDefineCursor(dpy, w, c);
+ }
+}
+
+/*
+ * Class: Java_jogamp_newt_driver_x11_WindowDriver
* Method: setPointerVisible0
* Signature: (JJZ)Z
*/
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java
index b54a2cd19..efec961de 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java
@@ -30,7 +30,9 @@ package com.jogamp.opengl.test.junit.jogl.demos.es2.newt;
import java.io.IOException;
+import com.jogamp.common.util.IOUtil;
import com.jogamp.newt.Display;
+import com.jogamp.newt.Display.PointerIcon;
import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.Screen;
import com.jogamp.newt.event.KeyAdapter;
@@ -44,9 +46,7 @@ import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
import com.jogamp.opengl.test.junit.util.MiscUtils;
import com.jogamp.opengl.test.junit.util.UITestCase;
import com.jogamp.opengl.test.junit.util.QuitAdapter;
-
import com.jogamp.opengl.util.Animator;
-
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
import javax.media.nativewindow.NativeWindowFactory;
@@ -54,7 +54,6 @@ import javax.media.nativewindow.util.Dimension;
import javax.media.nativewindow.util.Point;
import javax.media.nativewindow.util.PointImmutable;
import javax.media.nativewindow.util.DimensionImmutable;
-
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
@@ -171,6 +170,20 @@ public class TestGearsES2NEWT extends UITestCase {
}
});
+ final PointerIcon pointerIconOne;
+ {
+ PointerIcon _pointerIconOne = null;
+ final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } );
+ final Display disp = glWindow.getScreen().getDisplay();
+ disp.createNative();
+ try {
+ _pointerIconOne = disp.createPointerIcon(res, 32, 0);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ pointerIconOne = _pointerIconOne;
+ }
+
glWindow.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(final KeyEvent e) {
@@ -203,6 +216,16 @@ public class TestGearsES2NEWT extends UITestCase {
System.err.println("[set alwaysontop post]: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets());
glWindow.setExclusiveContextThread(t);
} }.start();
+ } else if(e.getKeyChar()=='c') {
+ new Thread() {
+ public void run() {
+ final Thread t = glWindow.setExclusiveContextThread(null);
+ System.err.println("[set pointer-icon pre]");
+ final PointerIcon currentPI = glWindow.getPointerIcon();
+ glWindow.setPointerIcon( currentPI == pointerIconOne ? null : pointerIconOne);
+ System.err.println("[set pointer-icon post] "+currentPI+" -> "+glWindow.getPointerIcon());
+ glWindow.setExclusiveContextThread(t);
+ } }.start();
} else if(e.getKeyChar()=='d') {
new Thread() {
public void run() {