Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dual monitor fix #1238

Closed
wants to merge 1 commit into from
Closed

Conversation

bloodsword
Copy link
Contributor

@bloodsword bloodsword commented Jun 5, 2017

SFML Tasks

  • Test and confirm fix by multiple people/distros/window managers

This should fix #1226.

XRRSetCrtcConfig is now used to set video mode instead of XRRSetScreenConfig.

@MarioLiebisch
Copy link
Member

Ah, very cool. Found a similar solution but couldn't be bothered trying to figure out the correct types etc. :)

Copy link
Member

@mantognini mantognini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a quick note on style: indentation is broken in a few places, there are extra spaces at the end of lines and some parenthesis are missing (see here). Otherwise, I can't judge much the patch as I can't test it. I'll trust @MarioLiebisch for that.

That being said, thanks for the PR! If you manage to fix the issues and squash all that in a nice commit that'd be awesome! :-)

Commit says "Mouse still can't be used in the second screen.". Do you have some ideas to fix that as well?

// Check XRandR version, 1.2 required
if(!XRRQueryVersion(m_display, &xRandRMajor, &xRandRMinor) || xRandRMajor < 1 || xRandRMinor < 2 )
{
err() << "XRandR is to old" << std::endl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/to/too/

Check will fail once v.2 is release (although it's not for tomorrow).

@MarioLiebisch
Copy link
Member

I know it's buggy in its current form and I think this is the right way to go, but I don't have a multi monitor setup to actually test this. However, running a program in fullscreen typically means you can't interact with anything on the second screen/desktop since it has exclusive access. At least that's how it's working on Windows. You can't force the ability to continue working on a secondary display.

@eXpl0it3r
Copy link
Member

Can this be tested in a VM?

@eXpl0it3r eXpl0it3r added this to the 2.5 milestone Jun 5, 2017
@MarioLiebisch
Copy link
Member

In theory, but never got multiple screens to work properly. I can set two displays, but "Displays" still only lists a single one.

@eXpl0it3r eXpl0it3r added this to Discussion in SFML 2.5.0 Jun 5, 2017
@eXpl0it3r eXpl0it3r moved this from Discussion to Review & Testing in SFML 2.5.0 Jun 5, 2017
@bloodsword
Copy link
Contributor Author

I changed XRandr check to accept a potential v2.
I fixed code style and squashed my commits.

The message "Mouse still can't be used in the second screen." was inaccurate, actually it's possible but you have to alt+tab.

Copy link
Member

@mantognini mantognini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I think X11 is tricky enough to be a bit picky about the implementation in order to make it easily maintainable. :-)

@@ -56,7 +56,7 @@
#include <SFML/Window/Unix/GlxContext.hpp>
typedef sf::priv::GlxContext ContextType;
#endif

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra spaces

output = XRRGetOutputPrimary(m_display, rootWindow);

// Check if output return is valid, otherwise use the first screen
if(output == None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing space after if

m_oldVideoMode = XRRConfigCurrentConfiguration(config, &currentRotation);
// If version > 1.2 get the primary screen else take the first screen
RROutput output;
if ((xRandRMajor == 1 && xRandRMinor >= 3) || xRandRMajor > 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to follow strictly our style rules, more parentheses are needed. But I'd argue it's more readable as is. Do others agree? (It's also the case in a few other places.)

XRRFreeScreenResources(res);

// If outputInfo->connection == RR_Disconnected, free output info
if(!outputInfo)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing space

// Free output info
XRRFreeOutputInfo(outputInfo);

// Free crtc info
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the // Free <stuff> comment should be removed -- they don't bring much.

}

// Check XRandR version, 1.2 required
if (!XRRQueryVersion(m_display, &xRandRMajor, &xRandRMinor) || xRandRMajor < 1 || (xRandRMajor == 1 && xRandRMinor < 2 ))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

} // namespace priv

} // namespace sf
}// namespace sf
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space was removed.


// Set "this" as the current fullscreen window
fullscreenWindow = this;
for (int i = 0; i < res->nmode; i++)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it was like that before, but it would be much more elegant IMO to have i < res->nmode && !modeFound as a loop condition and remove the break statement, wouldn't it?

return;
}

// Get crtc info from crtc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

X11 & cie being far from trivial, I'd add in the comment what kind of concrete info we're trying to get from CRTC. (screen dimension and rotation?) Otherwise the comment seems of no additional interest than the next function call.

/// \return True if a valid XRandR version found, false otherwise
///
////////////////////////////////////////////////////////////
bool checkXRandR(int &xRandRMajor, int &xRandRMinor);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be int& x and not int &x.

@bloodsword
Copy link
Contributor Author

I pushed a new revision.
Sorry for code style. I hope I did not forget anything :)

Copy link
Member

@mantognini mantognini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update!

Regarding XRRGetOutputPrimary, looking at https://cgit.freedesktop.org/xorg/lib/libXrandr/refs/tags it seems the function is first tagged in 1.3. It should simply fail to compile with older version, unless I missed something, so we could remove the runtime check altogether.

If, for some X11 specific reason I'm not aware of, the runtime check is best/okay, then I've no complain. Otherwise, it would be actually a good news as the code would be simpler: we just need a version requirement in CMake and that's it. (v1.3 is 8 years old so it should not be an issue to assume it's available on SFML supported system, hence no need to have conditional code for backward compatibility IMO.)

// Get the available screen sizes
int nbSizes;
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
// If version > 1.2 get the primary screen else take the first screen
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: should be >=

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually version > 1.2, but maybe >= 1.3 is more readable.

RROutput output;
if ((xRandRMajor == 1 && xRandRMinor >= 3) || xRandRMajor > 1)
{
output = XRRGetOutputPrimary(m_display, rootWindow);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually wondering: is this function define in xrandr 1.2? Isn't it instead defined in 1.3+?

@bloodsword bloodsword force-pushed the dual-monitor-fix branch 2 times, most recently from bed993d to 03610d4 Compare June 13, 2017 19:18
@bloodsword
Copy link
Contributor Author

You are absolutely right about XRRGetOutputPrimary.
We can do a compile time check, then no additional version requirement will be needed in CMake.
As you said 1.3 is quite old now, so it's not really a big deal, but it does not require a lot of changes to do a compile time check, so I pushed a new revision.

Copy link
Member

@mantognini mantognini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be interesting to have feedback from others at this point I think. Some things are beyond my knowledge. @bloodsword, it goes without saying that your point of view is also welcome on those issues!

if (!XQueryExtension(m_display, "RANDR", &version, &version, &version))
// Check if the XRandR extension
int xRandRMajor, xRandRMinor;
if (!checkXRandR(xRandRMajor, xRandRMinor))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't care about the actual version, but just the presence of the extension, then I'd remove the two parameters of checkXRandR. Having the function is fine, but the simpler it is the better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not enough familiar with X11 & cie, but do we need to actually check for the extension? Or can't we assume that if we were able to link against xrandr the extension will be available at runtime? @binary1248, since you edited those line before, could you clarify that for me. Thanks. :-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As strange as it sounds, I've experienced implementations where not calling XQueryExtension would cause the extension to fail even if it should be supported. It seemed like calling XQueryExtension would load the extension or something. So even if it should be supported, performing the runtime "check" is still the safer variant.

// Check if the XRandR extension is present
int version;
if (!XQueryExtension(m_display, "RANDR", &version, &version, &version))
// Check if the XRandR extension
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment was truncated, leaving out the end of the sentence.

int nbSizes;
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
// Compile time check : if version >= 1.3 get the primary screen else take the first screen
#if (RANDR_MAJOR == 1 && RANDR_MINOR >= 3) || RANDR_MAJOR > 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question I'm asking myself is, do really want to support older versions? If not, it would make the code much simpler without those conditional compilation macros. What do @binary1248, @Bromeon and @MarioLiebisch (or anyone who's familiar with Linux actually) think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer runtime version checking. It is done in the above code already anyway, and X on Linux doesn't exactly make it trivial to detect library versions during compile time. X works based on Client-Server so it might even be possible that the header you compile against on the system doesn't match what the X server is actually running.

if (!XQueryExtension(m_display, "RANDR", &version, &version, &version))
// Check if the XRandR extension
int xRandRMajor, xRandRMinor;
if (!checkXRandR(xRandRMajor, xRandRMinor))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As strange as it sounds, I've experienced implementations where not calling XQueryExtension would cause the extension to fail even if it should be supported. It seemed like calling XQueryExtension would load the extension or something. So even if it should be supported, performing the runtime "check" is still the safer variant.

{
// XRandR extension is not supported: we cannot use fullscreen mode
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no reason to remove this comment.

int nbSizes;
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
// Compile time check : if version >= 1.3 get the primary screen else take the first screen
#if (RANDR_MAJOR == 1 && RANDR_MINOR >= 3) || RANDR_MAJOR > 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer runtime version checking. It is done in the above code already anyway, and X on Linux doesn't exactly make it trivial to detect library versions during compile time. X works based on Client-Server so it might even be possible that the header you compile against on the system doesn't match what the X server is actually running.


if ((sizes[i].width == static_cast<int>(mode.width)) && (sizes[i].height == static_cast<int>(mode.height)))
// If outputInfo->connection == RR_Disconnected, free output info
if (!outputInfo)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be outputInfo and single line if blocks omit brackets.

if (!modeFound)
{
err() << "Failed to find a matching RRMode for fullscreen mode, switching to window mode" << std::endl;
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resources not freed here.

@eXpl0it3r
Copy link
Member

@bloodsword Can you follow up on @binary1248's review?

@eXpl0it3r eXpl0it3r moved this from Review & Testing to Requires Adjustments in SFML 2.5.0 Aug 1, 2017
@bloodsword
Copy link
Contributor Author

@eXpl0it3r yes. I will try to push something this week.

@eXpl0it3r eXpl0it3r modified the milestones: 2.5, 2.6 Mar 23, 2018
@eliasdaler
Copy link
Contributor

Can someone provide a sample code for testing and what the expected/buggy behaviour looks like?
I'll be happy to test it out on my dual-monitor Linux setup. :)

@bloodsword
Copy link
Contributor Author

I don't know what the buggy behaviour looks like since my last commit.
Prior my last commit, @binary1248 describes some problems, it should be fixed, but except my own test I have no feedback.
@eXpl0it3r reports that some users had problems, but I have no more details.
If you manage to produce a bug with my pull request version (https://github.com/bloodsword/SFML/tree/dual-monitor-fix),
please tell me what is your setup, maybe I will manage to reproduce it and to fix it.

Here is a sample code to test (press escape to quit) :

#include <SFML/Graphics.hpp>

int main()
{  
    sf::RenderWindow window( sf::VideoMode::getDesktopMode(), "SFML test", sf::Style::Fullscreen);

    while (window.isOpen())
    {        
        sf::Event event;
        while (window.pollEvent(event))
        {  
            if ((event.type == sf::Event::Closed) || 
               ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)))
            {
                window.close();
                break;
            }
        } 
        window.clear();
        window.display();
        sf::sleep(sf::milliseconds(16));
    }

    return EXIT_SUCCESS;
}

The normal behaviour should be a black fullscreen on one of your screen, your other screen should stay active.
Mouse cursor should be locked in the fullscreen monitor except if you alt+tab.

@binary1248
Copy link
Member

I attribute the test failure during my last test in part to my "exotic" screen setup. I can't test with 2 screens of the same resolution because... well... I simply don't have 2 screens with the same resolution. If others who can test using screens with the same resolution report that this is still an improvement over the state without it, I am willing to accept it as a partial solution on the way to something more complete.

@bloodsword
Copy link
Contributor Author

I have no problem with same resolution screens (1280x1024 x 2),
and since my last commit (01 November 2017) I have no problem with different screens either(1680x1050 + 1280x1024).
@binary1248 did you try the latest commit ? If you did, any improvement since your 16 October review ?

@danieljpetersen
Copy link
Contributor

danieljpetersen commented Apr 9, 2018

edit: Apologies. See the next post.

@danieljpetersen
Copy link
Contributor

danieljpetersen commented Apr 9, 2018

Actually, I take all of that back. I did a double check and the damn thing was still linking to the current version of master. e18b9d2 behaves correctly for me (1920x1080 dual monitor setup).

@bloodsword
Copy link
Contributor Author

No problem. When I booted my Mint trying to reproduce the behaviour you describe I did the same mistake :)
Thanks for your feedback 👍

@eXpl0it3r eXpl0it3r moved this from Discussion to Review & Testing in SFML 2.6.0 Aug 13, 2018
@fahlmant
Copy link

fahlmant commented Aug 17, 2018

EDIT: I misunderstood the intention of this PR. Works for me, Fedora 28, KDE. +1

@eliasdaler
Copy link
Contributor

Tested on Ubuntu 18.10, NVIDIA driver 396.51. Both "master" and this branch work as expected for me...

One monitor is 1366x768. The other is 1920x1080. The fullscreen shows up on the primary monitor.

@eXpl0it3r eXpl0it3r dismissed binary1248’s stale review August 17, 2018 21:38

Based on an updated diff

@eXpl0it3r eXpl0it3r added this to Discussion in SFML 2.5.1 via automation Aug 20, 2018
@eXpl0it3r eXpl0it3r removed this from Review & Testing in SFML 2.6.0 Aug 20, 2018
@eXpl0it3r eXpl0it3r modified the milestones: 2.6, 2.5.1 Aug 20, 2018
@eXpl0it3r eXpl0it3r moved this from Discussion to Review & Testing in SFML 2.5.1 Aug 30, 2018
@bloodsword
Copy link
Contributor Author

Nice to read your feedbacks.
Tell me if you need me to rebase the PR on master.

@eXpl0it3r eXpl0it3r moved this from Review & Testing to Ready in SFML 2.5.1 Sep 8, 2018
@eXpl0it3r
Copy link
Member

Merged in 46ce05c

@eXpl0it3r eXpl0it3r closed this Sep 8, 2018
SFML 2.5.1 automation moved this from Ready to Done Sep 8, 2018
@SFML SFML deleted a comment from eXpl0it3r Dec 31, 2022
@SFML SFML deleted a comment from eXpl0it3r Dec 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
SFML 2.5.1
  
Done
Development

Successfully merging this pull request may close these issues.

Fullscreen runs on second monitor and closes the main one in dual monitor setup, Linux