content: -- https://brianbuccola.com/how-to-install-xmonad-and-xmobar-via-stack/
  import System.IO
  import System.Exit
  
  -- import qualified Data.List as L
  -- import Data.Char (isSpace, toUpper)
  
  import XMonad
  -- import XMonad.Config.Xfce
  import XMonad.Actions.Navigation2D
  import XMonad.Actions.UpdatePointer
  import XMonad.Actions.Submap
  import XMonad.Actions.SpawnOn
  -- import qualified XMonad.Actions.Search as S
  
  import XMonad.Hooks.DynamicLog
  import XMonad.Hooks.ManageDocks
  import XMonad.Hooks.ManageHelpers
  import XMonad.Hooks.SetWMName
  import XMonad.Hooks.EwmhDesktops (ewmh)
  
  import XMonad.Layout.Gaps
  import XMonad.Layout.Fullscreen
  import XMonad.Layout.BinarySpacePartition as BSP
  import XMonad.Layout.NoBorders
  import XMonad.Layout.Tabbed
  -- import XMonad.Layout.ThreeColumns
  import XMonad.Layout.Spacing
  import XMonad.Layout.MultiToggle
  import XMonad.Layout.MultiToggle.Instances
  import XMonad.Layout.NoFrillsDecoration
  import XMonad.Layout.Renamed
  import XMonad.Layout.Simplest
  import XMonad.Layout.SubLayouts
  import XMonad.Layout.WindowNavigation
  import XMonad.Prompt
  import XMonad.Prompt.Input
  import XMonad.Config.Kde
  
  -- import XMonad.Layout.ZoomRow
  
  -- import Control.Arrow (first)
  
  import XMonad.Util.Run (spawnPipe)
  -- import XMonad.Util.EZConfig(additionalKeys)
  import XMonad.Util.Cursor
  
  import Graphics.X11.ExtraTypes.XF86
  import qualified XMonad.StackSet as W
  import qualified Data.Map        as M
  
  -- Defaults
  myTerminal = "kitty"
  myTodoList = "dela list '/home/a8ka/Dev/@A/notes/*.md' --format='- [$status] $title $tags' | rofi -dmenu -theme minimal"
  -- myScreensaver = "xscreensaver-command -activate"
  mySelectScreenshot = "xfce4-screenshooter -cr"
  myFinder = "kitty --class FZFFinder --directory ~ zsh -c 'source ~/.zshrc; ~/.bin/finder; sleep 0.5'"
  myLauncher = "rofi -show combi -theme minimal"
  mySearch = "rofi -show search -theme minimal"
  myCalc = "rofi -show calc -theme minimal"
  -- myBookmarks = "buku_run"
  
  
  ------------------------------------------------------------------------
  -- Workspaces
  myWorkspaces = map show [1..9]
  
  -- Window rules:
  -- Center Float Apps:
  myCenterFloatClassNames = [
      "1Password"
    , "Nitrogen"
    , "pamac-manager"
    , "Pavucontrol"
    , "pritunl"
    , "Slack"
    , "Spotify"
    , "Steam"
    , "TelegramDesktop"
    , "Todoist"
    , "Ulauncher"
    , "Xfce4-appfinder"
    , "Xfce4-power-manager-settings"
    , "Xscreensaver-demo"
    , "zoom"
    , "Blueman-manager"
    , "Newsboat"
    , "Oilbuku"
    , "FZFFinder"
    , "Blueberry.py"
    ]
  
  myCenterFloatTitles = [
      "CMUS"
    , "Picture-in-Picture"
    , "Picture in picture"
    ]
  
  -- Apps bound to a specific workspace:
  myWorkspaceAttachedApps = [
      ("1", "firefox")
    , ("4", "obsidian")
    , ("4", "Todoist")
    ]
  
  myManageHook = composeAll . concat $
    [
      [ resource =? "desktop_window" --> doIgnore ]
    , [ className =? c --> doCenterFloat | c <- myCenterFloatClassNames ]
    , [ title =? c --> doCenterFloat | c <- myCenterFloatTitles ]
    , [ className =? (snd t) --> doShift (fst t) | t <- myWorkspaceAttachedApps ]
    , [ isFullscreen --> (doF W.focusDown <+> doFullFloat) ]
    ]
  
  
  ---------------------------------------------------------
  
  ------------------------------------------------------------------------
  -- Layouts
  -- You can specify and transform your layouts by modifying these values.
  -- If you change layout bindings be sure to use 'mod-shift-space' after
  -- restarting (with 'mod-q') to reset your layout state to the new
  -- defaults, as xmonad preserves your old layout settings by default.
  --
  -- The available layouts.  Note that each layout is separated by |||,
  -- which denotes layout choice.
  
  myGaps       = gaps [(U, 10), (R, 10), (L, 10), (D, 10)]
  addSpace     = renamed [CutWordsLeft 2] . spacing gap
  tab          =  avoidStruts
                 $ renamed [Replace "Tabbed"]
                 $ addTopBar
                 $ myGaps
                 $ tabbed shrinkText myTabTheme
  
  layouts      = avoidStruts (
                  (
                      renamed [CutWordsLeft 1]
                    $ addTopBar
                    $ windowNavigation
                    $ renamed [Replace "BSP"]
                    $ addTabs shrinkText myTabTheme
                    $ subLayout [] Simplest
                    $ myGaps
                    $ addSpace (BSP.emptyBSP)
                  )
                  ||| tab
                 )
  
  myLayout    = smartBorders
                $ mkToggle (NOBORDERS ?? FULL ?? EOT)
                $ layouts
  
  myNav2DConf = def
      { defaultTiledNavigation    = centerNavigation
      , floatNavigation           = centerNavigation
      , screenNavigation          = lineNavigation
      , layoutNavigation          = [("Full",          centerNavigation)]
      , unmappedWindowRect        = [("Full", singleWindowRect)]
      }
  
  
  ------------------------------------------------------------------------
  -- Colors and borders
  
  -- Color of current window title in xmobar.
  xmobarTitleColor = "#C678DD"
  
  -- Color of current workspace in xmobar.
  xmobarCurrentWorkspaceColor = "#51AFEF"
  
  -- Width of the window border in pixels.
  myBorderWidth = 0
  
  myNormalBorderColor     = "#000000"
  myFocusedBorderColor    = active
  
  base03  = "#002b36"
  base02  = "#073642"
  base01  = "#586e75"
  base00  = "#657b83"
  base0   = "#839496"
  base1   = "#93a1a1"
  base2   = "#eee8d5"
  base3   = "#fdf6e3"
  yellow  = "#b58900"
  orange  = "#cb4b16"
  red     = "#dc322f"
  magenta = "#d33682"
  violet  = "#6c71c4"
  blue    = "#268bd2"
  cyan    = "#2aa198"
  green   = "#859900"
  
  -- sizes
  gap         = 10
  topbar      = 10
  border      = 0
  prompt      = 20
  status      = 20
  
  active      = blue
  activeWarn  = red
  inactive    = base02
  focusColor  = blue
  unfocusColor = base02
  
  myFont = "xft:Iosevka Nerd Font:size=14:antialias=true"
  mySmallFont = "xft:Iosevka Nerd Font:size=10:antialias=true"
  myBigFont = "xft:Iosevka Nerd Font:size=16:bold:antialias=true"
  myWideFont  = "xft:Iosevka Nerd Font:"
              ++ "style=Regular:pixelsize=180:hinting=true"
  
  -- this is a "fake title" used as a highlight bar in lieu of full borders
  -- (I find this a cleaner and less visually intrusive solution)
  topBarTheme = def
      {
        fontName              = myFont
      , inactiveBorderColor   = base03
      , inactiveColor         = base03
      , inactiveTextColor     = base03
      , activeBorderColor     = active
      , activeColor           = active
      , activeTextColor       = active
      , urgentBorderColor     = red
      , urgentTextColor       = yellow
      , decoHeight            = topbar
      }
  
  addTopBar =  noFrillsDeco shrinkText topBarTheme
  
  myTabTheme = def
      { fontName              = myFont
      , activeColor           = active
      , inactiveColor         = base02
      , activeBorderColor     = active
      , inactiveBorderColor   = base02
      , activeTextColor       = base03
      , inactiveTextColor     = base00
      }
  
  ------------------------------------------------------------------------
  -- Key bindings
  --
  -- modMask lets you specify which modkey you want to use. The default
  -- is mod1Mask ("left alt").  You may also consider using mod3Mask
  -- ("right alt"), which does not conflict with emacs keybindings. The
  -- "windows key" is usually mod4Mask.
  --
  winMask = mod4Mask
  altMask = mod1Mask
  
  myXPConfig :: XPConfig
  myXPConfig = def { font = mySmallFont,
    height = 80,
    borderColor = active,
    promptBorderWidth = 4,
    position = CenteredAt 0.25 0.5
  
  }
  
  myKeys conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $
    ----------------------------------------------------------------------
    -- Custom key bindings
    --
    -- Start a terminal.  Terminal to start is specified by myTerminal variable.
    [ 
      ((modMask .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf)
    , ((controlMask, xK_space),  inputPrompt myXPConfig " TODO" ?+ \t -> spawnHere ("/home/a8ka/.bin/add-todo " ++ t))
    , ((modMask .|. controlMask, xK_space), spawn myTodoList)
    , ((modMask, xK_o), spawn myFinder)
    , ((modMask, xK_d), spawn myLauncher)
    , ((modMask, xK_s), spawn mySearch)
    , ((modMask .|. shiftMask, xK_s), spawn mySelectScreenshot)
    , ((0, xF86XK_AudioMute), spawn "amixer -q set Master toggle")
    , ((0, xF86XK_AudioLowerVolume), spawn "amixer -q set Master 5%-")
    , ((0, xF86XK_AudioRaiseVolume), spawn "amixer -q set Master 5%+")
    , ((0, 0x1008FF16), spawn "")
    , ((0, 0x1008FF14), spawn "")
    , ((0, 0x1008FF17), spawn "")
  
    -- Bookmarks
    , ((modMask, xK_b), submap . M.fromList $
        [ ((0, xK_s),     spawn "kitty --class Oilbuku zsh -c 'oil; sleep .5'")
        , ((0, xK_t),     spawn "kitty --class Oilbuku zsh -c 'oil -t; sleep .5'")
        , ((0, xK_n),     spawn "kitty --class Oilbuku zsh -c 'oil -T; sleep .5'")
        , ((0, xK_a),     spawn "kitty --class Oilbuku zsh -c 'oil -a; sleep .5'")
        , ((0, xK_d),     spawn "kitty --class Oilbuku zsh -c 'oil -d; sleep .5'")
        ])
  
    , ((modMask .|. shiftMask, xK_c), kill)
    , ((modMask, xK_f), sendMessage $ Toggle FULL)
    , ((modMask, xK_space), sendMessage NextLayout)
    , ((modMask .|. shiftMask, xK_space), setLayout $ XMonad.layoutHook conf)
    , ((modMask, xK_j), windows W.focusDown)
    , ((modMask, xK_k), windows W.focusUp)
    , ((modMask, xK_m), windows W.focusMaster)
    , ((modMask, xK_Return), windows W.swapMaster)
    , ((modMask .|. shiftMask, xK_j), windows W.swapDown)
    , ((modMask .|. shiftMask, xK_k), windows W.swapUp)
    , ((modMask, xK_h), sendMessage Shrink)
    , ((modMask, xK_l), sendMessage Expand)
  
    -- Resize viewed windows to the correct size.
    , ((modMask, xK_n), refresh)
  
    -- Push window back into tiling.
    , ((modMask, xK_t), withFocused $ windows . W.sink)
  
    -- Increment the number of windows in the master area.
    , ((modMask, xK_comma), sendMessage (IncMasterN 1))
  
    -- Decrement the number of windows in the master area.
    , ((modMask, xK_period), sendMessage (IncMasterN (-1)))
  
    -- Quit xmonad.
    , ((modMask .|. shiftMask, xK_o), io (exitWith ExitSuccess))
  
    -- Restart xmonad.
    , ((modMask, xK_q), restart "xmonad" True)
    ]
    ++
  
    -- mod-[1..9], Switch to workspace N
    -- mod-shift-[1..9], Move client to workspace N
    [((m .|. modMask, k), windows $ f i)
        | (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9]
        , (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)]]
  
  
    ++
    -- Bindings for manage sub tabs in layouts please checkout the link below for reference
    -- https://hackage.haskell.org/package/xmonad-contrib-0.13/docs/XMonad-Layout-SubLayouts.html
    [
      -- Tab current focused window with the window to the left
      ((modMask .|. controlMask, xK_h), sendMessage $ pullGroup L)
      -- Tab current focused window with the window to the right
    , ((modMask .|. controlMask, xK_l), sendMessage $ pullGroup R)
      -- Tab current focused window with the window above
    , ((modMask .|. controlMask, xK_k), sendMessage $ pullGroup U)
      -- Tab current focused window with the window below
    , ((modMask .|. controlMask, xK_j), sendMessage $ pullGroup D)
  
    -- Tab all windows in the current workspace with current window as the focus
    , ((modMask .|. controlMask, xK_m), withFocused (sendMessage . MergeAll))
    -- Group the current tabbed windows
    , ((modMask .|. controlMask, xK_u), withFocused (sendMessage . UnMerge))
  
    -- Toggle through tabes from the right
    , ((modMask, xK_Tab), onGroup W.focusDown')
    ]
  
    ++
    -- Some bindings for BinarySpacePartition
    -- https://github.com/benweitzman/BinarySpacePartition
    [
      ((modMask .|. controlMask,               xK_Right ), sendMessage $ ExpandTowards R)
    , ((modMask .|. controlMask .|. shiftMask, xK_Right ), sendMessage $ ShrinkFrom R)
    , ((modMask .|. controlMask,               xK_Left  ), sendMessage $ ExpandTowards L)
    , ((modMask .|. controlMask .|. shiftMask, xK_Left  ), sendMessage $ ShrinkFrom L)
    , ((modMask .|. controlMask,               xK_Down  ), sendMessage $ ExpandTowards D)
    , ((modMask .|. controlMask .|. shiftMask, xK_Down  ), sendMessage $ ShrinkFrom D)
    , ((modMask .|. controlMask,               xK_Up    ), sendMessage $ ExpandTowards U)
    , ((modMask .|. controlMask .|. shiftMask, xK_Up    ), sendMessage $ ShrinkFrom U)
    , ((modMask,                               xK_r     ), sendMessage BSP.Rotate)
    -- , ((modMask,                               xK_s     ), sendMessage BSP.Swap)
    -- , ((modMask,                               xK_n     ), sendMessage BSP.FocusParent)
    -- , ((modMask .|. controlMask,               xK_n     ), sendMessage BSP.SelectNode)
    -- , ((modMask .|. shiftMask,                 xK_n     ), sendMessage BSP.MoveNode)
    ]
  
  ------------------------------------------------------------------------
  -- Mouse bindings
  --
  -- Focus rules
  -- True if your focus should follow your mouse cursor.
  myFocusFollowsMouse :: Bool
  myFocusFollowsMouse = True
  
  myMouseBindings (XConfig {XMonad.modMask = modMask}) = M.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))
  
      -- you may also bind events to the mouse scroll wheel (button4 and button5)
    ]
  
  ------------------------------------------------------------------------
  -- Status bars and logging
  -- Perform an arbitrary action on each internal state change or X event.
  -- See the 'DynamicLog' extension for examples.
  --
  -- To emulate dwm's status bar
  --
  -- > logHook = dynamicLogDzen
  --
  
  
  ------------------------------------------------------------------------
  -- Startup hook
  -- Perform an arbitrary action each time xmonad starts or is restarted
  -- with mod-q.  Used by, e.g., XMonad.Layout.PerWorkspace to initialize
  -- per-workspace layout choices.
  --
  -- By default, do nothing.
  myStartupHook = do
    setWMName "LG3D"
    spawn     "bash ~/.xmonad/run.sh"
    setDefaultCursor xC_left_ptr
  
  
  ------------------------------------------------------------------------
  -- Run xmonad with all the defaults we set up.
  --
  main = do
    xmproc <- spawnPipe "xmobar ~/.xmonad/xmobarrc.hs"
    -- xmproc <- spawnPipe "taffybar"
    xmonad $ docks
           $ withNavigation2DConfig myNav2DConf
           $ additionalNav2DKeys (xK_Up, xK_Left, xK_Down, xK_Right)
                                 [
                                    (mod4Mask,               windowGo  )
                                  , (mod4Mask .|. shiftMask, windowSwap)
                                 ]
                                 False
           $ ewmh
           -- $ pagerHints -- uncomment to use taffybar
           $ defaults {
           logHook = dynamicLogWithPP xmobarPP {
                    ppCurrent = xmobarColor xmobarCurrentWorkspaceColor "" . wrap "[" "]"
                  , ppTitle = xmobarColor xmobarTitleColor "" . shorten 50
                  , ppSep = "   "
                  , ppOutput = hPutStrLn xmproc
           } >> updatePointer (0.75, 0.75) (0.75, 0.75)
        }
  
  ------------------------------------------------------------------------
  -- Combine it all together
  -- A structure containing your configuration settings, overriding
  -- fields in the default config. Any you don't override, will
  -- use the defaults defined in xmonad/XMonad/Config.hs
  --
  -- No need to modify this.
  --
  defaults = kdeConfig{
      -- simple stuff
      terminal           = myTerminal,
      focusFollowsMouse  = myFocusFollowsMouse,
      borderWidth        = myBorderWidth,
      modMask            = winMask,
      workspaces         = myWorkspaces,
      normalBorderColor  = myNormalBorderColor,
      focusedBorderColor = myFocusedBorderColor,
  
      -- key bindings
      keys               = myKeys,
      mouseBindings      = myMouseBindings,
  
      -- hooks, layouts
      layoutHook         = myLayout,
      -- handleEventHook    = E.fullscreenEventHook,
      handleEventHook    = fullscreenEventHook,
      manageHook         = manageDocks <+> manageSpawn <+> myManageHook,
      startupHook        = myStartupHook
  }
  