-- System import System.IO import XMonad import Control.Monad -- Actions import XMonad.Actions.CycleRecentWS import XMonad.Actions.CycleWS import XMonad.Actions.DwmPromote import XMonad.Actions.DynamicWorkspaces import XMonad.Actions.FloatKeys import XMonad.Actions.FloatSnap import XMonad.Actions.GridSelect import XMonad.Actions.PhysicalScreens import XMonad.Actions.UpdateFocus import XMonad.Actions.WindowMenu -- Config import XMonad.Config.Desktop import XMonad.Config.Kde -- Hooks import XMonad.Hooks.DynamicLog import XMonad.Hooks.EwmhDesktops import XMonad.Hooks.FadeInactive import XMonad.Hooks.ManageDocks import XMonad.Hooks.ManageHelpers import XMonad.Hooks.RefocusLast import XMonad.Hooks.ScreenCorners import XMonad.Hooks.StatusBar import XMonad.Hooks.StatusBar.PP -- Layout import XMonad.Layout import XMonad.Layout.Accordion import XMonad.Layout.BinarySpacePartition import XMonad.Layout.Column import XMonad.Layout.Dishes import XMonad.Layout.DragPane import XMonad.Layout.Grid import XMonad.Layout.IM import XMonad.Layout.IndependentScreens import XMonad.Layout.LayoutCombinators hiding ((|||)) import XMonad.Layout.LayoutModifier import XMonad.Layout.NoBorders ( noBorders, smartBorders ) import XMonad.Layout.PerWorkspace import XMonad.Layout.ResizableTile import XMonad.Layout.SimpleFloat import XMonad.Layout.SimplestFloat import XMonad.Layout.Spacing import XMonad.Layout.Spiral import XMonad.Layout.StackTile import XMonad.Layout.Tabbed import XMonad.Layout.ThreeColumns import XMonad.Layout.TwoPane import XMonad.Layout.WindowNavigation -- Prompt import XMonad.Prompt import XMonad.Prompt.Window import XMonad.Prompt.Workspace import XMonad.Prompt.FuzzyMatch import XMonad.Prompt.RunOrRaise -- Util import XMonad.Util.ClickableWorkspaces import XMonad.Util.Dmenu import XMonad.Util.EZConfig import XMonad.Util.NamedScratchpad import XMonad.Util.NamedWindows (getName) import XMonad.Util.NoTaskbar import XMonad.Util.Paste import XMonad.Util.Run import XMonad.Util.Run(spawnPipe) import XMonad.Util.Themes -- Data import Data.Functor import Data.List (isInfixOf) import Data.Maybe (fromMaybe) import Data.Monoid import Data.Ratio ((%)) import Data.Semigroup import Text.Regex.Posix import qualified Data.Map as M import qualified XMonad.Actions.ConstrainedResize as Sqr import qualified XMonad.StackSet as W -- Define a function to match the window name using regular expressions and extract relevant parts matchesPattern :: String -> Maybe String matchesPattern s = case s =~ "Windows 10 P2V Original Clone [^ ]+ - Oracle VM VirtualBox : ([0-9]+)" of [[_, num]] -> Just num _ -> Nothing -- Manage Hook myManageHook :: ManageHook myManageHook = composeAll [ -- Start doShift className `oneOf` [ "Google-chrome", "claws-mail", "ktorrent" ] --> (doF . W.view <> doShift) "1:net", className `oneOf` [ "URxvt" ] --> (doF . W.view <> doShift) "2:$>_", className `oneOf` [ "VirtualBox Manager" ] --> (doF . W.view <> doShift) "5:vm", className `oneOf` [ "Gimp-2.10", "okular", "Inkscape", "gwenview-NOT" ] --> (doF . W.view <> doShift) "6:gfx", -- Remove NOT to make it function again className `oneOf` [ "mpv", "vlc", "smplayer", "obs" ] --> (doF . W.view <> doShift) "7:media", -- Sort Virtual Machines into separate workspaces className =? "VirtualBox Machine" <&&> title ^? "Windows 10 P2V Original Clone " <&&> title $? " Oracle VM VirtualBox : 1" --> (doF . W.view <> doShift) "8:win-A", className =? "VirtualBox Machine" <&&> title ^? "Windows 10 P2V Original Clone " <&&> title $? " Oracle VM VirtualBox : 2" --> (doF . W.view <> doShift) "8:win-B", name `oneOf` [ "TAILS [Running] - Oracle VM VirtualBox", "Ubuntu BTRFS TEST [Running] - Oracle VM VirtualBox" ] --> (doF . W.view <> doShift) "9:linux", className `oneOf` [ "libreoffice" ] --> (doF . W.view <> doShift) "10:office", className `oneOf` [ "libreoffice", "plasma-discover", "krdc", "systemsettings", "Timeshift-gtk", "GParted", "plasma-systemmonitor", "muon", "partitionmanager", "Gsmartcontrol" ] --> (doF . W.view <> doShift) "11:sys", className `oneOf` [ "discord", "firefox", "KeePassXC" ] --> (doF . W.view <> doShift) "12a:misc 1", className `oneOf` [ -- "Emacs" ] --> (doF . W.view <> doShift) "3:emacs", -- End doShift -- Start doFloat role `oneOf` [ "gimp-toolbox-color-dialog" ] --> doFloat, className `oneOf` [ "plasmashell", "kmix", "krunner", "ksplashqml", "ksplashsimple", "ksplashx", "Plasma", "Plasma-desktop", "kcmshell5" ] --> doFloat, -- End doFloat resource `oneOf` [ "desktop_window", "kdesktop" ] --> doIgnore, name `oneOf` [ "Diablo II", "Diablo II: Resurrected" ] --> (ask >>= doF . W.sink), name `oneOf` [ "Diablo II: Resurrected", "Diablo II" ] --> ask >>= \w -> liftX (screenWorkspace 1 >>= \x -> case x of Just ws -> pure . Endo $ W.shiftWin "18:Diablo" w . W.view "18:Diablo" . W.view ws Nothing -> pure . Endo $ W.view "18:Diablo" . W.shiftWin "18:Diablo" w), className `oneOf` [ "steam_app_22330" ] --> ask >>= \w -> liftX (screenWorkspace 1 >>= \x -> case x of Just ws -> pure . Endo $ W.shiftWin "19:" w . W.view "19:" . W.view ws Nothing -> pure . Endo $ W.view "19:" . W.shiftWin "19:" w) -- name `oneOf` [ "Diablo II: Resurrected", "Diablo II" ] --> do -- mtag <- liftX (screenWorkspace 1) -- let doView = doF . W.view -- (doView <> doShift) "18:Diablo" <> foldMap doView mtag ] where role = stringProperty "WM_WINDOW_ROLE" name = stringProperty "WM_NAME" prop `oneOf` ss = prop <&> (`elem` ss) -- Workspaces myWorkspaces = [ "1:net" , "2:$>_" , "3:emacs" , "4:fm" , "5:vm" , "6:gfx" , "7:media" , "8:win-A" , "8:win-B" , "9:linux" , "10:office" , "11:sys" , "12a:misc 1" , "12b:misc 2" , "12c:misc 3" , "12d:misc 4" , "13:school" , "14:art" , "15:net" , "16:firefox" , "17:downloads" , "18:Diablo" , "19:" , "20:" ] -- Update mouse keybindings with conditional checks myMouseBindings :: XConfig Layout -> M.Map (ButtonMask, Button) (Window -> X ()) myMouseBindings XConfig {XMonad.modMask = modMask} = M.fromList $ -- Regular mouse bindings [ ((modMask, button1), \w -> focus w >> mouseMoveWindow w >> afterDrag (snapMagicMove (Just 50) (Just 50) w)) , ((modMask .|. shiftMask, button1), \w -> focus w >> mouseMoveWindow w >> afterDrag (snapMagicResize [L,R,U,D] (Just 50) (Just 50) w)) , ((modMask, button3), \w -> focus w >> mouseResizeWindow w >> afterDrag (snapMagicResize [R,D] (Just 50) (Just 50) w)) ] ++ -- Conditional mouse bindings based on active window [ ((modMask, button1), \w -> whenX (not <$> isActiveVMWindow w) $ focus w >> mouseMoveWindow w >> afterDrag (snapMagicMove (Just 50) (Just 50) w)) , ((modMask .|. shiftMask, button1), \w -> whenX (not <$> isActiveVMWindow w) $ focus w >> mouseMoveWindow w >> afterDrag (snapMagicResize [L,R,U,D] (Just 50) (Just 50) w)) , ((modMask, button3), \w -> whenX (not <$> isActiveVMWindow w) $ focus w >> mouseResizeWindow w >> afterDrag (snapMagicResize [R,D] (Just 50) (Just 50) w)) ] where -- Function to check if the active window is a VirtualBox VM window isActiveVMWindow :: Window -> X Bool isActiveVMWindow = runQuery (className =? "VirtualBox Machine") -- Layouts mylayoutHook = avoidStruts . smartBorders $ windowNavigation $ screenCornerLayoutHook $ onWorkspace "6:Gimp" (Full) -- $ onWorkspace "2:$>_" ( Full ||| Mirror (ResizableTall 1 (3/100) (1/2) [])) $ -- First layout Full Windows Tabbed Bottom -- tabbedBottomAlways shrinkText (theme darkTheme) windowNavigation Full ||| Mirror (Column 1) -- To Do: Configure BSP algorithm keybindings -- ||| emptyBSP ||| Accordion ||| Mirror Accordion ||| Grid ||| Mirror (Grid) ||| ResizableTall 1 (3/100) (1/2) [] ||| Mirror (ResizableTall 1 (3/100) (1/2) []) ||| tiled ||| Mirror tiled ||| Dishes 2 (1/6) ||| spiral (6/7) ||| StackTile 1 (3/100) (1/2) ||| ThreeCol 1 (3/100) (1/2) ||| ThreeColMid 1 (3/100) (1/2) ||| TwoPane (3/100) (1/2) ||| simpleTabbedBottom ||| simpleTabbedLeft ||| simpleTabbedRight -- ||| withIM (1%7) (ClassName "kopete") Grid ||| simplestFloat -- ||| withIM (1%7) (ClassName "Tkabber") Grid where -- default tiling algorithm partitions the screen into two panes tiled = Tall nmaster delta ratio nmaster = 1 -- The default number of windows in the master pane ratio = 1/2 -- Default proportion of screen occupied by master pane delta = 3/100 -- Percent of screen to increment by when resizing panes gimpLayout = simpleTabbed */* Mirror (Tall (1) (2/3) (3/100)) -- scratchpads scratchpads :: [NamedScratchpad] scratchpads = -- name, cmd, query, hook -- (noTaskbar <> customFloating (W.RationalRect (1/10) (1/10) (8/10) (8/10))) -- (noTaskbar <> customFloating (W.RationalRect (1/10) (1/10) (8/10) (8/10))) [ NS "konsole" "konsole" (className =? "konsole") (noTaskbar <> customFloating (W.RationalRect (1/10) (1/10) (8/10) (8/10))) , NS "kate" "kate" (className =? "kate") (noTaskbar <> customFloating (W.RationalRect (1/10) (1/10) (8/10) (8/10))) , NS "chromium" "chromium" (className =? "Chromium") (noTaskbar <> customFloating (W.RationalRect (1/10) (1/10) (8/10) (8/10))) , NS "htop" "xst -e htop" (name =? "htop") (noTaskbar <> customFloating (W.RationalRect (1/10) (1/10) (8/10) (8/10))) , NS "pavucontrol" "pavucontrol-qt" (className =? "pavucontrol-qt") (noTaskbar <> customFloating (W.RationalRect (1/10) (1/10) (8/10) (8/10))) , NS "cool-retro-term" "cool-retro-term" (className =? "cool-retro-term") (noTaskbar <> customFloating (W.RationalRect (1/10) (1/10) (8/10) (8/10))) ] where name = stringProperty "WM_NAME" -- Startup Hooks myStartupHook = do -- Screen corners addScreenCorners [ (SCUpperLeft, namedScratchpadAction scratchpads "konsole") , (SCLowerLeft, namedScratchpadAction scratchpads "kate") , (SCUpperRight, namedScratchpadAction scratchpads "konsole") , (SCLowerRight, namedScratchpadAction scratchpads "kate") ] adjustEventInput myXPConfig = def { searchPredicate = fuzzyMatch , sorter = fuzzySort } -- toggleOrView ignoring scratchpad and named scratchpad workspace toggleOrViewNoSP = toggleOrDoSkip ["NSP"] W.greedyView -- Log Hooks -- myLogHook :: X () -- myLogHook = myXmobarLogHook xmproc = dynamicLogWithPP <=< clickablePP . filterOutWsPP [scratchpadWorkspaceTag] $ xmobarPP { ppOutput = hPutStrLn xmproc , ppTitle = xmobarColor "white" "" . shorten 256 , ppCurrent = xmobarColor "lightblue" "" . wrap "[" "]" , ppVisible = wrap "(" ")" } -- Main Xmonad Function main :: IO () main = do -- xmproc <- spawnPipe ("/home/stoned/.local/bin/xmobar ~/.xmobar/xmobarrc") xmproc <- spawnPipe ("~/.local/bin/xmobar ~/.xmobar/xmobarrc") xmonad $ docks $ ewmhFullscreen . ewmh $ def { -- hooks manageHook = manageDocks <+> myManageHook <+> namedScratchpadManageHook scratchpads <+> manageHook def , startupHook = myStartupHook , handleEventHook = focusOnMouseMove <+> screenCornerEventHook , layoutHook = mylayoutHook , logHook = myXmobarLogHook xmproc -- workspaces , workspaces = myWorkspaces -- current modifier key , modMask = mod4Mask -- Fix Virtual Box Winkey+Mouse , mouseBindings = myMouseBindings -- xmond config , focusedBorderColor = "black" , normalBorderColor = "#4A148C" , borderWidth = 1 , focusFollowsMouse = True -- default terminal , terminal = "x-terminal-emulator" } `additionalMouseBindings` ( -- [ -- -- FloatSnap -- ((mod4Mask, button1), -- (\w -> focus w >> mouseMoveWindow w >> afterDrag (snapMagicMove (Just 50) (Just 50) w))) -- , ((mod4Mask .|. shiftMask, button1), -- (\w -> focus w >> mouseMoveWindow w >> afterDrag (snapMagicResize [L,R,U,D] (Just 50) (Just 50) w))) -- , ((mod4Mask, button3), -- (\w -> focus w >> mouseResizeWindow w >> afterDrag (snapMagicResize [R,D] (Just 50) (Just 50) w))) -- ] -- ++ [ -- Switch windows using mousewheel ((mod4Mask .|. shiftMask, button4), (\w -> windows W.focusUp)) , ((mod4Mask .|. shiftMask, button5), (\w -> windows W.focusDown)) -- Resize master pane using mousewheel , ((mod4Mask, button5), (\w -> sendMessage Expand)) , ((mod4Mask, button4), (\w -> sendMessage Shrink)) ] ) `additionalKeys` ([ ((m .|. mod4Mask, key), windows $ f i) | (i, key) <- zip (myWorkspaces) ([xK_1 .. xK_9] ++ [xK_0, xK_minus, xK_equal]) , (f, m) <- [(W.view, 0), (W.shift, shiftMask)] ] ++ [ ((m .|. mod4Mask, key), screenWorkspace sc >>= flip whenJust (windows . f)) | (key, sc) <- zip [xK_F1..xK_F2] [0..] , (f, m) <- [(W.view, 0), (W.shift, shiftMask)] ] ) `additionalKeysP` -- Key modifier info: -- shift Shift_L (0x32), Shift_R (0x3e) -- control Control_L (0x25), Control_R (0x69) -- mod1 Alt_L (0x40), Alt_R (0x6c), Meta_L (0xcd) -- mod3 Hyper_R (0x42), Hyper_L (0xcf) -- mod4 Super_L (0x85), Super_R (0x86) -- M = Super (mod4) -- M1 = Alt -- M3 = Hyper (Caps Lock) [ ("M-S-r", renameWorkspace def) -- Winkey+Shift+r: Rename current workspace -- Window order / stack , ("M-S-j", windows W.swapDown) -- Winkey+Shift+j: Swap focused window with next window ⚠ Conflict: defined again below , ("M-S-j", windows W.swapUp) -- Winkey+Shift+j: Swap focused window with previous window ⚠ Overrides previous line -- Status bar & window menu , ("M-b", sendMessage ToggleStruts) -- Winkey+b: Toggle status bar visibility , ("M-o", windowMenu) -- Winkey+o: Open window menu/options -- Master pane , ("M-", dwmpromote) -- Winkey+Enter: Promote focused window to master pane -- Run / Raise prompts , ("M-C-x", runOrRaisePrompt def) -- Winkey+Ctrl+x: Run or raise a program , ("M-", runOrRaisePrompt def) -- Winkey+Escape: Alternate run/raise prompt -- Window list selection , ("M-x w", goToSelected def) -- Winkey+x then w: Show window list for selection -- GridSelect launcher , ("M-s", spawnSelected def [ "discord" , "dolphin" , "firefox" , "gimp" , "google-chrome" , "kate" , "smplayer" , "systemsettings5" , "urxvt" , "konsole" , "xterm" , "sudo timeshift-gtk" ]) -- Winkey+s: GridSelect menu to launch apps -- Volume control (numpad) , ("", spawn "~/bin/volume.sh plus") -- Numpad + : Increase volume , ("", spawn "~/bin/volume.sh minus")-- Numpad - : Decrease volume , ("", spawn "amixer -D pulse set Master 1+ toggle") -- Numpad / : Mute/unmute -- Terminal , ("M-S-t", spawn "x-terminal-emulator") -- Winkey+Shift+t: Launch terminal -- Multi-monitor navigation , ("M-", nextScreen) -- Winkey+Right: Focus next screen , ("M-", prevScreen) -- Winkey+Left: Focus previous screen -- Workspace navigation , ("M-", nextWS) -- Winkey+Up: Switch to next workspace , ("M-", prevWS) -- Winkey+Down: Switch to previous workspace , ("M-S-", shiftToNext >> nextWS) -- Winkey+Shift+Down: Move focused window to next workspace + switch , ("M-S-", shiftToPrev >> prevWS) -- Winkey+Shift+Up: Move focused window to previous workspace + switch , ("M-S-", shiftNextScreen) -- Winkey+Shift+Right: Move window to workspace on next screen , ("M-S-", shiftPrevScreen) -- Winkey+Shift+Left: Move window to workspace on previous screen -- Directional window focus (only tiled windows) , ("M3-", sendMessage $ Go R) -- Caps Lock+Right: Focus window to right , ("M3-", sendMessage $ Go L) -- Caps Lock+Left: Focus window to left , ("M3-", sendMessage $ Go U) -- Caps Lock+Up: Focus window above , ("M3-", sendMessage $ Go D) -- Caps Lock+Down: Focus window below , ("M3-M1-", sendMessage $ Go R) -- Caps Lock+Alt+Right: Alternate directional focus , ("M3-M1-", sendMessage $ Go L) -- Caps Lock+Alt+Left , ("M3-M1-", sendMessage $ Go U) -- Caps Lock+Alt+Up , ("M3-M1-", sendMessage $ Go D) -- Caps Lock+Alt+Down -- Workspace toggle & empty workspace , ("M-z", toggleWS) -- Winkey+z: Toggle to last workspace , ("M-S-e", moveTo Next emptyWS) -- Winkey+Shift+e: Move to first empty workspace -- Master area resize , ("M-]", sendMessage MirrorShrink) -- Winkey+]: Shrink master area , ("M-[", sendMessage MirrorExpand) -- Winkey+[: Expand master area -- Status bar toggle , ("", sendMessage ToggleStruts) -- F12: Toggle status bar -- Scratchpads , ("C-`", namedScratchpadAction scratchpads "konsole") -- Ctrl+`: Terminal , ("M-`", namedScratchpadAction scratchpads "kate") -- Winkey+`: Editor , ("M1-`", namedScratchpadAction scratchpads "chromium") -- Alt+`: Browser , ("M3-`", namedScratchpadAction scratchpads "htop") -- Caps Lock+`: System monitor , ("M3-1", namedScratchpadAction scratchpads "pavucontrol") -- Caps Lock+1: Sound control , ("M3-2", namedScratchpadAction scratchpads "cool-retro-term") -- Caps Lock+2: Retro terminal -- Window prompts , ("M-S-g", windowPrompt def Goto wsWindows) -- Winkey+Shift+g: Go to window in current workspace , ("M-S-b", windowPrompt myXPConfig Goto allWindows) -- Winkey+Shift+b: Go to any window , ("M-S-m", workspacePrompt def (windows . W.shift)) -- Winkey+Shift+m: Move window to workspace , ("M3-g", windowPrompt def Goto wsWindows) -- Caps Lock+g: Go to window in current workspace , ("M3-b", windowPrompt myXPConfig Goto allWindows) -- Caps Lock+b: Go to any window , ("M3-m", workspacePrompt def (windows . W.shift)) -- Caps Lock+m: Move window to workspace -- Toggle / view workspaces , ("M3-e", toggleOrViewNoSP "3:emacs") -- Caps Lock+e: Toggle / view workspace 3:emacs , ("M-x e", toggleOrViewNoSP "3:emacs") -- Winkey+x then e: Toggle / view workspace 3:macs , ("M-x 2", toggleOrViewNoSP "2:$>_") -- Winkey+x then 2: Toggle / view workspace 2:$>_ ]