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
130
131
132
133
134
135
|
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)
import XMonad.Layout.MultiColumns (multiCol)
-- 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" ultraWideLayout commonLayout
where ultraWideLayout = threeColMid ||| multiCol [1, 1, 1] 2 (-0.05) (-0.25) ||| commonLayout
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-u", 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-S-s", spawn "toggle-screenkey")
, ("M-q", spawn "notify-send 'Restarting xmonad'" >> spawn restartCmd)
, ("M-S-q", confirm "Are you sure you want to shutdown?" $ io exitSuccess)
-- , ("M1-a", spawn "xdotool type à")
-- , ("M1-e", spawn "xdotool type à")
]
-- 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)
|