[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    pub(crate) metal_view: sys::SDL_MetalView,
551}
552
553impl Drop for WindowContext {
554    #[inline]
555    #[doc(alias = "SDL_DestroyWindow")]
556    fn drop(&mut self) {
557        unsafe {
558            if !self.metal_view.is_null() {
559                sys::SDL_Metal_DestroyView(self.metal_view);
560            }
561            sys::SDL_DestroyWindow(self.raw)
562        };
563    }
564}
565
566impl WindowContext {
567    #[inline]
568    /// # Safety
569    ///
570    /// Unsound if the `*mut SDL_Window` is used after the `WindowContext` is dropped
571    pub unsafe fn from_ll(
572        subsystem: VideoSubsystem,
573        raw: *mut sys::SDL_Window,
574        metal_view: sys::SDL_MetalView,
575    ) -> WindowContext {
576        WindowContext {
577            subsystem: subsystem.clone(),
578            raw,
579            metal_view,
580        }
581    }
582}
583
584/// Represents a setting for vsync/swap interval.
585#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
586#[repr(i32)]
587pub enum SwapInterval {
588    Immediate = 0,
589    VSync = 1,
590    LateSwapTearing = -1,
591}
592
593impl From<i32> for SwapInterval {
594    fn from(i: i32) -> Self {
595        match i {
596            -1 => SwapInterval::LateSwapTearing,
597            0 => SwapInterval::Immediate,
598            1 => SwapInterval::VSync,
599            other => panic!(
600                "Invalid value for SwapInterval: {}; valid values are -1, 0, 1",
601                other
602            ),
603        }
604    }
605}
606
607/// Represents orientation of a display.
608#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
609#[repr(i32)]
610pub enum Orientation {
611    /// The display orientation can’t be determined
612    Unknown = sys::SDL_DisplayOrientation::SDL_ORIENTATION_UNKNOWN as i32,
613    /// The display is in landscape mode, with the right side up, relative to portrait mode
614    Landscape = sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE as i32,
615    /// The display is in landscape mode, with the left side up, relative to portrait mode
616    LandscapeFlipped = sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE_FLIPPED as i32,
617    /// The display is in portrait mode
618    Portrait = sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT as i32,
619    /// The display is in portrait mode, upside down
620    PortraitFlipped = sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT_FLIPPED as i32,
621}
622
623impl Orientation {
624    pub fn from_ll(orientation: sys::SDL_DisplayOrientation) -> Orientation {
625        match orientation {
626            sys::SDL_DisplayOrientation::SDL_ORIENTATION_UNKNOWN => Orientation::Unknown,
627            sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE => Orientation::Landscape,
628            sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE_FLIPPED => {
629                Orientation::LandscapeFlipped
630            }
631            sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT => Orientation::Portrait,
632            sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT_FLIPPED => {
633                Orientation::PortraitFlipped
634            }
635        }
636    }
637
638    pub fn to_ll(self) -> sys::SDL_DisplayOrientation {
639        match self {
640            Orientation::Unknown => sys::SDL_DisplayOrientation::SDL_ORIENTATION_UNKNOWN,
641            Orientation::Landscape => sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE,
642            Orientation::LandscapeFlipped => {
643                sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE_FLIPPED
644            }
645            Orientation::Portrait => sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT,
646            Orientation::PortraitFlipped => {
647                sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT_FLIPPED
648            }
649        }
650    }
651}
652
653/// Represents a setting for a window flash operation.
654#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
655#[repr(i32)]
656pub enum FlashOperation {
657    /// Cancel any window flash state
658    Cancel = sys::SDL_FlashOperation::SDL_FLASH_CANCEL as i32,
659    /// Flash the window briefly to get attention
660    Briefly = sys::SDL_FlashOperation::SDL_FLASH_BRIEFLY as i32,
661    /// Flash the window until it gets focus
662    UntilFocused = sys::SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED as i32,
663}
664
665impl FlashOperation {
666    pub fn from_ll(flash_operation: sys::SDL_FlashOperation) -> FlashOperation {
667        match flash_operation {
668            sys::SDL_FlashOperation::SDL_FLASH_CANCEL => FlashOperation::Cancel,
669            sys::SDL_FlashOperation::SDL_FLASH_BRIEFLY => FlashOperation::Briefly,
670            sys::SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED => FlashOperation::UntilFocused,
671        }
672    }
673
674    pub fn to_ll(self) -> sys::SDL_FlashOperation {
675        match self {
676            FlashOperation::Cancel => sys::SDL_FlashOperation::SDL_FLASH_CANCEL,
677            FlashOperation::Briefly => sys::SDL_FlashOperation::SDL_FLASH_BRIEFLY,
678            FlashOperation::UntilFocused => sys::SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED,
679        }
680    }
681}
682
683/// Represents the "shell" of a `Window`.
684///
685/// You can set get and set many of the `SDL_Window` properties (i.e., border, size, `PixelFormat`, etc)
686///
687/// However, you cannot directly access the pixels of the `Window`.
688/// It needs to be converted to a `Canvas` to access the rendering functions.
689///
690/// Note: If a `Window` goes out of scope but it cloned its context,
691/// then the `SDL_Window` will not be destroyed until there are no more references to the `WindowContext`.
692/// This may happen when a `TextureCreator<Window>` outlives the `Canvas<Window>`
693#[derive(Clone)]
694pub struct Window {
695    context: Rc<WindowContext>,
696}
697
698impl From<WindowContext> for Window {
699    fn from(context: WindowContext) -> Window {
700        Window {
701            context: Rc::new(context),
702        }
703    }
704}
705
706impl_raw_accessors!((GLContext, sys::SDL_GLContext));
707
708impl VideoSubsystem {
709    /// Initializes a new `WindowBuilder`; a convenience method that calls `WindowBuilder::new()`.
710    pub fn window(&self, title: &str, width: u32, height: u32) -> WindowBuilder {
711        WindowBuilder::new(self, title, width, height)
712    }
713
714    #[doc(alias = "SDL_GetCurrentVideoDriver")]
715    pub fn current_video_driver(&self) -> &'static str {
716        use std::str;
717
718        unsafe {
719            let buf = sys::SDL_GetCurrentVideoDriver();
720            assert!(!buf.is_null());
721
722            str::from_utf8(CStr::from_ptr(buf as *const _).to_bytes()).unwrap()
723        }
724    }
725
726    #[doc(alias = "SDL_GetNumVideoDisplays")]
727    pub fn num_video_displays(&self) -> Result<i32, String> {
728        let result = unsafe { sys::SDL_GetNumVideoDisplays() };
729        if result < 0 {
730            Err(get_error())
731        } else {
732            Ok(result as i32)
733        }
734    }
735
736    /// Get the name of the display at the index `display_name`.
737    ///
738    /// Will return an error if the index is out of bounds or if SDL experienced a failure; inspect
739    /// the returned string for further info.
740    #[doc(alias = "SDL_GetDisplayName")]
741    pub fn display_name(&self, display_index: i32) -> Result<String, String> {
742        unsafe {
743            let display = sys::SDL_GetDisplayName(display_index as c_int);
744            if display.is_null() {
745                Err(get_error())
746            } else {
747                Ok(CStr::from_ptr(display as *const _)
748                    .to_str()
749                    .unwrap()
750                    .to_owned())
751            }
752        }
753    }
754
755    #[doc(alias = "SDL_GetDisplayBounds")]
756    pub fn display_bounds(&self, display_index: i32) -> Result<Rect, String> {
757        let mut out = mem::MaybeUninit::uninit();
758        let result =
759            unsafe { sys::SDL_GetDisplayBounds(display_index as c_int, out.as_mut_ptr()) == 0 };
760
761        if result {
762            let out = unsafe { out.assume_init() };
763            Ok(Rect::from_ll(out))
764        } else {
765            Err(get_error())
766        }
767    }
768
769    #[doc(alias = "SDL_GetDisplayUsableBounds")]
770    pub fn display_usable_bounds(&self, display_index: i32) -> Result<Rect, String> {
771        let mut out = mem::MaybeUninit::uninit();
772        let result =
773            unsafe { sys::SDL_GetDisplayUsableBounds(display_index as c_int, out.as_mut_ptr()) };
774        if result == 0 {
775            let out = unsafe { out.assume_init() };
776            Ok(Rect::from_ll(out))
777        } else {
778            Err(get_error())
779        }
780    }
781
782    #[doc(alias = "SDL_GetNumDisplayModes")]
783    pub fn num_display_modes(&self, display_index: i32) -> Result<i32, String> {
784        let result = unsafe { sys::SDL_GetNumDisplayModes(display_index as c_int) };
785        if result < 0 {
786            Err(get_error())
787        } else {
788            Ok(result as i32)
789        }
790    }
791
792    #[doc(alias = "SDL_GetDisplayMode")]
793    pub fn display_mode(&self, display_index: i32, mode_index: i32) -> Result<DisplayMode, String> {
794        let mut dm = mem::MaybeUninit::uninit();
795        let result = unsafe {
796            sys::SDL_GetDisplayMode(display_index as c_int, mode_index as c_int, dm.as_mut_ptr())
797                == 0
798        };
799
800        if result {
801            let dm = unsafe { dm.assume_init() };
802            Ok(DisplayMode::from_ll(&dm))
803        } else {
804            Err(get_error())
805        }
806    }
807
808    #[doc(alias = "SDL_GetDesktopDisplayMode")]
809    pub fn desktop_display_mode(&self, display_index: i32) -> Result<DisplayMode, String> {
810        let mut dm = mem::MaybeUninit::uninit();
811        let result =
812            unsafe { sys::SDL_GetDesktopDisplayMode(display_index as c_int, dm.as_mut_ptr()) == 0 };
813
814        if result {
815            let dm = unsafe { dm.assume_init() };
816            Ok(DisplayMode::from_ll(&dm))
817        } else {
818            Err(get_error())
819        }
820    }
821
822    #[doc(alias = "SDL_GetCurrentDisplayMode")]
823    pub fn current_display_mode(&self, display_index: i32) -> Result<DisplayMode, String> {
824        let mut dm = mem::MaybeUninit::uninit();
825        let result =
826            unsafe { sys::SDL_GetCurrentDisplayMode(display_index as c_int, dm.as_mut_ptr()) == 0 };
827
828        if result {
829            let dm = unsafe { dm.assume_init() };
830            Ok(DisplayMode::from_ll(&dm))
831        } else {
832            Err(get_error())
833        }
834    }
835
836    #[doc(alias = "SDL_GetClosestDisplayMode")]
837    pub fn closest_display_mode(
838        &self,
839        display_index: i32,
840        mode: &DisplayMode,
841    ) -> Result<DisplayMode, String> {
842        let input = mode.to_ll();
843        let mut dm = mem::MaybeUninit::uninit();
844
845        let result = unsafe {
846            sys::SDL_GetClosestDisplayMode(display_index as c_int, &input, dm.as_mut_ptr())
847        };
848
849        if result.is_null() {
850            Err(get_error())
851        } else {
852            let dm = unsafe { dm.assume_init() };
853            Ok(DisplayMode::from_ll(&dm))
854        }
855    }
856
857    /// Return a triplet `(ddpi, hdpi, vdpi)` containing the diagonal, horizontal and vertical
858    /// dots/pixels-per-inch of a display
859    #[doc(alias = "SDL_GetDisplayDPI")]
860    pub fn display_dpi(&self, display_index: i32) -> Result<(f32, f32, f32), String> {
861        let mut ddpi = 0.0;
862        let mut hdpi = 0.0;
863        let mut vdpi = 0.0;
864        let result = unsafe {
865            sys::SDL_GetDisplayDPI(display_index as c_int, &mut ddpi, &mut hdpi, &mut vdpi)
866        };
867        if result < 0 {
868            Err(get_error())
869        } else {
870            Ok((ddpi, hdpi, vdpi))
871        }
872    }
873
874    /// Return orientation of a display or Unknown if orientation could not be determined.
875    #[doc(alias = "SDL_GetDisplayOrientation")]
876    pub fn display_orientation(&self, display_index: i32) -> Orientation {
877        Orientation::from_ll(unsafe { sys::SDL_GetDisplayOrientation(display_index as c_int) })
878    }
879
880    #[doc(alias = "SDL_IsScreenSaverEnabled")]
881    pub fn is_screen_saver_enabled(&self) -> bool {
882        unsafe { sys::SDL_IsScreenSaverEnabled() == sys::SDL_bool::SDL_TRUE }
883    }
884
885    #[doc(alias = "SDL_EnableScreenSaver")]
886    pub fn enable_screen_saver(&self) {
887        unsafe { sys::SDL_EnableScreenSaver() }
888    }
889
890    #[doc(alias = "SDL_DisableScreenSaver")]
891    pub fn disable_screen_saver(&self) {
892        unsafe { sys::SDL_DisableScreenSaver() }
893    }
894
895    /// Loads the default OpenGL library.
896    ///
897    /// This should be done after initializing the video driver, but before creating any OpenGL windows.
898    /// If no OpenGL library is loaded, the default library will be loaded upon creation of the first OpenGL window.
899    ///
900    /// If a different library is already loaded, this function will return an error.
901    #[doc(alias = "SDL_GL_LoadLibrary")]
902    pub fn gl_load_library_default(&self) -> Result<(), String> {
903        unsafe {
904            if sys::SDL_GL_LoadLibrary(ptr::null()) == 0 {
905                Ok(())
906            } else {
907                Err(get_error())
908            }
909        }
910    }
911
912    /// Loads the OpenGL library using a platform-dependent OpenGL library name (usually a file path).
913    ///
914    /// This should be done after initializing the video driver, but before creating any OpenGL windows.
915    /// If no OpenGL library is loaded, the default library will be loaded upon creation of the first OpenGL window.
916    ///
917    /// If a different library is already loaded, this function will return an error.
918    #[doc(alias = "SDL_GL_LoadLibrary")]
919    pub fn gl_load_library<P: AsRef<::std::path::Path>>(&self, path: P) -> Result<(), String> {
920        unsafe {
921            // TODO: use OsStr::to_cstring() once it's stable
922            let path = CString::new(path.as_ref().to_str().unwrap()).unwrap();
923            if sys::SDL_GL_LoadLibrary(path.as_ptr() as *const c_char) == 0 {
924                Ok(())
925            } else {
926                Err(get_error())
927            }
928        }
929    }
930
931    /// Unloads the current OpenGL library.
932    ///
933    /// To completely unload the library, this should be called for every successful load of the
934    /// OpenGL library.
935    #[doc(alias = "SDL_GL_UnloadLibrary")]
936    pub fn gl_unload_library(&self) {
937        unsafe {
938            sys::SDL_GL_UnloadLibrary();
939        }
940    }
941
942    /// Gets the pointer to the named OpenGL function.
943    ///
944    /// This is useful for OpenGL wrappers such as [`gl-rs`](https://github.com/bjz/gl-rs).
945    #[doc(alias = "SDL_GL_GetProcAddress")]
946    pub fn gl_get_proc_address(&self, procname: &str) -> *const () {
947        match CString::new(procname) {
948            Ok(procname) => unsafe {
949                sys::SDL_GL_GetProcAddress(procname.as_ptr() as *const c_char) as *const ()
950            },
951            // string contains a nul byte - it won't match anything.
952            Err(_) => ptr::null(),
953        }
954    }
955
956    #[doc(alias = "SDL_GL_ExtensionSupported")]
957    pub fn gl_extension_supported(&self, extension: &str) -> bool {
958        match CString::new(extension) {
959            Ok(extension) => unsafe {
960                sys::SDL_GL_ExtensionSupported(extension.as_ptr() as *const c_char)
961                    != sys::SDL_bool::SDL_FALSE
962            },
963            // string contains a nul byte - it won't match anything.
964            Err(_) => false,
965        }
966    }
967
968    #[doc(alias = "SDL_GL_GetCurrentWindow")]
969    pub fn gl_get_current_window_id(&self) -> Result<u32, String> {
970        let raw = unsafe { sys::SDL_GL_GetCurrentWindow() };
971        if raw.is_null() {
972            Err(get_error())
973        } else {
974            let id = unsafe { sys::SDL_GetWindowID(raw) };
975            Ok(id)
976        }
977    }
978
979    /// Releases the thread's current OpenGL context, i.e. sets the current OpenGL context to nothing.
980    #[doc(alias = "SDL_GL_MakeCurrent")]
981    pub fn gl_release_current_context(&self) -> Result<(), String> {
982        let result = unsafe { sys::SDL_GL_MakeCurrent(ptr::null_mut(), ptr::null_mut()) };
983
984        if result == 0 {
985            Ok(())
986        } else {
987            Err(get_error())
988        }
989    }
990
991    #[doc(alias = "SDL_GL_SetSwapInterval")]
992    pub fn gl_set_swap_interval<S: Into<SwapInterval>>(&self, interval: S) -> Result<(), String> {
993        let result = unsafe { sys::SDL_GL_SetSwapInterval(interval.into() as c_int) };
994        if result == 0 {
995            Ok(())
996        } else {
997            Err(get_error())
998        }
999    }
1000
1001    #[doc(alias = "SDL_GL_GetSwapInterval")]
1002    pub fn gl_get_swap_interval(&self) -> SwapInterval {
1003        unsafe {
1004            let interval = sys::SDL_GL_GetSwapInterval() as i32;
1005            assert!(interval == -1 || interval == 0 || interval == 1);
1006            mem::transmute(interval)
1007        }
1008    }
1009
1010    /// Loads the default Vulkan library.
1011    ///
1012    /// This should be done after initializing the video driver, but before creating any Vulkan windows.
1013    /// If no Vulkan library is loaded, the default library will be loaded upon creation of the first Vulkan window.
1014    ///
1015    /// If a different library is already loaded, this function will return an error.
1016    #[doc(alias = "SDL_Vulkan_LoadLibrary")]
1017    pub fn vulkan_load_library_default(&self) -> Result<(), String> {
1018        unsafe {
1019            if sys::SDL_Vulkan_LoadLibrary(ptr::null()) == 0 {
1020                Ok(())
1021            } else {
1022                Err(get_error())
1023            }
1024        }
1025    }
1026
1027    /// Loads the Vulkan library using a platform-dependent Vulkan library name (usually a file path).
1028    ///
1029    /// This should be done after initializing the video driver, but before creating any Vulkan windows.
1030    /// If no Vulkan library is loaded, the default library will be loaded upon creation of the first Vulkan window.
1031    ///
1032    /// If a different library is already loaded, this function will return an error.
1033    #[doc(alias = "SDL_Vulkan_LoadLibrary")]
1034    pub fn vulkan_load_library<P: AsRef<::std::path::Path>>(&self, path: P) -> Result<(), String> {
1035        unsafe {
1036            // TODO: use OsStr::to_cstring() once it's stable
1037            let path = CString::new(path.as_ref().to_str().unwrap()).unwrap();
1038            if sys::SDL_Vulkan_LoadLibrary(path.as_ptr() as *const c_char) == 0 {
1039                Ok(())
1040            } else {
1041                Err(get_error())
1042            }
1043        }
1044    }
1045
1046    /// Unloads the current Vulkan library.
1047    ///
1048    /// To completely unload the library, this should be called for every successful load of the
1049    /// Vulkan library.
1050    #[doc(alias = "SDL_Vulkan_UnloadLibrary")]
1051    pub fn vulkan_unload_library(&self) {
1052        unsafe {
1053            sys::SDL_Vulkan_UnloadLibrary();
1054        }
1055    }
1056
1057    /// Gets the pointer to the
1058    /// [`vkGetInstanceProcAddr`](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetInstanceProcAddr.html)
1059    /// Vulkan function. This function can be called to retrieve the address of other Vulkan
1060    /// functions.
1061    #[doc(alias = "SDL_Vulkan_GetVkGetInstanceProcAddr")]
1062    pub fn vulkan_get_proc_address_function(&self) -> Result<*const (), String> {
1063        let result = unsafe { sys::SDL_Vulkan_GetVkGetInstanceProcAddr() as *const () };
1064        if result.is_null() {
1065            Err(get_error())
1066        } else {
1067            Ok(result)
1068        }
1069    }
1070}
1071
1072#[derive(Debug, Clone)]
1073pub enum WindowBuildError {
1074    HeightOverflows(u32),
1075    WidthOverflows(u32),
1076    InvalidTitle(NulError),
1077    SdlError(String),
1078}
1079
1080impl fmt::Display for WindowBuildError {
1081    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1082        use self::WindowBuildError::*;
1083
1084        match *self {
1085            HeightOverflows(h) => write!(f, "Window height ({}) is too high.", h),
1086            WidthOverflows(w) => write!(f, "Window width ({}) is too high.", w),
1087            InvalidTitle(ref e) => write!(f, "Invalid window title: {}", e),
1088            SdlError(ref e) => write!(f, "SDL error: {}", e),
1089        }
1090    }
1091}
1092
1093impl Error for WindowBuildError {
1094    fn source(&self) -> Option<&(dyn Error + 'static)> {
1095        match self {
1096            Self::InvalidTitle(err) => Some(err),
1097            Self::HeightOverflows(_) | Self::WidthOverflows(_) | Self::SdlError(_) => None,
1098        }
1099    }
1100}
1101
1102/// The type that allows you to build windows.
1103#[derive(Debug)]
1104pub struct WindowBuilder {
1105    title: String,
1106    width: u32,
1107    height: u32,
1108    x: WindowPos,
1109    y: WindowPos,
1110    window_flags: u32,
1111    create_metal_view: bool,
1112    /// The window builder cannot be built on a non-main thread, so prevent cross-threaded moves and references.
1113    /// `!Send` and `!Sync`,
1114    subsystem: VideoSubsystem,
1115    shaped: bool,
1116}
1117
1118impl WindowBuilder {
1119    /// Initializes a new `WindowBuilder`.
1120    pub fn new(v: &VideoSubsystem, title: &str, width: u32, height: u32) -> WindowBuilder {
1121        WindowBuilder {
1122            title: title.to_owned(),
1123            width,
1124            height,
1125            x: WindowPos::Undefined,
1126            y: WindowPos::Undefined,
1127            window_flags: 0,
1128            subsystem: v.clone(),
1129            create_metal_view: false,
1130            shaped: false,
1131        }
1132    }
1133
1134    /// Builds the window.
1135    #[doc(alias = "SDL_CreateWindow")]
1136    pub fn build(&self) -> Result<Window, WindowBuildError> {
1137        use self::WindowBuildError::*;
1138        let title = match CString::new(self.title.as_bytes()) {
1139            Ok(t) => t,
1140            Err(err) => return Err(InvalidTitle(err)),
1141        };
1142        if self.width >= (1 << 31) {
1143            return Err(WidthOverflows(self.width));
1144        }
1145        if self.height >= (1 << 31) {
1146            return Err(HeightOverflows(self.width));
1147        }
1148
1149        let raw_width = self.width as c_int;
1150        let raw_height = self.height as c_int;
1151        unsafe {
1152            let raw = if self.shaped {
1153                sys::SDL_CreateShapedWindow(
1154                    title.as_ptr() as *const c_char,
1155                    to_ll_windowpos(self.x) as u32,
1156                    to_ll_windowpos(self.y) as u32,
1157                    raw_width as u32,
1158                    raw_height as u32,
1159                    self.window_flags,
1160                )
1161            } else {
1162                sys::SDL_CreateWindow(
1163                    title.as_ptr() as *const c_char,
1164                    to_ll_windowpos(self.x),
1165                    to_ll_windowpos(self.y),
1166                    raw_width,
1167                    raw_height,
1168                    self.window_flags,
1169                )
1170            };
1171
1172            if raw.is_null() {
1173                Err(SdlError(get_error()))
1174            } else {
1175                let metal_view = match self.create_metal_view {
1176                    #[cfg(target_os = "macos")]
1177                    true => sys::SDL_Metal_CreateView(raw),
1178                    _ => 0 as sys::SDL_MetalView,
1179                };
1180
1181                Ok(Window::from_ll(self.subsystem.clone(), raw, metal_view))
1182            }
1183        }
1184    }
1185
1186    /// Gets the underlying window flags.
1187    pub fn window_flags(&self) -> u32 {
1188        self.window_flags
1189    }
1190
1191    /// Sets the underlying window flags.
1192    /// This will effectively undo any previous build operations, excluding window size and position.
1193    pub fn set_window_flags(&mut self, flags: u32) -> &mut WindowBuilder {
1194        self.window_flags = flags;
1195        self
1196    }
1197
1198    /// Sets the window position.
1199    pub fn position(&mut self, x: i32, y: i32) -> &mut WindowBuilder {
1200        self.x = WindowPos::Positioned(x);
1201        self.y = WindowPos::Positioned(y);
1202        self
1203    }
1204
1205    /// Centers the window.
1206    pub fn position_centered(&mut self) -> &mut WindowBuilder {
1207        self.x = WindowPos::Centered;
1208        self.y = WindowPos::Centered;
1209        self
1210    }
1211
1212    /// Sets the window to fullscreen.
1213    pub fn fullscreen(&mut self) -> &mut WindowBuilder {
1214        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_FULLSCREEN as u32;
1215        self
1216    }
1217
1218    /// Sets the window to fullscreen at the current desktop resolution.
1219    pub fn fullscreen_desktop(&mut self) -> &mut WindowBuilder {
1220        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_FULLSCREEN_DESKTOP as u32;
1221        self
1222    }
1223
1224    /// Sets the window to be usable with an OpenGL context
1225    pub fn opengl(&mut self) -> &mut WindowBuilder {
1226        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_OPENGL as u32;
1227        self
1228    }
1229
1230    /// Sets the window to be usable with a Vulkan instance
1231    pub fn vulkan(&mut self) -> &mut WindowBuilder {
1232        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_VULKAN as u32;
1233        self
1234    }
1235
1236    /// Hides the window.
1237    pub fn hidden(&mut self) -> &mut WindowBuilder {
1238        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_HIDDEN as u32;
1239        self
1240    }
1241
1242    /// Removes the window decoration.
1243    pub fn borderless(&mut self) -> &mut WindowBuilder {
1244        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_BORDERLESS as u32;
1245        self
1246    }
1247
1248    /// Sets the window to be resizable.
1249    pub fn resizable(&mut self) -> &mut WindowBuilder {
1250        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_RESIZABLE as u32;
1251        self
1252    }
1253
1254    /// Minimizes the window.
1255    pub fn minimized(&mut self) -> &mut WindowBuilder {
1256        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_MINIMIZED as u32;
1257        self
1258    }
1259
1260    /// Maximizes the window.
1261    pub fn maximized(&mut self) -> &mut WindowBuilder {
1262        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_MAXIMIZED as u32;
1263        self
1264    }
1265
1266    /// Sets the window to have grabbed input focus.
1267    pub fn input_grabbed(&mut self) -> &mut WindowBuilder {
1268        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_INPUT_GRABBED as u32;
1269        self
1270    }
1271
1272    /// Creates the window in high-DPI mode if supported (>= SDL 2.0.1)
1273    pub fn allow_highdpi(&mut self) -> &mut WindowBuilder {
1274        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_ALLOW_HIGHDPI as u32;
1275        self
1276    }
1277
1278    /// Window should always above others (>= SDL 2.0.5)
1279    pub fn always_on_top(&mut self) -> &mut WindowBuilder {
1280        self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_ALWAYS_ON_TOP as u32;
1281        self
1282    }
1283
1284    /// Create a SDL_MetalView when constructing the window.
1285    /// This is required when using the raw_window_handle feature on MacOS.
1286    /// Has no effect no other platforms.
1287    pub fn metal_view(&mut self) -> &mut WindowBuilder {
1288        self.create_metal_view = true;
1289        self
1290    }
1291
1292    /// Sets shaped state, to create via SDL_CreateShapedWindow instead of SDL_CreateWindow
1293    pub fn set_shaped(&mut self) -> &mut WindowBuilder {
1294        self.shaped = true;
1295        self
1296    }
1297}
1298
1299impl From<Window> for CanvasBuilder {
1300    fn from(window: Window) -> CanvasBuilder {
1301        CanvasBuilder::new(window)
1302    }
1303}
1304
1305impl Window {
1306    #[inline]
1307    // this can prevent introducing UB until
1308    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
1309    #[allow(clippy::trivially_copy_pass_by_ref)]
1310    pub fn raw(&self) -> *mut sys::SDL_Window {
1311        self.context.raw
1312    }
1313
1314    #[inline]
1315    pub unsafe fn from_ll(
1316        subsystem: VideoSubsystem,
1317        raw: *mut sys::SDL_Window,
1318        metal_view: sys::SDL_MetalView,
1319    ) -> Window {
1320        let context = WindowContext::from_ll(subsystem, raw, metal_view);
1321        context.into()
1322    }
1323
1324    #[inline]
1325    /// Create a new `Window` without taking ownership of the `WindowContext`
1326    pub const fn from_ref(context: Rc<WindowContext>) -> Window {
1327        Window { context }
1328    }
1329
1330    #[inline]
1331    pub fn subsystem(&self) -> &VideoSubsystem {
1332        &self.context.subsystem
1333    }
1334
1335    /// Initializes a new `CanvasBuilder`; a convenience method that calls `CanvasBuilder::new()`.
1336    pub fn into_canvas(self) -> CanvasBuilder {
1337        self.into()
1338    }
1339
1340    pub fn context(&self) -> Rc<WindowContext> {
1341        self.context.clone()
1342    }
1343
1344    #[doc(alias = "SDL_GetWindowID")]
1345    pub fn id(&self) -> u32 {
1346        unsafe { sys::SDL_GetWindowID(self.context.raw) }
1347    }
1348
1349    #[doc(alias = "SDL_GL_CreateContext")]
1350    pub fn gl_create_context(&self) -> Result<GLContext, String> {
1351        let result = unsafe { sys::SDL_GL_CreateContext(self.context.raw) };
1352        if result.is_null() {
1353            Err(get_error())
1354        } else {
1355            Ok(GLContext { raw: result })
1356        }
1357    }
1358
1359    #[doc(alias = "SDL_GL_GetCurrentContext")]
1360    pub unsafe fn gl_get_current_context(&self) -> Option<GLContext> {
1361        let context_raw = sys::SDL_GL_GetCurrentContext();
1362
1363        if !context_raw.is_null() {
1364            Some(GLContext { raw: context_raw })
1365        } else {
1366            None
1367        }
1368    }
1369
1370    /// Set the window's OpenGL context to the current context on the thread.
1371    #[doc(alias = "SDL_GL_MakeCurrent")]
1372    pub fn gl_set_context_to_current(&self) -> Result<(), String> {
1373        unsafe {
1374            let context_raw = sys::SDL_GL_GetCurrentContext();
1375
1376            if !context_raw.is_null() && sys::SDL_GL_MakeCurrent(self.context.raw, context_raw) == 0
1377            {
1378                Ok(())
1379            } else {
1380                Err(get_error())
1381            }
1382        }
1383    }
1384
1385    #[doc(alias = "SDL_GL_MakeCurrent")]
1386    pub fn gl_make_current(&self, context: &GLContext) -> Result<(), String> {
1387        unsafe {
1388            if sys::SDL_GL_MakeCurrent(self.context.raw, context.raw) == 0 {
1389                Ok(())
1390            } else {
1391                Err(get_error())
1392            }
1393        }
1394    }
1395
1396    #[doc(alias = "SDL_GL_SwapWindow")]
1397    pub fn gl_swap_window(&self) {
1398        unsafe { sys::SDL_GL_SwapWindow(self.context.raw) }
1399    }
1400
1401    /// Get the names of the Vulkan instance extensions needed to create a surface with `vulkan_create_surface`.
1402    #[doc(alias = "SDL_Vulkan_GetInstanceExtensions")]
1403    pub fn vulkan_instance_extensions(&self) -> Result<Vec<&'static str>, String> {
1404        let mut count: c_uint = 0;
1405        if unsafe {
1406            sys::SDL_Vulkan_GetInstanceExtensions(self.context.raw, &mut count, ptr::null_mut())
1407        } == sys::SDL_bool::SDL_FALSE
1408        {
1409            return Err(get_error());
1410        }
1411        let mut names: Vec<*const c_char> = vec![ptr::null(); count as usize];
1412        if unsafe {
1413            sys::SDL_Vulkan_GetInstanceExtensions(self.context.raw, &mut count, names.as_mut_ptr())
1414        } == sys::SDL_bool::SDL_FALSE
1415        {
1416            return Err(get_error());
1417        }
1418        Ok(names
1419            .iter()
1420            .map(|&val| unsafe { CStr::from_ptr(val) }.to_str().unwrap())
1421            .collect())
1422    }
1423
1424    /// Create a Vulkan rendering surface for a window.
1425    ///
1426    /// The `VkInstance` must be created using a prior call to the
1427    /// [`vkCreateInstance`](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateInstance.html)
1428    /// function in the Vulkan library.
1429    #[doc(alias = "SDL_Vulkan_CreateSurface")]
1430    pub fn vulkan_create_surface(&self, instance: VkInstance) -> Result<VkSurfaceKHR, String> {
1431        let mut surface: VkSurfaceKHR = 0;
1432        if unsafe { sys::SDL_Vulkan_CreateSurface(self.context.raw, instance, &mut surface) }
1433            == sys::SDL_bool::SDL_FALSE
1434        {
1435            Err(get_error())
1436        } else {
1437            Ok(surface)
1438        }
1439    }
1440
1441    #[doc(alias = "SDL_GetWindowDisplayIndex")]
1442    pub fn display_index(&self) -> Result<i32, String> {
1443        let result = unsafe { sys::SDL_GetWindowDisplayIndex(self.context.raw) };
1444        if result < 0 {
1445            Err(get_error())
1446        } else {
1447            Ok(result as i32)
1448        }
1449    }
1450
1451    #[doc(alias = "SDL_SetWindowDisplayMode")]
1452    pub fn set_display_mode<D>(&mut self, display_mode: D) -> Result<(), String>
1453    where
1454        D: Into<Option<DisplayMode>>,
1455    {
1456        unsafe {
1457            let result = sys::SDL_SetWindowDisplayMode(
1458                self.context.raw,
1459                match display_mode.into() {
1460                    Some(ref mode) => &mode.to_ll(),
1461                    None => ptr::null(),
1462                },
1463            );
1464            if result < 0 {
1465                Err(get_error())
1466            } else {
1467                Ok(())
1468            }
1469        }
1470    }
1471
1472    #[doc(alias = "SDL_GetWindowDisplayMode")]
1473    pub fn display_mode(&self) -> Result<DisplayMode, String> {
1474        let mut dm = mem::MaybeUninit::uninit();
1475
1476        let result =
1477            unsafe { sys::SDL_GetWindowDisplayMode(self.context.raw, dm.as_mut_ptr()) == 0 };
1478
1479        if result {
1480            let dm = unsafe { dm.assume_init() };
1481            Ok(DisplayMode::from_ll(&dm))
1482        } else {
1483            Err(get_error())
1484        }
1485    }
1486
1487    #[doc(alias = "SDL_GetWindowICCProfile")]
1488    pub fn icc_profile(&self) -> Result<Vec<u8>, String> {
1489        unsafe {
1490            let mut size: libc::size_t = 0;
1491            let data = sys::SDL_GetWindowICCProfile(self.context.raw, &mut size as *mut _);
1492            if data.is_null() {
1493                return Err(get_error());
1494            }
1495            let mut result = vec![0; size as usize];
1496            result.copy_from_slice(std::slice::from_raw_parts(data as *const u8, size as usize));
1497            sys::SDL_free(data);
1498            Ok(result)
1499        }
1500    }
1501
1502    #[doc(alias = "SDL_GetWindowPixelFormat")]
1503    pub fn window_pixel_format(&self) -> PixelFormatEnum {
1504        unsafe {
1505            PixelFormatEnum::try_from(sys::SDL_GetWindowPixelFormat(self.context.raw) as u32)
1506                .unwrap()
1507        }
1508    }
1509
1510    #[doc(alias = "SDL_GetWindowFlags")]
1511    pub fn window_flags(&self) -> u32 {
1512        unsafe { sys::SDL_GetWindowFlags(self.context.raw) }
1513    }
1514
1515    /// Does the window have input focus?
1516    pub fn has_input_focus(&self) -> bool {
1517        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_INPUT_FOCUS as u32
1518    }
1519
1520    /// Has the window grabbed input focus?
1521    pub fn has_input_grabbed(&self) -> bool {
1522        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_INPUT_GRABBED as u32
1523    }
1524
1525    /// Does the window have mouse focus?
1526    pub fn has_mouse_focus(&self) -> bool {
1527        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_MOUSE_FOCUS as u32
1528    }
1529
1530    /// Is the window maximized?
1531    pub fn is_maximized(&self) -> bool {
1532        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_MAXIMIZED as u32
1533    }
1534
1535    /// Is the window minimized?
1536    pub fn is_minimized(&self) -> bool {
1537        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_MINIMIZED as u32
1538    }
1539
1540    /// Is the window always on top?
1541    pub fn is_always_on_top(&self) -> bool {
1542        0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_ALWAYS_ON_TOP as u32
1543    }
1544
1545    #[doc(alias = "SDL_SetWindowTitle")]
1546    pub fn set_title(&mut self, title: &str) -> Result<(), NulError> {
1547        let title = CString::new(title)?;
1548        unsafe {
1549            sys::SDL_SetWindowTitle(self.context.raw, title.as_ptr() as *const c_char);
1550        }
1551        Ok(())
1552    }
1553
1554    #[doc(alias = "SDL_SetWindowResizable")]
1555    pub fn set_resizable(&mut self, resizable: bool) {
1556        let resizable = if resizable {
1557            sys::SDL_bool::SDL_TRUE
1558        } else {
1559            sys::SDL_bool::SDL_FALSE
1560        };
1561        unsafe {
1562            sys::SDL_SetWindowResizable(self.context.raw, resizable);
1563        }
1564    }
1565
1566    /// Set the shape of the window
1567    /// To be effective:
1568    /// - shaped must have been set using windows builder
1569    /// - binarizationCutoff: specify the cutoff value for the shape's alpha
1570    ///   channel: At or above that cutoff value, a pixel is visible in the
1571    ///   shape. Below that, it's not part of the shape.
1572    pub fn set_window_shape_alpha<S: AsRef<SurfaceRef>>(
1573        &mut self,
1574        shape: S,
1575        binarization_cutoff: u8,
1576    ) -> Result<(), i32> {
1577        let mode = sys::WindowShapeMode::ShapeModeBinarizeAlpha;
1578        let parameters = sys::SDL_WindowShapeParams {
1579            binarizationCutoff: binarization_cutoff,
1580        };
1581        let mut shape_mode = sys::SDL_WindowShapeMode { mode, parameters };
1582        let result = unsafe {
1583            sys::SDL_SetWindowShape(self.context.raw, shape.as_ref().raw(), &mut shape_mode)
1584        };
1585        if result == 0 {
1586            Ok(())
1587        } else {
1588            Err(result)
1589        }
1590    }
1591
1592    #[doc(alias = "SDL_GetWindowTitle")]
1593    pub fn title(&self) -> &str {
1594        unsafe {
1595            let buf = sys::SDL_GetWindowTitle(self.context.raw);
1596
1597            // The window title must be encoded in UTF-8.
1598            CStr::from_ptr(buf as *const _).to_str().unwrap()
1599        }
1600    }
1601
1602    /// Use this function to set the icon for a window.
1603    ///
1604    /// # Example:
1605    /// ```compile_fail
1606    /// // requires "--features 'image'"
1607    /// use sdl2::surface::Surface;
1608    ///
1609    /// let window_icon = Surface::from_file("/path/to/icon.png")?;
1610    /// window.set_icon(window_icon);
1611    /// ```
1612    #[doc(alias = "SDL_SetWindowIcon")]
1613    pub fn set_icon<S: AsRef<SurfaceRef>>(&mut self, icon: S) {
1614        unsafe { sys::SDL_SetWindowIcon(self.context.raw, icon.as_ref().raw()) }
1615    }
1616
1617    //pub fn SDL_SetWindowData(window: *SDL_Window, name: *c_char, userdata: *c_void) -> *c_void; //TODO: Figure out what this does
1618    //pub fn SDL_GetWindowData(window: *SDL_Window, name: *c_char) -> *c_void;
1619
1620    #[doc(alias = "SDL_SetWindowPosition")]
1621    pub fn set_position(&mut self, x: WindowPos, y: WindowPos) {
1622        unsafe {
1623            sys::SDL_SetWindowPosition(self.context.raw, to_ll_windowpos(x), to_ll_windowpos(y))
1624        }
1625    }
1626
1627    #[doc(alias = "SDL_GetWindowPosition")]
1628    pub fn position(&self) -> (i32, i32) {
1629        let mut x: c_int = 0;
1630        let mut y: c_int = 0;
1631        unsafe { sys::SDL_GetWindowPosition(self.context.raw, &mut x, &mut y) };
1632        (x as i32, y as i32)
1633    }
1634
1635    /// Use this function to get the size of a window's borders (decorations) around the client area.
1636    ///
1637    /// # Remarks
1638    /// This function is only supported on X11, otherwise an error is returned.
1639    #[doc(alias = "SDL_GetWindowBordersSize")]
1640    pub fn border_size(&self) -> Result<(u16, u16, u16, u16), String> {
1641        let mut top: c_int = 0;
1642        let mut left: c_int = 0;
1643        let mut bottom: c_int = 0;
1644        let mut right: c_int = 0;
1645        let result = unsafe {
1646            sys::SDL_GetWindowBordersSize(
1647                self.context.raw,
1648                &mut top,
1649                &mut left,
1650                &mut bottom,
1651                &mut right,
1652            )
1653        };
1654        if result < 0 {
1655            Err(get_error())
1656        } else {
1657            Ok((top as u16, left as u16, bottom as u16, right as u16))
1658        }
1659    }
1660
1661    #[doc(alias = "SDL_SetWindowSize")]
1662    pub fn set_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1663        let w = validate_int(width, "width")?;
1664        let h = validate_int(height, "height")?;
1665        unsafe {
1666            sys::SDL_SetWindowSize(self.context.raw, w, h);
1667        }
1668        Ok(())
1669    }
1670
1671    #[doc(alias = "SDL_GetWindowSize")]
1672    pub fn size(&self) -> (u32, u32) {
1673        let mut w: c_int = 0;
1674        let mut h: c_int = 0;
1675        unsafe { sys::SDL_GetWindowSize(self.context.raw, &mut w, &mut h) };
1676        (w as u32, h as u32)
1677    }
1678
1679    #[doc(alias = "SDL_GL_GetDrawableSize")]
1680    pub fn drawable_size(&self) -> (u32, u32) {
1681        let mut w: c_int = 0;
1682        let mut h: c_int = 0;
1683        unsafe { sys::SDL_GL_GetDrawableSize(self.context.raw, &mut w, &mut h) };
1684        (w as u32, h as u32)
1685    }
1686
1687    #[doc(alias = "SDL_Vulkan_GetDrawableSize")]
1688    pub fn vulkan_drawable_size(&self) -> (u32, u32) {
1689        let mut w: c_int = 0;
1690        let mut h: c_int = 0;
1691        unsafe { sys::SDL_Vulkan_GetDrawableSize(self.context.raw, &mut w, &mut h) };
1692        (w as u32, h as u32)
1693    }
1694
1695    #[doc(alias = "SDL_SetWindowMinimumSize")]
1696    pub fn set_minimum_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1697        let w = validate_int(width, "width")?;
1698        let h = validate_int(height, "height")?;
1699        unsafe {
1700            sys::SDL_SetWindowMinimumSize(self.context.raw, w, h);
1701        }
1702        Ok(())
1703    }
1704
1705    #[doc(alias = "SDL_GetWindowMinimumSize")]
1706    pub fn minimum_size(&self) -> (u32, u32) {
1707        let mut w: c_int = 0;
1708        let mut h: c_int = 0;
1709        unsafe { sys::SDL_GetWindowMinimumSize(self.context.raw, &mut w, &mut h) };
1710        (w as u32, h as u32)
1711    }
1712
1713    #[doc(alias = "SDL_SetWindowMaximumSize")]
1714    pub fn set_maximum_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1715        let w = validate_int(width, "width")?;
1716        let h = validate_int(height, "height")?;
1717        unsafe {
1718            sys::SDL_SetWindowMaximumSize(self.context.raw, w, h);
1719        }
1720        Ok(())
1721    }
1722
1723    #[doc(alias = "SDL_GetWindowMaximumSize")]
1724    pub fn maximum_size(&self) -> (u32, u32) {
1725        let mut w: c_int = 0;
1726        let mut h: c_int = 0;
1727        unsafe { sys::SDL_GetWindowMaximumSize(self.context.raw, &mut w, &mut h) };
1728        (w as u32, h as u32)
1729    }
1730
1731    #[doc(alias = "SDL_SetWindowBordered")]
1732    pub fn set_bordered(&mut self, bordered: bool) {
1733        unsafe {
1734            sys::SDL_SetWindowBordered(
1735                self.context.raw,
1736                if bordered {
1737                    sys::SDL_bool::SDL_TRUE
1738                } else {
1739                    sys::SDL_bool::SDL_FALSE
1740                },
1741            )
1742        }
1743    }
1744
1745    #[doc(alias = "SDL_ShowWindow")]
1746    pub fn show(&mut self) {
1747        unsafe { sys::SDL_ShowWindow(self.context.raw) }
1748    }
1749
1750    #[doc(alias = "SDL_HideWindow")]
1751    pub fn hide(&mut self) {
1752        unsafe { sys::SDL_HideWindow(self.context.raw) }
1753    }
1754
1755    #[doc(alias = "SDL_RaiseWindow")]
1756    pub fn raise(&mut self) {
1757        unsafe { sys::SDL_RaiseWindow(self.context.raw) }
1758    }
1759
1760    #[doc(alias = "SDL_MaximizeWindow")]
1761    pub fn maximize(&mut self) {
1762        unsafe { sys::SDL_MaximizeWindow(self.context.raw) }
1763    }
1764
1765    #[doc(alias = "SDL_MinimizeWindow")]
1766    pub fn minimize(&mut self) {
1767        unsafe { sys::SDL_MinimizeWindow(self.context.raw) }
1768    }
1769
1770    #[doc(alias = "SDL_RestoreWindow")]
1771    pub fn restore(&mut self) {
1772        unsafe { sys::SDL_RestoreWindow(self.context.raw) }
1773    }
1774
1775    pub fn fullscreen_state(&self) -> FullscreenType {
1776        FullscreenType::from_window_flags(self.window_flags())
1777    }
1778
1779    #[doc(alias = "SDL_SetWindowFullscreen")]
1780    pub fn set_fullscreen(&mut self, fullscreen_type: FullscreenType) -> Result<(), String> {
1781        unsafe {
1782            let result = sys::SDL_SetWindowFullscreen(self.context.raw, fullscreen_type as u32);
1783            if result == 0 {
1784                Ok(())
1785            } else {
1786                Err(get_error())
1787            }
1788        }
1789    }
1790
1791    /// Returns a WindowSurfaceRef, which can be used like a regular Surface. This is an
1792    /// alternative way to the Renderer (Canvas) way to modify pixels directly in the Window.
1793    ///
1794    /// For this to happen, simply create a `WindowSurfaceRef` via this method, use the underlying
1795    /// Surface however you like, and when the changes of the Surface must be applied to the
1796    /// screen, call `update_window` if you intend to keep using the WindowSurfaceRef afterwards,
1797    /// or `finish` if you don't intend to use it afterwards.
1798    ///
1799    /// The Renderer way is of course much more flexible and recommended; even though you only want
1800    /// to support Software Rendering (which is what using Surface is), you can still create a
1801    /// Renderer which renders in a Software-based manner, so try to rely on a Renderer as much as
1802    /// possible !
1803    #[doc(alias = "SDL_GetWindowSurface")]
1804    pub fn surface<'a>(&'a self, _e: &'a EventPump) -> Result<WindowSurfaceRef<'a>, String> {
1805        let raw = unsafe { sys::SDL_GetWindowSurface(self.context.raw) };
1806
1807        if raw.is_null() {
1808            Err(get_error())
1809        } else {
1810            let surface_ref = unsafe { SurfaceRef::from_ll_mut(raw) };
1811            Ok(WindowSurfaceRef(surface_ref, self))
1812        }
1813    }
1814
1815    #[doc(alias = "SDL_SetWindowGrab")]
1816    pub fn set_grab(&mut self, grabbed: bool) {
1817        unsafe {
1818            sys::SDL_SetWindowGrab(
1819                self.context.raw,
1820                if grabbed {
1821                    sys::SDL_bool::SDL_TRUE
1822                } else {
1823                    sys::SDL_bool::SDL_FALSE
1824                },
1825            )
1826        }
1827    }
1828
1829    #[doc(alias = "SDL_SetWindowKeyboardGrab")]
1830    pub fn set_keyboard_grab(&mut self, grabbed: bool) {
1831        unsafe {
1832            sys::SDL_SetWindowKeyboardGrab(
1833                self.context.raw,
1834                if grabbed {
1835                    sys::SDL_bool::SDL_TRUE
1836                } else {
1837                    sys::SDL_bool::SDL_FALSE
1838                },
1839            )
1840        }
1841    }
1842
1843    #[doc(alias = "SDL_SetWindowMouseGrab")]
1844    pub fn set_mouse_grab(&mut self, grabbed: bool) {
1845        unsafe {
1846            sys::SDL_SetWindowMouseGrab(
1847                self.context.raw,
1848                if grabbed {
1849                    sys::SDL_bool::SDL_TRUE
1850                } else {
1851                    sys::SDL_bool::SDL_FALSE
1852                },
1853            )
1854        }
1855    }
1856
1857    #[doc(alias = "SDL_GetWindowGrab")]
1858    pub fn grab(&self) -> bool {
1859        unsafe { sys::SDL_GetWindowGrab(self.context.raw) == sys::SDL_bool::SDL_TRUE }
1860    }
1861
1862    #[doc(alias = "SDL_GetWindowKeyboardGrab")]
1863    pub fn keyboard_grab(&self) -> bool {
1864        unsafe { sys::SDL_GetWindowKeyboardGrab(self.context.raw) == sys::SDL_bool::SDL_TRUE }
1865    }
1866
1867    #[doc(alias = "SDL_GetWindowMouseGrab")]
1868    pub fn mouse_grab(&self) -> bool {
1869        unsafe { sys::SDL_GetWindowMouseGrab(self.context.raw) == sys::SDL_bool::SDL_TRUE }
1870    }
1871
1872    #[doc(alias = "SDL_SetWindowMouseRect")]
1873    pub fn set_mouse_rect<R>(&self, rect: R) -> Result<(), String>
1874    where
1875        R: Into<Option<Rect>>,
1876    {
1877        let rect = rect.into();
1878        let rect_raw_ptr = match rect {
1879            Some(ref rect) => rect.raw(),
1880            None => ptr::null(),
1881        };
1882
1883        unsafe {
1884            if sys::SDL_SetWindowMouseRect(self.context.raw, rect_raw_ptr) == 0 {
1885                Ok(())
1886            } else {
1887                Err(get_error())
1888            }
1889        }
1890    }
1891
1892    #[doc(alias = "SDL_GetWindowMouseRect")]
1893    pub fn mouse_rect(&self) -> Option<Rect> {
1894        unsafe {
1895            let raw_rect = sys::SDL_GetWindowMouseRect(self.context.raw);
1896            if raw_rect.is_null() {
1897                None
1898            } else {
1899                Some(Rect::new(
1900                    (*raw_rect).x,
1901                    (*raw_rect).y,
1902                    (*raw_rect).w as u32,
1903                    (*raw_rect).h as u32,
1904                ))
1905            }
1906        }
1907    }
1908
1909    #[doc(alias = "SDL_SetWindowBrightness")]
1910    pub fn set_brightness(&mut self, brightness: f64) -> Result<(), String> {
1911        unsafe {
1912            if sys::SDL_SetWindowBrightness(self.context.raw, brightness as c_float) == 0 {
1913                Ok(())
1914            } else {
1915                Err(get_error())
1916            }
1917        }
1918    }
1919
1920    #[doc(alias = "SDL_GetWindowBrightness")]
1921    pub fn brightness(&self) -> f64 {
1922        unsafe { sys::SDL_GetWindowBrightness(self.context.raw) as f64 }
1923    }
1924
1925    #[doc(alias = "SDL_SetWindowGammaRamp")]
1926    pub fn set_gamma_ramp<'a, 'b, 'c, R, G, B>(
1927        &mut self,
1928        red: R,
1929        green: G,
1930        blue: B,
1931    ) -> Result<(), String>
1932    where
1933        R: Into<Option<&'a [u16; 256]>>,
1934        G: Into<Option<&'b [u16; 256]>>,
1935        B: Into<Option<&'c [u16; 256]>>,
1936    {
1937        let unwrapped_red = match red.into() {
1938            Some(values) => values.as_ptr(),
1939            None => ptr::null(),
1940        };
1941        let unwrapped_green = match green.into() {
1942            Some(values) => values.as_ptr(),
1943            None => ptr::null(),
1944        };
1945        let unwrapped_blue = match blue.into() {
1946            Some(values) => values.as_ptr(),
1947            None => ptr::null(),
1948        };
1949        let result = unsafe {
1950            sys::SDL_SetWindowGammaRamp(
1951                self.context.raw,
1952                unwrapped_red,
1953                unwrapped_green,
1954                unwrapped_blue,
1955            )
1956        };
1957        if result != 0 {
1958            Err(get_error())
1959        } else {
1960            Ok(())
1961        }
1962    }
1963
1964    #[allow(clippy::type_complexity)]
1965    #[doc(alias = "SDL_GetWindowGammaRamp")]
1966    pub fn gamma_ramp(&self) -> Result<(Vec<u16>, Vec<u16>, Vec<u16>), String> {
1967        let mut red: Vec<u16> = vec![0; 256];
1968        let mut green: Vec<u16> = vec![0; 256];
1969        let mut blue: Vec<u16> = vec![0; 256];
1970        let result = unsafe {
1971            sys::SDL_GetWindowGammaRamp(
1972                self.context.raw,
1973                red.as_mut_ptr(),
1974                green.as_mut_ptr(),
1975                blue.as_mut_ptr(),
1976            )
1977        };
1978        if result == 0 {
1979            Ok((red, green, blue))
1980        } else {
1981            Err(get_error())
1982        }
1983    }
1984
1985    /// Set the transparency of the window. The given value will be clamped internally between
1986    /// `0.0` (fully transparent), and `1.0` (fully opaque).
1987    ///
1988    /// This method returns an error if opacity isn't supported by the current platform.
1989    #[doc(alias = "SDL_SetWindowOpacity")]
1990    pub fn set_opacity(&mut self, opacity: f32) -> Result<(), String> {
1991        let result = unsafe { sys::SDL_SetWindowOpacity(self.context.raw, opacity) };
1992        if result < 0 {
1993            Err(get_error())
1994        } else {
1995            Ok(())
1996        }
1997    }
1998
1999    /// Returns the transparency of the window, as a value between `0.0` (fully transparent), and
2000    /// `1.0` (fully opaque).
2001    ///
2002    /// If opacity isn't supported by the current platform, this method returns `Ok(1.0)` instead
2003    /// of an error.
2004    #[doc(alias = "SDL_GetWindowOpacity")]
2005    pub fn opacity(&self) -> Result<f32, String> {
2006        let mut opacity = 0.0;
2007        let result = unsafe { sys::SDL_GetWindowOpacity(self.context.raw, &mut opacity) };
2008        if result < 0 {
2009            Err(get_error())
2010        } else {
2011            Ok(opacity)
2012        }
2013    }
2014
2015    /// Requests a window to demand attention from the user.
2016    #[doc(alias = "SDL_FlashWindow")]
2017    pub fn flash(&mut self, operation: FlashOperation) -> Result<(), String> {
2018        let result = unsafe { sys::SDL_FlashWindow(self.context.raw, operation.to_ll()) };
2019        if result == 0 {
2020            Ok(())
2021        } else {
2022            Err(get_error())
2023        }
2024    }
2025
2026    /// Makes window appear on top of others
2027    #[doc(alias = "SDL_SetWindowAlwaysOnTop")]
2028    pub fn set_always_on_top(&mut self, on_top: bool) {
2029        unsafe {
2030            sys::SDL_SetWindowAlwaysOnTop(
2031                self.context.raw,
2032                if on_top {
2033                    sys::SDL_bool::SDL_TRUE
2034                } else {
2035                    sys::SDL_bool::SDL_FALSE
2036                },
2037            )
2038        };
2039    }
2040}
2041
2042#[derive(Copy, Clone)]
2043#[doc(alias = "SDL_GetVideoDriver")]
2044pub struct DriverIterator {
2045    length: i32,
2046    index: i32,
2047}
2048
2049// panics if SDL_GetVideoDriver returns a null pointer,
2050// which only happens if index is outside the range
2051// 0..SDL_GetNumVideoDrivers()
2052fn get_video_driver(index: i32) -> &'static str {
2053    use std::str;
2054
2055    unsafe {
2056        let buf = sys::SDL_GetVideoDriver(index);
2057        assert!(!buf.is_null());
2058
2059        str::from_utf8(CStr::from_ptr(buf as *const _).to_bytes()).unwrap()
2060    }
2061}
2062
2063impl Iterator for DriverIterator {
2064    type Item = &'static str;
2065
2066    #[inline]
2067    fn next(&mut self) -> Option<&'static str> {
2068        if self.index >= self.length {
2069            None
2070        } else {
2071            let driver = get_video_driver(self.index);
2072            self.index += 1;
2073
2074            Some(driver)
2075        }
2076    }
2077
2078    #[inline]
2079    fn size_hint(&self) -> (usize, Option<usize>) {
2080        let remaining = (self.length - self.index) as usize;
2081        (remaining, Some(remaining))
2082    }
2083
2084    #[inline]
2085    fn nth(&mut self, n: usize) -> Option<&'static str> {
2086        use std::convert::TryInto;
2087
2088        self.index = match n.try_into().ok().and_then(|n| self.index.checked_add(n)) {
2089            Some(index) if index < self.length => index,
2090            _ => self.length,
2091        };
2092
2093        self.next()
2094    }
2095}
2096
2097impl DoubleEndedIterator for DriverIterator {
2098    #[inline]
2099    fn next_back(&mut self) -> Option<&'static str> {
2100        if self.index >= self.length {
2101            None
2102        } else {
2103            self.length -= 1;
2104
2105            Some(get_video_driver(self.length))
2106        }
2107    }
2108
2109    #[inline]
2110    fn nth_back(&mut self, n: usize) -> Option<&'static str> {
2111        use std::convert::TryInto;
2112
2113        self.length = match n.try_into().ok().and_then(|n| self.length.checked_sub(n)) {
2114            Some(length) if length > self.index => length,
2115            _ => self.index,
2116        };
2117
2118        self.next_back()
2119    }
2120}
2121
2122impl ExactSizeIterator for DriverIterator {}
2123
2124impl std::iter::FusedIterator for DriverIterator {}
2125
2126/// Gets an iterator of all video drivers compiled into the SDL2 library.
2127#[inline]
2128#[doc(alias = "SDL_GetVideoDriver")]
2129pub fn drivers() -> DriverIterator {
2130    // This function is thread-safe and doesn't require the video subsystem to be initialized.
2131    // The list of drivers are read-only and statically compiled into SDL2, varying by platform.
2132
2133    // SDL_GetNumVideoDrivers can never return a negative value.
2134    DriverIterator {
2135        length: unsafe { sys::SDL_GetNumVideoDrivers() },
2136        index: 0,
2137    }
2138}