use std::{ cell::RefCell, mem::ManuallyDrop, path::{Path, PathBuf}, rc::Rc, sync::Arc,}; use ::util::{ResultExt, paths::SanitizedPath};use anyhow::{Context as _, Result, anyhow};use async_task::Runnable;use futures::channel::oneshot::{self, Receiver};use itertools::Itertools;use parking_lot::RwLock;use smallvec::SmallVec;use windows::{ UI::ViewManagement::UISettings, Win32::{ Foundation::*, Graphics::{ Gdi::*, Imaging::{CLSID_WICImagingFactory, IWICImagingFactory}, }, Security::Credentials::*, System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*, Threading::*}, UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*}, }, core::*,}; use crate::{platform::blade::BladeContext, *}; pub(crate) struct WindowsPlatform { state: RefCell<WindowsPlatformState>, raw_window_handles: RwLock<SmallVec<[HWND; 4]>>, // The below members will never change throughout the entire lifecycle of the app. gpu_context: BladeContext, icon: HICON, main_receiver: flume::Receiver<Runnable>, background_executor: BackgroundExecutor, foreground_executor: ForegroundExecutor, text_system: Arc<DirectWriteTextSystem>, windows_version: WindowsVersion, bitmap_factory: ManuallyDrop<IWICImagingFactory>, drop_target_helper: IDropTargetHelper, validation_number: usize, main_thread_id_win32: u32,} pub(crate) struct WindowsPlatformState { callbacks: PlatformCallbacks, menus: Vec<OwnedMenu>, jump_list: JumpList, // NOTE: standard cursor handles don't need to close. pub(crate) current_cursor: Option<HCURSOR>,} #[derive(Default)]struct PlatformCallbacks { open_urls: Option<Box<dyn FnMut(Vec<String>)>>, quit: Option<Box<dyn FnMut()>>, reopen: Option<Box<dyn FnMut()>>, app_menu_action: Option<Box<dyn FnMut(&dyn Action)>>, will_open_app_menu: Option<Box<dyn FnMut()>>, validate_app_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>, keyboard_layout_change: Option<Box<dyn FnMut()>>,} impl WindowsPlatformState { fn new() -> Self { let callbacks = PlatformCallbacks::default(); let jump_list = JumpList::new(); let current_cursor = load_cursor(CursorStyle::Arrow); Self { callbacks, jump_list, current_cursor, menus: Vec::new(), } }} impl WindowsPlatform { pub(crate) fn new() -> Result<Self> { unsafe { OleInitialize(None).context("unable to initialize Windows OLE")?; } let (main_sender, main_receiver) = flume::unbounded::<Runnable>(); let main_thread_id_win32 = unsafe { GetCurrentThreadId() }; let validation_number = rand::random::<usize>(); let dispatcher = Arc::new(WindowsDispatcher::new( main_sender, main_thread_id_win32, validation_number, )); let background_executor = BackgroundExecutor::new(dispatcher.clone()); let foreground_executor = ForegroundExecutor::new(dispatcher); let bitmap_factory = ManuallyDrop::new(unsafe { CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER) .context("Error creating bitmap factory.")? }); let text_system = Arc::new( DirectWriteTextSystem::new(&bitmap_factory) .context("Error creating DirectWriteTextSystem")?, ); let drop_target_helper: IDropTargetHelper = unsafe { CoCreateInstance(&CLSID_DragDropHelper, None, CLSCTX_INPROC_SERVER) .context("Error creating drop target helper.")? }; let icon = load_icon().unwrap_or_default(); let state = RefCell::new(WindowsPlatformState::new()); let raw_window_handles = RwLock::new(SmallVec::new()); let gpu_context = BladeContext::new().context("Unable to init GPU context")?; let windows_version = WindowsVersion::new().context("Error retrieve windows version")?; Ok(Self { state, raw_window_handles, gpu_context, icon, main_receiver, background_executor, foreground_executor, text_system, windows_version, bitmap_factory, drop_target_helper, validation_number, main_thread_id_win32, }) } fn redraw_all(&self) { for handle in self.raw_window_handles.read().iter() { unsafe { RedrawWindow(Some(*handle), None, None, RDW_INVALIDATE | RDW_UPDATENOW) .ok() .log_err(); } } } pub fn try_get_windows_inner_from_hwnd(&self, hwnd: HWND) -> Option<Rc<WindowsWindowStatePtr>> { self.raw_window_handles .read() .iter() .find(|entry| *entry == &hwnd) .and_then(|hwnd| try_get_window_inner(*hwnd)) } #[inline] fn post_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) { self.raw_window_handles .read() .iter() .for_each(|handle| unsafe { PostMessageW(Some(*handle), message, wparam, lparam).log_err(); }); } fn close_one_window(&self, target_window: HWND) -> bool { let mut lock = self.raw_window_handles.write(); let index = lock .iter() .position(|handle| *handle == target_window) .unwrap(); lock.remove(index); lock.is_empty() } #[inline] fn run_foreground_task(&self) { for runnable in self.main_receiver.drain() { runnable.run(); } } fn generate_creation_info(&self) -> WindowCreationInfo { WindowCreationInfo { icon: self.icon, executor: self.foreground_executor.clone(), current_cursor: self.state.borrow().current_cursor, windows_version: self.windows_version, drop_target_helper: self.drop_target_helper.clone(), validation_number: self.validation_number, main_receiver: self.main_receiver.clone(), main_thread_id_win32: self.main_thread_id_win32, } } fn handle_dock_action_event(&self, action_idx: usize) { let mut lock = self.state.borrow_mut(); if let Some(mut callback) = lock.callbacks.app_menu_action.take() { let Some(action) = lock .jump_list .dock_menus .get(action_idx) .map(|dock_menu| dock_menu.action.boxed_clone()) else { lock.callbacks.app_menu_action = Some(callback); log::error!("Dock menu for index {action_idx} not found"); return; }; drop(lock); callback(&*action); self.state.borrow_mut().callbacks.app_menu_action = Some(callback); } } fn handle_input_lang_change(&self) { let mut lock = self.state.borrow_mut(); if let Some(mut callback) = lock.callbacks.keyboard_layout_change.take() { drop(lock); callback(); self.state .borrow_mut() .callbacks .keyboard_layout_change .get_or_insert(callback); } } // Returns true if the app should quit. fn handle_events(&self) -> bool { let mut msg = MSG::default(); unsafe { while PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).as_bool() { match msg.message { WM_QUIT => return true, WM_INPUTLANGCHANGE | WM_GPUI_CLOSE_ONE_WINDOW | WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD | WM_GPUI_DOCK_MENU_ACTION => { if self.handle_gpui_evnets(msg.message, msg.wParam, msg.lParam, &msg) { return true; } } _ => { DispatchMessageW(&msg); } } } } false } // Returns true if the app should quit. fn handle_gpui_evnets( &self, message: u32, wparam: WPARAM, lparam: LPARAM, msg: *const MSG, ) -> bool { if wparam.0 != self.validation_number { unsafe { DispatchMessageW(msg) }; return false; } match message { WM_GPUI_CLOSE_ONE_WINDOW => { if self.close_one_window(HWND(lparam.0 as _)) { return true; } } WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD => self.run_foreground_task(), WM_GPUI_DOCK_MENU_ACTION => self.handle_dock_action_event(lparam.0 as _), WM_INPUTLANGCHANGE => self.handle_input_lang_change(), _ => unreachable!(), } false } fn set_dock_menus(&self, menus: Vec<MenuItem>) { let mut actions = Vec::new(); menus.into_iter().for_each(|menu| { if let Some(dock_menu) = DockMenuItem::new(menu).log_err() { actions.push(dock_menu); } }); let mut lock = self.state.borrow_mut(); lock.jump_list.dock_menus = actions; update_jump_list(&lock.jump_list).log_err(); } fn update_jump_list( &self, menus: Vec<MenuItem>, entries: Vec<SmallVec<[PathBuf; 2]>>, ) -> Vec<SmallVec<[PathBuf; 2]>> { let mut actions = Vec::new(); menus.into_iter().for_each(|menu| { if let Some(dock_menu) = DockMenuItem::new(menu).log_err() { actions.push(dock_menu); } }); let mut lock = self.state.borrow_mut(); lock.jump_list.dock_menus = actions; lock.jump_list.recent_workspaces = entries; update_jump_list(&lock.jump_list) .log_err() .unwrap_or_default() } fn find_current_active_window(&self) -> Option<HWND> { let active_window_hwnd = unsafe { GetActiveWindow() }; if active_window_hwnd.is_invalid() { return None; } self.raw_window_handles .read() .iter() .find(|&&hwnd| hwnd == active_window_hwnd) .copied() }} impl Platform for WindowsPlatform { fn background_executor(&self) -> BackgroundExecutor { self.background_executor.clone() } fn foreground_executor(&self) -> ForegroundExecutor { self.foreground_executor.clone() } fn text_system(&self) -> Arc<dyn PlatformTextSystem> { self.text_system.clone() } fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout> { Box::new( WindowsKeyboardLayout::new() .log_err() .unwrap_or(WindowsKeyboardLayout::unknown()), ) } fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>) { self.state.borrow_mut().callbacks.keyboard_layout_change = Some(callback); } fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) { on_finish_launching(); let vsync_event = unsafe { Owned::new(CreateEventW(None, false, false, None).unwrap()) }; begin_vsync(*vsync_event); 'a: loop { let wait_result = unsafe { MsgWaitForMultipleObjects(Some(&[*vsync_event]), false, INFINITE, QS_ALLINPUT) }; match wait_result { // compositor clock ticked so we should draw a frame WAIT_EVENT(0) => self.redraw_all(), // Windows thread messages are posted WAIT_EVENT(1) => { if self.handle_events() { break 'a; } } _ => { log::error!("Something went wrong while waiting {:?}", wait_result); break; } } } if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit { callback(); } } fn quit(&self) { self.foreground_executor() .spawn(async { unsafe { PostQuitMessage(0) } }) .detach(); } fn restart(&self, _: Option<PathBuf>) { let pid = std::process::id(); let Some(app_path) = self.app_path().log_err() else { return; }; let script = format!( r#" $pidToWaitFor = {} $exePath = "{}" while ($true) {{ $process = Get-Process -Id $pidToWaitFor -ErrorAction SilentlyContinue if (-not $process) {{ Start-Process -FilePath $exePath break }} Start-Sleep -Seconds 0.1 }} "#, pid, app_path.display(), ); let restart_process = util::command::new_std_command("powershell.exe") .arg("-command") .arg(script) .spawn(); match restart_process { Ok(_) => self.quit(), Err(e) => log::error!("failed to spawn restart script: {:?}", e), } } fn activate(&self, _ignoring_other_apps: bool) {} fn hide(&self) {} // todo(windows) fn hide_other_apps(&self) { unimplemented!() } // todo(windows) fn unhide_other_apps(&self) { unimplemented!() } fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> { WindowsDisplay::displays() } fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> { WindowsDisplay::primary_monitor().map(|display| Rc::new(display) as Rc<dyn PlatformDisplay>) } fn is_screen_capture_supported(&self) -> bool { false } fn screen_capture_sources( &self, ) -> oneshot::Receiver<Result<Vec<Box<dyn ScreenCaptureSource>>>> { let (mut tx, rx) = oneshot::channel(); tx.send(Err(anyhow!("screen capture not implemented"))).ok(); rx } fn active_window(&self) -> Option<AnyWindowHandle> { let active_window_hwnd = unsafe { GetActiveWindow() }; self.try_get_windows_inner_from_hwnd(active_window_hwnd) .map(|inner| inner.handle) } fn open_window( &self, handle: AnyWindowHandle, options: WindowParams, ) -> Result<Box<dyn PlatformWindow>> { let window = WindowsWindow::new( handle, options, self.generate_creation_info(), &self.gpu_context, )?; let handle = window.get_raw_handle(); self.raw_window_handles.write().push(handle); Ok(Box::new(window)) } fn window_appearance(&self) -> WindowAppearance { system_appearance().log_err().unwrap_or_default() } fn open_url(&self, url: &str) { let url_string = url.to_string(); self.background_executor() .spawn(async move { if url_string.is_empty() { return; } open_target(url_string.as_str()); }) .detach(); } fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>) { self.state.borrow_mut().callbacks.open_urls = Some(callback); } fn prompt_for_paths( &self, options: PathPromptOptions, ) -> Receiver<Result<Option<Vec<PathBuf>>>> { let (tx, rx) = oneshot::channel(); let window = self.find_current_active_window(); self.foreground_executor() .spawn(async move { let _ = tx.send(file_open_dialog(options, window)); }) .detach();Lines 1–500 of 899. Load more
use std::{ cell::RefCell, mem::ManuallyDrop, path::{Path, PathBuf}, rc::Rc, sync::Arc, }; use ::util::{ResultExt, paths::SanitizedPath}; use anyhow::{Context as _, Result, anyhow}; use async_task::Runnable; use futures::channel::oneshot::{self, Receiver}; use itertools::Itertools; use parking_lot::RwLock; use smallvec::SmallVec; use windows::{ UI::ViewManagement::UISettings, Win32::{ Foundation::*, Graphics::{ Gdi::*, Imaging::{CLSID_WICImagingFactory, IWICImagingFactory}, }, Security::Credentials::*, System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*, Threading::*}, UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*}, }, core::*, }; use crate::{platform::blade::BladeContext, *}; pub(crate) struct WindowsPlatform { state: RefCell<WindowsPlatformState>, raw_window_handles: RwLock<SmallVec<[HWND; 4]>>, // The below members will never change throughout the entire lifecycle of the app. gpu_context: BladeContext, icon: HICON, main_receiver: flume::Receiver<Runnable>, background_executor: BackgroundExecutor, foreground_executor: ForegroundExecutor, text_system: Arc<DirectWriteTextSystem>, windows_version: WindowsVersion, bitmap_factory: ManuallyDrop<IWICImagingFactory>, drop_target_helper: IDropTargetHelper, validation_number: usize, main_thread_id_win32: u32, } pub(crate) struct WindowsPlatformState { callbacks: PlatformCallbacks, menus: Vec<OwnedMenu>, jump_list: JumpList, // NOTE: standard cursor handles don't need to close. pub(crate) current_cursor: Option<HCURSOR>, } #[derive(Default)] struct PlatformCallbacks { open_urls: Option<Box<dyn FnMut(Vec<String>)>>, quit: Option<Box<dyn FnMut()>>, reopen: Option<Box<dyn FnMut()>>, app_menu_action: Option<Box<dyn FnMut(&dyn Action)>>, will_open_app_menu: Option<Box<dyn FnMut()>>, validate_app_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>, keyboard_layout_change: Option<Box<dyn FnMut()>>, } impl WindowsPlatformState { fn new() -> Self { let callbacks = PlatformCallbacks::default(); let jump_list = JumpList::new(); let current_cursor = load_cursor(CursorStyle::Arrow); Self { callbacks, jump_list, current_cursor, menus: Vec::new(), } } } impl WindowsPlatform { pub(crate) fn new() -> Result<Self> { unsafe { OleInitialize(None).context("unable to initialize Windows OLE")?; } let (main_sender, main_receiver) = flume::unbounded::<Runnable>(); let main_thread_id_win32 = unsafe { GetCurrentThreadId() }; let validation_number = rand::random::<usize>(); let dispatcher = Arc::new(WindowsDispatcher::new( main_sender, main_thread_id_win32, validation_number, )); let background_executor = BackgroundExecutor::new(dispatcher.clone()); let foreground_executor = ForegroundExecutor::new(dispatcher); let bitmap_factory = ManuallyDrop::new(unsafe { CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER) .context("Error creating bitmap factory.")? }); let text_system = Arc::new( DirectWriteTextSystem::new(&bitmap_factory) .context("Error creating DirectWriteTextSystem")?, ); let drop_target_helper: IDropTargetHelper = unsafe { CoCreateInstance(&CLSID_DragDropHelper, None, CLSCTX_INPROC_SERVER) .context("Error creating drop target helper.")? }; let icon = load_icon().unwrap_or_default(); let state = RefCell::new(WindowsPlatformState::new()); let raw_window_handles = RwLock::new(SmallVec::new()); let gpu_context = BladeContext::new().context("Unable to init GPU context")?; let windows_version = WindowsVersion::new().context("Error retrieve windows version")?; Ok(Self { state, raw_window_handles, gpu_context, icon, main_receiver, background_executor, foreground_executor, text_system, windows_version, bitmap_factory, drop_target_helper, validation_number, main_thread_id_win32, }) } fn redraw_all(&self) { for handle in self.raw_window_handles.read().iter() { unsafe { RedrawWindow(Some(*handle), None, None, RDW_INVALIDATE | RDW_UPDATENOW) .ok() .log_err(); } } } pub fn try_get_windows_inner_from_hwnd(&self, hwnd: HWND) -> Option<Rc<WindowsWindowStatePtr>> { self.raw_window_handles .read() .iter() .find(|entry| *entry == &hwnd) .and_then(|hwnd| try_get_window_inner(*hwnd)) } #[inline] fn post_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) { self.raw_window_handles .read() .iter() .for_each(|handle| unsafe { PostMessageW(Some(*handle), message, wparam, lparam).log_err(); }); } fn close_one_window(&self, target_window: HWND) -> bool { let mut lock = self.raw_window_handles.write(); let index = lock .iter() .position(|handle| *handle == target_window) .unwrap(); lock.remove(index); lock.is_empty() } #[inline] fn run_foreground_task(&self) { for runnable in self.main_receiver.drain() { runnable.run(); } } fn generate_creation_info(&self) -> WindowCreationInfo { WindowCreationInfo { icon: self.icon, executor: self.foreground_executor.clone(), current_cursor: self.state.borrow().current_cursor, windows_version: self.windows_version, drop_target_helper: self.drop_target_helper.clone(), validation_number: self.validation_number, main_receiver: self.main_receiver.clone(), main_thread_id_win32: self.main_thread_id_win32, } } fn handle_dock_action_event(&self, action_idx: usize) { let mut lock = self.state.borrow_mut(); if let Some(mut callback) = lock.callbacks.app_menu_action.take() { let Some(action) = lock .jump_list .dock_menus .get(action_idx) .map(|dock_menu| dock_menu.action.boxed_clone()) else { lock.callbacks.app_menu_action = Some(callback); log::error!("Dock menu for index {action_idx} not found"); return; }; drop(lock); callback(&*action); self.state.borrow_mut().callbacks.app_menu_action = Some(callback); } } fn handle_input_lang_change(&self) { let mut lock = self.state.borrow_mut(); if let Some(mut callback) = lock.callbacks.keyboard_layout_change.take() { drop(lock); callback(); self.state .borrow_mut() .callbacks .keyboard_layout_change .get_or_insert(callback); } } // Returns true if the app should quit. fn handle_events(&self) -> bool { let mut msg = MSG::default(); unsafe { while PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).as_bool() { match msg.message { WM_QUIT => return true, WM_INPUTLANGCHANGE | WM_GPUI_CLOSE_ONE_WINDOW | WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD | WM_GPUI_DOCK_MENU_ACTION => { if self.handle_gpui_evnets(msg.message, msg.wParam, msg.lParam, &msg) { return true; } } _ => { DispatchMessageW(&msg); } } } } false } // Returns true if the app should quit. fn handle_gpui_evnets( &self, message: u32, wparam: WPARAM, lparam: LPARAM, msg: *const MSG, ) -> bool { if wparam.0 != self.validation_number { unsafe { DispatchMessageW(msg) }; return false; } match message { WM_GPUI_CLOSE_ONE_WINDOW => { if self.close_one_window(HWND(lparam.0 as _)) { return true; } } WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD => self.run_foreground_task(), WM_GPUI_DOCK_MENU_ACTION => self.handle_dock_action_event(lparam.0 as _), WM_INPUTLANGCHANGE => self.handle_input_lang_change(), _ => unreachable!(), } false } fn set_dock_menus(&self, menus: Vec<MenuItem>) { let mut actions = Vec::new(); menus.into_iter().for_each(|menu| { if let Some(dock_menu) = DockMenuItem::new(menu).log_err() { actions.push(dock_menu); } }); let mut lock = self.state.borrow_mut(); lock.jump_list.dock_menus = actions; update_jump_list(&lock.jump_list).log_err(); } fn update_jump_list( &self, menus: Vec<MenuItem>, entries: Vec<SmallVec<[PathBuf; 2]>>, ) -> Vec<SmallVec<[PathBuf; 2]>> { let mut actions = Vec::new(); menus.into_iter().for_each(|menu| { if let Some(dock_menu) = DockMenuItem::new(menu).log_err() { actions.push(dock_menu); } }); let mut lock = self.state.borrow_mut(); lock.jump_list.dock_menus = actions; lock.jump_list.recent_workspaces = entries; update_jump_list(&lock.jump_list) .log_err() .unwrap_or_default() } fn find_current_active_window(&self) -> Option<HWND> { let active_window_hwnd = unsafe { GetActiveWindow() }; if active_window_hwnd.is_invalid() { return None; } self.raw_window_handles .read() .iter() .find(|&&hwnd| hwnd == active_window_hwnd) .copied() } } impl Platform for WindowsPlatform { fn background_executor(&self) -> BackgroundExecutor { self.background_executor.clone() } fn foreground_executor(&self) -> ForegroundExecutor { self.foreground_executor.clone() } fn text_system(&self) -> Arc<dyn PlatformTextSystem> { self.text_system.clone() } fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout> { Box::new( WindowsKeyboardLayout::new() .log_err() .unwrap_or(WindowsKeyboardLayout::unknown()), ) } fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>) { self.state.borrow_mut().callbacks.keyboard_layout_change = Some(callback); } fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) { on_finish_launching(); let vsync_event = unsafe { Owned::new(CreateEventW(None, false, false, None).unwrap()) }; begin_vsync(*vsync_event); 'a: loop { let wait_result = unsafe { MsgWaitForMultipleObjects(Some(&[*vsync_event]), false, INFINITE, QS_ALLINPUT) }; match wait_result { // compositor clock ticked so we should draw a frame WAIT_EVENT(0) => self.redraw_all(), // Windows thread messages are posted WAIT_EVENT(1) => { if self.handle_events() { break 'a; } } _ => { log::error!("Something went wrong while waiting {:?}", wait_result); break; } } } if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit { callback(); } } fn quit(&self) { self.foreground_executor() .spawn(async { unsafe { PostQuitMessage(0) } }) .detach(); } fn restart(&self, _: Option<PathBuf>) { let pid = std::process::id(); let Some(app_path) = self.app_path().log_err() else { return; }; let script = format!( r#" $pidToWaitFor = {} $exePath = "{}" while ($true) {{ $process = Get-Process -Id $pidToWaitFor -ErrorAction SilentlyContinue if (-not $process) {{ Start-Process -FilePath $exePath break }} Start-Sleep -Seconds 0.1 }} "#, pid, app_path.display(), ); let restart_process = util::command::new_std_command("powershell.exe") .arg("-command") .arg(script) .spawn(); match restart_process { Ok(_) => self.quit(), Err(e) => log::error!("failed to spawn restart script: {:?}", e), } } fn activate(&self, _ignoring_other_apps: bool) {} fn hide(&self) {} // todo(windows) fn hide_other_apps(&self) { unimplemented!() } // todo(windows) fn unhide_other_apps(&self) { unimplemented!() } fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> { WindowsDisplay::displays() } fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> { WindowsDisplay::primary_monitor().map(|display| Rc::new(display) as Rc<dyn PlatformDisplay>) } fn is_screen_capture_supported(&self) -> bool { false } fn screen_capture_sources( &self, ) -> oneshot::Receiver<Result<Vec<Box<dyn ScreenCaptureSource>>>> { let (mut tx, rx) = oneshot::channel(); tx.send(Err(anyhow!("screen capture not implemented"))).ok(); rx } fn active_window(&self) -> Option<AnyWindowHandle> { let active_window_hwnd = unsafe { GetActiveWindow() }; self.try_get_windows_inner_from_hwnd(active_window_hwnd) .map(|inner| inner.handle) } fn open_window( &self, handle: AnyWindowHandle, options: WindowParams, ) -> Result<Box<dyn PlatformWindow>> { let window = WindowsWindow::new( handle, options, self.generate_creation_info(), &self.gpu_context, )?; let handle = window.get_raw_handle(); self.raw_window_handles.write().push(handle); Ok(Box::new(window)) } fn window_appearance(&self) -> WindowAppearance { system_appearance().log_err().unwrap_or_default() } fn open_url(&self, url: &str) { let url_string = url.to_string(); self.background_executor() .spawn(async move { if url_string.is_empty() { return; } open_target(url_string.as_str()); }) .detach(); } fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>) { self.state.borrow_mut().callbacks.open_urls = Some(callback); } fn prompt_for_paths( &self, options: PathPromptOptions, ) -> Receiver<Result<Option<Vec<PathBuf>>>> { let (tx, rx) = oneshot::channel(); let window = self.find_current_active_window(); self.foreground_executor() .spawn(async move { let _ = tx.send(file_open_dialog(options, window)); }) .detach();