Dock-Eintrag nur solange ein Fenster offen ist

Im Hintergrund gehört Onyx nicht in den Dock — es hat kein Fenster, das ein
Klick öffnen könnte. Mit sichtbarem Einstellungsfenster ist das Gegenteil
richtig: als reine .accessory-App lässt sich das Fenster weder über den Dock
noch über ⌘-Tab zurückholen, wenn es hinter etwas anderes rutscht.

Deshalb wird beim Öffnen auf .regular geschaltet und beim Schließen zurück —
außer der Dock-Eintrag ist in den Einstellungen ausdrücklich gewünscht.

Das generische weiße Symbol im Dock kam nicht aus dem Bundle: CFBundleIconName,
CFBundleIconFile, AppIcon.icns und der Assets-Katalog waren alle in Ordnung.
Es war der Icon-Cache von Launch Services, der die App von den vielen Starts
her kannte, als es noch gar kein Icon gab. Neu registriert und Cache verworfen.
This commit is contained in:
Guido Schmit
2026-08-10 21:29:09 +02:00
parent c0874c83b7
commit a198d88104
3 changed files with 368 additions and 339 deletions

View File

@@ -1,7 +1,17 @@
{ {
"fill" : { "fill-specializations" : [
"automatic-gradient" : "display-p3:0.21900,0.30045,0.61471,1.00000" {
}, "value" : {
"automatic-gradient" : "display-p3:0.21900,0.30045,0.61471,1.00000"
}
},
{
"appearance" : "dark",
"value" : {
"automatic-gradient" : "display-p3:0.12445,0.17422,0.36459,1.00000"
}
}
],
"groups" : [ "groups" : [
{ {
"layers" : [ "layers" : [

View File

@@ -1,523 +1,526 @@
{ {
"sourceLanguage": "en", "sourceLanguage" : "en",
"strings": { "strings" : {
"menu.openPanel": { "menu.openPanel" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Panel öffnen" "value" : "Panel öffnen"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Open Panel" "value" : "Open Panel"
} }
} }
} }
}, },
"menu.quit": { "menu.quit" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Onyx beenden" "value" : "Onyx beenden"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Quit Onyx" "value" : "Quit Onyx"
} }
} }
} }
}, },
"menu.settings": { "menu.settings" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Einstellungen …" "value" : "Einstellungen …"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Settings…" "value" : "Settings…"
} }
} }
} }
}, },
"settings.display.all": { "settings.display.all" : {
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Allen Displays" "value" : "Allen Displays"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "All displays" "value" : "All displays"
} }
} }
} }
}, },
"settings.display.builtInOnly": { "settings.display.builtInOnly" : {
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Nur dem internen Display" "value" : "Nur dem internen Display"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Built-in display only" "value" : "Built-in display only"
} }
} }
} }
}, },
"settings.display.hint": { "settings.display.dockIcon" : {
"localizations": { "extractionState" : "stale",
"de": { "localizations" : {
"stringUnit": { "de" : {
"state": "translated", "stringUnit" : {
"value": "Auf Displays ohne echte Notch erscheint oben mittig ein Balken, der sich genauso verhält. Ist der Deckel geschlossen und kein internes Display vorhanden, erscheint das Panel trotzdem auf einem externen — sonst wäre Onyx nicht erreichbar." "state" : "translated",
"value" : "Symbol im Dock anzeigen"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "On displays without a real notch, a bar appears at the top centre and behaves the same. With the lid closed and no built-in display present, the panel still appears on an external one — otherwise Onyx would be unreachable." "value" : "Show icon in the Dock"
} }
} }
} }
}, },
"settings.display.menuBarIcon": { "settings.display.dockIcon.hint" : {
"extractionState": "stale", "localizations" : {
"localizations": { "de" : {
"de": { "stringUnit" : {
"stringUnit": { "state" : "translated",
"state": "translated", "value" : "Standardmäßig aus. Onyx lebt in der Notch und in der Menüleiste und hat kein Hauptfenster — im Dock wäre es ein Symbol, das beim Anklicken nichts öffnet, und es stünde im Programmumschalter zwischen den Programmen, mit denen du arbeitest."
"value": "Symbol in der Menüleiste anzeigen"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Show icon in the menu bar" "value" : "Off by default. Onyx lives in the notch and the menu bar and has no main window — in the Dock it would be an icon that opens nothing, and it would sit in the app switcher among the apps you actually work with."
} }
} }
} }
}, },
"settings.display.menuBarIcon.hint": { "settings.display.hint" : {
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Über das Symbol erreichst du Panel, Einstellungen und Beenden. Ohne es kommst du nur über die Notch an Onyx heran." "value" : "Auf Displays ohne echte Notch erscheint oben mittig ein Balken, der sich genauso verhält. Ist der Deckel geschlossen und kein internes Display vorhanden, erscheint das Panel trotzdem auf einem externen — sonst wäre Onyx nicht erreichbar."
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "The icon gives you the panel, settings and quit. Without it, the notch is the only way to reach Onyx." "value" : "On displays without a real notch, a bar appears at the top centre and behaves the same. With the lid closed and no built-in display present, the panel still appears on an external one — otherwise Onyx would be unreachable."
} }
} }
} }
}, },
"settings.display.policy": { "settings.display.menuBarIcon" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Panel anzeigen auf" "value" : "Symbol in der Menüleiste anzeigen"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Show panel on" "value" : "Show icon in the menu bar"
} }
} }
} }
}, },
"settings.permissions.calendar": { "settings.display.menuBarIcon.hint" : {
"extractionState": "stale", "localizations" : {
"localizations": { "de" : {
"de": { "stringUnit" : {
"stringUnit": { "state" : "translated",
"state": "translated", "value" : "Über das Symbol erreichst du Panel, Einstellungen und Beenden. Ohne es kommst du nur über die Notch an Onyx heran."
"value": "Kalender"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Calendar" "value" : "The icon gives you the panel, settings and quit. Without it, the notch is the only way to reach Onyx."
} }
} }
} }
}, },
"settings.permissions.calendar.why": { "settings.display.policy" : {
"localizations": { "extractionState" : "stale",
"de": { "localizations" : {
"stringUnit": { "de" : {
"state": "translated", "stringUnit" : {
"value": "Onyx zeigt deine Termine im Kalender-Widget an. Es wird ausschließlich gelesen, nie geschrieben." "state" : "translated",
"value" : "Panel anzeigen auf"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Onyx shows your events in the calendar widget. It only ever reads, never writes." "value" : "Show panel on"
} }
} }
} }
}, },
"settings.permissions.granted": { "settings.permissions.calendar" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Erteilt" "value" : "Kalender"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Granted" "value" : "Calendar"
} }
} }
} }
}, },
"settings.permissions.location": { "settings.permissions.calendar.why" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Standort" "value" : "Onyx zeigt deine Termine im Kalender-Widget an. Es wird ausschließlich gelesen, nie geschrieben."
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Location" "value" : "Onyx shows your events in the calendar widget. It only ever reads, never writes."
} }
} }
} }
}, },
"settings.permissions.location.why": { "settings.permissions.granted" : {
"localizations": { "extractionState" : "stale",
"de": { "localizations" : {
"stringUnit": { "de" : {
"state": "translated", "stringUnit" : {
"value": "Onyx zeigt das Wetter an deinem aktuellen Standort. Ohne Zugriff kannst du stattdessen einen festen Ort wählen." "state" : "translated",
"value" : "Erteilt"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Onyx shows the weather for your current location. Without access you can pick a fixed place instead." "value" : "Granted"
} }
} }
} }
}, },
"settings.permissions.openSystem": { "settings.permissions.location" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Systemeinstellungen öffnen" "value" : "Standort"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Open System Settings" "value" : "Location"
} }
} }
} }
}, },
"settings.permissions.request": { "settings.permissions.location.why" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Anfragen" "value" : "Onyx zeigt das Wetter an deinem aktuellen Standort. Ohne Zugriff kannst du stattdessen einen festen Ort wählen."
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Request" "value" : "Onyx shows the weather for your current location. Without access you can pick a fixed place instead."
} }
} }
} }
}, },
"settings.size.large": { "settings.permissions.openSystem" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Groß (2×2)" "value" : "Systemeinstellungen öffnen"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Large (2×2)" "value" : "Open System Settings"
} }
} }
} }
}, },
"settings.size.medium": { "settings.permissions.request" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Mittel (2×1)" "value" : "Anfragen"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Medium (2×1)" "value" : "Request"
} }
} }
} }
}, },
"settings.size.small": { "settings.size.large" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Klein (1×1)" "value" : "Groß (2×2)"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Small (1×1)" "value" : "Large (2×2)"
} }
} }
} }
}, },
"settings.size.wide": { "settings.size.medium" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Breit (4×1)" "value" : "Mittel (2×1)"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Wide (4×1)" "value" : "Medium (2×1)"
} }
} }
} }
}, },
"settings.tab.display": { "settings.size.small" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Anzeige" "value" : "Klein (1×1)"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Display" "value" : "Small (1×1)"
} }
} }
} }
}, },
"settings.tab.permissions": { "settings.size.wide" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Berechtigungen" "value" : "Breit (4×1)"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Permissions" "value" : "Wide (4×1)"
} }
} }
} }
}, },
"settings.tab.widgets": { "settings.tab.display" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Widgets" "value" : "Anzeige"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Widgets" "value" : "Display"
} }
} }
} }
}, },
"settings.widgets.add": { "settings.tab.permissions" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Hinzufügen" "value" : "Berechtigungen"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Add" "value" : "Permissions"
} }
} }
} }
}, },
"settings.widgets.available": { "settings.tab.widgets" : {
"extractionState": "stale", "extractionState" : "stale",
"localizations": { "localizations" : {
"de": { "de" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Verfügbar" "value" : "Widgets"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Available" "value" : "Widgets"
} }
} }
} }
}, },
"settings.widgets.empty": { "settings.widgets.add" : {
"localizations": { "extractionState" : "stale",
"de": { "localizations" : {
"stringUnit": { "de" : {
"state": "translated", "stringUnit" : {
"value": "Keine Widgets im Panel. Das Panel bleibt leer, bis du eins hinzufügst." "state" : "translated",
"value" : "Hinzufügen"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "No widgets in the panel. It stays empty until you add one." "value" : "Add"
} }
} }
} }
}, },
"settings.widgets.hint": { "settings.widgets.available" : {
"localizations": { "extractionState" : "stale",
"de": { "localizations" : {
"stringUnit": { "de" : {
"state": "translated", "stringUnit" : {
"value": "Die Reihenfolge bestimmt die Anordnung im Panel. Jedes Widget rückt an die erste Stelle, an die es passt." "state" : "translated",
"value" : "Verfügbar"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "The order determines the arrangement in the panel. Each widget takes the first spot it fits into." "value" : "Available"
} }
} }
} }
}, },
"settings.widgets.inPanel": { "settings.widgets.empty" : {
"extractionState": "stale", "localizations" : {
"localizations": { "de" : {
"de": { "stringUnit" : {
"stringUnit": { "state" : "translated",
"state": "translated", "value" : "Keine Widgets im Panel. Das Panel bleibt leer, bis du eins hinzufügst."
"value": "Im Panel"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "In the panel" "value" : "No widgets in the panel. It stays empty until you add one."
} }
} }
} }
}, },
"settings.widgets.remove": { "settings.widgets.hint" : {
"extractionState": "stale", "localizations" : {
"localizations": { "de" : {
"de": { "stringUnit" : {
"stringUnit": { "state" : "translated",
"state": "translated", "value" : "Die Reihenfolge bestimmt die Anordnung im Panel. Jedes Widget rückt an die erste Stelle, an die es passt."
"value": "Aus dem Panel entfernen"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Remove from panel" "value" : "The order determines the arrangement in the panel. Each widget takes the first spot it fits into."
} }
} }
} }
}, },
"settings.display.dockIcon": { "settings.widgets.inPanel" : {
"localizations": { "extractionState" : "stale",
"de": { "localizations" : {
"stringUnit": { "de" : {
"state": "translated", "stringUnit" : {
"value": "Symbol im Dock anzeigen" "state" : "translated",
"value" : "Im Panel"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Show icon in the Dock" "value" : "In the panel"
} }
} }
} }
}, },
"settings.display.dockIcon.hint": { "settings.widgets.remove" : {
"localizations": { "extractionState" : "stale",
"de": { "localizations" : {
"stringUnit": { "de" : {
"state": "translated", "stringUnit" : {
"value": "Standardmäßig aus. Onyx lebt in der Notch und in der Menüleiste und hat kein Hauptfenster — im Dock wäre es ein Symbol, das beim Anklicken nichts öffnet, und es stünde im Programmumschalter zwischen den Programmen, mit denen du arbeitest." "state" : "translated",
"value" : "Aus dem Panel entfernen"
} }
}, },
"en": { "en" : {
"stringUnit": { "stringUnit" : {
"state": "translated", "state" : "translated",
"value": "Off by default. Onyx lives in the notch and the menu bar and has no main window — in the Dock it would be an icon that opens nothing, and it would sit in the app switcher among the apps you actually work with." "value" : "Remove from panel"
} }
} }
} }
} }
}, },
"version": "1.0" "version" : "1.0"
} }

View File

@@ -20,9 +20,22 @@ final class SettingsWindowController: NSObject, NSWindowDelegate {
/// Muss außerhalb der View liegen, damit ein erneutes Öffnen den Reiter setzen kann. /// Muss außerhalb der View liegen, damit ein erneutes Öffnen den Reiter setzen kann.
private var selectedTab: SettingsTab = .widgets private var selectedTab: SettingsTab = .widgets
/// Ob Onyx dauerhaft im Dock steht. Bestimmt, wohin nach dem Schließen
/// zurückgeschaltet wird.
var keepsDockIcon = false
func show(model: AppModel, calendarModel: CalendarModel, weatherModel: WeatherModel, func show(model: AppModel, calendarModel: CalendarModel, weatherModel: WeatherModel,
tab: SettingsTab = .widgets) { tab: SettingsTab = .widgets) {
selectedTab = tab selectedTab = tab
keepsDockIcon = model.showsDockIcon
// Solange ein Fenster offen ist, gehört Onyx in den Dock.
//
// Als reine `.accessory`-App hat sie dort keinen Eintrag das ist im
// Hintergrund richtig, aber mit sichtbarem Fenster verwirrend: das
// Fenster lässt sich dann weder über den Dock noch über -Tab
// zurückholen, wenn es hinter etwas anderes rutscht.
NSApp.setActivationPolicy(.regular)
if window == nil { if window == nil {
let hosting = NSHostingController( let hosting = NSHostingController(
@@ -52,8 +65,11 @@ final class SettingsWindowController: NSObject, NSWindowDelegate {
} }
func windowWillClose(_ notification: Notification) { func windowWillClose(_ notification: Notification) {
// Zurück in den Hintergrund: Onyx hat sonst weiter den Fokus, obwohl // Zurück in den Hintergrund es sei denn, der Dock-Eintrag ist
// kein Fenster mehr offen ist. // ausdrücklich gewünscht.
if !keepsDockIcon {
NSApp.setActivationPolicy(.accessory)
}
NSApp.hide(nil) NSApp.hide(nil)
} }
} }