diff options
author | Sven Gothel <[email protected]> | 2015-03-20 21:42:23 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-03-20 21:42:23 +0100 |
commit | 2c88b6dfd4eb7e2cd9a50fa48e08ecafc980931a (patch) | |
tree | 2d89ec775fdd59499a934d622462b8915b89cead /src/newt | |
parent | d9fe5c4aee7547bb89571c19c89ad173b63a4598 (diff) |
Bug 1147 - Fix XRandR13 Usage: Rotate / Change-Mode, use unique CRTC/Mode ids, ..
RandR 1.3 XRRSetCrtcConfig related:
- X11RandR13 now sets the new screen size via XRRSetScreenSize(..)
- X11RandR13 now propagates RRScreenChangeNotify events
via XRRUpdateConfiguration(event).
Hence reporting virtual desktop size now.
- X11RandR13 now disables the CRTC before XRRSetCrtcConfig(..)
to avoid invalid configuration (see spec)!
RandR 1.3 General:
- Uses unique id named instead of unstable index
for modes and CRTC.
This allows proper identification even for 'swizzled' devices.
Diffstat (limited to 'src/newt')
-rw-r--r-- | src/newt/classes/com/jogamp/newt/MonitorDevice.java | 1 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/MonitorModeProps.java | 2 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/ScreenImpl.java | 2 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java | 25 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/x11/RandR.java | 23 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/x11/RandR11.java | 104 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/x11/RandR13.java | 71 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java | 37 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java | 6 | ||||
-rw-r--r-- | src/newt/native/X11Display.c | 22 | ||||
-rw-r--r-- | src/newt/native/X11RandR11.c | 89 | ||||
-rw-r--r-- | src/newt/native/X11RandR13.c | 275 | ||||
-rw-r--r-- | src/newt/native/X11Screen.c | 6 | ||||
-rw-r--r-- | src/newt/native/X11Screen.h | 4 | ||||
-rw-r--r-- | src/newt/native/X11Window.c | 6 | ||||
-rw-r--r-- | src/newt/native/xrandr_utils.c | 322 |
16 files changed, 766 insertions, 229 deletions
diff --git a/src/newt/classes/com/jogamp/newt/MonitorDevice.java b/src/newt/classes/com/jogamp/newt/MonitorDevice.java index 4f06a946a..e96fc82f5 100644 --- a/src/newt/classes/com/jogamp/newt/MonitorDevice.java +++ b/src/newt/classes/com/jogamp/newt/MonitorDevice.java @@ -332,6 +332,7 @@ public abstract class MonitorDevice { /** * Set the current {@link com.jogamp.newt.MonitorMode}. + * <p>This method is <a href="Window.html#lifecycleHeavy">lifecycle heavy</a>.</p> * @param mode to be made current, must be element of the list {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}. * @return true if successful, otherwise false * @throws IllegalStateException if the {@link #getScreen() associated screen} is not {@link Screen#isNativeValid() valid natively}. diff --git a/src/newt/classes/jogamp/newt/MonitorModeProps.java b/src/newt/classes/jogamp/newt/MonitorModeProps.java index 073a9a355..4e2806118 100644 --- a/src/newt/classes/jogamp/newt/MonitorModeProps.java +++ b/src/newt/classes/jogamp/newt/MonitorModeProps.java @@ -272,7 +272,7 @@ public class MonitorModeProps { * @param cache hash arrays of unique {@link MonitorMode} components and {@link MonitorDevice}s, allowing to avoid duplicates * @param screen the associated {@link ScreenImpl} * @param pixelScale pre-fetched current pixel-scale, maybe {@code null} for {@link ScalableSurface#IDENTITY_PIXELSCALE}. - * @param monitorProperties the input data minus supported modes! + * @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}. * @return {@link MonitorDevice} of the identical (old or new) element in {@link Cache#monitorDevices}, diff --git a/src/newt/classes/jogamp/newt/ScreenImpl.java b/src/newt/classes/jogamp/newt/ScreenImpl.java index c96a2e06e..347ea650e 100644 --- a/src/newt/classes/jogamp/newt/ScreenImpl.java +++ b/src/newt/classes/jogamp/newt/ScreenImpl.java @@ -440,7 +440,7 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { monitor.getMutuableViewportPU(), monitor.getMutuableViewportWU()); if( DEBUG ) { - System.err.println("Screen.updateMonitorViewport["+i+"] @ "+Thread.currentThread().getName()+": updated: "+viewportUpdated+ + System.err.println("Screen.updateMonitorViewport["+Display.toHexString(monitor.getId())+"] @ "+Thread.currentThread().getName()+": updated: "+viewportUpdated+ ", PU "+monitor.getViewport()+", WU "+monitor.getViewportInWindowUnits()+ ", pixelScale ["+pixelScale[0]+", "+pixelScale[1]+"]"); } diff --git a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java index 3276f3ed1..81ccdbfcd 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java @@ -40,7 +40,6 @@ import java.nio.ByteBuffer; import com.jogamp.nativewindow.AbstractGraphicsDevice; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.util.PixelFormat; - import com.jogamp.common.nio.Buffers; import com.jogamp.nativewindow.x11.X11GraphicsDevice; @@ -110,7 +109,8 @@ public class DisplayDriver extends DisplayImpl { try { final long handle = _aDevice.getHandle(); if(0 != handle) { - DispatchMessages0(handle, javaObjectAtom, windowDeleteAtom /*, kbdHandle */); // XKB disabled for now + DispatchMessages0(handle, javaObjectAtom, windowDeleteAtom /*, kbdHandle */, // XKB disabled for now + randr_event_base, randr_error_base); } } finally { _aDevice.unlock(); @@ -120,6 +120,8 @@ public class DisplayDriver extends DisplayImpl { protected long getJavaObjectAtom() { return javaObjectAtom; } protected long getWindowDeleteAtom() { return windowDeleteAtom; } // protected long getKbdHandle() { return kbdHandle; } // XKB disabled for now + protected int getRandREventBase() { return randr_event_base; } + protected int getRandRErrorBase() { return randr_error_base; } /** Returns <code>null</code> if !{@link #isNativeValid()}, otherwise the Boolean value of {@link X11GraphicsDevice#isXineramaEnabled()}. */ protected Boolean isXineramaEnabled() { return isNativeValid() ? Boolean.valueOf(((X11GraphicsDevice)aDevice).isXineramaEnabled()) : null; } @@ -142,14 +144,26 @@ public class DisplayDriver extends DisplayImpl { private native void CompleteDisplay0(long handle); - private void displayCompleted(final long javaObjectAtom, final long windowDeleteAtom /*, long kbdHandle */) { + private void displayCompleted(final long javaObjectAtom, final long windowDeleteAtom /*, long kbdHandle */, + final int randr_event_base, final int randr_error_base) { this.javaObjectAtom=javaObjectAtom; this.windowDeleteAtom=windowDeleteAtom; // this.kbdHandle = kbdHandle; // XKB disabled for now + this.randr_event_base = randr_event_base; + this.randr_error_base = randr_error_base; + } + private void sendRRScreenChangeNotify(final long event) { + if( null != rAndR ) { + rAndR.sendRRScreenChangeNotify(getHandle(), event); + } + } + void registerRandR(final RandR rAndR) { + this.rAndR = rAndR; } private native void DisplayRelease0(long handle, long javaObjectAtom, long windowDeleteAtom /*, long kbdHandle */); // XKB disabled for now - private native void DispatchMessages0(long display, long javaObjectAtom, long windowDeleteAtom /* , long kbdHandle */); // XKB disabled for now + private native void DispatchMessages0(long display, long javaObjectAtom, long windowDeleteAtom /* , long kbdHandle */, // XKB disabled for now + final int randr_event_base, final int randr_error_base); private static long createPointerIcon(final long display, final Buffer pixels, final int width, final int height, final int hotX, final int hotY) { final boolean pixels_is_direct = Buffers.isDirect(pixels); @@ -171,5 +185,8 @@ public class DisplayDriver extends DisplayImpl { /** X11 Keyboard handle used on EDT */ // private long kbdHandle; // XKB disabled for now + private int randr_event_base, randr_error_base; + + private RandR rAndR; } diff --git a/src/newt/classes/jogamp/newt/driver/x11/RandR.java b/src/newt/classes/jogamp/newt/driver/x11/RandR.java index 14c9c0856..f45762173 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/RandR.java +++ b/src/newt/classes/jogamp/newt/driver/x11/RandR.java @@ -43,6 +43,8 @@ public interface RandR { public static final VersionNumber version140 = new VersionNumber(1, 4, 0); VersionNumber getVersion(); + @Override + String toString(); void dumpInfo(final long dpy, final int screen_idx); @@ -50,7 +52,7 @@ public interface RandR { * Encapsulate initial device query allowing caching of internal data structures. * Methods covered: * <ul> - * <li>{@link #getMonitorDeviceCount(long, ScreenDriver)}</li> + * <li>{@link #getMonitorDeviceIds(long, ScreenDriver)}</li> * <li>{@link #getAvailableRotations(long, ScreenDriver, int)}</li> * <li>{@link #getMonitorModeProps(long, ScreenDriver, int)}</li> * <li>{@link #getCurrentMonitorModeProps(long, ScreenDriver, int)</li> @@ -67,8 +69,8 @@ public interface RandR { boolean beginInitialQuery(long dpy, ScreenDriver screen); void endInitialQuery(long dpy, ScreenDriver screen); - int getMonitorDeviceCount(final long dpy, final ScreenDriver screen); - int[] getAvailableRotations(final long dpy, final ScreenDriver screen, final int crt_idx); + int[] getMonitorDeviceIds(final long dpy, final ScreenDriver screen); + int[] getAvailableRotations(final long dpy, final ScreenDriver screen, final int crt_id); /** * * @param dpy @@ -77,10 +79,15 @@ public interface RandR { * @return props w/o actual rotation */ int[] getMonitorModeProps(final long dpy, final ScreenDriver screen, final int mode_idx); - int[] getMonitorDeviceProps(final long dpy, final ScreenDriver screen, MonitorModeProps.Cache cache, final int crt_idx); - int[] getMonitorDeviceViewport(final long dpy, final ScreenDriver screen, final int crt_idx); - int[] getCurrentMonitorModeProps(final long dpy, final ScreenDriver screen, final int crt_idx); - boolean setCurrentMonitorMode(final long dpy, final ScreenDriver screen, MonitorDevice monitor, final MonitorMode mode); + int[] getMonitorDeviceProps(final long dpy, final ScreenDriver screen, MonitorModeProps.Cache cache, final int crt_id); + int[] getMonitorDeviceViewport(final long dpy, final ScreenDriver screen, final int crt_id); + int[] getCurrentMonitorModeProps(final long dpy, final ScreenDriver screen, final int crt_id); + /** The device shall be locked, blocking message handling. */ + boolean setCurrentMonitorModeStart(final long dpy, final ScreenDriver screen, MonitorDevice monitor, final MonitorMode mode); + /** The device must not be locked, allowing message handling. */ + boolean setCurrentMonitorModeWait(final ScreenDriver screen); + /** Invoked from Display's EDT thread for message handling. */ + void sendRRScreenChangeNotify(final long dpy, final long event); - public void updateScreenViewport(final long dpy, final ScreenDriver screen, RectangleImmutable viewport); + void updateScreenViewport(final long dpy, final ScreenDriver screen, RectangleImmutable viewport); } diff --git a/src/newt/classes/jogamp/newt/driver/x11/RandR11.java b/src/newt/classes/jogamp/newt/driver/x11/RandR11.java index e9cb95548..8fd03320a 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/RandR11.java +++ b/src/newt/classes/jogamp/newt/driver/x11/RandR11.java @@ -40,12 +40,19 @@ import com.jogamp.newt.Screen; class RandR11 implements RandR { private static final boolean DEBUG = ScreenDriver.DEBUG; - RandR11() { + private static final int SINGLE_CRT_ID = 0x01; + + private final VersionNumber version; + + RandR11(final VersionNumber version) { + this.version = version; } @Override - public final VersionNumber getVersion() { - return version110; + public final VersionNumber getVersion() { return version; } + @Override + public String toString() { + return "RandR11[version "+version+"]"; } @Override @@ -104,13 +111,14 @@ class RandR11 implements RandR { } @Override - public int getMonitorDeviceCount(final long dpy, final ScreenDriver screen) { - return 1; + public int[] getMonitorDeviceIds(final long dpy, final ScreenDriver screen) { + // RandR11 only supports 1 CRT + return new int[] { SINGLE_CRT_ID }; } @Override - public int[] getAvailableRotations(final long dpy, final ScreenDriver screen, final int crt_idx) { - if( 0 < crt_idx ) { + public int[] getAvailableRotations(final long dpy, final ScreenDriver screen, final int crt_id) { + if( SINGLE_CRT_ID != crt_id ) { // RandR11 only supports 1 CRT return null; } @@ -171,12 +179,12 @@ class RandR11 implements RandR { } @Override - public int[] getMonitorDeviceProps(final long dpy, final ScreenDriver screen, final MonitorModeProps.Cache cache, final int crt_idx) { - if( 0 < crt_idx ) { + public int[] getMonitorDeviceProps(final long dpy, final ScreenDriver screen, final MonitorModeProps.Cache cache, final int crt_id) { + if( SINGLE_CRT_ID != crt_id ) { // RandR11 only supports 1 CRT return null; } - final int[] currentModeProps = getCurrentMonitorModeProps(dpy, screen, crt_idx); + final int[] currentModeProps = getCurrentMonitorModeProps(dpy, screen, crt_id); if( null == currentModeProps) { // disabled return null; } @@ -185,9 +193,9 @@ class RandR11 implements RandR { final int[] props = new int[MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES - 1 + allModesCount]; int i = 0; props[i++] = props.length; - props[i++] = crt_idx; + props[i++] = SINGLE_CRT_ID; props[i++] = 0; // is-clone - props[i++] = 0 == crt_idx ? 1 : 0; // is-primary + props[i++] = 0 == crt_id ? 1 : 0; // is-primary props[i++] = widthMM; props[i++] = heightMM; props[i++] = 0; // rotated viewport x pixel-units @@ -207,8 +215,8 @@ class RandR11 implements RandR { } @Override - public int[] getMonitorDeviceViewport(final long dpy, final ScreenDriver screen, final int crt_idx) { - if( 0 < crt_idx ) { + public int[] getMonitorDeviceViewport(final long dpy, final ScreenDriver screen, final int crt_id) { + if( SINGLE_CRT_ID != crt_id ) { // RandR11 only supports 1 CRT return null; } @@ -252,8 +260,8 @@ class RandR11 implements RandR { } @Override - public int[] getCurrentMonitorModeProps(final long dpy, final ScreenDriver screen, final int crt_idx) { - if( 0 < crt_idx ) { + public int[] getCurrentMonitorModeProps(final long dpy, final ScreenDriver screen, final int crt_id) { + if( SINGLE_CRT_ID != crt_id ) { // RandR11 only supports 1 CRT return null; } @@ -313,35 +321,63 @@ class RandR11 implements RandR { } @Override - public boolean setCurrentMonitorMode(final long dpy, final ScreenDriver screen, final MonitorDevice monitor, final MonitorMode mode) { - final long t0 = System.currentTimeMillis(); - boolean done = false; + public boolean setCurrentMonitorModeStart(final long dpy, final ScreenDriver screen, final MonitorDevice monitor, final MonitorMode mode) { final int screen_idx = screen.getIndex(); final long screenConfigHandle = getScreenConfiguration0(dpy, screen_idx); if(0 == screenConfigHandle) { - return Boolean.valueOf(done); + return false; } + boolean res = false; try { - final int resId = mode.getId(); - if(0>resId || resId>=resolutionCount) { - throw new RuntimeException("Invalid resolution index: ! 0 < "+resId+" < "+resolutionCount+", "+monitor+", "+mode); + final int mode_idx = mode.getId(); + if(0>mode_idx || mode_idx>=resolutionCount) { + throw new RuntimeException("Invalid resolution index: ! 0 < "+mode_idx+" < "+resolutionCount+", "+monitor+", "+mode); } - final int f = (int)mode.getRefreshRate(); // simply cut-off, orig is int - final int r = mode.getRotation(); - - if( setCurrentScreenModeStart0(dpy, screen_idx, screenConfigHandle, resId, f, r) ) { - while(!done && System.currentTimeMillis()-t0 < Screen.SCREEN_MODE_CHANGE_TIMEOUT) { - done = setCurrentScreenModePollEnd0(dpy, screen_idx, resId, f, r); - if(!done) { - try { Thread.sleep(10); } catch (final InterruptedException e) { } - } - } + final int freq = (int)mode.getRefreshRate(); // simply cut-off, orig is int + final int rot = mode.getRotation(); + set_screen_idx = screen_idx; + set_mode_idx = mode_idx; + set_freq = freq; + set_rot = rot; + set_done = false; + res = setCurrentScreenModeStart0(dpy, screen_idx, screenConfigHandle, mode_idx, freq, rot); + if( !res ) { + clearSetModeState(); } } finally { freeScreenConfiguration0(screenConfigHandle); } + return res; + } + @Override + public boolean setCurrentMonitorModeWait(final ScreenDriver screen) { + final long t0 = System.currentTimeMillis(); + boolean done = false; + while(!done && System.currentTimeMillis()-t0 < Screen.SCREEN_MODE_CHANGE_TIMEOUT) { + done = set_done; + if(!done) { + try { Thread.sleep(10); } catch (final InterruptedException e) { } + } + } + clearSetModeState(); return done; } + volatile int set_screen_idx; + volatile int set_mode_idx; + volatile int set_freq; + volatile int set_rot; + volatile boolean set_done; + @Override + public void sendRRScreenChangeNotify(final long dpy, final long event) { + set_done = sendRRScreenChangeNotify0(dpy, set_screen_idx, event, set_mode_idx, set_freq, set_rot); + } + private void clearSetModeState() { + set_screen_idx = -1; + set_mode_idx = -1; + set_freq = 0; + set_rot = 0; + set_done = false; + } @Override public final void updateScreenViewport(final long dpy, final ScreenDriver screen, final RectangleImmutable viewport) { @@ -367,6 +403,6 @@ class RandR11 implements RandR { /** needs own Display connection for XRANDR event handling */ private static native boolean setCurrentScreenModeStart0(long display, int screen_index, long screenConfiguration, int mode_index, int freq, int rot); - private static native boolean setCurrentScreenModePollEnd0(long display, int screen_index, int mode_index, int freq, int rot); + private static native boolean sendRRScreenChangeNotify0(long display, int screen_index, final long event, int mode_index, int freq, int rot); } diff --git a/src/newt/classes/jogamp/newt/driver/x11/RandR13.java b/src/newt/classes/jogamp/newt/driver/x11/RandR13.java index 2f7110b5c..95bff0118 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/RandR13.java +++ b/src/newt/classes/jogamp/newt/driver/x11/RandR13.java @@ -47,13 +47,17 @@ import com.jogamp.newt.MonitorMode; */ class RandR13 implements RandR { private static final boolean DEBUG = ScreenDriver.DEBUG; + private final VersionNumber version; - RandR13() { + RandR13(final VersionNumber version) { + this.version = version; } @Override - public final VersionNumber getVersion() { - return version130; + public final VersionNumber getVersion() { return version; } + @Override + public String toString() { + return "RandR13[version "+version+"]"; } @Override @@ -113,16 +117,16 @@ class RandR13 implements RandR { } } - private final long getMonitorInfoHandle(final long dpy, final int screen_idx, final long screenResources, final int monitor_idx) { + private final long getMonitorInfoHandle(final long dpy, final int screen_idx, final long screenResources, final int crt_id) { if( null != crtInfoHandleMap ) { - long h = crtInfoHandleMap.get(monitor_idx); + long h = crtInfoHandleMap.get(crt_id); if( 0 == h ) { - h = getMonitorInfoHandle0(dpy, screen_idx, screenResources, monitor_idx); - crtInfoHandleMap.put(monitor_idx, h); + h = getMonitorInfoHandle0(dpy, screen_idx, screenResources, crt_id); + crtInfoHandleMap.put(crt_id, h); } return h; } else { - return getMonitorInfoHandle0(dpy, screen_idx, screenResources, monitor_idx); + return getMonitorInfoHandle0(dpy, screen_idx, screenResources, crt_id); } } private final void releaseMonitorInfoHandle(final long monitorInfoHandle) { @@ -132,22 +136,22 @@ class RandR13 implements RandR { } @Override - public int getMonitorDeviceCount(final long dpy, final ScreenDriver screen) { + public int[] getMonitorDeviceIds(final long dpy, final ScreenDriver screen) { final int screen_idx = screen.getIndex(); final long screenResources = getScreenResourceHandle(dpy, screen_idx); try { - return getMonitorDeviceCount0(screenResources); + return getMonitorDeviceIds0(screenResources); } finally { releaseScreenResourceHandle(screenResources); } } @Override - public int[] getAvailableRotations(final long dpy, final ScreenDriver screen, final int crt_idx) { + public int[] getAvailableRotations(final long dpy, final ScreenDriver screen, final int crt_id) { final int screen_idx = screen.getIndex(); final long screenResources = getScreenResourceHandle(dpy, screen_idx); try { - final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_idx); + final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_id); try { final int[] availRotations = getAvailableRotations0(monitorInfo); if(null==availRotations || 0==availRotations.length) { @@ -174,13 +178,13 @@ class RandR13 implements RandR { } @Override - public int[] getMonitorDeviceProps(final long dpy, final ScreenDriver screen, final MonitorModeProps.Cache cache, final int crt_idx) { + public int[] getMonitorDeviceProps(final long dpy, final ScreenDriver screen, final MonitorModeProps.Cache cache, final int crt_id) { final int screen_idx = screen.getIndex(); final long screenResources = getScreenResourceHandle(dpy, screen_idx); try { - final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_idx); + final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_id); try { - return getMonitorDevice0(dpy, screenResources, monitorInfo, crt_idx); + return getMonitorDevice0(dpy, screenResources, monitorInfo, crt_id); } finally { releaseMonitorInfoHandle(monitorInfo); } @@ -190,11 +194,11 @@ class RandR13 implements RandR { } @Override - public int[] getMonitorDeviceViewport(final long dpy, final ScreenDriver screen, final int crt_idx) { + public int[] getMonitorDeviceViewport(final long dpy, final ScreenDriver screen, final int crt_id) { final int screen_idx = screen.getIndex(); final long screenResources = getScreenResourceHandle(dpy, screen_idx); try { - final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_idx); + final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_id); try { return getMonitorViewport0(monitorInfo); } finally { @@ -206,11 +210,11 @@ class RandR13 implements RandR { } @Override - public int[] getCurrentMonitorModeProps(final long dpy, final ScreenDriver screen, final int crt_idx) { + public int[] getCurrentMonitorModeProps(final long dpy, final ScreenDriver screen, final int crt_id) { final int screen_idx = screen.getIndex(); final long screenResources = getScreenResourceHandle(dpy, screen_idx); try { - final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_idx); + final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, crt_id); try { return getMonitorCurrentMode0(screenResources, monitorInfo); } finally { @@ -222,15 +226,15 @@ class RandR13 implements RandR { } @Override - public boolean setCurrentMonitorMode(final long dpy, final ScreenDriver screen, final MonitorDevice monitor, final MonitorMode mode) { + public boolean setCurrentMonitorModeStart(final long dpy, final ScreenDriver screen, final MonitorDevice monitor, final MonitorMode mode) { final int screen_idx = screen.getIndex(); final long screenResources = getScreenResourceHandle(dpy, screen_idx); final boolean res; try { final long monitorInfo = getMonitorInfoHandle(dpy, screen_idx, screenResources, monitor.getId()); try { - res = setMonitorMode0(dpy, screenResources, monitorInfo, monitor.getId(), mode.getId(), mode.getRotation(), - -1, -1); // no fixed position! + res = setMonitorMode0(dpy, screen_idx, screenResources, monitorInfo, monitor.getId(), + mode.getId(), mode.getRotation(), -1, -1); // no fixed position! } finally { releaseMonitorInfoHandle(monitorInfo); } @@ -239,6 +243,15 @@ class RandR13 implements RandR { } return res; } + @Override + public void sendRRScreenChangeNotify(final long dpy, final long event) { + sendRRScreenChangeNotify0(dpy, event); + } + @Override + public boolean setCurrentMonitorModeWait(final ScreenDriver screen) { + // RandR13 set command waits until done .. + return true; + } @Override public final void updateScreenViewport(final long dpy, final ScreenDriver screen, final RectangleImmutable viewport) { @@ -255,9 +268,9 @@ class RandR13 implements RandR { private static native void freeScreenResources0(long screenResources); private static native void dumpInfo0(long display, int screen_index, long screenResources); - private static native int getMonitorDeviceCount0(long screenResources); + private static native int[] getMonitorDeviceIds0(long screenResources); - private static native long getMonitorInfoHandle0(long display, int screen_index, long screenResources, int monitor_index); + private static native long getMonitorInfoHandle0(long display, int screen_index, long screenResources, int crtc_id); private static native void freeMonitorInfoHandle0(long monitorInfoHandle); private static native int[] getAvailableRotations0(long monitorInfo); @@ -266,8 +279,12 @@ class RandR13 implements RandR { private static native int[] getMonitorMode0(long screenResources, int mode_index); private static native int[] getMonitorCurrentMode0(long screenResources, long monitorInfo); - private static native int[] getMonitorDevice0(long display, long screenResources, long monitorInfo, int monitor_idx); + private static native int[] getMonitorDevice0(long display, long screenResources, long monitorInfo, int crtc_id); - private static native boolean setMonitorMode0(long display, long screenResources, long monitorInfo, int monitor_idx, int mode_id, int rotation, int x, int y); - private static native boolean setScreenViewport0(long display, int screen_index, long screenResources, int x, int y, int width, int height); + private static native boolean setMonitorMode0(long display, int screen_index, long screenResources, + long monitorInfo, int crtc_id, + int mode_id, int rotation, int x, int y); + private static native boolean setScreenViewport0(long display, int screen_index, long screenResources, + int x, int y, int width, int height); + private static native void sendRRScreenChangeNotify0(long display, final long event); } diff --git a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java index 993ff58f9..2dc416063 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java @@ -91,15 +91,16 @@ public class ScreenDriver extends ScreenImpl { } { if( !DEBUG_TEST_RANDR13_DISABLED && randrVersion.compareTo(RandR.version130) >= 0 ) { - rAndR = new RandR13(); + rAndR = new RandR13(randrVersion); } else if( randrVersion.compareTo(RandR.version110) >= 0 ) { - rAndR = new RandR11(); + rAndR = new RandR11(randrVersion); } else { rAndR = null; } } + ((DisplayDriver)display).registerRandR(rAndR); if( DEBUG ) { - System.err.println("RandR "+randrVersion+", "+rAndR); + System.err.println("Using "+rAndR); rAndR.dumpInfo(dpy, screen_idx); } } @@ -119,12 +120,13 @@ public class ScreenDriver extends ScreenImpl { try { if( rAndR.beginInitialQuery(device.getHandle(), this) ) { try { - final int crtCount = rAndR.getMonitorDeviceCount(device.getHandle(), this); + final int[] crt_ids = rAndR.getMonitorDeviceIds(device.getHandle(), this); + final int crtCount = crt_ids.length; // Gather all available rotations final ArrayHashSet<Integer> availableRotations = new ArrayHashSet<Integer>(); for(int i = 0; i < crtCount; i++) { - final int[] rotations = rAndR.getAvailableRotations(device.getHandle(), this, i); + final int[] rotations = rAndR.getAvailableRotations(device.getHandle(), this, crt_ids[i]); if( null != rotations ) { final List<Integer> rotationList = new ArrayList<Integer>(rotations.length); for(int j=0; j<rotations.length; j++ ) { rotationList.add(rotations[j]); } @@ -148,7 +150,7 @@ public class ScreenDriver extends ScreenImpl { } if( cache.monitorModes.size() > 0 ) { for(int i = 0; i < crtCount; i++) { - final int[] monitorProps = rAndR.getMonitorDeviceProps(device.getHandle(), this, cache, i); + final int[] monitorProps = rAndR.getMonitorDeviceProps(device.getHandle(), this, cache, crt_ids[i]); if( null != monitorProps && MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES <= monitorProps[0] && // Enabled ? I.e. contains active modes ? MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES <= monitorProps.length ) { @@ -196,16 +198,21 @@ public class ScreenDriver extends ScreenImpl { if( null == rAndR ) { return false; } final long t0 = System.currentTimeMillis(); - final boolean done = runWithOptTempDisplayHandle( new DisplayImpl.DisplayRunnable<Boolean>() { + final boolean started = runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Boolean>() { @Override public Boolean run(final long dpy) { - return Boolean.valueOf( rAndR.setCurrentMonitorMode(dpy, ScreenDriver.this, monitor, mode) ); + return Boolean.valueOf( rAndR.setCurrentMonitorModeStart(dpy, ScreenDriver.this, monitor, mode) ); } }).booleanValue(); - + final boolean done; + if( started ) { + done = rAndR.setCurrentMonitorModeWait(this); + } else { + done = false; + } if(DEBUG || !done) { - System.err.println("X11Screen.setCurrentMonitorModeImpl: TO ("+SCREEN_MODE_CHANGE_TIMEOUT+") reached: "+ - (System.currentTimeMillis()-t0)+"ms; "+monitor.getCurrentMode()+" -> "+mode); + System.err.println("X11Screen.setCurrentMonitorModeImpl: "+(done?" OK":"NOK")+" (started "+started+"): t/TO "+ + (System.currentTimeMillis()-t0)+"/"+SCREEN_MODE_CHANGE_TIMEOUT+"ms; "+monitor.getCurrentMode()+" -> "+mode); } return done; } @@ -276,14 +283,6 @@ public class ScreenDriver extends ScreenImpl { return res; } - private final <T> T runWithOptTempDisplayHandle(final DisplayRunnable<T> action) { - if( null != rAndR && rAndR.getVersion().compareTo(RandR.version130) >= 0 ) { - return display.runWithLockedDisplayDevice(action); - } else { - return runWithTempDisplayHandle(action); - } - } - private static native long GetScreen0(long dpy, int scrn_idx); private static native int getWidth0(long display, int scrn_idx); diff --git a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java index cdeb7d6d0..6cf9727f2 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java @@ -149,7 +149,8 @@ public class WindowDriver extends WindowImpl { edtDevice.lock(); try { CloseWindow0(edtDevice.getHandle(), windowHandleClose, - display.getJavaObjectAtom(), display.getWindowDeleteAtom() /* , display.getKbdHandle() */); // XKB disabled for now + display.getJavaObjectAtom(), display.getWindowDeleteAtom() /* , display.getKbdHandle() */, // XKB disabled for now + display.getRandREventBase(), display.getRandRErrorBase()); } catch (final Throwable t) { if(DEBUG_IMPLEMENTATION) { final Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t); @@ -451,7 +452,8 @@ public class WindowDriver extends WindowImpl { int visualID, long javaObjectAtom, long windowDeleteAtom, int x, int y, int width, int height, boolean autoPosition, int flags, int pixelDataSize, Object pixels, int pixels_byte_offset, boolean pixels_is_direct); - private native void CloseWindow0(long display, long windowHandle, long javaObjectAtom, long windowDeleteAtom /*, long kbdHandle*/ ); // XKB disabled for now + private native void CloseWindow0(long display, long windowHandle, long javaObjectAtom, long windowDeleteAtom /*, long kbdHandle*/, // XKB disabled for now + final int randr_event_base, final int randr_error_base); private native void reconfigureWindow0(long display, int screen_index, long parentWindowHandle, long windowHandle, long windowDeleteAtom, int x, int y, int width, int height, int flags); private native void requestFocus0(long display, long windowHandle, boolean force); diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index 60daf1af2..b79c1ee95 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -39,6 +39,7 @@ jmethodID visibleChangedID = NULL; static const char * const ClazzNameX11NewtWindow = "jogamp/newt/driver/x11/WindowDriver"; static jmethodID displayCompletedID = NULL; +static jmethodID sendRRScreenChangeNotifyID = NULL; static jmethodID getCurrentThreadNameID = NULL; static jmethodID dumpStackID = NULL; @@ -242,8 +243,9 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 } } - // displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJJ)V"); // Variant using XKB - displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJ)V"); + // displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJJII)V"); // Variant using XKB + displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJII)V"); + sendRRScreenChangeNotifyID = (*env)->GetMethodID(env, clazz, "sendRRScreenChangeNotify", "(J)V"); getCurrentThreadNameID = (*env)->GetStaticMethodID(env, X11NewtWindowClazz, "getCurrentThreadName", "()Ljava/lang/String;"); dumpStackID = (*env)->GetStaticMethodID(env, X11NewtWindowClazz, "dumpStack", "()V"); insetsChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "insetsChanged", "(ZIIII)V"); @@ -259,6 +261,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 requestFocusID = (*env)->GetMethodID(env, X11NewtWindowClazz, "requestFocus", "(Z)V"); if (displayCompletedID == NULL || + sendRRScreenChangeNotifyID == NULL || getCurrentThreadNameID == NULL || dumpStackID == NULL || insetsChangedID == NULL || @@ -311,9 +314,13 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_CompleteDisplay // XSetCloseDownMode(dpy, RetainTemporary); // Just a try .. // kbdHandle = (jlong) (intptr_t) XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd); // XKB disabled for now + int randr_event_base, randr_error_base; + XRRQueryExtension(dpy, &randr_event_base, &randr_error_base); + DBG_PRINT("X11: X11Display_completeDisplay dpy %p\n", dpy); - (*env)->CallVoidMethod(env, obj, displayCompletedID, javaObjectAtom, windowDeleteAtom /*, kbdHandle*/); // XKB disabled for now + (*env)->CallVoidMethod(env, obj, displayCompletedID, javaObjectAtom, windowDeleteAtom /*, kbdHandle*/, // XKB disabled for now + randr_event_base, randr_error_base); } /* @@ -349,7 +356,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DisplayRelease0 * Signature: (JJJ)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0 - (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong windowDeleteAtom /*, jlong kbdHandle*/) + (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong windowDeleteAtom /*, jlong kbdHandle*/, + jint randr_event_base, jint randr_error_base) { Display * dpy = (Display *) (intptr_t) display; Atom wm_delete_atom = (Atom)windowDeleteAtom; @@ -397,6 +405,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage return ; } + if( randr_event_base > 0 && RRScreenChangeNotify == ( evt.type - randr_event_base ) ) { + DBG_PRINT( "X11: DispatchMessages dpy %p, Event RRScreenChangeNotify %p\n", (void*)dpy, (void*)&evt); + (*env)->CallVoidMethod(env, obj, sendRRScreenChangeNotifyID, (jlong)(intptr_t)&evt); + continue; + } + if( 0==evt.xany.window ) { DBG_PRINT( "X11: DispatchMessages dpy %p, Event %d - Window NULL, ignoring\n", (void*)dpy, (int)evt.type); continue; diff --git a/src/newt/native/X11RandR11.c b/src/newt/native/X11RandR11.c index 38d61289b..8d2651d61 100644 --- a/src/newt/native/X11RandR11.c +++ b/src/newt/native/X11RandR11.c @@ -297,75 +297,56 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_RandR11_setCurrentScreenM DBG_PRINT("X11Screen.setCurrentScreenMode0: CHANGED TO %d: %d x %d PIXELS, %d Hz, %d degree\n", resMode_idx, xrrs[resMode_idx].width, xrrs[resMode_idx].height, (int)freq, rotation); - int xrot = NewtScreen_Degree2XRotation(env, rotation); - XRRSelectInput (dpy, root, RRScreenChangeNotifyMask); - - XSync(dpy, False); + Rotation xrot = NewtScreen_Degree2XRotation(env, rotation); XRRSetScreenConfigAndRate(dpy, conf, root, (int)resMode_idx, xrot, (short)freq, CurrentTime); - XSync(dpy, False); - return JNI_TRUE; } /* * Class: jogamp_newt_driver_x11_RandR11 - * Method: setCurrentScreenModePollEnd0 - * Signature: (JIII)Z + * Method: sendRRScreenChangeNotify0 + * Signature: (JIJIII)Z */ -JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_RandR11_setCurrentScreenModePollEnd0 - (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jint resMode_idx, jint freq, jint rotation) +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_RandR11_sendRRScreenChangeNotify0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jlong jevent, jint resMode_idx, jint freq, jint rotation) { - Display *dpy = (Display *) (intptr_t) display; - int randr_event_base, randr_error_base; - XEvent evt; - XRRScreenChangeNotifyEvent * scn_event = (XRRScreenChangeNotifyEvent *) &evt; - + Display * dpy = (Display *) (intptr_t) display; + XEvent *event = (XEvent*)(intptr_t)jevent; + XRRUpdateConfiguration(event); + DBG_PRINT("RandR11_sendRRScreenChangeNotify0: dpy %p, event %p\n", dpy, event); + if( -1 == resMode_idx || -1 == screen_idx ) { + // No validation requested + return JNI_FALSE; + } + // Validate numbers .. + XRRScreenChangeNotifyEvent * scn_event = (XRRScreenChangeNotifyEvent *) event; int num_sizes; XRRScreenSize *xrrs = XRRSizes(dpy, (int)screen_idx, &num_sizes); //get possible screen resolutions - XRRScreenConfiguration *conf; - if( 0 > resMode_idx || resMode_idx >= num_sizes ) { NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); } - XRRQueryExtension(dpy, &randr_event_base, &randr_error_base); - - int done = 0; - int rot; - do { - if ( 0 >= XEventsQueued(dpy, QueuedAfterFlush) ) { - return JNI_FALSE; // not done + jboolean done = JNI_FALSE; + if(0 < scn_event->rotation ) { // All valid values greater zero: 0, 90, 180, 270, .. + int rot = NewtScreen_XRotation2Degree(env, scn_event->rotation); + DBG_PRINT( "XRANDR: event . RRScreenChangeNotify call(OK) %p (root %p) resIdx %d rot %d %dx%d\n", + (void*)scn_event->window, (void*)scn_event->root, + (int)scn_event->size_index, rot, + scn_event->width, scn_event->height); + // done = scn_event->size_index == resMode_idx; // not reliable .. + if( rot == rotation && + scn_event->width == xrrs[resMode_idx].width && + scn_event->height == xrrs[resMode_idx].height ) { + done = JNI_TRUE; } - XNextEvent(dpy, &evt); - - switch (evt.type - randr_event_base) { - case RRScreenChangeNotify: - if(0 < scn_event->rotation ) { - rot = NewtScreen_XRotation2Degree(env, (int)scn_event->rotation); - DBG_PRINT( "XRANDR: event . RRScreenChangeNotify call(1) %p (root %p) resIdx %d rot %d %dx%d\n", - (void*)scn_event->window, (void*)scn_event->root, - (int)scn_event->size_index, rot, - scn_event->width, scn_event->height); - // done = scn_event->size_index == resMode_idx; // not reliable .. - done = rot == rotation && - scn_event->width == xrrs[resMode_idx].width && - scn_event->height == xrrs[resMode_idx].height; - } else { - DBG_PRINT( "XRANDR: event . RRScreenChangeNotify call(0) %p (root %p) resIdx %d %dx%d\n", - (void*)scn_event->window, (void*)scn_event->root, - (int)scn_event->size_index, - scn_event->width, scn_event->height); - } - break; - default: - DBG_PRINT("RANDR: event . unhandled %d 0x%X call %p\n", (int)evt.type, (int)evt.type, (void*)evt.xany.window); - } - XRRUpdateConfiguration(&evt); - } while(!done); - - XSync(dpy, False); - - return done ? JNI_TRUE : JNI_FALSE; + } else { // invalid .. skip + DBG_PRINT( "XRANDR: event . RRScreenChangeNotify call(SKIP) %p (root %p) resIdx %d %dx%d\n", + (void*)scn_event->window, (void*)scn_event->root, + (int)scn_event->size_index, + scn_event->width, scn_event->height); + } + return done; } + diff --git a/src/newt/native/X11RandR13.c b/src/newt/native/X11RandR13.c index 4f52ad190..37a6ea055 100644 --- a/src/newt/native/X11RandR13.c +++ b/src/newt/native/X11RandR13.c @@ -61,33 +61,35 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_RandR13_freeScreenResources0 #define SAFE_STRING(s) (NULL==s?"":s) -static void dumpOutputs(const char *prefix, Display *dpy, int screen_idx, XRRScreenResources *resources, int noutput, RROutput * outputs) { +static void dumpOutput(const char *prefix, Display *dpy, int screen_idx, XRRScreenResources *resources, int outputIdx, RROutput output) { int i, j, primIdx=0; Window root = RootWindow(dpy, screen_idx); RROutput pxid = XRRGetOutputPrimary (dpy, root); - fprintf(stderr, "%s %p: Output[count %d, prim %#lx]\n", prefix, resources, noutput, pxid); + int isPrim =0; + if ( None != pxid && pxid == output ) { + primIdx = i; + isPrim = 1; + } + XRROutputInfo * xrrOutputInfo = XRRGetOutputInfo (dpy, resources, output); + fprintf(stderr, "%s: Output[%d]: id %#lx, crtx 0x%lX, name %s (%d), %lux%lu, ncrtc %d, nclone %d, nmode %d (preferred %d), primary %d\n", + prefix, outputIdx, output, xrrOutputInfo->crtc, SAFE_STRING(xrrOutputInfo->name), xrrOutputInfo->nameLen, + xrrOutputInfo->mm_width, xrrOutputInfo->mm_height, + xrrOutputInfo->ncrtc, xrrOutputInfo->nclone, xrrOutputInfo->nmode, xrrOutputInfo->npreferred, isPrim); + for(j=0; j<xrrOutputInfo->ncrtc; j++) { + fprintf(stderr, "%s: Output[%d].Crtc[%d].id %#lx\n", prefix, i, j, xrrOutputInfo->crtcs[j]); + } + for(j=0; j<xrrOutputInfo->nclone; j++) { + fprintf(stderr, "%s: Output[%d].Clones[%d].id %#lx\n", prefix, i, j, xrrOutputInfo->clones[j]); + } + for(j=0; j<xrrOutputInfo->nmode; j++) { + fprintf(stderr, "%s: Output[%d].Mode[%d].id %#lx\n", prefix, i, j, xrrOutputInfo->modes[j]); + } + XRRFreeOutputInfo (xrrOutputInfo); +} +static void dumpOutputs(const char *prefix, Display *dpy, int screen_idx, XRRScreenResources *resources, int noutput, RROutput * outputs) { + int i; for(i=0; i<noutput; i++) { - int isPrim =0; - RROutput output = outputs[i]; - if ( None != pxid && pxid == output ) { - primIdx = i; - isPrim = 1; - } - XRROutputInfo * xrrOutputInfo = XRRGetOutputInfo (dpy, resources, output); - fprintf(stderr, " Output[%d]: id %#lx, crtx 0x%lX, name %s (%d), %lux%lu, ncrtc %d, nclone %d, nmode %d (preferred %d), primary %d\n", - i, output, xrrOutputInfo->crtc, SAFE_STRING(xrrOutputInfo->name), xrrOutputInfo->nameLen, - xrrOutputInfo->mm_width, xrrOutputInfo->mm_height, - xrrOutputInfo->ncrtc, xrrOutputInfo->nclone, xrrOutputInfo->nmode, xrrOutputInfo->npreferred, isPrim); - for(j=0; j<xrrOutputInfo->ncrtc; j++) { - fprintf(stderr, " Output[%d].Crtc[%d].id %#lx\n", i, j, xrrOutputInfo->crtcs[j]); - } - for(j=0; j<xrrOutputInfo->nclone; j++) { - fprintf(stderr, " Output[%d].Clones[%d].id %#lx\n", i, j, xrrOutputInfo->clones[j]); - } - for(j=0; j<xrrOutputInfo->nmode; j++) { - fprintf(stderr, " Output[%d].Mode[%d].id %#lx\n", i, j, xrrOutputInfo->modes[j]); - } - XRRFreeOutputInfo (xrrOutputInfo); + dumpOutput(prefix, dpy, screen_idx, resources, i, outputs[i]); } } @@ -116,7 +118,39 @@ static float getVRefresh(XRRModeInfo *mode) { } return rate; } +static RRCrtc findRRCrtc(XRRScreenResources *resources, RRCrtc crtc) { + if( NULL != resources ) { + int i; + for(i=resources->ncrtc-1; i>=0; i--) { + if( resources->crtcs[i] == crtc ) { + return crtc; + } + } + } + return 0; +} +static XRRCrtcInfo* getXRRCrtcInfo(Display *dpy, XRRScreenResources *resources, RRCrtc _crtc) { + RRCrtc crtc = findRRCrtc( resources, _crtc ); + if( 0 == crtc ) { + return NULL; + } else { + return XRRGetCrtcInfo (dpy, resources, crtc); + } +} +static XRRModeInfo* findMode(XRRScreenResources *resources, RRMode modeId) { + if( NULL != resources ) { + int i; + for(i=resources->nmode-1; i>=0; i--) { + XRRModeInfo *imode = &resources->modes[i]; + if( imode->id == modeId ) { + return imode; + } + } + } + return NULL; +} +#include "xrandr_utils.c" JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_RandR13_dumpInfo0 (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jlong screenResources) @@ -144,10 +178,11 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_RandR13_dumpInfo0 for(i=0; i<resources->ncrtc; i++) { RRCrtc crtc = resources->crtcs[i]; XRRCrtcInfo *xrrCrtcInfo = XRRGetCrtcInfo (dpy, resources, crtc); - fprintf(stderr, "Crtc[%d]: %d/%d %dx%d, rot 0x%X, mode.id %#lx\n", - i, xrrCrtcInfo->x, xrrCrtcInfo->y, xrrCrtcInfo->width, xrrCrtcInfo->height, xrrCrtcInfo->rotations, xrrCrtcInfo->mode); + fprintf(stderr, "Crtc[%d] %#lx: %d/%d %dx%d, rot 0x%X, mode.id %#lx\n", + i, crtc, xrrCrtcInfo->x, xrrCrtcInfo->y, xrrCrtcInfo->width, xrrCrtcInfo->height, xrrCrtcInfo->rotations, xrrCrtcInfo->mode); for(j=0; j<xrrCrtcInfo->noutput; j++) { fprintf(stderr, " Crtc[%d].Output[%d].id %#lx\n", i, j, xrrCrtcInfo->outputs[j]); + dumpOutput(" ", dpy, screen_idx, resources, j, xrrCrtcInfo->outputs[j]); } XRRFreeCrtcInfo(xrrCrtcInfo); } @@ -166,14 +201,28 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_RandR13_dumpInfo0 /* * Class: jogamp_newt_driver_x11_RandR13 - * Method: getMonitorDeviceCount0 + * Method: getMonitorDeviceIds0 * Signature: (J)I */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorDeviceCount0 +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorDeviceIds0 (JNIEnv *env, jclass clazz, jlong screenResources) { XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; - return ( NULL != resources ) ? resources->ncrtc : 0; + int ncrtc = ( NULL != resources ) ? resources->ncrtc : 0; + jintArray properties = NULL; + if( 0 < ncrtc ) { + int crtcs[ncrtc]; + int i; + for(i=0; i<ncrtc; i++) { + crtcs[i] = (int)(intptr_t)resources->crtcs[i]; + } + properties = (*env)->NewIntArray(env, ncrtc); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", ncrtc); + } + (*env)->SetIntArrayRegion(env, properties, 0, ncrtc, crtcs); + } + return properties; } /* @@ -182,19 +231,12 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorDeviceCount * Signature: (JIJI)J */ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorInfoHandle0 - (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jlong screenResources, jint crt_idx) + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jlong screenResources, jint crt_id) { - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)screen_idx); - XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; - - if( NULL == resources || crt_idx >= resources->ncrtc ) { - return 0; - } - RRCrtc crtc = resources->crtcs[crt_idx]; - XRRCrtcInfo *xrrCrtcInfo = XRRGetCrtcInfo (dpy, resources, crtc); - - return (jlong) (intptr_t) xrrCrtcInfo; + XRRCrtcInfo *xrrCrtcInfo = getXRRCrtcInfo((Display *)(intptr_t)display, + (XRRScreenResources *)(intptr_t)screenResources, + (RRCrtc)(intptr_t)crt_id ); + return (jlong)(intptr_t)xrrCrtcInfo; } /* @@ -360,16 +402,8 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorCurren return NULL; } - int modeId = xrrCrtcInfo->mode; - XRRModeInfo *mode = NULL; - int i; - for(i=0; i<resources->nmode; i++) { - XRRModeInfo *imode = &resources->modes[i]; - if( imode->id == modeId ) { - mode = imode; - break; - } - } + RRMode modeId = xrrCrtcInfo->mode; + XRRModeInfo *mode = findMode(resources, modeId); if( NULL == mode ) { // oops .. return NULL; @@ -412,17 +446,20 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorCurren * Signature: (JJJJ)[I */ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorDevice0 - (JNIEnv *env, jclass clazz, jlong display, jlong screenResources, jlong monitorInfo, jint crt_idx) + (JNIEnv *env, jclass clazz, jlong display, jlong screenResources, jlong monitorInfo, jint crt_id) { Display * dpy = (Display *) (intptr_t) display; XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; + RRCrtc crtc = findRRCrtc( resources, (RRCrtc)(intptr_t)crt_id ); + if( 0 == crtc ) { + // n/a + return NULL; + } XRRCrtcInfo *xrrCrtcInfo = (XRRCrtcInfo *) (intptr_t) monitorInfo; - - if( NULL == resources || NULL == xrrCrtcInfo || crt_idx >= resources->ncrtc ) { + if( NULL == xrrCrtcInfo ) { // n/a return NULL; } - if( None == xrrCrtcInfo->mode || 0 == xrrCrtcInfo->noutput ) { // disabled return NULL; @@ -444,7 +481,7 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorDevice int propIndex = 0; prop[propIndex++] = propCount; - prop[propIndex++] = crt_idx; + prop[propIndex++] = crt_id; prop[propIndex++] = 0; // isClone, does not work: 0 < xrrOutputInfo->nclone ? 1 : 0; prop[propIndex++] = isPrimary; prop[propIndex++] = xrrOutputInfo->mm_width; @@ -457,14 +494,13 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorDevice 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++] = xrrCrtcInfo->mode; // current mode id prop[propIndex++] = NewtScreen_XRotation2Degree(env, xrrCrtcInfo->rotation); int i; for(i=0; i<numModes; i++) { // avail modes .. prop[propIndex++] = xrrOutputInfo->modes[i]; } - XRRFreeOutputInfo (xrrOutputInfo); jintArray properties = (*env)->NewIntArray(env, propCount); @@ -482,43 +518,147 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorDevice * Signature: (JJJIIIII)Z */ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_RandR13_setMonitorMode0 - (JNIEnv *env, jclass clazz, jlong display, jlong screenResources, jlong monitorInfo, jint crt_idx, jint modeId, jint rotation, jint x, jint y) + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jlong screenResources, + jlong monitorInfo, jint crt_id, + jint jmode_id, jint rotation, jint x, jint y) { + jboolean res = JNI_FALSE; Display * dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)screen_idx); XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; + RRCrtc crtc = findRRCrtc( resources, (RRCrtc)(intptr_t)crt_id ); + if( 0 == crtc ) { + // n/a + DBG_PRINT("RandR13_setMonitorMode0.0: n/a: resources %p (%d), crt_id %#lx \n", + resources, (NULL == resources ? 0 : resources->ncrtc), (RRCrtc)(intptr_t)crt_id); + return res; + } XRRCrtcInfo *xrrCrtcInfo = (XRRCrtcInfo *) (intptr_t) monitorInfo; - jboolean res = JNI_FALSE; - - if( NULL == resources || NULL == xrrCrtcInfo || crt_idx >= resources->ncrtc ) { + if( NULL == xrrCrtcInfo ) { // n/a + DBG_PRINT("RandR13_setMonitorMode0.1: n/a: resources %p (%d), xrrCrtcInfo %p, crtc %#lx\n", + resources, (NULL == resources ? 0 : resources->ncrtc), xrrCrtcInfo, crtc); return res; } - if( None == xrrCrtcInfo->mode || 0 == xrrCrtcInfo->noutput ) { // disabled + DBG_PRINT("RandR13_setMonitorMode0: disabled: mode %d, noutput %d\n", xrrCrtcInfo->mode, xrrCrtcInfo->noutput); return res; } - - if( 0 >= modeId ) { + if( 0 >= jmode_id ) { // oops .. + DBG_PRINT("RandR13_setMonitorMode0: inv. modeId: modeId %d\n", jmode_id); return res; } + RRMode mode_id = (RRMode)(intptr_t)jmode_id; + XRRModeInfo *mode_info = findMode(resources, mode_id); + if( NULL == mode_info ) { + // oops .. + DBG_PRINT("RandR13_setMonitorMode0: inv. mode_id: mode_id %#lx\n", mode_id); + return res; + } if( 0 > x || 0 > y ) { x = xrrCrtcInfo->x; y = xrrCrtcInfo->y; } - Status status = XRRSetCrtcConfig( dpy, resources, resources->crtcs[crt_idx], CurrentTime, - x, y, modeId, NewtScreen_Degree2XRotation(env, rotation), - xrrCrtcInfo->outputs, xrrCrtcInfo->noutput ); + Rotation xrotation = NewtScreen_Degree2XRotation(env, rotation); + int rot_change = xrrCrtcInfo->rotation != xrotation; + DBG_PRINT("RandR13_setMonitorMode0: crt %#lx, noutput %d -> 0x%X, mode %#lx -> %#lx, pos %d / %d, rotation %d -> %d (change %d)\n", + crtc, xrrCrtcInfo->noutput, xrrCrtcInfo->outputs[0], xrrCrtcInfo->mode, mode_id, + x, y, (int)xrrCrtcInfo->rotation, (int)xrotation, rot_change); + + XRRSelectInput (dpy, root, RRScreenChangeNotifyMask); + Status status = RRSetConfigSuccess; + int pre_fb_width=0, pre_fb_height=0; + int fb_width=0, fb_height=0; + int fb_width_mm=0, fb_height_mm=0; + + crtc_t *root_crtc = get_screen_size1(dpy, root, &fb_width, &fb_height, + resources, crtc, xrrCrtcInfo, xrotation, x, y, mode_info); + + Bool fb_change = get_screen_sizemm(dpy, screen_idx, fb_width, fb_height, + &fb_width_mm, &fb_height_mm, + &pre_fb_width, &pre_fb_height); + + DBG_PRINT("RandR13_setMonitorMode0: crt %#lx, fb[change %d: %d x %d -> %d x %d [%d x %d mm]\n", + crtc, fb_change, pre_fb_width, pre_fb_height, fb_width, fb_height, fb_width_mm, fb_height_mm); + if(fb_change) { + // Disable CRTC first, since new size differs from current + // and we shall avoid invalid intermediate configuration (see spec)! + #if 0 + { + // Disable all CRTCs (Not required!) + crtc_t * iter_crtc; + for(iter_crtc=root_crtc; RRSetConfigSuccess == status && NULL!=iter_crtc; iter_crtc=iter_crtc->next) { + if( None == iter_crtc->mode_id || NULL == iter_crtc->mode_info || 0 == iter_crtc->crtc_info->noutput ) { + // disabled + continue; + } + status = XRRSetCrtcConfig (dpy, resources, iter_crtc->crtc_id, CurrentTime, + 0, 0, None, RR_Rotate_0, NULL, 0); + } + } + #else + status = XRRSetCrtcConfig (dpy, resources, crtc, CurrentTime, + 0, 0, None, RR_Rotate_0, NULL, 0); + #endif + DBG_PRINT("RandR13_setMonitorMode0: crt %#lx disable: %d -> %d\n", crtc, status, RRSetConfigSuccess == status); + if( RRSetConfigSuccess == status ) { + XRRSetScreenSize (dpy, root, fb_width, fb_height, + fb_width_mm, fb_height_mm); + DBG_PRINT("RandR13_setMonitorMode0: crt %#lx screen-size\n", crtc); + } + } + if( RRSetConfigSuccess == status ) { + #if 0 + { + // Enable/Set all CRTCs (Not required!) + crtc_t * iter_crtc; + for(iter_crtc=root_crtc; RRSetConfigSuccess == status && NULL!=iter_crtc; iter_crtc=iter_crtc->next) { + if( None == iter_crtc->mode_id || NULL == iter_crtc->mode_info || 0 == iter_crtc->crtc_info->noutput ) { + // disabled + continue; + } + status = XRRSetCrtcConfig( dpy, resources, iter_crtc->crtc_id, CurrentTime, + iter_crtc->x, iter_crtc->y, iter_crtc->mode_id, iter_crtc->rotation, + iter_crtc->crtc_info->outputs, iter_crtc->crtc_info->noutput ); + } + } + #else + status = XRRSetCrtcConfig( dpy, resources, crtc, CurrentTime, + x, y, mode_id, xrotation, + xrrCrtcInfo->outputs, xrrCrtcInfo->noutput ); + #endif + DBG_PRINT("RandR13_setMonitorMode0: crt %#lx set-config: %d -> %d\n", crtc, status, RRSetConfigSuccess == status); + } + res = status == RRSetConfigSuccess; + DBG_PRINT("RandR13_setMonitorMode0: FIN: %d -> ok %d\n", status, res); + + destroyCrtcChain(root_crtc, crtc); + root_crtc=NULL; return res; } /* * Class: jogamp_newt_driver_x11_RandR13 + * Method: sendRRScreenChangeNotify0 + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_RandR13_sendRRScreenChangeNotify0 + (JNIEnv *env, jclass clazz, jlong display, jlong jevent) +{ + Display * dpy = (Display *) (intptr_t) display; + XEvent *event = (XEvent*)(intptr_t)jevent; + XRRUpdateConfiguration(event); + DBG_PRINT("RandR13_sendRRScreenChangeNotify0: dpy %p, event %p\n", dpy, event); +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 * Method: setScreenViewport0 * Signature: (JIJIIII)Z */ @@ -539,4 +679,3 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_RandR13_setScreenViewport return JNI_TRUE; } - diff --git a/src/newt/native/X11Screen.c b/src/newt/native/X11Screen.c index 152a092c9..b4bb8a112 100644 --- a/src/newt/native/X11Screen.c +++ b/src/newt/native/X11Screen.c @@ -74,7 +74,7 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_getHeight0 return (jint) DisplayHeight( dpy, scrn_idx); } -int NewtScreen_XRotation2Degree(JNIEnv *env, int xrotation) { +int NewtScreen_XRotation2Degree(JNIEnv *env, Rotation xrotation) { int degree; if(xrotation == RR_Rotate_0) { degree = 0; @@ -93,8 +93,8 @@ int NewtScreen_XRotation2Degree(JNIEnv *env, int xrotation) { return degree; } -int NewtScreen_Degree2XRotation(JNIEnv *env, int degree) { - int xrot; +Rotation NewtScreen_Degree2XRotation(JNIEnv *env, int degree) { + Rotation xrot; if(degree == 0) { xrot = RR_Rotate_0; } diff --git a/src/newt/native/X11Screen.h b/src/newt/native/X11Screen.h index c81ee05d5..5f47cc90d 100644 --- a/src/newt/native/X11Screen.h +++ b/src/newt/native/X11Screen.h @@ -32,7 +32,7 @@ #include "X11Common.h" -int NewtScreen_XRotation2Degree(JNIEnv *env, int xrotation); -int NewtScreen_Degree2XRotation(JNIEnv *env, int degree); +int NewtScreen_XRotation2Degree(JNIEnv *env, Rotation xrotation); +Rotation NewtScreen_Degree2XRotation(JNIEnv *env, int degree); #endif /* _X11SCREEN_H */ diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 43506c6a6..e640b0c20 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -696,7 +696,8 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWindow0 * Signature: (JJ)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 - (JNIEnv *env, jobject obj, jlong display, jlong window, jlong javaObjectAtom, jlong windowDeleteAtom /*, jlong kbdHandle*/) // XKB disabled for now + (JNIEnv *env, jobject obj, jlong display, jlong window, jlong javaObjectAtom, jlong windowDeleteAtom /*, jlong kbdHandle*/, // XKB disabled for now + jint randr_event_base, jint randr_error_base) { Display * dpy = (Display *) (intptr_t) display; Window w = (Window)window; @@ -726,7 +727,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 XUnmapWindow(dpy, w); // Drain all events related to this window .. - Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0(env, obj, display, javaObjectAtom, windowDeleteAtom /*, kbdHandle */); // XKB disabled for now + Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0(env, obj, display, javaObjectAtom, windowDeleteAtom /*, kbdHandle */, // XKB disabled for now + randr_event_base, randr_error_base); XDestroyWindow(dpy, w); if( None != xwa.colormap ) { diff --git a/src/newt/native/xrandr_utils.c b/src/newt/native/xrandr_utils.c new file mode 100644 index 000000000..564fdd44b --- /dev/null +++ b/src/newt/native/xrandr_utils.c @@ -0,0 +1,322 @@ +/** + * This file contains code from xrandr.c, + * see <http://cgit.freedesktop.org/xorg/app/xrandr/tree/xrandr.c>: + * + * ++++ + * + * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. + * Copyright © 2002 Hewlett Packard Company, Inc. + * Copyright © 2006 Intel Corporation + * Copyright © 2013 NVIDIA Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * Thanks to Jim Gettys who wrote most of the client side code, + * and part of the server code for randr. + * + * ++++ + * + * Modifications / Additions are from: + * + * Copyright 2015 JogAmp Community. All rights reserved. + * + * License text: Same as above! + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include "X11Common.h" + +#include <math.h> + +typedef struct { + int x1, y1, x2, y2; +} box_t; +typedef struct { + int x, y; +} point_t; +typedef struct { + XTransform transform; + char *filter; + int nparams; + XFixed *params; +} transform_t; +typedef struct _crtc { + struct _crtc *next; + RRCrtc crtc_id; + Rotation rotation; + transform_t transform; + int x, y; + RRMode mode_id; + // float refresh; + // Bool primary; + + XRRModeInfo *mode_info; + XRRCrtcInfo *crtc_info; + XRRPanning *panning_info; +} crtc_t; +static int mode_height (XRRModeInfo *mode_info, Rotation rotation) { + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode_info->height; + case RR_Rotate_90: + case RR_Rotate_270: + return mode_info->width; + default: + return 0; + } +} +static int mode_width (XRRModeInfo *mode_info, Rotation rotation) { + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode_info->width; + case RR_Rotate_90: + case RR_Rotate_270: + return mode_info->height; + default: + return 0; + } +} +static Bool transform_point (XTransform *transform, double *xp, double *yp) { + double vector[3]; + double result[3]; + int i, j; + double v; + + vector[0] = *xp; + vector[1] = *yp; + vector[2] = 1; + for (j = 0; j < 3; j++) + { + v = 0; + for (i = 0; i < 3; i++) { + v += (XFixedToDouble (transform->matrix[j][i]) * vector[i]); + } + if (v > 32767 || v < -32767) { + return False; + } + result[j] = v; + } + if (!result[2]) { + return False; + } + for (j = 0; j < 2; j++) { + vector[j] = result[j] / result[2]; + } + *xp = vector[0]; + *yp = vector[1]; + return True; +} +static void path_bounds (XTransform *transform, point_t *points, int npoints, box_t *box) { + int i; + box_t point; + + for (i = 0; i < npoints; i++) { + double x, y; + x = points[i].x; + y = points[i].y; + transform_point (transform, &x, &y); + point.x1 = floor (x); + point.y1 = floor (y); + point.x2 = ceil (x); + point.y2 = ceil (y); + if (i == 0) { + *box = point; + } else { + if (point.x1 < box->x1) { box->x1 = point.x1; } + if (point.y1 < box->y1) { box->y1 = point.y1; } + if (point.x2 > box->x2) { box->x2 = point.x2; } + if (point.y2 > box->y2) { box->y2 = point.y2; } + } + } +} +static void mode_geometry (XRRModeInfo *mode_info, Rotation rotation, + XTransform *transform, box_t *bounds) { + point_t rect[4]; + int width = mode_width (mode_info, rotation); + int height = mode_height (mode_info, rotation); + + rect[0].x = 0; + rect[0].y = 0; + rect[1].x = width; + rect[1].y = 0; + rect[2].x = width; + rect[2].y = height; + rect[3].x = 0; + rect[3].y = height; + path_bounds (transform, rect, 4, bounds); +} +static void get_screen_size0(Display * dpy, Window root, + crtc_t * root_crtc, int *io_scrn_width, int *io_scrn_height) { + int fb_width = *io_scrn_width; + int fb_height = *io_scrn_height; + crtc_t *crtc; + for (crtc = root_crtc; NULL != crtc; crtc = crtc->next) { + if( None == crtc->mode_id || NULL == crtc->mode_info || 0 == crtc->crtc_info->noutput ) { + // disabled + continue; + } + XRRModeInfo *mode_info = crtc->mode_info; + int x, y, w, h; + box_t bounds; + + mode_geometry (mode_info, crtc->rotation, + &crtc->transform.transform, &bounds); + x = crtc->x + bounds.x1; + y = crtc->y + bounds.y1; + w = bounds.x2 - bounds.x1; + h = bounds.y2 - bounds.y1; + + /* fit fb to crtc */ + XRRPanning *pan; + if (x + w > fb_width) { + fb_width = x + w; + } + if (y + h > fb_height) { + fb_height = y + h; + } + pan = crtc->panning_info; + if (pan && pan->left + pan->width > fb_width) { + fb_width = pan->left + pan->width; + } + if (pan && pan->top + pan->height > fb_height) { + fb_height = pan->top + pan->height; + } + } + int minWidth=0, minHeight=0, maxWidth=0, maxHeight=0; + if( 1 != XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight, &maxWidth, &maxHeight) ) { + // Use defaults in case of error .. + minWidth=8; minHeight=8; maxWidth=16384; maxHeight=16384; + } + if( fb_width < minWidth ) { + fb_width = minWidth; + } else if( fb_width > maxWidth ) { + fb_width = maxWidth; + } + if( fb_height < minHeight ) { + fb_height = minHeight; + } else if( fb_height > maxHeight ) { + fb_height = maxHeight; + } + *io_scrn_width = fb_width; + *io_scrn_height = fb_height; +} +static crtc_t* createCrtcChain(Display *dpy, + XRRScreenResources *resources, + RRCrtc customCrtc, XRRCrtcInfo *customCrtcInfo, + Rotation customRotation, int customX, int customY, + XRRModeInfo *customModeInfo) +{ + crtc_t *root_crtc = NULL; + crtc_t *iter_crtc = NULL; + int i; + for(i=0; i<resources->ncrtc; i++) { + crtc_t *next_crtc = calloc(1, sizeof(crtc_t)); + if( NULL == iter_crtc ) { + root_crtc = next_crtc; + } else { + iter_crtc->next = next_crtc; + } + iter_crtc = next_crtc; + + RRCrtc crtcId = resources->crtcs[i]; + iter_crtc->crtc_id = crtcId; + if( crtcId == customCrtc && 0 != customCrtc ) { + iter_crtc->rotation = customRotation; + iter_crtc->x = customX; + iter_crtc->y = customY; + iter_crtc->mode_info = customModeInfo; + iter_crtc->mode_id = customModeInfo->id; + iter_crtc->crtc_info = customCrtcInfo; + } else { + XRRCrtcInfo *xrrCrtcInfo = XRRGetCrtcInfo (dpy, resources, crtcId); + iter_crtc->rotation = xrrCrtcInfo->rotation; + iter_crtc->x = xrrCrtcInfo->x; + iter_crtc->y = xrrCrtcInfo->y; + iter_crtc->mode_id = xrrCrtcInfo->mode; + iter_crtc->mode_info = findMode(resources, iter_crtc->mode_id); + iter_crtc->crtc_info = xrrCrtcInfo; + } + iter_crtc->panning_info = XRRGetPanning(dpy, resources, crtcId); + } + return root_crtc; +} +static void destroyCrtcChain(crtc_t *root_crtc, RRCrtc customCrtc) { + crtc_t * iter_crtc = root_crtc; + while(NULL!=iter_crtc) { + if( NULL != iter_crtc->crtc_info ) { + if( iter_crtc->crtc_id != customCrtc || 0 == customCrtc ) { + XRRFreeCrtcInfo(iter_crtc->crtc_info); + } + iter_crtc->crtc_info = NULL; + } + if( NULL != iter_crtc->panning_info ) { + XRRFreePanning(iter_crtc->panning_info); + iter_crtc->panning_info = NULL; + } + { + crtc_t * last = iter_crtc; + iter_crtc = iter_crtc->next; + last->next = NULL; + free(last); + } + } +} +static crtc_t *get_screen_size1(Display * dpy, Window root, + int *io_scrn_width, int *io_scrn_height, + XRRScreenResources *resources, + RRCrtc customCrtc, XRRCrtcInfo *customCrtcInfo, + Rotation customRotation, int customX, int customY, + XRRModeInfo *customModeInfo) { + crtc_t *root_crtc = createCrtcChain(dpy, resources, customCrtc, customCrtcInfo, + customRotation, customX, customY, customModeInfo); + get_screen_size0(dpy, root, root_crtc, io_scrn_width, io_scrn_height); + return root_crtc; +} +static crtc_t *get_screen_size2(Display * dpy, Window root, + int *io_scrn_width, int *io_scrn_height, + XRRScreenResources *resources) { + crtc_t *root_crtc = createCrtcChain(dpy, resources, 0, NULL, 0, 0, 0, NULL); + get_screen_size0(dpy, root, root_crtc, io_scrn_width, io_scrn_height); + return root_crtc; +} +static Bool get_screen_sizemm(Display *dpy, int screen_idx, + int fb_width, int fb_height, + int *fb_width_mm, int *fb_height_mm, + int *pre_fb_width, int *pre_fb_height) { + *pre_fb_width = DisplayWidth (dpy, screen_idx); + *pre_fb_height = DisplayHeight (dpy, screen_idx); + Bool fb_change; + if (fb_width != *pre_fb_width || fb_height != *pre_fb_height ) { + float dpi = (25.4 * *pre_fb_height) / DisplayHeightMM(dpy, screen_idx); + *fb_width_mm = (25.4 * fb_width) / dpi; + *fb_height_mm = (25.4 * fb_height) / dpi; + fb_change = True; + } else { + *fb_width_mm = DisplayWidthMM (dpy, screen_idx); + *fb_height_mm = DisplayHeightMM (dpy, screen_idx); + fb_change = False; + } + return fb_change; +} + |