Setup some basic WM stuff
- Standard image background
- Polybar
- A standard XMonad config
- Picom
diff --git a/modules/feh.nix b/modules/feh.nix
new file mode 100644
index 0000000..dafeb4a
--- /dev/null
+++ b/modules/feh.nix
@@ -0,0 +1,6 @@
+{pkgs, ...}: {
+ home.home = {
+ packages = [pkgs.feh];
+ file.".xmonad/background.png".source = ./feh/background.png;
+ };
+}
diff --git a/modules/feh/background.png b/modules/feh/background.png
new file mode 100644
index 0000000..c637bc9
--- /dev/null
+++ b/modules/feh/background.png
Binary files differ
diff --git a/modules/picom.nix b/modules/picom.nix
new file mode 100644
index 0000000..948a224
--- /dev/null
+++ b/modules/picom.nix
@@ -0,0 +1,28 @@
+{ lib, pkgs, ... }: {
+ home = {
+ services.picom = {
+ enable = true;
+ package = pkgs.picom-next;
+ experimentalBackends = true;
+ backend = "glx";
+ fade = true;
+ inactiveOpacity = 0.9;
+ vSync = true;
+ settings = {
+ blur.method = "dual_kawase";
+ corner-radius = 10;
+ glx-no-stencil = true;
+ unredir-if-possible = true;
+ use-damage = true;
+ no-fading-openclose = true;
+ fade-in-step = 0.005;
+ fade-out-step = 0.005;
+ no-fading-larger-than = 0.1;
+ rounded-corners-exclude = [
+ "class_g = 'Polybar'"
+ ];
+ };
+ };
+ systemd.user.services.picom.Install.WantedBy = lib.mkForce [ ];
+ };
+}
diff --git a/modules/polybar.nix b/modules/polybar.nix
index 44bb54b..8d78b1f 100644
--- a/modules/polybar.nix
+++ b/modules/polybar.nix
@@ -1,8 +1,65 @@
-{
- home.services.polybar = {
- enable = true;
- settings = {
-
+{ lib, pkgs, ... }: {
+ home = {
+ services.polybar = {
+ enable = true;
+ settings = {
+ "bar/main" = {
+ "inherit" = "base";
+ };
+ base = {
+ modules = {
+ left = "xmonad";
+ right = "date battery";
+ };
+ font = [
+ "Liga Roboto Mono:style=Regular:size=10;2"
+ "Twitter Color Emoji:style=Regular:antialias=false:scale=8;1"
+ ];
+ background = "\${colors.statusline}";
+ padding = 10;
+ module.margin = 5;
+ margin.bottom = "\${root.padding}";
+ tray.position = "right";
+ };
+ "module/xmonad" = {
+ type = "custom/script";
+ exec = "${pkgs.xmonad-log}/bin/xmonad-log";
+ tail = true;
+ };
+ "module/date" = {
+ type = "internal/date";
+ date = rec {
+ text = "%Y-%m-%d";
+ alt = text;
+ };
+ time = {
+ text = "%H:%M";
+ alt = "%H:%M:%S";
+ };
+ label = "%date% %time%";
+ };
+ "module/battery".type = "internal/battery";
+ colors = {
+ black = "#282c34";
+ red = "#e06c75";
+ green = "#98c379";
+ yellow = "#e5c07b";
+ blue = "#61afef";
+ purple = "#c678dd";
+ cyan = "#56b6c2";
+ statusline = "#313640";
+ lightgrey = "#474e5d";
+ darkred = "#844C55";
+ darkyellow = "#877658";
+ darkgreen = "#607857";
+ darkcyan = "#3F717B";
+ darkblue = "#456E92";
+ darkpurple = "#775289";
+ white = "#dcdfe4";
+ };
+ };
+ script = "polybar &";
};
+ systemd.user.services.polybar.Install.WantedBy = lib.mkForce [ ];
};
}
diff --git a/modules/xmonad.nix b/modules/xmonad.nix
index 745739e..0457b73 100644
--- a/modules/xmonad.nix
+++ b/modules/xmonad.nix
@@ -1,11 +1,24 @@
-{ pkgs, home, config, ... }: {
+{ lib, pkgs, home, config, ... }: {
home = {
xsession = {
windowManager.xmonad = {
enable = true;
enableContribAndExtras = true;
config = ./xmonad/xmonad.hs;
+ libFiles = lib.pipe ./xmonad [
+ builtins.readDir
+ builtins.attrNames
+ (builtins.filter (name: name != "xmonad.hs"))
+ (map (name: {
+ inherit name;
+ value = "${./xmonad}/${name}";
+ }))
+ builtins.listToAttrs
+ ];
extraPackages = haskellPackages: with haskellPackages; [
+ dbus
+ monad-logger
+ xmonad-contrib
];
};
};
@@ -15,7 +28,7 @@
fi
'';
home.file.".xinitrc".text = ''
- ${home.xsession.windowManager.command}
+ ${home.xsession.windowManager.command}
'';
};
config.services.xserver = {
diff --git a/modules/xmonad/XMonadLog.hs b/modules/xmonad/XMonadLog.hs
new file mode 100644
index 0000000..78b707b
--- /dev/null
+++ b/modules/xmonad/XMonadLog.hs
@@ -0,0 +1,44 @@
+-- spell-checker:words xmonad,dbus,polybar,mempty
+
+module XMonadLog where
+
+import qualified DBus as D
+import qualified DBus.Client as D
+
+import qualified Codec.Binary.UTF8.String as UTF8
+import XMonad.Hooks.StatusBar.PP
+import XMonad.Util.Replace (replace)
+
+xmonadLog :: IO D.Client
+xmonadLog = let opts = [D.nameAllowReplacement, D.nameReplaceExisting, D.nameDoNotQueue]
+ in do
+ dbus <- D.connectSession
+ D.requestName dbus (D.busName_ "org.xmonad.Log") opts
+ return dbus
+
+dbusOutput :: D.Client -> String -> IO ()
+dbusOutput dbus str =
+ let objectPath = D.objectPath_ "/org/xmonad/Log"
+ interfaceName = D.interfaceName_ "org.xmonad.Log"
+ memberName = D.memberName_ "Update"
+ signal = D.signal objectPath interfaceName memberName
+ body = [D.toVariant str]
+ in D.emit dbus $ signal { D.signalBody = body }
+
+polybarHook :: D.Client -> PP
+polybarHook dbus =
+ let wrapper c s | s /= "NSP" = wrap ("%{F" <> c <> "} ") " %{F-}" s
+ | otherwise = mempty
+ blue = "#61afef"
+ grey = "#474e5d"
+ orange = "#e5c07b"
+ purple = "#c678dd"
+ red = "#e06c75"
+ in def { ppOutput = dbusOutput dbus
+ , ppCurrent = wrapper blue
+ , ppVisible = wrapper red
+ , ppUrgent = wrapper orange
+ , ppHidden = wrapper red
+ , ppHiddenNoWindows = wrapper grey
+ , ppTitle = shorten 100 . wrapper purple
+ }
diff --git a/modules/xmonad/xmonad.hs b/modules/xmonad/xmonad.hs
index 725ae28..bbd949f 100644
--- a/modules/xmonad/xmonad.hs
+++ b/modules/xmonad/xmonad.hs
@@ -4,23 +4,48 @@
import System.Exit
import XMonad.Util.EZConfig
+import XMonad.Hooks.EwmhDesktops
+import XMonad.Hooks.ManageDocks
+import XMonad.Config.Desktop
+
+import XMonadLog
+import XMonad.Hooks.DynamicLog
+import qualified DBus.Client as D
+
+import XMonad.Layout.Spacing
+import XMonad.Layout.Gaps
+
terminal = "kitty" -- Kitty, my beloved <3
launcher = "pkill rofi; rofi -show combi"
networkManager = "wpa_cli select_network $(wpa_cli list_networks | tail -n +3 | rofi -dmenu -window-title 'Select Network' | awk '{print $1;}')"
modifierKey = mod4Mask -- Use Super as our mod key
statusBar = "pkill polybar; polybar"
+compositor = "pkill picom; picom"
+background = "feh --no-fehbg --bg-fill .xmonad/background.png"
shift = shiftMask
startupHook = do
- spawn statusBar
+ spawn Main.statusBar
+ spawn Main.compositor
+ spawn background
+
main :: IO ()
-main = xmonad $ ewmh def
+main = XMonadLog.xmonadLog >>= main'
+
+main' :: D.Client -> IO ()
+main' dbus = xmonad $ docks $ ewmh . ewmhFullscreen $ def
{ modMask = modifierKey -- Use Super as our mod key
+ , borderWidth = 0
, XMonad.terminal = Main.terminal
- , startupHook = startupHook
+ , XMonad.startupHook = Main.startupHook
+ , XMonad.logHook = dynamicLogWithPP (polybarHook dbus)
+ , XMonad.layoutHook = avoidStruts $
+ smartSpacing 5 $
+ gaps [(U, 5), (D, 5), (L, 5), (R, 5)] $
+ layoutHook def
} `additionalKeys`
[ ((modifierKey, xK_d), spawn launcher)
, ((modifierKey, xK_n), spawn networkManager)
diff --git a/packages/picom-next.nix b/packages/picom-next.nix
new file mode 100644
index 0000000..02f0943
--- /dev/null
+++ b/packages/picom-next.nix
@@ -0,0 +1,13 @@
+{ picom, lib, fetchFromGitHub }:
+
+picom.overrideAttrs (oldAttrs: rec {
+ pname = "picom-next";
+ version = "unstable-2022-11-05";
+ src = fetchFromGitHub {
+ owner = "yshui";
+ repo = "picom";
+ rev = "d59ec6a34ae7435e8d01d85412a5dfaf18f90f68";
+ sha256 = "sha256-CvSxeonV0pKvIyKQplnNFgDDlekN6LKGbhdwmOmwJTo=";
+ };
+ meta.maintainers = with lib.maintainers; oldAttrs.meta.maintainers ++ [ GKasparov minion3665 ];
+})
diff --git a/patches/picom-next/max_fade.patch b/patches/picom-next/max_fade.patch
new file mode 100644
index 0000000..0745dd0
--- /dev/null
+++ b/patches/picom-next/max_fade.patch
@@ -0,0 +1,105 @@
+diff --git a/src/config.c b/src/config.c
+index d9b2dd9..0eb49de 100644
+--- a/src/config.c
++++ b/src/config.c
+@@ -755,6 +755,7 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
+ .fade_in_step = 0.028,
+ .fade_out_step = 0.03,
+ .fade_delta = 10,
++ .no_fading_larger_than = 0,
+ .no_fading_openclose = false,
+ .no_fading_destroyed_argb = false,
+ .fade_blacklist = NULL,
+diff --git a/src/config.h b/src/config.h
+index 7259dc1..a555be7 100644
+--- a/src/config.h
++++ b/src/config.h
+@@ -165,6 +165,8 @@ typedef struct options {
+ double fade_out_step;
+ /// Fading time delta. In milliseconds.
+ int fade_delta;
++ /// The maximum opacity change to fade on.
++ double no_fading_larger_than;
+ /// Whether to disable fading on window open/close.
+ bool no_fading_openclose;
+ /// Whether to disable fading on ARGB managed destroyed windows.
+diff --git a/src/config_libconfig.c b/src/config_libconfig.c
+index 461fff3..1e008c2 100644
+--- a/src/config_libconfig.c
++++ b/src/config_libconfig.c
+@@ -351,6 +351,8 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
+ // -f (fading_enable)
+ if (config_lookup_bool(&cfg, "fading", &ival))
+ *fading_enable = ival;
++ // --no-fading-larger-than
++ config_lookup_float(&cfg, "no-fading-larger-than", &opt->no_fading_larger_than);
+ // --no-fading-open-close
+ lcfg_lookup_bool(&cfg, "no-fading-openclose", &opt->no_fading_openclose);
+ // --no-fading-destroyed-argb
+diff --git a/src/dbus.c b/src/dbus.c
+index 8b17b30..59d527e 100644
+--- a/src/dbus.c
++++ b/src/dbus.c
+@@ -1289,6 +1289,15 @@ static bool cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
+ goto cdbus_process_opts_set_success;
+ }
+
++ // no_fading_larger_than
++ if (!strcmp("no_fading_larger_than", target)) {
++ double val = 0.0;
++ if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val))
++ return false;
++ ps->o.no_fading_larger_than = normalize_d(val);
++ goto cdbus_process_opts_set_success;
++ }
++
+ // no_fading_openclose
+ if (!strcmp("no_fading_openclose", target)) {
+ dbus_bool_t val = FALSE;
+diff --git a/src/options.c b/src/options.c
+index ba7485d..69e1a40 100644
+--- a/src/options.c
++++ b/src/options.c
+@@ -175,6 +175,7 @@ static const struct picom_option picom_options[] = {
+ "you want to attach a debugger to picom"},
+ {"no-ewmh-fullscreen" , no_argument , 803, NULL , "Do not use EWMH to detect fullscreen windows. Reverts to checking if a "
+ "window is fullscreen based only on its size and coordinates."},
++ {"no-fading-larger-than" , required_argument, 804, NULL , "do not fade when the opacity difference would be larger than this value"},
+ };
+ // clang-format on
+
+@@ -402,6 +403,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
+ // These options are handled by get_early_config()
+ break;
+ P_CASEINT('D', fade_delta);
++ case 804: opt->no_fading_larger_than = normalize_d(atof(optarg)); break;
+ case 'I': opt->fade_in_step = normalize_d(atof(optarg)); break;
+ case 'O': opt->fade_out_step = normalize_d(atof(optarg)); break;
+ case 'c': shadow_enable = true; break;
+diff --git a/src/picom.c b/src/picom.c
+index fd693fc..1a475c5 100644
+--- a/src/picom.c
++++ b/src/picom.c
+@@ -992,7 +992,6 @@ void force_repaint(session_t *ps) {
+ /** @name DBus hooks
+ */
+ ///@{
+-
+ /**
+ * Set no_fading_openclose option.
+ *
+diff --git a/src/win.c b/src/win.c
+index 370fbfd..baea80b 100644
+--- a/src/win.c
++++ b/src/win.c
+@@ -864,6 +864,10 @@ bool win_should_fade(session_t *ps, const struct managed_win *w) {
+ if (w->fade_force != UNSET) {
+ return w->fade_force;
+ }
++ if (ps->o.no_fading_larger_than &&
++ ps->o.no_fading_larger_than < fabs(w->opacity - w->opacity_target)) {
++ return false;
++ }
+ if (ps->o.no_fading_openclose && w->in_openclose) {
+ return false;
+ }