1 use crate::platform::unix::x11::XConnection;
2 use glutin_glx_sys as ffi;
3 
4 use std::sync::Arc;
5 
6 /// A guard for when you want to make the context current. Destroying the guard
7 /// restores the previously-current context.
8 #[derive(Debug)]
9 pub struct MakeCurrentGuard {
10     old_display: *mut ffi::Display,
11     display: *mut ffi::Display,
12     xconn: Arc<XConnection>,
13     possibly_invalid: Option<MakeCurrentGuardInner>,
14 }
15 
16 #[derive(Debug)]
17 struct MakeCurrentGuardInner {
18     old_drawable: ffi::glx::types::GLXDrawable,
19     old_context: ffi::GLXContext,
20 }
21 
22 impl MakeCurrentGuard {
new( xconn: &Arc<XConnection>, drawable: ffi::glx::types::GLXDrawable, context: ffi::GLXContext, ) -> Result<Self, String>23     pub fn new(
24         xconn: &Arc<XConnection>,
25         drawable: ffi::glx::types::GLXDrawable,
26         context: ffi::GLXContext,
27     ) -> Result<Self, String> {
28         unsafe {
29             let glx = super::GLX.as_ref().unwrap();
30 
31             let ret = MakeCurrentGuard {
32                 old_display: glx.GetCurrentDisplay() as *mut _,
33                 display: xconn.display as *mut _,
34                 xconn: Arc::clone(xconn),
35                 possibly_invalid: Some(MakeCurrentGuardInner {
36                     old_drawable: glx.GetCurrentDrawable(),
37                     old_context: glx.GetCurrentContext(),
38                 }),
39             };
40 
41             let res = glx.MakeCurrent(xconn.display as *mut _, drawable, context);
42 
43             if res == 0 {
44                 let err = xconn.check_errors();
45                 Err(format!("`glXMakeCurrent` failed: {:?}", err))
46             } else {
47                 Ok(ret)
48             }
49         }
50     }
51 
old_context(&mut self) -> Option<ffi::GLXContext>52     pub fn old_context(&mut self) -> Option<ffi::GLXContext> {
53         self.possibly_invalid.as_ref().map(|pi| pi.old_context)
54     }
55 
invalidate(&mut self)56     pub fn invalidate(&mut self) {
57         self.possibly_invalid.take();
58     }
59 }
60 
61 impl Drop for MakeCurrentGuard {
drop(&mut self)62     fn drop(&mut self) {
63         let glx = super::GLX.as_ref().unwrap();
64         let (drawable, context) = match self.possibly_invalid.take() {
65             Some(inner) => (inner.old_drawable, inner.old_context),
66             None => (0, std::ptr::null()),
67         };
68 
69         let display = match self.old_display {
70             old_display if old_display == std::ptr::null_mut() => self.display,
71             old_display => old_display,
72         };
73 
74         let res = unsafe { glx.MakeCurrent(display as *mut _, drawable, context) };
75 
76         if res == 0 {
77             let err = self.xconn.check_errors();
78             panic!("`glXMakeCurrent` failed: {:?}", err);
79         }
80     }
81 }
82