aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--XMonad/Layout/Stoppable.hs15
-rw-r--r--XMonad/Util/RemoteWindows.hs90
-rw-r--r--xmonad-contrib.cabal1
3 files changed, 97 insertions, 9 deletions
diff --git a/XMonad/Layout/Stoppable.hs b/XMonad/Layout/Stoppable.hs
index 35c3c01..5c95aa1 100644
--- a/XMonad/Layout/Stoppable.hs
+++ b/XMonad/Layout/Stoppable.hs
@@ -46,10 +46,10 @@ module XMonad.Layout.Stoppable
import XMonad
import XMonad.Actions.WithAll
import XMonad.Util.WindowProperties
+import XMonad.Util.RemoteWindows
import XMonad.Util.Timer
import XMonad.StackSet hiding (filter)
import XMonad.Layout.LayoutModifier
-import System.Posix.Env
import System.Posix.Signals
import Data.Maybe
import Control.Monad
@@ -67,8 +67,10 @@ import Control.Monad
-- proccesses, which means that it needs to know the hostname, so it looks
-- for environment variables (e.g. HOST).
--
--- Beware that as of now this module does not support dynamically changing
--- hostnames.
+-- Environment variables will work for most cases, but won't work if the
+-- hostname changes. To cover dynamic hostnames case, in addition to
+-- layoutHook you have to provide manageHook from
+-- "XMonad.Util.RemoteWindows" module.
--
-- For more detailed instructions on editing the layoutHook see:
--
@@ -80,12 +82,7 @@ signalWindow s w = do
io $ (signalProcess s . fromIntegral) `mapM_` fromMaybe [] pid
signalLocalWindow :: Signal -> Window -> X ()
-signalLocalWindow s w = do
- host <- io $ pickOneMaybe `liftM` (getEnv `mapM` vars)
- hasProperty (Machine host) w >>= flip when (signalWindow s w)
- where
- pickOneMaybe = last . (mzero:) . take 1 . catMaybes
- vars = ["XAUTHLOCALHOSTNAME","HOST","HOSTNAME"]
+signalLocalWindow s w = isLocalWindow w >>= flip when (signalWindow s w)
withAllOn :: (a -> X ()) -> Workspace i l a -> X ()
withAllOn f wspc = f `mapM_` integrate' (stack wspc)
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
diff --git a/xmonad-contrib.cabal b/xmonad-contrib.cabal
index 166d217..cc605b5 100644
--- a/xmonad-contrib.cabal
+++ b/xmonad-contrib.cabal
@@ -307,6 +307,7 @@ library
XMonad.Util.NamedWindows
XMonad.Util.Paste
XMonad.Util.PositionStore
+ XMonad.Util.RemoteWindows
XMonad.Util.Replace
XMonad.Util.Run
XMonad.Util.Scratchpad