Compare commits
11 commits
7c52d0c6f4
...
d2b803818d
Author | SHA1 | Date | |
---|---|---|---|
d2b803818d | |||
d5e9ff6ad0 | |||
a25cbb4bc7 | |||
8b46d70319 | |||
53c3e49256 | |||
178bafe954 | |||
c632e4d9c3 | |||
d180eaa72e | |||
![]() |
1d0f2610f8 | ||
![]() |
51da9745fa | ||
![]() |
515b62ddcc |
8 changed files with 153 additions and 53 deletions
|
@ -29,3 +29,7 @@ background_path = "~/.local/share/backgrounds/adventurer/t.jpg"
|
||||||
match = "Pioneer Electronic Corporation AV Receiver Unknown"
|
match = "Pioneer Electronic Corporation AV Receiver Unknown"
|
||||||
mode = "3840x2160@60Hz"
|
mode = "3840x2160@60Hz"
|
||||||
scale = 2
|
scale = 2
|
||||||
|
|
||||||
|
[niri]
|
||||||
|
# 1/3 proportion is better for the ultrawide
|
||||||
|
default_column_width = 0.33333
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
wireless = ["wlp170s0"]
|
wireless = ["wlp170s0"]
|
||||||
#ethernet = ["enp2s0"]
|
auto_ethernet = true
|
||||||
temperature_path = "/sys/class/hwmon/hwmon4/temp1_input"
|
temperature_path = "/sys/class/hwmon/hwmon4/temp1_input"
|
||||||
|
has_battery = true
|
||||||
|
|
||||||
[[outputs]]
|
[[outputs]]
|
||||||
match = "eDP-1"
|
match = "eDP-1"
|
||||||
background_path = "~/.local/share/backgrounds/sway-dark-1920x1080.png"
|
background_path = "~/.local/share/backgrounds/liberation.jpg"
|
||||||
scale = 1.25
|
scale = 1
|
||||||
|
|
||||||
[[inputs]]
|
[[inputs]]
|
||||||
match = "2362:628:PIXA3854:00_093A:0274_Touchpad"
|
match = "2362:628:PIXA3854:00_093A:0274_Touchpad"
|
||||||
|
|
50
install.py
50
install.py
|
@ -90,7 +90,7 @@ class OutputConfig:
|
||||||
scale: float | None = None
|
scale: float | None = None
|
||||||
background_path: str | None = None
|
background_path: str | None = None
|
||||||
background_mode: BackgroundMode = BackgroundMode.Fill
|
background_mode: BackgroundMode = BackgroundMode.Fill
|
||||||
device: str | None = None
|
port: str | None = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sway_lines(self) -> str:
|
def sway_lines(self) -> str:
|
||||||
|
@ -108,12 +108,12 @@ class OutputConfig:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def swaylock_image_line(self) -> str | None:
|
def swaylock_image_line(self) -> str | None:
|
||||||
if (self.match != "*" and self.device is None) or self.background_path is None:
|
if (self.match != "*" and self.port is None) or self.background_path is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if self.match == "*":
|
if self.match == "*":
|
||||||
return f"image={self.background_path}"
|
return f"image={self.background_path}"
|
||||||
return f"image={self.device}:{self.background_path}"
|
return f"image={self.port}:{self.background_path}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def niri_lines(self) -> str:
|
def niri_lines(self) -> str:
|
||||||
|
@ -132,8 +132,9 @@ class OutputConfig:
|
||||||
if self.background_path is None:
|
if self.background_path is None:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
key = self.match
|
# TODO: match by serial number instead of by port
|
||||||
if key == "*":
|
key = self.port
|
||||||
|
if self.match == "*":
|
||||||
key = "any"
|
key = "any"
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -144,6 +145,11 @@ class OutputConfig:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@define
|
||||||
|
class NiriConfig:
|
||||||
|
default_column_width: float = 0.5
|
||||||
|
|
||||||
|
|
||||||
@define
|
@define
|
||||||
class HostConfig:
|
class HostConfig:
|
||||||
name: str
|
name: str
|
||||||
|
@ -151,7 +157,9 @@ class HostConfig:
|
||||||
base16_scheme: str = "seti"
|
base16_scheme: str = "seti"
|
||||||
wireless: list[str] = field(factory=list)
|
wireless: list[str] = field(factory=list)
|
||||||
ethernet: list[str] = field(factory=list)
|
ethernet: list[str] = field(factory=list)
|
||||||
|
auto_ethernet: bool = True
|
||||||
disks: list[str] = field(factory=lambda: ["/"])
|
disks: list[str] = field(factory=lambda: ["/"])
|
||||||
|
has_battery: bool = False
|
||||||
system_font: str = "Fira Sans"
|
system_font: str = "Fira Sans"
|
||||||
system_mono_font: str = "Fira Mono"
|
system_mono_font: str = "Fira Mono"
|
||||||
temperature_path: str | None = None
|
temperature_path: str | None = None
|
||||||
|
@ -162,6 +170,7 @@ class HostConfig:
|
||||||
use_jump_host: bool = False
|
use_jump_host: bool = False
|
||||||
inputs: list[InputConfig] = field(factory=list)
|
inputs: list[InputConfig] = field(factory=list)
|
||||||
outputs: list[OutputConfig] = field(factory=list)
|
outputs: list[OutputConfig] = field(factory=list)
|
||||||
|
niri: NiriConfig = field(factory=NiriConfig)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def swaylock_images(self) -> str:
|
def swaylock_images(self) -> str:
|
||||||
|
@ -213,10 +222,11 @@ def main():
|
||||||
)
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
raw_dir = args.dotfiles / "raw"
|
dotfiles_dir: Path = args.dotfiles
|
||||||
templates_dir = args.dotfiles / "templates"
|
raw_dir = dotfiles_dir / "raw"
|
||||||
include_dir = args.dotfiles / "include"
|
templates_dir = dotfiles_dir / "templates"
|
||||||
host_filename = args.dotfiles / "hosts" / "{}.toml".format(args.hostname)
|
include_dir = dotfiles_dir / "include"
|
||||||
|
host_filename = dotfiles_dir / "hosts" / "{}.toml".format(args.hostname)
|
||||||
|
|
||||||
host_toml = {
|
host_toml = {
|
||||||
"name": args.hostname,
|
"name": args.hostname,
|
||||||
|
@ -228,7 +238,7 @@ def main():
|
||||||
host_config = cattrs.structure(host_toml, HostConfig)
|
host_config = cattrs.structure(host_toml, HostConfig)
|
||||||
|
|
||||||
for output in host_config.outputs:
|
for output in host_config.outputs:
|
||||||
# Attempt to resolve device names for swaylock template
|
# Attempt to resolve port names for swaylock template
|
||||||
# (Workaround https://github.com/swaywm/swaylock/issues/114)
|
# (Workaround https://github.com/swaywm/swaylock/issues/114)
|
||||||
#
|
#
|
||||||
# This will only work if this is run on the target host
|
# This will only work if this is run on the target host
|
||||||
|
@ -242,9 +252,9 @@ def main():
|
||||||
["swaymsg", "-t", "get_outputs", "-p"],
|
["swaymsg", "-t", "get_outputs", "-p"],
|
||||||
).decode("utf-8")
|
).decode("utf-8")
|
||||||
for line in get_outputs.splitlines():
|
for line in get_outputs.splitlines():
|
||||||
# Line format: Output <device> '<match identifier>'
|
# Line format: Output <port> '<match identifier>'
|
||||||
if line.startswith("Output") and output.match in line:
|
if line.startswith("Output") and output.match in line:
|
||||||
output.device = line.split()[1]
|
output.port = line.split()[1]
|
||||||
break
|
break
|
||||||
|
|
||||||
elif "NIRI_SOCKET" in os.environ:
|
elif "NIRI_SOCKET" in os.environ:
|
||||||
|
@ -252,9 +262,9 @@ def main():
|
||||||
["niri", "msg", "outputs"],
|
["niri", "msg", "outputs"],
|
||||||
).decode("utf-8")
|
).decode("utf-8")
|
||||||
for line in get_outputs.splitlines():
|
for line in get_outputs.splitlines():
|
||||||
# Line format: Output "<match identifier>" (<device>)
|
# Line format: Output "<match identifier>" (<port>)
|
||||||
if line.startswith("Output") and output.match in line:
|
if line.startswith("Output") and output.match in line:
|
||||||
output.device = (
|
output.port = (
|
||||||
line.split()[-1].removeprefix("(").removesuffix(")")
|
line.split()[-1].removeprefix("(").removesuffix(")")
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
@ -262,9 +272,7 @@ def main():
|
||||||
print(
|
print(
|
||||||
"Could not find SWAYSOCK or NIRI_SOCKET, cannot retrieve output names."
|
"Could not find SWAYSOCK or NIRI_SOCKET, cannot retrieve output names."
|
||||||
)
|
)
|
||||||
print(
|
print("Please re-run in sway or niri to finish configuring swaylock.")
|
||||||
"Please re-run in sway or niri to finish configuring swaylock."
|
|
||||||
)
|
|
||||||
|
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
print("Could not contact sway or niri to retrieve output names.")
|
print("Could not contact sway or niri to retrieve output names.")
|
||||||
|
@ -277,6 +285,8 @@ def main():
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
changed_paths = set()
|
||||||
|
|
||||||
for raw_path in raw_dir.glob("**/*"):
|
for raw_path in raw_dir.glob("**/*"):
|
||||||
if not raw_path.is_file():
|
if not raw_path.is_file():
|
||||||
continue
|
continue
|
||||||
|
@ -287,6 +297,7 @@ def main():
|
||||||
print(rel_path)
|
print(rel_path)
|
||||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
shutil.copy(raw_path, output_path)
|
shutil.copy(raw_path, output_path)
|
||||||
|
changed_paths.update(map(str, rel_path.parents))
|
||||||
|
|
||||||
for template_path in templates_dir.glob("**/*"):
|
for template_path in templates_dir.glob("**/*"):
|
||||||
if not template_path.is_file():
|
if not template_path.is_file():
|
||||||
|
@ -312,6 +323,11 @@ def main():
|
||||||
|
|
||||||
# Copy permissions from original file
|
# Copy permissions from original file
|
||||||
output_path.chmod(template_path.stat().st_mode & 0o777)
|
output_path.chmod(template_path.stat().st_mode & 0o777)
|
||||||
|
changed_paths.update(map(str, rel_path.parents))
|
||||||
|
|
||||||
|
# Post-install hooks
|
||||||
|
if ".config/waybar" in changed_paths:
|
||||||
|
subprocess.call(["killall", "-USR2", "waybar"])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
1
raw/.local/share/backgrounds/liberation.jpg
Symbolic link
1
raw/.local/share/backgrounds/liberation.jpg
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
chase-baker-NPiv36bUc4I-unsplash.jpg
|
|
@ -56,6 +56,9 @@ input {
|
||||||
// Focus windows and outputs automatically when moving the mouse into them.
|
// Focus windows and outputs automatically when moving the mouse into them.
|
||||||
// Setting max-scroll-amount="0%" makes it work only on windows already fully on screen.
|
// Setting max-scroll-amount="0%" makes it work only on windows already fully on screen.
|
||||||
// focus-follows-mouse max-scroll-amount="0%"
|
// focus-follows-mouse max-scroll-amount="0%"
|
||||||
|
|
||||||
|
// https://github.com/YaLTeR/niri/wiki/Configuration:-Input#disable-power-key-handling
|
||||||
|
disable-power-key-handling
|
||||||
}
|
}
|
||||||
|
|
||||||
% for output in host.outputs:
|
% for output in host.outputs:
|
||||||
|
@ -97,7 +100,7 @@ layout {
|
||||||
// preset-window-heights { }
|
// preset-window-heights { }
|
||||||
|
|
||||||
// You can change the default width of the new windows.
|
// You can change the default width of the new windows.
|
||||||
default-column-width { proportion 0.33333; }
|
default-column-width { proportion ${host.niri.default_column_width}; }
|
||||||
// If you leave the brackets empty, the windows themselves will decide their initial width.
|
// If you leave the brackets empty, the windows themselves will decide their initial width.
|
||||||
// default-column-width {}
|
// default-column-width {}
|
||||||
|
|
||||||
|
@ -190,6 +193,11 @@ environment {
|
||||||
DISPLAY ":12"
|
DISPLAY ":12"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cursor {
|
||||||
|
xcursor-theme "breeze_cursors"
|
||||||
|
xcursor-size 24
|
||||||
|
}
|
||||||
|
|
||||||
// Uncomment this line to ask the clients to omit their client-side decorations if possible.
|
// Uncomment this line to ask the clients to omit their client-side decorations if possible.
|
||||||
// If the client will specifically ask for CSD, the request will be honored.
|
// If the client will specifically ask for CSD, the request will be honored.
|
||||||
// Additionally, clients will be informed that they are tiled, removing some client-side rounded corners.
|
// Additionally, clients will be informed that they are tiled, removing some client-side rounded corners.
|
||||||
|
@ -306,14 +314,14 @@ binds {
|
||||||
Mod+K { focus-window-up; }
|
Mod+K { focus-window-up; }
|
||||||
Mod+L { focus-column-right; }
|
Mod+L { focus-column-right; }
|
||||||
|
|
||||||
Mod+Ctrl+Left { move-column-left; }
|
Mod+Shift+Left { move-column-left; }
|
||||||
Mod+Ctrl+Down { move-window-down; }
|
Mod+Shift+Down { move-window-down; }
|
||||||
Mod+Ctrl+Up { move-window-up; }
|
Mod+Shift+Up { move-window-up; }
|
||||||
Mod+Ctrl+Right { move-column-right; }
|
Mod+Shift+Right { move-column-right; }
|
||||||
Mod+Ctrl+H { move-column-left; }
|
Mod+Shift+H { move-column-left; }
|
||||||
Mod+Ctrl+J { move-window-down; }
|
Mod+Shift+J { move-window-down; }
|
||||||
Mod+Ctrl+K { move-window-up; }
|
Mod+Shift+K { move-window-up; }
|
||||||
Mod+Ctrl+L { move-column-right; }
|
Mod+Shift+L { move-column-right; }
|
||||||
|
|
||||||
// Alternative commands that move across workspaces when reaching
|
// Alternative commands that move across workspaces when reaching
|
||||||
// the first or last window in a column.
|
// the first or last window in a column.
|
||||||
|
@ -327,31 +335,23 @@ binds {
|
||||||
Mod+Ctrl+Home { move-column-to-first; }
|
Mod+Ctrl+Home { move-column-to-first; }
|
||||||
Mod+Ctrl+End { move-column-to-last; }
|
Mod+Ctrl+End { move-column-to-last; }
|
||||||
|
|
||||||
Mod+Shift+Left { focus-monitor-left; }
|
Mod+Ctrl+Left { focus-monitor-left; }
|
||||||
Mod+Shift+Down { focus-monitor-down; }
|
Mod+Ctrl+Down { focus-monitor-down; }
|
||||||
Mod+Shift+Up { focus-monitor-up; }
|
Mod+Ctrl+Up { focus-monitor-up; }
|
||||||
Mod+Shift+Right { focus-monitor-right; }
|
Mod+Ctrl+Right { focus-monitor-right; }
|
||||||
Mod+Shift+H { focus-monitor-left; }
|
Mod+Ctrl+H { focus-monitor-left; }
|
||||||
Mod+Shift+J { focus-monitor-down; }
|
Mod+Ctrl+J { focus-monitor-down; }
|
||||||
Mod+Shift+K { focus-monitor-up; }
|
Mod+Ctrl+K { focus-monitor-up; }
|
||||||
Mod+Shift+L { focus-monitor-right; }
|
Mod+Ctrl+L { focus-monitor-right; }
|
||||||
|
|
||||||
Mod+Shift+Ctrl+Left { move-column-to-monitor-left; }
|
Mod+Shift+Ctrl+Left { move-workspace-to-monitor-left; }
|
||||||
Mod+Shift+Ctrl+Down { move-column-to-monitor-down; }
|
Mod+Shift+Ctrl+Down { move-workspace-to-monitor-down; }
|
||||||
Mod+Shift+Ctrl+Up { move-column-to-monitor-up; }
|
Mod+Shift+Ctrl+Up { move-workspace-to-monitor-up; }
|
||||||
Mod+Shift+Ctrl+Right { move-column-to-monitor-right; }
|
Mod+Shift+Ctrl+Right { move-workspace-to-monitor-right; }
|
||||||
Mod+Shift+Ctrl+H { move-column-to-monitor-left; }
|
Mod+Shift+Ctrl+H { move-workspace-to-monitor-left; }
|
||||||
Mod+Shift+Ctrl+J { move-column-to-monitor-down; }
|
Mod+Shift+Ctrl+J { move-workspace-to-monitor-down; }
|
||||||
Mod+Shift+Ctrl+K { move-column-to-monitor-up; }
|
Mod+Shift+Ctrl+K { move-workspace-to-monitor-up; }
|
||||||
Mod+Shift+Ctrl+L { move-column-to-monitor-right; }
|
Mod+Shift+Ctrl+L { move-workspace-to-monitor-right; }
|
||||||
|
|
||||||
// Alternatively, there are commands to move just a single window:
|
|
||||||
// Mod+Shift+Ctrl+Left { move-window-to-monitor-left; }
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// And you can also move a whole workspace to another monitor:
|
|
||||||
// Mod+Shift+Ctrl+Left { move-workspace-to-monitor-left; }
|
|
||||||
// ...
|
|
||||||
|
|
||||||
Mod+Page_Down { focus-workspace-down; }
|
Mod+Page_Down { focus-workspace-down; }
|
||||||
Mod+Page_Up { focus-workspace-up; }
|
Mod+Page_Up { focus-workspace-up; }
|
||||||
|
|
|
@ -16,7 +16,12 @@
|
||||||
"network#${iface}",
|
"network#${iface}",
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
|
% if not host.ethernet and host.auto_ethernet:
|
||||||
|
"network#auto_ethernet",
|
||||||
|
% endif
|
||||||
|
|
||||||
"wireplumber",
|
"wireplumber",
|
||||||
|
"battery",
|
||||||
"group/disks",
|
"group/disks",
|
||||||
"cpu",
|
"cpu",
|
||||||
"memory",
|
"memory",
|
||||||
|
@ -49,12 +54,39 @@
|
||||||
},
|
},
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
|
% if not host.ethernet and host.auto_ethernet:
|
||||||
|
"network#auto_ethernet": {
|
||||||
|
"interface": "en*",
|
||||||
|
"format": "\uf6ff \uf058",
|
||||||
|
"format-disconnected": "\uf6ff \uf057",
|
||||||
|
"tooltip-format": "${iface} {ipaddr}",
|
||||||
|
"tooltip-format-disconnected": "${iface} down"
|
||||||
|
},
|
||||||
|
% endif
|
||||||
|
|
||||||
"wireplumber": {
|
"wireplumber": {
|
||||||
"format": "{icon} {volume}%",
|
"format": "{icon} {volume}%",
|
||||||
"format-muted": "\uf6a9 {volume}%",
|
"format-muted": "\uf6a9 {volume}%",
|
||||||
"format-icons": ["\uf026", "\uf027", "\uf028"]
|
"format-icons": ["\uf026", "\uf027", "\uf028"]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
% if host.has_battery:
|
||||||
|
"battery": {
|
||||||
|
"design-capacity": true,
|
||||||
|
"format": "{icon} {capacity}% {time}",
|
||||||
|
"format-time": "{H}:{m}",
|
||||||
|
"format-icons": [
|
||||||
|
"\uf244",
|
||||||
|
"\uf243",
|
||||||
|
"\uf242",
|
||||||
|
"\uf241",
|
||||||
|
"\uf240",
|
||||||
|
],
|
||||||
|
"format-charging": "\ue55b {capacity}% {time}",
|
||||||
|
"format-full": "\ue55c {capacity}%",
|
||||||
|
},
|
||||||
|
% endif
|
||||||
|
|
||||||
"group/disks": {
|
"group/disks": {
|
||||||
// TODO: make drawer that expands orthogonally, outside of the bar
|
// TODO: make drawer that expands orthogonally, outside of the bar
|
||||||
"orientation": "inherit",
|
"orientation": "inherit",
|
||||||
|
|
46
templates/bin/wifi-pass
Executable file
46
templates/bin/wifi-pass
Executable file
|
@ -0,0 +1,46 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
from io import StringIO
|
||||||
|
import subprocess
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="""
|
||||||
|
Fetch the wifi password and generate a QR code.
|
||||||
|
|
||||||
|
This program assumes that the network PSK is stored
|
||||||
|
in the password-store, and will look for it
|
||||||
|
at the path `wifi/<essid>`.
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-H",
|
||||||
|
"--hidden",
|
||||||
|
action="store_true",
|
||||||
|
help="Indicate that this network's SSID is hidden.",
|
||||||
|
)
|
||||||
|
parser.add_argument("essid", help="ESSID for this network")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
psk = subprocess.check_output(["pass", f"wifi/{args.essid}"], text=True).strip()
|
||||||
|
|
||||||
|
hidden_data = "H:true;" if args.hidden else ""
|
||||||
|
qr_data = f"WIFI:T:WPA;S:{quote(args.essid)};{hidden_data}P:{quote(psk)};;"
|
||||||
|
|
||||||
|
proc = subprocess.Popen(["qrencode", "-tANSI"], stdin=subprocess.PIPE, text=True)
|
||||||
|
proc.communicate(qr_data)
|
||||||
|
|
||||||
|
|
||||||
|
PRINTABLE = [*range(0x20, 0x3B), *range(0x3C, 0x7F)]
|
||||||
|
|
||||||
|
|
||||||
|
def quote(s: str) -> str:
|
||||||
|
return urllib.parse.quote(s, safe=PRINTABLE)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Add table
Reference in a new issue