nixos: add river xmonad session
This commit is contained in:
322
dotfiles/config/river-xmonad/Main.hs
Normal file
322
dotfiles/config/river-xmonad/Main.hs
Normal file
@@ -0,0 +1,322 @@
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
|
||||
module Main where
|
||||
|
||||
import Control.Concurrent (forkIO)
|
||||
import Data.Bits ((.&.), complement)
|
||||
import Data.Function (on)
|
||||
import Data.List (minimumBy)
|
||||
import qualified Data.Map.Strict as M
|
||||
import Data.Maybe (mapMaybe)
|
||||
import Graphics.X11.ExtraTypes.XF86
|
||||
import System.IO (hFlush, stdout)
|
||||
import System.Process (spawnCommand, waitForProcess)
|
||||
import XMonad
|
||||
import XMonad.Layout.Accordion
|
||||
import XMonad.Layout.Cross
|
||||
import XMonad.Layout.Grid
|
||||
import XMonad.Layout.MultiColumns
|
||||
import qualified XMonad.Layout.Renamed as RN
|
||||
import XMonad.River.WindowManager
|
||||
import XMonad.River.WindowManager.Wayland
|
||||
import qualified XMonad.StackSet as W
|
||||
|
||||
data Direction = DirectionUp | DirectionDown | DirectionLeft | DirectionRight
|
||||
deriving (Eq, Show)
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
let bindings = keyBindings
|
||||
configLog $ "starting imalison-river-xmonad with keybindings=" ++ show (length bindings)
|
||||
initialState <- initialRiverWMState (defaultRiverWMConfig riverLayouts)
|
||||
runRiverWMWaylandConfig
|
||||
RiverWMWaylandConfig
|
||||
{ riverWMWaylandInitialState = initialState
|
||||
, riverWMWaylandKeyBindings = bindings
|
||||
}
|
||||
|
||||
riverLayouts =
|
||||
renamed "4 Columns" (multiCol [1, 1, 1] 2 0.0 (-0.5))
|
||||
||| renamed "3 Columns" (multiCol [1, 1] 2 0.01 (-0.5))
|
||||
||| renamed "Grid" Grid
|
||||
||| renamed "Large Main" (Tall 1 (3 / 100) (3 / 4))
|
||||
||| renamed "2 Columns" (Tall 1 (3 / 100) (1 / 2))
|
||||
||| renamed "Mirror 2 Columns" (Mirror (Tall 1 (3 / 100) (1 / 2)))
|
||||
||| renamed "Accordion" Accordion
|
||||
||| renamed "Cross" simpleCross
|
||||
||| Full
|
||||
where
|
||||
renamed name = RN.renamed [RN.Replace name]
|
||||
|
||||
keyBindings
|
||||
:: (LayoutClass l Window, Read (l Window))
|
||||
=> [RiverWMWaylandKeyBinding l]
|
||||
keyBindings =
|
||||
addHyperChordBindings hyper hyperChord $
|
||||
concat
|
||||
[ directionalBindings super directionalFocus
|
||||
, directionalBindings (super .|. shift) directionalSwap
|
||||
, workspaceBindings
|
||||
, layoutBindings
|
||||
, spawnBindings
|
||||
, mediaBindings
|
||||
]
|
||||
|
||||
directionalBindings
|
||||
:: RiverWMWaylandModifiers
|
||||
-> (Direction -> RiverWMWaylandAction l)
|
||||
-> [RiverWMWaylandKeyBinding l]
|
||||
directionalBindings mods command =
|
||||
[ key mods xK_w (command DirectionUp)
|
||||
, key mods xK_s (command DirectionDown)
|
||||
, key mods xK_a (command DirectionLeft)
|
||||
, key mods xK_d (command DirectionRight)
|
||||
]
|
||||
|
||||
workspaceBindings
|
||||
:: [RiverWMWaylandKeyBinding l]
|
||||
workspaceBindings =
|
||||
[ key (mods .|. super) keysym (stackAction $ command workspace)
|
||||
| (workspace, keysym) <- zip (map show [(1 :: Int) .. 9]) [xK_1 .. xK_9]
|
||||
, (command, mods) <-
|
||||
[ (W.greedyView, noMods)
|
||||
, (W.shift, shift)
|
||||
, (\workspaceId stackSet -> W.greedyView workspaceId (W.shift workspaceId stackSet), ctrl)
|
||||
]
|
||||
]
|
||||
|
||||
layoutBindings
|
||||
:: (LayoutClass l Window, Read (l Window))
|
||||
=> [RiverWMWaylandKeyBinding l]
|
||||
layoutBindings =
|
||||
[ key super xK_space (layoutAction NextLayout)
|
||||
, key super xK_bracketleft (layoutAction Shrink)
|
||||
, key super xK_bracketright (layoutAction Expand)
|
||||
, key super xK_comma (layoutAction (IncMasterN 1))
|
||||
, key super xK_period (layoutAction (IncMasterN (-1)))
|
||||
]
|
||||
|
||||
spawnBindings
|
||||
:: [RiverWMWaylandKeyBinding l]
|
||||
spawnBindings =
|
||||
[ key super xK_Return (spawnAction "ghostty --gtk-single-instance=false")
|
||||
, key super xK_p (spawnAction "rofi -show drun -show-icons")
|
||||
, key (super .|. shift) xK_p (spawnAction "rofi -show run")
|
||||
, key (super .|. alt) xK_c (spawnAction "google-chrome-stable")
|
||||
, key super xK_e (spawnAction "emacsclient --eval '(emacs-everywhere)'")
|
||||
, key super xK_v (spawnAction "wl-paste | wtype -")
|
||||
, key hyper xK_v (spawnAction "rofi -modi 'clipboard:greenclip print' -show clipboard")
|
||||
, key hyper xK_p (spawnAction "rofi-pass")
|
||||
, key hyper xK_h (spawnAction "rofi_shutter")
|
||||
, key hyper xK_c (spawnAction "shell_command.sh")
|
||||
, key hyper xK_x (spawnAction "rofi_command.sh")
|
||||
, key (hyper .|. shift) xK_l (spawnAction "loginctl lock-session")
|
||||
, key hyper xK_k (spawnAction "rofi_kill_process.sh")
|
||||
, key (hyper .|. shift) xK_k (spawnAction "rofi_kill_all.sh")
|
||||
, key hyper xK_r (spawnAction "rofi-systemd")
|
||||
, key hyper xK_9 (spawnAction "start_synergy.sh")
|
||||
, key hyper xK_backslash (spawnAction "$HOME/dotfiles/dotfiles/lib/functions/mpg341cx_input toggle")
|
||||
, key hyper xK_i (spawnAction "rofi_select_input.hs")
|
||||
, key hyper xK_o (spawnAction "rofi_paswitch")
|
||||
, key hyper xK_w (spawnAction "rofi_wallpaper.sh")
|
||||
, key hyper xK_y (spawnAction "rofi_agentic_skill")
|
||||
]
|
||||
|
||||
mediaBindings
|
||||
:: [RiverWMWaylandKeyBinding l]
|
||||
mediaBindings =
|
||||
[ key super xK_semicolon (spawnAction "playerctl play-pause")
|
||||
, key noMods xF86XK_AudioPause (spawnAction "playerctl play-pause")
|
||||
, key noMods xF86XK_AudioPlay (spawnAction "playerctl play-pause")
|
||||
, key super xK_l (spawnAction "playerctl next")
|
||||
, key noMods xF86XK_AudioNext (spawnAction "playerctl next")
|
||||
, key super xK_j (spawnAction "playerctl previous")
|
||||
, key noMods xF86XK_AudioPrev (spawnAction "playerctl previous")
|
||||
, key noMods xF86XK_AudioRaiseVolume (spawnAction "set_volume --unmute --change-volume +5")
|
||||
, key noMods xF86XK_AudioLowerVolume (spawnAction "set_volume --unmute --change-volume -5")
|
||||
, key noMods xF86XK_AudioMute (spawnAction "set_volume --toggle-mute")
|
||||
, key super xK_i (spawnAction "set_volume --unmute --change-volume +5")
|
||||
, key super xK_k (spawnAction "set_volume --unmute --change-volume -5")
|
||||
, key super xK_u (spawnAction "set_volume --toggle-mute")
|
||||
, key (hyper .|. shift) xK_q (spawnAction "toggle_mute_current_window.sh")
|
||||
, key (hyper .|. ctrl) xK_q (spawnAction "toggle_mute_current_window.sh only")
|
||||
, key noMods xF86XK_MonBrightnessUp (spawnAction "brightness.sh up")
|
||||
, key noMods xF86XK_MonBrightnessDown (spawnAction "brightness.sh down")
|
||||
]
|
||||
|
||||
key
|
||||
:: RiverWMWaylandModifiers
|
||||
-> KeySym
|
||||
-> RiverWMWaylandAction l
|
||||
-> RiverWMWaylandKeyBinding l
|
||||
key modifiers keysym action =
|
||||
RiverWMWaylandKeyBinding
|
||||
{ riverWMWaylandKeyModifiers = modifiers
|
||||
, riverWMWaylandKeyKeysym = fromIntegral keysym
|
||||
, riverWMWaylandKeyAction = action
|
||||
}
|
||||
|
||||
spawnAction :: String -> RiverWMWaylandAction l
|
||||
spawnAction command state = do
|
||||
configLog $ "spawn start: " ++ command
|
||||
process <- spawnCommand (riverSpawnPrelude ++ command)
|
||||
_ <- forkIO $ do
|
||||
exitCode <- waitForProcess process
|
||||
configLog $ "spawn exit: " ++ command ++ " -> " ++ show exitCode
|
||||
pure ()
|
||||
pure ([], state)
|
||||
|
||||
riverSpawnPrelude :: String
|
||||
riverSpawnPrelude =
|
||||
"XDG_RUNTIME_DIR=\"${XDG_RUNTIME_DIR:-/run/user/$(id -u)}\"; "
|
||||
++ "export XDG_RUNTIME_DIR; "
|
||||
++ "if [ -z \"${WAYLAND_DISPLAY:-}\" ]; then "
|
||||
++ "for socket in \"$XDG_RUNTIME_DIR\"/wayland-*; do "
|
||||
++ "[ -S \"$socket\" ] || continue; "
|
||||
++ "WAYLAND_DISPLAY=\"$(basename \"$socket\")\"; "
|
||||
++ "break; "
|
||||
++ "done; "
|
||||
++ "fi; "
|
||||
++ "export WAYLAND_DISPLAY=\"${WAYLAND_DISPLAY:-wayland-1}\"; "
|
||||
++ "export XDG_CURRENT_DESKTOP=river; "
|
||||
++ "export XDG_SESSION_DESKTOP=river-xmonad; "
|
||||
++ "export XDG_SESSION_TYPE=wayland; "
|
||||
++ "export IMALISON_SESSION_TYPE=wayland; "
|
||||
++ "export IMALISON_WINDOW_MANAGER=river-xmonad; "
|
||||
|
||||
configLog :: String -> IO ()
|
||||
configLog message = do
|
||||
putStrLn $ "imalison-river-xmonad: " ++ message
|
||||
hFlush stdout
|
||||
|
||||
layoutAction
|
||||
:: (LayoutClass l Window, Read (l Window), Message message)
|
||||
=> message
|
||||
-> RiverWMWaylandAction l
|
||||
layoutAction = handleRiverWMLayoutMessage
|
||||
|
||||
stackAction
|
||||
:: (W.StackSet WorkspaceId (l Window) Window RiverWMOutputId ScreenDetail
|
||||
-> W.StackSet WorkspaceId (l Window) Window RiverWMOutputId ScreenDetail)
|
||||
-> RiverWMWaylandAction l
|
||||
stackAction f state =
|
||||
pure $ modifyRiverWMStackSet f state
|
||||
|
||||
directionalSwap :: Direction -> RiverWMWaylandAction l
|
||||
directionalSwap direction =
|
||||
stackAction $
|
||||
case direction of
|
||||
DirectionUp -> W.swapUp
|
||||
DirectionLeft -> W.swapUp
|
||||
DirectionDown -> W.swapDown
|
||||
DirectionRight -> W.swapDown
|
||||
|
||||
directionalFocus :: Direction -> RiverWMWaylandAction l
|
||||
directionalFocus direction state =
|
||||
pure $ modifyRiverWMStackSet focusDirectionalWindow state
|
||||
where
|
||||
focusDirectionalWindow stackSet =
|
||||
maybe stackSet (`W.focusWindow` stackSet) $
|
||||
directionalTarget direction state
|
||||
|
||||
directionalTarget :: Direction -> RiverWMState l -> Maybe Window
|
||||
directionalTarget direction RiverWMState{riverWMStackSet, riverWMWindows, riverWMWindowIds} = do
|
||||
focused <- W.peek riverWMStackSet
|
||||
focusedId <- M.lookup focused riverWMWindowIds
|
||||
focusedRect <- riverWMWindowDesired =<< M.lookup focusedId riverWMWindows
|
||||
let focusedCenter = rectCenter focusedRect
|
||||
candidates =
|
||||
[ (window, directionScore direction focusedCenter (rectCenter rect))
|
||||
| (windowId, RiverWMWindowState{riverWMWindowXWindow = window, riverWMWindowDesired = Just rect}) <-
|
||||
M.toList riverWMWindows
|
||||
, windowId /= focusedId
|
||||
]
|
||||
viable = mapMaybe sequenceCandidate candidates
|
||||
fst <$> minimumMaybeBy (compare `on` snd) viable
|
||||
|
||||
sequenceCandidate :: (a, Maybe b) -> Maybe (a, b)
|
||||
sequenceCandidate (value, Just score) = Just (value, score)
|
||||
sequenceCandidate (_, Nothing) = Nothing
|
||||
|
||||
rectCenter :: Rectangle -> (Double, Double)
|
||||
rectCenter (Rectangle x y width height) =
|
||||
( fromIntegral x + fromIntegral width / 2
|
||||
, fromIntegral y + fromIntegral height / 2
|
||||
)
|
||||
|
||||
directionScore :: Direction -> (Double, Double) -> (Double, Double) -> Maybe (Double, Double)
|
||||
directionScore direction (fx, fy) (cx, cy) =
|
||||
case direction of
|
||||
DirectionUp | cy < fy -> Just (fy - cy, abs (cx - fx))
|
||||
DirectionDown | cy > fy -> Just (cy - fy, abs (cx - fx))
|
||||
DirectionLeft | cx < fx -> Just (fx - cx, abs (cy - fy))
|
||||
DirectionRight | cx > fx -> Just (cx - fx, abs (cy - fy))
|
||||
_ -> Nothing
|
||||
|
||||
minimumMaybeBy :: (a -> a -> Ordering) -> [a] -> Maybe a
|
||||
minimumMaybeBy _ [] = Nothing
|
||||
minimumMaybeBy compareFn xs = Just (minimumBy compareFn xs)
|
||||
|
||||
addHyperChordBindings
|
||||
:: RiverWMWaylandModifiers
|
||||
-> RiverWMWaylandModifiers
|
||||
-> [RiverWMWaylandKeyBinding l]
|
||||
-> [RiverWMWaylandKeyBinding l]
|
||||
addHyperChordBindings hyperMask chordMask bindings =
|
||||
bindings ++ M.elems chosen
|
||||
where
|
||||
existingKeys =
|
||||
M.fromList
|
||||
[ ((riverWMWaylandKeyModifiers binding, riverWMWaylandKeyKeysym binding), ())
|
||||
| binding <- bindings
|
||||
]
|
||||
|
||||
chordBinding binding@RiverWMWaylandKeyBinding{riverWMWaylandKeyModifiers} =
|
||||
binding
|
||||
{ riverWMWaylandKeyModifiers =
|
||||
(riverWMWaylandKeyModifiers .&. complement hyperMask) .|. chordMask
|
||||
}
|
||||
|
||||
candidates =
|
||||
[ ( (riverWMWaylandKeyModifiers chorded, riverWMWaylandKeyKeysym chorded)
|
||||
, (score (riverWMWaylandKeyModifiers binding), chorded)
|
||||
)
|
||||
| binding <- bindings
|
||||
, riverWMWaylandKeyModifiers binding .&. hyperMask /= 0
|
||||
, let chorded = chordBinding binding
|
||||
, M.notMember (riverWMWaylandKeyModifiers chorded, riverWMWaylandKeyKeysym chorded) existingKeys
|
||||
]
|
||||
|
||||
chosen =
|
||||
fmap snd $
|
||||
foldl' keepBest M.empty candidates
|
||||
|
||||
keepBest selected (bindingKey, candidate@(candidateScore, _binding)) =
|
||||
case M.lookup bindingKey selected of
|
||||
Nothing -> M.insert bindingKey candidate selected
|
||||
Just (bestScore, _) ->
|
||||
if candidateScore < bestScore
|
||||
then M.insert bindingKey candidate selected
|
||||
else selected
|
||||
|
||||
score modifiers =
|
||||
length $
|
||||
filter (/= 0)
|
||||
[ modifiers .&. shift
|
||||
, modifiers .&. ctrl
|
||||
, modifiers .&. alt
|
||||
, modifiers .&. hyper
|
||||
, modifiers .&. super
|
||||
, modifiers .&. riverWMWaylandModifierMod5
|
||||
]
|
||||
|
||||
noMods, shift, ctrl, alt, hyper, super, hyperChord :: RiverWMWaylandModifiers
|
||||
noMods = riverWMWaylandModifierNone
|
||||
shift = riverWMWaylandModifierShift
|
||||
ctrl = riverWMWaylandModifierCtrl
|
||||
alt = riverWMWaylandModifierAlt
|
||||
hyper = riverWMWaylandModifierHyper
|
||||
super = riverWMWaylandModifierSuper
|
||||
hyperChord = ctrl .|. alt .|. super
|
||||
18
dotfiles/config/river-xmonad/imalison-river-xmonad.cabal
Normal file
18
dotfiles/config/river-xmonad/imalison-river-xmonad.cabal
Normal file
@@ -0,0 +1,18 @@
|
||||
cabal-version: 2.4
|
||||
name: imalison-river-xmonad
|
||||
version: 0.1.0.0
|
||||
license: BSD-3-Clause
|
||||
author: Ivan Malison
|
||||
maintainer: IvanMalison@gmail.com
|
||||
build-type: Simple
|
||||
|
||||
executable imalison-river-xmonad
|
||||
main-is: Main.hs
|
||||
build-depends: base >= 4.12 && < 5
|
||||
, containers
|
||||
, process
|
||||
, X11
|
||||
, xmonad
|
||||
, xmonad-contrib
|
||||
ghc-options: -Wall -Wno-unused-do-bind -Wno-deprecations -Wno-missing-signatures -Wno-name-shadowing
|
||||
default-language: Haskell2010
|
||||
13
dotfiles/config/river-xmonad/overlay.nix
Normal file
13
dotfiles/config/river-xmonad/overlay.nix
Normal file
@@ -0,0 +1,13 @@
|
||||
_: pkgs: {
|
||||
haskellPackages = pkgs.haskellPackages.override (old: {
|
||||
overrides = pkgs.lib.composeExtensions (old.overrides or (_: _: {})) (self: _super: {
|
||||
imalison-river-xmonad = self.callCabal2nix "imalison-river-xmonad" (
|
||||
pkgs.lib.sourceByRegex ./.
|
||||
[
|
||||
"Main.hs"
|
||||
"imalison-river-xmonad.cabal"
|
||||
]
|
||||
) { };
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -37,6 +37,7 @@
|
||||
./rabbitmq.nix
|
||||
./quickshell.nix
|
||||
./remote-hyprland.nix
|
||||
./river-xmonad.nix
|
||||
./secrets.nix
|
||||
./ssh.nix
|
||||
./sni.nix
|
||||
|
||||
29
nixos/flake.lock
generated
29
nixos/flake.lock
generated
@@ -1808,7 +1808,8 @@
|
||||
"systems": "systems_4",
|
||||
"vscode-server": "vscode-server",
|
||||
"xmonad": "xmonad_2",
|
||||
"xmonad-contrib": "xmonad-contrib_2"
|
||||
"xmonad-contrib": "xmonad-contrib_2",
|
||||
"xmonad-river": "xmonad-river"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
@@ -2120,6 +2121,32 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"xmonad-river": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"git-ignore-nix": [
|
||||
"git-ignore-nix"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"unstable": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777476488,
|
||||
"narHash": "sha256-2Adfi0BDJEM/ITFbXJkS21wVQ96oNXLLUh4HsHonCl4=",
|
||||
"path": "/home/imalison/Projects/xmonad-river",
|
||||
"type": "path"
|
||||
},
|
||||
"original": {
|
||||
"path": "/home/imalison/Projects/xmonad-river",
|
||||
"type": "path"
|
||||
}
|
||||
},
|
||||
"xmonad_2": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
|
||||
@@ -147,6 +147,16 @@
|
||||
};
|
||||
};
|
||||
|
||||
xmonad-river = {
|
||||
url = "path:/home/imalison/Projects/xmonad-river";
|
||||
inputs = {
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
unstable.follows = "nixpkgs";
|
||||
flake-utils.follows = "flake-utils";
|
||||
git-ignore-nix.follows = "git-ignore-nix";
|
||||
};
|
||||
};
|
||||
|
||||
xmonad-contrib = {
|
||||
url = "github:IvanMalison/xmonad-contrib/withMyChanges";
|
||||
inputs = {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
myModules.base.enable = true;
|
||||
myModules.desktop.enable = true;
|
||||
myModules.xmonad.enable = true;
|
||||
myModules.riverXmonad.enable = true;
|
||||
myModules.extra.enable = false;
|
||||
myModules.code.enable = true;
|
||||
myModules.games.enable = false;
|
||||
|
||||
169
nixos/river-xmonad.nix
Normal file
169
nixos/river-xmonad.nix
Normal file
@@ -0,0 +1,169 @@
|
||||
{
|
||||
config,
|
||||
inputs,
|
||||
lib,
|
||||
makeEnable,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
session = import ./session-variables.nix;
|
||||
|
||||
riverXmonadPkgs = pkgs.extend (
|
||||
lib.composeManyExtensions [
|
||||
inputs.xmonad-river.overlay
|
||||
inputs.xmonad-contrib.overlay
|
||||
(import ../dotfiles/config/river-xmonad/overlay.nix)
|
||||
]
|
||||
);
|
||||
|
||||
riverXmonadPackage = riverXmonadPkgs.haskellPackages.imalison-river-xmonad;
|
||||
|
||||
riverRofi = pkgs.writeShellScriptBin "rofi" ''
|
||||
exec ${pkgs.rofi}/bin/rofi -normal-window "$@"
|
||||
'';
|
||||
|
||||
riverInit = pkgs.writeShellScript "river-xmonad-init" ''
|
||||
log_dir="''${XDG_STATE_HOME:-$HOME/.local/state}/river-xmonad"
|
||||
mkdir -p "$log_dir"
|
||||
echo "[$(${pkgs.coreutils}/bin/date --iso-8601=seconds)] river init start"
|
||||
|
||||
export PATH=${lib.makeBinPath [ riverRofi ]}:$PATH
|
||||
export XDG_CURRENT_DESKTOP=river
|
||||
export XDG_SESSION_DESKTOP=river-xmonad
|
||||
export XDG_SESSION_TYPE=wayland
|
||||
export ${session.sessionType}=wayland
|
||||
export ${session.windowManager}=river-xmonad
|
||||
|
||||
systemctl --user stop hyprland-session.target || true
|
||||
systemctl --user unset-environment HYPRLAND_INSTANCE_SIGNATURE || true
|
||||
|
||||
${pkgs.dbus}/bin/dbus-update-activation-environment --systemd \
|
||||
WAYLAND_DISPLAY DISPLAY XAUTHORITY XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE \
|
||||
${session.sessionType} ${session.windowManager} DBUS_SESSION_BUS_ADDRESS PATH || true
|
||||
systemctl --user set-environment \
|
||||
"WAYLAND_DISPLAY=''${WAYLAND_DISPLAY:-}" \
|
||||
"DISPLAY=''${DISPLAY:-}" \
|
||||
"XAUTHORITY=''${XAUTHORITY:-}" \
|
||||
XDG_CURRENT_DESKTOP=river \
|
||||
XDG_SESSION_DESKTOP=river-xmonad \
|
||||
XDG_SESSION_TYPE=wayland \
|
||||
${session.sessionType}=wayland \
|
||||
${session.windowManager}=river-xmonad \
|
||||
"DBUS_SESSION_BUS_ADDRESS=''${DBUS_SESSION_BUS_ADDRESS:-}" \
|
||||
"PATH=$PATH" || true
|
||||
systemctl --user import-environment \
|
||||
WAYLAND_DISPLAY DISPLAY XAUTHORITY XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE \
|
||||
${session.sessionType} ${session.windowManager} DBUS_SESSION_BUS_ADDRESS PATH || true
|
||||
systemctl --user start river-xmonad-session.target || true
|
||||
|
||||
echo "[$(${pkgs.coreutils}/bin/date --iso-8601=seconds)] exec imalison-river-xmonad"
|
||||
exec ${riverXmonadPackage}/bin/imalison-river-xmonad
|
||||
'';
|
||||
|
||||
riverSession = pkgs.writeShellScriptBin "river-xmonad-session" ''
|
||||
log_dir="''${XDG_STATE_HOME:-$HOME/.local/state}/river-xmonad"
|
||||
mkdir -p "$log_dir"
|
||||
log_file="$log_dir/session.log"
|
||||
exec >>"$log_file" 2>&1
|
||||
|
||||
echo
|
||||
echo "===== river-xmonad session start: $(${pkgs.coreutils}/bin/date --iso-8601=seconds) ====="
|
||||
|
||||
export XDG_CURRENT_DESKTOP=river
|
||||
export XDG_SESSION_DESKTOP=river-xmonad
|
||||
export XDG_SESSION_TYPE=wayland
|
||||
export ${session.sessionType}=wayland
|
||||
export ${session.windowManager}=river-xmonad
|
||||
export PATH=${lib.makeBinPath [ riverRofi ]}:$PATH
|
||||
|
||||
echo "river-xmonad: environment before river"
|
||||
env | ${pkgs.coreutils}/bin/sort
|
||||
|
||||
systemctl --user stop hyprland-session.target || true
|
||||
systemctl --user unset-environment HYPRLAND_INSTANCE_SIGNATURE || true
|
||||
|
||||
${pkgs.river}/bin/river -c ${lib.escapeShellArg "${riverInit}"}
|
||||
status=$?
|
||||
echo "river-xmonad: river exited with status $status at $(${pkgs.coreutils}/bin/date --iso-8601=seconds)"
|
||||
systemctl --user stop river-xmonad-session.target || true
|
||||
exit "$status"
|
||||
'';
|
||||
|
||||
riverDiagnostics = pkgs.writeShellScriptBin "river-xmonad-diagnostics" ''
|
||||
set -u
|
||||
|
||||
log_dir="''${XDG_STATE_HOME:-$HOME/.local/state}/river-xmonad"
|
||||
echo "river-xmonad diagnostics: $(${pkgs.coreutils}/bin/date --iso-8601=seconds)"
|
||||
echo
|
||||
|
||||
echo "== processes =="
|
||||
${pkgs.procps}/bin/pgrep -a 'river|imalison-river-xmonad|rofi|ghostty|hyprpaper|xsettingsd|picom|autorandr' || true
|
||||
echo
|
||||
|
||||
echo "== user manager environment =="
|
||||
systemctl --user show-environment | ${pkgs.coreutils}/bin/sort | ${pkgs.gnugrep}/bin/grep -E '^(HYPR|IMALISON|XDG_CURRENT_DESKTOP|XDG_SESSION_DESKTOP|XDG_SESSION_TYPE|WAYLAND_DISPLAY|DISPLAY)=' || true
|
||||
echo
|
||||
|
||||
echo "== session unit guards =="
|
||||
systemctl --user cat river-xmonad-session.target dunst.service hyprpaper.service hyprland-session.target xsettingsd.service picom.service autorandr.service 2>/dev/null \
|
||||
| ${pkgs.gnugrep}/bin/grep -E '^(# |\\[Unit\\]|Description=|ConditionEnvironment=|PartOf=|After=|WantedBy=|ExecStart=|\\[Install\\])' || true
|
||||
echo
|
||||
|
||||
echo "== recent user journal =="
|
||||
journalctl --user -b --since '10 minutes ago' --no-pager \
|
||||
| ${pkgs.gnugrep}/bin/grep -Ei 'river|xmonad|rofi|ghostty|hyprpaper|xsettingsd|picom|autorandr|failed|error|segfault|core-dump' || true
|
||||
echo
|
||||
|
||||
if [ -f "$log_dir/session.log" ]; then
|
||||
echo "== $log_dir/session.log tail =="
|
||||
${pkgs.coreutils}/bin/tail -n 250 "$log_dir/session.log"
|
||||
else
|
||||
echo "no session log at $log_dir/session.log"
|
||||
fi
|
||||
'';
|
||||
|
||||
riverSessionPackage = (pkgs.writeTextFile {
|
||||
name = "river-xmonad-session";
|
||||
destination = "/share/wayland-sessions/river-xmonad.desktop";
|
||||
text = ''
|
||||
[Desktop Entry]
|
||||
Name=river-xmonad
|
||||
Comment=river with xmonad as its external window manager
|
||||
Exec=${riverSession}/bin/river-xmonad-session
|
||||
Type=Application
|
||||
DesktopNames=river
|
||||
'';
|
||||
}).overrideAttrs (_old: {
|
||||
passthru.providedSessions = [ "river-xmonad" ];
|
||||
});
|
||||
in
|
||||
makeEnable config "myModules.riverXmonad" false {
|
||||
services.displayManager.sessionPackages = [
|
||||
riverSessionPackage
|
||||
];
|
||||
|
||||
home-manager.sharedModules = [
|
||||
{
|
||||
systemd.user.targets.river-xmonad-session = {
|
||||
Unit = {
|
||||
Description = "river-xmonad session";
|
||||
ConditionEnvironment = session.riverXmonad;
|
||||
BindsTo = [ "graphical-session.target" ];
|
||||
Wants = [ "graphical-session-pre.target" ];
|
||||
After = [ "graphical-session-pre.target" ];
|
||||
Before = [ "graphical-session.target" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
brightnessctl
|
||||
river
|
||||
riverDiagnostics
|
||||
riverXmonadPackage
|
||||
wl-clipboard
|
||||
wtype
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user