diff --git a/src/java/org/lwjgl/opengl/LinuxDisplay.java b/src/java/org/lwjgl/opengl/LinuxDisplay.java index d7bc6b1e..6abbab8c 100644 --- a/src/java/org/lwjgl/opengl/LinuxDisplay.java +++ b/src/java/org/lwjgl/opengl/LinuxDisplay.java @@ -129,7 +129,6 @@ final class LinuxDisplay implements DisplayImplementation { private DisplayMode saved_mode; private DisplayMode current_mode; - private Screen[] savedXrandrConfig; private boolean keyboard_grabbed; private boolean pointer_grabbed; @@ -603,12 +602,17 @@ final class LinuxDisplay implements DisplayImplementation { } private void switchDisplayModeOnTmpDisplay(DisplayMode mode) throws LWJGLException { - incDisplay(); - try { - nSwitchDisplayMode(getDisplay(), getDefaultScreen(), current_displaymode_extension, mode); - } finally { - decDisplay(); - } + if (current_displaymode_extension == XRANDR) { + // let Xrandr set the display mode + XRandR.setConfiguration(XRandR.toScreen(mode)); + } else { + incDisplay(); + try { + nSwitchDisplayMode(getDisplay(), getDefaultScreen(), current_displaymode_extension, mode); + } finally { + decDisplay(); + } + } } private static native void nSwitchDisplayMode(long display, int screen, int extension, DisplayMode mode) throws LWJGLException; @@ -625,11 +629,11 @@ final class LinuxDisplay implements DisplayImplementation { public void resetDisplayMode() { lockAWT(); try { - if( current_displaymode_extension == XRANDR && savedXrandrConfig.length > 0 ) + if( current_displaymode_extension == XRANDR ) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { - XRandR.setConfiguration( savedXrandrConfig ); + XRandR.restoreConfiguration(); return null; } }); @@ -727,12 +731,12 @@ final class LinuxDisplay implements DisplayImplementation { throw new LWJGLException("No modes available"); switch (current_displaymode_extension) { case XRANDR: - savedXrandrConfig = AccessController.doPrivileged(new PrivilegedAction() { - public Screen[] run() { - return XRandR.getConfiguration(); + saved_mode = AccessController.doPrivileged(new PrivilegedAction() { + public DisplayMode run() { + XRandR.saveConfiguration(); + return XRandR.toDisplayMode(XRandR.getConfiguration()); } }); - saved_mode = getCurrentXRandrMode(); break; case XF86VIDMODE: saved_mode = modes[0]; @@ -929,13 +933,24 @@ final class LinuxDisplay implements DisplayImplementation { public DisplayMode[] getAvailableDisplayModes() throws LWJGLException { lockAWT(); try { - incDisplay(); - try { - DisplayMode[] modes = nGetAvailableDisplayModes(getDisplay(), getDefaultScreen(), current_displaymode_extension); - return modes; - } finally { - decDisplay(); - } + incDisplay(); + if (current_displaymode_extension == XRANDR) { + // nGetAvailableDisplayModes cannot be trusted. Use xrandr + Screen[] resolutions = XRandR.getResolutions(XRandR.getScreenNames()[0]); + // quick hack, copy Screens to DisplayModes (todo: get bpp from somewhere, instead of using 24 as default) + DisplayMode[] modes = new DisplayMode[resolutions.length]; + for (int i = 0; i < modes.length; i++) { + modes[i] = new DisplayMode(resolutions[i].width, resolutions[i].height, 24, resolutions[i].freq); + } + return modes; + } else { + try { + DisplayMode[] modes = nGetAvailableDisplayModes(getDisplay(), getDefaultScreen(), current_displaymode_extension); + return modes; + } finally { + decDisplay(); + } + } } finally { unlockAWT(); } @@ -1101,11 +1116,11 @@ final class LinuxDisplay implements DisplayImplementation { if (current_window_mode == FULLSCREEN_NETWM) { nIconifyWindow(getDisplay(), getWindow(), getDefaultScreen()); try { - if( current_displaymode_extension == XRANDR && savedXrandrConfig.length > 0 ) + if( current_displaymode_extension == XRANDR ) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { - XRandR.setConfiguration( savedXrandrConfig ); + XRandR.restoreConfiguration(); return null; } }); diff --git a/src/java/org/lwjgl/opengl/XRandR.java b/src/java/org/lwjgl/opengl/XRandR.java index 79eb0f7d..cf8e65a4 100644 --- a/src/java/org/lwjgl/opengl/XRandR.java +++ b/src/java/org/lwjgl/opengl/XRandR.java @@ -49,6 +49,18 @@ public class XRandR { private static Screen[] current; + /** + * Either the screen marked as "primary" (if it is turned on) + * or the one with the largest (current) resolution. + */ + private static String primaryScreenIdentifier; + + /** + * Used to save the configuration of all output devices to + * restore it on exit or in case of crash. + */ + private static Screen[] savedConfiguration; + private static Map screens; private static void populate() @@ -89,7 +101,13 @@ public class XRandR name = sa[ 0 ]; // save position of this screen, will be used later when current modeline is parsed - parseScreenHeader(currentScreenPosition, "primary".equals(sa[ 2 ]) ? sa[ 3 ] : sa[ 2 ]); + if ("primary".equals(sa[ 2 ])) { + parseScreenHeader(currentScreenPosition, sa[ 3 ]); + // save primary + primaryScreenIdentifier = name; + } else { + parseScreenHeader(currentScreenPosition, sa[ 2 ]); + } } else if( Pattern.matches( "\\d*x\\d*", sa[ 0 ] ) ) { @@ -106,6 +124,17 @@ public class XRandR screens.put( name, possibles.toArray( new Screen[ possibles.size() ] ) ); current = currentList.toArray(new Screen[currentList.size()]); + + // set primary to largest screen if not set yet + if (primaryScreenIdentifier == null) { + long totalPixels = Long.MIN_VALUE; + for (Screen screen : current) { + if (1l * screen.width * screen.height > totalPixels) { + primaryScreenIdentifier = screen.name; + totalPixels = 1l * screen.width * screen.height; + } + } + } } catch( Throwable e ) { @@ -117,13 +146,22 @@ public class XRandR } /** - * @return The current screen configuration, or an empty array if - * xrandr is not supported + * @return The current screen configuration of the primary device, + * or an empty array if xrandr is not supported */ public static Screen[] getConfiguration() { populate(); + // find and return primary + for (Screen screen : current) { + if (screen.name.equals(primaryScreenIdentifier)) { + System.out.println("getConfiguration returned " + screen.width + "x" + screen.height + " @" + screen.freq); + return new Screen[]{screen}; + } + } + + // problem with primary device, fall back to old behaviour return current.clone(); } @@ -184,6 +222,25 @@ public class XRandR } } + /** + * Saves the current configuration for all connected display devices. + * This configuration can be restored on exit/crash by calling + * restoreConfiguration() + */ + public static void saveConfiguration() { + savedConfiguration = current.clone(); + } + + /** + * Restores the configuration for all connected display devices. + * Used on exit or in case of a crash to reset all devices. + */ + public static void restoreConfiguration() { + if (savedConfiguration != null) { + setConfiguration(savedConfiguration); + } + } + /** * @return the name of connected screens, or an empty array if * xrandr is not supported @@ -275,6 +332,18 @@ public class XRandR screenPosition[1] = Integer.parseInt(m.group(4)); } + static Screen toScreen(DisplayMode mode) { + populate(); + // test: use first screen in list + // TODO: replace with "primary" + return new Screen(current[0].name, mode.getWidth(), mode.getHeight(), mode.getFrequency(), current[0].xPos, current[0].yPos); + } + + static DisplayMode toDisplayMode(Screen... screens) { + // todo: use "primary" screen + return new DisplayMode(screens[0].width, screens[0].height, 24, screens[0].freq); + } + /** * Encapsulates the configuration of a monitor. * Resolution and freq are fixed, position is mutable