1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//! A window treating as a [`Surface`].

use std::{marker::PhantomData, os::raw::c_int, ptr::NonNull};

use crate::{bind, geo::Rect, window::Window, Result, Sdl, SdlError};

use super::{RawSurface, Surface};

/// A [`Surface`] made from the [`Window`].
pub struct WindowSurface<'window> {
    surface: NonNull<RawSurface>,
    window: &'window Window<'window>,
}

impl std::fmt::Debug for WindowSurface<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("WindowSurface")
            .field("window", &self.window)
            .finish_non_exhaustive()
    }
}

impl<'window> WindowSurface<'window> {
    pub(crate) fn new(window: &'window Window<'window>) -> Self {
        let surface = unsafe { bind::SDL_GetWindowSurface(window.as_ptr()) };
        Self {
            surface: NonNull::new(surface).unwrap(),
            window,
        }
    }

    /// Applies the surface into the original window.
    ///
    /// # Errors
    ///
    /// Returns `Err` if failed to copy the window surface to the screen.
    pub fn update_window_surface(&self) -> Result<()> {
        let ret = unsafe { bind::SDL_UpdateWindowSurface(self.window.as_ptr()) };
        if ret < 0 {
            Err(SdlError::Others { msg: Sdl::error() })
        } else {
            Ok(())
        }
    }

    /// Applies the surface into the original window area only where `rects`.
    ///
    /// # Errors
    ///
    /// Returns `Err` if failed to copy areas of the window surface to the screen.
    pub fn update_window_surface_rects(&self, rects: &[Rect]) -> Result<()> {
        let rects: Vec<_> = rects.iter().map(|&rect| rect.into()).collect();
        let ret = unsafe {
            bind::SDL_UpdateWindowSurfaceRects(
                self.window.as_ptr(),
                rects.as_ptr(),
                rects.len() as c_int,
            )
        };
        if ret < 0 {
            Err(SdlError::Others { msg: Sdl::error() })
        } else {
            Ok(())
        }
    }
}

impl Surface for WindowSurface<'_> {
    fn as_ptr(&self) -> std::ptr::NonNull<RawSurface> {
        self.surface
    }
}