winit/
icon.rs

1use crate::platform_impl::PlatformIcon;
2use std::{error::Error, fmt, io, mem};
3
4#[repr(C)]
5#[derive(Debug)]
6pub(crate) struct Pixel {
7    pub(crate) r: u8,
8    pub(crate) g: u8,
9    pub(crate) b: u8,
10    pub(crate) a: u8,
11}
12
13pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
14
15#[derive(Debug)]
16/// An error produced when using `Icon::from_rgba` with invalid arguments.
17pub enum BadIcon {
18    /// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
19    /// safely interpreted as 32bpp RGBA pixels.
20    ByteCountNotDivisibleBy4 { byte_count: usize },
21    /// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
22    /// At least one of your arguments is incorrect.
23    DimensionsVsPixelCount {
24        width: u32,
25        height: u32,
26        width_x_height: usize,
27        pixel_count: usize,
28    },
29    /// Produced when underlying OS functionality failed to create the icon
30    OsError(io::Error),
31}
32
33impl fmt::Display for BadIcon {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        match self {
36            BadIcon::ByteCountNotDivisibleBy4 { byte_count } => write!(f,
37                "The length of the `rgba` argument ({:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.",
38                byte_count,
39            ),
40            BadIcon::DimensionsVsPixelCount {
41                width,
42                height,
43                width_x_height,
44                pixel_count,
45            } => write!(f,
46                "The specified dimensions ({:?}x{:?}) don't match the number of pixels supplied by the `rgba` argument ({:?}). For those dimensions, the expected pixel count is {:?}.",
47                width, height, pixel_count, width_x_height,
48            ),
49            BadIcon::OsError(e) => write!(f, "OS error when instantiating the icon: {:?}", e),
50        }
51    }
52}
53
54impl Error for BadIcon {
55    fn source(&self) -> Option<&(dyn Error + 'static)> {
56        Some(self)
57    }
58}
59
60#[derive(Debug, Clone, PartialEq, Eq)]
61pub(crate) struct RgbaIcon {
62    pub(crate) rgba: Vec<u8>,
63    pub(crate) width: u32,
64    pub(crate) height: u32,
65}
66
67/// For platforms which don't have window icons (e.g. web)
68#[derive(Debug, Clone, PartialEq, Eq)]
69pub(crate) struct NoIcon;
70
71#[allow(dead_code)] // These are not used on every platform
72mod constructors {
73    use super::*;
74
75    impl RgbaIcon {
76        /// Creates an `Icon` from 32bpp RGBA data.
77        ///
78        /// The length of `rgba` must be divisible by 4, and `width * height` must equal
79        /// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
80        pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
81            if rgba.len() % PIXEL_SIZE != 0 {
82                return Err(BadIcon::ByteCountNotDivisibleBy4 {
83                    byte_count: rgba.len(),
84                });
85            }
86            let pixel_count = rgba.len() / PIXEL_SIZE;
87            if pixel_count != (width * height) as usize {
88                Err(BadIcon::DimensionsVsPixelCount {
89                    width,
90                    height,
91                    width_x_height: (width * height) as usize,
92                    pixel_count,
93                })
94            } else {
95                Ok(RgbaIcon {
96                    rgba,
97                    width,
98                    height,
99                })
100            }
101        }
102    }
103
104    impl NoIcon {
105        pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
106            // Create the rgba icon anyway to validate the input
107            let _ = RgbaIcon::from_rgba(rgba, width, height)?;
108            Ok(NoIcon)
109        }
110    }
111}
112
113/// An icon used for the window titlebar, taskbar, etc.
114#[derive(Clone)]
115pub struct Icon {
116    pub(crate) inner: PlatformIcon,
117}
118
119impl fmt::Debug for Icon {
120    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
121        fmt::Debug::fmt(&self.inner, formatter)
122    }
123}
124
125impl Icon {
126    /// Creates an `Icon` from 32bpp RGBA data.
127    ///
128    /// The length of `rgba` must be divisible by 4, and `width * height` must equal
129    /// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
130    pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
131        Ok(Icon {
132            inner: PlatformIcon::from_rgba(rgba, width, height)?,
133        })
134    }
135}