From baf9b92d3f8a62c6a10d2ea1506e262597e70ac9 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sun, 19 Jul 2015 13:53:40 +0200 Subject: [PATCH] Correct window creation on X11 --- src/api/android/mod.rs | 1 + src/api/cocoa/monitor.rs | 1 + src/api/glx/mod.rs | 331 ++++++++++++++++++++--------- src/api/win32/monitor.rs | 1 + src/api/x11/monitor.rs | 1 + src/api/x11/window.rs | 171 +++++---------- src/lib.rs | 3 +- src/platform/linux/api_dispatch.rs | 1 + 8 files changed, 297 insertions(+), 213 deletions(-) diff --git a/src/api/android/mod.rs b/src/api/android/mod.rs index b5fac08f..83ef12bb 100644 --- a/src/api/android/mod.rs +++ b/src/api/android/mod.rs @@ -30,6 +30,7 @@ pub struct Window { event_rx: Receiver, } +#[derive(Clone)] pub struct MonitorID; mod ffi; diff --git a/src/api/cocoa/monitor.rs b/src/api/cocoa/monitor.rs index 40c78960..138bbcd7 100644 --- a/src/api/cocoa/monitor.rs +++ b/src/api/cocoa/monitor.rs @@ -2,6 +2,7 @@ use core_graphics::display; use std::collections::VecDeque; use native_monitor::NativeMonitorId; +#[derive(Clone)] pub struct MonitorID(u32); pub fn get_available_monitors() -> VecDeque { diff --git a/src/api/glx/mod.rs b/src/api/glx/mod.rs index d286813b..37795971 100644 --- a/src/api/glx/mod.rs +++ b/src/api/glx/mod.rs @@ -23,6 +23,7 @@ pub struct Context { display: *mut ffi::Display, window: ffi::Window, context: ffi::GLXContext, + pixel_format: PixelFormat, } // TODO: remove me @@ -33,119 +34,86 @@ fn with_c_str(s: &str, f: F) -> T where F: FnOnce(*const libc::c_char) -> } impl Context { - pub fn new(glx: ffi::glx::Glx, builder: BuilderAttribs, display: *mut ffi::Display, window: ffi::Window, - fb_config: ffi::glx::types::GLXFBConfig, mut visual_infos: ffi::glx::types::XVisualInfo) - -> Result + pub fn new<'a>(glx: ffi::glx::Glx, xlib: &ffi::Xlib, builder: &'a BuilderAttribs<'a>, + display: *mut ffi::Display) + -> Result, CreationError> { - let share = if let Some(win) = 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.") + // finding the pixel format we want + // TODO: enumerate them instead + 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); } - } else { - ptr::null() - }; - // loading the list of extensions - let extensions = unsafe { - let extensions = glx.QueryExtensionsString(display as *mut _, 0); // FIXME: screen number - let extensions = CStr::from_ptr(extensions).to_bytes().to_vec(); - String::from_utf8(extensions).unwrap() - }; + 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}); + } - // loading the extra GLX functions - let extra_functions = ffi::glx_extra::Glx::load_with(|addr| { - with_c_str(addr, |s| { - unsafe { glx.GetProcAddress(s as *const u8) as *const _ } - }) - }); + visual_attributes.push(0); - // creating GL context - 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 + let mut num_fb: libc::c_int = mem::uninitialized(); - } else { - try!(create_context(&glx, &extra_functions, &extensions, (1, 0), - builder.gl_profile, builder.gl_debug, builder.gl_robustness, - share, display, fb_config, &mut visual_infos)) - } - }, - 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)) - }, - }; + let fb = glx.ChooseFBConfig(display as *mut _, (xlib.XDefaultScreen)(display), + visual_attributes.as_ptr(), &mut num_fb); + if fb.is_null() { + return Err(CreationError::OsError(format!("glxChooseFBConfig failed"))); + } - // vsync - if builder.vsync { - unsafe { glx.MakeCurrent(display as *mut _, window, context) }; + let preferred_fb = if builder.transparent { + let mut best_fbi_for_transparent = 0isize; - if extra_functions.SwapIntervalEXT.is_loaded() { - // this should be the most common extension - unsafe { - extra_functions.SwapIntervalEXT(display as *mut _, window, 1); - } - - // 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))); + for i in 0isize..num_fb as isize { + let vi = glx.GetVisualFromFBConfig(display as *mut _, *fb.offset(i)); + if (*vi).depth == 32 { + best_fbi_for_transparent = i; + break; } } - // GLX_MESA_swap_control is not official - /*} else if extra_functions.SwapIntervalMESA.is_loaded() { - unsafe { - extra_functions.SwapIntervalMESA(1); - }*/ + *fb.offset(best_fbi_for_transparent) + } else { + *fb // TODO: choose more wisely + }; - } else if extra_functions.SwapIntervalSGI.is_loaded() { - unsafe { - extra_functions.SwapIntervalSGI(1); - } + (xlib.XFree)(fb as *mut _); + preferred_fb + }; - } else if builder.strict { - return Err(CreationError::OsError(format!("Couldn't find any available vsync extension"))); + // getting the visual infos + 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(Context { + Ok(ContextPrototype { glx: glx, + builder: builder, display: display, - window: window, - context: context, + fb_config: fb_config, + visual_infos: unsafe { mem::transmute(visual_infos) }, }) } } @@ -183,7 +151,7 @@ impl GlContext for Context { } 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 { + 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, version: (u8, u8), profile: Option, debug: bool, robustness: Robustness, share: ffi::GLXContext, display: *mut ffi::Display, fb_config: ffi::glx::types::GLXFBConfig, - visual_infos: &mut ffi::glx::types::XVisualInfo) + visual_infos: &ffi::XVisualInfo) -> Result { unsafe { @@ -274,7 +376,8 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex attributes.as_ptr()) } 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() { @@ -284,3 +387,33 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex 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, + } +} diff --git a/src/api/win32/monitor.rs b/src/api/win32/monitor.rs index 4b592cb2..d87c9289 100644 --- a/src/api/win32/monitor.rs +++ b/src/api/win32/monitor.rs @@ -7,6 +7,7 @@ use std::mem; use native_monitor::NativeMonitorId; /// Win32 implementation of the main `MonitorID` object. +#[derive(Clone)] pub struct MonitorID { /// The system name of the adapter. adapter_name: [winapi::WCHAR; 32], diff --git a/src/api/x11/monitor.rs b/src/api/x11/monitor.rs index d5569304..90b12c25 100644 --- a/src/api/x11/monitor.rs +++ b/src/api/x11/monitor.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use super::XConnection; use native_monitor::NativeMonitorId; +#[derive(Clone)] pub struct MonitorID(pub Arc, pub u32); pub fn get_available_monitors(x: &Arc) -> VecDeque { diff --git a/src/api/x11/window.rs b/src/api/x11/window.rs index 79118ff1..6a4f39ae 100644 --- a/src/api/x11/window.rs +++ b/src/api/x11/window.rs @@ -271,7 +271,6 @@ pub struct Window { is_closed: AtomicBool, wm_delete_window: ffi::Atom, 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 pending_events: Mutex>, cursor_state: Mutex, @@ -287,64 +286,6 @@ impl Window { _ => 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 let (mode_to_switch_to, xf86_desk_mode) = unsafe { let mut mode_num: libc::c_int = mem::uninitialized(); @@ -385,40 +326,53 @@ impl Window { (mode_to_switch_to, xf86_desk_mode) }; - // getting the visual infos - let visual_infos: ffi::glx::types::XVisualInfo = unsafe { - let vi = display.glx.as_ref().unwrap().GetVisualFromFBConfig(display.display as *mut _, fb_config); - if vi.is_null() { - return Err(OsError(format!("glx::ChooseVisual failed"))); - } - let vi_copy = ptr::read(vi as *const _); - (display.xlib.XFree)(vi as *mut _); - vi_copy + // start the context building process + enum Prototype<'a> { + Glx(::api::glx::ContextPrototype<'a>), + Egl(::api::egl::ContextPrototype<'a>), + } + let builder_clone = builder.clone(); + let context = match builder.gl_version { + GlRequest::Latest | GlRequest::Specific(Api::OpenGl, _) | GlRequest::GlThenGles { .. } => { + 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 - let pixel_format = { - let get_attrib = |attrib: libc::c_int| -> i32 { - let mut value = 0; - unsafe { display.glx.as_ref().unwrap().GetFBConfigAttrib(display.display as *mut _, fb_config, attrib, &mut value); } - value - }; + // getting the `visual_infos` (a struct that contains information about the visual to use) + let visual_infos = match context { + Prototype::Glx(ref p) => p.get_visual_infos().clone(), + Prototype::Egl(ref p) => { + unsafe { + let mut template: ffi::XVisualInfo = mem::zeroed(); + template.visualid = p.get_native_visual_id() as ffi::VisualID; - 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, - } + let mut num_visuals = 0; + let vi = (display.xlib.XGetVisualInfo)(display.display, ffi::VisualIDMask, + &mut template, &mut num_visuals); + assert!(!vi.is_null()); + assert!(num_visuals == 1); + + let vi_copy = ptr::read(vi as *const _); + (display.xlib.XFree)(vi as *mut _); + vi_copy + } + }, }; // getting the root window @@ -427,7 +381,8 @@ impl Window { // creating the color map let cmap = unsafe { 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? cmap }; @@ -545,27 +500,14 @@ impl Window { } let is_fullscreen = builder.monitor.is_some(); - // creating the context - let context = match builder.gl_version { - GlRequest::Latest | GlRequest::Specific(Api::OpenGl, _) | GlRequest::GlThenGles { .. } => { - if let Some(ref glx) = display.glx { - Context::Glx(try!(GlxContext::new(glx.clone(), builder, display.display, 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); - } + + // finish creating the OpenGL context + let context = match context { + Prototype::Glx(ctxt) => { + Context::Glx(try!(ctxt.finish(window))) }, - GlRequest::Specific(Api::OpenGlEs, _) => { - 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(_, _) => { - return Err(CreationError::NotSupported); + Prototype::Egl(ctxt) => { + Context::Egl(try!(ctxt.finish(window as *const libc::c_void))) }, }; @@ -585,7 +527,6 @@ impl Window { is_closed: AtomicBool::new(false), wm_delete_window: wm_delete_window, current_size: Cell::new((0, 0)), - pixel_format: pixel_format, pending_events: Mutex::new(VecDeque::new()), cursor_state: Mutex::new(CursorState::Normal), input_handler: Mutex::new(XInputEventHandler::new(display, window, ic)) @@ -835,6 +776,10 @@ impl GlContext for Window { } 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!() + } } } diff --git a/src/lib.rs b/src/lib.rs index f128f401..d43dcfb8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -323,6 +323,7 @@ pub struct PixelFormat { /// Attributes // FIXME: remove `pub` (https://github.com/rust-lang/rust/issues/23585) +#[derive(Clone)] #[doc(hidden)] pub struct BuilderAttribs<'a> { #[allow(dead_code)] @@ -471,7 +472,7 @@ impl<'a> BuilderAttribs<'a> { mod native_monitor { /// Native platform identifier for a monitor. Different platforms use fundamentally different types /// to represent a monitor ID. - #[derive(PartialEq, Eq)] + #[derive(Clone, PartialEq, Eq)] pub enum NativeMonitorId { /// Cocoa and X11 use a numeric identifier to represent a monitor. Numeric(u32), diff --git a/src/platform/linux/api_dispatch.rs b/src/platform/linux/api_dispatch.rs index b2cd741b..e580ab10 100644 --- a/src/platform/linux/api_dispatch.rs +++ b/src/platform/linux/api_dispatch.rs @@ -60,6 +60,7 @@ impl WindowProxy { } } +#[derive(Clone)] pub enum MonitorID { #[doc(hidden)] X(x11::MonitorID),