1use std::sync::OnceLock;
2
3use ::util::ResultExt;
4use windows::Win32::{Foundation::*, System::Threading::*, UI::WindowsAndMessaging::*};
5
6use crate::*;
7
8pub(crate) trait HiLoWord {
9 fn hiword(&self) -> u16;
10 fn loword(&self) -> u16;
11 fn signed_hiword(&self) -> i16;
12 fn signed_loword(&self) -> i16;
13}
14
15impl HiLoWord for WPARAM {
16 fn hiword(&self) -> u16 {
17 ((self.0 >> 16) & 0xFFFF) as u16
18 }
19
20 fn loword(&self) -> u16 {
21 (self.0 & 0xFFFF) as u16
22 }
23
24 fn signed_hiword(&self) -> i16 {
25 ((self.0 >> 16) & 0xFFFF) as i16
26 }
27
28 fn signed_loword(&self) -> i16 {
29 (self.0 & 0xFFFF) as i16
30 }
31}
32
33impl HiLoWord for LPARAM {
34 fn hiword(&self) -> u16 {
35 ((self.0 >> 16) & 0xFFFF) as u16
36 }
37
38 fn loword(&self) -> u16 {
39 (self.0 & 0xFFFF) as u16
40 }
41
42 fn signed_hiword(&self) -> i16 {
43 ((self.0 >> 16) & 0xFFFF) as i16
44 }
45
46 fn signed_loword(&self) -> i16 {
47 (self.0 & 0xFFFF) as i16
48 }
49}
50
51pub(crate) unsafe fn get_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX) -> isize {
52 #[cfg(target_pointer_width = "64")]
53 unsafe {
54 GetWindowLongPtrW(hwnd, nindex)
55 }
56 #[cfg(target_pointer_width = "32")]
57 unsafe {
58 GetWindowLongW(hwnd, nindex) as isize
59 }
60}
61
62pub(crate) unsafe fn set_window_long(
63 hwnd: HWND,
64 nindex: WINDOW_LONG_PTR_INDEX,
65 dwnewlong: isize,
66) -> isize {
67 #[cfg(target_pointer_width = "64")]
68 unsafe {
69 SetWindowLongPtrW(hwnd, nindex, dwnewlong)
70 }
71 #[cfg(target_pointer_width = "32")]
72 unsafe {
73 SetWindowLongW(hwnd, nindex, dwnewlong as i32) as isize
74 }
75}
76
77#[derive(Debug, Clone)]
78pub(crate) struct OwnedHandle(HANDLE);
79
80impl OwnedHandle {
81 pub(crate) fn new(handle: HANDLE) -> Self {
82 Self(handle)
83 }
84
85 #[inline(always)]
86 pub(crate) fn to_raw(&self) -> HANDLE {
87 self.0
88 }
89}
90
91impl Drop for OwnedHandle {
92 fn drop(&mut self) {
93 if !self.0.is_invalid() {
94 unsafe { CloseHandle(self.0) }.log_err();
95 }
96 }
97}
98
99pub(crate) fn create_event() -> windows::core::Result<OwnedHandle> {
100 Ok(OwnedHandle::new(unsafe {
101 CreateEventW(None, false, false, None)?
102 }))
103}
104
105pub(crate) fn windows_credentials_target_name(url: &str) -> String {
106 format!("zed:url={}", url)
107}
108
109pub(crate) fn load_cursor(style: CursorStyle) -> HCURSOR {
110 static ARROW: OnceLock<HCURSOR> = OnceLock::new();
111 static IBEAM: OnceLock<HCURSOR> = OnceLock::new();
112 static CROSS: OnceLock<HCURSOR> = OnceLock::new();
113 static HAND: OnceLock<HCURSOR> = OnceLock::new();
114 static SIZEWE: OnceLock<HCURSOR> = OnceLock::new();
115 static SIZENS: OnceLock<HCURSOR> = OnceLock::new();
116 static NO: OnceLock<HCURSOR> = OnceLock::new();
117 let (lock, name) = match style {
118 CursorStyle::IBeam | CursorStyle::IBeamCursorForVerticalLayout => (&IBEAM, IDC_IBEAM),
119 CursorStyle::Crosshair => (&CROSS, IDC_CROSS),
120 CursorStyle::PointingHand | CursorStyle::DragLink => (&HAND, IDC_HAND),
121 CursorStyle::ResizeLeft
122 | CursorStyle::ResizeRight
123 | CursorStyle::ResizeLeftRight
124 | CursorStyle::ResizeColumn => (&SIZEWE, IDC_SIZEWE),
125 CursorStyle::ResizeUp
126 | CursorStyle::ResizeDown
127 | CursorStyle::ResizeUpDown
128 | CursorStyle::ResizeRow => (&SIZENS, IDC_SIZENS),
129 CursorStyle::OperationNotAllowed => (&NO, IDC_NO),
130 _ => (&ARROW, IDC_ARROW),
131 };
132 *lock.get_or_init(|| {
133 HCURSOR(
134 unsafe { LoadImageW(None, name, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) }
135 .log_err()
136 .unwrap_or_default()
137 .0,
138 )
139 })
140}
141
142#[inline]
143pub(crate) fn logical_size(physical_size: Size<DevicePixels>, scale_factor: f32) -> Size<Pixels> {
144 Size {
145 width: px(physical_size.width.0 as f32 / scale_factor),
146 height: px(physical_size.height.0 as f32 / scale_factor),
147 }
148}
149
150#[inline]
151pub(crate) fn logical_point(x: f32, y: f32, scale_factor: f32) -> Point<Pixels> {
152 Point {
153 x: px(x / scale_factor),
154 y: px(y / scale_factor),
155 }
156}