]> Git — Sourcephile - julm/julm-nix.git/commitdiff
xmonad: fix multiscreen support main
authorJulien Moutinho <julm+julm-nix@sourcephile.fr>
Sat, 4 May 2024 07:00:34 +0000 (09:00 +0200)
committerJulien Moutinho <julm+julm-nix@sourcephile.fr>
Sat, 4 May 2024 17:11:34 +0000 (19:11 +0200)
home-manager/profiles/xmonad.nix
home-manager/profiles/xmonad/xmobar0.hs [moved from home-manager/profiles/xmonad/xmobar.hs with 93% similarity]
home-manager/profiles/xmonad/xmonad.hs

index 6f1c59491dc715e80324663c22562e80f7003f74..a29653a4e6d70135c680fb8e844acc1bb2f05029 100644 (file)
@@ -5,7 +5,7 @@
     ./screen-locker.nix
     ./urxvt.nix
   ];
-  home.file.".xmonad/xmobar.hs".source = xmonad/xmobar.hs;
+  xdg.configFile."xmonad/xmobar0.hs".source = xmonad/xmobar0.hs;
   xsession = {
     enable = true;
     scriptPath = ".hm-xsession";
         haskellPackages.data-default
       ];
       enableContribAndExtras = true;
+      # Develop with:
+      # nix shell --impure --expr 'with import <nixpkgs> {}; haskellPackages.ghcWithPackages (hs: with hs; [ xmonad-contrib data-default ])'
+      # ln -fns $PWD/home-manager/profiles/xmonad/xmonad.hs ~/.xmonad/xmonad.hs
+      # ~/.xmonad/xmonad-x86_64-linux --recompile
       config = xmonad/xmonad.hs;
     };
   };
   home.packages = [
     pkgs.acpilight
+    pkgs.autorandr
     pkgs.ffmpegthumbnailer
     pkgs.gmrun
     pkgs.light
@@ -35,7 +40,8 @@
     #(pkgs.writeShellScriptBin "mate-terminal" ''exec ${pkgs.rxvt-unicode}/bin/urxvtc -hold "$@"'')
     pkgs.rofi
     pkgs.scrot
-    pkgs.stalonetray
+    pkgs.trayer
+    #pkgs.stalonetray
     pkgs.wmname
     pkgs.xmobar
     pkgs.xorg.appres
@@ -43,6 +49,7 @@
     pkgs.xorg.xhost
     pkgs.xorg.xmodmap
     pkgs.xorg.xset
+    #pkgs.xdotool
   ];
   xresources.properties = {
     "Xft.antialias" = true;
similarity index 93%
rename from home-manager/profiles/xmonad/xmobar.hs
rename to home-manager/profiles/xmonad/xmobar0.hs
index f068da7160d3431c0c54123d2fac2c08f3e09a34..335d0e168954be74d9047f175a99e812f82a40ac 100644 (file)
@@ -10,7 +10,7 @@ Config {
   -- , borderColor = "#646464"
   , sepChar = "%"   -- delineator between plugin names and straight text
   , alignSep = "}{"  -- separator between left-right alignment
-  , template = "%StdinReader% }{ %multicpu%   %thermal0%   %memory%   %dynnetwork%   %battery%   %kbd%   %parisTime% "
+  , template = "%_XMONAD_XMOBAR0% }{ %multicpu%   %thermal0%   %memory%   %dynnetwork%   %battery%   %kbd%   %parisTime% "
   , lowerOnStart = True -- send to bottom of window stack on start
   , hideOnStart = False -- start with window unmapped (hidden)
   , allDesktops = True -- show on all desktops
@@ -18,7 +18,7 @@ Config {
   , pickBroadest = False -- choose widest display (multi-monitor)
   , persistent = True -- enable/disable hiding (True = disabled)
   , commands =
-    [ Run StdinReader
+    [ Run XPropertyLog "_XMONAD_XMOBAR0"
     , Run MultiCpu
       [ "--template", "CPU:<autototal>%"
       , "--Low", "50" -- units: %
index 8075a02897c03ac5c0dccf5455f29e8e8a5f4e57..0e7925d79aed09e455366f04d5a4ecfdd72bdf58 100644 (file)
@@ -27,7 +27,9 @@ import XMonad.Hooks.DynamicLog
 import XMonad.Hooks.EwmhDesktops
 import XMonad.Hooks.ManageDocks
 import XMonad.Hooks.ManageHelpers
+import XMonad.Hooks.Rescreen
 import XMonad.Hooks.SetWMName
+import XMonad.Hooks.StatusBar
 import XMonad.Hooks.UrgencyHook
 import XMonad.Layout.Fullscreen
 import XMonad.Layout.Grid
@@ -41,288 +43,251 @@ import XMonad.Layout.ResizableTile
 import XMonad.Layout.Spiral
 import XMonad.Layout.Tabbed
 import XMonad.Layout.ThreeColumns
-import XMonad.Util.Run(spawnPipe)
+import XMonad.Util.Ungrab (unGrab)
+--import XMonad.Operations (unGrab) -- TODO: needs xmonad 0.18
 import XMonad.Util.SpawnOnce
 import qualified XMonad.StackSet as W
 
-myKeys
- conf@XConfig{XMonad.modMask} =
-  Map.fromList $
-  let xK_XF86Backward = 0x1008ff26
-      xK_XF86Forward = 0x1008ff27 in
-  [
-  -- Start a terminal
-    ((modMask, xK_Return), spawn $ XMonad.terminal conf)
-  -- Launch a program
-  , ((modMask, xK_Menu), spawn "exec rofi -show run -no-disable-history -run-command \"bash -c 'systemd-run --user --unit=app-org.rofi.\\$(systemd-escape \\\"{cmd}\\\")@\\$RANDOM -p CollectMode=inactive-or-failed {cmd}'\"")
-  -- Browse the filesystem
-  , ((modMask, xK_BackSpace), spawn "systemd-run --user --unit=app-org.rofi.caja@$RANDOM -p CollectMode=inactive-or-failed caja")
-
-  -- Lock the screen
-  , ((0, xK_Pause), spawn "systemctl --user start xss-lock.service; xset s activate dpms force off")
-
-  -- Take a full screenshot
-  , ((0, xK_Print), spawn "cd ~/img/cap && scrot --quality 42 '%Y-%m-%d_%H-%M-%S.png' && caja ~/img/cap")
-  -- Take a selective screenshot
-  , ((modMask, xK_Print), spawn "select-screenshot")
-
-  -- Volume control
-  , ((0, 0x1008FF12), spawn "pactl -- set-sink-mute @DEFAULT_SINK@ toggle") -- XF88AudioMute
-  , ((0, 0x1008FF11), spawn "pactl -- set-sink-volume @DEFAULT_SINK@ -5%") -- XF86AudioLowerVolume
-  , ((0, 0x1008FF13), spawn "pactl -- set-sink-volume @DEFAULT_SINK@ +5%") -- XF86AudioRaiseVolume
-  -- Audio previous
-  -- , ((0, 0x1008FF16), spawn "")
-  -- Play/pause
-  -- , ((0, 0x1008FF14), spawn "")
-  -- Audio next
-  -- , ((0, 0x1008FF17), spawn "")
-  -- Eject CD tray
-  -- , ((0, 0x1008FF2C), spawn "eject -T")
-
-  -- Close focused window.
-  , ((modMask, xK_Escape), kill)
-  , ((modMask, xK_q), kill)
-
-  -- Clipboard
-  , ((modMask, xK_c), spawn "clipster --select --primary")
-
-  -- Temporarily maximize a window
-  , ((modMask, xK_f), sendMessage $ XMonad.Layout.MultiToggle.Toggle FULL)
-  -- , ((modMask, xK_f), withFocused (sendMessage . maximizeRestore))
-
-  -- Cycle through the available layout algorithms
-  , ((modMask, 0x13bd),        sendMessage NextLayout) -- oe (²)
-  , ((modMask, xK_ampersand),  sendMessage $ JumpToLayout "ResizableTall") -- & (1)
-  , ((modMask, xK_eacute),     sendMessage $ JumpToLayout "Mirror ResizableTall") -- é (2)
-  , ((modMask, xK_quotedbl),   sendMessage $ JumpToLayout "Tabbed Simplest") -- ' (3)
-  , ((modMask, xK_apostrophe), sendMessage $ JumpToLayout "Magnifier Grid") -- " (4)
-  , ((modMask, xK_parenleft),  sendMessage $ JumpToLayout "Spiral") -- ( (5)
-  , ((modMask, xK_minus),      sendMessage $ JumpToLayout "Full") -- - (6)
-  , ((modMask, xK_egrave),     sendMessage $ JumpToLayout "ThreeCol") -- è (7)
-
-  -- Reset the layouts on the current workspace to default
-  -- , ((modMask .|. shiftMask, xK_space), setLayout $ XMonad.layoutHook conf)
-
-  -- Resize viewed windows to the correct size.
-  , ((modMask, xK_n), refresh)
-
-  -- Move focus between windows
-  , ((modMask, xK_Tab), windows W.focusDown)
-  , ((modMask .|. shiftMask, xK_Tab), windows W.focusUp)
-  , ((modMask, xK_i), windows W.focusUp)
-  , ((modMask, xK_k), windows W.focusDown)
-
-  -- Move focus to the master window
-  , ((modMask, xK_m), windows W.focusMaster)
-  -- Swap the focused window and the master window
-  , ((modMask, xK_space), windows W.swapMaster)
-
-  -- Swap the focused window with the next window.
-  --, ((modMask, xK_o), windows W.swapDown >> windows W.focusMaster)
-  -- Swap the focused window with the previous window.
-  , ((modMask, xK_m), windows W.swapUp >> windows W.focusMaster)
-
-  -- Push window back into tiling.
-  , ((modMask, xK_t), withFocused $ windows . W.sink)
-
-  -- Change the number of windows in the master area
-  , ((modMask, xK_Up), sendMessage $ IncMasterN 1)
-  , ((modMask, xK_Down), sendMessage $ IncMasterN (-1))
-
-  -- Toggle the status bar gap.
-  , ((modMask, xK_b), sendMessage ToggleStruts)
-
-  -- Quit xmonad
-  , ((modMask .|. shiftMask, xK_End), io exitSuccess)
-  -- Restart xmonad
-  , ((modMask, xK_End), restart "xmonad" True)
-
-  -- Workspace management
-  -- XF86Back: Switch to previous workspace
-  , ((0, xK_XF86Backward), prevWS)
-  , ((modMask, xK_j), prevWS)
-  -- Switch to next workspace
-  , ((0, xK_XF86Forward), nextWS)
-  , ((modMask, xK_l), nextWS)
-  -- XF86Back: Move the current client to the previous workspace and go there
-  , ((modMask, xK_XF86Backward), shiftToPrev >> prevWS)
-  , ((modMask .|. shiftMask, xK_j), shiftToPrev >> prevWS)
-  -- Move the current client to the next workspace and go there
-  , ((modMask, xK_XF86Forward), shiftToNext >> nextWS)
-  , ((modMask .|. shiftMask, xK_l), shiftToNext >> nextWS)
-  -- Switch to previous workspace
-  -- Switch to next workspace
-  {-
-  -- Move the current client to the previous workspace
-  , ((0 .|. shiftMask   , xK_XF86Backward), shiftToPrev          )
-  -- Move the current client to the next workspace
-  , ((0 .|. shiftMask   , xK_XF86Forward), shiftToNext          )
-  -}
-
-  -- Toggle copying window on all workspaces (sticky window)
-  , ((modMask, xK_s), do
-      copies <- wsContainingCopies -- NOTE: consider only hidden workspaces
-      case copies of
-       [] -> windows copyToAll
-       _  -> killAllOtherCopies
-    )
-
-  -- Resize the master area
-  , ((modMask, xK_Left), sendMessage Shrink)
-  , ((modMask, xK_Right), sendMessage Expand)
-  -- Resize windows in ResizableTall mode
-  , ((modMask .|. shiftMask, xK_Left), sendMessage MirrorShrink)
-  , ((modMask .|. shiftMask, xK_Right), sendMessage MirrorExpand)
-  ] ++
-
-  -- mod-[F1..F9], Switch to workspace N
-  -- mod-shift-[F1..F9], Move client to workspace N
-  [ ((m .|. modMask, k), windows $ f i)
-  | (i, k) <- zip (workspaces conf) [xK_F1 ..] ++
-              zip (workspaces conf) [xK_1 ..]
-  , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]
-  ] ++
-  {- NOTE: with Xinerama
-  [((m .|. modMask, k), windows $ onCurrentScreen f i)
-   | (i, k) <- zip (workspaces' conf) [xK_F1 ..]
-   , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)] ]
-  -}
-
-  -- mod-{w,e,r}, Switch to physical/Xinerama screens 1, 2, or 3
-  -- mod-shift-{w,e,r}, Move client to screen 1, 2, or 3
-  [ ((m .|. modMask, key), screenWorkspace sc >>= flip whenJust (windows . f))
-  | (key, sc) <- zip [xK_w, xK_e, xK_r] [0 ..]
-  , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]
-  ] ++
-
-  -- mod-shift-[F1..F9], Swap workspace with workspace N
-  -- mod-shift-[1..9], Swap workspace with workspace N
-  [ ((modMask .|. controlMask, k), windows $ swapWithCurrent i)
-  | (i, k) <- zip (workspaces conf) [xK_F1 ..] ++
-              zip (workspaces conf) [xK_1 ..]
-  ]
-  {- NOTE: with Xinerama
-  [((modMask .|. controlMask, k), windows $ onCurrentScreen swapWithCurrent i)
-   | (i, k) <- zip (workspaces' conf) [xK_F1 ..] ]
-  -}
-
-
-myMouseBindings
- XConfig{XMonad.modMask} =
-  Map.fromList
-  [
-  -- mod-button1, Set the window to floating mode and move by dragging
-    ((modMask, button1), \w -> focus w >> mouseMoveWindow w)
-
-  -- mod-button2, Raise the window to the top of the stack
-  , ((modMask, button2), \w -> focus w >> windows W.swapMaster)
-
-  -- mod-button3, Set the window to floating mode and resize by dragging
-  , ((modMask, button3), \w -> focus w >> mouseResizeWindow w)
-
-  , ((modMask, button4), \_ -> windows W.focusUp)
-  , ((modMask, button5), \_ -> windows W.focusDown)
-
-  -- Cycle through workspaces
-  , ((controlMask .|. modMask, button5), nextNonEmptyWS)
-  , ((controlMask .|. modMask, button4), prevNonEmptyWS)
-  ]
-  where
-    nextNonEmptyWS _ = moveTo Next (WSIs ((not .) <$> isWindowSpaceVisible))
-    prevNonEmptyWS _ = moveTo Prev (WSIs ((not .) <$> isWindowSpaceVisible))
-
-isWindowSpaceVisible :: X (WindowSpace -> Bool)
-isWindowSpaceVisible = do
-  vs <- gets (map (W.tag . W.workspace) . W.visible . windowset)
-  return (\w -> W.tag w `elem` vs)
-
-defaults xmproc _nScreens = docks $ ewmhFullscreen $ ewmh $
- azertyConfig
-  { borderWidth        = 1
-  , focusFollowsMouse  = True
+main = xmonad $
+  withUrgencyHook NoUrgencyHook $
+  -- dzenUrgencyHook { args = ["-bg", "darkgreen", "-xs", "1"] } $
+  --addAfterRescreenHook myAfterRescreenHook $
+  addRandrChangeHook (spawnExec "autorandr --change") $
+  dynamicSBs barSpawner $
+  docks $
+  setEwmhActivateHook doAskUrgent $
+  ewmhFullscreen $
+  ewmh $
+  azertyConfig
+  { borderWidth = 1
+  , focusFollowsMouse = True
   , focusedBorderColor = "#00b10b"
-  , handleEventHook    = handleEventHook def
-  , keys               = myKeys
-  , layoutHook         = smartBorders $
-                         mkToggle (NOBORDERS ?? FULL ?? EOT) $ -- enable temporarily maximizing a window
-                         avoidStruts $ -- prevents windows from overlapping dock windows
-                         let tall = ResizableTall 1 (1%200) (8%13) [] in
-                         tabbed shrinkText tabConfig
-                         ||| tall
-                         ||| Mirror tall
-                         ||| magnifiercz (13%10) Grid
-                         ||| spiral (6%7)
-                         ||| noBorders (fullscreenFull Full)
-                         ||| ThreeColMid 1 (1%200) (1%2)
-                         -- ||| Tall 1 (3/100) (1/2)
-  , manageHook         = composeAll
-                         -- [ , isFullscreen --> (doF W.focusDown <+> doFullFloat)
-                         [ isFullscreen --> doFullFloat
-                         , manageHook def
-                         , manageDocks -- NOTE: do not tile dock windows
-                         , resource  =? "desktop_window" --> doIgnore
-                         , className =? "Gimp"           --> doFloat
-                         , resource  =? "gpicview"       --> doSink
-                         , className =? "mpv"            --> doFloat
-                         --, className =? "MPlayer"        --> doShift "3:media" -- <+> doFloat
-                         --, className =? "vlc"            --> doShift "3:media"
-                         , className =? "stalonetray"    --> doIgnore
-                         ]
-  , modMask            = mod4Mask
-  , mouseBindings      = myMouseBindings
-  , normalBorderColor  = "#7C7C7C"
-  , startupHook        = setWMName "XMonad"
-                       <+> spawn "wmname XMonad"
-                       <+> spawn "xrdb -all .Xresources"
-                       <+> spawn "sleep 1 && xmodmap .Xmodmap"
-                       <+> spawn "xset r rate 250 25"
-                       <+> spawn "xset b off"
-                       <+> spawn "xhost local:root"
-                       <+> spawn "setxkbmap -option keypad:pointerkeys"
-                       -- Useful for programs launched by rofi
-                       <+> spawnOnce "exec systemctl --user import-environment GNUPGHOME PASSWORD_STORE_DIR PATH"
-                       -- <+> spawnOnce "exec arbtt-capture -r 60"
-                       -- <+> spawnOnce "exec parcellite"
-                       -- <+> spawnOnce "exec xautolock"
-                       -- <+> spawnOnce "exec redshift-gtk -l -45.7800:1.9700 -t 6500:3700"
-                       <+> spawnOnce "exec nm-applet"
-                       <+> spawnOnce (List.unwords
-                                     [ "exec stalonetray"
-                                     , "--background '#000000'"
-                                     , "--geometry 5x1-0+0"
-                                     , "--icon-gravity E"
-                                     , "--icon-size 16"
-                                     , "--kludges force_icons_size"
-                                     , "--max-geometry 0x1+0+0"
-                                     , "--skip-taskbar"
-                                     , "--window-strut none"
-                                     ])
-  , terminal           = "urxvtc"
-  , workspaces         = {- withScreens nScreens $ -}
-                         {-["1:work","2:web","3:media"] ++-}
-                         map show [1::Int .. 9]
-  , logHook =
-   dynamicLogWithPP xmobarPP
-    { ppCurrent = xmobarColor "black" "#CCCCCC"
-    , ppHidden  = xmobarColor "#CCCCCC" "black"
-    , ppHiddenNoWindows = xmobarColor "#606060" "black"
-    , ppLayout  = \s -> xmobarColor "black" "#606060" $
-                   case s of
-                    "ResizableTall"        -> " | "
-                    "Mirror ResizableTall" -> " - "
-                    "Tabbed Simplest"      -> " + "
-                    "Magnifier Grid"       -> " ~ "
-                    "Spiral"               -> " @ "
-                    "Full"                 -> " O "
-                    "ThreeCol"             -> " # "
-                    _                      -> s
-    , ppOutput  = hPutStrLn xmproc
-    , ppSep     = "  "
-    , ppTitle   = xmobarColor "white" "black" . shorten 50
-    , ppUrgent  = xmobarColor "yellow" "black"
-    , ppWsSep   = " "
-    }
-    >> updatePointer (0.5, 0.5) (0, 0)
+  , handleEventHook = handleEventHook def
+  , keys = \conf@XConfig{XMonad.modMask} ->
+      Map.fromList $
+      let xK_XF86Backward = 0x1008ff26
+          xK_XF86Forward = 0x1008ff27 in
+      [
+      -- Start a terminal
+        ((modMask, xK_Return), spawnExec $ XMonad.terminal conf)
+      -- Launch a program
+      , ((modMask, xK_Menu), spawnExec "rofi -show run -no-disable-history -run-command \"bash -c 'systemd-run --user --unit=app-org.rofi.\\$(systemd-escape \\\"{cmd}\\\")@\\$RANDOM -p CollectMode=inactive-or-failed {cmd}'\"")
+      -- Browse the filesystem
+      , ((modMask, xK_BackSpace), spawnExec "systemd-run --user --unit=app-org.rofi.caja@$RANDOM -p CollectMode=inactive-or-failed caja")
+
+      -- Lock the screen
+      , ((0, xK_Pause), unGrab >> spawnExec "loginctl lock-session \"$XDG_SESSION_ID\"")
+
+      -- Take a full screenshot
+      , ((0, xK_Print), spawn "cd ~/img/cap && scrot --quality 42 '%Y-%m-%d_%H-%M-%S.png' && caja ~/img/cap")
+      -- Take a selective screenshot
+      , ((modMask, xK_Print), spawn "select-screenshot")
+
+      -- Volume control
+      , ((0, 0x1008FF12), spawnExec "pactl -- set-sink-mute @DEFAULT_SINK@ toggle") -- XF88AudioMute
+      , ((0, 0x1008FF11), spawnExec "pactl -- set-sink-volume @DEFAULT_SINK@ -5%") -- XF86AudioLowerVolume
+      , ((0, 0x1008FF13), spawnExec "pactl -- set-sink-volume @DEFAULT_SINK@ +5%") -- XF86AudioRaiseVolume
+      -- Audio previous
+      -- , ((0, 0x1008FF16), spawnExec "")
+      -- Play/pause
+      -- , ((0, 0x1008FF14), spawnExec "")
+      -- Audio next
+      -- , ((0, 0x1008FF17), spawnExec "")
+      -- Eject CD tray
+      -- , ((0, 0x1008FF2C), spawnExec "eject -T")
+
+      -- Close focused window.
+      , ((modMask, xK_Escape), kill)
+      , ((modMask, xK_q), kill)
+
+      -- Clipboard
+      , ((modMask, xK_c), spawnExec "clipster --select --primary")
+
+      -- Temporarily maximize a window
+      , ((modMask, xK_f), sendMessage $ XMonad.Layout.MultiToggle.Toggle FULL)
+      -- , ((modMask, xK_f), withFocused (sendMessage . maximizeRestore))
+
+      -- Cycle through the available layout algorithms
+      , ((modMask, 0x13bd),        sendMessage NextLayout) -- oe (²)
+      , ((modMask, xK_ampersand),  sendMessage $ JumpToLayout "ResizableTall") -- & (1)
+      , ((modMask, xK_eacute),     sendMessage $ JumpToLayout "Mirror ResizableTall") -- é (2)
+      , ((modMask, xK_quotedbl),   sendMessage $ JumpToLayout "Tabbed Simplest") -- ' (3)
+      , ((modMask, xK_apostrophe), sendMessage $ JumpToLayout "Magnifier Grid") -- " (4)
+      , ((modMask, xK_parenleft),  sendMessage $ JumpToLayout "Spiral") -- ( (5)
+      , ((modMask, xK_minus),      sendMessage $ JumpToLayout "Full") -- - (6)
+      , ((modMask, xK_egrave),     sendMessage $ JumpToLayout "ThreeCol") -- è (7)
+
+      -- Reset the layouts on the current workspace to default
+      -- , ((modMask .|. shiftMask, xK_space), setLayout $ XMonad.layoutHook conf)
+
+      -- Resize viewed windows to the correct size.
+      , ((modMask, xK_n), refresh)
+
+      -- Move focus between windows
+      , ((modMask, xK_Tab), windows W.focusDown)
+      , ((modMask .|. shiftMask, xK_Tab), windows W.focusUp)
+      , ((modMask, xK_i), windows W.focusUp)
+      , ((modMask, xK_k), windows W.focusDown)
+
+      -- Move focus to the master window
+      , ((modMask, xK_m), windows W.focusMaster)
+      -- Swap the focused window and the master window
+      , ((modMask, xK_space), windows W.swapMaster)
+
+      -- Swap the focused window with the next window.
+      --, ((modMask, xK_o), windows W.swapDown >> windows W.focusMaster)
+      -- Swap the focused window with the previous window.
+      , ((modMask, xK_m), windows W.swapUp >> windows W.focusMaster)
+
+      -- Push window back into tiling.
+      , ((modMask, xK_t), withFocused $ windows . W.sink)
+
+      -- Change the number of windows in the master area
+      , ((modMask, xK_Up), sendMessage $ IncMasterN 1)
+      , ((modMask, xK_Down), sendMessage $ IncMasterN (-1))
+
+      -- Toggle the status bar gap.
+      , ((modMask, xK_b), sendMessage ToggleStruts)
+
+      -- Quit xmonad
+      , ((modMask .|. shiftMask, xK_End), io exitSuccess)
+      -- Restart xmonad
+      , ((modMask, xK_End), restart "xmonad" True)
+
+      -- Workspace management
+      -- XF86Back: Switch to previous workspace
+      , ((0, xK_XF86Backward), prevWS)
+      , ((modMask, xK_j), prevWS)
+      -- Switch to next workspace
+      , ((0, xK_XF86Forward), nextWS)
+      , ((modMask, xK_l), nextWS)
+      -- XF86Back: Move the current client to the previous workspace and go there
+      , ((modMask, xK_XF86Backward), shiftToPrev >> prevWS)
+      , ((modMask .|. shiftMask, xK_j), shiftToPrev >> prevWS)
+      -- Move the current client to the next workspace and go there
+      , ((modMask, xK_XF86Forward), shiftToNext >> nextWS)
+      , ((modMask .|. shiftMask, xK_l), shiftToNext >> nextWS)
+      -- Switch to previous workspace
+      -- Switch to next workspace
+      {-
+      -- Move the current client to the previous workspace
+      , ((0 .|. shiftMask   , xK_XF86Backward), shiftToPrev          )
+      -- Move the current client to the next workspace
+      , ((0 .|. shiftMask   , xK_XF86Forward), shiftToNext          )
+      -}
+
+      -- Toggle copying window on all workspaces (sticky window)
+      , ((modMask, xK_s), do
+          copies <- wsContainingCopies -- NOTE: consider only hidden workspaces
+          case copies of
+           [] -> windows copyToAll
+           _  -> killAllOtherCopies
+        )
+
+      -- Resize the master area
+      , ((modMask, xK_Left), sendMessage Shrink)
+      , ((modMask, xK_Right), sendMessage Expand)
+      -- Resize windows in ResizableTall mode
+      , ((modMask .|. shiftMask, xK_Left), sendMessage MirrorShrink)
+      , ((modMask .|. shiftMask, xK_Right), sendMessage MirrorExpand)
+      ] ++
+
+      -- mod-[F1..F9], Switch to workspace N
+      -- mod-shift-[F1..F9], Move client to workspace N
+      [ ((m .|. modMask, k), windows $ f i)
+      | (i, k) <- zip (workspaces conf) [xK_F1 ..] ++
+                  zip (workspaces conf) [xK_1 ..]
+      , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]
+      ] ++
+      {- NOTE: with Xinerama
+      [((m .|. modMask, k), windows $ onCurrentScreen f i)
+       | (i, k) <- zip (workspaces' conf) [xK_F1 ..]
+       , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)] ]
+      -}
+
+      -- mod-{w,e,r}, Switch to physical/Xinerama screens 1, 2, or 3
+      -- mod-shift-{w,e,r}, Move client to screen 1, 2, or 3
+      [ ((m .|. modMask, key), screenWorkspace sc >>= flip whenJust (windows . f))
+      | (key, sc) <- zip [xK_w, xK_e, xK_r] [0 ..]
+      , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]
+      ] ++
+
+      -- mod-shift-[F1..F9], Swap workspace with workspace N
+      -- mod-shift-[1..9], Swap workspace with workspace N
+      [ ((modMask .|. controlMask, k), windows $ swapWithCurrent i)
+      | (i, k) <- zip (workspaces conf) [xK_F1 ..] ++
+                  zip (workspaces conf) [xK_1 ..]
+      ]
+      {- NOTE: with Xinerama
+      [((modMask .|. controlMask, k), windows $ onCurrentScreen swapWithCurrent i)
+       | (i, k) <- zip (workspaces' conf) [xK_F1 ..] ]
+      -}
+      , layoutHook         = smartBorders $
+                             mkToggle (NOBORDERS ?? FULL ?? EOT) $ -- enable temporarily maximizing a window
+                             avoidStruts $ -- prevents windows from overlapping dock windows
+                             let tall = ResizableTall 1 (1%200) (8%13) [] in
+                             tabbed shrinkText tabConfig
+                             ||| tall
+                             ||| Mirror tall
+                             ||| magnifiercz (13%10) Grid
+                             ||| spiral (6%7)
+                             ||| noBorders (fullscreenFull Full)
+                             ||| ThreeColMid 1 (1%200) (1%2)
+                             -- ||| Tall 1 (3/100) (1/2)
+      , manageHook         = composeAll
+                             -- [ , isFullscreen --> (doF W.focusDown <+> doFullFloat)
+                             [ isFullscreen --> doFullFloat
+                             , manageHook def
+                             , manageDocks -- NOTE: do not tile dock windows
+                             , resource  =? "desktop_window" --> doIgnore
+                             , className =? "Gimp" --> doFloat
+                             , resource  =? "gpicview" --> doSink
+                             , className =? "mpv" --> doFloat
+                             --, className =? "MPlayer" --> doShift "3:media" -- <+> doFloat
+                             --, className =? "vlc" --> doShift "3:media"
+                             , className =? "trayer" --> doIgnore
+                             ]
+  , modMask = mod4Mask
+  , mouseBindings = \XConfig{XMonad.modMask} ->
+      Map.fromList
+      [
+      -- mod-button1, Set the window to floating mode and move by dragging
+        ((modMask, button1), \w -> focus w >> mouseMoveWindow w)
+
+      -- mod-button2, Raise the window to the top of the stack
+      , ((modMask, button2), \w -> focus w >> windows W.swapMaster)
+
+      -- mod-button3, Set the window to floating mode and resize by dragging
+      , ((modMask, button3), \w -> focus w >> mouseResizeWindow w)
+
+      , ((modMask, button4), \_ -> windows W.focusUp)
+      , ((modMask, button5), \_ -> windows W.focusDown)
+
+      -- Cycle through workspaces
+      , ((controlMask .|. modMask, button5), nextNonEmptyWS)
+      , ((controlMask .|. modMask, button4), prevNonEmptyWS)
+      ]
+  , normalBorderColor = "#7C7C7C"
+  , startupHook = setWMName "XMonad"
+      <+> spawnExec "wmname XMonad"
+      <+> spawnExec "xrdb -all .Xresources"
+      <+> spawn "sleep 1 && xmodmap .Xmodmap"
+      <+> spawnExec "xset r rate 250 25"
+      <+> spawnExec "xset b off"
+      <+> spawnExec "xhost local:root"
+      <+> spawnExec "setxkbmap -option keypad:pointerkeys"
+      -- Useful for programs launched by rofi
+      <+> spawnExec "systemctl --user import-environment GNUPGHOME PASSWORD_STORE_DIR PATH"
+      -- <+> spawnOnce "exec arbtt-capture -r 60"
+      -- <+> spawnOnce "exec parcellite"
+      -- <+> spawnOnce "exec xautolock"
+      -- <+> spawnOnce "exec redshift-gtk -l -45.7800:1.9700 -t 6500:3700"
+      <+> spawnOnce "exec nm-applet"
+  , terminal = "urxvtc"
+  , workspaces = {- withScreens nScreens $ -}
+                 {-["1:work","2:web","3:media"] ++-}
+                 map show [1::Int .. 9]
+  , logHook = updatePointer (0.5, 0.5) (0, 0)
     -- >> updatePointer (Relative 0.5 0.5)
   }
   where
@@ -336,12 +301,64 @@ defaults xmproc _nScreens = docks $ ewmhFullscreen $ ewmh $
      , fontName            = "Hack 7"
      }
 
---
--- Run xmonad
---
-main = do
-  nScreens <- countScreens
-  xmproc <- spawnPipe "exec xmobar ~/.xmonad/xmobar.hs"
-  xmonad $
-   withUrgencyHook NoUrgencyHook $ -- dzenUrgencyHook { args = ["-bg", "darkgreen", "-xs", "1"] }
-   defaults xmproc (nScreens::Integer)
+barSpawner :: ScreenId -> IO StatusBarConfig
+barSpawner 0 = pure $ topXmobar <> traySB
+--barSpawner 1 = pure $ xmobar1
+barSpawner _ = pure $ topXmobar -- nothing on the rest of the screens
+
+-- Display properties of the root window:
+-- xprop -display $DISPLAY -root
+topXmobar = statusBarPropTo "_XMONAD_XMOBAR0" "xmobar -x 0 ~/.config/xmonad/xmobar0.hs" (pure topPP)
+  where
+  topPP =
+     xmobarPP
+      { ppCurrent = xmobarColor "black" "#CCCCCC"
+      , ppHidden  = xmobarColor "#CCCCCC" "black"
+      , ppHiddenNoWindows = xmobarColor "#606060" "black"
+      , ppLayout  = \s -> xmobarColor "black" "#606060" $
+                     case s of
+                       "ResizableTall"        -> " | "
+                       "Mirror ResizableTall" -> " - "
+                       "Tabbed Simplest"      -> " + "
+                       "Magnifier Grid"       -> " ~ "
+                       "Spiral"               -> " @ "
+                       "Full"                 -> " O "
+                       "ThreeCol"             -> " # "
+                       _                      -> s
+      , ppSep     = "  "
+      , ppTitle   = xmobarColor "white" "black" . shorten 50
+      , ppUrgent  = xmobarColor "yellow" "black"
+      , ppWsSep   = " "
+      }
+
+traySB :: StatusBarConfig
+traySB =
+  statusBarGeneric
+    ( List.unwords
+        [ "trayer"
+        , "--align right"
+        , "--distance 0,0"
+        , "--distancefrom top,right"
+        , "--edge top"
+        , "--expand true"
+        , "--height 16"
+        , "--monitor primary"
+        , "--tint 0x000000"
+        , "--iconspacing 0"
+        , "--transparent true"
+        , "--widthtype request"
+        , "-l"
+        ]
+    )
+    mempty
+
+nextNonEmptyWS _ = moveTo Next (WSIs ((not .) <$> isWindowSpaceVisible))
+prevNonEmptyWS _ = moveTo Prev (WSIs ((not .) <$> isWindowSpaceVisible))
+
+isWindowSpaceVisible :: X (WindowSpace -> Bool)
+isWindowSpaceVisible = do
+  vs <- gets (map (W.tag . W.workspace) . W.visible . windowset)
+  return (\w -> W.tag w `elem` vs)
+
+spawnExec s = spawn $ List.unwords $ [ "exec" ] <> systemdCat <> [ s ]
+systemdCat = [ "systemd-cat" , "--priority=info", "--stderr-priority=warning", "--level-prefix=false" , "--" ]