[object Object]

← back to Ticket System

Keep ticket controls visible across app focus

b3088eee99f9ebd4692924520e6a5682904f19f2 · 2026-09-02 16:10:45 -0700 · Steve Abrams

Files touched

Diff

commit b3088eee99f9ebd4692924520e6a5682904f19f2
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Sep 2 16:10:45 2026 -0700

    Keep ticket controls visible across app focus
---
 desktop-bar/TicketBar.swift | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/desktop-bar/TicketBar.swift b/desktop-bar/TicketBar.swift
index f64bac03..6827d199 100644
--- a/desktop-bar/TicketBar.swift
+++ b/desktop-bar/TicketBar.swift
@@ -238,20 +238,22 @@ private final class BarController: NSObject, NSApplicationDelegate, NSWindowDele
   private func openTicketPopup() {
     NSLog("TicketBar opening control window")
     if let ticketPopup {
-      centerOnPointerScreen(ticketPopup)
+      centerOnBarScreen(ticketPopup)
       ticketPopup.makeKeyAndOrderFront(nil)
       ticketPopup.orderFrontRegardless()
       NSApp.activate(ignoringOtherApps: true)
       return
     }
     let size = NSSize(width: 1480, height: 860)
-    let popup = NSWindow(contentRect: NSRect(origin: .zero, size: size), styleMask: [.titled, .closable, .resizable, .miniaturizable], backing: .buffered, defer: false)
+    let popup = NSPanel(contentRect: NSRect(origin: .zero, size: size), styleMask: [.titled, .closable, .resizable, .miniaturizable, .nonactivatingPanel], backing: .buffered, defer: false)
     popup.title = "Fleet Ticket Control · All / Open / Blocked / Doing"
     popup.level = .statusBar
     popup.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
     popup.minSize = NSSize(width: 900, height: 560)
     popup.isReleasedWhenClosed = false
     popup.hidesOnDeactivate = false
+    popup.isFloatingPanel = true
+    popup.becomesKeyOnlyIfNeeded = false
     popup.delegate = self
     let web = WKWebView(frame: popup.contentView?.bounds ?? .zero)
     web.navigationDelegate = self
@@ -261,8 +263,9 @@ private final class BarController: NSObject, NSApplicationDelegate, NSWindowDele
     // a one-off Authorization header would authenticate the HTML navigation but
     // leave the board's same-origin fetch() calls unauthenticated and blank.
     web.load(URLRequest(url: viewerURL))
-    centerOnPointerScreen(popup)
+    centerOnBarScreen(popup)
     ticketPopup = popup
+    panel.addChildWindow(popup, ordered: .above)
     popup.makeKeyAndOrderFront(nil)
     popup.orderFrontRegardless()
     NSApp.activate(ignoringOtherApps: true)
@@ -270,14 +273,12 @@ private final class BarController: NSObject, NSApplicationDelegate, NSWindowDele
 
   func windowWillClose(_ notification: Notification) {
     guard let closing = notification.object as? NSWindow, closing === ticketPopup else { return }
+    panel.removeChildWindow(closing)
     ticketPopup = nil
   }
 
-  private func centerOnPointerScreen(_ window: NSWindow) {
-    let pointer = NSEvent.mouseLocation
-    let screen = NSScreen.screens.first(where: { NSMouseInRect(pointer, $0.frame, false) })
-      ?? NSScreen.main
-      ?? NSScreen.screens.first
+  private func centerOnBarScreen(_ window: NSWindow) {
+    let screen = panel.screen ?? NSScreen.main ?? NSScreen.screens.first
     guard let visible = screen?.visibleFrame else { window.center(); return }
     let width = min(window.frame.width, visible.width - 40)
     let height = min(window.frame.height, visible.height - 40)
@@ -287,6 +288,7 @@ private final class BarController: NSObject, NSApplicationDelegate, NSWindowDele
       width: width,
       height: height
     ), display: true)
+    NSLog("TicketBar control frame %@ on bar screen %@", NSStringFromRect(window.frame), NSStringFromRect(visible))
   }
 
   func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

← 35f0880e Record desktop ticket bar interaction proof  ·  back to Ticket System  ·  Update ticket bar focus proof 2600bc9e →