summaryrefslogtreecommitdiffstats
path: root/src/newt/classes
diff options
context:
space:
mode:
Diffstat (limited to 'src/newt/classes')
-rw-r--r--src/newt/classes/com/jogamp/newt/Display.java326
-rw-r--r--src/newt/classes/com/jogamp/newt/MonitorDevice.java299
-rw-r--r--src/newt/classes/com/jogamp/newt/MonitorMode.java458
-rw-r--r--src/newt/classes/com/jogamp/newt/NewtFactory.java186
-rw-r--r--src/newt/classes/com/jogamp/newt/NewtVersion.java21
-rw-r--r--src/newt/classes/com/jogamp/newt/Screen.java197
-rw-r--r--src/newt/classes/com/jogamp/newt/ScreenMode.java208
-rw-r--r--src/newt/classes/com/jogamp/newt/Window.java332
-rw-r--r--src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java979
-rw-r--r--[-rwxr-xr-x]src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java145
-rw-r--r--src/newt/classes/com/jogamp/newt/event/DoubleTapScrollGesture.java349
-rw-r--r--src/newt/classes/com/jogamp/newt/event/GestureHandler.java155
-rw-r--r--src/newt/classes/com/jogamp/newt/event/InputEvent.java168
-rw-r--r--src/newt/classes/com/jogamp/newt/event/KeyAdapter.java18
-rw-r--r--src/newt/classes/com/jogamp/newt/event/KeyEvent.java1413
-rw-r--r--src/newt/classes/com/jogamp/newt/event/KeyListener.java36
-rw-r--r--src/newt/classes/com/jogamp/newt/event/MonitorEvent.java73
-rw-r--r--src/newt/classes/com/jogamp/newt/event/MonitorModeListener.java (renamed from src/newt/classes/com/jogamp/newt/event/ScreenModeListener.java)12
-rw-r--r--src/newt/classes/com/jogamp/newt/event/MouseAdapter.java34
-rw-r--r--src/newt/classes/com/jogamp/newt/event/MouseEvent.java580
-rw-r--r--src/newt/classes/com/jogamp/newt/event/MouseListener.java47
-rw-r--r--src/newt/classes/com/jogamp/newt/event/NEWTEvent.java146
-rw-r--r--src/newt/classes/com/jogamp/newt/event/NEWTEventConsumer.java14
-rw-r--r--src/newt/classes/com/jogamp/newt/event/NEWTEventFiFo.java14
-rw-r--r--src/newt/classes/com/jogamp/newt/event/NEWTEventListener.java12
-rw-r--r--src/newt/classes/com/jogamp/newt/event/OutputEvent.java51
-rw-r--r--src/newt/classes/com/jogamp/newt/event/PinchToZoomGesture.java252
-rw-r--r--src/newt/classes/com/jogamp/newt/event/TraceKeyAdapter.java22
-rw-r--r--src/newt/classes/com/jogamp/newt/event/TraceMouseAdapter.java36
-rw-r--r--src/newt/classes/com/jogamp/newt/event/TraceWindowAdapter.java33
-rw-r--r--src/newt/classes/com/jogamp/newt/event/WindowAdapter.java31
-rw-r--r--src/newt/classes/com/jogamp/newt/event/WindowEvent.java34
-rw-r--r--src/newt/classes/com/jogamp/newt/event/WindowListener.java28
-rw-r--r--src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java14
-rw-r--r--src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java180
-rw-r--r--src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java72
-rw-r--r--src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java136
-rw-r--r--src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java183
-rw-r--r--src/newt/classes/com/jogamp/newt/opengl/GLWindow.java513
-rw-r--r--src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java386
-rw-r--r--src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java280
-rw-r--r--src/newt/classes/com/jogamp/newt/util/EDTUtil.java77
-rw-r--r--src/newt/classes/com/jogamp/newt/util/MainThread.java131
-rw-r--r--src/newt/classes/com/jogamp/newt/util/MonitorMode.java102
-rw-r--r--src/newt/classes/com/jogamp/newt/util/MonitorModeUtil.java258
-rw-r--r--src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java341
-rw-r--r--src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtApplet3Run.java360
-rw-r--r--[-rwxr-xr-x]src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java (renamed from src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java)218
-rw-r--r--src/newt/classes/com/jogamp/newt/util/applet/VersionApplet3.java226
-rw-r--r--src/newt/classes/jogamp/newt/Debug.java99
-rw-r--r--src/newt/classes/jogamp/newt/DefaultEDTUtil.java294
-rw-r--r--src/newt/classes/jogamp/newt/DisplayImpl.java566
-rw-r--r--src/newt/classes/jogamp/newt/MonitorDeviceImpl.java146
-rw-r--r--src/newt/classes/jogamp/newt/MonitorModeProps.java418
-rw-r--r--src/newt/classes/jogamp/newt/NEWTJNILibLoader.java47
-rw-r--r--src/newt/classes/jogamp/newt/OffscreenWindow.java65
-rw-r--r--src/newt/classes/jogamp/newt/PointerIconImpl.java171
-rw-r--r--src/newt/classes/jogamp/newt/ScreenImpl.java739
-rw-r--r--src/newt/classes/jogamp/newt/ScreenModeStatus.java231
-rw-r--r--src/newt/classes/jogamp/newt/ScreenMonitorState.java195
-rw-r--r--src/newt/classes/jogamp/newt/WindowImpl.java2916
-rw-r--r--src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java26
-rw-r--r--src/newt/classes/jogamp/newt/awt/event/AWTNewtEventFactory.java687
-rw-r--r--src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java152
-rw-r--r--src/newt/classes/jogamp/newt/driver/DriverClearFocus.java6
-rw-r--r--src/newt/classes/jogamp/newt/driver/DriverUpdatePosition.java12
-rw-r--r--src/newt/classes/jogamp/newt/driver/PNGIcon.java80
-rw-r--r--src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java13
-rw-r--r--src/newt/classes/jogamp/newt/driver/android/MD.java36
-rw-r--r--src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java325
-rw-r--r--src/newt/classes/jogamp/newt/driver/android/NewtVersionActivity.java107
-rw-r--r--src/newt/classes/jogamp/newt/driver/android/NewtVersionActivityLauncher.java12
-rw-r--r--src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java153
-rw-r--r--src/newt/classes/jogamp/newt/driver/android/WindowDriver.java603
-rw-r--r--src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java433
-rw-r--r--src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventTranslator.java50
-rw-r--r--src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java125
-rw-r--r--src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java221
-rw-r--r--src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java27
-rw-r--r--src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java98
-rw-r--r--src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java290
-rw-r--r--src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java18
-rw-r--r--src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java82
-rw-r--r--src/newt/classes/jogamp/newt/driver/bcm/egl/WindowDriver.java47
-rw-r--r--src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java147
-rw-r--r--src/newt/classes/jogamp/newt/driver/bcm/vc/iv/ScreenDriver.java89
-rw-r--r--src/newt/classes/jogamp/newt/driver/bcm/vc/iv/WindowDriver.java191
-rw-r--r--src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java20
-rw-r--r--src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java88
-rw-r--r--src/newt/classes/jogamp/newt/driver/intel/gdl/WindowDriver.java40
-rw-r--r--src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java18
-rw-r--r--src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java92
-rw-r--r--src/newt/classes/jogamp/newt/driver/kd/WindowDriver.java46
-rw-r--r--src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java959
-rw-r--r--src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java109
-rw-r--r--src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java83
-rw-r--r--src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java419
-rw-r--r--src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java220
-rw-r--r--src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java755
-rw-r--r--src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java89
-rw-r--r--src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java91
-rw-r--r--src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java162
-rw-r--r--src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java298
-rw-r--r--src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java142
-rw-r--r--src/newt/classes/jogamp/newt/driver/x11/RandR.java86
-rw-r--r--src/newt/classes/jogamp/newt/driver/x11/RandR11.java370
-rw-r--r--src/newt/classes/jogamp/newt/driver/x11/RandR13.java274
-rw-r--r--src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java445
-rw-r--r--src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java392
-rw-r--r--src/newt/classes/jogamp/newt/event/NEWTEventTask.java18
-rw-r--r--src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java370
-rw-r--r--src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java396
112 files changed, 18899 insertions, 7186 deletions
diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java
index 1e9a0e9eb..c4b919951 100644
--- a/src/newt/classes/com/jogamp/newt/Display.java
+++ b/src/newt/classes/com/jogamp/newt/Display.java
@@ -28,31 +28,212 @@
package com.jogamp.newt;
-import com.jogamp.newt.util.EDTUtil;
-import jogamp.newt.Debug;
-
-import java.util.*;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.util.PixelRectangle;
+import javax.media.nativewindow.util.PixelFormat;
+import javax.media.nativewindow.util.PointImmutable;
+
+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");
+ protected static final boolean DEBUG_POINTER_ICON = Debug.debug("Display.PointerIcon");
/** return precomputed hashCode from FQN {@link #getFQName()} */
+ @Override
public abstract int hashCode();
/** return true if obj is of type Display and both FQN {@link #getFQName()} equals */
- public boolean equals(Object obj) {
+ @Override
+ public boolean equals(final Object obj) {
if (this == obj) { return true; }
if (obj instanceof Display) {
- Display d = (Display)obj;
+ final Display d = (Display)obj;
return d.getFQName().equals(getFQName());
}
return false;
}
/**
+ * Native PointerIcon handle.
+ * <p>
+ * Instances can be created via {@link Display}'s
+ * {@link Display#createPointerIcon(com.jogamp.common.util.IOUtil.ClassResources, int, int) createPointerIcon(pngResource, ..)}
+ * or {@link Display#createPointerIcon(PixelRectangle, int, int) createPointerIcon(pixelrect, ..)}.
+ * </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} must not be {@link #destroy() destroyed} while in use!
+ * </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.
+ * However, this is not required.
+ * </p>
+ * <p>
+ * PointerIcons can be used via {@link Window#setPointerIcon(PointerIcon)}.
+ * </p>
+ */
+ public static interface PointerIcon extends PixelRectangle {
+ /**
+ * Always neatly packed, i.e. width * bytes_per_pixel.
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ */
+ @Override
+ int getStride();
+
+ /**
+ * Always false, i.e. origin is TOP-LEFT.
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ */
+ boolean isGLOriented();
+
+ /**
+ * Computes a hash code over:
+ * <ul>
+ * <li>display</li>
+ * <li>pixelformat</li>
+ * <li>size</li>
+ * <li>stride</li>
+ * <li>isGLOriented</li>
+ * <li>pixels</li>
+ * <li>hotspot</li>
+ * </ul>
+ * Dismissing the native handle!
+ * <p>
+ * The hashCode shall be computed only once with first call
+ * and stored for later retrieval to enhance performance.
+ * </p>
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ */
+ @Override
+ int hashCode();
+
+ /**
+ * @return the associated Display
+ */
+ Display getDisplay();
+
+ /** Returns the hotspot. */
+ PointImmutable getHotspot();
+
+ /**
+ * 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 native platform's {@link PixelFormat} for pointer-icon pixel data.
+ * <p>
+ * Using this value will avoid conversion within {@link #createPointerIcon(PixelRectangle, int, int)}.
+ * </p>
+ * <p>
+ * Known native pixel formats are:
+ * <ul>
+ * <li>X11: {@link PixelFormat#BGRA8888}</li>
+ * <li>Windows: {@link PixelFormat#BGRA8888}</li>
+ * <li>OSX: {@link PixelFormat#RGBA8888}</li>
+ * </ul>
+ * </p>
+ */
+ public abstract PixelFormat getNativePointerIconPixelFormat();
+
+ /**
+ * Returns the native platform's direct NIO buffer requirement pointer-icon pixel data.
+ * <p>
+ * Using this value will avoid conversion within {@link #createPointerIcon(PixelRectangle, int, int)}.
+ * </p>
+ */
+ public abstract boolean getNativePointerIconForceDirectNIO();
+
+ /**
+ * 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 single PNG resource for the {@link PointerIcon}. 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 IllegalArgumentException if pngResource is null or invalid
+ * @throws IllegalStateException if this Display instance is not {@link #isNativeValid() valid yet}.
+ * @throws IOException if the <code>pngResource</code> could not be {@link IOUtil.ClassResources#resolve(int) resolved}
+ * or via the PNG parser processing the input stream.
+ *
+ * @see PointerIcon
+ * @see Window#setPointerIcon(PointerIcon)
+ */
+ public abstract PointerIcon createPointerIcon(final IOUtil.ClassResources pngResource, final int hotX, final int hotY)
+ throws IllegalArgumentException, IllegalStateException, IOException;
+
+ /**
+ * Returns the newly created {@link PointerIcon} or <code>null</code> if not implemented on platform.
+ * <p>
+ * See {@link PointerIcon} for lifecycle semantics.
+ * </p>
+ * <p>
+ * In case {@link #getNativePointerIconPixelFormat()} or {@link #getNativePointerIconForceDirectNIO()}
+ * is not matched by the given <code>pixelrect</code>, the <code>pixelrect</code> is converted
+ * into the required {@link PixelFormat} and NIO type.
+ * </p>
+ *
+ * @param pixelrect {@link PixelRectangle} source for the {@link PointerIcon}
+ * @param hotX pointer hotspot x-coord, origin is upper-left corner
+ * @param hotY pointer hotspot y-coord, origin is upper-left corner
+ *
+ * @throws IllegalArgumentException if pixelrect is null.
+ * @throws IllegalStateException if this Display instance is not {@link #isNativeValid() valid yet}.
+ *
+ * @see PointerIcon
+ * @see Window#setPointerIcon(PointerIcon)
+ * @see #getNativePointerIconPixelFormat()
+ * @see #getNativePointerIconForceDirectNIO()
+ */
+ public abstract PointerIcon createPointerIcon(final PixelRectangle pixelrect, final int hotX, final int hotY) throws IllegalArgumentException, IllegalStateException;
+
+ /**
* 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>
@@ -77,7 +258,7 @@ public abstract class Display {
* Stop the running EDT in case this display is destroyed already.<br>
* @return true if EDT has been stopped (destroyed but running), otherwise false.
*/
- public abstract boolean validateEDT();
+ public abstract boolean validateEDTStopped();
/**
* @return true if the native display handle is valid and ready to operate,
@@ -88,7 +269,7 @@ public abstract class Display {
public abstract boolean isNativeValid();
/**
- * @return number of references by Screen
+ * @return number of references
*/
public abstract int getReferenceCount();
@@ -96,7 +277,7 @@ public abstract class Display {
* The 1st call will initiate native creation,
* since we follow the lazy creation pattern.
*
- * @return number of references after adding one
+ * @return number of references post operation
* @throws NativeWindowException if the native creation failed.
* @see #removeReference()
*/
@@ -106,31 +287,37 @@ public abstract class Display {
* The last call may destroy this instance,
* if {@link #getDestroyWhenUnused()} returns <code>true</code>.
*
- * @return number of references after removing one
+ * @return number of references post operation
* @see #addReference()
* @see #getDestroyWhenUnused()
* @see #setDestroyWhenUnused(boolean)
*/
public abstract int removeReference();
+ /**
+ * Return the {@link AbstractGraphicsDevice} used for depending resources lifecycle,
+ * i.e. {@link Screen} and {@link Window}, as well as the event dispatching (EDT). */
public abstract AbstractGraphicsDevice getGraphicsDevice();
/**
- * @return the fully qualified Display name,
- * which is a key of {@link #getType()} + {@link #getName()} + {@link #getId()}
+ * Return the handle of the {@link AbstractGraphicsDevice} as returned by {@link #getGraphicsDevice()}.
*/
- public abstract String getFQName();
-
public abstract long getHandle();
/**
+ * @return The fully qualified Display name,
+ * which is a key of {@link #getType()} + {@link #getName()} + {@link #getId()}.
+ */
+ public abstract String getFQName();
+
+ /**
* @return this display internal serial id
*/
public abstract int getId();
/**
- * @return This display connection name as defined at creation time.
- * The display connection name is a technical platform specific detail, see {@link AbstractGraphicsDevice#getConnection()}.
+ * @return This display connection name as defined at creation time.
+ * The display connection name is a technical platform specific detail, see {@link AbstractGraphicsDevice#getConnection()}.
*
* @see AbstractGraphicsDevice#getConnection()
*/
@@ -141,53 +328,60 @@ public abstract class Display {
*/
public abstract String getType();
+ /** Return true if this instance is exclusive, i.e. will not be shared. */
+ public abstract boolean isExclusive();
+
/**
* Sets a new {@link EDTUtil} and returns the previous one.
* <p>
- * If <code>newEDTUtil</code> is <code>null</code>,
+ * If <code>usrEDTUtil</code> is <code>null</code>,
* the device's default EDTUtil is created and used.
* </p>
* <p>
- * If a previous one exists and it differs from the new one,
- * it's being stopped, wait-until-idle and reset to allow restart.
+ * If a previous one exists and it differs from <code>usrEDTUtil</code>,
+ * it's being stopped, wait-until-idle.
* </p>
* <p>
- * If <code>newEDTUtil</code> is not null and equals the previous one,
- * <code>null</code> is returned and no change is being made.
+ * If <code>usrEDTUtil</code> is not null and equals the previous one,
+ * no change is being made.
* </p>
*/
- public abstract EDTUtil setEDTUtil(EDTUtil newEDTUtil);
-
+ public abstract EDTUtil setEDTUtil(EDTUtil usrEDTUtil);
+
public abstract EDTUtil getEDTUtil();
+ /**
+ * @return true if EDT is running and not subject to be stopped, otherwise false.
+ */
public abstract boolean isEDTRunning();
public abstract void dispatchMessages();
-
+
// Global Displays
- protected static ArrayList<Display> displayList = new ArrayList<Display>();
+ protected static final ArrayList<WeakReference<Display>> displayList = new ArrayList<WeakReference<Display>>();
protected static int displaysActive = 0;
- public static void dumpDisplayList(String prefix) {
+ public static void dumpDisplayList(final String prefix) {
synchronized(displayList) {
- Iterator<Display> i = displayList.iterator();
System.err.println(prefix+" DisplayList[] entries: "+displayList.size()+" - "+getThreadName());
- for(int j=0; i.hasNext(); j++) {
- Display d = i.next();
- System.err.println(" ["+j+"] : "+d);
+ final Iterator<WeakReference<Display>> ri = displayList.iterator();
+ for(int j=0; ri.hasNext(); j++) {
+ final Display d = ri.next().get();
+ System.err.println(" ["+j+"] : "+d+", GC'ed "+(null==d));
}
}
}
/**
- *
+ *
* @param type
* @param name
- * @param fromIndex start index, then increasing until found or end of list *
- * @return
+ * @param fromIndex start index, then increasing until found or end of list
+ * @paran shared if true, only shared instances are found, otherwise also exclusive
+ * @return
*/
- public static Display getFirstDisplayOf(String type, String name, int fromIndex) {
- return getDisplayOfImpl(type, name, fromIndex, 1);
+ public static Display getFirstDisplayOf(final String type, final String name, final int fromIndex, final boolean shared) {
+ return getDisplayOfImpl(type, name, fromIndex, 1, shared);
}
/**
@@ -195,33 +389,69 @@ public abstract class Display {
* @param type
* @param name
* @param fromIndex start index, then decreasing until found or end of list. -1 is interpreted as size - 1.
+ * @param shared if true, only shared instances are found, otherwise also exclusive
* @return
*/
- public static Display getLastDisplayOf(String type, String name, int fromIndex) {
- return getDisplayOfImpl(type, name, fromIndex, -1);
+ public static Display getLastDisplayOf(final String type, final String name, final int fromIndex, final boolean shared) {
+ return getDisplayOfImpl(type, name, fromIndex, -1, shared);
}
- private static Display getDisplayOfImpl(String type, String name, int fromIndex, int incr) {
+ private static Display getDisplayOfImpl(final String type, final String name, final int fromIndex, final int incr, final boolean shared) {
synchronized(displayList) {
int i = fromIndex >= 0 ? fromIndex : displayList.size() - 1 ;
while( ( incr > 0 ) ? i < displayList.size() : i >= 0 ) {
- Display display = (Display) displayList.get(i);
- if( display.getType().equals(type) &&
- display.getName().equals(name) ) {
- return display;
+ final Display display = displayList.get(i).get();
+ if( null == display ) {
+ // Clear GC'ed dead reference entry!
+ displayList.remove(i);
+ if( incr < 0 ) {
+ // decrease
+ i+=incr;
+ } // else nop - remove shifted subsequent elements to the left
+ } else {
+ if( display.getType().equals(type) &&
+ display.getName().equals(name) &&
+ ( !shared || shared && !display.isExclusive() )
+ ) {
+ return display;
+ }
+ i+=incr;
}
- i+=incr;
}
}
return null;
}
+ protected static void addDisplay2List(final Display display) {
+ synchronized(displayList) {
+ // GC before add
+ int i=0;
+ while( i < displayList.size() ) {
+ if( null == displayList.get(i).get() ) {
+ displayList.remove(i);
+ } else {
+ i++;
+ }
+ }
+ displayList.add(new WeakReference<Display>(display));
+ }
+ }
+
/** Returns the global display collection */
- @SuppressWarnings("unchecked")
public static Collection<Display> getAllDisplays() {
ArrayList<Display> list;
synchronized(displayList) {
- list = (ArrayList<Display>) displayList.clone();
+ list = new ArrayList<Display>();
+ int i = 0;
+ while( i < displayList.size() ) {
+ final Display d = displayList.get(i).get();
+ if( null == d ) {
+ displayList.remove(i);
+ } else {
+ list.add( displayList.get(i).get() );
+ i++;
+ }
+ }
}
return list;
}
@@ -236,15 +466,15 @@ public abstract class Display {
return Thread.currentThread().getName();
}
- public static String toHexString(int hex) {
+ public static String toHexString(final int hex) {
return "0x" + Integer.toHexString(hex);
}
- public static String toHexString(long hex) {
+ public static String toHexString(final long hex) {
return "0x" + Long.toHexString(hex);
}
- public static int hashCodeNullSafe(Object o) {
+ public static int hashCodeNullSafe(final Object o) {
return ( null != o ) ? o.hashCode() : 0;
}
}
diff --git a/src/newt/classes/com/jogamp/newt/MonitorDevice.java b/src/newt/classes/com/jogamp/newt/MonitorDevice.java
new file mode 100644
index 000000000..126162006
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/MonitorDevice.java
@@ -0,0 +1,299 @@
+/**
+ * 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 com.jogamp.newt;
+
+import java.util.List;
+
+import javax.media.nativewindow.util.DimensionImmutable;
+import javax.media.nativewindow.util.Rectangle;
+import javax.media.nativewindow.util.RectangleImmutable;
+import javax.media.nativewindow.util.SurfaceSize;
+
+import com.jogamp.common.util.ArrayHashSet;
+
+/**
+ * Visual output device, i.e. a CRT, LED ..consisting of it's components:<br>
+ * <ui>
+ * <li>Immutable
+ * <ul>
+ * <li>nativeId</li>
+ * <li>{@link DimensionImmutable} size in [mm]</li>
+ * <li>{@link MonitorMode} original mode</li>
+ * <li><code>List&lt;MonitorMode&gt;</code> supportedModes</li>
+ * </ul></li>
+ * <li>Mutable
+ * <ul>
+ * <li>{@link MonitorMode} current mode</li>
+ * <li>{@link RectangleImmutable} viewport (rotated)</li>
+ * </ul></li>
+ * </ul>
+ * <p>
+ * All values of this interface are represented in pixel units, if not stated otherwise.
+ * </p>
+ */
+public abstract class MonitorDevice {
+ protected final Screen screen; // backref
+ protected final int nativeId; // unique monitor device ID
+ protected final DimensionImmutable sizeMM; // in [mm]
+ protected final MonitorMode originalMode;
+ protected final ArrayHashSet<MonitorMode> supportedModes; // FIXME: May need to support mutable mode, i.e. adding modes on the fly!
+ protected MonitorMode currentMode;
+ protected boolean modeChanged;
+ protected Rectangle viewportPU; // in pixel units
+ protected Rectangle viewportWU; // in window units
+
+ protected MonitorDevice(final Screen screen, final int nativeId, final DimensionImmutable sizeMM, final Rectangle viewportPU, final Rectangle viewportWU, final MonitorMode currentMode, final ArrayHashSet<MonitorMode> supportedModes) {
+ this.screen = screen;
+ this.nativeId = nativeId;
+ this.sizeMM = sizeMM;
+ this.originalMode = currentMode;
+ this.supportedModes = supportedModes;
+ this.currentMode = currentMode;
+ this.viewportPU = viewportPU;
+ this.viewportWU = viewportWU;
+ this.modeChanged = false;
+ }
+
+ /** Returns the {@link Screen} owning this monitor. */
+ public final Screen getScreen() {
+ return screen;
+ }
+
+ /**
+ * Tests equality of two <code>MonitorDevice</code> objects
+ * by evaluating equality of it's components:<br>
+ * <ul>
+ * <li><code>nativeID</code></li>
+ * </ul>
+ * <br>
+ */
+ @Override
+ public final boolean equals(final Object obj) {
+ if (this == obj) { return true; }
+ if (obj instanceof MonitorDevice) {
+ final MonitorDevice md = (MonitorDevice)obj;
+ return md.nativeId == nativeId;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a combined hash code of it's elements:<br>
+ * <ul>
+ * <li><code>nativeID</code></li>
+ * </ul>
+ */
+ @Override
+ public final int hashCode() {
+ return nativeId;
+ }
+
+ /** @return the immutable unique native Id of this monitor device. */
+ public final int getId() { return nativeId; }
+
+ /**
+ * @return the immutable monitor size in millimeters.
+ */
+ public final DimensionImmutable getSizeMM() {
+ return sizeMM;
+ }
+
+ /**
+ * Returns the <i>pixels per millimeter</i> value according to the <i>current</i> {@link MonitorMode mode}'s
+ * {@link SurfaceSize#getResolution() surface resolution}.
+ * <p>
+ * To convert the result to <i>dpi</i>, i.e. dots-per-inch, multiply both components with <code>25.4f</code>.
+ * </p>
+ * @param ppmmStore float[2] storage for the ppmm result
+ * @return the passed storage containing the ppmm for chaining
+ */
+ public final float[] getPixelsPerMM(final float[] ppmmStore) {
+ return getPixelsPerMM(getCurrentMode(), ppmmStore);
+ }
+
+ /**
+ * Returns the <i>pixels per millimeter</i> value according to the given {@link MonitorMode mode}'s
+ * {@link SurfaceSize#getResolution() surface resolution}.
+ * <p>
+ * To convert the result to <i>dpi</i>, i.e. dots-per-inch, multiply both components with <code>25.4f</code>.
+ * </p>
+ * @param mode
+ * @param ppmmStore float[2] storage for the ppmm result
+ * @return the passed storage containing the ppmm for chaining
+ */
+ public final float[] getPixelsPerMM(final MonitorMode mode, final float[] ppmmStore) {
+ final DimensionImmutable sdim = getSizeMM();
+ final DimensionImmutable spix = mode.getSurfaceSize().getResolution();
+ ppmmStore[0] = (float)spix.getWidth() / (float)sdim.getWidth();
+ ppmmStore[1] = (float)spix.getHeight() / (float)sdim.getHeight();
+ return ppmmStore;
+ }
+
+ /**
+ * Returns the immutable original {@link com.jogamp.newt.MonitorMode}, as used at NEWT initialization.
+ * <p>
+ * The returned {@link MonitorMode} is element of the lists {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
+ * </p>
+ */
+ public final MonitorMode getOriginalMode() {
+ return originalMode;
+ }
+
+ /**
+ * Returns a list of immutable {@link MonitorMode}s supported by this monitor.
+ * <p>
+ * The list is ordered in descending order,
+ * see {@link MonitorMode#compareTo(MonitorMode)}.
+ * </p>
+ * <p>
+ * Use w/ care, it's not a copy!
+ * </p>
+ */
+ public final List<MonitorMode> getSupportedModes() {
+ return supportedModes.getData();
+ }
+
+ /**
+ * Returns the {@link RectangleImmutable rectangular} portion
+ * of the <b>rotated</b> virtual {@link Screen} size in pixel units
+ * represented by this monitor, i.e. top-left origin and size.
+ * @see Screen
+ */
+ public final RectangleImmutable getViewport() {
+ return viewportPU;
+ }
+
+ /**
+ * Returns the {@link RectangleImmutable rectangular} portion
+ * of the <b>rotated</b> virtual {@link Screen} size in window units
+ * represented by this monitor, i.e. top-left origin and size.
+ * @see Screen
+ */
+ public final RectangleImmutable getViewportInWindowUnits() {
+ return viewportWU;
+ }
+
+ /**
+ * Returns <code>true</code> if given screen coordinates in pixel units
+ * are contained by this {@link #getViewport() viewport}, otherwise <code>false</code>.
+ * @param x x-coord in pixel units
+ * @param y y-coord in pixel units
+ */
+ public final boolean contains(final int x, final int y) {
+ return x >= viewportPU.getX() &&
+ x < viewportPU.getX() + viewportPU.getWidth() &&
+ y >= viewportPU.getY() &&
+ y < viewportPU.getY() + viewportPU.getHeight() ;
+ }
+
+ /**
+ * Calculates the union of the given monitor's {@link #getViewport() viewport} in pixel- and window units.
+ * @param viewport storage for result in pixel units, maybe null
+ * @param viewportInWindowUnits storage for result in window units, maybe null
+ * @param monitors given list of monitors
+ */
+ public static void unionOfViewports(final Rectangle viewport, final Rectangle viewportInWindowUnits, final List<MonitorDevice> monitors) {
+ int x1PU=Integer.MAX_VALUE, y1PU=Integer.MAX_VALUE;
+ int x2PU=Integer.MIN_VALUE, y2PU=Integer.MIN_VALUE;
+ int x1WU=Integer.MAX_VALUE, y1WU=Integer.MAX_VALUE;
+ int x2WU=Integer.MIN_VALUE, y2WU=Integer.MIN_VALUE;
+ for(int i=monitors.size()-1; i>=0; i--) {
+ if( null != viewport ) {
+ final RectangleImmutable viewPU = monitors.get(i).getViewport();
+ x1PU = Math.min(x1PU, viewPU.getX());
+ x2PU = Math.max(x2PU, viewPU.getX() + viewPU.getWidth());
+ y1PU = Math.min(y1PU, viewPU.getY());
+ y2PU = Math.max(y2PU, viewPU.getY() + viewPU.getHeight());
+ }
+ if( null != viewportInWindowUnits ) {
+ final RectangleImmutable viewWU = monitors.get(i).getViewportInWindowUnits();
+ x1WU = Math.min(x1WU, viewWU.getX());
+ x2WU = Math.max(x2WU, viewWU.getX() + viewWU.getWidth());
+ y1WU = Math.min(y1WU, viewWU.getY());
+ y2WU = Math.max(y2WU, viewWU.getY() + viewWU.getHeight());
+ }
+ }
+ if( null != viewport ) {
+ viewport.set(x1PU, y1PU, x2PU - x1PU, y2PU - y1PU);
+ }
+ if( null != viewportInWindowUnits ) {
+ viewportInWindowUnits.set(x1WU, y1WU, x2WU - x1WU, y2WU - y1WU);
+ }
+ }
+
+ public final boolean isOriginalMode() {
+ return currentMode.hashCode() == originalMode.hashCode();
+ }
+
+ /**
+ * Returns <code>true</true> if the {@link MonitorMode}
+ * has been changed programmatic via this API <i>only</i>, otherwise <code>false</code>.
+ * <p>
+ * Note: We cannot guarantee that we won't interfere w/ another running
+ * application's screen mode change or vice versa.
+ * </p>
+ */
+ public final boolean isModeChangedByUs() {
+ return modeChanged && !isOriginalMode();
+ }
+
+ /**
+ * Returns the cached current {@link MonitorMode} w/o native query.
+ * <p>
+ * The returned {@link MonitorMode} is element of the lists {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
+ * </p>
+ * @see #queryCurrentMode()
+ */
+ public final MonitorMode getCurrentMode() {
+ return currentMode;
+ }
+
+ /**
+ * Returns the current {@link MonitorMode} resulting from a native query.
+ * <p>
+ * The returned {@link MonitorMode} is element of the lists {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
+ * </p>
+ * @see #getCurrentMode()
+ */
+ public abstract MonitorMode queryCurrentMode();
+
+ /**
+ * Set the current {@link com.jogamp.newt.MonitorMode}.
+ * @param mode to be made current, must be element of the list {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}.
+ * @return true if successful, otherwise false
+ */
+ public abstract boolean setCurrentMode(MonitorMode mode);
+
+ @Override
+ public String toString() {
+ return "Monitor[Id "+Display.toHexString(nativeId)+", "+sizeMM+" mm, viewport "+viewportPU+ " [pixels], "+viewportWU+" [window], orig "+originalMode+", curr "+currentMode+
+ ", modeChanged "+modeChanged+", modeCount "+supportedModes.size()+"]";
+ }
+}
+
diff --git a/src/newt/classes/com/jogamp/newt/MonitorMode.java b/src/newt/classes/com/jogamp/newt/MonitorMode.java
new file mode 100644
index 000000000..09bc06ebd
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/MonitorMode.java
@@ -0,0 +1,458 @@
+/**
+ * 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 com.jogamp.newt;
+
+import java.util.Comparator;
+
+import javax.media.nativewindow.util.DimensionImmutable;
+import javax.media.nativewindow.util.RectangleImmutable;
+import javax.media.nativewindow.util.SurfaceSize;
+
+import com.jogamp.newt.util.MonitorModeUtil;
+
+
+/**
+ * Immutable MonitorMode Class, consisting of it's read only components:<br>
+ * <ul>
+ * <li>nativeId</li>
+ * <li>{@link SizeAndRRate}, consist out of non rotated {@link #getSurfaceSize() surface size}, {@link #getRefreshRate() refresh rate} and {@link #getFlags() flags}.</li>
+ * <li><code>rotation</code>, measured counter clockwise (CCW)</li>
+ * </ul>
+ *
+ * <i>Aquire and filter MonitorMode</i><br>
+ * <ul>
+ * <li>{@link MonitorDevice} Selection:
+ * <ul>
+ * <li>A List of all {@link MonitorDevice}s is accessible via {@link Screen#getMonitorDevices()}.</li>
+ * <li>The main monitor used by a windows is accessible via {@link Window#getMainMonitor()}.</li>
+ * <li>The main monitor covering an arbitrary rectangle is accessible via {@link Screen#getMainMonitor(RectangleImmutable)}.</li>
+ * </ul></li>
+ * <li>The current MonitorMode can be obtained via {@link MonitorDevice#getCurrentMode()}.</li>
+ * <li>The original MonitorMode can be obtained via {@link MonitorDevice#getOriginalMode()}.</li>
+ * <li>{@link MonitorMode} Filtering:
+ * <ul>
+ * <li>A {@link MonitorDevice}'s MonitorModes is accessible via {@link MonitorDevice#getSupportedModes()}.</li>
+ * <li>You may utilize {@link MonitorModeUtil} to filter and select a desired MonitorMode.</li>
+ * </ul></li>
+ * </ul>
+ * <br>
+ *
+ * <i>Changing MonitorMode</i><br>
+ * <ul>
+ * <li> Use {@link MonitorDevice#setCurrentMode(MonitorMode)}
+ * to change the current MonitorMode for all {@link Screen}s referenced via the {@link Screen#getFQName() full qualified name (FQN)}.</li>
+ * <li> The {@link MonitorDevice#getOriginalMode() original mode} is restored when
+ * <ul>
+ * <li>the last FQN referenced Screen closes.</li>
+ * <li>the JVM shuts down.</li>
+ * </ul></li>
+ * </ul>
+ * <br>
+ * Example for changing the MonitorMode:
+ * <pre>
+ // Pick the monitor:
+ // Either the one used by a window ..
+ MonitorDevice monitor = window.getMainMonitor();
+
+ // Or arbitrary from the list ..
+ List<MonitorDevice> allMonitor = getMonitorDevices();
+ MonitorDevice monitor = allMonitor.get(0);
+
+ // Current and original modes ..
+ MonitorMode mmCurrent = monitor.queryCurrentMode();
+ MonitorMode mmOrig = monitor.getOriginalMode();
+
+ // Target resolution in pixel units
+ DimensionImmutable res = new Dimension(800, 600);
+
+ // Target refresh rate shall be similar to current one ..
+ float freq = mmCurrent.getRefreshRate();
+
+ // Target rotation shall be similar to current one
+ int rot = mmCurrent.getRotation();
+
+ // Filter criterias sequential out of all available MonitorMode of the chosen MonitorDevice
+ List<MonitorMode> monitorModes = monitor.getSupportedModes();
+ monitorModes = MonitorModeUtil.filterByFlags(monitorModes, 0); // no interlace, double-scan etc
+ monitorModes = MonitorModeUtil.filterByRotation(monitorModes, rot);
+ monitorModes = MonitorModeUtil.filterByResolution(monitorModes, res);
+ monitorModes = MonitorModeUtil.filterByRate(monitorModes, freq);
+ monitorModes = MonitorModeUtil.getHighestAvailableBpp(monitorModes);
+
+ // pick 1st one and set to current ..
+ MonitorMode mm = monitorModes.get(0);
+ monitor.setCurrentMode(mm);
+ * </pre>
+ */
+public class MonitorMode implements Comparable<MonitorMode> {
+
+ /** Comparator for 2 {@link MonitorMode}s, following comparison order as described in {@link MonitorMode#compareTo(MonitorMode)}, returning the ascending order. */
+ public static final Comparator<MonitorMode> monitorModeComparator = new Comparator<MonitorMode>() {
+ @Override
+ public int compare(final MonitorMode mm1, final MonitorMode mm2) {
+ return mm1.compareTo(mm2);
+ } };
+
+ /** Comparator for 2 {@link MonitorMode}s, following comparison order as described in {@link MonitorMode#compareTo(MonitorMode)}, returning the descending order. */
+ public static final Comparator<MonitorMode> monitorModeComparatorInv = new Comparator<MonitorMode>() {
+ @Override
+ public int compare(final MonitorMode mm1, final MonitorMode mm2) {
+ return mm2.compareTo(mm1);
+ } };
+
+ /**
+ * Immutable <i>surfaceSize, flags and refreshRate</i> Class, consisting of it's read only components:<br>
+ * <ul>
+ * <li>nativeId</li>
+ * <li>{@link SurfaceSize} surface memory size</li>
+ * <li><code>flags</code></li>
+ * <li><code>refresh rate</code></li>
+ * </ul>
+ */
+ public static class SizeAndRRate implements Comparable<SizeAndRRate> {
+ /** Non rotated surface size in pixel units */
+ public final SurfaceSize surfaceSize;
+ /** Mode bitfield flags, i.e. {@link #FLAG_DOUBLESCAN}, {@link #FLAG_INTERLACE}, .. */
+ public final int flags;
+ /** Vertical refresh rate */
+ public final float refreshRate;
+ public final int hashCode;
+
+ public SizeAndRRate(final SurfaceSize surfaceSize, final float refreshRate, final int flags) {
+ if(null==surfaceSize) {
+ throw new IllegalArgumentException("surfaceSize must be set ("+surfaceSize+")");
+ }
+ this.surfaceSize=surfaceSize;
+ this.flags = flags;
+ this.refreshRate=refreshRate;
+ this.hashCode = getHashCode();
+ }
+
+ private final static String STR_INTERLACE = "Interlace";
+ private final static String STR_DOUBLESCAN = "DoubleScan";
+ private final static String STR_SEP = ", ";
+
+ public static final StringBuilder flags2String(final int flags) {
+ final StringBuilder sb = new StringBuilder();
+ boolean sp = false;
+ if( 0 != ( flags & FLAG_INTERLACE ) ) {
+ sb.append(STR_INTERLACE);
+ sp = true;
+ }
+ if( 0 != ( flags & FLAG_DOUBLESCAN ) ) {
+ if( sp ) {
+ sb.append(STR_SEP);
+ }
+ sb.append(STR_DOUBLESCAN);
+ sp = true;
+ }
+ return sb;
+ }
+ @Override
+ public final String toString() {
+ return surfaceSize+" @ "+refreshRate+" Hz, flags ["+flags2String(flags).toString()+"]";
+ }
+
+ /**
+ * <p>
+ * Compares {@link SurfaceSize#compareTo(SurfaceSize) surfaceSize} 1st, then {@link #flags}, then {@link #refreshRate}.
+ * </p>
+ * <p>
+ * Flags are compared as follows:
+ * <pre>
+ * NONE > DOUBLESCAN > INTERLACE
+ * </pre>
+ * </p>
+ * <p>
+ * Refresh rate differences of &lt; 0.01 are considered equal (epsilon).
+ * </p>
+ * {@inheritDoc}
+ */
+ @Override
+ public int compareTo(final SizeAndRRate sszr) {
+ final int rssz = surfaceSize.compareTo(sszr.surfaceSize);
+ if( 0 != rssz ) {
+ return rssz;
+ }
+ final int tflags = 0 == flags ? Integer.MAX_VALUE : flags; // normalize NONE
+ final int xflags = 0 == sszr.flags ? Integer.MAX_VALUE : sszr.flags; // normalize NONE
+ if( tflags == xflags ) {
+ final float refreshEpsilon = 0.01f; // reasonable sorting granularity of refresh rate
+ final float drate = refreshRate - sszr.refreshRate;
+ if( Math.abs(drate) < refreshEpsilon ) {
+ return 0;
+ } else if( drate > refreshEpsilon ) {
+ return 1;
+ } else {
+ return -1;
+ }
+ } else {
+ if(tflags > xflags) {
+ return 1;
+ } else if(tflags < xflags) {
+ return -1;
+ }
+ return 0;
+ }
+ }
+
+ /**
+ * Tests equality of two {@link SizeAndRRate} objects
+ * by evaluating equality of it's components:<br/>
+ * <ul>
+ * <li><code>surfaceSize</code></li>
+ * <li><code>refreshRate</code></li>
+ * <li><code>flags</code></li>
+ * </ul>
+ */
+ @Override
+ public final boolean equals(final Object obj) {
+ if (this == obj) { return true; }
+ if (obj instanceof SizeAndRRate) {
+ final SizeAndRRate p = (SizeAndRRate)obj;
+ return surfaceSize.equals(p.surfaceSize) &&
+ flags == p.flags &&
+ refreshRate == p.refreshRate ;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a combined hash code of it's elements:<br/>
+ * <ul>
+ * <li><code>surfaceSize</code></li>
+ * <li><code>flags</code></li>
+ * <li><code>refreshRate</code></li>
+ * </ul>
+ */
+ @Override
+ public final int hashCode() {
+ return hashCode;
+ }
+ private final int getHashCode() {
+ // 31 * x == (x << 5) - x
+ int hash = 31 + surfaceSize.hashCode();
+ hash = ((hash << 5) - hash) + flags;
+ hash = ((hash << 5) - hash) + (int)(refreshRate*100.0f);
+ return hash;
+ }
+ }
+
+ /** zero rotation, compared to normal settings */
+ public static final int ROTATE_0 = 0;
+
+ /** 90 degrees CCW rotation */
+ public static final int ROTATE_90 = 90;
+
+ /** 180 degrees CCW rotation */
+ public static final int ROTATE_180 = 180;
+
+ /** 270 degrees CCW rotation */
+ public static final int ROTATE_270 = 270;
+
+ /** Frame is split into two fields. See {@link #getFlags()}. */
+ public static final int FLAG_INTERLACE = 1 << 0;
+
+ /** Lines are doubled. See {@link #getFlags()}. */
+ public static final int FLAG_DOUBLESCAN = 1 << 1;
+
+ /** The immutable native Id of this instance, which may not be unique. */
+ private final int nativeId;
+ private final SizeAndRRate sizeAndRRate;
+ private final int rotation;
+ private final int hashCode;
+
+ public static boolean isRotationValid(final int rotation) {
+ return rotation == MonitorMode.ROTATE_0 || rotation == MonitorMode.ROTATE_90 ||
+ rotation == MonitorMode.ROTATE_180 || rotation == MonitorMode.ROTATE_270 ;
+ }
+
+ /**
+ * @param sizeAndRRate the surface size and refresh rate mode
+ * @param rotation the screen rotation, measured counter clockwise (CCW)
+ */
+ public MonitorMode(final int nativeId, final SizeAndRRate sizeAndRRate, final int rotation) {
+ if ( !isRotationValid(rotation) ) {
+ throw new RuntimeException("invalid rotation: "+rotation);
+ }
+ this.nativeId = nativeId;
+ this.sizeAndRRate = sizeAndRRate;
+ this.rotation = rotation;
+ this.hashCode = getHashCode();
+ }
+
+ /**
+ * Creates a user instance w/o {@link #getId() identity} to filter our matching modes w/ identity.
+ * <p>
+ * See {@link com.jogamp.newt.util.MonitorModeUtil} for filter utilities.
+ * </p>
+ * @param surfaceSize
+ * @param refreshRate
+ * @param flags
+ * @param rotation
+ */
+ public MonitorMode(final SurfaceSize surfaceSize, final float refreshRate, final int flags, final int rotation) {
+ this(0, new SizeAndRRate(surfaceSize, refreshRate, flags), rotation);
+ }
+
+ /** @return the immutable native Id of this mode, may not be unique, may be 0. */
+ public final int getId() { return nativeId; }
+
+ /** Returns the <i>surfaceSize and refreshRate</i> instance. */
+ public final SizeAndRRate getSizeAndRRate() {
+ return sizeAndRRate;
+ }
+
+ /** Returns the unrotated {@link SurfaceSize} */
+ public final SurfaceSize getSurfaceSize() {
+ return sizeAndRRate.surfaceSize;
+ }
+
+ /** Returns the vertical refresh rate. */
+ public final float getRefreshRate() {
+ return sizeAndRRate.refreshRate;
+ }
+
+ /** Returns bitfield w/ flags, i.e. {@link #FLAG_DOUBLESCAN}, {@link #FLAG_INTERLACE}, .. */
+ public final int getFlags() {
+ return sizeAndRRate.flags;
+ }
+
+ /** Returns the CCW rotation of this mode */
+ public final int getRotation() {
+ return rotation;
+ }
+
+ /** Returns the rotated screen width in pixel units,
+ * derived from <code>getMonitorMode().getSurfaceSize().getResolution()</code>
+ * and <code>getRotation()</code>
+ */
+ public final int getRotatedWidth() {
+ return getRotatedWH(true);
+ }
+
+ /** Returns the rotated screen height in pixel units,
+ * derived from <code>getMonitorMode().getSurfaceSize().getResolution()</code>
+ * and <code>getRotation()</code>
+ */
+ public final int getRotatedHeight() {
+ return getRotatedWH(false);
+ }
+
+ @Override
+ public final String toString() {
+ return "[Id "+Display.toHexString(nativeId)+", " + sizeAndRRate + ", " + rotation + " degr]";
+ }
+
+ /**
+ * <p>
+ * Compares {@link SizeAndRRate#compareTo(SizeAndRRate) sizeAndRRate} 1st, then {@link #rotation}.
+ * </p>
+ * <p>
+ * Rotation is compared inverted, i.e. <code>360 - rotation</code>,
+ * so the lowest rotation reflects a higher value.
+ * </p>
+ * <p>
+ * Order of comparing MonitorMode:
+ * <ul>
+ * <li>resolution</li>
+ * <li>bits per pixel</li>
+ * <li>flags</li>
+ * <li>refresh rate</li>
+ * <li>rotation</li>
+ * </ul>
+ * </p>
+ * {@inheritDoc}
+ */
+ @Override
+ public int compareTo(final MonitorMode mm) {
+ final int c = sizeAndRRate.compareTo(mm.sizeAndRRate);
+ if( 0 != c ) {
+ return c;
+ }
+ final int trot = 360 - rotation; // normalize rotation
+ final int xrot = 360 - mm.rotation; // normalize rotation
+ if(trot > xrot) {
+ return 1;
+ } else if(trot < xrot) {
+ return -1;
+ }
+ return 0;
+ }
+
+ /**
+ * Tests equality of two {@link MonitorMode} objects
+ * by evaluating equality of it's components:<br/>
+ * <ul>
+ * <li><code>nativeId</code></li>
+ * <li><code>sizeAndRRate</code></li>
+ * <li><code>rotation</code></li>
+ * </ul>
+ */
+ @Override
+ public final boolean equals(final Object obj) {
+ if (this == obj) { return true; }
+ if (obj instanceof MonitorMode) {
+ final MonitorMode sm = (MonitorMode)obj;
+ return sm.nativeId == this.nativeId &&
+ sm.sizeAndRRate.equals(sizeAndRRate) &&
+ sm.rotation == this.rotation ;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a combined hash code of it's elements:<br/>
+ * <ul>
+ * <li><code>nativeId</code></li>
+ * <li><code>sizeAndRRate</code></li>
+ * <li><code>rotation</code></li>
+ * </ul>
+ */
+ @Override
+ public final int hashCode() {
+ return hashCode;
+ }
+ private final int getHashCode() {
+ // 31 * x == (x << 5) - x
+ int hash = 31 + getId();
+ hash = ((hash << 5) - hash) + sizeAndRRate.hashCode();
+ hash = ((hash << 5) - hash) + getRotation();
+ return hash;
+ }
+
+ private final int getRotatedWH(final boolean width) {
+ final DimensionImmutable d = sizeAndRRate.surfaceSize.getResolution();
+ final boolean swap = MonitorMode.ROTATE_90 == rotation || MonitorMode.ROTATE_270 == rotation ;
+ if ( ( width && swap ) || ( !width && !swap ) ) {
+ return d.getHeight();
+ }
+ return d.getWidth();
+ }
+}
diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java
index 0644c9164..9606fae08 100644
--- a/src/newt/classes/com/jogamp/newt/NewtFactory.java
+++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,11 +29,15 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
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;
import javax.media.nativewindow.AbstractGraphicsScreen;
@@ -41,6 +45,9 @@ import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.NativeWindowFactory;
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.PropertyAccess;
+
import jogamp.newt.Debug;
import jogamp.newt.DisplayImpl;
import jogamp.newt.ScreenImpl;
@@ -49,20 +56,60 @@ import jogamp.newt.WindowImpl;
public class NewtFactory {
public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window");
- // Work-around for initialization order problems on Mac OS X
- // between native Newt and (apparently) Fmod
+ public static final String DRIVER_DEFAULT_ROOT_PACKAGE = "jogamp.newt.driver";
+
+ private static IOUtil.ClassResources defaultWindowIcons;
+
static {
- NativeWindowFactory.initSingleton(); // last resort ..
- WindowImpl.init(NativeWindowFactory.getNativeWindowType(true));
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ NativeWindowFactory.initSingleton(); // last resort ..
+ {
+ /** See API Doc in {@link Window} ! */
+ final String[] paths = PropertyAccess.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;
+ } } );
}
- public static Class<?> getCustomClass(String packageName, String classBaseName) {
+ /**
+ * 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(final IOUtil.ClassResources cres) { defaultWindowIcons = cres; }
+
+ public static Class<?> getCustomClass(final String packageName, final String classBaseName) {
Class<?> clazz = null;
if(packageName!=null && classBaseName!=null) {
- final String clazzName = packageName + "." + classBaseName ;
+ final String clazzName;
+ if( packageName.startsWith(".") ) {
+ clazzName = DRIVER_DEFAULT_ROOT_PACKAGE + packageName + "." + classBaseName ;
+ } else {
+ clazzName = packageName + "." + classBaseName ;
+ }
try {
clazz = Class.forName(clazzName);
- } catch (Throwable t) {
+ } catch (final Throwable t) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Warning: Failed to find class <"+clazzName+">: "+t.getMessage());
t.printStackTrace();
@@ -74,12 +121,12 @@ public class NewtFactory {
private static boolean useEDT = true;
- /**
+ /**
* Toggles the usage of an EventDispatchThread while creating a Display.<br>
* The default is enabled.<br>
* The EventDispatchThread is thread local to the Display instance.<br>
*/
- public static synchronized void setUseEDT(boolean onoff) {
+ public static synchronized void setUseEDT(final boolean onoff) {
useEDT = onoff;
}
@@ -92,13 +139,13 @@ public class NewtFactory {
* Native creation is lazily done at usage, ie. {@link Display#addReference()}.
* </p>
* <p>
- * An already existing display connection of the same <code>name</code> will be reused.
+ * An already existing display connection of the same <code>name</code> will be reused.
* </p>
* @param name the display connection name which is a technical platform specific detail,
* see {@link AbstractGraphicsDevice#getConnection()}. Use <code>null</code> for default.
* @return the new or reused Display instance
*/
- public static Display createDisplay(String name) {
+ public static Display createDisplay(final String name) {
return createDisplay(name, true);
}
@@ -116,7 +163,7 @@ public class NewtFactory {
* @param reuse attempt to reuse an existing Display with same <code>name</code> if set true, otherwise create a new instance.
* @return the new or reused Display instance
*/
- public static Display createDisplay(String name, boolean reuse) {
+ public static Display createDisplay(final String name, final boolean reuse) {
return DisplayImpl.create(NativeWindowFactory.getNativeWindowType(true), name, 0, reuse);
}
@@ -133,7 +180,7 @@ public class NewtFactory {
* see {@link AbstractGraphicsDevice#getConnection()}. Use <code>null</code> for default.
* @return the new or reused Display instance
*/
- public static Display createDisplay(String type, String name) {
+ public static Display createDisplay(final String type, final String name) {
return createDisplay(type, name, true);
}
@@ -152,7 +199,7 @@ public class NewtFactory {
* @param reuse attempt to reuse an existing Display with same <code>name</code> if set true, otherwise create a new instance.
* @return the new or reused Display instance
*/
- public static Display createDisplay(String type, String name, boolean reuse) {
+ public static Display createDisplay(final String type, final String name, final boolean reuse) {
return DisplayImpl.create(type, name, 0, reuse);
}
@@ -166,7 +213,7 @@ public class NewtFactory {
* and {@link Display#removeReference()}.
* </p>
*/
- public static Screen createScreen(Display display, int index) {
+ public static Screen createScreen(final Display display, final int index) {
return ScreenImpl.create(display, index);
}
@@ -183,7 +230,7 @@ public class NewtFactory {
* and {@link Screen#removeReference()}.
* </p>
*/
- public static Window createWindow(CapabilitiesImmutable caps) {
+ public static Window createWindow(final CapabilitiesImmutable caps) {
return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), caps);
}
@@ -197,8 +244,8 @@ public class NewtFactory {
* and {@link Screen#removeReference()}.
* </p>
*/
- public static Window createWindow(Screen screen, CapabilitiesImmutable caps) {
- return createWindowImpl(screen, caps);
+ public static Window createWindow(final Screen screen, final CapabilitiesImmutable caps) {
+ return WindowImpl.create(null, 0, screen, caps);
}
/**
@@ -223,8 +270,11 @@ public class NewtFactory {
*
* @param parentWindowObject either a NativeWindow instance
*/
- public static Window createWindow(NativeWindow parentWindow, CapabilitiesImmutable caps) {
+ public static Window createWindow(final NativeWindow parentWindow, final CapabilitiesImmutable caps) {
final String type = NativeWindowFactory.getNativeWindowType(true);
+ if( null == parentWindow ) {
+ return createWindowImpl(type, caps);
+ }
Screen screen = null;
Window newtParentWindow = null;
@@ -234,18 +284,18 @@ public class NewtFactory {
screen = newtParentWindow.getScreen();
} else {
// create a Display/Screen compatible to the NativeWindow
- AbstractGraphicsConfiguration parentConfig = parentWindow.getGraphicsConfiguration();
+ final AbstractGraphicsConfiguration parentConfig = parentWindow.getGraphicsConfiguration();
if(null!=parentConfig) {
- AbstractGraphicsScreen parentScreen = parentConfig.getScreen();
- AbstractGraphicsDevice parentDevice = parentScreen.getDevice();
- Display display = NewtFactory.createDisplay(type, parentDevice.getHandle(), true);
+ final AbstractGraphicsScreen parentScreen = parentConfig.getScreen();
+ final AbstractGraphicsDevice parentDevice = parentScreen.getDevice();
+ final Display display = NewtFactory.createDisplay(type, parentDevice.getHandle(), true);
screen = NewtFactory.createScreen(display, parentScreen.getIndex());
} else {
- Display display = NewtFactory.createDisplay(type, null, true); // local display
+ final Display display = NewtFactory.createDisplay(type, null, true); // local display
screen = NewtFactory.createScreen(display, 0); // screen 0
}
}
- final Window win = createWindowImpl(parentWindow, screen, caps);
+ final Window win = WindowImpl.create(parentWindow, 0, screen, caps);
win.setSize(parentWindow.getWidth(), parentWindow.getHeight());
if ( null != newtParentWindow ) {
@@ -255,32 +305,26 @@ public class NewtFactory {
return win;
}
- protected static Window createWindowImpl(NativeWindow parentNativeWindow, Screen screen, CapabilitiesImmutable caps) {
- return WindowImpl.create(parentNativeWindow, 0, screen, caps);
- }
-
- protected static Window createWindowImpl(long parentWindowHandle, Screen screen, CapabilitiesImmutable caps) {
- return WindowImpl.create(null, parentWindowHandle, screen, caps);
- }
-
- protected static Window createWindowImpl(Screen screen, CapabilitiesImmutable caps) {
- return WindowImpl.create(null, 0, screen, caps);
- }
-
- protected static Window createWindowImpl(String type, CapabilitiesImmutable caps) {
- Display display = NewtFactory.createDisplay(type, null, true); // local display
- Screen screen = NewtFactory.createScreen(display, 0); // screen 0
+ private static Window createWindowImpl(final String type, final CapabilitiesImmutable caps) {
+ final Display display = NewtFactory.createDisplay(type, null, true); // local display
+ final Screen screen = NewtFactory.createScreen(display, 0); // screen 0
return WindowImpl.create(null, 0, screen, caps);
}
/**
* Create a child Window entity attached to the given parent, incl native creation<br>
*
- * @param parentWindowObject the native parent window handle
- * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always
+ * @param displayConnection the parent window's display connection
+ * @param screenIdx the desired screen index
+ * @param parentWindowHandle the native parent window handle
+ * @param caps the desired capabilities
+ * @return
*/
- public static Window createWindow(long parentWindowHandle, Screen screen, CapabilitiesImmutable caps) {
- return createWindowImpl(parentWindowHandle, screen, caps);
+ public static Window createWindow(final String displayConnection, final int screenIdx, final long parentWindowHandle, final CapabilitiesImmutable caps) {
+ final String type = NativeWindowFactory.getNativeWindowType(true);
+ final Display display = NewtFactory.createDisplay(type, displayConnection, true);
+ final Screen screen = NewtFactory.createScreen(display, screenIdx);
+ return WindowImpl.create(null, parentWindowHandle, screen, caps);
}
/**
@@ -290,26 +334,26 @@ public class NewtFactory {
*
* @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always
*/
- public static Window createWindow(Object[] cstrArguments, Screen screen, CapabilitiesImmutable caps) {
+ public static Window createWindow(final Object[] cstrArguments, final Screen screen, final CapabilitiesImmutable caps) {
return WindowImpl.create(cstrArguments, screen, caps);
}
/**
* Instantiate a Display entity using the native handle.
*/
- public static Display createDisplay(String type, long handle, boolean reuse) {
- return DisplayImpl.create(type, null, handle, false);
+ public static Display createDisplay(final String type, final long handle, final boolean reuse) {
+ return DisplayImpl.create(type, null, handle, reuse);
}
- public static boolean isScreenCompatible(NativeWindow parent, Screen childScreen) {
+ public static boolean isScreenCompatible(final NativeWindow parent, final Screen childScreen) {
// Get parent's NativeWindow details
- AbstractGraphicsConfiguration parentConfig = (AbstractGraphicsConfiguration) parent.getGraphicsConfiguration();
- AbstractGraphicsScreen parentScreen = (AbstractGraphicsScreen) parentConfig.getScreen();
- AbstractGraphicsDevice parentDevice = (AbstractGraphicsDevice) parentScreen.getDevice();
+ final AbstractGraphicsConfiguration parentConfig = parent.getGraphicsConfiguration();
+ final AbstractGraphicsScreen parentScreen = parentConfig.getScreen();
+ final AbstractGraphicsDevice parentDevice = parentScreen.getDevice();
- DisplayImpl childDisplay = (DisplayImpl) childScreen.getDisplay();
- String parentDisplayName = childDisplay.validateDisplayName(null, parentDevice.getHandle());
- String childDisplayName = childDisplay.getName();
+ final DisplayImpl childDisplay = (DisplayImpl) childScreen.getDisplay();
+ final String parentDisplayName = childDisplay.validateDisplayName(null, parentDevice.getHandle());
+ final String childDisplayName = childDisplay.getName();
if( ! parentDisplayName.equals( childDisplayName ) ) {
return false;
}
@@ -320,23 +364,23 @@ public class NewtFactory {
return true;
}
- public static Screen createCompatibleScreen(NativeWindow parent) {
+ public static Screen createCompatibleScreen(final NativeWindow parent) {
return createCompatibleScreen(parent, null);
}
- public static Screen createCompatibleScreen(NativeWindow parent, Screen childScreen) {
+ public static Screen createCompatibleScreen(final NativeWindow parent, final Screen childScreen) {
// Get parent's NativeWindow details
- AbstractGraphicsConfiguration parentConfig = (AbstractGraphicsConfiguration) parent.getGraphicsConfiguration();
- AbstractGraphicsScreen parentScreen = (AbstractGraphicsScreen) parentConfig.getScreen();
- AbstractGraphicsDevice parentDevice = (AbstractGraphicsDevice) parentScreen.getDevice();
+ final AbstractGraphicsConfiguration parentConfig = parent.getGraphicsConfiguration();
+ final AbstractGraphicsScreen parentScreen = parentConfig.getScreen();
+ final AbstractGraphicsDevice parentDevice = parentScreen.getDevice();
if(null != childScreen) {
// check if child Display/Screen is compatible already
- DisplayImpl childDisplay = (DisplayImpl) childScreen.getDisplay();
- String parentDisplayName = childDisplay.validateDisplayName(null, parentDevice.getHandle());
- String childDisplayName = childDisplay.getName();
- boolean displayEqual = parentDisplayName.equals( childDisplayName );
- boolean screenEqual = parentScreen.getIndex() == childScreen.getIndex();
+ final DisplayImpl childDisplay = (DisplayImpl) childScreen.getDisplay();
+ final String parentDisplayName = childDisplay.validateDisplayName(null, parentDevice.getHandle());
+ final String childDisplayName = childDisplay.getName();
+ final boolean displayEqual = parentDisplayName.equals( childDisplayName );
+ final boolean screenEqual = parentScreen.getIndex() == childScreen.getIndex();
if(DEBUG_IMPLEMENTATION) {
System.err.println("NewtFactory.createCompatibleScreen: Display: "+
parentDisplayName+" =? "+childDisplayName+" : "+displayEqual+"; Screen: "+
@@ -350,7 +394,7 @@ public class NewtFactory {
// Prep NEWT's Display and Screen according to the parent
final String type = NativeWindowFactory.getNativeWindowType(true);
- Display display = NewtFactory.createDisplay(type, parentDevice.getHandle(), true);
+ final Display display = NewtFactory.createDisplay(type, parentDevice.getHandle(), true);
return NewtFactory.createScreen(display, parentScreen.getIndex());
}
}
diff --git a/src/newt/classes/com/jogamp/newt/NewtVersion.java b/src/newt/classes/com/jogamp/newt/NewtVersion.java
index 961ffdf6a..f4cdee487 100644
--- a/src/newt/classes/com/jogamp/newt/NewtVersion.java
+++ b/src/newt/classes/com/jogamp/newt/NewtVersion.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,12 +20,12 @@
* 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 com.jogamp.newt;
import com.jogamp.common.GlueGenVersion;
@@ -38,7 +38,7 @@ public class NewtVersion extends JogampVersion {
protected static volatile NewtVersion jogampCommonVersionInfo;
- protected NewtVersion(String packageName, Manifest mf) {
+ protected NewtVersion(final String packageName, final Manifest mf) {
super(packageName, mf);
}
@@ -46,16 +46,17 @@ public class NewtVersion extends JogampVersion {
if(null == jogampCommonVersionInfo) { // volatile: ok
synchronized(NewtVersion.class) {
if( null == jogampCommonVersionInfo ) {
- final String packageName = "com.jogamp.newt";
- final Manifest mf = VersionUtil.getManifest(NewtVersion.class.getClassLoader(), packageName);
- jogampCommonVersionInfo = new NewtVersion(packageName, mf);
+ final String packageName1 = "com.jogamp.newt"; // atomic packaging - and identity
+ final String packageName2 = "javax.media.opengl"; // all packaging
+ final Manifest mf = VersionUtil.getManifest(NativeWindowVersion.class.getClassLoader(), new String[]{ packageName1, packageName2 } );
+ jogampCommonVersionInfo = new NewtVersion(packageName1, mf);
}
}
}
return jogampCommonVersionInfo;
}
- public static void main(String args[]) {
+ public static void main(final String args[]) {
System.err.println(VersionUtil.getPlatformInfo());
System.err.println(GlueGenVersion.getInstance());
System.err.println(NativeWindowVersion.getInstance());
diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java
index 26f19ad6b..0ba557972 100644
--- a/src/newt/classes/com/jogamp/newt/Screen.java
+++ b/src/newt/classes/com/jogamp/newt/Screen.java
@@ -27,14 +27,34 @@
*/
package com.jogamp.newt;
-import com.jogamp.newt.event.ScreenModeListener;
+import com.jogamp.newt.event.MonitorModeListener;
+
import jogamp.newt.Debug;
+
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+
import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.util.Rectangle;
+import javax.media.nativewindow.util.RectangleImmutable;
+/**
+ * A screen may span multiple {@link MonitorDevice}s representing their combined virtual size.
+ * <p>
+ * All values of this interface are represented in pixel units, if not stated otherwise.
+ * </p>
+ *
+ * <a name="coordinateSystem"><h5>Coordinate System</h5></a>
+ * <p>
+ * <ul>
+ * <li>Screen space has it's origin in the top-left corner, and may not be at 0/0.</li>
+ * <li>{@link #getViewport() Virtual viewport} covers all {@link MonitorDevice}s {@link MonitorDevice#getViewport() viewports} and has it's origin in the top-left corner, and may not be at 0/0.</li>
+ * </ul>
+ * </p>
+*/
public abstract class Screen {
/**
@@ -46,20 +66,22 @@ public abstract class Screen {
public static final boolean DEBUG = Debug.debug("Screen");
/** return precomputed hashCode from FQN {@link #getFQName()} */
+ @Override
public abstract int hashCode();
/** return true if obj is of type Display and both FQN {@link #getFQName()} equals */
- public boolean equals(Object obj) {
+ @Override
+ public boolean equals(final Object obj) {
if (this == obj) { return true; }
if (obj instanceof Screen) {
- Screen s = (Screen)obj;
+ final Screen s = (Screen)obj;
return s.getFQName().equals(getFQName());
}
return false;
}
/**
- * Manual trigger the native creation, if it is not done yet..<br>
+ * Manual trigger the native creation, if not done yet..<br>
* This is useful to be able to request the {@link javax.media.nativewindow.AbstractGraphicsScreen}, via
* {@link #getGraphicsScreen()}.<br>
* Otherwise the abstract device won't be available before the dependent component (Window) is realized.
@@ -89,13 +111,14 @@ public abstract class Screen {
public abstract boolean isNativeValid();
/**
- * @return number of references by Window
+ * @return number of references
*/
public abstract int getReferenceCount();
/**
* See {@link Display#addReference()}
*
+ * @return number of references post operation
* @throws NativeWindowException if the native creation failed.
* @see #removeReference()
* @see #setDestroyWhenUnused(boolean)
@@ -106,6 +129,7 @@ public abstract class Screen {
/**
* See {@link Display#removeReference()}
*
+ * @return number of references post operation
* @see #addReference()
* @see #setDestroyWhenUnused(boolean)
* @see #getDestroyWhenUnused()
@@ -120,81 +144,121 @@ public abstract class Screen {
public abstract int getIndex();
/**
- * @return the x position of the virtual top-left origin.
+ * See <a href="#coordinateSystem"> Coordinate System</a>.
+ *
+ * @return the x position of the virtual viewport's top-left origin in pixel units.
*/
public abstract int getX();
-
+
/**
- * @return the y position of the virtual top-left origin.
+ * See <a href="#coordinateSystem"> Coordinate System</a>.
+ *
+ * @return the y position of the virtual viewport's top-left origin in pixel units.
*/
public abstract int getY();
-
+
/**
- * @return the <b>rotated</b> virtual width.
+ * @return the <b>rotated</b> virtual viewport's width in pixel units.
*/
public abstract int getWidth();
/**
- * @return the <b>rotated</b> virtual height.
+ * @return the <b>rotated</b> virtual viewport's height in pixel units.
*/
public abstract int getHeight();
/**
+ * See <a href="#coordinateSystem"> Coordinate System</a>.
+ *
+ * @return the <b>rotated</b> virtual viewport, i.e. top-left origin and size, in pixel units.
+ * @see #getViewportInWindowUnits()
+ */
+ public abstract RectangleImmutable getViewport();
+
+ /**
+ * See <a href="#coordinateSystem"> Coordinate System</a>.
+ *
+ * @return the <b>rotated</b> virtual viewport, i.e. top-left origin and size, in window units.
+ * @see #getViewport()
+ */
+ public abstract RectangleImmutable getViewportInWindowUnits();
+
+ /**
* @return the associated Display
*/
public abstract Display getDisplay();
- /**
- * @return the screen fully qualified Screen name,
+ /**
+ * @return The screen fully qualified Screen name,
* which is a key of {@link com.jogamp.newt.Display#getFQName()} + {@link #getIndex()}.
*/
public abstract String getFQName();
/**
- * @param sml ScreenModeListener to be added for ScreenMode change events
+ * Return a list of all {@link MonitorMode}s for all {@link MonitorDevice}s.
+ * <p>
+ * The list is ordered in descending order,
+ * see {@link MonitorMode#compareTo(MonitorMode)}.
+ * </p>
*/
- public abstract void addScreenModeListener(ScreenModeListener sml);
+ public abstract List<MonitorMode> getMonitorModes();
/**
- * @param sml ScreenModeListener to be removed from ScreenMode change events
+ * Return a list of available {@link MonitorDevice}s.
*/
- public abstract void removeScreenModeListener(ScreenModeListener sml);
+ public abstract List<MonitorDevice> getMonitorDevices();
- /**
- * Return a list of available {@link com.jogamp.newt.ScreenMode ScreenMode}s.
+ /**
+ * Returns the {@link MonitorDevice} with the highest {@link MonitorDevice#getViewportInWindowUnits() viewport}
+ * {@link RectangleImmutable#coverage(RectangleImmutable) coverage} of the given rectangle in window units.
* <p>
- * If {@link com.jogamp.newt.ScreenMode ScreenMode}s are not supported for this
- * native type {@link com.jogamp.newt.Display#getType()}, it returns a list of size one with the current screen size.</p>
- *
- * @return a shallow copy of the internal immutable {@link com.jogamp.newt.ScreenMode ScreenMode}s.
+ * If no coverage is detected the first {@link MonitorDevice} is returned.
+ * </p>
+ * @param r arbitrary rectangle in window units
*/
- public abstract List<ScreenMode> getScreenModes();
+ public final MonitorDevice getMainMonitor(final RectangleImmutable r) {
+ MonitorDevice res = null;
+ float maxCoverage = Float.MIN_VALUE;
+ final List<MonitorDevice> monitors = getMonitorDevices();
+ for(int i=monitors.size()-1; i>=0; i--) {
+ final MonitorDevice monitor = monitors.get(i);
+ final float coverage = monitor.getViewportInWindowUnits().coverage(r);
+ if( coverage > maxCoverage ) {
+ maxCoverage = coverage;
+ res = monitor;
+ }
+ }
+ if( maxCoverage > 0.0f && null != res ) {
+ return res;
+ }
+ return monitors.get(0);
+ }
/**
- * Return the original {@link com.jogamp.newt.ScreenMode}, as used at NEWT initialization.
- * @return original ScreenMode which is element of the list {@link #getScreenModes()}.
+ * Calculates the union of all monitor's {@link MonitorDevice#getViewport() viewport} in pixel- and window units.
+ * <p>
+ * Should be equal to {@link #getX()}, {@link #getY()}, {@link #getWidth()} and {@link #getHeight()},
+ * however, some native toolkits may choose a different virtual screen area.
+ * </p>
+ * @param viewport storage for result in pixel units, maybe null
+ * @param viewportInWindowUnits storage for result in window units, maybe null
*/
- public abstract ScreenMode getOriginalScreenMode();
+ public final void unionOfMonitorViewports(final Rectangle viewport, final Rectangle viewportInWindowUnits) {
+ MonitorDevice.unionOfViewports(viewport, viewportInWindowUnits, getMonitorDevices());
+ }
/**
- * Return the current {@link com.jogamp.newt.ScreenMode}.
- * <p>
- * If {@link com.jogamp.newt.ScreenMode ScreenMode}s are not supported for this
- * native type {@link com.jogamp.newt.Display#getType()}, it returns one with the current screen size. </p>
- *
- * @return current ScreenMode which is element of the list {@link #getScreenModes()}.
+ * @param sml {@link MonitorModeListener} to be added for {@link MonitorEvent}
*/
- public abstract ScreenMode getCurrentScreenMode();
+ public abstract void addMonitorModeListener(MonitorModeListener sml);
/**
- * Set the current {@link com.jogamp.newt.ScreenMode}.
- * @param screenMode to be made current, must be element of the list {@link #getScreenModes()}.
- * @return true if successful, otherwise false
+ * @param sml {@link MonitorModeListener} to be removed from {@link MonitorEvent}
*/
- public abstract boolean setCurrentScreenMode(ScreenMode screenMode);
+ public abstract void removeMonitorModeListener(MonitorModeListener sml);
// Global Screens
- protected static ArrayList<Screen> screenList = new ArrayList<Screen>();
+ protected static final ArrayList<WeakReference<Screen>> screenList = new ArrayList<WeakReference<Screen>>();
protected static int screensActive = 0;
/**
@@ -204,7 +268,7 @@ public abstract class Screen {
* @param fromIndex start index, then increasing until found or end of list *
* @return
*/
- public static Screen getFirstScreenOf(Display display, int idx, int fromIndex) {
+ public static Screen getFirstScreenOf(final Display display, final int idx, final int fromIndex) {
return getScreenOfImpl(display, idx, fromIndex, 1);
}
@@ -215,29 +279,64 @@ public abstract class Screen {
* @param fromIndex start index, then decreasing until found or end of list. -1 is interpreted as size - 1.
* @return
*/
- public static Screen getLastScreenOf(Display display, int idx, int fromIndex) {
+ public static Screen getLastScreenOf(final Display display, final int idx, final int fromIndex) {
return getScreenOfImpl(display, idx, fromIndex, -1);
}
- private static Screen getScreenOfImpl(Display display, int idx, int fromIndex, int incr) {
+ private static Screen getScreenOfImpl(final Display display, final int idx, final int fromIndex, final int incr) {
synchronized(screenList) {
int i = fromIndex >= 0 ? fromIndex : screenList.size() - 1 ;
while( ( incr > 0 ) ? i < screenList.size() : i >= 0 ) {
- Screen screen = (Screen) screenList.get(i);
- if( screen.getDisplay().equals(display) &&
- screen.getIndex() == idx ) {
- return screen;
+ final Screen screen = screenList.get(i).get();
+ if( null == screen ) {
+ // Clear GC'ed dead reference entry!
+ screenList.remove(i);
+ if( incr < 0 ) {
+ // decrease
+ i+=incr;
+ } // else nop - remove shifted subsequent elements to the left
+ } else {
+ if( screen.getDisplay().equals(display) &&
+ screen.getIndex() == idx ) {
+ return screen;
+ }
+ i+=incr;
}
- i+=incr;
}
}
return null;
}
- /** Returns the global display collection */
+
+ protected static void addScreen2List(final Screen screen) {
+ synchronized(screenList) {
+ // GC before add
+ int i=0;
+ while( i < screenList.size() ) {
+ if( null == screenList.get(i).get() ) {
+ screenList.remove(i);
+ } else {
+ i++;
+ }
+ }
+ screenList.add(new WeakReference<Screen>(screen));
+ }
+ }
+
+ /** Returns the global screen collection */
public static Collection<Screen> getAllScreens() {
ArrayList<Screen> list;
synchronized(screenList) {
- list = (ArrayList<Screen>) screenList.clone();
+ list = new ArrayList<Screen>();
+ int i = 0;
+ while( i < screenList.size() ) {
+ final Screen s = screenList.get(i).get();
+ if( null == s ) {
+ screenList.remove(i);
+ } else {
+ list.add( screenList.get(i).get() );
+ i++;
+ }
+ }
}
return list;
}
diff --git a/src/newt/classes/com/jogamp/newt/ScreenMode.java b/src/newt/classes/com/jogamp/newt/ScreenMode.java
deleted file mode 100644
index 1f12217bb..000000000
--- a/src/newt/classes/com/jogamp/newt/ScreenMode.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/**
- * Copyright 2010 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 com.jogamp.newt;
-
-import javax.media.nativewindow.util.DimensionImmutable;
-
-import com.jogamp.newt.util.MonitorMode;
-
-/** Immutable ScreenMode Class, consisting of it's read only components:<br>
- * <ul>
- * <li>{@link com.jogamp.newt.util.MonitorMode}, non rotated values</li>
- * <li><code>rotation</code>, measured counter clockwise (CCW)</li>
- * </ul>
- *
- * <i>Aquire and filter ScreenModes</i><br>
- * <ul>
- * <li>A List of read only ScreenMode's is being returned by {@link com.jogamp.newt.Screen#getScreenModes()}.</li>
- * <li>You may utilize {@link com.jogamp.newt.util.ScreenModeUtil} to filter and select a desired ScreenMode.</li>
- * <li>The current ScreenMode can be obtained via {@link com.jogamp.newt.Screen#getCurrentScreenMode()}.</li>
- * <li>The initial original ScreenMode (at startup) can be obtained via {@link com.jogamp.newt.Screen#getOriginalScreenMode()}.</li>
- * </ul>
- * <br>
- *
- * <i>Changing ScreenModes</i><br>
- * <ul>
- * <li> Use {@link com.jogamp.newt.Screen#setCurrentScreenMode(com.jogamp.newt.ScreenMode)}</li>
- * to change the current ScreenMode of all Screen's referenced via the full qualified name (FQN)
- * {@link com.jogamp.newt.Screen#getFQName()}.</li>
- * <li> When the last FQN referenced Screen closes, the original ScreenMode ({@link com.jogamp.newt.Screen#getOriginalScreenMode()})
- * is restored.</li>
- * </ul>
- * <br>
- * Example for changing the ScreenMode:
- * <pre>
- // determine target refresh rate
- ScreenMode orig = screen.getOriginalScreenMode();
- int freq = orig.getMonitorMode().getRefreshRate();
-
- // target resolution
- Dimension res = new Dimension(800, 600);
-
- // target rotation
- int rot = 0;
-
- // filter available ScreenModes
- List screenModes = screen.getScreenModes();
- screenModes = ScreenModeUtil.filterByRate(screenModes, freq); // get the nearest ones
- screenModes = ScreenModeUtil.filterByRotation(screenModes, rot);
- screenModes = ScreenModeUtil.filterByResolution(screenModes, res); // get the nearest ones
- screenModes = ScreenModeUtil.getHighestAvailableBpp(screenModes);
-
- // pick 1st one ..
- screen.setCurrentScreenMode((ScreenMode) screenModes.get(0));
- * </pre>
- *
- * X11 / AMD just works<br>
- * <br>
- * X11 / NVidia difficulties
- * <pre>
- NVidia RANDR RefreshRate Bug
- If NVidia's 'DynamicTwinView' is enabled, all refresh rates are
- unique, ie consequent numbers starting with the default refresh, ie 50, 51, ..
- The only way to workaround it is to disable 'DynamicTwinView'.
- Read: http://us.download.nvidia.com/XFree86/Linux-x86/260.19.12/README/configtwinview.html
-
- Check to see if 'DynamicTwinView' is enable:
- nvidia-settings -q :0/DynamicTwinview
-
- To disable it (workaround), add the following option to your xorg.conf device section:
- Option "DynamicTwinView" "False"
-
- NVidia RANDR Rotation:
- To enable it, add the following option to your xorg.conf device section:
- Option "RandRRotation" "on"
- * </pre>
- *
- */
-public class ScreenMode {
- /** zero rotation, compared to normal settings */
- public static final int ROTATE_0 = 0;
-
- /** 90 degrees CCW rotation */
- public static final int ROTATE_90 = 90;
-
- /** 180 degrees CCW rotation */
- public static final int ROTATE_180 = 180;
-
- /** 270 degrees CCW rotation */
- public static final int ROTATE_270 = 270;
-
- MonitorMode monitorMode;
- int rotation;
-
- public static boolean isRotationValid(int rotation) {
- return rotation == ScreenMode.ROTATE_0 || rotation == ScreenMode.ROTATE_90 ||
- rotation == ScreenMode.ROTATE_180 || rotation == ScreenMode.ROTATE_270 ;
- }
-
- /**
- * @param monitorMode the monitor mode
- * @param rotation the screen rotation, measured counter clockwise (CCW)
- */
- public ScreenMode(MonitorMode monitorMode, int rotation) {
- if ( !isRotationValid(rotation) ) {
- throw new RuntimeException("invalid rotation: "+rotation);
- }
- this.monitorMode = monitorMode;
- this.rotation = rotation;
- }
-
- /** Returns the unrotated <code>MonitorMode</code> */
- public final MonitorMode getMonitorMode() {
- return monitorMode;
- }
-
- /** Returns the CCW rotation of this mode */
- public final int getRotation() {
- return rotation;
- }
-
- /** Returns the rotated screen width,
- * derived from <code>getMonitorMode().getSurfaceSize().getResolution()</code>
- * and <code>getRotation()</code>
- */
- public final int getRotatedWidth() {
- return getRotatedWH(true);
- }
-
- /** Returns the rotated screen height,
- * derived from <code>getMonitorMode().getSurfaceSize().getResolution()</code>
- * and <code>getRotation()</code>
- */
- public final int getRotatedHeight() {
- return getRotatedWH(false);
- }
-
- public final String toString() {
- return "[ " + getMonitorMode() + ", " + rotation + " degr ]";
- }
-
- /**
- * Tests equality of two <code>ScreenMode</code> objects
- * by evaluating equality of it's components:<br>
- * <ul>
- * <li><code>monitorMode</code></li>
- * <li><code>rotation</code></li>
- * </ul>
- * <br>
- */
- public final boolean equals(Object obj) {
- if (this == obj) { return true; }
- if (obj instanceof ScreenMode) {
- ScreenMode sm = (ScreenMode)obj;
- return sm.getMonitorMode().equals(getMonitorMode()) &&
- sm.getRotation() == this.getRotation() ;
- }
- return false;
- }
-
- /**
- * Returns a combined hash code of it's elements:<br>
- * <ul>
- * <li><code>monitorMode</code></li>
- * <li><code>rotation</code></li>
- * </ul>
- */
- public final int hashCode() {
- // 31 * x == (x << 5) - x
- int hash = 31 + getMonitorMode().hashCode();
- hash = ((hash << 5) - hash) + getRotation();
- return hash;
- }
-
- private final int getRotatedWH(boolean width) {
- final DimensionImmutable d = getMonitorMode().getSurfaceSize().getResolution();
- final boolean swap = ScreenMode.ROTATE_90 == rotation || ScreenMode.ROTATE_270 == rotation ;
- if ( ( width && swap ) || ( !width && !swap ) ) {
- return d.getHeight();
- }
- return d.getWidth();
- }
-}
diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java
index 78e2abc6e..ec6d767fa 100644
--- a/src/newt/classes/com/jogamp/newt/Window.java
+++ b/src/newt/classes/com/jogamp/newt/Window.java
@@ -28,16 +28,28 @@
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;
import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.MouseListener;
+
import jogamp.newt.Debug;
+import jogamp.newt.WindowImpl;
+
import javax.media.nativewindow.CapabilitiesChooser;
import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.nativewindow.NativeWindow;
+import javax.media.nativewindow.ScalableSurface;
import javax.media.nativewindow.WindowClosingProtocol;
+import javax.media.nativewindow.util.Rectangle;
+import javax.media.nativewindow.util.RectangleImmutable;
+import javax.media.nativewindow.util.SurfaceSize;
/**
* Specifying NEWT's Window functionality:
@@ -50,12 +62,41 @@ import javax.media.nativewindow.WindowClosingProtocol;
* <li>... and more</li>
* </ul>
* <p>
- * One use case is {@link com.jogamp.newt.opengl.GLWindow}, which delegates
- * window operation to an instance of this interface while providing OpenGL
+ * One use case is {@link com.jogamp.newt.opengl.GLWindow}, which delegates
+ * window operation to an instance of this interface while providing OpenGL
* functionality.
* </p>
+ * <p>
+ * All values of this interface are represented in window units, if not stated otherwise.
+ * </p>
+ *
+ * <a name="coordinateSystem"><h5>Coordinate System</h5></a>
+ * <p>
+ * <ul>
+ * <li>Screen space has it's origin in the top-left corner, and may not be at 0/0.</li>
+ * <li>Window origin is in it's top-left corner, see {@link #getX()} and {@link #getY()}. </li>
+ * <li>Window client-area excludes {@link #getInsets() insets}, i.e. window decoration.</li>
+ * <li>Window origin is relative to it's parent window if exist, or the screen position (top-level).</li>
+ * </ul>
+ * See {@link NativeWindow} and {@link Screen}.
+ * </p>
+ * <a name="customwindowicons"><h5>Custom Window Icons</h5></a>
+ * <p>
+ * Custom window icons can be defined via system property <code>newt.window.icons</code>,
+ * which shall contain a space separated list of PNG icon locations from low- to high-resolution.
+ * The location must be resolvable via classpath, i.e. shall reference a location within the jar file.
+ * Example (our default):
+ * <pre>
+ * -Dnewt.window.icons="newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png"
+ * -Djnlp.newt.window.icons="newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png"
+ * </pre>
+ * The property can also be set programmatically, which must happen before any NEWT classes are <i>touched</i>:
+ * <pre>
+ * System.setProperty("newt.window.icons", "newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png");
+ * </pre>
+ * </p>
*/
-public interface Window extends NativeWindow, WindowClosingProtocol {
+public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSurface {
public static final boolean DEBUG_MOUSE_EVENT = Debug.debug("Window.MouseEvent");
public static final boolean DEBUG_KEY_EVENT = Debug.debug("Window.KeyEvent");
public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window");
@@ -77,11 +118,20 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
boolean isNativeValid();
/**
- * @return The associated Screen
+ * @return The associated {@link Screen}
*/
Screen getScreen();
/**
+ * Returns the {@link MonitorDevice} with the highest {@link MonitorDevice#getViewportInWindowUnits() viewport}
+ * {@link RectangleImmutable#coverage(RectangleImmutable) coverage} of this window.
+ * <p>
+ * If no coverage is detected the first {@link MonitorDevice} is returned.
+ * </p>
+ */
+ MonitorDevice getMainMonitor();
+
+ /**
* Set the CapabilitiesChooser to help determine the native visual type.
*
* @param chooser the new CapabilitiesChooser
@@ -104,14 +154,26 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
CapabilitiesImmutable getChosenCapabilities();
/**
- * Destroy the Window and it's children, incl. native destruction.<br>
- * The Window can be recreate via {@link #setVisible(boolean) setVisible(true)}.
- * <p>Visibility is set to false.</p>
+ * {@inheritDoc}
+ * <p>
+ * Also iterates through this window's children and destroys them.
+ * </p>
+ * <p>
+ * Visibility is set to false.
+ * </p>
+ * <p>
+ * Method sends out {@link WindowEvent#EVENT_WINDOW_DESTROY_NOTIFY pre-} and
+ * {@link WindowEvent#EVENT_WINDOW_DESTROYED post-} destruction events
+ * to all of it's {@link WindowListener}.
+ * </p>
* <p>
* This method invokes {@link Screen#removeReference()} after it's own destruction,<br>
* which will issue {@link Screen#destroy()} if the reference count becomes 0.<br>
* This destruction sequence shall end up in {@link Display#destroy()}, if all reference counts become 0.
* </p>
+ * <p>
+ * The Window can be recreate via {@link #setVisible(boolean) setVisible(true)}.
+ * </p>
* @see #destroy()
* @see #setVisible(boolean)
*/
@@ -119,17 +181,38 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
void destroy();
/**
- * <code>setVisible</code> makes the window and children visible if <code>visible</code> is true,
+ * Set a custom action handling destruction issued by a {@link WindowImpl#windowDestroyNotify(boolean) toolkit triggered window destroy}
+ * replacing the default {@link #destroy()} action.
+ * <p>
+ * The custom action shall call {@link #destroy()}
+ * but may perform further tasks before and after.
+ * </p>
+ */
+ void setWindowDestroyNotifyAction(Runnable r);
+
+ /**
+ * Calls {@link #setVisible(boolean, boolean) setVisible(true, visible)},
+ * i.e. blocks until the window becomes visible.
+ * @see #setVisible(boolean, boolean)
+ */
+ void setVisible(boolean visible);
+
+ /**
+ * <code>setVisible(..)</code> makes the window and children visible if <code>visible</code> is true,
* otherwise the window and children becomes invisible.
* <p>
- * The <code>setVisible(true)</code> is responsible to actual create the native window.
+ * <code>setVisible(wait, true)</code> is responsible to actual create the native window.
+ * </p>
+ * <p>
+ * If <code>wait</code> is true, method blocks until window is {@link #isVisible() visible} and {@link #isNativeValid() valid},
+ * otherwise method returns immediately.
* </p>
* <p>
* Zero size semantics are respected, see {@link #setSize(int,int)}:<br>
* <pre>
* if ( 0 == windowHandle && visible ) {
* this.visible = visible;
- * if( 0 &lt; width*height ) {
+ * if( 0 &lt; width && 0 &lt; height ) {
* createNative();
* }
* } else if ( this.visible != visible ) {
@@ -139,12 +222,12 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
* </pre></p>
* <p>
* In case this window is a child window and has a {@link javax.media.nativewindow.NativeWindow} parent,<br>
- * <code>setVisible(true)</code> has no effect as long the parent's is not valid yet,
+ * <code>setVisible(wait, true)</code> has no effect as long the parent's is not valid yet,
* i.e. {@link javax.media.nativewindow.NativeWindow#getWindowHandle()} returns <code>null</code>.<br>
- * <code>setVisible(true)</code> shall be repeated when the parent becomes valid.
+ * <code>setVisible(wait, true)</code> shall be repeated when the parent becomes valid.
* </p>
*/
- void setVisible(boolean visible);
+ void setVisible(boolean wait, boolean visible);
boolean isVisible();
@@ -166,14 +249,40 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
//
/**
- * Sets the size of the window's client area, excluding decorations.
+ * Returns a newly created {@link Rectangle} containing window origin, {@link #getX()} & {@link #getY()},
+ * and size, {@link #getWidth()} & {@link #getHeight()}, in window units.
+ */
+ Rectangle getBounds();
+
+ /**
+ * Returns the <i>pixels per millimeter</i> of this window's {@link NativeSurface}
+ * according to the {@link #getMainMonitor() main monitor}'s <i>current</i> {@link MonitorMode mode}'s
+ * {@link SurfaceSize#getResolution() surface resolution}.
+ * <p>
+ * Method takes the {@link #getCurrentSurfaceScale(int[]) current surface-scale} and {@link #getNativeSurfaceScale(int[]) native surface-scale}
+ * into account, i.e.:
+ * <pre>
+ * surfacePpMM = monitorPpMM * currentSurfaceScale / nativeSurfaceScale,
+ * with PpMM == pixel per millimeter
+ * </pre>
+ * </p>
+ * <p>
+ * To convert the result to <i>dpi</i>, i.e. dots-per-inch, multiply both components with <code>25.4f</code>.
+ * </p>
+ * @param ppmmStore float[2] storage for the ppmm result
+ * @return the passed storage containing the ppmm for chaining
+ */
+ float[] getPixelsPerMM(final float[] ppmmStore);
+
+ /**
+ * Sets the size of the window's client area in window units, excluding decorations.
*
* <p>
* Zero size semantics are respected, see {@link #setVisible(boolean)}:<br>
* <pre>
- * if ( 0 != windowHandle && 0 &ge; width*height && visible ) {
+ * if ( visible && 0 != windowHandle && ( 0 &ge; width || 0 &ge; height ) ) {
* setVisible(false);
- * } else if ( 0 == windowHandle && 0 &lt; width*height && visible ) {
+ * } else if ( visible && 0 == windowHandle && 0 &lt; width && 0 &lt; height ) {
* setVisible(true);
* } else {
* // as expected ..
@@ -182,22 +291,54 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
* <p>
* This call is ignored if in fullscreen mode.<br></p>
*
- * @param width of the window's client area
- * @param height of the window's client area
+ * @param width of the window's client area in window units
+ * @param height of the window's client area in window units
*
+ * @see #setSurfaceSize(int, int)
+ * @see #setTopLevelSize(int, int)
* @see #getInsets()
*/
void setSize(int width, int height);
/**
- * Sets the size of the top-level window including insets (window decorations).
+ * Sets the size of the window's surface in pixel units which claims the window's client area excluding decorations.
+ *
+ * <p>
+ * In multiple monitor mode, setting the window's surface size in pixel units
+ * might not be possible due to unknown <i>scale</i> values of the target display.
+ * Hence re-setting the pixel unit size after window creation is recommended.
+ * </p>
+ * <p>
+ * Zero size semantics are respected, see {@link #setVisible(boolean)}:<br>
+ * <pre>
+ * if ( visible && 0 != windowHandle && ( 0 &ge; width || 0 &ge; height ) ) {
+ * setVisible(false);
+ * } else if ( visible && 0 == windowHandle && 0 &lt; width && 0 &lt; height ) {
+ * setVisible(true);
+ * } else {
+ * // as expected ..
+ * }
+ * </pre></p>
+ * <p>
+ * This call is ignored if in fullscreen mode.<br></p>
+ *
+ * @param pixelWidth of the window's client area in pixel units
+ * @param pixelHeight of the window's client area in pixel units
+ *
+ * @see #setSize(int, int)
+ * @see #getInsets()
+ */
+ void setSurfaceSize(int pixelWidth, int pixelHeight);
+
+ /**
+ * Sets the size of the top-level window including insets (window decorations) in window units.
*
* <p>
* Note: Insets (if supported) are available only after the window is set visible and hence has been created.
* </p>
*
- * @param width of the top-level window area
- * @param height of the top-level window area
+ * @param width of the top-level window area in window units
+ * @param height of the top-level window area in window units
*
* @see #setSize(int, int)
* @see #getInsets()
@@ -205,19 +346,19 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
void setTopLevelSize(int width, int height);
/**
- * Sets the location of the window's client area, excluding insets (window decorations).<br>
+ * Sets the location of the window's client area excluding insets (window decorations) in window units.<br>
*
* This call is ignored if in fullscreen mode.<br>
*
- * @param x coord of the client-area's top left corner
- * @param y coord of the client-area's top left corner
+ * @param x coord of the client-area's top left corner in window units
+ * @param y coord of the client-area's top left corner in window units
*
* @see #getInsets()
*/
void setPosition(int x, int y);
/**
- * Sets the location of the top-level window inclusive insets (window decorations).<br>
+ * Sets the location of the top-level window inclusive insets (window decorations) in window units.<br>
*
* <p>
* Note: Insets (if supported) are available only after the window is set visible and hence has been created.
@@ -225,8 +366,8 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
*
* This call is ignored if in fullscreen mode.<br>
*
- * @param x coord of the top-level left corner
- * @param y coord of the top-level left corner
+ * @param x coord of the top-level left corner in window units
+ * @param y coord of the top-level left corner in window units
*
* @see #setPosition(int, int)
* @see #getInsets()
@@ -257,6 +398,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();
@@ -276,10 +431,10 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
void confinePointer(boolean confine);
/**
- * Moves the pointer to x/y relative to this window's origin.
+ * Moves the pointer to x/y relative to this window's origin in pixel units.
*
- * @param x relative pointer x position within this window
- * @param y relative pointer y position within this window
+ * @param x relative pointer x position within this window in pixel units
+ * @param y relative pointer y position within this window in pixel units
*
* @see #confinePointer(boolean)
*/
@@ -303,6 +458,11 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
ACTION_NATIVE_CREATION_PENDING;
}
+ /** Reparenting hint (bitfield value): Force destroy and hence {@link ReparentOperation#ACTION_NATIVE_CREATION re-creating} the window. */
+ public static final int REPARENT_HINT_FORCE_RECREATION = 1 << 0;
+ /** Reparenting hint (bitfield value): Claim window becomes visible after reparenting, which is important for e.g. preserving the GL-states in case window is invisible while reparenting. */
+ public static final int REPARENT_HINT_BECOMES_VISIBLE = 1 << 1;
+
/**
* Change this window's parent window.<br>
* <P>
@@ -312,15 +472,40 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
* this window is added to it's list of children.<br></P>
*
* @param newParent The new parent NativeWindow. If null, this Window becomes a top level window.
+ * @param x new top-level position in window units, use -1 for default position.
+ * @param y new top-level position in window units, use -1 for default position.
+ * @param hints May contain hints (bitfield values) like {@link #REPARENT_HINT_FORCE_RECREATION} or {@link #REPARENT_HINT_BECOMES_VISIBLE}.
*
* @return The issued reparent action type (strategy) as defined in Window.ReparentAction
*/
- ReparentOperation reparentWindow(NativeWindow newParent);
-
- ReparentOperation reparentWindow(NativeWindow newParent, boolean forceDestroyCreate);
+ ReparentOperation reparentWindow(NativeWindow newParent, int x, int y, int hints);
+ /**
+ * Enable or disable fullscreen mode for this window.
+ * <p>
+ * Fullscreen mode is established on the {@link #getMainMonitor() main monitor}.
+ * </p>
+ * @param fullscreen enable or disable fullscreen mode
+ * @return success
+ * @see #setFullscreen(List)
+ * @see #isFullscreen()
+ */
boolean setFullscreen(boolean fullscreen);
+ /**
+ * Enable fullscreen mode for this window spanning across the given {@link MonitorDevice}s
+ * or across all {@link MonitorDevice}s.
+ * <p>
+ * Disable fullscreen via {@link #setFullscreen(boolean)}.
+ * </p>
+ * @param monitors if <code>null</code> fullscreen will be spanned across all {@link MonitorDevice}s,
+ * otherwise across the given list of {@link MonitorDevice}.
+ * @return success
+ * @see #setFullscreen(boolean)
+ * @see #isFullscreen()
+ */
+ boolean setFullscreen(List<MonitorDevice> monitors);
+
boolean isFullscreen();
static interface FocusRunnable {
@@ -345,7 +530,11 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
* Sets a {@link KeyListener} allowing focus traversal with a covered window toolkit like AWT.
* <p>
* The {@link KeyListener} methods are invoked prior to all other {@link KeyListener}'s
- * allowing to suppress the {@link KeyEvent} via the {@link InputEvent#consumedTag}.
+ * allowing to suppress the {@link KeyEvent} via the {@link InputEvent#consumedTag}
+ * and to perform focus traversal with a 3rd party toolkit.
+ * </p>
+ * <p>
+ * The {@link KeyListener} methods are not invoked for {@link KeyEvent#isAutoRepeat() auto-repeat} events.
* </p>
* @param l
*/
@@ -372,8 +561,20 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
*/
void requestFocus(boolean wait);
+ /**
+ * Trigger window repaint while passing the dirty region in pixel units.
+ * @param x dirty-region y-pos in pixel units
+ * @param y dirty-region x-pos in pixel units
+ * @param width dirty-region width in pixel units
+ * @param height dirty-region height in pixel units
+ */
void windowRepaint(int x, int y, int width, int height);
+ /**
+ * Enqueues a {@link com.jogamp.newt.event.NEWTEvent NEWT event}.
+ * @param wait Passing <code>true</code> will block until the event has been processed, otherwise method returns immediately.
+ * @param event The {@link com.jogamp.newt.event.NEWTEvent event} to enqueue.
+ */
void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event);
void runOnEDTIfAvail(boolean wait, final Runnable task);
@@ -383,10 +584,13 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
// WindowListener
//
+ /**
+ * Send a {@link WindowEvent} to all {@link WindowListener}.
+ * @param eventType a {@link WindowEvent} type, e.g. {@link WindowEvent#EVENT_WINDOW_REPAINT}.
+ */
public void sendWindowEvent(int eventType);
/**
- *
* Appends the given {@link com.jogamp.newt.event.WindowListener} to the end of
* the list.
*/
@@ -468,15 +672,12 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
//
/**
- *
- * Appends the given {@link com.jogamp.newt.event.MouseListener} to the end of
- * the list.
+ * Appends the given {@link MouseListener} to the end of the list.
*/
void addMouseListener(MouseListener l);
/**
- *
- * Inserts the given {@link com.jogamp.newt.event.MouseListener} at the
+ * Inserts the given {@link MouseListener} at the
* specified position in the list.<br>
*
* @param index Position where the listener will be inserted.
@@ -487,10 +688,61 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
*/
void addMouseListener(int index, MouseListener l);
+ /**
+ * Removes the given {@link MouseListener} from the list.
+ */
void removeMouseListener(MouseListener l);
+ /**
+ * Returns the {@link MouseListener} from the list at the given index.
+ */
MouseListener getMouseListener(int index);
+ /**
+ * Returns all {@link MouseListener}
+ */
MouseListener[] getMouseListeners();
+ /** Enable or disable default {@link GestureHandler}. Default is enabled. */
+ void setDefaultGesturesEnabled(boolean enable);
+ /** Return true if default {@link GestureHandler} are enabled. */
+ boolean areDefaultGesturesEnabled();
+ /**
+ * Appends the given {@link GestureHandler} to the end of the list.
+ */
+ void addGestureHandler(GestureHandler gh);
+ /**
+ * Inserts the given {@link GestureHandler} at the
+ * specified position in the list.<br>
+ *
+ * @param index Position where the listener will be inserted.
+ * Should be within (0 <= index && index <= size()).
+ * An index value of -1 is interpreted as the end of the list, size().
+ * @param l The listener object to be inserted
+ * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1
+ */
+ void addGestureHandler(int index, GestureHandler gh);
+ /**
+ * Removes the given {@link GestureHandler} from the list.
+ */
+ void removeGestureHandler(GestureHandler gh);
+ /**
+ * Appends the given {@link GestureHandler.GestureListener} to the end of the list.
+ */
+ void addGestureListener(GestureHandler.GestureListener gl);
+ /**
+ * Inserts the given {@link GestureHandler.GestureListener} at the
+ * specified position in the list.<br>
+ *
+ * @param index Position where the listener will be inserted.
+ * Should be within (0 <= index && index <= size()).
+ * An index value of -1 is interpreted as the end of the list, size().
+ * @param l The listener object to be inserted
+ * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1
+ */
+ void addGestureListener(int index, GestureHandler.GestureListener gl);
+ /**
+ * Removes the given {@link GestureHandler.GestureListener} from the list.
+ */
+ void removeGestureListener(GestureHandler.GestureListener gl);
}
diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
index 89a749c51..c470f6840 100644
--- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
+++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,20 +20,26 @@
* 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 com.jogamp.newt.awt;
+import java.applet.Applet;
import java.awt.AWTKeyStroke;
import java.awt.Canvas;
+import java.awt.Component;
+import java.awt.EventQueue;
import java.awt.Graphics;
+import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.KeyboardFocusManager;
+import java.awt.geom.NoninvertibleTransformException;
+import java.beans.Beans;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;
@@ -42,23 +48,33 @@ import java.security.PrivilegedAction;
import java.util.Set;
import javax.media.nativewindow.NativeWindow;
-import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.OffscreenLayerOption;
-import javax.media.nativewindow.OffscreenLayerSurface;
import javax.media.nativewindow.WindowClosingProtocol;
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLOffscreenAutoDrawable;
import javax.swing.MenuSelectionManager;
import jogamp.nativewindow.awt.AWTMisc;
+import jogamp.nativewindow.jawt.JAWTUtil;
import jogamp.newt.Debug;
+import jogamp.newt.WindowImpl;
import jogamp.newt.awt.NewtFactoryAWT;
import jogamp.newt.awt.event.AWTParentWindowAdapter;
import jogamp.newt.driver.DriverClearFocus;
+import jogamp.opengl.awt.AWTTilePainter;
+import com.jogamp.common.util.awt.AWTEDTExecutor;
+import com.jogamp.nativewindow.awt.AWTPrintLifecycle;
import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol;
import com.jogamp.nativewindow.awt.JAWTWindow;
import com.jogamp.newt.Display;
import com.jogamp.newt.Window;
-import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.WindowAdapter;
@@ -67,199 +83,265 @@ import com.jogamp.newt.event.WindowListener;
import com.jogamp.newt.event.awt.AWTAdapter;
import com.jogamp.newt.event.awt.AWTKeyAdapter;
import com.jogamp.newt.event.awt.AWTMouseAdapter;
+import com.jogamp.opengl.util.GLDrawableUtil;
+import com.jogamp.opengl.util.TileRenderer;
/**
* AWT {@link java.awt.Canvas Canvas} containing a NEWT {@link Window} using native parenting.
- *
+ *
* <h5><A NAME="java2dgl">Offscreen Layer Remarks</A></h5>
- *
+ *
* {@link OffscreenLayerOption#setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)}
- * maybe called to use an offscreen drawable (FBO or PBuffer) allowing
+ * maybe called to use an offscreen drawable (FBO or PBuffer) allowing
* the underlying JAWT mechanism to composite the image, if supported.
*/
@SuppressWarnings("serial")
-public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProtocol, OffscreenLayerOption {
+public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProtocol, OffscreenLayerOption, AWTPrintLifecycle {
public static final boolean DEBUG = Debug.debug("Window");
+ private final Object sync = new Object();
private JAWTWindow jawtWindow = null;
+ private boolean isApplet = false;
private boolean shallUseOffscreenLayer = false;
private Window newtChild = null;
+ private boolean newtChildAttached = false;
private boolean isOnscreen = true;
private WindowClosingMode newtChildCloseOp;
- private AWTAdapter awtAdapter = null;
- private AWTAdapter awtMouseAdapter = null;
- private AWTAdapter awtKeyAdapter = null;
-
- private AWTWindowClosingProtocol awtWindowClosingProtocol =
+ private final AWTParentWindowAdapter awtWinAdapter;
+ private final AWTAdapter awtMouseAdapter;
+ private final AWTAdapter awtKeyAdapter;
+
+ /** Mitigates Bug 910 (IcedTea-Web), i.e. crash via removeNotify() invoked before Applet.destroy(). */
+ private boolean destroyJAWTPending = false;
+ /** Mitigates Bug 910 (IcedTea-Web), i.e. crash via removeNotify() invoked before Applet.destroy(). */
+ private boolean skipJAWTDestroy = false;
+
+ /** Safeguard for AWTWindowClosingProtocol and 'removeNotify()' on other thread than AWT-EDT. */
+ private volatile boolean componentAdded = false;
+
+ private final AWTWindowClosingProtocol awtWindowClosingProtocol =
new AWTWindowClosingProtocol(this, new Runnable() {
+ @Override
+ public void run() {
+ if( componentAdded ) {
+ NewtCanvasAWT.this.destroyImpl(false /* removeNotify */, true /* windowClosing */);
+ }
+ }
+ }, new Runnable() {
+ @Override
public void run() {
- NewtCanvasAWT.this.destroy();
+ if( componentAdded && newtChild != null ) {
+ newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY);
+ }
}
- });
+ } );
/**
* Instantiates a NewtCanvas without a NEWT child.<br>
*/
public NewtCanvasAWT() {
super();
+ awtMouseAdapter = new AWTMouseAdapter().addTo(this);
+ awtKeyAdapter = new AWTKeyAdapter().addTo(this);
+ awtWinAdapter = (AWTParentWindowAdapter) new AWTParentWindowAdapter().addTo(this);
+ awtWinAdapter.removeWindowClosingFrom(this); // we utilize AWTWindowClosingProtocol triggered destruction!
}
/**
* Instantiates a NewtCanvas without a NEWT child.<br>
*/
- public NewtCanvasAWT(GraphicsConfiguration gc) {
+ public NewtCanvasAWT(final GraphicsConfiguration gc) {
super(gc);
+ awtMouseAdapter = new AWTMouseAdapter().addTo(this);
+ awtKeyAdapter = new AWTKeyAdapter().addTo(this);
+ awtWinAdapter = (AWTParentWindowAdapter) new AWTParentWindowAdapter().addTo(this);
+ awtWinAdapter.removeWindowClosingFrom(this); // we utilize AWTWindowClosingProtocol triggered destruction!
}
/**
* Instantiates a NewtCanvas with a NEWT child.
*/
- public NewtCanvasAWT(Window child) {
+ public NewtCanvasAWT(final Window child) {
super();
+ awtMouseAdapter = new AWTMouseAdapter().addTo(this);
+ awtKeyAdapter = new AWTKeyAdapter().addTo(this);
+ awtWinAdapter = (AWTParentWindowAdapter) new AWTParentWindowAdapter().addTo(this);
+ awtWinAdapter.removeWindowClosingFrom(this); // we utilize AWTWindowClosingProtocol triggered destruction!
setNEWTChild(child);
}
/**
* Instantiates a NewtCanvas with a NEWT child.
*/
- public NewtCanvasAWT(GraphicsConfiguration gc, Window child) {
+ public NewtCanvasAWT(final GraphicsConfiguration gc, final Window child) {
super(gc);
+ awtMouseAdapter = new AWTMouseAdapter().addTo(this);
+ awtKeyAdapter = new AWTKeyAdapter().addTo(this);
+ awtWinAdapter = (AWTParentWindowAdapter) new AWTParentWindowAdapter().addTo(this);
+ awtWinAdapter.removeWindowClosingFrom(this); // we utilize AWTWindowClosingProtocol triggered destruction!
setNEWTChild(child);
}
-
- public void setShallUseOffscreenLayer(boolean v) {
+
+ @Override
+ public void setShallUseOffscreenLayer(final boolean v) {
shallUseOffscreenLayer = v;
}
-
+
+ @Override
public final boolean getShallUseOffscreenLayer() {
- return shallUseOffscreenLayer;
+ return shallUseOffscreenLayer;
}
-
- public final boolean isOffscreenLayerSurfaceEnabled() {
- return jawtWindow.isOffscreenLayerSurfaceEnabled();
+
+ @Override
+ public final boolean isOffscreenLayerSurfaceEnabled() {
+ final JAWTWindow w = jawtWindow;
+ return null != w && w.isOffscreenLayerSurfaceEnabled();
}
-
- /**
- * Returns true if the AWT component is parented to an {@link java.applet.Applet},
- * otherwise false. This information is valid only after {@link #addNotify()} is issued,
- * ie. before adding the component to the AWT tree and make it visible.
+
+ /**
+ * Returns true if the AWT component is parented to an {@link java.applet.Applet},
+ * otherwise false. This information is valid only after {@link #addNotify()} is issued.
*/
- public boolean isApplet() {
- return jawtWindow.isApplet();
+ public final boolean isApplet() {
+ return isApplet;
}
- boolean isParent() {
- return null!=newtChild && jawtWindow == newtChild.getParent();
+ private final boolean isParent() {
+ final Window nw = newtChild;
+ return null!=nw && jawtWindow == nw.getParent();
}
-
- boolean isFullscreen() {
- return null != newtChild && newtChild.isFullscreen();
+
+ private final boolean isFullscreen() {
+ final Window nw = newtChild;
+ return null != nw && nw.isFullscreen();
}
-
+
class FocusAction implements Window.FocusRunnable {
+ @Override
public boolean run() {
final boolean isParent = isParent();
final boolean isFullscreen = isFullscreen();
if(DEBUG) {
System.err.println("NewtCanvasAWT.FocusAction: "+Display.getThreadName()+", isOnscreen "+isOnscreen+", hasFocus "+hasFocus()+", isParent "+isParent+", isFS "+isFullscreen);
}
- if(isParent && !isFullscreen) {
- // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus.
- if(!hasFocus()) {
- // Acquire the AWT focus 1st for proper AWT traversal
- NewtCanvasAWT.super.requestFocus();
- }
- if(isOnscreen) {
+ if( isParent && !isFullscreen ) { // must be parent of newtChild _and_ newtChild not fullscreen
+ if( isOnscreen ) {
// Remove the AWT focus in favor of the native NEWT focus
- KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
+ AWTEDTExecutor.singleton.invoke(false, awtClearGlobalFocusOwner);
+ } else if( !hasFocus() ) {
+ // In offscreen mode we require the focus!
+ // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus.
+ NewtCanvasAWT.super.requestFocus();
}
}
return false; // NEWT shall proceed requesting the native focus
}
}
- private FocusAction focusAction = new FocusAction();
-
- WindowListener clearAWTMenusOnNewtFocus = new WindowAdapter() {
+ private final FocusAction focusAction = new FocusAction();
+
+ private static class ClearFocusOwner implements Runnable {
+ @Override
+ public void run() {
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
+ }
+ }
+ private static final Runnable awtClearGlobalFocusOwner = new ClearFocusOwner();
+
+ /** Must run on AWT-EDT non-blocking, since it invokes tasks on AWT-EDT w/ waiting otherwise. */
+ private final Runnable awtClearSelectedMenuPath = new Runnable() {
+ @Override
+ public void run() {
+ MenuSelectionManager.defaultManager().clearSelectedPath();
+ }
+ };
+ private final WindowListener clearAWTMenusOnNewtFocus = new WindowAdapter() {
@Override
- public void windowGainedFocus(WindowEvent arg0) {
+ public void windowResized(final WindowEvent e) {
+ updateLayoutSize();
+ }
+ @Override
+ public void windowGainedFocus(final WindowEvent arg0) {
if( isParent() && !isFullscreen() ) {
- MenuSelectionManager.defaultManager().clearSelectedPath();
+ AWTEDTExecutor.singleton.invoke(false, awtClearSelectedMenuPath);
}
}
};
class FocusTraversalKeyListener implements KeyListener {
- boolean suppress = false;
-
- public void keyPressed(KeyEvent e) {
+ @Override
+ public void keyPressed(final KeyEvent e) {
if( isParent() && !isFullscreen() ) {
handleKey(e, false);
}
}
- public void keyReleased(KeyEvent e) {
+ @Override
+ public void keyReleased(final KeyEvent e) {
if( isParent() && !isFullscreen() ) {
handleKey(e, true);
}
}
- public void keyTyped(KeyEvent e) {
- if(suppress) {
- e.setAttachment(InputEvent.consumedTag);
- suppress = false; // reset
- }
- }
-
- void handleKey(KeyEvent evt, boolean onRelease) {
+
+ void handleKey(final KeyEvent evt, final boolean onRelease) {
if(null == keyboardFocusManager) {
throw new InternalError("XXX");
}
final AWTKeyStroke ks = AWTKeyStroke.getAWTKeyStroke(evt.getKeyCode(), evt.getModifiers(), onRelease);
+ boolean suppress = false;
if(null != ks) {
- final Set<AWTKeyStroke> fwdKeys = keyboardFocusManager.getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
- final Set<AWTKeyStroke> bwdKeys = keyboardFocusManager.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+ final Set<AWTKeyStroke> fwdKeys = keyboardFocusManager.getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+ final Set<AWTKeyStroke> bwdKeys = keyboardFocusManager.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
if(fwdKeys.contains(ks)) {
+ final Component nextFocus = AWTMisc.getNextFocus(NewtCanvasAWT.this, true /* forward */);
if(DEBUG) {
- System.err.println("NewtCanvasAWT.focusKey (fwd): "+ks+", current focusOwner "+keyboardFocusManager.getFocusOwner());
+ System.err.println("NewtCanvasAWT.focusKey (fwd): "+ks+", current focusOwner "+keyboardFocusManager.getFocusOwner()+", hasFocus: "+hasFocus()+", nextFocus "+nextFocus);
}
// Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus.
- NewtCanvasAWT.this.transferFocus();
+ nextFocus.requestFocus();
suppress = true;
} else if(bwdKeys.contains(ks)) {
+ final Component prevFocus = AWTMisc.getNextFocus(NewtCanvasAWT.this, false /* forward */);
if(DEBUG) {
- System.err.println("NewtCanvasAWT.focusKey (bwd): "+ks+", current focusOwner "+keyboardFocusManager.getFocusOwner());
+ System.err.println("NewtCanvasAWT.focusKey (bwd): "+ks+", current focusOwner "+keyboardFocusManager.getFocusOwner()+", hasFocus: "+hasFocus()+", prevFocus "+prevFocus);
}
// Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus.
- NewtCanvasAWT.this.transferFocusBackward();
+ prevFocus.requestFocus();
suppress = true;
}
}
if(suppress) {
- evt.setAttachment(InputEvent.consumedTag);
+ evt.setConsumed(true);
}
if(DEBUG) {
System.err.println("NewtCanvasAWT.focusKey: XXX: "+ks);
}
}
}
- private final FocusTraversalKeyListener newtFocusTraversalKeyListener = new FocusTraversalKeyListener();
+ private final FocusTraversalKeyListener newtFocusTraversalKeyListener = new FocusTraversalKeyListener();
class FocusPropertyChangeListener implements PropertyChangeListener {
- public void propertyChange(PropertyChangeEvent evt) {
+ @Override
+ public void propertyChange(final PropertyChangeEvent evt) {
final Object oldF = evt.getOldValue();
final Object newF = evt.getNewValue();
final boolean isParent = isParent();
- final boolean isFullscreen = isFullscreen();
+ final boolean isFullscreen = isFullscreen();
if(DEBUG) {
System.err.println("NewtCanvasAWT.FocusProperty: "+evt.getPropertyName()+", src "+evt.getSource()+", "+oldF+" -> "+newF+", isParent "+isParent+", isFS "+isFullscreen);
}
if(isParent && !isFullscreen) {
- if(oldF == NewtCanvasAWT.this && newF == null) {
+ if(newF == NewtCanvasAWT.this) {
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.FocusProperty: AWT focus -> NEWT focus traversal");
+ }
+ requestFocusNEWTChild();
+ } else if(oldF == NewtCanvasAWT.this && newF == null) {
// focus traversal to NEWT - NOP
- if(DEBUG) {
- System.err.println("NewtCanvasAWT.FocusProperty: NEWT focus traversal");
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.FocusProperty: NEWT focus");
}
} else if(null != newF && newF != NewtCanvasAWT.this) {
// focus traversal to another AWT component
- if(DEBUG) {
+ if(DEBUG) {
System.err.println("NewtCanvasAWT.FocusProperty: lost focus - clear focus");
}
if(newtChild.getDelegatedWindow() instanceof DriverClearFocus) {
@@ -267,40 +349,64 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
}
}
}
- }
+ }
}
private final FocusPropertyChangeListener focusPropertyChangeListener = new FocusPropertyChangeListener();
private volatile KeyboardFocusManager keyboardFocusManager = null;
- /**
+ private final void requestFocusNEWTChild() {
+ if(null!=newtChild) {
+ newtChild.setFocusAction(null);
+ if(isOnscreen) {
+ AWTEDTExecutor.singleton.invoke(false, awtClearGlobalFocusOwner);
+ }
+ newtChild.requestFocus();
+ newtChild.setFocusAction(focusAction);
+ }
+ }
+
+ /**
* Sets a new NEWT child, provoking reparenting.
* <p>
* A previously detached <code>newChild</code> will be released to top-level status
- * and made invisible.
+ * and made invisible.
* </p>
* <p>
- * Note: When switching NEWT child's, detaching the previous first via <code>setNEWTChild(null)</code>
- * produced much cleaner visual results.
+ * Note: When switching NEWT child's, detaching the previous first via <code>setNEWTChild(null)</code>
+ * produced much cleaner visual results.
* </p>
- * @return the previous attached newt child.
+ * @return the previous attached newt child.
*/
- public Window setNEWTChild(Window newChild) {
- final Window prevChild = newtChild;
- if(DEBUG) {
- System.err.println("NewtCanvasAWT.setNEWTChild.0: win "+newtWinHandleToHexString(prevChild)+" -> "+newtWinHandleToHexString(newChild));
- }
- final java.awt.Container cont = AWTMisc.getContainer(this);
- // remove old one
- if(null != newtChild) {
- reparentWindow( false, cont );
- newtChild = null;
+ public Window setNEWTChild(final Window newChild) {
+ synchronized(sync) {
+ final Window prevChild = newtChild;
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.setNEWTChild.0: win "+newtWinHandleToHexString(prevChild)+" -> "+newtWinHandleToHexString(newChild));
+ }
+ final java.awt.Container cont = AWTMisc.getContainer(this);
+ // remove old one
+ if(null != newtChild) {
+ detachNewtChild( cont );
+ newtChild = null;
+ }
+ // add new one, reparent only if ready
+ newtChild = newChild;
+
+ updateLayoutSize();
+ // will be done later at paint/display/..: attachNewtChild(cont);
+
+ return prevChild;
}
- // add new one, reparent only if ready
- newtChild = newChild;
- if( isDisplayable() && null != newChild) {
- reparentWindow( true, cont );
+ }
+
+ private final void updateLayoutSize() {
+ final Window w = newtChild;
+ if( null != w ) {
+ // use NEWT child's size for min/pref size!
+ final java.awt.Dimension minSize = new java.awt.Dimension(w.getWidth(), w.getHeight());
+ setMinimumSize(minSize);
+ setPreferredSize(minSize);
}
- return prevChild;
}
/** @return the current NEWT child */
@@ -311,158 +417,92 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
/** @return this AWT Canvas NativeWindow representation, may be null in case {@link #removeNotify()} has been called,
* or {@link #addNotify()} hasn't been called yet.*/
public NativeWindow getNativeWindow() { return jawtWindow; }
-
+
+ @Override
public WindowClosingMode getDefaultCloseOperation() {
return awtWindowClosingProtocol.getDefaultCloseOperation();
}
- public WindowClosingMode setDefaultCloseOperation(WindowClosingMode op) {
+ @Override
+ public WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) {
return awtWindowClosingProtocol.setDefaultCloseOperation(op);
}
- /* package */ void configureNewtChild(boolean attach) {
- if(null!=awtAdapter) {
- awtAdapter.removeFrom(this);
- awtAdapter=null;
- }
- if(null!=awtMouseAdapter) {
- awtMouseAdapter.removeFrom(this);
- awtMouseAdapter = null;
- }
- if(null!=awtKeyAdapter) {
- awtKeyAdapter.removeFrom(this);
- awtKeyAdapter = null;
- }
- if(null != keyboardFocusManager) {
- keyboardFocusManager.removePropertyChangeListener("focusOwner", focusPropertyChangeListener);
- keyboardFocusManager = null;
- }
-
- if( null != newtChild ) {
- newtChild.setKeyboardFocusHandler(null);
- if(attach) {
- if(null == jawtWindow.getGraphicsConfiguration()) {
- throw new InternalError("XXX");
- }
- isOnscreen = jawtWindow.getGraphicsConfiguration().getChosenCapabilities().isOnscreen();
- awtAdapter = new AWTParentWindowAdapter(jawtWindow, newtChild).addTo(this);
- newtChild.addWindowListener(clearAWTMenusOnNewtFocus);
- newtChild.setFocusAction(focusAction); // enable AWT focus traversal
- newtChildCloseOp = newtChild.setDefaultCloseOperation(WindowClosingMode.DO_NOTHING_ON_CLOSE);
- awtWindowClosingProtocol.addClosingListenerOneShot();
- keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
- keyboardFocusManager.addPropertyChangeListener("focusOwner", focusPropertyChangeListener);
- if(isOnscreen) {
- // onscreen newt child needs to fwd AWT focus
- newtChild.setKeyboardFocusHandler(newtFocusTraversalKeyListener);
- } else {
- // offscreen newt child requires AWT to fwd AWT key/mouse event
- awtMouseAdapter = new AWTMouseAdapter(newtChild).addTo(this);
- awtKeyAdapter = new AWTKeyAdapter(newtChild).addTo(this);
- }
- } else {
- newtChild.removeWindowListener(clearAWTMenusOnNewtFocus);
- newtChild.setFocusAction(null);
- newtChild.setDefaultCloseOperation(newtChildCloseOp);
- awtWindowClosingProtocol.removeClosingListener();
- }
+ /**
+ * Mitigates Bug 910 (IcedTea-Web), i.e. crash via removeNotify() invoked before Applet.destroy().
+ * <p>
+ * <code>skipJAWTDestroy</code> defaults to <code>false</code>.
+ * Due to above IcedTea-Web issue the <code>Applet</code> code needs to avoid JAWT destruction before
+ * <code>Applet.destroy()</code> is reached by setting <code>skipJAWTDestroy</code> to <code>true</code>.
+ * Afterwards the value should be reset to <code>false</code> and {@link #destroy()} needs to be called,
+ * which finally will perform the pending JAWT destruction.
+ * </p>
+ */
+ public final void setSkipJAWTDestroy(final boolean v) { skipJAWTDestroy = v; }
+ /** See {@link #setSkipJAWTDestroy(boolean)}. */
+ public final boolean getSkipJAWTDestroy() { return skipJAWTDestroy; }
+
+ private final void determineIfApplet() {
+ isApplet = false;
+ Component c = this;
+ while(!isApplet && null != c) {
+ isApplet = c instanceof Applet;
+ c = c.getParent();
}
}
@Override
public void addNotify() {
-
- // before native peer is valid: X11
- disableBackgroundErase();
-
- // creates the native peer
- super.addNotify();
-
- // after native peer is valid: Windows
- disableBackgroundErase();
-
- java.awt.Container cont = AWTMisc.getContainer(this);
- if(DEBUG) {
- // if ( isShowing() == false ) -> Container was not visible yet.
- // if ( isShowing() == true ) -> Container is already visible.
- System.err.println("NewtCanvasAWT.addNotify: "+newtChild+", "+this+", visible "+isVisible()+", showing "+isShowing()+
- ", displayable "+isDisplayable()+" -> "+cont);
+ if( Beans.isDesignTime() ) {
+ super.addNotify();
+ } else {
+ // before native peer is valid: X11
+ disableBackgroundErase();
+
+ // creates the native peer
+ super.addNotify();
+
+ // after native peer is valid: Windows
+ disableBackgroundErase();
+
+ synchronized(sync) {
+ determineIfApplet();
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.addNotify.0 - isApplet "+isApplet+", addedOnAWTEDT "+EventQueue.isDispatchThread()+" @ "+currentThreadName());
+ Thread.dumpStack();
+ }
+ jawtWindow = NewtFactoryAWT.getNativeWindow(NewtCanvasAWT.this, null != newtChild ? newtChild.getRequestedCapabilities() : null);
+ jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer);
+ awtWindowClosingProtocol.addClosingListener();
+ componentAdded = true; // Bug 910
+ if(DEBUG) {
+ // if ( isShowing() == false ) -> Container was not visible yet.
+ // if ( isShowing() == true ) -> Container is already visible.
+ System.err.println("NewtCanvasAWT.addNotify.X: twin "+newtWinHandleToHexString(newtChild)+
+ ", comp "+this+", visible "+isVisible()+", showing "+isShowing()+
+ ", displayable "+isDisplayable()+", cont "+AWTMisc.getContainer(this));
+ }
+ }
}
- reparentWindow(true, cont);
}
@Override
public void removeNotify() {
- java.awt.Container cont = AWTMisc.getContainer(this);
- if(DEBUG) {
- System.err.println("NewtCanvasAWT.removeNotify: "+newtChild+", from "+cont);
- }
- final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(newtChild, true);
- if(null != ols && ols.isSurfaceLayerAttached()) {
- ols.detachSurfaceLayer();
- }
- reparentWindow(false, cont);
-
- if(null != jawtWindow) {
- NewtFactoryAWT.destroyNativeWindow(jawtWindow);
- jawtWindow=null;
+ if( Beans.isDesignTime() ) {
+ super.removeNotify();
+ } else {
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.removeNotify.0 - isApplet "+isApplet+" @ "+currentThreadName());
+ Thread.dumpStack();
+ }
+ componentAdded = false; // Bug 910
+ awtWindowClosingProtocol.removeClosingListener();
+ destroyImpl(true /* removeNotify */, false /* windowClosing */);
+ super.removeNotify();
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.removeNotify.X @ "+currentThreadName());
+ }
}
-
- super.removeNotify();
- }
-
- void reparentWindow(boolean add, java.awt.Container cont) {
- if(null==newtChild) {
- return; // nop
- }
- if(DEBUG) {
- System.err.println("NewtCanvasAWT.reparentWindow.0: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil());
- }
-
- newtChild.setFocusAction(null); // no AWT focus traversal ..
- if(add) {
- if(DEBUG) {
- System.err.println("NewtCanvasAWT.reparentWindow: newtChild: "+newtChild);
- }
- if(null == jawtWindow) {
- jawtWindow = NewtFactoryAWT.getNativeWindow(this, newtChild.getRequestedCapabilities());
- jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer);
- }
- final int w;
- final int h;
- if(isPreferredSizeSet()) {
- java.awt.Dimension d = getPreferredSize();
- w = d.width;
- h = d.height;
- } else {
- final java.awt.Dimension min;
- if(this.isMinimumSizeSet()) {
- min = getMinimumSize();
- } else {
- min = new java.awt.Dimension(0, 0);
- }
- java.awt.Insets ins = cont.getInsets();
- w = Math.max(min.width, cont.getWidth() - ins.left - ins.right);
- h = Math.max(min.height, cont.getHeight() - ins.top - ins.bottom);
- }
- setSize(w, h);
- newtChild.setSize(w, h);
- newtChild.reparentWindow(jawtWindow);
- newtChild.setVisible(true);
- configureNewtChild(true);
- newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener
-
- // force this AWT Canvas to be focus-able,
- // since this it is completely covered by the newtChild (z-order).
- setFocusable(true);
- } else {
- configureNewtChild(false);
- newtChild.setVisible(false);
- newtChild.reparentWindow(null);
- }
- if(DEBUG) {
- System.err.println("NewtCanvasAWT.reparentWindow.X: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil());
- }
}
/**
@@ -472,88 +512,438 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
* <li> Disconnects the NEWT Child from this Canvas NativeWindow, reparent to NULL </li>
* <li> Issues <code>destroy()</code> on the NEWT Child</li>
* <li> Remove reference to the NEWT Child</li>
- * <li> Remove this Canvas from it's parent.</li>
* </ul>
* @see Window#destroy()
*/
public final void destroy() {
- if(null!=newtChild) {
- java.awt.Container cont = AWTMisc.getContainer(this);
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.destroy() @ "+currentThreadName());
+ Thread.dumpStack();
+ }
+ AWTEDTExecutor.singleton.invoke(true, new Runnable() {
+ @Override
+ public void run() {
+ destroyImpl(false /* removeNotify */, false /* windowClosing */);
+ } } );
+ }
+
+ private final void destroyImpl(final boolean removeNotify, final boolean windowClosing) {
+ synchronized(sync) {
+ final java.awt.Container cont = AWTMisc.getContainer(this);
if(DEBUG) {
- System.err.println("NewtCanvasAWT.destroy(): "+newtChild+", from "+cont);
+ System.err.println("NewtCanvasAWT.destroyImpl @ "+currentThreadName());
+ System.err.println("NewtCanvasAWT.destroyImpl.0 - isApplet "+isApplet+", isOnAWTEDT "+EventQueue.isDispatchThread()+", skipJAWTDestroy "+skipJAWTDestroy+
+ "; removeNotify "+removeNotify+", windowClosing "+windowClosing+", destroyJAWTPending "+destroyJAWTPending+
+ ", hasJAWT "+(null!=jawtWindow)+", hasNEWT "+(null!=newtChild)+
+ "): nw "+newtWinHandleToHexString(newtChild)+", from "+cont);
}
- configureNewtChild(false);
- if(null!=jawtWindow) {
- NewtFactoryAWT.destroyNativeWindow(jawtWindow);
- jawtWindow=null;
+ if( null !=newtChild ) {
+ detachNewtChild(cont);
+
+ if( !removeNotify ) {
+ final Window cWin = newtChild;
+ final Window dWin = cWin.getDelegatedWindow();
+ newtChild=null;
+ if( windowClosing && dWin instanceof WindowImpl ) {
+ ((WindowImpl)dWin).windowDestroyNotify(true);
+ } else {
+ cWin.destroy();
+ }
+ }
}
- newtChild.setVisible(false);
- newtChild.reparentWindow(null);
- newtChild.destroy();
- newtChild=null;
- if(null!=cont) {
- cont.remove(this);
+ if( ( destroyJAWTPending || removeNotify || windowClosing ) && null!=jawtWindow ) {
+ if( skipJAWTDestroy ) {
+ // Bug 910 - See setSkipJAWTDestroy(boolean)
+ destroyJAWTPending = true;
+ } else {
+ NewtFactoryAWT.destroyNativeWindow(jawtWindow);
+ jawtWindow=null;
+ destroyJAWTPending = false;
+ }
}
}
- }
+ }
@Override
- public void paint(Graphics g) {
- awtWindowClosingProtocol.addClosingListenerOneShot();
- if(null!=newtChild) {
- newtChild.windowRepaint(0, 0, getWidth(), getHeight());
+ public void paint(final Graphics g) {
+ synchronized(sync) {
+ if( validateComponent(true) && !printActive ) {
+ newtChild.windowRepaint(0, 0, getWidth(), getHeight());
+ }
}
}
@Override
- public void update(Graphics g) {
- awtWindowClosingProtocol.addClosingListenerOneShot();
- if(null!=newtChild) {
- newtChild.windowRepaint(0, 0, getWidth(), getHeight());
- }
+ public void update(final Graphics g) {
+ paint(g);
}
- private final void requestFocusNEWTChild() {
- if(null!=newtChild) {
- newtChild.setFocusAction(null);
- if(isOnscreen) {
- KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
+ @SuppressWarnings("deprecation")
+ @Override
+ public void reshape(final int x, final int y, final int width, final int height) {
+ synchronized (getTreeLock()) { // super.reshape(..) claims tree lock, so we do extend it's lock over reshape
+ synchronized(sync) {
+ super.reshape(x, y, width, height);
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.reshape: "+x+"/"+y+" "+width+"x"+height);
+ }
+ if( validateComponent(true) ) {
+ // newtChild.setSize(width, height);
+ }
}
- newtChild.requestFocus();
- newtChild.setFocusAction(focusAction);
}
}
+ private volatile boolean printActive = false;
+ private GLAnimatorControl printAnimator = null;
+ private GLAutoDrawable printGLAD = null;
+ private AWTTilePainter printAWTTiles = null;
+
+ private final GLAutoDrawable getGLAD() {
+ if( null != newtChild && newtChild instanceof GLAutoDrawable ) {
+ return (GLAutoDrawable)newtChild;
+ }
+ return null;
+ }
+
@Override
- public void requestFocus() {
- super.requestFocus();
- requestFocusNEWTChild();
+ public void setupPrint(final double scaleMatX, final double scaleMatY, final int numSamples, final int tileWidth, final int tileHeight) {
+ printActive = true;
+ final int componentCount = isOpaque() ? 3 : 4;
+ final TileRenderer printRenderer = new TileRenderer();
+ printAWTTiles = new AWTTilePainter(printRenderer, componentCount, scaleMatX, scaleMatY, numSamples, tileWidth, tileHeight, DEBUG);
+ AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, setupPrintOnEDT);
}
+ private final Runnable setupPrintOnEDT = new Runnable() {
+ @Override
+ public void run() {
+ synchronized(sync) {
+ if( !validateComponent(true) ) {
+ if(DEBUG) {
+ System.err.println(currentThreadName()+": Info: NewtCanvasAWT setupPrint - skipped GL render, drawable not valid yet");
+ }
+ printActive = false;
+ return; // not yet available ..
+ }
+ if( !isVisible() ) {
+ if(DEBUG) {
+ System.err.println(currentThreadName()+": Info: NewtCanvasAWT setupPrint - skipped GL render, canvas not visible");
+ }
+ printActive = false;
+ return; // not yet available ..
+ }
+ final GLAutoDrawable glad = getGLAD();
+ if( null == glad ) {
+ if( DEBUG ) {
+ System.err.println("AWT print.setup exit, newtChild not a GLAutoDrawable: "+newtChild);
+ }
+ printActive = false;
+ return;
+ }
+ printAnimator = glad.getAnimator();
+ if( null != printAnimator ) {
+ printAnimator.remove(glad);
+ }
+ printGLAD = glad; // _not_ default, shall be replaced by offscreen GLAD
+ final GLCapabilitiesImmutable gladCaps = glad.getChosenGLCapabilities();
+ final int printNumSamples = printAWTTiles.getNumSamples(gladCaps);
+ GLDrawable printDrawable = printGLAD.getDelegatedDrawable();
+ final boolean reqNewGLADSamples = printNumSamples != gladCaps.getNumSamples();
+ final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() ||
+ printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight();
+ final boolean reqNewGLADOnscrn = gladCaps.isOnscreen();
+
+ final GLCapabilities newGLADCaps = (GLCapabilities)gladCaps.cloneMutable();
+ newGLADCaps.setDoubleBuffered(false);
+ newGLADCaps.setOnscreen(false);
+ if( printNumSamples != newGLADCaps.getNumSamples() ) {
+ newGLADCaps.setSampleBuffers(0 < printNumSamples);
+ newGLADCaps.setNumSamples(printNumSamples);
+ }
+ final boolean reqNewGLADSafe = GLDrawableUtil.isSwapGLContextSafe(glad.getRequestedGLCapabilities(), gladCaps, newGLADCaps);
+
+ final boolean reqNewGLAD = ( reqNewGLADOnscrn || reqNewGLADSamples || reqNewGLADSize ) && reqNewGLADSafe;
+
+ if( DEBUG ) {
+ System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ onscreen "+reqNewGLADOnscrn+", samples "+reqNewGLADSamples+", size "+reqNewGLADSize+", safe "+reqNewGLADSafe+"], "+
+ ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+
+ ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+
+ ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+
+ ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator);
+ }
+ if( reqNewGLAD ) {
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(newGLADCaps.getGLProfile());
+ GLOffscreenAutoDrawable offGLAD = null;
+ try {
+ offGLAD = factory.createOffscreenAutoDrawable(null, newGLADCaps, null,
+ printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE,
+ printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE);
+ } catch (final GLException gle) {
+ if( DEBUG ) {
+ System.err.println("Caught: "+gle.getMessage());
+ gle.printStackTrace();
+ }
+ }
+ if( null != offGLAD ) {
+ printGLAD = offGLAD;
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(glad, printGLAD);
+ printDrawable = printGLAD.getDelegatedDrawable();
+ }
+ }
+ printAWTTiles.setGLOrientation(printGLAD.isGLOriented(), printGLAD.isGLOriented());
+ printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0);
+ printAWTTiles.renderer.attachAutoDrawable(printGLAD);
+ if( DEBUG ) {
+ System.err.println("AWT print.setup "+printAWTTiles);
+ System.err.println("AWT print.setup AA "+printNumSamples+", "+newGLADCaps);
+ System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD);
+ System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable);
+ }
+ }
+ }
+ };
@Override
- public boolean requestFocus(boolean temporary) {
- final boolean res = super.requestFocus(temporary);
- if(res) {
- requestFocusNEWTChild();
+ public void releasePrint() {
+ if( !printActive || null == printGLAD ) {
+ throw new IllegalStateException("setupPrint() not called");
}
- return res;
+ // sendReshape = false; // clear reshape flag
+ AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, releasePrintOnEDT);
+ newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener
}
+ private final Runnable releasePrintOnEDT = new Runnable() {
+ @Override
+ public void run() {
+ synchronized(sync) {
+ if( DEBUG ) {
+ System.err.println("AWT print.release "+printAWTTiles);
+ }
+ final GLAutoDrawable glad = getGLAD();
+ printAWTTiles.dispose();
+ printAWTTiles= null;
+ if( printGLAD != glad ) {
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, glad);
+ printGLAD.destroy();
+ }
+ printGLAD = null;
+ if( null != printAnimator ) {
+ printAnimator.add(glad);
+ printAnimator = null;
+ }
+ printActive = false;
+ }
+ }
+ };
@Override
- public boolean requestFocusInWindow() {
- final boolean res = super.requestFocusInWindow();
- if(res) {
- requestFocusNEWTChild();
+ public void print(final Graphics graphics) {
+ synchronized(sync) {
+ if( !printActive || null == printGLAD ) {
+ throw new IllegalStateException("setupPrint() not called");
+ }
+ if(DEBUG && !EventQueue.isDispatchThread()) {
+ System.err.println(currentThreadName()+": Warning: GLCanvas print - not called from AWT-EDT");
+ // we cannot dispatch print on AWT-EDT due to printing internal locking ..
+ }
+
+ final Graphics2D g2d = (Graphics2D)graphics;
+ try {
+ printAWTTiles.setupGraphics2DAndClipBounds(g2d, getWidth(), getHeight());
+ final TileRenderer tileRenderer = printAWTTiles.renderer;
+ if( DEBUG ) {
+ System.err.println("AWT print.0: "+tileRenderer);
+ }
+ if( !tileRenderer.eot() ) {
+ try {
+ do {
+ tileRenderer.display();
+ } while ( !tileRenderer.eot() );
+ if( DEBUG ) {
+ System.err.println("AWT print.1: "+printAWTTiles);
+ }
+ tileRenderer.reset();
+ } finally {
+ printAWTTiles.resetGraphics2D();
+ }
+ }
+ } catch (final NoninvertibleTransformException nte) {
+ System.err.println("Caught: Inversion failed of: "+g2d.getTransform());
+ nte.printStackTrace();
+ }
+ if( DEBUG ) {
+ System.err.println("AWT print.X: "+printAWTTiles);
+ }
}
- return res;
}
- @Override
- public boolean requestFocusInWindow(boolean temporary) {
- final boolean res = super.requestFocusInWindow(temporary);
- if(res) {
- requestFocusNEWTChild();
+ private final boolean validateComponent(final boolean attachNewtChild) {
+ if( Beans.isDesignTime() || !isDisplayable() ) {
+ return false;
+ }
+ if ( null == newtChild || null == jawtWindow ) {
+ return false;
+ }
+ if( 0 >= getWidth() || 0 >= getHeight() ) {
+ return false;
+ }
+
+ if( attachNewtChild && !newtChildAttached && null != newtChild ) {
+ attachNewtChild();
}
- return res;
+
+ return true;
+ }
+
+ private final void configureNewtChild(final boolean attach) {
+ awtWinAdapter.clear();
+ awtKeyAdapter.clear();
+ awtMouseAdapter.clear();
+
+ if(null != keyboardFocusManager) {
+ keyboardFocusManager.removePropertyChangeListener("focusOwner", focusPropertyChangeListener);
+ keyboardFocusManager = null;
+ }
+
+ if( null != newtChild ) {
+ newtChild.setKeyboardFocusHandler(null);
+ if(attach) {
+ if(null == jawtWindow.getGraphicsConfiguration()) {
+ throw new InternalError("XXX");
+ }
+ isOnscreen = jawtWindow.getGraphicsConfiguration().getChosenCapabilities().isOnscreen();
+ awtWinAdapter.setDownstream(jawtWindow, newtChild);
+ newtChild.addWindowListener(clearAWTMenusOnNewtFocus);
+ newtChild.setFocusAction(focusAction); // enable AWT focus traversal
+ newtChildCloseOp = newtChild.setDefaultCloseOperation(WindowClosingMode.DO_NOTHING_ON_CLOSE);
+ keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ keyboardFocusManager.addPropertyChangeListener("focusOwner", focusPropertyChangeListener);
+ // force this AWT Canvas to be focus-able,
+ // since this it is completely covered by the newtChild (z-order).
+ setFocusable(true);
+ if(isOnscreen) {
+ // onscreen newt child needs to fwd AWT focus
+ newtChild.setKeyboardFocusHandler(newtFocusTraversalKeyListener);
+ } else {
+ // offscreen newt child requires AWT to fwd AWT key/mouse event
+ awtMouseAdapter.setDownstream(newtChild);
+ // We cannot consume AWT mouse click, since it would disable focus via mouse click!
+ // awtMouseAdapter.setConsumeAWTEvent(true);
+ awtKeyAdapter.setDownstream(newtChild);
+ // We manually transfer the focus via NEWT KeyListener, hence we can mark AWT keys as consumed!
+ awtKeyAdapter.setConsumeAWTEvent(true);
+ }
+ } else {
+ newtChild.removeWindowListener(clearAWTMenusOnNewtFocus);
+ newtChild.setFocusAction(null);
+ newtChild.setDefaultCloseOperation(newtChildCloseOp);
+ setFocusable(false);
+ }
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if Key and Mouse input events will be passed through AWT,
+ * otherwise only the {@link #getNEWTChild() NEWT child} will receive them.
+ * <p>
+ * Normally only the {@link #getNEWTChild() NEWT child} will receive Key and Mouse input events.
+ * In offscreen mode, e.g. OSX/CALayer, the AWT events will be received and translated into NEWT events
+ * and delivered to the NEWT child window.<br/>
+ * Note: AWT key events will {@link java.awt.event.InputEvent#consume() consumed} in pass-through mode.
+ * </p>
+ */
+ public final boolean isAWTEventPassThrough() {
+ return !isOnscreen;
+ }
+
+ private final void attachNewtChild() {
+ if( null == newtChild || null == jawtWindow || newtChildAttached ) {
+ return; // nop
+ }
+ if(DEBUG) {
+ // if ( isShowing() == false ) -> Container was not visible yet.
+ // if ( isShowing() == true ) -> Container is already visible.
+ System.err.println("NewtCanvasAWT.attachNewtChild.0 @ "+currentThreadName());
+ System.err.println("\twin "+newtWinHandleToHexString(newtChild)+
+ ", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()+
+ ", comp "+this+", visible "+isVisible()+", showing "+isShowing()+", displayable "+isDisplayable()+
+ ", cont "+AWTMisc.getContainer(this));
+ }
+
+ newtChildAttached = true;
+ newtChild.setFocusAction(null); // no AWT focus traversal ..
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.attachNewtChild.1: newtChild: "+newtChild);
+ }
+ final int w = getWidth();
+ final int h = getHeight();
+ final boolean isNValid = newtChild.isNativeValid();
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.attachNewtChild.2: size "+w+"x"+h+", isNValid "+isNValid);
+ }
+ newtChild.setVisible(false);
+ newtChild.setSize(w, h);
+ final int[] reqSurfaceScale = new int[2];
+ if( isNValid ) {
+ newtChild.getCurrentSurfaceScale(reqSurfaceScale);
+ } else {
+ newtChild.getRequestedSurfaceScale(reqSurfaceScale);
+ }
+ jawtWindow.setSurfaceScale(reqSurfaceScale);
+ newtChild.reparentWindow(jawtWindow, -1, -1, Window.REPARENT_HINT_BECOMES_VISIBLE);
+ newtChild.addSurfaceUpdatedListener(jawtWindow);
+ if( jawtWindow.isOffscreenLayerSurfaceEnabled() &&
+ 0 != ( JAWTUtil.JAWT_OSX_CALAYER_QUIRK_POSITION & JAWTUtil.getOSXCALayerQuirks() ) ) {
+ AWTEDTExecutor.singleton.invoke(false, forceRelayout);
+ }
+ newtChild.setVisible(true);
+ configureNewtChild(true);
+ newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener
+
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.attachNewtChild.X: win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()+", comp "+this);
+ }
+ }
+ private final Runnable forceRelayout = new Runnable() {
+ @Override
+ public void run() {
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.forceRelayout.0");
+ }
+ // Hack to force proper native AWT layout incl. CALayer components on OSX
+ final java.awt.Component component = NewtCanvasAWT.this;
+ final int cW = component.getWidth();
+ final int cH = component.getHeight();
+ component.setSize(cW+1, cH+1);
+ component.setSize(cW, cH);
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.forceRelayout.X");
+ }
+ } };
+
+ private final void detachNewtChild(final java.awt.Container cont) {
+ if( null == newtChild || null == jawtWindow || !newtChildAttached ) {
+ return; // nop
+ }
+ if(DEBUG) {
+ // if ( isShowing() == false ) -> Container was not visible yet.
+ // if ( isShowing() == true ) -> Container is already visible.
+ System.err.println("NewtCanvasAWT.detachNewtChild.0: win "+newtWinHandleToHexString(newtChild)+
+ ", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()+
+ ", comp "+this+", visible "+isVisible()+", showing "+isShowing()+", displayable "+isDisplayable()+
+ ", cont "+cont);
+ }
+
+ newtChild.removeSurfaceUpdatedListener(jawtWindow);
+ newtChildAttached = false;
+ newtChild.setFocusAction(null); // no AWT focus traversal ..
+ configureNewtChild(false);
+ newtChild.setVisible(false);
+
+ newtChild.reparentWindow(null, -1, -1, 0 /* hint */); // will destroy context (offscreen -> onscreen) and implicit detachSurfaceLayer
+
+ if(DEBUG) {
+ System.err.println("NewtCanvasAWT.detachNewtChild.X: win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()+", comp "+this);
+ }
}
// Disables the AWT's erasing of this Canvas's background on Windows
@@ -567,6 +957,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
if (!disableBackgroundEraseInitialized) {
try {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
public Object run() {
try {
Class<?> clazz = getToolkit().getClass();
@@ -576,16 +967,16 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
clazz.getDeclaredMethod("disableBackgroundErase",
new Class[] { Canvas.class });
disableBackgroundEraseMethod.setAccessible(true);
- } catch (Exception e) {
+ } catch (final Exception e) {
clazz = clazz.getSuperclass();
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
}
return null;
}
});
- } catch (Exception e) {
+ } catch (final Exception e) {
}
disableBackgroundEraseInitialized = true;
if(DEBUG) {
@@ -597,7 +988,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
Throwable t=null;
try {
disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this });
- } catch (Exception e) {
+ } catch (final Exception e) {
t = e;
}
if(DEBUG) {
@@ -605,11 +996,13 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
}
}
}
-
- static String newtWinHandleToHexString(Window w) {
+
+ protected static String currentThreadName() { return "["+Thread.currentThread().getName()+", isAWT-EDT "+EventQueue.isDispatchThread()+"]"; }
+
+ static String newtWinHandleToHexString(final Window w) {
return null != w ? toHexString(w.getWindowHandle()) : "nil";
}
- static String toHexString(long l) {
+ static String toHexString(final long l) {
return "0x"+Long.toHexString(l);
}
}
diff --git a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java
index d06aca039..72b3e43f3 100755..100644
--- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java
+++ b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java
@@ -32,9 +32,11 @@ import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Component;
import java.awt.Container;
+import java.awt.EventQueue;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
+import java.util.Arrays;
import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode;
import javax.media.opengl.FPSCounter;
@@ -42,15 +44,19 @@ import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
+import jogamp.nativewindow.jawt.JAWTUtil;
+
+import com.jogamp.common.util.awt.AWTEDTExecutor;
import com.jogamp.newt.awt.NewtCanvasAWT;
import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.newt.util.applet.JOGLNewtAppletBase;
-/**
+/**
* Simple GLEventListener deployment as an applet using JOGL. This demo must be
* referenced from a web page via an &lt;applet&gt; tag.
- *
+ *
* <p>
- * Example of an applet tag using GearsES2 within the applet area (normal case):
+ * Example of an applet tag using GearsES2 within the applet area (normal case):
* <pre>
&lt;applet width=100 height=100&gt;
&lt;param name="java_arguments" value="-Dsun.java2d.noddraw=true"&gt;
@@ -63,9 +69,9 @@ import com.jogamp.newt.opengl.GLWindow;
&lt;/applet&gt;Hello Gears !
* </pre>
* </p>
- *
+ *
* <p>
- * Example of an applet tag using GearsES2 in an undecorated, translucent, closeable and always-on-top window:
+ * Example of an applet tag using GearsES2 in an undecorated, translucent, closeable and always-on-top window:
* <pre>
&lt;applet width=1 height=1&gt;
&lt;param name="java_arguments" value="-Dsun.java2d.noddraw=true"&gt;
@@ -93,22 +99,19 @@ import com.jogamp.newt.opengl.GLWindow;
@SuppressWarnings("serial")
public class JOGLNewtApplet1Run extends Applet {
public static final boolean DEBUG = JOGLNewtAppletBase.DEBUG;
-
- GLWindow glWindow;
- NewtCanvasAWT newtCanvasAWT;
- JOGLNewtAppletBase base;
+
+ GLWindow glWindow = null;
+ NewtCanvasAWT newtCanvasAWT = null;
+ JOGLNewtAppletBase base = null;
/** if valid glStandalone:=true (own window) ! */
- int glXd=Integer.MAX_VALUE, glYd=Integer.MAX_VALUE, glWidth=Integer.MAX_VALUE, glHeight=Integer.MAX_VALUE;
- boolean glStandalone = false;
+ int glXd=Integer.MAX_VALUE, glYd=Integer.MAX_VALUE, glWidth=Integer.MAX_VALUE, glHeight=Integer.MAX_VALUE;
+ @Override
public void init() {
if(DEBUG) {
- System.err.println("JOGLNewtApplet1Run.init() START");
- }
- if(!(this instanceof Container)) {
- throw new RuntimeException("This Applet is not a AWT Container");
+ System.err.println("JOGLNewtApplet1Run.init() START - "+currentThreadName());
}
- Container container = (Container) this;
+ final Container container = this;
String glEventListenerClazzName=null;
String glProfileName=null;
@@ -134,20 +137,20 @@ public class JOGLNewtApplet1Run extends Applet {
glCloseable = JOGLNewtAppletBase.str2Bool(getParameter("gl_closeable"), glCloseable);
glOpaque = JOGLNewtAppletBase.str2Bool(getParameter("gl_opaque"), glOpaque);
glAlphaBits = JOGLNewtAppletBase.str2Int(getParameter("gl_alpha"), glAlphaBits);
- glNumMultisampleBuffer = JOGLNewtAppletBase.str2Int(getParameter("gl_multisamplebuffer"), glNumMultisampleBuffer);
+ glNumMultisampleBuffer = JOGLNewtAppletBase.str2Int(getParameter("gl_multisamplebuffer"), glNumMultisampleBuffer);
glXd = JOGLNewtAppletBase.str2Int(getParameter("gl_dx"), glXd);
glYd = JOGLNewtAppletBase.str2Int(getParameter("gl_dy"), glYd);
glWidth = JOGLNewtAppletBase.str2Int(getParameter("gl_width"), glWidth);
glHeight = JOGLNewtAppletBase.str2Int(getParameter("gl_height"), glHeight);
glNoDefaultKeyListener = JOGLNewtAppletBase.str2Bool(getParameter("gl_nodefaultkeyListener"), glNoDefaultKeyListener);
appletDebugTestBorder = JOGLNewtAppletBase.str2Bool(getParameter("appletDebugTestBorder"), appletDebugTestBorder);
- } catch (Exception e) {
+ } catch (final Exception e) {
e.printStackTrace();
}
if(null==glEventListenerClazzName) {
throw new RuntimeException("No applet parameter 'gl_event_listener_class'");
}
- glStandalone = Integer.MAX_VALUE>glXd && Integer.MAX_VALUE>glYd && Integer.MAX_VALUE>glWidth && Integer.MAX_VALUE>glHeight;
+ final boolean glStandalone = Integer.MAX_VALUE>glXd && Integer.MAX_VALUE>glYd && Integer.MAX_VALUE>glWidth && Integer.MAX_VALUE>glHeight;
if(DEBUG) {
System.err.println("JOGLNewtApplet1Run Configuration:");
System.err.println("glStandalone: "+glStandalone);
@@ -167,8 +170,8 @@ public class JOGLNewtApplet1Run extends Applet {
System.err.println("glNumMultisampleBuffer: "+glNumMultisampleBuffer);
System.err.println("glNoDefaultKeyListener: "+glNoDefaultKeyListener);
}
-
- base = new JOGLNewtAppletBase(glEventListenerClazzName,
+
+ base = new JOGLNewtAppletBase(glEventListenerClazzName,
glSwapInterval,
glNoDefaultKeyListener,
glCloseable,
@@ -176,7 +179,7 @@ public class JOGLNewtApplet1Run extends Applet {
glTrace);
try {
- GLCapabilities caps = new GLCapabilities(GLProfile.get(glProfileName));
+ final GLCapabilities caps = new GLCapabilities(GLProfile.get(glProfileName));
caps.setAlphaBits(glAlphaBits);
if(0<glNumMultisampleBuffer) {
caps.setSampleBuffers(true);
@@ -190,14 +193,17 @@ public class JOGLNewtApplet1Run extends Applet {
glWindow.setDefaultCloseOperation(glCloseable ? WindowClosingMode.DISPOSE_ON_CLOSE : WindowClosingMode.DO_NOTHING_ON_CLOSE);
container.setLayout(new BorderLayout());
if(appletDebugTestBorder) {
- container.add(new Button("North"), BorderLayout.NORTH);
- container.add(new Button("South"), BorderLayout.SOUTH);
- container.add(new Button("East"), BorderLayout.EAST);
- container.add(new Button("West"), BorderLayout.WEST);
+ AWTEDTExecutor.singleton.invoke(true, new Runnable() {
+ public void run() {
+ container.add(new Button("North"), BorderLayout.NORTH);
+ container.add(new Button("South"), BorderLayout.SOUTH);
+ container.add(new Button("East"), BorderLayout.EAST);
+ container.add(new Button("West"), BorderLayout.WEST);
+ } } );
}
base.init(glWindow);
if(base.isValid()) {
- GLEventListener glEventListener = base.getGLEventListener();
+ final GLEventListener glEventListener = base.getGLEventListener();
if(glEventListener instanceof MouseListener) {
addMouseListener((MouseListener)glEventListener);
@@ -209,32 +215,45 @@ public class JOGLNewtApplet1Run extends Applet {
addKeyListener((KeyListener)glEventListener);
}
}
- if(glStandalone) {
- newtCanvasAWT = null;
- } else {
- newtCanvasAWT = new NewtCanvasAWT(glWindow);
- container.add(newtCanvasAWT, BorderLayout.CENTER);
- container.validate();
+ if( !glStandalone ) {
+ AWTEDTExecutor.singleton.invoke(true, new Runnable() {
+ public void run() {
+ newtCanvasAWT = new NewtCanvasAWT(glWindow);
+ newtCanvasAWT.setSkipJAWTDestroy(true); // Bug 910
+ container.add(newtCanvasAWT, BorderLayout.CENTER);
+ container.validate();
+ } } );
}
- } catch (Throwable t) {
+ } catch (final Throwable t) {
throw new RuntimeException(t);
}
if(DEBUG) {
- System.err.println("JOGLNewtApplet1Run.init() END");
+ System.err.println("JOGLNewtApplet1Run.init() END - "+currentThreadName());
}
}
+ private static String currentThreadName() { return "["+Thread.currentThread().getName()+", isAWT-EDT "+EventQueue.isDispatchThread()+"]"; }
+
+ @Override
public void start() {
if(DEBUG) {
- System.err.println("JOGLNewtApplet1Run.start() START");
+ System.err.println("JOGLNewtApplet1Run.start() START (isVisible "+isVisible()+", isDisplayable "+isDisplayable()+") - "+currentThreadName());
}
- this.validate();
- this.setVisible(true);
-
- final java.awt.Point p0 = this.getLocationOnScreen();
- if(glStandalone) {
+ final java.awt.Point[] p0 = { null };
+ AWTEDTExecutor.singleton.invoke(true, new Runnable() {
+ public void run() {
+ setVisible(true);
+ p0[0] = getLocationOnScreen();
+ if( null != newtCanvasAWT ) {
+ newtCanvasAWT.setFocusable(true);
+ newtCanvasAWT.requestFocus();
+ }
+ }
+ });
+ if( null == newtCanvasAWT ) {
+ glWindow.requestFocus();
glWindow.setSize(glWidth, glHeight);
- glWindow.setPosition(p0.x+glXd, p0.y+glYd);
+ glWindow.setPosition(p0[0].x+glXd, p0[0].y+glYd);
}
if(DEBUG) {
Component topC = this;
@@ -243,7 +262,7 @@ public class JOGLNewtApplet1Run extends Applet {
}
System.err.println("JOGLNewtApplet1Run start:");
System.err.println("TopComponent: "+topC.getLocation()+" rel, "+topC.getLocationOnScreen()+" screen, visible "+topC.isVisible()+", "+topC);
- System.err.println("Applet Pos: "+this.getLocation()+" rel, "+p0+" screen, visible "+this.isVisible()+", "+this);
+ System.err.println("Applet Pos: "+this.getLocation()+" rel, "+Arrays.toString(p0)+" screen, visible "+this.isVisible()+", "+this);
if(null != newtCanvasAWT) {
System.err.println("NewtCanvasAWT Pos: "+newtCanvasAWT.getLocation()+" rel, "+newtCanvasAWT.getLocationOnScreen()+" screen, visible "+newtCanvasAWT.isVisible()+", "+newtCanvasAWT);
}
@@ -251,34 +270,54 @@ public class JOGLNewtApplet1Run extends Applet {
System.err.println("GLWindow: "+glWindow);
}
base.start();
+ if( null != newtCanvasAWT &&
+ newtCanvasAWT.isOffscreenLayerSurfaceEnabled() &&
+ 0 != ( JAWTUtil.JAWT_OSX_CALAYER_QUIRK_POSITION & JAWTUtil.getOSXCALayerQuirks() ) ) {
+ // force relayout
+ AWTEDTExecutor.singleton.invoke(true, new Runnable() {
+ public void run() {
+ final int cW = newtCanvasAWT.getWidth();
+ final int cH = newtCanvasAWT.getHeight();
+ newtCanvasAWT.setSize(cW+1, cH+1);
+ newtCanvasAWT.setSize(cW, cH);
+ } } );
+ }
if(DEBUG) {
- System.err.println("JOGLNewtApplet1Run.start() END");
+ System.err.println("JOGLNewtApplet1Run.start() END - "+currentThreadName());
}
}
+ @Override
public void stop() {
if(DEBUG) {
- System.err.println("JOGLNewtApplet1Run.stop() START");
+ System.err.println("JOGLNewtApplet1Run.stop() START - "+currentThreadName());
}
base.stop();
if(DEBUG) {
- System.err.println("JOGLNewtApplet1Run.stop() END");
+ System.err.println("JOGLNewtApplet1Run.stop() END - "+currentThreadName());
}
}
+ @Override
public void destroy() {
if(DEBUG) {
- System.err.println("JOGLNewtApplet1Run.destroy() START");
- }
- glWindow.setVisible(false); // hide 1st
- if(!glStandalone) {
- glWindow.reparentWindow(null); // get out of newtCanvasAWT
- this.remove(newtCanvasAWT); // remove newtCanvasAWT
+ System.err.println("JOGLNewtApplet1Run.destroy() START - "+currentThreadName());
}
+ AWTEDTExecutor.singleton.invoke(true, new Runnable() {
+ public void run() {
+ glWindow.setVisible(false); // hide 1st
+ if( null != newtCanvasAWT ) {
+ newtCanvasAWT.setSkipJAWTDestroy(false); // Bug 910
+ remove(newtCanvasAWT); // remove newtCanvasAWT incl. glWindow.reparentWindow(null) if not done yet!
+ newtCanvasAWT.destroy();
+ }
+ } } );
base.destroy(); // destroy glWindow unrecoverable
base=null;
+ glWindow=null;
+ newtCanvasAWT=null;
if(DEBUG) {
- System.err.println("JOGLNewtApplet1Run.destroy() END");
+ System.err.println("JOGLNewtApplet1Run.destroy() END - "+currentThreadName());
}
}
}
diff --git a/src/newt/classes/com/jogamp/newt/event/DoubleTapScrollGesture.java b/src/newt/classes/com/jogamp/newt/event/DoubleTapScrollGesture.java
new file mode 100644
index 000000000..7fec29259
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/event/DoubleTapScrollGesture.java
@@ -0,0 +1,349 @@
+/**
+ * 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 com.jogamp.newt.event;
+
+import com.jogamp.common.util.PropertyAccess;
+
+import jogamp.newt.Debug;
+
+/**
+ * 2 pointer scroll/rotate gesture handler processing {@link MouseEvent}s
+ * while producing {@link MouseEvent#EVENT_MOUSE_WHEEL_MOVED} events if gesture is completed.
+ * <p>
+ * Criteria related to parameters:
+ * <pre>
+ * - doubleTapSlop (scaled in pixels):
+ * - Max 2 finger distance to start 'scroll' mode
+ * - Max. distance diff of current 2-pointer middle and initiated 2-pointer middle.
+ *
+ * - touchSlop (scaled in pixels):
+ * - Min. movement w/ 2 pointer within ScaledDoubleTapSlop starting 'scroll' mode
+ *
+ * - Avoid computation if not within gesture, especially for MOVE/DRAG
+ *
+ * - Only allow gesture to start with PRESS
+ *
+ * - Leave gesture completely with RELEASE of both/all fingers, or dist-diff exceeds doubleTapSlop
+ *
+ * - Tolerate temporary lift 1 of 2 pointer
+ *
+ * - Always validate pointer-id
+ * </pre>
+ * </p>
+ * Implementation uses a n-state to get detect gesture:
+ * <p>
+ * <table border="1">
+ * <tr><th>from</th> <th>to</th> <th>action</th></tr>
+ * <tr><td>NONE</td> <td>1PRESS</td> <td>1-pointer-pressed</td></tr>
+ * <tr><td>1PRESS</td> <td>2PRESS_T</td> <td>2-pointer-pressed within doubleTapSlope</td></tr>
+ * <tr><td>2PRESS_T</td> <td>SCROLL</td> <td>2-pointer dragged, dist-diff within doubleTapSlop and scrollLen >= scrollSlop</td></tr>
+ * <tr><td>2PRESS_C</td> <td>SCROLL</td> <td>2-pointer dragged, dist-diff within doubleTapSlop</td></tr>
+ * <tr><td>SCROLL</td> <td>SCROLL</td> <td>2-pointer dragged, dist-diff within doubleTapSlop</td></tr>
+ * </table>
+ * State ST_2PRESS_C merely exist to pick up gesture after one pointer has been lost temporarily.
+ * </p>
+ * <p>
+ * {@link #isWithinGesture()} returns gestureState >= 2PRESS_C
+ * </p>
+ */
+public class DoubleTapScrollGesture implements GestureHandler {
+ /** Scroll threshold in pixels (fallback), defaults to 16 pixels. Can be overriden by integer property <code>newt.event.scroll_slop_pixel</code>.*/
+ public static final int SCROLL_SLOP_PIXEL;
+ /** Two pointer 'double tap' slop in pixels (fallback), defaults to 104 pixels. Can be overriden by integer property <code>newt.event.double_tap_slop_pixel</code>.*/
+ public static final int DOUBLE_TAP_SLOP_PIXEL;
+
+ /** Scroll threshold in millimeter, defaults to 3 mm. Can be overriden by integer property <code>newt.event.scroll_slop_mm</code>.*/
+ public static final float SCROLL_SLOP_MM;
+ /** Two pointer 'double tap' slop in millimeter, defaults to 20 mm. Can be overriden by integer property <code>newt.event.double_tap_slop_mm</code>.*/
+ public static final float DOUBLE_TAP_SLOP_MM;
+
+ static {
+ Debug.initSingleton();
+
+ SCROLL_SLOP_PIXEL = PropertyAccess.getIntProperty("newt.event.scroll_slop_pixel", true, 16);
+ DOUBLE_TAP_SLOP_PIXEL = PropertyAccess.getIntProperty("newt.event.double_tap_slop_pixel", true, 104);
+ SCROLL_SLOP_MM = PropertyAccess.getIntProperty("newt.event.scroll_slop_mm", true, 3);
+ DOUBLE_TAP_SLOP_MM = PropertyAccess.getIntProperty("newt.event.double_tap_slop_mm", true, 20);
+ }
+
+ private static final int ST_NONE = 0;
+ private static final int ST_1PRESS = 1;
+ private static final int ST_2PRESS_T = 2;
+ private static final int ST_2PRESS_C = 3;
+ private static final int ST_SCROLL = 4;
+
+ private final int scrollSlop, scrollSlopSquare, doubleTapSlop, doubleTapSlopSquare;
+ private final float[] scrollDistance = new float[] { 0f, 0f };
+ private final int[] pIds = new int[] { -1, -1 };
+ /** See class docu */
+ private int gestureState;
+ private int sqStartDist;
+ private int lastX, lastY;
+ private int pointerDownCount;
+ private MouseEvent hitGestureEvent;
+
+ private static final int getSquareDistance(final float x1, final float y1, final float x2, final float y2) {
+ final int deltaX = (int) x1 - (int) x2;
+ final int deltaY = (int) y1 - (int) y2;
+ return deltaX * deltaX + deltaY * deltaY;
+ }
+
+ private int gesturePointers(final MouseEvent e, final int excludeIndex) {
+ int j = 0;
+ for(int i=e.getPointerCount()-1; i>=0; i--) {
+ if( excludeIndex != i ) {
+ final int id = e.getPointerId(i);
+ if( pIds[0] == id || pIds[1] == id ) {
+ j++;
+ }
+ }
+ }
+ return j;
+ }
+
+ /**
+ * scaledScrollSlop < scaledDoubleTapSlop
+ * @param scaledScrollSlop Distance a pointer can wander before we think the user is scrolling in <i>pixels</i>.
+ * @param scaledDoubleTapSlop Distance in <i>pixels</i> between the first touch and second touch to still be considered a double tap.
+ */
+ public DoubleTapScrollGesture(final int scaledScrollSlop, final int scaledDoubleTapSlop) {
+ scrollSlop = scaledScrollSlop;
+ scrollSlopSquare = scaledScrollSlop * scaledScrollSlop;
+ doubleTapSlop = scaledDoubleTapSlop;
+ doubleTapSlopSquare = scaledDoubleTapSlop * scaledDoubleTapSlop;
+ pointerDownCount = 0;
+ clear(true);
+ if(DEBUG) {
+ System.err.println("DoubleTapScroll scrollSlop (scaled) "+scrollSlop);
+ System.err.println("DoubleTapScroll doubleTapSlop (scaled) "+doubleTapSlop);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "DoubleTapScroll[state "+gestureState+", in "+isWithinGesture()+", has "+(null!=hitGestureEvent)+", pc "+pointerDownCount+"]";
+ }
+
+ @Override
+ public void clear(final boolean clearStarted) {
+ scrollDistance[0] = 0f;
+ scrollDistance[1] = 0f;
+ hitGestureEvent = null;
+ if( clearStarted ) {
+ gestureState = ST_NONE;
+ sqStartDist = 0;
+ pIds[0] = -1;
+ pIds[1] = -1;
+ lastX = 0;
+ lastY = 0;
+ }
+ }
+
+ @Override
+ public boolean isWithinGesture() {
+ return ST_2PRESS_C <= gestureState;
+ }
+
+ @Override
+ public boolean hasGesture() {
+ return null != hitGestureEvent;
+ }
+
+ @Override
+ public InputEvent getGestureEvent() {
+ if( null != hitGestureEvent ) {
+ final MouseEvent ge = hitGestureEvent;
+ int modifiers = ge.getModifiers();
+ final float[] rotationXYZ = ge.getRotation();
+ rotationXYZ[0] = scrollDistance[0] / scrollSlop;
+ rotationXYZ[1] = scrollDistance[1] / scrollSlop;
+ if( rotationXYZ[0]*rotationXYZ[0] > rotationXYZ[1]*rotationXYZ[1] ) {
+ // Horizontal scroll -> SHIFT
+ modifiers |= com.jogamp.newt.event.InputEvent.SHIFT_MASK;
+ }
+ return new MouseEvent(MouseEvent.EVENT_MOUSE_WHEEL_MOVED, ge.getSource(), ge.getWhen(), modifiers,
+ ge.getAllPointerTypes(), ge.getAllPointerIDs(),
+ ge.getAllX(), ge.getAllY(), ge.getAllPressures(), ge.getMaxPressure(),
+ ge.getButton(), ge.getClickCount(), rotationXYZ, scrollSlop);
+ }
+ return null;
+ }
+
+ public final float[] getScrollDistanceXY() {
+ return scrollDistance;
+ }
+
+ @Override
+ public boolean process(final InputEvent in) {
+ if( null != hitGestureEvent || !(in instanceof MouseEvent) ) {
+ return true;
+ }
+ final MouseEvent pe = (MouseEvent)in;
+ if( pe.getPointerType(0).getPointerClass() != MouseEvent.PointerClass.Onscreen ) {
+ return false;
+ }
+ pointerDownCount = pe.getPointerCount();
+ final int eventType = pe.getEventType();
+ final int x0 = pe.getX(0);
+ final int y0 = pe.getY(0);
+ switch ( eventType ) {
+ case MouseEvent.EVENT_MOUSE_PRESSED: {
+ int gPtr = 0;
+ if( ST_NONE == gestureState && 1 == pointerDownCount ) {
+ pIds[0] = pe.getPointerId(0);
+ pIds[1] = -1;
+ gestureState = ST_1PRESS;
+ } else if( ST_NONE < gestureState && 2 == pointerDownCount && 1 == gesturePointers(pe, 0) /* w/o pressed pointer */ ) {
+ final int x1 = pe.getX(1);
+ final int y1 = pe.getY(1);
+ final int xm = (x0+x1)/2;
+ final int ym = (y0+y1)/2;
+
+ if( ST_1PRESS == gestureState ) {
+ final int sqDist = getSquareDistance(x0, y0, x1, y1);
+ final boolean isDistWithinDoubleTapSlop = sqDist < doubleTapSlopSquare;
+ if( isDistWithinDoubleTapSlop ) {
+ // very first 2-finger touch-down
+ gPtr = 2;
+ pIds[0] = pe.getPointerId(0);
+ pIds[1] = pe.getPointerId(1);
+ lastX = xm;
+ lastY = ym;
+ sqStartDist = sqDist;
+ gestureState = ST_2PRESS_T;
+ }
+ if(DEBUG) {
+ final int dist = (int)Math.round(Math.sqrt(sqDist));
+ System.err.println(this+".pressed.1: dist "+dist+", gPtr "+gPtr+", distWithin2DTSlop "+isDistWithinDoubleTapSlop+", last "+lastX+"/"+lastY+", "+pe);
+ }
+ } else if( ST_2PRESS_C == gestureState ) { // pick up gesture after temp loosing one pointer
+ gPtr = gesturePointers(pe, -1);
+ if( 2 == gPtr ) {
+ // same pointers re-touch-down
+ lastX = xm;
+ lastY = ym;
+ } else {
+ // other 2 pointers .. should rarely happen!
+ clear(true);
+ }
+ }
+ }
+ if(DEBUG) {
+ System.err.println(this+".pressed: gPtr "+gPtr+", this "+lastX+"/"+lastY+", "+pe);
+ }
+ } break;
+
+ case MouseEvent.EVENT_MOUSE_RELEASED: {
+ pointerDownCount--; // lifted
+ final int gPtr = gesturePointers(pe, 0); // w/o lifted pointer
+ if ( 1 == gPtr ) {
+ // tolerate lifting 1 of 2 gesture pointers temporary
+ gestureState = ST_2PRESS_C;
+ } else if( 0 == gPtr ) {
+ // all lifted
+ clear(true);
+ }
+ if(DEBUG) {
+ System.err.println(this+".released: gPtr "+gPtr+", "+pe);
+ }
+ } break;
+
+ case MouseEvent.EVENT_MOUSE_DRAGGED: {
+ if( 2 == pointerDownCount && ST_1PRESS < gestureState ) {
+ final int gPtr = gesturePointers(pe, -1);
+ if( 2 == gPtr ) {
+ // same pointers
+ final int x1 = pe.getX(1);
+ final int y1 = pe.getY(1);
+ final int xm = (x0+x1)/2;
+ final int ym = (y0+y1)/2;
+ final int sqDist = getSquareDistance(x0, y0, x1, y1);
+ final boolean isDistDiffWithinDoubleTapSlop = Math.abs(sqDist - sqStartDist) <= doubleTapSlopSquare;
+ if( isDistDiffWithinDoubleTapSlop ) {
+ switch( gestureState ) {
+ case ST_2PRESS_T: {
+ final int sqScrollLen = getSquareDistance(lastX, lastY, xm, ym);
+ if( sqScrollLen > scrollSlopSquare ) { // min. scrolling threshold reached
+ gestureState = ST_SCROLL;
+ }
+ } break;
+
+ case ST_2PRESS_C:
+ gestureState = ST_SCROLL;
+ break;
+
+ case ST_SCROLL:
+ scrollDistance[0] = lastX - xm;
+ scrollDistance[1] = lastY - ym;
+ hitGestureEvent = pe;
+ break;
+ }
+ if(DEBUG) {
+ final boolean isDistWithinDoubleTapSlop = sqDist < doubleTapSlopSquare;
+ final int dist = (int)Math.round(Math.sqrt(sqDist));
+ final int sqScrollLen = getSquareDistance(lastX, lastY, xm, ym);
+ final int scrollLen = (int)Math.round(Math.sqrt(sqScrollLen));
+ System.err.println(this+".dragged.1: pDist "+dist+", scrollLen "+scrollLen+", gPtr "+gPtr+" ["+pIds[0]+", "+pIds[1]+"]"+
+ ", diffDistWithinTapSlop "+isDistDiffWithinDoubleTapSlop+
+ ", distWithin2DTSlop "+isDistWithinDoubleTapSlop+
+ ", this "+xm+"/"+ym+", last "+lastX+"/"+lastY+", d "+scrollDistance[0]+"/"+scrollDistance[1]);
+ }
+ } else {
+ // distance too big ..
+ if(DEBUG) {
+ final boolean isDistWithinDoubleTapSlop = sqDist < doubleTapSlopSquare;
+ final int dist = (int)Math.round(Math.sqrt(sqDist));
+ final int startDist = (int)Math.round(Math.sqrt(sqStartDist));
+ System.err.println(this+".dragged.X1: pDist "+dist+", distStart "+startDist+", gPtr "+gPtr+" ["+pIds[0]+", "+pIds[1]+"]"+
+ ", diffDistWithinTapSlop "+isDistDiffWithinDoubleTapSlop+
+ ", distWithin2DTSlop "+isDistWithinDoubleTapSlop+
+ ", this "+xm+"/"+ym+", last "+lastX+"/"+lastY+", d "+scrollDistance[0]+"/"+scrollDistance[1]);
+ }
+ clear(true);
+ }
+ if( ST_2PRESS_T < gestureState ) {
+ // state ST_2PRESS_T waits for min scroll threshold !
+ lastX = xm;
+ lastY = ym;
+ }
+ } else {
+ // other 2 pointers .. should rarely happen!
+ if(DEBUG) {
+ System.err.println(this+".dragged.X2: gPtr "+gPtr+" ["+pIds[0]+", "+pIds[1]+"]"+
+ ", last "+lastX+"/"+lastY+", d "+scrollDistance[0]+"/"+scrollDistance[1]);
+ }
+ clear(true);
+ }
+ }
+ } break;
+
+ default:
+ }
+ return null != hitGestureEvent;
+ }
+}
diff --git a/src/newt/classes/com/jogamp/newt/event/GestureHandler.java b/src/newt/classes/com/jogamp/newt/event/GestureHandler.java
new file mode 100644
index 000000000..ea0f76fbb
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/event/GestureHandler.java
@@ -0,0 +1,155 @@
+/**
+ * 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 com.jogamp.newt.event;
+
+import jogamp.newt.Debug;
+
+/**
+ * Generic gesture handler interface designed to allow pass-through
+ * filtering of {@link InputEvent}s.
+ * <p>
+ * To avoid negative impact on event processing,
+ * implementation shall restrict computation as much as possible
+ * and only within it's appropriate gesture states.
+ * </p>
+ * <p>
+ * To allow custom user events, other than the <i>normal</i> {@link InputEvent}s,
+ * a user may return a {@link GestureEvent} in it's implementation.
+ * </p>
+ */
+public interface GestureHandler {
+ public static final boolean DEBUG = Debug.debug("Window.MouseEvent");
+
+ /** A custom gesture event */
+ @SuppressWarnings("serial")
+ public static class GestureEvent extends InputEvent {
+ /** A gesture has been detected. */
+ public static final short EVENT_GESTURE_DETECTED = 400;
+
+ private final GestureHandler handler;
+ private final InputEvent ie;
+
+ /**
+ * Creates a gesture event with default type {@link #EVENT_GESTURE_DETECTED}.
+ *
+ * @param source
+ * @param when
+ * @param modifiers
+ * @param handler
+ * @param trigger TODO
+ */
+ public GestureEvent(final Object source, final long when, final int modifiers, final GestureHandler handler, final InputEvent trigger) {
+ super(EVENT_GESTURE_DETECTED, source, when, modifiers);
+ this.handler = handler;
+ this.ie = trigger;
+ }
+
+ /**
+ * Creates a gesture event with custom <i>event_type</i> !
+ * @param event_type must lie within [400..599]
+ * @param source
+ * @param when
+ * @param modifiers
+ * @param handler
+ * @param trigger TODO
+ */
+ public GestureEvent(final short event_type, final Object source, final long when, final int modifiers, final GestureHandler handler, final InputEvent trigger) {
+ super(event_type, source, when, modifiers);
+ this.handler = handler;
+ this.ie = trigger;
+ }
+
+ /** Return the {@link GestureHandler}, which produced the event. */
+ public final GestureHandler getHandler() { return handler; }
+
+ /** Triggering {@link InputEvent} */
+ public final InputEvent getTrigger() { return ie; }
+
+ public String toString() {
+ return "GestureEvent[handler "+handler+"]";
+ }
+ }
+
+ /**
+ * Listener for {@link GestureEvent}s.
+ *
+ * @see GestureEvent
+ */
+ public static interface GestureListener extends NEWTEventListener
+ {
+ /** {@link GestureHandler} {@link GestureHandler#hasGesture() has detected} the gesture. */
+ public void gestureDetected(GestureEvent gh);
+ }
+
+ /**
+ * Clears state of handler, i.e. resets all states incl. previous detected gesture.
+ * @param clearStarted if true, also clears {@link #isWithinGesture() started} state,
+ * otherwise stay within gesture - if appropriate.
+ * Staying within a gesture allows fluent continuous gesture sequence,
+ * e.g. for scrolling.
+ */
+ public void clear(boolean clearStarted);
+
+ /**
+ * Returns true if a previous {@link #process(InputEvent)} command produced a gesture,
+ * which has not been {@link #clear(boolean) cleared}.
+ * Otherwise returns false.
+ */
+ public boolean hasGesture();
+
+ /**
+ * Returns the corresponding {@link InputEvent} for the gesture as detected by
+ * a previous {@link #process(InputEvent)}, which has not been {@link #clear(boolean) cleared}.
+ * Otherwise returns null.
+ * <p>
+ * Only implemented for gestures mapping to {@link InputEvent}s.
+ * </p>
+ */
+ public InputEvent getGestureEvent();
+
+ /**
+ * Returns true if within a gesture as detected by a previous {@link #process(InputEvent)} command,
+ * which has not been {@link #clear(boolean) cleared}.
+ * Otherwise returns false.
+ */
+ public boolean isWithinGesture();
+
+ /**
+ * Process the given {@link InputEvent} and returns true if it produced the gesture.
+ * Otherwise returns false.
+ * <p>
+ * If a gesture was already detected previously and has not been cleared,
+ * method does not process the event and returns true.
+ * </p>
+ * <p>
+ * Besides validation of the event's details,
+ * the handler may also validate the {@link InputEvent.InputClass} and/or {@link InputEvent.InputType}.
+ * </p>
+ */
+ public boolean process(InputEvent e);
+}
diff --git a/src/newt/classes/com/jogamp/newt/event/InputEvent.java b/src/newt/classes/com/jogamp/newt/event/InputEvent.java
index 148ac5962..fbda79d46 100644
--- a/src/newt/classes/com/jogamp/newt/event/InputEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/InputEvent.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,100 +29,111 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package com.jogamp.newt.event;
+import com.jogamp.common.util.IntBitfield;
import com.jogamp.newt.Window;
@SuppressWarnings("serial")
public abstract class InputEvent extends NEWTEvent
{
+ /** Interface marking class of input types */
+ public static interface InputClass {
+ }
+
+ /** Interface marking type of input devices */
+ public static interface InputType {
+ }
+
public static final int SHIFT_MASK = 1 << 0;
public static final int CTRL_MASK = 1 << 1;
public static final int META_MASK = 1 << 2;
public static final int ALT_MASK = 1 << 3;
- public static final int ALT_GRAPH_MASK = 1 << 5;
- public static final int BUTTON1_MASK = 1 << 6;
- public static final int BUTTON2_MASK = 1 << 7;
- public static final int BUTTON3_MASK = 1 << 8;
- public static final int BUTTON4_MASK = 1 << 9;
- public static final int BUTTON5_MASK = 1 << 10;
- public static final int BUTTON6_MASK = 1 << 11;
-
+ public static final int ALT_GRAPH_MASK = 1 << 4;
+
+ public static final int BUTTON1_MASK = 1 << 5;
+ public static final int BUTTON2_MASK = 1 << 6;
+ public static final int BUTTON3_MASK = 1 << 7;
+ public static final int BUTTON4_MASK = 1 << 8;
+ public static final int BUTTON5_MASK = 1 << 9;
+ public static final int BUTTON6_MASK = 1 << 10;
+ public static final int BUTTON7_MASK = 1 << 11;
+ public static final int BUTTON8_MASK = 1 << 12;
+ public static final int BUTTON9_MASK = 1 << 13;
+
+ public static final int BUTTONLAST_MASK = 1 << 20; // 16 buttons
+ public static final int BUTTONALL_MASK = 0xffff << 5 ; // 16 buttons
+
/** Event is caused by auto-repeat. */
- public static final int AUTOREPEAT_MASK = 1 << 15;
-
+ public static final int AUTOREPEAT_MASK = 1 << 29;
+
/** Pointer is confined, see {@link Window#confinePointer(boolean)}. */
- public static final int CONFINED_MASK = 1 << 16;
-
+ public static final int CONFINED_MASK = 1 << 30;
+
/** Pointer is invisible, see {@link Window#setPointerVisible(boolean)}. */
- public static final int INVISIBLE_MASK = 1 << 17;
+ public static final int INVISIBLE_MASK = 1 << 31;
- /**
+ /**
* Returns the corresponding button mask for the given button.
* <p>
- * In case the given button lies outside
- * of the valid range [{@link MouseEvent#BUTTON1} .. {@link MouseEvent#BUTTON6}],
+ * In case the given button lies outside
+ * of the valid range [{@link MouseEvent#BUTTON1} .. {@link MouseEvent#BUTTON_COUNT}],
* null is returned.
* </p>
*/
- public static final int getButtonMask(int button) {
- if( 0 < button && button <= MouseEvent.BUTTON_NUMBER ) {
- return 1 << ( 5 + button ) ;
+ public static final int getButtonMask(final int button) {
+ if( 0 < button && button <= MouseEvent.BUTTON_COUNT ) {
+ return 1 << ( 4 + button ) ;
}
return 0;
}
-
- /** Object when attached via {@link #setAttachment(Object)} marks the event consumed,
- * ie. stops propagating the event any further to the event listener.
- */
- public static final Object consumedTag = new Object();
-
- protected InputEvent(int eventType, Object source, long when, int modifiers) {
+
+ protected InputEvent(final short eventType, final Object source, final long when, final int modifiers) {
super(eventType, source, when);
this.modifiers=modifiers;
}
/** Return the modifier bits of this event, e.g. see {@link #SHIFT_MASK} .. etc. */
- public int getModifiers() {
+ public final int getModifiers() {
return modifiers;
}
/** {@link #getModifiers()} contains {@link #ALT_MASK}. */
- public boolean isAltDown() {
+ public final boolean isAltDown() {
return (modifiers&ALT_MASK)!=0;
}
/** {@link #getModifiers()} contains {@link #ALT_GRAPH_MASK}. */
- public boolean isAltGraphDown() {
+ public final boolean isAltGraphDown() {
return (modifiers&ALT_GRAPH_MASK)!=0;
}
/** {@link #getModifiers()} contains {@link #CTRL_MASK}. */
- public boolean isControlDown() {
+ public final boolean isControlDown() {
return (modifiers&CTRL_MASK)!=0;
}
/** {@link #getModifiers()} contains {@link #META_MASK}. */
- public boolean isMetaDown() {
+ public final boolean isMetaDown() {
return (modifiers&META_MASK)!=0;
}
/** {@link #getModifiers()} contains {@link #SHIFT_MASK}. */
- public boolean isShiftDown() {
+ public final boolean isShiftDown() {
return (modifiers&SHIFT_MASK)!=0;
}
/** {@link #getModifiers()} contains {@link #AUTOREPEAT_MASK}. */
- public boolean isAutoRepeat() {
+ public final boolean isAutoRepeat() {
return (modifiers&AUTOREPEAT_MASK)!=0;
}
/** {@link #getModifiers()} contains {@link #CONFINED_MASK}. Pointer is confined, see {@link Window#confinePointer(boolean)}. */
- public boolean isConfined() {
+ public final boolean isConfined() {
return (modifiers&CONFINED_MASK)!=0;
}
- /** {@link #getModifiers()} contains {@link #INVISIBLE_MASK}. Pointer is invisible, see {@link Window#setPointerVisible(boolean)}. */
- public boolean isInvisible() {
+ /** {@link #getModifiers()} contains {@link #INVISIBLE_MASK}. Pointer is invisible, see {@link Window#setPointerVisible(boolean)}. */
+ public final boolean isInvisible() {
return (modifiers&INVISIBLE_MASK)!=0;
}
-
- public StringBuilder getModifiersString(StringBuilder sb) {
+
+ public final StringBuilder getModifiersString(StringBuilder sb) {
if(null == sb) {
sb = new StringBuilder();
}
@@ -130,46 +141,81 @@ public abstract class InputEvent extends NEWTEvent
boolean isFirst = true;
if(isShiftDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("shift"); }
if(isControlDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("ctrl"); }
- if(isMetaDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("meta"); }
+ if(isMetaDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("meta"); }
if(isAltDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("alt"); }
- if(isAltGraphDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("altg"); }
+ if(isAltGraphDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("altgr"); }
if(isAutoRepeat()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("repeat"); }
- for(int i=1; i<=MouseEvent.BUTTON_NUMBER; i++) {
+ for(int i=1; i<=MouseEvent.BUTTON_COUNT; i++) {
if(isButtonDown(i)) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("button").append(i); }
}
if(isConfined()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("confined"); }
if(isInvisible()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("invisible"); }
sb.append("]");
-
+
return sb;
}
/**
- * @return Array of pressed mouse buttons [{@link MouseEvent#BUTTON1} .. {@link MouseEvent#BUTTON6}].
+ * See also {@link MouseEvent}'s section about <i>Multiple-Pointer Events</i>.
+ * @return Array of pressed mouse buttons [{@link MouseEvent#BUTTON1} .. {@link MouseEvent#BUTTON6}].
* If none is down, the resulting array is of length 0.
*/
- public final int[] getButtonsDown() {
- int len = 0;
- for(int i=1; i<=MouseEvent.BUTTON_NUMBER; i++) {
- if(isButtonDown(i)) { len++; }
- }
-
- int[] res = new int[len];
+ public final short[] getButtonsDown() {
+ final int len = getButtonDownCount();
+
+ final short[] res = new short[len];
int j = 0;
- for(int i=1; i<=MouseEvent.BUTTON_NUMBER; i++) {
- if(isButtonDown(i)) { res[j++] = ( MouseEvent.BUTTON1 - 1 ) + i; }
+ for(int i=1; i<=MouseEvent.BUTTON_COUNT; i++) {
+ if( isButtonDown(i) ) { res[j++] = (short) ( ( MouseEvent.BUTTON1 - 1 ) + i ); }
}
return res;
}
- public final boolean isButtonDown(int button) {
+ /**
+ * See also {@link MouseEvent}'s section about <i>Multiple-Pointer Events</i>.
+ * @param button the button to test
+ * @return true if the given button is down
+ */
+ public final boolean isButtonDown(final int button) {
return ( modifiers & getButtonMask(button) ) != 0;
}
-
+
+ /**
+ * Returns the number of pressed buttons by counting the set bits:
+ * <pre>
+ * getBitCount(modifiers & BUTTONALL_MASK);
+ * </pre>
+ * <p>
+ * See also {@link MouseEvent}'s section about <i>Multiple-Pointer Events</i>.
+ * </p>
+ * @see IntBitfield#getBitCount(int)
+ * @see #BUTTONALL_MASK
+ */
+ public final int getButtonDownCount() {
+ return IntBitfield.getBitCount(modifiers & BUTTONALL_MASK);
+ }
+
+ /**
+ * Returns true if at least one button is pressed, otherwise false:
+ * <pre>
+ * 0 != ( modifiers & BUTTONALL_MASK )
+ * </pre>
+ * <p>
+ * See also {@link MouseEvent}'s section about <i>Multiple-Pointer Events</i>.
+ * </p>
+ * @see IntBitfield#getBitCount(int)
+ * @see #BUTTONALL_MASK
+ */
+ public final boolean isAnyButtonDown() {
+ return 0 != ( modifiers & BUTTONALL_MASK );
+ }
+
+ @Override
public String toString() {
return toString(null).toString();
}
-
+
+ @Override
public StringBuilder toString(StringBuilder sb) {
if(null == sb) {
sb = new StringBuilder();
diff --git a/src/newt/classes/com/jogamp/newt/event/KeyAdapter.java b/src/newt/classes/com/jogamp/newt/event/KeyAdapter.java
index 93c8409b1..0f147a722 100644
--- a/src/newt/classes/com/jogamp/newt/event/KeyAdapter.java
+++ b/src/newt/classes/com/jogamp/newt/event/KeyAdapter.java
@@ -4,14 +4,14 @@
*
* 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
@@ -21,21 +21,21 @@
* 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 com.jogamp.newt.event;
public abstract class KeyAdapter implements KeyListener
{
- public void keyPressed(KeyEvent e) {
- }
- public void keyReleased(KeyEvent e) {
+ @Override
+ public void keyPressed(final KeyEvent e) {
}
- public void keyTyped(KeyEvent e) {
+ @Override
+ public void keyReleased(final KeyEvent e) {
}
}
diff --git a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
index 7daaeada6..f29e9eb8c 100644
--- a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,734 +29,937 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package com.jogamp.newt.event;
+import com.jogamp.common.util.IntBitfield;
+
/**
+ * <a name="eventDelivery"><h5>KeyEvent Delivery</h5></a>
+ *
* Key events are delivered in the following order:
- * <ol>
- * <li>{@link #EVENT_KEY_PRESSED}</li>
- * <li>{@link #EVENT_KEY_RELEASED}</li>
- * <li>{@link #EVENT_KEY_TYPED}</li>
- * </ol>
+ * <p>
+ * <table border="0">
+ * <tr><th>#</th><th>Event Type</th> <th>Constraints</th> <th>Notes</th></tr>
+ * <tr><td>1</td><td>{@link #EVENT_KEY_PRESSED} </td><td> <i> excluding {@link #isAutoRepeat() auto-repeat}-{@link #isModifierKey() modifier} keys</i></td><td></td></tr>
+ * <tr><td>2</td><td>{@link #EVENT_KEY_RELEASED} </td><td> <i> excluding {@link #isAutoRepeat() auto-repeat}-{@link #isModifierKey() modifier} keys</i></td><td></td></tr>
+ * </table>
+ * </p>
* In case the native platform does not
- * deliver keyboard events in the above order or skip events,
- * the NEWT driver will reorder and inject synthetic events if required.
+ * deliver keyboard events in the above order or skip events,
+ * the NEWT driver will reorder and inject synthetic events if required.
+ * <p>
+ * Besides regular modifiers like {@link InputEvent#SHIFT_MASK} etc.,
+ * the {@link InputEvent#AUTOREPEAT_MASK} bit is added if repetition is detected, following above constraints.
+ * </p>
+ * <p>
+ * Auto-Repeat shall behave as follow:
+ * <pre>
+ P = pressed, R = released
+ 0 = normal, 1 = auto-repeat
+
+ P(0), [ R(1), P(1), R(1), ..], R(0)
+ * </pre>
+ * The idea is if you mask out auto-repeat in your event listener
+ * you just get one long pressed P/R tuple for {@link #isPrintableKey() printable} and {@link #isActionKey() Action} keys.
+ * </p>
+ * <p>
+ * {@link #isActionKey() Action} keys will produce {@link #EVENT_KEY_PRESSED pressed}
+ * and {@link #EVENT_KEY_RELEASED released} events including {@link #isAutoRepeat() auto-repeat}.
+ * </p>
+ * <p>
+ * {@link #isPrintableKey() Printable} keys will produce {@link #EVENT_KEY_PRESSED pressed} and {@link #EVENT_KEY_RELEASED released} events.
+ * </p>
+ * <p>
+ * {@link #isModifierKey() Modifier} keys will produce {@link #EVENT_KEY_PRESSED pressed} and {@link #EVENT_KEY_RELEASED released} events
+ * excluding {@link #isAutoRepeat() auto-repeat}.
+ * They will also influence subsequent event's {@link #getModifiers() modifier} bits while pressed.
+ * </p>
+ *
+ * <a name="unicodeMapping"><h5>Unicode Mapping</h5></a>
+ * <p>
+ * {@link #getKeyChar() Key-chars}, as well as
+ * {@link #isPrintableKey() printable} {@link #getKeyCode() key-codes} and {@link #getKeySymbol() key-symbols}
+ * use the UTF-16 unicode space w/o collision.
+ *
+ * </p>
* <p>
- * Besides regular modifiers like {@link InputEvent#SHIFT_MASK} etc.,
- * the {@link InputEvent#AUTOREPEAT_MASK} bit is added if repetition is detected.
+ * Non-{@link #isPrintableKey() printable} {@link #getKeyCode() key-codes} and {@link #getKeySymbol() key-symbols},
+ * i.e. {@link #isModifierKey() modifier-} and {@link #isActionKey() action-}keys,
+ * are mapped to unicode's control and private range and do not collide w/ {@link #isPrintableKey() printable} unicode values
+ * with the following exception.
+ * </p>
+ *
+ * <a name="unicodeCollision"><h5>Unicode Collision</h5></a>
+ * <p>
+ * The following {@link #getKeyCode() Key-code}s and {@link #getKeySymbol() key-symbol}s collide w/ unicode space:<br/>
+ * <table border="1">
+ * <tr><th>unicode range</th> <th>virtual key code</th> <th>unicode character</th></tr>
+ * <tr><td>[0x61 .. 0x78]</td> <td>[{@link #VK_F1}..{@link #VK_F24}]</td> <td>['a'..'x']</td></tr>
+ * </table>
+ * </p>
+ * <p>
+ * Collision was chosen for {@link #getKeyCode() Key-code} and {@link #getKeySymbol() key-symbol} mapping
+ * to allow a minimal code range, i.e. <code>[0..255]</code>.
+ * The reduced code range in turn allows the implementation to utilize fast and small lookup tables,
+ * e.g. to implement a key-press state tracker.
+ * </p>
+ * <pre>
+ * http://www.utf8-chartable.de/unicode-utf8-table.pl
+ * http://www.unicode.org/Public/5.1.0/ucd/PropList.txt
+ * https://en.wikipedia.org/wiki/Mapping_of_Unicode_characters
+ * https://en.wikipedia.org/wiki/Unicode_control_characters
+ * https://en.wikipedia.org/wiki/Private_Use_%28Unicode%29#Private_Use_Areas
+ * </pre>
* </p>
*/
@SuppressWarnings("serial")
public class KeyEvent extends InputEvent
{
- public KeyEvent(int eventType, Object source, long when, int modifiers, int keyCode, char keyChar) {
- super(eventType, source, when, modifiers);
- this.keyCode=keyCode;
- this.keyChar=keyChar;
- }
-
- /** Only valid on all platforms at {@link KeyListener#keyTyped(KeyEvent)} */
- public char getKeyChar() {
- return keyChar;
- }
-
- /** Always valid. */
- public int getKeyCode() {
- return keyCode;
- }
-
- public String toString() {
- return toString(null).toString();
- }
-
- public StringBuilder toString(StringBuilder sb) {
- if(null == sb) {
- sb = new StringBuilder();
- }
- sb.append("KeyEvent[").append(getEventTypeString(getEventType())).append(", code ").append(keyCode).append("(").append(toHexString(keyCode)).append("), char '").append(keyChar).append("' (").append(toHexString((int)keyChar)).append("), isActionKey ").append(isActionKey()).append(", ");
- return super.toString(sb).append("]");
- }
-
- public static String getEventTypeString(int type) {
- switch(type) {
- case EVENT_KEY_PRESSED: return "EVENT_KEY_PRESSED";
- case EVENT_KEY_RELEASED: return "EVENT_KEY_RELEASED";
- case EVENT_KEY_TYPED: return "EVENT_KEY_TYPED";
- default: return "unknown (" + type + ")";
- }
- }
-
- public boolean isActionKey() {
- switch (keyCode) {
- case VK_HOME:
- case VK_END:
- case VK_PAGE_UP:
- case VK_PAGE_DOWN:
- case VK_UP:
- case VK_DOWN:
- case VK_LEFT:
- case VK_RIGHT:
-
- case VK_F1:
- case VK_F2:
- case VK_F3:
- case VK_F4:
- case VK_F5:
- case VK_F6:
- case VK_F7:
- case VK_F8:
- case VK_F9:
- case VK_F10:
- case VK_F11:
- case VK_F12:
- case VK_F13:
- case VK_F14:
- case VK_F15:
- case VK_F16:
- case VK_F17:
- case VK_F18:
- case VK_F19:
- case VK_F20:
- case VK_F21:
- case VK_F22:
- case VK_F23:
- case VK_F24:
- case VK_PRINTSCREEN:
- case VK_CAPS_LOCK:
- case VK_PAUSE:
- case VK_INSERT:
-
- case VK_HELP:
- case VK_WINDOWS:
- return true;
+ private KeyEvent(final short eventType, final Object source, final long when, final int modifiers, final short keyCode, final short keySym, final int keySymModMask, final char keyChar) {
+ super(eventType, source, when, modifiers | keySymModMask);
+ this.keyCode=keyCode;
+ this.keySym=keySym;
+ this.keyChar=keyChar;
+ { // cache modifier and action flags
+ byte _flags = 0;
+ if( isPrintableKey(keySym, false) && isPrintableKey((short)keyChar, true) ) {
+ _flags |= F_PRINTABLE_MASK;
+ } else {
+ if( 0 != keySymModMask ) {
+ _flags |= F_MODIFIER_MASK;
+ } else {
+ // A = U - ( P + M )
+ _flags |= F_ACTION_MASK;
+ }
+ }
+ flags = _flags;
+
+ //
+ // Validate flags
+ //
+ final int pma_bits = flags & ( F_PRINTABLE_MASK | F_MODIFIER_MASK | F_ACTION_MASK ) ;
+ final int pma_count = IntBitfield.getBitCount(pma_bits);
+ if ( 1 != pma_count ) {
+ throw new InternalError("Key must be either of type printable, modifier or action - but it is of "+pma_count+" types: "+this);
+ }
+ }
}
- return false;
- }
-
- private final int keyCode;
- private final char keyChar;
-
- public static final int EVENT_KEY_PRESSED = 300;
- public static final int EVENT_KEY_RELEASED= 301;
- public static final int EVENT_KEY_TYPED = 302;
-
- /* Virtual key codes. */
- public static final int VK_ENTER = '\n';
- public static final int VK_BACK_SPACE = '\b';
- public static final int VK_TAB = '\t';
- public static final int VK_CANCEL = 0x03;
- public static final int VK_CLEAR = 0x0C;
- public static final int VK_SHIFT = 0x10;
- public static final int VK_CONTROL = 0x11;
- public static final int VK_ALT = 0x12;
- public static final int VK_PAUSE = 0x13;
- public static final int VK_CAPS_LOCK = 0x14;
- public static final int VK_ESCAPE = 0x1B;
- public static final int VK_SPACE = 0x20;
- public static final int VK_PAGE_UP = 0x21;
- public static final int VK_PAGE_DOWN = 0x22;
- public static final int VK_END = 0x23;
- public static final int VK_HOME = 0x24;
+ public static KeyEvent create(final short eventType, final Object source, final long when, final int modifiers, final short keyCode, final short keySym, final char keyChar) {
+ return new KeyEvent(eventType, source, when, modifiers, keyCode, keySym, getModifierMask(keySym), keyChar);
+ }
/**
- * Constant for the non-numpad <b>left</b> arrow key.
- * @see #VK_KP_LEFT
+ * Returns the <i>UTF-16</i> character reflecting the {@link #getKeySymbol() key symbol}
+ * incl. active {@link #isModifierKey() modifiers}.
+ * @see #getKeySymbol()
+ * @see #getKeyCode()
*/
- public static final int VK_LEFT = 0x25;
+ public final char getKeyChar() {
+ return keyChar;
+ }
/**
- * Constant for the non-numpad <b>up</b> arrow key.
- * @see #VK_KP_UP
+ * Returns the virtual <i>key symbol</i> reflecting the current <i>keyboard layout</i>.
+ * <p>
+ * For {@link #isPrintableKey() printable keys}, the <i>key symbol</i> is the {@link #isModifierKey() unmodified}
+ * representation of the UTF-16 {@link #getKeyChar() key char}.<br/>
+ * E.g. symbol [{@link #VK_A}, 'A'] for char 'a'.
+ * </p>
+ * @see #isPrintableKey()
+ * @see #getKeyChar()
+ * @see #getKeyCode()
*/
- public static final int VK_UP = 0x26;
+ public final short getKeySymbol() {
+ return keySym;
+ }
/**
- * Constant for the non-numpad <b>right</b> arrow key.
- * @see #VK_KP_RIGHT
- */
- public static final int VK_RIGHT = 0x27;
+ * Returns the virtual <i>key code</i> using a fixed mapping to the <i>US keyboard layout</i>.
+ * <p>
+ * In contrast to {@link #getKeySymbol() key symbol}, <i>key code</i>
+ * uses a fixed <i>US keyboard layout</i> and therefore is keyboard layout independent.
+ * </p>
+ * <p>
+ * E.g. <i>virtual key code</i> {@link #VK_Y} denotes the same physical key
+ * regardless whether <i>keyboard layout</i> <code>QWERTY</code> or
+ * <code>QWERTZ</code> is active. The {@link #getKeySymbol() key symbol} of the former is
+ * {@link #VK_Y}, where the latter produces {@link #VK_Y}.
+ * </p>
+ * @see #getKeyChar()
+ * @see #getKeySymbol()
+ */
+ public final short getKeyCode() {
+ return keyCode;
+ }
+
+ @Override
+ public final String toString() {
+ return toString(null).toString();
+ }
+
+ @Override
+ public final StringBuilder toString(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ sb.append("KeyEvent[").append(getEventTypeString(getEventType())).append(", code ").append(toHexString(keyCode)).append(", sym ").append(toHexString(keySym)).append(", char '").append(keyChar).append("' (").append(toHexString((short)keyChar))
+ .append("), printable ").append(isPrintableKey()).append(", modifier ").append(isModifierKey()).append(", action ").append(isActionKey()).append(", ");
+ return super.toString(sb).append("]");
+ }
+
+ public static String getEventTypeString(final short type) {
+ switch(type) {
+ case EVENT_KEY_PRESSED: return "EVENT_KEY_PRESSED";
+ case EVENT_KEY_RELEASED: return "EVENT_KEY_RELEASED";
+ default: return "unknown (" + type + ")";
+ }
+ }
/**
- * Constant for the non-numpad <b>down</b> arrow key.
- * @see #VK_KP_DOWN
+ * @param keyChar UTF16 value to map. It is expected that the incoming keyChar value is unshifted and unmodified,
+ * however, lower case a-z is mapped to {@link KeyEvent#VK_A} - {@link KeyEvent#VK_Z}.
+ * @return {@link KeyEvent} virtual key (VK) value.
*/
- public static final int VK_DOWN = 0x28;
+ public static short utf16ToVKey(final char keyChar) {
+ if( 'a' <= keyChar && keyChar <= 'z' ) {
+ return (short) ( ( keyChar - 'a' ) + KeyEvent.VK_A );
+ }
+ return (short) keyChar;
+ }
/**
- * Constant for the comma key, ","
- */
- public static final int VK_COMMA = 0x2C;
+ * Returns <code>true</code> if the given <code>virtualKey</code> represents a modifier key, otherwise <code>false</code>.
+ * <p>
+ * A modifier key is one of {@link #VK_SHIFT}, {@link #VK_CONTROL}, {@link #VK_ALT}, {@link #VK_ALT_GRAPH}, {@link #VK_META}.
+ * </p>
+ */
+ public static boolean isModifierKey(final short vKey) {
+ switch (vKey) {
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_ALT:
+ case VK_ALT_GRAPH:
+ case VK_META:
+ return true;
+ default:
+ return false;
+ }
+ }
/**
- * Constant for the minus key, "-"
- * @since 1.2
- */
- public static final int VK_MINUS = 0x2D;
+ * If <code>vKey</code> is a {@link #isModifierKey() modifier key}, method returns the corresponding modifier mask,
+ * otherwise 0.
+ */
+ public static int getModifierMask(final short vKey) {
+ switch (vKey) {
+ case VK_SHIFT:
+ return InputEvent.SHIFT_MASK;
+ case VK_CONTROL:
+ return InputEvent.CTRL_MASK;
+ case VK_ALT:
+ case VK_ALT_GRAPH:
+ return InputEvent.ALT_MASK;
+ case VK_META:
+ return InputEvent.META_MASK;
+ }
+ return 0;
+ }
/**
- * Constant for the period key, "."
+ * Returns <code>true</code> if {@link #getKeySymbol() key symbol} represents a modifier key,
+ * otherwise <code>false</code>.
+ * <p>
+ * See {@link #isModifierKey(short)} for details.
+ * </p>
+ * <p>
+ * Note: Implementation uses a cached value.
+ * </p>
*/
- public static final int VK_PERIOD = 0x2E;
+ public final boolean isModifierKey() {
+ return 0 != ( F_MODIFIER_MASK & flags ) ;
+ }
/**
- * Constant for the forward slash key, "/"
+ * Returns <code>true</code> if {@link #getKeySymbol() key symbol} represents a non-printable and
+ * non-{@link #isModifierKey(short) modifier} action key, otherwise <code>false</code>.
+ * <p>
+ * Hence it is the set A of all keys U w/o printable P and w/o modifiers M:
+ * <code> A = U - ( P + M ) </code>
+ * </p>
+ * @see #isPrintableKey()
+ * @see #isModifierKey()
*/
- public static final int VK_SLASH = 0x2F;
-
- /** VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
- public static final int VK_0 = 0x30;
- public static final int VK_1 = 0x31;
- public static final int VK_2 = 0x32;
- public static final int VK_3 = 0x33;
- public static final int VK_4 = 0x34;
- public static final int VK_5 = 0x35;
- public static final int VK_6 = 0x36;
- public static final int VK_7 = 0x37;
- public static final int VK_8 = 0x38;
- public static final int VK_9 = 0x39;
+ public final boolean isActionKey() {
+ return 0 != ( F_ACTION_MASK & flags ) ;
+ }
/**
- * Constant for the semicolon key, ";"
- */
- public static final int VK_SEMICOLON = 0x3B;
+ * Returns <code>true</code> if given <code>uniChar</code> represents a printable character,
+ * i.e. a value other than {@link #VK_UNDEFINED} and not a control or non-printable private code.
+ * <p>
+ * A printable character is neither a {@link #isModifierKey(short) modifier key}, nor an {@link #isActionKey(short) action key}.
+ * </p>
+ * <p>
+ * Otherwise returns <code>false</code>.
+ * </p>
+ * <p>
+ * Distinction of key character and virtual key code is made due to <a href="#unicodeCollision">unicode collision</a>.
+ * </p>
+ *
+ * @param uniChar the UTF-16 unicode value, which maybe a virtual key code or key character.
+ * @param isKeyChar true if <code>uniChar</code> is a key character, otherwise a virtual key code
+ */
+ public static boolean isPrintableKey(final short uniChar, final boolean isKeyChar) {
+ if ( VK_BACK_SPACE == uniChar || VK_TAB == uniChar || VK_ENTER == uniChar ) {
+ return true;
+ }
+ if( !isKeyChar ) {
+ if( ( nonPrintableKeys[0].min <= uniChar && uniChar <= nonPrintableKeys[0].max ) ||
+ ( nonPrintableKeys[1].min <= uniChar && uniChar <= nonPrintableKeys[1].max ) ||
+ ( nonPrintableKeys[2].min <= uniChar && uniChar <= nonPrintableKeys[2].max ) ||
+ ( nonPrintableKeys[3].min <= uniChar && uniChar <= nonPrintableKeys[3].max ) ) {
+ return false;
+ }
+ } else {
+ if( ( nonPrintableKeys[0].inclKeyChar && nonPrintableKeys[0].min <= uniChar && uniChar <= nonPrintableKeys[0].max ) ||
+ ( nonPrintableKeys[1].inclKeyChar && nonPrintableKeys[1].min <= uniChar && uniChar <= nonPrintableKeys[1].max ) ||
+ ( nonPrintableKeys[2].inclKeyChar && nonPrintableKeys[2].min <= uniChar && uniChar <= nonPrintableKeys[2].max ) ||
+ ( nonPrintableKeys[3].inclKeyChar && nonPrintableKeys[3].min <= uniChar && uniChar <= nonPrintableKeys[3].max ) ) {
+ return false;
+ }
+ }
+ return VK_UNDEFINED != uniChar;
+ }
/**
- * Constant for the equals key, "="
+ * Returns <code>true</code> if {@link #getKeySymbol() key symbol} and {@link #getKeyChar() key char}
+ * represents a printable character, i.e. a value other than {@link #VK_UNDEFINED}
+ * and not a control or non-printable private code.
+ * <p>
+ * A printable character is neither a {@link #isModifierKey(short) modifier key}, nor an {@link #isActionKey(short) action key}.
+ * </p>
+ * <p>
+ * Otherwise returns <code>false</code>.
+ * </p>
*/
- public static final int VK_EQUALS = 0x3D;
-
- /** VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
- public static final int VK_A = 0x41;
- public static final int VK_B = 0x42;
- public static final int VK_C = 0x43;
- public static final int VK_D = 0x44;
- public static final int VK_E = 0x45;
- public static final int VK_F = 0x46;
- public static final int VK_G = 0x47;
- public static final int VK_H = 0x48;
- public static final int VK_I = 0x49;
- public static final int VK_J = 0x4A;
- public static final int VK_K = 0x4B;
- public static final int VK_L = 0x4C;
- public static final int VK_M = 0x4D;
- public static final int VK_N = 0x4E;
- public static final int VK_O = 0x4F;
- public static final int VK_P = 0x50;
- public static final int VK_Q = 0x51;
- public static final int VK_R = 0x52;
- public static final int VK_S = 0x53;
- public static final int VK_T = 0x54;
- public static final int VK_U = 0x55;
- public static final int VK_V = 0x56;
- public static final int VK_W = 0x57;
- public static final int VK_X = 0x58;
- public static final int VK_Y = 0x59;
- public static final int VK_Z = 0x5A;
+ public final boolean isPrintableKey() {
+ return 0 != ( F_PRINTABLE_MASK & flags ) ;
+ }
+
+ private final short keyCode;
+ private final short keySym;
+ private final char keyChar;
+ private final byte flags;
+ private static final byte F_MODIFIER_MASK = 1 << 0;
+ private static final byte F_ACTION_MASK = 1 << 1;
+ private static final byte F_PRINTABLE_MASK = 1 << 2;
+
+ /** A key has been pressed, excluding {@link #isAutoRepeat() auto-repeat}-{@link #isModifierKey() modifier} keys. */
+ public static final short EVENT_KEY_PRESSED = 300;
+ /** A key has been released, excluding {@link #isAutoRepeat() auto-repeat}-{@link #isModifierKey() modifier} keys. */
+ public static final short EVENT_KEY_RELEASED= 301;
/**
- * Constant for the open bracket key, "["
+ * This value, {@code '\0'}, is used to indicate that the keyChar is unknown or not printable.
*/
- public static final int VK_OPEN_BRACKET = 0x5B;
+ public static final char NULL_CHAR = '\0';
+ /* Virtual key codes. */
+
+ public static class NonPrintableRange {
+ /** min. unicode value, inclusive */
+ public short min;
+ /** max. unicode value, inclusive */
+ public short max;
+ /** true if valid for keyChar values as well, otherwise only valid for keyCode and keySym due to collision. */
+ public final boolean inclKeyChar;
+ private NonPrintableRange(final short min, final short max, final boolean inclKeyChar) {
+ this.min = min;
+ this.max = max;
+ this.inclKeyChar = inclKeyChar;
+ }
+ };
/**
- * Constant for the back slash key, "\"
+ * Non printable key ranges, currently fixed to an array of size 4.
+ * <p>
+ * Not included, queried upfront:
+ * <ul>
+ * <li>{@link #VK_BACK_SPACE}</li>
+ * <li>{@link #VK_TAB}</li>
+ * <li>{@link #VK_ENTER}</li>
+ * </ul>
+ * </p>
*/
- public static final int VK_BACK_SLASH = 0x5C;
+ public final static NonPrintableRange[] nonPrintableKeys = {
+ new NonPrintableRange( (short)0x0000, (short)0x001F, true ), // Unicode: Non printable controls: [0x00 - 0x1F], see exclusion above
+ new NonPrintableRange( (short)0x0061, (short)0x0078, false), // Small 'a' thru 'z' (0x61 - 0x7a) - Not used for keyCode / keySym - Re-used for Fn (collision)
+ new NonPrintableRange( (short)0x008F, (short)0x009F, true ), // Unicode: Non printable controls: [0x7F - 0x9F], Numpad keys [0x7F - 0x8E] are printable!
+ new NonPrintableRange( (short)0xE000, (short)0xF8FF, true ) // Unicode: Private 0xE000 - 0xF8FF (Marked Non-Printable)
+ };
+
+ //
+ // Unicode: Non printable controls: [0x00 - 0x1F]
+ //
/**
- * Constant for the close bracket key, "]"
+ * This value, {@value}, is used to indicate that the keyCode is unknown.
*/
- public static final int VK_CLOSE_BRACKET = 0x5D;
-
- public static final int VK_NUMPAD0 = 0x60;
- public static final int VK_NUMPAD1 = 0x61;
- public static final int VK_NUMPAD2 = 0x62;
- public static final int VK_NUMPAD3 = 0x63;
- public static final int VK_NUMPAD4 = 0x64;
- public static final int VK_NUMPAD5 = 0x65;
- public static final int VK_NUMPAD6 = 0x66;
- public static final int VK_NUMPAD7 = 0x67;
- public static final int VK_NUMPAD8 = 0x68;
- public static final int VK_NUMPAD9 = 0x69;
- public static final int VK_MULTIPLY = 0x6A;
- public static final int VK_ADD = 0x6B;
-
- /**
- * This constant is obsolete, and is included only for backwards
- * compatibility.
- * @see #VK_SEPARATOR
- */
- public static final int VK_SEPARATER = 0x6C;
+ public static final short VK_UNDEFINED = (short) 0x0;
- /**
- * Constant for the Numpad Separator key.
- * @since 1.4
- */
- public static final int VK_SEPARATOR = VK_SEPARATER;
+ static final short VK_FREE01 = (short) 0x01;
- public static final int VK_SUBTRACT = 0x6D;
- public static final int VK_DECIMAL = 0x6E;
- public static final int VK_DIVIDE = 0x6F;
- public static final int VK_DELETE = 0x7F; /* ASCII DEL */
- public static final int VK_NUM_LOCK = 0x90;
- public static final int VK_SCROLL_LOCK = 0x91;
+ /** Constant for the HOME function key. ASCII: Start Of Text. */
+ public static final short VK_HOME = (short) 0x02;
- /** Constant for the F1 function key. */
- public static final int VK_F1 = 0x70;
+ /** Constant for the END function key. ASCII: End Of Text. */
+ public static final short VK_END = (short) 0x03;
- /** Constant for the F2 function key. */
- public static final int VK_F2 = 0x71;
+ /** Constant for the END function key. ASCII: End Of Transmission. */
+ public static final short VK_FINAL = (short) 0x04;
- /** Constant for the F3 function key. */
- public static final int VK_F3 = 0x72;
+ /** Constant for the PRINT function key. ASCII: Enquiry. */
+ public static final short VK_PRINTSCREEN = (short) 0x05;
- /** Constant for the F4 function key. */
- public static final int VK_F4 = 0x73;
+ static final short VK_FREE06 = (short) 0x06;
+ static final short VK_FREE07 = (short) 0x07;
- /** Constant for the F5 function key. */
- public static final int VK_F5 = 0x74;
+ /** Constant for the BACK SPACE key "\b", matching ASCII. Printable! */
+ public static final short VK_BACK_SPACE = (short) 0x08;
- /** Constant for the F6 function key. */
- public static final int VK_F6 = 0x75;
+ /** Constant for the HORIZ TAB key "\t", matching ASCII. Printable! */
+ public static final short VK_TAB = (short) 0x09;
- /** Constant for the F7 function key. */
- public static final int VK_F7 = 0x76;
+ /** LINE_FEED "\n", matching ASCII, n/a on keyboard. */
+ static final short VK_FREE0A = (short) 0x0A;
- /** Constant for the F8 function key. */
- public static final int VK_F8 = 0x77;
+ /** Constant for the PAGE DOWN function key. ASCII: Vertical Tabulation. */
+ public static final short VK_PAGE_DOWN = (short) 0x0B;
- /** Constant for the F9 function key. */
- public static final int VK_F9 = 0x78;
+ /** Constant for the CLEAR key, i.e. FORM FEED, matching ASCII. */
+ public static final short VK_CLEAR = (short) 0x0C;
- /** Constant for the F10 function key. */
- public static final int VK_F10 = 0x79;
+ /** Constant for the ENTER key, i.e. CARRIAGE RETURN, matching ASCII. Printable! */
+ public static final short VK_ENTER = (short) 0x0D;
- /** Constant for the F11 function key. */
- public static final int VK_F11 = 0x7A;
+ static final short VK_FREE0E = (short) 0x0E;
- /** Constant for the F12 function key. */
- public static final int VK_F12 = 0x7B;
+ /** Constant for the CTRL function key. ASCII: shift-in. */
+ public static final short VK_SHIFT = (short) 0x0F;
- /**
- * Constant for the F13 function key.
- * @since 1.2
- */
- /* F13 - F24 are used on IBM 3270 keyboard; use random range for constants. */
- public static final int VK_F13 = 0xF000;
-
- /**
- * Constant for the F14 function key.
- * @since 1.2
- */
- public static final int VK_F14 = 0xF001;
-
- /**
- * Constant for the F15 function key.
- * @since 1.2
- */
- public static final int VK_F15 = 0xF002;
-
- /**
- * Constant for the F16 function key.
- * @since 1.2
- */
- public static final int VK_F16 = 0xF003;
-
- /**
- * Constant for the F17 function key.
- * @since 1.2
- */
- public static final int VK_F17 = 0xF004;
-
- /**
- * Constant for the F18 function key.
- * @since 1.2
- */
- public static final int VK_F18 = 0xF005;
-
- /**
- * Constant for the F19 function key.
- * @since 1.2
- */
- public static final int VK_F19 = 0xF006;
-
- /**
- * Constant for the F20 function key.
- * @since 1.2
- */
- public static final int VK_F20 = 0xF007;
-
- /**
- * Constant for the F21 function key.
- * @since 1.2
- */
- public static final int VK_F21 = 0xF008;
-
- /**
- * Constant for the F22 function key.
- * @since 1.2
- */
- public static final int VK_F22 = 0xF009;
-
- /**
- * Constant for the F23 function key.
- * @since 1.2
- */
- public static final int VK_F23 = 0xF00A;
-
- /**
- * Constant for the F24 function key.
- * @since 1.2
- */
- public static final int VK_F24 = 0xF00B;
-
- public static final int VK_PRINTSCREEN = 0x9A;
- public static final int VK_INSERT = 0x9B;
- public static final int VK_HELP = 0x9C;
- public static final int VK_META = 0x9D;
+ /** Constant for the PAGE UP function key. ASCII: Data Link Escape. */
+ public static final short VK_PAGE_UP = (short) 0x10;
- public static final int VK_BACK_QUOTE = 0xC0;
- public static final int VK_QUOTE = 0xDE;
+ /** Constant for the CTRL function key. ASCII: device-ctrl-one. */
+ public static final short VK_CONTROL = (short) 0x11;
- /**
- * Constant for the numeric keypad <b>up</b> arrow key.
- * @see #VK_UP
- * @since 1.2
- */
- public static final int VK_KP_UP = 0xE0;
+ /** Constant for the left ALT function key. ASCII: device-ctrl-two. */
+ public static final short VK_ALT = (short) 0x12;
- /**
- * Constant for the numeric keypad <b>down</b> arrow key.
- * @see #VK_DOWN
- * @since 1.2
- */
- public static final int VK_KP_DOWN = 0xE1;
+ /** Constant for the ALT_GRAPH function key, i.e. right ALT key. ASCII: device-ctrl-three. */
+ public static final short VK_ALT_GRAPH = (short) 0x13;
- /**
- * Constant for the numeric keypad <b>left</b> arrow key.
- * @see #VK_LEFT
- * @since 1.2
- */
- public static final int VK_KP_LEFT = 0xE2;
+ /** Constant for the CAPS LOCK function key. ASCII: device-ctrl-four. */
+ public static final short VK_CAPS_LOCK = (short) 0x14;
- /**
- * Constant for the numeric keypad <b>right</b> arrow key.
- * @see #VK_RIGHT
- * @since 1.2
- */
- public static final int VK_KP_RIGHT = 0xE3;
-
- /* For European keyboards */
- /** @since 1.2 */
- public static final int VK_DEAD_GRAVE = 0x80;
- /** @since 1.2 */
- public static final int VK_DEAD_ACUTE = 0x81;
- /** @since 1.2 */
- public static final int VK_DEAD_CIRCUMFLEX = 0x82;
- /** @since 1.2 */
- public static final int VK_DEAD_TILDE = 0x83;
- /** @since 1.2 */
- public static final int VK_DEAD_MACRON = 0x84;
- /** @since 1.2 */
- public static final int VK_DEAD_BREVE = 0x85;
- /** @since 1.2 */
- public static final int VK_DEAD_ABOVEDOT = 0x86;
- /** @since 1.2 */
- public static final int VK_DEAD_DIAERESIS = 0x87;
- /** @since 1.2 */
- public static final int VK_DEAD_ABOVERING = 0x88;
- /** @since 1.2 */
- public static final int VK_DEAD_DOUBLEACUTE = 0x89;
- /** @since 1.2 */
- public static final int VK_DEAD_CARON = 0x8a;
- /** @since 1.2 */
- public static final int VK_DEAD_CEDILLA = 0x8b;
- /** @since 1.2 */
- public static final int VK_DEAD_OGONEK = 0x8c;
- /** @since 1.2 */
- public static final int VK_DEAD_IOTA = 0x8d;
- /** @since 1.2 */
- public static final int VK_DEAD_VOICED_SOUND = 0x8e;
- /** @since 1.2 */
- public static final int VK_DEAD_SEMIVOICED_SOUND = 0x8f;
-
- /** @since 1.2 */
- public static final int VK_AMPERSAND = 0x96;
- /** @since 1.2 */
- public static final int VK_ASTERISK = 0x97;
- /** @since 1.2 */
- public static final int VK_QUOTEDBL = 0x98;
- /** @since 1.2 */
- public static final int VK_LESS = 0x99;
-
- /** @since 1.2 */
- public static final int VK_GREATER = 0xa0;
- /** @since 1.2 */
- public static final int VK_BRACELEFT = 0xa1;
- /** @since 1.2 */
- public static final int VK_BRACERIGHT = 0xa2;
+ static final short VK_FREE15 = (short) 0x15;
+
+ /** Constant for the PAUSE function key. ASCII: sync-idle. */
+ public static final short VK_PAUSE = (short) 0x16;
+
+ /** <b>scroll lock</b> key. ASCII: End Of Transmission Block. */
+ public static final short VK_SCROLL_LOCK = (short) 0x17;
+
+ /** Constant for the CANCEL function key. ASCII: Cancel. */
+ public static final short VK_CANCEL = (short) 0x18;
+
+ static final short VK_FREE19 = (short) 0x19;
+
+ /** Constant for the INSERT function key. ASCII: Substitute. */
+ public static final short VK_INSERT = (short) 0x1A;
+
+ /** Constant for the ESCAPE function key. ASCII: Escape. */
+ public static final short VK_ESCAPE = (short) 0x1B;
+
+ /** Constant for the Convert function key, Japanese "henkan". ASCII: File Separator. */
+ public static final short VK_CONVERT = (short) 0x1C;
+
+ /** Constant for the Don't Convert function key, Japanese "muhenkan". ASCII: Group Separator.*/
+ public static final short VK_NONCONVERT = (short) 0x1D;
+
+ /** Constant for the Accept or Commit function key, Japanese "kakutei". ASCII: Record Separator.*/
+ public static final short VK_ACCEPT = (short) 0x1E;
+
+ /** Constant for the Mode Change (?). ASCII: Unit Separator.*/
+ public static final short VK_MODECHANGE = (short) 0x1F;
+
+ //
+ // Unicode: Printable [0x20 - 0x7E]
+ // NOTE: Collision of 'a' - 'x' [0x61 .. 0x78], used for keyCode/keySym Fn function keys
+ //
+
+ /** Constant for the SPACE function key. ASCII: SPACE. */
+ public static final short VK_SPACE = (short) 0x20;
+
+ /** Constant for the "!" key. */
+ public static final short VK_EXCLAMATION_MARK = (short) 0x21;
+
+ /** Constant for the """ key. */
+ public static final short VK_QUOTEDBL = (short) 0x22;
+
+ /** Constant for the "#" key. */
+ public static final short VK_NUMBER_SIGN = (short) 0x23;
+
+ /** Constant for the "$" key. */
+ public static final short VK_DOLLAR = (short) 0x24;
+
+ /** Constant for the "%" key. */
+ public static final short VK_PERCENT = (short) 0x25;
+
+ /** Constant for the "&" key. */
+ public static final short VK_AMPERSAND = (short) 0x26;
+
+ /** Constant for the "'" key. */
+ public static final short VK_QUOTE = (short) 0x27;
+
+ /** Constant for the "(" key. */
+ public static final short VK_LEFT_PARENTHESIS = (short) 0x28;
+
+ /** Constant for the ")" key. */
+ public static final short VK_RIGHT_PARENTHESIS = (short) 0x29;
+
+ /** Constant for the "*" key */
+ public static final short VK_ASTERISK = (short) 0x2A;
+
+ /** Constant for the "+" key. */
+ public static final short VK_PLUS = (short) 0x2B;
+
+ /** Constant for the comma key, "," */
+ public static final short VK_COMMA = (short) 0x2C;
+
+ /** Constant for the minus key, "-" */
+ public static final short VK_MINUS = (short) 0x2D;
+
+ /** Constant for the period key, "." */
+ public static final short VK_PERIOD = (short) 0x2E;
+
+ /** Constant for the forward slash key, "/" */
+ public static final short VK_SLASH = (short) 0x2F;
+
+ /** VK_0 thru VK_9 are the same as UTF16/ASCII '0' thru '9' [0x30 - 0x39] */
+ public static final short VK_0 = (short) 0x30;
+ /** See {@link #VK_0}. */
+ public static final short VK_1 = (short) 0x31;
+ /** See {@link #VK_0}. */
+ public static final short VK_2 = (short) 0x32;
+ /** See {@link #VK_0}. */
+ public static final short VK_3 = (short) 0x33;
+ /** See {@link #VK_0}. */
+ public static final short VK_4 = (short) 0x34;
+ /** See {@link #VK_0}. */
+ public static final short VK_5 = (short) 0x35;
+ /** See {@link #VK_0}. */
+ public static final short VK_6 = (short) 0x36;
+ /** See {@link #VK_0}. */
+ public static final short VK_7 = (short) 0x37;
+ /** See {@link #VK_0}. */
+ public static final short VK_8 = (short) 0x38;
+ /** See {@link #VK_0}. */
+ public static final short VK_9 = (short) 0x39;
+
+ /** Constant for the ":" key. */
+ public static final short VK_COLON = (short) 0x3A;
+
+ /** Constant for the semicolon key, ";" */
+ public static final short VK_SEMICOLON = (short) 0x3B;
+
+ /** Constant for the equals key, "<" */
+ public static final short VK_LESS = (short) 0x3C;
+
+ /** Constant for the equals key, "=" */
+ public static final short VK_EQUALS = (short) 0x3D;
+
+ /** Constant for the equals key, ">" */
+ public static final short VK_GREATER = (short) 0x3E;
+
+ /** Constant for the equals key, "?" */
+ public static final short VK_QUESTIONMARK = (short) 0x3F;
+
+ /** Constant for the equals key, "@" */
+ public static final short VK_AT = (short) 0x40;
+
+ /** VK_A thru VK_Z are the same as Capital UTF16/ASCII 'A' thru 'Z' (0x41 - 0x5A) */
+ public static final short VK_A = (short) 0x41;
+ /** See {@link #VK_A}. */
+ public static final short VK_B = (short) 0x42;
+ /** See {@link #VK_A}. */
+ public static final short VK_C = (short) 0x43;
+ /** See {@link #VK_A}. */
+ public static final short VK_D = (short) 0x44;
+ /** See {@link #VK_A}. */
+ public static final short VK_E = (short) 0x45;
+ /** See {@link #VK_A}. */
+ public static final short VK_F = (short) 0x46;
+ /** See {@link #VK_A}. */
+ public static final short VK_G = (short) 0x47;
+ /** See {@link #VK_A}. */
+ public static final short VK_H = (short) 0x48;
+ /** See {@link #VK_A}. */
+ public static final short VK_I = (short) 0x49;
+ /** See {@link #VK_A}. */
+ public static final short VK_J = (short) 0x4A;
+ /** See {@link #VK_A}. */
+ public static final short VK_K = (short) 0x4B;
+ /** See {@link #VK_A}. */
+ public static final short VK_L = (short) 0x4C;
+ /** See {@link #VK_A}. */
+ public static final short VK_M = (short) 0x4D;
+ /** See {@link #VK_A}. */
+ public static final short VK_N = (short) 0x4E;
+ /** See {@link #VK_A}. */
+ public static final short VK_O = (short) 0x4F;
+ /** See {@link #VK_A}. */
+ public static final short VK_P = (short) 0x50;
+ /** See {@link #VK_A}. */
+ public static final short VK_Q = (short) 0x51;
+ /** See {@link #VK_A}. */
+ public static final short VK_R = (short) 0x52;
+ /** See {@link #VK_A}. */
+ public static final short VK_S = (short) 0x53;
+ /** See {@link #VK_A}. */
+ public static final short VK_T = (short) 0x54;
+ /** See {@link #VK_A}. */
+ public static final short VK_U = (short) 0x55;
+ /** See {@link #VK_A}. */
+ public static final short VK_V = (short) 0x56;
+ /** See {@link #VK_A}. */
+ public static final short VK_W = (short) 0x57;
+ /** See {@link #VK_A}. */
+ public static final short VK_X = (short) 0x58;
+ /** See {@link #VK_A}. */
+ public static final short VK_Y = (short) 0x59;
+ /** See {@link #VK_A}. */
+ public static final short VK_Z = (short) 0x5A;
+
+ /** Constant for the open bracket key, "[" */
+ public static final short VK_OPEN_BRACKET = (short) 0x5B;
+
+ /**Constant for the back slash key, "\" */
+ public static final short VK_BACK_SLASH = (short) 0x5C;
+
+ /** Constant for the close bracket key, "]" */
+ public static final short VK_CLOSE_BRACKET = (short) 0x5D;
+
+ /** Constant for the "^" key. */
+ public static final short VK_CIRCUMFLEX = (short) 0x5E;
+
+ /** Constant for the "_" key */
+ public static final short VK_UNDERSCORE = (short) 0x5F;
+
+ /** Constant for the "`" key */
+ public static final short VK_BACK_QUOTE = (short) 0x60;
+
+ /** Small UTF/ASCII 'a' thru 'z' (0x61 - 0x7a) - Not used for keyCode / keySym. */
+
+ /**
+ * Constant for the F<i>n</i> function keys.
+ * <p>
+ * F1..F24, i.e. F<i>n</i>, are mapped from on <code>0x60+n</code> -> <code>[0x61 .. 0x78]</code>.
+ * </p>
+ * <p>
+ * <b>Warning:</b> The F<i>n</i> function keys <b>do collide</b> with unicode characters small 'a' thru 'x'!<br/>
+ * See <a href="#unicodeCollision">Unicode Collision</a> for details.
+ * </p>
+ */
+ public static final short VK_F1 = (short) ( 0x60+ 1 );
+
+ /** Constant for the F2 function key. See {@link #VK_F1}. */
+ public static final short VK_F2 = (short) ( 0x60+ 2 );
+
+ /** Constant for the F3 function key. See {@link #VK_F1}. */
+ public static final short VK_F3 = (short) ( 0x60+ 3 );
+
+ /** Constant for the F4 function key. See {@link #VK_F1}. */
+ public static final short VK_F4 = (short) ( 0x60+ 4 );
+
+ /** Constant for the F5 function key. See {@link #VK_F1}. */
+ public static final short VK_F5 = (short) ( 0x60+ 5 );
+
+ /** Constant for the F6 function key. See {@link #VK_F1}. */
+ public static final short VK_F6 = (short) ( 0x60+ 6 );
+
+ /** Constant for the F7 function key. See {@link #VK_F1}. */
+ public static final short VK_F7 = (short) ( 0x60+ 7 );
+
+ /** Constant for the F8 function key. See {@link #VK_F1}. */
+ public static final short VK_F8 = (short) ( 0x60+ 8 );
+
+ /** Constant for the F9 function key. See {@link #VK_F1}. */
+ public static final short VK_F9 = (short) ( 0x60+ 9 );
+
+ /** Constant for the F11 function key. See {@link #VK_F1}. */
+ public static final short VK_F10 = (short) ( 0x60+10 );
+
+ /** Constant for the F11 function key. See {@link #VK_F1}. */
+ public static final short VK_F11 = (short) ( 0x60+11 );
+
+ /** Constant for the F12 function key. See {@link #VK_F1}.*/
+ public static final short VK_F12 = (short) ( 0x60+12 );
+
+ /** Constant for the F13 function key. See {@link #VK_F1}. */
+ public static final short VK_F13 = (short) ( 0x60+13 );
+
+ /** Constant for the F14 function key. See {@link #VK_F1}. */
+ public static final short VK_F14 = (short) ( 0x60+14 );
+
+ /** Constant for the F15 function key. See {@link #VK_F1}. */
+ public static final short VK_F15 = (short) ( 0x60+15 );
+
+ /** Constant for the F16 function key. See {@link #VK_F1}. */
+ public static final short VK_F16 = (short) ( 0x60+16 );
+
+ /** Constant for the F17 function key. See {@link #VK_F1}. */
+ public static final short VK_F17 = (short) ( 0x60+17 );
+
+ /** Constant for the F18 function key. See {@link #VK_F1}. */
+ public static final short VK_F18 = (short) ( 0x60+18 );
+
+ /** Constant for the F19 function key. See {@link #VK_F1}. */
+ public static final short VK_F19 = (short) ( 0x60+19 );
+
+ /** Constant for the F20 function key. See {@link #VK_F1}. */
+ public static final short VK_F20 = (short) ( 0x60+20 );
+
+ /** Constant for the F21 function key. See {@link #VK_F1}. */
+ public static final short VK_F21 = (short) ( 0x60+21 );
+
+ /** Constant for the F22 function key. See {@link #VK_F1}. */
+ public static final short VK_F22 = (short) ( 0x60+22 );
+
+ /** Constant for the F23 function key. See {@link #VK_F1}. */
+ public static final short VK_F23 = (short) ( 0x60+23 );
+
+ /** Constant for the F24 function key. See {@link #VK_F1}. */
+ public static final short VK_F24 = (short) ( 0x60+24 );
+
+
+ /** Constant for the "{" key */
+ public static final short VK_LEFT_BRACE = (short) 0x7B;
+ /** Constant for the "|" key */
+ public static final short VK_PIPE = (short) 0x7C;
+ /** Constant for the "}" key */
+ public static final short VK_RIGHT_BRACE = (short) 0x7D;
+
+ /** Constant for the "~" key, matching ASCII */
+ public static final short VK_TILDE = (short) 0x7E;
+
+ //
+ // Unicode: Non printable controls: [0x7F - 0x9F]
+ //
+ // Numpad keys [0x7F - 0x8E] are printable
+ //
+
+ /** Numeric keypad <b>decimal separator</b> key. Non printable UTF control. */
+ public static final short VK_SEPARATOR = (short) 0x7F;
+
+ /** Numeric keypad VK_NUMPAD0 thru VK_NUMPAD9 are mapped to UTF control (0x80 - 0x89). Non printable UTF control. */
+ public static final short VK_NUMPAD0 = (short) 0x80;
+ /** See {@link #VK_NUMPAD0}. */
+ public static final short VK_NUMPAD1 = (short) 0x81;
+ /** See {@link #VK_NUMPAD0}. */
+ public static final short VK_NUMPAD2 = (short) 0x82;
+ /** See {@link #VK_NUMPAD0}. */
+ public static final short VK_NUMPAD3 = (short) 0x83;
+ /** See {@link #VK_NUMPAD0}. */
+ public static final short VK_NUMPAD4 = (short) 0x84;
+ /** See {@link #VK_NUMPAD0}. */
+ public static final short VK_NUMPAD5 = (short) 0x85;
+ /** See {@link #VK_NUMPAD0}. */
+ public static final short VK_NUMPAD6 = (short) 0x86;
+ /** See {@link #VK_NUMPAD0}. */
+ public static final short VK_NUMPAD7 = (short) 0x87;
+ /** See {@link #VK_NUMPAD0}. */
+ public static final short VK_NUMPAD8 = (short) 0x88;
+ /** See {@link #VK_NUMPAD0}. */
+ public static final short VK_NUMPAD9 = (short) 0x89;
+
+ /** Numeric keypad <b>decimal separator</b> key. Non printable UTF control. */
+ public static final short VK_DECIMAL = (short) 0x8A;
+
+ /** Numeric keypad <b>add</b> key. Non printable UTF control. */
+ public static final short VK_ADD = (short) 0x8B;
+
+ /** Numeric keypad <b>subtract</b> key. Non printable UTF control. */
+ public static final short VK_SUBTRACT = (short) 0x8C;
+
+ /** Numeric keypad <b>multiply</b> key. Non printable UTF control. */
+ public static final short VK_MULTIPLY = (short) 0x8D;
+
+ /** Numeric keypad <b>divide</b> key. Non printable UTF control. */
+ public static final short VK_DIVIDE = (short) 0x8E;
+
+ /** Constant for the DEL key, matching ASCII. Non printable UTF control. */
+ public static final short VK_DELETE = (short) 0x93;
+
+ /** Numeric keypad <b>num lock</b> key. Non printable UTF control. */
+ public static final short VK_NUM_LOCK = (short) 0x94;
+
+ /** Constant for the cursor- or numerical-pad <b>left</b> arrow key. Non printable UTF control. */
+ public static final short VK_LEFT = (short) 0x95;
+
+ /** Constant for the cursor- or numerical-pad <b>up</b> arrow key. Non printable UTF control. */
+ public static final short VK_UP = (short) 0x96;
+
+ /** Constant for the cursor- or numerical-pad <b>right</b> arrow key. Non printable UTF control. */
+ public static final short VK_RIGHT = (short) 0x97;
+
+ /** Constant for the cursor- or numerical pad <b>down</b> arrow key. Non printable UTF control. */
+ public static final short VK_DOWN = (short) 0x98;
+
+ /** Constant for the Context Menu key. Non printable UTF control. */
+ public static final short VK_CONTEXT_MENU = (short) 0x99;
/**
- * Constant for the "@" key.
- * @since 1.2
- */
- public static final int VK_AT = 0x0200;
-
- /**
- * Constant for the ":" key.
- * @since 1.2
- */
- public static final int VK_COLON = 0x0201;
-
- /**
- * Constant for the "^" key.
- * @since 1.2
- */
- public static final int VK_CIRCUMFLEX = 0x0202;
-
- /**
- * Constant for the "$" key.
- * @since 1.2
- */
- public static final int VK_DOLLAR = 0x0203;
-
- /**
- * Constant for the Euro currency sign key.
- * @since 1.2
- */
- public static final int VK_EURO_SIGN = 0x0204;
-
- /**
- * Constant for the "!" key.
- * @since 1.2
- */
- public static final int VK_EXCLAMATION_MARK = 0x0205;
-
- /**
- * Constant for the inverted exclamation mark key.
- * @since 1.2
- */
- public static final int VK_INVERTED_EXCLAMATION_MARK = 0x0206;
-
- /**
- * Constant for the "(" key.
- * @since 1.2
- */
- public static final int VK_LEFT_PARENTHESIS = 0x0207;
-
- /**
- * Constant for the "#" key.
- * @since 1.2
+ * Constant for the MS "Windows" function key.
+ * It is used for both the left and right version of the key.
*/
- public static final int VK_NUMBER_SIGN = 0x0208;
-
+ public static final short VK_WINDOWS = (short) 0x9A;
+
+ /** Constant for the Meta function key. */
+ public static final short VK_META = (short) 0x9B;
+
+ /** Constant for the Help function key. */
+ public static final short VK_HELP = (short) 0x9C;
+
+ /** Constant for the Compose function key. */
+ public static final short VK_COMPOSE = (short) 0x9D;
+
+ /** Constant for the Begin function key. */
+ public static final short VK_BEGIN = (short) 0x9E;
+
+ /** Constant for the Stop function key. */
+ public static final short VK_STOP = (short) 0x9F;
+
+ //
+ // Unicode: Printable [0x00A0 - 0xDFFF]
+ //
+
+ /** Constant for the inverted exclamation mark key. */
+ public static final short VK_INVERTED_EXCLAMATION_MARK = (short) 0xA1;
+
+ /** Constant for the Euro currency sign key. */
+ public static final short VK_EURO_SIGN = (short) 0x20AC;
+
+ //
+ // Unicode: Private 0xE000 - 0xF8FF (Marked Non-Printable)
+ //
+
+ /* for Sun keyboards */
+ public static final short VK_CUT = (short) 0xF879;
+ public static final short VK_COPY = (short) 0xF87A;
+ public static final short VK_PASTE = (short) 0xF87B;
+ public static final short VK_UNDO = (short) 0xF87C;
+ public static final short VK_AGAIN = (short) 0xF87D;
+ public static final short VK_FIND = (short) 0xF87E;
+ public static final short VK_PROPS = (short) 0xF87F;
+
+ /* for input method support on Asian Keyboards */
+
/**
- * Constant for the "+" key.
- * @since 1.2
+ * Constant for the input method on/off key.
*/
- public static final int VK_PLUS = 0x0209;
-
+ /* Japanese PC 106 keyboard: kanji. Japanese Solaris keyboard: nihongo */
+ public static final short VK_INPUT_METHOD_ON_OFF = (short) 0xF890;
+
/**
- * Constant for the ")" key.
- * @since 1.2
+ * Constant for the Code Input function key.
*/
- public static final int VK_RIGHT_PARENTHESIS = 0x020A;
-
+ /* Japanese PC 106 keyboard - VK_ALPHANUMERIC + ALT: kanji bangou */
+ public static final short VK_CODE_INPUT = (short) 0xF891;
+
/**
- * Constant for the "_" key.
- * @since 1.2
+ * Constant for the Roman Characters function key.
*/
- public static final int VK_UNDERSCORE = 0x020B;
-
+ /* Japanese PC 106 keyboard: roumaji */
+ public static final short VK_ROMAN_CHARACTERS = (short) 0xF892;
+
/**
- * Constant for the Microsoft Windows "Windows" key.
- * It is used for both the left and right version of the key.
- * @see #getKeyLocation()
- * @since 1.5
+ * Constant for the All Candidates function key.
*/
- public static final int VK_WINDOWS = 0x020C;
-
+ /* Japanese PC 106 keyboard - VK_CONVERT + ALT: zenkouho */
+ public static final short VK_ALL_CANDIDATES = (short) 0xF893;
+
/**
- * Constant for the Microsoft Windows Context Menu key.
- * @since 1.5
+ * Constant for the Previous Candidate function key.
*/
- public static final int VK_CONTEXT_MENU = 0x020D;
-
- /* for input method support on Asian Keyboards */
-
- /* not clear what this means - listed in Microsoft Windows API */
- public static final int VK_FINAL = 0x0018;
-
- /** Constant for the Convert function key. */
- /* Japanese PC 106 keyboard, Japanese Solaris keyboard: henkan */
- public static final int VK_CONVERT = 0x001C;
-
- /** Constant for the Don't Convert function key. */
- /* Japanese PC 106 keyboard: muhenkan */
- public static final int VK_NONCONVERT = 0x001D;
-
- /** Constant for the Accept or Commit function key. */
- /* Japanese Solaris keyboard: kakutei */
- public static final int VK_ACCEPT = 0x001E;
-
- /* not clear what this means - listed in Microsoft Windows API */
- public static final int VK_MODECHANGE = 0x001F;
-
- /* replaced by VK_KANA_LOCK for Microsoft Windows and Solaris;
- might still be used on other platforms */
- public static final int VK_KANA = 0x0015;
-
- /* replaced by VK_INPUT_METHOD_ON_OFF for Microsoft Windows and Solaris;
- might still be used for other platforms */
- public static final int VK_KANJI = 0x0019;
+ /* Japanese PC 106 keyboard - VK_CONVERT + SHIFT: maekouho */
+ public static final short VK_PREVIOUS_CANDIDATE = (short) 0xF894;
/**
* Constant for the Alphanumeric function key.
- * @since 1.2
*/
/* Japanese PC 106 keyboard: eisuu */
- public static final int VK_ALPHANUMERIC = 0x00F0;
-
+ public static final short VK_ALPHANUMERIC = (short) 0xF895;
+
/**
* Constant for the Katakana function key.
- * @since 1.2
*/
/* Japanese PC 106 keyboard: katakana */
- public static final int VK_KATAKANA = 0x00F1;
-
+ public static final short VK_KATAKANA = (short) 0xF896;
+
/**
* Constant for the Hiragana function key.
- * @since 1.2
*/
/* Japanese PC 106 keyboard: hiragana */
- public static final int VK_HIRAGANA = 0x00F2;
-
+ public static final short VK_HIRAGANA = (short) 0xF897;
+
/**
* Constant for the Full-Width Characters function key.
- * @since 1.2
*/
/* Japanese PC 106 keyboard: zenkaku */
- public static final int VK_FULL_WIDTH = 0x00F3;
-
+ public static final short VK_FULL_WIDTH = (short) 0xF898;
+
/**
* Constant for the Half-Width Characters function key.
- * @since 1.2
*/
/* Japanese PC 106 keyboard: hankaku */
- public static final int VK_HALF_WIDTH = 0x00F4;
-
- /**
- * Constant for the Roman Characters function key.
- * @since 1.2
- */
- /* Japanese PC 106 keyboard: roumaji */
- public static final int VK_ROMAN_CHARACTERS = 0x00F5;
-
- /**
- * Constant for the All Candidates function key.
- * @since 1.2
- */
- /* Japanese PC 106 keyboard - VK_CONVERT + ALT: zenkouho */
- public static final int VK_ALL_CANDIDATES = 0x0100;
-
- /**
- * Constant for the Previous Candidate function key.
- * @since 1.2
- */
- /* Japanese PC 106 keyboard - VK_CONVERT + SHIFT: maekouho */
- public static final int VK_PREVIOUS_CANDIDATE = 0x0101;
-
- /**
- * Constant for the Code Input function key.
- * @since 1.2
- */
- /* Japanese PC 106 keyboard - VK_ALPHANUMERIC + ALT: kanji bangou */
- public static final int VK_CODE_INPUT = 0x0102;
-
+ public static final short VK_HALF_WIDTH = (short) 0xF89A;
+
/**
* Constant for the Japanese-Katakana function key.
* This key switches to a Japanese input method and selects its Katakana input mode.
- * @since 1.2
*/
/* Japanese Macintosh keyboard - VK_JAPANESE_HIRAGANA + SHIFT */
- public static final int VK_JAPANESE_KATAKANA = 0x0103;
-
+ public static final short VK_JAPANESE_KATAKANA = (short) 0xF89B;
+
/**
* Constant for the Japanese-Hiragana function key.
* This key switches to a Japanese input method and selects its Hiragana input mode.
- * @since 1.2
*/
/* Japanese Macintosh keyboard */
- public static final int VK_JAPANESE_HIRAGANA = 0x0104;
-
+ public static final short VK_JAPANESE_HIRAGANA = (short) 0xF89C;
+
/**
* Constant for the Japanese-Roman function key.
* This key switches to a Japanese input method and selects its Roman-Direct input mode.
- * @since 1.2
*/
/* Japanese Macintosh keyboard */
- public static final int VK_JAPANESE_ROMAN = 0x0105;
+ public static final short VK_JAPANESE_ROMAN = (short) 0xF89D;
/**
* Constant for the locking Kana function key.
* This key locks the keyboard into a Kana layout.
- * @since 1.3
*/
/* Japanese PC 106 keyboard with special Windows driver - eisuu + Control; Japanese Solaris keyboard: kana */
- public static final int VK_KANA_LOCK = 0x0106;
-
- /**
- * Constant for the input method on/off key.
- * @since 1.3
- */
- /* Japanese PC 106 keyboard: kanji. Japanese Solaris keyboard: nihongo */
- public static final int VK_INPUT_METHOD_ON_OFF = 0x0107;
-
- /* for Sun keyboards */
- /** @since 1.2 */
- public static final int VK_CUT = 0xFFD1;
- /** @since 1.2 */
- public static final int VK_COPY = 0xFFCD;
- /** @since 1.2 */
- public static final int VK_PASTE = 0xFFCF;
- /** @since 1.2 */
- public static final int VK_UNDO = 0xFFCB;
- /** @since 1.2 */
- public static final int VK_AGAIN = 0xFFC9;
- /** @since 1.2 */
- public static final int VK_FIND = 0xFFD0;
- /** @since 1.2 */
- public static final int VK_PROPS = 0xFFCA;
- /** @since 1.2 */
- public static final int VK_STOP = 0xFFC8;
-
- /**
- * Constant for the Compose function key.
- * @since 1.2
- */
- public static final int VK_COMPOSE = 0xFF20;
-
- /**
- * Constant for the AltGraph function key.
- * @since 1.2
- */
- public static final int VK_ALT_GRAPH = 0xFF7E;
+ public static final short VK_KANA_LOCK = (short) 0xF89F;
/**
- * Constant for the Begin key.
- * @since 1.5
+ * Constant for Keyboard became invisible, e.g. Android's soft keyboard Back button hit while keyboard is visible.
*/
- public static final int VK_BEGIN = 0xFF58;
+ public static final short VK_KEYBOARD_INVISIBLE = (short) 0xF8FF;
- /**
- * This value is used to indicate that the keyCode is unknown.
- * KEY_TYPED events do not have a keyCode value; this value
- * is used instead.
- */
- public static final int VK_UNDEFINED = 0x0;
}
diff --git a/src/newt/classes/com/jogamp/newt/event/KeyListener.java b/src/newt/classes/com/jogamp/newt/event/KeyListener.java
index dae343d80..4b16ab61e 100644
--- a/src/newt/classes/com/jogamp/newt/event/KeyListener.java
+++ b/src/newt/classes/com/jogamp/newt/event/KeyListener.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,15 +29,33 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package com.jogamp.newt.event;
+/**
+ * Listener for {@link KeyEvent}s.
+ *
+ * @see KeyEvent
+ */
public interface KeyListener extends NEWTEventListener
{
- public void keyPressed(KeyEvent e);
- public void keyReleased(KeyEvent e);
- public void keyTyped(KeyEvent e) ;
+ /** A key has been {@link KeyEvent#EVENT_KEY_PRESSED pressed}, excluding {@link #isAutoRepeat() auto-repeat} {@link #isModifierKey() modifier} keys. See {@link KeyEvent}. */
+ public void keyPressed(KeyEvent e);
+
+ /**
+ * A key has been {@link KeyEvent#EVENT_KEY_RELEASED released}, excluding {@link #isAutoRepeat() auto-repeat} {@link #isModifierKey() modifier} keys. See {@link KeyEvent}.
+ * <p>
+ * To simulated the removed <code>keyTyped(KeyEvent e)</code> semantics,
+ * simply apply the following constraints upfront and bail out if not matched, i.e.:
+ * <pre>
+ if( !e.isPrintableKey() || e.isAutoRepeat() ) {
+ return;
+ }
+ * </pre>
+ * </p>
+ */
+ public void keyReleased(KeyEvent e);
}
diff --git a/src/newt/classes/com/jogamp/newt/event/MonitorEvent.java b/src/newt/classes/com/jogamp/newt/event/MonitorEvent.java
new file mode 100644
index 000000000..2e42f3392
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/event/MonitorEvent.java
@@ -0,0 +1,73 @@
+/**
+ * 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 com.jogamp.newt.event;
+
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+
+@SuppressWarnings("serial")
+public class MonitorEvent extends OutputEvent {
+ public static final short EVENT_MONITOR_MODE_CHANGE_NOTIFY = 600;
+ public static final short EVENT_MONITOR_MODE_CHANGED = 601;
+
+ private final MonitorMode mode;
+
+ public MonitorEvent (final short eventType, final MonitorDevice source, final long when, final MonitorMode mode) {
+ super(eventType, source, when);
+ this.mode = mode;
+ }
+
+ /** Returns the {@link #getSource() source}, which is a {@link MonitorDevice}. */
+ public final MonitorDevice getMonitor() { return (MonitorDevice)source; }
+
+ public final MonitorMode getMode() { return mode; }
+
+ public static String getEventTypeString(final short type) {
+ switch(type) {
+ case EVENT_MONITOR_MODE_CHANGE_NOTIFY: return "EVENT_MONITOR_MODE_CHANGE_NOTIFY";
+ case EVENT_MONITOR_MODE_CHANGED: return "EVENT_MONITOR_MODE_CHANGED";
+ default: return "unknown (" + type + ")";
+ }
+ }
+
+ @Override
+ public final String toString() {
+ return toString(null).toString();
+ }
+
+ @Override
+ public final StringBuilder toString(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ sb.append("MonitorEvent[").append(getEventTypeString(getEventType())).append(", source ").append(source)
+ .append(", mode ").append(mode).append(", ");
+ return super.toString(sb).append("]");
+ }
+}
diff --git a/src/newt/classes/com/jogamp/newt/event/ScreenModeListener.java b/src/newt/classes/com/jogamp/newt/event/MonitorModeListener.java
index 7bca23cfe..11e23def1 100644
--- a/src/newt/classes/com/jogamp/newt/event/ScreenModeListener.java
+++ b/src/newt/classes/com/jogamp/newt/event/MonitorModeListener.java
@@ -28,12 +28,10 @@
package com.jogamp.newt.event;
-import com.jogamp.newt.ScreenMode;
+public interface MonitorModeListener {
+ /** called before the monitor mode will be changed */
+ void monitorModeChangeNotify(MonitorEvent me);
-public interface ScreenModeListener {
- /** called before the screen mode will be changed */
- void screenModeChangeNotify(ScreenMode sm);
-
- /** called after the screen mode has been changed */
- void screenModeChanged(ScreenMode sm, boolean success);
+ /** called after the monitor mode has been changed */
+ void monitorModeChanged(MonitorEvent me, boolean success);
}
diff --git a/src/newt/classes/com/jogamp/newt/event/MouseAdapter.java b/src/newt/classes/com/jogamp/newt/event/MouseAdapter.java
index 3607ae634..679155d10 100644
--- a/src/newt/classes/com/jogamp/newt/event/MouseAdapter.java
+++ b/src/newt/classes/com/jogamp/newt/event/MouseAdapter.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,31 +20,39 @@
* 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 com.jogamp.newt.event;
public abstract class MouseAdapter implements MouseListener
{
- public void mouseClicked(MouseEvent e) {
+ @Override
+ public void mouseClicked(final MouseEvent e) {
}
- public void mouseEntered(MouseEvent e) {
+ @Override
+ public void mouseEntered(final MouseEvent e) {
}
- public void mouseExited(MouseEvent e) {
+ @Override
+ public void mouseExited(final MouseEvent e) {
}
- public void mousePressed(MouseEvent e) {
+ @Override
+ public void mousePressed(final MouseEvent e) {
}
- public void mouseReleased(MouseEvent e) {
+ @Override
+ public void mouseReleased(final MouseEvent e) {
}
- public void mouseMoved(MouseEvent e) {
+ @Override
+ public void mouseMoved(final MouseEvent e) {
}
- public void mouseDragged(MouseEvent e) {
+ @Override
+ public void mouseDragged(final MouseEvent e) {
}
- public void mouseWheelMoved(MouseEvent e) {
+ @Override
+ public void mouseWheelMoved(final MouseEvent e) {
}
}
diff --git a/src/newt/classes/com/jogamp/newt/event/MouseEvent.java b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java
index d293d2db7..2d68c5788 100644
--- a/src/newt/classes/com/jogamp/newt/event/MouseEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,192 +29,568 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package com.jogamp.newt.event;
+import java.util.Arrays;
+
+/**
+ * Pointer event of type {@link PointerType}.
+ * <p>
+ * The historical misleading class name may change in the future to <code>PointerEvent</code>.
+ * </p>
+ * <p>
+ * http://www.w3.org/Submission/pointer-events/#pointerevent-interface
+ * </p>
+ * <a name="coordUnit"><h5>Unit of Coordinates</h5></a>
+ * <p>
+ * All pointer coordinates of this interface are represented in pixel units,
+ * see {@link NativeSurface} and {@link NativeWindow}.
+ * </p>
+ * <a name="multiPtrEvent"><h5>Multiple-Pointer Events</h5></a>
+ * <p>
+ * In case an instance represents a multiple-pointer event, i.e. {@link #getPointerCount()} is &gt; 1,
+ * the first data element of the multiple-pointer fields represents the pointer triggering this event.<br/>
+ * For example {@link #getX(int) e.getX(0)} at {@link #EVENT_MOUSE_PRESSED} returns the data of the pressed pointer, etc.
+ * </p>
+ * <p>
+ * Multiple-pointer event's {@link #getButton() button number} is mapped to the <i>first {@link #getPointerId(int) pointer ID}</i>
+ * triggering the event and the {@link InputEvent#BUTTON1_MASK button mask bits} in the {@link #getModifiers() modifiers}
+ * field represent the pressed pointer IDs.
+ * </p>
+ * <p>
+ * Users can query the pressed button and pointer count via {@link InputEvent#getButtonDownCount()}
+ * or use the simple query {@link InputEvent#isAnyButtonDown()}.
+ * </p>
+ * <p>
+ * If representing a single-pointer {@link PointerType#Mouse} event, {@link #getPointerId(int) pointer-ID} is <code>0</code>
+ * and a {@link #getButton() button value} of <code>0</code> denotes no button activity, i.e. {@link PointerType#Mouse} move.
+ * </p>
+ */
@SuppressWarnings("serial")
public class MouseEvent extends InputEvent
{
+ /** Class of pointer types */
+ public static enum PointerClass implements InputEvent.InputClass {
+ Offscreen, Onscreen, Undefined;
+ }
+
+ /** Type of pointer devices */
+ public static enum PointerType implements InputEvent.InputType {
+ /** {@link PointerClass#Offscreen} mouse. Ordinal 0. */
+ Mouse(PointerClass.Offscreen),
+ /** {@link PointerClass#Offscreen} touch pad, usually using fingers. Ordinal 1. */
+ TouchPad(PointerClass.Offscreen),
+ /** {@link PointerClass#Onscreen} touch screen, usually using fingers. Ordinal 2. */
+ TouchScreen(PointerClass.Onscreen),
+ /** {@link PointerClass#Onscreen} pen usually on screen? Ordinal 3. FIXME*/
+ Pen(PointerClass.Onscreen),
+ /** {@link PointerClass#Undefined} ?. Ordinal 4. */
+ Undefined(PointerClass.Undefined);
+
+ public PointerClass getPointerClass() { return pc; }
+
+ /**
+ * Returns the matching PointerType value corresponding to the given PointerType's integer ordinal.
+ * <pre>
+ * given:
+ * ordinal = enumValue.ordinal()
+ * reverse:
+ * enumValue = EnumClass.values()[ordinal]
+ * </pre>
+ * @throws IllegalArgumentException if the given ordinal is out of range, i.e. not within [ 0 .. PointerType.values().length-1 ]
+ */
+ public static PointerType valueOf(final int ordinal) throws IllegalArgumentException {
+ final PointerType[] all = PointerType.values();
+ if( 0 <= ordinal && ordinal < all.length ) {
+ return all[ordinal];
+ }
+ throw new IllegalArgumentException("Ordinal "+ordinal+" out of range of PointerType.values()[0.."+(all.length-1)+"]");
+ }
+
+ /**
+ * Returns the PointerType array of matching PointerType values corresponding to the given PointerType's integer ordinal values.
+ * <p>
+ * See {@link #valueOf(int)}.
+ * </p>
+ * @throws IllegalArgumentException if one of the given ordinal values is out of range, i.e. not within [ 0 .. PointerType.values().length-1 ]
+ */
+ public static PointerType[] valuesOf(final int[] ordinals) throws IllegalArgumentException {
+ final int count = ordinals.length;
+ final PointerType[] types = new PointerType[count];
+ for(int i=count-1; i>=0; i--) {
+ types[i] = PointerType.valueOf(ordinals[i]);
+ }
+ return types;
+ }
+
+ private PointerType(final PointerClass pc) {
+ this.pc = pc;
+ }
+ PointerClass pc;
+ }
+
/** ID for button 1, value <code>1</code> */
- public static final int BUTTON1 = 1;
+ public static final short BUTTON1 = 1;
/** ID for button 2, value <code>2</code> */
- public static final int BUTTON2 = 2;
+ public static final short BUTTON2 = 2;
/** ID for button 3, value <code>3</code> */
- public static final int BUTTON3 = 3;
+ public static final short BUTTON3 = 3;
/** ID for button 4, value <code>4</code> */
- public static final int BUTTON4 = 4;
+ public static final short BUTTON4 = 4;
/** ID for button 5, value <code>5</code> */
- public static final int BUTTON5 = 5;
+ public static final short BUTTON5 = 5;
/** ID for button 6, value <code>6</code> */
- public static final int BUTTON6 = 6;
- /** Number of buttons, value <code>6</code> */
- public static final int BUTTON_NUMBER = 6;
+ public static final short BUTTON6 = 6;
+ /** ID for button 6, value <code>7</code> */
+ public static final short BUTTON7 = 7;
+ /** ID for button 6, value <code>8</code> */
+ public static final short BUTTON8 = 8;
+ /** ID for button 6, value <code>9</code> */
+ public static final short BUTTON9 = 9;
- public static final int getClickTimeout() {
- return 300;
+ /** Maximum number of buttons, value <code>16</code> */
+ public static final short BUTTON_COUNT = 16;
+
+ /** Returns the 3-axis XYZ rotation array by given rotation on Y axis or X axis (if SHIFT_MASK is given in mods). */
+ public static final float[] getRotationXYZ(final float rotationXorY, final int mods) {
+ final float[] rotationXYZ = new float[] { 0f, 0f, 0f };
+ if( 0 != ( mods & InputEvent.SHIFT_MASK ) ) {
+ rotationXYZ[0] = rotationXorY;
+ } else {
+ rotationXYZ[1] = rotationXorY;
+ }
+ return rotationXYZ;
}
- public MouseEvent(int eventType, Object source, long when,
- int modifiers, int x, int y, int clickCount, int button,
- int rotation)
+ public static final short getClickTimeout() {
+ return 300;
+ }
+
+ /**
+ * Constructor for traditional one-pointer event.
+ *
+ * @param eventType
+ * @param source
+ * @param when
+ * @param modifiers
+ * @param x X-axis
+ * @param y Y-axis
+ * @param clickCount Mouse-button click-count
+ * @param button button number, e.g. [{@link #BUTTON1}..{@link #BUTTON_COUNT}-1].
+ * A button value of <code>0</code> denotes no button activity, i.e. {@link PointerType#Mouse} move.
+ * @param rotationXYZ Rotation of all axis
+ * @param rotationScale Rotation scale
+ */
+ public MouseEvent(final short eventType, final Object source, final long when,
+ final int modifiers, final int x, final int y, final short clickCount, final short button,
+ final float[] rotationXYZ, final float rotationScale)
{
- super(eventType, source, when, modifiers);
+ super(eventType, source, when, modifiers);
this.x = new int[]{x};
this.y = new int[]{y};
- this.pressure = new float[]{0};
- this.pointerids = new int[]{-1};
+ switch(eventType) {
+ case EVENT_MOUSE_CLICKED:
+ case EVENT_MOUSE_PRESSED:
+ case EVENT_MOUSE_DRAGGED:
+ this.pressure = constMousePressure1;
+ break;
+ default:
+ this.pressure = constMousePressure0;
+ }
+ this.maxPressure= 1.0f;
+ this.pointerID = new short[] { (short)0 };
this.clickCount=clickCount;
this.button=button;
- this.wheelRotation = rotation;
+ this.rotationXYZ = rotationXYZ;
+ this.rotationScale = rotationScale;
+ this.pointerType = constMousePointerTypes;
}
- public MouseEvent(int eventType, Object source, long when,
- int modifiers, int[] x, int[] y, float[] pressure, int[] pointerids, int clickCount, int button,
- int rotation)
+ /**
+ * Constructor for a multiple-pointer event.
+ * <p>
+ * First element of multiple-pointer arrays represents the pointer which triggered the event!
+ * </p>
+ * <p>
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * </p>
+ *
+ * @param eventType
+ * @param source
+ * @param when
+ * @param modifiers
+ * @param pointerType PointerType for each pointer (multiple pointer)
+ * @param pointerID Pointer ID for each pointer (multiple pointer). IDs start w/ 0 and are consecutive numbers.
+ * A pointer-ID of -1 may also denote no pointer/button activity, i.e. {@link PointerType#Mouse} move.
+ * @param x X-axis for each pointer (multiple pointer)
+ * @param y Y-axis for each pointer (multiple pointer)
+ * @param pressure Pressure for each pointer (multiple pointer)
+ * @param maxPressure Maximum pointer pressure for all pointer
+ * @param button Corresponding mouse-button
+ * @param clickCount Mouse-button click-count
+ * @param rotationXYZ Rotation of all axis
+ * @param rotationScale Rotation scale
+ */
+ public MouseEvent(final short eventType, final Object source, final long when, final int modifiers,
+ final PointerType pointerType[], final short[] pointerID,
+ final int[] x, final int[] y, final float[] pressure, final float maxPressure,
+ final short button, final short clickCount, final float[] rotationXYZ, final float rotationScale)
{
- super(eventType, source, when, modifiers);
+ super(eventType, source, when, modifiers);
this.x = x;
this.y = y;
- if(pointerids.length != pressure.length ||
- pointerids.length != x.length ||
- pointerids.length != y.length) {
+ final int pointerCount = pointerType.length;
+ if(pointerCount != pointerID.length ||
+ pointerCount != x.length ||
+ pointerCount != y.length ||
+ pointerCount != pressure.length) {
throw new IllegalArgumentException("All multiple pointer arrays must be of same size");
}
+ if( 0.0f >= maxPressure ) {
+ throw new IllegalArgumentException("maxPressure must be > 0.0f");
+ }
this.pressure = pressure;
- this.pointerids = pointerids;
+ this.maxPressure= maxPressure;
+ this.pointerID = pointerID;
this.clickCount=clickCount;
this.button=button;
- this.wheelRotation = rotation;
+ this.rotationXYZ = rotationXYZ;
+ this.rotationScale = rotationScale;
+ this.pointerType = pointerType;
}
-
+
+ public final MouseEvent createVariant(final short newEventType) {
+ return new MouseEvent(newEventType, source, getWhen(), getModifiers(), pointerType, pointerID,
+ x, y, pressure, maxPressure, button, clickCount, rotationXYZ, rotationScale);
+ }
+
/**
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
* @return the count of pointers involved in this event
*/
- public int getPointerCount() {
- return x.length;
+ public final int getPointerCount() {
+ return pointerType.length;
+ }
+
+ /**
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @return the {@link PointerType} for the data at index or null if index not available.
+ */
+ public final PointerType getPointerType(final int index) {
+ if(0 > index || index >= pointerType.length) {
+ return null;
+ }
+ return pointerType[index];
}
-
+
/**
- * @return the pointer id for the data at index.
- * return -1 if index not available.
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @return array of all {@link PointerType}s for all pointers
*/
- public int getPointerId(int index) {
- if(index >= pointerids.length)
+ public final PointerType[] getAllPointerTypes() {
+ return pointerType;
+ }
+
+ /**
+ * Return the pointer id for the given index or -1 if index not available.
+ * <p>
+ * IDs start w/ 0 and are consecutive numbers.
+ * </p>
+ * <p>
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * </p>
+ */
+ public final short getPointerId(final int index) {
+ if(0 > index || index >= pointerID.length) {
return -1;
- return pointerids[index];
+ }
+ return pointerID[index];
}
-
- public int getButton() {
+
+ /**
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @return the pointer index for the given pointer id or -1 if id not available.
+ */
+ public final int getPointerIdx(final short id) {
+ if( id >= 0 ) {
+ for(int i=pointerID.length-1; i>=0; i--) {
+ if( pointerID[i] == id ) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @return array of all pointer IDs for all pointers. IDs start w/ 0 and are consecutive numbers.
+ */
+ public final short[] getAllPointerIDs() {
+ return pointerID;
+ }
+
+ /**
+ * Returns the button number, e.g. [{@link #BUTTON1}..{@link #BUTTON_COUNT}-1].
+ * <p>
+ * A button value of <code>0</code> denotes no button activity, i.e. {@link PointerType#Mouse} move.
+ * </p>
+ * <p>
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * </p>
+ */
+ public final short getButton() {
return button;
}
-
- public int getClickCount() {
+
+ public final short getClickCount() {
return clickCount;
}
- public int getX() {
+
+ /**
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @return X-Coord of the triggering pointer-index zero in pixel units.
+ */
+ public final int getX() {
return x[0];
}
-
- public int getY() {
+
+ /**
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @return Y-Coord of the triggering pointer-index zero in pixel units.
+ */
+ public final int getY() {
return y[0];
}
- /**
- * @return x-coord at index where index refers to the
- * data coming from a pointer.
+ /**
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @param index pointer-index within [0 .. {@link #getPointerCount()}-1]
+ * @return X-Coord associated with the pointer-index in pixel units.
* @see getPointerId(index)
*/
- public int getX(int index) {
+ public final int getX(final int index) {
return x[index];
}
- public int getY(int index) {
+ /**
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @param index pointer-index within [0 .. {@link #getPointerCount()}-1]
+ * @return Y-Coord associated with the pointer-index in pixel units.
+ * @see getPointerId(index)
+ */
+ public final int getY(final int index) {
return y[index];
}
-
- public float getPressure(){
- return pressure[0];
+
+ /**
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @return array of all X-Coords for all pointers in pixel units.
+ */
+ public final int[] getAllX() {
+ return x;
}
-
+
/**
- * @return the pressure associated with the pointer at index.
- * the value of zero is return if not available.
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @return array of all Y-Coords for all pointers in pixel units.
+ */
+ public final int[] getAllY() {
+ return y;
+ }
+
+ /**
+ * @param normalized if true, method returns the normalized pressure, i.e. <code>pressure / maxPressure</code>
+ * @return The pressure associated with the pointer-index 0.
+ * The value of zero is return if not available.
+ * @see #getMaxPressure()
+ */
+ public final float getPressure(final boolean normalized){
+ return normalized ? pressure[0] / maxPressure : pressure[0];
+ }
+
+ /**
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @param index pointer-index within [0 .. {@link #getPointerCount()}-1]
+ * @param normalized if true, method returns the normalized pressure, i.e. <code>pressure / maxPressure</code>
+ * @return The pressure associated with the pointer-index.
+ * The value of zero is return if not available.
+ * @see #getMaxPressure()
+ */
+ public final float getPressure(final int index, final boolean normalized){
+ return normalized ? pressure[index] / maxPressure : pressure[index];
+ }
+
+ /**
+ * See details for <a href="#multiPtrEvent">multiple-pointer events</a>.
+ * @return array of all raw, un-normalized pressures for all pointers
+ */
+ public final float[] getAllPressures() {
+ return pressure;
+ }
+
+ /**
+ * Returns the maximum pressure known for the input device generating this event.
+ * <p>
+ * This value may be self calibrating on devices/OS, where no known maximum pressure is known.
+ * Hence subsequent events may return a higher value.
+ * </p>
+ * <p>
+ * Self calibrating maximum pressure is performed on:
+ * <ul>
+ * <li>Android</li>
+ * </ul>
+ * </p>
*/
- public float getPressure(int index){
- return pressure[index];
+ public final float getMaxPressure() {
+ return maxPressure;
}
-
+
/**
- * <i>Usually</i> a wheel rotation of <b>&gt; 0 is up</b>,
- * and <b>&lt; 0 is down</b>.<br>
+ * Returns a 3-component float array filled with the values of the rotational axis
+ * in the following order: horizontal-, vertical- and z-axis.
+ * <p>
+ * A vertical rotation of <b>&gt; 0.0f is up</b> and <b>&lt; 0.0f is down</b>.
+ * </p>
+ * <p>
+ * A horizontal rotation of <b>&gt; 0.0f is left</b> and <b>&lt; 0.0f is right</b>.
+ * </p>
+ * <p>
+ * A z-axis rotation of <b>&gt; 0.0f is back</b> and <b>&lt; 0.0f is front</b>.
+ * </p>
+ * <p>
* <i>However</i>, on some OS this might be flipped due to the OS <i>default</i> behavior.
* The latter is true for OS X 10.7 (Lion) for example.
+ * </p>
+ * <p>
+ * On PointerClass {@link PointerClass#Onscreen onscreen} devices, i.e. {@link PointerType#TouchScreen touch screens},
+ * rotation events are usually produced by a 2-finger movement, where horizontal and vertical rotation values are filled.
+ * </p>
+ * <p>
+ * On PointerClass {@link PointerClass#Offscreen offscreen} devices, i.e. {@link PointerType#Mouse mouse},
+ * either the horizontal or the vertical rotation value is filled.
+ * </p>
+ * <p>
+ * The {@link InputEvent#SHIFT_MASK} modifier is set in case <b>|horizontal| &gt; |vertical|</b> value.<br/>
+ * This can be utilized to implement only one 2d rotation direction, you may use {@link #isShiftDown()} to query it.
+ * </p>
* <p>
- * The events will be send usually in steps of one, ie. <i>-1</i> and <i>1</i>.
+ * In case the pointer type is {@link PointerType#Mouse mouse},
+ * events are usually send in steps of one, ie. <i>-1.0f</i> and <i>1.0f</i>.
* Higher values may result due to fast scrolling.
+ * Fractional values may result due to slow scrolling with high resolution devices.<br/>
+ * Here the button number refers to the wheel number.
* </p>
* <p>
- * The button number refers to the wheel number.
- * </p>
- * @return
+ * In case the pointer type is of class {@link PointerClass#Onscreen}, e.g. {@link PointerType#TouchScreen touch screen},
+ * see {@link #getRotationScale()} for semantics.
+ * </p>
*/
- public int getWheelRotation() {
- return wheelRotation;
+ public final float[] getRotation() {
+ return rotationXYZ;
}
- public String toString() {
+ /**
+ * Returns the scale used to determine the {@link #getRotation() rotation value},
+ * which semantics depends on the {@link #getPointerType() pointer type's} {@link PointerClass}.
+ * <p>
+ * For {@link PointerClass#Offscreen}, the scale is usually <code>1.0f</code> and denominates
+ * an abstract value without association to a physical value.
+ * </p>
+ * <p>
+ * For {@link PointerClass#Onscreen}, the scale varies and denominates
+ * the divisor of the distance the finger[s] have moved on the screen.
+ * Hence <code>scale * rotation</code> reproduces the screen distance in pixels the finger[s] have moved.
+ * </p>
+ */
+ public final float getRotationScale() {
+ return rotationScale;
+ }
+
+ @Override
+ public final String toString() {
return toString(null).toString();
}
- public StringBuilder toString(StringBuilder sb) {
+ @Override
+ public final StringBuilder toString(StringBuilder sb) {
if(null == sb) {
sb = new StringBuilder();
}
sb.append("MouseEvent[").append(getEventTypeString(getEventType()))
- .append(", ").append(x).append("/").append(y)
+ .append(", ").append(Arrays.toString(x)).append("/").append(Arrays.toString(y))
.append(", button ").append(button).append(", count ")
- .append(clickCount).append(", wheel rotation ").append(wheelRotation);
- if(pointerids.length>0) {
- sb.append(", pointer<").append(pointerids.length).append(">[");
- for(int i=0; i<pointerids.length; i++) {
+ .append(clickCount).append(", rotation [").append(rotationXYZ[0]).append(", ").append(rotationXYZ[1]).append(", ").append(rotationXYZ[2]).append("] * ").append(rotationScale);
+ if(pointerID.length>0) {
+ sb.append(", pointer<").append(pointerID.length).append(">[");
+ for(int i=0; i<pointerID.length; i++) {
if(i>0) {
sb.append(", ");
}
- sb.append(pointerids[i]).append(": ")
- .append(x[i]).append(" / ").append(y[i]).append(" ")
- .append(pressure[i]).append("p");
+ sb.append(pointerID[i]).append("/").append(pointerType[i]).append(": ")
+ .append(x[i]).append("/").append(y[i]).append(", ")
+ .append("p[").append(pressure[i]).append("/").append(maxPressure).append("=").append(pressure[i]/maxPressure).append("]");
}
sb.append("]");
- }
+ }
sb.append(", ");
return super.toString(sb).append("]");
}
- public static String getEventTypeString(int type) {
+ public static String getEventTypeString(final short type) {
switch(type) {
- case EVENT_MOUSE_CLICKED: return "EVENT_MOUSE_CLICKED";
- case EVENT_MOUSE_ENTERED: return "EVENT_MOUSE_ENTERED";
- case EVENT_MOUSE_EXITED: return "EVENT_MOUSE_EXITED";
- case EVENT_MOUSE_PRESSED: return "EVENT_MOUSE_PRESSED";
- case EVENT_MOUSE_RELEASED: return "EVENT_MOUSE_RELEASED";
- case EVENT_MOUSE_MOVED: return "EVENT_MOUSE_MOVED";
- case EVENT_MOUSE_DRAGGED: return "EVENT_MOUSE_DRAGGED";
- case EVENT_MOUSE_WHEEL_MOVED: return "EVENT_MOUSE_WHEEL_MOVED";
- default: return "unknown (" + type + ")";
+ case EVENT_MOUSE_CLICKED: return "EVENT_MOUSE_CLICKED";
+ case EVENT_MOUSE_ENTERED: return "EVENT_MOUSE_ENTERED";
+ case EVENT_MOUSE_EXITED: return "EVENT_MOUSE_EXITED";
+ case EVENT_MOUSE_PRESSED: return "EVENT_MOUSE_PRESSED";
+ case EVENT_MOUSE_RELEASED: return "EVENT_MOUSE_RELEASED";
+ case EVENT_MOUSE_MOVED: return "EVENT_MOUSE_MOVED";
+ case EVENT_MOUSE_DRAGGED: return "EVENT_MOUSE_DRAGGED";
+ case EVENT_MOUSE_WHEEL_MOVED: return "EVENT_MOUSE_WHEEL_MOVED";
+ default: return "unknown (" + type + ")";
}
}
- private final int x[], y[], clickCount, button, wheelRotation;
+
+ /** PointerType for each pointer (multiple pointer) */
+ private final PointerType pointerType[];
+ /** Pointer-ID for each pointer (multiple pointer). IDs start w/ 0 and are consecutive numbers. */
+ private final short pointerID[];
+ /** X-axis for each pointer (multiple pointer) */
+ private final int x[];
+ /** Y-axis for each pointer (multiple pointer) */
+ private final int y[];
+ /** Pressure for each pointer (multiple pointer) */
private final float pressure[];
- private final int pointerids[];
-
- public static final int EVENT_MOUSE_CLICKED = 200;
- public static final int EVENT_MOUSE_ENTERED = 201;
- public static final int EVENT_MOUSE_EXITED = 202;
- public static final int EVENT_MOUSE_PRESSED = 203;
- public static final int EVENT_MOUSE_RELEASED = 204;
- public static final int EVENT_MOUSE_MOVED = 205;
- public static final int EVENT_MOUSE_DRAGGED = 206;
- public static final int EVENT_MOUSE_WHEEL_MOVED = 207;
+ // private final short tiltX[], tiltY[]; // TODO: A generic way for pointer axis information, see Android MotionEvent!
+ private final short clickCount;
+ /**
+ * Returns the button number, e.g. [{@link #BUTTON1}..{@link #BUTTON_COUNT}-1].
+ * <p>
+ * A button value of <code>0</code> denotes no button activity, i.e. {@link PointerType#Mouse} move.
+ * </p>
+ */
+ private final short button;
+ /** Rotation around the X, Y and X axis */
+ private final float[] rotationXYZ;
+ /** Rotation scale */
+ private final float rotationScale;
+ private final float maxPressure;
+
+ private static final float[] constMousePressure0 = new float[]{0f};
+ private static final float[] constMousePressure1 = new float[]{1f};
+ private static final PointerType[] constMousePointerTypes = new PointerType[] { PointerType.Mouse };
+
+ public static final short EVENT_MOUSE_CLICKED = 200;
+ /** Only generated for {@link PointerType#Mouse} */
+ public static final short EVENT_MOUSE_ENTERED = 201;
+ /** Only generated for {@link PointerType#Mouse} */
+ public static final short EVENT_MOUSE_EXITED = 202;
+ public static final short EVENT_MOUSE_PRESSED = 203;
+ public static final short EVENT_MOUSE_RELEASED = 204;
+ public static final short EVENT_MOUSE_MOVED = 205;
+ public static final short EVENT_MOUSE_DRAGGED = 206;
+ public static final short EVENT_MOUSE_WHEEL_MOVED = 207;
}
diff --git a/src/newt/classes/com/jogamp/newt/event/MouseListener.java b/src/newt/classes/com/jogamp/newt/event/MouseListener.java
index 7668b755c..5e62306f3 100644
--- a/src/newt/classes/com/jogamp/newt/event/MouseListener.java
+++ b/src/newt/classes/com/jogamp/newt/event/MouseListener.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,22 +29,37 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package com.jogamp.newt.event;
+import com.jogamp.newt.event.MouseEvent.PointerType;
+
+/**
+ * Listener for {@link MouseEvent}s.
+ *
+ * @see MouseEvent
+ */
public interface MouseListener extends NEWTEventListener
{
- public void mouseClicked(MouseEvent e);
- public void mouseEntered(MouseEvent e);
- public void mouseExited(MouseEvent e);
- public void mousePressed(MouseEvent e);
- public void mouseReleased(MouseEvent e);
- public void mouseMoved(MouseEvent e);
- public void mouseDragged(MouseEvent e);
-
- /** See {@link MouseEvent#getWheelRotation() } */
- public void mouseWheelMoved(MouseEvent e);
+ public void mouseClicked(MouseEvent e);
+ /** Only generated for {@link PointerType#Mouse} */
+ public void mouseEntered(MouseEvent e);
+ /** Only generated for {@link PointerType#Mouse} */
+ public void mouseExited(MouseEvent e);
+ public void mousePressed(MouseEvent e);
+ public void mouseReleased(MouseEvent e);
+ public void mouseMoved(MouseEvent e);
+ public void mouseDragged(MouseEvent e);
+
+ /**
+ * Traditional event name originally produced by a {@link PointerType#Mouse mouse} pointer type.
+ * <p>
+ * Triggered for any rotational pointer events, see
+ * {@link MouseEvent#getRotation()} and {@link MouseEvent#getRotationScale()}.
+ * </p>
+ */
+ public void mouseWheelMoved(MouseEvent e);
}
diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java
index fd5b69ccc..a9d9d8bdb 100644
--- a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package com.jogamp.newt.event;
@@ -41,88 +41,35 @@ package com.jogamp.newt.event;
*
* Event type registry:<br>
* <ul>
- * <li> WindowEvent <code>100..10x</code></li>
- * <li> MouseEvent <code>200..20x</code></li>
- * <li> KeyEvent <code>300..30x</code></li>
+ * <li> WindowEvent <code>100..10x</code></li>
+ * <li> MouseEvent <code>200..20x</code></li>
+ * <li> KeyEvent <code>300..30x</code></li>
+ * <li> GestureEvent <code>400..5xx</code></li>
+ * <li> MonitorEvent <code>600..60x</code></li>
* </ul><br>
*/
@SuppressWarnings("serial")
public class NEWTEvent extends java.util.EventObject {
- private final boolean isSystemEvent;
- private final int eventType;
+ /**
+ * See {@link #setConsumed(boolean)} for description.
+ */
+ public static final Object consumedTag = new Object();
+
+ private final short eventType;
private final long when;
private Object attachment;
static final boolean DEBUG = false;
- // 0: NEWTEvent.java
- // 1: InputEvent.java
- // 2: KeyEvent.java
- // 3: com.jogamp.newt.Window
- // 3: com.jogamp.newt.event.awt.AWTNewtEventFactory
- // 2: MouseEvent.java
- // 3: com.jogamp.newt.Window
- // 3: com.jogamp.newt.event.awt.AWTNewtEventFactory
- // 1: WindowEvent.java
- // 2: com.jogamp.newt.Window
- // 2: com.jogamp.newt.event.awt.AWTNewtEventFactory
- //
- // FIXME: verify the isSystemEvent evaluation
- //
- static final String WindowClazzName = "com.jogamp.newt.Window" ;
- static final String AWTNewtEventFactoryClazzName = "com.jogamp.newt.event.awt.AWTNewtEventFactory" ;
-
- /**
- static final boolean evaluateIsSystemEvent(NEWTEvent event, Throwable t) {
- StackTraceElement[] stack = t.getStackTrace();
- if(stack.length==0 || null==stack[0]) {
- return false;
- }
- if(DEBUG) {
- for (int i = 0; i < stack.length && i<5; i++) {
- System.err.println(i+": " + stack[i].getClassName()+ "." + stack[i].getMethodName());
- }
- }
-
- String clazzName = null;
-
- if( event instanceof com.jogamp.newt.event.WindowEvent ) {
- if ( stack.length > 2 ) {
- clazzName = stack[2].getClassName();
- }
- } else if( (event instanceof com.jogamp.newt.event.MouseEvent) ||
- (event instanceof com.jogamp.newt.event.KeyEvent) ) {
- if ( stack.length > 3 ) {
- clazzName = stack[3].getClassName();
- }
- }
-
- boolean res = null!=clazzName && (
- clazzName.equals(WindowClazzName) ||
- clazzName.equals(AWTNewtEventFactoryClazzName) ) ;
- if(DEBUG) {
- System.err.println("system: "+res);
- }
- return res;
- } */
-
- protected NEWTEvent(int eventType, Object source, long when) {
+ protected NEWTEvent(final short eventType, final Object source, final long when) {
super(source);
- // this.isSystemEvent = evaluateIsSystemEvent(this, new Throwable());
- this.isSystemEvent = false; // FIXME: Need a more efficient way to determine system events
this.eventType = eventType;
this.when = when;
this.attachment=null;
}
- /** Indicates whether this event was produced by the system or
- generated by user code. */
- public final boolean isSystemEvent() {
- return isSystemEvent;
- }
-
/** Returns the event type of this event. */
- public final int getEventType() {
+ public final short getEventType() {
return eventType;
}
@@ -131,25 +78,60 @@ public class NEWTEvent extends java.util.EventObject {
return when;
}
- /**
+ /**
* Attach the passed object to this event.<br>
* If an object was previously attached, it will be replaced.<br>
* Attachments to NEWT events allow users to pass on information
- * from one custom listener to another, ie custom listener to listener
+ * from one custom listener to another, ie custom listener to listener
* communication.
* @param attachment User application specific object
*/
- public final void setAttachment(Object attachment) {
- this.attachment=attachment;
+ public final void setAttachment(final Object attachment) {
+ this.attachment = attachment;
}
- /**
+ /**
* @return The user application specific attachment, or null
*/
public final Object getAttachment() {
return attachment;
}
+ /**
+ * Returns <code>true</code> if this events has been {@link #setConsumed(boolean) consumed},
+ * otherwise <code>false</code>.
+ * @see #setConsumed(boolean)
+ */
+ public final boolean isConsumed() {
+ return consumedTag == attachment;
+ }
+
+ /**
+ * If <code>consumed</code> is <code>true</code>, this event is marked as consumed,
+ * ie. the event will not be propagated any further to potential <i>other</i> event listener.
+ * Otherwise the event will be propagated to other event listener, the default.
+ * <p>
+ * The event is marked as being consumed while {@link #setAttachment(Object) attaching}
+ * the {@link #consumedTag}.
+ * </p>
+ * <p>
+ * Events with platform specific actions will be supressed if marked as consumed.
+ * Examples are:
+ * <ul>
+ * <li>{@link KeyEvent#VK_ESCAPE} on Android's BACK button w/ Activity::finish()</li>
+ * <li>{@link KeyEvent#VK_HOME} on Android's HOME button w/ Intend.ACTION_MAIN[Intend.CATEGORY_HOME]</li>
+ * </ul>
+ * </p>
+ */
+ public final void setConsumed(final boolean consumed) {
+ if( consumed ) {
+ setAttachment( consumedTag );
+ } else if( consumedTag == attachment ) {
+ setAttachment( null );
+ }
+ }
+
+ @Override
public String toString() {
return toString(null).toString();
}
@@ -158,14 +140,10 @@ public class NEWTEvent extends java.util.EventObject {
if(null == sb) {
sb = new StringBuilder();
}
- return sb.append("NEWTEvent[sys:").append(isSystemEvent()).append(", source:").append(getSource().getClass().getName()).append(", when:").append(getWhen()).append(" d ").append((System.currentTimeMillis()-getWhen())).append("ms]");
- }
-
- public static String toHexString(int hex) {
- return "0x" + Integer.toHexString(hex);
+ return sb.append("NEWTEvent[source:").append(getSource().getClass().getName()).append(", consumed ").append(isConsumed()).append(", when:").append(getWhen()).append(" d ").append((System.currentTimeMillis()-getWhen())).append("ms]");
}
- public static String toHexString(long hex) {
- return "0x" + Long.toHexString(hex);
+ public static String toHexString(final short hex) {
+ return "0x" + Integer.toHexString( hex & 0x0000FFFF );
}
}
diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEventConsumer.java b/src/newt/classes/com/jogamp/newt/event/NEWTEventConsumer.java
index 6aa19e5f8..14fba6742 100644
--- a/src/newt/classes/com/jogamp/newt/event/NEWTEventConsumer.java
+++ b/src/newt/classes/com/jogamp/newt/event/NEWTEventConsumer.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,18 +20,18 @@
* 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 com.jogamp.newt.event;
public interface NEWTEventConsumer {
- /**
- * Consume the event
+ /**
+ * Consume the event
*
* @return true if the event has been consumed,
* otherwise it returns false for later propagation.
diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEventFiFo.java b/src/newt/classes/com/jogamp/newt/event/NEWTEventFiFo.java
index fe224bba6..dd6395354 100644
--- a/src/newt/classes/com/jogamp/newt/event/NEWTEventFiFo.java
+++ b/src/newt/classes/com/jogamp/newt/event/NEWTEventFiFo.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,22 +20,22 @@
* 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 com.jogamp.newt.event;
import java.util.LinkedList;
public class NEWTEventFiFo
{
- private LinkedList/*<NEWTEvent>*/ events = new LinkedList/*<NEWTEvent>*/();
+ private final LinkedList/*<NEWTEvent>*/ events = new LinkedList/*<NEWTEvent>*/();
/** Add NEWTEvent to tail */
- public synchronized void put(NEWTEvent event) {
+ public synchronized void put(final NEWTEvent event) {
events.addLast(event);
notifyAll();
}
diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEventListener.java b/src/newt/classes/com/jogamp/newt/event/NEWTEventListener.java
index 677136573..f7ee3d739 100644
--- a/src/newt/classes/com/jogamp/newt/event/NEWTEventListener.java
+++ b/src/newt/classes/com/jogamp/newt/event/NEWTEventListener.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package com.jogamp.newt.event;
diff --git a/src/newt/classes/com/jogamp/newt/event/OutputEvent.java b/src/newt/classes/com/jogamp/newt/event/OutputEvent.java
new file mode 100644
index 000000000..bd3a11a13
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/event/OutputEvent.java
@@ -0,0 +1,51 @@
+/**
+ * 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 com.jogamp.newt.event;
+
+@SuppressWarnings("serial")
+public abstract class OutputEvent extends NEWTEvent
+{
+ protected OutputEvent(final short eventType, final Object source, final long when) {
+ super(eventType, source, when);
+ }
+
+ /**
+ public String toString() {
+ return toString(null).toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ sb.append("OutputEvent[");
+ super.toString(sb).append("]");
+ return sb;
+ } */
+}
diff --git a/src/newt/classes/com/jogamp/newt/event/PinchToZoomGesture.java b/src/newt/classes/com/jogamp/newt/event/PinchToZoomGesture.java
new file mode 100644
index 000000000..9c7a4bcb8
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/event/PinchToZoomGesture.java
@@ -0,0 +1,252 @@
+/**
+ * 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 com.jogamp.newt.event;
+
+import javax.media.nativewindow.NativeSurface;
+
+import com.jogamp.newt.event.MouseEvent.PointerClass;
+
+import jogamp.newt.Debug;
+
+/**
+ * 2 pointer zoom, a.k.a. <i>pinch to zoom</i>, gesture handler processing {@link MouseEvent}s
+ * while producing {@link ZoomEvent}s if gesture is completed.
+ * <p>
+ * Zoom value lies within [0..2], with 1 as <i>1:1</i>.
+ * </p>
+ * <pre>
+ * - choosing the smallest surface edge (width/height -> x/y)
+ * - tolerating other fingers to be pressed and hence user to add functionality (scale, ..)
+ * </pre>
+ */
+public class PinchToZoomGesture implements GestureHandler {
+ public static final boolean DEBUG = Debug.debug("Window.MouseEvent");
+
+ /** A {@link GestureHandler.GestureEvent} denominating zoom. */
+ @SuppressWarnings("serial")
+ public static class ZoomEvent extends GestureEvent {
+ private final float zoom;
+ private final float delta;
+ private final float scale;
+ public ZoomEvent(final Object source, final long when, final int modifiers, final GestureHandler handler, final MouseEvent pe,
+ final float zoom, final float delta, final float scale) {
+ super(source, when, modifiers, handler, pe);
+ this.zoom = zoom;
+ this.delta = delta;
+ this.scale = scale;
+ }
+ /** Zoom value lies within [0..2], with 1 as <i>1:1</i>. */
+ public final float getZoom() { return zoom; }
+ /** Delta to last zoom value lies within [-1..1]. */
+ public final float getDelta() { return delta; }
+ /**
+ * Returns the scale used to determine the {@link #getZoom() zoom}
+ * and hence it's {@link #getDelta() delta} value,
+ * which semantics depends on the {@link #getPointerType() pointer type's} {@link PointerClass}.
+ * <p>
+ * For {@link PointerClass#Offscreen}, the scale is usually <code>1.0f</code> and denominates
+ * an abstract value without association to a physical value.
+ * </p>
+ * <p>
+ * For {@link PointerClass#Onscreen}, the scale varies and denominates
+ * the divisor of the distance the finger[s] have moved on the screen.
+ * Hence <code>scale * delta</code> reproduces the screen distance in pixels the finger[s] have moved.
+ * </p>
+ */
+ public final float getScale() { return scale; }
+
+ public final String toString() {
+ return "ZoomEvent[zoom "+zoom+", delta "+delta+", scale "+scale+", trigger "+getTrigger()+", handler "+getHandler()+"]";
+ }
+ }
+
+ private final NativeSurface surface;
+ private final boolean allowMorePointer;
+ private float zoom;
+ private int zoomLastEdgeDist;
+ private boolean zoomFirstTouch;
+ private boolean zoomMode;
+ private ZoomEvent zoomEvent;
+ private final short[] pIds = new short[] { -1, -1 };
+
+ /**
+ * @param surface the {@link NativeSurface}, which size is used to compute the relative zoom factor
+ * @param allowMorePointer if false, allow only 2 pressed pointers (safe and recommended), otherwise accept other pointer to be pressed.
+ */
+ public PinchToZoomGesture(final NativeSurface surface, final boolean allowMorePointer) {
+ clear(true);
+ this.surface = surface;
+ this.allowMorePointer = allowMorePointer;
+ this.zoom = 1f;
+ }
+
+ @Override
+ public String toString() {
+ return "PinchZoom[1stTouch "+zoomFirstTouch+", in "+isWithinGesture()+", has "+(null!=zoomEvent)+", zoom "+zoom+"]";
+ }
+
+ private int gesturePointers(final MouseEvent e, final int excludeIndex) {
+ int j = 0;
+ for(int i=e.getPointerCount()-1; i>=0; i--) {
+ if( excludeIndex != i ) {
+ final int id = e.getPointerId(i);
+ if( pIds[0] == id || pIds[1] == id ) {
+ j++;
+ }
+ }
+ }
+ return j;
+ }
+
+ @Override
+ public void clear(final boolean clearStarted) {
+ zoomEvent = null;
+ if( clearStarted ) {
+ zoomLastEdgeDist = 0;
+ zoomFirstTouch = true;
+ zoomMode = false;
+ pIds[0] = -1;
+ pIds[1] = -1;
+ }
+ }
+
+ @Override
+ public boolean isWithinGesture() {
+ return zoomMode;
+ }
+
+ @Override
+ public boolean hasGesture() {
+ return null != zoomEvent;
+ }
+
+ @Override
+ public InputEvent getGestureEvent() {
+ return zoomEvent;
+ }
+
+ /** Zoom value lies within [0..2], with 1 as <i>1:1</i>. */
+ public final float getZoom() {
+ return zoom;
+ }
+ /** Set zoom value within [0..2], with 1 as <i>1:1</i>. */
+ public final void setZoom(final float zoom) {
+ this.zoom=zoom;
+ }
+
+ @Override
+ public boolean process(final InputEvent in) {
+ if( null != zoomEvent || !(in instanceof MouseEvent) ) {
+ return true;
+ }
+ final MouseEvent pe = (MouseEvent)in;
+ final int pointerDownCount = pe.getPointerCount();
+
+ if( pe.getPointerType(0).getPointerClass() != MouseEvent.PointerClass.Onscreen ||
+ ( !allowMorePointer && pointerDownCount > 2 ) ) {
+ return false;
+ }
+
+ final int eventType = pe.getEventType();
+ final boolean useY = surface.getSurfaceWidth() >= surface.getSurfaceHeight(); // use smallest dimension
+ switch ( eventType ) {
+ case MouseEvent.EVENT_MOUSE_PRESSED: {
+ if( 1 == pointerDownCount ) {
+ pIds[0] = pe.getPointerId(0);
+ pIds[1] = -1;
+ } else if ( 2 <= pointerDownCount ) { // && 1 == gesturePointers(pe, 0) /* w/o pressed pointer */) {
+ pIds[0] = pe.getPointerId(0);
+ pIds[1] = pe.getPointerId(1);
+ }
+ if(DEBUG) {
+ System.err.println("XXX1: id0 "+pIds[0]+" -> idx0 "+0+", id1 "+pIds[1]+" -> idx1 "+1);
+ System.err.println(this+".pressed: down "+pointerDownCount+", gPtr "+gesturePointers(pe, -1)+", event "+pe);
+ }
+ } break;
+
+ case MouseEvent.EVENT_MOUSE_RELEASED: {
+ final int gPtr = gesturePointers(pe, 0); // w/o lifted pointer
+ if ( 1 == gPtr ) {
+ zoomFirstTouch = true;
+ zoomMode = false;
+ } else if( 0 == gPtr ) {
+ // all lifted
+ clear(true);
+ }
+ if(DEBUG) {
+ System.err.println(this+".released: down "+pointerDownCount+", gPtr "+gPtr+", event "+pe);
+ }
+ } break;
+
+ case MouseEvent.EVENT_MOUSE_DRAGGED: {
+ if( 2 <= pointerDownCount ) {
+ final int gPtr = gesturePointers(pe, -1);
+ if( 2 == gPtr ) {
+ // same pointers
+ final int p0Idx = pe.getPointerIdx(pIds[0]);
+ final int p1Idx = pe.getPointerIdx(pIds[1]);
+ if( 0 <= p0Idx && 0 <= p1Idx ) {
+ final int edge0 = useY ? pe.getY(p0Idx) : pe.getX(p0Idx);
+ final int edge1 = useY ? pe.getY(p1Idx) : pe.getX(p1Idx);
+ // Diff. 1:1 Zoom: finger-distance to screen-coord
+ if(zoomFirstTouch) {
+ zoomLastEdgeDist = Math.abs(edge0-edge1);
+ zoomFirstTouch=false;
+ zoomMode = true;
+ } else if( zoomMode ) {
+ final int d = Math.abs(edge0-edge1);
+ final int dd = d - zoomLastEdgeDist;
+ final float screenEdge = useY ? surface.getSurfaceHeight() : surface.getSurfaceWidth();
+ final float delta = dd / screenEdge; // [-1..1]
+ if(DEBUG) {
+ System.err.println("XXX2: id0 "+pIds[0]+" -> idx0 "+p0Idx+", id1 "+pIds[1]+" -> idx1 "+p1Idx);
+ System.err.println("XXX3: d "+d+", ld "+zoomLastEdgeDist+", dd "+dd+", screen "+screenEdge+" -> incr "+delta+", zoom "+zoom+" -> "+(zoom+delta));
+ }
+ zoom += delta;
+ // clip value
+ if( 2f < zoom ) {
+ zoom = 2f;
+ } else if( 0 > zoom ) {
+ zoom = 0;
+ }
+ zoomLastEdgeDist = d;
+ zoomEvent = new ZoomEvent(pe.getSource(), pe.getWhen(), pe.getModifiers(), this, pe, zoom, delta, screenEdge);
+ }
+ }
+ }
+ if(DEBUG) {
+ System.err.println(this+".dragged: down "+pointerDownCount+", gPtr "+gPtr+", event "+pe);
+ }
+ }
+ } break;
+
+ default:
+ }
+ return null != zoomEvent;
+ }
+}
diff --git a/src/newt/classes/com/jogamp/newt/event/TraceKeyAdapter.java b/src/newt/classes/com/jogamp/newt/event/TraceKeyAdapter.java
index 98ba5a24d..50eae9626 100644
--- a/src/newt/classes/com/jogamp/newt/event/TraceKeyAdapter.java
+++ b/src/newt/classes/com/jogamp/newt/event/TraceKeyAdapter.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,12 +20,12 @@
* 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 com.jogamp.newt.event;
public class TraceKeyAdapter implements KeyListener {
@@ -36,21 +36,19 @@ public class TraceKeyAdapter implements KeyListener {
this.downstream = null;
}
- public TraceKeyAdapter(KeyListener downstream) {
+ public TraceKeyAdapter(final KeyListener downstream) {
this.downstream = downstream;
}
- public void keyPressed(KeyEvent e) {
+ @Override
+ public void keyPressed(final KeyEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.keyPressed(e); }
}
- public void keyReleased(KeyEvent e) {
+ @Override
+ public void keyReleased(final KeyEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.keyReleased(e); }
}
- public void keyTyped(KeyEvent e) {
- System.err.println(e);
- if(null!=downstream) { downstream.keyTyped(e); }
- }
}
diff --git a/src/newt/classes/com/jogamp/newt/event/TraceMouseAdapter.java b/src/newt/classes/com/jogamp/newt/event/TraceMouseAdapter.java
index 14ee633a0..e54c3730f 100644
--- a/src/newt/classes/com/jogamp/newt/event/TraceMouseAdapter.java
+++ b/src/newt/classes/com/jogamp/newt/event/TraceMouseAdapter.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,12 +20,12 @@
* 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 com.jogamp.newt.event;
public class TraceMouseAdapter implements MouseListener {
@@ -36,39 +36,47 @@ public class TraceMouseAdapter implements MouseListener {
this.downstream = null;
}
- public TraceMouseAdapter(MouseListener downstream) {
+ public TraceMouseAdapter(final MouseListener downstream) {
this.downstream = downstream;
}
- public void mouseClicked(MouseEvent e) {
+ @Override
+ public void mouseClicked(final MouseEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.mouseClicked(e); }
}
- public void mouseEntered(MouseEvent e) {
+ @Override
+ public void mouseEntered(final MouseEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.mouseEntered(e); }
}
- public void mouseExited(MouseEvent e) {
+ @Override
+ public void mouseExited(final MouseEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.mouseExited(e); }
}
- public void mousePressed(MouseEvent e) {
+ @Override
+ public void mousePressed(final MouseEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.mousePressed(e); }
}
- public void mouseReleased(MouseEvent e) {
+ @Override
+ public void mouseReleased(final MouseEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.mouseReleased(e); }
}
- public void mouseMoved(MouseEvent e) {
+ @Override
+ public void mouseMoved(final MouseEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.mouseMoved(e); }
}
- public void mouseDragged(MouseEvent e) {
+ @Override
+ public void mouseDragged(final MouseEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.mouseDragged(e); }
}
- public void mouseWheelMoved(MouseEvent e) {
+ @Override
+ public void mouseWheelMoved(final MouseEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.mouseWheelMoved(e); }
}
diff --git a/src/newt/classes/com/jogamp/newt/event/TraceWindowAdapter.java b/src/newt/classes/com/jogamp/newt/event/TraceWindowAdapter.java
index 8542820c4..299a6ff90 100644
--- a/src/newt/classes/com/jogamp/newt/event/TraceWindowAdapter.java
+++ b/src/newt/classes/com/jogamp/newt/event/TraceWindowAdapter.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,12 +20,12 @@
* 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 com.jogamp.newt.event;
public class TraceWindowAdapter implements WindowListener {
@@ -36,35 +36,42 @@ public class TraceWindowAdapter implements WindowListener {
this.downstream = null;
}
- public TraceWindowAdapter(WindowListener downstream) {
+ public TraceWindowAdapter(final WindowListener downstream) {
this.downstream = downstream;
}
- public void windowResized(WindowEvent e) {
+ @Override
+ public void windowResized(final WindowEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.windowResized(e); }
}
- public void windowMoved(WindowEvent e) {
+ @Override
+ public void windowMoved(final WindowEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.windowMoved(e); }
}
- public void windowDestroyNotify(WindowEvent e) {
+ @Override
+ public void windowDestroyNotify(final WindowEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.windowDestroyNotify(e); }
}
- public void windowDestroyed(WindowEvent e) {
+ @Override
+ public void windowDestroyed(final WindowEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.windowDestroyed(e); }
}
- public void windowGainedFocus(WindowEvent e) {
+ @Override
+ public void windowGainedFocus(final WindowEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.windowGainedFocus(e); }
}
- public void windowLostFocus(WindowEvent e) {
+ @Override
+ public void windowLostFocus(final WindowEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.windowLostFocus(e); }
}
- public void windowRepaint(WindowUpdateEvent e) {
+ @Override
+ public void windowRepaint(final WindowUpdateEvent e) {
System.err.println(e);
if(null!=downstream) { downstream.windowRepaint(e); }
}
diff --git a/src/newt/classes/com/jogamp/newt/event/WindowAdapter.java b/src/newt/classes/com/jogamp/newt/event/WindowAdapter.java
index b9e487e9b..c1bae40ea 100644
--- a/src/newt/classes/com/jogamp/newt/event/WindowAdapter.java
+++ b/src/newt/classes/com/jogamp/newt/event/WindowAdapter.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,28 +20,35 @@
* 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 com.jogamp.newt.event;
public abstract class WindowAdapter implements WindowListener
{
- public void windowResized(WindowEvent e) {
+ @Override
+ public void windowResized(final WindowEvent e) {
}
- public void windowMoved(WindowEvent e) {
+ @Override
+ public void windowMoved(final WindowEvent e) {
}
- public void windowDestroyNotify(WindowEvent e) {
+ @Override
+ public void windowDestroyNotify(final WindowEvent e) {
}
- public void windowDestroyed(WindowEvent e) {
+ @Override
+ public void windowDestroyed(final WindowEvent e) {
}
- public void windowGainedFocus(WindowEvent e) {
+ @Override
+ public void windowGainedFocus(final WindowEvent e) {
}
- public void windowLostFocus(WindowEvent e) {
+ @Override
+ public void windowLostFocus(final WindowEvent e) {
}
- public void windowRepaint(WindowUpdateEvent e) {
+ @Override
+ public void windowRepaint(final WindowUpdateEvent e) {
}
}
diff --git a/src/newt/classes/com/jogamp/newt/event/WindowEvent.java b/src/newt/classes/com/jogamp/newt/event/WindowEvent.java
index 163b51439..021bd6cae 100644
--- a/src/newt/classes/com/jogamp/newt/event/WindowEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/WindowEvent.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package com.jogamp.newt.event;
@@ -41,19 +41,19 @@ package com.jogamp.newt.event;
*/
@SuppressWarnings("serial")
public class WindowEvent extends NEWTEvent {
- public static final int EVENT_WINDOW_RESIZED = 100;
- public static final int EVENT_WINDOW_MOVED = 101;
- public static final int EVENT_WINDOW_DESTROY_NOTIFY = 102;
- public static final int EVENT_WINDOW_GAINED_FOCUS = 103;
- public static final int EVENT_WINDOW_LOST_FOCUS = 104;
- public static final int EVENT_WINDOW_REPAINT = 105;
- public static final int EVENT_WINDOW_DESTROYED = 106;
+ public static final short EVENT_WINDOW_RESIZED = 100;
+ public static final short EVENT_WINDOW_MOVED = 101;
+ public static final short EVENT_WINDOW_DESTROY_NOTIFY = 102;
+ public static final short EVENT_WINDOW_GAINED_FOCUS = 103;
+ public static final short EVENT_WINDOW_LOST_FOCUS = 104;
+ public static final short EVENT_WINDOW_REPAINT = 105;
+ public static final short EVENT_WINDOW_DESTROYED = 106;
- public WindowEvent(int eventType, Object source, long when) {
+ public WindowEvent(final short eventType, final Object source, final long when) {
super(eventType, source, when);
}
- public static String getEventTypeString(int type) {
+ public static String getEventTypeString(final short type) {
switch(type) {
case EVENT_WINDOW_RESIZED: return "WINDOW_RESIZED";
case EVENT_WINDOW_MOVED: return "WINDOW_MOVED";
@@ -65,11 +65,13 @@ public class WindowEvent extends NEWTEvent {
default: return "unknown (" + type + ")";
}
}
-
+
+ @Override
public String toString() {
return toString(null).toString();
}
+ @Override
public StringBuilder toString(StringBuilder sb) {
if(null == sb) {
sb = new StringBuilder();
diff --git a/src/newt/classes/com/jogamp/newt/event/WindowListener.java b/src/newt/classes/com/jogamp/newt/event/WindowListener.java
index e841a06cf..e097edf23 100644
--- a/src/newt/classes/com/jogamp/newt/event/WindowListener.java
+++ b/src/newt/classes/com/jogamp/newt/event/WindowListener.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,11 +29,14 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package com.jogamp.newt.event;
+import javax.media.nativewindow.WindowClosingProtocol;
+
+/** NEWT {@link WindowEvent} listener. */
public interface WindowListener extends NEWTEventListener {
/** Window is resized, your application shall respect the new window dimension. A repaint is recommended. */
public void windowResized(WindowEvent e);
@@ -41,10 +44,19 @@ public interface WindowListener extends NEWTEventListener {
/** Window has been moved. */
public void windowMoved(WindowEvent e);
- /** Window will be destroyed. Release of resources is recommended. */
+ /**
+ * Window destruction has been requested.
+ * <p>
+ * Depending on the {@link WindowClosingProtocol#getDefaultCloseOperation() default close operation},
+ * the window maybe destroyed or not.
+ * </p>
+ * In case the window will be destroyed (see above), release of resources is recommended.
+ **/
public void windowDestroyNotify(WindowEvent e);
- /** Window has been destroyed.*/
+ /**
+ * Window has been destroyed.
+ */
public void windowDestroyed(WindowEvent e);
/** Window gained focus. */
diff --git a/src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java b/src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java
index e3f0373ec..4a5fecd83 100644
--- a/src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,12 +20,12 @@
* 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 com.jogamp.newt.event;
import javax.media.nativewindow.util.Rectangle;
@@ -34,7 +34,7 @@ import javax.media.nativewindow.util.Rectangle;
public class WindowUpdateEvent extends WindowEvent {
final Rectangle bounds;
- public WindowUpdateEvent(int eventType, Object source, long when, Rectangle bounds)
+ public WindowUpdateEvent(final short eventType, final Object source, final long when, final Rectangle bounds)
{
super(eventType, source, when);
this.bounds = bounds;
@@ -44,10 +44,12 @@ public class WindowUpdateEvent extends WindowEvent {
return bounds;
}
+ @Override
public String toString() {
return toString(null).toString();
}
+ @Override
public StringBuilder toString(StringBuilder sb) {
if(null == sb) {
sb = new StringBuilder();
diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java
index 8991203d5..a49c10a1e 100644
--- a/src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java
+++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,14 +20,16 @@
* 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 com.jogamp.newt.event.awt;
+import javax.media.nativewindow.NativeSurfaceHolder;
+
import jogamp.newt.Debug;
/**
@@ -48,10 +50,10 @@ import jogamp.newt.Debug;
* Common:<br>
* <pre>
// your demo/render code
- javax.media.opengl.GLEvenListener demo1 = new javax.media.opengl.GLEvenListener() { ... } ;
+ javax.media.opengl.GLEvenListener demo1 = new javax.media.opengl.GLEvenListener() { ... } ;
// your AWT agnostic NEWT mouse listener code
- com.jogamp.newt.event.MouseListener mouseListener = new com.jogamp.newt.event.MouseAdapter() { ... } ;
+ com.jogamp.newt.event.MouseListener mouseListener = new com.jogamp.newt.event.MouseAdapter() { ... } ;
* </pre> </p>
* <p>
* Default NEWT use case, without using the AWTAdapter:<br>
@@ -96,7 +98,7 @@ import jogamp.newt.Debug;
<br>
new AWTMouseAdapter(mouseListener, glWindow).addTo(comp);<br>
* </pre> </p>
- *
+ *
* Last but not least, the AWTAdapter maybe used as a general AWT event forwarder to NEWT.<br>
*
* <p>
@@ -108,7 +110,7 @@ import jogamp.newt.Debug;
<br>
new AWTMouseAdapter(glWindow).addTo(comp); // forward all AWT events to glWindow, as NEWT events<br>
* </pre> </p>
- *
+ *
* @see #attachTo
*/
public abstract class AWTAdapter implements java.util.EventListener
@@ -117,60 +119,138 @@ public abstract class AWTAdapter implements java.util.EventListener
com.jogamp.newt.event.NEWTEventListener newtListener;
com.jogamp.newt.Window newtWindow;
+ NativeSurfaceHolder nsHolder;
+ boolean consumeAWTEvent;
+ protected boolean isSetup;
- /**
- * Simply wrap aroung a NEWT EventListener, exposed as an AWT EventListener.<br>
+ /**
+ * Create a proxy adapter, wrapping around an NEWT EventListener, exposed as an AWT EventListener,<br>
+ * where the given {@link NativeSurfaceHolder} impersonates the event's source.
* The NEWT EventListener will be called when an event happens.<br>
*/
- public AWTAdapter(com.jogamp.newt.event.NEWTEventListener newtListener) {
+ protected AWTAdapter(final com.jogamp.newt.event.NEWTEventListener newtListener, final NativeSurfaceHolder nsProxy) {
if(null==newtListener) {
- throw new RuntimeException("Argument newtListener is null");
+ throw new IllegalArgumentException("Argument newtListener is null");
+ }
+ if(null==nsProxy) {
+ throw new IllegalArgumentException("Argument nwProxy is null");
}
this.newtListener = newtListener;
this.newtWindow = null;
+ this.nsHolder = nsProxy;
+ this.consumeAWTEvent = false;
+ this.isSetup = true;
}
- /**
- * Wrap aroung a NEWT EventListener, exposed as an AWT EventListener,<br>
- * where the given NEWT Window impersonates as the event's source.
+ /**
+ * Create a proxy adapter, wrapping around an NEWT EventListener, exposed as an AWT EventListener,<br>
+ * where the given {@link com.jogamp.newt.Window NEWT Window}, a {@link NativeSurfaceHolder}, impersonates the event's source.
* The NEWT EventListener will be called when an event happens.<br>
*/
- public AWTAdapter(com.jogamp.newt.event.NEWTEventListener newtListener, com.jogamp.newt.Window newtProxy) {
+ protected AWTAdapter(final com.jogamp.newt.event.NEWTEventListener newtListener, final com.jogamp.newt.Window newtProxy) {
if(null==newtListener) {
- throw new RuntimeException("Argument newtListener is null");
+ throw new IllegalArgumentException("Argument newtListener is null");
}
if(null==newtProxy) {
- throw new RuntimeException("Argument newtProxy is null");
+ throw new IllegalArgumentException("Argument newtProxy is null");
}
this.newtListener = newtListener;
this.newtWindow = newtProxy;
+ this.nsHolder = newtProxy;
+ this.consumeAWTEvent = false;
+ this.isSetup = true;
}
- /**
+ /**
* Create a pipeline adapter, AWT EventListener.<br>
* Once attached to an AWT component, it sends the converted AWT events to the NEWT downstream window.<br>
* This is only supported with EDT enabled!
+ * @throws IllegalStateException if EDT is not enabled
*/
- public AWTAdapter(com.jogamp.newt.Window downstream) {
+ protected AWTAdapter(final com.jogamp.newt.Window downstream) throws IllegalStateException {
+ this();
+ setDownstream(downstream);
+ }
+
+ public AWTAdapter() {
+ clear();
+ this.consumeAWTEvent = false;
+ }
+
+ /**
+ * Setup a pipeline adapter, AWT EventListener.<br>
+ * Once attached to an AWT component, it sends the converted AWT events to the NEWT downstream window.<br>
+ * This is only supported with EDT enabled!
+ * @throws IllegalStateException if EDT is not enabled
+ */
+ public synchronized AWTAdapter setDownstream(final com.jogamp.newt.Window downstream) throws IllegalStateException {
if(null==downstream) {
throw new RuntimeException("Argument downstream is null");
}
this.newtListener = null;
this.newtWindow = downstream;
+ this.nsHolder = downstream;
if( null == newtWindow.getScreen().getDisplay().getEDTUtil() ) {
- throw new RuntimeException("EDT not enabled");
+ throw new IllegalStateException("EDT not enabled");
}
+ this.isSetup = true;
+ return this;
+ }
+
+ /**
+ * Removes all references, downstream and NEWT-EventListener.
+ * <p>
+ * Also sets the internal <code>setup</code> flag and {@link #setConsumeAWTEvent(boolean)} to <code>false</code>.
+ * </p>
+ */
+ public synchronized AWTAdapter clear() {
+ this.newtListener = null;
+ this.newtWindow = null;
+ this.nsHolder = null;
+ this.isSetup = false;
+ this.consumeAWTEvent = false;
+ return this;
+ }
+
+ public final synchronized void setConsumeAWTEvent(final boolean v) {
+ this.consumeAWTEvent = v;
}
- public final com.jogamp.newt.Window getNewtWindow() {
- return newtWindow;
+ /**
+ * Returns the {@link NativeSurfaceHolder} acting {@link #AWTAdapter(com.jogamp.newt.Window) as downstream},
+ * {@link #AWTAdapter(com.jogamp.newt.event.NEWTEventListener, com.jogamp.newt.Window) NEWT window proxy}
+ * or as an {@link #AWTAdapter(com.jogamp.newt.event.NEWTEventListener, NativeSurfaceHolder) NativeSurfaceHolder proxy}.
+ * <p>
+ * Returned value is never null.
+ * </p>
+ */
+ public final synchronized NativeSurfaceHolder getNativeSurfaceHolder() {
+ return nsHolder;
+ }
+
+ /**
+ * Returns the {@link com.jogamp.newt.Window NEWT Window} acting {@link #AWTAdapter(com.jogamp.newt.Window) as downstream}
+ * or as a {@link #AWTAdapter(com.jogamp.newt.event.NEWTEventListener, com.jogamp.newt.Window) NEWT window proxy}.
+ * <p>
+ * Returned value maybe null if instance is used to be a
+ * {@link #AWTAdapter(com.jogamp.newt.event.NEWTEventListener, NativeSurfaceHolder) NativeSurfaceHolder proxy}.
+ * </p>
+ */
+ public final synchronized com.jogamp.newt.Window getNewtWindow() {
+ return newtWindow;
}
-
- public final com.jogamp.newt.event.NEWTEventListener getNewtEventListener() {
- return newtListener;
+
+ /**
+ * Returns the {@link com.jogamp.newt.event.NEWTEventListener NEWT event-listener} if instance
+ * is used as an {@link #AWTAdapter(com.jogamp.newt.event.NEWTEventListener, NativeSurfaceHolder) NativeSurfaceHolder proxy}
+ * or {@link #AWTAdapter(com.jogamp.newt.event.NEWTEventListener, com.jogamp.newt.Window) NEWT window proxy},
+ * otherwise method returns <code>null</code>.
+ */
+ public final synchronized com.jogamp.newt.event.NEWTEventListener getNewtEventListener() {
+ return newtListener;
}
-
- /**
+
+ /**
* Due to the fact that some NEWT {@link com.jogamp.newt.event.NEWTEventListener}
* are mapped to more than one {@link java.util.EventListener},
* this method is for your convenience to use this Adapter as a listener for all types.<br>
@@ -181,8 +261,46 @@ public abstract class AWTAdapter implements java.util.EventListener
/** @see #addTo(java.awt.Component) */
public abstract AWTAdapter removeFrom(java.awt.Component awtComponent);
- void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) {
- newtWindow.enqueueEvent(wait, event);
+ /**
+ * Return value for {@link AWTAdapter#processEvent(boolean, com.jogamp.newt.event.NEWTEvent) event processing}.
+ */
+ static enum EventProcRes {
+ /** Event shall be dispatched appropriately */
+ DISPATCH,
+ /** Event has been enqueued */
+ ENQUEUED,
+ /** No known processing method applies */
+ NOP
+ }
+
+ /**
+ * Process the event.
+ * <p>
+ * If {@link #getNewtEventListener()} is not <code>null</code>,
+ * {@link EventProcRes#DISPATCH DISPATCH} is returned and caller shall dispatch the event appropriately.
+ * </p>
+ * <p>
+ * If {@link #getNewtWindow()} is not <code>null</code>,
+ * {@link EventProcRes#ENQUEUED ENQUEUED} is returned and the event has been {@link com.jogamp.newt.Window#enqueueEvent(boolean, com.jogamp.newt.event.NEWTEvent) enqueued already}.
+ * </p>
+ * <p>
+ * If none of the above matches, {@link EventProcRes#NOP NOP} is returned and none of the above processing method applies.
+ * </p>
+ *
+ * @param wait In case the event will be {@link EventProcRes#ENQUEUED ENQUEUED},
+ * passing <code>true</code> will block until the event has been processed, otherwise method returns immediately.
+ * @param event The {@link com.jogamp.newt.event.NEWTEvent event} to enqueue.
+ * @return One of the {@link EventProcRes} values, see above.
+ */
+ EventProcRes processEvent(final boolean wait, final com.jogamp.newt.event.NEWTEvent event) {
+ if(null != newtListener) {
+ return EventProcRes.DISPATCH;
+ }
+ if( null != newtWindow ) {
+ newtWindow.enqueueEvent(wait, event);
+ return EventProcRes.ENQUEUED;
+ }
+ return EventProcRes.NOP;
}
}
diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java
index 7b0f6ba97..4f11e8772 100644
--- a/src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java
+++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,64 +20,82 @@
* 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 com.jogamp.newt.event.awt;
+import javax.media.nativewindow.NativeSurfaceHolder;
+
import jogamp.newt.awt.event.AWTNewtEventFactory;
+/**
+ * AWT:
+ * printable: PRESSED (t0), TYPED (t0), RELEASED (t1)
+ * non-printable: PRESSED (t0), RELEASED (t1)
+ */
public class AWTKeyAdapter extends AWTAdapter implements java.awt.event.KeyListener
{
- public AWTKeyAdapter(com.jogamp.newt.event.KeyListener newtListener) {
- super(newtListener);
+ public AWTKeyAdapter(final com.jogamp.newt.event.KeyListener newtListener, final NativeSurfaceHolder nsProxy) {
+ super(newtListener, nsProxy);
}
- public AWTKeyAdapter(com.jogamp.newt.event.KeyListener newtListener, com.jogamp.newt.Window newtProxy) {
+ public AWTKeyAdapter(final com.jogamp.newt.event.KeyListener newtListener, final com.jogamp.newt.Window newtProxy) {
super(newtListener, newtProxy);
}
- public AWTKeyAdapter(com.jogamp.newt.Window downstream) {
+ public AWTKeyAdapter(final com.jogamp.newt.Window downstream) {
super(downstream);
}
- public AWTAdapter addTo(java.awt.Component awtComponent) {
+ public AWTKeyAdapter() {
+ super();
+ }
+
+ @Override
+ public synchronized AWTAdapter addTo(final java.awt.Component awtComponent) {
awtComponent.addKeyListener(this);
return this;
}
- public AWTAdapter removeFrom(java.awt.Component awtComponent) {
+ @Override
+ public synchronized AWTAdapter removeFrom(final java.awt.Component awtComponent) {
awtComponent.removeKeyListener(this);
return this;
}
- public void keyPressed(java.awt.event.KeyEvent e) {
- com.jogamp.newt.event.KeyEvent event = AWTNewtEventFactory.createKeyEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void keyPressed(final java.awt.event.KeyEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.KeyEvent event = AWTNewtEventFactory.createKeyEvent(com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED, e, nsHolder);
+ if( consumeAWTEvent ) {
+ e.consume();
+ }
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.KeyListener)newtListener).keyPressed(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void keyReleased(java.awt.event.KeyEvent e) {
- com.jogamp.newt.event.KeyEvent event = AWTNewtEventFactory.createKeyEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void keyReleased(final java.awt.event.KeyEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.KeyEvent event = AWTNewtEventFactory.createKeyEvent(com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED, e, nsHolder);
+ if( consumeAWTEvent ) {
+ e.consume();
+ }
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.KeyListener)newtListener).keyReleased(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void keyTyped(java.awt.event.KeyEvent e) {
- com.jogamp.newt.event.KeyEvent event = AWTNewtEventFactory.createKeyEvent(e, newtWindow);
- if(null!=newtListener) {
- ((com.jogamp.newt.event.KeyListener)newtListener).keyTyped(event);
- } else {
- enqueueEvent(false, event);
+ @Override
+ public synchronized void keyTyped(final java.awt.event.KeyEvent e) {
+ if( !isSetup ) { return; }
+ if( consumeAWTEvent ) {
+ e.consume();
}
}
}
diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java
index 115743a0d..d9531cd5f 100644
--- a/src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java
+++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,115 +20,147 @@
* 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 com.jogamp.newt.event.awt;
+import javax.media.nativewindow.NativeSurfaceHolder;
+
import jogamp.newt.awt.event.AWTNewtEventFactory;
-public class AWTMouseAdapter extends AWTAdapter implements java.awt.event.MouseListener,
+public class AWTMouseAdapter extends AWTAdapter implements java.awt.event.MouseListener,
java.awt.event.MouseMotionListener,
java.awt.event.MouseWheelListener
{
- public AWTMouseAdapter(com.jogamp.newt.event.MouseListener newtListener) {
- super(newtListener);
+ public AWTMouseAdapter(final com.jogamp.newt.event.MouseListener newtListener, final NativeSurfaceHolder nsProxy) {
+ super(newtListener, nsProxy);
}
- public AWTMouseAdapter(com.jogamp.newt.event.MouseListener newtListener, com.jogamp.newt.Window newtProxy) {
+ public AWTMouseAdapter(final com.jogamp.newt.event.MouseListener newtListener, final com.jogamp.newt.Window newtProxy) {
super(newtListener, newtProxy);
}
- public AWTMouseAdapter(com.jogamp.newt.Window downstream) {
+ public AWTMouseAdapter(final com.jogamp.newt.Window downstream) {
super(downstream);
}
- public AWTAdapter addTo(java.awt.Component awtComponent) {
+ public AWTMouseAdapter() {
+ super();
+ }
+
+ @Override
+ public synchronized AWTAdapter addTo(final java.awt.Component awtComponent) {
awtComponent.addMouseListener(this);
awtComponent.addMouseMotionListener(this);
awtComponent.addMouseWheelListener(this);
return this;
}
- public AWTAdapter removeFrom(java.awt.Component awtComponent) {
+ @Override
+ public synchronized AWTAdapter removeFrom(final java.awt.Component awtComponent) {
awtComponent.removeMouseListener(this);
awtComponent.removeMouseMotionListener(this);
awtComponent.removeMouseWheelListener(this);
return this;
}
- public void mouseClicked(java.awt.event.MouseEvent e) {
- com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void mouseClicked(final java.awt.event.MouseEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, nsHolder);
+ if( consumeAWTEvent ) {
+ e.consume();
+ }
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.MouseListener)newtListener).mouseClicked(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void mouseEntered(java.awt.event.MouseEvent e) {
- com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void mouseEntered(final java.awt.event.MouseEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, nsHolder);
+ if( consumeAWTEvent ) {
+ e.consume();
+ }
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.MouseListener)newtListener).mouseEntered(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void mouseExited(java.awt.event.MouseEvent e) {
- com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void mouseExited(final java.awt.event.MouseEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, nsHolder);
+ if( consumeAWTEvent ) {
+ e.consume();
+ }
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.MouseListener)newtListener).mouseExited(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void mousePressed(java.awt.event.MouseEvent e) {
- com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void mousePressed(final java.awt.event.MouseEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, nsHolder);
+ if( consumeAWTEvent ) {
+ e.consume();
+ }
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.MouseListener)newtListener).mousePressed(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void mouseReleased(java.awt.event.MouseEvent e) {
- com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void mouseReleased(final java.awt.event.MouseEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, nsHolder);
+ if( consumeAWTEvent ) {
+ e.consume();
+ }
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.MouseListener)newtListener).mouseReleased(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void mouseDragged(java.awt.event.MouseEvent e) {
- com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void mouseDragged(final java.awt.event.MouseEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, nsHolder);
+ if( consumeAWTEvent ) {
+ e.consume();
+ }
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.MouseListener)newtListener).mouseDragged(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void mouseMoved(java.awt.event.MouseEvent e) {
- com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void mouseMoved(final java.awt.event.MouseEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, nsHolder);
+ if( consumeAWTEvent ) {
+ e.consume();
+ }
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.MouseListener)newtListener).mouseMoved(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void mouseWheelMoved(java.awt.event.MouseWheelEvent e) {
- com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void mouseWheelMoved(final java.awt.event.MouseWheelEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, nsHolder);
+ if( consumeAWTEvent ) {
+ e.consume();
+ }
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.MouseListener)newtListener).mouseWheelMoved(event);
- } else {
- enqueueEvent(false, event);
}
}
}
diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java
index 2d63ca455..a8105403d 100644
--- a/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java
+++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,59 +20,70 @@
* 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 com.jogamp.newt.event.awt;
import java.awt.Dimension;
+import javax.media.nativewindow.NativeSurfaceHolder;
+
import jogamp.newt.awt.event.AWTNewtEventFactory;
-public class AWTWindowAdapter
- extends AWTAdapter
+public class AWTWindowAdapter
+ extends AWTAdapter
implements java.awt.event.ComponentListener, java.awt.event.WindowListener, java.awt.event.FocusListener
{
WindowClosingListener windowClosingListener;
- public AWTWindowAdapter(com.jogamp.newt.event.WindowListener newtListener) {
- super(newtListener);
+ public AWTWindowAdapter(final com.jogamp.newt.event.WindowListener newtListener, final NativeSurfaceHolder nsProxy) {
+ super(newtListener, nsProxy);
}
- public AWTWindowAdapter(com.jogamp.newt.event.WindowListener newtListener, com.jogamp.newt.Window newtProxy) {
+ public AWTWindowAdapter(final com.jogamp.newt.event.WindowListener newtListener, final com.jogamp.newt.Window newtProxy) {
super(newtListener, newtProxy);
}
- public AWTWindowAdapter(com.jogamp.newt.Window downstream) {
+ public AWTWindowAdapter(final com.jogamp.newt.Window downstream) {
super(downstream);
}
- public AWTAdapter addTo(java.awt.Component awtComponent) {
- java.awt.Window win = getWindow(awtComponent);
+ public AWTWindowAdapter() {
+ super();
+ }
+
+ @Override
+ public synchronized AWTAdapter addTo(final java.awt.Component awtComponent) {
+ final java.awt.Window win = getWindow(awtComponent);
awtComponent.addComponentListener(this);
awtComponent.addFocusListener(this);
- if( null == windowClosingListener ) {
+ if( null != win && null == windowClosingListener ) {
windowClosingListener = new WindowClosingListener();
- }
- if( null != win ) {
win.addWindowListener(windowClosingListener);
}
if(awtComponent instanceof java.awt.Window) {
((java.awt.Window)awtComponent).addWindowListener(this);
}
- return this;
+ return this;
}
-
- public AWTAdapter removeFrom(java.awt.Component awtComponent) {
- awtComponent.removeFocusListener(this);
- awtComponent.removeComponentListener(this);
- java.awt.Window win = getWindow(awtComponent);
+
+ public synchronized AWTAdapter removeWindowClosingFrom(final java.awt.Component awtComponent) {
+ final java.awt.Window win = getWindow(awtComponent);
if( null != win && null != windowClosingListener ) {
win.removeWindowListener(windowClosingListener);
}
+ return this;
+ }
+
+ @Override
+ public synchronized AWTAdapter removeFrom(final java.awt.Component awtComponent) {
+ awtComponent.removeFocusListener(this);
+ awtComponent.removeComponentListener(this);
+ removeWindowClosingFrom(awtComponent);
if(awtComponent instanceof java.awt.Window) {
((java.awt.Window)awtComponent).removeWindowListener(this);
}
@@ -83,38 +94,37 @@ public class AWTWindowAdapter
while( null != comp && !(comp instanceof java.awt.Window) ) {
comp = comp.getParent();
}
- if(comp instanceof java.awt.Window) {
- return (java.awt.Window) comp;
- }
- return null;
+ return (java.awt.Window) comp; // either null or a 'java.awt.Window'
}
- public void focusGained(java.awt.event.FocusEvent e) {
- com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow);
+ @Override
+ public synchronized void focusGained(final java.awt.event.FocusEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, nsHolder);
if(DEBUG_IMPLEMENTATION) {
System.err.println("AWT: focusGained: "+e+" -> "+event);
}
- if(null!=newtListener) {
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.WindowListener)newtListener).windowGainedFocus(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void focusLost(java.awt.event.FocusEvent e) {
- com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow);
+ @Override
+ public synchronized void focusLost(final java.awt.event.FocusEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, nsHolder);
if(DEBUG_IMPLEMENTATION) {
System.err.println("AWT: focusLost: "+e+" -> "+event);
}
- if(null!=newtListener) {
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.WindowListener)newtListener).windowLostFocus(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void componentResized(java.awt.event.ComponentEvent e) {
- com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow);
+ @Override
+ public synchronized void componentResized(final java.awt.event.ComponentEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, nsHolder);
if(DEBUG_IMPLEMENTATION) {
final java.awt.Component c = e.getComponent();
final java.awt.Dimension sz = c.getSize();
@@ -130,26 +140,26 @@ public class AWTWindowAdapter
}
System.err.println("AWT: componentResized: "+sz+" ( "+insets+", "+sz2+" ), "+e+" -> "+event);
}
- if(null!=newtListener) {
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.WindowListener)newtListener).windowResized(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void componentMoved(java.awt.event.ComponentEvent e) {
- com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow);
+ @Override
+ public synchronized void componentMoved(final java.awt.event.ComponentEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, nsHolder);
if(DEBUG_IMPLEMENTATION) {
System.err.println("AWT: componentMoved: "+e+" -> "+event);
}
- if(null!=newtListener) {
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.WindowListener)newtListener).windowMoved(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void componentShown(java.awt.event.ComponentEvent e) {
+ @Override
+ public synchronized void componentShown(final java.awt.event.ComponentEvent e) {
+ if( !isSetup ) { return; }
final java.awt.Component comp = e.getComponent();
if(DEBUG_IMPLEMENTATION) {
System.err.println("AWT: componentShown: "+comp);
@@ -166,7 +176,9 @@ public class AWTWindowAdapter
}*/
}
- public void componentHidden(java.awt.event.ComponentEvent e) {
+ @Override
+ public synchronized void componentHidden(final java.awt.event.ComponentEvent e) {
+ if( !isSetup ) { return; }
final java.awt.Component comp = e.getComponent();
if(DEBUG_IMPLEMENTATION) {
System.err.println("AWT: componentHidden: "+comp);
@@ -183,50 +195,71 @@ public class AWTWindowAdapter
}*/
}
- public void windowActivated(java.awt.event.WindowEvent e) {
- com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void windowActivated(final java.awt.event.WindowEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, nsHolder);
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.WindowListener)newtListener).windowGainedFocus(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void windowClosed(java.awt.event.WindowEvent e) { }
+ @Override
+ public synchronized void windowClosed(final java.awt.event.WindowEvent e) { }
- public void windowClosing(java.awt.event.WindowEvent e) { }
+ @Override
+ public synchronized void windowClosing(final java.awt.event.WindowEvent e) { }
- public void windowDeactivated(java.awt.event.WindowEvent e) {
- com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow);
- if(null!=newtListener) {
+ @Override
+ public synchronized void windowDeactivated(final java.awt.event.WindowEvent e) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, nsHolder);
+ if( EventProcRes.DISPATCH == processEvent(false, event) ) {
((com.jogamp.newt.event.WindowListener)newtListener).windowLostFocus(event);
- } else {
- enqueueEvent(false, event);
}
}
- public void windowDeiconified(java.awt.event.WindowEvent e) { }
+ @Override
+ public synchronized void windowDeiconified(final java.awt.event.WindowEvent e) { }
- public void windowIconified(java.awt.event.WindowEvent e) { }
+ @Override
+ public synchronized void windowIconified(final java.awt.event.WindowEvent e) { }
- public void windowOpened(java.awt.event.WindowEvent e) { }
+ @Override
+ public synchronized void windowOpened(final java.awt.event.WindowEvent e) { }
class WindowClosingListener implements java.awt.event.WindowListener {
- public void windowClosing(java.awt.event.WindowEvent e) {
- com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow);
- if(null!=newtListener) {
- ((com.jogamp.newt.event.WindowListener)newtListener).windowDestroyNotify(event);
- } else {
- enqueueEvent(true, event);
+ @Override
+ public void windowClosing(final java.awt.event.WindowEvent e) {
+ synchronized( AWTWindowAdapter.this ) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, nsHolder);
+ if( EventProcRes.DISPATCH == processEvent(true, event) ) {
+ ((com.jogamp.newt.event.WindowListener)newtListener).windowDestroyNotify(event);
+ }
+ }
+ }
+ @Override
+ public void windowClosed(final java.awt.event.WindowEvent e) {
+ synchronized( AWTWindowAdapter.this ) {
+ if( !isSetup ) { return; }
+ final com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, nsHolder);
+ if( EventProcRes.DISPATCH == processEvent(true, event) ) {
+ ((com.jogamp.newt.event.WindowListener)newtListener).windowDestroyed(event);
+ }
}
}
- public void windowActivated(java.awt.event.WindowEvent e) { }
- public void windowClosed(java.awt.event.WindowEvent e) { }
- public void windowDeactivated(java.awt.event.WindowEvent e) { }
- public void windowDeiconified(java.awt.event.WindowEvent e) { }
- public void windowIconified(java.awt.event.WindowEvent e) { }
- public void windowOpened(java.awt.event.WindowEvent e) { }
+ @Override
+ public void windowActivated(final java.awt.event.WindowEvent e) { }
+ @Override
+ public void windowDeactivated(final java.awt.event.WindowEvent e) { }
+ @Override
+ public void windowDeiconified(final java.awt.event.WindowEvent e) { }
+ @Override
+ public void windowIconified(final java.awt.event.WindowEvent e) { }
+ @Override
+ public void windowOpened(final java.awt.event.WindowEvent e) { }
}
}
diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
index a89ccaedb..2ba030f76 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
@@ -34,18 +34,24 @@
package com.jogamp.newt.opengl;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.List;
+
import javax.media.nativewindow.AbstractGraphicsConfiguration;
import javax.media.nativewindow.CapabilitiesChooser;
import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.NativeWindowException;
-import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.SurfaceUpdatedListener;
import javax.media.nativewindow.util.InsetsImmutable;
import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.util.Rectangle;
import javax.media.opengl.FPSCounter;
import javax.media.opengl.GL;
+import javax.media.opengl.GL3;
+import javax.media.opengl.GL4ES3;
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
@@ -53,9 +59,13 @@ import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLES2;
+import javax.media.opengl.GLES3;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
+import javax.media.opengl.GLRunnable;
+import javax.media.opengl.GLSharedContextSetter;
import jogamp.newt.WindowImpl;
import jogamp.opengl.GLAutoDrawableBase;
@@ -65,30 +75,45 @@ import jogamp.opengl.GLDrawableImpl;
import com.jogamp.common.GlueGenVersion;
import com.jogamp.common.util.VersionUtil;
import com.jogamp.common.util.locks.RecursiveLock;
+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;
import com.jogamp.newt.event.NEWTEvent;
import com.jogamp.newt.event.NEWTEventConsumer;
+import com.jogamp.newt.event.NEWTEventListener;
import com.jogamp.newt.event.WindowAdapter;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.event.WindowListener;
import com.jogamp.newt.event.WindowUpdateEvent;
import com.jogamp.opengl.JoglVersion;
+import com.jogamp.opengl.GLStateKeeper;
/**
* An implementation of {@link GLAutoDrawable} and {@link Window} interface,
* using a delegated {@link Window} instance, which may be an aggregation (lifecycle: created and destroyed).
* <P>
+ * This implementation supports {@link GLStateKeeper GL state preservation},
+ * hence {@link #isGLStatePreservationSupported()} returns <code>true</code>.
+ * </P>
+ * <P>
* This implementation does not make the OpenGL context current<br>
- * before calling the various input EventListener callbacks, ie {@link com.jogamp.newt.event.MouseListener} etc.<br>
+ * before calling the various input EventListener callbacks, ie {@link MouseListener} etc.<br>
* This design decision is made in favor of a more performant and simplified
* implementation. Also the event dispatcher shall be implemented OpenGL agnostic.<br>
- * To be able to use OpenGL commands from within such input {@link com.jogamp.newt.event.NEWTEventListener},<br>
- * you can inject {@link javax.media.opengl.GLRunnable} objects
- * via {@link #invoke(boolean, javax.media.opengl.GLRunnable)} to the OpenGL command stream.<br>
+ * To be able to use OpenGL commands from within such input {@link NEWTEventListener},<br>
+ * you can inject {@link GLRunnable} objects
+ * via {@link #invoke(boolean, GLRunnable)} to the OpenGL command stream.<br>
+ * </p>
+ * <p>
+ * <a name="contextSharing"><h5>OpenGL Context Sharing</h5></a>
+ * To share a {@link GLContext} see the following note in the documentation overview:
+ * <a href="../../../../overview-summary.html#SHARING">context sharing</a>
+ * as well as {@link GLSharedContextSetter}.
* </p>
*/
public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Window, NEWTEventConsumer, FPSCounter {
@@ -97,25 +122,25 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
/**
* Constructor. Do not call this directly -- use {@link #create()} instead.
*/
- protected GLWindow(Window window) {
+ protected GLWindow(final Window window) {
super(null, null, false /* always handle device lifecycle ourselves */);
this.window = (WindowImpl) window;
- this.window.setHandleDestroyNotify(false);
+ this.window.setWindowDestroyNotifyAction( new Runnable() {
+ @Override
+ public void run() {
+ defaultWindowDestroyNotifyOp();
+ } } );
window.addWindowListener(new WindowAdapter() {
@Override
- public void windowRepaint(WindowUpdateEvent e) {
+ public void windowRepaint(final WindowUpdateEvent e) {
defaultWindowRepaintOp();
}
@Override
- public void windowResized(WindowEvent e) {
- defaultWindowResizedOp(getWidth(), getHeight());
+ public void windowResized(final WindowEvent e) {
+ defaultWindowResizedOp(getSurfaceWidth(), getSurfaceHeight());
}
- @Override
- public void windowDestroyNotify(WindowEvent e) {
- defaultWindowDestroyNotifyOp();
- }
});
this.window.setLifecycleHook(new GLLifecycleHook());
}
@@ -124,7 +149,12 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
public final Object getUpstreamWidget() {
return window;
}
-
+
+ @Override
+ public final RecursiveLock getUpstreamLock() {
+ return window.getLock();
+ }
+
/**
* Creates a new GLWindow attaching a new Window referencing a
* new default Screen and default Display with the given GLCapabilities.
@@ -134,7 +164,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
* </p>
* The default Display will be reused if already instantiated.
*/
- public static GLWindow create(GLCapabilitiesImmutable caps) {
+ public static GLWindow create(final GLCapabilitiesImmutable caps) {
return new GLWindow(NewtFactory.createWindow(caps));
}
@@ -146,7 +176,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
* and {@link Screen#removeReference()}.
* </p>
*/
- public static GLWindow create(Screen screen, GLCapabilitiesImmutable caps) {
+ public static GLWindow create(final Screen screen, final GLCapabilitiesImmutable caps) {
return new GLWindow(NewtFactory.createWindow(screen, caps));
}
@@ -157,7 +187,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
* and {@link Screen#removeReference()}.
* </p>
*/
- public static GLWindow create(Window window) {
+ public static GLWindow create(final Window window) {
return new GLWindow(window);
}
@@ -174,7 +204,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
* and {@link Screen#removeReference()}.
* </p>
*/
- public static GLWindow create(NativeWindow parentNativeWindow, GLCapabilitiesImmutable caps) {
+ public static GLWindow create(final NativeWindow parentNativeWindow, final GLCapabilitiesImmutable caps) {
return new GLWindow(NewtFactory.createWindow(parentNativeWindow, caps));
}
@@ -187,7 +217,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public WindowClosingMode setDefaultCloseOperation(WindowClosingMode op) {
+ public WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) {
return window.setDefaultCloseOperation(op);
}
@@ -196,14 +226,14 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
//
@Override
- public CapabilitiesChooser setCapabilitiesChooser(CapabilitiesChooser chooser) {
+ public CapabilitiesChooser setCapabilitiesChooser(final CapabilitiesChooser chooser) {
return window.setCapabilitiesChooser(chooser);
}
@Override
public final CapabilitiesImmutable getChosenCapabilities() {
final GLDrawable _drawable = drawable;
- return null != _drawable ? _drawable.getChosenGLCapabilities() : window.getChosenCapabilities();
+ return null != _drawable ? _drawable.getChosenGLCapabilities() : window.getChosenCapabilities();
}
@Override
@@ -227,7 +257,12 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public final void setTitle(String title) {
+ public final MonitorDevice getMainMonitor() {
+ return window.getMainMonitor();
+ }
+
+ @Override
+ public final void setTitle(final String title) {
window.setTitle(title);
}
@@ -242,27 +277,37 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public final void setPointerVisible(boolean mouseVisible) {
+ public final void setPointerVisible(final boolean mouseVisible) {
window.setPointerVisible(mouseVisible);
}
@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();
}
@Override
- public final void confinePointer(boolean grab) {
+ public final void confinePointer(final boolean grab) {
window.confinePointer(grab);
}
@Override
- public final void setUndecorated(boolean value) {
+ public final void setUndecorated(final boolean value) {
window.setUndecorated(value);
}
@Override
- public final void warpPointer(int x, int y) {
+ public final void warpPointer(final int x, final int y) {
window.warpPointer(x, y);
}
@Override
@@ -271,7 +316,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public final void setAlwaysOnTop(boolean value) {
+ public final void setAlwaysOnTop(final boolean value) {
window.setAlwaysOnTop(value);
}
@@ -281,12 +326,12 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public final void setFocusAction(FocusRunnable focusAction) {
+ public final void setFocusAction(final FocusRunnable focusAction) {
window.setFocusAction(focusAction);
}
@Override
- public void setKeyboardFocusHandler(KeyListener l) {
+ public void setKeyboardFocusHandler(final KeyListener l) {
window.setKeyboardFocusHandler(l);
}
@@ -296,7 +341,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public final void requestFocus(boolean wait) {
+ public final void requestFocus(final boolean wait) {
window.requestFocus(wait);
}
@@ -319,7 +364,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
public final int getY() {
return window.getY();
}
-
+
@Override
public final int getWidth() {
return window.getWidth();
@@ -329,22 +374,77 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
public final int getHeight() {
return window.getHeight();
}
-
+
+ @Override
+ public final Rectangle getBounds() {
+ return window.getBounds();
+ }
+
+ @Override
+ public final int getSurfaceWidth() {
+ return window.getSurfaceWidth();
+ }
+
+ @Override
+ public final int getSurfaceHeight() {
+ return window.getSurfaceHeight();
+ }
+
+ @Override
+ public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) {
+ return window.convertToWindowUnits(pixelUnitsAndResult);
+ }
+
+ @Override
+ public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) {
+ return window.convertToPixelUnits(windowUnitsAndResult);
+ }
+
+ @Override
+ public final void setSurfaceScale(final int[] pixelScale) {
+ window.setSurfaceScale(pixelScale);
+ }
+
+ @Override
+ public final int[] getRequestedSurfaceScale(final int[] result) {
+ return window.getRequestedSurfaceScale(result);
+ }
+
+ @Override
+ public final int[] getCurrentSurfaceScale(final int[] result) {
+ return window.getCurrentSurfaceScale(result);
+ }
+
+ @Override
+ public final int[] getNativeSurfaceScale(final int[] result) {
+ return window.getNativeSurfaceScale(result);
+ }
+
@Override
- public final void setPosition(int x, int y) {
+ public final float[] getPixelsPerMM(final float[] ppmmStore) {
+ return window.getPixelsPerMM(ppmmStore);
+ }
+
+ @Override
+ public final void setPosition(final int x, final int y) {
window.setPosition(x, y);
}
@Override
- public void setTopLevelPosition(int x, int y) {
+ public void setTopLevelPosition(final int x, final int y) {
window.setTopLevelPosition(x, y);
}
@Override
- public final boolean setFullscreen(boolean fullscreen) {
+ public final boolean setFullscreen(final boolean fullscreen) {
return window.setFullscreen(fullscreen);
}
@Override
+ public boolean setFullscreen(final List<MonitorDevice> monitors) {
+ return window.setFullscreen(monitors);
+ }
+
+ @Override
public final boolean isFullscreen() {
return window.isFullscreen();
}
@@ -361,22 +461,17 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public final ReparentOperation reparentWindow(NativeWindow newParent) {
- return window.reparentWindow(newParent);
+ public final ReparentOperation reparentWindow(final NativeWindow newParent, final int x, final int y, final int hints) {
+ return window.reparentWindow(newParent, x, y, hints);
}
@Override
- public final ReparentOperation reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) {
- return window.reparentWindow(newParent, forceDestroyCreate);
- }
-
- @Override
- public final boolean removeChild(NativeWindow win) {
+ public final boolean removeChild(final NativeWindow win) {
return window.removeChild(win);
}
@Override
- public final boolean addChild(NativeWindow win) {
+ public final boolean addChild(final NativeWindow win) {
return window.addChild(win);
}
@@ -390,16 +485,30 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public final void setVisible(boolean visible) {
+ public void setWindowDestroyNotifyAction(final Runnable r) {
+ window.setWindowDestroyNotifyAction(r);
+ }
+
+ @Override
+ public final void setVisible(final boolean visible) {
window.setVisible(visible);
}
@Override
- public final void setSize(int width, int height) {
+ public void setVisible(final boolean wait, final boolean visible) {
+ window.setVisible(wait, visible);
+ }
+
+ @Override
+ public final void setSize(final int width, final int height) {
window.setSize(width, height);
}
@Override
- public void setTopLevelSize(int width, int height) {
+ public final void setSurfaceSize(final int pixelWidth, final int pixelHeight) {
+ window.setSurfaceSize(pixelWidth, pixelHeight);
+ }
+ @Override
+ public void setTopLevelSize(final int width, final int height) {
window.setTopLevelSize(width, height);
}
@@ -409,7 +518,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public Point getLocationOnScreen(Point storage) {
+ public Point getLocationOnScreen(final Point storage) {
return window.getLocationOnScreen(storage);
}
@@ -417,6 +526,11 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
protected class GLLifecycleHook implements WindowImpl.LifecycleHook {
@Override
+ public void preserveGLStateAtDestroy(final boolean value) {
+ GLWindow.this.preserveGLStateAtDestroy(value);
+ }
+
+ @Override
public synchronized void destroyActionPreLock() {
// nop
}
@@ -424,7 +538,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
@Override
public synchronized void destroyActionInLock() {
if(Window.DEBUG_IMPLEMENTATION) {
- String msg = "GLWindow.destroy() "+WindowImpl.getThreadName()+", start";
+ final String msg = "GLWindow.destroy() "+WindowImpl.getThreadName()+", start";
System.err.println(msg);
//Exception e1 = new Exception(msg);
//e1.printStackTrace();
@@ -443,10 +557,14 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
System.err.println("GLWindow.resetCounter() "+WindowImpl.getThreadName());
}
GLWindow.this.resetFPSCounter();
+ final GLAnimatorControl animator = GLWindow.this.getAnimator();
+ if( null != animator ) {
+ animator.resetFPSCounter();
+ }
}
@Override
- public synchronized void setVisibleActionPost(boolean visible, boolean nativeWindowCreated) {
+ public synchronized void setVisibleActionPost(final boolean visible, final boolean nativeWindowCreated) {
long t0;
if(Window.DEBUG_IMPLEMENTATION) {
t0 = System.nanoTime();
@@ -455,26 +573,29 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
t0 = 0;
}
- /* if (nativeWindowCreated && null != context) {
- throw new GLException("InternalError: Native Windows has been just created, but context wasn't destroyed (is not null)");
- } */
- if (null == context && visible && 0 != window.getWindowHandle() && 0<getWidth()*getHeight()) {
- NativeWindow nw;
- if (window.getWrappedWindow() != null) {
- nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getPrivateGraphicsConfiguration());
- } else {
- nw = window;
- }
- GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) nw.getGraphicsConfiguration().getChosenCapabilities();
- if(null==factory) {
- factory = GLDrawableFactory.getFactory(glCaps.getGLProfile());
+ if (null == drawable && visible && 0 != window.getWindowHandle() && 0<getSurfaceWidth()*getSurfaceHeight()) {
+ if( ( null != context ) ) {
+ throw new InternalError("GLWindow.LifecycleHook.setVisiblePost: "+WindowImpl.getThreadName()+" - Null drawable, but valid context - "+GLWindow.this);
}
- if(null==drawable) {
- drawable = (GLDrawableImpl) factory.createGLDrawable(nw);
+ final GLContext[] shareWith = { null };
+ if( !helper.isSharedGLContextPending(shareWith) ) {
+ final NativeSurface ns;
+ {
+ final NativeSurface wrapped_ns = window.getWrappedSurface();
+ ns = null != wrapped_ns ? wrapped_ns : window;
+ }
+ final GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) ns.getGraphicsConfiguration().getChosenCapabilities();
+ if(null==factory) {
+ factory = GLDrawableFactory.getFactory(glCaps.getGLProfile());
+ }
+ drawable = (GLDrawableImpl) factory.createGLDrawable(ns);
+ drawable.setRealized(true);
+
+ if( !GLWindow.this.restoreGLEventListenerState() ) {
+ context = (GLContextImpl) drawable.createContext(shareWith[0]);
+ context.setContextCreationFlags(additionalCtxCreationFlags);
+ }
}
- drawable.setRealized(true);
- context = (GLContextImpl) drawable.createContext(sharedContext);
- context.setContextCreationFlags(additionalCtxCreationFlags);
}
if(Window.DEBUG_IMPLEMENTATION) {
System.err.println("GLWindow.setVisibleActionPost("+visible+", "+nativeWindowCreated+") "+WindowImpl.getThreadName()+", fin: dt "+ (System.nanoTime()-t0)/1e6 +"ms");
@@ -485,10 +606,12 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
@Override
public synchronized boolean pauseRenderingAction() {
- boolean animatorPaused = false;
+ final boolean animatorPaused;
savedAnimator = GLWindow.this.getAnimator();
if ( null != savedAnimator ) {
animatorPaused = savedAnimator.pause();
+ } else {
+ animatorPaused = false;
}
return animatorPaused;
}
@@ -499,31 +622,40 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
savedAnimator.resume();
}
}
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void shutdownRenderingAction() {
+ final GLAnimatorControl anim = GLWindow.this.getAnimator();
+ if ( null != anim && anim.isAnimating() ) {
+ final Thread animThread = anim.getThread();
+ if( animThread == Thread.currentThread() ) {
+ anim.stop(); // on anim thread, non-blocking
+ } else {
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ if( anim.isAnimating() && null != animThread ) {
+ try {
+ animThread.stop();
+ } catch(final Throwable t) {
+ if( DEBUG ) {
+ System.err.println("Caught "+t.getClass().getName()+": "+t.getMessage());
+ t.printStackTrace();
+ }
+ }
+ }
+ return null;
+ } } );
+ }
+ }
+ }
}
//----------------------------------------------------------------------
// OpenGL-related methods and state
//
- private GLContext sharedContext = null;
-
- @Override
- protected final RecursiveLock getLock() {
- return window.getLock();
- }
-
- /**
- * Specifies an {@link javax.media.opengl.GLContext OpenGL context} to share with.<br>
- * At native creation, {@link #setVisible(boolean) setVisible(true)},
- * a {@link javax.media.opengl.GLDrawable drawable} and {@link javax.media.opengl.GLContext context} is created besides the native Window itself,<br>
- * hence you shall set the shared context before.
- *
- * @param sharedContext The OpenGL context shared by this GLWindow's one
- */
- public void setSharedContext(GLContext sharedContext) {
- this.sharedContext = sharedContext;
- }
-
@Override
public void display() {
if( !isNativeValid() || !isVisible() ) { return; }
@@ -548,12 +680,21 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
} finally {
lock.unlock();
}
- if( !done && 0<getWidth()*getHeight() ) {
+ if( !done && ( 0 < getSurfaceWidth() && 0 < getSurfaceHeight() ) ) {
// retry drawable and context creation, will itself issue resize -> display
setVisible(true);
}
}
+ /**
+ * {@inheritDoc}
+ * <p>
+ * GLWindow supports GL state preservation, hence returns <code>true</code>.
+ * </p>
+ */
+ @Override
+ public final boolean isGLStatePreservationSupported() { return true; }
+
//----------------------------------------------------------------------
// GLDrawable methods
//
@@ -565,19 +706,15 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public final void setRealized(boolean realized) {
- }
-
- @Override
public final void swapBuffers() throws GLException {
defaultSwapBuffers();
}
-
+
//----------------------------------------------------------------------
// NEWTEventConsumer
//
@Override
- public boolean consumeEvent(NEWTEvent event) {
+ public boolean consumeEvent(final NEWTEvent event) {
return window.consumeEvent(event);
}
@@ -585,42 +722,27 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
// Window completion
//
@Override
- public final void windowRepaint(int x, int y, int width, int height) {
+ public final void windowRepaint(final int x, final int y, final int width, final int height) {
window.windowRepaint(x, y, width, height);
}
@Override
- public final void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) {
+ public final void enqueueEvent(final boolean wait, final com.jogamp.newt.event.NEWTEvent event) {
window.enqueueEvent(wait, event);
}
@Override
- public final void runOnEDTIfAvail(boolean wait, final Runnable task) {
+ public final void runOnEDTIfAvail(final boolean wait, final Runnable task) {
window.runOnEDTIfAvail(wait, task);
}
@Override
- public final void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
- window.removeSurfaceUpdatedListener(l);
- }
-
- @Override
- public final void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
- window.addSurfaceUpdatedListener(l);
- }
-
- @Override
- public final void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
- window.addSurfaceUpdatedListener(index, l);
- }
-
- @Override
- public void sendWindowEvent(int eventType) {
+ public void sendWindowEvent(final int eventType) {
window.sendWindowEvent(eventType);
}
@Override
- public final WindowListener getWindowListener(int index) {
+ public final WindowListener getWindowListener(final int index) {
return window.getWindowListener(index);
}
@@ -630,22 +752,22 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public final void removeWindowListener(WindowListener l) {
+ public final void removeWindowListener(final WindowListener l) {
window.removeWindowListener(l);
}
@Override
- public final void addWindowListener(WindowListener l) {
+ public final void addWindowListener(final WindowListener l) {
window.addWindowListener(l);
}
@Override
- public final void addWindowListener(int index, WindowListener l) throws IndexOutOfBoundsException {
+ public final void addWindowListener(final int index, final WindowListener l) throws IndexOutOfBoundsException {
window.addWindowListener(index, l);
}
@Override
- public final void setKeyboardVisible(boolean visible) {
+ public final void setKeyboardVisible(final boolean visible) {
window.setKeyboardVisible(visible);
}
@@ -655,22 +777,22 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public final void addKeyListener(KeyListener l) {
+ public final void addKeyListener(final KeyListener l) {
window.addKeyListener(l);
}
@Override
- public final void addKeyListener(int index, KeyListener l) {
+ public final void addKeyListener(final int index, final KeyListener l) {
window.addKeyListener(index, l);
}
@Override
- public final void removeKeyListener(KeyListener l) {
+ public final void removeKeyListener(final KeyListener l) {
window.removeKeyListener(l);
}
@Override
- public final KeyListener getKeyListener(int index) {
+ public final KeyListener getKeyListener(final int index) {
return window.getKeyListener(index);
}
@@ -680,22 +802,22 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public final void addMouseListener(MouseListener l) {
+ public final void addMouseListener(final MouseListener l) {
window.addMouseListener(l);
}
@Override
- public final void addMouseListener(int index, MouseListener l) {
+ public final void addMouseListener(final int index, final MouseListener l) {
window.addMouseListener(index, l);
}
@Override
- public final void removeMouseListener(MouseListener l) {
+ public final void removeMouseListener(final MouseListener l) {
window.removeMouseListener(l);
}
@Override
- public final MouseListener getMouseListener(int index) {
+ public final MouseListener getMouseListener(final int index) {
return window.getMouseListener(index);
}
@@ -704,6 +826,39 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
return window.getMouseListeners();
}
+ @Override
+ public void setDefaultGesturesEnabled(final boolean enable) {
+ window.setDefaultGesturesEnabled(enable);
+ }
+ @Override
+ public boolean areDefaultGesturesEnabled() {
+ return window.areDefaultGesturesEnabled();
+ }
+ @Override
+ public final void addGestureHandler(final GestureHandler gh) {
+ window.addGestureHandler(gh);
+ }
+ @Override
+ public final void addGestureHandler(final int index, final GestureHandler gh) {
+ window.addGestureHandler(index, gh);
+ }
+ @Override
+ public final void removeGestureHandler(final GestureHandler gh) {
+ window.removeGestureHandler(gh);
+ }
+ @Override
+ public final void addGestureListener(final GestureHandler.GestureListener gl) {
+ window.addGestureListener(-1, gl);
+ }
+ @Override
+ public final void addGestureListener(final int index, final GestureHandler.GestureListener gl) {
+ window.addGestureListener(index, gl);
+ }
+ @Override
+ public final void removeGestureListener(final GestureHandler.GestureListener gl) {
+ window.removeGestureListener(gl);
+ }
+
//----------------------------------------------------------------------
// NativeWindow completion
//
@@ -735,6 +890,26 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
+ public final void removeSurfaceUpdatedListener(final SurfaceUpdatedListener l) {
+ window.removeSurfaceUpdatedListener(l);
+ }
+
+ @Override
+ public final void addSurfaceUpdatedListener(final SurfaceUpdatedListener l) {
+ window.addSurfaceUpdatedListener(l);
+ }
+
+ @Override
+ public final void addSurfaceUpdatedListener(final int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
+ window.addSurfaceUpdatedListener(index, l);
+ }
+
+ @Override
+ public final void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) {
+ window.surfaceUpdated(updater, ns, when);
+ }
+
+ @Override
public final long getWindowHandle() {
return window.getWindowHandle();
@@ -761,46 +936,102 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
return window.getScreenIndex();
}
- @Override
- public final void surfaceUpdated(Object updater, NativeSurface ns, long when) {
- window.surfaceUpdated(updater, ns, when);
- }
-
/**
* A most simple JOGL AWT test entry
*/
- public static void main(String args[]) {
+ public static void main(final String args[]) {
+ final boolean forceES2;
+ final boolean forceES3;
+ final boolean forceGL3;
+ final boolean forceGL4ES3;
+ {
+ boolean _forceES2 = false;
+ boolean _forceES3 = false;
+ boolean _forceGL3 = false;
+ boolean _forceGL4ES3 = false;
+ if( null != args ) {
+ for(int i=0; i<args.length; i++) {
+ if(args[i].equals("-es2")) {
+ _forceES2 = true;
+ } else if(args[i].equals("-es3")) {
+ _forceES3 = true;
+ } else if(args[i].equals("-gl3")) {
+ _forceGL3 = true;
+ } else if(args[i].equals("-gl4es3")) {
+ _forceGL4ES3 = true;
+ }
+ }
+ }
+ forceES2 = _forceES2;
+ forceES3 = _forceES3;
+ forceGL3 = _forceGL3;
+ forceGL4ES3 = _forceGL4ES3;
+ }
+ System.err.println("forceES2 "+forceES2);
+ System.err.println("forceES3 "+forceES3);
+ System.err.println("forceGL3 "+forceGL3);
+ System.err.println("forceGL4ES3 "+forceGL4ES3);
+
System.err.println(VersionUtil.getPlatformInfo());
System.err.println(GlueGenVersion.getInstance());
System.err.println(JoglVersion.getInstance());
System.err.println(JoglVersion.getDefaultOpenGLInfo(null, null, true).toString());
- final GLProfile glp = GLProfile.getDefault();
+ final GLProfile glp;
+ if(forceGL4ES3) {
+ glp = GLProfile.get(GLProfile.GL4ES3);
+ } else if(forceGL3) {
+ glp = GLProfile.get(GLProfile.GL3);
+ } else if(forceES3) {
+ glp = GLProfile.get(GLProfile.GLES3);
+ } else if(forceES2) {
+ glp = GLProfile.get(GLProfile.GLES2);
+ } else {
+ glp = GLProfile.getDefault();
+ }
final GLCapabilitiesImmutable caps = new GLCapabilities( glp );
+ System.err.println("Requesting: "+caps);
- GLWindow glWindow = GLWindow.create(caps);
+ final GLWindow glWindow = GLWindow.create(caps);
glWindow.setSize(128, 128);
glWindow.addGLEventListener(new GLEventListener() {
@Override
- public void init(GLAutoDrawable drawable) {
- GL gl = drawable.getGL();
+ public void init(final GLAutoDrawable drawable) {
+ final GL gl = drawable.getGL();
System.err.println(JoglVersion.getGLInfo(gl, null));
System.err.println("Requested: "+drawable.getNativeSurface().getGraphicsConfiguration().getRequestedCapabilities());
System.err.println("Chosen : "+drawable.getChosenGLCapabilities());
+ System.err.println("GL impl. class "+gl.getClass().getName());
+ if( gl.isGL4ES3() ) {
+ final GL4ES3 _gl = gl.getGL4ES3();
+ System.err.println("GL4ES3 retrieved, impl. class "+_gl.getClass().getName());
+ }
+ if( gl.isGL3() ) {
+ final GL3 _gl = gl.getGL3();
+ System.err.println("GL3 retrieved, impl. class "+_gl.getClass().getName());
+ }
+ if( gl.isGLES3() ) {
+ final GLES3 _gl = gl.getGLES3();
+ System.err.println("GLES3 retrieved, impl. class "+_gl.getClass().getName());
+ }
+ if( gl.isGLES2() ) {
+ final GLES2 _gl = gl.getGLES2();
+ System.err.println("GLES2 retrieved, impl. class "+_gl.getClass().getName());
+ }
}
@Override
- public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+ public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
}
@Override
- public void display(GLAutoDrawable drawable) {
+ public void display(final GLAutoDrawable drawable) {
}
@Override
- public void dispose(GLAutoDrawable drawable) {
+ public void dispose(final GLAutoDrawable drawable) {
}
});
diff --git a/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java b/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java
index 36bc3f28f..76af2d0ec 100644
--- a/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java
+++ b/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,13 +20,12 @@
* 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 com.jogamp.newt.swt;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
@@ -44,18 +43,20 @@ import javax.media.nativewindow.WindowClosingProtocol;
import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.InsetsImmutable;
import javax.media.nativewindow.util.Point;
+import javax.media.opengl.GLCapabilities;
import jogamp.nativewindow.macosx.OSXUtil;
+import jogamp.nativewindow.windows.GDIUtil;
+import jogamp.nativewindow.x11.X11Lib;
import jogamp.newt.Debug;
+import jogamp.newt.swt.SWTEDTUtil;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ControlAdapter;
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.events.PaintEvent;
-import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
import com.jogamp.nativewindow.swt.SWTAccessor;
import com.jogamp.newt.Display;
@@ -65,111 +66,159 @@ import com.jogamp.newt.util.EDTUtil;
/**
* SWT {@link Canvas} containing a NEWT {@link Window} using native parenting.
+ * <p>
+ * Implementation allows use of custom {@link GLCapabilities}.
+ * </p>
*/
public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol {
private static final boolean DEBUG = Debug.debug("Window");
- private static final boolean isOSX = NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(false);
-
- private final AbstractGraphicsScreen screen;
-
+
+ private final AbstractGraphicsScreen screen;
+
private WindowClosingMode newtChildCloseOp = WindowClosingMode.DISPOSE_ON_CLOSE;
private volatile Rectangle clientArea;
private volatile SWTNativeWindow nativeWindow;
private volatile Window newtChild = null;
+ private volatile boolean newtChildReady = false; // ready if SWTEDTUtil is set and newtChild parented
+ private volatile boolean postSetSize = false; // pending resize
+ private volatile boolean postSetPos = false; // pending pos
- /**
- * Creates an instance using {@link #NewtCanvasSWT(Composite, int, Window)}
+ /**
+ * Creates an instance using {@link #NewtCanvasSWT(Composite, int, Window)}
* on the SWT thread.
- *
+ *
* <p>
* Note: The NEWT child {@link Display}'s {@link EDTUtil} is being set to an SWT conform implementation
- * via {@link Display#setEDTUtil(EDTUtil)}.
+ * via {@link Display#setEDTUtil(EDTUtil)}.
* </p>
- *
+ *
* @param parent the SWT composite
- * @param style additional styles to SWT#NO_BACKGROUND
- * @param child optional preassigned {@link #Window}, maybe null
+ * @param style additional styles to SWT#NO_BACKGROUND
+ * @param child optional preassigned {@link #Window}, maybe null
* @return a new instance
*/
public static NewtCanvasSWT create(final Composite parent, final int style, final Window child) {
- final NewtCanvasSWT[] res = new NewtCanvasSWT[] { null };
+ final NewtCanvasSWT[] res = new NewtCanvasSWT[] { null };
parent.getDisplay().syncExec( new Runnable() {
+ @Override
public void run() {
res[0] = new NewtCanvasSWT( parent, style, child);
}
});
return res[0];
}
-
+
/**
* Instantiates a NewtCanvas with a NEWT child.
- *
+ *
* <p>
* Note: The NEWT child {@link Display}'s {@link EDTUtil} is being set to an SWT conform implementation
- * via {@link Display#setEDTUtil(EDTUtil)}.
+ * via {@link Display#setEDTUtil(EDTUtil)}.
* </p>
- *
+ *
* @param parent the SWT composite
- * @param style additional styles to SWT#NO_BACKGROUND
- * @param child optional preassigned {@link #Window}, maybe null
+ * @param style additional styles to SWT#NO_BACKGROUND
+ * @param child optional preassigned {@link #Window}, maybe null
*/
- public NewtCanvasSWT(final Composite parent, final int style, Window child) {
+ public NewtCanvasSWT(final Composite parent, final int style, final Window child) {
super(parent, style | SWT.NO_BACKGROUND);
-
+
SWTAccessor.setRealized(this, true);
clientArea = getClientArea();
final AbstractGraphicsDevice device = SWTAccessor.getDevice(this);
- screen = SWTAccessor.getScreen(device, 0);
+ screen = SWTAccessor.getScreen(device, -1 /* default */);
nativeWindow = null;
-
+
if(null != child) {
setNEWTChild(child);
}
-
- /* Register SWT listeners (e.g. PaintListener) to render/resize GL surface. */
- /* TODO: verify that these do not need to be manually de-registered when destroying the SWT component */
- addPaintListener(new PaintListener() {
+
+ final Listener listener = new Listener () {
@Override
- public void paintControl(final PaintEvent arg0) {
- if( null != nativeWindow || validateNative() ) {
- if( null !=newtChild ) {
- newtChild.windowRepaint(0, 0, clientArea.width, clientArea.height);
+ public void handleEvent (final Event event) {
+ switch (event.type) {
+ case SWT.Paint:
+ if( DEBUG ) {
+ System.err.println("NewtCanvasSWT.Event.PAINT, "+event);
+ }
+ if( null != nativeWindow || validateNative() ) {
+ if( newtChildReady ) {
+ if( postSetSize ) {
+ newtChild.setSize(clientArea.width, clientArea.height);
+ postSetSize = false;
+ }
+ if( postSetPos ) {
+ newtChild.setPosition(clientArea.x, clientArea.y);
+ postSetPos = false;
+ }
+ newtChild.windowRepaint(0, 0, clientArea.width, clientArea.height);
+ }
+ }
+ break;
+ case SWT.Move:
+ if( DEBUG ) {
+ System.err.println("NewtCanvasSWT.Event.MOVE, "+event);
+ }
+ // updatePosSizeCheck();
+ break;
+ case SWT.Resize:
+ if( DEBUG ) {
+ System.err.println("NewtCanvasSWT.Event.RESIZE, "+event);
+ }
+ updateSizeCheck();
+ break;
+ case SWT.Dispose:
+ if( DEBUG ) {
+ System.err.println("NewtCanvasSWT.Event.DISPOSE, "+event);
+ }
+ NewtCanvasSWT.this.dispose();
+ break;
+ default:
+ if( DEBUG ) {
+ System.err.println("NewtCanvasSWT.Event.misc: "+event.type+", "+event);
}
}
}
- });
+ };
+ // addListener (SWT.Move, listener);
+ addListener (SWT.Resize, listener);
+ addListener (SWT.Paint, listener);
+ addListener (SWT.Dispose, listener);
+ }
- addControlListener(new ControlAdapter() {
- @Override
- public void controlResized(final ControlEvent arg0) {
- updateSizeCheck();
- }
- });
+ @Override
+ public void setBounds(final int x, final int y, final int width, final int height) {
+ super.setBounds(x, y, width, height);
+ if( DEBUG ) {
+ System.err.println("NewtCanvasSWT.setBounds: "+x+"/"+y+" "+width+"x"+height);
+ }
+ if( SWTAccessor.isOSX ) {
+ // Force newtChild to update its size and position (OSX only)
+ updatePosSizeCheck(x, y, width, height, true /* updatePos */);
+ }
}
-
+
/** assumes nativeWindow == null ! */
protected final boolean validateNative() {
- if( isDisposed() ) {
- return false;
- }
updateSizeCheck();
final Rectangle nClientArea = clientArea;
- if(0 == nClientArea.width * nClientArea.height) {
+ if(0 >= nClientArea.width || 0 >= nClientArea.height) {
return false;
}
-
+ screen.getDevice().open();
+
/* Native handle for the control, used to associate with GLContext */
final long nativeWindowHandle = SWTAccessor.getWindowHandle(this);
final int visualID = SWTAccessor.getNativeVisualID(screen.getDevice(), nativeWindowHandle);
final boolean visualIDValid = NativeWindowFactory.isNativeVisualIDValidForProcessing(visualID);
if(DEBUG) {
System.err.println("NewtCanvasSWT.validateNative() windowHandle 0x"+Long.toHexString(nativeWindowHandle)+", visualID 0x"+Integer.toHexString(visualID)+", valid "+visualIDValid);
- }
+ }
if( visualIDValid ) {
- /* Get the nativewindow-Graphics Device associated with this control (which is determined by the parent Composite).
+ /* Get the nativewindow-Graphics Device associated with this control (which is determined by the parent Composite).
* Note: SWT is owner of the native handle, hence no closing operation will be a NOP. */
final CapabilitiesImmutable caps = new Capabilities();
final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(screen.getDevice(), caps);
@@ -177,27 +226,64 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol {
if(DEBUG) {
System.err.println("NewtCanvasSWT.validateNative() factory: "+factory+", windowHandle 0x"+Long.toHexString(nativeWindowHandle)+", visualID 0x"+Integer.toHexString(visualID)+", chosen config: "+config);
// Thread.dumpStack();
- }
+ }
if (null == config) {
throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this);
}
nativeWindow = new SWTNativeWindow(config, nativeWindowHandle);
reparentWindow( true );
+ if( SWTAccessor.isOSX && newtChildReady ) {
+ // initial positioning for OSX, called when the window is created
+ newtChild.setPosition(getLocation().x, getLocation().y);
+ }
}
return null != nativeWindow;
}
-
+
protected final void updateSizeCheck() {
- final Rectangle oClientArea = clientArea;
final Rectangle nClientArea = getClientArea();
- if ( nClientArea != null &&
- ( nClientArea.width != oClientArea.width || nClientArea.height != oClientArea.height )
- ) {
- clientArea = nClientArea; // write back new value
- if( null != newtChild ) {
- newtChild.setSize(clientArea.width, clientArea.height);
+ if( null != nClientArea ) {
+ updatePosSizeCheck(nClientArea.x, nClientArea.y, nClientArea.width, nClientArea.height, false /* updatePos */);
+ }
+ }
+ protected final void updatePosSizeCheck() {
+ final Rectangle nClientArea = getClientArea();
+ if( null != nClientArea ) {
+ updatePosSizeCheck(nClientArea.x, nClientArea.y, nClientArea.width, nClientArea.height, true /* updatePos */);
+ }
+ }
+ protected final void updatePosSizeCheck(final int newX, final int newY, final int newWidth, final int newHeight, final boolean updatePos) {
+ final boolean sizeChanged, posChanged;
+ final Rectangle nClientArea;
+ {
+ final Rectangle oClientArea = clientArea;
+ sizeChanged = newWidth != oClientArea.width || newHeight != oClientArea.height;
+ posChanged = newX != oClientArea.x || newY != oClientArea.y;
+ if( sizeChanged || posChanged ) {
+ nClientArea = new Rectangle(updatePos ? newX : oClientArea.x, updatePos ? newY : oClientArea.y, newWidth, newHeight);
+ clientArea = nClientArea;
+ } else {
+ nClientArea = clientArea;
+ }
+ }
+ if(DEBUG) {
+ final long nsh = newtChildReady ? newtChild.getSurfaceHandle() : 0;
+ System.err.println("NewtCanvasSWT.updatePosSizeCheck: sizeChanged "+sizeChanged+", posChanged "+posChanged+", updatePos "+updatePos+", ("+Thread.currentThread().getName()+"): newtChildReady "+newtChildReady+", "+nClientArea.x+"/"+nClientArea.y+" "+nClientArea.width+"x"+nClientArea.height+" - surfaceHandle 0x"+Long.toHexString(nsh));
+ }
+ if( sizeChanged ) {
+ if( newtChildReady ) {
+ newtChild.setSize(nClientArea.width, nClientArea.height);
+ } else {
+ postSetSize = true;
+ }
+ }
+ if( updatePos && posChanged ) {
+ if( newtChildReady ) {
+ newtChild.setPosition(nClientArea.x, nClientArea.y);
+ } else {
+ postSetPos = true;
}
}
}
@@ -206,7 +292,7 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol {
public void update() {
// don't paint background etc .. nop avoids flickering
}
-
+
/**
* Destroys this resource:
* <ul>
@@ -226,49 +312,61 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol {
}
configureNewtChild(false);
newtChild.setVisible(false);
- newtChild.reparentWindow(null);
+ newtChild.reparentWindow(null, -1, -1, 0 /* hint */);
newtChild.destroy();
newtChild = null;
}
+ screen.getDevice().close();
nativeWindow = null;
- super.dispose();
+ super.dispose();
}
-
+
+ private Point getParentLocationOnScreen() {
+ final org.eclipse.swt.graphics.Point[] parentLoc = new org.eclipse.swt.graphics.Point[] { null };
+ SWTAccessor.invoke(true, new Runnable() {
+ public void run() {
+ parentLoc[0] = getParent().toDisplay(0,0);
+ } } );
+ return new Point(parentLoc[0].x, parentLoc[0].y);
+ }
+
/** @return this SWT Canvas NativeWindow representation, may be null in case it has not been realized. */
public NativeWindow getNativeWindow() { return nativeWindow; }
-
+
+ @Override
public WindowClosingMode getDefaultCloseOperation() {
- return newtChildCloseOp; // FIXME
+ return newtChildCloseOp; // TODO: implement ?!
}
- public WindowClosingMode setDefaultCloseOperation(WindowClosingMode op) {
- return newtChildCloseOp = op; // FIXME
+ @Override
+ public WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) {
+ return newtChildCloseOp = op; // TODO: implement ?!
}
boolean isParent() {
- return null!=newtChild ;
+ return null!=newtChild ;
}
boolean isFullscreen() {
return null != newtChild && newtChild.isFullscreen();
}
- /**
+ /**
* Sets a new NEWT child, provoking reparenting.
* <p>
* A previously detached <code>newChild</code> will be released to top-level status
- * and made invisible.
+ * and made invisible.
* </p>
* <p>
- * Note: When switching NEWT child's, detaching the previous first via <code>setNEWTChild(null)</code>
- * produced much cleaner visual results.
+ * Note: When switching NEWT child's, detaching the previous first via <code>setNEWTChild(null)</code>
+ * produced much cleaner visual results.
* </p>
* <p>
* Note: The NEWT child {@link Display}'s {@link EDTUtil} is being set to an SWT conform implementation
- * via {@link Display#setEDTUtil(EDTUtil)}.
+ * via {@link Display#setEDTUtil(EDTUtil)}.
* </p>
- * @return the previous attached newt child.
+ * @return the previous attached newt child.
*/
public Window setNEWTChild(final Window newChild) {
final Window prevChild = newtChild;
@@ -285,62 +383,67 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol {
if(null != nativeWindow && null != newChild) {
reparentWindow( true );
}
- return prevChild;
+ return prevChild;
}
-
+
/** @return the current NEWT child */
public Window getNEWTChild() {
return newtChild;
}
-
+
@Override
- public boolean setParent(Composite parent) {
+ public boolean setParent(final Composite parent) {
return super.setParent(parent);
}
- /* package */ void configureNewtChild(boolean attach) {
-
+ /* package */ void configureNewtChild(final boolean attach) {
+ newtChildReady = attach;
if( null != newtChild ) {
newtChild.setKeyboardFocusHandler(null);
- if(attach) {
- newtChildCloseOp = newtChild.setDefaultCloseOperation(WindowClosingMode.DO_NOTHING_ON_CLOSE);
+ if(attach) {
+ newtChildCloseOp = newtChild.setDefaultCloseOperation(WindowClosingMode.DO_NOTHING_ON_CLOSE);
} else {
newtChild.setFocusAction(null);
- newtChild.setDefaultCloseOperation(newtChildCloseOp);
+ newtChild.setDefaultCloseOperation(newtChildCloseOp);
}
}
}
- void reparentWindow(boolean add) {
+ void reparentWindow(final boolean add) {
if( null == newtChild ) {
return; // nop
}
if(DEBUG) {
System.err.println("NewtCanvasSWT.reparentWindow.0: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil());
}
-
+
newtChild.setFocusAction(null); // no AWT focus traversal ..
if(add) {
updateSizeCheck();
final int w = clientArea.width;
final int h = clientArea.height;
- final Display newtDisplay = newtChild.getScreen().getDisplay();
- newtDisplay.setEDTUtil(new SWTEDTUtil(newtDisplay, getDisplay()));
-
+ // set SWT EDT and start it
+ {
+ final Display newtDisplay = newtChild.getScreen().getDisplay();
+ final EDTUtil edtUtil = new SWTEDTUtil(newtDisplay, getDisplay());
+ edtUtil.start();
+ newtDisplay.setEDTUtil( edtUtil );
+ }
+
newtChild.setSize(w, h);
- newtChild.reparentWindow(nativeWindow);
+ newtChild.reparentWindow(nativeWindow, -1, -1, Window.REPARENT_HINT_BECOMES_VISIBLE);
newtChild.setVisible(true);
configureNewtChild(true);
newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener
- // force this SWT Canvas to be focus-able,
- // since this it is completely covered by the newtChild (z-order).
+ // force this SWT Canvas to be focus-able,
+ // since it is completely covered by the newtChild (z-order).
setEnabled(true);
} else {
configureNewtChild(false);
newtChild.setVisible(false);
- newtChild.reparentWindow(null);
+ newtChild.reparentWindow(null, -1, -1, 0 /* hints */);
}
if(DEBUG) {
System.err.println("NewtCanvasSWT.reparentWindow.X: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil());
@@ -348,34 +451,34 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol {
}
private final void requestFocusNEWTChild() {
- if( null != newtChild ) {
+ if( newtChildReady ) {
newtChild.setFocusAction(null);
newtChild.requestFocus();
}
}
-
+
@Override
public boolean forceFocus() {
final boolean res = NewtCanvasSWT.super.forceFocus();
requestFocusNEWTChild();
- return res;
+ return res;
}
-
+
private class SWTNativeWindow implements NativeWindow {
private final AbstractGraphicsConfiguration config;
private final long nativeWindowHandle;
private final InsetsImmutable insets; // only required to allow proper client position calculation on OSX
-
- public SWTNativeWindow(AbstractGraphicsConfiguration config, long nativeWindowHandle) {
+
+ public SWTNativeWindow(final AbstractGraphicsConfiguration config, final long nativeWindowHandle) {
this.config = config;
this.nativeWindowHandle = nativeWindowHandle;
- if(isOSX) {
+ if( SWTAccessor.isOSX ) {
this.insets = OSXUtil.GetInsets(nativeWindowHandle);
} else {
this.insets = new Insets(0, 0, 0, 0);
}
}
-
+
@Override
public int lockSurface() throws NativeWindowException, RuntimeException {
return NativeSurface.LOCK_SUCCESS;
@@ -400,31 +503,54 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol {
}
@Override
- public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { }
+ public void addSurfaceUpdatedListener(final SurfaceUpdatedListener l) { }
@Override
- public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
+ public void addSurfaceUpdatedListener(final int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
}
@Override
- public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { }
+ public void removeSurfaceUpdatedListener(final SurfaceUpdatedListener l) { }
@Override
- public long getSurfaceHandle() {
+ public long getSurfaceHandle() {
return 0;
}
@Override
public int getWidth() {
- return clientArea.width;
+ return getSurfaceWidth(); // FIXME: Use 'scale' or an actual window-width
}
@Override
public int getHeight() {
+ return getSurfaceHeight(); // FIXME: Use 'scale' or an actual window-width
+ }
+
+ @Override
+ public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) {
+ return pixelUnitsAndResult; // FIXME HiDPI: use 'pixelScale'
+ }
+
+ @Override
+ public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) {
+ return windowUnitsAndResult; // FIXME HiDPI: use 'pixelScale'
+ }
+
+ @Override
+ public int getSurfaceWidth() {
+ return clientArea.width;
+ }
+
+ @Override
+ public int getSurfaceHeight() {
return clientArea.height;
}
@Override
+ public final NativeSurface getNativeSurface() { return this; }
+
+ @Override
public AbstractGraphicsConfiguration getGraphicsConfiguration() {
return config;
}
@@ -440,7 +566,7 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol {
}
@Override
- public void surfaceUpdated(Object updater, NativeSurface ns, long when) { }
+ public void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) { }
@Override
public void destroy() { }
@@ -471,36 +597,38 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol {
}
@Override
- public Point getLocationOnScreen(Point point) {
- if( isOSX ) {
- final Point los = OSXUtil.GetLocationOnScreen(nativeWindowHandle, false, 0, 0);
- // top-level position -> client window position
- los.setX(los.getX() + insets.getLeftWidth());
- los.setY(los.getY() + insets.getTopHeight());
- if(null!=point) {
- return point.translate(los);
- } else {
- return los;
- }
+ public Point getLocationOnScreen(final Point point) {
+ final Point los; // client window location on screen
+ if( SWTAccessor.isOSX ) {
+ // let getLOS provide the point where the child window may be placed
+ // from, as taken from SWT Control.toDisplay();
+ los = getParentLocationOnScreen();
+ } else if (SWTAccessor.isX11) {
+ final AbstractGraphicsScreen s = config.getScreen();
+ los = X11Lib.GetRelativeLocation(s.getDevice().getHandle(), s.getIndex(), nativeWindowHandle, 0 /*root win*/, 0, 0);
+ } else if (SWTAccessor.isWindows) {
+ los = GDIUtil.GetRelativeLocation( nativeWindowHandle, 0 /*root win*/, 0, 0);
} else {
- // client position on 'normal' windowing systems is 0/0
- if(null == point) {
- point = new Point(0, 0);
- }
- return point;
+ // fall-back to 0/0
+ los = new Point(0, 0);
+ }
+ if(null!=point) {
+ return point.translate(los);
+ } else {
+ return los;
}
}
@Override
public boolean hasFocus() {
return isFocusControl();
- }
+ }
};
- static String newtWinHandleToHexString(Window w) {
+ static String newtWinHandleToHexString(final Window w) {
return null != w ? toHexString(w.getWindowHandle()) : "nil";
}
- static String toHexString(long l) {
+ static String toHexString(final long l) {
return "0x"+Long.toHexString(l);
}
}
diff --git a/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java
deleted file mode 100644
index d4b83d891..000000000
--- a/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/**
- * Copyright 2012 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 com.jogamp.newt.swt;
-
-import java.awt.EventQueue;
-
-import jogamp.newt.Debug;
-
-import com.jogamp.newt.util.EDTUtil;
-
-/**
- * Simple {@link EDTUtil} implementation utilizing the SWT UI thread
- * of the given {@link Display}.
- */
-public class SWTEDTUtil implements EDTUtil {
- public static final boolean DEBUG = Debug.debug("EDT");
-
- private final Object edtLock = new Object(); // locking the EDT start/stop state
- private final ThreadGroup threadGroup;
- private final String name;
- private final Runnable dispatchMessages;
- private final org.eclipse.swt.widgets.Display swtDisplay;
- private NewtEventDispatchThread nedt = null;
- private int start_iter=0;
- private static long pollPeriod = EDTUtil.defaultEDTPollPeriod;
-
- public SWTEDTUtil(final com.jogamp.newt.Display newtDisplay, org.eclipse.swt.widgets.Display swtDisplay) {
- this.threadGroup = Thread.currentThread().getThreadGroup();
- this.name=Thread.currentThread().getName()+"-SWTDisplay-"+newtDisplay.getFQName()+"-EDT-";
- this.dispatchMessages = new Runnable() {
- public void run() {
- ((jogamp.newt.DisplayImpl) newtDisplay).dispatchMessages();
- } };
- this.swtDisplay = swtDisplay;
- this.nedt = new NewtEventDispatchThread(threadGroup, name);
- this.nedt.setDaemon(true); // don't stop JVM from shutdown ..
- }
-
- public final org.eclipse.swt.widgets.Display getDisplay() {
- return swtDisplay;
- }
-
- @Override
- public long getPollPeriod() {
- return pollPeriod;
- }
-
- @Override
- public void setPollPeriod(long ms) {
- pollPeriod = ms;
- }
-
- @Override
- public void reset() {
- synchronized(edtLock) {
- waitUntilStopped();
- if(DEBUG) {
- System.err.println(Thread.currentThread()+": EDT reset - edt: "+nedt);
- }
- this.nedt = new NewtEventDispatchThread(threadGroup, name);
- this.nedt.setDaemon(true); // don't stop JVM from shutdown ..
- }
- }
-
- private final void startImpl() {
- if(nedt.isAlive()) {
- throw new RuntimeException("EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning()+", edt: "+nedt);
- }
- start_iter++;
- nedt.setName(name+start_iter);
- nedt.shouldStop = false;
- if(DEBUG) {
- System.err.println(Thread.currentThread()+": EDT START - edt: "+nedt);
- // Thread.dumpStack();
- }
- nedt.start();
- }
-
- @Override
- public boolean isCurrentThreadEDT() {
- return swtDisplay.getThread() == Thread.currentThread();
- }
-
- @Override
- public final boolean isCurrentThreadNEDT() {
- return nedt == Thread.currentThread();
- }
-
- @Override
- public final boolean isCurrentThreadEDTorNEDT() {
- final Thread ct = Thread.currentThread();
- return ct == swtDisplay.getThread() || ct == nedt ;
- }
-
- @Override
- public boolean isRunning() {
- return nedt.isRunning() ; // SWT is always running
- }
-
- @Override
- public final void invokeStop(Runnable task) {
- invokeImpl(true, task, true);
- }
-
- @Override
- public final void invoke(boolean wait, Runnable task) {
- invokeImpl(wait, task, false);
- }
-
- private void invokeImpl(boolean wait, Runnable task, boolean stop) {
- if(task == null) {
- throw new RuntimeException("Null Runnable");
- }
- synchronized(edtLock) { // lock the EDT status
- if( nedt.shouldStop ) {
- // drop task ..
- if(DEBUG) {
- System.err.println("Warning: EDT about (1) to stop, won't enqueue new task: "+nedt);
- Thread.dumpStack();
- }
- return;
- }
- // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task);
- // Thread.dumpStack();
- if(stop) {
- nedt.shouldStop = true;
- if(DEBUG) {
- System.err.println(Thread.currentThread()+": EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt);
- // Thread.dumpStack();
- }
- }
-
- // start if should not stop && not started yet
- if( !stop && !nedt.isRunning() ) {
- startImpl();
- }
- }
- if(wait) {
- swtDisplay.syncExec(task);
- } else {
- swtDisplay.asyncExec(task);
- }
- }
-
- @Override
- final public void waitUntilIdle() {
- final NewtEventDispatchThread _edt;
- synchronized(edtLock) {
- _edt = nedt;
- }
- if(!_edt.isRunning() || EventQueue.isDispatchThread() || _edt == Thread.currentThread()) {
- return;
- }
- try {
- swtDisplay.syncExec(new Runnable() {
- public void run() { }
- });
- } catch (Exception e) { }
- }
-
- @Override
- final public void waitUntilStopped() {
- synchronized(edtLock) {
- if(nedt.isRunning() && nedt != Thread.currentThread() ) {
- while(nedt.isRunning()) {
- try {
- edtLock.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
-
- class NewtEventDispatchThread extends Thread {
- volatile boolean shouldStop = false;
- volatile boolean isRunning = false;
- Object sync = new Object();
-
- public NewtEventDispatchThread(ThreadGroup tg, String name) {
- super(tg, name);
- }
-
- final public boolean isRunning() {
- return isRunning;
- }
-
- @Override
- final public void start() throws IllegalThreadStateException {
- isRunning = true;
- super.start();
- }
-
- /**
- * Utilizing locking only on tasks and its execution,
- * not for event dispatching.
- */
- @Override
- final public void run() {
- if(DEBUG) {
- System.err.println(getName()+": EDT run() START "+ getName());
- }
- RuntimeException error = null;
- try {
- do {
- // event dispatch
- if(!shouldStop) {
- // FIXME: Determine whether we require to run the
- // delivery of events (dispatch) on AWT-EDT.
- // Since the WindowDriver itself delivers all Window related events,
- // this shall not be required.
- // AWTEDTExecutor.singleton.invoke(true, dispatchMessages);
- dispatchMessages.run();
- }
- // wait
- synchronized(sync) {
- if(!shouldStop) {
- try {
- sync.wait(pollPeriod);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- } while(!shouldStop) ;
- } catch (Throwable t) {
- // handle errors ..
- shouldStop = true;
- if(t instanceof RuntimeException) {
- error = (RuntimeException) t;
- } else {
- error = new RuntimeException("Within EDT", t);
- }
- } finally {
- if(DEBUG) {
- System.err.println(getName()+": EDT run() END "+ getName()+", "+error);
- }
- synchronized(edtLock) {
- isRunning = !shouldStop;
- if(!isRunning) {
- edtLock.notifyAll();
- }
- }
- if(DEBUG) {
- System.err.println(getName()+": EDT run() EXIT "+ getName()+", exception: "+error);
- }
- if(null!=error) {
- throw error;
- }
- } // finally
- } // run()
- } // EventDispatchThread
-
-}
diff --git a/src/newt/classes/com/jogamp/newt/util/EDTUtil.java b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java
index 7e19d9de5..58aa67105 100644
--- a/src/newt/classes/com/jogamp/newt/util/EDTUtil.java
+++ b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java
@@ -63,25 +63,30 @@ public interface EDTUtil {
* @param ms poll period in milliseconds
*/
public void setPollPeriod(long ms);
-
+
/**
- * Create a new EDT. One should invoke <code>reset()</code><br>
- * after <code>invokeStop(..)</code> in case another start via <code>invoke(..)</code>
- * is expected.
+ * Starts the EDT after it's creation or after {@link #invokeStop(boolean, Runnable) stopping}.
+ * <p>
+ * If the EDT is running, it must be {@link #invokeStop(boolean, Runnable) stopped} first
+ * and the caller should wait {@link #waitUntilStopped() until it's stopped}.
+ * </p>
*
- * @see #invoke(boolean, java.lang.Runnable)
- * @see #invokeStop(java.lang.Runnable)
+ * @throws IllegalStateException if EDT is running and not subject to be stopped, i.e. {@link #isRunning()} returns true
+ * @throws RuntimeException if EDT could not be started
+ *
+ * @see #invokeStop(boolean, java.lang.Runnable)
+ * @see #waitUntilStopped()
*/
- public void reset();
+ public void start() throws IllegalStateException;
/**
* Returns true if the current thread is the event dispatch thread (EDT).
* <p>
- * The EDT is the platform specific thread dispatching toolkit-events
+ * The EDT is the platform specific thread dispatching toolkit-events
* and executing toolkit-tasks enqueued via {@link #invoke(boolean, Runnable)}.
* </p>
* <p>
- * Usually it is the same thread as used to dequeue informal {@link NEWTEvent}s (NEDT), see {@link #isCurrentThreadNEDT()},
+ * Usually it is the same thread as used to dequeue informal {@link NEWTEvent}s (NEDT), see {@link #isCurrentThreadNEDT()},
* however, this may differ, e.g. SWT and AWT implementation.
* </p>
*/
@@ -90,60 +95,74 @@ public interface EDTUtil {
/**
* Returns true if the current thread is the internal NEWT event dequeue thread (NEDT).
* <p>
- * The NEDT is the NEWT thread used to dequeue informal {@link NEWTEvent}s enqueued internally
+ * The NEDT is the NEWT thread used to dequeue informal {@link NEWTEvent}s enqueued internally
* via {@link DisplayImpl#enqueueEvent(boolean, NEWTEvent)}.
* </p>
* <p>
- * Usually it is the same thread as the EDT, see {@link #isCurrentThreadEDT()},
+ * Usually it is the same thread as the EDT, see {@link #isCurrentThreadEDT()},
* however, this may differ, e.g. SWT and AWT implementation.
* </p>
*/
public boolean isCurrentThreadNEDT();
-
+
/**
* Returns <code>true</code> if either {@link #isCurrentThreadEDT()} or {@link #isCurrentThreadNEDT()} is <code>true</code>,
* otherwise <code>false</code>.
*/
public boolean isCurrentThreadEDTorNEDT();
-
+
/**
- * @return True if EDT is running
+ * @return True if EDT is running and not subject to be stopped.
*/
public boolean isRunning();
- /**
+ /**
* Append the final task to the EDT task queue,
- * signals EDT to stop and wait until stopped.<br>
+ * signals EDT to stop.
+ * <p>
+ * If <code>wait</code> is <code>true</code> methods
+ * blocks until EDT is stopped.
+ * </p>
+ * <p>
+ * <code>task</code> maybe <code>null</code><br/>
* Due to the nature of this method:
* <ul>
* <li>All previous queued tasks will be finished.</li>
* <li>No new tasks are allowed, an Exception is thrown.</li>
* <li>Can be issued from within EDT, ie from within an enqueued task.</li>
- * <li>{@link #reset()} may follow immediately, ie creating a new EDT</li>
+ * <li>{@link #start()} may follow immediately, ie creating a new EDT</li>
* </ul>
+ * </p>
+ * @return true if <code>task</code> has been executed or queued for later execution, otherwise false
*/
- public void invokeStop(Runnable finalTask);
+ public boolean invokeStop(boolean wait, Runnable finalTask);
- /**
- * Shall start the thread if not running.<br>
- * Append task to the EDT task queue.<br>
- * Wait until execution is finished if <code>wait == true</code>.<br>
+ /**
+ * Appends task to the EDT task queue if current thread is not EDT,
+ * otherwise execute task immediately.
+ * <p>
+ * Wait until execution is finished if <code>wait == true</code>.
+ * </p>
* Can be issued from within EDT, ie from within an enqueued task.<br>
- *
- * @throws RuntimeException in case EDT is stopped and not {@link #reset()}
+ * @return true if <code>task</code> has been executed or queued for later execution, otherwise false
*/
- public void invoke(boolean wait, Runnable task);
+ public boolean invoke(boolean wait, Runnable task);
- /**
+ /**
* Wait until the EDT task queue is empty.<br>
* The last task may still be in execution when this method returns.
+ * @return true if waited for idle, otherwise false, i.e. in case of current thread is EDT or NEDT
*/
- public void waitUntilIdle();
+ public boolean waitUntilIdle();
/**
* Wait until EDT task is stopped.<br>
- * No <code>stop</code> action is performed, {@link #invokeStop(java.lang.Runnable)} should be used before.
+ * No <code>stop</code> action is performed, {@link #invokeStop(boolean, java.lang.Runnable)} should be used before.
+ * <p>
+ * If caller thread is EDT or NEDT, this call will not block.
+ * </p>
+ * @return true if stopped, otherwise false, i.e. in case of current thread is EDT or NEDT
*/
- public void waitUntilStopped();
+ public boolean waitUntilStopped();
}
diff --git a/src/newt/classes/com/jogamp/newt/util/MainThread.java b/src/newt/classes/com/jogamp/newt/util/MainThread.java
index 5e79e9b49..80da1ce3b 100644
--- a/src/newt/classes/com/jogamp/newt/util/MainThread.java
+++ b/src/newt/classes/com/jogamp/newt/util/MainThread.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
@@ -45,6 +45,7 @@ import java.util.List;
import javax.media.nativewindow.NativeWindowFactory;
import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.PropertyAccess;
import com.jogamp.common.util.ReflectionUtil;
import jogamp.newt.Debug;
@@ -54,13 +55,13 @@ import jogamp.newt.NEWTJNILibLoader;
* NEWT Utility class MainThread<P>
*
* <p>
- * FIXME: Update this documentation!
+ * FIXME: Update this documentation!
* This class just provides a main-thread utility, forking of a main java class
* on another thread while being able to continue doing platform specific things
* on the main-thread. The latter is essential for eg. MacOSX, where we continue
* to run NSApp.run().
* </p>
- *
+ *
* This class provides a startup singleton <i>main thread</i>,
* from which a new thread with the users main class is launched.<br>
*
@@ -72,17 +73,17 @@ import jogamp.newt.NEWTJNILibLoader;
* use a NEWT multithreaded application with window handling within the different threads,
* even on these restricted platforms.<br>
*
- * To support your NEWT Window platform,
+ * To support your NEWT Window platform,
* you have to pass your <i>main thread</i> actions to {@link #invoke invoke(..)},
* have a look at the {@link jogamp.newt.driver.macosx.WindowDriver NEWT Mac OSX Window} driver implementation.<br>
- * <i>TODO</i>: Some hardcoded dependencies exist in this implementation,
+ * <i>TODO</i>: Some hardcoded dependencies exist in this implementation,
* where you have to patch this code or factor it out. <P>
- *
+ *
* If your platform is not Mac OS X, but you want to test your code without modifying
* this class, you have to set the system property <code>newt.MainThread.force</code> to <code>true</code>.<P>
*
* The code is compatible with all other platform, which support multithreaded windowing handling.
- * Since those platforms won't trigger the <i>main thread</i> serialization, the main method
+ * Since those platforms won't trigger the <i>main thread</i> serialization, the main method
* will be simply executed, in case you haven't set <code>newt.MainThread.force</code> to <code>true</code>.<P>
*
* Test case on Mac OS X (or any other platform):
@@ -96,36 +97,36 @@ public class MainThread {
private static final Platform.OSType osType;
private static final boolean isMacOSX;
private static final ThreadGroup rootThreadGroup;
-
+
/** if true, use the main thread EDT, otherwise AWT's EDT */
public static final boolean HINT_USE_MAIN_THREAD;
-
+
static {
NativeWindowFactory.initSingleton();
NEWTJNILibLoader.loadNEWT();
- HINT_USE_MAIN_THREAD = !NativeWindowFactory.isAWTAvailable() ||
- Debug.getBooleanProperty("newt.MainThread.force", true);
+ HINT_USE_MAIN_THREAD = !NativeWindowFactory.isAWTAvailable() ||
+ PropertyAccess.getBooleanProperty("newt.MainThread.force", true);
osType = Platform.getOSType();
isMacOSX = osType == Platform.OSType.MACOS;
rootThreadGroup = getRootThreadGroup();
}
-
+
public static boolean useMainThread = false;
-
+
protected static final boolean DEBUG = Debug.debug("MainThread");
private static final MainThread singletonMainThread = new MainThread(); // one singleton MainThread
-
+
private static final ThreadGroup getRootThreadGroup() {
ThreadGroup rootGroup = Thread.currentThread( ).getThreadGroup( );
ThreadGroup parentGroup;
while ( ( parentGroup = rootGroup.getParent() ) != null ) {
rootGroup = parentGroup;
}
- return rootGroup;
+ return rootGroup;
}
-
- private static final Thread[] getAllThreads(int[] count) {
+
+ private static final Thread[] getAllThreads(final int[] count) {
int tn;
Thread[] threads = new Thread[ rootThreadGroup.activeCount() ];
while ( ( tn = rootThreadGroup.enumerate( threads, true ) ) == threads.length ) {
@@ -135,9 +136,9 @@ public class MainThread {
return threads;
}
private static final List<Thread> getNonDaemonThreads() {
- List<Thread> res = new ArrayList<Thread>();
- int[] tn = { 0 };
- Thread[] threads = getAllThreads(tn);
+ final List<Thread> res = new ArrayList<Thread>();
+ final int[] tn = { 0 };
+ final Thread[] threads = getAllThreads(tn);
for(int i = tn[0] - 1; i >= 0; i--) {
final Thread thread = threads[i];
try {
@@ -145,31 +146,31 @@ public class MainThread {
res.add(thread);
if(DEBUG) System.err.println("XXX0: "+thread.getName()+", "+thread);
}
- } catch (Throwable t) {
+ } catch (final Throwable t) {
t.printStackTrace();
}
}
- return res;
+ return res;
}
- private static final int getNonDaemonThreadCount(List<Thread> ignoreThreads) {
+ private static final int getNonDaemonThreadCount(final List<Thread> ignoreThreads) {
int res = 0;
- int[] tn = { 0 };
- Thread[] threads = getAllThreads(tn);
-
+ final int[] tn = { 0 };
+ final Thread[] threads = getAllThreads(tn);
+
for(int i = tn[0] - 1; i >= 0; i--) {
final Thread thread = threads[i];
try {
- if(thread.isAlive() && !thread.isDaemon() && !ignoreThreads.contains(thread)) {
+ if(thread.isAlive() && !thread.isDaemon() && !ignoreThreads.contains(thread)) {
res++;
if(DEBUG) System.err.println("MainAction.run(): non daemon thread: "+thread);
}
- } catch (Throwable t) {
+ } catch (final Throwable t) {
t.printStackTrace();
}
}
- return res;
+ return res;
}
-
+
static class UserApp extends Thread {
private final String mainClassNameShort;
private final String mainClassName;
@@ -177,11 +178,11 @@ public class MainThread {
private final Method mainClassMain;
private List<Thread> nonDaemonThreadsAtStart;
- public UserApp(String mainClassName, String[] mainClassArgs) throws SecurityException, NoSuchMethodException, ClassNotFoundException {
+ public UserApp(final String mainClassName, final String[] mainClassArgs) throws SecurityException, NoSuchMethodException, ClassNotFoundException {
super();
this.mainClassName=mainClassName;
this.mainClassArgs=mainClassArgs;
-
+
final Class<?> mainClass = ReflectionUtil.getClass(mainClassName, true, getClass().getClassLoader());
if(null==mainClass) {
throw new ClassNotFoundException("MainAction couldn't find main class "+mainClassName);
@@ -192,7 +193,7 @@ public class MainThread {
setName(getName()+"-UserApp-"+mainClassNameShort);
setDaemon(false);
-
+
if(DEBUG) System.err.println("MainAction(): instantiated: "+getName()+", is daemon "+isDaemon()+", main-class: "+mainClass.getName());
}
@@ -204,10 +205,10 @@ public class MainThread {
try {
if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" invoke "+mainClassName);
mainClassMain.invoke(null, new Object[] { mainClassArgs } );
- } catch (InvocationTargetException ite) {
+ } catch (final InvocationTargetException ite) {
ite.getTargetException().printStackTrace();
return;
- } catch (Throwable t) {
+ } catch (final Throwable t) {
t.printStackTrace();
return;
}
@@ -219,7 +220,7 @@ public class MainThread {
if(DEBUG) System.err.println("MainAction.run(): post user app, non daemon threads alive: "+ndtr);
try {
Thread.sleep(1000);
- } catch (InterruptedException e) {
+ } catch (final InterruptedException e) {
e.printStackTrace();
}
}
@@ -230,32 +231,32 @@ public class MainThread {
if(isMacOSX) {
try {
if(DEBUG) {
- System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.0");
+ System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.0");
}
- ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "stopNSApplication",
+ ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "stopNSApplication",
null, null, MainThread.class.getClassLoader());
if(DEBUG) {
- System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.X");
+ System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.X");
}
- } catch (Exception e) {
+ } catch (final Exception e) {
e.printStackTrace();
}
} else {
if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainAction fin - System.exit(0)");
- System.exit(0);
- }
+ System.exit(0);
+ }
}
}
}
private static UserApp mainAction;
- /** Your new java application main entry, which pipelines your application
- * @throws ClassNotFoundException
- * @throws NoSuchMethodException
+ /** Your new java application main entry, which pipelines your application
+ * @throws ClassNotFoundException
+ * @throws NoSuchMethodException
* @throws SecurityException */
- public static void main(String[] args) throws SecurityException, NoSuchMethodException, ClassNotFoundException {
+ public static void main(final String[] args) throws SecurityException, NoSuchMethodException, ClassNotFoundException {
final Thread cur = Thread.currentThread();
-
+
useMainThread = HINT_USE_MAIN_THREAD;
if(DEBUG) {
@@ -268,13 +269,13 @@ public class MainThread {
if(!useMainThread && !NativeWindowFactory.isAWTAvailable()) {
throw new RuntimeException("!USE_MAIN_THREAD and no AWT available");
}
-
+
if(args.length==0) {
return;
}
- String mainClassName=args[0];
- String[] mainClassArgs=new String[args.length-1];
+ final String mainClassName=args[0];
+ final String[] mainClassArgs=new String[args.length-1];
if(args.length>1) {
System.arraycopy(args, 1, mainClassArgs, 0, args.length-1);
}
@@ -282,32 +283,32 @@ public class MainThread {
mainAction = new UserApp(mainClassName, mainClassArgs);
if(isMacOSX) {
- ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "initSingleton",
+ ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "initSingleton",
null, null, MainThread.class.getClassLoader());
}
if ( useMainThread ) {
try {
cur.setName(cur.getName()+"-MainThread");
- } catch (Exception e) {}
-
+ } catch (final Exception e) {}
+
// dispatch user's main thread ..
mainAction.start();
-
+
if(isMacOSX) {
try {
if(DEBUG) {
- System.err.println("MainThread.main(): "+cur.getName()+"- runNSApp");
+ System.err.println("MainThread.main(): "+cur.getName()+"- runNSApp");
}
- ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "runNSApplication",
+ ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "runNSApplication",
null, null, MainThread.class.getClassLoader());
- } catch (Exception e) {
+ } catch (final Exception e) {
e.printStackTrace();
}
- }
- if(DEBUG) { System.err.println("MainThread - wait until last non daemon thread ends ..."); }
+ }
+ if(DEBUG) { System.err.println("MainThread - wait until last non daemon thread ends ..."); }
} else {
- // run user's main in this thread
+ // run user's main in this thread
mainAction.run();
}
}
diff --git a/src/newt/classes/com/jogamp/newt/util/MonitorMode.java b/src/newt/classes/com/jogamp/newt/util/MonitorMode.java
deleted file mode 100644
index 8104f207a..000000000
--- a/src/newt/classes/com/jogamp/newt/util/MonitorMode.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * Copyright 2010 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 com.jogamp.newt.util;
-
-import javax.media.nativewindow.util.*;
-
-/** Immutable MonitorMode Class, consisting of it's read only components:<br>
- * <ul>
- * <li>{@link javax.media.nativewindow.util.SurfaceSize} surface memory size</li>
- * <li>{@link javax.media.nativewindow.util.DimensionImmutable} size in [mm]</li>
- * <li><code>refresh rate</code></li>
- * </ul>
- */
-public class MonitorMode {
- SurfaceSize surfaceSize;
- DimensionImmutable screenSizeMM; // in [mm]
- int refreshRate;
-
- public MonitorMode(SurfaceSize surfaceSize, DimensionImmutable screenSizeMM, int refreshRate) {
- // Don't validate screenSizeMM and refreshRate, since they may not be supported by the OS
- if(null==surfaceSize) {
- throw new IllegalArgumentException("surfaceSize must be set ("+surfaceSize+")");
- }
- this.surfaceSize=surfaceSize;
- this.screenSizeMM=screenSizeMM;
- this.refreshRate=refreshRate;
- }
-
- public final SurfaceSize getSurfaceSize() {
- return surfaceSize;
- }
-
- public final DimensionImmutable getScreenSizeMM() {
- return screenSizeMM;
- }
-
- public final int getRefreshRate() {
- return refreshRate;
- }
-
- public final String toString() {
- return new String("[ "+surfaceSize+" x "+refreshRate+" Hz, "+screenSizeMM+" mm ]");
- }
-
- /**
- * Checks whether two size objects are equal. Two instances
- * of <code>MonitorMode</code> are equal if the three components
- * <code>surfaceSize</code> and <code>refreshRate</code>
- * are equal. <code>screenSizeMM</code> is kept out intentional to reduce the requirements for finding the current mode.
- * @return <code>true</code> if the two dimensions are equal;
- * otherwise <code>false</code>.
- */
- public final boolean equals(Object obj) {
- if (this == obj) { return true; }
- if (obj instanceof MonitorMode) {
- MonitorMode p = (MonitorMode)obj;
- return getSurfaceSize().equals(p.getSurfaceSize()) &&
- /* getScreenSizeMM().equals(p.getScreenSizeMM()) && */
- getRefreshRate() == p.getRefreshRate() ;
- }
- return false;
- }
-
- /**
- * returns a hash code over <code>surfaceSize</code> and <code>refreshRate</code>.
- * <code>screenSizeMM</code> is kept out intentional to reduce the requirements for finding the current mode.
- */
- public final int hashCode() {
- // 31 * x == (x << 5) - x
- int hash = 31 + getSurfaceSize().hashCode();
- /* hash = ((hash << 5) - hash) + getScreenSizeMM().hashCode(); */
- hash = ((hash << 5) - hash) + getRefreshRate();
- return hash;
- }
-}
-
diff --git a/src/newt/classes/com/jogamp/newt/util/MonitorModeUtil.java b/src/newt/classes/com/jogamp/newt/util/MonitorModeUtil.java
new file mode 100644
index 000000000..e5f8ff17c
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/util/MonitorModeUtil.java
@@ -0,0 +1,258 @@
+/**
+ * Copyright 2010 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 com.jogamp.newt.util;
+
+import com.jogamp.newt.MonitorMode;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.media.nativewindow.util.DimensionImmutable;
+import javax.media.nativewindow.util.SurfaceSize;
+
+/**
+ * Convenient {@link com.jogamp.newt.MonitorMode} utility methods,
+ * filters etc.
+ */
+public class MonitorModeUtil {
+
+ public static int getIndex(final List<MonitorMode> monitorModes, final MonitorMode search) {
+ return monitorModes.indexOf(search);
+ }
+
+ public static int getIndexByHashCode(final List<MonitorMode> monitorModes, final MonitorMode search) {
+ if( null!=monitorModes && monitorModes.size()>0 ) {
+ for (int i=0; i<monitorModes.size(); i++) {
+ if ( search.hashCode() == monitorModes.get(i).hashCode() ) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ public static MonitorMode getByNativeSizeRateIdAndRotation(final List<MonitorMode> monitorModes, final MonitorMode.SizeAndRRate sizeAndRate, final int modeId, final int rotation) {
+ if( null!=monitorModes && monitorModes.size()>0 ) {
+ for (int i=0; i<monitorModes.size(); i++) {
+ final MonitorMode mode = monitorModes.get(i);
+ if( mode.getSizeAndRRate().equals(sizeAndRate) && mode.getId() == modeId && mode.getRotation() == rotation ) {
+ return mode;
+ }
+ }
+ }
+ return null;
+ }
+
+ /** Sort the given {@link MonitorMode} collection w/ {@link MonitorMode#compareTo(MonitorMode)} function. */
+ public static void sort(final List<MonitorMode> monitorModes, final boolean ascendingOrder) {
+ if( ascendingOrder ) {
+ Collections.sort(monitorModes);
+ } else {
+ Collections.sort(monitorModes, MonitorMode.monitorModeComparatorInv);
+ }
+ }
+
+ /**
+ *
+ * @param monitorModes
+ * @param surfaceSize
+ * @return modes with exact {@link SurfaceSize}. May return zero sized list for non.
+ */
+ public static List<MonitorMode> filterBySurfaceSize(final List<MonitorMode> monitorModes, final SurfaceSize surfaceSize) {
+ final List<MonitorMode> out = new ArrayList<MonitorMode>();
+ if( null!=monitorModes && monitorModes.size()>0 ) {
+ for (int i=0; null!=monitorModes && i<monitorModes.size(); i++) {
+ final MonitorMode mode = monitorModes.get(i);
+ if(mode.getSurfaceSize().equals(surfaceSize)) {
+ out.add(mode);
+ }
+ }
+ }
+ return out;
+ }
+
+ /**
+ *
+ * @param monitorModes
+ * @param rotation
+ * @return modes with exact rotation. May return zero sized list for non.
+ */
+ public static List<MonitorMode> filterByRotation(final List<MonitorMode> monitorModes, final int rotation) {
+ final List<MonitorMode> out = new ArrayList<MonitorMode>();
+ if( null!=monitorModes && monitorModes.size()>0 ) {
+ for (int i=0; null!=monitorModes && i<monitorModes.size(); i++) {
+ final MonitorMode mode = monitorModes.get(i);
+ if(mode.getRotation() == rotation) {
+ out.add(mode);
+ }
+ }
+ }
+ return out;
+ }
+
+ /**
+ *
+ * @param monitorModes
+ * @param bitsPerPixel
+ * @return modes with exact bpp. May return zero sized list for non.
+ */
+ public static List<MonitorMode> filterByBpp(final List<MonitorMode> monitorModes, final int bitsPerPixel) {
+ final List<MonitorMode> out = new ArrayList<MonitorMode>();
+ if( null!=monitorModes && monitorModes.size()>0 ) {
+ for (int i=0; null!=monitorModes && i<monitorModes.size(); i++) {
+ final MonitorMode mode = monitorModes.get(i);
+ if(mode.getSurfaceSize().getBitsPerPixel() == bitsPerPixel) {
+ out.add(mode);
+ }
+ }
+ }
+ return out;
+ }
+
+ /**
+ *
+ * @param monitorModes
+ * @param flags
+ * @return modes with exact flags. May return zero sized list for non.
+ */
+ public static List<MonitorMode> filterByFlags(final List<MonitorMode> monitorModes, final int flags) {
+ final List<MonitorMode> out = new ArrayList<MonitorMode>();
+ if( null!=monitorModes && monitorModes.size()>0 ) {
+ for (int i=0; null!=monitorModes && i<monitorModes.size(); i++) {
+ final MonitorMode mode = monitorModes.get(i);
+ if(mode.getFlags() == flags) {
+ out.add(mode);
+ }
+ }
+ }
+ return out;
+ }
+
+ /**
+ * @param monitorModes
+ * @param resolution in pixel units
+ * @return modes with nearest resolution, or matching ones. May return zero sized list for non.
+ */
+ public static List<MonitorMode> filterByResolution(final List<MonitorMode> monitorModes, final DimensionImmutable resolution) {
+ final List<MonitorMode> out = new ArrayList<MonitorMode>();
+ if( null!=monitorModes && monitorModes.size()>0 ) {
+ final int resolution_sq = resolution.getHeight()*resolution.getWidth();
+ int mode_dsq=Integer.MAX_VALUE, mode_dsq_idx=0;
+
+ for (int i=0; null!=monitorModes && i<monitorModes.size(); i++) {
+ final MonitorMode mode = monitorModes.get(i);
+ final DimensionImmutable res = mode.getSurfaceSize().getResolution();
+ final int dsq = Math.abs(resolution_sq - res.getHeight()*res.getWidth());
+ if(dsq<mode_dsq) {
+ mode_dsq = dsq;
+ mode_dsq_idx = i;
+ }
+ if(res.equals(resolution)) {
+ out.add(mode);
+ }
+ }
+ if(out.size() == 0 && 0 <= mode_dsq_idx ) {
+ // nearest ..
+ out.add(monitorModes.get(mode_dsq_idx));
+ }
+ }
+ return out;
+ }
+
+ /**
+ *
+ * @param monitorModes
+ * @param refreshRate
+ * @return modes with nearest refreshRate, or matching ones. May return zero sized list for non.
+ */
+ public static List<MonitorMode> filterByRate(final List<MonitorMode> monitorModes, final float refreshRate) {
+ final List<MonitorMode> out = new ArrayList<MonitorMode>();
+ if( null!=monitorModes && monitorModes.size()>0 ) {
+ float mode_dr = Float.MAX_VALUE;
+ int mode_dr_idx = -1;
+ for (int i=0; null!=monitorModes && i<monitorModes.size(); i++) {
+ final MonitorMode mode = monitorModes.get(i);
+ final float dr = Math.abs(refreshRate - mode.getRefreshRate());
+ if(dr<mode_dr) {
+ mode_dr = dr;
+ mode_dr_idx = i;
+ }
+ if(0 == dr) {
+ out.add(mode);
+ }
+ }
+ if(out.size() == 0 && 0 <= mode_dr_idx ) {
+ // nearest ..
+ out.add(monitorModes.get(mode_dr_idx));
+ }
+ }
+ return out;
+ }
+
+ /**
+ * @param monitorModes
+ * @return modes with highest available bpp (color depth). May return zero sized list for non.
+ */
+ public static List<MonitorMode> getHighestAvailableBpp(final List<MonitorMode> monitorModes) {
+ if( null!=monitorModes && monitorModes.size()>0 ) {
+ int highest = -1;
+ for (int i=0; null!=monitorModes && i < monitorModes.size(); i++) {
+ final MonitorMode mode = monitorModes.get(i);
+ final int bpp = mode.getSurfaceSize().getBitsPerPixel();
+ if (bpp > highest) {
+ highest = bpp;
+ }
+ }
+ return filterByBpp(monitorModes, highest);
+ }
+ return new ArrayList<MonitorMode>();
+ }
+
+ /**
+ *
+ * @param monitorModes
+ * @return modes with highest available refresh rate. May return zero sized list for non.
+ */
+ public static List<MonitorMode> getHighestAvailableRate(final List<MonitorMode> monitorModes) {
+ if( null!=monitorModes && monitorModes.size()>0 ) {
+ float highest = -1;
+ for (int i=0; null!=monitorModes && i < monitorModes.size(); i++) {
+ final MonitorMode mode = monitorModes.get(i);
+ final float rate = mode.getRefreshRate();
+ if (rate > highest) {
+ highest = rate;
+ }
+ }
+ return filterByRate(monitorModes, highest);
+ }
+ return new ArrayList<MonitorMode>();
+ }
+
+}
diff --git a/src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java b/src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java
deleted file mode 100644
index 93797c5fb..000000000
--- a/src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/**
- * Copyright 2010 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 com.jogamp.newt.util;
-
-import com.jogamp.common.util.ArrayHashSet;
-import com.jogamp.newt.ScreenMode;
-import java.util.ArrayList;
-import java.util.List;
-import javax.media.nativewindow.util.Dimension;
-import javax.media.nativewindow.util.DimensionImmutable;
-import javax.media.nativewindow.util.SurfaceSize;
-
-/**
- * Convenient {@link com.jogamp.newt.ScreenMode} utility methods,
- * filters etc.
- */
-public class ScreenModeUtil {
- /** WARNING: must be synchronized with ScreenMode.h, native implementation
- * 2: width and height
- */
- public static final int NUM_RESOLUTION_PROPERTIES = 2;
-
- /** WARNING: must be synchronized with ScreenMode.h, native implementation
- * 1: bpp
- */
- public static final int NUM_SURFACE_SIZE_PROPERTIES = 1;
-
- /** WARNING: must be synchronized with ScreenMode.h, native implementation
- * 3: ScreenSizeMM[width, height], refresh-rate
- */
- public static final int NUM_MONITOR_MODE_PROPERTIES = 3;
-
- /** WARNING: must be synchronized with ScreenMode.h, native implementation
- * 1: rotation, native_mode_id
- */
- public static final int NUM_SCREEN_MODE_PROPERTIES = 1;
-
- /** WARNING: must be synchronized with ScreenMode.h, native implementation
- * count + all the above
- */
- public static final int NUM_SCREEN_MODE_PROPERTIES_ALL = 8;
-
- public static int getIndex(List<ScreenMode> screenModes, ScreenMode search) {
- return screenModes.indexOf(search);
- }
-
- public static int getIndexByHashCode(List<ScreenMode> screenModes, ScreenMode search) {
- for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
- if ( search.hashCode() == screenModes.get(i).hashCode() ) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * @param screenModes
- * @param resolution
- * @return modes with nearest resolution, or matching ones
- */
- public static List<ScreenMode> filterByResolution(List<ScreenMode> screenModes, DimensionImmutable resolution) {
- if(null==screenModes || screenModes.size()==0) {
- return null;
- }
- List<ScreenMode> out = new ArrayList<ScreenMode>();
- int resolution_sq = resolution.getHeight()*resolution.getWidth();
- int sm_dsq=resolution_sq, sm_dsq_idx=0;
-
- for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
- ScreenMode sm = screenModes.get(i);
- DimensionImmutable res = sm.getMonitorMode().getSurfaceSize().getResolution();
- int dsq = Math.abs(resolution_sq - res.getHeight()*res.getWidth());
- if(dsq<sm_dsq) {
- sm_dsq = dsq;
- sm_dsq_idx = i;
- }
- if(res.equals(resolution)) {
- out.add(sm);
- }
- }
- if(out.size()>0) {
- return out;
- }
- // nearest ..
- resolution = screenModes.get(sm_dsq_idx).getMonitorMode().getSurfaceSize().getResolution();
- return filterByResolution(screenModes, resolution);
- }
-
- public static List<ScreenMode> filterBySurfaceSize(List<ScreenMode> screenModes, SurfaceSize surfaceSize) {
- if(null==screenModes || screenModes.size()==0) {
- return null;
- }
- List<ScreenMode> out = new ArrayList<ScreenMode>();
- for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
- ScreenMode sm = screenModes.get(i);
- if(sm.getMonitorMode().getSurfaceSize().equals(surfaceSize)) {
- out.add(sm);
- }
- }
- return out.size()>0 ? out : null;
- }
-
- public static List<ScreenMode> filterByRotation(List<ScreenMode> screenModes, int rotation) {
- if(null==screenModes || screenModes.size()==0) {
- return null;
- }
- List<ScreenMode> out = new ArrayList<ScreenMode>();
- for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
- ScreenMode sm = screenModes.get(i);
- if(sm.getRotation() == rotation) {
- out.add(sm);
- }
- }
- return out.size()>0 ? out : null;
- }
-
- public static List<ScreenMode> filterByBpp(List<ScreenMode> screenModes, int bitsPerPixel) {
- if(null==screenModes || screenModes.size()==0) {
- return null;
- }
- List<ScreenMode> out = new ArrayList<ScreenMode>();
- for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
- ScreenMode sm = screenModes.get(i);
- if(sm.getMonitorMode().getSurfaceSize().getBitsPerPixel() == bitsPerPixel) {
- out.add(sm);
- }
- }
- return out.size()>0 ? out : null;
- }
-
- /**
- *
- * @param screenModes
- * @param refreshRate
- * @return modes with nearest refreshRate, or matching ones
- */
- public static List<ScreenMode> filterByRate(List<ScreenMode> screenModes, int refreshRate) {
- if(null==screenModes || screenModes.size()==0) {
- return null;
- }
- int sm_dr = refreshRate;
- int sm_dr_idx = -1;
- List<ScreenMode> out = new ArrayList<ScreenMode>();
- for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
- ScreenMode sm = screenModes.get(i);
- int dr = Math.abs(refreshRate - sm.getMonitorMode().getRefreshRate());
- if(dr<sm_dr) {
- sm_dr = dr;
- sm_dr_idx = i;
- }
- if(0 == dr) {
- out.add(sm);
- }
- }
- if(out.size()>0) {
- return out;
- }
- refreshRate = screenModes.get(sm_dr_idx).getMonitorMode().getRefreshRate();
- return filterByRate(screenModes, refreshRate);
- }
-
- public static List<ScreenMode> getHighestAvailableBpp(List<ScreenMode> screenModes) {
- if(null==screenModes || screenModes.size()==0) {
- return null;
- }
- int highest = -1;
- for (int i=0; null!=screenModes && i < screenModes.size(); i++) {
- ScreenMode sm = screenModes.get(i);
- int bpp = sm.getMonitorMode().getSurfaceSize().getBitsPerPixel();
- if (bpp > highest) {
- highest = bpp;
- }
- }
- return filterByBpp(screenModes, highest);
- }
-
- public static List<ScreenMode> getHighestAvailableRate(List<ScreenMode> screenModes) {
- if(null==screenModes || screenModes.size()==0) {
- return null;
- }
- int highest = -1;
- for (int i=0; null!=screenModes && i < screenModes.size(); i++) {
- ScreenMode sm = screenModes.get(i);
- int rate = sm.getMonitorMode().getRefreshRate();
- if (rate > highest) {
- highest = rate;
- }
- }
- return filterByRate(screenModes, highest);
- }
-
- /** WARNING: must be synchronized with ScreenMode.h, native implementation */
- public static DimensionImmutable streamInResolution(int[] resolutionProperties, int offset) {
- Dimension resolution = new Dimension(resolutionProperties[offset++], resolutionProperties[offset++]);
- return resolution;
- }
-
- /** WARNING: must be synchronized with ScreenMode.h, native implementation */
- public static SurfaceSize streamInSurfaceSize(DimensionImmutable resolution, int[] sizeProperties, int offset) {
- SurfaceSize surfaceSize = new SurfaceSize(resolution, sizeProperties[offset++]);
- return surfaceSize;
- }
-
- /** WARNING: must be synchronized with ScreenMode.h, native implementation */
- public static MonitorMode streamInMonitorMode(SurfaceSize surfaceSize, DimensionImmutable screenSizeMM, int[] monitorProperties, int offset) {
- int refreshRate = monitorProperties[offset++];
- return new MonitorMode(surfaceSize, screenSizeMM, refreshRate);
- }
-
- /** WARNING: must be synchronized with ScreenMode.h, native implementation */
- public static ScreenMode streamInScreenMode(MonitorMode monitorMode, int[] modeProperties, int offset) {
- int rotation = modeProperties[offset++];
- return new ScreenMode(monitorMode, rotation);
- }
-
- /**
- * WARNING: must be synchronized with ScreenMode.h, native implementation
- *
- * @param modeProperties the input data
- * @param offset the offset to the input data
- * @return ScreenMode element matching the input <code>modeProperties</code>,
- * or null if input could not be processed.
- */
- public static ScreenMode streamIn(int[] modeProperties, int offset) {
- return streamInImpl(null, null, null, null, null, modeProperties, offset);
- }
-
- /**
- * WARNING: must be synchronized with ScreenMode.h, native implementation
- *
- * @param resolutionPool hash array of unique resolutions, no duplicates
- * @param surfaceSizePool hash array of unique SurfaceSize, no duplicates
- * @param monitorModePool hash array of unique MonitorMode, no duplicates
- * @param screenModePool hash array of unique ScreenMode, no duplicates
- * @param modeProperties the input data
- * @param offset the offset to the input data
- * @return index of the identical (old or new) ScreenMode element in <code>screenModePool</code>,
- * matching the input <code>modeProperties</code>, or -1 if input could not be processed.
- */
- public static int streamIn(ArrayHashSet<DimensionImmutable> resolutionPool,
- ArrayHashSet<SurfaceSize> surfaceSizePool,
- ArrayHashSet<DimensionImmutable> screenSizeMMPool,
- ArrayHashSet<MonitorMode> monitorModePool,
- ArrayHashSet<ScreenMode> screenModePool,
- int[] modeProperties, int offset) {
- ScreenMode screenMode = streamInImpl(resolutionPool, surfaceSizePool, screenSizeMMPool, monitorModePool, screenModePool,
- modeProperties, offset);
- return screenModePool.indexOf(screenMode);
- }
-
-
- private static ScreenMode streamInImpl(ArrayHashSet<DimensionImmutable> resolutionPool,
- ArrayHashSet<SurfaceSize> surfaceSizePool,
- ArrayHashSet<DimensionImmutable> screenSizeMMPool,
- ArrayHashSet<MonitorMode> monitorModePool,
- ArrayHashSet<ScreenMode> screenModePool,
- int[] modeProperties, int offset) {
- int count = modeProperties[offset];
- if(NUM_SCREEN_MODE_PROPERTIES_ALL != count) {
- throw new RuntimeException("NUM_SCREEN_MODE_PROPERTIES should be "+NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+count+", len "+(modeProperties.length-offset));
- }
- if(NUM_SCREEN_MODE_PROPERTIES_ALL > modeProperties.length-offset) {
- throw new RuntimeException("properties array too short, should be >= "+NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+(modeProperties.length-offset));
- }
- offset++;
- DimensionImmutable resolution = ScreenModeUtil.streamInResolution(modeProperties, offset);
- offset += ScreenModeUtil.NUM_RESOLUTION_PROPERTIES;
- if(null!=resolutionPool) {
- resolution = resolutionPool.getOrAdd(resolution);
- }
-
- SurfaceSize surfaceSize = ScreenModeUtil.streamInSurfaceSize(resolution, modeProperties, offset);
- offset += ScreenModeUtil.NUM_SURFACE_SIZE_PROPERTIES;
- if(null!=surfaceSizePool) {
- surfaceSize = surfaceSizePool.getOrAdd(surfaceSize);
- }
-
- DimensionImmutable screenSizeMM = ScreenModeUtil.streamInResolution(modeProperties, offset);
- offset += ScreenModeUtil.NUM_RESOLUTION_PROPERTIES;
- if(null!=screenSizeMMPool) {
- screenSizeMM = screenSizeMMPool.getOrAdd(screenSizeMM);
- }
-
- MonitorMode monitorMode = ScreenModeUtil.streamInMonitorMode(surfaceSize, screenSizeMM, modeProperties, offset);
- offset += ScreenModeUtil.NUM_MONITOR_MODE_PROPERTIES - ScreenModeUtil.NUM_RESOLUTION_PROPERTIES;
- if(null!=monitorModePool) {
- monitorMode = monitorModePool.getOrAdd(monitorMode);
- }
-
- ScreenMode screenMode = ScreenModeUtil.streamInScreenMode(monitorMode, modeProperties, offset);
- if(null!=screenModePool) {
- screenMode = screenModePool.getOrAdd(screenMode);
- }
- return screenMode;
- }
-
- /** WARNING: must be synchronized with ScreenMode.h, native implementation */
- public static int[] streamOut (ScreenMode screenMode) {
- int[] data = new int[NUM_SCREEN_MODE_PROPERTIES_ALL];
- int idx=0;
- data[idx++] = NUM_SCREEN_MODE_PROPERTIES_ALL;
- data[idx++] = screenMode.getMonitorMode().getSurfaceSize().getResolution().getWidth();
- data[idx++] = screenMode.getMonitorMode().getSurfaceSize().getResolution().getHeight();
- data[idx++] = screenMode.getMonitorMode().getSurfaceSize().getBitsPerPixel();
- data[idx++] = screenMode.getMonitorMode().getScreenSizeMM().getWidth();
- data[idx++] = screenMode.getMonitorMode().getScreenSizeMM().getHeight();
- data[idx++] = screenMode.getMonitorMode().getRefreshRate();
- data[idx++] = screenMode.getRotation();
- if(NUM_SCREEN_MODE_PROPERTIES_ALL != idx) {
- throw new InternalError("wrong number of attributes: got "+idx+" != should "+NUM_SCREEN_MODE_PROPERTIES_ALL);
- }
- return data;
- }
-
-}
diff --git a/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtApplet3Run.java b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtApplet3Run.java
new file mode 100644
index 000000000..9a3e79a8f
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtApplet3Run.java
@@ -0,0 +1,360 @@
+/**
+ * Copyright 2011 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 com.jogamp.newt.util.applet;
+
+import java.util.Locale;
+
+import com.jogamp.plugin.applet.Applet3;
+import com.jogamp.plugin.applet.Applet3Context;
+import com.jogamp.plugin.ui.NativeWindowDownstream;
+import com.jogamp.plugin.ui.NativeWindowUpstream;
+
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.AbstractGraphicsScreen;
+import javax.media.nativewindow.NativeWindow;
+import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode;
+import javax.media.nativewindow.util.PointImmutable;
+import javax.media.opengl.FPSCounter;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.nativewindow.UpstreamWindowHookMutableSizePos;
+import com.jogamp.newt.NewtFactory;
+import com.jogamp.newt.Window;
+import com.jogamp.newt.opengl.GLWindow;
+
+/**
+ * Simple GLEventListener deployment as an applet using JOGL. This demo must be
+ * referenced from a web page via an &lt;applet&gt; tag.
+ *
+ * <p>
+ * Example of an applet tag using GearsES2 within the applet area (normal case):
+ * <pre>
+ &lt;applet width=100 height=100&gt;
+ &lt;param name="java_arguments" value="-Dsun.java2d.noddraw=true"&gt;
+ &lt;param name="gl_event_listener_class" value="com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2"&gt;
+ &lt;param name="gl_profile" value="GL2"&gt;
+ &lt;param name="gl_swap_interval" value="1"&gt;
+ &lt;param name="gl_debug" value="false"&gt;
+ &lt;param name="gl_trace" value="false"&gt;
+ &lt;param name="jnlp_href" value="jogl-newt-applet-runner.jnlp"&gt;
+ &lt;/applet&gt;Hello Gears !
+ * </pre>
+ * </p>
+ *
+ * <p>
+ * Example of an applet tag using GearsES2 in an undecorated, translucent, closeable and always-on-top window:
+ * <pre>
+ &lt;applet width=1 height=1&gt;
+ &lt;param name="java_arguments" value="-Dsun.java2d.noddraw=true"&gt;
+ &lt;param name="gl_event_listener_class" value="com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2"&gt;
+ &lt;param name="gl_profile" value="GL2"&gt;
+ &lt;param name="gl_swap_interval" value="1"&gt;
+ &lt;param name="gl_undecorated" value="true"&gt;
+ &lt;param name="gl_alwaysontop" value="true"&gt;
+ &lt;param name="gl_closeable" value="true"&gt;
+ &lt;param name="gl_alpha" value="1"&gt;
+ &lt;param name="gl_multisamplebuffer" value="0"&gt;
+ &lt;param name="gl_opaque" value="false"&gt;
+ &lt;param name="gl_dx" value="10"&gt;
+ &lt;param name="gl_dy" value="0"&gt;
+ &lt;param name="gl_width" value="100"&gt;
+ &lt;param name="gl_height" value="100"&gt;
+ &lt;param name="gl_nodefaultkeyListener" value="true"&gt;
+ &lt;param name="gl_debug" value="false"&gt;
+ &lt;param name="gl_trace" value="false"&gt;
+ &lt;param name="jnlp_href" value="jogl-newt-applet-runner.jnlp"&gt;
+ &lt;/applet&gt;Hello Gears !
+ * </pre>
+ * </p>
+ */
+public class JOGLNewtApplet3Run implements Applet3 {
+ public static final boolean DEBUG = JOGLNewtAppletBase.DEBUG;
+
+ GLWindow glWindow = null;
+ JOGLNewtAppletBase base = null;
+ /** if valid glStandalone:=true (own window) ! */
+ int glXd=Integer.MAX_VALUE, glYd=Integer.MAX_VALUE, glWidth=Integer.MAX_VALUE, glHeight=Integer.MAX_VALUE;
+ Applet3Context ctx;
+ boolean glStandalone = false;
+ UpstreamWindowHookMutableSizePos upstreamSizePosHook;
+ PointImmutable upstreamLocOnScreen;
+ NativeWindow browserWin;
+
+ final String getParameter(final String name) {
+ return ctx.getParameter(name);
+ }
+
+ @Override
+ public NativeWindowDownstream createNativeWindow(final Applet3Context ctx, final NativeWindowUpstream upstreamWin) {
+ this.ctx = ctx;
+
+ String glProfileName=null;
+ boolean glOpaque=true;
+ int glAlphaBits=0;
+ int glNumMultisampleBuffer=0;
+ boolean glUndecorated=false;
+ boolean glAlwaysOnTop=false;
+ try {
+ glProfileName = getParameter("gl_profile");
+ glOpaque = JOGLNewtAppletBase.str2Bool(getParameter("gl_opaque"), glOpaque);
+ glAlphaBits = JOGLNewtAppletBase.str2Int(getParameter("gl_alpha"), glAlphaBits);
+ glNumMultisampleBuffer = JOGLNewtAppletBase.str2Int(getParameter("gl_multisamplebuffer"), glNumMultisampleBuffer);
+ glXd = JOGLNewtAppletBase.str2Int(getParameter("gl_dx"), glXd);
+ glYd = JOGLNewtAppletBase.str2Int(getParameter("gl_dy"), glYd);
+ glWidth = JOGLNewtAppletBase.str2Int(getParameter("gl_width"), glWidth);
+ glHeight = JOGLNewtAppletBase.str2Int(getParameter("gl_height"), glHeight);
+ glUndecorated = JOGLNewtAppletBase.str2Bool(getParameter("gl_undecorated"), glUndecorated);
+ glAlwaysOnTop = JOGLNewtAppletBase.str2Bool(getParameter("gl_alwaysontop"), glAlwaysOnTop);
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ glStandalone = Integer.MAX_VALUE>glXd && Integer.MAX_VALUE>glYd && Integer.MAX_VALUE>glWidth && Integer.MAX_VALUE>glHeight;
+ final GLCapabilities caps = new GLCapabilities(GLProfile.get(glProfileName));
+ caps.setAlphaBits(glAlphaBits);
+ if(0<glNumMultisampleBuffer) {
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(glNumMultisampleBuffer);
+ }
+ caps.setBackgroundOpaque(glOpaque);
+
+ final AbstractGraphicsDevice aDevice = NativeWindowFactory.createDevice(upstreamWin.getDisplayConnection(),
+ true /* own */); // open and own! (for upstreamLocOnScreen)
+ final AbstractGraphicsScreen aScreen = NativeWindowFactory.createScreen(aDevice, upstreamWin.getScreenIndex());
+ upstreamSizePosHook = new UpstreamWindowHookMutableSizePos(upstreamWin.getX(), upstreamWin.getY(),
+ upstreamWin.getWidth(), upstreamWin.getHeight(),
+ upstreamWin.getWidth(), upstreamWin.getHeight()); // FIXME: pixel-dim == window-dim 'for now' ?
+ browserWin = NativeWindowFactory.createWrappedWindow(aScreen, 0 /* surfaceHandle */, upstreamWin.getWindowHandle(),
+ upstreamSizePosHook);
+ upstreamLocOnScreen = NativeWindowFactory.getLocationOnScreen(browserWin);
+ if(DEBUG) {
+ System.err.println("JOGLNewtApplet3Run Configuration:");
+ System.err.println("glStandalone: "+glStandalone);
+ System.err.println("glProfileName: "+glProfileName);
+ System.err.println("glOpaque: "+glOpaque);
+ System.err.println("glAlphaBits: "+glAlphaBits);
+ System.err.println("glNumMultisampleBuffer: "+glNumMultisampleBuffer);
+ System.err.println("glUndecorated: "+glUndecorated);
+ System.err.println("glAlwaysOnTop: "+glAlwaysOnTop);
+ System.err.println("UpstreamWin: "+upstreamWin+", LOS "+upstreamLocOnScreen);
+ if(glStandalone) {
+ System.err.println("pos-size: "+glXd+"/"+glYd+" "+glWidth+"x"+glHeight);
+ }
+ }
+
+ final Window w = NewtFactory.createWindow(glStandalone ? null : browserWin, caps);
+ glWindow = GLWindow.create(w);
+ glWindow.setUndecorated(glUndecorated);
+ glWindow.setAlwaysOnTop(glAlwaysOnTop);
+ glWindow.setSize(browserWin.getWidth(), browserWin.getHeight());
+
+ return new NativeWindowDownstream() {
+ @Override
+ public void setVisible(final boolean v) {
+ if( null != glWindow ) {
+ glWindow.setVisible(v);
+ }
+ }
+
+ @Override
+ public void setSize(final int width, final int height) {
+ upstreamSizePosHook.setWinSize(width, height);
+ if( null != glWindow ) {
+ glWindow.setSize(width, height);
+ }
+ }
+
+ @Override
+ public void requestFocus() {
+ if( null != glWindow ) {
+ glWindow.requestFocus();
+ }
+ }
+
+ @Override
+ public void destroy() {
+ if( null != glWindow ) {
+ glWindow.destroy();
+ }
+ }
+
+ @Override
+ public NativeWindowUpstream getParent() {
+ return upstreamWin;
+ }
+
+ @Override
+ public long getWindowHandle() {
+ if( null != glWindow ) {
+ return glWindow.getWindowHandle();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public void display() {
+ if( null != glWindow ) {
+ glWindow.display();
+ }
+ }
+
+ @Override
+ public void notifyPositionChanged(final NativeWindowUpstream nw) {
+ upstreamSizePosHook.setWinPos(nw.getX(), nw.getY());
+ if( null != glWindow ) {
+ glWindow.setPosition(nw.getX(), nw.getY());
+ }
+ }
+ };
+ }
+
+ @Override
+ public void init(final Applet3Context ctx) {
+ if(DEBUG) {
+ System.err.println("JOGLNewtApplet1Run.init() START - "+currentThreadName());
+ }
+ this.ctx = ctx;
+ String glEventListenerClazzName=null;
+ int glSwapInterval=0;
+ boolean glDebug=false;
+ boolean glTrace=false;
+ boolean glNoDefaultKeyListener = false;
+ boolean glCloseable=false;
+
+ try {
+ glEventListenerClazzName = getParameter("gl_event_listener_class");
+ glSwapInterval = JOGLNewtAppletBase.str2Int(getParameter("gl_swap_interval"), glSwapInterval);
+ glDebug = JOGLNewtAppletBase.str2Bool(getParameter("gl_debug"), glDebug);
+ glTrace = JOGLNewtAppletBase.str2Bool(getParameter("gl_trace"), glTrace);
+ glNoDefaultKeyListener = JOGLNewtAppletBase.str2Bool(getParameter("gl_nodefaultkeyListener"), glNoDefaultKeyListener);
+ glCloseable = JOGLNewtAppletBase.str2Bool(getParameter("gl_closeable"), glCloseable);
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ if(null==glEventListenerClazzName) {
+ throw new RuntimeException("No applet parameter 'gl_event_listener_class'");
+ }
+ if(DEBUG) {
+ System.err.println("JOGLNewtApplet1Run Configuration:");
+ System.err.println("glEventListenerClazzName: "+glEventListenerClazzName);
+ System.err.println("glSwapInterval: "+glSwapInterval);
+ System.err.println("glDebug: "+glDebug);
+ System.err.println("glTrace: "+glTrace);
+ System.err.println("glNoDefaultKeyListener: "+glNoDefaultKeyListener);
+ System.err.println("glCloseable: "+glCloseable);
+ }
+
+ base = new JOGLNewtAppletBase(glEventListenerClazzName,
+ glSwapInterval,
+ glNoDefaultKeyListener,
+ glCloseable,
+ glDebug,
+ glTrace);
+
+ try {
+ glWindow.setUpdateFPSFrames(FPSCounter.DEFAULT_FRAMES_PER_INTERVAL, System.err);
+ glWindow.setDefaultCloseOperation(glCloseable ? WindowClosingMode.DISPOSE_ON_CLOSE : WindowClosingMode.DO_NOTHING_ON_CLOSE);
+ base.init(glWindow);
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ if(DEBUG) {
+ System.err.println("JOGLNewtApplet1Run.init() END - "+currentThreadName());
+ }
+ }
+
+ private static String currentThreadName() { return "["+Thread.currentThread().getName()+"]"; }
+
+ @Override
+ public void start() {
+ if(DEBUG) {
+ System.err.println("JOGLNewtApplet1Run.start() START (isVisible "+glWindow.isVisible()+") - "+currentThreadName());
+ }
+ if( glStandalone ) {
+ glWindow.setSize(glWidth, glHeight);
+ glWindow.setPosition(upstreamLocOnScreen.getX()+glXd, upstreamLocOnScreen.getY()+glYd);
+ glWindow.setVisible(true);
+ glWindow.requestFocus();
+ }
+ if(DEBUG) {
+ System.err.println("JOGLNewtApplet1Run start:");
+ System.err.println("GLWindow Pos: "+glWindow.getX()+"/"+glWindow.getY()+" rel, "+glWindow.getLocationOnScreen(null)+" screen");
+ System.err.println("GLWindow: "+glWindow);
+ }
+ base.start();
+ if(DEBUG) {
+ System.err.println("JOGLNewtApplet1Run.start() END - "+currentThreadName());
+ }
+ }
+
+ @Override
+ public void stop() {
+ if(DEBUG) {
+ System.err.println("JOGLNewtApplet1Run.stop() START - "+currentThreadName());
+ }
+ base.stop();
+ if(DEBUG) {
+ System.err.println("JOGLNewtApplet1Run.stop() END - "+currentThreadName());
+ }
+ }
+
+ @Override
+ public void destroy() {
+ if(DEBUG) {
+ System.err.println("JOGLNewtApplet1Run.destroy() START - "+currentThreadName());
+ }
+ glWindow.setVisible(false); // hide 1st
+ base.destroy(); // destroy glWindow unrecoverable
+ base=null;
+ glWindow=null;
+ browserWin.destroy(); // make sure the open display connection gets closed!
+ browserWin = null;
+ if(DEBUG) {
+ System.err.println("JOGLNewtApplet1Run.destroy() END - "+currentThreadName());
+ }
+ }
+
+ @Override
+ public String getAppletInfo() {
+ return null;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public String[][] getParameterInfo() {
+ return null;
+ }
+
+}
+
diff --git a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
index 082c01c23..d40e09d96 100755..100644
--- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java
+++ b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
@@ -25,7 +25,7 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
-package com.jogamp.newt.awt.applet;
+package com.jogamp.newt.util.applet;
import java.lang.reflect.Field;
import java.security.AccessController;
@@ -33,6 +33,7 @@ import java.security.PrivilegedAction;
import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode;
+import javax.media.nativewindow.util.InsetsImmutable;
import javax.media.opengl.FPSCounter;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
@@ -41,6 +42,10 @@ import javax.media.opengl.GLPipelineFactory;
import jogamp.newt.Debug;
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.newt.Display;
+import com.jogamp.newt.Window;
+import com.jogamp.newt.Display.PointerIcon;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.MouseListener;
@@ -49,6 +54,7 @@ import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.event.WindowListener;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.util.Animator;
+import com.jogamp.opengl.util.AnimatorBase;
/** Shows how to deploy an applet using JOGL. This demo must be
@@ -56,27 +62,28 @@ import com.jogamp.opengl.util.Animator;
public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
public static final boolean DEBUG = Debug.debug("Applet");
-
+
String glEventListenerClazzName;
int glSwapInterval;
boolean noDefaultKeyListener;
boolean glClosable;
boolean glDebug;
boolean glTrace;
+ PointerIcon pointerIconTest = null;
GLEventListener glEventListener = null;
GLWindow glWindow = null;
Animator glAnimator=null;
boolean isValid = false;
- NativeWindow awtParent;
-
- public JOGLNewtAppletBase(String glEventListenerClazzName,
- int glSwapInterval,
- boolean noDefaultKeyListener,
- boolean glClosable,
- boolean glDebug,
- boolean glTrace) {
-
+ NativeWindow parentWin;
+
+ public JOGLNewtAppletBase(final String glEventListenerClazzName,
+ final int glSwapInterval,
+ final boolean noDefaultKeyListener,
+ final boolean glClosable,
+ final boolean glDebug,
+ final boolean glTrace) {
+
this.glEventListenerClazzName=glEventListenerClazzName;
this.glSwapInterval=glSwapInterval;
this.noDefaultKeyListener = noDefaultKeyListener;
@@ -90,19 +97,19 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
public Animator getGLAnimator() { return glAnimator; }
public boolean isValid() { return isValid; }
- public static boolean str2Bool(String str, boolean def) {
+ public static boolean str2Bool(final String str, final boolean def) {
if(null==str) return def;
try {
return Boolean.valueOf(str).booleanValue();
- } catch (Exception ex) { ex.printStackTrace(); }
+ } catch (final Exception ex) { ex.printStackTrace(); }
return def;
}
- public static int str2Int(String str, int def) {
+ public static int str2Int(final String str, final int def) {
if(null==str) return def;
try {
return Integer.parseInt(str);
- } catch (Exception ex) { ex.printStackTrace(); }
+ } catch (final Exception ex) { ex.printStackTrace(); }
return def;
}
@@ -111,19 +118,20 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
try {
final Class<?> clazz = AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
+ @Override
public Class<?> run() {
final ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class<?> clazz = null;
try {
clazz = Class.forName(clazzName, false, cl);
- } catch (Throwable t) {
+ } catch (final Throwable t) {
t.printStackTrace();
}
return clazz;
}
});
instance = clazz.newInstance();
- } catch (Throwable t) {
+ } catch (final Throwable t) {
t.printStackTrace();
throw new RuntimeException("Error while instantiating demo: "+clazzName);
}
@@ -136,46 +144,30 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
return (GLEventListener) instance;
}
- public static boolean setField(Object instance, String fieldName, Object value) {
+ public static boolean setField(final Object instance, final String fieldName, final Object value) {
try {
- Field f = instance.getClass().getField(fieldName);
+ final Field f = instance.getClass().getField(fieldName);
if(f.getType().isInstance(value)) {
f.set(instance, value);
return true;
} else {
System.out.println(instance.getClass()+" '"+fieldName+"' field not assignable with "+value.getClass()+", it's a: "+f.getType());
}
- } catch (NoSuchFieldException nsfe) {
+ } catch (final NoSuchFieldException nsfe) {
System.out.println(instance.getClass()+" has no '"+fieldName+"' field");
- } catch (Throwable t) {
+ } catch (final Throwable t) {
t.printStackTrace();
}
return false;
}
- public void init(GLWindow glWindow) {
+ public void init(final GLWindow glWindow) {
init(Thread.currentThread().getThreadGroup(), glWindow);
}
- public void init(ThreadGroup tg, final GLWindow glWindow) {
+ public void init(final ThreadGroup tg, final GLWindow glWindow) {
isValid = false;
this.glWindow = glWindow;
- this.glWindow.addWindowListener(new WindowAdapter() {
- // Closing action: back to parent!
- @Override
- public void windowDestroyNotify(WindowEvent e) {
- if( WindowClosingMode.DO_NOTHING_ON_CLOSE == glWindow.getDefaultCloseOperation() ) {
- if(null == glWindow.getParent()) {
- // we may be called directly by the native EDT
- new Thread(new Runnable() {
- public void run() {
- glWindow.reparentWindow(awtParent);
- }
- }).start();
- }
- }
- } } );
-
glEventListener = createInstance(glEventListenerClazzName);
if(null == glEventListener) {
return;
@@ -200,7 +192,7 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
if(glEventListener instanceof KeyListener) {
glWindow.addKeyListener((KeyListener)glEventListener);
}
-
+
if(!noDefaultKeyListener) {
glWindow.addKeyListener(this);
}
@@ -208,26 +200,59 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
glWindow.setUpdateFPSFrames(FPSCounter.DEFAULT_FRAMES_PER_INTERVAL, System.err);
// glAnimator = new FPSAnimator(canvas, 60);
- glAnimator = new Animator(tg, glWindow);
+ glAnimator = new Animator();
+ glAnimator.setModeBits(false, AnimatorBase.MODE_EXPECT_AWT_RENDERING_THREAD); // No AWT thread involved!
+ glAnimator.setThreadGroup(tg);
+ glAnimator.add(glWindow);
glAnimator.setUpdateFPSFrames(FPSCounter.DEFAULT_FRAMES_PER_INTERVAL, null);
-
- } catch (Throwable t) {
+
+ } catch (final Throwable t) {
throw new RuntimeException(t);
}
isValid = true;
}
+ private final WindowListener reparentHomeListener = new WindowAdapter() {
+ // Closing action: back to parent!
+ @Override
+ public void windowDestroyNotify(final WindowEvent e) {
+ if( isValid() && WindowClosingMode.DO_NOTHING_ON_CLOSE == glWindow.getDefaultCloseOperation() &&
+ null == glWindow.getParent() && null != parentWin && 0 != parentWin.getWindowHandle() )
+ {
+ // we may be called directly by the native EDT
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ if( glWindow.isNativeValid() && null != parentWin && 0 != parentWin.getWindowHandle() ) {
+ glWindow.reparentWindow(parentWin, -1, -1, Window.REPARENT_HINT_BECOMES_VISIBLE);
+ }
+ }
+ }).start();
+ }
+ } };
+
public void start() {
if(isValid) {
glWindow.setVisible(true);
glWindow.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED);
+ if( null == pointerIconTest ) {
+ final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/cross-grey-alpha-16x16.png" } );
+ final Display disp = glWindow.getScreen().getDisplay();
+ try {
+ pointerIconTest = disp.createPointerIcon(res, 8, 8);
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
glAnimator.start();
- awtParent = glWindow.getParent();
+ parentWin = glWindow.getParent();
+ glWindow.addWindowListener(reparentHomeListener);
}
}
public void stop() {
if(null!=glAnimator) {
+ glWindow.removeWindowListener(reparentHomeListener);
glAnimator.stop();
glWindow.setVisible(false);
}
@@ -250,58 +275,117 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
// ***********************************************************************************
// ***********************************************************************************
- public void init(GLAutoDrawable drawable) {
+ @Override
+ public void init(final GLAutoDrawable drawable) {
GL _gl = drawable.getGL();
if(glDebug) {
try {
_gl = _gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Debug", null, _gl, null) );
- } catch (Exception e) {e.printStackTrace();}
+ } catch (final Exception e) {e.printStackTrace();}
}
if(glTrace) {
try {
// Trace ..
_gl = _gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, _gl, new Object[] { System.err } ) );
- } catch (Exception e) {e.printStackTrace();}
+ } catch (final Exception e) {e.printStackTrace();}
}
if(glSwapInterval>=0) {
_gl.setSwapInterval(glSwapInterval);
}
}
- public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+ @Override
+ public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
}
- public void display(GLAutoDrawable drawable) {
+ @Override
+ public void display(final GLAutoDrawable drawable) {
}
- public void dispose(GLAutoDrawable drawable) {
+ @Override
+ public void dispose(final GLAutoDrawable drawable) {
}
// ***********************************************************************************
// ***********************************************************************************
// ***********************************************************************************
- public void keyPressed(KeyEvent e) {
- }
- public void keyReleased(KeyEvent e) {
- }
- public void keyTyped(KeyEvent e) {
+ @Override
+ public void keyPressed(final KeyEvent e) {
+ if( !e.isPrintableKey() || e.isAutoRepeat() ) {
+ return;
+ }
if(e.getKeyChar()=='d') {
- glWindow.setUndecorated(!glWindow.isUndecorated());
+ new Thread() {
+ public void run() {
+ glWindow.setUndecorated(!glWindow.isUndecorated());
+ } }.start();
} if(e.getKeyChar()=='f') {
- glWindow.setFullscreen(!glWindow.isFullscreen());
+ new Thread() {
+ public void run() {
+ glWindow.setFullscreen(!glWindow.isFullscreen());
+ } }.start();
} else if(e.getKeyChar()=='a') {
- glWindow.setAlwaysOnTop(!glWindow.isAlwaysOnTop());
- } else if(e.getKeyChar()=='r' && null!=awtParent) {
- if(null == glWindow.getParent()) {
- glWindow.reparentWindow(awtParent);
- } else {
- glWindow.reparentWindow(null);
- if(glClosable) {
- glWindow.setDefaultCloseOperation(WindowClosingMode.DISPOSE_ON_CLOSE);
- }
- }
+ new Thread() {
+ public void run() {
+ glWindow.setAlwaysOnTop(!glWindow.isAlwaysOnTop());
+ } }.start();
+ } else if(e.getKeyChar()=='r' && null!=parentWin) {
+ new Thread() {
+ public void run() {
+ if(null == glWindow.getParent()) {
+ glWindow.reparentWindow(parentWin, -1, -1, 0 /* hints */);
+ } else {
+ final InsetsImmutable insets = glWindow.getInsets();
+ final int x, y;
+ if ( 0 >= insets.getTopHeight() ) {
+ // fail safe ..
+ x = 32;
+ y = 32;
+ } else {
+ x = insets.getLeftWidth();
+ y = insets.getTopHeight();
+ }
+ glWindow.reparentWindow(null, x, y, 0 /* hints */);
+ glWindow.setDefaultCloseOperation( glClosable ? WindowClosingMode.DISPOSE_ON_CLOSE : WindowClosingMode.DO_NOTHING_ON_CLOSE );
+ }
+ } }.start();
+ } else if(e.getKeyChar()=='c') {
+ new Thread() {
+ public void run() {
+ System.err.println("[set pointer-icon pre]");
+ final PointerIcon currentPI = glWindow.getPointerIcon();
+ glWindow.setPointerIcon( currentPI == pointerIconTest ? null : pointerIconTest);
+ System.err.println("[set pointer-icon post] "+currentPI+" -> "+glWindow.getPointerIcon());
+ } }.start();
+ } else if(e.getKeyChar()=='i') {
+ new Thread() {
+ public void run() {
+ System.err.println("[set mouse visible pre]: "+glWindow.isPointerVisible());
+ glWindow.setPointerVisible(!glWindow.isPointerVisible());
+ System.err.println("[set mouse visible post]: "+glWindow.isPointerVisible());
+ } }.start();
+ } else if(e.getKeyChar()=='j') {
+ new Thread() {
+ public void run() {
+ final Thread t = glWindow.setExclusiveContextThread(null);
+ System.err.println("[set mouse confined pre]: "+glWindow.isPointerConfined());
+ glWindow.confinePointer(!glWindow.isPointerConfined());
+ System.err.println("[set mouse confined post]: "+glWindow.isPointerConfined());
+ glWindow.setExclusiveContextThread(t);
+ } }.start();
+ } else if(e.getKeyChar()=='w') {
+ new Thread() {
+ public void run() {
+ System.err.println("[set mouse pos pre]");
+ glWindow.warpPointer(glWindow.getSurfaceWidth()/2, glWindow.getSurfaceHeight()/2);
+ System.err.println("[set mouse pos post]");
+ } }.start();
}
}
+
+ @Override
+ public void keyReleased(final KeyEvent e) {
+ }
}
diff --git a/src/newt/classes/com/jogamp/newt/util/applet/VersionApplet3.java b/src/newt/classes/com/jogamp/newt/util/applet/VersionApplet3.java
new file mode 100644
index 000000000..7ec790ee2
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/util/applet/VersionApplet3.java
@@ -0,0 +1,226 @@
+package com.jogamp.newt.util.applet;
+
+import com.jogamp.plugin.applet.Applet3;
+import com.jogamp.plugin.applet.Applet3Context;
+import com.jogamp.plugin.ui.NativeWindowDownstream;
+import com.jogamp.plugin.ui.NativeWindowUpstream;
+
+import java.util.List;
+import java.util.Locale;
+
+import javax.media.opengl.GLProfile;
+import javax.media.opengl.GL;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLEventListener;
+
+import com.jogamp.common.GlueGenVersion;
+import com.jogamp.common.util.VersionUtil;
+import com.jogamp.newt.NewtFactory;
+import com.jogamp.newt.Window;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.JoglVersion;
+
+public class VersionApplet3 implements Applet3 {
+
+ public static void main(final String[] args) {
+ final VersionApplet3 va = new VersionApplet3();
+
+ final NativeWindowDownstream nwc = va.createNativeWindow(null, new NativeWindowUpstream() {
+ @Override
+ public long getWindowHandle() {
+ return 0;
+ }
+ @Override
+ public int getWidth() {
+ return 64;
+ }
+ @Override
+ public int getHeight() {
+ return 64;
+ }
+ @Override
+ public String getDisplayConnection() {
+ return null; // default
+ }
+ @Override
+ public int getScreenIndex() {
+ return 0; // default
+ }
+ @Override
+ public void notifySurfaceUpdated(final NativeWindowDownstream swappedWin) {
+ // NOP
+ }
+ @Override
+ public int getX() {
+ return 0;
+ }
+ @Override
+ public int getY() {
+ return 0;
+ }
+ });
+ va.init(null);
+ va.start();
+ va.stop();
+ va.destroy();
+ nwc.destroy();
+ }
+
+ GLWindow canvas;
+
+ @Override
+ public NativeWindowDownstream createNativeWindow(final Applet3Context ctx, final NativeWindowUpstream parentWin) {
+ final GLCapabilities caps = new GLCapabilities(GLProfile.getDefault());
+ final Window w = NewtFactory.createWindow(parentWin.getDisplayConnection(), parentWin.getScreenIndex(), parentWin.getWindowHandle(), caps);
+ canvas = GLWindow.create(w);
+ canvas.setSize(parentWin.getWidth(), parentWin.getHeight());
+
+ return new NativeWindowDownstream() {
+ @Override
+ public void setVisible(final boolean v) {
+ if( null != canvas ) {
+ canvas.setVisible(v);
+ }
+ }
+
+ @Override
+ public void setSize(final int width, final int height) {
+ if( null != canvas ) {
+ canvas.setSize(width, height);
+ }
+ }
+
+ @Override
+ public void requestFocus() {
+ if( null != canvas ) {
+ canvas.requestFocus();
+ }
+ }
+
+ @Override
+ public void destroy() {
+ if( null != canvas ) {
+ canvas.destroy();
+ }
+ }
+
+ @Override
+ public NativeWindowUpstream getParent() {
+ return parentWin;
+ }
+
+ @Override
+ public long getWindowHandle() {
+ if( null != canvas ) {
+ return canvas.getWindowHandle();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public void display() {
+ if( null != canvas ) {
+ canvas.display();
+ }
+ }
+
+ @Override
+ public void notifyPositionChanged(final NativeWindowUpstream nw) {
+ if( null != canvas ) {
+ canvas.setPosition(nw.getX(), nw.getY());
+ }
+ }
+ };
+ }
+
+ @Override
+ public void init(final Applet3Context ctx) {
+ System.err.println("VersionApplet: init() - begin");
+ canvas.addGLEventListener(new GLInfo());
+ System.err.println("VersionApplet: init() - end");
+ }
+
+ @Override
+ public void start() {
+ System.err.println("VersionApplet: start() - begin");
+
+ String s;
+
+ s = VersionUtil.getPlatformInfo().toString();
+ System.err.println(s);
+
+ s = GlueGenVersion.getInstance().toString();
+ System.err.println(s);
+
+ /*
+ s = NativeWindowVersion.getInstance().toString();
+ System.err.println(s);
+ */
+
+ s = JoglVersion.getInstance().toString();
+ System.err.println(s);
+
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(canvas.getGLProfile());
+ final List<GLCapabilitiesImmutable> availCaps = factory.getAvailableCapabilities(null);
+ for(int i=0; i<availCaps.size(); i++) {
+ s = availCaps.get(i).toString();
+ System.err.println(s);
+ }
+ canvas.display();
+ System.err.println("VersionApplet: start() - end");
+ }
+
+ @Override
+ public void stop() {
+ System.err.println("VersionApplet: stop() - begin");
+ canvas.setVisible(false);
+ System.err.println("VersionApplet: stop() - end");
+ }
+
+ @Override
+ public void destroy() {
+ System.err.println("VersionApplet: destroy() - start");
+ if(null!=canvas) {
+ canvas.destroy();
+ canvas = null;
+ }
+ System.err.println("VersionApplet: destroy() - end");
+ }
+
+ @Override
+ public String getAppletInfo() {
+ return null;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public String[][] getParameterInfo() {
+ return null;
+ }
+
+ static class GLInfo implements GLEventListener {
+ @Override
+ public void init(final GLAutoDrawable drawable) {
+ final GL gl = drawable.getGL();
+ final String s = JoglVersion.getGLInfo(gl, null).toString();
+ System.err.println(s);
+ }
+ @Override
+ public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
+ }
+ @Override
+ public void display(final GLAutoDrawable drawable) {
+ }
+ @Override
+ public void dispose(final GLAutoDrawable drawable) {
+ }
+ }
+}
diff --git a/src/newt/classes/jogamp/newt/Debug.java b/src/newt/classes/jogamp/newt/Debug.java
index 3c83da4d9..a255cb755 100644
--- a/src/newt/classes/jogamp/newt/Debug.java
+++ b/src/newt/classes/jogamp/newt/Debug.java
@@ -1,44 +1,36 @@
-/*
- * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any kind. ALL
- * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
- * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
- * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
- * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
- * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
- * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
- * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
- * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
- * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed or intended for use
- * in the design, construction, operation or maintenance of any nuclear
- * facility.
- *
- * Sun gratefully acknowledges that this software was originally authored
- * and developed by Kenneth Bradley Russell and Christopher John Kline.
+/**
+ * Copyright 2014 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 java.security.AccessController;
+import java.security.PrivilegedAction;
+
import com.jogamp.common.util.PropertyAccess;
/** Helper routines for logging and debugging. */
@@ -47,40 +39,37 @@ public class Debug extends PropertyAccess {
// Some common properties
private static final boolean verbose;
private static final boolean debugAll;
-
+
static {
- PropertyAccess.addTrustedPrefix("newt.", Debug.class);
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ PropertyAccess.addTrustedPrefix("newt.");
+ return null;
+ } } );
+
verbose = isPropertyDefined("newt.verbose", true);
debugAll = isPropertyDefined("newt.debug", true);
if (verbose) {
- Package p = Package.getPackage("com.jogamp.newt");
+ final Package p = Package.getPackage("com.jogamp.newt");
System.err.println("NEWT specification version " + p.getSpecificationVersion());
System.err.println("NEWT implementation version " + p.getImplementationVersion());
System.err.println("NEWT implementation vendor " + p.getImplementationVendor());
}
}
- public static final boolean isPropertyDefined(final String property, final boolean jnlpAlias) {
- return PropertyAccess.isPropertyDefined(property, jnlpAlias, null);
- }
-
- public static final int getIntProperty(final String property, final boolean jnlpAlias, int defaultValue) {
- return PropertyAccess.getIntProperty(property, jnlpAlias, null, defaultValue);
- }
-
- public static final boolean getBooleanProperty(final String property, final boolean jnlpAlias) {
- return PropertyAccess.getBooleanProperty(property, jnlpAlias, null);
- }
-
- public static boolean verbose() {
+ /** Ensures static init block has been issues, i.e. if calling through to {@link PropertyAccess#isPropertyDefined(String, boolean)}. */
+ public static final void initSingleton() {}
+
+ public static final boolean verbose() {
return verbose;
}
- public static boolean debugAll() {
+ public static final boolean debugAll() {
return debugAll;
}
- public static boolean debug(String subcomponent) {
+ public static final boolean debug(final String subcomponent) {
return debugAll() || isPropertyDefined("newt.debug." + subcomponent, true);
}
}
diff --git a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java
index 18418a8dc..ef8ea66b6 100644
--- a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java
+++ b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
@@ -38,6 +38,7 @@
package jogamp.newt;
import java.util.ArrayList;
+
import javax.media.nativewindow.NativeWindowException;
import jogamp.common.util.locks.LockDebugUtil;
@@ -49,19 +50,24 @@ import com.jogamp.newt.util.EDTUtil;
public class DefaultEDTUtil implements EDTUtil {
public static final boolean DEBUG = Debug.debug("EDT");
+ /** Used to implement {@link #invokeStop(boolean, Runnable)}. */
+ private static final Object TASK_ATTACHMENT_STOP = new Object();
+ /** Used to provoke an exception on the EDT while waiting / blocking. Merely exists to test code.*/
+ private static final Object TASK_ATTACHMENT_TEST_ERROR = new Object();
+
private final Object edtLock = new Object(); // locking the EDT start/stop state
- private final ThreadGroup threadGroup;
+ private /* final */ ThreadGroup threadGroup;
private final String name;
private final Runnable dispatchMessages;
- private EventDispatchThread edt = null;
+ private NEDT edt = null;
private int start_iter=0;
private static long pollPeriod = EDTUtil.defaultEDTPollPeriod;
- public DefaultEDTUtil(ThreadGroup tg, String name, Runnable dispatchMessages) {
+ public DefaultEDTUtil(final ThreadGroup tg, final String name, final Runnable dispatchMessages) {
this.threadGroup = tg;
this.name=Thread.currentThread().getName()+"-"+name+"-EDT-";
this.dispatchMessages=dispatchMessages;
- this.edt = new EventDispatchThread(threadGroup, name);
+ this.edt = new NEDT(threadGroup, name);
this.edt.setDaemon(true); // don't stop JVM from shutdown ..
}
@@ -71,36 +77,45 @@ public class DefaultEDTUtil implements EDTUtil {
}
@Override
- final public void setPollPeriod(long ms) {
- pollPeriod = ms;
+ final public void setPollPeriod(final long ms) {
+ pollPeriod = ms; // writing to static field is intended
}
-
+
@Override
- public final void reset() {
- synchronized(edtLock) {
- waitUntilStopped();
+ public final void start() throws IllegalStateException {
+ synchronized(edtLock) {
+ if( edt.isRunning() ) {
+ throw new IllegalStateException("EDT still running and not subject to stop. Curr "+Thread.currentThread().getName()+", EDT "+edt.getName()+", isRunning "+edt.isRunning+", shouldStop "+edt.shouldStop);
+ }
if(DEBUG) {
if(edt.tasks.size()>0) {
- System.err.println(Thread.currentThread()+": EDT reset, remaining tasks: "+edt.tasks.size()+" - "+edt);
- // Thread.dumpStack();
+ System.err.println(Thread.currentThread()+": Default-EDT reset, remaining tasks: "+edt.tasks.size()+" - "+edt);
+ }
+ System.err.println(Thread.currentThread()+": Default-EDT reset - edt: "+edt);
+ }
+ if( edt.getState() != Thread.State.NEW ) {
+ if( null != threadGroup && threadGroup.isDestroyed() ) {
+ // best thing we can do is to use this thread's TG
+ threadGroup = Thread.currentThread().getThreadGroup();
}
- System.err.println(Thread.currentThread()+": EDT reset - edt: "+edt);
+ edt = new NEDT(threadGroup, name);
+ edt.setDaemon(true); // don't stop JVM from shutdown ..
}
- this.edt = new EventDispatchThread(threadGroup, name);
- this.edt.setDaemon(true); // don't stop JVM from shutdown ..
+ startImpl();
+ }
+ if( !edt.isRunning() ) {
+ throw new RuntimeException("EDT could not be started: "+edt);
}
}
private final void startImpl() {
if(edt.isAlive()) {
- throw new RuntimeException("EDT Thread.isAlive(): true, isRunning: "+edt.isRunning()+", edt: "+edt+", tasks: "+edt.tasks.size());
+ throw new RuntimeException("Default-EDT Thread.isAlive(): true, isRunning: "+edt.isRunning+", shouldStop "+edt.shouldStop+", edt: "+edt+", tasks: "+edt.tasks.size());
}
start_iter++;
edt.setName(name+start_iter);
- edt.shouldStop = false;
if(DEBUG) {
- System.err.println(Thread.currentThread()+": EDT START - edt: "+edt);
- // Thread.dumpStack();
+ System.err.println(Thread.currentThread()+": Default-EDT START - edt: "+edt);
}
edt.start();
}
@@ -109,7 +124,7 @@ public class DefaultEDTUtil implements EDTUtil {
public final boolean isCurrentThreadEDT() {
return edt == Thread.currentThread(); // EDT == NEDT
}
-
+
@Override
public final boolean isCurrentThreadNEDT() {
return edt == Thread.currentThread(); // EDT == NEDT
@@ -118,81 +133,109 @@ public class DefaultEDTUtil implements EDTUtil {
@Override
public final boolean isCurrentThreadEDTorNEDT() {
return edt == Thread.currentThread(); // EDT == NEDT
- }
-
+ }
+
@Override
public final boolean isRunning() {
return edt.isRunning() ;
}
@Override
- public final void invokeStop(Runnable task) {
- invokeImpl(true, task, true);
+ public final boolean invokeStop(final boolean wait, final Runnable task) {
+ if(DEBUG) {
+ System.err.println(Thread.currentThread()+": Default-EDT.invokeStop wait "+wait);
+ Thread.dumpStack();
+ }
+ return invokeImpl(wait, task, true /* stop */, false /* provokeError */);
+ }
+
+ public final boolean invokeAndWaitError(final Runnable task) {
+ if(DEBUG) {
+ System.err.println(Thread.currentThread()+": Default-EDT.invokeAndWaitError");
+ Thread.dumpStack();
+ }
+ return invokeImpl(true /* wait */, task, false /* stop */, true /* provokeError */);
}
@Override
- public final void invoke(boolean wait, Runnable task) {
- invokeImpl(wait, task, false);
+ public final boolean invoke(final boolean wait, final Runnable task) {
+ return invokeImpl(wait, task, false /* stop */, false /* provokeError */);
}
- private void invokeImpl(boolean wait, Runnable task, boolean stop) {
- if(task == null) {
- throw new RuntimeException("Null Runnable");
- }
+ private static Runnable nullTask = new Runnable() {
+ @Override
+ public void run() { }
+ };
+
+ private final boolean invokeImpl(boolean wait, Runnable task, final boolean stop, final boolean provokeError) {
Throwable throwable = null;
RunnableTask rTask = null;
- Object rTaskLock = new Object();
+ final Object rTaskLock = new Object();
synchronized(rTaskLock) { // lock the optional task execution
synchronized(edtLock) { // lock the EDT status
if( edt.shouldStop ) {
// drop task ..
+ System.err.println(Thread.currentThread()+": Warning: Default-EDT about (1) to stop, won't enqueue new task: "+edt);
if(DEBUG) {
- System.err.println("Warning: EDT about (1) to stop, won't enqueue new task: "+edt);
Thread.dumpStack();
}
- return;
- }
- // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task);
- // Thread.dumpStack();
- if(stop) {
- edt.shouldStop = true;
- if(DEBUG) {
- System.err.println(Thread.currentThread()+": EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - tasks: "+edt.tasks.size()+" - "+edt);
- // Thread.dumpStack();
- }
+ return false;
}
if( isCurrentThreadEDT() ) {
- task.run();
+ if(null != task) {
+ task.run();
+ }
wait = false; // running in same thread (EDT) -> no wait
- if(stop && edt.tasks.size()>0) {
- System.err.println("Warning: EDT about (2) to stop, having remaining tasks: "+edt.tasks.size()+" - "+edt);
- if(DEBUG) {
- Thread.dumpStack();
+ if( stop ) {
+ edt.shouldStop = true;
+ if( edt.tasks.size()>0 ) {
+ System.err.println(Thread.currentThread()+": Warning: Default-EDT about (2) to stop, task executed. Remaining tasks: "+edt.tasks.size()+" - "+edt);
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
}
}
} else {
- // start if should not stop && not started yet
- if( !stop && !edt.isRunning() ) {
- startImpl();
+ if( !edt.isRunning ) {
+ if( null != task ) {
+ if( stop ) {
+ System.err.println(Thread.currentThread()+": Warning: Default-EDT is about (3) to stop and stopped already, dropping task. Remaining tasks: "+edt.tasks.size()+" - "+edt);
+ } else {
+ System.err.println(Thread.currentThread()+": Warning: Default-EDT is not running, dropping task. NEDT "+edt);
+ }
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
+ }
+ return false;
+ } else if( stop && null == task ) {
+ task = nullTask; // ensures execution triggering stop
}
- synchronized(edt.tasks) {
- wait = wait && edt.isRunning();
- rTask = new RunnableTask(task,
- wait ? rTaskLock : null,
- true /* always catch and report Exceptions, don't disturb EDT */);
- if(stop) {
- rTask.setAttachment(new Boolean(true)); // mark final task
+
+ if(null != task) {
+ synchronized(edt.tasks) {
+ rTask = new RunnableTask(task,
+ wait ? rTaskLock : null,
+ true /* always catch and report Exceptions, don't disturb EDT */,
+ wait ? null : System.err);
+ if(stop) {
+ rTask.setAttachment(TASK_ATTACHMENT_STOP); // mark final task, will imply shouldStop:=true
+ } else if(provokeError) {
+ rTask.setAttachment(TASK_ATTACHMENT_TEST_ERROR);
+ }
+ // append task ..
+ edt.tasks.add(rTask);
+ edt.tasks.notifyAll();
}
- // append task ..
- edt.tasks.add(rTask);
- edt.tasks.notifyAll();
+ } else {
+ wait = false;
}
}
}
if( wait ) {
try {
rTaskLock.wait(); // free lock, allow execution of rTask
- } catch (InterruptedException ie) {
+ } catch (final InterruptedException ie) {
throwable = ie;
}
if(null==throwable) {
@@ -205,59 +248,66 @@ public class DefaultEDTUtil implements EDTUtil {
throw new RuntimeException(throwable);
}
}
- }
- if(DEBUG && stop) {
- System.err.println(Thread.currentThread()+": EDT signal STOP X edt: "+edt);
+ if(DEBUG) {
+ if( stop) {
+ System.err.println(Thread.currentThread()+": Default-EDT signal STOP X edt: "+edt);
+ }
+ }
+ return true;
}
}
@Override
- final public void waitUntilIdle() {
- final EventDispatchThread _edt;
+ final public boolean waitUntilIdle() {
+ final NEDT _edt;
synchronized(edtLock) {
_edt = edt;
}
- if(!_edt.isRunning() || _edt == Thread.currentThread()) {
- return;
+ if(!_edt.isRunning || _edt == Thread.currentThread()) {
+ return false;
}
synchronized(_edt.tasks) {
- while(_edt.isRunning() && _edt.tasks.size()>0) {
+ while(_edt.isRunning && _edt.tasks.size()>0) {
try {
_edt.tasks.notifyAll();
_edt.tasks.wait();
- } catch (InterruptedException e) {
+ } catch (final InterruptedException e) {
e.printStackTrace();
}
}
+ return true;
}
}
@Override
- final public void waitUntilStopped() {
+ final public boolean waitUntilStopped() {
synchronized(edtLock) {
- if(edt.isRunning() && edt != Thread.currentThread() ) {
- while(edt.isRunning()) {
+ if(edt.isRunning && edt != Thread.currentThread() ) {
+ while( edt.isRunning ) {
try {
edtLock.wait();
- } catch (InterruptedException e) {
+ } catch (final InterruptedException e) {
e.printStackTrace();
}
}
+ return true;
+ } else {
+ return false;
}
}
}
- class EventDispatchThread extends Thread {
+ class NEDT extends Thread {
volatile boolean shouldStop = false;
volatile boolean isRunning = false;
- ArrayList<RunnableTask> tasks = new ArrayList<RunnableTask>(); // one shot tasks
+ final ArrayList<RunnableTask> tasks = new ArrayList<RunnableTask>(); // one shot tasks
- public EventDispatchThread(ThreadGroup tg, String name) {
+ public NEDT(final ThreadGroup tg, final String name) {
super(tg, name);
}
final public boolean isRunning() {
- return isRunning;
+ return isRunning && !shouldStop;
}
@Override
@@ -267,24 +317,24 @@ public class DefaultEDTUtil implements EDTUtil {
}
private final void validateNoRecursiveLocksHold() {
- if(Lock.DEBUG) {
- if(LockDebugUtil.getRecursiveLockTrace().size()>0) {
- LockDebugUtil.dumpRecursiveLockTrace(System.err);
- throw new InternalError("XXX");
- }
+ if(LockDebugUtil.getRecursiveLockTrace().size()>0) {
+ LockDebugUtil.dumpRecursiveLockTrace(System.err);
+ throw new InternalError("XXX");
}
}
-
- /**
+
+ /**
* Utilizing locking only on tasks and its execution,
* not for event dispatching.
*/
@Override
final public void run() {
if(DEBUG) {
- System.err.println(getName()+": EDT run() START "+ getName());
+ System.err.println(getName()+": Default-EDT run() START "+ getName());
+ }
+ if(Lock.DEBUG) {
+ validateNoRecursiveLocksHold();
}
- validateNoRecursiveLocksHold();
RuntimeException error = null;
try {
do {
@@ -299,7 +349,7 @@ public class DefaultEDTUtil implements EDTUtil {
if(!shouldStop && tasks.size()==0) {
try {
tasks.wait(pollPeriod);
- } catch (InterruptedException e) {
+ } catch (final InterruptedException e) {
e.printStackTrace();
}
}
@@ -307,58 +357,58 @@ public class DefaultEDTUtil implements EDTUtil {
if(tasks.size()>0) {
task = tasks.remove(0);
tasks.notifyAll();
+ final Object attachment = task.getAttachment();
+ if( TASK_ATTACHMENT_STOP == attachment ) {
+ shouldStop = true;
+ } else if( TASK_ATTACHMENT_TEST_ERROR == attachment ) {
+ tasks.add(0, task);
+ task = null;
+ throw new RuntimeException("TASK_ATTACHMENT_TEST_ERROR");
+ }
}
}
if(null!=task) {
task.run();
- validateNoRecursiveLocksHold();
+ if(Lock.DEBUG) {
+ validateNoRecursiveLocksHold();
+ }
if(!task.hasWaiter() && null != task.getThrowable()) {
// at least dump stack-trace in case nobody waits for result
+ System.err.println("DefaultEDT.run(): Caught exception occured on thread "+Thread.currentThread().getName()+": "+task.toString());
task.getThrowable().printStackTrace();
}
}
} while(!shouldStop) ;
- } catch (Throwable t) {
+ } catch (final Throwable t) {
// handle errors ..
shouldStop = true;
if(t instanceof RuntimeException) {
error = (RuntimeException) t;
} else {
- error = new RuntimeException("Within EDT", t);
+ error = new RuntimeException("Within Default-EDT", t);
}
} finally {
+ final String msg = getName()+": Default-EDT finished w/ "+tasks.size()+" left";
if(DEBUG) {
- RunnableTask rt = ( tasks.size() > 0 ) ? tasks.get(0) : null ;
- System.err.println(getName()+": EDT run() END "+ getName()+", tasks: "+tasks.size()+", "+rt+", "+error);
+ System.err.println(msg+", "+error);
}
synchronized(edtLock) {
- if(null==error) {
- synchronized(tasks) {
- // drain remaining tasks (stop not on EDT),
- // while having tasks and no previous-task, or previous-task is non final
- RunnableTask task = null;
- while ( ( null == task || task.getAttachment() == null ) && tasks.size() > 0 ) {
- task = tasks.remove(0);
- task.run();
- tasks.notifyAll();
- }
- if(DEBUG) {
- if(null!=task && task.getAttachment()==null) {
- System.err.println(getName()+" Warning: EDT exit: Last task Not Final: "+tasks.size()+", "+task+" - "+edt);
- } else if(tasks.size()>0) {
- System.err.println(getName()+" Warning: EDT exit: Remaining tasks Post Final: "+tasks.size());
- }
- Thread.dumpStack();
- }
+ int i = 0;
+ while( tasks.size() > 0 ) {
+ // notify all waiter
+ final String msg2 = msg+", task #"+i;
+ final Throwable t = null != error ? new Throwable(msg2, error) : new Throwable(msg2);
+ final RunnableTask rt = tasks.remove(0);
+ if( null != rt ) {
+ rt.flush(t);
+ i++;
}
}
- isRunning = !shouldStop;
- if(!isRunning) {
- edtLock.notifyAll();
- }
+ isRunning = false;
+ edtLock.notifyAll();
}
if(DEBUG) {
- System.err.println(getName()+": EDT run() EXIT "+ getName()+", exception: "+error);
+ System.err.println(msg+" EXIT, exception: "+error);
}
if(null!=error) {
throw error;
diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java
index bca7f6e5b..84ce45238 100644
--- a/src/newt/classes/jogamp/newt/DisplayImpl.java
+++ b/src/newt/classes/jogamp/newt/DisplayImpl.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,44 +29,249 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt;
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.ReflectionUtil;
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 com.jogamp.opengl.util.PNGPixelRect;
+
+import java.io.IOException;
+import java.net.URLConnection;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
+
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.nativewindow.util.PixelFormatUtil;
+import javax.media.nativewindow.util.PixelRectangle;
+import javax.media.nativewindow.util.PixelFormat;
+import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.util.PointImmutable;
public abstract class DisplayImpl extends Display {
private static int serialno = 1;
+ private static final boolean pngUtilAvail;
+
+ static {
+ NativeWindowFactory.addCustomShutdownHook(true /* head */, new Runnable() {
+ @Override
+ public void run() {
+ WindowImpl.shutdownAll();
+ ScreenImpl.shutdownAll();
+ DisplayImpl.shutdownAll();
+ }
+ });
+
+ final ClassLoader cl = DisplayImpl.class.getClassLoader();
+ pngUtilAvail = ReflectionUtil.isClassAvailable("com.jogamp.opengl.util.PNGPixelRect", cl);
+ }
+
+ public static final boolean isPNGUtilAvailable() { return pngUtilAvail; }
+
+ final ArrayList<PointerIconImpl> pointerIconList = new ArrayList<PointerIconImpl>();
+
+ /** Executed from EDT! */
+ private void destroyAllPointerIconFromList(final long dpy) {
+ synchronized(pointerIconList) {
+ 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();
+ }
+ }
+
+ @Override
+ public PixelFormat getNativePointerIconPixelFormat() { return PixelFormat.BGRA8888; }
+ @Override
+ public boolean getNativePointerIconForceDirectNIO() { return false; }
+
+ @Override
+ public final PointerIcon createPointerIcon(final IOUtil.ClassResources pngResource, final int hotX, final int hotY)
+ throws IllegalArgumentException, IllegalStateException, IOException
+ {
+ if( null == pngResource || 0 >= pngResource.resourceCount() ) {
+ throw new IllegalArgumentException("Null or invalid pngResource "+pngResource);
+ }
+ if( !pngUtilAvail ) {
+ return null;
+ }
+ final PointerIconImpl[] res = { null };
+ runOnEDTIfAvail(true, new Runnable() {
+ public void run() {
+ try {
+ if( !DisplayImpl.this.isNativeValidAsync() ) {
+ throw new IllegalStateException("Display.createPointerIcon: Display invalid "+DisplayImpl.this);
+ }
+ final URLConnection urlConn = pngResource.resolve(0);
+ if( null == urlConn ) {
+ throw new IOException("Could not resolve "+pngResource.resourcePaths[0]);
+ }
+ final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(),
+ getNativePointerIconPixelFormat(),
+ getNativePointerIconForceDirectNIO(),
+ 0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ final long handle = createPointerIconImplChecked(image.getPixelformat(), image.getSize().getWidth(), image.getSize().getHeight(),
+ image.getPixels(), hotX, hotY);
+ final PointImmutable hotspot = new Point(hotX, hotY);
+ if( DEBUG_POINTER_ICON ) {
+ System.err.println("createPointerIconPNG.0: "+image+", handle: "+toHexString(handle)+", hot "+hotspot);
+ }
+ if( 0 != handle ) {
+ res[0] = new PointerIconImpl(DisplayImpl.this, image, hotspot, handle);
+ if( DEBUG_POINTER_ICON ) {
+ System.err.println("createPointerIconPNG.0: "+res[0]);
+ }
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ } } );
+ if( null != res[0] ) {
+ synchronized(pointerIconList) {
+ pointerIconList.add(res[0]);
+ }
+ }
+ return res[0];
+ }
+
+ @Override
+ public final PointerIcon createPointerIcon(final PixelRectangle pixelrect, final int hotX, final int hotY)
+ throws IllegalArgumentException, IllegalStateException
+ {
+ if( null == pixelrect ) {
+ throw new IllegalArgumentException("Null or pixelrect");
+ }
+ final PixelRectangle fpixelrect;
+ if( getNativePointerIconPixelFormat() != pixelrect.getPixelformat() || pixelrect.isGLOriented() ) {
+ // conversion !
+ fpixelrect = PixelFormatUtil.convert32(pixelrect, getNativePointerIconPixelFormat(),
+ 0 /* ddestStride */, false /* isGLOriented */, getNativePointerIconForceDirectNIO() );
+ if( DEBUG_POINTER_ICON ) {
+ System.err.println("createPointerIconRES.0: Conversion-FMT "+pixelrect+" -> "+fpixelrect);
+ }
+ } else if( getNativePointerIconForceDirectNIO() && !Buffers.isDirect(pixelrect.getPixels()) ) {
+ // transfer to direct NIO
+ final ByteBuffer sBB = pixelrect.getPixels();
+ final ByteBuffer dBB = Buffers.newDirectByteBuffer(sBB.array(), sBB.arrayOffset());
+ fpixelrect = new PixelRectangle.GenericPixelRect(pixelrect.getPixelformat(), pixelrect.getSize(), pixelrect.getStride(), pixelrect.isGLOriented(), dBB);
+ if( DEBUG_POINTER_ICON ) {
+ System.err.println("createPointerIconRES.0: Conversion-NIO "+pixelrect+" -> "+fpixelrect);
+ }
+ } else {
+ fpixelrect = pixelrect;
+ if( DEBUG_POINTER_ICON ) {
+ System.err.println("createPointerIconRES.0: No conversion "+fpixelrect);
+ }
+ }
+ final PointerIconImpl[] res = { null };
+ runOnEDTIfAvail(true, new Runnable() {
+ public void run() {
+ try {
+ if( !DisplayImpl.this.isNativeValidAsync() ) {
+ throw new IllegalStateException("Display.createPointerIcon: Display invalid "+DisplayImpl.this);
+ }
+ if( null != fpixelrect ) {
+ final long handle = createPointerIconImplChecked(fpixelrect.getPixelformat(),
+ fpixelrect.getSize().getWidth(),
+ fpixelrect.getSize().getHeight(),
+ fpixelrect.getPixels(), hotX, hotY);
+ if( 0 != handle ) {
+ res[0] = new PointerIconImpl(DisplayImpl.this, fpixelrect, new Point(hotX, hotY), handle);
+ }
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ } } );
+ if( null != res[0] ) {
+ synchronized(pointerIconList) {
+ pointerIconList.add(res[0]);
+ }
+ }
+ return res[0];
+ }
+
+ /**
+ * Executed from EDT!
+ *
+ * @param pixelformat the <code>pixels</code>'s format
+ * @param width the <code>pixels</code>'s width
+ * @param height the <code>pixels</code>'s height
+ * @param pixels the <code>pixels</code>
+ * @param hotX the PointerIcon's hot-spot x-coord
+ * @param hotY the PointerIcon's hot-spot x-coord
+ * @return if successful a valid handle (not null), otherwise null.
+ */
+ protected final long createPointerIconImplChecked(final PixelFormat pixelformat, final int width, final int height, final ByteBuffer pixels, final int hotX, final int hotY) {
+ if( getNativePointerIconPixelFormat() != pixelformat ) {
+ throw new IllegalArgumentException("Pixelformat no "+getNativePointerIconPixelFormat()+", but "+pixelformat);
+ }
+ if( getNativePointerIconForceDirectNIO() && !Buffers.isDirect(pixels) ) {
+ throw new IllegalArgumentException("pixel buffer is not direct "+pixels);
+ }
+ return createPointerIconImpl(pixelformat, width, height, pixels, hotX, hotY);
+ }
+
+ /**
+ * Executed from EDT!
+ *
+ * @param pixelformat the <code>pixels</code>'s format
+ * @param width the <code>pixels</code>'s width
+ * @param height the <code>pixels</code>'s height
+ * @param pixels the <code>pixels</code>
+ * @param hotX the PointerIcon's hot-spot x-coord
+ * @param hotY the PointerIcon's hot-spot x-coord
+ * @return if successful a valid handle (not null), otherwise null.
+ */
+ protected long createPointerIconImpl(final PixelFormat pixelformat, final int width, final int height, final ByteBuffer pixels, final int hotX, final int hotY) {
+ return 0;
+ }
- private static Class<?> getDisplayClass(String type)
- throws ClassNotFoundException
+ /** Executed from EDT! */
+ protected void destroyPointerIconImpl(final long displayHandle, final long piHandle) { }
+
+ /** Ensure static init has been run. */
+ /* pp */static void initSingleton() { }
+
+ private static Class<?> getDisplayClass(final String type)
+ throws ClassNotFoundException
{
final Class<?> displayClass = NewtFactory.getCustomClass(type, "DisplayDriver");
if(null==displayClass) {
- throw new ClassNotFoundException("Failed to find NEWT Display Class <"+type+".DisplayDriver>");
+ throw new ClassNotFoundException("Failed to find NEWT Display Class <"+type+".DisplayDriver>");
}
return displayClass;
}
/** Make sure to reuse a Display with the same name */
- public static Display create(String type, String name, final long handle, boolean reuse) {
+ public static Display create(final String type, String name, final long handle, final boolean reuse) {
try {
- Class<?> displayClass = getDisplayClass(type);
- DisplayImpl display = (DisplayImpl) displayClass.newInstance();
+ final Class<?> displayClass = getDisplayClass(type);
+ final DisplayImpl display = (DisplayImpl) displayClass.newInstance();
name = display.validateDisplayName(name, handle);
synchronized(displayList) {
if(reuse) {
- Display display0 = Display.getLastDisplayOf(type, name, -1);
+ final Display display0 = Display.getLastDisplayOf(type, name, -1, true /* shared only */);
if(null != display0) {
if(DEBUG) {
System.err.println("Display.create() REUSE: "+display0+" "+getThreadName());
@@ -74,29 +279,28 @@ public abstract class DisplayImpl extends Display {
return display0;
}
}
+ display.exclusive = !reuse;
display.name = name;
display.type=type;
- display.destroyWhenUnused=false;
display.refCount=0;
display.id = serialno++;
display.fqname = getFQName(display.type, display.name, display.id);
display.hashCode = display.fqname.hashCode();
- displayList.add(display);
- }
- if(null == display.edtUtil) {
- display.setEDTUtil(null); // device's default if EDT is used, or null
+ display.setEDTUtil( display.edtUtil ); // device's default if EDT is used, or null
+ Display.addDisplay2List(display);
}
+
if(DEBUG) {
System.err.println("Display.create() NEW: "+display+" "+getThreadName());
}
return display;
- } catch (Exception e) {
+ } catch (final Exception e) {
throw new RuntimeException(e);
}
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
@@ -116,48 +320,47 @@ public abstract class DisplayImpl extends Display {
return true;
}
+ @Override
public int hashCode() {
return hashCode;
}
- public synchronized final void createNative()
+ @Override
+ public synchronized final void createNative()
throws NativeWindowException
{
- if(null==aDevice) {
+ if( null == aDevice ) {
if(DEBUG) {
System.err.println("Display.createNative() START ("+getThreadName()+", "+this+")");
}
final DisplayImpl f_dpy = this;
try {
runOnEDTIfAvail(true, new Runnable() {
+ @Override
public void run() {
f_dpy.createNativeImpl();
}});
- } catch (Throwable t) {
+ } catch (final Throwable t) {
throw new NativeWindowException(t);
}
- if(null==aDevice) {
+ if( null == aDevice ) {
throw new NativeWindowException("Display.createNative() failed to instanciate an AbstractGraphicsDevice");
}
- if(DEBUG) {
- System.err.println("Display.createNative() END ("+getThreadName()+", "+this+")");
- }
synchronized(displayList) {
displaysActive++;
+ if(DEBUG) {
+ System.err.println("Display.createNative() END ("+getThreadName()+", "+this+", active "+displaysActive+")");
+ }
}
}
}
- protected boolean shallRunOnEDT() {
- return true;
- }
-
protected EDTUtil createEDTUtil() {
final EDTUtil def;
if(NewtFactory.useEDT()) {
- def = new DefaultEDTUtil(Thread.currentThread().getThreadGroup(), "Display-"+getFQName(), dispatchMessagesRunnable);
+ def = new DefaultEDTUtil(Thread.currentThread().getThreadGroup(), "Display-"+getFQName(), dispatchMessagesRunnable);
if(DEBUG) {
- System.err.println("Display.createNative("+getFQName()+") Create EDTUtil: "+def.getClass().getName());
+ System.err.println("Display.createEDTUtil("+getFQName()+"): "+def.getClass().getName());
}
} else {
def = null;
@@ -166,26 +369,20 @@ public abstract class DisplayImpl extends Display {
}
@Override
- public EDTUtil setEDTUtil(EDTUtil newEDTUtil) {
- if(null == newEDTUtil) {
- newEDTUtil = createEDTUtil();
- } else if( newEDTUtil == edtUtil ) {
- if(DEBUG) {
- System.err.println("Display.setEDTUtil: "+newEDTUtil+" - keep!");
+ public synchronized EDTUtil setEDTUtil(final EDTUtil usrEDTUtil) {
+ final EDTUtil oldEDTUtil = edtUtil;
+ if( null != usrEDTUtil && usrEDTUtil == oldEDTUtil ) {
+ if( DEBUG ) {
+ System.err.println("Display.setEDTUtil: "+usrEDTUtil+" - keep!");
}
- return null; // no change
+ return oldEDTUtil;
}
- final EDTUtil oldEDTUtil = edtUtil;
if(DEBUG) {
- System.err.println("Display.setEDTUtil: "+oldEDTUtil+" -> "+newEDTUtil);
- }
- if(null != oldEDTUtil) {
- stopEDT( new Runnable() { public void run() {} } );
- // ready for restart ..
- oldEDTUtil.waitUntilStopped();
- oldEDTUtil.reset();
+ final String msg = ( null == usrEDTUtil ) ? "default" : "custom";
+ System.err.println("Display.setEDTUtil("+msg+"): "+oldEDTUtil+" -> "+usrEDTUtil);
}
- edtUtil = newEDTUtil;
+ stopEDT( oldEDTUtil, null );
+ edtUtil = ( null == usrEDTUtil ) ? createEDTUtil() : usrEDTUtil;
return oldEDTUtil;
}
@@ -194,72 +391,143 @@ public abstract class DisplayImpl extends Display {
return edtUtil;
}
- private void stopEDT(final Runnable task) {
- if( shallRunOnEDT() && null!=edtUtil ) {
- edtUtil.invokeStop(task);
- } else {
+ private static void stopEDT(final EDTUtil edtUtil, final Runnable task) {
+ if( null != edtUtil ) {
+ if( edtUtil.isRunning() ) {
+ final boolean res = edtUtil.invokeStop(true, task);
+ if( DEBUG ) {
+ if ( !res ) {
+ System.err.println("Warning: invokeStop() failed");
+ Thread.dumpStack();
+ }
+ }
+ }
+ edtUtil.waitUntilStopped();
+ // ready for restart ..
+ } else if( null != task ) {
task.run();
}
}
- public void runOnEDTIfAvail(boolean wait, final Runnable task) {
- if( shallRunOnEDT() && null!=edtUtil && !edtUtil.isCurrentThreadEDT()) {
- edtUtil.invoke(wait, task);
- } else {
- task.run();
+ public void runOnEDTIfAvail(final boolean wait, final Runnable task) {
+ final EDTUtil _edtUtil = edtUtil;
+ if( !_edtUtil.isRunning() ) { // start EDT if not running yet
+ synchronized( this ) {
+ if( !_edtUtil.isRunning() ) { // // volatile dbl-checked-locking OK
+ if( DEBUG ) {
+ System.err.println("Info: EDT start "+Thread.currentThread().getName()+", "+this);
+ Thread.dumpStack();
+ }
+ _edtUtil.start();
+ }
+ }
+ }
+ if( !_edtUtil.isCurrentThreadEDT() ) {
+ if( _edtUtil.invoke(wait, task) ) {
+ return; // done
+ }
+ if( DEBUG ) {
+ System.err.println("Warning: invoke(wait "+wait+", ..) on EDT failed .. invoke on current thread "+Thread.currentThread().getName());
+ Thread.dumpStack();
+ }
}
+ task.run();
}
- public boolean validateEDT() {
- if(0==refCount && null==aDevice && null != edtUtil && edtUtil.isRunning()) {
- stopEDT( new Runnable() {
- public void run() {
- // nop
+ @Override
+ public boolean validateEDTStopped() {
+ if( 0==refCount && null == aDevice ) {
+ final EDTUtil _edtUtil = edtUtil;
+ if( null != _edtUtil && _edtUtil.isRunning() ) {
+ synchronized( this ) {
+ if( null != edtUtil && edtUtil.isRunning() ) { // // volatile dbl-checked-locking OK
+ stopEDT( edtUtil, null );
+ return true;
+ }
}
- } );
- edtUtil.waitUntilStopped();
- edtUtil.reset();
- return true;
+ }
}
return false;
}
+ @Override
public synchronized final void destroy() {
if(DEBUG) {
dumpDisplayList("Display.destroy("+getFQName()+") BEGIN");
}
synchronized(displayList) {
- displayList.remove(this);
if(0 < displaysActive) {
displaysActive--;
}
+ if(DEBUG) {
+ System.err.println("Display.destroy(): "+this+", active "+displaysActive+" "+getThreadName());
+ }
}
- if(DEBUG) {
- System.err.println("Display.destroy(): "+this+" "+getThreadName());
- }
- final AbstractGraphicsDevice f_aDevice = aDevice;
final DisplayImpl f_dpy = this;
- stopEDT( new Runnable() {
+ final AbstractGraphicsDevice f_aDevice = aDevice;
+ aDevice = null;
+ refCount=0;
+ stopEDT( edtUtil, new Runnable() { // blocks!
+ @Override
public void run() {
if ( null != f_aDevice ) {
- f_dpy.closeNativeImpl();
+ f_dpy.destroyAllPointerIconFromList(f_aDevice.getHandle());
+ f_dpy.closeNativeImpl(f_aDevice);
}
}
} );
- if(null!=edtUtil) {
- edtUtil.waitUntilStopped();
- edtUtil.reset();
- }
- aDevice = null;
- refCount=0;
if(DEBUG) {
dumpDisplayList("Display.destroy("+getFQName()+") END");
}
}
+ /** May be utilized at a shutdown hook, impl. does not block. */
+ /* pp */ static final void shutdownAll() {
+ final int dCount = displayList.size();
+ if(DEBUG) {
+ dumpDisplayList("Display.shutdownAll "+dCount+" instances, on thread "+getThreadName());
+ }
+ for(int i=0; i<dCount && displayList.size()>0; i++) { // be safe ..
+ final DisplayImpl d = (DisplayImpl) displayList.remove(0).get();
+ if(DEBUG) {
+ System.err.println("Display.shutdownAll["+(i+1)+"/"+dCount+"]: "+d+", GCed "+(null==d));
+ }
+ if( null != d ) { // GC'ed ?
+ if(0 < displaysActive) {
+ displaysActive--;
+ }
+ final EDTUtil edtUtil = d.getEDTUtil();
+ final AbstractGraphicsDevice f_aDevice = d.aDevice;
+ d.aDevice = null;
+ d.refCount=0;
+ final Runnable closeNativeTask = new Runnable() {
+ @Override
+ public void run() {
+ if ( null != d.getGraphicsDevice() ) {
+ d.destroyAllPointerIconFromList(f_aDevice.getHandle());
+ d.closeNativeImpl(f_aDevice);
+ }
+ }
+ };
+ if(null != edtUtil) {
+ final long coopSleep = edtUtil.getPollPeriod() * 2;
+ if( edtUtil.isRunning() ) {
+ edtUtil.invokeStop(false, closeNativeTask); // don't block
+ }
+ try {
+ Thread.sleep( coopSleep < 50 ? coopSleep : 50 );
+ } catch (final InterruptedException e) { }
+ } else {
+ closeNativeTask.run();
+ }
+ }
+ }
+ }
+
+ @Override
public synchronized final int addReference() {
if(DEBUG) {
- System.err.println("Display.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1));
+ System.err.println("Display.addReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount+1));
}
if ( 0 == refCount ) {
createNative();
@@ -271,9 +539,10 @@ public abstract class DisplayImpl extends Display {
}
+ @Override
public synchronized final int removeReference() {
if(DEBUG) {
- System.err.println("Display.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1));
+ System.err.println("Display.removeReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount-1));
}
refCount--; // could become < 0, in case of manual destruction without actual creation/addReference
if(0>=refCount) {
@@ -283,50 +552,61 @@ public abstract class DisplayImpl extends Display {
return refCount;
}
+ @Override
public synchronized final int getReferenceCount() {
return refCount;
}
protected abstract void createNativeImpl();
- protected abstract void closeNativeImpl();
+ protected abstract void closeNativeImpl(AbstractGraphicsDevice aDevice);
+ @Override
public final int getId() {
return id;
}
+ @Override
public final String getType() {
return type;
}
+ @Override
public final String getName() {
return name;
}
+ @Override
public final String getFQName() {
return fqname;
}
+ @Override
+ public final boolean isExclusive() {
+ return exclusive;
+ }
+
public static final String nilString = "nil" ;
- public String validateDisplayName(String name, long handle) {
+ public String validateDisplayName(String name, final long handle) {
if(null==name && 0!=handle) {
name="wrapping-"+toHexString(handle);
}
return ( null == name ) ? nilString : name ;
}
- private static String getFQName(String type, String name, int id) {
+ private static String getFQName(String type, String name, final int id) {
if(null==type) type=nilString;
if(null==name) name=nilString;
- StringBuilder sb = new StringBuilder();
+ final StringBuilder sb = new StringBuilder();
sb.append(type);
sb.append("_");
sb.append(name);
sb.append("-");
sb.append(id);
- return sb.toString().intern();
+ return sb.toString();
}
+ @Override
public final long getHandle() {
if(null!=aDevice) {
return aDevice.getHandle();
@@ -334,49 +614,51 @@ public abstract class DisplayImpl extends Display {
return 0;
}
+ @Override
public final AbstractGraphicsDevice getGraphicsDevice() {
return aDevice;
}
+ @Override
public synchronized final boolean isNativeValid() {
return null != aDevice;
}
+ protected final boolean isNativeValidAsync() {
+ return null != aDevice;
+ }
+ @Override
public boolean isEDTRunning() {
- if(null!=edtUtil) {
- return edtUtil.isRunning();
+ final EDTUtil _edtUtil = edtUtil;
+ if( null != _edtUtil ) {
+ return _edtUtil.isRunning();
}
return false;
}
@Override
public String toString() {
- return "NEWT-Display["+getFQName()+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", edtRunning "+isEDTRunning()+", "+aDevice+"]";
+ final EDTUtil _edtUtil = edtUtil;
+ final boolean _edtUtilRunning = ( null != _edtUtil ) ? _edtUtil.isRunning() : false;
+ return "NEWT-Display["+getFQName()+", excl "+exclusive+", refCount "+refCount+", hasEDT "+(null!=_edtUtil)+", edtRunning "+_edtUtilRunning+", "+aDevice+"]";
}
+ /** 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;
- class DispatchMessagesRunnable implements Runnable {
+ final protected Runnable dispatchMessagesRunnable = new Runnable() {
+ @Override
public void run() {
DisplayImpl.this.dispatchMessages();
- }
- }
- protected DispatchMessagesRunnable dispatchMessagesRunnable = new DispatchMessagesRunnable();
+ } };
- final void dispatchMessage(final NEWTEventTask eventTask) {
- final NEWTEvent event = eventTask.get();
- try {
- if(null == event) {
- // Ooops ?
- System.err.println("Warning: event of eventTask is NULL");
- Thread.dumpStack();
- return;
- }
- final Object source = event.getSource();
+ final void dispatchMessage(final NEWTEvent event) {
+ try {
+ final Object source = event.getSource();
if(source instanceof NEWTEventConsumer) {
final NEWTEventConsumer consumer = (NEWTEventConsumer) source ;
if(!consumer.consumeEvent(event)) {
@@ -386,13 +668,28 @@ public abstract class DisplayImpl extends Display {
} else {
throw new RuntimeException("Event source not NEWT: "+source.getClass().getName()+", "+source);
}
- } catch (Throwable t) {
+ } catch (final Throwable t) {
final RuntimeException re;
if(t instanceof RuntimeException) {
re = (RuntimeException) t;
} else {
re = new RuntimeException(t);
}
+ throw re;
+ }
+ }
+
+ final void dispatchMessage(final NEWTEventTask eventTask) {
+ final NEWTEvent event = eventTask.get();
+ try {
+ if(null == event) {
+ // Ooops ?
+ System.err.println("Warning: event of eventTask is NULL");
+ Thread.dumpStack();
+ return;
+ }
+ dispatchMessage(event);
+ } catch (final RuntimeException re) {
if( eventTask.isCallerWaiting() ) {
// propagate exception to caller
eventTask.setException(re);
@@ -400,14 +697,15 @@ public abstract class DisplayImpl extends Display {
throw re;
}
}
- eventTask.notifyCaller();
+ eventTask.notifyCaller();
}
-
+
+ @Override
public void dispatchMessages() {
// System.err.println("Display.dispatchMessages() 0 "+this+" "+getThreadName());
- if(0==refCount || // no screens
+ if(0==refCount || // no screens
null==getGraphicsDevice() // no native device
- )
+ )
{
return;
}
@@ -435,22 +733,23 @@ public abstract class DisplayImpl extends Display {
dispatchMessagesNative();
}
- public void enqueueEvent(boolean wait, NEWTEvent e) {
- if(!isEDTRunning()) {
+ public void enqueueEvent(final boolean wait, final NEWTEvent e) {
+ final EDTUtil _edtUtil = edtUtil;
+ if( !_edtUtil.isRunning() ) {
// oops .. we are already dead
if(DEBUG) {
- Throwable t = new Throwable("Warning: EDT already stopped: wait:="+wait+", "+e);
- t.printStackTrace();
+ System.err.println("Warning: EDT already stopped: wait:="+wait+", "+e);
+ Thread.dumpStack();
}
return;
}
-
+
// can't wait if we are on EDT or NEDT -> consume right away
- if(wait && edtUtil.isCurrentThreadEDTorNEDT() ) {
- dispatchMessage(new NEWTEventTask(e, null));
+ if(wait && _edtUtil.isCurrentThreadEDTorNEDT() ) {
+ dispatchMessage(e);
return;
}
-
+
final Object lock = new Object();
final NEWTEventTask eTask = new NEWTEventTask(e, wait?lock:null);
synchronized(lock) {
@@ -462,42 +761,45 @@ public abstract class DisplayImpl extends Display {
if( wait ) {
try {
lock.wait();
- } catch (InterruptedException ie) {
+ } catch (final InterruptedException ie) {
throw new RuntimeException(ie);
}
if( null != eTask.getException() ) {
throw eTask.getException();
}
- }
+ }
}
}
public interface DisplayRunnable<T> {
T run(long dpy);
- }
- public final <T> T runWithLockedDisplayHandle(DisplayRunnable<T> action) {
- final AbstractGraphicsDevice aDevice = getGraphicsDevice();
- if(null == aDevice) {
- throw new RuntimeException("null device - not initialized: "+this);
- }
+ }
+ public static final <T> T runWithLockedDevice(final AbstractGraphicsDevice device, final DisplayRunnable<T> action) {
T res;
- aDevice.lock();
+ device.lock();
try {
- res = action.run(aDevice.getHandle());
+ res = action.run(device.getHandle());
} finally {
- aDevice.unlock();
+ device.unlock();
}
return res;
}
-
- protected EDTUtil edtUtil = null;
+ public final <T> T runWithLockedDisplayDevice(final DisplayRunnable<T> action) {
+ final AbstractGraphicsDevice device = getGraphicsDevice();
+ if(null == device) {
+ throw new RuntimeException("null device - not initialized: "+this);
+ }
+ return runWithLockedDevice(device, action);
+ }
+
+ protected volatile EDTUtil edtUtil = null;
protected int id;
protected String name;
protected String type;
protected String fqname;
protected int hashCode;
protected int refCount; // number of Display references by Screen
- protected boolean destroyWhenUnused;
+ protected boolean exclusive; // do not share this display, uses NullLock!
protected AbstractGraphicsDevice aDevice;
}
diff --git a/src/newt/classes/jogamp/newt/MonitorDeviceImpl.java b/src/newt/classes/jogamp/newt/MonitorDeviceImpl.java
new file mode 100644
index 000000000..72300740f
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/MonitorDeviceImpl.java
@@ -0,0 +1,146 @@
+/**
+ * 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.Rectangle;
+
+import com.jogamp.common.util.ArrayHashSet;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+import com.jogamp.newt.Screen;
+
+public class MonitorDeviceImpl extends MonitorDevice {
+
+ public MonitorDeviceImpl(final ScreenImpl screen, final int nativeId, final DimensionImmutable sizeMM, final Rectangle viewportPU, final Rectangle viewportWU, final MonitorMode currentMode, final ArrayHashSet<MonitorMode> supportedModes) {
+ super(screen, nativeId, sizeMM, viewportPU, viewportWU, currentMode, supportedModes);
+ }
+
+ @Override
+ public final MonitorMode queryCurrentMode() {
+ final ScreenImpl screenImpl = (ScreenImpl)screen;
+ final ScreenMonitorState sms = screenImpl.getScreenMonitorStatus(true);
+ sms.lock();
+ try {
+ final MonitorMode mm0 = screenImpl.queryCurrentMonitorModeIntern(this);
+ if(null == mm0) {
+ throw new InternalError("getCurrentMonitorModeIntern() == null");
+ }
+ MonitorMode mmU = supportedModes.get(mm0); // unified instance
+ if( null == mmU ) {
+ // add new mode avoiding exception!
+ mmU = sms.getMonitorModes().getOrAdd(mm0);
+ mmU = supportedModes.getOrAdd(mmU);
+ if( Screen.DEBUG ) {
+ System.err.println("Adding new mode: "+mm0+" -> "+mmU);
+ }
+ }
+ // if mode has changed somehow, update it ..
+ if( getCurrentMode().hashCode() != mmU.hashCode() ) {
+ setCurrentModeValue(mmU);
+ sms.fireMonitorModeChanged(this, mmU, true);
+ }
+ return mmU;
+ } finally {
+ sms.unlock();
+ }
+ }
+
+ @Override
+ public final boolean setCurrentMode(final MonitorMode mode) {
+ if(Screen.DEBUG) {
+ System.err.println("Screen.setCurrentMode.0: "+this+" -> "+mode);
+ }
+ final ScreenImpl screenImpl = (ScreenImpl)screen;
+ final ScreenMonitorState sms = screenImpl.getScreenMonitorStatus(true);
+ sms.lock();
+ try {
+ final MonitorMode mmC = queryCurrentMode();
+ final MonitorMode mmU = supportedModes.get(mode); // unify via value hash
+ if( null == mmU ) {
+ throw new IllegalArgumentException("Given mode not in set of modes. Current mode "+mode+", "+this);
+ }
+ if( mmU.equals( mmC ) ) {
+ if(Screen.DEBUG) {
+ System.err.println("Screen.setCurrentMode: 0.0 is-current (skip) "+mmU+" == "+mmC);
+ }
+ return true;
+ }
+ final long tStart;
+ if(Screen.DEBUG) {
+ tStart = System.currentTimeMillis();
+ } else {
+ tStart = 0;
+ }
+
+ sms.fireMonitorModeChangeNotify(this, mmU);
+ if(Screen.DEBUG) {
+ System.err.println("Screen.setCurrentMode ("+(System.currentTimeMillis()-tStart)+"ms): fireModeChangeNotify() "+mmU);
+ }
+
+ boolean success = screenImpl.setCurrentMonitorModeImpl(this, mmU);
+ if(success) {
+ if(Screen.DEBUG) {
+ System.err.println("Screen.setCurrentMode ("+(System.currentTimeMillis()-tStart)+"ms): setCurrentModeImpl() "+mmU+", success(1): "+success);
+ }
+ } else {
+ // 2nd attempt validate!
+ final MonitorMode queriedCurrent = queryCurrentMode(); // may fireModeChanged(..) if successful and differs!
+ success = queriedCurrent.hashCode() == mmU.hashCode() ;
+ if(Screen.DEBUG) {
+ System.err.println("Screen.setCurrentMode.2: queried "+queriedCurrent);
+ System.err.println("Screen.setCurrentMode ("+(System.currentTimeMillis()-tStart)+"ms): setCurrentModeImpl() "+mmU+", success(2): "+success);
+ }
+ }
+ if( success ) {
+ setCurrentModeValue(mmU);
+ modeChanged = !isOriginalMode();
+ }
+ sms.fireMonitorModeChanged(this, mmU, success);
+ if(Screen.DEBUG) {
+ System.err.println("Screen.setCurrentMode ("+(System.currentTimeMillis()-tStart)+"ms): X.X: success "+success+": "+this);
+ }
+ return success;
+ } finally {
+ sms.unlock();
+ }
+ }
+
+ private final void setCurrentModeValue(final MonitorMode currentMode) {
+ this.currentMode = currentMode;
+ }
+
+ /* pp */ final Rectangle getMutuableViewportPU() { return viewportPU; }
+ /* pp */ final Rectangle getMutuableViewportWU() { return viewportWU; }
+
+ /* pp */ final ArrayHashSet<MonitorMode> getSupportedModesImpl() {
+ return supportedModes;
+ }
+
+}
diff --git a/src/newt/classes/jogamp/newt/MonitorModeProps.java b/src/newt/classes/jogamp/newt/MonitorModeProps.java
new file mode 100644
index 000000000..6e376ce48
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/MonitorModeProps.java
@@ -0,0 +1,418 @@
+/**
+ * Copyright 2010 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 com.jogamp.common.util.ArrayHashSet;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+
+import java.util.List;
+import javax.media.nativewindow.util.Dimension;
+import javax.media.nativewindow.util.DimensionImmutable;
+import javax.media.nativewindow.util.Rectangle;
+import javax.media.nativewindow.util.SurfaceSize;
+
+import jogamp.newt.MonitorDeviceImpl;
+import jogamp.newt.ScreenImpl;
+
+/**
+ * Encodes and decodes {@link MonitorMode} and {@link MonitorDevice} properties.
+ */
+public class MonitorModeProps {
+ /**
+ * {@value} Elements: width, height
+ * <p>
+ * WARNING: must be synchronized with ScreenMode.h, native implementation
+ * </p>
+ */
+ public static final int NUM_RESOLUTION_PROPERTIES = 2;
+
+ /**
+ * {@value} Element: bpp
+ * <p>
+ * WARNING: must be synchronized with ScreenMode.h, native implementation
+ * </p>
+ */
+ public static final int NUM_SURFACE_SIZE_PROPERTIES = 1;
+
+ /**
+ * {@value} Elements: refresh-rate (Hz*100), flags
+ * <p>
+ * WARNING: must be synchronized with ScreenMode.h, native implementation
+ * </p>
+ */
+ public static final int NUM_SIZEANDRATE_PROPERTIES = 2;
+
+ /**
+ * {@value} Elements: id, rotation
+ * <p>
+ * WARNING: must be synchronized with ScreenMode.h, native implementation
+ * </p>
+ */
+ public static final int NUM_MONITOR_MODE_PROPERTIES = 2;
+
+ /**
+ * {@value} Elements:
+ * <ul>
+ * <li>count</li>
+ * <li>{@link #NUM_RESOLUTION_PROPERTIES}</li>
+ * <li>{@link #NUM_SURFACE_SIZE_PROPERTIES}</li>
+ * <li>{@link #NUM_SIZEANDRATE_PROPERTIES}</li>
+ * <li>{@link #NUM_MONITOR_MODE_PROPERTIES}</li>
+ * <li>mode-id</li>
+ * </ul>
+ * <p>
+ * WARNING: must be synchronized with ScreenMode.h, native implementation
+ * </p>
+ */
+ public static final int NUM_MONITOR_MODE_PROPERTIES_ALL = 8;
+
+ /**
+ * {@value} Elements: count + {@link #NUM_RESOLUTION_PROPERTIES}
+ * <p>
+ * WARNING: must be synchronized with ScreenMode.h, native implementation
+ * </p>
+ */
+ public static final int IDX_MONITOR_MODE_BPP = 1 // count
+ + MonitorModeProps.NUM_RESOLUTION_PROPERTIES
+ ;
+ /**
+ * {@value} Elements:
+ * <ul>
+ * <li>count</li>
+ * <li>{@link #NUM_RESOLUTION_PROPERTIES}</li>
+ * <li>{@link #NUM_SURFACE_SIZE_PROPERTIES}</li>
+ * <li>{@link #NUM_SIZEANDRATE_PROPERTIES}</li>
+ * <li>mode-id</li>
+ * </ul>
+ * <p>
+ * WARNING: must be synchronized with ScreenMode.h, native implementation
+ * </p>
+ */
+ public static final int IDX_MONITOR_MODE_ROT = 1 // count
+ + MonitorModeProps.NUM_RESOLUTION_PROPERTIES
+ + MonitorModeProps.NUM_SURFACE_SIZE_PROPERTIES
+ + MonitorModeProps.NUM_SIZEANDRATE_PROPERTIES
+ + 1 // id of MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES
+ ;
+
+ /**
+ * {@value} Elements:
+ * <ul>
+ * <li>count</li>
+ * <li>id</li>
+ * <li>ScreenSizeMM[width, height] (2 elements)</li>
+ * <li>Rotated Viewport pixel-units (4 elements)</li>
+ * <li>Rotated Viewport window-units (4 elements)</li>
+ * <li>CurrentMonitorModeId</li>
+ * <li>Rotation</li>
+ * <li>SupportedModeId+</li>
+ * </ul>
+ * <p>
+ * Viewport := [x, y, width, height] (4 elements)
+ * </p>
+ * <p>
+ * WARNING: must be synchronized with ScreenMode.h, native implementation
+ * </p>
+ */
+ public static final int MIN_MONITOR_DEVICE_PROPERTIES = 15;
+
+ public static final int IDX_MONITOR_DEVICE_VIEWPORT = 1 // count
+ + 1 // native mode
+ + MonitorModeProps.NUM_RESOLUTION_PROPERTIES // sizeMM
+ ;
+
+ public static class Cache {
+ public final ArrayHashSet<DimensionImmutable> resolutions = new ArrayHashSet<DimensionImmutable>();
+ public final ArrayHashSet<SurfaceSize> surfaceSizes = new ArrayHashSet<SurfaceSize>();
+ public final ArrayHashSet<MonitorMode.SizeAndRRate> sizeAndRates = new ArrayHashSet<MonitorMode.SizeAndRRate>();
+ public final ArrayHashSet<MonitorMode> monitorModes = new ArrayHashSet<MonitorMode>();
+ public final ArrayHashSet<MonitorDevice> monitorDevices = new ArrayHashSet<MonitorDevice>();
+ }
+
+ /** WARNING: must be synchronized with ScreenMode.h, native implementation */
+ private static DimensionImmutable streamInResolution(final int[] resolutionProperties, int offset) {
+ final Dimension resolution = new Dimension(resolutionProperties[offset++], resolutionProperties[offset++]);
+ return resolution;
+ }
+
+ /** WARNING: must be synchronized with ScreenMode.h, native implementation */
+ private static SurfaceSize streamInSurfaceSize(final DimensionImmutable resolution, final int[] sizeProperties, final int offset) {
+ return new SurfaceSize(resolution, sizeProperties[offset]);
+ }
+
+ /** WARNING: must be synchronized with ScreenMode.h, native implementation */
+ private static MonitorMode.SizeAndRRate streamInSizeAndRRate(final SurfaceSize surfaceSize, final int[] sizeAndRRateProperties, int offset) {
+ final float refreshRate = sizeAndRRateProperties[offset++]/100.0f;
+ final int flags = sizeAndRRateProperties[offset++];
+ return new MonitorMode.SizeAndRRate(surfaceSize, refreshRate, flags);
+ }
+
+ /** WARNING: must be synchronized with ScreenMode.h, native implementation */
+ private static MonitorMode streamInMonitorMode0(final MonitorMode.SizeAndRRate sizeAndRate, final int[] modeProperties, int offset) {
+ final int id = modeProperties[offset++];
+ final int rotation = modeProperties[offset++];
+ return new MonitorMode(id, sizeAndRate, rotation);
+ }
+
+ /**
+ * WARNING: must be synchronized with ScreenMode.h, native implementation
+ *
+ * @param mode_idx if not null and cache is given, returns the index of resulting {@link MonitorMode} within {@link Cache#monitorModes}.
+ * @param cache optional hash arrays of unique {@link MonitorMode} components and {@link MonitorDevice}s, allowing to avoid duplicates
+ * @param modeProperties the input data
+ * @param offset the offset to the input data
+ * @return {@link MonitorMode} of the identical (old or new) element in {@link Cache#monitorModes},
+ * matching the input <code>modeProperties</code>, or null if input could not be processed.
+ */
+ public static MonitorMode streamInMonitorMode(final int[] mode_idx, final Cache cache,
+ final int[] modeProperties, int offset) {
+ final int count = modeProperties[offset];
+ if(NUM_MONITOR_MODE_PROPERTIES_ALL != count) {
+ throw new RuntimeException("property count should be "+NUM_MONITOR_MODE_PROPERTIES_ALL+", but is "+count+", len "+(modeProperties.length-offset));
+ }
+ if(NUM_MONITOR_MODE_PROPERTIES_ALL > modeProperties.length-offset) {
+ throw new RuntimeException("properties array too short, should be >= "+NUM_MONITOR_MODE_PROPERTIES_ALL+", is "+(modeProperties.length-offset));
+ }
+ offset++;
+ DimensionImmutable resolution = MonitorModeProps.streamInResolution(modeProperties, offset);
+ offset += MonitorModeProps.NUM_RESOLUTION_PROPERTIES;
+ if(null!=cache) {
+ resolution = cache.resolutions.getOrAdd(resolution);
+ }
+
+ SurfaceSize surfaceSize = MonitorModeProps.streamInSurfaceSize(resolution, modeProperties, offset);
+ offset += MonitorModeProps.NUM_SURFACE_SIZE_PROPERTIES;
+ if(null!=cache) {
+ surfaceSize = cache.surfaceSizes.getOrAdd(surfaceSize);
+ }
+
+ MonitorMode.SizeAndRRate sizeAndRate = MonitorModeProps.streamInSizeAndRRate(surfaceSize, modeProperties, offset);
+ offset += MonitorModeProps.NUM_SIZEANDRATE_PROPERTIES;
+ if(null!=cache) {
+ sizeAndRate = cache.sizeAndRates.getOrAdd(sizeAndRate);
+ }
+
+ MonitorMode monitorMode = MonitorModeProps.streamInMonitorMode0(sizeAndRate, modeProperties, offset);
+ if(null!=cache) {
+ monitorMode = cache.monitorModes.getOrAdd(monitorMode);
+ }
+ if( null != mode_idx && null!=cache) {
+ final int _modeIdx = cache.monitorModes.indexOf(monitorMode);
+ if( 0 > _modeIdx ) {
+ throw new InternalError("Invalid index of current unified mode "+monitorMode);
+ }
+ mode_idx[0] = _modeIdx;
+ }
+ return monitorMode;
+ }
+
+ /** WARNING: must be synchronized with ScreenMode.h, native implementation */
+ public static int[] streamOutMonitorMode (final MonitorMode monitorMode) {
+ final int[] data = new int[NUM_MONITOR_MODE_PROPERTIES_ALL];
+ int idx=0;
+ data[idx++] = NUM_MONITOR_MODE_PROPERTIES_ALL;
+ data[idx++] = monitorMode.getSurfaceSize().getResolution().getWidth();
+ data[idx++] = monitorMode.getSurfaceSize().getResolution().getHeight();
+ data[idx++] = monitorMode.getSurfaceSize().getBitsPerPixel();
+ data[idx++] = (int)(monitorMode.getRefreshRate()*100.0f); // Hz*100
+ data[idx++] = monitorMode.getFlags();
+ data[idx++] = monitorMode.getId();
+ data[idx++] = monitorMode.getRotation();
+ if(NUM_MONITOR_MODE_PROPERTIES_ALL != idx) {
+ throw new InternalError("wrong number of attributes: got "+idx+" != should "+NUM_MONITOR_MODE_PROPERTIES_ALL);
+ }
+ return data;
+ }
+
+ /**
+ * WARNING: must be synchronized with ScreenMode.h, native implementation
+ * <p>
+ * Note: This variant only works for impl. w/ a unique mode key pair <i>modeId, rotation</i>.
+ * </p>
+ * @param mode_idx if not null, returns the index of resulting {@link MonitorDevice} within {@link Cache#monitorDevices}.
+ * @param cache hash arrays of unique {@link MonitorMode} components and {@link MonitorDevice}s, allowing to avoid duplicates
+ * @param modeProperties the input data
+ * @param offset the offset to the input data
+ * @return {@link MonitorDevice} of the identical (old or new) element in {@link Cache#monitorDevices},
+ * matching the input <code>modeProperties</code>, or null if input could not be processed.
+ */
+ public static MonitorDevice streamInMonitorDevice(final int[] monitor_idx, final Cache cache, final ScreenImpl screen, final int[] monitorProperties, int offset) {
+ // min 11: count, id, ScreenSizeMM[width, height], Viewport[x, y, width, height], currentMonitorModeId, rotation, supportedModeId+
+ final int count = monitorProperties[offset];
+ if(MIN_MONITOR_DEVICE_PROPERTIES > count) {
+ throw new RuntimeException("property count should be >= "+MIN_MONITOR_DEVICE_PROPERTIES+", but is "+count+", len "+(monitorProperties.length-offset));
+ }
+ if(MIN_MONITOR_DEVICE_PROPERTIES > monitorProperties.length-offset) {
+ throw new RuntimeException("properties array too short (min), should be >= "+MIN_MONITOR_DEVICE_PROPERTIES+", is "+(monitorProperties.length-offset));
+ }
+ if(count > monitorProperties.length-offset) {
+ throw new RuntimeException("properties array too short (count), should be >= "+count+", is "+(monitorProperties.length-offset));
+ }
+ final int limit = offset + count;
+ offset++;
+ final List<MonitorMode> allMonitorModes = cache.monitorModes.getData();
+ final int id = monitorProperties[offset++];
+ final DimensionImmutable sizeMM = streamInResolution(monitorProperties, offset); offset+=NUM_RESOLUTION_PROPERTIES;
+ final Rectangle viewportPU = new Rectangle(monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++]);
+ final Rectangle viewportWU = new Rectangle(monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++]);
+ final MonitorMode currentMode;
+ {
+ final int modeId = monitorProperties[offset++];
+ final int rotation = monitorProperties[offset++];
+ currentMode = getByNativeIdAndRotation(allMonitorModes, modeId, rotation);
+ }
+ final ArrayHashSet<MonitorMode> supportedModes = new ArrayHashSet<MonitorMode>();
+ while( offset < limit ) {
+ final int modeId = monitorProperties[offset++];
+ for (int i=0; i<allMonitorModes.size(); i++) {
+ final MonitorMode mode = allMonitorModes.get(i);
+ if( mode.getId() == modeId ) {
+ supportedModes.add(mode);
+ }
+ }
+ }
+ MonitorDevice monitorDevice = new MonitorDeviceImpl(screen, id, sizeMM, viewportPU, viewportWU, currentMode, supportedModes);
+ if(null!=cache) {
+ monitorDevice = cache.monitorDevices.getOrAdd(monitorDevice);
+ }
+ if( null != monitor_idx ) {
+ final int _monitorIdx = cache.monitorDevices.indexOf(monitorDevice);
+ if( 0 > _monitorIdx ) {
+ throw new InternalError("Invalid index of current unified mode "+monitorDevice);
+ }
+ monitor_idx[0] = _monitorIdx;
+ }
+ return monitorDevice;
+ }
+ private static MonitorMode getByNativeIdAndRotation(final List<MonitorMode> monitorModes, final int modeId, final int rotation) {
+ if( null!=monitorModes && monitorModes.size()>0 ) {
+ for (int i=0; i<monitorModes.size(); i++) {
+ final MonitorMode mode = monitorModes.get(i);
+ if( mode.getId() == modeId && mode.getRotation() == rotation ) {
+ return mode;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * WARNING: must be synchronized with ScreenMode.h, native implementation
+ * <p>
+ * This variant expects <code>count</code> to be <code>{@link MIN_MONITOR_DEVICE_PROPERTIES} - 1 - {@link NUM_MONITOR_MODE_PROPERTIES}</code>,
+ * due to lack of supported mode and current mode.
+ * </p>
+ *
+ * @param mode_idx if not null, returns the index of resulting {@link MonitorDevice} within {@link Cache#monitorDevices}.
+ * @param cache hash arrays of unique {@link MonitorMode} components and {@link MonitorDevice}s, allowing to avoid duplicates
+ * @param supportedModes pre-assembled list of supported {@link MonitorMode}s from cache.
+ * @param currentMode pre-fetched current {@link MonitorMode}s from cache.
+ * @param modeProperties the input data minus supported modes!
+ * @param offset the offset to the input data
+ * @return {@link MonitorDevice} of the identical (old or new) element in {@link Cache#monitorDevices},
+ * matching the input <code>modeProperties</code>, or null if input could not be processed.
+ */
+ public static MonitorDevice streamInMonitorDevice(final int[] monitor_idx, final Cache cache, final ScreenImpl screen, final ArrayHashSet<MonitorMode> supportedModes, final MonitorMode currentMode, final int[] monitorProperties, int offset) {
+ // min 11: count, id, ScreenSizeMM[width, height], Viewport[x, y, width, height], currentMonitorModeId, rotation, supportedModeId+
+ final int count = monitorProperties[offset];
+ if(MIN_MONITOR_DEVICE_PROPERTIES - 1 - NUM_MONITOR_MODE_PROPERTIES != count) {
+ throw new RuntimeException("property count should be == "+(MIN_MONITOR_DEVICE_PROPERTIES-1-NUM_MONITOR_MODE_PROPERTIES)+", but is "+count+", len "+(monitorProperties.length-offset));
+ }
+ if(MIN_MONITOR_DEVICE_PROPERTIES - 1 - NUM_MONITOR_MODE_PROPERTIES > monitorProperties.length-offset) {
+ throw new RuntimeException("properties array too short (min), should be >= "+(MIN_MONITOR_DEVICE_PROPERTIES-1-NUM_MONITOR_MODE_PROPERTIES)+", is "+(monitorProperties.length-offset));
+ }
+ if(count > monitorProperties.length-offset) {
+ throw new RuntimeException("properties array too short (count), should be >= "+count+", is "+(monitorProperties.length-offset));
+ }
+ offset++;
+ final int id = monitorProperties[offset++];
+ final DimensionImmutable sizeMM = streamInResolution(monitorProperties, offset); offset+=NUM_RESOLUTION_PROPERTIES;
+ final Rectangle viewportPU = new Rectangle(monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++]);
+ final Rectangle viewportWU = new Rectangle(monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++]);
+ MonitorDevice monitorDevice = new MonitorDeviceImpl(screen, id, sizeMM, viewportPU, viewportWU, currentMode, supportedModes);
+ if(null!=cache) {
+ monitorDevice = cache.monitorDevices.getOrAdd(monitorDevice);
+ }
+ if( null != monitor_idx ) {
+ final int _monitorIdx = cache.monitorDevices.indexOf(monitorDevice);
+ if( 0 > _monitorIdx ) {
+ throw new InternalError("Invalid index of current unified mode "+monitorDevice);
+ }
+ monitor_idx[0] = _monitorIdx;
+ }
+ return monitorDevice;
+ }
+
+ /** WARNING: must be synchronized with ScreenMode.h, native implementation */
+ public static int[] streamOutMonitorDevice (final MonitorDevice monitorDevice) {
+ // min 11: count, id, ScreenSizeMM[width, height], Viewport[x, y, width, height], currentMonitorModeId, rotation, supportedModeId+
+ final int supportedModeCount = monitorDevice.getSupportedModes().size();
+ if( 0 == supportedModeCount ) {
+ throw new RuntimeException("no supported modes: "+monitorDevice);
+ }
+ final int[] data = new int[MIN_MONITOR_DEVICE_PROPERTIES + supportedModeCount - 1];
+ int idx=0;
+ data[idx++] = data.length;
+ data[idx++] = monitorDevice.getId();
+ data[idx++] = monitorDevice.getSizeMM().getWidth();
+ data[idx++] = monitorDevice.getSizeMM().getHeight();
+ data[idx++] = monitorDevice.getViewport().getX();
+ data[idx++] = monitorDevice.getViewport().getY();
+ data[idx++] = monitorDevice.getViewport().getWidth();
+ data[idx++] = monitorDevice.getViewport().getHeight();
+ data[idx++] = monitorDevice.getViewportInWindowUnits().getX();
+ data[idx++] = monitorDevice.getViewportInWindowUnits().getY();
+ data[idx++] = monitorDevice.getViewportInWindowUnits().getWidth();
+ data[idx++] = monitorDevice.getViewportInWindowUnits().getHeight();
+ data[idx++] = monitorDevice.getCurrentMode().getId();
+ data[idx++] = monitorDevice.getCurrentMode().getRotation();
+ final List<MonitorMode> supportedModes = monitorDevice.getSupportedModes();
+ for(int i=0; i<supportedModes.size(); i++) {
+ data[idx++] = supportedModes.get(i).getId();
+ }
+ if(data.length != idx) {
+ throw new InternalError("wrong number of attributes: got "+idx+" != should "+data.length);
+ }
+ return data;
+ }
+
+ public final void swapRotatePair(final int rotation, final int[] pairs, int offset, final int numPairs) {
+ if( MonitorMode.ROTATE_0 == rotation || MonitorMode.ROTATE_180 == rotation ) {
+ // nop
+ return;
+ }
+ for(int i=0; i<numPairs; i++, offset+=2) {
+ final int tmp = pairs[offset];
+ pairs[offset] = pairs[offset+1];
+ pairs[offset+1] = tmp;
+ }
+ }
+
+}
diff --git a/src/newt/classes/jogamp/newt/NEWTJNILibLoader.java b/src/newt/classes/jogamp/newt/NEWTJNILibLoader.java
index bc0eb7531..793fbf9b0 100644
--- a/src/newt/classes/jogamp/newt/NEWTJNILibLoader.java
+++ b/src/newt/classes/jogamp/newt/NEWTJNILibLoader.java
@@ -1,21 +1,21 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -28,11 +28,11 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
- *
+ *
* Sun gratefully acknowledges that this software was originally authored
* and developed by Kenneth Bradley Russell and Christopher John Kline.
*/
@@ -42,29 +42,22 @@ package jogamp.newt;
import java.security.AccessController;
import java.security.PrivilegedAction;
-import jogamp.nativewindow.NWJNILibLoader;
-
import com.jogamp.common.jvm.JNILibLoaderBase;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.cache.TempJarCache;
public class NEWTJNILibLoader extends JNILibLoaderBase {
-
- public static void loadNEWT() {
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- Platform.initSingleton();
- final String libName = "newt";
- if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) {
- // either: [jogl-all.jar, jogl-all-noawt.jar, jogl-all-mobile.jar] -> jogl-all-natives-<os.and.arch>.jar
- // or: nativewindow-core.jar -> nativewindow-natives-<os.and.arch>.jar,
- // newt-core.jar -> newt-natives-<os.and.arch>.jar
- JNILibLoaderBase.addNativeJarLibs(new Class<?>[] { NWJNILibLoader.class, NEWTJNILibLoader.class }, "-all", new String[] { "-noawt", "-mobile", "-core" } );
- }
- loadLibrary(libName, false, NEWTJNILibLoader.class.getClassLoader());
- return null;
- }
- });
- }
-
+ public static boolean loadNEWT() {
+ return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+ @Override
+ public Boolean run() {
+ Platform.initSingleton();
+ final String libName = "newt";
+ if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) {
+ JNILibLoaderBase.addNativeJarLibsJoglCfg(new Class<?>[] { jogamp.nativewindow.Debug.class, jogamp.newt.Debug.class });
+ }
+ return Boolean.valueOf(loadLibrary(libName, false, NEWTJNILibLoader.class.getClassLoader()));
+ }
+ }).booleanValue();
+ }
}
diff --git a/src/newt/classes/jogamp/newt/OffscreenWindow.java b/src/newt/classes/jogamp/newt/OffscreenWindow.java
index c6c1814f6..749391f1f 100644
--- a/src/newt/classes/jogamp/newt/OffscreenWindow.java
+++ b/src/newt/classes/jogamp/newt/OffscreenWindow.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,11 +29,13 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt;
+import java.util.List;
+
import javax.media.nativewindow.AbstractGraphicsConfiguration;
import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.GraphicsConfigurationFactory;
@@ -43,16 +45,19 @@ import javax.media.nativewindow.VisualIDHolder;
import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.Point;
+import com.jogamp.newt.MonitorDevice;
+
public class OffscreenWindow extends WindowImpl implements MutableSurface {
long surfaceHandle;
-
+
public OffscreenWindow() {
surfaceHandle = 0;
}
static long nextWindowHandle = 0x100; // start here - a marker
+ @Override
protected void createNativeImpl() {
if(capsRequested.isOnscreen()) {
throw new NativeWindowException("Capabilities is onscreen");
@@ -68,9 +73,10 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface {
synchronized(OffscreenWindow.class) {
setWindowHandle(nextWindowHandle++);
}
- visibleChanged(false, true);
+ visibleChanged(false, true);
}
+ @Override
protected void closeNativeImpl() {
// nop
}
@@ -81,30 +87,38 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface {
surfaceHandle = 0;
}
- public void setSurfaceHandle(long handle) {
+ @Override
+ public void setSurfaceHandle(final long handle) {
surfaceHandle = handle ;
}
@Override
public long getSurfaceHandle() {
return surfaceHandle;
- }
+ }
- protected void requestFocusImpl(boolean reparented) {
+ @Override
+ protected void requestFocusImpl(final boolean reparented) {
}
@Override
- public void setPosition(int x, int y) {
+ public void setPosition(final int x, final int y) {
// nop
}
-
+
@Override
- public boolean setFullscreen(boolean fullscreen) {
- // nop
- return false;
+ public boolean setFullscreen(final boolean fullscreen) {
+ return false; // nop
}
- protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
+ @Override
+ public boolean setFullscreen(final List<MonitorDevice> monitors) {
+ return false; // nop
+ }
+
+
+ @Override
+ protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) {
sizeChanged(false, width, height, false);
if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
@@ -121,21 +135,22 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface {
}
@Override
- public Point getLocationOnScreen(Point storage) {
+ public Point getLocationOnScreen(final Point storage) {
if(null!=storage) {
- storage.setX(0);
- storage.setY(0);
+ storage.set(0, 0);
return storage;
}
return new Point(0,0);
}
-
- protected Point getLocationOnScreenImpl(int x, int y) {
+
+ @Override
+ protected Point getLocationOnScreenImpl(final int x, final int y) {
return new Point(x,y);
}
-
- protected void updateInsetsImpl(Insets insets) {
- // nop ..
+
+ @Override
+ protected void updateInsetsImpl(final Insets insets) {
+ // nop ..
}
}
diff --git a/src/newt/classes/jogamp/newt/PointerIconImpl.java b/src/newt/classes/jogamp/newt/PointerIconImpl.java
new file mode 100644
index 000000000..546a463de
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/PointerIconImpl.java
@@ -0,0 +1,171 @@
+/**
+ * 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 java.nio.ByteBuffer;
+
+import javax.media.nativewindow.util.DimensionImmutable;
+import javax.media.nativewindow.util.PixelFormat;
+import javax.media.nativewindow.util.PixelRectangle;
+import javax.media.nativewindow.util.PointImmutable;
+
+import com.jogamp.newt.Display;
+import com.jogamp.newt.Display.PointerIcon;
+
+public class PointerIconImpl implements PointerIcon {
+ private final DisplayImpl display;
+ private final PixelFormat pixelformat;
+ private final DimensionImmutable size;
+ private final ByteBuffer pixels;
+ private final PointImmutable hotspot;
+ private long handle;
+ private int hashCode = 0;
+ private volatile boolean hashCodeComputed = false;
+
+ public PointerIconImpl(final DisplayImpl display, final PixelFormat pixelformat, final DimensionImmutable size, final ByteBuffer pixels, final PointImmutable hotspot, final long handle) {
+ this.display = display;
+ this.pixelformat = pixelformat;
+ this.size = size;
+ this.pixels = pixels;
+ this.hotspot = hotspot;
+
+ this.handle=handle;
+ }
+ public PointerIconImpl(final DisplayImpl display, final PixelRectangle pixelrect, final PointImmutable hotspot, final long handle) {
+ this.display = display;
+ this.pixelformat = pixelrect.getPixelformat();
+ this.size = pixelrect.getSize();
+ this.pixels = pixelrect.getPixels();
+ this.hotspot = hotspot;
+ this.handle=handle;
+ }
+
+ @Override
+ public int hashCode() {
+ if( !hashCodeComputed ) { // DBL CHECKED OK VOLATILE
+ synchronized (this) {
+ if( !hashCodeComputed ) {
+ // 31 * x == (x << 5) - x
+ int hash = 31 + display.getFQName().hashCode();
+ hash = ((hash << 5) - hash) + pixelformat.hashCode();
+ hash = ((hash << 5) - hash) + size.hashCode();
+ hash = ((hash << 5) - hash) + getStride();
+ hash = ((hash << 5) - hash) + ( isGLOriented() ? 1 : 0);
+ hash = ((hash << 5) - hash) + pixels.hashCode();
+ hashCode = ((hash << 5) - hash) + hotspot.hashCode();
+ }
+ }
+ }
+ return hashCode;
+ }
+
+ 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 {
+ handle = display.createPointerIconImpl(pixelformat, size.getWidth(), size.getHeight(), pixels, hotspot.getX(), hotspot.getY());
+ return handle;
+ } catch (final Exception e) {
+ e.printStackTrace();
+ return 0;
+ }
+ } else {
+ return handle;
+ }
+ }
+ @Override
+ public final Display getDisplay() { return display; }
+ @Override
+ public final PixelFormat getPixelformat() { return pixelformat; }
+ @Override
+ public final ByteBuffer getPixels() { return pixels; }
+ @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(Display.DEBUG) {
+ System.err.println("PointerIcon.destroy: "+this+", "+display+", "+Display.getThreadName());
+ }
+ if( 0 != handle ) {
+ synchronized(display.pointerIconList) {
+ display.pointerIconList.remove(this);
+ }
+ display.runOnEDTIfAvail(false, new Runnable() {
+ public void run() {
+ if( !display.isNativeValidAsync() ) {
+ 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 (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public final DimensionImmutable getSize() {
+ return size;
+ }
+ @Override
+ public final int getStride() {
+ return size.getWidth() * pixelformat.bytesPerPixel();
+ }
+ @Override
+ public final boolean isGLOriented() {
+ return false;
+ }
+ @Override
+ public final PointImmutable getHotspot() {
+ return hotspot;
+ }
+ @Override
+ public final String toString() {
+ return "PointerIcon[obj 0x"+Integer.toHexString(super.hashCode())+", "+display.getFQName()+", 0x"+Long.toHexString(handle)+", "+pixelformat+", "+size+", "+hotspot+", pixels "+pixels+"]";
+ }
+} \ No newline at end of file
diff --git a/src/newt/classes/jogamp/newt/ScreenImpl.java b/src/newt/classes/jogamp/newt/ScreenImpl.java
index e2c0f746f..e73e153ad 100644
--- a/src/newt/classes/jogamp/newt/ScreenImpl.java
+++ b/src/newt/classes/jogamp/newt/ScreenImpl.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,84 +29,84 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.NativeWindowException;
-import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.util.Dimension;
-import javax.media.nativewindow.util.DimensionImmutable;
-import javax.media.nativewindow.util.Point;
-import javax.media.nativewindow.util.SurfaceSize;
-
+import javax.media.nativewindow.util.Rectangle;
+import javax.media.nativewindow.util.RectangleImmutable;
import com.jogamp.common.util.ArrayHashSet;
-import com.jogamp.common.util.IntIntHashMap;
+import com.jogamp.common.util.PropertyAccess;
import com.jogamp.newt.Display;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.Screen;
-import com.jogamp.newt.ScreenMode;
-import com.jogamp.newt.event.ScreenModeListener;
-import com.jogamp.newt.util.MonitorMode;
-import com.jogamp.newt.util.ScreenModeUtil;
-
-public abstract class ScreenImpl extends Screen implements ScreenModeListener {
- protected static final boolean DEBUG_TEST_SCREENMODE_DISABLED = Debug.isPropertyDefined("newt.test.Screen.disableScreenMode", true);
-
- protected static final int default_sm_bpp = 32;
- protected static final int default_sm_widthmm = 519;
- protected static final int default_sm_heightmm = 324;
- protected static final int default_sm_rate = 60;
- protected static final int default_sm_rotation = 0;
-
+import com.jogamp.newt.event.MonitorEvent;
+import com.jogamp.newt.event.MonitorModeListener;
+import com.jogamp.newt.util.MonitorModeUtil;
+
+public abstract class ScreenImpl extends Screen implements MonitorModeListener {
+ protected static final boolean DEBUG_TEST_SCREENMODE_DISABLED;
+
+ static {
+ Debug.initSingleton();
+ DEBUG_TEST_SCREENMODE_DISABLED = PropertyAccess.isPropertyDefined("newt.test.Screen.disableScreenMode", true);
+ }
+
+ public static final int default_sm_bpp = 32;
+ public static final int default_sm_widthmm = 519;
+ public static final int default_sm_heightmm = 324;
+ public static final int default_sm_rate = 60;
+ public static final int default_sm_rotation = 0;
+
+ static {
+ DisplayImpl.initSingleton();
+ }
+
+ /** Ensure static init has been run. */
+ /* pp */static void initSingleton() { }
+
protected DisplayImpl display;
protected int screen_idx;
protected String fqname;
protected int hashCode;
protected AbstractGraphicsScreen aScreen;
protected int refCount; // number of Screen references by Window
- protected Point vOrigin = new Point(0, 0); // virtual top-left origin
- protected Dimension vSize = new Dimension(0, 0); // virtual rotated screen size
+ protected Rectangle virtViewportPU = new Rectangle(0, 0, 0, 0); // virtual rotated viewport in pixel units
+ protected Rectangle virtViewportWU = new Rectangle(0, 0, 0, 0); // virtual rotated viewport in window units
protected static Dimension usrSize = null; // property values: newt.ws.swidth and newt.ws.sheight
protected static volatile boolean usrSizeQueried = false;
- private ArrayList<ScreenModeListener> referencedScreenModeListener = new ArrayList<ScreenModeListener>();
+ private final ArrayList<MonitorModeListener> refMonitorModeListener = new ArrayList<MonitorModeListener>();
+
private long tCreated; // creationTime
- static {
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- registerShutdownHook();
- return null;
- }
- });
- }
-
- private static Class<?> getScreenClass(String type) throws ClassNotFoundException
+ private static Class<?> getScreenClass(final String type) throws ClassNotFoundException
{
final Class<?> screenClass = NewtFactory.getCustomClass(type, "ScreenDriver");
if(null==screenClass) {
- throw new ClassNotFoundException("Failed to find NEWT Screen Class <"+type+".ScreenDriver>");
+ throw new ClassNotFoundException("Failed to find NEWT Screen Class <"+type+".ScreenDriver>");
}
return screenClass;
}
- public static Screen create(Display display, int idx) {
+ public static Screen create(final Display display, int idx) {
try {
if(!usrSizeQueried) {
synchronized (Screen.class) {
if(!usrSizeQueried) {
usrSizeQueried = true;
- final int w = Debug.getIntProperty("newt.ws.swidth", true, 0);
- final int h = Debug.getIntProperty("newt.ws.sheight", true, 0);
+ final int w = PropertyAccess.getIntProperty("newt.ws.swidth", true, 0);
+ final int h = PropertyAccess.getIntProperty("newt.ws.sheight", true, 0);
if(w>0 && h>0) {
usrSize = new Dimension(w, h);
System.err.println("User screen size "+usrSize);
@@ -115,12 +115,12 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener {
}
}
synchronized(screenList) {
- Class<?> screenClass = getScreenClass(display.getType());
+ final Class<?> screenClass = getScreenClass(display.getType());
ScreenImpl screen = (ScreenImpl) screenClass.newInstance();
screen.display = (DisplayImpl) display;
idx = screen.validateScreenIndex(idx);
{
- Screen screen0 = ScreenImpl.getLastScreenOf(display, idx, -1);
+ final Screen screen0 = Screen.getLastScreenOf(display, idx, -1);
if(null != screen0) {
if(DEBUG) {
System.err.println("Screen.create() REUSE: "+screen0+" "+Display.getThreadName());
@@ -130,21 +130,30 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener {
}
}
screen.screen_idx = idx;
- screen.fqname = (display.getFQName()+idx).intern();
+ screen.fqname = display.getFQName()+"-s"+idx;
screen.hashCode = screen.fqname.hashCode();
- screenList.add(screen);
+ screen.instantiationFinished();
+ Screen.addScreen2List(screen);
if(DEBUG) {
System.err.println("Screen.create() NEW: "+screen+" "+Display.getThreadName());
}
return screen;
- }
- } catch (Exception e) {
+ }
+ } catch (final Exception e) {
throw new RuntimeException(e);
}
}
+ /**
+ * Notifies the driver impl. that the instantiation is finished,
+ * ie. instance created and all fields set.
+ */
+ protected void instantiationFinished() {
+ // nop
+ }
+
@Override
- public boolean equals(Object obj) {
+ public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
@@ -161,52 +170,54 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener {
return true;
}
+ @Override
public int hashCode() {
return hashCode;
}
+ @Override
public synchronized final void createNative()
throws NativeWindowException
- {
+ {
if(null == aScreen) {
if(DEBUG) {
tCreated = System.nanoTime();
- System.err.println("Screen.createNative() START ("+DisplayImpl.getThreadName()+", "+this+")");
+ System.err.println("Screen.createNative() START ("+Display.getThreadName()+", "+this+")");
} else {
tCreated = 0;
}
-
display.addReference();
-
+
createNativeImpl();
if(null == aScreen) {
throw new NativeWindowException("Screen.createNative() failed to instanciate an AbstractGraphicsScreen");
}
-
- initScreenModeStatus();
- updateVirtualScreenOriginAndSize();
- if(DEBUG) {
- System.err.println("Screen.createNative() END ("+DisplayImpl.getThreadName()+", "+this+"), total "+ (System.nanoTime()-tCreated)/1e6 +"ms");
- }
+
+ initMonitorState();
synchronized(screenList) {
screensActive++;
+ if(DEBUG) {
+ System.err.println("Screen.createNative() END ("+Display.getThreadName()+", "+this+"), active "+screensActive+", total "+ (System.nanoTime()-tCreated)/1e6 +"ms");
+ }
}
+ ScreenMonitorState.getScreenMonitorState(this.getFQName()).addListener(this);
}
- ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
- sms.addListener(this);
}
+ @Override
public synchronized final void destroy() {
- releaseScreenModeStatus();
-
synchronized(screenList) {
- screenList.remove(this);
if(0 < screensActive) {
screensActive--;
}
+ if(DEBUG) {
+ System.err.println("Screen.destroy() ("+Display.getThreadName()+"): active "+screensActive);
+ // Thread.dumpStack();
+ }
}
if ( null != aScreen ) {
+ releaseMonitorState();
closeNativeImpl();
aScreen = null;
}
@@ -214,23 +225,24 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener {
display.removeReference();
}
+ @Override
public synchronized final int addReference() throws NativeWindowException {
if(DEBUG) {
- System.err.println("Screen.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1));
+ System.err.println("Screen.addReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount+1));
// Thread.dumpStack();
}
if ( 0 == refCount ) {
createNative();
- }
- if(null == aScreen) {
+ } else if(null == aScreen) {
throw new NativeWindowException("Screen.addReference() (refCount "+refCount+") null AbstractGraphicsScreen");
}
return ++refCount;
}
+ @Override
public synchronized final int removeReference() {
if(DEBUG) {
- System.err.println("Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1));
+ System.err.println("Screen.removeReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount-1));
// Thread.dumpStack();
}
refCount--; // could become < 0, in case of manual destruction without actual creation/addReference
@@ -241,13 +253,14 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener {
return refCount;
}
+ @Override
public synchronized final int getReferenceCount() {
return refCount;
}
protected abstract void createNativeImpl();
protected abstract void closeNativeImpl();
-
+
/**
* Returns the validated screen index, which is either the passed <code>idx</code>
* value or <code>0</code>.
@@ -256,421 +269,433 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener {
* </p>
*/
protected abstract int validateScreenIndex(int idx);
-
+
/**
- * Stores the virtual origin and virtual <b>rotated</b> screen size.
+ * Calculates the virtual rotated viewport in pixel- and window units.
* <p>
- * This method is called after the ScreenMode has been set,
+ * This method is called after the MonitorMode has been set or changed,
* hence you may utilize it.
- * </p>
- * @param virtualOrigin the store for the virtual origin
- * @param virtualSize the store for the virtual rotated size
+ * </p>
+ * <p>
+ * Default implementation uses the union of all monitor's viewport,
+ * calculated via {@link #unionOfMonitorViewportSize()}, however driver impl. may chose a different methodology.
+ * </p>
+ * @param viewport storage for result in pixel units
+ * @param viewportInWindowUnits storage for result in window units
*/
- protected abstract void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize);
-
+ protected void calcVirtualScreenOriginAndSize(final Rectangle viewport, final Rectangle viewportInWindowUnits) {
+ unionOfMonitorViewports(viewport, viewportInWindowUnits);
+ }
+
+ @Override
public final String getFQName() {
return fqname;
}
/**
- * Updates the <b>rotated</b> virtual ScreenSize using the native impl.
+ * Updates the <b>rotated</b> virtual viewport, may use native impl.
*/
protected void updateVirtualScreenOriginAndSize() {
- getVirtualScreenOriginAndSize(vOrigin, vSize);
- if(DEBUG) {
- System.err.println("Detected screen origin "+vOrigin+", size "+vSize);
+ if(null != usrSize ) {
+ virtViewportPU.set(0, 0, usrSize.getWidth(), usrSize.getHeight());
+ virtViewportWU.set(0, 0, usrSize.getWidth(), usrSize.getHeight());
+ if(DEBUG) {
+ System.err.println("Update user virtual screen viewport @ "+Thread.currentThread().getName()+": "+virtViewportPU);
+ }
+ } else {
+ calcVirtualScreenOriginAndSize(virtViewportPU, virtViewportWU);
+ if(DEBUG) {
+ System.err.println("Updated virtual screen viewport @ "+Thread.currentThread().getName()+": "+virtViewportPU+" [pixel], "+virtViewportWU+" [window]");
+ }
}
}
+ @Override
public final Display getDisplay() {
return display;
}
+ @Override
public final int getIndex() {
return screen_idx;
}
+ @Override
public final AbstractGraphicsScreen getGraphicsScreen() {
return aScreen;
}
+ @Override
public synchronized final boolean isNativeValid() {
return null != aScreen;
}
- public int getX() { return vOrigin.getX(); }
- public int getY() { return vOrigin.getY(); }
-
- public final int getWidth() {
- return (null != usrSize) ? usrSize.getWidth() : vSize.getWidth();
- }
-
- public final int getHeight() {
- return (null != usrSize) ? usrSize.getHeight() : vSize.getHeight();
- }
+ @Override
+ public final int getX() { return virtViewportPU.getX(); }
+ @Override
+ public final int getY() { return virtViewportPU.getY(); }
+ @Override
+ public final int getWidth() { return virtViewportPU.getWidth(); }
+ @Override
+ public final int getHeight() { return virtViewportPU.getHeight(); }
+ @Override
+ public final RectangleImmutable getViewport() { return virtViewportPU; }
+ @Override
+ public final RectangleImmutable getViewportInWindowUnits() { return virtViewportWU; }
@Override
public String toString() {
- return "NEWT-Screen["+getFQName()+", idx "+screen_idx+", refCount "+refCount+", "+getWidth()+"x"+getHeight()+", "+aScreen+", "+display+"]";
+ return "NEWT-Screen["+getFQName()+", idx "+screen_idx+", refCount "+refCount+", vsize "+virtViewportPU+" [pixels], "+virtViewportWU+" [window], "+aScreen+", "+display+
+ ", monitors: "+getMonitorDevices()+"]";
}
- public final List<ScreenMode> getScreenModes() {
- ArrayHashSet<ScreenMode> screenModes = getScreenModesOrig();
- if(null != screenModes && 0 < screenModes.size()) {
- return screenModes.toArrayList();
- }
- return null;
+ //
+ // MonitorDevice and MonitorMode
+ //
+
+ /**
+ * To be implemented by the native specification.<br>
+ * Is called within a thread safe environment.<br>
+ * Is called only to collect the {@link MonitorMode}s and {@link MonitorDevice}s, usually at startup setting up modes.<br>
+ * <br>
+ * <b>WARNING</b>: must be synchronized with
+ * <ul>
+ * <li>{@link MonitorModeProps#NUM_SCREEN_MODE_PROPERTIES} and </li>
+ * <li>{@link MonitorModeProps#MIN_MONITOR_DEVICE_PROPERTIES}</li>
+ * </ul>, i.e.
+ * <ul>
+ * <li>{@link MonitorModeProps#streamInMonitorDevice(int[], jogamp.newt.MonitorModeProps.Cache, ScreenImpl, int[], int)}</li>
+ * <li>{@link MonitorModeProps#streamInMonitorDevice(int[], jogamp.newt.MonitorModeProps.Cache, ScreenImpl, ArrayHashSet, int[], int)}</li>
+ * <li>{@link MonitorModeProps#streamInMonitorMode(int[], jogamp.newt.MonitorModeProps.Cache, int[], int)}</li>
+ * </ul>
+ * @param cache memory pool caching the result
+ */
+ protected abstract void collectNativeMonitorModesAndDevicesImpl(MonitorModeProps.Cache cache);
+
+ protected boolean updateNativeMonitorDeviceViewportImpl(final MonitorDevice monitor,
+ final Rectangle viewportPU, final Rectangle viewportWU) {
+ return false;
}
- public ScreenMode getOriginalScreenMode() {
- ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
- return ( null != sms ) ? sms.getOriginalScreenMode() : null ;
+ /**
+ * To be implemented by the native specification.<br>
+ * Is called within a thread safe environment.<br>
+ * <p>
+ * Implementation shall not unify the result w/ monitor's supported modes or a locally
+ * saved {@link MonitorModeProps.Cache}, since caller will perform such tasks.
+ * </p>
+ */
+ protected abstract MonitorMode queryCurrentMonitorModeImpl(MonitorDevice monitor);
+
+ /**
+ * To be implemented by the native specification.<br>
+ * Is called within a thread safe environment.<br>
+ */
+ protected abstract boolean setCurrentMonitorModeImpl(MonitorDevice monitor, MonitorMode mode);
+
+ @Override
+ public final List<MonitorMode> getMonitorModes() {
+ final ScreenMonitorState sms = getScreenMonitorStatus(false);
+ return null != sms ? sms.getMonitorModes().getData() : null;
}
- public ScreenMode getCurrentScreenMode() {
- ScreenMode smU = null;
- ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
- if(null == sms) {
- throw new InternalError("ScreenModeStatus.getScreenModeStatus("+this.getFQName()+") == null");
- }
- ScreenMode sm0 = getCurrentScreenModeIntern();
- if(null == sm0) {
- throw new InternalError("getCurrentScreenModeImpl() == null");
- }
- sms.lock();
- try {
- smU = sms.getScreenModes().getOrAdd(sm0); // unified instance, maybe new
+ @Override
+ public final List<MonitorDevice> getMonitorDevices() {
+ final ScreenMonitorState sms = getScreenMonitorStatus(false);
+ return null != sms ? sms.getMonitorDevices().getData() : null;
+ }
- // if mode has changed somehow, update it ..
- if( sms.getCurrentScreenMode().hashCode() != smU.hashCode() ) {
- sms.fireScreenModeChanged(smU, true);
- }
- } finally {
- sms.unlock();
+ final ScreenMonitorState getScreenMonitorStatus(final boolean throwException) {
+ final String key = this.getFQName();
+ final ScreenMonitorState res = ScreenMonitorState.getScreenMonitorState(key);
+ if(null == res & throwException) {
+ throw new InternalError("ScreenMonitorStatus.getMonitorModeStatus("+key+") == null");
}
- return smU;
+ return res;
}
- public boolean setCurrentScreenMode(ScreenMode screenMode) {
- final ScreenMode smC = getCurrentScreenMode();
- ScreenMode smU = getScreenModesOrig().get(screenMode); // unify via value hash
- if(smU.equals(smC)) {
- if(DEBUG) {
- System.err.println("Screen.setCurrentScreenMode ("+(System.nanoTime()-tCreated)+"): 0.0 is-current (skip) "+smU+" == "+smC);
- }
- return true;
- }
- ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
- if(null == sms) {
- throw new InternalError("ScreenModeStatus.getScreenModeStatus("+this.getFQName()+") == null");
+ @Override
+ public void monitorModeChangeNotify(final MonitorEvent me) {
+ if(DEBUG) {
+ System.err.println("monitorModeChangeNotify @ "+Thread.currentThread().getName()+": "+me);
}
- boolean success;
- sms.lock();
- try {
- final long tStart;
- if(DEBUG) {
- tStart = System.nanoTime();
- } else {
- tStart = 0;
- }
-
- sms.fireScreenModeChangeNotify(smU);
- if(DEBUG) {
- System.err.println("Screen.setCurrentScreenMode ("+(System.nanoTime()-tStart)/1e6+"ms): fireScreenModeChangeNotify() "+smU);
- }
-
- success = setCurrentScreenModeImpl(smU);
- if(DEBUG) {
- System.err.println("Screen.setCurrentScreenMode ("+(System.nanoTime()-tStart)/1e6+"ms): setCurrentScreenModeImpl() "+smU+", success: "+success);
- }
-
- sms.fireScreenModeChanged(smU, success);
- if(DEBUG) {
- System.err.println("Screen.setCurrentScreenMode ("+(System.nanoTime()-tStart)/1e6+"ms): X.X "+smU+", success: "+success);
- }
- } finally {
- sms.unlock();
+ for(int i=0; i<refMonitorModeListener.size(); i++) {
+ refMonitorModeListener.get(i).monitorModeChangeNotify(me);
}
- return success;
}
- public void screenModeChangeNotify(ScreenMode sm) {
- for(int i=0; i<referencedScreenModeListener.size(); i++) {
- ((ScreenModeListener)referencedScreenModeListener.get(i)).screenModeChangeNotify(sm);
+ private void updateNativeMonitorDevicesViewport() {
+ final List<MonitorDevice> monitors = getMonitorDevices();
+ for(int i=monitors.size()-1; i>=0; i--) {
+ final MonitorDeviceImpl monitor = (MonitorDeviceImpl) monitors.get(i);
+ final boolean viewportUpdated = updateNativeMonitorDeviceViewportImpl(monitor, monitor.getMutuableViewportPU(), monitor.getMutuableViewportWU());
+ if( DEBUG ) {
+ System.err.println("Screen.updateMonitorViewport["+i+"] @ "+Thread.currentThread().getName()+": updated: "+viewportUpdated+", PU "+monitor.getViewport()+", WU "+monitor.getViewportInWindowUnits());
+ }
}
}
- public void screenModeChanged(ScreenMode sm, boolean success) {
+ @Override
+ public void monitorModeChanged(final MonitorEvent me, final boolean success) {
if(success) {
+ updateNativeMonitorDevicesViewport();
updateVirtualScreenOriginAndSize();
}
- for(int i=0; i<referencedScreenModeListener.size(); i++) {
- ((ScreenModeListener)referencedScreenModeListener.get(i)).screenModeChanged(sm, success);
+ if(DEBUG) {
+ System.err.println("monitorModeChangeNotify @ "+Thread.currentThread().getName()+": success "+success+", "+me);
}
- }
-
- public synchronized final void addScreenModeListener(ScreenModeListener sml) {
- referencedScreenModeListener.add(sml);
- }
-
- public synchronized final void removeScreenModeListener(ScreenModeListener sml) {
- referencedScreenModeListener.remove(sml);
- }
-
- /** ScreenModeStatus bridge to native implementation */
- protected final ArrayHashSet<ScreenMode> getScreenModesOrig() {
- ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
- if(null!=sms) {
- return sms.getScreenModes();
+ for(int i=0; i<refMonitorModeListener.size(); i++) {
+ refMonitorModeListener.get(i).monitorModeChanged(me, success);
}
- return null;
}
- /** ScreenModeStatus bridge to native implementation */
- protected final IntIntHashMap getScreenModesIdx2NativeIdx() {
- ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
- if(null!=sms) {
- return sms.getScreenModesIdx2NativeIdx();
- }
- return null;
+ @Override
+ public synchronized final void addMonitorModeListener(final MonitorModeListener sml) {
+ refMonitorModeListener.add(sml);
}
- /**
- * To be implemented by the native specification.<br>
- * Is called within a thread safe environment.<br>
- * Is called only to collect the ScreenModes, usually at startup setting up modes.<br>
- * <br>
- * <b>WARNING</b>: must be synchronized with {@link com.jogamp.newt.util.ScreenModeUtil#NUM_SCREEN_MODE_PROPERTIES},
- * ie {@link com.jogamp.newt.util.ScreenModeUtil#streamIn(com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, int[], int)}<br>
- * <br>
- * <b>Note</b>: Additional 1st element is native mode id.
- */
- protected int[] getScreenModeFirstImpl() {
- return null;
+ @Override
+ public synchronized final void removeMonitorModeListener(final MonitorModeListener sml) {
+ refMonitorModeListener.remove(sml);
}
/**
- * To be implemented by the native specification.<br>
- * Is called within a thread safe environment.<br>
- * Is called only to collect the ScreenModes, usually at startup setting up modes.<br>
- * <br>
- * <b>WARNING</b>: must be synchronized with {@link com.jogamp.newt.util.ScreenModeUtil#NUM_SCREEN_MODE_PROPERTIES},
- * ie {@link com.jogamp.newt.util.ScreenModeUtil#streamIn(com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, int[], int)}<br>
- * <br>
- * <b>Note</b>: Additional 1st element is native mode id.
+ *
+ * @param cache optional ..
+ * @param modeId
+ * @return
*/
- protected int[] getScreenModeNextImpl() {
- return null;
+ private final MonitorMode getVirtualMonitorMode(final MonitorModeProps.Cache cache, final int modeId) {
+ final int[] props = new int[MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL];
+ int i = 0;
+ props[i++] = MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL;
+ props[i++] = getWidth(); // width
+ props[i++] = getHeight(); // height
+ props[i++] = default_sm_bpp;
+ props[i++] = default_sm_rate * 100;
+ props[i++] = 0; // flags
+ props[i++] = modeId;
+ props[i++] = default_sm_rotation;
+ if( MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL != i ) {
+ throw new InternalError("XX");
+ }
+ return MonitorModeProps.streamInMonitorMode(null, cache, props, 0);
}
/**
- * To be implemented by the native specification.<br>
- * Is called within a thread safe environment.<br>
+ *
+ * @param cache mandatory !
+ * @param monitorId
+ * @param currentMode
+ * @return
*/
- protected ScreenMode getCurrentScreenModeImpl() {
- return null;
+ private final MonitorDevice getVirtualMonitorDevice(final MonitorModeProps.Cache cache, final int monitorId, final MonitorMode currentMode) {
+ final int[] props = new int[MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES];
+ int i = 0;
+ props[i++] = MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES;
+ props[i++] = monitorId;
+ props[i++] = default_sm_widthmm;
+ props[i++] = default_sm_heightmm;
+ props[i++] = 0; // rotated viewport x pixel-units
+ props[i++] = 0; // rotated viewport y pixel-units
+ props[i++] = currentMode.getRotatedWidth(); // rotated viewport width pixel-units
+ props[i++] = currentMode.getRotatedHeight(); // rotated viewport height pixel-units
+ props[i++] = 0; // rotated viewport x window-units
+ props[i++] = 0; // rotated viewport y window-units
+ props[i++] = currentMode.getRotatedWidth(); // rotated viewport width window-units
+ props[i++] = currentMode.getRotatedHeight(); // rotated viewport height window-units
+ props[i++] = currentMode.getId(); // current mode id
+ props[i++] = currentMode.getRotation();
+ props[i++] = currentMode.getId(); // supported mode id #1
+ if( MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES != i ) {
+ throw new InternalError("XX");
+ }
+ return MonitorModeProps.streamInMonitorDevice(null, cache, this, props, 0);
}
-
+
/**
- * Utilizes {@link #getCurrentScreenModeImpl()}, if the latter returns null it uses
+ * Utilizes {@link #getCurrentMonitorModeImpl()}, if the latter returns null it uses
* the current screen size and dummy values.
*/
- protected ScreenMode getCurrentScreenModeIntern() {
- ScreenMode res;
+ protected final MonitorMode queryCurrentMonitorModeIntern(final MonitorDevice monitor) {
+ MonitorMode res;
if(DEBUG_TEST_SCREENMODE_DISABLED) {
res = null;
} else {
- res = getCurrentScreenModeImpl();
+ res = queryCurrentMonitorModeImpl(monitor);
}
if(null == res) {
- if( 0==getWidth()*getHeight() ) {
+ if( 0>=getWidth() || 0>=getHeight() ) {
updateVirtualScreenOriginAndSize();
}
- int[] props = new int[ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL];
- int i = 0;
- props[i++] = 0; // set later for verification of iterator
- props[i++] = getWidth(); // width
- props[i++] = getHeight(); // height
- props[i++] = default_sm_bpp;
- props[i++] = default_sm_widthmm;
- props[i++] = default_sm_heightmm;
- props[i++] = default_sm_rate;
- props[i++] = default_sm_rotation;
- props[i - ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL] = i; // count
- res = ScreenModeUtil.streamIn(props, 0);
+ res = getVirtualMonitorMode(null, monitor.getCurrentMode().getId());
}
return res;
}
- /**
- * To be implemented by the native specification.<br>
- * Is called within a thread safe environment.<br>
- */
- protected boolean setCurrentScreenModeImpl(ScreenMode screenMode) {
- return false;
- }
-
- private ScreenModeStatus initScreenModeStatus() {
+ private final ScreenMonitorState initMonitorState() {
long t0;
if(DEBUG) {
t0 = System.nanoTime();
- System.err.println("Screen.initScreenModeStatus() START ("+DisplayImpl.getThreadName()+", "+this+")");
+ System.err.println("Screen.initMonitorState() START ("+Display.getThreadName()+", "+this+")");
} else {
t0 = 0;
}
- ScreenModeStatus sms;
- ScreenModeStatus.lockScreenModeStatus();
+ boolean vScrnSizeUpdated = false;
+ ScreenMonitorState sms;
+ ScreenMonitorState.lockScreenMonitorState();
try {
- sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
- if(null==sms) {
- IntIntHashMap screenModesIdx2NativeIdx = new IntIntHashMap();
- final ScreenMode currentSM = getCurrentScreenModeIntern();
- if(null == currentSM) {
- throw new InternalError("getCurrentScreenModeImpl() == null");
+ sms = ScreenMonitorState.getScreenMonitorState(this.getFQName());
+ if(null==sms) {
+ final MonitorModeProps.Cache cache = new MonitorModeProps.Cache();
+ if( 0 >= collectNativeMonitorModes(cache) ) {
+ updateVirtualScreenOriginAndSize();
+ vScrnSizeUpdated = true;
+ final MonitorMode mode = getVirtualMonitorMode(cache, 0);
+ cache.monitorModes.getOrAdd(mode);
+ final MonitorDevice monitor = getVirtualMonitorDevice(cache, 0, mode);
+ cache.monitorDevices.getOrAdd(monitor);
+ }
+ // Sort MonitorModes (all and per device) in descending order - default!
+ MonitorModeUtil.sort(cache.monitorModes.getData(), false ); // descending order
+ for(final Iterator<MonitorDevice> iMonitor=cache.monitorDevices.iterator(); iMonitor.hasNext(); ) {
+ MonitorModeUtil.sort(iMonitor.next().getSupportedModes(), false ); // descending order
}
-
- ArrayHashSet<ScreenMode> screenModes = collectNativeScreenModes(screenModesIdx2NativeIdx);
- screenModes.getOrAdd(currentSM);
if(DEBUG) {
int i=0;
- for(Iterator<ScreenMode> iter=screenModes.iterator(); iter.hasNext(); i++) {
- System.err.println(i+": "+iter.next());
+ for(final Iterator<MonitorMode> iMode=cache.monitorModes.iterator(); iMode.hasNext(); i++) {
+ System.err.println("All["+i+"]: "+iMode.next());
+ }
+ i=0;
+ for(final Iterator<MonitorDevice> iMonitor=cache.monitorDevices.iterator(); iMonitor.hasNext(); i++) {
+ final MonitorDevice crt = iMonitor.next();
+ System.err.println("["+i+"]: "+crt);
+ int j=0;
+ for(final Iterator<MonitorMode> iMode=crt.getSupportedModes().iterator(); iMode.hasNext(); j++) {
+ System.err.println("["+i+"]["+j+"]: "+iMode.next());
+ }
}
}
-
- sms = new ScreenModeStatus(screenModes, screenModesIdx2NativeIdx);
- ScreenMode originalScreenMode0 = screenModes.get(currentSM); // unify via value hash
- if(null == originalScreenMode0) {
- throw new RuntimeException(currentSM+" could not be hashed from ScreenMode list");
- }
- sms.setOriginalScreenMode(originalScreenMode0);
- ScreenModeStatus.mapScreenModeStatus(this.getFQName(), sms);
+ sms = new ScreenMonitorState(cache.monitorDevices, cache.monitorModes);
+ ScreenMonitorState.mapScreenMonitorState(this.getFQName(), sms);
}
} finally {
- ScreenModeStatus.unlockScreenModeStatus();
+ ScreenMonitorState.unlockScreenMonitorState();
}
if(DEBUG) {
- System.err.println("Screen.initScreenModeStatus() END dt "+ (System.nanoTime()-t0)/1e6 +"ms");
+ System.err.println("Screen.initMonitorState() END dt "+ (System.nanoTime()-t0)/1e6 +"ms");
}
+ if( !vScrnSizeUpdated ) {
+ updateVirtualScreenOriginAndSize();
+ }
+
return sms;
}
- /** ignores bpp < 15 */
- private ArrayHashSet<ScreenMode> collectNativeScreenModes(IntIntHashMap screenModesIdx2NativeId) {
- ArrayHashSet<DimensionImmutable> resolutionPool = new ArrayHashSet<DimensionImmutable>();
- ArrayHashSet<SurfaceSize> surfaceSizePool = new ArrayHashSet<SurfaceSize>();
- ArrayHashSet<DimensionImmutable> screenSizeMMPool = new ArrayHashSet<DimensionImmutable>();
- ArrayHashSet<MonitorMode> monitorModePool = new ArrayHashSet<MonitorMode>();
- ArrayHashSet<ScreenMode> screenModePool = new ArrayHashSet<ScreenMode>();
-
- int[] smProps = null;
- int num = 0;
- final int idxBpp = 1 // native mode
- + 1 // count
- + ScreenModeUtil.NUM_RESOLUTION_PROPERTIES
- + ScreenModeUtil.NUM_SURFACE_SIZE_PROPERTIES
- - 1 ; // index 0 based
- do {
- if(DEBUG_TEST_SCREENMODE_DISABLED) {
- smProps = null;
- } else if(0 == num) {
- smProps = getScreenModeFirstImpl();
- } else {
- smProps = getScreenModeNextImpl();
- }
- if(null != smProps && 0 < smProps.length && smProps[idxBpp] >= 15) {
- int nativeId = smProps[0];
- int screenModeIdx = ScreenModeUtil.streamIn(resolutionPool, surfaceSizePool, screenSizeMMPool,
- monitorModePool, screenModePool, smProps, 1);
- if(DEBUG) {
- System.err.println("ScreenImpl.collectNativeScreenModes: #"+num+": idx: "+nativeId+" native -> "+screenModeIdx+" newt");
+ /**
+ * Returns the number of successful collected {@link MonitorDevice}s.
+ * <p>
+ * Collects {@link MonitorDevice}s and {@link MonitorMode}s within the given cache.
+ * </p>
+ */
+ private final int collectNativeMonitorModes(final MonitorModeProps.Cache cache) {
+ if(!DEBUG_TEST_SCREENMODE_DISABLED) {
+ collectNativeMonitorModesAndDevicesImpl(cache);
+ }
+ // filter out insufficient modes
+ for(int i=cache.monitorModes.size()-1; i>=0; i--) {
+ final MonitorMode mode = cache.monitorModes.get(i);
+ if( 16 > mode.getSurfaceSize().getBitsPerPixel() ) {
+ boolean keep = false;
+ for(int j=cache.monitorDevices.size()-1; !keep && j>=0; j--) {
+ final MonitorDevice monitor = cache.monitorDevices.get(j);
+ keep = monitor.getCurrentMode().equals(mode);
}
-
- if(screenModeIdx >= 0) {
- screenModesIdx2NativeId.put(screenModeIdx, nativeId);
+ if(!keep) {
+ cache.monitorModes.remove(i);
+ for(int j=cache.monitorDevices.size()-1; j>=0; j--) {
+ final MonitorDeviceImpl monitor = (MonitorDeviceImpl) cache.monitorDevices.get(j);
+ monitor.getSupportedModesImpl().remove(mode);
+ }
}
- } else if(DEBUG) {
- System.err.println("ScreenImpl.collectNativeScreenModes: #"+num+": smProps: "+(null!=smProps)+
- ", len: "+(null != smProps ? smProps.length : 0)+
- ", bpp: "+(null != smProps && 0 < smProps.length ? smProps[idxBpp] : 0)+
- " - DROPPING");
}
- num++;
- } while ( null != smProps && 0 < smProps.length );
-
- if(DEBUG) {
- System.err.println("ScreenImpl.collectNativeScreenModes: ScreenMode number : "+screenModePool.size());
- System.err.println("ScreenImpl.collectNativeScreenModes: MonitorMode number : "+monitorModePool.size());
- System.err.println("ScreenImpl.collectNativeScreenModes: ScreenSizeMM number: "+screenSizeMMPool.size());
- System.err.println("ScreenImpl.collectNativeScreenModes: SurfaceSize number : "+surfaceSizePool.size());
- System.err.println("ScreenImpl.collectNativeScreenModes: Resolution number : "+resolutionPool.size());
}
-
- return screenModePool;
+ if( DEBUG ) {
+ System.err.println("ScreenImpl.collectNativeMonitorModes: MonitorDevice number : "+cache.monitorDevices.size());
+ System.err.println("ScreenImpl.collectNativeMonitorModes: MonitorMode number : "+cache.monitorModes.size());
+ System.err.println("ScreenImpl.collectNativeMonitorModes: SizeAndRate number : "+cache.sizeAndRates.size());
+ System.err.println("ScreenImpl.collectNativeMonitorModes: SurfaceSize number : "+cache.surfaceSizes.size());
+ System.err.println("ScreenImpl.collectNativeMonitorModes: Resolution number : "+cache.resolutions.size());
+ }
+ return cache.monitorDevices.size();
}
- private void releaseScreenModeStatus() {
- ScreenModeStatus sms;
- ScreenModeStatus.lockScreenModeStatus();
+ private final void releaseMonitorState() {
+ ScreenMonitorState sms;
+ ScreenMonitorState.lockScreenMonitorState();
try {
- sms = ScreenModeStatus.getScreenModeStatus(getFQName());
+ sms = ScreenMonitorState.getScreenMonitorState(getFQName());
if(null != sms) {
sms.lock();
try {
if(0 == sms.removeListener(this)) {
- if(sms.isOriginalModeChangedByOwner()) {
- System.err.println("Screen.destroy(): "+sms.getCurrentScreenMode()+" -> "+sms.getOriginalScreenMode());
- try {
- setCurrentScreenMode(sms.getOriginalScreenMode());
- } catch (Throwable t) {
- // be verbose but continue
- t.printStackTrace();
+ final ArrayList<MonitorDevice> monitorDevices = sms.getMonitorDevices().getData();
+ for(int i=0; i<monitorDevices.size(); i++) {
+ final MonitorDevice monitor = monitorDevices.get(i);
+ if( monitor.isModeChangedByUs() ) {
+ System.err.println("Screen.destroy(): Reset "+monitor);
+ try {
+ monitor.setCurrentMode(monitor.getOriginalMode());
+ } catch (final Throwable t) {
+ // be verbose but continue
+ t.printStackTrace();
+ }
}
}
- ScreenModeStatus.unmapScreenModeStatus(getFQName());
+ ScreenMonitorState.unmapScreenMonitorState(getFQName());
}
} finally {
sms.unlock();
}
- }
+ }
} finally {
- ScreenModeStatus.unlockScreenModeStatus();
+ ScreenMonitorState.unlockScreenMonitorState();
}
}
-
+
private final void shutdown() {
- ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatusUnlocked(getFQName());
+ final ScreenMonitorState sms = ScreenMonitorState.getScreenMonitorStateUnlocked(getFQName());
if(null != sms) {
- if(sms.isOriginalModeChangedByOwner()) {
- try {
- System.err.println("Screen.shutdown(): "+sms.getCurrentScreenMode()+" -> "+sms.getOriginalScreenMode());
- setCurrentScreenModeImpl(sms.getOriginalScreenMode());
- } catch (Throwable t) {
- // be quiet .. shutdown
+ final ArrayList<MonitorDevice> monitorDevices = sms.getMonitorDevices().getData();
+ for(int i=0; i<monitorDevices.size(); i++) {
+ final MonitorDevice monitor = monitorDevices.get(i);
+ if( monitor.isModeChangedByUs() ) {
+ System.err.println("Screen.shutdown(): Reset "+monitor);
+ try {
+ monitor.setCurrentMode(monitor.getOriginalMode());
+ } catch (final Throwable t) {
+ // be quiet .. shutdown
+ }
}
}
- ScreenModeStatus.unmapScreenModeStatusUnlocked(getFQName());
- }
- }
- private static final void shutdownAll() {
- for(int i=0; i < screenList.size(); i++) {
- ((ScreenImpl)screenList.get(i)).shutdown();
+ ScreenMonitorState.unmapScreenMonitorStateUnlocked(getFQName());
}
}
-
- private static synchronized void registerShutdownHook() {
- final Thread shutdownHook = new Thread(new Runnable() {
- public void run() {
- ScreenImpl.shutdownAll();
+
+ /** pp */ static final void shutdownAll() {
+ final int sCount = screenList.size();
+ if(DEBUG) {
+ System.err.println("Screen.shutdownAll "+sCount+" instances, on thread "+Display.getThreadName());
+ }
+ for(int i=0; i<sCount && screenList.size()>0; i++) { // be safe ..
+ final ScreenImpl s = (ScreenImpl) screenList.remove(0).get();
+ if(DEBUG) {
+ System.err.println("Screen.shutdownAll["+(i+1)+"/"+sCount+"]: "+s+", GCed "+(null==s));
}
- });
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- Runtime.getRuntime().addShutdownHook(shutdownHook);
- return null;
+ if( null != s ) {
+ s.shutdown();
}
- });
+ }
}
}
-
diff --git a/src/newt/classes/jogamp/newt/ScreenModeStatus.java b/src/newt/classes/jogamp/newt/ScreenModeStatus.java
deleted file mode 100644
index 4075fb131..000000000
--- a/src/newt/classes/jogamp/newt/ScreenModeStatus.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * Copyright 2010 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 com.jogamp.common.util.ArrayHashSet;
-import com.jogamp.common.util.IntIntHashMap;
-import com.jogamp.common.util.locks.LockFactory;
-import com.jogamp.common.util.locks.RecursiveLock;
-import com.jogamp.newt.Screen;
-import com.jogamp.newt.ScreenMode;
-import com.jogamp.newt.event.ScreenModeListener;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-public class ScreenModeStatus {
- private static boolean DEBUG = Screen.DEBUG;
-
- private RecursiveLock lock = LockFactory.createRecursiveLock();
- private ArrayHashSet<ScreenMode> screenModes;
- private IntIntHashMap screenModesIdx2NativeIdx;
- private ScreenMode currentScreenMode;
- private ScreenMode originalScreenMode;
- private boolean screenModeChangedByOwner;
- private ArrayList<ScreenModeListener> listener = new ArrayList<ScreenModeListener>();
-
- private static HashMap<String, ScreenModeStatus> screenFQN2ScreenModeStatus = new HashMap<String, ScreenModeStatus>();
- private static RecursiveLock screen2ScreenModeStatusLock = LockFactory.createRecursiveLock();
-
- protected static void mapScreenModeStatus(String screenFQN, ScreenModeStatus sms) {
- screen2ScreenModeStatusLock.lock();
- try {
- ScreenModeStatus _sms = screenFQN2ScreenModeStatus.get(screenFQN);
- if( null != _sms ) {
- throw new RuntimeException("ScreenModeStatus "+_sms+" already mapped to "+screenFQN);
- }
- screenFQN2ScreenModeStatus.put(screenFQN, sms);
- if(DEBUG) {
- System.err.println("ScreenModeStatus.map "+screenFQN+" -> "+sms);
- }
- } finally {
- screen2ScreenModeStatusLock.unlock();
- }
- }
-
- /**
- * @param screen the prev user
- * @return true if mapping is empty, ie no more usage of the mapped ScreenModeStatus
- */
- protected static void unmapScreenModeStatus(String screenFQN) {
- screen2ScreenModeStatusLock.lock();
- try {
- unmapScreenModeStatusUnlocked(screenFQN);
- } finally {
- screen2ScreenModeStatusLock.unlock();
- }
- }
- protected static void unmapScreenModeStatusUnlocked(String screenFQN) {
- ScreenModeStatus sms = screenFQN2ScreenModeStatus.remove(screenFQN);
- if(DEBUG) {
- System.err.println("ScreenModeStatus.unmap "+screenFQN+" -> "+sms);
- }
- }
-
- protected static ScreenModeStatus getScreenModeStatus(String screenFQN) {
- screen2ScreenModeStatusLock.lock();
- try {
- return getScreenModeStatusUnlocked(screenFQN);
- } finally {
- screen2ScreenModeStatusLock.unlock();
- }
- }
- protected static ScreenModeStatus getScreenModeStatusUnlocked(String screenFQN) {
- return screenFQN2ScreenModeStatus.get(screenFQN);
- }
-
- protected static void lockScreenModeStatus() {
- screen2ScreenModeStatusLock.lock();
- }
-
- protected static void unlockScreenModeStatus() {
- screen2ScreenModeStatusLock.unlock();
- }
-
- public ScreenModeStatus(ArrayHashSet<ScreenMode> screenModes,
- IntIntHashMap screenModesIdx2NativeIdx) {
- this.screenModes = screenModes;
- this.screenModesIdx2NativeIdx = screenModesIdx2NativeIdx;
- this.screenModeChangedByOwner = false;
- }
-
- protected final void setOriginalScreenMode(ScreenMode originalScreenMode) {
- this.originalScreenMode = originalScreenMode;
- this.currentScreenMode = originalScreenMode;
- }
-
- public final ScreenMode getOriginalScreenMode() {
- return originalScreenMode;
- }
-
- public final ScreenMode getCurrentScreenMode() {
- lock();
- try {
- return currentScreenMode;
- } finally {
- unlock();
- }
- }
-
- /**
- * We cannot guarantee that we won't interfere w/ another running
- * application's screen mode change.
- * <p>
- * At least we only return <code>true</true> if the owner, ie. the Screen,
- * has changed the screen mode and if the original screen mode
- * is not current the current one.
- * </p>
- * @return
- */
- public final boolean isOriginalModeChangedByOwner() {
- lock();
- try {
- return screenModeChangedByOwner && !isCurrentModeOriginalMode();
- } finally {
- unlock();
- }
- }
-
- protected final boolean isCurrentModeOriginalMode() {
- if(null != currentScreenMode && null != originalScreenMode) {
- return currentScreenMode.hashCode() == originalScreenMode.hashCode();
- }
- return true;
- }
-
- protected final ArrayHashSet<ScreenMode> getScreenModes() {
- return screenModes;
- }
-
- protected final IntIntHashMap getScreenModesIdx2NativeIdx() {
- return screenModesIdx2NativeIdx;
- }
-
- protected final int addListener(ScreenModeListener l) {
- lock();
- try {
- listener.add(l);
- if(DEBUG) {
- System.err.println("ScreenModeStatus.addListener (size: "+listener.size()+"): "+l);
- }
- return listener.size();
- } finally {
- unlock();
- }
- }
-
- protected final int removeListener(ScreenModeListener l) {
- lock();
- try {
- if(!listener.remove(l)) {
- throw new RuntimeException("ScreenModeListener "+l+" not contained");
- }
- if(DEBUG) {
- System.err.println("ScreenModeStatus.removeListener (size: "+listener.size()+"): "+l);
- }
- return listener.size();
- } finally {
- unlock();
- }
- }
-
- protected final void fireScreenModeChangeNotify(ScreenMode desiredScreenMode) {
- lock();
- try {
- for(int i=0; i<listener.size(); i++) {
- listener.get(i).screenModeChangeNotify(desiredScreenMode);
- }
- } finally {
- unlock();
- }
- }
-
- protected void fireScreenModeChanged(ScreenMode currentScreenMode, boolean success) {
- lock();
- try {
- if(success) {
- this.currentScreenMode = currentScreenMode;
- this.screenModeChangedByOwner = !isCurrentModeOriginalMode();
- }
- for(int i=0; i<listener.size(); i++) {
- listener.get(i).screenModeChanged(currentScreenMode, success);
- }
- } finally {
- unlock();
- }
- }
-
- protected final void lock() throws RuntimeException {
- lock.lock();
- }
-
- protected final void unlock() throws RuntimeException {
- lock.unlock();
- }
-}
diff --git a/src/newt/classes/jogamp/newt/ScreenMonitorState.java b/src/newt/classes/jogamp/newt/ScreenMonitorState.java
new file mode 100644
index 000000000..ae982414b
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/ScreenMonitorState.java
@@ -0,0 +1,195 @@
+/**
+ * Copyright 2010 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 com.jogamp.common.util.ArrayHashSet;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.Screen;
+import com.jogamp.newt.MonitorMode;
+import com.jogamp.newt.event.MonitorEvent;
+import com.jogamp.newt.event.MonitorModeListener;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class ScreenMonitorState {
+ private static boolean DEBUG = Screen.DEBUG;
+
+ private final RecursiveLock lock = LockFactory.createRecursiveLock();
+ private final ArrayHashSet<MonitorDevice> allMonitors;
+ private final ArrayHashSet<MonitorMode> allMonitorModes;
+ private final ArrayList<MonitorModeListener> listener = new ArrayList<MonitorModeListener>();
+
+ private static HashMap<String, ScreenMonitorState> screenFQN2ScreenMonitorState = new HashMap<String, ScreenMonitorState>();
+ private static RecursiveLock screen2ScreenMonitorState = LockFactory.createRecursiveLock();
+
+ protected static void mapScreenMonitorState(final String screenFQN, final ScreenMonitorState sms) {
+ screen2ScreenMonitorState.lock();
+ try {
+ final ScreenMonitorState _sms = screenFQN2ScreenMonitorState.get(screenFQN);
+ if( null != _sms ) {
+ throw new RuntimeException("ScreenMonitorState "+_sms+" already mapped to "+screenFQN);
+ }
+ screenFQN2ScreenMonitorState.put(screenFQN, sms);
+ if(DEBUG) {
+ System.err.println("ScreenMonitorState.map "+screenFQN+" -> "+sms);
+ }
+ } finally {
+ screen2ScreenMonitorState.unlock();
+ }
+ }
+
+ /**
+ * @param screen the prev user
+ * @return true if mapping is empty, ie no more usage of the mapped ScreenMonitorState
+ */
+ protected static void unmapScreenMonitorState(final String screenFQN) {
+ screen2ScreenMonitorState.lock();
+ try {
+ unmapScreenMonitorStateUnlocked(screenFQN);
+ } finally {
+ screen2ScreenMonitorState.unlock();
+ }
+ }
+ protected static void unmapScreenMonitorStateUnlocked(final String screenFQN) {
+ final ScreenMonitorState sms = screenFQN2ScreenMonitorState.remove(screenFQN);
+ if(DEBUG) {
+ System.err.println("ScreenMonitorState.unmap "+screenFQN+" -> "+sms);
+ }
+ }
+
+ protected static ScreenMonitorState getScreenMonitorState(final String screenFQN) {
+ screen2ScreenMonitorState.lock();
+ try {
+ return getScreenMonitorStateUnlocked(screenFQN);
+ } finally {
+ screen2ScreenMonitorState.unlock();
+ }
+ }
+ protected static ScreenMonitorState getScreenMonitorStateUnlocked(final String screenFQN) {
+ return screenFQN2ScreenMonitorState.get(screenFQN);
+ }
+
+ protected static void lockScreenMonitorState() {
+ screen2ScreenMonitorState.lock();
+ }
+
+ protected static void unlockScreenMonitorState() {
+ screen2ScreenMonitorState.unlock();
+ }
+
+ public ScreenMonitorState(final ArrayHashSet<MonitorDevice> allMonitors,
+ final ArrayHashSet<MonitorMode> allMonitorModes) {
+ this.allMonitors = allMonitors;
+ this.allMonitorModes = allMonitorModes;
+ }
+
+ protected ArrayHashSet<MonitorDevice> getMonitorDevices() {
+ return allMonitors;
+ }
+
+ protected ArrayHashSet<MonitorMode> getMonitorModes() {
+ return allMonitorModes;
+ }
+
+ protected final int addListener(final MonitorModeListener l) {
+ lock();
+ try {
+ listener.add(l);
+ if(DEBUG) {
+ System.err.println("ScreenMonitorState.addListener (size: "+listener.size()+"): "+l);
+ }
+ return listener.size();
+ } finally {
+ unlock();
+ }
+ }
+
+ protected final int removeListener(final MonitorModeListener l) {
+ lock();
+ try {
+ if(!listener.remove(l)) {
+ throw new RuntimeException("MonitorModeListener "+l+" not contained");
+ }
+ if(DEBUG) {
+ System.err.println("ScreenMonitorState.removeListener (size: "+listener.size()+"): "+l);
+ }
+ return listener.size();
+ } finally {
+ unlock();
+ }
+ }
+
+ protected final MonitorDevice getMonitor(final MonitorDevice monitor) {
+ return allMonitors.get(monitor);
+ }
+
+ protected final void validateMonitor(final MonitorDevice monitor) {
+ final MonitorDevice md = allMonitors.get(monitor);
+ if( null == md ) {
+ throw new InternalError("Monitor unknown: "+monitor);
+ }
+ }
+
+ protected final void fireMonitorModeChangeNotify(final MonitorDevice monitor, final MonitorMode desiredMode) {
+ lock();
+ try {
+ validateMonitor(monitor);
+ final MonitorEvent me = new MonitorEvent(MonitorEvent.EVENT_MONITOR_MODE_CHANGE_NOTIFY, monitor, System.currentTimeMillis(), desiredMode);
+ for(int i=0; i<listener.size(); i++) {
+ listener.get(i).monitorModeChangeNotify(me);
+ }
+ } finally {
+ unlock();
+ }
+ }
+
+ protected void fireMonitorModeChanged(final MonitorDevice monitor, final MonitorMode currentMode, final boolean success) {
+ lock();
+ try {
+ validateMonitor(monitor);
+ final MonitorEvent me = new MonitorEvent(MonitorEvent.EVENT_MONITOR_MODE_CHANGED, monitor, System.currentTimeMillis(), currentMode);
+ for(int i=0; i<listener.size(); i++) {
+ listener.get(i).monitorModeChanged(me, success);
+ }
+ } finally {
+ unlock();
+ }
+ }
+
+ protected final void lock() throws RuntimeException {
+ lock.lock();
+ }
+
+ protected final void unlock() throws RuntimeException {
+ lock.unlock();
+ }
+}
diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java
index c1ac87d38..b62628962 100644
--- a/src/newt/classes/jogamp/newt/WindowImpl.java
+++ b/src/newt/classes/jogamp/newt/WindowImpl.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,33 +29,15 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt;
-import java.util.ArrayList;
+import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
-
-import com.jogamp.common.util.ReflectionUtil;
-import com.jogamp.newt.NewtFactory;
-import com.jogamp.newt.Display;
-import com.jogamp.newt.Screen;
-import com.jogamp.newt.Window;
-import com.jogamp.common.util.locks.LockFactory;
-import com.jogamp.common.util.locks.RecursiveLock;
-import com.jogamp.newt.ScreenMode;
-import com.jogamp.newt.event.InputEvent;
-import com.jogamp.newt.event.KeyEvent;
-import com.jogamp.newt.event.KeyListener;
-import com.jogamp.newt.event.MouseEvent;
-import com.jogamp.newt.event.MouseListener;
-import com.jogamp.newt.event.NEWTEvent;
-import com.jogamp.newt.event.NEWTEventConsumer;
-import com.jogamp.newt.event.ScreenModeListener;
-import com.jogamp.newt.event.WindowEvent;
-import com.jogamp.newt.event.WindowListener;
-import com.jogamp.newt.event.WindowUpdateEvent;
+import java.util.ArrayList;
+import java.util.List;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
import javax.media.nativewindow.AbstractGraphicsDevice;
@@ -65,28 +47,123 @@ import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.nativewindow.OffscreenLayerSurface;
+import javax.media.nativewindow.ScalableSurface;
import javax.media.nativewindow.SurfaceUpdatedListener;
import javax.media.nativewindow.WindowClosingProtocol;
import javax.media.nativewindow.util.DimensionImmutable;
import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.InsetsImmutable;
+import javax.media.nativewindow.util.PixelRectangle;
import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.util.PointImmutable;
import javax.media.nativewindow.util.Rectangle;
+import javax.media.nativewindow.util.RectangleImmutable;
+import jogamp.nativewindow.SurfaceScaleUtils;
import jogamp.nativewindow.SurfaceUpdatedHelper;
+import com.jogamp.common.util.ArrayHashSet;
+import com.jogamp.common.util.IntBitfield;
+import com.jogamp.common.util.PropertyAccess;
+import com.jogamp.common.util.ReflectionUtil;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+import com.jogamp.newt.Display;
+import com.jogamp.newt.Display.PointerIcon;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.NewtFactory;
+import com.jogamp.newt.Screen;
+import com.jogamp.newt.Window;
+import com.jogamp.newt.event.DoubleTapScrollGesture;
+import com.jogamp.newt.event.GestureHandler;
+import com.jogamp.newt.event.InputEvent;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.event.MonitorEvent;
+import com.jogamp.newt.event.MonitorModeListener;
+import com.jogamp.newt.event.MouseEvent;
+import com.jogamp.newt.event.MouseEvent.PointerType;
+import com.jogamp.newt.event.MouseListener;
+import com.jogamp.newt.event.NEWTEvent;
+import com.jogamp.newt.event.NEWTEventConsumer;
+import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.event.WindowListener;
+import com.jogamp.newt.event.WindowUpdateEvent;
+
public abstract class WindowImpl implements Window, NEWTEventConsumer
{
- public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true);
-
+ public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE;
+
+ static {
+ Debug.initSingleton();
+ DEBUG_TEST_REPARENT_INCOMPATIBLE = PropertyAccess.isPropertyDefined("newt.test.Window.reparent.incompatible", true);
+
+ ScreenImpl.initSingleton();
+ }
+
+ protected static final ArrayList<WeakReference<WindowImpl>> windowList = new ArrayList<WeakReference<WindowImpl>>();
+
+ /** Maybe utilized at a shutdown hook, impl. does not block. */
+ public static final void shutdownAll() {
+ final int wCount = windowList.size();
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("Window.shutdownAll "+wCount+" instances, on thread "+getThreadName());
+ }
+ for(int i=0; i<wCount && windowList.size()>0; i++) { // be safe ..
+ final WindowImpl w = windowList.remove(0).get();
+ if(DEBUG_IMPLEMENTATION) {
+ final long wh = null != w ? w.getWindowHandle() : 0;
+ System.err.println("Window.shutdownAll["+(i+1)+"/"+wCount+"]: "+toHexString(wh)+", GCed "+(null==w));
+ }
+ if( null != w ) {
+ w.shutdown();
+ }
+ }
+ }
+ private static void addWindow2List(final WindowImpl window) {
+ synchronized(windowList) {
+ // GC before add
+ int i=0, gced=0;
+ while( i < windowList.size() ) {
+ if( null == windowList.get(i).get() ) {
+ gced++;
+ windowList.remove(i);
+ } else {
+ i++;
+ }
+ }
+ windowList.add(new WeakReference<WindowImpl>(window));
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("Window.addWindow2List: GCed "+gced+", size "+windowList.size());
+ }
+ }
+ }
+
/** Timeout of queued events (repaint and resize) */
- static final long QUEUED_EVENT_TO = 1200; // ms
-
+ static final long QUEUED_EVENT_TO = 1200; // ms
+
+ private static final PointerType[] constMousePointerTypes = new PointerType[] { PointerType.Mouse };
+
+ //
+ // Volatile: Multithread Mutable Access
+ //
private volatile long windowHandle = 0; // lifecycle critical
private volatile boolean visible = false; // lifecycle critical
- private RecursiveLock windowLock = LockFactory.createRecursiveLock(); // Window instance wide lock
- private RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); // Surface only lock
-
+ private volatile boolean hasFocus = false;
+ private volatile int pixWidth = 128, pixHeight = 128; // client-area size w/o insets in pixel units, default: may be overwritten by user
+ private volatile int winWidth = 128, winHeight = 128; // client-area size w/o insets in window units, default: may be overwritten by user
+ protected final int[] nativePixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+ protected final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+ protected final int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
+
+ private volatile int x = 64, y = 64; // client-area pos w/o insets in window units
+ private volatile Insets insets = new Insets(); // insets of decoration (if top-level && decorated)
+ private boolean blockInsetsChange = false; // block insets change (from same thread)
+
+ private final RecursiveLock windowLock = LockFactory.createRecursiveLock(); // Window instance wide lock
+ private int surfaceLockCount = 0; // surface lock recursion count
+
private ScreenImpl screen; // never null after create - may change reference though (reparent)
private boolean screenReferenceAdded = false;
private NativeWindow parentWindow = null;
@@ -94,72 +171,118 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
private AbstractGraphicsConfiguration config = null; // control access due to delegation
protected CapabilitiesImmutable capsRequested = null;
protected CapabilitiesChooser capabilitiesChooser = null; // default null -> default
- private boolean fullscreen = false, hasFocus = false, brokenFocusChange = false;
- private int width = 128, height = 128; // client-area size w/o insets, default: may be overwritten by user
- private int x = 64, y = 64; // client-area pos w/o insets
+ private boolean fullscreen = false, brokenFocusChange = false;
+ private List<MonitorDevice> fullscreenMonitors = null;
+ private boolean fullscreenUseMainMonitor = true;
private boolean autoPosition = true; // default: true (allow WM to choose top-level position, if not set by user)
- private Insets insets = new Insets(); // insets of decoration (if top-level && decorated)
-
+
private int nfs_width, nfs_height, nfs_x, nfs_y; // non fullscreen client-area size/pos w/o insets
+ private boolean nfs_alwaysOnTop; // non fullscreen alwaysOnTop setting
private NativeWindow nfs_parent = null; // non fullscreen parent, in case explicit reparenting is performed (offscreen)
private String title = "Newt Window";
private boolean undecorated = false;
private boolean alwaysOnTop = false;
+ private PointerIconImpl pointerIcon = null;
private boolean pointerVisible = true;
private boolean pointerConfined = false;
private LifecycleHook lifecycleHook = null;
- private boolean handleDestroyNotify = true;
+ private Runnable windowDestroyNotifyAction = null;
private FocusRunnable focusAction = null;
private KeyListener keyboardFocusHandler = null;
- private SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper();
-
- private Object childWindowsLock = new Object();
- private ArrayList<NativeWindow> childWindows = new ArrayList<NativeWindow>();
+ private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper();
+
+ private final Object childWindowsLock = new Object();
+ private final ArrayList<NativeWindow> childWindows = new ArrayList<NativeWindow>();
private ArrayList<MouseListener> mouseListeners = new ArrayList<MouseListener>();
- private int mouseButtonPressed = 0; // current pressed mouse button number
- private long lastMousePressed = 0; // last time when a mouse button was pressed
- private int lastMouseClickCount = 0; // last mouse button click count
- private boolean mouseInWindow = false;// mouse entered window - is inside the window (may be synthetic)
- private Point lastMousePosition = new Point();
- private ArrayList<KeyListener> keyListeners = new ArrayList<KeyListener>();
+ /** from event passing: {@link WindowImpl#consumePointerEvent(MouseEvent)}. */
+ private static class PointerState0 {
+ /** Pointer entered window - is inside the window (may be synthetic) */
+ boolean insideSurface = false;
+ /** Mouse EXIT has been sent (only for MOUSE type enter/exit)*/
+ boolean exitSent = false;
- private ArrayList<WindowListener> windowListeners = new ArrayList<WindowListener>();
- private boolean repaintQueued = false;
+ /** last time when a pointer button was pressed */
+ long lastButtonPressTime = 0;
- // Workaround for initialization order problems on Mac OS X
- // between native Newt and (apparently) Fmod -- if Fmod is
- // initialized first then the connection to the window server
- // breaks, leading to errors from deep within the AppKit
- public static void init(String type) {
- if (NativeWindowFactory.TYPE_MACOSX.equals(type)) {
- try {
- getWindowClass(type);
- } catch (Exception e) {
- e.printStackTrace();
+ /** Pointer in dragging mode */
+ boolean dragging = false;
+
+ void clearButton() {
+ lastButtonPressTime = 0;
+ }
+ public String toString() { return "PState0[inside "+insideSurface+", exitSent "+exitSent+", lastPress "+lastButtonPressTime+", dragging "+dragging+"]"; }
+ }
+ private final PointerState0 pState0 = new PointerState0();
+
+ /** from direct input: {@link WindowImpl#doPointerEvent(boolean, boolean, int[], short, int, int, boolean, short[], int[], int[], float[], float, float[], float)}. */
+ private static class PointerState1 extends PointerState0 {
+ /** Current pressed mouse button number */
+ short buttonPressed = (short)0;
+ /** Current pressed mouse button modifier mask */
+ int buttonPressedMask = 0;
+ /** Last mouse button click count */
+ short lastButtonClickCount = (short)0;
+
+ @Override
+ final void clearButton() {
+ super.clearButton();
+ lastButtonClickCount = (short)0;
+ if( !dragging || 0 == buttonPressedMask ) {
+ buttonPressed = 0;
+ buttonPressedMask = 0;
+ dragging = false;
+ }
+ }
+
+ /** Last pointer-move position for 8 touch-down pointers */
+ final Point[] movePositions = new Point[] {
+ new Point(), new Point(), new Point(), new Point(),
+ new Point(), new Point(), new Point(), new Point() };
+ final Point getMovePosition(final int id) {
+ if( 0 <= id && id < movePositions.length ) {
+ return movePositions[id];
}
+ return null;
}
+ public final String toString() { return "PState1[inside "+insideSurface+", exitSent "+exitSent+", lastPress "+lastButtonPressTime+
+ ", pressed [button "+buttonPressed+", mask "+buttonPressedMask+", dragging "+dragging+", clickCount "+lastButtonClickCount+"]"; }
}
+ private final PointerState1 pState1 = new PointerState1();
+
+ /** Pointer names -> pointer ID (consecutive index, starting w/ 0) */
+ private final ArrayHashSet<Integer> pName2pID = new ArrayHashSet<Integer>();
+
+ private boolean defaultGestureHandlerEnabled = true;
+ private DoubleTapScrollGesture gesture2PtrTouchScroll = null;
+ private ArrayList<GestureHandler> pointerGestureHandler = new ArrayList<GestureHandler>();
+
+ private ArrayList<GestureHandler.GestureListener> gestureListeners = new ArrayList<GestureHandler.GestureListener>();
+
+ private ArrayList<KeyListener> keyListeners = new ArrayList<KeyListener>();
+
+ private ArrayList<WindowListener> windowListeners = new ArrayList<WindowListener>();
+ private boolean repaintQueued = false;
//
// Construction Methods
//
- private static Class<?> getWindowClass(String type)
+ private static Class<?> getWindowClass(final String type)
throws ClassNotFoundException
{
final Class<?> windowClass = NewtFactory.getCustomClass(type, "WindowDriver");
if(null==windowClass) {
- throw new ClassNotFoundException("Failed to find NEWT Window Class <"+type+".WindowDriver>");
+ throw new ClassNotFoundException("Failed to find NEWT Window Class <"+type+".WindowDriver>");
}
return windowClass;
}
- public static WindowImpl create(NativeWindow parentWindow, long parentWindowHandle, Screen screen, CapabilitiesImmutable caps) {
+ public static WindowImpl create(final NativeWindow parentWindow, final long parentWindowHandle, final Screen screen, final CapabilitiesImmutable caps) {
try {
Class<?> windowClass;
if(caps.isOnscreen()) {
@@ -167,44 +290,60 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
} else {
windowClass = OffscreenWindow.class;
}
- WindowImpl window = (WindowImpl) windowClass.newInstance();
+ final WindowImpl window = (WindowImpl) windowClass.newInstance();
window.parentWindow = parentWindow;
window.parentWindowHandle = parentWindowHandle;
window.screen = (ScreenImpl) screen;
window.capsRequested = (CapabilitiesImmutable) caps.cloneMutable();
- window.setUndecorated(0!=parentWindowHandle);
window.instantiationFinished();
+ addWindow2List(window);
return window;
- } catch (Throwable t) {
+ } catch (final Throwable t) {
t.printStackTrace();
throw new NativeWindowException(t);
}
}
-
- public static WindowImpl create(Object[] cstrArguments, Screen screen, CapabilitiesImmutable caps) {
+
+ public static WindowImpl create(final Object[] cstrArguments, final Screen screen, final CapabilitiesImmutable caps) {
try {
- Class<?> windowClass = getWindowClass(screen.getDisplay().getType());
- Class<?>[] cstrArgumentTypes = getCustomConstructorArgumentTypes(windowClass);
+ final Class<?> windowClass = getWindowClass(screen.getDisplay().getType());
+ final Class<?>[] cstrArgumentTypes = getCustomConstructorArgumentTypes(windowClass);
if(null==cstrArgumentTypes) {
throw new NativeWindowException("WindowClass "+windowClass+" doesn't support custom arguments in constructor");
}
- int argsChecked = verifyConstructorArgumentTypes(cstrArgumentTypes, cstrArguments);
+ final int argsChecked = verifyConstructorArgumentTypes(cstrArgumentTypes, cstrArguments);
if ( argsChecked < cstrArguments.length ) {
throw new NativeWindowException("WindowClass "+windowClass+" constructor mismatch at argument #"+argsChecked+"; Constructor: "+getTypeStrList(cstrArgumentTypes)+", arguments: "+getArgsStrList(cstrArguments));
}
- WindowImpl window = (WindowImpl) ReflectionUtil.createInstance( windowClass, cstrArgumentTypes, cstrArguments ) ;
+ final WindowImpl window = (WindowImpl) ReflectionUtil.createInstance( windowClass, cstrArgumentTypes, cstrArguments ) ;
window.screen = (ScreenImpl) screen;
window.capsRequested = (CapabilitiesImmutable) caps.cloneMutable();
+ window.instantiationFinished();
+ addWindow2List(window);
return window;
- } catch (Throwable t) {
+ } catch (final Throwable t) {
throw new NativeWindowException(t);
}
}
- protected final void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg) {
+ /** Fast invalidation of instance w/o any blocking function call. */
+ private final void shutdown() {
+ if(null!=lifecycleHook) {
+ lifecycleHook.shutdownRenderingAction();
+ }
+ setWindowHandle(0);
+ visible = false;
+ fullscreen = false;
+ fullscreenMonitors = null;
+ fullscreenUseMainMonitor = true;
+ hasFocus = false;
+ parentWindowHandle = 0;
+ }
+
+ protected final void setGraphicsConfiguration(final AbstractGraphicsConfiguration cfg) {
config = cfg;
}
-
+
public static interface LifecycleHook {
/**
* Reset of internal state counter, ie totalFrames, etc.
@@ -212,15 +351,22 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
*/
public abstract void resetCounter();
- /**
- * Invoked after Window setVisible,
+ /**
+ * Invoked after Window setVisible,
* allows allocating resources depending on the native Window.
* Called from EDT while window is locked.
*/
void setVisibleActionPost(boolean visible, boolean nativeWindowCreated);
- /**
- * Invoked before Window destroy action,
+ /**
+ * Notifies the receiver to preserve resources (GL, ..)
+ * for the next destroy*() calls (only), if supported and if <code>value</code> is <code>true</code>, otherwise clears preservation flag.
+ * @param value <code>true</code> to set the one-shot preservation if supported, otherwise clears it.
+ */
+ void preserveGLStateAtDestroy(boolean value);
+
+ /**
+ * Invoked before Window destroy action,
* allows releasing of resources depending on the native Window.<br>
* Surface not locked yet.<br>
* Called not necessarily from EDT.
@@ -236,7 +382,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
void destroyActionInLock();
/**
- * Invoked for expensive modifications, ie while reparenting and ScreenMode change.<br>
+ * Invoked for expensive modifications, ie while reparenting and MonitorMode change.<br>
* No lock is hold when invoked.<br>
*
* @return true is paused, otherwise false. If true {@link #resumeRenderingAction()} shall be issued.
@@ -246,12 +392,20 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
boolean pauseRenderingAction();
/**
- * Invoked for expensive modifications, ie while reparenting and ScreenMode change.
+ * Invoked for expensive modifications, ie while reparenting and MonitorMode change.
* No lock is hold when invoked.<br>
*
* @see #pauseRenderingAction()
*/
void resumeRenderingAction();
+
+ /**
+ * Shutdown rendering action (thread) abnormally.
+ * <p>
+ * Should be called only at shutdown, if necessary.
+ * </p>
+ */
+ void shutdownRenderingAction();
}
private boolean createNative() {
@@ -262,38 +416,59 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
} else {
tStart = 0;
}
-
- if( null != parentWindow &&
+
+ if( null != parentWindow &&
NativeSurface.LOCK_SURFACE_NOT_READY >= parentWindow.lockSurface() ) {
throw new NativeWindowException("Parent surface lock: not ready: "+parentWindow);
}
-
+
+ final boolean hasParent = null != parentWindow || 0 != this.parentWindowHandle;
+
// child window: position defaults to 0/0, no auto position, no negative position
- if( null != parentWindow && ( autoPosition || 0>getX() || 0>getY() ) ) {
+ if( hasParent && ( autoPosition || 0>getX() || 0>getY() ) ) {
definePosition(0, 0);
}
boolean postParentlockFocus = false;
try {
if(validateParentWindowHandle()) {
- if(screenReferenceAdded) {
- throw new InternalError("XXX");
- }
- if(canCreateNativeImpl()) {
+ if( !screenReferenceAdded ) {
screen.addReference();
screenReferenceAdded = true;
+ }
+ if(canCreateNativeImpl()) {
+ final int wX, wY;
+ final boolean usePosition;
+ if( autoPosition ) {
+ wX = 0;
+ wY = 0;
+ usePosition = false;
+ } else {
+ wX = getX();
+ wY = getY();
+ usePosition = true;
+ }
+ final long t0 = System.currentTimeMillis();
createNativeImpl();
- screen.addScreenModeListener(screenModeListenerImpl);
+ screen.addMonitorModeListener(monitorModeListenerImpl);
setTitleImpl(title);
- setPointerVisibleImpl(pointerVisible);
+ setPointerIconIntern(pointerIcon);
+ setPointerVisibleIntern(pointerVisible);
confinePointerImpl(pointerConfined);
setKeyboardVisible(keyboardVisible);
- if(waitForVisible(true, false)) {
+ final long remainingV = waitForVisible(true, false);
+ if( 0 <= remainingV ) {
if(isFullscreen()) {
synchronized(fullScreenAction) {
fullscreen = false; // trigger a state change
fullScreenAction.init(true);
fullScreenAction.run();
}
+ } else if ( !hasParent ) {
+ // Wait until position is reached within tolerances, either auto-position or custom position.
+ waitForPosition(usePosition, wX, wY, Window.TIMEOUT_NATIVEWINDOW);
+ }
+ if (DEBUG_IMPLEMENTATION) {
+ System.err.println("Window.createNative(): elapsed "+(System.currentTimeMillis()-t0)+" ms");
}
postParentlockFocus = true;
}
@@ -306,7 +481,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
if(postParentlockFocus) {
// harmonize focus behavior for all platforms: focus on creation
- requestFocusInt(isFullscreen() /* skipFocusAction */);
+ requestFocusInt(isFullscreen() /* skipFocusAction if fullscreen */);
((DisplayImpl) screen.getDisplay()).dispatchMessagesNative(); // status up2date
}
if(DEBUG_IMPLEMENTATION) {
@@ -333,7 +508,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
return true;
}
- private static long getNativeWindowHandle(NativeWindow nativeWindow) {
+ private static long getNativeWindowHandle(final NativeWindow nativeWindow) {
long handle = 0;
if(null!=nativeWindow) {
boolean wasLocked = false;
@@ -344,7 +519,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(0==handle) {
throw new NativeWindowException("Parent native window handle is NULL, after succesful locking: "+nativeWindow);
}
- } catch (NativeWindowException nwe) {
+ } catch (final NativeWindowException nwe) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.getNativeWindowHandle: not successful yet: "+nwe);
}
@@ -371,18 +546,20 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
//----------------------------------------------------------------------
// WindowClosingProtocol implementation
//
- private Object closingListenerLock = new Object();
+ private final Object closingListenerLock = new Object();
private WindowClosingMode defaultCloseOperation = WindowClosingMode.DISPOSE_ON_CLOSE;
- public WindowClosingMode getDefaultCloseOperation() {
+ @Override
+ public final WindowClosingMode getDefaultCloseOperation() {
synchronized (closingListenerLock) {
return defaultCloseOperation;
}
}
- public WindowClosingMode setDefaultCloseOperation(WindowClosingMode op) {
+ @Override
+ public final WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) {
synchronized (closingListenerLock) {
- WindowClosingMode _op = defaultCloseOperation;
+ final WindowClosingMode _op = defaultCloseOperation;
defaultCloseOperation = op;
return _op;
}
@@ -394,28 +571,28 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
/**
* Notifies the driver impl. that the instantiation is finished,
- * ie. instance created and all fields set.
+ * ie. instance created and all fields set.
*/
protected void instantiationFinished() {
// nop
}
-
+
protected boolean canCreateNativeImpl() {
return true; // default: always able to be created
}
-
- /**
+
+ /**
* The native implementation must set the native windowHandle.<br>
*
* <p>
* The implementation shall respect the states {@link #isAlwaysOnTop()}/{@link #FLAG_IS_ALWAYSONTOP} and
* {@link #isUndecorated()}/{@link #FLAG_IS_UNDECORATED}, ie. the created window shall reflect those settings.
* </p>
- *
+ *
* <p>
* The implementation should invoke the referenced java state callbacks
* to notify this Java object of state changes.</p>
- *
+ *
* @see #windowDestroyNotify(boolean)
* @see #focusChanged(boolean, boolean)
* @see #visibleChanged(boolean, boolean)
@@ -427,16 +604,16 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
protected abstract void closeNativeImpl();
- /**
+ /**
* Async request which shall be performed within {@link #TIMEOUT_NATIVEWINDOW}.
* <p>
- * If if <code>force == false</code> the native implementation
+ * If if <code>force == false</code> the native implementation
* may only request focus if not yet owner.</p>
* <p>
* {@link #focusChanged(boolean, boolean)} should be called
- * to notify about the focus traversal.
- * </p>
- *
+ * to notify about the focus traversal.
+ * </p>
+ *
* @param force if true, bypass {@link #focusChanged(boolean, boolean)} and force focus request
*/
protected abstract void requestFocusImpl(boolean force);
@@ -446,26 +623,27 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
public static final int FLAG_CHANGE_FULLSCREEN = 1 << 2;
public static final int FLAG_CHANGE_ALWAYSONTOP = 1 << 3;
public static final int FLAG_CHANGE_VISIBILITY = 1 << 4;
-
+
public static final int FLAG_HAS_PARENT = 1 << 8;
public static final int FLAG_IS_UNDECORATED = 1 << 9;
public static final int FLAG_IS_FULLSCREEN = 1 << 10;
- public static final int FLAG_IS_ALWAYSONTOP = 1 << 11;
- public static final int FLAG_IS_VISIBLE = 1 << 12;
+ public static final int FLAG_IS_FULLSCREEN_SPAN = 1 << 11;
+ public static final int FLAG_IS_ALWAYSONTOP = 1 << 12;
+ public static final int FLAG_IS_VISIBLE = 1 << 13;
/**
* The native implementation should invoke the referenced java state callbacks
* to notify this Java object of state changes.
- *
+ *
* <p>
* Implementations shall set x/y to 0, in case it's negative. This could happen due
* to insets and positioning a decorated window to 0/0, which would place the frame
* outside of the screen.</p>
- *
- * @param x client-area position, or <0 if unchanged
- * @param y client-area position, or <0 if unchanged
- * @param width client-area size, or <=0 if unchanged
- * @param height client-area size, or <=0 if unchanged
+ *
+ * @param x client-area position in window units, or <0 if unchanged
+ * @param y client-area position in window units, or <0 if unchanged
+ * @param width client-area size in window units, or <=0 if unchanged
+ * @param height client-area size in window units, or <=0 if unchanged
* @param flags bitfield of change and status flags
*
* @see #sizeChanged(int,int)
@@ -473,79 +651,99 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
*/
protected abstract boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags);
- protected int getReconfigureFlags(int changeFlags, boolean visible) {
- return changeFlags |= ( ( 0 != getParentWindowHandle() ) ? FLAG_HAS_PARENT : 0 ) |
- ( isUndecorated() ? FLAG_IS_UNDECORATED : 0 ) |
- ( isFullscreen() ? FLAG_IS_FULLSCREEN : 0 ) |
- ( isAlwaysOnTop() ? FLAG_IS_ALWAYSONTOP : 0 ) |
- ( visible ? FLAG_IS_VISIBLE : 0 ) ;
+ /**
+ * Tests whether a single reconfigure flag is supported by implementation.
+ * <p>
+ * Default is all but {@link #FLAG_IS_FULLSCREEN_SPAN}
+ * </p>
+ */
+ protected boolean isReconfigureFlagSupported(final int changeFlags) {
+ return 0 == ( changeFlags & FLAG_IS_FULLSCREEN_SPAN );
}
- protected static String getReconfigureFlagsAsString(StringBuilder sb, int flags) {
+
+ protected int getReconfigureFlags(final int changeFlags, final boolean visible) {
+ return changeFlags | ( ( 0 != getParentWindowHandle() ) ? FLAG_HAS_PARENT : 0 ) |
+ ( isUndecorated() ? FLAG_IS_UNDECORATED : 0 ) |
+ ( isFullscreen() ? FLAG_IS_FULLSCREEN : 0 ) |
+ ( isAlwaysOnTop() ? FLAG_IS_ALWAYSONTOP : 0 ) |
+ ( visible ? FLAG_IS_VISIBLE : 0 ) ;
+ }
+ protected static String getReconfigureFlagsAsString(StringBuilder sb, final int flags) {
if(null == sb) { sb = new StringBuilder(); }
sb.append("[");
-
+
if( 0 != ( FLAG_CHANGE_PARENTING & flags) ) {
sb.append("*");
}
- sb.append("PARENT_");
+ sb.append("PARENT ");
sb.append(0 != ( FLAG_HAS_PARENT & flags));
sb.append(", ");
-
+
if( 0 != ( FLAG_CHANGE_FULLSCREEN & flags) ) {
sb.append("*");
}
- sb.append("FS_");
+ sb.append("FS ");
sb.append(0 != ( FLAG_IS_FULLSCREEN & flags));
- sb.append(", ");
+ sb.append("[span ");
+ sb.append(0 != ( FLAG_IS_FULLSCREEN_SPAN & flags));
+ sb.append("], ");
if( 0 != ( FLAG_CHANGE_DECORATION & flags) ) {
sb.append("*");
}
- sb.append("UNDECOR_");
+ sb.append("UNDECOR ");
sb.append(0 != ( FLAG_IS_UNDECORATED & flags));
sb.append(", ");
-
+
if( 0 != ( FLAG_CHANGE_ALWAYSONTOP & flags) ) {
sb.append("*");
}
- sb.append("ALWAYSONTOP_");
+ sb.append("ALWAYSONTOP ");
sb.append(0 != ( FLAG_IS_ALWAYSONTOP & flags));
sb.append(", ");
-
+
if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
sb.append("*");
}
- sb.append("VISIBLE_");
+ sb.append("VISIBLE ");
sb.append(0 != ( FLAG_IS_VISIBLE & flags));
-
+
sb.append("]");
return sb.toString();
}
-
- protected void setTitleImpl(String title) {}
+
+ protected void setTitleImpl(final String title) {}
/**
- * Return screen coordinates of the given coordinates
- * or null, in which case a NativeWindow traversal shall being used
+ * Translates the given window client-area coordinates with top-left origin
+ * to screen coordinates in window units.
+ * <p>
+ * Since the position reflects the client area, it does not include the insets.
+ * </p>
+ * <p>
+ * May return <code>null</code>, in which case the caller shall traverse through the NativeWindow tree
* as demonstrated in {@link #getLocationOnScreen(javax.media.nativewindow.util.Point)}.
+ * </p>
*
* @return if not null, the screen location of the given coordinates
*/
protected abstract Point getLocationOnScreenImpl(int x, int y);
-
- /** Triggered by user via {@link #getInsets()}.<br>
- * Implementations may implement this hook to update the insets.<br>
+
+ /**
+ * Triggered by user via {@link #getInsets()}.<br>
+ * Implementations may implement this hook to update the insets.<br>
* However, they may prefer the event driven path via {@link #insetsChanged(boolean, int, int, int, int)}.
- *
+ *
* @see #getInsets()
* @see #insetsChanged(boolean, int, int, int, int)
*/
protected abstract void updateInsetsImpl(Insets insets);
- protected boolean setPointerVisibleImpl(boolean pointerVisible) { return false; }
- protected boolean confinePointerImpl(boolean confine) { return false; }
- protected void warpPointerImpl(int x, int y) { }
-
+ protected boolean setPointerVisibleImpl(final boolean pointerVisible) { return false; }
+ protected boolean confinePointerImpl(final boolean confine) { return false; }
+ protected void warpPointerImpl(final int x, final int y) { }
+ protected void setPointerIconImpl(final PointerIconImpl pi) { }
+
//----------------------------------------------------------------------
// NativeSurface
//
@@ -553,10 +751,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
@Override
public final int lockSurface() throws NativeWindowException, RuntimeException {
final RecursiveLock _wlock = windowLock;
- final RecursiveLock _slock = surfaceLock;
_wlock.lock();
- _slock.lock();
- int res = _slock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ?
+ surfaceLockCount++;
+ int res = ( 1 == surfaceLockCount ) ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ?
if ( LOCK_SURFACE_NOT_READY == res ) {
try {
@@ -573,7 +770,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
} finally {
if (LOCK_SURFACE_NOT_READY >= res) {
- _slock.unlock();
+ surfaceLockCount--;
_wlock.unlock();
}
}
@@ -583,12 +780,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
@Override
public final void unlockSurface() {
- final RecursiveLock _slock = surfaceLock;
final RecursiveLock _wlock = windowLock;
- _slock.validateLocked();
_wlock.validateLocked();
- if (_slock.getHoldCount() == 1) {
+ if ( 1 == surfaceLockCount ) {
final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
try {
unlockSurfaceImpl();
@@ -596,42 +791,67 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
adevice.unlock();
}
}
- _slock.unlock();
+ surfaceLockCount--;
_wlock.unlock();
}
@Override
public final boolean isSurfaceLockedByOtherThread() {
- return surfaceLock.isLockedByOtherThread();
+ return windowLock.isLockedByOtherThread();
}
@Override
public final Thread getSurfaceLockOwner() {
- return surfaceLock.getOwner();
+ return windowLock.getOwner();
}
public final RecursiveLock getLock() {
return windowLock;
}
-
+
+ @Override
public long getSurfaceHandle() {
return windowHandle; // default: return window handle
}
+ @Override
public boolean surfaceSwap() {
return false;
}
+ @Override
+ public final void addSurfaceUpdatedListener(final SurfaceUpdatedListener l) {
+ surfaceUpdatedHelper.addSurfaceUpdatedListener(l);
+ }
+
+ @Override
+ public final void addSurfaceUpdatedListener(final int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
+ surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l);
+ }
+
+ @Override
+ public final void removeSurfaceUpdatedListener(final SurfaceUpdatedListener l) {
+ surfaceUpdatedHelper.removeSurfaceUpdatedListener(l);
+ }
+
+ @Override
+ public final void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) {
+ surfaceUpdatedHelper.surfaceUpdated(updater, ns, when);
+ }
+
+ @Override
public final AbstractGraphicsConfiguration getGraphicsConfiguration() {
return config.getNativeGraphicsConfiguration();
}
+ @Override
public final long getDisplayHandle() {
- return getScreen().getDisplay().getHandle();
+ return config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle();
}
+ @Override
public final int getScreenIndex() {
- return getScreen().getIndex();
+ return screen.getIndex();
}
//----------------------------------------------------------------------
@@ -640,14 +860,20 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
// public final void destroy() - see below
+ @Override
+ public final NativeSurface getNativeSurface() { return this; }
+
+ @Override
public final NativeWindow getParent() {
return parentWindow;
}
+ @Override
public final long getWindowHandle() {
return windowHandle;
}
+ @Override
public Point getLocationOnScreen(Point storage) {
if(isNativeValid()) {
Point d;
@@ -684,32 +910,47 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
// Window
//
+ @Override
public final boolean isNativeValid() {
return 0 != windowHandle ;
}
+ @Override
public final Screen getScreen() {
return screen;
}
- protected final void setVisibleImpl(boolean visible, int x, int y, int width, int height) {
- reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(FLAG_CHANGE_VISIBILITY, visible));
- }
- final void setVisibleActionImpl(boolean visible) {
+ protected void setScreen(final ScreenImpl newScreen) { // never null !
+ removeScreenReference();
+ screen = newScreen;
+ }
+
+ @Override
+ public final MonitorDevice getMainMonitor() {
+ return screen.getMainMonitor( getBounds() );
+ }
+
+ /**
+ * @param visible
+ * @param x client-area position in window units, or <0 if unchanged
+ * @param y client-area position in window units, or <0 if unchanged
+ * @param width client-area size in window units, or <=0 if unchanged
+ * @param height client-area size in window units, or <=0 if unchanged
+ */
+ protected final void setVisibleImpl(final boolean visible, final int x, final int y, final int width, final int height) {
+ reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(FLAG_CHANGE_VISIBILITY, visible));
+ }
+ final void setVisibleActionImpl(final boolean visible) {
boolean nativeWindowCreated = false;
boolean madeVisible = false;
-
+
final RecursiveLock _lock = windowLock;
_lock.lock();
try {
- if(null!=lifecycleHook) {
- lifecycleHook.resetCounter();
- }
-
if(!visible && null!=childWindows && childWindows.size()>0) {
synchronized(childWindowsLock) {
for(int i = 0; i < childWindows.size(); i++ ) {
- NativeWindow nw = childWindows.get(i);
+ final NativeWindow nw = childWindows.get(i);
if(nw instanceof WindowImpl) {
((WindowImpl)nw).setVisible(false);
}
@@ -722,12 +963,14 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
madeVisible = nativeWindowCreated;
}
// always flag visible, allowing a retry ..
- WindowImpl.this.visible = true;
+ WindowImpl.this.visible = true;
} else if(WindowImpl.this.visible != visible) {
if(isNativeValid()) {
setVisibleImpl(visible, getX(), getY(), getWidth(), getHeight());
- WindowImpl.this.waitForVisible(visible, true);
+ WindowImpl.this.waitForVisible(visible, false);
madeVisible = visible;
+ } else {
+ WindowImpl.this.visible = true;
}
}
@@ -738,7 +981,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(isNativeValid() && visible && null!=childWindows && childWindows.size()>0) {
synchronized(childWindowsLock) {
for(int i = 0; i < childWindows.size(); i++ ) {
- NativeWindow nw = childWindows.get(i);
+ final NativeWindow nw = childWindows.get(i);
if(nw instanceof WindowImpl) {
((WindowImpl)nw).setVisible(true);
}
@@ -749,6 +992,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
System.err.println("Window setVisible: END ("+getThreadName()+") "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+WindowImpl.this.visible+", nativeWindowCreated: "+nativeWindowCreated+", madeVisible: "+madeVisible);
}
} finally {
+ if(null!=lifecycleHook) {
+ lifecycleHook.resetCounter();
+ }
_lock.unlock();
}
if( nativeWindowCreated || madeVisible ) {
@@ -758,54 +1004,62 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
private class VisibleAction implements Runnable {
boolean visible;
- private VisibleAction(boolean visible) {
+ private VisibleAction(final boolean visible) {
this.visible = visible;
}
+ @Override
public final void run() {
setVisibleActionImpl(visible);
}
}
- protected void setVisible(boolean wait, boolean visible) {
+ @Override
+ public final void setVisible(final boolean wait, final boolean visible) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window setVisible: START ("+getThreadName()+") "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+this.visible+" -> "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+(null!=parentWindow));
}
- runOnEDTIfAvail(wait, new VisibleAction(visible));
+ runOnEDTIfAvail(wait, new VisibleAction(visible));
}
-
- public void setVisible(boolean visible) {
+
+ @Override
+ public final void setVisible(final boolean visible) {
setVisible(true, visible);
}
-
+
private class SetSizeAction implements Runnable {
int width, height;
+ boolean force;
- private SetSizeAction(int w, int h) {
+ private SetSizeAction(final int w, final int h, final boolean disregardFS) {
this.width = w;
this.height = h;
+ this.force = disregardFS;
}
+ @Override
public final void run() {
final RecursiveLock _lock = windowLock;
_lock.lock();
try {
- if ( !isFullscreen() && ( getWidth() != width || getHeight() != height ) ) {
+ if ( force || ( !isFullscreen() && ( getWidth() != width || getHeight() != height ) ) ) {
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window setSize: START "+getWidth()+"x"+getHeight()+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible);
+ System.err.println("Window setSize: START force "+force+", "+getWidth()+"x"+getHeight()+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible);
}
int visibleAction; // 0 nop, 1 invisible, 2 visible (create)
- if ( isNativeValid() && 0>=width*height && visible ) {
+ if ( visible && isNativeValid() && ( 0 >= width || 0 >= height ) ) {
visibleAction=1; // invisible
defineSize(0, 0);
- } else if ( !isNativeValid() && 0<width*height && visible ) {
+ } else if ( visible && !isNativeValid() && 0 < width && 0 < height ) {
visibleAction = 2; // visible (create)
defineSize(width, height);
- } else if ( isNativeValid() ) {
+ } else if ( visible && isNativeValid() ) {
visibleAction = 0;
// this width/height will be set by windowChanged, called by the native implementation
reconfigureWindowImpl(getX(), getY(), width, height, getReconfigureFlags(0, isVisible()));
+ WindowImpl.this.waitForSize(width, height, false, TIMEOUT_NATIVEWINDOW);
} else {
+ // invisible or invalid w/ 0 size
visibleAction = 0;
defineSize(width, height);
}
@@ -823,14 +1077,25 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
- public void setSize(int width, int height) {
- runOnEDTIfAvail(true, new SetSizeAction(width, height));
- }
- public void setTopLevelSize(int width, int height) {
+ private void setSize(final int width, final int height, final boolean force) {
+ runOnEDTIfAvail(true, new SetSizeAction(width, height, force));
+ }
+ @Override
+ public final void setSize(final int width, final int height) {
+ runOnEDTIfAvail(true, new SetSizeAction(width, height, false));
+ }
+ @Override
+ public final void setSurfaceSize(final int pixelWidth, final int pixelHeight) {
+ // FIXME HiDPI: Shortcut, may need to adjust if we change scaling methodology
+ setSize(pixelWidth / getPixelScaleX(), pixelHeight / getPixelScaleY());
+ }
+ @Override
+ public final void setTopLevelSize(final int width, final int height) {
setSize(width - getInsets().getTotalWidth(), height - getInsets().getTotalHeight());
}
- private class DestroyAction implements Runnable {
+ private final Runnable destroyAction = new Runnable() {
+ @Override
public final void run() {
boolean animatorPaused = false;
if(null!=lifecycleHook) {
@@ -839,23 +1104,27 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(null!=lifecycleHook) {
lifecycleHook.destroyActionPreLock();
}
+ RuntimeException lifecycleCaughtInLock = null;
final RecursiveLock _lock = windowLock;
_lock.lock();
try {
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window DestroyAction() "+getThreadName());
+ System.err.println("Window DestroyAction() hasScreen "+(null != screen)+", isNativeValid "+isNativeValid()+" - "+getThreadName());
}
+
+ // send synced destroy-notify notification
+ sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY);
+
// Childs first ..
synchronized(childWindowsLock) {
if(childWindows.size()>0) {
// avoid ConcurrentModificationException: parent -> child -> parent.removeChild(this)
@SuppressWarnings("unchecked")
- ArrayList<NativeWindow> clonedChildWindows = (ArrayList<NativeWindow>) childWindows.clone();
+ final ArrayList<NativeWindow> clonedChildWindows = (ArrayList<NativeWindow>) childWindows.clone();
while( clonedChildWindows.size() > 0 ) {
- NativeWindow nw = clonedChildWindows.remove(0);
+ final NativeWindow nw = clonedChildWindows.remove(0);
if(nw instanceof WindowImpl) {
- ((WindowImpl)nw).sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY);
- ((WindowImpl)nw).destroy();
+ ((WindowImpl)nw).windowDestroyNotify(true);
} else {
nw.destroy();
}
@@ -865,19 +1134,26 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(null!=lifecycleHook) {
// send synced destroy notification for proper cleanup, eg GLWindow/OpenGL
- lifecycleHook.destroyActionInLock();
+ try {
+ lifecycleHook.destroyActionInLock();
+ } catch (final RuntimeException re) {
+ lifecycleCaughtInLock = re;
+ }
}
- if( null != screen ) {
- if( isNativeValid() ) {
- screen.removeScreenModeListener(screenModeListenerImpl);
- closeNativeImpl();
- removeScreenReference();
- }
- Display dpy = screen.getDisplay();
- if(null != dpy) {
- dpy.validateEDT();
+ if( isNativeValid() ) {
+ screen.removeMonitorModeListener(monitorModeListenerImpl);
+ closeNativeImpl();
+ final AbstractGraphicsDevice cfgADevice = config.getScreen().getDevice();
+ if( cfgADevice != screen.getDisplay().getGraphicsDevice() ) { // don't pull display's device
+ cfgADevice.close(); // ensure a cfg's device is closed
}
+ setGraphicsConfiguration(null);
+ }
+ removeScreenReference();
+ final Display dpy = screen.getDisplay();
+ if(null != dpy) {
+ dpy.validateEDTStopped();
}
// send synced destroyed notification
@@ -885,54 +1161,73 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.destroy() END "+getThreadName()/*+", "+WindowImpl.this*/);
+ if( null != lifecycleCaughtInLock ) {
+ System.err.println("Window.destroy() caught: "+lifecycleCaughtInLock.getMessage());
+ lifecycleCaughtInLock.printStackTrace();
+ }
+ }
+ if( null != lifecycleCaughtInLock ) {
+ throw lifecycleCaughtInLock;
}
} finally {
// update states before release window lock
setWindowHandle(0);
visible = false;
fullscreen = false;
+ fullscreenMonitors = null;
+ fullscreenUseMainMonitor = true;
hasFocus = false;
parentWindowHandle = 0;
+ hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+ nativePixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ nativePixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
_lock.unlock();
}
if(animatorPaused) {
lifecycleHook.resumeRenderingAction();
}
-
+
// these refs shall be kept alive - resurrection via setVisible(true)
/**
if(null!=parentWindow && parentWindow instanceof Window) {
((Window)parentWindow).removeChild(WindowImpl.this);
- }
+ }
childWindows = null;
surfaceUpdatedListeners = null;
mouseListeners = null;
keyListeners = null;
capsRequested = null;
lifecycleHook = null;
-
- screen = null;
+
+ screen = null;
windowListeners = null;
parentWindow = null;
- */
- }
- }
- private final DestroyAction destroyAction = new DestroyAction();
+ */
+ } };
+ @Override
public void destroy() {
- visible = false; // Immediately mark synchronized visibility flag, avoiding possible recreation
+ visible = false; // Immediately mark synchronized visibility flag, avoiding possible recreation
runOnEDTIfAvail(true, destroyAction);
}
+ protected void destroy(final boolean preserveResources) {
+ if( null != lifecycleHook ) {
+ lifecycleHook.preserveGLStateAtDestroy( preserveResources );
+ }
+ destroy();
+ }
+
/**
* @param cWin child window, must not be null
* @param pWin parent window, may be null
- * @return true if at least one of both window's configurations is offscreen
+ * @return true if at least one of both window's configurations is offscreen
*/
- protected static boolean isOffscreenInstance(NativeWindow cWin, NativeWindow pWin) {
+ protected static boolean isOffscreenInstance(final NativeWindow cWin, final NativeWindow pWin) {
boolean ofs = false;
- final AbstractGraphicsConfiguration cWinCfg = cWin.getGraphicsConfiguration();
+ final AbstractGraphicsConfiguration cWinCfg = cWin.getGraphicsConfiguration();
if( null != cWinCfg ) {
ofs = !cWinCfg.getChosenCapabilities().isOnscreen();
}
@@ -944,15 +1239,21 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
return ofs;
}
-
+
private class ReparentAction implements Runnable {
- NativeWindow newParentWindow;
- boolean forceDestroyCreate;
+ final NativeWindow newParentWindow;
+ final int topLevelX, topLevelY;
+ final int hints;
ReparentOperation operation;
- private ReparentAction(NativeWindow newParentWindow, boolean forceDestroyCreate) {
+ private ReparentAction(final NativeWindow newParentWindow, final int topLevelX, final int topLevelY, int hints) {
this.newParentWindow = newParentWindow;
- this.forceDestroyCreate = forceDestroyCreate | DEBUG_TEST_REPARENT_INCOMPATIBLE;
+ this.topLevelX = topLevelX;
+ this.topLevelY = topLevelY;
+ if( DEBUG_TEST_REPARENT_INCOMPATIBLE ) {
+ hints |= REPARENT_HINT_FORCE_RECREATION;
+ }
+ this.hints = hints;
this.operation = ReparentOperation.ACTION_INVALID; // ensure it's set
}
@@ -960,12 +1261,16 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
return operation;
}
- private void setScreen(ScreenImpl newScreen) { // never null !
- removeScreenReference();
- screen = newScreen;
- }
-
+ @Override
public final void run() {
+ if( WindowImpl.this.isFullscreen() ) {
+ // Bug 924: Ignore reparent when in fullscreen - otherwise may confuse WM
+ if( DEBUG_IMPLEMENTATION) {
+ System.err.println("Window.reparent: NOP (in fullscreen, "+getThreadName()+") valid "+isNativeValid()+
+ ", windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle));
+ }
+ return;
+ }
boolean animatorPaused = false;
if(null!=lifecycleHook) {
animatorPaused = lifecycleHook.pauseRenderingAction();
@@ -975,24 +1280,35 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
lifecycleHook.resumeRenderingAction();
}
}
-
+
private void reparent() {
// mirror pos/size so native change notification can get overwritten
- int x = getX();
- int y = getY();
- int width = getWidth();
- int height = getHeight();
- boolean wasVisible;
-
+ final int oldX = getX();
+ final int oldY = getY();
+ final int oldWidth = getWidth();
+ final int oldHeight = getHeight();
+ final int x, y;
+ int width = oldWidth;
+ int height = oldHeight;
+
+ final boolean wasVisible;
+ final boolean becomesVisible;
+ final boolean forceDestroyCreate;
+
final RecursiveLock _lock = windowLock;
_lock.lock();
try {
- if(isNativeValid()) {
- // force recreation if offscreen, since it may become onscreen
- forceDestroyCreate |= isOffscreenInstance(WindowImpl.this, newParentWindow);
+ {
+ boolean v = 0 != ( REPARENT_HINT_FORCE_RECREATION & hints );
+ if(isNativeValid()) {
+ // force recreation if offscreen, since it may become onscreen
+ v |= isOffscreenInstance(WindowImpl.this, newParentWindow);
+ }
+ forceDestroyCreate = v;
}
-
+
wasVisible = isVisible();
+ becomesVisible = wasVisible || 0 != ( REPARENT_HINT_BECOMES_VISIBLE & hints );
Window newParentWindowNEWT = null;
if(newParentWindow instanceof Window) {
@@ -1001,15 +1317,21 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
long newParentWindowHandle = 0 ;
- if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.reparent: START ("+getThreadName()+") valid "+isNativeValid()+", windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+", visible "+wasVisible+", old parentWindow: "+Display.hashCodeNullSafe(parentWindow)+", new parentWindow: "+Display.hashCodeNullSafe(newParentWindow)+", forceDestroyCreate "+forceDestroyCreate+", "+x+"/"+y+" "+width+"x"+height);
- }
-
- if(null!=lifecycleHook) {
- lifecycleHook.resetCounter();
+ if( DEBUG_IMPLEMENTATION) {
+ System.err.println("Window.reparent: START ("+getThreadName()+") valid "+isNativeValid()+
+ ", windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+
+ ", visible "+wasVisible+", becomesVisible "+becomesVisible+
+ ", forceDestroyCreate "+forceDestroyCreate+
+ ", DEBUG_TEST_REPARENT_INCOMPATIBLE "+DEBUG_TEST_REPARENT_INCOMPATIBLE+
+ ", HINT_FORCE_RECREATION "+( 0 != ( REPARENT_HINT_FORCE_RECREATION & hints ) )+
+ ", HINT_BECOMES_VISIBLE "+( 0 != ( REPARENT_HINT_BECOMES_VISIBLE & hints ) ) +
+ ", old parentWindow: "+Display.hashCodeNullSafe(parentWindow)+
+ ", new parentWindow: "+Display.hashCodeNullSafe(newParentWindow) );
}
if(null!=newParentWindow) {
+ // REPARENT TO CHILD WINDOW
+
// reset position to 0/0 within parent space
x = 0;
y = 0;
@@ -1031,7 +1353,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
// Destroy this window and use parent's Screen.
// It may be created properly when the parent is made visible.
- destroy();
+ destroy( becomesVisible );
setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() );
operation = ReparentOperation.ACTION_NATIVE_CREATION_PENDING;
} else if(newParentWindow != getParent()) {
@@ -1042,25 +1364,24 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(null!=newParentWindowNEWT) {
setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() );
} else {
- Screen newScreen = NewtFactory.createCompatibleScreen(newParentWindow, getScreen());
- if( getScreen() != newScreen ) {
+ final Screen newScreen = NewtFactory.createCompatibleScreen(newParentWindow, screen);
+ if( screen != newScreen ) {
// auto destroy on-the-fly created Screen/Display
setScreen( (ScreenImpl) newScreen );
}
}
- if( 0<width*height ) {
+ if( 0 < width && 0 < height ) {
operation = ReparentOperation.ACTION_NATIVE_CREATION;
} else {
operation = ReparentOperation.ACTION_NATIVE_CREATION_PENDING;
}
- } else if ( forceDestroyCreate || !NewtFactory.isScreenCompatible(newParentWindow, getScreen()) ) {
- // Destroy this window, may create a new compatible Screen/Display,
- // and mark it for creation.
- destroy();
+ } else if ( forceDestroyCreate || !NewtFactory.isScreenCompatible(newParentWindow, screen) ) {
+ // Destroy this window, may create a new compatible Screen/Display, while trying to preserve resources if becoming visible again.
+ destroy( becomesVisible );
if(null!=newParentWindowNEWT) {
setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() );
} else {
- setScreen( (ScreenImpl) NewtFactory.createCompatibleScreen(newParentWindow, getScreen()) );
+ setScreen( (ScreenImpl) NewtFactory.createCompatibleScreen(newParentWindow, screen) );
}
operation = ReparentOperation.ACTION_NATIVE_CREATION;
} else {
@@ -1072,12 +1393,19 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
operation = ReparentOperation.ACTION_NOP;
}
} else {
- if( null != parentWindow ) {
+ // REPARENT TO TOP-LEVEL WINDOW
+ if( 0 <= topLevelX && 0 <= topLevelY ) {
+ x = topLevelX;
+ y = topLevelY;
+ } else if( null != parentWindow ) {
// child -> top
// put client to current parent+child position
- Point p = getLocationOnScreen(null);
+ final Point p = getLocationOnScreen(null);
x = p.getX();
y = p.getY();
+ } else {
+ x = oldX;
+ y = oldY;
}
// Case: Top Window
@@ -1086,8 +1414,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
operation = ReparentOperation.ACTION_NOP;
} else if( !isNativeValid() || forceDestroyCreate ) {
// Destroy this window and mark it for [pending] creation.
- destroy();
- if( 0<width*height ) {
+ // If isNativeValid() and becoming visible again - try to preserve resources, i.e. b/c on-/offscreen switch.
+ destroy( becomesVisible );
+ if( 0 < width && 0 < height ) {
operation = ReparentOperation.ACTION_NATIVE_CREATION;
} else {
operation = ReparentOperation.ACTION_NATIVE_CREATION_PENDING;
@@ -1103,15 +1432,18 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
throw new NativeWindowException("Internal Error: reparentAction not set");
}
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("Window.reparent: ACTION ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" new parentWindowHandle "+toHexString(newParentWindowHandle)+", reparentAction "+operation+", pos/size "+x+"/"+y+" "+width+"x"+height+", visible "+wasVisible);
+ }
+
if( ReparentOperation.ACTION_NOP == operation ) {
- if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.reparent: NO CHANGE ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" new parentWindowHandle "+toHexString(newParentWindowHandle)+", visible "+wasVisible);
- }
return;
}
- if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.reparent: ACTION ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" new parentWindowHandle "+toHexString(newParentWindowHandle)+", reparentAction "+operation+", visible "+wasVisible);
+ if( null == newParentWindow ) {
+ // CLIENT -> TOP: Reset Parent's Pointer State
+ setOffscreenPointerIcon(null);
+ setOffscreenPointerVisible(true, null);
}
// rearrange window tree
@@ -1123,23 +1455,17 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
((Window)parentWindow).addChild(WindowImpl.this);
}
- if( ReparentOperation.ACTION_NATIVE_CREATION_PENDING == operation ) {
- // make size and position persistent for proper recreation
- definePosition(x, y);
- defineSize(width, height);
- return;
- }
-
if( ReparentOperation.ACTION_NATIVE_REPARENTING == operation ) {
- DisplayImpl display = (DisplayImpl) screen.getDisplay();
+ final DisplayImpl display = (DisplayImpl) screen.getDisplay();
display.dispatchMessagesNative(); // status up2date
- if(wasVisible) {
- setVisibleImpl(false, x, y, width, height);
- WindowImpl.this.waitForVisible(false, true);
- // some composite WM behave slacky .. give 'em chance to change state -> invisible,
+ // TOP -> CLIENT: !visible first (fixes X11 unsuccessful return to parent window)
+ if( null != parentWindow && wasVisible && NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true) ) {
+ setVisibleImpl(false, oldX, oldY, oldWidth, oldHeight);
+ WindowImpl.this.waitForVisible(false, false);
+ // FIXME: Some composite WM behave slacky .. give 'em chance to change state -> invisible,
// even though we do exactly that (KDE+Composite)
- try { Thread.sleep(100); } catch (InterruptedException e) { }
+ try { Thread.sleep(100); } catch (final InterruptedException e) { }
display.dispatchMessagesNative(); // status up2date
}
@@ -1163,45 +1489,74 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
parentWindowLocked.unlockSurface();
}
}
+ definePosition(x, y); // position might not get updated by WM events (SWT parent apparently)
// set visible again
if(ok) {
display.dispatchMessagesNative(); // status up2date
if(wasVisible) {
setVisibleImpl(true, x, y, width, height);
- ok = WindowImpl.this.waitForVisible(true, false);
- display.dispatchMessagesNative(); // status up2date
+ ok = 0 <= WindowImpl.this.waitForVisible(true, false);
if(ok) {
+ if( isAlwaysOnTop() && 0 == parentWindowHandle && NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true) ) {
+ // Reinforce ALWAYSONTOP when CHILD -> TOP reparenting, since reparenting itself cause X11 WM to loose it's state.
+ reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(FLAG_CHANGE_ALWAYSONTOP, isVisible()));
+ }
ok = WindowImpl.this.waitForSize(width, height, false, TIMEOUT_NATIVEWINDOW);
}
if(ok) {
- requestFocusInt(false /* skipFocusAction */);
- display.dispatchMessagesNative(); // status up2date
+ if( 0 == parentWindowHandle ) {
+ // Position mismatch shall not lead to reparent failure
+ WindowImpl.this.waitForPosition(true, x, y, TIMEOUT_NATIVEWINDOW);
+ }
+
+ requestFocusInt( 0 == parentWindowHandle /* skipFocusAction if top-level */);
+ display.dispatchMessagesNative(); // status up2date
}
}
}
if(!ok || !wasVisible) {
- // make size and position persistent manual,
+ // make size and position persistent manual,
// since we don't have a WM feedback (invisible or recreation)
definePosition(x, y);
defineSize(width, height);
}
-
+
if(!ok) {
- // native reparent failed -> try creation
+ // native reparent failed -> try creation, while trying to preserve resources if becoming visible again.
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.reparent: native reparenting failed ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+" -> "+toHexString(newParentWindowHandle)+" - Trying recreation");
}
- destroy();
+ destroy( becomesVisible );
operation = ReparentOperation.ACTION_NATIVE_CREATION ;
+ } else {
+ if( null != parentWindow ) {
+ // TOP -> CLIENT: Setup Parent's Pointer State
+ setOffscreenPointerIcon(pointerIcon);
+ setOffscreenPointerVisible(pointerVisible, pointerIcon);
+ }
}
+ } else {
+ // Case
+ // ACTION_NATIVE_CREATION
+ // ACTION_NATIVE_CREATION_PENDING;
+
+ // make size and position persistent for proper [re]creation
+ definePosition(x, y);
+ defineSize(width, height);
}
-
+
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.reparentWindow: END-1 ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+ Display.hashCodeNullSafe(parentWindow)+" "+x+"/"+y+" "+width+"x"+height);
+ System.err.println("Window.reparent: END-1 ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+
+ ", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+
+ ", parentWindow "+ Display.hashCodeNullSafe(parentWindow)+" "+
+ getX()+"/"+getY()+" "+getWidth()+"x"+getHeight());
}
} finally {
+ if(null!=lifecycleHook) {
+ lifecycleHook.resetCounter();
+ }
_lock.unlock();
}
if(wasVisible) {
@@ -1215,53 +1570,55 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
// This may run on the new Display/Screen connection, hence a new EDT task
runOnEDTIfAvail(true, reparentActionRecreate);
break;
-
+
default:
}
}
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.reparentWindow: END-X ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+ Display.hashCodeNullSafe(parentWindow)+" "+x+"/"+y+" "+width+"x"+height);
+ System.err.println("Window.reparent: END-X ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+
+ ", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+
+ ", parentWindow "+ Display.hashCodeNullSafe(parentWindow)+" "+
+ getX()+"/"+getY()+" "+getWidth()+"x"+getHeight());
}
}
}
- private class ReparentActionRecreate implements Runnable {
+ private final Runnable reparentActionRecreate = new Runnable() {
+ @Override
public final void run() {
final RecursiveLock _lock = windowLock;
_lock.lock();
try {
- visible = true;
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.reparentWindow: ReparentActionRecreate ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+Display.hashCodeNullSafe(parentWindow));
+ System.err.println("Window.reparent: ReparentActionRecreate ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+Display.hashCodeNullSafe(parentWindow));
}
- setVisible(true); // native creation
+ setVisibleActionImpl(true); // native creation
+ requestFocusInt( 0 == parentWindowHandle /* skipFocusAction if top-level */);
} finally {
_lock.unlock();
}
- }
- }
- private final ReparentActionRecreate reparentActionRecreate = new ReparentActionRecreate();
+ } };
- public final ReparentOperation reparentWindow(NativeWindow newParent) {
- return reparentWindow(newParent, false);
- }
-
- public ReparentOperation reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) {
- final ReparentAction reparentAction = new ReparentAction(newParent, forceDestroyCreate);
+ @Override
+ public final ReparentOperation reparentWindow(final NativeWindow newParent, final int x, final int y, final int hints) {
+ final ReparentAction reparentAction = new ReparentAction(newParent, x, y, hints);
runOnEDTIfAvail(true, reparentAction);
return reparentAction.getOp();
}
- public CapabilitiesChooser setCapabilitiesChooser(CapabilitiesChooser chooser) {
- CapabilitiesChooser old = this.capabilitiesChooser;
+ @Override
+ public final CapabilitiesChooser setCapabilitiesChooser(final CapabilitiesChooser chooser) {
+ final CapabilitiesChooser old = this.capabilitiesChooser;
this.capabilitiesChooser = chooser;
return old;
}
+ @Override
public final CapabilitiesImmutable getChosenCapabilities() {
return getGraphicsConfiguration().getChosenCapabilities();
}
+ @Override
public final CapabilitiesImmutable getRequestedCapabilities() {
return capsRequested;
}
@@ -1269,10 +1626,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
private class DecorationAction implements Runnable {
boolean undecorated;
- private DecorationAction(boolean undecorated) {
+ private DecorationAction(final boolean undecorated) {
this.undecorated = undecorated;
}
+ @Override
public final void run() {
final RecursiveLock _lock = windowLock;
_lock.lock();
@@ -1288,7 +1646,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
final int width = getWidth();
final int height = getHeight();
- DisplayImpl display = (DisplayImpl) screen.getDisplay();
+ final DisplayImpl display = (DisplayImpl) screen.getDisplay();
display.dispatchMessagesNative(); // status up2date
reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(FLAG_CHANGE_DECORATION, isVisible()));
display.dispatchMessagesNative(); // status up2date
@@ -1301,10 +1659,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
- public void setUndecorated(boolean value) {
+ @Override
+ public final void setUndecorated(final boolean value) {
runOnEDTIfAvail(true, new DecorationAction(value));
}
+ @Override
public final boolean isUndecorated() {
return 0 != parentWindowHandle || undecorated || fullscreen ;
}
@@ -1312,10 +1672,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
private class AlwaysOnTopAction implements Runnable {
boolean alwaysOnTop;
- private AlwaysOnTopAction(boolean alwaysOnTop) {
+ private AlwaysOnTopAction(final boolean alwaysOnTop) {
this.alwaysOnTop = alwaysOnTop;
}
+ @Override
public final void run() {
final RecursiveLock _lock = windowLock;
_lock.lock();
@@ -1323,7 +1684,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(WindowImpl.this.alwaysOnTop != alwaysOnTop) {
// set current state
WindowImpl.this.alwaysOnTop = alwaysOnTop;
-
+
if( isNativeValid() ) {
// Mirror pos/size so native change notification can get overwritten
final int x = getX();
@@ -1331,7 +1692,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
final int width = getWidth();
final int height = getHeight();
- DisplayImpl display = (DisplayImpl) screen.getDisplay();
+ final DisplayImpl display = (DisplayImpl) screen.getDisplay();
display.dispatchMessagesNative(); // status up2date
reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(FLAG_CHANGE_ALWAYSONTOP, isVisible()));
display.dispatchMessagesNative(); // status up2date
@@ -1344,18 +1705,26 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
- public final void setAlwaysOnTop(boolean value) {
- runOnEDTIfAvail(true, new AlwaysOnTopAction(value));
+ @Override
+ public final void setAlwaysOnTop(final boolean value) {
+ if( isFullscreen() ) {
+ nfs_alwaysOnTop = value;
+ } else {
+ runOnEDTIfAvail(true, new AlwaysOnTopAction(value));
+ }
}
-
+
+ @Override
public final boolean isAlwaysOnTop() {
return alwaysOnTop;
}
-
- public String getTitle() {
+
+ @Override
+ public final String getTitle() {
return title;
}
- public void setTitle(String title) {
+ @Override
+ public final void setTitle(String title) {
if (title == null) {
title = "";
}
@@ -1365,31 +1734,128 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
- public boolean isPointerVisible() {
+ @Override
+ public final boolean isPointerVisible() {
return pointerVisible;
}
- public void setPointerVisible(boolean pointerVisible) {
+ @Override
+ public final void setPointerVisible(final boolean pointerVisible) {
if(this.pointerVisible != pointerVisible) {
boolean setVal = 0 == getWindowHandle();
if(!setVal) {
- setVal = setPointerVisibleImpl(pointerVisible);
+ setVal = setPointerVisibleIntern(pointerVisible);
}
if(setVal) {
- this.pointerVisible = pointerVisible;
+ this.pointerVisible = pointerVisible;
}
}
}
- public boolean isPointerConfined() {
+ private boolean setPointerVisibleIntern(final boolean pointerVisible) {
+ final boolean res = setOffscreenPointerVisible(pointerVisible, pointerIcon);
+ return setPointerVisibleImpl(pointerVisible) || res; // accept onscreen or offscreen positive result!
+ }
+ /**
+ * Helper method to delegate {@link #setPointerVisibleImpl(boolean)} to
+ * {@link OffscreenLayerSurface#hideCursor()} or {@link OffscreenLayerSurface#setCursor(PixelRectangle, PointImmutable)}.
+ * <p>
+ * Note: JAWTWindow is an OffscreenLayerSurface.
+ * </p>
+ * <p>
+ * Performing OffscreenLayerSurface's setCursor(..)/hideCursor(), if available,
+ * gives same behavior on all platforms.
+ * </p>
+ * <p>
+ * If visible, implementation invokes {@link #setOffscreenPointerIcon(OffscreenLayerSurface, PointerIconImpl)} using the
+ * given <code>defaultPointerIcon</code>, otherwise {@link OffscreenLayerSurface#hideCursor()} is invoked.
+ * </p>
+ * @param pointerVisible true for visible, otherwise invisible.
+ * @param defaultPointerIcon default PointerIcon for visibility
+ * @param ols the {@link OffscreenLayerSurface} instance, if null method does nothing.
+ */
+ private boolean setOffscreenPointerVisible(final boolean pointerVisible, final PointerIconImpl defaultPointerIcon) {
+ if( pointerVisible ) {
+ return setOffscreenPointerIcon(defaultPointerIcon);
+ } else {
+ final NativeWindow parent = getParent();
+ if( parent instanceof OffscreenLayerSurface ) {
+ final OffscreenLayerSurface ols = (OffscreenLayerSurface) parent;
+ try {
+ return ols.hideCursor();
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public final PointerIcon getPointerIcon() { return pointerIcon; }
+
+ @Override
+ public final void setPointerIcon(final PointerIcon pi) {
+ final PointerIconImpl piImpl = (PointerIconImpl)pi;
+ if( this.pointerIcon != piImpl ) {
+ if( isNativeValid() ) {
+ runOnEDTIfAvail(true, new Runnable() {
+ public void run() {
+ setPointerIconIntern(piImpl);
+ } } );
+ }
+ this.pointerIcon = piImpl;
+ }
+ }
+ private void setPointerIconIntern(final PointerIconImpl pi) {
+ setOffscreenPointerIcon(pi);
+ setPointerIconImpl(pi);
+ }
+ /**
+ * Helper method to delegate {@link #setPointerIconIntern(PointerIconImpl)} to
+ * {@link OffscreenLayerSurface#setCursor(PixelRectangle, PointImmutable)}
+ * <p>
+ * Note: JAWTWindow is an OffscreenLayerSurface.
+ * </p>
+ * <p>
+ * Performing OffscreenLayerSurface's setCursor(..), if available,
+ * gives same behavior on all platforms.
+ * </p>
+ * <p>
+ * Workaround for AWT/Windows bug within browser,
+ * where the PointerIcon gets periodically overridden
+ * by the AWT Component's icon.
+ * </p>
+ * @param ols the {@link OffscreenLayerSurface} instance, if null method does nothing.
+ * @param pi the {@link PointerIconImpl} instance, if null PointerIcon gets reset.
+ */
+ private boolean setOffscreenPointerIcon(final PointerIconImpl pi) {
+ final NativeWindow parent = getParent();
+ if( parent instanceof OffscreenLayerSurface ) {
+ final OffscreenLayerSurface ols = (OffscreenLayerSurface) parent;
+ try {
+ if( null != pi ) {
+ return ols.setCursor(pi, pi.getHotspot());
+ } else {
+ return ols.setCursor(null, null); // default
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public final boolean isPointerConfined() {
return pointerConfined;
}
-
- public void confinePointer(boolean confine) {
+ @Override
+ public final void confinePointer(final boolean confine) {
if(this.pointerConfined != confine) {
boolean setVal = 0 == getWindowHandle();
if(!setVal) {
if(confine) {
requestFocus();
- warpPointer(getWidth()/2, getHeight()/2);
+ warpPointer(getSurfaceWidth()/2, getSurfaceHeight()/2);
}
setVal = confinePointerImpl(confine);
if(confine) {
@@ -1397,21 +1863,23 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
// this allows user listener to sync previous position value to the new centered position
try {
Thread.sleep(3 * screen.getDisplay().getEDTUtil().getPollPeriod());
- } catch (InterruptedException e) { }
+ } catch (final InterruptedException e) { }
}
}
if(setVal) {
- this.pointerConfined = confine;
+ this.pointerConfined = confine;
}
- }
+ }
}
-
- public void warpPointer(int x, int y) {
+
+ @Override
+ public final void warpPointer(final int x, final int y) {
if(0 != getWindowHandle()) {
warpPointerImpl(x, y);
}
}
-
+
+ @Override
public final InsetsImmutable getInsets() {
if(isUndecorated()) {
return Insets.getZero();
@@ -1419,27 +1887,109 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
updateInsetsImpl(insets);
return insets;
}
-
+
+ @Override
+ public final int getX() {
+ return x;
+ }
+
+ @Override
+ public final int getY() {
+ return y;
+ }
+
+ @Override
public final int getWidth() {
- return width;
+ return winWidth;
}
+ @Override
public final int getHeight() {
- return height;
+ return winHeight;
}
- public final int getX() {
- return x;
+ @Override
+ public final Rectangle getBounds() {
+ return new Rectangle(x, y, winWidth, winHeight);
}
- public final int getY() {
- return y;
+ @Override
+ public final int getSurfaceWidth() {
+ return pixWidth;
+ }
+
+ @Override
+ public final int getSurfaceHeight() {
+ return pixHeight;
+ }
+
+ @Override
+ public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) {
+ pixelUnitsAndResult[0] /= getPixelScaleX();
+ pixelUnitsAndResult[1] /= getPixelScaleY();
+ return pixelUnitsAndResult;
+ }
+
+ @Override
+ public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) {
+ windowUnitsAndResult[0] *= getPixelScaleX();
+ windowUnitsAndResult[1] *= getPixelScaleY();
+ return windowUnitsAndResult;
+ }
+
+ protected final Point convertToWindowUnits(final Point pixelUnitsAndResult) {
+ return pixelUnitsAndResult.scaleInv(getPixelScaleX(), getPixelScaleY());
+ }
+
+ protected final Point convertToPixelUnits(final Point windowUnitsAndResult) {
+ return windowUnitsAndResult.scale(getPixelScaleX(), getPixelScaleY());
+ }
+
+ /** HiDPI: We currently base scaling of window units to pixel units on an integer scale factor per component. */
+ protected final int getPixelScaleX() {
+ return hasPixelScale[0];
+ }
+
+ /** HiDPI: We currently base scaling of window units to pixel units on an integer scale factor per component. */
+ protected final int getPixelScaleY() {
+ return hasPixelScale[1];
+ }
+
+ @Override
+ public void setSurfaceScale(final int[] pixelScale) {
+ SurfaceScaleUtils.validateReqPixelScale(reqPixelScale, pixelScale, DEBUG_IMPLEMENTATION ? getClass().getSimpleName() : null);
+ }
+
+ @Override
+ public final int[] getRequestedSurfaceScale(final int[] result) {
+ System.arraycopy(reqPixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ @Override
+ public final int[] getCurrentSurfaceScale(final int[] result) {
+ System.arraycopy(hasPixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ @Override
+ public final int[] getNativeSurfaceScale(final int[] result) {
+ System.arraycopy(nativePixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ @Override
+ public final float[] getPixelsPerMM(final float[] ppmmStore) {
+ getMainMonitor().getPixelsPerMM(ppmmStore);
+ ppmmStore[0] *= (float)hasPixelScale[0] / (float)nativePixelScale[0];
+ ppmmStore[1] *= (float)hasPixelScale[1] / (float)nativePixelScale[1];
+ return ppmmStore;
}
protected final boolean autoPosition() { return autoPosition; }
-
- /** Sets the position fields {@link #x} and {@link #y} to the given values and {@link #autoPosition} to false. */
- protected final void definePosition(int x, int y) {
+
+ /** Sets the position fields {@link #x} and {@link #y} in window units to the given values and {@link #autoPosition} to false. */
+ protected final void definePosition(final int x, final int y) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("definePosition: "+this.x+"/"+this.y+" -> "+x+"/"+y);
// Thread.dumpStack();
@@ -1448,19 +1998,28 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
this.x = x; this.y = y;
}
- /** Sets the size fields {@link #width} and {@link #height} to the given values. */
- protected final void defineSize(int width, int height) {
+ /**
+ * Sets the size fields {@link #winWidth} and {@link #winHeight} in window units to the given values
+ * and {@link #pixWidth} and {@link #pixHeight} in pixel units according to {@link #convertToPixelUnits(int[])}.
+ */
+ protected final void defineSize(final int winWidth, final int winHeight) {
+ final int pixWidth = winWidth * getPixelScaleX(); // FIXME HiDPI: Shortcut, may need to adjust if we change scaling methodology
+ final int pixHeight = winHeight * getPixelScaleY();
if(DEBUG_IMPLEMENTATION) {
- System.err.println("defineSize: "+this.width+"x"+this.height+" -> "+width+"x"+height);
+ System.err.println("defineSize: win["+this.winWidth+"x"+this.winHeight+" -> "+winWidth+"x"+winHeight+
+ "], pixel["+this.pixWidth+"x"+this.pixHeight+" -> "+pixWidth+"x"+pixHeight+"]");
// Thread.dumpStack();
}
- this.width = width; this.height = height;
+ this.winWidth = winWidth; this.winHeight = winHeight;
+ this.pixWidth = pixWidth; this.pixHeight = pixHeight;
}
-
+
+ @Override
public final boolean isVisible() {
return visible;
}
+ @Override
public final boolean isFullscreen() {
return fullscreen;
}
@@ -1469,6 +2028,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
// Window
//
+ @Override
+ public final Window getDelegatedWindow() {
+ return this;
+ }
+
+ //----------------------------------------------------------------------
+ // WindowImpl
+ //
+
/**
* If the implementation is capable of detecting a device change
* return true and clear the status/reason of the change.
@@ -1477,66 +2045,49 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
return false;
}
- public LifecycleHook getLifecycleHook() {
+ public final LifecycleHook getLifecycleHook() {
return lifecycleHook;
}
- public LifecycleHook setLifecycleHook(LifecycleHook hook) {
- LifecycleHook old = lifecycleHook;
+ public final LifecycleHook setLifecycleHook(final LifecycleHook hook) {
+ final LifecycleHook old = lifecycleHook;
lifecycleHook = hook;
return old;
}
- /** If this Window actually wraps one from another toolkit such as
- the AWT, this will return a non-null value. */
- public Object getWrappedWindow() {
- return null;
- }
-
- public final Window getDelegatedWindow() {
- return this;
- }
-
/**
- * If set to true, the default value, this NEWT Window implementation will
- * handle the destruction (ie {@link #destroy()} call) within {@link #windowDestroyNotify(boolean)} implementation.<br>
- * If set to false, it's up to the caller/owner to handle destruction within {@link #windowDestroyNotify(boolean)}.
+ * If this Window actually wraps a {@link NativeSurface} from another instance or toolkit,
+ * it will return such reference. Otherwise returns null.
*/
- public void setHandleDestroyNotify(boolean b) {
- handleDestroyNotify = b;
+ public NativeSurface getWrappedSurface() {
+ return null;
}
- //----------------------------------------------------------------------
- // WindowImpl
- //
-
- /**
- * Returns the non delegated {@link AbstractGraphicsConfiguration},
- * see {@link #getGraphicsConfiguration()}. */
- public final AbstractGraphicsConfiguration getPrivateGraphicsConfiguration() {
- return config;
+ @Override
+ public final void setWindowDestroyNotifyAction(final Runnable r) {
+ windowDestroyNotifyAction = r;
}
-
+
protected final long getParentWindowHandle() {
return isFullscreen() ? 0 : parentWindowHandle;
}
@Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
+ public final String toString() {
+ final StringBuilder sb = new StringBuilder();
sb.append(getClass().getName()+"[Config "+config+
- "\n, "+screen+
- "\n, ParentWindow "+parentWindow+
- "\n, ParentWindowHandle "+toHexString(parentWindowHandle)+" ("+(0!=getParentWindowHandle())+")"+
- "\n, WindowHandle "+toHexString(getWindowHandle())+
- "\n, SurfaceHandle "+toHexString(getSurfaceHandle())+ " (lockedExt window "+windowLock.isLockedByOtherThread()+", surface "+isSurfaceLockedByOtherThread()+")"+
- "\n, Pos "+getX()+"/"+getY()+" (auto "+autoPosition()+"), size "+getWidth()+"x"+getHeight()+
- "\n, Visible "+isVisible()+", focus "+hasFocus()+
- "\n, Undecorated "+undecorated+" ("+isUndecorated()+")"+
- "\n, AlwaysOnTop "+alwaysOnTop+", Fullscreen "+fullscreen+
- "\n, WrappedWindow "+getWrappedWindow()+
- "\n, ChildWindows "+childWindows.size());
+ ",\n "+screen+
+ ",\n ParentWindow "+parentWindow+
+ ",\n ParentWindowHandle "+toHexString(parentWindowHandle)+" ("+(0!=getParentWindowHandle())+")"+
+ ",\n WindowHandle "+toHexString(getWindowHandle())+
+ ",\n SurfaceHandle "+toHexString(getSurfaceHandle())+ " (lockedExt window "+windowLock.isLockedByOtherThread()+", surface "+isSurfaceLockedByOtherThread()+")"+
+ ",\n window["+getX()+"/"+getY()+" (auto "+autoPosition()+") "+getWidth()+"x"+getHeight()+"], pixel["+getSurfaceWidth()+"x"+getSurfaceHeight()+
+ "],\n Visible "+isVisible()+", focus "+hasFocus()+
+ ",\n Undecorated "+undecorated+" ("+isUndecorated()+")"+
+ ",\n AlwaysOnTop "+alwaysOnTop+", Fullscreen "+fullscreen+
+ ",\n WrappedSurface "+getWrappedSurface()+
+ ",\n ChildWindows "+childWindows.size());
sb.append(", SurfaceUpdatedListeners num "+surfaceUpdatedHelper.size()+" [");
for (int i = 0; i < surfaceUpdatedHelper.size(); i++ ) {
@@ -1550,33 +2101,33 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
for (int i = 0; i < mouseListeners.size(); i++ ) {
sb.append(mouseListeners.get(i)+", ");
}
+ sb.append("], PointerGestures default "+defaultGestureHandlerEnabled+", custom "+pointerGestureHandler.size()+" [");
+ for (int i = 0; i < pointerGestureHandler.size(); i++ ) {
+ sb.append(pointerGestureHandler.get(i)+", ");
+ }
sb.append("], KeyListeners num "+keyListeners.size()+" [");
for (int i = 0; i < keyListeners.size(); i++ ) {
sb.append(keyListeners.get(i)+", ");
}
- sb.append("], surfaceLock "+surfaceLock);
- sb.append(", windowLock "+windowLock+"]");
+ sb.append("], windowLock "+windowLock+", surfaceLockCount "+surfaceLockCount+"]");
return sb.toString();
}
- protected final void setWindowHandle(long handle) {
+ protected final void setWindowHandle(final long handle) {
windowHandle = handle;
}
- public void runOnEDTIfAvail(boolean wait, final Runnable task) {
- if(windowLock.isOwner(Thread.currentThread())) {
+ @Override
+ public final void runOnEDTIfAvail(final boolean wait, final Runnable task) {
+ if( windowLock.isOwner( Thread.currentThread() ) ) {
task.run();
} else {
- Screen scrn = getScreen();
- if(null==scrn) {
- throw new RuntimeException("Null screen of inner class: "+this);
- }
- DisplayImpl d = (DisplayImpl) scrn.getDisplay();
- d.runOnEDTIfAvail(wait, task);
+ ( (DisplayImpl) screen.getDisplay() ).runOnEDTIfAvail(wait, task);
}
}
private final Runnable requestFocusAction = new Runnable() {
+ @Override
public final void run() {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.RequestFocusAction: force 0 - ("+getThreadName()+"): "+hasFocus+" -> true - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle));
@@ -1585,6 +2136,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
};
private final Runnable requestFocusActionForced = new Runnable() {
+ @Override
public final void run() {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.RequestFocusAction: force 1 - ("+getThreadName()+"): "+hasFocus+" -> true - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle));
@@ -1593,40 +2145,44 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
};
+ @Override
public final boolean hasFocus() {
return hasFocus;
}
- public void requestFocus() {
+ @Override
+ public final void requestFocus() {
requestFocus(true);
}
- public void requestFocus(boolean wait) {
+ @Override
+ public final void requestFocus(final boolean wait) {
requestFocus(wait /* wait */, false /* skipFocusAction */, brokenFocusChange /* force */);
}
-
- private void requestFocus(boolean wait, boolean skipFocusAction, boolean force) {
+
+ private void requestFocus(final boolean wait, final boolean skipFocusAction, final boolean force) {
if( isNativeValid() &&
( force || !hasFocus() ) &&
( skipFocusAction || !focusAction() ) ) {
runOnEDTIfAvail(wait, force ? requestFocusActionForced : requestFocusAction);
}
}
-
+
/** Internally forcing request focus on current thread */
- private void requestFocusInt(boolean skipFocusAction) {
+ private void requestFocusInt(final boolean skipFocusAction) {
if( skipFocusAction || !focusAction() ) {
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.RequestFocusInt: forcing - ("+getThreadName()+"): "+hasFocus+" -> true - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle));
+ System.err.println("Window.RequestFocusInt: forcing - ("+getThreadName()+"): skipFocusAction "+skipFocusAction+", focus "+hasFocus+" -> true - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle));
}
requestFocusImpl(true);
- }
+ }
}
-
- public void setFocusAction(FocusRunnable focusAction) {
+
+ @Override
+ public final void setFocusAction(final FocusRunnable focusAction) {
this.focusAction = focusAction;
}
-
+
private boolean focusAction() {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.focusAction() START - "+getThreadName()+", focusAction: "+focusAction+" - windowHandle "+toHexString(getWindowHandle()));
@@ -1642,23 +2198,25 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
return res;
}
-
- protected void setBrokenFocusChange(boolean v) {
+
+ protected final void setBrokenFocusChange(final boolean v) {
brokenFocusChange = v;
}
-
- public void setKeyboardFocusHandler(KeyListener l) {
+
+ @Override
+ public final void setKeyboardFocusHandler(final KeyListener l) {
keyboardFocusHandler = l;
}
-
+
private class SetPositionAction implements Runnable {
int x, y;
- private SetPositionAction(int x, int y) {
+ private SetPositionAction(final int x, final int y) {
this.x = x;
this.y = y;
}
+ @Override
public final void run() {
final RecursiveLock _lock = windowLock;
_lock.lock();
@@ -1666,10 +2224,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window setPosition: "+getX()+"/"+getY()+" -> "+x+"/"+y+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle));
}
- if ( !isFullscreen() && ( getX() != x || getY() != y ) ) {
+ // Let the window be positioned if !fullscreen and position changed or being a child window.
+ if ( !isFullscreen() && ( getX() != x || getY() != y || null != getParent()) ) {
if(isNativeValid()) {
// this.x/this.y will be set by sizeChanged, triggered by windowing event system
reconfigureWindowImpl(x, y, getWidth(), getHeight(), getReconfigureFlags(0, isVisible()));
+ if( null == parentWindow ) {
+ // Wait until custom position is reached within tolerances
+ waitForPosition(true, x, y, Window.TIMEOUT_NATIVEWINDOW);
+ }
} else {
definePosition(x, y); // set pos for createNative(..)
}
@@ -1680,58 +2243,96 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
- public void setPosition(int x, int y) {
+ @Override
+ public void setPosition(final int x, final int y) {
autoPosition = false;
runOnEDTIfAvail(true, new SetPositionAction(x, y));
}
-
- public void setTopLevelPosition(int x, int y) {
+
+ @Override
+ public final void setTopLevelPosition(final int x, final int y) {
setPosition(x + getInsets().getLeftWidth(), y + getInsets().getTopHeight());
}
-
+
private class FullScreenAction implements Runnable {
- boolean fullscreen;
+ boolean _fullscreen;
- private boolean init(boolean fullscreen) {
+ private boolean init(final boolean fullscreen) {
if(isNativeValid()) {
- this.fullscreen = fullscreen;
+ this._fullscreen = fullscreen;
return isFullscreen() != fullscreen;
} else {
WindowImpl.this.fullscreen = fullscreen; // set current state for createNative(..)
return false;
}
- }
- public boolean fsOn() { return fullscreen; }
+ }
+ public boolean fsOn() { return _fullscreen; }
+ @Override
public final void run() {
final RecursiveLock _lock = windowLock;
_lock.lock();
+ blockInsetsChange = true;
try {
- // set current state
- WindowImpl.this.fullscreen = fullscreen;
+ final int oldX = getX();
+ final int oldY = getY();
+ final int oldWidth = getWidth();
+ final int oldHeight = getHeight();
int x,y,w,h;
-
- if(fullscreen) {
- nfs_x = getX();
- nfs_y = getY();
- nfs_width = getWidth();
- nfs_height = getHeight();
- x = screen.getX();
- y = screen.getY();
- w = screen.getWidth();
- h = screen.getHeight();
+
+ final RectangleImmutable sviewport = screen.getViewportInWindowUnits(); // window units
+ final RectangleImmutable viewport; // window units
+ final int fs_span_flag;
+ final boolean alwaysOnTopChange;
+ if(_fullscreen) {
+ if( null == fullscreenMonitors ) {
+ if( fullscreenUseMainMonitor ) {
+ fullscreenMonitors = new ArrayList<MonitorDevice>();
+ fullscreenMonitors.add( getMainMonitor() );
+ } else {
+ fullscreenMonitors = getScreen().getMonitorDevices();
+ }
+ }
+ {
+ final Rectangle viewportInWindowUnits = new Rectangle();
+ MonitorDevice.unionOfViewports(null, viewportInWindowUnits, fullscreenMonitors);
+ viewport = viewportInWindowUnits;
+ }
+ if( isReconfigureFlagSupported(FLAG_IS_FULLSCREEN_SPAN) &&
+ ( fullscreenMonitors.size() > 1 || sviewport.compareTo(viewport) > 0 ) ) {
+ fs_span_flag = FLAG_IS_FULLSCREEN_SPAN;
+ } else {
+ fs_span_flag = 0;
+ }
+ nfs_x = oldX;
+ nfs_y = oldY;
+ nfs_width = oldWidth;
+ nfs_height = oldHeight;
+ nfs_alwaysOnTop = alwaysOnTop;
+ x = viewport.getX();
+ y = viewport.getY();
+ w = viewport.getWidth();
+ h = viewport.getHeight();
+ alwaysOnTop = false;
+ alwaysOnTopChange = nfs_alwaysOnTop != alwaysOnTop;
} else {
+ fullscreenUseMainMonitor = true;
+ fullscreenMonitors = null;
+ fs_span_flag = 0;
+ viewport = null;
x = nfs_x;
y = nfs_y;
w = nfs_width;
h = nfs_height;
-
+ alwaysOnTopChange = nfs_alwaysOnTop != alwaysOnTop;
+ alwaysOnTop = nfs_alwaysOnTop;
+
if(null!=parentWindow) {
// reset position to 0/0 within parent space
x = 0;
y = 0;
-
+
// refit if size is bigger than parent
if( w > parentWindow.getWidth() ) {
w = parentWindow.getWidth();
@@ -1741,14 +2342,30 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
}
+
+ final DisplayImpl display = (DisplayImpl) screen.getDisplay();
+ display.dispatchMessagesNative(); // status up2date
+ final boolean wasVisible = isVisible();
+ final boolean tempInvisible = !_fullscreen && wasVisible && NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true);
+
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+isUndecorated()+", "+screen);
+ System.err.println("Window fs: "+_fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+isUndecorated()+
+ ", virtl-screenSize: "+sviewport+" [wu], monitorsViewport "+viewport+" [wu]"+
+ ", spanning "+(0!=fs_span_flag)+
+ ", alwaysOnTop "+alwaysOnTop+(alwaysOnTopChange?"*":"")+
+ ", wasVisible "+wasVisible+", tempInvisible "+tempInvisible+
+ ", hasParent "+(null!=parentWindow)+
+ " @ "+Thread.currentThread().getName());
+ }
+
+ // fullscreen off: !visible first (fixes X11 unsuccessful return to parent window _and_ wrong window size propagation)
+ if( tempInvisible ) {
+ setVisibleImpl(false, oldX, oldY, oldWidth, oldHeight);
+ WindowImpl.this.waitForVisible(false, false);
+ try { Thread.sleep(100); } catch (final InterruptedException e) { }
+ display.dispatchMessagesNative(); // status up2date
}
- DisplayImpl display = (DisplayImpl) screen.getDisplay();
- display.dispatchMessagesNative(); // status up2date
- boolean wasVisible = isVisible();
-
// Lock parentWindow only during reparenting (attempt)
final NativeWindow parentWindowLocked;
if( null != parentWindow ) {
@@ -1760,28 +2377,51 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
parentWindowLocked = null;
}
try {
- reconfigureWindowImpl(x, y, w, h,
- getReconfigureFlags( ( ( null != parentWindowLocked ) ? FLAG_CHANGE_PARENTING : 0 ) |
- FLAG_CHANGE_FULLSCREEN | FLAG_CHANGE_DECORATION, wasVisible) );
+ if(alwaysOnTopChange && _fullscreen) {
+ // Enter fullscreen - Disable alwaysOnTop
+ reconfigureWindowImpl(oldX, oldY, oldWidth, oldHeight, getReconfigureFlags(FLAG_CHANGE_ALWAYSONTOP, isVisible()));
+ }
+
+ WindowImpl.this.fullscreen = _fullscreen;
+ reconfigureWindowImpl(x, y, w, h,
+ getReconfigureFlags( ( ( null != parentWindowLocked ) ? FLAG_CHANGE_PARENTING : 0 ) |
+ fs_span_flag | FLAG_CHANGE_FULLSCREEN | FLAG_CHANGE_DECORATION, isVisible()) );
+ if(alwaysOnTopChange && !_fullscreen) {
+ // Leave fullscreen - Restore alwaysOnTop
+ reconfigureWindowImpl(x, y, w, h, getReconfigureFlags(FLAG_CHANGE_ALWAYSONTOP, isVisible()));
+ }
} finally {
if(null!=parentWindowLocked) {
parentWindowLocked.unlockSurface();
}
}
display.dispatchMessagesNative(); // status up2date
-
+
if(wasVisible) {
+ if( NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true) ) {
+ // Give sluggy WM's (e.g. Unity) a chance to properly restore window ..
+ try { Thread.sleep(100); } catch (final InterruptedException e) { }
+ display.dispatchMessagesNative(); // status up2date
+ }
setVisibleImpl(true, x, y, w, h);
- WindowImpl.this.waitForVisible(true, false);
- display.dispatchMessagesNative(); // status up2date
- WindowImpl.this.waitForSize(w, h, false, TIMEOUT_NATIVEWINDOW);
- display.dispatchMessagesNative(); // status up2date
-
+ boolean ok = 0 <= WindowImpl.this.waitForVisible(true, false);
+ if(ok) {
+ ok = WindowImpl.this.waitForSize(w, h, false, TIMEOUT_NATIVEWINDOW);
+ }
+ if(ok && !_fullscreen && null == parentWindow) {
+ // Position mismatch shall not lead to fullscreen failure
+ WindowImpl.this.waitForPosition(true, x, y, TIMEOUT_NATIVEWINDOW);
+ }
+ if(ok) {
+ requestFocusInt(_fullscreen /* skipFocusAction if fullscreen */);
+ display.dispatchMessagesNative(); // status up2date
+ }
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window fs done: " + WindowImpl.this);
+ System.err.println("Window fs done: ok " + ok + ", " + WindowImpl.this);
}
}
} finally {
+ blockInsetsChange = false;
_lock.unlock();
}
sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener
@@ -1789,86 +2429,170 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
private final FullScreenAction fullScreenAction = new FullScreenAction();
- public boolean setFullscreen(boolean fullscreen) {
+ @Override
+ public boolean setFullscreen(final boolean fullscreen) {
+ return setFullscreenImpl(fullscreen, true, null);
+ }
+
+ @Override
+ public boolean setFullscreen(final List<MonitorDevice> monitors) {
+ return setFullscreenImpl(true, false, monitors);
+ }
+
+ private boolean setFullscreenImpl(final boolean fullscreen, final boolean useMainMonitor, final List<MonitorDevice> monitors) {
synchronized(fullScreenAction) {
- if( fullScreenAction.init(fullscreen) ) {
- if(fullScreenAction.fsOn() && isOffscreenInstance(WindowImpl.this, parentWindow)) {
+ fullscreenMonitors = monitors;
+ fullscreenUseMainMonitor = useMainMonitor;
+ if( fullScreenAction.init(fullscreen) ) {
+ if( fullScreenAction.fsOn() && isOffscreenInstance(WindowImpl.this, parentWindow) ) {
// enable fullscreen on offscreen instance
if(null != parentWindow) {
nfs_parent = parentWindow;
- reparentWindow(null, true);
+ reparentWindow(null, -1, -1, REPARENT_HINT_FORCE_RECREATION | REPARENT_HINT_BECOMES_VISIBLE);
} else {
throw new InternalError("Offscreen instance w/o parent unhandled");
}
}
-
+
runOnEDTIfAvail(true, fullScreenAction);
-
+
if(!fullScreenAction.fsOn() && null != nfs_parent) {
// disable fullscreen on offscreen instance
- reparentWindow(nfs_parent, true);
+ reparentWindow(nfs_parent, -1, -1, REPARENT_HINT_FORCE_RECREATION | REPARENT_HINT_BECOMES_VISIBLE);
nfs_parent = null;
}
-
- if(isVisible()) {
- requestFocus(true /* wait */, this.fullscreen /* skipFocusAction */, true /* force */);
- }
}
- return this.fullscreen;
+ return this.fullscreen;
}
}
- private class ScreenModeListenerImpl implements ScreenModeListener {
- boolean animatorPaused = false;
+ /** Notify WindowDriver about the finished monitor mode change. */
+ protected void monitorModeChanged(final MonitorEvent me, final boolean success) {
+ }
- public void screenModeChangeNotify(ScreenMode sm) {
+ private class MonitorModeListenerImpl implements MonitorModeListener {
+ boolean animatorPaused = false;
+ boolean hidden = false;
+ boolean hadFocus = false;
+ boolean fullscreenPaused = false;
+ List<MonitorDevice> _fullscreenMonitors = null;
+ boolean _fullscreenUseMainMonitor = true;
+
+ @Override
+ public void monitorModeChangeNotify(final MonitorEvent me) {
+ hadFocus = hasFocus();
+ final boolean isOSX = NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(true);
+ final boolean quirkFSPause = fullscreen && isReconfigureFlagSupported(FLAG_IS_FULLSCREEN_SPAN);
+ final boolean quirkHide = !quirkFSPause && !fullscreen && isVisible() && isOSX;
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.screenModeChangeNotify: "+sm);
+ System.err.println("Window.monitorModeChangeNotify: hadFocus "+hadFocus+", qFSPause "+quirkFSPause+", qHide "+quirkHide+", "+me+" @ "+Thread.currentThread().getName());
}
if(null!=lifecycleHook) {
animatorPaused = lifecycleHook.pauseRenderingAction();
}
+ if( quirkFSPause ) {
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("Window.monitorModeChangeNotify: FS Pause");
+ }
+ fullscreenPaused = true;
+ _fullscreenMonitors = fullscreenMonitors;
+ _fullscreenUseMainMonitor = fullscreenUseMainMonitor;
+ setFullscreenImpl(false, true, null);
+ }
+ if( quirkHide ) {
+ // hiding & showing the window around mode-change solves issues w/ OSX,
+ // where the content would be black until a resize.
+ hidden = true;
+ WindowImpl.this.setVisible(false);
+ }
}
- public void screenModeChanged(ScreenMode sm, boolean success) {
- if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.screenModeChanged: "+sm+", success: "+success);
+ @Override
+ public void monitorModeChanged(final MonitorEvent me, final boolean success) {
+ if(!animatorPaused && success && null!=lifecycleHook) {
+ // Didn't pass above notify method. probably detected screen change after it happened.
+ animatorPaused = lifecycleHook.pauseRenderingAction();
}
-
- if(success) {
- if(!animatorPaused && null!=lifecycleHook) {
- // Didn't pass above notify method. probably detected screen change after it happened.
- animatorPaused = lifecycleHook.pauseRenderingAction();
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("Window.monitorModeChanged.0: success: "+success+", hadFocus "+hadFocus+", animPaused "+animatorPaused+
+ ", hidden "+hidden+", FS "+fullscreen+", FS-paused "+fullscreenPaused+
+ " @ "+Thread.currentThread().getName());
+ System.err.println("Window.monitorModeChanged.0: "+getScreen());
+ System.err.println("Window.monitorModeChanged.0: "+me);
+ }
+ WindowImpl.this.monitorModeChanged(me, success);
+
+ if( success && !fullscreen && !fullscreenPaused ) {
+ // Simply move/resize window to fit in virtual screen if required
+ final RectangleImmutable viewport = screen.getViewportInWindowUnits();
+ if( viewport.getWidth() > 0 && viewport.getHeight() > 0 ) { // failsafe
+ final RectangleImmutable rect = new Rectangle(getX(), getY(), getWidth(), getHeight());
+ final RectangleImmutable isect = viewport.intersection(rect);
+ if ( getHeight() > isect.getHeight() ||
+ getWidth() > isect.getWidth() ) {
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("Window.monitorModeChanged.1: Non-FS - Fit window "+rect+" into screen viewport "+viewport+
+ ", due to minimal intersection "+isect);
+ }
+ definePosition(viewport.getX(), viewport.getY()); // set pos for setVisible(..) or createNative(..) - reduce EDT roundtrip
+ setSize(viewport.getWidth(), viewport.getHeight(), true /* force */);
+ }
}
- DimensionImmutable screenSize = sm.getMonitorMode().getSurfaceSize().getResolution();
- if ( getHeight() > screenSize.getHeight() ||
- getWidth() > screenSize.getWidth() ) {
- setSize(screenSize.getWidth(), screenSize.getHeight());
+ } else if( fullscreenPaused ) {
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("Window.monitorModeChanged.2: FS Restore");
+ }
+ setFullscreenImpl(true, _fullscreenUseMainMonitor, _fullscreenMonitors);
+ fullscreenPaused = false;
+ _fullscreenMonitors = null;
+ _fullscreenUseMainMonitor = true;
+ } else if( success && fullscreen && null != fullscreenMonitors ) {
+ // If changed monitor is part of this fullscreen mode, reset size! (Bug 771)
+ final MonitorDevice md = me.getMonitor();
+ if( fullscreenMonitors.contains(md) ) {
+ final Rectangle viewportInWindowUnits = new Rectangle();
+ MonitorDevice.unionOfViewports(null, viewportInWindowUnits, fullscreenMonitors);
+ if(DEBUG_IMPLEMENTATION) {
+ final RectangleImmutable winBounds = WindowImpl.this.getBounds();
+ System.err.println("Window.monitorModeChanged.3: FS Monitor Match: Fit window "+winBounds+" into new viewport union "+viewportInWindowUnits+" [window], provoked by "+md);
+ }
+ definePosition(viewportInWindowUnits.getX(), viewportInWindowUnits.getY()); // set pos for setVisible(..) or createNative(..) - reduce EDT roundtrip
+ setSize(viewportInWindowUnits.getWidth(), viewportInWindowUnits.getHeight(), true /* force */);
}
}
-
+ if( hidden ) {
+ WindowImpl.this.setVisible(true);
+ hidden = false;
+ }
+ sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener
if(animatorPaused) {
lifecycleHook.resumeRenderingAction();
}
- sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener
+ if( hadFocus ) {
+ requestFocus(true);
+ }
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("Window.monitorModeChanged.X: @ "+Thread.currentThread().getName()+", this: "+WindowImpl.this);
+ }
}
}
- private final ScreenModeListenerImpl screenModeListenerImpl = new ScreenModeListenerImpl();
-
+ private final MonitorModeListenerImpl monitorModeListenerImpl = new MonitorModeListenerImpl();
//----------------------------------------------------------------------
// Child Window Management
- //
+ //
- public final boolean removeChild(NativeWindow win) {
+ @Override
+ public final boolean removeChild(final NativeWindow win) {
synchronized(childWindowsLock) {
return childWindows.remove(win);
}
}
- public final boolean addChild(NativeWindow win) {
+ @Override
+ public final boolean addChild(final NativeWindow win) {
if (win == null) {
return false;
}
@@ -1880,7 +2604,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
//----------------------------------------------------------------------
// Generic Event Support
//
- private void doEvent(boolean enqueue, boolean wait, com.jogamp.newt.event.NEWTEvent event) {
+ private void doEvent(final boolean enqueue, boolean wait, final com.jogamp.newt.event.NEWTEvent event) {
boolean done = false;
if(!enqueue) {
@@ -1893,13 +2617,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
- public void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) {
+ @Override
+ public final void enqueueEvent(final boolean wait, final com.jogamp.newt.event.NEWTEvent event) {
if(isNativeValid()) {
- ((DisplayImpl)getScreen().getDisplay()).enqueueEvent(wait, event);
+ ((DisplayImpl)screen.getDisplay()).enqueueEvent(wait, event);
}
}
- public boolean consumeEvent(NEWTEvent e) {
+ @Override
+ public final boolean consumeEvent(final NEWTEvent e) {
switch(e.getEventType()) {
// special repaint treatment
case WindowEvent.EVENT_WINDOW_REPAINT:
@@ -1910,9 +2636,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
repaintQueued=true;
final boolean discardTO = QUEUED_EVENT_TO <= System.currentTimeMillis()-e.getWhen();
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.consumeEvent: "+Thread.currentThread().getName()+" - queued "+e+", discard-to "+discardTO);
+ System.err.println("Window.consumeEvent: REPAINT "+Thread.currentThread().getName()+" - queued "+e+", discard-to "+discardTO);
// Thread.dumpStack();
- }
+ }
return discardTO; // discardTO:=true -> consumed
}
return true;
@@ -1926,7 +2652,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if( null != windowLock.getOwner() ) {
final boolean discardTO = QUEUED_EVENT_TO <= System.currentTimeMillis()-e.getWhen();
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.consumeEvent: "+Thread.currentThread().getName()+" - queued "+e+", discard-to "+discardTO);
+ System.err.println("Window.consumeEvent: RESIZED "+Thread.currentThread().getName()+" - queued "+e+", discard-to "+discardTO);
// Thread.dumpStack();
}
return discardTO; // discardTO:=true -> consumed
@@ -1940,7 +2666,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
} else if(e instanceof KeyEvent) {
consumeKeyEvent((KeyEvent)e);
} else if(e instanceof MouseEvent) {
- consumeMouseEvent((MouseEvent)e);
+ consumePointerEvent((MouseEvent)e);
} else {
throw new NativeWindowException("Unexpected NEWTEvent type " + e);
}
@@ -1948,189 +2674,736 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
//
- // SurfaceUpdatedListener Support
+ // MouseListener/Event Support
//
- public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
- surfaceUpdatedHelper.addSurfaceUpdatedListener(l);
- }
- public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
- surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l);
+ //
+ // Native MouseEvents pre-processed to be enqueued or consumed directly
+ //
+
+ public final void sendMouseEvent(final short eventType, final int modifiers,
+ final int x, final int y, final short button, final float rotation) {
+ doMouseEvent(false, false, eventType, modifiers, x, y, button, MouseEvent.getRotationXYZ(rotation, modifiers), 1f);
+ }
+ public final void enqueueMouseEvent(final boolean wait, final short eventType, final int modifiers,
+ final int x, final int y, final short button, final float rotation) {
+ doMouseEvent(true, wait, eventType, modifiers, x, y, button, MouseEvent.getRotationXYZ(rotation, modifiers), 1f);
+ }
+ protected final void doMouseEvent(final boolean enqueue, final boolean wait, final short eventType, final int modifiers,
+ final int x, final int y, final short button, final float rotation) {
+ doMouseEvent(enqueue, wait, eventType, modifiers, x, y, button, MouseEvent.getRotationXYZ(rotation, modifiers), 1f);
}
+ /**
+ public final void sendMouseEvent(final short eventType, final int modifiers,
+ final int x, final int y, final short button, final float[] rotationXYZ, final float rotationScale) {
+ doMouseEvent(false, false, eventType, modifiers, x, y, button, rotationXYZ, rotationScale);
+ }
+ public final void enqueueMouseEvent(final boolean wait, final short eventType, final int modifiers,
+ final int x, final int y, final short button, final float[] rotationXYZ, final float rotationScale) {
+ doMouseEvent(true, wait, eventType, modifiers, x, y, button, rotationXYZ, rotationScale);
+ } */
- public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
- surfaceUpdatedHelper.removeSurfaceUpdatedListener(l);
+ /**
+ * Send mouse event (one-pointer) either to be directly consumed or to be enqueued
+ *
+ * @param enqueue if true, event will be {@link #enqueueEvent(boolean, NEWTEvent) enqueued},
+ * otherwise {@link #consumeEvent(NEWTEvent) consumed} directly.
+ * @param wait if true wait until {@link #consumeEvent(NEWTEvent) consumed}.
+ */
+ protected void doMouseEvent(final boolean enqueue, final boolean wait, final short eventType, final int modifiers,
+ final int x, final int y, final short button, final float[] rotationXYZ, final float rotationScale) {
+ if( 0 > button || button > MouseEvent.BUTTON_COUNT ) {
+ throw new NativeWindowException("Invalid mouse button number" + button);
+ }
+ doPointerEvent(enqueue, wait, constMousePointerTypes, eventType, modifiers,
+ 0 /*actionIdx*/, new short[] { (short)0 }, button,
+ new int[]{x}, new int[]{y}, new float[]{0f} /*pressure*/,
+ 1f /*maxPressure*/, rotationXYZ, rotationScale);
}
- public void surfaceUpdated(Object updater, NativeSurface ns, long when) {
- surfaceUpdatedHelper.surfaceUpdated(updater, ns, when);
+ /**
+ * Send multiple-pointer event either to be directly consumed or to be enqueued
+ * <p>
+ * The index for the element of multiple-pointer arrays represents the pointer which triggered the event
+ * is passed via <i>actionIdx</i>.
+ * </p>
+ * <p>
+ * The given pointer names, <code>pNames</code>, are mapped to consecutive pointer IDs starting w/ 0
+ * using a hash-map if <code>normalPNames</code> is <code>false</code>.
+ * Otherwise a simple <code>int</code> to <code>short</code> type cast is performed.
+ * </p>
+ * <p>
+ * See {@link #doPointerEvent(boolean, boolean, PointerType[], short, int, int, short[], short, int[], int[], float[], float, float[], float)}
+ * for details!
+ * </p>
+ *
+ * @param enqueue if true, event will be {@link #enqueueEvent(boolean, NEWTEvent) enqueued},
+ * otherwise {@link #consumeEvent(NEWTEvent) consumed} directly.
+ * @param wait if true wait until {@link #consumeEvent(NEWTEvent) consumed}.
+ * @param pTypes {@link MouseEvent.PointerType} for each pointer (multiple pointer)
+ * @param eventType
+ * @param modifiers
+ * @param actionIdx index of multiple-pointer arrays representing the pointer which triggered the event
+ * @param normalPNames see pName below.
+ * @param pNames Pointer name for each pointer (multiple pointer).
+ * We assume consecutive pointer names starting w/ 0 if <code>normalPIDs</code> is <code>true</code>.
+ * Otherwise we hash-map the values during state pressed to retrieve the normal ID.
+ * @param pX X-axis for each pointer (multiple pointer)
+ * @param pY Y-axis for each pointer (multiple pointer)
+ * @param pPressure Pressure for each pointer (multiple pointer)
+ * @param maxPressure Maximum pointer pressure for all pointer
+ */
+ public final void doPointerEvent(final boolean enqueue, final boolean wait,
+ final PointerType[] pTypes, final short eventType, final int modifiers,
+ final int actionIdx, final boolean normalPNames, final int[] pNames,
+ final int[] pX, final int[] pY, final float[] pPressure,
+ final float maxPressure, final float[] rotationXYZ, final float rotationScale) {
+ final int pCount = pNames.length;
+ final short[] pIDs = new short[pCount];
+ for(int i=0; i<pCount; i++) {
+ if( !normalPNames ) {
+ // hash map int name -> short idx
+ final int sz0 = pName2pID.size();
+ final Integer pNameI1 = pName2pID.getOrAdd(Integer.valueOf(pNames[i]));
+ final short pID = (short)pName2pID.indexOf(pNameI1);
+ pIDs[i] = pID;
+ if(DEBUG_MOUSE_EVENT) {
+ final int sz1 = pName2pID.size();
+ if( sz0 != sz1 ) {
+ System.err.println("PointerName2ID[sz "+sz1+"]: Map "+pNameI1+" == "+pID);
+ }
+ }
+ if( MouseEvent.EVENT_MOUSE_RELEASED == eventType ) {
+ pName2pID.remove(pNameI1);
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("PointerName2ID[sz "+pName2pID.size()+"]: Unmap "+pNameI1+" == "+pID);
+ }
+ }
+ } else {
+ // simple type cast
+ pIDs[i] = (short)pNames[i];
+ }
+ }
+ final short button = 0 < pCount ? (short) ( pIDs[0] + 1 ) : (short)0;
+ doPointerEvent(enqueue, wait, pTypes, eventType, modifiers, actionIdx, pIDs, button,
+ pX, pY, pPressure, maxPressure, rotationXYZ, rotationScale);
}
- //
- // MouseListener/Event Support
- //
- public void sendMouseEvent(int eventType, int modifiers,
- int x, int y, int button, int rotation) {
- doMouseEvent(false, false, eventType, modifiers, x, y, button, rotation);
- }
- public void enqueueMouseEvent(boolean wait, int eventType, int modifiers,
- int x, int y, int button, int rotation) {
- doMouseEvent(true, wait, eventType, modifiers, x, y, button, rotation);
- }
-
- protected void doMouseEvent(boolean enqueue, boolean wait, int eventType, int modifiers,
- int x, int y, int button, int rotation) {
- if(eventType == MouseEvent.EVENT_MOUSE_ENTERED ||
- eventType == MouseEvent.EVENT_MOUSE_EXITED) {
- if(eventType == MouseEvent.EVENT_MOUSE_EXITED && x==-1 && y==-1) {
- x = lastMousePosition.getX();
- y = lastMousePosition.getY();
- }
- // clip coordinates to window dimension
- x = Math.min(Math.max(x, 0), getWidth()-1);
- y = Math.min(Math.max(y, 0), getHeight()-1);
- mouseInWindow = eventType == MouseEvent.EVENT_MOUSE_ENTERED;
- lastMousePressed=0; // clear state
- mouseButtonPressed=0; // clear state
- }
- if(x<0||y<0||x>=getWidth()||y>=getHeight()) {
+ /**
+ * Send multiple-pointer event either to be directly consumed or to be enqueued.
+ * <p>
+ * Pointer/Mouse Processing Pass 1 (Pass 2 is performed in {@link #consumePointerEvent(MouseEvent)}.
+ * </p>
+ * <p>
+ * Usually directly called by event source to enqueue and process event.
+ * </p>
+ * <p>
+ * The index for the element of multiple-pointer arrays represents the pointer which triggered the event
+ * is passed via <i>actionIdx</i>.
+ * </p>
+ * <p>
+ * <ul>
+ * <li>Determine ENTERED/EXITED state</li>
+ * <li>Remove redundant move/drag events</li>
+ * <li>Reset states if applicable</li>
+ * <li>Drop exterior events</li>
+ * <li>Determine CLICK COUNT</li>
+ * <li>Ignore sent CLICKED</li>
+ * <li>Track buttonPressed incl. buttonPressedMask</li>
+ * <li>Synthesize DRAGGED event (from MOVED if pointer is pressed)</li>
+ * </ul>
+ * </p>
+ *
+ * @param enqueue if true, event will be {@link #enqueueEvent(boolean, NEWTEvent) enqueued},
+ * otherwise {@link #consumeEvent(NEWTEvent) consumed} directly.
+ * @param wait if true wait until {@link #consumeEvent(NEWTEvent) consumed}.
+ * @param pTypes {@link MouseEvent.PointerType} for each pointer (multiple pointer)
+ * @param eventType
+ * @param modifiers
+ * @param pActionIdx index of multiple-pointer arrays representing the pointer which triggered the event
+ * @param pID Pointer ID for each pointer (multiple pointer). We assume consecutive pointerIDs starting w/ 0.
+ * @param button Corresponding mouse-button, a button of 0 denotes no activity, i.e. {@link PointerType#Mouse} move.
+ * @param pX X-axis for each pointer (multiple pointer)
+ * @param pY Y-axis for each pointer (multiple pointer)
+ * @param pPressure Pressure for each pointer (multiple pointer)
+ * @param maxPressure Maximum pointer pressure for all pointer
+ */
+ public final void doPointerEvent(final boolean enqueue, final boolean wait,
+ final PointerType[] pTypes, final short eventType, int modifiers,
+ final int pActionIdx, final short[] pID, final short buttonIn, final int[] pX, final int[] pY,
+ final float[] pPressure, final float maxPressure, final float[] rotationXYZ, final float rotationScale) {
+ final long when = System.currentTimeMillis();
+ final int pCount = pTypes.length;
+
+ if( 0 > pActionIdx || pActionIdx >= pCount) {
+ throw new IllegalArgumentException("actionIdx out of bounds [0.."+(pCount-1)+"]");
+ }
+ if( 0 < pActionIdx ) {
+ // swap values to make idx 0 the triggering pointer
+ {
+ final PointerType aType = pTypes[pActionIdx];
+ pTypes[pActionIdx] = pTypes[0];
+ pTypes[0] = aType;
+ }
+ {
+ final short s = pID[pActionIdx];
+ pID[pActionIdx] = pID[0];
+ pID[0] = s;
+ }
+ {
+ int s = pX[pActionIdx];
+ pX[pActionIdx] = pX[0];
+ pX[0] = s;
+ s = pY[pActionIdx];
+ pY[pActionIdx] = pY[0];
+ pY[0] = s;
+ }
+ {
+ final float aPress = pPressure[pActionIdx];
+ pPressure[pActionIdx] = pPressure[0];
+ pPressure[0] = aPress;
+ }
+ }
+ final short button;
+ {
+ // validate button
+ if( 0 <= buttonIn && buttonIn <= com.jogamp.newt.event.MouseEvent.BUTTON_COUNT ) { // we allow button==0 for no button, i.e. mouse-ptr move
+ button = buttonIn;
+ } else {
+ button = com.jogamp.newt.event.MouseEvent.BUTTON1;
+ }
+ }
+
+ //
+ // - Determine ENTERED/EXITED state
+ // - Remove redundant move/drag events
+ // - Reset states if applicable
+ //
+ int x = pX[0];
+ int y = pY[0];
+ final boolean insideSurface = x >= 0 && y >= 0 && x < getSurfaceWidth() && y < getSurfaceHeight();
+ final Point movePositionP0 = pState1.getMovePosition(pID[0]);
+ switch( eventType ) {
+ case MouseEvent.EVENT_MOUSE_EXITED:
+ if( pState1.dragging ) {
+ // Drop mouse EXIT if dragging, i.e. due to exterior dragging outside of window.
+ // NOTE-1: X11 produces the 'premature' EXIT, however it also produces 'EXIT' after exterior dragging!
+ // NOTE-2: consumePointerEvent(MouseEvent) will synthesize a missing EXIT event!
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("doPointerEvent: drop "+MouseEvent.getEventTypeString(eventType)+" due to dragging: "+pState1);
+ }
+ return;
+ }
+ if( null != movePositionP0 ) {
+ if( x==-1 && y==-1 ) {
+ x = movePositionP0.getX();
+ y = movePositionP0.getY();
+ }
+ movePositionP0.set(0, 0);
+ }
+ // Fall through intended!
+
+ case MouseEvent.EVENT_MOUSE_ENTERED:
+ if( eventType == MouseEvent.EVENT_MOUSE_ENTERED ) {
+ pState1.insideSurface = true;
+ pState1.exitSent = false;
+ } else {
+ pState1.insideSurface = false;
+ pState1.exitSent = true;
+ }
+ pState1.clearButton();
+ if( pTypes[0] != PointerType.Mouse ) {
+ // Drop !MOUSE ENTER/EXIT Events - Safeguard for non compliant implementations only.
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("doPointerEvent: drop "+MouseEvent.getEventTypeString(eventType)+" due to !Mouse but "+pTypes[0]+": "+pState1);
+ }
+ return;
+ }
+ // clip coordinates to window dimension
+ x = Math.min(Math.max(x, 0), getSurfaceWidth()-1);
+ y = Math.min(Math.max(y, 0), getSurfaceHeight()-1);
+ break;
+
+ case MouseEvent.EVENT_MOUSE_MOVED:
+ case MouseEvent.EVENT_MOUSE_DRAGGED:
+ if( null != movePositionP0 ) {
+ if( movePositionP0.getX() == x && movePositionP0.getY() == y ) {
+ // Drop same position
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("doPointerEvent: drop "+MouseEvent.getEventTypeString(eventType)+" w/ same position: "+movePositionP0+", "+pState1);
+ }
+ return;
+ }
+ movePositionP0.set(x, y);
+ }
+
+ // Fall through intended !
+
+ default:
+ if( pState1.insideSurface != insideSurface ) {
+ // ENTER/EXIT!
+ pState1.insideSurface = insideSurface;
+ if( insideSurface ) {
+ pState1.exitSent = false;
+ }
+ pState1.clearButton();
+ }
+ }
+
+ //
+ // Drop exterior events if not dragging pointer and not EXIT event
+ // Safeguard for non compliant implementations!
+ //
+ if( !pState1.dragging && !insideSurface && MouseEvent.EVENT_MOUSE_EXITED != eventType ) {
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("doPointerEvent: drop: "+MouseEvent.getEventTypeString(eventType)+
+ ", mod "+modifiers+", pos "+x+"/"+y+", button "+button+", lastMousePosition: "+movePositionP0+", insideWindow "+insideSurface+", "+pState1);
+ }
return; // .. invalid ..
}
if(DEBUG_MOUSE_EVENT) {
- System.err.println("doMouseEvent: enqueue "+enqueue+", wait "+wait+", "+MouseEvent.getEventTypeString(eventType)+
- ", mod "+modifiers+", pos "+x+"/"+y+", button "+button+", lastMousePosition: "+lastMousePosition);
- }
- long when = System.currentTimeMillis();
- MouseEvent eEntered = null;
- if(eventType == MouseEvent.EVENT_MOUSE_MOVED) {
- if(!mouseInWindow) {
- mouseInWindow = true;
- eEntered = new MouseEvent(MouseEvent.EVENT_MOUSE_ENTERED, this, when,
- modifiers, x, y, lastMouseClickCount, button, 0);
- lastMousePressed=0; // clear state
- mouseButtonPressed=0; // clear state
- } else if(lastMousePosition.getX() == x && lastMousePosition.getY()==y) {
+ System.err.println("doPointerEvent: enqueue "+enqueue+", wait "+wait+", "+MouseEvent.getEventTypeString(eventType)+
+ ", mod "+modifiers+", pos "+x+"/"+y+", button "+button+", lastMousePosition: "+movePositionP0+", "+pState1);
+ }
+
+ final int buttonMask = InputEvent.getButtonMask(button);
+ modifiers |= buttonMask; // Always add current button to modifier mask (Bug 571)
+ modifiers |= pState1.buttonPressedMask; // Always add currently pressed mouse buttons to modifier mask
+
+ if( isPointerConfined() ) {
+ modifiers |= InputEvent.CONFINED_MASK;
+ }
+ if( !isPointerVisible() ) {
+ modifiers |= InputEvent.INVISIBLE_MASK;
+ }
+
+ pX[0] = x;
+ pY[0] = y;
+
+ //
+ // - Determine CLICK COUNT
+ // - Ignore sent CLICKED
+ // - Track buttonPressed incl. buttonPressedMask
+ // - Synthesize DRAGGED event (from MOVED if pointer is pressed)
+ //
+ final MouseEvent e;
+ switch( eventType ) {
+ case MouseEvent.EVENT_MOUSE_CLICKED:
+ e = null;
+ break;
+
+ case MouseEvent.EVENT_MOUSE_PRESSED:
+ if( 0 >= pPressure[0] ) {
+ pPressure[0] = maxPressure;
+ }
+ pState1.buttonPressedMask |= buttonMask;
+ if( 1 == pCount ) {
+ if( when - pState1.lastButtonPressTime < MouseEvent.getClickTimeout() ) {
+ pState1.lastButtonClickCount++;
+ } else {
+ pState1.lastButtonClickCount=(short)1;
+ }
+ pState1.lastButtonPressTime = when;
+ pState1.buttonPressed = button;
+ e = new MouseEvent(eventType, this, when, modifiers, pTypes, pID,
+ pX, pY, pPressure, maxPressure, button, pState1.lastButtonClickCount, rotationXYZ, rotationScale);
+ } else {
+ e = new MouseEvent(eventType, this, when, modifiers, pTypes, pID,
+ pX, pY, pPressure, maxPressure, button, (short)1, rotationXYZ, rotationScale);
+ }
+ break;
+ case MouseEvent.EVENT_MOUSE_RELEASED:
+ pState1.buttonPressedMask &= ~buttonMask;
+ if( 1 == pCount ) {
+ e = new MouseEvent(eventType, this, when, modifiers, pTypes, pID,
+ pX, pY, pPressure, maxPressure, button, pState1.lastButtonClickCount, rotationXYZ, rotationScale);
+ if( when - pState1.lastButtonPressTime >= MouseEvent.getClickTimeout() ) {
+ pState1.lastButtonClickCount = (short)0;
+ pState1.lastButtonPressTime = 0;
+ }
+ pState1.buttonPressed = 0;
+ pState1.dragging = false;
+ } else {
+ e = new MouseEvent(eventType, this, when, modifiers, pTypes, pID,
+ pX, pY, pPressure, maxPressure, button, (short)1, rotationXYZ, rotationScale);
+ if( 0 == pState1.buttonPressedMask ) {
+ pState1.clearButton();
+ }
+ }
+ if( null != movePositionP0 ) {
+ movePositionP0.set(0, 0);
+ }
+ break;
+ case MouseEvent.EVENT_MOUSE_MOVED:
+ if ( 0 != pState1.buttonPressedMask ) { // any button or pointer move -> drag
+ e = new MouseEvent(MouseEvent.EVENT_MOUSE_DRAGGED, this, when, modifiers, pTypes, pID,
+ pX, pY, pPressure, maxPressure, pState1.buttonPressed, (short)1, rotationXYZ, rotationScale);
+ pState1.dragging = true;
+ } else {
+ e = new MouseEvent(eventType, this, when, modifiers, pTypes, pID,
+ pX, pY, pPressure, maxPressure, button, (short)0, rotationXYZ, rotationScale);
+ }
+ break;
+ case MouseEvent.EVENT_MOUSE_DRAGGED:
+ if( 0 >= pPressure[0] ) {
+ pPressure[0] = maxPressure;
+ }
+ pState1.dragging = true;
+ // Fall through intended!
+ default:
+ e = new MouseEvent(eventType, this, when, modifiers, pTypes, pID,
+ pX, pY, pPressure, maxPressure, button, (short)0, rotationXYZ, rotationScale);
+ }
+ doEvent(enqueue, wait, e); // actual mouse event
+ }
+
+ private static int step(final int lower, final int edge, final int value) {
+ return value < edge ? lower : value;
+ }
+
+ /**
+ * Consume the {@link MouseEvent}.
+ * <p>
+ * Pointer/Mouse Processing Pass 2 (Pass 1 is performed in {@link #doPointerEvent(boolean, boolean, PointerType[], short, int, int, short[], short, int[], int[], float[], float, float[], float)}).
+ * </p>
+ * <p>
+ * Invoked before dispatching the dequeued event.
+ * </p>
+ * <p>
+ * <ul>
+ * <li>Validate</li>
+ * <li>Handle gestures</li>
+ * <li>Synthesize events [ENTERED, EXIT, CLICK] and gestures.</li>
+ * <li>Drop exterior events</li>
+ * <li>Dispatch event to listener</li>
+ * </ul>
+ * </p>
+ */
+ protected void consumePointerEvent(MouseEvent pe) {
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("consumePointerEvent.in: "+pe+", "+pState0+", pos "+pe.getX()+"/"+pe.getY()+", win["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+
+ "], pixel["+getSurfaceWidth()+"x"+getSurfaceHeight()+"]");
+ }
+
+ //
+ // - Determine ENTERED/EXITED state
+ // - Synthesize ENTERED and EXIT event
+ // - Reset states if applicable
+ //
+ final long when = pe.getWhen();
+ final int eventType = pe.getEventType();
+ final boolean insideSurface;
+ boolean eExitAllowed = false;
+ MouseEvent eEntered = null, eExited = null;
+ switch( eventType ) {
+ case MouseEvent.EVENT_MOUSE_EXITED:
+ if( pState0.exitSent || pState0.dragging ) {
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("consumePointerEvent: drop "+(pState0.exitSent?"already sent":"due to dragging")+": "+pe+", "+pState0);
+ }
+ return;
+ }
+ // Fall through intended !
+ case MouseEvent.EVENT_MOUSE_ENTERED:
+ // clip coordinates to window dimension
+ // final int pe_x = Math.min(Math.max(pe.getX(), 0), getSurfaceWidth()-1);
+ // final int pe_y = Math.min(Math.max(pe.getY(), 0), getSurfaceHeight()-1);
+ pState0.clearButton();
+ if( eventType == MouseEvent.EVENT_MOUSE_ENTERED ) {
+ insideSurface = true;
+ pState0.insideSurface = true;
+ pState0.exitSent = false;
+ pState0.dragging = false;
+ } else {
+ insideSurface = false;
+ pState0.insideSurface = false;
+ pState0.exitSent = true;
+ }
+ break;
+
+ case MouseEvent.EVENT_MOUSE_MOVED:
+ case MouseEvent.EVENT_MOUSE_RELEASED:
+ if( 1 >= pe.getButtonDownCount() ) { // MOVE or RELEASE last button
+ eExitAllowed = !pState0.exitSent;
+ pState0.dragging = false;
+ }
+ // Fall through intended !
+
+ default:
+ final int pe_x = pe.getX();
+ final int pe_y = pe.getY();
+ insideSurface = pe_x >= 0 && pe_y >= 0 && pe_x < getSurfaceWidth() && pe_y < getSurfaceHeight();
+ if( pe.getPointerType(0) == PointerType.Mouse ) {
+ if( !pState0.insideSurface && insideSurface ) {
+ // ENTER .. use clipped coordinates
+ eEntered = new MouseEvent(MouseEvent.EVENT_MOUSE_ENTERED, pe.getSource(), pe.getWhen(), pe.getModifiers(),
+ Math.min(Math.max(pe_x, 0), getSurfaceWidth()-1),
+ Math.min(Math.max(pe_y, 0), getSurfaceHeight()-1),
+ (short)0, (short)0, pe.getRotation(), pe.getRotationScale());
+ pState0.exitSent = false;
+ } else if( !insideSurface && eExitAllowed ) {
+ // EXIT .. use clipped coordinates
+ eExited = new MouseEvent(MouseEvent.EVENT_MOUSE_EXITED, pe.getSource(), pe.getWhen(), pe.getModifiers(),
+ Math.min(Math.max(pe_x, 0), getSurfaceWidth()-1),
+ Math.min(Math.max(pe_y, 0), getSurfaceHeight()-1),
+ (short)0, (short)0, pe.getRotation(), pe.getRotationScale());
+ pState0.exitSent = true;
+ }
+ }
+ if( pState0.insideSurface != insideSurface || null != eEntered || null != eExited) {
+ pState0.clearButton();
+ }
+ pState0.insideSurface = insideSurface;
+ }
+ if( null != eEntered ) {
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("consumePointerEvent.send.0: "+eEntered+", "+pState0);
+ }
+ dispatchMouseEvent(eEntered);
+ } else if( DEBUG_MOUSE_EVENT && !insideSurface ) {
+ System.err.println("INFO consumePointerEvent.exterior: "+pState0+", "+pe);
+ }
+
+ //
+ // Handle Default Gestures
+ //
+ if( defaultGestureHandlerEnabled &&
+ pe.getPointerType(0).getPointerClass() == MouseEvent.PointerClass.Onscreen )
+ {
+ if( null == gesture2PtrTouchScroll ) {
+ final int scaledScrollSlop;
+ final int scaledDoubleTapSlop;
+ final MonitorDevice monitor = getMainMonitor();
+ if ( null != monitor ) {
+ final DimensionImmutable mm = monitor.getSizeMM();
+ final float pixWPerMM = (float)monitor.getCurrentMode().getRotatedWidth() / (float)mm.getWidth();
+ final float pixHPerMM = (float)monitor.getCurrentMode().getRotatedHeight() / (float)mm.getHeight();
+ final float pixPerMM = Math.min(pixHPerMM, pixWPerMM);
+ scaledScrollSlop = Math.round(DoubleTapScrollGesture.SCROLL_SLOP_MM * pixPerMM);
+ scaledDoubleTapSlop = Math.round(DoubleTapScrollGesture.DOUBLE_TAP_SLOP_MM * pixPerMM);
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("consumePointerEvent.gscroll: scrollSlop "+scaledScrollSlop+", doubleTapSlop "+scaledDoubleTapSlop+", pixPerMM "+pixPerMM+", "+monitor+", "+pState0);
+ }
+ } else {
+ scaledScrollSlop = DoubleTapScrollGesture.SCROLL_SLOP_PIXEL;
+ scaledDoubleTapSlop = DoubleTapScrollGesture.DOUBLE_TAP_SLOP_PIXEL;
+ }
+ gesture2PtrTouchScroll = new DoubleTapScrollGesture(step(DoubleTapScrollGesture.SCROLL_SLOP_PIXEL, DoubleTapScrollGesture.SCROLL_SLOP_PIXEL/2, scaledScrollSlop),
+ step(DoubleTapScrollGesture.DOUBLE_TAP_SLOP_PIXEL, DoubleTapScrollGesture.DOUBLE_TAP_SLOP_PIXEL/2, scaledDoubleTapSlop));
+ }
+ if( gesture2PtrTouchScroll.process(pe) ) {
+ pe = (MouseEvent) gesture2PtrTouchScroll.getGestureEvent();
+ gesture2PtrTouchScroll.clear(false);
if(DEBUG_MOUSE_EVENT) {
- System.err.println("doMouseEvent: skip EVENT_MOUSE_MOVED w/ same position: "+lastMousePosition);
+ System.err.println("consumePointerEvent.gscroll: "+pe+", "+pState0);
+ }
+ dispatchMouseEvent(pe);
+ return;
+ }
+ if( gesture2PtrTouchScroll.isWithinGesture() ) {
+ return; // within gesture .. need more input ..
+ }
+ }
+ //
+ // Handle Custom Gestures
+ //
+ {
+ final int pointerGestureHandlerCount = pointerGestureHandler.size();
+ if( pointerGestureHandlerCount > 0 ) {
+ boolean withinGesture = false;
+ for(int i = 0; !pe.isConsumed() && i < pointerGestureHandlerCount; i++ ) {
+ final GestureHandler gh = pointerGestureHandler.get(i);
+ if( gh.process(pe) ) {
+ final InputEvent ieG = gh.getGestureEvent();
+ gh.clear(false);
+ if( ieG instanceof MouseEvent ) {
+ dispatchMouseEvent((MouseEvent)ieG);
+ } else if( ieG instanceof GestureHandler.GestureEvent) {
+ final GestureHandler.GestureEvent ge = (GestureHandler.GestureEvent) ieG;
+ for(int j = 0; !ge.isConsumed() && j < gestureListeners.size(); j++ ) {
+ gestureListeners.get(j).gestureDetected(ge);
+ }
+ }
+ return;
+ }
+ withinGesture |= gh.isWithinGesture();
+ }
+ if( withinGesture ) {
+ return;
}
- return; // skip same position
}
- lastMousePosition.setX(x);
- lastMousePosition.setY(y);
- }
- if( 0 > button || button > MouseEvent.BUTTON_NUMBER ) {
- throw new NativeWindowException("Invalid mouse button number" + button);
}
- // Fixes Bug 571: X11 behavior, where the PRESSED button is not included in the native mask.
- modifiers |= InputEvent.getButtonMask(button);
+ //
+ // - Synthesize mouse CLICKED
+ // - Ignore sent CLICKED
+ //
MouseEvent eClicked = null;
- MouseEvent e = null;
+ switch( eventType ) {
+ case MouseEvent.EVENT_MOUSE_PRESSED:
+ if( 1 == pe.getPointerCount() ) {
+ pState0.lastButtonPressTime = when;
+ }
+ break;
+ case MouseEvent.EVENT_MOUSE_RELEASED:
+ if( 1 == pe.getPointerCount() && when - pState0.lastButtonPressTime < MouseEvent.getClickTimeout() ) {
+ eClicked = pe.createVariant(MouseEvent.EVENT_MOUSE_CLICKED);
+ } else {
+ pState0.lastButtonPressTime = 0;
+ }
+ break;
+ case MouseEvent.EVENT_MOUSE_CLICKED:
+ // ignore - synthesized here ..
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("consumePointerEvent: drop recv'ed (synth here) "+pe+", "+pState0);
+ }
+ pe = null;
+ break;
- if(isPointerConfined()) {
- modifiers |= InputEvent.CONFINED_MASK;
- }
- if(!isPointerVisible()) {
- modifiers |= InputEvent.INVISIBLE_MASK;
+ case MouseEvent.EVENT_MOUSE_DRAGGED:
+ pState0.dragging = true;
+ break;
}
-
- if(MouseEvent.EVENT_MOUSE_PRESSED==eventType) {
- if(when-lastMousePressed<MouseEvent.getClickTimeout()) {
- lastMouseClickCount++;
- } else {
- lastMouseClickCount=1;
- }
- lastMousePressed=when;
- mouseButtonPressed=button;
- e = new MouseEvent(eventType, this, when,
- modifiers, x, y, lastMouseClickCount, button, 0);
- } else if(MouseEvent.EVENT_MOUSE_RELEASED==eventType) {
- e = new MouseEvent(eventType, this, when,
- modifiers, x, y, lastMouseClickCount, button, 0);
- if(when-lastMousePressed<MouseEvent.getClickTimeout()) {
- eClicked = new MouseEvent(MouseEvent.EVENT_MOUSE_CLICKED, this, when,
- modifiers, x, y, lastMouseClickCount, button, 0);
- } else {
- lastMouseClickCount=0;
- lastMousePressed=0;
- }
- mouseButtonPressed=0;
- } else if(MouseEvent.EVENT_MOUSE_MOVED==eventType) {
- if (mouseButtonPressed>0) {
- e = new MouseEvent(MouseEvent.EVENT_MOUSE_DRAGGED, this, when,
- modifiers, x, y, 1, mouseButtonPressed, 0);
- } else {
- e = new MouseEvent(eventType, this, when,
- modifiers, x, y, 0, button, 0);
+
+ if( null != pe ) {
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("consumePointerEvent.send.1: "+pe+", "+pState0);
}
- } else if(MouseEvent.EVENT_MOUSE_WHEEL_MOVED==eventType) {
- e = new MouseEvent(eventType, this, when, modifiers, x, y, 0, button, rotation);
- } else {
- e = new MouseEvent(eventType, this, when, modifiers, x, y, 0, button, 0);
+ dispatchMouseEvent(pe); // actual mouse event
}
- if(null!=eEntered) {
+ if( null != eClicked ) {
if(DEBUG_MOUSE_EVENT) {
- System.err.println("doMouseEvent: synthesized MOUSE_ENTERED event: "+eEntered);
+ System.err.println("consumePointerEvent.send.2: "+eClicked+", "+pState0);
}
- doEvent(enqueue, wait, eEntered);
+ dispatchMouseEvent(eClicked);
}
- doEvent(enqueue, wait, e); // actual mouse event
- if(null!=eClicked) {
+ if( null != eExited ) {
if(DEBUG_MOUSE_EVENT) {
- System.err.println("doMouseEvent: synthesized MOUSE_CLICKED event: "+eClicked);
+ System.err.println("consumePointerEvent.send.3: "+eExited+", "+pState0);
}
- doEvent(enqueue, wait, eClicked);
+ dispatchMouseEvent(eExited);
}
}
-
- public void addMouseListener(MouseListener l) {
+ @Override
+ public final void addMouseListener(final MouseListener l) {
addMouseListener(-1, l);
}
- public void addMouseListener(int index, MouseListener l) {
+ @Override
+ public final void addMouseListener(int index, final MouseListener l) {
if(l == null) {
return;
}
@SuppressWarnings("unchecked")
+ final
ArrayList<MouseListener> clonedListeners = (ArrayList<MouseListener>) mouseListeners.clone();
- if(0>index) {
- index = clonedListeners.size();
+ if(0>index) {
+ index = clonedListeners.size();
}
clonedListeners.add(index, l);
mouseListeners = clonedListeners;
}
- public void removeMouseListener(MouseListener l) {
+ @Override
+ public final void removeMouseListener(final MouseListener l) {
if (l == null) {
return;
}
@SuppressWarnings("unchecked")
+ final
ArrayList<MouseListener> clonedListeners = (ArrayList<MouseListener>) mouseListeners.clone();
clonedListeners.remove(l);
mouseListeners = clonedListeners;
}
- public MouseListener getMouseListener(int index) {
+ @Override
+ public final MouseListener getMouseListener(int index) {
@SuppressWarnings("unchecked")
+ final
ArrayList<MouseListener> clonedListeners = (ArrayList<MouseListener>) mouseListeners.clone();
- if(0>index) {
- index = clonedListeners.size()-1;
+ if(0>index) {
+ index = clonedListeners.size()-1;
}
return clonedListeners.get(index);
}
- public MouseListener[] getMouseListeners() {
+ @Override
+ public final MouseListener[] getMouseListeners() {
return mouseListeners.toArray(new MouseListener[mouseListeners.size()]);
}
- protected void consumeMouseEvent(MouseEvent e) {
- if(DEBUG_MOUSE_EVENT) {
- System.err.println("consumeMouseEvent: event: "+e);
+ @Override
+ public final void setDefaultGesturesEnabled(final boolean enable) {
+ defaultGestureHandlerEnabled = enable;
+ }
+ @Override
+ public final boolean areDefaultGesturesEnabled() {
+ return defaultGestureHandlerEnabled;
+ }
+
+ @Override
+ public final void addGestureHandler(final GestureHandler gh) {
+ addGestureHandler(-1, gh);
+ }
+ @Override
+ public final void addGestureHandler(int index, final GestureHandler gh) {
+ if(gh == null) {
+ return;
+ }
+ @SuppressWarnings("unchecked")
+ final
+ ArrayList<GestureHandler> cloned = (ArrayList<GestureHandler>) pointerGestureHandler.clone();
+ if(0>index) {
+ index = cloned.size();
+ }
+ cloned.add(index, gh);
+ pointerGestureHandler = cloned;
+ }
+ @Override
+ public final void removeGestureHandler(final GestureHandler gh) {
+ if (gh == null) {
+ return;
+ }
+ @SuppressWarnings("unchecked")
+ final
+ ArrayList<GestureHandler> cloned = (ArrayList<GestureHandler>) pointerGestureHandler.clone();
+ cloned.remove(gh);
+ pointerGestureHandler = cloned;
+ }
+ @Override
+ public final void addGestureListener(final GestureHandler.GestureListener gl) {
+ addGestureListener(-1, gl);
+ }
+ @Override
+ public final void addGestureListener(int index, final GestureHandler.GestureListener gl) {
+ if(gl == null) {
+ return;
+ }
+ @SuppressWarnings("unchecked")
+ final
+ ArrayList<GestureHandler.GestureListener> cloned = (ArrayList<GestureHandler.GestureListener>) gestureListeners.clone();
+ if(0>index) {
+ index = cloned.size();
}
- boolean consumed = false;
- for(int i = 0; !consumed && i < mouseListeners.size(); i++ ) {
- MouseListener l = mouseListeners.get(i);
+ cloned.add(index, gl);
+ gestureListeners = cloned;
+ }
+ @Override
+ public final void removeGestureListener(final GestureHandler.GestureListener gl) {
+ if (gl == null) {
+ return;
+ }
+ @SuppressWarnings("unchecked")
+ final
+ ArrayList<GestureHandler.GestureListener> cloned = (ArrayList<GestureHandler.GestureListener>) gestureListeners.clone();
+ cloned.remove(gl);
+ gestureListeners= cloned;
+ }
+
+ private final void dispatchMouseEvent(final MouseEvent e) {
+ for(int i = 0; !e.isConsumed() && i < mouseListeners.size(); i++ ) {
+ final MouseListener l = mouseListeners.get(i);
switch(e.getEventType()) {
case MouseEvent.EVENT_MOUSE_CLICKED:
l.mouseClicked(e);
@@ -2159,46 +3432,83 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
default:
throw new NativeWindowException("Unexpected mouse event type " + e.getEventType());
}
- consumed = InputEvent.consumedTag == e.getAttachment();
}
}
//
// KeyListener/Event Support
//
- public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) {
- consumeKeyEvent(new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) );
+ private static final int keyTrackingRange = 255;
+ private final IntBitfield keyPressedState = new IntBitfield( keyTrackingRange + 1 );
+
+ protected final boolean isKeyCodeTracked(final short keyCode) {
+ return ( 0xFFFF & keyCode ) <= keyTrackingRange;
}
- public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) {
- enqueueEvent(wait, new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) );
+ /**
+ * @param keyCode the keyCode to set pressed state
+ * @param pressed true if pressed, otherwise false
+ * @return the previus pressed value
+ */
+ protected final boolean setKeyPressed(final short keyCode, final boolean pressed) {
+ final int v = 0xFFFF & keyCode;
+ if( v <= keyTrackingRange ) {
+ return keyPressedState.put(v, pressed);
+ }
+ return false;
+ }
+ /**
+ * @param keyCode the keyCode to test pressed state
+ * @return true if pressed, otherwise false
+ */
+ protected final boolean isKeyPressed(final short keyCode) {
+ final int v = 0xFFFF & keyCode;
+ if( v <= keyTrackingRange ) {
+ return keyPressedState.get(v);
+ }
+ return false;
}
- public void addKeyListener(KeyListener l) {
- addKeyListener(-1, l);
+ public void sendKeyEvent(final short eventType, final int modifiers, final short keyCode, final short keySym, final char keyChar) {
+ // Always add currently pressed mouse buttons to modifier mask
+ consumeKeyEvent( KeyEvent.create(eventType, this, System.currentTimeMillis(), modifiers | pState1.buttonPressedMask, keyCode, keySym, keyChar) );
+ }
+
+ public void enqueueKeyEvent(final boolean wait, final short eventType, final int modifiers, final short keyCode, final short keySym, final char keyChar) {
+ // Always add currently pressed mouse buttons to modifier mask
+ enqueueEvent(wait, KeyEvent.create(eventType, this, System.currentTimeMillis(), modifiers | pState1.buttonPressedMask, keyCode, keySym, keyChar) );
}
- public final void setKeyboardVisible(boolean visible) {
+ @Override
+ public final void setKeyboardVisible(final boolean visible) {
if(isNativeValid()) {
// We don't skip the impl. if it seems that there is no state change,
- // since we cannot assume the impl. reliably gives us it's current state.
- final boolean n = setKeyboardVisibleImpl(visible);
+ // since we cannot assume the impl. reliably gives us it's current state.
+ final boolean ok = setKeyboardVisibleImpl(visible);
if(DEBUG_IMPLEMENTATION || DEBUG_KEY_EVENT) {
- System.err.println("setKeyboardVisible(native): visible "+keyboardVisible+" -> "+visible +" -> "+n);
+ System.err.println("setKeyboardVisible(native): visible "+keyboardVisible+" -- op[visible:"+visible +", ok "+ok+"] -> "+(visible && ok));
}
- keyboardVisible = n;
+ keyboardVisibilityChanged( visible && ok );
} else {
- keyboardVisible = visible; // earmark for creation
+ keyboardVisibilityChanged( visible ); // earmark for creation
}
}
+ @Override
public final boolean isKeyboardVisible() {
return keyboardVisible;
- }
- protected boolean setKeyboardVisibleImpl(boolean visible) {
+ }
+ /**
+ * Returns <code>true</code> if operation was successful, otherwise <code>false</code>.
+ * <p>
+ * We assume that a failed invisible operation is due to an already invisible keyboard,
+ * hence even if an invisible operation failed, the keyboard is considered invisible!
+ * </p>
+ */
+ protected boolean setKeyboardVisibleImpl(final boolean visible) {
return false; // nop
}
/** Triggered by implementation's WM events to update the virtual on-screen keyboard's visibility state. */
- protected void keyboardVisibilityChanged(boolean visible) {
+ protected void keyboardVisibilityChanged(final boolean visible) {
if(keyboardVisible != visible) {
if(DEBUG_IMPLEMENTATION || DEBUG_KEY_EVENT) {
System.err.println("keyboardVisibilityChanged: "+keyboardVisible+" -> "+visible);
@@ -2207,44 +3517,56 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
protected boolean keyboardVisible = false;
-
- public void addKeyListener(int index, KeyListener l) {
+
+ @Override
+ public final void addKeyListener(final KeyListener l) {
+ addKeyListener(-1, l);
+ }
+
+ @Override
+ public final void addKeyListener(int index, final KeyListener l) {
if(l == null) {
return;
}
@SuppressWarnings("unchecked")
+ final
ArrayList<KeyListener> clonedListeners = (ArrayList<KeyListener>) keyListeners.clone();
- if(0>index) {
+ if(0>index) {
index = clonedListeners.size();
}
clonedListeners.add(index, l);
keyListeners = clonedListeners;
}
- public void removeKeyListener(KeyListener l) {
+ @Override
+ public final void removeKeyListener(final KeyListener l) {
if (l == null) {
return;
}
@SuppressWarnings("unchecked")
+ final
ArrayList<KeyListener> clonedListeners = (ArrayList<KeyListener>) keyListeners.clone();
clonedListeners.remove(l);
keyListeners = clonedListeners;
}
- public KeyListener getKeyListener(int index) {
+ @Override
+ public final KeyListener getKeyListener(int index) {
@SuppressWarnings("unchecked")
+ final
ArrayList<KeyListener> clonedListeners = (ArrayList<KeyListener>) keyListeners.clone();
- if(0>index) {
+ if(0>index) {
index = clonedListeners.size()-1;
}
return clonedListeners.get(index);
}
- public KeyListener[] getKeyListeners() {
+ @Override
+ public final KeyListener[] getKeyListeners() {
return keyListeners.toArray(new KeyListener[keyListeners.size()]);
}
- private final boolean propagateKeyEvent(KeyEvent e, KeyListener l) {
+ private final boolean propagateKeyEvent(final KeyEvent e, final KeyListener l) {
switch(e.getEventType()) {
case KeyEvent.EVENT_KEY_PRESSED:
l.keyPressed(e);
@@ -2252,92 +3574,101 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
case KeyEvent.EVENT_KEY_RELEASED:
l.keyReleased(e);
break;
- case KeyEvent.EVENT_KEY_TYPED:
- l.keyTyped(e);
- break;
default:
throw new NativeWindowException("Unexpected key event type " + e.getEventType());
}
- return InputEvent.consumedTag == e.getAttachment();
+ return e.isConsumed();
}
-
- protected void consumeKeyEvent(KeyEvent e) {
- boolean consumed;
- if(null != keyboardFocusHandler) {
- consumed = propagateKeyEvent(e, keyboardFocusHandler);
+
+ protected void consumeKeyEvent(final KeyEvent e) {
+ boolean consumedE = false;
+ if( null != keyboardFocusHandler && !e.isAutoRepeat() ) {
+ consumedE = propagateKeyEvent(e, keyboardFocusHandler);
if(DEBUG_KEY_EVENT) {
- System.err.println("consumeKeyEvent: "+e+", keyboardFocusHandler consumed: "+consumed);
+ if( consumedE ) {
+ System.err.println("consumeKeyEvent(kfh): "+e+", consumed: "+consumedE);
+ }
+ }
+ }
+ if( !consumedE ) {
+ for(int i = 0; !consumedE && i < keyListeners.size(); i++ ) {
+ consumedE = propagateKeyEvent(e, keyListeners.get(i));
}
- } else {
- consumed = false;
if(DEBUG_KEY_EVENT) {
- System.err.println("consumeKeyEvent: "+e);
+ System.err.println("consumeKeyEvent(usr): "+e+", consumed: "+consumedE);
}
}
- for(int i = 0; !consumed && i < keyListeners.size(); i++ ) {
- consumed = propagateKeyEvent(e, keyListeners.get(i));
- }
}
//
// WindowListener/Event Support
//
- public void sendWindowEvent(int eventType) {
- consumeWindowEvent( new WindowEvent(eventType, this, System.currentTimeMillis()) );
+ @Override
+ public final void sendWindowEvent(final int eventType) {
+ consumeWindowEvent( new WindowEvent((short)eventType, this, System.currentTimeMillis()) );
}
- public void enqueueWindowEvent(boolean wait, int eventType) {
- enqueueEvent( wait, new WindowEvent(eventType, this, System.currentTimeMillis()) );
+ public final void enqueueWindowEvent(final boolean wait, final int eventType) {
+ enqueueEvent( wait, new WindowEvent((short)eventType, this, System.currentTimeMillis()) );
}
- public void addWindowListener(WindowListener l) {
+ @Override
+ public final void addWindowListener(final WindowListener l) {
addWindowListener(-1, l);
}
- public void addWindowListener(int index, WindowListener l)
+ @Override
+ public final void addWindowListener(int index, final WindowListener l)
throws IndexOutOfBoundsException
{
if(l == null) {
return;
}
@SuppressWarnings("unchecked")
+ final
ArrayList<WindowListener> clonedListeners = (ArrayList<WindowListener>) windowListeners.clone();
- if(0>index) {
- index = clonedListeners.size();
+ if(0>index) {
+ index = clonedListeners.size();
}
clonedListeners.add(index, l);
windowListeners = clonedListeners;
}
- public final void removeWindowListener(WindowListener l) {
+ @Override
+ public final void removeWindowListener(final WindowListener l) {
if (l == null) {
return;
}
@SuppressWarnings("unchecked")
+ final
ArrayList<WindowListener> clonedListeners = (ArrayList<WindowListener>) windowListeners.clone();
clonedListeners.remove(l);
windowListeners = clonedListeners;
}
- public WindowListener getWindowListener(int index) {
+ @Override
+ public final WindowListener getWindowListener(int index) {
@SuppressWarnings("unchecked")
+ final
ArrayList<WindowListener> clonedListeners = (ArrayList<WindowListener>) windowListeners.clone();
- if(0>index) {
- index = clonedListeners.size()-1;
+ if(0>index) {
+ index = clonedListeners.size()-1;
}
return clonedListeners.get(index);
}
- public WindowListener[] getWindowListeners() {
+ @Override
+ public final WindowListener[] getWindowListeners() {
return windowListeners.toArray(new WindowListener[windowListeners.size()]);
}
- protected void consumeWindowEvent(WindowEvent e) {
+ protected void consumeWindowEvent(final WindowEvent e) {
if(DEBUG_IMPLEMENTATION) {
- System.err.println("consumeWindowEvent: "+e+", visible "+isVisible()+" "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight());
+ System.err.println("consumeWindowEvent: "+e+", visible "+isVisible()+" "+getX()+"/"+getY()+", win["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+
+ "], pixel["+getSurfaceWidth()+"x"+getSurfaceHeight()+"]");
}
- for(int i = 0; i < windowListeners.size(); i++ ) {
- WindowListener l = windowListeners.get(i);
+ for(int i = 0; !e.isConsumed() && i < windowListeners.size(); i++ ) {
+ final WindowListener l = windowListeners.get(i);
switch(e.getEventType()) {
case WindowEvent.EVENT_WINDOW_RESIZED:
l.windowResized(e);
@@ -2361,7 +3692,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
l.windowRepaint((WindowUpdateEvent)e);
break;
default:
- throw
+ throw
new NativeWindowException("Unexpected window event type "
+ e.getEventType());
}
@@ -2369,13 +3700,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
/** Triggered by implementation's WM events to update the focus state. */
- protected void focusChanged(boolean defer, boolean focusGained) {
+ protected void focusChanged(final boolean defer, final boolean focusGained) {
if(brokenFocusChange || hasFocus != focusGained) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.focusChanged: ("+getThreadName()+"): (defer: "+defer+") "+this.hasFocus+" -> "+focusGained+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle));
}
hasFocus = focusGained;
- final int evt = focusGained ? WindowEvent.EVENT_WINDOW_GAINED_FOCUS : WindowEvent.EVENT_WINDOW_LOST_FOCUS ;
+ final int evt = focusGained ? WindowEvent.EVENT_WINDOW_GAINED_FOCUS : WindowEvent.EVENT_WINDOW_LOST_FOCUS ;
if(!defer) {
sendWindowEvent(evt);
} else {
@@ -2383,9 +3714,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
}
-
+
/** Triggered by implementation's WM events to update the visibility state. */
- protected void visibleChanged(boolean defer, boolean visible) {
+ protected final void visibleChanged(final boolean defer, final boolean visible) {
if(this.visible != visible) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.visibleChanged ("+getThreadName()+"): (defer: "+defer+") "+this.visible+" -> "+visible+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle));
@@ -2394,32 +3725,43 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
- private boolean waitForVisible(boolean visible, boolean failFast) {
+ /** Returns -1 if failed, otherwise remaining time until {@link #TIMEOUT_NATIVEWINDOW}, maybe zero. */
+ private long waitForVisible(final boolean visible, final boolean failFast) {
return waitForVisible(visible, failFast, TIMEOUT_NATIVEWINDOW);
}
- private boolean waitForVisible(boolean visible, boolean failFast, long timeOut) {
- DisplayImpl display = (DisplayImpl) screen.getDisplay();
- for(long sleep = timeOut; 0<sleep && this.visible != visible; sleep-=10 ) {
+ /** Returns -1 if failed, otherwise remaining time until <code>timeOut</code>, maybe zero. */
+ private long waitForVisible(final boolean visible, final boolean failFast, final long timeOut) {
+ final DisplayImpl display = (DisplayImpl) screen.getDisplay();
+ display.dispatchMessagesNative(); // status up2date
+ long remaining;
+ for(remaining = timeOut; 0<remaining && this.visible != visible; remaining-=10 ) {
+ try { Thread.sleep(10); } catch (final InterruptedException ie) {}
display.dispatchMessagesNative(); // status up2date
- try { Thread.sleep(10); } catch (InterruptedException ie) {}
}
if(this.visible != visible) {
- final String msg = "Visibility not reached as requested within "+timeOut+"ms : requested "+visible+", is "+this.visible;
+ final String msg = "Visibility not reached as requested within "+timeOut+"ms : requested "+visible+", is "+this.visible;
if(failFast) {
throw new NativeWindowException(msg);
} else if (DEBUG_IMPLEMENTATION) {
System.err.println(msg);
+ Thread.dumpStack();
}
+ return -1;
+ } else if( 0 < remaining ){
+ return remaining;
+ } else {
+ return 0;
}
- return this.visible == visible;
}
- /** Triggered by implementation's WM events to update the client-area size w/o insets/decorations. */
- protected void sizeChanged(boolean defer, int newWidth, int newHeight, boolean force) {
+ /** Triggered by implementation's WM events to update the client-area size in window units w/o insets/decorations. */
+ protected void sizeChanged(final boolean defer, final int newWidth, final int newHeight, final boolean force) {
if(force || getWidth() != newWidth || getHeight() != newHeight) {
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.sizeChanged: ("+getThreadName()+"): (defer: "+defer+") force "+force+", "+getWidth()+"x"+getHeight()+" -> "+newWidth+"x"+newHeight+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle));
+ System.err.println("Window.sizeChanged: ("+getThreadName()+"): (defer: "+defer+") force "+force+", "+
+ getWidth()+"x"+getHeight()+" -> "+newWidth+"x"+newHeight+
+ " - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle));
}
if(0>newWidth || 0>newHeight) {
throw new NativeWindowException("Illegal width or height "+newWidth+"x"+newHeight+" (must be >= 0)");
@@ -2434,20 +3776,16 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
}
-
- private boolean waitForSize(int w, int h, boolean failFast, long timeOut) {
- DisplayImpl display = (DisplayImpl) screen.getDisplay();
- boolean reached = false;
- for(long sleep = timeOut; !reached && 0<sleep; sleep-=10 ) {
- if( w==getWidth() && h==getHeight() ) {
- // reached pos/size
- reached = true;
- } else {
- display.dispatchMessagesNative(); // status up2date
- try { Thread.sleep(10); } catch (InterruptedException ie) {}
- }
+
+ private boolean waitForSize(final int w, final int h, final boolean failFast, final long timeOut) {
+ final DisplayImpl display = (DisplayImpl) screen.getDisplay();
+ display.dispatchMessagesNative(); // status up2date
+ long sleep;
+ for(sleep = timeOut; 0<sleep && w!=getWidth() && h!=getHeight(); sleep-=10 ) {
+ try { Thread.sleep(10); } catch (final InterruptedException ie) {}
+ display.dispatchMessagesNative(); // status up2date
}
- if(!reached) {
+ if(0 >= sleep) {
final String msg = "Size/Pos not reached as requested within "+timeOut+"ms : requested "+w+"x"+h+", is "+getWidth()+"x"+getHeight();
if(failFast) {
throw new NativeWindowException(msg);
@@ -2455,12 +3793,14 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
System.err.println(msg);
Thread.dumpStack();
}
+ return false;
+ } else {
+ return true;
}
- return reached;
}
-
- /** Triggered by implementation's WM events to update the position. */
- protected void positionChanged(boolean defer, int newX, int newY) {
+
+ /** Triggered by implementation's WM events to update the position. */
+ protected final void positionChanged(final boolean defer, final int newX, final int newY) {
if ( getX() != newX || getY() != newY ) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.positionChanged: ("+getThreadName()+"): (defer: "+defer+") "+getX()+"/"+getY()+" -> "+newX+"/"+newY+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle));
@@ -2472,82 +3812,146 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_MOVED);
}
} else {
- autoPosition = false; // ensure it's off even w/ same position
+ autoPosition = false; // ensure it's off even w/ same position
+ }
+ }
+
+ /**
+ * Wait until position is reached within tolerances, either auto-position or custom position.
+ * <p>
+ * Since WM may not obey our positional request exactly, we allow a tolerance of 2 times insets[left/top], or 64 pixels, whatever is greater.
+ * </p>
+ */
+ private boolean waitForPosition(final boolean useCustomPosition, final int x, final int y, final long timeOut) {
+ final DisplayImpl display = (DisplayImpl) screen.getDisplay();
+ final int maxDX, maxDY;
+ {
+ final InsetsImmutable insets = getInsets();
+ maxDX = Math.max(64, insets.getLeftWidth() * 2);
+ maxDY = Math.max(64, insets.getTopHeight() * 2);
+ }
+ long remaining = timeOut;
+ boolean ok;
+ do {
+ if( useCustomPosition ) {
+ ok = Math.abs(x - getX()) <= maxDX && Math.abs(y - getY()) <= maxDY ;
+ } else {
+ ok = !autoPosition;
+ }
+ if( !ok ) {
+ try { Thread.sleep(10); } catch (final InterruptedException ie) {}
+ display.dispatchMessagesNative(); // status up2date
+ remaining-=10;
+ }
+ } while ( 0<remaining && !ok );
+ if (DEBUG_IMPLEMENTATION) {
+ if( !ok ) {
+ if( useCustomPosition ) {
+ System.err.println("Custom position "+x+"/"+y+" not reached within timeout, has "+getX()+"/"+getY()+", remaining "+remaining);
+ } else {
+ System.err.println("Auto position not reached within timeout, has "+getX()+"/"+getY()+", autoPosition "+autoPosition+", remaining "+remaining);
+ }
+ Thread.dumpStack();
+ }
}
+ return ok;
}
/**
- * Triggered by implementation's WM events to update the insets.
- *
+ * Triggered by implementation's WM events to update the insets.
+ *
* @see #getInsets()
* @see #updateInsetsImpl(Insets)
*/
- protected void insetsChanged(boolean defer, int left, int right, int top, int bottom) {
+ protected void insetsChanged(final boolean defer, final int left, final int right, final int top, final int bottom) {
if ( left >= 0 && right >= 0 && top >= 0 && bottom >= 0 ) {
- if(isUndecorated()) {
+ if( blockInsetsChange || isUndecorated() ) {
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.insetsChanged: skip insets change for undecoration mode");
+ System.err.println("Window.insetsChanged (defer: "+defer+"): Skip insets change "+insets+" -> "+new Insets(left, right, top, bottom)+" (blocked "+blockInsetsChange+", undecoration "+isUndecorated()+")");
}
- } else if ( (left != insets.getLeftWidth() || right != insets.getRightWidth() ||
+ } else if ( (left != insets.getLeftWidth() || right != insets.getRightWidth() ||
top != insets.getTopHeight() || bottom != insets.getBottomHeight() )
) {
- insets.setLeftWidth(left);
- insets.setRightWidth(right);
- insets.setTopHeight(top);
- insets.setBottomHeight(bottom);
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.insetsChanged: (defer: "+defer+") "+insets);
+ System.err.println("Window.insetsChanged (defer: "+defer+"): Changed "+insets+" -> "+new Insets(left, right, top, bottom));
}
+ insets.set(left, right, top, bottom);
}
}
}
-
+
/**
- * Triggered by implementation's WM events or programmatically
- *
+ * Triggered by implementation's WM events or programmatic while respecting {@link #getDefaultCloseOperation()}.
+ *
* @param force if true, overrides {@link #setDefaultCloseOperation(WindowClosingMode)} with {@link WindowClosingProtocol#DISPOSE_ON_CLOSE}
* and hence force destruction. Otherwise is follows the user settings.
* @return true if this window is no more valid and hence has been destroyed, otherwise false.
*/
- protected boolean windowDestroyNotify(boolean force) {
+ public final boolean windowDestroyNotify(final boolean force) {
+ final WindowClosingMode defMode = getDefaultCloseOperation();
+ final WindowClosingMode mode = force ? WindowClosingMode.DISPOSE_ON_CLOSE : defMode;
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.windowDestroyNotify(force: "+force+") START "+getThreadName()+": "+this);
- }
- if(force) {
- setDefaultCloseOperation(WindowClosingMode.DISPOSE_ON_CLOSE);
+ System.err.println("Window.windowDestroyNotify(isNativeValid: "+isNativeValid()+", force: "+force+", mode "+defMode+" -> "+mode+") "+getThreadName()+": "+this);
+ // Thread.dumpStack();
}
- // send synced destroy notifications
- enqueueWindowEvent(true, WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY);
+ final boolean destroyed;
- if(handleDestroyNotify && WindowClosingMode.DISPOSE_ON_CLOSE == getDefaultCloseOperation()) {
- destroy();
+ if( isNativeValid() ) {
+ if( WindowClosingMode.DISPOSE_ON_CLOSE == mode ) {
+ if(force) {
+ setDefaultCloseOperation(mode);
+ }
+ try {
+ if( null == windowDestroyNotifyAction ) {
+ destroy();
+ } else {
+ windowDestroyNotifyAction.run();
+ }
+ } finally {
+ if(force) {
+ setDefaultCloseOperation(defMode);
+ }
+ }
+ } else {
+ // send synced destroy notifications
+ sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY);
+ }
+
+ destroyed = !isNativeValid();
+ } else {
+ destroyed = true;
}
-
- final boolean destroyed = !isNativeValid();
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window.windowDestroyNotify(force: "+force+") END "+getThreadName()+": destroyed "+destroyed+", "+this);
+ System.err.println("Window.windowDestroyNotify(isNativeValid: "+isNativeValid()+", force: "+force+", mode "+mode+") END "+getThreadName()+": destroyed "+destroyed+", "+this);
}
+
return destroyed;
}
- public void windowRepaint(int x, int y, int width, int height) {
- windowRepaint(false, x, y, width, height);
+ @Override
+ public final void windowRepaint(final int x, final int y, final int width, final int height) {
+ windowRepaint(false, x, y, width, height);
}
-
+
/**
* Triggered by implementation's WM events to update the content
- */
- protected void windowRepaint(boolean defer, int x, int y, int width, int height) {
- width = ( 0 >= width ) ? getWidth() : width;
- height = ( 0 >= height ) ? getHeight() : height;
+ * @param defer if true sent event later, otherwise wait until processed.
+ * @param x dirty-region y-pos in pixel units
+ * @param y dirty-region x-pos in pixel units
+ * @param width dirty-region width in pixel units
+ * @param height dirty-region height in pixel units
+ */
+ protected final void windowRepaint(final boolean defer, final int x, final int y, int width, int height) {
+ width = ( 0 >= width ) ? getSurfaceWidth() : width;
+ height = ( 0 >= height ) ? getSurfaceHeight() : height;
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.windowRepaint "+getThreadName()+" (defer: "+defer+") "+x+"/"+y+" "+width+"x"+height);
}
if(isNativeValid()) {
- NEWTEvent e = new WindowUpdateEvent(WindowEvent.EVENT_WINDOW_REPAINT, this, System.currentTimeMillis(),
+ final NEWTEvent e = new WindowUpdateEvent(WindowEvent.EVENT_WINDOW_REPAINT, this, System.currentTimeMillis(),
new Rectangle(x, y, width, height));
doEvent(defer, false, e);
}
@@ -2557,16 +3961,16 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
// Reflection helper ..
//
- private static Class<?>[] getCustomConstructorArgumentTypes(Class<?> windowClass) {
+ private static Class<?>[] getCustomConstructorArgumentTypes(final Class<?> windowClass) {
Class<?>[] argTypes = null;
try {
- Method m = windowClass.getDeclaredMethod("getCustomConstructorArgumentTypes");
+ final Method m = windowClass.getDeclaredMethod("getCustomConstructorArgumentTypes");
argTypes = (Class[]) m.invoke(null, (Object[])null);
- } catch (Throwable t) {}
+ } catch (final Throwable t) {}
return argTypes;
}
- private static int verifyConstructorArgumentTypes(Class<?>[] types, Object[] args) {
+ private static int verifyConstructorArgumentTypes(final Class<?>[] types, final Object[] args) {
if(types.length != args.length) {
return -1;
}
@@ -2578,8 +3982,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
return args.length;
}
- private static String getArgsStrList(Object[] args) {
- StringBuilder sb = new StringBuilder();
+ private static String getArgsStrList(final Object[] args) {
+ final StringBuilder sb = new StringBuilder();
for(int i=0; i<args.length; i++) {
sb.append(args[i].getClass());
if(i<args.length) {
@@ -2589,8 +3993,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
return sb.toString();
}
- private static String getTypeStrList(Class<?>[] types) {
- StringBuilder sb = new StringBuilder();
+ private static String getTypeStrList(final Class<?>[] types) {
+ final StringBuilder sb = new StringBuilder();
for(int i=0; i<types.length; i++) {
sb.append(types[i]);
if(i<types.length) {
@@ -2600,19 +4004,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
return sb.toString();
}
- protected final void shouldNotCallThis() {
- throw new NativeWindowException("Should not call this");
- }
-
public static String getThreadName() {
return Display.getThreadName();
}
- public static String toHexString(int hex) {
+ public static String toHexString(final int hex) {
return Display.toHexString(hex);
}
- public static String toHexString(long hex) {
+ public static String toHexString(final long hex) {
return Display.toHexString(hex);
}
}
diff --git a/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java
index 861a6d6be..682313ef4 100644
--- a/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java
+++ b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,12 +20,12 @@
* 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.awt;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
@@ -55,7 +55,7 @@ public class NewtFactoryAWT extends NewtFactory {
*
* @param awtCompObject must be of type java.awt.Component
*/
- public static JAWTWindow getNativeWindow(Object awtCompObject, CapabilitiesImmutable capsRequested) {
+ public static JAWTWindow getNativeWindow(final Object awtCompObject, final CapabilitiesImmutable capsRequested) {
if(null==awtCompObject) {
throw new NativeWindowException("Null AWT Component");
}
@@ -65,9 +65,9 @@ public class NewtFactoryAWT extends NewtFactory {
return getNativeWindow( (java.awt.Component) awtCompObject, capsRequested );
}
- public static JAWTWindow getNativeWindow(java.awt.Component awtComp, CapabilitiesImmutable capsRequested) {
- AWTGraphicsConfiguration config = AWTGraphicsConfiguration.create(awtComp, null, capsRequested);
- NativeWindow nw = NativeWindowFactory.getNativeWindow(awtComp, config); // a JAWTWindow
+ public static JAWTWindow getNativeWindow(final java.awt.Component awtComp, final CapabilitiesImmutable capsRequested) {
+ final AWTGraphicsConfiguration config = AWTGraphicsConfiguration.create(awtComp, null, capsRequested);
+ final NativeWindow nw = NativeWindowFactory.getNativeWindow(awtComp, config); // a JAWTWindow
if(! ( nw instanceof JAWTWindow ) ) {
throw new NativeWindowException("Not an AWT NativeWindow: "+nw);
}
@@ -76,12 +76,12 @@ public class NewtFactoryAWT extends NewtFactory {
}
return (JAWTWindow)nw;
}
-
- public static void destroyNativeWindow(JAWTWindow jawtWindow) {
+
+ public static void destroyNativeWindow(final JAWTWindow jawtWindow) {
final AbstractGraphicsConfiguration config = jawtWindow.getGraphicsConfiguration();
jawtWindow.destroy();
- config.getScreen().getDevice().close();
+ config.getScreen().getDevice().close();
}
-
+
}
diff --git a/src/newt/classes/jogamp/newt/awt/event/AWTNewtEventFactory.java b/src/newt/classes/jogamp/newt/awt/event/AWTNewtEventFactory.java
index cb70da13f..31ee92ca4 100644
--- a/src/newt/classes/jogamp/newt/awt/event/AWTNewtEventFactory.java
+++ b/src/newt/classes/jogamp/newt/awt/event/AWTNewtEventFactory.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,138 +20,653 @@
* 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.awt.event;
-import com.jogamp.common.util.IntIntHashMap;
-import com.jogamp.newt.event.InputEvent;
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeSurfaceHolder;
+
+import com.jogamp.newt.event.MouseEvent;
+/**
+ *
+ * <a name="AWTEventModifierMapping"><h5>AWT Event Modifier Mapping</h5></a>
+ * <pre>
+ Modifier AWT Constant AWT Bit AWT Ex NEWT Constant NEWT Bit
+ ------------- ------------------------------- ------- ------ ------------------------- --------
+ Shift Event.SHIFT_MASK 0
+ Ctrl Event.CTRL_MASK 1
+ Meta Event.META_MASK 2
+ Alt Event.ALT_MASK 3
+ Button1 InputEvent.BUTTON1_MASK 4
+ Button2 InputEvent.BUTTON2_MASK 3
+ Button3 InputEvent.BUTTON3_MASK 2
+ Shift Down InputEvent.SHIFT_DOWN_MASK 6 * InputEvent.SHIFT_MASK 0
+ Ctrl Down InputEvent.CTRL_DOWN_MASK 7 * InputEvent.CTRL_MASK 1
+ Meta Down InputEvent.META_DOWN_MASK 8 * InputEvent.META_MASK 2
+ Alt Down InputEvent.ALT_DOWN_MASK 9 * InputEvent.ALT_MASK 3
+ Button1 Down InputEvent.BUTTON1_DOWN_MASK 10 * InputEvent.BUTTON1_MASK 5
+ Button2 Down InputEvent.BUTTON2_DOWN_MASK 11 * InputEvent.BUTTON2_MASK 6
+ Button3 Down InputEvent.BUTTON3_DOWN_MASK 12 * InputEvent.BUTTON3_MASK 7
+ AltGraph Down InputEvent.ALT_GRAPH_DOWN_MASK 13 * InputEvent.ALT_GRAPH_MASK 4
+ Button4 Down -- 14 * InputEvent.BUTTON4_MASK 8
+ Button5 Down -- 15 * InputEvent.BUTTON5_MASK 9
+ Button6 Down -- 16 * InputEvent.BUTTON6_MASK 10
+ Button7 Down -- 17 * InputEvent.BUTTON7_MASK 11
+ Button8 Down -- 18 * InputEvent.BUTTON8_MASK 12
+ Button9 Down -- 19 * InputEvent.BUTTON9_MASK 13
+ Button10 Down -- 20 * 14
+ Button11 Down -- 21 * 15
+ Button12 Down -- 22 * 16
+ Button13 Down -- 23 * 17
+ Button14 Down -- 24 * 18
+ Button15 Down -- 25 * 19
+ Button16 Down -- 26 * InputEvent.BUTTONLAST_MASK 20
+ Button17 Down -- 27 *
+ Button18 Down -- 28 *
+ Button19 Down -- 29 *
+ Button20 Down -- 30 *
+ Autorepeat -- - InputEvent.AUTOREPEAT_MASK 29
+ Confined -- - InputEvent.CONFINED_MASK 30
+ Invisible -- - InputEvent.INVISIBLE_MASK 31
+ * </pre>
+ *
+ */
public class AWTNewtEventFactory {
- protected static final IntIntHashMap eventTypeAWT2NEWT;
+ /** zero-based AWT button mask array filled by {@link #getAWTButtonDownMask(int)}, allowing fast lookup. */
+ private static int awtButtonDownMasks[] ;
static {
- IntIntHashMap map = new IntIntHashMap();
- map.setKeyNotFoundValue(0xFFFFFFFF);
- // n/a map.put(java.awt.event.WindowEvent.WINDOW_OPENED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_OPENED);
- map.put(java.awt.event.WindowEvent.WINDOW_CLOSING, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY);
- map.put(java.awt.event.WindowEvent.WINDOW_CLOSED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_DESTROYED);
- // n/a map.put(java.awt.event.WindowEvent.WINDOW_ICONIFIED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_ICONIFIED);
- // n/a map.put(java.awt.event.WindowEvent.WINDOW_DEICONIFIED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_DEICONIFIED);
- map.put(java.awt.event.WindowEvent.WINDOW_ACTIVATED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS);
- map.put(java.awt.event.WindowEvent.WINDOW_GAINED_FOCUS, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS);
- map.put(java.awt.event.FocusEvent.FOCUS_GAINED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS);
- map.put(java.awt.event.WindowEvent.WINDOW_DEACTIVATED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_LOST_FOCUS);
- map.put(java.awt.event.WindowEvent.WINDOW_LOST_FOCUS, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_LOST_FOCUS);
- map.put(java.awt.event.FocusEvent.FOCUS_LOST, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_LOST_FOCUS);
- // n/a map.put(java.awt.event.WindowEvent.WINDOW_STATE_CHANGED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_STATE_CHANGED);
-
- map.put(java.awt.event.ComponentEvent.COMPONENT_MOVED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_MOVED);
- map.put(java.awt.event.ComponentEvent.COMPONENT_RESIZED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_RESIZED);
- // n/a map.put(java.awt.event.ComponentEvent.COMPONENT_SHOWN, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_SHOWN);
- // n/a map.put(java.awt.event.ComponentEvent.COMPONENT_HIDDEN, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_HIDDEN);
-
- map.put(java.awt.event.MouseEvent.MOUSE_CLICKED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED);
- map.put(java.awt.event.MouseEvent.MOUSE_PRESSED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED);
- map.put(java.awt.event.MouseEvent.MOUSE_RELEASED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED);
- map.put(java.awt.event.MouseEvent.MOUSE_MOVED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_MOVED);
- map.put(java.awt.event.MouseEvent.MOUSE_ENTERED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_ENTERED);
- map.put(java.awt.event.MouseEvent.MOUSE_EXITED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_EXITED);
- map.put(java.awt.event.MouseEvent.MOUSE_DRAGGED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED);
- map.put(java.awt.event.MouseEvent.MOUSE_WHEEL, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_WHEEL_MOVED);
-
- map.put(java.awt.event.KeyEvent.KEY_PRESSED, com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED);
- map.put(java.awt.event.KeyEvent.KEY_RELEASED, com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED);
- map.put(java.awt.event.KeyEvent.KEY_TYPED, com.jogamp.newt.event.KeyEvent.EVENT_KEY_TYPED);
-
- eventTypeAWT2NEWT = map;
+ // There is an assumption in awtModifiers2Newt(int,int,boolean)
+ // that the awtButtonMasks and newtButtonMasks are peers, i.e.
+ // a given index refers to the same button in each array.
+
+ /* {
+ Method _getMaskForButtonMethod = null;
+ try {
+ _getMaskForButtonMethod = ReflectionUtil.getMethod(java.awt.event.InputEvent.class, "getMaskForButton", int.class);
+ } catch(Throwable t) {}
+ getMaskForButtonMethod = _getMaskForButtonMethod;
+ } */
+
+ awtButtonDownMasks = new int[com.jogamp.newt.event.MouseEvent.BUTTON_COUNT] ; // java.awt.MouseInfo.getNumberOfButtons() ;
+ for (int n = 0 ; n < awtButtonDownMasks.length ; ++n) {
+ awtButtonDownMasks[n] = getAWTButtonDownMaskImpl(n+1);
+ }
+ }
+
+ public static final short eventTypeAWT2NEWT(final int awtType) {
+ switch( awtType ) {
+ // n/a case java.awt.event.WindowEvent.WINDOW_OPENED: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_OPENED;
+ case java.awt.event.WindowEvent.WINDOW_CLOSING: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY;
+ case java.awt.event.WindowEvent.WINDOW_CLOSED: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_DESTROYED;
+ // n/a case java.awt.event.WindowEvent.WINDOW_ICONIFIED: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_ICONIFIED;
+ // n/a case java.awt.event.WindowEvent.WINDOW_DEICONIFIED: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_DEICONIFIED;
+ case java.awt.event.WindowEvent.WINDOW_ACTIVATED: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS;
+ case java.awt.event.WindowEvent.WINDOW_GAINED_FOCUS: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS;
+ case java.awt.event.FocusEvent.FOCUS_GAINED: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS;
+ case java.awt.event.WindowEvent.WINDOW_DEACTIVATED: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_LOST_FOCUS;
+ case java.awt.event.WindowEvent.WINDOW_LOST_FOCUS: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_LOST_FOCUS;
+ case java.awt.event.FocusEvent.FOCUS_LOST: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_LOST_FOCUS;
+ // n/a case java.awt.event.WindowEvent.WINDOW_STATE_CHANGED: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_STATE_CHANGED;
+
+ case java.awt.event.ComponentEvent.COMPONENT_MOVED: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_MOVED;
+ case java.awt.event.ComponentEvent.COMPONENT_RESIZED: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_RESIZED;
+ // n/a case java.awt.event.ComponentEvent.COMPONENT_SHOWN: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_SHOWN;
+ // n/a case java.awt.event.ComponentEvent.COMPONENT_HIDDEN: return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_HIDDEN;
+
+ case java.awt.event.MouseEvent.MOUSE_CLICKED: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED;
+ case java.awt.event.MouseEvent.MOUSE_PRESSED: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED;
+ case java.awt.event.MouseEvent.MOUSE_RELEASED: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED;
+ case java.awt.event.MouseEvent.MOUSE_MOVED: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_MOVED;
+ case java.awt.event.MouseEvent.MOUSE_ENTERED: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_ENTERED;
+ case java.awt.event.MouseEvent.MOUSE_EXITED: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_EXITED;
+ case java.awt.event.MouseEvent.MOUSE_DRAGGED: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED;
+ case java.awt.event.MouseEvent.MOUSE_WHEEL: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_WHEEL_MOVED;
+
+ case java.awt.event.KeyEvent.KEY_PRESSED: return com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED;
+ case java.awt.event.KeyEvent.KEY_RELEASED: return com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED;
+ }
+ return (short)0;
+ }
+
+ private static int getAWTButtonDownMaskImpl(final int button) {
+ /**
+ * java.awt.event.InputEvent.getMaskForButton(button);
+ *
+ if(null != getMaskForButtonMethod) {
+ Object r=null;
+ try {
+ r = getMaskForButtonMethod.invoke(null, new Integer(button));
+ } catch (Throwable t) { }
+ if(null != r) {
+ return ((Integer)r).intValue();
+ }
+ } */
+ final int m;
+ switch(button) {
+ case 0 : m = 0; break;
+ case 1 : m = java.awt.event.InputEvent.BUTTON1_DOWN_MASK; break; // 1<<10
+ case 2 : m = java.awt.event.InputEvent.BUTTON2_DOWN_MASK; break; // 1<<11
+ case 3 : m = java.awt.event.InputEvent.BUTTON3_DOWN_MASK; break; // 1<<12
+ default:
+ if( button <= com.jogamp.newt.event.MouseEvent.BUTTON_COUNT ) {
+ m = 1 << ( 10 + button ) ; // b4 = 1<<14, b5 = 1<<15, etc
+ } else {
+ m = 0;
+ }
+ }
+ return m;
+ }
+
+ /**
+ * <p>
+ * See <a href="#AWTEventModifierMapping"> AWT event modifier mapping details</a>.
+ * </p>
+ *
+ * @param button
+ * @return
+ */
+ public static int getAWTButtonDownMask(final int button) {
+ if( 0 < button && button <= awtButtonDownMasks.length ) {
+ return awtButtonDownMasks[button-1];
+ } else {
+ return 0;
+ }
+ }
+
+ public static final short awtButton2Newt(final int awtButton) {
+ if( 0 < awtButton && awtButton <= com.jogamp.newt.event.MouseEvent.BUTTON_COUNT ) {
+ return (short)awtButton;
+ } else {
+ return (short)0;
+ }
}
- public static final int awtModifiers2Newt(int awtMods, boolean mouseHint) {
+ /**
+ * Converts the specified set of AWT event modifiers and extended event
+ * modifiers to the equivalent NEWT event modifiers.
+ *
+ * <p>
+ * See <a href="#AWTEventModifierMapping"> AWT event modifier mapping details</a>.
+ * </p>
+ *
+ * @param awtMods
+ * The AWT event modifiers.
+ *
+ * @param awtModsEx
+ * The AWT extended event modifiers.
+ * AWT passes mouse button specific bits here and are the preferred way check the mouse button state.
+ */
+ public static final int awtModifiers2Newt(final int awtMods, final int awtModsEx) {
int newtMods = 0;
+
+ /** Redundant old modifiers ..
if ((awtMods & java.awt.event.InputEvent.SHIFT_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.SHIFT_MASK;
if ((awtMods & java.awt.event.InputEvent.CTRL_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.CTRL_MASK;
if ((awtMods & java.awt.event.InputEvent.META_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.META_MASK;
if ((awtMods & java.awt.event.InputEvent.ALT_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.ALT_MASK;
- if ((awtMods & java.awt.event.InputEvent.ALT_GRAPH_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.ALT_GRAPH_MASK;
+ if ((awtMods & java.awt.event.InputEvent.ALT_GRAPH_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.ALT_GRAPH_MASK; */
+
+ if ((awtModsEx & java.awt.event.InputEvent.SHIFT_DOWN_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.SHIFT_MASK;
+ if ((awtModsEx & java.awt.event.InputEvent.CTRL_DOWN_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.CTRL_MASK;
+ if ((awtModsEx & java.awt.event.InputEvent.META_DOWN_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.META_MASK;
+ if ((awtModsEx & java.awt.event.InputEvent.ALT_DOWN_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.ALT_MASK;
+ if ((awtModsEx & java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.ALT_GRAPH_MASK;
+
+ // The BUTTON1_MASK, BUTTON2_MASK, and BUTTON3_MASK bits are
+ // being ignored intentionally. The AWT docs say that the
+ // BUTTON1_DOWN_MASK etc bits in the extended modifiers are
+ // the preferred place to check current button state.
+
+ if( 0 != awtModsEx ) {
+ for (int n = 0 ; n < awtButtonDownMasks.length ; ++n) {
+ if ( (awtModsEx & awtButtonDownMasks[n]) != 0 ) {
+ newtMods |= com.jogamp.newt.event.InputEvent.getButtonMask(n+1);
+ }
+ }
+ }
+
return newtMods;
}
- public static final int awtButton2Newt(int awtButton) {
- switch (awtButton) {
- case java.awt.event.MouseEvent.BUTTON1: return com.jogamp.newt.event.MouseEvent.BUTTON1;
- case java.awt.event.MouseEvent.BUTTON2: return com.jogamp.newt.event.MouseEvent.BUTTON2;
- case java.awt.event.MouseEvent.BUTTON3: return com.jogamp.newt.event.MouseEvent.BUTTON3;
+ public static short awtKeyCode2NewtKeyCode(final int awtKeyCode) {
+ final short defNEWTKeyCode = (short)awtKeyCode;
+ switch (awtKeyCode) {
+ case java.awt.event.KeyEvent.VK_HOME : return com.jogamp.newt.event.KeyEvent.VK_HOME;
+ case java.awt.event.KeyEvent.VK_END : return com.jogamp.newt.event.KeyEvent.VK_END;
+ case java.awt.event.KeyEvent.VK_FINAL : return com.jogamp.newt.event.KeyEvent.VK_FINAL;
+ case java.awt.event.KeyEvent.VK_PRINTSCREEN : return com.jogamp.newt.event.KeyEvent.VK_PRINTSCREEN;
+ case java.awt.event.KeyEvent.VK_BACK_SPACE : return com.jogamp.newt.event.KeyEvent.VK_BACK_SPACE;
+ case java.awt.event.KeyEvent.VK_TAB : return com.jogamp.newt.event.KeyEvent.VK_TAB;
+ case java.awt.event.KeyEvent.VK_ENTER : return com.jogamp.newt.event.KeyEvent.VK_ENTER;
+ case java.awt.event.KeyEvent.VK_PAGE_DOWN : return com.jogamp.newt.event.KeyEvent.VK_PAGE_DOWN;
+ case java.awt.event.KeyEvent.VK_CLEAR : return com.jogamp.newt.event.KeyEvent.VK_CLEAR;
+ case java.awt.event.KeyEvent.VK_SHIFT : return com.jogamp.newt.event.KeyEvent.VK_SHIFT;
+ case java.awt.event.KeyEvent.VK_PAGE_UP : return com.jogamp.newt.event.KeyEvent.VK_PAGE_UP;
+ case java.awt.event.KeyEvent.VK_CONTROL : return com.jogamp.newt.event.KeyEvent.VK_CONTROL;
+ case java.awt.event.KeyEvent.VK_ALT : return com.jogamp.newt.event.KeyEvent.VK_ALT;
+ case java.awt.event.KeyEvent.VK_ALT_GRAPH : return com.jogamp.newt.event.KeyEvent.VK_ALT_GRAPH;
+ case java.awt.event.KeyEvent.VK_CAPS_LOCK : return com.jogamp.newt.event.KeyEvent.VK_CAPS_LOCK;
+ case java.awt.event.KeyEvent.VK_PAUSE : return com.jogamp.newt.event.KeyEvent.VK_PAUSE;
+ case java.awt.event.KeyEvent.VK_SCROLL_LOCK : return com.jogamp.newt.event.KeyEvent.VK_SCROLL_LOCK;
+ case java.awt.event.KeyEvent.VK_CANCEL : return com.jogamp.newt.event.KeyEvent.VK_CANCEL;
+ case java.awt.event.KeyEvent.VK_INSERT : return com.jogamp.newt.event.KeyEvent.VK_INSERT;
+ case java.awt.event.KeyEvent.VK_ESCAPE : return com.jogamp.newt.event.KeyEvent.VK_ESCAPE;
+ case java.awt.event.KeyEvent.VK_CONVERT : return com.jogamp.newt.event.KeyEvent.VK_CONVERT;
+ case java.awt.event.KeyEvent.VK_NONCONVERT : return com.jogamp.newt.event.KeyEvent.VK_NONCONVERT;
+ case java.awt.event.KeyEvent.VK_ACCEPT : return com.jogamp.newt.event.KeyEvent.VK_ACCEPT;
+ case java.awt.event.KeyEvent.VK_MODECHANGE : return com.jogamp.newt.event.KeyEvent.VK_MODECHANGE;
+ case java.awt.event.KeyEvent.VK_SPACE : return com.jogamp.newt.event.KeyEvent.VK_SPACE;
+ case java.awt.event.KeyEvent.VK_EXCLAMATION_MARK: return com.jogamp.newt.event.KeyEvent.VK_EXCLAMATION_MARK;
+ case java.awt.event.KeyEvent.VK_QUOTEDBL : return com.jogamp.newt.event.KeyEvent.VK_QUOTEDBL;
+ case java.awt.event.KeyEvent.VK_NUMBER_SIGN : return com.jogamp.newt.event.KeyEvent.VK_NUMBER_SIGN;
+ case java.awt.event.KeyEvent.VK_DOLLAR : return com.jogamp.newt.event.KeyEvent.VK_DOLLAR;
+ // case 0x25 : return com.jogamp.newt.event.KeyEvent.VK_PERCENT;
+ case java.awt.event.KeyEvent.VK_AMPERSAND : return com.jogamp.newt.event.KeyEvent.VK_AMPERSAND;
+ case java.awt.event.KeyEvent.VK_QUOTE : return com.jogamp.newt.event.KeyEvent.VK_QUOTE;
+ case java.awt.event.KeyEvent.VK_LEFT_PARENTHESIS : return com.jogamp.newt.event.KeyEvent.VK_LEFT_PARENTHESIS;
+ case java.awt.event.KeyEvent.VK_RIGHT_PARENTHESIS: return com.jogamp.newt.event.KeyEvent.VK_RIGHT_PARENTHESIS;
+ case java.awt.event.KeyEvent.VK_ASTERISK : return com.jogamp.newt.event.KeyEvent.VK_ASTERISK;
+ case java.awt.event.KeyEvent.VK_PLUS : return com.jogamp.newt.event.KeyEvent.VK_PLUS;
+ case java.awt.event.KeyEvent.VK_COMMA : return com.jogamp.newt.event.KeyEvent.VK_COMMA;
+ case java.awt.event.KeyEvent.VK_MINUS : return com.jogamp.newt.event.KeyEvent.VK_MINUS;
+ case java.awt.event.KeyEvent.VK_PERIOD : return com.jogamp.newt.event.KeyEvent.VK_PERIOD;
+ case java.awt.event.KeyEvent.VK_SLASH : return com.jogamp.newt.event.KeyEvent.VK_SLASH;
+ case java.awt.event.KeyEvent.VK_0 : return com.jogamp.newt.event.KeyEvent.VK_0;
+ case java.awt.event.KeyEvent.VK_1 : return com.jogamp.newt.event.KeyEvent.VK_1;
+ case java.awt.event.KeyEvent.VK_2 : return com.jogamp.newt.event.KeyEvent.VK_2;
+ case java.awt.event.KeyEvent.VK_3 : return com.jogamp.newt.event.KeyEvent.VK_3;
+ case java.awt.event.KeyEvent.VK_4 : return com.jogamp.newt.event.KeyEvent.VK_4;
+ case java.awt.event.KeyEvent.VK_5 : return com.jogamp.newt.event.KeyEvent.VK_5;
+ case java.awt.event.KeyEvent.VK_6 : return com.jogamp.newt.event.KeyEvent.VK_6;
+ case java.awt.event.KeyEvent.VK_7 : return com.jogamp.newt.event.KeyEvent.VK_7;
+ case java.awt.event.KeyEvent.VK_8 : return com.jogamp.newt.event.KeyEvent.VK_8;
+ case java.awt.event.KeyEvent.VK_9 : return com.jogamp.newt.event.KeyEvent.VK_9;
+ case java.awt.event.KeyEvent.VK_COLON : return com.jogamp.newt.event.KeyEvent.VK_COLON;
+ case java.awt.event.KeyEvent.VK_SEMICOLON : return com.jogamp.newt.event.KeyEvent.VK_SEMICOLON;
+ case java.awt.event.KeyEvent.VK_LESS : return com.jogamp.newt.event.KeyEvent.VK_LESS;
+ case java.awt.event.KeyEvent.VK_EQUALS : return com.jogamp.newt.event.KeyEvent.VK_EQUALS;
+ case java.awt.event.KeyEvent.VK_GREATER : return com.jogamp.newt.event.KeyEvent.VK_GREATER;
+ case 0x3f : return com.jogamp.newt.event.KeyEvent.VK_QUESTIONMARK;
+ case java.awt.event.KeyEvent.VK_AT : return com.jogamp.newt.event.KeyEvent.VK_AT;
+ case java.awt.event.KeyEvent.VK_A : return com.jogamp.newt.event.KeyEvent.VK_A;
+ case java.awt.event.KeyEvent.VK_B : return com.jogamp.newt.event.KeyEvent.VK_B;
+ case java.awt.event.KeyEvent.VK_C : return com.jogamp.newt.event.KeyEvent.VK_C;
+ case java.awt.event.KeyEvent.VK_D : return com.jogamp.newt.event.KeyEvent.VK_D;
+ case java.awt.event.KeyEvent.VK_E : return com.jogamp.newt.event.KeyEvent.VK_E;
+ case java.awt.event.KeyEvent.VK_F : return com.jogamp.newt.event.KeyEvent.VK_F;
+ case java.awt.event.KeyEvent.VK_G : return com.jogamp.newt.event.KeyEvent.VK_G;
+ case java.awt.event.KeyEvent.VK_H : return com.jogamp.newt.event.KeyEvent.VK_H;
+ case java.awt.event.KeyEvent.VK_I : return com.jogamp.newt.event.KeyEvent.VK_I;
+ case java.awt.event.KeyEvent.VK_J : return com.jogamp.newt.event.KeyEvent.VK_J;
+ case java.awt.event.KeyEvent.VK_K : return com.jogamp.newt.event.KeyEvent.VK_K;
+ case java.awt.event.KeyEvent.VK_L : return com.jogamp.newt.event.KeyEvent.VK_L;
+ case java.awt.event.KeyEvent.VK_M : return com.jogamp.newt.event.KeyEvent.VK_M;
+ case java.awt.event.KeyEvent.VK_N : return com.jogamp.newt.event.KeyEvent.VK_N;
+ case java.awt.event.KeyEvent.VK_O : return com.jogamp.newt.event.KeyEvent.VK_O;
+ case java.awt.event.KeyEvent.VK_P : return com.jogamp.newt.event.KeyEvent.VK_P;
+ case java.awt.event.KeyEvent.VK_Q : return com.jogamp.newt.event.KeyEvent.VK_Q;
+ case java.awt.event.KeyEvent.VK_R : return com.jogamp.newt.event.KeyEvent.VK_R;
+ case java.awt.event.KeyEvent.VK_S : return com.jogamp.newt.event.KeyEvent.VK_S;
+ case java.awt.event.KeyEvent.VK_T : return com.jogamp.newt.event.KeyEvent.VK_T;
+ case java.awt.event.KeyEvent.VK_U : return com.jogamp.newt.event.KeyEvent.VK_U;
+ case java.awt.event.KeyEvent.VK_V : return com.jogamp.newt.event.KeyEvent.VK_V;
+ case java.awt.event.KeyEvent.VK_W : return com.jogamp.newt.event.KeyEvent.VK_W;
+ case java.awt.event.KeyEvent.VK_X : return com.jogamp.newt.event.KeyEvent.VK_X;
+ case java.awt.event.KeyEvent.VK_Y : return com.jogamp.newt.event.KeyEvent.VK_Y;
+ case java.awt.event.KeyEvent.VK_Z : return com.jogamp.newt.event.KeyEvent.VK_Z;
+ case java.awt.event.KeyEvent.VK_OPEN_BRACKET : return com.jogamp.newt.event.KeyEvent.VK_OPEN_BRACKET;
+ case java.awt.event.KeyEvent.VK_BACK_SLASH : return com.jogamp.newt.event.KeyEvent.VK_BACK_SLASH;
+ case java.awt.event.KeyEvent.VK_CLOSE_BRACKET : return com.jogamp.newt.event.KeyEvent.VK_CLOSE_BRACKET;
+ case java.awt.event.KeyEvent.VK_CIRCUMFLEX : return com.jogamp.newt.event.KeyEvent.VK_CIRCUMFLEX;
+ case java.awt.event.KeyEvent.VK_UNDERSCORE : return com.jogamp.newt.event.KeyEvent.VK_UNDERSCORE;
+ case java.awt.event.KeyEvent.VK_BACK_QUOTE : return com.jogamp.newt.event.KeyEvent.VK_BACK_QUOTE;
+ case java.awt.event.KeyEvent.VK_F1 : return com.jogamp.newt.event.KeyEvent.VK_F1;
+ case java.awt.event.KeyEvent.VK_F2 : return com.jogamp.newt.event.KeyEvent.VK_F2;
+ case java.awt.event.KeyEvent.VK_F3 : return com.jogamp.newt.event.KeyEvent.VK_F3;
+ case java.awt.event.KeyEvent.VK_F4 : return com.jogamp.newt.event.KeyEvent.VK_F4;
+ case java.awt.event.KeyEvent.VK_F5 : return com.jogamp.newt.event.KeyEvent.VK_F5;
+ case java.awt.event.KeyEvent.VK_F6 : return com.jogamp.newt.event.KeyEvent.VK_F6;
+ case java.awt.event.KeyEvent.VK_F7 : return com.jogamp.newt.event.KeyEvent.VK_F7;
+ case java.awt.event.KeyEvent.VK_F8 : return com.jogamp.newt.event.KeyEvent.VK_F8;
+ case java.awt.event.KeyEvent.VK_F9 : return com.jogamp.newt.event.KeyEvent.VK_F9;
+ case java.awt.event.KeyEvent.VK_F10 : return com.jogamp.newt.event.KeyEvent.VK_F10;
+ case java.awt.event.KeyEvent.VK_F11 : return com.jogamp.newt.event.KeyEvent.VK_F11;
+ case java.awt.event.KeyEvent.VK_F12 : return com.jogamp.newt.event.KeyEvent.VK_F12;
+ case java.awt.event.KeyEvent.VK_F13 : return com.jogamp.newt.event.KeyEvent.VK_F13;
+ case java.awt.event.KeyEvent.VK_F14 : return com.jogamp.newt.event.KeyEvent.VK_F14;
+ case java.awt.event.KeyEvent.VK_F15 : return com.jogamp.newt.event.KeyEvent.VK_F15;
+ case java.awt.event.KeyEvent.VK_F16 : return com.jogamp.newt.event.KeyEvent.VK_F16;
+ case java.awt.event.KeyEvent.VK_F17 : return com.jogamp.newt.event.KeyEvent.VK_F17;
+ case java.awt.event.KeyEvent.VK_F18 : return com.jogamp.newt.event.KeyEvent.VK_F18;
+ case java.awt.event.KeyEvent.VK_F19 : return com.jogamp.newt.event.KeyEvent.VK_F19;
+ case java.awt.event.KeyEvent.VK_F20 : return com.jogamp.newt.event.KeyEvent.VK_F20;
+ case java.awt.event.KeyEvent.VK_F21 : return com.jogamp.newt.event.KeyEvent.VK_F21;
+ case java.awt.event.KeyEvent.VK_F22 : return com.jogamp.newt.event.KeyEvent.VK_F22;
+ case java.awt.event.KeyEvent.VK_F23 : return com.jogamp.newt.event.KeyEvent.VK_F23;
+ case java.awt.event.KeyEvent.VK_F24 : return com.jogamp.newt.event.KeyEvent.VK_F24;
+ case java.awt.event.KeyEvent.VK_BRACELEFT : return com.jogamp.newt.event.KeyEvent.VK_LEFT_BRACE;
+ case 0x7c : return com.jogamp.newt.event.KeyEvent.VK_PIPE;
+ case java.awt.event.KeyEvent.VK_BRACERIGHT : return com.jogamp.newt.event.KeyEvent.VK_RIGHT_BRACE;
+ case java.awt.event.KeyEvent.VK_DEAD_TILDE : return com.jogamp.newt.event.KeyEvent.VK_TILDE;
+ case java.awt.event.KeyEvent.VK_DELETE : return com.jogamp.newt.event.KeyEvent.VK_DELETE;
+ case java.awt.event.KeyEvent.VK_NUMPAD0 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD0;
+ case java.awt.event.KeyEvent.VK_NUMPAD1 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD1;
+ case java.awt.event.KeyEvent.VK_NUMPAD2 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD2;
+ case java.awt.event.KeyEvent.VK_NUMPAD3 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD3;
+ case java.awt.event.KeyEvent.VK_NUMPAD4 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD4;
+ case java.awt.event.KeyEvent.VK_NUMPAD5 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD5;
+ case java.awt.event.KeyEvent.VK_NUMPAD6 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD6;
+ case java.awt.event.KeyEvent.VK_NUMPAD7 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD7;
+ case java.awt.event.KeyEvent.VK_NUMPAD8 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD8;
+ case java.awt.event.KeyEvent.VK_NUMPAD9 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD9;
+ case java.awt.event.KeyEvent.VK_DECIMAL : return com.jogamp.newt.event.KeyEvent.VK_DECIMAL;
+ case java.awt.event.KeyEvent.VK_SEPARATOR : return com.jogamp.newt.event.KeyEvent.VK_SEPARATOR;
+ case java.awt.event.KeyEvent.VK_ADD : return com.jogamp.newt.event.KeyEvent.VK_ADD;
+ case java.awt.event.KeyEvent.VK_SUBTRACT : return com.jogamp.newt.event.KeyEvent.VK_SUBTRACT;
+ case java.awt.event.KeyEvent.VK_MULTIPLY : return com.jogamp.newt.event.KeyEvent.VK_MULTIPLY;
+ case java.awt.event.KeyEvent.VK_DIVIDE : return com.jogamp.newt.event.KeyEvent.VK_DIVIDE;
+ case java.awt.event.KeyEvent.VK_NUM_LOCK : return com.jogamp.newt.event.KeyEvent.VK_NUM_LOCK;
+ case java.awt.event.KeyEvent.VK_KP_LEFT : /** Fall through intended .. */
+ case java.awt.event.KeyEvent.VK_LEFT : return com.jogamp.newt.event.KeyEvent.VK_LEFT;
+ case java.awt.event.KeyEvent.VK_KP_UP : /** Fall through intended .. */
+ case java.awt.event.KeyEvent.VK_UP : return com.jogamp.newt.event.KeyEvent.VK_UP;
+ case java.awt.event.KeyEvent.VK_KP_RIGHT : /** Fall through intended .. */
+ case java.awt.event.KeyEvent.VK_RIGHT : return com.jogamp.newt.event.KeyEvent.VK_RIGHT;
+ case java.awt.event.KeyEvent.VK_KP_DOWN : /** Fall through intended .. */
+ case java.awt.event.KeyEvent.VK_DOWN : return com.jogamp.newt.event.KeyEvent.VK_DOWN;
+ case java.awt.event.KeyEvent.VK_CONTEXT_MENU : return com.jogamp.newt.event.KeyEvent.VK_CONTEXT_MENU;
+ case java.awt.event.KeyEvent.VK_WINDOWS : return com.jogamp.newt.event.KeyEvent.VK_WINDOWS;
+ case java.awt.event.KeyEvent.VK_META : return com.jogamp.newt.event.KeyEvent.VK_META;
+ case java.awt.event.KeyEvent.VK_HELP : return com.jogamp.newt.event.KeyEvent.VK_HELP;
+ case java.awt.event.KeyEvent.VK_COMPOSE : return com.jogamp.newt.event.KeyEvent.VK_COMPOSE;
+ case java.awt.event.KeyEvent.VK_BEGIN : return com.jogamp.newt.event.KeyEvent.VK_BEGIN;
+ case java.awt.event.KeyEvent.VK_STOP : return com.jogamp.newt.event.KeyEvent.VK_STOP;
+ case java.awt.event.KeyEvent.VK_INVERTED_EXCLAMATION_MARK: return com.jogamp.newt.event.KeyEvent.VK_INVERTED_EXCLAMATION_MARK;
+ case java.awt.event.KeyEvent.VK_EURO_SIGN : return com.jogamp.newt.event.KeyEvent.VK_EURO_SIGN;
+ case java.awt.event.KeyEvent.VK_CUT : return com.jogamp.newt.event.KeyEvent.VK_CUT;
+ case java.awt.event.KeyEvent.VK_COPY : return com.jogamp.newt.event.KeyEvent.VK_COPY;
+ case java.awt.event.KeyEvent.VK_PASTE : return com.jogamp.newt.event.KeyEvent.VK_PASTE;
+ case java.awt.event.KeyEvent.VK_UNDO : return com.jogamp.newt.event.KeyEvent.VK_UNDO;
+ case java.awt.event.KeyEvent.VK_AGAIN : return com.jogamp.newt.event.KeyEvent.VK_AGAIN;
+ case java.awt.event.KeyEvent.VK_FIND : return com.jogamp.newt.event.KeyEvent.VK_FIND;
+ case java.awt.event.KeyEvent.VK_PROPS : return com.jogamp.newt.event.KeyEvent.VK_PROPS;
+ case java.awt.event.KeyEvent.VK_INPUT_METHOD_ON_OFF: return com.jogamp.newt.event.KeyEvent.VK_INPUT_METHOD_ON_OFF;
+ case java.awt.event.KeyEvent.VK_CODE_INPUT : return com.jogamp.newt.event.KeyEvent.VK_CODE_INPUT;
+ case java.awt.event.KeyEvent.VK_ROMAN_CHARACTERS: return com.jogamp.newt.event.KeyEvent.VK_ROMAN_CHARACTERS;
+ case java.awt.event.KeyEvent.VK_ALL_CANDIDATES: return com.jogamp.newt.event.KeyEvent.VK_ALL_CANDIDATES;
+ case java.awt.event.KeyEvent.VK_PREVIOUS_CANDIDATE: return com.jogamp.newt.event.KeyEvent.VK_PREVIOUS_CANDIDATE;
+ case java.awt.event.KeyEvent.VK_ALPHANUMERIC : return com.jogamp.newt.event.KeyEvent.VK_ALPHANUMERIC;
+ case java.awt.event.KeyEvent.VK_KATAKANA : return com.jogamp.newt.event.KeyEvent.VK_KATAKANA;
+ case java.awt.event.KeyEvent.VK_HIRAGANA : return com.jogamp.newt.event.KeyEvent.VK_HIRAGANA;
+ case java.awt.event.KeyEvent.VK_FULL_WIDTH : return com.jogamp.newt.event.KeyEvent.VK_FULL_WIDTH;
+ case java.awt.event.KeyEvent.VK_HALF_WIDTH : return com.jogamp.newt.event.KeyEvent.VK_HALF_WIDTH;
+ case java.awt.event.KeyEvent.VK_JAPANESE_KATAKANA: return com.jogamp.newt.event.KeyEvent.VK_JAPANESE_KATAKANA;
+ case java.awt.event.KeyEvent.VK_JAPANESE_HIRAGANA: return com.jogamp.newt.event.KeyEvent.VK_JAPANESE_HIRAGANA;
+ case java.awt.event.KeyEvent.VK_JAPANESE_ROMAN: return com.jogamp.newt.event.KeyEvent.VK_JAPANESE_ROMAN;
+ case java.awt.event.KeyEvent.VK_KANA_LOCK : return com.jogamp.newt.event.KeyEvent.VK_KANA_LOCK;
+ }
+ return defNEWTKeyCode;
+ }
+
+ public static int newtKeyCode2AWTKeyCode(final short newtKeyCode) {
+ final int defAwtKeyCode = 0xFFFF & newtKeyCode;
+ switch (newtKeyCode) {
+ case com.jogamp.newt.event.KeyEvent.VK_HOME : return java.awt.event.KeyEvent.VK_HOME;
+ case com.jogamp.newt.event.KeyEvent.VK_END : return java.awt.event.KeyEvent.VK_END;
+ case com.jogamp.newt.event.KeyEvent.VK_FINAL : return java.awt.event.KeyEvent.VK_FINAL;
+ case com.jogamp.newt.event.KeyEvent.VK_PRINTSCREEN : return java.awt.event.KeyEvent.VK_PRINTSCREEN;
+ case com.jogamp.newt.event.KeyEvent.VK_BACK_SPACE : return java.awt.event.KeyEvent.VK_BACK_SPACE;
+ case com.jogamp.newt.event.KeyEvent.VK_TAB : return java.awt.event.KeyEvent.VK_TAB;
+ case com.jogamp.newt.event.KeyEvent.VK_ENTER : return java.awt.event.KeyEvent.VK_ENTER;
+ case com.jogamp.newt.event.KeyEvent.VK_PAGE_DOWN : return java.awt.event.KeyEvent.VK_PAGE_DOWN;
+ case com.jogamp.newt.event.KeyEvent.VK_CLEAR : return java.awt.event.KeyEvent.VK_CLEAR;
+ case com.jogamp.newt.event.KeyEvent.VK_SHIFT : return java.awt.event.KeyEvent.VK_SHIFT;
+ case com.jogamp.newt.event.KeyEvent.VK_PAGE_UP : return java.awt.event.KeyEvent.VK_PAGE_UP;
+ case com.jogamp.newt.event.KeyEvent.VK_CONTROL : return java.awt.event.KeyEvent.VK_CONTROL;
+ case com.jogamp.newt.event.KeyEvent.VK_ALT : return java.awt.event.KeyEvent.VK_ALT;
+ // FIXME: On X11 it results to 0xff7e w/ AWTRobot, which is wrong. 0xffea Alt_R is expected AFAIK.
+ case com.jogamp.newt.event.KeyEvent.VK_ALT_GRAPH : return java.awt.event.KeyEvent.VK_ALT_GRAPH;
+ case com.jogamp.newt.event.KeyEvent.VK_CAPS_LOCK : return java.awt.event.KeyEvent.VK_CAPS_LOCK;
+ case com.jogamp.newt.event.KeyEvent.VK_PAUSE : return java.awt.event.KeyEvent.VK_PAUSE;
+ case com.jogamp.newt.event.KeyEvent.VK_SCROLL_LOCK : return java.awt.event.KeyEvent.VK_SCROLL_LOCK;
+ case com.jogamp.newt.event.KeyEvent.VK_CANCEL : return java.awt.event.KeyEvent.VK_CANCEL;
+ case com.jogamp.newt.event.KeyEvent.VK_INSERT : return java.awt.event.KeyEvent.VK_INSERT;
+ case com.jogamp.newt.event.KeyEvent.VK_ESCAPE : return java.awt.event.KeyEvent.VK_ESCAPE;
+ case com.jogamp.newt.event.KeyEvent.VK_CONVERT : return java.awt.event.KeyEvent.VK_CONVERT;
+ case com.jogamp.newt.event.KeyEvent.VK_NONCONVERT : return java.awt.event.KeyEvent.VK_NONCONVERT;
+ case com.jogamp.newt.event.KeyEvent.VK_ACCEPT : return java.awt.event.KeyEvent.VK_ACCEPT;
+ case com.jogamp.newt.event.KeyEvent.VK_MODECHANGE : return java.awt.event.KeyEvent.VK_MODECHANGE;
+ case com.jogamp.newt.event.KeyEvent.VK_SPACE : return java.awt.event.KeyEvent.VK_SPACE;
+ case com.jogamp.newt.event.KeyEvent.VK_EXCLAMATION_MARK: return java.awt.event.KeyEvent.VK_EXCLAMATION_MARK;
+ case com.jogamp.newt.event.KeyEvent.VK_QUOTEDBL : return java.awt.event.KeyEvent.VK_QUOTEDBL;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMBER_SIGN : return java.awt.event.KeyEvent.VK_NUMBER_SIGN;
+ case com.jogamp.newt.event.KeyEvent.VK_DOLLAR : return java.awt.event.KeyEvent.VK_DOLLAR;
+ case com.jogamp.newt.event.KeyEvent.VK_PERCENT : return defAwtKeyCode;
+ case com.jogamp.newt.event.KeyEvent.VK_AMPERSAND : return java.awt.event.KeyEvent.VK_AMPERSAND;
+ case com.jogamp.newt.event.KeyEvent.VK_QUOTE : return java.awt.event.KeyEvent.VK_QUOTE;
+ case com.jogamp.newt.event.KeyEvent.VK_LEFT_PARENTHESIS : return java.awt.event.KeyEvent.VK_LEFT_PARENTHESIS;
+ case com.jogamp.newt.event.KeyEvent.VK_RIGHT_PARENTHESIS: return java.awt.event.KeyEvent.VK_RIGHT_PARENTHESIS;
+ case com.jogamp.newt.event.KeyEvent.VK_ASTERISK : return java.awt.event.KeyEvent.VK_ASTERISK;
+ case com.jogamp.newt.event.KeyEvent.VK_PLUS : return java.awt.event.KeyEvent.VK_PLUS;
+ case com.jogamp.newt.event.KeyEvent.VK_COMMA : return java.awt.event.KeyEvent.VK_COMMA;
+ case com.jogamp.newt.event.KeyEvent.VK_MINUS : return java.awt.event.KeyEvent.VK_MINUS;
+ case com.jogamp.newt.event.KeyEvent.VK_PERIOD : return java.awt.event.KeyEvent.VK_PERIOD;
+ case com.jogamp.newt.event.KeyEvent.VK_SLASH : return java.awt.event.KeyEvent.VK_SLASH;
+ case com.jogamp.newt.event.KeyEvent.VK_0 : return java.awt.event.KeyEvent.VK_0;
+ case com.jogamp.newt.event.KeyEvent.VK_1 : return java.awt.event.KeyEvent.VK_1;
+ case com.jogamp.newt.event.KeyEvent.VK_2 : return java.awt.event.KeyEvent.VK_2;
+ case com.jogamp.newt.event.KeyEvent.VK_3 : return java.awt.event.KeyEvent.VK_3;
+ case com.jogamp.newt.event.KeyEvent.VK_4 : return java.awt.event.KeyEvent.VK_4;
+ case com.jogamp.newt.event.KeyEvent.VK_5 : return java.awt.event.KeyEvent.VK_5;
+ case com.jogamp.newt.event.KeyEvent.VK_6 : return java.awt.event.KeyEvent.VK_6;
+ case com.jogamp.newt.event.KeyEvent.VK_7 : return java.awt.event.KeyEvent.VK_7;
+ case com.jogamp.newt.event.KeyEvent.VK_8 : return java.awt.event.KeyEvent.VK_8;
+ case com.jogamp.newt.event.KeyEvent.VK_9 : return java.awt.event.KeyEvent.VK_9;
+ case com.jogamp.newt.event.KeyEvent.VK_COLON : return java.awt.event.KeyEvent.VK_COLON;
+ case com.jogamp.newt.event.KeyEvent.VK_SEMICOLON : return java.awt.event.KeyEvent.VK_SEMICOLON;
+ case com.jogamp.newt.event.KeyEvent.VK_LESS : return java.awt.event.KeyEvent.VK_LESS;
+ case com.jogamp.newt.event.KeyEvent.VK_EQUALS : return java.awt.event.KeyEvent.VK_EQUALS;
+ case com.jogamp.newt.event.KeyEvent.VK_GREATER : return java.awt.event.KeyEvent.VK_GREATER;
+ case com.jogamp.newt.event.KeyEvent.VK_QUESTIONMARK : return defAwtKeyCode;
+ case com.jogamp.newt.event.KeyEvent.VK_AT : return java.awt.event.KeyEvent.VK_AT;
+ case com.jogamp.newt.event.KeyEvent.VK_A : return java.awt.event.KeyEvent.VK_A;
+ case com.jogamp.newt.event.KeyEvent.VK_B : return java.awt.event.KeyEvent.VK_B;
+ case com.jogamp.newt.event.KeyEvent.VK_C : return java.awt.event.KeyEvent.VK_C;
+ case com.jogamp.newt.event.KeyEvent.VK_D : return java.awt.event.KeyEvent.VK_D;
+ case com.jogamp.newt.event.KeyEvent.VK_E : return java.awt.event.KeyEvent.VK_E;
+ case com.jogamp.newt.event.KeyEvent.VK_F : return java.awt.event.KeyEvent.VK_F;
+ case com.jogamp.newt.event.KeyEvent.VK_G : return java.awt.event.KeyEvent.VK_G;
+ case com.jogamp.newt.event.KeyEvent.VK_H : return java.awt.event.KeyEvent.VK_H;
+ case com.jogamp.newt.event.KeyEvent.VK_I : return java.awt.event.KeyEvent.VK_I;
+ case com.jogamp.newt.event.KeyEvent.VK_J : return java.awt.event.KeyEvent.VK_J;
+ case com.jogamp.newt.event.KeyEvent.VK_K : return java.awt.event.KeyEvent.VK_K;
+ case com.jogamp.newt.event.KeyEvent.VK_L : return java.awt.event.KeyEvent.VK_L;
+ case com.jogamp.newt.event.KeyEvent.VK_M : return java.awt.event.KeyEvent.VK_M;
+ case com.jogamp.newt.event.KeyEvent.VK_N : return java.awt.event.KeyEvent.VK_N;
+ case com.jogamp.newt.event.KeyEvent.VK_O : return java.awt.event.KeyEvent.VK_O;
+ case com.jogamp.newt.event.KeyEvent.VK_P : return java.awt.event.KeyEvent.VK_P;
+ case com.jogamp.newt.event.KeyEvent.VK_Q : return java.awt.event.KeyEvent.VK_Q;
+ case com.jogamp.newt.event.KeyEvent.VK_R : return java.awt.event.KeyEvent.VK_R;
+ case com.jogamp.newt.event.KeyEvent.VK_S : return java.awt.event.KeyEvent.VK_S;
+ case com.jogamp.newt.event.KeyEvent.VK_T : return java.awt.event.KeyEvent.VK_T;
+ case com.jogamp.newt.event.KeyEvent.VK_U : return java.awt.event.KeyEvent.VK_U;
+ case com.jogamp.newt.event.KeyEvent.VK_V : return java.awt.event.KeyEvent.VK_V;
+ case com.jogamp.newt.event.KeyEvent.VK_W : return java.awt.event.KeyEvent.VK_W;
+ case com.jogamp.newt.event.KeyEvent.VK_X : return java.awt.event.KeyEvent.VK_X;
+ case com.jogamp.newt.event.KeyEvent.VK_Y : return java.awt.event.KeyEvent.VK_Y;
+ case com.jogamp.newt.event.KeyEvent.VK_Z : return java.awt.event.KeyEvent.VK_Z;
+ case com.jogamp.newt.event.KeyEvent.VK_OPEN_BRACKET : return java.awt.event.KeyEvent.VK_OPEN_BRACKET;
+ case com.jogamp.newt.event.KeyEvent.VK_BACK_SLASH : return java.awt.event.KeyEvent.VK_BACK_SLASH;
+ case com.jogamp.newt.event.KeyEvent.VK_CLOSE_BRACKET : return java.awt.event.KeyEvent.VK_CLOSE_BRACKET;
+ case com.jogamp.newt.event.KeyEvent.VK_CIRCUMFLEX : return java.awt.event.KeyEvent.VK_CIRCUMFLEX;
+ case com.jogamp.newt.event.KeyEvent.VK_UNDERSCORE : return java.awt.event.KeyEvent.VK_UNDERSCORE;
+ case com.jogamp.newt.event.KeyEvent.VK_BACK_QUOTE : return java.awt.event.KeyEvent.VK_BACK_QUOTE;
+ case com.jogamp.newt.event.KeyEvent.VK_F1 : return java.awt.event.KeyEvent.VK_F1;
+ case com.jogamp.newt.event.KeyEvent.VK_F2 : return java.awt.event.KeyEvent.VK_F2;
+ case com.jogamp.newt.event.KeyEvent.VK_F3 : return java.awt.event.KeyEvent.VK_F3;
+ case com.jogamp.newt.event.KeyEvent.VK_F4 : return java.awt.event.KeyEvent.VK_F4;
+ case com.jogamp.newt.event.KeyEvent.VK_F5 : return java.awt.event.KeyEvent.VK_F5;
+ case com.jogamp.newt.event.KeyEvent.VK_F6 : return java.awt.event.KeyEvent.VK_F6;
+ case com.jogamp.newt.event.KeyEvent.VK_F7 : return java.awt.event.KeyEvent.VK_F7;
+ case com.jogamp.newt.event.KeyEvent.VK_F8 : return java.awt.event.KeyEvent.VK_F8;
+ case com.jogamp.newt.event.KeyEvent.VK_F9 : return java.awt.event.KeyEvent.VK_F9;
+ case com.jogamp.newt.event.KeyEvent.VK_F10 : return java.awt.event.KeyEvent.VK_F10;
+ case com.jogamp.newt.event.KeyEvent.VK_F11 : return java.awt.event.KeyEvent.VK_F11;
+ case com.jogamp.newt.event.KeyEvent.VK_F12 : return java.awt.event.KeyEvent.VK_F12;
+ case com.jogamp.newt.event.KeyEvent.VK_F13 : return java.awt.event.KeyEvent.VK_F13;
+ case com.jogamp.newt.event.KeyEvent.VK_F14 : return java.awt.event.KeyEvent.VK_F14;
+ case com.jogamp.newt.event.KeyEvent.VK_F15 : return java.awt.event.KeyEvent.VK_F15;
+ case com.jogamp.newt.event.KeyEvent.VK_F16 : return java.awt.event.KeyEvent.VK_F16;
+ case com.jogamp.newt.event.KeyEvent.VK_F17 : return java.awt.event.KeyEvent.VK_F17;
+ case com.jogamp.newt.event.KeyEvent.VK_F18 : return java.awt.event.KeyEvent.VK_F18;
+ case com.jogamp.newt.event.KeyEvent.VK_F19 : return java.awt.event.KeyEvent.VK_F19;
+ case com.jogamp.newt.event.KeyEvent.VK_F20 : return java.awt.event.KeyEvent.VK_F20;
+ case com.jogamp.newt.event.KeyEvent.VK_F21 : return java.awt.event.KeyEvent.VK_F21;
+ case com.jogamp.newt.event.KeyEvent.VK_F22 : return java.awt.event.KeyEvent.VK_F22;
+ case com.jogamp.newt.event.KeyEvent.VK_F23 : return java.awt.event.KeyEvent.VK_F23;
+ case com.jogamp.newt.event.KeyEvent.VK_F24 : return java.awt.event.KeyEvent.VK_F24;
+ case com.jogamp.newt.event.KeyEvent.VK_LEFT_BRACE : return java.awt.event.KeyEvent.VK_BRACELEFT;
+ case com.jogamp.newt.event.KeyEvent.VK_PIPE : return defAwtKeyCode;
+ case com.jogamp.newt.event.KeyEvent.VK_RIGHT_BRACE : return java.awt.event.KeyEvent.VK_BRACERIGHT;
+ case com.jogamp.newt.event.KeyEvent.VK_TILDE : return java.awt.event.KeyEvent.VK_DEAD_TILDE;
+ case com.jogamp.newt.event.KeyEvent.VK_DELETE : return java.awt.event.KeyEvent.VK_DELETE;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD0 : return java.awt.event.KeyEvent.VK_NUMPAD0;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD1 : return java.awt.event.KeyEvent.VK_NUMPAD1;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD2 : return java.awt.event.KeyEvent.VK_NUMPAD2;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD3 : return java.awt.event.KeyEvent.VK_NUMPAD3;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD4 : return java.awt.event.KeyEvent.VK_NUMPAD4;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD5 : return java.awt.event.KeyEvent.VK_NUMPAD5;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD6 : return java.awt.event.KeyEvent.VK_NUMPAD6;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD7 : return java.awt.event.KeyEvent.VK_NUMPAD7;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD8 : return java.awt.event.KeyEvent.VK_NUMPAD8;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD9 : return java.awt.event.KeyEvent.VK_NUMPAD9;
+ case com.jogamp.newt.event.KeyEvent.VK_DECIMAL : return java.awt.event.KeyEvent.VK_DECIMAL;
+ case com.jogamp.newt.event.KeyEvent.VK_SEPARATOR : return java.awt.event.KeyEvent.VK_SEPARATOR;
+ case com.jogamp.newt.event.KeyEvent.VK_ADD : return java.awt.event.KeyEvent.VK_ADD;
+ case com.jogamp.newt.event.KeyEvent.VK_SUBTRACT : return java.awt.event.KeyEvent.VK_SUBTRACT;
+ case com.jogamp.newt.event.KeyEvent.VK_MULTIPLY : return java.awt.event.KeyEvent.VK_MULTIPLY;
+ case com.jogamp.newt.event.KeyEvent.VK_DIVIDE : return java.awt.event.KeyEvent.VK_DIVIDE;
+ case com.jogamp.newt.event.KeyEvent.VK_NUM_LOCK : return java.awt.event.KeyEvent.VK_NUM_LOCK;
+ case com.jogamp.newt.event.KeyEvent.VK_LEFT : return java.awt.event.KeyEvent.VK_LEFT;
+ case com.jogamp.newt.event.KeyEvent.VK_UP : return java.awt.event.KeyEvent.VK_UP;
+ case com.jogamp.newt.event.KeyEvent.VK_RIGHT : return java.awt.event.KeyEvent.VK_RIGHT;
+ case com.jogamp.newt.event.KeyEvent.VK_DOWN : return java.awt.event.KeyEvent.VK_DOWN;
+ case com.jogamp.newt.event.KeyEvent.VK_CONTEXT_MENU : return java.awt.event.KeyEvent.VK_CONTEXT_MENU;
+ case com.jogamp.newt.event.KeyEvent.VK_WINDOWS : return java.awt.event.KeyEvent.VK_WINDOWS;
+ case com.jogamp.newt.event.KeyEvent.VK_META : return java.awt.event.KeyEvent.VK_META;
+ case com.jogamp.newt.event.KeyEvent.VK_HELP : return java.awt.event.KeyEvent.VK_HELP;
+ case com.jogamp.newt.event.KeyEvent.VK_COMPOSE : return java.awt.event.KeyEvent.VK_COMPOSE;
+ case com.jogamp.newt.event.KeyEvent.VK_BEGIN : return java.awt.event.KeyEvent.VK_BEGIN;
+ case com.jogamp.newt.event.KeyEvent.VK_STOP : return java.awt.event.KeyEvent.VK_STOP;
+ case com.jogamp.newt.event.KeyEvent.VK_INVERTED_EXCLAMATION_MARK: return java.awt.event.KeyEvent.VK_INVERTED_EXCLAMATION_MARK;
+ case com.jogamp.newt.event.KeyEvent.VK_EURO_SIGN : return java.awt.event.KeyEvent.VK_EURO_SIGN;
+ case com.jogamp.newt.event.KeyEvent.VK_CUT : return java.awt.event.KeyEvent.VK_CUT;
+ case com.jogamp.newt.event.KeyEvent.VK_COPY : return java.awt.event.KeyEvent.VK_COPY;
+ case com.jogamp.newt.event.KeyEvent.VK_PASTE : return java.awt.event.KeyEvent.VK_PASTE;
+ case com.jogamp.newt.event.KeyEvent.VK_UNDO : return java.awt.event.KeyEvent.VK_UNDO;
+ case com.jogamp.newt.event.KeyEvent.VK_AGAIN : return java.awt.event.KeyEvent.VK_AGAIN;
+ case com.jogamp.newt.event.KeyEvent.VK_FIND : return java.awt.event.KeyEvent.VK_FIND;
+ case com.jogamp.newt.event.KeyEvent.VK_PROPS : return java.awt.event.KeyEvent.VK_PROPS;
+ case com.jogamp.newt.event.KeyEvent.VK_INPUT_METHOD_ON_OFF: return java.awt.event.KeyEvent.VK_INPUT_METHOD_ON_OFF;
+ case com.jogamp.newt.event.KeyEvent.VK_CODE_INPUT : return java.awt.event.KeyEvent.VK_CODE_INPUT;
+ case com.jogamp.newt.event.KeyEvent.VK_ROMAN_CHARACTERS: return java.awt.event.KeyEvent.VK_ROMAN_CHARACTERS;
+ case com.jogamp.newt.event.KeyEvent.VK_ALL_CANDIDATES: return java.awt.event.KeyEvent.VK_ALL_CANDIDATES;
+ case com.jogamp.newt.event.KeyEvent.VK_PREVIOUS_CANDIDATE: return java.awt.event.KeyEvent.VK_PREVIOUS_CANDIDATE;
+ case com.jogamp.newt.event.KeyEvent.VK_ALPHANUMERIC : return java.awt.event.KeyEvent.VK_ALPHANUMERIC;
+ case com.jogamp.newt.event.KeyEvent.VK_KATAKANA : return java.awt.event.KeyEvent.VK_KATAKANA;
+ case com.jogamp.newt.event.KeyEvent.VK_HIRAGANA : return java.awt.event.KeyEvent.VK_HIRAGANA;
+ case com.jogamp.newt.event.KeyEvent.VK_FULL_WIDTH : return java.awt.event.KeyEvent.VK_FULL_WIDTH;
+ case com.jogamp.newt.event.KeyEvent.VK_HALF_WIDTH : return java.awt.event.KeyEvent.VK_HALF_WIDTH;
+ case com.jogamp.newt.event.KeyEvent.VK_JAPANESE_KATAKANA: return java.awt.event.KeyEvent.VK_JAPANESE_KATAKANA;
+ case com.jogamp.newt.event.KeyEvent.VK_JAPANESE_HIRAGANA: return java.awt.event.KeyEvent.VK_JAPANESE_HIRAGANA;
+ case com.jogamp.newt.event.KeyEvent.VK_JAPANESE_ROMAN: return java.awt.event.KeyEvent.VK_JAPANESE_ROMAN;
+ case com.jogamp.newt.event.KeyEvent.VK_KANA_LOCK : return java.awt.event.KeyEvent.VK_KANA_LOCK;
}
- return 0;
+ return defAwtKeyCode;
}
- public static final com.jogamp.newt.event.WindowEvent createWindowEvent(java.awt.event.WindowEvent event, com.jogamp.newt.Window newtSource) {
- int type = eventTypeAWT2NEWT.get(event.getID());
- if(0xFFFFFFFF != type) {
- return new com.jogamp.newt.event.WindowEvent(type, ((null==newtSource)?(Object)event.getComponent():(Object)newtSource), System.currentTimeMillis());
+ public static final com.jogamp.newt.event.WindowEvent createWindowEvent(final java.awt.event.WindowEvent event, final NativeSurfaceHolder sourceHolder) {
+ final short newtType = eventTypeAWT2NEWT(event.getID());
+ if( (short)0 != newtType ) {
+ return new com.jogamp.newt.event.WindowEvent(newtType, sourceHolder, System.currentTimeMillis());
}
return null; // no mapping ..
}
- public static final com.jogamp.newt.event.WindowEvent createWindowEvent(java.awt.event.ComponentEvent event, com.jogamp.newt.Window newtSource) {
- int type = eventTypeAWT2NEWT.get(event.getID());
- if(0xFFFFFFFF != type) {
- return new com.jogamp.newt.event.WindowEvent(type, (null==newtSource)?(Object)event.getComponent():(Object)newtSource, System.currentTimeMillis());
+ public static final com.jogamp.newt.event.WindowEvent createWindowEvent(final java.awt.event.ComponentEvent event, final NativeSurfaceHolder sourceHolder) {
+ final short newtType = eventTypeAWT2NEWT(event.getID());
+ if( (short)0 != newtType ) {
+ return new com.jogamp.newt.event.WindowEvent(newtType, sourceHolder, System.currentTimeMillis());
}
return null; // no mapping ..
}
- public static final com.jogamp.newt.event.WindowEvent createWindowEvent(java.awt.event.FocusEvent event, com.jogamp.newt.Window newtSource) {
- int type = eventTypeAWT2NEWT.get(event.getID());
- if(0xFFFFFFFF != type) {
- return new com.jogamp.newt.event.WindowEvent(type, (null==newtSource)?(Object)event.getComponent():(Object)newtSource, System.currentTimeMillis());
+ public static final com.jogamp.newt.event.WindowEvent createWindowEvent(final java.awt.event.FocusEvent event, final NativeSurfaceHolder sourceHolder) {
+ final short newtType = eventTypeAWT2NEWT(event.getID());
+ if( (short)0 != newtType ) {
+ return new com.jogamp.newt.event.WindowEvent(newtType, sourceHolder, System.currentTimeMillis());
}
return null; // no mapping ..
}
- public static final com.jogamp.newt.event.MouseEvent createMouseEvent(java.awt.event.MouseEvent event, com.jogamp.newt.Window newtSource) {
- int type = eventTypeAWT2NEWT.get(event.getID());
- if(0xFFFFFFFF != type) {
- int rotation = 0;
+ public static final com.jogamp.newt.event.MouseEvent createMouseEvent(final java.awt.event.MouseEvent event, final NativeSurfaceHolder sourceHolder) {
+ final short newtType = eventTypeAWT2NEWT(event.getID());
+ if( (short)0 != newtType ) {
+ float rotation = 0;
if (event instanceof java.awt.event.MouseWheelEvent) {
// AWT/NEWT rotation is reversed - AWT +1 is down, NEWT +1 is up.
- rotation = -1 * ((java.awt.event.MouseWheelEvent)event).getWheelRotation();
+ rotation = -1f * ((java.awt.event.MouseWheelEvent)event).getWheelRotation();
}
- int mods = awtModifiers2Newt(event.getModifiers(), true);
- if(null!=newtSource) {
- if(newtSource.isPointerConfined()) {
- mods |= InputEvent.CONFINED_MASK;
- }
- if(!newtSource.isPointerVisible()) {
- mods |= InputEvent.INVISIBLE_MASK;
+ final short newtButton = awtButton2Newt(event.getButton());
+ int mods = awtModifiers2Newt(event.getModifiers(), event.getModifiersEx());
+ mods |= com.jogamp.newt.event.InputEvent.getButtonMask(newtButton); // always include NEWT BUTTON_MASK
+ final NativeSurface source = sourceHolder.getNativeSurface();
+ final int[] pixelPos;
+ if( null != source ) {
+ if( source instanceof com.jogamp.newt.Window ) {
+ final com.jogamp.newt.Window newtSource = (com.jogamp.newt.Window) source;
+ if(newtSource.isPointerConfined()) {
+ mods |= com.jogamp.newt.event.InputEvent.CONFINED_MASK;
+ }
+ if(!newtSource.isPointerVisible()) {
+ mods |= com.jogamp.newt.event.InputEvent.INVISIBLE_MASK;
+ }
}
+ pixelPos = source.convertToPixelUnits(new int[] { event.getX(), event.getY() });
+ } else {
+ pixelPos = new int[] { event.getX(), event.getY() };
}
-
+
return new com.jogamp.newt.event.MouseEvent(
- type, (null==newtSource)?(Object)event.getComponent():(Object)newtSource, event.getWhen(),
- mods, event.getX(), event.getY(), event.getClickCount(),
- awtButton2Newt(event.getButton()), rotation);
+ newtType, sourceHolder, event.getWhen(),
+ mods, pixelPos[0], pixelPos[1], (short)event.getClickCount(),
+ newtButton, MouseEvent.getRotationXYZ(rotation, mods), 1f);
}
return null; // no mapping ..
}
- public static final com.jogamp.newt.event.KeyEvent createKeyEvent(java.awt.event.KeyEvent event, com.jogamp.newt.Window newtSource) {
- int type = eventTypeAWT2NEWT.get(event.getID());
- if(0xFFFFFFFF != type) {
- return new com.jogamp.newt.event.KeyEvent(
- type, (null==newtSource)?(Object)event.getComponent():(Object)newtSource, event.getWhen(),
- awtModifiers2Newt(event.getModifiers(), false),
- event.getKeyCode(), event.getKeyChar());
+ public static final com.jogamp.newt.event.KeyEvent createKeyEvent(final java.awt.event.KeyEvent event, final NativeSurfaceHolder sourceHolder) {
+ return createKeyEvent(eventTypeAWT2NEWT(event.getID()), event, sourceHolder);
+ }
+
+ public static final com.jogamp.newt.event.KeyEvent createKeyEvent(final short newtType, final java.awt.event.KeyEvent event, final NativeSurfaceHolder sourceHolder) {
+ if( (short)0 != newtType ) {
+ final short newtKeyCode = awtKeyCode2NewtKeyCode( event.getKeyCode() );
+ return com.jogamp.newt.event.KeyEvent.create(
+ newtType, sourceHolder, event.getWhen(),
+ awtModifiers2Newt(event.getModifiers(), event.getModifiersEx()),
+ newtKeyCode, newtKeyCode, event.getKeyChar());
}
return null; // no mapping ..
}
}
-
diff --git a/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java b/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java
index 747e2368e..93cdd7e56 100644
--- a/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java
+++ b/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,12 +20,12 @@
* 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.awt.event;
import java.awt.KeyboardFocusManager;
@@ -42,113 +42,147 @@ import com.jogamp.newt.event.awt.AWTWindowAdapter;
* Specialized parent/client adapter,
* where the NEWT child window really gets resized,
* and the parent move window event gets discarded. */
-public class AWTParentWindowAdapter
- extends AWTWindowAdapter
- implements java.awt.event.HierarchyListener
+public class AWTParentWindowAdapter extends AWTWindowAdapter implements java.awt.event.HierarchyListener
{
NativeWindow downstreamParent;
-
- public AWTParentWindowAdapter(NativeWindow downstreamParent, com.jogamp.newt.Window downstream) {
+
+ public AWTParentWindowAdapter(final NativeWindow downstreamParent, final com.jogamp.newt.Window downstream) {
super(downstream);
this.downstreamParent = downstreamParent;
}
+ public AWTParentWindowAdapter() {
+ super();
+ }
+ public AWTParentWindowAdapter setDownstream(final NativeWindow downstreamParent, final com.jogamp.newt.Window downstream) {
+ setDownstream(downstream);
+ this.downstreamParent = downstreamParent;
+ return this;
+ }
+
+ @Override
+ public synchronized AWTAdapter clear() {
+ super.clear();
+ this.downstreamParent = null;
+ return this;
+ }
- public AWTAdapter addTo(java.awt.Component awtComponent) {
+ @Override
+ public synchronized AWTAdapter addTo(final java.awt.Component awtComponent) {
awtComponent.addHierarchyListener(this);
return super.addTo(awtComponent);
}
- public AWTAdapter removeFrom(java.awt.Component awtComponent) {
+ @Override
+ public synchronized AWTAdapter removeFrom(final java.awt.Component awtComponent) {
awtComponent.removeHierarchyListener(this);
return super.removeFrom(awtComponent);
}
- public void focusGained(java.awt.event.FocusEvent e) {
+ @Override
+ public synchronized void focusGained(final java.awt.event.FocusEvent e) {
+ if( !isSetup ) { return; }
// forward focus to NEWT child
final com.jogamp.newt.Window newtChild = getNewtWindow();
- final boolean isOnscreen = newtChild.isNativeValid() && newtChild.getGraphicsConfiguration().getChosenCapabilities().isOnscreen();
- final boolean isParent = downstreamParent == newtChild.getParent();
- final boolean isFullscreen = newtChild.isFullscreen();
- if(DEBUG_IMPLEMENTATION) {
- System.err.println("AWT: focusGained: onscreen "+ isOnscreen+", "+e+", isParent: "+isParent+", isFS "+isFullscreen);
- }
- if(isParent) {
- if(isOnscreen && !isFullscreen) {
- KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
+ if( null != newtChild ) {
+ final boolean isOnscreen = newtChild.isNativeValid() && newtChild.getGraphicsConfiguration().getChosenCapabilities().isOnscreen();
+ final boolean isParent = downstreamParent == newtChild.getParent();
+ final boolean isFullscreen = newtChild.isFullscreen();
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("AWT: focusGained: onscreen "+ isOnscreen+", "+e+", isParent: "+isParent+", isFS "+isFullscreen);
+ }
+ if(isParent) {
+ if(isOnscreen && !isFullscreen) {
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
+ }
+ newtChild.requestFocus(false);
}
- newtChild.requestFocus(false);
}
}
- public void focusLost(java.awt.event.FocusEvent e) {
+ @Override
+ public synchronized void focusLost(final java.awt.event.FocusEvent e) {
+ if( !isSetup ) { return; }
if(DEBUG_IMPLEMENTATION) {
System.err.println("AWT: focusLost: "+ e);
}
}
- public void componentResized(java.awt.event.ComponentEvent e) {
+ @Override
+ public synchronized void componentResized(final java.awt.event.ComponentEvent e) {
+ if( !isSetup ) { return; }
// Need to resize the NEWT child window
// the resized event will be send via the native window feedback.
final java.awt.Component comp = e.getComponent();
if(DEBUG_IMPLEMENTATION) {
System.err.println("AWT: componentResized: "+comp);
}
- final Window newtWindow = getNewtWindow();
- newtWindow.runOnEDTIfAvail(false, new Runnable() {
- public void run() {
- int cw = comp.getWidth();
- int ch = comp.getHeight();
- if( 0 < cw * ch ) {
- if( newtWindow.getWidth() != cw || newtWindow.getHeight() != ch ) {
- newtWindow.setSize(cw, ch);
- if(comp.isVisible() != newtWindow.isVisible()) {
- newtWindow.setVisible(comp.isVisible());
+ final Window newtChild = getNewtWindow();
+ if( null != newtChild ) {
+ newtChild.runOnEDTIfAvail(false, new Runnable() {
+ @Override
+ public void run() {
+ final int cw = comp.getWidth();
+ final int ch = comp.getHeight();
+ if( 0 < cw && 0 < ch ) {
+ if( newtChild.getWidth() != cw || newtChild.getHeight() != ch ) {
+ newtChild.setSize(cw, ch);
+ final boolean v = comp.isShowing(); // compute showing-state throughout hierarchy
+ if(v != newtChild.isVisible()) {
+ newtChild.setVisible(v);
+ }
}
+ } else if(newtChild.isVisible()) {
+ newtChild.setVisible(false);
}
- } else if(newtWindow.isVisible()) {
- newtWindow.setVisible(false);
- }
- }});
+ }});
+ }
}
- public void componentMoved(java.awt.event.ComponentEvent e) {
+ @Override
+ public synchronized void componentMoved(final java.awt.event.ComponentEvent e) {
+ if( !isSetup ) { return; }
if(DEBUG_IMPLEMENTATION) {
- System.err.println("AWT: componentMoved: "+e);
+ System.err.println("AWT: componentMoved: "+e);
+ }
+ final Window newtChild = getNewtWindow();
+ if( null != newtChild && ( newtChild.getDelegatedWindow() instanceof DriverUpdatePosition ) ) {
+ ((DriverUpdatePosition)newtChild.getDelegatedWindow()).updatePosition(0, 0);
}
- final Window newtWindow = getNewtWindow();
- if(newtWindow.getDelegatedWindow() instanceof DriverUpdatePosition) {
- ((DriverUpdatePosition)newtWindow.getDelegatedWindow()).updatePosition();
- }
}
- public void windowActivated(java.awt.event.WindowEvent e) {
+ @Override
+ public synchronized void windowActivated(final java.awt.event.WindowEvent e) {
// no propagation to NEWT child window
}
- public void windowDeactivated(java.awt.event.WindowEvent e) {
+ @Override
+ public synchronized void windowDeactivated(final java.awt.event.WindowEvent e) {
// no propagation to NEWT child window
}
- public void hierarchyChanged(java.awt.event.HierarchyEvent e) {
- if( null == getNewtEventListener() ) {
- long bits = e.getChangeFlags();
- final java.awt.Component changed = e.getChanged();
+ @Override
+ public synchronized void hierarchyChanged(final java.awt.event.HierarchyEvent e) {
+ if( !isSetup ) { return; }
+ final Window newtChild = getNewtWindow();
+ if( null != newtChild && null == getNewtEventListener() ) {
+ final long bits = e.getChangeFlags();
+ final java.awt.Component comp = e.getComponent();
if( 0 != ( java.awt.event.HierarchyEvent.SHOWING_CHANGED & bits ) ) {
- final boolean showing = changed.isShowing();
+ final boolean showing = comp.isShowing(); // compute showing-state throughout hierarchy
if(DEBUG_IMPLEMENTATION) {
- System.err.println("AWT: hierarchyChanged SHOWING_CHANGED: showing "+showing+", "+changed+", source "+e.getComponent());
+ System.err.println("AWT: hierarchyChanged SHOWING_CHANGED: showing "+showing+", comp "+comp+", changed "+e.getChanged());
}
- getNewtWindow().runOnEDTIfAvail(false, new Runnable() {
+ newtChild.runOnEDTIfAvail(false, new Runnable() {
+ @Override
public void run() {
- if(getNewtWindow().isVisible() != showing) {
- getNewtWindow().setVisible(showing);
+ if(newtChild.isVisible() != showing) {
+ newtChild.setVisible(showing);
}
}});
- }
+ }
if(DEBUG_IMPLEMENTATION) {
if( 0 != ( java.awt.event.HierarchyEvent.DISPLAYABILITY_CHANGED & bits ) ) {
- final boolean displayability = changed.isDisplayable();
- System.err.println("AWT: hierarchyChanged DISPLAYABILITY_CHANGED: displayability "+displayability+", "+changed);
+ System.err.println("AWT: hierarchyChanged DISPLAYABILITY_CHANGED: "+e.getChanged());
}
}
}
diff --git a/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java b/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java
index 0a824e83b..0ff86fe93 100644
--- a/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java
+++ b/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java
@@ -1,10 +1,10 @@
package jogamp.newt.driver;
-/**
+/**
* Interface tagging driver requirement of clearing the focus.
* <p>
- * Some drivers require a programmatic {@link #clearFocus()} when traversing the focus.
- * </p>
+ * Some drivers require a programmatic {@link #clearFocus()} when traversing the focus.
+ * </p>
*/
public interface DriverClearFocus {
/** Programmatic clear the focus */
diff --git a/src/newt/classes/jogamp/newt/driver/DriverUpdatePosition.java b/src/newt/classes/jogamp/newt/driver/DriverUpdatePosition.java
index bb846c081..e5f9b6a68 100644
--- a/src/newt/classes/jogamp/newt/driver/DriverUpdatePosition.java
+++ b/src/newt/classes/jogamp/newt/driver/DriverUpdatePosition.java
@@ -1,9 +1,15 @@
package jogamp.newt.driver;
-/**
+/**
* Interface tagging driver requirement of absolute positioning, ie. depend on parent position.
*/
public interface DriverUpdatePosition {
- /** Programmatic update the position */
- void updatePosition();
+ /**
+ * Programmatic update the top-left corner
+ * of the client area relative to it's parent.
+ *
+ * @param x x-component
+ * @param y y-component
+ **/
+ void updatePosition(int x, int y);
}
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..43cfa9b25
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/driver/PNGIcon.java
@@ -0,0 +1,80 @@
+/**
+ * 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 jogamp.newt.DisplayImpl;
+
+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 = DisplayImpl.isPNGUtilAvailable() && ReflectionUtil.isClassAvailable("jogamp.newt.driver.opengl.JoglUtilPNGIcon", cl);
+ }
+
+ /** Returns true if PNG decoder is available. */
+ public static boolean isAvailable() {
+ return avail;
+ }
+
+ /**
+ * Special implementation for X11 Window Icons
+ * <p>
+ * The returned byte buffer is a direct buffer!
+ * </p>
+ *
+ * @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(final IOUtil.ClassResources resources, final int[] data_size, final 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);
+ }
+}
diff --git a/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java
index a367462c4..a5f4fc769 100644
--- a/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,7 +20,7 @@
* 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.
@@ -53,14 +53,15 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl {
protected void createNativeImpl() {
// EGL Device
aDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT);
+ aDevice.open();
}
- protected void closeNativeImpl() {
+ protected void closeNativeImpl(final AbstractGraphicsDevice aDevice) {
aDevice.close();
}
protected void dispatchMessagesNative() {
// n/a .. DispatchMessages();
- }
+ }
}
diff --git a/src/newt/classes/jogamp/newt/driver/android/MD.java b/src/newt/classes/jogamp/newt/driver/android/MD.java
index f2f30937b..e6316004b 100644
--- a/src/newt/classes/jogamp/newt/driver/android/MD.java
+++ b/src/newt/classes/jogamp/newt/driver/android/MD.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,13 +20,15 @@
* 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.android;
+import jogamp.common.os.PlatformPropsImpl;
+
import com.jogamp.common.GlueGenVersion;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.VersionUtil;
@@ -34,22 +36,22 @@ import com.jogamp.opengl.JoglVersion;
public class MD {
public static final String TAG = "JogAmp.NEWT";
-
- public static String getInfo() {
- StringBuilder sb = new StringBuilder();
-
- sb.append(VersionUtil.getPlatformInfo()).append(Platform.NEWLINE)
- .append(GlueGenVersion.getInstance()).append(Platform.NEWLINE)
- .append(JoglVersion.getInstance()).append(Platform.NEWLINE)
- .append(Platform.NEWLINE);
-
+
+ public static String getInfo() {
+ final StringBuilder sb = new StringBuilder();
+
+ sb.append(VersionUtil.getPlatformInfo()).append(PlatformPropsImpl.NEWLINE)
+ .append(GlueGenVersion.getInstance()).append(PlatformPropsImpl.NEWLINE)
+ .append(JoglVersion.getInstance()).append(PlatformPropsImpl.NEWLINE)
+ .append(PlatformPropsImpl.NEWLINE);
+
JoglVersion.getDefaultOpenGLInfo(null, sb, true);
- return sb.toString();
+ return sb.toString();
}
-
- public static void main(String args[]) {
-
+
+ public static void main(final String args[]) {
+
System.err.println(getInfo());
}
}
diff --git a/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java b/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java
index 28c4da72f..68d43ac75 100644
--- a/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java
+++ b/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,7 +20,7 @@
* 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.
@@ -32,9 +32,12 @@ import java.util.List;
import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.opengl.FPSCounter;
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
import com.jogamp.newt.Window;
-import com.jogamp.opengl.util.Animator;
+import com.jogamp.opengl.GLEventListenerState;
+import com.jogamp.opengl.GLStateKeeper;
import jogamp.newt.driver.android.WindowDriver;
@@ -46,102 +49,174 @@ import android.view.WindowManager;
public class NewtBaseActivity extends Activity {
List<Window> newtWindows = new ArrayList<Window>();
- Animator animator = null;
-
+ List<GLAutoDrawable> glAutoDrawables = new ArrayList<GLAutoDrawable>();
+
+ GLAnimatorControl animator = null;
+
boolean isDelegatedActivity;
Activity rootActivity;
boolean setThemeCalled = false;
-
+
+ protected void startAnimation(final boolean start) {
+ if(null != animator) {
+ final boolean res;
+ if( start ) {
+ if( animator.isPaused() ) {
+ res = animator.resume();
+ } else {
+ res = animator.start();
+ }
+ } else {
+ res = animator.stop();
+ }
+ Log.d(MD.TAG, "Animator global: start "+start+", result "+res);
+ }
+ for(int i=0; i<glAutoDrawables.size(); i++) {
+ final GLAnimatorControl anim = glAutoDrawables.get(i).getAnimator();
+ if(null != anim) {
+ final boolean res;
+ if( start ) {
+ if( anim.isPaused() ) {
+ res = anim.resume();
+ } else {
+ res = anim.start();
+ }
+ } else {
+ res = anim.stop();
+ }
+ Log.d(MD.TAG, "Animator glad["+i+"]: start "+start+", result "+res);
+ }
+ }
+ }
+
public NewtBaseActivity() {
super();
isDelegatedActivity = false;
rootActivity = this;
}
-
- public void setRootActivity(Activity rootActivity) {
- this.isDelegatedActivity = true;
+
+ public void setRootActivity(final Activity rootActivity) {
this.rootActivity = rootActivity;
+ this.isDelegatedActivity = this != rootActivity;
}
-
+
public final boolean isDelegatedActivity() {
return isDelegatedActivity;
}
-
+
public final Activity getActivity() {
return rootActivity;
- }
-
+ }
+
/**
* This is one of the three registration methods (see below).
* <p>
* This methods issues {@link android.view.Window#setContentView(android.view.View, android.view.ViewGroup.LayoutParams) androidWindow.setContenView(newtWindow.getAndroidView())}
* and finally calls {@link #registerNEWTWindow(Window)}.
- * </p>
+ * </p>
* @param androidWindow
* @param newtWindow
+ * @throws IllegalArgumentException if the <code>newtWindow</code>'s {@link Window#getDelegatedWindow() delegate} is not an AndroidDriver.
+ * @see #registerNEWTWindow(Window)
* @see #addContentView(android.view.Window, Window, android.view.ViewGroup.LayoutParams)
*/
- public void setContentView(android.view.Window androidWindow, Window newtWindow) {
- newtWindow = newtWindow.getDelegatedWindow();
- if(newtWindow instanceof WindowDriver) {
- adaptTheme4Transparency(newtWindow.getRequestedCapabilities());
- layoutForNEWTWindow(androidWindow, newtWindow);
- WindowDriver newtAWindow = (WindowDriver)newtWindow;
+ public void setContentView(final android.view.Window androidWindow, final Window newtWindow) throws IllegalArgumentException {
+ final Window delegateWindow = newtWindow.getDelegatedWindow();
+ if(delegateWindow instanceof WindowDriver) {
+ adaptTheme4Transparency(delegateWindow.getRequestedCapabilities());
+ layoutForNEWTWindow(androidWindow, delegateWindow);
+ final WindowDriver newtAWindow = (WindowDriver)delegateWindow;
androidWindow.setContentView(newtAWindow.getAndroidView());
- registerNEWTWindow(newtAWindow);
} else {
- throw new IllegalArgumentException("Given NEWT Window is not an Android Window: "+newtWindow.getClass());
+ throw new IllegalArgumentException("Given NEWT Window is not an Android Window: "+newtWindow.getClass().getName());
}
+ registerNEWTWindow(newtWindow);
}
/**
* This is one of the three registration methods (see below).
* <p>
* This methods issues {@link android.view.Window#addContentView(android.view.View, android.view.ViewGroup.LayoutParams) androidWindow.addContenView(newtWindow.getAndroidView(), params)}
* and finally calls {@link #registerNEWTWindow(Window)}.
- * </p>
+ * </p>
* @param androidWindow
* @param newtWindow
* @param params
- * @see #setContentView(android.view.Window, Window)
+ * @throws IllegalArgumentException if the <code>newtWindow</code>'s {@link Window#getDelegatedWindow() delegate} is not an AndroidDriver.
* @see #registerNEWTWindow(Window)
+ * @see #setContentView(android.view.Window, Window)
*/
- public void addContentView(android.view.Window androidWindow, Window newtWindow, android.view.ViewGroup.LayoutParams params) {
- newtWindow = newtWindow.getDelegatedWindow();
- if(newtWindow instanceof WindowDriver) {
- WindowDriver newtAWindow = (WindowDriver)newtWindow;
+ public void addContentView(final android.view.Window androidWindow, final Window newtWindow, final android.view.ViewGroup.LayoutParams params) throws IllegalArgumentException {
+ final Window delegateWindow = newtWindow.getDelegatedWindow();
+ if(delegateWindow instanceof WindowDriver) {
+ final WindowDriver newtAWindow = (WindowDriver)delegateWindow;
androidWindow.addContentView(newtAWindow.getAndroidView(), params);
- registerNEWTWindow(newtAWindow);
} else {
- throw new IllegalArgumentException("Given NEWT Window is not an Android Window: "+newtWindow.getClass());
- }
+ throw new IllegalArgumentException("Given NEWT Window's Delegate is not an Android Window: "+delegateWindow.getClass().getName());
+ }
+ registerNEWTWindow(newtWindow);
}
/**
* This is one of the three registration methods (see below).
* <p>
- * This methods simply registers the given NEWT window to ensure it's destruction at {@link #onDestroy()}.
- * </p>
- *
+ * This methods registers the given NEWT window to ensure it's destruction at {@link #onDestroy()}.
+ * </p>
+ * <p>
+ * If adding a {@link GLAutoDrawable} implementation, the {@link GLAnimatorControl} retrieved by {@link GLAutoDrawable#getAnimator()}
+ * will be used for {@link #onPause()} and {@link #onResume()}.
+ * </p>
+ * <p>
+ * If adding a {@link GLAutoDrawable} implementation, the {@link GLEventListenerState} will preserve it's state
+ * when {@link #onPause()} is being called while not {@link #isFinishing()}. A later {@link #onResume()} will
+ * reinstate the {@link GLEventListenerState}.
+ * </p>
+ *
* @param newtWindow
+ * @throws IllegalArgumentException if the <code>newtWindow</code>'s {@link Window#getDelegatedWindow() delegate} is not an AndroidDriver.
* @see #setContentView(android.view.Window, Window)
* @see #addContentView(android.view.Window, Window, android.view.ViewGroup.LayoutParams)
*/
- public void registerNEWTWindow(Window newtWindow) {
+ public void registerNEWTWindow(final Window newtWindow) throws IllegalArgumentException {
+ final Window delegateWindow = newtWindow.getDelegatedWindow();
+ Log.d(MD.TAG, "registerNEWTWindow: Type "+newtWindow.getClass().getName()+", delegate "+delegateWindow.getClass().getName());
+ if(delegateWindow instanceof WindowDriver) {
+ final WindowDriver newtAWindow = (WindowDriver)delegateWindow;
+ newtAWindow.registerActivity(getActivity());
+ } else {
+ throw new IllegalArgumentException("Given NEWT Window's Delegate is not an Android Window: "+delegateWindow.getClass().getName());
+ }
newtWindows.add(newtWindow);
+ if(newtWindow instanceof GLAutoDrawable) {
+ glAutoDrawables.add((GLAutoDrawable)newtWindow);
+ }
+ if(newtWindow instanceof GLStateKeeper) {
+ ((GLStateKeeper)newtWindow).setGLStateKeeperListener(glStateKeeperListener);
+ }
}
-
+ private final GLStateKeeper.Listener glStateKeeperListener = new GLStateKeeper.Listener() {
+ @Override
+ public void glStatePreserveNotify(final GLStateKeeper glsk) {
+ Log.d(MD.TAG, "GLStateKeeper Preserving: 0x"+Integer.toHexString(glsk.hashCode()));
+ }
+ @Override
+ public void glStateRestored(final GLStateKeeper glsk) {
+ Log.d(MD.TAG, "GLStateKeeper Restored: 0x"+Integer.toHexString(glsk.hashCode()));
+ startAnimation(true);
+ }
+ };
+
/**
- * Convenient method to set the Android window's flags to fullscreen or size-layout depending on the given NEWT window.
+ * Convenient method to set the Android window's flags to fullscreen or size-layout depending on the given NEWT window.
* <p>
* Must be called before creating the view and adding any content, i.e. setContentView() !
* </p>
* @param androidWindow
* @param newtWindow
*/
- public void layoutForNEWTWindow(android.view.Window androidWindow, Window newtWindow) {
+ public void layoutForNEWTWindow(final android.view.Window androidWindow, final Window newtWindow) {
if(null == androidWindow || null == newtWindow) {
throw new IllegalArgumentException("Android or NEWT Window null");
}
-
+
if( newtWindow.isFullscreen() || newtWindow.isUndecorated() ) {
androidWindow.requestFeature(android.view.Window.FEATURE_NO_TITLE);
}
@@ -150,27 +225,27 @@ public class NewtBaseActivity extends Activity {
androidWindow.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
} else {
androidWindow.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
- androidWindow.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ androidWindow.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
-
- if(newtWindow.getWidth()>0 && newtWindow.getHeight()>0 && !newtWindow.isFullscreen()) {
+
+ if(newtWindow.getWidth()>0 && newtWindow.getHeight()>0 && !newtWindow.isFullscreen()) {
androidWindow.setLayout(newtWindow.getWidth(), newtWindow.getHeight());
- }
+ }
}
/**
- * Convenient method to set the Android window's flags to fullscreen or size-layout depending on the given NEWT window.
+ * Convenient method to set the Android window's flags to fullscreen or size-layout depending on the given NEWT window.
* <p>
* Must be called before creating the view and adding any content, i.e. setContentView() !
* </p>
* @param androidWindow
* @param newtWindow
*/
- public void setFullscreenFeature(android.view.Window androidWindow, boolean fullscreen) {
+ public void setFullscreenFeature(final android.view.Window androidWindow, final boolean fullscreen) {
if(null == androidWindow) {
throw new IllegalArgumentException("Android or Window null");
}
-
+
if( fullscreen ) {
androidWindow.requestFeature(android.view.Window.FEATURE_NO_TITLE);
androidWindow.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
@@ -180,19 +255,19 @@ public class NewtBaseActivity extends Activity {
androidWindow.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
-
+
/**
- * Convenient method to set this context's theme to transparency depending on {@link CapabilitiesImmutable#isBackgroundOpaque()}.
+ * Convenient method to set this context's theme to transparency depending on {@link CapabilitiesImmutable#isBackgroundOpaque()}.
* <p>
* Must be called before creating the view and adding any content, i.e. setContentView() !
* </p>
*/
- protected void adaptTheme4Transparency(CapabilitiesImmutable caps) {
+ protected void adaptTheme4Transparency(final CapabilitiesImmutable caps) {
if(!caps.isBackgroundOpaque()) {
setTransparencyTheme();
}
}
-
+
/**
* Convenient method to set this context's theme to transparency.
* <p>
@@ -204,12 +279,12 @@ public class NewtBaseActivity extends Activity {
* </p>
* <p>
* Can be called only once.
- * </p>
+ * </p>
*/
public void setTransparencyTheme() {
if(!setThemeCalled) {
setThemeCalled = true;
- final Context ctx = getActivity().getApplicationContext();
+ final Context ctx = getActivity().getApplicationContext();
final String frn = ctx.getPackageName()+":style/Theme.Transparent";
final int resID = ctx.getResources().getIdentifier("Theme.Transparent", "style", ctx.getPackageName());
if(0 == resID) {
@@ -220,48 +295,72 @@ public class NewtBaseActivity extends Activity {
}
}
}
-
- public void setAnimator(Animator animator) {
+
+ /**
+ * Setting up a global {@Link GLAnimatorControl} for {@link #onPause()} and {@link #onResume()}.
+ * <p>
+ * Note that if adding a {@link GLAutoDrawable} implementation via {@link #registerNEWTWindow(Window)},
+ * {@link #setContentView(android.view.Window, Window)} or {@link #addContentView(android.view.Window, Window, android.view.ViewGroup.LayoutParams)}
+ * their {@link GLAnimatorControl} retrieved by {@link GLAutoDrawable#getAnimator()} will be used as well.
+ * In this case, using this global {@Link GLAnimatorControl} is redundant.
+ * </p>
+ * @see #registerNEWTWindow(Window)
+ * @see #setContentView(android.view.Window, Window)
+ * @see #addContentView(android.view.Window, Window, android.view.ViewGroup.LayoutParams)
+ */
+ public void setAnimator(final GLAnimatorControl animator) {
this.animator = animator;
if(!animator.isStarted()) {
animator.start();
}
animator.pause();
}
-
+
@Override
public android.view.Window getWindow() {
- return getActivity().getWindow();
+ if( isDelegatedActivity() ) {
+ return getActivity().getWindow();
+ } else {
+ return super.getWindow();
+ }
}
-
+
@Override
- public void onCreate(Bundle savedInstanceState) {
- Log.d(MD.TAG, "onCreate");
+ public void onCreate(final Bundle savedInstanceState) {
+ Log.d(MD.TAG, "onCreate.0");
if(!isDelegatedActivity()) {
super.onCreate(savedInstanceState);
}
+ // Extraordinary cleanup, for cases of 'onCreate()' calls w/ valid states,
+ // i.e. w/o having onDestroy() being called.
+ // Could happened due to spec when App process is killed for memory exhaustion or other reasons.
+ cleanup();
+
jogamp.common.os.android.StaticContext.init(rootActivity.getApplicationContext());
+ Log.d(MD.TAG, "onCreate.X");
}
-
+
@Override
public void onStart() {
- Log.d(MD.TAG, "onStart");
+ Log.d(MD.TAG, "onStart.0");
if(!isDelegatedActivity()) {
super.onStart();
}
+ Log.d(MD.TAG, "onStart.X");
}
-
+
@Override
public void onRestart() {
- Log.d(MD.TAG, "onRestart");
+ Log.d(MD.TAG, "onRestart.0");
if(!isDelegatedActivity()) {
super.onRestart();
}
+ Log.d(MD.TAG, "onRestart.X");
}
@Override
public void onResume() {
- Log.d(MD.TAG, "onResume");
+ Log.d(MD.TAG, "onResume.0");
if(!isDelegatedActivity()) {
super.onResume();
}
@@ -272,49 +371,93 @@ public class NewtBaseActivity extends Activity {
((FPSCounter)win).resetFPSCounter();
}
}
- if(null != animator) {
- animator.resume();
- animator.resetFPSCounter();
- }
+ startAnimation(true);
+ Log.d(MD.TAG, "onResume.X");
}
@Override
public void onPause() {
- Log.d(MD.TAG, "onPause");
- if(null != animator) {
- animator.pause();
- }
- for(int i=0; i<newtWindows.size(); i++) {
- final Window win = newtWindows.get(i);
- win.setVisible(false);
+ Log.d(MD.TAG, "onPause.0");
+ if( !getActivity().isFinishing() ) {
+ int ok=0, fail=0;
+ for(int i=0; i<glAutoDrawables.size(); i++) {
+ final GLAutoDrawable glad = glAutoDrawables.get(i);
+ if(glad instanceof GLStateKeeper) {
+ if( ((GLStateKeeper)glad).preserveGLStateAtDestroy(true) ) {
+ ok++;
+ } else {
+ fail++;
+ }
+ }
+ }
+ Log.d(MD.TAG, "GLStateKeeper.Mark2Preserve: Total "+glAutoDrawables.size()+", OK "+ok+", Fail "+fail);
}
- if(!isDelegatedActivity()) {
+ startAnimation(false);
+ if( !isDelegatedActivity() ) {
super.onPause();
}
+ Log.d(MD.TAG, "onPause.X");
}
@Override
public void onStop() {
- Log.d(MD.TAG, "onStop");
- if(!isDelegatedActivity()) {
- super.onStop();
+ Log.d(MD.TAG, "onStop.0");
+ for(int i=0; i<newtWindows.size(); i++) {
+ final Window win = newtWindows.get(i);
+ win.setVisible(false);
+ }
+ if( !isDelegatedActivity() ) {
+ super.onStop();
}
+ Log.d(MD.TAG, "onStop.X");
}
- @Override
- public void onDestroy() {
- Log.d(MD.TAG, "onDestroy");
- if(null != animator) {
- animator.stop();
- animator = null;
+ /**
+ * Performs cleaning up all references,
+ * <p>
+ * Cleaning and destroying up all preserved GLEventListenerState
+ * and clearing the preserve-flag of all GLStateKeeper.
+ * </p>
+ * <p>
+ * Destroying all GLWindow.
+ * </p>
+ */
+ private void cleanup() {
+ Log.d(MD.TAG, "cleanup.0");
+ int glelsKilled = 0, glelsClean = 0;
+ for(int i=0; i<glAutoDrawables.size(); i++) {
+ final GLAutoDrawable glad = glAutoDrawables.get(i);
+ if(glad instanceof GLStateKeeper) {
+ final GLStateKeeper glsk = (GLStateKeeper)glad;
+ glsk.preserveGLStateAtDestroy(false);
+ final GLEventListenerState glels = glsk.clearPreservedGLState();
+ if( null != glels) {
+ glels.destroy();
+ glelsKilled++;
+ } else {
+ glelsClean++;
+ }
+ }
}
- while(newtWindows.size()>0) {
- final Window win = newtWindows.remove(newtWindows.size()-1);
+ Log.d(MD.TAG, "cleanup.1: GLStateKeeper.ForceDestroy: Total "+glAutoDrawables.size()+", destroyed "+glelsKilled+", clean "+glelsClean);
+ for(int i=0; i<newtWindows.size(); i++) {
+ final Window win = newtWindows.get(i);
win.destroy();
}
+ newtWindows.clear();
+ glAutoDrawables.clear();
+ Log.d(MD.TAG, "cleanup.1: StaticContext.getContext: "+jogamp.common.os.android.StaticContext.getContext());
jogamp.common.os.android.StaticContext.clear();
+ Log.d(MD.TAG, "cleanup.X");
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.d(MD.TAG, "onDestroy.0");
+ cleanup(); // normal cleanup
if(!isDelegatedActivity()) {
- super.onDestroy();
+ super.onDestroy();
}
- }
+ Log.d(MD.TAG, "onDestroy.X");
+ }
}
diff --git a/src/newt/classes/jogamp/newt/driver/android/NewtVersionActivity.java b/src/newt/classes/jogamp/newt/driver/android/NewtVersionActivity.java
index a49f1648c..4dd96c9a0 100644
--- a/src/newt/classes/jogamp/newt/driver/android/NewtVersionActivity.java
+++ b/src/newt/classes/jogamp/newt/driver/android/NewtVersionActivity.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,7 +20,7 @@
* 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.
@@ -33,6 +33,8 @@ import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
+import jogamp.common.os.PlatformPropsImpl;
+
import com.jogamp.common.GlueGenVersion;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.VersionUtil;
@@ -47,58 +49,75 @@ import android.widget.ScrollView;
import android.widget.TextView;
public class NewtVersionActivity extends NewtBaseActivity {
+
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
+
setFullscreenFeature(getWindow(), true);
final android.view.ViewGroup viewGroup = new android.widget.FrameLayout(getActivity().getApplicationContext());
getWindow().setContentView(viewGroup);
-
+
final TextView tv = new TextView(getActivity());
final ScrollView scroller = new ScrollView(getActivity());
scroller.addView(tv);
viewGroup.addView(scroller, new android.widget.FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.TOP|Gravity.LEFT));
-
- tv.setText(VersionUtil.getPlatformInfo()+Platform.NEWLINE+GlueGenVersion.getInstance()+Platform.NEWLINE+JoglVersion.getInstance()+Platform.NEWLINE);
-
- // create GLWindow (-> incl. underlying NEWT Display, Screen & Window)
- GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GLES2));
- GLWindow glWindow = GLWindow.create(caps);
- glWindow.setUndecorated(true);
- glWindow.setSize(32, 32);
- glWindow.setPosition(0, 0);
- final android.view.View androidGLView = ((WindowDriver)glWindow.getDelegatedWindow()).getAndroidView();
- viewGroup.addView(androidGLView, new android.widget.FrameLayout.LayoutParams(glWindow.getWidth(), glWindow.getHeight(), Gravity.BOTTOM|Gravity.RIGHT));
- registerNEWTWindow(glWindow);
-
- glWindow.addGLEventListener(new GLEventListener() {
- public void init(GLAutoDrawable drawable) {
- GL gl = drawable.getGL();
- final StringBuffer sb = new StringBuffer();
- sb.append(JoglVersion.getGLInfo(gl, null)).append(Platform.NEWLINE);
- sb.append("Requested: ").append(Platform.NEWLINE);
- sb.append(drawable.getNativeSurface().getGraphicsConfiguration().getRequestedCapabilities()).append(Platform.NEWLINE).append(Platform.NEWLINE);
- sb.append("Chosen: ").append(Platform.NEWLINE);
- sb.append(drawable.getChosenGLCapabilities()).append(Platform.NEWLINE).append(Platform.NEWLINE);
- viewGroup.post(new Runnable() {
- public void run() {
- tv.append(sb.toString());
- viewGroup.removeView(androidGLView);
- } } );
- }
- public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
- }
+ final String info1 = "JOGL Version Info"+PlatformPropsImpl.NEWLINE+VersionUtil.getPlatformInfo()+PlatformPropsImpl.NEWLINE+GlueGenVersion.getInstance()+PlatformPropsImpl.NEWLINE+JoglVersion.getInstance()+PlatformPropsImpl.NEWLINE;
+ Log.d(MD.TAG, info1);
+ tv.setText(info1);
+
+ final GLProfile glp;
+ if( GLProfile.isAvailable(GLProfile.GL2ES2) ) {
+ glp = GLProfile.get(GLProfile.GL2ES2);
+ } else if( GLProfile.isAvailable(GLProfile.GL2ES1) ) {
+ glp = GLProfile.get(GLProfile.GL2ES1);
+ } else {
+ glp = null;
+ tv.append("No GLProfile GL2ES2 nor GL2ES1 available!");
+ }
+ if( null != glp ) {
+ // create GLWindow (-> incl. underlying NEWT Display, Screen & Window)
+ final GLCapabilities caps = new GLCapabilities(glp);
+ final GLWindow glWindow = GLWindow.create(caps);
+ glWindow.setUndecorated(true);
+ glWindow.setSize(32, 32);
+ glWindow.setPosition(0, 0);
+ final android.view.View androidGLView = ((WindowDriver)glWindow.getDelegatedWindow()).getAndroidView();
+ viewGroup.addView(androidGLView, new android.widget.FrameLayout.LayoutParams(glWindow.getSurfaceWidth(), glWindow.getSurfaceHeight(), Gravity.BOTTOM|Gravity.RIGHT));
+ registerNEWTWindow(glWindow);
+
+ glWindow.addGLEventListener(new GLEventListener() {
+ public void init(final GLAutoDrawable drawable) {
+ final GL gl = drawable.getGL();
+ final StringBuilder sb = new StringBuilder();
+ sb.append(JoglVersion.getGLInfo(gl, null, true)).append(PlatformPropsImpl.NEWLINE);
+ sb.append("Requested: ").append(PlatformPropsImpl.NEWLINE);
+ sb.append(drawable.getNativeSurface().getGraphicsConfiguration().getRequestedCapabilities()).append(PlatformPropsImpl.NEWLINE).append(PlatformPropsImpl.NEWLINE);
+ sb.append("Chosen: ").append(PlatformPropsImpl.NEWLINE);
+ sb.append(drawable.getChosenGLCapabilities()).append(PlatformPropsImpl.NEWLINE).append(PlatformPropsImpl.NEWLINE);
+ final String info2 = sb.toString();
+ // Log.d(MD.TAG, info2); // too big!
+ System.err.println(info2);
+ viewGroup.post(new Runnable() {
+ public void run() {
+ tv.append(info2);
+ viewGroup.removeView(androidGLView);
+ } } );
+ }
+
+ public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
+ }
- public void display(GLAutoDrawable drawable) {
- }
+ public void display(final GLAutoDrawable drawable) {
+ }
- public void dispose(GLAutoDrawable drawable) {
- }
- });
- glWindow.setVisible(true);
+ public void dispose(final GLAutoDrawable drawable) {
+ }
+ });
+ glWindow.setVisible(true);
+ }
Log.d(MD.TAG, "onCreate - X");
- }
+ }
}
diff --git a/src/newt/classes/jogamp/newt/driver/android/NewtVersionActivityLauncher.java b/src/newt/classes/jogamp/newt/driver/android/NewtVersionActivityLauncher.java
index cb8799b19..190f55e71 100644
--- a/src/newt/classes/jogamp/newt/driver/android/NewtVersionActivityLauncher.java
+++ b/src/newt/classes/jogamp/newt/driver/android/NewtVersionActivityLauncher.java
@@ -8,14 +8,14 @@ import android.util.Log;
public class NewtVersionActivityLauncher extends Activity {
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- final Uri uri = Uri.parse("launch://jogamp.org/jogamp.newt.driver.android.NewtVersionActivity");
- final Intent intent = new Intent("org.jogamp.launcher.action.LAUNCH_ACTIVITY_NORMAL", uri);
+
+ final Uri uri = Uri.parse("launch://jogamp.org/jogamp.newt.driver.android.NewtVersionActivity?sys=com.jogamp.common&sys=javax.media.opengl&pkg=com.jogamp.opengl.test&jogamp.debug=all&nativewindow.debug=all&jogl.debug=all&newt.debug=all");
+ final Intent intent = new Intent("org.jogamp.launcher.action.LAUNCH_ACTIVITY_NORMAL", uri);
Log.d(getClass().getSimpleName(), "Launching Activity: "+intent);
startActivity (intent);
-
+
finish(); // done
- }
+ }
}
diff --git a/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java
index 795aac5fb..b28cdcbed 100644
--- a/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,7 +20,7 @@
* 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.
@@ -28,12 +28,10 @@
package jogamp.newt.driver.android;
-import javax.media.nativewindow.*;
-import javax.media.nativewindow.util.Dimension;
-import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.DefaultGraphicsScreen;
-import com.jogamp.newt.ScreenMode;
-import com.jogamp.newt.util.ScreenModeUtil;
+import jogamp.newt.MonitorModeProps;
+import jogamp.newt.MonitorModeProps.Cache;
import android.content.Context;
import android.graphics.PixelFormat;
@@ -41,6 +39,9 @@ import android.util.DisplayMetrics;
import android.view.Surface;
import android.view.WindowManager;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+
public class ScreenDriver extends jogamp.newt.ScreenImpl {
static {
@@ -50,59 +51,103 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl {
public ScreenDriver() {
}
+ @Override
protected void createNativeImpl() {
aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx);
}
+ @Override
protected void closeNativeImpl() { }
- protected ScreenMode getCurrentScreenModeImpl() {
+ @Override
+ protected int validateScreenIndex(final int idx) {
+ return 0; // FIXME: only one screen available ?
+ }
+
+ private final MonitorMode getModeImpl(final Cache cache, final android.view.Display aDisplay, final DisplayMetrics outMetrics, final int modeIdx, final int screenSizeNRot, final int nrot) {
+ final int[] props = new int[MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL];
+ int i = 0;
+ props[i++] = MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL;
+ i = getScreenSize(outMetrics, screenSizeNRot, props, i); // width, height
+ i = getBpp(aDisplay, props, i); // bpp
+ props[i++] = (int) ( aDisplay.getRefreshRate() * 100.0f ); // Hz * 100
+ props[i++] = 0; // flags
+ props[i++] = modeIdx; // modeId;
+ props[i++] = nrot;
+ return MonitorModeProps.streamInMonitorMode(null, cache, props, 0);
+ }
+
+ @Override
+ protected void collectNativeMonitorModesAndDevicesImpl(final Cache cache) {
+ // FIXME: Multi Monitor Implementation missing [for newer Android version ?]
+
final Context ctx = jogamp.common.os.android.StaticContext.getContext();
final WindowManager wmgr = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
final DisplayMetrics outMetrics = new DisplayMetrics();
final android.view.Display aDisplay = wmgr.getDefaultDisplay();
aDisplay.getMetrics(outMetrics);
-
+
final int arot = aDisplay.getRotation();
final int nrot = androidRotation2NewtRotation(arot);
- int[] props = new int[ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL];
- int offset = 1; // set later for verification of iterator
- offset = getScreenSize(outMetrics, nrot, props, offset);
- offset = getBpp(aDisplay, props, offset);
- offset = getScreenSizeMM(outMetrics, props, offset);
- props[offset++] = (int) aDisplay.getRefreshRate();
- props[offset++] = nrot;
- props[offset - ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL] = offset; // count
- return ScreenModeUtil.streamIn(props, 0);
+
+ final int modeIdx=0; // no native modeId in use - use 0
+ MonitorMode currentMode = null;
+ for(int r=0; r<4; r++) { // for all rotations
+ final int nrot_i = r*MonitorMode.ROTATE_90;
+ final MonitorMode mode = getModeImpl(cache, aDisplay, outMetrics, modeIdx, 0, nrot_i);
+ if( nrot == nrot_i ) {
+ currentMode = mode;
+ }
+ }
+
+ final int[] props = new int[MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES - 1 - MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES];
+ int i = 0;
+ props[i++] = props.length;
+ props[i++] = 0; // crt_idx
+ i = getScreenSizeMM(outMetrics, props, i); // sizeMM
+ props[i++] = 0; // rotated viewport x pixel-units
+ props[i++] = 0; // rotated viewport y pixel-units
+ props[i++] = outMetrics.widthPixels; // rotated viewport width pixel-units
+ props[i++] = outMetrics.heightPixels; // rotated viewport height pixel-units
+ props[i++] = 0; // rotated viewport x window-units
+ props[i++] = 0; // rotated viewport y window-units
+ props[i++] = outMetrics.widthPixels; // rotated viewport width window-units
+ props[i++] = outMetrics.heightPixels; // rotated viewport height window-units
+ MonitorModeProps.streamInMonitorDevice(null, cache, this, cache.monitorModes, currentMode, props, 0);
}
-
- protected int validateScreenIndex(int idx) {
- return 0; // FIXME: only one screen available ?
+
+ @Override
+ protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) {
+ final Context ctx = jogamp.common.os.android.StaticContext.getContext();
+ final WindowManager wmgr = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
+ final DisplayMetrics outMetrics = new DisplayMetrics();
+ final android.view.Display aDisplay = wmgr.getDefaultDisplay();
+ aDisplay.getMetrics(outMetrics);
+
+ final int currNRot = androidRotation2NewtRotation(aDisplay.getRotation());
+ return getModeImpl(null, aDisplay, outMetrics, 0, currNRot, currNRot);
}
-
- protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) {
- virtualOrigin.setX(0);
- virtualOrigin.setY(0);
- final ScreenMode sm = getCurrentScreenMode();
- virtualSize.setWidth(sm.getRotatedWidth());
- virtualSize.setHeight(sm.getRotatedHeight());
+
+ @Override
+ protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) {
+ return false;
}
-
+
//----------------------------------------------------------------------
// Internals only
//
- static int androidRotation2NewtRotation(int arot) {
+ static int androidRotation2NewtRotation(final int arot) {
switch(arot) {
- case Surface.ROTATION_270: return ScreenMode.ROTATE_270;
- case Surface.ROTATION_180: return ScreenMode.ROTATE_180;
- case Surface.ROTATION_90: return ScreenMode.ROTATE_90;
+ case Surface.ROTATION_270: return MonitorMode.ROTATE_270;
+ case Surface.ROTATION_180: return MonitorMode.ROTATE_180;
+ case Surface.ROTATION_90: return MonitorMode.ROTATE_90;
case Surface.ROTATION_0:
}
- return ScreenMode.ROTATE_0;
+ return MonitorMode.ROTATE_0;
}
- static int getScreenSize(DisplayMetrics outMetrics, int nrot, int[] props, int offset) {
+ static int getScreenSize(final DisplayMetrics outMetrics, final int nrot, final int[] props, int offset) {
// swap width and height, since Android reflects rotated dimension, we don't
- if (ScreenMode.ROTATE_90 == nrot || ScreenMode.ROTATE_270 == nrot) {
+ if (MonitorMode.ROTATE_90 == nrot || MonitorMode.ROTATE_270 == nrot) {
props[offset++] = outMetrics.heightPixels;
props[offset++] = outMetrics.widthPixels;
} else {
@@ -110,8 +155,8 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl {
props[offset++] = outMetrics.heightPixels;
}
return offset;
- }
- static int getBpp(android.view.Display aDisplay, int[] props, int offset) {
+ }
+ static int getBpp(final android.view.Display aDisplay, final int[] props, int offset) {
int bpp;
switch(aDisplay.getPixelFormat()) {
case PixelFormat.RGBA_8888: bpp=32; break;
@@ -121,18 +166,28 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl {
case PixelFormat.RGBA_5551: bpp=16; break;
case PixelFormat.RGBA_4444: bpp=16; break;
case PixelFormat.RGB_332: bpp= 8; break;
- default: bpp=32;
- }
- props[offset++] = bpp;
+ default: bpp=32;
+ }
+ props[offset++] = bpp;
return offset;
}
- static int getScreenSizeMM(DisplayMetrics outMetrics, int[] props, int offset) {
- final float iw = (float) outMetrics.widthPixels / outMetrics.xdpi;
- final float ih = (float) outMetrics.heightPixels / outMetrics.xdpi;
+ static int getScreenSizeMM(final DisplayMetrics outMetrics, final int[] props, int offset) {
+ final float inW = outMetrics.widthPixels / outMetrics.xdpi;
+ final float inH = outMetrics.heightPixels / outMetrics.ydpi;
final float mmpi = 25.4f;
- props[offset++] = (int) ((iw * mmpi)+0.5);
- props[offset++] = (int) ((ih * mmpi)+0.5);
+ final float mmW = inW * mmpi;
+ final float mmH = inH * mmpi;
+ if( DEBUG ) {
+ System.err.println("Screen A screen "+outMetrics.widthPixels+" x "+outMetrics.heightPixels);
+ System.err.println("Screen A xy dpi "+outMetrics.xdpi+" x "+outMetrics.ydpi);
+ System.err.println("Screen A densityDPI "+outMetrics.densityDpi);
+ System.err.println("Screen A density "+outMetrics.density);
+ System.err.println("Screen N xy inch "+inW+" x "+inH);
+ System.err.println("Screen N xy mm "+mmW+" x "+mmH);
+ }
+ props[offset++] = Math.round(mmW);
+ props[offset++] = Math.round(mmH);
return offset;
- }
+ }
}
diff --git a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java
index f18520630..786ebb31c 100644
--- a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,7 +20,7 @@
* 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.
@@ -29,53 +29,144 @@
package jogamp.newt.driver.android;
import jogamp.common.os.android.StaticContext;
+import jogamp.newt.WindowImpl;
import jogamp.newt.driver.android.event.AndroidNewtEventFactory;
+import jogamp.newt.driver.android.event.AndroidNewtEventTranslator;
+import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.Capabilities;
import javax.media.nativewindow.CapabilitiesImmutable;
+import javax.media.nativewindow.DefaultGraphicsScreen;
import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.VisualIDHolder;
import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.util.Rectangle;
+import javax.media.nativewindow.util.RectangleImmutable;
import javax.media.opengl.GLCapabilitiesChooser;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLException;
+import com.jogamp.common.os.AndroidVersion;
import com.jogamp.nativewindow.egl.EGLGraphicsDevice;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.Window;
import jogamp.opengl.egl.EGL;
+import jogamp.opengl.egl.EGLDisplayUtil;
import jogamp.opengl.egl.EGLGraphicsConfiguration;
import jogamp.opengl.egl.EGLGraphicsConfigurationFactory;
-
+import android.app.Activity;
import android.content.Context;
+import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Looper;
import android.os.ResultReceiver;
import android.util.Log;
+import android.view.Gravity;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback2;
+import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.view.SurfaceView;
-import android.view.View;
+import android.view.KeyEvent;
-public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
+
+public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
static {
DisplayDriver.initSingleton();
}
- public static CapabilitiesImmutable fixCaps(boolean matchFormatPrecise, int format, CapabilitiesImmutable rCaps) {
- PixelFormat pf = new PixelFormat();
+ /**
+ * First stage of selecting an Android PixelFormat,
+ * at construction via {@link SurfaceHolder#setFormat(int)}
+ * before native realization!
+ *
+ * @param rCaps requested Capabilities
+ * @return An Android PixelFormat number suitable for {@link SurfaceHolder#setFormat(int)}.
+ */
+ public static final int getSurfaceHolderFormat(final CapabilitiesImmutable rCaps) {
+ int fmt = PixelFormat.UNKNOWN;
+
+ if( !rCaps.isBackgroundOpaque() ) {
+ fmt = PixelFormat.TRANSLUCENT;
+ } else if( rCaps.getRedBits()<=5 &&
+ rCaps.getGreenBits()<=6 &&
+ rCaps.getBlueBits()<=5 &&
+ rCaps.getAlphaBits()==0 ) {
+ fmt = PixelFormat.RGB_565;
+ } else if( rCaps.getAlphaBits()==0 ) {
+ fmt = PixelFormat.RGB_888;
+ } else {
+ fmt = PixelFormat.RGBA_8888;
+ }
+ Log.d(MD.TAG, "getSurfaceHolderFormat: requested: "+rCaps);
+ Log.d(MD.TAG, "getSurfaceHolderFormat: returned: "+fmt);
+
+ return fmt;
+ }
+
+
+ public static final int NATIVE_WINDOW_FORMAT_RGBA_8888 = 1;
+ public static final int NATIVE_WINDOW_FORMAT_RGBX_8888 = 2;
+ public static final int NATIVE_WINDOW_FORMAT_RGB_565 = 4;
+
+ /**
+ * Second stage of selecting an Android PixelFormat,
+ * at right after native (surface) realization at {@link Callback2#surfaceChanged(SurfaceHolder, int, int, int)}.
+ * Selection happens via {@link #setSurfaceVisualID0(long, int)} before native EGL creation.
+ *
+ * @param androidPixelFormat An Android PixelFormat delivered via {@link Callback2#surfaceChanged(SurfaceHolder, int, int, int)} params.
+ * @return A native Android PixelFormat number suitable for {@link #setSurfaceVisualID0(long, int)}.
+ */
+ public static final int getANativeWindowFormat(final int androidPixelFormat) {
+ final int nativePixelFormat;
+ switch(androidPixelFormat) {
+ case PixelFormat.RGBA_8888:
+ case PixelFormat.RGBA_5551:
+ case PixelFormat.RGBA_4444:
+ nativePixelFormat = NATIVE_WINDOW_FORMAT_RGBA_8888;
+ break;
+
+ case PixelFormat.RGBX_8888:
+ case PixelFormat.RGB_888:
+ nativePixelFormat = NATIVE_WINDOW_FORMAT_RGBX_8888;
+ break;
+
+ case PixelFormat.RGB_565:
+ case PixelFormat.RGB_332:
+ nativePixelFormat = NATIVE_WINDOW_FORMAT_RGB_565;
+ break;
+ default: nativePixelFormat = NATIVE_WINDOW_FORMAT_RGBA_8888;
+ }
+ Log.d(MD.TAG, "getANativeWindowFormat: android: "+androidPixelFormat+" -> native "+nativePixelFormat);
+ return nativePixelFormat;
+ }
+
+ /**
+ * Final stage of Android PixelFormat operation,
+ * match the requested Capabilities w/ Android PixelFormat number.
+ * This is done at native realization @ {@link Callback2#surfaceChanged(SurfaceHolder, int, int, int)}.
+ *
+ * @param matchFormatPrecise
+ * @param format
+ * @param rCaps requested Capabilities
+ * @return The fixed Capabilities
+ */
+ public static final CapabilitiesImmutable fixCaps(final boolean matchFormatPrecise, final int format, final CapabilitiesImmutable rCaps) {
+ final PixelFormat pf = new PixelFormat();
PixelFormat.getPixelFormatInfo(format, pf);
- final CapabilitiesImmutable res;
+ final CapabilitiesImmutable res;
int r, g, b, a;
-
+
switch(format) {
- case PixelFormat.RGBA_8888: r=8; g=8; b=8; a=8; break;
- case PixelFormat.RGBX_8888: r=8; g=8; b=8; a=0; break;
+ case PixelFormat.RGBA_8888: r=8; g=8; b=8; a=8; break; // NATIVE_WINDOW_FORMAT_RGBA_8888
+ case PixelFormat.RGBX_8888: r=8; g=8; b=8; a=0; break; // NATIVE_WINDOW_FORMAT_RGBX_8888
case PixelFormat.RGB_888: r=8; g=8; b=8; a=0; break;
- case PixelFormat.RGB_565: r=5; g=6; b=5; a=0; break;
+ case PixelFormat.RGB_565: r=5; g=6; b=5; a=0; break; // NATIVE_WINDOW_FORMAT_RGB_565
case PixelFormat.RGBA_5551: r=5; g=5; b=5; a=1; break;
case PixelFormat.RGBA_4444: r=4; g=4; b=4; a=4; break;
case PixelFormat.RGB_332: r=3; g=3; b=2; a=0; break;
@@ -86,51 +177,25 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
rCaps.getGreenBits() > g &&
rCaps.getBlueBits() > b &&
rCaps.getAlphaBits() > a ;
-
+
if(change) {
- Capabilities nCaps = (Capabilities) rCaps.cloneMutable();
+ final Capabilities nCaps = (Capabilities) rCaps.cloneMutable();
nCaps.setRedBits(r);
nCaps.setGreenBits(g);
nCaps.setBlueBits(b);
nCaps.setAlphaBits(a);
- res = nCaps;
+ res = nCaps;
} else {
res = rCaps;
}
Log.d(MD.TAG, "fixCaps: format: "+format);
Log.d(MD.TAG, "fixCaps: requested: "+rCaps);
Log.d(MD.TAG, "fixCaps: chosen: "+res);
-
+
return res;
}
-
- public static int getFormat(CapabilitiesImmutable rCaps) {
- int fmt = PixelFormat.UNKNOWN;
-
- if(!rCaps.isBackgroundOpaque()) {
- fmt = PixelFormat.TRANSLUCENT;
- } else if(rCaps.getRedBits()<=5 &&
- rCaps.getGreenBits()<=6 &&
- rCaps.getBlueBits()<=5 &&
- rCaps.getAlphaBits()==0) {
- fmt = PixelFormat.RGB_565;
- }
- /* else if(rCaps.getRedBits()<=5 &&
- rCaps.getGreenBits()<=5 &&
- rCaps.getBlueBits()<=5 &&
- rCaps.getAlphaBits()==1) {
- fmt = PixelFormat.RGBA_5551; // FIXME: Supported ?
- } */
- else {
- fmt = PixelFormat.RGBA_8888;
- }
- Log.d(MD.TAG, "getFormat: requested: "+rCaps);
- Log.d(MD.TAG, "getFormat: returned: "+fmt);
-
- return fmt;
- }
-
- public static boolean isAndroidFormatTransparent(int aFormat) {
+
+ public static final boolean isAndroidFormatTransparent(final int aFormat) {
switch (aFormat) {
case PixelFormat.TRANSLUCENT:
case PixelFormat.TRANSPARENT:
@@ -138,53 +203,22 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
}
return false;
}
-
- class AndroidEvents implements View.OnKeyListener, View.OnTouchListener, View.OnFocusChangeListener {
-
- @Override
- public boolean onTouch(View v, android.view.MotionEvent event) {
- final com.jogamp.newt.event.MouseEvent[] newtEvents = AndroidNewtEventFactory.createMouseEvents(event, WindowDriver.this);
- if(null != newtEvents) {
- focusChanged(false, true);
- for(int i=0; i<newtEvents.length; i++) {
- WindowDriver.this.enqueueEvent(false, newtEvents[i]);
- }
- try { Thread.sleep((long) (1000.0F/30.0F)); }
- catch(InterruptedException e) { }
- return true; // consumed/handled, further interest in events
- }
- return false; // no mapping, no further interest in the event!
- }
-
- @Override
- public boolean onKey(View v, int keyCode, android.view.KeyEvent event) {
- final com.jogamp.newt.event.KeyEvent[] newtEvents = AndroidNewtEventFactory.createKeyEvents(keyCode, event, WindowDriver.this);
- if(null != newtEvents) {
- for(int i=0; i<newtEvents.length; i++) {
- WindowDriver.this.enqueueEvent(false, newtEvents[i]);
- }
- return true;
- }
- return false;
- }
-
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- WindowDriver.this.focusChanged(false, hasFocus);
- }
-
- }
public static Class<?>[] getCustomConstructorArgumentTypes() {
return new Class<?>[] { Context.class } ;
}
-
+
public WindowDriver() {
reset();
}
- private void reset() {
- ownAndroidWindow = false;
+ public void registerActivity(final Activity activity) {
+ this.activity = activity;
+ }
+ protected Activity activity = null;
+
+ private final void reset() {
+ added2StaticViewGroup = false;
androidView = null;
nativeFormat = VisualIDHolder.VID_UNDEFINED;
androidFormat = VisualIDHolder.VID_UNDEFINED;
@@ -193,93 +227,200 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
surfaceHandle = 0;
eglSurface = 0;
definePosition(0, 0); // default to 0/0
+ defineSize(0, 0); // default size -> TBD !
+
setBrokenFocusChange(true);
}
-
+
+ private final void setupInputListener(final boolean enable) {
+ Log.d(MD.TAG, "setupInputListener(enable "+enable+") - "+Thread.currentThread().getName());
+
+ final AndroidNewtEventTranslator eventTranslator =
+ enable ? new AndroidNewtEventTranslator(this, androidView.getContext(), androidView.getHandler()) : null;
+ androidView.setOnTouchListener(eventTranslator);
+ androidView.setOnKeyListener(eventTranslator);
+ androidView.setOnFocusChangeListener(eventTranslator);
+ if(AndroidVersion.SDK_INT >= 12) { // API Level 12
+ Log.d(MD.TAG, "setupInputListener - enable GenericMotionListener - "+Thread.currentThread().getName());
+ androidView.setOnGenericMotionListener(eventTranslator);
+ }
+ if( enable ) {
+ androidView.post(new Runnable() {
+ public void run() {
+ androidView.setClickable(false);
+ androidView.setFocusable(true);
+ androidView.setFocusableInTouchMode(true);
+ } } );
+ }
+ }
+
+ private final void setupAndroidView(final Context ctx) {
+ androidView = new MSurfaceView(ctx);
+
+ final SurfaceHolder sh = androidView.getHolder();
+ sh.addCallback(WindowDriver.this);
+ sh.setFormat(getSurfaceHolderFormat(getRequestedCapabilities()));
+ }
+
+ public final SurfaceView getAndroidView() { return androidView; }
+
@Override
- protected void instantiationFinished() {
- final Context ctx = StaticContext.getContext();
+ protected final void instantiationFinished() {
+ Log.d(MD.TAG, "instantiationFinished() - "+Thread.currentThread().getName());
+
+ final Context ctx = StaticContext.getContext();
if(null == ctx) {
throw new NativeWindowException("No static [Application] Context has been set. Call StaticContext.setContext(Context) first.");
}
- androidView = new MSurfaceView(ctx);
-
- final AndroidEvents ae = new AndroidEvents();
- androidView.setOnTouchListener(ae);
- androidView.setClickable(false);
- androidView.setOnKeyListener(ae);
- androidView.setOnFocusChangeListener(ae);
- androidView.setFocusable(true);
- androidView.setFocusableInTouchMode(true);
-
- final SurfaceHolder sh = androidView.getHolder();
- sh.addCallback(WindowDriver.this);
- sh.setFormat(getFormat(getRequestedCapabilities()));
-
- // default size -> TBD !
- defineSize(0, 0);
- }
-
- public SurfaceView getAndroidView() { return androidView; }
-
+
+ if( null != Looper.myLooper() ) {
+ setupAndroidView(ctx);
+ }
+ }
+
@Override
- protected boolean canCreateNativeImpl() {
- final boolean b = 0 != surfaceHandle;
- Log.d(MD.TAG, "canCreateNativeImpl: "+b);
+ protected final boolean canCreateNativeImpl() {
+ Log.d(MD.TAG, "canCreateNativeImpl.0: surfaceHandle ready "+(0!=surfaceHandle)+" - on thread "+Thread.currentThread().getName());
+ if(Window.DEBUG_IMPLEMENTATION) {
+ Thread.dumpStack();
+ }
+
+ if( isFullscreen() ) {
+ final MonitorDevice mainMonitor = getMainMonitor();
+ final RectangleImmutable winRect = mainMonitor.getViewportInWindowUnits();
+ definePosition(winRect.getX(), winRect.getY());
+ defineSize(winRect.getWidth(), winRect.getHeight());
+ }
+
+ final boolean b;
+
+ if( 0 == surfaceHandle ) {
+ // Static ViewGroup, i.e. self contained main code
+ final ViewGroup viewGroup = StaticContext.getContentViewGroup();
+ Log.d(MD.TAG, "canCreateNativeImpl: viewGroup "+viewGroup);
+ if( null != viewGroup && !added2StaticViewGroup ) {
+ added2StaticViewGroup = true;
+ viewGroup.post(new Runnable() {
+ public void run() {
+ if(null == androidView) {
+ setupAndroidView( StaticContext.getContext() );
+ }
+ viewGroup.addView(androidView, new android.widget.FrameLayout.LayoutParams(getWidth(), getHeight(), Gravity.BOTTOM|Gravity.RIGHT));
+ Log.d(MD.TAG, "canCreateNativeImpl: added to static ViewGroup - on thread "+Thread.currentThread().getName());
+ } });
+ for(long sleep = TIMEOUT_NATIVEWINDOW; 0<sleep && 0 == surfaceHandle; sleep-=10 ) {
+ try { Thread.sleep(10); } catch (final InterruptedException ie) {}
+ }
+ b = 0 != surfaceHandle;
+ Log.d(MD.TAG, "canCreateNativeImpl: surfaceHandle ready(2) "+b+" - on thread "+Thread.currentThread().getName());
+ } else {
+ // No surfaceHandle defined, No static ViewGroup to add ourselves
+ b = false;
+ }
+ } else {
+ // surfaceHandle already defined
+ b = true;
+ }
return b;
}
@Override
- protected void createNativeImpl() {
- Log.d(MD.TAG, "createNativeImpl 0 - surfaceHandle 0x"+Long.toHexString(surfaceHandle)+
- ", format [a "+androidFormat+", n "+nativeFormat+"], "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+" - "+Thread.currentThread().getName());
+ protected final void createNativeImpl() {
+ // Create own screen/device resource instance allowing independent ownership,
+ // while still utilizing shared EGL resources.
+ final AbstractGraphicsScreen aScreen = getScreen().getGraphicsScreen();
+ final EGLGraphicsDevice aDevice = (EGLGraphicsDevice) aScreen.getDevice();
+ final EGLGraphicsDevice eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(aDevice.getNativeDisplayID(), aDevice.getConnection(), aDevice.getUnitID());
+ eglDevice.open();
+ final DefaultGraphicsScreen eglScreen = new DefaultGraphicsScreen(eglDevice, aScreen.getIndex());
+
+ Log.d(MD.TAG, "createNativeImpl 0 - eglDevice 0x"+Integer.toHexString(eglDevice.hashCode())+", "+eglDevice+", surfaceHandle 0x"+Long.toHexString(surfaceHandle)+
+ ", format [a "+androidFormat+", n "+nativeFormat+"], win["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+
+ "], pixel["+getSurfaceWidth()+"x"+getSurfaceHeight()+
+ "] - on thread "+Thread.currentThread().getName());
if(0!=getParentWindowHandle()) {
throw new NativeWindowException("Window parenting not supported (yet)");
}
if(0==surfaceHandle) {
- throw new InternalError("XXX");
+ throw new InternalError("surfaceHandle null");
}
-
- final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) getScreen().getDisplay().getGraphicsDevice();
+
final EGLGraphicsConfiguration eglConfig = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(
- capsByFormat, (GLCapabilitiesImmutable) getRequestedCapabilities(),
- (GLCapabilitiesChooser)capabilitiesChooser, getScreen().getGraphicsScreen(), nativeFormat,
- isAndroidFormatTransparent(androidFormat));
+ capsByFormat, (GLCapabilitiesImmutable) getRequestedCapabilities(),
+ (GLCapabilitiesChooser)capabilitiesChooser, eglScreen, nativeFormat, isAndroidFormatTransparent(androidFormat));
if (eglConfig == null) {
throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this);
}
final int nativeVisualID = eglConfig.getVisualID(VisualIDHolder.VIDType.NATIVE);
Log.d(MD.TAG, "nativeVisualID 0x"+Integer.toHexString(nativeVisualID));
+ Log.d(MD.TAG, "requestedCaps: "+eglConfig.getRequestedCapabilities());
+ Log.d(MD.TAG, "chosenCaps : "+eglConfig.getChosenCapabilities());
if(VisualIDHolder.VID_UNDEFINED != nativeVisualID) {
setSurfaceVisualID0(surfaceHandle, nativeVisualID);
}
-
+
eglSurface = EGL.eglCreateWindowSurface(eglDevice.getHandle(), eglConfig.getNativeConfig(), surfaceHandle, null);
if (EGL.EGL_NO_SURFACE==eglSurface) {
throw new NativeWindowException("Creation of window surface failed: "+eglConfig+", surfaceHandle 0x"+Long.toHexString(surfaceHandle)+", error "+toHexString(EGL.eglGetError()));
}
-
+
// propagate data ..
setGraphicsConfiguration(eglConfig);
setWindowHandle(surfaceHandle);
+ visibleChanged(false, true);
focusChanged(false, true);
- Log.d(MD.TAG, "createNativeImpl X: eglSurfaceHandle 0x"+Long.toHexString(eglSurface));
+
+ setupInputListener(true);
+
+ Log.d(MD.TAG, "createNativeImpl X: eglDevice 0x"+Integer.toHexString(eglDevice.hashCode())+", "+eglDevice+", eglSurfaceHandle 0x"+Long.toHexString(eglSurface));
}
@Override
- protected void closeNativeImpl() {
- Log.d(MD.TAG, "closeNativeImpl 0 - surfaceHandle 0x"+Long.toHexString(surfaceHandle)+
+ protected final void closeNativeImpl() {
+ final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) getGraphicsConfiguration().getScreen().getDevice();
+
+ Log.d(MD.TAG, "closeNativeImpl 0 - eglDevice 0x"+Integer.toHexString(eglDevice.hashCode())+", "+eglDevice+", surfaceHandle 0x"+Long.toHexString(surfaceHandle)+
", eglSurfaceHandle 0x"+Long.toHexString(eglSurface)+
- ", format [a "+androidFormat+", n "+nativeFormat+"], "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+" - "+Thread.currentThread().getName());
+ ", format [a "+androidFormat+", n "+nativeFormat+"], win["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+
+ "], pixel["+getSurfaceWidth()+"x"+getSurfaceHeight()+"],"+
+ " - on thread "+Thread.currentThread().getName());
+ if(Window.DEBUG_IMPLEMENTATION) {
+ Thread.dumpStack();
+ }
+
+ setupInputListener(false);
+
if(0 != eglSurface) {
- final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) getScreen().getDisplay().getGraphicsDevice();
- if (!EGL.eglDestroySurface(eglDevice.getHandle(), eglSurface)) {
- throw new GLException("Error destroying window surface (eglDestroySurface)");
+ try {
+ if (!EGL.eglDestroySurface(eglDevice.getHandle(), eglSurface)) {
+ throw new GLException("Error destroying window surface (eglDestroySurface)");
+ }
+ } catch (final Throwable t) {
+ Log.d(MD.TAG, "closeNativeImpl: Catch exception "+t.getMessage());
+ t.printStackTrace();
+ } finally {
+ eglSurface = 0;
}
- eglSurface = 0;
- }
+ }
release0(surfaceHandle);
+
+ eglDevice.close();
+
+ if( null != androidView ) {
+ if( added2StaticViewGroup ) {
+ added2StaticViewGroup = false;
+ final ViewGroup viewGroup = StaticContext.getContentViewGroup();
+ if( null != viewGroup) {
+ viewGroup.post(new Runnable() {
+ public void run() {
+ viewGroup.removeView(androidView);
+ Log.d(MD.TAG, "closeNativeImpl: removed from static ViewGroup - on thread "+Thread.currentThread().getName());
+ } });
+ }
+ }
+ }
+
surface = null;
surfaceHandle = 0;
}
@@ -288,8 +429,21 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
public final long getSurfaceHandle() {
return eglSurface;
}
-
- protected void requestFocusImpl(boolean reparented) {
+
+ /**
+ * <p>
+ * Accessible protected method!
+ * </p>
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public final void focusChanged(final boolean defer, final boolean focusGained) {
+ super.focusChanged(defer, focusGained);
+ }
+
+ @Override
+ protected final void requestFocusImpl(final boolean reparented) {
if(null != androidView) {
Log.d(MD.TAG, "requestFocusImpl: reparented "+reparented);
androidView.post(new Runnable() {
@@ -301,9 +455,10 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
}
}
- protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
+ @Override
+ protected final boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) {
boolean res = true;
-
+
if( 0 != ( FLAG_CHANGE_FULLSCREEN & flags) ) {
Log.d(MD.TAG, "reconfigureWindowImpl.setFullscreen post creation (setContentView()) n/a");
return false;
@@ -325,32 +480,34 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
}
}
if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
- visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
+ visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
}
return res;
}
- protected Point getLocationOnScreenImpl(int x, int y) {
+ @Override
+ protected final Point getLocationOnScreenImpl(final int x, final int y) {
return new Point(x,y);
}
- protected void updateInsetsImpl(Insets insets) {
- // nop ..
+ @Override
+ protected final void updateInsetsImpl(final Insets insets) {
+ // nop ..
}
-
+
//----------------------------------------------------------------------
- // Virtual On-Screen Keyboard / SoftInput
+ // Virtual On-Screen Keyboard / SoftInput
//
-
+
private class KeyboardVisibleReceiver extends ResultReceiver {
public KeyboardVisibleReceiver() {
super(null);
}
-
- @Override
- public void onReceiveResult(int r, Bundle data) {
+
+ @Override
+ public void onReceiveResult(final int r, final Bundle data) {
boolean v = false;
-
+
switch(r) {
case InputMethodManager.RESULT_UNCHANGED_SHOWN:
case InputMethodManager.RESULT_SHOWN:
@@ -359,41 +516,49 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
case InputMethodManager.RESULT_HIDDEN:
case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
v = false;
- break;
+ break;
}
Log.d(MD.TAG, "keyboardVisible: "+v);
keyboardVisibilityChanged(v);
}
}
- private KeyboardVisibleReceiver keyboardVisibleReceiver = new KeyboardVisibleReceiver();
-
- protected final boolean setKeyboardVisibleImpl(boolean visible) {
+ private final KeyboardVisibleReceiver keyboardVisibleReceiver = new KeyboardVisibleReceiver();
+
+ @Override
+ protected final boolean setKeyboardVisibleImpl(final boolean visible) {
if(null != androidView) {
final InputMethodManager imm = (InputMethodManager) getAndroidView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
final IBinder winid = getAndroidView().getWindowToken();
+ final boolean result;
if(visible) {
// Show soft-keyboard:
- imm.showSoftInput(androidView, 0, keyboardVisibleReceiver);
+ result = imm.showSoftInput(androidView, 0, keyboardVisibleReceiver);
} else {
// hide keyboard :
- imm.hideSoftInputFromWindow(winid, 0, keyboardVisibleReceiver);
+ result = imm.hideSoftInputFromWindow(winid, 0, keyboardVisibleReceiver);
}
- return visible;
+ return result;
} else {
return false; // nop
}
}
-
+
//----------------------------------------------------------------------
- // Surface Callbacks
+ // Surface Callbacks
//
-
- public void surfaceCreated(SurfaceHolder holder) {
- Log.d(MD.TAG, "surfaceCreated: "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight());
+
+ @Override
+ public final void surfaceCreated(final SurfaceHolder holder) {
+ Log.d(MD.TAG, "surfaceCreated: win["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+
+ "], pixels["+" "+getSurfaceWidth()+"x"+getSurfaceHeight()+"] - on thread "+Thread.currentThread().getName());
}
- public void surfaceChanged(SurfaceHolder aHolder, int aFormat, int aWidth, int aHeight) {
- Log.d(MD.TAG, "surfaceChanged: f "+nativeFormat+" -> "+aFormat+", "+aWidth+"x"+aHeight+", current surfaceHandle: 0x"+Long.toHexString(surfaceHandle));
+ @Override
+ public final void surfaceChanged(final SurfaceHolder aHolder, final int aFormat, final int aWidth, final int aHeight) {
+ Log.d(MD.TAG, "surfaceChanged: f "+nativeFormat+" -> "+aFormat+", "+aWidth+"x"+aHeight+", current surfaceHandle: 0x"+Long.toHexString(surfaceHandle)+" - on thread "+Thread.currentThread().getName());
+ if(Window.DEBUG_IMPLEMENTATION) {
+ Thread.dumpStack();
+ }
if(0!=surfaceHandle && androidFormat != aFormat ) {
// re-create
Log.d(MD.TAG, "surfaceChanged (destroy old)");
@@ -404,29 +569,35 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
surface=null;
}
if(getScreen().isNativeValid()) {
- getScreen().getCurrentScreenMode(); // if ScreenMode changed .. trigger ScreenMode event
+ // if MonitorMode changed .. trigger MonitorMode event
+ final MonitorDevice mainMonitor = getMainMonitor();
+ mainMonitor.queryCurrentMode();
}
if(0>getX() || 0>getY()) {
positionChanged(false, 0, 0);
}
-
+
if(0 == surfaceHandle) {
androidFormat = aFormat;
surface = aHolder.getSurface();
surfaceHandle = getSurfaceHandle0(surface);
acquire0(surfaceHandle);
+ final int aNativeWindowFormat = getANativeWindowFormat(androidFormat);
+ setSurfaceVisualID0(surfaceHandle, aNativeWindowFormat);
nativeFormat = getSurfaceVisualID0(surfaceHandle);
- final int nWidth = getWidth0(surfaceHandle);
- final int nHeight = getHeight0(surfaceHandle);
+ Log.d(MD.TAG, "surfaceChanged: androidFormat "+androidFormat+" -- (set-native "+aNativeWindowFormat+") --> nativeFormat "+nativeFormat);
+
+ final int[] newSurfSize = { getWidth0(surfaceHandle), getHeight0(surfaceHandle) };
+ final int[] newWinSize = convertToWindowUnits(new int[]{ newSurfSize[0], newSurfSize[1] }); // HiDPI: Not necessary yet ..
capsByFormat = (GLCapabilitiesImmutable) fixCaps(true /* matchFormatPrecise */, nativeFormat, getRequestedCapabilities());
- sizeChanged(false, nWidth, nHeight, false);
-
+ sizeChanged(false, newWinSize[0], newWinSize[1], false);
+
Log.d(MD.TAG, "surfaceRealized: isValid: "+surface.isValid()+
", new surfaceHandle 0x"+Long.toHexString(surfaceHandle)+
- ", format [a "+androidFormat+"/n "+nativeFormat+"], "+
- getX()+"/"+getY()+" "+nWidth+"x"+nHeight+", visible: "+isVisible());
-
+ ", format [a "+androidFormat+"/n "+nativeFormat+"], win["+
+ getX()+"/"+getY()+" "+newWinSize[0]+"x"+newWinSize[1]+"], pixel["+newSurfSize[0]+"x"+newSurfSize[1]+"], visible: "+isVisible());
+
if(isVisible()) {
setVisible(false, true);
}
@@ -435,18 +606,78 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
windowRepaint(0, 0, aWidth, aHeight);
Log.d(MD.TAG, "surfaceChanged: X");
}
-
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.d(MD.TAG, "surfaceDestroyed");
+
+ @Override
+ public final void surfaceDestroyed(final SurfaceHolder holder) {
+ Log.d(MD.TAG, "surfaceDestroyed - on thread "+Thread.currentThread().getName());
windowDestroyNotify(true); // actually too late .. however ..
+ Thread.dumpStack();
}
- public void surfaceRedrawNeeded(SurfaceHolder holder) {
- Log.d(MD.TAG, "surfaceRedrawNeeded");
- windowRepaint(0, 0, getWidth(), getHeight());
+ @Override
+ public final void surfaceRedrawNeeded(final SurfaceHolder holder) {
+ Log.d(MD.TAG, "surfaceRedrawNeeded - on thread "+Thread.currentThread().getName());
+ windowRepaint(0, 0, getSurfaceWidth(), getSurfaceHeight());
}
-
- private boolean ownAndroidWindow;
+
+ protected boolean handleKeyCodeBack(final KeyEvent.DispatcherState state, final android.view.KeyEvent event) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
+ Log.d(MD.TAG, "handleKeyCodeBack.0 : "+event);
+ state.startTracking(event, this);
+ } else if (event.getAction() == KeyEvent.ACTION_UP && !event.isCanceled() && state.isTracking(event)) {
+ // Since we cannot trust the visibility state 'completly',
+ // assume an already invisible state if the invisible operation fails.
+ final boolean wasVisible = setKeyboardVisibleImpl(false);
+ Log.d(MD.TAG, "handleKeyCodeBack.1 : wasVisible "+wasVisible+": "+event);
+ keyboardVisibilityChanged(false);
+ if( wasVisible ) {
+ // event processed, just send invisible event, no activity.finished()
+ enqueueAKey2NKeyUpDown(event, com.jogamp.newt.event.KeyEvent.VK_KEYBOARD_INVISIBLE);
+ return true;
+ } else if( null != activity ) {
+ // process event on our own, since we have an activity to call finish()
+ // and decide in overriden consumeKeyEvent(..) whether we suppress or proceed w/ activity.finish().
+ enqueueAKey2NKeyUpDown(event, com.jogamp.newt.event.KeyEvent.VK_ESCAPE);
+ return true;
+ } else {
+ Log.d(MD.TAG, "handleKeyCodeBack.X1 : "+event);
+ windowDestroyNotify(true);
+ // -> default BACK action, usually activity.finish()
+ }
+ }
+ return false; // continue w/ further processing
+ }
+ private void enqueueAKey2NKeyUpDown(final android.view.KeyEvent aEvent, final short newtKeyCode) {
+ final com.jogamp.newt.event.KeyEvent eDown = AndroidNewtEventFactory.createKeyEvent(aEvent, newtKeyCode, com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED, this);
+ final com.jogamp.newt.event.KeyEvent eUp = AndroidNewtEventFactory.createKeyEvent(aEvent, newtKeyCode, com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED, this);
+ enqueueEvent(false, eDown);
+ enqueueEvent(false, eUp);
+ }
+
+ @Override
+ protected void consumeKeyEvent(final com.jogamp.newt.event.KeyEvent e) {
+ super.consumeKeyEvent(e); // consume event, i.e. call all KeyListener
+ if( com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED == e.getEventType() && !e.isConsumed() ) {
+ if( com.jogamp.newt.event.KeyEvent.VK_ESCAPE == e.getKeyCode() ) {
+ Log.d(MD.TAG, "handleKeyCodeBack.X2 : "+e);
+ activity.finish();
+ } else if( com.jogamp.newt.event.KeyEvent.VK_HOME == e.getKeyCode() ) {
+ Log.d(MD.TAG, "handleKeyCodeHome.X2 : "+e);
+ triggerHome();
+ }
+ }
+ }
+ private void triggerHome() {
+ final Context ctx = StaticContext.getContext();
+ if(null == ctx) {
+ throw new NativeWindowException("No static [Application] Context has been set. Call StaticContext.setContext(Context) first.");
+ }
+ final Intent showOptions = new Intent(Intent.ACTION_MAIN);
+ showOptions.addCategory(Intent.CATEGORY_HOME);
+ ctx.startActivity(showOptions);
+ }
+
+ private boolean added2StaticViewGroup;
private MSurfaceView androidView;
private int nativeFormat; // chosen current native PixelFormat (suitable for EGL)
private int androidFormat; // chosen current android PixelFormat (-1, -2 ..)
@@ -454,20 +685,34 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
private Surface surface;
private volatile long surfaceHandle;
private long eglSurface;
-
+
class MSurfaceView extends SurfaceView {
- public MSurfaceView (Context ctx) {
+ public MSurfaceView (final Context ctx) {
super(ctx);
setBackgroundDrawable(null);
// setBackgroundColor(Color.TRANSPARENT);
}
+
+ @Override
+ public boolean onKeyPreIme(final int keyCode, final KeyEvent event) {
+ Log.d(MD.TAG, "onKeyPreIme : "+event);
+ if ( event.getKeyCode() == KeyEvent.KEYCODE_BACK ) {
+ final KeyEvent.DispatcherState state = getKeyDispatcherState();
+ if (state != null) {
+ return handleKeyCodeBack(state, event);
+ }
+ }
+ return false; // cont. processing
+ }
}
//----------------------------------------------------------------------
// Internals only
//
protected static native boolean initIDs0();
protected static native long getSurfaceHandle0(Surface surface);
+ /** Return the native window format via <code>ANativeWindow_getFormat(..)</code>. */
protected static native int getSurfaceVisualID0(long surfaceHandle);
+ /** Set the native window format via <code>ANativeWindow_setBuffersGeometry(..)</code>. */
protected static native void setSurfaceVisualID0(long surfaceHandle, int nativeVisualID);
protected static native int getWidth0(long surfaceHandle);
protected static native int getHeight0(long surfaceHandle);
diff --git a/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java
index d23b5f576..579edc590 100644
--- a/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java
+++ b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,60 +20,99 @@
* 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.android.event;
-import java.awt.event.MouseEvent;
+import jogamp.newt.Debug;
+import android.view.MotionEvent;
-import com.jogamp.common.util.IntIntHashMap;
-import com.jogamp.newt.Window;
+import com.jogamp.common.os.AndroidVersion;
import com.jogamp.newt.event.InputEvent;
+import com.jogamp.newt.event.MouseEvent;
+import com.jogamp.newt.event.NEWTEvent;
public class AndroidNewtEventFactory {
+ private static final boolean DEBUG_MOUSE_EVENT = Debug.debug("Android.MouseEvent");
+ private static final boolean DEBUG_KEY_EVENT = Debug.debug("Android.KeyEvent");
- protected static final IntIntHashMap eventTypeANDROID2NEWT;
-
- private static final String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" ,
- "POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" };
-
- static {
- IntIntHashMap map = new IntIntHashMap();
- map.setKeyNotFoundValue(0xFFFFFFFF);
-
- map.put(android.view.MotionEvent.ACTION_DOWN, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED);
- map.put(android.view.MotionEvent.ACTION_UP, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED);
- map.put(android.view.MotionEvent.ACTION_CANCEL, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED);
- map.put(android.view.MotionEvent.ACTION_MOVE, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED);
- map.put(android.view.MotionEvent.ACTION_OUTSIDE, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_MOVED);
-
- map.put(android.view.MotionEvent.ACTION_POINTER_DOWN, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED);
- map.put(android.view.MotionEvent.ACTION_POINTER_UP, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED);
-
- map.put(android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS);
-
- eventTypeANDROID2NEWT = map;
+ /** API Level 12: {@link android.view.MotionEvent#ACTION_SCROLL} = {@value} */
+ private static final int ACTION_SCROLL = 8;
+
+ private static final com.jogamp.newt.event.MouseEvent.PointerType aToolType2PointerType(final int aToolType) {
+ switch( aToolType ) {
+ case MotionEvent.TOOL_TYPE_FINGER:
+ return com.jogamp.newt.event.MouseEvent.PointerType.TouchScreen;
+ case MotionEvent.TOOL_TYPE_MOUSE:
+ return com.jogamp.newt.event.MouseEvent.PointerType.Mouse;
+ case MotionEvent.TOOL_TYPE_STYLUS:
+ case MotionEvent.TOOL_TYPE_ERASER:
+ return com.jogamp.newt.event.MouseEvent.PointerType.Pen;
+ default:
+ return com.jogamp.newt.event.MouseEvent.PointerType.Undefined;
+ }
+ }
+
+ private static final short aMotionEventType2Newt(final int aType) {
+ switch( aType ) {
+ case android.view.MotionEvent.ACTION_DOWN:
+ case android.view.MotionEvent.ACTION_POINTER_DOWN:
+ return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED;
+ case android.view.MotionEvent.ACTION_UP:
+ case android.view.MotionEvent.ACTION_POINTER_UP:
+ case android.view.MotionEvent.ACTION_CANCEL:
+ return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED;
+ case android.view.MotionEvent.ACTION_MOVE:
+ return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED;
+ case android.view.MotionEvent.ACTION_OUTSIDE:
+ return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_MOVED;
+ // case ACTION_HOVER_MOVE
+ case ACTION_SCROLL: // API Level 12 !
+ return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_WHEEL_MOVED;
+ // case ACTION_HOVER_ENTER
+ // case ACTION_HOVER_EXIT
+ }
+ return (short)0;
+ }
+
+ private static final short aAccessibilityEventType2Newt(final int aType) {
+ switch( aType ) {
+ case android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED:
+ return com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS;
+ }
+ return (short)0;
+ }
+
+ private static final short aKeyEventType2NewtEventType(final int androidKeyAction) {
+ switch(androidKeyAction) {
+ case android.view.KeyEvent.ACTION_DOWN:
+ case android.view.KeyEvent.ACTION_MULTIPLE:
+ return com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED;
+ case android.view.KeyEvent.ACTION_UP:
+ return com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED;
+ }
+ return (short)0;
}
- static final int androidKeyCode2Newt(int androidKeyCode) {
+ private static final short aKeyCode2NewtKeyCode(final int androidKeyCode, final boolean inclSysKeys) {
if(android.view.KeyEvent.KEYCODE_0 <= androidKeyCode && androidKeyCode <= android.view.KeyEvent.KEYCODE_9) {
- return com.jogamp.newt.event.KeyEvent.VK_0 + ( androidKeyCode - android.view.KeyEvent.KEYCODE_0 ) ;
+ return (short) ( com.jogamp.newt.event.KeyEvent.VK_0 + ( androidKeyCode - android.view.KeyEvent.KEYCODE_0 ) );
}
if(android.view.KeyEvent.KEYCODE_A <= androidKeyCode && androidKeyCode <= android.view.KeyEvent.KEYCODE_Z) {
- return com.jogamp.newt.event.KeyEvent.VK_A + ( androidKeyCode - android.view.KeyEvent.KEYCODE_A ) ;
+ return (short) ( com.jogamp.newt.event.KeyEvent.VK_A + ( androidKeyCode - android.view.KeyEvent.KEYCODE_A ) );
}
if(android.view.KeyEvent.KEYCODE_F1 <= androidKeyCode && androidKeyCode <= android.view.KeyEvent.KEYCODE_F12) {
- return com.jogamp.newt.event.KeyEvent.VK_F1 + ( androidKeyCode - android.view.KeyEvent.KEYCODE_F1 ) ;
+ return (short) ( com.jogamp.newt.event.KeyEvent.VK_F1 + ( androidKeyCode - android.view.KeyEvent.KEYCODE_F1 ) );
}
if(android.view.KeyEvent.KEYCODE_NUMPAD_0 <= androidKeyCode && androidKeyCode <= android.view.KeyEvent.KEYCODE_NUMPAD_9) {
- return com.jogamp.newt.event.KeyEvent.VK_NUMPAD0 + ( androidKeyCode - android.view.KeyEvent.KEYCODE_NUMPAD_0 ) ;
- }
+ return (short) ( com.jogamp.newt.event.KeyEvent.VK_NUMPAD0 + ( androidKeyCode - android.view.KeyEvent.KEYCODE_NUMPAD_0 ) );
+ }
switch(androidKeyCode) {
- case android.view.KeyEvent.KEYCODE_COMMA: return com.jogamp.newt.event.KeyEvent.VK_COMMA;
+ case android.view.KeyEvent.KEYCODE_COMMA: return com.jogamp.newt.event.KeyEvent.VK_COMMA;
case android.view.KeyEvent.KEYCODE_PERIOD: return com.jogamp.newt.event.KeyEvent.VK_PERIOD;
case android.view.KeyEvent.KEYCODE_ALT_LEFT: return com.jogamp.newt.event.KeyEvent.VK_ALT;
case android.view.KeyEvent.KEYCODE_ALT_RIGHT: return com.jogamp.newt.event.KeyEvent.VK_ALT_GRAPH;
@@ -82,7 +121,7 @@ public class AndroidNewtEventFactory {
case android.view.KeyEvent.KEYCODE_TAB: return com.jogamp.newt.event.KeyEvent.VK_TAB;
case android.view.KeyEvent.KEYCODE_SPACE: return com.jogamp.newt.event.KeyEvent.VK_SPACE;
case android.view.KeyEvent.KEYCODE_ENTER: return com.jogamp.newt.event.KeyEvent.VK_ENTER;
- case android.view.KeyEvent.KEYCODE_DEL: return com.jogamp.newt.event.KeyEvent.VK_DELETE;
+ case android.view.KeyEvent.KEYCODE_DEL: return com.jogamp.newt.event.KeyEvent.VK_BACK_SPACE;
case android.view.KeyEvent.KEYCODE_MINUS: return com.jogamp.newt.event.KeyEvent.VK_MINUS;
case android.view.KeyEvent.KEYCODE_EQUALS: return com.jogamp.newt.event.KeyEvent.VK_EQUALS;
case android.view.KeyEvent.KEYCODE_LEFT_BRACKET: return com.jogamp.newt.event.KeyEvent.VK_LEFT_PARENTHESIS;
@@ -95,149 +134,231 @@ public class AndroidNewtEventFactory {
// case android.view.KeyEvent.KEYCODE_MUTE: ??
case android.view.KeyEvent.KEYCODE_PAGE_UP: return com.jogamp.newt.event.KeyEvent.VK_PAGE_UP;
case android.view.KeyEvent.KEYCODE_PAGE_DOWN: return com.jogamp.newt.event.KeyEvent.VK_PAGE_DOWN;
- // case android.view.KeyEvent.KEYCODE_HOME: return com.jogamp.newt.event.KeyEvent.VK_HOME;
- // case android.view.KeyEvent.KEYCODE_BACK: return com.jogamp.newt.event.KeyEvent.VK_BACK_SPACE;
case android.view.KeyEvent.KEYCODE_ESCAPE: return com.jogamp.newt.event.KeyEvent.VK_ESCAPE;
case android.view.KeyEvent.KEYCODE_CTRL_LEFT: return com.jogamp.newt.event.KeyEvent.VK_CONTROL;
case android.view.KeyEvent.KEYCODE_CTRL_RIGHT: return com.jogamp.newt.event.KeyEvent.VK_CONTROL; // ??
- }
- return 0;
- }
-
- public static final com.jogamp.newt.event.WindowEvent createWindowEvent(android.view.accessibility.AccessibilityEvent event, com.jogamp.newt.Window newtSource) {
- int type = eventTypeANDROID2NEWT.get(event.getEventType());
- if(0xFFFFFFFF != type) {
- return new com.jogamp.newt.event.WindowEvent(type, ((null==newtSource)?null:(Object)newtSource), event.getEventTime());
+ case android.view.KeyEvent.KEYCODE_BACK:
+ if( inclSysKeys ) {
+ // Note that manual mapping is performed, based on the keyboard state.
+ // I.e. we map to VK_KEYBOARD_INVISIBLE if keyboard was visible and now becomes invisible!
+ // Otherwise we map to VK_ESCAPE, and if not consumed by user, the application will be terminated.
+ return com.jogamp.newt.event.KeyEvent.VK_ESCAPE;
+ }
+ break;
+ case android.view.KeyEvent.KEYCODE_HOME:
+ if( inclSysKeys ) {
+ // If not consumed by user, the application will be 'paused',
+ // i.e. resources (GLEventListener) pulled before surface gets destroyed!
+ return com.jogamp.newt.event.KeyEvent.VK_HOME;
+ }
+ break;
}
- return null; // no mapping ..
+ return com.jogamp.newt.event.KeyEvent.VK_UNDEFINED;
}
- static final int androidKeyModifiers2Newt(int androidMods) {
+ private static final int aKeyModifiers2Newt(final int androidMods) {
int newtMods = 0;
if ((androidMods & android.view.KeyEvent.META_SYM_ON) != 0) newtMods |= com.jogamp.newt.event.InputEvent.META_MASK;
if ((androidMods & android.view.KeyEvent.META_SHIFT_ON) != 0) newtMods |= com.jogamp.newt.event.InputEvent.SHIFT_MASK;
if ((androidMods & android.view.KeyEvent.META_ALT_ON) != 0) newtMods |= com.jogamp.newt.event.InputEvent.ALT_MASK;
-
+
return newtMods;
}
-
- private static final int androidKeyAction2NewtEventType(int androidKeyAction) {
- switch(androidKeyAction) {
- case android.view.KeyEvent.ACTION_DOWN:
- case android.view.KeyEvent.ACTION_MULTIPLE:
- return com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED;
- case android.view.KeyEvent.ACTION_UP:
- return com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED;
- default:
- return 0;
+
+ public static com.jogamp.newt.event.WindowEvent createWindowEvent(final android.view.accessibility.AccessibilityEvent event, final com.jogamp.newt.Window newtSource) {
+ final int aType = event.getEventType();
+ final short nType = aAccessibilityEventType2Newt(aType);
+
+ if( (short)0 != nType) {
+ return new com.jogamp.newt.event.WindowEvent(nType, ((null==newtSource)?null:(Object)newtSource), event.getEventTime());
}
+ return null; // no mapping ..
}
-
- public static final com.jogamp.newt.event.KeyEvent[] createKeyEvents(int keyCode, android.view.KeyEvent event, com.jogamp.newt.Window newtSource) {
- final int type = androidKeyAction2NewtEventType(event.getAction());
- if(Window.DEBUG_MOUSE_EVENT) {
- System.err.println("createKeyEvent: type 0x"+Integer.toHexString(type)+", keyCode 0x"+Integer.toHexString(keyCode)+", "+event);
- }
- if(0xFFFFFFFF != type) {
- final int newtKeyCode = androidKeyCode2Newt(keyCode);
- if(0 != newtKeyCode) {
- final Object src = (null==newtSource)?null:(Object)newtSource;
- final long unixTime = System.currentTimeMillis() + ( event.getEventTime() - android.os.SystemClock.uptimeMillis() );
- final int newtMods = androidKeyModifiers2Newt(event.getMetaState());
-
- final com.jogamp.newt.event.KeyEvent ke1 = new com.jogamp.newt.event.KeyEvent(
- type, src, unixTime, newtMods, newtKeyCode, event.getDisplayLabel());
-
- if( com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED == type ) {
- return new com.jogamp.newt.event.KeyEvent[] { ke1,
- new com.jogamp.newt.event.KeyEvent(
- com.jogamp.newt.event.KeyEvent.EVENT_KEY_TYPED,
- src, unixTime, newtMods, newtKeyCode, event.getDisplayLabel()) };
- } else {
- return new com.jogamp.newt.event.KeyEvent[] { ke1 };
- }
- }
+
+
+ public static com.jogamp.newt.event.KeyEvent createKeyEvent(final android.view.KeyEvent aEvent, final com.jogamp.newt.Window newtSource, final boolean inclSysKeys) {
+ final com.jogamp.newt.event.KeyEvent res;
+ final short newtType = aKeyEventType2NewtEventType(aEvent.getAction());
+ if( (short)0 != newtType) {
+ final short newtKeyCode = aKeyCode2NewtKeyCode(aEvent.getKeyCode(), inclSysKeys);
+ res = createKeyEventImpl(aEvent, newtType, newtKeyCode, newtSource);
+ } else {
+ res = null;
+ }
+ if(DEBUG_KEY_EVENT) {
+ System.err.println("createKeyEvent0: "+aEvent+" -> "+res);
+ }
+ return res;
+ }
+
+ public static com.jogamp.newt.event.KeyEvent createKeyEvent(final android.view.KeyEvent aEvent, final short newtType, final com.jogamp.newt.Window newtSource, final boolean inclSysKeys) {
+ final short newtKeyCode = aKeyCode2NewtKeyCode(aEvent.getKeyCode(), inclSysKeys);
+ final com.jogamp.newt.event.KeyEvent res = createKeyEventImpl(aEvent, newtType, newtKeyCode, newtSource);
+ if(DEBUG_KEY_EVENT) {
+ System.err.println("createKeyEvent1: newtType "+NEWTEvent.toHexString(newtType)+", "+aEvent+" -> "+res);
+ }
+ return res;
+ }
+
+ public static com.jogamp.newt.event.KeyEvent createKeyEvent(final android.view.KeyEvent aEvent, final short newtKeyCode, final short newtType, final com.jogamp.newt.Window newtSource) {
+ final com.jogamp.newt.event.KeyEvent res = createKeyEventImpl(aEvent, newtType, newtKeyCode, newtSource);
+ if(DEBUG_KEY_EVENT) {
+ System.err.println("createKeyEvent2: newtType "+NEWTEvent.toHexString(newtType)+", "+aEvent+" -> "+res);
+ }
+ return res;
+ }
+
+ private static com.jogamp.newt.event.KeyEvent createKeyEventImpl(final android.view.KeyEvent aEvent, final short newtType, final short newtKeyCode, final com.jogamp.newt.Window newtSource) {
+ if( (short)0 != newtType && com.jogamp.newt.event.KeyEvent.VK_UNDEFINED != newtKeyCode ) {
+ final Object src = null==newtSource ? null : newtSource;
+ final long unixTime = System.currentTimeMillis() + ( aEvent.getEventTime() - android.os.SystemClock.uptimeMillis() );
+ final int newtMods = aKeyModifiers2Newt(aEvent.getMetaState());
+
+ return com.jogamp.newt.event.KeyEvent.create(
+ newtType, src, unixTime, newtMods, newtKeyCode, newtKeyCode, (char) aEvent.getUnicodeChar());
}
return null;
}
- public static final com.jogamp.newt.event.MouseEvent[] createMouseEvents(android.view.MotionEvent event, com.jogamp.newt.Window newtSource) {
- if(Window.DEBUG_MOUSE_EVENT) {
- System.err.println("createMouseEvent: "+toString(event));
+ private static float maxPressure = 0.7f; // experienced maximum value (Amazon HD = 0.8f)
+
+ /**
+ * Dynamic calibration of maximum MotionEvent pressure, starting from 0.7f
+ * <p>
+ * Specification says no pressure is 0.0f and
+ * normal pressure is 1.0f, where &gt; 1.0f denominates very high pressure.
+ * </p>
+ * <p>
+ * Some devices exceed this spec, or better, most devices do.
+ * <ul>
+ * <li>Asus TF2*: Pressure always &gt; 1.0f</li>
+ * <li>Amazon HD: Pressure always &le; 0.8f</li>
+ * </ul>
+ * </p>
+ *
+ * @return
+ */
+ public static float getMaxPressure() {
+ return maxPressure;
+ }
+
+ private final int touchSlop;
+ public AndroidNewtEventFactory(final android.content.Context context, final android.os.Handler handler) {
+ final android.view.ViewConfiguration configuration = android.view.ViewConfiguration.get(context);
+ touchSlop = configuration.getScaledTouchSlop();
+ final int doubleTapSlop = configuration.getScaledDoubleTapSlop();
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("AndroidNewtEventFactory scrollSlop (scaled) "+touchSlop);
+ System.err.println("AndroidNewtEventFactory doubleTapSlop (scaled) "+doubleTapSlop);
}
- int type = eventTypeANDROID2NEWT.get(event.getAction());
- if(0xFFFFFFFF != type) {
- int rotation = 0;
- int clickCount = 1;
+ }
+
+ private static void collectPointerData(final MotionEvent e, final int count, final int[] x, final int[] y, final float[] pressure,
+ final short[] pointerIds, final MouseEvent.PointerType[] pointerTypes) {
+ for(int i=0; i < count; i++) {
+ x[i] = (int)e.getX(i);
+ y[i] = (int)e.getY(i);
+ pressure[i] = e.getPressure(i);
+ pointerIds[i] = (short)e.getPointerId(i);
+ if( pressure[i] > maxPressure ) {
+ maxPressure = pressure[i];
+ }
+ pointerTypes[i] = aToolType2PointerType( e.getToolType(i) );
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("createMouseEvent: ptr-data["+i+"] "+x[i]+"/"+y[i]+", pressure "+pressure[i]+", id "+pointerIds[i]+", type "+pointerTypes[i]);
+ }
+ }
+ }
+
+ public boolean sendPointerEvent(final boolean enqueue, final boolean wait, final boolean setFocusOnDown, final boolean isOnTouchEvent,
+ final android.view.MotionEvent event, final jogamp.newt.driver.android.WindowDriver newtSource) {
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("createMouseEvent: isOnTouchEvent "+isOnTouchEvent+", "+event);
+ }
+
+ if( event.getPressure() > maxPressure ) {
+ maxPressure = event.getPressure(); // write to static field intended
+ }
+
+ //
+ // Prefilter Android Event (Gesture, ..) and determine final type
+ //
+ final int aType = event.getActionMasked();
+ final short nType = aMotionEventType2Newt(aType);
+ final float rotationScale = touchSlop;
+ final float[] rotationXYZ = new float[] { 0f, 0f, 0f };
+
+ if( (short)0 != nType ) {
int modifiers = 0;
-
- int[] x = new int[event.getPointerCount()];
- int[] y = new int[event.getPointerCount()];
- float[] pressure = new float[event.getPointerCount()];
- int[] pointers = new int[event.getPointerCount()];
- int index = 0;
- while(index < event.getPointerCount()) {
- x[index] = (int)event.getX(index);
- y[index] = (int)event.getY(index);
- pressure[index] = event.getPressure(index);
- pointers[index] = event.getPointerId(index);
- index++;
+
+ //
+ // Determine SDK 12 SCROLL, newt-button and whether dedicated pointer is pressed
+ //
+ final int pIndex;
+ final short button;
+ switch( aType ) {
+ case android.view.MotionEvent.ACTION_POINTER_DOWN:
+ case android.view.MotionEvent.ACTION_POINTER_UP: {
+ pIndex = event.getActionIndex();
+ final int b = event.getPointerId(pIndex) + 1; // FIXME: Assumption that Pointer-ID starts w/ 0 !
+ if( com.jogamp.newt.event.MouseEvent.BUTTON1 <= b && b <= com.jogamp.newt.event.MouseEvent.BUTTON_COUNT ) {
+ button = (short)b;
+ } else {
+ button = com.jogamp.newt.event.MouseEvent.BUTTON1;
+ }
+ }
+ break;
+
+ case ACTION_SCROLL:
+ if( AndroidVersion.SDK_INT >= 12 ) { // API Level 12
+ rotationXYZ[0] = event.getAxisValue(android.view.MotionEvent.AXIS_X) / rotationScale;
+ rotationXYZ[1] = event.getAxisValue(android.view.MotionEvent.AXIS_Y) / rotationScale;
+
+ if( rotationXYZ[0]*rotationXYZ[0] > rotationXYZ[1]*rotationXYZ[1] ) {
+ // Horizontal
+ modifiers |= com.jogamp.newt.event.InputEvent.SHIFT_MASK;
+ }
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("createMouseEvent: SDK-12 Scroll "+rotationXYZ[0]+"/"+rotationXYZ[1]+", "+rotationScale+", mods "+modifiers);
+ }
+ }
+ // Fall through intended!
+
+ default: {
+ pIndex = 0;
+ button = com.jogamp.newt.event.MouseEvent.BUTTON1;
+ }
}
+ final int pCount = event.getPointerCount(); // all
- if(null!=newtSource) {
- if(newtSource.isPointerConfined()) {
- modifiers |= InputEvent.CONFINED_MASK;
- }
- if(!newtSource.isPointerVisible()) {
- modifiers |= InputEvent.INVISIBLE_MASK;
- }
+ switch( aType ) {
+ case android.view.MotionEvent.ACTION_DOWN:
+ case android.view.MotionEvent.ACTION_POINTER_DOWN:
+ // modifier button-mask will be set on doPointerEvent(..)
+ if( setFocusOnDown ) {
+ newtSource.focusChanged(false, true);
+ }
}
-
- final Object src = (null==newtSource)?null:(Object)newtSource;
- final long unixTime = System.currentTimeMillis() + ( event.getEventTime() - android.os.SystemClock.uptimeMillis() );
- final int button = pointers.length==1 ? MouseEvent.BUTTON1 : 0;
-
- final com.jogamp.newt.event.MouseEvent me1 = new com.jogamp.newt.event.MouseEvent(
- type, src, unixTime,
- modifiers, x, y, pressure, pointers, clickCount,
- button, rotation);
-
- if(type == com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED) {
- return new com.jogamp.newt.event.MouseEvent[] { me1,
- new com.jogamp.newt.event.MouseEvent(
- com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED,
- src, unixTime, modifiers, x, y, pressure, pointers, clickCount,
- button, rotation) };
- } else {
- return new com.jogamp.newt.event.MouseEvent[] { me1 };
+
+ //
+ // Collect common data
+ //
+ final int[] x = new int[pCount];
+ final int[] y = new int[pCount];
+ final float[] pressure = new float[pCount];
+ final short[] pointerIds = new short[pCount];
+ final MouseEvent.PointerType[] pointerTypes = new MouseEvent.PointerType[pCount];
+ if( 0 < pCount ) {
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("createMouseEvent: collect ptr-data [0.."+(pCount-1)+", count "+pCount+", action "+pIndex+"], aType "+aType+", button "+button);
+ }
+ collectPointerData(event, pCount, x, y, pressure, pointerIds, pointerTypes);
}
- }
- return null; // no mapping ..
+ newtSource.doPointerEvent(enqueue, wait, pointerTypes, nType, modifiers,
+ pIndex, pointerIds, button, x, y, pressure, maxPressure, rotationXYZ, rotationScale);
+ return true;
+ }
+ return false; // no mapping ..
}
-
-
- public static String toString(android.view.MotionEvent event) {
- StringBuilder sb = new StringBuilder();
- int action = event.getAction();
- int actionCode = action & android.view.MotionEvent.ACTION_MASK;
- sb.append("ACTION_" ).append(names[actionCode]);
- if (actionCode == android.view.MotionEvent.ACTION_POINTER_DOWN
- || actionCode == android.view.MotionEvent.ACTION_POINTER_UP) {
- sb.append("(pid " ).append(
- action >> android.view.MotionEvent.ACTION_POINTER_ID_SHIFT);
- sb.append(")" );
- }
- sb.append("[" );
- for (int i = 0; i < event.getPointerCount(); i++) {
- sb.append("#" ).append(i);
- sb.append("(pid " ).append(event.getPointerId(i));
- sb.append(")=" ).append((int) event.getX(i));
- sb.append("," ).append((int) event.getY(i));
- if (i + 1 < event.getPointerCount())
- sb.append(";" );
- }
- sb.append("]" );
- return sb.toString();
- }
}
diff --git a/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventTranslator.java b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventTranslator.java
new file mode 100644
index 000000000..8d20ef448
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventTranslator.java
@@ -0,0 +1,50 @@
+package jogamp.newt.driver.android.event;
+
+import jogamp.newt.driver.android.WindowDriver;
+import android.view.View;
+
+public class AndroidNewtEventTranslator implements View.OnKeyListener, View.OnTouchListener, View.OnFocusChangeListener, View.OnGenericMotionListener {
+ private final WindowDriver newtWindow;
+ private final AndroidNewtEventFactory factory;
+
+ public AndroidNewtEventTranslator(final WindowDriver newtWindow, final android.content.Context context, final android.os.Handler handler) {
+ this.newtWindow = newtWindow;
+ this.factory = new AndroidNewtEventFactory(context, handler);
+ }
+
+ private final boolean processTouchMotionEvents(final View v, final android.view.MotionEvent event, final boolean isOnTouchEvent) {
+ final boolean eventSent = factory.sendPointerEvent(true /*enqueue*/, false /*wait*/, true /*setFocusOnDown*/,
+ isOnTouchEvent, event, newtWindow);
+ if( eventSent ) {
+ try { Thread.sleep((long) (100.0F/3.0F)); } // 33 ms - FIXME ??
+ catch(final InterruptedException e) { }
+ return true; // consumed/handled, further interest in events
+ }
+ return false; // no mapping, no further interest in the event!
+ }
+
+ @Override
+ public boolean onTouch(final View v, final android.view.MotionEvent event) {
+ return processTouchMotionEvents(v, event, true);
+ }
+
+ @Override
+ public boolean onGenericMotion(final View v, final android.view.MotionEvent event) {
+ return processTouchMotionEvents(v, event, false);
+ }
+
+ @Override
+ public boolean onKey(final View v, final int keyCode, final android.view.KeyEvent event) {
+ final com.jogamp.newt.event.KeyEvent newtEvent = AndroidNewtEventFactory.createKeyEvent(event, newtWindow, false /* no system keys */);
+ if(null != newtEvent) {
+ newtWindow.enqueueEvent(false, newtEvent);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onFocusChange(final View v, final boolean hasFocus) {
+ newtWindow.focusChanged(false, hasFocus);
+ }
+}
diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java
index 17eb6a2fb..eccdd63cf 100644
--- a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java
+++ b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.awt;
@@ -47,13 +47,15 @@ import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.CapabilitiesChooser;
import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.nativewindow.GraphicsConfigurationFactory;
+import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.VisualIDHolder;
-
import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration;
import com.jogamp.nativewindow.awt.AWTGraphicsDevice;
import com.jogamp.nativewindow.awt.AWTGraphicsScreen;
+import com.jogamp.nativewindow.awt.JAWTWindow;
import com.jogamp.newt.Window;
@SuppressWarnings("serial")
@@ -61,22 +63,27 @@ public class AWTCanvas extends Canvas {
private GraphicsDevice device;
private GraphicsConfiguration chosen;
private AWTGraphicsConfiguration awtConfig;
-
- private WindowDriver newtWindowImpl;
+ private volatile JAWTWindow jawtWindow=null; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle
private CapabilitiesChooser chooser=null;
- private CapabilitiesImmutable capabilities;
+ private final CapabilitiesImmutable capabilities;
+ private final UpstreamScalable upstreamScale;
+
+ public static interface UpstreamScalable {
+ int[] getReqPixelScale();
+ void setHasPixelScale(final int[] pixelScale);
+ }
private boolean displayConfigChanged=false;
- public AWTCanvas(WindowDriver newtWindowImpl, CapabilitiesImmutable capabilities, CapabilitiesChooser chooser) {
+ public AWTCanvas(final CapabilitiesImmutable capabilities, final CapabilitiesChooser chooser, final UpstreamScalable upstreamScale) {
super();
- this.newtWindowImpl = newtWindowImpl;
if(null==capabilities) {
throw new NativeWindowException("Capabilities null");
}
this.capabilities=capabilities;
this.chooser=chooser;
+ this.upstreamScale = upstreamScale;
}
public AWTGraphicsConfiguration getAWTGraphicsConfiguration() {
@@ -88,8 +95,8 @@ public class AWTCanvas extends Canvas {
* canvas from interfering with the OpenGL rendering.
*/
@Override
- public void update(Graphics g) {
- paint(g);
+ public void update(final Graphics g) {
+ // paint(g);
}
/** Overridden to cause OpenGL rendering to be performed during
@@ -98,16 +105,16 @@ public class AWTCanvas extends Canvas {
properly.
*/
@Override
- public void paint(Graphics g) {
- newtWindowImpl.windowRepaint(0, 0, getWidth(), getHeight());
+ public void paint(final Graphics g) {
}
-
+
public boolean hasDeviceChanged() {
- boolean res = displayConfigChanged;
+ final boolean res = displayConfigChanged;
displayConfigChanged=false;
return res;
}
+ @Override
public void addNotify() {
/**
@@ -120,8 +127,7 @@ public class AWTCanvas extends Canvas {
*/
awtConfig = chooseGraphicsConfiguration(capabilities, capabilities, chooser, device);
if(Window.DEBUG_IMPLEMENTATION) {
- Exception e = new Exception("Info: Created Config: "+awtConfig);
- e.printStackTrace();
+ System.err.println(getThreadName()+": AWTCanvas.addNotify.0: Created Config: "+awtConfig);
}
if(null==awtConfig) {
throw new NativeWindowException("Error: NULL AWTGraphicsConfiguration");
@@ -137,12 +143,34 @@ public class AWTCanvas extends Canvas {
// after native peer is valid: Windows
disableBackgroundErase();
- GraphicsConfiguration gc = super.getGraphicsConfiguration();
+ {
+ jawtWindow = (JAWTWindow) NativeWindowFactory.getNativeWindow(this, awtConfig);
+ // trigger initialization cycle
+ jawtWindow.setSurfaceScale(upstreamScale.getReqPixelScale() );
+ jawtWindow.lockSurface();
+ upstreamScale.setHasPixelScale(jawtWindow.getCurrentSurfaceScale(new int[2]));
+ jawtWindow.unlockSurface();
+ }
+
+ final GraphicsConfiguration gc = super.getGraphicsConfiguration();
if(null!=gc) {
device = gc.getDevice();
}
+ if(Window.DEBUG_IMPLEMENTATION) {
+ System.err.println(getThreadName()+": AWTCanvas.addNotify.X");
+ }
}
+ public NativeWindow getNativeWindow() {
+ final JAWTWindow _jawtWindow = jawtWindow;
+ return (null != _jawtWindow) ? _jawtWindow : null;
+ }
+
+ public boolean isOffscreenLayerSurfaceEnabled() {
+ return null != jawtWindow ? jawtWindow.isOffscreenLayerSurfaceEnabled() : false;
+ }
+
+ @Override
public void removeNotify() {
try {
dispose();
@@ -152,29 +180,39 @@ public class AWTCanvas extends Canvas {
}
private void dispose() {
+ if( null != jawtWindow ) {
+ jawtWindow.destroy();
+ if(Window.DEBUG_IMPLEMENTATION) {
+ System.err.println(getThreadName()+": AWTCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post JAWTWindow: "+jawtWindow);
+ }
+ jawtWindow=null;
+ }
if(null != awtConfig) {
- AbstractGraphicsDevice adevice = awtConfig.getNativeGraphicsConfiguration().getScreen().getDevice();
+ final AbstractGraphicsDevice adevice = awtConfig.getNativeGraphicsConfiguration().getScreen().getDevice();
String adeviceMsg=null;
if(Window.DEBUG_IMPLEMENTATION) {
adeviceMsg = adevice.toString();
}
- boolean closed = adevice.close();
+ final boolean closed = adevice.close();
if(Window.DEBUG_IMPLEMENTATION) {
- System.err.println("AWTCanvas.dispose(): closed GraphicsDevice: "+adeviceMsg+", result: "+closed);
+ System.err.println(getThreadName()+": AWTCanvas.dispose(): closed GraphicsDevice: "+adeviceMsg+", result: "+closed);
}
}
}
+ private String getThreadName() { return Thread.currentThread().getName(); }
+
/**
* Overridden to choose a GraphicsConfiguration on a parent container's
* GraphicsDevice because both devices
*/
+ @Override
public GraphicsConfiguration getGraphicsConfiguration() {
/*
* Workaround for problems with Xinerama and java.awt.Component.checkGD
* when adding to a container on a different graphics device than the
* one that this Canvas is associated with.
- *
+ *
* GC will be null unless:
* - A native peer has assigned it. This means we have a native
* peer, and are already comitted to a graphics configuration.
@@ -188,7 +226,7 @@ public class AWTCanvas extends Canvas {
* chosen is only non-null on platforms where the GLDrawableFactory
* returns a non-null GraphicsConfiguration (in the GLCanvas
* constructor).
- *
+ *
* if gc is from this Canvas' native peer then it should equal chosen,
* otherwise it is from an ancestor component that this Canvas is being
* added to, and we go into this block.
@@ -198,30 +236,30 @@ public class AWTCanvas extends Canvas {
* Check for compatibility with gc. If they differ by only the
* device then return a new GCconfig with the super-class' GDevice
* (and presumably the same visual ID in Xinerama).
- *
+ *
*/
if (!chosen.getDevice().getIDstring().equals(gc.getDevice().getIDstring())) {
/*
* Here we select a GraphicsConfiguration on the alternate
* device that is presumably identical to the chosen
* configuration, but on the other device.
- *
+ *
* Should really check to ensure that we select a configuration
* with the same X visual ID for Xinerama screens, otherwise the
* GLDrawable may have the wrong visual ID (I don't think this
* ever gets updated). May need to add a method to
* X11GLDrawableFactory to do this in a platform specific
* manner.
- *
+ *
* However, on platforms where we can actually get into this
* block, both devices should have the same visual list, and the
* same configuration should be selected here.
*/
- AWTGraphicsConfiguration config = chooseGraphicsConfiguration(
+ final AWTGraphicsConfiguration config = chooseGraphicsConfiguration(
awtConfig.getChosenCapabilities(), awtConfig.getRequestedCapabilities(), chooser, gc.getDevice());
final GraphicsConfiguration compatible = (null!=config)?config.getAWTGraphicsConfiguration():null;
if(Window.DEBUG_IMPLEMENTATION) {
- Exception e = new Exception("Info: Call Stack: "+Thread.currentThread().getName());
+ final Exception e = new Exception("Info: Call Stack: "+Thread.currentThread().getName());
e.printStackTrace();
System.err.println("Created Config (n): HAVE GC "+chosen);
System.err.println("Created Config (n): THIS GC "+gc);
@@ -239,7 +277,7 @@ public class AWTCanvas extends Canvas {
chosen = compatible;
if( !config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities())) {
displayConfigChanged=true;
- }
+ }
awtConfig = config;
}
}
@@ -249,7 +287,7 @@ public class AWTCanvas extends Canvas {
* return the GC that was selected in the constructor (and might
* cause an exception in Component.checkGD when adding to a
* container, but in this case that would be the desired behavior).
- *
+ *
*/
return chosen;
} else if (gc == null) {
@@ -269,14 +307,14 @@ public class AWTCanvas extends Canvas {
return gc;
}
- private static AWTGraphicsConfiguration chooseGraphicsConfiguration(CapabilitiesImmutable capsChosen,
- CapabilitiesImmutable capsRequested,
- CapabilitiesChooser chooser,
- GraphicsDevice device) {
- final AbstractGraphicsScreen aScreen = null != device ?
+ private static AWTGraphicsConfiguration chooseGraphicsConfiguration(final CapabilitiesImmutable capsChosen,
+ final CapabilitiesImmutable capsRequested,
+ final CapabilitiesChooser chooser,
+ final GraphicsDevice device) {
+ final AbstractGraphicsScreen aScreen = null != device ?
AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT):
AWTGraphicsScreen.createDefault();
- AWTGraphicsConfiguration config = (AWTGraphicsConfiguration)
+ final AWTGraphicsConfiguration config = (AWTGraphicsConfiguration)
GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, capsChosen.getClass()).chooseGraphicsConfiguration(capsChosen,
capsRequested,
chooser, aScreen, VisualIDHolder.VID_UNDEFINED);
@@ -298,6 +336,7 @@ public class AWTCanvas extends Canvas {
if (!disableBackgroundEraseInitialized) {
try {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
public Object run() {
try {
Class<?> clazz = getToolkit().getClass();
@@ -307,16 +346,16 @@ public class AWTCanvas extends Canvas {
clazz.getDeclaredMethod("disableBackgroundErase",
new Class[] { Canvas.class });
disableBackgroundEraseMethod.setAccessible(true);
- } catch (Exception e) {
+ } catch (final Exception e) {
clazz = clazz.getSuperclass();
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
}
return null;
}
});
- } catch (Exception e) {
+ } catch (final Exception e) {
}
disableBackgroundEraseInitialized = true;
if(Window.DEBUG_IMPLEMENTATION) {
@@ -328,7 +367,7 @@ public class AWTCanvas extends Canvas {
Throwable t=null;
try {
disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this });
- } catch (Exception e) {
+ } catch (final Exception e) {
// FIXME: workaround for 6504460 (incorrect backport of 6333613 in 5.0u10)
// throw new GLException(e);
t = e;
diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java
index 8771f5c74..39e68e48c 100644
--- a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java
+++ b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java
@@ -30,27 +30,30 @@ package jogamp.newt.driver.awt;
import java.awt.EventQueue;
+import javax.media.nativewindow.NativeWindowException;
+
+import com.jogamp.common.util.RunnableTask;
+import com.jogamp.common.util.awt.AWTEDTExecutor;
import com.jogamp.newt.util.EDTUtil;
-import jogamp.common.awt.AWTEDTExecutor;
import jogamp.newt.Debug;
public class AWTEDTUtil implements EDTUtil {
public static final boolean DEBUG = Debug.debug("EDT");
-
+
private final Object edtLock = new Object(); // locking the EDT start/stop state
- private final ThreadGroup threadGroup;
+ private final ThreadGroup threadGroup;
private final String name;
private final Runnable dispatchMessages;
- private NewtEventDispatchThread nedt = null;
+ private NEDT nedt = null;
private int start_iter=0;
private static long pollPeriod = EDTUtil.defaultEDTPollPeriod;
- public AWTEDTUtil(ThreadGroup tg, String name, Runnable dispatchMessages) {
+ public AWTEDTUtil(final ThreadGroup tg, final String name, final Runnable dispatchMessages) {
this.threadGroup = tg;
this.name=Thread.currentThread().getName()+"-"+name+"-EDT-";
this.dispatchMessages=dispatchMessages;
- this.nedt = new NewtEventDispatchThread(threadGroup, name);
+ this.nedt = new NEDT(threadGroup, name);
this.nedt.setDaemon(true); // don't stop JVM from shutdown ..
}
@@ -60,31 +63,38 @@ public class AWTEDTUtil implements EDTUtil {
}
@Override
- final public void setPollPeriod(long ms) {
- pollPeriod = ms;
+ final public void setPollPeriod(final long ms) {
+ pollPeriod = ms; // writing to static field is intended
}
-
+
@Override
- final public void reset() {
- synchronized(edtLock) {
- waitUntilStopped();
+ public final void start() throws IllegalStateException {
+ synchronized(edtLock) {
+ if( nedt.isRunning() ) {
+ throw new IllegalStateException("EDT still running and not subject to stop. Curr "+Thread.currentThread().getName()+", NEDT "+nedt.getName()+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop+", on AWT-EDT "+EventQueue.isDispatchThread());
+ }
if(DEBUG) {
- System.err.println(Thread.currentThread()+": EDT reset - edt: "+nedt);
+ System.err.println(Thread.currentThread()+": AWT-EDT reset - edt: "+nedt);
}
- this.nedt = new NewtEventDispatchThread(threadGroup, name);
- this.nedt.setDaemon(true); // don't stop JVM from shutdown ..
+ if( nedt.getState() != Thread.State.NEW ) {
+ nedt = new NEDT(threadGroup, name);
+ nedt.setDaemon(true); // don't stop JVM from shutdown ..
+ }
+ startImpl();
+ }
+ if( !nedt.isRunning() ) {
+ throw new RuntimeException("EDT could not be started: "+nedt);
}
}
private final void startImpl() {
if(nedt.isAlive()) {
- throw new RuntimeException("EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning()+", edt: "+nedt);
+ throw new RuntimeException("AWT-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning+", shouldStop "+nedt.shouldStop+", edt: "+nedt);
}
start_iter++;
nedt.setName(name+start_iter);
- nedt.shouldStop = false;
if(DEBUG) {
- System.err.println(Thread.currentThread()+": EDT START - edt: "+nedt);
+ System.err.println(Thread.currentThread()+": AWT-EDT START - edt: "+nedt);
// Thread.dumpStack();
}
nedt.start();
@@ -99,100 +109,148 @@ public class AWTEDTUtil implements EDTUtil {
public final boolean isCurrentThreadNEDT() {
return nedt == Thread.currentThread();
}
-
+
@Override
public final boolean isCurrentThreadEDTorNEDT() {
- return EventQueue.isDispatchThread() || nedt == Thread.currentThread();
+ return EventQueue.isDispatchThread() || nedt == Thread.currentThread();
}
-
+
@Override
final public boolean isRunning() {
- return nedt.isRunning() ; // AWT is always running
+ return nedt.isRunning() ;
}
@Override
- public final void invokeStop(Runnable task) {
- invokeImpl(true, task, true);
+ public final boolean invokeStop(final boolean wait, final Runnable task) {
+ return invokeImpl(wait, task, true);
}
@Override
- public final void invoke(boolean wait, Runnable task) {
- invokeImpl(wait, task, false);
+ public final boolean invoke(final boolean wait, final Runnable task) {
+ return invokeImpl(wait, task, false);
}
-
- private void invokeImpl(boolean wait, Runnable task, boolean stop) {
- if(task == null) {
- throw new RuntimeException("Null Runnable");
- }
- synchronized(edtLock) { // lock the EDT status
- if( nedt.shouldStop ) {
- // drop task ..
- if(DEBUG) {
- System.err.println("Warning: EDT about (1) to stop, won't enqueue new task: "+nedt);
- Thread.dumpStack();
+
+ private final boolean invokeImpl(boolean wait, final Runnable task, final boolean stop) {
+ Throwable throwable = null;
+ RunnableTask rTask = null;
+ final Object rTaskLock = new Object();
+ synchronized(rTaskLock) { // lock the optional task execution
+ synchronized(edtLock) { // lock the EDT status
+ if( nedt.shouldStop ) {
+ // drop task ..
+ System.err.println(Thread.currentThread()+": Warning: AWT-EDT about (1) to stop, won't enqueue new task: "+nedt);
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
+ return false;
}
- return;
- }
- // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task);
- // Thread.dumpStack();
- if(stop) {
- nedt.shouldStop = true;
- if(DEBUG) {
- System.err.println(Thread.currentThread()+": EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt);
- // Thread.dumpStack();
+ if( isCurrentThreadEDT() ) {
+ if(null != task) {
+ task.run();
+ }
+ wait = false; // running in same thread (EDT) -> no wait
+ if(stop) {
+ nedt.shouldStop = true;
+ }
+ } else {
+ if( !nedt.isRunning ) {
+ if( null != task ) {
+ if( stop ) {
+ System.err.println(Thread.currentThread()+": Warning: AWT-EDT is about (3) to stop and stopped already, dropping task. NEDT "+nedt);
+ } else {
+ System.err.println(Thread.currentThread()+": Warning: AWT-EDT is not running, dropping task. NEDT "+nedt);
+ }
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
+ }
+ return false;
+ } else if( stop ) {
+ if(DEBUG) {
+ System.err.println(Thread.currentThread()+": AWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop);
+ }
+ synchronized(nedt.sync) {
+ nedt.shouldStop = true;
+ nedt.sync.notifyAll(); // stop immediate if waiting (poll freq)
+ }
+ }
+
+ if(null != task) {
+ rTask = new RunnableTask(task,
+ wait ? rTaskLock : null,
+ true /* always catch and report Exceptions, don't disturb EDT */,
+ wait ? null : System.err);
+ AWTEDTExecutor.singleton.invoke(false, rTask);
+ }
}
}
-
- // start if should not stop && not started yet
- if( !stop && !nedt.isRunning() ) {
- startImpl();
+ if( wait ) {
+ try {
+ rTaskLock.wait(); // free lock, allow execution of rTask
+ } catch (final InterruptedException ie) {
+ throwable = ie;
+ }
+ if(null==throwable) {
+ throwable = rTask.getThrowable();
+ }
+ if(null!=throwable) {
+ if(throwable instanceof NativeWindowException) {
+ throw (NativeWindowException)throwable;
+ }
+ throw new RuntimeException(throwable);
+ }
}
+ return true;
}
- AWTEDTExecutor.singleton.invoke(wait, task);
- }
+ }
@Override
- final public void waitUntilIdle() {
- final NewtEventDispatchThread _edt;
+ final public boolean waitUntilIdle() {
+ final NEDT _edt;
synchronized(edtLock) {
_edt = nedt;
}
- if(!_edt.isRunning() || EventQueue.isDispatchThread() || _edt == Thread.currentThread()) {
- return;
+ if(!_edt.isRunning || _edt == Thread.currentThread() || EventQueue.isDispatchThread()) {
+ return false;
}
try {
AWTEDTExecutor.singleton.invoke(true, new Runnable() {
+ @Override
public void run() { }
});
- } catch (Exception e) { }
+ } catch (final Exception e) { }
+ return true;
}
@Override
- final public void waitUntilStopped() {
+ final public boolean waitUntilStopped() {
synchronized(edtLock) {
- if(nedt.isRunning() && nedt != Thread.currentThread() ) {
- while(nedt.isRunning()) {
+ if( nedt.isRunning && nedt != Thread.currentThread() && !EventQueue.isDispatchThread() ) {
+ while( nedt.isRunning ) {
try {
edtLock.wait();
- } catch (InterruptedException e) {
+ } catch (final InterruptedException e) {
e.printStackTrace();
}
}
+ return true;
+ } else {
+ return false;
}
}
}
-
- class NewtEventDispatchThread extends Thread {
+
+ class NEDT extends Thread {
volatile boolean shouldStop = false;
volatile boolean isRunning = false;
Object sync = new Object();
- public NewtEventDispatchThread(ThreadGroup tg, String name) {
+ public NEDT(final ThreadGroup tg, final String name) {
super(tg, name);
}
final public boolean isRunning() {
- return isRunning;
+ return isRunning && !shouldStop;
}
@Override
@@ -201,58 +259,55 @@ public class AWTEDTUtil implements EDTUtil {
super.start();
}
- /**
+ /**
* Utilizing locking only on tasks and its execution,
* not for event dispatching.
*/
@Override
final public void run() {
if(DEBUG) {
- System.err.println(getName()+": EDT run() START "+ getName());
+ System.err.println(getName()+": AWT-EDT run() START "+ getName());
}
RuntimeException error = null;
try {
do {
// event dispatch
if(!shouldStop) {
- // FIXME: Determine whether we require to run the
- // delivery of events (dispatch) on AWT-EDT.
- // Since the WindowDriver itself delivers all Window related events,
- // this shall not be required.
- // AWTEDTExecutor.singleton.invoke(true, dispatchMessages);
- dispatchMessages.run();
+ // EDT invoke thread is AWT-EDT,
+ // hence dispatching is required to run on AWT-EDT as well.
+ // Otherwise a deadlock may happen due to dispatched event's
+ // triggering a locking action.
+ AWTEDTExecutor.singleton.invoke(true, dispatchMessages);
}
// wait
synchronized(sync) {
if(!shouldStop) {
try {
sync.wait(pollPeriod);
- } catch (InterruptedException e) {
+ } catch (final InterruptedException e) {
e.printStackTrace();
}
}
}
} while(!shouldStop) ;
- } catch (Throwable t) {
+ } catch (final Throwable t) {
// handle errors ..
shouldStop = true;
if(t instanceof RuntimeException) {
error = (RuntimeException) t;
} else {
- error = new RuntimeException("Within EDT", t);
+ error = new RuntimeException("Within AWT-EDT", t);
}
} finally {
if(DEBUG) {
- System.err.println(getName()+": EDT run() END "+ getName()+", "+error);
+ System.err.println(getName()+": AWT-EDT run() END "+ getName()+", "+error);
}
synchronized(edtLock) {
- isRunning = !shouldStop;
- if(!isRunning) {
- edtLock.notifyAll();
- }
+ isRunning = false;
+ edtLock.notifyAll();
}
if(DEBUG) {
- System.err.println(getName()+": EDT run() EXIT "+ getName()+", exception: "+error);
+ System.err.println(getName()+": AWT-EDT run() EXIT "+ getName()+", exception: "+error);
}
if(null!=error) {
throw error;
@@ -260,7 +315,7 @@ public class AWTEDTUtil implements EDTUtil {
} // finally
} // run()
} // EventDispatchThread
-
+
}
diff --git a/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java
index 70e9ba570..23da69dba 100644
--- a/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,34 +29,37 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.awt;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+
import com.jogamp.nativewindow.awt.AWTGraphicsDevice;
import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.util.EDTUtil;
-import jogamp.newt.DefaultEDTUtil;
import jogamp.newt.DisplayImpl;
public class DisplayDriver extends DisplayImpl {
public DisplayDriver() {
}
+ @Override
protected void createNativeImpl() {
aDevice = AWTGraphicsDevice.createDefault();
}
- protected void setAWTGraphicsDevice(AWTGraphicsDevice d) {
+ protected void setAWTGraphicsDevice(final AWTGraphicsDevice d) {
aDevice = d;
}
+ @Override
protected EDTUtil createEDTUtil() {
final EDTUtil def;
if(NewtFactory.useEDT()) {
- def = new AWTEDTUtil(Thread.currentThread().getThreadGroup(), "AWTDisplay-"+getFQName(), dispatchMessagesRunnable);
+ def = new AWTEDTUtil(Thread.currentThread().getThreadGroup(), "AWTDisplay-"+getFQName(), dispatchMessagesRunnable);
if(DEBUG) {
System.err.println("Display.createNative("+getFQName()+") Create EDTUtil: "+def.getClass().getName());
}
@@ -66,8 +69,12 @@ public class DisplayDriver extends DisplayImpl {
return def;
}
- protected void closeNativeImpl() { }
+ @Override
+ protected void closeNativeImpl(final AbstractGraphicsDevice aDevice) {
+ aDevice.close();
+ }
+ @Override
protected void dispatchMessagesNative() { /* nop */ }
}
diff --git a/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java
index 6b1283a00..57948cfc3 100644
--- a/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java
@@ -1,21 +1,21 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -28,29 +28,33 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.awt;
import java.awt.DisplayMode;
+import java.awt.GraphicsDevice;
+import jogamp.newt.MonitorModeProps.Cache;
+import jogamp.newt.MonitorModeProps;
import jogamp.newt.ScreenImpl;
-import javax.media.nativewindow.util.Dimension;
-import javax.media.nativewindow.util.Point;
import com.jogamp.nativewindow.awt.AWTGraphicsDevice;
import com.jogamp.nativewindow.awt.AWTGraphicsScreen;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
public class ScreenDriver extends ScreenImpl {
public ScreenDriver() {
}
+ @Override
protected void createNativeImpl() {
aScreen = new AWTGraphicsScreen((AWTGraphicsDevice)display.getGraphicsDevice());
}
- protected void setAWTGraphicsScreen(AWTGraphicsScreen s) {
+ protected void setAWTGraphicsScreen(final AWTGraphicsScreen s) {
aScreen = s;
}
@@ -62,20 +66,70 @@ public class ScreenDriver extends ScreenImpl {
super.updateVirtualScreenOriginAndSize();
}
+ @Override
protected void closeNativeImpl() { }
-
- protected int validateScreenIndex(int idx) {
- return idx; // pass through ...
- }
-
- protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) {
- final DisplayMode mode = ((AWTGraphicsDevice)getDisplay().getGraphicsDevice()).getGraphicsDevice().getDisplayMode();
- if(null != mode) {
- virtualOrigin.setX(0);
- virtualOrigin.setY(0);
- virtualSize.setWidth(mode.getWidth());
- virtualSize.setHeight(mode.getHeight());
+
+ @Override
+ protected int validateScreenIndex(final int idx) {
+ return idx; // pass through ...
+ }
+
+ private static MonitorMode getModeProps(final Cache cache, final DisplayMode mode) {
+ int rate = mode.getRefreshRate();
+ if( DisplayMode.REFRESH_RATE_UNKNOWN == rate ) {
+ rate = ScreenImpl.default_sm_rate;
+ }
+ int bpp = mode.getBitDepth();
+ if( DisplayMode.BIT_DEPTH_MULTI == bpp ) {
+ bpp= ScreenImpl.default_sm_bpp;
}
+ final int[] props = new int[ MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL ];
+ int i = 0;
+ props[i++] = MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL;
+ props[i++] = mode.getWidth();
+ props[i++] = mode.getHeight();
+ props[i++] = bpp;
+ props[i++] = rate * 100;
+ props[i++] = 0; // flags
+ props[i++] = 0; // mode_idx
+ props[i++] = 0; // rotation
+ return MonitorModeProps.streamInMonitorMode(null, cache, props, 0);
}
-
+
+ @Override
+ protected void collectNativeMonitorModesAndDevicesImpl(final Cache cache) {
+ final GraphicsDevice awtGD = ((AWTGraphicsDevice)getDisplay().getGraphicsDevice()).getGraphicsDevice();
+ final DisplayMode[] awtModes = awtGD.getDisplayModes();
+ for(int i=0; i<awtModes.length; i++) {
+ getModeProps(cache, awtModes[i]);
+ }
+ final MonitorMode currentMode = getModeProps(cache, awtGD.getDisplayMode());
+
+ final int[] props = new int[MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES - 1 - MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES];
+ int i = 0;
+ props[i++] = props.length;
+ props[i++] = 0; // crt_idx
+ props[i++] = ScreenImpl.default_sm_widthmm; // FIXME
+ props[i++] = ScreenImpl.default_sm_heightmm; // FIXME
+ props[i++] = 0; // rotated viewport x pixel-units
+ props[i++] = 0; // rotated viewport y pixel-units
+ props[i++] = currentMode.getRotatedWidth(); // rotated viewport width pixel-units
+ props[i++] = currentMode.getRotatedHeight(); // rotated viewport height pixel-units
+ props[i++] = 0; // rotated viewport x window-units
+ props[i++] = 0; // rotated viewport y window-units
+ props[i++] = currentMode.getRotatedWidth(); // rotated viewport width window-units
+ props[i++] = currentMode.getRotatedHeight(); // rotated viewport height window-units
+ MonitorModeProps.streamInMonitorDevice(null, cache, this, cache.monitorModes, currentMode, props, 0);
+ }
+
+ @Override
+ protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) {
+ return null;
+ }
+
+ @Override
+ protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) {
+ return false;
+ }
+
}
diff --git a/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java
index bee43a95e..06dcb8ff5 100644
--- a/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.awt;
@@ -40,11 +40,15 @@ import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Insets;
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.util.Point;
+import jogamp.nativewindow.awt.AWTMisc;
import jogamp.newt.WindowImpl;
+import com.jogamp.common.os.Platform;
import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration;
import com.jogamp.nativewindow.awt.AWTGraphicsDevice;
import com.jogamp.nativewindow.awt.AWTGraphicsScreen;
@@ -68,146 +72,205 @@ public class WindowDriver extends WindowImpl {
return new Class<?>[] { Container.class } ;
}
- public WindowDriver(Container container) {
+ public WindowDriver(final Container container) {
super();
- this.container = container;
+ this.awtContainer = container;
if(container instanceof Frame) {
- frame = (Frame) container;
+ awtFrame = (Frame) container;
}
}
private boolean owningFrame;
- private Container container = null;
- private Frame frame = null; // same instance as container, just for impl. convenience
- private AWTCanvas canvas;
+ private Container awtContainer = null;
+ /** same instance as container, just for impl. convenience */
+ private Frame awtFrame = null;
+ private AWTCanvas awtCanvas;
- protected void requestFocusImpl(boolean reparented) {
- container.requestFocus();
+ @Override
+ protected void requestFocusImpl(final boolean reparented) {
+ awtContainer.requestFocus();
}
@Override
protected void setTitleImpl(final String title) {
- if (frame != null) {
- frame.setTitle(title);
+ if (awtFrame != null) {
+ awtFrame.setTitle(title);
}
}
+ private final AWTCanvas.UpstreamScalable upstreamScalable = new AWTCanvas.UpstreamScalable() {
+ @Override
+ public int[] getReqPixelScale() {
+ return WindowDriver.this.reqPixelScale;
+ }
+
+ @Override
+ public void setHasPixelScale(final int[] pixelScale) {
+ System.arraycopy(pixelScale, 0, WindowDriver.this.hasPixelScale, 0, 2);
+ }
+ };
+
+ @Override
protected void createNativeImpl() {
if(0!=getParentWindowHandle()) {
throw new RuntimeException("Window parenting not supported in AWT, use AWTWindow(Frame) cstr for wrapping instead");
}
- if(null==container) {
- frame = new Frame();
- container = frame;
+ if(null==awtContainer) {
+ awtFrame = new Frame();
+ awtContainer = awtFrame;
owningFrame=true;
} else {
owningFrame=false;
- defineSize(container.getWidth(), container.getHeight());
- definePosition(container.getX(), container.getY());
+ defineSize(awtContainer.getWidth(), awtContainer.getHeight());
+ definePosition(awtContainer.getX(), awtContainer.getY());
}
- if(null!=frame) {
- frame.setTitle(getTitle());
+ if(null!=awtFrame) {
+ awtFrame.setTitle(getTitle());
+ }
+ awtContainer.setLayout(new BorderLayout());
+
+ if( null == awtCanvas ) {
+ awtCanvas = new AWTCanvas(capsRequested, WindowDriver.this.capabilitiesChooser, upstreamScalable);
+
+ // canvas.addComponentListener(listener);
+ awtContainer.add(awtCanvas, BorderLayout.CENTER);
+
+ // via EDT ..
+ new AWTMouseAdapter(this).addTo(awtCanvas); // fwd all AWT Mouse events to here
+ new AWTKeyAdapter(this).addTo(awtCanvas); // fwd all AWT Key events to here
+
+ // direct w/o EDT
+ new AWTWindowAdapter(new LocalWindowListener(), this).addTo(awtCanvas); // fwd all AWT Window events to here
}
- container.setLayout(new BorderLayout());
-
- canvas = new AWTCanvas(this, capsRequested, WindowDriver.this.capabilitiesChooser);
-
- // canvas.addComponentListener(listener);
- container.add(canvas, BorderLayout.CENTER);
-
- // via EDT ..
- new AWTMouseAdapter(this).addTo(canvas); // fwd all AWT Mouse events to here
- new AWTKeyAdapter(this).addTo(canvas); // fwd all AWT Key events to here
-
- // direct w/o EDT
- new AWTWindowAdapter(new LocalWindowListener(), this).addTo(canvas); // fwd all AWT Window events to here
reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), getReconfigureFlags(FLAG_CHANGE_VISIBILITY | FLAG_CHANGE_DECORATION, true));
// throws exception if failed ..
-
- setWindowHandle(1); // just a marker ..
+
+ final NativeWindow nw = awtCanvas.getNativeWindow();
+ if( null != nw ) {
+ setGraphicsConfiguration( awtCanvas.getAWTGraphicsConfiguration() );
+ setWindowHandle( nw.getWindowHandle() );
+ }
}
+ @Override
protected void closeNativeImpl() {
- setWindowHandle(0); // just a marker ..
- if(null!=container) {
- container.setVisible(false);
- container.remove(canvas);
- container.setEnabled(false);
- canvas.setEnabled(false);
+ setWindowHandle(0);
+ if(null!=awtContainer) {
+ awtContainer.setVisible(false);
+ awtContainer.remove(awtCanvas);
+ awtContainer.setEnabled(false);
+ awtCanvas.setEnabled(false);
}
- if(owningFrame && null!=frame) {
- frame.dispose();
+ if(owningFrame && null!=awtFrame) {
+ awtFrame.dispose();
owningFrame=false;
- frame = null;
}
+ awtCanvas = null;
+ awtFrame = null;
+ awtContainer = null;
}
@Override
public boolean hasDeviceChanged() {
- boolean res = canvas.hasDeviceChanged();
+ final boolean res = awtCanvas.hasDeviceChanged();
if(res) {
- final AWTGraphicsConfiguration cfg = canvas.getAWTGraphicsConfiguration();
+ final AWTGraphicsConfiguration cfg = awtCanvas.getAWTGraphicsConfiguration();
if (null == cfg) {
throw new NativeWindowException("Error Device change null GraphicsConfiguration: "+this);
}
setGraphicsConfiguration(cfg);
-
+
// propagate new info ..
((ScreenDriver)getScreen()).setAWTGraphicsScreen((AWTGraphicsScreen)cfg.getScreen());
((DisplayDriver)getScreen().getDisplay()).setAWTGraphicsDevice((AWTGraphicsDevice)cfg.getScreen().getDevice());
-
+
((ScreenDriver)getScreen()).updateVirtualScreenOriginAndSize();
}
return res;
}
- protected void updateInsetsImpl(javax.media.nativewindow.util.Insets insets) {
- Insets contInsets = container.getInsets();
- insets.setLeftWidth(contInsets.left);
- insets.setRightWidth(contInsets.right);
- insets.setTopHeight(contInsets.top);
- insets.setBottomHeight(contInsets.bottom);
+ @Override
+ protected void updateInsetsImpl(final javax.media.nativewindow.util.Insets insets) {
+ final Insets contInsets = awtContainer.getInsets();
+ insets.set(contInsets.left, contInsets.right, contInsets.top, contInsets.bottom);
}
- protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
- if(0 != ( FLAG_CHANGE_DECORATION & flags) && null!=frame) {
- if(!container.isDisplayable()) {
- frame.setUndecorated(isUndecorated());
+ private void setCanvasSizeImpl(final int width, final int height) {
+ final Dimension szClient = new Dimension(width, height);
+ final java.awt.Window awtWindow = AWTMisc.getWindow(awtCanvas);
+ final Container c= null != awtWindow ? awtWindow : awtContainer;
+ awtCanvas.setMinimumSize(szClient);
+ awtCanvas.setPreferredSize(szClient);
+ if(DEBUG_IMPLEMENTATION) {
+ final Insets insets = c.getInsets();
+ final Dimension szContainer = new Dimension(width + insets.left + insets.right,
+ height + insets.top + insets.bottom);
+ System.err.println(getThreadName()+": AWTWindow setCanvasSize: szClient "+szClient+", szCont "+szContainer+", insets "+insets);
+ }
+ awtCanvas.setSize(szClient);
+ awtCanvas.invalidate();
+ if(null != awtWindow) {
+ awtWindow.pack();
+ } else {
+ awtContainer.validate();
+ }
+ }
+ private void setFrameSizeImpl(final int width, final int height) {
+ final Insets insets = awtContainer.getInsets();
+ final Dimension szContainer = new Dimension(width + insets.left + insets.right,
+ height + insets.top + insets.bottom);
+ if(DEBUG_IMPLEMENTATION) {
+ final Dimension szClient = new Dimension(width, height);
+ System.err.println(getThreadName()+": AWTWindow setFrameSize: szClient "+szClient+", szCont "+szContainer+", insets "+insets);
+ }
+ awtContainer.setSize(szContainer);
+ awtCanvas.invalidate();
+ awtContainer.validate();
+ }
+
+ @Override
+ protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) {
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("AWTWindow reconfig: "+x+"/"+y+" "+width+"x"+height+", "+
+ getReconfigureFlagsAsString(null, flags));
+ }
+ if(0 != ( FLAG_CHANGE_DECORATION & flags) && null!=awtFrame) {
+ if(!awtContainer.isDisplayable()) {
+ awtFrame.setUndecorated(isUndecorated());
} else {
if(DEBUG_IMPLEMENTATION) {
System.err.println(getThreadName()+": AWTWindow can't undecorate already created frame");
}
}
}
-
- final Dimension szClient = new Dimension(width, height);
- canvas.setMinimumSize(szClient);
- canvas.setPreferredSize(szClient);
- canvas.setSize(szClient);
- if(DEBUG_IMPLEMENTATION) {
- final Insets insets = container.getInsets();
- final Dimension szContainer = new Dimension(width + insets.left + insets.right,
- height + insets.top + insets.bottom);
- System.err.println(getThreadName()+": AWTWindow new size: szClient "+szClient+", szCont "+szContainer+", insets "+insets);
- }
-
+
if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
- if(null != frame) {
- frame.pack();
+ if( 0 != ( FLAG_IS_VISIBLE & flags) ) {
+ setCanvasSizeImpl(width, height);
+ awtContainer.setVisible( true );
+ } else {
+ awtContainer.setVisible( false );
+ }
+ } else if( awtCanvas.getWidth() != width || awtCanvas.getHeight() != height ) {
+ if( Platform.OSType.MACOS == Platform.getOSType() && awtCanvas.isOffscreenLayerSurfaceEnabled() ) {
+ setFrameSizeImpl(width, height);
+ } else {
+ setCanvasSizeImpl(width, height);
}
- container.validate();
- container.setVisible(0 != ( FLAG_IS_VISIBLE & flags));
}
-
- container.setLocation(x, y);
-
+ defineSize(width, height); // we are on AWT-EDT .. change values immediately
+
+ if( awtContainer.getX() != x || awtContainer.getY() != y ) {
+ awtContainer.setLocation(x, y);
+ }
+
if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
if( 0 != ( FLAG_IS_VISIBLE & flags ) ) {
if( !hasDeviceChanged() ) {
- // oops ??
- final AWTGraphicsConfiguration cfg = canvas.getAWTGraphicsConfiguration();
+ // oops ??
+ final AWTGraphicsConfiguration cfg = awtCanvas.getAWTGraphicsConfiguration();
if(null == cfg) {
throw new NativeWindowException("Error: !hasDeviceChanged && null == GraphicsConfiguration: "+this);
}
@@ -215,63 +278,64 @@ public class WindowDriver extends WindowImpl {
}
}
visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
- } else {
- container.invalidate();
- if(null != frame) {
- frame.pack();
- }
- container.validate();
}
-
+
return true;
}
- protected Point getLocationOnScreenImpl(int x, int y) {
- java.awt.Point ap = canvas.getLocationOnScreen();
+ @Override
+ protected Point getLocationOnScreenImpl(final int x, final int y) {
+ final java.awt.Point ap = awtCanvas.getLocationOnScreen();
ap.translate(x, y);
return new Point((int)(ap.getX()+0.5),(int)(ap.getY()+0.5));
}
-
+
@Override
- public Object getWrappedWindow() {
- return canvas;
+ public NativeSurface getWrappedSurface() {
+ return ( null != awtCanvas ) ? awtCanvas.getNativeWindow() : null;
}
- class LocalWindowListener implements com.jogamp.newt.event.WindowListener {
+ class LocalWindowListener implements com.jogamp.newt.event.WindowListener {
@Override
- public void windowMoved(com.jogamp.newt.event.WindowEvent e) {
- if(null!=container) {
- WindowDriver.this.positionChanged(false, container.getX(), container.getY());
+ public void windowMoved(final com.jogamp.newt.event.WindowEvent e) {
+ if(null!=awtContainer) {
+ WindowDriver.this.positionChanged(false, awtContainer.getX(), awtContainer.getY());
}
}
@Override
- public void windowResized(com.jogamp.newt.event.WindowEvent e) {
- if(null!=canvas) {
- WindowDriver.this.sizeChanged(false, canvas.getWidth(), canvas.getHeight(), false);
+ public void windowResized(final com.jogamp.newt.event.WindowEvent e) {
+ if(null!=awtCanvas) {
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("Window Resized: "+awtCanvas);
+ }
+ WindowDriver.this.sizeChanged(false, awtCanvas.getWidth(), awtCanvas.getHeight(), true);
+ WindowDriver.this.windowRepaint(false, 0, 0, getSurfaceWidth(), getSurfaceHeight());
}
}
@Override
- public void windowDestroyNotify(WindowEvent e) {
+ public void windowDestroyNotify(final WindowEvent e) {
WindowDriver.this.windowDestroyNotify(false);
}
@Override
- public void windowDestroyed(WindowEvent e) {
- if(isNativeValid()) {
- WindowDriver.this.windowDestroyNotify(true);
- }
-
+ public void windowDestroyed(final WindowEvent e) {
+ // Not fwd by AWTWindowAdapter, synthesized by NEWT
}
@Override
- public void windowGainedFocus(WindowEvent e) {
- WindowDriver.this.focusChanged(false, true);
+ public void windowGainedFocus(final WindowEvent e) {
+ WindowDriver.this.focusChanged(false, true);
}
@Override
- public void windowLostFocus(WindowEvent e) {
- WindowDriver.this.focusChanged(false, false);
+ public void windowLostFocus(final WindowEvent e) {
+ WindowDriver.this.focusChanged(false, false);
}
@Override
- public void windowRepaint(WindowUpdateEvent e) {
- WindowDriver.this.windowRepaint(false, 0, 0, getWidth(), getHeight());
+ public void windowRepaint(final WindowUpdateEvent e) {
+ if(null!=awtCanvas) {
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("Window Repaint: "+awtCanvas);
+ }
+ WindowDriver.this.windowRepaint(false, 0, 0, getSurfaceWidth(), getSurfaceHeight());
+ }
}
}
}
diff --git a/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java
index 65ca63eec..ceb337150 100644
--- a/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2012 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.bcm.egl;
@@ -60,6 +60,7 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl {
public DisplayDriver() {
}
+ @Override
protected void createNativeImpl() {
final long handle = CreateDisplay(ScreenDriver.fixedWidth, ScreenDriver.fixedHeight);
if (handle == EGL.EGL_NO_DISPLAY) {
@@ -68,12 +69,15 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl {
aDevice = new EGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, handle, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT, null);
}
- protected void closeNativeImpl() {
+ @Override
+ protected void closeNativeImpl(final AbstractGraphicsDevice aDevice) {
if (aDevice.getHandle() != EGL.EGL_NO_DISPLAY) {
DestroyDisplay(aDevice.getHandle());
}
+ aDevice.close();
}
+ @Override
protected void dispatchMessagesNative() {
// n/a .. DispatchMessages();
}
diff --git a/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java
index deb2a534b..2cd47313a 100644
--- a/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2012 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,14 +29,19 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.bcm.egl;
import javax.media.nativewindow.DefaultGraphicsScreen;
-import javax.media.nativewindow.util.Dimension;
-import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.util.Rectangle;
+
+import jogamp.newt.MonitorModeProps;
+import jogamp.newt.ScreenImpl;
+
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
public class ScreenDriver extends jogamp.newt.ScreenImpl {
@@ -48,23 +53,66 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl {
public ScreenDriver() {
}
+ @Override
protected void createNativeImpl() {
aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx);
}
+ @Override
protected void closeNativeImpl() { }
- protected int validateScreenIndex(int idx) {
- return 0; // only one screen available
+ @Override
+ protected int validateScreenIndex(final int idx) {
+ return 0; // only one screen available
+ }
+
+ @Override
+ protected final void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) {
+ int[] props = new int[ MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL ];
+ int i = 0;
+ props[i++] = MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL;
+ props[i++] = fixedWidth; // FIXME
+ props[i++] = fixedHeight; // FIXME
+ props[i++] = ScreenImpl.default_sm_bpp; // FIXME
+ props[i++] = ScreenImpl.default_sm_rate * 100; // FIXME
+ props[i++] = 0; // flags
+ props[i++] = 0; // mode_idx
+ props[i++] = 0; // rotation
+ final MonitorMode currentMode = MonitorModeProps.streamInMonitorMode(null, cache, props, 0);
+
+ props = new int[MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES - 1 - MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES];
+ i = 0;
+ props[i++] = props.length;
+ props[i++] = 0; // crt_idx
+ props[i++] = ScreenImpl.default_sm_widthmm; // FIXME
+ props[i++] = ScreenImpl.default_sm_heightmm; // FIXME
+ props[i++] = 0; // rotated viewport x pixel-units
+ props[i++] = 0; // rotated viewport y pixel-units
+ props[i++] = fixedWidth; // FIXME rotated viewport width pixel-units
+ props[i++] = fixedHeight; // FIXME rotated viewport height pixel-units
+ props[i++] = 0; // rotated viewport x window-units
+ props[i++] = 0; // rotated viewport y window-units
+ props[i++] = fixedWidth; // FIXME rotated viewport width window-units
+ props[i++] = fixedHeight; // FIXME rotated viewport height window-units
+ MonitorModeProps.streamInMonitorDevice(null, cache, this, cache.monitorModes, currentMode, props, 0);
}
-
- protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) {
- virtualOrigin.setX(0);
- virtualOrigin.setY(0);
- virtualSize.setWidth(fixedWidth); // FIXME
- virtualSize.setHeight(fixedHeight); // FIXME
+
+ @Override
+ protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) {
+ return monitor.getSupportedModes().get(0);
}
-
+
+ @Override
+ protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) {
+ return false;
+ }
+
+ @Override
+ protected void calcVirtualScreenOriginAndSize(final Rectangle viewport, final Rectangle viewportInWindowUnits) {
+ viewport.set(0, 0, fixedWidth, fixedHeight); // FIXME
+ viewportInWindowUnits.set(viewport);
+ }
+
//----------------------------------------------------------------------
// Internals only
//
diff --git a/src/newt/classes/jogamp/newt/driver/bcm/egl/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/egl/WindowDriver.java
index 49d3d98ba..aec85f875 100644
--- a/src/newt/classes/jogamp/newt/driver/bcm/egl/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/bcm/egl/WindowDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2012 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.bcm.egl;
@@ -52,11 +52,12 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
public WindowDriver() {
}
+ @Override
protected void createNativeImpl() {
if(0!=getParentWindowHandle()) {
throw new RuntimeException("Window parenting not supported (yet)");
}
- // query a good configuration, however chose the final one by the native queried egl-cfg-id
+ // query a good configuration, however chose the final one by the native queried egl-cfg-id
// after creation at {@link #windowCreated(int, int, int)}.
final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice(), capsRequested).chooseGraphicsConfiguration(
capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED);
@@ -64,7 +65,8 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this);
}
setGraphicsConfiguration(cfg);
- setSizeImpl(getScreen().getWidth(), getScreen().getHeight());
+ final int[] winSize = convertToWindowUnits(new int[] {getScreen().getWidth(), getScreen().getHeight()});
+ setSizeImpl(winSize[0], winSize[1]);
setWindowHandle(realizeWindow(true, getWidth(), getHeight()));
if (0 == getWindowHandle()) {
@@ -72,15 +74,17 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
}
}
+ @Override
protected void closeNativeImpl() {
if(0!=windowHandleClose) {
CloseWindow(getDisplayHandle(), windowHandleClose);
}
}
- protected void requestFocusImpl(boolean reparented) { }
+ @Override
+ protected void requestFocusImpl(final boolean reparented) { }
- protected void setSizeImpl(int width, int height) {
+ protected void setSizeImpl(final int width, final int height) {
if(0!=getWindowHandle()) {
// n/a in BroadcomEGL
System.err.println("BCEGL Window.setSizeImpl n/a in BroadcomEGL with realized window");
@@ -89,8 +93,9 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
}
}
- protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
- if(0!=getWindowHandle()) {
+ @Override
+ protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) {
+ if(0!=getWindowHandle()) {
if(0 != ( FLAG_CHANGE_FULLSCREEN & flags)) {
if( 0 != ( FLAG_IS_FULLSCREEN & flags) ) {
// n/a in BroadcomEGL
@@ -110,19 +115,21 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
if(x>=0 || y>=0) {
System.err.println("BCEGL Window.setPositionImpl n/a in BroadcomEGL");
}
-
+
if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
}
return true;
}
- protected Point getLocationOnScreenImpl(int x, int y) {
+ @Override
+ protected Point getLocationOnScreenImpl(final int x, final int y) {
return new Point(x,y);
}
- protected void updateInsetsImpl(Insets insets) {
- // nop ..
+ @Override
+ protected void updateInsetsImpl(final Insets insets) {
+ // nop ..
}
@Override
@@ -141,11 +148,11 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
private native void SwapWindow(long eglDisplayHandle, long eglWindowHandle);
- private long realizeWindow(boolean chromaKey, int width, int height) {
+ private long realizeWindow(final boolean chromaKey, final int width, final int height) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("BCEGL Window.realizeWindow() with: chroma "+chromaKey+", "+width+"x"+height+", "+getGraphicsConfiguration());
}
- long handle = CreateWindow(getDisplayHandle(), chromaKey, width, height);
+ final long handle = CreateWindow(getDisplayHandle(), chromaKey, width, height);
if (0 == handle) {
throw new NativeWindowException("Error native Window Handle is null");
}
@@ -153,9 +160,9 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
return handle;
}
- private void windowCreated(int cfgID, int width, int height) {
+ private void windowCreated(final int cfgID, final int width, final int height) {
defineSize(width, height);
- GLCapabilitiesImmutable capsReq = (GLCapabilitiesImmutable) getGraphicsConfiguration().getRequestedCapabilities();
+ final GLCapabilitiesImmutable capsReq = (GLCapabilitiesImmutable) getGraphicsConfiguration().getRequestedCapabilities();
final AbstractGraphicsConfiguration cfg = EGLGraphicsConfiguration.create(capsReq, getScreen().getGraphicsScreen(), cfgID);
if (null == cfg) {
throw new NativeWindowException("Error creating EGLGraphicsConfiguration from id: "+cfgID+", "+this);
diff --git a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java
index 08c5c573c..1b67fa755 100644
--- a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,7 +20,7 @@
* 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.
@@ -28,15 +28,28 @@
package jogamp.newt.driver.bcm.vc.iv;
+import java.net.URLConnection;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.util.PixelFormat;
+
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.opengl.util.PNGPixelRect;
import jogamp.newt.DisplayImpl;
import jogamp.newt.NEWTJNILibLoader;
+import jogamp.newt.PointerIconImpl;
+import jogamp.newt.driver.linux.LinuxMouseTracker;
import jogamp.opengl.egl.EGL;
import jogamp.opengl.egl.EGLDisplayUtil;
public class DisplayDriver extends DisplayImpl {
+ static final PNGPixelRect defaultPointerIconImage;
+
static {
NEWTJNILibLoader.loadNEWT();
@@ -49,6 +62,18 @@ public class DisplayDriver extends DisplayImpl {
if (!WindowDriver.initIDs()) {
throw new NativeWindowException("Failed to initialize bcm.vc.iv Window jmethodIDs");
}
+
+ PNGPixelRect image = null;
+ if( DisplayImpl.isPNGUtilAvailable() ) {
+ final IOUtil.ClassResources res = new IOUtil.ClassResources(DisplayDriver.class, new String[] { "newt/data/pointer-grey-alpha-16x24.png" } );
+ try {
+ final URLConnection urlConn = res.resolve(0);
+ image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+ defaultPointerIconImage = image;
}
public static void initSingleton() {
@@ -57,22 +82,128 @@ public class DisplayDriver extends DisplayImpl {
public DisplayDriver() {
+ bcmHandle = 0;
+ activePointerIcon = 0;
+ activePointerIconVisible = false;
}
+ @Override
protected void createNativeImpl() {
// FIXME: map name to EGL_*_DISPLAY
+ bcmHandle = OpenBCMDisplay0();
aDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT);
+ aDevice.open();
+
+ defaultPointerIcon = (PointerIconImpl) createPointerIcon(defaultPointerIconImage, 0, 0);
+ if( DEBUG_POINTER_ICON ) {
+ System.err.println("Display.PointerIcon.createDefault: "+defaultPointerIcon);
+ }
+ if( null != defaultPointerIcon ) {
+ final LinuxMouseTracker lmt = LinuxMouseTracker.getSingleton();
+ setPointerIconActive(defaultPointerIcon.getHandle(), lmt.getLastX(), lmt.getLastY());
+ }
}
+ private PointerIconImpl defaultPointerIcon = null;
- protected void closeNativeImpl() {
+ @Override
+ protected void closeNativeImpl(final AbstractGraphicsDevice aDevice) {
aDevice.close();
+ CloseBCMDisplay0(bcmHandle);
+ bcmHandle = 0;
}
+ /* pp */ final long getBCMHandle() { return bcmHandle; }
+
+ @Override
protected void dispatchMessagesNative() {
- DispatchMessages();
+ DispatchMessages0();
+ }
+
+ // @Override
+ // public final PixelFormat getNativePointerIconPixelFormat() { return PixelFormat.BGRA8888; }
+
+ @Override
+ protected final long createPointerIconImpl(final PixelFormat pixelformat, final int width, final int height, final ByteBuffer pixels, final int hotX, final int hotY) {
+ return CreatePointerIcon(bcmHandle, pixels, width, height, hotX, hotY);
+ }
+
+ @Override
+ protected final void destroyPointerIconImpl(final long displayHandle, final long piHandle) {
+ DestroyPointerIcon0(piHandle);
+ }
+
+ /* pp */ void setPointerIconActive(long piHandle, final int x, final int y) {
+ synchronized(pointerIconSync) {
+ if( DEBUG_POINTER_ICON ) {
+ System.err.println("Display.PointerIcon.set.0: active ["+toHexString(activePointerIcon)+", visible "+activePointerIconVisible+"] -> "+toHexString(piHandle));
+ }
+ if( 0 != activePointerIcon && activePointerIconVisible ) {
+ SetPointerIcon0(bcmHandle, activePointerIcon, false, x, y);
+ }
+ if( 0 == piHandle && null != defaultPointerIcon ) {
+ piHandle = defaultPointerIcon.getHandle();
+ }
+ if( 0 != piHandle ) {
+ SetPointerIcon0(bcmHandle, piHandle, true, x, y);
+ activePointerIconVisible = true;
+ } else {
+ activePointerIconVisible = false;
+ }
+ activePointerIcon = piHandle;
+ if( DEBUG_POINTER_ICON ) {
+ System.err.println("Display.PointerIcon.set.X: active ["+toHexString(activePointerIcon)+", visible "+activePointerIconVisible+"]");
+ }
+ }
+ }
+ /* pp */ void setActivePointerIconVisible(final boolean visible, final int x, final int y) {
+ synchronized(pointerIconSync) {
+ if( DEBUG_POINTER_ICON ) {
+ System.err.println("Display.PointerIcon.visible: active ["+toHexString(activePointerIcon)+", visible "+activePointerIconVisible+"] -> visible "+visible);
+ }
+ if( activePointerIconVisible != visible ) {
+ if( 0 != activePointerIcon ) {
+ SetPointerIcon0(bcmHandle, activePointerIcon, visible, x, y);
+ }
+ activePointerIconVisible = visible;
+ }
+ }
}
+ /* pp */ void moveActivePointerIcon(final int x, final int y) {
+ synchronized(pointerIconSync) {
+ if( DEBUG_POINTER_ICON ) {
+ System.err.println("Display.PointerIcon.move: active ["+toHexString(activePointerIcon)+", visible "+activePointerIconVisible+"], "+x+"/"+y);
+ }
+ if( 0 != activePointerIcon && activePointerIconVisible ) {
+ MovePointerIcon0(activePointerIcon, x, y);
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only
+ //
+
+ protected static native boolean initIDs();
+ private static native long OpenBCMDisplay0();
+ private static native void CloseBCMDisplay0(long handle);
+
+ private static long CreatePointerIcon(final long bcmHandle, final Buffer pixels, final int width, final int height, final int hotX, final int hotY) {
+ final boolean pixels_is_direct = Buffers.isDirect(pixels);
+ return CreatePointerIcon0(pixels_is_direct ? pixels : Buffers.getArray(pixels),
+ pixels_is_direct ? Buffers.getDirectBufferByteOffset(pixels) : Buffers.getIndirectBufferByteOffset(pixels),
+ pixels_is_direct,
+ width, height, hotX, hotY);
+ }
+ private static native long CreatePointerIcon0(Object pixels, int pixels_byte_offset, boolean pixels_is_direct, int width, int height, int hotX, int hotY);
+ private static native void DestroyPointerIcon0(long handle);
+ private static native void SetPointerIcon0(long bcmHandle, long handle, boolean enable, int x, int y);
+ private static native void MovePointerIcon0(long handle, int x, int y);
+
+ private static native void DispatchMessages0();
- protected static native boolean initIDs();
- private native void DispatchMessages();
+ private long bcmHandle;
+ private long activePointerIcon;
+ private boolean activePointerIconVisible;
+ private final Object pointerIconSync = new Object();
}
diff --git a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/ScreenDriver.java
index 787d1a1b4..64cae75f6 100644
--- a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/ScreenDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/ScreenDriver.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,7 +20,7 @@
* 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.
@@ -29,9 +29,12 @@
package jogamp.newt.driver.bcm.vc.iv;
import javax.media.nativewindow.DefaultGraphicsScreen;
-import javax.media.nativewindow.util.Dimension;
-import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.util.Rectangle;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+
+import jogamp.newt.MonitorModeProps;
import jogamp.newt.ScreenImpl;
public class ScreenDriver extends ScreenImpl {
@@ -42,31 +45,75 @@ public class ScreenDriver extends ScreenImpl {
public ScreenDriver() {
}
+ @Override
protected void createNativeImpl() {
aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx);
initNative();
}
+ @Override
protected void closeNativeImpl() { }
- protected int validateScreenIndex(int idx) {
- return 0; // only one screen available
- }
-
- protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) {
- virtualOrigin.setX(0);
- virtualOrigin.setY(0);
- virtualSize.setWidth(cachedWidth);
- virtualSize.setHeight(cachedHeight);
+ @Override
+ protected int validateScreenIndex(final int idx) {
+ return 0; // only one screen available
+ }
+
+ @Override
+ protected final void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) {
+ int[] props = new int[ MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL ];
+ int i = 0;
+ props[i++] = MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL;
+ props[i++] = cachedWidth; // width
+ props[i++] = cachedHeight; // height
+ props[i++] = ScreenImpl.default_sm_bpp; // FIXME
+ props[i++] = ScreenImpl.default_sm_rate * 100; // FIXME
+ props[i++] = 0; // flags
+ props[i++] = 0; // mode_idx
+ props[i++] = 0; // rotation
+ final MonitorMode currentMode = MonitorModeProps.streamInMonitorMode(null, cache, props, 0);
+
+ props = new int[MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES - 1 - MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES];
+ i = 0;
+ props[i++] = props.length;
+ props[i++] = 0; // crt_idx
+ props[i++] = ScreenImpl.default_sm_widthmm; // FIXME
+ props[i++] = ScreenImpl.default_sm_heightmm; // FIXME
+ props[i++] = 0; // rotated viewport x pixel-units
+ props[i++] = 0; // rotated viewport y pixel-units
+ props[i++] = cachedWidth; // rotated viewport width pixel-units
+ props[i++] = cachedWidth; // rotated viewport height pixel-units
+ props[i++] = 0; // rotated viewport x window-units
+ props[i++] = 0; // rotated viewport y window-units
+ props[i++] = cachedWidth; // rotated viewport width window-units
+ props[i++] = cachedWidth; // rotated viewport height window-units
+ MonitorModeProps.streamInMonitorDevice(null, cache, this, cache.monitorModes, currentMode, props, 0);
}
-
- protected void setScreenSize(int width, int height) {
- cachedWidth = width;
- cachedHeight = height;
+
+ @Override
+ protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) {
+ return monitor.getSupportedModes().get(0);
+ }
+
+ @Override
+ protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) {
+ return false;
+ }
+
+ @Override
+ protected void calcVirtualScreenOriginAndSize(final Rectangle viewport, final Rectangle viewportInWindowUnits) {
+ viewport.set(0, 0, cachedWidth, cachedHeight);
+ viewportInWindowUnits.set(viewport);
+ }
+
+ /** Called from {@link #initNative()}. */
+ protected void setScreenSize(final int width, final int height) {
+ cachedWidth = width; // write to static field intended
+ cachedHeight = height; // write to static field intended
}
-
+
private static int cachedWidth = 0;
- private static int cachedHeight = 0;
+ private static int cachedHeight = 0;
protected static native boolean initIDs();
protected native void initNative();
diff --git a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/WindowDriver.java
index 7b8d2e958..ad6d0b688 100644
--- a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/WindowDriver.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,7 +20,7 @@
* 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.
@@ -29,15 +29,24 @@
package jogamp.newt.driver.bcm.vc.iv;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.Capabilities;
+import javax.media.nativewindow.DefaultGraphicsScreen;
import javax.media.nativewindow.GraphicsConfigurationFactory;
import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.VisualIDHolder;
import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.Point;
+import com.jogamp.common.util.IntBitfield;
+import com.jogamp.nativewindow.egl.EGLGraphicsDevice;
+import com.jogamp.newt.event.MouseEvent;
+
+import jogamp.newt.PointerIconImpl;
import jogamp.newt.WindowImpl;
+import jogamp.newt.driver.linux.LinuxEventDeviceTracker;
import jogamp.newt.driver.linux.LinuxMouseTracker;
+import jogamp.opengl.egl.EGLDisplayUtil;
public class WindowDriver extends WindowImpl {
private static final String WINDOW_CLASS_NAME = "NewtWindow";
@@ -47,110 +56,160 @@ public class WindowDriver extends WindowImpl {
}
public WindowDriver() {
+ linuxMouseTracker = LinuxMouseTracker.getSingleton();
+ linuxEventDeviceTracker = LinuxEventDeviceTracker.getSingleton();
+ layer = -1;
+ nativeWindowHandle = 0;
+ windowHandleClose = 0;
}
+ @Override
protected void createNativeImpl() {
if(0!=getParentWindowHandle()) {
throw new RuntimeException("Window parenting not supported (yet)");
}
- // FIXME: Hack - Native BCM_VC_IV code CreateWindow() uses the default alpha value setting,
- // which is alpha:8 ! Hence we require to chose alpha from the egl configurations.
- // TODO: Properly select the alpha mode in CreateWindow()! This will allow this hack.
- final Capabilities capsChosen = (Capabilities) capsRequested.cloneMutable();
- capsChosen.setAlphaBits(1);
-
+ synchronized( layerSync ) {
+ if( layerCount >= MAX_LAYERS ) {
+ throw new RuntimeException("Max windows reached: "+layerCount+" ( "+MAX_LAYERS+" )");
+ }
+ for(int i=0; 0 > layer && i<MAX_LAYERS; i++) {
+ if( !usedLayers.get(nextLayer) ) {
+ layer = nextLayer;
+ usedLayers.put(layer, true);
+ layerCount++;
+ }
+ nextLayer++;
+ if( MAX_LAYERS == nextLayer ) {
+ nextLayer=0;
+ }
+ }
+ // System.err.println("XXX.Open capacity "+usedLayers.capacity()+", count "+usedLayers.getBitCount());
+ }
+ if( 0 > layer ) {
+ throw new InternalError("Could not find a free layer: count "+layerCount+", max "+MAX_LAYERS);
+ }
+ final ScreenDriver screen = (ScreenDriver) getScreen();
+ final DisplayDriver display = (DisplayDriver) screen.getDisplay();
+
+ // Create own screen/device resource instance allowing independent ownership,
+ // while still utilizing shared EGL resources.
+ final AbstractGraphicsScreen aScreen = screen.getGraphicsScreen();
+ final EGLGraphicsDevice aDevice = (EGLGraphicsDevice) aScreen.getDevice();
+ final EGLGraphicsDevice eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(aDevice.getNativeDisplayID(), aDevice.getConnection(), aDevice.getUnitID());
+ eglDevice.open();
+ final DefaultGraphicsScreen eglScreen = new DefaultGraphicsScreen(eglDevice, aScreen.getIndex());
+
final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice(), capsRequested).chooseGraphicsConfiguration(
- capsChosen, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED);
+ capsRequested, capsRequested, capabilitiesChooser, eglScreen, VisualIDHolder.VID_UNDEFINED);
if (null == cfg) {
throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this);
}
+ final Capabilities chosenCaps = (Capabilities) cfg.getChosenCapabilities();
+ // FIXME: Pass along opaque flag, since EGL doesn't determine it
+ if(capsRequested.isBackgroundOpaque() != chosenCaps.isBackgroundOpaque()) {
+ chosenCaps.setBackgroundOpaque(capsRequested.isBackgroundOpaque());
+ }
setGraphicsConfiguration(cfg);
-
- nativeWindowHandle = CreateWindow(getWidth(), getHeight());
+ nativeWindowHandle = CreateWindow0(display.getBCMHandle(), layer, getX(), getY(), getWidth(), getHeight(),
+ chosenCaps.isBackgroundOpaque(), chosenCaps.getAlphaBits());
if (nativeWindowHandle == 0) {
throw new NativeWindowException("Error creating egl window: "+cfg);
}
- setVisible0(nativeWindowHandle, false);
setWindowHandle(nativeWindowHandle);
if (0 == getWindowHandle()) {
throw new NativeWindowException("Error native Window Handle is null");
}
windowHandleClose = nativeWindowHandle;
- addWindowListener(LinuxMouseTracker.getSingleton());
- focusChanged(false, true);
+
+ addWindowListener(linuxEventDeviceTracker);
+ addWindowListener(linuxMouseTracker);
+ focusChanged(false, true);
}
+ @Override
protected void closeNativeImpl() {
- removeWindowListener(LinuxMouseTracker.getSingleton());
-
+ final DisplayDriver display = (DisplayDriver) getScreen().getDisplay();
+ final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) getGraphicsConfiguration().getScreen().getDevice();
+
+ removeWindowListener(linuxMouseTracker);
+ removeWindowListener(linuxEventDeviceTracker);
+
if(0!=windowHandleClose) {
- CloseWindow(windowHandleClose, windowUserData);
- windowUserData=0;
+ CloseWindow0(display.getBCMHandle(), windowHandleClose);
+ }
+
+ eglDevice.close();
+
+ synchronized( layerSync ) {
+ usedLayers.put(layer, false);
+ layerCount--;
+ layer = -1;
+ // System.err.println("XXX.Close capacity "+usedLayers.capacity()+", count "+usedLayers.getBitCount());
}
}
- protected void requestFocusImpl(boolean reparented) {
+ @Override
+ protected void requestFocusImpl(final boolean reparented) {
focusChanged(false, true);
}
- protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
- if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
- setVisible0(nativeWindowHandle, 0 != ( FLAG_IS_VISIBLE & flags));
- visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
- }
-
- if(0!=nativeWindowHandle) {
- if(0 != ( FLAG_CHANGE_FULLSCREEN & flags)) {
- final boolean fs = 0 != ( FLAG_IS_FULLSCREEN & flags) ;
- setFullScreen0(nativeWindowHandle, fs);
- if(fs) {
- return true;
- }
- }
- // int _x=(x>=0)?x:this.x;
- // int _y=(x>=0)?y:this.y;
- width=(width>0)?width:getWidth();
- height=(height>0)?height:getHeight();
- if(width>0 || height>0) {
- setSize0(nativeWindowHandle, width, height);
- }
- if(x>=0 || y>=0) {
- System.err.println("setPosition n/a in KD");
- }
- }
-
- if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
- visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
- }
-
+ @Override
+ protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) {
+ reconfigure0(nativeWindowHandle, x, y, width, height, flags);
return true;
}
- protected Point getLocationOnScreenImpl(int x, int y) {
+ @Override
+ protected Point getLocationOnScreenImpl(final int x, final int y) {
return new Point(x,y);
}
- protected void updateInsetsImpl(Insets insets) {
- // nop ..
+ @Override
+ protected void updateInsetsImpl(final Insets insets) {
+ // nop ..
+ }
+
+ @Override
+ protected final void doMouseEvent(final boolean enqueue, final boolean wait, final short eventType, final int modifiers,
+ final int x, final int y, final short button, final float[] rotationXYZ, final float rotationScale) {
+ if( MouseEvent.EVENT_MOUSE_MOVED == eventType ) {
+ final DisplayDriver display = (DisplayDriver) getScreen().getDisplay();
+ display.moveActivePointerIcon(x, y);
+ }
+ super.doMouseEvent(enqueue, wait, eventType, modifiers, x, y, button, rotationXYZ, rotationScale);
+ }
+
+ @Override
+ protected void setPointerIconImpl(final PointerIconImpl pi) {
+ final DisplayDriver display = (DisplayDriver) getScreen().getDisplay();
+ display.setPointerIconActive(null != pi ? pi.validatedHandle() : 0, linuxMouseTracker.getLastX(), linuxMouseTracker.getLastY());
+ }
+
+ @Override
+ protected boolean setPointerVisibleImpl(final boolean pointerVisible) {
+ final DisplayDriver display = (DisplayDriver) getScreen().getDisplay();
+ display.setActivePointerIconVisible(pointerVisible, linuxMouseTracker.getLastX(), linuxMouseTracker.getLastY());
+ return true;
}
-
+
//----------------------------------------------------------------------
// Internals only
//
+ private final LinuxMouseTracker linuxMouseTracker;
+ private final LinuxEventDeviceTracker linuxEventDeviceTracker;
protected static native boolean initIDs();
- private native long CreateWindow(int width, int height);
- private native long RealizeWindow(long eglWindowHandle);
- private native int CloseWindow(long eglWindowHandle, long userData);
- private native void setVisible0(long eglWindowHandle, boolean visible);
- private native void setSize0(long eglWindowHandle, int width, int height);
- private native void setFullScreen0(long eglWindowHandle, boolean fullscreen);
-
- private void windowCreated(long userData) {
- windowUserData=userData;
- }
+ private native long CreateWindow0(long bcmDisplay, int layer, int x, int y, int width, int height, boolean opaque, int alphaBits);
+ private native void CloseWindow0(long bcmDisplay, long eglWindowHandle);
+ private native void reconfigure0(long eglWindowHandle, int x, int y, int width, int height, int flags);
+ private int layer;
private long nativeWindowHandle;
private long windowHandleClose;
- private long windowUserData;
+
+ private static int nextLayer = 0;
+ private static int layerCount = 0;
+ private static final int MAX_LAYERS = 32;
+ private static final IntBitfield usedLayers = new IntBitfield(MAX_LAYERS);
+ private static final Object layerSync = new Object();
}
diff --git a/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java
index 97c384d33..1d43017c3 100644
--- a/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2012 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.intel.gdl;
@@ -59,6 +59,7 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl {
public DisplayDriver() {
}
+ @Override
protected void createNativeImpl() {
synchronized(DisplayDriver.class) {
if(0==initCounter) {
@@ -72,7 +73,8 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl {
aDevice = new DefaultGraphicsDevice(NativeWindowFactory.TYPE_DEFAULT, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT, displayHandle);
}
- protected void closeNativeImpl() {
+ @Override
+ protected void closeNativeImpl(final AbstractGraphicsDevice aDevice) {
if(0==displayHandle) {
throw new NativeWindowException("displayHandle null; initCnt "+initCounter);
}
@@ -84,15 +86,17 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl {
}
}
}
+ aDevice.close();
}
+ @Override
protected void dispatchMessagesNative() {
if(0!=displayHandle) {
DispatchMessages(displayHandle, focusedWindow);
}
}
- protected void setFocus(WindowDriver focus) {
+ protected void setFocus(final WindowDriver focus) {
focusedWindow = focus;
}
diff --git a/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java
index 8eed14dde..2ce835c52 100644
--- a/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2012 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,15 +29,20 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.intel.gdl;
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.DefaultGraphicsScreen;
-import javax.media.nativewindow.util.Dimension;
-import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.util.Rectangle;
+
+import jogamp.newt.MonitorModeProps;
+import jogamp.newt.ScreenImpl;
+
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
public class ScreenDriver extends jogamp.newt.ScreenImpl {
@@ -48,25 +53,68 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl {
public ScreenDriver() {
}
+ @Override
protected void createNativeImpl() {
- AbstractGraphicsDevice adevice = getDisplay().getGraphicsDevice();
+ final AbstractGraphicsDevice adevice = getDisplay().getGraphicsDevice();
GetScreenInfo(adevice.getHandle(), screen_idx);
aScreen = new DefaultGraphicsScreen(adevice, screen_idx);
}
+ @Override
protected void closeNativeImpl() { }
- protected int validateScreenIndex(int idx) {
- return 0; // only one screen available
+ @Override
+ protected int validateScreenIndex(final int idx) {
+ return 0; // only one screen available
+ }
+
+ @Override
+ protected final void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) {
+ int[] props = new int[ MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL ];
+ int i = 0;
+ props[i++] = MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL;
+ props[i++] = cachedWidth; // width
+ props[i++] = cachedHeight; // height
+ props[i++] = ScreenImpl.default_sm_bpp; // FIXME
+ props[i++] = ScreenImpl.default_sm_rate * 100; // FIXME
+ props[i++] = 0; // flags
+ props[i++] = 0; // mode_idx
+ props[i++] = 0; // rotation
+ final MonitorMode currentMode = MonitorModeProps.streamInMonitorMode(null, cache, props, 0);
+
+ props = new int[MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES - 1 - MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES];
+ i = 0;
+ props[i++] = props.length;
+ props[i++] = 0; // crt_idx
+ props[i++] = ScreenImpl.default_sm_widthmm; // FIXME
+ props[i++] = ScreenImpl.default_sm_heightmm; // FIXME
+ props[i++] = 0; // rotated viewport x pixel-units
+ props[i++] = 0; // rotated viewport y pixel-units
+ props[i++] = cachedWidth; // rotated viewport width pixel-units
+ props[i++] = cachedWidth; // rotated viewport height pixel-units
+ props[i++] = 0; // rotated viewport x window-units
+ props[i++] = 0; // rotated viewport y window-units
+ props[i++] = cachedWidth; // rotated viewport width window-units
+ props[i++] = cachedWidth; // rotated viewport height window-units
+ MonitorModeProps.streamInMonitorDevice(null, cache, this, cache.monitorModes, currentMode, props, 0);
+ }
+
+ @Override
+ protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) {
+ return monitor.getSupportedModes().get(0);
+ }
+
+ @Override
+ protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) {
+ return false;
}
-
- protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) {
- virtualOrigin.setX(0);
- virtualOrigin.setY(0);
- virtualSize.setWidth(cachedWidth);
- virtualSize.setHeight(cachedHeight);
+
+ @Override
+ protected void calcVirtualScreenOriginAndSize(final Rectangle viewport, final Rectangle viewportInWindowUnits) {
+ viewport.set(0, 0, cachedWidth, cachedHeight);
+ viewportInWindowUnits.set(viewport);
}
-
+
//----------------------------------------------------------------------
// Internals only
//
@@ -75,11 +123,11 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl {
private native void GetScreenInfo(long displayHandle, int screen_idx);
// called by GetScreenInfo() ..
- private void screenCreated(int width, int height) {
+ private void screenCreated(final int width, final int height) {
cachedWidth = width;
cachedHeight = height;
}
-
+
private static int cachedWidth = 0;
private static int cachedHeight = 0;
}
diff --git a/src/newt/classes/jogamp/newt/driver/intel/gdl/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/intel/gdl/WindowDriver.java
index 98335f192..d7bd17e42 100644
--- a/src/newt/classes/jogamp/newt/driver/intel/gdl/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/WindowDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2012 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.intel.gdl;
@@ -48,6 +48,7 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
static long nextWindowHandle = 1;
+ @Override
protected void createNativeImpl() {
if(0!=getParentWindowHandle()) {
throw new NativeWindowException("GDL Window does not support window parenting");
@@ -65,13 +66,15 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
synchronized(WindowDriver.class) {
setWindowHandle(nextWindowHandle++); // just a marker
- surfaceHandle = CreateSurface(aDevice.getHandle(), getScreen().getWidth(), getScreen().getHeight(), getX(), getY(), getWidth(), getHeight());
+ surfaceHandle = CreateSurface(aDevice.getHandle(), getScreen().getWidth(), getScreen().getHeight(),
+ getX(), getY(), getSurfaceWidth(), getSurfaceHeight());
if (surfaceHandle == 0) {
throw new NativeWindowException("Error creating window");
}
}
}
+ @Override
protected void closeNativeImpl() {
if(0!=surfaceHandle) {
synchronized(WindowDriver.class) {
@@ -82,9 +85,11 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
}
}
- protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
- ScreenDriver screen = (ScreenDriver) getScreen();
+ @Override
+ protected boolean reconfigureWindowImpl(int x, int y, int width, int height, final int flags) {
+ final ScreenDriver screen = (ScreenDriver) getScreen();
+ // Note for GDL: window units == pixel units
if(width>screen.getWidth()) {
width=screen.getWidth();
}
@@ -108,11 +113,12 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
}
visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
}
-
+
return true;
}
- protected void requestFocusImpl(boolean reparented) {
+ @Override
+ protected void requestFocusImpl(final boolean reparented) {
((DisplayDriver)getScreen().getDisplay()).setFocus(this);
}
@@ -121,14 +127,16 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
return surfaceHandle;
}
- protected Point getLocationOnScreenImpl(int x, int y) {
+ @Override
+ protected Point getLocationOnScreenImpl(final int x, final int y) {
return new Point(x,y);
}
- protected void updateInsetsImpl(Insets insets) {
- // nop ..
+ @Override
+ protected void updateInsetsImpl(final Insets insets) {
+ // nop ..
}
-
+
//----------------------------------------------------------------------
// Internals only
//
@@ -138,7 +146,7 @@ public class WindowDriver extends jogamp.newt.WindowImpl {
private native void CloseSurface(long displayHandle, long surfaceHandle);
private native void SetBounds0(long surfaceHandle, int scrn_width, int scrn_height, int x, int y, int width, int height);
- private void updateBounds(int x, int y, int width, int height) {
+ private void updateBounds(final int x, final int y, final int width, final int height) {
definePosition(x, y);
defineSize(width, height);
}
diff --git a/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java
index 745be5dae..e72ddbc11 100644
--- a/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2012 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.kd;
@@ -59,15 +59,19 @@ public class DisplayDriver extends DisplayImpl {
public DisplayDriver() {
}
+ @Override
protected void createNativeImpl() {
// FIXME: map name to EGL_*_DISPLAY
aDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT);
+ aDevice.open();
}
- protected void closeNativeImpl() {
+ @Override
+ protected void closeNativeImpl(final AbstractGraphicsDevice aDevice) {
aDevice.close();
}
+ @Override
protected void dispatchMessagesNative() {
DispatchMessages();
}
diff --git a/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java
index 656bcf5c9..d4113561a 100644
--- a/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2012 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,15 +29,18 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.kd;
import javax.media.nativewindow.DefaultGraphicsScreen;
-import javax.media.nativewindow.util.Dimension;
-import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.util.Rectangle;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+
+import jogamp.newt.MonitorModeProps;
import jogamp.newt.ScreenImpl;
public class ScreenDriver extends ScreenImpl {
@@ -48,28 +51,71 @@ public class ScreenDriver extends ScreenImpl {
public ScreenDriver() {
}
+ @Override
protected void createNativeImpl() {
aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx);
}
+ @Override
protected void closeNativeImpl() { }
- protected int validateScreenIndex(int idx) {
- return 0; // only one screen available
- }
-
- protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) {
- virtualOrigin.setX(0);
- virtualOrigin.setY(0);
- virtualSize.setWidth(cachedWidth);
- virtualSize.setHeight(cachedHeight);
+ @Override
+ protected int validateScreenIndex(final int idx) {
+ return 0; // only one screen available
+ }
+
+ @Override
+ protected final void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) {
+ int[] props = new int[ MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL ];
+ int i = 0;
+ props[i++] = MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL;
+ props[i++] = cachedWidth; // width
+ props[i++] = cachedHeight; // height
+ props[i++] = ScreenImpl.default_sm_bpp; // FIXME
+ props[i++] = ScreenImpl.default_sm_rate * 100; // FIXME
+ props[i++] = 0; // flags
+ props[i++] = 0; // mode_idx
+ props[i++] = 0; // rotation
+ final MonitorMode currentMode = MonitorModeProps.streamInMonitorMode(null, cache, props, 0);
+
+ props = new int[MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES - 1 - MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES];
+ i = 0;
+ props[i++] = props.length;
+ props[i++] = 0; // crt_idx
+ props[i++] = ScreenImpl.default_sm_widthmm; // FIXME
+ props[i++] = ScreenImpl.default_sm_heightmm; // FIXME
+ props[i++] = 0; // rotated viewport x pixel-units
+ props[i++] = 0; // rotated viewport y pixel-units
+ props[i++] = cachedWidth; // rotated viewport width pixel-units
+ props[i++] = cachedWidth; // rotated viewport height pixel-units
+ props[i++] = 0; // rotated viewport x window-units
+ props[i++] = 0; // rotated viewport y window-units
+ props[i++] = cachedWidth; // rotated viewport width window-units
+ props[i++] = cachedWidth; // rotated viewport height window-units
+ MonitorModeProps.streamInMonitorDevice(null, cache, this, cache.monitorModes, currentMode, props, 0);
+ }
+
+ @Override
+ protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) {
+ return monitor.getSupportedModes().get(0);
}
-
- protected void sizeChanged(int w, int h) {
- cachedWidth = w;
- cachedHeight = h;
+
+ @Override
+ protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) {
+ return false;
+ }
+
+ @Override
+ protected void calcVirtualScreenOriginAndSize(final Rectangle viewport, final Rectangle viewportInWindowUnits) {
+ viewport.set(0, 0, cachedWidth, cachedHeight);
+ viewportInWindowUnits.set(viewport);
}
-
+
+ protected void sizeChanged(final int w, final int h) {
+ cachedWidth = w; // write to static field intended
+ cachedHeight = h; // write to static field intended
+ }
+
private static int cachedWidth = 0;
- private static int cachedHeight = 0;
+ private static int cachedHeight = 0;
}
diff --git a/src/newt/classes/jogamp/newt/driver/kd/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/kd/WindowDriver.java
index c733a3e94..d53ef00cd 100644
--- a/src/newt/classes/jogamp/newt/driver/kd/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/kd/WindowDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2012 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.kd;
@@ -56,6 +56,7 @@ public class WindowDriver extends WindowImpl {
public WindowDriver() {
}
+ @Override
protected void createNativeImpl() {
if(0!=getParentWindowHandle()) {
throw new RuntimeException("Window parenting not supported (yet)");
@@ -67,9 +68,9 @@ public class WindowDriver extends WindowImpl {
}
setGraphicsConfiguration(cfg);
- GLCapabilitiesImmutable eglCaps = (GLCapabilitiesImmutable) cfg.getChosenCapabilities();
- int eglConfigID = eglCaps.getVisualID(VIDType.EGL_CONFIG);
- long eglConfig = EGLGraphicsConfiguration.EGLConfigId2EGLConfig(getDisplayHandle(), eglConfigID);
+ final GLCapabilitiesImmutable eglCaps = (GLCapabilitiesImmutable) cfg.getChosenCapabilities();
+ final int eglConfigID = eglCaps.getVisualID(VIDType.EGL_CONFIG);
+ final long eglConfig = EGLGraphicsConfiguration.EGLConfigId2EGLConfig(getDisplayHandle(), eglConfigID);
eglWindowHandle = CreateWindow(getDisplayHandle(), eglConfig);
if (eglWindowHandle == 0) {
@@ -83,6 +84,7 @@ public class WindowDriver extends WindowImpl {
windowHandleClose = eglWindowHandle;
}
+ @Override
protected void closeNativeImpl() {
if(0!=windowHandleClose) {
CloseWindow(windowHandleClose, windowUserData);
@@ -90,14 +92,16 @@ public class WindowDriver extends WindowImpl {
}
}
- protected void requestFocusImpl(boolean reparented) { }
+ @Override
+ protected void requestFocusImpl(final boolean reparented) { }
- protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
+ @Override
+ protected boolean reconfigureWindowImpl(final int x, final int y, int width, int height, final int flags) {
if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
setVisible0(eglWindowHandle, 0 != ( FLAG_IS_VISIBLE & flags));
visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
}
-
+
if(0!=eglWindowHandle) {
if(0 != ( FLAG_CHANGE_FULLSCREEN & flags)) {
final boolean fs = 0 != ( FLAG_IS_FULLSCREEN & flags) ;
@@ -117,22 +121,24 @@ public class WindowDriver extends WindowImpl {
System.err.println("setPosition n/a in KD");
}
}
-
+
if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
}
-
+
return true;
}
- protected Point getLocationOnScreenImpl(int x, int y) {
+ @Override
+ protected Point getLocationOnScreenImpl(final int x, final int y) {
return new Point(x,y);
}
- protected void updateInsetsImpl(Insets insets) {
- // nop ..
+ @Override
+ protected void updateInsetsImpl(final Insets insets) {
+ // nop ..
}
-
+
//----------------------------------------------------------------------
// Internals only
//
@@ -145,12 +151,12 @@ public class WindowDriver extends WindowImpl {
private native void setSize0(long eglWindowHandle, int width, int height);
private native void setFullScreen0(long eglWindowHandle, boolean fullscreen);
- private void windowCreated(long userData) {
+ private void windowCreated(final long userData) {
windowUserData=userData;
}
@Override
- protected void sizeChanged(boolean defer, int newWidth, int newHeight, boolean force) {
+ protected void sizeChanged(final boolean defer, final int newWidth, final int newHeight, final boolean force) {
if(isFullscreen()) {
((ScreenDriver)getScreen()).sizeChanged(getWidth(), getHeight());
}
diff --git a/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java b/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java
new file mode 100644
index 000000000..49a815cb6
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java
@@ -0,0 +1,959 @@
+/**
+ * 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.linux;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.Integer;
+import java.lang.Runnable;
+import java.lang.String;
+import java.lang.Thread;
+import java.nio.ByteBuffer;
+
+import jogamp.newt.WindowImpl;
+
+import com.jogamp.common.nio.StructAccessor;
+import com.jogamp.newt.Window;
+import com.jogamp.newt.event.InputEvent;
+import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.event.WindowListener;
+import com.jogamp.newt.event.WindowUpdateEvent;
+import com.jogamp.newt.event.KeyEvent;
+
+/**
+ * Experimental native event device tracker thread for GNU/Linux
+ * just reading <code>/dev/input/event*</code>
+ * within it's own polling thread.
+ */
+
+public class LinuxEventDeviceTracker implements WindowListener {
+
+ private static final LinuxEventDeviceTracker ledt;
+
+
+ static {
+ ledt = new LinuxEventDeviceTracker();
+ final Thread t = new Thread(ledt.eventDeviceManager, "NEWT-LinuxEventDeviceManager");
+ t.setDaemon(true);
+ t.start();
+ }
+
+ public static LinuxEventDeviceTracker getSingleton() {
+ return ledt;
+ }
+
+ private WindowImpl focusedWindow = null;
+ private final EventDeviceManager eventDeviceManager = new EventDeviceManager();
+
+ /*
+ The devices are in /dev/input:
+
+ crw-r--r-- 1 root root 13, 64 Apr 1 10:49 event0
+ crw-r--r-- 1 root root 13, 65 Apr 1 10:50 event1
+ crw-r--r-- 1 root root 13, 66 Apr 1 10:50 event2
+ crw-r--r-- 1 root root 13, 67 Apr 1 10:50 event3
+ ...
+
+ And so on up to event31.
+ */
+ private final EventDevicePoller[] eventDevicePollers = new EventDevicePoller[32];
+
+ @Override
+ public void windowResized(final WindowEvent e) { }
+
+ @Override
+ public void windowMoved(final WindowEvent e) { }
+
+ @Override
+ public void windowDestroyNotify(final WindowEvent e) {
+ final Object s = e.getSource();
+ if(focusedWindow == s) {
+ focusedWindow = null;
+ }
+ }
+
+ @Override
+ public void windowDestroyed(final WindowEvent e) { }
+
+ @Override
+ public void windowGainedFocus(final WindowEvent e) {
+ final Object s = e.getSource();
+ if(s instanceof WindowImpl) {
+ focusedWindow = (WindowImpl) s;
+ }
+ }
+
+ @Override
+ public void windowLostFocus(final WindowEvent e) {
+ final Object s = e.getSource();
+ if(focusedWindow == s) {
+ focusedWindow = null;
+ }
+ }
+
+ public static void main(final String[] args ){
+ System.setProperty("newt.debug.Window.KeyEvent", "true");
+ LinuxEventDeviceTracker.getSingleton();
+ try {
+ while(true) {
+ Thread.sleep(1000);
+ }
+ } catch (final InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void windowRepaint(final WindowUpdateEvent e) { }
+
+ class EventDeviceManager implements Runnable {
+
+ private volatile boolean stop = false;
+
+ @Override
+ public void run() {
+ final File f = new File("/dev/input/");
+ int number;
+ while(!stop){
+ for(final String path:f.list()){
+ if(path.startsWith("event")) {
+ final String stringNumber = path.substring(5);
+ number = Integer.parseInt(stringNumber);
+ if(number<32&&number>=0) {
+ if(eventDevicePollers[number]==null){
+ eventDevicePollers[number] = new EventDevicePoller(number);
+ final Thread t = new Thread(eventDevicePollers[number], "NEWT-LinuxEventDeviceTracker-event"+number);
+ t.setDaemon(true);
+ t.start();
+ } else if(eventDevicePollers[number].stop) {
+ eventDevicePollers[number]=null;
+ }
+ }
+ }
+ }
+ try {
+ Thread.sleep(2000);
+ } catch (final InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ class EventDevicePoller implements Runnable {
+
+ private volatile boolean stop = false;
+ private final String eventDeviceName;
+
+ public EventDevicePoller(final int eventDeviceNumber){
+ this.eventDeviceName="/dev/input/event"+eventDeviceNumber;
+ }
+
+ @Override
+ public void run() {
+ final byte[] b = new byte[16];
+ /**
+ * The Linux input event interface.
+ * http://www.kernel.org/doc/Documentation/input/input.txt
+ *
+ * struct input_event {
+ * struct timeval time;
+ * unsigned short type;
+ * unsigned short code;
+ * unsigned int value;
+ * };
+ */
+ final ByteBuffer bb = ByteBuffer.wrap(b);
+ final StructAccessor s = new StructAccessor(bb);
+ final File f = new File(eventDeviceName);
+ f.setReadOnly();
+ InputStream fis;
+ try {
+ fis = new FileInputStream(f);
+ } catch (final FileNotFoundException e) {
+ stop=true;
+ return;
+ }
+
+ int timeSeconds;
+ int timeSecondFraction;
+ short type;
+ short code;
+ int value;
+
+ short keyCode=KeyEvent.VK_UNDEFINED;
+ char keyChar=' ';
+ short eventType=0;
+ int modifiers=0;
+
+ loop:
+ while(!stop) {
+ int remaining=16;
+ while(remaining>0) {
+ int read = 0;
+ try {
+ read = fis.read(b, 0, remaining);
+ } catch (final IOException e) {
+ stop = true;
+ break loop;
+ }
+ if(read<0) {
+ stop = true; // EOF of event device file !?
+ break loop;
+ } else {
+ remaining -= read;
+ }
+ }
+
+ timeSeconds = s.getIntAt(0);
+ timeSecondFraction = s.getShortAt(4);
+ type = s.getShortAt(8);
+ code = s.getShortAt(10);
+ value = s.getIntAt(12);
+
+
+ /*
+ * Linux sends Keyboard events in the following order:
+ * EV_MSC (optional, contains scancode)
+ * EV_KEY
+ * SYN_REPORT (sent before next key)
+ */
+
+ switch(type) {
+ case 0: // SYN_REPORT
+ // Clear
+ eventType = 0;
+ keyCode = KeyEvent.VK_UNDEFINED;
+ keyChar = 0; // Print null for unprintable char.
+ if(Window.DEBUG_KEY_EVENT) {
+ System.out.println("[SYN_REPORT----]");
+ }
+ break;
+ case 1: // EV_KEY
+ keyCode = LinuxEVKey2NewtVKey(code); // The device independent code.
+ keyChar = NewtVKey2Unicode(keyCode, modifiers); // The printable character w/ key modifiers.
+ if(Window.DEBUG_KEY_EVENT) {
+ System.out.println("[EV_KEY: [time "+timeSeconds+":"+timeSecondFraction+"] type "+type+" / code "+code+" = value "+value);
+ }
+
+ switch(value) {
+ case 0:
+ eventType=KeyEvent.EVENT_KEY_RELEASED;
+
+ switch(keyCode) {
+ case KeyEvent.VK_SHIFT:
+ modifiers &= ~InputEvent.SHIFT_MASK;
+ break;
+ case KeyEvent.VK_ALT:
+ modifiers &= ~InputEvent.ALT_MASK;
+ break;
+ case KeyEvent.VK_ALT_GRAPH:
+ modifiers &= ~InputEvent.ALT_GRAPH_MASK;
+ break;
+ case KeyEvent.VK_CONTROL:
+ modifiers &= ~InputEvent.CTRL_MASK;
+ break;
+ }
+
+ if(null != focusedWindow) {
+ focusedWindow.sendKeyEvent(eventType, modifiers, keyCode, keyCode, keyChar);
+ }
+ if(Window.DEBUG_KEY_EVENT) {
+ System.out.println("[event released] keyCode: "+keyCode+" keyChar: "+keyChar+ " modifiers: "+modifiers);
+ }
+ break;
+ case 1:
+ eventType=KeyEvent.EVENT_KEY_PRESSED;
+
+ switch(keyCode) {
+ case KeyEvent.VK_SHIFT:
+ modifiers |= InputEvent.SHIFT_MASK;
+ break;
+ case KeyEvent.VK_ALT:
+ modifiers |= InputEvent.ALT_MASK;
+ break;
+ case KeyEvent.VK_ALT_GRAPH:
+ modifiers |= InputEvent.ALT_GRAPH_MASK;
+ break;
+ case KeyEvent.VK_CONTROL:
+ modifiers |= InputEvent.CTRL_MASK;
+ break;
+ }
+
+ if(null != focusedWindow) {
+ focusedWindow.sendKeyEvent(eventType, modifiers, keyCode, keyCode, keyChar);
+ }
+ if(Window.DEBUG_KEY_EVENT) {
+ System.out.println("[event pressed] keyCode: "+keyCode+" keyChar: "+keyChar+ " modifiers: "+modifiers);
+ }
+ break;
+ case 2:
+ eventType=KeyEvent.EVENT_KEY_PRESSED;
+ modifiers |= InputEvent.AUTOREPEAT_MASK;
+
+ switch(keyCode) {
+ case KeyEvent.VK_SHIFT:
+ modifiers |= InputEvent.SHIFT_MASK;
+ break;
+ case KeyEvent.VK_ALT:
+ modifiers |= InputEvent.ALT_MASK;
+ break;
+ case KeyEvent.VK_ALT_GRAPH:
+ modifiers |= InputEvent.ALT_GRAPH_MASK;
+ break;
+ case KeyEvent.VK_CONTROL:
+ modifiers |= InputEvent.CTRL_MASK;
+ break;
+ }
+
+ if(null != focusedWindow) {
+ //Send syntetic autorepeat release
+ focusedWindow.sendKeyEvent(KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, keyCode, keyChar);
+
+ focusedWindow.sendKeyEvent(eventType, modifiers, keyCode, keyCode, keyChar);
+ }
+ if(Window.DEBUG_KEY_EVENT) {
+ System.out.println("[event released auto] keyCode: "+keyCode+" keyChar: "+keyChar+ " modifiers: "+modifiers);
+ System.out.println("[event pressed auto] keyCode: "+keyCode+" keyChar: "+keyChar+ " modifiers: "+modifiers);
+ }
+ modifiers &= ~InputEvent.AUTOREPEAT_MASK;
+ break;
+ }
+ break;
+ case 4: // EV_MSC
+ if(code==4) { // MSC_SCAN
+ // scancode ignore, linux kernel specific
+ }
+ break;
+ // TODO: handle joystick events
+ // TODO: handle mouse events
+ // TODO: handle headphone/hdmi connector events
+ default: // Print number.
+ if(Window.DEBUG_KEY_EVENT) {
+ System.out.println("TODO EventDevicePoller: [time "+timeSeconds+":"+timeSecondFraction+"] type "+type+" / code "+code+" = value "+value);
+ }
+ }
+ }
+
+ if(null != fis) {
+ try {
+ fis.close();
+ } catch (final IOException e) {
+ }
+ }
+ stop=true;
+ }
+
+ private char NewtVKey2Unicode(final short VK, final int modifiers) {
+ if( KeyEvent.isPrintableKey(VK, true) ) {
+ if((modifiers & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK) {
+ return (char)VK;
+ } else {
+ return String.valueOf((char)VK).toLowerCase().charAt(0);
+ }
+ }
+ return 0;
+ }
+
+ @SuppressWarnings("unused")
+ private char LinuxEVKey2Unicode(final short EVKey) {
+ // This is the stuff normally mapped by a system keymap
+
+ switch(EVKey) {
+ case 17: // w
+ return 'w';
+ case 31: // s
+ return 's';
+ case 30: // a
+ return 'a';
+ case 32: // d
+ return 'd';
+ case 1: // ESC
+ return 27;
+ case 28: // Enter
+ case 96: // Keypad Enter
+ return '\n';
+ case 57: // Space
+ return ' ';
+ case 11: // 0
+ case 82: // Numpad 0
+ return '0';
+ case 2: // 1
+ case 79: // Numpad 1
+ return '1';
+ case 3: // 2
+ case 80: // Numpad 1
+ return '2';
+ case 4: // 3
+ case 81: // Numpad 3
+ return '3';
+ case 5: // 4
+ case 75: // Numpad 4
+ return '4';
+ case 6: // 5
+ case 76: // Numpad 5
+ return '5';
+ case 7: // 6
+ case 77: // Numpad 6
+ return '6';
+ case 8: // 7
+ case 71: // Numpad 7
+ return '7';
+ case 9: // 8
+ case 72: // Numpad 8
+ return '8';
+ case 10: // 9
+ case 73: // Numpad 9
+ return '9';
+
+ default:
+ }
+
+ return 0;
+ }
+
+ private short LinuxEVKey2NewtVKey(final short EVKey) {
+
+ switch(EVKey) {
+ case 1: // ESC
+ return KeyEvent.VK_ESCAPE;
+ case 2: // 1
+ return KeyEvent.VK_1;
+ case 79: // Numpad 1
+ return KeyEvent.VK_NUMPAD1;
+ case 3: // 2
+ return KeyEvent.VK_2;
+ case 80: // Numpad 2
+ return KeyEvent.VK_NUMPAD2;
+ case 4: // 3
+ return KeyEvent.VK_3;
+ case 81: // Numpad 3
+ return KeyEvent.VK_NUMPAD3;
+ case 5: // 4
+ return KeyEvent.VK_4;
+ case 75: // Numpad 4
+ return KeyEvent.VK_NUMPAD4;
+ case 6: // 5
+ return KeyEvent.VK_5;
+ case 76: // Numpad 5
+ return KeyEvent.VK_NUMPAD5;
+ case 7: // 6
+ return KeyEvent.VK_6;
+ case 77: // Numpad 6
+ return KeyEvent.VK_NUMPAD6;
+ case 8: // 7
+ return KeyEvent.VK_7;
+ case 71: // Numpad 7
+ return KeyEvent.VK_NUMPAD7;
+ case 9: // 8
+ return KeyEvent.VK_8;
+ case 72: // Numpad 8
+ return KeyEvent.VK_NUMPAD8;
+ case 10: // 9
+ return KeyEvent.VK_9;
+ case 73: // Numpad 9
+ return KeyEvent.VK_NUMPAD9;
+ case 11: // 0
+ return KeyEvent.VK_0;
+ case 82: // Numpad 0
+ return KeyEvent.VK_NUMPAD0;
+ case 12:
+ return KeyEvent.VK_MINUS;
+ case 13:
+ return KeyEvent.VK_EQUALS;
+ case 14: // Backspace
+ return KeyEvent.VK_BACK_SPACE;
+
+ case 15:
+ return KeyEvent.VK_TAB;
+ case 16:
+ return KeyEvent.VK_Q;
+ case 17: // w
+ return KeyEvent.VK_W;
+ case 18:
+ return KeyEvent.VK_E;
+ case 19:
+ return KeyEvent.VK_R;
+ case 20:
+ return KeyEvent.VK_T;
+ case 21:
+ return KeyEvent.VK_Y;
+ case 22:
+ return KeyEvent.VK_U;
+ case 23:
+ return KeyEvent.VK_I;
+ case 24:
+ return KeyEvent.VK_O;
+ case 25:
+ return KeyEvent.VK_P;
+ case 26: // left brace
+ return KeyEvent.VK_LEFT_PARENTHESIS;
+ case 27: // right brace
+ return KeyEvent.VK_RIGHT_PARENTHESIS;
+ case 28: // Enter
+ case 96: // Keypad Enter
+ return KeyEvent.VK_ENTER;
+
+ case 29: // left ctrl
+ return KeyEvent.VK_CONTROL;
+ case 30: // a
+ return KeyEvent.VK_A;
+ case 31: // s
+ return KeyEvent.VK_S;
+ case 32: // d
+ return KeyEvent.VK_D;
+ case 33:
+ return KeyEvent.VK_F;
+ case 34:
+ return KeyEvent.VK_G;
+ case 35:
+ return KeyEvent.VK_H;
+ case 36:
+ return KeyEvent.VK_J;
+ case 37:
+ return KeyEvent.VK_K;
+ case 38:
+ return KeyEvent.VK_L;
+ case 39:
+ return KeyEvent.VK_SEMICOLON;
+ case 40: // apostrophe
+ return KeyEvent.VK_QUOTE;
+ case 41: // grave
+ return KeyEvent.VK_BACK_QUOTE;
+
+ case 42: // left shift
+ return KeyEvent.VK_SHIFT;
+ case 43:
+ return KeyEvent.VK_BACK_SLASH;
+ case 44:
+ return KeyEvent.VK_Z;
+ case 45:
+ return KeyEvent.VK_X;
+ case 46:
+ return KeyEvent.VK_C;
+ case 47:
+ return KeyEvent.VK_V;
+ case 48:
+ return KeyEvent.VK_B;
+ case 49:
+ return KeyEvent.VK_N;
+ case 50:
+ return KeyEvent.VK_M;
+ case 51:
+ return KeyEvent.VK_COMMA;
+ case 52: // dot
+ return KeyEvent.VK_PERIOD;
+ case 53:
+ return KeyEvent.VK_SLASH;
+ case 54:
+ return KeyEvent.VK_SHIFT;
+ case 55: // kp asterisk
+ return KeyEvent.VK_ASTERISK;
+ case 56: // left alt
+ return KeyEvent.VK_ALT;
+ case 57: // Space
+ return KeyEvent.VK_SPACE;
+ case 58:
+ return KeyEvent.VK_CAPS_LOCK;
+
+ case 59:
+ return KeyEvent.VK_F1;
+ case 60:
+ return KeyEvent.VK_F2;
+ case 61:
+ return KeyEvent.VK_F3;
+ case 62:
+ return KeyEvent.VK_F4;
+ case 63:
+ return KeyEvent.VK_F5;
+ case 64:
+ return KeyEvent.VK_F6;
+ case 65:
+ return KeyEvent.VK_F7;
+ case 66:
+ return KeyEvent.VK_F8;
+ case 67:
+ return KeyEvent.VK_F9;
+ case 68:
+ return KeyEvent.VK_F10;
+
+ case 69:
+ return KeyEvent.VK_NUM_LOCK;
+ case 70:
+ return KeyEvent.VK_SCROLL_LOCK;
+
+ case 74: // kp minus
+ return KeyEvent.VK_MINUS;
+ case 78: // kp plus
+ return KeyEvent.VK_PLUS;
+ case 83: // kp dot
+ return KeyEvent.VK_PERIOD;
+
+ // TODO: add mappings for japanese special buttons
+ case 85: // zenkakuhankaku
+ case 86: // 102nd
+ break; // FIXME
+
+ case 87:
+ return KeyEvent.VK_F11;
+ case 88:
+ return KeyEvent.VK_F12;
+
+ case 89: // ro
+ return KeyEvent.VK_ROMAN_CHARACTERS;
+ case 90: // Katakana
+ return KeyEvent.VK_KATAKANA;
+ case 91:
+ return KeyEvent.VK_HIRAGANA;
+
+ case 92: // kenkan
+ break; // FIXME
+ case 93: // katakana hiragana
+ break; // FIXME
+ case 94: // mu henkan
+ break; // FIXME
+ case 95: // kp jp comma
+ break; // FIXME
+
+ case 97: // right ctrl
+ return KeyEvent.VK_CONTROL;
+ case 98: // kp slash
+ return KeyEvent.VK_SLASH;
+
+ case 99: // sysrq
+ break; // FIXME
+
+ case 100: // right alt
+ return KeyEvent.VK_ALT;
+ case 101: // linefeed
+ break; // FIXME
+ case 102: // home
+ return KeyEvent.VK_HOME;
+ case 103: // KEY_UP
+ return KeyEvent.VK_UP;
+ case 104:
+ return KeyEvent.VK_PAGE_UP;
+ case 105: // KEY_LEFT
+ return KeyEvent.VK_LEFT;
+ case 106: // KEY_RIGHT
+ return KeyEvent.VK_RIGHT;
+ case 107:
+ return KeyEvent.VK_END;
+ case 108: // KEY_DOWN
+ return KeyEvent.VK_DOWN;
+ case 109:
+ return KeyEvent.VK_PAGE_DOWN;
+ case 110:
+ return KeyEvent.VK_INSERT;
+ case 111: // del
+ return KeyEvent.VK_DELETE;
+
+ case 112: // macro
+ break; // FIXME DEAD_MACRON?
+ case 113: // mute
+ break; // FIXME
+ case 114: // vol up
+ break; // FIXME
+ case 115: // vol down
+ break; // FIXME
+ case 116: // power
+ break; // FIXME
+
+ case 117: // kp equals
+ return KeyEvent.VK_EQUALS;
+ case 118: // kp plus minux
+ break; // FIXME
+ case 119: // pause
+ return KeyEvent.VK_PAUSE;
+ case 120: // scale AL compiz scale expose
+ break; // FIXME
+ case 121: // kp comma
+ return KeyEvent.VK_COMMA;
+ case 122: // hangeul
+ break; // FIXME
+ case 123: // hanja
+ break; // FIXME
+ case 124: // yen
+ break; // FIXME
+
+ case 125: // left meta
+ case 126: // right meta
+ return KeyEvent.VK_META;
+ case 127: // compose
+ return KeyEvent.VK_COMPOSE;
+
+ case 128: // stop
+ return KeyEvent.VK_STOP;
+ case 129: // again
+ return KeyEvent.VK_AGAIN;
+ case 130: // properties
+ return KeyEvent.VK_PROPS;
+ case 131: // undo
+ return KeyEvent.VK_UNDO;
+ case 132: // front
+ break; // FIXME
+ case 133: // copy
+ return KeyEvent.VK_COPY;
+ case 134: // open
+ break; // FIXME
+ case 135: // paste
+ return KeyEvent.VK_PASTE;
+ case 136: // find
+ return KeyEvent.VK_FIND;
+ case 137: // cut
+ return KeyEvent.VK_CUT;
+ case 138: // help
+ return KeyEvent.VK_HELP;
+ case 139: // menu
+ break; // FIXME
+ case 140: // calc
+ break; // FIXME
+ case 141: // setup
+ break; // FIXME
+ case 142: // sleep
+ break; // FIXME
+ case 143: // wakeup
+ break; // FIXME
+ case 144: // file
+ break; // FIXME
+ case 145: // send file
+ break; // FIXME
+ case 146: // delete file
+ break; // FIXME
+ case 147: // xfer
+ break; // FIXME
+ case 148: // prog1
+ break; // FIXME
+ case 149: // prog2
+ break; // FIXME
+ case 150: // www
+ break; // FIXME
+ case 151: // msdos
+ break; // FIXME
+ case 152: // coffee
+ break; // FIXME
+ case 153: // direction
+ break; // FIXME
+ case 154: // cycle windows
+ break; // FIXME
+ case 155: // mail
+ break; // FIXME
+ case 156: // bookmarks
+ break; // FIXME
+ case 157: // computer
+ break; // FIXME
+ case 158: // back
+ break; // FIXME
+ case 159: // forward
+ break; // FIXME
+ case 160: // close cd
+ break; // FIXME
+ case 161: // eject cd
+ break; // FIXME
+ case 162: // eject close cd
+ break; // FIXME
+ case 163: // next song
+ break; // FIXME
+ case 164: // play pause
+ break; // FIXME
+ case 165: // previous song
+ break; // FIXME
+ case 166: // stop cd
+ break; // FIXME
+ case 167: // record
+ break; // FIXME
+ case 168: // rewind
+ break; // FIXME
+ case 169: // phone
+ break; // FIXME
+ case 170: // ISO
+ break; // FIXME
+ case 171: // config
+ break; // FIXME
+ case 172: // home page
+ break; // FIXME
+ case 173: // refresh
+ break; // FIXME
+ case 174: // exit
+ break; // FIXME
+ case 175: // move
+ break; // FIXME
+ case 176: // edit
+ break; // FIXME
+ case 177: // scroll up
+ break; // FIXME PAGE_UP?
+ case 178: // scroll down
+ break; // FIXME PAGE_DOWN?
+ case 179: // kp left paren
+ return KeyEvent.VK_LEFT_PARENTHESIS;
+ case 180: // kp right paren
+ return KeyEvent.VK_RIGHT_PARENTHESIS;
+ case 181: // new
+ break; // FIXME
+ case 182: // redo
+ break; // FIXME
+
+ case 183: // F13
+ return KeyEvent.VK_F13;
+ case 184: // F14
+ return KeyEvent.VK_F14;
+ case 185: // F15
+ return KeyEvent.VK_F15;
+ case 186: // F16
+ return KeyEvent.VK_F16;
+ case 187: // F17
+ return KeyEvent.VK_F17;
+ case 188: // F18
+ return KeyEvent.VK_F18;
+ case 189: // F19
+ return KeyEvent.VK_F19;
+ case 190: // F20
+ return KeyEvent.VK_F20;
+ case 191: // F21
+ return KeyEvent.VK_F21;
+ case 192: // F22
+ return KeyEvent.VK_F22;
+ case 193: // F23
+ return KeyEvent.VK_F23;
+ case 194: // F24
+ return KeyEvent.VK_F24;
+
+ case 200: // play cd
+ break; // FIXME
+ case 201: // pause cd
+ break; // FIXME
+ case 202: // prog 3
+ break; // FIXME
+ case 203: // prog 4
+ break; // FIXME
+ case 204: // dashboard
+ break; // FIXME
+ case 205: // suspend
+ break; // FIXME
+ case 206: // close
+ break; // FIXME
+ case 207: // play
+ break; // FIXME
+ case 208: // fast forward
+ break; // FIXME
+ case 210: // print
+ return KeyEvent.VK_PRINTSCREEN; // FIXME ?
+ case 211: // HP
+ break; // FIXME
+ case 212: // camera
+ break; // FIXME
+ case 213: // sound
+ break; // FIXME
+ case 214: // question
+ break; // FIXME
+ case 215: // email
+ break; // FIXME
+ case 216: // chat
+ break; // FIXME
+ case 217: // search
+ break; // FIXME
+ case 218: // connect
+ break; // FIXME
+ case 219: // finance
+ break; // FIXME
+ case 220: // sport
+ break; // FIXME
+ case 221: // shop
+ break; // FIXME
+ case 222: // alt erase
+ break; // FIXME
+ case 223: // cancel
+ break; // FIXME
+ case 224: // brightness down
+ break; // FIXME
+ case 225: // brightness up
+ break; // FIXME
+ case 226: // media
+ break; // FIXME
+ case 227: // switch video mode
+ break; // FIXME
+ case 228: // kb dillum toggle
+ break; // FIXME
+ case 229: // kb dillum down
+ break; // FIXME
+ case 230: // kb dillum up
+ break; // FIXME
+ case 231: // send
+ break; // FIXME
+ case 232: // reply
+ break; // FIXME
+ case 233: // forward mail
+ break; // FIXME
+ case 234: // save
+ break; // FIXME
+ case 235: // documents
+ break; // FIXME
+ case 236: // battery
+ break; // FIXME
+ case 237: // bluetooth
+ break; // FIXME
+ case 238: // wlan
+ break; // FIXME
+ case 239: // UWB
+ break; // FIXME
+ case 240: // unknown
+ return KeyEvent.VK_UNDEFINED;
+ case 241: // video next
+ break; // FIXME
+ case 242: // video prev
+ break; // FIXME
+ case 243: // brightness cycle
+ break; // FIXME
+ case 244: // brightness zero
+ break; // FIXME
+ case 245: // display off
+ break; // FIXME
+ case 246: // wimax
+ break; // FIXME
+ case 247: // rf kill radio off
+ break; // FIXME
+ case 248: // mic mute
+ break; // FIXME
+
+ default:
+ }
+
+ if(Window.DEBUG_KEY_EVENT) {
+ System.out.println("TODO LinuxEVKey2NewtVKey: Unmapped EVKey "+EVKey);
+ }
+
+ return KeyEvent.VK_UNDEFINED;
+ }
+ }
+}
diff --git a/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java b/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java
index 885649d17..1d9377563 100644
--- a/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java
+++ b/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,7 +20,7 @@
* 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.
@@ -36,6 +36,7 @@ import java.io.InputStream;
import jogamp.newt.WindowImpl;
+import com.jogamp.newt.Screen;
import com.jogamp.newt.Window;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.WindowEvent;
@@ -48,16 +49,16 @@ import com.jogamp.newt.event.WindowUpdateEvent;
* within it's own polling thread.
*/
public class LinuxMouseTracker implements WindowListener {
-
+
private static final LinuxMouseTracker lmt;
-
+
static {
lmt = new LinuxMouseTracker();
final Thread t = new Thread(lmt.mouseDevicePoller, "NEWT-LinuxMouseTracker");
t.setDaemon(true);
t.start();
}
-
+
public static LinuxMouseTracker getSingleton() {
return lmt;
}
@@ -65,49 +66,54 @@ public class LinuxMouseTracker implements WindowListener {
private volatile boolean stop = false;
private int x = 0;
private int y = 0;
- private int buttonDown = 0;
+ private short buttonDown = 0;
private int old_x = 0;
private int old_y = 0;
- private int old_buttonDown = 0;
+ private volatile int lastFocusedX = 0;
+ private volatile int lastFocusedY = 0;
+ private short old_buttonDown = 0;
private WindowImpl focusedWindow = null;
- private MouseDevicePoller mouseDevicePoller = new MouseDevicePoller();
-
+ private final MouseDevicePoller mouseDevicePoller = new MouseDevicePoller();
+
+ public final int getLastX() { return lastFocusedX; }
+ public final int getLastY() { return lastFocusedY; }
+
@Override
- public void windowResized(WindowEvent e) { }
+ public void windowResized(final WindowEvent e) { }
@Override
- public void windowMoved(WindowEvent e) { }
+ public void windowMoved(final WindowEvent e) { }
@Override
- public void windowDestroyNotify(WindowEvent e) {
- Object s = e.getSource();
+ public void windowDestroyNotify(final WindowEvent e) {
+ final Object s = e.getSource();
if(focusedWindow == s) {
focusedWindow = null;
}
}
@Override
- public void windowDestroyed(WindowEvent e) { }
+ public void windowDestroyed(final WindowEvent e) { }
@Override
- public void windowGainedFocus(WindowEvent e) {
- Object s = e.getSource();
+ public void windowGainedFocus(final WindowEvent e) {
+ final Object s = e.getSource();
if(s instanceof WindowImpl) {
focusedWindow = (WindowImpl) s;
}
}
@Override
- public void windowLostFocus(WindowEvent e) {
- Object s = e.getSource();
+ public void windowLostFocus(final WindowEvent e) {
+ final Object s = e.getSource();
if(focusedWindow == s) {
focusedWindow = null;
}
}
@Override
- public void windowRepaint(WindowUpdateEvent e) { }
-
+ public void windowRepaint(final WindowUpdateEvent e) { }
+
class MouseDevicePoller implements Runnable {
@Override
public void run() {
@@ -117,7 +123,7 @@ public class LinuxMouseTracker implements WindowListener {
InputStream fis;
try {
fis = new FileInputStream(f);
- } catch (FileNotFoundException e) {
+ } catch (final FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
@@ -131,7 +137,7 @@ public class LinuxMouseTracker implements WindowListener {
int read = 0;
try {
read = fis.read(b, 0, remaining);
- } catch (IOException e) {
+ } catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
@@ -150,17 +156,18 @@ public class LinuxMouseTracker implements WindowListener {
yo=(b[0]&128)>0;
xd=b[1];
yd=b[2];
-
+
x+=xd;
- y+=yd;
-
+ y-=yd;
+
if(x<0) {
x=0;
}
if(y<0) {
y=0;
}
-
+
+ buttonDown = 0;
if(lb) {
buttonDown = MouseEvent.BUTTON1;
}
@@ -170,52 +177,56 @@ public class LinuxMouseTracker implements WindowListener {
if(rb) {
buttonDown = MouseEvent.BUTTON3;
}
-
+
if(null != focusedWindow) {
- if( x >= focusedWindow.getScreen().getWidth() ) {
- x = focusedWindow.getScreen().getWidth() - 1;
- }
- if( y >= focusedWindow.getScreen().getHeight() ) {
- y = focusedWindow.getScreen().getHeight() - 1;
+ // Clip to Screen Size
+ {
+ final Screen focusedScreen = focusedWindow.getScreen();
+ final int sw = focusedScreen.getWidth();
+ final int sh = focusedScreen.getHeight();
+ if( x >= sw ) {
+ x = sw - 1;
+ }
+ if( y >= sh ) {
+ y = sh - 1;
+ }
}
- int wx = x - focusedWindow.getX(), wy = y - focusedWindow.getY();
-
+ final int[] winScreenPos = focusedWindow.convertToPixelUnits(new int[] { focusedWindow.getX(), focusedWindow.getY() });
+ final int wx = x - winScreenPos[0], wy = y - winScreenPos[1];
if(old_x != x || old_y != y) {
// mouse moved
- focusedWindow.sendMouseEvent(MouseEvent.EVENT_MOUSE_MOVED, 0, wx, wy, 0, 0 );
+ lastFocusedX = wx;
+ lastFocusedY = wy;
+ focusedWindow.sendMouseEvent(MouseEvent.EVENT_MOUSE_MOVED, 0, wx, wy, (short)0, 0 );
}
-
+
if(old_buttonDown != buttonDown) {
// press/release
if( 0 != buttonDown ) {
- focusedWindow.sendMouseEvent(
- MouseEvent.EVENT_MOUSE_PRESSED,
- 0, wx, wy, buttonDown, 0 );
+ focusedWindow.sendMouseEvent(MouseEvent.EVENT_MOUSE_PRESSED, 0, wx, wy, buttonDown, 0 );
} else {
- focusedWindow.sendMouseEvent(
- MouseEvent.EVENT_MOUSE_RELEASED,
- 0, wx, wy, old_buttonDown, 0 );
+ focusedWindow.sendMouseEvent(MouseEvent.EVENT_MOUSE_RELEASED, 0, wx, wy, old_buttonDown, 0 );
}
- }
+ }
} else {
if(Window.DEBUG_MOUSE_EVENT) {
System.out.println(x+"/"+y+", hs="+hs+",vs="+vs+",lb="+lb+",rb="+rb+",mb="+mb+",xo="+xo+",yo="+yo+"xd="+xd+",yd="+yd);
}
}
-
+
old_x = x;
old_y = y;
old_buttonDown = buttonDown;
-
+
}
if(null != fis) {
try {
fis.close();
- } catch (IOException e) {
+ } catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
- }
+ }
}
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java
index 1a3f14859..051294dce 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2012 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,20 +29,31 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.macosx;
+import java.net.URLConnection;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.util.PixelFormat;
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.util.IOUtil;
import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice;
+import com.jogamp.newt.NewtFactory;
+import com.jogamp.opengl.util.PNGPixelRect;
import jogamp.newt.DisplayImpl;
import jogamp.newt.NEWTJNILibLoader;
public class DisplayDriver extends DisplayImpl {
+ private static final PNGPixelRect defaultIconData;
+
static {
NEWTJNILibLoader.loadNEWT();
@@ -52,6 +63,27 @@ public class DisplayDriver extends DisplayImpl {
if(!WindowDriver.initIDs0()) {
throw new NativeWindowException("Failed to initialize jmethodIDs");
}
+ {
+ PNGPixelRect image=null;
+ if( DisplayImpl.isPNGUtilAvailable() ) {
+ try {
+ // NOTE: MUST BE DIRECT BUFFER, since NSBitmapImageRep uses buffer directly!
+ final IOUtil.ClassResources iconRes = NewtFactory.getWindowIcons();
+ final URLConnection urlConn = iconRes.resolve(iconRes.resourceCount()-1);
+ image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.RGBA8888, true /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+ defaultIconData = image;
+ if( null != defaultIconData ) {
+ final Buffer pixels = defaultIconData.getPixels();
+ DisplayDriver.setAppIcon0(
+ pixels, Buffers.getDirectBufferByteOffset(pixels), true /* pixels_is_direct */,
+ defaultIconData.getSize().getWidth(), defaultIconData.getSize().getHeight());
+ }
+ }
+
if(DEBUG) {
System.err.println("MacDisplay.init App and IDs OK "+Thread.currentThread().getName());
}
@@ -60,19 +92,48 @@ public class DisplayDriver extends DisplayImpl {
public static void initSingleton() {
// just exist to ensure static init has been run
}
-
+
public DisplayDriver() {
}
+ @Override
+ public PixelFormat getNativePointerIconPixelFormat() { return PixelFormat.RGBA8888; }
+
+ @Override
protected void dispatchMessagesNative() {
// nop
}
-
+
+ @Override
protected void createNativeImpl() {
aDevice = new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT);
}
- protected void closeNativeImpl() { }
+ @Override
+ protected void closeNativeImpl(final AbstractGraphicsDevice aDevice) {
+ aDevice.close();
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * NOTE: MUST BE DIRECT BUFFER, since NSBitmapImageRep uses buffer directly!
+ * </p>
+ */
+ @Override
+ public final boolean getNativePointerIconForceDirectNIO() { return true; }
+
+ @Override
+ protected final long createPointerIconImpl(final PixelFormat pixelformat, final int width, final int height, final ByteBuffer pixels, final int hotX, final int hotY) {
+ return createPointerIcon0(
+ pixels, Buffers.getDirectBufferByteOffset(pixels), true /* pixels_is_direct */,
+ width, height, hotX, hotY);
+ }
+
+ @Override
+ protected final void destroyPointerIconImpl(final long displayHandle, final long piHandle) {
+ destroyPointerIcon0(piHandle);
+ }
public static void runNSApplication() {
runNSApplication0();
@@ -84,5 +145,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 pixels, int pixels_byte_offset, boolean pixels_is_direct, int width, int height);
+ private static native long createPointerIcon0(Object pixels, int pixels_byte_offset, boolean pixels_is_direct, int width, int height, int hotX, int hotY);
+ private static native long destroyPointerIcon0(long handle);
+
}
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java b/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java
index d39e0027b..d80d43e8f 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,7 +20,7 @@
* 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.
@@ -30,57 +30,130 @@ package jogamp.newt.driver.macosx;
import com.jogamp.newt.event.KeyEvent;
public class MacKeyUtil {
-
- // KeyCodes (independent)
- private static final int kVK_Return = 0x24;
- private static final int kVK_Tab = 0x30;
- private static final int kVK_Space = 0x31;
- private static final int kVK_Delete = 0x33;
- private static final int kVK_Escape = 0x35;
- private static final int kVK_Command = 0x37;
- private static final int kVK_Shift = 0x38;
- private static final int kVK_CapsLock = 0x39;
- private static final int kVK_Option = 0x3A;
- private static final int kVK_Control = 0x3B;
- private static final int kVK_RightShift = 0x3C;
- private static final int kVK_RightOption = 0x3D;
- private static final int kVK_RightControl = 0x3E;
- private static final int kVK_Function = 0x3F;
- private static final int kVK_F17 = 0x40;
- private static final int kVK_VolumeUp = 0x48;
- private static final int kVK_VolumeDown = 0x49;
- private static final int kVK_Mute = 0x4A;
- private static final int kVK_F18 = 0x4F;
- private static final int kVK_F19 = 0x50;
- private static final int kVK_F20 = 0x5A;
- private static final int kVK_F5 = 0x60;
- private static final int kVK_F6 = 0x61;
- private static final int kVK_F7 = 0x62;
- private static final int kVK_F3 = 0x63;
- private static final int kVK_F8 = 0x64;
- private static final int kVK_F9 = 0x65;
- private static final int kVK_F11 = 0x67;
- private static final int kVK_F13 = 0x69;
- private static final int kVK_F16 = 0x6A;
- private static final int kVK_F14 = 0x6B;
- private static final int kVK_F10 = 0x6D;
- private static final int kVK_F12 = 0x6F;
- private static final int kVK_F15 = 0x71;
- private static final int kVK_Help = 0x72;
- private static final int kVK_Home = 0x73;
- private static final int kVK_PageUp = 0x74;
- private static final int kVK_ForwardDelete = 0x75;
- private static final int kVK_F4 = 0x76;
- private static final int kVK_End = 0x77;
- private static final int kVK_F2 = 0x78;
- private static final int kVK_PageDown = 0x79;
- private static final int kVK_F1 = 0x7A;
- private static final int kVK_LeftArrow = 0x7B;
- private static final int kVK_RightArrow = 0x7C;
- private static final int kVK_DownArrow = 0x7D;
- private static final int kVK_UpArrow = 0x7E;
-
+
+ //
+ // KeyCodes (Layout Dependent)
+ //
+ private static final short kVK_ANSI_A = 0x00;
+ private static final short kVK_ANSI_S = 0x01;
+ private static final short kVK_ANSI_D = 0x02;
+ private static final short kVK_ANSI_F = 0x03;
+ private static final short kVK_ANSI_H = 0x04;
+ private static final short kVK_ANSI_G = 0x05;
+ private static final short kVK_ANSI_Z = 0x06;
+ private static final short kVK_ANSI_X = 0x07;
+ private static final short kVK_ANSI_C = 0x08;
+ private static final short kVK_ANSI_V = 0x09;
+ private static final short kVK_ANSI_B = 0x0B;
+ private static final short kVK_ANSI_Q = 0x0C;
+ private static final short kVK_ANSI_W = 0x0D;
+ private static final short kVK_ANSI_E = 0x0E;
+ private static final short kVK_ANSI_R = 0x0F;
+ private static final short kVK_ANSI_Y = 0x10;
+ private static final short kVK_ANSI_T = 0x11;
+ private static final short kVK_ANSI_1 = 0x12;
+ private static final short kVK_ANSI_2 = 0x13;
+ private static final short kVK_ANSI_3 = 0x14;
+ private static final short kVK_ANSI_4 = 0x15;
+ private static final short kVK_ANSI_6 = 0x16;
+ private static final short kVK_ANSI_5 = 0x17;
+ private static final short kVK_ANSI_Equal = 0x18;
+ private static final short kVK_ANSI_9 = 0x19;
+ private static final short kVK_ANSI_7 = 0x1A;
+ private static final short kVK_ANSI_Minus = 0x1B;
+ private static final short kVK_ANSI_8 = 0x1C;
+ private static final short kVK_ANSI_0 = 0x1D;
+ private static final short kVK_ANSI_RightBracket = 0x1E;
+ private static final short kVK_ANSI_O = 0x1F;
+ private static final short kVK_ANSI_U = 0x20;
+ private static final short kVK_ANSI_LeftBracket = 0x21;
+ private static final short kVK_ANSI_I = 0x22;
+ private static final short kVK_ANSI_P = 0x23;
+ private static final short kVK_ANSI_L = 0x25;
+ private static final short kVK_ANSI_J = 0x26;
+ private static final short kVK_ANSI_Quote = 0x27;
+ private static final short kVK_ANSI_K = 0x28;
+ private static final short kVK_ANSI_Semicolon = 0x29;
+ private static final short kVK_ANSI_Backslash = 0x2A;
+ private static final short kVK_ANSI_Comma = 0x2B;
+ private static final short kVK_ANSI_Slash = 0x2C;
+ private static final short kVK_ANSI_N = 0x2D;
+ private static final short kVK_ANSI_M = 0x2E;
+ private static final short kVK_ANSI_Period = 0x2F;
+ private static final short kVK_ANSI_Grave = 0x32;
+ private static final short kVK_ANSI_KeypadDecimal = 0x41;
+ private static final short kVK_ANSI_KeypadMultiply = 0x43;
+ private static final short kVK_ANSI_KeypadPlus = 0x45;
+ private static final short kVK_ANSI_KeypadClear = 0x47;
+ private static final short kVK_ANSI_KeypadDivide = 0x4B;
+ private static final short kVK_ANSI_KeypadEnter = 0x4C;
+ private static final short kVK_ANSI_KeypadMinus = 0x4E;
+ private static final short kVK_ANSI_KeypadEquals = 0x51;
+ private static final short kVK_ANSI_Keypad0 = 0x52;
+ private static final short kVK_ANSI_Keypad1 = 0x53;
+ private static final short kVK_ANSI_Keypad2 = 0x54;
+ private static final short kVK_ANSI_Keypad3 = 0x55;
+ private static final short kVK_ANSI_Keypad4 = 0x56;
+ private static final short kVK_ANSI_Keypad5 = 0x57;
+ private static final short kVK_ANSI_Keypad6 = 0x58;
+ private static final short kVK_ANSI_Keypad7 = 0x59;
+ private static final short kVK_ANSI_Keypad8 = 0x5B;
+ private static final short kVK_ANSI_Keypad9 = 0x5C;
+
+ //
+ // KeyCodes (Layout Independent)
+ //
+ private static final short kVK_Return = 0x24;
+ private static final short kVK_Tab = 0x30;
+ private static final short kVK_Space = 0x31;
+ private static final short kVK_Delete = 0x33;
+ private static final short kVK_Escape = 0x35;
+ private static final short kVK_Command = 0x37;
+ private static final short kVK_Shift = 0x38;
+ private static final short kVK_CapsLock = 0x39;
+ private static final short kVK_Option = 0x3A;
+ private static final short kVK_Control = 0x3B;
+ private static final short kVK_RightShift = 0x3C;
+ private static final short kVK_RightOption = 0x3D;
+ private static final short kVK_RightControl = 0x3E;
+ // private static final short kVK_Function = 0x3F;
+ private static final short kVK_F17 = 0x40;
+ // private static final short kVK_VolumeUp = 0x48;
+ // private static final short kVK_VolumeDown = 0x49;
+ // private static final short kVK_Mute = 0x4A;
+ private static final short kVK_F18 = 0x4F;
+ private static final short kVK_F19 = 0x50;
+ private static final short kVK_F20 = 0x5A;
+ private static final short kVK_F5 = 0x60;
+ private static final short kVK_F6 = 0x61;
+ private static final short kVK_F7 = 0x62;
+ private static final short kVK_F3 = 0x63;
+ private static final short kVK_F8 = 0x64;
+ private static final short kVK_F9 = 0x65;
+ private static final short kVK_F11 = 0x67;
+ private static final short kVK_F13 = 0x69;
+ private static final short kVK_F16 = 0x6A;
+ private static final short kVK_F14 = 0x6B;
+ private static final short kVK_F10 = 0x6D;
+ private static final short kVK_F12 = 0x6F;
+ private static final short kVK_F15 = 0x71;
+ private static final short kVK_Help = 0x72;
+ private static final short kVK_Home = 0x73;
+ private static final short kVK_PageUp = 0x74;
+ private static final short kVK_ForwardDelete = 0x75;
+ private static final short kVK_F4 = 0x76;
+ private static final short kVK_End = 0x77;
+ private static final short kVK_F2 = 0x78;
+ private static final short kVK_PageDown = 0x79;
+ private static final short kVK_F1 = 0x7A;
+ private static final short kVK_LeftArrow = 0x7B;
+ private static final short kVK_RightArrow = 0x7C;
+ private static final short kVK_DownArrow = 0x7D;
+ private static final short kVK_UpArrow = 0x7E;
+
+ //
// Key constants handled differently on Mac OS X than other platforms
+ //
private static final char NSUpArrowFunctionKey = 0xF700;
private static final char NSDownArrowFunctionKey = 0xF701;
private static final char NSLeftArrowFunctionKey = 0xF702;
@@ -109,6 +182,7 @@ public class MacKeyUtil {
private static final char NSF22FunctionKey = 0xF719;
private static final char NSF23FunctionKey = 0xF71A;
private static final char NSF24FunctionKey = 0xF71B;
+ /**
private static final char NSF25FunctionKey = 0xF71C;
private static final char NSF26FunctionKey = 0xF71D;
private static final char NSF27FunctionKey = 0xF71E;
@@ -120,6 +194,7 @@ public class MacKeyUtil {
private static final char NSF33FunctionKey = 0xF724;
private static final char NSF34FunctionKey = 0xF725;
private static final char NSF35FunctionKey = 0xF726;
+ */
private static final char NSInsertFunctionKey = 0xF727;
private static final char NSDeleteFunctionKey = 0xF728;
private static final char NSHomeFunctionKey = 0xF729;
@@ -130,10 +205,11 @@ public class MacKeyUtil {
private static final char NSPrintScreenFunctionKey = 0xF72E;
private static final char NSScrollLockFunctionKey = 0xF72F;
private static final char NSPauseFunctionKey = 0xF730;
- private static final char NSSysReqFunctionKey = 0xF731;
- private static final char NSBreakFunctionKey = 0xF732;
- private static final char NSResetFunctionKey = 0xF733;
+ // private static final char NSSysReqFunctionKey = 0xF731;
+ // private static final char NSBreakFunctionKey = 0xF732;
+ // private static final char NSResetFunctionKey = 0xF733;
private static final char NSStopFunctionKey = 0xF734;
+ /**
private static final char NSMenuFunctionKey = 0xF735;
private static final char NSUserFunctionKey = 0xF736;
private static final char NSSystemFunctionKey = 0xF737;
@@ -153,26 +229,99 @@ public class MacKeyUtil {
private static final char NSFindFunctionKey = 0xF745;
private static final char NSHelpFunctionKey = 0xF746;
private static final char NSModeSwitchFunctionKey = 0xF747;
-
- static int validateKeyCode(int keyCode, char keyChar) {
+ */
+
+ static short validateKeyCode(final short keyCode, final char keyChar) {
// OS X Virtual Keycodes
switch(keyCode) {
+ //
+ // KeyCodes (Layout Dependent)
+ //
+ case kVK_ANSI_A: return KeyEvent.VK_A;
+ case kVK_ANSI_S: return KeyEvent.VK_S;
+ case kVK_ANSI_D: return KeyEvent.VK_D;
+ case kVK_ANSI_F: return KeyEvent.VK_F;
+ case kVK_ANSI_H: return KeyEvent.VK_H;
+ case kVK_ANSI_G: return KeyEvent.VK_G;
+ case kVK_ANSI_Z: return KeyEvent.VK_Z;
+ case kVK_ANSI_X: return KeyEvent.VK_X;
+ case kVK_ANSI_C: return KeyEvent.VK_C;
+ case kVK_ANSI_V: return KeyEvent.VK_V;
+ case kVK_ANSI_B: return KeyEvent.VK_B;
+ case kVK_ANSI_Q: return KeyEvent.VK_Q;
+ case kVK_ANSI_W: return KeyEvent.VK_W;
+ case kVK_ANSI_E: return KeyEvent.VK_E;
+ case kVK_ANSI_R: return KeyEvent.VK_R;
+ case kVK_ANSI_Y: return KeyEvent.VK_Y;
+ case kVK_ANSI_T: return KeyEvent.VK_T;
+ case kVK_ANSI_1: return KeyEvent.VK_1;
+ case kVK_ANSI_2: return KeyEvent.VK_2;
+ case kVK_ANSI_3: return KeyEvent.VK_3;
+ case kVK_ANSI_4: return KeyEvent.VK_4;
+ case kVK_ANSI_6: return KeyEvent.VK_6;
+ case kVK_ANSI_5: return KeyEvent.VK_5;
+ case kVK_ANSI_Equal: return KeyEvent.VK_EQUALS;
+ case kVK_ANSI_9: return KeyEvent.VK_9;
+ case kVK_ANSI_7: return KeyEvent.VK_7;
+ case kVK_ANSI_Minus: return KeyEvent.VK_MINUS;
+ case kVK_ANSI_8: return KeyEvent.VK_8;
+ case kVK_ANSI_0: return KeyEvent.VK_0;
+ case kVK_ANSI_RightBracket: return KeyEvent.VK_CLOSE_BRACKET;
+ case kVK_ANSI_O: return KeyEvent.VK_O;
+ case kVK_ANSI_U: return KeyEvent.VK_U;
+ case kVK_ANSI_LeftBracket: return KeyEvent.VK_OPEN_BRACKET;
+ case kVK_ANSI_I: return KeyEvent.VK_I;
+ case kVK_ANSI_P: return KeyEvent.VK_P;
+ case kVK_ANSI_L: return KeyEvent.VK_L;
+ case kVK_ANSI_J: return KeyEvent.VK_J;
+ case kVK_ANSI_Quote: return KeyEvent.VK_QUOTE;
+ case kVK_ANSI_K: return KeyEvent.VK_K;
+ case kVK_ANSI_Semicolon: return KeyEvent.VK_SEMICOLON;
+ case kVK_ANSI_Backslash: return KeyEvent.VK_BACK_SLASH;
+ case kVK_ANSI_Comma: return KeyEvent.VK_COMMA;
+ case kVK_ANSI_Slash: return KeyEvent.VK_SLASH;
+ case kVK_ANSI_N: return KeyEvent.VK_N;
+ case kVK_ANSI_M: return KeyEvent.VK_M;
+ case kVK_ANSI_Period: return KeyEvent.VK_PERIOD;
+ case kVK_ANSI_Grave: return KeyEvent.VK_BACK_QUOTE; // KeyEvent.VK_DEAD_GRAVE
+ case kVK_ANSI_KeypadDecimal: return KeyEvent.VK_DECIMAL;
+ case kVK_ANSI_KeypadMultiply: return KeyEvent.VK_MULTIPLY;
+ case kVK_ANSI_KeypadPlus: return KeyEvent.VK_PLUS;
+ case kVK_ANSI_KeypadClear: return KeyEvent.VK_CLEAR;
+ case kVK_ANSI_KeypadDivide: return KeyEvent.VK_DIVIDE;
+ case kVK_ANSI_KeypadEnter: return KeyEvent.VK_ENTER;
+ case kVK_ANSI_KeypadMinus: return KeyEvent.VK_MINUS;
+ case kVK_ANSI_KeypadEquals: return KeyEvent.VK_EQUALS;
+ case kVK_ANSI_Keypad0: return KeyEvent.VK_0;
+ case kVK_ANSI_Keypad1: return KeyEvent.VK_1;
+ case kVK_ANSI_Keypad2: return KeyEvent.VK_2;
+ case kVK_ANSI_Keypad3: return KeyEvent.VK_3;
+ case kVK_ANSI_Keypad4: return KeyEvent.VK_4;
+ case kVK_ANSI_Keypad5: return KeyEvent.VK_5;
+ case kVK_ANSI_Keypad6: return KeyEvent.VK_6;
+ case kVK_ANSI_Keypad7: return KeyEvent.VK_7;
+ case kVK_ANSI_Keypad8: return KeyEvent.VK_8;
+ case kVK_ANSI_Keypad9: return KeyEvent.VK_9;
+
+ //
+ // KeyCodes (Layout Independent)
+ //
case kVK_Return: return KeyEvent.VK_ENTER;
case kVK_Tab: return KeyEvent.VK_TAB;
case kVK_Space: return KeyEvent.VK_SPACE;
case kVK_Delete: return KeyEvent.VK_BACK_SPACE;
case kVK_Escape: return KeyEvent.VK_ESCAPE;
- case kVK_Command: return KeyEvent.VK_ALT;
+ case kVK_Command: return KeyEvent.VK_WINDOWS;
case kVK_Shift: return KeyEvent.VK_SHIFT;
case kVK_CapsLock: return KeyEvent.VK_CAPS_LOCK;
- case kVK_Option: return KeyEvent.VK_WINDOWS;
+ case kVK_Option: return KeyEvent.VK_ALT;
case kVK_Control: return KeyEvent.VK_CONTROL;
case kVK_RightShift: return KeyEvent.VK_SHIFT;
- case kVK_RightOption: return KeyEvent.VK_WINDOWS;
+ case kVK_RightOption: return KeyEvent.VK_ALT_GRAPH;
case kVK_RightControl: return KeyEvent.VK_CONTROL;
// case kVK_Function: return KeyEvent.VK_F;
case kVK_F17: return KeyEvent.VK_F17;
- // case kVK_VolumeUp:
+ // case kVK_VolumeUp:
// case kVK_VolumeDown:
// case kVK_Mute:
case kVK_F18: return KeyEvent.VK_F18;
@@ -205,85 +354,73 @@ public class MacKeyUtil {
case kVK_DownArrow: return KeyEvent.VK_DOWN;
case kVK_UpArrow: return KeyEvent.VK_UP;
}
-
- if (keyChar == '\r') {
- // Turn these into \n
- return KeyEvent.VK_ENTER;
- }
-
- if (keyChar >= NSUpArrowFunctionKey && keyChar <= NSModeSwitchFunctionKey) {
- switch (keyChar) {
- case NSUpArrowFunctionKey: return KeyEvent.VK_UP;
- case NSDownArrowFunctionKey: return KeyEvent.VK_DOWN;
- case NSLeftArrowFunctionKey: return KeyEvent.VK_LEFT;
- case NSRightArrowFunctionKey: return KeyEvent.VK_RIGHT;
- case NSF1FunctionKey: return KeyEvent.VK_F1;
- case NSF2FunctionKey: return KeyEvent.VK_F2;
- case NSF3FunctionKey: return KeyEvent.VK_F3;
- case NSF4FunctionKey: return KeyEvent.VK_F4;
- case NSF5FunctionKey: return KeyEvent.VK_F5;
- case NSF6FunctionKey: return KeyEvent.VK_F6;
- case NSF7FunctionKey: return KeyEvent.VK_F7;
- case NSF8FunctionKey: return KeyEvent.VK_F8;
- case NSF9FunctionKey: return KeyEvent.VK_F9;
- case NSF10FunctionKey: return KeyEvent.VK_F10;
- case NSF11FunctionKey: return KeyEvent.VK_F11;
- case NSF12FunctionKey: return KeyEvent.VK_F12;
- case NSF13FunctionKey: return KeyEvent.VK_F13;
- case NSF14FunctionKey: return KeyEvent.VK_F14;
- case NSF15FunctionKey: return KeyEvent.VK_F15;
- case NSF16FunctionKey: return KeyEvent.VK_F16;
- case NSF17FunctionKey: return KeyEvent.VK_F17;
- case NSF18FunctionKey: return KeyEvent.VK_F18;
- case NSF19FunctionKey: return KeyEvent.VK_F19;
- case NSF20FunctionKey: return KeyEvent.VK_F20;
- case NSF21FunctionKey: return KeyEvent.VK_F21;
- case NSF22FunctionKey: return KeyEvent.VK_F22;
- case NSF23FunctionKey: return KeyEvent.VK_F23;
- case NSF24FunctionKey: return KeyEvent.VK_F24;
- case NSInsertFunctionKey: return KeyEvent.VK_INSERT;
- case NSDeleteFunctionKey: return KeyEvent.VK_DELETE;
- case NSHomeFunctionKey: return KeyEvent.VK_HOME;
- case NSBeginFunctionKey: return KeyEvent.VK_BEGIN;
- case NSEndFunctionKey: return KeyEvent.VK_END;
- case NSPageUpFunctionKey: return KeyEvent.VK_PAGE_UP;
- case NSPageDownFunctionKey: return KeyEvent.VK_PAGE_DOWN;
- case NSPrintScreenFunctionKey: return KeyEvent.VK_PRINTSCREEN;
- case NSScrollLockFunctionKey: return KeyEvent.VK_SCROLL_LOCK;
- case NSPauseFunctionKey: return KeyEvent.VK_PAUSE;
- // Not handled:
- // NSSysReqFunctionKey
- // NSBreakFunctionKey
- // NSResetFunctionKey
- case NSStopFunctionKey: return KeyEvent.VK_STOP;
- // Not handled:
- // NSMenuFunctionKey
- // NSUserFunctionKey
- // NSSystemFunctionKey
- // NSPrintFunctionKey
- // NSClearLineFunctionKey
- // NSClearDisplayFunctionKey
- // NSInsertLineFunctionKey
- // NSDeleteLineFunctionKey
- // NSInsertCharFunctionKey
- // NSDeleteCharFunctionKey
- // NSPrevFunctionKey
- // NSNextFunctionKey
- // NSSelectFunctionKey
- // NSExecuteFunctionKey
- // NSUndoFunctionKey
- // NSRedoFunctionKey
- // NSFindFunctionKey
- // NSHelpFunctionKey
- // NSModeSwitchFunctionKey
- default: break;
- }
- }
- if ('a' <= keyChar && keyChar <= 'z') {
- return KeyEvent.VK_A + ( keyChar - 'a' ) ;
+ switch (keyChar) {
+ case NSUpArrowFunctionKey: return KeyEvent.VK_UP;
+ case NSDownArrowFunctionKey: return KeyEvent.VK_DOWN;
+ case NSLeftArrowFunctionKey: return KeyEvent.VK_LEFT;
+ case NSRightArrowFunctionKey: return KeyEvent.VK_RIGHT;
+ case NSF1FunctionKey: return KeyEvent.VK_F1;
+ case NSF2FunctionKey: return KeyEvent.VK_F2;
+ case NSF3FunctionKey: return KeyEvent.VK_F3;
+ case NSF4FunctionKey: return KeyEvent.VK_F4;
+ case NSF5FunctionKey: return KeyEvent.VK_F5;
+ case NSF6FunctionKey: return KeyEvent.VK_F6;
+ case NSF7FunctionKey: return KeyEvent.VK_F7;
+ case NSF8FunctionKey: return KeyEvent.VK_F8;
+ case NSF9FunctionKey: return KeyEvent.VK_F9;
+ case NSF10FunctionKey: return KeyEvent.VK_F10;
+ case NSF11FunctionKey: return KeyEvent.VK_F11;
+ case NSF12FunctionKey: return KeyEvent.VK_F12;
+ case NSF13FunctionKey: return KeyEvent.VK_F13;
+ case NSF14FunctionKey: return KeyEvent.VK_F14;
+ case NSF15FunctionKey: return KeyEvent.VK_F15;
+ case NSF16FunctionKey: return KeyEvent.VK_F16;
+ case NSF17FunctionKey: return KeyEvent.VK_F17;
+ case NSF18FunctionKey: return KeyEvent.VK_F18;
+ case NSF19FunctionKey: return KeyEvent.VK_F19;
+ case NSF20FunctionKey: return KeyEvent.VK_F20;
+ case NSF21FunctionKey: return KeyEvent.VK_F21;
+ case NSF22FunctionKey: return KeyEvent.VK_F22;
+ case NSF23FunctionKey: return KeyEvent.VK_F23;
+ case NSF24FunctionKey: return KeyEvent.VK_F24;
+ case NSInsertFunctionKey: return KeyEvent.VK_INSERT;
+ case NSDeleteFunctionKey: return KeyEvent.VK_DELETE;
+ case NSHomeFunctionKey: return KeyEvent.VK_HOME;
+ case NSBeginFunctionKey: return KeyEvent.VK_BEGIN;
+ case NSEndFunctionKey: return KeyEvent.VK_END;
+ case NSPageUpFunctionKey: return KeyEvent.VK_PAGE_UP;
+ case NSPageDownFunctionKey: return KeyEvent.VK_PAGE_DOWN;
+ case NSPrintScreenFunctionKey: return KeyEvent.VK_PRINTSCREEN;
+ case NSScrollLockFunctionKey: return KeyEvent.VK_SCROLL_LOCK;
+ case NSPauseFunctionKey: return KeyEvent.VK_PAUSE;
+ // Not handled:
+ // NSSysReqFunctionKey
+ // NSBreakFunctionKey
+ // NSResetFunctionKey
+ case NSStopFunctionKey: return KeyEvent.VK_STOP;
+ // Not handled:
+ // NSMenuFunctionKey
+ // NSUserFunctionKey
+ // NSSystemFunctionKey
+ // NSPrintFunctionKey
+ // NSClearLineFunctionKey
+ // NSClearDisplayFunctionKey
+ // NSInsertLineFunctionKey
+ // NSDeleteLineFunctionKey
+ // NSInsertCharFunctionKey
+ // NSDeleteCharFunctionKey
+ // NSPrevFunctionKey
+ // NSNextFunctionKey
+ // NSSelectFunctionKey
+ // NSExecuteFunctionKey
+ // NSUndoFunctionKey
+ // NSRedoFunctionKey
+ // NSFindFunctionKey
+ // NSHelpFunctionKey
+ // NSModeSwitchFunctionKey
}
- return (int) keyChar; // let's hope for the best (compatibility of keyChar/keyCode's)
- }
+ return (short) keyChar; // let's hope for the best (compatibility of keyChar/keyCode's)
+ }
}
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java
index 24e60ba0a..5f458e2c9 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2011 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,115 +29,179 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.macosx;
-import java.util.List;
-
import javax.media.nativewindow.DefaultGraphicsScreen;
-import javax.media.nativewindow.util.Dimension;
-import javax.media.nativewindow.util.DimensionImmutable;
-import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.util.Rectangle;
+import jogamp.nativewindow.macosx.OSXUtil;
+import jogamp.newt.MonitorModeProps;
import jogamp.newt.ScreenImpl;
-import com.jogamp.common.util.IntObjectHashMap;
-import com.jogamp.newt.ScreenMode;
-import com.jogamp.newt.util.ScreenModeUtil;
+import com.jogamp.common.util.ArrayHashSet;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+import com.jogamp.opengl.math.FloatUtil;
public class ScreenDriver extends ScreenImpl {
-
- // caching native CGDisplayScreenSize() results, since it's ridiculous slow (~6 ms each call)
- private static IntObjectHashMap/*<int, DimensionImmutable>*/ scrnIdx2Dimension;
-
+
static {
DisplayDriver.initSingleton();
- scrnIdx2Dimension = new IntObjectHashMap();
- scrnIdx2Dimension.setKeyNotFoundValue(null);
}
public ScreenDriver() {
}
+ @Override
protected void createNativeImpl() {
aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx);
}
+ @Override
protected void closeNativeImpl() { }
- private static native int getWidthImpl0(int scrn_idx);
- private static native int getHeightImpl0(int scrn_idx);
-
- private int[] getScreenModeIdx(int idx) {
- // caching native CGDisplayScreenSize() results, since it's ridiculous slow (~6 ms each call)
- DimensionImmutable dim = (DimensionImmutable) scrnIdx2Dimension.get(screen_idx);
- if(null == dim) {
- int[] res = getScreenSizeMM0(screen_idx);
- if(null == res || 0 == res.length) {
- return null;
- }
- dim = new Dimension(res[0], res[1]);
- scrnIdx2Dimension.put(screen_idx, dim);
+ private MonitorMode getMonitorModeImpl(final MonitorModeProps.Cache cache, final int crt_idx, final int mode_idx) {
+ final int[] modeProps = getMonitorMode0(crt_idx, mode_idx);
+ final MonitorMode res;
+ if (null == modeProps || 0 >= modeProps.length) {
+ res = null;
+ } else {
+ res = MonitorModeProps.streamInMonitorMode(null, cache, modeProps, 0);
}
+ return res;
+ }
- int[] modeProps = getScreenMode0(screen_idx, idx, dim.getWidth(), dim.getHeight());
- if (null == modeProps || 0 == modeProps.length) {
- return null;
- }
- if(modeProps.length < ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL) {
- throw new RuntimeException("properties array too short, should be >= "+ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+modeProps.length);
+ private class CrtProps {
+ CrtProps() {
+ count = getMonitorCount0();
+ pixelScaleArray = new int[count];
+ propsOrigArray = new int[count][];
+ propsFixedArray = new int[count][];
+
+ //
+ // Gather whole topology of monitors (NSScreens)
+ //
+ for(int crtIdx=0; crtIdx<count; crtIdx++) {
+ final float pixelScaleRaw = (float) OSXUtil.GetPixelScale(crtIdx);
+ pixelScaleArray[crtIdx] = FloatUtil.isZero(pixelScaleRaw, FloatUtil.EPSILON) ? 1 : (int)pixelScaleRaw;
+ propsOrigArray[crtIdx] = getMonitorProps0(crtIdx);
+ if ( null == propsOrigArray[crtIdx] ) {
+ throw new InternalError("Could not gather device props "+crtIdx+"/"+count);
+ }
+ // copy orig -> fixed
+ final int propsLen = propsOrigArray[crtIdx].length;
+ propsFixedArray[crtIdx] = new int[propsLen];
+ System.arraycopy(propsOrigArray[crtIdx], 0, propsFixedArray[crtIdx], 0, propsLen);
+ }
+
+ //
+ // Fix scaled viewport w/ pixelScale of each monitorProps,
+ // i.e. size by its own pixelScale and x/y offset by querying it's neighbors.
+ //
+ for(int crtIdx=0; crtIdx<count; crtIdx++) {
+ final int[] thisMonitorProps = propsFixedArray[crtIdx];
+ final int x = thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+0];
+ final int y = thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+1];
+ final int thisPixelScale = pixelScaleArray[crtIdx];
+ thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+2] *= thisPixelScale; // fix width
+ thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+3] *= thisPixelScale; // fix height
+ if( 0 != x ) {
+ // find matching viewport width for x-offset to apply it's pixelSize
+ for(int i=0; i<count; i++) {
+ if( i != crtIdx && x == propsOrigArray[i][MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+2] ) {
+ thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+0] *= pixelScaleArray[i];
+ break;
+ }
+ }
+ }
+ if( 0 != y ) {
+ // find matching viewport height for y-offset to apply it's pixelSize
+ for(int i=0; i<count; i++) {
+ if( i != crtIdx && y == propsOrigArray[i][MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+3] ) {
+ thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+1] *= pixelScaleArray[i];
+ break;
+ }
+ }
+ }
+ }
}
- return modeProps;
+ final int count;
+ final int[] pixelScaleArray;
+ final int[][] propsOrigArray;
+ final int[][] propsFixedArray;
}
- private int nativeModeIdx;
-
- protected int[] getScreenModeFirstImpl() {
- nativeModeIdx = 0;
- return getScreenModeNextImpl();
- }
+ @Override
+ protected final void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) {
+ final CrtProps crtProps = new CrtProps();
- protected int[] getScreenModeNextImpl() {
- int[] modeProps = getScreenModeIdx(nativeModeIdx);
- if (null != modeProps && 0 < modeProps.length) {
- nativeModeIdx++;
- return modeProps;
+ //
+ // Collect all monitorModes for all monitorDevices
+ //
+ for(int crtIdx=0; crtIdx<crtProps.count; crtIdx++) {
+ final ArrayHashSet<MonitorMode> supportedModes = new ArrayHashSet<MonitorMode>();
+ int modeIdx = 0;
+ {
+ // Get all supported modes for this monitorDevice
+ MonitorMode mode;
+ while( true ) {
+ mode = getMonitorModeImpl(cache, crtIdx, modeIdx);
+ if( null != mode ) {
+ if( mode.getSurfaceSize().getBitsPerPixel() >= 24 ) { // drop otherwise
+ supportedModes.getOrAdd(mode);
+ }
+ modeIdx++; // next mode on same monitor
+ } else {
+ break; // done with modes on this monitor
+ }
+ }
+ }
+ if( 0 >= modeIdx ) {
+ throw new InternalError("Could not gather single mode of device "+crtIdx+"/"+crtProps.count);
+ }
+ final MonitorMode currentMode = getMonitorModeImpl(cache, crtIdx, -1);
+ if ( null == currentMode ) {
+ throw new InternalError("Could not gather current mode of device "+crtIdx+"/"+crtProps.count+", but gathered "+modeIdx+" modes");
+ }
+ // merge monitor-props + supported modes
+ MonitorModeProps.streamInMonitorDevice(null, cache, this, supportedModes, currentMode, crtProps.propsFixedArray[crtIdx], 0);
}
- return null;
}
- protected ScreenMode getCurrentScreenModeImpl() {
- int[] modeProps = getScreenModeIdx(-1);
- if (null != modeProps && 0 < modeProps.length) {
- return ScreenModeUtil.streamIn(modeProps, 0);
+ @Override
+ protected boolean updateNativeMonitorDeviceViewportImpl(final MonitorDevice monitor, final Rectangle viewportPU, final Rectangle viewportWU) {
+ final CrtProps crtProps = new CrtProps();
+ final int crtIdx = monitor.getId();
+ if( 0 > crtIdx || crtIdx >= crtProps.count ) {
+ throw new IndexOutOfBoundsException("monitor id "+crtIdx+" not withon [0.."+(crtProps.count-1)+"]");
}
- return null;
+ final int[] fixedMonitorProps = crtProps.propsFixedArray[crtIdx];
+ int offset = MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT;
+ viewportPU.set(fixedMonitorProps[offset++], fixedMonitorProps[offset++], fixedMonitorProps[offset++], fixedMonitorProps[offset++]);
+ viewportWU.set(fixedMonitorProps[offset++], fixedMonitorProps[offset++], fixedMonitorProps[offset++], fixedMonitorProps[offset++]);
+ return true;
}
-
- protected boolean setCurrentScreenModeImpl(final ScreenMode screenMode) {
- final List<ScreenMode> screenModes = this.getScreenModesOrig();
- final int screenModeIdx = screenModes.indexOf(screenMode);
- if(0>screenModeIdx) {
- throw new RuntimeException("ScreenMode not element of ScreenMode list: "+screenMode);
- }
- final int nativeModeIdx = getScreenModesIdx2NativeIdx().get(screenModeIdx);
- return setScreenMode0(screen_idx, nativeModeIdx);
+
+ @Override
+ protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) {
+ return getMonitorModeImpl(null, monitor.getId(), -1);
}
-
- protected int validateScreenIndex(int idx) {
- return idx;
+
+ @Override
+ protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) {
+ return setMonitorMode0(monitor.getId(), mode.getId(), mode.getRotation());
}
-
- protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) {
- virtualOrigin.setX(0);
- virtualOrigin.setY(0);
- virtualSize.setWidth(getWidthImpl0(screen_idx));
- virtualSize.setHeight(getHeightImpl0(screen_idx));
+
+ @Override
+ protected int validateScreenIndex(final int idx) {
+ return 0; // big-desktop w/ multiple monitor attached, only one screen available
}
- private native int[] getScreenSizeMM0(int screen_idx);
- private native int[] getScreenMode0(int screen_index, int mode_index, int widthMM, int heightMM);
- private native boolean setScreenMode0(int screen_index, int mode_idx);
+ private native int getMonitorCount0();
+ private native int[] getMonitorProps0(int crt_idx);
+ private native int[] getMonitorMode0(int crt_index, int mode_idx);
+ private native boolean setMonitorMode0(int crt_index, int nativeId, int rot);
}
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
index 4eeafb244..c0f7d3859 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.macosx;
@@ -39,28 +39,146 @@ import javax.media.nativewindow.GraphicsConfigurationFactory;
import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.MutableSurface;
+import javax.media.nativewindow.ScalableSurface;
import javax.media.nativewindow.VisualIDHolder;
import javax.media.nativewindow.util.Insets;
-import javax.media.nativewindow.util.InsetsImmutable;
import javax.media.nativewindow.util.Point;
import javax.media.nativewindow.util.PointImmutable;
+import jogamp.nativewindow.SurfaceScaleUtils;
+import jogamp.nativewindow.macosx.OSXUtil;
+import jogamp.newt.PointerIconImpl;
+import jogamp.newt.ScreenImpl;
import jogamp.newt.WindowImpl;
import jogamp.newt.driver.DriverClearFocus;
import jogamp.newt.driver.DriverUpdatePosition;
import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.MonitorEvent;
+import com.jogamp.opengl.math.FloatUtil;
public class WindowDriver extends WindowImpl implements MutableSurface, DriverClearFocus, DriverUpdatePosition {
-
+
static {
DisplayDriver.initSingleton();
}
public WindowDriver() {
}
-
+
+ private boolean updatePixelScale(final boolean sendEvent, final boolean defer, final float newPixelScaleRaw, final float nativePixelScaleRaw) {
+ final int[] newPixelScale = new int[2];
+ {
+ final int _newPixelScale = FloatUtil.isZero(newPixelScaleRaw, FloatUtil.EPSILON) ? ScalableSurface.IDENTITY_PIXELSCALE : (int) newPixelScaleRaw;
+ newPixelScale[0]= _newPixelScale;
+ newPixelScale[1]= _newPixelScale;
+ final int _nativePixelScale = FloatUtil.isZero(nativePixelScaleRaw, FloatUtil.EPSILON) ? ScalableSurface.IDENTITY_PIXELSCALE : (int) nativePixelScaleRaw;
+ nativePixelScale[0]= _nativePixelScale;
+ nativePixelScale[1]= _nativePixelScale;
+ }
+
+ if( SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, newPixelScale, DEBUG_IMPLEMENTATION ? getClass().getName() : null) ) {
+ if( sendEvent ) {
+ super.sizeChanged(defer, getWidth(), getHeight(), true);
+ } else {
+ defineSize(getWidth(), getHeight());
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private boolean updatePixelScaleByScreenIdx(final boolean sendEvent) {
+ final float nativePixelScaleRaw = (float) OSXUtil.GetPixelScale(getScreen().getIndex());
+ if( DEBUG_IMPLEMENTATION ) {
+ System.err.println("WindowDriver.updatePixelScale.1: "+hasPixelScale[0]+", "+nativePixelScaleRaw+" (native)");
+ }
+ return updatePixelScale(sendEvent, true /* defer */, nativePixelScaleRaw, nativePixelScaleRaw);
+ }
+
+ private boolean updatePixelScaleByWindowHandle(final boolean sendEvent) {
+ final long handle = getWindowHandle();
+ if( 0 != handle ) {
+ final float nativePixelScaleRaw = (float)OSXUtil.GetPixelScale(handle);
+ if( DEBUG_IMPLEMENTATION ) {
+ System.err.println("WindowDriver.updatePixelScale.2: "+hasPixelScale[0]+", "+nativePixelScaleRaw+" (native)");
+ }
+ return updatePixelScale(sendEvent, true /* defer */, nativePixelScaleRaw, nativePixelScaleRaw);
+ } else {
+ return false;
+ }
+ }
+
+ /** Called from native code */
+ protected void updatePixelScale(final boolean defer, final float newPixelScaleRaw, final float nativePixelScaleRaw) {
+ final long handle = getWindowHandle();
+ if( DEBUG_IMPLEMENTATION ) {
+ System.err.println("WindowDriver.updatePixelScale.3: "+hasPixelScale[0]+" (has) -> "+newPixelScaleRaw+" (raw), "+nativePixelScaleRaw+" (native), drop "+(0==handle));
+ }
+ if( 0 != handle ) {
+ updatePixelScale(true /* sendEvent*/, defer, newPixelScaleRaw, nativePixelScaleRaw);
+ }
+ }
+
+ @Override
+ protected final void instantiationFinished() {
+ updatePixelScaleByScreenIdx(false /* sendEvent*/);
+ }
+
+ @Override
+ protected void setScreen(final ScreenImpl newScreen) { // never null !
+ super.setScreen(newScreen);
+ updatePixelScaleByScreenIdx(false /* sendEvent*/); // caller (reparent, ..) will send reshape event
+ }
+
+ @Override
+ protected void monitorModeChanged(final MonitorEvent me, final boolean success) {
+ updatePixelScaleByWindowHandle(false /* sendEvent*/); // send reshape event itself
+ }
+
+ @Override
+ public final void setSurfaceScale(final int[] pixelScale) {
+ SurfaceScaleUtils.validateReqPixelScale(reqPixelScale, pixelScale, DEBUG_IMPLEMENTATION ? getClass().getName() : null);
+
+ final int[] resPixelScale;
+ if( isNativeValid() ) {
+ if( isOffscreenInstance ) {
+ final NativeWindow pWin = getParent();
+ if( pWin instanceof ScalableSurface ) {
+ final ScalableSurface sSurf = (ScalableSurface)pWin;
+ sSurf.setSurfaceScale(reqPixelScale);
+ final int[] pPixelScale = sSurf.getCurrentSurfaceScale(new int[2]);
+ sSurf.getNativeSurfaceScale(nativePixelScale);
+ updatePixelScale(true /* sendEvent */, true /* defer */, pPixelScale[0], nativePixelScale[0]); // HiDPI: uniformPixelScale
+ } else {
+ // just notify updated pixelScale if offscreen
+ SurfaceScaleUtils.replaceAutoMaxWithPlatformMax(reqPixelScale);
+ updatePixelScale(true /* sendEvent */, true /* defer */, reqPixelScale[0], nativePixelScale[0]); // HiDPI: uniformPixelScale
+ }
+ } else {
+ // set pixelScale in native code, will issue an update PixelScale
+ OSXUtil.RunOnMainThread(true, false, new Runnable() {
+ @Override
+ public void run() {
+ setPixelScale0(getWindowHandle(), surfaceHandle, reqPixelScale[0]); // HiDPI: uniformPixelScale
+ }
+ } );
+ }
+ resPixelScale = hasPixelScale;
+ } else {
+ hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+ resPixelScale = reqPixelScale;
+ }
+ if( DEBUG_IMPLEMENTATION ) {
+ System.err.println("WindowDriver.setPixelScale: "+pixelScale[0]+"x"+pixelScale[1]+" (req) -> "+
+ reqPixelScale[0]+"x"+reqPixelScale[1]+" (validated) -> "+
+ resPixelScale[0]+"x"+resPixelScale[1]+" (result) - realized "+isNativeValid());
+ }
+ }
+
@Override
protected void createNativeImpl() {
final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice(), capsRequested).chooseGraphicsConfiguration(
@@ -69,7 +187,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this);
}
setGraphicsConfiguration(cfg);
- reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), getReconfigureFlags(FLAG_CHANGE_VISIBILITY, true));
+ reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), getReconfigureFlags(FLAG_CHANGE_VISIBILITY, true));
if (0 == getWindowHandle()) {
throw new NativeWindowException("Error creating window");
}
@@ -79,373 +197,532 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
protected void closeNativeImpl() {
try {
if(DEBUG_IMPLEMENTATION) { System.err.println("MacWindow.CloseAction "+Thread.currentThread().getName()); }
- final long handle = getWindowHandle();
+ final long handle = getWindowHandle();
+ visibleChanged(true, false);
setWindowHandle(0);
surfaceHandle = 0;
sscSurfaceHandle = 0;
- isOffscreenInstance = false;
+ isOffscreenInstance = false;
if (0 != handle) {
- close0(handle);
+ OSXUtil.RunOnMainThread(false, true /* kickNSApp */, new Runnable() {
+ @Override
+ public void run() {
+ close0( handle );
+ } });
}
- } catch (Throwable t) {
- if(DEBUG_IMPLEMENTATION) {
- Exception e = new Exception("Warning: closeNative failed - "+Thread.currentThread().getName(), t);
+ } catch (final Throwable t) {
+ if(DEBUG_IMPLEMENTATION) {
+ final Exception e = new Exception("Warning: closeNative failed - "+Thread.currentThread().getName(), t);
e.printStackTrace();
}
}
}
-
+
@Override
protected int lockSurfaceImpl() {
- if(!isOffscreenInstance) {
- return lockSurface0(getWindowHandle()) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY;
+ /**
+ * if( isOffscreenInstance ) {
+ * return LOCK_SUCCESS;
+ * }
+ */
+ final long w = getWindowHandle();
+ final long v = surfaceHandle;
+ if( 0 != v && 0 != w ) {
+ return lockSurface0(w, v) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY;
}
- return LOCK_SUCCESS;
+ return LOCK_SURFACE_NOT_READY;
}
@Override
protected void unlockSurfaceImpl() {
- if(!isOffscreenInstance) {
- final long h = getWindowHandle();
- if(0 != h) {
- unlockSurface0(h);
+ /**
+ * if( isOffscreenInstance ) {
+ * return;
+ * }
+ */
+ final long w = getWindowHandle();
+ final long v = surfaceHandle;
+ if(0 != w && 0 != v) {
+ if( !unlockSurface0(w, v) ) {
+ throw new NativeWindowException("Failed to unlock surface, probably not locked!");
}
}
}
-
+
@Override
public final long getSurfaceHandle() {
return 0 != sscSurfaceHandle ? sscSurfaceHandle : surfaceHandle;
}
@Override
- public void setSurfaceHandle(long surfaceHandle) {
+ public void setSurfaceHandle(final long surfaceHandle) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("MacWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle));
}
sscSurfaceHandle = surfaceHandle;
if (isNativeValid()) {
if (0 != sscSurfaceHandle) {
- orderOut0( 0!=getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle() );
- } /** this is done by recreation!
+ OSXUtil.RunOnMainThread(false, false, new Runnable() {
+ @Override
+ public void run() {
+ orderOut0( 0 != getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle() );
+ } } );
+ } /** this is done by recreation!
else if (isVisible()){
- orderFront0( 0!=getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle() );
+ OSXUtil.RunOnMainThread(false, new Runnable() {
+ public void run() {
+ orderFront0( 0!=getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle() );
+ } } );
} */
- }
+ }
}
@Override
protected void setTitleImpl(final String title) {
- setTitle0(getWindowHandle(), title);
+ OSXUtil.RunOnMainThread(false, false, new Runnable() {
+ @Override
+ public void run() {
+ setTitle0(getWindowHandle(), title);
+ } } );
}
- protected void requestFocusImpl(boolean force) {
- if(!isOffscreenInstance) {
- requestFocus0(getWindowHandle(), force);
+ @Override
+ protected void requestFocusImpl(final boolean force) {
+ final boolean _isFullscreen = isFullscreen();
+ final boolean _isOffscreenInstance = isOffscreenInstance;
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("MacWindow: requestFocusImpl(), isOffscreenInstance "+_isOffscreenInstance+", isFullscreen "+_isFullscreen);
+ }
+ if(!_isOffscreenInstance) {
+ OSXUtil.RunOnMainThread(false, false, new Runnable() {
+ @Override
+ public void run() {
+ requestFocus0(getWindowHandle(), force);
+ if(_isFullscreen) {
+ // 'NewtMacWindow::windowDidBecomeKey()' is not always called in fullscreen-mode!
+ focusChanged(false, true);
+ }
+ } } );
} else {
focusChanged(false, true);
}
}
-
+
+ @Override
public final void clearFocus() {
if(DEBUG_IMPLEMENTATION) {
- System.err.println("MacWindow: clearFocus() - requestFocusParent, isOffscreenInstance "+isOffscreenInstance);
+ System.err.println("MacWindow: clearFocus(), isOffscreenInstance "+isOffscreenInstance);
}
if(!isOffscreenInstance) {
- resignFocus0(getWindowHandle());
+ OSXUtil.RunOnMainThread(false, false, new Runnable() {
+ @Override
+ public void run() {
+ resignFocus0(getWindowHandle());
+ } } );
} else {
focusChanged(false, false);
}
}
-
- public void updatePosition() {
- final Point pS = getTopLevelLocationOnScreen(getX(), getY());
- if(DEBUG_IMPLEMENTATION) {
- System.err.println("MacWindow: updatePosition() - isOffscreenInstance "+isOffscreenInstance+", new abs pos: pS "+pS);
+
+ private boolean useParent(final NativeWindow parent) { return null != parent && 0 != parent.getWindowHandle(); }
+
+ @Override
+ public void updatePosition(final int x, final int y) {
+ final long handle = getWindowHandle();
+ if( 0 != handle && !isOffscreenInstance ) {
+ final NativeWindow parent = getParent();
+ final boolean useParent = useParent(parent);
+ final int pX=parent.getX(), pY=parent.getY();
+ final Point p0S = getLocationOnScreenImpl(x, y, parent, useParent);
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("MacWindow: updatePosition() parent["+useParent+" "+pX+"/"+pY+"] "+x+"/"+y+" -> "+x+"/"+y+" rel-client-pos, "+p0S+" screen-client-pos");
+ }
+ OSXUtil.RunOnMainThread(false, false, new Runnable() {
+ @Override
+ public void run() {
+ setWindowClientTopLeftPoint0(handle, p0S.getX(), p0S.getY(), isVisible());
+ } } );
+ // no native event (fullscreen, some reparenting)
+ positionChanged(true, x, y);
+ }
+ }
+
+ @Override
+ protected void sizeChanged(final boolean defer, final int newWidth, final int newHeight, final boolean force) {
+ final long handle = getWindowHandle();
+ if( 0 != handle && !isOffscreenInstance ) {
+ final NativeWindow parent = getParent();
+ final boolean useParent = useParent(parent);
+ if( useParent && ( getWidth() != newWidth || getHeight() != newHeight ) ) {
+ final int x=getX(), y=getY();
+ final Point p0S = getLocationOnScreenImpl(x, y, parent, useParent);
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("MacWindow: sizeChanged() parent["+useParent+" "+x+"/"+y+"] "+getX()+"/"+getY()+" "+newWidth+"x"+newHeight+" -> "+p0S+" screen-client-pos");
+ }
+ OSXUtil.RunOnMainThread(false, false, new Runnable() {
+ @Override
+ public void run() {
+ setWindowClientTopLeftPoint0(getWindowHandle(), p0S.getX(), p0S.getY(), isVisible());
+ } } );
+ }
}
- if( !isOffscreenInstance ) {
- setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), pS.getX(), pS.getY());
- } // else no offscreen position
- // no native event (fullscreen, some reparenting)
- super.positionChanged(true, getX(), getY());
+ super.sizeChanged(defer, newWidth, newHeight, force);
}
-
-
- protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
+
+ @Override
+ protected boolean reconfigureWindowImpl(int x, int y, final int width, final int height, final int flags) {
final boolean _isOffscreenInstance = isOffscreenInstance(this, this.getParent());
isOffscreenInstance = 0 != sscSurfaceHandle || _isOffscreenInstance;
- final PointImmutable pS = isOffscreenInstance ? new Point(0, 0) : getTopLevelLocationOnScreen(x, y);
-
+ final PointImmutable pClientLevelOnSreen;
+ if( isOffscreenInstance ) {
+ x = 0; y = 0;
+ pClientLevelOnSreen = new Point(0, 0);
+ } else {
+ final NativeWindow parent = getParent();
+ final boolean useParent = useParent(parent);
+ if( useParent ) {
+ pClientLevelOnSreen = getLocationOnScreenImpl(x, y, parent, useParent);
+ } else {
+ pClientLevelOnSreen = new Point(x, y);
+ }
+ }
+
+ final boolean setVisible = 0 != ( FLAG_IS_VISIBLE & flags);
+ final boolean hasFocus = hasFocus();
+
if(DEBUG_IMPLEMENTATION) {
final AbstractGraphicsConfiguration cWinCfg = this.getGraphicsConfiguration();
final NativeWindow pWin = getParent();
final AbstractGraphicsConfiguration pWinCfg = null != pWin ? pWin.getGraphicsConfiguration() : null;
- System.err.println("MacWindow reconfig: "+x+"/"+y+" -> "+pS+" - "+width+"x"+height+
+ System.err.println("MacWindow reconfig.0: "+x+"/"+y+" -> clientPos "+pClientLevelOnSreen+" - "+width+"x"+height+
",\n\t parent type "+(null != pWin ? pWin.getClass().getName() : null)+
",\n\t this-chosenCaps "+(null != cWinCfg ? cWinCfg.getChosenCapabilities() : null)+
",\n\t parent-chosenCaps "+(null != pWinCfg ? pWinCfg.getChosenCapabilities() : null)+
", isOffscreenInstance(sscSurfaceHandle "+toHexString(sscSurfaceHandle)+
", ioi: "+_isOffscreenInstance+
") -> "+isOffscreenInstance+
- "\n\t, "+getReconfigureFlagsAsString(null, flags));
+ "\n\t, "+getReconfigureFlagsAsString(null, flags)+", setVisible "+setVisible+", hasFocus "+hasFocus);
+ // Thread.dumpStack();
}
-
- if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && 0 == ( FLAG_IS_VISIBLE & flags) ) {
+
+ if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && !setVisible ) {
if ( !isOffscreenInstance ) {
- orderOut0(getWindowHandle());
+ OSXUtil.RunOnMainThread(false, false, new Runnable() {
+ @Override
+ public void run() {
+ orderOut0(getWindowHandle());
+ visibleChanged(true, false);
+ } } );
+ } else {
+ visibleChanged(true, false);
}
- // no native event ..
- visibleChanged(true, false);
}
- if( 0 == getWindowHandle() && 0 != ( FLAG_IS_VISIBLE & flags) ||
+ if( 0 == getWindowHandle() && setVisible ||
0 != ( FLAG_CHANGE_DECORATION & flags) ||
0 != ( FLAG_CHANGE_PARENTING & flags) ||
0 != ( FLAG_CHANGE_FULLSCREEN & flags) ) {
if(isOffscreenInstance) {
- createWindow(true, 0 != getWindowHandle(), pS, 64, 64, false);
+ createWindow(true, 0 != getWindowHandle(), pClientLevelOnSreen, 64, 64, false, setVisible, false);
} else {
- createWindow(false, 0 != getWindowHandle(), pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags));
+ createWindow(false, 0 != getWindowHandle(), pClientLevelOnSreen, width, height,
+ 0 != ( FLAG_IS_FULLSCREEN & flags), setVisible, 0 != ( FLAG_IS_ALWAYSONTOP & flags));
}
- if(isVisible()) { flags |= FLAG_CHANGE_VISIBILITY; }
- }
- if(x>=0 && y>=0) {
- if( !isOffscreenInstance ) {
- setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), pS.getX(), pS.getY());
- } // else no offscreen position
- // no native event (fullscreen, some reparenting)
- super.positionChanged(true, x, y);
- }
- if(width>0 && height>0) {
- if( !isOffscreenInstance ) {
- setContentSize0(getWindowHandle(), width, height);
- } // else offscreen size is realized via recreation
// no native event (fullscreen, some reparenting)
- sizeChanged(true, width, height, false); // incl. validation (incl. repositioning)
- }
- if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && 0 != ( FLAG_IS_VISIBLE & flags) ) {
- if( !isOffscreenInstance ) {
- orderFront0(getWindowHandle());
+ positionChanged(false, x, y);
+ updatePixelScaleByWindowHandle(false /* sendEvent */);
+ super.sizeChanged(false, width, height, true);
+ visibleChanged(false, setVisible);
+ if( hasFocus ) {
+ requestFocusImpl(true);
+ }
+ } else {
+ if( width>0 && height>0 ) {
+ if( !isOffscreenInstance ) {
+ OSXUtil.RunOnMainThread(false, false, new Runnable() {
+ @Override
+ public void run() {
+ setWindowClientTopLeftPointAndSize0(getWindowHandle(), pClientLevelOnSreen.getX(), pClientLevelOnSreen.getY(), width, height, setVisible);
+ } } );
+ } // else offscreen size is realized via recreation
+ // no native event (fullscreen, some reparenting)
+ positionChanged(true, x, y);
+ super.sizeChanged(true, width, height, false);
+ }
+ if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && setVisible ) {
+ if( !isOffscreenInstance ) {
+ OSXUtil.RunOnMainThread(false, false, new Runnable() {
+ @Override
+ public void run() {
+ orderFront0(getWindowHandle());
+ visibleChanged(true, true);
+ } } );
+ } else {
+ visibleChanged(true, true);
+ }
+ }
+ if( !isOffscreenInstance ) {
+ setAlwaysOnTop0(getWindowHandle(), 0 != ( FLAG_IS_ALWAYSONTOP & flags));
}
- // no native event ..
- visibleChanged(true, true);
- }
- if( !isOffscreenInstance ) {
- setAlwaysOnTop0(getWindowHandle(), 0 != ( FLAG_IS_ALWAYSONTOP & flags));
+ }
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("MacWindow reconfig.X: clientPos "+pClientLevelOnSreen+", "+width+"x"+height+" -> clientPos "+getLocationOnScreenImpl(0, 0)+", insets: "+getInsets());
}
return true;
}
- protected Point getLocationOnScreenImpl(int x, int y) {
- Point p = new Point(x, y);
- // min val is 0
- p.setX(Math.max(p.getX(), 0));
- p.setY(Math.max(p.getY(), 0));
-
+ @Override
+ protected Point getLocationOnScreenImpl(final int x, final int y) {
final NativeWindow parent = getParent();
- if( null != parent && 0 != parent.getWindowHandle() ) {
- p.translate(parent.getLocationOnScreen(null));
- }
- return p;
+ final boolean useParent = useParent(parent);
+ return getLocationOnScreenImpl(x, y, parent, useParent);
}
-
- private Point getTopLevelLocationOnScreen(int x, int y) {
- final InsetsImmutable _insets = getInsets(); // zero if undecorated
- // client position -> top-level window position
- x -= _insets.getLeftWidth() ;
- y -= _insets.getTopHeight() ;
- return getLocationOnScreenImpl(x, y);
- }
-
- protected void updateInsetsImpl(Insets insets) {
- // nop - using event driven insetsChange(..)
- }
-
- @Override
- protected void sizeChanged(boolean defer, int newWidth, int newHeight, boolean force) {
- if(getWidth() != newWidth || getHeight() != newHeight) {
- final Point p0S = getTopLevelLocationOnScreen(getX(), getY());
- setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), p0S.getX(), p0S.getY());
+
+ private Point getLocationOnScreenImpl(final int x, final int y, final NativeWindow parent, final boolean useParent) {
+ if( !useParent && !isOffscreenInstance && 0 != surfaceHandle) {
+ return OSXUtil.GetLocationOnScreen(surfaceHandle, x, y);
}
- super.sizeChanged(defer, newWidth, newHeight, force);
+
+ final Point p = new Point(x, y);
+ if( useParent ) {
+ p.translate( parent.getLocationOnScreen(null) );
+ }
+ return p;
}
-
+
@Override
- protected void positionChanged(boolean defer, int newX, int newY) {
+ protected void updateInsetsImpl(final Insets insets) {
+ // nop - using event driven insetsChange(..)
+ }
+
+ /** Callback for native screen position change event of the client area. */
+ protected void screenPositionChanged(final boolean defer, final int newX, final int newY) {
// passed coordinates are in screen position of the client area
if(getWindowHandle()!=0) {
- // screen position -> window position
- Point absPos = new Point(newX, newY);
final NativeWindow parent = getParent();
- if(null != parent) {
- absPos.translate( parent.getLocationOnScreen(null).scale(-1, -1) );
+ if( null == parent || isOffscreenInstance ) {
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("MacWindow.positionChanged.0 (Screen Pos - TOP): ("+getThreadName()+"): (defer: "+defer+") "+getX()+"/"+getY()+" -> "+newX+"/"+newY);
+ }
+ positionChanged(defer, newX, newY);
+ } else {
+ // screen position -> rel child window position
+ final Point absPos = new Point(newX, newY);
+ final Point parentOnScreen = parent.getLocationOnScreen(null);
+ absPos.translate( parentOnScreen.scale(-1, -1) );
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("MacWindow.positionChanged.1 (Screen Pos - CHILD): ("+getThreadName()+"): (defer: "+defer+") "+getX()+"/"+getY()+" -> absPos "+newX+"/"+newY+", parentOnScreen "+parentOnScreen+" -> "+absPos);
+ }
+ positionChanged(defer, absPos.getX(), absPos.getY());
}
- super.positionChanged(defer, absPos.getX(), absPos.getY());
+ } else if(DEBUG_IMPLEMENTATION) {
+ System.err.println("MacWindow.positionChanged.2 (Screen Pos - IGN): ("+getThreadName()+"): (defer: "+defer+") "+getX()+"/"+getY()+" -> "+newX+"/"+newY);
}
}
-
+
+ @Override
+ protected void setPointerIconImpl(final PointerIconImpl pi) {
+ if( !isOffscreenInstance ) {
+ final long piHandle = null != pi ? pi.validatedHandle() : 0;
+ OSXUtil.RunOnMainThread(true, false, new Runnable() { // waitUntildone due to PointerIconImpl's Lifecycle !
+ @Override
+ public void run() {
+ setPointerIcon0(getWindowHandle(), piHandle);
+ } } );
+ }
+ }
+
@Override
protected boolean setPointerVisibleImpl(final boolean pointerVisible) {
- if( !isOffscreenInstance ) {
- return setPointerVisible0(getWindowHandle(), hasFocus(), pointerVisible);
- } // else may need offscreen solution ? FIXME
+ if( !isOffscreenInstance ) {
+ OSXUtil.RunOnMainThread(false, false, new Runnable() {
+ @Override
+ public void run() {
+ setPointerVisible0(getWindowHandle(), hasFocus(), pointerVisible);
+ } } );
+ return true;
+ }
return false;
}
@Override
protected boolean confinePointerImpl(final boolean confine) {
- if( !isOffscreenInstance ) {
- return confinePointer0(getWindowHandle(), confine);
+ if( !isOffscreenInstance ) {
+ confinePointer0(getWindowHandle(), confine);
+ return true;
} // else may need offscreen solution ? FIXME
return false;
}
-
+
@Override
protected void warpPointerImpl(final int x, final int y) {
- if( !isOffscreenInstance ) {
- warpPointer0(getWindowHandle(), x, y);
+ if( !isOffscreenInstance ) {
+ warpPointer0(getWindowHandle(), x / getPixelScaleX(), y / getPixelScaleY());
} // else may need offscreen solution ? FIXME
}
-
+
@Override
- public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) {
- // Note that we send the key char for the key code on this
- // platform -- we do not get any useful key codes out of the system
- final int keyCode2 = MacKeyUtil.validateKeyCode(keyCode, keyChar);
- final boolean valid = validateKeyEvent(eventType, modifiers, keyCode);
- if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName()+" char: 0x"+Integer.toHexString(keyChar)+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2)+", valid "+valid);
- if(valid) {
- if(pressedKeyBalance > 1) {
- // Auto-Repeat: OSX delivers only PRESSED
- // inject auto-repeat RELEASE and TYPED keys _before_
- pressedKeyBalance--;
- modifiers |= InputEvent.AUTOREPEAT_MASK;
- super.sendKeyEvent(KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, (char)-1); // RELEASED
- super.sendKeyEvent(KeyEvent.EVENT_KEY_TYPED, modifiers, keyCode, keyChar); // TYPED
- }
- // only deliver keyChar on key Typed events, harmonizing platform behavior
- keyChar = KeyEvent.EVENT_KEY_TYPED == eventType ? keyChar : (char)-1;
- super.sendKeyEvent(eventType, modifiers, keyCode2, keyChar);
- }
- }
-
+ protected final void doMouseEvent(final boolean enqueue, final boolean wait, final short eventType, final int modifiers,
+ final int x, final int y, final short button, final float[] rotationXYZ, final float rotationScale) {
+ super.doMouseEvent(enqueue, wait, eventType, modifiers, x * getPixelScaleX(), y * getPixelScaleY(), button, rotationXYZ, rotationScale);
+ }
+
@Override
- public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) {
+ public final void sendKeyEvent(final short eventType, final int modifiers, final short keyCode, final short keySym, final char keyChar) {
+ throw new InternalError("XXX: Adapt Java Code to Native Code Changes");
+ }
+
+ @Override
+ public final void enqueueKeyEvent(final boolean wait, final short eventType, final int modifiers, final short _keyCode, final short _keySym, final char keyChar) {
+ throw new InternalError("XXX: Adapt Java Code to Native Code Changes");
+ }
+
+ protected final void enqueueKeyEvent(final boolean wait, final short eventType, int modifiers, final short _keyCode, final char keyChar, final char keySymChar) {
// Note that we send the key char for the key code on this
// platform -- we do not get any useful key codes out of the system
- final int keyCode2 = MacKeyUtil.validateKeyCode(keyCode, keyChar);
- final boolean valid = validateKeyEvent(eventType, modifiers, keyCode);
- if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.enqueueKeyEvent "+Thread.currentThread().getName()+" char: 0x"+Integer.toHexString(keyChar)+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2)+", valid "+valid);
- if(valid) {
- if(pressedKeyBalance > 1) {
- // Auto-Repeat: OSX delivers only PRESSED
- // inject auto-repeat RELEASE and TYPED keys _before_
- pressedKeyBalance--;
- modifiers |= InputEvent.AUTOREPEAT_MASK;
- super.enqueueKeyEvent(wait, KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, (char)-1); // RELEASED
- super.enqueueKeyEvent(wait, KeyEvent.EVENT_KEY_TYPED, modifiers, keyCode, keyChar); // TYPED
- }
- // only deliver keyChar on key Typed events, harmonizing platform behavior
- keyChar = KeyEvent.EVENT_KEY_TYPED == eventType ? keyChar : (char)-1;
- super.enqueueKeyEvent(wait, eventType, modifiers, keyCode2, keyChar);
- }
- }
-
- private int keyDownModifiers = 0;
- private int keyDownCode = 0;
- private int pressedKeyBalance = 0;
-
- private boolean validateKeyEvent(int eventType, int modifiers, int keyCode) {
+ final short keyCode = MacKeyUtil.validateKeyCode(_keyCode, keyChar);
+ final short keySym;
+ {
+ final short _keySym = KeyEvent.NULL_CHAR != keySymChar ? KeyEvent.utf16ToVKey(keySymChar) : KeyEvent.VK_UNDEFINED;
+ keySym = KeyEvent.VK_UNDEFINED != _keySym ? _keySym : keyCode;
+ }
+ /**
+ {
+ final boolean isModifierKeyCode = KeyEvent.isModifierKey(keyCode);
+ System.err.println("*** handleKeyEvent: event "+KeyEvent.getEventTypeString(eventType)+
+ ", keyCode 0x"+Integer.toHexString(_keyCode)+" -> 0x"+Integer.toHexString(keyCode)+
+ ", keySymChar '"+keySymChar+"', 0x"+Integer.toHexString(keySymChar)+" -> 0x"+Integer.toHexString(keySym)+
+ ", mods "+toHexString(modifiers)+
+ ", was: pressed "+isKeyPressed(keyCode)+", isModifierKeyCode "+isModifierKeyCode+
+ ", nativeValid "+isNativeValid()+", isOffscreen "+isOffscreenInstance);
+ } */
+
+ // OSX delivery order is PRESSED (t0), RELEASED (t1) and TYPED (t2) -> NEWT order: PRESSED (t0) and RELEASED (t1)
+ // Auto-Repeat: OSX delivers only PRESSED, inject auto-repeat RELEASE key _before_ PRESSED
switch(eventType) {
- case KeyEvent.EVENT_KEY_PRESSED:
- pressedKeyBalance++;
- keyDownModifiers = modifiers;
- keyDownCode = keyCode;
- return true;
case KeyEvent.EVENT_KEY_RELEASED:
- pressedKeyBalance--;
- return keyDownModifiers == modifiers && keyDownCode == keyCode;
- case KeyEvent.EVENT_KEY_TYPED:
- final boolean matchKeyDown = keyDownModifiers == modifiers && keyDownCode == keyCode;
- keyDownModifiers = 0;
- keyDownCode = 0;
- return matchKeyDown;
- default:
- throw new NativeWindowException("Unexpected key event type " + eventType);
+ if( isKeyCodeTracked(keyCode) ) {
+ setKeyPressed(keyCode, false);
+ }
+ break;
+ case KeyEvent.EVENT_KEY_PRESSED:
+ if( isKeyCodeTracked(keyCode) ) {
+ if( setKeyPressed(keyCode, true) ) {
+ // key was already pressed
+ modifiers |= InputEvent.AUTOREPEAT_MASK;
+ super.enqueueKeyEvent(wait, KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, keySym, keyChar); // RELEASED
+ }
+ }
+ break;
}
+ super.enqueueKeyEvent(wait, eventType, modifiers, keyCode, keySym, keyChar);
}
-
//----------------------------------------------------------------------
// Internals only
- //
-
- private void createWindow(final boolean offscreenInstance, final boolean recreate,
- final PointImmutable pS, final int width, final int height,
- final boolean fullscreen) {
+ //
+
+ private void createWindow(final boolean offscreenInstance, final boolean recreate,
+ final PointImmutable pS, final int width, final int height,
+ final boolean fullscreen, final boolean visible, final boolean alwaysOnTop) {
+
+ final long parentWinHandle = getParentWindowHandle();
+ final long preWinHandle = getWindowHandle();
- if(0!=getWindowHandle() && !recreate) {
- return;
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("MacWindow.createWindow on thread "+Thread.currentThread().getName()+
+ ": offscreen "+offscreenInstance+", recreate "+recreate+
+ ", pS "+pS+", "+width+"x"+height+", fullscreen "+fullscreen+", visible "+visible+
+ ", alwaysOnTop "+alwaysOnTop+", preWinHandle "+toHexString(preWinHandle)+", parentWin "+toHexString(parentWinHandle)+
+ ", surfaceHandle "+toHexString(surfaceHandle));
+ // Thread.dumpStack();
}
try {
- if(0!=getWindowHandle()) {
- // save the view .. close the window
- surfaceHandle = changeContentView0(getParentWindowHandle(), getWindowHandle(), 0);
- if(recreate && 0==surfaceHandle) {
- throw new NativeWindowException("Internal Error - recreate, window but no view");
- }
- close0(getWindowHandle());
+ if( 0 != preWinHandle ) {
setWindowHandle(0);
+ if( 0 == surfaceHandle ) {
+ throw new NativeWindowException("Internal Error - create w/ window, but no Newt NSView");
+ }
+ OSXUtil.RunOnMainThread(false, false /* kickNSApp */, new Runnable() {
+ @Override
+ public void run() {
+ changeContentView0(parentWinHandle, preWinHandle, 0);
+ close0( preWinHandle );
+ } });
} else {
- surfaceHandle = 0;
- }
- setWindowHandle(createWindow0(getParentWindowHandle(),
- pS.getX(), pS.getY(), width, height,
- (getGraphicsConfiguration().getChosenCapabilities().isBackgroundOpaque() && !offscreenInstance),
- fullscreen,
- ((isUndecorated() || offscreenInstance) ?
- NSBorderlessWindowMask :
- NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask),
- NSBackingStoreBuffered,
- getScreen().getIndex(), surfaceHandle));
- if (getWindowHandle() == 0) {
- throw new NativeWindowException("Could create native window "+Thread.currentThread().getName()+" "+this);
+ if( 0 != surfaceHandle ) {
+ throw new NativeWindowException("Internal Error - create w/o window, but has Newt NSView");
+ }
+ surfaceHandle = createView0(pS.getX(), pS.getY(), width, height);
+ if( 0 == surfaceHandle ) {
+ throw new NativeWindowException("Could not create native view "+Thread.currentThread().getName()+" "+this);
+ }
}
- surfaceHandle = contentView0(getWindowHandle());
- if( offscreenInstance ) {
- orderOut0(0!=getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle());
- } else {
- setTitle0(getWindowHandle(), getTitle());
+
+ final long newWin = createWindow0( pS.getX(), pS.getY(), width, height, fullscreen,
+ ( isUndecorated() || offscreenInstance ) ? NSBorderlessWindowMask :
+ NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask,
+ NSBackingStoreBuffered, surfaceHandle);
+ if ( newWin == 0 ) {
+ throw new NativeWindowException("Could not create native window "+Thread.currentThread().getName()+" "+this);
}
- } catch (Exception ie) {
+ setWindowHandle( newWin );
+
+ final boolean isOpaque = getGraphicsConfiguration().getChosenCapabilities().isBackgroundOpaque() && !offscreenInstance;
+ // Blocking initialization on main-thread!
+ OSXUtil.RunOnMainThread(true, false /* kickNSApp */, new Runnable() {
+ @Override
+ public void run() {
+ initWindow0( parentWinHandle, newWin, pS.getX(), pS.getY(), width, height, reqPixelScale[0] /* HiDPI uniformPixelScale */,
+ isOpaque, visible && !offscreenInstance, surfaceHandle);
+ if( offscreenInstance ) {
+ orderOut0(0!=parentWinHandle ? parentWinHandle : newWin);
+ } else {
+ setTitle0(newWin, getTitle());
+ setAlwaysOnTop0(getWindowHandle(), alwaysOnTop);
+ }
+ } });
+ } catch (final Exception ie) {
ie.printStackTrace();
}
}
-
+
protected static native boolean initIDs0();
- private native long createWindow0(long parentWindowHandle, int x, int y, int w, int h,
- boolean opaque, boolean fullscreen, int windowStyle,
- int backingStoreType,
- int screen_idx, long view);
- private native boolean lockSurface0(long window);
- private native void unlockSurface0(long window);
+ private native long createView0(int x, int y, int w, int h);
+ private native long createWindow0(int x, int y, int w, int h, boolean fullscreen, int windowStyle, int backingStoreType, long view);
+ /** Must be called on Main-Thread */
+ private native void initWindow0(long parentWindow, long window, int x, int y, int w, int h, float reqPixelScale,
+ boolean opaque, boolean visible, long view);
+ private native void setPixelScale0(long window, long view, float reqPixelScale);
+ private native boolean lockSurface0(long window, long view);
+ private native boolean unlockSurface0(long window, long view);
+ /** Must be called on Main-Thread */
private native void requestFocus0(long window, boolean force);
+ /** Must be called on Main-Thread */
private native void resignFocus0(long window);
- /** in case of a child window, it actually only issues orderBack(..) */
+ /** Must be called on Main-Thread. In case this is a child window and parent is still visible, orderBack(..) is issued instead of orderOut(). */
private native void orderOut0(long window);
+ /** Must be called on Main-Thread */
private native void orderFront0(long window);
+ /** Must be called on Main-Thread */
private native void close0(long window);
+ /** Must be called on Main-Thread */
private native void setTitle0(long window, String title);
private native long contentView0(long window);
- private native long changeContentView0(long parentWindowOrViewHandle, long window, long view);
- private native void setContentSize0(long window, int w, int h);
- private native void setFrameTopLeftPoint0(long parentWindowHandle, long window, int x, int y);
+ /** Must be called on Main-Thread */
+ private native void changeContentView0(long parentWindowOrView, long window, long view);
+ /** Must be called on Main-Thread */
+ private native void setWindowClientTopLeftPointAndSize0(long window, int x, int y, int w, int h, boolean display);
+ /** Must be called on Main-Thread */
+ private native void setWindowClientTopLeftPoint0(long window, int x, int y, boolean display);
+ /** 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 setPointerVisible0(long windowHandle, boolean hasFocus, boolean visible);
- private static native boolean confinePointer0(long windowHandle, boolean confine);
+ private static native void setPointerIcon0(long windowHandle, long handle);
+ private static native void setPointerVisible0(long windowHandle, boolean hasFocus, boolean visible);
+ private static native void confinePointer0(long windowHandle, boolean confine);
private static native void warpPointer0(long windowHandle, int x, int y);
-
+
// Window styles
private static final int NSBorderlessWindowMask = 0;
private static final int NSTitledWindowMask = 1 << 0;
@@ -461,5 +738,5 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
private volatile long surfaceHandle = 0;
private long sscSurfaceHandle = 0;
private boolean isOffscreenInstance = false;
-
+
}
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..5e703f690
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java
@@ -0,0 +1,89 @@
+/**
+ * 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 javax.media.nativewindow.util.PixelFormat;
+
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.opengl.util.PNGPixelRect;
+
+public class JoglUtilPNGIcon {
+
+ public static ByteBuffer arrayToX11BGRAImages(final IOUtil.ClassResources resources, final int[] data_size, final int[] elem_bytesize) throws UnsupportedOperationException, InterruptedException, IOException, MalformedURLException {
+ final PNGPixelRect[] images = new PNGPixelRect[resources.resourceCount()];
+ data_size[0] = 0;
+ for(int i=0; i<resources.resourceCount(); i++) {
+ final URLConnection urlConn = resources.resolve(i);
+ final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ data_size[0] += 2 + image.getSize().getWidth() * image.getSize().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 PNGPixelRect image1 = images[i];
+ final int width = image1.getSize().getWidth();
+ final int height = image1.getSize().getHeight();
+ if( is64Bit ) {
+ buffer.putLong(width);
+ buffer.putLong(height);
+ } else {
+ buffer.putInt(width);
+ buffer.putInt(height);
+ }
+ final ByteBuffer bb = image1.getPixels();
+ final int stride = image1.getStride();
+ for(int y=0; y<height; y++) {
+ int bbOff = y * stride;
+ for(int x=0; x<width; x++) {
+ long pixel;
+ pixel = ( 0xffL & bb.get(bbOff++) ); // B
+ pixel |= ( 0xffL & bb.get(bbOff++) ) << 8; // G
+ pixel |= ( 0xffL & bb.get(bbOff++) ) << 16; // R
+ pixel |= ( 0xffL & bb.get(bbOff++) ) << 24; // A
+ if( is64Bit ) {
+ buffer.putLong(pixel);
+ } else {
+ buffer.putInt((int)pixel);
+ }
+ }
+ }
+ }
+ 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 579ec5be8..8973ae7ed 100644
--- a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,67 +29,128 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.windows;
+import java.net.URLConnection;
+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 javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.util.PixelFormat;
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.util.IOUtil;
import com.jogamp.nativewindow.windows.WindowsGraphicsDevice;
+import com.jogamp.newt.NewtFactory;
+import com.jogamp.opengl.util.PNGPixelRect;
public class DisplayDriver extends DisplayImpl {
private static final String newtClassBaseName = "_newt_clazz" ;
+ private static final long[] defaultIconHandles;
private static RegisteredClassFactory sharedClassFactory;
static {
NEWTJNILibLoader.loadNEWT();
-
- if (!WindowDriver.initIDs0()) {
+ {
+ final long[] _defaultIconHandle = { 0, 0 };
+ if( DisplayImpl.isPNGUtilAvailable() ) {
+ try {
+ final IOUtil.ClassResources iconRes = NewtFactory.getWindowIcons();
+ {
+ final URLConnection urlConn = iconRes.resolve(0);
+ final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ _defaultIconHandle[0] = DisplayDriver.createBGRA8888Icon0(image.getPixels(), image.getSize().getWidth(), image.getSize().getHeight(), false, 0, 0);
+ }
+ {
+ final URLConnection urlConn = iconRes.resolve(iconRes.resourceCount()-1);
+ final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ _defaultIconHandle[1] = DisplayDriver.createBGRA8888Icon0(image.getPixels(), image.getSize().getWidth(), image.getSize().getHeight(), false, 0, 0);
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+ defaultIconHandles = _defaultIconHandle;
+ }
+ sharedClassFactory = new RegisteredClassFactory(newtClassBaseName, WindowDriver.getNewtWndProc0(),
+ false /* useDummyDispatchThread */, defaultIconHandles[0], defaultIconHandles[1]);
+
+ if (!WindowDriver.initIDs0(RegisteredClassFactory.getHInstance())) {
throw new NativeWindowException("Failed to initialize WindowsWindow jmethodIDs");
- }
- sharedClassFactory = new RegisteredClassFactory(newtClassBaseName, WindowDriver.getNewtWndProc0());
+ }
}
public static void initSingleton() {
// just exist to ensure static init has been run
}
+ protected static long getHInstance() {
+ return RegisteredClassFactory.getHInstance();
+ }
+
private RegisteredClass sharedClass;
public DisplayDriver() {
}
+ @Override
protected void createNativeImpl() {
sharedClass = sharedClassFactory.getSharedClass();
aDevice = new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT);
}
- protected void closeNativeImpl() {
+ @Override
+ protected void closeNativeImpl(final AbstractGraphicsDevice aDevice) {
sharedClassFactory.releaseSharedClass();
+ aDevice.close();
}
+ @Override
protected void dispatchMessagesNative() {
DispatchMessages0();
}
- protected long getHInstance() {
- return sharedClass.getHandle();
- }
-
protected String getWindowClassName() {
return sharedClass.getName();
}
+ @Override
+ protected final long createPointerIconImpl(final PixelFormat pixelformat, final int width, final int height, final ByteBuffer pixels, final int hotX, final int hotY) {
+ return createBGRA8888Icon0(pixels, width, height, true, hotX, hotY);
+ }
+
+ @Override
+ protected final void destroyPointerIconImpl(final long displayHandle, final long piHandle) {
+ destroyIcon0(piHandle);
+ }
+
//----------------------------------------------------------------------
// Internals only
//
private static native void DispatchMessages0();
+
+ static long createBGRA8888Icon0(final Buffer pixels, final int width, final int height, final boolean isCursor, final int hotX, final int hotY) {
+ if( null == pixels ) {
+ throw new IllegalArgumentException("data buffer/size");
+ }
+ final boolean pixels_is_direct = Buffers.isDirect(pixels);
+ return createBGRA8888Icon0(
+ pixels_is_direct ? pixels : Buffers.getArray(pixels),
+ pixels_is_direct ? Buffers.getDirectBufferByteOffset(pixels) : Buffers.getIndirectBufferByteOffset(pixels),
+ pixels_is_direct,
+ width, height, isCursor, hotX, hotY);
+ }
+ private static native long createBGRA8888Icon0(Object pixels, int pixels_byte_offset, boolean pixels_is_direct, 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/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java
index 948b29460..38acd03ae 100644
--- a/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,96 +29,148 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.windows;
import javax.media.nativewindow.DefaultGraphicsScreen;
-import javax.media.nativewindow.util.Dimension;
-import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.util.Rectangle;
+import jogamp.newt.MonitorModeProps;
import jogamp.newt.ScreenImpl;
-import com.jogamp.newt.ScreenMode;
-import com.jogamp.newt.util.ScreenModeUtil;
+import com.jogamp.common.util.ArrayHashSet;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+import com.jogamp.newt.Screen;
public class ScreenDriver extends ScreenImpl {
static {
DisplayDriver.initSingleton();
+ if( Screen.DEBUG ) {
+ dumpMonitorInfo0();
+ }
}
public ScreenDriver() {
}
+ @Override
protected void createNativeImpl() {
aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx);
}
-
+
+ @Override
protected void closeNativeImpl() {
}
- private int[] getScreenModeIdx(int idx) {
- int[] modeProps = getScreenMode0(screen_idx, idx);
- if (null == modeProps || 0 == modeProps.length) {
+ private final String getAdapterName(final int crt_idx) {
+ return getAdapterName0(crt_idx);
+ }
+ private final String getActiveMonitorName(final String adapterName, final int monitor_idx) {
+ return getActiveMonitorName0(adapterName, monitor_idx);
+ }
+
+ private final MonitorMode getMonitorModeImpl(final MonitorModeProps.Cache cache, final String adapterName, final int crtModeIdx) {
+ if( null == adapterName ) {
return null;
}
- if(modeProps.length < ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL) {
- throw new RuntimeException("properties array too short, should be >= "+ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+modeProps.length);
+ final String activeMonitorName = getActiveMonitorName(adapterName, 0);
+ final int[] modeProps = null != activeMonitorName ? getMonitorMode0(adapterName, crtModeIdx) : null;
+ if ( null == modeProps || 0 >= modeProps.length) {
+ return null;
}
- return modeProps;
+ return MonitorModeProps.streamInMonitorMode(null, cache, modeProps, 0);
}
- private int nativeModeIdx;
+ @Override
+ protected void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) {
+ int crtIdx = 0;
+ ArrayHashSet<MonitorMode> supportedModes = new ArrayHashSet<MonitorMode>();
+ String adapterName = getAdapterName(crtIdx);
+ while( null != adapterName ) {
+ int crtModeIdx = 0;
+ MonitorMode mode;
+ do {
+ mode = getMonitorModeImpl(cache, adapterName, crtModeIdx);
+ if( null != mode ) {
+ supportedModes.getOrAdd(mode);
+ // next mode on same monitor
+ crtModeIdx++;
+ }
+ } while( null != mode);
+ if( 0 < crtModeIdx ) {
+ // has at least one mode -> add device
+ final MonitorMode currentMode = getMonitorModeImpl(cache, adapterName, -1);
+ if ( null != currentMode ) { // enabled
+ final int[] monitorProps = getMonitorDevice0(adapterName, crtIdx);
+ // merge monitor-props + supported modes
+ MonitorModeProps.streamInMonitorDevice(null, cache, this, supportedModes, currentMode, monitorProps, 0);
- protected int[] getScreenModeFirstImpl() {
- nativeModeIdx = 0;
- return getScreenModeNextImpl();
+ // next monitor, 1st mode
+ supportedModes= new ArrayHashSet<MonitorMode>();
+ }
+ }
+ crtIdx++;
+ adapterName = getAdapterName(crtIdx);
+ }
}
- protected int[] getScreenModeNextImpl() {
- int[] modeProps = getScreenModeIdx(nativeModeIdx);
- if (null != modeProps && 0 < modeProps.length) {
- nativeModeIdx++;
- return modeProps;
+ @Override
+ protected boolean updateNativeMonitorDeviceViewportImpl(final MonitorDevice monitor, final Rectangle viewportPU, final Rectangle viewportWU) {
+ final String adapterName = getAdapterName(monitor.getId());
+ if( null != adapterName ) {
+ final String activeMonitorName = getActiveMonitorName(adapterName, 0);
+ if( null != activeMonitorName ) {
+ final int[] monitorProps = getMonitorDevice0(adapterName, monitor.getId());
+ int offset = MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT;
+ viewportPU.set(monitorProps[offset++], monitorProps[offset++], monitorProps[offset++], monitorProps[offset++]);
+ viewportWU.set(monitorProps[offset++], monitorProps[offset++], monitorProps[offset++], monitorProps[offset++]);
+ return true;
+ }
}
- return null;
+ return false;
}
- protected ScreenMode getCurrentScreenModeImpl() {
- int[] modeProps = getScreenModeIdx(-1);
- if (null != modeProps && 0 < modeProps.length) {
- return ScreenModeUtil.streamIn(modeProps, 0);
- }
- return null;
+ @Override
+ protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) {
+ return getMonitorModeImpl(null, getAdapterName(monitor.getId()), -1);
}
- protected boolean setCurrentScreenModeImpl(ScreenMode sm) {
- return setScreenMode0(screen_idx,
- sm.getMonitorMode().getSurfaceSize().getResolution().getWidth(),
- sm.getMonitorMode().getSurfaceSize().getResolution().getHeight(),
- sm.getMonitorMode().getSurfaceSize().getBitsPerPixel(),
- sm.getMonitorMode().getRefreshRate(),
- sm.getRotation());
+ @Override
+ protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) {
+ return setMonitorMode0(monitor.getId(),
+ -1, -1, // no fixed position!
+ mode.getSurfaceSize().getResolution().getWidth(),
+ mode.getSurfaceSize().getResolution().getHeight(),
+ mode.getSurfaceSize().getBitsPerPixel(),
+ (int)mode.getRefreshRate(), // simply cut-off, orig is int
+ mode.getFlags(),
+ mode.getRotation());
}
- protected int validateScreenIndex(int idx) {
- return 0; // big-desktop, only one screen available
+ @Override
+ protected int validateScreenIndex(final int idx) {
+ return 0; // big-desktop w/ multiple monitor attached, only one screen available
}
-
- protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) {
- virtualOrigin.setX(getOriginX0(screen_idx));
- virtualOrigin.setY(getOriginY0(screen_idx));
- virtualSize.setWidth(getWidthImpl0(screen_idx));
- virtualSize.setHeight(getHeightImpl0(screen_idx));
+
+ @Override
+ protected void calcVirtualScreenOriginAndSize(final Rectangle viewport, final Rectangle viewportInWindowUnits) {
+ viewport.set(getVirtualOriginX0(), getVirtualOriginY0(), getVirtualWidthImpl0(), getVirtualHeightImpl0());
+ viewportInWindowUnits.set(viewport);
}
-
+
// Native calls
- private native int getOriginX0(int screen_idx);
- private native int getOriginY0(int screen_idx);
- private native int getWidthImpl0(int scrn_idx);
- private native int getHeightImpl0(int scrn_idx);
+ private native int getVirtualOriginX0();
+ private native int getVirtualOriginY0();
+ private native int getVirtualWidthImpl0();
+ private native int getVirtualHeightImpl0();
- private native int[] getScreenMode0(int screen_index, int mode_index);
- private native boolean setScreenMode0(int screen_index, int width, int height, int bits, int freq, int rot);
+ private static native void dumpMonitorInfo0();
+ private native String getAdapterName0(int crt_index);
+ private native String getActiveMonitorName0(String adapterName, int crtModeIdx);
+ private native int[] getMonitorMode0(String adapterName, int crtModeIdx);
+ private native int[] getMonitorDevice0(String adapterName, int monitor_index);
+ private native boolean setMonitorMode0(int monitor_index, int x, int y, int width, int height, int bits, int freq, int flags, int rot);
}
diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
index 71437c461..1c5c34457 100644
--- a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,13 +29,16 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.windows;
+import java.nio.ByteBuffer;
+
import jogamp.nativewindow.windows.GDI;
import jogamp.nativewindow.windows.GDIUtil;
+import jogamp.newt.PointerIconImpl;
import jogamp.newt.WindowImpl;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
@@ -46,22 +49,24 @@ import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.InsetsImmutable;
import javax.media.nativewindow.util.Point;
+import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.VersionNumber;
import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.KeyEvent;
-import com.jogamp.newt.event.MouseAdapter;
import com.jogamp.newt.event.MouseEvent;
+import com.jogamp.newt.event.MouseEvent.PointerType;
public class WindowDriver extends WindowImpl {
+ static {
+ DisplayDriver.initSingleton();
+ }
+
private long hmon;
private long hdc;
private long hdc_old;
private long windowHandleClose;
- static {
- DisplayDriver.initSingleton();
- }
-
public WindowDriver() {
}
@@ -70,21 +75,28 @@ public class WindowDriver extends WindowImpl {
if (0 != hdc) {
throw new InternalError("surface not released");
}
- hdc = GDI.GetDC(getWindowHandle());
- hmon = MonitorFromWindow0(getWindowHandle());
-
+ final long hWnd = getWindowHandle();
+ hdc = GDI.GetDC(hWnd);
+
// return ( 0 == hdc ) ? LOCK_SURFACE_NOT_READY : ( hdc_old != hdc ) ? LOCK_SURFACE_CHANGED : LOCK_SUCCESS ;
- if( 0 == hdc ) {
+ if( 0 == hdc ) {
return LOCK_SURFACE_NOT_READY;
}
+ hmon = MonitorFromWindow0(hWnd);
+
+ // Let's not trigger on HDC change, GLDrawableImpl.'s destroy/create is a nop here anyways.
+ // FIXME: Validate against EGL surface creation: ANGLE uses HWND -> fine!
+ return LOCK_SUCCESS;
+
+ /**
if( hdc_old == hdc ) {
return LOCK_SUCCESS;
}
- if(DEBUG_IMPLEMENTATION) {
+ if(DEBUG_IMPLEMENTATION) {
System.err.println("WindowsWindow: surface change "+toHexString(hdc_old)+" -> "+toHexString(hdc));
// Thread.dumpStack();
}
- return LOCK_SURFACE_CHANGED;
+ return LOCK_SURFACE_CHANGED; */
}
@Override
@@ -104,7 +116,7 @@ public class WindowDriver extends WindowImpl {
@Override
public boolean hasDeviceChanged() {
if(0!=getWindowHandle()) {
- long _hmon = MonitorFromWindow0(getWindowHandle());
+ final long _hmon = MonitorFromWindow0(getWindowHandle());
if (hmon != _hmon) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Info: Window Device Changed "+Thread.currentThread().getName()+
@@ -118,6 +130,7 @@ public class WindowDriver extends WindowImpl {
return false;
}
+ @Override
protected void createNativeImpl() {
final ScreenDriver screen = (ScreenDriver) getScreen();
final DisplayDriver display = (DisplayDriver) screen.getDisplay();
@@ -127,70 +140,68 @@ public class WindowDriver extends WindowImpl {
throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this);
}
setGraphicsConfiguration(cfg);
- final int flags = getReconfigureFlags(0, true) &
+ final VersionNumber winVer = Platform.getOSVersionNumber();
+ final int flags = getReconfigureFlags(0, true) &
( FLAG_IS_ALWAYSONTOP | FLAG_IS_UNDECORATED ) ;
- setWindowHandle(CreateWindow0(display.getHInstance(), display.getWindowClassName(), display.getWindowClassName(),
- getParentWindowHandle(), getX(), getY(), getWidth(), getHeight(), autoPosition(), flags));
- if (getWindowHandle() == 0) {
+ final long _windowHandle = CreateWindow0(DisplayDriver.getHInstance(), display.getWindowClassName(), display.getWindowClassName(),
+ winVer.getMajor(), winVer.getMinor(),
+ getParentWindowHandle(),
+ getX(), getY(), getWidth(), getHeight(), autoPosition(), flags);
+ if ( 0 == _windowHandle ) {
throw new NativeWindowException("Error creating window");
}
- windowHandleClose = getWindowHandle();
- addMouseListener(new MouseTracker());
-
+ setWindowHandle(_windowHandle);
+ windowHandleClose = _windowHandle;
+
if(DEBUG_IMPLEMENTATION) {
- Exception e = new Exception("Info: Window new window handle "+Thread.currentThread().getName()+
+ final Exception e = new Exception("Info: Window new window handle "+Thread.currentThread().getName()+
" (Parent HWND "+toHexString(getParentWindowHandle())+
- ") : HWND "+toHexString(getWindowHandle())+", "+Thread.currentThread());
+ ") : HWND "+toHexString(_windowHandle)+", "+Thread.currentThread());
e.printStackTrace();
}
}
-
- class MouseTracker extends MouseAdapter {
- public void mouseEntered(MouseEvent e) {
- WindowDriver.trackPointerLeave0(WindowDriver.this.getWindowHandle());
- }
- }
+ @Override
protected void closeNativeImpl() {
- if(windowHandleClose != 0) {
- if (hdc != 0) {
+ if( 0 != windowHandleClose ) {
+ if ( 0 != hdc ) {
try {
GDI.ReleaseDC(windowHandleClose, hdc);
- } catch (Throwable t) {
- if(DEBUG_IMPLEMENTATION) {
- Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t);
+ } catch (final Throwable t) {
+ if(DEBUG_IMPLEMENTATION) {
+ final Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t);
e.printStackTrace();
}
}
}
try {
GDI.DestroyWindow(windowHandleClose);
- } catch (Throwable t) {
+ } catch (final Throwable t) {
if(DEBUG_IMPLEMENTATION) {
- Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t);
+ final Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t);
e.printStackTrace();
}
- } finally {
- windowHandleClose = 0;
}
}
+ windowHandleClose = 0;
hdc = 0;
hdc_old = 0;
}
- protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
+ @Override
+ protected boolean reconfigureWindowImpl(int x, int y, int width, int height, final int flags) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("WindowsWindow reconfig: "+x+"/"+y+" "+width+"x"+height+", "+
getReconfigureFlagsAsString(null, flags));
}
-
+
if(0 == ( FLAG_IS_UNDECORATED & flags)) {
final InsetsImmutable i = getInsets();
-
+
// client position -> top-level window position
x -= i.getLeftWidth() ;
y -= i.getTopHeight() ;
-
+
if(0<width && 0<height) {
// client size -> top-level window size
width += i.getTotalWidth();
@@ -198,14 +209,15 @@ public class WindowDriver extends WindowImpl {
}
}
reconfigureWindow0( getParentWindowHandle(), getWindowHandle(), x, y, width, height, flags);
-
+
if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
- visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
+ visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
}
return true;
}
- protected void requestFocusImpl(boolean force) {
+ @Override
+ protected void requestFocusImpl(final boolean force) {
requestFocus0(getWindowHandle(), force);
}
@@ -215,136 +227,150 @@ public class WindowDriver extends WindowImpl {
}
@Override
+ protected void setPointerIconImpl(final PointerIconImpl pi) {
+ setPointerIcon0(getWindowHandle(), null != pi ? pi.validatedHandle() : 0);
+ }
+
+ @Override
protected boolean setPointerVisibleImpl(final boolean pointerVisible) {
- final Boolean[] res = new Boolean[] { Boolean.FALSE };
-
+ final boolean[] res = new boolean[] { false };
+
this.runOnEDTIfAvail(true, new Runnable() {
+ @Override
public void run() {
- res[0] = Boolean.valueOf(setPointerVisible0(getWindowHandle(), pointerVisible));
+ res[0] = setPointerVisible0(getWindowHandle(), pointerVisible);
}
});
- return res[0].booleanValue();
+ return res[0];
}
@Override
protected boolean confinePointerImpl(final boolean confine) {
final Boolean[] res = new Boolean[] { Boolean.FALSE };
-
+
this.runOnEDTIfAvail(true, new Runnable() {
+ @Override
public void run() {
- final Point p0 = getLocationOnScreenImpl(0, 0);
- res[0] = Boolean.valueOf(confinePointer0(getWindowHandle(), confine,
- p0.getX(), p0.getY(), p0.getX()+getWidth(), p0.getY()+getHeight()));
+ final Point p0 = convertToPixelUnits( getLocationOnScreenImpl(0, 0) );
+ res[0] = Boolean.valueOf(confinePointer0(getWindowHandle(), confine,
+ p0.getX(), p0.getY(),
+ p0.getX()+getSurfaceWidth(), p0.getY()+getSurfaceHeight()));
}
});
return res[0].booleanValue();
}
-
+
@Override
- protected void warpPointerImpl(final int x, final int y) {
+ protected void warpPointerImpl(final int x, final int y) {
this.runOnEDTIfAvail(true, new Runnable() {
+ @Override
public void run() {
- final Point sPos = getLocationOnScreenImpl(x, y);
+ final Point sPos = convertToPixelUnits( getLocationOnScreenImpl(x, y) );
warpPointer0(getWindowHandle(), sPos.getX(), sPos.getY());
}
});
return;
}
-
- protected Point getLocationOnScreenImpl(int x, int y) {
+
+ @Override
+ protected Point getLocationOnScreenImpl(final int x, final int y) {
return GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y);
}
- protected void updateInsetsImpl(Insets insets) {
- // nop - using event driven insetsChange(..)
+ @Override
+ protected void updateInsetsImpl(final Insets insets) {
+ // nop - using event driven insetsChange(..)
}
-
- private final int validateKeyCode(int eventType, int modifiers, int keyCode, char keyChar) {
- switch(eventType) {
- case KeyEvent.EVENT_KEY_RELEASED:
- pressedKeyBalance--;
- lastPressedKeyCode = keyCode;
- break;
- case KeyEvent.EVENT_KEY_PRESSED:
- pressedKeyBalance++;
- lastPressedKeyCode = keyCode;
- break;
- case KeyEvent.EVENT_KEY_TYPED:
- if(-1==keyCode) {
- keyCode = lastPressedKeyCode;
- }
- lastPressedKeyCode = -1;
- break;
+
+ //
+ // PointerEvent Handling
+ //
+ /**
+ * Send multiple-pointer {@link MouseEvent.PointerType#TouchScreen} event to be directly consumed
+ * <p>
+ * Assumes non normal pointer names and rotation/scroll will be determined by a gesture handler.
+ * </p>
+ * <p>
+ * See {@link #doPointerEvent(boolean, boolean, PointerType[], short, int, int, boolean, int[], int[], int[], float[], float, float[], float)}
+ * for details.
+ * </p>
+ */
+ public final void sendTouchScreenEvent(final short eventType, final int modifiers,
+ final int pActionIdx, final int[] pNames,
+ final int[] pX, final int[] pY, final float[] pPressure, final float maxPressure) {
+ final int pCount = pNames.length;
+ final MouseEvent.PointerType[] pTypes = new MouseEvent.PointerType[pCount];
+ for(int i=pCount-1; i>=0; i--) { pTypes[i] = PointerType.TouchScreen; }
+ doPointerEvent(false /*enqueue*/, false /*wait*/,
+ pTypes, eventType, modifiers, pActionIdx, false /*normalPNames*/, pNames,
+ pX, pY, pPressure, maxPressure, new float[] { 0f, 0f, 0f} /*rotationXYZ*/, 1f/*rotationScale*/);
+ }
+
+ //
+ // KeyEvent Handling
+ //
+ private short repeatedKey = KeyEvent.VK_UNDEFINED;
+
+ private final boolean handlePressTypedAutoRepeat(final boolean isModifierKey, int modifiers, final short keyCode, final short keySym, final char keyChar) {
+ if( setKeyPressed(keyCode, true) ) {
+ // AR: Key was already pressed: Either [enter | within] AR mode
+ final boolean withinAR = repeatedKey == keyCode;
+ repeatedKey = keyCode;
+ if( !isModifierKey ) {
+ // AR: Key was already pressed: Either [enter | within] AR mode
+ modifiers |= InputEvent.AUTOREPEAT_MASK;
+ if( withinAR ) {
+ // AR: Within AR mode
+ super.sendKeyEvent(KeyEvent.EVENT_KEY_PRESSED, modifiers, keyCode, keySym, keyChar);
+ } // else { AR: Enter AR mode - skip already send PRESSED ; or ALT }
+ super.sendKeyEvent(KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, keySym, keyChar);
+ }
+ return true;
}
- return keyCode;
+ return false;
}
- private int lastPressedKeyCode = 0;
- private int pressedKeyBalance = 0;
- private int autoRepeat = 0;
-
+
@Override
- public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) {
- // Note that we have to regenerate the keyCode for EVENT_KEY_TYPED on this platform
- keyCode = validateKeyCode(eventType, modifiers, keyCode, keyChar);
+ public final void sendKeyEvent(final short eventType, final int modifiers, final short keyCode, final short keySym, final char keyChar) {
+ final boolean isModifierKey = KeyEvent.isModifierKey(keySym);
+ // System.err.println("*** sendKeyEvent: event "+KeyEvent.getEventTypeString(eventType)+", keyCode "+toHexString(keyCode)+", keyChar <"+keyChar+">, mods "+toHexString(modifiers)+
+ // ", isKeyCodeTracked "+isKeyCodeTracked(keyCode)+", was: pressed "+isKeyPressed(keyCode)+", printableKey "+KeyEvent.isPrintableKey(keyCode, false)+" [modifierKey "+isModifierKey+"] - "+System.currentTimeMillis());
+
+ // Reorder: WINDOWS delivery order is PRESSED (t0), TYPED (t0) and RELEASED (t1) -> NEWT order: PRESSED (t0) and RELEASED (t1)
+ // Auto-Repeat: WINDOWS delivers only PRESSED (t0) and TYPED (t0).
switch(eventType) {
case KeyEvent.EVENT_KEY_RELEASED:
- // reorder: WINDOWS delivery order is PRESSED, TYPED and RELEASED -> NEWT order: PRESSED, RELEASED and TYPED
+ if( isKeyCodeTracked(keyCode) ) {
+ if( repeatedKey == keyCode && !isModifierKey ) {
+ // AR out - send out missing PRESSED
+ super.sendKeyEvent(KeyEvent.EVENT_KEY_PRESSED, modifiers | InputEvent.AUTOREPEAT_MASK, keyCode, keySym, keyChar);
+ }
+ setKeyPressed(keyCode, false);
+ repeatedKey = KeyEvent.VK_UNDEFINED;
+ }
+ super.sendKeyEvent(KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, keySym, keyChar);
break;
case KeyEvent.EVENT_KEY_PRESSED:
- if(pressedKeyBalance > 1) {
- // Auto-Repeat: WINDOWS delivers only PRESSED and TYPED.
- // Since reordering already injects RELEASE, we only need to set the AUTOREPEAT_MASK.
- pressedKeyBalance--;
- autoRepeat |= InputEvent.AUTOREPEAT_MASK;
- } else {
- autoRepeat &= ~InputEvent.AUTOREPEAT_MASK;
+ if( !handlePressTypedAutoRepeat(isModifierKey, modifiers, keyCode, keySym, keyChar) ) {
+ super.sendKeyEvent(KeyEvent.EVENT_KEY_PRESSED, modifiers, keyCode, keySym, keyChar);
}
- super.sendKeyEvent(eventType, modifiers | autoRepeat, keyCode, (char)-1);
- break;
- case KeyEvent.EVENT_KEY_TYPED:
- modifiers |= autoRepeat;
- super.sendKeyEvent(KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, (char)-1);
- super.sendKeyEvent(eventType, modifiers, keyCode, keyChar);
break;
}
}
-
+
@Override
- public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) {
- // Note that we have to regenerate the keyCode for EVENT_KEY_TYPED on this platform
- keyCode = validateKeyCode(eventType, modifiers, keyCode, keyChar);
- switch(eventType) {
- case KeyEvent.EVENT_KEY_RELEASED:
- // reorder: WINDOWS delivery order is PRESSED, TYPED and RELEASED -> NEWT order: PRESSED, RELEASED and TYPED
- break;
- case KeyEvent.EVENT_KEY_PRESSED:
- if(pressedKeyBalance > 1) {
- // Auto-Repeat: WINDOWS delivers only PRESSED and TYPED.
- // Since reordering already injects RELEASE, we only need to set the AUTOREPEAT_MASK.
- pressedKeyBalance--;
- autoRepeat |= InputEvent.AUTOREPEAT_MASK;
- } else {
- autoRepeat &= ~InputEvent.AUTOREPEAT_MASK;
- }
- super.enqueueKeyEvent(wait, eventType, modifiers | autoRepeat, keyCode, (char)-1);
- break;
- case KeyEvent.EVENT_KEY_TYPED:
- modifiers |= autoRepeat;
- super.enqueueKeyEvent(wait, KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, (char)-1);
- super.enqueueKeyEvent(wait, eventType, modifiers, keyCode, keyChar);
- break;
- }
+ public final void enqueueKeyEvent(final boolean wait, final short eventType, final int modifiers, final short keyCode, final short keySym, final char keyChar) {
+ throw new InternalError("XXX: Adapt Java Code to Native Code Changes");
}
-
+
//----------------------------------------------------------------------
// Internals only
//
- protected static native boolean initIDs0();
protected static native long getNewtWndProc0();
+ protected static native boolean initIDs0(long hInstance);
- private native long CreateWindow0(long hInstance, String wndClassName, String wndName,
- long parentWindowHandle,
- int x, int y, int width, int height, boolean autoPosition, int flags);
+ 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);
private native long MonitorFromWindow0(long windowHandle);
private native void reconfigureWindow0(long parentWindowHandle, long windowHandle,
int x, int y, int width, int height, int flags);
@@ -353,6 +379,8 @@ 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 void trackPointerLeave0(long windowHandle);
+ 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 714324d63..e2b9a65d1 100644
--- a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,15 +29,19 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.x11;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
-import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.nativewindow.util.PixelFormat;
+import com.jogamp.common.nio.Buffers;
import com.jogamp.nativewindow.x11.X11GraphicsDevice;
import jogamp.nativewindow.x11.X11Util;
@@ -58,15 +62,14 @@ public class DisplayDriver extends DisplayImpl {
}
}
- public static void initSingleton() {
- // just exist to ensure static init has been run
- }
-
+ /** Ensure static init has been run. */
+ /* pp */static void initSingleton() { }
public DisplayDriver() {
}
- public String validateDisplayName(String name, long handle) {
+ @Override
+ public String validateDisplayName(final String name, final long handle) {
return X11Util.validateDisplayName(name, handle);
}
@@ -74,98 +77,99 @@ public class DisplayDriver extends DisplayImpl {
* {@inheritDoc}
*
* We use a private non-shared X11 Display instance for EDT window operations and one for exposed animation, eg. OpenGL.
- * <p>
- * In case {@link X11Util#HAS_XLOCKDISPLAY_BUG} and {@link X11Util#XINITTHREADS_ALWAYS_ENABLED},
- * we use null locking. Even though this seems not to be rational, it gives most stable results on all platforms.
- * </p>
- * <p>
- * Otherwise we use basic locking via the constructor {@link X11GraphicsDevice#X11GraphicsDevice(long, int, boolean)},
- * since it is possible to share this device via {@link com.jogamp.newt.NewtFactory#createDisplay(String, boolean)}.
- * </p>
*/
- @SuppressWarnings("unused")
+ @Override
protected void createNativeImpl() {
- long handle = X11Util.openDisplay(name);
+ X11Util.setX11ErrorHandler(true, DEBUG ? false : true); // make sure X11 error handler is set
+ final long handle = X11Util.openDisplay(name);
if( 0 == handle ) {
throw new RuntimeException("Error creating display(Win): "+name);
}
- if(USE_SEPARATE_DISPLAY_FOR_EDT) {
- edtDisplayHandle = X11Util.openDisplay(name);
- if( 0 == edtDisplayHandle ) {
- X11Util.closeDisplay(handle);
- throw new RuntimeException("Error creating display(EDT): "+name);
- }
- } else {
- edtDisplayHandle = handle;
- }
+ aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, true /* owner */);
try {
- CompleteDisplay0(edtDisplayHandle);
- } catch(RuntimeException e) {
- closeNativeImpl();
+ CompleteDisplay0(aDevice.getHandle());
+ } catch(final RuntimeException e) {
+ closeNativeImpl(aDevice);
throw e;
}
-
- // see API doc above!
- if(X11Util.XINITTHREADS_ALWAYS_ENABLED && X11Util.HAS_XLOCKDISPLAY_BUG) {
- aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, NativeWindowFactory.getNullToolkitLock(), false);
- } else {
- aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, false);
- }
}
- protected void closeNativeImpl() {
- DisplayRelease0(edtDisplayHandle, javaObjectAtom, windowDeleteAtom);
+ @Override
+ protected void closeNativeImpl(final AbstractGraphicsDevice aDevice) {
+ DisplayRelease0(aDevice.getHandle(), javaObjectAtom, windowDeleteAtom /*, kbdHandle */); // XKB disabled for now
javaObjectAtom = 0;
windowDeleteAtom = 0;
- // closing using ATI driver bug 'same order'
- final long handle = getHandle();
- X11Util.closeDisplay(handle);
- if(handle != edtDisplayHandle) {
- X11Util.closeDisplay(edtDisplayHandle);
- }
- edtDisplayHandle = 0;
+ // kbdHandle = 0;
+ aDevice.close(); // closes X11 display
}
+ @Override
protected void dispatchMessagesNative() {
- if(0 != edtDisplayHandle) {
- DispatchMessages0(edtDisplayHandle, javaObjectAtom, windowDeleteAtom);
+ final AbstractGraphicsDevice _aDevice = aDevice; // aDevice could be pulled by destroy event
+ _aDevice.lock();
+ try {
+ final long handle = _aDevice.getHandle();
+ if(0 != handle) {
+ DispatchMessages0(handle, javaObjectAtom, windowDeleteAtom /*, kbdHandle */); // XKB disabled for now
+ }
+ } finally {
+ _aDevice.unlock();
}
}
- protected long getEDTHandle() { return edtDisplayHandle; }
protected long getJavaObjectAtom() { return javaObjectAtom; }
protected long getWindowDeleteAtom() { return windowDeleteAtom; }
-
+ // protected long getKbdHandle() { return kbdHandle; } // XKB disabled for now
+
+ /** 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 final long createPointerIconImpl(final PixelFormat pixelformat, final int width, final int height, final ByteBuffer pixels, final int hotX, final int hotY) {
+ return createPointerIcon(getHandle(), pixels, width, height, hotX, hotY);
+ }
+
+ @Override
+ protected final void destroyPointerIconImpl(final long displayHandle, final long piHandle) {
+ destroyPointerIcon0(displayHandle, piHandle);
+ }
+
//----------------------------------------------------------------------
// Internals only
//
+
private static native boolean initIDs0(boolean debug);
private native void CompleteDisplay0(long handle);
- private void displayCompleted(long javaObjectAtom, long windowDeleteAtom) {
+ private void displayCompleted(final long javaObjectAtom, final long windowDeleteAtom /*, long kbdHandle */) {
this.javaObjectAtom=javaObjectAtom;
this.windowDeleteAtom=windowDeleteAtom;
+ // this.kbdHandle = kbdHandle; // XKB disabled for now
}
- private native void DisplayRelease0(long handle, long javaObjectAtom, long windowDeleteAtom);
+ private native void DisplayRelease0(long handle, long javaObjectAtom, long windowDeleteAtom /*, long kbdHandle */); // XKB disabled for now
- private native void DispatchMessages0(long display, long javaObjectAtom, long windowDeleteAtom);
+ private native void DispatchMessages0(long display, long javaObjectAtom, long windowDeleteAtom /* , long kbdHandle */); // XKB disabled for now
+
+ private static long createPointerIcon(final long display, final Buffer pixels, final int width, final int height, final int hotX, final int hotY) {
+ final boolean pixels_is_direct = Buffers.isDirect(pixels);
+ return createPointerIcon0(display,
+ pixels_is_direct ? pixels : Buffers.getArray(pixels),
+ pixels_is_direct ? Buffers.getDirectBufferByteOffset(pixels) : Buffers.getIndirectBufferByteOffset(pixels),
+ pixels_is_direct,
+ width, height, hotX, hotY);
+ }
+ private static native long createPointerIcon0(long display, Object pixels, int pixels_byte_offset, boolean pixels_is_direct, int width, int height, int hotX, int hotY);
+
+ private static native void destroyPointerIcon0(long display, long handle);
- /**
- * 2011/06/14 libX11 1.4.2 and libxcb 1.7 bug 20708 - Multithreading Issues w/ OpenGL, ..
- * https://bugs.freedesktop.org/show_bug.cgi?id=20708
- * https://jogamp.org/bugzilla/show_bug.cgi?id=502
- * Affects: Ubuntu 11.04, OpenSuSE 11, ..
- * Workaround: Using a separate X11 Display connection for event dispatching (EDT)
- */
- private final boolean USE_SEPARATE_DISPLAY_FOR_EDT = true;
-
- private long edtDisplayHandle;
-
/** X11 Window delete atom marker used on EDT */
private long windowDeleteAtom;
-
+
/** X11 Window java object property used on EDT */
private long javaObjectAtom;
+
+ /** X11 Keyboard handle used on EDT */
+ // private long kbdHandle; // XKB disabled for now
}
diff --git a/src/newt/classes/jogamp/newt/driver/x11/RandR.java b/src/newt/classes/jogamp/newt/driver/x11/RandR.java
new file mode 100644
index 000000000..8b065d1f0
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/driver/x11/RandR.java
@@ -0,0 +1,86 @@
+/**
+ * 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.x11;
+
+import java.util.List;
+
+import javax.media.nativewindow.util.RectangleImmutable;
+
+import jogamp.newt.MonitorModeProps;
+
+import com.jogamp.common.util.VersionNumber;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+
+public interface RandR {
+ public static final VersionNumber version110 = new VersionNumber(1, 1, 0);
+ public static final VersionNumber version130 = new VersionNumber(1, 3, 0);
+ public static final VersionNumber version140 = new VersionNumber(1, 4, 0);
+
+ VersionNumber getVersion();
+
+ void dumpInfo(final long dpy, final int screen_idx);
+
+ /**
+ * Encapsulate initial device query allowing caching of internal data structures.
+ * Methods covered:
+ * <ul>
+ * <li>{@link #getMonitorDeviceCount(long, ScreenDriver)}</li>
+ * <li>{@link #getAvailableRotations(long, ScreenDriver, int)}</li>
+ * <li>{@link #getMonitorModeProps(long, ScreenDriver, int)}</li>
+ * <li>{@link #getCurrentMonitorModeProps(long, ScreenDriver, int)</li>
+ * <li>{@link #getMonitorDeviceProps(long, ScreenDriver, List, int, MonitorMode)}</li>
+ * </ul>
+ * <p>
+ * Above methods may be called w/o begin/end, in which case no
+ * internal data structures can be cached:
+ * </p>
+ * @param dpy TODO
+ * @param screen TODO
+ * @return TODO
+ */
+ boolean beginInitialQuery(long dpy, ScreenDriver screen);
+ void endInitialQuery(long dpy, ScreenDriver screen);
+
+ int getMonitorDeviceCount(final long dpy, final ScreenDriver screen);
+ int[] getAvailableRotations(final long dpy, final ScreenDriver screen, final int crt_idx);
+ /**
+ *
+ * @param dpy
+ * @param screen
+ * @param mode_idx w/o indexing rotation
+ * @return props w/o actual rotation
+ */
+ int[] getMonitorModeProps(final long dpy, final ScreenDriver screen, final int mode_idx);
+ int[] getMonitorDeviceProps(final long dpy, final ScreenDriver screen, MonitorModeProps.Cache cache, final int crt_idx);
+ int[] getMonitorDeviceViewport(final long dpy, final ScreenDriver screen, final int crt_idx);
+ int[] getCurrentMonitorModeProps(final long dpy, final ScreenDriver screen, final int crt_idx);
+ boolean setCurrentMonitorMode(final long dpy, final ScreenDriver screen, MonitorDevice monitor, final MonitorMode mode);
+
+ public void updateScreenViewport(final long dpy, final ScreenDriver screen, RectangleImmutable viewport);
+}
diff --git a/src/newt/classes/jogamp/newt/driver/x11/RandR11.java b/src/newt/classes/jogamp/newt/driver/x11/RandR11.java
new file mode 100644
index 000000000..4803852f9
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/driver/x11/RandR11.java
@@ -0,0 +1,370 @@
+/**
+ * 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.x11;
+
+import javax.media.nativewindow.util.RectangleImmutable;
+
+import jogamp.newt.MonitorModeProps;
+import jogamp.newt.ScreenImpl;
+
+import com.jogamp.common.util.VersionNumber;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+import com.jogamp.newt.Screen;
+
+class RandR11 implements RandR {
+ private static final boolean DEBUG = ScreenDriver.DEBUG;
+
+ RandR11() {
+ }
+
+ @Override
+ public final VersionNumber getVersion() {
+ return version110;
+ }
+
+ @Override
+ public void dumpInfo(final long dpy, final int screen_idx) {
+ // NOP
+ }
+
+ private int widthMM=0, heightMM=0;
+ private int modeCount = 0;
+ private int resolutionCount = 0;
+ private int[][] nrates = null; // [nres_number][nrate_number]
+ private int[] idx_rate = null, idx_res = null;
+
+ @Override
+ public boolean beginInitialQuery(final long dpy, final ScreenDriver screen) {
+ // initialize iterators and static data
+ final int screen_idx = screen.getIndex();
+ resolutionCount = getNumScreenResolutions0(dpy, screen_idx);
+ if(0==resolutionCount) {
+ endInitialQuery(dpy, screen);
+ return false;
+ }
+
+ nrates = new int[resolutionCount][];
+ for(int i=0; i<resolutionCount; i++) {
+ nrates[i] = getScreenRates0(dpy, screen_idx, i);
+ if(null==nrates[i] || 0==nrates[i].length) {
+ endInitialQuery(dpy, screen);
+ return false;
+ }
+ }
+
+ for(int nresIdx=0; nresIdx < resolutionCount; nresIdx++) {
+ modeCount += nrates[nresIdx].length;
+ }
+
+ idx_rate = new int[modeCount];
+ idx_res = new int[modeCount];
+
+ int modeIdx=0;
+ for(int nresIdx=0; nresIdx < resolutionCount; nresIdx++) {
+ for(int nrateIdx=0; nrateIdx < nrates[nresIdx].length; nrateIdx++) {
+ idx_rate[modeIdx] = nrateIdx;
+ idx_res[modeIdx] = nresIdx;
+ modeIdx++;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void endInitialQuery(final long dpy, final ScreenDriver screen) {
+ idx_rate=null;
+ idx_res=null;
+ nrates=null;
+ }
+
+ @Override
+ public int getMonitorDeviceCount(final long dpy, final ScreenDriver screen) {
+ return 1;
+ }
+
+ @Override
+ public int[] getAvailableRotations(final long dpy, final ScreenDriver screen, final int crt_idx) {
+ if( 0 < crt_idx ) {
+ // RandR11 only supports 1 CRT
+ return null;
+ }
+ final int screen_idx = screen.getIndex();
+ final int[] availRotations = getAvailableScreenRotations0(dpy, screen_idx);
+ if(null==availRotations || 0==availRotations.length) {
+ return null;
+ }
+ return availRotations;
+ }
+
+ @Override
+ public int[] getMonitorModeProps(final long dpy, final ScreenDriver screen, final int mode_idx) {
+ if( mode_idx >= modeCount ) {
+ return null;
+ }
+ final int screen_idx = screen.getIndex();
+
+ final int nres_index = idx_res[mode_idx];
+ final int nrate_index = idx_rate[mode_idx];
+
+ final int[] res = getScreenResolution0(dpy, screen_idx, nres_index);
+ if(null==res || 0==res.length) {
+ return null;
+ }
+ if(0>=res[0] || 0>=res[1]) {
+ throw new InternalError("invalid resolution: "+res[0]+"x"+res[1]+" for res idx "+nres_index+"/"+resolutionCount);
+ }
+ if( res[2] > widthMM ) {
+ widthMM = res[2];
+ }
+ if( res[3] > heightMM ) {
+ heightMM = res[3];
+ }
+
+ int rate = nrates[nres_index][nrate_index];
+ if(0>=rate) {
+ rate = ScreenImpl.default_sm_rate;
+ if(DEBUG) {
+ System.err.println("Invalid rate: "+rate+" at index "+nrate_index+"/"+nrates.length+", using default: "+ScreenImpl.default_sm_rate);
+ }
+ }
+
+ final int[] props = new int[ MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL ];
+ int i = 0;
+ props[i++] = MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL;
+ props[i++] = res[0]; // width
+ props[i++] = res[1]; // height
+ props[i++] = ScreenImpl.default_sm_bpp; // bpp n/a in RandR11
+ props[i++] = rate*100; // rate (Hz*100)
+ props[i++] = 0; // flags;
+ props[i++] = nres_index;
+ props[i++] = -1; // rotation placeholder;
+ if( MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL != i ) {
+ throw new InternalError("XX");
+ }
+ return props;
+ }
+
+ @Override
+ public int[] getMonitorDeviceProps(final long dpy, final ScreenDriver screen, final MonitorModeProps.Cache cache, final int crt_idx) {
+ if( 0 < crt_idx ) {
+ // RandR11 only supports 1 CRT
+ return null;
+ }
+ final int[] currentModeProps = getCurrentMonitorModeProps(dpy, screen, crt_idx);
+ if( null == currentModeProps) { // disabled
+ return null;
+ }
+ final MonitorMode currentMode = MonitorModeProps.streamInMonitorMode(null, cache, currentModeProps, 0);
+ final int allModesCount = cache.monitorModes.size();
+ final int[] props = new int[MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES - 1 + allModesCount];
+ int i = 0;
+ props[i++] = props.length;
+ props[i++] = crt_idx;
+ props[i++] = widthMM;
+ props[i++] = heightMM;
+ props[i++] = 0; // rotated viewport x pixel-units
+ props[i++] = 0; // rotated viewport y pixel-units
+ props[i++] = currentMode.getRotatedWidth(); // rotated viewport width pixel-units
+ props[i++] = currentMode.getRotatedHeight(); // rotated viewport height pixel-units
+ props[i++] = 0; // rotated viewport x window-units
+ props[i++] = 0; // rotated viewport y window-units
+ props[i++] = currentMode.getRotatedWidth(); // rotated viewport width window-units
+ props[i++] = currentMode.getRotatedHeight(); // rotated viewport height window-units
+ props[i++] = currentMode.getId(); // current mode id
+ props[i++] = currentMode.getRotation();
+ for(int j=0; j<allModesCount; j++) {
+ props[i++] = cache.monitorModes.get(j).getId();
+ }
+ return props;
+ }
+
+ @Override
+ public int[] getMonitorDeviceViewport(final long dpy, final ScreenDriver screen, final int crt_idx) {
+ if( 0 < crt_idx ) {
+ // RandR11 only supports 1 CRT
+ return null;
+ }
+ final int screen_idx = screen.getIndex();
+ final long screenConfigHandle = getScreenConfiguration0(dpy, screen_idx);
+ if(0 == screenConfigHandle) {
+ return null;
+ }
+ int[] res;
+ final int nres_idx;
+ try {
+ final int resNumber = getNumScreenResolutions0(dpy, screen_idx);
+ if(0==resNumber) {
+ return null;
+ }
+
+ nres_idx = getCurrentScreenResolutionIndex0(screenConfigHandle);
+ if(0>nres_idx) {
+ return null;
+ }
+ if(nres_idx>=resNumber) {
+ throw new RuntimeException("Invalid resolution index: ! "+nres_idx+" < "+resNumber);
+ }
+ res = getScreenResolution0(dpy, screen_idx, nres_idx);
+ if(null==res || 0==res.length) {
+ return null;
+ }
+ if(0>=res[0] || 0>=res[1]) {
+ throw new InternalError("invalid resolution: "+res[0]+"x"+res[1]+" for res idx "+nres_idx+"/"+resNumber);
+ }
+ } finally {
+ freeScreenConfiguration0(screenConfigHandle);
+ }
+ final int[] props = new int[4];
+ int i = 0;
+ props[i++] = 0;
+ props[i++] = 0;
+ props[i++] = res[0]; // width
+ props[i++] = res[1]; // height
+ return props;
+ }
+
+ @Override
+ public int[] getCurrentMonitorModeProps(final long dpy, final ScreenDriver screen, final int crt_idx) {
+ if( 0 < crt_idx ) {
+ // RandR11 only supports 1 CRT
+ return null;
+ }
+ final int screen_idx = screen.getIndex();
+ final long screenConfigHandle = getScreenConfiguration0(dpy, screen_idx);
+ if(0 == screenConfigHandle) {
+ return null;
+ }
+ int[] res;
+ int rate, rot;
+ final int nres_idx;
+ try {
+ final int resNumber = getNumScreenResolutions0(dpy, screen_idx);
+ if(0==resNumber) {
+ return null;
+ }
+
+ nres_idx = getCurrentScreenResolutionIndex0(screenConfigHandle);
+ if(0>nres_idx) {
+ return null;
+ }
+ if(nres_idx>=resNumber) {
+ throw new RuntimeException("Invalid resolution index: ! "+nres_idx+" < "+resNumber);
+ }
+ res = getScreenResolution0(dpy, screen_idx, nres_idx);
+ if(null==res || 0==res.length) {
+ return null;
+ }
+ if(0>=res[0] || 0>=res[1]) {
+ throw new InternalError("invalid resolution: "+res[0]+"x"+res[1]+" for res idx "+nres_idx+"/"+resNumber);
+ }
+ rate = getCurrentScreenRate0(screenConfigHandle);
+ if(0>rate) {
+ return null;
+ }
+ rot = getCurrentScreenRotation0(screenConfigHandle);
+ if(0>rot) {
+ return null;
+ }
+ } finally {
+ freeScreenConfiguration0(screenConfigHandle);
+ }
+ final int[] props = new int[ MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL ];
+ int i = 0;
+ props[i++] = MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL;
+ props[i++] = res[0]; // width
+ props[i++] = res[1]; // height
+ props[i++] = ScreenImpl.default_sm_bpp;
+ props[i++] = rate*100; // rate (Hz*100)
+ props[i++] = 0; // flags;
+ props[i++] = nres_idx; // mode_idx;
+ props[i++] = rot;
+ if( MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL != i ) {
+ throw new InternalError("XX");
+ }
+ return props;
+ }
+
+ @Override
+ public boolean setCurrentMonitorMode(final long dpy, final ScreenDriver screen, final MonitorDevice monitor, final MonitorMode mode) {
+ final long t0 = System.currentTimeMillis();
+ boolean done = false;
+ final int screen_idx = screen.getIndex();
+ final long screenConfigHandle = getScreenConfiguration0(dpy, screen_idx);
+ if(0 == screenConfigHandle) {
+ return Boolean.valueOf(done);
+ }
+ try {
+ final int resId = mode.getId();
+ if(0>resId || resId>=resolutionCount) {
+ throw new RuntimeException("Invalid resolution index: ! 0 < "+resId+" < "+resolutionCount+", "+monitor+", "+mode);
+ }
+ final int f = (int)mode.getRefreshRate(); // simply cut-off, orig is int
+ final int r = mode.getRotation();
+
+ if( setCurrentScreenModeStart0(dpy, screen_idx, screenConfigHandle, resId, f, r) ) {
+ while(!done && System.currentTimeMillis()-t0 < Screen.SCREEN_MODE_CHANGE_TIMEOUT) {
+ done = setCurrentScreenModePollEnd0(dpy, screen_idx, resId, f, r);
+ if(!done) {
+ try { Thread.sleep(10); } catch (final InterruptedException e) { }
+ }
+ }
+ }
+ } finally {
+ freeScreenConfiguration0(screenConfigHandle);
+ }
+ return done;
+ }
+
+ @Override
+ public final void updateScreenViewport(final long dpy, final ScreenDriver screen, final RectangleImmutable viewport) {
+ // nop
+ }
+
+ /** @return int[] { rot1, .. } */
+ private static native int[] getAvailableScreenRotations0(long display, int screen_index);
+
+ private static native int getNumScreenResolutions0(long display, int screen_index);
+
+ /** @return int[] { width, height, widthmm, heightmm } */
+ private static native int[] getScreenResolution0(long display, int screen_index, int mode_index);
+
+ private static native int[] getScreenRates0(long display, int screen_index, int mode_index);
+
+ private static native long getScreenConfiguration0(long display, int screen_index);
+ private static native void freeScreenConfiguration0(long screenConfiguration);
+
+ private static native int getCurrentScreenResolutionIndex0(long screenConfiguration);
+ private static native int getCurrentScreenRate0(long screenConfiguration);
+ private static native int getCurrentScreenRotation0(long screenConfiguration);
+
+ /** needs own Display connection for XRANDR event handling */
+ private static native boolean setCurrentScreenModeStart0(long display, int screen_index, long screenConfiguration, int mode_index, int freq, int rot);
+ private static native boolean setCurrentScreenModePollEnd0(long display, int screen_index, int mode_index, int freq, int rot);
+
+}
diff --git a/src/newt/classes/jogamp/newt/driver/x11/RandR13.java b/src/newt/classes/jogamp/newt/driver/x11/RandR13.java
new file mode 100644
index 000000000..7a409bba1
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/driver/x11/RandR13.java
@@ -0,0 +1,274 @@
+/**
+ * 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.x11;
+
+import java.util.Iterator;
+
+import javax.media.nativewindow.util.RectangleImmutable;
+
+import jogamp.newt.MonitorModeProps;
+
+import com.jogamp.common.util.IntLongHashMap;
+import com.jogamp.common.util.VersionNumber;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+
+/**
+ * Mapping details:
+ * <pre>
+ * MonitorMode.id == XRR mode-id (not index)
+ * MonitorDevice.id == XRR monitor-idx (not id)
+ * </pre>
+ */
+class RandR13 implements RandR {
+ private static final boolean DEBUG = ScreenDriver.DEBUG;
+
+ RandR13() {
+ }
+
+ @Override
+ public final VersionNumber getVersion() {
+ return version130;
+ }
+
+ @Override
+ public void dumpInfo(final long dpy, final int screen_idx) {
+ final long screenResources = getScreenResources0(dpy, screen_idx);
+ if(0 == screenResources) {
+ return;
+ }
+ try {
+ dumpInfo0(dpy, screen_idx, screenResources);
+ } finally {
+ freeScreenResources0(screenResources);
+ }
+ }
+
+ long sessionScreenResources = 0;
+ IntLongHashMap crtInfoHandleMap = null;
+
+ @Override
+ public boolean beginInitialQuery(final long dpy, final ScreenDriver screen) {
+ final int screen_idx = screen.getIndex();
+ sessionScreenResources = getScreenResources0(dpy, screen_idx);
+ if( 0 != sessionScreenResources ) {
+ crtInfoHandleMap = new IntLongHashMap();
+ crtInfoHandleMap.setKeyNotFoundValue(0);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void endInitialQuery(final long dpy, final ScreenDriver screen) {
+ if( null != crtInfoHandleMap ) {
+ for(final Iterator<IntLongHashMap.Entry> iter = crtInfoHandleMap.iterator(); iter.hasNext(); ) {
+ final IntLongHashMap.Entry entry = iter.next();
+ freeMonitorInfoHandle0(entry.value);
+ }
+ crtInfoHandleMap.clear();
+ crtInfoHandleMap = null;
+ }
+ if( 0 != sessionScreenResources ) {
+ freeScreenResources0( sessionScreenResources );
+ sessionScreenResources = 0;
+ }
+ }
+
+ private final long getScreenResourceHandle(final long dpy, final int screen_idx) {
+ if( 0 != sessionScreenResources ) {
+ return sessionScreenResources;
+ }
+ return getScreenResources0(dpy, screen_idx);
+ }
+ private final void releaseScreenResourceHandle(final long screenResourceHandle) {
+ if( 0 == sessionScreenResources ) {
+ freeScreenResources0( screenResourceHandle );
+ }
+ }
+
+ private final long getMonitorInfoHandle(final long dpy, final int screen_idx, final long screenResources, final int monitor_idx) {
+ if( null != crtInfoHandleMap ) {
+ long h = crtInfoHandleMap.get(monitor_idx);
+ if( 0 == h ) {
+ h = getMonitorInfoHandle0(dpy, screen_idx, screenResources, monitor_idx);
+ crtInfoHandleMap.put(monitor_idx, h);
+ }
+ return h;
+ } else {
+ return getMonitorInfoHandle0(dpy, screen_idx, screenResources, monitor_idx);
+ }
+ }
+ private final void releaseMonitorInfoHandle(final long monitorInfoHandle) {
+ if( null == crtInfoHandleMap ) {
+ freeMonitorInfoHandle0(monitorInfoHandle);
+ }
+ }
+
+ @Override
+ public int getMonitorDeviceCount(final long dpy, final ScreenDriver screen) {
+ final int screen_idx = screen.getIndex();
+ final long screenResources = getScreenResourceHandle(dpy, screen_idx);
+ try {
+ return getMonitorDeviceCount0(screenResources);
+ } finally {
+ releaseScreenResourceHandle(screenResources);
+ }
+ }
+
+ @Override
+ public int[] getAvailableRotations(final long dpy, final ScreenDriver screen, final int crt_idx) {
+ final int screen_idx = screen.getIndex();
+ final long screenResources = getScreenResourceHandle(dpy, screen_idx);
+ try {
+ final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_idx);
+ try {
+ final int[] availRotations = getAvailableRotations0(monitorInfo);
+ if(null==availRotations || 0==availRotations.length) {
+ return null;
+ }
+ return availRotations;
+ } finally {
+ releaseMonitorInfoHandle(monitorInfo);
+ }
+ } finally {
+ releaseScreenResourceHandle(screenResources);
+ }
+ }
+
+ @Override
+ public int[] getMonitorModeProps(final long dpy, final ScreenDriver screen, final int mode_idx) {
+ final int screen_idx = screen.getIndex();
+ final long screenResources = getScreenResourceHandle(dpy, screen_idx);
+ try {
+ return getMonitorMode0(screenResources, mode_idx);
+ } finally {
+ releaseScreenResourceHandle(screenResources);
+ }
+ }
+
+ @Override
+ public int[] getMonitorDeviceProps(final long dpy, final ScreenDriver screen, final MonitorModeProps.Cache cache, final int crt_idx) {
+ final int screen_idx = screen.getIndex();
+ final long screenResources = getScreenResourceHandle(dpy, screen_idx);
+ try {
+ final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_idx);
+ try {
+ return getMonitorDevice0(dpy, screenResources, monitorInfo, crt_idx);
+ } finally {
+ releaseMonitorInfoHandle(monitorInfo);
+ }
+ } finally {
+ releaseScreenResourceHandle(screenResources);
+ }
+ }
+
+ @Override
+ public int[] getMonitorDeviceViewport(final long dpy, final ScreenDriver screen, final int crt_idx) {
+ final int screen_idx = screen.getIndex();
+ final long screenResources = getScreenResourceHandle(dpy, screen_idx);
+ try {
+ final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_idx);
+ try {
+ return getMonitorViewport0(monitorInfo);
+ } finally {
+ releaseMonitorInfoHandle(monitorInfo);
+ }
+ } finally {
+ releaseScreenResourceHandle(screenResources);
+ }
+ }
+
+ @Override
+ public int[] getCurrentMonitorModeProps(final long dpy, final ScreenDriver screen, final int crt_idx) {
+ final int screen_idx = screen.getIndex();
+ final long screenResources = getScreenResourceHandle(dpy, screen_idx);
+ try {
+ final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_idx);
+ try {
+ return getMonitorCurrentMode0(screenResources, monitorInfo);
+ } finally {
+ releaseMonitorInfoHandle(monitorInfo);
+ }
+ } finally {
+ releaseScreenResourceHandle(screenResources);
+ }
+ }
+
+ @Override
+ public boolean setCurrentMonitorMode(final long dpy, final ScreenDriver screen, final MonitorDevice monitor, final MonitorMode mode) {
+ final int screen_idx = screen.getIndex();
+ final long screenResources = getScreenResourceHandle(dpy, screen_idx);
+ final boolean res;
+ try {
+ final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, monitor.getId());
+ try {
+ res = setMonitorMode0(dpy, screenResources, monitorInfo, monitor.getId(), mode.getId(), mode.getRotation(),
+ -1, -1); // no fixed position!
+ } finally {
+ releaseMonitorInfoHandle(monitorInfo);
+ }
+ } finally {
+ releaseScreenResourceHandle(screenResources);
+ }
+ return res;
+ }
+
+ @Override
+ public final void updateScreenViewport(final long dpy, final ScreenDriver screen, final RectangleImmutable viewport) {
+ final int screen_idx = screen.getIndex();
+ final long screenResources = getScreenResourceHandle(dpy, screen_idx);
+ try {
+ setScreenViewport0(dpy, screen_idx, screenResources, viewport.getX(), viewport.getY(), viewport.getWidth(), viewport.getHeight());
+ } finally {
+ dumpInfo0(dpy, screen_idx, screenResources);
+ releaseScreenResourceHandle(screenResources);
+ }
+ }
+
+ private static native long getScreenResources0(long display, int screen_index);
+ private static native void freeScreenResources0(long screenResources);
+ private static native void dumpInfo0(long display, int screen_index, long screenResources);
+
+ private static native int getMonitorDeviceCount0(long screenResources);
+
+ private static native long getMonitorInfoHandle0(long display, int screen_index, long screenResources, int monitor_index);
+ private static native void freeMonitorInfoHandle0(long monitorInfoHandle);
+
+ private static native int[] getAvailableRotations0(long monitorInfo);
+ private static native int[] getMonitorViewport0(long monitorInfo);
+ private static native int[] getMonitorCurrentMode0(long monitorInfo);
+
+ private static native int[] getMonitorMode0(long screenResources, int mode_index);
+ private static native int[] getMonitorCurrentMode0(long screenResources, long monitorInfo);
+ private static native int[] getMonitorDevice0(long display, long screenResources, long monitorInfo, int monitor_idx);
+
+ private static native boolean setMonitorMode0(long display, long screenResources, long monitorInfo, int monitor_idx, int mode_id, int rotation, int x, int y);
+ private static native boolean setScreenViewport0(long display, int screen_index, long screenResources, int x, int y, int width, int height);
+}
diff --git a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java
index 10f6b84da..f7361740e 100644
--- a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,290 +29,241 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package jogamp.newt.driver.x11;
+import java.util.ArrayList;
import java.util.List;
-import javax.media.nativewindow.util.Dimension;
-import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.util.Rectangle;
+import javax.media.nativewindow.util.RectangleImmutable;
import jogamp.nativewindow.x11.X11Util;
+import jogamp.newt.Debug;
import jogamp.newt.DisplayImpl;
+import jogamp.newt.MonitorModeProps;
import jogamp.newt.DisplayImpl.DisplayRunnable;
import jogamp.newt.ScreenImpl;
+import com.jogamp.common.util.ArrayHashSet;
+import com.jogamp.common.util.PropertyAccess;
+import com.jogamp.common.util.VersionNumber;
import com.jogamp.nativewindow.x11.X11GraphicsDevice;
import com.jogamp.nativewindow.x11.X11GraphicsScreen;
-import com.jogamp.newt.ScreenMode;
-import com.jogamp.newt.util.ScreenModeUtil;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
public class ScreenDriver extends ScreenImpl {
+ protected static final boolean DEBUG_TEST_RANDR13_DISABLED;
static {
+ Debug.initSingleton();
+ DEBUG_TEST_RANDR13_DISABLED = PropertyAccess.isPropertyDefined("newt.test.Screen.disableRandR13", true);
+
DisplayDriver.initSingleton();
}
+ /** Ensure static init has been run. */
+ /* pp */static void initSingleton() { }
+
public ScreenDriver() {
}
+ @Override
protected void createNativeImpl() {
// validate screen index
- Long handle = display.runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Long>() {
- public Long run(long dpy) {
- return new Long(GetScreen0(dpy, screen_idx));
- } } );
+ final Long handle = runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Long>() {
+ @Override
+ public Long run(final long dpy) {
+ return Long.valueOf(GetScreen0(dpy, screen_idx));
+ } } );
if (handle.longValue() == 0) {
throw new RuntimeException("Error creating screen: " + screen_idx);
- }
- aScreen = new X11GraphicsScreen((X11GraphicsDevice) getDisplay().getGraphicsDevice(), screen_idx);
+ }
+ final X11GraphicsDevice x11dev = (X11GraphicsDevice) getDisplay().getGraphicsDevice();
+ final long dpy = x11dev.getHandle();
+ aScreen = new X11GraphicsScreen(x11dev, screen_idx);
+ {
+ final int v[] = getRandRVersion0(dpy);
+ randrVersion = new VersionNumber(v[0], v[1], 0);
+ }
+ {
+ if( !DEBUG_TEST_RANDR13_DISABLED && randrVersion.compareTo(RandR.version130) >= 0 ) {
+ rAndR = new RandR13();
+ } else if( randrVersion.compareTo(RandR.version110) >= 0 ) {
+ rAndR = new RandR11();
+ } else {
+ rAndR = null;
+ }
+ }
+ if( DEBUG ) {
+ System.err.println("RandR "+randrVersion+", "+rAndR);
+ rAndR.dumpInfo(dpy, screen_idx);
+ }
}
+ @Override
protected void closeNativeImpl() {
}
- private int[] nrotations;
- private int nrotation_index;
- private int nres_number;
- private int nres_index;
- private int[] nrates;
- private int nrate_index;
- private int nmode_number;
+ private VersionNumber randrVersion;
+ private RandR rAndR;
- protected int[] getScreenModeFirstImpl() {
- return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<int[]>() {
- public int[] run(long dpy) {
- // initialize iterators and static data
- nrotations = getAvailableScreenModeRotations0(dpy, screen_idx);
- if(null==nrotations || 0==nrotations.length) {
- return null;
- }
- nrotation_index = 0;
-
- nres_number = getNumScreenModeResolutions0(dpy, screen_idx);
- if(0==nres_number) {
- return null;
- }
- nres_index = 0;
-
- nrates = getScreenModeRates0(dpy, screen_idx, nres_index);
- if(null==nrates || 0==nrates.length) {
- return null;
- }
- nrate_index = 0;
-
- nmode_number = 0;
-
- return getScreenModeNextImpl();
- } } );
- }
+ @Override
+ protected final void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) {
+ if( null == rAndR ) { return; }
+ final AbstractGraphicsDevice device = getDisplay().getGraphicsDevice();
+ device.lock();
+ try {
+ if( rAndR.beginInitialQuery(device.getHandle(), this) ) {
+ try {
+ final int crtCount = rAndR.getMonitorDeviceCount(device.getHandle(), this);
- protected int[] getScreenModeNextImpl() {
- // assemble: w x h x bpp x f x r
- return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<int[]>() {
- public int[] run(long dpy) {
- /**
- System.err.println("******** mode: "+nmode_number);
- System.err.println("rot "+nrotation_index);
- System.err.println("rate "+nrate_index);
- System.err.println("res "+nres_index); */
-
- int[] res = getScreenModeResolution0(dpy, screen_idx, nres_index);
- if(null==res || 0==res.length) {
- return null;
- }
- if(0>=res[0] || 0>=res[1]) {
- throw new InternalError("invalid resolution: "+res[0]+"x"+res[1]+" for res idx "+nres_index+"/"+nres_number);
- }
- int rate = nrates[nrate_index];
- if(0>=rate) {
- rate = default_sm_rate;
- if(DEBUG) {
- System.err.println("Invalid rate: "+rate+" at index "+nrate_index+"/"+nrates.length+", using default: "+default_sm_rate);
- }
- }
- int rotation = nrotations[nrotation_index];
-
- int[] props = new int[ 1 + ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL ];
- int i = 0;
- props[i++] = nres_index; // use resolution index, not unique for native -> ScreenMode
- props[i++] = 0; // set later for verification of iterator
- props[i++] = res[0]; // width
- props[i++] = res[1]; // height
- props[i++] = default_sm_bpp; // FIXME
- props[i++] = res[2]; // widthmm
- props[i++] = res[3]; // heightmm
- props[i++] = rate; // rate
- props[i++] = rotation;
- props[i - ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL] = i - 1; // count without extra element
-
- nmode_number++;
-
- // iteration: r -> f -> bpp -> [w x h]
- nrotation_index++;
- if(nrotation_index == nrotations.length) {
- nrotation_index=0;
- nrate_index++;
- if(null == nrates || nrate_index == nrates.length){
- nres_index++;
- if(nres_index == nres_number) {
- // done
- nrates=null;
- nrotations=null;
- return null;
+ // Gather all available rotations
+ final ArrayHashSet<Integer> availableRotations = new ArrayHashSet<Integer>();
+ for(int i = 0; i < crtCount; i++) {
+ final int[] rotations = rAndR.getAvailableRotations(device.getHandle(), this, i);
+ if( null != rotations ) {
+ final List<Integer> rotationList = new ArrayList<Integer>(rotations.length);
+ for(int j=0; j<rotations.length; j++ ) { rotationList.add(rotations[j]); }
+ availableRotations.addAll(rotationList);
}
-
- nrates = getScreenModeRates0(dpy, screen_idx, nres_index);
- if(null==nrates || 0==nrates.length) {
- return null;
- }
- nrate_index = 0;
}
- }
-
- return props;
- } } );
- }
- protected ScreenMode getCurrentScreenModeImpl() {
- return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<ScreenMode>() {
- public ScreenMode run(long dpy) {
- long screenConfigHandle = getScreenConfiguration0(dpy, screen_idx);
- if(0 == screenConfigHandle) {
- return null;
- }
- int[] res;
- int rate, rot;
- try {
- int resNumber = getNumScreenModeResolutions0(dpy, screen_idx);
- if(0==resNumber) {
- return null;
- }
-
- int resIdx = getCurrentScreenResolutionIndex0(screenConfigHandle);
- if(0>resIdx) {
- return null;
- }
- if(resIdx>=resNumber) {
- throw new RuntimeException("Invalid resolution index: ! "+resIdx+" < "+resNumber);
- }
- res = getScreenModeResolution0(dpy, screen_idx, resIdx);
- if(null==res || 0==res.length) {
- return null;
- }
- if(0>=res[0] || 0>=res[1]) {
- throw new InternalError("invalid resolution: "+res[0]+"x"+res[1]+" for res idx "+resIdx+"/"+resNumber);
- }
- rate = getCurrentScreenRate0(screenConfigHandle);
- if(0>rate) {
- return null;
+ // collect all modes, while injecting all available rotations
+ {
+ int modeIdx = 0;
+ int[] props;
+ do {
+ props = rAndR.getMonitorModeProps(device.getHandle(), this, modeIdx++);
+ if( null != props ) {
+ for(int i = 0; i < availableRotations.size(); i++) {
+ props[MonitorModeProps.IDX_MONITOR_MODE_ROT] = availableRotations.get(i);
+ MonitorModeProps.streamInMonitorMode(null, cache, props, 0);
+ }
+ }
+ } while( null != props);
}
- rot = getCurrentScreenRotation0(screenConfigHandle);
- if(0>rot) {
- return null;
+ if( cache.monitorModes.size() > 0 ) {
+ for(int i = 0; i < crtCount; i++) {
+ final int[] monitorProps = rAndR.getMonitorDeviceProps(device.getHandle(), this, cache, i);
+ if( null != monitorProps &&
+ MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES <= monitorProps[0] && // Enabled ? I.e. contains active modes ?
+ MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES <= monitorProps.length ) {
+ MonitorModeProps.streamInMonitorDevice(null, cache, this, monitorProps, 0);
+ }
+ }
}
} finally {
- freeScreenConfiguration0(screenConfigHandle);
+ rAndR.endInitialQuery(device.getHandle(), this);
}
- int[] props = new int[ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL];
- int i = 0;
- props[i++] = 0; // set later for verification of iterator
- props[i++] = res[0]; // width
- props[i++] = res[1]; // height
- props[i++] = default_sm_bpp; // FIXME
- props[i++] = res[2]; // widthmm
- props[i++] = res[3]; // heightmm
- props[i++] = rate; // rate
- props[i++] = rot;
- props[i - ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL] = i; // count
- return ScreenModeUtil.streamIn(props, 0);
- } } );
+ }
+ } finally {
+ device.unlock();
+ }
}
- protected boolean setCurrentScreenModeImpl(final ScreenMode screenMode) {
- final List<ScreenMode> screenModes = this.getScreenModesOrig();
- final int screenModeIdx = screenModes.indexOf(screenMode);
- if(0>screenModeIdx) {
- throw new RuntimeException("ScreenMode not element of ScreenMode list: "+screenMode);
+ @Override
+ protected boolean updateNativeMonitorDeviceViewportImpl(final MonitorDevice monitor, final Rectangle viewportPU, final Rectangle viewportWU) {
+ final AbstractGraphicsDevice device = getDisplay().getGraphicsDevice();
+ device.lock();
+ try {
+ final int[] viewportProps = rAndR.getMonitorDeviceViewport(device.getHandle(), this, monitor.getId());
+ viewportPU.set(viewportProps[0], viewportProps[1], viewportProps[2], viewportProps[3]);
+ viewportWU.set(viewportProps[0], viewportProps[1], viewportProps[2], viewportProps[3]); // equal window-units and pixel-units
+ return true;
+ } finally {
+ device.unlock();
}
+ }
+
+ @Override
+ protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) {
+ if( null == rAndR ) { return null; }
+
+ return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<MonitorMode>() {
+ @Override
+ public MonitorMode run(final long dpy) {
+ final int[] currentModeProps = rAndR.getCurrentMonitorModeProps(dpy, ScreenDriver.this, monitor.getId());
+ return MonitorModeProps.streamInMonitorMode(null, null, currentModeProps, 0);
+ } } );
+ }
+
+ @Override
+ protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) {
+ if( null == rAndR ) { return false; }
+
final long t0 = System.currentTimeMillis();
- boolean done = runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Boolean>() {
- public Boolean run(long dpy) {
- boolean done = false;
- long screenConfigHandle = getScreenConfiguration0(dpy, screen_idx);
- if(0 == screenConfigHandle) {
- return Boolean.valueOf(done);
- }
- try {
- int resNumber = getNumScreenModeResolutions0(dpy, screen_idx);
- int resIdx = getScreenModesIdx2NativeIdx().get(screenModeIdx);
- if(0>resIdx || resIdx>=resNumber) {
- throw new RuntimeException("Invalid resolution index: ! 0 < "+resIdx+" < "+resNumber+", screenMode["+screenModeIdx+"] "+screenMode);
- }
-
- final int f = screenMode.getMonitorMode().getRefreshRate();
- final int r = screenMode.getRotation();
-
- if( setCurrentScreenModeStart0(dpy, screen_idx, screenConfigHandle, resIdx, f, r) ) {
- while(!done && System.currentTimeMillis()-t0 < SCREEN_MODE_CHANGE_TIMEOUT) {
- done = setCurrentScreenModePollEnd0(dpy, screen_idx, resIdx, f, r);
- if(!done) {
- try { Thread.sleep(10); } catch (InterruptedException e) { }
- }
- }
- }
- } finally {
- freeScreenConfiguration0(screenConfigHandle);
- }
- return Boolean.valueOf(done);
- }
+ final boolean done = runWithOptTempDisplayHandle( new DisplayImpl.DisplayRunnable<Boolean>() {
+ @Override
+ public Boolean run(final long dpy) {
+ return Boolean.valueOf( rAndR.setCurrentMonitorMode(dpy, ScreenDriver.this, monitor, mode) );
+ }
}).booleanValue();
-
+
if(DEBUG || !done) {
- System.err.println("X11Screen.setCurrentScreenModeImpl: TO ("+SCREEN_MODE_CHANGE_TIMEOUT+") reached: "+
- (System.currentTimeMillis()-t0)+"ms; Current: "+getCurrentScreenMode()+"; Desired: "+screenMode);
+ System.err.println("X11Screen.setCurrentMonitorModeImpl: TO ("+SCREEN_MODE_CHANGE_TIMEOUT+") reached: "+
+ (System.currentTimeMillis()-t0)+"ms; "+monitor.getCurrentMode()+" -> "+mode);
}
return done;
}
- private class XineramaEnabledQuery implements DisplayImpl.DisplayRunnable<Boolean> {
- public Boolean run(long dpy) {
- return new Boolean(X11Util.XineramaIsEnabled(dpy));
- }
- }
- private XineramaEnabledQuery xineramaEnabledQuery = new XineramaEnabledQuery();
-
+ private final DisplayImpl.DisplayRunnable<Boolean> xineramaEnabledQueryWithTemp = new DisplayImpl.DisplayRunnable<Boolean>() {
+ @Override
+ public Boolean run(final long dpy) {
+ return Boolean.valueOf(X11Util.XineramaIsEnabled(dpy));
+ } };
+
+ @Override
protected int validateScreenIndex(final int idx) {
- if(getDisplay().isNativeValid()) {
- return runWithLockedDisplayHandle( xineramaEnabledQuery ).booleanValue() ? 0 : idx;
+ final DisplayDriver x11Display = (DisplayDriver) getDisplay();
+ final Boolean r = x11Display.isXineramaEnabled();
+ if( null != r ) {
+ return r.booleanValue() ? 0 : idx;
} else {
- return runWithTempDisplayHandle( xineramaEnabledQuery ).booleanValue() ? 0 : idx;
+ return runWithTempDisplayHandle( xineramaEnabledQueryWithTemp ).booleanValue() ? 0 : idx;
}
}
-
- protected void getVirtualScreenOriginAndSize(final Point virtualOrigin, final Dimension virtualSize) {
- display.runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Object>() {
- public Object run(long dpy) {
- virtualOrigin.setX(0);
- virtualOrigin.setY(0);
- virtualSize.setWidth(getWidth0(dpy, screen_idx));
- virtualSize.setHeight(getHeight0(dpy, screen_idx));
- return null;
- } } );
- }
-
+
+ @Override
+ protected void calcVirtualScreenOriginAndSize(final Rectangle viewport, final Rectangle viewportInWindowUnits) {
+ final RectangleImmutable ov = DEBUG ? (RectangleImmutable) getViewport().cloneMutable() : null;
+ /**
+ if( null != rAndR && rAndR.getVersion().compareTo(RandR.version130) >= 0 && getMonitorDevices().size()>0 ) {
+ super.calcVirtualScreenOriginAndSize(vOriginSize);
+ if( DEBUG ) {
+ System.err.println("X11Screen.calcVirtualScreenOriginAndSize: UpdatingViewport "+ov+" -> "+vOriginSize);
+ }
+ runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() {
+ public Object run(long dpy) {
+ rAndR.updateScreenViewport(dpy, ScreenDriver.this, vOriginSize);
+ return null;
+ } } );
+ } else */ {
+ runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() {
+ @Override
+ public Object run(final long dpy) {
+ viewport.set(0, 0, getWidth0(dpy, screen_idx), getHeight0(dpy, screen_idx));
+ viewportInWindowUnits.set(viewport);
+ return null;
+ } } );
+ if( DEBUG ) {
+ System.err.println("X11Screen.calcVirtualScreenOriginAndSize: Querying X11: "+ov+" -> "+viewport);
+ }
+ }
+ }
+
//----------------------------------------------------------------------
// Internals only
- //
- private final <T> T runWithLockedDisplayHandle(DisplayRunnable<T> action) {
- return display.runWithLockedDisplayHandle(action);
- // return runWithTempDisplayHandle(action);
- // return runWithoutLock(action);
+ //
+ private final <T> T runWithLockedDisplayDevice(final DisplayRunnable<T> action) {
+ return display.runWithLockedDisplayDevice(action);
}
-
- private final <T> T runWithTempDisplayHandle(DisplayRunnable<T> action) {
- final long displayHandle = X11Util.openDisplay(display.getName());
+
+ private final <T> T runWithTempDisplayHandle(final DisplayRunnable<T> action) {
+ final long displayHandle = X11Util.openDisplay(display.getName());
if(0 == displayHandle) {
throw new RuntimeException("null device");
}
@@ -324,34 +275,20 @@ public class ScreenDriver extends ScreenImpl {
}
return res;
}
- private final <T> T runWithoutLock(DisplayRunnable<T> action) {
- return action.run(display.getHandle());
+
+ private final <T> T runWithOptTempDisplayHandle(final DisplayRunnable<T> action) {
+ if( null != rAndR && rAndR.getVersion().compareTo(RandR.version130) >= 0 ) {
+ return display.runWithLockedDisplayDevice(action);
+ } else {
+ return runWithTempDisplayHandle(action);
+ }
}
-
+
private static native long GetScreen0(long dpy, int scrn_idx);
private static native int getWidth0(long display, int scrn_idx);
private static native int getHeight0(long display, int scrn_idx);
- /** @return int[] { rot1, .. } */
- private static native int[] getAvailableScreenModeRotations0(long display, int screen_index);
-
- private static native int getNumScreenModeResolutions0(long display, int screen_index);
-
- /** @return int[] { width, height, widthmm, heightmm } */
- private static native int[] getScreenModeResolution0(long display, int screen_index, int mode_index);
-
- private static native int[] getScreenModeRates0(long display, int screen_index, int mode_index);
-
- private static native long getScreenConfiguration0(long display, int screen_index);
- private static native void freeScreenConfiguration0(long screenConfiguration);
-
- private static native int getCurrentScreenResolutionIndex0(long screenConfiguration);
- private static native int getCurrentScreenRate0(long screenConfiguration);
- private static native int getCurrentScreenRotation0(long screenConfiguration);
-
- /** needs own Display connection for XRANDR event handling */
- private static native boolean setCurrentScreenModeStart0(long display, int screen_index, long screenConfiguration, int mode_index, int freq, int rot);
- private static native boolean setCurrentScreenModePollEnd0(long display, int screen_index, int mode_index, int freq, int rot);
+ private static native int[] getRandRVersion0(long display);
}
diff --git a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java
index 97d1ae3db..afa9786e2 100644
--- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 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:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,46 +29,91 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
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.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;
import javax.media.nativewindow.util.InsetsImmutable;
import javax.media.nativewindow.util.Point;
+import com.jogamp.common.nio.Buffers;
+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;
public class WindowDriver extends WindowImpl {
private static final String WINDOW_CLASS_NAME = "NewtWindow";
- private static final int X11_WHEEL_ONE_UP_BUTTON = 4;
+ private static final int X11_WHEEL_ONE_UP_BUTTON = 4;
private static final int X11_WHEEL_ONE_DOWN_BUTTON = 5;
- private static final int X11_WHEEL_TWO_UP_BUTTON = 6;
+ 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 {
- DisplayDriver.initSingleton();
+ ScreenDriver.initSingleton();
+
+ int _icon_data_size=0, _icon_elem_bytesize=0;
+ Buffer _icon_data=null;
+ if( PNGIcon.isAvailable() ) {
+ try {
+ // NOTE: MUST BE DIRECT BUFFER, since _NET_WM_ICON Atom uses buffer directly!
+ 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 (final 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() {
}
+ @Override
protected void createNativeImpl() {
final ScreenDriver screen = (ScreenDriver) getScreen();
final DisplayDriver display = (DisplayDriver) screen.getDisplay();
+ final AbstractGraphicsDevice edtDevice = display.getGraphicsDevice();
+
+ // Decoupled X11 Device/Screen allowing X11 display lock-free off-thread rendering
+ final long renderDeviceHandle = X11Util.openDisplay(edtDevice.getConnection());
+ if( 0 == renderDeviceHandle ) {
+ throw new RuntimeException("Error creating display(GfxCfg/Render): "+edtDevice.getConnection());
+ }
+ renderDevice = new X11GraphicsDevice(renderDeviceHandle, AbstractGraphicsDevice.DEFAULT_UNIT, true /* owner */);
+ final AbstractGraphicsScreen renderScreen = new X11GraphicsScreen(renderDevice, screen.getIndex());
+
final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice(), capsRequested);
final AbstractGraphicsConfiguration cfg = factory.chooseGraphicsConfiguration(
- capsRequested, capsRequested, capabilitiesChooser, screen.getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED);
+ capsRequested, capsRequested, capabilitiesChooser, renderScreen, VisualIDHolder.VID_UNDEFINED);
if(DEBUG_IMPLEMENTATION) {
System.err.println("X11Window.createNativeImpl() factory: "+factory+", chosen config: "+cfg);
- }
+ }
if (null == cfg) {
throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this);
}
@@ -77,115 +122,231 @@ public class WindowDriver extends WindowImpl {
throw new NativeWindowException("Chosen Configuration w/o native visual ID: "+cfg);
}
setGraphicsConfiguration(cfg);
- final int flags = getReconfigureFlags(0, true) &
- ( FLAG_IS_ALWAYSONTOP | FLAG_IS_UNDECORATED ) ;
- setWindowHandle(CreateWindow0(getParentWindowHandle(),
- display.getEDTHandle(), screen.getIndex(), visualID,
- display.getJavaObjectAtom(), display.getWindowDeleteAtom(),
- getX(), getY(), getWidth(), getHeight(), autoPosition(), flags));
+ final int flags = getReconfigureFlags(0, true) &
+ ( FLAG_IS_ALWAYSONTOP | FLAG_IS_UNDECORATED ) ;
+ edtDevice.lock();
+ try {
+ setWindowHandle(CreateWindow(getParentWindowHandle(),
+ edtDevice.getHandle(), screen.getIndex(), visualID,
+ display.getJavaObjectAtom(), display.getWindowDeleteAtom(),
+ getX(), getY(), getWidth(), getHeight(), autoPosition(), flags,
+ defaultIconDataSize, defaultIconData));
+ } finally {
+ edtDevice.unlock();
+ }
windowHandleClose = getWindowHandle();
if (0 == windowHandleClose) {
throw new NativeWindowException("Error creating window");
}
}
+ @Override
protected void closeNativeImpl() {
if(0!=windowHandleClose && null!=getScreen() ) {
- DisplayDriver display = (DisplayDriver) getScreen().getDisplay();
+ final DisplayDriver display = (DisplayDriver) getScreen().getDisplay();
+ final AbstractGraphicsDevice edtDevice = display.getGraphicsDevice();
+ edtDevice.lock();
try {
- CloseWindow0(display.getEDTHandle(), windowHandleClose,
- display.getJavaObjectAtom(), display.getWindowDeleteAtom());
- } catch (Throwable t) {
- if(DEBUG_IMPLEMENTATION) {
- Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t);
+ CloseWindow0(edtDevice.getHandle(), windowHandleClose,
+ display.getJavaObjectAtom(), display.getWindowDeleteAtom() /* , display.getKbdHandle() */); // XKB disabled for now
+ } catch (final Throwable t) {
+ if(DEBUG_IMPLEMENTATION) {
+ final Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t);
e.printStackTrace();
}
} finally {
+ edtDevice.unlock();
windowHandleClose = 0;
}
}
+ if(null != renderDevice) {
+ renderDevice.close(); // closes X11 display
+ renderDevice = null;
+ }
}
- protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
+ /**
+ * <p>
+ * X11 Window supports {@link #FLAG_IS_FULLSCREEN_SPAN}
+ * </p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean isReconfigureFlagSupported(final int changeFlags) {
+ return true; // all flags!
+ }
+
+ @Override
+ protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, int flags) {
+ final int _x, _y;
+ final InsetsImmutable _insets;
+ if( 0 == ( FLAG_IS_UNDECORATED & flags) ) {
+ // client position -> top-level window position
+ _insets = getInsets();
+ _x = x - _insets.getLeftWidth() ;
+ _y = y - _insets.getTopHeight() ;
+ } else {
+ _insets = null;
+ _x = x;
+ _y = y;
+ }
if(DEBUG_IMPLEMENTATION) {
- System.err.println("X11Window reconfig: "+x+"/"+y+" "+width+"x"+height+", "+
- getReconfigureFlagsAsString(null, flags));
+ System.err.println("X11Window reconfig: "+x+"/"+y+" -> "+_x+"/"+_y+" "+width+"x"+height+", insets "+_insets+", "+ getReconfigureFlagsAsString(null, flags));
}
- if(0 == ( FLAG_IS_UNDECORATED & flags)) {
- final InsetsImmutable i = getInsets();
-
- // client position -> top-level window position
- x -= i.getLeftWidth() ;
- y -= i.getTopHeight() ;
+ if( 0 != ( FLAG_CHANGE_FULLSCREEN & flags ) ) {
+ if( 0 != ( FLAG_IS_FULLSCREEN & flags) && 0 == ( FLAG_IS_ALWAYSONTOP & flags) ) {
+ tempFSAlwaysOnTop = true;
+ flags |= FLAG_IS_ALWAYSONTOP;
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("X11Window reconfig.2: temporary "+getReconfigureFlagsAsString(null, flags));
+ }
+ } else {
+ tempFSAlwaysOnTop = false;
+ }
}
+ final int fflags = flags;
final DisplayDriver display = (DisplayDriver) getScreen().getDisplay();
- reconfigureWindow0( getDisplayEDTHandle(), getScreenIndex(),
- getParentWindowHandle(), getWindowHandle(), display.getWindowDeleteAtom(),
- x, y, width, height, flags);
-
+ runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() {
+ @Override
+ public Object run(final long dpy) {
+ reconfigureWindow0( dpy, getScreenIndex(),
+ getParentWindowHandle(), getWindowHandle(), display.getWindowDeleteAtom(),
+ _x, _y, width, height, fflags);
+ return null;
+ }
+ });
return true;
}
+ volatile boolean tempFSAlwaysOnTop = false;
+
+ /**
+ * <p>
+ * Deal w/ tempAlwaysOnTop.
+ * </p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected void focusChanged(final boolean defer, final boolean focusGained) {
+ if( isNativeValid() && isFullscreen() && tempFSAlwaysOnTop && hasFocus() != focusGained ) {
+ final int flags = getReconfigureFlags(FLAG_CHANGE_ALWAYSONTOP, isVisible()) | ( focusGained ? FLAG_IS_ALWAYSONTOP : 0 );
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("X11Window reconfig.3 (focus): temporary "+getReconfigureFlagsAsString(null, flags));
+ }
+ final DisplayDriver display = (DisplayDriver) getScreen().getDisplay();
+ runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() {
+ @Override
+ public Object run(final long dpy) {
+ reconfigureWindow0( dpy, getScreenIndex(),
+ getParentWindowHandle(), getWindowHandle(), display.getWindowDeleteAtom(),
+ getX(), getY(), getWidth(), getHeight(), flags);
+ return null;
+ }
+ });
+ }
+ super.focusChanged(defer, focusGained);
+ }
- protected void reparentNotify(long newParentWindowHandle) {
+ protected void reparentNotify(final long newParentWindowHandle) {
if(DEBUG_IMPLEMENTATION) {
final long p0 = getParentWindowHandle();
System.err.println("Window.reparentNotify ("+getThreadName()+"): "+toHexString(p0)+" -> "+toHexString(newParentWindowHandle));
}
}
-
- protected void requestFocusImpl(boolean force) {
- requestFocus0(getDisplayEDTHandle(), getWindowHandle(), force);
+
+ @Override
+ protected void requestFocusImpl(final boolean force) {
+ runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() {
+ @Override
+ public Object run(final long dpy) {
+ requestFocus0(dpy, getWindowHandle(), force);
+ return null;
+ }
+ });
}
@Override
protected void setTitleImpl(final String title) {
- runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Object>() {
- public Object run(long dpy) {
+ runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() {
+ @Override
+ public Object run(final long dpy) {
setTitle0(dpy, getWindowHandle(), title);
return null;
}
});
}
-
+
+ @Override
+ protected void setPointerIconImpl(final PointerIconImpl pi) {
+ runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() {
+ @Override
+ public Object run(final long dpy) {
+ try {
+ setPointerIcon0(dpy, getWindowHandle(), null != pi ? pi.validatedHandle() : 0);
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+ });
+ }
+
@Override
protected boolean setPointerVisibleImpl(final boolean pointerVisible) {
- return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Boolean>() {
- public Boolean run(long dpy) {
- return Boolean.valueOf(setPointerVisible0(getDisplayEDTHandle(), getWindowHandle(), pointerVisible));
+ return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Boolean>() {
+ @Override
+ public Boolean run(final long dpy) {
+ final PointerIconImpl pi = (PointerIconImpl)getPointerIcon();
+ final boolean res;
+ if( pointerVisible && null != pi ) {
+ setPointerIcon0(dpy, getWindowHandle(), pi.validatedHandle());
+ res = true;
+ } else {
+ res = setPointerVisible0(dpy, getWindowHandle(), pointerVisible);
+ }
+ return Boolean.valueOf(res);
}
}).booleanValue();
}
@Override
protected boolean confinePointerImpl(final boolean confine) {
- return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Boolean>() {
- public Boolean run(long dpy) {
- return Boolean.valueOf(confinePointer0(getDisplayEDTHandle(), getWindowHandle(), confine));
+ return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Boolean>() {
+ @Override
+ public Boolean run(final long dpy) {
+ return Boolean.valueOf(confinePointer0(dpy, getWindowHandle(), confine));
}
}).booleanValue();
}
-
+
@Override
protected void warpPointerImpl(final int x, final int y) {
- runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Object>() {
- public Object run(long dpy) {
- warpPointer0(getDisplayEDTHandle(), getWindowHandle(), x, y);
+ runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() {
+ @Override
+ public Object run(final long dpy) {
+ warpPointer0(dpy, getWindowHandle(), x, y);
return null;
}
});
}
-
+
+ @Override
protected Point getLocationOnScreenImpl(final int x, final int y) {
- // X11Util.GetRelativeLocation: locks display already !
- return X11Lib.GetRelativeLocation( getScreen().getDisplay().getHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y);
+ return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Point>() {
+ @Override
+ public Point run(final long dpy) {
+ return X11Lib.GetRelativeLocation(dpy, getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y);
+ }
+ } );
}
- protected void updateInsetsImpl(Insets insets) {
- // nop - using event driven insetsChange(..)
+ @Override
+ protected void updateInsetsImpl(final Insets insets) {
+ // nop - using event driven insetsChange(..)
}
-
- protected void doMouseEvent(boolean enqueue, boolean wait, int eventType, int modifiers,
- int x, int y, int button, int rotation) {
+
+ @Override
+ protected final void doMouseEvent(final boolean enqueue, final boolean wait, short eventType, int modifiers,
+ final int x, final int y, short button, final float[] rotationXYZ, final float rotationScale) {
switch(eventType) {
case MouseEvent.EVENT_MOUSE_PRESSED:
switch(button) {
@@ -198,64 +359,111 @@ public class WindowDriver extends WindowImpl {
}
break;
case MouseEvent.EVENT_MOUSE_RELEASED:
+ final boolean shiftPressed = 0 != ( modifiers & InputEvent.SHIFT_MASK );
switch(button) {
- case X11_WHEEL_ONE_UP_BUTTON:
+ case X11_WHEEL_ONE_UP_BUTTON: // vertical scroll up
eventType = MouseEvent.EVENT_MOUSE_WHEEL_MOVED;
button = 1;
- rotation = 1;
+ rotationXYZ[shiftPressed ? 0 : 1] = 1;
break;
- case X11_WHEEL_ONE_DOWN_BUTTON:
+ case X11_WHEEL_ONE_DOWN_BUTTON: // vertical scroll down
eventType = MouseEvent.EVENT_MOUSE_WHEEL_MOVED;
button = 1;
- rotation = -1;
+ rotationXYZ[shiftPressed ? 0 : 1] = -1;
break;
- case X11_WHEEL_TWO_UP_BUTTON:
+ case X11_WHEEL_TWO_UP_BUTTON: // horizontal scroll left
eventType = MouseEvent.EVENT_MOUSE_WHEEL_MOVED;
- button = 2;
- rotation = 1;
+ button = 1;
+ rotationXYZ[0] = 1;
+ modifiers |= InputEvent.SHIFT_MASK;
break;
- case X11_WHEEL_TWO_DOWN_BUTTON:
+ case X11_WHEEL_TWO_DOWN_BUTTON: // horizontal scroll right
eventType = MouseEvent.EVENT_MOUSE_WHEEL_MOVED;
- button = 2;
- rotation = -1;
+ button = 1;
+ rotationXYZ[0] = -1;
+ modifiers |= InputEvent.SHIFT_MASK;
break;
- }
+ }
break;
}
- super.doMouseEvent(enqueue, wait, eventType, modifiers, x, y, button, rotation);
+ super.doMouseEvent(enqueue, wait, eventType, modifiers, x, y, button, rotationXYZ, rotationScale);
}
-
-
+
+ /** Called by native TK */
+ protected final void sendKeyEvent(final short eventType, final int modifiers, final short keyCode, final short keySym, final char keyChar0, final String keyString) {
+ // handleKeyEvent(true, false, eventType, modifiers, keyCode, keyChar);
+ final boolean isModifierKey = KeyEvent.isModifierKey(keyCode);
+ final boolean isAutoRepeat = 0 != ( InputEvent.AUTOREPEAT_MASK & modifiers );
+ final char keyChar = ( null != keyString ) ? keyString.charAt(0) : keyChar0;
+ // System.err.println("*** sendKeyEvent: event "+KeyEvent.getEventTypeString(eventType)+", keyCode "+toHexString(keyCode)+", keyChar <"+keyChar0+">/<"+keyChar+">, keyString "+keyString+", mods "+toHexString(modifiers)+
+ // ", isKeyCodeTracked "+isKeyCodeTracked(keyCode)+", was: pressed "+isKeyPressed(keyCode)+", repeat "+isAutoRepeat+", [modifierKey "+isModifierKey+"] - "+System.currentTimeMillis());
+
+ if( !isAutoRepeat || !isModifierKey ) { // ! ( isModifierKey && isAutoRepeat )
+ switch(eventType) {
+ case KeyEvent.EVENT_KEY_PRESSED:
+ super.sendKeyEvent(KeyEvent.EVENT_KEY_PRESSED, modifiers, keyCode, keySym, keyChar);
+ break;
+
+ case KeyEvent.EVENT_KEY_RELEASED:
+ super.sendKeyEvent(KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, keySym, keyChar);
+ break;
+ }
+ }
+ }
+
+ @Override
+ public final void sendKeyEvent(final short eventType, final int modifiers, final short keyCode, final short keySym, final char keyChar) {
+ throw new InternalError("XXX: Adapt Java Code to Native Code Changes");
+ }
+ @Override
+ public final void enqueueKeyEvent(final boolean wait, final short eventType, final int modifiers, final short keyCode, final short keySym, final char keyChar) {
+ throw new InternalError("XXX: Adapt Java Code to Native Code Changes");
+ }
+
//----------------------------------------------------------------------
// Internals only
//
-
private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI
private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI
-
- private final long getDisplayEDTHandle() {
- return ((DisplayDriver) getScreen().getDisplay()).getEDTHandle();
- }
- private final <T> T runWithLockedDisplayHandle(DisplayRunnable<T> action) {
- return ((DisplayImpl) getScreen().getDisplay()).runWithLockedDisplayHandle(action);
- // return runWithTempDisplayHandle(action);
+
+ private final <T> T runWithLockedDisplayDevice(final DisplayRunnable<T> action) {
+ return ((DisplayDriver) getScreen().getDisplay()).runWithLockedDisplayDevice(action);
}
protected static native boolean initIDs0();
-
- 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);
- private native void CloseWindow0(long display, long windowHandle, long javaObjectAtom, long windowDeleteAtom);
+
+ private long CreateWindow(final long parentWindowHandle, final long display, final int screen_index,
+ final int visualID, final long javaObjectAtom, final long windowDeleteAtom,
+ final int x, final int y, final int width, final int height, final boolean autoPosition, final int flags,
+ final int pixelDataSize, final Buffer pixels) {
+ // NOTE: MUST BE DIRECT BUFFER, since _NET_WM_ICON Atom uses buffer directly!
+ if( !Buffers.isDirect(pixels) ) {
+ throw new IllegalArgumentException("data buffer is not direct "+pixels);
+ }
+ return CreateWindow0(parentWindowHandle, display, screen_index,
+ visualID, javaObjectAtom, windowDeleteAtom,
+ x, y, width, height, autoPosition, flags,
+ pixelDataSize,
+ pixels, Buffers.getDirectBufferByteOffset(pixels), true /* pixels_is_direct */);
+ }
+ 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 pixelDataSize, Object pixels, int pixels_byte_offset, boolean pixels_is_direct);
+ 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);
+ 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);
private static native void warpPointer0(long display, long windowHandle, int x, int y);
-
+
private long windowHandleClose;
+ private X11GraphicsDevice renderDevice;
}
diff --git a/src/newt/classes/jogamp/newt/event/NEWTEventTask.java b/src/newt/classes/jogamp/newt/event/NEWTEventTask.java
index 93d5e2fb9..2bdab2796 100644
--- a/src/newt/classes/jogamp/newt/event/NEWTEventTask.java
+++ b/src/newt/classes/jogamp/newt/event/NEWTEventTask.java
@@ -3,14 +3,14 @@
*
* 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
@@ -20,12 +20,12 @@
* 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.event;
import com.jogamp.newt.event.NEWTEvent;
@@ -35,18 +35,18 @@ import com.jogamp.newt.event.NEWTEvent;
* which notifies after sending the event for the <code>invokeAndWait()</code> semantics.
*/
public class NEWTEventTask {
- private NEWTEvent event;
- private Object notifyObject;
+ private final NEWTEvent event;
+ private final Object notifyObject;
private RuntimeException exception;
- public NEWTEventTask(NEWTEvent event, Object notifyObject) {
+ public NEWTEventTask(final NEWTEvent event, final Object notifyObject) {
this.event = event ;
this.notifyObject = notifyObject ;
this.exception = null;
}
public final NEWTEvent get() { return event; }
- public final void setException(RuntimeException e) { exception = e; }
+ public final void setException(final RuntimeException e) { exception = e; }
public final RuntimeException getException() { return exception; }
public final boolean isCallerWaiting() { return null != notifyObject; }
diff --git a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java
new file mode 100644
index 000000000..794e989a6
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java
@@ -0,0 +1,370 @@
+/**
+ * Copyright 2012 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.swt;
+
+import javax.media.nativewindow.NativeWindowException;
+
+import jogamp.newt.Debug;
+
+import com.jogamp.common.util.RunnableTask;
+import com.jogamp.newt.util.EDTUtil;
+
+/**
+ * Simple {@link EDTUtil} implementation utilizing the SWT UI thread
+ * of the given {@link Display}.
+ */
+public class SWTEDTUtil implements EDTUtil {
+ public static final boolean DEBUG = Debug.debug("EDT");
+
+ private final Object edtLock = new Object(); // locking the EDT start/stop state
+ private final ThreadGroup threadGroup;
+ private final String name;
+ private final Runnable dispatchMessages;
+ private final org.eclipse.swt.widgets.Display swtDisplay;
+ private NEDT nedt = null;
+ private int start_iter=0;
+ private static long pollPeriod = EDTUtil.defaultEDTPollPeriod;
+
+ public SWTEDTUtil(final com.jogamp.newt.Display newtDisplay, final org.eclipse.swt.widgets.Display swtDisplay) {
+ this.threadGroup = Thread.currentThread().getThreadGroup();
+ this.name=Thread.currentThread().getName()+"-SWTDisplay-"+newtDisplay.getFQName()+"-EDT-";
+ this.dispatchMessages = new Runnable() {
+ @Override
+ public void run() {
+ ((jogamp.newt.DisplayImpl) newtDisplay).dispatchMessages();
+ } };
+ this.swtDisplay = swtDisplay;
+ this.nedt = new NEDT(threadGroup, name);
+ this.nedt.setDaemon(true); // don't stop JVM from shutdown ..
+ }
+
+ public final org.eclipse.swt.widgets.Display getDisplay() {
+ return swtDisplay;
+ }
+
+ @Override
+ public long getPollPeriod() {
+ return pollPeriod;
+ }
+
+ @Override
+ public void setPollPeriod(final long ms) {
+ pollPeriod = ms; // writing to static field is intended
+ }
+
+ @Override
+ public final void start() throws IllegalStateException {
+ final boolean swtDisposed = swtDisplay.isDisposed();
+ synchronized(edtLock) {
+ if( nedt.isRunning() ) {
+ final Thread curT = Thread.currentThread();
+ final String swtTName;
+ final Thread swtT;
+ if( !swtDisposed ) {
+ swtT = swtDisplay.getThread();
+ swtTName = swtT.getName();
+ } else {
+ swtT = null;
+ swtTName = null;
+ }
+ final boolean onSWTEDT = swtT == curT;
+ throw new IllegalStateException("EDT still running and not subject to stop. Curr "+curT.getName()+
+ ", NEDT "+nedt.getName()+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop+", SWT-EDT "+swtTName+", on SWT-EDT "+onSWTEDT);
+ }
+ if(DEBUG) {
+ System.err.println(Thread.currentThread()+": SWT-EDT reset - edt: "+nedt+", swtDisposed (skipping) "+swtDisposed);
+ }
+ if( !swtDisposed ) {
+ if( nedt.getState() != Thread.State.NEW ) {
+ nedt = new NEDT(threadGroup, name);
+ nedt.setDaemon(true); // don't stop JVM from shutdown ..
+ }
+ startImpl();
+ }
+ }
+ if( !swtDisposed ) {
+ if( !nedt.isRunning() ) {
+ throw new RuntimeException("EDT could not be started: "+nedt);
+ }
+ } else {
+ // FIXME: Throw exception ?
+ }
+ }
+
+ private final void startImpl() {
+ if(nedt.isAlive()) {
+ throw new RuntimeException("SWT-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning+", shouldStop "+nedt.shouldStop+", edt: "+nedt);
+ }
+ start_iter++;
+ nedt.setName(name+start_iter);
+ if(DEBUG) {
+ System.err.println(Thread.currentThread()+": SWT-EDT START - edt: "+nedt);
+ // Thread.dumpStack();
+ }
+ nedt.start();
+ }
+
+ @Override
+ public boolean isCurrentThreadEDT() {
+ return !swtDisplay.isDisposed() && swtDisplay.getThread() == Thread.currentThread();
+ }
+
+ @Override
+ public final boolean isCurrentThreadNEDT() {
+ return nedt == Thread.currentThread();
+ }
+
+ @Override
+ public final boolean isCurrentThreadEDTorNEDT() {
+ final Thread ct = Thread.currentThread();
+ return ( !swtDisplay.isDisposed() && ct == swtDisplay.getThread() ) || ct == nedt ;
+ }
+
+ @Override
+ public boolean isRunning() {
+ return nedt.isRunning();
+ }
+
+ @Override
+ public final boolean invokeStop(final boolean wait, final Runnable task) {
+ return invokeImpl(wait, task, true);
+ }
+
+ @Override
+ public final boolean invoke(final boolean wait, final Runnable task) {
+ return invokeImpl(wait, task, false);
+ }
+
+ private final boolean invokeImpl(boolean wait, final Runnable task, boolean stop) {
+ Throwable throwable = null;
+ RunnableTask rTask = null;
+ final Object rTaskLock = new Object();
+ synchronized(rTaskLock) { // lock the optional task execution
+ synchronized(edtLock) { // lock the EDT status
+ if( nedt.shouldStop ) {
+ // drop task ..
+ if(DEBUG) {
+ System.err.println(Thread.currentThread()+": Warning: SWT-EDT about (1) to stop, won't enqueue new task: "+nedt+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop);
+ Thread.dumpStack();
+ }
+ return false;
+ }
+ if( swtDisplay.isDisposed() ) {
+ stop = true;
+ }
+
+ if( isCurrentThreadEDT() ) {
+ if(null != task) {
+ task.run();
+ }
+ wait = false; // running in same thread (EDT) -> no wait
+ if( stop ) {
+ nedt.shouldStop = true;
+ }
+ } else {
+ if( !nedt.isRunning && !swtDisplay.isDisposed() ) {
+ if( null != task ) {
+ if( stop ) {
+ System.err.println(Thread.currentThread()+": Warning: SWT-EDT is about (3) to stop and stopped already, dropping task. NEDT "+nedt);
+ } else {
+ System.err.println(Thread.currentThread()+": Warning: SWT-EDT is not running, dropping task. NEDT "+nedt);
+ }
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
+ }
+ return false;
+ } else if( stop ) {
+ if( nedt.isRunning ) {
+ if(DEBUG) {
+ System.err.println(Thread.currentThread()+": SWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop);
+ }
+ synchronized(nedt.sync) {
+ nedt.shouldStop = true;
+ nedt.sync.notifyAll(); // stop immediate if waiting (poll freq)
+ }
+ }
+ if( swtDisplay.isDisposed() ) {
+ System.err.println(Thread.currentThread()+": Warning: SWT-EDT is about (3) to stop and stopped already, dropping task. "+nedt);
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
+ return false;
+ }
+ }
+
+ if( null != task ) {
+ rTask = new RunnableTask(task,
+ wait ? rTaskLock : null,
+ true /* always catch and report Exceptions, don't disturb EDT */,
+ wait ? null : System.err);
+ swtDisplay.asyncExec(rTask);
+ }
+ }
+ }
+ if( wait ) {
+ try {
+ rTaskLock.wait(); // free lock, allow execution of rTask
+ } catch (final InterruptedException ie) {
+ throwable = ie;
+ }
+ if(null==throwable) {
+ throwable = rTask.getThrowable();
+ }
+ if(null!=throwable) {
+ if(throwable instanceof NativeWindowException) {
+ throw (NativeWindowException)throwable;
+ }
+ throw new RuntimeException(throwable);
+ }
+ }
+ return true;
+ }
+ }
+
+ @Override
+ final public boolean waitUntilIdle() {
+ final NEDT _nedt;
+ synchronized(edtLock) {
+ _nedt = nedt;
+ }
+ final Thread ct = Thread.currentThread();
+ if( !_nedt.isRunning || _nedt == ct || swtDisplay.isDisposed() || swtDisplay.getThread() == ct ) {
+ return false;
+ }
+ try {
+ swtDisplay.syncExec(new Runnable() {
+ @Override
+ public void run() { }
+ });
+ } catch (final Exception e) { }
+ return true;
+ }
+
+ @Override
+ final public boolean waitUntilStopped() {
+ synchronized(edtLock) {
+ final Thread curT = Thread.currentThread();
+ final Thread swtT = !swtDisplay.isDisposed() ? swtDisplay.getThread() : null;
+ final boolean onSWTEDT = swtT == curT;
+ if( nedt.isRunning && nedt != curT && !onSWTEDT ) {
+ while( nedt.isRunning ) {
+ try {
+ edtLock.wait();
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ class NEDT extends Thread {
+ volatile boolean shouldStop = false;
+ volatile boolean isRunning = false;
+ Object sync = new Object();
+
+ public NEDT(final ThreadGroup tg, final String name) {
+ super(tg, name);
+ }
+
+ final public boolean isRunning() {
+ return isRunning && !shouldStop;
+ }
+
+ @Override
+ final public void start() throws IllegalThreadStateException {
+ isRunning = true;
+ super.start();
+ }
+
+ /**
+ * Utilizing locking only on tasks and its execution,
+ * not for event dispatching.
+ */
+ @Override
+ final public void run() {
+ if(DEBUG) {
+ System.err.println(getName()+": SWT-EDT run() START "+ getName());
+ }
+ RuntimeException error = null;
+ try {
+ do {
+ // event dispatch
+ if(!shouldStop) {
+ // EDT invoke thread is SWT-EDT,
+ // hence dispatching is required to run on SWT-EDT as well.
+ // Otherwise a deadlock may happen due to dispatched event's
+ // triggering a locking action.
+ if ( !swtDisplay.isDisposed() ) {
+ swtDisplay.syncExec(dispatchMessages);
+ } else {
+ dispatchMessages.run();
+ }
+ }
+ // wait
+ synchronized(sync) {
+ if(!shouldStop) {
+ try {
+ sync.wait(pollPeriod);
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ } while(!shouldStop) ;
+ } catch (final Throwable t) {
+ // handle errors ..
+ shouldStop = true;
+ if(t instanceof RuntimeException) {
+ error = (RuntimeException) t;
+ } else {
+ error = new RuntimeException("Within SWT-EDT", t);
+ }
+ } finally {
+ if(DEBUG) {
+ System.err.println(getName()+": SWT-EDT run() END "+ getName()+", "+error);
+ }
+ synchronized(edtLock) {
+ isRunning = false;
+ edtLock.notifyAll();
+ }
+ if(DEBUG) {
+ System.err.println(getName()+": SWT-EDT run() EXIT "+ getName()+", exception: "+error);
+ }
+ if(null!=error) {
+ throw error;
+ }
+ } // finally
+ } // run()
+ } // EventDispatchThread
+
+}
diff --git a/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java b/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java
new file mode 100644
index 000000000..a989345dd
--- /dev/null
+++ b/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java
@@ -0,0 +1,396 @@
+/**
+ * Copyright 2012 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.swt.event;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeSurfaceHolder;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+import com.jogamp.newt.event.InputEvent;
+import com.jogamp.newt.event.MouseEvent;
+
+/**
+ * SWT event translator to NEWT, inclusive dispatch listener.
+ * <p>
+ * <b>Disclaimer:</b> This code is merely tested and subject to change.
+ * </p>
+ */
+public class SWTNewtEventFactory {
+
+ public static final short eventTypeSWT2NEWT(final int swtType) {
+ switch( swtType ) {
+ // case SWT.MouseXXX: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED;
+ case SWT.MouseDown: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED;
+ case SWT.MouseUp: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED;
+ case SWT.MouseMove: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_MOVED;
+ case SWT.MouseEnter: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_ENTERED;
+ case SWT.MouseExit: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_EXITED;
+ // case SWT.MouseXXX: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED;
+ case SWT.MouseVerticalWheel: return com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_WHEEL_MOVED;
+
+ case SWT.KeyDown: return com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED;
+ case SWT.KeyUp: return com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED;
+ }
+ return (short)0;
+ }
+
+ public static final int swtModifiers2Newt(final int awtMods, final boolean mouseHint) {
+ int newtMods = 0;
+ if ((awtMods & SWT.SHIFT) != 0) newtMods |= com.jogamp.newt.event.InputEvent.SHIFT_MASK;
+ if ((awtMods & SWT.CTRL) != 0) newtMods |= com.jogamp.newt.event.InputEvent.CTRL_MASK;
+ if ((awtMods & SWT.ALT) != 0) newtMods |= com.jogamp.newt.event.InputEvent.ALT_MASK;
+ return newtMods;
+ }
+
+ public static short swtKeyCode2NewtKeyCode(final int swtKeyCode) {
+ final short defNEWTKeyCode = (short)swtKeyCode;
+ switch (swtKeyCode) {
+ case SWT.HOME : return com.jogamp.newt.event.KeyEvent.VK_HOME;
+ case SWT.END : return com.jogamp.newt.event.KeyEvent.VK_END;
+ case SWT.PRINT_SCREEN : return com.jogamp.newt.event.KeyEvent.VK_PRINTSCREEN;
+ case SWT.BS : return com.jogamp.newt.event.KeyEvent.VK_BACK_SPACE;
+ case SWT.TAB : return com.jogamp.newt.event.KeyEvent.VK_TAB;
+ case SWT.LF : return com.jogamp.newt.event.KeyEvent.VK_ENTER;
+ case SWT.PAGE_DOWN : return com.jogamp.newt.event.KeyEvent.VK_PAGE_DOWN;
+ case SWT.PAGE_UP : return com.jogamp.newt.event.KeyEvent.VK_PAGE_UP;
+ case SWT.CONTROL : return com.jogamp.newt.event.KeyEvent.VK_CONTROL;
+ case SWT.CAPS_LOCK : return com.jogamp.newt.event.KeyEvent.VK_CAPS_LOCK;
+ case SWT.PAUSE : return com.jogamp.newt.event.KeyEvent.VK_PAUSE;
+ case SWT.SCROLL_LOCK : return com.jogamp.newt.event.KeyEvent.VK_SCROLL_LOCK;
+ case SWT.CANCEL : return com.jogamp.newt.event.KeyEvent.VK_CANCEL;
+ case SWT.INSERT : return com.jogamp.newt.event.KeyEvent.VK_INSERT;
+ case SWT.ESC : return com.jogamp.newt.event.KeyEvent.VK_ESCAPE;
+ case SWT.SPACE : return com.jogamp.newt.event.KeyEvent.VK_SPACE;
+ case SWT.F1 : return com.jogamp.newt.event.KeyEvent.VK_F1;
+ case SWT.F2 : return com.jogamp.newt.event.KeyEvent.VK_F2;
+ case SWT.F3 : return com.jogamp.newt.event.KeyEvent.VK_F3;
+ case SWT.F4 : return com.jogamp.newt.event.KeyEvent.VK_F4;
+ case SWT.F5 : return com.jogamp.newt.event.KeyEvent.VK_F5;
+ case SWT.F6 : return com.jogamp.newt.event.KeyEvent.VK_F6;
+ case SWT.F7 : return com.jogamp.newt.event.KeyEvent.VK_F7;
+ case SWT.F8 : return com.jogamp.newt.event.KeyEvent.VK_F8;
+ case SWT.F9 : return com.jogamp.newt.event.KeyEvent.VK_F9;
+ case SWT.F10 : return com.jogamp.newt.event.KeyEvent.VK_F10;
+ case SWT.F11 : return com.jogamp.newt.event.KeyEvent.VK_F11;
+ case SWT.F12 : return com.jogamp.newt.event.KeyEvent.VK_F12;
+ case SWT.F13 : return com.jogamp.newt.event.KeyEvent.VK_F13;
+ case SWT.F14 : return com.jogamp.newt.event.KeyEvent.VK_F14;
+ case SWT.F15 : return com.jogamp.newt.event.KeyEvent.VK_F15;
+ case SWT.F16 : return com.jogamp.newt.event.KeyEvent.VK_F16;
+ case SWT.F17 : return com.jogamp.newt.event.KeyEvent.VK_F17;
+ case SWT.F18 : return com.jogamp.newt.event.KeyEvent.VK_F18;
+ case SWT.F19 : return com.jogamp.newt.event.KeyEvent.VK_F19;
+ case SWT.F20 : return com.jogamp.newt.event.KeyEvent.VK_F20;
+ case SWT.DEL : return com.jogamp.newt.event.KeyEvent.VK_DELETE;
+ case SWT.KEYPAD_0 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD0;
+ case SWT.KEYPAD_1 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD1;
+ case SWT.KEYPAD_2 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD2;
+ case SWT.KEYPAD_3 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD3;
+ case SWT.KEYPAD_4 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD4;
+ case SWT.KEYPAD_5 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD5;
+ case SWT.KEYPAD_6 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD6;
+ case SWT.KEYPAD_7 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD7;
+ case SWT.KEYPAD_8 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD8;
+ case SWT.KEYPAD_9 : return com.jogamp.newt.event.KeyEvent.VK_NUMPAD9;
+ case SWT.KEYPAD_DECIMAL: return com.jogamp.newt.event.KeyEvent.VK_DECIMAL;
+ case SWT.KEYPAD_ADD : return com.jogamp.newt.event.KeyEvent.VK_ADD;
+ case SWT.KEYPAD_SUBTRACT: return com.jogamp.newt.event.KeyEvent.VK_SUBTRACT;
+ case SWT.KEYPAD_MULTIPLY: return com.jogamp.newt.event.KeyEvent.VK_MULTIPLY;
+ case SWT.KEYPAD_DIVIDE : return com.jogamp.newt.event.KeyEvent.VK_DIVIDE;
+ case SWT.NUM_LOCK : return com.jogamp.newt.event.KeyEvent.VK_NUM_LOCK;
+ case SWT.ARROW_LEFT : return com.jogamp.newt.event.KeyEvent.VK_LEFT;
+ case SWT.ARROW_UP : return com.jogamp.newt.event.KeyEvent.VK_UP;
+ case SWT.ARROW_RIGHT : return com.jogamp.newt.event.KeyEvent.VK_RIGHT;
+ case SWT.ARROW_DOWN : return com.jogamp.newt.event.KeyEvent.VK_DOWN;
+ case SWT.HELP : return com.jogamp.newt.event.KeyEvent.VK_HELP;
+ }
+ return defNEWTKeyCode;
+ }
+
+ public static int newtKeyCode2SWTKeyCode(final short newtKeyCode) {
+ final int defSWTKeyCode = 0xFFFF & newtKeyCode;
+ switch (newtKeyCode) {
+ case com.jogamp.newt.event.KeyEvent.VK_HOME : return SWT.HOME;
+ case com.jogamp.newt.event.KeyEvent.VK_END : return SWT.END;
+ case com.jogamp.newt.event.KeyEvent.VK_PRINTSCREEN : return SWT.PRINT_SCREEN;
+ case com.jogamp.newt.event.KeyEvent.VK_BACK_SPACE : return SWT.BS;
+ case com.jogamp.newt.event.KeyEvent.VK_TAB : return SWT.TAB;
+ case com.jogamp.newt.event.KeyEvent.VK_ENTER : return SWT.LF;
+ case com.jogamp.newt.event.KeyEvent.VK_PAGE_DOWN : return SWT.PAGE_DOWN;
+ case com.jogamp.newt.event.KeyEvent.VK_PAGE_UP : return SWT.PAGE_UP;
+ case com.jogamp.newt.event.KeyEvent.VK_CONTROL : return SWT.CONTROL;
+ case com.jogamp.newt.event.KeyEvent.VK_CAPS_LOCK : return SWT.CAPS_LOCK;
+ case com.jogamp.newt.event.KeyEvent.VK_PAUSE : return SWT.PAUSE;
+ case com.jogamp.newt.event.KeyEvent.VK_SCROLL_LOCK : return SWT.SCROLL_LOCK;
+ case com.jogamp.newt.event.KeyEvent.VK_CANCEL : return SWT.CANCEL;
+ case com.jogamp.newt.event.KeyEvent.VK_INSERT : return SWT.INSERT;
+ case com.jogamp.newt.event.KeyEvent.VK_ESCAPE : return SWT.ESC;
+ case com.jogamp.newt.event.KeyEvent.VK_SPACE : return SWT.SPACE;
+ case com.jogamp.newt.event.KeyEvent.VK_F1 : return SWT.F1;
+ case com.jogamp.newt.event.KeyEvent.VK_F2 : return SWT.F2;
+ case com.jogamp.newt.event.KeyEvent.VK_F3 : return SWT.F3;
+ case com.jogamp.newt.event.KeyEvent.VK_F4 : return SWT.F4;
+ case com.jogamp.newt.event.KeyEvent.VK_F5 : return SWT.F5;
+ case com.jogamp.newt.event.KeyEvent.VK_F6 : return SWT.F6;
+ case com.jogamp.newt.event.KeyEvent.VK_F7 : return SWT.F7;
+ case com.jogamp.newt.event.KeyEvent.VK_F8 : return SWT.F8;
+ case com.jogamp.newt.event.KeyEvent.VK_F9 : return SWT.F9;
+ case com.jogamp.newt.event.KeyEvent.VK_F10 : return SWT.F10;
+ case com.jogamp.newt.event.KeyEvent.VK_F11 : return SWT.F11;
+ case com.jogamp.newt.event.KeyEvent.VK_F12 : return SWT.F12;
+ case com.jogamp.newt.event.KeyEvent.VK_F13 : return SWT.F13;
+ case com.jogamp.newt.event.KeyEvent.VK_F14 : return SWT.F14;
+ case com.jogamp.newt.event.KeyEvent.VK_F15 : return SWT.F15;
+ case com.jogamp.newt.event.KeyEvent.VK_F16 : return SWT.F16;
+ case com.jogamp.newt.event.KeyEvent.VK_F17 : return SWT.F17;
+ case com.jogamp.newt.event.KeyEvent.VK_F18 : return SWT.F18;
+ case com.jogamp.newt.event.KeyEvent.VK_F19 : return SWT.F19;
+ case com.jogamp.newt.event.KeyEvent.VK_F20 : return SWT.F20;
+ case com.jogamp.newt.event.KeyEvent.VK_DELETE : return SWT.DEL;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD0 : return SWT.KEYPAD_0;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD1 : return SWT.KEYPAD_1;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD2 : return SWT.KEYPAD_2;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD3 : return SWT.KEYPAD_3;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD4 : return SWT.KEYPAD_4;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD5 : return SWT.KEYPAD_5;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD6 : return SWT.KEYPAD_6;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD7 : return SWT.KEYPAD_7;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD8 : return SWT.KEYPAD_8;
+ case com.jogamp.newt.event.KeyEvent.VK_NUMPAD9 : return SWT.KEYPAD_9;
+ case com.jogamp.newt.event.KeyEvent.VK_DECIMAL : return SWT.KEYPAD_DECIMAL;
+ case com.jogamp.newt.event.KeyEvent.VK_ADD : return SWT.KEYPAD_ADD;
+ case com.jogamp.newt.event.KeyEvent.VK_SUBTRACT : return SWT.KEYPAD_SUBTRACT;
+ case com.jogamp.newt.event.KeyEvent.VK_MULTIPLY : return SWT.KEYPAD_MULTIPLY;
+ case com.jogamp.newt.event.KeyEvent.VK_DIVIDE : return SWT.KEYPAD_DIVIDE;
+ case com.jogamp.newt.event.KeyEvent.VK_NUM_LOCK : return SWT.NUM_LOCK;
+ case com.jogamp.newt.event.KeyEvent.VK_LEFT : return SWT.ARROW_LEFT;
+ case com.jogamp.newt.event.KeyEvent.VK_UP : return SWT.ARROW_UP;
+ case com.jogamp.newt.event.KeyEvent.VK_RIGHT : return SWT.ARROW_RIGHT;
+ case com.jogamp.newt.event.KeyEvent.VK_DOWN : return SWT.ARROW_DOWN;
+ case com.jogamp.newt.event.KeyEvent.VK_HELP : return SWT.HELP;
+ }
+ return defSWTKeyCode;
+ }
+
+
+ public static final com.jogamp.newt.event.InputEvent createInputEvent(final org.eclipse.swt.widgets.Event event, final NativeSurfaceHolder sourceHolder) {
+ com.jogamp.newt.event.InputEvent res = createMouseEvent(event, sourceHolder);
+ if(null == res) {
+ res = createKeyEvent(event, sourceHolder);
+ }
+ return res;
+ }
+
+ public static final com.jogamp.newt.event.MouseEvent createMouseEvent(final org.eclipse.swt.widgets.Event event, final NativeSurfaceHolder sourceHolder) {
+ switch(event.type) {
+ case SWT.MouseDown:
+ case SWT.MouseUp:
+ case SWT.MouseMove:
+ case SWT.MouseEnter:
+ case SWT.MouseExit:
+ case SWT.MouseVerticalWheel:
+ break;
+ default:
+ return null;
+ }
+ final short type = eventTypeSWT2NEWT(event.type);
+ if( (short)0 != type ) {
+ float rotation = 0;
+ if (SWT.MouseVerticalWheel == event.type) {
+ // SWT/NEWT rotation is reversed - AWT +1 is down, NEWT +1 is up.
+ // rotation = -1 * (int) event.rotation;
+ rotation = (float) event.rotation;
+ }
+
+ int mods = swtModifiers2Newt(event.stateMask, true);
+
+ final NativeSurface source = sourceHolder.getNativeSurface();
+ final int[] pixelPos;
+ if( null != source ) {
+ if( source instanceof com.jogamp.newt.Window) {
+ final com.jogamp.newt.Window newtSource = (com.jogamp.newt.Window)source;
+ if(newtSource.isPointerConfined()) {
+ mods |= InputEvent.CONFINED_MASK;
+ }
+ if(!newtSource.isPointerVisible()) {
+ mods |= InputEvent.INVISIBLE_MASK;
+ }
+ }
+ pixelPos = source.convertToPixelUnits(new int[] { event.x, event.y });
+ } else {
+ pixelPos = new int[] { event.x, event.y };
+ }
+
+ return new com.jogamp.newt.event.MouseEvent(
+ type, sourceHolder, (0xFFFFFFFFL & event.time),
+ mods, pixelPos[0], pixelPos[1], (short)event.count, (short)event.button, MouseEvent.getRotationXYZ(rotation, mods), 1f);
+ }
+ return null; // no mapping ..
+ }
+
+ public static final com.jogamp.newt.event.KeyEvent createKeyEvent(final org.eclipse.swt.widgets.Event event, final NativeSurfaceHolder sourceHolder) {
+ switch(event.type) {
+ case SWT.KeyDown:
+ case SWT.KeyUp:
+ break;
+ default:
+ return null;
+ }
+ final short type = eventTypeSWT2NEWT(event.type);
+ if( (short)0 != type ) {
+ final short newtKeyCode = swtKeyCode2NewtKeyCode( event.keyCode );
+ return com.jogamp.newt.event.KeyEvent.create(
+ type, sourceHolder, (0xFFFFFFFFL & event.time),
+ swtModifiers2Newt(event.stateMask, false),
+ newtKeyCode, newtKeyCode, event.character);
+ }
+ return null; // no mapping ..
+ }
+
+ //
+ //
+ //
+
+ short dragButtonDown = 0;
+
+ public SWTNewtEventFactory() {
+ resetButtonsDown();
+ }
+
+ final void resetButtonsDown() {
+ dragButtonDown = 0;
+ }
+
+ public final boolean dispatchMouseEvent(final org.eclipse.swt.widgets.Event event, final NativeSurfaceHolder sourceHolder, final com.jogamp.newt.event.MouseListener l) {
+ final com.jogamp.newt.event.MouseEvent res = createMouseEvent(event, sourceHolder);
+ if(null != res) {
+ if(null != l) {
+ switch(event.type) {
+ case SWT.MouseDown:
+ dragButtonDown = (short) event.button;
+ l.mousePressed(res); break;
+ case SWT.MouseUp:
+ dragButtonDown = 0;
+ l.mouseReleased(res);
+ {
+ final com.jogamp.newt.event.MouseEvent res2 = new com.jogamp.newt.event.MouseEvent(
+ com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED,
+ res.getSource(),
+ res.getWhen(), res.getModifiers(),
+ res.getX(), res.getY(), res.getClickCount(),
+ res.getButton(), res.getRotation(), res.getRotationScale());
+ l.mouseClicked(res2);
+ }
+ break;
+ case SWT.MouseMove:
+ if( 0 < dragButtonDown ) {
+ final com.jogamp.newt.event.MouseEvent res2 = new com.jogamp.newt.event.MouseEvent(
+ com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED,
+ res.getSource(),
+ res.getWhen(), res.getModifiers(),
+ res.getX(), res.getY(), res.getClickCount(),
+ dragButtonDown, res.getRotation(), res.getRotationScale());
+ l.mouseDragged( res2 );
+ } else {
+ l.mouseMoved(res);
+ }
+ break;
+ case SWT.MouseEnter:
+ l.mouseEntered(res);
+ break;
+ case SWT.MouseExit:
+ resetButtonsDown();
+ l.mouseExited(res);
+ break;
+ case SWT.MouseVerticalWheel:
+ l.mouseWheelMoved(res);
+ break;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public final boolean dispatchKeyEvent(final org.eclipse.swt.widgets.Event event, final NativeSurfaceHolder sourceHolder, final com.jogamp.newt.event.KeyListener l) {
+ final com.jogamp.newt.event.KeyEvent res = createKeyEvent(event, sourceHolder);
+ if(null != res) {
+ if(null != l) {
+ switch(event.type) {
+ case SWT.KeyDown:
+ l.keyPressed(res);
+ break;
+ case SWT.KeyUp:
+ l.keyReleased(res);
+ break;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public final void attachDispatchListener(final org.eclipse.swt.widgets.Control ctrl, final NativeSurfaceHolder sourceHolder,
+ final com.jogamp.newt.event.MouseListener ml,
+ final com.jogamp.newt.event.KeyListener kl) {
+ if(null==ctrl) {
+ throw new IllegalArgumentException("Argument ctrl is null");
+ }
+ if(null==sourceHolder) {
+ throw new IllegalArgumentException("Argument source is null");
+ }
+
+ if( null != ml ) {
+ final Listener listener = new Listener () {
+ @Override
+ public void handleEvent (final Event event) {
+ dispatchMouseEvent( event, sourceHolder, ml );
+ } };
+ ctrl.addListener(SWT.MouseDown, listener);
+ ctrl.addListener(SWT.MouseUp, listener);
+ ctrl.addListener(SWT.MouseMove, listener);
+ ctrl.addListener(SWT.MouseEnter, listener);
+ ctrl.addListener(SWT.MouseExit, listener);
+ ctrl.addListener(SWT.MouseVerticalWheel, listener);
+ }
+ if( null != kl ) {
+ final Listener listener = new Listener () {
+ @Override
+ public void handleEvent (final Event event) {
+ dispatchKeyEvent( event, sourceHolder, kl );
+ } };
+ ctrl.addListener(SWT.KeyDown, listener);
+ ctrl.addListener(SWT.KeyUp, listener);
+ }
+ }
+}
+