fix: overlay not showing on non-primary monitors (#969)
This commit is contained in:
parent
82297fa146
commit
aebd432390
1 changed files with 45 additions and 26 deletions
|
|
@ -137,9 +137,23 @@ fn get_monitor_with_cursor(app_handle: &AppHandle) -> Option<tauri::Monitor> {
|
||||||
if let Some(mouse_location) = input::get_cursor_position(app_handle) {
|
if let Some(mouse_location) = input::get_cursor_position(app_handle) {
|
||||||
if let Ok(monitors) = app_handle.available_monitors() {
|
if let Ok(monitors) = app_handle.available_monitors() {
|
||||||
for monitor in monitors {
|
for monitor in monitors {
|
||||||
let is_within =
|
// Tauri's monitor position/size are physical pixels, but enigo
|
||||||
is_mouse_within_monitor(mouse_location, monitor.position(), monitor.size());
|
// may return logical coordinates (confirmed on macOS via
|
||||||
if is_within {
|
// NSEvent::mouseLocation; on Windows, GetCursorPos behavior
|
||||||
|
// depends on the process DPI-awareness context). Dividing by
|
||||||
|
// scale_factor normalizes to logical, which is safe regardless:
|
||||||
|
// if enigo returns logical it matches directly, and if it returns
|
||||||
|
// physical on a scale=1 monitor the division is a no-op.
|
||||||
|
let scale = monitor.scale_factor();
|
||||||
|
let pos = PhysicalPosition::new(
|
||||||
|
(monitor.position().x as f64 / scale) as i32,
|
||||||
|
(monitor.position().y as f64 / scale) as i32,
|
||||||
|
);
|
||||||
|
let size = PhysicalSize::new(
|
||||||
|
(monitor.size().width as f64 / scale) as u32,
|
||||||
|
(monitor.size().height as f64 / scale) as u32,
|
||||||
|
);
|
||||||
|
if is_mouse_within_monitor(mouse_location, &pos, &size) {
|
||||||
return Some(monitor);
|
return Some(monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -170,28 +184,35 @@ fn is_mouse_within_monitor(
|
||||||
&& mouse_y < (monitor_y + monitor_height as i32)
|
&& mouse_y < (monitor_y + monitor_height as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns overlay position in logical coordinates (points on macOS).
|
||||||
|
///
|
||||||
|
/// Uses monitor position/size directly rather than work_area(), which can
|
||||||
|
/// return incorrect coordinates on macOS for monitors with negative positions.
|
||||||
|
/// The per-platform OVERLAY_TOP_OFFSET / OVERLAY_BOTTOM_OFFSET constants
|
||||||
|
/// already account for system chrome (menu bar, taskbar).
|
||||||
|
///
|
||||||
|
/// We must use LogicalPosition (not PhysicalPosition) because Tauri/tao
|
||||||
|
/// converts PhysicalPosition using the scale factor of the monitor the window
|
||||||
|
/// is *currently* on, which is wrong when moving cross-monitor.
|
||||||
fn calculate_overlay_position(app_handle: &AppHandle) -> Option<(f64, f64)> {
|
fn calculate_overlay_position(app_handle: &AppHandle) -> Option<(f64, f64)> {
|
||||||
if let Some(monitor) = get_monitor_with_cursor(app_handle) {
|
let monitor = get_monitor_with_cursor(app_handle)?;
|
||||||
let work_area = monitor.work_area();
|
let scale = monitor.scale_factor();
|
||||||
let scale = monitor.scale_factor();
|
let monitor_x = monitor.position().x as f64 / scale;
|
||||||
let work_area_width = work_area.size.width as f64 / scale;
|
let monitor_y = monitor.position().y as f64 / scale;
|
||||||
let work_area_height = work_area.size.height as f64 / scale;
|
let monitor_width = monitor.size().width as f64 / scale;
|
||||||
let work_area_x = work_area.position.x as f64 / scale;
|
let monitor_height = monitor.size().height as f64 / scale;
|
||||||
let work_area_y = work_area.position.y as f64 / scale;
|
|
||||||
|
|
||||||
let settings = settings::get_settings(app_handle);
|
let settings = settings::get_settings(app_handle);
|
||||||
|
|
||||||
let x = work_area_x + (work_area_width - OVERLAY_WIDTH) / 2.0;
|
let x = monitor_x + (monitor_width - OVERLAY_WIDTH) / 2.0;
|
||||||
let y = match settings.overlay_position {
|
let y = match settings.overlay_position {
|
||||||
OverlayPosition::Top => work_area_y + OVERLAY_TOP_OFFSET,
|
OverlayPosition::Top => monitor_y + OVERLAY_TOP_OFFSET,
|
||||||
OverlayPosition::Bottom | OverlayPosition::None => {
|
OverlayPosition::Bottom | OverlayPosition::None => {
|
||||||
work_area_y + work_area_height - OVERLAY_HEIGHT - OVERLAY_BOTTOM_OFFSET
|
monitor_y + monitor_height - OVERLAY_HEIGHT - OVERLAY_BOTTOM_OFFSET
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return Some((x, y));
|
Some((x, y))
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the recording overlay window and keeps it hidden by default
|
/// Creates the recording overlay window and keeps it hidden by default
|
||||||
|
|
@ -200,13 +221,15 @@ pub fn create_recording_overlay(app_handle: &AppHandle) {
|
||||||
let position = calculate_overlay_position(app_handle);
|
let position = calculate_overlay_position(app_handle);
|
||||||
|
|
||||||
// On Linux (Wayland), monitor detection often fails, but we don't need exact coordinates
|
// On Linux (Wayland), monitor detection often fails, but we don't need exact coordinates
|
||||||
// for Layer Shell as we use anchors. On other platforms, we require a position.
|
// for Layer Shell as we use anchors. On other platforms, we require a monitor.
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
if position.is_none() {
|
if position.is_none() {
|
||||||
debug!("Failed to determine overlay position, not creating overlay window");
|
debug!("Failed to determine overlay position, not creating overlay window");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Position starts unset — update_overlay_position() sets the correct
|
||||||
|
// LogicalPosition before the overlay is shown.
|
||||||
let mut builder = WebviewWindowBuilder::new(
|
let mut builder = WebviewWindowBuilder::new(
|
||||||
app_handle,
|
app_handle,
|
||||||
"recording_overlay",
|
"recording_overlay",
|
||||||
|
|
@ -231,10 +254,6 @@ pub fn create_recording_overlay(app_handle: &AppHandle) {
|
||||||
builder = builder.data_directory(data_dir.join("webview"));
|
builder = builder.data_directory(data_dir.join("webview"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((x, y)) = position {
|
|
||||||
builder = builder.position(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
match builder.build() {
|
match builder.build() {
|
||||||
Ok(window) => {
|
Ok(window) => {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue