Merge pull request #38 from tomaka/x11_fullscreen

X11 fullscreen
This commit is contained in:
tomaka 2014-09-19 20:36:50 +02:00
commit 3ac5f6d115
5 changed files with 164 additions and 44 deletions

View file

@ -1,5 +1,8 @@
language: rust language: rust
install:
- sudo apt-get install libXxf86vm-dev
os: os:
- linux - linux
- osx - osx

View file

@ -29,6 +29,7 @@ pub type XrmDatabase = *const (); // TODO: not sure
pub type XIC = *mut (); pub type XIC = *mut ();
pub type XID = uint; pub type XID = uint;
pub type XIM = *mut (); pub type XIM = *mut ();
pub type Screen = ();
pub static AllocNone: libc::c_int = 0; pub static AllocNone: libc::c_int = 0;
pub static AllocAll: libc::c_int = 1; pub static AllocAll: libc::c_int = 1;
@ -1337,8 +1338,26 @@ pub struct XButtonEvent {
pub same_screen: Bool, pub same_screen: Bool,
} }
#[repr(C)]
pub struct XF86VidModeModeInfo {
pub dotclock: libc::c_uint,
pub hdisplay: libc::c_ushort,
pub hsyncstart: libc::c_ushort,
pub hsyncend: libc::c_ushort,
pub htotal: libc::c_ushort,
pub hskew: libc::c_ushort,
pub vdisplay: libc::c_ushort,
pub vsyncstart: libc::c_ushort,
pub vsyncend: libc::c_ushort,
pub vtotal: libc::c_ushort,
pub flags: libc::c_uint,
privsize: libc::c_int,
private: libc::c_long,
}
#[link(name = "GL")] #[link(name = "GL")]
#[link(name = "X11")] #[link(name = "X11")]
#[link(name = "Xxf86vm")]
extern "C" { extern "C" {
pub fn XCloseDisplay(display: *mut Display); pub fn XCloseDisplay(display: *mut Display);
pub fn XCheckMaskEvent(display: *mut Display, event_mask: libc::c_long, pub fn XCheckMaskEvent(display: *mut Display, event_mask: libc::c_long,
@ -1375,6 +1394,10 @@ extern "C" {
pub fn XSetWMProtocols(display: *mut Display, w: Window, protocols: *mut Atom, pub fn XSetWMProtocols(display: *mut Display, w: Window, protocols: *mut Atom,
count: libc::c_int) -> Status; count: libc::c_int) -> Status;
pub fn XStoreName(display: *mut Display, w: Window, window_name: *const libc::c_char); pub fn XStoreName(display: *mut Display, w: Window, window_name: *const libc::c_char);
pub fn XScreenCount(display: *mut Display) -> libc::c_int;
pub fn XScreenOfDisplay(display: *mut Display, screen_number: libc::c_int) -> *const Screen;
pub fn XWidthOfScreen(screen: *const Screen) -> libc::c_int;
pub fn XHeightOfScreen(screen: *const Screen) -> libc::c_int;
pub fn XCloseIM(im: XIM) -> Status; pub fn XCloseIM(im: XIM) -> Status;
pub fn XOpenIM(display: *mut Display, db: XrmDatabase, res_name: *mut libc::c_char, pub fn XOpenIM(display: *mut Display, db: XrmDatabase, res_name: *mut libc::c_char,
@ -1408,6 +1431,13 @@ extern "C" {
pub fn glXSwapBuffers(dpy: *mut Display, drawable: GLXDrawable); pub fn glXSwapBuffers(dpy: *mut Display, drawable: GLXDrawable);
pub fn XkbSetDetectableAutoRepeat(dpy: *mut Display, detectable: bool, supported_rtm: *mut bool) -> bool; pub fn XkbSetDetectableAutoRepeat(dpy: *mut Display, detectable: bool, supported_rtm: *mut bool) -> bool;
pub fn XF86VidModeSwitchToMode(dpy: *mut Display, screen: libc::c_int,
modeline: *mut XF86VidModeModeInfo) -> Bool;
pub fn XF86VidModeSetViewPort(dpy: *mut Display, screen: libc::c_int,
x: libc::c_int, y: libc::c_int) -> Bool;
pub fn XF86VidModeGetAllModeLines(dpy: *mut Display, screen: libc::c_int,
modecount_return: *mut libc::c_int, modesinfo: *mut *mut *mut XF86VidModeModeInfo) -> Bool;
} }
/* /*

View file

@ -3,8 +3,11 @@ use libc;
use std::{mem, ptr}; use std::{mem, ptr};
use std::sync::atomics::AtomicBool; use std::sync::atomics::AtomicBool;
pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};
mod events; mod events;
mod ffi; mod ffi;
mod monitor;
pub struct Window { pub struct Window {
display: *mut ffi::Display, display: *mut ffi::Display,
@ -14,32 +17,14 @@ pub struct Window {
context: ffi::GLXContext, context: ffi::GLXContext,
is_closed: AtomicBool, is_closed: AtomicBool,
wm_delete_window: ffi::Atom, wm_delete_window: ffi::Atom,
} xf86_desk_mode: *mut ffi::XF86VidModeModeInfo,
screen_id: libc::c_int,
pub struct MonitorID(uint); is_fullscreen: bool,
pub fn get_available_monitors() -> Vec<MonitorID> {
unimplemented!()
}
pub fn get_primary_monitor() -> MonitorID {
unimplemented!()
}
impl MonitorID {
pub fn get_name(&self) -> Option<String> {
Some("<Unknown>".to_string())
}
pub fn get_dimensions(&self) -> (uint, uint) {
unimplemented!()
}
} }
impl Window { impl Window {
pub fn new(builder: WindowBuilder) -> Result<Window, String> { pub fn new(builder: WindowBuilder) -> Result<Window, String> {
// TODO: temporary let dimensions = builder.dimensions.unwrap_or((800, 600));
let dimensions = builder.dimensions;
// calling XOpenDisplay // calling XOpenDisplay
let display = unsafe { let display = unsafe {
@ -50,7 +35,9 @@ impl Window {
display display
}; };
// TODO: set error handler? let screen_id = unsafe {
ffi::XDefaultScreen(display)
};
// getting the FBConfig // getting the FBConfig
let fb_config = unsafe { let fb_config = unsafe {
@ -81,6 +68,31 @@ impl Window {
preferred_fb preferred_fb
}; };
let mut best_mode = -1;
let modes = unsafe {
let mut mode_num: libc::c_int = mem::uninitialized();
let mut modes: *mut *mut ffi::XF86VidModeModeInfo = mem::uninitialized();
if ffi::XF86VidModeGetAllModeLines(display, screen_id, &mut mode_num, &mut modes) == 0 {
return Err(format!("Could not query the video modes"));
}
for i in range(0, mode_num) {
let mode: ffi::XF86VidModeModeInfo = **modes.offset(i as int);
if mode.hdisplay == dimensions.val0() as u16 && mode.vdisplay == dimensions.val1() as u16 {
best_mode = i;
}
};
if best_mode == -1 {
return Err(format!("Could not find a suitable graphics mode"));
}
modes
};
let xf86_desk_mode = unsafe {
*modes.offset(0)
};
// getting the visual infos // getting the visual infos
let visual_infos = unsafe { let visual_infos = unsafe {
let vi = ffi::glXGetVisualFromFBConfig(display, fb_config); let vi = ffi::glXGetVisualFromFBConfig(display, fb_config);
@ -109,18 +121,28 @@ impl Window {
swa.colormap = cmap; swa.colormap = cmap;
swa.event_mask = ffi::ExposureMask | ffi::ResizeRedirectMask | swa.event_mask = ffi::ExposureMask | ffi::ResizeRedirectMask |
ffi::VisibilityChangeMask | ffi::KeyPressMask | ffi::PointerMotionMask | ffi::VisibilityChangeMask | ffi::KeyPressMask | ffi::PointerMotionMask |
ffi::KeyPressMask | ffi::KeyReleaseMask | ffi::ButtonPressMask | ffi::KeyReleaseMask | ffi::ButtonPressMask |
ffi::ButtonReleaseMask | ffi::KeymapStateMask; ffi::ButtonReleaseMask | ffi::KeymapStateMask;
swa.border_pixel = 0;
swa.override_redirect = 0;
swa swa
}; };
let mut window_attributes = ffi::CWBorderPixel | ffi::CWColormap | ffi:: CWEventMask;
if builder.monitor.is_some() {
window_attributes |= ffi::CWOverrideRedirect;
unsafe {
ffi::XF86VidModeSwitchToMode(display, screen_id, *modes.offset(best_mode as int));
ffi::XF86VidModeSetViewPort(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 dimensions = dimensions.unwrap_or((800, 600)); let win = ffi::XCreateWindow(display, root, 0, 0, dimensions.val0() as libc::c_uint,
let win = ffi::XCreateWindow(display, root, 50, 50, dimensions.val0() as libc::c_uint,
dimensions.val1() as libc::c_uint, 0, visual_infos.depth, ffi::InputOutput, dimensions.val1() as libc::c_uint, 0, visual_infos.depth, ffi::InputOutput,
visual_infos.visual, ffi::CWColormap | ffi::CWEventMask, visual_infos.visual, window_attributes,
&mut set_win_attr); &mut set_win_attr);
win win
}; };
@ -208,7 +230,7 @@ impl Window {
create_context_attribs(display, fb_config, ptr::null(), 1, create_context_attribs(display, fb_config, ptr::null(), 1,
attributes.as_ptr()) attributes.as_ptr())
} else { } else {
ffi::glXCreateNewContext(display, fb_config, ffi::GLX_RGBA_TYPE, ptr::null(), 1) ffi::glXCreateContext(display, &visual_infos, ptr::null(), 1)
}; };
if context.is_null() { if context.is_null() {
@ -227,6 +249,9 @@ impl Window {
context: context, context: context,
is_closed: AtomicBool::new(false), is_closed: AtomicBool::new(false),
wm_delete_window: wm_delete_window, wm_delete_window: wm_delete_window,
xf86_desk_mode: xf86_desk_mode,
screen_id: screen_id,
is_fullscreen: builder.monitor.is_some(),
}; };
// calling glViewport // calling glViewport
@ -457,7 +482,14 @@ impl Window {
impl Drop for Window { impl Drop for Window {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { ffi::glXMakeCurrent(self.display, 0, ptr::null()); }
unsafe { ffi::glXDestroyContext(self.display, self.context); } unsafe { ffi::glXDestroyContext(self.display, self.context); }
if self.is_fullscreen {
unsafe { ffi::XF86VidModeSwitchToMode(self.display, self.screen_id, self.xf86_desk_mode); }
unsafe { ffi::XF86VidModeSetViewPort(self.display, self.screen_id, 0, 0); }
}
unsafe { ffi::XDestroyIC(self.ic); } unsafe { ffi::XDestroyIC(self.ic); }
unsafe { ffi::XCloseIM(self.im); } unsafe { ffi::XCloseIM(self.im); }
unsafe { ffi::XDestroyWindow(self.display, self.window); } unsafe { ffi::XDestroyWindow(self.display, self.window); }

55
src/x11/monitor.rs Normal file
View file

@ -0,0 +1,55 @@
use std::{ptr};
use super::ffi;
pub struct MonitorID(uint);
pub fn get_available_monitors() -> Vec<MonitorID> {
let nb_monitors = unsafe {
let display = ffi::XOpenDisplay(ptr::null());
if display.is_null() {
fail!("get_available_monitors failed");
}
let nb_monitors = ffi::XScreenCount(display);
ffi::XCloseDisplay(display);
nb_monitors
};
let mut vec = Vec::new();
vec.grow_fn(nb_monitors as uint, |i| MonitorID(i));
vec
}
pub fn get_primary_monitor() -> MonitorID {
let primary_monitor = unsafe {
let display = ffi::XOpenDisplay(ptr::null());
if display.is_null() {
fail!("get_available_monitors failed");
}
let primary_monitor = ffi::XDefaultScreen(display);
ffi::XCloseDisplay(display);
primary_monitor
};
MonitorID(primary_monitor as uint)
}
impl MonitorID {
pub fn get_name(&self) -> Option<String> {
let MonitorID(screen_num) = *self;
Some(format!("Monitor #{}", screen_num))
}
pub fn get_dimensions(&self) -> (uint, uint) {
let dimensions = unsafe {
let display = ffi::XOpenDisplay(ptr::null());
let MonitorID(screen_num) = *self;
let screen = ffi::XScreenOfDisplay(display, screen_num as i32);
let width = ffi::XWidthOfScreen(screen);
let height = ffi::XHeightOfScreen(screen);
(width as uint, height as uint)
};
dimensions
}
}