Skip to main content

azul_core/
window.rs

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