use std::{ cell::{Cell, RefCell}, ffi::OsStr, path::{Path, PathBuf}, rc::{Rc, Weak}, sync::{ Arc, atomic::{AtomicBool, Ordering}, },}; use ::util::{ResultExt, paths::SanitizedPath};use anyhow::{Context as _, Result, anyhow};use futures::channel::oneshot::{self, Receiver};use itertools::Itertools;use parking_lot::RwLock;use smallvec::SmallVec;use windows::{ UI::ViewManagement::UISettings, Win32::{ Foundation::*, Graphics::{Direct3D11::ID3D11Device, Gdi::*}, Security::Credentials::*, System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*}, UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*}, }, core::*,}; use crate::*;use gpui::*; pub struct WindowsPlatform { inner: Rc<WindowsPlatformInner>, raw_window_handles: Arc<RwLock<SmallVec<[SafeHwnd; 4]>>>, // The below members will never change throughout the entire lifecycle of the app. headless: bool, icon: HICON, background_executor: BackgroundExecutor, foreground_executor: ForegroundExecutor, text_system: Arc<dyn PlatformTextSystem>, direct_write_text_system: Option<Arc<DirectWriteTextSystem>>, drop_target_helper: Option<IDropTargetHelper>, /// Flag to instruct the `VSyncProvider` thread to invalidate the directx devices /// as resizing them has failed, causing us to have lost at least the render target. invalidate_devices: Arc<AtomicBool>, handle: HWND, disable_direct_composition: bool,} struct WindowsPlatformInner { state: WindowsPlatformState, raw_window_handles: std::sync::Weak<RwLock<SmallVec<[SafeHwnd; 4]>>>, // The below members will never change throughout the entire lifecycle of the app. validation_number: usize, main_receiver: PriorityQueueReceiver<RunnableVariant>, dispatcher: Arc<WindowsDispatcher>,} pub(crate) struct WindowsPlatformState { callbacks: PlatformCallbacks, menus: RefCell<Vec<OwnedMenu>>, jump_list: RefCell<JumpList>, // NOTE: standard cursor handles don't need to close. pub(crate) current_cursor: Cell<Option<HCURSOR>>, directx_devices: RefCell<Option<DirectXDevices>>,} #[derive(Default)]struct PlatformCallbacks { open_urls: Cell<Option<Box<dyn FnMut(Vec<String>)>>>, quit: Cell<Option<Box<dyn FnMut()>>>, reopen: Cell<Option<Box<dyn FnMut()>>>, app_menu_action: Cell<Option<Box<dyn FnMut(&dyn Action)>>>, will_open_app_menu: Cell<Option<Box<dyn FnMut()>>>, validate_app_menu_command: Cell<Option<Box<dyn FnMut(&dyn Action) -> bool>>>, keyboard_layout_change: Cell<Option<Box<dyn FnMut()>>>,} impl WindowsPlatformState { fn new(directx_devices: Option<DirectXDevices>) -> Self { let callbacks = PlatformCallbacks::default(); let jump_list = JumpList::new(); let current_cursor = load_cursor(CursorStyle::Arrow); Self { callbacks, jump_list: RefCell::new(jump_list), current_cursor: Cell::new(current_cursor), directx_devices: RefCell::new(directx_devices), menus: RefCell::new(Vec::new()), } }} impl WindowsPlatform { pub fn new(headless: bool) -> Result<Self> { unsafe { OleInitialize(None).context("unable to initialize Windows OLE")?; } let (directx_devices, text_system, direct_write_text_system) = if !headless { let devices = DirectXDevices::new().context("Creating DirectX devices")?; let dw_text_system = Arc::new( DirectWriteTextSystem::new(&devices) .context("Error creating DirectWriteTextSystem")?, ); ( Some(devices), dw_text_system.clone() as Arc<dyn PlatformTextSystem>, Some(dw_text_system), ) } else { ( None, Arc::new(gpui::NoopTextSystem::new()) as Arc<dyn PlatformTextSystem>, None, ) }; let (main_sender, main_receiver) = PriorityQueueReceiver::new(); let validation_number = if usize::BITS == 64 { rand::random::<u64>() as usize } else { rand::random::<u32>() as usize }; let raw_window_handles = Arc::new(RwLock::new(SmallVec::new())); register_platform_window_class(); let mut context = PlatformWindowCreateContext { inner: None, raw_window_handles: Arc::downgrade(&raw_window_handles), validation_number, main_sender: Some(main_sender), main_receiver: Some(main_receiver), directx_devices, dispatcher: None, }; let result = unsafe { CreateWindowExW( WINDOW_EX_STYLE(0), PLATFORM_WINDOW_CLASS_NAME, None, WINDOW_STYLE(0), 0, 0, 0, 0, Some(HWND_MESSAGE), None, None, Some(&raw const context as *const _), ) }; let inner = context .inner .take() .context("CreateWindowExW did not run correctly")??; let dispatcher = context .dispatcher .take() .context("CreateWindowExW did not run correctly")?; let handle = result?; let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION) .is_ok_and(|value| value == "true" || value == "1"); let background_executor = BackgroundExecutor::new(dispatcher.clone()); let foreground_executor = ForegroundExecutor::new(dispatcher); let drop_target_helper: Option<IDropTargetHelper> = if !headless { Some(unsafe { CoCreateInstance(&CLSID_DragDropHelper, None, CLSCTX_INPROC_SERVER) .context("Error creating drop target helper.")? }) } else { None }; let icon = if !headless { load_icon().unwrap_or_default() } else { HICON::default() }; Ok(Self { inner, handle, raw_window_handles, headless, icon, background_executor, foreground_executor, text_system, direct_write_text_system, disable_direct_composition, drop_target_helper, invalidate_devices: Arc::new(AtomicBool::new(false)), }) } pub(crate) fn window_from_hwnd(&self, hwnd: HWND) -> Option<Rc<WindowsWindowInner>> { self.raw_window_handles .read() .iter() .find(|entry| entry.as_raw() == hwnd) .and_then(|hwnd| window_from_hwnd(hwnd.as_raw())) } #[inline] fn post_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) { self.raw_window_handles .read() .iter() .for_each(|handle| unsafe { PostMessageW(Some(handle.as_raw()), message, wparam, lparam).log_err(); }); } fn generate_creation_info(&self) -> WindowCreationInfo { WindowCreationInfo { icon: self.icon, executor: self.foreground_executor.clone(), current_cursor: self.inner.state.current_cursor.get(), drop_target_helper: self.drop_target_helper.clone().unwrap(), validation_number: self.inner.validation_number, main_receiver: self.inner.main_receiver.clone(), platform_window_handle: self.handle, disable_direct_composition: self.disable_direct_composition, directx_devices: self.inner.state.directx_devices.borrow().clone().unwrap(), invalidate_devices: self.invalidate_devices.clone(), } } 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); } }); self.inner.state.jump_list.borrow_mut().dock_menus = actions; let borrow = self.inner.state.jump_list.borrow(); let dock_menus = borrow .dock_menus .iter() .map(|menu| (menu.name.clone(), menu.description.clone())) .collect::<Vec<_>>(); let recent_workspaces = borrow.recent_workspaces.clone(); self.background_executor .spawn(async move { update_jump_list(&recent_workspaces, &dock_menus).log_err(); }) .detach(); } fn update_jump_list( &self, menus: Vec<MenuItem>, entries: Vec<SmallVec<[PathBuf; 2]>>, ) -> Task<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 jump_list = self.inner.state.jump_list.borrow_mut(); jump_list.dock_menus = actions; jump_list.recent_workspaces = entries.into(); let dock_menus = jump_list .dock_menus .iter() .map(|menu| (menu.name.clone(), menu.description.clone())) .collect::<Vec<_>>(); let recent_workspaces = jump_list.recent_workspaces.clone(); self.background_executor.spawn(async move { update_jump_list(&recent_workspaces, &dock_menus) .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.as_raw() == active_window_hwnd) .map(|hwnd| hwnd.as_raw()) } fn begin_vsync_thread(&self) { let Some(directx_devices) = self.inner.state.directx_devices.borrow().clone() else { return; }; let Some(direct_write_text_system) = &self.direct_write_text_system else { return; }; let mut directx_device = directx_devices; let platform_window: SafeHwnd = self.handle.into(); let validation_number = self.inner.validation_number; let all_windows = Arc::downgrade(&self.raw_window_handles); let text_system = Arc::downgrade(direct_write_text_system); let invalidate_devices = self.invalidate_devices.clone(); std::thread::Builder::new() .name("VSyncProvider".to_owned()) .spawn(move || { let vsync_provider = VSyncProvider::new(); loop { vsync_provider.wait_for_vsync(); if check_device_lost(&directx_device.device) || invalidate_devices.fetch_and(false, Ordering::Acquire) { if let Err(err) = handle_gpu_device_lost( &mut directx_device, platform_window.as_raw(), validation_number, &all_windows, &text_system, ) { panic!("Device lost: {err}"); } } let Some(all_windows) = all_windows.upgrade() else { break; }; for hwnd in all_windows.read().iter() { unsafe { let _ = RedrawWindow(Some(hwnd.as_raw()), None, None, RDW_INVALIDATE); } } } }) .unwrap(); }} fn translate_accelerator(msg: &MSG) -> Option<()> { if msg.message != WM_KEYDOWN && msg.message != WM_SYSKEYDOWN { return None; } let result = unsafe { SendMessageW( msg.hwnd, WM_GPUI_KEYDOWN, Some(msg.wParam), Some(msg.lParam), ) }; (result.0 == 0).then_some(())} 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 keyboard_mapper(&self) -> Rc<dyn PlatformKeyboardMapper> { Rc::new(WindowsKeyboardMapper::new()) } fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>) { self.inner .state .callbacks .keyboard_layout_change .set(Some(callback)); } fn on_thermal_state_change(&self, _callback: Box<dyn FnMut()>) {} fn thermal_state(&self) -> ThermalState { ThermalState::Nominal } fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) { on_finish_launching(); if !self.headless { self.begin_vsync_thread(); } let mut msg = MSG::default(); unsafe { while GetMessageW(&mut msg, None, 0, 0).as_bool() { if translate_accelerator(&msg).is_none() { _ = TranslateMessage(&msg); DispatchMessageW(&msg); } } } self.inner .with_callback(|callbacks| &callbacks.quit, |callback| callback()); } fn quit(&self) { self.foreground_executor() .spawn(async { unsafe { PostQuitMessage(0) } }) .detach(); } fn restart(&self, binary_path: Option<PathBuf>) { let pid = std::process::id(); let Some(app_path) = binary_path.or(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(), ); // Defer spawning to the foreground executor so it runs after the // current `AppCell` borrow is released. On Windows, `Command::spawn()` // can pump the Win32 message loop (via `CreateProcessW`), which // re-enters message handling possibly resulting in another mutable // borrow of the `AppCell` ending up with a double borrow panic self.foreground_executor .spawn(async move { #[allow( clippy::disallowed_methods, reason = "We are restarting ourselves, using std command thus is fine" )] let restart_process = ::util::command::new_std_command(::util::shell::get_windows_system_shell()) .arg("-command") .arg(script) .spawn(); match restart_process { Ok(_) => unsafe { PostQuitMessage(0) }, Err(e) => log::error!("failed to spawn restart script: {:?}", e), } }) .detach(); } 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>) } #[cfg(feature = "screen-capture")] fn is_screen_capture_supported(&self) -> bool { true } #[cfg(feature = "screen-capture")] fn screen_capture_sources( &self, ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> { gpui::scap_screen_capture::scap_screen_sources(&self.foreground_executor)Lines 1–500 of 1361. Load more
use std::{ cell::{Cell, RefCell}, ffi::OsStr, path::{Path, PathBuf}, rc::{Rc, Weak}, sync::{ Arc, atomic::{AtomicBool, Ordering}, }, }; use ::util::{ResultExt, paths::SanitizedPath}; use anyhow::{Context as _, Result, anyhow}; use futures::channel::oneshot::{self, Receiver}; use itertools::Itertools; use parking_lot::RwLock; use smallvec::SmallVec; use windows::{ UI::ViewManagement::UISettings, Win32::{ Foundation::*, Graphics::{Direct3D11::ID3D11Device, Gdi::*}, Security::Credentials::*, System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*}, UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*}, }, core::*, }; use crate::*; use gpui::*; pub struct WindowsPlatform { inner: Rc<WindowsPlatformInner>, raw_window_handles: Arc<RwLock<SmallVec<[SafeHwnd; 4]>>>, // The below members will never change throughout the entire lifecycle of the app. headless: bool, icon: HICON, background_executor: BackgroundExecutor, foreground_executor: ForegroundExecutor, text_system: Arc<dyn PlatformTextSystem>, direct_write_text_system: Option<Arc<DirectWriteTextSystem>>, drop_target_helper: Option<IDropTargetHelper>, /// Flag to instruct the `VSyncProvider` thread to invalidate the directx devices /// as resizing them has failed, causing us to have lost at least the render target. invalidate_devices: Arc<AtomicBool>, handle: HWND, disable_direct_composition: bool, } struct WindowsPlatformInner { state: WindowsPlatformState, raw_window_handles: std::sync::Weak<RwLock<SmallVec<[SafeHwnd; 4]>>>, // The below members will never change throughout the entire lifecycle of the app. validation_number: usize, main_receiver: PriorityQueueReceiver<RunnableVariant>, dispatcher: Arc<WindowsDispatcher>, } pub(crate) struct WindowsPlatformState { callbacks: PlatformCallbacks, menus: RefCell<Vec<OwnedMenu>>, jump_list: RefCell<JumpList>, // NOTE: standard cursor handles don't need to close. pub(crate) current_cursor: Cell<Option<HCURSOR>>, directx_devices: RefCell<Option<DirectXDevices>>, } #[derive(Default)] struct PlatformCallbacks { open_urls: Cell<Option<Box<dyn FnMut(Vec<String>)>>>, quit: Cell<Option<Box<dyn FnMut()>>>, reopen: Cell<Option<Box<dyn FnMut()>>>, app_menu_action: Cell<Option<Box<dyn FnMut(&dyn Action)>>>, will_open_app_menu: Cell<Option<Box<dyn FnMut()>>>, validate_app_menu_command: Cell<Option<Box<dyn FnMut(&dyn Action) -> bool>>>, keyboard_layout_change: Cell<Option<Box<dyn FnMut()>>>, } impl WindowsPlatformState { fn new(directx_devices: Option<DirectXDevices>) -> Self { let callbacks = PlatformCallbacks::default(); let jump_list = JumpList::new(); let current_cursor = load_cursor(CursorStyle::Arrow); Self { callbacks, jump_list: RefCell::new(jump_list), current_cursor: Cell::new(current_cursor), directx_devices: RefCell::new(directx_devices), menus: RefCell::new(Vec::new()), } } } impl WindowsPlatform { pub fn new(headless: bool) -> Result<Self> { unsafe { OleInitialize(None).context("unable to initialize Windows OLE")?; } let (directx_devices, text_system, direct_write_text_system) = if !headless { let devices = DirectXDevices::new().context("Creating DirectX devices")?; let dw_text_system = Arc::new( DirectWriteTextSystem::new(&devices) .context("Error creating DirectWriteTextSystem")?, ); ( Some(devices), dw_text_system.clone() as Arc<dyn PlatformTextSystem>, Some(dw_text_system), ) } else { ( None, Arc::new(gpui::NoopTextSystem::new()) as Arc<dyn PlatformTextSystem>, None, ) }; let (main_sender, main_receiver) = PriorityQueueReceiver::new(); let validation_number = if usize::BITS == 64 { rand::random::<u64>() as usize } else { rand::random::<u32>() as usize }; let raw_window_handles = Arc::new(RwLock::new(SmallVec::new())); register_platform_window_class(); let mut context = PlatformWindowCreateContext { inner: None, raw_window_handles: Arc::downgrade(&raw_window_handles), validation_number, main_sender: Some(main_sender), main_receiver: Some(main_receiver), directx_devices, dispatcher: None, }; let result = unsafe { CreateWindowExW( WINDOW_EX_STYLE(0), PLATFORM_WINDOW_CLASS_NAME, None, WINDOW_STYLE(0), 0, 0, 0, 0, Some(HWND_MESSAGE), None, None, Some(&raw const context as *const _), ) }; let inner = context .inner .take() .context("CreateWindowExW did not run correctly")??; let dispatcher = context .dispatcher .take() .context("CreateWindowExW did not run correctly")?; let handle = result?; let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION) .is_ok_and(|value| value == "true" || value == "1"); let background_executor = BackgroundExecutor::new(dispatcher.clone()); let foreground_executor = ForegroundExecutor::new(dispatcher); let drop_target_helper: Option<IDropTargetHelper> = if !headless { Some(unsafe { CoCreateInstance(&CLSID_DragDropHelper, None, CLSCTX_INPROC_SERVER) .context("Error creating drop target helper.")? }) } else { None }; let icon = if !headless { load_icon().unwrap_or_default() } else { HICON::default() }; Ok(Self { inner, handle, raw_window_handles, headless, icon, background_executor, foreground_executor, text_system, direct_write_text_system, disable_direct_composition, drop_target_helper, invalidate_devices: Arc::new(AtomicBool::new(false)), }) } pub(crate) fn window_from_hwnd(&self, hwnd: HWND) -> Option<Rc<WindowsWindowInner>> { self.raw_window_handles .read() .iter() .find(|entry| entry.as_raw() == hwnd) .and_then(|hwnd| window_from_hwnd(hwnd.as_raw())) } #[inline] fn post_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) { self.raw_window_handles .read() .iter() .for_each(|handle| unsafe { PostMessageW(Some(handle.as_raw()), message, wparam, lparam).log_err(); }); } fn generate_creation_info(&self) -> WindowCreationInfo { WindowCreationInfo { icon: self.icon, executor: self.foreground_executor.clone(), current_cursor: self.inner.state.current_cursor.get(), drop_target_helper: self.drop_target_helper.clone().unwrap(), validation_number: self.inner.validation_number, main_receiver: self.inner.main_receiver.clone(), platform_window_handle: self.handle, disable_direct_composition: self.disable_direct_composition, directx_devices: self.inner.state.directx_devices.borrow().clone().unwrap(), invalidate_devices: self.invalidate_devices.clone(), } } 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); } }); self.inner.state.jump_list.borrow_mut().dock_menus = actions; let borrow = self.inner.state.jump_list.borrow(); let dock_menus = borrow .dock_menus .iter() .map(|menu| (menu.name.clone(), menu.description.clone())) .collect::<Vec<_>>(); let recent_workspaces = borrow.recent_workspaces.clone(); self.background_executor .spawn(async move { update_jump_list(&recent_workspaces, &dock_menus).log_err(); }) .detach(); } fn update_jump_list( &self, menus: Vec<MenuItem>, entries: Vec<SmallVec<[PathBuf; 2]>>, ) -> Task<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 jump_list = self.inner.state.jump_list.borrow_mut(); jump_list.dock_menus = actions; jump_list.recent_workspaces = entries.into(); let dock_menus = jump_list .dock_menus .iter() .map(|menu| (menu.name.clone(), menu.description.clone())) .collect::<Vec<_>>(); let recent_workspaces = jump_list.recent_workspaces.clone(); self.background_executor.spawn(async move { update_jump_list(&recent_workspaces, &dock_menus) .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.as_raw() == active_window_hwnd) .map(|hwnd| hwnd.as_raw()) } fn begin_vsync_thread(&self) { let Some(directx_devices) = self.inner.state.directx_devices.borrow().clone() else { return; }; let Some(direct_write_text_system) = &self.direct_write_text_system else { return; }; let mut directx_device = directx_devices; let platform_window: SafeHwnd = self.handle.into(); let validation_number = self.inner.validation_number; let all_windows = Arc::downgrade(&self.raw_window_handles); let text_system = Arc::downgrade(direct_write_text_system); let invalidate_devices = self.invalidate_devices.clone(); std::thread::Builder::new() .name("VSyncProvider".to_owned()) .spawn(move || { let vsync_provider = VSyncProvider::new(); loop { vsync_provider.wait_for_vsync(); if check_device_lost(&directx_device.device) || invalidate_devices.fetch_and(false, Ordering::Acquire) { if let Err(err) = handle_gpu_device_lost( &mut directx_device, platform_window.as_raw(), validation_number, &all_windows, &text_system, ) { panic!("Device lost: {err}"); } } let Some(all_windows) = all_windows.upgrade() else { break; }; for hwnd in all_windows.read().iter() { unsafe { let _ = RedrawWindow(Some(hwnd.as_raw()), None, None, RDW_INVALIDATE); } } } }) .unwrap(); } } fn translate_accelerator(msg: &MSG) -> Option<()> { if msg.message != WM_KEYDOWN && msg.message != WM_SYSKEYDOWN { return None; } let result = unsafe { SendMessageW( msg.hwnd, WM_GPUI_KEYDOWN, Some(msg.wParam), Some(msg.lParam), ) }; (result.0 == 0).then_some(()) } 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 keyboard_mapper(&self) -> Rc<dyn PlatformKeyboardMapper> { Rc::new(WindowsKeyboardMapper::new()) } fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>) { self.inner .state .callbacks .keyboard_layout_change .set(Some(callback)); } fn on_thermal_state_change(&self, _callback: Box<dyn FnMut()>) {} fn thermal_state(&self) -> ThermalState { ThermalState::Nominal } fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) { on_finish_launching(); if !self.headless { self.begin_vsync_thread(); } let mut msg = MSG::default(); unsafe { while GetMessageW(&mut msg, None, 0, 0).as_bool() { if translate_accelerator(&msg).is_none() { _ = TranslateMessage(&msg); DispatchMessageW(&msg); } } } self.inner .with_callback(|callbacks| &callbacks.quit, |callback| callback()); } fn quit(&self) { self.foreground_executor() .spawn(async { unsafe { PostQuitMessage(0) } }) .detach(); } fn restart(&self, binary_path: Option<PathBuf>) { let pid = std::process::id(); let Some(app_path) = binary_path.or(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(), ); // Defer spawning to the foreground executor so it runs after the // current `AppCell` borrow is released. On Windows, `Command::spawn()` // can pump the Win32 message loop (via `CreateProcessW`), which // re-enters message handling possibly resulting in another mutable // borrow of the `AppCell` ending up with a double borrow panic self.foreground_executor .spawn(async move { #[allow( clippy::disallowed_methods, reason = "We are restarting ourselves, using std command thus is fine" )] let restart_process = ::util::command::new_std_command(::util::shell::get_windows_system_shell()) .arg("-command") .arg(script) .spawn(); match restart_process { Ok(_) => unsafe { PostQuitMessage(0) }, Err(e) => log::error!("failed to spawn restart script: {:?}", e), } }) .detach(); } 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>) } #[cfg(feature = "screen-capture")] fn is_screen_capture_supported(&self) -> bool { true } #[cfg(feature = "screen-capture")] fn screen_capture_sources( &self, ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> { gpui::scap_screen_capture::scap_screen_sources(&self.foreground_executor)