I haven't been particularly pleased with i3wm 's container strategy and basically just miss some of the simplicity of operating with XMonad. I don't miss all the complexity of it though, but maybe I'm in a better position to write roam:Haskell now... Easy enough to fuck around and find out.
i haven't used this in a while...
Minimal Haskell support in Emacs
#+ARROYO_EMACS_MODULE: haskell
Of course this will be included in Arroyo Emacs to make developing this configuration viable.
emacs-lisp source: :tangle cce/haskell.el(use-package haskell-mode) (provide 'cce/haskell)
xomand.hs configuration file
Because KDE is a Base for my Emacs Desktop , I don't fuck with things like xmobar or R&R support in this layer, let my desktop environment deal with all of that instead of me. It has built in integration to configure it to manage the Plasma windows and whatnot reasonably.
haskell source: :tangle ~/arroyo-nix/files/xmonad.hs :noweb yes -rimport XMonad import XMonad.Config.Kde <<imports>> myMod = mod4Mask main = xmonad myConfig myConfig = kde4Config { modMask = myMod , layoutHook = desktopLayoutModifiers $ myLayoutHook , manageHook = manageHook kde4Config <+> myManageHook , workspaces = myWorkspaces <<kde4ConfigDecl>> } `additionalKeys` [ ((myMod, xK_Tab), toggleRecentWS) -- (ref:recentWS) <<additionalKeys>> ] <<myLayoutHook>> <<myManageHook>> <<myWorkspaces>> <<helperFns>>
de-tangling this a bit is probably a fool's errand, but here we go...
XMonad's docs on configuring as well as the quick start guide will make a lot more sense of the hooks but broadly:
The basic kde4Config
"but rrix don't you run Plasma 5?" yes, yes I do, but unlike in the 3->4 transition the KDE developers were able to maintain a large amount of backwards compatibility. I think it would behoove the XMonad developers to recognize this and make, say, a kde3Config for the 30 Trinity users still left but Sir, This is a Wendy's . So all this is broadly defined in XMonad.Config.Kde and XMonad.Config.Desktop except it doesn't talk about Plasma 5 at all.
Make sure if you do make your own kde4Config that it pulls the default manageHook and invokes desktopLayoutModifiers out of the default configuration.
The only really notable things other than wiring up the hooks defined below are some simple appearance changes:
haskell source: :noweb-ref kde4ConfigDecl, focusedBorderColor = "#ebbe7b" , normalBorderColor = "#707231" , borderWidth = 4
EZConfig makes it eazy to define new keybindings
There's not a lot of "there" there additionalKeys is used to add or override keybindings.
haskell source: :noweb-ref importsimport XMonad.Util.EZConfig (additionalKeys) import XMonad.Actions.CycleRecentWS (toggleRecentWS)
That's right, we're nesting noweb functions!
I have a bunch of little helpers in i3wm and A World Without EXWM which I should collate and expand on for example to add my org-fc function... but anyways, S-a opens my agenda, S-f opens a new Emacs frame, S-g opens my Journal , S-x opens a new frame with the M-x execute-interactive-command open on it. S-z opens my todo list. S-c opens my Flash Cards.
haskell source: :noweb-ref additionalKeys, ((myMod, xK_a), spawn "org-agenda") , ((myMod, xK_f), spawn "emacsclient -c -n") , ((myMod, xK_g), spawn "org-journal") , ((myMod, xK_x), spawn "meta-x") , ((myMod, xK_z), spawn "org-todos") , ((myMod, xK_c), spawn "emacsclient -c -e '(srs)' -n") , ((myMod, xK_p), spawn "bash -c 'pkill krunner; krunner'")
There is also (recentWS) above which toggles between the ... most recent workspace ... on S-Tab. Useful for jumping between work terminals spread on the high-numbered workspaces when I am working on a high-context activity on my laptop display only. I provide it up there so that the first element of that list doesn't start with a comma, basically. All the other parts which go in to additionalKeys should start with a commas as though they're (rightfully) being spliced in to a list.
myWorkspaces culls down my workspace list a bit
I don't need nine workspaces. If I am working on that many different things it's a sign I should close stuff out. myWorkspaces is included in the kde4Config declaration above. This pattern is lifted from an example xmonad configuration.
haskell source: :noweb-ref myWorkspacesmyWorkspaces = ["front", "im", "music", "misc1", "misc2", "fullscreen"]
myLayoutHook captures Layout Customization
myLayoutHook customizes each of the layouts you can swap between (by default bound to S-SPC)
"main" window with everything tiled to the right
"main" window with everything tiled below
"main" window as full screen
"three column" layout with the main window in the middle
my IM windows are set to "three column" by default
my fullscreen workspace is set to
fullscreenby default.
myLayoutHookhaskell source:myLayoutHook = imw $ fullscr $ tiled ||| Mirror tiled ||| full ||| threeCol where tiled = BW.boringWindows $ smartSpacingWithEdge 4 $ Tall nmaster delta ratio full = BW.boringWindows $ noBorders $ Full threeCol = BW.boringWindows $ smartSpacingWithEdge 4 $ ThreeColMid nmaster delta ratio imw = onWorkspace "im" $ threeCol ||| tiled ||| Mirror tiled ||| full fullscr = onWorkspace "fullscreen" full nmaster = 1 -- Default number of windows in the master pane ratio = 2/3 -- Default proportion of screen occupied by master pane delta = 3/100 -- Percent of screen to increment by when resizing panes
This code block I think was ultimately what I left i3wm for. The "do it yourself" container design made it a real pain in the ass especially when swapping between my 3:2 laptop display and 21:9 widescreen desktop. Now it's just a Super-SPACE away.
I modify my layouts with two modules:
XMonad.Layout.BoringWindows lets a user mark a window as "boring". (lol) that is, it'll still manage, tile, apply rules to the windows, but if you cycle between them with the
focusUpandfocusDowncommands that are provided in the module, the "boring" windows will be skipped. Great for something you want to keep an eye on like a terminal running a log tail while you're working.XMonad.Layout.Spacing provides
smartSpacingWithEdgewhich pushes my windows in a few pixels so that I can differentiate them easier, and so that I can see some of my beautiful art of rally desktop backgrounds 😉
The Boring Window commands are spliced in to additionalKeys above:
haskell source: :noweb-ref additionalKeys, ((myMod, xK_j), BW.focusDown) , ((myMod, xK_k), BW.focusUp) , ((myMod, xK_m), BW.focusMaster) , ((myMod, xK_s), BW.markBoringEverywhere) , ((myMod .|. shiftMask, xK_s), BW.clearBoring)
This relies on these libraries:
haskell source: :noweb-ref importsimport XMonad.Layout.ThreeColumns import qualified XMonad.Layout.BoringWindows as BW import XMonad.Layout.Spacing import XMonad.Layout.NoBorders import XMonad.Layout.PerWorkspace
myManageHook provides rules that apply to windows when they are opened
This does a fair bit at once, and is based on some examples taken out of the xmonad docs. Seriously go read them and do your best to make sense of all these new and interesting operators. I'm sorry about all the Haskell and all the line-noise operators, I really am. I don't understand them either, they're mostly lifted from folks who took too many math courses at Uni.
haskell source:myFloats = ["pinentry", "ksmserver-logout-greeter", "krunner"] myTitleFloats = [] prodApps = ["firefox", "emacs"] commApps = ["discord", "Signal", "Element", "telegram-desktop"] mediaApps = ["cantata"] myManageHook = composeAll . concat $ [ [ className =? c --> doFloat | c <- myFloats] , [ title =? t --> doFloat | t <- myTitleFloats] , [ className =? c --> doF (W.shift "1") | c <- prodApps] , [ className =? c --> doF (W.shift "2") | c <- commApps] , [ className =? c --> doF (W.shift "3") | c <- mediaApps] , [ className =? "plasmashell" <&&> checkSkipTaskbar --> doIgnore] -- (ref:checkSkips) , [ className =? "plasmashell" <&&> checkIsDesktop --> doIgnore] ]
myFloatsandmyTitleFloatsdefine window classes and titles which will be floated above the tiling layout. So things like my pass master password dialog (provided byGPGpinentry), the KDE logout screen... this is not so confusing.prodApps,commApps, andmediaAppsare classes of windows which will be stuffed in to workspaces for productivity, communication, and media. workspaces 4-9 are basically overflow areas and places to stuff my "do-nothing" Firefox window.the two rules in (checkSkips) are used to signal to
XMonadto not manage the Plasma desktop elements. These should be included in the defaultkde4ConfigIMO but alas it seems like most of the folks who runXMonadswap out forXMobar...
haskell source: :noweb-ref importsimport qualified XMonad.StackSet as W import XMonad.Hooks.ManageHelpers (isInProperty)
These are the (checkSkips) helpers..:
haskell source:checkSkipTaskbar :: Query Bool checkSkipTaskbar = isInProperty "_NET_WM_STATE" "_NET_WM_STATE_SKIP_TASKBAR" checkIsDesktop :: Query Bool checkIsDesktop = isInProperty "_NET_WM_WINDOW_TYPE" "_NET_WM_WINDOW_TYPE_DESKTOP"
home-manager configuration
#+ARROYO_HOME_MODULE: hm/xmonad.nix #+ARROYO_SYSTEM_ROLE: endpoint
nix source: :tangle ~/arroyo-nix/hm/xmonad.nix :noweb yes{ pkgs, config, ... }: rec { home.sessionVariables = { KDEWM="${pkgs.xmonad-with-packages}/bin/xmonad"; }; xsession.windowManager.xmonad = { enable = true; enableContribAndExtras = true; config = ../files/xmonad.hs; }; # <<plasma-xmonad>> }
XMonad Auto Start on KDE >= 5.25
After KDE 5.25, Plasma now uses roam:SystemD to start up the desktop. This means that KDEWM is ignored roam:because reasons . Well. Here's a work around. "just write a user unit and do a bunch of BS"
nix source: :noweb-ref plasma-xmonadsystemd.user.services.plasma-xmonad = { Install.WantedBy = ["plasma-plasmashell.service"]; Unit.Description = "Start XMonad instead of KWin"; Unit.Before = "plasma-plasmashell.service"; Service.ExecStart = "${config.home.homeDirectory}/.xmonad/xmonad-${pkgs.stdenv.hostPlatform.system}"; Service.Slice="session.slice"; Service.Restart="on-failure"; }; home.activation.plasma-xmonad = '' # systemctl --user mask plasma-kwin_x11.service # systemctl --user daemon-reload # back to kwin ... systemctl --user unmask plasma-kwin_x11.service systemctl --user disable plasma-xmonad.service '';
Thinking about this Thread from roam:Geoffrey Litt ....
Along these lines, one of my favorite findings in malleable software research:
Wendy Mackay found in 1991 that a very common reason people customized their Unix setups was to keep things the way they used to be
Kinda ironic, right?