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:
David Hewitt 2020-03-07 19:42:21 +00:00 committed by GitHub
parent 2f27f64cdb
commit 098fd5d602
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 266 additions and 126 deletions

View file

@ -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)

View file

@ -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)?,
})
}
} }

View file

@ -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 })
}
}

View file

@ -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 {

View file

@ -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,

View file

@ -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;

View file

@ -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());

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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 {

View file

@ -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 {

View file

@ -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,

View file

@ -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.
/// ///