Skip to main content

azul_core/
window.rs

1#[cfg(not(feature = "std"))]
2use alloc::string::{String, ToString};
3use alloc::{
4    boxed::Box,
5    collections::{btree_map::BTreeMap, btree_set::BTreeSet},
6    vec::Vec,
7};
8use core::{
9    cmp::Ordering,
10    ffi::c_void,
11    hash::{Hash, Hasher},
12    ops,
13    sync::atomic::{AtomicI64, AtomicUsize, Ordering as AtomicOrdering},
14};
15
16use azul_css::{
17    css::CssPath,
18    props::{
19        basic::{ColorU, FloatValue, LayoutPoint, LayoutRect, LayoutSize},
20        property::CssProperty,
21        style::StyleCursor,
22    },
23    AzString, LayoutDebugMessage, OptionF32, OptionI32, OptionString, U8Vec,
24};
25use rust_fontconfig::FcFontCache;
26
27use crate::{
28    callbacks::{LayoutCallback, LayoutCallbackType, Update},
29    dom::{DomId, DomNodeId, NodeHierarchy},
30    geom::{
31        LogicalPosition, LogicalRect, LogicalSize, OptionLogicalSize, PhysicalPositionI32,
32        PhysicalSize,
33    },
34    gl::OptionGlContextPtr,
35    hit_test::{ExternalScrollId, OverflowingScrollNode},
36    id::{NodeDataContainer, NodeId},
37    refany::OptionRefAny,
38    resources::{
39        DpiScaleFactor, Epoch, GlTextureCache, IdNamespace, ImageCache, ImageMask, ImageRef,
40        RendererResources, ResourceUpdate,
41    },
42    selection::SelectionState,
43    styled_dom::NodeHierarchyItemId,
44    task::{Instant, ThreadId, TimerId},
45    FastBTreeSet, FastHashMap,
46};
47
48pub const DEFAULT_TITLE: &str = "Azul App";
49
50static LAST_WINDOW_ID: AtomicI64 = AtomicI64::new(0);
51
52/// Each default callback is identified by its ID (not by it's function pointer),
53/// since multiple IDs could point to the same function.
54#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
55#[repr(transparent)]
56pub struct WindowId {
57    pub id: i64,
58}
59
60impl WindowId {
61    pub fn new() -> Self {
62        WindowId {
63            id: LAST_WINDOW_ID.fetch_add(1, AtomicOrdering::SeqCst),
64        }
65    }
66}
67
68static LAST_ICON_KEY: AtomicUsize = AtomicUsize::new(0);
69
70/// Key that is used for checking whether a window icon has changed -
71/// this way azul doesn't need to diff the actual bytes, just the icon key.
72/// Use `IconKey::new()` to generate a new, unique key
73#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
74#[repr(C)]
75pub struct IconKey {
76    icon_id: usize,
77}
78
79impl IconKey {
80    pub fn new() -> Self {
81        Self {
82            icon_id: LAST_ICON_KEY.fetch_add(1, AtomicOrdering::SeqCst),
83        }
84    }
85}
86
87#[repr(C)]
88#[derive(PartialEq, Copy, Clone, Debug, PartialOrd, Ord, Eq, Hash)]
89pub struct RendererOptions {
90    pub vsync: Vsync,
91    pub srgb: Srgb,
92    pub hw_accel: HwAcceleration,
93}
94
95impl_option!(
96    RendererOptions,
97    OptionRendererOptions,
98    [PartialEq, Copy, Clone, Debug, PartialOrd, Ord, Eq, Hash]
99);
100
101impl Default for RendererOptions {
102    fn default() -> Self {
103        Self {
104            vsync: Vsync::Enabled,
105            srgb: Srgb::Disabled,
106            hw_accel: HwAcceleration::Enabled,
107        }
108    }
109}
110
111impl RendererOptions {
112    pub const fn new(vsync: Vsync, srgb: Srgb, hw_accel: HwAcceleration) -> Self {
113        Self {
114            vsync,
115            srgb,
116            hw_accel,
117        }
118    }
119}
120
121#[repr(C)]
122#[derive(PartialEq, Copy, Clone, Debug, PartialOrd, Ord, Eq, Hash)]
123pub enum Vsync {
124    Enabled,
125    Disabled,
126    DontCare,
127}
128
129impl Vsync {
130    pub const fn is_enabled(&self) -> bool {
131        match self {
132            Vsync::Enabled => true,
133            _ => false,
134        }
135    }
136}
137
138#[repr(C)]
139#[derive(PartialEq, Copy, Clone, Debug, PartialOrd, Ord, Eq, Hash)]
140pub enum Srgb {
141    Enabled,
142    Disabled,
143    DontCare,
144}
145impl Srgb {
146    pub const fn is_enabled(&self) -> bool {
147        match self {
148            Srgb::Enabled => true,
149            _ => false,
150        }
151    }
152}
153
154#[repr(C)]
155#[derive(PartialEq, Copy, Clone, Debug, PartialOrd, Ord, Eq, Hash)]
156pub enum HwAcceleration {
157    Enabled,
158    Disabled,
159    DontCare,
160}
161impl HwAcceleration {
162    pub const fn is_enabled(&self) -> bool {
163        match self {
164            HwAcceleration::Enabled => true,
165            _ => false,
166        }
167    }
168}
169
170#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
171#[repr(C, u8)]
172pub enum RawWindowHandle {
173    IOS(IOSHandle),
174    MacOS(MacOSHandle),
175    Xlib(XlibHandle),
176    Xcb(XcbHandle),
177    Wayland(WaylandHandle),
178    Windows(WindowsHandle),
179    Web(WebHandle),
180    Android(AndroidHandle),
181    Unsupported,
182}
183
184unsafe impl Send for RawWindowHandle {}
185
186#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
187#[repr(C)]
188pub struct IOSHandle {
189    pub ui_window: *mut c_void,
190    pub ui_view: *mut c_void,
191    pub ui_view_controller: *mut c_void,
192}
193
194#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
195#[repr(C)]
196pub struct MacOSHandle {
197    pub ns_window: *mut c_void,
198    pub ns_view: *mut c_void,
199}
200
201#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
202#[repr(C)]
203pub struct XlibHandle {
204    /// An Xlib Window
205    pub window: u64,
206    pub display: *mut c_void,
207}
208
209#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
210#[repr(C)]
211pub struct XcbHandle {
212    /// An X11 xcb_window_t.
213    pub window: u32,
214    /// A pointer to an X server xcb_connection_t.
215    pub connection: *mut c_void,
216}
217
218#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
219#[repr(C)]
220pub struct WaylandHandle {
221    /// A pointer to a wl_surface
222    pub surface: *mut c_void,
223    /// A pointer to a wl_display.
224    pub display: *mut c_void,
225}
226
227#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
228#[repr(C)]
229pub struct WindowsHandle {
230    /// A Win32 HWND handle.
231    pub hwnd: *mut c_void,
232    /// The HINSTANCE associated with this type's HWND.
233    pub hinstance: *mut c_void,
234}
235
236#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
237#[repr(C)]
238pub struct WebHandle {
239    /// An ID value inserted into the data attributes of the canvas element as 'raw-handle'
240    ///
241    /// When accessing from JS, the attribute will automatically be called rawHandle. Each canvas
242    /// created by the windowing system should be assigned their own unique ID.
243    /// 0 should be reserved for invalid / null IDs.
244    pub id: u32,
245}
246
247#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
248#[repr(C)]
249pub struct AndroidHandle {
250    /// A pointer to an ANativeWindow.
251    pub a_native_window: *mut c_void,
252}
253
254#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
255#[repr(C)]
256pub enum MouseCursorType {
257    Default,
258    Crosshair,
259    Hand,
260    Arrow,
261    Move,
262    Text,
263    Wait,
264    Help,
265    Progress,
266    NotAllowed,
267    ContextMenu,
268    Cell,
269    VerticalText,
270    Alias,
271    Copy,
272    NoDrop,
273    Grab,
274    Grabbing,
275    AllScroll,
276    ZoomIn,
277    ZoomOut,
278    EResize,
279    NResize,
280    NeResize,
281    NwResize,
282    SResize,
283    SeResize,
284    SwResize,
285    WResize,
286    EwResize,
287    NsResize,
288    NeswResize,
289    NwseResize,
290    ColResize,
291    RowResize,
292}
293
294impl Default for MouseCursorType {
295    fn default() -> Self {
296        MouseCursorType::Default
297    }
298}
299
300/// Hardware-dependent keyboard scan code.
301pub type ScanCode = u32;
302
303/// Determines which keys are pressed currently (modifiers, etc.)
304#[derive(Default, Debug, Clone, PartialEq)]
305#[repr(C)]
306pub struct KeyboardState {
307    /// Currently pressed virtual keycode - **DO NOT USE THIS FOR TEXT INPUT**.
308    ///
309    /// For text input, use the `text_input` parameter in callbacks.
310    /// For example entering `à` will fire a `VirtualKeyCode::Grave`, then `VirtualKeyCode::A`,
311    /// so to correctly combine characters, the framework handles text composition internally.
312    pub current_virtual_keycode: OptionVirtualKeyCode,
313    /// Currently pressed virtual keycodes (READONLY) - it can happen that more than one key is
314    /// pressed
315    ///
316    /// This is essentially an "extension" of `current_scancodes` - `current_keys` stores the
317    /// characters, but what if the pressed key is not a character (such as `ArrowRight` or
318    /// `PgUp`)?
319    ///
320    /// Note that this can have an overlap, so pressing "a" on the keyboard will insert
321    /// both a `VirtualKeyCode::A` into `current_virtual_keycodes` and text input will be handled
322    /// by the framework automatically for contenteditable nodes.
323    pub pressed_virtual_keycodes: VirtualKeyCodeVec,
324    /// Same as `current_virtual_keycodes`, but the scancode identifies the physical key pressed,
325    /// independent of the keyboard layout. The scancode does not change if the user adjusts the
326    /// host's keyboard map. Use when the physical location of the key is more important than
327    /// the key's host GUI semantics, such as for movement controls in a first-person game
328    /// (German keyboard: Z key, UK keyboard: Y key, etc.)
329    pub pressed_scancodes: ScanCodeVec,
330}
331
332impl KeyboardState {
333    pub fn shift_down(&self) -> bool {
334        self.is_key_down(VirtualKeyCode::LShift) || self.is_key_down(VirtualKeyCode::RShift)
335    }
336    pub fn ctrl_down(&self) -> bool {
337        self.is_key_down(VirtualKeyCode::LControl) || self.is_key_down(VirtualKeyCode::RControl)
338    }
339    pub fn alt_down(&self) -> bool {
340        self.is_key_down(VirtualKeyCode::LAlt) || self.is_key_down(VirtualKeyCode::RAlt)
341    }
342    pub fn super_down(&self) -> bool {
343        self.is_key_down(VirtualKeyCode::LWin) || self.is_key_down(VirtualKeyCode::RWin)
344    }
345    pub fn is_key_down(&self, key: VirtualKeyCode) -> bool {
346        self.pressed_virtual_keycodes.iter().any(|k| *k == key)
347    }
348}
349
350impl_option!(
351    KeyboardState,
352    OptionKeyboardState,
353    copy = false,
354    [Debug, Clone, PartialEq]
355);
356
357// char is not ABI-stable, use u32 instead
358impl_option!(
359    u32,
360    OptionChar,
361    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
362);
363impl_option!(
364    VirtualKeyCode,
365    OptionVirtualKeyCode,
366    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
367);
368
369impl_vec!(
370    VirtualKeyCode,
371    VirtualKeyCodeVec,
372    VirtualKeyCodeVecDestructor,
373    VirtualKeyCodeVecDestructorType
374);
375impl_vec_debug!(VirtualKeyCode, VirtualKeyCodeVec);
376impl_vec_partialord!(VirtualKeyCode, VirtualKeyCodeVec);
377impl_vec_ord!(VirtualKeyCode, VirtualKeyCodeVec);
378impl_vec_clone!(
379    VirtualKeyCode,
380    VirtualKeyCodeVec,
381    VirtualKeyCodeVecDestructor
382);
383impl_vec_partialeq!(VirtualKeyCode, VirtualKeyCodeVec);
384impl_vec_eq!(VirtualKeyCode, VirtualKeyCodeVec);
385impl_vec_hash!(VirtualKeyCode, VirtualKeyCodeVec);
386
387impl_vec_as_hashmap!(VirtualKeyCode, VirtualKeyCodeVec);
388
389impl_vec!(
390    ScanCode,
391    ScanCodeVec,
392    ScanCodeVecDestructor,
393    ScanCodeVecDestructorType
394);
395impl_vec_debug!(ScanCode, ScanCodeVec);
396impl_vec_partialord!(ScanCode, ScanCodeVec);
397impl_vec_ord!(ScanCode, ScanCodeVec);
398impl_vec_clone!(ScanCode, ScanCodeVec, ScanCodeVecDestructor);
399impl_vec_partialeq!(ScanCode, ScanCodeVec);
400impl_vec_eq!(ScanCode, ScanCodeVec);
401impl_vec_hash!(ScanCode, ScanCodeVec);
402
403impl_vec_as_hashmap!(ScanCode, ScanCodeVec);
404
405/// Mouse position, cursor type, user scroll input, etc.
406#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
407#[repr(C)]
408pub struct MouseState {
409    /// Current mouse cursor type, set to `None` if the cursor is hidden. (READWRITE)
410    pub mouse_cursor_type: OptionMouseCursorType,
411    /// Where is the mouse cursor currently? Set to `None` if the window is not focused.
412    /// (READWRITE)
413    pub cursor_position: CursorPosition,
414    /// Is the mouse cursor locked to the current window (important for applications like games)?
415    /// (READWRITE)
416    pub is_cursor_locked: bool,
417    /// Is the left mouse button down? (READONLY)
418    pub left_down: bool,
419    /// Is the right mouse button down? (READONLY)
420    pub right_down: bool,
421    /// Is the middle mouse button down? (READONLY)
422    pub middle_down: bool,
423}
424
425impl MouseState {
426    pub fn matches(&self, context: &ContextMenuMouseButton) -> bool {
427        use self::ContextMenuMouseButton::*;
428        match context {
429            Left => self.left_down,
430            Right => self.right_down,
431            Middle => self.middle_down,
432        }
433    }
434}
435
436impl_option!(
437    MouseState,
438    OptionMouseState,
439    [Debug, Copy, Clone, PartialEq, PartialOrd]
440);
441
442impl_option!(
443    MouseCursorType,
444    OptionMouseCursorType,
445    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
446);
447
448impl Default for MouseState {
449    fn default() -> Self {
450        Self {
451            mouse_cursor_type: Some(MouseCursorType::Default).into(),
452            cursor_position: CursorPosition::default(),
453            is_cursor_locked: false,
454            left_down: false,
455            right_down: false,
456            middle_down: false,
457        }
458    }
459}
460
461#[derive(Debug, Clone, PartialEq, PartialOrd, Hash, Eq, Ord)]
462#[repr(C)]
463pub struct VirtualKeyCodeCombo {
464    pub keys: VirtualKeyCodeVec,
465}
466
467impl_option!(
468    VirtualKeyCodeCombo,
469    OptionVirtualKeyCodeCombo,
470    copy = false,
471    [Debug, Clone, PartialEq, PartialOrd, Hash, Eq, Ord]
472);
473
474#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Hash, Eq, Ord)]
475#[repr(C)]
476pub enum ContextMenuMouseButton {
477    Right,
478    Middle,
479    Left,
480}
481
482impl Default for ContextMenuMouseButton {
483    fn default() -> Self {
484        ContextMenuMouseButton::Right
485    }
486}
487
488impl MouseState {
489    /// Returns whether any mouse button (left, right or center) is currently held down
490    pub fn mouse_down(&self) -> bool {
491        self.right_down || self.left_down || self.middle_down
492    }
493}
494
495// TODO: returned by process_system_scroll
496#[derive(Debug)]
497pub struct ScrollResult {}
498
499#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
500#[repr(C, u8)]
501pub enum CursorPosition {
502    OutOfWindow(LogicalPosition),
503    Uninitialized,
504    InWindow(LogicalPosition),
505}
506
507impl Default for CursorPosition {
508    fn default() -> CursorPosition {
509        CursorPosition::Uninitialized
510    }
511}
512
513impl CursorPosition {
514    pub fn get_position(&self) -> Option<LogicalPosition> {
515        match self {
516            CursorPosition::InWindow(logical_pos) => Some(*logical_pos),
517            CursorPosition::OutOfWindow(_) | CursorPosition::Uninitialized => None,
518        }
519    }
520
521    pub fn is_inside_window(&self) -> bool {
522        self.get_position().is_some()
523    }
524}
525
526/// Toggles webrender debug flags (will make stuff appear on
527/// the screen that you might not want to - used for debugging purposes)
528#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
529#[repr(C)]
530pub struct DebugState {
531    pub profiler_dbg: bool,
532    pub render_target_dbg: bool,
533    pub texture_cache_dbg: bool,
534    pub gpu_time_queries: bool,
535    pub gpu_sample_queries: bool,
536    pub disable_batching: bool,
537    pub epochs: bool,
538    pub echo_driver_messages: bool,
539    pub show_overdraw: bool,
540    pub gpu_cache_dbg: bool,
541    pub texture_cache_dbg_clear_evicted: bool,
542    pub picture_caching_dbg: bool,
543    pub primitive_dbg: bool,
544    pub zoom_dbg: bool,
545    pub small_screen: bool,
546    pub disable_opaque_pass: bool,
547    pub disable_alpha_pass: bool,
548    pub disable_clip_masks: bool,
549    pub disable_text_prims: bool,
550    pub disable_gradient_prims: bool,
551    pub obscure_images: bool,
552    pub glyph_flashing: bool,
553    pub smart_profiler: bool,
554    pub invalidation_dbg: bool,
555    pub tile_cache_logging_dbg: bool,
556    pub profiler_capture: bool,
557    pub force_picture_invalidation: bool,
558}
559
560fn translate_cursor(cursor: StyleCursor) -> MouseCursorType {
561    use azul_css::props::style::effects::StyleCursor;
562    match cursor {
563        StyleCursor::Default => MouseCursorType::Default,
564        StyleCursor::Crosshair => MouseCursorType::Crosshair,
565        StyleCursor::Pointer => MouseCursorType::Hand,
566        StyleCursor::Move => MouseCursorType::Move,
567        StyleCursor::Text => MouseCursorType::Text,
568        StyleCursor::Wait => MouseCursorType::Wait,
569        StyleCursor::Help => MouseCursorType::Help,
570        StyleCursor::Progress => MouseCursorType::Progress,
571        StyleCursor::ContextMenu => MouseCursorType::ContextMenu,
572        StyleCursor::Cell => MouseCursorType::Cell,
573        StyleCursor::VerticalText => MouseCursorType::VerticalText,
574        StyleCursor::Alias => MouseCursorType::Alias,
575        StyleCursor::Copy => MouseCursorType::Copy,
576        StyleCursor::Grab => MouseCursorType::Grab,
577        StyleCursor::Grabbing => MouseCursorType::Grabbing,
578        StyleCursor::AllScroll => MouseCursorType::AllScroll,
579        StyleCursor::ZoomIn => MouseCursorType::ZoomIn,
580        StyleCursor::ZoomOut => MouseCursorType::ZoomOut,
581        StyleCursor::EResize => MouseCursorType::EResize,
582        StyleCursor::NResize => MouseCursorType::NResize,
583        StyleCursor::SResize => MouseCursorType::SResize,
584        StyleCursor::SeResize => MouseCursorType::SeResize,
585        StyleCursor::WResize => MouseCursorType::WResize,
586        StyleCursor::EwResize => MouseCursorType::EwResize,
587        StyleCursor::NsResize => MouseCursorType::NsResize,
588        StyleCursor::NeswResize => MouseCursorType::NeswResize,
589        StyleCursor::NwseResize => MouseCursorType::NwseResize,
590        StyleCursor::ColResize => MouseCursorType::ColResize,
591        StyleCursor::RowResize => MouseCursorType::RowResize,
592        StyleCursor::Unset => MouseCursorType::Default,
593    }
594}
595
596#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd, Hash, Ord, Eq)]
597#[repr(C)]
598pub struct TouchState {
599    /// Number of active touch points
600    pub num_touches: usize,
601}
602
603/// Single touch point (finger, stylus, etc.)
604#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
605#[repr(C)]
606pub struct TouchPoint {
607    /// Unique identifier for this touch point (persists across move events)
608    pub id: u64,
609    /// Current position of the touch point in logical coordinates
610    pub position: LogicalPosition,
611    /// Force/pressure of the touch (0.0 = no pressure, 1.0 = maximum pressure)
612    /// Set to 0.5 if pressure is not available
613    pub force: f32,
614}
615
616impl_vec!(
617    TouchPoint,
618    TouchPointVec,
619    TouchPointVecDestructor,
620    TouchPointVecDestructorType
621);
622impl_vec_debug!(TouchPoint, TouchPointVec);
623impl_vec_clone!(TouchPoint, TouchPointVec, TouchPointVecDestructor);
624impl_vec_partialeq!(TouchPoint, TouchPointVec);
625
626/// State, size, etc of the window, for comparing to the last frame
627#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Hash, Ord, Eq)]
628#[repr(C)]
629pub enum WindowTheme {
630    DarkMode,
631    LightMode,
632}
633
634impl Default for WindowTheme {
635    fn default() -> WindowTheme {
636        WindowTheme::LightMode // sorry!
637    }
638}
639
640impl_option!(
641    WindowTheme,
642    OptionWindowTheme,
643    [Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash]
644);
645
646/// Identifies a specific monitor/display
647///
648/// Contains both an index (for fast current-session lookup) and a stable hash
649/// (for persistence across app restarts and monitor reconfigurations).
650///
651/// - `index`: Runtime index (0-based), may change if monitors are added/removed
652/// - `hash`: Stable identifier based on monitor properties (name, size, position)
653///
654/// Applications can serialize `hash` to remember which monitor a window was on,
655/// then search for matching hash on next launch, falling back to index or PRIMARY.
656#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
657#[repr(C)]
658pub struct MonitorId {
659    /// Runtime index of the monitor (may change between sessions)
660    pub index: usize,
661    /// Stable hash of monitor properties (for persistence)
662    pub hash: u64,
663}
664
665impl MonitorId {
666    /// Primary/default monitor (index 0, hash 0)
667    pub const PRIMARY: MonitorId = MonitorId { index: 0, hash: 0 };
668
669    /// Create a MonitorId from index only (hash will be 0)
670    pub const fn new(index: usize) -> Self {
671        Self { index, hash: 0 }
672    }
673
674    /// Create a MonitorId from index and hash
675    pub const fn from_index_and_hash(index: usize, hash: u64) -> Self {
676        Self { index, hash }
677    }
678
679    /// Create a stable monitor ID from monitor properties
680    ///
681    /// Uses FNV-1a hash of: name + position + size
682    /// This ensures the hash is stable across app restarts as long as
683    /// the monitor configuration doesn't change significantly
684    pub fn from_properties(
685        index: usize,
686        name: &str,
687        position: LayoutPoint,
688        size: LayoutSize,
689    ) -> Self {
690        use core::hash::{Hash, Hasher};
691
692        // FNV-1a hash (simple, fast, good distribution)
693        struct FnvHasher(u64);
694
695        impl Hasher for FnvHasher {
696            fn write(&mut self, bytes: &[u8]) {
697                const FNV_PRIME: u64 = 0x100000001b3;
698                for &byte in bytes {
699                    self.0 ^= byte as u64;
700                    self.0 = self.0.wrapping_mul(FNV_PRIME);
701                }
702            }
703
704            fn finish(&self) -> u64 {
705                self.0
706            }
707        }
708
709        const FNV_OFFSET_BASIS: u64 = 0xcbf29ce484222325;
710        let mut hasher = FnvHasher(FNV_OFFSET_BASIS);
711
712        // Hash the monitor properties
713        name.hash(&mut hasher);
714        (position.x as i64).hash(&mut hasher);
715        (position.y as i64).hash(&mut hasher);
716        (size.width as i64).hash(&mut hasher);
717        (size.height as i64).hash(&mut hasher);
718
719        Self {
720            index,
721            hash: hasher.finish(),
722        }
723    }
724}
725
726impl_option!(
727    MonitorId,
728    OptionMonitorId,
729    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
730);
731
732/// Complete information about a monitor/display
733#[derive(Debug, PartialEq, PartialOrd, Clone)]
734#[repr(C)]
735pub struct Monitor {
736    /// Unique identifier for this monitor (stable across frames)
737    pub monitor_id: MonitorId,
738    /// Human-readable name (e.g., "\\.\DISPLAY1", "HDMI-1", "Built-in Retina Display")
739    pub monitor_name: OptionString,
740    /// Physical size of the monitor in logical pixels
741    pub size: LayoutSize,
742    /// Position of the monitor in the virtual screen coordinate system
743    pub position: LayoutPoint,
744    /// DPI scale factor (1.0 = 96 DPI, 2.0 = 192 DPI for Retina)
745    pub scale_factor: f64,
746    /// Work area (monitor bounds minus taskbars/panels) in logical pixels
747    pub work_area: LayoutRect,
748    /// Available video modes for this monitor
749    pub video_modes: VideoModeVec,
750    /// Whether this is the primary/main monitor
751    pub is_primary_monitor: bool,
752}
753
754impl_vec!(
755    Monitor,
756    MonitorVec,
757    MonitorVecDestructor,
758    MonitorVecDestructorType
759);
760impl_vec_debug!(Monitor, MonitorVec);
761impl_vec_clone!(Monitor, MonitorVec, MonitorVecDestructor);
762impl_vec_partialeq!(Monitor, MonitorVec);
763impl_vec_partialord!(Monitor, MonitorVec);
764
765impl core::hash::Hash for Monitor {
766    fn hash<H>(&self, state: &mut H)
767    where
768        H: core::hash::Hasher,
769    {
770        self.monitor_id.hash(state)
771    }
772}
773
774impl Default for Monitor {
775    fn default() -> Self {
776        Monitor {
777            monitor_id: MonitorId::PRIMARY,
778            monitor_name: OptionString::None,
779            size: LayoutSize::zero(),
780            position: LayoutPoint::zero(),
781            scale_factor: 1.0,
782            work_area: LayoutRect::zero(),
783            video_modes: Vec::new().into(),
784            is_primary_monitor: false,
785        }
786    }
787}
788#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
789#[repr(C)]
790pub struct VideoMode {
791    pub size: LayoutSize,
792    pub bit_depth: u16,
793    pub refresh_rate: u16,
794}
795
796impl_vec!(
797    VideoMode,
798    VideoModeVec,
799    VideoModeVecDestructor,
800    VideoModeVecDestructorType
801);
802impl_vec_clone!(VideoMode, VideoModeVec, VideoModeVecDestructor);
803impl_vec_debug!(VideoMode, VideoModeVec);
804impl_vec_partialeq!(VideoMode, VideoModeVec);
805impl_vec_partialord!(VideoMode, VideoModeVec);
806
807#[derive(Debug, Copy, Clone, PartialEq)]
808#[repr(C, u8)]
809pub enum WindowPosition {
810    Uninitialized,
811    Initialized(PhysicalPositionI32),
812}
813
814impl Default for WindowPosition {
815    fn default() -> WindowPosition {
816        WindowPosition::Uninitialized
817    }
818}
819
820#[derive(Debug, Copy, Clone, PartialEq)]
821#[repr(C, u8)]
822/// IME composition window rectangle (cursor position + height)
823pub enum ImePosition {
824    Uninitialized,
825    Initialized(LogicalRect),
826}
827
828impl Default for ImePosition {
829    fn default() -> ImePosition {
830        ImePosition::Uninitialized
831    }
832}
833
834#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
835#[repr(C)]
836pub struct WindowFlags {
837    /// Is the window currently maximized, minimized or fullscreen
838    pub frame: WindowFrame,
839    /// User clicked the close button (set by WindowDelegate, checked by event loop)
840    /// The close_callback can set this to false to prevent closing
841    pub close_requested: bool,
842    /// Window decoration style (title bar, native controls)
843    pub decorations: WindowDecorations,
844    /// Is the window currently visible?
845    pub is_visible: bool,
846    /// Is the window always on top?
847    pub is_always_on_top: bool,
848    /// Whether the window is resizable
849    pub is_resizable: bool,
850    /// Whether the window has focus or not (mutating this will request user attention)
851    pub has_focus: bool,
852    /// Compositor blur/transparency effect material
853    pub background_material: WindowBackgroundMaterial,
854    /// Is smooth scrolling enabled for this window?
855    pub smooth_scroll_enabled: bool,
856    /// Is automatic TAB switching supported?
857    pub autotab_enabled: bool,
858    /// Window type classification (Normal, Menu, Tooltip, Dialog)
859    pub window_type: WindowType,
860    /// Enable client-side decorations (custom titlebar with CSD)
861    /// Only effective when decorations == WindowDecorations::None
862    pub has_decorations: bool,
863    /// Use native menus (Win32 HMENU, macOS NSMenu) instead of Azul window-based menus
864    /// Default: true on Windows/macOS, false on Linux
865    pub use_native_menus: bool,
866    /// Use native context menus instead of Azul window-based context menus
867    /// Default: true on Windows/macOS, false on Linux
868    pub use_native_context_menus: bool,
869    /// Keep window above all others (even from other applications)
870    /// Platform-specific: Uses SetWindowPos(HWND_TOPMOST) on Windows, [NSWindow setLevel:] on
871    /// macOS, _NET_WM_STATE_ABOVE on X11, zwlr_layer_shell on Wayland
872    pub is_top_level: bool,
873    /// Prevent system from sleeping while window is open
874    /// Platform-specific: Uses SetThreadExecutionState on Windows, IOPMAssertionCreateWithName on
875    /// macOS, org.freedesktop.ScreenSaver.Inhibit on Linux
876    pub prevent_system_sleep: bool,
877}
878
879impl_option!(
880    WindowFlags,
881    OptionWindowFlags,
882    copy = false,
883    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
884);
885
886/// Window type classification for behavior control
887#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
888#[repr(C)]
889pub enum WindowType {
890    /// Normal application window
891    Normal,
892    /// Menu popup window (always-on-top, frameless, auto-closes on focus loss)
893    Menu,
894    /// Tooltip window (always-on-top, no interaction)
895    Tooltip,
896    /// Dialog window (blocks parent window)
897    Dialog,
898}
899
900impl Default for WindowType {
901    fn default() -> Self {
902        Self::Normal
903    }
904}
905
906#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
907#[repr(C)]
908pub enum WindowFrame {
909    Normal,
910    Minimized,
911    Maximized,
912    Fullscreen,
913}
914
915/// Window decoration style
916#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
917#[repr(C)]
918pub enum WindowDecorations {
919    /// Full decorations: title bar with controls
920    Normal,
921    /// No title text but controls visible (extended frame)
922    NoTitle,
923    /// No controls visible but title bar area present
924    NoControls,
925    /// No decorations at all (borderless)
926    None,
927}
928
929impl Default for WindowDecorations {
930    fn default() -> Self {
931        Self::Normal
932    }
933}
934
935/// Compositor blur/transparency effects for window background
936#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
937#[repr(C)]
938pub enum WindowBackgroundMaterial {
939    /// No transparency or blur
940    Opaque,
941    /// Transparent without blur
942    Transparent,
943    /// macOS: Sidebar material, Windows: Acrylic light
944    Sidebar,
945    /// macOS: Menu material, Windows: Acrylic
946    Menu,
947    /// macOS: HUD material, Windows: Acrylic dark
948    HUD,
949    /// macOS: Titlebar material, Windows: Mica
950    Titlebar,
951    /// Windows: Mica Alt material
952    MicaAlt,
953}
954
955impl Default for WindowBackgroundMaterial {
956    fn default() -> Self {
957        Self::Opaque
958    }
959}
960
961impl Default for WindowFlags {
962    fn default() -> Self {
963        Self {
964            frame: WindowFrame::Normal,
965            close_requested: false,
966            decorations: WindowDecorations::Normal,
967            is_visible: true,
968            is_always_on_top: false,
969            is_resizable: true,
970            has_focus: true,
971            background_material: WindowBackgroundMaterial::Opaque,
972            smooth_scroll_enabled: true,
973            autotab_enabled: true,
974            window_type: WindowType::Normal,
975            has_decorations: false,
976            // Native menus are the default on platforms that support them (Windows/macOS)
977            // The platform layer will override this appropriately
978            use_native_menus: cfg!(any(target_os = "windows", target_os = "macos")),
979            use_native_context_menus: cfg!(any(target_os = "windows", target_os = "macos")),
980            is_top_level: false,
981            prevent_system_sleep: false,
982        }
983    }
984}
985
986impl WindowFlags {
987    /// Check if window is a menu popup
988    #[inline]
989    pub fn is_menu_window(&self) -> bool {
990        self.window_type == WindowType::Menu
991    }
992
993    /// Check if window is a tooltip
994    #[inline]
995    pub fn is_tooltip_window(&self) -> bool {
996        self.window_type == WindowType::Tooltip
997    }
998
999    /// Check if window is a dialog
1000    #[inline]
1001    pub fn is_dialog_window(&self) -> bool {
1002        self.window_type == WindowType::Dialog
1003    }
1004
1005    /// Check if window currently has focus
1006    #[inline]
1007    pub fn window_has_focus(&self) -> bool {
1008        self.has_focus
1009    }
1010
1011    /// Check if close was requested via callback
1012    #[inline]
1013    pub fn is_close_requested(&self) -> bool {
1014        self.close_requested
1015    }
1016
1017    /// Check if window has client-side decorations enabled
1018    #[inline]
1019    pub fn has_csd(&self) -> bool {
1020        self.has_decorations
1021    }
1022
1023    /// Check if native menus should be used
1024    #[inline]
1025    pub fn use_native_menus(&self) -> bool {
1026        self.use_native_menus
1027    }
1028
1029    /// Check if native context menus should be used
1030    #[inline]
1031    pub fn use_native_context_menus(&self) -> bool {
1032        self.use_native_context_menus
1033    }
1034}
1035
1036#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
1037#[repr(C)]
1038pub struct PlatformSpecificOptions {
1039    pub windows_options: WindowsWindowOptions,
1040    pub linux_options: LinuxWindowOptions,
1041    pub mac_options: MacWindowOptions,
1042    pub wasm_options: WasmWindowOptions,
1043}
1044
1045unsafe impl Sync for PlatformSpecificOptions {}
1046unsafe impl Send for PlatformSpecificOptions {}
1047
1048#[derive(Debug, Clone, PartialEq, PartialOrd)]
1049#[repr(C)]
1050pub struct WindowsWindowOptions {
1051    /// STARTUP ONLY: Whether the window should allow drag + drop operations (default: true)
1052    pub allow_drag_and_drop: bool,
1053    /// STARTUP ONLY: Sets `WS_EX_NOREDIRECTIONBITMAP`
1054    pub no_redirection_bitmap: bool,
1055    /// STARTUP ONLY: Window icon (decoded bytes), appears at the top right corner of the window
1056    pub window_icon: OptionWindowIcon,
1057    /// READWRITE: Taskbar icon (decoded bytes), usually 256x256x4 bytes large (`ICON_BIG`).
1058    ///
1059    /// Can be changed in callbacks / at runtime.
1060    pub taskbar_icon: OptionTaskBarIcon,
1061    /// STARTUP ONLY: Pointer (casted to void pointer) to a HWND handle
1062    pub parent_window: OptionHwndHandle,
1063}
1064
1065impl Default for WindowsWindowOptions {
1066    fn default() -> WindowsWindowOptions {
1067        WindowsWindowOptions {
1068            allow_drag_and_drop: true,
1069            no_redirection_bitmap: false,
1070            window_icon: OptionWindowIcon::None,
1071            taskbar_icon: OptionTaskBarIcon::None,
1072            parent_window: OptionHwndHandle::None,
1073        }
1074    }
1075}
1076
1077/// Note: this should be a *mut HWND
1078pub type HwndHandle = *mut c_void;
1079
1080impl_option!(
1081    HwndHandle,
1082    OptionHwndHandle,
1083    copy = false,
1084    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
1085);
1086
1087/// X window type. Maps directly to
1088/// [`_NET_WM_WINDOW_TYPE`](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html).
1089#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1090#[repr(C)]
1091pub enum XWindowType {
1092    /// A desktop feature. This can include a single window containing desktop icons with the same
1093    /// dimensions as the screen, allowing the desktop environment to have full control of the
1094    /// desktop, without the need for proxying root window clicks.
1095    Desktop,
1096    /// A dock or panel feature. Typically a Window Manager would keep such windows on top of all
1097    /// other windows.
1098    Dock,
1099    /// Toolbar windows. "Torn off" from the main application.
1100    Toolbar,
1101    /// Pinnable menu windows. "Torn off" from the main application.
1102    Menu,
1103    /// A small persistent utility window, such as a palette or toolbox.
1104    Utility,
1105    /// The window is a splash screen displayed as an application is starting up.
1106    Splash,
1107    /// This is a dialog window.
1108    Dialog,
1109    /// A dropdown menu that usually appears when the user clicks on an item in a menu bar.
1110    /// This property is typically used on override-redirect windows.
1111    DropdownMenu,
1112    /// A popup menu that usually appears when the user right clicks on an object.
1113    /// This property is typically used on override-redirect windows.
1114    PopupMenu,
1115    /// A tooltip window. Usually used to show additional information when hovering over an object
1116    /// with the cursor. This property is typically used on override-redirect windows.
1117    Tooltip,
1118    /// The window is a notification.
1119    /// This property is typically used on override-redirect windows.
1120    Notification,
1121    /// This should be used on the windows that are popped up by combo boxes.
1122    /// This property is typically used on override-redirect windows.
1123    Combo,
1124    /// This indicates the the window is being dragged.
1125    /// This property is typically used on override-redirect windows.
1126    Dnd,
1127    /// This is a normal, top-level window.
1128    Normal,
1129}
1130
1131impl Default for XWindowType {
1132    fn default() -> Self {
1133        XWindowType::Normal
1134    }
1135}
1136
1137#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
1138#[repr(C)]
1139pub enum UserAttentionType {
1140    None,
1141    Critical,
1142    Informational,
1143}
1144
1145impl Default for UserAttentionType {
1146    fn default() -> UserAttentionType {
1147        UserAttentionType::None
1148    }
1149}
1150
1151/// State for tracking hover and interaction with Linux window decoration elements (CSD).
1152#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
1153#[repr(C)]
1154pub struct LinuxDecorationsState {
1155    pub is_dragging_titlebar: bool,
1156    pub close_button_hover: bool,
1157    pub maximize_button_hover: bool,
1158    pub minimize_button_hover: bool,
1159}
1160
1161impl_option!(
1162    LinuxDecorationsState,
1163    OptionLinuxDecorationsState,
1164    [Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash]
1165);
1166
1167#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
1168#[repr(C)]
1169pub struct LinuxWindowOptions {
1170    /// (Unimplemented) - Can only be set at window creation, can't be changed in callbacks.
1171    pub x11_visual: OptionX11Visual,
1172    /// (Unimplemented) - Can only be set at window creation, can't be changed in callbacks.
1173    pub x11_screen: OptionI32,
1174    /// Build window with `WM_CLASS` hint; defaults to the name of the binary. Only relevant on
1175    /// X11. Can only be set at window creation, can't be changed in callbacks.
1176    pub x11_wm_classes: StringPairVec,
1177    /// Build window with override-redirect flag; defaults to false. Only relevant on X11.
1178    /// Can only be set at window creation, can't be changed in callbacks.
1179    pub x11_override_redirect: bool,
1180    /// Build window with `_NET_WM_WINDOW_TYPE` hint; defaults to `Normal`. Only relevant on X11.
1181    /// Can only be set at window creation, can't be changed in callbacks.
1182    pub x11_window_types: XWindowTypeVec,
1183    /// Build window with `_GTK_THEME_VARIANT` hint set to the specified value. Currently only
1184    /// relevant on X11. Can only be set at window creation, can't be changed in callbacks.
1185    pub x11_gtk_theme_variant: OptionString,
1186    /// Build window with resize increment hint. Only implemented on X11.
1187    /// Can only be set at window creation, can't be changed in callbacks.
1188    pub x11_resize_increments: OptionLogicalSize,
1189    /// Build window with base size hint. Only implemented on X11.
1190    /// Can only be set at window creation, can't be changed in callbacks.
1191    pub x11_base_size: OptionLogicalSize,
1192    /// Build window with a given application ID. It should match the `.desktop` file distributed
1193    /// with your program. Only relevant on Wayland.
1194    /// Can only be set at window creation, can't be changed in callbacks.
1195    ///
1196    /// For details about application ID conventions, see the
1197    /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
1198    pub wayland_app_id: OptionString,
1199    pub wayland_theme: OptionWaylandTheme,
1200    pub request_user_attention: UserAttentionType,
1201    pub window_icon: OptionWindowIcon,
1202    /// X11-specific: Client-side decoration state (drag position, button hover, etc.)
1203    pub x11_decorations_state: OptionLinuxDecorationsState,
1204}
1205
1206pub type X11Visual = *const c_void;
1207impl_option!(
1208    X11Visual,
1209    OptionX11Visual,
1210    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
1211);
1212
1213#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1214#[repr(C)]
1215pub struct AzStringPair {
1216    pub key: AzString,
1217    pub value: AzString,
1218}
1219
1220impl_vec!(
1221    AzStringPair,
1222    StringPairVec,
1223    StringPairVecDestructor,
1224    StringPairVecDestructorType
1225);
1226impl_vec_mut!(AzStringPair, StringPairVec);
1227impl_vec_debug!(AzStringPair, StringPairVec);
1228impl_vec_partialord!(AzStringPair, StringPairVec);
1229impl_vec_ord!(AzStringPair, StringPairVec);
1230impl_vec_clone!(AzStringPair, StringPairVec, StringPairVecDestructor);
1231impl_vec_partialeq!(AzStringPair, StringPairVec);
1232impl_vec_eq!(AzStringPair, StringPairVec);
1233impl_vec_hash!(AzStringPair, StringPairVec);
1234
1235impl_option!(
1236    StringPairVec,
1237    OptionStringPairVec,
1238    copy = false,
1239    [Debug, Clone, PartialOrd, PartialEq, Ord, Eq, Hash]
1240);
1241
1242impl StringPairVec {
1243    pub fn get_key(&self, search_key: &str) -> Option<&AzString> {
1244        self.as_ref().iter().find_map(|v| {
1245            if v.key.as_str() == search_key {
1246                Some(&v.value)
1247            } else {
1248                None
1249            }
1250        })
1251    }
1252    pub fn get_key_mut(&mut self, search_key: &str) -> Option<&mut AzStringPair> {
1253        self.as_mut()
1254            .iter_mut()
1255            .find(|v| v.key.as_str() == search_key)
1256    }
1257    pub fn insert_kv<I: Into<AzString>>(&mut self, key: I, value: I) {
1258        let key = key.into();
1259        let value = value.into();
1260        match self.get_key_mut(key.as_str()) {
1261            None => {}
1262            Some(s) => {
1263                s.value = value;
1264                return;
1265            }
1266        }
1267        self.push(AzStringPair { key, value });
1268    }
1269}
1270
1271impl_vec!(
1272    XWindowType,
1273    XWindowTypeVec,
1274    XWindowTypeVecDestructor,
1275    XWindowTypeVecDestructorType
1276);
1277impl_vec_debug!(XWindowType, XWindowTypeVec);
1278impl_vec_partialord!(XWindowType, XWindowTypeVec);
1279impl_vec_ord!(XWindowType, XWindowTypeVec);
1280impl_vec_clone!(XWindowType, XWindowTypeVec, XWindowTypeVecDestructor);
1281impl_vec_partialeq!(XWindowType, XWindowTypeVec);
1282impl_vec_eq!(XWindowType, XWindowTypeVec);
1283impl_vec_hash!(XWindowType, XWindowTypeVec);
1284
1285impl_option!(
1286    WaylandTheme,
1287    OptionWaylandTheme,
1288    copy = false,
1289    [Debug, Clone, PartialEq, PartialOrd]
1290);
1291
1292#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1293#[repr(C)]
1294pub struct MacWindowOptions {
1295    // empty for now, single field must be present for ABI compat - always set to 0
1296    pub _reserved: u8,
1297}
1298
1299#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1300#[repr(C)]
1301pub struct WasmWindowOptions {
1302    // empty for now, single field must be present for ABI compat - always set to 0
1303    pub _reserved: u8,
1304}
1305
1306#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1307#[repr(C)]
1308pub enum FullScreenMode {
1309    /// - macOS: If the window is in windowed mode, transitions it slowly to fullscreen mode
1310    /// - other: Does the same as `FastFullScreen`.
1311    SlowFullScreen,
1312    /// Window should immediately go into fullscreen mode (on macOS this is not the default
1313    /// behaviour).
1314    FastFullScreen,
1315    /// - macOS: If the window is in fullscreen mode, transitions slowly back to windowed state.
1316    /// - other: Does the same as `FastWindowed`.
1317    SlowWindowed,
1318    /// If the window is in fullscreen mode, will immediately go back to windowed mode (on macOS
1319    /// this is not the default behaviour).
1320    FastWindowed,
1321}
1322
1323// Translation type because in winit 24.0 the WinitWaylandTheme is a trait instead
1324// of a struct, which makes things more complicated
1325#[derive(Debug, Clone, PartialEq, PartialOrd)]
1326#[repr(C)]
1327pub struct WaylandTheme {
1328    pub title_bar_active_background_color: ColorU,
1329    pub title_bar_active_separator_color: ColorU,
1330    pub title_bar_active_text_color: ColorU,
1331    pub title_bar_inactive_background_color: ColorU,
1332    pub title_bar_inactive_separator_color: ColorU,
1333    pub title_bar_inactive_text_color: ColorU,
1334    pub maximize_idle_foreground_inactive_color: ColorU,
1335    pub minimize_idle_foreground_inactive_color: ColorU,
1336    pub close_idle_foreground_inactive_color: ColorU,
1337    pub maximize_hovered_foreground_inactive_color: ColorU,
1338    pub minimize_hovered_foreground_inactive_color: ColorU,
1339    pub close_hovered_foreground_inactive_color: ColorU,
1340    pub maximize_disabled_foreground_inactive_color: ColorU,
1341    pub minimize_disabled_foreground_inactive_color: ColorU,
1342    pub close_disabled_foreground_inactive_color: ColorU,
1343    pub maximize_idle_background_inactive_color: ColorU,
1344    pub minimize_idle_background_inactive_color: ColorU,
1345    pub close_idle_background_inactive_color: ColorU,
1346    pub maximize_hovered_background_inactive_color: ColorU,
1347    pub minimize_hovered_background_inactive_color: ColorU,
1348    pub close_hovered_background_inactive_color: ColorU,
1349    pub maximize_disabled_background_inactive_color: ColorU,
1350    pub minimize_disabled_background_inactive_color: ColorU,
1351    pub close_disabled_background_inactive_color: ColorU,
1352    pub maximize_idle_foreground_active_color: ColorU,
1353    pub minimize_idle_foreground_active_color: ColorU,
1354    pub close_idle_foreground_active_color: ColorU,
1355    pub maximize_hovered_foreground_active_color: ColorU,
1356    pub minimize_hovered_foreground_active_color: ColorU,
1357    pub close_hovered_foreground_active_color: ColorU,
1358    pub maximize_disabled_foreground_active_color: ColorU,
1359    pub minimize_disabled_foreground_active_color: ColorU,
1360    pub close_disabled_foreground_active_color: ColorU,
1361    pub maximize_idle_background_active_color: ColorU,
1362    pub minimize_idle_background_active_color: ColorU,
1363    pub close_idle_background_active_color: ColorU,
1364    pub maximize_hovered_background_active_color: ColorU,
1365    pub minimize_hovered_background_active_color: ColorU,
1366    pub close_hovered_background_active_color: ColorU,
1367    pub maximize_disabled_background_active_color: ColorU,
1368    pub minimize_disabled_background_active_color: ColorU,
1369    pub close_disabled_background_active_color: ColorU,
1370    pub title_bar_font: AzString,
1371    pub title_bar_font_size: f32,
1372}
1373
1374#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1375#[repr(C)]
1376pub struct WindowSize {
1377    /// Width and height of the window, in logical
1378    /// units (may not correspond to the physical on-screen size)
1379    pub dimensions: LogicalSize,
1380    /// Actual DPI value (default: 96)
1381    pub dpi: u32,
1382    /// Minimum dimensions of the window
1383    pub min_dimensions: OptionLogicalSize,
1384    /// Maximum dimensions of the window
1385    pub max_dimensions: OptionLogicalSize,
1386}
1387
1388impl WindowSize {
1389    pub fn get_layout_size(&self) -> LayoutSize {
1390        LayoutSize::new(
1391            libm::roundf(self.dimensions.width) as isize,
1392            libm::roundf(self.dimensions.height) as isize,
1393        )
1394    }
1395
1396    /// Get the actual logical size
1397    pub fn get_logical_size(&self) -> LogicalSize {
1398        self.dimensions
1399    }
1400
1401    pub fn get_physical_size(&self) -> PhysicalSize<u32> {
1402        self.dimensions
1403            .to_physical(self.get_hidpi_factor().inner.get())
1404    }
1405
1406    pub fn get_hidpi_factor(&self) -> DpiScaleFactor {
1407        DpiScaleFactor {
1408            inner: FloatValue::new(self.dpi as f32 / 96.0),
1409        }
1410    }
1411}
1412
1413impl Default for WindowSize {
1414    fn default() -> Self {
1415        Self {
1416            #[cfg(not(feature = "glow"))]
1417            dimensions: LogicalSize::new(640.0, 480.0),
1418            dpi: 96,
1419            min_dimensions: None.into(),
1420            max_dimensions: None.into(),
1421        }
1422    }
1423}
1424
1425#[repr(C)]
1426#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
1427pub enum RendererType {
1428    /// Force hardware rendering
1429    Hardware,
1430    /// Force software rendering
1431    Software,
1432}
1433
1434impl_option!(
1435    RendererType,
1436    OptionRendererType,
1437    [Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash]
1438);
1439
1440#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
1441pub enum UpdateFocusWarning {
1442    FocusInvalidDomId(DomId),
1443    FocusInvalidNodeId(NodeHierarchyItemId),
1444    CouldNotFindFocusNode(CssPath),
1445}
1446
1447impl ::core::fmt::Display for UpdateFocusWarning {
1448    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
1449        use self::UpdateFocusWarning::*;
1450        match self {
1451            FocusInvalidDomId(dom_id) => write!(f, "Focusing on DOM with invalid ID: {:?}", dom_id),
1452            FocusInvalidNodeId(node_id) => {
1453                write!(f, "Focusing on node with invalid ID: {}", node_id)
1454            }
1455            CouldNotFindFocusNode(css_path) => {
1456                write!(f, "Could not find focus node for path: {}", css_path)
1457            }
1458        }
1459    }
1460}
1461
1462/// Utility function for easier creation of a keymap - i.e. `[vec![Ctrl, S], my_function]`
1463#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1464#[repr(C, u8)]
1465pub enum AcceleratorKey {
1466    Ctrl,
1467    Alt,
1468    Shift,
1469    Key(VirtualKeyCode),
1470}
1471
1472impl AcceleratorKey {
1473    /// Checks if the current keyboard state contains the given char or modifier,
1474    /// i.e. if the keyboard state currently has the shift key pressed and the
1475    /// accelerator key is `Shift`, evaluates to true, otherwise to false.
1476    pub fn matches(&self, keyboard_state: &KeyboardState) -> bool {
1477        use self::AcceleratorKey::*;
1478        match self {
1479            Ctrl => keyboard_state.ctrl_down(),
1480            Alt => keyboard_state.alt_down(),
1481            Shift => keyboard_state.shift_down(),
1482            Key(k) => keyboard_state.is_key_down(*k),
1483        }
1484    }
1485}
1486
1487/// Symbolic name for a keyboard key, does NOT take the keyboard locale into account
1488#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1489#[repr(C)]
1490pub enum VirtualKeyCode {
1491    Key1,
1492    Key2,
1493    Key3,
1494    Key4,
1495    Key5,
1496    Key6,
1497    Key7,
1498    Key8,
1499    Key9,
1500    Key0,
1501    A,
1502    B,
1503    C,
1504    D,
1505    E,
1506    F,
1507    G,
1508    H,
1509    I,
1510    J,
1511    K,
1512    L,
1513    M,
1514    N,
1515    O,
1516    P,
1517    Q,
1518    R,
1519    S,
1520    T,
1521    U,
1522    V,
1523    W,
1524    X,
1525    Y,
1526    Z,
1527    Escape,
1528    F1,
1529    F2,
1530    F3,
1531    F4,
1532    F5,
1533    F6,
1534    F7,
1535    F8,
1536    F9,
1537    F10,
1538    F11,
1539    F12,
1540    F13,
1541    F14,
1542    F15,
1543    F16,
1544    F17,
1545    F18,
1546    F19,
1547    F20,
1548    F21,
1549    F22,
1550    F23,
1551    F24,
1552    Snapshot,
1553    Scroll,
1554    Pause,
1555    Insert,
1556    Home,
1557    Delete,
1558    End,
1559    PageDown,
1560    PageUp,
1561    Left,
1562    Up,
1563    Right,
1564    Down,
1565    Back,
1566    Return,
1567    Space,
1568    Compose,
1569    Caret,
1570    Numlock,
1571    Numpad0,
1572    Numpad1,
1573    Numpad2,
1574    Numpad3,
1575    Numpad4,
1576    Numpad5,
1577    Numpad6,
1578    Numpad7,
1579    Numpad8,
1580    Numpad9,
1581    NumpadAdd,
1582    NumpadDivide,
1583    NumpadDecimal,
1584    NumpadComma,
1585    NumpadEnter,
1586    NumpadEquals,
1587    NumpadMultiply,
1588    NumpadSubtract,
1589    AbntC1,
1590    AbntC2,
1591    Apostrophe,
1592    Apps,
1593    Asterisk,
1594    At,
1595    Ax,
1596    Backslash,
1597    Calculator,
1598    Capital,
1599    Colon,
1600    Comma,
1601    Convert,
1602    Equals,
1603    Grave,
1604    Kana,
1605    Kanji,
1606    LAlt,
1607    LBracket,
1608    LControl,
1609    LShift,
1610    LWin,
1611    Mail,
1612    MediaSelect,
1613    MediaStop,
1614    Minus,
1615    Mute,
1616    MyComputer,
1617    NavigateForward,
1618    NavigateBackward,
1619    NextTrack,
1620    NoConvert,
1621    OEM102,
1622    Period,
1623    PlayPause,
1624    Plus,
1625    Power,
1626    PrevTrack,
1627    RAlt,
1628    RBracket,
1629    RControl,
1630    RShift,
1631    RWin,
1632    Semicolon,
1633    Slash,
1634    Sleep,
1635    Stop,
1636    Sysrq,
1637    Tab,
1638    Underline,
1639    Unlabeled,
1640    VolumeDown,
1641    VolumeUp,
1642    Wake,
1643    WebBack,
1644    WebFavorites,
1645    WebForward,
1646    WebHome,
1647    WebRefresh,
1648    WebSearch,
1649    WebStop,
1650    Yen,
1651    Copy,
1652    Paste,
1653    Cut,
1654}
1655
1656impl VirtualKeyCode {
1657    pub fn get_lowercase(&self) -> Option<char> {
1658        use self::VirtualKeyCode::*;
1659        match self {
1660            A => Some('a'),
1661            B => Some('b'),
1662            C => Some('c'),
1663            D => Some('d'),
1664            E => Some('e'),
1665            F => Some('f'),
1666            G => Some('g'),
1667            H => Some('h'),
1668            I => Some('i'),
1669            J => Some('j'),
1670            K => Some('k'),
1671            L => Some('l'),
1672            M => Some('m'),
1673            N => Some('n'),
1674            O => Some('o'),
1675            P => Some('p'),
1676            Q => Some('q'),
1677            R => Some('r'),
1678            S => Some('s'),
1679            T => Some('t'),
1680            U => Some('u'),
1681            V => Some('v'),
1682            W => Some('w'),
1683            X => Some('x'),
1684            Y => Some('y'),
1685            Z => Some('z'),
1686            Key0 | Numpad0 => Some('0'),
1687            Key1 | Numpad1 => Some('1'),
1688            Key2 | Numpad2 => Some('2'),
1689            Key3 | Numpad3 => Some('3'),
1690            Key4 | Numpad4 => Some('4'),
1691            Key5 | Numpad5 => Some('5'),
1692            Key6 | Numpad6 => Some('6'),
1693            Key7 | Numpad7 => Some('7'),
1694            Key8 | Numpad8 => Some('8'),
1695            Key9 | Numpad9 => Some('9'),
1696            Minus => Some('-'),
1697            Asterisk => Some('´'),
1698            At => Some('@'),
1699            Period => Some('.'),
1700            Semicolon => Some(';'),
1701            Slash => Some('/'),
1702            Caret => Some('^'),
1703            _ => None,
1704        }
1705    }
1706}
1707
1708/// 16x16x4 bytes icon
1709#[derive(Debug, Clone)]
1710#[repr(C)]
1711pub struct SmallWindowIconBytes {
1712    pub key: IconKey,
1713    pub rgba_bytes: U8Vec,
1714}
1715
1716/// 16x16x4 bytes icon
1717#[derive(Debug, Clone)]
1718#[repr(C)]
1719pub struct LargeWindowIconBytes {
1720    pub key: IconKey,
1721    pub rgba_bytes: U8Vec,
1722}
1723
1724// Window icon that usually appears in the top-left corner of the window
1725#[derive(Debug, Clone)]
1726#[repr(C, u8)]
1727pub enum WindowIcon {
1728    Small(SmallWindowIconBytes),
1729    /// 32x32x4 bytes icon
1730    Large(LargeWindowIconBytes),
1731}
1732
1733impl_option!(
1734    WindowIcon,
1735    OptionWindowIcon,
1736    copy = false,
1737    [Debug, Clone, PartialOrd, PartialEq, Eq, Hash, Ord]
1738);
1739
1740impl WindowIcon {
1741    pub fn get_key(&self) -> IconKey {
1742        match &self {
1743            WindowIcon::Small(SmallWindowIconBytes { key, .. }) => *key,
1744            WindowIcon::Large(LargeWindowIconBytes { key, .. }) => *key,
1745        }
1746    }
1747}
1748// -- Only compare the IconKey (for WindowIcon and TaskBarIcon)
1749
1750impl PartialEq for WindowIcon {
1751    fn eq(&self, rhs: &Self) -> bool {
1752        self.get_key() == rhs.get_key()
1753    }
1754}
1755
1756impl PartialOrd for WindowIcon {
1757    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
1758        Some((self.get_key()).cmp(&rhs.get_key()))
1759    }
1760}
1761
1762impl Eq for WindowIcon {}
1763
1764impl Ord for WindowIcon {
1765    fn cmp(&self, rhs: &Self) -> Ordering {
1766        (self.get_key()).cmp(&rhs.get_key())
1767    }
1768}
1769
1770impl Hash for WindowIcon {
1771    fn hash<H>(&self, state: &mut H)
1772    where
1773        H: Hasher,
1774    {
1775        self.get_key().hash(state);
1776    }
1777}
1778
1779/// 256x256x4 bytes window icon
1780#[derive(Debug, Clone)]
1781#[repr(C)]
1782pub struct TaskBarIcon {
1783    pub key: IconKey,
1784    pub rgba_bytes: U8Vec,
1785}
1786
1787impl_option!(
1788    TaskBarIcon,
1789    OptionTaskBarIcon,
1790    copy = false,
1791    [Debug, Clone, PartialOrd, PartialEq, Eq, Hash, Ord]
1792);
1793
1794impl PartialEq for TaskBarIcon {
1795    fn eq(&self, rhs: &Self) -> bool {
1796        self.key == rhs.key
1797    }
1798}
1799
1800impl PartialOrd for TaskBarIcon {
1801    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
1802        Some((self.key).cmp(&rhs.key))
1803    }
1804}
1805
1806impl Eq for TaskBarIcon {}
1807
1808impl Ord for TaskBarIcon {
1809    fn cmp(&self, rhs: &Self) -> Ordering {
1810        (self.key).cmp(&rhs.key)
1811    }
1812}
1813
1814impl Hash for TaskBarIcon {
1815    fn hash<H>(&self, state: &mut H)
1816    where
1817        H: Hasher,
1818    {
1819        self.key.hash(state);
1820    }
1821}