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 =
42                 glx.MakeCurrent(xconn.display as *mut _, drawable, context);
43 
44             if res == 0 {
45                 let err = xconn.check_errors();
46                 Err(format!("`glXMakeCurrent` failed: {:?}", err))
47             } else {
48                 Ok(ret)
49             }
50         }
51     }
52 
old_context(&mut self) -> Option<ffi::GLXContext>53     pub fn old_context(&mut self) -> Option<ffi::GLXContext> {
54         self.possibly_invalid.as_ref().map(|pi| pi.old_context)
55     }
56 
invalidate(&mut self)57     pub fn invalidate(&mut self) {
58         self.possibly_invalid.take();
59     }
60 }
61 
62 impl Drop for MakeCurrentGuard {
drop(&mut self)63     fn drop(&mut self) {
64         let glx = super::GLX.as_ref().unwrap();
65         let (drawable, context) = match self.possibly_invalid.take() {
66             Some(inner) => (inner.old_drawable, inner.old_context),
67             None => (0, std::ptr::null()),
68         };
69 
70         let display = match self.old_display {
71             old_display if old_display == std::ptr::null_mut() => self.display,
72             old_display => old_display,
73         };
74 
75         let res =
76             unsafe { glx.MakeCurrent(display as *mut _, drawable, context) };
77 
78         if res == 0 {
79             let err = self.xconn.check_errors();
80             panic!("`glXMakeCurrent` failed: {:?}", err);
81         }
82     }
83 }
84