make Theme monitor dependent
This commit is contained in:
@@ -7,18 +7,19 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
private var observers: [IPCObserver] = []
|
private var observers: [IPCObserver] = []
|
||||||
|
|
||||||
/// Create one bar controller per screen. Each screen resolves its own
|
/// Create one bar controller per screen. Each screen resolves its own
|
||||||
/// window and block set from the config, so refresh state and layout stay
|
/// theme, window and block set from the config, so refresh state and layout stay
|
||||||
/// independent across monitors.
|
/// independent across monitors.
|
||||||
init(
|
init(
|
||||||
config: PHConfig,
|
config: PHConfig,
|
||||||
screens: [NSScreen],
|
screens: [NSScreen],
|
||||||
theme: PHTheme,
|
|
||||||
debug: Bool
|
debug: Bool
|
||||||
) throws {
|
) throws {
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
for screen in screens {
|
for screen in screens {
|
||||||
|
let theme = try PHTheme.load(config.theme(for: screen))
|
||||||
let blocks = try PHBlock.load(config.blocks(for: screen))
|
let blocks = try PHBlock.load(config.blocks(for: screen))
|
||||||
|
|
||||||
controllers.append(
|
controllers.append(
|
||||||
BarController(
|
BarController(
|
||||||
config: config,
|
config: config,
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ extension phbar {
|
|||||||
|
|
||||||
mutating func run() throws {
|
mutating func run() throws {
|
||||||
let config = try PHConfig.load()
|
let config = try PHConfig.load()
|
||||||
let theme = try PHTheme.load("voltage")
|
|
||||||
|
|
||||||
// NOTE: Make sure NSApp.run() runs in the main thread
|
// NOTE: Make sure NSApp.run() runs in the main thread
|
||||||
dispatchPrecondition(condition: .onQueue(.main))
|
dispatchPrecondition(condition: .onQueue(.main))
|
||||||
@@ -28,7 +27,6 @@ extension phbar {
|
|||||||
let delegate = try AppDelegate(
|
let delegate = try AppDelegate(
|
||||||
config: config,
|
config: config,
|
||||||
screens: screens,
|
screens: screens,
|
||||||
theme: theme,
|
|
||||||
debug: debug
|
debug: debug
|
||||||
)
|
)
|
||||||
let app = NSApplication.shared
|
let app = NSApplication.shared
|
||||||
|
|||||||
@@ -1,43 +1,12 @@
|
|||||||
struct PHConfig: Decodable {
|
struct PHConfig: Decodable {
|
||||||
|
let theme: String
|
||||||
let window: String
|
let window: String
|
||||||
let blocks: String?
|
let blocks: String?
|
||||||
let env: [String: String]?
|
let env: [String: String]?
|
||||||
let monitors: [String: PHMonitorOverride]?
|
let monitors: [String: PHConfigMonitorOverride]?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case window, blocks, env
|
case theme, window, blocks, env
|
||||||
case monitors = "monitor"
|
case monitors = "monitor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A per-monitor entry from the config's `[monitor]` table.
|
|
||||||
///
|
|
||||||
/// Either field is optional; an unset field inherits the matching global
|
|
||||||
/// (`window` or `blocks`) so a monitor can override just one of the two.
|
|
||||||
struct PHMonitorOverride: Decodable {
|
|
||||||
let window: String?
|
|
||||||
let blocks: String?
|
|
||||||
}
|
|
||||||
|
|
||||||
extension PHConfig {
|
|
||||||
/// The override matching a screen identifier, if any.
|
|
||||||
/// Pure (no AppKit). Precedence: monitor name → monitor index.
|
|
||||||
func monitorOverride(screenName: String, screenIndex: Int?) -> PHMonitorOverride? {
|
|
||||||
guard let monitors else { return nil }
|
|
||||||
if let byName = monitors[screenName] { return byName }
|
|
||||||
if let index = screenIndex, let byIndex = monitors[String(index)] { return byIndex }
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Window definition name for a screen (pure resolver).
|
|
||||||
/// Override's `window` if set, else the global `window`.
|
|
||||||
func windowName(screenName: String, screenIndex: Int?) -> String {
|
|
||||||
monitorOverride(screenName: screenName, screenIndex: screenIndex)?.window ?? window
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Block-set name for a screen (pure resolver).
|
|
||||||
/// Override's `blocks` if set, else the global `blocks` (default `"default"`).
|
|
||||||
func blocksName(screenName: String, screenIndex: Int?) -> String {
|
|
||||||
monitorOverride(screenName: screenName, screenIndex: screenIndex)?.blocks ?? (blocks ?? "default")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
import AppKit
|
|
||||||
|
|
||||||
extension PHConfig {
|
|
||||||
/// The per-monitor override that applies to `screen`, if any.
|
|
||||||
/// Precedence: monitor name → monitor index.
|
|
||||||
func monitorOverride(for screen: NSScreen) -> PHMonitorOverride? {
|
|
||||||
let index = NSScreen.screens.firstIndex(of: screen)
|
|
||||||
return monitorOverride(screenName: screen.localizedName, screenIndex: index)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Window definition name for `screen`: the override's `window` if set,
|
|
||||||
/// otherwise the global `window`.
|
|
||||||
func windowName(for screen: NSScreen) -> String {
|
|
||||||
monitorOverride(for: screen)?.window ?? window
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Block-set name for `screen`: the override's `blocks` if set, otherwise
|
|
||||||
/// the global `blocks` (defaulting to `"default"`).
|
|
||||||
func blocks(for screen: NSScreen) -> String {
|
|
||||||
monitorOverride(for: screen)?.blocks ?? (blocks ?? "default")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import AppKit
|
||||||
|
|
||||||
|
/// A per-monitor entry from the config's `[monitor]` table.
|
||||||
|
///
|
||||||
|
/// Either field is optional; an unset field inherits the matching global
|
||||||
|
/// (`window` or `blocks`) so a monitor can override just one of the two.
|
||||||
|
struct PHConfigMonitorOverride: Decodable {
|
||||||
|
let theme: String?
|
||||||
|
let window: String?
|
||||||
|
let blocks: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PHConfig {
|
||||||
|
/// The override matching a screen identifier, if any.
|
||||||
|
/// Pure (no AppKit). Precedence: monitor name → monitor index.
|
||||||
|
func monitorOverride(screenName: String, screenIndex: Int?) -> PHConfigMonitorOverride? {
|
||||||
|
guard let monitors else { return nil }
|
||||||
|
if let byName = monitors[screenName] { return byName }
|
||||||
|
if let index = screenIndex, let byIndex = monitors[String(index)] { return byIndex }
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Window definition name for a screen (pure resolver).
|
||||||
|
/// Override's `window` if set, else the global `window`.
|
||||||
|
func windowName(screenName: String, screenIndex: Int?) -> String {
|
||||||
|
monitorOverride(screenName: screenName, screenIndex: screenIndex)?.window ?? window
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Block-set name for a screen (pure resolver).
|
||||||
|
/// Override's `blocks` if set, else the global `blocks` (default `"default"`).
|
||||||
|
func blocksName(screenName: String, screenIndex: Int?) -> String {
|
||||||
|
monitorOverride(screenName: screenName, screenIndex: screenIndex)?.blocks ?? (blocks ?? "default")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The per-monitor override that applies to `screen`, if any.
|
||||||
|
/// Precedence: monitor name → monitor index.
|
||||||
|
func monitorOverride(for screen: NSScreen) -> PHConfigMonitorOverride? {
|
||||||
|
let index = NSScreen.screens.firstIndex(of: screen)
|
||||||
|
return monitorOverride(screenName: screen.localizedName, screenIndex: index)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Window definition name for `screen`: the override's `window` if set,
|
||||||
|
/// otherwise the global `window`.
|
||||||
|
func windowName(for screen: NSScreen) -> String {
|
||||||
|
monitorOverride(for: screen)?.window ?? window
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Block-set name for `screen`: the override's `blocks` if set, otherwise
|
||||||
|
/// the global `blocks` (defaulting to `"default"`).
|
||||||
|
func blocks(for screen: NSScreen) -> String {
|
||||||
|
monitorOverride(for: screen)?.blocks ?? (blocks ?? "default")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Theme name for `screen`: the override's `theme` if set, otherwise
|
||||||
|
/// the global `theme` (defaulting to `"default"`).
|
||||||
|
func theme(for screen: NSScreen) -> String {
|
||||||
|
monitorOverride(for: screen)?.theme ?? theme
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,23 @@
|
|||||||
# Default window and block set for every monitor.
|
# Default window and block set for every monitor.
|
||||||
|
# - theme: a named theme at ~/.config/phbar/themes/<name>.toml
|
||||||
# - window: a [[window]] definition from the theme file
|
# - window: a [[window]] definition from the theme file
|
||||||
# - blocks: a named set at ~/.config/phbar/blocks/<name>.toml
|
# - blocks: a named set at ~/.config/phbar/blocks/<name>.toml
|
||||||
|
theme = "default"
|
||||||
window = "default"
|
window = "default"
|
||||||
blocks = "default"
|
blocks = "default"
|
||||||
|
|
||||||
# Optional: override the window and/or block set per monitor.
|
# Optional: override the theme, window, and/or block set per monitor.
|
||||||
# - quoted numeric key → NSScreen index
|
# - quoted numeric key → NSScreen index
|
||||||
# - string key → NSScreen.localizedName (stable across replugs)
|
# - string key → NSScreen.localizedName (stable across replugs)
|
||||||
# Precedence: monitor name → monitor index → the globals above.
|
# Precedence: monitor name → monitor index → the globals above.
|
||||||
# Either field may be omitted to inherit its global value.
|
# Either field may be omitted to inherit its global value.
|
||||||
#
|
#
|
||||||
# [monitor."1"]
|
# [monitor."1"]
|
||||||
|
# theme = "default"
|
||||||
# window = "bottom"
|
# window = "bottom"
|
||||||
# blocks = "laptop"
|
# blocks = "laptop"
|
||||||
#
|
#
|
||||||
# [monitor."DELL U2723QE"]
|
# [monitor."DELL U2723QE"]
|
||||||
|
# theme = "external"
|
||||||
# window = "clock"
|
# window = "clock"
|
||||||
# blocks = "external"
|
# blocks = "external"
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
# phbar theme file ~ Voltage
|
# phbar theme file
|
||||||
#
|
#
|
||||||
# Place at ~/.config/phbar/themes/voltage.toml
|
# Place at ~/.config/phbar/themes/default.toml
|
||||||
|
|
||||||
[[window]]
|
[[window]]
|
||||||
name = "default"
|
name = "default"
|
||||||
anchor = "top"
|
anchor = "top"
|
||||||
height = 30
|
height = 30
|
||||||
width = "100%"
|
width = "100%"
|
||||||
margin = { leading = 30, top = 30, trailing = 30, bottom = 30 }
|
|
||||||
|
|
||||||
[[window]]
|
[[window]]
|
||||||
name = "bottom"
|
name = "bottom"
|
||||||
|
|||||||
Reference in New Issue
Block a user