oficina / meet Public

Clone
git clone https://amadan.net/oficina/meet

Plain git — no account needed to clone.

Download

Download this file

1#if os(macOS)
2 import AppKit
3 import SwiftUI
4
5 /// The mini window pressed as a person presses it, for CallsInterop's
6 /// --mini-clicks (2026-10-05, Paul: "Sometimes I can't click the mini
7 /// window"). A real panel, on screen, in an app that is not active (the
8 /// harness never activates), with a call behind it; presses made as
9 /// NSEvents and sent through the window, so AppKit's hit-testing, first
10 /// mouse, the surface's tracking loop and SwiftUI's buttons all take
11 /// part. What each press did is read from the actions it called and
12 /// from the window's frame. This Mac refuses screen capture and event
13 /// posting to this process, so these presses do not pass through the
14 /// window server; everything after it they do.
15 @_spi(Fixtures) @MainActor public enum MiniWindowProbe {
16 public struct Result: Sendable {
17 public let name: String
18 public let passed: Bool
19 public let detail: String
20 }
21
22 public static func run(call: Call) async -> [Result] {
23 var results: [Result] = []
24 for width in [MiniWindowRules.minimumWidth, MiniWindowRules.size.width, 480] {
25 results += await pressWindow(call: call, width: width)
26 }
27 results += await pressTab(call: call)
28 return results
29 }
30
31 static func trace(_ line: String) {
32 FileHandle.standardError.write(Data(("mini-clicks: " + line + "\n").utf8))
33 }
34
35 private final class Recorder {
36 var calls: [String] = []
37 }
38
39 private static func panel(call: Call, recorder: Recorder) -> MiniWindowPanel {
40 MiniWindowPanel(
41 call: call,
42 actions: MiniWindowActions(
43 leave: { recorder.calls.append("leave") },
44 open: { recorder.calls.append("open") },
45 moved: { option in recorder.calls.append(option ? "moved-option" : "moved") },
46 resized: { recorder.calls.append("resized") },
47 collapse: { recorder.calls.append("collapse") },
48 expand: { recorder.calls.append("expand") },
49 tabReleased: { recorder.calls.append("tabReleased") }))
50 }
51
52 private static func pressWindow(call: Call, width: CGFloat) async -> [Result] {
53 let recorder = Recorder()
54 let size = CGSize(width: width, height: width / MiniWindowRules.aspect)
55 let panel = panel(call: call, recorder: recorder)
56 let visible = NSScreen.main?.visibleFrame ?? CGRect(x: 0, y: 0, width: 1440, height: 900)
57 let home = CGRect(x: visible.midX - size.width / 2, y: visible.midY - size.height / 2, width: size.width, height: size.height)
58 panel.expand(to: home, animated: false)
59 panel.reassert(because: "probe")
60 try? await Task.sleep(for: .milliseconds(300))
61 var results: [Result] = []
62 let tag = "\(Int(width))"
63 trace("window \(tag) up at \(panel.frame)")
64 func check(_ name: String, _ expected: String, _ act: () async -> Void, frame: ((CGRect) -> Bool)? = nil) async {
65 panel.expand(to: home, animated: false)
66 recorder.calls = []
67 trace("\(tag) \(name)")
68 await act()
69 try? await Task.sleep(for: .milliseconds(80))
70 let got = recorder.calls.joined(separator: ",")
71 let frameOK = frame?(panel.frame) ?? true
72 results.append(
73 Result(
74 name: "\(tag) \(name)", passed: got == expected && frameOK,
75 detail: "expected \(expected), got [\(got)], frame \(panel.frame)"))
76 }
77 let w = size.width, h = size.height
78 // Hover off: the picture alone.
79 panel.content.hovering = false
80 try? await Task.sleep(for: .milliseconds(100))
81 await check("click in the middle brings the call forward", "open") { await click(panel, at: CGPoint(x: w / 2, y: h / 2)) }
82 await check("click on the name brings the call forward", "open") { await click(panel, at: CGPoint(x: 24, y: 16)) }
83 await check("click near the top left brings the call forward", "open") { await click(panel, at: CGPoint(x: 20, y: h - 20)) }
84 await check("a shaky click is still a click", "open") {
85 await press(panel, from: CGPoint(x: w / 2, y: h / 2), by: CGSize(width: 3, height: -2))
86 }
87 await check("a drag from the middle moves it", "moved", {
88 await press(panel, from: CGPoint(x: w / 2, y: h / 2), by: CGSize(width: 60, height: -40))
89 }, frame: { abs($0.minX - (home.minX + 60)) < 1 && abs($0.minY - (home.minY - 40)) < 1 })
90 await check("a drag from the right edge resizes it", "resized", {
91 await press(panel, from: CGPoint(x: w - 3, y: h / 2), by: CGSize(width: 40, height: 0))
92 }, frame: { $0.width > w + 20 || w >= MiniWindowRules.size(width: 10_000, in: visible).width })
93 await check("a drag from the bottom left corner resizes it", "resized", {
94 await press(panel, from: CGPoint(x: 3, y: 3), by: CGSize(width: -30, height: -20))
95 }, frame: { $0.width > w + 10 || w >= MiniWindowRules.size(width: 10_000, in: visible).width })
96 // Marks over the picture are not controls: muted, and someone
97 // still connecting (the ear), a press on them is the window's.
98 call.showFixtureSelf(muted: true, cameraOff: false, sharingScreen: false)
99 call.showFixtureConnecting(["li"])
100 try? await Task.sleep(for: .milliseconds(200))
101 await check("click on the Muted mark brings the call forward", "open") { await click(panel, at: CGPoint(x: 10 + 16, y: h - 10 - 16)) }
102 await check("click on the connecting ear brings the call forward", "open") { await click(panel, at: CGPoint(x: w - 10 - 16, y: h - 10 - 16)) }
103 await check("a drag from the Muted mark moves it", "moved") {
104 await press(panel, from: CGPoint(x: 10 + 16, y: h - 10 - 16), by: CGSize(width: -50, height: -30))
105 }
106 call.showFixtureSelf(muted: false, cameraOff: false, sharingScreen: false)
107 call.showFixtureConnecting([])
108 // Hover on: the controls (44 pt, 8 apart, 10 in from the top right:
109 // Collapse, Mute, Leave) answer the first click.
110 panel.content.hovering = true
111 try? await Task.sleep(for: .milliseconds(200))
112 let row = h - 10 - 22
113 await check("first click on Leave", "leave") { await click(panel, at: CGPoint(x: w - 10 - 22, y: row), control: true) }
114 await check("first click on Collapse", "collapse") { await click(panel, at: CGPoint(x: w - 10 - 44 - 8 - 44 - 8 - 22, y: row), control: true) }
115 let before = call.muted
116 await click(panel, at: CGPoint(x: w - 10 - 44 - 8 - 22, y: row), control: true)
117 try? await Task.sleep(for: .milliseconds(80))
118 results.append(Result(name: "\(tag) first click on Mute", passed: call.muted != before, detail: "muted \(before) -> \(call.muted)"))
119 if call.muted != before { call.showFixtureSelf(muted: before, cameraOff: false, sharingScreen: false) }
120 await check("click in the middle with the controls up", "open") { await click(panel, at: CGPoint(x: w / 2, y: h / 2)) }
121 panel.dismiss()
122 return results
123 }
124
125 private static func pressTab(call: Call) async -> [Result] {
126 let recorder = Recorder()
127 let panel = panel(call: call, recorder: recorder)
128 let visible = NSScreen.main?.visibleFrame ?? CGRect(x: 0, y: 0, width: 1440, height: 900)
129 let expanded = CGRect(origin: CGPoint(x: visible.maxX - 340, y: visible.minY + 20), size: MiniWindowRules.size)
130 let tab = MiniWindowTab.dock(expanded, in: visible).1
131 var results: [Result] = []
132 func reset() {
133 panel.collapse(to: tab, expanded: expanded)
134 recorder.calls = []
135 }
136 reset()
137 panel.reassert(because: "probe")
138 try? await Task.sleep(for: .milliseconds(300))
139 let middle = CGPoint(x: tab.width / 2, y: tab.height / 2)
140 await click(panel, at: middle)
141 try? await Task.sleep(for: .milliseconds(80))
142 results.append(Result(name: "tab click opens the window", passed: recorder.calls == ["expand"], detail: "\(recorder.calls)"))
143 reset()
144 await click(panel, at: middle, count: 2)
145 try? await Task.sleep(for: .milliseconds(80))
146 results.append(Result(name: "tab double click opens the call", passed: recorder.calls.last == "open", detail: "\(recorder.calls)"))
147 reset()
148 await press(panel, from: CGPoint(x: 3, y: middle.y), by: CGSize(width: -120, height: 30))
149 try? await Task.sleep(for: .milliseconds(80))
150 results.append(Result(name: "tab drag, even from its edge, is a drag", passed: recorder.calls == ["tabReleased"], detail: "\(recorder.calls)"))
151 panel.dismiss()
152 return results
153 }
154
155 private static func click(_ panel: NSWindow, at point: CGPoint, count: Int = 1, control: Bool = false) async {
156 for n in 1...count {
157 await press(panel, from: point, by: .zero, clickCount: n, control: control)
158 }
159 }
160
161 /// A press at `point` in the window, moved by `by` in steps, released:
162 /// the down sent through the window as AppKit would, the drags and
163 /// the up queued for the surface's tracking loop, in screen points.
164 /// A control's up goes to the window, where SwiftUI's button reads it;
165 /// the surface's tracking loop reads screen points from window-less
166 /// events (SurfaceView.screenLocation).
167 private static func press(
168 _ panel: NSWindow, from point: CGPoint, by: CGSize, clickCount: Int = 1, control: Bool = false
169 ) async {
170 let screenStart = panel.convertPoint(toScreen: point)
171 let now = ProcessInfo.processInfo.systemUptime
172 func event(_ type: NSEvent.EventType, at location: CGPoint, window: Bool) -> NSEvent? {
173 NSEvent.mouseEvent(
174 with: type, location: location, modifierFlags: [], timestamp: now,
175 windowNumber: window ? panel.windowNumber : 0, context: nil, eventNumber: 0,
176 clickCount: clickCount, pressure: type == .leftMouseUp ? 0 : 1)
177 }
178 let steps = by == .zero ? 0 : 5
179 for i in stride(from: 1, through: steps, by: 1) {
180 let f = CGFloat(i) / CGFloat(steps)
181 if let drag = event(.leftMouseDragged, at: CGPoint(x: screenStart.x + by.width * f, y: screenStart.y + by.height * f), window: false) {
182 NSApp.postEvent(drag, atStart: false)
183 }
184 }
185 if control, let up = event(.leftMouseUp, at: point, window: true) {
186 NSApp.postEvent(up, atStart: false)
187 } else if let up = event(.leftMouseUp, at: CGPoint(x: screenStart.x + by.width, y: screenStart.y + by.height), window: false) {
188 NSApp.postEvent(up, atStart: false)
189 }
190 if let down = event(.leftMouseDown, at: point, window: true) { panel.sendEvent(down) }
191 // A SwiftUI button acts on the up, which it reads from the queue
192 // itself; let the run loop turn.
193 try? await Task.sleep(for: .milliseconds(60))
194 }
195 }
196#endif
197