module Rahm.Desktop.Common where import Prelude hiding ((!!)) import Control.Monad (void, when, forM_) import Control.Monad.Trans.Maybe import XMonad.Util.Run import XMonad.Prompt import XMonad.Prompt.Input import XMonad.Prompt.Shell import XMonad.Util.XUtils import Rahm.Desktop.PromptConfig import Data.Char import Data.List hiding ((!!)) import Data.List.Safe ((!!)) import Data.Maybe import Text.Printf import XMonad hiding (workspaces, Screen) import qualified Data.Map as Map import Rahm.Desktop.DMenu import Data.Ord (comparing) import qualified Rahm.Desktop.StackSet as S -- A location is a workspace and maybe a window with that workspace. data Location = Location { locationWorkspace :: WorkspaceId, locationWindow :: Maybe Window } deriving (Read, Show, Eq, Ord) focusLocation :: Location -> X () focusLocation (Location ws Nothing) = windows $ S.greedyView ws focusLocation (Location _ (Just win)) = windows $ S.focusWindow win masterWindow :: MaybeT X Window masterWindow = MaybeT $ withWindowSet $ \ss -> let windows = (S.integrate' . S.stack . S.workspace . S.current) ss in case windows of (a:_) -> return $ Just a _ -> return Nothing windowsInWorkspace :: WorkspaceId -> X [Location] windowsInWorkspace wid = withWindowSet $ return . concatMap (\ws -> if S.tag ws == wid then map (Location wid . Just) $ S.integrate' (S.stack ws) else []) . S.workspaces data WinPrompt = WinPrompt instance XPrompt WinPrompt where showXPrompt _ = "[Window] " commandToComplete _ = id 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 askWindowId :: X (Maybe [Window]) askWindowId = do windowTitlesToWinId <- withWindowSet $ \ss -> Map.fromListWith (++) <$> mapM (\wid -> (,) <$> getString wid <*> return [wid]) (S.allWindows ss) runDMenuPromptWithMap "Window" (Just "#f542f5") windowTitlesToWinId windowJump :: X () windowJump = mapM_ (focus . head) =<< askWindowId -- Temporarily set the border color of the given windows. withBorderColor :: String -> [Window] -> X a -> X a withBorderColor color wins fn = do d <- asks display px <- stringToPixel d color oPx <- stringToPixel d =<< asks (normalBorderColor . config) fPx <- stringToPixel d =<< asks (focusedBorderColor . config) colorName <- io (pixelToString d px) oColorName <- io (pixelToString d oPx) fColorName <- io (pixelToString d fPx) forM_ wins $ \w -> setWindowBorderWithFallback d w colorName px ret <- fn withFocused $ \fw -> do forM_ wins $ \w -> when (w /= fw) $ setWindowBorderWithFallback d w oColorName oPx setWindowBorderWithFallback d fw fColorName fPx return ret withBorderWidth :: Int -> [Window] -> X a -> X a withBorderWidth width ws fn = do d <- asks display forM_ ws $ \window -> io $ setWindowBorderWidth d window $ fromIntegral width ret <- fn forM_ ws $ \window -> io $ setWindowBorderWidth d window 2 refresh return ret gotoWorkspace :: WorkspaceId -> X () gotoWorkspace wid = windows $ S.greedyView wid moveLocationToWorkspace :: Location -> WorkspaceId -> X () moveLocationToWorkspace (Location _ (Just win)) wid = windows $ S.shiftWin wid win moveLocationToWorkspace _ _ = return () getCurrentWorkspace :: X WorkspaceId getCurrentWorkspace = withWindowSet $ \(S.StackSet (S.Screen (S.Workspace t _ _) _ _) _ _ _) -> do return t getCurrentLocation :: X Location getCurrentLocation = do ws <- getCurrentWorkspace win <- withWindowSet (return . S.peek) return (Location ws win) runMaybeT_ :: (Monad m) => MaybeT m a -> m () runMaybeT_ = void . runMaybeT