diff options
author | Sven Gothel <[email protected]> | 2023-01-31 07:35:58 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-01-31 07:35:58 +0100 |
commit | 97b79ad351e48e7d3c6f9c95bacdf4f9d5d158ef (patch) | |
tree | 0945989bcd6ffbe87f295f422002b3055a1e082d /src/newt/classes/jogamp | |
parent | 6eb13066996e94b2fe40bf64e74ea43d8f4e9171 (diff) |
NEWT Soft-PixelScale (p6): Implement Soft-PixelScale for X11 and Windows ... (working state)
Both:
- Using Soft-PixelScale mode, i.e. converting all given window-units to pixel-units for native GDI/X11 ops
- Using scaled pixel-sized surface
- Adjusting NEWT's Monitor's window-unit viewport value to pixel-scale
For X11:
- Using global scale factor from environment variable, either: "GDK_SCALE", "QT_SCALE_FACTOR" or "SOFT_SCALE".
The latter is for testing only.
See https://wiki.archlinux.org/title/HiDPI
For Windows:
- Using actual monitor's pixel-scale via native SHC API (Shellscaling API, shcore.dll)
Misc:
- SurfaceScaleUtils.getGlobalPixelScaleEnv() reads a float value from given env names, first come, first serve
- MonitorModeProps.streamInMonitorDevice(..): Add `invscale_wuviewport` argument to scale wuvieport for soft-pixel-scale
- TestGearsNEWT: Enhance GL2 demo to be suitable for manual tests, this since my Windows KVM machine doesn't support ES2
- TestGLContextDrawableSwitch10NEWT: Add a few more test constraints .. working
Tested:
- Manually on a Windows virtual machine (KVM) using
- 2 virtualized 'Video QXL' cards and
- and 'remote-viewer' to see the 2 monitors
since `Virtual Machine Manager` build-in doesn't support
- remote-viewer spice://localhost:5917
- Manually on a Linux machine w/ SOFT_SCALE
- Both, X11 and Windows
- Place window on each monitor
- Move window across monitors w/ pixel-scale change (or not)
- TODO: Test and fix utilization with AWT, i.e. NewtCanvasAWT
Diffstat (limited to 'src/newt/classes/jogamp')
16 files changed, 251 insertions, 52 deletions
diff --git a/src/newt/classes/jogamp/newt/MonitorModeProps.java b/src/newt/classes/jogamp/newt/MonitorModeProps.java index 873ee3ed6..292551559 100644 --- a/src/newt/classes/jogamp/newt/MonitorModeProps.java +++ b/src/newt/classes/jogamp/newt/MonitorModeProps.java @@ -273,6 +273,7 @@ public class MonitorModeProps { * @param screen the associated {@link ScreenImpl} * @param monitor_handle unique monitor long handle, implementation specific * @param pixelScale pre-fetched current pixel-scale, maybe {@code null} for {@link ScalableSurface#IDENTITY_PIXELSCALE}. + * @param invscale_wuviewport if true, the viewport in window-units will be scaled by 1/pixelScale for soft-pixel-scale * @param monitorProperties the input data inclusive supported modes. * @param offset the offset to the input data * @param monitor_idx if not null, returns the index of resulting {@link MonitorDevice} within {@link Cache#monitorDevices}. @@ -281,8 +282,8 @@ public class MonitorModeProps { */ public static MonitorDevice streamInMonitorDevice(final Cache cache, final ScreenImpl screen, final long monitor_handle, - final float[] pixelScale, final int[] monitorProperties, - int offset, final int[] monitor_idx) { + final float[] pixelScale, final boolean invscale_wuviewport, + final int[] monitorProperties, int offset, final int[] monitor_idx) { // 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) { @@ -303,6 +304,9 @@ public class MonitorModeProps { 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++]); + if( invscale_wuviewport && null != pixelScale ) { + viewportWU.scaleInv(pixelScale[0], pixelScale[1]); + } final MonitorMode currentMode; { final int modeId = monitorProperties[offset++]; @@ -360,6 +364,7 @@ public class MonitorModeProps { * @param monitor_handle unique monitor long handle, implementation specific * @param currentMode pre-fetched current {@link MonitorMode}s from cache. * @param pixelScale pre-fetched current pixel-scale, maybe {@code null} for {@link ScalableSurface#IDENTITY_PIXELSCALE}. + * @param invscale_wuviewport if true, the viewport in window-units will be scaled by 1/pixelScale for soft-pixel-scale * @param supportedModes pre-assembled list of supported {@link MonitorMode}s from cache. * @param monitorProperties the input data minus supported modes! * @param offset the offset to the input data @@ -371,9 +376,9 @@ public class MonitorModeProps { final long monitor_handle, final MonitorMode currentMode, final float[] pixelScale, - final ArrayHashSet<MonitorMode> supportedModes, - final int[] monitorProperties, int offset, - final int[] monitor_idx) { + final boolean invscale_wuviewport, + final ArrayHashSet<MonitorMode> supportedModes, final int[] monitorProperties, + int offset, final int[] monitor_idx) { // 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) { @@ -392,6 +397,9 @@ public class MonitorModeProps { 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++]); + if( invscale_wuviewport && null != pixelScale ) { + viewportWU.scaleInv(pixelScale[0], pixelScale[1]); + } MonitorDevice monitorDevice = new MonitorDeviceImpl(screen, monitor_handle, monitor_id, isClone, isPrimary, sizeMM, currentMode, pixelScale, viewportPU, viewportWU, supportedModes); diff --git a/src/newt/classes/jogamp/newt/ScreenImpl.java b/src/newt/classes/jogamp/newt/ScreenImpl.java index 1dba31d4f..d90ee73bb 100644 --- a/src/newt/classes/jogamp/newt/ScreenImpl.java +++ b/src/newt/classes/jogamp/newt/ScreenImpl.java @@ -360,8 +360,8 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { * <li>{@link MonitorModeProps#MIN_MONITOR_DEVICE_PROPERTIES}</li> * </ul>, i.e. * <ul> - * <li>{@link MonitorModeProps#streamInMonitorDevice(jogamp.newt.MonitorModeProps.Cache, ScreenImpl, long, double[], int[], int, int[])}</li> - * <li>{@link MonitorModeProps#streamInMonitorDevice(int[], jogamp.newt.MonitorModeProps.Cache, long, ArrayHashSet, int[], int, ScreenImpl)}</li> + * <li>{@link MonitorModeProps#streamInMonitorDevice(jogamp.newt.MonitorModeProps.Cache, ScreenImpl, long, double[], boolean, int[], int, int[])}</li> + * <li>{@link MonitorModeProps#streamInMonitorDevice(int[], jogamp.newt.MonitorModeProps.Cache, long, ArrayHashSet, boolean, int[], int, ScreenImpl)}</li> * <li>{@link MonitorModeProps#streamInMonitorMode(int[], jogamp.newt.MonitorModeProps.Cache, int[], int)}</li> * </ul> * @param cache memory pool caching the result @@ -520,7 +520,7 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { if( MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES != i ) { throw new InternalError("XX"); } - return MonitorModeProps.streamInMonitorDevice(cache, this, monitorId, null, props, 0, null); + return MonitorModeProps.streamInMonitorDevice(cache, this, monitorId, null, false /* invscale_wuviewport */, props, 0, null); } /** diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index ef8c4916d..ae63c4539 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -2966,12 +2966,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer boolean res = false; if( DEBUG_IMPLEMENTATION ) { System.err.println("Window.SoftPixelScale.0a: req "+reqPixelScale[0]+", has "+hasPixelScale[0]+", new "+newPixelScale[0]+" - "+getThreadName()); - Thread.dumpStack(); + // Thread.dumpStack(); } synchronized( scaleLock ) { - if( DEBUG_IMPLEMENTATION ) { - System.err.println("Window.SoftPixelScale.0b: req "+reqPixelScale[0]+", has "+hasPixelScale[0]+", new "+newPixelScale[0]+" - "+getThreadName()); - } try { res = applySoftPixelScaleImpl(move_diff, sendEvent, defer, newPixelScale); } finally { diff --git a/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java index 3c0b1aef4..8d73592b5 100644 --- a/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java @@ -116,7 +116,7 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl { 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(cache, this, crt_id, currentMode, null, cache.monitorModes, props, 0, null); + MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, currentMode, null, false, cache.monitorModes, props, 0, null); } @Override diff --git a/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java index d577ed501..fc4bf03a4 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java @@ -122,7 +122,7 @@ public class ScreenDriver extends ScreenImpl { 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(cache, this, crt_id, currentMode, null, cache.monitorModes, props, 0, null); + MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, currentMode, null, false, cache.monitorModes, props, 0, null); } @Override 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 62dbd0c72..3cdb368f2 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java @@ -97,7 +97,7 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl { 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(cache, this, crt_id, currentMode, null, cache.monitorModes, props, 0, null); + MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, currentMode, null, false, cache.monitorModes, props, 0, null); } @Override 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 9e05e1002..1b3807a94 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 @@ -90,7 +90,7 @@ public class ScreenDriver extends ScreenImpl { props[i++] = 0; // rotated viewport y window-units props[i++] = cachedWidth; // rotated viewport width window-units props[i++] = cachedHeight; // rotated viewport height window-units - MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, currentMode, null, cache.monitorModes, props, 0, null); + MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, currentMode, null, false, cache.monitorModes, props, 0, null); } @Override diff --git a/src/newt/classes/jogamp/newt/driver/egl/gbm/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/egl/gbm/ScreenDriver.java index 5281f0ddc..a08b5a445 100644 --- a/src/newt/classes/jogamp/newt/driver/egl/gbm/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/egl/gbm/ScreenDriver.java @@ -129,7 +129,7 @@ public class ScreenDriver extends ScreenImpl { props[i++] = 0; // rotated viewport y window-units props[i++] = mode[scridx].getHdisplay(); // rotated viewport width window-units props[i++] = mode[scridx].getVdisplay(); // rotated viewport height window-units - MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, currentMode, null, cache.monitorModes, props, 0, null); + MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, currentMode, null, false, cache.monitorModes, props, 0, null); crtc_ids = new int[] { encoder[scridx].getCrtc_id() }; 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 ceb2c4cc6..7eb6eea92 100644 --- a/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java @@ -99,7 +99,7 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl { 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(cache, this, crt_id, currentMode, null, cache.monitorModes, props, 0, null); + MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, currentMode, null, false, cache.monitorModes, props, 0, null); } @Override diff --git a/src/newt/classes/jogamp/newt/driver/ios/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/ios/ScreenDriver.java index de5cdd239..4cf459699 100644 --- a/src/newt/classes/jogamp/newt/driver/ios/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/ios/ScreenDriver.java @@ -177,7 +177,8 @@ public class ScreenDriver extends ScreenImpl { // merge monitor-props + supported modes final float pixelScale = crtProps.pixelScaleArray[crtIdx]; MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, currentMode, - new float[] { pixelScale, pixelScale }, supportedModes, crtProps.propsFixedArray[crtIdx], 0, null); + new float[] { pixelScale, pixelScale }, false /* invscale_wuviewport */, + supportedModes, crtProps.propsFixedArray[crtIdx], 0, null); } } diff --git a/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java index 3112aa88f..ba28e161d 100644 --- a/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java @@ -95,7 +95,7 @@ public class ScreenDriver extends ScreenImpl { 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(cache, this, crt_id, currentMode, null, cache.monitorModes, props, 0, null); + MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, currentMode, null, false, cache.monitorModes, props, 0, null); } @Override diff --git a/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java index a4823034f..635fffc0b 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/ScreenDriver.java @@ -183,7 +183,8 @@ public class ScreenDriver extends ScreenImpl { // merge monitor-props + supported modes final float pixelScale = crtProps.pixelScaleArray[crtIdx]; MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, currentMode, - new float[] { pixelScale, pixelScale }, supportedModes, crtProps.propsFixedArray[crtIdx], 0, null); + new float[] { pixelScale, pixelScale }, false /* invscale_wuviewport */, + supportedModes, crtProps.propsFixedArray[crtIdx], 0, null); } } diff --git a/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java index 002836e0c..c3aa94648 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java @@ -143,7 +143,8 @@ public class ScreenDriver extends ScreenImpl { monitor_handle = monitor_id; } // merge monitor-props + supported modes - MonitorModeProps.streamInMonitorDevice(cache, this, monitor_handle, currentMode, pixel_scale, supportedModes, monitorProps, 0, null); + MonitorModeProps.streamInMonitorDevice(cache, this, monitor_handle, currentMode, pixel_scale, true /* invscale_wuviewport */, + supportedModes, monitorProps, 0, null); // next monitor, 1st mode supportedModes = new ArrayHashSet<MonitorMode>(false, ArrayHashSet.DEFAULT_INITIAL_CAPACITY, ArrayHashSet.DEFAULT_LOAD_FACTOR); @@ -168,6 +169,7 @@ public class ScreenDriver extends ScreenImpl { 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++]); + viewportWU.scaleInv(pixelScale[0], pixelScale[1]); return true; } } diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java index fb20265ce..1605d4126 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java @@ -36,6 +36,7 @@ package jogamp.newt.driver.windows; import java.nio.ByteBuffer; +import jogamp.nativewindow.SurfaceScaleUtils; import jogamp.nativewindow.windows.GDI; import jogamp.nativewindow.windows.GDIUtil; import jogamp.newt.PointerIconImpl; @@ -47,11 +48,12 @@ import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.VisualIDHolder; import com.jogamp.nativewindow.util.InsetsImmutable; import com.jogamp.nativewindow.util.Point; - import com.jogamp.common.os.Platform; import com.jogamp.common.util.VersionNumber; +import com.jogamp.newt.MonitorDevice; import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.MonitorEvent; import com.jogamp.newt.event.MouseEvent; import com.jogamp.newt.event.MouseEvent.PointerType; @@ -61,7 +63,7 @@ public class WindowDriver extends WindowImpl { DisplayDriver.initSingleton(); } - private long hmon; + private volatile long hmon; private long hdc; private long hdc_old; private long windowHandleClose; @@ -69,6 +71,20 @@ public class WindowDriver extends WindowImpl { public WindowDriver() { } + /** + * Essentially updates {@code hasPixelScale} + */ + private boolean updatePixelScaleByMonitor(final long crt_handle, final int[] move_diff, final boolean sendEvent, final boolean defer) { + boolean res = false; + if( 0 != crt_handle ) { + final float newPixelScaleRaw[] = { 0, 0 }; + if( GDIUtil.GetMonitorPixelScale(crt_handle, newPixelScaleRaw) ) { + res = applySoftPixelScale(move_diff, sendEvent, defer, newPixelScaleRaw); + } + } + return res; + } + @Override protected int lockSurfaceImpl() { if (0 != hdc) { @@ -81,7 +97,14 @@ public class WindowDriver extends WindowImpl { if( 0 == hdc ) { return LOCK_SURFACE_NOT_READY; } - hmon = MonitorFromWindow0(hWnd); + if(DEBUG_IMPLEMENTATION) { + final long _hmon = GDIUtil.GetMonitorFromWindow(hWnd); + if (hmon != _hmon) { + System.err.println("Info: Window Device Changed (L) "+getThreadName()+ + ", HMON "+toHexString(hmon)+" -> "+toHexString(_hmon)); + // Thread.dumpStack(); + } + } // 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! @@ -113,20 +136,27 @@ public class WindowDriver extends WindowImpl { } @Override - public boolean hasDeviceChanged() { - if(0!=getWindowHandle()) { - final long _hmon = MonitorFromWindow0(getWindowHandle()); - if (hmon != _hmon) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Info: Window Device Changed "+Thread.currentThread().getName()+ - ", HMON "+toHexString(hmon)+" -> "+toHexString(_hmon)); - // Thread.dumpStack(); - } - hmon = _hmon; - return true; - } + protected void monitorModeChanged(final MonitorEvent me, final boolean success) { + if( hmon == me.getMonitor().getHandle() ) { + updatePixelScaleByMonitor(me.getMonitor().getHandle(), null, false /* sendEvent*/, false /* defer */); // send reshape event itself } - return false; + } + + @Override + public final boolean setSurfaceScale(final float[] pixelScale) { + super.setSurfaceScale(pixelScale); // pixelScale -> reqPixelScale + + boolean changed = false; + if( isNativeValid() ) { + changed = applySoftPixelScale(null, true /* sendEvent */, false /* defer */, reqPixelScale); + } + if( DEBUG_IMPLEMENTATION ) { + System.err.println("WindowDriver.setPixelScale: min["+minPixelScale[0]+", "+minPixelScale[1]+"], max["+ + maxPixelScale[0]+", "+maxPixelScale[1]+"], req["+ + reqPixelScale[0]+", "+reqPixelScale[1]+"] -> result["+ + hasPixelScale[0]+", "+hasPixelScale[1]+"] - changed "+changed+", realized "+isNativeValid()); + } + return changed; } @Override @@ -150,10 +180,14 @@ public class WindowDriver extends WindowImpl { flags |= CHANGE_MASK_MAXIMIZED_VERT; maxCount++; } + final int[] xy_pix = getPixelPosI(); + final int[] sz_pix = getPixelSizeI(); + + // this.convertToWindowUnits(null) final long _windowHandle = CreateWindow0(DisplayDriver.getHInstance(), display.getWindowClassName(), display.getWindowClassName(), winVer.getMajor(), winVer.getMinor(), getParentWindowHandle(), - getX(), getY(), getWidth(), getHeight(), flags); + xy_pix[0], xy_pix[1], sz_pix[0], sz_pix[1], flags); if ( 0 == _windowHandle ) { throw new NativeWindowException("Error creating window"); } @@ -164,10 +198,17 @@ public class WindowDriver extends WindowImpl { setWindowHandle(_windowHandle); windowHandleClose = _windowHandle; - if( 0 == ( STATE_MASK_CHILDWIN & flags ) && 1 == maxCount ) { - reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), flags); + if( 0 == ( STATE_MASK_CHILDWIN & flags ) && 1 <= maxCount ) { + reconfigureWindowImpl(xy_pix[0], xy_pix[1], sz_pix[0], sz_pix[1], flags); } + hmon = GDIUtil.GetMonitorFromWindow(_windowHandle); + boolean changedPixelScale = applySoftPixelScale(null, true /* sendEvent */, false /* defer */, reqPixelScale); + if( !changedPixelScale ) { + changedPixelScale = updatePixelScaleByMonitor(hmon, null, true /* sendEvent */, false /* defer */); + } + positionModified[0] = changedPixelScale; + if(DEBUG_IMPLEMENTATION) { final Exception e = new Exception("Info: Window new window handle "+Thread.currentThread().getName()+ " (Parent HWND "+toHexString(getParentWindowHandle())+ @@ -201,6 +242,7 @@ public class WindowDriver extends WindowImpl { windowHandleClose = 0; hdc = 0; hdc_old = 0; + hmon = 0; } @Override @@ -244,7 +286,11 @@ public class WindowDriver extends WindowImpl { if( changeDecoration && isTranslucent ) { GDIUtil.DwmSetupTranslucency(getWindowHandle(), false); } - reconfigureWindow0( getParentWindowHandle(), getWindowHandle(), x, y, width, height, flags); + final int xy_pix[] = SurfaceScaleUtils.scale(new int[2], x, y, hasPixelScale); + final int sz_pix[] = SurfaceScaleUtils.scale(new int[2], width, height, hasPixelScale); + reconfigureWindow0( getParentWindowHandle(), getWindowHandle(), + xy_pix[0], xy_pix[1], sz_pix[0], sz_pix[1], flags); + if( changeDecoration && isTranslucent ) { GDIUtil.DwmSetupTranslucency(getWindowHandle(), true); } @@ -259,6 +305,37 @@ public class WindowDriver extends WindowImpl { } @Override + protected boolean positionChanged(final boolean defer, final boolean windowUnits, final int newX, final int newY) { + final boolean res = super.positionChanged(defer, windowUnits, newX, newY); + + if ( res ) { + final long hWnd = getWindowHandle(); + if( 0 != hWnd ) { + final long _hmon = GDIUtil.GetMonitorFromWindow(hWnd); + if( hmon != _hmon ) { + final int[] move_diff = new int[] { 0, 0 }; + MonitorDevice.Orientation orientation = MonitorDevice.Orientation.clone; + // Move from md0 -> md1 + final MonitorDevice md0 = getScreen().getMonitorByHandle(hmon); + final MonitorDevice md1 = getScreen().getMonitorByHandle(_hmon); + if( null != md0 && null != md1 ) { + orientation = md1.getOrientationTo(md0, move_diff); + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Info: Window Device Changed (P: "+newX+"/"+newY+ + ", crt_move[orient "+orientation+", diff "+move_diff[0]+"/"+move_diff[1]+") "+ + ", HMON "+toHexString(hmon)+" -> "+toHexString(_hmon)+ + " - "+Thread.currentThread().getName()); + } + hmon = _hmon; + updatePixelScaleByMonitor(_hmon, move_diff, true /* sendEvent */, defer); + } + } + } + return res; + } + + @Override protected void requestFocusImpl(final boolean force) { requestFocus0(getWindowHandle(), force); } @@ -307,7 +384,8 @@ public class WindowDriver extends WindowImpl { this.runOnEDTIfAvail(true, new Runnable() { @Override public void run() { - final Point sPos = convertToPixelUnits( getLocationOnScreenImpl(x, y) ); + // shortcut from getLocationOnScreenImpl(..) while maintaining pixel-units + final Point sPos = GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y ); warpPointer0(getWindowHandle(), sPos.getX(), sPos.getY()); } }); @@ -316,7 +394,8 @@ public class WindowDriver extends WindowImpl { @Override protected Point getLocationOnScreenImpl(final int x, final int y) { - return GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); + final int xy_pix[] = SurfaceScaleUtils.scale(new int[2], x, y, hasPixelScale); + return convertToWindowUnits( GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, xy_pix[0], xy_pix[1]) ); } // diff --git a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java index 7fb70cc32..c6b91cbf6 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java @@ -37,9 +37,11 @@ import java.util.ArrayList; import java.util.List; import com.jogamp.nativewindow.AbstractGraphicsDevice; +import com.jogamp.nativewindow.ScalableSurface; import com.jogamp.nativewindow.util.Rectangle; import com.jogamp.nativewindow.util.RectangleImmutable; +import jogamp.nativewindow.SurfaceScaleUtils; import jogamp.nativewindow.x11.X11Util; import jogamp.newt.Debug; import jogamp.newt.DisplayImpl; @@ -57,11 +59,27 @@ import com.jogamp.newt.MonitorMode; public class ScreenDriver extends ScreenImpl { protected static final boolean DEBUG_TEST_RANDR13_DISABLED; + protected static final float[] global_pixel_scale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; + protected static final boolean global_pixel_scale_set; static { Debug.initSingleton(); DEBUG_TEST_RANDR13_DISABLED = PropertyAccess.isPropertyDefined("newt.test.Screen.disableRandR13", true); + final String[] env_var_names = new String[] { "GDK_SCALE", "QT_SCALE_FACTOR", "SOFT_SCALE" }; + int var_name_idx = -1; + try { + var_name_idx = SurfaceScaleUtils.getGlobalPixelScaleEnv(env_var_names, global_pixel_scale); + } catch (final Throwable t) { t.printStackTrace(); } + if( 0 <= var_name_idx && var_name_idx < env_var_names.length ) { + global_pixel_scale_set = true; + if( DEBUG ) { + System.err.println("X11Screen: Global PixelScale Set: "+env_var_names[var_name_idx]+": "+global_pixel_scale[0]+"/"+global_pixel_scale[1]); + } + } else { + global_pixel_scale_set = false; + } + DisplayDriver.initSingleton(); } @@ -120,6 +138,10 @@ public class ScreenDriver extends ScreenImpl { try { if( rAndR.beginInitialQuery(device.getHandle(), this) ) { try { + final float pixel_scale[] = { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + if( global_pixel_scale_set ) { + System.arraycopy(global_pixel_scale, 0, pixel_scale, 0, 2); + } final int[] crt_ids = rAndR.getMonitorDeviceIds(device.getHandle(), this); final int crtCount = null != crt_ids ? crt_ids.length : 0; @@ -155,7 +177,8 @@ public class ScreenDriver extends ScreenImpl { 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(cache, this, crt_id, null, monitorProps, 0, null); + MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, pixel_scale, true /* invscale_wuviewport */, + monitorProps, 0, null); } } } @@ -177,6 +200,7 @@ public class ScreenDriver extends ScreenImpl { if( null != viewportProps ) { 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 + viewportWU.scaleInv(pixelScale[0], pixelScale[1]); return true; } else { return false; diff --git a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java index c1a24797b..38c463e7c 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java @@ -36,6 +36,8 @@ package jogamp.newt.driver.x11; import java.nio.Buffer; +import jogamp.nativewindow.SurfaceScaleUtils; +import jogamp.nativewindow.windows.GDIUtil; import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; import jogamp.newt.DisplayImpl; @@ -53,9 +55,11 @@ import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.nativewindow.x11.X11GraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsScreen; +import com.jogamp.newt.MonitorDevice; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.MonitorEvent; import com.jogamp.newt.event.MouseEvent; public class WindowDriver extends WindowImpl { @@ -68,6 +72,8 @@ public class WindowDriver extends WindowImpl { private static final int defaultIconDataSize; private static final Buffer defaultIconData; + private volatile MonitorDevice last_monitor; + static { ScreenDriver.initSingleton(); @@ -94,8 +100,45 @@ public class WindowDriver extends WindowImpl { public WindowDriver() { } + /** + * Essentially updates {@code hasPixelScale} + */ + private boolean updatePixelScaleByMonitor(final MonitorDevice md, final int[] move_diff, final boolean sendEvent, final boolean defer) { + boolean res = false; + if( null != md ) { + final float newPixelScale[] = { 0, 0 }; + md.getPixelScale(newPixelScale); + res = applySoftPixelScale(move_diff, sendEvent, defer, newPixelScale); + } + return res; + } + + @Override + protected void monitorModeChanged(final MonitorEvent me, final boolean success) { + if( last_monitor == me.getMonitor() ) { + updatePixelScaleByMonitor(me.getMonitor(), null, false /* sendEvent*/, false /* defer */); // send reshape event itself + } + } + @Override - protected void createNativeImpl(boolean[] positionModified) { + public final boolean setSurfaceScale(final float[] pixelScale) { + super.setSurfaceScale(pixelScale); // pixelScale -> reqPixelScale + + boolean changed = false; + if( isNativeValid() ) { + changed = applySoftPixelScale(null, true /* sendEvent */, false /* defer */, reqPixelScale); + } + if( DEBUG_IMPLEMENTATION ) { + System.err.println("WindowDriver.setPixelScale: min["+minPixelScale[0]+", "+minPixelScale[1]+"], max["+ + maxPixelScale[0]+", "+maxPixelScale[1]+"], req["+ + reqPixelScale[0]+", "+reqPixelScale[1]+"] -> result["+ + hasPixelScale[0]+", "+hasPixelScale[1]+"] - changed "+changed+", realized "+isNativeValid()); + } + return changed; + } + + @Override + protected void createNativeImpl(final boolean[] positionModified) { final ScreenDriver screen = (ScreenDriver) getScreen(); final DisplayDriver display = (DisplayDriver) screen.getDisplay(); final AbstractGraphicsDevice edtDevice = display.getGraphicsDevice(); @@ -124,11 +167,14 @@ public class WindowDriver extends WindowImpl { setGraphicsConfiguration(cfg); final int flags = getReconfigureMask(0, true) & STATE_MASK_CREATENATIVE; edtDevice.lock(); + + final int[] xy_pix = getPixelPosI(); + final int[] sz_pix = getPixelSizeI(); try { final long[] handles = CreateWindow(getParentWindowHandle(), edtDevice.getHandle(), screen.getIndex(), visualID, display.getJavaObjectAtom(), display.getWindowDeleteAtom(), display.getXiOpcode(), - getX(), getY(), getWidth(), getHeight(), flags, + xy_pix[0], xy_pix[1], sz_pix[0], sz_pix[1], flags, defaultIconDataSize, defaultIconData, DEBUG_IMPLEMENTATION); if (null == handles || 2 != handles.length || 0 == handles[0] || 0 == handles[1] ) { throw new NativeWindowException("Error creating window"); @@ -138,6 +184,14 @@ public class WindowDriver extends WindowImpl { } setWindowHandle(handles[0]); javaWindowHandle = handles[1]; + + last_monitor = getMainMonitor(); + boolean changedPixelScale = applySoftPixelScale(null, true /* sendEvent */, false /* defer */, reqPixelScale); + if( !changedPixelScale ) { + changedPixelScale = updatePixelScaleByMonitor(last_monitor, null, true /* sendEvent */, false /* defer */); + } + positionModified[0] = changedPixelScale; + } finally { edtDevice.unlock(); } @@ -160,6 +214,7 @@ public class WindowDriver extends WindowImpl { } finally { edtDevice.unlock(); javaWindowHandle = 0; + last_monitor = null; } } if(null != renderDevice) { @@ -200,9 +255,13 @@ public class WindowDriver extends WindowImpl { _x = x; _y = y; } + final int xy_pix[] = SurfaceScaleUtils.scale(new int[2], _x, _y, hasPixelScale); + final int sz_pix[] = SurfaceScaleUtils.scale(new int[2], width, height, hasPixelScale); + if(DEBUG_IMPLEMENTATION) { - System.err.println("X11Window reconfig.0: "+x+"/"+y+" -> "+_x+"/"+_y+" "+width+"x"+height+", insets "+_insets+ - ", "+getReconfigStateMaskString(flags)); + System.err.println("X11Window reconfig.0: "+x+"/"+y+" -> "+_x+"/"+_y+" "+width+"x"+height+ + " -> pixel["+xy_pix[0]+"/"+xy_pix[1]+" "+sz_pix[0]+"x"+sz_pix[1]+ + "], insets "+_insets+", "+getReconfigStateMaskString(flags)); } if( 0 != ( CHANGE_MASK_FULLSCREEN & flags ) ) { if( 0 != ( STATE_MASK_FULLSCREEN & flags) && @@ -222,7 +281,7 @@ public class WindowDriver extends WindowImpl { @Override public Object run(final long dpy) { reconfigureWindow0( dpy, getScreenIndex(), - getParentWindowHandle(), javaWindowHandle, _x, _y, width, height, fflags); + getParentWindowHandle(), javaWindowHandle, xy_pix[0], xy_pix[1], sz_pix[0], sz_pix[1], fflags); return null; } }); @@ -259,6 +318,32 @@ public class WindowDriver extends WindowImpl { super.focusChanged(defer, focusGained); } + @Override + protected boolean positionChanged(final boolean defer, final boolean windowUnits, final int newX, final int newY) { + final boolean res = super.positionChanged(defer, windowUnits, newX, newY); + + if ( res ) { + if( isNativeValid() ) { + final MonitorDevice new_monitor = getMainMonitor(); + if( null != last_monitor && !new_monitor.equals(last_monitor) ) { + final int[] move_diff = new int[] { 0, 0 }; + MonitorDevice.Orientation orientation = MonitorDevice.Orientation.clone; + // Move from last_monitor -> new_monitor + orientation = new_monitor.getOrientationTo(last_monitor, move_diff); + if(DEBUG_IMPLEMENTATION) { + System.err.println("Info: Window Device Changed (P: "+newX+"/"+newY+ + ", crt_move[orient "+orientation+", diff "+move_diff[0]+"/"+move_diff[1]+") "+ + ", monitor "+last_monitor.getId()+" -> "+new_monitor.getId()+ + " - "+Thread.currentThread().getName()); + } + last_monitor = new_monitor; + updatePixelScaleByMonitor(new_monitor, move_diff, true /* sendEvent */, defer); + } + } + } + return res; + } + protected void reparentNotify(final long newParentWindowHandle) { if(DEBUG_IMPLEMENTATION) { final long p0 = getParentWindowHandle(); @@ -344,12 +429,14 @@ public class WindowDriver extends WindowImpl { @Override protected Point getLocationOnScreenImpl(final int x, final int y) { - return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Point>() { + final int xy_pix[] = SurfaceScaleUtils.scale(new int[2], x, y, hasPixelScale); + final Point res_pix = runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Point>() { @Override public Point run(final long dpy) { - return X11Lib.GetRelativeLocation(dpy, getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + return X11Lib.GetRelativeLocation(dpy, getScreenIndex(), getWindowHandle(), 0 /*root win*/, xy_pix[0], xy_pix[1]); } } ); + return convertToWindowUnits( res_pix ); } @Override |