wayland_egl/lib.rs
1#![warn(missing_docs, missing_debug_implementations)]
2#![forbid(improper_ctypes, unsafe_op_in_unsafe_fn)]
3
4//! EGL utilities
5//!
6//! This module contains bindings to the `libwayland-egl.so` library.
7//!
8//! This library is used to interface with the OpenGL stack, and creating
9//! EGL surfaces from a wayland surface.
10//!
11//! See [`WlEglSurface`] documentation for details.
12
13use std::{fmt, os::raw::c_void};
14
15use wayland_backend::client::ObjectId;
16use wayland_sys::{client::wl_proxy, egl::*, ffi_dispatch};
17
18/// Checks if the wayland-egl lib is available and can be used
19///
20/// Trying to create an [`WlEglSurface`] while this function returns
21/// [`false`] will result in a panic.
22pub fn is_available() -> bool {
23 is_lib_available()
24}
25
26/// EGL surface
27///
28/// This object is a simple wrapper around a `wl_surface` to add the EGL
29/// capabilities. Just use the [`ptr()`][WlEglSurface::ptr()] method once this object
30/// is created to get the window pointer your OpenGL library is needing to initialize
31/// the EGL context (you'll most likely need the display ptr as well, that you can
32/// get via the [`ObjectId::as_ptr()`] method on of the `wl_display` ID).
33#[derive(Debug)]
34pub struct WlEglSurface {
35 ptr: *mut wl_egl_window,
36}
37
38impl WlEglSurface {
39 /// Create an EGL surface from a wayland surface
40 ///
41 /// This method will check that the provided [`ObjectId`] is still alive and from the
42 /// correct interface (`wl_surface`).
43 ///
44 /// You must always destroy the [`WlEglSurface`] *before* the underling `wl_surface`
45 /// protocol object.
46 pub fn new(surface: ObjectId, width: i32, height: i32) -> Result<Self, Error> {
47 if surface.interface().name != "wl_surface" {
48 return Err(Error::InvalidId);
49 }
50
51 let ptr = surface.as_ptr();
52 if ptr.is_null() {
53 // ObjectId::as_ptr() returns NULL if the surface is no longer alive
54 Err(Error::InvalidId)
55 } else {
56 // SAFETY: We are sure the pointer is valid and the interface is correct.
57 unsafe { Self::new_from_raw(ptr, width, height) }
58 }
59 }
60
61 /// Create an EGL surface from a raw pointer to a wayland surface.
62 ///
63 /// # Safety
64 ///
65 /// The provided pointer must be a valid `wl_surface` pointer from `libwayland-client`.
66 pub unsafe fn new_from_raw(
67 surface: *mut wl_proxy,
68 width: i32,
69 height: i32,
70 ) -> Result<Self, Error> {
71 if width <= 0 || height <= 0 {
72 return Err(Error::InvalidSize);
73 }
74 let ptr = ffi_dispatch!(wayland_egl_handle(), wl_egl_window_create, surface, width, height);
75 if ptr.is_null() {
76 panic!("egl window allocation failed");
77 }
78 Ok(Self { ptr })
79 }
80
81 /// Fetch current size of the EGL surface
82 pub fn get_size(&self) -> (i32, i32) {
83 let mut w = 0i32;
84 let mut h = 0i32;
85 unsafe {
86 ffi_dispatch!(
87 wayland_egl_handle(),
88 wl_egl_window_get_attached_size,
89 self.ptr,
90 &mut w as *mut i32,
91 &mut h as *mut i32
92 );
93 }
94 (w, h)
95 }
96
97 /// Resize the EGL surface
98 ///
99 /// The two first arguments `(width, height)` are the new size of
100 /// the surface, the two others `(dx, dy)` represent the displacement
101 /// of the top-left corner of the surface. It allows you to control the
102 /// direction of the resizing if necessary.
103 pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) {
104 unsafe {
105 ffi_dispatch!(
106 wayland_egl_handle(),
107 wl_egl_window_resize,
108 self.ptr,
109 width,
110 height,
111 dx,
112 dy
113 )
114 }
115 }
116
117 /// Raw pointer to the EGL surface
118 ///
119 /// You'll need this pointer to initialize the EGL context in your
120 /// favourite OpenGL lib.
121 pub fn ptr(&self) -> *const c_void {
122 self.ptr as *const c_void
123 }
124}
125
126// SAFETY: We own the pointer to the wl_egl_window and can therefore be transferred to another thread.
127unsafe impl Send for WlEglSurface {}
128// Note that WlEglSurface is !Sync. This is because the pointer performs no internal synchronization.
129
130impl Drop for WlEglSurface {
131 fn drop(&mut self) {
132 unsafe {
133 ffi_dispatch!(wayland_egl_handle(), wl_egl_window_destroy, self.ptr);
134 }
135 }
136}
137
138/// EGL surface creation error.
139#[derive(Debug)]
140pub enum Error {
141 /// Surface width or height are <= 0.
142 InvalidSize,
143 /// Passed surface object is not a surface.
144 InvalidId,
145}
146
147impl std::error::Error for Error {}
148
149impl fmt::Display for Error {
150 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151 match self {
152 Error::InvalidSize => write!(f, "surface width or height is <= 0"),
153 Error::InvalidId => write!(f, "object id is not a surface"),
154 }
155 }
156}