diff options
author | Sven Gothel <[email protected]> | 2014-05-26 18:54:27 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-05-26 18:54:27 +0200 |
commit | 56d60b36798fa8dae48bf2aa5e2de6f3178ab0d1 (patch) | |
tree | 4c86190128414205d0b768780e3272e32bd1e81a /src/newt | |
parent | 98ed02cdb7b325d8afde596a5ef04f97be2018d4 (diff) |
Bug 741 HiDPI: Refine Monitor/Screen [virtual] Viewport Definition / Add NEWT Support / Fix JAWT getPixelScale deadlock
- NativeWindow/Surface/NEWT API DOC: Define Coordinate System of Window and Screen
- OSXUtil: Add getPixelScale(..) via Screen index and 'windowOrView'
- JAWTWindow/JAWTUtil.getPixelScale(..): Use pre-fetched AWT GraphicsConfiguration to solve AWT-TreeLock (deadlock)
- [Virtual] Viewport of MonitorDevice and Screen:
- Properly calculate and expose [virtual] viewport in window and pixel units
- OSX Monitor viewports in pixel units are 'reconstructed'
- Window/Viewport to Monitor selection shall be perfomed via window units (unique)
- OSX NEWT Window create/init (native): Use given size and coordinates even in fullscreen mode
Don't override by quering NSScreen coordinates, trust given values.
- Fix test cases, i.e. usage of pixel- and window-units
Diffstat (limited to 'src/newt')
25 files changed, 593 insertions, 262 deletions
diff --git a/src/newt/classes/com/jogamp/newt/MonitorDevice.java b/src/newt/classes/com/jogamp/newt/MonitorDevice.java index af0ce0146..8e5d305dd 100644 --- a/src/newt/classes/com/jogamp/newt/MonitorDevice.java +++ b/src/newt/classes/com/jogamp/newt/MonitorDevice.java @@ -52,6 +52,9 @@ import com.jogamp.common.util.ArrayHashSet; * <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 @@ -61,16 +64,18 @@ public abstract class MonitorDevice { 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 viewport; + protected Rectangle viewportPU; // in pixel units + protected Rectangle viewportWU; // in window units - protected MonitorDevice(Screen screen, int nativeId, DimensionImmutable sizeMM, Rectangle viewport, MonitorMode currentMode, ArrayHashSet<MonitorMode> supportedModes) { + protected MonitorDevice(Screen screen, int nativeId, DimensionImmutable sizeMM, Rectangle viewportPU, Rectangle viewportWU, MonitorMode currentMode, ArrayHashSet<MonitorMode> supportedModes) { this.screen = screen; this.nativeId = nativeId; this.sizeMM = sizeMM; this.originalMode = currentMode; this.supportedModes = supportedModes; this.currentMode = currentMode; - this.viewport = viewport; + this.viewportPU = viewportPU; + this.viewportWU = viewportWU; this.modeChanged = false; } @@ -170,11 +175,22 @@ public abstract class MonitorDevice { /** * Returns the {@link RectangleImmutable rectangular} portion - * of the rotated virtual {@link Screen} size in pixel units - * represented by this monitor. + * 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 viewport; + 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; } /** @@ -184,46 +200,45 @@ public abstract class MonitorDevice { * @param y y-coord in pixel units */ public final boolean contains(final int x, final int y) { - return x >= viewport.getX() && - x < viewport.getX() + viewport.getWidth() && - y >= viewport.getY() && - y < viewport.getY() + viewport.getHeight() ; + return x >= viewportPU.getX() && + x < viewportPU.getX() + viewportPU.getWidth() && + y >= viewportPU.getY() && + y < viewportPU.getY() + viewportPU.getHeight() ; } /** - * Returns the coverage of given rectangle in pixel units - * w/ this {@link #getViewport() viewport}, i.e. between <code>0.0</code> and <code>1.0</code>. - * <p> - * Coverage is computed by: - * <pre> - * isect = viewport.intersection(r); - * coverage = area( isect ) / area( viewport ) ; - * </pre> - * </p> - * @param r {@link RectangleImmutable rectangle} in pixel units - */ - public final float coverage(final RectangleImmutable r) { - return viewport.coverage(r); - } - - /** - * Returns the union of the given monitor's {@link #getViewport() viewport} in pixel units. - * @param result storage for result, will be returned + * 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 - * @return viewport representing the union of given monitor's viewport in pixel units, i.e. result storage for chaining */ - public static Rectangle unionOfViewports(final Rectangle result, final List<MonitorDevice> monitors) { - int x1=Integer.MAX_VALUE, y1=Integer.MAX_VALUE; - int x2=Integer.MIN_VALUE, y2=Integer.MIN_VALUE; + 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--) { - final RectangleImmutable vp = monitors.get(i).getViewport(); - x1 = Math.min(x1, vp.getX()); - x2 = Math.max(x2, vp.getX() + vp.getWidth()); - y1 = Math.min(y1, vp.getY()); - y2 = Math.max(y2, vp.getY() + vp.getHeight()); + 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); } - result.set(x1, y1, x2 - x1, y2 - y1); - return result; } public final boolean isOriginalMode() { @@ -247,6 +262,7 @@ public abstract class MonitorDevice { * <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; @@ -257,6 +273,7 @@ public abstract class MonitorDevice { * <p> * The returned {@link MonitorMode} is element of the lists {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}. * </p> + * @see #getCurrentMode() */ public abstract MonitorMode queryCurrentMode(); @@ -269,7 +286,7 @@ public abstract class MonitorDevice { @Override public String toString() { - return "Monitor[Id "+Display.toHexString(nativeId)+", "+sizeMM+" mm, viewport "+viewport+ ", orig "+originalMode+", curr "+currentMode+ + 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/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java index 919b98b45..cef254634 100644 --- a/src/newt/classes/com/jogamp/newt/Screen.java +++ b/src/newt/classes/com/jogamp/newt/Screen.java @@ -28,12 +28,14 @@ package com.jogamp.newt; 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; @@ -41,7 +43,18 @@ 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 { /** @@ -131,11 +144,15 @@ public abstract class Screen { public abstract int getIndex(); /** + * 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(); /** + * 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(); @@ -151,20 +168,20 @@ public abstract class Screen { public abstract int getHeight(); /** - * @return the <b>rotated</b> virtual viewport, i.e. origin and size in pixel units. - * @see #getViewportInWindowUnits(Window) + * 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(); /** - * Returns a newly created {@link Rectangle} containing the <b>rotated</b> virtual viewport - * in window units of the given {@link Window} instance. - * @return rotated viewport values, i.e. origin and size, in pixel units. + * 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 final Rectangle getViewportInWindowUnits(final Window win) { - return win.convertToWindowUnits( (Rectangle) getViewport().cloneMutable() ); - } + public abstract RectangleImmutable getViewportInWindowUnits(); /** * @return the associated Display @@ -192,12 +209,12 @@ public abstract class Screen { public abstract List<MonitorDevice> getMonitorDevices(); /** - * Returns the {@link MonitorDevice} with the highest {@link MonitorDevice#getViewport() viewport} - * {@link MonitorDevice#coverage(RectangleImmutable) coverage} of the given rectangle in pixel units. + * 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 no coverage is detected the first {@link MonitorDevice} is returned. * </p> - * @param r arbitrary rectangle in pixel units + * @param r arbitrary rectangle in window units */ public final MonitorDevice getMainMonitor(final RectangleImmutable r) { MonitorDevice res = null; @@ -205,7 +222,7 @@ public abstract class Screen { final List<MonitorDevice> monitors = getMonitorDevices(); for(int i=monitors.size()-1; i>=0; i--) { final MonitorDevice monitor = monitors.get(i); - final float coverage = monitor.coverage(r); + final float coverage = monitor.getViewportInWindowUnits().coverage(r); if( coverage > maxCoverage ) { maxCoverage = coverage; res = monitor; @@ -218,15 +235,16 @@ public abstract class Screen { } /** - * Returns the union of all monitor's {@link MonitorDevice#getViewport() viewport} in pixel units. + * 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 result storage for result, will be returned + * @param viewport storage for result in pixel units, maybe null + * @param viewportInWindowUnits storage for result in window units, maybe null */ - public final Rectangle unionOfMonitorViewportSize(final Rectangle result) { - return MonitorDevice.unionOfViewports(result, getMonitorDevices()); + public final void unionOfMonitorViewports(final Rectangle viewport, final Rectangle viewportInWindowUnits) { + MonitorDevice.unionOfViewports(viewport, viewportInWindowUnits, getMonitorDevices()); } /** diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index 872d67087..57fcb626d 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -46,7 +46,6 @@ import javax.media.nativewindow.CapabilitiesChooser; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.WindowClosingProtocol; -import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.Rectangle; import javax.media.nativewindow.util.RectangleImmutable; @@ -65,6 +64,20 @@ import javax.media.nativewindow.util.RectangleImmutable; * 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>, @@ -108,8 +121,8 @@ public interface Window extends NativeWindow, WindowClosingProtocol { Screen getScreen(); /** - * Returns the {@link MonitorDevice} which {@link MonitorDevice#getViewport() viewport} - * {@link MonitorDevice#coverage(RectangleImmutable) covers} this window the most. + * 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> @@ -242,6 +255,10 @@ public interface Window extends NativeWindow, WindowClosingProtocol { /** * Returns a newly created {@link Rectangle} containing the scaled window origin, {@link #getX()} & {@link #getY()}, * and size, {@link #getSurfaceWidth()} & {@link #getSurfaceHeight()}, in pixel units. + * + * @deprecated The returned position in pixel units might be erroneous in case of multiple monitor setup where a mixed pixel-scale exist, + * since this method currently does not take the monitor viewport and each of it's pixel-scale into account (expensive). + * Either we fix this issue or remove this method at a later time. */ Rectangle getSurfaceBounds(); diff --git a/src/newt/classes/jogamp/newt/MonitorDeviceImpl.java b/src/newt/classes/jogamp/newt/MonitorDeviceImpl.java index 9e10879c4..e9e41a0ef 100644 --- a/src/newt/classes/jogamp/newt/MonitorDeviceImpl.java +++ b/src/newt/classes/jogamp/newt/MonitorDeviceImpl.java @@ -38,8 +38,8 @@ import com.jogamp.newt.Screen; public class MonitorDeviceImpl extends MonitorDevice { - public MonitorDeviceImpl(ScreenImpl screen, int nativeId, DimensionImmutable sizeMM, Rectangle viewport, MonitorMode currentMode, ArrayHashSet<MonitorMode> supportedModes) { - super(screen, nativeId, sizeMM, viewport, currentMode, supportedModes); + public MonitorDeviceImpl(ScreenImpl screen, int nativeId, DimensionImmutable sizeMM, Rectangle viewportPU, Rectangle viewportWU, MonitorMode currentMode, ArrayHashSet<MonitorMode> supportedModes) { + super(screen, nativeId, sizeMM, viewportPU, viewportWU, currentMode, supportedModes); } @Override @@ -136,11 +136,10 @@ public class MonitorDeviceImpl extends MonitorDevice { this.currentMode = currentMode; } - /* pp */ final void setViewportValue(Rectangle viewport) { - this.viewport = viewport; - } + /* pp */ final Rectangle getMutuableViewportPU() { return viewportPU; } + /* pp */ final Rectangle getMutuableViewportWU() { return viewportWU; } - /* pp */ ArrayHashSet<MonitorMode> getSupportedModesImpl() { + /* 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 index 9d8f4919c..55cbf77f3 100644 --- a/src/newt/classes/jogamp/newt/MonitorModeProps.java +++ b/src/newt/classes/jogamp/newt/MonitorModeProps.java @@ -81,9 +81,10 @@ public class MonitorModeProps { ; /** WARNING: must be synchronized with ScreenMode.h, native implementation - * 10: count + id, ScreenSizeMM[width, height], rotated Viewport[x, y, width, height], currentMonitorModeId, rotation, supportedModeId+ + * 15: count + id, ScreenSizeMM[width, height], rotated Viewport pixel-units, rotated viewport window-units, currentMonitorModeId, rotation, supportedModeId+ + * Viewport := [x, y, width, height] (4 elements) */ - public static final int MIN_MONITOR_DEVICE_PROPERTIES = 11; + public static final int MIN_MONITOR_DEVICE_PROPERTIES = 15; public static final int IDX_MONITOR_DEVICE_VIEWPORT = 1 // count + 1 // native mode @@ -223,7 +224,8 @@ public class MonitorModeProps { final List<MonitorMode> allMonitorModes = cache.monitorModes.getData(); final int id = monitorProperties[offset++]; final DimensionImmutable sizeMM = streamInResolution(monitorProperties, offset); offset+=NUM_RESOLUTION_PROPERTIES; - final Rectangle viewport = new Rectangle(monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++]); + 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++]; @@ -240,7 +242,7 @@ public class MonitorModeProps { } } } - MonitorDevice monitorDevice = new MonitorDeviceImpl(screen, id, sizeMM, viewport, currentMode, supportedModes); + MonitorDevice monitorDevice = new MonitorDeviceImpl(screen, id, sizeMM, viewportPU, viewportWU, currentMode, supportedModes); if(null!=cache) { monitorDevice = cache.monitorDevices.getOrAdd(monitorDevice); } @@ -296,8 +298,9 @@ public class MonitorModeProps { offset++; final int id = monitorProperties[offset++]; final DimensionImmutable sizeMM = streamInResolution(monitorProperties, offset); offset+=NUM_RESOLUTION_PROPERTIES; - final Rectangle viewport = new Rectangle(monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++]); - MonitorDevice monitorDevice = new MonitorDeviceImpl(screen, id, sizeMM, viewport, currentMode, supportedModes); + 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); } @@ -328,6 +331,10 @@ public class MonitorModeProps { 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(); diff --git a/src/newt/classes/jogamp/newt/ScreenImpl.java b/src/newt/classes/jogamp/newt/ScreenImpl.java index d7e6c641c..949e7fa3b 100644 --- a/src/newt/classes/jogamp/newt/ScreenImpl.java +++ b/src/newt/classes/jogamp/newt/ScreenImpl.java @@ -81,10 +81,11 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { protected int hashCode; protected AbstractGraphicsScreen aScreen; protected int refCount; // number of Screen references by Window - protected Rectangle vOriginSize = new Rectangle(0, 0, 0, 0); // virtual rotated screen origin and 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<MonitorModeListener> refMonitorModeListener = new ArrayList<MonitorModeListener>(); + private final ArrayList<MonitorModeListener> refMonitorModeListener = new ArrayList<MonitorModeListener>(); private long tCreated; // creationTime @@ -130,6 +131,7 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { screen.screen_idx = idx; screen.fqname = display.getFQName()+"-s"+idx; screen.hashCode = screen.fqname.hashCode(); + screen.instantiationFinished(); Screen.addScreen2List(screen); if(DEBUG) { System.err.println("Screen.create() NEW: "+screen+" "+Display.getThreadName()); @@ -141,6 +143,14 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { } } + /** + * 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) { if (obj == null) { @@ -260,19 +270,20 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { 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 MonitorMode has been set or changed, * hence you may utilize it. * </p> * <p> * Default implementation uses the union of all monitor's viewport, - * calculated via {@link #unionOfMonitorViewportSize()}. + * calculated via {@link #unionOfMonitorViewportSize()}, however driver impl. may chose a different methodology. * </p> - * @param vOriginSize storage for result + * @param viewport storage for result in pixel units + * @param viewportInWindowUnits storage for result in window units */ - protected void calcVirtualScreenOriginAndSize(final Rectangle vOriginSize) { - unionOfMonitorViewportSize(vOriginSize); + protected void calcVirtualScreenOriginAndSize(final Rectangle viewport, final Rectangle viewportInWindowUnits) { + unionOfMonitorViewports(viewport, viewportInWindowUnits); } @Override @@ -281,18 +292,19 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { } /** - * 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() { if(null != usrSize ) { - vOriginSize.set(0, 0, usrSize.getWidth(), usrSize.getHeight()); + 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()+": "+vOriginSize); + System.err.println("Update user virtual screen viewport @ "+Thread.currentThread().getName()+": "+virtViewportPU); } } else { - calcVirtualScreenOriginAndSize(vOriginSize); + calcVirtualScreenOriginAndSize(virtViewportPU, virtViewportWU); if(DEBUG) { - System.err.println("Updated virtual screen viewport @ "+Thread.currentThread().getName()+": "+vOriginSize); + System.err.println("Updated virtual screen viewport @ "+Thread.currentThread().getName()+": "+virtViewportPU+" [pixel], "+virtViewportWU+" [window]"); } } } @@ -318,19 +330,21 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { } @Override - public final int getX() { return vOriginSize.getX(); } + public final int getX() { return virtViewportPU.getX(); } @Override - public final int getY() { return vOriginSize.getY(); } + public final int getY() { return virtViewportPU.getY(); } @Override - public final int getWidth() { return vOriginSize.getWidth(); } + public final int getWidth() { return virtViewportPU.getWidth(); } @Override - public final int getHeight() { return vOriginSize.getHeight(); } + public final int getHeight() { return virtViewportPU.getHeight(); } @Override - public final RectangleImmutable getViewport() { return vOriginSize; } + 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+", vsize "+vOriginSize+", "+aScreen+", "+display+ + return "NEWT-Screen["+getFQName()+", idx "+screen_idx+", refCount "+refCount+", vsize "+virtViewportPU+" [pixels], "+virtViewportWU+" [window], "+aScreen+", "+display+ ", monitors: "+getMonitorDevices()+"]"; } @@ -357,7 +371,10 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { */ protected abstract void collectNativeMonitorModesAndDevicesImpl(MonitorModeProps.Cache cache); - protected Rectangle getNativeMonitorDeviceViewportImpl(MonitorDevice monitor) { return null; } + protected boolean updateNativeMonitorDeviceViewportImpl(final MonitorDevice monitor, + final Rectangle viewportPU, final Rectangle viewportWU) { + return false; + } /** * To be implemented by the native specification.<br> @@ -402,7 +419,7 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { System.err.println("monitorModeChangeNotify @ "+Thread.currentThread().getName()+": "+me); } for(int i=0; i<refMonitorModeListener.size(); i++) { - ((MonitorModeListener)refMonitorModeListener.get(i)).monitorModeChangeNotify(me); + refMonitorModeListener.get(i).monitorModeChangeNotify(me); } } @@ -410,12 +427,9 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { final List<MonitorDevice> monitors = getMonitorDevices(); for(int i=monitors.size()-1; i>=0; i--) { final MonitorDeviceImpl monitor = (MonitorDeviceImpl) monitors.get(i); - final Rectangle newViewport = getNativeMonitorDeviceViewportImpl(monitor); + final boolean viewportUpdated = updateNativeMonitorDeviceViewportImpl(monitor, monitor.getMutuableViewportPU(), monitor.getMutuableViewportWU()); if( DEBUG ) { - System.err.println("Screen.updateMonitorViewport["+i+"] @ "+Thread.currentThread().getName()+": "+monitor.getViewport()+" -> "+newViewport); - } - if( null != newViewport ) { - monitor.setViewportValue(newViewport); + System.err.println("Screen.updateMonitorViewport["+i+"] @ "+Thread.currentThread().getName()+": updated: "+viewportUpdated+", PU "+monitor.getViewport()+", WU "+monitor.getViewportInWindowUnits()); } } } @@ -430,7 +444,7 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { System.err.println("monitorModeChangeNotify @ "+Thread.currentThread().getName()+": success "+success+", "+me); } for(int i=0; i<refMonitorModeListener.size(); i++) { - ((MonitorModeListener)refMonitorModeListener.get(i)).monitorModeChanged(me, success); + refMonitorModeListener.get(i).monitorModeChanged(me, success); } } diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 6a5fc5de0..08559c14d 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -910,9 +910,14 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer return screen; } + protected void setScreen(ScreenImpl newScreen) { // never null ! + removeScreenReference(); + screen = newScreen; + } + @Override public final MonitorDevice getMainMonitor() { - return screen.getMainMonitor( getSurfaceBounds() ); + return screen.getMainMonitor( getBounds() ); } /** @@ -1072,7 +1077,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @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()); + setSize(pixelWidth / getPixelScaleX(), pixelHeight / getPixelScaleY()); } @Override public final void setTopLevelSize(final int width, final int height) { @@ -1232,11 +1237,6 @@ 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() ) { @@ -2249,8 +2249,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer int x,y,w,h; - final RectangleImmutable sviewport = screen.getViewportInWindowUnits(WindowImpl.this); - final RectangleImmutable viewport; + final RectangleImmutable sviewport = screen.getViewportInWindowUnits(); // window units + final RectangleImmutable viewport; // window units final int fs_span_flag; final boolean alwaysOnTopChange; if(_fullscreen) { @@ -2262,7 +2262,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer fullscreenMonitors = getScreen().getMonitorDevices(); } } - viewport = convertToWindowUnits(MonitorDevice.unionOfViewports(new Rectangle(), fullscreenMonitors)); + { + 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; @@ -2620,7 +2624,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // Native MouseEvents pre-processed to be enqueued or consumed directly // - public void sendMouseEvent(final short eventType, final int modifiers, + 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); } diff --git a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java index 7a571318b..5671a05e4 100644 --- a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java @@ -286,8 +286,7 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { if( isFullscreen() ) { final MonitorDevice mainMonitor = getMainMonitor(); - final RectangleImmutable screenRect = mainMonitor.getViewport(); - final RectangleImmutable winRect = this.convertToWindowUnits((Rectangle)screenRect.cloneMutable()); + final RectangleImmutable winRect = mainMonitor.getViewportInWindowUnits(); definePosition(winRect.getX(), winRect.getY()); defineSize(winRect.getWidth(), winRect.getHeight()); } diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java index f7722c91c..5dab64e39 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java @@ -65,7 +65,7 @@ public class AWTCanvas extends Canvas { private AWTGraphicsConfiguration awtConfig; 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 boolean displayConfigChanged=false; @@ -152,6 +152,10 @@ public class AWTCanvas extends Canvas { } } + public int getPixelScale() { + final JAWTWindow _jawtWindow = jawtWindow; + return (null != _jawtWindow) ? _jawtWindow.getPixelScale() : 1; + } public NativeWindow getNativeWindow() { final JAWTWindow _jawtWindow = jawtWindow; return (null != _jawtWindow) ? _jawtWindow : null; diff --git a/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java index f99476851..1f0ba6f09 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java @@ -99,6 +99,17 @@ public class WindowDriver extends WindowImpl { } @Override + protected final int getPixelScaleX() { + final AWTCanvas _awtCanvas = awtCanvas; + return null != _awtCanvas ? _awtCanvas.getPixelScale() : 1; + } + + @Override + protected final int getPixelScaleY() { + return getPixelScaleX(); + } + + @Override protected void createNativeImpl() { if(0!=getParentWindowHandle()) { throw new RuntimeException("Window parenting not supported in AWT, use AWTWindow(Frame) cstr for wrapping instead"); 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 d3231557f..64bc87a41 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java @@ -104,8 +104,8 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl { } @Override - protected void calcVirtualScreenOriginAndSize(Rectangle vOriginSize) { - vOriginSize.set(0, 0, fixedWidth, fixedHeight); // FIXME + protected void calcVirtualScreenOriginAndSize(Rectangle viewport, Rectangle viewportInWindowUnits) { + viewport.set(0, 0, fixedWidth, fixedHeight); // FIXME } //---------------------------------------------------------------------- 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 dc2a8459a..e0228c10f 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 @@ -97,8 +97,8 @@ public class ScreenDriver extends ScreenImpl { } @Override - protected void calcVirtualScreenOriginAndSize(Rectangle vOriginSize) { - vOriginSize.set(0, 0, cachedWidth, cachedHeight); + protected void calcVirtualScreenOriginAndSize(Rectangle viewport, Rectangle viewportInWindowUnits) { + viewport.set(0, 0, cachedWidth, cachedHeight); } /** Called from {@link #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 1c927acc4..188e5b964 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 @@ -170,13 +170,13 @@ public class WindowDriver extends WindowImpl { } @Override - public final void sendMouseEvent(final short eventType, final int modifiers, - final int x, final int y, final short button, final float rotation) { + 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.sendMouseEvent(eventType, modifiers, x, y, button, rotation); + super.doMouseEvent(enqueue, wait, eventType, modifiers, x, y, button, rotationXYZ, rotationScale); } @Override 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 44802e348..20c60565a 100644 --- a/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java @@ -106,8 +106,8 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl { } @Override - protected void calcVirtualScreenOriginAndSize(Rectangle vOriginSize) { - vOriginSize.set(0, 0, cachedWidth, cachedHeight); + protected void calcVirtualScreenOriginAndSize(Rectangle viewport, Rectangle viewportInWindowUnits) { + viewport.set(0, 0, cachedWidth, cachedHeight); } //---------------------------------------------------------------------- diff --git a/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java index 9ebe2629a..541576250 100644 --- a/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java @@ -102,8 +102,8 @@ public class ScreenDriver extends ScreenImpl { } @Override - protected void calcVirtualScreenOriginAndSize(Rectangle vOriginSize) { - vOriginSize.set(0, 0, cachedWidth, cachedHeight); + protected void calcVirtualScreenOriginAndSize(Rectangle viewport, Rectangle viewportInWindowUnits) { + viewport.set(0, 0, cachedWidth, cachedHeight); } protected void sizeChanged(int w, int h) { diff --git a/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java index 4f3cc691b..5f458e2c9 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java @@ -35,13 +35,16 @@ package jogamp.newt.driver.macosx; import javax.media.nativewindow.DefaultGraphicsScreen; +import javax.media.nativewindow.util.Rectangle; +import jogamp.nativewindow.macosx.OSXUtil; import jogamp.newt.MonitorModeProps; import jogamp.newt.ScreenImpl; 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 { @@ -60,7 +63,7 @@ public class ScreenDriver extends ScreenImpl { @Override protected void closeNativeImpl() { } - private MonitorMode getMonitorModeImpl(MonitorModeProps.Cache cache, int crt_idx, int mode_idx) { + 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) { @@ -71,56 +74,133 @@ public class ScreenDriver extends ScreenImpl { return res; } - @Override - protected final void collectNativeMonitorModesAndDevicesImpl(MonitorModeProps.Cache cache) { - int crtIdx = 0; - int modeIdx = 0; - ArrayHashSet<MonitorMode> supportedModes = new ArrayHashSet<MonitorMode>(); - do { - final MonitorMode mode = getMonitorModeImpl(cache, crtIdx, modeIdx); - if( null != mode ) { - supportedModes.getOrAdd(mode); - // next mode on same monitor - modeIdx++; - } else if( 0 < modeIdx ) { - // end of monitor modes - got at least one mode - final MonitorMode currentMode = getMonitorModeImpl(cache, crtIdx, -1); - if ( null == currentMode ) { - throw new InternalError("Could not gather current mode of device "+crtIdx+", but gathered "+modeIdx+" modes"); + 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); } - final int[] monitorProps = getMonitorProps0(crtIdx); - if ( null == monitorProps ) { - throw new InternalError("Could not gather device "+crtIdx+", but gathered "+modeIdx+" modes"); + // 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; + } + } } - // merge monitor-props + supported modes - MonitorModeProps.streamInMonitorDevice(null, cache, this, supportedModes, currentMode, monitorProps, 0); - - // next monitor, 1st mode - supportedModes= new ArrayHashSet<MonitorMode>(); - crtIdx++; - modeIdx=0; - } else { - // end of monitor - break; } - } while ( true ); + } + final int count; + final int[] pixelScaleArray; + final int[][] propsOrigArray; + final int[][] propsFixedArray; + } + + @Override + protected final void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) { + final CrtProps crtProps = new CrtProps(); + + // + // 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); + } + } + + @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)+"]"); + } + 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; } @Override - protected MonitorMode queryCurrentMonitorModeImpl(MonitorDevice monitor) { + protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) { return getMonitorModeImpl(null, monitor.getId(), -1); } @Override - protected boolean setCurrentMonitorModeImpl(MonitorDevice monitor, MonitorMode mode) { + protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) { return setMonitorMode0(monitor.getId(), mode.getId(), mode.getRotation()); } @Override - protected int validateScreenIndex(int idx) { + protected int validateScreenIndex(final int idx) { return 0; // big-desktop w/ multiple monitor attached, only one screen available } + 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 eebf280de..540186f2e 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java @@ -46,12 +46,15 @@ import javax.media.nativewindow.util.PointImmutable; 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 { @@ -59,7 +62,81 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl DisplayDriver.initSingleton(); } + private int pixelScale; + public WindowDriver() { + pixelScale = 1; + } + + private boolean updatePixelScale(final boolean sendEvent, final boolean defer, final float newPixelScaleRaw) { + final int newPixelScaleSafe = FloatUtil.isZero(newPixelScaleRaw, FloatUtil.EPSILON) ? 1 : (int) newPixelScaleRaw; + final boolean changed = pixelScale != newPixelScaleSafe; + if( DEBUG_IMPLEMENTATION ) { + System.err.println("WindowDriver.updatePixelScale.X: "+pixelScale+" -> "+newPixelScaleSafe+" (raw "+newPixelScaleRaw+") - changed "+changed); + } + if( changed ) { + pixelScale = newPixelScaleSafe; + if( sendEvent ) { + super.sizeChanged(defer, getWindowWidth(), getWindowHeight(), true); + } else { + defineSize(getWindowWidth(), getWindowHeight()); + } + } + return changed; + } + + private boolean updatePixelScaleByScreenIdx(final boolean sendEvent) { + final float newPixelScaleRaw = (float) OSXUtil.GetPixelScale(getScreen().getIndex()); + if( DEBUG_IMPLEMENTATION ) { + System.err.println("WindowDriver.updatePixelScale.1: "+pixelScale+" -> "+newPixelScaleRaw); + } + return updatePixelScale(sendEvent, true /* defer */, newPixelScaleRaw); + } + + private boolean updatePixelScaleByWindowHandle(final boolean sendEvent) { + final long wh = getWindowHandle(); + if( 0 != wh ) { + final float newPixelScaleRaw = (float)OSXUtil.GetPixelScale(wh); + if( DEBUG_IMPLEMENTATION ) { + System.err.println("WindowDriver.updatePixelScale.2: "+pixelScale+" -> "+newPixelScaleRaw); + } + return updatePixelScale(sendEvent, true /* defer */, newPixelScaleRaw); + } else { + return false; + } + } + + /** Called from native code */ + protected void updatePixelScale(final boolean defer, final float newPixelScaleRaw) { + final long handle = getWindowHandle(); + if( 0 != handle ) { + if( DEBUG_IMPLEMENTATION ) { + System.err.println("WindowDriver.updatePixelScale.3: "+pixelScale+" -> "+newPixelScaleRaw); + } + updatePixelScale(true /* sendEvent*/, defer, newPixelScaleRaw); + } + } + + @Override + protected final void instantiationFinished() { + updatePixelScaleByScreenIdx(false /* sendEvent*/); + } + + @Override + protected void setScreen(ScreenImpl newScreen) { // never null ! + super.setScreen(newScreen); + updatePixelScaleByScreenIdx(false /* sendEvent*/); // caller (reparent, ..) will send reshape event + } + + + @Override + protected final int getPixelScaleX() { + return pixelScale; + } + + @Override + protected final int getPixelScaleY() { + return pixelScale; } @Override @@ -210,16 +287,6 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl private boolean useParent(NativeWindow parent) { return null != parent && 0 != parent.getWindowHandle(); } @Override - protected final int getPixelScaleX() { - return 1; // FIXME HiDPI: Use pixelScale - } - - @Override - protected final int getPixelScaleY() { - return 1; // FIXME HiDPI: Use pixelScale - } - - @Override public void updatePosition(int x, int y) { final long handle = getWindowHandle(); if( 0 != handle && !isOffscreenInstance ) { @@ -263,11 +330,12 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl } @Override - protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, int flags) { + protected boolean reconfigureWindowImpl(int x, int y, final int width, final int height, int flags) { final boolean _isOffscreenInstance = isOffscreenInstance(this, this.getParent()); isOffscreenInstance = 0 != sscSurfaceHandle || _isOffscreenInstance; final PointImmutable pClientLevelOnSreen; if( isOffscreenInstance ) { + x = 0; y = 0; pClientLevelOnSreen = new Point(0, 0); } else { final NativeWindow parent = getParent(); @@ -313,9 +381,9 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl 0 != ( FLAG_CHANGE_PARENTING & flags) || 0 != ( FLAG_CHANGE_FULLSCREEN & flags) ) { if(isOffscreenInstance) { - createWindow(true, 0 != getWindowHandle(), pClientLevelOnSreen, 64, 64, false, setVisible, false); + createWindow(true, 0 != getWindowHandle(), pClientLevelOnSreen, x, y, 64, 64, false, setVisible, false); } else { - createWindow(false, 0 != getWindowHandle(), pClientLevelOnSreen, width, height, + createWindow(false, 0 != getWindowHandle(), pClientLevelOnSreen, x, y, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags), setVisible, 0 != ( FLAG_IS_ALWAYSONTOP & flags)); } } else { @@ -329,7 +397,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl } // else offscreen size is realized via recreation // no native event (fullscreen, some reparenting) positionChanged(true, x, y); - sizeChanged(true, width, height, false); + super.sizeChanged(true, width, height, false); } if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && setVisible ) { if( !isOffscreenInstance ) { @@ -439,11 +507,17 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl @Override protected void warpPointerImpl(final int x, final int y) { if( !isOffscreenInstance ) { - warpPointer0(getWindowHandle(), x, y); + warpPointer0(getWindowHandle(), x / getPixelScaleX(), y / getPixelScaleY()); } // else may need offscreen solution ? FIXME } @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) { + super.doMouseEvent(enqueue, wait, eventType, modifiers, x * getPixelScaleX(), y * getPixelScaleY(), button, rotationXYZ, rotationScale); + } + + @Override public final void sendKeyEvent(short eventType, int modifiers, short keyCode, short keySym, char keyChar) { throw new InternalError("XXX: Adapt Java Code to Native Code Changes"); } @@ -499,8 +573,8 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl // 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 PointImmutable pS, final int x, final int y, + final int width, final int height, final boolean fullscreen, final boolean visible, final boolean alwaysOnTop) { final long parentWinHandle = getParentWindowHandle(); final long preWinHandle = getWindowHandle(); @@ -558,8 +632,12 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl setTitle0(newWin, getTitle()); setAlwaysOnTop0(getWindowHandle(), alwaysOnTop); } - visibleChanged(true, visible); } } ); + // no native event (fullscreen, some reparenting) + positionChanged(false, x, y); + updatePixelScaleByWindowHandle(false /* sendEvent */); + super.sizeChanged(false, width, height, true); + visibleChanged(false, visible); } catch (Exception ie) { ie.printStackTrace(); } @@ -569,7 +647,8 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl private native long createView0(int x, int y, int w, int h, boolean fullscreen); 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, boolean opaque, boolean visible, long view); + private native void initWindow0(long parentWindow, long window, int x, int y, int w, int h, + boolean opaque, boolean visible, long view); private native boolean lockSurface0(long window, long view); private native boolean unlockSurface0(long window, long view); /** Must be called on Main-Thread */ diff --git a/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java index e789b995f..af265cfd3 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java @@ -65,14 +65,14 @@ public class ScreenDriver extends ScreenImpl { protected void closeNativeImpl() { } - private final String getAdapterName(int crt_idx) { + private final String getAdapterName(final int crt_idx) { return getAdapterName0(crt_idx); } - private final String getActiveMonitorName(String adapterName, int monitor_idx) { + private final String getActiveMonitorName(final String adapterName, final int monitor_idx) { return getActiveMonitorName0(adapterName, monitor_idx); } - private final MonitorMode getMonitorModeImpl(MonitorModeProps.Cache cache, String adapterName, int crtModeIdx) { + private final MonitorMode getMonitorModeImpl(final MonitorModeProps.Cache cache, final String adapterName, final int crtModeIdx) { if( null == adapterName ) { return null; } @@ -85,7 +85,7 @@ public class ScreenDriver extends ScreenImpl { } @Override - protected void collectNativeMonitorModesAndDevicesImpl(MonitorModeProps.Cache cache) { + protected void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) { int crtIdx = 0; ArrayHashSet<MonitorMode> supportedModes = new ArrayHashSet<MonitorMode>(); String adapterName = getAdapterName(crtIdx); @@ -118,26 +118,28 @@ public class ScreenDriver extends ScreenImpl { } @Override - protected Rectangle getNativeMonitorDeviceViewportImpl(MonitorDevice monitor) { + 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; - return new Rectangle(monitorProps[offset++], monitorProps[offset++], monitorProps[offset++], monitorProps[offset++]); + 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; } @Override - protected MonitorMode queryCurrentMonitorModeImpl(MonitorDevice monitor) { + protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) { return getMonitorModeImpl(null, getAdapterName(monitor.getId()), -1); } @Override - protected boolean setCurrentMonitorModeImpl(MonitorDevice monitor, MonitorMode mode) { + protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) { return setMonitorMode0(monitor.getId(), -1, -1, // no fixed position! mode.getSurfaceSize().getResolution().getWidth(), @@ -149,13 +151,13 @@ public class ScreenDriver extends ScreenImpl { } @Override - protected int validateScreenIndex(int idx) { + protected int validateScreenIndex(final int idx) { return 0; // big-desktop w/ multiple monitor attached, only one screen available } @Override - protected void calcVirtualScreenOriginAndSize(Rectangle vOriginSize) { - vOriginSize.set(getVirtualOriginX0(), getVirtualOriginY0(), getVirtualWidthImpl0(), getVirtualHeightImpl0()); + protected void calcVirtualScreenOriginAndSize(final Rectangle viewport, Rectangle viewportInWindowUnits) { + viewport.set(getVirtualOriginX0(), getVirtualOriginY0(), getVirtualWidthImpl0(), getVirtualHeightImpl0()); } // Native calls diff --git a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java index bef7f60ec..2d7c6509d 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java @@ -111,7 +111,7 @@ public class ScreenDriver extends ScreenImpl { private RandR rAndR; @Override - protected final void collectNativeMonitorModesAndDevicesImpl(MonitorModeProps.Cache cache) { + protected final void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) { if( null == rAndR ) { return; } final AbstractGraphicsDevice device = getDisplay().getGraphicsDevice(); device.lock(); @@ -165,12 +165,14 @@ public class ScreenDriver extends ScreenImpl { } @Override - protected Rectangle getNativeMonitorDeviceViewportImpl(MonitorDevice monitor) { + protected boolean updateNativeMonitorDeviceViewportImpl(final MonitorDevice monitor, final Rectangle viewportPU, final Rectangle viewportWU) { final AbstractGraphicsDevice device = getDisplay().getGraphicsDevice(); device.lock(); try { int[] viewportProps = rAndR.getMonitorDeviceViewport(device.getHandle(), this, monitor.getId()); - return new Rectangle(viewportProps[0], viewportProps[1], viewportProps[2], viewportProps[3]); + 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(); } @@ -207,7 +209,7 @@ public class ScreenDriver extends ScreenImpl { return done; } - private DisplayImpl.DisplayRunnable<Boolean> xineramaEnabledQueryWithTemp = new DisplayImpl.DisplayRunnable<Boolean>() { + private final DisplayImpl.DisplayRunnable<Boolean> xineramaEnabledQueryWithTemp = new DisplayImpl.DisplayRunnable<Boolean>() { @Override public Boolean run(long dpy) { return new Boolean(X11Util.XineramaIsEnabled(dpy)); @@ -225,8 +227,8 @@ public class ScreenDriver extends ScreenImpl { } @Override - protected void calcVirtualScreenOriginAndSize(final Rectangle vOriginSize) { - final RectangleImmutable ov = (RectangleImmutable) getViewport().cloneMutable(); + protected void calcVirtualScreenOriginAndSize(final Rectangle viewport, 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); @@ -242,11 +244,11 @@ public class ScreenDriver extends ScreenImpl { runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() { @Override public Object run(long dpy) { - vOriginSize.set(0, 0, getWidth0(dpy, screen_idx), getHeight0(dpy, screen_idx)); + viewport.set(0, 0, getWidth0(dpy, screen_idx), getHeight0(dpy, screen_idx)); return null; } } ); if( DEBUG ) { - System.err.println("X11Screen.calcVirtualScreenOriginAndSize: Querying X11: "+ov+" -> "+vOriginSize); + System.err.println("X11Screen.calcVirtualScreenOriginAndSize: Querying X11: "+ov+" -> "+viewport); } } } @@ -254,11 +256,11 @@ public class ScreenDriver extends ScreenImpl { //---------------------------------------------------------------------- // Internals only // - private final <T> T runWithLockedDisplayDevice(DisplayRunnable<T> action) { + private final <T> T runWithLockedDisplayDevice(final DisplayRunnable<T> action) { return display.runWithLockedDisplayDevice(action); } - private final <T> T runWithTempDisplayHandle(DisplayRunnable<T> action) { + private final <T> T runWithTempDisplayHandle(final DisplayRunnable<T> action) { final long displayHandle = X11Util.openDisplay(display.getName()); if(0 == displayHandle) { throw new RuntimeException("null device"); @@ -272,7 +274,7 @@ public class ScreenDriver extends ScreenImpl { return res; } - private final <T> T runWithOptTempDisplayHandle(DisplayRunnable<T> action) { + private final <T> T runWithOptTempDisplayHandle(final DisplayRunnable<T> action) { if( null != rAndR && rAndR.getVersion().compareTo(RandR.version130) >= 0 ) { return display.runWithLockedDisplayDevice(action); } else { diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index 25ea47c47..80e70216e 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -366,7 +366,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_destroyPoint [pool release]; } -static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx, BOOL cap) { +NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx, BOOL cap) { NSArray *screens = [NSScreen screens]; if( screen_idx<0 || screen_idx>=[screens count] ) { if( cap ) { @@ -378,7 +378,7 @@ static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx, BOOL cap) { return (NSScreen *) [screens objectAtIndex: screen_idx]; } -static NSScreen * NewtScreen_getNSScreenByCoord(int x, int y) { +NSScreen * NewtScreen_getNSScreenByCoord(int x, int y) { NSArray *screens = [NSScreen screens]; int i; for(i=[screens count]-1; i>=0; i--) { @@ -394,7 +394,32 @@ static NSScreen * NewtScreen_getNSScreenByCoord(int x, int y) { return (NSScreen *) [screens objectAtIndex: 0]; } -static CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) { +static void NewtScreen_dump() { +#ifdef VERBOSE_ON + NSArray *screens = [NSScreen screens]; + int i; + for(i=0; i<[screens count]; i++) { + NSScreen * screen = (NSScreen *) [screens objectAtIndex: i]; + NSRect screenFrame = [screen frame]; + NSRect screenVisibleFrame = [screen visibleFrame]; + CGFloat pixelScale = 1.0; // default +NS_DURING + // Available >= 10.7 + pixelScale = [screen backingScaleFactor]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + NSWindowDepth depth = [screen depth]; // an (int) value! + DBG_PRINT( "NSScreen #%d (%p): Frame %lf/%lf %lfx%lf (vis %lf/%lf %lfx%lf), scale %lf, depth %d\n", + i, screen, + screenFrame.origin.x, screenFrame.origin.y, screenFrame.size.width, screenFrame.size.height, + screenVisibleFrame.origin.x, screenVisibleFrame.origin.y, screenVisibleFrame.size.width, screenVisibleFrame.size.height, + pixelScale, depth); + } +#endif +} + + +CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) { // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?! NSDictionary * dict = [screen deviceDescription]; NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"]; @@ -428,6 +453,20 @@ static long GetDictionaryLong(CFDictionaryRef theDict, const void* key) /* * Class: jogamp_newt_driver_macosx_ScreenDriver + * Method: getMonitorCount0 + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonitorCount0 + (JNIEnv *env, jobject obj) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSArray *screens = [NSScreen screens]; + [pool release]; + return (jint) [screens count]; +} + +/* + * Class: jogamp_newt_driver_macosx_ScreenDriver * Method: getMonitorProps0 * Signature: (I)[I */ @@ -463,8 +502,16 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonit fprintf(stderr, "MacScreen_getMonitorProps0.3: %ld ms\n", td_ms); fflush(NULL); #endif - CGRect bounds = CGDisplayBounds (display); - + CGRect dBounds = CGDisplayBounds (display); // origin top-left +#ifdef VERBOSE_ON + BOOL usesGL = CGDisplayUsesOpenGLAcceleration(display); + NSRect sFrame = [screen frame]; // origin bottom-left + DBG_PRINT( "getMonitorProps0: scrn %d, top-left displayBounds[%d/%d %dx%d], bottom-left screenFrame[%d/%d %dx%d], usesGL %d\n", (int)crt_idx, + (int)dBounds.origin.x, (int)dBounds.origin.y, (int)dBounds.size.width, (int)dBounds.size.height, + (int)sFrame.origin.x, (int)sFrame.origin.y, (int)sFrame.size.width, (int)sFrame.size.height, + (int)usesGL); +#endif + jsize propCount = MIN_MONITOR_DEVICE_PROPERTIES - 1 - NUM_MONITOR_MODE_PROPERTIES; jint prop[ propCount ]; int offset = 0; @@ -472,10 +519,14 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonit prop[offset++] = crt_idx; prop[offset++] = (jint) sizeMM.width; prop[offset++] = (jint) sizeMM.height; - prop[offset++] = (jint) bounds.origin.x; // rotated viewport x - prop[offset++] = (jint) bounds.origin.y; // rotated viewport y - prop[offset++] = (jint) bounds.size.width; // rotated viewport width - prop[offset++] = (jint) bounds.size.height; // rotated viewport height + prop[offset++] = (jint) dBounds.origin.x; // rotated viewport x (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.origin.y; // rotated viewport y (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.width; // rotated viewport width (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.height; // rotated viewport height (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.origin.x; // rotated viewport x (window units, will be fixed in java code) + prop[offset++] = (jint) dBounds.origin.y; // rotated viewport y (window units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.width; // rotated viewport width (window units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.height; // rotated viewport height (window units, will be fixed in java code) jintArray properties = (*env)->NewIntArray(env, propCount); if (properties == NULL) { @@ -503,6 +554,13 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonit [pool release]; return NULL; } + CGFloat pixelScale = 1.0; // default +NS_DURING + // Available >= 10.7 + pixelScale = [screen backingScaleFactor]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); CFArrayRef availableModes = CGDisplayAvailableModes(display); @@ -516,8 +574,8 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonit #ifdef VERBOSE_ON if(0 >= mode_idx) { // only for current mode (-1) and first mode (scanning) - DBG_PRINT( "getScreenMode0: scrn %d (%p, %p), mode %d, avail: %d/%d, current rot %d ccw\n", - (int)crt_idx, screen, (void*)(intptr_t)display, (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots, currentCCWRot); + DBG_PRINT( "getScreenMode0: scrn %d (s %p, d %p, pscale %lf), mode %d, avail: %d/%d, current rot %d ccw\n", + (int)crt_idx, screen, (void*)(intptr_t)display, pixelScale, (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots, currentCCWRot); } #endif @@ -543,6 +601,10 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonit int mWidth = CGDDGetModeWidth(mode); int mHeight = CGDDGetModeHeight(mode); + if( -1 == mode_idx ) { + mWidth *= (int)pixelScale; // accomodate HiDPI + mHeight *= (int)pixelScale; // accomodate HiDPI + } // swap width and height, since OSX reflects rotated dimension, we don't if ( 90 == currentCCWRot || 270 == currentCCWRot ) { @@ -564,7 +626,7 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonit prop[propIndex++] = 0; // flags prop[propIndex++] = nativeId; prop[propIndex++] = ccwRot; - + DBG_PRINT( "getScreenMode0: Mode %d/%d (%d): %dx%d, %d bpp, %d / %d Hz, nativeId %d, rot %d ccw\n", (int)mode_idx, (int)numberOfAvailableModesRots, (int)numberOfAvailableModes, (int)prop[1], (int)prop[2], (int)prop[3], @@ -653,6 +715,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initIDs0 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NewtScreen_dump(); + jclass c; c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { @@ -694,21 +758,13 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createView0 DBG_PRINT( "createView0 - %p (this), %d/%d %dx%d, fs %d (START)\n", (void*)(intptr_t)jthis, (int)x, (int)y, (int)w, (int)h, (int)fullscreen); - NSScreen *myScreen = NewtScreen_getNSScreenByCoord(x, y); - NSRect rectWin; - - if (fullscreen) { - rectWin = [myScreen frame]; - x = 0; - y = 0; - w = (jint) (rectWin.size.width); - h = (jint) (rectWin.size.height); - } else { - rectWin = NSMakeRect(x, y, w, h); - } - NSRect rectView = NSMakeRect(0, 0, w, h); NewtView *myView = [[NewtView alloc] initWithFrame: rectView] ; +NS_DURING + // Available >= 10.7 + [myView setWantsBestResolutionOpenGLSurface: YES]; // HiDPI scaling: Always desired +NS_HANDLER +NS_ENDHANDLER DBG_PRINT( "createView0.X - new view: %p\n", myView); [pool release]; @@ -735,19 +791,10 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createWindow (int)styleMask, (int)bufferingType, myView); (void)myView; - NSScreen *myScreen = NewtScreen_getNSScreenByCoord(x, y); - - NSRect rectWin; if (fullscreen) { styleMask = NSBorderlessWindowMask; - rectWin = [myScreen frame]; - x = 0; - y = 0; - w = (jint) (rectWin.size.width); - h = (jint) (rectWin.size.height); - } else { - rectWin = NSMakeRect(x, y, w, h); } + NSRect rectWin = NSMakeRect(x, y, w, h); // Allocate the window NewtMacWindow* myWindow = [[NewtMacWindow alloc] initWithContentRect: rectWin @@ -772,7 +819,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createWindow * Signature: (JJIIIIZZZJ)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initWindow0 - (JNIEnv *env, jobject jthis, jlong parent, jlong window, jint x, jint y, jint w, jint h, + (JNIEnv *env, jobject jthis, jlong parent, jlong window, jint x, jint y, jint w, jint h, jboolean opaque, jboolean visible, jlong jview) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; @@ -784,19 +831,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initWindow0 (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, (int)x, (int)y, (int)w, (int)h, (int) opaque, (int)fullscreen, (int)visible, myView); - NSScreen *myScreen = NewtScreen_getNSScreenByCoord(x, y); - - NSRect rectWin; - if (fullscreen) { - rectWin = [myScreen frame]; - x = 0; - y = 0; - w = (jint) (rectWin.size.width); - h = (jint) (rectWin.size.height); - } else { - rectWin = NSMakeRect(x, y, w, h); - } - [myWindow setReleasedWhenClosed: NO]; // We control NSWindow destruction! [myWindow setPreservesContentDuringLiveResize: NO]; NS_DURING @@ -927,6 +961,7 @@ NS_DURING * Shall have no penalty on modern GPU and is also recommended, see bottom box @ * <https://developer.apple.com/library/mac/documentation/graphicsimaging/Conceptual/QuartzDisplayServicesConceptual/Articles/DisplayCapture.html> * + NSScreen *myScreen = NewtScreen_getNSScreenByCoord(x, y); if ( [myView respondsToSelector:@selector(enterFullScreenMode:withOptions:)] ) { // Available >= 10.5 - Makes the menubar disapear [myView enterFullScreenMode: myScreen withOptions:NULL]; diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h index 8f6362ac2..0f80df2d7 100644 --- a/src/newt/native/NewtMacWindow.h +++ b/src/newt/native/NewtMacWindow.h @@ -49,6 +49,10 @@ // #define DBG_LIFECYCLE 1 +NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx, BOOL cap); +NSScreen * NewtScreen_getNSScreenByCoord(int x, int y); +CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen); + @interface NewtView : NSView { jobject javaWindowObject; @@ -129,6 +133,7 @@ - (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods; - (void) sendKeyEvent: (NSEvent*) event eventType: (jshort) evType; - (void) sendKeyEvent: (jshort) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jshort) evType; +- (void) viewDidChangeBackingProperties; @end diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index b4133ac7e..1a70de445 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -174,6 +174,7 @@ static jmethodID requestFocusID = NULL; static jmethodID insetsChangedID = NULL; static jmethodID sizeChangedID = NULL; +static jmethodID updatePixelScaleID = NULL; static jmethodID visibleChangedID = NULL; static jmethodID positionChangedID = NULL; static jmethodID focusChangedID = NULL; @@ -330,8 +331,8 @@ static jmethodID windowRepaintID = NULL; NSRect viewFrame = [self frame]; (*env)->CallVoidMethod(env, javaWindowObject, windowRepaintID, JNI_TRUE, // defer .. - dirtyRect.origin.x, viewFrame.size.height - dirtyRect.origin.y, - dirtyRect.size.width, dirtyRect.size.height); + (int)dirtyRect.origin.x, (int)viewFrame.size.height - (int)dirtyRect.origin.y, + (int)dirtyRect.size.width, (int)dirtyRect.size.height); // detaching thread not required - daemon // NewtCommon_ReleaseJNIEnv(shallBeDetached); @@ -761,6 +762,31 @@ static jmethodID windowRepaintID = NULL; // NewtCommon_ReleaseJNIEnv(shallBeDetached); } +- (void)viewDidChangeBackingProperties +{ + [super viewDidChangeBackingProperties]; + + CGFloat pixelScale = [[self window] backingScaleFactor]; + [[self layer] setContentsScale: pixelScale]; + + if (javaWindowObject == NULL) { + DBG_PRINT("viewDidChangeBackingProperties: null javaWindowObject\n"); + return; + } + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("viewDidChangeBackingProperties: null JNIEnv\n"); + return; + } + + (*env)->CallVoidMethod(env, javaWindowObject, updatePixelScaleID, JNI_TRUE, (jfloat)pixelScale); // defer + + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); +} + + @end @implementation NewtMacWindow @@ -769,7 +795,8 @@ static jmethodID windowRepaintID = NULL; { enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(ZSIIISF)V"); enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZSISCC)V"); - sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V"); + sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V"); + updatePixelScaleID = (*env)->GetMethodID(env, clazz, "updatePixelScale", "(ZF)V"); visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(ZIIII)V"); positionChangedID = (*env)->GetMethodID(env, clazz, "screenPositionChanged", "(ZII)V"); @@ -777,7 +804,7 @@ static jmethodID windowRepaintID = NULL; windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); - if (enqueueMouseEventID && enqueueKeyEventID && sizeChangedID && visibleChangedID && insetsChangedID && + if (enqueueMouseEventID && enqueueKeyEventID && sizeChangedID && updatePixelScaleID && visibleChangedID && insetsChangedID && positionChangedID && focusChangedID && windowDestroyNotifyID && requestFocusID && windowRepaintID) { CKCH_CreateDictionaries(); @@ -824,10 +851,12 @@ static jmethodID windowRepaintID = NULL; // Why is this necessary? Without it we don't get any of the // delegate methods like resizing and window movement. [self setDelegate: self]; + cachedInsets[0] = 0; // l cachedInsets[1] = 0; // r cachedInsets[2] = 0; // t cachedInsets[3] = 0; // b + realized = YES; DBG_PRINT("NewtWindow::create: %p, realized %d, hasPresentationSwitch %d[defaultOptions 0x%X, fullscreenOptions 0x%X], (refcnt %d)\n", res, realized, (int)hasPresentationSwitch, (int)defaultPresentationOptions, (int)fullscreenPresentationOptions, (int)[res retainCount]); @@ -1123,7 +1152,7 @@ static jmethodID windowRepaintID = NULL; NSRect frameRect = [self frame]; NSRect contentRect = [self contentRectForFrameRect: frameRect]; - (*env)->CallVoidMethod(env, javaWindowObject, sizeChangedID, JNI_FALSE, + (*env)->CallVoidMethod(env, javaWindowObject, sizeChangedID, JNI_TRUE, // defer (jint) contentRect.size.width, (jint) contentRect.size.height, JNI_FALSE); } diff --git a/src/newt/native/ScreenMode.h b/src/newt/native/ScreenMode.h index 110f1c493..56c424b11 100644 --- a/src/newt/native/ScreenMode.h +++ b/src/newt/native/ScreenMode.h @@ -40,7 +40,8 @@ #define NUM_MONITOR_MODE_PROPERTIES_ALL 8 /* count + the above */ -#define MIN_MONITOR_DEVICE_PROPERTIES 11 /* count + id, ScreenSizeMM[width, height], rotated Viewport[x, y, width, height], currentMonitorModeId, rotation, supportedModeId+ */ +#define MIN_MONITOR_DEVICE_PROPERTIES 15 /* count + id, ScreenSizeMM[width, height], rotated Viewport pixel-units, rotated Viewport pixel-units, currentMonitorModeId, rotation, supportedModeId+ */ + /* Viewport := [x, y, width, height] (4 elements) */ #define FLAG_INTERLACE ( 1 << 0 ) #define FLAG_DOUBLESCAN ( 1 << 1 ) diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index c20e156c1..70d0c6f83 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -1859,10 +1859,14 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getMoni prop[propIndex++] = monitor_idx; prop[propIndex++] = widthmm; prop[propIndex++] = heightmm; - prop[propIndex++] = dm.dmPosition.x; // rotated viewport - prop[propIndex++] = dm.dmPosition.y; // rotated viewport - prop[propIndex++] = dm.dmPelsWidth; // rotated viewport - prop[propIndex++] = dm.dmPelsHeight; // rotated viewport + prop[propIndex++] = dm.dmPosition.x; // rotated viewport pixel units + prop[propIndex++] = dm.dmPosition.y; // rotated viewport pixel units + prop[propIndex++] = dm.dmPelsWidth; // rotated viewport pixel units + prop[propIndex++] = dm.dmPelsHeight; // rotated viewport pixel units + prop[propIndex++] = dm.dmPosition.x; // rotated viewport window units (same) + prop[propIndex++] = dm.dmPosition.y; // rotated viewport window units (same) + prop[propIndex++] = dm.dmPelsWidth; // rotated viewport window units (same) + prop[propIndex++] = dm.dmPelsHeight; // rotated viewport window units (same) jintArray properties = (*env)->NewIntArray(env, propCount); if (properties == NULL) { diff --git a/src/newt/native/X11RandR13.c b/src/newt/native/X11RandR13.c index 92c20e893..4e92a32b4 100644 --- a/src/newt/native/X11RandR13.c +++ b/src/newt/native/X11RandR13.c @@ -426,10 +426,14 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorDevice prop[propIndex++] = crt_idx; prop[propIndex++] = xrrOutputInfo->mm_width; prop[propIndex++] = xrrOutputInfo->mm_height; - prop[propIndex++] = xrrCrtcInfo->x; - prop[propIndex++] = xrrCrtcInfo->y; - prop[propIndex++] = xrrCrtcInfo->width; - prop[propIndex++] = xrrCrtcInfo->height; + prop[propIndex++] = xrrCrtcInfo->x; // rotated viewport pixel units + prop[propIndex++] = xrrCrtcInfo->y; // rotated viewport pixel units + prop[propIndex++] = xrrCrtcInfo->width; // rotated viewport pixel units + prop[propIndex++] = xrrCrtcInfo->height; // rotated viewport pixel units + prop[propIndex++] = xrrCrtcInfo->x; // rotated viewport window units (same) + prop[propIndex++] = xrrCrtcInfo->y; // rotated viewport window units (same) + prop[propIndex++] = xrrCrtcInfo->width; // rotated viewport window units (same) + prop[propIndex++] = xrrCrtcInfo->height; // rotated viewport window units (same) prop[propIndex++] = xrrCrtcInfo->mode; // current mode id prop[propIndex++] = NewtScreen_XRotation2Degree(env, xrrCrtcInfo->rotation); int i; |