Search code examples
awesome-wm

Prevent content shrinking in awesomewm


I'm customizing my awesome-wm taskbar and what I'm trying to achieve is :

  • have a tasklist with fixed items width, which can shrink if there is not enough space
  • have a button right after the tasklist to open a program launcher on click (rofi), this button should never shrink

For debugging purpose, the button was replace by the red textbox

This is how it looks when there is only few items, exactly what I want : enter image description here enter image description here

When there is a lot of clients, the tasklist items shrink as expected, but the textfield too : enter image description here enter image description here

here is my complete rc.lua, which is mainly the same as the default one :

-- If LuaRocks is installed, make sure that packages installed through it are
-- found (e.g. lgi). If LuaRocks is not installed, do nothing.
pcall(require, "luarocks.loader")

-- Standard awesome library
local gears = require("gears")
local awful = require("awful")
require("awful.autofocus")
-- Widget and layout library
local wibox = require("wibox")
-- Theme handling library
local beautiful = require("beautiful")
-- Notification library
local naughty = require("naughty")
local menubar = require("menubar")
local hotkeys_popup = require("awful.hotkeys_popup")
-- Enable hotkeys help widget for VIM and other apps
-- when client with a matching name is opened:
require("awful.hotkeys_popup.keys")

-- {{{ Error handling
-- Check if awesome encountered an error during startup and fell back to
-- another config (This code will only ever execute for the fallback config)
if awesome.startup_errors then
    naughty.notify({ preset = naughty.config.presets.critical,
                     title = "Oops, there were errors during startup!",
                     text = awesome.startup_errors })
end

-- Handle runtime errors after startup
do
    local in_error = false
    awesome.connect_signal("debug::error", function (err)
        -- Make sure we don't go into an endless error loop
        if in_error then return end
        in_error = true

        naughty.notify({ preset = naughty.config.presets.critical,
                         title = "Oops, an error happened!",
                         text = tostring(err) })
        in_error = false
    end)
end
-- }}}

-- {{{ Variable definitions
-- Themes define colours, icons, font and wallpapers.
beautiful.init(gears.filesystem.get_themes_dir() .. "default/theme.lua")

-- This is used later as the default terminal and editor to run.
terminal = "xterm"
editor = os.getenv("EDITOR") or "nano"
editor_cmd = terminal .. " -e " .. editor

-- Default modkey.
-- Usually, Mod4 is the key with a logo between Control and Alt.
-- If you do not like this or do not have such a key,
-- I suggest you to remap Mod4 to another key using xmodmap or other tools.
-- However, you can use another modifier like Mod1, but it may interact with others.
modkey = "Mod4"

-- Table of layouts to cover with awful.layout.inc, order matters.
awful.layout.layouts = {
    awful.layout.suit.floating,
    awful.layout.suit.tile,
    awful.layout.suit.tile.left,
    awful.layout.suit.tile.bottom,
    awful.layout.suit.tile.top,
    awful.layout.suit.fair,
    awful.layout.suit.fair.horizontal,
    awful.layout.suit.spiral,
    awful.layout.suit.spiral.dwindle,
    awful.layout.suit.max,
    awful.layout.suit.max.fullscreen,
    awful.layout.suit.magnifier,
    awful.layout.suit.corner.nw,
    -- awful.layout.suit.corner.ne,
    -- awful.layout.suit.corner.sw,
    -- awful.layout.suit.corner.se,
}
-- }}}

-- {{{ Menu
-- Create a launcher widget and a main menu
myawesomemenu = {
   { "hotkeys", function() hotkeys_popup.show_help(nil, awful.screen.focused()) end },
   { "manual", terminal .. " -e man awesome" },
   { "edit config", editor_cmd .. " " .. awesome.conffile },
   { "restart", awesome.restart },
   { "quit", function() awesome.quit() end },
}

mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon },
                                    { "open terminal", terminal }
                                  }
                        })

mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
                                     menu = mymainmenu })

-- Menubar configuration
menubar.utils.terminal = terminal -- Set the terminal for applications that require it
-- }}}

-- Keyboard map indicator and switcher
mykeyboardlayout = awful.widget.keyboardlayout()

-- {{{ Wibar
-- Create a textclock widget
mytextclock = wibox.widget.textclock()

-- Create a wibox for each screen and add it
local taglist_buttons = gears.table.join(
                    awful.button({ }, 1, function(t) t:view_only() end),
                    awful.button({ modkey }, 1, function(t)
                                              if client.focus then
                                                  client.focus:move_to_tag(t)
                                              end
                                          end),
                    awful.button({ }, 3, awful.tag.viewtoggle),
                    awful.button({ modkey }, 3, function(t)
                                              if client.focus then
                                                  client.focus:toggle_tag(t)
                                              end
                                          end),
                    awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
                    awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
                )

local tasklist_buttons = gears.table.join(
                     awful.button({ }, 1, function (c)
                                              if c == client.focus then
                                                  c.minimized = true
                                              else
                                                  c:emit_signal(
                                                      "request::activate",
                                                      "tasklist",
                                                      {raise = true}
                                                  )
                                              end
                                          end),
                     awful.button({ }, 3, function()
                                              awful.menu.client_list({ theme = { width = 250 } })
                                          end),
                     awful.button({ }, 4, function ()
                                              awful.client.focus.byidx(1)
                                          end),
                     awful.button({ }, 5, function ()
                                              awful.client.focus.byidx(-1)
                                          end))


local tasklist_layout = {
  layout = wibox.layout.flex.horizontal,
  max_widget_size = 300
}

local function tasklist_create_function(self, c, index, objects) --luacheck: no unused
  -- adding close action on button
  local cbm = self:get_children_by_id('close_button_role')[1]
  cbm:buttons(
    awful.button({}, 1, nil,
      function()
        c:kill()
      end
    )
  )
end

local tasklist_template = {
  -- bgb
  id = "background_role",
  widget = wibox.container.background,
  create_callback = tasklist_create_function,
  {
    -- l
    layout = wibox.layout.align.horizontal,
    {
      -- ibm
      id = "icon_margin_role",
      widget = wibox.container.margin,
      left = 12,
      right = 12,
      {
        -- ib
        id = 'icon_role',
        widget = wibox.widget.imagebox,
      }
    },
    {
      -- tbm
      id = "text_margin_role",
      widget = wibox.container.margin,
      left = 4,
      right = 4,
      {
        -- tb
        id = "text_role",
        widget = wibox.widget.textbox,
        ellipsize = 'end'
      }
    },
    {
      -- cbm
      id = "close_button_role",
      widget = wibox.container.margin,
      left = 4,
      right = 8,
      {
        widget = wibox.widget.textbox,
        text = "X"
      }
    }
  }
}

local function set_wallpaper(s)
    -- Wallpaper
    if beautiful.wallpaper then
        local wallpaper = beautiful.wallpaper
        -- If wallpaper is a function, call it with the screen
        if type(wallpaper) == "function" then
            wallpaper = wallpaper(s)
        end
        gears.wallpaper.maximized(wallpaper, s, true)
    end
end

-- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
screen.connect_signal("property::geometry", set_wallpaper)

awful.screen.connect_for_each_screen(function(s)
    -- Wallpaper
    set_wallpaper(s)

    -- Each screen has its own tag table.
    awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, s, awful.layout.layouts[1])

    -- Create a promptbox for each screen
    s.mypromptbox = awful.widget.prompt()
    -- Create an imagebox widget which will contain an icon indicating which layout we're using.
    -- We need one layoutbox per screen.
    s.mylayoutbox = awful.widget.layoutbox(s)
    s.mylayoutbox:buttons(gears.table.join(
                           awful.button({ }, 1, function () awful.layout.inc( 1) end),
                           awful.button({ }, 3, function () awful.layout.inc(-1) end),
                           awful.button({ }, 4, function () awful.layout.inc( 1) end),
                           awful.button({ }, 5, function () awful.layout.inc(-1) end)))
    -- Create a taglist widget
    s.mytaglist = awful.widget.taglist {
        screen  = s,
        filter  = awful.widget.taglist.filter.all,
        buttons = taglist_buttons
    }

    -- Create a tasklist widget
    s.mytasklist = awful.widget.tasklist {
        screen  = s,
        filter  = awful.widget.tasklist.filter.currenttags,
        buttons = tasklist_buttons,
        layout = tasklist_layout,
        widget_template = tasklist_template
    }

    s.add_button = {
      widget = wibox.container.background,
      bg = "#FF0000",
      fg = "#FFFFFF",
      {
        widget = wibox.widget.textbox,
        text = "I don't want to be wrapped !"
      }
    }

    -- Create the wibox
    s.mywibox = awful.wibar({ position = "top", screen = s })

    -- 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,
        },
        { -- Middle widget
          layout = wibox.layout.fixed.horizontal,
          s.mytasklist,
          s.add_button,
        },
        { -- Right widgets
            layout = wibox.layout.fixed.horizontal,
            mykeyboardlayout,
            wibox.widget.systray(),
            mytextclock,
            s.mylayoutbox,
        },
    }
end)
-- }}}

-- {{{ Mouse bindings
root.buttons(gears.table.join(
    awful.button({ }, 3, function () mymainmenu:toggle() end),
    awful.button({ }, 4, awful.tag.viewnext),
    awful.button({ }, 5, awful.tag.viewprev)
))
-- }}}

-- {{{ Key bindings
globalkeys = gears.table.join(
    awful.key({ modkey,           }, "s",      hotkeys_popup.show_help,
              {description="show help", group="awesome"}),
    awful.key({ modkey,           }, "Left",   awful.tag.viewprev,
              {description = "view previous", group = "tag"}),
    awful.key({ modkey,           }, "Right",  awful.tag.viewnext,
              {description = "view next", group = "tag"}),
    awful.key({ modkey,           }, "Escape", awful.tag.history.restore,
              {description = "go back", group = "tag"}),

    awful.key({ modkey,           }, "j",
        function ()
            awful.client.focus.byidx( 1)
        end,
        {description = "focus next by index", group = "client"}
    ),
    awful.key({ modkey,           }, "k",
        function ()
            awful.client.focus.byidx(-1)
        end,
        {description = "focus previous by index", group = "client"}
    ),
    awful.key({ modkey,           }, "w", function () mymainmenu:show() end,
              {description = "show main menu", group = "awesome"}),

    -- Layout manipulation
    awful.key({ modkey, "Shift"   }, "j", function () awful.client.swap.byidx(  1)    end,
              {description = "swap with next client by index", group = "client"}),
    awful.key({ modkey, "Shift"   }, "k", function () awful.client.swap.byidx( -1)    end,
              {description = "swap with previous client by index", group = "client"}),
    awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative( 1) end,
              {description = "focus the next screen", group = "screen"}),
    awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end,
              {description = "focus the previous screen", group = "screen"}),
    awful.key({ modkey,           }, "u", awful.client.urgent.jumpto,
              {description = "jump to urgent client", group = "client"}),
    awful.key({ modkey,           }, "Tab",
        function ()
            awful.client.focus.history.previous()
            if client.focus then
                client.focus:raise()
            end
        end,
        {description = "go back", group = "client"}),

    -- Standard program
    awful.key({ modkey,           }, "Return", function () awful.spawn(terminal) end,
              {description = "open a terminal", group = "launcher"}),
    awful.key({ modkey, "Control" }, "r", awesome.restart,
              {description = "reload awesome", group = "awesome"}),
    awful.key({ modkey, "Shift"   }, "q", awesome.quit,
              {description = "quit awesome", group = "awesome"}),

    awful.key({ modkey,           }, "l",     function () awful.tag.incmwfact( 0.05)          end,
              {description = "increase master width factor", group = "layout"}),
    awful.key({ modkey,           }, "h",     function () awful.tag.incmwfact(-0.05)          end,
              {description = "decrease master width factor", group = "layout"}),
    awful.key({ modkey, "Shift"   }, "h",     function () awful.tag.incnmaster( 1, nil, true) end,
              {description = "increase the number of master clients", group = "layout"}),
    awful.key({ modkey, "Shift"   }, "l",     function () awful.tag.incnmaster(-1, nil, true) end,
              {description = "decrease the number of master clients", group = "layout"}),
    awful.key({ modkey, "Control" }, "h",     function () awful.tag.incncol( 1, nil, true)    end,
              {description = "increase the number of columns", group = "layout"}),
    awful.key({ modkey, "Control" }, "l",     function () awful.tag.incncol(-1, nil, true)    end,
              {description = "decrease the number of columns", group = "layout"}),
    awful.key({ modkey,           }, "space", function () awful.layout.inc( 1)                end,
              {description = "select next", group = "layout"}),
    awful.key({ modkey, "Shift"   }, "space", function () awful.layout.inc(-1)                end,
              {description = "select previous", group = "layout"}),

    awful.key({ modkey, "Control" }, "n",
              function ()
                  local c = awful.client.restore()
                  -- Focus restored client
                  if c then
                    c:emit_signal(
                        "request::activate", "key.unminimize", {raise = true}
                    )
                  end
              end,
              {description = "restore minimized", group = "client"}),

    -- Prompt
    awful.key({ modkey },            "r",     function () awful.screen.focused().mypromptbox:run() end,
              {description = "run prompt", group = "launcher"}),

    awful.key({ modkey }, "x",
              function ()
                  awful.prompt.run {
                    prompt       = "Run Lua code: ",
                    textbox      = awful.screen.focused().mypromptbox.widget,
                    exe_callback = awful.util.eval,
                    history_path = awful.util.get_cache_dir() .. "/history_eval"
                  }
              end,
              {description = "lua execute prompt", group = "awesome"}),
    -- Menubar
    awful.key({ modkey }, "p", function() menubar.show() end,
              {description = "show the menubar", group = "launcher"})
)

clientkeys = gears.table.join(
    awful.key({ modkey,           }, "f",
        function (c)
            c.fullscreen = not c.fullscreen
            c:raise()
        end,
        {description = "toggle fullscreen", group = "client"}),
    awful.key({ modkey, "Shift"   }, "c",      function (c) c:kill()                         end,
              {description = "close", group = "client"}),
    awful.key({ modkey, "Control" }, "space",  awful.client.floating.toggle                     ,
              {description = "toggle floating", group = "client"}),
    awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
              {description = "move to master", group = "client"}),
    awful.key({ modkey,           }, "o",      function (c) c:move_to_screen()               end,
              {description = "move to screen", group = "client"}),
    awful.key({ modkey,           }, "t",      function (c) c.ontop = not c.ontop            end,
              {description = "toggle keep on top", group = "client"}),
    awful.key({ modkey,           }, "n",
        function (c)
            -- The client currently has the input focus, so it cannot be
            -- minimized, since minimized clients can't have the focus.
            c.minimized = true
        end ,
        {description = "minimize", group = "client"}),
    awful.key({ modkey,           }, "m",
        function (c)
            c.maximized = not c.maximized
            c:raise()
        end ,
        {description = "(un)maximize", group = "client"}),
    awful.key({ modkey, "Control" }, "m",
        function (c)
            c.maximized_vertical = not c.maximized_vertical
            c:raise()
        end ,
        {description = "(un)maximize vertically", group = "client"}),
    awful.key({ modkey, "Shift"   }, "m",
        function (c)
            c.maximized_horizontal = not c.maximized_horizontal
            c:raise()
        end ,
        {description = "(un)maximize horizontally", group = "client"})
)

-- Bind all key numbers to tags.
-- Be careful: we use keycodes to make it work on any keyboard layout.
-- This should map on the top row of your keyboard, usually 1 to 9.
for i = 1, 9 do
    globalkeys = gears.table.join(globalkeys,
        -- View tag only.
        awful.key({ modkey }, "#" .. i + 9,
                  function ()
                        local screen = awful.screen.focused()
                        local tag = screen.tags[i]
                        if tag then
                           tag:view_only()
                        end
                  end,
                  {description = "view tag #"..i, group = "tag"}),
        -- Toggle tag display.
        awful.key({ modkey, "Control" }, "#" .. i + 9,
                  function ()
                      local screen = awful.screen.focused()
                      local tag = screen.tags[i]
                      if tag then
                         awful.tag.viewtoggle(tag)
                      end
                  end,
                  {description = "toggle tag #" .. i, group = "tag"}),
        -- Move client to tag.
        awful.key({ modkey, "Shift" }, "#" .. i + 9,
                  function ()
                      if client.focus then
                          local tag = client.focus.screen.tags[i]
                          if tag then
                              client.focus:move_to_tag(tag)
                          end
                     end
                  end,
                  {description = "move focused client to tag #"..i, group = "tag"}),
        -- Toggle tag on focused client.
        awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
                  function ()
                      if client.focus then
                          local tag = client.focus.screen.tags[i]
                          if tag then
                              client.focus:toggle_tag(tag)
                          end
                      end
                  end,
                  {description = "toggle focused client on tag #" .. i, group = "tag"})
    )
end

clientbuttons = gears.table.join(
    awful.button({ }, 1, function (c)
        c:emit_signal("request::activate", "mouse_click", {raise = true})
    end),
    awful.button({ modkey }, 1, function (c)
        c:emit_signal("request::activate", "mouse_click", {raise = true})
        awful.mouse.client.move(c)
    end),
    awful.button({ modkey }, 3, function (c)
        c:emit_signal("request::activate", "mouse_click", {raise = true})
        awful.mouse.client.resize(c)
    end)
)

-- Set keys
root.keys(globalkeys)
-- }}}

-- {{{ Rules
-- Rules to apply to new clients (through the "manage" signal).
awful.rules.rules = {
    -- All clients will match this rule.
    { rule = { },
      properties = { border_width = beautiful.border_width,
                     border_color = beautiful.border_normal,
                     focus = awful.client.focus.filter,
                     raise = true,
                     keys = clientkeys,
                     buttons = clientbuttons,
                     screen = awful.screen.preferred,
                     placement = awful.placement.no_overlap+awful.placement.no_offscreen
     }
    },

    -- Floating clients.
    { rule_any = {
        instance = {
          "DTA",  -- Firefox addon DownThemAll.
          "copyq",  -- Includes session name in class.
          "pinentry",
        },
        class = {
          "Arandr",
          "Blueman-manager",
          "Gpick",
          "Kruler",
          "MessageWin",  -- kalarm.
          "Sxiv",
          "Tor Browser", -- Needs a fixed window size to avoid fingerprinting by screen size.
          "Wpa_gui",
          "veromix",
          "xtightvncviewer"},

        -- Note that the name property shown in xprop might be set slightly after creation of the client
        -- and the name shown there might not match defined rules here.
        name = {
          "Event Tester",  -- xev.
        },
        role = {
          "AlarmWindow",  -- Thunderbird's calendar.
          "ConfigManager",  -- Thunderbird's about:config.
          "pop-up",       -- e.g. Google Chrome's (detached) Developer Tools.
        }
      }, properties = { floating = true }},

    -- Add titlebars to normal clients and dialogs
    { rule_any = {type = { "normal", "dialog" }
      }, properties = { titlebars_enabled = true }
    },

    -- Set Firefox to always map on the tag named "2" on screen 1.
    -- { rule = { class = "Firefox" },
    --   properties = { screen = 1, tag = "2" } },
}
-- }}}

-- {{{ Signals
-- Signal function to execute when a new client appears.
client.connect_signal("manage", function (c)
    -- Set the windows at the slave,
    -- i.e. put it at the end of others instead of setting it master.
    -- if not awesome.startup then awful.client.setslave(c) end

    if awesome.startup
      and not c.size_hints.user_position
      and not c.size_hints.program_position then
        -- Prevent clients from being unreachable after screen count changes.
        awful.placement.no_offscreen(c)
    end
end)

-- Add a titlebar if titlebars_enabled is set to true in the rules.
client.connect_signal("request::titlebars", function(c)
    -- buttons for the titlebar
    local buttons = gears.table.join(
        awful.button({ }, 1, function()
            c:emit_signal("request::activate", "titlebar", {raise = true})
            awful.mouse.client.move(c)
        end),
        awful.button({ }, 3, function()
            c:emit_signal("request::activate", "titlebar", {raise = true})
            awful.mouse.client.resize(c)
        end)
    )

    awful.titlebar(c) : setup {
        { -- Left
            awful.titlebar.widget.iconwidget(c),
            buttons = buttons,
            layout  = wibox.layout.fixed.horizontal
        },
        { -- Middle
            { -- Title
                align  = "center",
                widget = awful.titlebar.widget.titlewidget(c)
            },
            buttons = buttons,
            layout  = wibox.layout.flex.horizontal
        },
        { -- Right
            awful.titlebar.widget.floatingbutton (c),
            awful.titlebar.widget.maximizedbutton(c),
            awful.titlebar.widget.stickybutton   (c),
            awful.titlebar.widget.ontopbutton    (c),
            awful.titlebar.widget.closebutton    (c),
            layout = wibox.layout.fixed.horizontal()
        },
        layout = wibox.layout.align.horizontal
    }
end)

-- Enable sloppy focus, so that focus follows mouse.
client.connect_signal("mouse::enter", function(c)
    c:emit_signal("request::activate", "mouse_enter", {raise = false})
end)

client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
-- }}}

The relevant part are :

  • tasklist variables definition :
local tasklist_layout = {
  layout = wibox.layout.flex.horizontal,
  max_widget_size = 300
}

local function tasklist_create_function(self, c, index, objects) --luacheck: no unused
  -- adding close action on button
  local cbm = self:get_children_by_id('close_button_role')[1]
  cbm:buttons(
    awful.button({}, 1, nil,
      function()
        c:kill()
      end
    )
  )
end

local tasklist_template = {
  -- bgb
  id = "background_role",
  widget = wibox.container.background,
  create_callback = tasklist_create_function,
  {
    -- l
    layout = wibox.layout.align.horizontal,
    {
      -- ibm
      id = "icon_margin_role",
      widget = wibox.container.margin,
      left = 12,
      right = 12,
      {
        -- ib
        id = 'icon_role',
        widget = wibox.widget.imagebox,
      }
    },
    {
      -- tbm
      id = "text_margin_role",
      widget = wibox.container.margin,
      left = 4,
      right = 4,
      {
        -- tb
        id = "text_role",
        widget = wibox.widget.textbox,
        ellipsize = 'end'
      }
    },
    {
      -- cbm
      id = "close_button_role",
      widget = wibox.container.margin,
      left = 4,
      right = 8,
      {
        widget = wibox.widget.textbox,
        text = "X"
      }
    }
  }
}
  • the panel configuration :
    -- Create a tasklist widget
    s.mytasklist = awful.widget.tasklist {
        screen  = s,
        filter  = awful.widget.tasklist.filter.currenttags,
        buttons = tasklist_buttons,
        layout = tasklist_layout,
        widget_template = tasklist_template
    }

    s.add_button = {
      widget = wibox.container.background,
      bg = "#FF0000",
      fg = "#FFFFFF",
      {
        widget = wibox.widget.textbox,
        text = "I don't want to be wrapped !"
      }
    }

    -- Create the wibox
    s.mywibox = awful.wibar({ position = "top", screen = s })

    -- 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,
        },
        { -- Middle widget
          layout = wibox.layout.fixed.horizontal,
          s.mytasklist,
          s.add_button,
        },
        { -- Right widgets
            layout = wibox.layout.fixed.horizontal,
            mykeyboardlayout,
            wibox.widget.systray(),
            mytextclock,
            s.mylayoutbox,
        },
    }

EDIT : After trying Uli Schlachter solution, the content of the textbox isn't shrinked, but it is stuck on the right side enter image description here enter image description here


Solution

  • Finally, I could make it work with a custom layout : I duplicate the wibox.layout.align file and edited it to make it suit my needs. I ends up with a layout which can take up to 3 widgets : prepend, main and append The prepend and append widgets are fixed size and main take its own space or the remaining space.

    NOTE1: This layout has a vertical mode that should work but I haven't test it yet.

    NOTE2 : I haven't test what happened if prepend and append widget are wider than their parent ...

    Here are some screenshots of the result : enter image description here enter image description here

    The code of the layout :

    local base = require("wibox.widget.base")
    
    local layout = {}
    
    -- Calculate the layout.
    -- @param context The context in which we are drawn.
    -- @param width The available width.
    -- @param height The available height.
    function layout:layout(context, width, height)
        local result = {}
    
        local prepend_width, prepend_height = 0, 0
        if self._private.prepend then
            prepend_width, prepend_height = base.fit_widget(self, context, self._private.prepend, width, height)
        end
    
        local append_width, append_height = 0, 0
        if self._private.append then
            append_width, append_height = base.fit_widget(self, context, self._private.append, width, height)
        end
    
        local width_remains = self._private.dir == "x" and (width - prepend_width - append_width) or width
        local height_remains = self._private.dir == "y" and (height - prepend_height - append_height) or height
    
        local main_width, main_height = base.fit_widget(self, context, self._private.main, width_remains, height_remains)
    
        if self._private.prepend then
            local x, y, w, h = 0, 0, width, height
            if self._private.dir == "x" then
                w = prepend_width
            elseif self._private.dir == "y" then
                h = prepend_height
            end
            table.insert(result, base.place_widget_at(self._private.prepend, x, y, w, h))
        end
    
        if self._private.main then
            local x, y, w, h = 0, 0, width, height
            if self._private.dir == "x" then
                x = prepend_width
                w = main_width
            elseif self._private.dir == "y" then
                y = prepend_height
                h = main_height
            end
            table.insert(result, base.place_widget_at(self._private.main, x, y, w, h))
        end
    
        if self._private.append then
            local x, y, w, h = 0, 0, width, height
            if self._private.dir == "x" then
                x = prepend_width + main_width
                w = append_width
            elseif self._private.dir == "y" then
                y = prepend_height + main_height
                h = append_height
            end
            table.insert(result, base.place_widget_at(self._private.append, x, y, w, h))
        end
    
        return result
    end
    
    --- Set the layout's prepend widget.
    -- This is the widget which is before the main widget
    -- @property prepend
    -- @tparam widget prepend
    -- @propemits true false
    
    function layout:set_prepend(widget)
        if self._private.prepend == widget then
            return
        end
        self._private.prepend = widget
        self:emit_signal("widget::layout_changed")
        self:emit_signal("property::prepend", widget)
    end
    
    --- Set the layout's main widget. This is the centered one.
    -- @property main
    -- @tparam widget main
    -- @propemits true false
    
    function layout:set_main(widget)
        if self._private.main == widget then
            return
        end
        self._private.main = widget
        self:emit_signal("widget::layout_changed")
        self:emit_signal("property::main", widget)
    end
    
    --- Set the layout's append widget.
    -- This is the widget which is after the main widget
    -- @property append
    -- @tparam widget append
    -- @propemits true false
    
    function layout:set_append(widget)
        if self._private.append == widget then
            return
        end
        self._private.append = widget
        self:emit_signal("widget::layout_changed")
        self:emit_signal("property::append", widget)
    end
    
    for _, prop in ipairs {"prepend", "main", "append" } do
        layout["get_"..prop] = function(self)
            return self._private[prop]
        end
    end
    
    function layout:get_children()
        return gears.table.from_sparse {self._private.prepend, self._private.main, self._private.append}
    end
    
    function layout:set_children(children)
        self:set_prepend(children[1])
        self:set_main(children[2])
        self:set_append(children[3])
    end
    
    -- Fit the layout into the given space. The layout will
    -- ask for the sum of the sizes of its sub-widgets in its direction
    -- and the largest sized sub widget in the other direction.
    -- @param context The context in which we are fit.
    -- @param orig_width The available width.
    -- @param orig_height The available height.
    function layout:fit(context, orig_width, orig_height)
        local used_in_dir = 0
        local used_in_other = 0
    
        for _, v in pairs{self._private.prepend, self._private.main, self._private.append} do
            local w, h = base.fit_widget(self, context, v, orig_width, orig_height)
    
            local max = self._private.dir == "y" and w or h
            if max > used_in_other then
                used_in_other = max
            end
    
            used_in_dir = used_in_dir + (self._private.dir == "y" and h or w)
        end
    
        if self._private.dir == "y" then
            return used_in_other, used_in_dir
        end
        return used_in_dir, used_in_other
    end
    
    function layout:reset()
        for _, v in pairs({ "prepend", "main", "append" }) do
            self[v] = nil
        end
        self:emit_signal("widget::layout_changed")
    end
    
    local function get_layout(dir, prepend, main, append)
        local ret = base.make_widget(nil, nil, {enable_properties = true})
        ret._private.dir = dir
    
        for k, v in pairs(layout) do
            if type(v) == "function" then
                rawset(ret, k, v)
            end
        end
    
        ret:set_prepend(prepend)
        ret:set_main(main)
        ret:set_append(append)
    
        -- The layout allow set_children to have empty entries
        ret.allow_empty_widget = true
    
        return ret
    end
    
    --- Returns a new horizontal layout. This layout can display up to three widgets.
    -- :set_prepend() sets a widget with a fixed size at the beginning.
    -- :set_append() sets a widget with a fixed size at the end.
    -- :set_main() sets a widget which shrink if their is not enough space.
    -- @tparam[opt] widget prepend Widget to be put to the beginning.
    -- @tparam[opt] widget main Widget to be put to the middle.
    -- @tparam[opt] widget append Widget to be put to the end.
    function layout.horizontal(prepend, main, append)
        local ret = get_layout("x", prepend, main, append)
        return ret
    end
    
    --- Returns a new vertical layout. This layout can display up to three widgets.
    -- :set_prepend() sets a widget with a fixed size at the beginning.
    -- :set_append() sets a widget with a fixed size at the end.
    -- :set_main() sets a widget which shrink if their is not enough space.
    -- @tparam[opt] widget prepend Widget to be put to the beginning.
    -- @tparam[opt] widget main Widget to be put to the middle.
    -- @tparam[opt] widget append Widget to be put to the end.
    function layout.vertical(prepend, main, append)
        local ret = get_layout("y", prepend, main, append)
        return ret
    end
    
    return layout
    

    And a use case :

    local customLayout = require('CustomLayout')
    
    -- ...
    
    awful.screen.connect_for_each_screen(function(s)
        -- ...
    
        -- Add widgets to the wibox
        s.mywibox:setup {
            layout = wibox.layout.align.horizontal,
            { -- Left widgets
                -- ...
            },
            { -- Middle widget
              layout = customLayout.horizontal,
              {
                widget = wibox.container.background,
                bg = "#FF0000",
                fg = "#FFFFFF",
                {
                  widget = wibox.widget.textbox,
                  text = "Prepend content"
                }
              },
              s.mytasklist,
              {
                widget = wibox.container.background,
                bg = "#FF0000",
                fg = "#FFFFFF",
                {
                  widget = wibox.widget.textbox,
                  text = "Append content"
                }
              },
            },
            { -- Right widgets
                -- ...
            },
        }