mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-25 06:41:31 +11:00
Merge pull request #527 from tomaka/split-glx
Correct window creation on X11
This commit is contained in:
commit
d838ff7d44
|
@ -30,6 +30,7 @@ pub struct Window {
|
||||||
event_rx: Receiver<android_glue::Event>,
|
event_rx: Receiver<android_glue::Event>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct MonitorID;
|
pub struct MonitorID;
|
||||||
|
|
||||||
mod ffi;
|
mod ffi;
|
||||||
|
|
|
@ -2,6 +2,7 @@ use core_graphics::display;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use native_monitor::NativeMonitorId;
|
use native_monitor::NativeMonitorId;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct MonitorID(u32);
|
pub struct MonitorID(u32);
|
||||||
|
|
||||||
pub fn get_available_monitors() -> VecDeque<MonitorID> {
|
pub fn get_available_monitors() -> VecDeque<MonitorID> {
|
||||||
|
|
|
@ -23,6 +23,7 @@ pub struct Context {
|
||||||
display: *mut ffi::Display,
|
display: *mut ffi::Display,
|
||||||
window: ffi::Window,
|
window: ffi::Window,
|
||||||
context: ffi::GLXContext,
|
context: ffi::GLXContext,
|
||||||
|
pixel_format: PixelFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove me
|
// TODO: remove me
|
||||||
|
@ -33,119 +34,86 @@ fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const libc::c_char) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn new(glx: ffi::glx::Glx, builder: BuilderAttribs, display: *mut ffi::Display, window: ffi::Window,
|
pub fn new<'a>(glx: ffi::glx::Glx, xlib: &ffi::Xlib, builder: &'a BuilderAttribs<'a>,
|
||||||
fb_config: ffi::glx::types::GLXFBConfig, mut visual_infos: ffi::glx::types::XVisualInfo)
|
display: *mut ffi::Display)
|
||||||
-> Result<Context, CreationError>
|
-> Result<ContextPrototype<'a>, CreationError>
|
||||||
{
|
{
|
||||||
let share = if let Some(win) = builder.sharing {
|
// finding the pixel format we want
|
||||||
match win {
|
// TODO: enumerate them instead
|
||||||
&PlatformWindow::X(ref win) => match win.x.context {
|
let fb_config = unsafe {
|
||||||
::api::x11::Context::Glx(ref c) => c.context,
|
let mut visual_attributes = vec![
|
||||||
_ => panic!("Cannot share contexts between different APIs")
|
ffi::glx::X_RENDERABLE as libc::c_int, 1,
|
||||||
},
|
ffi::glx::DRAWABLE_TYPE as libc::c_int, ffi::glx::WINDOW_BIT as libc::c_int,
|
||||||
_ => panic!("Cannot use glx on a non-X11 window.")
|
ffi::glx::RENDER_TYPE as libc::c_int, ffi::glx::RGBA_BIT as libc::c_int,
|
||||||
|
ffi::glx::X_VISUAL_TYPE as libc::c_int, ffi::glx::TRUE_COLOR as libc::c_int,
|
||||||
|
ffi::glx::RED_SIZE as libc::c_int, 8,
|
||||||
|
ffi::glx::GREEN_SIZE as libc::c_int, 8,
|
||||||
|
ffi::glx::BLUE_SIZE as libc::c_int, 8,
|
||||||
|
ffi::glx::ALPHA_SIZE as libc::c_int, 8,
|
||||||
|
ffi::glx::DEPTH_SIZE as libc::c_int, 24,
|
||||||
|
ffi::glx::STENCIL_SIZE as libc::c_int, 8,
|
||||||
|
ffi::glx::DOUBLEBUFFER as libc::c_int, 1,
|
||||||
|
];
|
||||||
|
|
||||||
|
if let Some(val) = builder.multisampling {
|
||||||
|
visual_attributes.push(ffi::glx::SAMPLE_BUFFERS as libc::c_int);
|
||||||
|
visual_attributes.push(1);
|
||||||
|
visual_attributes.push(ffi::glx::SAMPLES as libc::c_int);
|
||||||
|
visual_attributes.push(val as libc::c_int);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ptr::null()
|
|
||||||
};
|
|
||||||
|
|
||||||
// loading the list of extensions
|
if let Some(val) = builder.srgb {
|
||||||
let extensions = unsafe {
|
visual_attributes.push(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as libc::c_int);
|
||||||
let extensions = glx.QueryExtensionsString(display as *mut _, 0); // FIXME: screen number
|
visual_attributes.push(if val {1} else {0});
|
||||||
let extensions = CStr::from_ptr(extensions).to_bytes().to_vec();
|
}
|
||||||
String::from_utf8(extensions).unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
// loading the extra GLX functions
|
visual_attributes.push(0);
|
||||||
let extra_functions = ffi::glx_extra::Glx::load_with(|addr| {
|
|
||||||
with_c_str(addr, |s| {
|
|
||||||
unsafe { glx.GetProcAddress(s as *const u8) as *const _ }
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
// creating GL context
|
let mut num_fb: libc::c_int = mem::uninitialized();
|
||||||
let context = match builder.gl_version {
|
|
||||||
GlRequest::Latest => {
|
|
||||||
if let Ok(ctxt) = create_context(&glx, &extra_functions, &extensions, (3, 2),
|
|
||||||
builder.gl_profile, builder.gl_debug,
|
|
||||||
builder.gl_robustness, share,
|
|
||||||
display, fb_config, &mut visual_infos)
|
|
||||||
{
|
|
||||||
ctxt
|
|
||||||
} else if let Ok(ctxt) = create_context(&glx, &extra_functions, &extensions, (3, 1),
|
|
||||||
builder.gl_profile, builder.gl_debug,
|
|
||||||
builder.gl_robustness, share, display,
|
|
||||||
fb_config, &mut visual_infos)
|
|
||||||
{
|
|
||||||
ctxt
|
|
||||||
|
|
||||||
} else {
|
let fb = glx.ChooseFBConfig(display as *mut _, (xlib.XDefaultScreen)(display),
|
||||||
try!(create_context(&glx, &extra_functions, &extensions, (1, 0),
|
visual_attributes.as_ptr(), &mut num_fb);
|
||||||
builder.gl_profile, builder.gl_debug, builder.gl_robustness,
|
if fb.is_null() {
|
||||||
share, display, fb_config, &mut visual_infos))
|
return Err(CreationError::OsError(format!("glxChooseFBConfig failed")));
|
||||||
}
|
}
|
||||||
},
|
|
||||||
GlRequest::Specific(Api::OpenGl, (major, minor)) => {
|
|
||||||
try!(create_context(&glx, &extra_functions, &extensions, (major, minor),
|
|
||||||
builder.gl_profile, builder.gl_debug, builder.gl_robustness,
|
|
||||||
share, display, fb_config, &mut visual_infos))
|
|
||||||
},
|
|
||||||
GlRequest::Specific(_, _) => panic!("Only OpenGL is supported"),
|
|
||||||
GlRequest::GlThenGles { opengl_version: (major, minor), .. } => {
|
|
||||||
try!(create_context(&glx, &extra_functions, &extensions, (major, minor),
|
|
||||||
builder.gl_profile, builder.gl_debug, builder.gl_robustness,
|
|
||||||
share, display, fb_config, &mut visual_infos))
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// vsync
|
let preferred_fb = if builder.transparent {
|
||||||
if builder.vsync {
|
let mut best_fbi_for_transparent = 0isize;
|
||||||
unsafe { glx.MakeCurrent(display as *mut _, window, context) };
|
|
||||||
|
|
||||||
if extra_functions.SwapIntervalEXT.is_loaded() {
|
for i in 0isize..num_fb as isize {
|
||||||
// this should be the most common extension
|
let vi = glx.GetVisualFromFBConfig(display as *mut _, *fb.offset(i));
|
||||||
unsafe {
|
if (*vi).depth == 32 {
|
||||||
extra_functions.SwapIntervalEXT(display as *mut _, window, 1);
|
best_fbi_for_transparent = i;
|
||||||
}
|
break;
|
||||||
|
|
||||||
// checking that it worked
|
|
||||||
if builder.strict {
|
|
||||||
let mut swap = unsafe { mem::uninitialized() };
|
|
||||||
unsafe {
|
|
||||||
glx.QueryDrawable(display as *mut _, window,
|
|
||||||
ffi::glx_extra::SWAP_INTERVAL_EXT as i32,
|
|
||||||
&mut swap);
|
|
||||||
}
|
|
||||||
|
|
||||||
if swap != 1 {
|
|
||||||
return Err(CreationError::OsError(format!("Couldn't setup vsync: expected \
|
|
||||||
interval `1` but got `{}`", swap)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GLX_MESA_swap_control is not official
|
*fb.offset(best_fbi_for_transparent)
|
||||||
/*} else if extra_functions.SwapIntervalMESA.is_loaded() {
|
} else {
|
||||||
unsafe {
|
*fb // TODO: choose more wisely
|
||||||
extra_functions.SwapIntervalMESA(1);
|
};
|
||||||
}*/
|
|
||||||
|
|
||||||
} else if extra_functions.SwapIntervalSGI.is_loaded() {
|
(xlib.XFree)(fb as *mut _);
|
||||||
unsafe {
|
preferred_fb
|
||||||
extra_functions.SwapIntervalSGI(1);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
} else if builder.strict {
|
// getting the visual infos
|
||||||
return Err(CreationError::OsError(format!("Couldn't find any available vsync extension")));
|
let visual_infos: ffi::glx::types::XVisualInfo = unsafe {
|
||||||
|
let vi = glx.GetVisualFromFBConfig(display as *mut _, fb_config);
|
||||||
|
if vi.is_null() {
|
||||||
|
return Err(CreationError::OsError(format!("glxGetVisualFromFBConfig failed")));
|
||||||
}
|
}
|
||||||
|
let vi_copy = ptr::read(vi as *const _);
|
||||||
|
(xlib.XFree)(vi as *mut _);
|
||||||
|
vi_copy
|
||||||
|
};
|
||||||
|
|
||||||
unsafe { glx.MakeCurrent(display as *mut _, 0, ptr::null()) };
|
Ok(ContextPrototype {
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Context {
|
|
||||||
glx: glx,
|
glx: glx,
|
||||||
|
builder: builder,
|
||||||
display: display,
|
display: display,
|
||||||
window: window,
|
fb_config: fb_config,
|
||||||
context: context,
|
visual_infos: unsafe { mem::transmute(visual_infos) },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,7 +151,7 @@ impl GlContext for Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pixel_format(&self) -> PixelFormat {
|
fn get_pixel_format(&self) -> PixelFormat {
|
||||||
unimplemented!();
|
self.pixel_format.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,11 +170,145 @@ impl Drop for Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ContextPrototype<'a> {
|
||||||
|
glx: ffi::glx::Glx,
|
||||||
|
builder: &'a BuilderAttribs<'a>,
|
||||||
|
display: *mut ffi::Display,
|
||||||
|
fb_config: ffi::glx::types::GLXFBConfig,
|
||||||
|
visual_infos: ffi::XVisualInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ContextPrototype<'a> {
|
||||||
|
pub fn get_visual_infos(&self) -> &ffi::XVisualInfo {
|
||||||
|
&self.visual_infos
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self, window: ffi::Window) -> Result<Context, CreationError> {
|
||||||
|
let share = if let Some(win) = self.builder.sharing {
|
||||||
|
match win {
|
||||||
|
&PlatformWindow::X(ref win) => match win.x.context {
|
||||||
|
::api::x11::Context::Glx(ref c) => c.context,
|
||||||
|
_ => panic!("Cannot share contexts between different APIs")
|
||||||
|
},
|
||||||
|
_ => panic!("Cannot use glx on a non-X11 window.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ptr::null()
|
||||||
|
};
|
||||||
|
|
||||||
|
// loading the list of extensions
|
||||||
|
let extensions = unsafe {
|
||||||
|
let extensions = self.glx.QueryExtensionsString(self.display as *mut _, 0); // FIXME: screen number
|
||||||
|
let extensions = CStr::from_ptr(extensions).to_bytes().to_vec();
|
||||||
|
String::from_utf8(extensions).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// loading the extra GLX functions
|
||||||
|
let extra_functions = ffi::glx_extra::Glx::load_with(|addr| {
|
||||||
|
with_c_str(addr, |s| {
|
||||||
|
unsafe { self.glx.GetProcAddress(s as *const u8) as *const _ }
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// creating GL context
|
||||||
|
let context = match self.builder.gl_version {
|
||||||
|
GlRequest::Latest => {
|
||||||
|
if let Ok(ctxt) = create_context(&self.glx, &extra_functions, &extensions, (3, 2),
|
||||||
|
self.builder.gl_profile, self.builder.gl_debug,
|
||||||
|
self.builder.gl_robustness, share,
|
||||||
|
self.display, self.fb_config, &self.visual_infos)
|
||||||
|
{
|
||||||
|
ctxt
|
||||||
|
} else if let Ok(ctxt) = create_context(&self.glx, &extra_functions, &extensions,
|
||||||
|
(3, 1), self.builder.gl_profile,
|
||||||
|
self.builder.gl_debug,
|
||||||
|
self.builder.gl_robustness, share, self.display,
|
||||||
|
self.fb_config, &self.visual_infos)
|
||||||
|
{
|
||||||
|
ctxt
|
||||||
|
|
||||||
|
} else {
|
||||||
|
try!(create_context(&self.glx, &extra_functions, &extensions, (1, 0),
|
||||||
|
self.builder.gl_profile, self.builder.gl_debug,
|
||||||
|
self.builder.gl_robustness,
|
||||||
|
share, self.display, self.fb_config, &self.visual_infos))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GlRequest::Specific(Api::OpenGl, (major, minor)) => {
|
||||||
|
try!(create_context(&self.glx, &extra_functions, &extensions, (major, minor),
|
||||||
|
self.builder.gl_profile, self.builder.gl_debug,
|
||||||
|
self.builder.gl_robustness, share, self.display, self.fb_config,
|
||||||
|
&self.visual_infos))
|
||||||
|
},
|
||||||
|
GlRequest::Specific(_, _) => panic!("Only OpenGL is supported"),
|
||||||
|
GlRequest::GlThenGles { opengl_version: (major, minor), .. } => {
|
||||||
|
try!(create_context(&self.glx, &extra_functions, &extensions, (major, minor),
|
||||||
|
self.builder.gl_profile, self.builder.gl_debug,
|
||||||
|
self.builder.gl_robustness, share, self.display, self.fb_config,
|
||||||
|
&self.visual_infos))
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// vsync
|
||||||
|
if self.builder.vsync {
|
||||||
|
unsafe { self.glx.MakeCurrent(self.display as *mut _, window, context) };
|
||||||
|
|
||||||
|
if extra_functions.SwapIntervalEXT.is_loaded() {
|
||||||
|
// this should be the most common extension
|
||||||
|
unsafe {
|
||||||
|
extra_functions.SwapIntervalEXT(self.display as *mut _, window, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// checking that it worked
|
||||||
|
if self.builder.strict {
|
||||||
|
let mut swap = unsafe { mem::uninitialized() };
|
||||||
|
unsafe {
|
||||||
|
self.glx.QueryDrawable(self.display as *mut _, window,
|
||||||
|
ffi::glx_extra::SWAP_INTERVAL_EXT as i32,
|
||||||
|
&mut swap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if swap != 1 {
|
||||||
|
return Err(CreationError::OsError(format!("Couldn't setup vsync: expected \
|
||||||
|
interval `1` but got `{}`", swap)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GLX_MESA_swap_control is not official
|
||||||
|
/*} else if extra_functions.SwapIntervalMESA.is_loaded() {
|
||||||
|
unsafe {
|
||||||
|
extra_functions.SwapIntervalMESA(1);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
} else if extra_functions.SwapIntervalSGI.is_loaded() {
|
||||||
|
unsafe {
|
||||||
|
extra_functions.SwapIntervalSGI(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if self.builder.strict {
|
||||||
|
return Err(CreationError::OsError(format!("Couldn't find any available vsync extension")));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { self.glx.MakeCurrent(self.display as *mut _, 0, ptr::null()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
let pixel_format = unsafe { get_pixel_format(&self.glx, self.display, self.fb_config) };
|
||||||
|
|
||||||
|
Ok(Context {
|
||||||
|
glx: self.glx,
|
||||||
|
display: self.display,
|
||||||
|
window: window,
|
||||||
|
context: context,
|
||||||
|
pixel_format: pixel_format,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, extensions: &str,
|
fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, extensions: &str,
|
||||||
version: (u8, u8), profile: Option<GlProfile>, debug: bool,
|
version: (u8, u8), profile: Option<GlProfile>, debug: bool,
|
||||||
robustness: Robustness, share: ffi::GLXContext, display: *mut ffi::Display,
|
robustness: Robustness, share: ffi::GLXContext, display: *mut ffi::Display,
|
||||||
fb_config: ffi::glx::types::GLXFBConfig,
|
fb_config: ffi::glx::types::GLXFBConfig,
|
||||||
visual_infos: &mut ffi::glx::types::XVisualInfo)
|
visual_infos: &ffi::XVisualInfo)
|
||||||
-> Result<ffi::GLXContext, CreationError>
|
-> Result<ffi::GLXContext, CreationError>
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -274,7 +376,8 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex
|
||||||
attributes.as_ptr())
|
attributes.as_ptr())
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
glx.CreateContext(display as *mut _, visual_infos, share, 1)
|
let visual_infos: *const ffi::XVisualInfo = visual_infos;
|
||||||
|
glx.CreateContext(display as *mut _, visual_infos as *mut _, share, 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
if context.is_null() {
|
if context.is_null() {
|
||||||
|
@ -284,3 +387,33 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex
|
||||||
Ok(context)
|
Ok(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn get_pixel_format(glx: &ffi::glx::Glx, display: *mut ffi::Display,
|
||||||
|
fb_config: ffi::glx::types::GLXFBConfig) -> PixelFormat
|
||||||
|
{
|
||||||
|
let get_attrib = |attrib: libc::c_int| -> i32 {
|
||||||
|
let mut value = 0;
|
||||||
|
glx.GetFBConfigAttrib(display as *mut _, fb_config, attrib, &mut value);
|
||||||
|
// TODO: check return value
|
||||||
|
value
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: make sure everything is supported
|
||||||
|
PixelFormat {
|
||||||
|
hardware_accelerated: true,
|
||||||
|
color_bits: get_attrib(ffi::glx::RED_SIZE as libc::c_int) as u8 +
|
||||||
|
get_attrib(ffi::glx::GREEN_SIZE as libc::c_int) as u8 +
|
||||||
|
get_attrib(ffi::glx::BLUE_SIZE as libc::c_int) as u8,
|
||||||
|
alpha_bits: get_attrib(ffi::glx::ALPHA_SIZE as libc::c_int) as u8,
|
||||||
|
depth_bits: get_attrib(ffi::glx::DEPTH_SIZE as libc::c_int) as u8,
|
||||||
|
stencil_bits: get_attrib(ffi::glx::STENCIL_SIZE as libc::c_int) as u8,
|
||||||
|
stereoscopy: get_attrib(ffi::glx::STEREO as libc::c_int) != 0,
|
||||||
|
double_buffer: get_attrib(ffi::glx::DOUBLEBUFFER as libc::c_int) != 0,
|
||||||
|
multisampling: if get_attrib(ffi::glx::SAMPLE_BUFFERS as libc::c_int) != 0 {
|
||||||
|
Some(get_attrib(ffi::glx::SAMPLES as libc::c_int) as u16)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
srgb: get_attrib(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as libc::c_int) != 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::mem;
|
||||||
use native_monitor::NativeMonitorId;
|
use native_monitor::NativeMonitorId;
|
||||||
|
|
||||||
/// Win32 implementation of the main `MonitorID` object.
|
/// Win32 implementation of the main `MonitorID` object.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct MonitorID {
|
pub struct MonitorID {
|
||||||
/// The system name of the adapter.
|
/// The system name of the adapter.
|
||||||
adapter_name: [winapi::WCHAR; 32],
|
adapter_name: [winapi::WCHAR; 32],
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::sync::Arc;
|
||||||
use super::XConnection;
|
use super::XConnection;
|
||||||
use native_monitor::NativeMonitorId;
|
use native_monitor::NativeMonitorId;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct MonitorID(pub Arc<XConnection>, pub u32);
|
pub struct MonitorID(pub Arc<XConnection>, pub u32);
|
||||||
|
|
||||||
pub fn get_available_monitors(x: &Arc<XConnection>) -> VecDeque<MonitorID> {
|
pub fn get_available_monitors(x: &Arc<XConnection>) -> VecDeque<MonitorID> {
|
||||||
|
|
|
@ -271,7 +271,6 @@ pub struct Window {
|
||||||
is_closed: AtomicBool,
|
is_closed: AtomicBool,
|
||||||
wm_delete_window: ffi::Atom,
|
wm_delete_window: ffi::Atom,
|
||||||
current_size: Cell<(libc::c_int, libc::c_int)>,
|
current_size: Cell<(libc::c_int, libc::c_int)>,
|
||||||
pixel_format: PixelFormat,
|
|
||||||
/// Events that have been retreived with XLib but not dispatched with iterators yet
|
/// Events that have been retreived with XLib but not dispatched with iterators yet
|
||||||
pending_events: Mutex<VecDeque<Event>>,
|
pending_events: Mutex<VecDeque<Event>>,
|
||||||
cursor_state: Mutex<CursorState>,
|
cursor_state: Mutex<CursorState>,
|
||||||
|
@ -287,64 +286,6 @@ impl Window {
|
||||||
_ => unsafe { (display.xlib.XDefaultScreen)(display.display) },
|
_ => unsafe { (display.xlib.XDefaultScreen)(display.display) },
|
||||||
};
|
};
|
||||||
|
|
||||||
// getting the FBConfig
|
|
||||||
let fb_config = unsafe {
|
|
||||||
let mut visual_attributes = vec![
|
|
||||||
ffi::glx::X_RENDERABLE as libc::c_int, 1,
|
|
||||||
ffi::glx::DRAWABLE_TYPE as libc::c_int, ffi::glx::WINDOW_BIT as libc::c_int,
|
|
||||||
ffi::glx::RENDER_TYPE as libc::c_int, ffi::glx::RGBA_BIT as libc::c_int,
|
|
||||||
ffi::glx::X_VISUAL_TYPE as libc::c_int, ffi::glx::TRUE_COLOR as libc::c_int,
|
|
||||||
ffi::glx::RED_SIZE as libc::c_int, 8,
|
|
||||||
ffi::glx::GREEN_SIZE as libc::c_int, 8,
|
|
||||||
ffi::glx::BLUE_SIZE as libc::c_int, 8,
|
|
||||||
ffi::glx::ALPHA_SIZE as libc::c_int, 8,
|
|
||||||
ffi::glx::DEPTH_SIZE as libc::c_int, 24,
|
|
||||||
ffi::glx::STENCIL_SIZE as libc::c_int, 8,
|
|
||||||
ffi::glx::DOUBLEBUFFER as libc::c_int, 1,
|
|
||||||
];
|
|
||||||
|
|
||||||
if let Some(val) = builder.multisampling {
|
|
||||||
visual_attributes.push(ffi::glx::SAMPLE_BUFFERS as libc::c_int);
|
|
||||||
visual_attributes.push(1);
|
|
||||||
visual_attributes.push(ffi::glx::SAMPLES as libc::c_int);
|
|
||||||
visual_attributes.push(val as libc::c_int);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(val) = builder.srgb {
|
|
||||||
visual_attributes.push(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as libc::c_int);
|
|
||||||
visual_attributes.push(if val {1} else {0});
|
|
||||||
}
|
|
||||||
|
|
||||||
visual_attributes.push(0);
|
|
||||||
|
|
||||||
let mut num_fb: libc::c_int = mem::uninitialized();
|
|
||||||
|
|
||||||
let fb = display.glx.as_ref().unwrap().ChooseFBConfig(display.display as *mut _, (display.xlib.XDefaultScreen)(display.display),
|
|
||||||
visual_attributes.as_ptr(), &mut num_fb);
|
|
||||||
if fb.is_null() {
|
|
||||||
return Err(OsError(format!("glx::ChooseFBConfig failed")));
|
|
||||||
}
|
|
||||||
|
|
||||||
let preferred_fb = if builder.transparent {
|
|
||||||
let mut best_fbi_for_transparent = 0isize;
|
|
||||||
|
|
||||||
for i in 0isize..num_fb as isize {
|
|
||||||
let vi = display.glx.as_ref().unwrap().GetVisualFromFBConfig(display.display as *mut _, *fb.offset(i));
|
|
||||||
if (*vi).depth == 32 {
|
|
||||||
best_fbi_for_transparent = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*fb.offset(best_fbi_for_transparent)
|
|
||||||
} else {
|
|
||||||
*fb // TODO: choose more wisely
|
|
||||||
};
|
|
||||||
|
|
||||||
(display.xlib.XFree)(fb as *mut _);
|
|
||||||
preferred_fb
|
|
||||||
};
|
|
||||||
|
|
||||||
// finding the mode to switch to if necessary
|
// finding the mode to switch to if necessary
|
||||||
let (mode_to_switch_to, xf86_desk_mode) = unsafe {
|
let (mode_to_switch_to, xf86_desk_mode) = unsafe {
|
||||||
let mut mode_num: libc::c_int = mem::uninitialized();
|
let mut mode_num: libc::c_int = mem::uninitialized();
|
||||||
|
@ -385,40 +326,53 @@ impl Window {
|
||||||
(mode_to_switch_to, xf86_desk_mode)
|
(mode_to_switch_to, xf86_desk_mode)
|
||||||
};
|
};
|
||||||
|
|
||||||
// getting the visual infos
|
// start the context building process
|
||||||
let visual_infos: ffi::glx::types::XVisualInfo = unsafe {
|
enum Prototype<'a> {
|
||||||
let vi = display.glx.as_ref().unwrap().GetVisualFromFBConfig(display.display as *mut _, fb_config);
|
Glx(::api::glx::ContextPrototype<'a>),
|
||||||
if vi.is_null() {
|
Egl(::api::egl::ContextPrototype<'a>),
|
||||||
return Err(OsError(format!("glx::ChooseVisual failed")));
|
}
|
||||||
}
|
let builder_clone = builder.clone();
|
||||||
let vi_copy = ptr::read(vi as *const _);
|
let context = match builder.gl_version {
|
||||||
(display.xlib.XFree)(vi as *mut _);
|
GlRequest::Latest | GlRequest::Specific(Api::OpenGl, _) | GlRequest::GlThenGles { .. } => {
|
||||||
vi_copy
|
if let Some(ref glx) = display.glx {
|
||||||
|
Prototype::Glx(try!(GlxContext::new(glx.clone(), &display.xlib, &builder_clone, display.display)))
|
||||||
|
} else if let Some(ref egl) = display.egl {
|
||||||
|
Prototype::Egl(try!(EglContext::new(egl.clone(), &builder_clone, Some(display.display as *const _))))
|
||||||
|
} else {
|
||||||
|
return Err(CreationError::NotSupported);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GlRequest::Specific(Api::OpenGlEs, _) => {
|
||||||
|
if let Some(ref egl) = display.egl {
|
||||||
|
Prototype::Egl(try!(EglContext::new(egl.clone(), &builder_clone, Some(display.display as *const _))))
|
||||||
|
} else {
|
||||||
|
return Err(CreationError::NotSupported);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GlRequest::Specific(_, _) => {
|
||||||
|
return Err(CreationError::NotSupported);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// querying the chosen pixel format
|
// getting the `visual_infos` (a struct that contains information about the visual to use)
|
||||||
let pixel_format = {
|
let visual_infos = match context {
|
||||||
let get_attrib = |attrib: libc::c_int| -> i32 {
|
Prototype::Glx(ref p) => p.get_visual_infos().clone(),
|
||||||
let mut value = 0;
|
Prototype::Egl(ref p) => {
|
||||||
unsafe { display.glx.as_ref().unwrap().GetFBConfigAttrib(display.display as *mut _, fb_config, attrib, &mut value); }
|
unsafe {
|
||||||
value
|
let mut template: ffi::XVisualInfo = mem::zeroed();
|
||||||
};
|
template.visualid = p.get_native_visual_id() as ffi::VisualID;
|
||||||
|
|
||||||
PixelFormat {
|
let mut num_visuals = 0;
|
||||||
hardware_accelerated: true,
|
let vi = (display.xlib.XGetVisualInfo)(display.display, ffi::VisualIDMask,
|
||||||
color_bits: get_attrib(ffi::glx::RED_SIZE as libc::c_int) as u8 +
|
&mut template, &mut num_visuals);
|
||||||
get_attrib(ffi::glx::GREEN_SIZE as libc::c_int) as u8 +
|
assert!(!vi.is_null());
|
||||||
get_attrib(ffi::glx::BLUE_SIZE as libc::c_int) as u8,
|
assert!(num_visuals == 1);
|
||||||
alpha_bits: get_attrib(ffi::glx::ALPHA_SIZE as libc::c_int) as u8,
|
|
||||||
depth_bits: get_attrib(ffi::glx::DEPTH_SIZE as libc::c_int) as u8,
|
let vi_copy = ptr::read(vi as *const _);
|
||||||
stencil_bits: get_attrib(ffi::glx::STENCIL_SIZE as libc::c_int) as u8,
|
(display.xlib.XFree)(vi as *mut _);
|
||||||
stereoscopy: get_attrib(ffi::glx::STEREO as libc::c_int) != 0,
|
vi_copy
|
||||||
double_buffer: get_attrib(ffi::glx::DOUBLEBUFFER as libc::c_int) != 0,
|
}
|
||||||
multisampling: if get_attrib(ffi::glx::SAMPLE_BUFFERS as libc::c_int) != 0 {
|
},
|
||||||
Some(get_attrib(ffi::glx::SAMPLES as libc::c_int) as u16)
|
|
||||||
}else { None },
|
|
||||||
srgb: get_attrib(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as libc::c_int) != 0,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// getting the root window
|
// getting the root window
|
||||||
|
@ -427,7 +381,8 @@ impl Window {
|
||||||
// creating the color map
|
// creating the color map
|
||||||
let cmap = unsafe {
|
let cmap = unsafe {
|
||||||
let cmap = (display.xlib.XCreateColormap)(display.display, root,
|
let cmap = (display.xlib.XCreateColormap)(display.display, root,
|
||||||
visual_infos.visual as *mut _, ffi::AllocNone);
|
visual_infos.visual as *mut _,
|
||||||
|
ffi::AllocNone);
|
||||||
// TODO: error checking?
|
// TODO: error checking?
|
||||||
cmap
|
cmap
|
||||||
};
|
};
|
||||||
|
@ -545,27 +500,14 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_fullscreen = builder.monitor.is_some();
|
let is_fullscreen = builder.monitor.is_some();
|
||||||
// creating the context
|
|
||||||
let context = match builder.gl_version {
|
// finish creating the OpenGL context
|
||||||
GlRequest::Latest | GlRequest::Specific(Api::OpenGl, _) | GlRequest::GlThenGles { .. } => {
|
let context = match context {
|
||||||
if let Some(ref glx) = display.glx {
|
Prototype::Glx(ctxt) => {
|
||||||
Context::Glx(try!(GlxContext::new(glx.clone(), builder, display.display, window,
|
Context::Glx(try!(ctxt.finish(window)))
|
||||||
fb_config, visual_infos)))
|
|
||||||
} else if let Some(ref egl) = display.egl {
|
|
||||||
Context::Egl(try!(EglContext::new(egl.clone(), &builder, Some(display.display as *const _)).and_then(|p| p.finish(window as *const _))))
|
|
||||||
} else {
|
|
||||||
return Err(CreationError::NotSupported);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
GlRequest::Specific(Api::OpenGlEs, _) => {
|
Prototype::Egl(ctxt) => {
|
||||||
if let Some(ref egl) = display.egl {
|
Context::Egl(try!(ctxt.finish(window as *const libc::c_void)))
|
||||||
Context::Egl(try!(EglContext::new(egl.clone(), &builder, Some(display.display as *const _)).and_then(|p| p.finish(window as *const _))))
|
|
||||||
} else {
|
|
||||||
return Err(CreationError::NotSupported);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
GlRequest::Specific(_, _) => {
|
|
||||||
return Err(CreationError::NotSupported);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -585,7 +527,6 @@ impl Window {
|
||||||
is_closed: AtomicBool::new(false),
|
is_closed: AtomicBool::new(false),
|
||||||
wm_delete_window: wm_delete_window,
|
wm_delete_window: wm_delete_window,
|
||||||
current_size: Cell::new((0, 0)),
|
current_size: Cell::new((0, 0)),
|
||||||
pixel_format: pixel_format,
|
|
||||||
pending_events: Mutex::new(VecDeque::new()),
|
pending_events: Mutex::new(VecDeque::new()),
|
||||||
cursor_state: Mutex::new(CursorState::Normal),
|
cursor_state: Mutex::new(CursorState::Normal),
|
||||||
input_handler: Mutex::new(XInputEventHandler::new(display, window, ic))
|
input_handler: Mutex::new(XInputEventHandler::new(display, window, ic))
|
||||||
|
@ -835,6 +776,10 @@ impl GlContext for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pixel_format(&self) -> PixelFormat {
|
fn get_pixel_format(&self) -> PixelFormat {
|
||||||
self.pixel_format.clone()
|
match self.x.context {
|
||||||
|
Context::Glx(ref ctxt) => ctxt.get_pixel_format(),
|
||||||
|
Context::Egl(ref ctxt) => ctxt.get_pixel_format(),
|
||||||
|
Context::None => panic!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,6 +323,7 @@ pub struct PixelFormat {
|
||||||
|
|
||||||
/// Attributes
|
/// Attributes
|
||||||
// FIXME: remove `pub` (https://github.com/rust-lang/rust/issues/23585)
|
// FIXME: remove `pub` (https://github.com/rust-lang/rust/issues/23585)
|
||||||
|
#[derive(Clone)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct BuilderAttribs<'a> {
|
pub struct BuilderAttribs<'a> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -471,7 +472,7 @@ impl<'a> BuilderAttribs<'a> {
|
||||||
mod native_monitor {
|
mod native_monitor {
|
||||||
/// Native platform identifier for a monitor. Different platforms use fundamentally different types
|
/// Native platform identifier for a monitor. Different platforms use fundamentally different types
|
||||||
/// to represent a monitor ID.
|
/// to represent a monitor ID.
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub enum NativeMonitorId {
|
pub enum NativeMonitorId {
|
||||||
/// Cocoa and X11 use a numeric identifier to represent a monitor.
|
/// Cocoa and X11 use a numeric identifier to represent a monitor.
|
||||||
Numeric(u32),
|
Numeric(u32),
|
||||||
|
|
|
@ -60,6 +60,7 @@ impl WindowProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum MonitorID {
|
pub enum MonitorID {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
X(x11::MonitorID),
|
X(x11::MonitorID),
|
||||||
|
|
Loading…
Reference in a new issue