@@ -49,6 +49,7 @@ pub struct MonitorInfo { |
| 49 | pub y: i32, | 49 | pub y: i32, |
| 50 | pub width: u32, | 50 | pub width: u32, |
| 51 | pub height: u32, | 51 | pub height: u32, |
| | 52 | + pub scale: f32, |
| 52 | } | 53 | } |
| 53 | | 54 | |
| 54 | /// Configuration for edge barriers | 55 | /// Configuration for edge barriers |
@@ -130,27 +131,28 @@ impl EdgeCaptureState { |
| 130 | let mut used_monitors: Vec<bool> = vec![false; self.config.monitors.len()]; | 131 | let mut used_monitors: Vec<bool> = vec![false; self.config.monitors.len()]; |
| 131 | let mut assigned_outputs: Vec<bool> = vec![false; self.outputs.len()]; | 132 | let mut assigned_outputs: Vec<bool> = vec![false; self.outputs.len()]; |
| 132 | | 133 | |
| | 134 | + // Helper to check if a monitor's logical size matches an output |
| | 135 | + let sizes_match = |mon: &MonitorInfo, out_w: u32, out_h: u32| -> bool { |
| | 136 | + // Use the monitor's actual scale from Hyprland |
| | 137 | + let scale = mon.scale as f64; |
| | 138 | + let logical_w = (mon.width as f64 / scale).round() as u32; |
| | 139 | + let logical_h = (mon.height as f64 / scale).round() as u32; |
| | 140 | + |
| | 141 | + // Allow 1 pixel tolerance for rounding differences |
| | 142 | + let w_match = (logical_w as i32 - out_w as i32).abs() <= 1; |
| | 143 | + let h_match = (logical_h as i32 - out_h as i32).abs() <= 1; |
| | 144 | + w_match && h_match |
| | 145 | + }; |
| | 146 | + |
| 133 | // First pass: try to find unique matches | 147 | // First pass: try to find unique matches |
| 134 | for (out_idx, out) in self.outputs.iter_mut().enumerate() { | 148 | for (out_idx, out) in self.outputs.iter_mut().enumerate() { |
| 135 | - // Find monitors that could match this output size (considering possible scales) | | |
| 136 | let mut candidates: Vec<usize> = Vec::new(); | 149 | let mut candidates: Vec<usize> = Vec::new(); |
| 137 | for (i, mon) in self.config.monitors.iter().enumerate() { | 150 | for (i, mon) in self.config.monitors.iter().enumerate() { |
| 138 | if used_monitors[i] { | 151 | if used_monitors[i] { |
| 139 | continue; | 152 | continue; |
| 140 | } | 153 | } |
| 141 | - // Check if sizes match directly | 154 | + if sizes_match(mon, out.width, out.height) { |
| 142 | - if mon.width == out.width && mon.height == out.height { | | |
| 143 | candidates.push(i); | 155 | candidates.push(i); |
| 144 | - continue; | | |
| 145 | - } | | |
| 146 | - // Check common scale factors (1.5, 2.0) | | |
| 147 | - for scale in [1.5_f64, 2.0_f64] { | | |
| 148 | - let scaled_w = (mon.width as f64 / scale).round() as u32; | | |
| 149 | - let scaled_h = (mon.height as f64 / scale).round() as u32; | | |
| 150 | - if scaled_w == out.width && scaled_h == out.height { | | |
| 151 | - candidates.push(i); | | |
| 152 | - break; | | |
| 153 | - } | | |
| 154 | } | 156 | } |
| 155 | } | 157 | } |
| 156 | | 158 | |
@@ -158,8 +160,8 @@ impl EdgeCaptureState { |
| 158 | if candidates.len() == 1 { | 160 | if candidates.len() == 1 { |
| 159 | let i = candidates[0]; | 161 | let i = candidates[0]; |
| 160 | let mon = &self.config.monitors[i]; | 162 | let mon = &self.config.monitors[i]; |
| 161 | - tracing::info!("Matched output {}x{} to monitor {} at ({}, {})", | 163 | + tracing::info!("Matched output {}x{} to monitor {} at ({}, {}) scale={}", |
| 162 | - out.width, out.height, mon.name, mon.x, mon.y); | 164 | + out.width, out.height, mon.name, mon.x, mon.y, mon.scale); |
| 163 | out.x = mon.x; | 165 | out.x = mon.x; |
| 164 | out.y = mon.y; | 166 | out.y = mon.y; |
| 165 | used_monitors[i] = true; | 167 | used_monitors[i] = true; |
@@ -176,21 +178,14 @@ impl EdgeCaptureState { |
| 176 | if assigned_outputs[out_idx] { | 178 | if assigned_outputs[out_idx] { |
| 177 | continue; // Already assigned in first pass | 179 | continue; // Already assigned in first pass |
| 178 | } | 180 | } |
| 179 | - // Find first unused monitor that could match | 181 | + // Find first unused monitor that matches |
| 180 | for (i, mon) in self.config.monitors.iter().enumerate() { | 182 | for (i, mon) in self.config.monitors.iter().enumerate() { |
| 181 | if used_monitors[i] { | 183 | if used_monitors[i] { |
| 182 | continue; | 184 | continue; |
| 183 | } | 185 | } |
| 184 | - // Check all possible scales | 186 | + if sizes_match(mon, out.width, out.height) { |
| 185 | - let matches = (mon.width == out.width && mon.height == out.height) | 187 | + tracing::info!("Assigned remaining output {}x{} to monitor {} at ({}, {}) scale={}", |
| 186 | - || [1.5_f64, 2.0_f64].iter().any(|&scale| { | 188 | + out.width, out.height, mon.name, mon.x, mon.y, mon.scale); |
| 187 | - let scaled_w = (mon.width as f64 / scale).round() as u32; | | |
| 188 | - let scaled_h = (mon.height as f64 / scale).round() as u32; | | |
| 189 | - scaled_w == out.width && scaled_h == out.height | | |
| 190 | - }); | | |
| 191 | - if matches { | | |
| 192 | - tracing::info!("Assigned remaining output {}x{} to monitor {} at ({}, {})", | | |
| 193 | - out.width, out.height, mon.name, mon.x, mon.y); | | |
| 194 | out.x = mon.x; | 189 | out.x = mon.x; |
| 195 | out.y = mon.y; | 190 | out.y = mon.y; |
| 196 | used_monitors[i] = true; | 191 | used_monitors[i] = true; |
@@ -615,26 +610,18 @@ impl PointerHandler for EdgeCaptureState { |
| 615 | if should_trigger { | 610 | if should_trigger { |
| 616 | self.last_trigger_time.insert(barrier.direction, now); | 611 | self.last_trigger_time.insert(barrier.direction, now); |
| 617 | | 612 | |
| 618 | - // Calculate screen position | 613 | + // Send edge event with direction only |
| 619 | - let (min_x, min_y, max_x, max_y) = self.screen_bounds(); | 614 | + // Main daemon will query Hyprland for actual cursor position |
| 620 | - let screen_pos = match barrier.direction { | 615 | + // and verify we're at screen boundary before triggering transfer |
| 621 | - Direction::Left => (min_x, min_y + y as i32), | | |
| 622 | - Direction::Right => (max_x - 1, min_y + y as i32), | | |
| 623 | - Direction::Up => (min_x + x as i32, min_y), | | |
| 624 | - Direction::Down => (min_x + x as i32, max_y - 1), | | |
| 625 | - }; | | |
| 626 | - | | |
| 627 | let edge_event = EdgeEvent { | 616 | let edge_event = EdgeEvent { |
| 628 | direction: barrier.direction, | 617 | direction: barrier.direction, |
| 629 | - position: screen_pos, | 618 | + position: (0, 0), // Placeholder - main daemon uses Hyprland cursor pos |
| 630 | timestamp: now, | 619 | timestamp: now, |
| 631 | }; | 620 | }; |
| 632 | | 621 | |
| 633 | tracing::info!( | 622 | tracing::info!( |
| 634 | - "Edge trigger: {:?} at screen ({}, {})", | 623 | + "Edge event: {:?} barrier triggered", |
| 635 | - barrier.direction, | 624 | + barrier.direction |
| 636 | - screen_pos.0, | | |
| 637 | - screen_pos.1 | | |
| 638 | ); | 625 | ); |
| 639 | | 626 | |
| 640 | let _ = self.event_tx.send(edge_event); | 627 | let _ = self.event_tx.send(edge_event); |