complete-computing-environment/xmonad.org

259 lines
13 KiB
Org Mode

:PROPERTIES:
:ID: 20220421T100313.402598
:ROAM_ALIASES: "xmonad additionalKeys" XMonad
:END:
#+title: Trying out XMonad in Home Manager
#+FILETAGS: :CCE:
#+AUTO_TANGLE: t
#+ARCOLOGY_KEY: cce/xmonad
#+ARCOLOGY_ALLOW_CRAWL: t
I haven't been particularly pleased with [[id:20211206T133651.674012][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.
* Minimal Haskell support in Emacs
#+ARROYO_EMACS_MODULE: haskell
Of course this will be included in [[id:arroyo/emacs][Arroyo Emacs]] to make developing this configuration viable.
#+begin_src emacs-lisp :tangle cce/haskell.el
(use-package haskell-mode)
(provide 'cce/haskell)
#+end_src
* =xomand.hs= configuration file
Because [[id:cce/kde_is_a_base_for_my_emacs_desktop][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 [[https://wiki.haskell.org/Xmonad/Using_xmonad_in_KDE][integration]] to configure it to manage the Plasma windows and whatnot reasonably.
#+begin_src haskell :tangle ~/arroyo-nix/files/xmonad.hs :noweb yes -r
import 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>>
#+end_src
de-tangling this a bit is probably a fool's errand, but here we go...
[[https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Doc-Configuring.html][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 [[roam:Sir, This is a Wendy's][Sir, This is a Wendy's]]. So all this is broadly defined in [[https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Config-Kde.html][XMonad.Config.Kde]] and [[https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Config-Desktop.htmle][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:
#+begin_src haskell :noweb-ref kde4ConfigDecl
, focusedBorderColor = "#ebbe7b"
, normalBorderColor = "#707231"
, borderWidth = 4
#+end_src
** =EZConfig= makes it eazy to define new keybindings
There's not a lot of "there" there [[https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-EZConfig.html#v:additionalKeys][additionalKeys]] is used to add or override keybindings.
#+begin_src haskell :noweb-ref imports
import XMonad.Util.EZConfig (additionalKeys)
import XMonad.Actions.CycleRecentWS (toggleRecentWS)
#+end_src
That's right, we're nesting =noweb= functions!
I have a bunch of little helpers in [[id:20211206T133651.674012][i3wm]] and [[id:20211116T135637.841698][A World Without EXWM]] which I should collate and expand on for example to add my [[id:2e31b385-a003-4369-a136-c6b78c0917e1][org-fc]] function... but anyways, =S-a= opens my agenda, =S-f= opens a new [[id:cce/emacs][Emacs]] frame, =S-g= opens my [[id:Journal][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.
#+begin_src haskell :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'")
#+end_src
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 [[https://wiki.haskell.org/Xmonad/Config_archive/Thomas_ten_Cate's_xmonad.hs][example xmonad configuration]].
#+begin_src haskell :noweb-ref myWorkspaces
myWorkspaces = ["front", "im", "music", "misc1", "misc2", "fullscreen"]
#+end_src
** =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 =fullscreen= by default.
#+NAME: myLayoutHook
#+begin_src haskell
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
#+end_src
This code block I think was ultimately what I left [[id:20211206T133651.674012][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:
#+name: boring-windows
- [[https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-BoringWindows.html][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 =focusUp= and =focusDown= commands 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.
- [[https://hackage.haskell.org/package/xmonad-contrib-0.13/docs/XMonad-Layout-Spacing.html][XMonad.Layout.Spacing]] provides =smartSpacingWithEdge= which pushes my windows in a few pixels so that I can differentiate them easier, and so that I can see some of my beautiful [[id:00c7b86a-6040-4627-9b79-6070b1b94823][art of rally]] desktop backgrounds 😉
The Boring Window commands are spliced in to [[additionalKeys]] above:
#+begin_src haskell :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)
#+end_src
This relies on these libraries:
#+begin_src haskell :noweb-ref imports
import XMonad.Layout.ThreeColumns
import qualified XMonad.Layout.BoringWindows as BW
import XMonad.Layout.Spacing
import XMonad.Layout.NoBorders
import XMonad.Layout.PerWorkspace
#+end_src
** =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.
#+name: myManageHook
#+begin_src haskell -r
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]
]
#+end_src
- =myFloats= and =myTitleFloats= define window classes and titles which will be floated above the tiling layout. So things like my [[id:cce/the_standard_unix_password_manager][pass]] master password dialog (provided by =GPG= pinentry), the [[id:cce/kde_is_a_base_for_my_emacs_desktop][KDE]] logout screen... this is not so confusing.
- =prodApps=, =commApps=, and =mediaApps= are 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" [[id:cce/a_basic_firefox_installation][Firefox]] window.
- the two rules in [[(checkSkips)]] are used to signal to =XMonad= to not manage the Plasma desktop elements. These should be included in the default =kde4Config= IMO but alas it seems like most of the folks who run =XMonad= swap out for =XMobar=...
#+begin_src haskell :noweb-ref imports
import qualified XMonad.StackSet as W
import XMonad.Hooks.ManageHelpers (isInProperty)
#+end_src
These are the [[(checkSkips)]] helpers..:
#+name: helperFns
#+begin_src haskell
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"
#+end_src
* [[id:cce/home-manager][home-manager]] configuration
#+ARROYO_HOME_MODULE: hm/xmonad.nix
#+ARROYO_SYSTEM_ROLE: endpoint
#+begin_src nix :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>>
}
#+end_src
** XMonad Auto Start on KDE >= 5.25
:PROPERTIES:
:ID: 20220820T115138.901480
:ROAM_REFS: https://maxnatt.gitlab.io/posts/kde-plasma-with-i3wm/#kde-525-and-newer
:END:
After KDE 5.25, Plasma now uses [[roam:SystemD]] to start up the desktop. This means that =KDEWM= is ignored [[roam:because reasons]]. Well. [[https://maxnatt.gitlab.io/posts/kde-plasma-with-i3wm/#kde-525-and-newer][Here's]] a work around. "just write a user unit and do a bunch of BS"
#+begin_src nix :noweb-ref plasma-xmonad
systemd.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
'';
#+end_src
Thinking about [[https://twitter.com/geoffreylitt/status/1364646089756934148][this]] [[id:threads][Thread]] from [[roam:Geoffrey Litt]]....
#+begin_quote
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?
#+end_quote