winit-core: move icon
This commit is contained in:
parent
a491c2abed
commit
cbb29ab526
8 changed files with 60 additions and 39 deletions
108
src/icon.rs
108
src/icon.rs
|
|
@ -1,108 +0,0 @@
|
|||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
use std::{fmt, io, mem};
|
||||
|
||||
use crate::utils::{impl_dyn_casting, AsAny};
|
||||
|
||||
pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
|
||||
|
||||
/// An icon used for the window titlebar, taskbar, etc.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Icon(pub(crate) Arc<dyn IconProvider>);
|
||||
|
||||
// TODO remove that once split.
|
||||
pub trait IconProvider: AsAny + fmt::Debug + Send + Sync {}
|
||||
|
||||
impl_dyn_casting!(IconProvider);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Pixel {
|
||||
pub(crate) r: u8,
|
||||
pub(crate) g: u8,
|
||||
pub(crate) b: u8,
|
||||
pub(crate) a: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// An error produced when using [`RgbaIcon::new`] with invalid arguments.
|
||||
pub enum BadIcon {
|
||||
/// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
|
||||
/// safely interpreted as 32bpp RGBA pixels.
|
||||
ByteCountNotDivisibleBy4 { byte_count: usize },
|
||||
/// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
|
||||
/// At least one of your arguments is incorrect.
|
||||
DimensionsVsPixelCount { width: u32, height: u32, width_x_height: usize, pixel_count: usize },
|
||||
/// Produced when underlying OS functionality failed to create the icon
|
||||
OsError(io::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for BadIcon {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
BadIcon::ByteCountNotDivisibleBy4 { byte_count } => write!(
|
||||
f,
|
||||
"The length of the `rgba` argument ({byte_count:?}) isn't divisible by 4, making \
|
||||
it impossible to interpret as 32bpp RGBA pixels.",
|
||||
),
|
||||
BadIcon::DimensionsVsPixelCount { width, height, width_x_height, pixel_count } => {
|
||||
write!(
|
||||
f,
|
||||
"The specified dimensions ({width:?}x{height:?}) don't match the number of \
|
||||
pixels supplied by the `rgba` argument ({pixel_count:?}). For those \
|
||||
dimensions, the expected pixel count is {width_x_height:?}.",
|
||||
)
|
||||
},
|
||||
BadIcon::OsError(e) => write!(f, "OS error when instantiating the icon: {e:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for BadIcon {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RgbaIcon {
|
||||
pub(crate) width: u32,
|
||||
pub(crate) height: u32,
|
||||
pub(crate) rgba: Vec<u8>,
|
||||
}
|
||||
|
||||
impl RgbaIcon {
|
||||
pub fn new(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
|
||||
if rgba.len() % PIXEL_SIZE != 0 {
|
||||
return Err(BadIcon::ByteCountNotDivisibleBy4 { byte_count: rgba.len() });
|
||||
}
|
||||
let pixel_count = rgba.len() / PIXEL_SIZE;
|
||||
if pixel_count != (width * height) as usize {
|
||||
Err(BadIcon::DimensionsVsPixelCount {
|
||||
width,
|
||||
height,
|
||||
width_x_height: (width * height) as usize,
|
||||
pixel_count,
|
||||
})
|
||||
} else {
|
||||
Ok(RgbaIcon { rgba, width, height })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn width(&self) -> u32 {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub fn height(&self) -> u32 {
|
||||
self.height
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
self.rgba.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl IconProvider for RgbaIcon {}
|
||||
|
||||
impl From<RgbaIcon> for Icon {
|
||||
fn from(value: RgbaIcon) -> Self {
|
||||
Self(Arc::new(value))
|
||||
}
|
||||
}
|
||||
|
|
@ -304,8 +304,7 @@ pub mod error;
|
|||
mod cursor;
|
||||
pub mod event;
|
||||
pub mod event_loop;
|
||||
pub mod icon;
|
||||
pub use winit_core::{keyboard, monitor};
|
||||
pub use winit_core::{icon, keyboard, monitor};
|
||||
mod platform_impl;
|
||||
use winit_core::as_any as utils;
|
||||
pub mod window;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,18 @@
|
|||
#![allow(clippy::assertions_on_constants)]
|
||||
|
||||
use super::*;
|
||||
use crate::icon::{Pixel, RgbaIcon, PIXEL_SIZE};
|
||||
use crate::icon::RgbaIcon;
|
||||
|
||||
pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Pixel {
|
||||
pub(crate) r: u8,
|
||||
pub(crate) g: u8,
|
||||
pub(crate) b: u8,
|
||||
pub(crate) a: u8,
|
||||
}
|
||||
|
||||
impl Pixel {
|
||||
pub fn to_packed_argb(&self) -> Cardinal {
|
||||
|
|
@ -18,19 +29,17 @@ impl Pixel {
|
|||
}
|
||||
}
|
||||
|
||||
impl RgbaIcon {
|
||||
pub(crate) fn to_cardinals(&self) -> Vec<Cardinal> {
|
||||
assert_eq!(self.rgba.len() % PIXEL_SIZE, 0);
|
||||
let pixel_count = self.rgba.len() / PIXEL_SIZE;
|
||||
assert_eq!(pixel_count, (self.width * self.height) as usize);
|
||||
let mut data = Vec::with_capacity(pixel_count);
|
||||
data.push(self.width as Cardinal);
|
||||
data.push(self.height as Cardinal);
|
||||
let pixels = self.rgba.as_ptr() as *const Pixel;
|
||||
for pixel_index in 0..pixel_count {
|
||||
let pixel = unsafe { &*pixels.add(pixel_index) };
|
||||
data.push(pixel.to_packed_argb());
|
||||
}
|
||||
data
|
||||
pub(crate) fn rgba_to_cardinals(icon: &RgbaIcon) -> Vec<Cardinal> {
|
||||
assert_eq!(icon.buffer().len() % PIXEL_SIZE, 0);
|
||||
let pixel_count = icon.buffer().len() / PIXEL_SIZE;
|
||||
assert_eq!(pixel_count, (icon.width() * icon.height()) as usize);
|
||||
let mut data = Vec::with_capacity(pixel_count);
|
||||
data.push(icon.width() as Cardinal);
|
||||
data.push(icon.height() as Cardinal);
|
||||
let pixels = icon.buffer().as_ptr() as *const Pixel;
|
||||
for pixel_index in 0..pixel_count {
|
||||
let pixel = unsafe { &*pixels.add(pixel_index) };
|
||||
data.push(pixel.to_packed_argb());
|
||||
}
|
||||
data
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ use x11rb::protocol::xproto::{self, ConnectionExt as _};
|
|||
pub use self::cursor::*;
|
||||
pub use self::geometry::*;
|
||||
pub use self::hint::*;
|
||||
pub(crate) use self::icon::rgba_to_cardinals;
|
||||
pub use self::input::*;
|
||||
pub use self::mouse::*;
|
||||
pub use self::window_property::*;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ use crate::monitor::{
|
|||
use crate::platform::x11::WindowType;
|
||||
use crate::platform_impl::common;
|
||||
use crate::platform_impl::x11::atoms::*;
|
||||
use crate::platform_impl::x11::util::rgba_to_cardinals;
|
||||
use crate::platform_impl::x11::{
|
||||
xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, X11Error,
|
||||
};
|
||||
|
|
@ -205,7 +206,7 @@ impl CoreWindow for Window {
|
|||
|
||||
fn set_window_icon(&self, window_icon: Option<crate::window::Icon>) {
|
||||
let icon = match window_icon.as_ref() {
|
||||
Some(icon) => icon.0.cast_ref::<RgbaIcon>(),
|
||||
Some(icon) => icon.cast_ref::<RgbaIcon>(),
|
||||
None => None,
|
||||
};
|
||||
self.0.set_window_icon(icon)
|
||||
|
|
@ -771,7 +772,7 @@ impl UnownedWindow {
|
|||
|
||||
// Set window icons
|
||||
if let Some(icon) =
|
||||
window_attrs.window_icon.as_ref().and_then(|icon| icon.0.cast_ref::<RgbaIcon>())
|
||||
window_attrs.window_icon.as_ref().and_then(|icon| icon.cast_ref::<RgbaIcon>())
|
||||
{
|
||||
leap!(window.set_icon_inner(icon)).ignore_error();
|
||||
}
|
||||
|
|
@ -1414,7 +1415,7 @@ impl UnownedWindow {
|
|||
fn set_icon_inner(&self, icon: &RgbaIcon) -> Result<VoidCookie<'_>, X11Error> {
|
||||
let atoms = self.xconn.atoms();
|
||||
let icon_atom = atoms[_NET_WM_ICON];
|
||||
let data = icon.to_cardinals();
|
||||
let data = rgba_to_cardinals(icon);
|
||||
self.xconn.change_property(
|
||||
self.xwindow,
|
||||
icon_atom,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ use crate::error::RequestError;
|
|||
use crate::icon::*;
|
||||
use crate::platform::windows::WinIcon;
|
||||
|
||||
pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
|
||||
|
||||
unsafe impl Send for WinIcon {}
|
||||
|
||||
impl WinIcon {
|
||||
|
|
@ -92,10 +94,10 @@ impl WinIcon {
|
|||
}
|
||||
|
||||
pub(crate) fn from_rgba(rgba: &RgbaIcon) -> Result<Self, BadIcon> {
|
||||
let pixel_count = rgba.rgba.len() / PIXEL_SIZE;
|
||||
let pixel_count = rgba.buffer().len() / PIXEL_SIZE;
|
||||
let mut and_mask = Vec::with_capacity(pixel_count);
|
||||
let pixels = unsafe {
|
||||
std::slice::from_raw_parts_mut(rgba.rgba.as_ptr() as *mut Pixel, pixel_count)
|
||||
std::slice::from_raw_parts_mut(rgba.buffer().as_ptr() as *mut Pixel, pixel_count)
|
||||
};
|
||||
for pixel in pixels {
|
||||
and_mask.push(pixel.a.wrapping_sub(u8::MAX)); // invert alpha channel
|
||||
|
|
@ -105,12 +107,12 @@ impl WinIcon {
|
|||
let handle = unsafe {
|
||||
CreateIcon(
|
||||
ptr::null_mut(),
|
||||
rgba.width as i32,
|
||||
rgba.height as i32,
|
||||
rgba.width() as i32,
|
||||
rgba.height() as i32,
|
||||
1,
|
||||
(PIXEL_SIZE * 8) as u8,
|
||||
and_mask.as_ptr(),
|
||||
rgba.rgba.as_ptr(),
|
||||
rgba.buffer().as_ptr(),
|
||||
)
|
||||
};
|
||||
if !handle.is_null() {
|
||||
|
|
@ -250,3 +252,12 @@ impl RaiiCursor {
|
|||
self.handle
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Pixel {
|
||||
pub(crate) r: u8,
|
||||
pub(crate) g: u8,
|
||||
pub(crate) b: u8,
|
||||
pub(crate) a: u8,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ impl Window {
|
|||
}
|
||||
|
||||
fn set_icon(&self, mut new_icon: Icon, icon_type: IconType) {
|
||||
if let Some(icon) = new_icon.0.cast_ref::<RgbaIcon>() {
|
||||
if let Some(icon) = new_icon.cast_ref::<RgbaIcon>() {
|
||||
let icon = match WinIcon::from_rgba(icon) {
|
||||
Ok(icon) => icon,
|
||||
Err(err) => {
|
||||
|
|
@ -362,7 +362,7 @@ impl Window {
|
|||
new_icon = Icon(Arc::new(icon));
|
||||
}
|
||||
|
||||
if let Some(icon) = new_icon.0.cast_ref::<WinIcon>() {
|
||||
if let Some(icon) = new_icon.cast_ref::<WinIcon>() {
|
||||
unsafe {
|
||||
SendMessageW(
|
||||
self.hwnd(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue