From 5cbc0e7f24242b28471ec2539898dff1fa934fc9 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 14:57:24 +0800 Subject: [PATCH 01/39] build target add --- rust-toolchain.toml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f71bbee6be10c..09697a34b2042 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,11 @@ [toolchain] channel = "1.76" profile = "minimal" -components = [ "rustfmt", "clippy" ] -targets = [ "x86_64-apple-darwin", "aarch64-apple-darwin", "x86_64-unknown-linux-gnu", "wasm32-wasi" ] +components = ["rustfmt", "clippy"] +targets = [ + "x86_64-apple-darwin", + "aarch64-apple-darwin", + "x86_64-unknown-linux-gnu", + "x86_64-pc-windows-msvc", + "wasm32-wasi", +] From ebf3943d211e3e6be0429807d0228123e13cb854 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 15:34:42 +0800 Subject: [PATCH 02/39] terminal fix --- Cargo.lock | 5 ++--- crates/terminal/Cargo.toml | 3 ++- crates/terminal/src/terminal.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ba0cd82ac274..a9062a2406320 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,9 +113,8 @@ dependencies = [ [[package]] name = "alacritty_terminal" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ceabf6fc76511f616ca216b51398a2511f19ba9f71bcbd977999edff1b0d1" +version = "0.22.1-dev" +source = "git+https://github.com/JunkuiZhang/alacritty?rev=5f5028be3b55092a19dc0a295e0007c37c30db1c#5f5028be3b55092a19dc0a295e0007c37c30db1c" dependencies = [ "base64 0.21.4", "bitflags 2.4.2", diff --git a/crates/terminal/Cargo.toml b/crates/terminal/Cargo.toml index 884b754aacbf6..cf81d0c57119f 100644 --- a/crates/terminal/Cargo.toml +++ b/crates/terminal/Cargo.toml @@ -11,7 +11,8 @@ doctest = false [dependencies] -alacritty_terminal = "0.22.0" +# alacritty_terminal = "0.22.0" +alacritty_terminal = { git = "https://github.com/JunkuiZhang/alacritty", rev = "5f5028be3b55092a19dc0a295e0007c37c30db1c" } anyhow.workspace = true collections.workspace = true dirs = "4.0.0" diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 342d4c6cc2086..45d9ef0234d1f 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -42,6 +42,8 @@ use task::TaskId; use terminal_settings::{AlternateScroll, Shell, TerminalBlink, TerminalSettings}; use theme::{ActiveTheme, Theme}; use util::truncate_and_trailoff; +#[cfg(windows)] +use windows_sys::Win32::{Foundation::HANDLE, System::Threading::GetProcessId}; use std::{ cmp::{self, min}, @@ -400,9 +402,8 @@ impl TerminalBuilder { #[cfg(unix)] let (fd, shell_pid) = (pty.file().as_raw_fd(), pty.child().id()); - // todo("windows") #[cfg(windows)] - let (fd, shell_pid) = (-1, 0); + let (fd, shell_pid) = (pty.fd(), pty.pid()); //And connect them together let event_loop = EventLoop::new( @@ -668,7 +669,6 @@ impl Terminal { fn update_process_info(&mut self) -> bool { #[cfg(unix)] let mut pid = unsafe { libc::tcgetpgrp(self.shell_fd as i32) }; - // todo("windows") #[cfg(windows)] let mut pid = unsafe { windows::Win32::System::Threading::GetCurrentProcessId() } as i32; if pid < 0 { From d4daee37e1bfea8e838ff2f2b86c0d43efa0fdea Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 16:15:18 +0800 Subject: [PATCH 03/39] rename to cross_platfrom --- crates/gpui/src/platform.rs | 5 ++++- .../src/platform/{blade.rs => cross_platform.rs} | 4 ++++ .../{blade => cross_platform}/blade_atlas.rs | 0 .../{blade => cross_platform}/blade_belt.rs | 0 .../{blade => cross_platform}/blade_renderer.rs | 0 .../{blade => cross_platform}/shaders.wgsl | 0 .../{linux => cross_platform}/text_system.rs | 14 +++++++------- 7 files changed, 15 insertions(+), 8 deletions(-) rename crates/gpui/src/platform/{blade.rs => cross_platform.rs} (55%) rename crates/gpui/src/platform/{blade => cross_platform}/blade_atlas.rs (100%) rename crates/gpui/src/platform/{blade => cross_platform}/blade_belt.rs (100%) rename crates/gpui/src/platform/{blade => cross_platform}/blade_renderer.rs (100%) rename crates/gpui/src/platform/{blade => cross_platform}/shaders.wgsl (100%) rename crates/gpui/src/platform/{linux => cross_platform}/text_system.rs (98%) diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 8222b88fe1ea6..530629294a160 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -12,8 +12,11 @@ mod linux; #[cfg(target_os = "macos")] mod mac; +#[cfg(target_os = "windows")] +mod windows; + #[cfg(any(target_os = "linux", target_os = "windows", feature = "macos-blade"))] -mod blade; +mod cross_platform; #[cfg(any(test, feature = "test-support"))] mod test; diff --git a/crates/gpui/src/platform/blade.rs b/crates/gpui/src/platform/cross_platform.rs similarity index 55% rename from crates/gpui/src/platform/blade.rs rename to crates/gpui/src/platform/cross_platform.rs index 830f69daedceb..f3cfb7eb6c169 100644 --- a/crates/gpui/src/platform/blade.rs +++ b/crates/gpui/src/platform/cross_platform.rs @@ -1,8 +1,12 @@ mod blade_atlas; mod blade_belt; mod blade_renderer; +#[cfg(not(feature = "macos-blade"))] +mod text_system; pub(crate) use blade_atlas::*; pub(crate) use blade_renderer::*; use blade_belt::*; +#[cfg(not(feature = "macos-blade"))] +use text_system::*; diff --git a/crates/gpui/src/platform/blade/blade_atlas.rs b/crates/gpui/src/platform/cross_platform/blade_atlas.rs similarity index 100% rename from crates/gpui/src/platform/blade/blade_atlas.rs rename to crates/gpui/src/platform/cross_platform/blade_atlas.rs diff --git a/crates/gpui/src/platform/blade/blade_belt.rs b/crates/gpui/src/platform/cross_platform/blade_belt.rs similarity index 100% rename from crates/gpui/src/platform/blade/blade_belt.rs rename to crates/gpui/src/platform/cross_platform/blade_belt.rs diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/cross_platform/blade_renderer.rs similarity index 100% rename from crates/gpui/src/platform/blade/blade_renderer.rs rename to crates/gpui/src/platform/cross_platform/blade_renderer.rs diff --git a/crates/gpui/src/platform/blade/shaders.wgsl b/crates/gpui/src/platform/cross_platform/shaders.wgsl similarity index 100% rename from crates/gpui/src/platform/blade/shaders.wgsl rename to crates/gpui/src/platform/cross_platform/shaders.wgsl diff --git a/crates/gpui/src/platform/linux/text_system.rs b/crates/gpui/src/platform/cross_platform/text_system.rs similarity index 98% rename from crates/gpui/src/platform/linux/text_system.rs rename to crates/gpui/src/platform/cross_platform/text_system.rs index 70caa7175b09f..9718a37b361c3 100644 --- a/crates/gpui/src/platform/linux/text_system.rs +++ b/crates/gpui/src/platform/cross_platform/text_system.rs @@ -19,9 +19,9 @@ use pathfinder_geometry::{ use smallvec::SmallVec; use std::{borrow::Cow, sync::Arc}; -pub(crate) struct LinuxTextSystem(RwLock); +pub(crate) struct CosmicTextSystem(RwLock); -struct LinuxTextSystemState { +struct CosmicTextSystemState { swash_cache: SwashCache, font_system: FontSystem, fonts: Vec>, @@ -30,14 +30,14 @@ struct LinuxTextSystemState { postscript_names_by_font_id: HashMap, } -impl LinuxTextSystem { +impl CosmicTextSystem { pub(crate) fn new() -> Self { let mut font_system = FontSystem::new(); // todo(linux) make font loading non-blocking font_system.db_mut().load_system_fonts(); - Self(RwLock::new(LinuxTextSystemState { + Self(RwLock::new(CosmicTextSystemState { font_system, swash_cache: SwashCache::new(), fonts: Vec::new(), @@ -49,14 +49,14 @@ impl LinuxTextSystem { } } -impl Default for LinuxTextSystem { +impl Default for CosmicTextSystem { fn default() -> Self { Self::new() } } #[allow(unused)] -impl PlatformTextSystem for LinuxTextSystem { +impl PlatformTextSystem for CosmicTextSystem { fn add_fonts(&self, fonts: Vec>) -> Result<()> { self.0.write().add_fonts(fonts) } @@ -200,7 +200,7 @@ impl PlatformTextSystem for LinuxTextSystem { } } -impl LinuxTextSystemState { +impl CosmicTextSystemState { #[profiling::function] fn add_fonts(&mut self, fonts: Vec>) -> Result<()> { let db = self.font_system.db_mut(); From a8e82250998409901bc5ead48abb751217ef6675 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 16:33:36 +0800 Subject: [PATCH 04/39] basic impl --- Cargo.lock | 62 +- crates/gpui/Cargo.toml | 54 +- crates/gpui/assets/windows/manifest.xml | 11 + crates/gpui/build.rs | 16 + crates/gpui/src/platform/cross_platform.rs | 2 +- crates/gpui/src/platform/windows.rs | 18 +- crates/gpui/src/platform/windows/constants.rs | 53 + .../gpui/src/platform/windows/dispatcher.rs | 220 ++-- crates/gpui/src/platform/windows/display.rs | 56 +- crates/gpui/src/platform/windows/events.rs | 430 +++++++ crates/gpui/src/platform/windows/monitor.rs | 56 + crates/gpui/src/platform/windows/platform.rs | 882 +++++++++++--- crates/gpui/src/platform/windows/utils.rs | 117 ++ crates/gpui/src/platform/windows/window.rs | 1084 +++++++++++------ crates/terminal/src/terminal.rs | 1 + crates/zed/build.rs | 4 + 16 files changed, 2378 insertions(+), 688 deletions(-) create mode 100644 crates/gpui/assets/windows/manifest.xml create mode 100644 crates/gpui/src/platform/windows/constants.rs create mode 100644 crates/gpui/src/platform/windows/events.rs create mode 100644 crates/gpui/src/platform/windows/monitor.rs create mode 100644 crates/gpui/src/platform/windows/utils.rs diff --git a/Cargo.lock b/Cargo.lock index a9062a2406320..c9983368be27b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4379,7 +4379,8 @@ dependencies = [ "wayland-client", "wayland-cursor", "wayland-protocols", - "windows 0.53.0", + "windows 0.54.0", + "winresource", "xcb", "xkbcommon", ] @@ -10050,6 +10051,18 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", +] + [[package]] name = "toml" version = "0.8.10" @@ -10089,6 +10102,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.5.15", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", "toml_datetime", "winnow 0.5.15", ] @@ -11974,24 +12002,48 @@ dependencies = [ [[package]] name = "windows" -version = "0.53.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" dependencies = [ "windows-core", + "windows-implement", + "windows-interface", "windows-targets 0.52.4", ] [[package]] name = "windows-core" -version = "0.53.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" dependencies = [ "windows-result", "windows-targets 0.52.4", ] +[[package]] +name = "windows-implement" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942ac266be9249c84ca862f0a164a39533dc2f6f33dc98ec89c8da99b82ea0bd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "windows-interface" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da33557140a288fae4e1d5f8873aaf9eb6613a9cf82c3e070223ff177f598b60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "windows-result" version = "0.1.0" diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index c917f92cbd5aa..3feb4c2f3078c 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -105,18 +105,62 @@ cosmic-text = "0.10.0" open = "5.0.1" ashpd = "0.7.0" xcb = { version = "1.3", features = ["as-raw-xcb-connection", "randr", "xkb"] } -wayland-client= { version = "0.31.2" } +wayland-client = { version = "0.31.2" } wayland-cursor = "0.31.1" -wayland-protocols = { version = "0.31.2", features = ["client", "staging", "unstable"] } +wayland-protocols = { version = "0.31.2", features = [ + "client", + "staging", + "unstable", +] } wayland-backend = { version = "0.3.3", features = ["client_system"] } xkbcommon = { version = "0.7", features = ["wayland", "x11"] } as-raw-xcb-connection = "1" calloop = "0.12.4" calloop-wayland-source = "0.2.0" -oo7 = "0.3.0" +#TODO: use these on all platforms +blade-graphics.workspace = true +blade-macros.workspace = true +blade-rwh.workspace = true +bytemuck = "1" +cosmic-text = "0.10.0" + +[target.'cfg(target_os = "windows")'.dependencies] +blade-graphics.workspace = true +blade-macros.workspace = true +blade-rwh.workspace = true +bytemuck = "1" +cosmic-text = "0.10.0" +flume = "0.11" +windows = { version = "0.54", features = [ + "implement", + "Wdk_System_SystemServices", + "Win32_Foundation", + "Win32_Globalization", + "Win32_Graphics_DirectWrite", + "Win32_Graphics_Gdi", + "Win32_Security_Credentials", + "Win32_System_Com", + "Win32_System_Com_StructuredStorage", + "Win32_System_DataExchange", + "Win32_System_LibraryLoader", + "Win32_System_Memory", + "Win32_System_Ole", + "Win32_System_SystemInformation", + "Win32_System_SystemServices", + "Win32_System_Time", + "Win32_System_Threading", + "Win32_UI_Accessibility", + "Win32_UI_Controls", + "Win32_UI_HiDpi", + "Win32_UI_Input_Ime", + "Win32_UI_Input_KeyboardAndMouse", + "Win32_UI_Input_Pointer", + "Win32_UI_Shell", + "Win32_UI_WindowsAndMessaging", +] } -[target.'cfg(windows)'.dependencies] -windows.workspace = true +[target.'cfg(target_os = "windows")'.build-dependencies] +winresource = "0.1" [[example]] name = "hello_world" diff --git a/crates/gpui/assets/windows/manifest.xml b/crates/gpui/assets/windows/manifest.xml new file mode 100644 index 0000000000000..ac30a368ae92a --- /dev/null +++ b/crates/gpui/assets/windows/manifest.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index 8f63787c8bb1c..8473547730ce5 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -21,6 +21,22 @@ fn main() { #[cfg(all(target_os = "macos", not(feature = "macos-blade")))] #[cfg(not(feature = "runtime_shaders"))] compile_metal_shaders(&header_path); + + // We are using Windows Visita+, right..? + if cfg!(target_os = "windows") { + println!("cargo:rerun-if-changed=assets/windows/manifest.xml"); + let mut res = winresource::WindowsResource::new(); + let manifest_path = std::env::current_dir() + .unwrap() + .join("assets") + .join("windows") + .join("manifest.xml"); + res.set_manifest_file(manifest_path.to_str().unwrap()); + if let Err(e) = res.compile() { + eprintln!("{}", e); + std::process::exit(1); + } + } } fn generate_dispatch_bindings() { diff --git a/crates/gpui/src/platform/cross_platform.rs b/crates/gpui/src/platform/cross_platform.rs index f3cfb7eb6c169..4f436d5e80d3a 100644 --- a/crates/gpui/src/platform/cross_platform.rs +++ b/crates/gpui/src/platform/cross_platform.rs @@ -9,4 +9,4 @@ pub(crate) use blade_renderer::*; use blade_belt::*; #[cfg(not(feature = "macos-blade"))] -use text_system::*; +pub(crate) use text_system::*; diff --git a/crates/gpui/src/platform/windows.rs b/crates/gpui/src/platform/windows.rs index 4347b9169ad0e..719343f20695e 100644 --- a/crates/gpui/src/platform/windows.rs +++ b/crates/gpui/src/platform/windows.rs @@ -1,13 +1,17 @@ +mod constants; mod dispatcher; mod display; +mod events; +mod monitor; mod platform; -mod text_system; -mod util; +mod utils; mod window; -pub(crate) use dispatcher::*; -pub(crate) use display::*; +pub use constants::*; +use dispatcher::*; +use display::*; +pub use events::*; +pub use monitor::*; pub(crate) use platform::*; -pub(crate) use text_system::*; -pub(crate) use util::*; -pub(crate) use window::*; +pub use utils::*; +pub use window::*; diff --git a/crates/gpui/src/platform/windows/constants.rs b/crates/gpui/src/platform/windows/constants.rs new file mode 100644 index 0000000000000..0030d17e5e3a9 --- /dev/null +++ b/crates/gpui/src/platform/windows/constants.rs @@ -0,0 +1,53 @@ +use windows::{ + core::PCWSTR, + Win32::UI::WindowsAndMessaging::{ + WINDOW_EX_STYLE, WINDOW_STYLE, WM_USER, WS_EX_ACCEPTFILES, WS_EX_LAYERED, WS_EX_NOACTIVATE, + WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_OVERLAPPEDWINDOW, + }, +}; + +// window class +pub const DISPATCH_WINDOW_CLASS: PCWSTR = windows::core::w!("ZedDispatch"); +pub const WINDOW_CLASS: PCWSTR = windows::core::w!("ZedWindow"); + +// window style +pub const DISPATCH_WINDOW_STYLE: WINDOW_STYLE = WS_OVERLAPPED; +pub const DISPATCH_WINDOW_EXSTYLE: WINDOW_EX_STYLE = WINDOW_EX_STYLE( + WS_EX_NOACTIVATE.0 | WS_EX_TRANSPARENT.0 | WS_EX_LAYERED.0 | WS_EX_TOOLWINDOW.0, +); +pub const WINODW_STYLE: WINDOW_STYLE = WS_OVERLAPPEDWINDOW; +pub const WINODW_EXTRA_EXSTYLE: WINDOW_EX_STYLE = WS_EX_ACCEPTFILES; + +// events +// Values in the range 0x0400 (the value of WM_USER) through 0x7FFF are +// available for message identifiers for private window classes. +pub const MAIN_DISPATCH: u32 = WM_USER + 1; +pub const WINDOW_CLOSE: u32 = WM_USER + 2; +pub const WINDOW_OPEN: u32 = WM_USER + 3; +pub const MENU_ACTIONS: u32 = WM_USER + 4; + +// mouse buttons +pub const MOUSE_MOVE_BUTTONS: [usize; 5] = [ + MOUSE_MOVE_LBUTTON, + MOUSE_MOVE_RBUTTON, + MOUSE_MOVE_MBUTTON, + MOUSE_MOVE_XBUTTON1, + MOUSE_MOVE_XBUTTON2, +]; +pub const MOUSE_MOVE_LBUTTON: usize = 0x0001; +pub const MOUSE_MOVE_RBUTTON: usize = 0x0002; +pub const MOUSE_MOVE_MBUTTON: usize = 0x0010; +pub const MOUSE_MOVE_XBUTTON1: usize = 0x0020; +pub const MOUSE_MOVE_XBUTTON2: usize = 0x0040; + +// text system +pub const STRING_MAX_LENGTH: usize = 128; +pub const CF_UNICODETEXT: u32 = 13; +pub const DRAGDROP_GET_COUNT: u32 = 0xFFFFFFFF; +pub const FILENAME_MAXLENGTH: usize = 256; + +// ACCEL structure fVirt +pub const ACCEL_FVIRTKEY: u8 = 0x01; +pub const ACCEL_FSHIFT: u8 = 0x04; +pub const ACCEL_FCONTROL: u8 = 0x08; +pub const ACCEL_FALT: u8 = 0x10; diff --git a/crates/gpui/src/platform/windows/dispatcher.rs b/crates/gpui/src/platform/windows/dispatcher.rs index 16fdcd2b85783..7ea843ded620c 100644 --- a/crates/gpui/src/platform/windows/dispatcher.rs +++ b/crates/gpui/src/platform/windows/dispatcher.rs @@ -1,123 +1,100 @@ -use std::{ - cmp::Ordering, - thread::{current, JoinHandle, ThreadId}, - time::{Duration, Instant}, -}; - +use crate::{log_windows_error, PlatformDispatcher, TaskLabel}; use async_task::Runnable; -use collections::BinaryHeap; -use flume::{RecvTimeoutError, Sender}; -use parking::Parker; +use parking::{Parker, Unparker}; use parking_lot::Mutex; -use windows::Win32::{Foundation::HANDLE, System::Threading::SetEvent}; - -use crate::{PlatformDispatcher, TaskLabel}; +use std::{panic, thread, time::Duration}; +use windows::Win32::{ + Foundation::{BOOLEAN, HANDLE, HWND, LPARAM, WPARAM}, + System::Threading::{ + CreateThreadpool, CreateThreadpoolWork, CreateTimerQueue, CreateTimerQueueTimer, + SetThreadpoolThreadMinimum, SubmitThreadpoolWork, PTP_CALLBACK_INSTANCE, PTP_POOL, + PTP_WORK, WT_EXECUTEONLYONCE, + }, + UI::WindowsAndMessaging::PostMessageW, +}; pub(crate) struct WindowsDispatcher { - background_sender: Sender<(Runnable, Option)>, - main_sender: Sender, - timer_sender: Sender<(Runnable, Duration)>, - background_threads: Vec>, - timer_thread: JoinHandle<()>, + dispatch_window: HWND, parker: Mutex, - main_thread_id: ThreadId, - event: HANDLE, + main_sender: flume::Sender, + main_thread_id: thread::ThreadId, + threadpool: PTP_POOL, + // timer queue maybe not accuracy + // https://www.virtualdub.org/blog2/entry_272.html + timer_queue: HANDLE, } impl WindowsDispatcher { - pub(crate) fn new(main_sender: Sender, event: HANDLE) -> Self { - let parker = Mutex::new(Parker::new()); - let (background_sender, background_receiver) = - flume::unbounded::<(Runnable, Option)>(); - let background_threads = (0..std::thread::available_parallelism() - .map(|i| i.get()) - .unwrap_or(1)) - .map(|_| { - let receiver = background_receiver.clone(); - std::thread::spawn(move || { - for (runnable, label) in receiver { - if let Some(label) = label { - log::debug!("TaskLabel: {label:?}"); - } - runnable.run(); - } - }) - }) - .collect::>(); - let (timer_sender, timer_receiver) = flume::unbounded::<(Runnable, Duration)>(); - let timer_thread = std::thread::spawn(move || { - let mut runnables = BinaryHeap::::new(); - let mut timeout_dur = None; - loop { - let recv = if let Some(dur) = timeout_dur { - match timer_receiver.recv_timeout(dur) { - Ok(recv) => Some(recv), - Err(RecvTimeoutError::Timeout) => None, - Err(RecvTimeoutError::Disconnected) => break, - } - } else if let Ok(recv) = timer_receiver.recv() { - Some(recv) - } else { - break; - }; - let now = Instant::now(); - if let Some((runnable, dur)) = recv { - runnables.push(RunnableAfter { - runnable, - instant: now + dur, - }); - while let Ok((runnable, dur)) = timer_receiver.try_recv() { - runnables.push(RunnableAfter { - runnable, - instant: now + dur, - }) - } - } - while runnables.peek().is_some_and(|entry| entry.instant <= now) { - runnables.pop().unwrap().runnable.run(); - } - timeout_dur = runnables.peek().map(|entry| entry.instant - now); - } - }); - let main_thread_id = current().id(); + pub fn new(main_sender: flume::Sender, dispatch_window_handle: HWND) -> Self { + let (threadpool, timer_queue) = dispatcher_init().expect("error init dispatcher"); + Self { - background_sender, + dispatch_window: dispatch_window_handle, + parker: Mutex::new(Parker::new()), main_sender, - timer_sender, - background_threads, - timer_thread, - parker, - main_thread_id, - event, + main_thread_id: thread::current().id(), + threadpool, + timer_queue, + } + } + + fn send_dispatch_message(&self) -> anyhow::Result<()> { + unsafe { + PostMessageW( + self.dispatch_window, + super::MAIN_DISPATCH, + WPARAM::default(), + LPARAM::default(), + ) + .inspect_err(log_windows_error)?; + } + Ok(()) + } + + fn dispatch_on_threadpool(&self, runnable: Runnable) -> anyhow::Result<()> { + unsafe { + let ptr = Box::into_raw(Box::new(runnable)); + let work = CreateThreadpoolWork(Some(background_runner), Some(ptr as _), None) + .inspect_err(log_windows_error)?; + SubmitThreadpoolWork(work); } + Ok(()) } } impl PlatformDispatcher for WindowsDispatcher { fn is_main_thread(&self) -> bool { - current().id() == self.main_thread_id + thread::current().id() == self.main_thread_id } - fn dispatch(&self, runnable: Runnable, label: Option) { - self.background_sender - .send((runnable, label)) - .inspect_err(|e| log::error!("Dispatch failed: {e}")) - .ok(); + fn dispatch(&self, runnable: Runnable, _: Option) { + // should panic ? + let _ = self.dispatch_on_threadpool(runnable); } fn dispatch_on_main_thread(&self, runnable: Runnable) { - self.main_sender - .send(runnable) - .inspect_err(|e| log::error!("Dispatch failed: {e}")) - .ok(); - unsafe { SetEvent(self.event) }.ok(); + self.main_sender.send(runnable).unwrap(); + if self.send_dispatch_message().is_err() { + self.send_dispatch_message().expect("Error sending message"); + } } - fn dispatch_after(&self, duration: std::time::Duration, runnable: Runnable) { - self.timer_sender - .send((runnable, duration)) - .inspect_err(|e| log::error!("Dispatch failed: {e}")) - .ok(); + fn dispatch_after(&self, duration: Duration, runnable: Runnable) { + // println!("Dispatched timed task {:#?}", duration); + unsafe { + let mut handle = std::mem::zeroed(); + let ptr = Box::into_raw(Box::new(runnable)); + CreateTimerQueueTimer( + &mut handle, + self.timer_queue, + Some(timer_runner), + Some(ptr as _), + duration.as_millis() as u32, + 0, + WT_EXECUTEONLYONCE, + ) + .expect("error create timer task"); + } } fn tick(&self, _background_only: bool) -> bool { @@ -125,35 +102,46 @@ impl PlatformDispatcher for WindowsDispatcher { } fn park(&self) { - self.parker.lock().park(); + self.parker.lock().park() } - fn unparker(&self) -> parking::Unparker { + fn unparker(&self) -> Unparker { self.parker.lock().unparker() } } -struct RunnableAfter { - runnable: Runnable, - instant: Instant, -} - -impl PartialEq for RunnableAfter { - fn eq(&self, other: &Self) -> bool { - self.instant == other.instant - } +fn dispatcher_init() -> anyhow::Result<(PTP_POOL, HANDLE)> { + let threadpool = unsafe { + let mut threadpool_handle = CreateThreadpool(None); + if threadpool_handle.0 == 0 { + log::error!("Windows error: {}", std::io::Error::last_os_error()); + threadpool_handle = CreateThreadpool(None); + if threadpool_handle.0 == 0 { + log::error!("Windows error: {}", std::io::Error::last_os_error()); + return anyhow::Result::Err(anyhow::anyhow!("Error init dispatcher")); + } + } + SetThreadpoolThreadMinimum(threadpool_handle, 1).inspect_err(log_windows_error)?; + threadpool_handle + }; + let timer_queue = unsafe { CreateTimerQueue().inspect_err(log_windows_error)? }; + Ok((threadpool, timer_queue)) } -impl Eq for RunnableAfter {} - -impl Ord for RunnableAfter { - fn cmp(&self, other: &Self) -> Ordering { - self.instant.cmp(&other.instant).reverse() +extern "system" fn background_runner( + _: PTP_CALLBACK_INSTANCE, + ptr: *mut std::ffi::c_void, + _: PTP_WORK, +) { + unsafe { + let runnable = Box::from_raw(ptr as *mut Runnable); + panic::catch_unwind(|| runnable.run()).expect("error running runnable"); } } -impl PartialOrd for RunnableAfter { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) +unsafe extern "system" fn timer_runner(ptr: *mut std::ffi::c_void, _: BOOLEAN) { + unsafe { + let runnable = Box::from_raw(ptr as *mut Runnable); + panic::catch_unwind(|| runnable.run()).expect("error running runnable"); } } diff --git a/crates/gpui/src/platform/windows/display.rs b/crates/gpui/src/platform/windows/display.rs index 448433b6fb10b..79d3e7d5539f4 100644 --- a/crates/gpui/src/platform/windows/display.rs +++ b/crates/gpui/src/platform/windows/display.rs @@ -1,36 +1,58 @@ -use anyhow::{anyhow, Result}; +use std::rc::Rc; + +use anyhow::Result; use uuid::Uuid; -use crate::{Bounds, DisplayId, GlobalPixels, PlatformDisplay, Point, Size}; +use crate::{available_monitors, Bounds, DisplayId, GlobalPixels, PlatformDisplay, Size}; #[derive(Debug)] -pub(crate) struct WindowsDisplay; +pub(crate) struct WindowsDisplay { + pub display_id: DisplayId, + bounds: Bounds, + uuid: Uuid, +} impl WindowsDisplay { - pub(crate) fn new() -> Self { - Self + pub(crate) fn new(display_id: DisplayId) -> Self { + let screen = available_monitors() + .into_iter() + .nth(display_id.0 as _) + .unwrap(); + + Self { + display_id, + bounds: Bounds { + origin: Default::default(), + size: Size { + width: GlobalPixels(screen.size().width as f32), + height: GlobalPixels(screen.size().height as f32), + }, + }, + uuid: Uuid::from_bytes([0; 16]), + } + } + + pub fn displays() -> Vec> { + available_monitors() + .into_iter() + .enumerate() + .map(|(id, _)| { + Rc::new(WindowsDisplay::new(DisplayId(id as _))) as Rc + }) + .collect() } } impl PlatformDisplay for WindowsDisplay { - // todo!("windows") fn id(&self) -> DisplayId { - DisplayId(1) + self.display_id } - // todo!("windows") fn uuid(&self) -> Result { - Err(anyhow!("not implemented yet.")) + Ok(self.uuid) } - // todo!("windows") fn bounds(&self) -> Bounds { - Bounds::new( - Point::new(0.0.into(), 0.0.into()), - Size { - width: 1920.0.into(), - height: 1280.0.into(), - }, - ) + self.bounds } } diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs new file mode 100644 index 0000000000000..6c1cae142affa --- /dev/null +++ b/crates/gpui/src/platform/windows/events.rs @@ -0,0 +1,430 @@ +use std::rc::Rc; + +use windows::{ + core::PCWSTR, + Win32::{ + Foundation::{HWND, LPARAM, LRESULT, WPARAM}, + Globalization::{WideCharToMultiByte, CP_UTF8}, + Graphics::Gdi::HBRUSH, + UI::{ + Input::KeyboardAndMouse::{ + VIRTUAL_KEY, VK_BACK, VK_CONTROL, VK_DELETE, VK_DOWN, VK_END, VK_ESCAPE, VK_F1, + VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, + VK_HOME, VK_LEFT, VK_LWIN, VK_MENU, VK_NEXT, VK_PRIOR, VK_RETURN, VK_RIGHT, + VK_RWIN, VK_SHIFT, VK_UP, + }, + WindowsAndMessaging::{ + CreateWindowExW, DefWindowProcW, RegisterClassExW, CS_DBLCLKS, CS_HREDRAW, + CS_VREDRAW, HCURSOR, HICON, HMENU, WINDOW_EX_STYLE, WINDOW_STYLE, WM_KEYDOWN, + WM_LBUTTONDBLCLK, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, + WM_MBUTTONUP, WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_XBUTTONDBLCLK, + WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSEXW, XBUTTON1, + }, + }, + }, +}; + +use crate::{ + get_module_handle, get_windowdata, hiword, loword, KeyDownEvent, KeyUpEvent, Keystroke, + Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, PlatformInput, + Point, ScrollDelta, ScrollWheelEvent, TouchPhase, WindowsPlatformInner, MOUSE_MOVE_BUTTONS, + MOUSE_MOVE_LBUTTON, MOUSE_MOVE_MBUTTON, MOUSE_MOVE_RBUTTON, MOUSE_MOVE_XBUTTON1, + MOUSE_MOVE_XBUTTON2, +}; + +struct DispatchWindowData(Rc); + +pub struct WindowsWinodwDataWrapper(pub Rc); + +pub trait WindowsWindowBase +where + Self: Sized, +{ + unsafe fn handle_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT; + + extern "system" fn event_runner( + handle: HWND, + message: u32, + wparam: WPARAM, + lparam: LPARAM, + ) -> LRESULT { + unsafe { + let ptr = get_windowdata(handle) as *const WindowsWinodwDataWrapper; + if ptr.is_null() { + return DefWindowProcW(handle, message, wparam, lparam); + } + let this = &*ptr; + this.0.handle_message(message, wparam, lparam) + } + } + + fn create( + window_class_name: PCWSTR, + style: WINDOW_STYLE, + exstyle: WINDOW_EX_STYLE, + x: Option, + y: Option, + width: Option, + height: Option, + menu_handle: Option, + title: Option, + ) -> HWND { + let window_class = WNDCLASSEXW { + cbSize: std::mem::size_of::() as u32, + style: CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, + // lpfnWndProc: runner, + lpfnWndProc: Some(Self::event_runner), + cbClsExtra: 0, + cbWndExtra: 0, + hInstance: get_module_handle().into(), + hIcon: HICON::default(), + hCursor: HCURSOR::default(), + hbrBackground: HBRUSH::default(), + lpszMenuName: PCWSTR::null(), + lpszClassName: window_class_name, + hIconSm: HICON(0), + }; + // we register windows class multuple times, so it will give an error + let _ = unsafe { RegisterClassExW(&window_class) }; + + let handle = unsafe { + CreateWindowExW( + exstyle, + window_class_name, + title.unwrap_or(PCWSTR::null()), + style, + x.unwrap_or(0), + y.unwrap_or(0), + width.unwrap_or(0), + height.unwrap_or(0), + HWND::default(), + menu_handle.unwrap_or(HMENU::default()), + get_module_handle(), + None, + ) + }; + if handle == HWND::default() { + panic!("Window create error: {}", std::io::Error::last_os_error()); + } + + handle + } +} + +pub fn parse_system_key( + message: u32, + wparam: WPARAM, + lparam: LPARAM, + modifiers: &mut Modifiers, +) -> Option { + let keydown = message == WM_KEYDOWN; + let mut logical_key = None; + match VIRTUAL_KEY(wparam.0 as _) { + VK_BACK => logical_key = Some("backspace".to_string()), + VK_ESCAPE => logical_key = Some("escape".to_string()), + VK_RETURN => logical_key = Some("enter".to_string()), + VK_UP => logical_key = Some("up".to_string()), + VK_DOWN => logical_key = Some("down".to_string()), + VK_LEFT => logical_key = Some("left".to_string()), + VK_RIGHT => logical_key = Some("right".to_string()), + VK_PRIOR => logical_key = Some("pageup".to_string()), + VK_NEXT => logical_key = Some("pagedown".to_string()), + VK_HOME => logical_key = Some("home".to_string()), + VK_END => logical_key = Some("end".to_string()), + VK_DELETE => logical_key = Some("delete".to_string()), + VK_F1 => logical_key = Some("f1".to_string()), + VK_F2 => logical_key = Some("f2".to_string()), + VK_F3 => logical_key = Some("f3".to_string()), + VK_F4 => logical_key = Some("f4".to_string()), + VK_F5 => logical_key = Some("f5".to_string()), + VK_F6 => logical_key = Some("f6".to_string()), + VK_F7 => logical_key = Some("f7".to_string()), + VK_F8 => logical_key = Some("f8".to_string()), + VK_F9 => logical_key = Some("f9".to_string()), + VK_F10 => logical_key = Some("f10".to_string()), + VK_F11 => logical_key = Some("f11".to_string()), + VK_F12 => logical_key = Some("f12".to_string()), + // modifiers + VK_CONTROL => modifiers.control = keydown, + VK_MENU => modifiers.alt = keydown, + VK_SHIFT => modifiers.shift = keydown, + VK_LWIN | VK_RWIN => modifiers.command = keydown, + _ => {} + } + + if let Some(key) = logical_key { + if keydown { + Some(PlatformInput::KeyDown(KeyDownEvent { + keystroke: Keystroke { + key, + ime_key: None, + modifiers: modifiers.clone(), + }, + is_held: lparam.0 & (0x1 << 30) > 0, + })) + } else { + Some(PlatformInput::KeyUp(KeyUpEvent { + keystroke: Keystroke { + key, + ime_key: None, + modifiers: modifiers.clone(), + }, + })) + } + } else { + None + } +} + +pub fn parse_keyboard_input( + wparam: WPARAM, + lparam: LPARAM, + modifiers: &Modifiers, +) -> Option { + if wparam.0 == 8 || wparam.0 == 27 || wparam.0 == 13 || (lparam.0 >> 24) & 1 == 1 { + // backspace escape enter ctrl + // these keys are handled by Zed + return None; + } + let src = [wparam.0 as u16]; + let Ok(first_char) = char::decode_utf16(src) + .map(|r| r.map_err(|e| e.unpaired_surrogate())) + .collect::>()[0] + else { + return None; + }; + println!("{} => {:?}", wparam.0, first_char); + if first_char.is_control() { + return None; + } + Some(PlatformInput::KeyDown(KeyDownEvent { + keystroke: Keystroke { + key: first_char.to_string(), + ime_key: None, + modifiers: modifiers.clone(), + }, + is_held: lparam.0 & (0x1 << 30) > 0, + })) +} + +pub fn parse_mouse_button( + msg: u32, + wparam: WPARAM, + lparam: LPARAM, + modifiers: &Modifiers, +) -> PlatformInput { + match msg { + WM_LBUTTONDOWN => PlatformInput::MouseDown(MouseDownEvent { + button: MouseButton::Left, + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 1, + }), + WM_LBUTTONDBLCLK => PlatformInput::MouseDown(MouseDownEvent { + button: MouseButton::Left, + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 2, + }), + WM_LBUTTONUP => PlatformInput::MouseUp(MouseUpEvent { + button: MouseButton::Left, + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 1, + }), + WM_RBUTTONDOWN => PlatformInput::MouseDown(MouseDownEvent { + button: MouseButton::Right, + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 1, + }), + WM_RBUTTONDBLCLK => PlatformInput::MouseDown(MouseDownEvent { + button: MouseButton::Right, + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 2, + }), + WM_RBUTTONUP => PlatformInput::MouseUp(MouseUpEvent { + button: MouseButton::Right, + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 1, + }), + WM_MBUTTONDOWN => PlatformInput::MouseDown(MouseDownEvent { + button: MouseButton::Middle, + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 1, + }), + WM_MBUTTONDBLCLK => PlatformInput::MouseDown(MouseDownEvent { + button: MouseButton::Middle, + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 2, + }), + WM_MBUTTONUP => PlatformInput::MouseUp(MouseUpEvent { + button: MouseButton::Middle, + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 1, + }), + WM_XBUTTONDOWN => { + if hiword!(wparam.0, u16) == XBUTTON1 { + PlatformInput::MouseDown(MouseDownEvent { + button: MouseButton::Navigate(crate::NavigationDirection::Forward), + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 1, + }) + } else { + PlatformInput::MouseDown(MouseDownEvent { + button: MouseButton::Navigate(crate::NavigationDirection::Back), + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 1, + }) + } + } + WM_XBUTTONDBLCLK => { + if hiword!(wparam.0, u16) == XBUTTON1 { + PlatformInput::MouseDown(MouseDownEvent { + button: MouseButton::Navigate(crate::NavigationDirection::Forward), + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 2, + }) + } else { + PlatformInput::MouseDown(MouseDownEvent { + button: MouseButton::Navigate(crate::NavigationDirection::Back), + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 2, + }) + } + } + WM_XBUTTONUP => { + if hiword!(wparam.0, u16) == XBUTTON1 { + PlatformInput::MouseUp(MouseUpEvent { + button: MouseButton::Navigate(crate::NavigationDirection::Forward), + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 1, + }) + } else { + PlatformInput::MouseUp(MouseUpEvent { + button: MouseButton::Navigate(crate::NavigationDirection::Back), + position: crate::Point { + x: crate::Pixels(loword!(lparam.0, i16) as _), + y: crate::Pixels(hiword!(lparam.0, i16) as _), + }, + modifiers: modifiers.clone(), + click_count: 1, + }) + } + } + _ => unreachable!(), + } +} + +pub fn parse_mouse_movement( + wparam: WPARAM, + lparam: LPARAM, + modifiers: Modifiers, +) -> (Point, PlatformInput) { + let new_pos = Point { + x: Pixels(loword!(lparam.0, i16) as _), + y: Pixels(hiword!(lparam.0, i16) as _), + }; + let mut pressed_button = None; + for button_mask in MOUSE_MOVE_BUTTONS { + if wparam.0 & button_mask > 0 { + pressed_button = buttonmask_to_button(button_mask); + break; + } + } + let input = PlatformInput::MouseMove(MouseMoveEvent { + position: new_pos.clone(), + pressed_button, + modifiers, + }); + + (new_pos, input) +} + +pub fn parse_mouse_wheel(wparam: WPARAM, lparam: LPARAM, modifiers: Modifiers) -> PlatformInput { + let position = Point { + x: Pixels(loword!(lparam.0, i16) as _), + y: Pixels(hiword!(lparam.0, i16) as _), + }; + let lines = hiword!(wparam.0, i16); + println!("Lines: {}", lines); + PlatformInput::ScrollWheel(ScrollWheelEvent { + position, + delta: ScrollDelta::Lines(Point { + x: 0.0, + y: lines as f32 / 120.0, + }), + modifiers, + touch_phase: TouchPhase::default(), + }) +} + +pub unsafe fn parse_dropfiles(wparam: WPARAM, lparam: LPARAM) -> PlatformInput { + let hdrop = windows::Win32::UI::Shell::HDROP(wparam.0 as isize); + // DragQueryFileW(hdrop, ifile, lpszfile); + + PlatformInput::FileDrop(crate::FileDropEvent::Exited) +} + +fn buttonmask_to_button(mask: usize) -> Option { + match mask { + MOUSE_MOVE_LBUTTON => Some(MouseButton::Left), + MOUSE_MOVE_RBUTTON => Some(MouseButton::Right), + MOUSE_MOVE_MBUTTON => Some(MouseButton::Middle), + MOUSE_MOVE_XBUTTON1 => Some(MouseButton::Navigate(crate::NavigationDirection::Back)), + MOUSE_MOVE_XBUTTON2 => Some(MouseButton::Navigate(crate::NavigationDirection::Forward)), + _ => None, + } +} diff --git a/crates/gpui/src/platform/windows/monitor.rs b/crates/gpui/src/platform/windows/monitor.rs new file mode 100644 index 0000000000000..ede52503d7200 --- /dev/null +++ b/crates/gpui/src/platform/windows/monitor.rs @@ -0,0 +1,56 @@ +use windows::Win32::{ + Graphics::Gdi::{GetMonitorInfoW, HMONITOR, MONITORINFO, MONITORINFOEXW}, + UI::HiDpi::{GetDpiForMonitor, MDT_EFFECTIVE_DPI}, +}; + +use crate::Size; + +pub struct MonitorHandle(HMONITOR); + +impl MonitorHandle { + pub fn new(hmonitor: HMONITOR) -> Self { + MonitorHandle(hmonitor) + } + + pub fn size(&self) -> Size { + let info = get_monitor_info(self.0).unwrap(); + let size = info.monitorInfo.rcMonitor; + + Size { + width: size.right - size.left, + height: size.top - size.bottom, + } + } + + pub fn scale_factor(&self) -> f32 { + (self.get_dpi() as f32) / (96 as f32) + } + + fn get_dpi(&self) -> u32 { + unsafe { + let mut dpi_x = 0; + let mut dpi_y = 0; + if GetDpiForMonitor(self.0, MDT_EFFECTIVE_DPI, &mut dpi_x, &mut dpi_y).is_ok() { + dpi_x + } else { + 96 + } + } + } +} + +fn get_monitor_info(hmonitor: HMONITOR) -> Result { + let mut monitor_info: MONITORINFOEXW = unsafe { std::mem::zeroed() }; + monitor_info.monitorInfo.cbSize = std::mem::size_of::() as u32; + let status = unsafe { + GetMonitorInfoW( + hmonitor, + &mut monitor_info as *mut MONITORINFOEXW as *mut MONITORINFO, + ) + }; + if status.as_bool() { + Ok(monitor_info) + } else { + Err(std::io::Error::last_os_error()) + } +} diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index e7751579c9d5e..968c0c6e1a2fc 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -1,259 +1,424 @@ -// todo!("windows"): remove -#![allow(unused_variables)] - use std::{ + alloc::GlobalAlloc, cell::RefCell, - collections::HashSet, + fmt::Write, + os::windows::process::CommandExt, path::{Path, PathBuf}, + process::Stdio, rc::Rc, - sync::Arc, + str::FromStr, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, + }, time::Duration, }; -use anyhow::{anyhow, Result}; use async_task::Runnable; -use futures::channel::oneshot::Receiver; -use parking_lot::Mutex; +use futures::channel::oneshot; use time::UtcOffset; -use util::SemanticVersion; -use windows::Win32::{ - Foundation::{CloseHandle, HANDLE, HWND}, - System::Threading::{CreateEventW, INFINITE}, - UI::WindowsAndMessaging::{ - DispatchMessageW, MsgWaitForMultipleObjects, PeekMessageW, PostQuitMessage, - TranslateMessage, MSG, PM_REMOVE, QS_ALLINPUT, WM_QUIT, +use windows::{ + core::{HSTRING, PCWSTR}, + Wdk::System::SystemServices::RtlGetVersion, + Win32::{ + Foundation::{HANDLE, HGLOBAL, HWND, LPARAM, LRESULT, STATUS_SUCCESS, WPARAM}, + Globalization::{u_memcpy, MultiByteToWideChar}, + Security::Credentials::{ + CredEnumerateW, CredWriteDomainCredentialsW, CREDENTIAL_TARGET_INFORMATIONW, + }, + System::{ + Com::{ + CoCreateInstance, CoInitializeEx, CoUninitialize, CreateBindCtx, CLSCTX_ALL, + COINIT_DISABLE_OLE1DDE, COINIT_MULTITHREADED, DVASPECT_CONTENT, FORMATETC, + TYMED_HGLOBAL, + }, + DataExchange::{ + CloseClipboard, EmptyClipboard, GetClipboardData, OpenClipboard, SetClipboardData, + }, + Memory::{GlobalAlloc, GlobalLock, GlobalUnlock, GMEM_MOVEABLE}, + Ole::{OleGetClipboard, OleInitialize, OleUninitialize, ReleaseStgMedium}, + Threading::CREATE_NO_WINDOW, + Time::{GetTimeZoneInformation, TIME_ZONE_ID_INVALID}, + }, + UI::{ + HiDpi::{SetProcessDpiAwarenessContext, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE}, + Input::KeyboardAndMouse::{ + GetDoubleClickTime, ToUnicode, VIRTUAL_KEY, VK_BACK, VK_DELETE, VK_DOWN, VK_END, + VK_ESCAPE, VK_F1, VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, + VK_F8, VK_F9, VK_HOME, VK_LEFT, VK_NEXT, VK_PRIOR, VK_RETURN, VK_RIGHT, VK_UP, + }, + Shell::{ + FileOpenDialog, FileSaveDialog, IFileOpenDialog, IFileSaveDialog, IShellItem, + SHCreateItemFromParsingName, ShellExecuteW, FILEOPENDIALOGOPTIONS, + FOS_ALLOWMULTISELECT, FOS_PICKFOLDERS, SIGDN_PARENTRELATIVEPARSING, + }, + WindowsAndMessaging::{ + AppendMenuW, CreateAcceleratorTableW, CreateMenu, DefWindowProcW, DestroyWindow, + DispatchMessageW, GetMessageW, LoadCursorW, LoadImageW, PostQuitMessage, SetCursor, + TranslateMessage, ACCEL, ACCEL_VIRT_FLAGS, HCURSOR, HMENU, IDC_ARROW, IDC_CROSS, + IDC_HAND, IDC_IBEAM, IDC_NO, IDC_SIZENS, IDC_SIZEWE, IMAGE_CURSOR, LR_DEFAULTSIZE, + MF_POPUP, MF_SEPARATOR, MF_STRING, SW_SHOWDEFAULT, WM_DESTROY, + }, + }, }, }; use crate::{ - Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, ForegroundExecutor, - Keymap, Menu, PathPromptOptions, Platform, PlatformDisplay, PlatformInput, PlatformTextSystem, - PlatformWindow, Task, WindowAppearance, WindowOptions, WindowsDispatcher, WindowsDisplay, - WindowsTextSystem, WindowsWindow, + encode_wide, log_windows_error, platform::cross_platform::CosmicTextSystem, set_windowdata, + Keystroke, WindowsWindow, WindowsWindowBase, WindowsWinodwDataWrapper, ACCEL_FALT, + ACCEL_FCONTROL, ACCEL_FSHIFT, ACCEL_FVIRTKEY, CF_UNICODETEXT, DISPATCH_WINDOW_CLASS, + DISPATCH_WINDOW_EXSTYLE, DISPATCH_WINDOW_STYLE, MAIN_DISPATCH, MENU_ACTIONS, WINDOW_CLOSE, }; +use crate::{ + Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId, + ForegroundExecutor, Keymap, Menu, PathPromptOptions, Platform, PlatformDisplay, PlatformInput, + PlatformTextSystem, PlatformWindow, Result, SemanticVersion, Task, WindowOptions, +}; + +use super::{WindowsDispatcher, WindowsDisplay}; + +#[derive(Default)] +pub struct PlatformCallbacks { + pub quit: Option>, + pub open_urls: Option)>>, + pub become_active: Option>, + pub resign_active: Option>, + pub reopen: Option>, + pub event: Option bool>>, + pub app_menu_action: Option>, + pub will_open_app_menu: Option>, + pub validate_app_menu_command: Option bool>>, +} pub(crate) struct WindowsPlatform { + background_executor: BackgroundExecutor, + foreground_executor: ForegroundExecutor, + text_system: Arc, inner: Rc, + menu_handle: RefCell>, } -pub(crate) struct WindowsPlatformInner { - background_executor: BackgroundExecutor, - pub(crate) foreground_executor: ForegroundExecutor, - main_receiver: flume::Receiver, - text_system: Arc, - callbacks: Mutex, - pub(crate) window_handles: RefCell>, - pub(crate) event: HANDLE, +impl WindowsPlatform { + pub(crate) fn new() -> Self { + platform_init().expect("error init windows platform"); + let (sender, receiver) = flume::unbounded::(); + let dispatch_window_handle = ::create( + DISPATCH_WINDOW_CLASS, + DISPATCH_WINDOW_STYLE, + DISPATCH_WINDOW_EXSTYLE, + None, + None, + None, + None, + None, + None, + ); + let inner = Rc::new(WindowsPlatformInner::new(dispatch_window_handle, receiver)); + unsafe { + set_windowdata( + dispatch_window_handle, + WindowsWinodwDataWrapper(inner.clone()), + ); + } + let dispatcher = Arc::new(WindowsDispatcher::new(sender, dispatch_window_handle)); + + WindowsPlatform { + background_executor: BackgroundExecutor::new(dispatcher.clone()), + foreground_executor: ForegroundExecutor::new(dispatcher), + text_system: Arc::new(CosmicTextSystem::new()), + inner, + menu_handle: RefCell::new(None), + } + } } -impl Drop for WindowsPlatformInner { +impl Drop for WindowsPlatform { fn drop(&mut self) { - unsafe { CloseHandle(self.event) }.ok(); + unsafe { + OleUninitialize(); + } } } -#[derive(Default)] -struct Callbacks { - open_urls: Option)>>, - become_active: Option>, - resign_active: Option>, - quit: Option>, - reopen: Option>, - event: Option bool>>, - app_menu_action: Option>, - will_open_app_menu: Option>, - validate_app_menu_command: Option bool>>, +pub struct WindowsPlatformInner { + pub dispatch_window_handle: HWND, + pub main_receiver: flume::Receiver, + windows_count: AtomicUsize, + pub callbacks: RefCell, + pub menu_actions: RefCell>>, } -impl WindowsPlatform { - pub(crate) fn new() -> Self { - let (main_sender, main_receiver) = flume::unbounded::(); - let event = unsafe { CreateEventW(None, false, false, None) }.unwrap(); - let dispatcher = Arc::new(WindowsDispatcher::new(main_sender, event)); - let background_executor = BackgroundExecutor::new(dispatcher.clone()); - let foreground_executor = ForegroundExecutor::new(dispatcher); - let text_system = Arc::new(WindowsTextSystem::new()); - let callbacks = Mutex::new(Callbacks::default()); - let window_handles = RefCell::new(HashSet::new()); - let inner = Rc::new(WindowsPlatformInner { - background_executor, - foreground_executor, +impl WindowsPlatformInner { + pub fn new(dispatch_window_handle: HWND, main_receiver: flume::Receiver) -> Self { + WindowsPlatformInner { + dispatch_window_handle, main_receiver, - text_system, - callbacks, - window_handles, - event, - }); - Self { inner } + windows_count: AtomicUsize::new(0), + callbacks: RefCell::new(PlatformCallbacks::default()), + menu_actions: RefCell::new(Vec::new()), + } + } + + pub fn open_new_window(&self) { + self.windows_count.fetch_add(1, Ordering::SeqCst); + } + + pub fn close_one_window(&self) { + if self.windows_count.load(Ordering::SeqCst) == 1 { + unsafe { + PostQuitMessage(0); + } + } + let old_val = self.windows_count.fetch_sub(1, Ordering::SeqCst); } } impl Platform for WindowsPlatform { fn background_executor(&self) -> BackgroundExecutor { - self.inner.background_executor.clone() + self.background_executor.clone() } fn foreground_executor(&self) -> ForegroundExecutor { - self.inner.foreground_executor.clone() + self.foreground_executor.clone() } fn text_system(&self) -> Arc { - self.inner.text_system.clone() + self.text_system.clone() } - fn run(&self, on_finish_launching: Box) { + fn run(&self, on_finish_launching: Box) { on_finish_launching(); - 'a: loop { - unsafe { - MsgWaitForMultipleObjects(Some(&[self.inner.event]), false, INFINITE, QS_ALLINPUT) - }; - let mut msg = MSG::default(); - while unsafe { PeekMessageW(&mut msg, HWND::default(), 0, 0, PM_REMOVE) }.as_bool() { - if msg.message == WM_QUIT { - break 'a; - } - unsafe { TranslateMessage(&msg) }; - unsafe { DispatchMessageW(&msg) }; - } - while let Ok(runnable) = self.inner.main_receiver.try_recv() { - runnable.run(); + unsafe { + let mut msg = std::mem::zeroed(); + while GetMessageW(&mut msg, HWND::default(), 0, 0).as_bool() { + TranslateMessage(&msg); + DispatchMessageW(&msg); } } - let mut callbacks = self.inner.callbacks.lock(); - if let Some(callback) = callbacks.quit.as_mut() { - callback() + if let Some(ref mut func) = self.inner.callbacks.borrow_mut().quit { + func(); + } + unsafe { + let _ = DestroyWindow(self.inner.dispatch_window_handle); } } fn quit(&self) { - self.foreground_executor() - .spawn(async { unsafe { PostQuitMessage(0) } }) - .detach(); + unsafe { + PostQuitMessage(0); + } } - // todo!("windows") - fn restart(&self) { - unimplemented!() - } + //todo!(windows) + fn restart(&self) {} - // todo!("windows") + //todo!(windows) fn activate(&self, ignoring_other_apps: bool) {} - // todo!("windows") - fn hide(&self) { - unimplemented!() - } + //todo!(windows) + fn hide(&self) {} - // todo!("windows") - fn hide_other_apps(&self) { - unimplemented!() - } + //todo!(windows) + fn hide_other_apps(&self) {} - // todo!("windows") - fn unhide_other_apps(&self) { - unimplemented!() - } + //todo!(windows) + fn unhide_other_apps(&self) {} - // todo!("windows") fn displays(&self) -> Vec> { - vec![Rc::new(WindowsDisplay::new())] + WindowsDisplay::displays() } - // todo!("windows") - fn display(&self, id: crate::DisplayId) -> Option> { - Some(Rc::new(WindowsDisplay::new())) + fn display(&self, id: DisplayId) -> Option> { + Some(Rc::new(WindowsDisplay::new(id))) } - // todo!("windows") + //todo!(windows) fn active_window(&self) -> Option { - unimplemented!() + None } fn open_window( &self, - handle: AnyWindowHandle, + _handle: AnyWindowHandle, options: WindowOptions, ) -> Box { - Box::new(WindowsWindow::new(self.inner.clone(), handle, options)) - } + let menu_handle = self.menu_handle.borrow().clone(); + let window = WindowsWindow::new( + self.foreground_executor(), + self.inner.dispatch_window_handle.into(), + &options, + menu_handle, + ); + self.inner.open_new_window(); - // todo!("windows") - fn window_appearance(&self) -> WindowAppearance { - WindowAppearance::Dark + Box::new(window) } - // todo!("windows") fn open_url(&self, url: &str) { - // todo!("windows") + let url_string = url.to_string(); + println!("Open: {}", url_string); + self.background_executor() + .spawn(async move { + open_target(url_string); + }) + .detach(); } - // todo!("windows") fn on_open_urls(&self, callback: Box)>) { - self.inner.callbacks.lock().open_urls = Some(callback); + self.inner.callbacks.borrow_mut().open_urls = Some(callback); } - // todo!("windows") - fn prompt_for_paths(&self, options: PathPromptOptions) -> Receiver>> { - unimplemented!() + fn prompt_for_paths( + &self, + options: PathPromptOptions, + ) -> oneshot::Receiver>> { + let (tx, rx) = oneshot::channel(); + self.foreground_executor() + .spawn(async move { + unsafe { + let dialog = show_openfile_dialog(options).expect("error show openfile dialog"); + if let Ok(_) = dialog.Show(None) { + let Ok(items) = dialog.GetResults() else { + log::error!( + "Error get result from dialog {}", + std::io::Error::last_os_error() + ); + let _ = tx.send(None); + return; + }; + let Ok(count) = items.GetCount() else { + log::error!( + "Error get results count from dialog {}", + std::io::Error::last_os_error() + ); + let _ = tx.send(None); + return; + }; + let mut path_vec = Vec::new(); + for index in 0..count { + let Ok(item) = items.GetItemAt(index) else { + log::error!( + "Error get item dialog {}", + std::io::Error::last_os_error() + ); + continue; + }; + let Ok(item_string) = item.GetDisplayName(SIGDN_PARENTRELATIVEPARSING) + else { + log::error!( + "Error parsing item name {}", + std::io::Error::last_os_error() + ); + continue; + }; + let Ok(path_string) = item_string.to_string() else { + log::error!( + "Error parsing item name from utf16 to string {}", + std::io::Error::last_os_error() + ); + continue; + }; + path_vec.push(PathBuf::from(path_string)); + } + let _ = tx.send(Some(path_vec)); + } + } + }) + .detach(); + + rx } - // todo!("windows") - fn prompt_for_new_path(&self, directory: &Path) -> Receiver> { - unimplemented!() + fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver> { + let directory = directory.to_owned(); + let (tx, rx) = oneshot::channel(); + self.foreground_executor() + .spawn(async move { + unsafe { + let dialog = + show_savefile_dialog(directory).expect("error open savefile dialog"); + if let Ok(_) = dialog.Show(None) { + if let Ok(shell_item) = dialog.GetResult() { + if let Ok(file) = shell_item.GetDisplayName(SIGDN_PARENTRELATIVEPARSING) + { + let _ = tx.send(Some(PathBuf::from(file.to_string().unwrap()))); + return; + } + } + } + let _ = tx.send(None); + } + }) + .detach(); + + rx } - // todo!("windows") fn reveal_path(&self, path: &Path) { - unimplemented!() + let file_path = path.to_string_lossy().into_owned(); + self.background_executor() + .spawn(async move { + open_target(file_path); + }) + .detach(); } fn on_become_active(&self, callback: Box) { - self.inner.callbacks.lock().become_active = Some(callback); + self.inner.callbacks.borrow_mut().become_active = Some(callback); } fn on_resign_active(&self, callback: Box) { - self.inner.callbacks.lock().resign_active = Some(callback); + self.inner.callbacks.borrow_mut().resign_active = Some(callback); } fn on_quit(&self, callback: Box) { - self.inner.callbacks.lock().quit = Some(callback); + self.inner.callbacks.borrow_mut().quit = Some(callback); } fn on_reopen(&self, callback: Box) { - self.inner.callbacks.lock().reopen = Some(callback); + self.inner.callbacks.borrow_mut().reopen = Some(callback); } fn on_event(&self, callback: Box bool>) { - self.inner.callbacks.lock().event = Some(callback); + self.inner.callbacks.borrow_mut().event = Some(callback); } - // todo!("windows") - fn set_menus(&self, menus: Vec, keymap: &Keymap) {} - fn on_app_menu_action(&self, callback: Box) { - self.inner.callbacks.lock().app_menu_action = Some(callback); + self.inner.callbacks.borrow_mut().app_menu_action = Some(callback); } fn on_will_open_app_menu(&self, callback: Box) { - self.inner.callbacks.lock().will_open_app_menu = Some(callback); + self.inner.callbacks.borrow_mut().will_open_app_menu = Some(callback); } fn on_validate_app_menu_command(&self, callback: Box bool>) { - self.inner.callbacks.lock().validate_app_menu_command = Some(callback); + self.inner.callbacks.borrow_mut().validate_app_menu_command = Some(callback); } fn os_name(&self) -> &'static str { "Windows" } + fn double_click_interval(&self) -> Duration { + let millis = unsafe { GetDoubleClickTime() }; + Duration::from_millis(millis as _) + } + fn os_version(&self) -> Result { - Ok(SemanticVersion { - major: 1, - minor: 0, - patch: 0, - }) + let mut info = unsafe { std::mem::zeroed() }; + let status = unsafe { RtlGetVersion(&mut info) }; + if status == STATUS_SUCCESS { + Ok(SemanticVersion { + major: info.dwMajorVersion as _, + minor: info.dwMinorVersion as _, + patch: info.dwBuildNumber as _, + }) + } else { + Err(anyhow::anyhow!("{}", std::io::Error::last_os_error())) + } } + // todo!(windows) fn app_version(&self) -> Result { Ok(SemanticVersion { major: 1, @@ -262,56 +427,445 @@ impl Platform for WindowsPlatform { }) } - // todo!("windows") + // todo!(windows) fn app_path(&self) -> Result { - Err(anyhow!("not yet implemented")) + unimplemented!() } - // todo!("windows") - fn local_timezone(&self) -> UtcOffset { - UtcOffset::from_hms(9, 0, 0).unwrap() + //todo!(windows) + fn set_menus(&self, menus: Vec, keymap: &Keymap) { + let mut actions_vec = Vec::new(); + let mut accelerator_vec = Vec::new(); + unsafe { + let menu_bar_handle = CreateMenu().expect("unable to create menu"); + let actions_count = AtomicUsize::new(1); + for menu in menus { + let _ = generate_menu( + menu_bar_handle, + menu, + &actions_count, + &mut actions_vec, + keymap, + &mut accelerator_vec, + ); + } + let _ = self.menu_handle.borrow_mut().insert(menu_bar_handle); + let _ = CreateAcceleratorTableW(&accelerator_vec).inspect_err(log_windows_error); + } + (*self.inner.menu_actions.borrow_mut()) = actions_vec; } - // todo!("windows") - fn double_click_interval(&self) -> Duration { - Duration::from_millis(100) + fn local_timezone(&self) -> UtcOffset { + let mut info = unsafe { std::mem::zeroed() }; + let ret = unsafe { GetTimeZoneInformation(&mut info) }; + if ret == TIME_ZONE_ID_INVALID { + log::error!( + "Unable to get local timezone: {}", + std::io::Error::last_os_error() + ); + + return UtcOffset::UTC; + } + // Windows treat offset as: + // UTC = localtime + offset + // so we add a minus here + let hours = -info.Bias / 60; + let minutes = -info.Bias % 60; + + UtcOffset::from_hms(hours as _, minutes as _, 0).unwrap() } - // todo!("windows") fn path_for_auxiliary_executable(&self, name: &str) -> Result { - Err(anyhow!("not yet implemented")) + unimplemented!() } - // todo!("windows") - fn set_cursor_style(&self, style: CursorStyle) {} + fn set_cursor_style(&self, style: CursorStyle) { + unsafe { + let handle = match style { + CursorStyle::IBeam | CursorStyle::IBeamCursorForVerticalLayout => { + LoadImageW(None, IDC_IBEAM, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) + } + CursorStyle::Crosshair => { + LoadImageW(None, IDC_CROSS, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) + } + CursorStyle::PointingHand | CursorStyle::DragLink => { + LoadImageW(None, IDC_HAND, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) + } + CursorStyle::ResizeLeft + | CursorStyle::ResizeRight + | CursorStyle::ResizeLeftRight => { + LoadImageW(None, IDC_SIZEWE, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) + } + CursorStyle::ResizeUp | CursorStyle::ResizeDown | CursorStyle::ResizeUpDown => { + LoadImageW(None, IDC_SIZENS, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) + } + CursorStyle::OperationNotAllowed => { + LoadImageW(None, IDC_NO, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) + } + _ => LoadImageW(None, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE), + }; + if handle.is_err() { + log::error!("Windows error: {}", std::io::Error::last_os_error()); + return; + } + let _ = SetCursor(HCURSOR(handle.unwrap().0)); + } + } - // todo!("windows") + //todo!(windows) fn should_auto_hide_scrollbars(&self) -> bool { false } - // todo!("windows") + //todo!(windows) fn write_to_clipboard(&self, item: ClipboardItem) { - unimplemented!() + unsafe { + if OpenClipboard(self.inner.dispatch_window_handle).is_err() { + log::error!("Windows error: {}", std::io::Error::last_os_error()); + return; + } + if EmptyClipboard().is_err() { + log::error!("Windows error: {}", std::io::Error::last_os_error()); + return; + } + // MultiByteToWideChar(codepage, dwflags, lpmultibytestr, lpwidecharstr); + let data_ptr = encode_wide(&item.text); + let count = data_ptr.len() + 1; + let global = GlobalAlloc(GMEM_MOVEABLE, count * 2).unwrap(); + let handle = GlobalLock(global); + u_memcpy(handle as _, data_ptr.as_ptr() as _, count as _); + let _ = GlobalUnlock(global); + if SetClipboardData(CF_UNICODETEXT, HANDLE(global.0 as isize)).is_err() { + log::error!("Windows error: {}", std::io::Error::last_os_error()); + return; + } + let _ = CloseClipboard(); + } } - // todo!("windows") + //todo!(windows) fn read_from_clipboard(&self) -> Option { - unimplemented!() + // unsafe { + // if OpenClipboard(self.inner.dispatch_window_handle).is_err() { + // log::error!("Windows error: {}", std::io::Error::last_os_error()); + // return None; + // } + // let ret = GetClipboardData(CF_UNICODETEXT); + // if ret.is_err() { + // log::error!("Windows error: {}", std::io::Error::last_os_error()); + // return None; + // } + // let data_ptr = GlobalLock(HGLOBAL(ret.unwrap().0 as _)) as *mut Vec; + // // let x: *mut Vec = data_ptr as _; + // let data = String::from_utf16_lossy(&*data_ptr); + // let _ = CloseClipboard(); + + // Some(ClipboardItem { + // text: data, + // metadata: None, + // }) + // } + unsafe { + let Ok(clipboard) = OleGetClipboard().inspect_err(log_windows_error) else { + return None; + }; + let config = FORMATETC { + cfFormat: CF_UNICODETEXT as _, + ptd: std::ptr::null_mut() as _, + dwAspect: DVASPECT_CONTENT.0, + lindex: -1, + tymed: TYMED_HGLOBAL.0 as _, + }; + let Ok(mut data) = clipboard + .GetData(&config as _) + .inspect_err(log_windows_error) + else { + return None; + }; + let string_raw = GlobalLock(data.u.hGlobal) as *mut Vec; + let string = String::from_utf16_lossy(&*string_raw); + let _ = GlobalUnlock(data.u.hGlobal); + ReleaseStgMedium(&mut data); + + Some(ClipboardItem { + text: string, + metadata: None, + }) + } } - // todo!("windows") + // todo!(windows) fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task> { - Task::Ready(Some(Err(anyhow!("not implemented yet.")))) + unimplemented!() } - // todo!("windows") + // todo!(windows) fn read_credentials(&self, url: &str) -> Task)>>> { - Task::Ready(Some(Err(anyhow!("not implemented yet.")))) + unimplemented!() } - // todo!("windows") + // todo!(windows) fn delete_credentials(&self, url: &str) -> Task> { - Task::Ready(Some(Err(anyhow!("not implemented yet.")))) + unimplemented!() + } + + // todo!(windows) + fn window_appearance(&self) -> crate::WindowAppearance { + crate::WindowAppearance::Light + } +} + +impl WindowsWindowBase for WindowsPlatformInner { + unsafe fn handle_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT { + match message { + MAIN_DISPATCH => { + if let Ok(runnable) = self.main_receiver.try_recv() { + runnable.run(); + } + LRESULT(0) + } + WM_DESTROY => { + PostQuitMessage(0); + LRESULT(0) + } + WINDOW_CLOSE => { + self.close_one_window(); + LRESULT(0) + } + MENU_ACTIONS => { + if let Some(ref mut callback) = self.callbacks.borrow_mut().app_menu_action { + if let Some(action) = self.menu_actions.borrow().get(wparam.0) { + println!("Action index: {}", wparam.0); + let action = action.boxed_clone(); + callback(&*action); + } + } + LRESULT(0) + } + _ => DefWindowProcW(self.dispatch_window_handle, message, wparam, lparam), + } } } + +fn platform_init() -> anyhow::Result<()> { + unsafe { + SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE) + .inspect_err(log_windows_error)?; + // if CoInitializeEx(None, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE).is_err() { + // log::error!("Windows error: {}", std::io::Error::last_os_error()); + // return anyhow::Result::Err(anyhow::anyhow!("Set dpi awareness failed")); + // } + OleInitialize(None).inspect_err(log_windows_error)?; + Ok(()) + } +} + +fn open_target(target: String) { + unsafe { + let operation = encode_wide("open"); + let file_path_vec = encode_wide(&target); + let ret = ShellExecuteW( + None, + PCWSTR::from_raw(operation.as_ptr()), + PCWSTR::from_raw(file_path_vec.as_ptr()), + None, + None, + SW_SHOWDEFAULT, + ); + if ret.0 <= 32 { + log::error!("Unable to open: {}", std::io::Error::last_os_error()); + return; + } + } +} + +fn show_openfile_dialog(options: PathPromptOptions) -> anyhow::Result { + unsafe { + let dialog: IFileOpenDialog = + CoCreateInstance(&FileOpenDialog, None, CLSCTX_ALL).inspect_err(log_windows_error)?; + let mut config = FILEOPENDIALOGOPTIONS::default(); + if options.directories { + config |= FOS_PICKFOLDERS; + } + if options.multiple { + config |= FOS_ALLOWMULTISELECT; + } + let _ = dialog.SetOptions(config).inspect_err(log_windows_error)?; + + Ok(dialog) + } +} + +fn show_savefile_dialog(directory: PathBuf) -> anyhow::Result { + unsafe { + let dialog: IFileSaveDialog = + CoCreateInstance(&FileSaveDialog, None, CLSCTX_ALL).inspect_err(log_windows_error)?; + let dir_str = directory.to_str().unwrap(); + println!("Target dir: {}", dir_str); + let dir_vec = encode_wide(dir_str); + let bind_context = CreateBindCtx(0).inspect_err(log_windows_error)?; + let dir_shell_item: IShellItem = + SHCreateItemFromParsingName(PCWSTR::from_raw(dir_vec.as_ptr()), &bind_context) + .inspect_err(log_windows_error)?; + let _ = dialog + .SetFolder(&dir_shell_item) + .inspect_err(log_windows_error); + + Ok(dialog) + } +} + +unsafe fn generate_menu( + parent_handle: HMENU, + menu: Menu, + actions_count: &AtomicUsize, + actions_vec: &mut Vec>, + keymap: &Keymap, + accelerator_vec: &mut Vec, +) -> anyhow::Result<()> { + let menu_handle = CreateMenu().unwrap(); + let menu_name = encode_wide(menu.name); + AppendMenuW( + parent_handle, + MF_POPUP, + menu_handle.0 as _, + PCWSTR::from_raw(menu_name.as_ptr()), + ) + .inspect_err(log_windows_error)?; + if menu.items.is_empty() { + return Ok(()); + } + for menu_item in menu.items { + match menu_item { + crate::MenuItem::Separator => AppendMenuW(menu_handle, MF_SEPARATOR, 0, PCWSTR::null()) + .inspect_err(log_windows_error)?, + crate::MenuItem::Submenu(submenu) => { + generate_menu( + menu_handle, + submenu, + actions_count, + actions_vec, + keymap, + accelerator_vec, + )?; + } + crate::MenuItem::Action { + name, + action, + os_action, + } => { + let keystrokes = keymap + .bindings_for_action(action.as_ref()) + .next() + .map(|binding| binding.keystrokes()); + println!("Shortcut: {:#?}", keystrokes); + + let mut item_name = name.to_string(); + let action_index = actions_count.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + if let Some(keystrokes) = keystrokes { + // TODO: deal with 2 keystrokes + if keystrokes.len() == 1 { + let keystroke = &keystrokes[0]; + item_name.push('\t'); + keystroke_to_menu_string(keystroke, &mut item_name); + let accel_table = keystroke_to_accel_table(keystroke, action_index as _); + accelerator_vec.push(accel_table); + } else { + item_name.push('\t'); + for (keyindex, keystroke) in keystrokes.iter().enumerate() { + keystroke_to_menu_string(keystroke, &mut item_name); + item_name.push('\t'); + let accel_table = + keystroke_to_accel_table(keystroke, action_index as _); + accelerator_vec.push(accel_table); + } + item_name.pop(); + } + } + let name_vec = encode_wide(&item_name); + AppendMenuW( + menu_handle, + MF_STRING, + action_index, + PCWSTR::from_raw(name_vec.as_ptr()), + ) + .inspect_err(log_windows_error)?; + println!("action [{}]: {:#?}", action_index, action); + actions_vec.push(action); + } + } + } + + Ok(()) +} + +fn keystroke_to_menu_string(keystroke: &Keystroke, menu_string: &mut String) { + if keystroke.modifiers.control { + let _ = write!(menu_string, "Ctrl+"); + } + if keystroke.modifiers.shift { + let _ = write!(menu_string, "Shift+"); + } + if keystroke.modifiers.alt { + let _ = write!(menu_string, "Alt+"); + } + let _ = write!(menu_string, "{}", keystroke.key.to_uppercase()); +} + +fn keystroke_to_accel_table(keystroke: &Keystroke, action_index: u16) -> ACCEL { + let mut table = ACCEL::default(); + if keystroke.modifiers.control { + table.fVirt |= ACCEL_VIRT_FLAGS(ACCEL_FCONTROL); + } + if keystroke.modifiers.shift { + table.fVirt |= ACCEL_VIRT_FLAGS(ACCEL_FSHIFT); + } + if keystroke.modifiers.alt { + table.fVirt |= ACCEL_VIRT_FLAGS(ACCEL_FALT); + } + table.fVirt |= ACCEL_VIRT_FLAGS(ACCEL_FVIRTKEY); + table.key = keycode_to_vkey(&keystroke.key).unwrap_or(VK_DELETE).0; + table.cmd = action_index + 1; + + table +} + +fn keycode_to_vkey(keycode: &str) -> Option { + let mut key = match keycode { + "backspace" => Some(VK_BACK), + "escape" => Some(VK_ESCAPE), + "enter" => Some(VK_RETURN), + "up" => Some(VK_UP), + "down" => Some(VK_DOWN), + "left" => Some(VK_LEFT), + "right" => Some(VK_RIGHT), + "pageup" => Some(VK_PRIOR), + "pagedown" => Some(VK_NEXT), + "home" => Some(VK_HOME), + "end" => Some(VK_END), + "delete" => Some(VK_DELETE), + "f1" => Some(VK_F1), + "f2" => Some(VK_F2), + "f3" => Some(VK_F3), + "f4" => Some(VK_F4), + "f5" => Some(VK_F5), + "f6" => Some(VK_F6), + "f7" => Some(VK_F7), + "f8" => Some(VK_F8), + "f9" => Some(VK_F9), + "f10" => Some(VK_F10), + "f11" => Some(VK_F11), + "f12" => Some(VK_F12), + _ => None, + }; + if key.is_none() { + let Ok(this_char) = char::from_str(keycode) else { + return None; + }; + // TODO: is this correct? + key = Some(VIRTUAL_KEY(this_char as u16)); + // println!("Char {} to vk {:?}", this_char, key); + } + + key +} diff --git a/crates/gpui/src/platform/windows/utils.rs b/crates/gpui/src/platform/windows/utils.rs new file mode 100644 index 0000000000000..c7566373507b6 --- /dev/null +++ b/crates/gpui/src/platform/windows/utils.rs @@ -0,0 +1,117 @@ +use std::{iter::once, panic::Location}; + +use collections::VecDeque; +use windows::Win32::{ + Foundation::{BOOL, HMODULE, HWND, LPARAM, RECT}, + Graphics::Gdi::{EnumDisplayMonitors, HDC, HMONITOR}, + System::LibraryLoader::{ + GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + }, + UI::WindowsAndMessaging::{GetWindowLongPtrW, SetWindowLongPtrW, GWL_USERDATA}, +}; + +use crate::MonitorHandle; + +pub fn encode_wide(input: &str) -> Vec { + input.encode_utf16().chain(once(0)).collect::>() +} + +pub fn get_module_handle() -> HMODULE { + unsafe { + let mut h_module = std::mem::zeroed(); + GetModuleHandleExW( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + windows::core::w!("ZedModule"), + &mut h_module, + ) + .unwrap(); // should never fail + + return h_module; + } +} + +pub fn available_monitors() -> VecDeque { + let mut monitors: VecDeque = VecDeque::new(); + unsafe { + EnumDisplayMonitors( + HDC::default(), + None, + Some(monitor_enum_proc), + LPARAM(&mut monitors as *mut _ as _), + ); + } + monitors +} + +/// Get the low-order word, the first arg can be signed or unsigned number, +/// the second arg must be i16 or u16 +/// +/// # examples +/// ```rust +/// let num: u32 = 0x00008001; +/// assert_eq!(loword!(num, u16), 32769); +/// assert_eq!(loword!(num, i16), -32767); +/// ``` +#[macro_export] +macro_rules! loword { + ($num:expr, $t:ty) => { + ($num & 0xFFFF) as $t + }; +} + +/// Get the high-order word, the first arg can be signed or unsigned number, +/// the second arg must be i16 or u16 +/// +/// # examples +/// ```rust +/// let num: u32 = 0x80010000; +/// assert_eq!(hiword!(num, u16), 32769); +/// assert_eq!(hiword!(num, i16), -32767); +/// ``` +#[macro_export] +macro_rules! hiword { + ($num:expr, $t:ty) => { + (($num >> 16) & 0xFFFF) as $t + }; +} + +#[inline] +pub unsafe fn set_windowdata(handle: HWND, data: T) { + let raw = Box::into_raw(Box::new(data)); + let ret = SetWindowLongPtrW(handle, GWL_USERDATA, raw as _); + if ret == 0 { + log::error!("Windows error: {}", std::io::Error::last_os_error()); + let _ = SetWindowLongPtrW(handle, GWL_USERDATA, raw as _); + } +} + +#[inline] +pub unsafe fn get_windowdata(handle: HWND) -> isize { + GetWindowLongPtrW(handle, GWL_USERDATA) +} + +pub fn log_windows_error(e: &windows::core::Error) { + let caller = Location::caller(); + log::error!( + "Windows error at {}:{}: {}", + caller.file(), + caller.line(), + std::io::Error::last_os_error() + ); +} + +pub fn log_anyhow_error(_: &anyhow::Error) { + log::error!("Windows error: {}", std::io::Error::last_os_error()); +} + +unsafe extern "system" fn monitor_enum_proc( + hmonitor: HMONITOR, + _hdc: HDC, + _place: *mut RECT, + data: LPARAM, +) -> BOOL { + let monitors = data.0 as *mut VecDeque; + unsafe { (*monitors).push_back(MonitorHandle::new(hmonitor)) }; + true.into() // continue enumeration +} diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index f43ac7cec8c9f..7c371525f0dea 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -1,535 +1,873 @@ -#![deny(unsafe_op_in_unsafe_fn)] -// todo!("windows"): remove -#![allow(unused_variables)] - use std::{ - any::Any, cell::{Cell, RefCell}, ffi::c_void, + mem, num::NonZeroIsize, + path::PathBuf, rc::{Rc, Weak}, - sync::{Arc, Once}, + str::FromStr, + sync::{ + atomic::{AtomicIsize, Ordering}, + Arc, + }, }; -use blade_graphics as gpu; -use futures::channel::oneshot::Receiver; -use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; +use futures::channel::oneshot; +use parking_lot::Mutex; +use raw_window_handle as rwh; +use smallvec::SmallVec; +use util::ResultExt; use windows::{ - core::{w, HSTRING, PCWSTR}, + core::{implement, IUnknown, Interface, IntoParam, Param, ReferenceType, PCWSTR}, Win32::{ - Foundation::{HINSTANCE, HWND, LPARAM, LRESULT, WPARAM}, - UI::WindowsAndMessaging::{ - CreateWindowExW, DefWindowProcW, GetWindowLongPtrW, LoadCursorW, PostQuitMessage, - RegisterClassW, SetWindowLongPtrW, SetWindowTextW, ShowWindow, CREATESTRUCTW, - CW_USEDEFAULT, GWLP_USERDATA, HMENU, IDC_ARROW, SW_MAXIMIZE, SW_SHOW, WINDOW_EX_STYLE, - WINDOW_LONG_PTR_INDEX, WM_CLOSE, WM_DESTROY, WM_MOVE, WM_NCCREATE, WM_NCDESTROY, - WM_PAINT, WM_SIZE, WNDCLASSW, WS_OVERLAPPEDWINDOW, WS_VISIBLE, + Foundation::{ + ERROR_UNRECOVERABLE_STACK_OVERFLOW, HWND, LPARAM, LRESULT, POINTL, RECT, S_OK, WPARAM, + }, + Graphics::Gdi::{ + GetMonitorInfoW, MonitorFromWindow, RedrawWindow, UpdateWindow, ValidateRect, HRGN, + MONITORINFO, MONITOR_DEFAULTTONEAREST, RDW_INVALIDATE, + }, + System::{ + Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL}, + Memory::{GlobalLock, GlobalUnlock}, + Ole::{ + IDropTarget, IDropTarget_Impl, RegisterDragDrop, ReleaseStgMedium, RevokeDragDrop, + CF_HDROP, DROPEFFECT, DROPEFFECT_LINK, DROPEFFECT_NONE, + }, + SystemServices::MODIFIERKEYS_FLAGS, + }, + UI::{ + Controls::{ + TaskDialogIndirect, TASKDIALOGCONFIG, TASKDIALOG_BUTTON, TASKDIALOG_FLAGS, + TDF_USE_HICON_MAIN, TD_ERROR_ICON, TD_INFORMATION_ICON, TD_WARNING_ICON, + }, + HiDpi::{GetDpiForMonitor, GetDpiForWindow, MDT_EFFECTIVE_DPI}, + Input::{ + Ime::{ + ImmGetContext, ImmReleaseContext, ImmSetCompositionWindow, CFS_POINT, + COMPOSITIONFORM, + }, + KeyboardAndMouse::GetMouseMovePointsEx, + }, + Shell::{DragQueryFileA, DragQueryFileW, HDROP}, + WindowsAndMessaging::{ + CreateWindowExW, DefWindowProcW, GetClientRect, GetCursorPos, MessageBoxExW, + PostMessageW, PostQuitMessage, RegisterClassExW, SetWindowTextW, ShowWindow, + CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, GWLP_HINSTANCE, HMENU, SIZE_MINIMIZED, + SW_SHOW, WINDOW_EX_STYLE, WINDOW_STYLE, WM_CHAR, WM_CLOSE, WM_COMMAND, WM_DESTROY, + WM_DROPFILES, WM_IME_STARTCOMPOSITION, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDBLCLK, + WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, WM_MBUTTONUP, + WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_PAINT, WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, + WM_RBUTTONUP, WM_SIZE, WM_XBUTTONDBLCLK, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSEXW, + WS_EX_ACCEPTFILES, WS_MAXIMIZE, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_VISIBLE, + }, }, }, }; use crate::{ - platform::blade::BladeRenderer, AnyWindowHandle, Bounds, GlobalPixels, HiLoWord, Modifiers, - Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, - Point, PromptLevel, Scene, Size, WindowAppearance, WindowBounds, WindowOptions, WindowsDisplay, - WindowsPlatformInner, + available_monitors, encode_wide, get_module_handle, hiword, log_windows_error, loword, + parse_dropfiles, parse_keyboard_input, parse_mouse_button, parse_mouse_movement, + parse_mouse_wheel, parse_system_key, platform::cross_platform::BladeRenderer, set_windowdata, + Action, Bounds, DisplayId, ForegroundExecutor, Modifiers, Pixels, PlatformDisplay, + PlatformInput, PlatformInputHandler, PlatformWindow, Point, Size, WindowKind, WindowOptions, + WindowsWindowBase, WindowsWinodwDataWrapper, DRAGDROP_GET_COUNT, FILENAME_MAXLENGTH, + MENU_ACTIONS, WINDOW_CLOSE, WINODW_EXTRA_EXSTYLE, WINODW_STYLE, }; -struct WindowsWindowInner { - hwnd: HWND, - origin: Cell>, - size: Cell>, - mouse_position: Cell>, - input_handler: Cell>, - renderer: RefCell, - callbacks: RefCell, - platform_inner: Rc, - handle: AnyWindowHandle, +use super::{display::WindowsDisplay, WINDOW_CLASS}; + +#[derive(Default)] +pub struct Callbacks { + pub request_frame: Option>, + pub input: Option bool>>, + pub active_status_change: Option>, + pub resize: Option, f32)>>, + pub fullscreen: Option>, + pub moved: Option>, + pub should_close: Option bool>>, + pub close: Option>, + pub appearance_changed: Option>, } -impl WindowsWindowInner { - fn new( - hwnd: HWND, - cs: &CREATESTRUCTW, - platform_inner: Rc, - handle: AnyWindowHandle, +pub struct WindowsWindow { + foreground_executor: ForegroundExecutor, + inner: Rc, + display: Rc, + windows_dragdrop: IDropTarget, +} + +impl WindowsWindow { + pub fn new( + foreground_executor: ForegroundExecutor, + dispatch_window_handle: HWND, + options: &WindowOptions, + menu_handle: Option, ) -> Self { - let origin = Cell::new(Point::new((cs.x as f64).into(), (cs.y as f64).into())); - let size = Cell::new(Size { - width: (cs.cx as f64).into(), - height: (cs.cy as f64).into(), - }); - let mouse_position = Cell::new(Point::default()); - let input_handler = Cell::new(None); - struct RawWindow { - hwnd: *mut c_void, - } - unsafe impl blade_rwh::HasRawWindowHandle for RawWindow { - fn raw_window_handle(&self) -> blade_rwh::RawWindowHandle { - let mut handle = blade_rwh::Win32WindowHandle::empty(); - handle.hwnd = self.hwnd; - handle.into() - } + let mut monitor = available_monitors() + .into_iter() + .nth(0) + .expect("no monitor detected!"); + let mut display = WindowsDisplay::new(DisplayId(0)); + if let Some(display_id) = options.display_id { + monitor = available_monitors() + .into_iter() + .nth(display_id.0 as usize) + .unwrap(); + // TODO: move window to target monitor + display.display_id = display_id; } - unsafe impl blade_rwh::HasRawDisplayHandle for RawWindow { - fn raw_display_handle(&self) -> blade_rwh::RawDisplayHandle { - blade_rwh::WindowsDisplayHandle::empty().into() + let scale_factor = monitor.scale_factor(); + + let mut lpwindowname = None; + if let Some(ref titlebar_opt) = options.titlebar { + if let Some(ref title) = titlebar_opt.title { + let title = encode_wide(title.as_ref()); + lpwindowname = Some(PCWSTR::from_raw(title.as_ptr())); } } - let raw = RawWindow { hwnd: hwnd.0 as _ }; - let gpu = Arc::new( - unsafe { - gpu::Context::init_windowed( - &raw, - gpu::ContextDesc { - validation: false, - capture: false, - }, - ) - } - .unwrap(), + let (style, exstyle, width, height) = parse_window_options(options); + let raw_window_handle = ::create( + WINDOW_CLASS, + style, + exstyle, + Some(CW_USEDEFAULT), + Some(CW_USEDEFAULT), + Some(width.unwrap_or(CW_USEDEFAULT)), + Some(height.unwrap_or(CW_USEDEFAULT)), + menu_handle, + lpwindowname, ); - let extent = gpu::Extent { - width: 1, - height: 1, + let window_handle = RawWindow::new(raw_window_handle); + let bounds = match options.bounds { + crate::WindowBounds::Fullscreen | crate::WindowBounds::Maximized => Bounds { + origin: Point::default(), + size: window_handle.size(), + }, + crate::WindowBounds::Fixed(bounds) => bounds.map(|p| p.0 as i32), + }; + let gpu = Arc::new(unsafe { + blade_graphics::Context::init_windowed( + &window_handle, + blade_graphics::ContextDesc { + validation: false, + capture: false, + }, + ) + .unwrap() + }); + let gpu_extent = blade_graphics::Extent { + width: window_handle.size().width as _, + height: window_handle.size().height as _, depth: 1, }; - let renderer = RefCell::new(BladeRenderer::new(gpu, extent)); - let callbacks = RefCell::new(Callbacks::default()); - Self { - hwnd, - origin, - size, - mouse_position, - input_handler, + let renderer = BladeRenderer::new(gpu, gpu_extent); + let inner = WindowsWindowinner::new( + dispatch_window_handle, + options, + scale_factor, + window_handle, + bounds, renderer, - callbacks, - platform_inner, - handle, + ); + let windows_dragdrop = unsafe { + set_windowdata(raw_window_handle, WindowsWinodwDataWrapper(inner.clone())); + let drop_target = WindowsDragDropTarget(inner.clone()); + let windows_dragdrop: IDropTarget = drop_target.into(); + RegisterDragDrop(raw_window_handle, &windows_dragdrop) + .inspect_err(log_windows_error) + .expect("Unable to register drawgrop op"); + windows_dragdrop + }; + + WindowsWindow { + foreground_executor, + display: Rc::new(display), + inner, + windows_dragdrop, + } + } +} + +pub struct WindowsWindowinner { + pub dispatch_window_handle: HWND, + pub window_handle: RawWindow, + bounds: RefCell>, + scale_factor: f32, + pub callbacks: RefCell, + input_handler: RefCell>, + pub renderer: RefCell, + pub modifiers: RefCell, + mouse_position: RefCell>, +} + +#[implement(IDropTarget)] +struct WindowsDragDropTarget(pub Rc); + +struct RawWindow { + handle: HWND, +} + +impl WindowsWindowinner { + pub fn new( + dispatch_window_handle: HWND, + options: &WindowOptions, + scale_factor: f32, + window_handle: RawWindow, + bounds: Bounds, + renderer: BladeRenderer, + ) -> Rc { + window_handle.show(); + + Rc::new(WindowsWindowinner { + dispatch_window_handle, + window_handle, + callbacks: RefCell::new(Callbacks::default()), + bounds: RefCell::new(bounds), + input_handler: RefCell::new(None), + scale_factor, + renderer: RefCell::new(renderer), + modifiers: RefCell::new(Modifiers::default()), + mouse_position: RefCell::new(Point::default()), + }) + } + + fn request_redraw(&self) { + if let Some(ref mut func) = self.callbacks.borrow_mut().request_frame { + func(); + } + } + + fn destroy(&self) { + self.renderer.borrow_mut().destroy(); + if let Some(func) = self.callbacks.borrow_mut().close.take() { + func(); + } + } + + fn update(&self) { + unsafe { + RedrawWindow( + self.window_handle.hwnd(), + None, + HRGN::default(), + RDW_INVALIDATE, + ); } } - fn handle_msg(&self, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT { - log::debug!("msg: {msg}, wparam: {}, lparam: {}", wparam.0, lparam.0); - match msg { - WM_MOVE => { - let x = lparam.loword() as f64; - let y = lparam.hiword() as f64; - self.origin.set(Point::new(x.into(), y.into())); - let mut callbacks = self.callbacks.borrow_mut(); - if let Some(callback) = callbacks.moved.as_mut() { - callback() + fn handle_input(&self, input: PlatformInput) { + if let Some(ref mut func) = self.callbacks.borrow_mut().input { + if func(input.clone()) { + return; + } + } + match input.clone() { + PlatformInput::KeyDown(event) => { + if let Some(mut input_handler) = self.input_handler.borrow_mut().as_mut() { + input_handler.replace_text_in_range(None, &event.keystroke.key); } } - WM_SIZE => { - // todo!("windows"): handle maximized or minimized - let width = lparam.loword().max(1) as f64; - let height = lparam.hiword().max(1) as f64; - self.renderer - .borrow_mut() - .update_drawable_size(Size { width, height }); - let width = width.into(); - let height = height.into(); - self.size.set(Size { width, height }); - let mut callbacks = self.callbacks.borrow_mut(); - if let Some(callback) = callbacks.resize.as_mut() { - callback( - Size { - width: Pixels(width.0), - height: Pixels(height.0), - }, - 1.0, - ) + PlatformInput::KeyUp(_) => {} + PlatformInput::ModifiersChanged(_) => {} + PlatformInput::MouseDown(_) => { + if let Some(ref mut input_handler) = self.callbacks.borrow_mut().input { + input_handler(input); } } + PlatformInput::MouseUp(_) => {} + PlatformInput::MouseMove(_) => {} + PlatformInput::MouseExited(_) => {} + PlatformInput::ScrollWheel(_) => {} + PlatformInput::FileDrop(_) => {} + } + } + + fn resize(&self, width: u32, height: u32) { + let mut resize_args = None; + { + let mut bounds_lock = self.bounds.borrow_mut(); + let bounds = Bounds { + origin: bounds_lock.origin, + size: Size { + width: width as _, + height: height as _, + }, + }; + *bounds_lock = bounds; + let window_size = self.window_handle.size(); + let gpu_size = blade_graphics::Extent { + width, + height, + depth: 1, + }; + let mut render = self.renderer.borrow_mut(); + if render.viewport_size() != gpu_size { + render.update_drawable_size(crate::size(gpu_size.width as _, gpu_size.height as _)); + let content_size = Size { + width: render.viewport_size().width.into(), + height: render.viewport_size().height.into(), + }; + resize_args = Some((content_size, self.scale_factor)); + } + } + + if let Some((content_size, scale_factor)) = resize_args { + if let Some(ref mut func) = self.callbacks.borrow_mut().resize { + func(content_size, scale_factor) + } + } + } +} + +impl WindowsWindowBase for WindowsWindowinner { + unsafe fn handle_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT { + match message { WM_PAINT => { - let mut callbacks = self.callbacks.borrow_mut(); - if let Some(callback) = callbacks.request_frame.as_mut() { - callback() + self.request_redraw(); + ValidateRect(self.window_handle.hwnd(), None); + DefWindowProcW(self.window_handle.hwnd(), message, wparam, lparam) + } + WM_DESTROY => { + self.destroy(); + let _ = PostMessageW( + self.dispatch_window_handle, + WINDOW_CLOSE, + WPARAM::default(), + LPARAM::default(), + ); + PostQuitMessage(0); + LRESULT(0) + } + WM_COMMAND => { + let action_index = loword!(wparam.0, u16) as usize; + if action_index != 0 { + let _ = PostMessageW( + self.dispatch_window_handle, + MENU_ACTIONS, + WPARAM(action_index - 1), + LPARAM::default(), + ) + .inspect_err(log_windows_error); } + LRESULT(0) } - WM_CLOSE => { - let mut callbacks: std::cell::RefMut<'_, Callbacks> = self.callbacks.borrow_mut(); - if let Some(callback) = callbacks.should_close.as_mut() { - if callback() { - return LRESULT(0); - } + WM_KEYDOWN | WM_KEYUP => { + let mut modifiers = self.modifiers.borrow().clone(); + if let Some(key) = parse_system_key(message, wparam, lparam, &mut modifiers) { + self.handle_input(key); + self.update(); } - drop(callbacks); - return unsafe { DefWindowProcW(self.hwnd, msg, wparam, lparam) }; + (*self.modifiers.borrow_mut()) = modifiers; + LRESULT(0) } - WM_DESTROY => { - let mut callbacks: std::cell::RefMut<'_, Callbacks> = self.callbacks.borrow_mut(); - if let Some(callback) = callbacks.close.take() { - callback() + WM_LBUTTONDOWN | WM_RBUTTONDOWN | WM_MBUTTONDOWN | WM_LBUTTONUP | WM_RBUTTONUP + | WM_MBUTTONUP | WM_XBUTTONDOWN | WM_XBUTTONUP | WM_LBUTTONDBLCLK + | WM_RBUTTONDBLCLK | WM_MBUTTONDBLCLK | WM_XBUTTONDBLCLK => { + let modifiers = self.modifiers.borrow(); + let key = parse_mouse_button(message, wparam, lparam, &modifiers); + self.handle_input(key); + + self.update(); + LRESULT(0) + } + WM_MOUSEMOVE => { + let modifiers = self.modifiers.borrow().clone(); + let (new_pos, input) = parse_mouse_movement(wparam, lparam, modifiers); + *self.mouse_position.borrow_mut() = new_pos; + self.handle_input(input); + LRESULT(0) + } + WM_CHAR => { + let modifiers = self.modifiers.borrow(); + let keycode = parse_keyboard_input(wparam, lparam, &*modifiers); + if let Some(key) = keycode { + self.handle_input(key); + self.update(); + } + LRESULT(0) + } + WM_MOUSEWHEEL => { + let modifiers = self.modifiers.borrow().clone(); + let input = parse_mouse_wheel(wparam, lparam, modifiers); + self.handle_input(input); + self.update(); + LRESULT(0) + } + WM_SIZE => { + if wparam.0 as u32 == SIZE_MINIMIZED { + return DefWindowProcW(self.window_handle.hwnd(), message, wparam, lparam); } - let mut window_handles = self.platform_inner.window_handles.borrow_mut(); - window_handles.remove(&self.handle); - if window_handles.is_empty() { - self.platform_inner - .foreground_executor - .spawn(async { - unsafe { PostQuitMessage(0) }; - }) - .detach(); + let width = loword!(lparam.0, u16) as u32; + let height = hiword!(lparam.0, u16) as u32; + self.resize(width, height); + self.update(); + LRESULT(0) + } + WM_IME_STARTCOMPOSITION => { + let ctx = ImmGetContext(None); + let mut config = COMPOSITIONFORM::default(); + config.dwStyle = CFS_POINT; + let mut cursor = std::mem::zeroed(); + if let Err(ref e) = GetCursorPos(&mut cursor) { + log_windows_error(e); + cursor.x = self.mouse_position.borrow().x.0 as _; + cursor.y = self.mouse_position.borrow().y.0 as _; } - return LRESULT(1); + config.ptCurrentPos.x = cursor.x; + config.ptCurrentPos.y = cursor.y; + ImmSetCompositionWindow(ctx, &config as _); + ImmReleaseContext(self.window_handle.hwnd(), ctx); + LRESULT(0) } - _ => return unsafe { DefWindowProcW(self.hwnd, msg, wparam, lparam) }, + _ => DefWindowProcW(self.window_handle.hwnd(), message, wparam, lparam), } - LRESULT(0) } } -#[derive(Default)] -struct Callbacks { - request_frame: Option>, - input: Option bool>>, - active_status_change: Option>, - resize: Option, f32)>>, - fullscreen: Option>, - moved: Option>, - should_close: Option bool>>, - close: Option>, - appearance_changed: Option>, -} +impl IDropTarget_Impl for WindowsDragDropTarget { + fn DragEnter( + &self, + pdataobj: Option<&IDataObject>, + grfkeystate: MODIFIERKEYS_FLAGS, + pt: &POINTL, + pdweffect: *mut DROPEFFECT, + ) -> windows::core::Result<()> { + unsafe { + let Some(idata_obj) = pdataobj else { + log::error!("no file detected while dragging"); + return Ok(()); + }; + let config = FORMATETC { + cfFormat: CF_HDROP.0, + ptd: std::ptr::null_mut() as _, + dwAspect: DVASPECT_CONTENT.0, + lindex: -1, + tymed: TYMED_HGLOBAL.0 as _, + }; + let mut paths = SmallVec::<[PathBuf; 2]>::new(); + if idata_obj.QueryGetData(&config as _) == S_OK { + *pdweffect = DROPEFFECT_LINK; + let Ok(mut idata) = idata_obj.GetData(&config as _) else { + return Ok(()); + }; + // idata_obj.query(iid, interface) + if idata.u.hGlobal.is_invalid() { + return Ok(()); + } + let hdrop = idata.u.hGlobal.0 as *mut HDROP; + // let mut temp_buffer = [0u16; FILENAME_MAXLENGTH]; + let file_count = DragQueryFileW(*hdrop, DRAGDROP_GET_COUNT, None); + for file_index in 0..file_count { + let mut buffer = [0u16; FILENAME_MAXLENGTH]; + let filename_length = DragQueryFileW(*hdrop, file_index, None) as usize; + let ret = DragQueryFileW(*hdrop, file_index, Some(&mut buffer)); + if ret == 0 { + log::error!("unable to read file name"); + continue; + } + if let Ok(file_name) = String::from_utf16(&buffer[0..filename_length]) { + if let Ok(path) = PathBuf::from_str(&file_name) { + paths.push(path); + } + } + } + ReleaseStgMedium(&mut idata); + } else { + *pdweffect = DROPEFFECT_NONE; + } -pub(crate) struct WindowsWindow { - inner: Rc, -} + let input = PlatformInput::FileDrop(crate::FileDropEvent::Entered { + position: Point { + x: Pixels(pt.x as _), + y: Pixels(pt.y as _), + }, + paths: crate::ExternalPaths(paths), + }); + self.0.handle_input(input); + } + Ok(()) + } -struct WindowCreateContext { - inner: Option>, - platform_inner: Rc, - handle: AnyWindowHandle, -} + fn DragOver( + &self, + grfkeystate: MODIFIERKEYS_FLAGS, + pt: &POINTL, + pdweffect: *mut DROPEFFECT, + ) -> windows::core::Result<()> { + let input = PlatformInput::FileDrop(crate::FileDropEvent::Pending { + position: Point { + x: Pixels(pt.x as _), + y: Pixels(pt.y as _), + }, + }); + self.0.handle_input(input); -impl WindowsWindow { - pub(crate) fn new( - platform_inner: Rc, - handle: AnyWindowHandle, - options: WindowOptions, - ) -> Self { - let dwexstyle = WINDOW_EX_STYLE::default(); - let classname = register_wnd_class(); - let windowname = HSTRING::from( - options - .titlebar - .as_ref() - .and_then(|titlebar| titlebar.title.as_ref()) - .map(|title| title.as_ref()) - .unwrap_or(""), - ); - let dwstyle = WS_OVERLAPPEDWINDOW & !WS_VISIBLE; - let mut x = CW_USEDEFAULT; - let mut y = CW_USEDEFAULT; - let mut nwidth = CW_USEDEFAULT; - let mut nheight = CW_USEDEFAULT; - match options.bounds { - WindowBounds::Fullscreen => {} - WindowBounds::Maximized => {} - WindowBounds::Fixed(bounds) => { - x = bounds.origin.x.0 as i32; - y = bounds.origin.y.0 as i32; - nwidth = bounds.size.width.0 as i32; - nheight = bounds.size.height.0 as i32; - } - }; - let hwndparent = HWND::default(); - let hmenu = HMENU::default(); - let hinstance = HINSTANCE::default(); - let mut context = WindowCreateContext { - inner: None, - platform_inner: platform_inner.clone(), - handle, - }; - let lpparam = Some(&context as *const _ as *const _); - unsafe { - CreateWindowExW( - dwexstyle, - classname, - &windowname, - dwstyle, - x, - y, - nwidth, - nheight, - hwndparent, - hmenu, - hinstance, - lpparam, - ) - }; - let wnd = Self { - inner: context.inner.unwrap(), - }; - platform_inner.window_handles.borrow_mut().insert(handle); - match options.bounds { - WindowBounds::Fullscreen => wnd.toggle_full_screen(), - WindowBounds::Maximized => wnd.maximize(), - WindowBounds::Fixed(_) => {} - } - unsafe { ShowWindow(wnd.inner.hwnd, SW_SHOW) }; - wnd + Ok(()) } - fn maximize(&self) { - unsafe { ShowWindow(self.inner.hwnd, SW_MAXIMIZE) }; + fn DragLeave(&self) -> windows::core::Result<()> { + let input = PlatformInput::FileDrop(crate::FileDropEvent::Exited); + self.0.handle_input(input); + + Ok(()) } -} -impl HasWindowHandle for WindowsWindow { - fn window_handle( + fn Drop( &self, - ) -> Result, raw_window_handle::HandleError> { - let raw = raw_window_handle::Win32WindowHandle::new(unsafe { - NonZeroIsize::new_unchecked(self.inner.hwnd.0) - }) - .into(); - Ok(unsafe { raw_window_handle::WindowHandle::borrow_raw(raw) }) + pdataobj: ::core::option::Option<&IDataObject>, + grfkeystate: MODIFIERKEYS_FLAGS, + pt: &POINTL, + pdweffect: *mut DROPEFFECT, + ) -> windows::core::Result<()> { + let input = PlatformInput::FileDrop(crate::FileDropEvent::Submit { + position: Point { + x: Pixels(pt.x as _), + y: Pixels(pt.y as _), + }, + }); + self.0.handle_input(input); + + Ok(()) } } -// todo!("windows") -impl HasDisplayHandle for WindowsWindow { - fn display_handle( - &self, - ) -> Result, raw_window_handle::HandleError> { - unimplemented!() +impl rwh::HasWindowHandle for WindowsWindow { + fn window_handle(&self) -> Result, rwh::HandleError> { + Ok(unsafe { rwh::WindowHandle::borrow_raw(self.inner.window_handle.raw_wh()) }) + } +} + +impl rwh::HasDisplayHandle for WindowsWindow { + fn display_handle(&self) -> Result, rwh::HandleError> { + Ok(unsafe { rwh::DisplayHandle::borrow_raw(self.inner.window_handle.raw_dh()) }) } } impl PlatformWindow for WindowsWindow { - fn bounds(&self) -> WindowBounds { - WindowBounds::Fixed(Bounds { - origin: self.inner.origin.get(), - size: self.inner.size.get(), - }) + fn bounds(&self) -> crate::WindowBounds { + let block = self.inner.bounds.borrow(); + crate::WindowBounds::Fixed(block.map(|v| crate::GlobalPixels(v as f32))) } - // todo!("windows") fn content_size(&self) -> Size { - let size = self.inner.size.get(); + let size = self.inner.renderer.borrow().viewport_size(); Size { - width: size.width.0.into(), - height: size.height.0.into(), + width: size.width.into(), + height: size.height.into(), } } - // todo!("windows") fn scale_factor(&self) -> f32 { - 1.0 + self.inner.scale_factor } - // todo!("windows") fn titlebar_height(&self) -> Pixels { - 20.0.into() + todo!() } - // todo!("windows") - fn appearance(&self) -> WindowAppearance { - WindowAppearance::Dark + fn appearance(&self) -> crate::WindowAppearance { + crate::WindowAppearance::Light } - // todo!("windows") - fn display(&self) -> Rc { - Rc::new(WindowsDisplay::new()) + fn display(&self) -> Rc { + Rc::clone(&self.display) } - fn mouse_position(&self) -> Point { - self.inner.mouse_position.get() + fn mouse_position(&self) -> crate::Point { + self.inner.mouse_position.borrow().clone() } - // todo!("windows") - fn modifiers(&self) -> Modifiers { - Modifiers::none() + fn modifiers(&self) -> crate::Modifiers { + self.inner.modifiers.borrow().clone() } - fn as_any_mut(&mut self) -> &mut dyn Any { + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self } - // todo!("windows") - fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { - self.inner.input_handler.set(Some(input_handler)); + fn set_input_handler(&mut self, input_handler: crate::PlatformInputHandler) { + (*self.inner.input_handler.borrow_mut()) = Some(input_handler); } - // todo!("windows") - fn take_input_handler(&mut self) -> Option { - self.inner.input_handler.take() + fn take_input_handler(&mut self) -> Option { + self.inner.input_handler.borrow_mut().take() } - // todo!("windows") fn prompt( &self, - level: PromptLevel, + level: crate::PromptLevel, msg: &str, detail: Option<&str>, answers: &[&str], - ) -> Receiver { - unimplemented!() + ) -> futures::channel::oneshot::Receiver { + let (done_tx, done_rx) = oneshot::channel(); + let mut config; + unsafe { + config = std::mem::zeroed::(); + config.cbSize = std::mem::size_of::() as _; + config.hwndParent = self.inner.window_handle.hwnd(); + let title; + let main_icon; + match level { + crate::PromptLevel::Info => { + title = windows::core::w!("Info"); + main_icon = TD_INFORMATION_ICON; + } + crate::PromptLevel::Warning => { + title = windows::core::w!("Warning"); + main_icon = TD_WARNING_ICON; + } + crate::PromptLevel::Critical => { + title = windows::core::w!("Critical"); + main_icon = TD_ERROR_ICON; + } + }; + config.pszWindowTitle = title; + config.Anonymous1.pszMainIcon = main_icon; + let instruction = encode_wide(msg); + config.pszMainInstruction = PCWSTR::from_raw(instruction.as_ptr()); + let hints_encoded; + if let Some(hints) = detail { + hints_encoded = encode_wide(hints); + config.pszContent = PCWSTR::from_raw(hints_encoded.as_ptr()); + }; + let mut buttons = Vec::new(); + let mut btn_encoded = Vec::new(); + for (index, btn_string) in answers.iter().enumerate() { + let encoded = encode_wide(btn_string); + buttons.push(TASKDIALOG_BUTTON { + nButtonID: index as _, + pszButtonText: PCWSTR::from_raw(encoded.as_ptr()), + }); + btn_encoded.push(encoded); + } + config.cButtons = buttons.len() as _; + config.pButtons = buttons.as_ptr(); + } + self.foreground_executor + .spawn(async move { + unsafe { + config.pfCallback = None; + let mut res = std::mem::zeroed(); + let _ = TaskDialogIndirect(&config, Some(&mut res), None, None) + .inspect_err(log_windows_error); + + let _ = done_tx.send(res as usize); + } + }) + .detach(); + + done_rx } - // todo!("windows") fn activate(&self) {} - // todo!("windows") fn set_title(&mut self, title: &str) { - unsafe { SetWindowTextW(self.inner.hwnd, &HSTRING::from(title)) } - .inspect_err(|e| log::error!("Set title failed: {e}")) - .ok(); + self.inner.window_handle.set_title(title); } - // todo!("windows") fn set_edited(&mut self, edited: bool) {} - // todo!("windows") - fn show_character_palette(&self) {} + fn show_character_palette(&self) { + todo!() + } - // todo!("windows") - fn minimize(&self) {} + fn minimize(&self) { + // TODO: + } - // todo!("windows") - fn zoom(&self) {} + fn zoom(&self) { + todo!() + } - // todo!("windows") - fn toggle_full_screen(&self) {} + fn toggle_full_screen(&self) { + todo!() + } - // todo!("windows") fn on_request_frame(&self, callback: Box) { self.inner.callbacks.borrow_mut().request_frame = Some(callback); } - // todo!("windows") - fn on_input(&self, callback: Box bool>) { + fn on_input(&self, callback: Box bool>) { self.inner.callbacks.borrow_mut().input = Some(callback); } - // todo!("windows") fn on_active_status_change(&self, callback: Box) { self.inner.callbacks.borrow_mut().active_status_change = Some(callback); } - // todo!("windows") fn on_resize(&self, callback: Box, f32)>) { self.inner.callbacks.borrow_mut().resize = Some(callback); } - // todo!("windows") fn on_fullscreen(&self, callback: Box) { self.inner.callbacks.borrow_mut().fullscreen = Some(callback); } - // todo!("windows") fn on_moved(&self, callback: Box) { self.inner.callbacks.borrow_mut().moved = Some(callback); } - // todo!("windows") fn on_should_close(&self, callback: Box bool>) { self.inner.callbacks.borrow_mut().should_close = Some(callback); } - // todo!("windows") fn on_close(&self, callback: Box) { self.inner.callbacks.borrow_mut().close = Some(callback); } - // todo!("windows") fn on_appearance_changed(&self, callback: Box) { self.inner.callbacks.borrow_mut().appearance_changed = Some(callback); } - // todo!("windows") - fn is_topmost_for_position(&self, position: Point) -> bool { - true + fn is_topmost_for_position(&self, position: crate::Point) -> bool { + todo!() } - // todo!("windows") - fn draw(&self, scene: &Scene) { - self.inner.renderer.borrow_mut().draw(scene) + fn draw(&self, scene: &crate::Scene) { + self.inner.renderer.borrow_mut().draw(scene); } - // todo!("windows") - fn sprite_atlas(&self) -> Arc { + fn sprite_atlas(&self) -> std::sync::Arc { self.inner.renderer.borrow().sprite_atlas().clone() } } -fn register_wnd_class() -> PCWSTR { - const CLASS_NAME: PCWSTR = w!("Zed::Window"); +impl RawWindow { + pub fn new(handle: HWND) -> Self { + RawWindow { handle } + } - static ONCE: Once = Once::new(); - ONCE.call_once(|| { - let wc = WNDCLASSW { - lpfnWndProc: Some(wnd_proc), - hCursor: unsafe { LoadCursorW(None, IDC_ARROW).ok().unwrap() }, - lpszClassName: PCWSTR(CLASS_NAME.as_ptr()), - ..Default::default() + pub fn hwnd(&self) -> HWND { + self.handle + } + + pub fn set_title(&self, title: &str) { + let title_vec = encode_wide(title); + unsafe { + SetWindowTextW(self.hwnd(), PCWSTR::from_raw(title_vec.as_ptr())).log_err(); + } + } + + pub fn set_data(&self, data: Rc) { + unsafe { + set_windowdata(self.hwnd(), data); + } + } + + pub fn show(&self) { + unsafe { + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow + // UpdateWindow(self.hwnd()); + ShowWindow(self.hwnd(), SW_SHOW); + println!("Show window Error: {:?}", std::io::Error::last_os_error()); + } + } + + pub fn size(&self) -> Size { + let mut rect: RECT = unsafe { mem::zeroed() }; + unsafe { GetClientRect(self.hwnd(), &mut rect).log_err() }; + Size { + width: (rect.right - rect.left) as i32, + height: (rect.bottom - rect.top) as i32, + } + } + + pub fn scale_factor(&self) -> f32 { + (self.get_dpi() as f32) / (96 as f32) + } + + fn get_dpi(&self) -> u32 { + unsafe { + let res = GetDpiForWindow(self.hwnd()); + if res > 0 { + return res; + } + // failed + let monitor = { MonitorFromWindow(self.hwnd(), MONITOR_DEFAULTTONEAREST) }; + if monitor.is_invalid() { + return 96; + } + + let mut dpi_x = 0; + let mut dpi_y = 0; + if GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &mut dpi_x, &mut dpi_y).is_ok() { + dpi_x + } else { + 96 + } + } + } + + pub fn raw_wh(&self) -> rwh::RawWindowHandle { + let mut window_handle = rwh::Win32WindowHandle::new(unsafe { + // SAFETY: Handle will never be zero. + std::num::NonZeroIsize::new_unchecked(self.hwnd().0) + }); + let hinstance = unsafe { + windows::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW(self.hwnd(), GWLP_HINSTANCE) }; - unsafe { RegisterClassW(&wc) }; - }); + window_handle.hinstance = std::num::NonZeroIsize::new(hinstance); - CLASS_NAME -} + rwh::RawWindowHandle::Win32(window_handle) + } -unsafe extern "system" fn wnd_proc( - hwnd: HWND, - msg: u32, - wparam: WPARAM, - lparam: LPARAM, -) -> LRESULT { - if msg == WM_NCCREATE { - let cs = lparam.0 as *const CREATESTRUCTW; - let cs = unsafe { &*cs }; - let ctx = cs.lpCreateParams as *mut WindowCreateContext; - let ctx = unsafe { &mut *ctx }; - let inner = Rc::new(WindowsWindowInner::new( - hwnd, - cs, - ctx.platform_inner.clone(), - ctx.handle, - )); - let weak = Box::new(Rc::downgrade(&inner)); - unsafe { set_window_long(hwnd, GWLP_USERDATA, Box::into_raw(weak) as isize) }; - ctx.inner = Some(inner); - return LRESULT(1); - } - let ptr = unsafe { get_window_long(hwnd, GWLP_USERDATA) } as *mut Weak; - if ptr.is_null() { - return unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) }; - } - let inner = unsafe { &*ptr }; - let r = if let Some(inner) = inner.upgrade() { - inner.handle_msg(msg, wparam, lparam) - } else { - unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) } - }; - if msg == WM_NCDESTROY { - unsafe { set_window_long(hwnd, GWLP_USERDATA, 0) }; - unsafe { std::mem::drop(Box::from_raw(ptr)) }; - } - r + pub fn raw_dh(&self) -> rwh::RawDisplayHandle { + rwh::RawDisplayHandle::Windows(rwh::WindowsDisplayHandle::new()) + } } -unsafe fn get_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX) -> isize { - #[cfg(target_pointer_width = "64")] - unsafe { - GetWindowLongPtrW(hwnd, nindex) +impl Drop for RawWindow { + fn drop(&mut self) { + unsafe { + let _ = RevokeDragDrop(self.handle); + } } - #[cfg(target_pointer_width = "32")] - unsafe { - GetWindowLongW(hwnd, nindex) as isize +} + +unsafe impl blade_rwh::HasRawWindowHandle for RawWindow { + fn raw_window_handle(&self) -> blade_rwh::RawWindowHandle { + let mut window_handle = blade_rwh::Win32WindowHandle::empty(); + window_handle.hwnd = self.hwnd().0 as *mut _; + let hinstance = unsafe { + windows::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW(self.hwnd(), GWLP_HINSTANCE) + }; + window_handle.hinstance = hinstance as *mut _; + + blade_rwh::RawWindowHandle::Win32(window_handle) } } -unsafe fn set_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX, dwnewlong: isize) -> isize { - #[cfg(target_pointer_width = "64")] - unsafe { - SetWindowLongPtrW(hwnd, nindex, dwnewlong) +unsafe impl blade_rwh::HasRawDisplayHandle for RawWindow { + fn raw_display_handle(&self) -> blade_rwh::RawDisplayHandle { + blade_rwh::RawDisplayHandle::Windows(blade_rwh::WindowsDisplayHandle::empty()) } - #[cfg(target_pointer_width = "32")] - unsafe { - SetWindowLongW(hwnd, nindex, dwnewlong as i32) as isize +} + +fn parse_window_options( + options: &WindowOptions, +) -> (WINDOW_STYLE, WINDOW_EX_STYLE, Option, Option) { + let mut style = WINODW_STYLE; + // https://learn.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles + let exstyle = WINDOW_EX_STYLE::default() | WINODW_EXTRA_EXSTYLE; + let mut width = None; + let mut height = None; + if options.show { + style |= WS_VISIBLE + } + if options.kind == WindowKind::PopUp { + style |= WS_POPUP; + } + match options.bounds { + crate::WindowBounds::Fullscreen => style &= !WS_OVERLAPPEDWINDOW, + crate::WindowBounds::Maximized => style |= WS_MAXIMIZE, + crate::WindowBounds::Maximized => {} + crate::WindowBounds::Fixed(bounds) => { + width = Some(bounds.size.width.0 as _); + height = Some(bounds.size.height.0 as _); + } } + + (style, exstyle, width, height) } diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 45d9ef0234d1f..56dc0103ecad0 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -674,6 +674,7 @@ impl Terminal { if pid < 0 { pid = self.shell_pid as i32; } + println!("Updated PID: {}", pid); if let Some(process_info) = LocalProcessInfo::with_root_pid(pid as u32) { let res = self diff --git a/crates/zed/build.rs b/crates/zed/build.rs index daea199e21ac1..50fe6e7f2367b 100644 --- a/crates/zed/build.rs +++ b/crates/zed/build.rs @@ -23,6 +23,10 @@ fn main() { println!("cargo:rustc-link-arg=-Wl,-ObjC"); } + if cfg!(target_os = "windows") { + println!("cargo:rustc-link-arg=/stack:{}", 4 * 1024 * 1024); + } + // Populate git sha environment variable if git is available println!("cargo:rerun-if-changed=../../.git/logs/HEAD"); if let Ok(output) = Command::new("git").args(["rev-parse", "HEAD"]).output() { From 4e2af697aac0f3bd143a939ec14105e85363c170 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 17:29:43 +0800 Subject: [PATCH 05/39] fix build on wsl --- crates/gpui/build.rs | 5 ++++- crates/zed/build.rs | 5 ++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index 8473547730ce5..003813c0a7d1e 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -23,7 +23,10 @@ fn main() { compile_metal_shaders(&header_path); // We are using Windows Visita+, right..? - if cfg!(target_os = "windows") { + // if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" { + #[cfg(target_os = "windows")] + { + println!("cargo:rustc-link-arg=/stack:{}", 4 * 1024 * 1024); println!("cargo:rerun-if-changed=assets/windows/manifest.xml"); let mut res = winresource::WindowsResource::new(); let manifest_path = std::env::current_dir() diff --git a/crates/zed/build.rs b/crates/zed/build.rs index 50fe6e7f2367b..738890519dca4 100644 --- a/crates/zed/build.rs +++ b/crates/zed/build.rs @@ -23,9 +23,8 @@ fn main() { println!("cargo:rustc-link-arg=-Wl,-ObjC"); } - if cfg!(target_os = "windows") { - println!("cargo:rustc-link-arg=/stack:{}", 4 * 1024 * 1024); - } + #[cfg(target_os = "windows")] + println!("cargo:rustc-link-arg=/stack:{}", 4 * 1024 * 1024); // Populate git sha environment variable if git is available println!("cargo:rerun-if-changed=../../.git/logs/HEAD"); From 0d3ea370ff76d8f424fd3855bd529d26b04c54ff Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 18:21:40 +0800 Subject: [PATCH 06/39] fix build on linux --- crates/gpui/src/platform/linux.rs | 2 -- crates/gpui/src/platform/linux/platform.rs | 11 ++++++----- crates/gpui/src/platform/linux/wayland/window.rs | 2 +- crates/gpui/src/platform/linux/x11/window.rs | 6 +++--- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/gpui/src/platform/linux.rs b/crates/gpui/src/platform/linux.rs index f334b23399801..a0a27a33a74a1 100644 --- a/crates/gpui/src/platform/linux.rs +++ b/crates/gpui/src/platform/linux.rs @@ -1,12 +1,10 @@ mod client; mod dispatcher; mod platform; -mod text_system; mod util; mod wayland; mod x11; pub(crate) use dispatcher::*; pub(crate) use platform::*; -pub(crate) use text_system::*; // pub(crate) use x11::*; diff --git a/crates/gpui/src/platform/linux/platform.rs b/crates/gpui/src/platform/linux/platform.rs index 8db32e7264e76..58b49917429c1 100644 --- a/crates/gpui/src/platform/linux/platform.rs +++ b/crates/gpui/src/platform/linux/platform.rs @@ -19,13 +19,14 @@ use parking_lot::Mutex; use time::UtcOffset; use wayland_client::Connection; +use crate::platform::cross_platform::CosmicTextSystem; use crate::platform::linux::client::Client; use crate::platform::linux::wayland::WaylandClient; use crate::{ Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId, - ForegroundExecutor, Keymap, LinuxDispatcher, LinuxTextSystem, Menu, PathPromptOptions, - Platform, PlatformDisplay, PlatformInput, PlatformTextSystem, PlatformWindow, Result, - SemanticVersion, Task, WindowOptions, + ForegroundExecutor, Keymap, LinuxDispatcher, Menu, PathPromptOptions, Platform, + PlatformDisplay, PlatformInput, PlatformTextSystem, PlatformWindow, Result, SemanticVersion, + Task, WindowOptions, }; use super::x11::X11Client; @@ -49,7 +50,7 @@ pub(crate) struct LinuxPlatformInner { pub(crate) loop_signal: LoopSignal, pub(crate) background_executor: BackgroundExecutor, pub(crate) foreground_executor: ForegroundExecutor, - pub(crate) text_system: Arc, + pub(crate) text_system: Arc, pub(crate) callbacks: RefCell, } @@ -70,7 +71,7 @@ impl LinuxPlatform { let use_wayland = wayland_display.is_some() && !wayland_display.unwrap().is_empty(); let (main_sender, main_receiver) = calloop::channel::channel::(); - let text_system = Arc::new(LinuxTextSystem::new()); + let text_system = Arc::new(CosmicTextSystem::new()); let callbacks = RefCell::new(Callbacks::default()); let event_loop = EventLoop::try_new().unwrap(); diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index 11e1743b037f1..f85088c9dcb53 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -14,7 +14,7 @@ use wayland_client::{protocol::wl_surface, Proxy}; use wayland_protocols::wp::viewporter::client::wp_viewport; use wayland_protocols::xdg::shell::client::xdg_toplevel; -use crate::platform::blade::BladeRenderer; +use crate::platform::cross_platform::BladeRenderer; use crate::platform::linux::wayland::display::WaylandDisplay; use crate::platform::{PlatformAtlas, PlatformInputHandler, PlatformWindow}; use crate::scene::Scene; diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui/src/platform/linux/x11/window.rs index f60f7f19b951d..5a7ff1529af7d 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui/src/platform/linux/x11/window.rs @@ -2,9 +2,9 @@ #![allow(unused)] use crate::{ - platform::blade::BladeRenderer, size, Bounds, GlobalPixels, Modifiers, Pixels, PlatformAtlas, - PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PromptLevel, - Scene, Size, WindowAppearance, WindowBounds, WindowOptions, + platform::cross_platform::BladeRenderer, size, Bounds, GlobalPixels, Modifiers, Pixels, + PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, + PromptLevel, Scene, Size, WindowAppearance, WindowBounds, WindowOptions, }; use blade_graphics as gpu; use parking_lot::Mutex; From f0e58ccf55e4118ff355ef5fbd6b267fd4bc7dd4 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 21:15:06 +0800 Subject: [PATCH 07/39] draw window every 16ms --- crates/gpui/src/platform/windows/constants.rs | 3 + crates/gpui/src/platform/windows/platform.rs | 5 +- crates/gpui/src/platform/windows/window.rs | 60 +++++++++++++++---- 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/crates/gpui/src/platform/windows/constants.rs b/crates/gpui/src/platform/windows/constants.rs index 0030d17e5e3a9..473290eaedeb6 100644 --- a/crates/gpui/src/platform/windows/constants.rs +++ b/crates/gpui/src/platform/windows/constants.rs @@ -21,6 +21,9 @@ pub const WINODW_EXTRA_EXSTYLE: WINDOW_EX_STYLE = WS_EX_ACCEPTFILES; // events // Values in the range 0x0400 (the value of WM_USER) through 0x7FFF are // available for message identifiers for private window classes. +pub const WINDOW_REFRESH_TIMER: usize = 1; +// the minimum value is 0xA, which means only max to 100fps +pub const WINODW_REFRESH_INTERVAL: u32 = 16; pub const MAIN_DISPATCH: u32 = WM_USER + 1; pub const WINDOW_CLOSE: u32 = WM_USER + 2; pub const WINDOW_OPEN: u32 = WM_USER + 3; diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 968c0c6e1a2fc..7e3f951487d01 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -169,7 +169,7 @@ impl WindowsPlatformInner { PostQuitMessage(0); } } - let old_val = self.windows_count.fetch_sub(1, Ordering::SeqCst); + self.windows_count.fetch_sub(1, Ordering::SeqCst); } } @@ -198,9 +198,6 @@ impl Platform for WindowsPlatform { if let Some(ref mut func) = self.inner.callbacks.borrow_mut().quit { func(); } - unsafe { - let _ = DestroyWindow(self.inner.dispatch_window_handle); - } } fn quit(&self) { diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 7c371525f0dea..c05a882df5aac 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -51,15 +51,17 @@ use windows::{ }, Shell::{DragQueryFileA, DragQueryFileW, HDROP}, WindowsAndMessaging::{ - CreateWindowExW, DefWindowProcW, GetClientRect, GetCursorPos, MessageBoxExW, - PostMessageW, PostQuitMessage, RegisterClassExW, SetWindowTextW, ShowWindow, - CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, GWLP_HINSTANCE, HMENU, SIZE_MINIMIZED, - SW_SHOW, WINDOW_EX_STYLE, WINDOW_STYLE, WM_CHAR, WM_CLOSE, WM_COMMAND, WM_DESTROY, - WM_DROPFILES, WM_IME_STARTCOMPOSITION, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDBLCLK, - WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, WM_MBUTTONUP, - WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_PAINT, WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, - WM_RBUTTONUP, WM_SIZE, WM_XBUTTONDBLCLK, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSEXW, - WS_EX_ACCEPTFILES, WS_MAXIMIZE, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_VISIBLE, + CreateWindowExW, DefWindowProcW, GetClientRect, GetCursorPos, KillTimer, + MessageBoxExW, PostMessageW, PostQuitMessage, RegisterClassExW, SetTimer, + SetWindowTextW, ShowWindow, CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, GWLP_HINSTANCE, + HMENU, SIZE_MINIMIZED, SW_SHOW, TIMERPROC, WA_ACTIVE, WA_CLICKACTIVE, WA_INACTIVE, + WINDOW_EX_STYLE, WINDOW_STYLE, WM_ACTIVATE, WM_CHAR, WM_CLOSE, WM_COMMAND, + WM_DESTROY, WM_DROPFILES, WM_IME_STARTCOMPOSITION, WM_KEYDOWN, WM_KEYUP, + WM_LBUTTONDBLCLK, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, + WM_MBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_PAINT, WM_RBUTTONDBLCLK, + WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SIZE, WM_TIMER, WM_XBUTTONDBLCLK, WM_XBUTTONDOWN, + WM_XBUTTONUP, WNDCLASSEXW, WS_EX_ACCEPTFILES, WS_MAXIMIZE, WS_OVERLAPPEDWINDOW, + WS_POPUP, WS_VISIBLE, }, }, }, @@ -72,7 +74,8 @@ use crate::{ Action, Bounds, DisplayId, ForegroundExecutor, Modifiers, Pixels, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, Size, WindowKind, WindowOptions, WindowsWindowBase, WindowsWinodwDataWrapper, DRAGDROP_GET_COUNT, FILENAME_MAXLENGTH, - MENU_ACTIONS, WINDOW_CLOSE, WINODW_EXTRA_EXSTYLE, WINODW_STYLE, + MENU_ACTIONS, WINDOW_CLOSE, WINDOW_REFRESH_TIMER, WINODW_EXTRA_EXSTYLE, + WINODW_REFRESH_INTERVAL, WINODW_STYLE, }; use super::{display::WindowsDisplay, WINDOW_CLASS}; @@ -170,6 +173,14 @@ impl WindowsWindow { bounds, renderer, ); + unsafe { + SetTimer( + raw_window_handle, + WINDOW_REFRESH_TIMER, + WINODW_REFRESH_INTERVAL, + TIMERPROC::None, + ) + }; let windows_dragdrop = unsafe { set_windowdata(raw_window_handle, WindowsWinodwDataWrapper(inner.clone())); let drop_target = WindowsDragDropTarget(inner.clone()); @@ -318,11 +329,21 @@ impl WindowsWindowinner { } } } + + fn set_focused(&self, focus: bool) { + if let Some(ref mut func) = self.callbacks.borrow_mut().active_status_change { + func(focus); + } + } } impl WindowsWindowBase for WindowsWindowinner { unsafe fn handle_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT { match message { + WM_TIMER => { + self.update(); + LRESULT(0) + } WM_PAINT => { self.request_redraw(); ValidateRect(self.window_handle.hwnd(), None); @@ -336,6 +357,10 @@ impl WindowsWindowBase for WindowsWindowinner { WPARAM::default(), LPARAM::default(), ); + if let Some(func) = self.callbacks.borrow_mut().close.take() { + func(); + } + KillTimer(self.window_handle.hwnd(), WINDOW_REFRESH_TIMER); PostQuitMessage(0); LRESULT(0) } @@ -350,6 +375,15 @@ impl WindowsWindowBase for WindowsWindowinner { ) .inspect_err(log_windows_error); } + self.update(); + LRESULT(0) + } + WM_ACTIVATE => { + if loword!(wparam.0, u16) as u32 & (WA_ACTIVE | WA_CLICKACTIVE) > 0 { + self.set_focused(true); + } else if loword!(wparam.0, u16) as u32 & WA_INACTIVE > 0 { + self.set_focused(false); + } LRESULT(0) } WM_KEYDOWN | WM_KEYUP => { @@ -376,6 +410,7 @@ impl WindowsWindowBase for WindowsWindowinner { let (new_pos, input) = parse_mouse_movement(wparam, lparam, modifiers); *self.mouse_position.borrow_mut() = new_pos; self.handle_input(input); + self.update(); LRESULT(0) } WM_CHAR => { @@ -418,6 +453,11 @@ impl WindowsWindowBase for WindowsWindowinner { config.ptCurrentPos.y = cursor.y; ImmSetCompositionWindow(ctx, &config as _); ImmReleaseContext(self.window_handle.hwnd(), ctx); + self.update(); + println!( + "Set composition pos: ({}, {})", + config.ptCurrentPos.x, config.ptCurrentPos.y + ); LRESULT(0) } _ => DefWindowProcW(self.window_handle.hwnd(), message, wparam, lparam), From 47aa507cff46f1556496267c92a48f9cd2a0235a Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 22:14:54 +0800 Subject: [PATCH 08/39] better error --- .../gpui/src/platform/windows/dispatcher.rs | 6 +- crates/gpui/src/platform/windows/platform.rs | 83 +++++-------------- crates/gpui/src/platform/windows/utils.rs | 43 +++++++--- crates/gpui/src/platform/windows/window.rs | 24 +++--- 4 files changed, 68 insertions(+), 88 deletions(-) diff --git a/crates/gpui/src/platform/windows/dispatcher.rs b/crates/gpui/src/platform/windows/dispatcher.rs index 7ea843ded620c..dba9ef8057912 100644 --- a/crates/gpui/src/platform/windows/dispatcher.rs +++ b/crates/gpui/src/platform/windows/dispatcher.rs @@ -1,4 +1,4 @@ -use crate::{log_windows_error, PlatformDispatcher, TaskLabel}; +use crate::{log_windows_error, log_windows_error_with_message, PlatformDispatcher, TaskLabel}; use async_task::Runnable; use parking::{Parker, Unparker}; use parking_lot::Mutex; @@ -114,10 +114,10 @@ fn dispatcher_init() -> anyhow::Result<(PTP_POOL, HANDLE)> { let threadpool = unsafe { let mut threadpool_handle = CreateThreadpool(None); if threadpool_handle.0 == 0 { - log::error!("Windows error: {}", std::io::Error::last_os_error()); + log_windows_error_with_message!("Error creating threadpool"); threadpool_handle = CreateThreadpool(None); if threadpool_handle.0 == 0 { - log::error!("Windows error: {}", std::io::Error::last_os_error()); + log_windows_error_with_message!("Error creating threadpool"); return anyhow::Result::Err(anyhow::anyhow!("Error init dispatcher")); } } diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 7e3f951487d01..c85f287104e53 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -64,10 +64,11 @@ use windows::{ }; use crate::{ - encode_wide, log_windows_error, platform::cross_platform::CosmicTextSystem, set_windowdata, - Keystroke, WindowsWindow, WindowsWindowBase, WindowsWinodwDataWrapper, ACCEL_FALT, - ACCEL_FCONTROL, ACCEL_FSHIFT, ACCEL_FVIRTKEY, CF_UNICODETEXT, DISPATCH_WINDOW_CLASS, - DISPATCH_WINDOW_EXSTYLE, DISPATCH_WINDOW_STYLE, MAIN_DISPATCH, MENU_ACTIONS, WINDOW_CLOSE, + encode_wide, log_windows_error, log_windows_error_with_message, + platform::cross_platform::CosmicTextSystem, set_windowdata, Keystroke, WindowsWindow, + WindowsWindowBase, WindowsWinodwDataWrapper, ACCEL_FALT, ACCEL_FCONTROL, ACCEL_FSHIFT, + ACCEL_FVIRTKEY, CF_UNICODETEXT, DISPATCH_WINDOW_CLASS, DISPATCH_WINDOW_EXSTYLE, + DISPATCH_WINDOW_STYLE, MAIN_DISPATCH, MENU_ACTIONS, WINDOW_CLOSE, }; use crate::{ Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId, @@ -276,42 +277,29 @@ impl Platform for WindowsPlatform { let dialog = show_openfile_dialog(options).expect("error show openfile dialog"); if let Ok(_) = dialog.Show(None) { let Ok(items) = dialog.GetResults() else { - log::error!( - "Error get result from dialog {}", - std::io::Error::last_os_error() - ); + log_windows_error_with_message!("Error get result from dialog"); let _ = tx.send(None); return; }; let Ok(count) = items.GetCount() else { - log::error!( - "Error get results count from dialog {}", - std::io::Error::last_os_error() - ); + log_windows_error_with_message!("Error get results count from dialog"); let _ = tx.send(None); return; }; let mut path_vec = Vec::new(); for index in 0..count { let Ok(item) = items.GetItemAt(index) else { - log::error!( - "Error get item dialog {}", - std::io::Error::last_os_error() - ); + log_windows_error_with_message!("Error get item dialog"); continue; }; let Ok(item_string) = item.GetDisplayName(SIGDN_PARENTRELATIVEPARSING) else { - log::error!( - "Error parsing item name {}", - std::io::Error::last_os_error() - ); + log_windows_error_with_message!("Error parsing item name"); continue; }; let Ok(path_string) = item_string.to_string() else { - log::error!( - "Error parsing item name from utf16 to string {}", - std::io::Error::last_os_error() + log_windows_error_with_message!( + "Error parsing item name from utf16 to string" ); continue; }; @@ -456,11 +444,7 @@ impl Platform for WindowsPlatform { let mut info = unsafe { std::mem::zeroed() }; let ret = unsafe { GetTimeZoneInformation(&mut info) }; if ret == TIME_ZONE_ID_INVALID { - log::error!( - "Unable to get local timezone: {}", - std::io::Error::last_os_error() - ); - + log_windows_error_with_message!("Unable to get local timezone"); return UtcOffset::UTC; } // Windows treat offset as: @@ -502,7 +486,7 @@ impl Platform for WindowsPlatform { _ => LoadImageW(None, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE), }; if handle.is_err() { - log::error!("Windows error: {}", std::io::Error::last_os_error()); + log_windows_error_with_message!("Error loading cursor image"); return; } let _ = SetCursor(HCURSOR(handle.unwrap().0)); @@ -517,12 +501,13 @@ impl Platform for WindowsPlatform { //todo!(windows) fn write_to_clipboard(&self, item: ClipboardItem) { unsafe { - if OpenClipboard(self.inner.dispatch_window_handle).is_err() { - log::error!("Windows error: {}", std::io::Error::last_os_error()); + if OpenClipboard(self.inner.dispatch_window_handle) + .inspect_err(log_windows_error) + .is_err() + { return; } - if EmptyClipboard().is_err() { - log::error!("Windows error: {}", std::io::Error::last_os_error()); + if EmptyClipboard().inspect_err(log_windows_error).is_err() { return; } // MultiByteToWideChar(codepage, dwflags, lpmultibytestr, lpwidecharstr); @@ -532,8 +517,10 @@ impl Platform for WindowsPlatform { let handle = GlobalLock(global); u_memcpy(handle as _, data_ptr.as_ptr() as _, count as _); let _ = GlobalUnlock(global); - if SetClipboardData(CF_UNICODETEXT, HANDLE(global.0 as isize)).is_err() { - log::error!("Windows error: {}", std::io::Error::last_os_error()); + if SetClipboardData(CF_UNICODETEXT, HANDLE(global.0 as isize)) + .inspect_err(log_windows_error) + .is_err() + { return; } let _ = CloseClipboard(); @@ -542,26 +529,6 @@ impl Platform for WindowsPlatform { //todo!(windows) fn read_from_clipboard(&self) -> Option { - // unsafe { - // if OpenClipboard(self.inner.dispatch_window_handle).is_err() { - // log::error!("Windows error: {}", std::io::Error::last_os_error()); - // return None; - // } - // let ret = GetClipboardData(CF_UNICODETEXT); - // if ret.is_err() { - // log::error!("Windows error: {}", std::io::Error::last_os_error()); - // return None; - // } - // let data_ptr = GlobalLock(HGLOBAL(ret.unwrap().0 as _)) as *mut Vec; - // // let x: *mut Vec = data_ptr as _; - // let data = String::from_utf16_lossy(&*data_ptr); - // let _ = CloseClipboard(); - - // Some(ClipboardItem { - // text: data, - // metadata: None, - // }) - // } unsafe { let Ok(clipboard) = OleGetClipboard().inspect_err(log_windows_error) else { return None; @@ -648,10 +615,6 @@ fn platform_init() -> anyhow::Result<()> { unsafe { SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE) .inspect_err(log_windows_error)?; - // if CoInitializeEx(None, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE).is_err() { - // log::error!("Windows error: {}", std::io::Error::last_os_error()); - // return anyhow::Result::Err(anyhow::anyhow!("Set dpi awareness failed")); - // } OleInitialize(None).inspect_err(log_windows_error)?; Ok(()) } @@ -670,7 +633,7 @@ fn open_target(target: String) { SW_SHOWDEFAULT, ); if ret.0 <= 32 { - log::error!("Unable to open: {}", std::io::Error::last_os_error()); + log_windows_error_with_message!("Unable to open target"); return; } } diff --git a/crates/gpui/src/platform/windows/utils.rs b/crates/gpui/src/platform/windows/utils.rs index c7566373507b6..97678b71be2ca 100644 --- a/crates/gpui/src/platform/windows/utils.rs +++ b/crates/gpui/src/platform/windows/utils.rs @@ -1,4 +1,4 @@ -use std::{iter::once, panic::Location}; +use std::iter::once; use collections::VecDeque; use windows::Win32::{ @@ -11,7 +11,7 @@ use windows::Win32::{ UI::WindowsAndMessaging::{GetWindowLongPtrW, SetWindowLongPtrW, GWL_USERDATA}, }; -use crate::MonitorHandle; +use crate::{log_windows_error_with_message, MonitorHandle}; pub fn encode_wide(input: &str) -> Vec { input.encode_utf16().chain(once(0)).collect::>() @@ -91,18 +91,37 @@ pub unsafe fn get_windowdata(handle: HWND) -> isize { GetWindowLongPtrW(handle, GWL_USERDATA) } -pub fn log_windows_error(e: &windows::core::Error) { - let caller = Location::caller(); - log::error!( - "Windows error at {}:{}: {}", - caller.file(), - caller.line(), - std::io::Error::last_os_error() - ); +pub fn log_windows_error(_e: &windows::core::Error) { + log_windows_error_with_message!(None); } -pub fn log_anyhow_error(_: &anyhow::Error) { - log::error!("Windows error: {}", std::io::Error::last_os_error()); +/// Log windows errors. +/// +/// # examples +/// ```rust +/// log_windows_error_with_message!("Error"); +/// log_windows_error_with_message!(None); +/// ``` +#[macro_export] +macro_rules! log_windows_error_with_message { + ($s: literal) => {{ + let caller = std::panic::Location::caller(); + log::error!( + "$s at {}:{}: {}", + caller.file(), + caller.line(), + std::io::Error::last_os_error() + ); + }}; + (None) => {{ + let caller = std::panic::Location::caller(); + log::error!( + "Windows error at {}:{}: {}", + caller.file(), + caller.line(), + std::io::Error::last_os_error() + ); + }}; } unsafe extern "system" fn monitor_enum_proc( diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index c05a882df5aac..0e8efb0b96c20 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -68,14 +68,14 @@ use windows::{ }; use crate::{ - available_monitors, encode_wide, get_module_handle, hiword, log_windows_error, loword, - parse_dropfiles, parse_keyboard_input, parse_mouse_button, parse_mouse_movement, - parse_mouse_wheel, parse_system_key, platform::cross_platform::BladeRenderer, set_windowdata, - Action, Bounds, DisplayId, ForegroundExecutor, Modifiers, Pixels, PlatformDisplay, - PlatformInput, PlatformInputHandler, PlatformWindow, Point, Size, WindowKind, WindowOptions, - WindowsWindowBase, WindowsWinodwDataWrapper, DRAGDROP_GET_COUNT, FILENAME_MAXLENGTH, - MENU_ACTIONS, WINDOW_CLOSE, WINDOW_REFRESH_TIMER, WINODW_EXTRA_EXSTYLE, - WINODW_REFRESH_INTERVAL, WINODW_STYLE, + available_monitors, encode_wide, get_module_handle, hiword, log_windows_error, + log_windows_error_with_message, loword, parse_dropfiles, parse_keyboard_input, + parse_mouse_button, parse_mouse_movement, parse_mouse_wheel, parse_system_key, + platform::cross_platform::BladeRenderer, set_windowdata, Action, Bounds, DisplayId, + ForegroundExecutor, Modifiers, Pixels, PlatformDisplay, PlatformInput, PlatformInputHandler, + PlatformWindow, Point, Size, WindowKind, WindowOptions, WindowsWindowBase, + WindowsWinodwDataWrapper, DRAGDROP_GET_COUNT, FILENAME_MAXLENGTH, MENU_ACTIONS, WINDOW_CLOSE, + WINDOW_REFRESH_TIMER, WINODW_EXTRA_EXSTYLE, WINODW_REFRESH_INTERVAL, WINODW_STYLE, }; use super::{display::WindowsDisplay, WINDOW_CLASS}; @@ -360,7 +360,7 @@ impl WindowsWindowBase for WindowsWindowinner { if let Some(func) = self.callbacks.borrow_mut().close.take() { func(); } - KillTimer(self.window_handle.hwnd(), WINDOW_REFRESH_TIMER); + let _ = KillTimer(self.window_handle.hwnd(), WINDOW_REFRESH_TIMER); PostQuitMessage(0); LRESULT(0) } @@ -401,7 +401,6 @@ impl WindowsWindowBase for WindowsWindowinner { let modifiers = self.modifiers.borrow(); let key = parse_mouse_button(message, wparam, lparam, &modifiers); self.handle_input(key); - self.update(); LRESULT(0) } @@ -410,7 +409,6 @@ impl WindowsWindowBase for WindowsWindowinner { let (new_pos, input) = parse_mouse_movement(wparam, lparam, modifiers); *self.mouse_position.borrow_mut() = new_pos; self.handle_input(input); - self.update(); LRESULT(0) } WM_CHAR => { @@ -475,7 +473,7 @@ impl IDropTarget_Impl for WindowsDragDropTarget { ) -> windows::core::Result<()> { unsafe { let Some(idata_obj) = pdataobj else { - log::error!("no file detected while dragging"); + log_windows_error_with_message!("no file detected while dragging"); return Ok(()); }; let config = FORMATETC { @@ -503,7 +501,7 @@ impl IDropTarget_Impl for WindowsDragDropTarget { let filename_length = DragQueryFileW(*hdrop, file_index, None) as usize; let ret = DragQueryFileW(*hdrop, file_index, Some(&mut buffer)); if ret == 0 { - log::error!("unable to read file name"); + log_windows_error_with_message!("unable to read file name"); continue; } if let Ok(file_name) = String::from_utf16(&buffer[0..filename_length]) { From ab5750095c6350f33d2e03db629db87c0251d8f2 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 22:58:00 +0800 Subject: [PATCH 09/39] fix cursor --- crates/gpui/src/platform/windows/platform.rs | 66 +++++++++++++++----- crates/gpui/src/platform/windows/utils.rs | 2 +- crates/gpui/src/platform/windows/window.rs | 24 ++++--- 3 files changed, 68 insertions(+), 24 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index c85f287104e53..e5e32dc14e7d9 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -57,7 +57,7 @@ use windows::{ DispatchMessageW, GetMessageW, LoadCursorW, LoadImageW, PostQuitMessage, SetCursor, TranslateMessage, ACCEL, ACCEL_VIRT_FLAGS, HCURSOR, HMENU, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_IBEAM, IDC_NO, IDC_SIZENS, IDC_SIZEWE, IMAGE_CURSOR, LR_DEFAULTSIZE, - MF_POPUP, MF_SEPARATOR, MF_STRING, SW_SHOWDEFAULT, WM_DESTROY, + LR_SHARED, MF_POPUP, MF_SEPARATOR, MF_STRING, SW_SHOWDEFAULT, WM_DESTROY, }, }, }, @@ -463,27 +463,61 @@ impl Platform for WindowsPlatform { fn set_cursor_style(&self, style: CursorStyle) { unsafe { let handle = match style { - CursorStyle::IBeam | CursorStyle::IBeamCursorForVerticalLayout => { - LoadImageW(None, IDC_IBEAM, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) - } - CursorStyle::Crosshair => { - LoadImageW(None, IDC_CROSS, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) - } - CursorStyle::PointingHand | CursorStyle::DragLink => { - LoadImageW(None, IDC_HAND, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) - } + CursorStyle::IBeam | CursorStyle::IBeamCursorForVerticalLayout => LoadImageW( + None, + IDC_IBEAM, + IMAGE_CURSOR, + 0, + 0, + LR_DEFAULTSIZE | LR_SHARED, + ), + CursorStyle::Crosshair => LoadImageW( + None, + IDC_CROSS, + IMAGE_CURSOR, + 0, + 0, + LR_DEFAULTSIZE | LR_SHARED, + ), + CursorStyle::PointingHand | CursorStyle::DragLink => LoadImageW( + None, + IDC_HAND, + IMAGE_CURSOR, + 0, + 0, + LR_DEFAULTSIZE | LR_SHARED, + ), CursorStyle::ResizeLeft | CursorStyle::ResizeRight - | CursorStyle::ResizeLeftRight => { - LoadImageW(None, IDC_SIZEWE, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) - } + | CursorStyle::ResizeLeftRight => LoadImageW( + None, + IDC_SIZEWE, + IMAGE_CURSOR, + 0, + 0, + LR_DEFAULTSIZE | LR_SHARED, + ), CursorStyle::ResizeUp | CursorStyle::ResizeDown | CursorStyle::ResizeUpDown => { - LoadImageW(None, IDC_SIZENS, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) + LoadImageW( + None, + IDC_SIZENS, + IMAGE_CURSOR, + 0, + 0, + LR_DEFAULTSIZE | LR_SHARED, + ) } CursorStyle::OperationNotAllowed => { - LoadImageW(None, IDC_NO, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE) + LoadImageW(None, IDC_NO, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) } - _ => LoadImageW(None, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE), + _ => LoadImageW( + None, + IDC_ARROW, + IMAGE_CURSOR, + 0, + 0, + LR_DEFAULTSIZE | LR_SHARED, + ), }; if handle.is_err() { log_windows_error_with_message!("Error loading cursor image"); diff --git a/crates/gpui/src/platform/windows/utils.rs b/crates/gpui/src/platform/windows/utils.rs index 97678b71be2ca..8025df3941920 100644 --- a/crates/gpui/src/platform/windows/utils.rs +++ b/crates/gpui/src/platform/windows/utils.rs @@ -107,7 +107,7 @@ macro_rules! log_windows_error_with_message { ($s: literal) => {{ let caller = std::panic::Location::caller(); log::error!( - "$s at {}:{}: {}", + concat!($s, " at {}:{}: {}"), caller.file(), caller.line(), std::io::Error::last_os_error() diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 0e8efb0b96c20..53b7fe3d48ab9 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -25,7 +25,7 @@ use windows::{ }, Graphics::Gdi::{ GetMonitorInfoW, MonitorFromWindow, RedrawWindow, UpdateWindow, ValidateRect, HRGN, - MONITORINFO, MONITOR_DEFAULTTONEAREST, RDW_INVALIDATE, + MONITORINFO, MONITOR_DEFAULTTONEAREST, RDW_ERASENOW, RDW_INVALIDATE, RDW_UPDATENOW, }, System::{ Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL}, @@ -262,7 +262,18 @@ impl WindowsWindowinner { self.window_handle.hwnd(), None, HRGN::default(), - RDW_INVALIDATE, + RDW_INVALIDATE | RDW_ERASENOW, + ); + } + } + + pub fn update_now(&self) { + unsafe { + RedrawWindow( + self.window_handle.hwnd(), + None, + HRGN::default(), + RDW_INVALIDATE | RDW_UPDATENOW, ); } } @@ -375,7 +386,6 @@ impl WindowsWindowBase for WindowsWindowinner { ) .inspect_err(log_windows_error); } - self.update(); LRESULT(0) } WM_ACTIVATE => { @@ -390,7 +400,7 @@ impl WindowsWindowBase for WindowsWindowinner { let mut modifiers = self.modifiers.borrow().clone(); if let Some(key) = parse_system_key(message, wparam, lparam, &mut modifiers) { self.handle_input(key); - self.update(); + self.update_now(); } (*self.modifiers.borrow_mut()) = modifiers; LRESULT(0) @@ -401,7 +411,7 @@ impl WindowsWindowBase for WindowsWindowinner { let modifiers = self.modifiers.borrow(); let key = parse_mouse_button(message, wparam, lparam, &modifiers); self.handle_input(key); - self.update(); + self.update_now(); LRESULT(0) } WM_MOUSEMOVE => { @@ -416,7 +426,7 @@ impl WindowsWindowBase for WindowsWindowinner { let keycode = parse_keyboard_input(wparam, lparam, &*modifiers); if let Some(key) = keycode { self.handle_input(key); - self.update(); + self.update_now(); } LRESULT(0) } @@ -424,7 +434,7 @@ impl WindowsWindowBase for WindowsWindowinner { let modifiers = self.modifiers.borrow().clone(); let input = parse_mouse_wheel(wparam, lparam, modifiers); self.handle_input(input); - self.update(); + self.update_now(); LRESULT(0) } WM_SIZE => { From 305b3eab298a75e95a60ae179fb8888b8ddc674a Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 23:27:21 +0800 Subject: [PATCH 10/39] mouse hwheel --- crates/gpui/src/platform/windows/events.rs | 21 +++++++++++-- crates/gpui/src/platform/windows/platform.rs | 8 ++--- crates/gpui/src/platform/windows/window.rs | 31 +++++++++++++------- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index 6c1cae142affa..0bf85142143ea 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -6,6 +6,7 @@ use windows::{ Foundation::{HWND, LPARAM, LRESULT, WPARAM}, Globalization::{WideCharToMultiByte, CP_UTF8}, Graphics::Gdi::HBRUSH, + System::SystemServices::{MK_CONTROL, MK_SHIFT}, UI::{ Input::KeyboardAndMouse::{ VIRTUAL_KEY, VK_BACK, VK_CONTROL, VK_DELETE, VK_DOWN, VK_END, VK_ESCAPE, VK_F1, @@ -393,13 +394,12 @@ pub fn parse_mouse_movement( (new_pos, input) } -pub fn parse_mouse_wheel(wparam: WPARAM, lparam: LPARAM, modifiers: Modifiers) -> PlatformInput { +pub fn parse_mouse_vwheel(wparam: WPARAM, lparam: LPARAM, modifiers: Modifiers) -> PlatformInput { let position = Point { x: Pixels(loword!(lparam.0, i16) as _), y: Pixels(hiword!(lparam.0, i16) as _), }; let lines = hiword!(wparam.0, i16); - println!("Lines: {}", lines); PlatformInput::ScrollWheel(ScrollWheelEvent { position, delta: ScrollDelta::Lines(Point { @@ -411,6 +411,23 @@ pub fn parse_mouse_wheel(wparam: WPARAM, lparam: LPARAM, modifiers: Modifiers) - }) } +pub fn parse_mouse_hwheel(wparam: WPARAM, lparam: LPARAM, modifiers: Modifiers) -> PlatformInput { + let position = Point { + x: Pixels(loword!(lparam.0, i16) as _), + y: Pixels(hiword!(lparam.0, i16) as _), + }; + let lines = hiword!(wparam.0, i16); + PlatformInput::ScrollWheel(ScrollWheelEvent { + position, + delta: ScrollDelta::Lines(Point { + x: lines as f32 / 120.0, + y: 0.0, + }), + modifiers, + touch_phase: TouchPhase::default(), + }) +} + pub unsafe fn parse_dropfiles(wparam: WPARAM, lparam: LPARAM) -> PlatformInput { let hdrop = windows::Win32::UI::Shell::HDROP(wparam.0 as isize); // DragQueryFileW(hdrop, ifile, lpszfile); diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index e5e32dc14e7d9..9bc9347018efa 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -765,15 +765,13 @@ unsafe fn generate_menu( let accel_table = keystroke_to_accel_table(keystroke, action_index as _); accelerator_vec.push(accel_table); } else { - item_name.push('\t'); - for (keyindex, keystroke) in keystrokes.iter().enumerate() { + // windows cant show multiple chortcuts on menu item + for keystroke in keystrokes.iter() { keystroke_to_menu_string(keystroke, &mut item_name); - item_name.push('\t'); let accel_table = keystroke_to_accel_table(keystroke, action_index as _); accelerator_vec.push(accel_table); } - item_name.pop(); } } let name_vec = encode_wide(&item_name); @@ -784,7 +782,7 @@ unsafe fn generate_menu( PCWSTR::from_raw(name_vec.as_ptr()), ) .inspect_err(log_windows_error)?; - println!("action [{}]: {:#?}", action_index, action); + // println!("action [{}]: {:#?}", action_index, action); actions_vec.push(action); } } diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 53b7fe3d48ab9..ffedddf622e35 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -58,10 +58,10 @@ use windows::{ WINDOW_EX_STYLE, WINDOW_STYLE, WM_ACTIVATE, WM_CHAR, WM_CLOSE, WM_COMMAND, WM_DESTROY, WM_DROPFILES, WM_IME_STARTCOMPOSITION, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDBLCLK, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, - WM_MBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_PAINT, WM_RBUTTONDBLCLK, - WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SIZE, WM_TIMER, WM_XBUTTONDBLCLK, WM_XBUTTONDOWN, - WM_XBUTTONUP, WNDCLASSEXW, WS_EX_ACCEPTFILES, WS_MAXIMIZE, WS_OVERLAPPEDWINDOW, - WS_POPUP, WS_VISIBLE, + WM_MBUTTONUP, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_PAINT, + WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SIZE, WM_TIMER, + WM_XBUTTONDBLCLK, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSEXW, WS_EX_ACCEPTFILES, + WS_MAXIMIZE, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_VISIBLE, }, }, }, @@ -70,12 +70,13 @@ use windows::{ use crate::{ available_monitors, encode_wide, get_module_handle, hiword, log_windows_error, log_windows_error_with_message, loword, parse_dropfiles, parse_keyboard_input, - parse_mouse_button, parse_mouse_movement, parse_mouse_wheel, parse_system_key, - platform::cross_platform::BladeRenderer, set_windowdata, Action, Bounds, DisplayId, - ForegroundExecutor, Modifiers, Pixels, PlatformDisplay, PlatformInput, PlatformInputHandler, - PlatformWindow, Point, Size, WindowKind, WindowOptions, WindowsWindowBase, - WindowsWinodwDataWrapper, DRAGDROP_GET_COUNT, FILENAME_MAXLENGTH, MENU_ACTIONS, WINDOW_CLOSE, - WINDOW_REFRESH_TIMER, WINODW_EXTRA_EXSTYLE, WINODW_REFRESH_INTERVAL, WINODW_STYLE, + parse_mouse_button, parse_mouse_hwheel, parse_mouse_movement, parse_mouse_vwheel, + parse_system_key, platform::cross_platform::BladeRenderer, set_windowdata, Action, Bounds, + DisplayId, ForegroundExecutor, Modifiers, Pixels, PlatformDisplay, PlatformInput, + PlatformInputHandler, PlatformWindow, Point, Size, WindowKind, WindowOptions, + WindowsWindowBase, WindowsWinodwDataWrapper, DRAGDROP_GET_COUNT, FILENAME_MAXLENGTH, + MENU_ACTIONS, WINDOW_CLOSE, WINDOW_REFRESH_TIMER, WINODW_EXTRA_EXSTYLE, + WINODW_REFRESH_INTERVAL, WINODW_STYLE, }; use super::{display::WindowsDisplay, WINDOW_CLASS}; @@ -410,6 +411,7 @@ impl WindowsWindowBase for WindowsWindowinner { | WM_RBUTTONDBLCLK | WM_MBUTTONDBLCLK | WM_XBUTTONDBLCLK => { let modifiers = self.modifiers.borrow(); let key = parse_mouse_button(message, wparam, lparam, &modifiers); + println!("Mouse button down: {:#?}", key); self.handle_input(key); self.update_now(); LRESULT(0) @@ -432,7 +434,14 @@ impl WindowsWindowBase for WindowsWindowinner { } WM_MOUSEWHEEL => { let modifiers = self.modifiers.borrow().clone(); - let input = parse_mouse_wheel(wparam, lparam, modifiers); + let input = parse_mouse_vwheel(wparam, lparam, modifiers); + self.handle_input(input); + self.update_now(); + LRESULT(0) + } + WM_MOUSEHWHEEL => { + let modifiers = self.modifiers.borrow().clone(); + let input = parse_mouse_hwheel(wparam, lparam, modifiers); self.handle_input(input); self.update_now(); LRESULT(0) From e002a0324ee397ef5b7fa7882658131ad158fea6 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 23:53:47 +0800 Subject: [PATCH 11/39] scale factor issue --- crates/gpui/src/platform/windows/platform.rs | 2 +- crates/gpui/src/platform/windows/window.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 9bc9347018efa..1de20c9fc3b30 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -752,7 +752,7 @@ unsafe fn generate_menu( .bindings_for_action(action.as_ref()) .next() .map(|binding| binding.keystrokes()); - println!("Shortcut: {:#?}", keystrokes); + // println!("Shortcut: {:#?}", keystrokes); let mut item_name = name.to_string(); let action_index = actions_count.fetch_add(1, std::sync::atomic::Ordering::SeqCst); diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index ffedddf622e35..1aaa898a6405d 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -122,6 +122,7 @@ impl WindowsWindow { display.display_id = display_id; } let scale_factor = monitor.scale_factor(); + println!("Scale factor: {}", scale_factor); let mut lpwindowname = None; if let Some(ref titlebar_opt) = options.titlebar { @@ -165,6 +166,7 @@ impl WindowsWindow { height: window_handle.size().height as _, depth: 1, }; + println!("Window size: {:#?}", gpu_extent); let renderer = BladeRenderer::new(gpu, gpu_extent); let inner = WindowsWindowinner::new( dispatch_window_handle, @@ -324,6 +326,7 @@ impl WindowsWindowinner { height, depth: 1, }; + println!("Resize with: {:#?}", gpu_size); let mut render = self.renderer.borrow_mut(); if render.viewport_size() != gpu_size { render.update_drawable_size(crate::size(gpu_size.width as _, gpu_size.height as _)); @@ -816,9 +819,9 @@ impl RawWindow { pub fn show(&self) { unsafe { // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow - // UpdateWindow(self.hwnd()); - ShowWindow(self.hwnd(), SW_SHOW); - println!("Show window Error: {:?}", std::io::Error::last_os_error()); + if !ShowWindow(self.hwnd(), SW_SHOW).as_bool() { + log_windows_error_with_message!("Unable to show window"); + } } } From d5427ff9ce8ebd01c35080b12ffe5979b2cd3cdf Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 1 Mar 2024 23:54:54 +0800 Subject: [PATCH 12/39] temp fix on scale factor --- crates/gpui/src/platform/windows/window.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 1aaa898a6405d..e1f433fe67bb5 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -121,8 +121,8 @@ impl WindowsWindow { // TODO: move window to target monitor display.display_id = display_id; } - let scale_factor = monitor.scale_factor(); - println!("Scale factor: {}", scale_factor); + // let scale_factor = monitor.scale_factor(); + let scale_factor = 1.0; let mut lpwindowname = None; if let Some(ref titlebar_opt) = options.titlebar { From 832a825dc66414c9aa5389ef30a1d5a0310f7138 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sat, 2 Mar 2024 04:36:12 +0800 Subject: [PATCH 13/39] fix clipboard --- crates/gpui/src/platform/windows/platform.rs | 50 ++++++++++- crates/gpui/src/platform/windows/utils.rs | 2 +- crates/gpui/src/platform/windows/window.rs | 92 +++++++++++--------- 3 files changed, 97 insertions(+), 47 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 1de20c9fc3b30..28b58adebcd51 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -189,6 +189,7 @@ impl Platform for WindowsPlatform { fn run(&self, on_finish_launching: Box) { on_finish_launching(); + println!("{:?}", self.read_from_clipboard()); unsafe { let mut msg = std::mem::zeroed(); while GetMessageW(&mut msg, HWND::default(), 0, 0).as_bool() { @@ -557,7 +558,7 @@ impl Platform for WindowsPlatform { { return; } - let _ = CloseClipboard(); + let _ = CloseClipboard().inspect_err(log_windows_error); } } @@ -580,8 +581,8 @@ impl Platform for WindowsPlatform { else { return None; }; - let string_raw = GlobalLock(data.u.hGlobal) as *mut Vec; - let string = String::from_utf16_lossy(&*string_raw); + let wstring = PCWSTR(GlobalLock(data.u.hGlobal) as *mut u16); + let string = String::from_utf16_lossy(wstring.as_wide()); let _ = GlobalUnlock(data.u.hGlobal); ReleaseStgMedium(&mut data); @@ -590,6 +591,25 @@ impl Platform for WindowsPlatform { metadata: None, }) } + // unsafe { + // if OpenClipboard(self.inner.dispatch_window_handle) + // .inspect_err(log_windows_error) + // .is_err() + // { + // return None; + // } + // let Ok(handle) = GetClipboardData(CF_UNICODETEXT).inspect_err(log_windows_error) else { + // return None; + // }; + // let wstring = PCWSTR(handle.0 as _); + // let string = String::from_utf16_lossy(wstring.as_wide()); + // let _ = CloseClipboard().inspect_err(log_windows_error); + + // Some(ClipboardItem { + // text: string, + // metadata: None, + // }) + // } } // todo!(windows) @@ -861,3 +881,27 @@ fn keycode_to_vkey(keycode: &str) -> Option { key } + +#[cfg(test)] +mod tests { + use crate::ClipboardItem; + + use super::*; + + #[test] + fn test_clipboard() { + let platform = WindowsPlatform::new(); + println!("{:?}", platform.read_from_clipboard()); + // assert_eq!(platform.read_from_clipboard(), None); + + let item = ClipboardItem::new("123".to_string()); + platform.write_to_clipboard(item.clone()); + println!("{:?}", platform.read_from_clipboard()); + // assert_eq!(platform.read_from_clipboard(), Some(item)); + + let item = ClipboardItem::new("456".to_string()).with_metadata(vec![3, 4]); + platform.write_to_clipboard(item.clone()); + println!("{:?}", platform.read_from_clipboard()); + // assert_eq!(platform.read_from_clipboard(), Some(item)); + } +} diff --git a/crates/gpui/src/platform/windows/utils.rs b/crates/gpui/src/platform/windows/utils.rs index 8025df3941920..e8afcb48cd0a3 100644 --- a/crates/gpui/src/platform/windows/utils.rs +++ b/crates/gpui/src/platform/windows/utils.rs @@ -81,7 +81,7 @@ pub unsafe fn set_windowdata(handle: HWND, data: T) { let raw = Box::into_raw(Box::new(data)); let ret = SetWindowLongPtrW(handle, GWL_USERDATA, raw as _); if ret == 0 { - log::error!("Windows error: {}", std::io::Error::last_os_error()); + log_windows_error_with_message!(None); let _ = SetWindowLongPtrW(handle, GWL_USERDATA, raw as _); } } diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index e1f433fe67bb5..63646ea9e4b5f 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -662,52 +662,58 @@ impl PlatformWindow for WindowsWindow { answers: &[&str], ) -> futures::channel::oneshot::Receiver { let (done_tx, done_rx) = oneshot::channel(); - let mut config; - unsafe { - config = std::mem::zeroed::(); - config.cbSize = std::mem::size_of::() as _; - config.hwndParent = self.inner.window_handle.hwnd(); - let title; - let main_icon; - match level { - crate::PromptLevel::Info => { - title = windows::core::w!("Info"); - main_icon = TD_INFORMATION_ICON; - } - crate::PromptLevel::Warning => { - title = windows::core::w!("Warning"); - main_icon = TD_WARNING_ICON; - } - crate::PromptLevel::Critical => { - title = windows::core::w!("Critical"); - main_icon = TD_ERROR_ICON; - } - }; - config.pszWindowTitle = title; - config.Anonymous1.pszMainIcon = main_icon; - let instruction = encode_wide(msg); - config.pszMainInstruction = PCWSTR::from_raw(instruction.as_ptr()); - let hints_encoded; - if let Some(hints) = detail { - hints_encoded = encode_wide(hints); - config.pszContent = PCWSTR::from_raw(hints_encoded.as_ptr()); - }; - let mut buttons = Vec::new(); - let mut btn_encoded = Vec::new(); - for (index, btn_string) in answers.iter().enumerate() { - let encoded = encode_wide(btn_string); - buttons.push(TASKDIALOG_BUTTON { - nButtonID: index as _, - pszButtonText: PCWSTR::from_raw(encoded.as_ptr()), - }); - btn_encoded.push(encoded); - } - config.cButtons = buttons.len() as _; - config.pButtons = buttons.as_ptr(); - } + let msg = msg.to_string(); + let detail = match detail { + Some(info) => Some(info.to_string()), + None => None, + }; + let answers = answers.iter().map(|s| s.to_string()).collect::>(); + let handle = self.inner.window_handle.hwnd(); self.foreground_executor .spawn(async move { unsafe { + let mut config; + config = std::mem::zeroed::(); + config.cbSize = std::mem::size_of::() as _; + config.hwndParent = handle; + let title; + let main_icon; + match level { + crate::PromptLevel::Info => { + title = windows::core::w!("Info"); + main_icon = TD_INFORMATION_ICON; + } + crate::PromptLevel::Warning => { + title = windows::core::w!("Warning"); + main_icon = TD_WARNING_ICON; + } + crate::PromptLevel::Critical => { + title = windows::core::w!("Critical"); + main_icon = TD_ERROR_ICON; + } + }; + config.pszWindowTitle = title; + config.Anonymous1.pszMainIcon = main_icon; + let instruction = encode_wide(&msg); + config.pszMainInstruction = PCWSTR::from_raw(instruction.as_ptr()); + let hints_encoded; + if let Some(ref hints) = detail { + hints_encoded = encode_wide(hints); + config.pszContent = PCWSTR::from_raw(hints_encoded.as_ptr()); + }; + let mut buttons = Vec::new(); + let mut btn_encoded = Vec::new(); + for (index, btn_string) in answers.iter().enumerate() { + let encoded = encode_wide(btn_string); + buttons.push(TASKDIALOG_BUTTON { + nButtonID: index as _, + pszButtonText: PCWSTR::from_raw(encoded.as_ptr()), + }); + btn_encoded.push(encoded); + } + config.cButtons = buttons.len() as _; + config.pButtons = buttons.as_ptr(); + config.pfCallback = None; let mut res = std::mem::zeroed(); let _ = TaskDialogIndirect(&config, Some(&mut res), None, None) From b3715f7aef4174db0857baff80e95a8759a5f522 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sat, 2 Mar 2024 18:42:18 +0800 Subject: [PATCH 14/39] update clipboard --- crates/gpui/src/platform/windows/constants.rs | 4 + crates/gpui/src/platform/windows/platform.rs | 190 ++++++++++++------ 2 files changed, 129 insertions(+), 65 deletions(-) diff --git a/crates/gpui/src/platform/windows/constants.rs b/crates/gpui/src/platform/windows/constants.rs index 473290eaedeb6..c068a808aec62 100644 --- a/crates/gpui/src/platform/windows/constants.rs +++ b/crates/gpui/src/platform/windows/constants.rs @@ -54,3 +54,7 @@ pub const ACCEL_FVIRTKEY: u8 = 0x01; pub const ACCEL_FSHIFT: u8 = 0x04; pub const ACCEL_FCONTROL: u8 = 0x08; pub const ACCEL_FALT: u8 = 0x10; + +// clipboard +pub const CLIPBOARD_TEXT_HASH: PCWSTR = windows::core::w!("ZedTextHash"); +pub const CLIPBOARD_METADATA: PCWSTR = windows::core::w!("ZedMetadata"); diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 28b58adebcd51..a400fe06fcb05 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -5,6 +5,7 @@ use std::{ os::windows::process::CommandExt, path::{Path, PathBuf}, process::Stdio, + ptr::copy_nonoverlapping, rc::Rc, str::FromStr, sync::{ @@ -28,15 +29,18 @@ use windows::{ }, System::{ Com::{ - CoCreateInstance, CoInitializeEx, CoUninitialize, CreateBindCtx, CLSCTX_ALL, - COINIT_DISABLE_OLE1DDE, COINIT_MULTITHREADED, DVASPECT_CONTENT, FORMATETC, - TYMED_HGLOBAL, + CoCreateInstance, CoInitializeEx, CoUninitialize, CreateBindCtx, IDataObject, + CLSCTX_ALL, COINIT_DISABLE_OLE1DDE, COINIT_MULTITHREADED, DVASPECT_CONTENT, + FORMATETC, TYMED_HGLOBAL, }, DataExchange::{ - CloseClipboard, EmptyClipboard, GetClipboardData, OpenClipboard, SetClipboardData, + CloseClipboard, EmptyClipboard, GetClipboardData, OpenClipboard, + RegisterClipboardFormatW, SetClipboardData, }, Memory::{GlobalAlloc, GlobalLock, GlobalUnlock, GMEM_MOVEABLE}, - Ole::{OleGetClipboard, OleInitialize, OleUninitialize, ReleaseStgMedium}, + Ole::{ + OleGetClipboard, OleInitialize, OleSetClipboard, OleUninitialize, ReleaseStgMedium, + }, Threading::CREATE_NO_WINDOW, Time::{GetTimeZoneInformation, TIME_ZONE_ID_INVALID}, }, @@ -67,8 +71,8 @@ use crate::{ encode_wide, log_windows_error, log_windows_error_with_message, platform::cross_platform::CosmicTextSystem, set_windowdata, Keystroke, WindowsWindow, WindowsWindowBase, WindowsWinodwDataWrapper, ACCEL_FALT, ACCEL_FCONTROL, ACCEL_FSHIFT, - ACCEL_FVIRTKEY, CF_UNICODETEXT, DISPATCH_WINDOW_CLASS, DISPATCH_WINDOW_EXSTYLE, - DISPATCH_WINDOW_STYLE, MAIN_DISPATCH, MENU_ACTIONS, WINDOW_CLOSE, + ACCEL_FVIRTKEY, CF_UNICODETEXT, CLIPBOARD_METADATA, CLIPBOARD_TEXT_HASH, DISPATCH_WINDOW_CLASS, + DISPATCH_WINDOW_EXSTYLE, DISPATCH_WINDOW_STYLE, MAIN_DISPATCH, MENU_ACTIONS, WINDOW_CLOSE, }; use crate::{ Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId, @@ -97,6 +101,8 @@ pub(crate) struct WindowsPlatform { text_system: Arc, inner: Rc, menu_handle: RefCell>, + text_hash_clipboard_type: u32, + metadata_clipboard_type: u32, } impl WindowsPlatform { @@ -122,6 +128,8 @@ impl WindowsPlatform { ); } let dispatcher = Arc::new(WindowsDispatcher::new(sender, dispatch_window_handle)); + let text_hash_clipboard_type = unsafe { RegisterClipboardFormatW(CLIPBOARD_TEXT_HASH) }; + let metadata_clipboard_type = unsafe { RegisterClipboardFormatW(CLIPBOARD_METADATA) }; WindowsPlatform { background_executor: BackgroundExecutor::new(dispatcher.clone()), @@ -129,6 +137,8 @@ impl WindowsPlatform { text_system: Arc::new(CosmicTextSystem::new()), inner, menu_handle: RefCell::new(None), + text_hash_clipboard_type, + metadata_clipboard_type, } } } @@ -533,7 +543,6 @@ impl Platform for WindowsPlatform { false } - //todo!(windows) fn write_to_clipboard(&self, item: ClipboardItem) { unsafe { if OpenClipboard(self.inner.dispatch_window_handle) @@ -543,73 +552,73 @@ impl Platform for WindowsPlatform { return; } if EmptyClipboard().inspect_err(log_windows_error).is_err() { + let _ = CloseClipboard().inspect_err(log_windows_error); return; } - // MultiByteToWideChar(codepage, dwflags, lpmultibytestr, lpwidecharstr); let data_ptr = encode_wide(&item.text); - let count = data_ptr.len() + 1; - let global = GlobalAlloc(GMEM_MOVEABLE, count * 2).unwrap(); - let handle = GlobalLock(global); - u_memcpy(handle as _, data_ptr.as_ptr() as _, count as _); - let _ = GlobalUnlock(global); - if SetClipboardData(CF_UNICODETEXT, HANDLE(global.0 as isize)) - .inspect_err(log_windows_error) - .is_err() - { + let count = data_ptr.len(); + if set_rawdata_to_clipboard(data_ptr.as_ptr(), count, CF_UNICODETEXT).is_err() { + let _ = CloseClipboard().inspect_err(log_windows_error); return; } + if let Some(metadata) = item.metadata.as_ref() { + let hash_result = ClipboardItem::text_hash(&item.text); + let mut hash_rawdata = hash_result.to_be_bytes(); + let hash_wbytes = + std::slice::from_raw_parts::(hash_rawdata.as_mut_ptr().cast::(), 4); + if set_rawdata_to_clipboard(hash_wbytes.as_ptr(), 4, self.text_hash_clipboard_type) + .is_err() + { + let _ = CloseClipboard().inspect_err(log_windows_error); + return; + } + let metadata_ptr = encode_wide(metadata); + let count = metadata_ptr.len() + 1; + if set_rawdata_to_clipboard( + metadata_ptr.as_ptr(), + count, + self.metadata_clipboard_type, + ) + .is_err() + { + let _ = CloseClipboard().inspect_err(log_windows_error); + return; + } + } let _ = CloseClipboard().inspect_err(log_windows_error); } } - //todo!(windows) fn read_from_clipboard(&self) -> Option { unsafe { let Ok(clipboard) = OleGetClipboard().inspect_err(log_windows_error) else { return None; }; - let config = FORMATETC { - cfFormat: CF_UNICODETEXT as _, - ptd: std::ptr::null_mut() as _, - dwAspect: DVASPECT_CONTENT.0, - lindex: -1, - tymed: TYMED_HGLOBAL.0 as _, - }; - let Ok(mut data) = clipboard - .GetData(&config as _) - .inspect_err(log_windows_error) + let Ok((text, _)) = read_rawdata_from_clipboard(&clipboard, CF_UNICODETEXT, false) else { return None; }; - let wstring = PCWSTR(GlobalLock(data.u.hGlobal) as *mut u16); - let string = String::from_utf16_lossy(wstring.as_wide()); - let _ = GlobalUnlock(data.u.hGlobal); - ReleaseStgMedium(&mut data); - - Some(ClipboardItem { - text: string, + let mut item = ClipboardItem { + text, metadata: None, - }) + }; + // hash & metadata + let Ok((_, hash_data)) = + read_rawdata_from_clipboard(&clipboard, self.text_hash_clipboard_type, true) + else { + return Some(item); + }; + let Ok((metadata, _)) = + read_rawdata_from_clipboard(&clipboard, self.metadata_clipboard_type, false) + else { + return Some(item); + }; + if hash_data == ClipboardItem::text_hash(&item.text) { + item.metadata = Some(metadata); + } + + Some(item) } - // unsafe { - // if OpenClipboard(self.inner.dispatch_window_handle) - // .inspect_err(log_windows_error) - // .is_err() - // { - // return None; - // } - // let Ok(handle) = GetClipboardData(CF_UNICODETEXT).inspect_err(log_windows_error) else { - // return None; - // }; - // let wstring = PCWSTR(handle.0 as _); - // let string = String::from_utf16_lossy(wstring.as_wide()); - // let _ = CloseClipboard().inspect_err(log_windows_error); - - // Some(ClipboardItem { - // text: string, - // metadata: None, - // }) - // } } // todo!(windows) @@ -802,7 +811,6 @@ unsafe fn generate_menu( PCWSTR::from_raw(name_vec.as_ptr()), ) .inspect_err(log_windows_error)?; - // println!("action [{}]: {:#?}", action_index, action); actions_vec.push(action); } } @@ -882,6 +890,59 @@ fn keycode_to_vkey(keycode: &str) -> Option { key } +fn set_rawdata_to_clipboard(src: *const u16, len_in_u16: usize, format: u32) -> anyhow::Result<()> { + unsafe { + let global = GlobalAlloc(GMEM_MOVEABLE, len_in_u16 * 2).unwrap(); + let handle = GlobalLock(global); + u_memcpy(handle as _, src, len_in_u16 as _); + let _ = GlobalUnlock(global); + SetClipboardData(format, HANDLE(global.0 as isize)).inspect_err(log_windows_error)?; + } + Ok(()) +} + +fn read_rawdata_from_clipboard( + clipboard: &IDataObject, + format: u32, + getting_hash: bool, +) -> anyhow::Result<(String, u64)> { + unsafe { + let config = FORMATETC { + cfFormat: format as _, + ptd: std::ptr::null_mut() as _, + dwAspect: DVASPECT_CONTENT.0, + lindex: -1, + tymed: TYMED_HGLOBAL.0 as _, + }; + let mut data = clipboard + .GetData(&config as _) + .inspect_err(log_windows_error)?; + let mut hash_result = 0u64; + let mut string = String::new(); + if getting_hash { + let raw_ptr = GlobalLock(data.u.hGlobal) as *mut u16; + let wbytes_ref = std::slice::from_raw_parts(raw_ptr, 4); + let mut wbytes = [0u16; 4]; + for x in 0..4 { + wbytes[x] = wbytes_ref[x]; + } + let hash_bytes_ref = std::slice::from_raw_parts(wbytes.as_mut_ptr().cast::(), 8); + let mut hash_bytes = [0u8; 8]; + for x in 0..8 { + hash_bytes[x] = hash_bytes_ref[x]; + } + hash_result = u64::from_be_bytes(hash_bytes); + let _ = GlobalUnlock(data.u.hGlobal); + } else { + let wstring = PCWSTR(GlobalLock(data.u.hGlobal) as *mut u16); + string = String::from_utf16_lossy(wstring.as_wide()); + let _ = GlobalUnlock(data.u.hGlobal); + } + ReleaseStgMedium(&mut data); + Ok((string, hash_result)) + } +} + #[cfg(test)] mod tests { use crate::ClipboardItem; @@ -891,17 +952,16 @@ mod tests { #[test] fn test_clipboard() { let platform = WindowsPlatform::new(); - println!("{:?}", platform.read_from_clipboard()); - // assert_eq!(platform.read_from_clipboard(), None); + let item = ClipboardItem::new("你好".to_string()); + platform.write_to_clipboard(item.clone()); + assert_eq!(platform.read_from_clipboard(), Some(item)); - let item = ClipboardItem::new("123".to_string()); + let item = ClipboardItem::new("1".to_string()); platform.write_to_clipboard(item.clone()); - println!("{:?}", platform.read_from_clipboard()); - // assert_eq!(platform.read_from_clipboard(), Some(item)); + assert_eq!(platform.read_from_clipboard(), Some(item)); - let item = ClipboardItem::new("456".to_string()).with_metadata(vec![3, 4]); + let item = ClipboardItem::new("a".to_string()).with_metadata(vec![3, 4]); platform.write_to_clipboard(item.clone()); - println!("{:?}", platform.read_from_clipboard()); - // assert_eq!(platform.read_from_clipboard(), Some(item)); + assert_eq!(platform.read_from_clipboard(), Some(item)); } } From 5ed1a6c1aef2c1b3e5fa1c7d9095684fb840099c Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sat, 2 Mar 2024 19:09:17 +0800 Subject: [PATCH 15/39] update read clipboard fn --- crates/gpui/src/platform/windows/platform.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index a400fe06fcb05..5dc47337a80d1 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -738,6 +738,8 @@ fn show_savefile_dialog(directory: PathBuf) -> anyhow::Result { } } +// todo("windows") +// what is the os action stuff?? unsafe fn generate_menu( parent_handle: HMENU, menu: Menu, @@ -786,7 +788,7 @@ unsafe fn generate_menu( let mut item_name = name.to_string(); let action_index = actions_count.fetch_add(1, std::sync::atomic::Ordering::SeqCst); if let Some(keystrokes) = keystrokes { - // TODO: deal with 2 keystrokes + // TODO: deal with os action if keystrokes.len() == 1 { let keystroke = &keystrokes[0]; item_name.push('\t'); @@ -921,16 +923,10 @@ fn read_rawdata_from_clipboard( let mut string = String::new(); if getting_hash { let raw_ptr = GlobalLock(data.u.hGlobal) as *mut u16; - let wbytes_ref = std::slice::from_raw_parts(raw_ptr, 4); - let mut wbytes = [0u16; 4]; - for x in 0..4 { - wbytes[x] = wbytes_ref[x]; - } - let hash_bytes_ref = std::slice::from_raw_parts(wbytes.as_mut_ptr().cast::(), 8); - let mut hash_bytes = [0u8; 8]; - for x in 0..8 { - hash_bytes[x] = hash_bytes_ref[x]; - } + let hash_bytes: [u8; 8] = std::slice::from_raw_parts(raw_ptr.cast::(), 8) + .to_vec() + .try_into() + .unwrap(); hash_result = u64::from_be_bytes(hash_bytes); let _ = GlobalUnlock(data.u.hGlobal); } else { From 80e26904824d35e84f017b40c6219b9e0a6ab0ae Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sat, 2 Mar 2024 19:30:04 +0800 Subject: [PATCH 16/39] refine error handling --- crates/gpui/src/platform/windows/platform.rs | 4 ++-- crates/gpui/src/platform/windows/utils.rs | 7 ++----- crates/gpui/src/platform/windows/window.rs | 9 ++------- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 5dc47337a80d1..634884d96c906 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -199,7 +199,6 @@ impl Platform for WindowsPlatform { fn run(&self, on_finish_launching: Box) { on_finish_launching(); - println!("{:?}", self.read_from_clipboard()); unsafe { let mut msg = std::mem::zeroed(); while GetMessageW(&mut msg, HWND::default(), 0, 0).as_bool() { @@ -403,7 +402,7 @@ impl Platform for WindowsPlatform { fn os_version(&self) -> Result { let mut info = unsafe { std::mem::zeroed() }; let status = unsafe { RtlGetVersion(&mut info) }; - if status == STATUS_SUCCESS { + if status.is_ok() { Ok(SemanticVersion { major: info.dwMajorVersion as _, minor: info.dwMinorVersion as _, @@ -467,6 +466,7 @@ impl Platform for WindowsPlatform { UtcOffset::from_hms(hours as _, minutes as _, 0).unwrap() } + // todo("windows") fn path_for_auxiliary_executable(&self, name: &str) -> Result { unimplemented!() } diff --git a/crates/gpui/src/platform/windows/utils.rs b/crates/gpui/src/platform/windows/utils.rs index e8afcb48cd0a3..524685430bb3e 100644 --- a/crates/gpui/src/platform/windows/utils.rs +++ b/crates/gpui/src/platform/windows/utils.rs @@ -79,11 +79,8 @@ macro_rules! hiword { #[inline] pub unsafe fn set_windowdata(handle: HWND, data: T) { let raw = Box::into_raw(Box::new(data)); - let ret = SetWindowLongPtrW(handle, GWL_USERDATA, raw as _); - if ret == 0 { - log_windows_error_with_message!(None); - let _ = SetWindowLongPtrW(handle, GWL_USERDATA, raw as _); - } + // this may generate false error + let _ = SetWindowLongPtrW(handle, GWL_USERDATA, raw as _); } #[inline] diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 63646ea9e4b5f..5f55a5ea1a9a2 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -414,7 +414,6 @@ impl WindowsWindowBase for WindowsWindowinner { | WM_RBUTTONDBLCLK | WM_MBUTTONDBLCLK | WM_XBUTTONDBLCLK => { let modifiers = self.modifiers.borrow(); let key = parse_mouse_button(message, wparam, lparam, &modifiers); - println!("Mouse button down: {:#?}", key); self.handle_input(key); self.update_now(); LRESULT(0) @@ -825,9 +824,7 @@ impl RawWindow { pub fn show(&self) { unsafe { // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow - if !ShowWindow(self.hwnd(), SW_SHOW).as_bool() { - log_windows_error_with_message!("Unable to show window"); - } + let _ = ShowWindow(self.hwnd(), SW_SHOW); // succes reports as error } } @@ -926,9 +923,7 @@ fn parse_window_options( style |= WS_POPUP; } match options.bounds { - crate::WindowBounds::Fullscreen => style &= !WS_OVERLAPPEDWINDOW, - crate::WindowBounds::Maximized => style |= WS_MAXIMIZE, - crate::WindowBounds::Maximized => {} + crate::WindowBounds::Maximized | crate::WindowBounds::Fullscreen => style |= WS_MAXIMIZE, crate::WindowBounds::Fixed(bounds) => { width = Some(bounds.size.width.0 as _); height = Some(bounds.size.height.0 as _); From 5f646ce23a2e590212cc73dc6eff9d55a77250e8 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sat, 2 Mar 2024 19:50:59 +0800 Subject: [PATCH 17/39] some cleanup --- crates/gpui/src/platform/windows/events.rs | 16 +-- crates/gpui/src/platform/windows/platform.rs | 58 +++++------ crates/gpui/src/platform/windows/window.rs | 103 +++++++++---------- 3 files changed, 76 insertions(+), 101 deletions(-) diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index 0bf85142143ea..5f755b959d7f8 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -4,9 +4,7 @@ use windows::{ core::PCWSTR, Win32::{ Foundation::{HWND, LPARAM, LRESULT, WPARAM}, - Globalization::{WideCharToMultiByte, CP_UTF8}, Graphics::Gdi::HBRUSH, - System::SystemServices::{MK_CONTROL, MK_SHIFT}, UI::{ Input::KeyboardAndMouse::{ VIRTUAL_KEY, VK_BACK, VK_CONTROL, VK_DELETE, VK_DOWN, VK_END, VK_ESCAPE, VK_F1, @@ -28,13 +26,10 @@ use windows::{ use crate::{ get_module_handle, get_windowdata, hiword, loword, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, PlatformInput, - Point, ScrollDelta, ScrollWheelEvent, TouchPhase, WindowsPlatformInner, MOUSE_MOVE_BUTTONS, - MOUSE_MOVE_LBUTTON, MOUSE_MOVE_MBUTTON, MOUSE_MOVE_RBUTTON, MOUSE_MOVE_XBUTTON1, - MOUSE_MOVE_XBUTTON2, + Point, ScrollDelta, ScrollWheelEvent, TouchPhase, MOUSE_MOVE_BUTTONS, MOUSE_MOVE_LBUTTON, + MOUSE_MOVE_MBUTTON, MOUSE_MOVE_RBUTTON, MOUSE_MOVE_XBUTTON1, MOUSE_MOVE_XBUTTON2, }; -struct DispatchWindowData(Rc); - pub struct WindowsWinodwDataWrapper(pub Rc); pub trait WindowsWindowBase @@ -428,13 +423,6 @@ pub fn parse_mouse_hwheel(wparam: WPARAM, lparam: LPARAM, modifiers: Modifiers) }) } -pub unsafe fn parse_dropfiles(wparam: WPARAM, lparam: LPARAM) -> PlatformInput { - let hdrop = windows::Win32::UI::Shell::HDROP(wparam.0 as isize); - // DragQueryFileW(hdrop, ifile, lpszfile); - - PlatformInput::FileDrop(crate::FileDropEvent::Exited) -} - fn buttonmask_to_button(mask: usize) -> Option { match mask { MOUSE_MOVE_LBUTTON => Some(MouseButton::Left), diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 634884d96c906..e5d3d8ff5439b 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -1,11 +1,7 @@ use std::{ - alloc::GlobalAlloc, cell::RefCell, fmt::Write, - os::windows::process::CommandExt, path::{Path, PathBuf}, - process::Stdio, - ptr::copy_nonoverlapping, rc::Rc, str::FromStr, sync::{ @@ -19,37 +15,30 @@ use async_task::Runnable; use futures::channel::oneshot; use time::UtcOffset; use windows::{ - core::{HSTRING, PCWSTR}, + core::PCWSTR, Wdk::System::SystemServices::RtlGetVersion, Win32::{ - Foundation::{HANDLE, HGLOBAL, HWND, LPARAM, LRESULT, STATUS_SUCCESS, WPARAM}, - Globalization::{u_memcpy, MultiByteToWideChar}, - Security::Credentials::{ - CredEnumerateW, CredWriteDomainCredentialsW, CREDENTIAL_TARGET_INFORMATIONW, - }, + Foundation::{HANDLE, HWND, LPARAM, LRESULT, WPARAM}, + Globalization::u_memcpy, System::{ Com::{ - CoCreateInstance, CoInitializeEx, CoUninitialize, CreateBindCtx, IDataObject, - CLSCTX_ALL, COINIT_DISABLE_OLE1DDE, COINIT_MULTITHREADED, DVASPECT_CONTENT, + CoCreateInstance, CreateBindCtx, IDataObject, CLSCTX_ALL, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL, }, DataExchange::{ - CloseClipboard, EmptyClipboard, GetClipboardData, OpenClipboard, - RegisterClipboardFormatW, SetClipboardData, + CloseClipboard, EmptyClipboard, OpenClipboard, RegisterClipboardFormatW, + SetClipboardData, }, Memory::{GlobalAlloc, GlobalLock, GlobalUnlock, GMEM_MOVEABLE}, - Ole::{ - OleGetClipboard, OleInitialize, OleSetClipboard, OleUninitialize, ReleaseStgMedium, - }, - Threading::CREATE_NO_WINDOW, + Ole::{OleGetClipboard, OleInitialize, OleUninitialize, ReleaseStgMedium}, Time::{GetTimeZoneInformation, TIME_ZONE_ID_INVALID}, }, UI::{ HiDpi::{SetProcessDpiAwarenessContext, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE}, Input::KeyboardAndMouse::{ - GetDoubleClickTime, ToUnicode, VIRTUAL_KEY, VK_BACK, VK_DELETE, VK_DOWN, VK_END, - VK_ESCAPE, VK_F1, VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, - VK_F8, VK_F9, VK_HOME, VK_LEFT, VK_NEXT, VK_PRIOR, VK_RETURN, VK_RIGHT, VK_UP, + GetDoubleClickTime, VIRTUAL_KEY, VK_BACK, VK_DELETE, VK_DOWN, VK_END, VK_ESCAPE, + VK_F1, VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, + VK_F9, VK_HOME, VK_LEFT, VK_NEXT, VK_PRIOR, VK_RETURN, VK_RIGHT, VK_UP, }, Shell::{ FileOpenDialog, FileSaveDialog, IFileOpenDialog, IFileSaveDialog, IShellItem, @@ -57,11 +46,11 @@ use windows::{ FOS_ALLOWMULTISELECT, FOS_PICKFOLDERS, SIGDN_PARENTRELATIVEPARSING, }, WindowsAndMessaging::{ - AppendMenuW, CreateAcceleratorTableW, CreateMenu, DefWindowProcW, DestroyWindow, - DispatchMessageW, GetMessageW, LoadCursorW, LoadImageW, PostQuitMessage, SetCursor, - TranslateMessage, ACCEL, ACCEL_VIRT_FLAGS, HCURSOR, HMENU, IDC_ARROW, IDC_CROSS, - IDC_HAND, IDC_IBEAM, IDC_NO, IDC_SIZENS, IDC_SIZEWE, IMAGE_CURSOR, LR_DEFAULTSIZE, - LR_SHARED, MF_POPUP, MF_SEPARATOR, MF_STRING, SW_SHOWDEFAULT, WM_DESTROY, + AppendMenuW, CreateAcceleratorTableW, CreateMenu, DefWindowProcW, DispatchMessageW, + GetMessageW, LoadImageW, PostQuitMessage, SetCursor, TranslateMessage, ACCEL, + ACCEL_VIRT_FLAGS, HCURSOR, HMENU, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_IBEAM, + IDC_NO, IDC_SIZENS, IDC_SIZEWE, IMAGE_CURSOR, LR_DEFAULTSIZE, LR_SHARED, MF_POPUP, + MF_SEPARATOR, MF_STRING, SW_SHOWDEFAULT, WM_DESTROY, }, }, }, @@ -221,7 +210,7 @@ impl Platform for WindowsPlatform { fn restart(&self) {} //todo!(windows) - fn activate(&self, ignoring_other_apps: bool) {} + fn activate(&self, _ignoring_other_apps: bool) {} //todo!(windows) fn hide(&self) {} @@ -467,7 +456,7 @@ impl Platform for WindowsPlatform { } // todo("windows") - fn path_for_auxiliary_executable(&self, name: &str) -> Result { + fn path_for_auxiliary_executable(&self, _name: &str) -> Result { unimplemented!() } @@ -622,17 +611,22 @@ impl Platform for WindowsPlatform { } // todo!(windows) - fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task> { + fn write_credentials( + &self, + _url: &str, + _usernamee: &str, + _passwordrd: &[u8], + ) -> Task> { unimplemented!() } // todo!(windows) - fn read_credentials(&self, url: &str) -> Task)>>> { + fn read_credentials(&self, _url: &str) -> Task)>>> { unimplemented!() } // todo!(windows) - fn delete_credentials(&self, url: &str) -> Task> { + fn delete_credentials(&self, _url: &str) -> Task> { unimplemented!() } @@ -777,7 +771,7 @@ unsafe fn generate_menu( crate::MenuItem::Action { name, action, - os_action, + os_action: _, } => { let keystrokes = keymap .bindings_for_action(action.as_ref()) diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 5f55a5ea1a9a2..eb2d67b115e8d 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -1,35 +1,19 @@ -use std::{ - cell::{Cell, RefCell}, - ffi::c_void, - mem, - num::NonZeroIsize, - path::PathBuf, - rc::{Rc, Weak}, - str::FromStr, - sync::{ - atomic::{AtomicIsize, Ordering}, - Arc, - }, -}; +use std::{cell::RefCell, mem, path::PathBuf, rc::Rc, str::FromStr, sync::Arc}; use futures::channel::oneshot; -use parking_lot::Mutex; use raw_window_handle as rwh; use smallvec::SmallVec; use util::ResultExt; use windows::{ - core::{implement, IUnknown, Interface, IntoParam, Param, ReferenceType, PCWSTR}, + core::{implement, PCWSTR}, Win32::{ - Foundation::{ - ERROR_UNRECOVERABLE_STACK_OVERFLOW, HWND, LPARAM, LRESULT, POINTL, RECT, S_OK, WPARAM, - }, + Foundation::{HWND, LPARAM, LRESULT, POINTL, RECT, S_OK, WPARAM}, Graphics::Gdi::{ - GetMonitorInfoW, MonitorFromWindow, RedrawWindow, UpdateWindow, ValidateRect, HRGN, - MONITORINFO, MONITOR_DEFAULTTONEAREST, RDW_ERASENOW, RDW_INVALIDATE, RDW_UPDATENOW, + MonitorFromWindow, RedrawWindow, ValidateRect, HRGN, MONITOR_DEFAULTTONEAREST, + RDW_ERASENOW, RDW_INVALIDATE, RDW_UPDATENOW, }, System::{ Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL}, - Memory::{GlobalLock, GlobalUnlock}, Ole::{ IDropTarget, IDropTarget_Impl, RegisterDragDrop, ReleaseStgMedium, RevokeDragDrop, CF_HDROP, DROPEFFECT, DROPEFFECT_LINK, DROPEFFECT_NONE, @@ -38,8 +22,8 @@ use windows::{ }, UI::{ Controls::{ - TaskDialogIndirect, TASKDIALOGCONFIG, TASKDIALOG_BUTTON, TASKDIALOG_FLAGS, - TDF_USE_HICON_MAIN, TD_ERROR_ICON, TD_INFORMATION_ICON, TD_WARNING_ICON, + TaskDialogIndirect, TASKDIALOGCONFIG, TASKDIALOG_BUTTON, TD_ERROR_ICON, + TD_INFORMATION_ICON, TD_WARNING_ICON, }, HiDpi::{GetDpiForMonitor, GetDpiForWindow, MDT_EFFECTIVE_DPI}, Input::{ @@ -47,32 +31,29 @@ use windows::{ ImmGetContext, ImmReleaseContext, ImmSetCompositionWindow, CFS_POINT, COMPOSITIONFORM, }, - KeyboardAndMouse::GetMouseMovePointsEx, + KeyboardAndMouse::SetActiveWindow, }, - Shell::{DragQueryFileA, DragQueryFileW, HDROP}, + Shell::{DragQueryFileW, HDROP}, WindowsAndMessaging::{ - CreateWindowExW, DefWindowProcW, GetClientRect, GetCursorPos, KillTimer, - MessageBoxExW, PostMessageW, PostQuitMessage, RegisterClassExW, SetTimer, - SetWindowTextW, ShowWindow, CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, GWLP_HINSTANCE, - HMENU, SIZE_MINIMIZED, SW_SHOW, TIMERPROC, WA_ACTIVE, WA_CLICKACTIVE, WA_INACTIVE, - WINDOW_EX_STYLE, WINDOW_STYLE, WM_ACTIVATE, WM_CHAR, WM_CLOSE, WM_COMMAND, - WM_DESTROY, WM_DROPFILES, WM_IME_STARTCOMPOSITION, WM_KEYDOWN, WM_KEYUP, + DefWindowProcW, GetClientRect, GetCursorPos, KillTimer, PostMessageW, + PostQuitMessage, SetTimer, SetWindowTextW, ShowWindow, CW_USEDEFAULT, + GWLP_HINSTANCE, HMENU, SIZE_MINIMIZED, SW_MINIMIZE, SW_SHOW, TIMERPROC, WA_ACTIVE, + WA_CLICKACTIVE, WA_INACTIVE, WINDOW_EX_STYLE, WINDOW_STYLE, WM_ACTIVATE, WM_CHAR, + WM_COMMAND, WM_DESTROY, WM_IME_STARTCOMPOSITION, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDBLCLK, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_PAINT, WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SIZE, WM_TIMER, - WM_XBUTTONDBLCLK, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSEXW, WS_EX_ACCEPTFILES, - WS_MAXIMIZE, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_VISIBLE, + WM_XBUTTONDBLCLK, WM_XBUTTONDOWN, WM_XBUTTONUP, WS_MAXIMIZE, WS_POPUP, WS_VISIBLE, }, }, }, }; use crate::{ - available_monitors, encode_wide, get_module_handle, hiword, log_windows_error, - log_windows_error_with_message, loword, parse_dropfiles, parse_keyboard_input, - parse_mouse_button, parse_mouse_hwheel, parse_mouse_movement, parse_mouse_vwheel, - parse_system_key, platform::cross_platform::BladeRenderer, set_windowdata, Action, Bounds, - DisplayId, ForegroundExecutor, Modifiers, Pixels, PlatformDisplay, PlatformInput, + available_monitors, encode_wide, hiword, log_windows_error, log_windows_error_with_message, + loword, parse_keyboard_input, parse_mouse_button, parse_mouse_hwheel, parse_mouse_movement, + parse_mouse_vwheel, parse_system_key, platform::cross_platform::BladeRenderer, set_windowdata, + Bounds, DisplayId, ForegroundExecutor, Modifiers, Pixels, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, Size, WindowKind, WindowOptions, WindowsWindowBase, WindowsWinodwDataWrapper, DRAGDROP_GET_COUNT, FILENAME_MAXLENGTH, MENU_ACTIONS, WINDOW_CLOSE, WINDOW_REFRESH_TIMER, WINODW_EXTRA_EXSTYLE, @@ -108,13 +89,13 @@ impl WindowsWindow { options: &WindowOptions, menu_handle: Option, ) -> Self { - let mut monitor = available_monitors() + let mut _monitor = available_monitors() .into_iter() .nth(0) .expect("no monitor detected!"); let mut display = WindowsDisplay::new(DisplayId(0)); if let Some(display_id) = options.display_id { - monitor = available_monitors() + _monitor = available_monitors() .into_iter() .nth(display_id.0 as usize) .unwrap(); @@ -122,6 +103,7 @@ impl WindowsWindow { display.display_id = display_id; } // let scale_factor = monitor.scale_factor(); + // TODO: actually use scale factor let scale_factor = 1.0; let mut lpwindowname = None; @@ -170,7 +152,6 @@ impl WindowsWindow { let renderer = BladeRenderer::new(gpu, gpu_extent); let inner = WindowsWindowinner::new( dispatch_window_handle, - options, scale_factor, window_handle, bounds, @@ -205,7 +186,7 @@ impl WindowsWindow { pub struct WindowsWindowinner { pub dispatch_window_handle: HWND, - pub window_handle: RawWindow, + window_handle: RawWindow, bounds: RefCell>, scale_factor: f32, pub callbacks: RefCell, @@ -223,9 +204,8 @@ struct RawWindow { } impl WindowsWindowinner { - pub fn new( + fn new( dispatch_window_handle: HWND, - options: &WindowOptions, scale_factor: f32, window_handle: RawWindow, bounds: Bounds, @@ -320,7 +300,7 @@ impl WindowsWindowinner { }, }; *bounds_lock = bounds; - let window_size = self.window_handle.size(); + let _window_size = self.window_handle.size(); let gpu_size = blade_graphics::Extent { width, height, @@ -488,7 +468,7 @@ impl IDropTarget_Impl for WindowsDragDropTarget { fn DragEnter( &self, pdataobj: Option<&IDataObject>, - grfkeystate: MODIFIERKEYS_FLAGS, + _grfkeystate: MODIFIERKEYS_FLAGS, pt: &POINTL, pdweffect: *mut DROPEFFECT, ) -> windows::core::Result<()> { @@ -550,9 +530,9 @@ impl IDropTarget_Impl for WindowsDragDropTarget { fn DragOver( &self, - grfkeystate: MODIFIERKEYS_FLAGS, + _grfkeystate: MODIFIERKEYS_FLAGS, pt: &POINTL, - pdweffect: *mut DROPEFFECT, + _pdweffect: *mut DROPEFFECT, ) -> windows::core::Result<()> { let input = PlatformInput::FileDrop(crate::FileDropEvent::Pending { position: Point { @@ -574,10 +554,10 @@ impl IDropTarget_Impl for WindowsDragDropTarget { fn Drop( &self, - pdataobj: ::core::option::Option<&IDataObject>, - grfkeystate: MODIFIERKEYS_FLAGS, + _pdataobj: ::core::option::Option<&IDataObject>, + _grfkeystate: MODIFIERKEYS_FLAGS, pt: &POINTL, - pdweffect: *mut DROPEFFECT, + _pdweffect: *mut DROPEFFECT, ) -> windows::core::Result<()> { let input = PlatformInput::FileDrop(crate::FileDropEvent::Submit { position: Point { @@ -621,10 +601,12 @@ impl PlatformWindow for WindowsWindow { self.inner.scale_factor } + // todo("windows") fn titlebar_height(&self) -> Pixels { todo!() } + // todo("windows") fn appearance(&self) -> crate::WindowAppearance { crate::WindowAppearance::Light } @@ -726,26 +708,36 @@ impl PlatformWindow for WindowsWindow { done_rx } - fn activate(&self) {} + fn activate(&self) { + unsafe { + let _ = SetActiveWindow(self.inner.window_handle.hwnd()); + } + } fn set_title(&mut self, title: &str) { self.inner.window_handle.set_title(title); } - fn set_edited(&mut self, edited: bool) {} + // todo("windows") + fn set_edited(&mut self, _edited: bool) {} + // todo("windows") fn show_character_palette(&self) { todo!() } fn minimize(&self) { - // TODO: + unsafe { + ShowWindow(self.inner.window_handle.hwnd(), SW_MINIMIZE); + } } + // todo("windows") fn zoom(&self) { todo!() } + // todo("windows") fn toggle_full_screen(&self) { todo!() } @@ -786,7 +778,8 @@ impl PlatformWindow for WindowsWindow { self.inner.callbacks.borrow_mut().appearance_changed = Some(callback); } - fn is_topmost_for_position(&self, position: crate::Point) -> bool { + // todo("windows") + fn is_topmost_for_position(&self, _position: crate::Point) -> bool { todo!() } From 475255ef542323ad5a2f53f2ea5e1dfce94795d4 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sat, 2 Mar 2024 22:43:24 +0800 Subject: [PATCH 18/39] disable mouse leave event --- crates/gpui/src/platform/windows/events.rs | 216 +++++++++---------- crates/gpui/src/platform/windows/platform.rs | 10 +- crates/gpui/src/platform/windows/window.rs | 102 +++++---- 3 files changed, 174 insertions(+), 154 deletions(-) diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index 5f755b959d7f8..f62e9fcb49a99 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -1,16 +1,20 @@ -use std::rc::Rc; +use std::{ + rc::Rc, + sync::atomic::{AtomicBool, AtomicUsize, Ordering}, +}; use windows::{ core::PCWSTR, Win32::{ - Foundation::{HWND, LPARAM, LRESULT, WPARAM}, + Foundation::{HANDLE, HWND, LPARAM, LRESULT, WPARAM}, Graphics::Gdi::HBRUSH, UI::{ Input::KeyboardAndMouse::{ - VIRTUAL_KEY, VK_BACK, VK_CONTROL, VK_DELETE, VK_DOWN, VK_END, VK_ESCAPE, VK_F1, - VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, - VK_HOME, VK_LEFT, VK_LWIN, VK_MENU, VK_NEXT, VK_PRIOR, VK_RETURN, VK_RIGHT, - VK_RWIN, VK_SHIFT, VK_UP, + GetAsyncKeyState, TrackMouseEvent, TME_LEAVE, TRACKMOUSEEVENT, VIRTUAL_KEY, + VK_BACK, VK_CONTROL, VK_DELETE, VK_DOWN, VK_END, VK_ESCAPE, VK_F1, VK_F10, VK_F11, + VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_HOME, + VK_LBUTTON, VK_LEFT, VK_LWIN, VK_MBUTTON, VK_MENU, VK_NEXT, VK_PRIOR, VK_RBUTTON, + VK_RETURN, VK_RIGHT, VK_RWIN, VK_SHIFT, VK_UP, }, WindowsAndMessaging::{ CreateWindowExW, DefWindowProcW, RegisterClassExW, CS_DBLCLKS, CS_HREDRAW, @@ -24,10 +28,11 @@ use windows::{ }; use crate::{ - get_module_handle, get_windowdata, hiword, loword, KeyDownEvent, KeyUpEvent, Keystroke, - Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, PlatformInput, - Point, ScrollDelta, ScrollWheelEvent, TouchPhase, MOUSE_MOVE_BUTTONS, MOUSE_MOVE_LBUTTON, - MOUSE_MOVE_MBUTTON, MOUSE_MOVE_RBUTTON, MOUSE_MOVE_XBUTTON1, MOUSE_MOVE_XBUTTON2, + get_module_handle, get_windowdata, hiword, log_windows_error, loword, KeyDownEvent, KeyUpEvent, + Keystroke, Modifiers, MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent, + MouseUpEvent, Pixels, PlatformInput, Point, ScrollDelta, ScrollWheelEvent, TouchPhase, + MOUSE_MOVE_BUTTONS, MOUSE_MOVE_LBUTTON, MOUSE_MOVE_MBUTTON, MOUSE_MOVE_RBUTTON, + MOUSE_MOVE_XBUTTON1, MOUSE_MOVE_XBUTTON2, }; pub struct WindowsWinodwDataWrapper(pub Rc); @@ -36,7 +41,13 @@ pub trait WindowsWindowBase where Self: Sized, { - unsafe fn handle_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT; + unsafe fn handle_message( + &self, + handle: HWND, + message: u32, + wparam: WPARAM, + lparam: LPARAM, + ) -> LRESULT; extern "system" fn event_runner( handle: HWND, @@ -50,7 +61,7 @@ where return DefWindowProcW(handle, message, wparam, lparam); } let this = &*ptr; - this.0.handle_message(message, wparam, lparam) + this.0.handle_message(handle, message, wparam, lparam) } } @@ -175,10 +186,10 @@ pub fn parse_system_key( pub fn parse_keyboard_input( wparam: WPARAM, lparam: LPARAM, - modifiers: &Modifiers, + modifiers: Modifiers, ) -> Option { - if wparam.0 == 8 || wparam.0 == 27 || wparam.0 == 13 || (lparam.0 >> 24) & 1 == 1 { - // backspace escape enter ctrl + if wparam.0 == 8 || wparam.0 == 27 || wparam.0 == 13 { + // backspace escape enter // these keys are handled by Zed return None; } @@ -191,13 +202,14 @@ pub fn parse_keyboard_input( }; println!("{} => {:?}", wparam.0, first_char); if first_char.is_control() { + // ctrl is handled by zed return None; } Some(PlatformInput::KeyDown(KeyDownEvent { keystroke: Keystroke { key: first_char.to_string(), ime_key: None, - modifiers: modifiers.clone(), + modifiers, }, is_held: lparam.0 & (0x1 << 30) > 0, })) @@ -207,109 +219,79 @@ pub fn parse_mouse_button( msg: u32, wparam: WPARAM, lparam: LPARAM, - modifiers: &Modifiers, + modifiers: Modifiers, ) -> PlatformInput { + let position = parse_mouse_events_lparam(lparam); match msg { WM_LBUTTONDOWN => PlatformInput::MouseDown(MouseDownEvent { button: MouseButton::Left, - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 1, }), + WM_LBUTTONDBLCLK => PlatformInput::MouseDown(MouseDownEvent { button: MouseButton::Left, - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 2, }), WM_LBUTTONUP => PlatformInput::MouseUp(MouseUpEvent { button: MouseButton::Left, - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 1, }), WM_RBUTTONDOWN => PlatformInput::MouseDown(MouseDownEvent { button: MouseButton::Right, - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 1, }), WM_RBUTTONDBLCLK => PlatformInput::MouseDown(MouseDownEvent { button: MouseButton::Right, - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 2, }), WM_RBUTTONUP => PlatformInput::MouseUp(MouseUpEvent { button: MouseButton::Right, - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 1, }), WM_MBUTTONDOWN => PlatformInput::MouseDown(MouseDownEvent { button: MouseButton::Middle, - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 1, }), WM_MBUTTONDBLCLK => PlatformInput::MouseDown(MouseDownEvent { button: MouseButton::Middle, - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 2, }), WM_MBUTTONUP => PlatformInput::MouseUp(MouseUpEvent { button: MouseButton::Middle, - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 1, }), + WM_XBUTTONDOWN => { if hiword!(wparam.0, u16) == XBUTTON1 { PlatformInput::MouseDown(MouseDownEvent { button: MouseButton::Navigate(crate::NavigationDirection::Forward), - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 1, }) } else { PlatformInput::MouseDown(MouseDownEvent { button: MouseButton::Navigate(crate::NavigationDirection::Back), - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 1, }) } @@ -318,21 +300,15 @@ pub fn parse_mouse_button( if hiword!(wparam.0, u16) == XBUTTON1 { PlatformInput::MouseDown(MouseDownEvent { button: MouseButton::Navigate(crate::NavigationDirection::Forward), - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 2, }) } else { PlatformInput::MouseDown(MouseDownEvent { button: MouseButton::Navigate(crate::NavigationDirection::Back), - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 2, }) } @@ -341,21 +317,15 @@ pub fn parse_mouse_button( if hiword!(wparam.0, u16) == XBUTTON1 { PlatformInput::MouseUp(MouseUpEvent { button: MouseButton::Navigate(crate::NavigationDirection::Forward), - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 1, }) } else { PlatformInput::MouseUp(MouseUpEvent { button: MouseButton::Navigate(crate::NavigationDirection::Back), - position: crate::Point { - x: crate::Pixels(loword!(lparam.0, i16) as _), - y: crate::Pixels(hiword!(lparam.0, i16) as _), - }, - modifiers: modifiers.clone(), + position, + modifiers, click_count: 1, }) } @@ -364,15 +334,30 @@ pub fn parse_mouse_button( } } -pub fn parse_mouse_movement( - wparam: WPARAM, - lparam: LPARAM, - modifiers: Modifiers, -) -> (Point, PlatformInput) { - let new_pos = Point { +// #[inline] +// pub unsafe fn query_mouse_button_state() -> Option { +// if GetAsyncKeyState(VK_LBUTTON.0 as _) & 1 > 0 { +// return Some(MouseButton::Left); +// } +// if GetAsyncKeyState(VK_RBUTTON.0 as _) & 1 > 0 { +// return Some(MouseButton::Right); +// } +// if GetAsyncKeyState(VK_MBUTTON.0 as _) & 1 > 0 { +// return Some(MouseButton::Middle); +// } +// None +// } + +#[inline] +pub fn parse_mouse_events_lparam(lparam: LPARAM) -> Point { + Point { x: Pixels(loword!(lparam.0, i16) as _), y: Pixels(hiword!(lparam.0, i16) as _), - }; + } +} + +#[inline] +pub fn parse_mouse_movement_wparam(wparam: WPARAM) -> Option { let mut pressed_button = None; for button_mask in MOUSE_MOVE_BUTTONS { if wparam.0 & button_mask > 0 { @@ -380,23 +365,14 @@ pub fn parse_mouse_movement( break; } } - let input = PlatformInput::MouseMove(MouseMoveEvent { - position: new_pos.clone(), - pressed_button, - modifiers, - }); - - (new_pos, input) + pressed_button } pub fn parse_mouse_vwheel(wparam: WPARAM, lparam: LPARAM, modifiers: Modifiers) -> PlatformInput { - let position = Point { - x: Pixels(loword!(lparam.0, i16) as _), - y: Pixels(hiword!(lparam.0, i16) as _), - }; let lines = hiword!(wparam.0, i16); + PlatformInput::ScrollWheel(ScrollWheelEvent { - position, + position: parse_mouse_events_lparam(lparam), delta: ScrollDelta::Lines(Point { x: 0.0, y: lines as f32 / 120.0, @@ -407,13 +383,10 @@ pub fn parse_mouse_vwheel(wparam: WPARAM, lparam: LPARAM, modifiers: Modifiers) } pub fn parse_mouse_hwheel(wparam: WPARAM, lparam: LPARAM, modifiers: Modifiers) -> PlatformInput { - let position = Point { - x: Pixels(loword!(lparam.0, i16) as _), - y: Pixels(hiword!(lparam.0, i16) as _), - }; let lines = hiword!(wparam.0, i16); + PlatformInput::ScrollWheel(ScrollWheelEvent { - position, + position: parse_mouse_events_lparam(lparam), delta: ScrollDelta::Lines(Point { x: lines as f32 / 120.0, y: 0.0, @@ -423,6 +396,17 @@ pub fn parse_mouse_hwheel(wparam: WPARAM, lparam: LPARAM, modifiers: Modifiers) }) } +// pub unsafe fn enable_tracking_mouse_leave_event(handle: HWND) { +// let mut config = TRACKMOUSEEVENT { +// cbSize: std::mem::size_of::() as _, +// dwFlags: TME_LEAVE, +// hwndTrack: handle, +// dwHoverTime: 0, +// }; +// // Zed should run without mouse-leave event emitting +// let _ = TrackMouseEvent(&mut config as _).inspect_err(log_windows_error); +// } + fn buttonmask_to_button(mask: usize) -> Option { match mask { MOUSE_MOVE_LBUTTON => Some(MouseButton::Left), diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index e5d3d8ff5439b..f548c606885c0 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -637,7 +637,13 @@ impl Platform for WindowsPlatform { } impl WindowsWindowBase for WindowsPlatformInner { - unsafe fn handle_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT { + unsafe fn handle_message( + &self, + handle: HWND, + message: u32, + wparam: WPARAM, + lparam: LPARAM, + ) -> LRESULT { match message { MAIN_DISPATCH => { if let Ok(runnable) = self.main_receiver.try_recv() { @@ -663,7 +669,7 @@ impl WindowsWindowBase for WindowsPlatformInner { } LRESULT(0) } - _ => DefWindowProcW(self.dispatch_window_handle, message, wparam, lparam), + _ => DefWindowProcW(handle, message, wparam, lparam), } } } diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index eb2d67b115e8d..5a7d7c5c330b3 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -7,7 +7,7 @@ use util::ResultExt; use windows::{ core::{implement, PCWSTR}, Win32::{ - Foundation::{HWND, LPARAM, LRESULT, POINTL, RECT, S_OK, WPARAM}, + Foundation::{HANDLE, HWND, LPARAM, LRESULT, POINTL, RECT, S_OK, WPARAM}, Graphics::Gdi::{ MonitorFromWindow, RedrawWindow, ValidateRect, HRGN, MONITOR_DEFAULTTONEAREST, RDW_ERASENOW, RDW_INVALIDATE, RDW_UPDATENOW, @@ -23,7 +23,7 @@ use windows::{ UI::{ Controls::{ TaskDialogIndirect, TASKDIALOGCONFIG, TASKDIALOG_BUTTON, TD_ERROR_ICON, - TD_INFORMATION_ICON, TD_WARNING_ICON, + TD_INFORMATION_ICON, TD_WARNING_ICON, WM_MOUSELEAVE, }, HiDpi::{GetDpiForMonitor, GetDpiForWindow, MDT_EFFECTIVE_DPI}, Input::{ @@ -31,7 +31,7 @@ use windows::{ ImmGetContext, ImmReleaseContext, ImmSetCompositionWindow, CFS_POINT, COMPOSITIONFORM, }, - KeyboardAndMouse::SetActiveWindow, + KeyboardAndMouse::{SetActiveWindow, TrackMouseEvent, TME_LEAVE, TRACKMOUSEEVENT}, }, Shell::{DragQueryFileW, HDROP}, WindowsAndMessaging::{ @@ -51,13 +51,13 @@ use windows::{ use crate::{ available_monitors, encode_wide, hiword, log_windows_error, log_windows_error_with_message, - loword, parse_keyboard_input, parse_mouse_button, parse_mouse_hwheel, parse_mouse_movement, - parse_mouse_vwheel, parse_system_key, platform::cross_platform::BladeRenderer, set_windowdata, - Bounds, DisplayId, ForegroundExecutor, Modifiers, Pixels, PlatformDisplay, PlatformInput, - PlatformInputHandler, PlatformWindow, Point, Size, WindowKind, WindowOptions, - WindowsWindowBase, WindowsWinodwDataWrapper, DRAGDROP_GET_COUNT, FILENAME_MAXLENGTH, - MENU_ACTIONS, WINDOW_CLOSE, WINDOW_REFRESH_TIMER, WINODW_EXTRA_EXSTYLE, - WINODW_REFRESH_INTERVAL, WINODW_STYLE, + loword, parse_keyboard_input, parse_mouse_button, parse_mouse_events_lparam, + parse_mouse_hwheel, parse_mouse_movement_wparam, parse_mouse_vwheel, parse_system_key, + platform::cross_platform::BladeRenderer, set_windowdata, Bounds, DisplayId, ForegroundExecutor, + Modifiers, Pixels, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, + Size, WindowKind, WindowOptions, WindowsWindowBase, WindowsWinodwDataWrapper, + DRAGDROP_GET_COUNT, FILENAME_MAXLENGTH, MENU_ACTIONS, WINDOW_CLOSE, WINDOW_REFRESH_TIMER, + WINODW_EXTRA_EXSTYLE, WINODW_REFRESH_INTERVAL, WINODW_STYLE, }; use super::{display::WindowsDisplay, WINDOW_CLASS}; @@ -163,15 +163,15 @@ impl WindowsWindow { WINDOW_REFRESH_TIMER, WINODW_REFRESH_INTERVAL, TIMERPROC::None, - ) - }; + ); + } let windows_dragdrop = unsafe { set_windowdata(raw_window_handle, WindowsWinodwDataWrapper(inner.clone())); let drop_target = WindowsDragDropTarget(inner.clone()); let windows_dragdrop: IDropTarget = drop_target.into(); RegisterDragDrop(raw_window_handle, &windows_dragdrop) .inspect_err(log_windows_error) - .expect("Unable to register drawgrop op"); + .expect("Unable to register drag-drop op"); windows_dragdrop }; @@ -193,7 +193,6 @@ pub struct WindowsWindowinner { input_handler: RefCell>, pub renderer: RefCell, pub modifiers: RefCell, - mouse_position: RefCell>, } #[implement(IDropTarget)] @@ -222,7 +221,6 @@ impl WindowsWindowinner { scale_factor, renderer: RefCell::new(renderer), modifiers: RefCell::new(Modifiers::default()), - mouse_position: RefCell::new(Point::default()), }) } @@ -333,7 +331,13 @@ impl WindowsWindowinner { } impl WindowsWindowBase for WindowsWindowinner { - unsafe fn handle_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT { + unsafe fn handle_message( + &self, + handle: HWND, + message: u32, + wparam: WPARAM, + lparam: LPARAM, + ) -> LRESULT { match message { WM_TIMER => { self.update(); @@ -341,8 +345,8 @@ impl WindowsWindowBase for WindowsWindowinner { } WM_PAINT => { self.request_redraw(); - ValidateRect(self.window_handle.hwnd(), None); - DefWindowProcW(self.window_handle.hwnd(), message, wparam, lparam) + ValidateRect(handle, None); + DefWindowProcW(handle, message, wparam, lparam) } WM_DESTROY => { self.destroy(); @@ -355,7 +359,7 @@ impl WindowsWindowBase for WindowsWindowinner { if let Some(func) = self.callbacks.borrow_mut().close.take() { func(); } - let _ = KillTimer(self.window_handle.hwnd(), WINDOW_REFRESH_TIMER); + let _ = KillTimer(handle, WINDOW_REFRESH_TIMER); PostQuitMessage(0); LRESULT(0) } @@ -384,30 +388,42 @@ impl WindowsWindowBase for WindowsWindowinner { let mut modifiers = self.modifiers.borrow().clone(); if let Some(key) = parse_system_key(message, wparam, lparam, &mut modifiers) { self.handle_input(key); + let mut old_state = self.modifiers.borrow_mut(); + if modifiers != *old_state { + let input = PlatformInput::ModifiersChanged(crate::ModifiersChangedEvent { + modifiers: modifiers.clone(), + }); + self.handle_input(input); + (*old_state) = modifiers; + } self.update_now(); } - (*self.modifiers.borrow_mut()) = modifiers; LRESULT(0) } WM_LBUTTONDOWN | WM_RBUTTONDOWN | WM_MBUTTONDOWN | WM_LBUTTONUP | WM_RBUTTONUP | WM_MBUTTONUP | WM_XBUTTONDOWN | WM_XBUTTONUP | WM_LBUTTONDBLCLK | WM_RBUTTONDBLCLK | WM_MBUTTONDBLCLK | WM_XBUTTONDBLCLK => { - let modifiers = self.modifiers.borrow(); - let key = parse_mouse_button(message, wparam, lparam, &modifiers); + let modifiers = self.modifiers.borrow().clone(); + let key = parse_mouse_button(message, wparam, lparam, modifiers); self.handle_input(key); self.update_now(); LRESULT(0) } WM_MOUSEMOVE => { let modifiers = self.modifiers.borrow().clone(); - let (new_pos, input) = parse_mouse_movement(wparam, lparam, modifiers); - *self.mouse_position.borrow_mut() = new_pos; - self.handle_input(input); + let pressed_button = parse_mouse_movement_wparam(wparam); + let new_position = parse_mouse_events_lparam(lparam); + let move_event = PlatformInput::MouseMove(crate::MouseMoveEvent { + position: new_position.clone(), + pressed_button, + modifiers, + }); + self.handle_input(move_event); LRESULT(0) } WM_CHAR => { - let modifiers = self.modifiers.borrow(); - let keycode = parse_keyboard_input(wparam, lparam, &*modifiers); + let modifiers = self.modifiers.borrow().clone(); + let keycode = parse_keyboard_input(wparam, lparam, modifiers); if let Some(key) = keycode { self.handle_input(key); self.update_now(); @@ -430,7 +446,7 @@ impl WindowsWindowBase for WindowsWindowinner { } WM_SIZE => { if wparam.0 as u32 == SIZE_MINIMIZED { - return DefWindowProcW(self.window_handle.hwnd(), message, wparam, lparam); + return DefWindowProcW(handle, message, wparam, lparam); } let width = loword!(lparam.0, u16) as u32; let height = hiword!(lparam.0, u16) as u32; @@ -443,15 +459,17 @@ impl WindowsWindowBase for WindowsWindowinner { let mut config = COMPOSITIONFORM::default(); config.dwStyle = CFS_POINT; let mut cursor = std::mem::zeroed(); - if let Err(ref e) = GetCursorPos(&mut cursor) { - log_windows_error(e); - cursor.x = self.mouse_position.borrow().x.0 as _; - cursor.y = self.mouse_position.borrow().y.0 as _; + if GetCursorPos(&mut cursor) + .inspect_err(log_windows_error) + .is_err() + { + cursor.x = 0; + cursor.y = 0; } config.ptCurrentPos.x = cursor.x; config.ptCurrentPos.y = cursor.y; ImmSetCompositionWindow(ctx, &config as _); - ImmReleaseContext(self.window_handle.hwnd(), ctx); + ImmReleaseContext(handle, ctx); self.update(); println!( "Set composition pos: ({}, {})", @@ -459,7 +477,7 @@ impl WindowsWindowBase for WindowsWindowinner { ); LRESULT(0) } - _ => DefWindowProcW(self.window_handle.hwnd(), message, wparam, lparam), + _ => DefWindowProcW(handle, message, wparam, lparam), } } } @@ -615,8 +633,20 @@ impl PlatformWindow for WindowsWindow { Rc::clone(&self.display) } - fn mouse_position(&self) -> crate::Point { - self.inner.mouse_position.borrow().clone() + fn mouse_position(&self) -> Point { + unsafe { + let mut position = std::mem::zeroed(); + if GetCursorPos(&mut position) + .inspect_err(log_windows_error) + .is_err() + { + return Point::default(); + } + Point { + x: Pixels(position.x as _), + y: Pixels(position.y as _), + } + } } fn modifiers(&self) -> crate::Modifiers { From 95a418a722d8c4794b53b60b6eb4222ab4daa373 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sat, 2 Mar 2024 23:00:16 +0800 Subject: [PATCH 19/39] fix ime --- crates/gpui/src/platform/windows/window.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 5a7d7c5c330b3..3e68c15036cbb 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -455,7 +455,7 @@ impl WindowsWindowBase for WindowsWindowinner { LRESULT(0) } WM_IME_STARTCOMPOSITION => { - let ctx = ImmGetContext(None); + let ctx = ImmGetContext(handle); let mut config = COMPOSITIONFORM::default(); config.dwStyle = CFS_POINT; let mut cursor = std::mem::zeroed(); @@ -470,7 +470,6 @@ impl WindowsWindowBase for WindowsWindowinner { config.ptCurrentPos.y = cursor.y; ImmSetCompositionWindow(ctx, &config as _); ImmReleaseContext(handle, ctx); - self.update(); println!( "Set composition pos: ({}, {})", config.ptCurrentPos.x, config.ptCurrentPos.y From c791e4c6fc6cc3e51a79d88b9b35894eafc3bbae Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sat, 2 Mar 2024 23:48:21 +0800 Subject: [PATCH 20/39] small fix --- crates/gpui/src/platform/windows/window.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 3e68c15036cbb..6bb81bb62e3a1 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -833,7 +833,8 @@ impl RawWindow { pub fn set_title(&self, title: &str) { let title_vec = encode_wide(title); unsafe { - SetWindowTextW(self.hwnd(), PCWSTR::from_raw(title_vec.as_ptr())).log_err(); + let _ = SetWindowTextW(self.hwnd(), PCWSTR::from_raw(title_vec.as_ptr())) + .inspect_err(log_windows_error); } } From d87546942a6b51ff201d5565a1f7c11db42f6800 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sun, 3 Mar 2024 01:03:53 +0800 Subject: [PATCH 21/39] remove unused --- crates/gpui/Cargo.toml | 2 -- crates/gpui/src/platform/windows/events.rs | 25 +++++++++------------- crates/gpui/src/platform/windows/window.rs | 6 +++--- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 3feb4c2f3078c..839138e335c4d 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -136,7 +136,6 @@ windows = { version = "0.54", features = [ "Wdk_System_SystemServices", "Win32_Foundation", "Win32_Globalization", - "Win32_Graphics_DirectWrite", "Win32_Graphics_Gdi", "Win32_Security_Credentials", "Win32_System_Com", @@ -154,7 +153,6 @@ windows = { version = "0.54", features = [ "Win32_UI_HiDpi", "Win32_UI_Input_Ime", "Win32_UI_Input_KeyboardAndMouse", - "Win32_UI_Input_Pointer", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging", ] } diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index f62e9fcb49a99..df9112fd02ee3 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -1,20 +1,16 @@ -use std::{ - rc::Rc, - sync::atomic::{AtomicBool, AtomicUsize, Ordering}, -}; +use std::rc::Rc; use windows::{ core::PCWSTR, Win32::{ - Foundation::{HANDLE, HWND, LPARAM, LRESULT, WPARAM}, + Foundation::{HWND, LPARAM, LRESULT, WPARAM}, Graphics::Gdi::HBRUSH, UI::{ Input::KeyboardAndMouse::{ - GetAsyncKeyState, TrackMouseEvent, TME_LEAVE, TRACKMOUSEEVENT, VIRTUAL_KEY, - VK_BACK, VK_CONTROL, VK_DELETE, VK_DOWN, VK_END, VK_ESCAPE, VK_F1, VK_F10, VK_F11, - VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_HOME, - VK_LBUTTON, VK_LEFT, VK_LWIN, VK_MBUTTON, VK_MENU, VK_NEXT, VK_PRIOR, VK_RBUTTON, - VK_RETURN, VK_RIGHT, VK_RWIN, VK_SHIFT, VK_UP, + VIRTUAL_KEY, VK_BACK, VK_CONTROL, VK_DELETE, VK_DOWN, VK_END, VK_ESCAPE, VK_F1, + VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, + VK_HOME, VK_LEFT, VK_LWIN, VK_MENU, VK_NEXT, VK_PRIOR, VK_RETURN, VK_RIGHT, + VK_RWIN, VK_SHIFT, VK_UP, }, WindowsAndMessaging::{ CreateWindowExW, DefWindowProcW, RegisterClassExW, CS_DBLCLKS, CS_HREDRAW, @@ -28,11 +24,10 @@ use windows::{ }; use crate::{ - get_module_handle, get_windowdata, hiword, log_windows_error, loword, KeyDownEvent, KeyUpEvent, - Keystroke, Modifiers, MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent, - MouseUpEvent, Pixels, PlatformInput, Point, ScrollDelta, ScrollWheelEvent, TouchPhase, - MOUSE_MOVE_BUTTONS, MOUSE_MOVE_LBUTTON, MOUSE_MOVE_MBUTTON, MOUSE_MOVE_RBUTTON, - MOUSE_MOVE_XBUTTON1, MOUSE_MOVE_XBUTTON2, + get_module_handle, get_windowdata, hiword, loword, KeyDownEvent, KeyUpEvent, Keystroke, + Modifiers, MouseButton, MouseDownEvent, MouseUpEvent, Pixels, PlatformInput, Point, + ScrollDelta, ScrollWheelEvent, TouchPhase, MOUSE_MOVE_BUTTONS, MOUSE_MOVE_LBUTTON, + MOUSE_MOVE_MBUTTON, MOUSE_MOVE_RBUTTON, MOUSE_MOVE_XBUTTON1, MOUSE_MOVE_XBUTTON2, }; pub struct WindowsWinodwDataWrapper(pub Rc); diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 6bb81bb62e3a1..868e393d192e4 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -7,7 +7,7 @@ use util::ResultExt; use windows::{ core::{implement, PCWSTR}, Win32::{ - Foundation::{HANDLE, HWND, LPARAM, LRESULT, POINTL, RECT, S_OK, WPARAM}, + Foundation::{HWND, LPARAM, LRESULT, POINTL, RECT, S_OK, WPARAM}, Graphics::Gdi::{ MonitorFromWindow, RedrawWindow, ValidateRect, HRGN, MONITOR_DEFAULTTONEAREST, RDW_ERASENOW, RDW_INVALIDATE, RDW_UPDATENOW, @@ -23,7 +23,7 @@ use windows::{ UI::{ Controls::{ TaskDialogIndirect, TASKDIALOGCONFIG, TASKDIALOG_BUTTON, TD_ERROR_ICON, - TD_INFORMATION_ICON, TD_WARNING_ICON, WM_MOUSELEAVE, + TD_INFORMATION_ICON, TD_WARNING_ICON, }, HiDpi::{GetDpiForMonitor, GetDpiForWindow, MDT_EFFECTIVE_DPI}, Input::{ @@ -31,7 +31,7 @@ use windows::{ ImmGetContext, ImmReleaseContext, ImmSetCompositionWindow, CFS_POINT, COMPOSITIONFORM, }, - KeyboardAndMouse::{SetActiveWindow, TrackMouseEvent, TME_LEAVE, TRACKMOUSEEVENT}, + KeyboardAndMouse::SetActiveWindow, }, Shell::{DragQueryFileW, HDROP}, WindowsAndMessaging::{ From 6eaa7f1dc12a0f0c58c6bba05950df7a20b02b29 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sun, 3 Mar 2024 17:49:12 +0800 Subject: [PATCH 22/39] update shortcuts --- Cargo.lock | 10 +++ crates/gpui/src/platform/windows/platform.rs | 76 +++++++++++++------- crates/gpui/src/platform/windows/window.rs | 3 +- 3 files changed, 61 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9983368be27b..6c57241f03864 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12279,6 +12279,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winresource" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e2aaaf8cfa92078c0c0375423d631f82f2f57979c2884fdd5f604a11e45329" +dependencies = [ + "toml 0.7.8", + "version_check", +] + [[package]] name = "winx" version = "0.36.3" diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index f548c606885c0..edd68196ac916 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -36,9 +36,9 @@ use windows::{ UI::{ HiDpi::{SetProcessDpiAwarenessContext, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE}, Input::KeyboardAndMouse::{ - GetDoubleClickTime, VIRTUAL_KEY, VK_BACK, VK_DELETE, VK_DOWN, VK_END, VK_ESCAPE, - VK_F1, VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, - VK_F9, VK_HOME, VK_LEFT, VK_NEXT, VK_PRIOR, VK_RETURN, VK_RIGHT, VK_UP, + GetDoubleClickTime, VkKeyScanW, VIRTUAL_KEY, VK_BACK, VK_DELETE, VK_DOWN, VK_END, + VK_ESCAPE, VK_F1, VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, + VK_F8, VK_F9, VK_HOME, VK_LEFT, VK_NEXT, VK_PRIOR, VK_RETURN, VK_RIGHT, VK_UP, }, Shell::{ FileOpenDialog, FileSaveDialog, IFileOpenDialog, IFileSaveDialog, IShellItem, @@ -47,17 +47,18 @@ use windows::{ }, WindowsAndMessaging::{ AppendMenuW, CreateAcceleratorTableW, CreateMenu, DefWindowProcW, DispatchMessageW, - GetMessageW, LoadImageW, PostQuitMessage, SetCursor, TranslateMessage, ACCEL, - ACCEL_VIRT_FLAGS, HCURSOR, HMENU, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_IBEAM, - IDC_NO, IDC_SIZENS, IDC_SIZEWE, IMAGE_CURSOR, LR_DEFAULTSIZE, LR_SHARED, MF_POPUP, - MF_SEPARATOR, MF_STRING, SW_SHOWDEFAULT, WM_DESTROY, + GetMessageW, LoadAcceleratorsW, LoadImageW, PostQuitMessage, SetCursor, + TranslateAcceleratorW, TranslateMessage, ACCEL, ACCEL_VIRT_FLAGS, HACCEL, HCURSOR, + HMENU, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_IBEAM, IDC_NO, IDC_SIZENS, IDC_SIZEWE, + IMAGE_CURSOR, LR_DEFAULTSIZE, LR_SHARED, MF_POPUP, MF_SEPARATOR, MF_STRING, + SW_SHOWDEFAULT, WM_COMMAND, WM_DESTROY, }, }, }, }; use crate::{ - encode_wide, log_windows_error, log_windows_error_with_message, + encode_wide, get_module_handle, log_windows_error, log_windows_error_with_message, loword, platform::cross_platform::CosmicTextSystem, set_windowdata, Keystroke, WindowsWindow, WindowsWindowBase, WindowsWinodwDataWrapper, ACCEL_FALT, ACCEL_FCONTROL, ACCEL_FSHIFT, ACCEL_FVIRTKEY, CF_UNICODETEXT, CLIPBOARD_METADATA, CLIPBOARD_TEXT_HASH, DISPATCH_WINDOW_CLASS, @@ -92,6 +93,7 @@ pub(crate) struct WindowsPlatform { menu_handle: RefCell>, text_hash_clipboard_type: u32, metadata_clipboard_type: u32, + shortcuts_table: RefCell>, } impl WindowsPlatform { @@ -128,6 +130,7 @@ impl WindowsPlatform { menu_handle: RefCell::new(None), text_hash_clipboard_type, metadata_clipboard_type, + shortcuts_table: RefCell::new(None), } } } @@ -171,6 +174,16 @@ impl WindowsPlatformInner { } self.windows_count.fetch_sub(1, Ordering::SeqCst); } + + fn do_action(&self, action_index: usize) { + if let Some(ref mut callback) = self.callbacks.borrow_mut().app_menu_action { + if let Some(action) = self.menu_actions.borrow().get(action_index - 1) { + println!("Action index: {}", action_index); + let action = action.boxed_clone(); + callback(&*action); + } + } + } } impl Platform for WindowsPlatform { @@ -190,9 +203,13 @@ impl Platform for WindowsPlatform { on_finish_launching(); unsafe { let mut msg = std::mem::zeroed(); + let dispatch_window_handle = self.inner.dispatch_window_handle; + let table = self.shortcuts_table.borrow_mut().take().unwrap(); while GetMessageW(&mut msg, HWND::default(), 0, 0).as_bool() { - TranslateMessage(&msg); - DispatchMessageW(&msg); + if TranslateAcceleratorW(dispatch_window_handle, table, &mut msg) == 0 { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } } } if let Some(ref mut func) = self.inner.callbacks.borrow_mut().quit { @@ -434,7 +451,11 @@ impl Platform for WindowsPlatform { ); } let _ = self.menu_handle.borrow_mut().insert(menu_bar_handle); - let _ = CreateAcceleratorTableW(&accelerator_vec).inspect_err(log_windows_error); + if let Ok(table) = + CreateAcceleratorTableW(&accelerator_vec).inspect_err(log_windows_error) + { + (*self.shortcuts_table.borrow_mut()) = Some(table); + } } (*self.inner.menu_actions.borrow_mut()) = actions_vec; } @@ -659,16 +680,18 @@ impl WindowsWindowBase for WindowsPlatformInner { self.close_one_window(); LRESULT(0) } - MENU_ACTIONS => { - if let Some(ref mut callback) = self.callbacks.borrow_mut().app_menu_action { - if let Some(action) = self.menu_actions.borrow().get(wparam.0) { - println!("Action index: {}", wparam.0); - let action = action.boxed_clone(); - callback(&*action); - } + WM_COMMAND => { + let action_index = loword!(wparam.0, u16) as usize; + if action_index != 0 { + println!("Get shorcut index: {}", action_index); + self.do_action(action_index); } LRESULT(0) } + MENU_ACTIONS => { + self.do_action(wparam.0); + LRESULT(0) + } _ => DefWindowProcW(handle, message, wparam, lparam), } } @@ -793,15 +816,14 @@ unsafe fn generate_menu( let keystroke = &keystrokes[0]; item_name.push('\t'); keystroke_to_menu_string(keystroke, &mut item_name); - let accel_table = keystroke_to_accel_table(keystroke, action_index as _); - accelerator_vec.push(accel_table); + let accel = keystroke_to_accel(keystroke, action_index as _); + accelerator_vec.push(accel); } else { // windows cant show multiple chortcuts on menu item for keystroke in keystrokes.iter() { keystroke_to_menu_string(keystroke, &mut item_name); - let accel_table = - keystroke_to_accel_table(keystroke, action_index as _); - accelerator_vec.push(accel_table); + let accel = keystroke_to_accel(keystroke, action_index as _); + accelerator_vec.push(accel); } } } @@ -834,7 +856,7 @@ fn keystroke_to_menu_string(keystroke: &Keystroke, menu_string: &mut String) { let _ = write!(menu_string, "{}", keystroke.key.to_uppercase()); } -fn keystroke_to_accel_table(keystroke: &Keystroke, action_index: u16) -> ACCEL { +fn keystroke_to_accel(keystroke: &Keystroke, action_index: u16) -> ACCEL { let mut table = ACCEL::default(); if keystroke.modifiers.control { table.fVirt |= ACCEL_VIRT_FLAGS(ACCEL_FCONTROL); @@ -847,7 +869,7 @@ fn keystroke_to_accel_table(keystroke: &Keystroke, action_index: u16) -> ACCEL { } table.fVirt |= ACCEL_VIRT_FLAGS(ACCEL_FVIRTKEY); table.key = keycode_to_vkey(&keystroke.key).unwrap_or(VK_DELETE).0; - table.cmd = action_index + 1; + table.cmd = action_index; table } @@ -885,8 +907,8 @@ fn keycode_to_vkey(keycode: &str) -> Option { return None; }; // TODO: is this correct? - key = Some(VIRTUAL_KEY(this_char as u16)); - // println!("Char {} to vk {:?}", this_char, key); + key = unsafe { Some(VIRTUAL_KEY(VkKeyScanW(this_char as _) as _)) }; + println!("Char {} to vk {:?}", this_char, key); } key diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 868e393d192e4..621d3a215dd36 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -366,10 +366,11 @@ impl WindowsWindowBase for WindowsWindowinner { WM_COMMAND => { let action_index = loword!(wparam.0, u16) as usize; if action_index != 0 { + println!("Get action: {}", action_index); let _ = PostMessageW( self.dispatch_window_handle, MENU_ACTIONS, - WPARAM(action_index - 1), + WPARAM(action_index), LPARAM::default(), ) .inspect_err(log_windows_error); From 71764331297ed118c391a50abd1c100a38fa2577 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sun, 3 Mar 2024 17:53:54 +0800 Subject: [PATCH 23/39] destroy accel --- crates/gpui/src/platform/windows/platform.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index edd68196ac916..9df5bfaa0b97b 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -46,12 +46,12 @@ use windows::{ FOS_ALLOWMULTISELECT, FOS_PICKFOLDERS, SIGDN_PARENTRELATIVEPARSING, }, WindowsAndMessaging::{ - AppendMenuW, CreateAcceleratorTableW, CreateMenu, DefWindowProcW, DispatchMessageW, - GetMessageW, LoadAcceleratorsW, LoadImageW, PostQuitMessage, SetCursor, - TranslateAcceleratorW, TranslateMessage, ACCEL, ACCEL_VIRT_FLAGS, HACCEL, HCURSOR, - HMENU, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_IBEAM, IDC_NO, IDC_SIZENS, IDC_SIZEWE, - IMAGE_CURSOR, LR_DEFAULTSIZE, LR_SHARED, MF_POPUP, MF_SEPARATOR, MF_STRING, - SW_SHOWDEFAULT, WM_COMMAND, WM_DESTROY, + AppendMenuW, CreateAcceleratorTableW, CreateMenu, DefWindowProcW, + DestroyAcceleratorTable, DispatchMessageW, GetMessageW, LoadAcceleratorsW, + LoadImageW, PostQuitMessage, SetCursor, TranslateAcceleratorW, TranslateMessage, + ACCEL, ACCEL_VIRT_FLAGS, HACCEL, HCURSOR, HMENU, IDC_ARROW, IDC_CROSS, IDC_HAND, + IDC_IBEAM, IDC_NO, IDC_SIZENS, IDC_SIZEWE, IMAGE_CURSOR, LR_DEFAULTSIZE, LR_SHARED, + MF_POPUP, MF_SEPARATOR, MF_STRING, SW_SHOWDEFAULT, WM_COMMAND, WM_DESTROY, }, }, }, @@ -211,6 +211,7 @@ impl Platform for WindowsPlatform { DispatchMessageW(&msg); } } + let _ = DestroyAcceleratorTable(table); } if let Some(ref mut func) = self.inner.callbacks.borrow_mut().quit { func(); From b86caf1e6213b2acd335486fc83e61167cf1462b Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sun, 3 Mar 2024 18:59:13 +0800 Subject: [PATCH 24/39] credential stuff --- crates/gpui/src/platform/windows/platform.rs | 95 ++++++++++++++++---- 1 file changed, 79 insertions(+), 16 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 9df5bfaa0b97b..4901d44d474f1 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -15,11 +15,15 @@ use async_task::Runnable; use futures::channel::oneshot; use time::UtcOffset; use windows::{ - core::PCWSTR, + core::{PCWSTR, PWSTR}, Wdk::System::SystemServices::RtlGetVersion, Win32::{ Foundation::{HANDLE, HWND, LPARAM, LRESULT, WPARAM}, Globalization::u_memcpy, + Security::Credentials::{ + CredDeleteW, CredReadDomainCredentialsW, CredWriteDomainCredentialsW, CREDENTIALW, + CREDENTIAL_TARGET_INFORMATIONW, CRED_PERSIST_SESSION, CRED_TYPE_DOMAIN_PASSWORD, + }, System::{ Com::{ CoCreateInstance, CreateBindCtx, IDataObject, CLSCTX_ALL, DVASPECT_CONTENT, @@ -632,27 +636,86 @@ impl Platform for WindowsPlatform { } } - // todo!(windows) - fn write_credentials( - &self, - _url: &str, - _usernamee: &str, - _passwordrd: &[u8], - ) -> Task> { - unimplemented!() + // todo("windows") + // not tested yet + fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task> { + let url = url.to_string(); + let username = username.to_string(); + let password = password.to_vec(); + self.background_executor().spawn(async move { + let mut url_wide = encode_wide(&url); + let mut usrname_wide = encode_wide(&username); + let target_info = CREDENTIAL_TARGET_INFORMATIONW { + TargetName: PWSTR::from_raw(url_wide.as_mut_ptr()), + DnsDomainName: PWSTR::from_raw(url_wide.as_mut_ptr()), + ..Default::default() + }; + let mut blob = password.to_vec(); + let cred = CREDENTIALW { + Type: CRED_TYPE_DOMAIN_PASSWORD, + TargetName: PWSTR::from_raw(url_wide.as_mut_ptr()), + CredentialBlobSize: blob.len() as _, + CredentialBlob: blob.as_mut_ptr(), + Persist: CRED_PERSIST_SESSION, + UserName: PWSTR::from_raw(usrname_wide.as_mut_ptr()), + ..Default::default() + }; + unsafe { + CredWriteDomainCredentialsW(&target_info as _, &cred as _, 0) + .inspect_err(log_windows_error)?; + } + Ok(()) + }) } - // todo!(windows) - fn read_credentials(&self, _url: &str) -> Task)>>> { - unimplemented!() + // todo("windows") + // not tested yet + fn read_credentials(&self, url: &str) -> Task)>>> { + let url = url.to_string(); + self.background_executor().spawn(async move { + let mut url_wide = encode_wide(&url); + let target_info = CREDENTIAL_TARGET_INFORMATIONW { + TargetName: PWSTR::from_raw(url_wide.as_mut_ptr()), + DnsDomainName: PWSTR::from_raw(url_wide.as_mut_ptr()), + ..Default::default() + }; + unsafe { + let mut count = std::mem::zeroed(); + let mut creds_ptr = std::mem::zeroed(); + CredReadDomainCredentialsW(&target_info as _, 0, &mut count, &mut creds_ptr) + .inspect_err(log_windows_error)?; + let creds: Vec<*mut CREDENTIALW> = + Vec::from_raw_parts(creds_ptr as _, count as _, count as _); + // get the first one for now + let cred = &*(creds[0]); + let username = String::from_utf16_lossy(cred.UserName.as_wide()); + let size = cred.CredentialBlobSize as usize; + let password = Vec::from_raw_parts(cred.CredentialBlob, size, size); + Ok(Some((username, password))) + } + }) } - // todo!(windows) - fn delete_credentials(&self, _url: &str) -> Task> { - unimplemented!() + // todo("windows") + // not tested yet + fn delete_credentials(&self, url: &str) -> Task> { + let url = url.to_string(); + + self.background_executor().spawn(async move { + let url_wide = encode_wide(&url); + unsafe { + CredDeleteW( + PCWSTR::from_raw(url_wide.as_ptr()), + CRED_TYPE_DOMAIN_PASSWORD, + 0, + ) + .inspect_err(log_windows_error)?; + } + Ok(()) + }) } - // todo!(windows) + // todo("windows") fn window_appearance(&self) -> crate::WindowAppearance { crate::WindowAppearance::Light } From 2259868e8a0c2b60d4b4fed98b43cad9479c31a8 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Sun, 3 Mar 2024 19:10:10 +0800 Subject: [PATCH 25/39] small fix --- crates/gpui/src/platform/windows/platform.rs | 41 +++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 4901d44d474f1..13ad95d0815d4 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -51,9 +51,9 @@ use windows::{ }, WindowsAndMessaging::{ AppendMenuW, CreateAcceleratorTableW, CreateMenu, DefWindowProcW, - DestroyAcceleratorTable, DispatchMessageW, GetMessageW, LoadAcceleratorsW, - LoadImageW, PostQuitMessage, SetCursor, TranslateAcceleratorW, TranslateMessage, - ACCEL, ACCEL_VIRT_FLAGS, HACCEL, HCURSOR, HMENU, IDC_ARROW, IDC_CROSS, IDC_HAND, + DestroyAcceleratorTable, DispatchMessageW, GetMessageW, LoadImageW, + PostQuitMessage, SetCursor, TranslateAcceleratorW, TranslateMessage, ACCEL, + ACCEL_VIRT_FLAGS, HACCEL, HCURSOR, HMENU, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_IBEAM, IDC_NO, IDC_SIZENS, IDC_SIZEWE, IMAGE_CURSOR, LR_DEFAULTSIZE, LR_SHARED, MF_POPUP, MF_SEPARATOR, MF_STRING, SW_SHOWDEFAULT, WM_COMMAND, WM_DESTROY, }, @@ -62,7 +62,7 @@ use windows::{ }; use crate::{ - encode_wide, get_module_handle, log_windows_error, log_windows_error_with_message, loword, + encode_wide, log_windows_error, log_windows_error_with_message, loword, platform::cross_platform::CosmicTextSystem, set_windowdata, Keystroke, WindowsWindow, WindowsWindowBase, WindowsWinodwDataWrapper, ACCEL_FALT, ACCEL_FCONTROL, ACCEL_FSHIFT, ACCEL_FVIRTKEY, CF_UNICODETEXT, CLIPBOARD_METADATA, CLIPBOARD_TEXT_HASH, DISPATCH_WINDOW_CLASS, @@ -182,7 +182,6 @@ impl WindowsPlatformInner { fn do_action(&self, action_index: usize) { if let Some(ref mut callback) = self.callbacks.borrow_mut().app_menu_action { if let Some(action) = self.menu_actions.borrow().get(action_index - 1) { - println!("Action index: {}", action_index); let action = action.boxed_clone(); callback(&*action); } @@ -228,19 +227,19 @@ impl Platform for WindowsPlatform { } } - //todo!(windows) + // todo("windows") fn restart(&self) {} - //todo!(windows) + // todo("windows") fn activate(&self, _ignoring_other_apps: bool) {} - //todo!(windows) + // todo("windows") fn hide(&self) {} - //todo!(windows) + // todo("windows") fn hide_other_apps(&self) {} - //todo!(windows) + // todo("windows") fn unhide_other_apps(&self) {} fn displays(&self) -> Vec> { @@ -251,7 +250,7 @@ impl Platform for WindowsPlatform { Some(Rc::new(WindowsDisplay::new(id))) } - //todo!(windows) + // todo("windows") fn active_window(&self) -> Option { None } @@ -275,7 +274,6 @@ impl Platform for WindowsPlatform { fn open_url(&self, url: &str) { let url_string = url.to_string(); - println!("Open: {}", url_string); self.background_executor() .spawn(async move { open_target(url_string); @@ -420,11 +418,14 @@ impl Platform for WindowsPlatform { patch: info.dwBuildNumber as _, }) } else { - Err(anyhow::anyhow!("{}", std::io::Error::last_os_error())) + Err(anyhow::anyhow!( + "unable to get Windows version: {}", + std::io::Error::last_os_error() + )) } } - // todo!(windows) + // todo("windows") fn app_version(&self) -> Result { Ok(SemanticVersion { major: 1, @@ -433,12 +434,11 @@ impl Platform for WindowsPlatform { }) } - // todo!(windows) + // todo("windows") fn app_path(&self) -> Result { unimplemented!() } - //todo!(windows) fn set_menus(&self, menus: Vec, keymap: &Keymap) { let mut actions_vec = Vec::new(); let mut accelerator_vec = Vec::new(); @@ -553,7 +553,7 @@ impl Platform for WindowsPlatform { } } - //todo!(windows) + // todo("windows") fn should_auto_hide_scrollbars(&self) -> bool { false } @@ -747,7 +747,6 @@ impl WindowsWindowBase for WindowsPlatformInner { WM_COMMAND => { let action_index = loword!(wparam.0, u16) as usize; if action_index != 0 { - println!("Get shorcut index: {}", action_index); self.do_action(action_index); } LRESULT(0) @@ -772,11 +771,10 @@ fn platform_init() -> anyhow::Result<()> { fn open_target(target: String) { unsafe { - let operation = encode_wide("open"); let file_path_vec = encode_wide(&target); let ret = ShellExecuteW( None, - PCWSTR::from_raw(operation.as_ptr()), + windows::core::w!("open"), PCWSTR::from_raw(file_path_vec.as_ptr()), None, None, @@ -870,7 +868,6 @@ unsafe fn generate_menu( .bindings_for_action(action.as_ref()) .next() .map(|binding| binding.keystrokes()); - // println!("Shortcut: {:#?}", keystrokes); let mut item_name = name.to_string(); let action_index = actions_count.fetch_add(1, std::sync::atomic::Ordering::SeqCst); @@ -970,9 +967,7 @@ fn keycode_to_vkey(keycode: &str) -> Option { let Ok(this_char) = char::from_str(keycode) else { return None; }; - // TODO: is this correct? key = unsafe { Some(VIRTUAL_KEY(VkKeyScanW(this_char as _) as _)) }; - println!("Char {} to vk {:?}", this_char, key); } key From 5213f4ad05f87d04df8b79b41dd0c59b7cf9bc9f Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 4 Mar 2024 03:22:12 +0800 Subject: [PATCH 26/39] small fix --- crates/gpui/src/platform/windows/events.rs | 6 +- crates/gpui/src/platform/windows/platform.rs | 165 ++++++++++--------- crates/gpui/src/platform/windows/utils.rs | 1 + crates/gpui/src/platform/windows/window.rs | 103 ++++++++---- crates/terminal/src/terminal.rs | 1 - 5 files changed, 164 insertions(+), 112 deletions(-) diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index df9112fd02ee3..8d6948bcc016d 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -189,13 +189,9 @@ pub fn parse_keyboard_input( return None; } let src = [wparam.0 as u16]; - let Ok(first_char) = char::decode_utf16(src) - .map(|r| r.map_err(|e| e.unpaired_surrogate())) - .collect::>()[0] - else { + let Ok(first_char) = char::decode_utf16(src).collect::>()[0] else { return None; }; - println!("{} => {:?}", wparam.0, first_char); if first_char.is_control() { // ctrl is handled by zed return None; diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 13ad95d0815d4..5e20c4b6f9fbd 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -1,6 +1,7 @@ use std::{ cell::RefCell, fmt::Write, + os::windows::ffi::OsStrExt, path::{Path, PathBuf}, rc::Rc, str::FromStr, @@ -13,6 +14,7 @@ use std::{ use async_task::Runnable; use futures::channel::oneshot; +use itertools::Itertools; use time::UtcOffset; use windows::{ core::{PCWSTR, PWSTR}, @@ -55,14 +57,14 @@ use windows::{ PostQuitMessage, SetCursor, TranslateAcceleratorW, TranslateMessage, ACCEL, ACCEL_VIRT_FLAGS, HACCEL, HCURSOR, HMENU, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_IBEAM, IDC_NO, IDC_SIZENS, IDC_SIZEWE, IMAGE_CURSOR, LR_DEFAULTSIZE, LR_SHARED, - MF_POPUP, MF_SEPARATOR, MF_STRING, SW_SHOWDEFAULT, WM_COMMAND, WM_DESTROY, + MF_POPUP, MF_SEPARATOR, MF_STRING, SW_SHOWDEFAULT, WM_DESTROY, }, }, }, }; use crate::{ - encode_wide, log_windows_error, log_windows_error_with_message, loword, + encode_wide, log_windows_error, log_windows_error_with_message, platform::cross_platform::CosmicTextSystem, set_windowdata, Keystroke, WindowsWindow, WindowsWindowBase, WindowsWinodwDataWrapper, ACCEL_FALT, ACCEL_FCONTROL, ACCEL_FSHIFT, ACCEL_FVIRTKEY, CF_UNICODETEXT, CLIPBOARD_METADATA, CLIPBOARD_TEXT_HASH, DISPATCH_WINDOW_CLASS, @@ -293,39 +295,45 @@ impl Platform for WindowsPlatform { self.foreground_executor() .spawn(async move { unsafe { - let dialog = show_openfile_dialog(options).expect("error show openfile dialog"); - if let Ok(_) = dialog.Show(None) { - let Ok(items) = dialog.GetResults() else { - log_windows_error_with_message!("Error get result from dialog"); - let _ = tx.send(None); - return; + let Ok(dialog) = show_openfile_dialog(options) else { + log_windows_error_with_message!("error show openfile dialog"); + let _ = tx.send(None); + return; + }; + let Ok(_) = dialog.Show(None) else { + let _ = tx.send(None); // user cancel + return; + }; + let Ok(items) = dialog.GetResults() else { + log_windows_error_with_message!("Error get result from dialog"); + let _ = tx.send(None); + return; + }; + let Ok(count) = items.GetCount() else { + log_windows_error_with_message!("Error get results count from dialog"); + let _ = tx.send(None); + return; + }; + let mut path_vec = Vec::new(); + for index in 0..count { + let Ok(item) = items.GetItemAt(index) else { + log_windows_error_with_message!("Error get item dialog"); + continue; }; - let Ok(count) = items.GetCount() else { - log_windows_error_with_message!("Error get results count from dialog"); - let _ = tx.send(None); - return; + let Ok(item_string) = item.GetDisplayName(SIGDN_PARENTRELATIVEPARSING) + else { + log_windows_error_with_message!("Error parsing item name"); + continue; }; - let mut path_vec = Vec::new(); - for index in 0..count { - let Ok(item) = items.GetItemAt(index) else { - log_windows_error_with_message!("Error get item dialog"); - continue; - }; - let Ok(item_string) = item.GetDisplayName(SIGDN_PARENTRELATIVEPARSING) - else { - log_windows_error_with_message!("Error parsing item name"); - continue; - }; - let Ok(path_string) = item_string.to_string() else { - log_windows_error_with_message!( - "Error parsing item name from utf16 to string" - ); - continue; - }; - path_vec.push(PathBuf::from(path_string)); - } - let _ = tx.send(Some(path_vec)); + let Ok(path_string) = item_string.to_string() else { + log_windows_error_with_message!( + "Error parsing item name from utf16 to string" + ); + continue; + }; + path_vec.push(PathBuf::from(path_string)); } + let _ = tx.send(Some(path_vec)); } }) .detach(); @@ -339,15 +347,18 @@ impl Platform for WindowsPlatform { self.foreground_executor() .spawn(async move { unsafe { - let dialog = - show_savefile_dialog(directory).expect("error open savefile dialog"); - if let Ok(_) = dialog.Show(None) { - if let Ok(shell_item) = dialog.GetResult() { - if let Ok(file) = shell_item.GetDisplayName(SIGDN_PARENTRELATIVEPARSING) - { - let _ = tx.send(Some(PathBuf::from(file.to_string().unwrap()))); - return; - } + let Ok(dialog) = show_savefile_dialog(directory) else { + let _ = tx.send(None); + return; + }; + let Ok(_) = dialog.Show(None) else { + let _ = tx.send(None); // user cancel + return; + }; + if let Ok(shell_item) = dialog.GetResult() { + if let Ok(file) = shell_item.GetDisplayName(SIGDN_PARENTRELATIVEPARSING) { + let _ = tx.send(Some(PathBuf::from(file.to_string().unwrap()))); + return; } } let _ = tx.send(None); @@ -744,13 +755,6 @@ impl WindowsWindowBase for WindowsPlatformInner { self.close_one_window(); LRESULT(0) } - WM_COMMAND => { - let action_index = loword!(wparam.0, u16) as usize; - if action_index != 0 { - self.do_action(action_index); - } - LRESULT(0) - } MENU_ACTIONS => { self.do_action(wparam.0); LRESULT(0) @@ -804,23 +808,28 @@ fn show_openfile_dialog(options: PathPromptOptions) -> anyhow::Result anyhow::Result { - unsafe { - let dialog: IFileSaveDialog = - CoCreateInstance(&FileSaveDialog, None, CLSCTX_ALL).inspect_err(log_windows_error)?; - let dir_str = directory.to_str().unwrap(); - println!("Target dir: {}", dir_str); - let dir_vec = encode_wide(dir_str); - let bind_context = CreateBindCtx(0).inspect_err(log_windows_error)?; - let dir_shell_item: IShellItem = - SHCreateItemFromParsingName(PCWSTR::from_raw(dir_vec.as_ptr()), &bind_context) - .inspect_err(log_windows_error)?; +unsafe fn show_savefile_dialog(directory: PathBuf) -> anyhow::Result { + let dialog: IFileSaveDialog = + CoCreateInstance(&FileSaveDialog, None, CLSCTX_ALL).inspect_err(log_windows_error)?; + let bind_context = CreateBindCtx(0).inspect_err(log_windows_error)?; + let Ok(full_path) = directory.canonicalize() else { + return Ok(dialog); + }; + let dir_str = full_path.into_os_string(); + if dir_str.is_empty() { + return Ok(dialog); + } + let dir_vec = dir_str.encode_wide().collect_vec(); + let ret = SHCreateItemFromParsingName(PCWSTR::from_raw(dir_vec.as_ptr()), &bind_context) + .inspect_err(log_windows_error); + if ret.is_ok() { + let dir_shell_item: IShellItem = ret.unwrap(); let _ = dialog .SetFolder(&dir_shell_item) .inspect_err(log_windows_error); - - Ok(dialog) } + + Ok(dialog) } // todo("windows") @@ -873,20 +882,24 @@ unsafe fn generate_menu( let action_index = actions_count.fetch_add(1, std::sync::atomic::Ordering::SeqCst); if let Some(keystrokes) = keystrokes { // TODO: deal with os action - if keystrokes.len() == 1 { - let keystroke = &keystrokes[0]; - item_name.push('\t'); - keystroke_to_menu_string(keystroke, &mut item_name); - let accel = keystroke_to_accel(keystroke, action_index as _); + let keystroke = &keystrokes[0]; + item_name.push('\t'); + keystroke_to_menu_string(keystroke, &mut item_name); + if let Some(accel) = register_shortcuts(keystroke, action_index) { accelerator_vec.push(accel); - } else { - // windows cant show multiple chortcuts on menu item - for keystroke in keystrokes.iter() { - keystroke_to_menu_string(keystroke, &mut item_name); - let accel = keystroke_to_accel(keystroke, action_index as _); - accelerator_vec.push(accel); - } } + // the below codes can work, but disable them for now, + // sice we don't have a default keymap for windows + // if keystrokes.len() > 1 { + // // windows can not show multiple chortcuts on menu item + // for keystroke in keystrokes.iter() { + // if let Some(accel) = + // register_shortcuts(hashmap, keystroke, action_index) + // { + // accelerator_vec.push(accel); + // } + // } + // } } let name_vec = encode_wide(&item_name); AppendMenuW( @@ -917,7 +930,7 @@ fn keystroke_to_menu_string(keystroke: &Keystroke, menu_string: &mut String) { let _ = write!(menu_string, "{}", keystroke.key.to_uppercase()); } -fn keystroke_to_accel(keystroke: &Keystroke, action_index: u16) -> ACCEL { +fn register_shortcuts(keystroke: &Keystroke, action_index: usize) -> Option { let mut table = ACCEL::default(); if keystroke.modifiers.control { table.fVirt |= ACCEL_VIRT_FLAGS(ACCEL_FCONTROL); @@ -930,9 +943,9 @@ fn keystroke_to_accel(keystroke: &Keystroke, action_index: u16) -> ACCEL { } table.fVirt |= ACCEL_VIRT_FLAGS(ACCEL_FVIRTKEY); table.key = keycode_to_vkey(&keystroke.key).unwrap_or(VK_DELETE).0; - table.cmd = action_index; + table.cmd = action_index as _; - table + Some(table) } fn keycode_to_vkey(keycode: &str) -> Option { diff --git a/crates/gpui/src/platform/windows/utils.rs b/crates/gpui/src/platform/windows/utils.rs index 524685430bb3e..49b025b7360fd 100644 --- a/crates/gpui/src/platform/windows/utils.rs +++ b/crates/gpui/src/platform/windows/utils.rs @@ -88,6 +88,7 @@ pub unsafe fn get_windowdata(handle: HWND) -> isize { GetWindowLongPtrW(handle, GWL_USERDATA) } +#[track_caller] pub fn log_windows_error(_e: &windows::core::Error) { log_windows_error_with_message!(None); } diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 621d3a215dd36..fb4dcdbfb725c 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -3,7 +3,6 @@ use std::{cell::RefCell, mem, path::PathBuf, rc::Rc, str::FromStr, sync::Arc}; use futures::channel::oneshot; use raw_window_handle as rwh; use smallvec::SmallVec; -use util::ResultExt; use windows::{ core::{implement, PCWSTR}, Win32::{ @@ -23,7 +22,7 @@ use windows::{ UI::{ Controls::{ TaskDialogIndirect, TASKDIALOGCONFIG, TASKDIALOG_BUTTON, TD_ERROR_ICON, - TD_INFORMATION_ICON, TD_WARNING_ICON, + TD_INFORMATION_ICON, TD_WARNING_ICON, WM_MOUSELEAVE, }, HiDpi::{GetDpiForMonitor, GetDpiForWindow, MDT_EFFECTIVE_DPI}, Input::{ @@ -31,19 +30,19 @@ use windows::{ ImmGetContext, ImmReleaseContext, ImmSetCompositionWindow, CFS_POINT, COMPOSITIONFORM, }, - KeyboardAndMouse::SetActiveWindow, + KeyboardAndMouse::{SetActiveWindow, TrackMouseEvent, TME_LEAVE, TRACKMOUSEEVENT}, }, Shell::{DragQueryFileW, HDROP}, WindowsAndMessaging::{ - DefWindowProcW, GetClientRect, GetCursorPos, KillTimer, PostMessageW, - PostQuitMessage, SetTimer, SetWindowTextW, ShowWindow, CW_USEDEFAULT, - GWLP_HINSTANCE, HMENU, SIZE_MINIMIZED, SW_MINIMIZE, SW_SHOW, TIMERPROC, WA_ACTIVE, - WA_CLICKACTIVE, WA_INACTIVE, WINDOW_EX_STYLE, WINDOW_STYLE, WM_ACTIVATE, WM_CHAR, - WM_COMMAND, WM_DESTROY, WM_IME_STARTCOMPOSITION, WM_KEYDOWN, WM_KEYUP, - WM_LBUTTONDBLCLK, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, - WM_MBUTTONUP, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_PAINT, - WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SIZE, WM_TIMER, - WM_XBUTTONDBLCLK, WM_XBUTTONDOWN, WM_XBUTTONUP, WS_MAXIMIZE, WS_POPUP, WS_VISIBLE, + DefWindowProcW, GetClientRect, GetCursorPos, KillTimer, PostMessageW, SetTimer, + SetWindowTextW, ShowWindow, CW_USEDEFAULT, GWLP_HINSTANCE, HMENU, SIZE_MINIMIZED, + SW_MINIMIZE, SW_SHOW, TIMERPROC, WA_ACTIVE, WA_CLICKACTIVE, WA_INACTIVE, + WINDOW_EX_STYLE, WINDOW_STYLE, WM_ACTIVATE, WM_CHAR, WM_COMMAND, WM_DESTROY, + WM_IME_STARTCOMPOSITION, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDBLCLK, WM_LBUTTONDOWN, + WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEHWHEEL, + WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_PAINT, WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, + WM_RBUTTONUP, WM_SIZE, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TIMER, WM_XBUTTONDBLCLK, + WM_XBUTTONDOWN, WM_XBUTTONUP, WS_MAXIMIZE, WS_POPUP, WS_VISIBLE, }, }, }, @@ -148,7 +147,6 @@ impl WindowsWindow { height: window_handle.size().height as _, depth: 1, }; - println!("Window size: {:#?}", gpu_extent); let renderer = BladeRenderer::new(gpu, gpu_extent); let inner = WindowsWindowinner::new( dispatch_window_handle, @@ -304,7 +302,6 @@ impl WindowsWindowinner { height, depth: 1, }; - println!("Resize with: {:#?}", gpu_size); let mut render = self.renderer.borrow_mut(); if render.viewport_size() != gpu_size { render.update_drawable_size(crate::size(gpu_size.width as _, gpu_size.height as _)); @@ -360,13 +357,11 @@ impl WindowsWindowBase for WindowsWindowinner { func(); } let _ = KillTimer(handle, WINDOW_REFRESH_TIMER); - PostQuitMessage(0); LRESULT(0) } WM_COMMAND => { let action_index = loword!(wparam.0, u16) as usize; if action_index != 0 { - println!("Get action: {}", action_index); let _ = PostMessageW( self.dispatch_window_handle, MENU_ACTIONS, @@ -379,24 +374,63 @@ impl WindowsWindowBase for WindowsWindowinner { } WM_ACTIVATE => { if loword!(wparam.0, u16) as u32 & (WA_ACTIVE | WA_CLICKACTIVE) > 0 { + let mut config = TRACKMOUSEEVENT { + cbSize: std::mem::size_of::() as _, + dwFlags: TME_LEAVE, + hwndTrack: handle, + dwHoverTime: 0, + }; + let _ = TrackMouseEvent(&mut config).inspect_err(log_windows_error); self.set_focused(true); } else if loword!(wparam.0, u16) as u32 & WA_INACTIVE > 0 { self.set_focused(false); } LRESULT(0) } + WM_SYSKEYDOWN | WM_SYSKEYUP => { + // alt key is pressed + let old_state = self.modifiers.borrow().alt; + let mut update = false; + if lparam.0 & (0x1 << 29) > 0 { + if message == WM_SYSKEYDOWN { + if !old_state { + self.modifiers.borrow_mut().alt = true; + update = true; + } + } else { + if old_state { + self.modifiers.borrow_mut().alt = false; + update = true; + } + } + } + if update { + let input = PlatformInput::ModifiersChanged(crate::ModifiersChangedEvent { + modifiers: self.modifiers.borrow().clone(), + }); + self.handle_input(input); + } + // let Windows to hanle the left things, so we still have the system-wide + // Alt+Tab, Alt+F4 ... working + DefWindowProcW(handle, message, wparam, lparam) + } WM_KEYDOWN | WM_KEYUP => { - let mut modifiers = self.modifiers.borrow().clone(); + let mut old_state = self.modifiers.borrow_mut(); + let mut modifiers = old_state.clone(); + let mut update = false; if let Some(key) = parse_system_key(message, wparam, lparam, &mut modifiers) { self.handle_input(key); - let mut old_state = self.modifiers.borrow_mut(); - if modifiers != *old_state { - let input = PlatformInput::ModifiersChanged(crate::ModifiersChangedEvent { - modifiers: modifiers.clone(), - }); - self.handle_input(input); - (*old_state) = modifiers; - } + update = true; + } + if modifiers != *old_state { + let input = PlatformInput::ModifiersChanged(crate::ModifiersChangedEvent { + modifiers: modifiers.clone(), + }); + self.handle_input(input); + update = true; + (*old_state) = modifiers; + } + if update { self.update_now(); } LRESULT(0) @@ -445,6 +479,15 @@ impl WindowsWindowBase for WindowsWindowinner { self.update_now(); LRESULT(0) } + WM_MOUSELEAVE => { + let input = PlatformInput::MouseExited(crate::MouseExitEvent { + position: Point::default(), + pressed_button: None, + modifiers: self.modifiers.borrow().clone(), + }); + self.handle_input(input); + LRESULT(0) + } WM_SIZE => { if wparam.0 as u32 == SIZE_MINIMIZED { return DefWindowProcW(handle, message, wparam, lparam); @@ -471,10 +514,6 @@ impl WindowsWindowBase for WindowsWindowinner { config.ptCurrentPos.y = cursor.y; ImmSetCompositionWindow(ctx, &config as _); ImmReleaseContext(handle, ctx); - println!( - "Set composition pos: ({}, {})", - config.ptCurrentPos.x, config.ptCurrentPos.y - ); LRESULT(0) } _ => DefWindowProcW(handle, message, wparam, lparam), @@ -854,7 +893,11 @@ impl RawWindow { pub fn size(&self) -> Size { let mut rect: RECT = unsafe { mem::zeroed() }; - unsafe { GetClientRect(self.hwnd(), &mut rect).log_err() }; + unsafe { + GetClientRect(self.hwnd(), &mut rect) + .inspect_err(log_windows_error) + .expect("unable to get window size") + }; Size { width: (rect.right - rect.left) as i32, height: (rect.bottom - rect.top) as i32, diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 56dc0103ecad0..45d9ef0234d1f 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -674,7 +674,6 @@ impl Terminal { if pid < 0 { pid = self.shell_pid as i32; } - println!("Updated PID: {}", pid); if let Some(process_info) = LocalProcessInfo::with_root_pid(pid as u32) { let res = self From 646009900f01bedc6016283d29ca86a21f4734b6 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 4 Mar 2024 14:11:30 +0800 Subject: [PATCH 27/39] revoke terminal change --- Cargo.lock | 5 +++-- crates/terminal/Cargo.toml | 3 +-- crates/terminal/src/terminal.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c57241f03864..689b11b550e3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,8 +113,9 @@ dependencies = [ [[package]] name = "alacritty_terminal" -version = "0.22.1-dev" -source = "git+https://github.com/JunkuiZhang/alacritty?rev=5f5028be3b55092a19dc0a295e0007c37c30db1c#5f5028be3b55092a19dc0a295e0007c37c30db1c" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ceabf6fc76511f616ca216b51398a2511f19ba9f71bcbd977999edff1b0d1" dependencies = [ "base64 0.21.4", "bitflags 2.4.2", diff --git a/crates/terminal/Cargo.toml b/crates/terminal/Cargo.toml index cf81d0c57119f..884b754aacbf6 100644 --- a/crates/terminal/Cargo.toml +++ b/crates/terminal/Cargo.toml @@ -11,8 +11,7 @@ doctest = false [dependencies] -# alacritty_terminal = "0.22.0" -alacritty_terminal = { git = "https://github.com/JunkuiZhang/alacritty", rev = "5f5028be3b55092a19dc0a295e0007c37c30db1c" } +alacritty_terminal = "0.22.0" anyhow.workspace = true collections.workspace = true dirs = "4.0.0" diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 45d9ef0234d1f..c2eddbc41c5ee 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -42,8 +42,8 @@ use task::TaskId; use terminal_settings::{AlternateScroll, Shell, TerminalBlink, TerminalSettings}; use theme::{ActiveTheme, Theme}; use util::truncate_and_trailoff; -#[cfg(windows)] -use windows_sys::Win32::{Foundation::HANDLE, System::Threading::GetProcessId}; +// #[cfg(windows)] +// use windows_sys::Win32::{Foundation::HANDLE, System::Threading::GetProcessId}; use std::{ cmp::{self, min}, @@ -403,7 +403,7 @@ impl TerminalBuilder { let (fd, shell_pid) = (pty.file().as_raw_fd(), pty.child().id()); #[cfg(windows)] - let (fd, shell_pid) = (pty.fd(), pty.pid()); + let (fd, shell_pid) = (-1, 0); //And connect them together let event_loop = EventLoop::new( From f03226a07fce2b8678e931d22b5da2f5d78ce445 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 4 Mar 2024 14:46:20 +0800 Subject: [PATCH 28/39] fix error --- Cargo.lock | 343 ++++-------------------------------- crates/gpui/src/platform.rs | 5 +- 2 files changed, 34 insertions(+), 314 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 689b11b550e3a..3b9b04401fca8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,18 +40,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if 1.0.0", - "cipher 0.4.4", - "cpufeatures", - "zeroize", -] - [[package]] name = "ahash" version = "0.7.6" @@ -324,7 +312,7 @@ dependencies = [ "serde", "serde_repr", "url", - "zbus 3.15.1", + "zbus", ] [[package]] @@ -396,18 +384,6 @@ dependencies = [ "futures-core", ] -[[package]] -name = "async-broadcast" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258b52a1aa741b9f09783b2d86cf0aeeb617bbf847f6933340a39644227acbdb" -dependencies = [ - "event-listener 5.1.0", - "event-listener-strategy 0.5.0", - "futures-core", - "pin-project-lite", -] - [[package]] name = "async-channel" version = "1.9.0" @@ -631,24 +607,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "async-process" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451e3cf68011bd56771c79db04a9e333095ab6349f7e47592b788e9b98720cc8" -dependencies = [ - "async-channel 2.2.0", - "async-io 2.3.1", - "async-lock 3.3.0", - "async-signal", - "blocking", - "cfg-if 1.0.0", - "event-listener 5.1.0", - "futures-lite 2.2.0", - "rustix 0.38.30", - "windows-sys 0.52.0", -] - [[package]] name = "async-recursion" version = "0.3.2" @@ -671,24 +629,6 @@ dependencies = [ "syn 2.0.48", ] -[[package]] -name = "async-signal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" -dependencies = [ - "async-io 2.3.1", - "async-lock 2.8.0", - "atomic-waker", - "cfg-if 1.0.0", - "futures-core", - "futures-io", - "rustix 0.38.30", - "signal-hook-registry", - "slab", - "windows-sys 0.48.0", -] - [[package]] name = "async-std" version = "1.12.0" @@ -699,7 +639,7 @@ dependencies = [ "async-global-executor", "async-io 1.13.0", "async-lock 2.8.0", - "async-process 1.7.0", + "async-process", "crossbeam-utils", "futures-channel", "futures-core", @@ -1512,15 +1452,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - [[package]] name = "blocking" version = "1.5.1" @@ -1829,15 +1760,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher 0.4.4", -] - [[package]] name = "cbindgen" version = "0.26.0" @@ -1945,17 +1867,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - [[package]] name = "clang-sys" version = "1.6.1" @@ -2865,7 +2776,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core 0.6.4", "typenum", ] @@ -3335,12 +3245,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "endi" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" - [[package]] name = "enumflags2" version = "0.7.9" @@ -4347,7 +4251,6 @@ dependencies = [ "metal", "num_cpus", "objc", - "oo7", "open", "parking", "parking_lot 0.11.2", @@ -4840,16 +4743,6 @@ dependencies = [ "libc", ] -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "block-padding", - "generic-array", -] - [[package]] name = "install_cli" version = "0.1.0" @@ -6056,7 +5949,6 @@ dependencies = [ "bitflags 2.4.2", "cfg-if 1.0.0", "libc", - "memoffset 0.9.0", ] [[package]] @@ -6154,20 +6046,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" -dependencies = [ - "num-bigint 0.4.4", - "num-complex 0.4.4", - "num-integer", - "num-iter", - "num-rational 0.4.1", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.2.6" @@ -6220,7 +6098,6 @@ dependencies = [ "num-iter", "num-traits", "rand 0.8.5", - "serde", "smallvec", "zeroize", ] @@ -6299,18 +6176,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint 0.4.4", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.16" @@ -6427,35 +6292,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "oo7" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37558cac1af63a81fd2ff7f3469c02a4da06b163c5671791553b8dac10f07c82" -dependencies = [ - "aes", - "async-fs 2.1.1", - "async-io 2.3.1", - "async-lock 3.3.0", - "blocking", - "cbc", - "cipher 0.4.4", - "digest 0.10.7", - "futures-lite 2.2.0", - "futures-util", - "hkdf", - "hmac 0.12.1", - "num 0.4.1", - "num-bigint-dig 0.8.4", - "pbkdf2 0.12.2", - "rand 0.8.5", - "serde", - "sha2 0.10.7", - "zbus 4.0.1", - "zeroize", - "zvariant 4.0.2", -] - [[package]] name = "opaque-debug" version = "0.3.0" @@ -6713,7 +6549,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7037e5e93e0172a5a96874380bf73bc6ecef022e26fa25f2be26864d6b3ba95d" dependencies = [ "lazy_static", - "num 0.2.1", + "num", "regex", ] @@ -6767,16 +6603,6 @@ dependencies = [ "crypto-mac", ] -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest 0.10.7", - "hmac 0.12.1", -] - [[package]] name = "peeking_take_while" version = "0.1.2" @@ -7061,15 +6887,6 @@ dependencies = [ "toml_edit 0.19.15", ] -[[package]] -name = "proc-macro-crate" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" -dependencies = [ - "toml_edit 0.21.1", -] - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -8253,7 +8070,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecbd2eb639fd7cab5804a0837fe373cc2172d15437e804c054a9fb885cb923b0" dependencies = [ - "cipher 0.3.0", + "cipher", ] [[package]] @@ -8326,7 +8143,7 @@ dependencies = [ "base64ct", "hmac 0.11.0", "password-hash", - "pbkdf2 0.8.0", + "pbkdf2", "salsa20", "sha2 0.9.9", ] @@ -8928,7 +8745,7 @@ dependencies = [ "async-io 1.13.0", "async-lock 2.8.0", "async-net 1.7.0", - "async-process 1.7.0", + "async-process", "blocking", "futures-lite 1.13.0", ] @@ -10090,30 +9907,6 @@ name = "toml_edit" version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.0.0", - "toml_datetime", - "winnow 0.5.15", -] - -[[package]] -name = "toml_edit" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" -dependencies = [ - "indexmap 2.0.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.5.15", -] - -[[package]] -name = "toml_edit" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ "indexmap 2.0.0", "serde", @@ -12001,18 +11794,38 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538" +dependencies = [ + "windows-core 0.53.0", + "windows-targets 0.52.4", +] + [[package]] name = "windows" version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" dependencies = [ - "windows-core", + "windows-core 0.54.0", "windows-implement", "windows-interface", "windows-targets 0.52.4", ] +[[package]] +name = "windows-core" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" +dependencies = [ + "windows-result", + "windows-targets 0.52.4", +] + [[package]] name = "windows-core" version = "0.54.0" @@ -12589,7 +12402,7 @@ dependencies = [ "async-fs 1.6.0", "async-io 1.13.0", "async-lock 2.8.0", - "async-process 1.7.0", + "async-process", "async-recursion 1.0.5", "async-task", "async-trait", @@ -12614,48 +12427,9 @@ dependencies = [ "uds_windows", "winapi 0.3.9", "xdg-home", - "zbus_macros 3.15.1", - "zbus_names 2.6.1", - "zvariant 3.15.1", -] - -[[package]] -name = "zbus" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8e3d6ae3342792a6cc2340e4394334c7402f3d793b390d2c5494a4032b3030" -dependencies = [ - "async-broadcast 0.7.0", - "async-executor", - "async-fs 2.1.1", - "async-io 2.3.1", - "async-lock 3.3.0", - "async-process 2.1.0", - "async-recursion 1.0.5", - "async-task", - "async-trait", - "blocking", - "derivative", - "enumflags2", - "event-listener 5.1.0", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "nix 0.27.1", - "ordered-stream", - "rand 0.8.5", - "serde", - "serde_repr", - "sha1", - "static_assertions", - "tracing", - "uds_windows", - "windows-sys 0.52.0", - "xdg-home", - "zbus_macros 4.0.1", - "zbus_names 3.0.0", - "zvariant 4.0.2", + "zbus_macros", + "zbus_names", + "zvariant", ] [[package]] @@ -12672,20 +12446,6 @@ dependencies = [ "zvariant_utils", ] -[[package]] -name = "zbus_macros" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a3e850ff1e7217a3b7a07eba90d37fe9bb9e89a310f718afcde5885ca9b6d7" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "regex", - "syn 1.0.109", - "zvariant_utils", -] - [[package]] name = "zbus_names" version = "2.6.1" @@ -12694,18 +12454,7 @@ checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" dependencies = [ "serde", "static_assertions", - "zvariant 3.15.1", -] - -[[package]] -name = "zbus_names" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" -dependencies = [ - "serde", - "static_assertions", - "zvariant 4.0.2", + "zvariant", ] [[package]] @@ -12900,20 +12649,7 @@ dependencies = [ "serde", "static_assertions", "url", - "zvariant_derive 3.15.1", -] - -[[package]] -name = "zvariant" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1b3ca6db667bfada0f1ebfc94b2b1759ba25472ee5373d4551bb892616389a" -dependencies = [ - "endi", - "enumflags2", - "serde", - "static_assertions", - "zvariant_derive 4.0.2", + "zvariant_derive", ] [[package]] @@ -12929,19 +12665,6 @@ dependencies = [ "zvariant_utils", ] -[[package]] -name = "zvariant_derive" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a4b236063316163b69039f77ce3117accb41a09567fd24c168e43491e521bc" -dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2", - "quote", - "syn 1.0.109", - "zvariant_utils", -] - [[package]] name = "zvariant_utils" version = "1.1.0" diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 530629294a160..4202de4b2807f 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -21,9 +21,6 @@ mod cross_platform; #[cfg(any(test, feature = "test-support"))] mod test; -#[cfg(target_os = "windows")] -mod windows; - use crate::{ Action, AnyWindowHandle, AsyncWindowContext, BackgroundExecutor, Bounds, DevicePixels, Font, FontId, FontMetrics, FontRun, ForegroundExecutor, GlobalPixels, GlyphId, Keymap, LineLayout, @@ -71,7 +68,7 @@ pub(crate) fn current_platform() -> Rc { pub(crate) fn current_platform() -> Rc { Rc::new(LinuxPlatform::new()) } -// todo("windows") + #[cfg(target_os = "windows")] pub(crate) fn current_platform() -> Rc { Rc::new(WindowsPlatform::new()) From 2925897602778c2ea505acfe7cefff0b1b5b4984 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 4 Mar 2024 15:34:54 +0800 Subject: [PATCH 29/39] fix typo --- crates/gpui/src/platform/windows/constants.rs | 6 +++--- crates/gpui/src/platform/windows/events.rs | 4 ++-- crates/gpui/src/platform/windows/platform.rs | 4 ++-- crates/gpui/src/platform/windows/window.rs | 18 +++++++++--------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/crates/gpui/src/platform/windows/constants.rs b/crates/gpui/src/platform/windows/constants.rs index c068a808aec62..840d98fccbffb 100644 --- a/crates/gpui/src/platform/windows/constants.rs +++ b/crates/gpui/src/platform/windows/constants.rs @@ -15,15 +15,15 @@ pub const DISPATCH_WINDOW_STYLE: WINDOW_STYLE = WS_OVERLAPPED; pub const DISPATCH_WINDOW_EXSTYLE: WINDOW_EX_STYLE = WINDOW_EX_STYLE( WS_EX_NOACTIVATE.0 | WS_EX_TRANSPARENT.0 | WS_EX_LAYERED.0 | WS_EX_TOOLWINDOW.0, ); -pub const WINODW_STYLE: WINDOW_STYLE = WS_OVERLAPPEDWINDOW; -pub const WINODW_EXTRA_EXSTYLE: WINDOW_EX_STYLE = WS_EX_ACCEPTFILES; +pub const BASIC_WINDOW_STYLE: WINDOW_STYLE = WS_OVERLAPPEDWINDOW; +pub const WINDOW_EXTRA_EXSTYLE: WINDOW_EX_STYLE = WS_EX_ACCEPTFILES; // events // Values in the range 0x0400 (the value of WM_USER) through 0x7FFF are // available for message identifiers for private window classes. pub const WINDOW_REFRESH_TIMER: usize = 1; // the minimum value is 0xA, which means only max to 100fps -pub const WINODW_REFRESH_INTERVAL: u32 = 16; +pub const WINDOW_REFRESH_INTERVAL: u32 = 16; pub const MAIN_DISPATCH: u32 = WM_USER + 1; pub const WINDOW_CLOSE: u32 = WM_USER + 2; pub const WINDOW_OPEN: u32 = WM_USER + 3; diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index 8d6948bcc016d..0fb4a303c259e 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -30,7 +30,7 @@ use crate::{ MOUSE_MOVE_MBUTTON, MOUSE_MOVE_RBUTTON, MOUSE_MOVE_XBUTTON1, MOUSE_MOVE_XBUTTON2, }; -pub struct WindowsWinodwDataWrapper(pub Rc); +pub struct WindowsWindowDataWrapper(pub Rc); pub trait WindowsWindowBase where @@ -51,7 +51,7 @@ where lparam: LPARAM, ) -> LRESULT { unsafe { - let ptr = get_windowdata(handle) as *const WindowsWinodwDataWrapper; + let ptr = get_windowdata(handle) as *const WindowsWindowDataWrapper; if ptr.is_null() { return DefWindowProcW(handle, message, wparam, lparam); } diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 5e20c4b6f9fbd..1a7fb5b5221ef 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -66,7 +66,7 @@ use windows::{ use crate::{ encode_wide, log_windows_error, log_windows_error_with_message, platform::cross_platform::CosmicTextSystem, set_windowdata, Keystroke, WindowsWindow, - WindowsWindowBase, WindowsWinodwDataWrapper, ACCEL_FALT, ACCEL_FCONTROL, ACCEL_FSHIFT, + WindowsWindowBase, WindowsWindowDataWrapper, ACCEL_FALT, ACCEL_FCONTROL, ACCEL_FSHIFT, ACCEL_FVIRTKEY, CF_UNICODETEXT, CLIPBOARD_METADATA, CLIPBOARD_TEXT_HASH, DISPATCH_WINDOW_CLASS, DISPATCH_WINDOW_EXSTYLE, DISPATCH_WINDOW_STYLE, MAIN_DISPATCH, MENU_ACTIONS, WINDOW_CLOSE, }; @@ -121,7 +121,7 @@ impl WindowsPlatform { unsafe { set_windowdata( dispatch_window_handle, - WindowsWinodwDataWrapper(inner.clone()), + WindowsWindowDataWrapper(inner.clone()), ); } let dispatcher = Arc::new(WindowsDispatcher::new(sender, dispatch_window_handle)); diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index fb4dcdbfb725c..d14f639aa5f1e 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -54,9 +54,9 @@ use crate::{ parse_mouse_hwheel, parse_mouse_movement_wparam, parse_mouse_vwheel, parse_system_key, platform::cross_platform::BladeRenderer, set_windowdata, Bounds, DisplayId, ForegroundExecutor, Modifiers, Pixels, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, - Size, WindowKind, WindowOptions, WindowsWindowBase, WindowsWinodwDataWrapper, - DRAGDROP_GET_COUNT, FILENAME_MAXLENGTH, MENU_ACTIONS, WINDOW_CLOSE, WINDOW_REFRESH_TIMER, - WINODW_EXTRA_EXSTYLE, WINODW_REFRESH_INTERVAL, WINODW_STYLE, + Size, WindowKind, WindowOptions, WindowsWindowBase, WindowsWindowDataWrapper, + BASIC_WINDOW_STYLE, DRAGDROP_GET_COUNT, FILENAME_MAXLENGTH, MENU_ACTIONS, WINDOW_CLOSE, + WINDOW_EXTRA_EXSTYLE, WINDOW_REFRESH_INTERVAL, WINDOW_REFRESH_TIMER, }; use super::{display::WindowsDisplay, WINDOW_CLASS}; @@ -159,12 +159,12 @@ impl WindowsWindow { SetTimer( raw_window_handle, WINDOW_REFRESH_TIMER, - WINODW_REFRESH_INTERVAL, + WINDOW_REFRESH_INTERVAL, TIMERPROC::None, ); } let windows_dragdrop = unsafe { - set_windowdata(raw_window_handle, WindowsWinodwDataWrapper(inner.clone())); + set_windowdata(raw_window_handle, WindowsWindowDataWrapper(inner.clone())); let drop_target = WindowsDragDropTarget(inner.clone()); let windows_dragdrop: IDropTarget = drop_target.into(); RegisterDragDrop(raw_window_handle, &windows_dragdrop) @@ -410,7 +410,7 @@ impl WindowsWindowBase for WindowsWindowinner { }); self.handle_input(input); } - // let Windows to hanle the left things, so we still have the system-wide + // let Windows to handle the left things, so we still have the system-wide // Alt+Tab, Alt+F4 ... working DefWindowProcW(handle, message, wparam, lparam) } @@ -887,7 +887,7 @@ impl RawWindow { pub fn show(&self) { unsafe { // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow - let _ = ShowWindow(self.hwnd(), SW_SHOW); // succes reports as error + let _ = ShowWindow(self.hwnd(), SW_SHOW); // success reports as error } } @@ -978,9 +978,9 @@ unsafe impl blade_rwh::HasRawDisplayHandle for RawWindow { fn parse_window_options( options: &WindowOptions, ) -> (WINDOW_STYLE, WINDOW_EX_STYLE, Option, Option) { - let mut style = WINODW_STYLE; + let mut style = BASIC_WINDOW_STYLE; // https://learn.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles - let exstyle = WINDOW_EX_STYLE::default() | WINODW_EXTRA_EXSTYLE; + let exstyle = WINDOW_EX_STYLE::default() | WINDOW_EXTRA_EXSTYLE; let mut width = None; let mut height = None; if options.show { From 6514fe57afb437b7d8c4fbfb1b826ad49c99cd54 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 4 Mar 2024 16:41:41 +0800 Subject: [PATCH 30/39] fix build on linux --- Cargo.lock | 308 +++++++++++++++++++++++++++++++++++++++-- crates/gpui/Cargo.toml | 1 + 2 files changed, 297 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b9b04401fca8..ed6c3b114659b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,6 +40,18 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if 1.0.0", + "cipher 0.4.4", + "cpufeatures", + "zeroize", +] + [[package]] name = "ahash" version = "0.7.6" @@ -312,7 +324,7 @@ dependencies = [ "serde", "serde_repr", "url", - "zbus", + "zbus 3.15.1", ] [[package]] @@ -384,6 +396,18 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-broadcast" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258b52a1aa741b9f09783b2d86cf0aeeb617bbf847f6933340a39644227acbdb" +dependencies = [ + "event-listener 5.1.0", + "event-listener-strategy 0.5.0", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-channel" version = "1.9.0" @@ -607,6 +631,24 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "async-process" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451e3cf68011bd56771c79db04a9e333095ab6349f7e47592b788e9b98720cc8" +dependencies = [ + "async-channel 2.2.0", + "async-io 2.3.1", + "async-lock 3.3.0", + "async-signal", + "blocking", + "cfg-if 1.0.0", + "event-listener 5.1.0", + "futures-lite 2.2.0", + "rustix 0.38.30", + "windows-sys 0.52.0", +] + [[package]] name = "async-recursion" version = "0.3.2" @@ -629,6 +671,24 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "async-signal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" +dependencies = [ + "async-io 2.3.1", + "async-lock 2.8.0", + "atomic-waker", + "cfg-if 1.0.0", + "futures-core", + "futures-io", + "rustix 0.38.30", + "signal-hook-registry", + "slab", + "windows-sys 0.48.0", +] + [[package]] name = "async-std" version = "1.12.0" @@ -639,7 +699,7 @@ dependencies = [ "async-global-executor", "async-io 1.13.0", "async-lock 2.8.0", - "async-process", + "async-process 1.7.0", "crossbeam-utils", "futures-channel", "futures-core", @@ -1452,6 +1512,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + [[package]] name = "blocking" version = "1.5.1" @@ -1760,6 +1829,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "cbindgen" version = "0.26.0" @@ -1867,6 +1945,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + [[package]] name = "clang-sys" version = "1.6.1" @@ -2776,6 +2865,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] @@ -3245,6 +3335,12 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + [[package]] name = "enumflags2" version = "0.7.9" @@ -4251,6 +4347,7 @@ dependencies = [ "metal", "num_cpus", "objc", + "oo7", "open", "parking", "parking_lot 0.11.2", @@ -4743,6 +4840,16 @@ dependencies = [ "libc", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "block-padding", + "generic-array", +] + [[package]] name = "install_cli" version = "0.1.0" @@ -5949,6 +6056,7 @@ dependencies = [ "bitflags 2.4.2", "cfg-if 1.0.0", "libc", + "memoffset 0.9.0", ] [[package]] @@ -6046,6 +6154,20 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint 0.4.4", + "num-complex 0.4.4", + "num-integer", + "num-iter", + "num-rational 0.4.1", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.2.6" @@ -6098,6 +6220,7 @@ dependencies = [ "num-iter", "num-traits", "rand 0.8.5", + "serde", "smallvec", "zeroize", ] @@ -6176,6 +6299,18 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint 0.4.4", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.16" @@ -6292,6 +6427,35 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "oo7" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37558cac1af63a81fd2ff7f3469c02a4da06b163c5671791553b8dac10f07c82" +dependencies = [ + "aes", + "async-fs 2.1.1", + "async-io 2.3.1", + "async-lock 3.3.0", + "blocking", + "cbc", + "cipher 0.4.4", + "digest 0.10.7", + "futures-lite 2.2.0", + "futures-util", + "hkdf", + "hmac 0.12.1", + "num 0.4.1", + "num-bigint-dig 0.8.4", + "pbkdf2 0.12.2", + "rand 0.8.5", + "serde", + "sha2 0.10.7", + "zbus 4.0.1", + "zeroize", + "zvariant 4.0.2", +] + [[package]] name = "opaque-debug" version = "0.3.0" @@ -6549,7 +6713,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7037e5e93e0172a5a96874380bf73bc6ecef022e26fa25f2be26864d6b3ba95d" dependencies = [ "lazy_static", - "num", + "num 0.2.1", "regex", ] @@ -6603,6 +6767,16 @@ dependencies = [ "crypto-mac", ] +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", +] + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -6887,6 +7061,15 @@ dependencies = [ "toml_edit 0.19.15", ] +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -8070,7 +8253,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecbd2eb639fd7cab5804a0837fe373cc2172d15437e804c054a9fb885cb923b0" dependencies = [ - "cipher", + "cipher 0.3.0", ] [[package]] @@ -8143,7 +8326,7 @@ dependencies = [ "base64ct", "hmac 0.11.0", "password-hash", - "pbkdf2", + "pbkdf2 0.8.0", "salsa20", "sha2 0.9.9", ] @@ -8745,7 +8928,7 @@ dependencies = [ "async-io 1.13.0", "async-lock 2.8.0", "async-net 1.7.0", - "async-process", + "async-process 1.7.0", "blocking", "futures-lite 1.13.0", ] @@ -9915,6 +10098,17 @@ dependencies = [ "winnow 0.5.15", ] +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.0.0", + "toml_datetime", + "winnow 0.5.15", +] + [[package]] name = "toml_edit" version = "0.22.6" @@ -12402,7 +12596,7 @@ dependencies = [ "async-fs 1.6.0", "async-io 1.13.0", "async-lock 2.8.0", - "async-process", + "async-process 1.7.0", "async-recursion 1.0.5", "async-task", "async-trait", @@ -12427,9 +12621,48 @@ dependencies = [ "uds_windows", "winapi 0.3.9", "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", + "zbus_macros 3.15.1", + "zbus_names 2.6.1", + "zvariant 3.15.1", +] + +[[package]] +name = "zbus" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b8e3d6ae3342792a6cc2340e4394334c7402f3d793b390d2c5494a4032b3030" +dependencies = [ + "async-broadcast 0.7.0", + "async-executor", + "async-fs 2.1.1", + "async-io 2.3.1", + "async-lock 3.3.0", + "async-process 2.1.0", + "async-recursion 1.0.5", + "async-task", + "async-trait", + "blocking", + "derivative", + "enumflags2", + "event-listener 5.1.0", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.27.1", + "ordered-stream", + "rand 0.8.5", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.52.0", + "xdg-home", + "zbus_macros 4.0.1", + "zbus_names 3.0.0", + "zvariant 4.0.2", ] [[package]] @@ -12446,6 +12679,20 @@ dependencies = [ "zvariant_utils", ] +[[package]] +name = "zbus_macros" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a3e850ff1e7217a3b7a07eba90d37fe9bb9e89a310f718afcde5885ca9b6d7" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils", +] + [[package]] name = "zbus_names" version = "2.6.1" @@ -12454,7 +12701,18 @@ checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" dependencies = [ "serde", "static_assertions", - "zvariant", + "zvariant 3.15.1", +] + +[[package]] +name = "zbus_names" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +dependencies = [ + "serde", + "static_assertions", + "zvariant 4.0.2", ] [[package]] @@ -12649,7 +12907,20 @@ dependencies = [ "serde", "static_assertions", "url", - "zvariant_derive", + "zvariant_derive 3.15.1", +] + +[[package]] +name = "zvariant" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1b3ca6db667bfada0f1ebfc94b2b1759ba25472ee5373d4551bb892616389a" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "zvariant_derive 4.0.2", ] [[package]] @@ -12665,6 +12936,19 @@ dependencies = [ "zvariant_utils", ] +[[package]] +name = "zvariant_derive" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a4b236063316163b69039f77ce3117accb41a09567fd24c168e43491e521bc" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils", +] + [[package]] name = "zvariant_utils" version = "1.1.0" diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 839138e335c4d..60eebe6195e7f 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -123,6 +123,7 @@ blade-macros.workspace = true blade-rwh.workspace = true bytemuck = "1" cosmic-text = "0.10.0" +oo7 = "0.3.0" [target.'cfg(target_os = "windows")'.dependencies] blade-graphics.workspace = true From 38327bb590ff368b89fc2a152cc6127b69a16f33 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 4 Mar 2024 17:45:07 +0800 Subject: [PATCH 31/39] use workspace windows crate --- Cargo.lock | 24 ++--------------------- Cargo.toml | 43 +++++++++++++++++++++++++++++++++++------- crates/fs/Cargo.toml | 5 +---- crates/gpui/Cargo.toml | 26 +------------------------ 4 files changed, 40 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed6c3b114659b..6a8d52e1ae38c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9680,7 +9680,7 @@ dependencies = [ "theme", "thiserror", "util", - "windows 0.53.0", + "windows 0.54.0", ] [[package]] @@ -11988,38 +11988,18 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538" -dependencies = [ - "windows-core 0.53.0", - "windows-targets 0.52.4", -] - [[package]] name = "windows" version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" dependencies = [ - "windows-core 0.54.0", + "windows-core", "windows-implement", "windows-interface", "windows-targets 0.52.4", ] -[[package]] -name = "windows-core" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" -dependencies = [ - "windows-result", - "windows-targets 0.52.4", -] - [[package]] name = "windows-core" version = "0.54.0" diff --git a/Cargo.toml b/Cargo.toml index 682908e2f6e89..8b99b3f4c0998 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -215,7 +215,10 @@ hex = "0.4.3" ignore = "0.4.22" indoc = "1" # We explicitly disable http2 support in isahc. -isahc = { version = "1.7.2", default-features = false, features = ["static-curl", "text-decoding"] } +isahc = { version = "1.7.2", default-features = false, features = [ + "static-curl", + "text-decoding", +] } itertools = "0.11.0" lazy_static = "1.4.0" linkify = "0.10.0" @@ -238,7 +241,10 @@ semver = "1.0" serde = { version = "1.0", features = ["derive", "rc"] } serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] } -serde_json_lenient = { version = "0.1", features = ["preserve_order", "raw_value"] } +serde_json_lenient = { version = "0.1", features = [ + "preserve_order", + "raw_value", +] } serde_repr = "0.1" sha2 = "0.10" shellexpand = "2.1.0" @@ -249,7 +255,11 @@ sysinfo = "0.29.10" tempfile = "3.9.0" thiserror = "1.0.29" tiktoken-rs = "0.5.7" -time = { version = "0.3", features = ["serde", "serde-well-known", "formatting"] } +time = { version = "0.3", features = [ + "serde", + "serde-well-known", + "formatting", +] } toml = "0.8" tower-http = "0.4.4" tree-sitter = { version = "0.20", features = ["wasm"] } @@ -310,16 +320,35 @@ which = "6.0.0" sys-locale = "0.3.1" [workspace.dependencies.windows] -version = "0.53.0" +version = "0.54.0" features = [ + "implement", + "Wdk_System_SystemServices", + "Win32_Foundation", + "Win32_Globalization", "Win32_Graphics_Gdi", - "Win32_UI_WindowsAndMessaging", - "Win32_Security", + "Win32_Security_Credentials", + "Win32_Storage_FileSystem", + "Win32_System_Com", + "Win32_System_Com_StructuredStorage", + "Win32_System_DataExchange", + "Win32_System_LibraryLoader", + "Win32_System_Memory", + "Win32_System_Ole", + "Win32_System_SystemInformation", + "Win32_System_SystemServices", + "Win32_System_Time", "Win32_System_Threading", + "Win32_UI_Accessibility", + "Win32_UI_Controls", + "Win32_UI_HiDpi", + "Win32_UI_Input_Ime", + "Win32_UI_Input_KeyboardAndMouse", + "Win32_UI_Shell", + "Win32_UI_WindowsAndMessaging", ] - [patch.crates-io] tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "e4a23971ec3071a09c1e84816954c98f96e98e52" } # Workaround for a broken nightly build of gpui: See #7644 and revisit once 0.5.3 is released. diff --git a/crates/fs/Cargo.toml b/crates/fs/Cargo.toml index 4b48dbc2bf19d..15ca34ec09bb4 100644 --- a/crates/fs/Cargo.toml +++ b/crates/fs/Cargo.toml @@ -38,10 +38,7 @@ gpui = { workspace = true, optional = true } notify = "6.1.1" [target.'cfg(target_os = "windows")'.dependencies] -windows-sys = { version = "0.52", features = [ - "Win32_Foundation", - "Win32_Storage_FileSystem", -] } +windows.workspace = true [dev-dependencies] gpui = { workspace = true, features = ["test-support"] } diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 60eebe6195e7f..95c128e47f469 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -132,31 +132,7 @@ blade-rwh.workspace = true bytemuck = "1" cosmic-text = "0.10.0" flume = "0.11" -windows = { version = "0.54", features = [ - "implement", - "Wdk_System_SystemServices", - "Win32_Foundation", - "Win32_Globalization", - "Win32_Graphics_Gdi", - "Win32_Security_Credentials", - "Win32_System_Com", - "Win32_System_Com_StructuredStorage", - "Win32_System_DataExchange", - "Win32_System_LibraryLoader", - "Win32_System_Memory", - "Win32_System_Ole", - "Win32_System_SystemInformation", - "Win32_System_SystemServices", - "Win32_System_Time", - "Win32_System_Threading", - "Win32_UI_Accessibility", - "Win32_UI_Controls", - "Win32_UI_HiDpi", - "Win32_UI_Input_Ime", - "Win32_UI_Input_KeyboardAndMouse", - "Win32_UI_Shell", - "Win32_UI_WindowsAndMessaging", -] } +windows.workspace = true [target.'cfg(target_os = "windows")'.build-dependencies] winresource = "0.1" From c36b2ab50a7f7dcee0071b47312d0e09dcd8eba6 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 4 Mar 2024 18:26:59 +0800 Subject: [PATCH 32/39] fix fs --- Cargo.lock | 2 +- crates/fs/src/fs.rs | 9 +++------ crates/gpui/src/platform/windows/window.rs | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6a8d52e1ae38c..eb4582f668db1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3888,7 +3888,7 @@ dependencies = [ "text", "time", "util", - "windows-sys 0.52.0", + "windows 0.54.0", ] [[package]] diff --git a/crates/fs/src/fs.rs b/crates/fs/src/fs.rs index 968ab68389b55..149dd74f6d9fe 100644 --- a/crates/fs/src/fs.rs +++ b/crates/fs/src/fs.rs @@ -1440,7 +1440,7 @@ async fn file_id(path: impl AsRef) -> Result { use std::os::windows::io::AsRawHandle; use smol::fs::windows::OpenOptionsExt; - use windows_sys::Win32::{ + use windows::Win32::{ Foundation::HANDLE, Storage::FileSystem::{ GetFileInformationByHandle, BY_HANDLE_FILE_INFORMATION, FILE_FLAG_BACKUP_SEMANTICS, @@ -1449,7 +1449,7 @@ async fn file_id(path: impl AsRef) -> Result { let file = smol::fs::OpenOptions::new() .read(true) - .custom_flags(FILE_FLAG_BACKUP_SEMANTICS) + .custom_flags(FILE_FLAG_BACKUP_SEMANTICS.0) .open(path) .await?; @@ -1457,10 +1457,7 @@ async fn file_id(path: impl AsRef) -> Result { // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle // This function supports Windows XP+ smol::unblock(move || { - let ret = unsafe { GetFileInformationByHandle(file.as_raw_handle() as HANDLE, &mut info) }; - if ret == 0 { - return Err(anyhow!(format!("{}", std::io::Error::last_os_error()))); - }; + unsafe { GetFileInformationByHandle(HANDLE(file.as_raw_handle() as _), &mut info)? }; Ok(((info.nFileIndexHigh as u64) << 32) | (info.nFileIndexLow as u64)) }) diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index d14f639aa5f1e..e45c743385642 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -905,7 +905,7 @@ impl RawWindow { } pub fn scale_factor(&self) -> f32 { - (self.get_dpi() as f32) / (96 as f32) + (self.get_dpi() as f32) / 96.0 } fn get_dpi(&self) -> u32 { From 275642510d1d0ab2cc4a9002ba19d02d01654f06 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 4 Mar 2024 23:36:12 +0800 Subject: [PATCH 33/39] fix a crash --- crates/terminal_view/src/terminal_view.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 00cda8fc32c3b..4d40a88984c79 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -872,7 +872,7 @@ impl Item for TerminalView { ) -> Task>> { let window = cx.window_handle(); cx.spawn(|pane, mut cx| async move { - let cwd = TERMINAL_DB + let mut cwd = TERMINAL_DB .get_working_directory(item_id, workspace_id) .log_err() .flatten() @@ -886,7 +886,11 @@ impl Item for TerminalView { .ok() .flatten() }); - + if let Some(ref cwd_str) = cwd { + if cwd_str.as_os_str().is_empty() { + cwd = None; + } + } let terminal = project.update(&mut cx, |project, cx| { project.create_terminal(cwd, None, window, cx) })??; From c2a1a2824571254b890cc82474201eb105a21926 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 4 Mar 2024 23:37:01 +0800 Subject: [PATCH 34/39] remove extra deps --- crates/gpui/Cargo.toml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 95c128e47f469..ee917da9e693a 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -117,21 +117,9 @@ xkbcommon = { version = "0.7", features = ["wayland", "x11"] } as-raw-xcb-connection = "1" calloop = "0.12.4" calloop-wayland-source = "0.2.0" -#TODO: use these on all platforms -blade-graphics.workspace = true -blade-macros.workspace = true -blade-rwh.workspace = true -bytemuck = "1" -cosmic-text = "0.10.0" oo7 = "0.3.0" [target.'cfg(target_os = "windows")'.dependencies] -blade-graphics.workspace = true -blade-macros.workspace = true -blade-rwh.workspace = true -bytemuck = "1" -cosmic-text = "0.10.0" -flume = "0.11" windows.workspace = true [target.'cfg(target_os = "windows")'.build-dependencies] From 423e1d3d8941898a02f0d028559dd4250ecf2c8a Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 4 Mar 2024 23:59:34 +0800 Subject: [PATCH 35/39] run cargo clippy --- crates/gpui/src/platform/cross_platform.rs | 4 +-- crates/gpui/src/platform/windows/events.rs | 2 +- crates/gpui/src/platform/windows/monitor.rs | 2 +- crates/gpui/src/platform/windows/platform.rs | 9 +++---- crates/gpui/src/platform/windows/util.rs | 26 -------------------- crates/gpui/src/platform/windows/utils.rs | 2 +- crates/gpui/src/platform/windows/window.rs | 24 +++++++++--------- 7 files changed, 22 insertions(+), 47 deletions(-) delete mode 100644 crates/gpui/src/platform/windows/util.rs diff --git a/crates/gpui/src/platform/cross_platform.rs b/crates/gpui/src/platform/cross_platform.rs index 4f436d5e80d3a..398fb2448b5b5 100644 --- a/crates/gpui/src/platform/cross_platform.rs +++ b/crates/gpui/src/platform/cross_platform.rs @@ -6,7 +6,7 @@ mod text_system; pub(crate) use blade_atlas::*; pub(crate) use blade_renderer::*; - -use blade_belt::*; #[cfg(not(feature = "macos-blade"))] pub(crate) use text_system::*; + +use blade_belt::*; diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index 0fb4a303c259e..79592199e569f 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -100,7 +100,7 @@ where width.unwrap_or(0), height.unwrap_or(0), HWND::default(), - menu_handle.unwrap_or(HMENU::default()), + menu_handle.unwrap_or_default(), get_module_handle(), None, ) diff --git a/crates/gpui/src/platform/windows/monitor.rs b/crates/gpui/src/platform/windows/monitor.rs index ede52503d7200..b56ca0385fc89 100644 --- a/crates/gpui/src/platform/windows/monitor.rs +++ b/crates/gpui/src/platform/windows/monitor.rs @@ -23,7 +23,7 @@ impl MonitorHandle { } pub fn scale_factor(&self) -> f32 { - (self.get_dpi() as f32) / (96 as f32) + (self.get_dpi() as f32) / 96.0 } fn get_dpi(&self) -> u32 { diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 1a7fb5b5221ef..a7c6c501fa97f 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -211,7 +211,7 @@ impl Platform for WindowsPlatform { let dispatch_window_handle = self.inner.dispatch_window_handle; let table = self.shortcuts_table.borrow_mut().take().unwrap(); while GetMessageW(&mut msg, HWND::default(), 0, 0).as_bool() { - if TranslateAcceleratorW(dispatch_window_handle, table, &mut msg) == 0 { + if TranslateAcceleratorW(dispatch_window_handle, table, &msg) == 0 { TranslateMessage(&msg); DispatchMessageW(&msg); } @@ -262,10 +262,10 @@ impl Platform for WindowsPlatform { _handle: AnyWindowHandle, options: WindowOptions, ) -> Box { - let menu_handle = self.menu_handle.borrow().clone(); + let menu_handle = *self.menu_handle.borrow(); let window = WindowsWindow::new( self.foreground_executor(), - self.inner.dispatch_window_handle.into(), + self.inner.dispatch_window_handle, &options, menu_handle, ); @@ -786,7 +786,6 @@ fn open_target(target: String) { ); if ret.0 <= 32 { log_windows_error_with_message!("Unable to open target"); - return; } } } @@ -802,7 +801,7 @@ fn show_openfile_dialog(options: PathPromptOptions) -> anyhow::Result u16; - fn loword(&self) -> u16; -} - -impl HiLoWord for WPARAM { - fn hiword(&self) -> u16 { - ((self.0 >> 16) & 0xFFFF) as u16 - } - - fn loword(&self) -> u16 { - (self.0 & 0xFFFF) as u16 - } -} - -impl HiLoWord for LPARAM { - fn hiword(&self) -> u16 { - ((self.0 >> 16) & 0xFFFF) as u16 - } - - fn loword(&self) -> u16 { - (self.0 & 0xFFFF) as u16 - } -} diff --git a/crates/gpui/src/platform/windows/utils.rs b/crates/gpui/src/platform/windows/utils.rs index 49b025b7360fd..c0e3182fc2aa5 100644 --- a/crates/gpui/src/platform/windows/utils.rs +++ b/crates/gpui/src/platform/windows/utils.rs @@ -27,7 +27,7 @@ pub fn get_module_handle() -> HMODULE { ) .unwrap(); // should never fail - return h_module; + h_module } } diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index e45c743385642..99238fcca9f6c 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -6,7 +6,7 @@ use smallvec::SmallVec; use windows::{ core::{implement, PCWSTR}, Win32::{ - Foundation::{HWND, LPARAM, LRESULT, POINTL, RECT, S_OK, WPARAM}, + Foundation::{HWND, LPARAM, LRESULT, POINT, POINTL, RECT, S_OK, WPARAM}, Graphics::Gdi::{ MonitorFromWindow, RedrawWindow, ValidateRect, HRGN, MONITOR_DEFAULTTONEAREST, RDW_ERASENOW, RDW_INVALIDATE, RDW_UPDATENOW, @@ -36,8 +36,8 @@ use windows::{ WindowsAndMessaging::{ DefWindowProcW, GetClientRect, GetCursorPos, KillTimer, PostMessageW, SetTimer, SetWindowTextW, ShowWindow, CW_USEDEFAULT, GWLP_HINSTANCE, HMENU, SIZE_MINIMIZED, - SW_MINIMIZE, SW_SHOW, TIMERPROC, WA_ACTIVE, WA_CLICKACTIVE, WA_INACTIVE, - WINDOW_EX_STYLE, WINDOW_STYLE, WM_ACTIVATE, WM_CHAR, WM_COMMAND, WM_DESTROY, + SW_MINIMIZE, SW_SHOW, TIMERPROC, WA_ACTIVE, WA_CLICKACTIVE, WINDOW_EX_STYLE, + WINDOW_STYLE, WM_ACTIVATE, WM_CHAR, WM_COMMAND, WM_DESTROY, WM_IME_STARTCOMPOSITION, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDBLCLK, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_PAINT, WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, @@ -382,8 +382,6 @@ impl WindowsWindowBase for WindowsWindowinner { }; let _ = TrackMouseEvent(&mut config).inspect_err(log_windows_error); self.set_focused(true); - } else if loword!(wparam.0, u16) as u32 & WA_INACTIVE > 0 { - self.set_focused(false); } LRESULT(0) } @@ -500,8 +498,6 @@ impl WindowsWindowBase for WindowsWindowinner { } WM_IME_STARTCOMPOSITION => { let ctx = ImmGetContext(handle); - let mut config = COMPOSITIONFORM::default(); - config.dwStyle = CFS_POINT; let mut cursor = std::mem::zeroed(); if GetCursorPos(&mut cursor) .inspect_err(log_windows_error) @@ -510,8 +506,14 @@ impl WindowsWindowBase for WindowsWindowinner { cursor.x = 0; cursor.y = 0; } - config.ptCurrentPos.x = cursor.x; - config.ptCurrentPos.y = cursor.y; + let config = COMPOSITIONFORM { + dwStyle: CFS_POINT, + ptCurrentPos: POINT { + x: cursor.x, + y: cursor.y, + }, + ..Default::default() + }; ImmSetCompositionWindow(ctx, &config as _); ImmReleaseContext(handle, ctx); LRESULT(0) @@ -713,7 +715,7 @@ impl PlatformWindow for WindowsWindow { ) -> futures::channel::oneshot::Receiver { let (done_tx, done_rx) = oneshot::channel(); let msg = msg.to_string(); - let detail = match detail { + let detail_string = match detail { Some(info) => Some(info.to_string()), None => None, }; @@ -747,7 +749,7 @@ impl PlatformWindow for WindowsWindow { let instruction = encode_wide(&msg); config.pszMainInstruction = PCWSTR::from_raw(instruction.as_ptr()); let hints_encoded; - if let Some(ref hints) = detail { + if let Some(ref hints) = detail_string { hints_encoded = encode_wide(hints); config.pszContent = PCWSTR::from_raw(hints_encoded.as_ptr()); }; From 0a8739aeafac18b14329cc5e5524dc5896da9fd4 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Tue, 5 Mar 2024 00:02:44 +0800 Subject: [PATCH 36/39] fix typo --- crates/gpui/src/platform/windows/window.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 99238fcca9f6c..ca5aedf9c9b55 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -76,7 +76,7 @@ pub struct Callbacks { pub struct WindowsWindow { foreground_executor: ForegroundExecutor, - inner: Rc, + inner: Rc, display: Rc, windows_dragdrop: IDropTarget, } @@ -113,7 +113,7 @@ impl WindowsWindow { } } let (style, exstyle, width, height) = parse_window_options(options); - let raw_window_handle = ::create( + let raw_window_handle = ::create( WINDOW_CLASS, style, exstyle, @@ -148,7 +148,7 @@ impl WindowsWindow { depth: 1, }; let renderer = BladeRenderer::new(gpu, gpu_extent); - let inner = WindowsWindowinner::new( + let inner = WindowsWindowInner::new( dispatch_window_handle, scale_factor, window_handle, @@ -182,7 +182,7 @@ impl WindowsWindow { } } -pub struct WindowsWindowinner { +pub struct WindowsWindowInner { pub dispatch_window_handle: HWND, window_handle: RawWindow, bounds: RefCell>, @@ -194,13 +194,13 @@ pub struct WindowsWindowinner { } #[implement(IDropTarget)] -struct WindowsDragDropTarget(pub Rc); +struct WindowsDragDropTarget(pub Rc); struct RawWindow { handle: HWND, } -impl WindowsWindowinner { +impl WindowsWindowInner { fn new( dispatch_window_handle: HWND, scale_factor: f32, @@ -210,7 +210,7 @@ impl WindowsWindowinner { ) -> Rc { window_handle.show(); - Rc::new(WindowsWindowinner { + Rc::new(WindowsWindowInner { dispatch_window_handle, window_handle, callbacks: RefCell::new(Callbacks::default()), @@ -327,7 +327,7 @@ impl WindowsWindowinner { } } -impl WindowsWindowBase for WindowsWindowinner { +impl WindowsWindowBase for WindowsWindowInner { unsafe fn handle_message( &self, handle: HWND, @@ -880,7 +880,7 @@ impl RawWindow { } } - pub fn set_data(&self, data: Rc) { + pub fn set_data(&self, data: Rc) { unsafe { set_windowdata(self.hwnd(), data); } From 0a125e6d970862163530b493cd60cbf2f1886e52 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Tue, 5 Mar 2024 00:21:20 +0800 Subject: [PATCH 37/39] fix mac imports --- crates/gpui/src/platform/mac.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gpui/src/platform/mac.rs b/crates/gpui/src/platform/mac.rs index 15d10225bac0e..453913ce90ec9 100644 --- a/crates/gpui/src/platform/mac.rs +++ b/crates/gpui/src/platform/mac.rs @@ -14,7 +14,7 @@ pub mod metal_renderer; use metal_renderer as renderer; #[cfg(feature = "macos-blade")] -use crate::platform::blade as renderer; +use crate::platform::cross_platform as renderer; mod open_type; mod platform; From 01cdc7038f58acb54445756c3bc22b674c9be3b7 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Tue, 5 Mar 2024 00:40:00 +0800 Subject: [PATCH 38/39] fix typo --- crates/gpui/build.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index 003813c0a7d1e..2cc8914cef7fa 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -22,8 +22,7 @@ fn main() { #[cfg(not(feature = "runtime_shaders"))] compile_metal_shaders(&header_path); - // We are using Windows Visita+, right..? - // if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" { + // We are using Windows Vista+, right..? #[cfg(target_os = "windows")] { println!("cargo:rustc-link-arg=/stack:{}", 4 * 1024 * 1024); From d163ba41e9db4cbfb998fb4c455d81314da5256a Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Tue, 5 Mar 2024 03:24:09 +0800 Subject: [PATCH 39/39] need a deeper look into the `input()` and `input_handler()` functions currently, they are just black boxs for me --- crates/gpui/src/platform/windows/window.rs | 35 +++++++++++----------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index ca5aedf9c9b55..a218b5e0a6c1e 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -263,24 +263,25 @@ impl WindowsWindowInner { return; } } - match input.clone() { - PlatformInput::KeyDown(event) => { - if let Some(mut input_handler) = self.input_handler.borrow_mut().as_mut() { - input_handler.replace_text_in_range(None, &event.keystroke.key); - } - } - PlatformInput::KeyUp(_) => {} - PlatformInput::ModifiersChanged(_) => {} - PlatformInput::MouseDown(_) => { - if let Some(ref mut input_handler) = self.callbacks.borrow_mut().input { - input_handler(input); - } + if let PlatformInput::KeyDown(event) = input { + if event.keystroke.key.len() > 1 { + return; } - PlatformInput::MouseUp(_) => {} - PlatformInput::MouseMove(_) => {} - PlatformInput::MouseExited(_) => {} - PlatformInput::ScrollWheel(_) => {} - PlatformInput::FileDrop(_) => {} + self.with_input_handler(|input_handler| { + input_handler.replace_text_in_range(None, &event.keystroke.key) + }); + } + } + + fn with_input_handler(&self, f: F) -> Option + where + F: FnOnce(&mut PlatformInputHandler) -> R, + { + if let Some(ref mut input_handler) = *self.input_handler.borrow_mut() { + let result = f(input_handler); + Some(result) + } else { + None } }