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