Merge pull request #81 from tfg13/master
linux: basic compatibility for systems with multiple monitors
This commit is contained in:
commit
52933da812
|
@ -129,7 +129,6 @@ final class LinuxDisplay implements DisplayImplementation {
|
||||||
private DisplayMode saved_mode;
|
private DisplayMode saved_mode;
|
||||||
private DisplayMode current_mode;
|
private DisplayMode current_mode;
|
||||||
|
|
||||||
private Screen[] savedXrandrConfig;
|
|
||||||
|
|
||||||
private boolean keyboard_grabbed;
|
private boolean keyboard_grabbed;
|
||||||
private boolean pointer_grabbed;
|
private boolean pointer_grabbed;
|
||||||
|
@ -483,7 +482,16 @@ final class LinuxDisplay implements DisplayImplementation {
|
||||||
window_y = y;
|
window_y = y;
|
||||||
window_width = mode.getWidth();
|
window_width = mode.getWidth();
|
||||||
window_height = mode.getHeight();
|
window_height = mode.getHeight();
|
||||||
|
|
||||||
|
// overwrite arguments x and y - superclass always uses 0,0 for fullscreen windows
|
||||||
|
// use the coordinates of XRandRs primary screen instead
|
||||||
|
// this is required to let the fullscreen window appear on the primary screen
|
||||||
|
if (mode.isFullscreenCapable() && current_displaymode_extension == XRANDR) {
|
||||||
|
Screen primaryScreen = XRandR.DisplayModetoScreen(Display.getDisplayMode());
|
||||||
|
x = primaryScreen.xPos;
|
||||||
|
y = primaryScreen.yPos;
|
||||||
|
}
|
||||||
|
|
||||||
current_window = nCreateWindow(getDisplay(), getDefaultScreen(), handle, mode, current_window_mode, x, y, undecorated, parent_window, resizable);
|
current_window = nCreateWindow(getDisplay(), getDefaultScreen(), handle, mode, current_window_mode, x, y, undecorated, parent_window, resizable);
|
||||||
|
|
||||||
// Set the WM_CLASS hint which is needed by some WM's e.g. Gnome Shell
|
// Set the WM_CLASS hint which is needed by some WM's e.g. Gnome Shell
|
||||||
|
@ -603,12 +611,17 @@ final class LinuxDisplay implements DisplayImplementation {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void switchDisplayModeOnTmpDisplay(DisplayMode mode) throws LWJGLException {
|
private void switchDisplayModeOnTmpDisplay(DisplayMode mode) throws LWJGLException {
|
||||||
incDisplay();
|
if (current_displaymode_extension == XRANDR) {
|
||||||
try {
|
// let Xrandr set the display mode
|
||||||
nSwitchDisplayMode(getDisplay(), getDefaultScreen(), current_displaymode_extension, mode);
|
XRandR.setConfiguration(false, XRandR.DisplayModetoScreen(mode));
|
||||||
} finally {
|
} else {
|
||||||
decDisplay();
|
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;
|
private static native void nSwitchDisplayMode(long display, int screen, int extension, DisplayMode mode) throws LWJGLException;
|
||||||
|
|
||||||
|
@ -625,11 +638,11 @@ final class LinuxDisplay implements DisplayImplementation {
|
||||||
public void resetDisplayMode() {
|
public void resetDisplayMode() {
|
||||||
lockAWT();
|
lockAWT();
|
||||||
try {
|
try {
|
||||||
if( current_displaymode_extension == XRANDR && savedXrandrConfig.length > 0 )
|
if( current_displaymode_extension == XRANDR )
|
||||||
{
|
{
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||||
public Object run() {
|
public Object run() {
|
||||||
XRandR.setConfiguration( savedXrandrConfig );
|
XRandR.restoreConfiguration();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -727,12 +740,12 @@ final class LinuxDisplay implements DisplayImplementation {
|
||||||
throw new LWJGLException("No modes available");
|
throw new LWJGLException("No modes available");
|
||||||
switch (current_displaymode_extension) {
|
switch (current_displaymode_extension) {
|
||||||
case XRANDR:
|
case XRANDR:
|
||||||
savedXrandrConfig = AccessController.doPrivileged(new PrivilegedAction<Screen[]>() {
|
saved_mode = AccessController.doPrivileged(new PrivilegedAction<DisplayMode>() {
|
||||||
public Screen[] run() {
|
public DisplayMode run() {
|
||||||
return XRandR.getConfiguration();
|
XRandR.saveConfiguration();
|
||||||
|
return XRandR.ScreentoDisplayMode(XRandR.getConfiguration());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
saved_mode = getCurrentXRandrMode();
|
|
||||||
break;
|
break;
|
||||||
case XF86VIDMODE:
|
case XF86VIDMODE:
|
||||||
saved_mode = modes[0];
|
saved_mode = modes[0];
|
||||||
|
@ -929,13 +942,29 @@ final class LinuxDisplay implements DisplayImplementation {
|
||||||
public DisplayMode[] getAvailableDisplayModes() throws LWJGLException {
|
public DisplayMode[] getAvailableDisplayModes() throws LWJGLException {
|
||||||
lockAWT();
|
lockAWT();
|
||||||
try {
|
try {
|
||||||
incDisplay();
|
incDisplay();
|
||||||
try {
|
if (current_displaymode_extension == XRANDR) {
|
||||||
DisplayMode[] modes = nGetAvailableDisplayModes(getDisplay(), getDefaultScreen(), current_displaymode_extension);
|
// nGetAvailableDisplayModes cannot be trusted. Use it only for bitsPerPixel
|
||||||
return modes;
|
DisplayMode[] nDisplayModes = nGetAvailableDisplayModes(getDisplay(), getDefaultScreen(), current_displaymode_extension);
|
||||||
} finally {
|
int bpp = 24;
|
||||||
decDisplay();
|
if (nDisplayModes.length > 0) {
|
||||||
}
|
bpp = nDisplayModes[0].getBitsPerPixel();
|
||||||
|
}
|
||||||
|
// get the resolutions and frequencys from XRandR
|
||||||
|
Screen[] resolutions = XRandR.getResolutions(XRandR.getScreenNames()[0]);
|
||||||
|
DisplayMode[] modes = new DisplayMode[resolutions.length];
|
||||||
|
for (int i = 0; i < modes.length; i++) {
|
||||||
|
modes[i] = new DisplayMode(resolutions[i].width, resolutions[i].height, bpp, resolutions[i].freq);
|
||||||
|
}
|
||||||
|
return modes;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
DisplayMode[] modes = nGetAvailableDisplayModes(getDisplay(), getDefaultScreen(), current_displaymode_extension);
|
||||||
|
return modes;
|
||||||
|
} finally {
|
||||||
|
decDisplay();
|
||||||
|
}
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
unlockAWT();
|
unlockAWT();
|
||||||
}
|
}
|
||||||
|
@ -1101,11 +1130,11 @@ final class LinuxDisplay implements DisplayImplementation {
|
||||||
if (current_window_mode == FULLSCREEN_NETWM) {
|
if (current_window_mode == FULLSCREEN_NETWM) {
|
||||||
nIconifyWindow(getDisplay(), getWindow(), getDefaultScreen());
|
nIconifyWindow(getDisplay(), getWindow(), getDefaultScreen());
|
||||||
try {
|
try {
|
||||||
if( current_displaymode_extension == XRANDR && savedXrandrConfig.length > 0 )
|
if( current_displaymode_extension == XRANDR )
|
||||||
{
|
{
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||||
public Object run() {
|
public Object run() {
|
||||||
XRandR.setConfiguration( savedXrandrConfig );
|
XRandR.restoreConfiguration();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -49,6 +49,18 @@ public class XRandR
|
||||||
{
|
{
|
||||||
private static Screen[] current;
|
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<String, Screen[]> screens;
|
private static Map<String, Screen[]> screens;
|
||||||
|
|
||||||
private static void populate()
|
private static void populate()
|
||||||
|
@ -89,7 +101,13 @@ public class XRandR
|
||||||
name = sa[ 0 ];
|
name = sa[ 0 ];
|
||||||
|
|
||||||
// save position of this screen, will be used later when current modeline is parsed
|
// 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 ] ) )
|
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() ] ) );
|
screens.put( name, possibles.toArray( new Screen[ possibles.size() ] ) );
|
||||||
|
|
||||||
current = currentList.toArray(new Screen[currentList.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 )
|
catch( Throwable e )
|
||||||
{
|
{
|
||||||
|
@ -117,23 +146,33 @@ public class XRandR
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The current screen configuration, or an empty array if
|
* @return The current screen configuration of the primary device,
|
||||||
* xrandr is not supported
|
* or an empty array if xrandr is not supported
|
||||||
*/
|
*/
|
||||||
public static Screen[] getConfiguration()
|
public static Screen[] getConfiguration()
|
||||||
{
|
{
|
||||||
populate();
|
populate();
|
||||||
|
|
||||||
|
// find and return primary
|
||||||
|
for (Screen screen : current) {
|
||||||
|
if (screen.name.equals(primaryScreenIdentifier)) {
|
||||||
|
return new Screen[]{screen};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// problem with primary device, fall back to old behaviour
|
||||||
return current.clone();
|
return current.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param disableOthers
|
||||||
|
* if screens not included in screens should be turned off (true) or left alone (false)
|
||||||
* @param screens
|
* @param screens
|
||||||
* The desired screen set, may not be <code>null</code>
|
* The desired screen set, may not be <code>null</code>
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
* if no screens are specified
|
* if no screens are specified
|
||||||
*/
|
*/
|
||||||
public static void setConfiguration(Screen... screens)
|
public static void setConfiguration(boolean disableOthers, Screen... screens)
|
||||||
{
|
{
|
||||||
if( screens.length == 0 )
|
if( screens.length == 0 )
|
||||||
throw new IllegalArgumentException( "Must specify at least one screen" );
|
throw new IllegalArgumentException( "Must specify at least one screen" );
|
||||||
|
@ -141,22 +180,24 @@ public class XRandR
|
||||||
List<String> cmd = new ArrayList<String>();
|
List<String> cmd = new ArrayList<String>();
|
||||||
cmd.add( "xrandr" );
|
cmd.add( "xrandr" );
|
||||||
|
|
||||||
// switch off those in the current set not in the new set
|
if (disableOthers) {
|
||||||
for ( Screen screen : current ) {
|
// switch off those in the current set not in the new set
|
||||||
boolean found = false;
|
for ( Screen screen : current ) {
|
||||||
for ( Screen screen1 : screens ) {
|
boolean found = false;
|
||||||
if ( screen1.name.equals(screen.name) ) {
|
for ( Screen screen1 : screens ) {
|
||||||
found = true;
|
if ( screen1.name.equals(screen.name) ) {
|
||||||
break;
|
found = true;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( !found ) {
|
if ( !found ) {
|
||||||
cmd.add("--output");
|
cmd.add("--output");
|
||||||
cmd.add(screen.name);
|
cmd.add(screen.name);
|
||||||
cmd.add("--off");
|
cmd.add("--off");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// set up new set
|
// set up new set
|
||||||
for ( Screen screen : screens )
|
for ( Screen screen : screens )
|
||||||
|
@ -184,6 +225,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(true, savedConfiguration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the name of connected screens, or an empty array if
|
* @return the name of connected screens, or an empty array if
|
||||||
* xrandr is not supported
|
* xrandr is not supported
|
||||||
|
@ -275,6 +335,28 @@ public class XRandR
|
||||||
screenPosition[1] = Integer.parseInt(m.group(4));
|
screenPosition[1] = Integer.parseInt(m.group(4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Screen DisplayModetoScreen(DisplayMode mode) {
|
||||||
|
populate();
|
||||||
|
Screen primary = findPrimary(current);
|
||||||
|
return new Screen(primary.name, mode.getWidth(), mode.getHeight(), mode.getFrequency(), primary.xPos, primary.yPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DisplayMode ScreentoDisplayMode(Screen... screens) {
|
||||||
|
populate();
|
||||||
|
Screen primary = findPrimary(screens);
|
||||||
|
return new DisplayMode(primary.width, primary.height, 24, primary.freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Screen findPrimary(Screen... screens) {
|
||||||
|
for (Screen screen : screens) {
|
||||||
|
if (screen.name.equals(primaryScreenIdentifier)) {
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fallback
|
||||||
|
return screens[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the configuration of a monitor.
|
* Encapsulates the configuration of a monitor.
|
||||||
* Resolution and freq are fixed, position is mutable
|
* Resolution and freq are fixed, position is mutable
|
||||||
|
|
Loading…
Reference in New Issue