diff --git a/general/.gitignore b/general/.gitignore index 67ad35e..08dd7ea 100644 --- a/general/.gitignore +++ b/general/.gitignore @@ -12,3 +12,6 @@ .mpd/mpdstate* .ncmpcpp/error.log + +.xmonad/*.hi +.xmonad/*.o diff --git a/general/.xmonad/xmonad.hs b/general/.xmonad/xmonad.hs new file mode 100644 index 0000000..9e8c94f --- /dev/null +++ b/general/.xmonad/xmonad.hs @@ -0,0 +1,411 @@ + +-- ░▀█▀░█▄█░█▀█░█▀█░█▀▄░▀█▀░█▀▀ +-- ░░█░░█░█░█▀▀░█░█░█▀▄░░█░░▀▀█ +-- ░▀▀▀░▀░▀░▀░░░▀▀▀░▀░▀░░▀░░▀▀▀ +-- imports + +import XMonad +-- import Data.Monoid +import System.Exit + +import XMonad.Hooks.ManageDocks +import XMonad.Hooks.DynamicLog (dynamicLogWithPP, wrap, xmobarPP, xmobarColor, shorten, PP(..)) + +import XMonad.ManageHook + +import qualified XMonad.StackSet as W +import qualified Data.Map as M + +import XMonad.Util.Run (spawnPipe, hPutStrLn, runProcessWithInput) +import XMonad.Util.NamedScratchpad +-- import XMonad.Util.SpawnOnce + +import XMonad.Layout.Spacing +import XMonad.Layout.Fullscreen +import XMonad.Layout.NoBorders +import XMonad.Layout.Renamed +import XMonad.Layout.MultiToggle +import XMonad.Layout.MultiToggle.Instances + +import qualified XMonad.Layout.Magnifier as Mag + +import Graphics.X11.ExtraTypes.XF86 + +-- ░█▀▀░█▀█░█░░░█▀█░█▀▄░█▀▀ +-- ░█░░░█░█░█░░░█░█░█▀▄░▀▀█ +-- ░▀▀▀░▀▀▀░▀▀▀░▀▀▀░▀░▀░▀▀▀ +-- colors + +type Color = String + +background = "#272822" +foreground = "#f8f8f2" +red = "#f92672" +green = "#a6e22e" +yellow = "#f4bf75" +blue = "#66d9ef" +magenta = "#ae81ff" +cyan = "#a1efe4" + + +-- ░█▀▀░█▀█░█▀█░█▀▀░▀█▀░█▀▀ +-- ░█░░░█░█░█░█░█▀▀░░█░░█░█ +-- ░▀▀▀░▀▀▀░▀░▀░▀░░░▀▀▀░▀▀▀ +-- config + +type TerminalCommand = String + +myTerminal = "alacritty" +myBrowser = "qutebrowser" +myFileBrowser = "thunar" + +emacsCommand :: TerminalCommand +emacsCommand = "emacs" + +myFocusFollowsMouse :: Bool +myFocusFollowsMouse = False + +myClickJustFocuses :: Bool +myClickJustFocuses = True + +myModMask :: KeyMask +myModMask = mod4Mask + +myWorkspaces :: [WorkspaceId] +myWorkspaces = ["gen","www","emx","dev","slk","6","7","8","9"] + +myNormalBorderColor = "#dddddd" +myFocusedBorderColor = "#ff0000" +myBorderWidth = 4 + +myScratchpads = [ NS "ncmpcpp" spawnNC findNC layoutNC + , NS "terminal" spawnTM findTM layoutTM + , NS "schedule" spawnSC findSC layoutNC + , NS "help" spawnH findH layoutNC ] + where + spawnNC = myTerminal ++ " --title ncmpcppScratchpad -e ncmpcpp" + findNC = title =? "ncmpcppScratchpad" + layoutNC = customFloating $ W.RationalRect l t w h + where + h = 0.9 + w = 0.9 + t = 0.05 + l = 0.05 + + spawnTM = myTerminal ++ " --class instanceClass,floatingTerminal -e tmux new-session -A -s floating" + findTM = className =? "floatingTerminal" + layoutTM = customFloating $ W.RationalRect (1/6) (1/6) (2/3) (2/3) + + spawnSC = "sxiv ~/uni/schedule.png" + findSC = className =? "sxiv" + + spawnH = "echo \"" ++ help ++ "\" | xmessage -file -" + findH = className =? "Xmessage" + +-- ░█░█░█▀▀░█░█░█▀▀ +-- ░█▀▄░█▀▀░░█░░▀▀█ +-- ░▀░▀░▀▀▀░░▀░░▀▀▀ +-- keys + +myKeys :: XConfig Layout -> M.Map (KeyMask, KeySym) (X ()) +myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList $ + [ + ((modm .|. shiftMask, xK_l ), sendMessage NextLayout) + , ((modm .|. shiftMask, xK_space ), setLayout $ XMonad.layoutHook conf) + , ((modm, xK_n ), refresh) + , ((modm, xK_Tab ), windows W.focusDown) + , ((modm, xK_j ), windows W.focusDown) + , ((modm, xK_k ), windows W.focusUp ) + , ((modm, xK_m ), windows W.focusMaster ) + -- , ((modm, xK_Return), windows W.swapMaster) + , ((modm .|. shiftMask, xK_j ), windows W.swapDown ) + , ((modm .|. shiftMask, xK_k ), windows W.swapUp ) + , ((modm, xK_h ), sendMessage Shrink) + , ((modm, xK_l ), sendMessage Expand) + , ((modm, xK_t ), withFocused $ windows . W.sink) + , ((modm , xK_comma ), sendMessage (IncMasterN 1)) + , ((modm , xK_period), sendMessage (IncMasterN (-1))) + -- , ((modm , xK_b ), sendMessage ToggleStruts) + , ((modm .|. shiftMask, xK_q ), io (exitWith ExitSuccess)) + , ((modm , xK_c ), myRestartHook ) + ] + + ++ + + [((m .|. modm, 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 .|. modm, key), screenWorkspace sc >>= flip whenJust (windows . f)) + | (key, sc) <- zip [xK_u, xK_i] [0..] + , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]] + + ++ + + -- TODO: Clean up formatting + + [ + ((modm .|. shiftMask , xK_Return), spawn $ myTerminal ++ " -e tmux") + , ((modm , xK_BackSpace), kill) + , ((modm , xK_s), spawn myBrowser) + , ((modm , xK_f), sendMessage $ Toggle FULL) + , ((modm .|. shiftMask , xK_w), spawn "io.elementary.code -t") + , ((modm , xK_e), spawn emacsCommand) + , ((modm .|. shiftMask , xK_e), spawn myFileBrowser) + , ((modm , xK_r), spawn "rofi -show drun") + , ((modm , xK_p), spawn "mpc toggle") + , ((modm , xK_q), namedScratchpadAction myScratchpads "ncmpcpp") + , ((modm , xK_minus), namedScratchpadAction myScratchpads "schedule") + , ((modm , xK_F7), spawn "amixer set Master 2%-") + , ((modm , xK_F8), spawn "amixer set Master 2%+") + -- , ((modm , xK_c), spawn myTerminal ++ " -e cfile") + , ((modm , xK_n), spawn "fcitx-remote -s fcitx-keyboard-no") + , ((modm , xK_m), spawn "fcitx-remote -s fcitx-keyboard-us") + , ((modm , xK_b), spawn "fcitx-remote -s mozc") + , ((modm , xK_Return), namedScratchpadAction myScratchpads "terminal") + , ((modm .|. shiftMask , xK_Print ), spawn "scrot -s '%Y-%m-%d_$wx$h_scrot.png' -e 'mv $f ~/pictures/screenshots'") + , ((modm , xK_Print ), spawn "scrot '%Y-%m-%d_$wx$h_scrot.png' -e 'mv $f ~/pictures/screenshots'") + , ((0 , xK_Print ), spawn "$HOME/.scripts/git/boomer/boomer") + , ((modm , xK_v ), spawn "rofi -modi lpass:$HOME/.scripts/rofi/lpass//rofi-lpass -show lpass") + + , ((0, xF86XK_AudioRaiseVolume ), spawn "amixer set Master 2%+") + , ((0, xF86XK_AudioLowerVolume ), spawn "amixer set Master 2%-") + , ((0, xF86XK_AudioMute ), spawn "pactl set-sink-mute @DEFAULT_SINK@ toggle") + + , ((0, xF86XK_AudioPlay ), spawn "mpc toggle") + , ((0, xF86XK_AudioPrev ), spawn "mpc prev") + , ((0, xF86XK_AudioNext ), spawn "mpc next") + + , ((0, xF86XK_MonBrightnessUp ), spawn "light -A 5") + , ((0, xF86XK_MonBrightnessDown ), spawn "light -U 5") + + , ((modm .|. shiftMask, xK_slash ), namedScratchpadAction myScratchpads "help") + , ((modm .|. shiftMask, xK_d ), viewDropboxStatus) + ] + + +viewDropboxStatus :: X () +viewDropboxStatus = spawn =<< ((++) "notify-send -t 3000 " . unpack) <$> status + where + status :: X String + status = liftIO $ runProcessWithInput "python" ["$HOME/.scripts/dropbox.py", "status"] "" + + unpack :: String -> String + unpack = wrap "\" " "\"" . unwords . map (wrap " [" "] "). lines + + +------------------------------------------------------------------------ +-- 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 -> focus w >> mouseMoveWindow w + >> windows W.shiftMaster)) + + -- mod-button2, Raise the window to the top of the stack + , ((modm, button2), (\w -> focus w >> windows W.shiftMaster)) + + -- mod-button3, Set the window to floating mode and resize by dragging + , ((modm, button3), (\w -> focus w >> mouseResizeWindow w + >> windows W.shiftMaster)) + + -- you may also bind events to the mouse scroll wheel (button4 and button5) + ] + +-- ░█░░░█▀█░█░█░█▀█░█░█░▀█▀ +-- ░█░░░█▀█░░█░░█░█░█░█░░█░ +-- ░▀▀▀░▀░▀░░▀░░▀▀▀░▀▀▀░░▀░ +-- layout + + +myLayout = + fullscreenFull $ + avoidStruts $ + smartBorders $ + spacingRaw True (Border 0 10 10 10) True (Border 10 10 10 10) True $ + mkToggle (NOBORDERS ?? FULL ?? EOT) $ + tiled ||| + Mag.magnifier tiled ||| + Mirror tiled ||| + Full + + where + -- default tiling algorithm partitions the screen into two panes + tiled = Tall 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 + + +------------------------------------------------------------------------ +-- Window rules: + +-- Execute arbitrary actions and WindowSet manipulations when managing +-- a new window. You can use this to, for example, always float a +-- particular program, or have a client always appear on a particular +-- workspace. +-- +-- To find the property name associated with a program, use +-- > xprop | grep WM_CLASS +-- and click on the client you're interested in. +-- +-- To match on the WM_NAME, you can use 'title' in the same way that +-- 'className' and 'resource' are used below. +-- +myManageHook = composeAll + [ className =? "Gimp" --> doFloat + , className =? "QjackCtl" --> doFloat + , resource =? "desktop_window" --> doIgnore + , resource =? "kdesktop" --> doIgnore + , resource =? "fcitx-config" --> doFloat + ] <+> namedScratchpadManageHook myScratchpads + +------------------------------------------------------------------------ +-- 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 + +------------------------------------------------------------------------ + +-- ░█░█░█▄█░█▀█░█▀▄░█▀█░█▀▄ +-- ░▄▀▄░█░█░█░█░█▀▄░█▀█░█▀▄ +-- ░▀░▀░▀░▀░▀▀▀░▀▀░░▀░▀░▀░▀ +-- xmobar + +-- Perform an arbitrary action on each internal state change or X event. +-- See the 'XMonad.Hooks.DynamicLog' extension for examples. + +windowCount :: X (Maybe String) +windowCount = gets $ Just . show . length . W.integrate' . W.stack . W.workspace . W.current . windowset + +myLogHook xmproc = dynamicLogWithPP $ xmobarPP + { + ppOutput = hPutStrLn xmproc + , ppCurrent = xmobarColor green "" . wrap "[" "]" + , ppVisible = xmobarColor green "" + , ppHidden = xmobarColor blue "" + , ppHiddenNoWindows = xmobarColor yellow "" + , ppTitle = xmobarColor foreground "" . shorten 60 + , ppSep = " | " + , ppUrgent = xmobarColor red "" . wrap "!" "!" + , ppExtras = [windowCount] + , ppOrder = \(ws:l:t:ex) -> [ws,l] ++ ex ++ [t] + } + +------------------------------------------------------------------------ +-- 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. +-- +myStartupHook :: X () +myStartupHook = do + spawn "stalonetray &" + -- spawnOnce "$HOME/.xmonad/xinit.sh" + +myRestartHook :: X () +myRestartHook = do + spawn "killall stalonetray" + spawn "killall xmobar" + spawn "xmonad --recompile" + spawn "xmonad --restart" + +------------------------------------------------------------------------ + +main :: IO () +main = do + xmproc <- spawnPipe "xmobar" + xmonad + $ fullscreenSupport + $ docks def { + -- simple stuff + terminal = myTerminal, + focusFollowsMouse = myFocusFollowsMouse, + clickJustFocuses = myClickJustFocuses, + borderWidth = myBorderWidth, + modMask = myModMask, + workspaces = myWorkspaces, + normalBorderColor = myNormalBorderColor, + focusedBorderColor = myFocusedBorderColor, + + -- key bindings + keys = myKeys, + mouseBindings = myMouseBindings, + + -- hooks, layouts + layoutHook = myLayout, + manageHook = myManageHook, + handleEventHook = myEventHook, + logHook = myLogHook xmproc, + startupHook = myStartupHook + } + +-- TODO: Generate this automatically +help :: String +help = unlines ["The default modifier key is 'alt'. Default keybindings:", + "", + "-- launching and killing programs", + "mod-Shift-Enter Launch xterminal", + "mod-p Launch dmenu", + "mod-Shift-p Launch gmrun", + "mod-Shift-c Close/kill the focused window", + "mod-Space Rotate through the available layout algorithms", + "mod-Shift-Space Reset the layouts on the current workSpace to default", + "mod-n Resize/refresh viewed windows to the correct size", + "", + "-- move focus up or down the window stack", + "mod-Tab Move focus to the next window", + "mod-Shift-Tab Move focus to the previous window", + "mod-j Move focus to the next window", + "mod-k Move focus to the previous window", + "mod-m Move focus to the master window", + "", + "-- modifying the window order", + "mod-Return Swap the focused window and the master window", + "mod-Shift-j Swap the focused window with the next window", + "mod-Shift-k Swap the focused window with the previous window", + "", + "-- resizing the master/slave ratio", + "mod-h Shrink the master area", + "mod-l Expand the master area", + "", + "-- floating layer support", + "mod-t Push window back into tiling; unfloat and re-tile it", + "", + "-- increase or decrease number of windows in the master area", + "mod-comma (mod-,) Increment the number of windows in the master area", + "mod-period (mod-.) Deincrement the number of windows in the master area", + "", + "-- quit, or restart", + "mod-Shift-q Quit xmonad", + "mod-q Restart xmonad", + "mod-[1..9] Switch to workSpace N", + "", + "-- Workspaces & screens", + "mod-Shift-[1..9] Move client to workspace N", + "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", + "", + "-- Mouse bindings: default actions bound to mouse events", + "mod-button1 Set the window to floating mode and move by dragging", + "mod-button2 Raise the window to the top of the stack", + "mod-button3 Set the window to floating mode and resize by dragging"]