简体   繁体   中英

Only inner spacing in XMonad

Is it possible to only have spacing between tiles in XMonad, ie no spacing around them? The left-most tile would have no spacing to the left, the top-most ones no spacing to the top, etc. 具有外部间距的 XMonad 瓦片

I haven't been able to find a suitable option for removing the outer spacing reading the documentation.
https://hackage.haskell.org/package/xmonad-contrib-0.17.1/docs/XMonad-Layout-Spacing.html
https://hackage.haskell.org/package/xmonad-contrib-0.17.1/docs/XMonad-Layout-Gaps.html

This is my current spacing config in xmonad.hs .

myConfig = def
    ...
    -- , layoutHook = smartSpacingWithEdge 10 $ myLayout
    , layoutHook = smartSpacing 10 $ myLayout
    ...

Edit: Testing @Ismore 's solution.

This approach looks promising, but screen borders, window borders, and gaps seem to be totally independent. They are only additive; eg, you can't negate the outer most window borders by setting the screen borders to 0. I'm not totally sure about the difference between gaps and screen borders, they seem to add spacing to the exact same place (a outer surrounding border).

Using this code,

testSpace = spacingRaw True (Border 30 30 30 30) True (Border 40 40 40 40) True
testGaps = gaps [(U,20), (D,20), (L,20), (R,20)]
expandedL = testGaps . testSpace $ myLayout

I colored gaps green, screen borders blue, and window borders red. I don't know wether gaps or screen borders are outmost, here I put gaps (green) closest to the edge:

间距和间隙

Experimenting a bit more, it seems like gaps, screen borders, and window borders don't interact. For example, this code

--                                           `False` produces the same outcome as `True` with the parameter to the left set to all 0's.
--                                           |
testSpace = spacingRaw True (Border 0 0 0 0) True (Border 40 40 40 40) True
testGaps = gaps [(U,0), (D,0), (L,0), (R,0)]
expandedL = testGaps . testSpace $ myLayout

removes gaps and screen borders (the green and blue rectangles) but the window borders (red rectangles) are still present, creating outer spacing.

Disclaimer: I haven't tested this solution and I don't have a Xmonad env to test it, but this doesn't fit in the comment section.

For this sort of "expanded layout" I don't know if you have to use gaps , spacingRaw or both. Anyway, below there are snippets for configuring each the way I think you should.

gaps should be configured using a association list [(screen border, num of pixels)] . Up to the documentation this should be enough.

import XMonad.Layout.Gaps

-- Set up, down, left and right screen gaps to 0
expandedL = gaps [(U,0), (D,0), (L,0), (R,0) ]

myConfig = def
    ...
    , layoutHook = expandedL $ myLayout
    ...

Another posibility is to use fine grained window spacing function spacingRaw . It has many parameters, You should disable screen borders I guess. Notice you can set Borders to some pixels and then disable it. This helps to send a message toggleScreenSpacingEnabled if you wish

import XMonad.Layout.Spacing

--           |- fine grained constructor for spacing
--           |         |- Enable Smart border
--           |         |     |- Set screen border to 10 pixel except for the top one
--           |         |     |                  |- Disable screen borders
--           |         |     |                  |      |- Add a 10 pixel border to windows
--           |         |     |      T  B  R  L  |      |       T  B  R  L  |- Enable window borders
expandedL = spacingRaw True (Border 0 10 10 10) False (Border 10 10 10 10) True

myConfig = def
    ...
    , layoutHook = expandedL $ myLayout
    ...

Maybe you need to hack on both modifiers. I guess you can simply chain them together

import XMonad.Layout.Spacing
import XMonad.Layout.Gaps

noGaps = gaps [(U,0), (D,0), (L,0), (R,0)]
noSpace = spacingRaw True (Border 0 10 10 10) False (Border 10 10 10 10) True

-- chain both mods
expandedL = noSpace  . noGaps 

myConfig = def
    ...
    , layoutHook = expandedL $ myLayout
    ...

Edit after OP's edition

I see you are running into the problem that spacing does not detect if an edge is "inner" or "outer" (within windows or between window and screen). Notice that detecting such a thing can be difficult, for example if you have shrinking available or floating windows.

Nevertheless, I think you can write your own LayoutModifier , implementing only the pureModifier . I am not that into the xmonad library to build by myself, so the code below is just a sketch (I build it from documentation only and looking into Spacing source code, I don't even have the compiler at hand, so do not expect any working code)

import qualified XMonad.Util.Rectangle as R
import           XMonad.Layout.LayoutModifier
import           Data.Function (on)
import           Data.List (minimumBy)

-- Probably you need to enable some compiler extension.
-- It will warn you with the right one
data Expanded a = Expanded

-- expand is defined as "add 10 pixel space to each window; then expand outer borders"
-- Notice you can define expand = ModifiedLayout Expanded but this way you ensure expand is applied to spaced windows.
expand :: l a -> ModifiedLayout Expanded (ModifiedLayout Spacing l) a
expand = ModifiedLayout Expanded . spacing 10

instance Eq a => LayoutModifier Expanded a where
  -- the last parameter of this function is the window list and rectangles
  -- returned by the underlying layout (the spacing layout in your case)
  pureModifier Expanded screen_rectangle window_stack window_list = 
     let rectangle_coords = fmap (pixelsToCoordinates . snd) window_list
         -- Notice that this may fail on runtime if no windows are on the stack...
         minimum_x = minimumBy (compare `on` point_x1) rectangle_coords 
         minimum_y = minimumBy (compare `on` point_y1) rectangle_coords 
         maximum_x = maximumBy (compare `on` point_x2) rectangle_coords 
         maximum_y = maximumBy (compare `on` point_y2) rectangle_coords
         -- this function takes a rectangle and change the borders to match the screen borders if the rectangle border is outer
         extend_border rect = 
            case pixelsToCoordinates rect of
              PointRectangle x1 y1 x2 y2 = 
                 let new_x1 = if x1 == minimum_x then point_x1 (pixelsToCoordinates screen_rectangle) else x1
                     new_y1 = if y1 == minimum_y then point_y1 (pixelsToCoordinates screen_rectangle) else y1
                     new_x2 = if x2 == maximum_x then point_x2 (pixelsToCoordinates screen_rectangle) else x2 
                     new_y2 = if y2 == maximum_y then point_y2 (pixelsToCoordinates screen_rectangle) else y2 
                 in coordinatesToRectangle (PointRectangle new_x1 new_y2 new_x2 new_y2)
         extended_rectangles = fmap (\(w, r) -> (w, extend_border r)) window_list 
      in if null window_list
          then ([], Nothing)
          else (extended_rectangles, Nothing)

-- then you can expand your layouts with this
myConfig = def
    ...
    , layoutHook = expand $ myLayout
    ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM