Awesome: How do I use the widget system? Please add documentation

Created on 13 Jul 2017  路  3Comments  路  Source: awesomeWM/awesome

I recently started using awesome 4.1. I had an old, simple config for 3.5 and decided I wanted to add a bit more flair this time around. So I tried to read up on the widget system. Turns out there isn't much to read. Even after going through every single article on the API docs I still have no idea how it works. Most of it evidently suffers from the common documentation phenomenon where you only understand it if you already know how it works.

There are wiboxes, wibars, widgets, containers and layouts and some other things. Some of these are the same, or maybe not. There's no inheritance graph anywhere. You can evidently use a declarative system, but it's optional. Some things have a :setup method, others are constructors, some things you just kind of randomly throw into a nested setup table for other things (are the layouts just constants?). I'd love to say the few examples help me understand it but they really just add to the confusion. Probably because they all mix seventy seven different styles and syntaxes. /rant

As an example here's the first thing I tried to do: Add some padding to my main bar at the top of the screen. Should be easy, there's a wibox.container.margin class. Except I have absolutely no idea where to put it. Do I pass the wibar as a first argument? Do I throw it in the wibar's :setup? How do I get the other things inside this apparent "container"?

Once that's done I'd like to reduce the size of my systray icons. Should be easy, there's a set_base_size method. Except when I call it the whole thing glitches out and starts overlapping with other things in the bar.

Trying to figure these things out is very frustrating. It's cool that there is an API documentation but it's mostly just a massive list of available classes, methods and arguments with almost no explanations how to actually use anything. I need prose that tells me what those various things are or what they do and how you put one thing next to / inside another.

TL;DR: In My first awesome

Add widgets

TODO: Write this section.

Yes, please.

Most helpful comment

I will add more doc when I find the time to write it, for now there is https://awesomewm.org/apidoc/documentation/03-declarative-layout.md.html, but its ready for a rewrite as it went from being dedicated to the declarative syntax to being kind of the generic widget page. It's a very bad generic widget page. For for now I will write you a quick overview of your questions answers (the rant is already documented in #1373).

Widgets vs. containers vs. layouts

The cardinalities are:

  • A layout: Many children
  • A container: 1 child (add a layout if you need more)
  • A widget: no children

The different syntax

There is 3 main syntax. Awesome 3.0-3.4 were using property+declarative placement table. 3.5 only supported an imperative syntax. 4.0+ restore the property+declarative table style. All 3 syntax are exactly the same under the hood. They don't live in a parallel universe, so the documentation for one is translatable to the others. They use the same API. The old 3.5 "documentation" had almost no example. All examples I wrote for the 4.0 and 4.1 documentation uses the declarative syntax for consistency. But I agree there is giant holes in the "sequence diagram" to go from nothing to a screen full of widgets. I got a pull request to improve the titlebar/wibar/wibox/notification documentation, but it can't be merged right now because all the example it adds make compiling Awesome slow (yes, we test documentation examples when building Awesome to avoid code rot).

The declarative syntax

This syntax use {} section to create widgets. Each {} section need either a widget or layout key. If a layout is within a container, then the container will wrap the layout.

mywibar:setup {
    {
        {
            {
                id = "mytextbox",
                text = "foo",
                widget = wibox.widget.textbox
            },
            bg = "#ff0000",
            widget = wibox.container.background
        },
        {--[[other widget]]},
        {--[[other widget]]},
        layout = wibox.layout.align.horizontal
    },
    top = 4,
    bottom = 4,
    widget = wibox.container.margin
}

To access the widgets, add id keys (see the declarative doc page).

The :setup{} function is mostly just an helper around

mywibar.widget = wibox.widget {....}

But is preferred as it also auto generate the get_children_by_id() function on the wibar (you otherwise would need to extract it from the widget).

The Property syntax

This is an hybrid between fully declarative and imperative. Widgets are created using a declarative table, but are then normal imperative objects. wibox.widget is the function used to create such widgets:

local my_widget = wibox.widget {
    {
        id = "mytextbox",
        text = "foo",
        widget = wibox.widget.textbox
    }.
    bg = "#ff0000",
    widget = wibox.container.background
}

-- Change the text color to green
my_widget.fg = "#00ff00"

-- Change the text
my_widget.mytextbox.text = "bar"

-- Add to an existing layout
myexistinglayout:add(my_widget)

mywibar.widget = myexistinglayout

The imperative syntax

This is the Awesome 3.5 style code. You have to create each object and insert them manually.

local tb = wibox.widget.textbox()
tb.text = "foobar"

local bg = wibox.container.background()
bg.bg = "#ff0000"
bg.fg = "#00ff00"
bg.widget = tb 
-- or bg:set_widget(tb), it's exactly the same thing, properties are implicit
-- when `set_` and `get_` exists.

myexistinglayout:add(bg)

mywibar.widget = myexistinglayout

Please note that I would stay away from the constructors when using this syntax. They are whatever the widget author wanted them to be and are not consistent across widgets. In theory, you can always use an empty constructor, if that doesn't work, then that's a bug. I personally don't recommend this syntax because it doesn't scale. After a while you have a big ball of hard to read code unless you spend a lot of time cleaning it up.

Adding things to the wibar

This part isn't documented well but this is being addressed. rc.lua from the 3.5 era will have the imperative syntax, anything else (3.4, 4.0, 4.1) will have the declarative one.

Assuming a 4.1 based rc.lua. If you want to add a margin, you need change:

-- Add widgets to the wibox
s.mywibox:setup {
    layout = wibox.layout.align.horizontal,
    { -- Left widgets
        layout = wibox.layout.fixed.horizontal,
        mylauncher,
        s.mytaglist,
        s.mypromptbox,
    },
    s.mytasklist, -- Middle widget
    { -- Right widgets
        layout = wibox.layout.fixed.horizontal,
        mykeyboardlayout,
        wibox.widget.systray(),
        mytextclock,
        s.mylayoutbox,
    },
}

to:

-- Add widgets to the wibox
s.mywibox:setup {
    {
        layout = wibox.layout.align.horizontal,
        { -- Left widgets
            layout = wibox.layout.fixed.horizontal,
            mylauncher,
            s.mytaglist,
            s.mypromptbox,
        },
        s.mytasklist, -- Middle widget
        { -- Right widgets
            layout = wibox.layout.fixed.horizontal,
            mykeyboardlayout,
            wibox.widget.systray(),
            mytextclock,
            s.mylayoutbox,
        },
    },
    top = 4,
    bottom = 4,
    widget = wibox.container.margin
}

Wibar vs. wibox vs. titlebars, etc

They are the same, behave the same and have the same API. A wibar is a wibox attached to the side of the screen. A titlebar is a wibox attached to the side of the client. A wibox itself is a free floating widget box you can place anywhere. All other differences are technicalities that don't need to be known to be able to use Awesome.

All 3 comments

I will add more doc when I find the time to write it, for now there is https://awesomewm.org/apidoc/documentation/03-declarative-layout.md.html, but its ready for a rewrite as it went from being dedicated to the declarative syntax to being kind of the generic widget page. It's a very bad generic widget page. For for now I will write you a quick overview of your questions answers (the rant is already documented in #1373).

Widgets vs. containers vs. layouts

The cardinalities are:

  • A layout: Many children
  • A container: 1 child (add a layout if you need more)
  • A widget: no children

The different syntax

There is 3 main syntax. Awesome 3.0-3.4 were using property+declarative placement table. 3.5 only supported an imperative syntax. 4.0+ restore the property+declarative table style. All 3 syntax are exactly the same under the hood. They don't live in a parallel universe, so the documentation for one is translatable to the others. They use the same API. The old 3.5 "documentation" had almost no example. All examples I wrote for the 4.0 and 4.1 documentation uses the declarative syntax for consistency. But I agree there is giant holes in the "sequence diagram" to go from nothing to a screen full of widgets. I got a pull request to improve the titlebar/wibar/wibox/notification documentation, but it can't be merged right now because all the example it adds make compiling Awesome slow (yes, we test documentation examples when building Awesome to avoid code rot).

The declarative syntax

This syntax use {} section to create widgets. Each {} section need either a widget or layout key. If a layout is within a container, then the container will wrap the layout.

mywibar:setup {
    {
        {
            {
                id = "mytextbox",
                text = "foo",
                widget = wibox.widget.textbox
            },
            bg = "#ff0000",
            widget = wibox.container.background
        },
        {--[[other widget]]},
        {--[[other widget]]},
        layout = wibox.layout.align.horizontal
    },
    top = 4,
    bottom = 4,
    widget = wibox.container.margin
}

To access the widgets, add id keys (see the declarative doc page).

The :setup{} function is mostly just an helper around

mywibar.widget = wibox.widget {....}

But is preferred as it also auto generate the get_children_by_id() function on the wibar (you otherwise would need to extract it from the widget).

The Property syntax

This is an hybrid between fully declarative and imperative. Widgets are created using a declarative table, but are then normal imperative objects. wibox.widget is the function used to create such widgets:

local my_widget = wibox.widget {
    {
        id = "mytextbox",
        text = "foo",
        widget = wibox.widget.textbox
    }.
    bg = "#ff0000",
    widget = wibox.container.background
}

-- Change the text color to green
my_widget.fg = "#00ff00"

-- Change the text
my_widget.mytextbox.text = "bar"

-- Add to an existing layout
myexistinglayout:add(my_widget)

mywibar.widget = myexistinglayout

The imperative syntax

This is the Awesome 3.5 style code. You have to create each object and insert them manually.

local tb = wibox.widget.textbox()
tb.text = "foobar"

local bg = wibox.container.background()
bg.bg = "#ff0000"
bg.fg = "#00ff00"
bg.widget = tb 
-- or bg:set_widget(tb), it's exactly the same thing, properties are implicit
-- when `set_` and `get_` exists.

myexistinglayout:add(bg)

mywibar.widget = myexistinglayout

Please note that I would stay away from the constructors when using this syntax. They are whatever the widget author wanted them to be and are not consistent across widgets. In theory, you can always use an empty constructor, if that doesn't work, then that's a bug. I personally don't recommend this syntax because it doesn't scale. After a while you have a big ball of hard to read code unless you spend a lot of time cleaning it up.

Adding things to the wibar

This part isn't documented well but this is being addressed. rc.lua from the 3.5 era will have the imperative syntax, anything else (3.4, 4.0, 4.1) will have the declarative one.

Assuming a 4.1 based rc.lua. If you want to add a margin, you need change:

-- Add widgets to the wibox
s.mywibox:setup {
    layout = wibox.layout.align.horizontal,
    { -- Left widgets
        layout = wibox.layout.fixed.horizontal,
        mylauncher,
        s.mytaglist,
        s.mypromptbox,
    },
    s.mytasklist, -- Middle widget
    { -- Right widgets
        layout = wibox.layout.fixed.horizontal,
        mykeyboardlayout,
        wibox.widget.systray(),
        mytextclock,
        s.mylayoutbox,
    },
}

to:

-- Add widgets to the wibox
s.mywibox:setup {
    {
        layout = wibox.layout.align.horizontal,
        { -- Left widgets
            layout = wibox.layout.fixed.horizontal,
            mylauncher,
            s.mytaglist,
            s.mypromptbox,
        },
        s.mytasklist, -- Middle widget
        { -- Right widgets
            layout = wibox.layout.fixed.horizontal,
            mykeyboardlayout,
            wibox.widget.systray(),
            mytextclock,
            s.mylayoutbox,
        },
    },
    top = 4,
    bottom = 4,
    widget = wibox.container.margin
}

Wibar vs. wibox vs. titlebars, etc

They are the same, behave the same and have the same API. A wibar is a wibox attached to the side of the screen. A titlebar is a wibox attached to the side of the client. A wibox itself is a free floating widget box you can place anywhere. All other differences are technicalities that don't need to be known to be able to use Awesome.

That was extremely helpful, thanks a lot for taking the time to write this down! With this I've now managed to set up my bar the way I want.

All other differences are technicalities that don't need to be known to be able to use Awesome.

I understand that this is the way it's intended to work, however there are still certain differences that can take some time to work out. Most importantly the various different ways of adding spacing and backgrounds. There are widgets that bring their own properties for borders and backgrounds, others have theme variables and some need to be enclosed in container type widgets. Some layouts offer spacing, others don't. It appears to follow some logic but with my limited insight it's not always obvious. Maybe I'm just way too used to the HTML+CSS box model.

Some layouts offer spacing, others don't.

Most of them indeed have some logic behind them, but I agree it's not obvious. Layouts with multiple elements have spacing because otherwise it would be a repetitive pain to get unified look. Some others have them because they are shaped (not a rectangle) and using the margin container on curvy/clipped paths would have been harder.

About the "All other differences are technicalities that don't need to be known" quote, I was referring to wibox vs. titlebars, not the whole widget system. Sorry for the confusion.

I added your complaints to #1373, which is the issue to keep track of the underdocumented APIs. Shall I/you close this issue as resolved?

Was this page helpful?
0 / 5 - 0 ratings