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

Move fullscreen modes to not touch physical resolutions #270

Merged
merged 20 commits into from
Sep 7, 2017

Conversation

pedrocr
Copy link
Contributor

@pedrocr pedrocr commented Aug 29, 2017

The previous XF86 resolution switching was broken and everything seems to have moved on to xrandr. Use that instead while cleaning up the code a bit as well. Right now everything seems to work fine. The only bug I've noticed is that at least in Unity after the resolution change the top bar is still there. Doing an alt-tab from and to the app again makes _NET_WM_STATE_FULLSCREEN take effect. Don't know how to fix that right now but this is already much better than what was before.

@pedrocr pedrocr force-pushed the maximization branch 2 times, most recently from bbb92fd to c4bf208 Compare August 29, 2017 16:43
@Ralith
Copy link
Contributor

Ralith commented Aug 29, 2017

Has this been tested on a multi-monitor system? XDisplayWidth/Height are definitely the wrong function here, and I suspect XRRSizes is inappropriate as well. Under XRandR, the root window spans all outputs; there is only one native X11 "screen" no matter how many monitors you have. The xrandr command line utility should contain examples of correct use, though it's not easy to make sense of.

In particular, we should be working in terms of XRandR "outputs," not X11 screens. MonitorId should be adjusted to account for this. XRRGetOutputInfo provides access to the current set of output states.

@pedrocr
Copy link
Contributor Author

pedrocr commented Aug 29, 2017

Haven't tested on multiscreen yet but I have a few external screens I can test this with. I assumed MonitorId was all we needed given all the functions take that as input but maybe it's not so simple.

@pedrocr
Copy link
Contributor Author

pedrocr commented Aug 30, 2017

This now has the basics needed for proper multiscreen and the resolution changes seem to work. I still need to place the window in the correct place and figure out why in some cases it will segfault.

@pedrocr pedrocr force-pushed the maximization branch 2 times, most recently from 54ea27a to a0d929f Compare August 30, 2017 23:35
@pedrocr pedrocr changed the title Fix X11 screen resolution change using XrandR Move fullscreen modes to not touch physical resolutions Aug 31, 2017
@pedrocr
Copy link
Contributor Author

pedrocr commented Aug 31, 2017

@tomaka after discussions on IRC with @Ralith and looking at Wayland it seems much cleaner to just never change the physical hardware resolution. With LCD panels there's no actual resolution change and GPU scaling is cheap enough that apps should just scale to whatever the physical resolution is and not do any mode switching. So the proposed semantics are:

  • FullScreen::None: make the window normal with decorations at whatever size has been set
  • FullScreen::CurrentMonitor: make it fullscreen in whatever monitor it happens to be in right now
  • FullScreen::SpecificMonitor(MonitorId): make it fullscreen in a specific monitor specified by the app

The X11 code for this ends up very clean and should even make it easy to support weird setups like videowalls and MST monitors.

@pedrocr
Copy link
Contributor Author

pedrocr commented Aug 31, 2017

Implemented XRandR 1.5 now so even MST/videowalls should work fine.

src/lib.rs Outdated
None,
Windowed,
Exclusive(MonitorId),
/// Set fullscreen in whatever monitor the window happens to be right now
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that's a bad design. The user should just have a way to retrieve the monitor of the window instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In that case we can just get rid of the enum and do .set_/.with_fullscreen(Option<MonitorId>) and do a Window::get_monitor(). How does that sound?

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess it's good.

@pedrocr
Copy link
Contributor Author

pedrocr commented Sep 3, 2017

I've implemented the interface as discussed but I'm not too sure of it. w.set_fullscreen(Some(w.get_current_monitor())) ends up much slower than w.set_fullscreen(FullScreen::CurrentMonitor) because the first, at least on X11, needs to enumerate monitors and check the window position and dimensions against it. The second, again on X11, just needs to set a window manager hint and it does everything for us, possibly with more info than we have.

@pedrocr pedrocr force-pushed the maximization branch 2 times, most recently from 6b7bd9a to fbbd347 Compare September 3, 2017 15:47
@pedrocr
Copy link
Contributor Author

pedrocr commented Sep 3, 2017

The basics should be done and the remaining issues are:

  • Not all platforms implement all things. Implementations for get_current_monitor() and set_fullscreen() are missing in most non-X11 platforms. The code compiles and is no worse than before though.
  • with_fullscreen() implementations (particularly Windows) should stop fiddling with resolutions and just set the window fullscreen at the current resolution in the given monitor
  • It may make sense to go back to .set_fullscreen(FullScreen::None/CurrentMonitor/Monitor<MonitorId>) as at least on X11 .set_fullscreen(FullScreen::CurrentMonitor) can be implemented much faster than .set_fullscreen(Some(window.get_current_monitor()))

@pedrocr pedrocr force-pushed the maximization branch 7 times, most recently from ac29dd8 to c824e14 Compare September 5, 2017 20:27
@pedrocr
Copy link
Contributor Author

pedrocr commented Sep 5, 2017

@tomaka From my point of view this is ready to merge. Let me know if you want something else.

xinput2: xinput2,
xlib_xcb: xlib_xcb,
display: display,
xlib,
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's keep compatibility with older Rust versions if we can. Please don't use that new syntax.

}

#[inline]
pub fn set_fullscreen(&self, state: FullScreenState) {
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should contain unimplemented!().

@@ -280,11 +279,16 @@ impl Window {
}

#[inline]
pub fn set_maximized(&self, maximized: bool) {
pub fn set_maximized(&self, _maximized: bool) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should contain unimplemented!().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't set these as unimplemented because they're safe as no-ops. No need to panic the app just because we can't set it as maximized/fullscreen.

Copy link
Contributor

Choose a reason for hiding this comment

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

Using no-ops means that these functions will likely be left unimplemented for years.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, done now

}

#[inline]
pub fn set_fullscreen(&self, state: FullScreenState) {
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should contain unimplemented!().

@@ -636,11 +636,16 @@ impl Window {
}

#[inline]
pub fn set_maximized(&self, maximized: bool) {
pub fn set_maximized(&self, _maximized: bool) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should contain unimplemented!().


use super::XConnection;

#[derive(Clone)]
pub struct MonitorId(pub Arc<XConnection>, pub u32);
pub struct MonitorId {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wrong indentation


#[inline]
pub fn get_current_monitor(&self) -> RootMonitorId {
unimplemented!()
Copy link
Contributor

Choose a reason for hiding this comment

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

Android provides only one dummy monitor. This function should return RootMonitorId(MonitorId).


#[inline]
pub fn get_current_monitor(&self) -> RootMonitorId {
unimplemented!()
Copy link
Contributor

Choose a reason for hiding this comment

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

iOS provides only one dummy monitor. This function should return RootMonitorId(MonitorId).


#[inline]
pub fn get_position(&self) -> (u32, u32) {
unimplemented!()
Copy link
Contributor

Choose a reason for hiding this comment

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

(0, 0)


#[inline]
pub fn get_position(&self) -> (u32, u32) {
unimplemented!()
Copy link
Contributor

Choose a reason for hiding this comment

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

(0, 0)

The previous XF86 resolution switching was broken and everything
seems to have moved on to xrandr. Use that instead while cleaning
up the code a bit as well.
Wayland has made the decision that apps shouldn't change screen
resolutions and just take the screens as they've been setup. In the
modern world where GPU scaling is cheap and LCD panels are scaling
anyway it makes no sense to make "physical" resolution changes when
software should be taking care of it. This massively simplifies the
code and makes it easier to extend to more niche setups like MST and
videowalls.
Moving to just having two states None and Some(MonitorId) and then
being able to set full screen in the current monitor with something
like:

window.set_fullscreen(Some(window.current_monitor()));
Do it by iterating over the available monitors and finding which
has the biggest overlap with the window. For this MonitorId needs
a new get_position() that needs to be implemented for all platforms.
Since we're no longer using XF86 there's no need to keep the package
around for CI.
On Android and iOS we can assume single screen apps that are already
fullscreen and maximized so there are a few methods that are implemented
by just returning a fixed value or not doing anything.
These would be safe as no-ops but we should make it explicit so
there is more of an incentive to actually implement them.
@tomaka tomaka merged commit 59c33d2 into rust-windowing:master Sep 7, 2017
@tomaka
Copy link
Contributor

tomaka commented Sep 7, 2017

Thanks for all the trouble

@pedrocr
Copy link
Contributor Author

pedrocr commented Sep 7, 2017

No trouble, hope it helps. Do ping me if you need help with any of this code or with anything on X11.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants