aboutsummaryrefslogtreecommitdiffstats
path: root/XMonad/Hooks/FadeWindows.hs
diff options
context:
space:
mode:
authorBrandon S Allbery KF8NH <allbery.b@gmail.com>2011-02-26 01:24:36 +0100
committerBrandon S Allbery KF8NH <allbery.b@gmail.com>2011-02-26 01:24:36 +0100
commit21773f2888ef818ba6f3cd0b8f150939fdd01965 (patch)
tree7b4e6913284db35f299a9fe0f9990c3d9b66c9b0 /XMonad/Hooks/FadeWindows.hs
parent5328e0918c3995bb6355670b44805b3853684f41 (diff)
downloadXMonadContrib-21773f2888ef818ba6f3cd0b8f150939fdd01965.tar.gz
XMonadContrib-21773f2888ef818ba6f3cd0b8f150939fdd01965.tar.xz
XMonadContrib-21773f2888ef818ba6f3cd0b8f150939fdd01965.zip
XMonad.Hooks.FadeWindows: A generalized window fading hook
Ignore-this: f21d1085ecca26602631f46c45bc198b darcs-hash:20110226002436-8238f-94884b9edfc4117dba16642bb1f17a719abbbe25.gz
Diffstat (limited to 'XMonad/Hooks/FadeWindows.hs')
-rw-r--r--XMonad/Hooks/FadeWindows.hs221
1 files changed, 221 insertions, 0 deletions
diff --git a/XMonad/Hooks/FadeWindows.hs b/XMonad/Hooks/FadeWindows.hs
new file mode 100644
index 0000000..9e72e02
--- /dev/null
+++ b/XMonad/Hooks/FadeWindows.hs
@@ -0,0 +1,221 @@
+{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module : XMonad.Hooks.FadeWindows
+-- Copyright : Brandon S Allbery KF8NH <allbery.b@gmail.com>
+-- License : BSD
+--
+-- Maintainer : Brandon S Allbery KF8NH
+-- Stability : unstable
+-- Portability : unportable
+--
+-- A more flexible and general compositing interface than FadeInactive.
+-- Windows can be selected and opacity specified by means of FadeHooks,
+-- which are very similar to ManageHooks and use the same machinery.
+--
+-----------------------------------------------------------------------------
+
+module XMonad.Hooks.FadeWindows (-- * Usage
+ -- $usage
+
+ -- * The 'logHook' for window fading
+ fadeWindowsLogHook
+
+ -- * The 'FadeHook'
+ ,FadeHook
+ ,Opacity
+ ,idFadeHook
+
+ -- * Predefined 'FadeHook's
+ ,opaque
+ ,solid
+ ,transparent
+ ,invisible
+ ,transparency
+ ,translucence
+ ,fadeBy
+ ,opacity
+ ,fadeTo
+
+ -- * 'handleEventHook' for mapped/unmapped windows
+ ,fadeWindowsEventHook
+
+ -- * 'doF' for simple hooks
+ ,doS
+
+ -- * Useful 'Query's for 'FadeHook's
+ ,isFloating
+ ,isUnfocused
+ ) where
+
+import XMonad.Core
+import XMonad.ManageHook (liftX)
+import qualified XMonad.StackSet as W
+
+import XMonad.Hooks.FadeInactive (setOpacity
+ ,isUnfocused
+ )
+
+import Control.Monad (forM_)
+import Control.Monad.Reader (ask
+ ,asks)
+import Control.Monad.State (gets)
+import qualified Data.Map as M
+import Data.Monoid
+
+import Graphics.X11.Xlib.Extras (Event(..))
+
+-- $usage
+-- To use this module, make sure your @xmonad@ core supports generalized
+-- 'ManageHook's (check the type of 'idHook'; if it's @ManageHook@ then
+-- your @xmonad@ is too old) and then add @fadeWindowsLogHook@ to your
+-- 'logHook' and @fadeWindowsEventHook@ to your 'handleEventHook':
+--
+-- > , logHook = fadeWindowsLogHook myFadeHook
+-- > , handleEventHook = fadeWindowsEventHook
+-- > {- ... -}
+-- >
+-- > myFadeHook = composeAll [isUnfocused --> transparency 0.2
+-- > , opaque
+-- > ]
+--
+-- The above is like FadeInactive with a fade value of 0.2.
+--
+-- FadeHooks do not accumulate; instead, they compose from right to
+-- left like 'ManageHook's, so the above example @myFadeHook@ will
+-- render unfocused windows at 4/5 opacity and the focused window
+-- as opaque. The 'opaque' hook above is optional, by the way, as any
+-- unmatched window will be opaque by default.
+--
+-- This module is best used with "XMonad.Hooks.MoreManageHelpers", which
+-- exports a number of Queries that can be used in either @ManageHook@
+-- or @FadeHook@.
+--
+-- Note that you need a compositing manager such as @xcompmgr@,
+-- @dcompmgr@, or @cairo-compmgr@ for window fading to work. If you
+-- aren't running a compositing manager, the opacity will be recorded
+-- but won't take effect until a compositing manager is started.
+--
+-- For more detailed instructions on editing the 'logHook' see:
+--
+-- "XMonad.Doc.Extending#The_log_hook_and_external_status_bars"
+--
+-- For more detailed instructions on editing the 'handleEventHook',
+-- see:
+--
+-- "XMonad.Doc.Extending#Editing_the_event_hook"
+-- (which sadly doesnt exist at the time of writing...)
+--
+-- /WARNING:/ This module is very good at triggering bugs in
+-- compositing managers. Symptoms range from windows not being
+-- repainted until the compositing manager is restarted or the
+-- window is unmapped and remapped, to the machine becoming sluggish
+-- until the compositing manager is restarted (at which point a
+-- popup/dialog will suddenly appear; apparently it's getting into
+-- a tight loop trying to fade the popup in). I find it useful to
+-- have a key binding to restart the compositing manager; for example,
+--
+-- main = xmonad $ defaultConfig {
+-- {- ... -}
+-- }
+-- `additionalKeysP`
+-- [("M-S-4",spawn "killall xcompmgr; sleep 1; xcompmgr -cCfF &")]
+-- {- ... -}
+-- ]
+--
+-- (See "XMonad.Util.EZConfig" for 'additionalKeysP'.)
+
+-- a window opacity to be carried in a Query. OEmpty is sort of a hack
+-- to make it obay the monoid laws
+data Opacity = Opacity Rational | OEmpty
+
+instance Monoid Opacity where
+ mempty = OEmpty
+ r `mappend` OEmpty = r
+ _ `mappend` r = r
+
+-- | A FadeHook is similar to a ManageHook, but records window opacity.
+type FadeHook = Query Opacity
+
+-- | Render a window fully opaque.
+opaque :: FadeHook
+opaque = doS (Opacity 1)
+
+-- | Render a window fully transparent.
+transparent :: FadeHook
+transparent = doS (Opacity 0)
+
+-- | Specify a window's transparency.
+transparency :: Rational -- ^ The window's transparency as a fraction.
+ -- @transparency 1@ is the same as 'transparent',
+ -- whereas @transparency 0@ is the same as 'opaque'.
+ -> FadeHook
+transparency = doS . Opacity . (1-) . clampRatio
+
+-- | Specify a window's opacity; this is the inverse of 'transparency'.
+opacity :: Rational -- ^ The opacity of a window as a fraction.
+ -- @opacity 1@ is the same as 'opaque',
+ -- whereas @opacity 0@ is the same as 'transparent'.
+ -> FadeHook
+opacity = doS . Opacity . clampRatio
+
+fadeTo, translucence, fadeBy :: Rational -> FadeHook
+-- ^ An alias for 'transparency'.
+fadeTo = transparency
+-- ^ An alias for 'transparency'.
+translucence = transparency
+-- ^ An alias for 'transparency'.
+fadeBy = opacity
+
+invisible, solid :: FadeHook
+-- ^ An alias for 'transparent'.
+invisible = transparent
+-- ^ An alias for 'opaque'.
+solid = opaque
+
+-- | Like 'doF', but usable with 'ManageHook'-like hooks that
+-- aren't 'Query' wrapped around transforming functions ('Endo').
+doS :: Monoid m => m -> Query m
+doS = return
+
+-- | The identity 'FadeHook', which renders windows 'opaque'.
+idFadeHook :: FadeHook
+idFadeHook = opaque
+
+-- | A Query to determine if a window is floating.
+isFloating :: Query Bool
+isFloating = ask >>= \w -> liftX . gets $ M.member w . W.floating . windowset
+
+-- boring windows can't be seen outside of a layout, so we watch messages with
+-- a dummy LayoutModifier and stow them in a persistent bucket. this is not
+-- entirely reliable given that boringAuto still isn't observable; we just hope
+-- those aren't visible and won;t be affected anyway
+-- @@@ punted for now, will be a separate module. it's still slimy, though
+
+-- | A 'logHook' to fade windows under control of a 'FadeHook', which is
+-- similar to but not identical to 'ManageHook'.
+fadeWindowsLogHook :: FadeHook -> X ()
+fadeWindowsLogHook h = withWindowSet $ \s -> do
+ let visibleWins = (W.integrate' . W.stack . W.workspace . W.current $ s) ++
+ concatMap (W.integrate' . W.stack . W.workspace) (W.visible s)
+ forM_ visibleWins $ \w -> do
+ o <- userCodeDef (Opacity 1) (runQuery h w)
+ setOpacity w $ case o of
+ OEmpty -> 0.93
+ Opacity r -> r
+
+-- | A 'handleEventHook' to handle fading and unfading of newly mapped
+-- or unmapped windows; this avoids problems with layouts such as
+-- "XMonad.Layout.Full" or "XMonad.Layout.Tabbed". This hook may
+-- also be useful with "XMonad.Hooks.FadeInactive".
+fadeWindowsEventHook :: Event -> X All
+fadeWindowsEventHook (MapNotifyEvent {}) =
+ -- we need to run the fadeWindowsLogHook. only one way...
+ asks config >>= logHook >> return (All True)
+fadeWindowsEventHook _ = return (All True)
+
+-- A utility to clamp opacity fractions to the range (0,1)
+clampRatio :: Rational -> Rational
+clampRatio r | r >= 0 && r <= 1 = r
+ | r < 0 = 0
+ | otherwise = 1