diff options
| -rw-r--r-- | build.rs | 4 | ||||
| -rw-r--r-- | src/android/mod.rs | 3 | ||||
| -rw-r--r-- | src/lib.rs | 53 | ||||
| -rw-r--r-- | src/win32/init.rs | 734 | ||||
| -rw-r--r-- | src/win32/mod.rs | 3 | ||||
| -rw-r--r-- | src/x11/window/mod.rs | 3 | 
6 files changed, 477 insertions, 323 deletions
@@ -22,7 +22,9 @@ fn main() {                                          khronos_api::WGL_XML,                                          vec![                                              "WGL_ARB_create_context".to_string(), -                                            "WGL_EXT_swap_control".to_string() +                                            "WGL_EXT_swap_control".to_string(), +                                            "WGL_ARB_pixel_format".to_string(), +                                            "WGL_ARB_framebuffer_sRGB".to_string(),                                          ],                                          "1.0", "core", &mut file).unwrap();      } diff --git a/src/android/mod.rs b/src/android/mod.rs index 5f05300..ea93040 100644 --- a/src/android/mod.rs +++ b/src/android/mod.rs @@ -358,8 +358,9 @@ impl Drop for Window {          use std::ptr;          unsafe { +            // we don't call MakeCurrent(0, 0) because we are not sure that the context +            // is still the current one              android_glue::write_log("Destroying gl-init window"); -            ffi::egl::MakeCurrent(self.display, ptr::null(), ptr::null(), ptr::null());              ffi::egl::DestroySurface(self.display, self.surface);              ffi::egl::DestroyContext(self.display, self.context);              ffi::egl::Terminate(self.display); @@ -170,6 +170,21 @@ pub enum MouseCursor {      RowResize,  } +/// Describes a possible format. Unused. +#[allow(missing_docs)] +pub struct PixelFormat { +    pub red_bits: u8, +    pub green_bits: u8, +    pub blue_bits: u8, +    pub alpha_bits: u8, +    pub depth_bits: u8, +    pub stencil_bits: u8, +    pub stereoscopy: bool, +    pub double_buffer: bool, +    pub multisampling: Option<u16>, +    pub srgb: bool, +} +  /// Attributes  struct BuilderAttribs<'a> {      #[allow(dead_code)] @@ -239,5 +254,41 @@ impl<'a> BuilderAttribs<'a> {          (new_attribs, sharing)      } -} +    fn choose_pixel_format<T, I>(&self, iter: I) -> (T, PixelFormat) +                                 where I: Iterator<Item=(T, PixelFormat)>, T: Clone +    { +        let mut current_result = None; + +        // TODO: do this more properly +        for (id, format) in iter { +            if format.red_bits + format.green_bits + format.blue_bits < self.color_bits.unwrap_or(0) { +                continue; +            } + +            if format.alpha_bits < self.alpha_bits.unwrap_or(0) { +                continue; +            } + +            if format.depth_bits < self.depth_bits.unwrap_or(0) { +                continue; +            } + +            if format.stencil_bits < self.stencil_bits.unwrap_or(0) { +                continue; +            } + +            if !format.stereoscopy && self.stereoscopy { +                continue; +            } + +            if self.multisampling.is_some() && format.multisampling.is_none() { +                continue; +            } + +            current_result = Some((id, format)); +        } + +        current_result.expect("Could not find compliant pixel format") +    } +} diff --git a/src/win32/init.rs b/src/win32/init.rs index c3352b6..90a6035 100644 --- a/src/win32/init.rs +++ b/src/win32/init.rs @@ -1,10 +1,14 @@  use std::sync::atomic::AtomicBool;  use std::ptr; +use std::mem; +use std::os;  use super::callback;  use super::Window; +use super::MonitorID;  use BuilderAttribs;  use CreationError;  use CreationError::OsError; +use PixelFormat;  use std::ffi::CString;  use std::sync::mpsc::channel; @@ -23,9 +27,6 @@ unsafe impl Send for ContextHack {}  pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option<ContextHack>)                    -> Result<Window, CreationError>  { -    use std::mem; -    use std::os; -      // initializing variables to be sent to the task      let title = builder.title.as_slice().utf16_units()          .chain(Some(0).into_iter()).collect::<Vec<u16>>();    // title to utf16 @@ -36,266 +37,320 @@ pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option<C      //  so we create a new thread dedicated to this window.      // This is the only safe method. Using `nosend` wouldn't work for non-native runtime.      ::std::thread::Thread::spawn(move || { -        let builder_sharelists = builder_sharelists.map(|s| s.0); - -        // registering the window class -        let class_name = { -            let class_name: Vec<u16> = "Window Class".utf16_units().chain(Some(0).into_iter()) -                .collect::<Vec<u16>>(); -             -            let class = winapi::WNDCLASSEXW { -                cbSize: mem::size_of::<winapi::WNDCLASSEXW>() as winapi::UINT, -                style: winapi::CS_HREDRAW | winapi::CS_VREDRAW | winapi::CS_OWNDC, -                lpfnWndProc: callback::callback, -                cbClsExtra: 0, -                cbWndExtra: 0, -                hInstance: unsafe { kernel32::GetModuleHandleW(ptr::null()) }, -                hIcon: ptr::null_mut(), -                hCursor: ptr::null_mut(), -                hbrBackground: ptr::null_mut(), -                lpszMenuName: ptr::null(), -                lpszClassName: class_name.as_ptr(), -                hIconSm: ptr::null_mut(), -            }; - -            // We ignore errors because registering the same window class twice would trigger -            //  an error, and because errors here are detected during CreateWindowEx anyway. -            // Also since there is no weird element in the struct, there is no reason for this -            //  call to fail. -            unsafe { user32::RegisterClassExW(&class) }; - -            class_name -        }; - -        // building a RECT object with coordinates -        let mut rect = winapi::RECT { -            left: 0, right: builder.dimensions.unwrap_or((1024, 768)).0 as winapi::LONG, -            top: 0, bottom: builder.dimensions.unwrap_or((1024, 768)).1 as winapi::LONG, -        }; - -        // switching to fullscreen if necessary -        // this means adjusting the window's position so that it overlaps the right monitor, -        //  and change the monitor's resolution if necessary -        if builder.monitor.is_some() { -            let monitor = builder.monitor.as_ref().unwrap(); - -            // adjusting the rect -            { -                let pos = monitor.get_position(); -                rect.left += pos.0 as winapi::LONG; -                rect.right += pos.0 as winapi::LONG; -                rect.top += pos.1 as winapi::LONG; -                rect.bottom += pos.1 as winapi::LONG; -            } - -            // changing device settings -            let mut screen_settings: winapi::DEVMODEW = unsafe { mem::zeroed() }; -            screen_settings.dmSize = mem::size_of::<winapi::DEVMODEW>() as winapi::WORD; -            screen_settings.dmPelsWidth = (rect.right - rect.left) as winapi::DWORD; -            screen_settings.dmPelsHeight = (rect.bottom - rect.top) as winapi::DWORD; -            screen_settings.dmBitsPerPel = 32;      // TODO: ? -            screen_settings.dmFields = winapi::DM_BITSPERPEL | winapi::DM_PELSWIDTH | winapi::DM_PELSHEIGHT; - -            let result = unsafe { user32::ChangeDisplaySettingsExW(monitor.get_system_name().as_ptr(), -                &mut screen_settings, ptr::null_mut(), winapi::CDS_FULLSCREEN, ptr::null_mut()) }; -             -            if result != winapi::DISP_CHANGE_SUCCESSFUL { -                tx.send(Err(OsError(format!("ChangeDisplaySettings failed: {}", result)))); +        // sending +        match init(title, builder, builder_sharelists) { +            Ok(w) => tx.send(Ok(w)).ok(), +            Err(e) => { +                tx.send(Err(e)).ok();                  return;              } -        } - -        // computing the style and extended style of the window -        let (ex_style, style) = if builder.monitor.is_some() { -            (winapi::WS_EX_APPWINDOW, winapi::WS_POPUP | winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN) -        } else { -            (winapi::WS_EX_APPWINDOW | winapi::WS_EX_WINDOWEDGE, -                winapi::WS_OVERLAPPEDWINDOW | winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN)          }; -        // adjusting the window coordinates using the style -        unsafe { user32::AdjustWindowRectEx(&mut rect, style, 0, ex_style) }; - -        // getting the address of wglCreateContextAttribsARB and the pixel format -        //  that we will use -        let (extra_functions, pixel_format) = { -            // creating a dummy invisible window for GL initialization -            let dummy_window = unsafe { -                let handle = user32::CreateWindowExW(ex_style, class_name.as_ptr(), -                    title.as_ptr() as winapi::LPCWSTR, -                    style | winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN, -                    winapi::CW_USEDEFAULT, winapi::CW_USEDEFAULT, -                    rect.right - rect.left, rect.bottom - rect.top, -                    ptr::null_mut(), ptr::null_mut(), kernel32::GetModuleHandleW(ptr::null()), -                    ptr::null_mut()); - -                if handle.is_null() { -                    use std::os; -                    tx.send(Err(OsError(format!("CreateWindowEx function failed: {}", -                        os::error_string(os::errno() as usize))))); -                    return; -                } - -                handle -            }; - -            // getting the HDC of the dummy window -            let dummy_hdc = { -                let hdc = unsafe { user32::GetDC(dummy_window) }; -                if hdc.is_null() { -                    tx.send(Err(OsError(format!("GetDC function failed: {}", -                        os::error_string(os::errno() as usize))))); -                    unsafe { user32::DestroyWindow(dummy_window); } -                    return; -                } -                hdc -            }; - -            // getting the pixel format that we will use -            let pixel_format = { -                // initializing a PIXELFORMATDESCRIPTOR that indicates what we want -                let mut output: winapi::PIXELFORMATDESCRIPTOR = unsafe { mem::zeroed() }; -                output.nSize = mem::size_of::<winapi::PIXELFORMATDESCRIPTOR>() as winapi::WORD; -                output.nVersion = 1; -                output.dwFlags = winapi::PFD_DRAW_TO_WINDOW | winapi::PFD_DOUBLEBUFFER | -                    winapi::PFD_SUPPORT_OPENGL | winapi::PFD_GENERIC_ACCELERATED; -                output.iPixelType = winapi::PFD_TYPE_RGBA; -                output.cColorBits = 24; -                output.cAlphaBits = 8; -                output.cAccumBits = 0; -                output.cDepthBits = 24; -                output.cStencilBits = 8; -                output.cAuxBuffers = 0; -                output.iLayerType = winapi::PFD_MAIN_PLANE; - -                let pf_index = unsafe { gdi32::ChoosePixelFormat(dummy_hdc, &output) }; - -                if pf_index == 0 { -                    tx.send(Err(OsError(format!("ChoosePixelFormat function failed: {}", -                        os::error_string(os::errno() as usize))))); -                    unsafe { user32::DestroyWindow(dummy_window); } -                    return; -                } - -                if unsafe { gdi32::DescribePixelFormat(dummy_hdc, pf_index, -                    mem::size_of::<winapi::PIXELFORMATDESCRIPTOR>() as winapi::UINT, &mut output) } == 0 -                { -                    tx.send(Err(OsError(format!("DescribePixelFormat function failed: {}", -                        os::error_string(os::errno() as usize))))); -                    unsafe { user32::DestroyWindow(dummy_window); } -                    return; -                } - -                output -            }; - -            // calling SetPixelFormat -            unsafe { -                if gdi32::SetPixelFormat(dummy_hdc, 1, &pixel_format) == 0 { -                    tx.send(Err(OsError(format!("SetPixelFormat function failed: {}", -                        os::error_string(os::errno() as usize))))); -                    user32::DestroyWindow(dummy_window); -                    return; -                } -            } - -            // creating the dummy OpenGL context -            let dummy_context = { -                let ctxt = unsafe { gl::wgl::CreateContext(dummy_hdc as *const libc::c_void) }; -                if ctxt.is_null() { -                    tx.send(Err(OsError(format!("wglCreateContext function failed: {}", -                        os::error_string(os::errno() as usize))))); -                    unsafe { user32::DestroyWindow(dummy_window); } -                    return; -                } -                ctxt -            }; - -            // making context current -            unsafe { gl::wgl::MakeCurrent(dummy_hdc as *const libc::c_void, dummy_context); } - -            // loading the extra WGL functions -            let extra_functions = gl::wgl_extra::Wgl::load_with(|addr| { -                use libc; - -                let addr = CString::from_slice(addr.as_bytes()); -                let addr = addr.as_slice_with_nul().as_ptr(); - -                unsafe { -                    gl::wgl::GetProcAddress(addr) as *const libc::c_void -                } -            }); - -            // removing current context -            unsafe { gl::wgl::MakeCurrent(ptr::null(), ptr::null()); } - -            // destroying the context and the window -            unsafe { gl::wgl::DeleteContext(dummy_context); } -            unsafe { user32::DestroyWindow(dummy_window); } +        // now that the `Window` struct is initialized, the main `Window::new()` function will +        //  return and this events loop will run in parallel +        loop { +            let mut msg = unsafe { mem::uninitialized() }; -            // returning the address -            (extra_functions, pixel_format) -        }; +            if unsafe { user32::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) } == 0 { +                break; +            } -        // creating the real window this time -        let real_window = unsafe { -            let (width, height) = if builder.monitor.is_some() || builder.dimensions.is_some() { -                (Some(rect.right - rect.left), Some(rect.bottom - rect.top)) -            } else { -                (None, None) -            }; +            unsafe { user32::TranslateMessage(&msg) }; +            unsafe { user32::DispatchMessageW(&msg) };     // calls `callback` (see below) +        } +    }); -            let style = if !builder.visible || builder.headless { -                style -            } else { -                style | winapi::WS_VISIBLE -            }; +    rx.recv().unwrap() +} +fn init(title: Vec<u16>, builder: BuilderAttribs<'static>, builder_sharelists: Option<ContextHack>) +        -> Result<Window, CreationError> +{ +    let builder_sharelists = builder_sharelists.map(|s| s.0); + +    // registering the window class +    let class_name = register_window_class(); + +    // building a RECT object with coordinates +    let mut rect = winapi::RECT { +        left: 0, right: builder.dimensions.unwrap_or((1024, 768)).0 as winapi::LONG, +        top: 0, bottom: builder.dimensions.unwrap_or((1024, 768)).1 as winapi::LONG, +    }; + +    // switching to fullscreen if necessary +    // this means adjusting the window's position so that it overlaps the right monitor, +    //  and change the monitor's resolution if necessary +    if builder.monitor.is_some() { +        let monitor = builder.monitor.as_ref().unwrap(); +        switch_to_fullscreen(&mut rect, monitor); +    } + +    // computing the style and extended style of the window +    let (ex_style, style) = if builder.monitor.is_some() { +        (winapi::WS_EX_APPWINDOW, winapi::WS_POPUP | winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN) +    } else { +        (winapi::WS_EX_APPWINDOW | winapi::WS_EX_WINDOWEDGE, +            winapi::WS_OVERLAPPEDWINDOW | winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN) +    }; + +    // adjusting the window coordinates using the style +    unsafe { user32::AdjustWindowRectEx(&mut rect, style, 0, ex_style) }; + +    // getting the address of wglCreateContextAttribsARB and the pixel format +    //  that we will use +    let (extra_functions, pixel_format) = { +        // creating a dummy invisible window for GL initialization +        let dummy_window = unsafe {              let handle = user32::CreateWindowExW(ex_style, class_name.as_ptr(),                  title.as_ptr() as winapi::LPCWSTR,                  style | winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN, -                if builder.monitor.is_some() { 0 } else { winapi::CW_USEDEFAULT }, -                if builder.monitor.is_some() { 0 } else { winapi::CW_USEDEFAULT }, -                width.unwrap_or(winapi::CW_USEDEFAULT), height.unwrap_or(winapi::CW_USEDEFAULT), +                winapi::CW_USEDEFAULT, winapi::CW_USEDEFAULT, +                rect.right - rect.left, rect.bottom - rect.top,                  ptr::null_mut(), ptr::null_mut(), kernel32::GetModuleHandleW(ptr::null()),                  ptr::null_mut());              if handle.is_null() { -                use std::os; -                tx.send(Err(OsError(format!("CreateWindowEx function failed: {}", -                    os::error_string(os::errno() as usize))))); -                return; +                return Err(OsError(format!("CreateWindowEx function failed: {}", +                    os::error_string(os::errno() as usize))));              }              handle          }; -        // getting the HDC of the window -        let hdc = { -            let hdc = unsafe { user32::GetDC(real_window) }; +        // getting the HDC of the dummy window +        let dummy_hdc = { +            let hdc = unsafe { user32::GetDC(dummy_window) };              if hdc.is_null() { -                tx.send(Err(OsError(format!("GetDC function failed: {}", -                    os::error_string(os::errno() as usize))))); -                unsafe { user32::DestroyWindow(real_window); } -                return; +                let err = Err(OsError(format!("GetDC function failed: {}", +                    os::error_string(os::errno() as usize)))); +                unsafe { user32::DestroyWindow(dummy_window); } +                return err;              }              hdc          }; +        // getting the pixel format that we will use +        let pixel_format = { +            let formats = enumerate_native_pixel_formats(dummy_hdc); +            let (id, _) = builder.choose_pixel_format(formats.into_iter().map(|(a, b)| (b, a))); + +            let mut output: winapi::PIXELFORMATDESCRIPTOR = unsafe { mem::zeroed() }; +            if unsafe { gdi32::DescribePixelFormat(dummy_hdc, id, +                mem::size_of::<winapi::PIXELFORMATDESCRIPTOR>() as winapi::UINT, &mut output) } == 0 +            { +                let err = Err(OsError(format!("DescribePixelFormat function failed: {}", +                    os::error_string(os::errno() as usize)))); +                unsafe { user32::DestroyWindow(dummy_window); } +                return err; +            } + +            output +        }; +          // calling SetPixelFormat          unsafe { -            if gdi32::SetPixelFormat(hdc, 1, &pixel_format) == 0 { -                tx.send(Err(OsError(format!("SetPixelFormat function failed: {}", -                    os::error_string(os::errno() as usize))))); -                user32::DestroyWindow(real_window); -                return; +            if gdi32::SetPixelFormat(dummy_hdc, 1, &pixel_format) == 0 { +                let err = Err(OsError(format!("SetPixelFormat function failed: {}", +                    os::error_string(os::errno() as usize)))); +                user32::DestroyWindow(dummy_window); +                return err;              }          } -        // creating the OpenGL context -        let context = { +        // creating the dummy OpenGL context +        let dummy_context = try!(create_context(None, dummy_hdc, None)); + +        // making context current +        unsafe { gl::wgl::MakeCurrent(dummy_hdc as *const libc::c_void, dummy_context as *const libc::c_void); } + +        // loading the extra WGL functions +        let extra_functions = gl::wgl_extra::Wgl::load_with(|addr| {              use libc; +            let addr = CString::from_slice(addr.as_bytes()); +            let addr = addr.as_slice_with_nul().as_ptr(); + +            unsafe { +                gl::wgl::GetProcAddress(addr) as *const libc::c_void +            } +        }); + +        // removing current context +        unsafe { gl::wgl::MakeCurrent(ptr::null(), ptr::null()); } + +        // destroying the context and the window +        unsafe { gl::wgl::DeleteContext(dummy_context as *const libc::c_void); } +        unsafe { user32::DestroyWindow(dummy_window); } + +        // returning the address +        (extra_functions, pixel_format) +    }; + +    // creating the real window this time +    let real_window = unsafe { +        let (width, height) = if builder.monitor.is_some() || builder.dimensions.is_some() { +            (Some(rect.right - rect.left), Some(rect.bottom - rect.top)) +        } else { +            (None, None) +        }; + +        let style = if !builder.visible || builder.headless { +            style +        } else { +            style | winapi::WS_VISIBLE +        }; + +        let handle = user32::CreateWindowExW(ex_style, class_name.as_ptr(), +            title.as_ptr() as winapi::LPCWSTR, +            style | winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN, +            if builder.monitor.is_some() { 0 } else { winapi::CW_USEDEFAULT }, +            if builder.monitor.is_some() { 0 } else { winapi::CW_USEDEFAULT }, +            width.unwrap_or(winapi::CW_USEDEFAULT), height.unwrap_or(winapi::CW_USEDEFAULT), +            ptr::null_mut(), ptr::null_mut(), kernel32::GetModuleHandleW(ptr::null()), +            ptr::null_mut()); + +        if handle.is_null() { +            return Err(OsError(format!("CreateWindowEx function failed: {}", +                os::error_string(os::errno() as usize)))); +        } + +        handle +    }; + +    // getting the HDC of the window +    let hdc = { +        let hdc = unsafe { user32::GetDC(real_window) }; +        if hdc.is_null() { +            let err = Err(OsError(format!("GetDC function failed: {}", +                os::error_string(os::errno() as usize)))); +            unsafe { user32::DestroyWindow(real_window); } +            return err; +        } +        hdc +    }; + +    // calling SetPixelFormat +    unsafe { +        if gdi32::SetPixelFormat(hdc, 1, &pixel_format) == 0 { +            let err = Err(OsError(format!("SetPixelFormat function failed: {}", +                os::error_string(os::errno() as usize)))); +            user32::DestroyWindow(real_window); +            return err; +        } +    } + +    // creating the OpenGL context +    let context = try!(create_context(Some((&extra_functions, &builder)), hdc, builder_sharelists)); + +    // calling SetForegroundWindow if fullscreen +    if builder.monitor.is_some() { +        unsafe { user32::SetForegroundWindow(real_window) }; +    } + +    // filling the WINDOW task-local storage +    let events_receiver = { +        let (tx, rx) = channel(); +        let mut tx = Some(tx); +        callback::WINDOW.with(|window| { +            (*window.borrow_mut()) = Some((real_window, tx.take().unwrap())); +        }); +        rx +    }; + +    // loading the opengl32 module +    let gl_library = try!(load_opengl32_dll()); + +    // handling vsync +    if builder.vsync { +        if extra_functions.SwapIntervalEXT.is_loaded() { +            unsafe { gl::wgl::MakeCurrent(hdc as *const libc::c_void, context as *const libc::c_void) }; +            if unsafe { extra_functions.SwapIntervalEXT(1) } == 0 { +                unsafe { gl::wgl::DeleteContext(context as *const libc::c_void); } +                unsafe { user32::DestroyWindow(real_window); } +                return Err(OsError(format!("wglSwapIntervalEXT failed"))); +            } + +            // it is important to remove the current context, otherwise you get very weird +            // errors +            unsafe { gl::wgl::MakeCurrent(ptr::null(), ptr::null()); } +        } +    } + +    // building the struct +    Ok(Window { +        window: real_window, +        hdc: hdc as winapi::HDC, +        context: context, +        gl_library: gl_library, +        events_receiver: events_receiver, +        is_closed: AtomicBool::new(false), +    }) +} + +fn register_window_class() -> Vec<u16> { +    let class_name: Vec<u16> = "Window Class".utf16_units().chain(Some(0).into_iter()) +                                             .collect::<Vec<u16>>(); +     +    let class = winapi::WNDCLASSEXW { +        cbSize: mem::size_of::<winapi::WNDCLASSEXW>() as winapi::UINT, +        style: winapi::CS_HREDRAW | winapi::CS_VREDRAW | winapi::CS_OWNDC, +        lpfnWndProc: callback::callback, +        cbClsExtra: 0, +        cbWndExtra: 0, +        hInstance: unsafe { kernel32::GetModuleHandleW(ptr::null()) }, +        hIcon: ptr::null_mut(), +        hCursor: ptr::null_mut(), +        hbrBackground: ptr::null_mut(), +        lpszMenuName: ptr::null(), +        lpszClassName: class_name.as_ptr(), +        hIconSm: ptr::null_mut(), +    }; + +    // We ignore errors because registering the same window class twice would trigger +    //  an error, and because errors here are detected during CreateWindowEx anyway. +    // Also since there is no weird element in the struct, there is no reason for this +    //  call to fail. +    unsafe { user32::RegisterClassExW(&class) }; + +    class_name +} + +fn switch_to_fullscreen(rect: &mut winapi::RECT, monitor: &MonitorID) -> Result<(), CreationError> { +    // adjusting the rect +    { +        let pos = monitor.get_position(); +        rect.left += pos.0 as winapi::LONG; +        rect.right += pos.0 as winapi::LONG; +        rect.top += pos.1 as winapi::LONG; +        rect.bottom += pos.1 as winapi::LONG; +    } + +    // changing device settings +    let mut screen_settings: winapi::DEVMODEW = unsafe { mem::zeroed() }; +    screen_settings.dmSize = mem::size_of::<winapi::DEVMODEW>() as winapi::WORD; +    screen_settings.dmPelsWidth = (rect.right - rect.left) as winapi::DWORD; +    screen_settings.dmPelsHeight = (rect.bottom - rect.top) as winapi::DWORD; +    screen_settings.dmBitsPerPel = 32;      // TODO: ? +    screen_settings.dmFields = winapi::DM_BITSPERPEL | winapi::DM_PELSWIDTH | winapi::DM_PELSHEIGHT; + +    let result = unsafe { user32::ChangeDisplaySettingsExW(monitor.get_system_name().as_ptr(), +        &mut screen_settings, ptr::null_mut(), winapi::CDS_FULLSCREEN, ptr::null_mut()) }; +     +    if result != winapi::DISP_CHANGE_SUCCESSFUL { +        return Err(OsError(format!("ChangeDisplaySettings failed: {}", result))); +    } + +    Ok(()) +} + +fn create_context(extra: Option<(&gl::wgl_extra::Wgl, &BuilderAttribs<'static>)>, +                  hdc: winapi::HDC, share: Option<winapi::HGLRC>) +                  -> Result<winapi::HGLRC, CreationError> +{ +    let share = share.unwrap_or(ptr::null_mut()); + +    let ctxt = if let Some((extra_functions, builder)) = extra { +        if extra_functions.CreateContextAttribsARB.is_loaded() {              let mut attributes = Vec::new();              if builder.gl_version.is_some() { @@ -313,105 +368,148 @@ pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option<C              attributes.push(0); -            let ctxt = unsafe { -                if extra_functions.CreateContextAttribsARB.is_loaded() { -                    let share = if let Some(c) = builder_sharelists { c } else { ptr::null_mut() }; -                    extra_functions.CreateContextAttribsARB(hdc as *const libc::c_void, -                                                            share as *const libc::c_void, -                                                            attributes.as_slice().as_ptr()) - -                } else { -                    let ctxt = gl::wgl::CreateContext(hdc as *const libc::c_void); -                    if let Some(c) = builder_sharelists { -                        gl::wgl::ShareLists(c as *const libc::c_void, ctxt); -                    }; -                    ctxt -                } -            }; - -            if ctxt.is_null() { -                tx.send(Err(OsError(format!("OpenGL context creation failed: {}", -                    os::error_string(os::errno() as usize))))); -                unsafe { user32::DestroyWindow(real_window); } -                return; +            Some(unsafe { +                extra_functions.CreateContextAttribsARB(hdc as *const libc::c_void, +                                                        share as *const libc::c_void, +                                                        attributes.as_slice().as_ptr()) +            }) +        } else { +            None +        } +    } else { +        None +    }; + +    let ctxt = match ctxt { +        Some(ctxt) => ctxt, +        None => { +            unsafe { +                let ctxt = gl::wgl::CreateContext(hdc as *const libc::c_void); +                if !share.is_null() { +                    gl::wgl::ShareLists(share as *const libc::c_void, ctxt); +                }; +                ctxt              } +        } +    }; -            ctxt -        }; +    if ctxt.is_null() { +        return Err(OsError(format!("OpenGL context creation failed: {}", +                           os::error_string(os::errno() as usize)))); +    } -        // calling SetForegroundWindow if fullscreen -        if builder.monitor.is_some() { -            unsafe { user32::SetForegroundWindow(real_window) }; -        } +    Ok(ctxt as winapi::HGLRC) +} -        // filling the WINDOW task-local storage -        let events_receiver = { -            let (tx, rx) = channel(); -            let mut tx = Some(tx); -            callback::WINDOW.with(|window| { -                (*window.borrow_mut()) = Some((real_window, tx.take().unwrap())); -            }); -            rx -        }; +fn enumerate_native_pixel_formats(hdc: winapi::HDC) -> Vec<(PixelFormat, libc::c_int)> { +    let size_of_pxfmtdescr = mem::size_of::<winapi::PIXELFORMATDESCRIPTOR>() as u32; +    let num = unsafe { gdi32::DescribePixelFormat(hdc, 1, size_of_pxfmtdescr, ptr::null_mut()) }; -        // loading the opengl32 module -        let gl_library = { -            let name = "opengl32.dll".utf16_units().chain(Some(0).into_iter()) -                .collect::<Vec<u16>>().as_ptr(); -            let lib = unsafe { kernel32::LoadLibraryW(name) }; -            if lib.is_null() { -                tx.send(Err(OsError(format!("LoadLibrary function failed: {}", -                    os::error_string(os::errno() as usize))))); -                unsafe { gl::wgl::DeleteContext(context); } -                unsafe { user32::DestroyWindow(real_window); } -                return; -            } -            lib -        }; +    let mut result = Vec::new(); -        // handling vsync -        if builder.vsync { -            if extra_functions.SwapIntervalEXT.is_loaded() { -                unsafe { gl::wgl::MakeCurrent(hdc as *const libc::c_void, context) }; -                if unsafe { extra_functions.SwapIntervalEXT(1) } == 0 { -                    tx.send(Err(OsError(format!("wglSwapIntervalEXT failed")))); -                    unsafe { gl::wgl::DeleteContext(context); } -                    unsafe { user32::DestroyWindow(real_window); } -                    return; -                } - -                // it is important to remove the current context, otherwise you get very weird -                // errors -                unsafe { gl::wgl::MakeCurrent(ptr::null(), ptr::null()); } -            } +    for index in (0 .. num) { +        let mut output: winapi::PIXELFORMATDESCRIPTOR = unsafe { mem::zeroed() }; +         +        if unsafe { gdi32::DescribePixelFormat(hdc, index, size_of_pxfmtdescr, +                                               &mut output) } == 0 +        { +            continue;          } -        // building the struct -        let window = Window{ -            window: real_window, -            hdc: hdc as winapi::HDC, -            context: context as winapi::HGLRC, -            gl_library: gl_library, -            events_receiver: events_receiver, -            is_closed: AtomicBool::new(false), -        }; +        if (output.dwFlags & winapi::PFD_DRAW_TO_WINDOW) == 0 { +            continue; +        } +        if (output.dwFlags & winapi::PFD_SUPPORT_OPENGL) == 0 { +            continue; +        } -        // sending -        tx.send(Ok(window)); +        if (output.dwFlags & winapi::PFD_GENERIC_ACCELERATED) == 0 && +            (output.dwFlags & winapi::PFD_GENERIC_FORMAT) == 0 +        { +            continue; +        } -        // now that the `Window` struct is initialized, the main `Window::new()` function will -        //  return and this events loop will run in parallel -        loop { -            let mut msg = unsafe { mem::uninitialized() }; +        if output.iPixelType != winapi::PFD_TYPE_RGBA { +            continue; +        } -            if unsafe { user32::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) } == 0 { -                break; -            } +        result.push((PixelFormat { +            red_bits: output.cRedBits, +            green_bits: output.cGreenBits, +            blue_bits: output.cBlueBits, +            alpha_bits: output.cAlphaBits, +            depth_bits: output.cDepthBits, +            stencil_bits: output.cStencilBits, +            stereoscopy: (output.dwFlags & winapi::PFD_STEREO) != 0, +            double_buffer: (output.dwFlags & winapi::PFD_DOUBLEBUFFER) != 0, +            multisampling: None, +            srgb: false, +        }, index)); +    } + +    result +} -            unsafe { user32::TranslateMessage(&msg) }; -            unsafe { user32::DispatchMessageW(&msg) };     // calls `callback` (see below) +fn enumerate_arb_pixel_formats(extra: &gl::wgl_extra::Wgl, hdc: winapi::HDC) +                               -> Vec<(PixelFormat, libc::c_int)> +{ +    let get_info = |index: u32, attrib: u32| { +        let mut value = unsafe { mem::uninitialized() }; +        unsafe { extra.GetPixelFormatAttribivARB(hdc as *const libc::c_void, index as libc::c_int, +                                                 0, 1, [attrib as libc::c_int].as_ptr(), +                                                 &mut value) }; +        value as u32 +    }; + +    // getting the number of formats +    // the `1` is ignored +    let num = get_info(1, gl::wgl_extra::NUMBER_PIXEL_FORMATS_ARB); + +    let mut result = Vec::new(); + +    for index in (0 .. num) { +        if get_info(index, gl::wgl_extra::DRAW_TO_WINDOW_ARB) == 0 { +            continue; +        } +        if get_info(index, gl::wgl_extra::SUPPORT_OPENGL_ARB) == 0 { +            continue;          } -    }); -    rx.recv().unwrap() +        if get_info(index, gl::wgl_extra::ACCELERATION_ARB) == gl::wgl_extra::NO_ACCELERATION_ARB { +            continue; +        } + +        if get_info(index, gl::wgl_extra::PIXEL_TYPE_ARB) != gl::wgl_extra::TYPE_RGBA_ARB { +            continue; +        } + +        result.push((PixelFormat { +            red_bits: get_info(index, gl::wgl_extra::RED_BITS_ARB) as u8, +            green_bits: get_info(index, gl::wgl_extra::GREEN_BITS_ARB) as u8, +            blue_bits: get_info(index, gl::wgl_extra::BLUE_BITS_ARB) as u8, +            alpha_bits: get_info(index, gl::wgl_extra::ALPHA_BITS_ARB) as u8, +            depth_bits: get_info(index, gl::wgl_extra::DEPTH_BITS_ARB) as u8, +            stencil_bits: get_info(index, gl::wgl_extra::STENCIL_BITS_ARB) as u8, +            stereoscopy: get_info(index, gl::wgl_extra::STEREO_ARB) != 0, +            double_buffer: get_info(index, gl::wgl_extra::DOUBLE_BUFFER_ARB) != 0, +            multisampling: None,        // FIXME:  +            srgb: false,        // FIXME:  +        }, index as libc::c_int)); +    } + +    result +} + +fn load_opengl32_dll() -> Result<winapi::HMODULE, CreationError> { +    let name = "opengl32.dll".utf16_units().chain(Some(0).into_iter()) +                             .collect::<Vec<u16>>().as_ptr(); + +    let lib = unsafe { kernel32::LoadLibraryW(name) }; + +    if lib.is_null() { +        return Err(OsError(format!("LoadLibrary function failed: {}", +                                    os::error_string(os::errno() as usize)))); +    } + +    Ok(lib)  } diff --git a/src/win32/mod.rs b/src/win32/mod.rs index 8076bcc..e0adb7b 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -277,8 +277,9 @@ impl<'a> Iterator for WaitEventsIterator<'a> {  impl Drop for Window {      fn drop(&mut self) {          use std::ptr; +        // we don't call MakeCurrent(0, 0) because we are not sure that the context +        // is still the current one          unsafe { user32::PostMessageW(self.window, winapi::WM_DESTROY, 0, 0); } -        unsafe { gl::wgl::MakeCurrent(ptr::null(), ptr::null()); }          unsafe { gl::wgl::DeleteContext(self.context as *const libc::c_void); }          unsafe { user32::DestroyWindow(self.window); }      } diff --git a/src/x11/window/mod.rs b/src/x11/window/mod.rs index 0c501ff..05fcf14 100644 --- a/src/x11/window/mod.rs +++ b/src/x11/window/mod.rs @@ -59,7 +59,8 @@ unsafe impl Sync for Window {}  impl Drop for XWindow {      fn drop(&mut self) {          unsafe { -            ffi::glx::MakeCurrent(self.display, 0, ptr::null()); +            // we don't call MakeCurrent(0, 0) because we are not sure that the context +            // is still the current one              ffi::glx::DestroyContext(self.display, self.context);              if self.is_fullscreen {  | 
