mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-23 10:26:34 +11:00
Add ability to create Icons from embedded resources on Windows (#1410)
* Add IconExtWindows trait * Move changelog entries to unreleased category Co-authored-by: Osspial <osspial@gmail.com>
This commit is contained in:
parent
2f27f64cdb
commit
098fd5d602
14 changed files with 266 additions and 126 deletions
|
@ -12,6 +12,8 @@
|
||||||
- On Wayland, Hide CSD for fullscreen windows.
|
- On Wayland, Hide CSD for fullscreen windows.
|
||||||
- On Windows, ignore spurious mouse move messages.
|
- On Windows, ignore spurious mouse move messages.
|
||||||
- **Breaking:** Move `ModifiersChanged` variant from `DeviceEvent` to `WindowEvent`.
|
- **Breaking:** Move `ModifiersChanged` variant from `DeviceEvent` to `WindowEvent`.
|
||||||
|
- On Windows, add `IconExtWindows` trait which exposes creating an `Icon` from an external file or embedded resource
|
||||||
|
- Add `BadIcon::OsError` variant for when OS icon functionality fails
|
||||||
- On Windows, fix crash at startup on systems that do not properly support Windows' Dark Mode
|
- On Windows, fix crash at startup on systems that do not properly support Windows' Dark Mode
|
||||||
|
|
||||||
# 0.21.0 (2020-02-04)
|
# 0.21.0 (2020-02-04)
|
||||||
|
|
56
src/icon.rs
56
src/icon.rs
|
@ -1,4 +1,5 @@
|
||||||
use std::{error::Error, fmt, mem};
|
use crate::platform_impl::PlatformIcon;
|
||||||
|
use std::{error::Error, fmt, io, mem};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -11,7 +12,7 @@ pub(crate) struct Pixel {
|
||||||
|
|
||||||
pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
|
pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug)]
|
||||||
/// An error produced when using `Icon::from_rgba` with invalid arguments.
|
/// An error produced when using `Icon::from_rgba` with invalid arguments.
|
||||||
pub enum BadIcon {
|
pub enum BadIcon {
|
||||||
/// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
|
/// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
|
||||||
|
@ -25,6 +26,8 @@ pub enum BadIcon {
|
||||||
width_x_height: usize,
|
width_x_height: usize,
|
||||||
pixel_count: usize,
|
pixel_count: usize,
|
||||||
},
|
},
|
||||||
|
/// Produced when underlying OS functionality failed to create the icon
|
||||||
|
OsError(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for BadIcon {
|
impl fmt::Display for BadIcon {
|
||||||
|
@ -43,6 +46,7 @@ impl fmt::Display for BadIcon {
|
||||||
"The specified dimensions ({:?}x{:?}) don't match the number of pixels supplied by the `rgba` argument ({:?}). For those dimensions, the expected pixel count is {:?}.",
|
"The specified dimensions ({:?}x{:?}) don't match the number of pixels supplied by the `rgba` argument ({:?}). For those dimensions, the expected pixel count is {:?}.",
|
||||||
width, height, pixel_count, width_x_height,
|
width, height, pixel_count, width_x_height,
|
||||||
),
|
),
|
||||||
|
BadIcon::OsError(e) => write!(f, "OS error when instantiating the icon: {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,14 +58,21 @@ impl Error for BadIcon {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
/// An icon used for the window titlebar, taskbar, etc.
|
pub(crate) struct RgbaIcon {
|
||||||
pub struct Icon {
|
|
||||||
pub(crate) rgba: Vec<u8>,
|
pub(crate) rgba: Vec<u8>,
|
||||||
pub(crate) width: u32,
|
pub(crate) width: u32,
|
||||||
pub(crate) height: u32,
|
pub(crate) height: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Icon {
|
/// For platforms which don't have window icons (e.g. web)
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub(crate) struct NoIcon;
|
||||||
|
|
||||||
|
#[allow(dead_code)] // These are not used on every platform
|
||||||
|
mod constructors {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl RgbaIcon {
|
||||||
/// Creates an `Icon` from 32bpp RGBA data.
|
/// Creates an `Icon` from 32bpp RGBA data.
|
||||||
///
|
///
|
||||||
/// The length of `rgba` must be divisible by 4, and `width * height` must equal
|
/// The length of `rgba` must be divisible by 4, and `width * height` must equal
|
||||||
|
@ -81,11 +92,44 @@ impl Icon {
|
||||||
pixel_count,
|
pixel_count,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Ok(Icon {
|
Ok(RgbaIcon {
|
||||||
rgba,
|
rgba,
|
||||||
width,
|
width,
|
||||||
height,
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An icon used for the window titlebar, taskbar, etc.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Icon {
|
||||||
|
pub(crate) inner: PlatformIcon,
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
Ok(Icon {
|
||||||
|
inner: PlatformIcon::from_rgba(rgba, width, height)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
#![cfg(target_os = "windows")]
|
#![cfg(target_os = "windows")]
|
||||||
|
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use libc;
|
use libc;
|
||||||
|
use winapi::shared::minwindef::WORD;
|
||||||
use winapi::shared::windef::HWND;
|
use winapi::shared::windef::HWND;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
dpi::PhysicalSize,
|
||||||
event::DeviceId,
|
event::DeviceId,
|
||||||
event_loop::EventLoop,
|
event_loop::EventLoop,
|
||||||
monitor::MonitorHandle,
|
monitor::MonitorHandle,
|
||||||
platform_impl::EventLoop as WindowsEventLoop,
|
platform_impl::{EventLoop as WindowsEventLoop, WinIcon},
|
||||||
window::{Icon, Window, WindowBuilder},
|
window::{BadIcon, Icon, Window, WindowBuilder},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Additional methods on `EventLoop` that are specific to Windows.
|
/// Additional methods on `EventLoop` that are specific to Windows.
|
||||||
|
@ -171,3 +174,40 @@ impl DeviceIdExtWindows for DeviceId {
|
||||||
self.0.persistent_identifier()
|
self.0.persistent_identifier()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Additional methods on `Icon` that are specific to Windows.
|
||||||
|
pub trait IconExtWindows: Sized {
|
||||||
|
/// Create an icon from a file path.
|
||||||
|
///
|
||||||
|
/// 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_path<P: AsRef<Path>>(path: P, size: Option<PhysicalSize<u32>>)
|
||||||
|
-> Result<Self, BadIcon>;
|
||||||
|
|
||||||
|
/// Create an icon from a resource embedded in this executable or library.
|
||||||
|
///
|
||||||
|
/// 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: WORD, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IconExtWindows for Icon {
|
||||||
|
fn from_path<P: AsRef<Path>>(
|
||||||
|
path: P,
|
||||||
|
size: Option<PhysicalSize<u32>>,
|
||||||
|
) -> Result<Self, BadIcon> {
|
||||||
|
let win_icon = WinIcon::from_path(path, size)?;
|
||||||
|
Ok(Icon { inner: win_icon })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_resource(ordinal: WORD, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> {
|
||||||
|
let win_icon = WinIcon::from_resource(ordinal, size)?;
|
||||||
|
Ok(Icon { inner: win_icon })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ use crate::{
|
||||||
use raw_window_handle::{android::AndroidHandle, RawWindowHandle};
|
use raw_window_handle::{android::AndroidHandle, RawWindowHandle};
|
||||||
use CreationError::OsError;
|
use CreationError::OsError;
|
||||||
|
|
||||||
|
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||||
|
|
||||||
pub type OsError = std::io::Error;
|
pub type OsError = std::io::Error;
|
||||||
|
|
||||||
pub struct EventLoop {
|
pub struct EventLoop {
|
||||||
|
|
|
@ -83,6 +83,8 @@ pub use self::{
|
||||||
window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId},
|
window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct DeviceId {
|
pub struct DeviceId {
|
||||||
uiscreen: ffi::id,
|
uiscreen: ffi::id,
|
||||||
|
|
|
@ -18,6 +18,8 @@ use crate::{
|
||||||
window::{CursorIcon, Fullscreen, WindowAttributes},
|
window::{CursorIcon, Fullscreen, WindowAttributes},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
|
||||||
|
|
||||||
pub mod wayland;
|
pub mod wayland;
|
||||||
pub mod x11;
|
pub mod x11;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::window::{Icon, Pixel, PIXEL_SIZE};
|
use crate::icon::{Icon, Pixel, PIXEL_SIZE};
|
||||||
|
|
||||||
impl Pixel {
|
impl Pixel {
|
||||||
pub fn to_packed_argb(&self) -> Cardinal {
|
pub fn to_packed_argb(&self) -> Cardinal {
|
||||||
|
@ -18,13 +18,14 @@ impl Pixel {
|
||||||
|
|
||||||
impl Icon {
|
impl Icon {
|
||||||
pub(crate) fn to_cardinals(&self) -> Vec<Cardinal> {
|
pub(crate) fn to_cardinals(&self) -> Vec<Cardinal> {
|
||||||
assert_eq!(self.rgba.len() % PIXEL_SIZE, 0);
|
let rgba_icon = &self.inner;
|
||||||
let pixel_count = self.rgba.len() / PIXEL_SIZE;
|
assert_eq!(rgba_icon.rgba.len() % PIXEL_SIZE, 0);
|
||||||
assert_eq!(pixel_count, (self.width * self.height) as usize);
|
let pixel_count = rgba_icon.rgba.len() / PIXEL_SIZE;
|
||||||
|
assert_eq!(pixel_count, (rgba_icon.width * rgba_icon.height) as usize);
|
||||||
let mut data = Vec::with_capacity(pixel_count);
|
let mut data = Vec::with_capacity(pixel_count);
|
||||||
data.push(self.width as Cardinal);
|
data.push(rgba_icon.width as Cardinal);
|
||||||
data.push(self.height as Cardinal);
|
data.push(rgba_icon.height as Cardinal);
|
||||||
let pixels = self.rgba.as_ptr() as *const Pixel;
|
let pixels = rgba_icon.rgba.as_ptr() as *const Pixel;
|
||||||
for pixel_index in 0..pixel_count {
|
for pixel_index in 0..pixel_count {
|
||||||
let pixel = unsafe { &*pixels.offset(pixel_index as isize) };
|
let pixel = unsafe { &*pixels.offset(pixel_index as isize) };
|
||||||
data.push(pixel.to_packed_argb());
|
data.push(pixel.to_packed_argb());
|
||||||
|
|
|
@ -25,6 +25,8 @@ use crate::{
|
||||||
error::OsError as RootOsError, event::DeviceId as RootDeviceId, window::WindowAttributes,
|
error::OsError as RootOsError, event::DeviceId as RootDeviceId, window::WindowAttributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct DeviceId;
|
pub struct DeviceId;
|
||||||
|
|
||||||
|
|
|
@ -44,3 +44,5 @@ pub use self::window::{
|
||||||
Id as WindowId, PlatformSpecificBuilderAttributes as PlatformSpecificWindowBuilderAttributes,
|
Id as WindowId, PlatformSpecificBuilderAttributes as PlatformSpecificWindowBuilderAttributes,
|
||||||
Window,
|
Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
use std::{io, mem, os::windows::ffi::OsStrExt, path::Path, ptr};
|
use std::{fmt, io, iter::once, mem, os::windows::ffi::OsStrExt, path::Path, ptr, sync::Arc};
|
||||||
|
|
||||||
use winapi::{
|
use winapi::{
|
||||||
ctypes::{c_int, wchar_t},
|
ctypes::{c_int, wchar_t},
|
||||||
shared::{
|
shared::{
|
||||||
minwindef::{BYTE, LPARAM, WPARAM},
|
minwindef::{BYTE, LPARAM, WORD, WPARAM},
|
||||||
windef::{HICON, HWND},
|
windef::{HICON, HWND},
|
||||||
},
|
},
|
||||||
|
um::libloaderapi,
|
||||||
um::winuser,
|
um::winuser,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::icon::{Icon, Pixel, PIXEL_SIZE};
|
use crate::dpi::PhysicalSize;
|
||||||
|
use crate::icon::*;
|
||||||
|
|
||||||
impl Pixel {
|
impl Pixel {
|
||||||
fn to_bgra(&mut self) {
|
fn to_bgra(&mut self) {
|
||||||
|
@ -17,92 +19,149 @@ impl Pixel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RgbaIcon {
|
||||||
|
fn into_windows_icon(self) -> Result<WinIcon, BadIcon> {
|
||||||
|
let mut 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_mut_ptr() as *mut Pixel, pixel_count) };
|
||||||
|
for pixel in pixels {
|
||||||
|
and_mask.push(pixel.a.wrapping_sub(std::u8::MAX)); // invert alpha channel
|
||||||
|
pixel.to_bgra();
|
||||||
|
}
|
||||||
|
assert_eq!(and_mask.len(), pixel_count);
|
||||||
|
let handle = unsafe {
|
||||||
|
winuser::CreateIcon(
|
||||||
|
ptr::null_mut(),
|
||||||
|
self.width as c_int,
|
||||||
|
self.height as c_int,
|
||||||
|
1,
|
||||||
|
(PIXEL_SIZE * 8) as BYTE,
|
||||||
|
and_mask.as_ptr() as *const BYTE,
|
||||||
|
rgba.as_ptr() as *const BYTE,
|
||||||
|
) as HICON
|
||||||
|
};
|
||||||
|
if !handle.is_null() {
|
||||||
|
Ok(WinIcon::from_handle(handle))
|
||||||
|
} else {
|
||||||
|
Err(BadIcon::OsError(io::Error::last_os_error()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum IconType {
|
pub enum IconType {
|
||||||
Small = winuser::ICON_SMALL as isize,
|
Small = winuser::ICON_SMALL as isize,
|
||||||
Big = winuser::ICON_BIG as isize,
|
Big = winuser::ICON_BIG as isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
|
struct RaiiIcon {
|
||||||
|
handle: HICON,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct WinIcon {
|
pub struct WinIcon {
|
||||||
pub handle: HICON,
|
inner: Arc<RaiiIcon>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for WinIcon {}
|
unsafe impl Send for WinIcon {}
|
||||||
|
|
||||||
impl WinIcon {
|
impl WinIcon {
|
||||||
#[allow(dead_code)]
|
pub fn as_raw_handle(&self) -> HICON {
|
||||||
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
|
self.inner.handle
|
||||||
let wide_path: Vec<u16> = path.as_ref().as_os_str().encode_wide().collect();
|
}
|
||||||
|
|
||||||
|
pub fn from_path<P: AsRef<Path>>(
|
||||||
|
path: P,
|
||||||
|
size: Option<PhysicalSize<u32>>,
|
||||||
|
) -> Result<Self, BadIcon> {
|
||||||
|
let wide_path: Vec<u16> = path
|
||||||
|
.as_ref()
|
||||||
|
.as_os_str()
|
||||||
|
.encode_wide()
|
||||||
|
.chain(once(0))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// width / height of 0 along with LR_DEFAULTSIZE tells windows to load the default icon size
|
||||||
|
let (width, height) = size.map(Into::into).unwrap_or((0, 0));
|
||||||
|
|
||||||
let handle = unsafe {
|
let handle = unsafe {
|
||||||
winuser::LoadImageW(
|
winuser::LoadImageW(
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
wide_path.as_ptr() as *const wchar_t,
|
wide_path.as_ptr() as *const wchar_t,
|
||||||
winuser::IMAGE_ICON,
|
winuser::IMAGE_ICON,
|
||||||
0, // 0 indicates that we want to use the actual width
|
|
||||||
0, // and height
|
|
||||||
winuser::LR_LOADFROMFILE,
|
|
||||||
) as HICON
|
|
||||||
};
|
|
||||||
if !handle.is_null() {
|
|
||||||
Ok(WinIcon { handle })
|
|
||||||
} else {
|
|
||||||
Err(io::Error::last_os_error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_icon(icon: Icon) -> Result<Self, io::Error> {
|
|
||||||
Self::from_rgba(icon.rgba, icon.width, icon.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_rgba(mut rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, io::Error> {
|
|
||||||
assert_eq!(rgba.len() % PIXEL_SIZE, 0);
|
|
||||||
let pixel_count = rgba.len() / PIXEL_SIZE;
|
|
||||||
assert_eq!(pixel_count, (width * height) as usize);
|
|
||||||
let mut and_mask = Vec::with_capacity(pixel_count);
|
|
||||||
let pixels = rgba.as_mut_ptr() as *mut Pixel; // how not to write idiomatic Rust
|
|
||||||
for pixel_index in 0..pixel_count {
|
|
||||||
let pixel = unsafe { &mut *pixels.offset(pixel_index as isize) };
|
|
||||||
and_mask.push(pixel.a.wrapping_sub(std::u8::MAX)); // invert alpha channel
|
|
||||||
pixel.to_bgra();
|
|
||||||
}
|
|
||||||
assert_eq!(and_mask.len(), pixel_count);
|
|
||||||
let handle = unsafe {
|
|
||||||
winuser::CreateIcon(
|
|
||||||
ptr::null_mut(),
|
|
||||||
width as c_int,
|
width as c_int,
|
||||||
height as c_int,
|
height as c_int,
|
||||||
1,
|
winuser::LR_DEFAULTSIZE | winuser::LR_LOADFROMFILE,
|
||||||
(PIXEL_SIZE * 8) as BYTE,
|
|
||||||
and_mask.as_ptr() as *const BYTE,
|
|
||||||
rgba.as_ptr() as *const BYTE,
|
|
||||||
) as HICON
|
) as HICON
|
||||||
};
|
};
|
||||||
if !handle.is_null() {
|
if !handle.is_null() {
|
||||||
Ok(WinIcon { handle })
|
Ok(WinIcon::from_handle(handle))
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::last_os_error())
|
Err(BadIcon::OsError(io::Error::last_os_error()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_resource(
|
||||||
|
resource_id: WORD,
|
||||||
|
size: Option<PhysicalSize<u32>>,
|
||||||
|
) -> Result<Self, BadIcon> {
|
||||||
|
// width / height of 0 along with LR_DEFAULTSIZE tells windows to load the default icon size
|
||||||
|
let (width, height) = size.map(Into::into).unwrap_or((0, 0));
|
||||||
|
let handle = unsafe {
|
||||||
|
winuser::LoadImageW(
|
||||||
|
libloaderapi::GetModuleHandleW(ptr::null_mut()),
|
||||||
|
winuser::MAKEINTRESOURCEW(resource_id),
|
||||||
|
winuser::IMAGE_ICON,
|
||||||
|
width as c_int,
|
||||||
|
height as c_int,
|
||||||
|
winuser::LR_DEFAULTSIZE,
|
||||||
|
) as HICON
|
||||||
|
};
|
||||||
|
if !handle.is_null() {
|
||||||
|
Ok(WinIcon::from_handle(handle))
|
||||||
|
} else {
|
||||||
|
Err(BadIcon::OsError(io::Error::last_os_error()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 fn set_for_window(&self, hwnd: HWND, icon_type: IconType) {
|
pub fn set_for_window(&self, hwnd: HWND, icon_type: IconType) {
|
||||||
unsafe {
|
unsafe {
|
||||||
winuser::SendMessageW(
|
winuser::SendMessageW(
|
||||||
hwnd,
|
hwnd,
|
||||||
winuser::WM_SETICON,
|
winuser::WM_SETICON,
|
||||||
icon_type as WPARAM,
|
icon_type as WPARAM,
|
||||||
self.handle as LPARAM,
|
self.as_raw_handle() as LPARAM,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_handle(handle: HICON) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Arc::new(RaiiIcon { handle }),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for WinIcon {
|
impl Drop for RaiiIcon {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { winuser::DestroyIcon(self.handle) };
|
unsafe { winuser::DestroyIcon(self.handle) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for WinIcon {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
|
(*self.inner).fmt(formatter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn unset_for_window(hwnd: HWND, icon_type: IconType) {
|
pub fn unset_for_window(hwnd: HWND, icon_type: IconType) {
|
||||||
unsafe {
|
unsafe {
|
||||||
winuser::SendMessageW(hwnd, winuser::WM_SETICON, icon_type as WPARAM, 0 as LPARAM);
|
winuser::SendMessageW(hwnd, winuser::WM_SETICON, icon_type as WPARAM, 0 as LPARAM);
|
||||||
|
|
|
@ -4,11 +4,15 @@ use winapi::{self, shared::windef::HWND};
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget},
|
event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget},
|
||||||
|
icon::WinIcon,
|
||||||
monitor::{MonitorHandle, VideoMode},
|
monitor::{MonitorHandle, VideoMode},
|
||||||
window::Window,
|
window::Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{event::DeviceId as RootDeviceId, window::Icon};
|
pub use self::icon::WinIcon as PlatformIcon;
|
||||||
|
|
||||||
|
use crate::event::DeviceId as RootDeviceId;
|
||||||
|
use crate::icon::Icon;
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct PlatformSpecificWindowBuilderAttributes {
|
pub struct PlatformSpecificWindowBuilderAttributes {
|
||||||
|
|
|
@ -32,18 +32,19 @@ use winapi::{
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||||
|
icon::Icon,
|
||||||
monitor::MonitorHandle as RootMonitorHandle,
|
monitor::MonitorHandle as RootMonitorHandle,
|
||||||
platform_impl::platform::{
|
platform_impl::platform::{
|
||||||
dark_mode::try_dark_mode,
|
dark_mode::try_dark_mode,
|
||||||
dpi::{dpi_to_scale_factor, hwnd_dpi},
|
dpi::{dpi_to_scale_factor, hwnd_dpi},
|
||||||
drop_handler::FileDropHandler,
|
drop_handler::FileDropHandler,
|
||||||
event_loop::{self, EventLoopWindowTarget, DESTROY_MSG_ID},
|
event_loop::{self, EventLoopWindowTarget, DESTROY_MSG_ID},
|
||||||
icon::{self, IconType, WinIcon},
|
icon::{self, IconType},
|
||||||
monitor, util,
|
monitor, util,
|
||||||
window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState},
|
window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState},
|
||||||
PlatformSpecificWindowBuilderAttributes, WindowId,
|
PlatformSpecificWindowBuilderAttributes, WindowId,
|
||||||
},
|
},
|
||||||
window::{CursorIcon, Fullscreen, Icon, WindowAttributes},
|
window::{CursorIcon, Fullscreen, WindowAttributes},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The Win32 implementation of the main `Window` object.
|
/// The Win32 implementation of the main `Window` object.
|
||||||
|
@ -576,12 +577,11 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_window_icon(&self, mut window_icon: Option<Icon>) {
|
pub fn set_window_icon(&self, window_icon: Option<Icon>) {
|
||||||
let window_icon = window_icon
|
|
||||||
.take()
|
|
||||||
.map(|icon| WinIcon::from_icon(icon).expect("Failed to create `ICON_SMALL`"));
|
|
||||||
if let Some(ref window_icon) = window_icon {
|
if let Some(ref window_icon) = window_icon {
|
||||||
window_icon.set_for_window(self.window.0, IconType::Small);
|
window_icon
|
||||||
|
.inner
|
||||||
|
.set_for_window(self.window.0, IconType::Small);
|
||||||
} else {
|
} else {
|
||||||
icon::unset_for_window(self.window.0, IconType::Small);
|
icon::unset_for_window(self.window.0, IconType::Small);
|
||||||
}
|
}
|
||||||
|
@ -589,12 +589,11 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_taskbar_icon(&self, mut taskbar_icon: Option<Icon>) {
|
pub fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) {
|
||||||
let taskbar_icon = taskbar_icon
|
|
||||||
.take()
|
|
||||||
.map(|icon| WinIcon::from_icon(icon).expect("Failed to create `ICON_BIG`"));
|
|
||||||
if let Some(ref taskbar_icon) = taskbar_icon {
|
if let Some(ref taskbar_icon) = taskbar_icon {
|
||||||
taskbar_icon.set_for_window(self.window.0, IconType::Big);
|
taskbar_icon
|
||||||
|
.inner
|
||||||
|
.set_for_window(self.window.0, IconType::Big);
|
||||||
} else {
|
} else {
|
||||||
icon::unset_for_window(self.window.0, IconType::Big);
|
icon::unset_for_window(self.window.0, IconType::Big);
|
||||||
}
|
}
|
||||||
|
@ -636,7 +635,7 @@ unsafe impl Sync for WindowWrapper {}
|
||||||
unsafe impl Send for WindowWrapper {}
|
unsafe impl Send for WindowWrapper {}
|
||||||
|
|
||||||
unsafe fn init<T: 'static>(
|
unsafe fn init<T: 'static>(
|
||||||
mut attributes: WindowAttributes,
|
attributes: WindowAttributes,
|
||||||
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||||
event_loop: &EventLoopWindowTarget<T>,
|
event_loop: &EventLoopWindowTarget<T>,
|
||||||
) -> Result<Window, RootOsError> {
|
) -> Result<Window, RootOsError> {
|
||||||
|
@ -645,25 +644,8 @@ unsafe fn init<T: 'static>(
|
||||||
.chain(Some(0).into_iter())
|
.chain(Some(0).into_iter())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let window_icon = {
|
|
||||||
let icon = attributes.window_icon.take().map(WinIcon::from_icon);
|
|
||||||
if let Some(icon) = icon {
|
|
||||||
Some(icon.map_err(|e| os_error!(e))?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let taskbar_icon = {
|
|
||||||
let icon = attributes.window_icon.take().map(WinIcon::from_icon);
|
|
||||||
if let Some(icon) = icon {
|
|
||||||
Some(icon.map_err(|e| os_error!(e))?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// registering the window class
|
// registering the window class
|
||||||
let class_name = register_window_class(&window_icon, &taskbar_icon);
|
let class_name = register_window_class(&attributes.window_icon, &pl_attribs.taskbar_icon);
|
||||||
|
|
||||||
let mut window_flags = WindowFlags::empty();
|
let mut window_flags = WindowFlags::empty();
|
||||||
window_flags.set(WindowFlags::DECORATIONS, attributes.decorations);
|
window_flags.set(WindowFlags::DECORATIONS, attributes.decorations);
|
||||||
|
@ -756,8 +738,7 @@ unsafe fn init<T: 'static>(
|
||||||
let window_state = {
|
let window_state = {
|
||||||
let window_state = WindowState::new(
|
let window_state = WindowState::new(
|
||||||
&attributes,
|
&attributes,
|
||||||
window_icon,
|
pl_attribs.taskbar_icon,
|
||||||
taskbar_icon,
|
|
||||||
scale_factor,
|
scale_factor,
|
||||||
dark_mode,
|
dark_mode,
|
||||||
);
|
);
|
||||||
|
@ -787,8 +768,8 @@ unsafe fn init<T: 'static>(
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn register_window_class(
|
unsafe fn register_window_class(
|
||||||
window_icon: &Option<WinIcon>,
|
window_icon: &Option<Icon>,
|
||||||
taskbar_icon: &Option<WinIcon>,
|
taskbar_icon: &Option<Icon>,
|
||||||
) -> Vec<u16> {
|
) -> Vec<u16> {
|
||||||
let class_name: Vec<_> = OsStr::new("Window Class")
|
let class_name: Vec<_> = OsStr::new("Window Class")
|
||||||
.encode_wide()
|
.encode_wide()
|
||||||
|
@ -797,11 +778,11 @@ unsafe fn register_window_class(
|
||||||
|
|
||||||
let h_icon = taskbar_icon
|
let h_icon = taskbar_icon
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|icon| icon.handle)
|
.map(|icon| icon.inner.as_raw_handle())
|
||||||
.unwrap_or(ptr::null_mut());
|
.unwrap_or(ptr::null_mut());
|
||||||
let h_icon_small = window_icon
|
let h_icon_small = window_icon
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|icon| icon.handle)
|
.map(|icon| icon.inner.as_raw_handle())
|
||||||
.unwrap_or(ptr::null_mut());
|
.unwrap_or(ptr::null_mut());
|
||||||
|
|
||||||
let class = winuser::WNDCLASSEXW {
|
let class = winuser::WNDCLASSEXW {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::{PhysicalPosition, Size},
|
dpi::{PhysicalPosition, Size},
|
||||||
event::ModifiersState,
|
event::ModifiersState,
|
||||||
platform_impl::platform::{event_loop, icon::WinIcon, util},
|
icon::Icon,
|
||||||
|
platform_impl::platform::{event_loop, util},
|
||||||
window::{CursorIcon, Fullscreen, WindowAttributes},
|
window::{CursorIcon, Fullscreen, WindowAttributes},
|
||||||
};
|
};
|
||||||
use parking_lot::MutexGuard;
|
use parking_lot::MutexGuard;
|
||||||
|
@ -15,7 +16,6 @@ use winapi::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Contains information about states and the window that the callback is going to use.
|
/// Contains information about states and the window that the callback is going to use.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct WindowState {
|
pub struct WindowState {
|
||||||
pub mouse: MouseProperties,
|
pub mouse: MouseProperties,
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@ pub struct WindowState {
|
||||||
pub min_size: Option<Size>,
|
pub min_size: Option<Size>,
|
||||||
pub max_size: Option<Size>,
|
pub max_size: Option<Size>,
|
||||||
|
|
||||||
pub window_icon: Option<WinIcon>,
|
pub window_icon: Option<Icon>,
|
||||||
pub taskbar_icon: Option<WinIcon>,
|
pub taskbar_icon: Option<Icon>,
|
||||||
|
|
||||||
pub saved_window: Option<SavedWindow>,
|
pub saved_window: Option<SavedWindow>,
|
||||||
pub scale_factor: f64,
|
pub scale_factor: f64,
|
||||||
|
@ -96,8 +96,7 @@ bitflags! {
|
||||||
impl WindowState {
|
impl WindowState {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
attributes: &WindowAttributes,
|
attributes: &WindowAttributes,
|
||||||
window_icon: Option<WinIcon>,
|
taskbar_icon: Option<Icon>,
|
||||||
taskbar_icon: Option<WinIcon>,
|
|
||||||
scale_factor: f64,
|
scale_factor: f64,
|
||||||
is_dark_mode: bool,
|
is_dark_mode: bool,
|
||||||
) -> WindowState {
|
) -> WindowState {
|
||||||
|
@ -112,7 +111,7 @@ impl WindowState {
|
||||||
min_size: attributes.min_inner_size,
|
min_size: attributes.min_inner_size,
|
||||||
max_size: attributes.max_inner_size,
|
max_size: attributes.max_inner_size,
|
||||||
|
|
||||||
window_icon,
|
window_icon: attributes.window_icon.clone(),
|
||||||
taskbar_icon,
|
taskbar_icon,
|
||||||
|
|
||||||
saved_window: None,
|
saved_window: None,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
||||||
platform_impl,
|
platform_impl,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::icon::*;
|
pub use crate::icon::{BadIcon, Icon};
|
||||||
|
|
||||||
/// Represents a window.
|
/// Represents a window.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Add table
Reference in a new issue