linux observer
at main 110 lines 3.3 kB view raw
1# SPDX-License-Identifier: AGPL-3.0-only 2# Copyright (c) 2026 sol pbc 3 4"""Monitor position assignment based on geometry. 5 6Extracted from solstone's observe/utils.py — the assign_monitor_positions() 7function only. Also remains in solstone core (used by server-side naming). 8""" 9 10from __future__ import annotations 11 12 13def assign_monitor_positions(monitors: list[dict]) -> list[dict]: 14 """ 15 Assign position labels to monitors based on relative positions. 16 17 Uses pairwise comparison to determine positions. Vertical labels (top/bottom) 18 are only assigned when monitors actually overlap horizontally, avoiding 19 phantom relationships from offset monitors. 20 21 Parameters 22 ---------- 23 monitors : list[dict] 24 List of monitor dicts, each with keys: 25 - id: Monitor identifier (e.g., "DP-3", "HDMI-1") 26 - box: [x1, y1, x2, y2] coordinates 27 28 Returns 29 ------- 30 list[dict] 31 Same monitors with "position" key added to each: 32 - "center": No monitors on both sides 33 - "left"/"right": Horizontal position 34 - "top"/"bottom": Vertical position (only with horizontal overlap) 35 - "left-top", "right-bottom", etc.: Corner positions 36 """ 37 if not monitors: 38 return [] 39 40 if len(monitors) == 1: 41 monitors[0]["position"] = "center" 42 return monitors 43 44 # Tolerance for center classification 45 epsilon = 1 46 47 for m in monitors: 48 x1, y1, x2, y2 = m["box"] 49 center_x = (x1 + x2) / 2 50 center_y = (y1 + y2) / 2 51 52 has_left = False 53 has_right = False 54 has_above = False 55 has_below = False 56 57 for other in monitors: 58 if other is m: 59 continue 60 61 ox1, oy1, ox2, oy2 = other["box"] 62 other_center_x = (ox1 + ox2) / 2 63 other_center_y = (oy1 + oy2) / 2 64 65 # Horizontal relationship (always check) 66 if other_center_x < center_x - epsilon: 67 has_left = True 68 elif other_center_x > center_x + epsilon: 69 has_right = True 70 71 # Vertical relationship only if horizontal overlap exists 72 # Overlap means ranges intersect (not just touch) 73 h_overlap = (x1 < ox2) and (x2 > ox1) 74 if h_overlap: 75 if other_center_y < center_y - epsilon: 76 has_above = True 77 elif other_center_y > center_y + epsilon: 78 has_below = True 79 80 # Determine horizontal label 81 if has_left and has_right: 82 h_pos = "center" 83 elif has_left: 84 h_pos = "right" 85 elif has_right: 86 h_pos = "left" 87 else: 88 h_pos = "center" 89 90 # Determine vertical label (only if monitors above/below with overlap) 91 if has_above and has_below: 92 v_pos = "middle" 93 elif has_above: 94 v_pos = "bottom" 95 elif has_below: 96 v_pos = "top" 97 else: 98 v_pos = None 99 100 # Combine positions 101 if v_pos is None: 102 position = h_pos 103 elif h_pos == "center": 104 position = v_pos 105 else: 106 position = f"{h_pos}-{v_pos}" 107 108 m["position"] = position 109 110 return monitors