gpui(windows): Move interior mutability down into fields (#44002)
Windows applications tend to be fairly re-entrant which does not work well with our current top-level `RefCell` approach. We have worked around a bunch of panics in the past due to this, but ultimately this will re-occur (and still does according to sentry) in the future. So this PR moves all interior mutability down to the fields. Fixes ZED-1HM Fixes ZED-3SH Fixes ZED-1YV Fixes ZED-29S Fixes ZED-29X Fixes ZED-369 Fixes ZED-20W Release Notes: - Fixed panics on windows caused by unexpected re-entrancy for interior mutability
This commit is contained in:
@@ -748,7 +748,7 @@ impl Size<Length> {
|
||||
/// assert_eq!(bounds.origin, origin);
|
||||
/// assert_eq!(bounds.size, size);
|
||||
/// ```
|
||||
#[derive(Refineable, Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
#[derive(Refineable, Copy, Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
#[refineable(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Bounds<T: Clone + Debug + Default + PartialEq> {
|
||||
@@ -1676,8 +1676,6 @@ impl Bounds<DevicePixels> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Clone + Debug + Default + PartialEq> Copy for Bounds<T> {}
|
||||
|
||||
/// Represents the edges of a box in a 2D space, such as padding or margin.
|
||||
///
|
||||
/// Each field represents the size of the edge on one side of the box: `top`, `right`, `bottom`, and `left`.
|
||||
|
||||
@@ -116,17 +116,16 @@ impl WindowsWindowInner {
|
||||
}
|
||||
|
||||
fn handle_move_msg(&self, handle: HWND, lparam: LPARAM) -> Option<isize> {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let origin = logical_point(
|
||||
lparam.signed_loword() as f32,
|
||||
lparam.signed_hiword() as f32,
|
||||
lock.scale_factor,
|
||||
self.state.scale_factor.get(),
|
||||
);
|
||||
lock.origin = origin;
|
||||
let size = lock.logical_size;
|
||||
self.state.origin.set(origin);
|
||||
let size = self.state.logical_size.get();
|
||||
let center_x = origin.x.0 + size.width.0 / 2.;
|
||||
let center_y = origin.y.0 + size.height.0 / 2.;
|
||||
let monitor_bounds = lock.display.bounds();
|
||||
let monitor_bounds = self.state.display.get().bounds();
|
||||
if center_x < monitor_bounds.left().0
|
||||
|| center_x > monitor_bounds.right().0
|
||||
|| center_y < monitor_bounds.top().0
|
||||
@@ -136,42 +135,42 @@ impl WindowsWindowInner {
|
||||
let monitor = unsafe { MonitorFromWindow(handle, MONITOR_DEFAULTTONULL) };
|
||||
// minimize the window can trigger this event too, in this case,
|
||||
// monitor is invalid, we do nothing.
|
||||
if !monitor.is_invalid() && lock.display.handle != monitor {
|
||||
if !monitor.is_invalid() && self.state.display.get().handle != monitor {
|
||||
// we will get the same monitor if we only have one
|
||||
lock.display = WindowsDisplay::new_with_handle(monitor).log_err()?;
|
||||
self.state
|
||||
.display
|
||||
.set(WindowsDisplay::new_with_handle(monitor).log_err()?);
|
||||
}
|
||||
}
|
||||
if let Some(mut callback) = lock.callbacks.moved.take() {
|
||||
drop(lock);
|
||||
if let Some(mut callback) = self.state.callbacks.moved.take() {
|
||||
callback();
|
||||
self.state.borrow_mut().callbacks.moved = Some(callback);
|
||||
self.state.callbacks.moved.set(Some(callback));
|
||||
}
|
||||
Some(0)
|
||||
}
|
||||
|
||||
fn handle_get_min_max_info_msg(&self, lparam: LPARAM) -> Option<isize> {
|
||||
let lock = self.state.borrow();
|
||||
let min_size = lock.min_size?;
|
||||
let scale_factor = lock.scale_factor;
|
||||
let boarder_offset = lock.border_offset;
|
||||
drop(lock);
|
||||
let min_size = self.state.min_size?;
|
||||
let scale_factor = self.state.scale_factor.get();
|
||||
let boarder_offset = &self.state.border_offset;
|
||||
|
||||
unsafe {
|
||||
let minmax_info = &mut *(lparam.0 as *mut MINMAXINFO);
|
||||
minmax_info.ptMinTrackSize.x =
|
||||
min_size.width.scale(scale_factor).0 as i32 + boarder_offset.width_offset;
|
||||
min_size.width.scale(scale_factor).0 as i32 + boarder_offset.width_offset.get();
|
||||
minmax_info.ptMinTrackSize.y =
|
||||
min_size.height.scale(scale_factor).0 as i32 + boarder_offset.height_offset;
|
||||
min_size.height.scale(scale_factor).0 as i32 + boarder_offset.height_offset.get();
|
||||
}
|
||||
Some(0)
|
||||
}
|
||||
|
||||
fn handle_size_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
|
||||
// Don't resize the renderer when the window is minimized, but record that it was minimized so
|
||||
// that on restore the swap chain can be recreated via `update_drawable_size_even_if_unchanged`.
|
||||
if wparam.0 == SIZE_MINIMIZED as usize {
|
||||
lock.restore_from_minimized = lock.callbacks.request_frame.take();
|
||||
self.state
|
||||
.restore_from_minimized
|
||||
.set(self.state.callbacks.request_frame.take());
|
||||
return Some(0);
|
||||
}
|
||||
|
||||
@@ -179,14 +178,16 @@ impl WindowsWindowInner {
|
||||
let height = lparam.hiword().max(1) as i32;
|
||||
let new_size = size(DevicePixels(width), DevicePixels(height));
|
||||
|
||||
let scale_factor = lock.scale_factor;
|
||||
let scale_factor = self.state.scale_factor.get();
|
||||
let mut should_resize_renderer = false;
|
||||
if lock.restore_from_minimized.is_some() {
|
||||
lock.callbacks.request_frame = lock.restore_from_minimized.take();
|
||||
if let Some(restore_from_minimized) = self.state.restore_from_minimized.take() {
|
||||
self.state
|
||||
.callbacks
|
||||
.request_frame
|
||||
.set(Some(restore_from_minimized));
|
||||
} else {
|
||||
should_resize_renderer = true;
|
||||
}
|
||||
drop(lock);
|
||||
|
||||
self.handle_size_change(new_size, scale_factor, should_resize_renderer);
|
||||
Some(0)
|
||||
@@ -199,17 +200,19 @@ impl WindowsWindowInner {
|
||||
should_resize_renderer: bool,
|
||||
) {
|
||||
let new_logical_size = device_size.to_pixels(scale_factor);
|
||||
let mut lock = self.state.borrow_mut();
|
||||
lock.logical_size = new_logical_size;
|
||||
if should_resize_renderer && let Err(e) = lock.renderer.resize(device_size) {
|
||||
|
||||
self.state.logical_size.set(new_logical_size);
|
||||
if should_resize_renderer
|
||||
&& let Err(e) = self.state.renderer.borrow_mut().resize(device_size)
|
||||
{
|
||||
log::error!("Failed to resize renderer, invalidating devices: {}", e);
|
||||
lock.invalidate_devices
|
||||
self.state
|
||||
.invalidate_devices
|
||||
.store(true, std::sync::atomic::Ordering::Release);
|
||||
}
|
||||
if let Some(mut callback) = lock.callbacks.resize.take() {
|
||||
drop(lock);
|
||||
if let Some(mut callback) = self.state.callbacks.resize.take() {
|
||||
callback(new_logical_size, scale_factor);
|
||||
self.state.borrow_mut().callbacks.resize = Some(callback);
|
||||
self.state.callbacks.resize.set(Some(callback));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,17 +257,14 @@ impl WindowsWindowInner {
|
||||
}
|
||||
|
||||
fn handle_close_msg(&self) -> Option<isize> {
|
||||
let mut callback = self.state.borrow_mut().callbacks.should_close.take()?;
|
||||
let mut callback = self.state.callbacks.should_close.take()?;
|
||||
let should_close = callback();
|
||||
self.state.borrow_mut().callbacks.should_close = Some(callback);
|
||||
self.state.callbacks.should_close.set(Some(callback));
|
||||
if should_close { None } else { Some(0) }
|
||||
}
|
||||
|
||||
fn handle_destroy_msg(&self, handle: HWND) -> Option<isize> {
|
||||
let callback = {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
lock.callbacks.close.take()
|
||||
};
|
||||
let callback = { self.state.callbacks.close.take() };
|
||||
if let Some(callback) = callback {
|
||||
callback();
|
||||
}
|
||||
@@ -283,12 +283,10 @@ impl WindowsWindowInner {
|
||||
fn handle_mouse_move_msg(&self, handle: HWND, lparam: LPARAM, wparam: WPARAM) -> Option<isize> {
|
||||
self.start_tracking_mouse(handle, TME_LEAVE);
|
||||
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let Some(mut func) = lock.callbacks.input.take() else {
|
||||
let Some(mut func) = self.state.callbacks.input.take() else {
|
||||
return Some(1);
|
||||
};
|
||||
let scale_factor = lock.scale_factor;
|
||||
drop(lock);
|
||||
let scale_factor = self.state.scale_factor.get();
|
||||
|
||||
let pressed_button = match MODIFIERKEYS_FLAGS(wparam.loword() as u32) {
|
||||
flags if flags.contains(MK_LBUTTON) => Some(MouseButton::Left),
|
||||
@@ -310,32 +308,32 @@ impl WindowsWindowInner {
|
||||
modifiers: current_modifiers(),
|
||||
});
|
||||
let handled = !func(input).propagate;
|
||||
self.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
|
||||
if handled { Some(0) } else { Some(1) }
|
||||
}
|
||||
|
||||
fn handle_mouse_leave_msg(&self) -> Option<isize> {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
lock.hovered = false;
|
||||
if let Some(mut callback) = lock.callbacks.hovered_status_change.take() {
|
||||
drop(lock);
|
||||
self.state.hovered.set(false);
|
||||
if let Some(mut callback) = self.state.callbacks.hovered_status_change.take() {
|
||||
callback(false);
|
||||
self.state.borrow_mut().callbacks.hovered_status_change = Some(callback);
|
||||
self.state
|
||||
.callbacks
|
||||
.hovered_status_change
|
||||
.set(Some(callback));
|
||||
}
|
||||
|
||||
Some(0)
|
||||
}
|
||||
|
||||
fn handle_syskeyup_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let input = handle_key_event(wparam, lparam, &mut lock, |keystroke, _| {
|
||||
let input = handle_key_event(wparam, lparam, &self.state, |keystroke, _| {
|
||||
PlatformInput::KeyUp(KeyUpEvent { keystroke })
|
||||
})?;
|
||||
let mut func = lock.callbacks.input.take()?;
|
||||
drop(lock);
|
||||
let mut func = self.state.callbacks.input.take()?;
|
||||
|
||||
func(input);
|
||||
self.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
|
||||
// Always return 0 to indicate that the message was handled, so we could properly handle `ModifiersChanged` event.
|
||||
Some(0)
|
||||
@@ -344,11 +342,10 @@ impl WindowsWindowInner {
|
||||
// It's a known bug that you can't trigger `ctrl-shift-0`. See:
|
||||
// https://superuser.com/questions/1455762/ctrl-shift-number-key-combination-has-stopped-working-for-a-few-numbers
|
||||
fn handle_keydown_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let Some(input) = handle_key_event(
|
||||
wparam,
|
||||
lparam,
|
||||
&mut lock,
|
||||
&self.state,
|
||||
|keystroke, prefer_character_input| {
|
||||
PlatformInput::KeyDown(KeyDownEvent {
|
||||
keystroke,
|
||||
@@ -359,34 +356,31 @@ impl WindowsWindowInner {
|
||||
) else {
|
||||
return Some(1);
|
||||
};
|
||||
drop(lock);
|
||||
|
||||
let Some(mut func) = self.state.borrow_mut().callbacks.input.take() else {
|
||||
let Some(mut func) = self.state.callbacks.input.take() else {
|
||||
return Some(1);
|
||||
};
|
||||
|
||||
let handled = !func(input).propagate;
|
||||
|
||||
self.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
|
||||
if handled { Some(0) } else { Some(1) }
|
||||
}
|
||||
|
||||
fn handle_keyup_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let Some(input) = handle_key_event(wparam, lparam, &mut lock, |keystroke, _| {
|
||||
let Some(input) = handle_key_event(wparam, lparam, &self.state, |keystroke, _| {
|
||||
PlatformInput::KeyUp(KeyUpEvent { keystroke })
|
||||
}) else {
|
||||
return Some(1);
|
||||
};
|
||||
|
||||
let Some(mut func) = lock.callbacks.input.take() else {
|
||||
let Some(mut func) = self.state.callbacks.input.take() else {
|
||||
return Some(1);
|
||||
};
|
||||
drop(lock);
|
||||
|
||||
let handled = !func(input).propagate;
|
||||
self.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
|
||||
if handled { Some(0) } else { Some(1) }
|
||||
}
|
||||
@@ -407,16 +401,15 @@ impl WindowsWindowInner {
|
||||
lparam: LPARAM,
|
||||
) -> Option<isize> {
|
||||
unsafe { SetCapture(handle) };
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let Some(mut func) = lock.callbacks.input.take() else {
|
||||
|
||||
let Some(mut func) = self.state.callbacks.input.take() else {
|
||||
return Some(1);
|
||||
};
|
||||
let x = lparam.signed_loword();
|
||||
let y = lparam.signed_hiword();
|
||||
let physical_point = point(DevicePixels(x as i32), DevicePixels(y as i32));
|
||||
let click_count = lock.click_state.update(button, physical_point);
|
||||
let scale_factor = lock.scale_factor;
|
||||
drop(lock);
|
||||
let click_count = self.state.click_state.update(button, physical_point);
|
||||
let scale_factor = self.state.scale_factor.get();
|
||||
|
||||
let input = PlatformInput::MouseDown(MouseDownEvent {
|
||||
button,
|
||||
@@ -426,7 +419,7 @@ impl WindowsWindowInner {
|
||||
first_mouse: false,
|
||||
});
|
||||
let handled = !func(input).propagate;
|
||||
self.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
|
||||
if handled { Some(0) } else { Some(1) }
|
||||
}
|
||||
@@ -438,15 +431,14 @@ impl WindowsWindowInner {
|
||||
lparam: LPARAM,
|
||||
) -> Option<isize> {
|
||||
unsafe { ReleaseCapture().log_err() };
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let Some(mut func) = lock.callbacks.input.take() else {
|
||||
|
||||
let Some(mut func) = self.state.callbacks.input.take() else {
|
||||
return Some(1);
|
||||
};
|
||||
let x = lparam.signed_loword() as f32;
|
||||
let y = lparam.signed_hiword() as f32;
|
||||
let click_count = lock.click_state.current_count;
|
||||
let scale_factor = lock.scale_factor;
|
||||
drop(lock);
|
||||
let click_count = self.state.click_state.current_count.get();
|
||||
let scale_factor = self.state.scale_factor.get();
|
||||
|
||||
let input = PlatformInput::MouseUp(MouseUpEvent {
|
||||
button,
|
||||
@@ -455,7 +447,7 @@ impl WindowsWindowInner {
|
||||
click_count,
|
||||
});
|
||||
let handled = !func(input).propagate;
|
||||
self.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
|
||||
if handled { Some(0) } else { Some(1) }
|
||||
}
|
||||
@@ -482,24 +474,23 @@ impl WindowsWindowInner {
|
||||
lparam: LPARAM,
|
||||
) -> Option<isize> {
|
||||
let modifiers = current_modifiers();
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let Some(mut func) = lock.callbacks.input.take() else {
|
||||
|
||||
let Some(mut func) = self.state.callbacks.input.take() else {
|
||||
return Some(1);
|
||||
};
|
||||
let scale_factor = lock.scale_factor;
|
||||
let scale_factor = self.state.scale_factor.get();
|
||||
let wheel_scroll_amount = match modifiers.shift {
|
||||
true => {
|
||||
self.system_settings()
|
||||
.mouse_wheel_settings
|
||||
.wheel_scroll_chars
|
||||
}
|
||||
false => {
|
||||
self.system_settings()
|
||||
.mouse_wheel_settings
|
||||
.wheel_scroll_lines
|
||||
}
|
||||
true => self
|
||||
.system_settings()
|
||||
.mouse_wheel_settings
|
||||
.wheel_scroll_chars
|
||||
.get(),
|
||||
false => self
|
||||
.system_settings()
|
||||
.mouse_wheel_settings
|
||||
.wheel_scroll_lines
|
||||
.get(),
|
||||
};
|
||||
drop(lock);
|
||||
|
||||
let wheel_distance =
|
||||
(wparam.signed_hiword() as f32 / WHEEL_DELTA as f32) * wheel_scroll_amount as f32;
|
||||
@@ -524,7 +515,7 @@ impl WindowsWindowInner {
|
||||
touch_phase: TouchPhase::Moved,
|
||||
});
|
||||
let handled = !func(input).propagate;
|
||||
self.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
|
||||
if handled { Some(0) } else { Some(1) }
|
||||
}
|
||||
@@ -535,16 +526,15 @@ impl WindowsWindowInner {
|
||||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
) -> Option<isize> {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let Some(mut func) = lock.callbacks.input.take() else {
|
||||
let Some(mut func) = self.state.callbacks.input.take() else {
|
||||
return Some(1);
|
||||
};
|
||||
let scale_factor = lock.scale_factor;
|
||||
let scale_factor = self.state.scale_factor.get();
|
||||
let wheel_scroll_chars = self
|
||||
.system_settings()
|
||||
.mouse_wheel_settings
|
||||
.wheel_scroll_chars;
|
||||
drop(lock);
|
||||
.wheel_scroll_chars
|
||||
.get();
|
||||
|
||||
let wheel_distance =
|
||||
(-wparam.signed_hiword() as f32 / WHEEL_DELTA as f32) * wheel_scroll_chars as f32;
|
||||
@@ -563,7 +553,7 @@ impl WindowsWindowInner {
|
||||
touch_phase: TouchPhase::Moved,
|
||||
});
|
||||
let handled = !func(event).propagate;
|
||||
self.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
|
||||
if handled { Some(0) } else { Some(1) }
|
||||
}
|
||||
@@ -657,11 +647,11 @@ impl WindowsWindowInner {
|
||||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
) -> Option<isize> {
|
||||
if !self.hide_title_bar || self.state.borrow().is_fullscreen() || wparam.0 == 0 {
|
||||
if !self.hide_title_bar || self.state.is_fullscreen() || wparam.0 == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let is_maximized = self.state.borrow().is_maximized();
|
||||
let is_maximized = self.state.is_maximized();
|
||||
let insets = get_client_area_insets(handle, is_maximized, self.windows_version);
|
||||
// wparam is TRUE so lparam points to an NCCALCSIZE_PARAMS structure
|
||||
let mut params = lparam.0 as *mut NCCALCSIZE_PARAMS;
|
||||
@@ -676,7 +666,7 @@ impl WindowsWindowInner {
|
||||
// used by Chrome. However, it may result in one row of pixels being obscured
|
||||
// in our client area. But as Chrome says, "there seems to be no better solution."
|
||||
if is_maximized
|
||||
&& let Some(ref taskbar_position) = self.system_settings().auto_hide_taskbar_position
|
||||
&& let Some(taskbar_position) = self.system_settings().auto_hide_taskbar_position.get()
|
||||
{
|
||||
// For the auto-hide taskbar, adjust in by 1 pixel on taskbar edge,
|
||||
// so the window isn't treated as a "fullscreen app", which would cause
|
||||
@@ -705,11 +695,9 @@ impl WindowsWindowInner {
|
||||
let this = self.clone();
|
||||
self.executor
|
||||
.spawn(async move {
|
||||
let mut lock = this.state.borrow_mut();
|
||||
if let Some(mut func) = lock.callbacks.active_status_change.take() {
|
||||
drop(lock);
|
||||
if let Some(mut func) = this.state.callbacks.active_status_change.take() {
|
||||
func(activated);
|
||||
this.state.borrow_mut().callbacks.active_status_change = Some(func);
|
||||
this.state.callbacks.active_status_change.set(Some(func));
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
@@ -733,12 +721,11 @@ impl WindowsWindowInner {
|
||||
lparam: LPARAM,
|
||||
) -> Option<isize> {
|
||||
let new_dpi = wparam.loword() as f32;
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let is_maximized = lock.is_maximized();
|
||||
|
||||
let is_maximized = self.state.is_maximized();
|
||||
let new_scale_factor = new_dpi / USER_DEFAULT_SCREEN_DPI as f32;
|
||||
lock.scale_factor = new_scale_factor;
|
||||
lock.border_offset.update(handle).log_err();
|
||||
drop(lock);
|
||||
self.state.scale_factor.set(new_scale_factor);
|
||||
self.state.border_offset.update(handle).log_err();
|
||||
|
||||
if is_maximized {
|
||||
// Get the monitor and its work area at the new DPI
|
||||
@@ -812,7 +799,7 @@ impl WindowsWindowInner {
|
||||
// Because WM_DPICHANGED, WM_MOVE, WM_SIZE will come first, window reposition and resize
|
||||
// are handled there.
|
||||
// So we only care about if monitor is disconnected.
|
||||
let previous_monitor = self.state.borrow().display;
|
||||
let previous_monitor = self.state.display.get();
|
||||
if WindowsDisplay::is_connected(previous_monitor.handle) {
|
||||
// we are fine, other display changed
|
||||
return None;
|
||||
@@ -830,24 +817,22 @@ impl WindowsWindowInner {
|
||||
return None;
|
||||
}
|
||||
let new_display = WindowsDisplay::new_with_handle(new_monitor).log_err()?;
|
||||
self.state.borrow_mut().display = new_display;
|
||||
self.state.display.set(new_display);
|
||||
Some(0)
|
||||
}
|
||||
|
||||
fn handle_hit_test_msg(&self, handle: HWND, lparam: LPARAM) -> Option<isize> {
|
||||
if !self.is_movable || self.state.borrow().is_fullscreen() {
|
||||
if !self.is_movable || self.state.is_fullscreen() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let callback = self
|
||||
.state
|
||||
.borrow_mut()
|
||||
.callbacks
|
||||
.hit_test_window_control
|
||||
.take();
|
||||
let callback = self.state.callbacks.hit_test_window_control.take();
|
||||
let drag_area = if let Some(mut callback) = callback {
|
||||
let area = callback();
|
||||
self.state.borrow_mut().callbacks.hit_test_window_control = Some(callback);
|
||||
self.state
|
||||
.callbacks
|
||||
.hit_test_window_control
|
||||
.set(Some(callback));
|
||||
if let Some(area) = area {
|
||||
match area {
|
||||
WindowControlArea::Drag => Some(HTCAPTION as _),
|
||||
@@ -878,7 +863,7 @@ impl WindowsWindowInner {
|
||||
};
|
||||
|
||||
unsafe { ScreenToClient(handle, &mut cursor_point).ok().log_err() };
|
||||
if !self.state.borrow().is_maximized() && 0 <= cursor_point.y && cursor_point.y <= frame_y {
|
||||
if !self.state.is_maximized() && 0 <= cursor_point.y && cursor_point.y <= frame_y {
|
||||
// x-axis actually goes from -frame_x to 0
|
||||
return Some(if cursor_point.x <= 0 {
|
||||
HTTOPLEFT
|
||||
@@ -902,10 +887,8 @@ impl WindowsWindowInner {
|
||||
fn handle_nc_mouse_move_msg(&self, handle: HWND, lparam: LPARAM) -> Option<isize> {
|
||||
self.start_tracking_mouse(handle, TME_LEAVE | TME_NONCLIENT);
|
||||
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let mut func = lock.callbacks.input.take()?;
|
||||
let scale_factor = lock.scale_factor;
|
||||
drop(lock);
|
||||
let mut func = self.state.callbacks.input.take()?;
|
||||
let scale_factor = self.state.scale_factor.get();
|
||||
|
||||
let mut cursor_point = POINT {
|
||||
x: lparam.signed_loword().into(),
|
||||
@@ -918,7 +901,7 @@ impl WindowsWindowInner {
|
||||
modifiers: current_modifiers(),
|
||||
});
|
||||
let handled = !func(input).propagate;
|
||||
self.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
|
||||
if handled { Some(0) } else { None }
|
||||
}
|
||||
@@ -930,17 +913,15 @@ impl WindowsWindowInner {
|
||||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
) -> Option<isize> {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
if let Some(mut func) = lock.callbacks.input.take() {
|
||||
let scale_factor = lock.scale_factor;
|
||||
if let Some(mut func) = self.state.callbacks.input.take() {
|
||||
let scale_factor = self.state.scale_factor.get();
|
||||
let mut cursor_point = POINT {
|
||||
x: lparam.signed_loword().into(),
|
||||
y: lparam.signed_hiword().into(),
|
||||
};
|
||||
unsafe { ScreenToClient(handle, &mut cursor_point).ok().log_err() };
|
||||
let physical_point = point(DevicePixels(cursor_point.x), DevicePixels(cursor_point.y));
|
||||
let click_count = lock.click_state.update(button, physical_point);
|
||||
drop(lock);
|
||||
let click_count = self.state.click_state.update(button, physical_point);
|
||||
|
||||
let input = PlatformInput::MouseDown(MouseDownEvent {
|
||||
button,
|
||||
@@ -951,21 +932,20 @@ impl WindowsWindowInner {
|
||||
});
|
||||
let result = func(input);
|
||||
let handled = !result.propagate || result.default_prevented;
|
||||
self.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
|
||||
if handled {
|
||||
return Some(0);
|
||||
}
|
||||
} else {
|
||||
drop(lock);
|
||||
};
|
||||
|
||||
// Since these are handled in handle_nc_mouse_up_msg we must prevent the default window proc
|
||||
if button == MouseButton::Left {
|
||||
match wparam.0 as u32 {
|
||||
HTMINBUTTON => self.state.borrow_mut().nc_button_pressed = Some(HTMINBUTTON),
|
||||
HTMAXBUTTON => self.state.borrow_mut().nc_button_pressed = Some(HTMAXBUTTON),
|
||||
HTCLOSE => self.state.borrow_mut().nc_button_pressed = Some(HTCLOSE),
|
||||
HTMINBUTTON => self.state.nc_button_pressed.set(Some(HTMINBUTTON)),
|
||||
HTMAXBUTTON => self.state.nc_button_pressed.set(Some(HTMAXBUTTON)),
|
||||
HTCLOSE => self.state.nc_button_pressed.set(Some(HTCLOSE)),
|
||||
_ => return None,
|
||||
};
|
||||
Some(0)
|
||||
@@ -981,10 +961,8 @@ impl WindowsWindowInner {
|
||||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
) -> Option<isize> {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
if let Some(mut func) = lock.callbacks.input.take() {
|
||||
let scale_factor = lock.scale_factor;
|
||||
drop(lock);
|
||||
if let Some(mut func) = self.state.callbacks.input.take() {
|
||||
let scale_factor = self.state.scale_factor.get();
|
||||
|
||||
let mut cursor_point = POINT {
|
||||
x: lparam.signed_loword().into(),
|
||||
@@ -998,16 +976,15 @@ impl WindowsWindowInner {
|
||||
click_count: 1,
|
||||
});
|
||||
let handled = !func(input).propagate;
|
||||
self.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
|
||||
if handled {
|
||||
return Some(0);
|
||||
}
|
||||
} else {
|
||||
drop(lock);
|
||||
}
|
||||
|
||||
let last_pressed = self.state.borrow_mut().nc_button_pressed.take();
|
||||
let last_pressed = self.state.nc_button_pressed.take();
|
||||
if button == MouseButton::Left
|
||||
&& let Some(last_pressed) = last_pressed
|
||||
{
|
||||
@@ -1017,7 +994,7 @@ impl WindowsWindowInner {
|
||||
true
|
||||
}
|
||||
(HTMAXBUTTON, HTMAXBUTTON) => {
|
||||
if self.state.borrow().is_maximized() {
|
||||
if self.state.is_maximized() {
|
||||
unsafe { ShowWindowAsync(handle, SW_NORMAL).ok().log_err() };
|
||||
} else {
|
||||
unsafe { ShowWindowAsync(handle, SW_MAXIMIZE).ok().log_err() };
|
||||
@@ -1042,17 +1019,16 @@ impl WindowsWindowInner {
|
||||
}
|
||||
|
||||
fn handle_cursor_changed(&self, lparam: LPARAM) -> Option<isize> {
|
||||
let mut state = self.state.borrow_mut();
|
||||
let had_cursor = state.current_cursor.is_some();
|
||||
let had_cursor = self.state.current_cursor.get().is_some();
|
||||
|
||||
state.current_cursor = if lparam.0 == 0 {
|
||||
self.state.current_cursor.set(if lparam.0 == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(HCURSOR(lparam.0 as _))
|
||||
};
|
||||
});
|
||||
|
||||
if had_cursor != state.current_cursor.is_some() {
|
||||
unsafe { SetCursor(state.current_cursor) };
|
||||
if had_cursor != self.state.current_cursor.get().is_some() {
|
||||
unsafe { SetCursor(self.state.current_cursor.get()) };
|
||||
}
|
||||
|
||||
Some(0)
|
||||
@@ -1075,7 +1051,7 @@ impl WindowsWindowInner {
|
||||
return None;
|
||||
}
|
||||
unsafe {
|
||||
SetCursor(self.state.borrow().current_cursor);
|
||||
SetCursor(self.state.current_cursor.get());
|
||||
};
|
||||
Some(0)
|
||||
}
|
||||
@@ -1087,13 +1063,12 @@ impl WindowsWindowInner {
|
||||
lparam: LPARAM,
|
||||
) -> Option<isize> {
|
||||
if wparam.0 != 0 {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let display = lock.display;
|
||||
lock.click_state.system_update(wparam.0);
|
||||
lock.border_offset.update(handle).log_err();
|
||||
// system settings may emit a window message which wants to take the refcell lock, so drop it
|
||||
drop(lock);
|
||||
self.system_settings_mut().update(display, wparam.0);
|
||||
let display = self.state.display.get();
|
||||
self.state.click_state.system_update(wparam.0);
|
||||
self.state.border_offset.update(handle).log_err();
|
||||
// system settings may emit a window message which wants to take the refcell self.state, so drop it
|
||||
|
||||
self.system_settings().update(display, wparam.0);
|
||||
} else {
|
||||
self.handle_system_theme_changed(handle, lparam)?;
|
||||
};
|
||||
@@ -1116,13 +1091,13 @@ impl WindowsWindowInner {
|
||||
let new_appearance = system_appearance()
|
||||
.context("unable to get system appearance when handling ImmersiveColorSet")
|
||||
.log_err()?;
|
||||
let mut lock = self.state.borrow_mut();
|
||||
if new_appearance != lock.appearance {
|
||||
lock.appearance = new_appearance;
|
||||
let mut callback = lock.callbacks.appearance_changed.take()?;
|
||||
drop(lock);
|
||||
|
||||
if new_appearance != self.state.appearance.get() {
|
||||
self.state.appearance.set(new_appearance);
|
||||
let mut callback = self.state.callbacks.appearance_changed.take()?;
|
||||
|
||||
callback();
|
||||
self.state.borrow_mut().callbacks.appearance_changed = Some(callback);
|
||||
self.state.callbacks.appearance_changed.set(Some(callback));
|
||||
configure_dwm_dark_mode(handle, new_appearance);
|
||||
}
|
||||
}
|
||||
@@ -1151,10 +1126,14 @@ impl WindowsWindowInner {
|
||||
}
|
||||
|
||||
fn handle_device_lost(&self, lparam: LPARAM) -> Option<isize> {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let devices = lparam.0 as *const DirectXDevices;
|
||||
let devices = unsafe { &*devices };
|
||||
if let Err(err) = lock.renderer.handle_device_lost(&devices) {
|
||||
if let Err(err) = self
|
||||
.state
|
||||
.renderer
|
||||
.borrow_mut()
|
||||
.handle_device_lost(&devices)
|
||||
{
|
||||
panic!("Device lost: {err}");
|
||||
}
|
||||
Some(0)
|
||||
@@ -1162,18 +1141,18 @@ impl WindowsWindowInner {
|
||||
|
||||
#[inline]
|
||||
fn draw_window(&self, handle: HWND, force_render: bool) -> Option<isize> {
|
||||
let mut request_frame = self.state.borrow_mut().callbacks.request_frame.take()?;
|
||||
let mut request_frame = self.state.callbacks.request_frame.take()?;
|
||||
|
||||
// we are instructing gpui to force render a frame, this will
|
||||
// re-populate all the gpu textures for us so we can resume drawing in
|
||||
// case we disabled drawing earlier due to a device loss
|
||||
self.state.borrow_mut().renderer.mark_drawable();
|
||||
self.state.renderer.borrow_mut().mark_drawable();
|
||||
request_frame(RequestFrameOptions {
|
||||
require_presentation: false,
|
||||
force_render,
|
||||
});
|
||||
|
||||
self.state.borrow_mut().callbacks.request_frame = Some(request_frame);
|
||||
self.state.callbacks.request_frame.set(Some(request_frame));
|
||||
unsafe { ValidateRect(Some(handle), None).ok().log_err() };
|
||||
|
||||
Some(0)
|
||||
@@ -1182,16 +1161,16 @@ impl WindowsWindowInner {
|
||||
#[inline]
|
||||
fn parse_char_message(&self, wparam: WPARAM) -> Option<String> {
|
||||
let code_point = wparam.loword();
|
||||
let mut lock = self.state.borrow_mut();
|
||||
|
||||
// https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G2630
|
||||
match code_point {
|
||||
0xD800..=0xDBFF => {
|
||||
// High surrogate, wait for low surrogate
|
||||
lock.pending_surrogate = Some(code_point);
|
||||
self.state.pending_surrogate.set(Some(code_point));
|
||||
None
|
||||
}
|
||||
0xDC00..=0xDFFF => {
|
||||
if let Some(high_surrogate) = lock.pending_surrogate.take() {
|
||||
if let Some(high_surrogate) = self.state.pending_surrogate.take() {
|
||||
// Low surrogate, combine with pending high surrogate
|
||||
String::from_utf16(&[high_surrogate, code_point]).ok()
|
||||
} else {
|
||||
@@ -1203,7 +1182,7 @@ impl WindowsWindowInner {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
lock.pending_surrogate = None;
|
||||
self.state.pending_surrogate.set(None);
|
||||
char::from_u32(code_point as u32)
|
||||
.filter(|c| !c.is_control())
|
||||
.map(|c| c.to_string())
|
||||
@@ -1212,9 +1191,8 @@ impl WindowsWindowInner {
|
||||
}
|
||||
|
||||
fn start_tracking_mouse(&self, handle: HWND, flags: TRACKMOUSEEVENT_FLAGS) {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
if !lock.hovered {
|
||||
lock.hovered = true;
|
||||
if !self.state.hovered.get() {
|
||||
self.state.hovered.set(true);
|
||||
unsafe {
|
||||
TrackMouseEvent(&mut TRACKMOUSEEVENT {
|
||||
cbSize: std::mem::size_of::<TRACKMOUSEEVENT>() as u32,
|
||||
@@ -1224,10 +1202,12 @@ impl WindowsWindowInner {
|
||||
})
|
||||
.log_err()
|
||||
};
|
||||
if let Some(mut callback) = lock.callbacks.hovered_status_change.take() {
|
||||
drop(lock);
|
||||
if let Some(mut callback) = self.state.callbacks.hovered_status_change.take() {
|
||||
callback(true);
|
||||
self.state.borrow_mut().callbacks.hovered_status_change = Some(callback);
|
||||
self.state
|
||||
.callbacks
|
||||
.hovered_status_change
|
||||
.set(Some(callback));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1236,9 +1216,9 @@ impl WindowsWindowInner {
|
||||
where
|
||||
F: FnOnce(&mut PlatformInputHandler) -> R,
|
||||
{
|
||||
let mut input_handler = self.state.borrow_mut().input_handler.take()?;
|
||||
let mut input_handler = self.state.input_handler.take()?;
|
||||
let result = f(&mut input_handler);
|
||||
self.state.borrow_mut().input_handler = Some(input_handler);
|
||||
self.state.input_handler.set(Some(input_handler));
|
||||
Some(result)
|
||||
}
|
||||
|
||||
@@ -1246,12 +1226,11 @@ impl WindowsWindowInner {
|
||||
where
|
||||
F: FnOnce(&mut PlatformInputHandler, f32) -> Option<R>,
|
||||
{
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let mut input_handler = lock.input_handler.take()?;
|
||||
let scale_factor = lock.scale_factor;
|
||||
drop(lock);
|
||||
let mut input_handler = self.state.input_handler.take()?;
|
||||
let scale_factor = self.state.scale_factor.get();
|
||||
|
||||
let result = f(&mut input_handler, scale_factor);
|
||||
self.state.borrow_mut().input_handler = Some(input_handler);
|
||||
self.state.input_handler.set(Some(input_handler));
|
||||
result
|
||||
}
|
||||
}
|
||||
@@ -1259,7 +1238,7 @@ impl WindowsWindowInner {
|
||||
fn handle_key_event<F>(
|
||||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
state: &mut WindowsWindowState,
|
||||
state: &WindowsWindowState,
|
||||
f: F,
|
||||
) -> Option<PlatformInput>
|
||||
where
|
||||
@@ -1272,11 +1251,12 @@ where
|
||||
VK_SHIFT | VK_CONTROL | VK_MENU | VK_LMENU | VK_RMENU | VK_LWIN | VK_RWIN => {
|
||||
if state
|
||||
.last_reported_modifiers
|
||||
.get()
|
||||
.is_some_and(|prev_modifiers| prev_modifiers == modifiers)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
state.last_reported_modifiers = Some(modifiers);
|
||||
state.last_reported_modifiers.set(Some(modifiers));
|
||||
Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent {
|
||||
modifiers,
|
||||
capslock: current_capslock(),
|
||||
@@ -1287,11 +1267,12 @@ where
|
||||
let capslock = current_capslock();
|
||||
if state
|
||||
.last_reported_capslock
|
||||
.get()
|
||||
.is_some_and(|prev_capslock| prev_capslock == capslock)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
state.last_reported_capslock = Some(capslock);
|
||||
state.last_reported_capslock.set(Some(capslock));
|
||||
Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent {
|
||||
modifiers,
|
||||
capslock,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
cell::{Cell, RefCell},
|
||||
ffi::OsStr,
|
||||
path::{Path, PathBuf},
|
||||
rc::{Rc, Weak},
|
||||
@@ -47,7 +47,7 @@ pub(crate) struct WindowsPlatform {
|
||||
}
|
||||
|
||||
struct WindowsPlatformInner {
|
||||
state: RefCell<WindowsPlatformState>,
|
||||
state: WindowsPlatformState,
|
||||
raw_window_handles: std::sync::Weak<RwLock<SmallVec<[SafeHwnd; 4]>>>,
|
||||
// The below members will never change throughout the entire lifecycle of the app.
|
||||
validation_number: usize,
|
||||
@@ -57,22 +57,22 @@ struct WindowsPlatformInner {
|
||||
|
||||
pub(crate) struct WindowsPlatformState {
|
||||
callbacks: PlatformCallbacks,
|
||||
menus: Vec<OwnedMenu>,
|
||||
jump_list: JumpList,
|
||||
menus: RefCell<Vec<OwnedMenu>>,
|
||||
jump_list: RefCell<JumpList>,
|
||||
// NOTE: standard cursor handles don't need to close.
|
||||
pub(crate) current_cursor: Option<HCURSOR>,
|
||||
directx_devices: Option<DirectXDevices>,
|
||||
pub(crate) current_cursor: Cell<Option<HCURSOR>>,
|
||||
directx_devices: RefCell<Option<DirectXDevices>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct PlatformCallbacks {
|
||||
open_urls: Option<Box<dyn FnMut(Vec<String>)>>,
|
||||
quit: Option<Box<dyn FnMut()>>,
|
||||
reopen: Option<Box<dyn FnMut()>>,
|
||||
app_menu_action: Option<Box<dyn FnMut(&dyn Action)>>,
|
||||
will_open_app_menu: Option<Box<dyn FnMut()>>,
|
||||
validate_app_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>,
|
||||
keyboard_layout_change: Option<Box<dyn FnMut()>>,
|
||||
open_urls: Cell<Option<Box<dyn FnMut(Vec<String>)>>>,
|
||||
quit: Cell<Option<Box<dyn FnMut()>>>,
|
||||
reopen: Cell<Option<Box<dyn FnMut()>>>,
|
||||
app_menu_action: Cell<Option<Box<dyn FnMut(&dyn Action)>>>,
|
||||
will_open_app_menu: Cell<Option<Box<dyn FnMut()>>>,
|
||||
validate_app_menu_command: Cell<Option<Box<dyn FnMut(&dyn Action) -> bool>>>,
|
||||
keyboard_layout_change: Cell<Option<Box<dyn FnMut()>>>,
|
||||
}
|
||||
|
||||
impl WindowsPlatformState {
|
||||
@@ -84,10 +84,10 @@ impl WindowsPlatformState {
|
||||
|
||||
Self {
|
||||
callbacks,
|
||||
jump_list,
|
||||
current_cursor,
|
||||
directx_devices,
|
||||
menus: Vec::new(),
|
||||
jump_list: RefCell::new(jump_list),
|
||||
current_cursor: Cell::new(current_cursor),
|
||||
directx_devices: RefCell::new(directx_devices),
|
||||
menus: RefCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,14 +194,14 @@ impl WindowsPlatform {
|
||||
WindowCreationInfo {
|
||||
icon: self.icon,
|
||||
executor: self.foreground_executor.clone(),
|
||||
current_cursor: self.inner.state.borrow().current_cursor,
|
||||
current_cursor: self.inner.state.current_cursor.get(),
|
||||
windows_version: self.windows_version,
|
||||
drop_target_helper: self.drop_target_helper.clone(),
|
||||
validation_number: self.inner.validation_number,
|
||||
main_receiver: self.inner.main_receiver.clone(),
|
||||
platform_window_handle: self.handle,
|
||||
disable_direct_composition: self.disable_direct_composition,
|
||||
directx_devices: self.inner.state.borrow().directx_devices.clone().unwrap(),
|
||||
directx_devices: self.inner.state.directx_devices.borrow().clone().unwrap(),
|
||||
invalidate_devices: self.invalidate_devices.clone(),
|
||||
}
|
||||
}
|
||||
@@ -213,9 +213,8 @@ impl WindowsPlatform {
|
||||
actions.push(dock_menu);
|
||||
}
|
||||
});
|
||||
let mut lock = self.inner.state.borrow_mut();
|
||||
lock.jump_list.dock_menus = actions;
|
||||
update_jump_list(&lock.jump_list).log_err();
|
||||
self.inner.state.jump_list.borrow_mut().dock_menus = actions;
|
||||
update_jump_list(&self.inner.state.jump_list.borrow()).log_err();
|
||||
}
|
||||
|
||||
fn update_jump_list(
|
||||
@@ -229,12 +228,10 @@ impl WindowsPlatform {
|
||||
actions.push(dock_menu);
|
||||
}
|
||||
});
|
||||
let mut lock = self.inner.state.borrow_mut();
|
||||
lock.jump_list.dock_menus = actions;
|
||||
lock.jump_list.recent_workspaces = entries;
|
||||
update_jump_list(&lock.jump_list)
|
||||
.log_err()
|
||||
.unwrap_or_default()
|
||||
let mut jump_list = self.inner.state.jump_list.borrow_mut();
|
||||
jump_list.dock_menus = actions;
|
||||
jump_list.recent_workspaces = entries;
|
||||
update_jump_list(&jump_list).log_err().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn find_current_active_window(&self) -> Option<HWND> {
|
||||
@@ -250,7 +247,7 @@ impl WindowsPlatform {
|
||||
}
|
||||
|
||||
fn begin_vsync_thread(&self) {
|
||||
let mut directx_device = self.inner.state.borrow().directx_devices.clone().unwrap();
|
||||
let mut directx_device = self.inner.state.directx_devices.borrow().clone().unwrap();
|
||||
let platform_window: SafeHwnd = self.handle.into();
|
||||
let validation_number = self.inner.validation_number;
|
||||
let all_windows = Arc::downgrade(&self.raw_window_handles);
|
||||
@@ -334,9 +331,9 @@ impl Platform for WindowsPlatform {
|
||||
fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>) {
|
||||
self.inner
|
||||
.state
|
||||
.borrow_mut()
|
||||
.callbacks
|
||||
.keyboard_layout_change = Some(callback);
|
||||
.keyboard_layout_change
|
||||
.set(Some(callback));
|
||||
}
|
||||
|
||||
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {
|
||||
@@ -354,7 +351,7 @@ impl Platform for WindowsPlatform {
|
||||
}
|
||||
|
||||
self.inner
|
||||
.with_callback(|callbacks| &mut callbacks.quit, |callback| callback());
|
||||
.with_callback(|callbacks| &callbacks.quit, |callback| callback());
|
||||
}
|
||||
|
||||
fn quit(&self) {
|
||||
@@ -473,7 +470,7 @@ impl Platform for WindowsPlatform {
|
||||
}
|
||||
|
||||
fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>) {
|
||||
self.inner.state.borrow_mut().callbacks.open_urls = Some(callback);
|
||||
self.inner.state.callbacks.open_urls.set(Some(callback));
|
||||
}
|
||||
|
||||
fn prompt_for_paths(
|
||||
@@ -543,19 +540,19 @@ impl Platform for WindowsPlatform {
|
||||
}
|
||||
|
||||
fn on_quit(&self, callback: Box<dyn FnMut()>) {
|
||||
self.inner.state.borrow_mut().callbacks.quit = Some(callback);
|
||||
self.inner.state.callbacks.quit.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_reopen(&self, callback: Box<dyn FnMut()>) {
|
||||
self.inner.state.borrow_mut().callbacks.reopen = Some(callback);
|
||||
self.inner.state.callbacks.reopen.set(Some(callback));
|
||||
}
|
||||
|
||||
fn set_menus(&self, menus: Vec<Menu>, _keymap: &Keymap) {
|
||||
self.inner.state.borrow_mut().menus = menus.into_iter().map(|menu| menu.owned()).collect();
|
||||
*self.inner.state.menus.borrow_mut() = menus.into_iter().map(|menu| menu.owned()).collect();
|
||||
}
|
||||
|
||||
fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
|
||||
Some(self.inner.state.borrow().menus.clone())
|
||||
Some(self.inner.state.menus.borrow().clone())
|
||||
}
|
||||
|
||||
fn set_dock_menu(&self, menus: Vec<MenuItem>, _keymap: &Keymap) {
|
||||
@@ -563,19 +560,27 @@ impl Platform for WindowsPlatform {
|
||||
}
|
||||
|
||||
fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>) {
|
||||
self.inner.state.borrow_mut().callbacks.app_menu_action = Some(callback);
|
||||
self.inner
|
||||
.state
|
||||
.callbacks
|
||||
.app_menu_action
|
||||
.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>) {
|
||||
self.inner.state.borrow_mut().callbacks.will_open_app_menu = Some(callback);
|
||||
self.inner
|
||||
.state
|
||||
.callbacks
|
||||
.will_open_app_menu
|
||||
.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_validate_app_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>) {
|
||||
self.inner
|
||||
.state
|
||||
.borrow_mut()
|
||||
.callbacks
|
||||
.validate_app_menu_command = Some(callback);
|
||||
.validate_app_menu_command
|
||||
.set(Some(callback));
|
||||
}
|
||||
|
||||
fn app_path(&self) -> Result<PathBuf> {
|
||||
@@ -589,13 +594,13 @@ impl Platform for WindowsPlatform {
|
||||
|
||||
fn set_cursor_style(&self, style: CursorStyle) {
|
||||
let hcursor = load_cursor(style);
|
||||
if self.inner.state.borrow_mut().current_cursor.map(|c| c.0) != hcursor.map(|c| c.0) {
|
||||
if self.inner.state.current_cursor.get().map(|c| c.0) != hcursor.map(|c| c.0) {
|
||||
self.post_message(
|
||||
WM_GPUI_CURSOR_STYLE_CHANGED,
|
||||
WPARAM(0),
|
||||
LPARAM(hcursor.map_or(0, |c| c.0 as isize)),
|
||||
);
|
||||
self.inner.state.borrow_mut().current_cursor = hcursor;
|
||||
self.inner.state.current_cursor.set(hcursor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,12 +726,12 @@ impl Platform for WindowsPlatform {
|
||||
|
||||
impl WindowsPlatformInner {
|
||||
fn new(context: &mut PlatformWindowCreateContext) -> Result<Rc<Self>> {
|
||||
let state = RefCell::new(WindowsPlatformState::new(
|
||||
let state = WindowsPlatformState::new(
|
||||
context
|
||||
.directx_devices
|
||||
.take()
|
||||
.context("missing directx devices")?,
|
||||
));
|
||||
);
|
||||
Ok(Rc::new(Self {
|
||||
state,
|
||||
raw_window_handles: context.raw_window_handles.clone(),
|
||||
@@ -746,13 +751,13 @@ impl WindowsPlatformInner {
|
||||
/// Calls `project` to project to the corresponding callback field, removes it from callbacks, calls `f` with the callback and then puts the callback back.
|
||||
fn with_callback<T>(
|
||||
&self,
|
||||
project: impl Fn(&mut PlatformCallbacks) -> &mut Option<T>,
|
||||
project: impl Fn(&PlatformCallbacks) -> &Cell<Option<T>>,
|
||||
f: impl FnOnce(&mut T),
|
||||
) {
|
||||
let callback = project(&mut self.state.borrow_mut().callbacks).take();
|
||||
let callback = project(&self.state.callbacks).take();
|
||||
if let Some(mut callback) = callback {
|
||||
f(&mut callback);
|
||||
*project(&mut self.state.borrow_mut().callbacks) = Some(callback)
|
||||
project(&self.state.callbacks).set(Some(callback));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -877,8 +882,8 @@ impl WindowsPlatformInner {
|
||||
fn handle_dock_action_event(&self, action_idx: usize) -> Option<isize> {
|
||||
let Some(action) = self
|
||||
.state
|
||||
.borrow_mut()
|
||||
.jump_list
|
||||
.borrow()
|
||||
.dock_menus
|
||||
.get(action_idx)
|
||||
.map(|dock_menu| dock_menu.action.boxed_clone())
|
||||
@@ -887,7 +892,7 @@ impl WindowsPlatformInner {
|
||||
return Some(1);
|
||||
};
|
||||
self.with_callback(
|
||||
|callbacks| &mut callbacks.app_menu_action,
|
||||
|callbacks| &callbacks.app_menu_action,
|
||||
|callback| callback(&*action),
|
||||
);
|
||||
Some(0)
|
||||
@@ -895,7 +900,7 @@ impl WindowsPlatformInner {
|
||||
|
||||
fn handle_keyboard_layout_change(&self) -> Option<isize> {
|
||||
self.with_callback(
|
||||
|callbacks| &mut callbacks.keyboard_layout_change,
|
||||
|callbacks| &callbacks.keyboard_layout_change,
|
||||
|callback| callback(),
|
||||
);
|
||||
Some(0)
|
||||
@@ -904,9 +909,8 @@ impl WindowsPlatformInner {
|
||||
fn handle_device_lost(&self, lparam: LPARAM) -> Option<isize> {
|
||||
let directx_devices = lparam.0 as *const DirectXDevices;
|
||||
let directx_devices = unsafe { &*directx_devices };
|
||||
let mut lock = self.state.borrow_mut();
|
||||
lock.directx_devices.take();
|
||||
lock.directx_devices = Some(directx_devices.clone());
|
||||
self.state.directx_devices.borrow_mut().take();
|
||||
*self.state.directx_devices.borrow_mut() = Some(directx_devices.clone());
|
||||
|
||||
Some(0)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use std::ffi::{c_uint, c_void};
|
||||
use std::{
|
||||
cell::Cell,
|
||||
ffi::{c_uint, c_void},
|
||||
};
|
||||
|
||||
use ::util::ResultExt;
|
||||
use windows::Win32::UI::{
|
||||
@@ -15,18 +18,18 @@ use super::WindowsDisplay;
|
||||
|
||||
/// Windows settings pulled from SystemParametersInfo
|
||||
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub(crate) struct WindowsSystemSettings {
|
||||
pub(crate) mouse_wheel_settings: MouseWheelSettings,
|
||||
pub(crate) auto_hide_taskbar_position: Option<AutoHideTaskbarPosition>,
|
||||
pub(crate) auto_hide_taskbar_position: Cell<Option<AutoHideTaskbarPosition>>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub(crate) struct MouseWheelSettings {
|
||||
/// SEE: SPI_GETWHEELSCROLLCHARS
|
||||
pub(crate) wheel_scroll_chars: u32,
|
||||
pub(crate) wheel_scroll_chars: Cell<u32>,
|
||||
/// SEE: SPI_GETWHEELSCROLLLINES
|
||||
pub(crate) wheel_scroll_lines: u32,
|
||||
pub(crate) wheel_scroll_lines: Cell<u32>,
|
||||
}
|
||||
|
||||
impl WindowsSystemSettings {
|
||||
@@ -36,12 +39,13 @@ impl WindowsSystemSettings {
|
||||
settings
|
||||
}
|
||||
|
||||
fn init(&mut self, display: WindowsDisplay) {
|
||||
fn init(&self, display: WindowsDisplay) {
|
||||
self.mouse_wheel_settings.update();
|
||||
self.auto_hide_taskbar_position = AutoHideTaskbarPosition::new(display).log_err().flatten();
|
||||
self.auto_hide_taskbar_position
|
||||
.set(AutoHideTaskbarPosition::new(display).log_err().flatten());
|
||||
}
|
||||
|
||||
pub(crate) fn update(&mut self, display: WindowsDisplay, wparam: usize) {
|
||||
pub(crate) fn update(&self, display: WindowsDisplay, wparam: usize) {
|
||||
match wparam {
|
||||
// SPI_SETWORKAREA
|
||||
47 => self.update_taskbar_position(display),
|
||||
@@ -51,22 +55,23 @@ impl WindowsSystemSettings {
|
||||
}
|
||||
}
|
||||
|
||||
fn update_mouse_wheel_settings(&mut self) {
|
||||
fn update_mouse_wheel_settings(&self) {
|
||||
self.mouse_wheel_settings.update();
|
||||
}
|
||||
|
||||
fn update_taskbar_position(&mut self, display: WindowsDisplay) {
|
||||
self.auto_hide_taskbar_position = AutoHideTaskbarPosition::new(display).log_err().flatten();
|
||||
fn update_taskbar_position(&self, display: WindowsDisplay) {
|
||||
self.auto_hide_taskbar_position
|
||||
.set(AutoHideTaskbarPosition::new(display).log_err().flatten());
|
||||
}
|
||||
}
|
||||
|
||||
impl MouseWheelSettings {
|
||||
fn update(&mut self) {
|
||||
fn update(&self) {
|
||||
self.update_wheel_scroll_chars();
|
||||
self.update_wheel_scroll_lines();
|
||||
}
|
||||
|
||||
fn update_wheel_scroll_chars(&mut self) {
|
||||
fn update_wheel_scroll_chars(&self) {
|
||||
let mut value = c_uint::default();
|
||||
let result = unsafe {
|
||||
SystemParametersInfoW(
|
||||
@@ -77,12 +82,12 @@ impl MouseWheelSettings {
|
||||
)
|
||||
};
|
||||
|
||||
if result.log_err() != None && self.wheel_scroll_chars != value {
|
||||
self.wheel_scroll_chars = value;
|
||||
if result.log_err() != None && self.wheel_scroll_chars.get() != value {
|
||||
self.wheel_scroll_chars.set(value);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_wheel_scroll_lines(&mut self) {
|
||||
fn update_wheel_scroll_lines(&self) {
|
||||
let mut value = c_uint::default();
|
||||
let result = unsafe {
|
||||
SystemParametersInfoW(
|
||||
@@ -93,8 +98,8 @@ impl MouseWheelSettings {
|
||||
)
|
||||
};
|
||||
|
||||
if result.log_err() != None && self.wheel_scroll_lines != value {
|
||||
self.wheel_scroll_lines = value;
|
||||
if result.log_err() != None && self.wheel_scroll_lines.get() != value {
|
||||
self.wheel_scroll_lines.set(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
cell::{Cell, RefCell},
|
||||
num::NonZeroIsize,
|
||||
path::PathBuf,
|
||||
rc::{Rc, Weak},
|
||||
@@ -30,43 +30,51 @@ use crate::*;
|
||||
|
||||
pub(crate) struct WindowsWindow(pub Rc<WindowsWindowInner>);
|
||||
|
||||
impl std::ops::Deref for WindowsWindow {
|
||||
type Target = WindowsWindowInner;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WindowsWindowState {
|
||||
pub origin: Point<Pixels>,
|
||||
pub logical_size: Size<Pixels>,
|
||||
pub origin: Cell<Point<Pixels>>,
|
||||
pub logical_size: Cell<Size<Pixels>>,
|
||||
pub min_size: Option<Size<Pixels>>,
|
||||
pub fullscreen_restore_bounds: Bounds<Pixels>,
|
||||
pub fullscreen_restore_bounds: Cell<Bounds<Pixels>>,
|
||||
pub border_offset: WindowBorderOffset,
|
||||
pub appearance: WindowAppearance,
|
||||
pub scale_factor: f32,
|
||||
pub restore_from_minimized: Option<Box<dyn FnMut(RequestFrameOptions)>>,
|
||||
pub appearance: Cell<WindowAppearance>,
|
||||
pub scale_factor: Cell<f32>,
|
||||
pub restore_from_minimized: Cell<Option<Box<dyn FnMut(RequestFrameOptions)>>>,
|
||||
|
||||
pub callbacks: Callbacks,
|
||||
pub input_handler: Option<PlatformInputHandler>,
|
||||
pub pending_surrogate: Option<u16>,
|
||||
pub last_reported_modifiers: Option<Modifiers>,
|
||||
pub last_reported_capslock: Option<Capslock>,
|
||||
pub hovered: bool,
|
||||
pub input_handler: Cell<Option<PlatformInputHandler>>,
|
||||
pub pending_surrogate: Cell<Option<u16>>,
|
||||
pub last_reported_modifiers: Cell<Option<Modifiers>>,
|
||||
pub last_reported_capslock: Cell<Option<Capslock>>,
|
||||
pub hovered: Cell<bool>,
|
||||
|
||||
pub renderer: DirectXRenderer,
|
||||
pub renderer: RefCell<DirectXRenderer>,
|
||||
|
||||
pub click_state: ClickState,
|
||||
pub current_cursor: Option<HCURSOR>,
|
||||
pub nc_button_pressed: Option<u32>,
|
||||
pub current_cursor: Cell<Option<HCURSOR>>,
|
||||
pub nc_button_pressed: Cell<Option<u32>>,
|
||||
|
||||
pub display: WindowsDisplay,
|
||||
pub display: Cell<WindowsDisplay>,
|
||||
/// Flag to instruct the `VSyncProvider` thread to invalidate the directx devices
|
||||
/// as resizing them has failed, causing us to have lost at least the render target.
|
||||
pub invalidate_devices: Arc<AtomicBool>,
|
||||
fullscreen: Option<StyleAndBounds>,
|
||||
initial_placement: Option<WindowOpenStatus>,
|
||||
fullscreen: Cell<Option<StyleAndBounds>>,
|
||||
initial_placement: Cell<Option<WindowOpenStatus>>,
|
||||
hwnd: HWND,
|
||||
}
|
||||
|
||||
pub(crate) struct WindowsWindowInner {
|
||||
hwnd: HWND,
|
||||
drop_target_helper: IDropTargetHelper,
|
||||
pub(crate) state: RefCell<WindowsWindowState>,
|
||||
system_settings: RefCell<WindowsSystemSettings>,
|
||||
pub(crate) state: WindowsWindowState,
|
||||
system_settings: WindowsSystemSettings,
|
||||
pub(crate) handle: AnyWindowHandle,
|
||||
pub(crate) hide_title_bar: bool,
|
||||
pub(crate) is_movable: bool,
|
||||
@@ -121,27 +129,27 @@ impl WindowsWindowState {
|
||||
let initial_placement = None;
|
||||
|
||||
Ok(Self {
|
||||
origin,
|
||||
logical_size,
|
||||
fullscreen_restore_bounds,
|
||||
origin: Cell::new(origin),
|
||||
logical_size: Cell::new(logical_size),
|
||||
fullscreen_restore_bounds: Cell::new(fullscreen_restore_bounds),
|
||||
border_offset,
|
||||
appearance,
|
||||
scale_factor,
|
||||
restore_from_minimized,
|
||||
appearance: Cell::new(appearance),
|
||||
scale_factor: Cell::new(scale_factor),
|
||||
restore_from_minimized: Cell::new(restore_from_minimized),
|
||||
min_size,
|
||||
callbacks,
|
||||
input_handler,
|
||||
pending_surrogate,
|
||||
last_reported_modifiers,
|
||||
last_reported_capslock,
|
||||
hovered,
|
||||
renderer,
|
||||
input_handler: Cell::new(input_handler),
|
||||
pending_surrogate: Cell::new(pending_surrogate),
|
||||
last_reported_modifiers: Cell::new(last_reported_modifiers),
|
||||
last_reported_capslock: Cell::new(last_reported_capslock),
|
||||
hovered: Cell::new(hovered),
|
||||
renderer: RefCell::new(renderer),
|
||||
click_state,
|
||||
current_cursor,
|
||||
nc_button_pressed,
|
||||
display,
|
||||
fullscreen,
|
||||
initial_placement,
|
||||
current_cursor: Cell::new(current_cursor),
|
||||
nc_button_pressed: Cell::new(nc_button_pressed),
|
||||
display: Cell::new(display),
|
||||
fullscreen: Cell::new(fullscreen),
|
||||
initial_placement: Cell::new(initial_placement),
|
||||
hwnd,
|
||||
invalidate_devices,
|
||||
})
|
||||
@@ -149,7 +157,7 @@ impl WindowsWindowState {
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn is_fullscreen(&self) -> bool {
|
||||
self.fullscreen.is_some()
|
||||
self.fullscreen.get().is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn is_maximized(&self) -> bool {
|
||||
@@ -158,8 +166,8 @@ impl WindowsWindowState {
|
||||
|
||||
fn bounds(&self) -> Bounds<Pixels> {
|
||||
Bounds {
|
||||
origin: self.origin,
|
||||
size: self.logical_size,
|
||||
origin: self.origin.get(),
|
||||
size: self.logical_size.get(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,8 +186,8 @@ impl WindowsWindowState {
|
||||
(
|
||||
calculate_client_rect(
|
||||
placement.rcNormalPosition,
|
||||
self.border_offset,
|
||||
self.scale_factor,
|
||||
&self.border_offset,
|
||||
self.scale_factor.get(),
|
||||
),
|
||||
placement.showCmd == SW_SHOWMAXIMIZED.0 as u32,
|
||||
)
|
||||
@@ -189,7 +197,7 @@ impl WindowsWindowState {
|
||||
let (bounds, maximized) = self.calculate_window_bounds();
|
||||
|
||||
if self.is_fullscreen() {
|
||||
WindowBounds::Fullscreen(self.fullscreen_restore_bounds)
|
||||
WindowBounds::Fullscreen(self.fullscreen_restore_bounds.get())
|
||||
} else if maximized {
|
||||
WindowBounds::Maximized(bounds)
|
||||
} else {
|
||||
@@ -202,13 +210,13 @@ impl WindowsWindowState {
|
||||
/// Currently, GPUI uses the logical size of the app to handle mouse interactions (such as
|
||||
/// whether the mouse collides with other elements of GPUI).
|
||||
fn content_size(&self) -> Size<Pixels> {
|
||||
self.logical_size
|
||||
self.logical_size.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowsWindowInner {
|
||||
fn new(context: &mut WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Result<Rc<Self>> {
|
||||
let state = RefCell::new(WindowsWindowState::new(
|
||||
let state = WindowsWindowState::new(
|
||||
hwnd,
|
||||
&context.directx_devices,
|
||||
cs,
|
||||
@@ -218,7 +226,7 @@ impl WindowsWindowInner {
|
||||
context.appearance,
|
||||
context.disable_direct_composition,
|
||||
context.invalidate_devices.clone(),
|
||||
)?);
|
||||
)?;
|
||||
|
||||
Ok(Rc::new(Self {
|
||||
hwnd,
|
||||
@@ -232,7 +240,7 @@ impl WindowsWindowInner {
|
||||
validation_number: context.validation_number,
|
||||
main_receiver: context.main_receiver.clone(),
|
||||
platform_window_handle: context.platform_window_handle,
|
||||
system_settings: RefCell::new(WindowsSystemSettings::new(context.display)),
|
||||
system_settings: WindowsSystemSettings::new(context.display),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -240,19 +248,17 @@ impl WindowsWindowInner {
|
||||
let this = self.clone();
|
||||
self.executor
|
||||
.spawn(async move {
|
||||
let mut lock = this.state.borrow_mut();
|
||||
let StyleAndBounds {
|
||||
style,
|
||||
x,
|
||||
y,
|
||||
cx,
|
||||
cy,
|
||||
} = match lock.fullscreen.take() {
|
||||
} = match this.state.fullscreen.take() {
|
||||
Some(state) => state,
|
||||
None => {
|
||||
let (window_bounds, _) = lock.calculate_window_bounds();
|
||||
lock.fullscreen_restore_bounds = window_bounds;
|
||||
drop(lock);
|
||||
let (window_bounds, _) = this.state.calculate_window_bounds();
|
||||
this.state.fullscreen_restore_bounds.set(window_bounds);
|
||||
|
||||
let style =
|
||||
WINDOW_STYLE(unsafe { get_window_long(this.hwnd, GWL_STYLE) } as _);
|
||||
@@ -260,22 +266,20 @@ impl WindowsWindowInner {
|
||||
unsafe { GetWindowRect(this.hwnd, &mut rc) }
|
||||
.context("failed to get window rect")
|
||||
.log_err();
|
||||
|
||||
lock = this.state.borrow_mut();
|
||||
let _ = lock.fullscreen.insert(StyleAndBounds {
|
||||
let _ = this.state.fullscreen.set(Some(StyleAndBounds {
|
||||
style,
|
||||
x: rc.left,
|
||||
y: rc.top,
|
||||
cx: rc.right - rc.left,
|
||||
cy: rc.bottom - rc.top,
|
||||
});
|
||||
}));
|
||||
let style = style
|
||||
& !(WS_THICKFRAME
|
||||
| WS_SYSMENU
|
||||
| WS_MAXIMIZEBOX
|
||||
| WS_MINIMIZEBOX
|
||||
| WS_CAPTION);
|
||||
let physical_bounds = lock.display.physical_bounds();
|
||||
let physical_bounds = this.state.display.get().physical_bounds();
|
||||
StyleAndBounds {
|
||||
style,
|
||||
x: physical_bounds.left().0,
|
||||
@@ -285,7 +289,6 @@ impl WindowsWindowInner {
|
||||
}
|
||||
}
|
||||
};
|
||||
drop(lock);
|
||||
unsafe { set_window_long(this.hwnd, GWL_STYLE, style.0 as isize) };
|
||||
unsafe {
|
||||
SetWindowPos(
|
||||
@@ -304,7 +307,7 @@ impl WindowsWindowInner {
|
||||
}
|
||||
|
||||
fn set_window_placement(self: &Rc<Self>) -> Result<()> {
|
||||
let Some(open_status) = self.state.borrow_mut().initial_placement.take() else {
|
||||
let Some(open_status) = self.state.initial_placement.take() else {
|
||||
return Ok(());
|
||||
};
|
||||
match open_status.state {
|
||||
@@ -328,27 +331,23 @@ impl WindowsWindowInner {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn system_settings(&self) -> std::cell::Ref<'_, WindowsSystemSettings> {
|
||||
self.system_settings.borrow()
|
||||
}
|
||||
|
||||
pub(crate) fn system_settings_mut(&self) -> std::cell::RefMut<'_, WindowsSystemSettings> {
|
||||
self.system_settings.borrow_mut()
|
||||
pub(crate) fn system_settings(&self) -> &WindowsSystemSettings {
|
||||
&self.system_settings
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Callbacks {
|
||||
pub(crate) request_frame: Option<Box<dyn FnMut(RequestFrameOptions)>>,
|
||||
pub(crate) input: Option<Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>>,
|
||||
pub(crate) active_status_change: Option<Box<dyn FnMut(bool)>>,
|
||||
pub(crate) hovered_status_change: Option<Box<dyn FnMut(bool)>>,
|
||||
pub(crate) resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
|
||||
pub(crate) moved: Option<Box<dyn FnMut()>>,
|
||||
pub(crate) should_close: Option<Box<dyn FnMut() -> bool>>,
|
||||
pub(crate) close: Option<Box<dyn FnOnce()>>,
|
||||
pub(crate) hit_test_window_control: Option<Box<dyn FnMut() -> Option<WindowControlArea>>>,
|
||||
pub(crate) appearance_changed: Option<Box<dyn FnMut()>>,
|
||||
pub(crate) request_frame: Cell<Option<Box<dyn FnMut(RequestFrameOptions)>>>,
|
||||
pub(crate) input: Cell<Option<Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>>>,
|
||||
pub(crate) active_status_change: Cell<Option<Box<dyn FnMut(bool)>>>,
|
||||
pub(crate) hovered_status_change: Cell<Option<Box<dyn FnMut(bool)>>>,
|
||||
pub(crate) resize: Cell<Option<Box<dyn FnMut(Size<Pixels>, f32)>>>,
|
||||
pub(crate) moved: Cell<Option<Box<dyn FnMut()>>>,
|
||||
pub(crate) should_close: Cell<Option<Box<dyn FnMut() -> bool>>>,
|
||||
pub(crate) close: Cell<Option<Box<dyn FnOnce()>>>,
|
||||
pub(crate) hit_test_window_control: Cell<Option<Box<dyn FnMut() -> Option<WindowControlArea>>>>,
|
||||
pub(crate) appearance_changed: Cell<Option<Box<dyn FnMut()>>>,
|
||||
}
|
||||
|
||||
struct WindowCreateContext {
|
||||
@@ -476,21 +475,21 @@ impl WindowsWindow {
|
||||
|
||||
register_drag_drop(&this)?;
|
||||
configure_dwm_dark_mode(hwnd, appearance);
|
||||
this.state.borrow_mut().border_offset.update(hwnd)?;
|
||||
this.state.border_offset.update(hwnd)?;
|
||||
let placement = retrieve_window_placement(
|
||||
hwnd,
|
||||
display,
|
||||
params.bounds,
|
||||
this.state.borrow().scale_factor,
|
||||
this.state.borrow().border_offset,
|
||||
this.state.scale_factor.get(),
|
||||
&this.state.border_offset,
|
||||
)?;
|
||||
if params.show {
|
||||
unsafe { SetWindowPlacement(hwnd, &placement)? };
|
||||
} else {
|
||||
this.state.borrow_mut().initial_placement = Some(WindowOpenStatus {
|
||||
this.state.initial_placement.set(Some(WindowOpenStatus {
|
||||
placement,
|
||||
state: WindowOpenState::Windowed,
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(Self(this))
|
||||
@@ -533,15 +532,15 @@ impl Drop for WindowsWindow {
|
||||
|
||||
impl PlatformWindow for WindowsWindow {
|
||||
fn bounds(&self) -> Bounds<Pixels> {
|
||||
self.0.state.borrow().bounds()
|
||||
self.state.bounds()
|
||||
}
|
||||
|
||||
fn is_maximized(&self) -> bool {
|
||||
self.0.state.borrow().is_maximized()
|
||||
self.state.is_maximized()
|
||||
}
|
||||
|
||||
fn window_bounds(&self) -> WindowBounds {
|
||||
self.0.state.borrow().window_bounds()
|
||||
self.state.window_bounds()
|
||||
}
|
||||
|
||||
/// get the logical size of the app's drawable area.
|
||||
@@ -549,14 +548,14 @@ impl PlatformWindow for WindowsWindow {
|
||||
/// Currently, GPUI uses the logical size of the app to handle mouse interactions (such as
|
||||
/// whether the mouse collides with other elements of GPUI).
|
||||
fn content_size(&self) -> Size<Pixels> {
|
||||
self.0.state.borrow().content_size()
|
||||
self.state.content_size()
|
||||
}
|
||||
|
||||
fn resize(&mut self, size: Size<Pixels>) {
|
||||
let hwnd = self.0.hwnd;
|
||||
let bounds =
|
||||
crate::bounds(self.bounds().origin, size).to_device_pixels(self.scale_factor());
|
||||
let rect = calculate_window_rect(bounds, self.0.state.borrow().border_offset);
|
||||
let rect = calculate_window_rect(bounds, &self.state.border_offset);
|
||||
|
||||
self.0
|
||||
.executor
|
||||
@@ -579,15 +578,15 @@ impl PlatformWindow for WindowsWindow {
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f32 {
|
||||
self.0.state.borrow().scale_factor
|
||||
self.state.scale_factor.get()
|
||||
}
|
||||
|
||||
fn appearance(&self) -> WindowAppearance {
|
||||
self.0.state.borrow().appearance
|
||||
self.state.appearance.get()
|
||||
}
|
||||
|
||||
fn display(&self) -> Option<Rc<dyn PlatformDisplay>> {
|
||||
Some(Rc::new(self.0.state.borrow().display))
|
||||
Some(Rc::new(self.state.display.get()))
|
||||
}
|
||||
|
||||
fn mouse_position(&self) -> Point<Pixels> {
|
||||
@@ -612,11 +611,11 @@ impl PlatformWindow for WindowsWindow {
|
||||
}
|
||||
|
||||
fn set_input_handler(&mut self, input_handler: PlatformInputHandler) {
|
||||
self.0.state.borrow_mut().input_handler = Some(input_handler);
|
||||
self.state.input_handler.set(Some(input_handler));
|
||||
}
|
||||
|
||||
fn take_input_handler(&mut self) -> Option<PlatformInputHandler> {
|
||||
self.0.state.borrow_mut().input_handler.take()
|
||||
self.state.input_handler.take()
|
||||
}
|
||||
|
||||
fn prompt(
|
||||
@@ -762,7 +761,7 @@ impl PlatformWindow for WindowsWindow {
|
||||
}
|
||||
|
||||
fn is_hovered(&self) -> bool {
|
||||
self.0.state.borrow().hovered
|
||||
self.state.hovered.get()
|
||||
}
|
||||
|
||||
fn set_title(&mut self, title: &str) {
|
||||
@@ -805,8 +804,9 @@ impl PlatformWindow for WindowsWindow {
|
||||
unsafe {
|
||||
if IsWindowVisible(self.0.hwnd).as_bool() {
|
||||
ShowWindowAsync(self.0.hwnd, SW_MAXIMIZE).ok().log_err();
|
||||
} else if let Some(status) = self.0.state.borrow_mut().initial_placement.as_mut() {
|
||||
} else if let Some(mut status) = self.state.initial_placement.take() {
|
||||
status.state = WindowOpenState::Maximized;
|
||||
self.state.initial_placement.set(Some(status));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -814,61 +814,78 @@ impl PlatformWindow for WindowsWindow {
|
||||
fn toggle_fullscreen(&self) {
|
||||
if unsafe { IsWindowVisible(self.0.hwnd).as_bool() } {
|
||||
self.0.toggle_fullscreen();
|
||||
} else if let Some(status) = self.0.state.borrow_mut().initial_placement.as_mut() {
|
||||
} else if let Some(mut status) = self.state.initial_placement.take() {
|
||||
status.state = WindowOpenState::Fullscreen;
|
||||
self.state.initial_placement.set(Some(status));
|
||||
}
|
||||
}
|
||||
|
||||
fn is_fullscreen(&self) -> bool {
|
||||
self.0.state.borrow().is_fullscreen()
|
||||
self.state.is_fullscreen()
|
||||
}
|
||||
|
||||
fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions)>) {
|
||||
self.0.state.borrow_mut().callbacks.request_frame = Some(callback);
|
||||
self.state.callbacks.request_frame.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_input(&self, callback: Box<dyn FnMut(PlatformInput) -> DispatchEventResult>) {
|
||||
self.0.state.borrow_mut().callbacks.input = Some(callback);
|
||||
self.state.callbacks.input.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {
|
||||
self.0.state.borrow_mut().callbacks.active_status_change = Some(callback);
|
||||
self.0
|
||||
.state
|
||||
.callbacks
|
||||
.active_status_change
|
||||
.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_hover_status_change(&self, callback: Box<dyn FnMut(bool)>) {
|
||||
self.0.state.borrow_mut().callbacks.hovered_status_change = Some(callback);
|
||||
self.0
|
||||
.state
|
||||
.callbacks
|
||||
.hovered_status_change
|
||||
.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
|
||||
self.0.state.borrow_mut().callbacks.resize = Some(callback);
|
||||
self.state.callbacks.resize.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_moved(&self, callback: Box<dyn FnMut()>) {
|
||||
self.0.state.borrow_mut().callbacks.moved = Some(callback);
|
||||
self.state.callbacks.moved.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_should_close(&self, callback: Box<dyn FnMut() -> bool>) {
|
||||
self.0.state.borrow_mut().callbacks.should_close = Some(callback);
|
||||
self.state.callbacks.should_close.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_close(&self, callback: Box<dyn FnOnce()>) {
|
||||
self.0.state.borrow_mut().callbacks.close = Some(callback);
|
||||
self.state.callbacks.close.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_hit_test_window_control(&self, callback: Box<dyn FnMut() -> Option<WindowControlArea>>) {
|
||||
self.0.state.borrow_mut().callbacks.hit_test_window_control = Some(callback);
|
||||
self.0
|
||||
.state
|
||||
.callbacks
|
||||
.hit_test_window_control
|
||||
.set(Some(callback));
|
||||
}
|
||||
|
||||
fn on_appearance_changed(&self, callback: Box<dyn FnMut()>) {
|
||||
self.0.state.borrow_mut().callbacks.appearance_changed = Some(callback);
|
||||
self.0
|
||||
.state
|
||||
.callbacks
|
||||
.appearance_changed
|
||||
.set(Some(callback));
|
||||
}
|
||||
|
||||
fn draw(&self, scene: &Scene) {
|
||||
self.0.state.borrow_mut().renderer.draw(scene).log_err();
|
||||
self.state.renderer.borrow_mut().draw(scene).log_err();
|
||||
}
|
||||
|
||||
fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
|
||||
self.0.state.borrow().renderer.sprite_atlas()
|
||||
self.state.renderer.borrow().sprite_atlas()
|
||||
}
|
||||
|
||||
fn get_raw_handle(&self) -> HWND {
|
||||
@@ -876,7 +893,7 @@ impl PlatformWindow for WindowsWindow {
|
||||
}
|
||||
|
||||
fn gpu_specs(&self) -> Option<GpuSpecs> {
|
||||
self.0.state.borrow().renderer.gpu_specs().log_err()
|
||||
self.state.renderer.borrow().gpu_specs().log_err()
|
||||
}
|
||||
|
||||
fn update_ime_position(&self, _bounds: Bounds<Pixels>) {
|
||||
@@ -889,11 +906,9 @@ struct WindowsDragDropHandler(pub Rc<WindowsWindowInner>);
|
||||
|
||||
impl WindowsDragDropHandler {
|
||||
fn handle_drag_drop(&self, input: PlatformInput) {
|
||||
let mut lock = self.0.state.borrow_mut();
|
||||
if let Some(mut func) = lock.callbacks.input.take() {
|
||||
drop(lock);
|
||||
if let Some(mut func) = self.0.state.callbacks.input.take() {
|
||||
func(input);
|
||||
self.0.state.borrow_mut().callbacks.input = Some(func);
|
||||
self.0.state.callbacks.input.set(Some(func));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -937,7 +952,7 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
|
||||
ScreenToClient(self.0.hwnd, &mut cursor_position)
|
||||
.ok()
|
||||
.log_err();
|
||||
let scale_factor = self.0.state.borrow().scale_factor;
|
||||
let scale_factor = self.0.state.scale_factor.get();
|
||||
let input = PlatformInput::FileDrop(FileDropEvent::Entered {
|
||||
position: logical_point(
|
||||
cursor_position.x as f32,
|
||||
@@ -975,7 +990,7 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
|
||||
.ok()
|
||||
.log_err();
|
||||
}
|
||||
let scale_factor = self.0.state.borrow().scale_factor;
|
||||
let scale_factor = self.0.state.scale_factor.get();
|
||||
let input = PlatformInput::FileDrop(FileDropEvent::Pending {
|
||||
position: logical_point(
|
||||
cursor_position.x as f32,
|
||||
@@ -1017,7 +1032,7 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
|
||||
.ok()
|
||||
.log_err();
|
||||
}
|
||||
let scale_factor = self.0.state.borrow().scale_factor;
|
||||
let scale_factor = self.0.state.scale_factor.get();
|
||||
let input = PlatformInput::FileDrop(FileDropEvent::Submit {
|
||||
position: logical_point(
|
||||
cursor_position.x as f32,
|
||||
@@ -1031,15 +1046,15 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ClickState {
|
||||
button: MouseButton,
|
||||
last_click: Instant,
|
||||
last_position: Point<DevicePixels>,
|
||||
double_click_spatial_tolerance_width: i32,
|
||||
double_click_spatial_tolerance_height: i32,
|
||||
double_click_interval: Duration,
|
||||
pub(crate) current_count: usize,
|
||||
button: Cell<MouseButton>,
|
||||
last_click: Cell<Instant>,
|
||||
last_position: Cell<Point<DevicePixels>>,
|
||||
double_click_spatial_tolerance_width: Cell<i32>,
|
||||
double_click_spatial_tolerance_height: Cell<i32>,
|
||||
double_click_interval: Cell<Duration>,
|
||||
pub(crate) current_count: Cell<usize>,
|
||||
}
|
||||
|
||||
impl ClickState {
|
||||
@@ -1049,61 +1064,59 @@ impl ClickState {
|
||||
let double_click_interval = Duration::from_millis(unsafe { GetDoubleClickTime() } as u64);
|
||||
|
||||
ClickState {
|
||||
button: MouseButton::Left,
|
||||
last_click: Instant::now(),
|
||||
last_position: Point::default(),
|
||||
double_click_spatial_tolerance_width,
|
||||
double_click_spatial_tolerance_height,
|
||||
double_click_interval,
|
||||
current_count: 0,
|
||||
button: Cell::new(MouseButton::Left),
|
||||
last_click: Cell::new(Instant::now()),
|
||||
last_position: Cell::new(Point::default()),
|
||||
double_click_spatial_tolerance_width: Cell::new(double_click_spatial_tolerance_width),
|
||||
double_click_spatial_tolerance_height: Cell::new(double_click_spatial_tolerance_height),
|
||||
double_click_interval: Cell::new(double_click_interval),
|
||||
current_count: Cell::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// update self and return the needed click count
|
||||
pub fn update(&mut self, button: MouseButton, new_position: Point<DevicePixels>) -> usize {
|
||||
if self.button == button && self.is_double_click(new_position) {
|
||||
self.current_count += 1;
|
||||
pub fn update(&self, button: MouseButton, new_position: Point<DevicePixels>) -> usize {
|
||||
if self.button.get() == button && self.is_double_click(new_position) {
|
||||
self.current_count.update(|it| it + 1);
|
||||
} else {
|
||||
self.current_count = 1;
|
||||
self.current_count.set(1);
|
||||
}
|
||||
self.last_click = Instant::now();
|
||||
self.last_position = new_position;
|
||||
self.button = button;
|
||||
self.last_click.set(Instant::now());
|
||||
self.last_position.set(new_position);
|
||||
self.button.set(button);
|
||||
|
||||
self.current_count
|
||||
self.current_count.get()
|
||||
}
|
||||
|
||||
pub fn system_update(&mut self, wparam: usize) {
|
||||
pub fn system_update(&self, wparam: usize) {
|
||||
match wparam {
|
||||
// SPI_SETDOUBLECLKWIDTH
|
||||
29 => {
|
||||
self.double_click_spatial_tolerance_width =
|
||||
unsafe { GetSystemMetrics(SM_CXDOUBLECLK) }
|
||||
}
|
||||
29 => self
|
||||
.double_click_spatial_tolerance_width
|
||||
.set(unsafe { GetSystemMetrics(SM_CXDOUBLECLK) }),
|
||||
// SPI_SETDOUBLECLKHEIGHT
|
||||
30 => {
|
||||
self.double_click_spatial_tolerance_height =
|
||||
unsafe { GetSystemMetrics(SM_CYDOUBLECLK) }
|
||||
}
|
||||
30 => self
|
||||
.double_click_spatial_tolerance_height
|
||||
.set(unsafe { GetSystemMetrics(SM_CYDOUBLECLK) }),
|
||||
// SPI_SETDOUBLECLICKTIME
|
||||
32 => {
|
||||
self.double_click_interval =
|
||||
Duration::from_millis(unsafe { GetDoubleClickTime() } as u64)
|
||||
}
|
||||
32 => self
|
||||
.double_click_interval
|
||||
.set(Duration::from_millis(unsafe { GetDoubleClickTime() } as u64)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_double_click(&self, new_position: Point<DevicePixels>) -> bool {
|
||||
let diff = self.last_position - new_position;
|
||||
let diff = self.last_position.get() - new_position;
|
||||
|
||||
self.last_click.elapsed() < self.double_click_interval
|
||||
&& diff.x.0.abs() <= self.double_click_spatial_tolerance_width
|
||||
&& diff.y.0.abs() <= self.double_click_spatial_tolerance_height
|
||||
self.last_click.get().elapsed() < self.double_click_interval.get()
|
||||
&& diff.x.0.abs() <= self.double_click_spatial_tolerance_width.get()
|
||||
&& diff.y.0.abs() <= self.double_click_spatial_tolerance_height.get()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct StyleAndBounds {
|
||||
style: WINDOW_STYLE,
|
||||
x: i32,
|
||||
@@ -1129,14 +1142,14 @@ struct AccentPolicy {
|
||||
|
||||
type Color = (u8, u8, u8, u8);
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub(crate) struct WindowBorderOffset {
|
||||
pub(crate) width_offset: i32,
|
||||
pub(crate) height_offset: i32,
|
||||
pub(crate) width_offset: Cell<i32>,
|
||||
pub(crate) height_offset: Cell<i32>,
|
||||
}
|
||||
|
||||
impl WindowBorderOffset {
|
||||
pub(crate) fn update(&mut self, hwnd: HWND) -> anyhow::Result<()> {
|
||||
pub(crate) fn update(&self, hwnd: HWND) -> anyhow::Result<()> {
|
||||
let window_rect = unsafe {
|
||||
let mut rect = std::mem::zeroed();
|
||||
GetWindowRect(hwnd, &mut rect)?;
|
||||
@@ -1147,19 +1160,21 @@ impl WindowBorderOffset {
|
||||
GetClientRect(hwnd, &mut rect)?;
|
||||
rect
|
||||
};
|
||||
self.width_offset =
|
||||
(window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
|
||||
self.height_offset =
|
||||
(window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
|
||||
self.width_offset
|
||||
.set((window_rect.right - window_rect.left) - (client_rect.right - client_rect.left));
|
||||
self.height_offset
|
||||
.set((window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct WindowOpenStatus {
|
||||
placement: WINDOWPLACEMENT,
|
||||
state: WindowOpenState,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum WindowOpenState {
|
||||
Maximized,
|
||||
Fullscreen,
|
||||
@@ -1269,7 +1284,7 @@ fn register_drag_drop(window: &Rc<WindowsWindowInner>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn calculate_window_rect(bounds: Bounds<DevicePixels>, border_offset: WindowBorderOffset) -> RECT {
|
||||
fn calculate_window_rect(bounds: Bounds<DevicePixels>, border_offset: &WindowBorderOffset) -> RECT {
|
||||
// NOTE:
|
||||
// The reason we're not using `AdjustWindowRectEx()` here is
|
||||
// that the size reported by this function is incorrect.
|
||||
@@ -1283,10 +1298,10 @@ fn calculate_window_rect(bounds: Bounds<DevicePixels>, border_offset: WindowBord
|
||||
right: bounds.right().0,
|
||||
bottom: bounds.bottom().0,
|
||||
};
|
||||
let left_offset = border_offset.width_offset / 2;
|
||||
let top_offset = border_offset.height_offset / 2;
|
||||
let right_offset = border_offset.width_offset - left_offset;
|
||||
let bottom_offset = border_offset.height_offset - top_offset;
|
||||
let left_offset = border_offset.width_offset.get() / 2;
|
||||
let top_offset = border_offset.height_offset.get() / 2;
|
||||
let right_offset = border_offset.width_offset.get() - left_offset;
|
||||
let bottom_offset = border_offset.height_offset.get() - top_offset;
|
||||
rect.left -= left_offset;
|
||||
rect.top -= top_offset;
|
||||
rect.right += right_offset;
|
||||
@@ -1296,13 +1311,13 @@ fn calculate_window_rect(bounds: Bounds<DevicePixels>, border_offset: WindowBord
|
||||
|
||||
fn calculate_client_rect(
|
||||
rect: RECT,
|
||||
border_offset: WindowBorderOffset,
|
||||
border_offset: &WindowBorderOffset,
|
||||
scale_factor: f32,
|
||||
) -> Bounds<Pixels> {
|
||||
let left_offset = border_offset.width_offset / 2;
|
||||
let top_offset = border_offset.height_offset / 2;
|
||||
let right_offset = border_offset.width_offset - left_offset;
|
||||
let bottom_offset = border_offset.height_offset - top_offset;
|
||||
let left_offset = border_offset.width_offset.get() / 2;
|
||||
let top_offset = border_offset.height_offset.get() / 2;
|
||||
let right_offset = border_offset.width_offset.get() - left_offset;
|
||||
let bottom_offset = border_offset.height_offset.get() - top_offset;
|
||||
let left = rect.left + left_offset;
|
||||
let top = rect.top + top_offset;
|
||||
let right = rect.right - right_offset;
|
||||
@@ -1319,7 +1334,7 @@ fn retrieve_window_placement(
|
||||
display: WindowsDisplay,
|
||||
initial_bounds: Bounds<Pixels>,
|
||||
scale_factor: f32,
|
||||
border_offset: WindowBorderOffset,
|
||||
border_offset: &WindowBorderOffset,
|
||||
) -> Result<WINDOWPLACEMENT> {
|
||||
let mut placement = WINDOWPLACEMENT {
|
||||
length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
|
||||
@@ -1429,7 +1444,9 @@ mod tests {
|
||||
state.update(MouseButton::Left, point(DevicePixels(0), DevicePixels(0))),
|
||||
2
|
||||
);
|
||||
state.last_click -= Duration::from_millis(700);
|
||||
state
|
||||
.last_click
|
||||
.update(|it| it - Duration::from_millis(700));
|
||||
assert_eq!(
|
||||
state.update(MouseButton::Left, point(DevicePixels(0), DevicePixels(0))),
|
||||
1
|
||||
|
||||
Reference in New Issue
Block a user