diff --git a/patches/oriontoolbar_visibility_foreground_fix.py b/patches/oriontoolbar_visibility_foreground_fix.py new file mode 100644 index 0000000..402913a --- /dev/null +++ b/patches/oriontoolbar_visibility_foreground_fix.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +"""Fix OrionToolbar service visibility and foreground activation, preserving other UI.""" +from pathlib import Path +from datetime import datetime +import shutil + +root = Path.cwd() +controller = root / 'OrionToolbar/OrionVMController.swift' +view = root / 'OrionToolbar/OrionMenuView.swift' +if not controller.exists() or not view.exists(): + raise SystemExit('Run from the OrionToolbar project root. No changes made.') +c = controller.read_text() +v = view.read_text() + +def swap(src, old, new, count, label): + found = src.count(old) + if found != count: + raise ValueError(f'{label}: expected {count} matches, found {found}') + return src.replace(old, new) + +try: + # Keep both the startup and timer paths checking actual services. + c = swap(c, 'await discoverVMs()\n await refreshAll()', + 'await discoverVMs()\n await refreshAll()\n await refreshServiceAvailability()', 1, 'initial refresh') + c = swap(c, 'await self.discoverVMs(); await self.refreshAll()', + 'await self.discoverVMs(); await self.refreshAll(); await self.refreshServiceAvailability()', 1, 'timer refresh') + + # Use the observed probe results, never just the existence of settings. + v = swap(v, 'if !server.host.isEmpty && !server.sshUser.isEmpty {', + 'if !server.host.isEmpty && !server.sshUser.isEmpty && vm.reachableSSH.contains(server.id) {', 2, 'SSH visibility') + v = swap(v, 'if !server.host.isEmpty && server.mailpitPort != nil {', + 'if !server.host.isEmpty && server.mailpitPort != nil && vm.reachableMailpit.contains(server.id) {', 2, 'Mailpit visibility') + + # Hide the menu bar panel *before* launching other apps. Activate the target + # again shortly afterwards to prevent the menu-bar panel stealing focus. + c = swap(c, ' func openSSH(_ s: ServerDefinition) {', + ' func openSSH(_ s: ServerDefinition) {\n NSApp.hide(nil)', 1, 'SSH panel dismissal') + old = ''' NSWorkspace.shared.open([scriptURL], withApplicationAt: terminalURL, configuration: configuration) { _, error in + Task { @MainActor in + if let error { self.lastError = "Could not open Terminal: \\(error.localizedDescription)" } + } + }''' + new = ''' NSWorkspace.shared.open([scriptURL], withApplicationAt: terminalURL, configuration: configuration) { application, error in + Task { @MainActor in + if let error { + self.lastError = "Could not open Terminal: \\(error.localizedDescription)" + } else { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) { + application?.activate(options: [.activateAllWindows]) + } + } + } + }''' + c = swap(c, old, new, 1, 'Terminal foreground') + old = ' func openMailpit(_ s: ServerDefinition) { if let p = s.mailpitPort, let url = URL(string: "http://\\(s.host):\\(p)") { NSWorkspace.shared.open(url) } }' + new = ''' func openMailpit(_ s: ServerDefinition) { + guard let p = s.mailpitPort, + let url = URL(string: "http://\\(s.host):\\(p)") else { return } + NSApp.hide(nil) + let browserURL = NSWorkspace.shared.urlForApplication(toOpen: url) + NSWorkspace.shared.open(url) + if let browserURL { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) { + let browser = NSWorkspace.shared.runningApplications.first { + $0.bundleURL == browserURL + } + browser?.activate(options: [.activateAllWindows]) + } + } + }''' + c = swap(c, old, new, 1, 'browser foreground') +except ValueError as error: + raise SystemExit(f'Patch not applied: {error}. No files changed.') + +stamp = datetime.now().strftime('%Y%m%d-%H%M%S') +for path, updated in ((controller, c), (view, v)): + backup = root / 'backups' / f'services-focus-{stamp}' / path.relative_to(root) + backup.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(path, backup) + path.write_text(updated) + print(f'Updated: {path.relative_to(root)}; backup: {backup.relative_to(root)}') +print('Done. Build using: /bin/zsh scripts/build.sh --launch')