1//! Everything related to the GLXWindow.
2
3use std::fmt;
4use std::marker::PhantomData;
5use std::num::NonZeroU32;
6use std::os::raw::{c_int, c_uint};
7
8use glutin_glx_sys::glx::types::GLXWindow;
9use glutin_glx_sys::{glx, glx_extra};
10use raw_window_handle::RawWindowHandle;
11
12use crate::config::GetGlConfig;
13use crate::display::{DisplayFeatures, GetGlDisplay};
14use crate::error::{ErrorKind, Result};
15use crate::private::Sealed;
16use crate::surface::{
17 AsRawSurface, GlSurface, NativePixmap, PbufferSurface, PixmapSurface, RawSurface,
18 SurfaceAttributes, SurfaceType, SurfaceTypeTrait, SwapInterval, WindowSurface,
19};
20
21use super::config::Config;
22use super::context::PossiblyCurrentContext;
23use super::display::Display;
24
25/// Hint for the attributes array.
26const ATTR_SIZE_HINT: usize = 8;
27
28impl Display {
29 pub(crate) unsafe fn create_pixmap_surface(
30 &self,
31 config: &Config,
32 surface_attributes: &SurfaceAttributes<PixmapSurface>,
33 ) -> Result<Surface<PixmapSurface>> {
34 let native_pixmap = surface_attributes.native_pixmap.as_ref().unwrap();
35 let xid = match native_pixmap {
36 NativePixmap::XlibPixmap(xid) => {
37 if *xid == 0 {
38 return Err(ErrorKind::BadNativePixmap.into());
39 }
40
41 *xid
42 },
43 _ => {
44 return Err(
45 ErrorKind::NotSupported("provided native pixmap is not supported.").into()
46 )
47 },
48 };
49
50 let mut attrs = Vec::<c_int>::with_capacity(ATTR_SIZE_HINT);
51
52 // Push X11 `None` to terminate the list.
53 attrs.push(0);
54
55 let config = config.clone();
56 let surface = super::last_glx_error(|| unsafe {
57 self.inner.glx.CreatePixmap(
58 self.inner.raw.cast(),
59 *config.inner.raw,
60 xid,
61 attrs.as_ptr(),
62 )
63 })?;
64
65 Ok(Surface {
66 display: self.clone(),
67 config,
68 raw: surface,
69 _nosendsync: PhantomData,
70 _ty: PhantomData,
71 })
72 }
73
74 pub(crate) unsafe fn create_pbuffer_surface(
75 &self,
76 config: &Config,
77 surface_attributes: &SurfaceAttributes<PbufferSurface>,
78 ) -> Result<Surface<PbufferSurface>> {
79 let width = surface_attributes.width.unwrap();
80 let height = surface_attributes.height.unwrap();
81
82 let mut attrs = Vec::<c_int>::with_capacity(ATTR_SIZE_HINT);
83
84 attrs.push(glx::PBUFFER_WIDTH as c_int);
85 attrs.push(width.get() as c_int);
86 attrs.push(glx::PBUFFER_HEIGHT as c_int);
87 attrs.push(height.get() as c_int);
88 attrs.push(glx::LARGEST_PBUFFER as c_int);
89 attrs.push(surface_attributes.largest_pbuffer as c_int);
90
91 // Push X11 `None` to terminate the list.
92 attrs.push(0);
93
94 let config = config.clone();
95 let surface = super::last_glx_error(|| unsafe {
96 self.inner.glx.CreatePbuffer(self.inner.raw.cast(), *config.inner.raw, attrs.as_ptr())
97 })?;
98
99 Ok(Surface {
100 display: self.clone(),
101 config,
102 raw: surface,
103 _nosendsync: PhantomData,
104 _ty: PhantomData,
105 })
106 }
107
108 pub(crate) unsafe fn create_window_surface(
109 &self,
110 config: &Config,
111 surface_attributes: &SurfaceAttributes<WindowSurface>,
112 ) -> Result<Surface<WindowSurface>> {
113 let window = match surface_attributes.raw_window_handle.unwrap() {
114 RawWindowHandle::Xlib(window_handle) => {
115 if window_handle.window == 0 {
116 return Err(ErrorKind::BadNativeWindow.into());
117 }
118
119 window_handle.window
120 },
121 _ => {
122 return Err(
123 ErrorKind::NotSupported("provided native window is not supported").into()
124 )
125 },
126 };
127
128 let mut attrs = Vec::<c_int>::with_capacity(ATTR_SIZE_HINT);
129
130 // Push X11 `None` to terminate the list.
131 attrs.push(0);
132
133 let config = config.clone();
134 let surface = super::last_glx_error(|| unsafe {
135 self.inner.glx.CreateWindow(
136 self.inner.raw.cast(),
137 *config.inner.raw,
138 window,
139 attrs.as_ptr() as *const _,
140 )
141 })?;
142
143 Ok(Surface {
144 display: self.clone(),
145 config,
146 raw: surface,
147 _nosendsync: PhantomData,
148 _ty: PhantomData,
149 })
150 }
151}
152
153/// A wrapper around the `GLXWindow`.
154pub struct Surface<T: SurfaceTypeTrait> {
155 display: Display,
156 config: Config,
157 pub(crate) raw: GLXWindow,
158 _nosendsync: PhantomData<*const std::ffi::c_void>,
159 _ty: PhantomData<T>,
160}
161
162// Impl only `Send` for Surface.
163unsafe impl<T: SurfaceTypeTrait> Send for Surface<T> {}
164
165impl<T: SurfaceTypeTrait> Surface<T> {
166 /// # Safety
167 ///
168 /// The caller must ensure that the attribute could be present.
169 unsafe fn raw_attribute(&self, attr: c_int) -> c_uint {
170 unsafe {
171 let mut value: u32 = 0;
172 // This shouldn't generate any errors given that we know that the surface is
173 // valid.
174 self.display.inner.glx.QueryDrawable(
175 self.display.inner.raw.cast(),
176 self.raw,
177 attribute:attr,
178 &mut value,
179 );
180 value
181 }
182 }
183}
184
185impl<T: SurfaceTypeTrait> Drop for Surface<T> {
186 fn drop(&mut self) {
187 let _ = super::last_glx_error(|| unsafe {
188 match T::surface_type() {
189 SurfaceType::Pbuffer => {
190 self.display.inner.glx.DestroyPbuffer(self.display.inner.raw.cast(), self.raw);
191 },
192 SurfaceType::Window => {
193 self.display.inner.glx.DestroyWindow(self.display.inner.raw.cast(), self.raw);
194 },
195 SurfaceType::Pixmap => {
196 self.display.inner.glx.DestroyPixmap(self.display.inner.raw.cast(), self.raw);
197 },
198 }
199 });
200 }
201}
202
203impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> {
204 type Context = PossiblyCurrentContext;
205 type SurfaceType = T;
206
207 fn buffer_age(&self) -> u32 {
208 self.display
209 .inner
210 .client_extensions
211 .contains("GLX_EXT_buffer_age")
212 .then(|| unsafe { self.raw_attribute(glx_extra::BACK_BUFFER_AGE_EXT as c_int) })
213 .unwrap_or(0) as u32
214 }
215
216 fn width(&self) -> Option<u32> {
217 unsafe { Some(self.raw_attribute(glx::WIDTH as c_int) as u32) }
218 }
219
220 fn height(&self) -> Option<u32> {
221 unsafe { Some(self.raw_attribute(glx::HEIGHT as c_int) as u32) }
222 }
223
224 fn is_single_buffered(&self) -> bool {
225 self.config.is_single_buffered()
226 }
227
228 fn swap_buffers(&self, _context: &Self::Context) -> Result<()> {
229 super::last_glx_error(|| unsafe {
230 self.display.inner.glx.SwapBuffers(self.display.inner.raw.cast(), self.raw);
231 })
232 }
233
234 fn set_swap_interval(&self, _context: &Self::Context, interval: SwapInterval) -> Result<()> {
235 let extra = match self.display.inner.glx_extra {
236 Some(extra) if self.display.inner.features.contains(DisplayFeatures::SWAP_CONTROL) => {
237 extra
238 },
239 _ => {
240 return Err(
241 ErrorKind::NotSupported("swap contol extrensions are not supported").into()
242 );
243 },
244 };
245
246 let interval = match interval {
247 SwapInterval::DontWait => 0,
248 SwapInterval::Wait(n) => n.get(),
249 };
250
251 let mut applied = false;
252
253 // Apply the `EXT` first since it's per window.
254 if !applied && self.display.inner.client_extensions.contains("GLX_EXT_swap_control") {
255 super::last_glx_error(|| unsafe {
256 // Check for error explicitly here, other apis do have indication for failure.
257 extra.SwapIntervalEXT(self.display.inner.raw.cast(), self.raw, interval as _);
258 applied = true;
259 })?;
260 }
261
262 if !applied && self.display.inner.client_extensions.contains("GLX_MESA_swap_control") {
263 unsafe {
264 applied = extra.SwapIntervalMESA(interval as _) != glx::BAD_CONTEXT as _;
265 }
266 }
267
268 if !applied && self.display.inner.client_extensions.contains("GLX_SGI_swap_control") {
269 unsafe {
270 applied = extra.SwapIntervalSGI(interval as _) != glx::BAD_CONTEXT as _;
271 }
272 }
273
274 if applied {
275 Ok(())
276 } else {
277 Err(ErrorKind::BadContext.into())
278 }
279 }
280
281 fn is_current(&self, context: &Self::Context) -> bool {
282 self.is_current_draw(context) && self.is_current_read(context)
283 }
284
285 fn is_current_draw(&self, _context: &Self::Context) -> bool {
286 unsafe { self.display.inner.glx.GetCurrentDrawable() == self.raw }
287 }
288
289 fn is_current_read(&self, _context: &Self::Context) -> bool {
290 unsafe { self.display.inner.glx.GetCurrentReadDrawable() == self.raw }
291 }
292
293 fn resize(&self, _context: &Self::Context, _width: NonZeroU32, _height: NonZeroU32) {
294 // This isn't supported with GLXDrawable.
295 }
296}
297
298impl<T: SurfaceTypeTrait> GetGlConfig for Surface<T> {
299 type Target = Config;
300
301 fn config(&self) -> Self::Target {
302 self.config.clone()
303 }
304}
305
306impl<T: SurfaceTypeTrait> GetGlDisplay for Surface<T> {
307 type Target = Display;
308
309 fn display(&self) -> Self::Target {
310 self.display.clone()
311 }
312}
313
314impl<T: SurfaceTypeTrait> fmt::Debug for Surface<T> {
315 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316 f&mut DebugStruct<'_, '_>.debug_struct("Surface")
317 .field("display", &self.display.inner.raw)
318 .field("config", &self.config.inner.raw)
319 .field("raw", &self.raw)
320 .field(name:"type", &T::surface_type())
321 .finish()
322 }
323}
324
325impl<T: SurfaceTypeTrait> AsRawSurface for Surface<T> {
326 fn raw_surface(&self) -> RawSurface {
327 RawSurface::Glx(self.raw as u64)
328 }
329}
330
331impl<T: SurfaceTypeTrait> Sealed for Surface<T> {}
332