Merge pull request #646 from adambadawy/master

Fix fullscreen on X11
This commit is contained in:
tomaka 2015-11-11 20:38:12 +01:00
commit 6a3ee2af75
2 changed files with 79 additions and 24 deletions

View file

@ -85,39 +85,39 @@ osmesa-sys = "0.0.5"
wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] } wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] }
wayland-kbd = "0.2.0" wayland-kbd = "0.2.0"
wayland-window = "0.1.0" wayland-window = "0.1.0"
x11-dl = "~2.0" x11-dl = "~2.2"
[target.x86_64-unknown-linux-gnu.dependencies] [target.x86_64-unknown-linux-gnu.dependencies]
osmesa-sys = "0.0.5" osmesa-sys = "0.0.5"
wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] } wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] }
wayland-kbd = "0.2.0" wayland-kbd = "0.2.0"
wayland-window = "0.1.0" wayland-window = "0.1.0"
x11-dl = "~2.0" x11-dl = "~2.2"
[target.arm-unknown-linux-gnueabihf.dependencies] [target.arm-unknown-linux-gnueabihf.dependencies]
osmesa-sys = "0.0.5" osmesa-sys = "0.0.5"
wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] } wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] }
wayland-kbd = "0.2.0" wayland-kbd = "0.2.0"
wayland-window = "0.1.0" wayland-window = "0.1.0"
x11-dl = "~2.0" x11-dl = "~2.2"
[target.aarch64-unknown-linux-gnu.dependencies] [target.aarch64-unknown-linux-gnu.dependencies]
osmesa-sys = "0.0.5" osmesa-sys = "0.0.5"
wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] } wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] }
wayland-kbd = "0.2.0" wayland-kbd = "0.2.0"
wayland-window = "0.1.0" wayland-window = "0.1.0"
x11-dl = "~2.0" x11-dl = "~2.2"
[target.x86_64-unknown-dragonfly.dependencies] [target.x86_64-unknown-dragonfly.dependencies]
osmesa-sys = "0.0.5" osmesa-sys = "0.0.5"
wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] } wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] }
wayland-kbd = "0.2.0" wayland-kbd = "0.2.0"
wayland-window = "0.1.0" wayland-window = "0.1.0"
x11-dl = "~2.0" x11-dl = "~2.2"
[target.x86_64-unknown-freebsd.dependencies] [target.x86_64-unknown-freebsd.dependencies]
osmesa-sys = "0.0.5" osmesa-sys = "0.0.5"
wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] } wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] }
wayland-kbd = "0.2.0" wayland-kbd = "0.2.0"
wayland-window = "0.1.0" wayland-window = "0.1.0"
x11-dl = "~2.0" x11-dl = "~2.2"

View file

@ -54,7 +54,7 @@ pub struct XWindow {
pub context: Context, pub context: Context,
is_fullscreen: bool, is_fullscreen: bool,
screen_id: libc::c_int, screen_id: libc::c_int,
xf86_desk_mode: *mut ffi::XF86VidModeModeInfo, xf86_desk_mode: ffi::XF86VidModeModeInfo,
ic: ffi::XIC, ic: ffi::XIC,
im: ffi::XIM, im: ffi::XIM,
colormap: ffi::Colormap, colormap: ffi::Colormap,
@ -87,7 +87,7 @@ impl Drop for XWindow {
let _lock = GLOBAL_XOPENIM_LOCK.lock().unwrap(); let _lock = GLOBAL_XOPENIM_LOCK.lock().unwrap();
if self.is_fullscreen { if self.is_fullscreen {
(self.display.xf86vmode.XF86VidModeSwitchToMode)(self.display.display, self.screen_id, self.xf86_desk_mode); (self.display.xf86vmode.XF86VidModeSwitchToMode)(self.display.display, self.screen_id, &mut self.xf86_desk_mode);
(self.display.xf86vmode.XF86VidModeSetViewPort)(self.display.display, self.screen_id, 0, 0); (self.display.xf86vmode.XF86VidModeSetViewPort)(self.display.display, self.screen_id, 0, 0);
} }
@ -317,15 +317,12 @@ impl Window {
return Err(OsError(format!("Could not query the video modes"))); return Err(OsError(format!("Could not query the video modes")));
} }
let xf86_desk_mode = *modes.offset(0); let xf86_desk_mode: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(0));
// FIXME: `XF86VidModeModeInfo` is missing its `hskew` field. Therefore we point to
// `vsyncstart` instead of `vdisplay` as a temporary hack.
let mode_to_switch_to = if window_attrs.monitor.is_some() { let mode_to_switch_to = if window_attrs.monitor.is_some() {
let matching_mode = (0 .. mode_num).map(|i| { let matching_mode = (0 .. mode_num).map(|i| {
let m: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _); m let m: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _); m
}).find(|m| m.hdisplay == dimensions.0 as u16 && m.vsyncstart == dimensions.1 as u16); }).find(|m| m.hdisplay == dimensions.0 as u16 && m.vdisplay == dimensions.1 as u16);
if let Some(matching_mode) = matching_mode { if let Some(matching_mode) = matching_mode {
Some(matching_mode) Some(matching_mode)
@ -333,7 +330,7 @@ impl Window {
} else { } else {
let m = (0 .. mode_num).map(|i| { let m = (0 .. mode_num).map(|i| {
let m: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _); m let m: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _); m
}).find(|m| m.hdisplay >= dimensions.0 as u16 && m.vsyncstart == dimensions.1 as u16); }).find(|m| m.hdisplay >= dimensions.0 as u16 && m.vdisplay >= dimensions.1 as u16);
match m { match m {
Some(m) => Some(m), Some(m) => Some(m),
@ -435,16 +432,6 @@ impl Window {
window_attributes |= ffi::CWBackPixel; window_attributes |= ffi::CWBackPixel;
} }
// switching to fullscreen
if let Some(mut mode_to_switch_to) = mode_to_switch_to {
window_attributes |= ffi::CWOverrideRedirect;
unsafe {
(display.xf86vmode.XF86VidModeSwitchToMode)(display.display, screen_id, &mut mode_to_switch_to);
(display.xf86vmode.XF86VidModeSetViewPort)(display.display, screen_id, 0, 0);
set_win_attr.override_redirect = 1;
}
}
// finally creating the window // finally creating the window
let window = unsafe { let window = unsafe {
let win = (display.xlib.XCreateWindow)(display.display, root, 0, 0, dimensions.0 as libc::c_uint, let win = (display.xlib.XCreateWindow)(display.display, root, 0, 0, dimensions.0 as libc::c_uint,
@ -527,6 +514,64 @@ impl Window {
let is_fullscreen = window_attrs.monitor.is_some(); let is_fullscreen = window_attrs.monitor.is_some();
if is_fullscreen {
let state_atom = unsafe {
with_c_str("_NET_WM_STATE", |state|
(display.xlib.XInternAtom)(display.display, state, 0)
)
};
let fullscreen_atom = unsafe {
with_c_str("_NET_WM_STATE_FULLSCREEN", |state_fullscreen|
(display.xlib.XInternAtom)(display.display, state_fullscreen, 0)
)
};
let client_message_event = ffi::XClientMessageEvent {
type_: ffi::ClientMessage,
serial: 0,
send_event: 1, // true because we are sending this through `XSendEvent`
display: display.display,
window: window,
message_type: state_atom, // the _NET_WM_STATE atom is sent to change the state of a window
format: 32, // view `data` as `c_long`s
data: {
let mut data = ffi::ClientMessageData::new();
// This first `long` is the action; `1` means add/set following property.
data.set_long(0, 1);
// This second `long` is the property to set (fullscreen)
data.set_long(1, fullscreen_atom as i64);
data
}
};
let mut x_event = ffi::XEvent::from(client_message_event);
unsafe {
(display.xlib.XSendEvent)(
display.display,
root,
0,
ffi::SubstructureRedirectMask | ffi::SubstructureNotifyMask,
&mut x_event as *mut _
);
}
if let Some(mut mode_to_switch_to) = mode_to_switch_to {
unsafe {
(display.xf86vmode.XF86VidModeSwitchToMode)(
display.display,
screen_id,
&mut mode_to_switch_to
);
}
}
else {
println!("[glutin] Unexpected state: `mode` is None creating fullscreen window");
}
unsafe {
(display.xf86vmode.XF86VidModeSetViewPort)(display.display, screen_id, 0, 0);
}
}
// finish creating the OpenGL context // finish creating the OpenGL context
let context = match context { let context = match context {
Prototype::Glx(ctxt) => { Prototype::Glx(ctxt) => {
@ -565,6 +610,16 @@ impl Window {
input_handler: Mutex::new(XInputEventHandler::new(display, window, ic, window_attrs)) input_handler: Mutex::new(XInputEventHandler::new(display, window, ic, window_attrs))
}; };
unsafe {
let ref x_window: &XWindow = window.x.borrow();
(display.xlib.XSetInputFocus)(
display.display,
x_window.window,
ffi::RevertToParent,
ffi::CurrentTime
);
}
// returning // returning
Ok(window) Ok(window)
} }