infinisil
infinisil

Reputation: 1876

Making every window transparent with xmonad

I'd like every window to be transparent, I'm using xmonad and X11. I am not very familiar with any of Haskell, xmonad or X11.

How can I configure xmonad for that? I don't even know how to even get started.

Upvotes: 3

Views: 3002

Answers (1)

infinisil
infinisil

Reputation: 1876

To do that, you need an event hook that sets the opacity property on creation of new windows. This is what I'm using (requires xprop to be on the path):

import XMonad
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras
import Data.Monoid
import Data.Word

setTransparentHook :: Event -> X All
setTransparentHook ConfigureEvent{ev_event_type = createNotify, ev_window = id} = do
  setOpacity id opacity
  return (All True) where
    opacityFloat = 0.9
    opacity = floor $ fromIntegral (maxBound :: Word32) * opacityFloat
    setOpacity id op = spawn $ "xprop -id " ++ show id ++ " -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY " ++ show op
setTransparentHook _ = return (All True)

main = xmonad $ def
  { handleEventHook = setTransparentHook <+> handleEventHook def }

Process

Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.

In the spirit of this quote I'm describing my process of coming up with this. Note that I have very limited experience with all of Haskell, xmonad and X11.

The initial mindset was that I needed a script that sets the opacity on all windows (which turned out not to be exactly what I needed). I know that composite managers on linux do this kind of stuff (visual effects), so I check out the man page of compton (which I'm using) via man compton.

Searching for "opacity", I see the --opacity-rule flag, which mentions that compton-trans is recommended for this instead, so I look at its source. Trying out the script in the command line to discover that I need the window ID to set its opacity, so I look up how to do that.

A solution was to use xwininfo. You can list all the windows using xwininfo -tree -root. I thought I needed to parse the output of that and was already looking up awk tutorials.

Then I get the idea: "Wait, what if I just set the opacity on window creation? Xmonad is a window manager, it should definitely have the window ID!". So I look through xmonad's config options where I find the handleEventHook property. By clicking on the types Event and All I find out which imports I need (Graphics.X11.Xlib.Extras and Data.Monoid).

Creating a skeleton for my event hook by coping the default:

import XMonad
import Graphics.X11.Xlib.Extras
import Data.Monoid

myEventHook :: Event -> X All
myEventHook _ = return (All True)

Now some Haskell knowledge is needed, I want to do something when Event is a window creation event. Looking through the Event docs and a bit of probing, I found out I need the ConfigureEvent where ev_event_type is createNotify while ev_window is the created window ID. To use createNotify I also import Graphics.X11.Xlib:

import XMonad
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras
import Data.Monoid

myEventHook :: Event -> X All
myEventHook ConfigureEvent{ ev_event_type = createNotify, ev_window = id } = do
  return (All True)
myEventHook _ = return (All True)

Now what do we actually want to do? We want to spawn a shell process with the compton-trans command. There is the simple function spawn used throughout xmonad:

myEventHook :: Event -> X All
myEventHook ConfigureEvent{ ev_event_type = createNotify, ev_window = id } = do
  spawn $ "compton-trans -w " ++ show id ++ " 50"
  return (All True)
myEventHook _ = return (All True)

It worked! That's great but I noticed it being a bit slow and it still has the compton dependency which isn't really needed. So I look at the compton-trans source again, and see the last line that actually does the work which just uses xprop! Now this is great because I don't need all the stuff of compton-trans which does some checks and is optimized for user convenience. Using some number conversion I came up with the final version as shown above. It may even be faster to use the direct path to the executable.

I sometimes also used the ghci ~/.xmonad/xmonad.hs to check some types and man xprop/man whatever to check the documentation.

I hope this helps fellow xmonads to getting started! If someone has some improvements, please let me know.

Upvotes: 13

Related Questions