[FIXED] xRandR and dual screens

Started by ryanm, February 28, 2010, 17:31:51

Previous topic - Next topic

ryanm

Howdy

I run linux with two screens - configured through xrandr like so:
xrandr --output LVDS1 --auto --pos 0x300 --output VGA1 --auto --pos 1440x0

The problem is: whenever I exit any LWJGL application one of my displays is switched off. Setting LWJGL_DISABLE_XRANDR fixes this problem, but then fullscreen mode breaks - the app permanently loses focus.

I've had a quick poke through the lwjgl sources and can see why this happens. On startup, the current screen configuration is saved as a DisplayMode object, which has no notion of dual screens. This saved mode is restored on shutdown, thus disabling one of my screens.

The quickest/easiest fix that I can see is to store the startup display mode on the native side, avoiding DisplayMode's lack of dual-screen knowledge.
Does this sound reasonable? If I fumble my way through adding this (probably by adding save/restore mode methods to LinuxDisplay and display.c) what will I break?

kappa

I don't you would break anything.

Would be great if you could provide a patch for everyone to use :)

ryanm

I had a stab at it, but without success :-\
I've attached the files I altered for the amusement of those who actually know what they're doing with this stuff.

elias_naur: I throw myself upon thy mercy.

elias

Hi there,

I don't have much time to spare to lwjgl development at the moment, so I'm not really able to help in this. Without looking a the code, we probably need the equivalent of Windows' temporary mode switches. If that is not possible, I'd look for a way to only set the display mode for one monitor and leave the rest alone, since we really want to avoid the multimonitor mess, especially since LWJGL itself does not expose any multimonitor APIs.

- elias

kappa

elias great to see your still around :)

I can't really help with this problem due to now knowing enough about the native stuff, but would like to point out that there is a bounty for anyone who fixes this issue/bug (+ mouse grab on multiple monitors) as set in this thread. Can confirm that Notch paid (donated) for a previous lwjgl bug fix.

So if anyone is up for a quick bounty and eternal lwjgl bug fixing fame, do have a go at fixing it, I'm sure the lwjgl dev's wouldn't object :)

ryanm

I've tried the code on this page and the same problem is present, so for once my own cack-handedness isn't the root problem. I've also had a poke through the source of the command-line xrandr utility, and it uses a lot of stuff that isn't mentioned in xrandr.h's man page.
I'm thinking the way to go here is just to call out to the xrandr utility. Parse and store the output of "xrandr -q" on startup, and then restore that config on shutdown. No native code for me to write, and the current method is still there if the xrandr utility isn't present for whatever reason.
Does anyone see any problems looming with this approach?

ryanm

Well that went well. I created a wee static class that manipulates the xrandr command-line, and then altered LinuxDisplay as little as possible to plumb it in.
End result: My screen configuration remains unmolested on exit :)
Any chance of this being included in LWJGL?
Find files attached.

diff of old and new LinuxDisplay:
51a52
> import org.lwjgl.opengl.XRandR.Screen;
115a117,118
>
>       private Screen[] savedXrandrConfig;
525c528,535
<                       switchDisplayMode(saved_mode);
---
>                       if( current_displaymode_extension == XRANDR && savedXrandrConfig.length > 0 )
>                       {
>                               XRandR.setConfiguration( savedXrandrConfig );
>                       }
>                       else
>                       {
>                               switchDisplayMode(saved_mode);
>                       }
610a621
>                                       savedXrandrConfig = XRandR.getConfiguration();
883c894,901
<                               switchDisplayModeOnTmpDisplay(saved_mode);
---
>                               if( current_displaymode_extension == XRANDR && savedXrandrConfig.length > 0 )
>                               {
>                                       XRandR.setConfiguration( savedXrandrConfig );
>                               }
>                               else
>                               {
>                                       switchDisplayModeOnTmpDisplay(saved_mode);
>                               }

Matzon

Great. Two comments:
1) using processes sounds ... brittle
2) not using linux so cant tes't, no sure whats in all this xrandr.

Any linux users to comment and/or test?

kappa


ryanm

Quote from: Matzon on March 02, 2010, 16:56:04
1) using processes sounds ... brittle

Agreed. It feels slightly dirty to me as well. The risks as I see them are:

  • The output format of xrandr changes, breaking the parsing: xrandr is the standard way to manipulate screen resolution and so on - the output is probably relied upon by plenty more people than me. I can only imagine that the devs will be loathe to alter it.
  • Weirdly configured systems that have the xrandr library but not the command-line: Sounds like a pathologically bizarre case, but the current behaviour will work as normal here
And on the purely positive side:

  • The current behaviour (close a window - your monitor switches off) is just flat-out broken
  • Less native code to deal with
  • Multi-monitor information is exposed. Might be useful in the future.

On the whole I reckon it's a win. To handle this stuff properly in your own native code, you'd essentially be reimplementing the xrandr command-line. Besides, hooking up simple command-line tools to form new programs is the Linux WayTM.

edit: probably should have put this in the previous post. A jar with the changes included is over here, just gagging for a bit of firm testing.
edit2: Made some small changes to the XRandr class - fails faster, more defensive, logs to LWJGLUtil, etc. Find file attached, jar linked above updated also.

princec

Is there not like an XRandR library or something that has an API we can call out to?

Cas :)

ryanm

Yup, that's what happens currently, but display.c only uses the 1.1 specification which doesn't handle multiple monitors. We could write new native code for xrandr 1.2, but:

  • After a lot of work, it'd end up being at best a duplication of the xrandr comand-line tool
  • Someone would need to actually do the work. Elias doesn't have the time, I don't have the skill
Calling out to the command line:

  • Works right now
  • Fails gracefully back to current behaviour
  • Is easy to maintain - it's just java. If the output/argument format changes in the future, it's trivial to check the version number and act accordingly
  • Shifts support burden to xrandr devs: when some linux user reports dual-screen problems on their beowulf cluster of analytical engines and aztec calendar wheels, you can tell him to get xrandr working first, and then to come back to you
The only costs that I can see is an extra 3.8KiB in lwjgl.jar and parsing a few lines of text on startup. I understand that it feels a bit mucky, but I reckon pragmatism wins here.

Matzon

+1 to get it in - with some testing on different linux platforms.

delt0r

I will run some tests. I have quite a few single and dual screen Linux boxes around. Including one with 4 video cards and 3 monitors ;)

But it won't able to till next week when i get back from Germany and we only have Nvida hardware.

xRandR does have some problems i know. Like you can't have duplicate modelines. Nvidia hack around this by giving fake refresh rates. I hope this doesn't cause a problem.

OT:
Later in the year i will want multimonitor support in lwjgl. I am currently planing to to write my own patch since core dev support for dual+ screens seems low. However this would be a BSD patch and i would try to keep it current with lwjgl. (I have looked that the code. it would be a "refactor" of Display).   
If you want a plot read a book and leave Hollywood out of it.

princec

I think possibly the best official way to really support multimonitors is to use AWT which already has a pretty comprehensive display configuration API. LWJGL's Display is really designed for lightweight simplicity and aims for the common case of one simple display.

Cas :)