xmonad / xmonad-contrib

Contributed modules for xmonad
https://xmonad.org
BSD 3-Clause "New" or "Revised" License
579 stars 271 forks source link

X.L.DecorationEx: extensible mechanism for window decorations #857

Closed portnov closed 5 months ago

portnov commented 6 months ago

Sorry for a lot of letters :)

Preface

At some moment I wanted to customize window decorations in xmonad: set decoration bar height a bit bigger than it is by default, set another font, maybe adjust padding between window buttons, probably add non-standard window buttons (for example to move windows between groups in X.L.Groups)... Initially I expected that all of it is possible if not by simple configuration, then by writing a custom DecorationStyle, which would inherit most methods from the default one and override only some methods. Probably I'm spoiled with OOP :)

This is an example what I wanted to achieve in the beginning:

Screenshot_20231206_163349

But when I tried to do so, it appeared that X.L.Decoration is not exactly designed for ease of adding new features without rewriting from scratch. For example,

I honestly started from trying to copy-paste (since in the beginning I hoped that all modifications will be just in my ~/.xmonad/lib) as less code as possible, and where possible - call default implementation of methods. But that road took me far. I had to understand how default implementation works (and for that - to change naming style during copy-pasting, because insert_dwr ((w,r),(Just dw,Just dr)) xs = (dw,dr):(w, shrink ds dr r):xs is... sorry but :D)).

So I ended up with a whole new implementation of LayoutModifier for decorations and related classes, see description below. When I understood that I have a more or less generic framework for window decoration, I figured that now I can write another implementation of DecorationEngine, which would be able to draw more fancy window decorations, much more like traditional WMs: with gradients and pixmaps. Obviously it's "a bit tedious" to write such things in plain xlib, so I considered several alternatives and ended up with cairo.

Currently I have all code for generic framework and new default decoration engine in separate repo (https://github.com/portnov/xmonad-decoration-ex), current PR is basically a copy-paste from there. And I have cairo-based engine in another repo (https://github.com/portnov/xmonad-decoration-cairo), that will probably later be PR-ed into xmonad-extra.

This is what is now possible with cairo engine:

Screenshot_20231217_144813

More screenshots : https://github.com/portnov/xmonad-decoration-ex/issues/1

More technical description

Within this mechanism, there are the following entities which define how decorations will look and work:

This mechanism makes a huge use of parametrized data types and type families, in order to make it possible to define different types of decorations, and easily combine different aspects of decorations. For example, each decoration engine can be combined with each decoration geometry.

See haddock documentation for more details.

Checklist

portnov commented 6 months ago

Hmm, it seems I will have to address compilation issues. Strange, simple stack build in this branch works for me. Will investigate.

portnov commented 6 months ago

There is still "orphan instances" thing. Will think what to do with them.

portnov commented 6 months ago

Nearly minimal configuration:


import XMonad

import XMonad.Config.Desktop
import XMonad.Hooks.EwmhDesktops

import XMonad.Layout.DecorationEx

theme = (themeEx def) {
          exWidgetsLeft = [titleW],
          exWidgetsCenter = [],
          exWidgetsRight = [minimizeW, maximizeW, closeW]
        }

main =  do
  xmonad $ ewmh $
    desktopConfig {
        terminal           = "konsole",
        focusFollowsMouse  = False,
        borderWidth        = 2,
        modMask            = mod4Mask,
        workspaces         = ["1", "2"],
        clickJustFocuses   = False,

        layoutHook         = textDecoration shrinkText theme (layoutHook def)
    }

Screenshot_20231222_172736

portnov commented 6 months ago

Wow. Warnings fixed. Please review. Suggestions are welcome.

portnov commented 6 months ago

@geekosaur , about calcWidgetPlace: I decided, rather than invent a special data type just for one function, let's just allow the method to return any X coordinate of rectangle. It will be simply ignored by functions which align widgets.

About "DwmStyle", I didn't come up with better name. Maybe let it be as it is?

portnov commented 6 months ago

Also, I have a couple of smaller improvements in continuation of this topic. I guess it's better to put them in separate PR after this one will be merged?

portnov commented 6 months ago

@geekosaur Don't want to sound pushy, but what's status of this? is it waiting for another round of review or?...

geekosaur commented 6 months ago

I was waiting to see if @liskin or @slotThe wanted to say something, and giving extra time because of the holidays. I'm also failing to come up with anything better than DwmStyle, so I guess it stands.

portnov commented 5 months ago

Hello What's the status of this? Can this be merged or we're waiting for something?

portnov commented 5 months ago

woo-hoo! thanks to all :)