Dylan
Dylan

Reputation: 315

How would I remove borders from all Floating windows in XMonad

There are several similar questions but none quite solve it for me, for example this question explains how to remove borders from fullscreen floating windows.

Using XMonad.Layout.NoBorders you can do lots of cool stuff like remove borders from certain windows or if it is the only window or only fullscreen floating windows.

I couldn't find anything for all floating windows, however if someone could just point me to some tool that I could use to check if a window is floating or not, I am sure I could try hack up a solution.

Any suggestions are welcome

Upvotes: 4

Views: 1059

Answers (1)

DarthFennec
DarthFennec

Reputation: 2778

I'll be using the source code of XMonad.Layout.NoBorders as a reference, since I can't find anything more fitting that already exists. We want to see how it implements "remove borders on fullscreen floating windows", to see if it can be easily relaxed to "remove borders on floating windows" (without the fullscreen constraint).

According to the answer on the question you linked:

layoutHook = lessBorders OnlyFloat $ avoidStruts $ myLayout

OnlyFloat seems to be the specifier for "remove borders on fullscreen floating windows", so let's check the definition of that:

data Ambiguity = Combine With Ambiguity Ambiguity
               | OnlyFloat
               | Never
               | EmptyScreen
               | OtherIndicated
               | Screen
    deriving (Read, Show)

Not too helpful on its own. We should look elsewhere to see how the code treats these values.


It's a pretty safe bet that the first function to check is lessBorders:

lessBorders :: (SetsAmbiguous p, Read p, Show p, LayoutClass l a) =>
        p -> l a -> ModifiedLayout (ConfigurableBorder p) l a
lessBorders amb = ModifiedLayout (ConfigurableBorder amb [])

From the type signature of lessBorders, we can see that:

OnlyFloat :: (SetsAmbiguous p, Read p, Show p) => p

This is a good sign, as it means lessBorders doesn't explicitly expect an Ambiguity: we can extend the functionality here by implementing our own SetsAmbiguous and passing it to the existing lessBorders. Let's now look at SetsAmbiguous, and Ambiguity's implementation of it:

class SetsAmbiguous p where
    hiddens :: p -> WindowSet -> Maybe (W.Stack Window) -> [(Window, Rectangle)] -> [Window]

instance SetsAmbiguous Ambiguity where
    hiddens amb wset mst wrs
      | Combine Union a b <- amb = on union next a b
      | Combine Difference a b <- amb = on (\\) next a b
      | Combine Intersection a b <- amb = on intersect next a b
      | otherwise = tiled ms ++ floating
      where next p = hiddens p wset mst wrs
            nonzerorect (Rectangle _ _ 0 0) = False
            nonzerorect _ = True
            screens =
              [ scr | scr <- W.screens wset,
                      case amb of
                            Never -> True
                            _ -> not $ null $ integrate scr,
                      nonzerorect . screenRect $ W.screenDetail scr]
            floating = [ w |
                        (w, W.RationalRect px py wx wy) <- M.toList . W.floating $ wset,
                        px <= 0, py <= 0,
                        wx + px >= 1, wy + py >= 1]
            ms = filter (`elem` W.integrate' mst) $ map fst wrs
            tiled [w]
              | Screen <- amb = [w]
              | OnlyFloat <- amb = []
              | OtherIndicated <- amb
              , let nonF = map integrate $ W.current wset : W.visible wset
              , length (concat nonF) > length wrs
              , singleton $ filter (1==) $ map length nonF = [w]
              | singleton screens = [w]
            tiled _ = []
            integrate y = W.integrate' . W.stack $ W.workspace y

hiddens is the only method here that we need to implement. Its arguments are our SetsAmbiguous value, a WindowSet, and some other things, and it returns a list of windows that should not show borders. There's a lot of logic for the combining operations and other Ambiguity values, but those don't matter to us right now. What we care about is this snippet:

            floating = [ w |
                        (w, W.RationalRect px py wx wy) <- M.toList . W.floating $ wset,
                        px <= 0, py <= 0,
                        wx + px >= 1, wy + py >= 1]

This is very promising. It defines a set of floating windows by extracting all windows from the floating section of the WindowSet, converting it to a list (initially it's a Data.Map), and filtering out all the windows that don't cover the entire screen. All we need to do is remove the filter.


After making that change, and removing all unnecessary code pertaining to tiled windows and set operations (which is most of the implementation), we end up with simply:

import XMonad.Layout.NoBorders
import qualified XMonad.StackSet as W
import qualified Data.Map as M

data AllFloats = AllFloats deriving (Read, Show)

instance SetsAmbiguous AllFloats where
    hiddens _ wset _ _ = M.keys $ W.floating wset

We can then say:

layoutHook = lessBorders AllFloats $ myLayout...

Upvotes: 7

Related Questions