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;
+ 	}