Implement more GPUI services on windows. (#8940)

### Description

This is a part of #8809 , impl the following functions:

- `os_version`
- `local_timezone`
- `double_click_interval`
- `set_cursor_style`
- `open_url`
- `reveal_path`

Release Notes:
- N/A

---------

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
Small White 2024-03-07 04:48:43 +08:00 committed by GitHub
parent effc317a06
commit af87fb98d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 140 additions and 26 deletions

View File

@ -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"] }
@ -312,11 +322,15 @@ sys-locale = "0.3.1"
[workspace.dependencies.windows]
version = "0.53.0"
features = [
"Wdk_System_SystemServices",
"Win32_Graphics_Gdi",
"Win32_Graphics_DirectComposition",
"Win32_UI_WindowsAndMessaging",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_Shell",
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_System_Time",
"Win32_Security",
"Win32_System_Threading",
"Win32_System_DataExchange",

View File

@ -17,14 +17,28 @@ use futures::channel::oneshot::Receiver;
use parking_lot::Mutex;
use time::UtcOffset;
use util::{ResultExt, SemanticVersion};
use windows::Win32::{
Foundation::{CloseHandle, BOOL, HANDLE, HWND, LPARAM, TRUE},
Graphics::DirectComposition::DCompositionWaitForCompositorClock,
System::Threading::{CreateEventW, GetCurrentThreadId, INFINITE},
UI::WindowsAndMessaging::{
DispatchMessageW, EnumThreadWindows, PeekMessageW, PostQuitMessage, SystemParametersInfoW,
TranslateMessage, MSG, PM_REMOVE, SPI_GETWHEELSCROLLCHARS, SPI_GETWHEELSCROLLLINES,
SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, WM_QUIT, WM_SETTINGCHANGE,
use windows::{
core::{HSTRING, PCWSTR},
Wdk::System::SystemServices::RtlGetVersion,
Win32::{
Foundation::{CloseHandle, BOOL, HANDLE, HWND, LPARAM, TRUE},
Graphics::DirectComposition::DCompositionWaitForCompositorClock,
System::{
Threading::{CreateEventW, GetCurrentThreadId, INFINITE},
Time::{GetTimeZoneInformation, TIME_ZONE_ID_INVALID},
},
UI::{
Input::KeyboardAndMouse::GetDoubleClickTime,
Shell::ShellExecuteW,
WindowsAndMessaging::{
DispatchMessageW, EnumThreadWindows, LoadImageW, MsgWaitForMultipleObjects,
PeekMessageW, PostQuitMessage, SetCursor, SystemParametersInfoW, TranslateMessage,
HCURSOR, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_IBEAM, IDC_NO, IDC_SIZENS, IDC_SIZEWE,
IMAGE_CURSOR, LR_DEFAULTSIZE, LR_SHARED, MSG, PM_REMOVE, QS_ALLINPUT,
SPI_GETWHEELSCROLLCHARS, SPI_GETWHEELSCROLLLINES, SW_SHOWDEFAULT,
SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, WM_QUIT, WM_SETTINGCHANGE,
},
},
},
};
@ -300,9 +314,16 @@ impl Platform for WindowsPlatform {
WindowAppearance::Dark
}
// todo!("windows")
fn open_url(&self, url: &str) {
// todo!("windows")
let url_string = url.to_string();
self.background_executor()
.spawn(async move {
if url_string.is_empty() {
return;
}
open_target(url_string.as_str());
})
.detach();
}
// todo!("windows")
@ -320,9 +341,22 @@ impl Platform for WindowsPlatform {
unimplemented!()
}
// todo!("windows")
fn reveal_path(&self, path: &Path) {
unimplemented!()
let Ok(file_full_path) = path.canonicalize() else {
log::error!("unable to parse file path");
return;
};
self.background_executor()
.spawn(async move {
let Some(path) = file_full_path.to_str() else {
return;
};
if path.is_empty() {
return;
}
open_target(path);
})
.detach();
}
fn on_become_active(&self, callback: Box<dyn FnMut()>) {
@ -365,11 +399,20 @@ impl Platform for WindowsPlatform {
}
fn os_version(&self) -> Result<SemanticVersion> {
Ok(SemanticVersion {
major: 1,
minor: 0,
patch: 0,
})
let mut info = unsafe { std::mem::zeroed() };
let status = unsafe { RtlGetVersion(&mut info) };
if status.is_ok() {
Ok(SemanticVersion {
major: info.dwMajorVersion as _,
minor: info.dwMinorVersion as _,
patch: info.dwBuildNumber as _,
})
} else {
Err(anyhow::anyhow!(
"unable to get Windows version: {}",
std::io::Error::last_os_error()
))
}
}
fn app_version(&self) -> Result<SemanticVersion> {
@ -385,14 +428,28 @@ impl Platform for WindowsPlatform {
Err(anyhow!("not yet implemented"))
}
// todo!("windows")
fn local_timezone(&self) -> UtcOffset {
UtcOffset::from_hms(9, 0, 0).unwrap()
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 double_click_interval(&self) -> Duration {
Duration::from_millis(100)
let millis = unsafe { GetDoubleClickTime() };
Duration::from_millis(millis as _)
}
// todo!("windows")
@ -400,8 +457,31 @@ impl Platform for WindowsPlatform {
Err(anyhow!("not yet implemented"))
}
// todo!("windows")
fn set_cursor_style(&self, style: CursorStyle) {}
fn set_cursor_style(&self, style: CursorStyle) {
let handle = match style {
CursorStyle::IBeam | CursorStyle::IBeamCursorForVerticalLayout => unsafe {
load_cursor(IDC_IBEAM)
},
CursorStyle::Crosshair => unsafe { load_cursor(IDC_CROSS) },
CursorStyle::PointingHand | CursorStyle::DragLink => unsafe { load_cursor(IDC_HAND) },
CursorStyle::ResizeLeft | CursorStyle::ResizeRight | CursorStyle::ResizeLeftRight => unsafe {
load_cursor(IDC_SIZEWE)
},
CursorStyle::ResizeUp | CursorStyle::ResizeDown | CursorStyle::ResizeUpDown => unsafe {
load_cursor(IDC_SIZENS)
},
CursorStyle::OperationNotAllowed => unsafe { load_cursor(IDC_NO) },
_ => unsafe { load_cursor(IDC_ARROW) },
};
if handle.is_err() {
log::error!(
"Error loading cursor image: {}",
std::io::Error::last_os_error()
);
return;
}
let _ = unsafe { SetCursor(HCURSOR(handle.unwrap().0)) };
}
// todo!("windows")
fn should_auto_hide_scrollbars(&self) -> bool {
@ -437,3 +517,23 @@ impl Platform for WindowsPlatform {
Task::ready(Err(anyhow!("register_url_scheme unimplemented")))
}
}
unsafe fn load_cursor(name: PCWSTR) -> Result<HANDLE> {
LoadImageW(None, name, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED).map_err(|e| anyhow!(e))
}
fn open_target(target: &str) {
unsafe {
let ret = ShellExecuteW(
None,
windows::core::w!("open"),
&HSTRING::from(target),
None,
None,
SW_SHOWDEFAULT,
);
if ret.0 <= 32 {
log::error!("Unable to open target: {}", std::io::Error::last_os_error());
}
}
}