| 1 | //! A cross platform OpenGL surface representation. |
| 2 | #![allow (unreachable_patterns)] |
| 3 | |
| 4 | use std::marker::PhantomData; |
| 5 | use std::num::NonZeroU32; |
| 6 | |
| 7 | use raw_window_handle::RawWindowHandle; |
| 8 | |
| 9 | use crate::context::{PossiblyCurrentContext, PossiblyCurrentGlContext}; |
| 10 | use crate::display::{Display, GetGlDisplay}; |
| 11 | use crate::error::Result; |
| 12 | use crate::private::{gl_api_dispatch, Sealed}; |
| 13 | |
| 14 | #[cfg (cgl_backend)] |
| 15 | use crate::api::cgl::surface::Surface as CglSurface; |
| 16 | #[cfg (egl_backend)] |
| 17 | use crate::api::egl::surface::Surface as EglSurface; |
| 18 | #[cfg (glx_backend)] |
| 19 | use crate::api::glx::surface::Surface as GlxSurface; |
| 20 | #[cfg (wgl_backend)] |
| 21 | use crate::api::wgl::surface::Surface as WglSurface; |
| 22 | |
| 23 | /// A trait to group common operations on the surface. |
| 24 | pub trait GlSurface<T: SurfaceTypeTrait>: Sealed { |
| 25 | /// The type of the surface. |
| 26 | type SurfaceType: SurfaceTypeTrait; |
| 27 | /// The context to access surface data. |
| 28 | type Context: PossiblyCurrentGlContext; |
| 29 | |
| 30 | /// The age of the back buffer of that surface. The `0` indicates that the |
| 31 | /// buffer is either a new one or we failed to get the information about |
| 32 | /// its age. In both cases you must redraw the entire buffer. |
| 33 | /// |
| 34 | /// # Platform-specific |
| 35 | /// |
| 36 | /// - **Wayland:** this call will latch the underlying back buffer, meaning |
| 37 | /// that all resize operations will apply after the next |
| 38 | /// [`GlSurface::swap_buffers`]. |
| 39 | fn buffer_age(&self) -> u32; |
| 40 | |
| 41 | /// The **physical** width of the underlying surface. |
| 42 | fn width(&self) -> Option<u32>; |
| 43 | |
| 44 | /// The **physical** height of the underlying surface. |
| 45 | /// |
| 46 | /// # Platform specific |
| 47 | /// |
| 48 | /// - **macOS: this will block if your main thread is blocked.** |
| 49 | fn height(&self) -> Option<u32>; |
| 50 | |
| 51 | /// Check whether the surface is single buffered. |
| 52 | /// |
| 53 | /// # Platform specific |
| 54 | /// |
| 55 | /// - **macOS: this will block if your main thread is blocked.** |
| 56 | fn is_single_buffered(&self) -> bool; |
| 57 | |
| 58 | /// Swaps the underlying back buffers when the surface is not single |
| 59 | /// buffered. |
| 60 | fn swap_buffers(&self, context: &Self::Context) -> Result<()>; |
| 61 | |
| 62 | /// Check whether the surface is current on to the current thread. |
| 63 | fn is_current(&self, context: &Self::Context) -> bool; |
| 64 | |
| 65 | /// Check whether the surface is the current draw surface to the current |
| 66 | /// thread. |
| 67 | fn is_current_draw(&self, context: &Self::Context) -> bool; |
| 68 | |
| 69 | /// Check whether the surface is the current read surface to the current |
| 70 | /// thread. |
| 71 | fn is_current_read(&self, context: &Self::Context) -> bool; |
| 72 | |
| 73 | /// Set swap interval for the surface. |
| 74 | /// |
| 75 | /// See [`crate::surface::SwapInterval`] for details. |
| 76 | fn set_swap_interval(&self, context: &Self::Context, interval: SwapInterval) -> Result<()>; |
| 77 | |
| 78 | /// Resize the surface to a new size. |
| 79 | /// |
| 80 | /// This call is for compatibility reasons, on most platforms it's a no-op. |
| 81 | /// It's recommended to call this function before doing any rendering and |
| 82 | /// performing [`PossiblyCurrentGlContext::make_current`], and |
| 83 | /// [`GlSurface::buffer_age`]. |
| 84 | /// |
| 85 | /// # Platform specific |
| 86 | /// |
| 87 | /// - **Wayland:** resizes the surface; |
| 88 | /// - **macOS: this will block if your main thread is blocked;** |
| 89 | /// - **Other:** no op. |
| 90 | fn resize(&self, context: &Self::Context, width: NonZeroU32, height: NonZeroU32) |
| 91 | where |
| 92 | Self::SurfaceType: ResizeableSurface; |
| 93 | } |
| 94 | |
| 95 | /// The marker trait to indicate the type of the surface. |
| 96 | pub trait SurfaceTypeTrait: Sealed { |
| 97 | /// Get the type of the surface. |
| 98 | fn surface_type() -> SurfaceType; |
| 99 | } |
| 100 | |
| 101 | /// Marker indicating that the surface could be resized. |
| 102 | pub trait ResizeableSurface: Sealed {} |
| 103 | |
| 104 | /// Trait for accessing the raw GL surface. |
| 105 | pub trait AsRawSurface { |
| 106 | /// Get the raw handle to the surface. |
| 107 | fn raw_surface(&self) -> RawSurface; |
| 108 | } |
| 109 | |
| 110 | /// Builder to get the required set of attributes initialized before hand. |
| 111 | #[derive (Default, Debug, Clone)] |
| 112 | pub struct SurfaceAttributesBuilder<T: SurfaceTypeTrait + Default> { |
| 113 | attributes: SurfaceAttributes<T>, |
| 114 | } |
| 115 | |
| 116 | impl<T: SurfaceTypeTrait + Default> SurfaceAttributesBuilder<T> { |
| 117 | /// Get new surface attributes. |
| 118 | pub fn new() -> Self { |
| 119 | Default::default() |
| 120 | } |
| 121 | |
| 122 | /// Specify whether the surface should support srgb or not. Passing `None` |
| 123 | /// means you don't care. |
| 124 | /// |
| 125 | /// # Api-specific. |
| 126 | /// |
| 127 | /// This only controls EGL surfaces, other platforms use the context for |
| 128 | /// that. |
| 129 | pub fn with_srgb(mut self, srgb: Option<bool>) -> Self { |
| 130 | self.attributes.srgb = srgb; |
| 131 | self |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | impl SurfaceAttributesBuilder<WindowSurface> { |
| 136 | /// Specify whether the single buffer should be used instead of double |
| 137 | /// buffering. This doesn't guarantee that the resulted buffer will have |
| 138 | /// only single buffer, to know that the single buffer is actually used |
| 139 | /// query the created surface with [`Surface::is_single_buffered`]. |
| 140 | /// |
| 141 | /// The surface is requested as double buffered by default. |
| 142 | /// |
| 143 | /// # Api-specific. |
| 144 | /// |
| 145 | /// This is EGL specific, other platforms use the context for that. |
| 146 | pub fn with_single_buffer(mut self, single_buffer: bool) -> Self { |
| 147 | self.attributes.single_buffer = single_buffer; |
| 148 | self |
| 149 | } |
| 150 | |
| 151 | /// Build the surface attributes suitable to create a window surface. |
| 152 | pub fn build( |
| 153 | mut self, |
| 154 | raw_window_handle: RawWindowHandle, |
| 155 | width: NonZeroU32, |
| 156 | height: NonZeroU32, |
| 157 | ) -> SurfaceAttributes<WindowSurface> { |
| 158 | self.attributes.raw_window_handle = Some(raw_window_handle); |
| 159 | self.attributes.width = Some(width); |
| 160 | self.attributes.height = Some(height); |
| 161 | self.attributes |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | impl SurfaceAttributesBuilder<PbufferSurface> { |
| 166 | /// Request the largest pbuffer. |
| 167 | pub fn with_largest_pbuffer(mut self, largest_pbuffer: bool) -> Self { |
| 168 | self.attributes.largest_pbuffer = largest_pbuffer; |
| 169 | self |
| 170 | } |
| 171 | |
| 172 | /// The same as in |
| 173 | /// [`SurfaceAttributesBuilder::<WindowSurface>::with_single_buffer`]. |
| 174 | pub fn with_single_buffer(mut self, single_buffer: bool) -> Self { |
| 175 | self.attributes.single_buffer = single_buffer; |
| 176 | self |
| 177 | } |
| 178 | |
| 179 | /// Build the surface attributes suitable to create a pbuffer surface. |
| 180 | pub fn build( |
| 181 | mut self, |
| 182 | width: NonZeroU32, |
| 183 | height: NonZeroU32, |
| 184 | ) -> SurfaceAttributes<PbufferSurface> { |
| 185 | self.attributes.width = Some(width); |
| 186 | self.attributes.height = Some(height); |
| 187 | self.attributes |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | impl SurfaceAttributesBuilder<PixmapSurface> { |
| 192 | /// Build the surface attributes suitable to create a pixmap surface. |
| 193 | pub fn build(mut self, native_pixmap: NativePixmap) -> SurfaceAttributes<PixmapSurface> { |
| 194 | self.attributes.native_pixmap = Some(native_pixmap); |
| 195 | self.attributes |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | /// Attributes which are used for creating a particular surface. |
| 200 | #[derive (Default, Debug, Clone)] |
| 201 | pub struct SurfaceAttributes<T: SurfaceTypeTrait> { |
| 202 | pub(crate) srgb: Option<bool>, |
| 203 | pub(crate) single_buffer: bool, |
| 204 | pub(crate) width: Option<NonZeroU32>, |
| 205 | pub(crate) height: Option<NonZeroU32>, |
| 206 | pub(crate) largest_pbuffer: bool, |
| 207 | pub(crate) raw_window_handle: Option<RawWindowHandle>, |
| 208 | pub(crate) native_pixmap: Option<NativePixmap>, |
| 209 | _ty: PhantomData<T>, |
| 210 | } |
| 211 | |
| 212 | /// Marker that used to type-gate methods for window. |
| 213 | #[derive (Default, Debug, Clone, Copy, PartialEq, Eq)] |
| 214 | pub struct WindowSurface; |
| 215 | |
| 216 | impl SurfaceTypeTrait for WindowSurface { |
| 217 | fn surface_type() -> SurfaceType { |
| 218 | SurfaceType::Window |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | impl ResizeableSurface for WindowSurface {} |
| 223 | |
| 224 | impl Sealed for WindowSurface {} |
| 225 | |
| 226 | /// Marker that used to type-gate methods for pbuffer. |
| 227 | #[derive (Default, Debug, Clone, Copy, PartialEq, Eq)] |
| 228 | pub struct PbufferSurface; |
| 229 | |
| 230 | impl SurfaceTypeTrait for PbufferSurface { |
| 231 | fn surface_type() -> SurfaceType { |
| 232 | SurfaceType::Pbuffer |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | impl Sealed for PbufferSurface {} |
| 237 | |
| 238 | /// Marker that used to type-gate methods for pixmap. |
| 239 | #[derive (Default, Debug, Clone, Copy, PartialEq, Eq)] |
| 240 | pub struct PixmapSurface; |
| 241 | |
| 242 | impl SurfaceTypeTrait for PixmapSurface { |
| 243 | fn surface_type() -> SurfaceType { |
| 244 | SurfaceType::Pixmap |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | impl Sealed for PixmapSurface {} |
| 249 | |
| 250 | /// The underlying type of the surface. |
| 251 | #[derive (Debug, Clone, Copy)] |
| 252 | pub enum SurfaceType { |
| 253 | /// The window surface. |
| 254 | Window, |
| 255 | |
| 256 | /// Pixmap surface. |
| 257 | Pixmap, |
| 258 | |
| 259 | /// Pbuffer surface. |
| 260 | Pbuffer, |
| 261 | } |
| 262 | |
| 263 | /// The GL surface that is used for rendering. |
| 264 | /// |
| 265 | /// Similar to the context, the GL surface is [`Send`] but not [`Sync`]. This |
| 266 | /// means it could be sent to a different thread as long as it is not current on |
| 267 | /// another thread. |
| 268 | /// |
| 269 | /// ```no_run |
| 270 | /// fn test_send<T: Send>() {} |
| 271 | /// test_send::<glutin::surface::Surface<glutin::surface::WindowSurface>>(); |
| 272 | /// ``` |
| 273 | /// ```compile_fail |
| 274 | /// fn test_sync<T: Sync>() {} |
| 275 | /// test_sync::<glutin::surface::Surface<glutin::surface::WindowSurface>>(); |
| 276 | /// ``` |
| 277 | #[derive (Debug)] |
| 278 | pub enum Surface<T: SurfaceTypeTrait> { |
| 279 | /// The EGL surface. |
| 280 | #[cfg (egl_backend)] |
| 281 | Egl(EglSurface<T>), |
| 282 | |
| 283 | /// The GLX surface. |
| 284 | #[cfg (glx_backend)] |
| 285 | Glx(GlxSurface<T>), |
| 286 | |
| 287 | /// The WGL surface. |
| 288 | #[cfg (wgl_backend)] |
| 289 | Wgl(WglSurface<T>), |
| 290 | |
| 291 | /// The CGL surface. |
| 292 | #[cfg (cgl_backend)] |
| 293 | Cgl(CglSurface<T>), |
| 294 | } |
| 295 | |
| 296 | impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> { |
| 297 | type Context = PossiblyCurrentContext; |
| 298 | type SurfaceType = T; |
| 299 | |
| 300 | fn buffer_age(&self) -> u32 { |
| 301 | gl_api_dispatch!(self; Self(surface) => surface.buffer_age()) |
| 302 | } |
| 303 | |
| 304 | fn width(&self) -> Option<u32> { |
| 305 | gl_api_dispatch!(self; Self(surface) => surface.width()) |
| 306 | } |
| 307 | |
| 308 | fn height(&self) -> Option<u32> { |
| 309 | gl_api_dispatch!(self; Self(surface) => surface.height()) |
| 310 | } |
| 311 | |
| 312 | fn is_single_buffered(&self) -> bool { |
| 313 | gl_api_dispatch!(self; Self(surface) => surface.is_single_buffered()) |
| 314 | } |
| 315 | |
| 316 | fn swap_buffers(&self, context: &Self::Context) -> Result<()> { |
| 317 | match (self, context) { |
| 318 | #[cfg (egl_backend)] |
| 319 | (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => { |
| 320 | surface.swap_buffers(context) |
| 321 | }, |
| 322 | #[cfg (glx_backend)] |
| 323 | (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => { |
| 324 | surface.swap_buffers(context) |
| 325 | }, |
| 326 | #[cfg (cgl_backend)] |
| 327 | (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => { |
| 328 | surface.swap_buffers(context) |
| 329 | }, |
| 330 | #[cfg (wgl_backend)] |
| 331 | (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => { |
| 332 | surface.swap_buffers(context) |
| 333 | }, |
| 334 | _ => unreachable!(), |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | fn set_swap_interval(&self, context: &Self::Context, interval: SwapInterval) -> Result<()> { |
| 339 | match (self, context) { |
| 340 | #[cfg (egl_backend)] |
| 341 | (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => { |
| 342 | surface.set_swap_interval(context, interval) |
| 343 | }, |
| 344 | #[cfg (glx_backend)] |
| 345 | (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => { |
| 346 | surface.set_swap_interval(context, interval) |
| 347 | }, |
| 348 | #[cfg (cgl_backend)] |
| 349 | (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => { |
| 350 | surface.set_swap_interval(context, interval) |
| 351 | }, |
| 352 | #[cfg (wgl_backend)] |
| 353 | (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => { |
| 354 | surface.set_swap_interval(context, interval) |
| 355 | }, |
| 356 | _ => unreachable!(), |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | fn is_current(&self, context: &Self::Context) -> bool { |
| 361 | match (self, context) { |
| 362 | #[cfg (egl_backend)] |
| 363 | (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => { |
| 364 | surface.is_current(context) |
| 365 | }, |
| 366 | #[cfg (glx_backend)] |
| 367 | (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => { |
| 368 | surface.is_current(context) |
| 369 | }, |
| 370 | #[cfg (cgl_backend)] |
| 371 | (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => { |
| 372 | surface.is_current(context) |
| 373 | }, |
| 374 | #[cfg (wgl_backend)] |
| 375 | (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => { |
| 376 | surface.is_current(context) |
| 377 | }, |
| 378 | _ => unreachable!(), |
| 379 | } |
| 380 | } |
| 381 | |
| 382 | fn is_current_draw(&self, context: &Self::Context) -> bool { |
| 383 | match (self, context) { |
| 384 | #[cfg (egl_backend)] |
| 385 | (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => { |
| 386 | surface.is_current_draw(context) |
| 387 | }, |
| 388 | #[cfg (glx_backend)] |
| 389 | (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => { |
| 390 | surface.is_current_draw(context) |
| 391 | }, |
| 392 | #[cfg (cgl_backend)] |
| 393 | (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => { |
| 394 | surface.is_current_draw(context) |
| 395 | }, |
| 396 | #[cfg (wgl_backend)] |
| 397 | (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => { |
| 398 | surface.is_current_draw(context) |
| 399 | }, |
| 400 | _ => unreachable!(), |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | fn is_current_read(&self, context: &Self::Context) -> bool { |
| 405 | match (self, context) { |
| 406 | #[cfg (egl_backend)] |
| 407 | (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => { |
| 408 | surface.is_current_read(context) |
| 409 | }, |
| 410 | #[cfg (glx_backend)] |
| 411 | (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => { |
| 412 | surface.is_current_read(context) |
| 413 | }, |
| 414 | #[cfg (cgl_backend)] |
| 415 | (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => { |
| 416 | surface.is_current_read(context) |
| 417 | }, |
| 418 | #[cfg (wgl_backend)] |
| 419 | (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => { |
| 420 | surface.is_current_read(context) |
| 421 | }, |
| 422 | _ => unreachable!(), |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | fn resize(&self, context: &Self::Context, width: NonZeroU32, height: NonZeroU32) |
| 427 | where |
| 428 | Self::SurfaceType: ResizeableSurface, |
| 429 | { |
| 430 | match (self, context) { |
| 431 | #[cfg (egl_backend)] |
| 432 | (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => { |
| 433 | surface.resize(context, width, height) |
| 434 | }, |
| 435 | #[cfg (glx_backend)] |
| 436 | (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => { |
| 437 | surface.resize(context, width, height) |
| 438 | }, |
| 439 | #[cfg (cgl_backend)] |
| 440 | (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => { |
| 441 | surface.resize(context, width, height) |
| 442 | }, |
| 443 | #[cfg (wgl_backend)] |
| 444 | (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => { |
| 445 | surface.resize(context, width, height) |
| 446 | }, |
| 447 | _ => unreachable!(), |
| 448 | } |
| 449 | } |
| 450 | } |
| 451 | |
| 452 | impl<T: SurfaceTypeTrait> GetGlDisplay for Surface<T> { |
| 453 | type Target = Display; |
| 454 | |
| 455 | fn display(&self) -> Self::Target { |
| 456 | gl_api_dispatch!(self; Self(surface) => surface.display(); as Display) |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | impl<T: SurfaceTypeTrait> AsRawSurface for Surface<T> { |
| 461 | fn raw_surface(&self) -> RawSurface { |
| 462 | gl_api_dispatch!(self; Self(surface) => surface.raw_surface()) |
| 463 | } |
| 464 | } |
| 465 | |
| 466 | impl<T: SurfaceTypeTrait> Sealed for Surface<T> {} |
| 467 | |
| 468 | /// A swap interval. |
| 469 | /// |
| 470 | /// The default swap interval for your [`Surface`] is platform-dependent. For |
| 471 | /// example, on EGL it is `1` by default, but on GLX it is `0` by default. |
| 472 | /// |
| 473 | /// Please note that your application's desired swap interval may be overridden |
| 474 | /// by external, driver-specific configuration, which means that you can't know |
| 475 | /// in advance whether [`crate::surface::GlSurface::swap_buffers`] will block |
| 476 | /// or not. |
| 477 | /// |
| 478 | /// # Platform specific |
| 479 | /// |
| 480 | /// - **Wayland:** when the window is hidden and [`SwapInterval::Wait`] is used |
| 481 | /// [`GlSurface::swap_buffers`] and any functions based on it may block until |
| 482 | /// the window is visible again. Using this variant is not recommended on |
| 483 | /// Wayland and instead the throttling should be performed by [`frame |
| 484 | /// callbacks`]. |
| 485 | /// |
| 486 | /// [`frame callbacks`]: https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_surface-request-frame |
| 487 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
| 488 | pub enum SwapInterval { |
| 489 | /// When this variant is used calling |
| 490 | /// [`crate::surface::GlSurface::swap_buffers()`] will not block. |
| 491 | DontWait, |
| 492 | |
| 493 | /// The swap is synchronized to the `n`'th video frame. This is typically |
| 494 | /// set to `1` to enable vsync and prevent screen tearing. |
| 495 | Wait(NonZeroU32), |
| 496 | } |
| 497 | |
| 498 | /// A platform native pixmap. |
| 499 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
| 500 | pub enum NativePixmap { |
| 501 | /// XID of X11 pixmap. |
| 502 | XlibPixmap(std::os::raw::c_ulong), |
| 503 | |
| 504 | /// XID of X11 pixmap from xcb. |
| 505 | XcbPixmap(u32), |
| 506 | |
| 507 | /// HBITMAP handle for windows bitmap. |
| 508 | WindowsPixmap(isize), |
| 509 | } |
| 510 | |
| 511 | /// Handle to the raw OpenGL surface. |
| 512 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
| 513 | pub enum RawSurface { |
| 514 | /// A pointer to EGLSurface. |
| 515 | #[cfg (egl_backend)] |
| 516 | Egl(*const std::ffi::c_void), |
| 517 | |
| 518 | /// GLXDrawable. |
| 519 | #[cfg (glx_backend)] |
| 520 | Glx(u64), |
| 521 | |
| 522 | /// Either a `HWND` or `HPBUFFEREXT` depending on [`SurfaceType`]. |
| 523 | #[cfg (wgl_backend)] |
| 524 | Wgl(*const std::ffi::c_void), |
| 525 | |
| 526 | /// Pointer to `NSView`. |
| 527 | #[cfg (cgl_backend)] |
| 528 | Cgl(*const std::ffi::c_void), |
| 529 | } |
| 530 | |
| 531 | /// The rect that is being used in various surface operations. |
| 532 | /// |
| 533 | /// The origin is in the bottom left of the surface. |
| 534 | #[repr (C)] |
| 535 | #[derive (Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] |
| 536 | pub struct Rect { |
| 537 | /// `X` of the origin. |
| 538 | pub x: i32, |
| 539 | /// `Y` of the origin. |
| 540 | pub y: i32, |
| 541 | /// Rect width. |
| 542 | pub width: i32, |
| 543 | /// Rect height. |
| 544 | pub height: i32, |
| 545 | } |
| 546 | |
| 547 | impl Rect { |
| 548 | /// Helper to simplify rectangle creation. |
| 549 | pub fn new(x: i32, y: i32, width: i32, height: i32) -> Self { |
| 550 | Self { x, y, width, height } |
| 551 | } |
| 552 | } |
| 553 | |