initial commit

This commit is contained in:
GammaKinematics 2026-03-30 13:10:42 +07:00
commit 90cff4f16a
59 changed files with 6855 additions and 0 deletions

92
Suckless/dwm/api.nix Normal file
View file

@ -0,0 +1,92 @@
# dwm fifo API - control dwm via named pipe
# Usage: echo "command" > /tmp/dwm.fifo
{ lib }:
{
config = ''
/* dwmfifo - control dwm via named pipe */
static const char *dwmfifo = "/tmp/dwm.fifo";
static Command commands[] = {
/*
* TAG NAVIGATION - Semantic names matching workflow
* */
{ "view", view, .parse = parsetag }, /* Generic: view 5 */
{ "view-all", view, {.ui = ~0} }, /* All tags */
{ "view-prev", viewprev, {0} }, /* Previous tag */
{ "view-next", viewnext, {0} }, /* Next tag */
/* Semantic tag shortcuts (matching tags.nix) */
{ "terminal", view, {.ui = 1 << 9} }, /* Tag 10: */
{ "files", view, {.ui = 1 << 10} }, /* Tag 11: */
{ "video", view, {.ui = 1 << 11} }, /* Tag 12: */
{ "browser", view, {.ui = 1 << 12} }, /* Tag 13: 󰖟 */
{ "code", view, {.ui = 1 << 13} }, /* Tag 14: */
{ "freecad", view, {.ui = 1 << 14} }, /* Tag 15: 󰻬 */
{ "kicad-pm", view, {.ui = 1 << 15} }, /* Tag 16: (project manager) */
{ "kicad", view, {.ui = 1 << 16} }, /* Tag 17: (sch/pcb) */
{ "kicad-aux", view, {.ui = 1 << 17} }, /* Tag 18: (pcb mobile) */
/*
* MONITOR CONTROL - Primary (left) / Secondary (right)
* */
{ "mon-prim", focusnthmon, {.i = 1} }, /* Focus primary monitor */
{ "mon-sec", focusnthmon, {.i = 0} }, /* Focus secondary monitor */
{ "mon-send-prim", tagnthmon, {.i = 1} }, /* Send window to primary */
{ "mon-send-sec", tagnthmon, {.i = 0} }, /* Send window to secondary */
{ "mon-swap", swapmon, {0} }, /* Swap monitor contents */
/*
* WINDOW MANAGEMENT
* */
{ "focus-next", focusstack, {.i = +1} }, /* Next window in stack */
{ "focus-prev", focusstack, {.i = -1} }, /* Previous window */
{ "focus", focusstack, .parse = parseplusminus },/* Generic: focus +2 */
{ "kill", killclient, {0} }, /* Close window */
{ "zoom", zoom, {0} }, /* Promote to master */
{ "float", togglefloating, {0} }, /* Toggle floating */
/*
* LAYOUT
* */
{ "layout-tile", setlayout, {.v = &layouts[0]} },
{ "layout-float", setlayout, {.v = &layouts[1]} },
{ "layout-mono", setlayout, {.v = &layouts[2]} },
{ "layout-toggle", setlayout, {0} }, /* Cycle layouts */
/*
* MASTER AREA
* */
{ "master-inc", incnmaster, {.i = +1} },
{ "master-dec", incnmaster, {.i = -1} },
{ "mfact", setmfact, .parse = parseplusminus },/* mfact +0.05 */
/*
* TAG MANAGEMENT
* */
{ "toggleview", toggleview, .parse = parsetag },
{ "tag", tag, .parse = parsetag },
{ "toggletag", toggletag, .parse = parsetag },
{ "tagmon", tagmon, .parse = parseplusminus },
/*
* ADVANCED (window targeting)
* */
{ "viewwin", viewwin, .parse = parsexid }, /* Focus by X window ID */
{ "viewname", viewname, .parse = parsestr }, /* Focus by name */
/*
* SPAWNS
* */
{ "spawn-term", spawn, {.v = termcmd} },
{ "spawn-browser", spawn, {.v = browsercmd} },
{ "spawn-rofi", spawn, {.v = roficmd} },
{ "spawn-files", spawn, {.v = filescmd} },
{ "spawn-editor", spawn, {.v = editorcmd} },
/*
* SESSION
* */
{ "quit", quit, {0} },
};
'';
}

View file

@ -0,0 +1,39 @@
# dwm appearance settings (colors, fonts, borders, gaps)
# Integrates with Stylix for consistent theming
{ config, lib }:
let
colors = config.lib.stylix.colors;
fonts = config.stylix.fonts;
in
{
config = ''
/* See LICENSE file for copyright and license details. */
/* appearance */
static const unsigned int borderpx = 2; /* border pixel of windows */
static const unsigned int gappx = 5; /* gaps between windows */
static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 0; /* 0 means no bar (holdbar shows on key hold) */
static const int topbar = 1; /* 0 means bottom bar */
/* Display modes of the tab bar: never shown, always shown, shown only in */
/* monocle mode in the presence of several windows. */
/* Modes after showtab_nmodes are disabled. */
enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always};
static const int showtab = showtab_auto; /* Default tab bar show mode */
static const int toptab = False; /* False means bottom tab bar */
static const char *fonts[] = { "${fonts.monospace.name}:size=${toString fonts.sizes.terminal}" };
static const char dmenufont[] = "${fonts.monospace.name}:size=${toString fonts.sizes.terminal}";
static const char col_gray1[] = "#${colors.base00}";
static const char col_gray2[] = "#${colors.base01}";
static const char col_gray3[] = "#${colors.base04}";
static const char col_gray4[] = "#${colors.base05}";
static const char col_cyan[] = "#${colors.base0D}";
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
};
'';
}

File diff suppressed because it is too large Load diff

100
Suckless/dwm/dwm.nix Normal file
View file

@ -0,0 +1,100 @@
# dwm window manager configuration
#
# =============================================================================
# Patch Development Notes
# =============================================================================
#
# Base: dwm 6.6 (matches nixpkgs)
# Clone: ~/NixOS/dwm
#
# Clean & Build Commands:
# cd ~/NixOS/dwm
# git reset --hard 6.6
# rm -f config.h drw.o dwm dwm.o util.o
# nix-shell -p xorg.libX11 xorg.libXft xorg.libXinerama xorg.libXcursor pkg-config gnumake gcc
# make clean && make
#
# Generate patch after all patches applied:
# git diff 6.6 > ~/NixOS/Suckless/dwm/dwm-lebowski.patch
#
# =============================================================================
# Patches (apply in order):
# =============================================================================
#
# 1. pertag - Per-tag layouts (applied separately, then tab)
# 2. tab - Tabbed monocle bar
# 3. fullgaps - Simple gaps between windows
# 4. holdbar-modkey - Show bar while holding mod key
# 5. hide_vacant_tags - Only show occupied tags
# 6. bardwmlogo - DWM logo in bar
# 7. cursorwarp - Cursor follows focus
# 8. alwayscenter - Float windows spawn centered
# 9. swapmonitors - Swap tagsets between monitors
# 10. adjacenttag - Navigate tags with arrows (skipvacant)
# 11. accessnthmonitor - Focus/send to specific monitor by number
# 12. dwmfifo - Control dwm via named pipe
# 13. xcursor - Use system Xcursor theme (Stylix)
# 14. actualfullscreen
#
# Custom additions:
# - def_layouts array for per-tag default layouts
#
# =============================================================================
{
config,
pkgs,
lib,
...
}:
let
appearance = import ./appearance.nix { inherit config lib; };
tags = import ./tags.nix { inherit lib; };
rules = import ./rules.nix { inherit lib; };
layouts = import ./layouts.nix { inherit lib; };
keybindings = import ./keybindings.nix { inherit lib; };
api = import ./api.nix { inherit lib; };
configDefH = ''
${appearance.config}
${tags.config}
${rules.config}
${layouts.config}
${keybindings.config}
${api.config}
'';
in
{
services.xserver.windowManager.dwm = {
enable = true;
package =
(pkgs.dwm.override {
conf = configDefH;
}).overrideAttrs
(old: {
patches = [ ./dwm-lebowski.patch ];
buildInputs = old.buildInputs ++ [ pkgs.xorg.libXcursor ];
});
};
environment.systemPackages = [
(pkgs.writeShellScriptBin "vieworspawn" ''
mon=$1; tag=$2; class=$3; shift 3
# Focus monitor if multi-monitor setup (0=secondary, 1=primary)
if [[ $(${pkgs.autorandr}/bin/autorandr --detected) != "mobile" ]]; then
[[ "$mon" == "0" ]] && echo "mon-sec" > /tmp/dwm.fifo || echo "mon-prim" > /tmp/dwm.fifo
fi
echo "view $tag" > /tmp/dwm.fifo
sleep 0.02
if ! ${pkgs.xdotool}/bin/xdotool search --class "$class" >/dev/null 2>&1; then
exec "$@"
fi
'')
];
}

View file

@ -0,0 +1,181 @@
# dwm keybindings
{ lib }:
{
config = ''
/* key definitions */
#define MODKEY Mod4Mask
#define TAGKEYS(KEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
#define HOLDKEY 0xffeb // 0 - disable; 0xffe9 - Mod1Mask; 0xffeb - Mod4Mask (Super)
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *roficmd[] = { "rofi", "-show", "system", NULL };
static const char *rofiwebcmd[] = { "rofi-websearch", NULL };
static const char *browsercmd[] = { "zen-twilight", NULL };
static const char *lockcmd[] = { "slock", NULL };
static const char *kicadshowcmd[] = { "kicad-show", NULL };
static const char *kicadprojectscmd[] = { "kicad-projects", NULL };
static const char *kicadlibcmd[] = { "kicad-lib-launch", NULL };
static const char *kicadswapcmd[] = { "kicad-swap", NULL };
static const char *kicadcyclefcmd[] = { "kicad-cycle", "f", NULL };
static const char *kicadcyclebcmd[] = { "kicad-cycle", "b", NULL };
static const char *screenshotcmd[] = { "flameshot", "gui", NULL };
static const char *screenshotfullcmd[] = { "flameshot", "full", "--path", "/home/lebowski/Pictures/Screenshots", NULL };
static const char *cliphistcmd[] = { "sh", "-c", "greenclip print | rofi -dmenu -p Clipboard | xclip -selection clipboard", NULL };
static const char *volmutecmd[] = { "wpctl", "set-mute", "@DEFAULT_AUDIO_SINK@", "toggle", NULL };
static const char *micmutecmd[] = { "wpctl", "set-mute", "@DEFAULT_AUDIO_SOURCE@", "toggle", NULL };
static const char *volupcmd[] = { "sh", "-c", "wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+", NULL };
static const char *voldowncmd[] = { "wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "5%-", NULL };
/* vieworspawn: monitor, tag (1-based), class, cmd... */
static const char *termvos[] = { "vieworspawn", "0", "10", "st-256color", "st", NULL };
static const char *filesvos[] = { "vieworspawn", "0", "11", "Thunar", "thunar", NULL };
static const char *editorvos[] = { "vieworspawn", "1", "14", "dev.zed.Zed", "zeditor", NULL };
static const char *freecadvos[] = { "vieworspawn", "1", "15", "FreeCAD", "FreeCAD", "--single-instance", NULL };
static const char *bambuvos[] = { "vieworspawn", "1", "19", "BambuStudio", "bambu-studio", NULL };
/* fallback spawn commands */
static const char *termcmd[] = { "st", NULL };
static const char *filescmd[] = { "thunar", NULL };
static const char *editorcmd[] = { "zeditor", NULL };
static const char *freecadcmd[] = { "FreeCAD", "--single-instance", NULL };
static const char *bambucmd[] = { "bambu-studio", NULL };
static const Key keys[] = {
/* modifier key function argument */
/* Rofi */
{ MODKEY, XK_space, spawn, {.v = roficmd } },
{ MODKEY|Mod1Mask, XK_space, spawn, {.v = rofiwebcmd } },
/* Terminal */
{ MODKEY, XK_a, spawn, {.v = termvos } },
{ MODKEY|ShiftMask, XK_a, spawn, {.v = termcmd } },
/* Zed (code) */
{ MODKEY, XK_z, spawn, {.v = editorvos } },
{ MODKEY|ShiftMask, XK_z, spawn, {.v = editorcmd } },
/* Zen Browser (web) */
{ MODKEY, XK_x, view, {.ui = 1 << 12 } },
{ MODKEY|ShiftMask, XK_x, spawn, {.v = browsercmd } },
/* Thunar (files) */
{ MODKEY, XK_n, spawn, {.v = filesvos } },
{ MODKEY|ShiftMask, XK_n, spawn, {.v = filescmd } },
/* Video */
{ MODKEY, XK_m, view, {.ui = 1 << 11 } },
/* Lock */
{ MODKEY, XK_Escape, spawn, {.v = lockcmd } },
/* KiCad */
{ MODKEY, XK_k, spawn, {.v = kicadshowcmd } },
{ MODKEY|ShiftMask, XK_k, spawn, {.v = kicadprojectscmd } },
{ MODKEY, XK_l, spawn, {.v = kicadlibcmd } },
{ MODKEY|ControlMask, XK_k, view, {.ui = 1 << 15 } },
{ MODKEY|Mod1Mask, XK_k, spawn, {.v = kicadswapcmd } },
{ MODKEY, XK_bracketright, spawn, {.v = kicadcyclefcmd } },
{ MODKEY, XK_bracketleft, spawn, {.v = kicadcyclebcmd } },
/* FreeCAD */
{ MODKEY, XK_f, spawn, {.v = freecadvos } },
{ MODKEY|ShiftMask, XK_f, spawn, {.v = freecadcmd } },
/* Bambu Studio */
{ MODKEY, XK_p, spawn, {.v = bambuvos } },
{ MODKEY|ShiftMask, XK_p, spawn, {.v = bambucmd } },
/* Window management */
{ MODKEY, XK_q, killclient, {0} },
{ MODKEY, XK_e, togglefloating, {0} },
{ MODKEY, XK_w, togglefullscr, {0} },
{ MODKEY, XK_t, tabmode, {-1} },
/* Focus movement - stack */
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY|ShiftMask, XK_j, focusstack, {.i = -1 } },
/* Adjacent tags - Up/Down */
{ MODKEY, XK_Up, viewprev, {0} },
{ MODKEY, XK_Down, viewnext, {0} },
{ MODKEY|ShiftMask, XK_Up, tagtoprev, {0} },
{ MODKEY|ShiftMask, XK_Down, tagtonext, {0} },
/* Move to monitor */
{ MODKEY, XK_Left, focusnthmon, {.i = 1 } },
{ MODKEY, XK_Right, focusnthmon, {.i = 0 } },
{ MODKEY|ShiftMask, XK_Left, tagnthmon, {.i = 1 } },
{ MODKEY|ShiftMask, XK_Right, tagnthmon, {.i = 0 } },
/* Swap monitors */
{ MODKEY|ShiftMask, XK_apostrophe, swapmon, {0} },
/* Resize master */
{ MODKEY|Mod1Mask, XK_Left, setmfact, {.f = -0.05} },
{ MODKEY|Mod1Mask, XK_Right, setmfact, {.f = +0.05} },
/* Tags */
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
TAGKEYS( XK_4, 3)
TAGKEYS( XK_5, 4)
TAGKEYS( XK_6, 5)
TAGKEYS( XK_7, 6)
TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8)
{ MODKEY, XK_0, view, {.ui = ~0 } },
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
/* Clipboard */
{ MODKEY|ShiftMask, XK_v, spawn, {.v = cliphistcmd } },
/* Screenshots */
{ 0, XK_Print, spawn, {.v = screenshotcmd } },
{ ShiftMask, XK_Print, spawn, {.v = screenshotfullcmd } },
/* Media keys */
{ 0, XF86XK_AudioMute, spawn, {.v = volmutecmd } },
{ 0, XF86XK_AudioMicMute, spawn, {.v = micmutecmd } },
{ 0, XF86XK_AudioRaiseVolume, spawn, {.v = volupcmd } },
{ 0, XF86XK_AudioLowerVolume, spawn, {.v = voldowncmd } },
/* Holdbar */
{ 0, HOLDKEY, holdbar, {0} },
};
/* button definitions */
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static const Button buttons[] = {
/* click event mask button function argument */
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
{ ClkTagBar, 0, Button1, view, {0} },
{ ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
{ ClkTabBar, 0, Button1, focuswin, {0} },
/* Scroll through tags with Mod+scroll */
{ ClkRootWin, MODKEY, Button4, viewprev, {0} },
{ ClkRootWin, MODKEY, Button5, viewnext, {0} },
{ ClkClientWin, MODKEY, Button4, viewprev, {0} },
{ ClkClientWin, MODKEY, Button5, viewnext, {0} },
};
'';
}

49
Suckless/dwm/layouts.nix Normal file
View file

@ -0,0 +1,49 @@
# dwm layouts
{ lib }:
let
# Layout indices: 0 = tile, 1 = floating, 2 = monocle
defLayouts = [
0 # index 0: all-tags view
0 # tag 1
0 # tag 2
0 # tag 3
0 # tag 4
0 # tag 5
0 # tag 6
0 # tag 7
0 # tag 8
0 # tag 9
2 # tag 10: terminal
2 # tag 11: files
2 # tag 12: video
2 # tag 13: web/browser
2 # tag 14: code
2 # tag 15: freecad
2 # tag 16: kicad project manager
2 # tag 17: kicad (sch/pcb editors)
2 # tag 18: kicad-aux (pcb/footprint mobile)
2 # tag 19: bambu studio
];
defLayoutsStr = lib.concatMapStringsSep ", " toString defLayouts;
in
{
config = ''
/* layout(s) */
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */
static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
static const Layout layouts[] = {
/* symbol arrange function */
{ "[]=", tile }, /* 0: first entry is default */
{ "><>", NULL }, /* 1: floating */
{ "[M]", monocle }, /* 2: monocle (tabbed) */
};
/* default layout per tag */
/* 0 = tile, 1 = floating, 2 = monocle */
static int def_layouts[1 + LENGTH(tags)] = { ${defLayoutsStr} };
'';
}

41
Suckless/dwm/rules.nix Normal file
View file

@ -0,0 +1,41 @@
# dwm window rules
# Tag mapping: 1<<9=term, 1<<10=files, 1<<11=video, 1<<12=web, 1<<13=code,
# 1<<14=freecad, 1<<15=kicad-pm, 1<<16=kicad, 1<<17=kicad-aux
{ lib }:
{
config = ''
static const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
/* class instance title tags mask isfloating monitor */
{ "Polkit-gnome-authentication-agent-1", NULL, NULL, 0, 1, -1 },
{ "KeePassXC", NULL, NULL, 0, 1, -1 },
{ NULL, NULL, "Picture-in-Picture", 0, 1, -1 },
{ "slint-viewer", NULL, NULL, 0, 1, -1 },
{ "LVGL Simulator", NULL, NULL, 0, 1, -1 },
{ NULL, NULL, "Axium Browser", 0, 1, -1 },
{ NULL, NULL, "Axium", 0, 1, -1 },
{ NULL, NULL, "Fex", 0, 1, -1 },
{ NULL, NULL, "@", 0, 1, -1 },
{ NULL, NULL, "OSM", 0, 1, -1 },
{ NULL, NULL, "YouNix", 0, 1, -1 },
{ "st-256color", NULL, NULL, 1 << 9, 0, 0 }, /* terminal */
{ "Thunar", NULL, NULL, 1 << 10, 0, 0 }, /* files */
{ "haruna", NULL, NULL, 1 << 11, 0, 1 }, /* video */
{ "zen-twilight", NULL, "Zen Twilight", 1 << 12, 0, 1 }, /* web */
{ "dev.zed.Zed", NULL, NULL, 1 << 13, 0, 1 }, /* code */
{ "FreeCAD", NULL, "Expression editor", 0, 1, -1 }, /* freecad formula popup */
{ "FreeCAD", NULL, "Insert length", 0, 1, -1 }, /* freecad dimension popup */
{ "FreeCAD", NULL, NULL, 1 << 14, 0, 1 }, /* freecad */
{ "KiCad", NULL, "KiCad 9", 1 << 15, 0, 0 }, /* kicad-pm: tag 16 */
{ "KiCad", NULL, "Schematic Editor", 1 << 16, 0, 0 }, /* kicad: tag 17, mon 0 */
{ "KiCad", NULL, "Symbol Editor", 1 << 16, 0, 0 }, /* kicad: tag 17, mon 0 */
{ "KiCad", NULL, "PCB Editor", 1 << 16, 0, 1 }, /* kicad: tag 17, mon 1 */
{ "KiCad", NULL, "Footprint Editor", 1 << 16, 0, 1 }, /* kicad: tag 17, mon 1 */
{ "BambuStudio", NULL, NULL, 1 << 18, 0, 1 }, /* bambu studio */
};
'';
}

33
Suckless/dwm/tags.nix Normal file
View file

@ -0,0 +1,33 @@
# dwm tag names (Nerd Font icons for special workspaces)
{ lib }:
let
tags = [
"1"
"2"
"3"
"4"
"5"
"6"
"7"
"8"
"9"
"" # 10: terminal
"" # 11: files
"" # 12: video
"󰖟" # 13: web/browser
"" # 14: code
"󰻬" # 15: freecad
"" # 16: kicad project manager
"" # 17: kicad (sch/pcb editors)
"" # 18: kicad-aux (pcb/footprint mobile)
"󰹜" # 19: bambu studio
];
tagsStr = lib.concatMapStringsSep ", " (t: ''"${t}"'') tags;
in
{
config = ''
/* tagging */
static const char *tags[] = { ${tagsStr} };
'';
}

144
Suckless/home.nix Normal file
View file

@ -0,0 +1,144 @@
# Suckless home-manager configuration
# X11-specific settings that integrate with home-manager
{ pkgs-stable, ... }:
{
# Monitor management
programs.autorandr = {
enable = true;
package = pkgs-stable.autorandr;
hooks.postswitch = {
"set-xft-dpi" = "echo 'Xft.dpi: 96' | xrdb -merge";
"set-wallpaper" = ''
case "$AUTORANDR_CURRENT_PROFILE" in
docked)
xwallpaper --output eDP-1 --zoom ~/NixOS/Wallpapers/pearl.jpg --output DP-3 --zoom ~/NixOS/Wallpapers/siege.png
;;
mobile)
xwallpaper --output eDP-1 --zoom ~/NixOS/Wallpapers/siege.png
;;
esac
'';
};
profiles = {
"docked" = {
fingerprint = {
eDP-1 = "00ffffffffffff002c831207000000001d220104a51e1378025645935e5b9325185054000000010101010101010101010101010101010f3c80a070b0204018303c002ebd10000018000000000000000000000000000000000000000000000000000000000000000000000000000000fe004b443134304e3336333041303100df";
DP-3 = "00ffffffffffff0061a906b00100000025220103803c2278afa545ad504da6260c5054a5cb0081809500a9c0b300d1c0010101010101023a801871382d40582c450055502100001e000000ff0035333738323030303434353132000000fd0030a561ba3c000a202020202020000000fc005032374642422d52410a20202001c0020319b349010311130414051f90e200ca67030c00100038448e4480a070382d40582c450055502100001e605980a0703814403024350055502100001c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050";
};
config = {
DP-3 = {
enable = true;
primary = false;
mode = "1920x1080";
rate = "75.00";
dpi = 96;
position = "0x180";
};
eDP-1 = {
enable = true;
primary = true;
mode = "1920x1200";
rate = "60.00";
dpi = 96;
position = "1920x0";
rotate = "left";
scale = {
x = 0.75;
y = 0.75;
};
};
};
};
"mobile" = {
fingerprint = {
eDP-1 = "00ffffffffffff002c831207000000001d220104a51e1378025645935e5b9325185054000000010101010101010101010101010101010f3c80a070b0204018303c002ebd10000018000000000000000000000000000000000000000000000000000000000000000000000000000000fe004b443134304e3336333041303100df";
};
config = {
eDP-1 = {
enable = true;
primary = true;
mode = "1920x1200";
rate = "60.00";
dpi = 96;
position = "0x0";
};
};
};
};
};
services.autorandr = {
enable = true;
package = pkgs-stable.autorandr;
};
# Screenshots
services.flameshot = {
enable = true;
package = pkgs-stable.flameshot;
};
# Touchpad gestures (for mobile mode)
home.file.".config/libinput-gestures.conf".text = ''
# 3-finger up/down: tag navigation
gesture swipe up 3 sh -c 'echo "view-prev" > /tmp/dwm.fifo'
gesture swipe down 3 sh -c 'echo "view-next" > /tmp/dwm.fifo'
# 3-finger left/right: window cycling
gesture swipe left 3 sh -c 'echo "focus-prev" > /tmp/dwm.fifo'
gesture swipe right 3 sh -c 'echo "focus-next" > /tmp/dwm.fifo'
# 4-finger up/down: layout
gesture swipe up 4 sh -c 'echo "layout-mono" > /tmp/dwm.fifo'
gesture swipe down 4 sh -c 'echo "layout-tile" > /tmp/dwm.fifo'
# Pinch: rofi system menu / view all
gesture pinch in rofi -show system
gesture pinch out sh -c 'echo "view-all" > /tmp/dwm.fifo'
'';
# X11 startup script
home.file.".xinitrc".text = ''
# D-Bus environment for GTK apps (fixes slow first launch)
dbus-update-activation-environment --systemd DBUS_SESSION_BUS_ADDRESS DISPLAY XAUTHORITY
# Apply monitor profile
autorandr --change --default mobile
# Disable DPMS and screen blanking
xset s off
xset -dpms
xset s noblank
# Numlock on
numlockx
# Status bar
slstatus &
# Compositor
# picom &
# Touchpad gestures
libinput-gestures-setup start &
# Auto-rotate
auto-rotate &
# KeePassXC (minimized, ready for browser extension)
keepassxc --minimized &
# Create dwmfifo for IPC
mkfifo /tmp/dwm.fifo 2>/dev/null || true
# Start dwm
exec dwm
'';
# Auto-start X11/dwm on tty1
programs.bash.profileExtra = ''
if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = 1 ]; then
exec startx
fi
'';
}

93
Suckless/slstatus.nix Normal file
View file

@ -0,0 +1,93 @@
# slstatus - suckless status bar
{ pkgs, ... }:
let
# Dynamic icon scripts
batteryScript = pkgs.writeShellScript "slstatus-battery" ''
perc=$(cat /sys/class/power_supply/BATT/capacity 2>/dev/null || echo "0")
status=$(cat /sys/class/power_supply/BATT/status 2>/dev/null || echo "Unknown")
if [ "$status" = "Charging" ]; then icon="󰂄"
elif [ "$perc" -ge 90 ]; then icon="󰁹"
elif [ "$perc" -ge 80 ]; then icon="󰂂"
elif [ "$perc" -ge 70 ]; then icon="󰂁"
elif [ "$perc" -ge 60 ]; then icon="󰂀"
elif [ "$perc" -ge 50 ]; then icon="󰁿"
elif [ "$perc" -ge 40 ]; then icon="󰁾"
elif [ "$perc" -ge 30 ]; then icon="󰁽"
elif [ "$perc" -ge 20 ]; then icon="󰁼"
elif [ "$perc" -ge 10 ]; then icon="󰁻"
else icon="󰁺"
fi
printf "%s %s%%" "$icon" "$perc"
'';
mouseScript = pkgs.writeShellScript "slstatus-mouse" ''
perc=$(cat /sys/class/power_supply/hidpp_battery_0/capacity 2>/dev/null || echo "")
[ -z "$perc" ] && exit 0
printf "󰍽 %s%%" "$perc"
'';
volumeScript = pkgs.writeShellScript "slstatus-volume" ''
vol=$(${pkgs.wireplumber}/bin/wpctl get-volume @DEFAULT_AUDIO_SINK@ 2>/dev/null)
muted=$(echo "$vol" | grep -c MUTED)
perc=$(echo "$vol" | awk '{printf "%.0f", $2*100}')
if [ "$muted" -eq 1 ]; then icon="󰝟"
elif [ "$perc" -ge 66 ]; then icon="󰕾"
elif [ "$perc" -ge 33 ]; then icon="󰖀"
else icon="󰕿"
fi
printf "%s %s%%" "$icon" "$perc"
'';
wifiScript = pkgs.writeShellScript "slstatus-wifi" ''
essid=$(cat /sys/class/net/wlp2s0/wireless/../uevent 2>/dev/null | grep INTERFACE | cut -d= -f2)
essid=$(${pkgs.iw}/bin/iw dev wlp2s0 link 2>/dev/null | grep SSID | awk '{print $2}')
[ -z "$essid" ] && exit 0
perc=$(awk 'NR==3 {printf "%.0f", $3*100/70}' /proc/net/wireless 2>/dev/null || echo "0")
if [ "$perc" -ge 75 ]; then icon="󰤥"
elif [ "$perc" -ge 50 ]; then icon="󰤢"
elif [ "$perc" -ge 25 ]; then icon="󰤟"
else icon="󰤯"
fi
printf "%s %s %s%%" "$icon" "$essid" "$perc"
'';
config = ''
/* See LICENSE file for copyright and license details. */
/* interval between updates (in ms) */
const unsigned int interval = 1000;
/* text to show if no value can be retrieved */
static const char unknown_str[] = "";
/* maximum output string length */
#define MAXLEN 512
static const struct arg args[] = {
/* function format argument */
{ cpu_freq, " %s/", NULL },
{ cpu_perc, "%s%% | ", NULL },
{ ram_used, " %s/", NULL },
{ ram_perc, "%s%% | ", NULL },
{ temp, " %s°C | ", "/sys/class/thermal/thermal_zone0/temp" },
{ run_command, "%s | ", "${wifiScript}" },
{ run_command, "%s | ", "${volumeScript}" },
{ run_command, "%s | ", "${batteryScript}" },
{ run_command, "%s | ", "${mouseScript}" },
{ datetime, " %s ", "%d/%m %H:%M:%S" },
};
'';
in
{
environment.systemPackages = [
(pkgs.slstatus.override { conf = config; })
];
}

View file

@ -0,0 +1,46 @@
# st appearance settings
{ config, lib }:
let
colors = config.lib.stylix.colors;
fonts = config.stylix.fonts;
in
{
font = "${fonts.monospace.name}:pixelsize=${
toString (fonts.sizes.terminal + 6)
}:antialias=true:autohint=true";
alpha = "0.9";
colorsSed = ''
sed -i '/static const char \*colorname\[\]/,/^};/c\
static const char *colorname[] = {\
/* 8 normal colors */\
"#${colors.base00}",\
"#${colors.base08}",\
"#${colors.base0B}",\
"#${colors.base0A}",\
"#${colors.base0D}",\
"#${colors.base0E}",\
"#${colors.base0C}",\
"#${colors.base05}",\
\
/* 8 bright colors */\
"#${colors.base03}",\
"#${colors.base08}",\
"#${colors.base0B}",\
"#${colors.base0A}",\
"#${colors.base0D}",\
"#${colors.base0E}",\
"#${colors.base0C}",\
"#${colors.base07}",\
\
[255] = 0,\
\
/* more colors can be added after 255 to use with DefaultXX */\
"#${colors.base04}", /* 256: cursor */\
"#${colors.base03}", /* 257: reverse cursor */\
"#${colors.base05}", /* 258: foreground */\
"#${colors.base00}", /* 259: background */\
};' config.def.h
'';
}

69
Suckless/st/st.nix Normal file
View file

@ -0,0 +1,69 @@
# st terminal configuration
{ config, pkgs, lib, ... }:
let
appearance = import ./appearance.nix { inherit config lib; };
in
{
nixpkgs.overlays = [(final: prev: {
st = prev.st.overrideAttrs (oldAttrs: {
buildInputs = oldAttrs.buildInputs ++ [ final.harfbuzz ];
patches = (oldAttrs.patches or []) ++ [
# Scrollback (ringbuffer + float + mouse)
(final.fetchurl {
url = "https://st.suckless.org/patches/scrollback/st-scrollback-ringbuffer-0.9.2.diff";
sha256 = "1r23q4mi5bkam49ld5c3ccwaa1li7bbjx0ndjgm207p02az9h4cn";
})
(final.fetchurl {
url = "https://st.suckless.org/patches/scrollback/st-scrollback-float-0.9.2.diff";
sha256 = "01r1gdgkcpf9194257myjnr5nn1fj1baj13wjm9rf2nclbagifgm";
})
(final.fetchurl {
url = "https://st.suckless.org/patches/scrollback/st-scrollback-mouse-0.9.2.diff";
sha256 = "068s5rjvvw2174y34i5xxvpw4jvjy58akd1kgf025h1153hmf7jy";
})
# Alpha (transparency)
(final.fetchurl {
url = "https://st.suckless.org/patches/alpha/st-alpha-20240814-a0274bc.diff";
sha256 = "0hld9dwkk7i1f0z0k9biigx2g4wzlqa2yb7vdn5rrf6ymr5nlbsn";
})
# Anysize (no gaps)
(final.fetchurl {
url = "https://st.suckless.org/patches/anysize/st-expected-anysize-0.9.diff";
sha256 = "04gvkf80lhaiwyv3m7fdkf81msf8al1kfb7inx1bf02ygx9152v2";
})
# Bold is not bright
(final.fetchurl {
url = "https://st.suckless.org/patches/bold-is-not-bright/st-bold-is-not-bright-20190127-3be4cf1.diff";
sha256 = "1cpap2jz80n90izhq5fdv2cvg29hj6bhhvjxk40zkskwmjn6k49j";
})
# Clipboard
(final.fetchurl {
url = "https://st.suckless.org/patches/clipboard/st-clipboard-0.8.3.diff";
sha256 = "1h1nwilwws02h2lnxzmrzr69lyh6pwsym21hvalp9kmbacwy6p0g";
})
# Ligatures (scrollback-ringbuffer variant)
(final.fetchurl {
url = "https://st.suckless.org/patches/ligatures/0.9.3/st-ligatures-scrollback-ringbuffer-20251007-0.9.3.diff";
sha256 = "0c2w1p0siafiyarfx6skdighwzw29d1mydpjfrwgrvdsywwyq2di";
})
];
postPatch = (oldAttrs.postPatch or "") + ''
# Font
substituteInPlace config.def.h \
--replace '"Liberation Mono:pixelsize=12:antialias=true:autohint=true"' \
'"${appearance.font}"'
# Alpha
substituteInPlace config.def.h \
--replace 'float alpha = 0.8;' \
'float alpha = ${appearance.alpha};'
# Colors
${appearance.colorsSed}
'';
});
})];
environment.systemPackages = [ pkgs.st ];
}

121
Suckless/suckless.nix Normal file
View file

@ -0,0 +1,121 @@
# Suckless configuration entry point
# X11 window manager setup with dwm, st, and related tools
{ pkgs, ... }:
{
imports = [
./dwm/dwm.nix
./st/st.nix
./slstatus.nix
];
# ============================================================================
# X11 Display Server
# ============================================================================
services.xserver = {
enable = true;
# Keyboard layout
xkb.layout = "us";
displayManager.startx.enable = true;
# Auto-lock after 10 minutes of inactivity
xautolock = {
enable = true;
time = 10;
locker = "${pkgs.slock}/bin/slock";
};
};
# Input (libinput)
services.libinput.enable = true;
# Tablet/stylus support
services.xserver.wacom.enable = true;
# Accelerometer for auto-rotation
hardware.sensor.iio.enable = true;
# ============================================================================
# Screen Locker
# ============================================================================
programs.slock = {
enable = true;
package = pkgs.slock;
};
# ============================================================================
# XDG Portal for X11
# ============================================================================
xdg.portal = {
enable = true;
extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
config.common.default = "gtk";
};
# ============================================================================
# X11 ecosystem packages
# ============================================================================
environment.systemPackages = with pkgs; [
# Clipboard
xclip
# Wallpaper
xwallpaper
# Numlock on startup
numlockx
# Touchpad gestures
libinput-gestures
# Auto-rotate based on accelerometer (with wallpaper switching, mobile only)
(writeShellScriptBin "auto-rotate" ''
export DISPLAY=''${DISPLAY:-:0}
WALLPAPER_DIR="$HOME/NixOS/Wallpapers"
${iio-sensor-proxy}/bin/monitor-sensor | while read -r line; do
# Skip rotation when docked (would mess up monitor positions)
[[ $(${autorandr}/bin/autorandr --detected) != "mobile" ]] && continue
case "$line" in
*"normal"*)
${xorg.xrandr}/bin/xrandr --output eDP-1 --rotate normal
${xwallpaper}/bin/xwallpaper --output eDP-1 --zoom "$WALLPAPER_DIR/siege.png"
;;
*"left-up"*)
${xorg.xrandr}/bin/xrandr --output eDP-1 --rotate left
${xwallpaper}/bin/xwallpaper --output eDP-1 --zoom "$WALLPAPER_DIR/pearl.jpg"
;;
*"right-up"*)
${xorg.xrandr}/bin/xrandr --output eDP-1 --rotate right
${xwallpaper}/bin/xwallpaper --output eDP-1 --zoom "$WALLPAPER_DIR/pearl.jpg"
;;
*"bottom-up"*)
${xorg.xrandr}/bin/xrandr --output eDP-1 --rotate inverted
${xwallpaper}/bin/xwallpaper --output eDP-1 --zoom "$WALLPAPER_DIR/siege.png"
;;
esac
done
'')
];
# ============================================================================
# Polkit authentication agent
# ============================================================================
security.polkit.enable = true;
systemd.user.services.polkit-gnome-authentication-agent-1 = {
description = "polkit-gnome-authentication-agent-1";
wantedBy = [ "graphical-session.target" ];
wants = [ "graphical-session.target" ];
after = [ "graphical-session.target" ];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1";
Restart = "on-failure";
RestartSec = 1;
TimeoutStopSec = 10;
};
};
}