tenseleyflow/hyprkvm / e7c88f9

Browse files

feat: support Up/Down layouts with multi-monitor barriers

- Changed find_edge_output() to find_edge_outputs() returning Vec
- For Left/Right: still returns single monitor at edge
- For Up/Down: returns ALL monitors at top/bottom edge
- create_barriers() now loops through all edge outputs
- Creates barrier on each monitor for Up/Down directions
- Enables proper Up/Down neighbor configs with horizontal multi-monitor setups
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
e7c88f9c332875cff03ef9fe8e3c4e8a1db193e8
Parents
c6d72a3
Tree
48ec6ec

1 changed file

StatusFile+-
M hyprkvm-daemon/src/input/capture.rs 131 75
hyprkvm-daemon/src/input/capture.rsmodified
@@ -211,95 +211,151 @@ impl EdgeCaptureState {
211211
         tracing::info!("Screen bounds: ({}, {}) to ({}, {})", min_x, min_y, max_x, max_y);
212212
 
213213
         for direction in &self.config.enabled_edges.clone() {
214
-            // Find the correct output for this edge direction
215
-            let target_output = self.find_edge_output(*direction);
216
-            tracing::info!("  {:?} edge -> output at {:?}",
217
-                direction,
218
-                target_output.as_ref().map(|o| (o.x, o.y, o.width, o.height)));
219
-
220
-            let (width, height, anchor) = match direction {
221
-                Direction::Left => (
222
-                    self.config.barrier_size,
223
-                    target_output.as_ref().map(|o| o.height).unwrap_or((max_y - min_y) as u32),
224
-                    Anchor::LEFT | Anchor::TOP | Anchor::BOTTOM,
225
-                ),
226
-                Direction::Right => (
227
-                    self.config.barrier_size,
228
-                    target_output.as_ref().map(|o| o.height).unwrap_or((max_y - min_y) as u32),
229
-                    Anchor::RIGHT | Anchor::TOP | Anchor::BOTTOM,
230
-                ),
231
-                Direction::Up => (
232
-                    target_output.as_ref().map(|o| o.width).unwrap_or((max_x - min_x) as u32),
233
-                    self.config.barrier_size,
234
-                    Anchor::TOP | Anchor::LEFT | Anchor::RIGHT,
235
-                ),
236
-                Direction::Down => (
237
-                    target_output.as_ref().map(|o| o.width).unwrap_or((max_x - min_x) as u32),
238
-                    self.config.barrier_size,
239
-                    Anchor::BOTTOM | Anchor::LEFT | Anchor::RIGHT,
240
-                ),
241
-            };
242
-
243
-            // Create layer surface on the specific edge output
244
-            let surface = self.compositor_state.create_surface(qh);
245
-            let output_ref = target_output.as_ref().map(|o| &o.output);
246
-            let layer_surface = self.layer_shell.create_layer_surface(
247
-                qh,
248
-                surface,
249
-                Layer::Top, // Top layer to catch pointer
250
-                Some(format!("hyprkvm-edge-{}", direction)),
251
-                output_ref,
252
-            );
253
-
254
-            tracing::info!(
255
-                "Creating {:?} barrier on output {:?}, size {}x{}",
256
-                direction,
257
-                target_output.as_ref().map(|o| format!("at ({}, {})", o.x, o.y)),
258
-                width,
259
-                height
260
-            );
261
-
262
-            // Configure the layer surface
263
-            layer_surface.set_anchor(anchor);
264
-            layer_surface.set_size(width, height);
265
-            layer_surface.set_exclusive_zone(-1); // Don't reserve space
266
-            layer_surface.set_keyboard_interactivity(KeyboardInteractivity::None);
267
-
268
-            // Commit to apply configuration
269
-            layer_surface.commit();
270
-
271
-            self.barriers.push(EdgeBarrier {
272
-                direction: *direction,
273
-                surface: layer_surface,
274
-                width,
275
-                height,
276
-                configured: false,
277
-            });
214
+            // Find the output(s) for this edge direction
215
+            // Up/Down may return multiple outputs (all monitors at top/bottom)
216
+            let edge_outputs = self.find_edge_outputs(*direction);
217
+            tracing::info!("  {:?} edge -> {} output(s)", direction, edge_outputs.len());
218
+
219
+            // Create a barrier on each edge output
220
+            for target_output in &edge_outputs {
221
+                let (width, height, anchor) = match direction {
222
+                    Direction::Left => (
223
+                        self.config.barrier_size,
224
+                        target_output.height,
225
+                        Anchor::LEFT | Anchor::TOP | Anchor::BOTTOM,
226
+                    ),
227
+                    Direction::Right => (
228
+                        self.config.barrier_size,
229
+                        target_output.height,
230
+                        Anchor::RIGHT | Anchor::TOP | Anchor::BOTTOM,
231
+                    ),
232
+                    Direction::Up => (
233
+                        target_output.width,
234
+                        self.config.barrier_size,
235
+                        Anchor::TOP | Anchor::LEFT | Anchor::RIGHT,
236
+                    ),
237
+                    Direction::Down => (
238
+                        target_output.width,
239
+                        self.config.barrier_size,
240
+                        Anchor::BOTTOM | Anchor::LEFT | Anchor::RIGHT,
241
+                    ),
242
+                };
243
+
244
+                // Create layer surface on this specific output
245
+                let surface = self.compositor_state.create_surface(qh);
246
+                let layer_surface = self.layer_shell.create_layer_surface(
247
+                    qh,
248
+                    surface,
249
+                    Layer::Top, // Top layer to catch pointer
250
+                    Some(format!("hyprkvm-edge-{}", direction)),
251
+                    Some(&target_output.output),
252
+                );
253
+
254
+                tracing::info!(
255
+                    "Creating {:?} barrier on output at ({}, {}), size {}x{}",
256
+                    direction,
257
+                    target_output.x,
258
+                    target_output.y,
259
+                    width,
260
+                    height
261
+                );
262
+
263
+                // Configure the layer surface
264
+                layer_surface.set_anchor(anchor);
265
+                layer_surface.set_size(width, height);
266
+                layer_surface.set_exclusive_zone(-1); // Don't reserve space
267
+                layer_surface.set_keyboard_interactivity(KeyboardInteractivity::None);
268
+
269
+                // Commit to apply configuration
270
+                layer_surface.commit();
271
+
272
+                self.barriers.push(EdgeBarrier {
273
+                    direction: *direction,
274
+                    surface: layer_surface,
275
+                    width,
276
+                    height,
277
+                    configured: false,
278
+                });
279
+            }
280
+
281
+            // Fallback if no outputs found for this direction
282
+            if edge_outputs.is_empty() {
283
+                tracing::warn!("No outputs found for {:?} edge, creating fallback barrier", direction);
284
+                let (width, height, anchor) = match direction {
285
+                    Direction::Left => (
286
+                        self.config.barrier_size,
287
+                        (max_y - min_y) as u32,
288
+                        Anchor::LEFT | Anchor::TOP | Anchor::BOTTOM,
289
+                    ),
290
+                    Direction::Right => (
291
+                        self.config.barrier_size,
292
+                        (max_y - min_y) as u32,
293
+                        Anchor::RIGHT | Anchor::TOP | Anchor::BOTTOM,
294
+                    ),
295
+                    Direction::Up => (
296
+                        (max_x - min_x) as u32,
297
+                        self.config.barrier_size,
298
+                        Anchor::TOP | Anchor::LEFT | Anchor::RIGHT,
299
+                    ),
300
+                    Direction::Down => (
301
+                        (max_x - min_x) as u32,
302
+                        self.config.barrier_size,
303
+                        Anchor::BOTTOM | Anchor::LEFT | Anchor::RIGHT,
304
+                    ),
305
+                };
306
+
307
+                let surface = self.compositor_state.create_surface(qh);
308
+                let layer_surface = self.layer_shell.create_layer_surface(
309
+                    qh,
310
+                    surface,
311
+                    Layer::Top,
312
+                    Some(format!("hyprkvm-edge-{}", direction)),
313
+                    None, // No specific output
314
+                );
315
+
316
+                layer_surface.set_anchor(anchor);
317
+                layer_surface.set_size(width, height);
318
+                layer_surface.set_exclusive_zone(-1);
319
+                layer_surface.set_keyboard_interactivity(KeyboardInteractivity::None);
320
+                layer_surface.commit();
321
+
322
+                self.barriers.push(EdgeBarrier {
323
+                    direction: *direction,
324
+                    surface: layer_surface,
325
+                    width,
326
+                    height,
327
+                    configured: false,
328
+                });
329
+            }
278330
         }
279331
     }
280332
 
281
-    /// Find the output at the edge of the screen for a given direction
282
-    fn find_edge_output(&self, direction: Direction) -> Option<OutputInfo> {
333
+    /// Find the output(s) at the edge of the screen for a given direction
334
+    /// For Left/Right: returns single monitor at the edge
335
+    /// For Up/Down: returns ALL monitors at the top/bottom edge (for horizontal layouts)
336
+    fn find_edge_outputs(&self, direction: Direction) -> Vec<OutputInfo> {
283337
         if self.outputs.is_empty() {
284
-            return None;
338
+            return vec![];
285339
         }
286340
 
287341
         match direction {
288342
             Direction::Left => {
289
-                // Find output with minimum x (leftmost)
290
-                self.outputs.iter().min_by_key(|o| o.x).cloned()
343
+                // Find output with minimum x (leftmost) - single monitor
344
+                self.outputs.iter().min_by_key(|o| o.x).cloned().into_iter().collect()
291345
             }
292346
             Direction::Right => {
293
-                // Find output with maximum x + width (rightmost)
294
-                self.outputs.iter().max_by_key(|o| o.x + o.width as i32).cloned()
347
+                // Find output with maximum x + width (rightmost) - single monitor
348
+                self.outputs.iter().max_by_key(|o| o.x + o.width as i32).cloned().into_iter().collect()
295349
             }
296350
             Direction::Up => {
297
-                // Find output with minimum y (topmost)
298
-                self.outputs.iter().min_by_key(|o| o.y).cloned()
351
+                // Find ALL outputs at minimum y (all topmost monitors)
352
+                let min_y = self.outputs.iter().map(|o| o.y).min().unwrap_or(0);
353
+                self.outputs.iter().filter(|o| o.y == min_y).cloned().collect()
299354
             }
300355
             Direction::Down => {
301
-                // Find output with maximum y + height (bottommost)
302
-                self.outputs.iter().max_by_key(|o| o.y + o.height as i32).cloned()
356
+                // Find ALL outputs at maximum y + height (all bottommost monitors)
357
+                let max_bottom = self.outputs.iter().map(|o| o.y + o.height as i32).max().unwrap_or(0);
358
+                self.outputs.iter().filter(|o| o.y + o.height as i32 == max_bottom).cloned().collect()
303359
             }
304360
         }
305361
     }