XMonad


-- base
import Control.Monad (void)
import System.IO
import System.Exit

-- Hackage
import DBus.Client
import Data.Default
import System.Taffybar.Hooks.PagerHints (pagerHints)
import qualified Data.Map as M

-- Xmonad
import System.Exit
import XMonad
import XMonad.Config.Desktop
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.EwmhDesktops (ewmh)
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers
import XMonad.Hooks.SetWMName
import XMonad.Layout.BinarySpacePartition (emptyBSP)
import XMonad.Layout.Fullscreen
import XMonad.Layout.NoBorders
import XMonad.Layout.ResizableTile (ResizableTall(..))
import XMonad.Layout.Spiral
import XMonad.Layout.Tabbed
import XMonad.Layout.ToggleLayouts (ToggleLayout(..), toggleLayouts)
import XMonad.Prompt
import XMonad.Prompt.ConfirmPrompt
import XMonad.Prompt.Man
import XMonad.Prompt.Pass
import XMonad.Prompt.Shell
import XMonad.Util.EZConfig
import XMonad.Util.Run (spawnPipe)
import qualified XMonad.StackSet as W
import XMonad.Wallpaper

myTerminal = "terminology"

myWorkspaces = ["1:chat","2:web","3:code","4:vm","5:media","6:extra", "7:reading", "8:writing"]


myManageHook = composeAll
    [
      className =? "Pidgin"         --> doShift "1:chat"
    , className =? "Thunderbird"    --> doShift "1:chat"
    , className =? "Chromium"       --> doShift "2:web"
    , className =? "Google-chrome"  --> doShift "2:web"
    , className =? "Emacs"          --> doShift "3:code"
    , className =? "VirtualBox"     --> doShift "4:vm"
    , className =? "Kodi"           --> doShift "5:media"
    , className =? "scribus"        --> doShift "8:writing"
    , className =? "Okular"         --> doShift "7:reading"
    , resource  =? "desktop_window" --> doIgnore
    , className =? "Gimp"           --> doFloat
    , title     =? "pinentry-gtk-2" --> doFloat
    , resource  =? "gpicview"       --> doFloat
    , className =? "MPlayer"        --> doFloat
    , isFullscreen --> (doF W.focusDown <+> doFullFloat)]

myLayout = avoidStruts (
    Tall 1 (3/100) (1/2) |||
    Mirror (Tall 1 (3/100) (1/2)) |||
    tabbed shrinkText tabConfig |||
    Full |||
    spiral (6/7)) |||
    noBorders (fullscreenFull Full) |||
    layoutHook desktopConfig

myNormalBorderColor  = "#7c7c7c"
myFocusedBorderColor = "#ceffac"

tabConfig = def {
    activeBorderColor = "#7c7c7c",
    activeTextColor = "#ceffac",
    activeColor = "#000000",
    inactiveBorderColor = "#7c7c7c",
    inactiveTextColor = "#eeeeee",
    inactiveColor = "#000000"
}

myBorderWidth = 4

myModMask = mod4Mask

xK_XF86AudioMute           = 0x1008FF12
xK_XF86XK_AudioLowerVolume = 0x1008FF11
xK_XF86XK_AudioRaiseVolume = 0x1008FF13
xK_XF86XK_AudioPrev        = 0x1008FF16
xK_XF86XK_AudioNext        = 0x1008FF17
xK_XF86XK_AudioPlay        = 0x1008FF14


-- | Generate action in the X monad to
vol :: String -> X ()
vol = spawn . (++) "amixer -D pulse sset Master "

-- | Mute/unmute within the `X` Monad.
toggleMute :: X ()
toggleMute = vol "toggle"

-- | Raise volume
raiseVolume :: (Integral a, Show a) => a -> X ()
raiseVolume n = vol $ show n ++ "%+"

-- | Lower volume
lowerVolume :: (Integral a, Show a) => a -> X ()
lowerVolume n = vol $ show n ++ "%-"

startUp = do
    spawn "setxkbmap -option ctrl:nocaps"
    spawn "xinput set-prop 'Logitech Trackball' 'libinput Accel Speed' 1"
    spawn "/home/adam/.local/bin/taffybar"
    return ()

myKeys conf@XConfig {XMonad.modMask = modMask} = M.fromList $

  [ ((modMask .|. shiftMask, xK_Return),
     spawn $ XMonad.terminal conf)

   -- Lock the screen using xscreensaver.
  , ((modMask .|. controlMask, xK_l),
     spawn "xscreensaver-command -lock")

  -- Launch dmenu via yeganesh.
  -- Use this to launch programs without a key binding.
  , ((modMask, xK_p),
     spawn "$(/home/adam/.local/bin/yeganesh -x -- -fn '-*-terminus-*-r-normal-*-*-120-*-*-*-*-iso8859-*' -nb '#000000' -nf '#ffffff' -sb '#7c7c7c' -sf '#ceffac')")

  -- Take a screenshot in select mode.
  -- After pressing this key binding, click a window, or draw a rectangle with
  -- the mouse.
  , ((modMask .|. shiftMask, xK_p),
     spawn "select-screenshot")

  -- Take full screenshot in multi-head mode.
  -- That is, take a screenshot of everything you see.
  , ((modMask .|. controlMask .|. shiftMask, xK_p),
     spawn "screenshot")

  -- Lower, raise, mute volume.
  , ((0, xK_XF86XK_AudioLowerVolume), lowerVolume 3)
  , ((0, xK_XF86XK_AudioRaiseVolume), raiseVolume 3)
  , ((0, xK_XF86AudioMute), toggleMute)

  -- Eject CD tray.
  , ((0, 0x1008FF2C),
     spawn "eject -T")

  , ((modMask .|. controlMask , xK_p), passPrompt ((def XPC) { font = "xft:Fira Mono:style=Bold" }))

  --------------------------------------------------------------------
  -- "Standard" xmonad key bindings
  --

  -- Close focused window.
  , ((modMask .|. shiftMask, xK_c),
     kill)

  -- Cycle through the available layout algorithms.
  , ((modMask, xK_space),
     sendMessage NextLayout)

  --  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 to the next window.
  , ((modMask, xK_Tab),
     windows W.focusDown)

  -- Move focus to the next window.
  , ((modMask, xK_j),
     windows W.focusDown)

  -- Move focus to the previous window.
  , ((modMask, xK_k),
     windows W.focusUp  )

  -- Swap the focused window and the master window.
  , ((modMask, xK_Return),
     windows W.swapMaster)

  -- Swap the focused window with the next window.
  , ((modMask .|. shiftMask, xK_j),
     windows W.swapDown  )

  -- Swap the focused window with the previous window.
  , ((modMask .|. shiftMask, xK_k),
     windows W.swapUp    )

  -- Shrink the master area.
  , ((modMask, xK_h),
     sendMessage Shrink)

  -- Expand the master area.
  , ((modMask, xK_l),
     sendMessage Expand)

  -- 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 .|. controlMask, xK_q),
     io exitSuccess)

  -- Restart xmonad.
  , ((modMask .|. shiftMask, xK_q),
     restart "/home/adam/.local/bin/xmonad" True)
  ]
  ++

  -- mod-[1..8], Switch to workspace N
  -- mod-shift-[1..8], Move client to workspace N
  [((m .|. modMask, k), windows $ f i)
      | (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_8]
      , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]


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)
  ]

main :: IO ()
main = do
    client <- connectSession

    setRandomWallpaper ["/void/pictures/wallpapers"]

    xmonad $ desktopConfig {
        -- simple stuff
        terminal           = myTerminal,
        focusFollowsMouse  = True,
        borderWidth        = myBorderWidth,
        modMask            = myModMask,
        workspaces         = myWorkspaces,
        normalBorderColor  = myNormalBorderColor,
        focusedBorderColor = myFocusedBorderColor,

        -- key bindings
        keys               = myKeys,
        mouseBindings      = myMouseBindings,

        -- hooks, layouts
        layoutHook         = smartBorders myLayout,
        manageHook         = myManageHook <+> manageHook desktopConfig,
        startupHook        = setWMName "LG3D" <+> startUp
    }