1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
import Control.Monad
import Data.List
import System.Exit
import XMonad
import XMonad.Config.Desktop (desktopConfig)
import XMonad.ManageHook (composeAll, willFloat, doFloat, doF, className, stringProperty, (-->), (=?), (<+>))
-- Utilities
import XMonad.Util.Dmenu (menuArgs)
import XMonad.Util.EZConfig (additionalKeys, additionalKeysP)
import XMonad.Util.SpawnOnce (spawnOnOnce)
-- Layouts
import XMonad.Layout.NoBorders (noBorders)
import XMonad.Layout.Reflect (reflectHoriz)
import XMonad.Layout.Spacing (Border (..), spacingRaw)
import XMonad.Layout.Grid (Grid (..))
import XMonad.Layout.ThreeColumns (ThreeCol (ThreeColMid))
import XMonad.Layout.CenteredIfSingle (centeredIfSingle)
import XMonad.Layout.OnHost (onHost)
-- Hooks
import XMonad.Hooks.InsertPosition (Focus (..), Position (..),
insertPosition)
import XMonad.Hooks.WindowSwallowing
import XMonad.Hooks.ManageHelpers (isDialog)
import XMonad.StackSet (swapUp)
-- TODO: no weird screen layout
-- put 2 window in master next to each other and the rest in a stack as usual
import XMonad.Layout.LayoutScreens
import XMonad.Layout.TwoPane
myTerminal = "alacritty"
-- xmonad :: XConfig -> IO ()
-- https://hackage.haskell.org/package/xmonad-0.15/docs/XMonad-Core.html#t:XConfig
main = xmonad $ desktopConfig
{ normalBorderColor = "#1c1c1c"
, focusedBorderColor = "#8a8a8a"
, terminal = myTerminal
, layoutHook = layoutHook'
, manageHook = manageHook'
, modMask = mod4Mask -- mod key to super
, borderWidth = 2
, focusFollowsMouse = False -- don't change window based on mouse position (need to click)
, workspaces = ["code", "web"] ++ map show [3..9]
-- , handleEventHook = handleEventHook'
-- , startupHook = startupHook'
} `additionalKeysP` keys'
layoutHook' = spacing' 4 $ onHost "charles-fractal" (threeColMid ||| commonLayout) commonLayout
where commonLayout = reflectHoriz tiledVerticalBigMaster -- main monitor is slighly to the left
||| tiledVerticalBigMaster -- bigger master for code and smaller slave for compiling
||| noBorders Full -- disable borders for fullscreen layout
||| Mirror tiledHorizontalEven -- 50/50 horizontal split
||| Grid
-- ||| layoutScreens 2 (TwoPane 0.5 0.5)
threeColMid = centeredIfSingle (1/2) (95/100) (ThreeColMid 1 (3/100) (1/2))
tiledVerticalBigMaster = Tall 1 (3 / 100) (3 / 5)
tiledHorizontalEven = Tall 1 (3 / 100) (1 / 2)
spacing' x = spacingRaw True (Border x x x x) False (Border x x x x) True
manageHook' = composeAll
[ insertPosition Below Newer -- insert new window at the end of the current layout
, fmap not willFloat --> insertPosition Below Newer
, willFloat --> insertPosition Above Newer -- insert little pop up windows above all the rest
, className =? "Anki" --> doFloat
, className =? "Steam" --> doFloat
, className =? "CustomFloating" --> doFloat
, stringProperty "WM_NAME(UTF8_STRING)" =? "Bitwarden" --> doFloat
-- , className =? "Gimp" --> doFloat
-- , className =? "OBS" --> doFloat
, isDialog --> doF swapUp
]
keys' = [ ("<XF86AudioLowerVolume>", spawn "pulseaudio-ctl down")
, ("<XF86AudioRaiseVolume>", spawn "pulseaudio-ctl up")
, ("<XF86AudioMute>", spawn "pulseaudio-ctl mute")
, ("<XF86AudioMicMute>", spawn "pulseaudio-ctl mute-input")
, ("M--", spawn "pulseaudio-ctl down")
, ("M-=", spawn "pulseaudio-ctl up")
-- , ("M-g", layoutSplitScreen 2 (TwoPane 0.5 0.5))
-- , ("M-f", rescreen)
, ("<XF86MonBrightnessUp>", spawn "backlight-ctl up")
, ("<XF86MonBrightnessDown>", spawn "backlight-ctl down")
, ("<XF86TouchpadToggle>", spawn "touchpad-toggle")
, ("<XF86ScreenSaver>", spawn "i3lock")
, ("M-<Delete>", spawn "i3lock")
, ("M-o", spawn "project-open")
, ("M-p", spawn "rofi -show run")
, ("<XF86Search>", spawn "rofi -show run")
, ("M-s", spawn "rofi -show ssh")
, ("M-s-w", spawn "rofi -show window")
, ("M-i", spawn "insert-special-character")
, ("M-S-i", spawn "insert-special-character copy")
, ("M-S-t", spawn "translate-prompt")
, ("M-a", spawn "screenshot-prompt")
, ("M-S-d", spawn "notify-send -i x-office-calendar \"$(date +\"%H:%M %A %d/%m/%Y %B\")\"")
, ("M-S-b", spawn "battery-notify")
, ("M-q", spawn "notify-send 'Restarting xmonad'" >> spawn restartCmd)
, ("M-S-q", confirm "Are you sure you want to shutdown?" $ io exitSuccess)
]
-- startupHook' :: X ()
-- startupHook' = do
-- spawnOnOnce "code" myTerminal
-- spawnOnOnce "web" "qutebrowser"
confirm :: String -> X () -> X ()
confirm prompt f = do
result <- menuArgs "rofi" ["-dmenu", "-p", prompt] ["yes", "no"]
when (result == "yes") f
restartCmd :: String
restartCmd = intercalate "; " [ "if type xmonad"
, "then xmonad --recompile && xmonad --restart"
, "else xmessage xmonad not in \\$PATH: \"$PATH\""
, "fi"
]
-- handleEventHook' = swallowEventHook (className =? "Alacritty" <||> className =? "Termite") (return True)
|