sway
This commit is contained in:
parent
492f085d52
commit
bb021a1aae
30 changed files with 487 additions and 573 deletions
|
@ -24,7 +24,6 @@
|
||||||
hardware.enableRedistributableFirmware = true;
|
hardware.enableRedistributableFirmware = true;
|
||||||
|
|
||||||
frogeye.desktop = {
|
frogeye.desktop = {
|
||||||
x11_screens = [ "DP-2" "eDP-1" ];
|
|
||||||
maxVideoHeight = 1080;
|
maxVideoHeight = 1080;
|
||||||
|
|
||||||
phasesCommands = {
|
phasesCommands = {
|
||||||
|
@ -47,7 +46,7 @@
|
||||||
home-manager.users.geoffrey =
|
home-manager.users.geoffrey =
|
||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
xsession.windowManager.i3.config.modifier = "Mod1";
|
wayland.windowManager.sway.config.modifier = "Mod1";
|
||||||
};
|
};
|
||||||
|
|
||||||
# 8 makes it run out of memory when rebuilding.
|
# 8 makes it run out of memory when rebuilding.
|
||||||
|
|
|
@ -6,18 +6,9 @@
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
displays = {
|
displays = {
|
||||||
embedded = {
|
embedded = "Chimei Innolux Corporation 0x1738 Unknown";
|
||||||
output = "eDP-1";
|
deskLeft = "Samsung Electric Company S24B420 H4MCB03534"; # Internal HDMI
|
||||||
edid = "00ffffffffffff000dae381700000000011c01049526157802a155a556519d280b505400000001010101010101010101010101010101b43b804a71383440302035007dd61000001ac32f804a71383440302035007dd61000001a000000fe003059395747803137334843450a00000000000041319e001000000a010a2020004f";
|
deskRight = "Samsung Electric Company S24B420 H4MC800865"; # DisplayLink DVI
|
||||||
};
|
|
||||||
deskLeft = {
|
|
||||||
output = "HDMI-1-3"; # Internal HDMI port
|
|
||||||
edid = "00ffffffffffff004c2d7b09333032302f160103803420782a01f1a257529f270a505423080081c0810081809500a9c0b300d1c00101283c80a070b023403020360006442100001a000000fd00353f1e5111000a202020202020000000fc00533234423432300a2020202020000000ff0048344d434230333533340a2020010702010400023a80d072382d40102c458006442100001e011d007251d01e206e28550006442100001e011d00bc52d01e20b828554006442100001e8c0ad090204031200c4055000644210000188c0ad08a20e02d10103e9600064421000018000000000000000000000000000000000000000000000000000000000000000000d2";
|
|
||||||
};
|
|
||||||
deskRight = {
|
|
||||||
output = "DVI-I-2-1"; # DisplayLink
|
|
||||||
edid = "00ffffffffffff004c2d7b093330323020160103803420782a01f1a257529f270a505423080081c0810081809500a9c0b300d1c00101283c80a070b023403020360006442100001a000000fd00353f1e5111000a202020202020000000fc00533234423432300a2020202020000000ff0048344d433830303836350a2020011c02010400023a80d072382d40102c458006442100001e011d007251d01e206e28550006442100001e011d00bc52d01e20b828554006442100001e8c0ad090204031200c4055000644210000188c0ad08a20e02d10103e9600064421000018000000000000000000000000000000000000000000000000000000000000000000d2";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
@ -33,8 +24,6 @@ in
|
||||||
"rtsx_usb_sdmmc"
|
"rtsx_usb_sdmmc"
|
||||||
];
|
];
|
||||||
kernelModules = [ "kvm-intel" ];
|
kernelModules = [ "kvm-intel" ];
|
||||||
kernelPackages = pkgs.linuxKernel.packages.linux_6_6;
|
|
||||||
# displaylink doesn't seem to be working for kernels >= 6.9?
|
|
||||||
|
|
||||||
# UEFI works here, and variables can be touched
|
# UEFI works here, and variables can be touched
|
||||||
loader = {
|
loader = {
|
||||||
|
@ -55,12 +44,7 @@ in
|
||||||
hardware.keyboard.qmk.enable = true;
|
hardware.keyboard.qmk.enable = true;
|
||||||
|
|
||||||
frogeye.desktop = {
|
frogeye.desktop = {
|
||||||
x11_screens = [
|
|
||||||
displays.deskLeft.output
|
|
||||||
displays.deskRight.output
|
|
||||||
];
|
|
||||||
maxVideoHeight = 1440;
|
maxVideoHeight = 1440;
|
||||||
numlock = true;
|
|
||||||
phasesCommands = {
|
phasesCommands = {
|
||||||
jour = ''
|
jour = ''
|
||||||
${pkgs.brightnessctl}/bin/brightnessctl set 40000 &
|
${pkgs.brightnessctl}/bin/brightnessctl set 40000 &
|
||||||
|
@ -80,44 +64,80 @@ in
|
||||||
# TODO Display 2 doesn't work anymore?
|
# TODO Display 2 doesn't work anymore?
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Screens
|
||||||
|
home-manager.users.geoffrey =
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
services = {
|
services = {
|
||||||
autorandr = {
|
kanshi.settings = [
|
||||||
profiles = {
|
{
|
||||||
portable = {
|
profile = {
|
||||||
fingerprint.${displays.embedded.output} = displays.embedded.edid;
|
name = "portable";
|
||||||
config.${displays.embedded.output} = { };
|
outputs = [
|
||||||
|
{ criteria = displays.embedded; }
|
||||||
|
];
|
||||||
};
|
};
|
||||||
extOnly = {
|
}
|
||||||
fingerprint = {
|
{
|
||||||
${displays.embedded.output} = displays.embedded.edid;
|
profile = {
|
||||||
${displays.deskLeft.output} = displays.deskLeft.edid;
|
name = "extOnly";
|
||||||
${displays.deskRight.output} = displays.deskRight.edid;
|
outputs = [
|
||||||
|
{
|
||||||
|
criteria = displays.embedded;
|
||||||
|
status = "disable";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
criteria = displays.deskLeft;
|
||||||
|
position = "0,0";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
criteria = displays.deskRight;
|
||||||
|
position = "1920,0";
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
config = {
|
}
|
||||||
${displays.embedded.output}.enable = false;
|
{
|
||||||
${displays.deskLeft.output} = {
|
profile = {
|
||||||
primary = true;
|
name = "leftOnly";
|
||||||
mode = "1920x1200";
|
outputs = [
|
||||||
rate = "59.95";
|
{
|
||||||
position = "0x0";
|
criteria = displays.embedded;
|
||||||
|
status = "disable";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
criteria = displays.deskLeft;
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
${displays.deskRight.output} = {
|
}
|
||||||
mode = "1920x1200";
|
];
|
||||||
rate = "59.95";
|
|
||||||
position = "1920x0";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Displaylink
|
||||||
|
environment.variables = {
|
||||||
|
WLR_EVDI_RENDER_DEVICE = "/dev/dri/card1";
|
||||||
};
|
};
|
||||||
# TODO leftOnly and other things.Might want to abstract a few things first.
|
nixpkgs.overlays = [
|
||||||
};
|
(final: prev: {
|
||||||
};
|
wlroots_0_18 = prev.wlroots_0_18.overrideAttrs (old: {
|
||||||
# Needs prefetched binary blobs, see https://nixos.wiki/wiki/Displaylink
|
patches = (old.patches or [ ]) ++ [
|
||||||
xserver.videoDrivers = [
|
(prev.fetchpatch {
|
||||||
|
url = "https://gitlab.freedesktop.org/wlroots/wlroots/uploads/bd115aa120d20f2c99084951589abf9c/DisplayLink_v2.patch";
|
||||||
|
hash = "sha256-vWQc2e8a5/YZaaHe+BxfAR/Ni8HOs2sPJ8Nt9pfxqiE=";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
});
|
||||||
|
})
|
||||||
|
];
|
||||||
|
services.xserver.videoDrivers = [
|
||||||
"displaylink"
|
"displaylink"
|
||||||
"modesetting"
|
"modesetting"
|
||||||
];
|
];
|
||||||
# TODO See if nvidia and DL can work together.
|
systemd.services.dlm.wantedBy = [ "multi-user.target" ];
|
||||||
};
|
# Needs prefetched binary blobs, see https://wiki.nixos.org/wiki/Displaylink
|
||||||
};
|
};
|
||||||
imports = [
|
imports = [
|
||||||
nixos-hardware.nixosModules.dell-g3-3779
|
nixos-hardware.nixosModules.dell-g3-3779
|
||||||
|
|
19
flake.lock
generated
19
flake.lock
generated
|
@ -654,7 +654,8 @@
|
||||||
"nur": "nur",
|
"nur": "nur",
|
||||||
"onixpkgs": "onixpkgs",
|
"onixpkgs": "onixpkgs",
|
||||||
"stylix": "stylix",
|
"stylix": "stylix",
|
||||||
"unixpkgs": "unixpkgs"
|
"unixpkgs": "unixpkgs",
|
||||||
|
"zelbarnixpkgs": "zelbarnixpkgs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scss-reset": {
|
"scss-reset": {
|
||||||
|
@ -909,6 +910,22 @@
|
||||||
"ref": "master",
|
"ref": "master",
|
||||||
"type": "indirect"
|
"type": "indirect"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"zelbarnixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1748415083,
|
||||||
|
"narHash": "sha256-jmIRxOA7kj1CFNiP6S6pg6e6XeQi3whBVvWsATpEiC4=",
|
||||||
|
"owner": "GeoffreyFrogeye",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "bc0e8ee7d08241e8fbcb5e13a7abb445329e5644",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "GeoffreyFrogeye",
|
||||||
|
"ref": "zelbar",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
onixpkgs.url = "nixpkgs/nixos-24.11";
|
onixpkgs.url = "nixpkgs/nixos-24.11";
|
||||||
nixpkgs.url = "nixpkgs/nixos-25.05";
|
nixpkgs.url = "nixpkgs/nixos-25.05";
|
||||||
unixpkgs.url = "nixpkgs/master";
|
unixpkgs.url = "nixpkgs/master";
|
||||||
|
zelbarnixpkgs.url = "github:GeoffreyFrogeye/nixpkgs/zelbar";
|
||||||
# OS
|
# OS
|
||||||
disko = {
|
disko = {
|
||||||
url = "disko";
|
url = "disko";
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
self,
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
unixpkgs,
|
unixpkgs,
|
||||||
|
zelbarnixpkgs,
|
||||||
disko,
|
disko,
|
||||||
nix-on-droid,
|
nix-on-droid,
|
||||||
flake-utils,
|
flake-utils,
|
||||||
|
@ -62,9 +64,11 @@
|
||||||
self: super:
|
self: super:
|
||||||
let
|
let
|
||||||
upkgs = import unixpkgs { inherit (super) system; };
|
upkgs = import unixpkgs { inherit (super) system; };
|
||||||
|
zelbarpkgs = import zelbarnixpkgs { inherit (super) system; };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
hello = upkgs.hello; # Placeholder
|
hello = upkgs.hello; # Placeholder
|
||||||
|
zelbar = zelbarpkgs.zelbar;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
|
|
@ -20,7 +20,7 @@ let
|
||||||
specialisation = "dark";
|
specialisation = "dark";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
mod = config.xsession.windowManager.i3.config.modifier;
|
mod = config.wayland.windowManager.sway.config.modifier;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = {
|
config = {
|
||||||
|
@ -48,7 +48,7 @@ in
|
||||||
++ (with pkgs; [
|
++ (with pkgs; [
|
||||||
brightnessctl
|
brightnessctl
|
||||||
]);
|
]);
|
||||||
xsession.windowManager.i3.config.keybindings = {
|
wayland.windowManager.sway.config.keybindings = lib.mkOptionDefault {
|
||||||
XF86MonBrightnessUp = "exec ${pkgs.brightnessctl}/bin/brightnessctl set +5%";
|
XF86MonBrightnessUp = "exec ${pkgs.brightnessctl}/bin/brightnessctl set +5%";
|
||||||
XF86MonBrightnessDown = "exec ${pkgs.brightnessctl}/bin/brightnessctl set 5%-";
|
XF86MonBrightnessDown = "exec ${pkgs.brightnessctl}/bin/brightnessctl set 5%-";
|
||||||
"${mod}+F6" = "exec ${pkgs.brightnessctl}/bin/brightnessctl set 1%-";
|
"${mod}+F6" = "exec ${pkgs.brightnessctl}/bin/brightnessctl set 1%-";
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
pactl = "exec ${pkgs.pulseaudio}/bin/pactl"; # TODO Use NixOS package if using NixOS
|
pactl = "exec ${pkgs.pulseaudio}/bin/pactl"; # TODO Use NixOS package if using NixOS
|
||||||
mod = config.xsession.windowManager.i3.config.modifier;
|
mod = config.wayland.windowManager.sway.config.modifier;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = lib.mkIf config.frogeye.desktop.xorg {
|
config = lib.mkIf config.frogeye.desktop.xorg {
|
||||||
|
@ -32,7 +32,7 @@ in
|
||||||
text = ''cookie-file = .config/pulse/pulse-cookie'';
|
text = ''cookie-file = .config/pulse/pulse-cookie'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
xsession.windowManager.i3.config.keybindings = {
|
wayland.windowManager.sway.config.keybindings = lib.mkOptionDefault {
|
||||||
"XF86AudioRaiseVolume" = "${pactl} set-sink-mute @DEFAULT_SINK@ false; ${pactl} set-sink-volume @DEFAULT_SINK@ +5%";
|
"XF86AudioRaiseVolume" = "${pactl} set-sink-mute @DEFAULT_SINK@ false; ${pactl} set-sink-volume @DEFAULT_SINK@ +5%";
|
||||||
"XF86AudioLowerVolume" = "${pactl} set-sink-mute @DEFAULT_SINK@ false; ${pactl} set-sink-volume @DEFAULT_SINK@ -5%";
|
"XF86AudioLowerVolume" = "${pactl} set-sink-mute @DEFAULT_SINK@ false; ${pactl} set-sink-volume @DEFAULT_SINK@ -5%";
|
||||||
"XF86AudioMute" = "${pactl} set-sink-mute @DEFAULT_SINK@ true";
|
"XF86AudioMute" = "${pactl} set-sink-mute @DEFAULT_SINK@ true";
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
{
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
builtin_configs = [
|
|
||||||
"off"
|
|
||||||
"common"
|
|
||||||
"clone-largest"
|
|
||||||
"horizontal"
|
|
||||||
"vertical"
|
|
||||||
"horizontal-reverse"
|
|
||||||
"vertical-reverse"
|
|
||||||
];
|
|
||||||
autorandrmenu =
|
|
||||||
{
|
|
||||||
title,
|
|
||||||
option,
|
|
||||||
builtin ? false,
|
|
||||||
}:
|
|
||||||
pkgs.writeShellScript "autorandrmenu" ''
|
|
||||||
shopt -s nullglob globstar
|
|
||||||
profiles="${
|
|
||||||
if builtin then lib.strings.concatLines builtin_configs else ""
|
|
||||||
}$(${pkgs.autorandr}/bin/autorandr | ${pkgs.gawk}/bin/awk '{ print $1 }')"
|
|
||||||
profile="$(echo "$profiles" | ${config.programs.rofi.package}/bin/rofi -dmenu -p "${title}")"
|
|
||||||
[[ -n "$profile" ]] || exit
|
|
||||||
${pkgs.autorandr}/bin/autorandr ${option} "$profile"
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
{
|
|
||||||
config = lib.mkIf config.frogeye.desktop.xorg {
|
|
||||||
frogeye.desktop.i3.bindmodes = {
|
|
||||||
"Screen setup [A] Auto [L] Load [S] Save [R] Remove [D] Default" = {
|
|
||||||
bindings = {
|
|
||||||
"a" = "exec ${pkgs.autorandr}/bin/autorandr --change --force, mode default";
|
|
||||||
"l" = "exec ${
|
|
||||||
autorandrmenu {
|
|
||||||
title = "Load profile";
|
|
||||||
option = "--load";
|
|
||||||
builtin = true;
|
|
||||||
}
|
|
||||||
}, mode default";
|
|
||||||
"s" = "exec ${
|
|
||||||
autorandrmenu {
|
|
||||||
title = "Save profile";
|
|
||||||
option = "--save";
|
|
||||||
}
|
|
||||||
}, mode default";
|
|
||||||
"r" = "exec ${
|
|
||||||
autorandrmenu {
|
|
||||||
title = "Remove profile";
|
|
||||||
option = "--remove";
|
|
||||||
}
|
|
||||||
}, mode default";
|
|
||||||
"d" = "exec ${
|
|
||||||
autorandrmenu {
|
|
||||||
title = "Default profile";
|
|
||||||
option = "--default";
|
|
||||||
builtin = true;
|
|
||||||
}
|
|
||||||
}, mode default";
|
|
||||||
};
|
|
||||||
mod_enter = "t";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
programs.autorandr.enable = true;
|
|
||||||
services.autorandr.enable = true;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
config = {
|
|
||||||
# This correctly sets the background on some occasions, below does the rest
|
|
||||||
programs.autorandr.hooks.postswitch = {
|
|
||||||
background = "${pkgs.feh}/bin/feh --no-fehbg --bg-fill ${config.stylix.image}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -122,7 +122,7 @@
|
||||||
github = "https://github.com/search?q={}";
|
github = "https://github.com/search?q={}";
|
||||||
google = "https://www.google.fr/search?q={}";
|
google = "https://www.google.fr/search?q={}";
|
||||||
hm = homemanager;
|
hm = homemanager;
|
||||||
homemanager = "https://home-manager-options.extranix.com/?query={}&release=${config.home.version.release}";
|
homemanager = "https://home-manager-options.extranix.com/?query={}&release=release-${config.home.version.release}";
|
||||||
invidious = "https://invidious.frogeye.fr/search?q={}";
|
invidious = "https://invidious.frogeye.fr/search?q={}";
|
||||||
inv = invidious;
|
inv = invidious;
|
||||||
nixos = "https://search.nixos.org/options?channel=${config.home.version.release}&query={}";
|
nixos = "https://search.nixos.org/options?channel=${config.home.version.release}&query={}";
|
||||||
|
@ -194,8 +194,8 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
xsession.windowManager.i3.config.keybindings = {
|
wayland.windowManager.sway.config.keybindings = lib.mkOptionDefault {
|
||||||
"${config.xsession.windowManager.i3.config.modifier}+m" =
|
"${config.wayland.windowManager.sway.config.modifier}+m" =
|
||||||
"exec ${config.programs.qutebrowser.package}/bin/qutebrowser --override-restore";
|
"exec ${config.programs.qutebrowser.package}/bin/qutebrowser --override-restore";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,43 +7,32 @@
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./audio
|
./audio
|
||||||
./autorandr
|
|
||||||
./background
|
|
||||||
./browser
|
./browser
|
||||||
./cursor
|
./cursor
|
||||||
./frobar/module.nix
|
./frobar/module.nix
|
||||||
./i3.nix
|
|
||||||
./lock
|
./lock
|
||||||
./mpd
|
./mpd
|
||||||
./presentation
|
./presentation
|
||||||
./redness
|
|
||||||
./screenshots
|
./screenshots
|
||||||
|
./sway
|
||||||
./terminal
|
./terminal
|
||||||
];
|
];
|
||||||
config = lib.mkIf config.frogeye.desktop.xorg {
|
config = lib.mkIf config.frogeye.desktop.xorg {
|
||||||
|
wayland.windowManager.sway.enable = true;
|
||||||
xsession = {
|
|
||||||
enable = true;
|
|
||||||
# Not using config.xdg.configHome because it needs to be $HOME-relative paths and path manipulation is hard
|
|
||||||
scriptPath = ".config/xsession";
|
|
||||||
profilePath = ".config/xprofile";
|
|
||||||
windowManager = {
|
|
||||||
i3.enable = true;
|
|
||||||
};
|
|
||||||
numlock.enable = config.frogeye.desktop.numlock;
|
|
||||||
};
|
|
||||||
|
|
||||||
programs = {
|
programs = {
|
||||||
# Terminal
|
# Terminal
|
||||||
bash.shellAliases = {
|
bash.shellAliases = {
|
||||||
x = "startx ${config.home.homeDirectory}/${config.xsession.scriptPath}; logout";
|
|
||||||
lmms = "lmms --config ${config.xdg.configHome}/lmmsrc.xml";
|
lmms = "lmms --config ${config.xdg.configHome}/lmmsrc.xml";
|
||||||
};
|
};
|
||||||
rofi = {
|
rofi = {
|
||||||
# TODO This theme template, that was used for Arch, looks much better:
|
# TODO This theme template, that was used for Arch, looks much better:
|
||||||
# https://gitlab.com/jordiorlando/base16-rofi/-/blob/master/templates/default.mustache
|
# https://gitlab.com/jordiorlando/base16-rofi/-/blob/master/templates/default.mustache
|
||||||
enable = true;
|
enable = true;
|
||||||
pass.enable = true;
|
pass = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.rofi-pass-wayland;
|
||||||
|
};
|
||||||
extraConfig = {
|
extraConfig = {
|
||||||
lazy-grab = false;
|
lazy-grab = false;
|
||||||
matching = "regex";
|
matching = "regex";
|
||||||
|
@ -111,7 +100,6 @@
|
||||||
};
|
};
|
||||||
services = {
|
services = {
|
||||||
blueman-applet.enable = true;
|
blueman-applet.enable = true;
|
||||||
unclutter.enable = true;
|
|
||||||
dunst = {
|
dunst = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = with config.lib.stylix.colors.withHashtag; {
|
settings = with config.lib.stylix.colors.withHashtag; {
|
||||||
|
@ -139,7 +127,7 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
keynav.enable = true;
|
kanshi.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
home = {
|
home = {
|
||||||
|
@ -176,13 +164,13 @@
|
||||||
meld
|
meld
|
||||||
python3Packages.magic
|
python3Packages.magic
|
||||||
bluetuith
|
bluetuith
|
||||||
|
trayer # For occasional applications that want to put themselves in tray
|
||||||
|
|
||||||
# x11-exclusive
|
# wayland exclusive
|
||||||
simplescreenrecorder
|
wl-clipboard # Easy copy/paste from/to terminal
|
||||||
trayer
|
# TODO Clipboard history?
|
||||||
xclip
|
wdisplays # Ad-hoc display setup GUI
|
||||||
xorg.xinit
|
wf-recorder # Screen recorder (much more basic than simplescreenrecorder but alright)
|
||||||
scrot
|
|
||||||
];
|
];
|
||||||
sessionVariables = {
|
sessionVariables = {
|
||||||
# XAUTHORITY = "${config.xdg.configHome}/Xauthority"; # Disabled as this causes lock-ups with DMs
|
# XAUTHORITY = "${config.xdg.configHome}/Xauthority"; # Disabled as this causes lock-ups with DMs
|
||||||
|
|
|
@ -1,23 +1,12 @@
|
||||||
{
|
{
|
||||||
pkgs ? import <nixpkgs> {
|
# nixpkgs ? builtins.getFlake "github:GeoffreyFrogeye/nixpkgs/zelbar",
|
||||||
|
nixpkgs ? /nix/store/8g86qw3c2fr56bhhvqznrlic4jig9hb3-source,
|
||||||
|
pkgs ? import nixpkgs {
|
||||||
config = { };
|
config = { };
|
||||||
overlays = [ ];
|
overlays = [ ];
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
|
||||||
lemonbar = (
|
|
||||||
pkgs.lemonbar-xft.overrideAttrs (old: {
|
|
||||||
src = pkgs.fetchFromGitHub {
|
|
||||||
owner = "drscream";
|
|
||||||
repo = "lemonbar-xft";
|
|
||||||
rev = "a64a2a6a6d643f4d92f9d7600722710eebce7bdb";
|
|
||||||
sha256 = "sha256-T5FhEPIiDt/9paJwL9Sj84CBtA0YFi1hZz0+87Hd6jU=";
|
|
||||||
# https://github.com/drscream/lemonbar-xft/pull/2
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
in
|
|
||||||
# Tried using pyproject.nix but mpd2 dependency wouldn't resolve,
|
# Tried using pyproject.nix but mpd2 dependency wouldn't resolve,
|
||||||
# is called pyton-mpd2 on PyPi but mpd2 in nixpkgs.
|
# is called pyton-mpd2 on PyPi but mpd2 in nixpkgs.
|
||||||
pkgs.python3Packages.buildPythonApplication rec {
|
pkgs.python3Packages.buildPythonApplication rec {
|
||||||
|
@ -31,12 +20,12 @@ pkgs.python3Packages.buildPythonApplication rec {
|
||||||
pygobject3
|
pygobject3
|
||||||
rich
|
rich
|
||||||
];
|
];
|
||||||
nativeBuildInputs =
|
# TODO Might just be buildInputs, maybe without the need for prefix?
|
||||||
[ lemonbar ]
|
nativeBuildInputs = with pkgs; [
|
||||||
++ (with pkgs; [
|
|
||||||
wirelesstools
|
wirelesstools
|
||||||
playerctl
|
playerctl
|
||||||
]);
|
zelbar
|
||||||
|
];
|
||||||
makeWrapperArgs = [
|
makeWrapperArgs = [
|
||||||
"--prefix PATH : ${pkgs.lib.makeBinPath nativeBuildInputs}"
|
"--prefix PATH : ${pkgs.lib.makeBinPath nativeBuildInputs}"
|
||||||
"--prefix GI_TYPELIB_PATH : ${GI_TYPELIB_PATH}"
|
"--prefix GI_TYPELIB_PATH : ${GI_TYPELIB_PATH}"
|
||||||
|
|
|
@ -36,9 +36,7 @@ def main() -> None:
|
||||||
|
|
||||||
theme = rich.terminal_theme.TerminalTheme(
|
theme = rich.terminal_theme.TerminalTheme(
|
||||||
base16_color(0x0),
|
base16_color(0x0),
|
||||||
base16_color(
|
base16_color(0x7),
|
||||||
0x0
|
|
||||||
), # TODO should be 7, currently 0 so it's compatible with v2
|
|
||||||
[
|
[
|
||||||
base16_color(0x0), # black
|
base16_color(0x0), # black
|
||||||
base16_color(0x8), # red
|
base16_color(0x8), # red
|
||||||
|
@ -68,7 +66,7 @@ def main() -> None:
|
||||||
|
|
||||||
workspaces_suffixes = "▲■"
|
workspaces_suffixes = "▲■"
|
||||||
workspaces_names = {
|
workspaces_names = {
|
||||||
str(i + 1): f"{i+1} {c}" for i, c in enumerate(workspaces_suffixes)
|
str(i + 1): f"{i + 1} {c}" for i, c in enumerate(workspaces_suffixes)
|
||||||
}
|
}
|
||||||
|
|
||||||
color = rich.color.Color.parse
|
color = rich.color.Color.parse
|
||||||
|
|
|
@ -4,6 +4,7 @@ import datetime
|
||||||
import enum
|
import enum
|
||||||
import logging
|
import logging
|
||||||
import signal
|
import signal
|
||||||
|
import sys
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
@ -62,6 +63,10 @@ def clip(text: str, length: int = 30) -> str:
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def color_0x(color: rich.color.ColorTriplet) -> str:
|
||||||
|
return f"0x{color.red:02X}{color.green:02X}{color.blue:02X}"
|
||||||
|
|
||||||
|
|
||||||
class ComposableText(typing.Generic[P, C]):
|
class ComposableText(typing.Generic[P, C]):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -73,6 +78,7 @@ class ComposableText(typing.Generic[P, C]):
|
||||||
self.sortKey = sort_key
|
self.sortKey = sort_key
|
||||||
if parent:
|
if parent:
|
||||||
self.set_parent(parent)
|
self.set_parent(parent)
|
||||||
|
self.screen = self.get_first_parent_of_type(Screen)
|
||||||
self.bar = self.get_first_parent_of_type(Bar)
|
self.bar = self.get_first_parent_of_type(Bar)
|
||||||
|
|
||||||
def set_parent(self, parent: P) -> None:
|
def set_parent(self, parent: P) -> None:
|
||||||
|
@ -92,12 +98,14 @@ class ComposableText(typing.Generic[P, C]):
|
||||||
def get_first_parent_of_type(self, typ: type[T]) -> T:
|
def get_first_parent_of_type(self, typ: type[T]) -> T:
|
||||||
parent = self
|
parent = self
|
||||||
while not isinstance(parent, typ):
|
while not isinstance(parent, typ):
|
||||||
assert parent.parent, f"{self} doesn't have a parent of {typ}"
|
if not parent.parent:
|
||||||
|
msg = f"{self} doesn't have a parent of {typ}"
|
||||||
|
raise RuntimeError(msg)
|
||||||
parent = parent.parent
|
parent = parent.parent
|
||||||
return parent
|
return parent
|
||||||
|
|
||||||
def update_markup(self) -> None:
|
def update_markup(self) -> None:
|
||||||
self.bar.refresh.set()
|
self.parent.update_markup()
|
||||||
# TODO OPTI See if worth caching the output
|
# TODO OPTI See if worth caching the output
|
||||||
|
|
||||||
def generate_markup(self) -> str:
|
def generate_markup(self) -> str:
|
||||||
|
@ -191,23 +199,24 @@ class Section(ComposableText):
|
||||||
else:
|
else:
|
||||||
self.animationTask = self.bar.taskGroup.create_task(self.animate())
|
self.animationTask = self.bar.taskGroup.create_task(self.animate())
|
||||||
|
|
||||||
def set_action(
|
def set_action(self, button: Button, callback: typing.Callable | None) -> None:
|
||||||
self, button: Button, callback: typing.Callable | None
|
|
||||||
) -> None:
|
|
||||||
if button in self.actions:
|
if button in self.actions:
|
||||||
command = self.actions[button]
|
command = self.actions[button]
|
||||||
self.bar.remove_action(command)
|
self.bar.remove_action(command)
|
||||||
del self.actions[button]
|
del self.actions[button]
|
||||||
if callback:
|
if callback:
|
||||||
command = self.bar.add_action(callback)
|
command = self.screen.add_action(callback)
|
||||||
self.actions[button] = command
|
self.actions[button] = command
|
||||||
|
|
||||||
def generate_markup(self) -> str:
|
def generate_markup(self) -> str:
|
||||||
assert not self.is_hidden()
|
assert not self.is_hidden()
|
||||||
pad = max(0, self.size - len(self.text))
|
pad = max(0, self.size - len(self.text))
|
||||||
text = self.text[: self.size] + " " * pad
|
text = self.text[: self.size] + " " * pad
|
||||||
|
if text:
|
||||||
for button, command in self.actions.items():
|
for button, command in self.actions.items():
|
||||||
text = "%{A" + button.value + ":" + command + ":}" + text + "%{A}"
|
# TODO zelbar doesn't support other button types
|
||||||
|
if button == Button.CLICK_LEFT:
|
||||||
|
text = "%{A:" + command + "}" + text
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
@ -239,8 +248,8 @@ class Module(ComposableText):
|
||||||
|
|
||||||
class Alignment(enum.Enum):
|
class Alignment(enum.Enum):
|
||||||
LEFT = "l"
|
LEFT = "l"
|
||||||
RIGHT = "r"
|
|
||||||
CENTER = "c"
|
CENTER = "c"
|
||||||
|
RIGHT = "r"
|
||||||
|
|
||||||
|
|
||||||
class Side(ComposableText):
|
class Side(ComposableText):
|
||||||
|
@ -255,38 +264,64 @@ class Side(ComposableText):
|
||||||
def generate_markup(self) -> str:
|
def generate_markup(self) -> str:
|
||||||
if not self.children:
|
if not self.children:
|
||||||
return ""
|
return ""
|
||||||
text = "%{" + self.alignment.value + "}"
|
markup = ""
|
||||||
last_section: Section | None = None
|
last_section: Section | None = None
|
||||||
|
|
||||||
|
default = self.bar.theme.background_color
|
||||||
|
current = default # Fallback value
|
||||||
|
|
||||||
|
def text(
|
||||||
|
text: str,
|
||||||
|
bg: rich.color.ColorTriplet = default,
|
||||||
|
fg: rich.color.ColorTriplet = default,
|
||||||
|
) -> None:
|
||||||
|
if not text:
|
||||||
|
return ""
|
||||||
|
return (
|
||||||
|
"%{F:"
|
||||||
|
+ color_0x(fg)
|
||||||
|
+ "}%{B:"
|
||||||
|
+ color_0x(bg)
|
||||||
|
+ "}%{"
|
||||||
|
+ self.alignment.value
|
||||||
|
+ "}"
|
||||||
|
+ text
|
||||||
|
)
|
||||||
|
|
||||||
for module in self.children:
|
for module in self.children:
|
||||||
for section in module.get_sections():
|
for section in module.get_sections():
|
||||||
if section.is_hidden():
|
if section.is_hidden():
|
||||||
continue
|
continue
|
||||||
hexa = section.color.get_truecolor(theme=self.bar.theme).hex
|
current = section.color.get_truecolor(theme=self.bar.theme)
|
||||||
if last_section is None:
|
if last_section is None:
|
||||||
text += (
|
markup += (
|
||||||
"%{B" + hexa + "}%{F-}"
|
text("", default, current)
|
||||||
if self.alignment == Alignment.LEFT
|
if self.alignment != Alignment.LEFT
|
||||||
else "%{B-}%{F" + hexa + "}%{R}%{F-}"
|
else ""
|
||||||
)
|
)
|
||||||
elif isinstance(last_section, SpacerSection):
|
elif isinstance(last_section, SpacerSection):
|
||||||
text += "%{B-}%{F" + hexa + "}%{R}%{F-}"
|
markup += text("", default, current)
|
||||||
else:
|
|
||||||
if self.alignment == Alignment.RIGHT:
|
|
||||||
text += (
|
|
||||||
""
|
|
||||||
if last_section.color == section.color
|
|
||||||
else "%{F" + hexa + "}%{R}"
|
|
||||||
)
|
|
||||||
elif last_section.color == section.color:
|
elif last_section.color == section.color:
|
||||||
text += ""
|
markup += text(
|
||||||
|
"" if self.alignment == Alignment.RIGHT else "",
|
||||||
|
current,
|
||||||
|
default,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
text += "%{R}%{B" + hexa + "}"
|
lastone = last_section.color.get_truecolor(theme=self.bar.theme)
|
||||||
text += "%{F-}"
|
markup += (
|
||||||
text += section.get_markup()
|
text("", lastone, current)
|
||||||
|
if self.alignment == Alignment.RIGHT
|
||||||
|
else text("", current, lastone)
|
||||||
|
)
|
||||||
|
markup += text(section.get_markup(), current, default)
|
||||||
last_section = section
|
last_section = section
|
||||||
if self.alignment != Alignment.RIGHT and last_section:
|
markup += (
|
||||||
text += "%{R}%{B-}"
|
text("", default, current)
|
||||||
return text
|
if self.alignment != Alignment.RIGHT and last_section
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
return markup
|
||||||
|
|
||||||
|
|
||||||
class Screen(ComposableText):
|
class Screen(ComposableText):
|
||||||
|
@ -296,15 +331,79 @@ class Screen(ComposableText):
|
||||||
self.children: typing.MutableSequence[Side]
|
self.children: typing.MutableSequence[Side]
|
||||||
|
|
||||||
self.output = output
|
self.output = output
|
||||||
|
self.refresh = asyncio.Event()
|
||||||
|
|
||||||
|
self.actionIndex = 0
|
||||||
|
self.actions: dict[str, typing.Callable] = {}
|
||||||
|
|
||||||
for alignment in Alignment:
|
for alignment in Alignment:
|
||||||
Side(parent=self, alignment=alignment)
|
Side(parent=self, alignment=alignment)
|
||||||
|
|
||||||
|
def update_markup(self) -> str:
|
||||||
|
self.screen.refresh.set()
|
||||||
|
|
||||||
def generate_markup(self) -> str:
|
def generate_markup(self) -> str:
|
||||||
return ("%{Sn" + self.output + "}") + "".join(
|
return "".join(side.get_markup() for side in self.children) + "\n"
|
||||||
side.get_markup() for side in self.children
|
|
||||||
|
async def run(self) -> None:
|
||||||
|
cmd = [
|
||||||
|
"zelbar",
|
||||||
|
"-btm",
|
||||||
|
"-g",
|
||||||
|
"0:20",
|
||||||
|
"-fn",
|
||||||
|
"DejaVuSansM Nerd Font:size=13",
|
||||||
|
"-F",
|
||||||
|
color_0x(self.bar.theme.foreground_color),
|
||||||
|
"-B",
|
||||||
|
color_0x(self.bar.theme.background_color),
|
||||||
|
"-o",
|
||||||
|
self.output,
|
||||||
|
]
|
||||||
|
print(" ".join(cmd))
|
||||||
|
proc = await asyncio.create_subprocess_exec(
|
||||||
|
*cmd,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stdin=asyncio.subprocess.PIPE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def refresher() -> None:
|
||||||
|
assert proc.stdin
|
||||||
|
while True:
|
||||||
|
await self.refresh.wait()
|
||||||
|
self.refresh.clear()
|
||||||
|
markup = self.get_markup()
|
||||||
|
# sys.stdout.write(markup) # DEBUG
|
||||||
|
proc.stdin.write(markup.encode())
|
||||||
|
|
||||||
|
async def action_handler() -> None:
|
||||||
|
assert proc.stdout
|
||||||
|
while True:
|
||||||
|
line = await proc.stdout.readline()
|
||||||
|
try:
|
||||||
|
command = line.decode().strip()
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
# FIXME zelbar seems to have some memory issues
|
||||||
|
log.exception("Not unicode: %s", str(line))
|
||||||
|
continue
|
||||||
|
callback = self.actions.get(command)
|
||||||
|
if callback is None:
|
||||||
|
log.error("Unknown command: %s", command)
|
||||||
|
continue
|
||||||
|
callback()
|
||||||
|
|
||||||
|
self.bar.add_long_running_task(refresher())
|
||||||
|
self.bar.add_long_running_task(action_handler())
|
||||||
|
|
||||||
|
def add_action(self, callback: typing.Callable) -> str:
|
||||||
|
command = f"com{self.actionIndex:x}"
|
||||||
|
self.actions[command] = callback
|
||||||
|
self.actionIndex += 1
|
||||||
|
return command
|
||||||
|
|
||||||
|
def remove_action(self, command: str) -> None:
|
||||||
|
del self.actions[command]
|
||||||
|
|
||||||
|
|
||||||
RICH_DEFAULT_THEME = rich.terminal_theme.DEFAULT_TERMINAL_THEME
|
RICH_DEFAULT_THEME = rich.terminal_theme.DEFAULT_TERMINAL_THEME
|
||||||
|
|
||||||
|
@ -322,11 +421,8 @@ class Bar(ComposableText):
|
||||||
self.longRunningTasks: list[asyncio.Task] = []
|
self.longRunningTasks: list[asyncio.Task] = []
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
|
|
||||||
self.refresh = asyncio.Event()
|
|
||||||
self.taskGroup = asyncio.TaskGroup()
|
self.taskGroup = asyncio.TaskGroup()
|
||||||
self.providers: list[Provider] = []
|
self.providers: list[Provider] = []
|
||||||
self.actionIndex = 0
|
|
||||||
self.actions: dict[str, typing.Callable] = {}
|
|
||||||
|
|
||||||
self.periodicProviderTask: typing.Coroutine | None = None
|
self.periodicProviderTask: typing.Coroutine | None = None
|
||||||
|
|
||||||
|
@ -343,45 +439,9 @@ class Bar(ComposableText):
|
||||||
self.longRunningTasks.append(task)
|
self.longRunningTasks.append(task)
|
||||||
|
|
||||||
async def run(self) -> None:
|
async def run(self) -> None:
|
||||||
cmd = [
|
|
||||||
"lemonbar",
|
|
||||||
"-b",
|
|
||||||
"-a",
|
|
||||||
"64",
|
|
||||||
"-f",
|
|
||||||
"DejaVuSansM Nerd Font:size=10",
|
|
||||||
"-F",
|
|
||||||
self.theme.foreground_color.hex,
|
|
||||||
"-B",
|
|
||||||
self.theme.background_color.hex,
|
|
||||||
]
|
|
||||||
proc = await asyncio.create_subprocess_exec(
|
|
||||||
*cmd, stdout=asyncio.subprocess.PIPE, stdin=asyncio.subprocess.PIPE
|
|
||||||
)
|
|
||||||
|
|
||||||
async def refresher() -> None:
|
|
||||||
assert proc.stdin
|
|
||||||
while True:
|
|
||||||
await self.refresh.wait()
|
|
||||||
self.refresh.clear()
|
|
||||||
markup = self.get_markup()
|
|
||||||
proc.stdin.write(markup.encode())
|
|
||||||
|
|
||||||
async def action_handler() -> None:
|
|
||||||
assert proc.stdout
|
|
||||||
while True:
|
|
||||||
line = await proc.stdout.readline()
|
|
||||||
command = line.decode().strip()
|
|
||||||
callback = self.actions.get(command)
|
|
||||||
if callback is None:
|
|
||||||
# In some conditions on start it's empty
|
|
||||||
log.error("Unknown command: %s", command)
|
|
||||||
return
|
|
||||||
callback()
|
|
||||||
|
|
||||||
async with self.taskGroup:
|
async with self.taskGroup:
|
||||||
self.add_long_running_task(refresher())
|
for screen in self.children:
|
||||||
self.add_long_running_task(action_handler())
|
await screen.run()
|
||||||
for provider in self.providers:
|
for provider in self.providers:
|
||||||
self.add_long_running_task(provider.run())
|
self.add_long_running_task(provider.run())
|
||||||
|
|
||||||
|
@ -393,9 +453,6 @@ class Bar(ComposableText):
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
loop.add_signal_handler(signal.SIGINT, finish)
|
loop.add_signal_handler(signal.SIGINT, finish)
|
||||||
|
|
||||||
def generate_markup(self) -> str:
|
|
||||||
return "".join(screen.get_markup() for screen in self.children) + "\n"
|
|
||||||
|
|
||||||
def add_provider(
|
def add_provider(
|
||||||
self,
|
self,
|
||||||
provider: "Provider",
|
provider: "Provider",
|
||||||
|
@ -405,24 +462,13 @@ class Bar(ComposableText):
|
||||||
modules = []
|
modules = []
|
||||||
for s, screen in enumerate(self.children):
|
for s, screen in enumerate(self.children):
|
||||||
if screen_num is None or s == screen_num:
|
if screen_num is None or s == screen_num:
|
||||||
side = next(
|
side = next(filter(lambda s: s.alignment == alignment, screen.children))
|
||||||
filter(lambda s: s.alignment == alignment, screen.children)
|
|
||||||
)
|
|
||||||
module = Module(parent=side)
|
module = Module(parent=side)
|
||||||
modules.append(module)
|
modules.append(module)
|
||||||
provider.modules = modules
|
provider.modules = modules
|
||||||
if modules:
|
if modules:
|
||||||
self.providers.append(provider)
|
self.providers.append(provider)
|
||||||
|
|
||||||
def add_action(self, callback: typing.Callable) -> str:
|
|
||||||
command = f"{self.actionIndex:x}"
|
|
||||||
self.actions[command] = callback
|
|
||||||
self.actionIndex += 1
|
|
||||||
return command
|
|
||||||
|
|
||||||
def remove_action(self, command: str) -> None:
|
|
||||||
del self.actions[command]
|
|
||||||
|
|
||||||
def launch(self) -> None:
|
def launch(self) -> None:
|
||||||
# Using GLib's event loop so we can run GLib's code
|
# Using GLib's event loop so we can run GLib's code
|
||||||
policy = gi.events.GLibEventLoopPolicy()
|
policy = gi.events.GLibEventLoopPolicy()
|
||||||
|
@ -430,6 +476,9 @@ class Bar(ComposableText):
|
||||||
loop = policy.get_event_loop()
|
loop = policy.get_event_loop()
|
||||||
loop.run_until_complete(self.run())
|
loop.run_until_complete(self.run())
|
||||||
|
|
||||||
|
def update_markup(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Provider:
|
class Provider:
|
||||||
section_type: type[Section] = Section
|
section_type: type[Section] = Section
|
||||||
|
@ -462,9 +511,7 @@ class SingleSectionProvider(MirrorProvider):
|
||||||
|
|
||||||
|
|
||||||
class StaticProvider(SingleSectionProvider):
|
class StaticProvider(SingleSectionProvider):
|
||||||
def __init__(
|
def __init__(self, text: str, color: rich.color.Color = RICH_DEFAULT_COLOR) -> None:
|
||||||
self, text: str, color: rich.color.Color = RICH_DEFAULT_COLOR
|
|
||||||
) -> None:
|
|
||||||
super().__init__(color=color)
|
super().__init__(color=color)
|
||||||
self.text = text
|
self.text = text
|
||||||
|
|
||||||
|
@ -524,9 +571,7 @@ class StatefulSectionProvider(Provider):
|
||||||
section_type = StatefulSection
|
section_type = StatefulSection
|
||||||
|
|
||||||
|
|
||||||
class SingleStatefulSectionProvider(
|
class SingleStatefulSectionProvider(StatefulSectionProvider, SingleSectionProvider):
|
||||||
StatefulSectionProvider, SingleSectionProvider
|
|
||||||
):
|
|
||||||
section: StatefulSection
|
section: StatefulSection
|
||||||
|
|
||||||
|
|
||||||
|
@ -545,9 +590,7 @@ class MultiSectionsProvider(Provider):
|
||||||
async def do_nothing() -> None:
|
async def do_nothing() -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def update_sections(
|
async def update_sections(self, sections: set[Sortable], module: Module) -> None:
|
||||||
self, sections: set[Sortable], module: Module
|
|
||||||
) -> None:
|
|
||||||
module_sections = self.sectionKeys[module]
|
module_sections = self.sectionKeys[module]
|
||||||
async with asyncio.TaskGroup() as tg:
|
async with asyncio.TaskGroup() as tg:
|
||||||
for sort_key in sections:
|
for sort_key in sections:
|
||||||
|
@ -556,9 +599,7 @@ class MultiSectionsProvider(Provider):
|
||||||
section = self.section_type(
|
section = self.section_type(
|
||||||
parent=module, sort_key=sort_key, color=self.color
|
parent=module, sort_key=sort_key, color=self.color
|
||||||
)
|
)
|
||||||
self.updaters[section] = await self.get_section_updater(
|
self.updaters[section] = await self.get_section_updater(section)
|
||||||
section
|
|
||||||
)
|
|
||||||
module_sections[sort_key] = section
|
module_sections[sort_key] = section
|
||||||
|
|
||||||
updater = self.updaters[section]
|
updater = self.updaters[section]
|
||||||
|
@ -608,9 +649,7 @@ class PeriodicProvider(Provider):
|
||||||
bar.add_long_running_task(bar.periodicProviderTask)
|
bar.add_long_running_task(bar.periodicProviderTask)
|
||||||
|
|
||||||
|
|
||||||
class PeriodicStatefulProvider(
|
class PeriodicStatefulProvider(SingleStatefulSectionProvider, PeriodicProvider):
|
||||||
SingleStatefulSectionProvider, PeriodicProvider
|
|
||||||
):
|
|
||||||
async def run(self) -> None:
|
async def run(self) -> None:
|
||||||
await super().run()
|
await super().run()
|
||||||
self.section.set_changed_state(self.loop)
|
self.section.set_changed_state(self.loop)
|
||||||
|
|
|
@ -6,25 +6,25 @@
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
config = lib.mkIf config.frogeye.desktop.xorg {
|
config = lib.mkIf config.frogeye.desktop.xorg {
|
||||||
xsession.windowManager.i3.config.bars = [ ];
|
wayland.windowManager.sway.config.bars = [ ];
|
||||||
programs.autorandr.hooks.postswitch = {
|
programs.autorandr.hooks.postswitch = {
|
||||||
frobar = "${pkgs.systemd}/bin/systemctl --user restart frobar";
|
frobar = "${pkgs.systemd}/bin/systemctl --user restart frobar";
|
||||||
};
|
};
|
||||||
systemd.user.services.frobar = {
|
systemd.user.services.frobar = {
|
||||||
Unit = {
|
Unit = {
|
||||||
Description = "frobar";
|
Description = "frobar";
|
||||||
After = [ "graphical-session-pre.target" ];
|
After = [ "kanshi.service" ];
|
||||||
PartOf = [ "graphical-session.target" ];
|
PartOf = [ "kanshi.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
Service = {
|
Service = {
|
||||||
# Wait for i3 to start. Can't use ExecStartPre because otherwise it blocks graphical-session.target, and there's nothing i3/systemd
|
# Wait for i3 to start. Can't use ExecStartPre because otherwise it blocks graphical-session.target, and there's nothing i3/systemd
|
||||||
# TODO Do that better
|
# TODO Do that better
|
||||||
ExecStart = ''${pkgs.bash}/bin/bash -c "while ! ${pkgs.i3}/bin/i3-msg; do ${pkgs.coreutils}/bin/sleep 1; done; ${pkgs.callPackage ./. { }}/bin/frobar"'';
|
ExecStart = ''${pkgs.bash}/bin/bash -c "while ! ${pkgs.sway}/bin/swaymsg; do ${pkgs.coreutils}/bin/sleep 1; done; ${pkgs.callPackage ./. { }}/bin/frobar"'';
|
||||||
};
|
};
|
||||||
|
|
||||||
Install = {
|
Install = {
|
||||||
WantedBy = [ "graphical-session.target" ];
|
WantedBy = [ "kanshi.service" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,68 +19,77 @@ let
|
||||||
</svg>
|
</svg>
|
||||||
'';
|
'';
|
||||||
lockPng = pkgs.runCommand "lock.png" { } "${pkgs.imagemagick}/bin/convert ${lockSvg} $out";
|
lockPng = pkgs.runCommand "lock.png" { } "${pkgs.imagemagick}/bin/convert ${lockSvg} $out";
|
||||||
mod = config.xsession.windowManager.i3.config.modifier;
|
mod = config.wayland.windowManager.sway.config.modifier;
|
||||||
xautolockState = "${config.xdg.cacheHome}/xautolock";
|
idleTime = 10; # minutes
|
||||||
|
# Like wayidle but exit when there is activity
|
||||||
|
wayresume = pkgs.wayidle.overrideAttrs (old: {
|
||||||
|
pname = "wayresume";
|
||||||
|
patches = (old.patches or [ ]) ++ [ ./wayresume.diff ];
|
||||||
|
});
|
||||||
|
powerScreen =
|
||||||
|
state: ''${config.wayland.windowManager.sway.package}/bin/swaymsg "output * power ${state}"'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
# Can't use loginctl lock-session, auto-opened session has type greeter, even without that it couldn't figure it out
|
||||||
config = lib.mkIf config.frogeye.desktop.xorg {
|
config = lib.mkIf config.frogeye.desktop.xorg {
|
||||||
home.packages = [
|
programs.swaylock = {
|
||||||
(pkgs.writeShellApplication {
|
enable = true;
|
||||||
name = "xlock";
|
settings = {
|
||||||
text = ''
|
color = (builtins.substring 1 6 lockColors.d);
|
||||||
${config.frogeye.hooks.lock}
|
image = lockPng;
|
||||||
# TODO Reevaluate whether we want this or not
|
tiling = true;
|
||||||
if ! ${pkgs.lightdm}/bin/dm-tool lock
|
ignore-empty-password = true;
|
||||||
then
|
indicator-idle-visible = false;
|
||||||
if [ -d ${config.xdg.cacheHome}/lockpatterns ]
|
show-failed-attempts = true;
|
||||||
then
|
indicator-radius = 100;
|
||||||
pattern=$(${pkgs.findutils} ${config.xdg.cacheHome}/lockpatterns | sort -R | head -1)
|
|
||||||
else
|
|
||||||
pattern=${lockPng}
|
|
||||||
fi
|
|
||||||
revert() {
|
|
||||||
${pkgs.xorg.xset}/bin/xset dpms 0 0 0
|
|
||||||
}
|
|
||||||
trap revert SIGHUP SIGINT SIGTERM
|
|
||||||
${pkgs.xorg.xset}/bin/xset dpms 5 5 5
|
|
||||||
${pkgs.i3lock}/bin/i3lock --nofork --color ${
|
|
||||||
builtins.substring 1 6 lockColors.d
|
|
||||||
} --image="$pattern" --tiling --ignore-empty-password
|
|
||||||
revert
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
})
|
|
||||||
];
|
|
||||||
xsession.windowManager.i3.config = {
|
|
||||||
keybindings = {
|
|
||||||
# Screen off commands
|
|
||||||
"${mod}+F1" = "--release exec --no-startup-id ${pkgs.xorg.xset}/bin/xset dpms force off";
|
|
||||||
# Toggle to save on buttons
|
|
||||||
# xautolock -toggle doesn't allow to read state.
|
|
||||||
# Writing into a file also allows frobar to display a lock icon
|
|
||||||
"${mod}+F5" = "exec --no-startup-id ${pkgs.writeShellScript "xautolock-toggle" ''
|
|
||||||
state="$(cat "${xautolockState}")"
|
|
||||||
if [ "$state" = "disabled" ]
|
|
||||||
then
|
|
||||||
${pkgs.xautolock}/bin/xautolock -enable
|
|
||||||
echo enabled > ${xautolockState}
|
|
||||||
else
|
|
||||||
${pkgs.xautolock}/bin/xautolock -disable
|
|
||||||
echo disabled > ${xautolockState}
|
|
||||||
fi
|
|
||||||
''}";
|
|
||||||
};
|
};
|
||||||
startup = [
|
};
|
||||||
# Stop screen after 10 minutes, 1 minutes after lock it
|
services.swayidle = {
|
||||||
|
enable = true;
|
||||||
|
timeouts = [
|
||||||
{
|
{
|
||||||
notification = false;
|
# Warn
|
||||||
command = "${pkgs.writeShellScript "xautolock-start" ''
|
timeout = (idleTime - 1) * 60;
|
||||||
echo enabled > ${xautolockState}
|
command = ''${lib.getExe pkgs.libnotify} "Screen turns off in 1 minute"'';
|
||||||
${pkgs.xautolock}/bin/xautolock -time 10 -locker '${pkgs.xorg.xset}/bin/xset dpms force standby' -killtime 1 -killer xlock
|
}
|
||||||
|
{
|
||||||
|
# Screen off
|
||||||
|
timeout = idleTime * 60;
|
||||||
|
command = powerScreen "off";
|
||||||
|
resumeCommand = powerScreen "on";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
# Lock
|
||||||
|
# Call swaylock, but also call another swayidle so screen is turned off after 10 seconds instead of minutes
|
||||||
|
timeout = (idleTime + 1) * 60;
|
||||||
|
command = "${pkgs.writeShellScript "lock" ''
|
||||||
|
${config.frogeye.hooks.lock}
|
||||||
|
${lib.getExe config.services.swayidle.package} timeout 10 ${lib.strings.escapeShellArg (powerScreen "off")} resume ${lib.strings.escapeShellArg (powerScreen "on")} &
|
||||||
|
si=$!
|
||||||
|
revert() {
|
||||||
|
kill $si
|
||||||
|
}
|
||||||
|
trap revert 0
|
||||||
|
${lib.getExe config.programs.swaylock.package}
|
||||||
''}";
|
''}";
|
||||||
}
|
}
|
||||||
# services.screen-locker.xautolock is hardcoded to use systemd for -locker (doesn't even work...)
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
stylix.targets.swaylock.enable = false;
|
||||||
|
wayland.windowManager.sway.config.keybindings = lib.mkOptionDefault {
|
||||||
|
# Turn screen off until activity
|
||||||
|
"${mod}+F1" =
|
||||||
|
''--release exec ${powerScreen "off"} && ${lib.getExe wayresume} -t0; ${powerScreen "on"}'';
|
||||||
|
# Toggle to save on buttons
|
||||||
|
# TODO Bar indicator
|
||||||
|
"${mod}+F5" = "exec --no-startup-id ${pkgs.writeShellScript "swayidle-toggle" ''
|
||||||
|
if ${pkgs.systemd}/bin/systemctl --user is-active swayidle --quiet
|
||||||
|
then
|
||||||
|
${pkgs.systemd}/bin/systemctl --user stop swayidle
|
||||||
|
else
|
||||||
|
${pkgs.systemd}/bin/systemctl --user start swayidle
|
||||||
|
fi
|
||||||
|
''}";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
14
hm/desktop/lock/wayresume.diff
Normal file
14
hm/desktop/lock/wayresume.diff
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
diff --git a/src/main.rs b/src/main.rs
|
||||||
|
index 85930bd..586ee55 100644
|
||||||
|
--- a/src/main.rs
|
||||||
|
+++ b/src/main.rs
|
||||||
|
@@ -110,7 +110,7 @@ impl SeatHandler for State {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn notification_cb(ctx: EventCtx<State, ExtIdleNotificationV1>) {
|
||||||
|
- if let ext_idle_notification_v1::Event::Idled = ctx.event {
|
||||||
|
+ if let ext_idle_notification_v1::Event::Resumed = ctx.event {
|
||||||
|
ctx.state.exit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
xsession.windowManager.i3.config.keybindings = {
|
wayland.windowManager.sway.config.keybindings = lib.mkOptionDefault {
|
||||||
"XF86AudioPrev" = "exec ${lib.getExe pkgs.playerctl} previous";
|
"XF86AudioPrev" = "exec ${lib.getExe pkgs.playerctl} previous";
|
||||||
"XF86AudioPlay" = "exec ${lib.getExe pkgs.playerctl} play-pause";
|
"XF86AudioPlay" = "exec ${lib.getExe pkgs.playerctl} play-pause";
|
||||||
"XF86AudioNext" = "exec ${lib.getExe pkgs.playerctl} next";
|
"XF86AudioNext" = "exec ${lib.getExe pkgs.playerctl} next";
|
||||||
|
|
|
@ -33,7 +33,7 @@ in
|
||||||
return_bindings = false;
|
return_bindings = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
xsession.windowManager.i3.config.window.commands = [
|
wayland.windowManager.sway.config.window.commands = [
|
||||||
# Open specific applications in floating mode
|
# Open specific applications in floating mode
|
||||||
{
|
{
|
||||||
criteria = {
|
criteria = {
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
{
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
# UPST
|
|
||||||
sct = pkgs.sct.overrideAttrs (old: {
|
|
||||||
patches = (old.patches or [ ]) ++ [
|
|
||||||
./sct_aarch64.patch
|
|
||||||
];
|
|
||||||
});
|
|
||||||
in
|
|
||||||
{
|
|
||||||
config = lib.mkIf config.frogeye.desktop.xorg {
|
|
||||||
frogeye.desktop.i3.bindmodes = {
|
|
||||||
"Temperature [R] Red [D] Dust storm [C] Campfire [O] Normal [A] All nighter [B] Blue" = {
|
|
||||||
bindings = {
|
|
||||||
"r" = "exec ${sct}/bin/sct 1000";
|
|
||||||
"d" = "exec ${sct}/bin/sct 2000";
|
|
||||||
"c" = "exec ${sct}/bin/sct 4500";
|
|
||||||
"o" = "exec ${sct}/bin/sct";
|
|
||||||
"a" = "exec ${sct}/bin/sct 8000";
|
|
||||||
"b" = "exec ${sct}/bin/sct 10000";
|
|
||||||
};
|
|
||||||
mod_enter = "y";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
home.packages = [ sct ];
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
--- a/Makefile
|
|
||||||
+++ b/Makefile
|
|
||||||
@@ -32,6 +32,7 @@ LIBDIR_i386=$(PREFIX)/lib
|
|
||||||
LIBDIR_i686=$(PREFIX)/lib
|
|
||||||
LIBDIR_amd64=$(PREFIX)/lib
|
|
||||||
LIBDIR_x86_64=$(PREFIX)/lib64
|
|
||||||
+LIBDIR_aarch64=$(PREFIX)/lib
|
|
||||||
LIBDIR?=$(LIBDIR_$(MACHINE))
|
|
||||||
MANDIR_Darwin=$(PREFIX)/share/man
|
|
||||||
MANDIR_Linux=$(PREFIX)/share/man
|
|
|
@ -6,16 +6,23 @@
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
dir = config.xdg.userDirs.extraConfig.XDG_SCREENSHOTS_DIR;
|
dir = config.xdg.userDirs.extraConfig.XDG_SCREENSHOTS_DIR;
|
||||||
scrot = "${pkgs.scrot}/bin/scrot --exec '${pkgs.coreutils}/bin/mv $f ${dir}/ && ${pkgs.optipng}/bin/optipng ${dir}/$f'";
|
gs =
|
||||||
mod = config.xsession.windowManager.i3.config.modifier;
|
mode:
|
||||||
|
pkgs.writeShellScript "grimshot-${mode}" ''
|
||||||
|
path="${dir}/$(date -Isec).png"
|
||||||
|
${lib.getExe pkgs.sway-contrib.grimshot} savecopy ${mode} "$path"
|
||||||
|
${pkgs.optipng}/bin/optipng "$path"
|
||||||
|
'';
|
||||||
|
mod = config.wayland.windowManager.sway.config.modifier;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = lib.mkIf config.frogeye.desktop.xorg {
|
config = lib.mkIf config.frogeye.desktop.xorg {
|
||||||
frogeye.folders.screenshots.path = "Screenshots";
|
frogeye.folders.screenshots.path = "Screenshots";
|
||||||
xsession.windowManager.i3.config.keybindings = {
|
home.packages = [ pkgs.sway-contrib.grimshot ];
|
||||||
"Print" = "exec ${scrot} --focused";
|
wayland.windowManager.sway.config.keybindings = lib.mkOptionDefault {
|
||||||
"${mod}+Print" = "exec ${scrot}";
|
"Print" = "exec ${gs "active"}";
|
||||||
"Ctrl+Print" = "--release exec ${scrot} --select";
|
"${mod}+Print" = "exec ${gs "screen"}";
|
||||||
|
"Ctrl+Print" = "exec ${gs "anything"}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,6 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
# FOCUS
|
|
||||||
focus = "exec ${pkgs.writeShellScript "i3-focus-window" ''
|
|
||||||
WINDOW=`${pkgs.xdotool}/bin/xdotool getwindowfocus`
|
|
||||||
eval `${pkgs.xdotool}/bin/xdotool getwindowgeometry --shell $WINDOW` # this brings in variables WIDTH and HEIGHT
|
|
||||||
TX=`${pkgs.coreutils}/bin/expr $WIDTH / 2`
|
|
||||||
TY=`${pkgs.coreutils}/bin/expr $HEIGHT / 2`
|
|
||||||
${pkgs.xdotool}/bin/xdotool mousemove -window $WINDOW $TX $TY
|
|
||||||
''}";
|
|
||||||
|
|
||||||
# CARDINALS
|
# CARDINALS
|
||||||
cardinals = [
|
cardinals = [
|
||||||
{
|
{
|
||||||
|
@ -57,15 +48,34 @@ let
|
||||||
forEachWorkspace = f: map (w: f w) workspaces;
|
forEachWorkspace = f: map (w: f w) workspaces;
|
||||||
|
|
||||||
# MISC
|
# MISC
|
||||||
mod = config.xsession.windowManager.i3.config.modifier;
|
mod = config.wayland.windowManager.sway.config.modifier;
|
||||||
rofi = "exec --no-startup-id ${config.programs.rofi.package}/bin/rofi";
|
rofi = "exec --no-startup-id ${config.programs.rofi.package}/bin/rofi";
|
||||||
modes = config.frogeye.desktop.i3.bindmodes;
|
modes = config.frogeye.desktop.i3.bindmodes;
|
||||||
x11_screens = config.frogeye.desktop.x11_screens;
|
|
||||||
|
screenCombinations = lib.trivial.pipe config.services.kanshi.settings [
|
||||||
|
# All settings
|
||||||
|
(builtins.map (
|
||||||
|
setting:
|
||||||
|
lib.trivial.pipe setting [
|
||||||
|
# Profile/setting (assumes one profile is defined at most over one setting)
|
||||||
|
(lib.attrsets.attrByPath [ "profile" "outputs" ] [ ])
|
||||||
|
# List of output objects
|
||||||
|
(builtins.filter (output: (lib.attrsets.attrByPath [ "status" ] [ "enable" ] output) != "disable"))
|
||||||
|
# List of output objects that are enabled
|
||||||
|
(builtins.filter (output: (lib.attrsets.attrByPath [ "criteria" ] [ "*" ] output) != "*"))
|
||||||
|
# Lost of outputs objects with a defined criteria
|
||||||
|
# (at this point we could sort by position like we do in frobar, but we can rely on definition order)
|
||||||
|
(builtins.map (output: output.criteria))
|
||||||
|
# List of output names
|
||||||
|
]
|
||||||
|
))
|
||||||
|
# List of list of output name
|
||||||
|
(builtins.filter (outputs: builtins.length outputs >= 2))
|
||||||
|
# List of list of output name with at least two screens
|
||||||
|
];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = lib.mkIf config.xsession.windowManager.i3.enable {
|
config = lib.mkIf config.wayland.windowManager.sway.enable {
|
||||||
stylix.targets.i3.enable = false;
|
|
||||||
services.picom.enable = true;
|
|
||||||
xdg.configFile = {
|
xdg.configFile = {
|
||||||
"rofimoji.rc" = {
|
"rofimoji.rc" = {
|
||||||
text = ''
|
text = ''
|
||||||
|
@ -75,10 +85,18 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
xsession.windowManager.i3.config = {
|
wayland = {
|
||||||
|
systemd.target = "sway-session.target";
|
||||||
|
windowManager.sway.checkConfig = false; # us_qwerty-fr is not in the testing environment
|
||||||
|
};
|
||||||
|
# https://github.com/nix-community/home-manager/issues/5311
|
||||||
|
# Setting a compiled file is not desirable as it depends on the keyboard's, uuuh, key placement
|
||||||
|
wayland.windowManager.sway.config = {
|
||||||
|
input."*".xkb_layout = "us_qwerty-fr";
|
||||||
modifier = lib.mkDefault "Mod4";
|
modifier = lib.mkDefault "Mod4";
|
||||||
fonts = {
|
fonts = {
|
||||||
names = [ config.stylix.fonts.sansSerif.name ];
|
names = [ config.stylix.fonts.sansSerif.name ];
|
||||||
|
size = lib.mkForce 8.0;
|
||||||
};
|
};
|
||||||
terminal = "alacritty";
|
terminal = "alacritty";
|
||||||
colors =
|
colors =
|
||||||
|
@ -125,8 +143,11 @@ in
|
||||||
background = base07;
|
background = base07;
|
||||||
# I set the color of the active tab as the the background color of the terminal so they merge together.
|
# I set the color of the active tab as the the background color of the terminal so they merge together.
|
||||||
};
|
};
|
||||||
focus.followMouse = false;
|
focus = {
|
||||||
keybindings =
|
followMouse = false;
|
||||||
|
mouseWarping = "container";
|
||||||
|
};
|
||||||
|
keybindings = lib.mkOptionDefault (
|
||||||
{
|
{
|
||||||
# Compatibility layer for people coming from other backgrounds
|
# Compatibility layer for people coming from other backgrounds
|
||||||
"Mod1+Tab" = "${rofi} -modi window -show window";
|
"Mod1+Tab" = "${rofi} -modi window -show window";
|
||||||
|
@ -142,59 +163,46 @@ in
|
||||||
"${mod}+Shift+d" = "${rofi} -modi drun -show drun";
|
"${mod}+Shift+d" = "${rofi} -modi drun -show drun";
|
||||||
# Start Applications
|
# Start Applications
|
||||||
"${mod}+p" = "exec ${pkgs.xfce.thunar}/bin/thunar";
|
"${mod}+p" = "exec ${pkgs.xfce.thunar}/bin/thunar";
|
||||||
# Misc
|
|
||||||
"${mod}+F10" = "exec ${pkgs.writeShellScript "show-keyboard-layout" ''
|
|
||||||
layout=`${pkgs.xorg.setxkbmap}/bin/setxkbmap -query | ${pkgs.gnugrep}/bin/grep ^layout: | ${pkgs.gawk}/bin/awk '{ print $2 }'`
|
|
||||||
${pkgs.libgnomekbd}/bin/gkbd-keyboard-display -l $layout
|
|
||||||
''}";
|
|
||||||
# workspace back and forth (with/without active container)
|
# workspace back and forth (with/without active container)
|
||||||
"${mod}+b" = "workspace back_and_forth; ${focus}";
|
"${mod}+b" = "workspace back_and_forth";
|
||||||
"${mod}+Shift+b" = "move container to workspace back_and_forth; workspace back_and_forth; ${focus}";
|
"${mod}+Shift+b" = "move container to workspace back_and_forth; workspace back_and_forth";
|
||||||
|
# Split horizontally (rebound from ${mod}+b because used above)
|
||||||
|
"${mod}+g" = "splith";
|
||||||
# Change container layout
|
# Change container layout
|
||||||
"${mod}+g" = "split h; ${focus}";
|
"${mod}+q" = "focus child";
|
||||||
"${mod}+v" = "split v; ${focus}";
|
|
||||||
"${mod}+f" = "fullscreen toggle; ${focus}";
|
|
||||||
"${mod}+s" = "layout stacking; ${focus}";
|
|
||||||
"${mod}+w" = "layout tabbed; ${focus}";
|
|
||||||
"${mod}+e" = "layout toggle split; ${focus}";
|
|
||||||
"${mod}+Shift+space" = "floating toggle; ${focus}";
|
|
||||||
# Focus container
|
|
||||||
"${mod}+space" = "focus mode_toggle; ${focus}";
|
|
||||||
"${mod}+a" = "focus parent; ${focus}";
|
|
||||||
"${mod}+q" = "focus child; ${focus}";
|
|
||||||
# i3 control
|
# i3 control
|
||||||
"${mod}+Shift+c" = "reload";
|
|
||||||
"${mod}+Shift+r" = "restart";
|
"${mod}+Shift+r" = "restart";
|
||||||
"${mod}+Shift+e" = "exit";
|
# Warp around (ex-keynav)
|
||||||
|
"Mod4+Mod1+x" = "exec ${lib.getExe pkgs.warpd} --hint";
|
||||||
|
"Mod4+Mod1+c" = "exec ${lib.getExe pkgs.warpd} --normal";
|
||||||
|
"Mod4+Mod1+g" = "exec ${lib.getExe pkgs.warpd} --grid";
|
||||||
}
|
}
|
||||||
// lib.mapAttrs' (k: v: lib.nameValuePair v.enter "mode ${v.name}") (
|
// lib.mapAttrs' (k: v: lib.nameValuePair v.enter ''mode "${v.name}"'') (
|
||||||
lib.filterAttrs (k: v: v.enter != null) modes
|
lib.filterAttrs (k: v: v.enter != null) modes
|
||||||
)
|
)
|
||||||
// lib.attrsets.mergeAttrsList (
|
// lib.attrsets.mergeAttrsList (
|
||||||
forEachCardinal (c: {
|
forEachCardinal (c: {
|
||||||
# change focus
|
|
||||||
"${mod}+${c.vi}" = "focus ${c.container}; ${focus}";
|
|
||||||
# move focused window
|
|
||||||
"${mod}+Shift+${c.vi}" = "move ${c.container}; ${focus}";
|
|
||||||
#navigate workspaces next / previous
|
#navigate workspaces next / previous
|
||||||
"${mod}+Ctrl+${c.vi}" = "workspace ${c.workspace}; ${focus}";
|
"${mod}+Ctrl+${c.vi}" = "workspace ${c.workspace}";
|
||||||
# Move to workspace next / previous with focused container
|
# Move to workspace next / previous with focused container
|
||||||
"${mod}+Ctrl+Shift+${c.vi}" = "move container to workspace ${c.workspace}; workspace ${c.workspace}; ${focus}";
|
"${mod}+Ctrl+Shift+${c.vi}" =
|
||||||
|
"move container to workspace ${c.workspace}; workspace ${c.workspace}";
|
||||||
# move workspaces to screen (arrow keys)
|
# move workspaces to screen (arrow keys)
|
||||||
"${mod}+Ctrl+Shift+${c.arrow}" = "move workspace to output ${c.output}; ${focus}";
|
"${mod}+Ctrl+Shift+${c.arrow}" = "move workspace to output ${c.output}";
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
// lib.attrsets.mergeAttrsList (
|
// lib.attrsets.mergeAttrsList (
|
||||||
forEachWorkspace (w: {
|
forEachWorkspace (w: {
|
||||||
# Switch to workspace
|
# move container to workspace, do not follow (normally bound to ${mod}+Shift+${w.key}
|
||||||
"${mod}+${w.key}" = "workspace ${w.name}; ${focus}";
|
"${mod}+Ctrl+${w.key}" = "move container to workspace number ${w.name}";
|
||||||
# move focused container to workspace
|
# move container to workspace, follow it
|
||||||
"${mod}+ctrl+${w.key}" = "move container to workspace ${w.name}; ${focus}";
|
"${mod}+Shift+${w.key}" =
|
||||||
# move to workspace with focused container
|
"move container to workspace number ${w.name}; workspace number ${w.name}";
|
||||||
"${mod}+shift+${w.key}" = "move container to workspace ${w.name}; workspace ${w.name}; ${focus}";
|
|
||||||
})
|
})
|
||||||
|
)
|
||||||
);
|
);
|
||||||
modes = lib.mapAttrs' (
|
modes = lib.mkOptionDefault (
|
||||||
|
lib.mapAttrs' (
|
||||||
k: v:
|
k: v:
|
||||||
lib.nameValuePair v.name (
|
lib.nameValuePair v.name (
|
||||||
v.bindings
|
v.bindings
|
||||||
|
@ -203,7 +211,8 @@ in
|
||||||
"Escape" = "mode default";
|
"Escape" = "mode default";
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
) modes;
|
) modes
|
||||||
|
);
|
||||||
window = {
|
window = {
|
||||||
hideEdgeBorders = "both";
|
hideEdgeBorders = "both";
|
||||||
titlebar = false; # So that single-container screens are basically almost fullscreen
|
titlebar = false; # So that single-container screens are basically almost fullscreen
|
||||||
|
@ -223,9 +232,11 @@ in
|
||||||
{ window_role = "task_dialog"; }
|
{ window_role = "task_dialog"; }
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
seat."*" = {
|
||||||
|
hide_cursor = "10";
|
||||||
|
};
|
||||||
startup = [
|
startup = [
|
||||||
{
|
{
|
||||||
notification = false;
|
|
||||||
command = "${
|
command = "${
|
||||||
pkgs.writeShellApplication {
|
pkgs.writeShellApplication {
|
||||||
name = "batteryNotify";
|
name = "batteryNotify";
|
||||||
|
@ -241,28 +252,24 @@ in
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
workspaceLayout = "tabbed";
|
workspaceLayout = "tabbed";
|
||||||
focus.mouseWarping = true; # i3 only supports warping to workspace, hence ${focus}
|
workspaceOutputAssign = lib.mkIf (builtins.length screenCombinations > 0) (
|
||||||
workspaceOutputAssign = forEachWorkspace (w: {
|
forEachWorkspace (w: {
|
||||||
output = builtins.elemAt x11_screens (lib.mod w.id (builtins.length x11_screens));
|
output = builtins.map (
|
||||||
|
combination: builtins.elemAt combination (lib.mod w.id (builtins.length combination))
|
||||||
|
) screenCombinations;
|
||||||
workspace = w.name;
|
workspace = w.name;
|
||||||
});
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
frogeye.desktop.i3.bindmodes = {
|
frogeye.desktop.i3.bindmodes = {
|
||||||
"Resize" = {
|
|
||||||
bindings = {
|
|
||||||
"h" = "resize shrink width 10 px or 10 ppt; ${focus}";
|
|
||||||
"j" = "resize grow height 10 px or 10 ppt; ${focus}";
|
|
||||||
"k" = "resize shrink height 10 px or 10 ppt; ${focus}";
|
|
||||||
"l" = "resize grow width 10 px or 10 ppt; ${focus}";
|
|
||||||
};
|
|
||||||
mod_enter = "r";
|
|
||||||
};
|
|
||||||
"[L] Vérouillage [E] Déconnexion [S] Veille [H] Hibernation [R] Redémarrage [P] Extinction" = {
|
"[L] Vérouillage [E] Déconnexion [S] Veille [H] Hibernation [R] Redémarrage [P] Extinction" = {
|
||||||
bindings = {
|
bindings = {
|
||||||
"l" = "exec --no-startup-id exec xlock, mode default";
|
"l" = "exec --no-startup-id ${pkgs.procps}/bin/pkill -USR1 swayidle, mode default";
|
||||||
"e" = "exit, mode default";
|
"e" = "exit, mode default";
|
||||||
"s" = "exec --no-startup-id exec xlock & ${pkgs.systemd}/bin/systemctl suspend --check-inhibitors=no, mode default";
|
# TODO Sometimes, exit gets stuck on terminal. Restarting greetd helps.
|
||||||
"h" = "exec --no-startup-id exec xlock & ${pkgs.systemd}/bin/systemctl hibernate, mode default";
|
"s" =
|
||||||
|
"exec --no-startup-id ${pkgs.systemd}/bin/systemctl suspend --check-inhibitors=no, mode default";
|
||||||
|
"h" = "exec --no-startup-id ${pkgs.systemd}/bin/systemctl hibernate, mode default";
|
||||||
"r" = "exec --no-startup-id ${pkgs.systemd}/bin/systemctl reboot, mode default";
|
"r" = "exec --no-startup-id ${pkgs.systemd}/bin/systemctl reboot, mode default";
|
||||||
"p" = "exec --no-startup-id ${pkgs.systemd}/bin/systemctl poweroff -i, mode default";
|
"p" = "exec --no-startup-id ${pkgs.systemd}/bin/systemctl poweroff -i, mode default";
|
||||||
};
|
};
|
|
@ -5,7 +5,7 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
mod = config.xsession.windowManager.i3.config.modifier;
|
mod = config.wayland.windowManager.sway.config.modifier;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = lib.mkIf config.frogeye.desktop.xorg {
|
config = lib.mkIf config.frogeye.desktop.xorg {
|
||||||
|
@ -149,7 +149,7 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
xsession.windowManager.i3.config.keybindings = {
|
wayland.windowManager.sway.config.keybindings = lib.mkOptionDefault {
|
||||||
"${mod}+Return" = "exec ${config.programs.alacritty.package}/bin/alacritty msg create-window -e zsh || exec ${config.programs.alacritty.package}/bin/alacritty -e zsh";
|
"${mod}+Return" = "exec ${config.programs.alacritty.package}/bin/alacritty msg create-window -e zsh || exec ${config.programs.alacritty.package}/bin/alacritty -e zsh";
|
||||||
# -e zsh is for systems where I can't configure my user's shell
|
# -e zsh is for systems where I can't configure my user's shell
|
||||||
"${mod}+Shift+Return" = "exec ${config.programs.urxvt.package}/bin/urxvt";
|
"${mod}+Shift+Return" = "exec ${config.programs.urxvt.package}/bin/urxvt";
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
mod = config.xsession.windowManager.i3.config.modifier;
|
mod = config.wayland.windowManager.sway.config.modifier;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = {
|
config = {
|
||||||
|
@ -67,7 +67,9 @@ in
|
||||||
};
|
};
|
||||||
password-store.enable = true;
|
password-store.enable = true;
|
||||||
};
|
};
|
||||||
xsession.windowManager.i3.config.keybindings."${mod}+c" = "exec --no-startup-id ${config.programs.rofi.pass.package}/bin/rofi-pass --last-used";
|
wayland.windowManager.sway.config.keybindings = lib.mkOptionDefault {
|
||||||
|
"${mod}+c" = "exec --no-startup-id ${config.programs.rofi.pass.package}/bin/rofi-pass --last-used";
|
||||||
|
};
|
||||||
# TODO Try autopass.cr
|
# TODO Try autopass.cr
|
||||||
};
|
};
|
||||||
options = {
|
options = {
|
||||||
|
|
10
options.nix
10
options.nix
|
@ -32,14 +32,8 @@ in
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
desktop = {
|
desktop = {
|
||||||
xorg = lib.mkEnableOption "Enable X11 support";
|
xorg = lib.mkEnableOption "Enable graphics support";
|
||||||
# TODO Use appropriate OS/HM option(s) instead
|
# TODO Rename
|
||||||
numlock = lib.mkEnableOption "Auto-enable numlock";
|
|
||||||
x11_screens = lib.mkOption {
|
|
||||||
default = [ "UNSET1" ];
|
|
||||||
description = "A list of xrandr screen names from left to right.";
|
|
||||||
type = lib.types.listOf lib.types.str;
|
|
||||||
};
|
|
||||||
maxVideoHeight = lib.mkOption {
|
maxVideoHeight = lib.mkOption {
|
||||||
type = lib.types.int;
|
type = lib.types.int;
|
||||||
description = "Maximum video height in pixel the machine can reasonably watch";
|
description = "Maximum video height in pixel the machine can reasonably watch";
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
{
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
config = lib.mkIf (builtins.length config.frogeye.desktop.x11_screens > 1) {
|
|
||||||
services = {
|
|
||||||
autorandr.enable = true;
|
|
||||||
xserver.displayManager.lightdm.extraConfig =
|
|
||||||
let
|
|
||||||
setupScript = "${
|
|
||||||
pkgs.writeShellApplication {
|
|
||||||
name = "greeter-setup-script";
|
|
||||||
runtimeInputs = [ pkgs.autorandr ];
|
|
||||||
text = ''
|
|
||||||
autorandr --change
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
}/bin/greeter-setup-script";
|
|
||||||
in
|
|
||||||
''
|
|
||||||
[Seat:*]
|
|
||||||
display-setup-script = ${setupScript}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -7,10 +7,23 @@
|
||||||
{
|
{
|
||||||
config = lib.mkIf config.frogeye.desktop.xorg {
|
config = lib.mkIf config.frogeye.desktop.xorg {
|
||||||
boot.kernelModules = [ "i2c-dev" ]; # Allows using ddcutil
|
boot.kernelModules = [ "i2c-dev" ]; # Allows using ddcutil
|
||||||
|
programs.sway.enable = true;
|
||||||
security.rtkit.enable = true; # Recommended for pipewire
|
security.rtkit.enable = true; # Recommended for pipewire
|
||||||
services = {
|
services = {
|
||||||
blueman.enable = true;
|
blueman.enable = true;
|
||||||
displayManager.defaultSession = "none+i3";
|
greetd = {
|
||||||
|
enable = true;
|
||||||
|
settings = rec {
|
||||||
|
# Automatically log in as myself.
|
||||||
|
# Because everything is encrypted and I'm the only user, this is fine.
|
||||||
|
initial_session = {
|
||||||
|
command = "${lib.getExe config.programs.sway.package} --unsupported-gpu";
|
||||||
|
# --unsupported-gpu is for curacao (DisplayLink)
|
||||||
|
user = "geoffrey";
|
||||||
|
};
|
||||||
|
default_session = initial_session;
|
||||||
|
};
|
||||||
|
};
|
||||||
udev.packages = with pkgs; [ ddcutil ]; # TODO Doesn't seem to help
|
udev.packages = with pkgs; [ ddcutil ]; # TODO Doesn't seem to help
|
||||||
pipewire = {
|
pipewire = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -34,40 +47,20 @@
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
# Video
|
|
||||||
xserver = {
|
|
||||||
enable = true;
|
|
||||||
windowManager.i3.enable = true;
|
|
||||||
|
|
||||||
# Keyboard layout
|
# Keyboard layout
|
||||||
xkb = {
|
xserver.xkb.extraLayouts.us_qwerty-fr = {
|
||||||
extraLayouts.qwerty-fr = {
|
|
||||||
description = "QWERTY-fr";
|
description = "QWERTY-fr";
|
||||||
languages = [ "fr" ];
|
languages = [
|
||||||
|
"fre"
|
||||||
|
"eng"
|
||||||
|
];
|
||||||
symbolsFile = "${
|
symbolsFile = "${
|
||||||
pkgs.stdenv.mkDerivation {
|
pkgs.qwerty-fr.overrideAttrs (old: {
|
||||||
name = "qwerty-fr-keypad";
|
patches = (old.patches or [ ]) ++ [ ./qwerty-fr-keypad.diff ];
|
||||||
src = pkgs.fetchFromGitHub {
|
# TODO Does this work?
|
||||||
owner = "qwerty-fr";
|
})
|
||||||
repo = "qwerty-fr";
|
}/share/X11/xkb/symbols/us_qwerty-fr";
|
||||||
rev = "3a4d13089e8ef016aa20baf6b2bf3ea53de674b8";
|
|
||||||
sha256 = "sha256-wn5n6jJVDrQWJze8xYF2nEY8a7mHI3hVO4xsT4LMo9c=";
|
|
||||||
};
|
};
|
||||||
patches = [ ./qwerty-fr-keypad.diff ];
|
|
||||||
# TODO This doesn't seem to be applied... it's the whole point of the derivation :(
|
|
||||||
installPhase = ''
|
|
||||||
runHook preInstall
|
|
||||||
mkdir -p $out/linux
|
|
||||||
cp $src/linux/us_qwerty-fr $out/linux
|
|
||||||
runHook postInstall
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
}/linux/us_qwerty-fr";
|
|
||||||
};
|
|
||||||
layout = "qwerty-fr";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
# Disco
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Enable sound & bluetooth
|
# Enable sound & bluetooth
|
||||||
|
@ -76,7 +69,4 @@
|
||||||
# So we can use gnome3 pinentry flavour
|
# So we can use gnome3 pinentry flavour
|
||||||
services.dbus.packages = [ pkgs.gcr ];
|
services.dbus.packages = [ pkgs.gcr ];
|
||||||
};
|
};
|
||||||
imports = [
|
|
||||||
./autorandr.nix
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,9 +49,6 @@
|
||||||
|
|
||||||
# Fix https://nix-community.github.io/home-manager/index.html#_why_do_i_get_an_error_message_about_literal_ca_desrt_dconf_literal_or_literal_dconf_service_literal
|
# Fix https://nix-community.github.io/home-manager/index.html#_why_do_i_get_an_error_message_about_literal_ca_desrt_dconf_literal_or_literal_dconf_service_literal
|
||||||
programs.dconf.enable = true;
|
programs.dconf.enable = true;
|
||||||
|
|
||||||
# Because everything is encrypted and I'm the only user, this is fine.
|
|
||||||
services.displayManager.autoLogin.user = "geoffrey";
|
|
||||||
};
|
};
|
||||||
imports = [
|
imports = [
|
||||||
home-manager.nixosModules.home-manager
|
home-manager.nixosModules.home-manager
|
||||||
|
|
|
@ -15,10 +15,6 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
frogeye.desktop = {
|
frogeye.desktop = {
|
||||||
x11_screens = [
|
|
||||||
"DP-1"
|
|
||||||
"eDP-1"
|
|
||||||
];
|
|
||||||
maxVideoHeight = 1080;
|
maxVideoHeight = 1080;
|
||||||
phasesCommands = {
|
phasesCommands = {
|
||||||
jour = ''
|
jour = ''
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue