diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2022-04-10 13:26:16 -0600 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2022-10-09 12:19:46 -0600 |
| commit | a652c330707e2e9bbe963e01af79ce730cf3452e (patch) | |
| tree | 047655195f50efcbd51db8f825acf589dc6abead /src/Internal | |
| parent | 381a3e5a00813314249bb74b5460f5ff5a4006bb (diff) | |
| download | rde-a652c330707e2e9bbe963e01af79ce730cf3452e.tar.gz rde-a652c330707e2e9bbe963e01af79ce730cf3452e.tar.bz2 rde-a652c330707e2e9bbe963e01af79ce730cf3452e.zip | |
Rename Internal to Rahm.Desktop
Diffstat (limited to 'src/Internal')
| -rw-r--r-- | src/Internal/CornerLayout.hs | 58 | ||||
| -rw-r--r-- | src/Internal/DMenu.hs | 45 | ||||
| -rw-r--r-- | src/Internal/Hash.hs | 11 | ||||
| -rw-r--r-- | src/Internal/Keys.hs | 820 | ||||
| -rw-r--r-- | src/Internal/KeysM.hs | 497 | ||||
| -rw-r--r-- | src/Internal/Layout.hs | 326 | ||||
| -rw-r--r-- | src/Internal/LayoutDraw.hs | 155 | ||||
| -rw-r--r-- | src/Internal/LayoutList.hs | 297 | ||||
| -rw-r--r-- | src/Internal/Lib.hs | 160 | ||||
| -rw-r--r-- | src/Internal/Logger.hs | 32 | ||||
| -rw-r--r-- | src/Internal/Marking.hs | 204 | ||||
| -rw-r--r-- | src/Internal/MouseMotion.hs | 97 | ||||
| -rw-r--r-- | src/Internal/NoPersist.hs | 23 | ||||
| -rw-r--r-- | src/Internal/PassMenu.hs | 13 | ||||
| -rw-r--r-- | src/Internal/PromptConfig.hs | 12 | ||||
| -rw-r--r-- | src/Internal/RebindKeys.hs | 119 | ||||
| -rw-r--r-- | src/Internal/ScreenRotate.hs | 19 | ||||
| -rw-r--r-- | src/Internal/Submap.hs | 104 | ||||
| -rw-r--r-- | src/Internal/Swallow.hs | 29 | ||||
| -rw-r--r-- | src/Internal/SwapMaster.hs | 41 | ||||
| -rw-r--r-- | src/Internal/Windows.hs | 86 | ||||
| -rw-r--r-- | src/Internal/XMobarLog.hs | 78 |
22 files changed, 0 insertions, 3226 deletions
diff --git a/src/Internal/CornerLayout.hs b/src/Internal/CornerLayout.hs deleted file mode 100644 index 5545aef..0000000 --- a/src/Internal/CornerLayout.hs +++ /dev/null @@ -1,58 +0,0 @@ -{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-} --- Creates a layout, the "corner layout" that keeps the master window in the --- corner and the other windows go around it. -module Internal.CornerLayout where - -import Data.Typeable (Typeable) -import XMonad (LayoutClass(..), Rectangle(..), Resize(..), fromMessage) -import qualified XMonad.StackSet as S - -data Corner a = Corner Rational Rational - deriving (Show, Typeable, Read) - -instance LayoutClass Corner a where - pureLayout (Corner frac _) screen@(Rectangle x y w h) ss = - let w' = floor $ fromIntegral w * frac - h' = floor $ fromIntegral h * frac - corner = Rectangle 0 0 w' h' - vertRect = Rectangle (fromIntegral w') 0 (w - w') h - horizRect = Rectangle 0 (fromIntegral h') w' (h - h') - ws = S.integrate ss - - vn = (length ws - 1) `div` 2 - hn = (length ws - 1) - vn - in - case ws of - [a] -> [(a, screen)] - [a, b] -> [ - (a, Rectangle x y w' h), - (b, Rectangle (x + fromIntegral w') y (w - w') h)] - _ -> - zip ws $ map ( - \(Rectangle x' y' w h) -> Rectangle (x + x') (y + y') w h) $ - corner : - splitVert vertRect vn ++ - splitHoriz horizRect hn - - pureMessage (Corner frac delta) m = fmap resize (fromMessage m) - where - resize Shrink = Corner (frac - delta) delta - resize Expand = Corner (frac + delta) delta - -splitVert :: Rectangle -> Int -> [Rectangle] -splitVert (Rectangle x y w h) i' = - map - (\i -> Rectangle x (y + fromIntegral (step * i)) w step) - [0 .. i - 1] - where - i = fromIntegral i' - step = h `div` i - -splitHoriz :: Rectangle -> Int -> [Rectangle] -splitHoriz (Rectangle x y w h) i' = - map - (\i -> Rectangle (x + fromIntegral (step * i)) y step h) - [0 .. i - 1] - where - step = w `div` i - i = fromIntegral i' diff --git a/src/Internal/DMenu.hs b/src/Internal/DMenu.hs deleted file mode 100644 index 0d22b55..0000000 --- a/src/Internal/DMenu.hs +++ /dev/null @@ -1,45 +0,0 @@ -module Internal.DMenu where - -import XMonad.Util.Dmenu -import XMonad -import Control.Monad -import Data.Map (Map) -import qualified Data.Map as Map -import XMonad.Util.Run -import Data.List (intercalate) -import Text.Printf (printf) - -data Colors = - Colors { - fg :: String, - bg :: String - } | DefaultColors - -menuCommand :: [String] -menuCommand = ["rofi", "-monitor", "-4", "-dmenu", "-sort", "-levenshtein-sort"] - -menuCommandString :: String -menuCommandString = unwords menuCommand - -runDMenu :: X () -runDMenu = void $ - safeSpawn - "rofi" - ["-monitor", "-4", "-display-run", "Execute", "-show", "run"] - -runDMenuPrompt :: String -> Maybe String -> [String] -> X String -runDMenuPrompt prompt color select = - let realColor = maybe [] (\c -> ["-sb", c, "-nf", c]) color - in - runProcessWithInput "/home/rahm/.local/bin/dmenu_debug.sh" ([ - "-p", prompt, - "-l", "12", - "-dim", "0.4" ] ++ realColor) (intercalate "\n" select) - - -runDMenuPromptWithMap :: String -> Maybe String -> Map String a -> X (Maybe a) -runDMenuPromptWithMap prompt color map = do - let realColor = maybe [] ( - \c -> ["-theme-str", printf "* {theme-color: %s;}" c]) color - menuMapArgs (head menuCommand) - (tail menuCommand ++ ["-p", prompt] ++ realColor) map diff --git a/src/Internal/Hash.hs b/src/Internal/Hash.hs deleted file mode 100644 index 272808b..0000000 --- a/src/Internal/Hash.hs +++ /dev/null @@ -1,11 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} -module Internal.Hash where - -import Numeric (showHex) -import qualified Data.ByteString as BS -import qualified Data.ByteString.Char8 as BC -import qualified Crypto.Hash.SHA1 as SHA1 - -quickHash :: String -> String -quickHash str = - concatMap (`showHex` "") $ BS.unpack (SHA1.hash $ BC.pack str) diff --git a/src/Internal/Keys.hs b/src/Internal/Keys.hs deleted file mode 100644 index ad9d719..0000000 --- a/src/Internal/Keys.hs +++ /dev/null @@ -1,820 +0,0 @@ -{-# LANGUAGE RankNTypes, FlexibleContexts, ViewPatterns #-} -module Internal.Keys (applyKeys) where - -import XMonad.Util.Run (safeSpawn) -import Data.Monoid (Endo(..)) -import Control.Monad.Trans.Class -import Control.Monad.Reader -import Control.Monad.Writer -import Control.Monad.Loops (iterateWhile) -import Control.Monad.Fix (fix) -import Graphics.X11.ExtraTypes.XF86; -import Internal.KeysM -import Internal.SwapMaster (swapMaster) -import XMonad.Hooks.ManageDocks -import XMonad.Layout.MosaicAlt -import Graphics.X11.ExtraTypes.XorgDefault -import System.Process -import XMonad.Util.Ungrab -import XMonad.Layout.Spacing -import Data.Maybe (isJust, fromMaybe) -import Debug.Trace -import Control.Applicative -import Prelude hiding ((!!)) -import Control.Monad -import Data.Char -import Data.List hiding ((!!)) -import Data.List.Safe ((!!)) -import Data.Map (Map) -import Internal.Layout -import Internal.Marking -import Internal.PromptConfig -import System.IO -import Text.Printf -import XMonad -import Internal.Submap -import XMonad.Actions.WindowNavigation -import XMonad.Prompt -import XMonad.Prompt.Input -import XMonad.Prompt.Shell -import XMonad.Util.CustomKeys -import XMonad.Util.Scratchpad -import XMonad.Actions.RotSlaves -import XMonad.Actions.CopyWindow as CopyWindow -import XMonad.Actions.SpawnOn as SpawnOn - -import qualified Data.Map as Map -import qualified XMonad.StackSet as W - -import Internal.LayoutList -import Internal.MouseMotion -import Internal.Windows -import Internal.Lib -import Internal.DMenu -import Internal.PassMenu -import Internal.Logger -import Internal.RebindKeys -import Internal.Swallow -import Internal.ScreenRotate (screenRotateForward, screenRotateBackward) - -type KeyMap l = XConfig l -> Map (KeyMask, KeySym) (X ()) -type ButtonsMap l = XConfig l -> Map (KeyMask, Button) (Window -> X ()) - - -spawnX :: String -> X () -spawnX = spawn - -noWindow :: b -> Window -> b -noWindow = const - -decreaseVolume = spawnX "pactl set-sink-volume @DEFAULT_SINK@ -5%" -increaseVolume = spawnX "pactl set-sink-volume @DEFAULT_SINK@ +5%" -playPause = spawnX "spotify-control play" -mediaPrev = spawnX "spotify-control prev" -mediaNext = spawnX "spotify-control next" - -decreaseVolumeDoc = doc "Decrease volume" decreaseVolume -increaseVolumeDoc = doc "Increase volume" increaseVolume -playPauseDoc = doc "Play/Pause current media" playPause -mediaPrevDoc = doc "Previous media" mediaPrev -mediaNextDoc = doc "Next media" mediaNext - - -button6 :: Button -button6 = 6 - -button7 :: Button -button7 = 7 - -button8 :: Button -button8 = 8 - -button9 :: Button -button9 = 9 - -button10 :: Button -button10 = 10 - -button11 :: Button -button11 = 11 - -button12 :: Button -button12 = 12 - -button13 :: Button -button13 = 13 - -button14 :: Button -button14 = 14 - -button15 :: Button -button15 = 15 - -keyBindingToKeymap :: (XConfig l -> KeyBindings) -> KeyMap l -keyBindingToKeymap bindings config = fmap bindingToX (bindings config) - - where - bindingToX b = - case b of - Documented _ (Action x) -> x - Documented _ (Submap mapping) -> - submap (fmap bindingToX mapping) - Documented _ (Repeat mapping) -> - fix $ \recur -> - submap (fmap (\b -> bindingToX b >> recur) mapping) - -keymap :: XConfig l -> KeyBindings -keymap = runKeys $ do - config <- getConfig - - let subkeys keysM = Submap (runKeys keysM config) - repeatable keysM = Repeat (runKeys keysM config) - - bind xK_apostrophe $ do - justMod $ - doc "Jumps between marks." $ - mapNextString $ \_ str -> - case str of - ['\''] -> jumpToLast - [ch] | isAlphaNum ch -> jumpToMark ch - "[" -> historyPrev - "]" -> historyNext - _ -> return () - - shiftMod $ - doc "Swap the current window with a mark." $ - mapNextString $ \_ str -> - case str of - ['\''] -> swapWithLastMark - [ch] | isAlphaNum ch -> swapWithMark ch - _ -> return () - - bind xK_BackSpace $ do - -- The only raw keybinding. Meant to get a terminal to unbrick XMonad if - -- something goes wrong with the keyboard layout and for first-time boots - -- where dmenu/alacritty may not be installed. - rawMask mod4Mask $ - doc "Spawns XTerm as a fallback if xkb is messed up." $ - spawnX "xterm" - - -- Moves xmobar to different monitors. - justMod $ - doc "Move XMobar to another screen." $ - spawnX "pkill -SIGUSR1 xmobar" - - bind xK_F1 $ do - -- Experimental. Sends 'a' to all windows. - -- - -- I've discovered that many clients ignore such synthetic events, including - -- Spotify, Chrome and Gedit. Some, like Chrome, seem to honor them if it's - -- focused. It's pretty annoying because it keeps me from doing some cool - -- things all for BS security theater, but I guess there might be some way - -- to do this via XTest? - shiftMod $ forAllWindows $ \w -> do - logs $ "Try send to " ++ show w - sendKey (0, xK_a) w - - justMod $ - doc "Print this documentation" - (safeSpawn "gxmessage" [ - "-fn", "Source Code Pro", - documentation (keymap config)] :: X ()) - - bind xK_F7 $ - - justMod $ - doc "Print this documentation." $ - logs (documentation (keymap config)) - - bind xK_F10 $ do - justMod playPauseDoc - - bind xK_F11 $ do - justMod mediaPrevDoc - - bind xK_F12 $ do - justMod mediaNextDoc - - bind xK_Return $ do - justMod swapMaster - - bind xK_Tab $ do - justMod $ windows W.focusDown - shiftMod $ windows W.focusUp - - -- Switch between different screens. These are the leftmost keys on the home - -- row in a Dvorak layout. One might want to switch these to ASD for QWERTY. - forM_ (zip [xK_a, xK_o, xK_e] [0..]) $ \(key, idx) -> - bind key $ do - -- Move focus to that screen. - justMod $ - doc ("Switch focus to screen " ++ show idx) $ - withScreen W.view idx - -- Swap the current screen with the one given - altMod $ - doc ("Swap the current screen with screen " ++ show idx) $ - withScreen W.greedyView idx - -- Move the current window to the select screen. - shiftMod $ - doc ("Move the current window to screne " ++ show idx) $ - withScreen W.shift idx - - altgrMod $ - logs "Test altgr" - - bind xK_bracketright $ do - justMod $ - doc "Increase the gaps between windows." $ - sendMessage $ modifyWindowBorder 5 - - bind xK_bracketleft $ do - justMod $ - doc "Decrease the gaps between windows." $ - sendMessage $ modifyWindowBorder (-5) - - bind xK_b $ do - justMod $ spawnX "bluetooth-select.sh" - - bind xK_c $ do - justMod $ - doc "Run PassMenu" runPassMenu - - shiftMod $ - doc "Kill the current window" CopyWindow.kill1 - - bind xK_f $ do - justMod $ - doc "Flip the current layout vertically" $ - sendMessage FlipLayout - shiftMod $ - doc "Flip the current layout horizontally" $ - sendMessage HFlipLayout - - bind xK_g $ do - justMod $ - doc "Goto a workspace\n\n\t\ - - \If the second character typed is alpha-numberic, jump to that\n\t\ - \workspace. The workspace is created on-the-fly if such a workspace\n\t\ - \does not exist.\n\n\t\ - - \If the second character typed is:\n\t\t\ - \]: go to the next workspace\n\t\t\ - \[: go to the previous workspace\n\t\t\ - \}: cycle the workspaces on the screens to the right\n\t\t\ - \{: cycle the workspaces on the screens to the left\n\t\t\ - \<space>: Jump to the accompaning workspace.\n\t\t\ - \F1: display this help.\n" $ - mapNextStringWithKeysym $ \_ keysym str -> - case (keysym, str) of - (_, [ch]) | isAlphaNum ch -> gotoWorkspace ch - (_, "]") -> pushHistory $ withRelativeWorkspace next W.greedyView - (_, "[") -> pushHistory $ withRelativeWorkspace prev W.greedyView - (_, "}") -> windows screenRotateForward - (_, "{") -> windows screenRotateBackward - (_, " ") -> gotoAccompaningWorkspace - - -- Test binding. Tests that I can still submap keysyms alone (keys - -- where XLookupString won't return anything helpful.) - (f, _) | f == xK_F1 -> - (safeSpawn "gxmessage" [ - "-fn", "Source Code Pro", - documentation (keymap config)] :: X ()) - - _ -> return () - shiftMod $ - doc "Move the currently focused window to another workspace" $ - mapNextString $ \_ str -> - case str of - [ch] | isAlphaNum ch -> shiftToWorkspace ch - "]" -> withRelativeWorkspace next W.shift - "[" -> withRelativeWorkspace prev W.shift - _ -> return () - shiftAltMod $ - doc "Swap this workspace with another workspace (rename)." $ - mapNextString $ \_ str -> - case str of - [ch] | isAlphaNum ch -> swapWorkspace ch - _ -> return () - - bind xK_h $ do - justMod $ - doc "Focus on the next window down in the stack" $ - windows W.focusDown - - shiftMod $ - doc "Swap the current window with the next one down in the stack" $ - windows W.swapDown - - controlMod $ - doc "Rotate all the windows down the stack" - rotAllDown - - bind xK_j $ do - justMod $ - doc "Shrink the size of the zoom region" $ - sendMessage ShrinkZoom - - shiftMod $ - doc "Go to the previous window in history." historyPrev - - bind xK_k $ do - justMod $ - doc "Expand the size of the zoom region" $ - sendMessage ExpandZoom - - shiftMod $ - doc "Go to the next window in history." historyNext - - bind xK_l $ do - justMod $ - doc "Focus the next window in the stack" $ - windows W.focusUp - - shiftMod $ - doc "Swap the currently focused window with the next window in the stack." $ - windows W.swapUp - - controlMod $ - doc "Rotate the windows up." - rotAllUp - - altMod $ - doc "Lock the screen" $ - spawnX "xsecurelock" - - bind xK_minus $ do - justMod $ - doc "Decrease the number of windows in the master region." $ - sendMessage (IncMasterN (-1)) - - shiftMod $ - doc "For mosaic layout, shrink the size-share of the current window" $ - withFocused $ sendMessage . shrinkWindowAlt - - bind xK_m $ do - justMod $ - doc "Mark the current window with the next typed character." $ - mapNextString $ \_ str -> - case str of - [ch] | isAlphaNum ch -> markCurrentWindow ch - _ -> return () - - bind xK_n $ do - justMod $ - doc "Shift to the next workspace." $ - withRelativeWorkspace next W.greedyView - - bind xK_p $ do - justMod $ - doc "Shift to the previous workspace." $ - withRelativeWorkspace prev W.greedyView - - bind xK_plus $ do - justMod $ - doc "Increase the number of windows in the master region." $ - sendMessage (IncMasterN 1) - - shiftMod $ - doc "For mosaic layout, increase the size-share of the current window." $ - withFocused $ sendMessage . expandWindowAlt - - bind xK_q $ do - shiftMod $ - doc "Recompile and restart XMonad" $ - spawnX "xmonad --recompile && xmonad --restart" - - justMod $ - doc "Experimental Bindings" $ - subkeys $ do - - bind xK_q $ - (justMod -|- noMod) $ - doc "EXPERIMENTAL: Move mouse to control media." $ - mouseRotateMotion (logs "CW") (logs "CCW") - - bind xK_r $ do - justMod $ doc "Run a command via Rofi" runDMenu - shiftMod $ - doc "Rotate the current layout. (flips x, y coordinates)" $ - sendMessage DoRotate - - bind xK_s $ do - altMod $ spawnX "sudo -A systemctl suspend && xsecurelock" - - bind xK_space $ do - justMod $ - doc "Use the next layout in the layout list." $ sendMessage toNextLayout - - altMod $ - doc "Reset the layout to the default layout." $ sendMessage toFirstLayout - - shiftMod $ - doc "Use the previous layout in the layout list." $ - sendMessage toPreviousLayout - - bind xK_t $ do - justMod $ - doc "Spawn a terminal." $ spawnX (terminal config) - - shiftMod $ - doc "Sink the current window into the tiling." $ withFocused $ windows . W.sink - - altMod $ - doc "Spawn a floating terminal" $ spawnX (terminal config ++ " -t Floating\\ Term") - - bind xK_v $ - -- Allows repeated strokes of M-h and M-l to reduce and increase volume - -- respectively. - justMod $ - doc "Changes the volume." $ - repeatable $ do - bind xK_h $ - justMod $ - doc "Decrease volume." - decreaseVolumeDoc - - bind xK_l $ - justMod $ - doc "Increase volume." - increaseVolumeDoc - - bind xK_v $ - justMod (return () :: X ()) - - bind xK_w $ do - justMod $ doc "Jump to a window (via rofi)" windowJump - - bind xK_x $ do - justMod $ - doc "Toggles respect for struts." $ - sendMessage ToggleStruts - - bind xK_z $ do - - justMod $ - doc "Less often used keybindings." $ - subkeys $ do - - bind xK_g $ do - (justMod -|- noMod) $ - doc "Copy a window to the given workspace" $ - mapNextString $ \_ s -> - case s of - [ch] | isAlphaNum ch -> windows (CopyWindow.copy s) - _ -> return () - - bind xK_p $ do - (justMod -|- noMod) $ - doc "Go to the prior window in the history" historyPrev - - bind xK_t $ do - (justMod -|- noMod) $ logs "Test Log" - - -- bind xK_n $ do - -- (justMod -|- noMod) $ - -- doc "Take a note" $ - -- spawnX (terminal config ++ " -t Notes -e notes new") - bind xK_n $ do - (justMod -|- noMod) $ - doc "Go to the next window in the history" historyNext - - bind xK_c $ do - shiftMod $ - doc "Kill all other copies of a window." - CopyWindow.killAllOtherCopies - - bind xK_e $ do - (justMod -|- noMod) $ - doc "Select an emoji" $ - spawnX "emoji-select.sh" - - (shiftMod -|- rawMask shiftMask) $ - doc "Select an emoticon" $ - spawnX "emoticon-select.sh" - - bind xK_a $ - (justMod -|- noMod) $ - doc "Move the audio sink for an application." $ - spawnX "set-sink.sh" - - bind xK_w $ - (justMod -|- noMod) $ - doc "Select a network to connect to." $ - spawnX "networkmanager_dmenu" - - bind xK_o $ - (justMod -|- noMod) $ - doc "Open a file from the library" $ - spawnX "library-view.sh" - - bind xK_s $ - (justMod -|- noMod) $ - doc "Toggle the ability for terminals to swallow child windows." - toggleSwallowEnabled - - bind xK_v $ do - (justMod -|- noMod) $ - doc "Set the volume via rofi." $ - spawnX "set-volume.sh" - (shiftMod -|- rawMask shiftMask) $ - doc "Set the volume of an application via rofi." $ - spawnX "set-volume.sh -a" - - -- Double-tap Z to toggle zoom. - bind xK_z $ do - noMod -|- justMod $ - doc "Toggle zoom on the current window." $ - sendMessage ToggleZoom - - -- Z is reserved to create sub keybindings to do various things. - -- I don't really use these at the moment. - bind xK_h $ noMod mediaPrevDoc - bind xK_j $ noMod playPauseDoc - bind xK_l $ noMod mediaNextDoc - - -- Centers the current focused window. i.e. toggles the Zoom layout - -- modifier. - shiftMod $ - doc "Toggle zoom on the current window." $ - sendMessage ToggleZoom - - bind xF86XK_Calculator $ do - noMod $ spawnX $ terminal config ++ " -t Floating\\ Term -e /usr/bin/env python3" - - bind xF86XK_AudioLowerVolume $ do - noMod $ spawnX "pactl set-sink-volume @DEFAULT_SINK@ -1%" - justMod mediaPrevDoc - - bind xF86XK_AudioRaiseVolume $ do - noMod $ spawnX "pactl set-sink-volume @DEFAULT_SINK@ +1%" - justMod mediaNextDoc - - bind xF86XK_AudioMute $ do - noMod $ spawnX "pactl set-sink-mute @DEFAULT_SINK@ toggle" - - bind xF86XK_AudioPlay $ do - noMod playPauseDoc - - bind xF86XK_AudioNext $ do - noMod mediaNextDoc - - bind xF86XK_AudioPrev $ do - noMod mediaPrevDoc - - bind xF86XK_AudioPrev $ do - noMod mediaPrevDoc - - bind xF86XK_MonBrightnessUp $ do - noMod $ spawnX "set-backlight.sh +0.05" - justMod $ spawnX "set-backlight.sh 1" - - bind xF86XK_MonBrightnessDown $ do - noMod $ spawnX "set-backlight.sh -0.05" - justMod $ spawnX "set-backlight.sh 0.01" - rawMask shiftMask $ spawnX "set-backlight.sh 0" - -mouseMap :: ButtonsMap l -mouseMap = runButtons $ do - config <- getConfig - - let x button = Map.lookup button (mouseMap config) - - let defaultButtons button = fromMaybe (\w -> return ()) $ - Map.lookup button (mouseMap config) - subMouse = submapButtonsWithKey defaultButtons . flip runButtons config - - - let continuous :: [(Button, X ())] -> Button -> Window -> X () - continuous actions button w = do - case find ((==button) . fst) actions of - Just (_, action) -> action - Nothing -> return () - - (subMouse $ - forM_ (map fst actions) $ \b -> - bind b $ noMod $ \w -> continuous actions b w) w - - bind button1 $ do - justMod $ \w -> focus w >> mouseMoveWindow w >> windows W.shiftMaster - - bind button2 $ do - justMod $ windows . (W.shiftMaster .) . W.focusWindow - - bind button3 $ do - justMod $ \w -> focus w >> mouseResizeWindow w >> windows W.shiftMaster - - bind button6 $ - justMod $ noWindow (withRelativeWorkspace prev W.greedyView) - - bind button7 $ - justMod $ noWindow (withRelativeWorkspace next W.greedyView) - - bind button8 $ - justMod $ noWindow mediaPrev - - bind button9 $ - justMod $ noWindow mediaNext - - bind button14 $ do - noMod $ subMouse $ do - - bind button3 $ - noMod $ noWindow (gotoWorkspace 's') - - bind button13 $ do - noMod $ noWindow $ click >> CopyWindow.kill1 - - bind button14 $ do - noMod $ noWindow $ click >> sendMessage ToggleZoom - - bind button15 $ do - noMod $ noWindow $ spawnX "pavucontrol" - - let mediaButtons = [ - (button4, increaseVolume), - (button5, decreaseVolume), - (button2, playPause), - (button9, historyNext), - (button8, historyPrev), - (button6, mediaPrev), - (button7, mediaNext) - ] - - forM_ (map fst mediaButtons) $ \b -> - bind b $ noMod $ continuous mediaButtons b - - bind button13 $ noMod $ subMouse $ do - bind button1 $ noMod mouseMoveWindow - bind button2 $ noMod $ windows . W.sink - bind button3 $ noMod mouseResizeWindow - - bind button13 $ noMod $ subMouse $ do - bind button13 $ noMod $ subMouse $ do - bind button13 $ noMod $ noWindow $ spawnX "xsecurelock" - bind button1 $ noMod $ noWindow $ - spawnX "sudo -A systemctl suspend && xsecurelock" - - bind button15 $ do - - noMod $ subMouse $ do - bind button13 $ noMod $ noWindow gotoAccompaningWorkspace - - bind button15 $ do - noMod $ noWindow jumpToLast - - - let workspaceButtons = [ - (button2, swapMaster), - - (button9, withRelativeWorkspace next W.greedyView), - (button8, withRelativeWorkspace prev W.greedyView), - - (button4, windows W.focusUp), - (button5, windows W.focusDown), - - (button7, windows screenRotateForward), - (button6, windows screenRotateBackward) - ] - - forM_ (map fst workspaceButtons) $ \b -> - bind b $ noMod $ continuous workspaceButtons b - --- Bindings specific to a window. These are set similarly to th ekeymap above, --- but uses a Query monad to tell which windows the keys will apply to. --- --- This is useful to create hotkeys in applications where hot keys are not --- configurable, or to remove keybindings that are irritating (looking at you, --- ctrl+w in Chrome!!). -windowSpecificBindings :: - XConfig l -> WriterT (Map (KeyMask, KeySym) (X ())) Query () -windowSpecificBindings config = do - - w <- lift ask - - let configureIf b k = tell =<< lift (b --> return (keyBindingToKeymap (runKeys k) config)) - emitKey = flip sendKey w - - configureIf (flip elem browsers <$> className) $ do - - -- if the window is a browser, configure these bindings. Lots of browsers - -- make up their own garbage bindings that are not standard across many - -- other applications. This alleviates the issue. - -- - -- Consistency with terminal: - -- - -- Ctrl+h is backspace - -- Ctrl+w is ctrl+backspace - -- Ctrl+u is ctrl+shift+backspace - -- - -- Consistency with Vim/Emacs-ish: - -- - -- Alt+{Shift,Ctrl,}+{h,j,k,l} -> {Shift,Ctrl,}+{Left,Down,Up,Right} - -- Ctrl+b -> Ctrl+Left - -- Ctrl+e -> Ctrl+Right - -- Ctrl+$ -> End - -- Ctrl+^ -> Home - -- - -- Ctrl+d -> Delete current tab. - - - let mods = permuteMods [shiftMask, controlMask, 0] - - bind xK_h $ do - rawMask controlMask $ emitKey (0, xK_BackSpace) - forM_ mods $ \mask -> - rawMask (altMask .|. mask) $ emitKey (mask, xK_Left) - - bind xK_j $ - forM_ mods $ \mask -> - rawMask (altMask .|. mask) $ emitKey (mask, xK_Down) - - bind xK_k $ - forM_ mods $ \mask -> - rawMask (altMask .|.mask) $ emitKey (mask, xK_Up) - - bind xK_l $ - forM_ mods $ \mask -> - rawMask (altMask .|. mask) $ emitKey (mask, xK_Right) - - bind xK_u $ - rawMask controlMask $ emitKey (controlMask .|. shiftMask, xK_BackSpace) - - bind xK_w $ - rawMask controlMask $ emitKey (controlMask, xK_BackSpace) - - bind xK_b $ do - rawMask controlMask $ emitKey (controlMask, xK_Left) - rawMask (controlMask .|. shiftMask) $ - emitKey (controlMask .|. shiftMask, xK_Left) - - bind xK_e $ do - rawMask controlMask $ emitKey (controlMask, xK_Right) - rawMask (controlMask .|. shiftMask) $ - emitKey (controlMask .|. shiftMask, xK_Right) - - bind xK_dollar $ - rawMask controlMask $ emitKey (0, xK_End) - - bind xK_at $ - rawMask (controlMask .|. shiftMask) $ emitKey (0, xK_Home) - - bind xK_d $ - rawMask controlMask $ emitKey (controlMask, xK_w) - - bind xK_F2 $ - -- Experimental. - noMod $ logs "This is a test" - - -- Add a binding to xev as a test. - configureIf (title =? "Event Tester") $ - bind xK_F2 $ - noMod $ emitKey (controlMask, xK_F2) - - where - browsers = ["Google-chrome", "Brave-browser", "firefox-default"] - - -- Create a permutation from a list of modifiers. - -- - -- i.e. permuteMods [C, S, M] will return - -- - -- [C, S, M, C + M, C + S, M + S, C + S + M, 0] - permuteMods = map (foldl' (.|.) 0) . filterM (const [True, False]) - -windowBindings :: XConfig l -> XConfig l -windowBindings xconfig = - xconfig { - startupHook = do - forAllWindows (runQuery doQuery) - startupHook xconfig, - - manageHook = (doQuery >> return (Endo id)) <> manageHook xconfig - } - - where - doQuery :: Query () - doQuery = do - map <- execWriterT $ windowSpecificBindings xconfig - w <- ask - - liftX $ logs $ printf "For Window: %s" (show w) - forM_ (Map.toList map) $ \(key, action) -> do - liftX $ logs $ printf " -- remap: %s" (show key) - remapKey key action - -applyKeys :: XConfig l -> IO (XConfig l) -applyKeys config = - return $ windowBindings $ config { keys = keyBindingToKeymap keymap, mouseBindings = mouseMap } - -click :: X () -click = do - (dpy, root) <- asks $ (,) <$> display <*> theRoot - (_, _, window, _, _, _, _, _) <- io $ queryPointer dpy root - focus window - -modifyWindowBorder :: Integer -> SpacingModifier -modifyWindowBorder i = ModifyWindowBorder $ \(Border a b c d) -> - Border (clip $ a + i) (clip $ b + i) (clip $ c + i) (clip $ d + i) - - where clip i | i < 0 = 0 - clip i = i diff --git a/src/Internal/KeysM.hs b/src/Internal/KeysM.hs deleted file mode 100644 index e490b89..0000000 --- a/src/Internal/KeysM.hs +++ /dev/null @@ -1,497 +0,0 @@ -{-# Language GeneralizedNewtypeDeriving, MultiParamTypeClasses, - FunctionalDependencies, FlexibleInstances, TypeFamilies, FlexibleContexts #-} -module Internal.KeysM where - -import Data.List -import Data.Bits ((.&.)) -import Control.Monad.Writer -import Text.Printf -import Control.Arrow (second, first) -import Control.Monad (void) -import Control.Monad.State (State(..), modify', get, execState) -import XMonad -import Data.Map (Map) -import qualified Data.Map as Map - -data Documented t = Documented String t - -data KeyBinding = - Action (X ()) | - Submap KeyBindings | - Repeat KeyBindings - -type KeyBindings = Map (KeyMask, KeySym) (Documented KeyBinding) - -type ButtonBinding = Window -> X () -type ButtonBindings = Map (KeyMask, Button) ButtonBinding - -{- Module that defines a DSL for binding keys. -} -newtype KeysM l a = KeysM (State (XConfig l, KeyBindings) a) - deriving (Functor, Applicative, Monad) - -newtype ButtonsM l a = ButtonsM (State (XConfig l, ButtonBindings) a) - deriving (Functor, Applicative, Monad) - -newtype BindingBuilder b a = BindingBuilder (State (KeyMask, [(KeyMask, b)]) a) - deriving (Functor, Applicative, Monad) - -class HasConfig m where - getConfig :: m l (XConfig l) - -class Bindable k where - type BindableValue k :: * - type BindableMonad k :: (* -> *) -> * -> * - - bind :: k -> BindingBuilder (BindableValue k) a -> BindableMonad k l () - -- section :: String -> BindableMonad k l () -> BindableMonad k l () - -class Binding k b where - toB :: k -> b - - rawMask :: KeyMask -> k -> BindingBuilder b () - rawMask m x = BindingBuilder $ modify' (second ((m, toB x):)) - -instance Binding (X ()) (Documented KeyBinding) where - toB = Documented "" . Action - -instance Binding KeyBindings (Documented KeyBinding) where - toB = Documented "" . Submap - -instance Binding a (Documented a) where - toB = Documented "" - -instance Binding a a where - toB = id - -doc :: (Binding k (Documented KeyBinding)) => String -> k -> Documented KeyBinding -doc str k = let (Documented _ t) = toB k in Documented str t - -runKeys :: KeysM l a -> XConfig l -> KeyBindings -runKeys (KeysM stateM) config = - snd $ execState stateM (config, Map.empty) - -runButtons :: ButtonsM l a -> XConfig l -> ButtonBindings -runButtons (ButtonsM stateM) config = - snd $ execState stateM (config, Map.empty) - -instance HasConfig KeysM where - getConfig = fst <$> KeysM get - -instance HasConfig ButtonsM where - getConfig = fst <$> ButtonsM get - -{- Generally it is assumed that the mod key shoud be pressed, but not always. -} -noMod :: (Binding k b) => k -> BindingBuilder b () -noMod = rawMask 0 - -maskMod :: (Binding k b) => KeyMask -> k -> BindingBuilder b () -maskMod mask action = do - modMask <- fst <$> BindingBuilder get - rawMask (modMask .|. mask) action - -altMask :: KeyMask -altMask = mod1Mask - -hyperMask :: KeyMask -hyperMask = mod3Mask - -altgrMask :: KeyMask -altgrMask = 0x80 - -superMask :: KeyMask -superMask = mod4Mask - -justMod :: (Binding k b) => k -> BindingBuilder b () -justMod = maskMod 0 - -instance Bindable KeySym where - type BindableValue KeySym = Documented KeyBinding - type BindableMonad KeySym = KeysM - - -- bind :: KeySym -> BindingBuilder (X x) a -> KeysM l () - bind key (BindingBuilder stM) = do - m <- modMask <$> getConfig - let (_, values) = execState stM (m, []) - - KeysM $ modify' $ second $ - flip (<>) (Map.fromList (map (\(m, v) -> ((m, key), v)) values)) - - -instance Bindable Button where - type BindableValue Button = ButtonBinding - type BindableMonad Button = ButtonsM - - -- bind :: KeySym -> BindingBuilder (Window -> X ()) a -> ButtonsM l () - bind button (BindingBuilder stM) = do - m <- modMask <$> getConfig - let (_, values) = execState stM (m, []) - - ButtonsM $ modify' $ second $ - flip (<>) (Map.fromList (map (\(m, v) -> ((m, button), v)) values)) - -shiftControlAltSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltSuperHyperAltgrMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. superMask .|. hyperMask .|. altgrMask) - -shiftControlAltSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltSuperHyperMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. superMask .|. hyperMask) - -shiftControlAltSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltSuperAltgrMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. superMask .|. altgrMask) - -shiftControlAltSuperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltSuperMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. superMask) - -shiftControlAltHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltHyperAltgrMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. hyperMask .|. altgrMask) - -shiftControlAltHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltHyperMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. hyperMask) - -shiftControlAltAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltAltgrMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. altgrMask) - -shiftControlAltMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltMod = - maskMod (shiftMask .|. controlMask .|. altMask) - -shiftControlSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlSuperHyperAltgrMod = - maskMod (shiftMask .|. controlMask .|. superMask .|. hyperMask .|. altgrMask) - -shiftControlSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlSuperHyperMod = - maskMod (shiftMask .|. controlMask .|. superMask .|. hyperMask) - -shiftControlSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlSuperAltgrMod = - maskMod (shiftMask .|. controlMask .|. superMask .|. altgrMask) - -shiftControlSuperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlSuperMod = - maskMod (shiftMask .|. controlMask .|. superMask) - -shiftControlHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlHyperAltgrMod = - maskMod (shiftMask .|. controlMask .|. hyperMask .|. altgrMask) - -shiftControlHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlHyperMod = - maskMod (shiftMask .|. controlMask .|. hyperMask) - -shiftControlAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltgrMod = - maskMod (shiftMask .|. controlMask .|. altgrMask) - -shiftControlMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlMod = - maskMod (shiftMask .|. controlMask) - -shiftAltSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltSuperHyperAltgrMod = - maskMod (shiftMask .|. altMask .|. superMask .|. hyperMask .|. altgrMask) - -shiftAltSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltSuperHyperMod = - maskMod (shiftMask .|. altMask .|. superMask .|. hyperMask) - -shiftAltSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltSuperAltgrMod = - maskMod (shiftMask .|. altMask .|. superMask .|. altgrMask) - -shiftAltSuperMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltSuperMod = - maskMod (shiftMask .|. altMask .|. superMask) - -shiftAltHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltHyperAltgrMod = - maskMod (shiftMask .|. altMask .|. hyperMask .|. altgrMask) - -shiftAltHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltHyperMod = - maskMod (shiftMask .|. altMask .|. hyperMask) - -shiftAltAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltAltgrMod = - maskMod (shiftMask .|. altMask .|. altgrMask) - -shiftAltMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltMod = - maskMod (shiftMask .|. altMask) - -shiftSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftSuperHyperAltgrMod = - maskMod (shiftMask .|. superMask .|. hyperMask .|. altgrMask) - -shiftSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftSuperHyperMod = - maskMod (shiftMask .|. superMask .|. hyperMask) - -shiftSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftSuperAltgrMod = - maskMod (shiftMask .|. superMask .|. altgrMask) - -shiftSuperMod :: (Binding k b) => k -> BindingBuilder b () -shiftSuperMod = - maskMod (shiftMask .|. superMask) - -shiftHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftHyperAltgrMod = - maskMod (shiftMask .|. hyperMask .|. altgrMask) - -shiftHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftHyperMod = - maskMod (shiftMask .|. hyperMask) - -shiftAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltgrMod = - maskMod (shiftMask .|. altgrMask) - -shiftMod :: (Binding k b) => k -> BindingBuilder b () -shiftMod = maskMod shiftMask - -controlAltSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlAltSuperHyperAltgrMod = - maskMod (controlMask .|. altMask .|. superMask .|. hyperMask .|. altgrMask) - -controlAltSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -controlAltSuperHyperMod = - maskMod (controlMask .|. altMask .|. superMask .|. hyperMask) - -controlAltSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlAltSuperAltgrMod = - maskMod (controlMask .|. altMask .|. superMask .|. altgrMask) - -controlAltSuperMod :: (Binding k b) => k -> BindingBuilder b () -controlAltSuperMod = - maskMod (controlMask .|. altMask .|. superMask) - -controlAltHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlAltHyperAltgrMod = - maskMod (controlMask .|. altMask .|. hyperMask .|. altgrMask) - -controlAltHyperMod :: (Binding k b) => k -> BindingBuilder b () -controlAltHyperMod = - maskMod (controlMask .|. altMask .|. hyperMask) - -controlAltAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlAltAltgrMod = - maskMod (controlMask .|. altMask .|. altgrMask) - -controlAltMod :: (Binding k b) => k -> BindingBuilder b () -controlAltMod = - maskMod (controlMask .|. altMask) - -controlSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlSuperHyperAltgrMod = - maskMod (controlMask .|. superMask .|. hyperMask .|. altgrMask) - -controlSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -controlSuperHyperMod = - maskMod (controlMask .|. superMask .|. hyperMask) - -controlSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlSuperAltgrMod = - maskMod (controlMask .|. superMask .|. altgrMask) - -controlSuperMod :: (Binding k b) => k -> BindingBuilder b () -controlSuperMod = - maskMod (controlMask .|. superMask) - -controlHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlHyperAltgrMod = - maskMod (controlMask .|. hyperMask .|. altgrMask) - -controlHyperMod :: (Binding k b) => k -> BindingBuilder b () -controlHyperMod = - maskMod (controlMask .|. hyperMask) - -controlAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlAltgrMod = - maskMod (controlMask .|. altgrMask) - -controlMod :: (Binding k b) => k -> BindingBuilder b () -controlMod = maskMod controlMask - -altSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -altSuperHyperAltgrMod = - maskMod (altMask .|. superMask .|. hyperMask .|. altgrMask) - -altSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -altSuperHyperMod = - maskMod (altMask .|. superMask .|. hyperMask) - -altSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -altSuperAltgrMod = - maskMod (altMask .|. superMask .|. altgrMask) - -altSuperMod :: (Binding k b) => k -> BindingBuilder b () -altSuperMod = - maskMod (altMask .|. superMask) - -altHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -altHyperAltgrMod = - maskMod (altMask .|. hyperMask .|. altgrMask) - -altHyperMod :: (Binding k b) => k -> BindingBuilder b () -altHyperMod = - maskMod (altMask .|. hyperMask) - -altAltgrMod :: (Binding k b) => k -> BindingBuilder b () -altAltgrMod = - maskMod (altMask .|. altgrMask) - -altMod :: (Binding k b) => k -> BindingBuilder b () -altMod = maskMod altMask - -superHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -superHyperAltgrMod = - maskMod (superMask .|. hyperMask .|. altgrMask) - -superHyperMod :: (Binding k b) => k -> BindingBuilder b () -superHyperMod = - maskMod (superMask .|. hyperMask) - -superAltgrMod :: (Binding k b) => k -> BindingBuilder b () -superAltgrMod = - maskMod (superMask .|. altgrMask) - -superMod :: (Binding k b) => k -> BindingBuilder b () -superMod = maskMod superMask - -hyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -hyperAltgrMod = - maskMod (hyperMask .|. altgrMask) - -hyperMod :: (Binding k b) => k -> BindingBuilder b () -hyperMod = maskMod hyperMask - -altgrMod :: (Binding k b) => k -> BindingBuilder b () -altgrMod = maskMod altgrMask - -{- Can combine two or more of the functions above to apply the same action to - - multiple masks. -} -(-|-) :: (Binding k b) => - (k -> BindingBuilder b ()) -> - (k -> BindingBuilder b ()) -> - k -> BindingBuilder b () -(-|-) fn1 fn2 f = fn1 f >> fn2 f - -{- Meant for submapping, binds all alphanumeric charactes to (fn c). -} -mapNumbersAndAlpha :: KeyMask -> (Char -> X ()) -> KeysM l () -mapNumbersAndAlpha km fn = do - mapNumbers km fn - mapAlpha km fn - -{- Meant for submapping. This binds all numbers to (fn x) where x is the number - - pressed and fn is the function provided. -} -mapNumbers :: KeyMask -> (Char -> X ()) -> KeysM l () -mapNumbers km fn = do - mapM_ (\(key, ch) -> bind key $ rawMask km (fn ch)) - [ (xK_0, '0') - , (xK_1, '1') - , (xK_2, '2') - , (xK_3, '3') - , (xK_4, '4') - , (xK_5, '5') - , (xK_6, '6') - , (xK_7, '7') - , (xK_8, '8') - , (xK_9, '9') - -- Programmer Dvorak shifts the numbers so I have to map to their unshifted - -- form. - , (xK_bracketright, '6') - , (xK_exclam, '8') - , (xK_bracketleft, '7') - , (xK_braceleft, '5') - , (xK_braceright, '3') - , (xK_parenleft, '1') - , (xK_equal, '9') - , (xK_asterisk, '0') - , (xK_parenright, '2') - , (xK_plus, '4') ] - -{- Meant for submapping. This binds all alpha charactes to (fn c) where c is the - - character pressed and fn is the function provided. -} -mapAlpha :: KeyMask -> (Char -> X ()) -> KeysM l () -mapAlpha km fn = - mapM_ (\(key, ch) -> bind key $ rawMask km (fn ch)) [ - (xK_a, 'a') - , (xK_b, 'b') - , (xK_c, 'c') - , (xK_d, 'd') - , (xK_e, 'e') - , (xK_f, 'f') - , (xK_g, 'g') - , (xK_h, 'h') - , (xK_i, 'i') - , (xK_j, 'j') - , (xK_k, 'k') - , (xK_l, 'l') - , (xK_m, 'm') - , (xK_n, 'n') - , (xK_o, 'o') - , (xK_p, 'p') - , (xK_q, 'q') - , (xK_r, 'r') - , (xK_s, 's') - , (xK_t, 't') - , (xK_u, 'u') - , (xK_v, 'v') - , (xK_w, 'w') - , (xK_x, 'x') - , (xK_y, 'y') - , (xK_z, 'z') - ] - - -documentation :: KeyBindings -> String -documentation = execWriter . document' "" - where - document' pref keybindings = - forM_ (sortOn (map (\(a, b) -> (b, a)) . snd . snd) $ Map.toList (keyBindingsToList keybindings)) $ \(doc, (thing, keys)) -> do - when ((not $ null doc) || hasSubmap thing) $ - tell $ printf "%s%s: %s\n" pref (intercalate " or " $ map prettyShow keys) doc - case thing of - Action _ -> return () - Submap submap -> document' (pref ++ " ") submap - Repeat submap -> do - tell pref - tell " (repeatable):\n" - document' (pref ++ " ") submap - - keyBindingsToList :: KeyBindings -> Map String (KeyBinding, [(KeyMask, KeySym)]) - keyBindingsToList b = - fmap (\list -> ((\(_, Documented _ t) -> t) (head list), map fst list)) $ - group (\(_, Documented doc _) -> doc) (sortOn (snd . fst) $ Map.toList b) - - prettyShow :: (KeyMask, KeySym) -> String - prettyShow (mask, key) = printf "<%s%s>" (showMask mask) (keysymToString key) - - hasSubmap b = case b of - Action _ -> False - _ -> True - - - showMask :: KeyMask -> String - showMask mask = - let masks = [(shiftMask, "S"), - (altMask, "A"), - (mod3Mask, "H"), - (mod4Mask, "M"), - (altgrMask, "AGr"), - (controlMask, "C")] in - - concatMap ((++"-") . snd) $ filter ((/=0) . (.&.mask) . fst) masks - - - group :: (Ord b) => (a -> b) -> [a] -> (Map b [a]) - group fn = Map.fromListWith (++) . map (first fn . (\a -> (a, [a]))) - - diff --git a/src/Internal/Layout.hs b/src/Internal/Layout.hs deleted file mode 100644 index 229e958..0000000 --- a/src/Internal/Layout.hs +++ /dev/null @@ -1,326 +0,0 @@ -{-# LANGUAGE MultiParamTypeClasses, ViewPatterns, FlexibleInstances, KindSignatures, DataKinds, GADTs, RankNTypes, PolyKinds #-} -module Internal.Layout where - -import GHC.TypeLits - -import Data.Proxy (Proxy(..)) -import Internal.CornerLayout (Corner(..)) -import Control.Arrow (second) -import XMonad.Hooks.ManageDocks -import XMonad.Layout.Circle -import XMonad.Layout.Accordion -import Control.Applicative -import XMonad.Layout.Spacing -import Data.List -import XMonad.Layout.Spiral -import XMonad.Layout.ThreeColumns -import XMonad.Layout.Grid -import XMonad.Layout.Dishes -import XMonad.Layout.MosaicAlt -import XMonad.Layout.Fullscreen -import qualified XMonad.Layout.Dwindle as D -import XMonad.Layout -import XMonad.Layout.LayoutModifier -import XMonad -import XMonad.Core -import XMonad.Layout.NoBorders (smartBorders, noBorders) - -import Internal.LayoutList -import Internal.Windows - -import qualified Data.Map as M -import qualified XMonad.StackSet as W - -myLayout = - fullscreenFull $ - avoidStruts $ - spacingRaw True (Border 5 5 5 5) True (Border 5 5 5 5) True $ - layoutZipper $ - mods (reinterpretIncMaster $ spiral (6/7)) |: - mods (modifyMosaic (MosaicAlt M.empty :: MosaicAlt Window)) |: - mods (reinterpretIncMaster $ Corner (3/4) (3/100)) |: - mods (ModifyDescription TallDescriptionModifier (Tall 1 (3/100) (1/2))) |: - mods (ModifyDescription ThreeColDescMod (ThreeCol 1 (3/100) (1/2))) |: - mods Grid |: - mods (Dishes 2 (1/6)) |: - mods (reinterpretIncMaster $ D.Dwindle D.R D.CW 1.5 1.1) |: - nil - --- This is a type class that defines how to reinterpret a message. One can think --- of this as a kind of type-level function. It lets one associate a function --- (reinterpretMessage) with a type construct, which for the case below is a --- Symbol. --- --- It would be nice to attach this function to the LayoutModifier directly as a --- value, however LayoutModifiers must be Show-able and Read-able and functions --- are not. However encoding in the typesystem itsef which function is to be --- called is the best alternative I have. -class DoReinterpret (k :: t) where - reinterpretMessage :: - Proxy k -> SomeMessage -> X (Maybe SomeMessage) - --- Mosaic doesn't have the concept of a "Master Space", so reinterpret messages --- intended to modify the master space and instead have those messages expand --- and shrink the current window. --- --- "ForMosaic" is an instance of the Symbol kind. This is some neat type-system --- hacking one can do in Haskell. -instance DoReinterpret "ForMosaic" where - - -- IncMaster message - reinterpretMessage _ (fromMessage -> Just (IncMasterN n)) = do - fmap (SomeMessage . - (if n > 0 - then expandWindowAlt - else shrinkWindowAlt)) <$> getFocusedWindow - - -- ResizeMaster message - reinterpretMessage _ (fromMessage -> Just m) = do - fmap (SomeMessage . - (case m of - Expand -> expandWindowAlt - Shrink -> shrinkWindowAlt)) <$> getFocusedWindow - - -- Messages that don't match the above, just leave it unmodified. - reinterpretMessage _ m = return (Just m) - -instance DoReinterpret "IncMasterToResizeMaster" where - reinterpretMessage _ (fromMessage -> Just (IncMasterN n)) = - return $ Just $ - if n > 0 - then SomeMessage Expand - else SomeMessage Shrink - reinterpretMessage _ m = return (Just m) - --- Data construct for association a DoReinterpret function with a concrete --- construct that can be used in the LayoutModifier instance. --- --- It wolud be nice to have ReinterpretMessage hold the function as a value --- rather than delegate to this kind-instance, however, it won't work because --- LayoutModifiers have to be Read-able and Show-able, and functions are neither --- of those, so a value-level function may not be a member of a LayoutModifier, --- thus I have to settle for delegating to a hard-coded instance using --- type-classes. -data ReinterpretMessage k a = ReinterpretMessage - deriving (Show, Read) - --- Instance for ReinterpretMessage as a Layout modifier. -instance (DoReinterpret k) => - LayoutModifier (ReinterpretMessage k) a where - - handleMessOrMaybeModifyIt self message = do - - -- Delegates to the reinterpretMessage function associatied with the - -- type-variable k. - newMessage <- reinterpretMessage (ofProxy self) message - case newMessage of - Just m -> return $ Just $ Right m - Nothing -> return $ Just $ Left self - where - -- ofProxy just provides reifies the phantom type k so the type system can - -- figure out what instance to go to. - ofProxy :: ReinterpretMessage k a -> Proxy k - ofProxy _ = Proxy - -modifyMosaic :: l a -> ModifiedLayout (ReinterpretMessage "ForMosaic") l a -modifyMosaic = ModifiedLayout ReinterpretMessage - -reinterpretIncMaster :: - l a -> ModifiedLayout (ReinterpretMessage "IncMasterToResizeMaster") l a -reinterpretIncMaster = ModifiedLayout ReinterpretMessage - -mods = - ModifiedLayout (Zoomable False 0.05 0.05) . - ModifiedLayout (Flippable False) . - ModifiedLayout (HFlippable False) . - ModifiedLayout (Rotateable False) - - -data ModifyDescription m l a = ModifyDescription m (l a) - deriving (Show, Read) - -data TallDescriptionModifier = TallDescriptionModifier - deriving (Show, Read) - -data ThreeColDescMod = ThreeColDescMod - deriving (Show, Read) - -class DescriptionModifier m l where - newDescription :: m -> l a -> String -> String - -instance (Typeable m, Show m, DescriptionModifier m l, LayoutClass l a) => LayoutClass (ModifyDescription m l) a where - runLayout (W.Workspace t (ModifyDescription m l) a) rect = do - (rects, maybeNewLayout) <- runLayout (W.Workspace t l a) rect - return (rects, fmap (ModifyDescription m) maybeNewLayout) - - doLayout (ModifyDescription m l) a s = do - (rects, maybeNewLayout) <- doLayout l a s - return (rects, fmap (ModifyDescription m) maybeNewLayout) - - pureLayout (ModifyDescription m l) a s = pureLayout l a s - - emptyLayout (ModifyDescription m l) a = do - (rects, maybeNewLayout) <- emptyLayout l a - return (rects, fmap (ModifyDescription m) maybeNewLayout) - - handleMessage (ModifyDescription m l) a = do - maybeNewLayout <- handleMessage l a - return (ModifyDescription m <$> maybeNewLayout) - - pureMessage (ModifyDescription m l) a = - let maybeNewLayout = pureMessage l a in - ModifyDescription m <$> maybeNewLayout - - description (ModifyDescription m l) = newDescription m l (description l) - -instance DescriptionModifier TallDescriptionModifier Tall where - newDescription _ (Tall mast _ _) _ = "Tall(" ++ show mast ++ ")" - -instance DescriptionModifier ThreeColDescMod ThreeCol where - newDescription _ (ThreeCol mast _ _) _ = "ThreeCol(" ++ show mast ++ ")" - newDescription _ (ThreeColMid mast _ _) _ = "ThreeColMid(" ++ show mast ++ ")" - -data ResizeZoom = ShrinkZoom | ExpandZoom deriving (Typeable) - -instance Message ResizeZoom where - -newtype Flippable a = Flippable Bool -- True if flipped - deriving (Show, Read) - -newtype HFlippable a = HFlippable Bool -- True if flipped - deriving (Show, Read) - -newtype Rotateable a = Rotateable Bool -- True if rotated - deriving (Show, Read) - -data FlipLayout = FlipLayout deriving (Typeable) - -data HFlipLayout = HFlipLayout deriving (Typeable) - -data DoRotate = DoRotate deriving (Typeable) - -data Zoomable a = Zoomable Bool Float Float -- True if zooming in on the focused window. - deriving (Show, Read) - --- Toggles if the current window should be zoomed or not. Set the boolean --- to set the zoom.mhar -data ZoomModifier = - ToggleZoom | - Zoom | - Unzoom - deriving (Typeable) - -instance Message FlipLayout where - -instance Message HFlipLayout where - -instance Message ZoomModifier where - -instance Message DoRotate where - -instance (Eq a) => LayoutModifier Rotateable a where - pureModifier (Rotateable rotate) (Rectangle x' y' sw sh) _ returned = - if rotate - then (map (second (unzero . scaleRect . mirrorRect . zero)) returned, Nothing) - else (returned, Nothing) - where - zero (Rectangle x y w h) = Rectangle (x - x') (y - y') w h - unzero (Rectangle x y w h) = Rectangle (x + x') (y + y') w h - - scaleRect (Rectangle x y w h) = - Rectangle (x * fi sw `div` fi sh) - (y * fi sh `div` fi sw) - (w * sw `div` sh) - (h * sh `div` sw) - - fi = fromIntegral - - - pureMess (Rotateable rot) mess = - fmap (\DoRotate -> Rotateable (not rot)) (fromMessage mess) - - modifyDescription (Rotateable rot) underlying = - let descr = description underlying in - if rot - then descr ++ " Rotated" - else descr - -instance (Eq a) => LayoutModifier Flippable a where - pureModifier (Flippable flip) (Rectangle sx _ sw _) stack returned = - if flip - then (map (second doFlip) returned, Nothing) - else (returned, Nothing) - where - doFlip (Rectangle x y w h) = - Rectangle ((sx + fromIntegral sw) - x - fromIntegral w + sx) y w h - - pureMess (Flippable flip) message = - case fromMessage message of - Just FlipLayout -> Just (Flippable (not flip)) - Nothing -> Nothing - - modifyDescription (Flippable flipped) underlying = - let descr = description underlying in - if flipped - then descr ++ " Flipped" - else descr - -instance (Eq a) => LayoutModifier HFlippable a where - pureModifier (HFlippable flip) (Rectangle _ sy _ sh) stack returned = - if flip - then (map (second doFlip) returned, Nothing) - else (returned, Nothing) - where - doFlip (Rectangle x y w h) = - Rectangle x ((sy + fromIntegral sh) - y - fromIntegral h + sy) w h - - pureMess (HFlippable flip) message = - case fromMessage message of - Just HFlipLayout -> Just (HFlippable (not flip)) - Nothing -> Nothing - - modifyDescription (HFlippable flipped) underlying = - let descr = description underlying in - if flipped - then descr ++ " HFlipped" - else descr - - -instance (Eq a) => LayoutModifier Zoomable a where - redoLayout (Zoomable doit ws hs) (Rectangle x y w h) stack returned = - if doit - then - let focused = W.focus <$> stack - (zoomed, rest) = partition ((==focused) . Just . fst) returned - in case zoomed of - [] -> return (rest, Nothing) - ((fwin, _):_) -> return ((fwin, Rectangle (x + wp) (y + hp) (w - fromIntegral (wp * 2)) (h - fromIntegral (hp * 2))) : rest, Nothing) - - else return (returned, Nothing) - where - wp = floor $ fromIntegral w * ws - hp = floor $ fromIntegral h * hs - - handleMessOrMaybeModifyIt self@(Zoomable showing sw sh) mess = - return $ - (handleResize <$> fromMessage mess) - <|> (Left . handleZoom <$> fromMessage mess) - where - handleResize r = - if showing - then Left $ Zoomable showing (guard $ sw + d) (guard $ sh + d) - else Right $ case r of - ShrinkZoom -> SomeMessage Shrink - ExpandZoom -> SomeMessage Expand - - where d = (case r of - ShrinkZoom -> -1 - ExpandZoom -> 1) * 0.02 - - handleZoom ToggleZoom = Zoomable (not showing) sw sh - handleZoom Zoom = Zoomable True sw sh - handleZoom Unzoom = Zoomable False sw sh - - guard f | f > 1 = 1 - | f < 0 = 0 - | otherwise = f diff --git a/src/Internal/LayoutDraw.hs b/src/Internal/LayoutDraw.hs deleted file mode 100644 index a105c98..0000000 --- a/src/Internal/LayoutDraw.hs +++ /dev/null @@ -1,155 +0,0 @@ -{-# LANGUAGE FlexibleInstances, FlexibleContexts, MultiParamTypeClasses, -ScopedTypeVariables, BangPatterns #-} -module Internal.LayoutDraw (drawLayout) where - -import Control.Monad - -import Control.Arrow (second) -import Control.Concurrent (threadDelay) -import Control.Exception (handle) -import Control.Monad.Writer (execWriter, tell) -import Data.Foldable (find) -import Data.Maybe (fromMaybe) -import Internal.Hash (quickHash) -import Internal.Layout (ZoomModifier(..)) -import System.Directory (createDirectoryIfMissing, doesFileExist) -import System.FilePath ((</>)) -import Text.Printf (printf) -import XMonad.Layout.Spacing (SpacingModifier(..), Border(..)) - -import XMonad (X, - Rectangle(..), - Dimension, - LayoutClass, - Message, - Window, - SomeMessage(..)) - -import qualified XMonad as X -import qualified XMonad.StackSet as S - --- Draws and returns an XPM for the current layout. --- --- Returns --- - Bool - true if the xpm has already been written, and is thus cached. --- - String - description of the current layout --- - String - the text to send to XMobar --- --- This function actually runs the current layout's doLayout function to --- generate the XPM, so it's completely portable to all layouts. --- --- Note this function is impure and running the layout to create the XPM is also --- impure. While in-practice most layouts are pure, it should be kept in mind. -drawLayout :: X (Bool, String, String) -drawLayout = do - winset <- X.gets X.windowset - let layout = S.layout $ S.workspace $ S.current winset - - -- Gotta reset the layout to a consistent state. - layout' <- foldM (flip ($)) layout [ - handleMessage' $ ModifyWindowBorder $ const $ Border 0 0 0 0, - handleMessage' Unzoom - ] - - (cached, xpm) <- drawXpmIO layout' - - return (cached , X.description layout, printf "<icon=%s/>" xpm) - --- Returns true if a point is inside a rectangle (inclusive). -pointInRect :: (Dimension, Dimension) -> Rectangle -> Bool -pointInRect (x, y) (Rectangle x' y' w h) = - x <= (fi x' + fi w) && x >= fi x' && y <= (fi y' + fi h) && y >= fi y' - where - fi :: (Integral a, Num b) => a -> b - fi = fromIntegral - --- Scale factory. Scaling the rectangles before writing the XPM helps to reduce --- noise from things like AvoidStruts, as there is unfortunately no way to force --- avoid struts to be off, one can only toggle it. -sf :: (Integral a) => a -sf = 1024 - -handleMessage' :: - (LayoutClass layout a, Message m) => m -> layout a -> X (layout a) -handleMessage' message layout = do - fromMaybe layout <$> X.handleMessage layout (SomeMessage message) - --- Creates the XPM for the given layout and returns the path to it. --- --- This function does run doLayout on the given layout, and that should be --- accounted for. -drawXpmIO :: (LayoutClass layout Window) => layout Window -> X (Bool, String) -drawXpmIO l = do - dir <- X.getXMonadDir - - let shrinkAmt = 5 -- amount to shrink the windows by to make pretty gaps. - - let (w, h) = (56, 24) - let descr = X.description l - let iconCacheDir = dir </> "icons" </> "cache" - let iconPath = iconCacheDir </> (quickHash descr ++ ".xpm") - - let colors = [ - "#cc9a9a", "#cc9999", "#cc8080", "#cc6666", - "#cc4c4c", "#cc3232", "#cc1818", "#cc0000" ] - - (rects', _) <- - X.runLayout - (S.Workspace "0" l (S.differentiate [1 .. 5])) - (Rectangle 0 0 ((w + shrinkAmt) * sf) ((h + shrinkAmt) * sf)) - - let rects = flip map rects' $ \(_, Rectangle x y w h) -> - Rectangle (x `div` sf) (y `div` sf) (w `div` sf) (h `div` sf) - - X.liftIO $ do - exists <- doesFileExist iconPath - createDirectoryIfMissing True iconCacheDir - - unless exists $ do - let xpmText = drawXpm (w, h) (zip (cycle colors) rects) 4 - writeFile iconPath xpmText - - return (exists, iconPath) - --- --- Create's an XPM, purely. Returns a string with the XPM contents. --- Takes as arguments --- --- - dimensions of the icon. --- - list of (color, rectangle) pairs. --- - The amount to shrink the windows by for those pretty gaps. --- -drawXpm :: - (Dimension, Dimension) -> [(String, Rectangle)] -> Dimension -> String -drawXpm (w, h) rects' shrinkAmt = execWriter $ do - tell "/* XPM */\n" - tell "static char *out[] = {\n" - tell $ printf "\"%d %d %d 1 \",\n" w h (length rects + 1) - - let zipRects = zip ['A' .. 'Z'] rects - - forM_ zipRects $ \(char, (color, _)) -> do - tell $ printf "\"%c c %s\",\n" char color - tell "\"% c None\"a,\n" - - forM_ [0 .. h - 1] $ \y -> do - tell "\"" - forM_ [0 .. w - 1] $ \x -> - (case find (matches x y) zipRects of - Nothing -> tell "%" - Just (chr, _) -> tell [chr]) - tell "\"" - when (y /= h - 1 - shrinkAmt) (tell ",") - tell "\n" - tell "};\n" - - where - matches x y (_, (_, r)) = pointInRect (x, y) r - rects = map (second (shrink shrinkAmt)) rects' - guard a b = if a <= shrinkAmt then 1 else b - shrink amt (Rectangle x y w h) = - Rectangle - x - y - (guard w $ w - fromIntegral amt) - (guard h $ h - fromIntegral amt) diff --git a/src/Internal/LayoutList.hs b/src/Internal/LayoutList.hs deleted file mode 100644 index 2405f71..0000000 --- a/src/Internal/LayoutList.hs +++ /dev/null @@ -1,297 +0,0 @@ -{-# LANGUAGE GADTs, RankNTypes, FlexibleInstances, MultiParamTypeClasses, - FlexibleContexts, UndecidableInstances, ViewPatterns, StandaloneDeriving, - RankNTypes, TupleSections, TypeFamilies #-} - -{- - - This module provides a more powerful version of the "Choose" layout that can - - be bidirectionally navigated. - - - - The indexing uses a type-safe zipper to keep track of the currently-selected - - layout. - -} -module Internal.LayoutList ( - LayoutList, - layoutZipper, - LCons, - LNil, - toNextLayout, - toPreviousLayout, - toFirstLayout, - (|:), - nil - )where - -import Control.Applicative ((<|>)) -import Data.Void -import Control.Monad.Identity (runIdentity) -import Data.Maybe (fromMaybe, fromJust) -import Control.Arrow (second) -import XMonad -import qualified XMonad.StackSet as W -import Data.Proxy - --- Type-level lists. LNil is the final of the list. LCons contains a layout and a --- tail. -data LNil a = LNil deriving (Read, Show) -data LCons l t a = LCons (l a) (t a) deriving (Read, Show) - --- Sel - This defines a structure where either this selected, or some --- other element is selected. --- --- These types can be composed to create what is effectively a bounded integer. --- I.e. there can be a type like --- --- Sel (Sel (Sel (Sel End))) --- --- Such a type is equivalent to an integer bounded at 4, because this type can --- exist in no more than 4 states: --- --- Sel --- Skip Sel --- Skip (Skip Sel) --- Skip (Skip (Skip Sel)) --- --- Note that a type (Sel End) can only be in the Sel as End may not be --- construted (without using undefined). -data Sel l = - Sel | - (Selector l) => Skip l -deriving instance (Read l, Selector l) => Read (Sel l) -deriving instance (Show l, Selector l) => Show (Sel l) -deriving instance (Eq l, Selector l) => Eq (Sel l) - --- Reimplement Void as End, just to keep the two separate, but End is for all --- intents and purposes Void. -data End -deriving instance Read End -deriving instance Show End -deriving instance Eq End - - --- Types that constitute a selection. Selections can be moved to the next --- selection, moved to the previous selection, optionally there could be a --- previous selection and they may be currently selected. -class (Eq c) => Selector c where - -- Increments the selection to the next state - -- - -- Returns Nothing if the selection class is in the final state and cannot be - -- incremented any farther. (This is helpful to facilitate modular - -- arithmatic) - increment :: c -> Maybe c - - -- Decrements the selection to the previous state. Returns Nothing if the - -- state is already in its initial setting. - decrement :: c -> Maybe c - - -- The initial state. - initial :: Maybe c - - -- The final state. - final :: Maybe c - --- --- Is selelected can be in two states: --- --- 1. The current element is selected --- 2. The current element is not selected and another element deeper in the --- structure is selected. -instance (Selector t) => Selector (Sel t) where - -- If the current element is not selected, increment the tail. - increment (Skip l) = Skip <$> increment l - -- If the current element is selected, the increment is just the initial of - -- the tail. - increment Sel = Skip <$> initial - - -- For a selection, the initial is just this in the Sel state. - initial = Just Sel - - -- Looks ahead at the tail, sees if it is selected, if so, select this one - -- instead, if the one ahead isn't selected, then decrement that one. - decrement (Skip t) = Just $ maybe Sel Skip (decrement t) - decrement Sel = Nothing - - -- Navigates to the end of the structure to find the final form. - final = Just $ maybe Sel Skip final - --- The End structure (which is equivalent to Void) is the "null" selector; the --- basecase that the Sel selector terminates at. -instance Selector End where - - -- Incrementing the End Selector doesn't do anything. - increment = const Nothing - - -- Decrementing the End Selector doesn't do anythig - decrement = const Nothing - - -- There is no initial value for the End selector. - initial = Nothing - - -- There is not final state for the End selector. - final = Nothing - --- Increment a selector, but cyclicly -incrementCycle :: (Selector c) => c -> c -incrementCycle c = - case increment c of - Nothing -> fromMaybe c initial - Just x -> x - --- Add two selectors together, incrementing the first until the second cannot be --- incremented anymore. -addSelector :: (Selector c) => c -> c -> c -addSelector c1 c2 = addSel c1 (decrement c2) - where - addSel c1 Nothing = c1 - addSel c1 (Just c2) = addSel (incrementCycle c1) (decrement c2) - --- Turn an int into a selector by repeatably incrementing. -intToSelector :: (Selector c) => Int -> c -intToSelector 0 = fromJust initial -intToSelector n = incrementCycle $ intToSelector (n - 1) - --- A LayoutList consists of a LayoutSelect type and a corresponding Selector. -data LayoutList l a where - LayoutList :: - (LayoutSelect l a, Selector (SelectorFor l)) => - SelectorFor l -> l a -> LayoutList l a - -deriving instance (LayoutSelect l a) => Show (LayoutList l a) -deriving instance (LayoutSelect l a) => Read (LayoutList l a) - -(|:) :: (LayoutSelect t a, LayoutClass l a) => l a -> t a -> LCons l t a -(|:) = LCons - -infixr 5 |: - --- Constructs a LayoutList. This function enforces that the SelectorFor l --- is a 'Sel' type. Essentially this enforces that there must be at least one --- underlying layout, otherwise a LayoutList cannot be constructed. -layoutZipper :: (LayoutSelect l a, SelectorFor l ~ Sel n) => - l a -> LayoutList l a -layoutZipper = LayoutList Sel - --- The termination of a layout zipper. -nil :: LNil a -nil = LNil - --- Message to navigate to a layout. -newtype NavigateLayout = - -- Sets the layout based on the given function. - NavigateLayout { - changeLayoutFn :: forall c. (Selector c) => c -> c - } - deriving (Typeable) - --- NavigateLayout instance to move to the next layout, circularly. -toNextLayout :: NavigateLayout -toNextLayout = NavigateLayout $ addSelector (intToSelector 1) - --- NavigateLayout instance to move to the previous layout, circularly. -toPreviousLayout :: NavigateLayout -toPreviousLayout = NavigateLayout $ \c -> fromMaybe c (decrement c <|> final) - --- NavigateLayotu instance to move to the first layout. -toFirstLayout :: NavigateLayout -toFirstLayout = NavigateLayout (`fromMaybe` initial) - -instance Message NavigateLayout where - --- LayoutSelect class Describes a type that can be used to select a layout using --- the associated type SelectorFor. --- --- Instances of this class are LCons and LNil. -class (Show (l a), - Read (l a), - Read (SelectorFor l), - Show (SelectorFor l), - Selector (SelectorFor l)) => LayoutSelect l a where - - -- The selector that is used to update the layout corresponding to the - -- selector. This selector must be an instance of the Selector class. - type SelectorFor l :: * - - -- Update applies a functor to the selected layout and maybe returns a result - -- and an updated layout. - update :: forall r m. (Monad m) => - -- The selector for this type. Determines which layout the function is - -- applied to. - SelectorFor l -> - -- The LayoutSelect being modified. - l a -> - -- Higher-ordered function to generically apply to the Layout associated - -- with the Selector. Works on all LayoutClass's. - (forall l'. (LayoutClass l' a) => l' a -> m (r, Maybe (l' a))) -> - - -- Returns a result r, and an updated LayoutSelect. - m (Maybe (r, l a)) - --- Instance for LayoutSelect for cons -instance (Read (l a), - LayoutClass l a, - LayoutSelect t a, - Show (SelectorFor t), - Read (SelectorFor t)) => - LayoutSelect (LCons l t) a where - - -- The SelectorFor Cons is Sel (SelectorFor t). This creates the structure - -- Sel (Sel (Sel ( ... (Sel End) .. ))) where the number of Sel's match the - -- number of Cons in this structure enforcing safe selection. - type SelectorFor (LCons l t) = Sel (SelectorFor t) - - -- The current layout in this Cons-list is selected. - update Sel (LCons layout t) fn = do - (r, layout') <- fn layout - return $ Just (r, LCons (fromMaybe layout layout') t) - - -- The current layout is not selected. Move on to another layout. - update (Skip s) (LCons l t) fn = - fmap (second $ \t' -> LCons l t') <$> update s t fn - --- LNil is a layout select. It doesn't do anything. Indeed update really can't --- be called on on this because that would require instantiating a End type. -instance LayoutSelect LNil a where - type SelectorFor LNil = End -- LNil cannot be selected. - update _ _ _ = return Nothing - --- Instance of layout class for LayoutList. The implementation for this --- just delegates to the underlying LayoutSelect class using the generic --- update method. -instance (Show (l a), Typeable l, LayoutSelect l a) => - LayoutClass (LayoutList l) a where - - runLayout (W.Workspace i (LayoutList idx l) ms) r = do - r <- update idx l $ \layout -> - runLayout (W.Workspace i layout ms) r - case r of - Nothing -> return ([], Nothing) - Just (r, la) -> return (r, Just (LayoutList idx la)) - - pureLayout (LayoutList idx l) r s = runIdentity $ do - r <- update idx l $ \layout -> return (pureLayout layout r s, Nothing) - case r of - Nothing -> return [] - Just (r, a) -> return r - - emptyLayout (LayoutList idx l) r = do - r <- update idx l $ \layout -> emptyLayout layout r - case r of - Nothing -> return ([], Nothing) - Just (r, la) -> return (r, Just (LayoutList idx la)) - - handleMessage (LayoutList idx l) (fromMessage -> Just (NavigateLayout fn)) = - return $ Just (LayoutList (fn idx) l) - - handleMessage (LayoutList idx l) m = do - r <- update idx l $ \layout -> ((),) <$> handleMessage layout m - return $ LayoutList idx . snd <$> r - - pureMessage (LayoutList idx l) m = runIdentity $ do - r <- update idx l $ \layout -> return ((), pureMessage layout m) - return $ LayoutList idx . snd <$> r - - description (LayoutList idx l) = runIdentity $ do - r <- update idx l $ \l -> return (description l, Nothing) - return $ - case r of - Nothing -> "No Layout" - Just (descr, _) -> descr diff --git a/src/Internal/Lib.hs b/src/Internal/Lib.hs deleted file mode 100644 index fdbc9a5..0000000 --- a/src/Internal/Lib.hs +++ /dev/null @@ -1,160 +0,0 @@ -{-# LANGUAGE RankNTypes #-} -module Internal.Lib where - -import Prelude hiding ((!!)) - -import XMonad.Actions.DynamicWorkspaces -import XMonad.Util.Run -import XMonad.Prompt -import XMonad.Prompt.Input -import XMonad.Prompt.Shell - -import Internal.PromptConfig - -import Data.Char -import Data.List hiding ((!!)) -import Data.List.Safe ((!!)) -import Data.Maybe -import Internal.Marking -import Text.Printf -import XMonad hiding (workspaces, Screen) -import XMonad.StackSet hiding (filter, focus) -import qualified Data.Map as Map -import Internal.DMenu -import Data.Ord (comparing) - -import qualified XMonad.StackSet as S -import Internal.Windows - -type WorkspaceName = Char -newtype Selector = Selector (forall a. (Eq a) => a -> [a] -> a) - -data WinPrompt = WinPrompt - -instance XPrompt WinPrompt where - showXPrompt _ = "[Window] " - commandToComplete _ = id - -data WorkspaceState = Current | Hidden | Visible - deriving (Ord, Eq, Enum) - --- Returns all the workspaces that are either visible, current or Hidden but --- have windows and that workspace's state. --- --- In other words, filters out workspaces that have no windows and are not --- visible. --- --- This function will sort the result by the workspace tag. -getPopulatedWorkspaces :: - (Ord i) => S.StackSet i l a sid sd -> [(WorkspaceState, S.Workspace i l a)] -getPopulatedWorkspaces (S.StackSet (S.Screen cur _ _) vis hi _) = - sortOn (tag . snd) $ - mapMaybe (\w@(S.Workspace _ _ s) -> fmap (const (Hidden, w)) s) hi ++ - map (\(S.Screen w _ _) -> (Visible, w)) vis ++ - [(Current, cur)] - -getHorizontallyOrderedScreens :: - StackSet wid l a ScreenId ScreenDetail -> - [Screen wid l a ScreenId ScreenDetail] --- ^ Returns a list of screens ordered from leftmost to rightmost. -getHorizontallyOrderedScreens windowSet = - flip sortBy screens $ \sc1 sc2 -> - let (SD (Rectangle x1 _ _ _)) = screenDetail sc1 - (SD (Rectangle x2 _ _ _)) = screenDetail sc2 - in x1 `compare` x2 - where - screens = current windowSet : visible windowSet - -getCurrentWorkspace :: X WorkspaceName -getCurrentWorkspace = withWindowSet $ - \(StackSet (Screen (Workspace t _ _) _ _) _ _ _) -> do - return (head t) - -gotoAccompaningWorkspace :: X () -gotoAccompaningWorkspace = do - cur <- getCurrentWorkspace - if isUpper cur - then gotoWorkspace (toLower cur) - else gotoWorkspace (toUpper cur) - -gotoWorkspace :: WorkspaceName -> X () -gotoWorkspace ch = pushHistory $ do - addHiddenWorkspace [ch] - windows $ greedyView $ return ch - -shiftToWorkspace :: WorkspaceName -> X () -shiftToWorkspace ch = do - addHiddenWorkspace [ch] - (windows . shift . return) ch - -swapWorkspace :: WorkspaceName -> X () -swapWorkspace toWorkspaceName = do - addHiddenWorkspace [toWorkspaceName] - windows $ \ss -> do - let fromWorkspace = tag $ workspace $ current ss - toWorkspace = [toWorkspaceName] in - StackSet (swapSc fromWorkspace toWorkspace $ current ss) - (map (swapSc fromWorkspace toWorkspace) $ visible ss) - (map (swapWs fromWorkspace toWorkspace) $ hidden ss) - (floating ss) - where - swapSc fromWorkspace toWorkspace (Screen ws a b) = - Screen (swapWs fromWorkspace toWorkspace ws) a b - - swapWs fromWorkspace toWorkspace ws@(Workspace t' l s) - | t' == fromWorkspace = Workspace toWorkspace l s - | t' == toWorkspace = Workspace fromWorkspace l s - | otherwise = ws - -fuzzyCompletion :: String -> String -> Bool -fuzzyCompletion str0 str1 = - all (`isInfixOf`l0) ws - where - ws = filter (not . all isSpace) $ words (map toLower str0) - l0 = map toLower str1 - -getString :: Window -> X String -getString = runQuery $ do - t <- title - a <- appName - return $ - if map toLower a `isInfixOf` map toLower t - then t - else printf "%s - %s" t a - -withRelativeWorkspace :: Selector -> (WorkspaceId -> WindowSet -> WindowSet) -> X () -withRelativeWorkspace (Selector selector) fn = - windows $ \ss -> - let tags = sort (tag . snd <$> filter (\x -> fst x /= Visible ) (getPopulatedWorkspaces ss)) - from = tag $ workspace $ current ss - to = selector from tags - in fn to ss - -next :: Selector -next = Selector $ \a l -> select a l l - where select n (x:y:xs) _ | n == x = y - select n [x] (y:_) | n == x = y - select n (x:xs) orig = select n xs orig - select n _ _ = n - -prev :: Selector -prev = Selector $ \a l -> - let (Selector fn) = next in fn a (reverse l) - -withScreen :: (WorkspaceId -> WindowSet -> WindowSet) -> Int -> X () -withScreen fn n = do - windows $ \windowSet -> - case getHorizontallyOrderedScreens windowSet !! n of - Nothing -> windowSet - Just screen -> fn (tag $ workspace screen) windowSet - -windowJump :: X () -windowJump = pushHistory $ do - windowTitlesToWinId <- withWindowSet $ \ss -> - Map.fromList <$> mapM (\wid -> (,) <$> getString wid <*> return wid) (allWindows ss) - - windowId <- runDMenuPromptWithMap "Window" (Just "#f542f5") windowTitlesToWinId - - case windowId of - Nothing -> return () - Just wid -> focus wid diff --git a/src/Internal/Logger.hs b/src/Internal/Logger.hs deleted file mode 100644 index e5824a4..0000000 --- a/src/Internal/Logger.hs +++ /dev/null @@ -1,32 +0,0 @@ -module Internal.Logger where - -import XMonad -import qualified XMonad.Util.ExtensibleState as XS -import System.IO - -import Internal.NoPersist - -newtype LoggerState = - LoggerState { - logHandle :: Maybe (NoPersist Handle) - } - -instance ExtensionClass LoggerState where - initialValue = LoggerState Nothing - -logs :: String -> X () -logs s = do - LoggerState handle' <- XS.get - - handle <- - case handle' of - Nothing -> do - handle <- io $ openFile "/tmp/xmonad.log" AppendMode - XS.put $ LoggerState $ Just $ NoPersist handle - return handle - - Just (NoPersist h) -> return h - - io $ do - hPutStrLn handle s - hFlush handle diff --git a/src/Internal/Marking.hs b/src/Internal/Marking.hs deleted file mode 100644 index 3ffb411..0000000 --- a/src/Internal/Marking.hs +++ /dev/null @@ -1,204 +0,0 @@ -{-# LANGUAGE ScopedTypeVariables #-} -module Internal.Marking ( - historyNext, historyPrev, - markCurrentWindow, pushHistory, - jumpToMark, jumpToLast, swapWithLastMark, - swapWithMark - ) where - -import Internal.Windows (mapWindows, findWindow, getLocationWorkspace) -import XMonad -import XMonad.StackSet hiding (focus) -import Data.IORef -import Data.Map (Map) -import Control.Monad (when) - -import System.FilePath -import System.IO -import Control.Exception -import System.Environment -import qualified Data.Sequence as Seq -import Data.Sequence (Seq(..)) - -import qualified XMonad.Util.ExtensibleState as XS - -import qualified Data.Map as Map - -{- Submodule that handles marking windows so they can be jumped back to. -} - -type Mark = Char - -historySize = 100 -- max number of history elements the tail. - -data History a = History [a] (Seq a) - deriving (Read, Show) - -instance Default (History a) where - - def = History [] Seq.empty - -seqPush :: a -> Seq a -> Seq a -seqPush elem s@(seq :|> _) | Seq.length s >= historySize = elem :<| seq -seqPush elem s = elem :<| s - -historyForward :: History a -> History a -historyForward (History (a:as) tail) = History as (seqPush a tail) -historyForward z = z - -historyBackward :: History a -> History a -historyBackward (History head (a :<| as)) = History (a : head) as -historyBackward z = z - -historyCurrent :: History a -> Maybe a -historyCurrent (History (a:_) _) = Just a -historyCurrent _ = Nothing - -historyPush :: (Eq a) => a -> History a -> History a -historyPush a h@(History (w : _) _) | a == w = h -historyPush a (History (w : _) tail) = History [a] (seqPush w tail) -historyPush a (History _ tail) = History [a] tail - -historySwap :: History a -> History a -historySwap (History (a:as) (t :<| ts)) = History (t : as) (seqPush a ts) -historySwap z = z - -historyLast :: History a -> Maybe a -historyLast (History _ (t :<| _)) = Just t -historyLast _ = Nothing - -data Spot = - WindowSpot Window | -- Focus is on a window. - TagSpot String -- Focus is on an (empty) tag - deriving (Read, Show, Eq, Ord) - -greedyFocus :: Spot -> X () -greedyFocus (WindowSpot win) = do - ws <- withWindowSet $ \ss -> - return $ getLocationWorkspace =<< findWindow ss win - - mapM_ (windows . greedyView . tag) ws - focus win -greedyFocus (TagSpot tag) = - windows $ greedyView tag - -data MarkState = - MarkState { - markStateMap :: Map Mark Window - , windowHistory :: History Spot - } deriving (Read, Show) - - -instance ExtensionClass MarkState where - initialValue = MarkState Map.empty def - extensionType = PersistentExtension - -changeHistory :: (History Spot -> History Spot) -> (MarkState -> MarkState) -changeHistory fn ms = ms { windowHistory = fn (windowHistory ms)} - -withMaybeFocused :: (Maybe Window -> X ()) -> X () -withMaybeFocused f = withWindowSet $ f . peek - -normalizeWindows :: X () -normalizeWindows = do - MarkState { windowHistory = h } <- XS.get - mapM_ greedyFocus (historyCurrent h) - --- greedyFocus :: Window -> X () --- greedyFocus win = do --- ws <- withWindowSet $ \ss -> --- return $ getLocationWorkspace =<< findWindow ss win --- --- mapM_ (windows . greedyView . tag) ws --- focus win - -markCurrentWindow :: Mark -> X () -markCurrentWindow mark = do - withFocused $ \win -> - XS.modify $ \state@MarkState {markStateMap = ms} -> - state { - markStateMap = Map.insert mark win ms - } - -pushHistory :: X () -> X () -pushHistory fn = do - withMaybeFocused $ \maybeWindowBefore -> do - case maybeWindowBefore of - (Just windowBefore) -> - XS.modify $ changeHistory (historyPush (WindowSpot windowBefore)) - Nothing -> - withWindowSet $ \ws -> - XS.modify $ changeHistory (historyPush (TagSpot (currentTag ws))) - - fn - - withMaybeFocused $ \maybeWindowAfter -> - case maybeWindowAfter of - Just windowAfter -> - XS.modify $ changeHistory (historyPush $ WindowSpot windowAfter) - Nothing -> - withWindowSet $ \ws -> - XS.modify $ changeHistory (historyPush $ TagSpot $ currentTag ws) - -withHistory :: (History Spot -> X ()) -> X () -withHistory fn = do - MarkState { windowHistory = w } <- XS.get - fn w - -jumpToLast :: X () -jumpToLast = do - XS.modify (changeHistory historySwap) - normalizeWindows - -jumpToMark :: Mark -> X () -jumpToMark mark = do - MarkState {markStateMap = m} <- XS.get - case Map.lookup mark m of - Nothing -> return () - Just w -> pushHistory $ - greedyFocus (WindowSpot w) - -setFocusedWindow :: a -> StackSet i l a s sd -> StackSet i l a s sd -setFocusedWindow - window - (StackSet (Screen (Workspace t l stack) a b) vis hid float) = - let newStack = - case stack of - Nothing -> Nothing - Just (Stack _ up down) -> Just (Stack window up down) in - StackSet (Screen (Workspace t l newStack) a b) vis hid float - -swapWithFocused :: (Ord a) => a -> StackSet i l a s sd -> StackSet i l a s sd -swapWithFocused winToSwap stackSet = - case peek stackSet of - Nothing -> stackSet - Just focused -> do - setFocusedWindow winToSwap $ - mapWindows ( - \w -> if w == winToSwap then focused else w) stackSet - -swapWithLastMark :: X () -swapWithLastMark = pushHistory $ withHistory $ \hist -> do - - case historyLast hist of - Just (WindowSpot win) -> - windows $ swapWithFocused win - Nothing -> return () - -swapWithMark :: Mark -> X () -swapWithMark mark = pushHistory $ do - MarkState {markStateMap = m} <- XS.get - - case Map.lookup mark m of - Nothing -> return () - Just winToSwap -> do - windows $ swapWithFocused winToSwap - -historyPrev :: X () -historyPrev = do - XS.modify $ changeHistory historyBackward - normalizeWindows - -historyNext :: X () -historyNext = do - XS.modify $ changeHistory historyForward - normalizeWindows diff --git a/src/Internal/MouseMotion.hs b/src/Internal/MouseMotion.hs deleted file mode 100644 index c72c824..0000000 --- a/src/Internal/MouseMotion.hs +++ /dev/null @@ -1,97 +0,0 @@ -{-# LANGUAGE ViewPatterns, BangPatterns #-} -module Internal.MouseMotion where - -import XMonad - -import Control.Monad (void, forever) -import Text.Printf -import Internal.Submap -import Control.Monad.Loops (iterateWhile) -import Control.Monad.Fix (fix) -import Internal.Logger - -import Linear.V2 -import Linear.Metric - -data Quadrant = NE | SE | SW | NW deriving (Enum, Show) -data Direction = CW | CCW deriving (Enum, Show) - -getQuadrant :: (Num a, Ord a) => (a, a) -> Quadrant -getQuadrant (x, y) | x >= 0 && y >= 0 = NE -getQuadrant (x, y) | x < 0 && y >= 0 = SE -getQuadrant (x, y) | x < 0 && y < 0 = SW -getQuadrant (x, y) = NW - - -getDirection :: Quadrant -> Quadrant -> Maybe Direction -getDirectory a b | a == b = Nothing -getDirection SW SE = Just CCW -getDirection SE NE = Just CCW -getDirection NE NW = Just CCW -getDirection NW SW = Just CCW -getDirection _ _ = Just CW - - -liftMouseMotionM :: X a -> MouseMotionM a -liftMouseMotionM = MouseMotionM . fmap Just - -motion :: MouseMotionM (V2 Int) -motion = MouseMotionM $ do - ev <- nextMotionOrButton - case ev of - Right button -> do - logs ("Button " ++ show button) - return Nothing - - Left motion -> return (Just $ uncurry V2 motion) - -motionSize :: Int -> MouseMotionM (V2 Int) -motionSize size = do - let fsize = fromIntegral size - - !firstmotion <- fmap fromIntegral <$> motion - - let get = do - !next <- motion - if distance (fmap fromIntegral next) firstmotion >= fsize - then return next - else get - - get - -runMouseMotionM :: MouseMotionM a -> X (Maybe a) -runMouseMotionM (MouseMotionM a) = a - -execMouseMotionM :: MouseMotionM () -> X () -execMouseMotionM = void . runMouseMotionM - --- Monad for capturing mouse motion. Terminates and holds Nothing when a --- button is pressed. -newtype MouseMotionM a = MouseMotionM (X (Maybe a)) - -instance Functor MouseMotionM where - fmap fn (MouseMotionM xma) = MouseMotionM (fmap (fmap fn) xma) - -instance Applicative MouseMotionM where - mf <*> ma = do - !f <- mf - !a <- ma - return (f a) - - pure = return - -instance Monad MouseMotionM where - return a = MouseMotionM (return (Just a)) - (MouseMotionM !xa) >>= fn = MouseMotionM $ do - !ma <- xa - case ma of - Just !a -> - let (MouseMotionM !xb) = fn a in xb - Nothing -> return Nothing - -mouseRotateMotion :: X () -> X () -> X () -mouseRotateMotion clockWise counterClockwise = execMouseMotionM doMouse - where - doMouse = forever $ do - v <- motion - liftMouseMotionM $ logs $ "Motion: " ++ show v diff --git a/src/Internal/NoPersist.hs b/src/Internal/NoPersist.hs deleted file mode 100644 index a67e649..0000000 --- a/src/Internal/NoPersist.hs +++ /dev/null @@ -1,23 +0,0 @@ --- Module for not persisting XMonad state. To be used with ExtensibleState --- for data types that cannot be persisted. -module Internal.NoPersist where - -import Data.Default (Default, def) -import Data.Typeable - -import XMonad (ExtensionClass(..)) - -newtype NoPersist a = NoPersist a - deriving (Typeable) - -instance Show (NoPersist a) where - show (NoPersist _) = show () - -instance (Default a) => Read (NoPersist a) where - readsPrec i s = map (\(_, s) -> (NoPersist def, s)) (readsPrec i s :: [((), String)]) - -instance (Default a) => Default (NoPersist a) where - def = NoPersist def - -instance (Default a, Typeable a) => ExtensionClass (NoPersist a) where - initialValue = NoPersist def diff --git a/src/Internal/PassMenu.hs b/src/Internal/PassMenu.hs deleted file mode 100644 index 5b031c0..0000000 --- a/src/Internal/PassMenu.hs +++ /dev/null @@ -1,13 +0,0 @@ -module Internal.PassMenu where - -import XMonad -import XMonad.Util.Run -import Control.Monad - -runPassMenu :: X () -runPassMenu = void $ - safeSpawn "rofi-pass" [ - "-p", "Password ", - "-theme-str", - "* {theme-color: #f54245;}"] - diff --git a/src/Internal/PromptConfig.hs b/src/Internal/PromptConfig.hs deleted file mode 100644 index 0db3027..0000000 --- a/src/Internal/PromptConfig.hs +++ /dev/null @@ -1,12 +0,0 @@ -module Internal.PromptConfig where - -import XMonad.Prompt - -xpConfig :: XPConfig -xpConfig = def { - font = "xft:Source Code Pro:size=10" - , bgColor = "#404040" - , fgColor = "#8888ff" - , promptBorderWidth = 0 - , height = 40 - } diff --git a/src/Internal/RebindKeys.hs b/src/Internal/RebindKeys.hs deleted file mode 100644 index 38af754..0000000 --- a/src/Internal/RebindKeys.hs +++ /dev/null @@ -1,119 +0,0 @@ - --- Module for intercepting key presses not explicity mapped in the key bindings. --- This uses some deep magic with grabKey and windows and everything else, but --- it makes window-specific key bindings awesome! -module Internal.RebindKeys where - -import XMonad - -import Text.Printf -import Control.Monad.Trans.Class (lift) -import Control.Monad (forM, forM_) -import Data.Default (Default, def) -import Data.Map (Map) -import qualified Data.Map as Map -import qualified XMonad.Util.ExtensibleState as XS -import Data.Monoid (All(..)) - -import Internal.Logger -import Internal.NoPersist - -type WindowHook = Query () - -newtype InterceptState = - InterceptState (NoPersist (Map (KeyMask, KeySym) (X ()))) - -newtype RemapState = - RemapState (NoPersist (Map (Window, (KeyMask, KeySym)) (X ()))) - -instance ExtensionClass InterceptState where - initialValue = InterceptState def - -instance ExtensionClass RemapState where - initialValue = RemapState def - -remapHook :: Event -> X All -remapHook event = do - RemapState (NoPersist map) <- XS.get - - case event of - KeyEvent { ev_window = win, ev_event_type = typ, ev_keycode = code, ev_state = m } - | typ == keyPress-> do - XConf {display = dpy, theRoot = rootw} <- ask - keysym <- io $ keycodeToKeysym dpy code 0 - - case Map.lookup (win, (m, keysym)) map of - - Just xdo -> do - xdo - return (All False) - - Nothing -> return (All True) - - _ -> return (All True) - -getKeyCodesForKeysym :: Display -> KeySym -> IO [KeyCode] -getKeyCodesForKeysym dpy keysym = do - let (minCode, maxCode) = displayKeycodes dpy - allCodes = [fromIntegral minCode .. fromIntegral maxCode] - - syms <- forM allCodes $ \code -> keycodeToKeysym dpy code 0 - let keysymMap' = Map.fromListWith (++) (zip syms [[code] | code <- allCodes]) - - -- keycodeToKeysym returns noSymbol for all unbound keycodes, and we don't - -- want to grab those whenever someone accidentally uses def :: KeySym - let keysymMap = Map.delete noSymbol keysymMap' - let keysymToKeycodes sym = Map.findWithDefault [] keysym keysymMap - - return $ keysymToKeycodes keysym - - -doGrab :: Display -> Window -> (KeyMask, KeySym) -> X () -doGrab dpy win (keyMask, keysym) = do - let grab kc m = io $ grabKey dpy kc m win True grabModeAsync grabModeAsync - - codes <- io $ getKeyCodesForKeysym dpy keysym - - forM_ codes $ \kc -> - mapM_ (grab kc . (keyMask .|.)) =<< extraModifiers - -disableKey :: (KeyMask, KeySym) -> WindowHook -disableKey key = remapKey key (return ()) - -remapKey :: (KeyMask, KeySym) -> X () -> WindowHook -remapKey keyFrom action = do - window <- ask - Query $ lift $ do - XConf { display = disp, theRoot = rootw } <- ask - doGrab disp window keyFrom - - XS.modify $ \(RemapState (NoPersist keyMap)) -> RemapState $ NoPersist $ - Map.insert (window, keyFrom) action keyMap - --- sendKey, but as a query. -sendKeyQ :: (KeyMask, KeySym) -> Query () -sendKeyQ key = do - win <- ask - liftX (sendKey key win) - -sendKey :: (KeyMask, KeySym) -> Window -> X () -sendKey (keymask, keysym) w = do - XConf { display = disp, theRoot = rootw } <- ask - - codes <- io $ getKeyCodesForKeysym disp keysym - - case codes of - (keycode:_) -> - io $ allocaXEvent $ \xEv -> do - setEventType xEv keyPress - setKeyEvent xEv w rootw none keymask keycode True - sendEvent disp w True keyPressMask xEv - - setEventType xEv keyRelease - sendEvent disp w True keyReleaseMask xEv - - _ -> return () - -rebindKey :: (KeyMask, KeySym) -> (KeyMask, KeySym) -> WindowHook -rebindKey keyFrom keyTo = - (remapKey keyFrom . sendKey keyTo) =<< ask diff --git a/src/Internal/ScreenRotate.hs b/src/Internal/ScreenRotate.hs deleted file mode 100644 index 8108381..0000000 --- a/src/Internal/ScreenRotate.hs +++ /dev/null @@ -1,19 +0,0 @@ -module Internal.ScreenRotate where - -import XMonad.StackSet as W - -screenRotateBackward :: W.StackSet i l a sid sd -> W.StackSet i l a sid sd -screenRotateBackward (W.StackSet current visible others floating) = do - let screens = current : visible - workspaces = tail $ cycle $ map W.workspace screens - (current':visible') = zipWith (\s w -> s {workspace = w} ) screens workspaces - in W.StackSet current' visible' others floating - -screenRotateForward :: W.StackSet i l a sid sd -> W.StackSet i l a sid sd -screenRotateForward (W.StackSet current visible others floating) = do - let screens = current : visible - workspaces = rcycle $ map W.workspace screens - (current':visible') = zipWith (\s w -> s {workspace = w} ) screens workspaces - in W.StackSet current' visible' others floating - - where rcycle l = last l : l diff --git a/src/Internal/Submap.hs b/src/Internal/Submap.hs deleted file mode 100644 index 0e54c43..0000000 --- a/src/Internal/Submap.hs +++ /dev/null @@ -1,104 +0,0 @@ -module Internal.Submap ( - mapNextString, - mapNextStringWithKeysym, - submapButtonsWithKey, - nextButton, - nextMotion, - nextMotionOrButton, - module X) where - -import XMonad hiding (keys) -import Control.Monad.Fix (fix) -import qualified Data.Map as Map -import Data.Map (Map) - -import XMonad.Actions.Submap as X - -{- - - Like submap fram XMonad.Actions.Submap, but sends the string from - - XLookupString to the function along side the keysym. - - - - This function allows mappings where the mapped string might be important, - - but also allows submappings for keys that may not have a character associated - - with them (for example, the function keys). - -} -mapNextStringWithKeysym :: (KeyMask -> KeySym -> String -> X a) -> X a -mapNextStringWithKeysym fn = do - XConf { theRoot = root, display = d } <- ask - io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime - - (m, str, keysym) <- io $ allocaXEvent $ \p -> fix $ \nextkey -> do - maskEvent d keyPressMask p - KeyEvent { ev_keycode = code, ev_state = m } <- getEvent p - keysym <- keycodeToKeysym d code 0 - (_, str) <- lookupString (asKeyEvent p) - - if isModifierKey keysym - then nextkey - else return (m, str, keysym) - - io $ ungrabKeyboard d currentTime - - fn m keysym str - -{- Like submap, but on the character typed rather than the kysym. -} -mapNextString :: (KeyMask -> String -> X a) -> X a -mapNextString fn = mapNextStringWithKeysym (\m _ s -> fn m s) - -{- Grabs the mouse and returns the next button press. -} -nextButton :: X (ButtonMask, Button) -nextButton = do - XConf { theRoot = root, display = d } <- ask - io $ grabPointer d root False buttonPressMask grabModeAsync grabModeAsync 0 0 currentTime - - ret <- io $ allocaXEvent $ \xEv -> do - maskEvent d buttonPressMask xEv - ButtonEvent { ev_button = button, ev_state = m } <- getEvent xEv - return (m, button) - - io $ ungrabPointer d currentTime - - return ret - -{- Grabs the mouse and reports the next mouse motion. -} -nextMotion :: X (Int, Int) -nextMotion = do - XConf { theRoot = root, display = d } <- ask - io $ grabPointer d root False pointerMotionMask grabModeAsync grabModeAsync 0 0 currentTime - - ret <- io $ allocaXEvent $ \xEv -> do - maskEvent d pointerMotionMask xEv - MotionEvent { ev_x = x, ev_y = y } <- getEvent xEv - return (fromIntegral x, fromIntegral y) - - io $ ungrabPointer d currentTime - - return ret - -{- Grabs the mouse and reports the next mouse motion or button press. -} -nextMotionOrButton :: X (Either (Int, Int) (ButtonMask, Button)) -nextMotionOrButton = do - XConf { theRoot = root, display = d } <- ask - io $ grabPointer d root False (pointerMotionMask .|. buttonPressMask) grabModeAsync grabModeAsync 0 0 currentTime - - ret <- io $ allocaXEvent $ \xEv -> do - maskEvent d (pointerMotionMask .|. buttonPressMask) xEv - ev <- getEvent xEv - case ev of - MotionEvent { ev_x = x, ev_y = y } -> - return $ Left (fromIntegral x, fromIntegral y) - ButtonEvent { ev_button = button, ev_state = m } -> - return $ Right (m, button) - - io $ ungrabPointer d currentTime - - return ret - -submapButtonsWithKey :: - ((ButtonMask, Button) -> Window -> X ()) -> Map (ButtonMask, Button) (Window -> X ()) -> Window -> X () -submapButtonsWithKey defaultAction actions window = do - arg <- nextButton - - case Map.lookup arg actions of - Nothing -> defaultAction arg window - Just fn -> fn window diff --git a/src/Internal/Swallow.hs b/src/Internal/Swallow.hs deleted file mode 100644 index 3e4112f..0000000 --- a/src/Internal/Swallow.hs +++ /dev/null @@ -1,29 +0,0 @@ -module Internal.Swallow ( - swallowHook, setSwallowEnabled, isSwallowEnabled, toggleSwallowEnabled) where - -import XMonad -import Data.Monoid (All) -import XMonad.Hooks.WindowSwallowing -import XMonad.Util.ExtensibleState as XS - -data DisableSwallow = DisableSwallow Bool deriving (Show) - -swallowHook :: Event -> X All -swallowHook = swallowEventHook (className =? "Alacritty") $ - liftX $ do - (DisableSwallow disable) <- XS.get - return (not disable) - -isSwallowEnabled :: X Bool -isSwallowEnabled = do - (DisableSwallow b) <- XS.get - return (not b) - -setSwallowEnabled :: Bool -> X () -setSwallowEnabled enable = XS.modify $ const $ DisableSwallow $ not enable - -toggleSwallowEnabled :: X () -toggleSwallowEnabled = (setSwallowEnabled . not) =<< isSwallowEnabled - -instance ExtensionClass DisableSwallow where - initialValue = DisableSwallow False diff --git a/src/Internal/SwapMaster.hs b/src/Internal/SwapMaster.hs deleted file mode 100644 index e7ade19..0000000 --- a/src/Internal/SwapMaster.hs +++ /dev/null @@ -1,41 +0,0 @@ -{- Swap window with the master, but save it. -} -module Internal.SwapMaster (swapMaster) where - -import qualified XMonad.StackSet as W - -import Internal.Windows (mapWindows, getMaster, swapWindows) -import Control.Monad.Trans.Maybe -import XMonad (Window, ExtensionClass(..), X(..), windows, windowset) -import Control.Monad (void) -import Control.Monad.Trans (lift) -import Data.Maybe (fromMaybe) -import Control.Monad.State (gets) - -import qualified XMonad.Util.ExtensibleState as XS - -newtype LastWindow = LastWindow { - lastWindow :: Maybe Window - } deriving (Show, Read) - -instance ExtensionClass LastWindow where - initialValue = LastWindow Nothing - -hoist :: (Monad m) => Maybe a -> MaybeT m a -hoist = MaybeT . return - -swapMaster :: X () -swapMaster = void $ runMaybeT $ do - ss <- gets windowset - - focused <- hoist $ W.peek ss - master <- hoist $ getMaster ss - - if focused == master - then do - lw <- MaybeT $ lastWindow <$> XS.get - lift $ windows (swapWindows focused lw) - else lift $ windows (swapWindows focused master) - - lift $ do - XS.put (LastWindow $ Just master) - windows W.focusMaster diff --git a/src/Internal/Windows.hs b/src/Internal/Windows.hs deleted file mode 100644 index 35f093c..0000000 --- a/src/Internal/Windows.hs +++ /dev/null @@ -1,86 +0,0 @@ -module Internal.Windows where - -import XMonad (windowset, X, Window, get) - -import Control.Applicative ((<|>)) -import XMonad.StackSet (Stack(..), StackSet(..), Screen(..), Workspace(..), peek, integrate, integrate', allWindows) -import Data.Maybe (listToMaybe, catMaybes) -import qualified Data.Map as Map - -mapWindows :: (Ord a, Ord b) => (a -> b) -> StackSet i l a s sd -> StackSet i l b s sd -mapWindows fn (StackSet cur vis hid float) = - StackSet - (mapWindowsScreen cur) - (map mapWindowsScreen vis) - (map mapWindowsWorkspace hid) - (Map.mapKeys fn float) - where - mapWindowsScreen (Screen work a b) = Screen (mapWindowsWorkspace work) a b - mapWindowsWorkspace (Workspace t l stack) = - Workspace t l (fmap (mapStack fn) stack) - --- | What genius decided to hide the instances for the Stack type!!??? -mapStack :: (a -> b) -> Stack a -> Stack b -mapStack fn (Stack focus up down) = Stack (fn focus) (map fn up) (map fn down) - -getMaster :: StackSet i l a s sd -> Maybe a -getMaster (StackSet (Screen (Workspace _ _ ss) _ _) _ _ _) = - head . integrate <$> ss - -swapWindows :: (Ord a) => a -> a -> StackSet i l a s d -> StackSet i l a s d -swapWindows wa wb = mapWindows $ \w -> - case w of - _ | w == wa -> wb - _ | w == wb -> wa - _ -> w - -data WindowLocation i l a s sd = - OnScreen (Screen i l a s sd) | - OnHiddenWorkspace (Workspace i l a) | - Floating - -getLocationWorkspace :: WindowLocation i l a s sd -> Maybe (Workspace i l a) -getLocationWorkspace (OnScreen (Screen w _ _)) = Just w -getLocationWorkspace (OnHiddenWorkspace w) = Just w -getLocationWorkspace _ = Nothing - -workspaceMember :: (Eq a) => Workspace i l a -> a -> Bool -workspaceMember (Workspace _ _ s) w = w `elem` integrate' s - -forAllWindows :: (Window -> X ()) -> X () -forAllWindows fn = do - stackSet <- windowset <$> get - mapM_ fn (allWindows stackSet) - -getFocusedWindow :: X (Maybe Window) -getFocusedWindow = do - peek . windowset <$> get - -{- Finds a Window and returns the screen its on and the workspace its on. - - Returns nothing if the window doesn't exist. - - - - If the window is not a screen Just (Nothing, workspace) is returned. - - If the window is a floating window Just (Nothing, Nothing) is returned. -} -findWindow :: - (Eq a) => StackSet i l a s sd -> a -> Maybe (WindowLocation i l a s sd) -findWindow (StackSet cur vis hid float) win = - listToMaybe . catMaybes $ - map findWindowScreen (cur : vis) ++ - map findWindowWorkspace hid ++ - [findWindowFloat] - - where - findWindowScreen s@(Screen ws _ _) = - if workspaceMember ws win - then Just (OnScreen s) - else Nothing - - findWindowWorkspace w = - if workspaceMember w win - then Just (OnHiddenWorkspace w) - else Nothing - - findWindowFloat = - if win `elem` Map.keys float - then Just Floating - else Nothing diff --git a/src/Internal/XMobarLog.hs b/src/Internal/XMobarLog.hs deleted file mode 100644 index c0aa2a7..0000000 --- a/src/Internal/XMobarLog.hs +++ /dev/null @@ -1,78 +0,0 @@ -module Internal.XMobarLog ( XMobarLog, spawnXMobar, xMobarLogHook ) where - -import Control.Arrow (second) -import Control.Monad (forM_) -import Control.Monad.Writer (tell, execWriter) -import Data.List (sortBy) -import Data.Maybe (mapMaybe) -import Data.Ord (comparing) -import Internal.LayoutDraw (drawLayout) -import System.IO (Handle, hSetEncoding, hPutStrLn, utf8) -import XMonad.Util.NamedWindows (getName) -import XMonad.Util.Run (spawnPipe) -import XMonad (X) -import Internal.Lib (getPopulatedWorkspaces, WorkspaceState(..)) - -import qualified XMonad as X -import qualified XMonad.StackSet as S - -data XMobarLog = XMobarLog Handle - --- The log hook for XMobar. This is a custom log hook that does not use any --- of the Xmonad dynamic log libraries. --- --- This is because the given dynamic log libraries don't handle unicode properly --- and this has been causing issues. It is also more flexible and frankly easier --- to just DIY. - -spawnXMobar :: IO XMobarLog -spawnXMobar = do - pipe <- spawnPipe "xmobar" - hSetEncoding pipe utf8 - return (XMobarLog pipe) - - --- XMonad Log Hook meant to be used with the XMonad config logHook. -xMobarLogHook :: XMobarLog -> X () -xMobarLogHook (XMobarLog xmproc) = do - (_, _, layoutXpm) <- drawLayout - - winset <- X.gets X.windowset - title <- maybe (pure "") (fmap show . getName) . S.peek $ winset - let wss = getPopulatedWorkspaces winset - - X.liftIO $ do - hPutStrLn xmproc $ trunc 80 $ execWriter $ do - tell layoutXpm - tell $ "<fc=#404040> │ </fc>" - - forM_ wss $ \(t, ws) -> do - case t of - Current -> tell "<fn=1><fc=#ff8888>" - Visible -> tell "<fn=6><fc=#8888ff>" - Hidden -> tell "<fn=2><fc=#888888>" - tell (S.tag ws) - tell " </fc></fn>" - - tell $ "<fc=#404040>│ </fc><fc=#a0a0a0><fn=3>" - tell $ title - tell $ "</fn></fc>" - --- Truncate an XMobar string to the provided number of _visible_ characters. --- This is to keep long window titles from overrunning the whole bar. -trunc :: Int -> String -> String -trunc amt str = reverse $ trunc' False amt str [] - where - trunc' _ _ [] acc = acc - trunc' ignore amt (a:as) acc = - case a of - '<' -> trunc' True amt as (a : acc) - '>' -> trunc' False amt as (a : acc) - _ -> - if ignore - then trunc' True amt as (a : acc) - else - case amt of - 0 -> trunc' False 0 as acc - 3 -> trunc' False 0 as ("..." ++ acc) - _ -> trunc' False (amt - 1) as (a : acc) |