1 {-# LANGUAGE GHC2024 #-}
2 {-# OPTIONS_GHC -Wall #-}
3 {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
5 import qualified Data.Char as Char
6 import Data.List as List
7 import Data.Functor ((<&>))
10 import qualified Data.Map as Map
11 import Control.Arrow (first)
13 -- import XMonad.Actions.DwmPromote
14 -- import XMonad.Actions.Warp
15 -- import XMonad.Layout.Maximize
16 -- import XMonad.Layout.Monitor
17 -- import XMonad.Layout.ResizableTile
18 -- import XMonad.Layout.TabBarDecoration
19 -- import XMonad.Util.EZConfig
20 -- import XMonad.Util.EZConfig(additionalKeys)
21 -- import XMonad.Util.WorkspaceCompare
22 import XMonad hiding ((|||))
23 import XMonad.Actions.CopyWindow
24 import XMonad.Actions.CycleWS
25 import XMonad.Actions.SwapWorkspaces
26 import XMonad.Actions.UpdatePointer
27 import XMonad.Config.Azerty
28 import XMonad.Hooks.DynamicLog
29 import XMonad.Hooks.EwmhDesktops
30 import XMonad.Hooks.ManageDocks
31 import XMonad.Hooks.ManageHelpers
32 import XMonad.Hooks.RefocusLast
33 import XMonad.Hooks.Rescreen
34 import XMonad.Hooks.SetWMName
35 import XMonad.Hooks.StatusBar
36 import XMonad.Hooks.UrgencyHook
37 import XMonad.Layout.Columns
38 import XMonad.Layout.Fullscreen
39 import XMonad.Layout.Grid
40 import XMonad.Layout.LayoutCombinators
41 import XMonad.Layout.Magnifier
42 import XMonad.Layout.MultiToggle
43 import XMonad.Layout.MultiToggle.Instances
44 import XMonad.Layout.NoBorders
45 import XMonad.Layout.ResizableTile
46 import XMonad.Layout.Spiral
47 import XMonad.Layout.Tabbed
48 import XMonad.Layout.ThreeColumns
49 import XMonad.Layout.WindowNavigation
50 import XMonad.ManageHook
51 import XMonad.Operations (unGrab)
53 import XMonad.Prompt.FuzzyMatch
54 import XMonad.Prompt.Pass
55 import XMonad.Prompt.Window
56 import XMonad.Util.NamedScratchpad
57 import XMonad.Util.SpawnOnce
58 import qualified XMonad.StackSet as W
61 withUrgencyHook NoUrgencyHook $
62 -- dzenUrgencyHook { args = ["-bg", "darkgreen", "-xs", "1"] } $
63 --addAfterRescreenHook myAfterRescreenHook $
64 addRandrChangeHook (spawnExec "autorandr --change") $
65 dynamicSBs barSpawner $
67 setEwmhActivateHook doAskUrgent $
72 , focusFollowsMouse = True
73 , focusedBorderColor = "#00b10b"
74 , handleEventHook = handleEventHook def
75 , keys = \conf@XConfig{XMonad.modMask} ->
77 let xK_XF86Backward = 0x1008ff26
78 xK_XF86Forward = 0x1008ff27 in
81 ((modMask, xK_Return), spawnExec $ XMonad.terminal conf)
83 , ((modMask, xK_Menu), spawnCommand)
84 , ((modMask, xK_space), spawnCommand)
85 -- Browse the filesystem
86 , ((modMask, xK_BackSpace), spawnExec "systemd-run --user --unit=app-caja@$RANDOM -p CollectMode=inactive-or-failed caja")
89 , ((0, xK_Pause), unGrab >> spawnExec "loginctl lock-session \"$XDG_SESSION_ID\"")
90 , ((modMask, xK_Delete), unGrab >> spawnExec "loginctl lock-session \"$XDG_SESSION_ID\"")
92 -- Take a full screenshot
93 , ((0, xK_Print), spawn "mkdir -p ~/Images/screenshots && scrot --quality 42 ~/Images/screenshots/'%Y-%m-%d_%H-%M-%S.png' && caja ~/Images/screenshots")
94 -- Take a selective screenshot
95 , ((modMask, xK_Print), spawn "select-screenshot")
98 , ((0, 0x1008FF12), spawnExec "pactl -- set-sink-mute @DEFAULT_SINK@ toggle") -- XF88AudioMute
99 , ((0, 0x1008FF11), spawnExec "pactl -- set-sink-volume @DEFAULT_SINK@ -5%") -- XF86AudioLowerVolume
100 , ((0, 0x1008FF13), spawnExec "pactl -- set-sink-volume @DEFAULT_SINK@ +5%") -- XF86AudioRaiseVolume
102 -- , ((0, 0x1008FF16), spawnExec "")
104 -- , ((0, 0x1008FF14), spawnExec "")
106 -- , ((0, 0x1008FF17), spawnExec "")
108 -- , ((0, 0x1008FF2C), spawnExec "eject -T")
110 -- Close focused window.
111 , ((modMask, xK_Escape), kill)
114 , ((modMask, xK_c), spawnExec "clipster --select --primary")
116 -- Temporarily maximize a window
117 , ((modMask, xK_f), sendMessage $ XMonad.Layout.MultiToggle.Toggle FULL)
118 -- , ((modMask, xK_f), withFocused (sendMessage . maximizeRestore))
120 -- Cycle through the available layout algorithms
121 , ((modMask, 0x13bd), sendMessage NextLayout) -- oe (²)
122 , ((modMask, xK_ampersand), sendMessage $ JumpToLayout "ResizableTall") -- & (1)
123 , ((modMask, xK_eacute), sendMessage $ JumpToLayout "Mirror ResizableTall") -- é (2)
124 , ((modMask, xK_quotedbl), sendMessage $ JumpToLayout "Tabbed Simplest") -- ' (3)
125 , ((modMask, xK_apostrophe), sendMessage $ JumpToLayout "Magnifier Grid") -- " (4)
126 , ((modMask, xK_parenleft), sendMessage $ JumpToLayout "Spiral") -- ( (5)
127 , ((modMask, xK_minus), sendMessage $ JumpToLayout "Full") -- - (6)
128 , ((modMask, xK_egrave), sendMessage $ JumpToLayout "ThreeCol") -- è (7)
129 , ((modMask, xK_underscore), sendMessage $ JumpToLayout "Columns") -- _ (8)
131 -- Reset the layouts on the current workspace to default
132 -- , ((modMask .|. shiftMask, xK_space), setLayout $ XMonad.layoutHook conf)
134 -- Resize viewed windows to the correct size.
135 , ((modMask, xK_n), refresh)
137 -- Move focus to the master window
138 , ((modMask .|. shiftMask, xK_exclam), windows W.focusMaster)
139 -- Swap the focused window and the master window
140 , ((modMask, xK_exclam), windows W.swapMaster)
142 -- Swap the focused window with the next window.
143 --, ((modMask, xK_o), windows W.swapDown >> windows W.focusMaster)
144 -- Swap the focused window with the previous window.
145 , ((modMask, xK_m), windows W.swapUp >> windows W.focusMaster)
148 , ((modMask, xK_h), sendMessage $ Go L)
149 , ((modMask, xK_m), sendMessage $ Go R)
150 --, ((modMask, xK_i), sendMessage $ Go U)
151 --, ((modMask, xK_k), sendMessage $ Go D)
152 , ((modMask, xK_i), windows W.focusUp)
153 , ((modMask, xK_k), windows W.focusDown)
154 , ((modMask, xK_j), prevWS)
155 , ((modMask, xK_l), nextWS)
156 , ((modMask, xK_Left), windows W.focusUp)
157 , ((modMask, xK_Right), windows W.focusDown)
158 --, ((modMask, xK_Left), onGroup W.focusUp')
159 --, ((modMask, xK_Right), onGroup W.focusDown')
160 , ((modMask, xK_Up), sendMessage $ Go U)
161 , ((modMask, xK_Down), sendMessage $ Go D)
164 , ((modMask .|. shiftMask, xK_h), sendMessage MoveLeft)
165 , ((modMask .|. shiftMask, xK_m), sendMessage MoveRight)
166 , ((modMask .|. controlMask, xK_h), sendMessage MoveLeft)
167 , ((modMask .|. controlMask, xK_m), sendMessage MoveRight)
168 , ((modMask .|. controlMask, xK_i), sendMessage MoveUp)
169 , ((modMask .|. controlMask, xK_k), sendMessage MoveDown)
170 , ((modMask .|. controlMask, xK_j), shiftToPrev >> prevWS)
171 , ((modMask .|. controlMask, xK_l), shiftToNext >> nextWS)
174 , ((modMask .|. shiftMask, xK_l), sendMessage HorizontalExpand)
175 , ((modMask .|. shiftMask, xK_j), sendMessage HorizontalShrink)
176 , ((modMask .|. shiftMask, xK_i), sendMessage VerticalExpand)
177 , ((modMask .|. shiftMask, xK_k), sendMessage VerticalShrink)
179 -- Push window back into tiling.
180 , ((modMask, xK_t), withFocused $ windows . W.sink)
182 -- Change the number of windows in the master area
183 , ((modMask, xK_Up), sendMessage $ IncMasterN 1)
184 , ((modMask, xK_Down), sendMessage $ IncMasterN (-1))
186 -- Toggle the status bar gap.
187 , ((modMask, xK_b), sendMessage ToggleStruts)
190 , ((modMask .|. shiftMask, xK_End), io exitSuccess)
192 , ((modMask, xK_End), restart "xmonad" True)
194 , ((modMask, xK_p), passPrompt promptConfig)
195 , ((modMask .|. controlMask, xK_p), passGeneratePrompt promptConfig)
196 , ((modMask .|. controlMask .|. shiftMask, xK_p), passRemovePrompt promptConfig)
197 , ((modMask, xK_Tab), windowMultiPrompt promptConfig [(Goto, allWindows), (Goto, wsWindows)])
199 -- Jump to latest viewed workspace
200 , ((modMask, xK_less), toggleWS' ["NSP"])
202 -- Workspace management
203 -- XF86Back: Switch to previous workspace
204 , ((0, xK_XF86Backward), prevWS)
205 , ((modMask, xK_Page_Up), prevWS)
206 -- Switch to next workspace
207 , ((0, xK_XF86Forward), nextWS)
208 , ((modMask, xK_Page_Down), nextWS)
209 -- XF86Back: Move the current client to the previous workspace and go there
210 , ((modMask, xK_XF86Backward), shiftToPrev >> prevWS)
211 -- Move the current client to the next workspace and go there
212 , ((modMask, xK_XF86Forward), shiftToNext >> nextWS)
213 -- Switch to previous workspace
214 -- Switch to next workspace
216 -- Move the current client to the previous workspace
217 , ((0 .|. shiftMask , xK_XF86Backward), shiftToPrev )
218 -- Move the current client to the next workspace
219 , ((0 .|. shiftMask , xK_XF86Forward), shiftToNext )
222 -- Toggle copying window on all workspaces (sticky window)
223 , ((modMask, xK_s), do
224 copies <- wsContainingCopies -- NOTE: consider only hidden workspaces
226 [] -> windows copyToAll
227 _ -> killAllOtherCopies
230 -- Resize the master area
231 --, ((modMask, xK_Left), sendMessage Shrink)
232 --, ((modMask, xK_Right), sendMessage Expand)
233 -- Resize windows in ResizableTall mode
234 --, ((modMask .|. shiftMask, xK_Left), sendMessage MirrorShrink)
235 --, ((modMask .|. shiftMask, xK_Right), sendMessage MirrorExpand)
238 -- Dynamic scratchpads
240 [ [ ((modMask .|. altMask .|. controlMask, key), withFocused $ toggleDynamicNSP name)
241 , ((modMask .|. altMask, key), dynamicNSPAction name)
243 | (key, chr) <- zip [xK_a..] ['a'..'z']
249 -- Note: those keybindings override dynamic scratchpads above
250 [ ((modMask .|. altMask, xK_b), namedScratchpadAction scratchpads "btop")
251 , ((modMask .|. altMask, xK_c), namedScratchpadAction scratchpads "中文")
252 , ((modMask .|. altMask, xK_d), namedScratchpadAction scratchpads "dino")
253 , ((modMask .|. altMask, xK_e), namedScratchpadAction scratchpads "english")
254 , ((modMask .|. altMask, xK_h), namedScratchpadAction scratchpads "htop")
255 , ((modMask .|. altMask, xK_m), namedScratchpadAction scratchpads "matrix")
256 , ((modMask .|. altMask, xK_n), namedScratchpadAction scratchpads "notes")
257 , ((modMask .|. altMask, xK_o), namedScratchpadAction scratchpads "concerns")
258 , ((modMask .|. altMask, xK_s), namedScratchpadAction scratchpads "signal")
259 , ((modMask .|. altMask, xK_v), namedScratchpadAction scratchpads "pavucontrol")
260 , ((modMask .|. altMask, xK_u), namedScratchpadAction scratchpads "umpv")
261 , ((modMask .|. altMask, xK_space), namedScratchpadAction scratchpads "terminal")
262 , ((modMask .|. altMask, xK_Return), namedScratchpadAction scratchpads "terminal")
263 , ((modMask .|. altMask, xK_BackSpace), resetFocusedNSP)
266 -- mod-[F1..F9], Switch to workspace N
267 [ ((modMask, k), windows $ W.greedyView i)
268 | (i, k) <- zip (workspaces conf) [xK_F1 ..] ++
269 zip (workspaces conf) [xK_1 ..]
272 -- mod-shift-[F1..F9], Move client to workspace N
273 [ ((modMask .|. shiftMask, k), windows $ W.shift i)
274 | (i, k) <- zip (workspaces conf) [xK_F1 ..] ++
275 zip (workspaces conf) [xK_1 ..]
278 {- NOTE: with Xinerama
279 [((m .|. modMask, k), windows $ onCurrentScreen f i)
280 | (i, k) <- zip (workspaces' conf) [xK_F1 ..]
281 , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)] ]
284 -- mod-{w,e,r}, Switch to physical/Xinerama screens 1, 2, or 3
285 [ ((modMask, key), screenWorkspace sc >>= flip whenJust (windows . W.view))
286 | (key, sc) <- zip [xK_w, xK_e, xK_r] [0 ..]
289 -- mod-shift-{w,e,r}, Move client to screen 1, 2, or 3
290 [ ((modMask .|. shiftMask, key), screenWorkspace sc >>= flip whenJust (windows . W.shift))
291 | (key, sc) <- zip [xK_w, xK_e, xK_r] [0 ..]
294 -- mod-ctrl-[F1..F9], Swap workspace with workspace N
295 -- mod-ctrl-[1..9], Swap workspace with workspace N
296 [ ((modMask .|. controlMask, k), windows $ swapWithCurrent i)
297 | (i, k) <- zip (workspaces conf) [xK_F1 ..] ++
298 zip (workspaces conf) [xK_1 ..]
300 {- NOTE: with Xinerama
301 [((modMask .|. controlMask, k), windows $ onCurrentScreen swapWithCurrent i)
302 | (i, k) <- zip (workspaces' conf) [xK_F1 ..] ]
304 , layoutHook = smartBorders $
305 mkToggle (NOBORDERS ?? FULL ?? EOT) $ -- enable temporarily maximizing a window
306 avoidStruts $ -- prevents windows from overlapping dock windows
307 let tall = ResizableTall 1 (1%200) (8%13) [] in
309 -- addTabs shrinkText tabBar (subLayout [] Simplest (Columns 1 []))
311 ||| tabbed shrinkText tabConfig
314 ||| magnifiercz (13%10) Grid
316 ||| noBorders (fullscreenFull Full)
317 ||| ThreeColMid 1 (1%200) (1%2)
318 -- ||| Tall 1 (3/100) (1/2)
319 , manageHook = composeAll
320 -- [ , isFullscreen --> (doF W.focusDown <+> doFullFloat)
321 [ isFullscreen --> doFullFloat
323 , manageDocks -- NOTE: do not tile dock windows
324 , namedScratchpadManageHook scratchpads
325 , resource =? "desktop_window" --> doIgnore
326 , className =? "Gimp" --> doFloat
327 , resource =? "gpicview" --> doSink
328 , className =? "mpv" --> doFloat
329 , className =? "ultrastardx" --> doSink
330 --, className =? "MPlayer" --> doShift "3:media" -- <+> doFloat
331 --, className =? "vlc" --> doShift "3:media"
332 , className =? "trayer" --> doIgnore
335 , mouseBindings = \XConfig{XMonad.modMask} ->
338 -- mod-button1, Set the window to floating mode and move by dragging
339 ((modMask, button1), floatMoveNoexclusive)
341 -- mod-button2, Raise the window to the top of the stack
342 , ((modMask, button2), \w -> focus w >> windows W.swapMaster)
344 -- mod-button3, Set the window to floating mode and resize by dragging
345 , ((modMask, button3), resizeNoexclusive)
347 , ((modMask, button4), \_ -> windows W.focusUp)
348 , ((modMask, button5), \_ -> windows W.focusDown)
350 -- Cycle through workspaces
351 , ((controlMask .|. modMask, button5), nextNonEmptyWS)
352 , ((controlMask .|. modMask, button4), prevNonEmptyWS)
354 , normalBorderColor = "#7C7C7C"
357 <+> addExclusives [ [ name | NS{name} <- scratchpadsExclusive ] ]
358 <+> spawnExec "wmname XMonad"
359 <+> spawnExec "xrdb -all .Xresources"
360 <+> spawn "sleep 1 && xmodmap .Xmodmap"
361 <+> spawnExec "xset r rate 250 25"
362 <+> spawnExec "xinput --set-button-map 'Logitech USB Receiver Mouse' 1 2 3 4 5 6 7 2"
363 <+> spawnExec "xset b off"
364 <+> spawnExec "xhost local:root"
365 <+> spawnExec "setxkbmap -option keypad:pointerkeys"
366 -- Useful for programs launched by rofi
367 <+> spawnExec (unwords [ "systemctl --user import-environment"
368 , "DBUS_SESSION_BUS_ADDRESS"
369 , "GDK_PIXBUF_MODULE_FILE"
370 , "GIO_EXTRA_MODULES"
378 , "LD_LIBRARY_PATH" -- For sane and pipewire
380 , "NIX_PROFILES" -- fcitx5 does not work without it…
381 , "PASSWORD_STORE_DIR"
383 , "QTWEBKIT_PLUGIN_PATH"
391 -- <+> spawnOnce "exec arbtt-capture -r 60"
392 -- <+> spawnOnce "exec parcellite"
393 -- <+> spawnOnce "exec xautolock"
394 -- <+> spawnOnce "exec redshift-gtk -l -45.7800:1.9700 -t 6500:3700"
395 <+> spawnOnce "exec nm-applet"
396 , terminal = "$TERMINAL"
397 , workspaces = {- withScreens nScreens $ -}
398 {-["1:work","2:web","3:media"] ++-}
399 map show [1::Int .. 9]
401 -- updatePointer (Relative 0.5 0.5)
403 nsHideOnFocusLoss scratchpadsExclusive
404 updatePointer (0.5, 0.5) (0, 0)
408 { activeBorderColor = "#7C7C7C"
409 , activeColor = "#000000"
410 , activeTextColor = "#00FF00"
411 , inactiveBorderColor = "#7C7C7C"
412 , inactiveColor = "#000000"
413 , inactiveTextColor = "#EEEEEE"
414 , fontName = "Hack 7"
417 spawnCommand = spawnExec "rofi -show run -no-disable-history -run-command \"bash -c 'systemd-run --user --unit=app-\\$(systemd-escape \\\"{cmd}\\\")@\\$RANDOM -p CollectMode=inactive-or-failed {cmd}'\""
419 barSpawner :: ScreenId -> X StatusBarConfig
420 barSpawner 0 = pure $ topXmobar <> traySB
421 --barSpawner 1 = pure $ xmobar1
422 barSpawner _ = pure $ topXmobar -- nothing on the rest of the screens
424 -- Display properties of the root window:
425 -- xprop -display $DISPLAY -root
426 topXmobar = statusBarPropTo "_XMONAD_XMOBAR0" "xmobar -x 0 ~/.config/xmonad/xmobar0.hs" (pure topPP)
430 { ppCurrent = xmobarColor "black" "#CCCCCC"
431 , ppHidden = xmobarColor "#CCCCCC" "black"
432 , ppHiddenNoWindows = xmobarColor "#606060" "black"
433 , ppLayout = \s -> xmobarColor "black" "#606060" $
436 "ResizableTall" -> " | "
437 "Mirror ResizableTall" -> " - "
438 "Tabbed Simplest" -> " + "
439 "Magnifier Grid" -> " ~ "
445 , ppTitle = xmobarColor "white" "black" . shorten 50
446 , ppUrgent = xmobarColor "yellow" "black"
450 traySB :: StatusBarConfig
457 , "--distancefrom top,right"
461 , "--monitor primary"
464 , "--transparent true"
465 , "--widthtype request"
471 nextNonEmptyWS _ = moveTo Next (WSIs ((not .) <$> isWindowSpaceVisible))
472 prevNonEmptyWS _ = moveTo Prev (WSIs ((not .) <$> isWindowSpaceVisible))
474 isWindowSpaceVisible :: X (WindowSpace -> Bool)
475 isWindowSpaceVisible = do
476 vs <- gets (map (W.tag . W.workspace) . W.visible . windowset)
477 return (\w -> W.tag w `elem` vs)
479 spawnExec s = spawn $ List.unwords $ [ "exec" ] <> systemdCat <> [ s ]
480 systemdCat = [ "systemd-cat" , "--priority=info", "--stderr-priority=warning", "--level-prefix=false" , "--" ]
482 promptConfig :: XPConfig
484 { font = "xft:monospace-"<>show fontSize
488 , fgHLight = "#000000"
489 , borderColor = "darkgreen"
490 , promptBorderWidth = 1
491 , promptKeymap = promptKeyMap
492 , position = CenteredAt { xpCenterY = 0.3, xpWidth = 0.5 }
493 , height = fontSize + 11
497 , autoComplete = Nothing -- Just 500000 -- nanoseconds
498 , showCompletionOnTab = False
499 , completionKey = (0, xK_Down)
500 , prevCompletionKey = (0, xK_Up)
501 , searchPredicate = fuzzyMatch -- isPrefixOf
503 , defaultPrompter = const ""
504 , alwaysHighlight = True
505 , maxComplRows = Just 10
506 , maxComplColumns = Just 1
507 , changeModeKey = xK_twosuperior
512 promptKeyMap :: Map.Map (KeyMask,KeySym) (XP ())
513 promptKeyMap = Map.fromList $
514 List.map (first $ (,) controlMask) -- control + <key>
515 [ (xK_z, killBefore) -- kill line backwards
516 , (xK_k, killAfter) -- kill line forwards
517 , (xK_u, killBefore) -- kill line backwards
518 , (xK_a, startOfLine) -- move to the beginning of the line
519 , (xK_e, endOfLine) -- move to the end of the line
520 , (xK_m, deleteString Next) -- delete a character forward
521 , (xK_b, moveCursor Prev) -- move cursor forward
522 , (xK_f, moveCursor Next) -- move cursor backward
523 , (xK_BackSpace, killWord Prev) -- kill the previous word
524 , (xK_y, pasteString) -- paste a string
525 , (xK_g, quit) -- quit out of prompt
526 , (xK_bracketleft, quit)
529 List.map (first $ (,) altMask) -- meta key + <key>
530 [ (xK_BackSpace, killWord Prev) -- kill the prev word
531 , (xK_f, moveWord Next) -- move a word forward
532 , (xK_b, moveWord Prev) -- move a word backward
533 , (xK_d, killWord Next) -- kill the next word
534 , (xK_n, moveHistory W.focusUp') -- move up through history
535 , (xK_p, moveHistory W.focusDown') -- move down through history
538 List.map (first $ (,) 0) -- <key>
539 [ (xK_Return, setSuccess True >> setDone True)
540 , (xK_KP_Enter, setSuccess True >> setDone True)
541 , (xK_BackSpace, deleteString Prev)
542 , (xK_Delete, deleteString Next)
543 , (xK_Left, moveCursor Prev)
544 , (xK_Right, moveCursor Next)
545 , (xK_Home, startOfLine)
546 , (xK_End, endOfLine)
547 , (xK_Down, moveHistory W.focusUp')
548 , (xK_Up, moveHistory W.focusDown')
555 -- HowTo(develop): use xprop to see window properties to query them
557 scratchpadsExclusive <>
560 scratchpadsExclusive =
561 [ NS { name = "btop", cmd = "$TERMINAL --title=btop -e btop", query = title =? "btop", hook }
562 , NS { name = "concerns", cmd = "$TERMINAL --title=concerns -e sh -c 'cd $HOME/work/sourcephile && vi Concerns.md'", query = title =? "concerns", hook }
563 , NS { name = "dino", cmd = "dino", query = className =? "dino", hook }
564 , NS { name = "english", cmd = "$TERMINAL --title=english -e sh -c 'cd $HOME/files/notes/english && vi vocabulary.org'", query = title =? "english", hook }
565 , NS { name = "htop", cmd = "$TERMINAL --title=htop -e htop", query = title =? "htop", hook }
566 , NS { name = "matrix", cmd = "element-desktop", query = className =? "Element", hook }
567 , NS { name = "notes", cmd = "$TERMINAL --title=notes -e sh -c 'cd $HOME/files/notes && vi notes.md'", query = title =? "notes", hook }
568 , NS { name = "pavucontrol", cmd = "pavucontrol", query = className =? "pavucontrol", hook }
569 , NS { name = "signal", cmd = "signal-desktop", query = className =? "Signal", hook }
570 , NS { name = "terminal", cmd = "$TERMINAL --title=scratch-term", query = title =? "scratch-term", hook }
571 , NS { name = "中文", cmd = "$TERMINAL --title=中文 -e sh -c 'cd $HOME/files/notes/中文 && vi Vocabulary.hs'", query = title =? "中文", hook }
576 [ "sh -c 'exec systemd-run --user"
577 , " -p CollectMode=inactive-or-failed"
578 , " --unit=app-" <> cmd ns
583 where hook = customFloating (W.RationalRect (1/2) (0) (1/2) (1))
585 scratchpadsInclusive =
586 [ NS { name = "umpv", cmd = "umpv", query = className =? "mpv", hook }
588 where hook = customFloating (W.RationalRect (0) (0) (0) (0))