panel: reorganize runtime files

parent dbee2b25
...@@ -11,7 +11,14 @@ user-facing configuration UI is expected to live in `ximperconf shell panel`. ...@@ -11,7 +11,14 @@ user-facing configuration UI is expected to live in `ximperconf shell panel`.
- User modules: `~/.config/ximper-shell/panel/modules.json` - User modules: `~/.config/ximper-shell/panel/modules.json`
- User style: `~/.config/ximper-shell/panel/style.css` - User style: `~/.config/ximper-shell/panel/style.css`
- User dark style: `~/.config/ximper-shell/panel/style-dark.css` - User dark style: `~/.config/ximper-shell/panel/style-dark.css`
- System modules: `/usr/share/ximperdistro/wm/base/waybar/modules.json` - System defaults: `/etc/xdg/ximper-shell/panel/`
- System config: `/etc/xdg/ximper-shell/panel/config.json`
- System modules: `/etc/xdg/ximper-shell/panel/modules.json`
- System styles: `/etc/xdg/ximper-shell/panel/style.css`,
`/etc/xdg/ximper-shell/panel/style-dark.css`
System defaults are searched through `XDG_CONFIG_DIRS`, falling back to
`/etc/xdg`.
## Commands ## Commands
......
{
"position": "top",
"type": "panel",
"modules_left": [
"image#menu",
"tray"
],
"modules_center": [
"workspaces"
],
"modules_right": [
"custom/media",
"language",
"group/volume",
"battery",
"network",
"bluetooth",
"custom/notification"
]
}
\ No newline at end of file
install_data(
'config.json',
'modules.json',
'style-base.css',
'style.css',
'style-dark.css',
install_dir: get_option('sysconfdir') / 'xdg' / 'ximper-shell' / 'panel',
)
{
"backlight": {
"format": "{icon} {percent}%",
"format-icons": [
"",
"",
"",
"",
"",
"",
"",
"",
""
],
"tooltip-format": "{percent}%",
"on-scroll-up": "brightnessctl s +5%",
"on-scroll-down": "brightnessctl s 5%-"
},
"backlight#vertical": {
"format": "{icon}",
"format-icons": [
"",
"",
"",
"",
"",
"",
"",
"",
""
],
"tooltip-format": "{percent}%",
"on-scroll-up": "brightnessctl s +5%",
"on-scroll-down": "brightnessctl s 5%-"
},
"battery": {
"states": {
"good": 95,
"warning": 30,
"critical": 15
},
"format": "{icon} {capacity}%",
"rotate": 0,
"format-icons": {
"default": [
"󰂎",
"󰁺",
"󰁻",
"󰁼",
"󰁽",
"󰁾",
"󰁿",
"󰂀",
"󰂁",
"󰂂",
"󰁹"
],
"charging": [
"󰢟",
"󰢜",
"󰂆",
"󰂇",
"󰂈",
"󰢝",
"󰂉",
"󰢞",
"󰂊",
"󰂋",
"󰂅"
],
},
"tooltip-format": "{capacity}% | {timeTo}"
},
"battery#vertical": {
"states": {
"good": 95,
"warning": 30,
"critical": 15
},
"format": "{icon}",
"rotate": 0,
"format-icons": {
"default": [
"󰂎",
"󰁺",
"󰁻",
"󰁼",
"󰁽",
"󰁾",
"󰁿",
"󰂀",
"󰂁",
"󰂂",
"󰁹"
],
"charging": [
"󰢟",
"󰢜",
"󰂆",
"󰂇",
"󰂈",
"󰢝",
"󰂉",
"󰢞",
"󰂊",
"󰂋",
"󰂅"
],
},
"tooltip-format": "{capacity}% | {timeTo}"
},
// TODO
"bluetooth": {
"format": "",
"format-disabled": "󰂳",
"format-on": "󰂱",
"format-off": "󰂲",
"format-disconnected": "󰂲",
"format-connected": "󰂱 {num_connections}",
"tooltip": true,
"tooltip-format": "",
"tooltip-format-disabled": "󰂳 Отключено",
"tooltip-format-on": "󰂱 Включено",
"tooltip-format-off": "󰂳 Выключено",
"tooltip-format-connected": "{device_enumerate}",
"tooltip-format-enumerate-connected": " {device_alias} 󰂄{device_battery_percentage}%",
"on-click-right": "hyprctl dispatch exec '[size 530 350; move 100%-550 4%]' blueman-manager"
},
// TODO
"cpu": {
"interval": 1,
"format": " {icon}",
"format-icons": [
"<span color='#3a944a'>▁</span>",
"<span color='#3584e4'>▂</span>",
"<span color='#3584e4'>▃</span>",
"<span color='#c88800'>▄</span>",
"<span color='#c88800'>▅</span>",
"<span color='#ed5b00'>▆</span>",
"<span color='#ed5b00'>▇</span>",
"<span color='#e62d42'>█</span>"
],
"tooltip-format": "{usage}"
},
"cpu#vertical": {
"interval": 1,
"format": "\n{icon}",
"format-icons": [
"<span color='#3a944a'>▁</span>",
"<span color='#3584e4'>▂</span>",
"<span color='#3584e4'>▃</span>",
"<span color='#c88800'>▄</span>",
"<span color='#c88800'>▅</span>",
"<span color='#ed5b00'>▆</span>",
"<span color='#ed5b00'>▇</span>",
"<span color='#e62d42'>█</span>"
],
"tooltip-format": "{usage}"
},
"clock": {
"format": "{:%H:%M}",
"tooltip-format": "<tt><big>{calendar}</big></tt>",
"format-alt": "{:%Y-%m-%d}",
"calendar": {
"mode": "month",
"weeks-pos": "left",
"format": {
"months": "<span color='#d0d3d8'><b>{}</b></span>",
"days": "<span color='#cbced3'><b>{}</b></span>",
"weeks": "<span color='#95d3af'><b>W{}</b></span>",
"weekdays": "<span color='#98d3ee'><b>{}</b></span>",
"today": "<span color='#e26c7c'><b><u>{}</u></b></span>"
}
}
},
"clock#vertical": {
"format": "{:%H\n%M}",
"tooltip-format": "<tt><big>{calendar}</big></tt>",
"format-alt": "{:%Y-%m-%d}",
"calendar": {
"mode": "month",
"weeks-pos": "left",
"format": {
"months": "<span color='#d0d3d8'><b>{}</b></span>",
"days": "<span color='#cbced3'><b>{}</b></span>",
"weeks": "<span color='#95d3af'><b>W{}</b></span>",
"weekdays": "<span color='#98d3ee'><b>{}</b></span>",
"today": "<span color='#e26c7c'><b><u>{}</u></b></span>"
}
}
},
"custom/notification": {
"format": "{icon}",
"format-icons": {
"notification": "󰂜<span foreground='red'><sup></sup></span>",
"none": "󰂜",
"dnd-notification": "󰪑<span foreground='red'><sup></sup></span>",
"dnd-none": "󰪑",
"inhibited-notification": "<span foreground='red'><sup></sup></span>",
"inhibited-none": "󰂜",
"dnd-inhibited-notification": "󰪑<span foreground='red'><sup></sup></span>",
"dnd-inhibited-none": "󰪑"
},
"return-type": "json",
"exec-if": "which ximper-shell-notification-center-client",
"exec": "ximper-shell-notification-center-client -swb",
"on-click": "ximper-shell-notification-center-client -t -sw",
"on-click-right": "ximper-shell-notification-center-client -d -sw",
"escape": true
},
"custom/media": {
"format": "{icon} {0}",
"return-type": "json",
"format-icons": {
"Playing": "",
"Paused": ""
},
"max-length": 50,
"exec": "playerctl -a metadata --format '{\"text\": \"{{artist}} - {{markup_escape(title)}}\", \"tooltip\": \"{{playerName}} : {{markup_escape(title)}}\", \"alt\": \"{{status}}\", \"class\": \"{{status}}\"}' -F",
"on-click": "playerctl play-pause",
"on-scroll-up": "playerctl next",
"on-scroll-down": "playerctl previous"
},
"custom/media#vertical": {
"format": "{icon}",
"return-type": "json",
"format-icons": {
"Playing": "",
"Paused": ""
},
"max-length": 50,
"exec": "playerctl -a metadata --format '{\"text\": \"{{artist}} - {{markup_escape(title)}}\", \"tooltip\": \"{{playerName}} : {{artist}} - {{markup_escape(title)}}\", \"alt\": \"{{status}}\", \"class\": \"{{status}}\"}' -F",
"on-click": "playerctl play-pause",
"on-scroll-up": "playerctl next",
"on-scroll-down": "playerctl previous"
},
"hyprland/workspaces": {
"active-only": false,
"all-outputs": false,
"format": "{name}",
"show-special": true,
"on-click": "activate",
"on-scroll-up": "hyprctl dispatch workspace e+1",
"on-scroll-down": "hyprctl dispatch workspace e-1",
},
"hyprland/window": {
"format": "{title}",
"icon": "true",
"icon-size": 16,
"max-length": 30,
},
"hyprland/windowcount": {
"format": "{}",
"separate-outputs": true
},
"hyprland/language": {
"format": "{}",
"format-en": "EN",
"format-ru": "RU",
"on-scroll-up": "hyprctl switchxkblayout all next",
"on-scroll-down": "hyprctl switchxkblayout all prev",
},
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
"activated": "󰅶",
"deactivated": "󰾫"
},
"tooltip-format-activated": "Кофеин: активен\nРежим ожидания: отключен",
"tooltip-format-deactivated": "Кофеин: отключен\nРежим ожидания: активен"
},
"image#menu": {
"path": "/usr/share/pixmaps/ximperlinux.svg",
"size": 18,
"on-click": "pkill wofi || wofi --show drun -x 8 -y 10 --height 35% --width 25%"
},
"memory": {
"interval": 1,
"format": " {icon}",
"format-icons": [
"<span color='#3a944a'>▁</span>",
"<span color='#3a944a'>▂</span>",
"<span color='#3584e4'>▃</span>",
"<span color='#3584e4'>▄</span>",
"<span color='#c88800'>▅</span>",
"<span color='#ed5b00'>▆</span>",
"<span color='#ed5b00'>▇</span>",
"<span color='#e62d42'>█</span>"
],
"tooltip-format": "memory: {used:0.1f}/{total:0.1f} GiB \nSWAP: {swapUsed:0.1f}/{swapTotal:0.1f} GiB"
},
"memory#vertical": {
"interval": 1,
"format": "\n{icon}",
"format-icons": [
"<span color='#3a944a'>▁</span>",
"<span color='#3a944a'>▂</span>",
"<span color='#3584e4'>▃</span>",
"<span color='#3584e4'>▄</span>",
"<span color='#c88800'>▅</span>",
"<span color='#ed5b00'>▆</span>",
"<span color='#ed5b00'>▇</span>",
"<span color='#e62d42'>█</span>"
],
"tooltip-format": "memory: {used:0.1f}/{total:0.1f} GiB \nSWAP: {swapUsed:0.1f}/{swapTotal:0.1f} GiB"
},
"network": {
"tooltip": true,
"format-wifi": " ",
"rotate": 0,
"format-ethernet": "󰈀",
"format-linked": "󰈀 (No IP)",
"format-disconnected": "󰖪 ",
"tooltip-format-disconnected": "Нет соединения",
"format-alt": "<span foreground='#90ceaa'> {bandwidthDownBytes}</span> <span foreground='#dd6777'>  {bandwidthUpBytes}</span>",
"interval": 2,
"on-click-right": "hyprctl dispatch exec '[size 910 460; move 100%-930 4%]' kitty nmtui"
},
"niri/workspaces": {
"active-only": false,
"all-outputs": false,
"format": "{value}",
"show-special": true,
"on-click": "activate",
"on-scroll-up": "niri msg action focus-workspace-up",
"on-scroll-down": "niri msg action focus-workspace-down",
},
"niri/window": {
"format": "{title}",
"icon": "true",
"icon-size": 16,
"max-length": 30,
},
"niri/language": {
"format": "{}",
"format-en": "EN",
"format-ru": "RU",
"on-scroll-up": "niri msg action switch-layout next",
"on-scroll-down": "niri msg action switch-layout prev",
},
"wlr/taskbar": {
"format": "{icon}",
"icon-size": 15,
"tooltip-format": "{title}",
"on-click": "activate",
"on-click-middle": "close",
"ignore-list": [
"Alacritty",
"kitty"
]
},
"temperature": {
"format": " {icon}",
"format-icons": [
"<span color='#3a944a'>▁</span>",
"<span color='#3a944a'>▂</span>",
"<span color='#3584e4'>▃</span>",
"<span color='#3584e4'>▄</span>",
"<span color='#c88800'>▅</span>",
"<span color='#ed5b00'>▆</span>",
"<span color='#ed5b00'>▇</span>",
"<span color='#e62d42'>█</span>"
],
},
"temperature#vertical": {
"format": "\n{icon}",
"format-icons": [
"<span color='#3a944a'>▁</span>",
"<span color='#3a944a'>▂</span>",
"<span color='#3584e4'>▃</span>",
"<span color='#3584e4'>▄</span>",
"<span color='#c88800'>▅</span>",
"<span color='#ed5b00'>▆</span>",
"<span color='#ed5b00'>▇</span>",
"<span color='#e62d42'>█</span>"
],
},
"tray": {
"icon-size": 15,
"show-passive-items": true,
"spacing": 8
},
"pulseaudio#volume": {
"scroll-step": 5,
"format": "{icon} ",
"format-bluetooth": " {icon} {volume}%",
"format-muted": " ",
"tooltip-format": "{volume}%",
"format-icons": {
"default": [
"",
"",
""
]
},
"on-click": "hyprctl dispatch exec pwvucontrol",
"on-click-right": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
},
"pulseaudio#microphone": {
"format": "{format_source}",
"format-source": "",
"format-source-muted": " ",
"on-click": "hyprctl dispatch exec '[size 820 400; move 100%-840 4%]' pwvucontrol",
"on-click-right": "wpctl set-mute @DEFAULT_SOURCE@ toggle",
"on-scroll-up": "wpctl set-volume @DEFAULT_SOURCE@ 10%+ -l 1.0",
"on-scroll-down": "wpctl set-volume @DEFAULT_SOURCE@ 10%- -l 1.0",
"tooltip-format": "{source_volume}%"
},
"group/volume": {
"orientation": "inherit",
"modules": [
"pulseaudio#volume",
"pulseaudio#microphone",
]
}
}
\ No newline at end of file
* {
min-height: 0;
font-size: 14px;
font-family: Evolventa-Regular, FiraCode Nerd Font;
font-weight: 700;
}
window#waybar {
background: alpha(@bg, .99);
}
window#waybar.islands {
background: alpha(@bg, .0);
}
window#waybar.top {
border-radius: 0 0 20px 20px;
}
window#waybar.bottom {
border-radius: 20px 20px 0 0;
}
window#waybar.left {
border-radius: 0 20px 20px 0;
}
window#waybar.right {
border-radius: 20px 0 0 20px;
}
window#waybar.floating {
border-radius: 20px;
}
.module {
background-color: @selected_bg;
min-height: 0;
border-radius: 20px;
color: @text;
border: none;
}
window#waybar.top .module,
window#waybar.bottom .module {
margin: 5px 0;
padding: 0px 10px;
}
window#waybar.left .module,
window#waybar.right .module {
margin: 0 5px;
padding: 10px 0px;
}
window#waybar.top .modules-left,
window#waybar.bottom .modules-left {
margin: 0 5px;
}
window#waybar.top .modules-right,
window#waybar.bottom .modules-right {
margin: 0 5px;
}
window#waybar.left .modules-left,
window#waybar.right .modules-left {
margin: 5px 0;
}
window#waybar.left .modules-right,
window#waybar.right .modules-right {
margin: 5px 0;
}
.module:hover {
background-color: alpha(@selected_bg, .4);
}
window#waybar.islands .module:hover {
background-color: @bg;
}
.horizontal>widget>box.horizontal>widget:first-child>.module {
border-radius: 20px 0 0 20px;
margin: 3px 0;
padding: 0 5px 0 10px;
}
.horizontal>widget>box.horizontal>widget:not(:first-child):not(:last-child)>.module {
border-radius: 0;
margin: 3px 0;
padding: 0 5px;
}
.horizontal>widget>box.horizontal>widget:last-child>.module {
border-radius: 0 20px 20px 0;
margin: 3px 0;
padding: 0 10px 0 5px;
}
.vertical>widget>box.vertical>widget:first-child>.module {
border-radius: 20px 20px 0 0;
margin: 0 3px;
padding: 100px 10px 0 10px;
}
.vertical>widget>box.vertical>widget:not(:first-child):not(:last-child)>.module {
border-radius: 0;
margin: 3px 0;
padding: 0 5px;
}
.vertical>widget>box.vertical>widget:last-child>.module {
border-radius: 0 0 20px 20px;
margin: 3px 0;
padding: 0 10px 0 5px;
}
window#waybar.left .module#workspaces {
padding: 0px;
}
#workspaces button {
color: @text;
margin: 3px;
border-radius: 20px;
transition: padding, background 200ms ease-in-out 100ms;
}
window#waybar.top #workspaces button,
window#waybar.bottom #workspaces button,
window#waybar.left #workspaces button,
window#waybar.right #workspaces button {
padding: 0px;
}
window#waybar.top #workspaces button:hover,
window#waybar.top #workspaces button.active,
window#waybar.top #workspaces button.urgent,
window#waybar.bottom #workspaces button:hover,
window#waybar.bottom #workspaces button.active,
window#waybar.bottom #workspaces button.urgent {
padding: 0 10px;
}
window#waybar.left #workspaces button:hover,
window#waybar.left #workspaces button.active,
window#waybar.left #workspaces button.urgent,
window#waybar.right #workspaces button:hover,
window#waybar.right #workspaces button.active,
window#waybar.right #workspaces button.urgent {
padding: 10px 0;
}
#workspaces button.active {
background: alpha(@accent, .7);
}
#workspaces button.urgent {
background: alpha(@urgent, .7);
}
#workspaces button.special {
padding: 0px 5px;
}
#workspaces button.special.active {
background: alpha(@accent, .7);
padding: 0px 5px;
}
#workspaces button.special.urgent {
background: alpha(@urgent, .7);
padding: 0px 5px;
}
#tray menu {
background-color: @bg;
}
#idle_inhibitor {
padding: 0px 10px 0px 7px;
}
#pulseaudio.volume.muted {
color: @unfocused;
}
#pulseaudio.microphone.source-muted {
color: @unfocused;
}
window#waybar.empty #window {
background-color: transparent;
}
tooltip {
border-radius: 20px;
background: @bg;
color: @text
}
tooltip label {
color: @text
}
\ No newline at end of file
@define-color bg #222226;
@define-color selected_bg #343437;
@define-color text #ffffff;
@define-color workspace_text #a6a7ac;
@define-color unfocused #f85656;
@define-color urgent #e89b0b;
@define-color accent #3584e4;
@import url("style-base.css");
@define-color bg #fafafb;
@define-color selected_bg #deddda;
@define-color text rgb(0, 0, 6);
@define-color workspace_text #9a9996;
@define-color unfocused #f85656;
@define-color urgent #e89b0b;
@define-color accent #3584e4;
@import url("style-base.css");
...@@ -3,20 +3,5 @@ project('ximper-shell-panel', ...@@ -3,20 +3,5 @@ project('ximper-shell-panel',
meson_version: '>= 1.0.0', meson_version: '>= 1.0.0',
) )
custom_target( subdir('src')
'go-build', subdir('data')
build_by_default: true,
build_always_stale: true,
output: meson.project_name(),
console: true,
install: true,
install_dir: get_option('bindir'),
command: [
'go', 'build',
'-o', '@OUTPUT@',
meson.current_source_dir(),
],
env: [
'CGO_ENABLED=0',
],
)
...@@ -11,12 +11,10 @@ import ( ...@@ -11,12 +11,10 @@ import (
) )
const ( const (
SystemConfigHome = "/usr/share/ximperdistro/wm/base" ConfigSubdir = "ximper-shell/panel"
SystemWaybarDir = SystemConfigHome + "/waybar" DefaultSystemXDGPath = "/etc/xdg"
ModulesFile = SystemWaybarDir + "/modules.json" SafeModeEnv = "XIMPER_SHELL_SAFEMODE"
StyleFile = SystemWaybarDir + "/style.css" WaybarConfigDirEnv = "WAYBAR_CONFIG_DIR"
DarkStyleFile = SystemWaybarDir + "/style-dark.css"
SafeModeEnv = "XIMPER_SHELL_SAFEMODE"
) )
type Config struct { type Config struct {
...@@ -27,18 +25,12 @@ type Config struct { ...@@ -27,18 +25,12 @@ type Config struct {
ModulesRight []string `json:"modules_right"` ModulesRight []string `json:"modules_right"`
} }
func DefaultConfig() Config { func LoadConfig(path string) (Config, error) {
return Config{ cfg, err := LoadDefaultConfig()
Position: "top", if err != nil {
Type: "panel", return Config{}, err
ModulesLeft: []string{"image#menu"},
ModulesCenter: []string{"workspaces"},
ModulesRight: []string{"group/volume", "network", "clock"},
} }
}
func LoadConfig(path string) (Config, error) {
cfg := DefaultConfig()
data, err := os.ReadFile(path) data, err := os.ReadFile(path)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
...@@ -55,6 +47,22 @@ func LoadConfig(path string) (Config, error) { ...@@ -55,6 +47,22 @@ func LoadConfig(path string) (Config, error) {
return cfg, cfg.Validate() return cfg, cfg.Validate()
} }
func LoadDefaultConfig() (Config, error) {
var cfg Config
path := SystemConfigPath()
data, err := os.ReadFile(path)
if err != nil {
return cfg, err
}
if len(bytes.TrimSpace(data)) == 0 {
return cfg, fmt.Errorf("system panel config %s is empty", path)
}
if err := json.Unmarshal(data, &cfg); err != nil {
return cfg, fmt.Errorf("parse system panel config: %w", err)
}
return cfg, cfg.Validate()
}
func (c Config) Validate() error { func (c Config) Validate() error {
switch c.Position { switch c.Position {
case "top", "bottom", "left", "right": case "top", "bottom", "left", "right":
...@@ -69,7 +77,7 @@ func (c Config) Validate() error { ...@@ -69,7 +77,7 @@ func (c Config) Validate() error {
} }
for _, name := range append(append([]string{}, c.ModulesLeft...), append(c.ModulesCenter, c.ModulesRight...)...) { for _, name := range append(append([]string{}, c.ModulesLeft...), append(c.ModulesCenter, c.ModulesRight...)...) {
if name == "" { if strings.TrimSpace(name) == "" {
return errors.New("module name cannot be empty") return errors.New("module name cannot be empty")
} }
} }
...@@ -78,19 +86,72 @@ func (c Config) Validate() error { ...@@ -78,19 +86,72 @@ func (c Config) Validate() error {
} }
func UserConfigPath() string { func UserConfigPath() string {
return filepath.Join(os.Getenv("HOME"), ".config", "ximper-shell", "panel", "config.json") return userConfigPath("config.json")
}
func SystemConfigPath() string {
return systemConfigPath("config.json")
} }
func UserModulesPath() string { func UserModulesPath() string {
return filepath.Join(os.Getenv("HOME"), ".config", "ximper-shell", "panel", "modules.json") return userConfigPath("modules.json")
} }
func UserStylePath() string { func UserStylePath() string {
return filepath.Join(os.Getenv("HOME"), ".config", "ximper-shell", "panel", "style.css") return userConfigPath("style.css")
} }
func UserDarkStylePath() string { func UserDarkStylePath() string {
return filepath.Join(os.Getenv("HOME"), ".config", "ximper-shell", "panel", "style-dark.css") return userConfigPath("style-dark.css")
}
func SystemModulesPath() string {
return systemConfigPath("modules.json")
}
func SystemStylePath() string {
return systemConfigPath("style.css")
}
func SystemDarkStylePath() string {
return systemConfigPath("style-dark.css")
}
func userConfigPath(name string) string {
dir, err := os.UserConfigDir()
if err != nil || dir == "" {
dir = filepath.Join(os.Getenv("HOME"), ".config")
}
return filepath.Join(dir, filepath.FromSlash(ConfigSubdir), name)
}
func systemConfigPath(name string) string {
dirs := systemConfigDirs()
for _, dir := range dirs {
path := filepath.Join(dir, filepath.FromSlash(ConfigSubdir), name)
if fileExists(path) {
return path
}
}
return filepath.Join(dirs[0], filepath.FromSlash(ConfigSubdir), name)
}
func systemConfigDirs() []string {
value := os.Getenv("XDG_CONFIG_DIRS")
if strings.TrimSpace(value) == "" {
return []string{DefaultSystemXDGPath}
}
var dirs []string
for _, dir := range filepath.SplitList(value) {
if strings.TrimSpace(dir) != "" {
dirs = append(dirs, dir)
}
}
if len(dirs) == 0 {
return []string{DefaultSystemXDGPath}
}
return dirs
} }
func SafeMode() bool { func SafeMode() bool {
...@@ -107,20 +168,16 @@ func RuntimeDir() string { ...@@ -107,20 +168,16 @@ func RuntimeDir() string {
return filepath.Join(os.TempDir(), "ximper-shell", "panel") return filepath.Join(os.TempDir(), "ximper-shell", "panel")
} }
func RuntimeWaybarDir() string {
return filepath.Join(RuntimeDir(), "waybar")
}
func RuntimeConfigPath() string { func RuntimeConfigPath() string {
return filepath.Join(RuntimeWaybarDir(), "config") return filepath.Join(RuntimeDir(), "config")
} }
func RuntimeModulesPath() string { func RuntimeModulesPath() string {
return filepath.Join(RuntimeWaybarDir(), "modules.jsonc") return filepath.Join(RuntimeDir(), "modules.jsonc")
} }
func RuntimeStylePath(name string) string { func RuntimeStylePath(name string) string {
return filepath.Join(RuntimeWaybarDir(), name) return filepath.Join(RuntimeDir(), name)
} }
func RuntimePIDPath() string { func RuntimePIDPath() string {
......
...@@ -106,11 +106,11 @@ func WriteRuntimeModules(registry Registry) error { ...@@ -106,11 +106,11 @@ func WriteRuntimeModules(registry Registry) error {
} }
func WriteRuntimeStyles() error { func WriteRuntimeStyles() error {
if err := os.MkdirAll(RuntimeWaybarDir(), 0755); err != nil { if err := os.MkdirAll(RuntimeDir(), 0755); err != nil {
return err return err
} }
userStyle := UserStylePath() userStyle := UserStylePath()
userDarkStyle := UserStylePath() userDarkStyle := ""
if SafeMode() { if SafeMode() {
userStyle = "" userStyle = ""
userDarkStyle = "" userDarkStyle = ""
...@@ -118,10 +118,10 @@ func WriteRuntimeStyles() error { ...@@ -118,10 +118,10 @@ func WriteRuntimeStyles() error {
userDarkStyle = UserDarkStylePath() userDarkStyle = UserDarkStylePath()
} }
if err := writeRuntimeStyle(RuntimeStylePath("style.css"), StyleFile, userStyle); err != nil { if err := writeRuntimeStyle(RuntimeStylePath("style.css"), SystemStylePath(), userStyle); err != nil {
return err return err
} }
return writeRuntimeStyle(RuntimeStylePath("style-dark.css"), DarkStyleFile, userDarkStyle) return writeRuntimeStyle(RuntimeStylePath("style-dark.css"), SystemDarkStylePath(), userDarkStyle)
} }
func writeRuntimeStyle(runtimePath, systemPath, userPath string) error { func writeRuntimeStyle(runtimePath, systemPath, userPath string) error {
...@@ -147,16 +147,16 @@ func loadInputs() (Config, Registry, error) { ...@@ -147,16 +147,16 @@ func loadInputs() (Config, Registry, error) {
func loadConfig() (Config, error) { func loadConfig() (Config, error) {
if SafeMode() { if SafeMode() {
return DefaultConfig(), nil return LoadDefaultConfig()
} }
return LoadConfig(UserConfigPath()) return LoadConfig(UserConfigPath())
} }
func loadRegistry() (Registry, error) { func loadRegistry() (Registry, error) {
if SafeMode() { if SafeMode() {
return LoadRegistry(ModulesFile) return LoadRegistry(SystemModulesPath())
} }
return LoadMergedRegistry(ModulesFile, UserModulesPath()) return LoadMergedRegistry(SystemModulesPath(), UserModulesPath())
} }
func resolveModuleList(modules []string, position string, registry Registry) ([]string, error) { func resolveModuleList(modules []string, position string, registry Registry) ([]string, error) {
......
panel_sources = files(
'config.go',
'generate.go',
'jsonc.go',
'main.go',
'registry.go',
'runner.go',
)
custom_target(
'go-build',
input: panel_sources,
build_by_default: true,
build_always_stale: true,
output: meson.project_name(),
console: true,
install: true,
install_dir: get_option('bindir'),
command: [
'go', 'build',
'-o', '@OUTPUT@',
meson.current_source_dir(),
],
env: [
'CGO_ENABLED=0',
],
)
...@@ -127,8 +127,8 @@ func (r Registry) SelectableNames() []string { ...@@ -127,8 +127,8 @@ func (r Registry) SelectableNames() []string {
} }
func (r Registry) Resolve(name, position string) (string, error) { func (r Registry) Resolve(name, position string) (string, error) {
explicit := strings.Contains(name, "/") || strings.Contains(name, "#") explicitVariant := strings.Contains(name, "#")
if explicit { if explicitVariant {
if _, ok := r.Modules[name]; ok { if _, ok := r.Modules[name]; ok {
return name, nil return name, nil
} }
...@@ -137,6 +137,7 @@ func (r Registry) Resolve(name, position string) (string, error) { ...@@ -137,6 +137,7 @@ func (r Registry) Resolve(name, position string) (string, error) {
wm := currentWM() wm := currentWM()
vertical := position == "left" || position == "right" vertical := position == "left" || position == "right"
explicitModule := strings.Contains(name, "/")
var candidates []string var candidates []string
if vertical { if vertical {
...@@ -145,6 +146,16 @@ func (r Registry) Resolve(name, position string) (string, error) { ...@@ -145,6 +146,16 @@ func (r Registry) Resolve(name, position string) (string, error) {
} }
candidates = append(candidates, name+"#vertical") candidates = append(candidates, name+"#vertical")
} }
if explicitModule {
candidates = append(candidates, name)
for _, candidate := range candidates {
if _, ok := r.Modules[candidate]; ok {
return candidate, nil
}
}
return "", fmt.Errorf("module %q not found", name)
}
if wm != "" { if wm != "" {
candidates = append(candidates, wm+"/"+name) candidates = append(candidates, wm+"/"+name)
} }
......
...@@ -35,7 +35,7 @@ func StartWaybar() error { ...@@ -35,7 +35,7 @@ func StartWaybar() error {
defer logFile.Close() defer logFile.Close()
cmd := exec.Command("waybar") cmd := exec.Command("waybar")
cmd.Env = append(os.Environ(), "XDG_CONFIG_HOME="+RuntimeDir()) cmd.Env = append(os.Environ(), WaybarConfigDirEnv+"="+RuntimeDir())
cmd.Stdout = logFile cmd.Stdout = logFile
cmd.Stderr = logFile cmd.Stderr = logFile
cmd.Stdin = nil cmd.Stdin = nil
...@@ -167,17 +167,17 @@ func isPanelProcess(pid int) bool { ...@@ -167,17 +167,17 @@ func isPanelProcess(pid int) bool {
return false return false
} }
hasWaybar := bytes.Contains([]byte(filepath.Base(string(parts[0]))), []byte("waybar")) hasWaybar := filepath.Base(string(parts[0])) == "waybar"
return hasWaybar && hasPanelConfigHome(pid) return hasWaybar && hasPanelConfigDir(pid)
} }
func hasPanelConfigHome(pid int) bool { func hasPanelConfigDir(pid int) bool {
data, err := os.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "environ")) data, err := os.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "environ"))
if err != nil { if err != nil {
return false return false
} }
for _, part := range bytes.Split(bytes.TrimRight(data, "\x00"), []byte{0}) { for _, part := range bytes.Split(bytes.TrimRight(data, "\x00"), []byte{0}) {
if string(part) == "XDG_CONFIG_HOME="+RuntimeDir() { if string(part) == WaybarConfigDirEnv+"="+RuntimeDir() {
return true return true
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment