diff --git a/Cargo.toml b/Cargo.toml index b543890e..2551701a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ android-native-activity = ["android-activity/native-activity"] default = ["rwh_06", "x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"] mint = ["dpi/mint"] rwh_06 = ["dep:rwh_06", "ndk/rwh_06"] -serde = ["dep:serde", "cursor-icon/serde", "smol_str/serde", "dpi/serde"] +serde = ["dep:serde", "cursor-icon/serde", "smol_str/serde", "dpi/serde", "bitflags/serde"] wayland = [ "wayland-client", "wayland-backend", diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 5f3e0da2..0ffccfb9 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -59,6 +59,8 @@ changelog entry. - Add `Touch::finger_id` with a new type `FingerId`. - On Web and Windows, add `FingerIdExt*::is_primary()`, exposing a way to determine the primary finger in a multi-touch interaction. +- Implement `Clone`, `Copy`, `Debug`, `Deserialize`, `Eq`, `Hash`, `Ord`, `PartialEq`, `PartialOrd` + and `Serialize` on many types. ### Changed @@ -91,6 +93,7 @@ changelog entry. - On Web, `CursorGrabMode::Locked` now lets `DeviceEvent::MouseMotion` return raw data, not OS accelerated, if the browser supports it. - `(Active)EventLoop::create_custom_cursor()` now returns a `Result`. +- Changed how `ModifiersState` is serialized by Serde. ### Removed diff --git a/src/cursor.rs b/src/cursor.rs index b54e082d..0a980162 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -107,7 +107,7 @@ impl CustomCursor { /// Source for [`CustomCursor`]. /// /// See [`CustomCursor`] for more details. -#[derive(Debug)] +#[derive(Debug, Clone, Eq, Hash, PartialEq)] pub struct CustomCursorSource { // Some platforms don't support custom cursors. #[allow(dead_code)] @@ -115,7 +115,8 @@ pub struct CustomCursorSource { } /// An error produced when using [`CustomCursor::from_rgba`] with invalid arguments. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum BadImage { /// Produced when the image dimensions are larger than [`MAX_CURSOR_SIZE`]. This doesn't /// guarantee that the cursor will work, but should avoid many platform and device specific @@ -166,7 +167,7 @@ impl Error for BadImage {} /// Platforms export this directly as `PlatformCustomCursorSource` if they need to only work with /// images. #[allow(dead_code)] -#[derive(Debug)] +#[derive(Debug, Clone, Eq, Hash, PartialEq)] pub(crate) struct OnlyCursorImageSource(pub(crate) CursorImage); #[allow(dead_code)] @@ -201,7 +202,7 @@ impl PartialEq for OnlyCursorImage { impl Eq for OnlyCursorImage {} -#[derive(Debug)] +#[derive(Debug, Clone, Eq, Hash, PartialEq)] #[allow(dead_code)] pub(crate) struct CursorImage { pub(crate) rgba: Vec, diff --git a/src/error.rs b/src/error.rs index d15bb9e7..3e9ec852 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,7 +15,8 @@ pub enum ExternalError { } /// The error type for when the requested operation is not supported by the backend. -#[derive(Clone)] +#[derive(Clone, Copy, Default, Eq, Hash, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct NotSupportedError { _marker: (), } diff --git a/src/event.rs b/src/event.rs index eb231175..ec7fd975 100644 --- a/src/event.rs +++ b/src/event.rs @@ -115,7 +115,7 @@ pub(crate) enum Event { } /// Describes the reason the event loop is resuming. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum StartCause { /// Sent if the time specified by [`ControlFlow::WaitUntil`] has been reached. Contains the /// moment the timeout was requested and the requested resume time. The actual resume time is @@ -434,6 +434,12 @@ pub enum WindowEvent { #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DeviceId(pub(crate) platform_impl::DeviceId); +impl Default for DeviceId { + fn default() -> Self { + Self::dummy() + } +} + impl DeviceId { /// Returns a dummy id, useful for unit testing. /// @@ -475,7 +481,7 @@ impl FingerId { /// (corresponding to GUI cursors and keyboard focus) the device IDs may not match. /// /// Note that these events are delivered regardless of input focus. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum DeviceEvent { /// Change in physical position of a pointing device. /// @@ -524,7 +530,7 @@ pub enum DeviceEvent { /// repeat or the initial keypress. An application may emulate this by, for /// example keeping a Map/Set of pressed keys and determining whether a keypress /// corresponds to an already pressed key. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct RawKeyEvent { pub physical_key: keyboard::PhysicalKey, @@ -669,7 +675,8 @@ pub struct KeyEvent { } /// Describes keyboard modifiers event. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Modifiers { pub(crate) state: ModifiersState, @@ -871,6 +878,7 @@ pub struct Touch { /// Describes the force of a touch event #[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Force { /// On iOS, the force is calibrated so that the same number corresponds to /// roughly the same amount of pressure on the screen regardless of the @@ -1020,6 +1028,8 @@ impl PartialEq for InnerSizeWriter { } } +impl Eq for InnerSizeWriter {} + #[cfg(test)] mod tests { use std::collections::{BTreeSet, HashSet}; diff --git a/src/event_loop.rs b/src/event_loop.rs index d769d11e..4f1947c5 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -52,7 +52,7 @@ pub struct EventLoop { /// easier. But note that constructing multiple event loops is not supported. /// /// This can be created using [`EventLoop::builder`]. -#[derive(Default)] +#[derive(Default, PartialEq, Eq, Hash)] pub struct EventLoopBuilder { pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes, } @@ -115,9 +115,15 @@ impl EventLoopBuilder { } } +impl fmt::Debug for EventLoopBuilder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EventLoopBuilder").finish_non_exhaustive() + } +} + impl fmt::Debug for EventLoop { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("EventLoop { .. }") + f.debug_struct("EventLoop").finish_non_exhaustive() } } @@ -129,7 +135,7 @@ impl fmt::Debug for EventLoop { /// /// [`Wait`]: Self::Wait /// [`about_to_wait`]: crate::application::ApplicationHandler::about_to_wait -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)] pub enum ControlFlow { /// When the current loop iteration finishes, immediately begin a new iteration regardless of /// whether or not new events are available to process. @@ -419,7 +425,7 @@ pub trait ActiveEventLoop { /// /// - A zero-sized type that is likely optimized out. /// - A reference-counted pointer to the underlying type. -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct OwnedDisplayHandle { #[cfg_attr(not(feature = "rwh_06"), allow(dead_code))] pub(crate) platform: platform_impl::OwnedDisplayHandle, @@ -474,12 +480,13 @@ impl EventLoopProxy { impl fmt::Debug for EventLoopProxy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("EventLoopProxy { .. }") + f.debug_struct("ActiveEventLoop").finish_non_exhaustive() } } /// Control when device events are captured. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum DeviceEvents { /// Report device events regardless of window focus. Always, @@ -499,7 +506,7 @@ pub enum DeviceEvents { /// containing [`AsyncRequestSerial`] and some closure associated with it. /// Then once event is arriving the working list is being traversed and a job /// executed and removed from the list. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct AsyncRequestSerial { serial: usize, } diff --git a/src/icon.rs b/src/icon.rs index bb8f4fea..f0f611cd 100644 --- a/src/icon.rs +++ b/src/icon.rs @@ -50,7 +50,7 @@ impl fmt::Display for BadIcon { impl Error for BadIcon {} -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct RgbaIcon { pub(crate) rgba: Vec, pub(crate) width: u32, @@ -58,7 +58,7 @@ pub(crate) struct RgbaIcon { } /// For platforms which don't have window icons (e.g. Web) -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct NoIcon; #[allow(dead_code)] // These are not used on every platform @@ -94,7 +94,7 @@ mod constructors { } /// An icon used for the window titlebar, taskbar, etc. -#[derive(Clone)] +#[derive(Clone, Eq, Hash, PartialEq)] pub struct Icon { pub(crate) inner: PlatformIcon, } diff --git a/src/keyboard.rs b/src/keyboard.rs index f8171d20..da501b2d 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -1628,7 +1628,7 @@ impl Key { /// /// [`location`]: ../event/struct.KeyEvent.html#structfield.location /// [`KeyEvent`]: crate::event::KeyEvent -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum KeyLocation { /// The key is in its "normal" location on the keyboard. @@ -1700,6 +1700,7 @@ bitflags! { /// /// Each flag represents a modifier and is set if this modifier is active. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ModifiersState: u32 { /// The "shift" key. const SHIFT = 0b100; @@ -1735,7 +1736,8 @@ impl ModifiersState { } /// The state of the particular modifiers key. -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ModifiersKeyState { /// The particular key is pressed. Pressed, @@ -1754,6 +1756,7 @@ pub enum ModifiersKeyState { // on macOS due to their AltGr/Option situation. bitflags! { #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub(crate) struct ModifiersKeys: u8 { const LSHIFT = 0b0000_0001; const RSHIFT = 0b0000_0010; @@ -1765,51 +1768,3 @@ bitflags! { const RSUPER = 0b1000_0000; } } - -#[cfg(feature = "serde")] -mod modifiers_serde { - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - - use super::ModifiersState; - - #[derive(Default, Serialize, Deserialize)] - #[serde(default)] - #[serde(rename = "ModifiersState")] - pub struct ModifiersStateSerialize { - pub shift_key: bool, - pub control_key: bool, - pub alt_key: bool, - pub super_key: bool, - } - - impl Serialize for ModifiersState { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let s = ModifiersStateSerialize { - shift_key: self.shift_key(), - control_key: self.control_key(), - alt_key: self.alt_key(), - super_key: self.super_key(), - }; - s.serialize(serializer) - } - } - - impl<'de> Deserialize<'de> for ModifiersState { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let ModifiersStateSerialize { shift_key, control_key, alt_key, super_key } = - ModifiersStateSerialize::deserialize(deserializer)?; - let mut m = ModifiersState::empty(); - m.set(ModifiersState::SHIFT, shift_key); - m.set(ModifiersState::CONTROL, control_key); - m.set(ModifiersState::ALT, alt_key); - m.set(ModifiersState::SUPER, super_key); - Ok(m) - } - } -} diff --git a/src/monitor.rs b/src/monitor.rs index d66a54bc..f25eb79e 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -116,7 +116,7 @@ impl std::fmt::Display for VideoModeHandle { /// to check. /// /// [`Window`]: crate::window::Window -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct MonitorHandle { pub(crate) inner: platform_impl::MonitorHandle, } diff --git a/src/platform/ios.rs b/src/platform/ios.rs index 38243411..3b118308 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -66,6 +66,9 @@ use std::os::raw::c_void; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + use crate::monitor::{MonitorHandle, VideoModeHandle}; use crate::window::{Window, WindowAttributes}; @@ -355,6 +358,7 @@ impl MonitorHandleExtIOS for MonitorHandle { /// Valid orientations for a particular [`Window`]. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ValidOrientations { /// Excludes `PortraitUpsideDown` on iphone #[default] @@ -371,6 +375,7 @@ bitflags::bitflags! { /// /// [edges]: https://developer.apple.com/documentation/uikit/uirectedge?language=objc #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ScreenEdge: u8 { const NONE = 0; const TOP = 1 << 0; @@ -382,7 +387,8 @@ bitflags::bitflags! { } } -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum StatusBarStyle { #[default] Default, diff --git a/src/platform/macos.rs b/src/platform/macos.rs index af2d1846..cce9dedd 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -170,6 +170,7 @@ impl WindowExtMacOS for Window { /// Corresponds to `NSApplicationActivationPolicy`. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ActivationPolicy { /// Corresponds to `NSApplicationActivationPolicyRegular`. #[default] @@ -432,7 +433,7 @@ impl ActiveEventLoopExtMacOS for &dyn ActiveEventLoop { /// Option as alt behavior. /// /// The default is `None`. -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum OptionAsAlt { /// The left `Option` key is treated as `Alt`. diff --git a/src/platform/pump_events.rs b/src/platform/pump_events.rs index c44bc334..4d070fea 100644 --- a/src/platform/pump_events.rs +++ b/src/platform/pump_events.rs @@ -117,6 +117,7 @@ impl EventLoopExtPumpEvents for EventLoop { } /// The return status for `pump_events` +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum PumpStatus { /// Continue running external loop. Continue, diff --git a/src/platform/web.rs b/src/platform/web.rs index a3242b0b..bbcb75d1 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -50,6 +50,8 @@ use std::pin::Pin; use std::task::{Context, Poll}; use std::time::Duration; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; #[cfg(web_platform)] use web_sys::HtmlCanvasElement; @@ -429,7 +431,8 @@ impl ActiveEventLoopExtWeb for &dyn ActiveEventLoop { } /// Strategy used for [`ControlFlow::Poll`][crate::event_loop::ControlFlow::Poll]. -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum PollStrategy { /// Uses [`Window.requestIdleCallback()`] to queue the next event loop. If not available /// this will fallback to [`setTimeout()`]. @@ -455,7 +458,8 @@ pub enum PollStrategy { } /// Strategy used for [`ControlFlow::WaitUntil`][crate::event_loop::ControlFlow::WaitUntil]. -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum WaitUntilStrategy { /// Uses the [Prioritized Task Scheduling API] to queue the next event loop. If not available /// this will fallback to [`setTimeout()`]. @@ -524,7 +528,8 @@ impl CustomCursorExtWeb for CustomCursor { } /// An error produced when using [`CustomCursor::from_animation`] with invalid arguments. -#[derive(Debug, Clone)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum BadAnimation { /// Produced when no cursors were supplied. Empty, @@ -557,7 +562,8 @@ impl Future for CustomCursorFuture { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum CustomCursorError { Blob, Decode(String), diff --git a/src/platform/windows.rs b/src/platform/windows.rs index bf235d24..b6315b9b 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -6,6 +6,9 @@ use std::borrow::Borrow; use std::ffi::c_void; use std::path::Path; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + use crate::dpi::PhysicalSize; use crate::event::{DeviceId, FingerId}; use crate::event_loop::EventLoopBuilder; @@ -25,6 +28,7 @@ pub type HMONITOR = isize; /// /// [`DWM_SYSTEMBACKDROP_TYPE docs`]: https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum BackdropType { /// Corresponds to `DWMSBT_AUTO`. /// @@ -54,6 +58,7 @@ pub enum BackdropType { /// Describes a color used by Windows #[repr(transparent)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Color(u32); impl Color { @@ -82,6 +87,7 @@ impl Default for Color { /// [`DWM_WINDOW_CORNER_PREFERENCE docs`]: https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_window_corner_preference #[repr(i32)] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum CornerPreference { /// Corresponds to `DWMWCP_DEFAULT`. /// @@ -108,7 +114,7 @@ pub enum CornerPreference { /// A wrapper around a [`Window`] that ignores thread-specific window handle limitations. /// /// See [`WindowBorrowExtWindows::any_thread`] for more information. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct AnyThread(W); impl> AnyThread { diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index ecfccd6e..527f2f05 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -112,7 +112,7 @@ pub struct EventLoop { combining_accent: Option, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct PlatformSpecificEventLoopAttributes { pub(crate) android_app: Option, pub(crate) ignore_volume_keys: bool, @@ -662,7 +662,7 @@ impl rwh_06::HasDisplayHandle for ActiveEventLoop { } } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub(crate) struct OwnedDisplayHandle; impl OwnedDisplayHandle { diff --git a/src/platform_impl/apple/appkit/event_loop.rs b/src/platform_impl/apple/appkit/event_loop.rs index 5590b658..10215dc5 100644 --- a/src/platform_impl/apple/appkit/event_loop.rs +++ b/src/platform_impl/apple/appkit/event_loop.rs @@ -375,7 +375,7 @@ impl EventLoop { } } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub(crate) struct OwnedDisplayHandle; impl OwnedDisplayHandle { diff --git a/src/platform_impl/apple/appkit/window_delegate.rs b/src/platform_impl/apple/appkit/window_delegate.rs index af65f850..04504488 100644 --- a/src/platform_impl/apple/appkit/window_delegate.rs +++ b/src/platform_impl/apple/appkit/window_delegate.rs @@ -42,7 +42,7 @@ use crate::window::{ WindowAttributes, WindowButtons, WindowId as RootWindowId, WindowLevel, }; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct PlatformSpecificWindowAttributes { pub movable_by_window_background: bool, pub titlebar_transparent: bool, diff --git a/src/platform_impl/apple/uikit/event_loop.rs b/src/platform_impl/apple/uikit/event_loop.rs index eafae5dc..fd63fac7 100644 --- a/src/platform_impl/apple/uikit/event_loop.rs +++ b/src/platform_impl/apple/uikit/event_loop.rs @@ -112,7 +112,7 @@ impl rwh_06::HasDisplayHandle for ActiveEventLoop { } } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub(crate) struct OwnedDisplayHandle; impl OwnedDisplayHandle { diff --git a/src/platform_impl/apple/uikit/window.rs b/src/platform_impl/apple/uikit/window.rs index 9e2819be..d60e79af 100644 --- a/src/platform_impl/apple/uikit/window.rs +++ b/src/platform_impl/apple/uikit/window.rs @@ -702,7 +702,7 @@ impl From<&AnyObject> for WindowId { } } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, PartialEq)] pub struct PlatformSpecificWindowAttributes { pub scale_factor: Option, pub valid_orientations: ValidOrientations, diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index f3476335..734b3289 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -67,7 +67,7 @@ impl ApplicationName { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct PlatformSpecificWindowAttributes { pub name: Option, pub activation_token: Option, @@ -75,7 +75,7 @@ pub struct PlatformSpecificWindowAttributes { pub x11: X11WindowAttributes, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] #[cfg(x11_platform)] pub struct X11WindowAttributes { pub visual_id: Option, @@ -194,7 +194,7 @@ impl FingerId { } } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum MonitorHandle { #[cfg(x11_platform)] X(x11::MonitorHandle), @@ -850,6 +850,21 @@ impl OwnedDisplayHandle { } } +impl PartialEq for OwnedDisplayHandle { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + #[cfg(x11_platform)] + (Self::X(this), Self::X(other)) => Arc::as_ptr(this).eq(&Arc::as_ptr(other)), + #[cfg(wayland_platform)] + (Self::Wayland(this), Self::Wayland(other)) => this.eq(other), + #[cfg(all(x11_platform, wayland_platform))] + _ => false, + } + } +} + +impl Eq for OwnedDisplayHandle {} + /// Returns the minimum `Option`, taking into account that `None` /// equates to an infinite timeout, not a zero timeout (so can't just use /// `Option::min`) diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index f75f5687..71ee0917 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -796,7 +796,7 @@ impl rwh_06::HasDisplayHandle for ActiveEventLoop { } } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub(crate) struct OwnedDisplayHandle; impl OwnedDisplayHandle { diff --git a/src/platform_impl/web/cursor.rs b/src/platform_impl/web/cursor.rs index 7fcb8506..bdd0ad4b 100644 --- a/src/platform_impl/web/cursor.rs +++ b/src/platform_impl/web/cursor.rs @@ -27,7 +27,7 @@ use super::ActiveEventLoop; use crate::cursor::{BadImage, Cursor, CursorImage, CustomCursor as RootCustomCursor}; use crate::platform::web::CustomCursorError; -#[derive(Debug)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub(crate) enum CustomCursorSource { Image(CursorImage), Url { url: String, hotspot_x: u16, hotspot_y: u16 }, diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 8643c696..a2b9fc49 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -711,7 +711,7 @@ impl rwh_06::HasDisplayHandle for ActiveEventLoop { } } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub(crate) struct OwnedDisplayHandle; impl OwnedDisplayHandle { diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index bdead767..19992bb3 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -457,6 +457,18 @@ pub struct PlatformSpecificWindowAttributes { pub(crate) append: bool, } +impl PartialEq for PlatformSpecificWindowAttributes { + fn eq(&self, other: &Self) -> bool { + (match (&self.canvas, &other.canvas) { + (Some(this), Some(other)) => Arc::ptr_eq(this, other), + (None, None) => true, + _ => false, + }) && self.prevent_default.eq(&other.prevent_default) + && self.focusable.eq(&other.focusable) + && self.append.eq(&other.append) + } +} + impl PlatformSpecificWindowAttributes { pub(crate) fn set_canvas(&mut self, canvas: Option) { let Some(canvas) = canvas else { diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index eeb748ce..1a6107ef 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -143,6 +143,28 @@ impl Default for PlatformSpecificEventLoopAttributes { } } +impl PartialEq for PlatformSpecificEventLoopAttributes { + fn eq(&self, other: &Self) -> bool { + self.any_thread.eq(&other.any_thread) + && self.dpi_aware.eq(&other.dpi_aware) + && match (&self.msg_hook, &other.msg_hook) { + (Some(this), Some(other)) => std::ptr::eq(&this, &other), + (None, None) => true, + _ => false, + } + } +} + +impl Eq for PlatformSpecificEventLoopAttributes {} + +impl std::hash::Hash for PlatformSpecificEventLoopAttributes { + fn hash(&self, state: &mut H) { + self.any_thread.hash(state); + self.dpi_aware.hash(state); + std::ptr::hash(&self.msg_hook, state); + } +} + pub struct ActiveEventLoop { thread_id: u32, thread_msg_target: HWND, @@ -565,7 +587,7 @@ impl rwh_06::HasDisplayHandle for ActiveEventLoop { } } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub(crate) struct OwnedDisplayHandle; impl OwnedDisplayHandle { diff --git a/src/platform_impl/windows/icon.rs b/src/platform_impl/windows/icon.rs index a90d04d1..b3e814be 100644 --- a/src/platform_impl/windows/icon.rs +++ b/src/platform_impl/windows/icon.rs @@ -63,12 +63,12 @@ pub enum IconType { Big = ICON_BIG as isize, } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Hash)] struct RaiiIcon { handle: HICON, } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct WinIcon { inner: Arc, } diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 9c98c3a0..93349f7f 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -17,7 +17,7 @@ use crate::keyboard::Key; use crate::platform::windows::{BackdropType, Color, CornerPreference}; use crate::platform_impl::Fullscreen; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct PlatformSpecificWindowAttributes { pub owner: Option, pub menu: Option, diff --git a/src/window.rs b/src/window.rs index 99143124..7de8c43f 100644 --- a/src/window.rs +++ b/src/window.rs @@ -36,8 +36,8 @@ pub struct Window { } impl fmt::Debug for Window { - fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result { - fmtr.pad("Window { .. }") + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Window").finish_non_exhaustive() } } @@ -58,6 +58,20 @@ impl Drop for Window { } } +impl PartialEq for Window { + fn eq(&self, other: &Self) -> bool { + self.id().eq(&other.id()) + } +} + +impl Eq for Window {} + +impl std::hash::Hash for Window { + fn hash(&self, state: &mut H) { + self.id().hash(state); + } +} + /// Identifier of a window. Unique for each window. /// /// Can be obtained with [`window.id()`][`Window::id`]. @@ -99,7 +113,7 @@ impl From for WindowId { } /// Attributes used when creating a window. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct WindowAttributes { pub inner_size: Option, pub min_inner_size: Option, @@ -165,7 +179,7 @@ impl Default for WindowAttributes { /// /// The user has to account for that when using [`WindowAttributes::with_parent_window()`], /// which is `unsafe`. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] #[cfg(feature = "rwh_06")] pub(crate) struct SendSyncRawWindowHandle(pub(crate) rwh_06::RawWindowHandle); @@ -1685,6 +1699,7 @@ pub enum CursorGrabMode { /// Defines the orientation that a window resize will be performed. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ResizeDirection { East, North, @@ -1713,7 +1728,7 @@ impl From for CursorIcon { } /// Fullscreen modes. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Fullscreen { Exclusive(VideoModeHandle), @@ -1722,7 +1737,7 @@ pub enum Fullscreen { } /// The theme variant to use. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Theme { /// Use the light variant. @@ -1739,7 +1754,8 @@ pub enum Theme { /// /// [`Critical`]: Self::Critical /// [`Informational`]: Self::Informational -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum UserAttentionType { /// ## Platform-specific /// @@ -1773,7 +1789,8 @@ bitflags::bitflags! { /// ## Platform-specific /// /// - **iOS / Android / Web / Wayland:** Unsupported. -#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, Default, PartialEq, Eq, Clone, Copy, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum WindowLevel { /// The window will always be below normal windows. /// @@ -1796,8 +1813,9 @@ pub enum WindowLevel { /// ## Platform-specific /// /// - **iOS / Android / Web / Windows / X11 / macOS / Orbital:** Unsupported. -#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ImePurpose { /// No special hints for the IME (default). Normal, @@ -1818,7 +1836,7 @@ impl Default for ImePurpose { /// An opaque token used to activate the [`Window`]. /// /// [`Window`]: crate::window::Window -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Hash)] pub struct ActivationToken { pub(crate) _token: String, }