diff options
Diffstat (limited to '')
-rw-r--r-- | XMonad/Util/RemoteWindows.hs | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/XMonad/Util/RemoteWindows.hs b/XMonad/Util/RemoteWindows.hs new file mode 100644 index 0000000..8eeb025 --- /dev/null +++ b/XMonad/Util/RemoteWindows.hs @@ -0,0 +1,90 @@ +----------------------------------------------------------------------------- +-- | +-- Module : XMonad.Util.RemoteWindows +-- Copyright : (c) Anton Vorontsov <anton@enomsg.org> 2014 +-- License : BSD-style (as xmonad) +-- +-- Maintainer : Anton Vorontsov <anton@enomsg.org> +-- Stability : unstable +-- Portability : unportable +-- +-- This module implements a proper way of finding out whether the window +-- is remote or local. +-- +-- Just checking for a hostname and WM_CLIENT_MACHINE being equal is often +-- not enough because the hostname is a changing subject (without any +-- established notification mechanisms), and thus WM_CLIENT_MACHINE and +-- the hostname can diverge even for a local window. +-- +-- This module solves the problem. As soon as there is a new window +-- created, we check the hostname and WM_CLIENT_MACHINE, and then we cache +-- the result into the XMONAD_REMOTE property. +-- +-- Notice that XMonad itself does not know anything about hostnames, nor +-- does it have any dependency on Network.* modules. For this module it is +-- not a problem: you can provide a mean to get the hostname through your +-- config file (see usage). Or, if you don't like the hassle of handling +-- dynamic hostnames (suppose your hostname never changes), it is also +-- fine: this module will fallback to using environment variables. +-- +----------------------------------------------------------------------------- + +module XMonad.Util.RemoteWindows + ( -- $usage + isLocalWindow + , manageRemote + , manageRemoteG + ) where + +import XMonad +import XMonad.Util.WindowProperties +import Data.Monoid +import Data.Maybe +import Control.Monad +import System.Posix.Env + +-- $usage +-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@: +-- +-- > import XMonad +-- > import XMonad.Util.RemoteWindows +-- > import Network.BSD +-- > +-- > main = xmonad def +-- > { manageHook = manageRemote =<< io getHostName } + +guessHostName :: IO String +guessHostName = pickOneMaybe `liftM` (getEnv `mapM` vars) + where + pickOneMaybe = last . (mzero:) . take 1 . catMaybes + vars = ["XAUTHLOCALHOSTNAME","HOST","HOSTNAME"] + +setRemoteProp :: Window -> String -> X () +setRemoteProp w host = do + d <- asks display + p <- getAtom "XMONAD_REMOTE" + t <- getAtom "CARDINAL" + v <- hasProperty (Machine host) w + io $ changeProperty32 d w p t propModeReplace + [fromIntegral . fromEnum $ not v] + +-- | Given a window, tell if it is a local or a remote process. Normally, +-- it checks XMONAD_REMOTE property. If it does not exist (i.e. the +-- manageRemote hook was not deployed in user's config), it falls back to +-- checking environment variables and assuming that hostname never +-- changes. +isLocalWindow :: Window -> X Bool +isLocalWindow w = getProp32s "XMONAD_REMOTE" w >>= \p -> case p of + Just [y] -> return $ y == 0 + _ -> io guessHostName >>= \host -> hasProperty (Machine host) w + +-- | Use this hook to let XMonad properly track remote/local windows. For +-- example, @manageHook = manageRemote =<< io getHostName@. +manageRemote :: String -> ManageHook +manageRemote host = ask >>= \w -> liftX (setRemoteProp w host) >> return mempty + +-- | Use this hook if you want to manage XMONAD_REMOTE properties, but +-- don't want to use an external getHostName in your config. That way you +-- are retreating to environment variables. +manageRemoteG :: ManageHook +manageRemoteG = manageRemote =<< io guessHostName |