[go: up one dir, main page]

sdl2/
video.rs

1use libc::{c_char, c_float, c_int, c_uint};
2use std::convert::TryFrom;
3use std::error::Error;
4use std::ffi::{CStr, CString, NulError};
5use std::ops::{Deref, DerefMut};
6use std::rc::Rc;
7use std::{fmt, mem, ptr};
8
9use crate::common::{validate_int, IntegerOrSdlError};
10use crate::pixels::PixelFormatEnum;
11use crate::rect::Rect;
12use crate::render::CanvasBuilder;
13use crate::surface::SurfaceRef;
14use crate::EventPump;
15use crate::VideoSubsystem;
16
17use crate::get_error;
18
19use crate::sys;
20
21pub use crate::sys::{VkInstance, VkSurfaceKHR};
22
23pub struct WindowSurfaceRef<'a>(&'a mut SurfaceRef, &'a Window);
24
25impl<'a> Deref for WindowSurfaceRef<'a> {
26    type Target = SurfaceRef;
27
28    #[inline]
29    fn deref(&self) -> &SurfaceRef {
30        self.0
31    }
32}
33
34impl<'a> DerefMut for WindowSurfaceRef<'a> {
35    #[inline]
36    fn deref_mut(&mut self) -> &mut SurfaceRef {
37        self.0
38    }
39}
40
41impl<'a> WindowSurfaceRef<'a> {
42    /// Updates the change made to the inner Surface to the Window it was created from.
43    ///
44    /// This would effectively be the theoretical equivalent of `present` from a Canvas.
45    #[doc(alias = "SDL_UpdateWindowSurface")]
46    pub fn update_window(&self) -> Result<(), String> {
47        unsafe {
48            if sys::SDL_UpdateWindowSurface(self.1.context.raw) == 0 {
49                Ok(())
50            } else {
51                Err(get_error())
52            }
53        }
54    }
55
56    /// Same as `update_window`, but only update the parts included in `rects` to the Window it was
57    /// created from.
58    #[doc(alias = "SDL_UpdateWindowSurfaceRects")]
59    pub fn update_window_rects(&self, rects: &[Rect]) -> Result<(), String> {
60        unsafe {
61            if sys::SDL_UpdateWindowSurfaceRects(
62                self.1.context.raw,
63                Rect::raw_slice(rects),
64                rects.len() as c_int,
65            ) == 0
66            {
67                Ok(())
68            } else {
69                Err(get_error())
70            }
71        }
72    }
73
74    /// Gives up this WindowSurfaceRef, allowing to use the window freely again. Before being
75    /// destroyed, calls `update_window` one last time.
76    ///
77    /// If you don't want to `update_window` one last time, simply Drop this struct. However
78    /// beware, since the Surface will still be in the state you left it the next time you will
79    /// call `window.surface()` again.
80    pub fn finish(self) -> Result<(), String> {
81        self.update_window()
82    }
83}
84
85#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
86pub enum GLProfile {
87    /// OpenGL core profile - deprecated functions are disabled
88    Core,
89    /// OpenGL compatibility profile - deprecated functions are allowed
90    Compatibility,
91    /// OpenGL ES profile - only a subset of the base OpenGL functionality is available
92    GLES,
93    /// Unknown profile - SDL will tend to return 0 if you ask when no particular profile
94    /// has been defined or requested.
95    Unknown(i32),
96}
97
98trait GLAttrTypeUtil {
99    fn to_gl_value(self) -> i32;
100    fn from_gl_value(value: i32) -> Self;
101}
102
103impl GLAttrTypeUtil for u8 {
104    fn to_gl_value(self) -> i32 {
105        self as i32
106    }
107    fn from_gl_value(value: i32) -> u8 {
108        value as u8
109    }
110}
111
112impl GLAttrTypeUtil for bool {
113    fn to_gl_value(self) -> i32 {
114        if self {
115            1
116        } else {
117            0
118        }
119    }
120    fn from_gl_value(value: i32) -> bool {
121        value != 0
122    }
123}
124
125impl GLAttrTypeUtil for GLProfile {
126    fn to_gl_value(self) -> i32 {
127        use self::GLProfile::*;
128
129        match self {
130            Unknown(i) => i,
131            Core => 1,
132            Compatibility => 2,
133            GLES => 4,
134        }
135    }
136    fn from_gl_value(value: i32) -> GLProfile {
137        use self::GLProfile::*;
138
139        match value {
140            1 => Core,
141            2 => Compatibility,
142            4 => GLES,
143            i => Unknown(i),
144        }
145    }
146}
147
148macro_rules! attrs {
149    (
150        $(($attr_name:ident, $set_property:ident, $get_property:ident, $t:ty, $doc:expr)),*
151    ) => (
152
153        $(
154        #[doc = "**Sets** the attribute: "]
155        #[doc = $doc]
156        #[inline]
157        pub fn $set_property(&self, value: $t) {
158            gl_set_attribute!($attr_name, value.to_gl_value());
159        }
160
161        #[doc = "**Gets** the attribute: "]
162        #[doc = $doc]
163        #[inline]
164        pub fn $get_property(&self) -> $t {
165            let value = gl_get_attribute!($attr_name);
166            GLAttrTypeUtil::from_gl_value(value)
167        }
168        )*
169    );
170}
171
172/// OpenGL context getters and setters
173///
174/// # Example
175/// ```no_run
176/// use sdl2::video::GLProfile;
177///
178/// let sdl_context = sdl2::init().unwrap();
179/// let video_subsystem = sdl_context.video().unwrap();
180/// let gl_attr = video_subsystem.gl_attr();
181///
182/// // Don't use deprecated OpenGL functions
183/// gl_attr.set_context_profile(GLProfile::Core);
184///
185/// // Set the context into debug mode
186/// gl_attr.set_context_flags().debug().set();
187///
188/// // Set the OpenGL context version (OpenGL 3.2)
189/// gl_attr.set_context_version(3, 2);
190///
191/// // Enable anti-aliasing
192/// gl_attr.set_multisample_buffers(1);
193/// gl_attr.set_multisample_samples(4);
194///
195/// let window = video_subsystem.window("rust-sdl2 demo: Video", 800, 600).opengl().build().unwrap();
196///
197/// // Yes, we're still using the Core profile
198/// assert_eq!(gl_attr.context_profile(), GLProfile::Core);
199/// // ... and we're still using OpenGL 3.2
200/// assert_eq!(gl_attr.context_version(), (3, 2));
201/// ```
202pub mod gl_attr {
203    use super::{GLAttrTypeUtil, GLProfile};
204    use crate::get_error;
205    use crate::sys;
206    use std::marker::PhantomData;
207
208    /// OpenGL context getters and setters. Obtain with `VideoSubsystem::gl_attr()`.
209    pub struct GLAttr<'a> {
210        _marker: PhantomData<&'a crate::VideoSubsystem>,
211    }
212
213    impl crate::VideoSubsystem {
214        /// Obtains access to the OpenGL window attributes.
215        pub fn gl_attr(&self) -> GLAttr {
216            GLAttr {
217                _marker: PhantomData,
218            }
219        }
220    }
221
222    macro_rules! gl_set_attribute {
223        ($attr:ident, $value:expr) => {{
224            let result = unsafe { sys::SDL_GL_SetAttribute(sys::SDL_GLattr::$attr, $value) };
225
226            if result != 0 {
227                // Panic and print the attribute that failed.
228                panic!(
229                    "couldn't set attribute {}: {}",
230                    stringify!($attr),
231                    get_error()
232                );
233            }
234        }};
235    }
236
237    macro_rules! gl_get_attribute {
238        ($attr:ident) => {{
239            let mut value = 0;
240            let result = unsafe { sys::SDL_GL_GetAttribute(sys::SDL_GLattr::$attr, &mut value) };
241            if result != 0 {
242                // Panic and print the attribute that failed.
243                panic!(
244                    "couldn't get attribute {}: {}",
245                    stringify!($attr),
246                    get_error()
247                );
248            }
249            value
250        }};
251    }
252
253    impl<'a> GLAttr<'a> {
254        // Note: Wish I could avoid the redundancy of set_property and property (without namespacing into new modules),
255        // but Rust's `concat_idents!` macro isn't stable.
256        attrs! {
257            (SDL_GL_RED_SIZE, set_red_size, red_size, u8,
258                "the minimum number of bits for the red channel of the color buffer; defaults to 3"),
259
260            (SDL_GL_GREEN_SIZE, set_green_size, green_size, u8,
261                "the minimum number of bits for the green channel of the color buffer; defaults to 3"),
262
263            (SDL_GL_BLUE_SIZE, set_blue_size, blue_size, u8,
264                "the minimum number of bits for the blue channel of the color buffer; defaults to 2"),
265
266            (SDL_GL_ALPHA_SIZE, set_alpha_size, alpha_size, u8,
267                "the minimum number of bits for the alpha channel of the color buffer; defaults to 0"),
268
269            (SDL_GL_BUFFER_SIZE, set_buffer_size, buffer_size, u8,
270                "the minimum number of bits for frame buffer size; defaults to 0"),
271
272            (SDL_GL_DOUBLEBUFFER, set_double_buffer, double_buffer, bool,
273                "whether the output is single or double buffered; defaults to double buffering on"),
274
275            (SDL_GL_DEPTH_SIZE, set_depth_size, depth_size, u8,
276                "the minimum number of bits in the depth buffer; defaults to 16"),
277
278            (SDL_GL_STENCIL_SIZE, set_stencil_size, stencil_size, u8,
279                "the minimum number of bits in the stencil buffer; defaults to 0"),
280
281            (SDL_GL_ACCUM_RED_SIZE, set_accum_red_size, accum_red_size, u8,
282                "the minimum number of bits for the red channel of the accumulation buffer; defaults to 0"),
283
284            (SDL_GL_ACCUM_GREEN_SIZE, set_accum_green_size, accum_green_size, u8,
285                "the minimum number of bits for the green channel of the accumulation buffer; defaults to 0"),
286
287            (SDL_GL_ACCUM_BLUE_SIZE, set_accum_blue_size, accum_blue_size, u8,
288                "the minimum number of bits for the blue channel of the accumulation buffer; defaults to 0"),
289
290            (SDL_GL_ACCUM_ALPHA_SIZE, set_accum_alpha_size, accum_alpha_size, u8,
291                "the minimum number of bits for the alpha channel of the accumulation buffer; defaults to 0"),
292
293            (SDL_GL_STEREO, set_stereo, stereo, bool,
294                "whether the output is stereo 3D; defaults to off"),
295
296            (SDL_GL_MULTISAMPLEBUFFERS, set_multisample_buffers, multisample_buffers, u8,
297                "the number of buffers used for multisample anti-aliasing; defaults to 0"),
298
299            (SDL_GL_MULTISAMPLESAMPLES, set_multisample_samples, multisample_samples, u8,
300                "the number of samples used around the current pixel used for multisample anti-aliasing; defaults to 0"),
301
302            (SDL_GL_ACCELERATED_VISUAL, set_accelerated_visual, accelerated_visual, bool,
303                "whether to require hardware acceleration; false to force software rendering; defaults to allow either"),
304
305            (SDL_GL_CONTEXT_MAJOR_VERSION, set_context_major_version, context_major_version, u8,
306                "OpenGL context major version"),
307
308            (SDL_GL_CONTEXT_MINOR_VERSION, set_context_minor_version, context_minor_version, u8,
309                "OpenGL context minor version"),
310
311            (SDL_GL_CONTEXT_PROFILE_MASK, set_context_profile, context_profile, GLProfile,
312                "type of GL context (Core, Compatibility, ES)"),
313
314            (SDL_GL_SHARE_WITH_CURRENT_CONTEXT, set_share_with_current_context, share_with_current_context, bool,
315                "OpenGL context sharing; defaults to false"),
316
317            (SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, set_framebuffer_srgb_compatible, framebuffer_srgb_compatible, bool,
318                "requests sRGB capable visual; defaults to false (>= SDL 2.0.1)"),
319
320            (SDL_GL_CONTEXT_NO_ERROR, set_context_no_error, context_no_error, bool,
321                "disables OpenGL error checking; defaults to false (>= SDL 2.0.6)")
322        }
323
324        /// **Sets** the OpenGL context major and minor versions.
325        #[inline]
326        pub fn set_context_version(&self, major: u8, minor: u8) {
327            self.set_context_major_version(major);
328            self.set_context_minor_version(minor);
329        }
330
331        /// **Gets** the OpenGL context major and minor versions as a tuple.
332        #[inline]
333        pub fn context_version(&self) -> (u8, u8) {
334            (self.context_major_version(), self.context_minor_version())
335        }
336    }
337
338    /// The type that allows you to build a OpenGL context configuration.
339    pub struct ContextFlagsBuilder<'a> {
340        flags: i32,
341        _marker: PhantomData<&'a crate::VideoSubsystem>,
342    }
343
344    impl<'a> ContextFlagsBuilder<'a> {
345        /// Finishes the builder and applies the GL context flags to the GL context.
346        #[inline]
347        pub fn set(&self) {
348            gl_set_attribute!(SDL_GL_CONTEXT_FLAGS, self.flags);
349        }
350
351        /// Sets the context into "debug" mode.
352        #[inline]
353        pub fn debug(&mut self) -> &mut ContextFlagsBuilder<'a> {
354            self.flags |= 0x0001;
355            self
356        }
357
358        /// Sets the context into "forward compatible" mode.
359        #[inline]
360        pub fn forward_compatible(&mut self) -> &mut ContextFlagsBuilder<'a> {
361            self.flags |= 0x0002;
362            self
363        }
364
365        #[inline]
366        pub fn robust_access(&mut self) -> &mut ContextFlagsBuilder<'a> {
367            self.flags |= 0x0004;
368            self
369        }
370
371        #[inline]
372        pub fn reset_isolation(&mut self) -> &mut ContextFlagsBuilder<'a> {
373            self.flags |= 0x0008;
374            self
375        }
376    }
377
378    pub struct ContextFlags {
379        flags: i32,
380    }
381
382    impl ContextFlags {
383        #[inline]
384        pub const fn has_debug(&self) -> bool {
385            self.flags & 0x0001 != 0
386        }
387
388        #[inline]
389        pub const fn has_forward_compatible(&self) -> bool {
390            self.flags & 0x0002 != 0
391        }
392
393        #[inline]
394        pub const fn has_robust_access(&self) -> bool {
395            self.flags & 0x0004 != 0
396        }
397
398        #[inline]
399        pub const fn has_reset_isolation(&self) -> bool {
400            self.flags & 0x0008 != 0
401        }
402    }
403
404    impl<'a> GLAttr<'a> {
405        /// **Sets** any combination of OpenGL context configuration flags.
406        ///
407        /// Note that calling this will reset any existing context flags.
408        ///
409        /// # Example
410        /// ```no_run
411        /// let sdl_context = sdl2::init().unwrap();
412        /// let video_subsystem = sdl_context.video().unwrap();
413        /// let gl_attr = video_subsystem.gl_attr();
414        ///
415        /// // Sets the GL context into debug mode.
416        /// gl_attr.set_context_flags().debug().set();
417        /// ```
418        pub fn set_context_flags(&self) -> ContextFlagsBuilder {
419            ContextFlagsBuilder {
420                flags: 0,
421                _marker: PhantomData,
422            }
423        }
424
425        /// **Gets** the applied OpenGL context configuration flags.
426        ///
427        /// # Example
428        /// ```no_run
429        /// let sdl_context = sdl2::init().unwrap();
430        /// let video_subsystem = sdl_context.video().unwrap();
431        /// let gl_attr = video_subsystem.gl_attr();
432        ///
433        /// // Is the GL context in debug mode?
434        /// if gl_attr.context_flags().has_debug() {
435        ///     println!("Debug mode");
436        /// }
437        /// ```
438        pub fn context_flags(&self) -> ContextFlags {
439            let flags = gl_get_attribute!(SDL_GL_CONTEXT_FLAGS);
440
441            ContextFlags { flags }
442        }
443    }
444}
445
446#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
447pub struct DisplayMode {
448    pub format: PixelFormatEnum,
449    pub w: i32,
450    pub h: i32,
451    pub refresh_rate: i32,
452}
453
454impl DisplayMode {
455    pub fn new(format: PixelFormatEnum, w: i32, h: i32, refresh_rate: i32) -> DisplayMode {
456        DisplayMode {
457            format,
458            w,
459            h,
460            refresh_rate,
461        }
462    }
463
464    pub fn from_ll(raw: &sys::SDL_DisplayMode) -> DisplayMode {
465        DisplayMode::new(
466            PixelFormatEnum::try_from(raw.format).unwrap_or(PixelFormatEnum::Unknown),
467            raw.w,
468            raw.h,
469            raw.refresh_rate,
470        )
471    }
472
473    pub fn to_ll(&self) -> sys::SDL_DisplayMode {
474        sys::SDL_DisplayMode {
475            format: self.format as u32,
476            w: self.w as c_int,
477            h: self.h as c_int,
478            refresh_rate: self.refresh_rate as c_int,
479            driverdata: ptr::null_mut(),
480        }
481    }
482}
483
484#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
485pub enum FullscreenType {
486    Off = 0,
487    True = 0x00_00_00_01,
488    Desktop = 0x00_00_10_01,
489}
490
491impl FullscreenType {
492    pub fn from_window_flags(window_flags: u32) -> FullscreenType {
493        if window_flags & FullscreenType::Desktop as u32 == FullscreenType::Desktop as u32 {
494            FullscreenType::Desktop
495        } else if window_flags & FullscreenType::True as u32 == FullscreenType::True as u32 {
496            FullscreenType::True
497        } else {
498            FullscreenType::Off
499        }
500    }
501}
502
503#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
504pub enum WindowPos {
505    Undefined,
506    Centered,
507    Positioned(i32),
508}
509
510impl From<i32> for WindowPos {
511    fn from(pos: i32) -> Self {
512        WindowPos::Positioned(pos)
513    }
514}
515
516fn to_ll_windowpos(pos: WindowPos) -> c_int {
517    match pos {
518        WindowPos::Undefined => sys::SDL_WINDOWPOS_UNDEFINED_MASK as c_int,
519        WindowPos::Centered => sys::SDL_WINDOWPOS_CENTERED_MASK as c_int,
520        WindowPos::Positioned(x) => x as c_int,
521    }
522}
523
524pub struct GLContext {
525    raw: sys::SDL_GLContext,
526}
527
528impl Drop for GLContext {
529    #[doc(alias = "SDL_GL_DeleteContext")]
530    fn drop(&mut self) {
531        unsafe { sys::SDL_GL_DeleteContext(self.raw) }
532    }
533}
534
535impl GLContext {
536    /// Returns true if the OpenGL context is the current one in the thread.
537    #[doc(alias = "SDL_GL_GetCurrentContext")]
538    pub fn is_current(&self) -> bool {
539        let current_raw = unsafe { sys::SDL_GL_GetCurrentContext() };
540        self.raw == current_raw
541    }
542}
543
544/// Holds a `SDL_Window`
545///
546/// When the `WindowContext` is dropped, it destroys the `SDL_Window`
547pub struct WindowContext {
548    subsystem: VideoSubsystem,
549    raw: *mut sys::SDL_Window,
550    #[allow(dead_code)]
551    pub(crate) metal_view: sys::SDL_MetalView,
552}
553
554impl Drop for WindowContext {
555    #[inline]
556    #[doc(alias = "SDL_DestroyWindow")]
557    fn drop(&mut self) {
558        unsafe {
559            #[cfg(target_os = "macos")]
560            if !self.metal_view.is_null() {
561                sys::SDL_Metal_DestroyView(self.metal_view);
562            }
563            sys::SDL_DestroyWindow(self.raw)
564        };
565    }
566}
567
568impl WindowContext {
569    #[inline]
570    /// # Safety
571    ///
572    /// Unsound if the `*mut SDL_Window` is used after the `WindowContext` is dropped
573    pub unsafe fn from_ll(
574        subsystem: VideoSubsystem,
575        raw: *mut sys::SDL_Window,
576        metal_view: sys::SDL_MetalView,
577    ) -> WindowContext {
578        WindowContext {
579            subsystem,
580            raw,
581            metal_view,
582        }
583    }
584}
585
586/// Represents a setting for vsync/swap interval.
587#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
588#[repr(i32)]
589pub enum SwapInterval {
590    Immediate = 0,
591    VSync = 1,
592    LateSwapTearing = -1,
593}
594
595impl From<i32> for SwapInterval {
596    fn from(i: i32) -> Self {
597        match i {
598            -1 => SwapInterval::LateSwapTearing,
599            0 => SwapInterval::Immediate,
600            1 => SwapInterval::VSync,
601            other => panic!(
602                "Invalid value for SwapInterval: {}; valid values are -1, 0, 1",
603                other
604            ),
605        }
606    }
607}
608
609/// Represents orientation of a display.
610#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
611#[repr(i32)]
612pub enum Orientation {
613    /// The display orientation can’t be determined
614    Unknown = sys::SDL_DisplayOrientation::SDL_ORIENTATION_UNKNOWN as i32,
615    /// The display is in landscape mode, with the right side up, relative to portrait mode
616    Landscape = sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE as i32,
617    /// The display is in landscape mode, with the left side up, relative to portrait mode
618    LandscapeFlipped = sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE_FLIPPED as i32,
619    /// The display is in portrait mode
620    Portrait = sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT as i32,
621    /// The display is in portrait mode, upside down
622    PortraitFlipped = sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT_FLIPPED as i32,
623}
624
625impl Orientation {
626    pub fn from_ll(orientation: sys::SDL_DisplayOrientation) -> Orientation {
627        match orientation {
628            sys::SDL_DisplayOrientation::SDL_ORIENTATION_UNKNOWN => Orientation::Unknown,
629            sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE => Orientation::Landscape,
630            sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE_FLIPPED => {
631                Orientation::LandscapeFlipped
632            }
633            sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT => Orientation::Portrait,
634            sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT_FLIPPED => {
635                Orientation::PortraitFlipped
636            }
637        }
638    }
639
640    pub fn to_ll(self) -> sys::SDL_DisplayOrientation {
641        match self {
642            Orientation::Unknown => sys::SDL_DisplayOrientation::SDL_ORIENTATION_UNKNOWN,
643            Orientation::Landscape => sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE,
644            Orientation::LandscapeFlipped => {
645                sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE_FLIPPED
646            }
647            Orientation::Portrait => sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT,
648            Orientation::PortraitFlipped => {
649                sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT_FLIPPED
650            }
651        }
652    }
653}
654
655/// Represents a setting for a window flash operation.
656#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
657#[repr(i32)]
658pub enum FlashOperation {
659    /// Cancel any window flash state
660    Cancel = sys::SDL_FlashOperation::SDL_FLASH_CANCEL as i32,
661    /// Flash the window briefly to get attention
662    Briefly = sys::SDL_FlashOperation::SDL_FLASH_BRIEFLY as i32,
663    /// Flash the window until it gets focus
664    UntilFocused = sys::SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED as i32,
665}
666
667impl FlashOperation {
668    pub fn from_ll(flash_operation: sys::SDL_FlashOperation) -> FlashOperation {
669        match flash_operation {
670            sys::SDL_FlashOperation::SDL_FLASH_CANCEL => FlashOperation::Cancel,
671            sys::SDL_FlashOperation::SDL_FLASH_BRIEFLY => FlashOperation::Briefly,
672            sys::SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED => FlashOperation::UntilFocused,
673        }
674    }
675
676    pub fn to_ll(self) -> sys::SDL_FlashOperation {
677        match self {
678            FlashOperation::Cancel => sys::SDL_FlashOperation::SDL_FLASH_CANCEL,
679            FlashOperation::Briefly => sys::SDL_FlashOperation::SDL_FLASH_BRIEFLY,
680            FlashOperation::UntilFocused => sys::SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED,
681        }
682    }
683}
684
685/// Represents the "shell" of a `Window`.
686///
687/// You can set get and set many of the `SDL_Window` properties (i.e., border, size, `PixelFormat`, etc)
688///
689/// However, you cannot directly access the pixels of the `Window`.
690/// It needs to be converted to a `Canvas` to access the rendering functions.
691///
692/// Note: If a `Window` goes out of scope but it cloned its context,
693/// then the `SDL_Window` will not be destroyed until there are no more references to the `WindowContext`.
694/// This may happen when a `TextureCreator<Window>` outlives the `Canvas<Window>`
695#[derive(Clone)]
696pub struct Window {
697    context: Rc<WindowContext>,
698}
699
700impl From<WindowContext> for Window {
701    fn from(context: WindowContext) -> Window {
702        Window {
703            context: Rc::new(context),
704        }
705    }
706}
707
708impl_raw_accessors!((GLContext, sys::SDL_GLContext));
709
710impl VideoSubsystem {
711    /// Initializes a new `WindowBuilder`; a convenience method that calls `WindowBuilder::new()`.
712    pub fn window(&self, title: &str, width: u32, height: u32) -> WindowBuilder {
713        WindowBuilder::new(self, title, width, height)
714    }
715
716    /// Get the name of the currently initialized video driver.
717    #[doc(alias = "SDL_GetCurrentVideoDriver")]
718    pub fn current_video_driver(&self) -> &'static str {
719        use std::str;
720
721        unsafe {
722            let buf = sys::SDL_GetCurrentVideoDriver();
723            assert!(!buf.is_null());
724
725            str::from_utf8(CStr::from_ptr(buf as *const _).to_bytes()).unwrap()
726        }
727    }
728
729    /// Get the number of available video displays.
730    #[doc(alias = "SDL_GetNumVideoDisplays")]
731    pub fn num_video_displays(&self) -> Result<i32, String> {
732        let result = unsafe { sys::SDL_GetNumVideoDisplays() };
733        if result < 0 {
734            Err(get_error())
735        } else {
736            Ok(result as i32)
737        }
738    }
739
740    /// Get the name of the display at the index `display_name`.
741    ///
742    /// Will return an error if the index is out of bounds or if SDL experienced a failure; inspect
743    /// the returned string for further info.
744    #[doc(alias = "SDL_GetDisplayName")]
745    pub fn display_name(&self, display_index: i32) -> Result<String, String> {
746        unsafe {
747            let display = sys::SDL_GetDisplayName(display_index as c_int);
748            if display.is_null() {
749                Err(get_error())
750            } else {
751                Ok(CStr::from_ptr(display as *const _)
752                    .to_str()
753                    .unwrap()
754                    .to_owned())
755            }
756        }
757    }
758
759    /// Get the desktop area represented by a display.
760    ///
761    /// The primary display (`display_index = 0`) is always located at 0,0.
762    #[doc(alias = "SDL_GetDisplayBounds")]
763    pub fn display_bounds(&self, display_index: i32) -> Result<Rect, String> {
764        let mut out = mem::MaybeUninit::uninit();
765        let result =
766            unsafe { sys::SDL_GetDisplayBounds(display_index as c_int, out.as_mut_ptr()) == 0 };
767
768        if result {
769            let out = unsafe { out.assume_init() };
770            Ok(Rect::from_ll(out))
771        } else {
772            Err(get_error())
773        }
774    }
775
776    /// Get the usable desktop area represented by a display.
777    ///
778    /// The primary display (`display_index = 0`) is always located at 0,0.
779    ///
780    /// This is the same area as `display_bounds` reports,
781    /// but with portions reserved by the system removed.
782    /// For example, on Apple's macOS, this subtracts the area occupied by the menu bar and dock.
783    /// Setting a window to be fullscreen generally bypasses these unusable areas,
784    /// so these are good guidelines for the maximum space available to a non-fullscreen window.
785    #[doc(alias = "SDL_GetDisplayUsableBounds")]
786    pub fn display_usable_bounds(&self, display_index: i32) -> Result<Rect, String> {
787        let mut out = mem::MaybeUninit::uninit();
788        let result =
789            unsafe { sys::SDL_GetDisplayUsableBounds(display_index as c_int, out.as_mut_ptr()) };
790        if result == 0 {
791            let out = unsafe { out.assume_init() };
792            Ok(Rect::from_ll(out))
793        } else {
794            Err(get_error())
795        }
796    }
797
798    /// Get the number of available display modes.
799    #[doc(alias = "SDL_GetNumDisplayModes")]
800    pub fn num_display_modes(&self, display_index: i32) -> Result<i32, String> {
801        let result = unsafe { sys::SDL_GetNumDisplayModes(display_index as c_int) };
802        if result < 0 {
803            Err(get_error())
804        } else {
805            Ok(result as i32)
806        }
807    }
808
809    /// Get information about a specific display mode.
810    ///
811    /// The display modes are sorted in this priority:
812    /// - width -> largest to smallest
813    /// - height -> largest to smallest
814    /// - bits per pixel -> more colors to fewer colors
815    /// - packed pixel layout -> largest to smallest
816    /// - refresh rate -> highest to lowest
817    #[doc(alias = "SDL_GetDisplayMode")]
818    pub fn display_mode(&self, display_index: i32, mode_index: i32) -> Result<DisplayMode, String> {
819        let mut dm = mem::MaybeUninit::uninit();
820        let result = unsafe {
821            sys::SDL_GetDisplayMode(display_index as c_int, mode_index as c_int, dm.as_mut_ptr())
822                == 0
823        };
824
825        if result {
826            let dm = unsafe { dm.assume_init() };
827            Ok(DisplayMode::from_ll(&dm))
828        } else {
829            Err(get_error())
830        }
831    }
832
833    /// Get information about the desktop's display mode.
834    ///
835    /// There's a difference between this function and `current_display_mode`
836    /// when SDL runs fullscreen and has changed the resolution.
837    /// In that case this function will return the previous  native display mode,
838    /// and not the current display mode.
839    #[doc(alias = "SDL_GetDesktopDisplayMode")]
840    pub fn desktop_display_mode(&self, display_index: i32) -> Result<DisplayMode, String> {
841        let mut dm = mem::MaybeUninit::uninit();
842        let result =
843            unsafe { sys::SDL_GetDesktopDisplayMode(display_index as c_int, dm.as_mut_ptr()) == 0 };
844
845        if result {
846            let dm = unsafe { dm.assume_init() };
847            Ok(DisplayMode::from_ll(&dm))
848        } else {
849            Err(get_error())
850        }
851    }
852
853    /// Get information about the current display mode.
854    ///
855    /// There's a difference between this function and `desktop_display_mode`
856    /// when SDL runs fullscreen and has changed the resolution.
857    /// In that case this function will return the current display mode,
858    /// and not the previous native display mode.
859    #[doc(alias = "SDL_GetCurrentDisplayMode")]
860    pub fn current_display_mode(&self, display_index: i32) -> Result<DisplayMode, String> {
861        let mut dm = mem::MaybeUninit::uninit();
862        let result =
863            unsafe { sys::SDL_GetCurrentDisplayMode(display_index as c_int, dm.as_mut_ptr()) == 0 };
864
865        if result {
866            let dm = unsafe { dm.assume_init() };
867            Ok(DisplayMode::from_ll(&dm))
868        } else {
869            Err(get_error())
870        }
871    }
872
873    /// Get the closest match to the requested display mode.
874    ///
875    /// The available display modes are scanned and the closest mode
876    /// matching the requested mode is returned.
877    /// The mode format and refresh rate default to the desktop mode if they are set to 0.
878    ///
879    /// The modes are scanned with size being first priority, format being second priority,
880    /// and finally checking the refresh rate.
881    /// If all the available modes are too small, then error is returned.
882    #[doc(alias = "SDL_GetClosestDisplayMode")]
883    pub fn closest_display_mode(
884        &self,
885        display_index: i32,
886        mode: &DisplayMode,
887    ) -> Result<DisplayMode, String> {
888        let input = mode.to_ll();
889        let mut dm = mem::MaybeUninit::uninit();
890
891        let result = unsafe {
892            sys::SDL_GetClosestDisplayMode(display_index as c_int, &input, dm.as_mut_ptr())
893        };
894
895        if result.is_null() {
896            Err(get_error())
897        } else {
898            let dm = unsafe { dm.assume_init() };
899            Ok(DisplayMode::from_ll(&dm))
900        }
901    }
902
903    /// Return a triplet `(ddpi, hdpi, vdpi)` containing the diagonal, horizontal and vertical
904    /// dots/pixels-per-inch of a display
905    #[doc(alias = "SDL_GetDisplayDPI")]
906    pub fn display_dpi(&self, display_index: i32) -> Result<(f32, f32, f32), String> {
907        let mut ddpi = 0.0;
908        let mut hdpi = 0.0;
909        let mut vdpi = 0.0;
910        let result = unsafe {
911            sys::SDL_GetDisplayDPI(display_index as c_int, &mut ddpi, &mut hdpi, &mut vdpi)
912        };
913        if result < 0 {
914            Err(get_error())
915        } else {
916            Ok((ddpi, hdpi, vdpi))
917        }
918    }
919
920    /// Return orientation of a display or Unknown if orientation could not be determined.
921    #[doc(alias = "SDL_GetDisplayOrientation")]
922    pub fn display_orientation(&self, display_index: i32) -> Orientation {
923        Orientation::from_ll(unsafe { sys::SDL_GetDisplayOrientation(display_index as c_int) })
924    }
925
926    /// Check whether the screensaver is currently enabled.
927    #[doc(alias = "SDL_IsScreenSaverEnabled")]
928    pub fn is_screen_saver_enabled(&self) -> bool {
929        unsafe { sys::SDL_IsScreenSaverEnabled() == sys::SDL_bool::SDL_TRUE }
930    }
931
932    /// Allow the screen to be blanked by a screen saver.
933    #[doc(alias = "SDL_EnableScreenSaver")]
934    pub fn enable_screen_saver(&self) {
935        unsafe { sys::SDL_EnableScreenSaver() }
936    }
937
938    /// Prevent the screen from being blanked by a screen saver.
939    #[doc(alias = "SDL_DisableScreenSaver")]
940    pub fn disable_screen_saver(&self) {
941        unsafe { sys::SDL_DisableScreenSaver() }
942    }
943
944    /// Loads the default OpenGL library.
945    ///
946    /// This should be done after initializing the video driver, but before creating any OpenGL windows.
947    /// If no OpenGL library is loaded, the default library will be loaded upon creation of the first OpenGL window.
948    ///
949    /// If a different library is already loaded, this function will return an error.
950    #[doc(alias = "SDL_GL_LoadLibrary")]
951    pub fn gl_load_library_default(&self) -> Result<(), String> {
952        unsafe {
953            if sys::SDL_GL_LoadLibrary(ptr::null()) == 0 {
954                Ok(())
955            } else {
956                Err(get_error())
957            }
958        }
959    }
960
961    /// Loads the OpenGL library using a platform-dependent OpenGL library name (usually a file path).
962    ///
963    /// This should be done after initializing the video driver, but before creating any OpenGL windows.
964    /// If no OpenGL library is loaded, the default library will be loaded upon creation of the first OpenGL window.
965    ///
966    /// If a different library is already loaded, this function will return an error.
967    #[doc(alias = "SDL_GL_LoadLibrary")]
968    pub fn gl_load_library<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
969        unsafe {
970            let path = CString::new(path.as_ref().to_str().unwrap()).unwrap();
971            if sys::SDL_GL_LoadLibrary(path.as_ptr() as *const c_char) == 0 {
972                Ok(())
973            } else {
974                Err(get_error())
975            }
976        }
977    }
978
979    /// Unloads the current OpenGL library.
980    ///
981    /// To completely unload the library, this should be called for every successful load of the
982    /// OpenGL library.
983    #[doc(alias = "SDL_GL_UnloadLibrary")]
984    pub fn gl_unload_library(&self) {
985        unsafe {
986            sys::SDL_GL_UnloadLibrary();
987        }
988    }
989
990    /// Gets the pointer to the named OpenGL function.
991    ///
992    /// This is useful for OpenGL wrappers such as [`gl-rs`](https://github.com/bjz/gl-rs).
993    #[doc(alias = "SDL_GL_GetProcAddress")]
994    pub fn gl_get_proc_address(&self, procname: &str) -> *const () {
995        match CString::new(procname) {
996            Ok(procname) => unsafe {
997                sys::SDL_GL_GetProcAddress(procname.as_ptr() as *const c_char) as *const ()
998            },
999            // string contains a nul byte - it won't match anything.
1000            Err(_) => ptr::null(),
1001        }
1002    }
1003
1004    /// Check if an OpenGL extension is supported for the current context.
1005    ///
1006    /// This function operates on the current GL context;
1007    /// you must have created a context, and it must be current before calling this function.
1008    /// Do not assume that all contexts you create will have the same set of extensions available,
1009    /// or that recreating an existing context will offer the same extensions again.
1010    /// While it's probably not a massive overhead, this function is not an O(1) operation.
1011    /// Check the extensions you care about after creating the GL context and save that information
1012    /// somewhere instead of calling the function every time you need to know.
1013    #[doc(alias = "SDL_GL_ExtensionSupported")]
1014    pub fn gl_extension_supported(&self, extension: &str) -> bool {
1015        match CString::new(extension) {
1016            Ok(extension) => unsafe {
1017                sys::SDL_GL_ExtensionSupported(extension.as_ptr() as *const c_char)
1018                    != sys::SDL_bool::SDL_FALSE
1019            },
1020            // string contains a nul byte - it won't match anything.
1021            Err(_) => false,
1022        }
1023    }
1024
1025    /// Get the currently active OpenGL window.
1026    #[doc(alias = "SDL_GL_GetCurrentWindow")]
1027    pub fn gl_get_current_window_id(&self) -> Result<u32, String> {
1028        let raw = unsafe { sys::SDL_GL_GetCurrentWindow() };
1029        if raw.is_null() {
1030            Err(get_error())
1031        } else {
1032            let id = unsafe { sys::SDL_GetWindowID(raw) };
1033            Ok(id)
1034        }
1035    }
1036
1037    /// Releases the thread's current OpenGL context, i.e. sets the current OpenGL context to nothing.
1038    #[doc(alias = "SDL_GL_MakeCurrent")]
1039    pub fn gl_release_current_context(&self) -> Result<(), String> {
1040        let result = unsafe { sys::SDL_GL_MakeCurrent(ptr::null_mut(), ptr::null_mut()) };
1041
1042        if result == 0 {
1043            Ok(())
1044        } else {
1045            Err(get_error())
1046        }
1047    }
1048
1049    /// Set the swap interval for the current OpenGL context.
1050    #[doc(alias = "SDL_GL_SetSwapInterval")]
1051    pub fn gl_set_swap_interval<S: Into<SwapInterval>>(&self, interval: S) -> Result<(), String> {
1052        let result = unsafe { sys::SDL_GL_SetSwapInterval(interval.into() as c_int) };
1053        if result == 0 {
1054            Ok(())
1055        } else {
1056            Err(get_error())
1057        }
1058    }
1059
1060    #[doc(alias = "SDL_GL_GetSwapInterval")]
1061    pub fn gl_get_swap_interval(&self) -> SwapInterval {
1062        unsafe {
1063            let interval = sys::SDL_GL_GetSwapInterval() as i32;
1064            assert!(interval == -1 || interval == 0 || interval == 1);
1065            mem::transmute(interval)
1066        }
1067    }
1068
1069    /// Loads the default Vulkan library.
1070    ///
1071    /// This should be done after initializing the video driver, but before creating any Vulkan windows.
1072    /// If no Vulkan library is loaded, the default library will be loaded upon creation of the first Vulkan window.
1073    ///
1074    /// If a different library is already loaded, this function will return an error.
1075    #[doc(alias = "SDL_Vulkan_LoadLibrary")]
1076    pub fn vulkan_load_library_default(&self) -> Result<(), String> {
1077        unsafe {
1078            if sys::SDL_Vulkan_LoadLibrary(ptr::null()) == 0 {
1079                Ok(())
1080            } else {
1081                Err(get_error())
1082            }
1083        }
1084    }
1085
1086    /// Loads the Vulkan library using a platform-dependent Vulkan library name (usually a file path).
1087    ///
1088    /// This should be done after initializing the video driver, but before creating any Vulkan windows.
1089    /// If no Vulkan library is loaded, the default library will be loaded upon creation of the first Vulkan window.
1090    ///
1091    /// If a different library is already loaded, this function will return an error.
1092    #[doc(alias = "SDL_Vulkan_LoadLibrary")]
1093    pub fn vulkan_load_library<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
1094        unsafe {
1095            let path = CString::new(path.as_ref().to_str().unwrap()).unwrap();
1096            if sys::SDL_Vulkan_LoadLibrary(path.as_ptr() as *const c_char) == 0 {
1097                Ok(())
1098            } else {
1099                Err(get_error())
1100            }
1101        }
1102    }
1103
1104    /// Unloads the current Vulkan library.
1105    ///
1106    /// To completely unload the library, this should be called for every successful load of the
1107    /// Vulkan library.
1108    #[doc(alias = "SDL_Vulkan_UnloadLibrary")]
1109    pub fn vulkan_unload_library(&self) {
1110        unsafe {
1111            sys::SDL_Vulkan_UnloadLibrary();
1112        }
1113    }
1114
1115    /// Gets the pointer to the
1116    /// [`vkGetInstanceProcAddr`](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetInstanceProcAddr.html)
1117    /// Vulkan function. This function can be called to retrieve the address of other Vulkan
1118    /// functions.
1119    #[doc(alias = "SDL_Vulkan_GetVkGetInstanceProcAddr")]
1120    pub fn vulkan_get_proc_address_function(&self) -> Result<*const (), String> {
1121        let result = unsafe { sys::SDL_Vulkan_GetVkGetInstanceProcAddr() as *const () };
1122        if result.is_null() {
1123            Err(get_error())
1124        } else {
1125            Ok(result)
1126        }
1127    }
1128}
1129
1130#[derive(Debug, Clone)]
1131pub enum WindowBuildError {
1132    HeightOverflows(u32),
1133    WidthOverflows(u32),
1134    InvalidTitle(NulError),
1135    SdlError(String),
1136}
1137
1138impl fmt::Display for WindowBuildError {
1139    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1140        use self::WindowBuildError::*;
1141
1142        match *self {
1143            HeightOverflows(h) => write!(f, "Window height ({}) is too high.", h),
1144            WidthOverflows(w) => write!(f, "Window width ({}) is too high.", w),
1145            InvalidTitle(ref e) => write!(f, "Invalid window title: {}", e),
1146            SdlError(ref e) => write!(f, "SDL error: {}", e),
1147        }
1148    }
1149}
1150
1151impl Error for WindowBuildError {
1152    fn source(&self) -> Option<&(dyn Error + 'static)> {
1153        match self {
1154            Self::InvalidTitle(err) => Some(err),
1155            Self::HeightOverflows(_) | Self::WidthOverflows(_) | Self::SdlError(_) => None,
1156        }
1157    }
1158}
1159
1160/// The type that allows you to build windows.
1161#[derive(Debug)]
1162pub struct WindowBuilder {
1163    title: String,
1164    width: u32,
1165    height: u32,
1166    x: WindowPos,
1167    y: WindowPos,
1168    window_flags: u32,
1169    create_metal_view: bool,
1170    /// The window builder cannot be built on a non-main thread, so prevent cross-threaded moves and references.
1171    /// `!Send` and `!Sync`,
1172    subsystem: VideoSubsystem,
1173    shaped: bool,
1174}
1175
1176impl WindowBuilder {
1177    /// Initializes a new `WindowBuilder`.
1178    pub fn new(v: &VideoSubsystem, title: &str, width: u32, height: u32) -> WindowBuilder {
1179        WindowBuilder {
1180            title: title.to_owned(),
1181            width,
1182            height,
1183            x: WindowPos::Undefined,
1184            y: WindowPos::Undefined,
1185            window_flags: 0,
1186            subsystem: v.clone(),
1187            create_metal_view: false,
1188            shaped: false,
1189        }
1190    }
1191
1192    /// Builds the window.
1193    #[doc(alias = "SDL_CreateWindow")]
1194    pub fn build(&self) -> Result<Window, WindowBuildError> {
1195        use self::WindowBuildError::*;
1196        let title = match CString::new(self.title.as_bytes()) {
1197            Ok(t) => t,
1198            Err(err) => return Err(InvalidTitle(err)),
1199        };
1200        if self.width >= (1 << 31) {
1201            return Err(WidthOverflows(self.width));
1202        }
1203        if self.height >= (1 << 31) {
1204            return Err(HeightOverflows(self.height));
1205        }
1206
1207        let raw_width = self.width as c_int;
1208        let raw_height = self.height as c_int;
1209        unsafe {
1210            let raw = if self.shaped {
1211                sys::SDL_CreateShapedWindow(
1212                    title.as_ptr() as *const c_char,
1213                    to_ll_windowpos(self.x) as u32,
1214                    to_ll_windowpos(self.y) as u32,
1215                    raw_width as u32,
1216                    raw_height as u32,
1217                    self.window_flags,
1218                )
1219            } else {
1220                sys::SDL_CreateWindow(
1221                    title.as_ptr() as *const c_char,
1222                    to_ll_windowpos(self.x),
1223                    to_ll_windowpos(self.y),
1224                    raw_width,
1225                    raw_height,
1226                    self.window_flags,
1227                )
1228            };
1229
1230            if raw.is_null() {
1231                Err(SdlError(get_error()))
1232            } else {
1233                let metal_view = match self.create_metal_view {
1234                    #[cfg(target_os = "macos")]
1235                    true => sys::SDL_Metal_CreateView(raw),
1236                    _ => 0 as sys::SDL_MetalView,
1237                };
1238
1239                Ok(Window::from_ll(self.subsystem.clone(), raw, metal_view))
1240            }
1241        }
1242    }
1243
1244    /// Gets the underlying window flags.
1245    pub fn window_flags(&self) -> u32 {
1246        self.window_flags
1247    }
1248
1249    /// Sets the underlying window flags.
1250    /// This will effectively undo any previous build operations, excluding window size and position.
1251    pub fn set_window_flags(&mut self, flags: u32) -> &mut WindowBuilder {
1252        self.window_flags = flags;
1253        self
1254    }
1255
1256    /// Sets the window position.
1257    pub fn position(&mut self, x: i32, y: i32) -> &mut WindowBuilder {
1258        self.x = WindowPos::Positioned(x);
1259        self.y = WindowPos::Positioned(y);
1260        self
1261    }
1262
1263    /// Centers the window.
1264    pub fn position_centered(&mut self) -> &mut WindowBuilder {
1265        self.x = WindowPos::Centered;
1266        self.y = WindowPos::Centered;
1267        self
1268    }
1269
1270    /// Sets the window to fullscreen.
1271    pub fn fullscreen(&mut self) -> &mut WindowBuilder {
1272        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_FULLSCREEN as u32;
1273        self
1274    }
1275
1276    /// Sets the window to fullscreen at the current desktop resolution.
1277    pub fn fullscreen_desktop(&mut self) -> &mut WindowBuilder {
1278        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_FULLSCREEN_DESKTOP as u32;
1279        self
1280    }
1281
1282    /// Sets the window to be usable with an OpenGL context
1283    pub fn opengl(&mut self) -> &mut WindowBuilder {
1284        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_OPENGL as u32;
1285        self
1286    }
1287
1288    /// Sets the window to be usable with a Vulkan instance
1289    pub fn vulkan(&mut self) -> &mut WindowBuilder {
1290        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_VULKAN as u32;
1291        self
1292    }
1293
1294    /// Hides the window.
1295    pub fn hidden(&mut self) -> &mut WindowBuilder {
1296        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_HIDDEN as u32;
1297        self
1298    }
1299
1300    /// Removes the window decoration.
1301    pub fn borderless(&mut self) -> &mut WindowBuilder {
1302        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_BORDERLESS as u32;
1303        self
1304    }
1305
1306    /// Sets the window to be resizable.
1307    pub fn resizable(&mut self) -> &mut WindowBuilder {
1308        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_RESIZABLE as u32;
1309        self
1310    }
1311
1312    /// Minimizes the window (minimizes the window to its iconic representation).
1313    pub fn minimized(&mut self) -> &mut WindowBuilder {
1314        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_MINIMIZED as u32;
1315        self
1316    }
1317
1318    /// Maximizes the window.
1319    pub fn maximized(&mut self) -> &mut WindowBuilder {
1320        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_MAXIMIZED as u32;
1321        self
1322    }
1323
1324    /// Sets the window to have grabbed input focus.
1325    pub fn input_grabbed(&mut self) -> &mut WindowBuilder {
1326        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_INPUT_GRABBED as u32;
1327        self
1328    }
1329
1330    /// Creates the window in high-DPI mode if supported (>= SDL 2.0.1)
1331    pub fn allow_highdpi(&mut self) -> &mut WindowBuilder {
1332        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_ALLOW_HIGHDPI as u32;
1333        self
1334    }
1335
1336    /// Window should always above others (>= SDL 2.0.5)
1337    pub fn always_on_top(&mut self) -> &mut WindowBuilder {
1338        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_ALWAYS_ON_TOP as u32;
1339        self
1340    }
1341
1342    /// Create a SDL_MetalView when constructing the window.
1343    /// This is required when using the raw_window_handle feature on MacOS.
1344    /// Has no effect no other platforms.
1345    pub fn metal_view(&mut self) -> &mut WindowBuilder {
1346        self.create_metal_view = true;
1347        self
1348    }
1349
1350    /// Sets shaped state, to create via SDL_CreateShapedWindow instead of SDL_CreateWindow
1351    pub fn set_shaped(&mut self) -> &mut WindowBuilder {
1352        self.shaped = true;
1353        self
1354    }
1355}
1356
1357impl From<Window> for CanvasBuilder {
1358    fn from(window: Window) -> CanvasBuilder {
1359        CanvasBuilder::new(window)
1360    }
1361}
1362
1363impl Window {
1364    #[inline]
1365    // this can prevent introducing UB until
1366    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
1367    #[allow(clippy::trivially_copy_pass_by_ref)]
1368    pub fn raw(&self) -> *mut sys::SDL_Window {
1369        self.context.raw
1370    }
1371
1372    #[inline]
1373    pub unsafe fn from_ll(
1374        subsystem: VideoSubsystem,
1375        raw: *mut sys::SDL_Window,
1376        metal_view: sys::SDL_MetalView,
1377    ) -> Window {
1378        let context = WindowContext::from_ll(subsystem, raw, metal_view);
1379        context.into()
1380    }
1381
1382    #[inline]
1383    /// Create a new `Window` without taking ownership of the `WindowContext`
1384    pub const fn from_ref(context: Rc<WindowContext>) -> Window {
1385        Window { context }
1386    }
1387
1388    /// Returns this context's video system.
1389    #[inline]
1390    pub fn subsystem(&self) -> &VideoSubsystem {
1391        &self.context.subsystem
1392    }
1393
1394    /// Initializes a new `CanvasBuilder`; a convenience method that calls `CanvasBuilder::new()`.
1395    pub fn into_canvas(self) -> CanvasBuilder {
1396        self.into()
1397    }
1398
1399    /// Returns the window context.
1400    pub fn context(&self) -> Rc<WindowContext> {
1401        self.context.clone()
1402    }
1403
1404    /// Get the numeric ID of a window.
1405    #[doc(alias = "SDL_GetWindowID")]
1406    pub fn id(&self) -> u32 {
1407        unsafe { sys::SDL_GetWindowID(self.context.raw) }
1408    }
1409
1410    /// Create an OpenGL context for an OpenGL window, and make it current.
1411    #[doc(alias = "SDL_GL_CreateContext")]
1412    pub fn gl_create_context(&self) -> Result<GLContext, String> {
1413        let result = unsafe { sys::SDL_GL_CreateContext(self.context.raw) };
1414        if result.is_null() {
1415            Err(get_error())
1416        } else {
1417            Ok(GLContext { raw: result })
1418        }
1419    }
1420
1421    /// Get the currently active OpenGL context.
1422    #[doc(alias = "SDL_GL_GetCurrentContext")]
1423    pub unsafe fn gl_get_current_context(&self) -> Option<GLContext> {
1424        let context_raw = sys::SDL_GL_GetCurrentContext();
1425
1426        if !context_raw.is_null() {
1427            Some(GLContext { raw: context_raw })
1428        } else {
1429            None
1430        }
1431    }
1432
1433    /// Set the window's OpenGL context to the current context on the thread.
1434    #[doc(alias = "SDL_GL_MakeCurrent")]
1435    pub fn gl_set_context_to_current(&self) -> Result<(), String> {
1436        unsafe {
1437            let context_raw = sys::SDL_GL_GetCurrentContext();
1438
1439            if !context_raw.is_null() && sys::SDL_GL_MakeCurrent(self.context.raw, context_raw) == 0
1440            {
1441                Ok(())
1442            } else {
1443                Err(get_error())
1444            }
1445        }
1446    }
1447
1448    /// Set up an OpenGL context for rendering into an OpenGL window.
1449    ///
1450    /// The context must have been created with a compatible window.
1451    #[doc(alias = "SDL_GL_MakeCurrent")]
1452    pub fn gl_make_current(&self, context: &GLContext) -> Result<(), String> {
1453        unsafe {
1454            if sys::SDL_GL_MakeCurrent(self.context.raw, context.raw) == 0 {
1455                Ok(())
1456            } else {
1457                Err(get_error())
1458            }
1459        }
1460    }
1461
1462    /// Update a window with OpenGL rendering.
1463    ///
1464    /// This is used with double-buffered OpenGL contexts, which are the default.
1465    /// On macOS, make sure you bind 0 to the draw framebuffer before swapping the window,
1466    /// otherwise nothing will happen.
1467    /// If you aren't using glBindFramebuffer(),
1468    /// this is the default, and you won't have to do anything extra.
1469    #[doc(alias = "SDL_GL_SwapWindow")]
1470    pub fn gl_swap_window(&self) {
1471        unsafe { sys::SDL_GL_SwapWindow(self.context.raw) }
1472    }
1473
1474    /// Get the names of the Vulkan instance extensions needed to create a surface with `vulkan_create_surface`.
1475    #[doc(alias = "SDL_Vulkan_GetInstanceExtensions")]
1476    pub fn vulkan_instance_extensions(&self) -> Result<Vec<&'static str>, String> {
1477        let mut count: c_uint = 0;
1478        if unsafe {
1479            sys::SDL_Vulkan_GetInstanceExtensions(self.context.raw, &mut count, ptr::null_mut())
1480        } == sys::SDL_bool::SDL_FALSE
1481        {
1482            return Err(get_error());
1483        }
1484        let mut names: Vec<*const c_char> = vec![ptr::null(); count as usize];
1485        if unsafe {
1486            sys::SDL_Vulkan_GetInstanceExtensions(self.context.raw, &mut count, names.as_mut_ptr())
1487        } == sys::SDL_bool::SDL_FALSE
1488        {
1489            return Err(get_error());
1490        }
1491        Ok(names
1492            .iter()
1493            .map(|&val| unsafe { CStr::from_ptr(val) }.to_str().unwrap())
1494            .collect())
1495    }
1496
1497    /// Create a Vulkan rendering surface for a window.
1498    ///
1499    /// The `VkInstance` must be created using a prior call to the
1500    /// [`vkCreateInstance`](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateInstance.html)
1501    /// function in the Vulkan library.
1502    #[doc(alias = "SDL_Vulkan_CreateSurface")]
1503    pub fn vulkan_create_surface(&self, instance: VkInstance) -> Result<VkSurfaceKHR, String> {
1504        let mut surface: VkSurfaceKHR = 0;
1505        if unsafe { sys::SDL_Vulkan_CreateSurface(self.context.raw, instance, &mut surface) }
1506            == sys::SDL_bool::SDL_FALSE
1507        {
1508            Err(get_error())
1509        } else {
1510            Ok(surface)
1511        }
1512    }
1513
1514    /// Get the index of the display associated with a window.
1515    #[doc(alias = "SDL_GetWindowDisplayIndex")]
1516    pub fn display_index(&self) -> Result<i32, String> {
1517        let result = unsafe { sys::SDL_GetWindowDisplayIndex(self.context.raw) };
1518        if result < 0 {
1519            Err(get_error())
1520        } else {
1521            Ok(result as i32)
1522        }
1523    }
1524
1525    /// Set the display mode to use when a window is visible at fullscreen.
1526    ///
1527    /// This only affects the display mode used when the window is fullscreen.
1528    /// To change the window size when the window is not fullscreen, use `set_size`.
1529    #[doc(alias = "SDL_SetWindowDisplayMode")]
1530    pub fn set_display_mode<D>(&mut self, display_mode: D) -> Result<(), String>
1531    where
1532        D: Into<Option<DisplayMode>>,
1533    {
1534        unsafe {
1535            let result = sys::SDL_SetWindowDisplayMode(
1536                self.context.raw,
1537                match display_mode.into() {
1538                    Some(ref mode) => &mode.to_ll(),
1539                    None => ptr::null(),
1540                },
1541            );
1542            if result < 0 {
1543                Err(get_error())
1544            } else {
1545                Ok(())
1546            }
1547        }
1548    }
1549
1550    /// Query the display mode to use when a window is visible at fullscreen.
1551    #[doc(alias = "SDL_GetWindowDisplayMode")]
1552    pub fn display_mode(&self) -> Result<DisplayMode, String> {
1553        let mut dm = mem::MaybeUninit::uninit();
1554
1555        let result =
1556            unsafe { sys::SDL_GetWindowDisplayMode(self.context.raw, dm.as_mut_ptr()) == 0 };
1557
1558        if result {
1559            let dm = unsafe { dm.assume_init() };
1560            Ok(DisplayMode::from_ll(&dm))
1561        } else {
1562            Err(get_error())
1563        }
1564    }
1565
1566    /// Get the raw ICC profile data for the screen the window is currently on.
1567    #[doc(alias = "SDL_GetWindowICCProfile")]
1568    pub fn icc_profile(&self) -> Result<Vec<u8>, String> {
1569        unsafe {
1570            let mut size: libc::size_t = 0;
1571            let data = sys::SDL_GetWindowICCProfile(self.context.raw, &mut size as *mut _);
1572            if data.is_null() {
1573                return Err(get_error());
1574            }
1575            let mut result = vec![0; size as usize];
1576            result.copy_from_slice(std::slice::from_raw_parts(data as *const u8, size as usize));
1577            sys::SDL_free(data);
1578            Ok(result)
1579        }
1580    }
1581
1582    /// Get the pixel format associated with the window.
1583    #[doc(alias = "SDL_GetWindowPixelFormat")]
1584    pub fn window_pixel_format(&self) -> PixelFormatEnum {
1585        unsafe {
1586            PixelFormatEnum::try_from(sys::SDL_GetWindowPixelFormat(self.context.raw) as u32)
1587                .unwrap()
1588        }
1589    }
1590
1591    #[doc(alias = "SDL_GetWindowFlags")]
1592    pub fn window_flags(&self) -> u32 {
1593        unsafe { sys::SDL_GetWindowFlags(self.context.raw) }
1594    }
1595
1596    /// Does the window have input focus?
1597    pub fn has_input_focus(&self) -> bool {
1598        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_INPUT_FOCUS as u32
1599    }
1600
1601    /// Has the window grabbed input focus?
1602    pub fn has_input_grabbed(&self) -> bool {
1603        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_INPUT_GRABBED as u32
1604    }
1605
1606    /// Does the window have mouse focus?
1607    pub fn has_mouse_focus(&self) -> bool {
1608        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_MOUSE_FOCUS as u32
1609    }
1610
1611    /// Is the window maximized?
1612    pub fn is_maximized(&self) -> bool {
1613        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_MAXIMIZED as u32
1614    }
1615
1616    /// Is the window minimized?
1617    pub fn is_minimized(&self) -> bool {
1618        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_MINIMIZED as u32
1619    }
1620
1621    /// Is the window always on top?
1622    pub fn is_always_on_top(&self) -> bool {
1623        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_ALWAYS_ON_TOP as u32
1624    }
1625
1626    /// Set the user-resizable state of a window - `true` to allow resizing and `false` to forbid.
1627    #[doc(alias = "SDL_SetWindowResizable")]
1628    pub fn set_resizable(&mut self, resizable: bool) {
1629        let resizable = if resizable {
1630            sys::SDL_bool::SDL_TRUE
1631        } else {
1632            sys::SDL_bool::SDL_FALSE
1633        };
1634        unsafe {
1635            sys::SDL_SetWindowResizable(self.context.raw, resizable);
1636        }
1637    }
1638
1639    /// Set the shape of the window
1640    /// To be effective:
1641    /// - shaped must have been set using windows builder
1642    /// - binarizationCutoff: specify the cutoff value for the shape's alpha
1643    ///   channel: At or above that cutoff value, a pixel is visible in the
1644    ///   shape. Below that, it's not part of the shape.
1645    pub fn set_window_shape_alpha<S: AsRef<SurfaceRef>>(
1646        &mut self,
1647        shape: S,
1648        binarization_cutoff: u8,
1649    ) -> Result<(), i32> {
1650        let mode = sys::WindowShapeMode::ShapeModeBinarizeAlpha;
1651        let parameters = sys::SDL_WindowShapeParams {
1652            binarizationCutoff: binarization_cutoff,
1653        };
1654        let mut shape_mode = sys::SDL_WindowShapeMode { mode, parameters };
1655        let result = unsafe {
1656            sys::SDL_SetWindowShape(self.context.raw, shape.as_ref().raw(), &mut shape_mode)
1657        };
1658        if result == 0 {
1659            Ok(())
1660        } else {
1661            Err(result)
1662        }
1663    }
1664
1665    /// Set the title of a window.
1666    #[doc(alias = "SDL_SetWindowTitle")]
1667    pub fn set_title(&mut self, title: &str) -> Result<(), NulError> {
1668        let title = CString::new(title)?;
1669        unsafe {
1670            sys::SDL_SetWindowTitle(self.context.raw, title.as_ptr() as *const c_char);
1671        }
1672        Ok(())
1673    }
1674    /// Get the title of a window.
1675    #[doc(alias = "SDL_GetWindowTitle")]
1676    pub fn title(&self) -> &str {
1677        unsafe {
1678            let buf = sys::SDL_GetWindowTitle(self.context.raw);
1679
1680            // The window title must be encoded in UTF-8.
1681            CStr::from_ptr(buf as *const _).to_str().unwrap()
1682        }
1683    }
1684
1685    /// Use this function to set the icon for a window.
1686    ///
1687    /// # Example:
1688    /// ```compile_fail
1689    /// // requires "--features 'image'"
1690    /// use sdl2::surface::Surface;
1691    ///
1692    /// let window_icon = Surface::from_file("/path/to/icon.png")?;
1693    /// window.set_icon(window_icon);
1694    /// ```
1695    #[doc(alias = "SDL_SetWindowIcon")]
1696    pub fn set_icon<S: AsRef<SurfaceRef>>(&mut self, icon: S) {
1697        unsafe { sys::SDL_SetWindowIcon(self.context.raw, icon.as_ref().raw()) }
1698    }
1699
1700    // Those functions allow to store pointer to an arbitrary data (`userdata`) within the window
1701    // (similar to hashmap) and to access it through the window. TODO
1702    //pub fn SDL_SetWindowData(window: *SDL_Window, name: *c_char, userdata: *c_void) -> *c_void;
1703    //pub fn SDL_GetWindowData(window: *SDL_Window, name: *c_char) -> *c_void;
1704
1705    #[doc(alias = "SDL_SetWindowPosition")]
1706    pub fn set_position(&mut self, x: WindowPos, y: WindowPos) {
1707        unsafe {
1708            sys::SDL_SetWindowPosition(self.context.raw, to_ll_windowpos(x), to_ll_windowpos(y))
1709        }
1710    }
1711
1712    /// Get the position of a window.
1713    #[doc(alias = "SDL_GetWindowPosition")]
1714    pub fn position(&self) -> (i32, i32) {
1715        let mut x: c_int = 0;
1716        let mut y: c_int = 0;
1717        unsafe { sys::SDL_GetWindowPosition(self.context.raw, &mut x, &mut y) };
1718        (x as i32, y as i32)
1719    }
1720
1721    /// Use this function to get the size of a window's borders (decorations) around the client area.
1722    ///
1723    /// # Remarks
1724    /// This function is only supported on X11, otherwise an error is returned.
1725    #[doc(alias = "SDL_GetWindowBordersSize")]
1726    pub fn border_size(&self) -> Result<(u16, u16, u16, u16), String> {
1727        let mut top: c_int = 0;
1728        let mut left: c_int = 0;
1729        let mut bottom: c_int = 0;
1730        let mut right: c_int = 0;
1731        let result = unsafe {
1732            sys::SDL_GetWindowBordersSize(
1733                self.context.raw,
1734                &mut top,
1735                &mut left,
1736                &mut bottom,
1737                &mut right,
1738            )
1739        };
1740        if result < 0 {
1741            Err(get_error())
1742        } else {
1743            Ok((top as u16, left as u16, bottom as u16, right as u16))
1744        }
1745    }
1746
1747    /// Set the size of a window's client area.
1748    #[doc(alias = "SDL_SetWindowSize")]
1749    pub fn set_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1750        let w = validate_int(width, "width")?;
1751        let h = validate_int(height, "height")?;
1752        unsafe {
1753            sys::SDL_SetWindowSize(self.context.raw, w, h);
1754        }
1755        Ok(())
1756    }
1757
1758    /// Get the size of a window's client area.
1759    #[doc(alias = "SDL_GetWindowSize")]
1760    pub fn size(&self) -> (u32, u32) {
1761        let mut w: c_int = 0;
1762        let mut h: c_int = 0;
1763        unsafe { sys::SDL_GetWindowSize(self.context.raw, &mut w, &mut h) };
1764        (w as u32, h as u32)
1765    }
1766
1767    /// Get the size of the window's underlying drawable dimensions in pixels.
1768    ///
1769    /// Note that the size could differ from `Window::size` - that would be if we're rendering
1770    /// to a high-DPI drawable (Apple's Retina is an example of that).
1771    #[doc(alias = "SDL_GL_GetDrawableSize")]
1772    pub fn drawable_size(&self) -> (u32, u32) {
1773        let mut w: c_int = 0;
1774        let mut h: c_int = 0;
1775        unsafe { sys::SDL_GL_GetDrawableSize(self.context.raw, &mut w, &mut h) };
1776        (w as u32, h as u32)
1777    }
1778
1779    /// Get the size of the window's underlying drawable dimensions in pixels.
1780    ///
1781    /// Note that the size could differ from `Window::size` - that would be if we're rendering
1782    /// to a high-DPI drawable (Apple's Retina is an example of that).
1783    #[doc(alias = "SDL_Vulkan_GetDrawableSize")]
1784    pub fn vulkan_drawable_size(&self) -> (u32, u32) {
1785        let mut w: c_int = 0;
1786        let mut h: c_int = 0;
1787        unsafe { sys::SDL_Vulkan_GetDrawableSize(self.context.raw, &mut w, &mut h) };
1788        (w as u32, h as u32)
1789    }
1790
1791    /// Set the minimum size of a window's client area.
1792    #[doc(alias = "SDL_SetWindowMinimumSize")]
1793    pub fn set_minimum_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1794        let w = validate_int(width, "width")?;
1795        let h = validate_int(height, "height")?;
1796        unsafe {
1797            sys::SDL_SetWindowMinimumSize(self.context.raw, w, h);
1798        }
1799        Ok(())
1800    }
1801
1802    /// Get the minimum size of a window's client area.
1803    #[doc(alias = "SDL_GetWindowMinimumSize")]
1804    pub fn minimum_size(&self) -> (u32, u32) {
1805        let mut w: c_int = 0;
1806        let mut h: c_int = 0;
1807        unsafe { sys::SDL_GetWindowMinimumSize(self.context.raw, &mut w, &mut h) };
1808        (w as u32, h as u32)
1809    }
1810
1811    /// Set the maximum size of a window's client area.
1812    #[doc(alias = "SDL_SetWindowMaximumSize")]
1813    pub fn set_maximum_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1814        let w = validate_int(width, "width")?;
1815        let h = validate_int(height, "height")?;
1816        unsafe {
1817            sys::SDL_SetWindowMaximumSize(self.context.raw, w, h);
1818        }
1819        Ok(())
1820    }
1821
1822    /// Get the maximum size of a window's client area.
1823    #[doc(alias = "SDL_GetWindowMaximumSize")]
1824    pub fn maximum_size(&self) -> (u32, u32) {
1825        let mut w: c_int = 0;
1826        let mut h: c_int = 0;
1827        unsafe { sys::SDL_GetWindowMaximumSize(self.context.raw, &mut w, &mut h) };
1828        (w as u32, h as u32)
1829    }
1830
1831    /// Set the border state of a window - `true` adds border and `false` removes it.
1832    ///
1833    /// The border state of a fullscreen window cannot be changed.
1834    #[doc(alias = "SDL_SetWindowBordered")]
1835    pub fn set_bordered(&mut self, bordered: bool) {
1836        unsafe {
1837            sys::SDL_SetWindowBordered(
1838                self.context.raw,
1839                if bordered {
1840                    sys::SDL_bool::SDL_TRUE
1841                } else {
1842                    sys::SDL_bool::SDL_FALSE
1843                },
1844            )
1845        }
1846    }
1847
1848    /// Shows the window that was hidden by `hide`.
1849    #[doc(alias = "SDL_ShowWindow")]
1850    pub fn show(&mut self) {
1851        unsafe { sys::SDL_ShowWindow(self.context.raw) }
1852    }
1853
1854    /// Hides the window, so it won't even show in the taskbar.
1855    #[doc(alias = "SDL_HideWindow")]
1856    pub fn hide(&mut self) {
1857        unsafe { sys::SDL_HideWindow(self.context.raw) }
1858    }
1859
1860    /// Raise a window above other windows and set the input focus.
1861    #[doc(alias = "SDL_RaiseWindow")]
1862    pub fn raise(&mut self) {
1863        unsafe { sys::SDL_RaiseWindow(self.context.raw) }
1864    }
1865
1866    /// Sets window size to be as large as possible.
1867    #[doc(alias = "SDL_MaximizeWindow")]
1868    pub fn maximize(&mut self) {
1869        unsafe { sys::SDL_MaximizeWindow(self.context.raw) }
1870    }
1871
1872    /// Minimize a window to an iconic representation (will show up in taskbar).
1873    #[doc(alias = "SDL_MinimizeWindow")]
1874    pub fn minimize(&mut self) {
1875        unsafe { sys::SDL_MinimizeWindow(self.context.raw) }
1876    }
1877
1878    /// Restores the size and position of a minimized or maximized window.
1879    #[doc(alias = "SDL_RestoreWindow")]
1880    pub fn restore(&mut self) {
1881        unsafe { sys::SDL_RestoreWindow(self.context.raw) }
1882    }
1883
1884    /// Returns the type of fullscreen that the window is currently using.
1885    pub fn fullscreen_state(&self) -> FullscreenType {
1886        FullscreenType::from_window_flags(self.window_flags())
1887    }
1888
1889    /// Sets new fullscreen type for the window.
1890    #[doc(alias = "SDL_SetWindowFullscreen")]
1891    pub fn set_fullscreen(&mut self, fullscreen_type: FullscreenType) -> Result<(), String> {
1892        unsafe {
1893            let result = sys::SDL_SetWindowFullscreen(self.context.raw, fullscreen_type as u32);
1894            if result == 0 {
1895                Ok(())
1896            } else {
1897                Err(get_error())
1898            }
1899        }
1900    }
1901
1902    /// Returns a WindowSurfaceRef, which can be used like a regular Surface. This is an
1903    /// alternative way to the Renderer (Canvas) way to modify pixels directly in the Window.
1904    ///
1905    /// For this to happen, simply create a `WindowSurfaceRef` via this method, use the underlying
1906    /// Surface however you like, and when the changes of the Surface must be applied to the
1907    /// screen, call `update_window` if you intend to keep using the WindowSurfaceRef afterwards,
1908    /// or `finish` if you don't intend to use it afterwards.
1909    ///
1910    /// The Renderer way is of course much more flexible and recommended; even though you only want
1911    /// to support Software Rendering (which is what using Surface is), you can still create a
1912    /// Renderer which renders in a Software-based manner, so try to rely on a Renderer as much as
1913    /// possible !
1914    #[doc(alias = "SDL_GetWindowSurface")]
1915    pub fn surface<'a>(&'a self, _e: &'a EventPump) -> Result<WindowSurfaceRef<'a>, String> {
1916        let raw = unsafe { sys::SDL_GetWindowSurface(self.context.raw) };
1917
1918        if raw.is_null() {
1919            Err(get_error())
1920        } else {
1921            let surface_ref = unsafe { SurfaceRef::from_ll_mut(raw) };
1922            Ok(WindowSurfaceRef(surface_ref, self))
1923        }
1924    }
1925
1926    /// When input is grabbed, the mouse is confined to the window.
1927    #[doc(alias = "SDL_SetWindowGrab")]
1928    pub fn set_grab(&mut self, grabbed: bool) {
1929        unsafe {
1930            sys::SDL_SetWindowGrab(
1931                self.context.raw,
1932                if grabbed {
1933                    sys::SDL_bool::SDL_TRUE
1934                } else {
1935                    sys::SDL_bool::SDL_FALSE
1936                },
1937            )
1938        }
1939    }
1940
1941    /// Keyboard grab enables capture of system keyboard shortcuts like Alt+Tab or the Meta/Super key.
1942    /// Note that not all system keyboard shortcuts can be captured by applications (one example is Ctrl+Alt+Del on Windows).
1943    ///
1944    /// If the caller enables a grab while another window is currently grabbed,
1945    /// the other window loses its grab in favor of the caller's window.
1946    #[doc(alias = "SDL_SetWindowKeyboardGrab")]
1947    pub fn set_keyboard_grab(&mut self, grabbed: bool) {
1948        unsafe {
1949            sys::SDL_SetWindowKeyboardGrab(
1950                self.context.raw,
1951                if grabbed {
1952                    sys::SDL_bool::SDL_TRUE
1953                } else {
1954                    sys::SDL_bool::SDL_FALSE
1955                },
1956            )
1957        }
1958    }
1959
1960    /// Mouse grab confines the mouse cursor to the window.
1961    #[doc(alias = "SDL_SetWindowMouseGrab")]
1962    pub fn set_mouse_grab(&mut self, grabbed: bool) {
1963        unsafe {
1964            sys::SDL_SetWindowMouseGrab(
1965                self.context.raw,
1966                if grabbed {
1967                    sys::SDL_bool::SDL_TRUE
1968                } else {
1969                    sys::SDL_bool::SDL_FALSE
1970                },
1971            )
1972        }
1973    }
1974
1975    /// Returns whether the window was grabbed by `set_grab` or not.
1976    #[doc(alias = "SDL_GetWindowGrab")]
1977    pub fn grab(&self) -> bool {
1978        unsafe { sys::SDL_GetWindowGrab(self.context.raw) == sys::SDL_bool::SDL_TRUE }
1979    }
1980
1981    /// Returns whether the keyboard was grabbed by `set_keyboard_grab` or not.
1982    #[doc(alias = "SDL_GetWindowKeyboardGrab")]
1983    pub fn keyboard_grab(&self) -> bool {
1984        unsafe { sys::SDL_GetWindowKeyboardGrab(self.context.raw) == sys::SDL_bool::SDL_TRUE }
1985    }
1986
1987    /// Returns whether the mouse was grabbed by `set_mouse_grab` or not.
1988    #[doc(alias = "SDL_GetWindowMouseGrab")]
1989    pub fn mouse_grab(&self) -> bool {
1990        unsafe { sys::SDL_GetWindowMouseGrab(self.context.raw) == sys::SDL_bool::SDL_TRUE }
1991    }
1992
1993    /// Confines the cursor to the specified area of a window.
1994    /// Note that this does NOT grab the cursor,
1995    /// it only defines the area a cursor is restricted to when the window has mouse focus.
1996    #[doc(alias = "SDL_SetWindowMouseRect")]
1997    pub fn set_mouse_rect<R>(&self, rect: R) -> Result<(), String>
1998    where
1999        R: Into<Option<Rect>>,
2000    {
2001        let rect = rect.into();
2002        let rect_raw_ptr = match rect {
2003            Some(ref rect) => rect.raw(),
2004            None => ptr::null(),
2005        };
2006
2007        unsafe {
2008            if sys::SDL_SetWindowMouseRect(self.context.raw, rect_raw_ptr) == 0 {
2009                Ok(())
2010            } else {
2011                Err(get_error())
2012            }
2013        }
2014    }
2015
2016    /// Returns `Rect` to which the mouse is currently confined by `set_mouse_rect` function.
2017    ///
2018    /// Returns `None` if mouse was not confined.
2019    #[doc(alias = "SDL_GetWindowMouseRect")]
2020    pub fn mouse_rect(&self) -> Option<Rect> {
2021        unsafe {
2022            let raw_rect = sys::SDL_GetWindowMouseRect(self.context.raw);
2023            if raw_rect.is_null() {
2024                None
2025            } else {
2026                Some(Rect::new(
2027                    (*raw_rect).x,
2028                    (*raw_rect).y,
2029                    (*raw_rect).w as u32,
2030                    (*raw_rect).h as u32,
2031                ))
2032            }
2033        }
2034    }
2035
2036    /// Set the brightness (gamma multiplier) for a given window's display.
2037    ///
2038    /// Despite the name and signature, this method sets the brightness of the entire display,
2039    /// not an individual window.
2040    /// A window is considered to be owned by the display that contains the window's center pixel.
2041    /// So, if the window was moved to another display, it will not retain set brightness.
2042    #[doc(alias = "SDL_SetWindowBrightness")]
2043    pub fn set_brightness(&mut self, brightness: f64) -> Result<(), String> {
2044        unsafe {
2045            if sys::SDL_SetWindowBrightness(self.context.raw, brightness as c_float) == 0 {
2046                Ok(())
2047            } else {
2048                Err(get_error())
2049            }
2050        }
2051    }
2052
2053    #[doc(alias = "SDL_GetWindowBrightness")]
2054    pub fn brightness(&self) -> f64 {
2055        unsafe { sys::SDL_GetWindowBrightness(self.context.raw) as f64 }
2056    }
2057
2058    /// Set the gamma ramp for the display that owns a given window.
2059    /// A window is considered to be owned by the display that contains the window's center pixel.
2060    ///
2061    /// Set the gamma translation table for the red, green, and blue channels of the video hardware.
2062    /// Each table is an array of 256 16-bit quantities, representing a mapping
2063    /// between the input and output for that channel.
2064    #[doc(alias = "SDL_SetWindowGammaRamp")]
2065    pub fn set_gamma_ramp<'a, 'b, 'c, R, G, B>(
2066        &mut self,
2067        red: R,
2068        green: G,
2069        blue: B,
2070    ) -> Result<(), String>
2071    where
2072        R: Into<Option<&'a [u16; 256]>>,
2073        G: Into<Option<&'b [u16; 256]>>,
2074        B: Into<Option<&'c [u16; 256]>>,
2075    {
2076        let unwrapped_red = match red.into() {
2077            Some(values) => values.as_ptr(),
2078            None => ptr::null(),
2079        };
2080        let unwrapped_green = match green.into() {
2081            Some(values) => values.as_ptr(),
2082            None => ptr::null(),
2083        };
2084        let unwrapped_blue = match blue.into() {
2085            Some(values) => values.as_ptr(),
2086            None => ptr::null(),
2087        };
2088        let result = unsafe {
2089            sys::SDL_SetWindowGammaRamp(
2090                self.context.raw,
2091                unwrapped_red,
2092                unwrapped_green,
2093                unwrapped_blue,
2094            )
2095        };
2096        if result != 0 {
2097            Err(get_error())
2098        } else {
2099            Ok(())
2100        }
2101    }
2102
2103    /// Get the gamma ramp in form of 3 vectors for a given window's display.
2104    ///
2105    /// This method retrieves the gamma ramp of the entire display,
2106    /// not an individual window.
2107    /// A window is considered to be owned by the display that contains the window's center pixel.
2108    #[allow(clippy::type_complexity)]
2109    #[doc(alias = "SDL_GetWindowGammaRamp")]
2110    pub fn gamma_ramp(&self) -> Result<(Vec<u16>, Vec<u16>, Vec<u16>), String> {
2111        let mut red: Vec<u16> = vec![0; 256];
2112        let mut green: Vec<u16> = vec![0; 256];
2113        let mut blue: Vec<u16> = vec![0; 256];
2114        let result = unsafe {
2115            sys::SDL_GetWindowGammaRamp(
2116                self.context.raw,
2117                red.as_mut_ptr(),
2118                green.as_mut_ptr(),
2119                blue.as_mut_ptr(),
2120            )
2121        };
2122        if result == 0 {
2123            Ok((red, green, blue))
2124        } else {
2125            Err(get_error())
2126        }
2127    }
2128
2129    /// Get the gamma ramp in form of 3 arrays for a given window's display.
2130    ///
2131    /// Despite the name and signature, this method retrieves the gamma ramp of the entire display,
2132    /// not an individual window.
2133    /// A window is considered to be owned by the display that contains the window's center pixel.
2134    #[doc(alias = "SDL_GetWindowGammaRamp")]
2135    pub fn gamma_ramp_arrays(&self) -> Result<[[u16; 256]; 3], String> {
2136        let [mut red, mut green, mut blue] = [mem::MaybeUninit::<[u16; 256]>::uninit(); 3];
2137        let result = unsafe {
2138            sys::SDL_GetWindowGammaRamp(
2139                self.context.raw,
2140                red.as_mut_ptr().cast::<u16>(),
2141                green.as_mut_ptr().cast::<u16>(),
2142                blue.as_mut_ptr().cast::<u16>(),
2143            )
2144        };
2145        if result == 0 {
2146            Ok(unsafe { [red.assume_init(), green.assume_init(), blue.assume_init()] })
2147        } else {
2148            Err(get_error())
2149        }
2150    }
2151
2152    /// Set the transparency of the window. The given value will be clamped internally between
2153    /// `0.0` (fully transparent), and `1.0` (fully opaque).
2154    ///
2155    /// This method returns an error if opacity isn't supported by the current platform.
2156    #[doc(alias = "SDL_SetWindowOpacity")]
2157    pub fn set_opacity(&mut self, opacity: f32) -> Result<(), String> {
2158        let result = unsafe { sys::SDL_SetWindowOpacity(self.context.raw, opacity) };
2159        if result < 0 {
2160            Err(get_error())
2161        } else {
2162            Ok(())
2163        }
2164    }
2165
2166    /// Returns the transparency of the window, as a value between `0.0` (fully transparent), and
2167    /// `1.0` (fully opaque).
2168    ///
2169    /// If opacity isn't supported by the current platform, this method returns `Ok(1.0)` instead
2170    /// of an error.
2171    #[doc(alias = "SDL_GetWindowOpacity")]
2172    pub fn opacity(&self) -> Result<f32, String> {
2173        let mut opacity = 0.0;
2174        let result = unsafe { sys::SDL_GetWindowOpacity(self.context.raw, &mut opacity) };
2175        if result < 0 {
2176            Err(get_error())
2177        } else {
2178            Ok(opacity)
2179        }
2180    }
2181
2182    /// Requests a window to demand attention from the user.
2183    #[doc(alias = "SDL_FlashWindow")]
2184    pub fn flash(&mut self, operation: FlashOperation) -> Result<(), String> {
2185        let result = unsafe { sys::SDL_FlashWindow(self.context.raw, operation.to_ll()) };
2186        if result == 0 {
2187            Ok(())
2188        } else {
2189            Err(get_error())
2190        }
2191    }
2192
2193    /// Makes window appear on top of others.
2194    #[doc(alias = "SDL_SetWindowAlwaysOnTop")]
2195    pub fn set_always_on_top(&mut self, on_top: bool) {
2196        unsafe {
2197            sys::SDL_SetWindowAlwaysOnTop(
2198                self.context.raw,
2199                if on_top {
2200                    sys::SDL_bool::SDL_TRUE
2201                } else {
2202                    sys::SDL_bool::SDL_FALSE
2203                },
2204            )
2205        };
2206    }
2207}
2208
2209#[derive(Copy, Clone)]
2210#[doc(alias = "SDL_GetVideoDriver")]
2211pub struct DriverIterator {
2212    length: i32,
2213    index: i32,
2214}
2215
2216// panics if SDL_GetVideoDriver returns a null pointer,
2217// which only happens if index is outside the range
2218// 0..SDL_GetNumVideoDrivers()
2219fn get_video_driver(index: i32) -> &'static str {
2220    use std::str;
2221
2222    unsafe {
2223        let buf = sys::SDL_GetVideoDriver(index);
2224        assert!(!buf.is_null());
2225
2226        str::from_utf8(CStr::from_ptr(buf as *const _).to_bytes()).unwrap()
2227    }
2228}
2229
2230impl Iterator for DriverIterator {
2231    type Item = &'static str;
2232
2233    #[inline]
2234    fn next(&mut self) -> Option<&'static str> {
2235        if self.index >= self.length {
2236            None
2237        } else {
2238            let driver = get_video_driver(self.index);
2239            self.index += 1;
2240
2241            Some(driver)
2242        }
2243    }
2244
2245    #[inline]
2246    fn size_hint(&self) -> (usize, Option<usize>) {
2247        let remaining = (self.length - self.index) as usize;
2248        (remaining, Some(remaining))
2249    }
2250
2251    #[inline]
2252    fn nth(&mut self, n: usize) -> Option<&'static str> {
2253        use std::convert::TryInto;
2254
2255        self.index = match n.try_into().ok().and_then(|n| self.index.checked_add(n)) {
2256            Some(index) if index < self.length => index,
2257            _ => self.length,
2258        };
2259
2260        self.next()
2261    }
2262}
2263
2264impl DoubleEndedIterator for DriverIterator {
2265    #[inline]
2266    fn next_back(&mut self) -> Option<&'static str> {
2267        if self.index >= self.length {
2268            None
2269        } else {
2270            self.length -= 1;
2271
2272            Some(get_video_driver(self.length))
2273        }
2274    }
2275
2276    #[inline]
2277    fn nth_back(&mut self, n: usize) -> Option<&'static str> {
2278        use std::convert::TryInto;
2279
2280        self.length = match n.try_into().ok().and_then(|n| self.length.checked_sub(n)) {
2281            Some(length) if length > self.index => length,
2282            _ => self.index,
2283        };
2284
2285        self.next_back()
2286    }
2287}
2288
2289impl ExactSizeIterator for DriverIterator {}
2290
2291impl std::iter::FusedIterator for DriverIterator {}
2292
2293/// Gets an iterator of all video drivers compiled into the SDL2 library.
2294#[inline]
2295#[doc(alias = "SDL_GetVideoDriver")]
2296pub fn drivers() -> DriverIterator {
2297    // This function is thread-safe and doesn't require the video subsystem to be initialized.
2298    // The list of drivers are read-only and statically compiled into SDL2, varying by platform.
2299
2300    // SDL_GetNumVideoDrivers can never return a negative value.
2301    DriverIterator {
2302        length: unsafe { sys::SDL_GetNumVideoDrivers() },
2303        index: 0,
2304    }
2305}
2306
2307#[doc(alias = "SDL_CalculateGammaRamp")]
2308pub fn calculate_gamma_ramp(gamma: f32) -> [u16; 256] {
2309    unsafe {
2310        let mut ret = mem::MaybeUninit::<[u16; 256]>::uninit();
2311        sys::SDL_CalculateGammaRamp(gamma as c_float, ret.as_mut_ptr().cast::<u16>());
2312        ret.assume_init()
2313    }
2314}