XMonad Cubic Setup

This is a setup with 24 workspaces that are arranged in a cubemap type of way. Each workspace has as its background a picture from a common scene from a unique angle, so that as you move around the workspaces, it feels like moving inside the scene!

XMonad Cubic/Panoramic Setup

A quick video is often easier to explain the concept!

In this article Iā€™ll teach you how to set it up. I will also have some tips at the end on how to use it productively.

What You Will Need?

  1. XMonad, I tested it on version 0.15, probably can work on other versions
  2. A compositing manager, for example Xcompmgr as transparency is important in this setup
  3. Download & install wallpaperd
  4. Have 6 images, ā€œarranged in a cubeā€ If unsure of what images you want to use, I recommend starting with those mountain images kindly made publicly available by Emil Persson. I will assume you have saved the images to ā€˜~/Pictures/mountain-skyboxesā€™
  5. Finally, download the config file Octahedral.hs, and put it in your ā€˜.xmonad/libā€™ folder.

Setting up the Images

Transforming your 6 Base Views

For this tutorial, weā€™ll use the pictures of the mountain ā€œRyfjalletā€, which you can find under the directory of the same name in the directory ā€˜~/Pictures/mountain-skyboxesā€™.

You should find 6 pictures there: ā€˜posx.jpgā€™, ā€˜negx.jpgā€™, ā€˜posy.jpgā€™, ā€˜negy.jpgā€™, ā€˜posz.jpgā€™, ā€˜negz.jpgā€™, which we may call your base views.

Each of these pictures contain one side of the cube, or one side of the 360 view if you prefer.

The only thing that we are missing here is that, in the configuration, we can see each view from 4 angles, which corresponds to rotation of the head around the ā€œMaybeā€ axis (see video for explanation). These different angles are not present in this directory!

As a reminder, the maybe rotation corresponds to tilting the head to the right, bringing the right hear to the right shoulder.

When you do a maybe rotation, your view rotates counterclockwise (check it!).

Weā€™ll have to simulate this using an image software of your choice, start with posx.jpg and rotate it 3 times counterclockwise, saving each image to a different file like so:

  • ā€œposx.jpgā€ -> original, not rotated
  • ā€œposx-M.jpgā€ -> rotated once counterclockwise
  • ā€œposx-M2.jpgā€ -> rotated twice counterclockwise
  • ā€œposx-M3.jpgā€ -> rotated three times counterclockwise

Once you have done this for ā€œposx.jpgā€, youā€™ll need to do the same for each of the remaining images, leaving you with 24 images!

We are now ready to setup the background of each workspace.

Setting up Wallpaperd

Wallpaperd is a small software which is going to help us have a different wallpaper on each workspace.

Once you have installed wallpaperd, you need to configure it by creating a ā€˜.wallpaperd.cfgā€™ in your home directory.

  • The first two lines tell wallpaperd where to look for your images.
    path.search=~/Pictures:~/Pictures/Wallpapers:/usr/share/backgrounds
    config.mode=NUMBER
    
  • Then we need to tell it what to show on workspace 0
    wallpaper.0.image=mountain-skyboxes/Ryfjallet/posz.jpg
    wallpaper.0.mode=ZOOMED
    
  • Then we need to tell it what to show on workspace 1
    wallpaper.1.image=mountain-skyboxes/Ryfjallet/posz-M.jpg
    wallpaper.1.mode=ZOOMED
    
  • And then on until 23, in the end your file will look like this

To check that it is working, start the daemon by entering wallpaperd in a terminal, you should see the new wallpapers, and you should see the wallpapers changing as you change workspaces, even if you currently have less than 24.

Finally, the last step is making sure wallpaperd starts whenever you log in, which you can do by updating your ā€œ.xsessionā€ file or in my case ā€œ~/.xmonad/.xmonad-session-rcā€ and putting at the end: wallpaperd&

Setting Up Movement Keys

First make sure that you have 24 workspaces and that they are labelled by their number, as in ā€œ1ā€, ā€œ2ā€, ā€¦ ā€œ24ā€.

Then weā€™ll need to setup the keys, weā€™ll use a standard setup where using mod+movement switches to other workspace, while mod+shift+movement, moves the active window and then switches to other workspace.

Here, weā€™ll follow my ā€œYes, No, Maybeā€ movement setup, binding the mod+y, mod+n and mod+m keys as shown below:

        , ((mod4Mask,               xK_m),  windows $ cubic_switch Octahedral.maybe)
        , ((mod4Mask,               xK_y),  windows $ cubic_switch Octahedral.yes)
        , ((mod4Mask,               xK_n),  windows $ cubic_switch Octahedral.no)
        , ((mod4Mask .|. shiftMask, xK_m),  windows $ cubic_shift Octahedral.maybe)
        , ((mod4Mask .|. shiftMask, xK_y),  windows $ cubic_shift Octahedral.yes)
        , ((mod4Mask .|. shiftMask, xK_n),  windows $ cubic_shift Octahedral.no)

Of course this is just a basic config, you can play with it as much as you want. For example if you want a key that does ā€œopposite mā€, you can use the movement inv maybe.

If you want a key that corresponds to movement N done twice, you can use the movement mult no no.

Using inv and mult in a nested way, you can produce any motion of the cube you might desire (assuming here that you desire explore movements of the cube).

Setting Up Transparency

If youā€™ve seen the video, youā€™ve noticed that there are a lot of workspaces, and how to move between them is not completely straightforward.

For example, if you are facing at the red cabana and press Mod+Y, itā€™s going to take you to the ground. But if you are facing the same cabana upside down , pressing Mod+Y will take you to the sky.

The conclusion is that you need to know where you are in order to know where youā€™ll go.

What then, happens when you are working? You have windows covering the wallpaper and you might already have forgotten which way you were facing.

The solution is to use on demand transparency, that is transparency that turns on only when you want to switch workspaces. This is achieved by turning on a heavy transparency (like0.75) whenever the mod key is down (and then of course turning it back off when it is released).

Here is how to set this up.

  1. Create an extensible state to store the current value of the transparency

import XMonad.Hooks.FadeWindows
import qualified XMonad.Util.ExtensibleState as XState

newtype MyState = MyState { seethrough :: Rational } deriving (Show, Read, Typeable)

instance ExtensionClass (MyState) where
	initialValue  = MyState 0 
  1. Activate the transparency

Have a variable that encodes transparency is our state is not enough, we still need to tell the XServer to actually use it.

fadingHook :: X ()
fadingHook = do 
		transparency_value <- XState.gets seethrough
		fadeWindowsLogHook $ composeAll [ 
						transparency transparency_value,
                        isUnfocused --> transparency 0.2
                        ]

You will also need to <+> this function to your configā€™s logHook.

  1. Create a hook that will catch the mod key (here the windows key) and accordingly set and remove transparency
on_switch_transparency :: Rational
on_switch_transparency = 0.75

keyDownActions :: XConf -> M.Map (KeyMask, KeySym) (X ())
keyDownActions (XConf{ config = XConfig {XMonad.modMask = modMask} }) = M.fromList $ 
    [ 
	  -- pressing left mod key
	  ((noModMask, xK_Super_L), XState.put (MyState on_switch_transparency) >> windows id)
    ]

keyUpActions :: XConf -> M.Map (KeyMask, KeySym) (X ())
keyUpActions (XConf{ config = XConfig {XMonad.modMask = modMask} }) = M.fromList $ 
    [ 
	  -- releasing left mod key
	  ((mod4Mask, xK_Super_L), XState.put (MyState 0) >> windows id)
    ]

handleKeyEvent :: Event -> X ()
handleKeyEvent (KeyEvent {ev_event_type = eventType, ev_state = mask, ev_keycode = code})
    | eventType == keyRelease = 
		withDisplay $ \dpy -> do
        keyPressed  <- io $ keycodeToKeysym dpy code 0
        maskClean <- cleanMask mask
        keyMappings <- asks keyUpActions
        userCodeDef () $ whenJust (M.lookup (maskClean, keyPressed) keyMappings) id
    | eventType == keyPress = 
		withDisplay $ \dpy -> do
        keyPressed  <- io $ keycodeToKeysym dpy code 0
        maskClean <- cleanMask mask
        keyMappings <- asks keyDownActions
        userCodeDef () $ whenJust (M.lookup (maskClean, keyPressed) keyMappings) id
handleKeyEvent _ = return ()

handleKeyEventHook :: Event -> X All
handleKeyEventHook e = handleKeyEvent e >> return (All True)

You will need to mappend the function handleKeyEventHook to your handleEventHook in your config.

  1. Last piece of setup

You will need to add this line to your key config. It doesnā€™t do anything in itself but it ā€œregistersā€ the mod key in xmonad. If you donā€™t put it in the key detection above will not work.

((noModMask,              xK_Super_L),  return ())

Usability Tips

I tend to use the ā€œsquaredā€ movements a lot: MM, NN, and YY.

They are convenient because they have order 2: if you do them twice, you come back where you started.

For example, Iā€™ll choose a random workspace and start coding there. Of course Iā€™ll need to check some documentation at some point, on which workspace should I put it? I suggest using one of the squares, for example MM.

Pressing twice m I can go from code to documentation, which is convenient. Pressing twice m again takes me from documentation back to code, making it easy to go between the two.

What if now my code also requires me to access a command line, to restart some servers, run some tests or whatever, on which workspace should I put it? Again Iā€™d go for one of the squares, for example Iā€™d open a terminal on YY. I can now easily switch from my terminal to my code back and forth using YY.

The good thing is that, you can now switch back and forth between your documentation and your terminal using NN.

The general pattern is that if you have a base workspace and 3 other workspaces places in NN, MM and YY, then it is very easy to navigate between any pair of those 4 workspaces.

So thatā€™s a great way to arrange your windows you use a lot and together.

I have an additional advice for you, for windows you donā€™t use so frequently, maybe like your music or some other program you only check out occasionaly. Iā€™d put them all on either one of the 4 sky workspaces or floor ones.

Sure it will take a bit more time alternating between these 2 and your work, but it is generally very easy to know which way is the ground or the sky.

Conclusion

Thank you guys for checking out this configuration!

If you have any questions it might be easier to just comment on the youtube video, as I donā€™t have comments here yet!