icon: refactor Icon to be dyn
Same as for `CustomCursor`. However, the API uses `dyn` stuff only because of `Windows` backend at the time of writing, generally, platforms should just have a separate method that deals with all of that, and e.g. top-level winit only guarantees `Rgba`.
This commit is contained in:
parent
cdbdd974fb
commit
07c25b9703
16 changed files with 230 additions and 211 deletions
|
|
@ -20,6 +20,7 @@ use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
|
|||
use winit::error::RequestError;
|
||||
use winit::event::{DeviceEvent, DeviceId, Ime, MouseButton, MouseScrollDelta, WindowEvent};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::icon::RgbaIcon;
|
||||
use winit::keyboard::{Key, ModifiersState};
|
||||
use winit::monitor::Fullscreen;
|
||||
#[cfg(macos_platform)]
|
||||
|
|
@ -1156,7 +1157,7 @@ fn load_icon(bytes: &[u8]) -> Icon {
|
|||
let rgba = image.into_raw();
|
||||
(rgba, width, height)
|
||||
};
|
||||
Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
|
||||
RgbaIcon::new(icon_rgba, icon_width, icon_height).expect("Failed to open icon").into()
|
||||
}
|
||||
|
||||
fn modifiers_to_string(mods: ModifiersState) -> String {
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ changelog entry.
|
|||
- On X11, set an "area" attribute on XIM input connection to convey the cursor area.
|
||||
- Implement `CustomCursorProvider` for `CustomCursor` to access cursor API.
|
||||
- Add `CustomCursorSource::Url`, `CustomCursorSource::from_animation`.
|
||||
- Implement `CustomIconProvider` for `RgbaIcon`.
|
||||
- Add `icon` module that exposes winit's icon API.
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
@ -196,6 +198,7 @@ changelog entry.
|
|||
- Move `window::Fullscreen` to `monitor::Fullscreen`.
|
||||
- Renamed "super" key to "meta", to match the naming in the W3C specification.
|
||||
`NamedKey::Super` still exists, but it's non-functional and deprecated, `NamedKey::Meta` should be used instead.
|
||||
- Move `IconExtWindows` into `WinIcon`.
|
||||
|
||||
### Removed
|
||||
|
||||
|
|
@ -230,9 +233,10 @@ changelog entry.
|
|||
- Remove `Window::inner_position`, use the new `Window::surface_position` instead.
|
||||
- Remove `CustomCursorExtWeb`, use the `CustomCursorSource`.
|
||||
- Remove `CustomCursor::from_rgba`, use `CustomCursorSource` instead.
|
||||
- Removed `ApplicationHandler::exited`, the event loop being shut down can now be listened to in
|
||||
- Remove `ApplicationHandler::exited`, the event loop being shut down can now be listened to in
|
||||
the `Drop` impl on the application handler.
|
||||
- Removed `NamedKey::Space`, match on `Key::Character(" ")` instead.
|
||||
- Remove `NamedKey::Space`, match on `Key::Character(" ")` instead.
|
||||
- Remove `PartialEq` impl for `WindowAttributes`.
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
|||
104
src/icon.rs
104
src/icon.rs
|
|
@ -1,7 +1,20 @@
|
|||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
use std::{fmt, io, mem};
|
||||
|
||||
use crate::platform_impl::PlatformIcon;
|
||||
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)]
|
||||
|
|
@ -12,10 +25,8 @@ pub(crate) struct Pixel {
|
|||
pub(crate) a: u8,
|
||||
}
|
||||
|
||||
pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
|
||||
|
||||
#[derive(Debug)]
|
||||
/// An error produced when using [`Icon::from_rgba`] with invalid arguments.
|
||||
/// 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.
|
||||
|
|
@ -50,69 +61,48 @@ impl fmt::Display for BadIcon {
|
|||
|
||||
impl Error for BadIcon {}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct RgbaIcon {
|
||||
pub(crate) rgba: Vec<u8>,
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RgbaIcon {
|
||||
pub(crate) width: u32,
|
||||
pub(crate) height: u32,
|
||||
pub(crate) rgba: Vec<u8>,
|
||||
}
|
||||
|
||||
/// For platforms which don't have window icons (e.g. Web)
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct NoIcon;
|
||||
|
||||
#[allow(dead_code)] // These are not used on every platform
|
||||
mod constructors {
|
||||
use super::*;
|
||||
|
||||
impl RgbaIcon {
|
||||
pub fn from_rgba(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 })
|
||||
}
|
||||
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 })
|
||||
}
|
||||
}
|
||||
|
||||
impl NoIcon {
|
||||
pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
|
||||
// Create the rgba icon anyway to validate the input
|
||||
let _ = RgbaIcon::from_rgba(rgba, width, height)?;
|
||||
Ok(NoIcon)
|
||||
}
|
||||
pub fn width(&self) -> u32 {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub fn height(&self) -> u32 {
|
||||
self.height
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
self.rgba.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
/// An icon used for the window titlebar, taskbar, etc.
|
||||
#[derive(Clone, Eq, Hash, PartialEq)]
|
||||
pub struct Icon {
|
||||
pub(crate) inner: PlatformIcon,
|
||||
}
|
||||
impl IconProvider for RgbaIcon {}
|
||||
|
||||
impl fmt::Debug for Icon {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
fmt::Debug::fmt(&self.inner, formatter)
|
||||
}
|
||||
}
|
||||
|
||||
impl Icon {
|
||||
/// Creates an icon from 32bpp RGBA data.
|
||||
///
|
||||
/// The length of `rgba` must be divisible by 4, and `width * height` must equal
|
||||
/// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
|
||||
pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
|
||||
let _span = tracing::debug_span!("winit::Icon::from_rgba", width, height).entered();
|
||||
|
||||
Ok(Icon { inner: PlatformIcon::from_rgba(rgba, width, height)? })
|
||||
impl From<RgbaIcon> for Icon {
|
||||
fn from(value: RgbaIcon) -> Self {
|
||||
Self(Arc::new(value))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ pub mod error;
|
|||
mod cursor;
|
||||
pub mod event;
|
||||
pub mod event_loop;
|
||||
mod icon;
|
||||
pub mod icon;
|
||||
pub mod keyboard;
|
||||
pub mod monitor;
|
||||
mod platform_impl;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use std::borrow::Borrow;
|
|||
use std::ffi::c_void;
|
||||
use std::ops::Deref;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -15,7 +16,9 @@ use windows_sys::Win32::Foundation::HANDLE;
|
|||
use crate::dpi::PhysicalSize;
|
||||
use crate::event::DeviceId;
|
||||
use crate::event_loop::EventLoopBuilder;
|
||||
use crate::window::{BadIcon, Icon, Window, WindowAttributes};
|
||||
use crate::icon::BadIcon;
|
||||
use crate::platform_impl::RaiiIcon;
|
||||
use crate::window::{Icon, Window, WindowAttributes};
|
||||
|
||||
/// Window Handle type used by Win32 API
|
||||
pub type HWND = *mut c_void;
|
||||
|
|
@ -637,7 +640,7 @@ impl DeviceIdExtWindows for DeviceId {
|
|||
}
|
||||
}
|
||||
|
||||
/// Additional methods on `Icon` that are specific to Windows.
|
||||
/// Windows specific `Icon`.
|
||||
///
|
||||
/// Windows icons can be created from files, or from the [`embedded resources`](https://learn.microsoft.com/en-us/windows/win32/menurc/about-resource-files).
|
||||
///
|
||||
|
|
@ -649,7 +652,12 @@ impl DeviceIdExtWindows for DeviceId {
|
|||
/// `filename` is the name of the file that contains the resource.
|
||||
///
|
||||
/// More information about the `ICON` resource can be found at [`Microsoft Learn`](https://learn.microsoft.com/en-us/windows/win32/menurc/icon-resource) portal.
|
||||
pub trait IconExtWindows: Sized {
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct WinIcon {
|
||||
pub(crate) inner: Arc<RaiiIcon>,
|
||||
}
|
||||
|
||||
impl WinIcon {
|
||||
/// Create an icon from a file path.
|
||||
///
|
||||
/// Specify `size` to load a specific icon size from the file, or `None` to load the default
|
||||
|
|
@ -657,22 +665,31 @@ pub trait IconExtWindows: Sized {
|
|||
///
|
||||
/// In cases where the specified size does not exist in the file, Windows may perform scaling
|
||||
/// to get an icon of the desired size.
|
||||
fn from_path<P: AsRef<Path>>(path: P, size: Option<PhysicalSize<u32>>)
|
||||
-> Result<Self, BadIcon>;
|
||||
pub fn from_path<P: AsRef<Path>>(
|
||||
path: P,
|
||||
size: Option<PhysicalSize<u32>>,
|
||||
) -> Result<Self, BadIcon> {
|
||||
Self::from_path_impl(path, size)
|
||||
}
|
||||
|
||||
/// Create an icon from a resource embedded in this executable or library by its ordinal id.
|
||||
///
|
||||
/// The valid `ordinal` values range from 1 to [`u16::MAX`] (inclusive). The value `0` is an
|
||||
/// invalid ordinal id, but it can be used with [`from_resource_name`] as `"0"`.
|
||||
///
|
||||
/// [`from_resource_name`]: IconExtWindows::from_resource_name
|
||||
/// [`from_resource_name`]: Self::from_resource_name
|
||||
///
|
||||
/// Specify `size` to load a specific icon size from the file, or `None` to load the default
|
||||
/// icon size from the file.
|
||||
///
|
||||
/// In cases where the specified size does not exist in the file, Windows may perform scaling
|
||||
/// to get an icon of the desired size.
|
||||
fn from_resource(ordinal: u16, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon>;
|
||||
pub fn from_resource(
|
||||
resource_id: u16,
|
||||
size: Option<PhysicalSize<u32>>,
|
||||
) -> Result<Self, BadIcon> {
|
||||
Self::from_resource_impl(resource_id, size)
|
||||
}
|
||||
|
||||
/// Create an icon from a resource embedded in this executable or library by its name.
|
||||
///
|
||||
|
|
@ -697,17 +714,16 @@ pub trait IconExtWindows: Sized {
|
|||
/// `"002"`, etc.) cannot be used as valid resource names, and instead should be passed into
|
||||
/// [`from_resource`]:
|
||||
///
|
||||
/// [`from_resource`]: IconExtWindows::from_resource
|
||||
/// [`from_resource`]: Self::from_resource
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use winit::platform::windows::IconExtWindows;
|
||||
/// use winit::window::Icon;
|
||||
/// use winit::platform::windows::WinIcon;
|
||||
///
|
||||
/// assert!(Icon::from_resource_name("app", None).is_ok());
|
||||
/// assert!(Icon::from_resource(1, None).is_ok());
|
||||
/// assert!(Icon::from_resource(27, None).is_ok());
|
||||
/// assert!(Icon::from_resource_name("27", None).is_err());
|
||||
/// assert!(Icon::from_resource_name("0027", None).is_err());
|
||||
/// assert!(WinIcon::from_resource_name("app", None).is_ok());
|
||||
/// assert!(WinIcon::from_resource(1, None).is_ok());
|
||||
/// assert!(WinIcon::from_resource(27, None).is_ok());
|
||||
/// assert!(WinIcon::from_resource_name("27", None).is_err());
|
||||
/// assert!(WinIcon::from_resource_name("0027", None).is_err());
|
||||
/// ```
|
||||
///
|
||||
/// While `0` cannot be used as an ordinal id (see [`from_resource`]), it can be used as a
|
||||
|
|
@ -716,30 +732,21 @@ pub trait IconExtWindows: Sized {
|
|||
/// [`from_resource`]: IconExtWindows::from_resource
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use winit::platform::windows::IconExtWindows;
|
||||
/// # use winit::platform::windows::WinIcon;
|
||||
/// # use winit::window::Icon;
|
||||
/// assert!(Icon::from_resource_name("0", None).is_ok());
|
||||
/// assert!(Icon::from_resource(0, None).is_err());
|
||||
/// assert!(WinIcon::from_resource_name("0", None).is_ok());
|
||||
/// assert!(WinIcon::from_resource(0, None).is_err());
|
||||
/// ```
|
||||
fn from_resource_name(name: &str, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon>;
|
||||
}
|
||||
|
||||
impl IconExtWindows for Icon {
|
||||
fn from_path<P: AsRef<Path>>(
|
||||
path: P,
|
||||
pub fn from_resource_name(
|
||||
resource_name: &str,
|
||||
size: Option<PhysicalSize<u32>>,
|
||||
) -> Result<Self, BadIcon> {
|
||||
let win_icon = crate::platform_impl::WinIcon::from_path(path, size)?;
|
||||
Ok(Icon { inner: win_icon })
|
||||
}
|
||||
|
||||
fn from_resource(ordinal: u16, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> {
|
||||
let win_icon = crate::platform_impl::WinIcon::from_resource(ordinal, size)?;
|
||||
Ok(Icon { inner: win_icon })
|
||||
}
|
||||
|
||||
fn from_resource_name(name: &str, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> {
|
||||
let win_icon = crate::platform_impl::WinIcon::from_resource_name(name, size)?;
|
||||
Ok(Icon { inner: win_icon })
|
||||
Self::from_resource_name_impl(resource_name, size)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WinIcon> for Icon {
|
||||
fn from(value: WinIcon) -> Self {
|
||||
Self(Arc::new(value))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ use crate::event_loop::{
|
|||
EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
|
||||
OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
||||
};
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle};
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
use crate::window::{
|
||||
|
|
|
|||
|
|
@ -21,4 +21,3 @@ pub(crate) use self::event_loop::{
|
|||
pub(crate) use self::monitor::MonitorHandle;
|
||||
pub(crate) use self::window::Window;
|
||||
pub(crate) use self::window_delegate::PlatformSpecificWindowAttributes;
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ pub(crate) use self::event_loop::{
|
|||
};
|
||||
pub(crate) use self::monitor::MonitorHandle;
|
||||
pub(crate) use self::window::{PlatformSpecificWindowAttributes, Window};
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OsError {}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ use crate::application::ApplicationHandler;
|
|||
use crate::dpi::Size;
|
||||
use crate::error::{EventLoopError, NotSupportedError};
|
||||
use crate::event_loop::ActiveEventLoop;
|
||||
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
#[cfg(x11_platform)]
|
||||
use crate::platform::x11::WindowType as XWindowType;
|
||||
|
|
|
|||
|
|
@ -28,15 +28,16 @@ use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}
|
|||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::event::{SurfaceSizeWriter, WindowEvent};
|
||||
use crate::event_loop::AsyncRequestSerial;
|
||||
use crate::icon::RgbaIcon;
|
||||
use crate::monitor::{
|
||||
Fullscreen, MonitorHandle as CoreMonitorHandle, MonitorHandleProvider, VideoMode,
|
||||
};
|
||||
use crate::platform::x11::WindowType;
|
||||
use crate::platform_impl::common;
|
||||
use crate::platform_impl::x11::atoms::*;
|
||||
use crate::platform_impl::x11::{
|
||||
xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, X11Error,
|
||||
};
|
||||
use crate::platform_impl::{common, PlatformIcon};
|
||||
use crate::window::{
|
||||
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow,
|
||||
WindowAttributes, WindowButtons, WindowId, WindowLevel,
|
||||
|
|
@ -203,7 +204,11 @@ impl CoreWindow for Window {
|
|||
}
|
||||
|
||||
fn set_window_icon(&self, window_icon: Option<crate::window::Icon>) {
|
||||
self.0.set_window_icon(window_icon.map(|inner| inner.inner))
|
||||
let icon = match window_icon.as_ref() {
|
||||
Some(icon) => icon.0.cast_ref::<RgbaIcon>(),
|
||||
None => None,
|
||||
};
|
||||
self.0.set_window_icon(icon)
|
||||
}
|
||||
|
||||
fn set_ime_cursor_area(&self, position: Position, size: Size) {
|
||||
|
|
@ -765,8 +770,10 @@ impl UnownedWindow {
|
|||
.check());
|
||||
|
||||
// Set window icons
|
||||
if let Some(icon) = window_attrs.window_icon {
|
||||
leap!(window.set_icon_inner(icon.inner)).ignore_error();
|
||||
if let Some(icon) =
|
||||
window_attrs.window_icon.as_ref().and_then(|icon| icon.0.cast_ref::<RgbaIcon>())
|
||||
{
|
||||
leap!(window.set_icon_inner(icon)).ignore_error();
|
||||
}
|
||||
|
||||
// Opt into handling window close and resize synchronization
|
||||
|
|
@ -1404,7 +1411,7 @@ impl UnownedWindow {
|
|||
self.xconn.flush_requests().expect("Failed to set window-level state");
|
||||
}
|
||||
|
||||
fn set_icon_inner(&self, icon: PlatformIcon) -> Result<VoidCookie<'_>, X11Error> {
|
||||
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();
|
||||
|
|
@ -1431,7 +1438,7 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn set_window_icon(&self, icon: Option<PlatformIcon>) {
|
||||
pub(crate) fn set_window_icon(&self, icon: Option<&RgbaIcon>) {
|
||||
match icon {
|
||||
Some(icon) => self.set_icon_inner(icon),
|
||||
None => self.unset_icon_inner(),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ use std::{fmt, str};
|
|||
|
||||
pub(crate) use self::event_loop::{ActiveEventLoop, EventLoop};
|
||||
pub use self::window::Window;
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
|
||||
mod event_loop;
|
||||
mod window;
|
||||
|
|
|
|||
|
|
@ -42,4 +42,3 @@ pub(crate) use self::monitor::{
|
|||
};
|
||||
use self::web_sys as backend;
|
||||
pub use self::window::{PlatformSpecificWindowAttributes, Window};
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
|
|
|
|||
|
|
@ -5,13 +5,12 @@ use std::{fmt, io, mem, ptr};
|
|||
|
||||
use cursor_icon::CursorIcon;
|
||||
use windows_sys::core::PCWSTR;
|
||||
use windows_sys::Win32::Foundation::HWND;
|
||||
use windows_sys::Win32::Graphics::Gdi::{
|
||||
CreateBitmap, CreateCompatibleBitmap, DeleteObject, GetDC, ReleaseDC, SetBitmapBits,
|
||||
};
|
||||
use windows_sys::Win32::UI::WindowsAndMessaging::{
|
||||
CreateIcon, CreateIconIndirect, DestroyCursor, DestroyIcon, LoadImageW, SendMessageW, HCURSOR,
|
||||
HICON, ICONINFO, ICON_BIG, ICON_SMALL, IMAGE_ICON, LR_DEFAULTSIZE, LR_LOADFROMFILE, WM_SETICON,
|
||||
CreateIcon, CreateIconIndirect, DestroyCursor, DestroyIcon, LoadImageW, HCURSOR, HICON,
|
||||
ICONINFO, ICON_BIG, ICON_SMALL, IMAGE_ICON, LR_DEFAULTSIZE, LR_LOADFROMFILE,
|
||||
};
|
||||
|
||||
use super::util;
|
||||
|
|
@ -19,71 +18,12 @@ use crate::cursor::{CursorImage, CustomCursorProvider};
|
|||
use crate::dpi::PhysicalSize;
|
||||
use crate::error::RequestError;
|
||||
use crate::icon::*;
|
||||
|
||||
impl Pixel {
|
||||
fn convert_to_bgra(&mut self) {
|
||||
mem::swap(&mut self.r, &mut self.b);
|
||||
}
|
||||
}
|
||||
|
||||
impl RgbaIcon {
|
||||
fn into_windows_icon(self) -> Result<WinIcon, BadIcon> {
|
||||
let rgba = self.rgba;
|
||||
let pixel_count = rgba.len() / PIXEL_SIZE;
|
||||
let mut and_mask = Vec::with_capacity(pixel_count);
|
||||
let pixels =
|
||||
unsafe { std::slice::from_raw_parts_mut(rgba.as_ptr() as *mut Pixel, pixel_count) };
|
||||
for pixel in pixels {
|
||||
and_mask.push(pixel.a.wrapping_sub(u8::MAX)); // invert alpha channel
|
||||
pixel.convert_to_bgra();
|
||||
}
|
||||
assert_eq!(and_mask.len(), pixel_count);
|
||||
let handle = unsafe {
|
||||
CreateIcon(
|
||||
ptr::null_mut(),
|
||||
self.width as i32,
|
||||
self.height as i32,
|
||||
1,
|
||||
(PIXEL_SIZE * 8) as u8,
|
||||
and_mask.as_ptr(),
|
||||
rgba.as_ptr(),
|
||||
)
|
||||
};
|
||||
if !handle.is_null() {
|
||||
Ok(WinIcon::from_handle(handle))
|
||||
} else {
|
||||
Err(BadIcon::OsError(io::Error::last_os_error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IconType {
|
||||
Small = ICON_SMALL as isize,
|
||||
Big = ICON_BIG as isize,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
struct RaiiIcon {
|
||||
handle: HICON,
|
||||
}
|
||||
|
||||
unsafe impl Send for RaiiIcon {}
|
||||
unsafe impl Sync for RaiiIcon {}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct WinIcon {
|
||||
inner: Arc<RaiiIcon>,
|
||||
}
|
||||
use crate::platform::windows::WinIcon;
|
||||
|
||||
unsafe impl Send for WinIcon {}
|
||||
|
||||
impl WinIcon {
|
||||
pub fn as_raw_handle(&self) -> HICON {
|
||||
self.inner.handle
|
||||
}
|
||||
|
||||
pub fn from_path<P: AsRef<Path>>(
|
||||
pub(crate) fn from_path_impl<P: AsRef<Path>>(
|
||||
path: P,
|
||||
size: Option<PhysicalSize<u32>>,
|
||||
) -> Result<Self, BadIcon> {
|
||||
|
|
@ -109,14 +49,14 @@ impl WinIcon {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_resource(
|
||||
pub(crate) fn from_resource_impl(
|
||||
resource_id: u16,
|
||||
size: Option<PhysicalSize<u32>>,
|
||||
) -> Result<Self, BadIcon> {
|
||||
Self::from_resource_ptr(resource_id as PCWSTR, size)
|
||||
}
|
||||
|
||||
pub fn from_resource_name(
|
||||
pub(crate) fn from_resource_name_impl(
|
||||
resource_name: &str,
|
||||
size: Option<PhysicalSize<u32>>,
|
||||
) -> Result<Self, BadIcon> {
|
||||
|
|
@ -147,14 +87,36 @@ impl WinIcon {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
|
||||
let rgba_icon = RgbaIcon::from_rgba(rgba, width, height)?;
|
||||
rgba_icon.into_windows_icon()
|
||||
pub(crate) fn as_raw_handle(&self) -> HICON {
|
||||
self.inner.handle
|
||||
}
|
||||
|
||||
pub fn set_for_window(&self, hwnd: HWND, icon_type: IconType) {
|
||||
unsafe {
|
||||
SendMessageW(hwnd, WM_SETICON, icon_type as usize, self.as_raw_handle() as isize);
|
||||
pub(crate) fn from_rgba(rgba: &RgbaIcon) -> Result<Self, BadIcon> {
|
||||
let pixel_count = rgba.rgba.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)
|
||||
};
|
||||
for pixel in pixels {
|
||||
and_mask.push(pixel.a.wrapping_sub(u8::MAX)); // invert alpha channel
|
||||
pixel.convert_to_bgra();
|
||||
}
|
||||
assert_eq!(and_mask.len(), pixel_count);
|
||||
let handle = unsafe {
|
||||
CreateIcon(
|
||||
ptr::null_mut(),
|
||||
rgba.width as i32,
|
||||
rgba.height as i32,
|
||||
1,
|
||||
(PIXEL_SIZE * 8) as u8,
|
||||
and_mask.as_ptr(),
|
||||
rgba.rgba.as_ptr(),
|
||||
)
|
||||
};
|
||||
if !handle.is_null() {
|
||||
Ok(WinIcon::from_handle(handle))
|
||||
} else {
|
||||
Err(BadIcon::OsError(io::Error::last_os_error()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,11 +125,7 @@ impl WinIcon {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for RaiiIcon {
|
||||
fn drop(&mut self) {
|
||||
unsafe { DestroyIcon(self.handle) };
|
||||
}
|
||||
}
|
||||
impl IconProvider for WinIcon {}
|
||||
|
||||
impl fmt::Debug for WinIcon {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
|
|
@ -175,9 +133,29 @@ impl fmt::Debug for WinIcon {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn unset_for_window(hwnd: HWND, icon_type: IconType) {
|
||||
unsafe {
|
||||
SendMessageW(hwnd, WM_SETICON, icon_type as usize, 0);
|
||||
impl Pixel {
|
||||
fn convert_to_bgra(&mut self) {
|
||||
mem::swap(&mut self.r, &mut self.b);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum IconType {
|
||||
Small = ICON_SMALL as isize,
|
||||
Big = ICON_BIG as isize,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct RaiiIcon {
|
||||
handle: HICON,
|
||||
}
|
||||
|
||||
unsafe impl Send for RaiiIcon {}
|
||||
unsafe impl Sync for RaiiIcon {}
|
||||
|
||||
impl Drop for RaiiIcon {
|
||||
fn drop(&mut self) {
|
||||
unsafe { DestroyIcon(self.handle) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use windows_sys::Win32::Foundation::HWND;
|
|||
use windows_sys::Win32::UI::WindowsAndMessaging::{HMENU, WINDOW_LONG_PTR_INDEX};
|
||||
|
||||
pub(crate) use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes};
|
||||
pub(crate) use self::icon::{SelectedCursor, WinIcon as PlatformIcon, WinIcon};
|
||||
pub(crate) use self::icon::{RaiiIcon, SelectedCursor};
|
||||
pub(crate) use self::keyboard::{physicalkey_to_scancode, scancode_to_physicalkey};
|
||||
pub(crate) use self::monitor::MonitorHandle;
|
||||
pub(crate) use self::window::Window;
|
||||
|
|
@ -10,7 +10,7 @@ use crate::event::DeviceId;
|
|||
use crate::icon::Icon;
|
||||
use crate::platform::windows::{BackdropType, Color, CornerPreference};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PlatformSpecificWindowAttributes {
|
||||
pub owner: Option<HWND>,
|
||||
pub menu: Option<HMENU>,
|
||||
|
|
|
|||
|
|
@ -37,14 +37,15 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{
|
|||
CreateWindowExW, EnableMenuItem, FlashWindowEx, GetClientRect, GetCursorPos,
|
||||
GetForegroundWindow, GetSystemMenu, GetSystemMetrics, GetWindowPlacement, GetWindowTextLengthW,
|
||||
GetWindowTextW, IsWindowVisible, LoadCursorW, PeekMessageW, PostMessageW, RegisterClassExW,
|
||||
SetCursor, SetCursorPos, SetForegroundWindow, SetMenuDefaultItem, SetWindowDisplayAffinity,
|
||||
SetWindowPlacement, SetWindowPos, SetWindowTextW, TrackPopupMenu, CS_HREDRAW, CS_VREDRAW,
|
||||
CW_USEDEFAULT, FLASHWINFO, FLASHW_ALL, FLASHW_STOP, FLASHW_TIMERNOFG, FLASHW_TRAY,
|
||||
GWLP_HINSTANCE, HTBOTTOM, HTBOTTOMLEFT, HTBOTTOMRIGHT, HTCAPTION, HTLEFT, HTRIGHT, HTTOP,
|
||||
HTTOPLEFT, HTTOPRIGHT, MENU_ITEM_STATE, MFS_DISABLED, MFS_ENABLED, MF_BYCOMMAND, NID_READY,
|
||||
PM_NOREMOVE, SC_CLOSE, SC_MAXIMIZE, SC_MINIMIZE, SC_MOVE, SC_RESTORE, SC_SIZE, SM_DIGITIZER,
|
||||
SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOSIZE, SWP_NOZORDER, TPM_LEFTALIGN, TPM_RETURNCMD,
|
||||
WDA_EXCLUDEFROMCAPTURE, WDA_NONE, WM_NCLBUTTONDOWN, WM_SYSCOMMAND, WNDCLASSEXW,
|
||||
SendMessageW, SetCursor, SetCursorPos, SetForegroundWindow, SetMenuDefaultItem,
|
||||
SetWindowDisplayAffinity, SetWindowPlacement, SetWindowPos, SetWindowTextW, TrackPopupMenu,
|
||||
CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, FLASHWINFO, FLASHW_ALL, FLASHW_STOP, FLASHW_TIMERNOFG,
|
||||
FLASHW_TRAY, GWLP_HINSTANCE, HTBOTTOM, HTBOTTOMLEFT, HTBOTTOMRIGHT, HTCAPTION, HTLEFT, HTRIGHT,
|
||||
HTTOP, HTTOPLEFT, HTTOPRIGHT, MENU_ITEM_STATE, MFS_DISABLED, MFS_ENABLED, MF_BYCOMMAND,
|
||||
NID_READY, PM_NOREMOVE, SC_CLOSE, SC_MAXIMIZE, SC_MINIMIZE, SC_MOVE, SC_RESTORE, SC_SIZE,
|
||||
SM_DIGITIZER, SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOSIZE, SWP_NOZORDER, TPM_LEFTALIGN,
|
||||
TPM_RETURNCMD, WDA_EXCLUDEFROMCAPTURE, WDA_NONE, WM_NCLBUTTONDOWN, WM_SETICON, WM_SYSCOMMAND,
|
||||
WNDCLASSEXW,
|
||||
};
|
||||
|
||||
use super::icon::WinCursor;
|
||||
|
|
@ -52,9 +53,9 @@ use super::MonitorHandle;
|
|||
use crate::cursor::Cursor;
|
||||
use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::icon::Icon;
|
||||
use crate::icon::{Icon, RgbaIcon};
|
||||
use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle, MonitorHandleProvider};
|
||||
use crate::platform::windows::{BackdropType, Color, CornerPreference};
|
||||
use crate::platform::windows::{BackdropType, Color, CornerPreference, WinIcon};
|
||||
use crate::platform_impl::platform::dark_mode::try_theme;
|
||||
use crate::platform_impl::platform::definitions::{
|
||||
CLSID_TaskbarList, IID_ITaskbarList, IID_ITaskbarList2, ITaskbarList, ITaskbarList2,
|
||||
|
|
@ -66,7 +67,7 @@ use crate::platform_impl::platform::drop_handler::FileDropHandler;
|
|||
use crate::platform_impl::platform::event_loop::{
|
||||
self, ActiveEventLoop, Event, EventLoopRunner, DESTROY_MSG_ID,
|
||||
};
|
||||
use crate::platform_impl::platform::icon::{self, IconType};
|
||||
use crate::platform_impl::platform::icon::IconType;
|
||||
use crate::platform_impl::platform::ime::ImeContext;
|
||||
use crate::platform_impl::platform::keyboard::KeyEventBuilder;
|
||||
use crate::platform_impl::platform::window_state::{
|
||||
|
|
@ -189,12 +190,11 @@ impl Window {
|
|||
}
|
||||
|
||||
pub fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) {
|
||||
if let Some(ref taskbar_icon) = taskbar_icon {
|
||||
taskbar_icon.inner.set_for_window(self.hwnd(), IconType::Big);
|
||||
if let Some(taskbar_icon) = taskbar_icon {
|
||||
self.set_icon(taskbar_icon, IconType::Big);
|
||||
} else {
|
||||
icon::unset_for_window(self.hwnd(), IconType::Big);
|
||||
self.unset_icon(IconType::Big);
|
||||
}
|
||||
self.window_state_lock().taskbar_icon = taskbar_icon;
|
||||
}
|
||||
|
||||
unsafe fn handle_os_dragging(&self, wparam: WPARAM) {
|
||||
|
|
@ -349,6 +349,45 @@ impl Window {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_icon(&self, mut new_icon: Icon, icon_type: IconType) {
|
||||
if let Some(icon) = new_icon.0.cast_ref::<RgbaIcon>() {
|
||||
let icon = match WinIcon::from_rgba(icon) {
|
||||
Ok(icon) => icon,
|
||||
Err(err) => {
|
||||
warn!("{}", err);
|
||||
return;
|
||||
},
|
||||
};
|
||||
new_icon = Icon(Arc::new(icon));
|
||||
}
|
||||
|
||||
if let Some(icon) = new_icon.0.cast_ref::<WinIcon>() {
|
||||
unsafe {
|
||||
SendMessageW(
|
||||
self.hwnd(),
|
||||
WM_SETICON,
|
||||
icon_type as usize,
|
||||
icon.as_raw_handle() as isize,
|
||||
);
|
||||
}
|
||||
|
||||
match icon_type {
|
||||
IconType::Small => self.window_state_lock().window_icon = Some(new_icon),
|
||||
IconType::Big => self.window_state_lock().taskbar_icon = Some(new_icon),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unset_icon(&self, icon_type: IconType) {
|
||||
unsafe {
|
||||
SendMessageW(self.hwnd(), WM_SETICON, icon_type as usize, 0);
|
||||
}
|
||||
match icon_type {
|
||||
IconType::Small => self.window_state_lock().window_icon = None,
|
||||
IconType::Big => self.window_state_lock().taskbar_icon = None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Window {
|
||||
|
|
@ -974,12 +1013,11 @@ impl CoreWindow for Window {
|
|||
}
|
||||
|
||||
fn set_window_icon(&self, window_icon: Option<Icon>) {
|
||||
if let Some(ref window_icon) = window_icon {
|
||||
window_icon.inner.set_for_window(self.hwnd(), IconType::Small);
|
||||
if let Some(window_icon) = window_icon {
|
||||
self.set_icon(window_icon, IconType::Small);
|
||||
} else {
|
||||
icon::unset_for_window(self.hwnd(), IconType::Small);
|
||||
self.unset_icon(IconType::Small);
|
||||
}
|
||||
self.window_state_lock().window_icon = window_icon;
|
||||
}
|
||||
|
||||
fn set_ime_cursor_area(&self, spot: Position, size: Size) {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ impl fmt::Debug for WindowId {
|
|||
}
|
||||
|
||||
/// Attributes used when creating a window.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowAttributes {
|
||||
pub surface_size: Option<Size>,
|
||||
pub min_surface_size: Option<Size>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue