import Control.Monad (when) import Data.Map qualified as M import Data.Monoid import Data.Ratio import Graphics.X11.ExtraTypes.XF86 import System.Exit import XMonad import XMonad.Actions.KeyRemap import XMonad.Hooks.EwmhDesktops import XMonad.Hooks.ManageDocks import XMonad.Hooks.StatusBar import XMonad.Hooks.StatusBar.PP import XMonad.Layout.Circle import XMonad.Layout.DraggingVisualizer import XMonad.Layout.Grid import XMonad.Layout.IfMax import XMonad.Layout.Magnifier import XMonad.Layout.Spacing import XMonad.Layout.Tabbed import XMonad.Layout.ThreeColumns import XMonad.Layout.VoidBorders import XMonad.Layout.WindowSwitcherDecoration import XMonad.Prompt import XMonad.Prompt.Layout import XMonad.StackSet qualified as W import XMonad.Actions.NoBorders myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList $ [ ((modm, xK_Return), spawn $ XMonad.terminal conf), ((modm .|. shiftMask, xK_q), kill), -- -- Rotate through the available layout algorithms ((modm, xK_space), sendMessage NextLayout), -- rofiing ((modm, xK_d), spawn "rofi -show drun"), ((modm .|. shiftMask, xK_e), spawn "rofi -show desktopctl -modes desktopctl:desktopctl -show-icons"), ((modm, xK_m), spawn "menu-qalc -- -theme gruvbox-dark"), ((modm, xK_i), spawn "rofimoji --selector-args '-theme gruvbox-dark' -f alchemical_symbols anatolian_hieroglyphs emojis braille_patterns box_drawing chess_symbols emoticons geometric_shapes gothic greek_extended math mathematical_alphanumeric_symbols mathematical_operators miscellaneous_symbols miscellaneous_mathematical_symbols-a miscellaneous_mathematical_symbols-b miscellaneous_symbols_and_arrows miscellaneous_symbols_and_pictographs miscellaneous_technical modi modifier_tone_letters musical_symbols nerd_font number_forms shorthand_format_controls specials variation_selectors vertical_forms -a copy"), -- screenshotting -- TODO: Fix/rewrite window-screenshot ((modm, xK_w), spawn "window-screenshot.nu"), ((modm, xK_s), spawn "flameshot gui -c -p $HOME/Pictures/screenshots"), ((modm, xK_a), spawn "flameshot screen -c -p $HOME/Pictures/screenshots"), ((modm, xK_t), spawn "ocr-screenshot.sh"), ((modm .|. shiftMask, xK_t), spawn "DEVICE=\"MELF0410:00 1FD2:7007\"; if [ $(xinput list-props \"$DEVICE\" | awk '/^\\tDevice Enabled \\([0-9]+\\):\\t[01]/ {print $NF}') = \"1\" ]; then xinput disable \"$DEVICE\"; else xinput enable \"$DEVICE\"; fi"), -- Push window back into tiling ((modm .|. shiftMask, xK_space), withFocused $ windows . W.sink), -- Resize viewed windows to the correct size ((modm, xK_n), refresh), -- Move focus to the next window ((modm, xK_Tab), layoutPrompt def), -- Move focus ((modm, xK_j), windows W.focusDown), ((modm, xK_k), windows W.focusUp), -- Swap the focused window with the next window ((modm .|. shiftMask, xK_j), windows W.swapDown), ((modm .|. shiftMask, xK_k), windows W.swapUp), -- Shrink the master area ((modm, xK_h), sendMessage Shrink), ((modm, xK_l), sendMessage Expand), -- Increment the number of windows in the master area ((modm, xK_comma), sendMessage (IncMasterN 1)), ((modm, xK_period), sendMessage (IncMasterN (-1))), ((modm, xK_b), sendMessage ToggleStruts >> withFocused toggleBorder), -- volume keys -- TODO: other media keys ((0, xF86XK_AudioRaiseVolume), spawn "amixer -D pulse sset Master 10%+"), ((0, xF86XK_AudioLowerVolume), spawn "amixer -D pulse sset Master 10%-"), ((0, xF86XK_AudioMute), spawn "amixer -D pulse sset Master toggle") ] ++ [ ((m .|. modm, k), windows $ f i) | (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9], (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)] ] -- TODO: figure out multi screen stuff, including xinerama -- Mouse bindings: default actions bound to mouse events myMouseBindings (XConfig {XMonad.modMask = modm}) = M.fromList -- mod-button1, Set the window to floating mode and move by dragging [ ( (modm, button1), \w -> do focus w mouseMoveWindow w windows W.shiftMaster ), -- mod-button2, Raise the window to the top of the stack ( (modm, button3), \w -> do focus w mouseResizeWindow w windows W.shiftMaster ) ] ------------------------------------------------------------------------ -- 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. tabCfg = def { activeColor = "#282828", inactiveColor = "#1d2021", urgentColor = "#9d0006", activeBorderColor = "#504945", inactiveBorderColor = "#3c3836", urgentBorderColor = "#cc241d", activeTextColor = "#ebdbb2", inactiveTextColor = "#bdae93", urgentTextColor = "#ebdbb2" } myLayout = avoidStruts $ autoChoose ||| threeCol ||| tiled ||| tabbed shrinkText tabCfg ||| Mirror tiled where -- default tiling algorithm partitions the screen into two panes autoChoose = IfMax 2 tiled $ IfMax 3 tiled_mag $ IfMax 4 Grid threeCol tiled = Tall nmaster delta ratio tiled_mag = magnifiercz' 1.4 tiled threeCol = magnifiercz' 1.6 $ ThreeColMid nmaster delta ratio -- The default number of windows in the master pane nmaster = 1 -- Default proportion of screen occupied by master pane ratio = 1 / 2 -- Percent of screen to increment by when resizing panes delta = 3 / 100 myManageHook = composeAll [ className =? "MPlayer" --> doFloat, className =? "Gimp" --> doFloat, className =? "firefox" --> doShift "browser", className =? "Evolution" --> doShift "comms", className =? "Signal" --> doShift "comms", className =? "SchildiChat" --> doShift "comms", resource =? "desktop_window" --> doIgnore, resource =? "kdesktop" --> doIgnore ] ------------------------------------------------------------------------ -- Event handling -- * EwmhDesktops users should change this to ewmhDesktopsEventHook -- -- Defines a custom handler function for X Events. The function should -- return (All True) if the default handler is to be run afterwards. To -- combine event hooks use mappend or mconcat from Data.Monoid. -- myEventHook = mempty focusChangeHook (FocusChangeEvent {ev_event_type = t, ev_window = window}) = do when (t == focusIn) $ spawn "notify-send 'focusIn'" when (t == focusOut) $ spawn "notify-send 'focusOut'" return $ All True ------------------------------------------------------------------------ -- Status bars and logging -- Perform an arbitrary action on each internal state change or X event. -- See the 'XMonad.Hooks.DynamicLog' extension for examples. -- myLogHook = return () ------------------------------------------------------------------------ -- 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 spawn "pgrep oneko || oneko -tofocus -tora -position +-1+5 -fg palevioletred3 -bg pink -name 'Rose the desktop kitty'" spawn "pgrep volumeicon || volumeicon" spawn "pgrep nm-applet || nm-applet" spawn "pgrep mullvad-gui || mullvad-vpn" spawn "feh --bg-fill ~/Pictures/wallpaper.jpg" ------------------------------------------------------------------------ -- Now run xmonad with all the defaults we set up. -- Run xmonad with the settings you specify. No need to modify this. -- mySB = statusBarProp "polybar" (pure xmobarPP) main = xmonad $ docks $ withSB mySB (ewmh defaults) -- 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 = def { -- simple stuff terminal = "kitty", focusFollowsMouse = False, clickJustFocuses = False, borderWidth = 2, modMask = mod4Mask, workspaces = ["comms", "browser"] ++ map show [3 .. 9], normalBorderColor = "#3c3836", focusedBorderColor = "#504945", -- , clientMask = focusChangeMask .|. XMonad.clientMask -- key bindings keys = myKeys, mouseBindings = myMouseBindings, -- hooks, layouts layoutHook = spacingRaw True (Border 0 0 0 0) True (Border 7 7 7 7) True myLayout, manageHook = myManageHook, handleEventHook = myEventHook, logHook = myLogHook, startupHook = myStartupHook }