Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0671abed8 | ||
|
|
569abe967f | ||
|
|
3e57efe312 | ||
|
|
2312e09105 |
@@ -135,12 +135,16 @@ preferred position controls where the hidden/kept boundary lands:
|
||||
hidden too; above ~300 app icons (Now Playing, TextInput) leak back.
|
||||
- `debug.spacerPos` (Double) overrides the seed for tuning without rebuilding.
|
||||
- Pressing a tray tile calls `MenuBarItemManager.press`. A hidden item sits
|
||||
off-screen, and its menu would open off-screen too, so press briefly
|
||||
`suspend()`s the hider, waits ~0.18s for the layout to settle, performs the
|
||||
accessibility action (`kAXPressAction`, then `kAXShowMenuAction`), and
|
||||
`resume()`s ~1s later. The reveal is momentary, not for the whole time the
|
||||
panel is open. macOS does not let us place or anchor another app's menu
|
||||
anywhere else, so a momentary reveal is the only way to show it in view.
|
||||
off-screen, and its menu opens off-screen too (verified with `--diag-press`:
|
||||
the menu window lands at negative x). So press briefly `suspend()`s the hider,
|
||||
waits ~0.2s for the layout to settle, performs the accessibility action
|
||||
(`kAXPressAction`, then `kAXShowMenuAction`), and `resume()`s ~0.1s later. The
|
||||
menu is its own window anchored at the item's on-screen spot, so it survives
|
||||
re-hiding.
|
||||
- **Cannot reveal a single icon.** The spacer hides a contiguous block to its
|
||||
left, so a press can only reveal the whole block. Isolating one item would
|
||||
need either per-item ordering control (not available) or covering the icons
|
||||
with an overlay window instead of moving them off-screen.
|
||||
- **Order matters**: `AppDelegate` must call `setupStatusItem()` *before*
|
||||
`MenuBarHider.shared.prepare()`. If the hider contracts the bar first, the
|
||||
hamburger is created into the collapsed space and lands off-screen.
|
||||
|
||||
@@ -48,6 +48,27 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
setupStatusItem()
|
||||
MenuBarHider.shared.prepare()
|
||||
|
||||
if CommandLine.arguments.contains("--diag-press") {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
|
||||
MenuBarHider.shared.suspend()
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2.25) {
|
||||
if let item = MenuBarItemManager.enumerate().first(where: {
|
||||
$0.title.lowercased().contains("wireguard")
|
||||
}) {
|
||||
NSLog("diag-press: pressing \(item.appName) after brief reveal")
|
||||
_ = AXUIElementPerformAction(item.element, kAXPressAction as CFString)
|
||||
}
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2.45) {
|
||||
MenuBarHider.shared.resume()
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) {
|
||||
dumpWindows()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if CommandLine.arguments.contains("--diag") {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) {
|
||||
dumpMenuBarItems()
|
||||
|
||||
@@ -117,10 +117,11 @@ final class MenuBarItemManager: ObservableObject {
|
||||
return
|
||||
}
|
||||
hider.suspend()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.18) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
||||
_ = self.performPress(item)
|
||||
// Let the menu finish appearing before the bar contracts again.
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
||||
// The menu is its own window, positioned at the item's on-screen
|
||||
// spot, so the bar can be re-hidden almost immediately.
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
hider.resume()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
import AppKit
|
||||
import ApplicationServices
|
||||
import CoreGraphics
|
||||
|
||||
/// Diagnostic used by `open SimpleTopBar.app --args --diag-press`. Presses a
|
||||
/// hidden item's accessibility element without revealing it and dumps the
|
||||
/// resulting high-level windows, to see where its menu actually opens.
|
||||
func dumpWindows() {
|
||||
var lines: [String] = []
|
||||
if let list = CGWindowListCopyWindowInfo([], kCGNullWindowID) as? [[String: Any]] {
|
||||
for window in list {
|
||||
let layer = window[kCGWindowLayer as String] as? Int ?? -1
|
||||
guard layer > 20 else { continue }
|
||||
let owner = window[kCGWindowOwnerName as String] as? String ?? "?"
|
||||
let bounds = window[kCGWindowBounds as String] as? [String: Any] ?? [:]
|
||||
let x = bounds["X"] as? Double ?? 0
|
||||
let y = bounds["Y"] as? Double ?? 0
|
||||
let width = bounds["Width"] as? Double ?? 0
|
||||
let height = bounds["Height"] as? Double ?? 0
|
||||
lines.append("\(owner) layer=\(layer) frame=\(Int(x)),\(Int(y)) \(Int(width))x\(Int(height))")
|
||||
}
|
||||
}
|
||||
try? lines.joined(separator: "\n").write(toFile: "/tmp/simpletopbar-windows.txt", atomically: true, encoding: .utf8)
|
||||
exit(0)
|
||||
}
|
||||
|
||||
/// Diagnostic used by `open SimpleTopBar.app --args --dump-items`. Writes the
|
||||
/// live Accessibility view of the menu bar to /tmp so it can be inspected
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
VERSION="${1:-0.2.3}"
|
||||
VERSION="${1:-0.4.1}"
|
||||
|
||||
swift build -c release
|
||||
|
||||
|
||||
Reference in New Issue
Block a user