diff --git a/Cargo.toml b/Cargo.toml index e4a44fd5..2a229866 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,8 @@ raw-window-handle = "0.6.0" wgpu = { version = "22.0.0" } parking_lot = { version = "0.12.1" } swash = { version = "0.1.17" } -winit = { git = "https://github.com/rust-windowing/winit", rev = "ae4c449670674d8ac0d6d8754caf3fe5f4954c25" } +muda = { version = "0.15.3" } +winit = { git = "https://github.com/rust-windowing/winit", rev = "3a60cbaba5fd96d9244a1f316ae562d7032b2b98" } [dependencies] slotmap = "1.0.7" @@ -68,6 +69,7 @@ parking_lot = { workspace = true } image = { workspace = true } im = { workspace = true } wgpu = { workspace = true } +muda = { workspace = true } winit = { workspace = true } futures = { version = "0.3.30", optional = true } crossbeam = "0.8" diff --git a/src/app.rs b/src/app.rs index 84017d68..ae7331ea 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,7 +1,7 @@ use std::{cell::RefCell, rc::Rc, sync::Arc}; use crossbeam_channel::{Receiver, Sender}; -use floem_reactive::WriteSignal; +use floem_reactive::{Trigger, WriteSignal}; use parking_lot::Mutex; use raw_window_handle::HasDisplayHandle; use winit::{ @@ -53,15 +53,15 @@ pub enum AppEvent { } pub(crate) enum UserEvent { - AppUpdate, - Idle, + AppUpdate(AppUpdateEvent), + Idle(Trigger), QuitApp, GpuResourcesUpdate { window_id: WindowId }, } pub(crate) enum AppUpdateEvent { NewWindow { - view_fn: Box Box>, + view_fn: Box Box + Send + Sync>, config: Option, }, CloseWindow { @@ -69,11 +69,11 @@ pub(crate) enum AppUpdateEvent { }, CaptureWindow { window_id: WindowId, - capture: WriteSignal>>, + capture: WriteSignal>>, }, ProfileWindow { window_id: WindowId, - end_profile: Option>>>, + end_profile: Option>>>, }, RequestTimer { timer: Timer, @@ -89,12 +89,7 @@ pub(crate) enum AppUpdateEvent { } pub(crate) fn add_app_update_event(event: AppUpdateEvent) { - APP_UPDATE_EVENTS.with(|events| { - events.borrow_mut().push(event); - }); - Application::with_event_loop_proxy(|proxy| { - proxy.wake_up(); - }); + Application::send_proxy_event(UserEvent::AppUpdate(event)); } /// Floem top level application @@ -115,10 +110,12 @@ impl Default for Application { impl ApplicationHandler for Application { fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { + println!("can create surfaces"); while let Some((view_fn, window_config)) = self.initial_windows.pop() { self.handle .new_window(event_loop, view_fn, window_config.unwrap_or_default()); } + println!("window creation done"); } fn window_event( @@ -127,14 +124,19 @@ impl ApplicationHandler for Application { window_id: WindowId, event: WindowEvent, ) { + println!("window event {event:?}"); + self.handle.handle_timer(event_loop); self.handle .handle_window_event(window_id, event, event_loop); } fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) { + println!("proxy wake up"); + self.handle.handle_timer(event_loop); for event in self.receiver.try_iter() { self.handle.handle_user_event(event_loop, event); } + self.handle.handle_updates_for_all_windows(); } fn exiting(&mut self, _event_loop: &dyn ActiveEventLoop) { @@ -142,6 +144,10 @@ impl ApplicationHandler for Application { action(AppEvent::WillTerminate); } } + + fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) { + self.handle.handle_timer(event_loop); + } } impl Application { @@ -189,46 +195,10 @@ impl Application { pub fn run(mut self) { let event_loop = self.event_loop.take().unwrap(); + println!("now run app"); event_loop.run_app(self); } - pub fn old_run(mut self) { - let mut handle = self.handle.take().unwrap(); - handle.idle(); - let event_loop_proxy = self.event_loop.create_proxy(); - let _ = self.event_loop.run(|event, event_loop| { - event_loop.set_control_flow(ControlFlow::Wait); - handle.handle_timer(event_loop); - - match event { - floem_winit::event::Event::NewEvents(_) => {} - floem_winit::event::Event::WindowEvent { window_id, event } => { - handle.handle_window_event(window_id, event, event_loop); - } - floem_winit::event::Event::DeviceEvent { .. } => {} - floem_winit::event::Event::UserEvent(event) => { - handle.handle_user_event(event_loop, event_loop_proxy.clone(), event); - } - floem_winit::event::Event::Suspended => {} - floem_winit::event::Event::Resumed => {} - floem_winit::event::Event::AboutToWait => {} - floem_winit::event::Event::LoopExiting => { - if let Some(action) = self.event_listener.as_ref() { - action(AppEvent::WillTerminate); - } - } - floem_winit::event::Event::MemoryWarning => {} - floem_winit::event::Event::Reopen => {} - } - }); - } - - pub(crate) fn with_event_loop_proxy(f: impl FnOnce(&EventLoopProxy)) { - if let Some(proxy) = EVENT_LOOP_PROXY.lock().as_ref() { - f(proxy); - } - } - pub(crate) fn send_proxy_event(event: UserEvent) { if let Some((proxy, sender)) = EVENT_LOOP_PROXY.lock().as_ref() { let _ = sender.send(event); @@ -236,13 +206,13 @@ impl Application { } } - pub fn available_monitors(&self) -> impl Iterator { - self.event_loop.as_ref().unwrap().available_monitors() - } + // pub fn available_monitors(&self) -> impl Iterator { + // self.event_loop.as_ref().unwrap().available_monitors() + // } - pub fn primary_monitor(&self) -> Option { - self.event_loop.as_ref().unwrap().primary_monitor() - } + // pub fn primary_monitor(&self) -> Option { + // self.event_loop.as_ref().unwrap().primary_monitor() + // } } /// Initiates the application shutdown process. diff --git a/src/app_handle.rs b/src/app_handle.rs index 3b264887..65eaa147 100644 --- a/src/app_handle.rs +++ b/src/app_handle.rs @@ -6,9 +6,9 @@ use web_time::Instant; #[cfg(target_arch = "wasm32")] use wgpu::web_sys; -use floem_reactive::SignalUpdate; +use floem_reactive::{SignalUpdate, Trigger}; use peniko::kurbo::{Point, Size}; -use std::{collections::HashMap, mem, rc::Rc}; +use std::{collections::HashMap, mem, rc::Rc, sync::Arc}; use winit::{ dpi::{LogicalPosition, LogicalSize}, event::WindowEvent, @@ -43,11 +43,11 @@ impl ApplicationHandle { pub(crate) fn handle_user_event(&mut self, event_loop: &dyn ActiveEventLoop, event: UserEvent) { match event { - UserEvent::AppUpdate => { - self.handle_update_event(event_loop); + UserEvent::AppUpdate(event) => { + self.handle_update_event(event_loop, event); } - UserEvent::Idle => { - self.idle(); + UserEvent::Idle(trigger) => { + self.idle(trigger); } UserEvent::QuitApp => { event_loop.exit(); @@ -61,55 +61,53 @@ impl ApplicationHandle { } } - pub(crate) fn handle_update_event(&mut self, event_loop: &dyn ActiveEventLoop) { - let events = APP_UPDATE_EVENTS.with(|events| { - let mut events = events.borrow_mut(); - std::mem::take(&mut *events) - }); - for event in events { - match event { - AppUpdateEvent::NewWindow { view_fn, config } => { - self.new_window(event_loop, view_fn, config.unwrap_or_default()) - } - AppUpdateEvent::CloseWindow { window_id } => { - self.close_window(window_id, event_loop); - } - AppUpdateEvent::RequestTimer { timer } => { - self.request_timer(timer, event_loop); - } - AppUpdateEvent::CancelTimer { timer } => { - self.remove_timer(&timer); - } - AppUpdateEvent::CaptureWindow { window_id, capture } => { - capture.set(self.capture_window(window_id).map(Rc::new)); - } - AppUpdateEvent::ProfileWindow { - window_id, - end_profile, - } => { - let handle = self.window_handles.get_mut(&window_id); - if let Some(handle) = handle { - if let Some(profile) = end_profile { - profile.set(handle.profile.take().map(|mut profile| { - profile.next_frame(); - Rc::new(profile) - })); - } else { - handle.profile = Some(Profile::default()); - } + pub(crate) fn handle_update_event( + &mut self, + event_loop: &dyn ActiveEventLoop, + event: AppUpdateEvent, + ) { + match event { + AppUpdateEvent::NewWindow { view_fn, config } => { + self.new_window(event_loop, view_fn, config.unwrap_or_default()) + } + AppUpdateEvent::CloseWindow { window_id } => { + self.close_window(window_id, event_loop); + } + AppUpdateEvent::RequestTimer { timer } => { + self.request_timer(timer, event_loop); + } + AppUpdateEvent::CancelTimer { timer } => { + self.remove_timer(&timer); + } + AppUpdateEvent::CaptureWindow { window_id, capture } => { + capture.set(self.capture_window(window_id).map(Arc::new)); + } + AppUpdateEvent::ProfileWindow { + window_id, + end_profile, + } => { + let handle = self.window_handles.get_mut(&window_id); + if let Some(handle) = handle { + if let Some(profile) = end_profile { + profile.set(handle.profile.take().map(|mut profile| { + profile.next_frame(); + Arc::new(profile) + })); + } else { + handle.profile = Some(Profile::default()); } } - #[cfg(any(target_os = "linux", target_os = "freebsd"))] - AppUpdateEvent::MenuAction { - window_id, - action_id, - } => { - let window_handle = match self.window_handles.get_mut(&window_id) { - Some(window_handle) => window_handle, - None => return, - }; - window_handle.menu_action(action_id); - } + } + #[cfg(any(target_os = "linux", target_os = "freebsd"))] + AppUpdateEvent::MenuAction { + window_id, + action_id, + } => { + let window_handle = match self.window_handles.get_mut(&window_id) { + Some(window_handle) => window_handle, + None => return, + }; + window_handle.menu_action(action_id); } } } @@ -228,9 +226,13 @@ impl ApplicationHandle { WindowEvent::Occluded(_) => {} WindowEvent::RedrawRequested => { window_handle.render_frame(); - } // WindowEvent::MenuAction(id) => { - // window_handle.menu_action(id); - // } + } + WindowEvent::PinchGesture { .. } => {} + WindowEvent::PanGesture { .. } => {} + WindowEvent::DoubleTapGesture { .. } => {} + WindowEvent::RotationGesture { .. } => {} // WindowEvent::MenuAction(id) => { + // window_handle.menu_action(id); + // } } if let Some((name, start, new_frame)) = start { @@ -275,6 +277,7 @@ impl ApplicationHandle { font_embolden, }: WindowConfig, ) { + println!("new window"); let logical_size = size.map(|size| LogicalSize::new(size.width, size.height)); let mut window_attributes = winit::window::WindowAttributes::default() @@ -394,6 +397,7 @@ impl ApplicationHandle { } } + println!("window attributes {window_attributes:?}"); let Ok(window) = event_loop.create_window(window_attributes) else { return; }; @@ -432,17 +436,11 @@ impl ApplicationHandle { .map(|handle| handle.capture()) } - pub(crate) fn idle(&mut self) { - let ext_events = { mem::take(&mut *EXT_EVENT_HANDLER.queue.lock()) }; - - for trigger in ext_events { - trigger.notify(); - } - - self.handle_updates_for_all_windows(); + pub(crate) fn idle(&mut self, trigger: Trigger) { + trigger.notify(); } - fn handle_updates_for_all_windows(&mut self) { + pub(crate) fn handle_updates_for_all_windows(&mut self) { for (window_id, handle) in self.window_handles.iter_mut() { handle.process_update(); while process_window_updates(window_id) {} diff --git a/src/ext_event.rs b/src/ext_event.rs index fefad07a..3d5f3c36 100644 --- a/src/ext_event.rs +++ b/src/ext_event.rs @@ -32,14 +32,7 @@ impl ExtEventHandler { } pub fn add_trigger(&self, trigger: Trigger) { - { - // Run this in a short block to prevent any deadlock if running the trigger effects - // causes another trigger to be registered - EXT_EVENT_HANDLER.queue.lock().push_back(trigger); - } - Application::with_event_loop_proxy(|proxy| { - let _ = proxy.send_event(UserEvent::Idle); - }); + Application::send_proxy_event(UserEvent::Idle(trigger)); } } diff --git a/src/inspector.rs b/src/inspector.rs index 960e1199..a96cefe1 100644 --- a/src/inspector.rs +++ b/src/inspector.rs @@ -229,7 +229,7 @@ fn captured_view_no_children( view: &CapturedView, depth: usize, capture_view: &CaptureView, - capture: &Rc, + capture: &Arc, ) -> impl IntoView { let offset = depth as f64 * 14.0; let name = captured_view_name(view).into_view(); @@ -291,7 +291,7 @@ fn captured_view_with_children( depth: usize, capture_view: &CaptureView, children: Vec>, - capture: &Rc, + capture: &Arc, ) -> impl IntoView { let offset = depth as f64 * 14.0; let name = captured_view_name(view).into_view(); @@ -404,7 +404,7 @@ fn captured_view( view: &Arc, depth: usize, capture_view: &CaptureView, - capture: &Rc, + capture: &Arc, ) -> impl IntoView { if view.children.is_empty() { captured_view_no_children(view, depth, capture_view, capture).into_any() @@ -423,7 +423,7 @@ fn add_event( name: String, id: ViewId, capture_view: CaptureView, - capture: &Rc, + capture: &Arc, ) -> impl View { let capture = capture.clone(); row.keyboard_navigable() @@ -541,7 +541,7 @@ fn stats(capture: &Capture) -> impl IntoView { )) } -fn selected_view(capture: &Rc, selected: RwSignal>) -> impl IntoView { +fn selected_view(capture: &Arc, selected: RwSignal>) -> impl IntoView { let capture = capture.clone(); dyn_container( move || selected.get(), @@ -776,8 +776,8 @@ struct CaptureView { fn capture_view( window_id: WindowId, - capture_s: RwSignal>>, - capture: &Rc, + capture_s: RwSignal>>, + capture: &Arc, ) -> impl IntoView { let capture_view = CaptureView { expanding_selection: create_rw_signal(None), @@ -1051,8 +1051,8 @@ fn capture_view( fn inspector_view( window_id: WindowId, - capture_s: RwSignal>>, - capture: &Option>, + capture_s: RwSignal>>, + capture: &Option>, ) -> impl IntoView { let view = if let Some(capture) = capture { capture_view(window_id, capture_s, capture).into_any() @@ -1082,7 +1082,7 @@ fn inspector_view( thread_local! { pub(crate) static RUNNING: Cell = const { Cell::new(false) }; - pub(crate) static CAPTURE: RwSignal>> = { + pub(crate) static CAPTURE: RwSignal>> = { Scope::new().create_rw_signal(None) }; } diff --git a/src/menu.rs b/src/menu.rs index ea956734..4a49ff9f 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -1,5 +1,7 @@ use std::sync::atomic::AtomicU64; +use muda::PredefinedMenuItem; + /// An entry in a menu. /// /// An entry is either a [`MenuItem`], a submenu (i.e. [`Menu`]). @@ -46,30 +48,46 @@ impl Menu { self.entry(MenuEntry::Separator) } - pub(crate) fn platform_menu(&self) -> winit::menu::Menu { - let mut menu = if self.popup { - floem_winit::menu::Menu::new_for_popup() - } else { - floem_winit::menu::Menu::new() - }; + pub(crate) fn platform_menu(&self) -> muda::Menu { + let menu = muda::Menu::new(); + for entry in &self.children { + match entry { + MenuEntry::Separator => { + menu.append(&PredefinedMenuItem::separator()); + } + MenuEntry::Item(item) => { + menu.append(&muda::MenuItem::with_id( + item.id, + item.title.clone(), + item.enabled, + None, + )); + } + MenuEntry::SubMenu(floem_menu) => { + menu.append(&floem_menu.platform_submenu()); + } + } + } + menu + } + + pub(crate) fn platform_submenu(&self) -> muda::Submenu { + let menu = muda::Submenu::new(self.item.title.clone(), self.item.enabled); for entry in &self.children { match entry { MenuEntry::Separator => { - menu.add_separator(); + menu.append(&PredefinedMenuItem::separator()); } MenuEntry::Item(item) => { - menu.add_item( - item.id as u32, - &item.title, - // item.key.as_ref(), - item.selected, + menu.append(&muda::MenuItem::with_id( + item.id, + item.title.clone(), item.enabled, - ); + None, + )); } - MenuEntry::SubMenu(m) => { - let enabled = m.item.enabled; - let title = m.item.title.clone(); - menu.add_dropdown(m.platform_menu(), &title, enabled); + MenuEntry::SubMenu(floem_menu) => { + menu.append(&floem_menu.platform_submenu()); } } } diff --git a/src/profiler.rs b/src/profiler.rs index a50ce7c4..244468c3 100644 --- a/src/profiler.rs +++ b/src/profiler.rs @@ -11,6 +11,7 @@ use peniko::Color; use std::fmt::Display; use std::mem; use std::rc::Rc; +use std::sync::Arc; use taffy::style::FlexDirection; use winit::window::WindowId; @@ -67,7 +68,7 @@ fn info_row(name: String, view: impl IntoView + 'static) -> impl IntoView { }) } -fn profile_view(profile: &Rc) -> impl IntoView { +fn profile_view(profile: &Arc) -> impl IntoView { let mut frames: Vec<_> = profile .frames .iter() @@ -243,7 +244,7 @@ fn profile_view(profile: &Rc) -> impl IntoView { } thread_local! { - pub(crate) static PROFILE: RwSignal>> = { + pub(crate) static PROFILE: RwSignal>> = { Scope::new().create_rw_signal(None) }; } diff --git a/src/views/editor/keypress/key.rs b/src/views/editor/keypress/key.rs index cd794d6c..ec0c3037 100644 --- a/src/views/editor/keypress/key.rs +++ b/src/views/editor/keypress/key.rs @@ -547,12 +547,12 @@ impl KeyInput { } fn mouse_from_str(s: &str) -> Option { - use crate::pointer::PointerButton as B; + use crate::pointer::MouseButton as B; Some(match s { - "mousemiddle" => B::Auxiliary, - "mouseforward" => B::X2, - "mousebackward" => B::X1, + "mousemiddle" => PointerButton::Mouse(B::Auxiliary), + "mouseforward" => PointerButton::Mouse(B::X2), + "mousebackward" => PointerButton::Mouse(B::X1), _ => return None, }) } @@ -560,8 +560,6 @@ impl KeyInput { impl Display for KeyInput { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use crate::pointer::PointerButton as B; - match self { Self::Keyboard(_key, key_code) => match key_code { PhysicalKey::Unidentified(_) => f.write_str("Unidentified"), diff --git a/src/views/editor/mod.rs b/src/views/editor/mod.rs index 22bd3150..904e8722 100644 --- a/src/views/editor/mod.rs +++ b/src/views/editor/mod.rs @@ -1576,17 +1576,18 @@ pub struct CursorInfo { pub blink_timer: RwSignal, // TODO: should these just be rwsignals? - pub should_blink: Rc bool + 'static>, - pub blink_interval: Rc u64 + 'static>, + pub should_blink: Arc bool + 'static + Send + Sync>, + pub blink_interval: Arc u64 + 'static + Send + Sync>, } + impl CursorInfo { pub fn new(cx: Scope) -> CursorInfo { CursorInfo { hidden: cx.create_rw_signal(false), blink_timer: cx.create_rw_signal(TimerToken::INVALID), - should_blink: Rc::new(|| true), - blink_interval: Rc::new(|| 500), + should_blink: Arc::new(|| true), + blink_interval: Arc::new(|| 500), } } diff --git a/src/views/text_input.rs b/src/views/text_input.rs index acd71e3d..08554981 100644 --- a/src/views/text_input.rs +++ b/src/views/text_input.rs @@ -2,7 +2,7 @@ use crate::action::exec_after; use crate::event::{EventListener, EventPropagation}; use crate::id::ViewId; use crate::keyboard::{self, KeyEvent, Modifiers}; -use crate::pointer::{PointerButton, PointerInputEvent}; +use crate::pointer::{MouseButton, PointerButton, PointerInputEvent}; use crate::reactive::{create_effect, RwSignal}; use crate::style::{FontProps, PaddingLeft, SelectionStyle}; use crate::style::{FontStyle, FontWeight, TextColor}; @@ -1044,7 +1044,7 @@ impl View for TextInput { // match on pointer primary button press Event::PointerDown( event @ PointerInputEvent { - button: PointerButton::Primary, + button: PointerButton::Mouse(MouseButton::Primary), .. }, ) => { diff --git a/src/window.rs b/src/window.rs index 1c6d326e..b6799b8d 100644 --- a/src/window.rs +++ b/src/window.rs @@ -363,7 +363,7 @@ impl WebWindowConfig { /// create a new window. You'll need to create Application first, otherwise it /// will panic pub fn new_window( - app_view: impl FnOnce(WindowId) -> V + 'static, + app_view: impl FnOnce(WindowId) -> V + 'static + Send + Sync, config: Option, ) { add_app_update_event(AppUpdateEvent::NewWindow { diff --git a/src/window_handle.rs b/src/window_handle.rs index 1eb0ffc6..b97788bd 100644 --- a/src/window_handle.rs +++ b/src/window_handle.rs @@ -39,7 +39,7 @@ use crate::{ keyboard::{KeyEvent, Modifiers}, menu::Menu, nav::view_arrow_navigation, - pointer::{MouseButton, PointerButton, PointerInputEvent, PointerMoveEvent, PointerWheelEvent}, + pointer::{PointerButton, PointerInputEvent, PointerMoveEvent, PointerWheelEvent}, profiler::Profile, style::{CursorStyle, Style, StyleSelector}, theme::{default_theme, Theme}, @@ -183,6 +183,7 @@ impl WindowHandle { } pub(crate) fn init_renderer(&mut self) { + println!("now init renderer"); self.paint_state.init_renderer(); // On the web, we need to get the canvas size once. The size will be updated automatically // when the canvas element is resized subsequently. This is the correct place to do so @@ -1115,19 +1116,21 @@ impl WindowHandle { } #[cfg(target_os = "macos")] - fn show_context_menu(&self, menu: winit::menu::Menu, pos: Option) { + fn show_context_menu(&self, menu: muda::Menu, pos: Option) { + use muda::{ + dpi::{LogicalPosition, Position}, + ContextMenu, + }; + use raw_window_handle::RawWindowHandle; + if let Some(window) = self.window.as_ref() { - { - use winit::platform::macos::WindowExtMacOS; - window.show_context_menu( - menu, - pos.map(|pos| { - winit::dpi::Position::Logical(winit::dpi::LogicalPosition::new( - pos.x * self.app_state.scale, - pos.y * self.app_state.scale, - )) - }), - ); + if let RawWindowHandle::AppKit(handle) = window.window_handle().unwrap().as_raw() { + unsafe { + menu.show_context_menu_for_nsview( + handle.ns_view.as_ptr() as _, + pos.map(|pos| Position::Logical(LogicalPosition::new(pos.x, pos.y))), + ) + }; } } } diff --git a/src/window_id.rs b/src/window_id.rs index e6030413..40214e52 100644 --- a/src/window_id.rs +++ b/src/window_id.rs @@ -257,11 +257,8 @@ impl WindowIdExt for WindowId { #[cfg(target_os = "macos")] #[allow(dead_code)] fn is_document_edited(&self) -> bool { - with_window( - self, - winit::platform::macos::WindowExtMacOS::is_document_edited, - ) - .unwrap_or(false) + use winit::platform::macos::WindowExtMacOS; + with_window(self, |window| window.is_document_edited()).unwrap_or(false) } #[cfg(not(target_os = "macos"))] diff --git a/src/window_tracking.rs b/src/window_tracking.rs index 5476c7e2..7785aea8 100644 --- a/src/window_tracking.rs +++ b/src/window_tracking.rs @@ -158,8 +158,11 @@ pub fn monitor_bounds(id: &WindowId) -> Option { pub fn monitor_bounds_for_monitor(window: &Arc, monitor: &MonitorHandle) -> Rect { let scale = 1.0 / window.scale_factor(); - let pos = monitor.position(); - let sz = monitor.size(); + let pos = monitor.position().unwrap_or_default(); + let sz = monitor + .current_video_mode() + .map(|h| h.size()) + .unwrap_or_default(); let x = pos.x as f64 * scale; let y = pos.y as f64 * scale; Rect::new(