AwesomeWM

From the Arch Wiki: awesome is a highly configurable, next generation framework window manager for Xorg. It is very fast and extensible. It is primarily targeted at power users, developers and any people dealing with every day computing tasks and who want to have fine-grained control on its graphical environment.

Personally, what really made me want to try Awesome is the fact its configuration file is written with an actual programming language and not just a configuration language like with i3, and by the fact it works with tags and not workspaces which makes window management much more flexible.

This document was written in Emacs with Org-mode and is both the documentation and source code of my configuration file which can be extracted to $HOME/.config/awesome/rc.lua through a call to org-babel-tangle.

Launching Awesome

In order to launch Awesome with startx, I need a xinit-compatible script. Here is my $HOME/.xinitrc.awesome file:

Loading libraries

First of all, some initialization is needed, and this initialization is about math randomness. So, let’s initialize the random method of the math library:

math.randomseed(os.time())

In order to be able to load libraries properly, I first need to make sure LuaRocks is installed, so I can also make sure the packages our configuration depends on installed through it can be found. If LuaRocks is not installed, then do nothing.

pcall(require, "luarocks.loader")

Next, we’ll also load the following libraries

LibraryImport asWhat it is
gearsgearsStandard Awesome library
awfulawfulStandard Awesome library
wiboxwiboxWidget and layout library
beautifulbeautifulTheme handling library
naughtynaughtyNotification library
menubarmenubarCreate menus
awful.hotkeys_popuphotkeys_popupHelp window for hotkeys

Here is the actual code in the config file:

local gears = require("gears")
local awful = require("awful")
local wibox = require("wibox")
local beautiful = require("beautiful")
local naughty = require("naughty")
local menubar = require("menubar")
local hotkeys_popup = require("awful.hotkeys_popup")

I also want to be able to autofocus the first window when I go to another workspace, so let’s require that:

require("awful.autofocus")

And finally, I want to be able to declare some shortcuts specific to some apps thanks to the hotkeys help widget.

require("awful.hotkeys_popup.keys")

By the way, let’s initialize the random method of the math library:

math.randomseed(os.time())

Error handling

This code checks 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

And this code handles runtime errors after startup thanks to signals.

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

With Awesome, it is possible to load or write custom themes in order to give Awesome a special look that fits the user. I am currently using a custom theme that is not yet included in my dotfiles. I will add it later, along with the images used for the theme.

beautiful.init("/home/phundrak/.config/awesome/nord/theme.lua")

Default terminal and text editor

The two following variables are set so that I don’t need to go over my whole config file in order to modify which terminal or text editor I use, not that I do it often though.

terminal = "kitty"
editor = os.getenv("EDITOR") or "emacsclient -c -a emacs"

Keys

The following declares the default Modkey. Usually, Mod4 is the Super key, situated between the Ctrl key and the Alt key with a logo (usually Windows’). Another usual value for this is Mod1, which is the Alt key, but it has greater chances of interfering with other software. I also defined some other obvious variables in order to make my code cleaner later on.

modkey = "Mod4"
shift = "Shift"
control = "Control"
meta = "Mod1"
alt = "Mod1" -- Just in case

Custom functions

Set a random wallpaper

This function sets a random wallpaper from the directory ~/Pictures/Wallpapers, see pape-update in my custom scripts.

local function set_random_pape()
  awful.spawn.with_shell("pape-update")
  naughty.notify({ preset = naughty.config.presets.normal,
                   title = "Wallpaper change",
                   text = "Done!"})
end

Restore previous wallpaper

I also wrote the following function that will restore the previously set wallpaper:

local function set_wallpaper(_)
  awful.spawn.with_shell("nitrogen --restore")
end

Layout manipulation

The following function is used by a shortcut described below in Keybindings: Clients.

local function client_go_back()
  awful.client.focus.history.previous()
  if client.focus then
    client.focus:raise()
  end
end

Clients manipulation

local function restore_minimized_clients()
  local c = awful.client.restore()
  -- Focus restored client
  if c then
    c:emit_signal(
      "request::activate", "key.unminimize", {raise = true}
    )
  end
end
local function toggle_fullscreen_client(c)
  c.fullscreen = not c.fullscreen
  c:raise()
end
local function toggle_maximized(c)
  c.maximized = not c.maximized
  c:raise()
end
local function toggle_vertical_maximized(c)
  c.maximized_vertical = not c.maximized_vertical
  c:raise()
end
local function toggle_horizontal_maximized(c)
  c.maximized_horizontal = not c.maximized_horizontal
  c:raise()
end

Tag manipulation

local function view_tag_n(i)
  local screen = awful.screen.focused()
  local tag = screen.tags[i]
  if tag then
    tag:view_only()
  end
end
local function toggle_tag_n(i)
  local screen = awful.screen.focused()
  local tag = screen.tags[i]
  if tag then
    awful.tag.viewtoggle(tag)
  end
end
local function move_focused_to_tag_n(i)
  if client.focus then
    local tag = client.focus.screen.tags[i]
    if tag then
      client.focus:move_to_tag(tag)
    end
  end
end
local function toggle_focused_client_to_tag_n(i)
  if client.focus then
    local tag = client.focus.screen.tags[i]
    if tag then
      client.focus:toggle_tag(tag)
    end
  end
end

Awesome prompt

local function invoke_lua_execute_prompt()
  awful.prompt.run {
    prompt       = "Run Lua code: ",
    textbox      = awful.screen.focused().promptbox.widget,
    exe_callback = awful.util.eval,
    history_path = awful.util.get_cache_dir() .. "/history_eval"
  }
end

Layouts

The following is a list of available windows layouts. I only enable some of them, and their order in the table is their order in Awesome.

LayoutEnabled?
magnifieryes
tile.leftyes
tileyes
tile.bottomyes
tile.topyes
maxyes
max.fullscreenyes
floatingyes
fairyes
fair.horizontalyes
spiralyes
spiral.dwindleyes
corner.nwno
corner.neopen in new windowno
corner.swno
corner.seopen in new windowno

Here is the code that activates these layouts:

awful.layout.layouts = {
  awful.layout.suit.magnifier,
  awful.layout.suit.tile.left,
  awful.layout.suit.tile,
  awful.layout.suit.tile.bottom,
  awful.layout.suit.tile.top,
  awful.layout.suit.max,
  awful.layout.suit.max.fullscreen,
  awful.layout.suit.floating,
  awful.layout.suit.fair,
  awful.layout.suit.fair.horizontal,
  awful.layout.suit.spiral,
  awful.layout.suit.spiral.dwindle,

}

Top bar

The top bar in Awesome is declared thanks to a wibar widget fro the awful library. It is comprised of several buttons and widgets that will be declared below.

It is possible to create actual menus in Awesome, including the one available at the top-left corner of the screen. First, let’s declare a menu related to Awesome:

NameCommand
hotkeysfunction() hotkeys_popup.show_help(nil, awful.screen.focused()) end
edit configeditor … " " … awesome.conffile
restartawesome.restart
quitfunction() awesome.quit() end

And here is the actual code:

awesomewm_menu = {
  { "hotkeys", function() hotkeys_popup.show_help(nil, awful.screen.focused()) end },
  { "edit config", editor .. " " .. awesome.conffile },
  { "restart", awesome.restart },
  { "quit", function() awesome.quit() end }
}

Next, let’s create the main menu that will be used on S-w and at the top left of the window:

NameCommandIcon
awesomeawesomewm_menubeautiful.awesome_icon
open terminalterminalnil

Here is the actual code:

mainmenu = awful.menu({ items = {
                          { "awesome", awesomewm_menu, beautiful.awesome_icon },
                          { "open terminal", terminal, nil }
                     }})

For now it only has two entries: the Awesome menu and opening a terminal, I will add some more later probably. Let’s specify it as being our main launcher:

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

Finally, let’s declare the menubar’s terminal for applications that require it.

menubar.utils.terminal = terminal

Widgets

Let’s declare the keyboard map indicator and switcher for the top bar:

keyboardlayout = awful.widget.keyboardlayout()

Let’s also create a clock widget:

textclock = wibox.widget.textclock()

Tag list

In order to create the taglist (an equivalent to workspaces, but better), we need to create first a local variable that will hold the widget. It will be declared as you can see below:

local tasklist_buttons = gears.table.join(
  -- configuration goes here
)

gears.table.join() joins several tables together, as described hereopen in new window, which will be useful since all its arguments will be tables generated by the awful.button method which will be useful in order to manage what clicks on the tags should do. First, let’s manage left clicks.

Left clicks in general are dedicated to tag visibility. A simple left click on a tag should switch this tag as the only visible tag, no matter how many of them were visible beforehand.

awful.button({ }, 1, function(t) t:view_only() end)

However, left clicks combined with the modkey will add the clicked tag to the list of visible tags, which allows the user to see windows from several tags at once.

awful.button({ modkey }, 1, awful.tag.viewtoggle)

Right clicks are dedicated to window tagging. A simple right click will untag the currently focused window and tag it again with the clicked tag, moving it effectively from one tag to another.

awful.button({ }, 3, function(t)
    if client.focus then
      client.focus:move_to_tag(t)
    end
end)

However, a right click combined with the modkey will add the clicked tag to the currently focused window, making it visible to both tags.

awful.button({ modkey }, 3, function(t)
    if client.focus then
      client.focus:toggle_tag(t)
    end
end)

The scroll wheel is treated as clicks just as any right or left clicks and can be interpreted by Awesome. They can prove useful when it comes to tags. If a scroll up is detected over tags, then Awesome will display the previous tag.

awful.button({ }, 4, function(t) awful.tag.viewprev(t.screen) end)

Otherwise, if a scroll down is detected, the next tag will be displayed.

awful.button({ }, 5, function(t) awful.tag.viewnext(t.screen) end)

So, here’s the actual configuration code for the taglist:

local taglist_buttons = gears.table.join(
  awful.button({ }, 1, function(t) t:view_only() end),
  awful.button({ modkey }, 1, awful.tag.viewtoggle),
  awful.button({ }, 3, function(t)
      if client.focus then
        client.focus:move_to_tag(t)
      end
  end),
  awful.button({ modkey }, 3, function(t)
      if client.focus then
        client.focus:toggle_tag(t)
      end
  end),
  awful.button({ }, 4, function(t) awful.tag.viewprev(t.screen) end),
  awful.button({ }, 5, function(t) awful.tag.viewnext(t.screen) end)
)

Tasks list

Similarly to the tag list, the task list can display some special behavior depending on the clicks it receives. These clicks are set like so:

local tasklist_buttons = gears.table.join(
  -- List of clicks
)

A left click on a task in the taskbar will simply focus and raise the window linked to it if it is not focused. Otherwise, if the window is focused, the window will be minimized.

awful.button({ }, 1, function (c)
    if c == client.focus then
      c.minimized = true
    else
      c:emit_signal(
        "request::activate",
        "tasklist",
        {raise = true}
      )
    end
end)

If the right click is detected, then a list of all the opened clients is invoked so we can switch to another (and if needed switch visible tag). The width of this list will be 250px.

awful.button({ }, 3, function()
      awful.menu.client_list({ theme = { width = 250 } })
end)

If a scroll up is detected, then let’s select the previous client in the tasklist.

awful.button({ }, 4, function ()
      awful.client.focus.byidx(1)
end)

If a scroll down is detected, then let’s select the next client in the tasklist.

awful.button({ }, 5, function ()
      awful.client.focus.byidx(-1)
end)

So, here’s the actual code for the tasklist:

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)
)

Theme and display

Screen update

When a screen’s geometry changes (e.g. when a different resolution is applied), the signal property::geometry is sent. When this is the case, the wallpaper should be redisplayed since it won’t necessarily fit the new geometry of the screen. And remember, I have a function that does exactly that! Let’s connect this function to the geometry change signal:

screen.connect_signal("property::geometry", set_wallpaper)

If a new screen gets connected, it will need to get a new wallpaper. A lot needs to be done, and all the following lines of code will be inside a block like this:

awful.screen.connect_for_each_screen(function(s)
    -- Code to be executed goes here
end)

So, due the code block above, if you see any reference to s in the code blocks below, it will refer to the screen being set up by the function.

First, let’s set its wallpaper:

set_wallpaper()

Next, let’s build a list of tags for the screen. Be aware that each screen has its own tag table! The default layout will be the first refered to in the layouts list described above.

awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" }, s, awful.layout.layouts[1])

Next, let’s create the taglist widget. It will use the taglist_buttons declared above in order to handle clicks on tags, and due to the filter, all tags will be displayed in the tagbar (more about tag filtersopen in new window).

s.taglist = awful.widget.taglist {
  screen  = s,
  filter  = awful.widget.taglist.filter.all,
  buttons = taglist_buttons
}

A tasklist widget will also get created thanks with the tasklist_button declared above that will handle clicks on tasks. Contrarily to the taglist widget above, the tasklist will only display the screen’s current tags thanks to its filter.

s.tasklist = awful.widget.tasklist {
  screen  = s,
  filter  = awful.widget.tasklist.filter.currenttags,
  buttons = tasklist_buttons
}

A promptbox will also be created for the screen:

s.promptbox = awful.widget.prompt()

Then, Let’s create an imagebox widget in which will be contained an icon indicating which layout is being used. We need one per screen. We will also make it clickable: if there is a left click or a scroll up detected above it, the next layout will be loaded; otherwise if a right click or a scroll down is detected, the previous layout will be loaded.

s.layoutbox = awful.widget.layoutbox(s)
s.layoutbox: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)))

Now it is time to create the widget, a wibox that will contain our bar.

s.wibox = awful.wibar({ position = "top", screen = s })

Finally, let’s set up our bar. Since it is a horizontal bar, its layout will be horizontal too. Our launcher, taglist and promptbox will be part of the left widgets, while the tasklist will be at the center, and the keyboard indicator, the system tray, the clock and the layout indicator will be on the right.

s.wibox:setup {
  layout = wibox.layout.align.horizontal,
  { -- Left widgets
    layout = wibox.layout.fixed.horizontal,
    launcher,
    s.taglist,
    s.promptbox,
  },
  s.tasklist, -- Middle widget
  { -- Right widgets
    layout = wibox.layout.fixed.horizontal,
    keyboardlayout,
    wibox.widget.systray(),
    textclock,
    s.layoutbox,
  },
}

In the end, our code looks like this:

awful.screen.connect_for_each_screen(function(s)
      set_wallpaper()
      awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" }, s, awful.layout.layouts[1])
      s.taglist = awful.widget.taglist {
        screen  = s,
        filter  = awful.widget.taglist.filter.all,
        buttons = taglist_buttons
      }
      s.tasklist = awful.widget.tasklist {
        screen  = s,
        filter  = awful.widget.tasklist.filter.currenttags,
        buttons = tasklist_buttons
      }
      s.promptbox = awful.widget.prompt()
      s.layoutbox = awful.widget.layoutbox(s)
      s.layoutbox: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)))
      s.wibox = awful.wibar({ position = "top", screen = s })
      s.wibox:setup {
        layout = wibox.layout.align.horizontal,
        { -- Left widgets
          layout = wibox.layout.fixed.horizontal,
          launcher,
          s.taglist,
          s.promptbox,
        },
        s.tasklist, -- Middle widget
        { -- Right widgets
          layout = wibox.layout.fixed.horizontal,
          keyboardlayout,
          wibox.widget.systray(),
          textclock,
          s.layoutbox,
        },
      }
end)

Mouse bindings

It is possible with Awesome to bind some shortcuts to mouse events when the mouse is above Awesome itself (not above some client). Only one is set: the right click opens the Awesome menu.

root.buttons(gears.table.join(
               awful.button({}, 3, function() mainmenu:toggle() end)
))

I will also set three mouse bindings for when the mouse is above a client:

  • A simple click on a client will focus and raise it.
  • A click on a client combined with a modkey press will allow the user to move a client after focusing it and making it floating.
  • A middle click on a client combined with a modkey press will toggle the floating status of the client.
  • A right click combined with the modkey will allow the user to resize a after focusing it and making it a floating client.
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})
      c.floating = true
      awful.mouse.client.move(c)
  end),
  awful.button({ modkey }, 2, function (c)
        awful.client.floating.toggle(c)
  end),
  awful.button({ modkey }, 3, function (c)
      c:emit_signal("request::activate", "mouse_click", {raise = true})
      c.floating = true
      awful.mouse.client.resize(c)
  end)
)

Keybindings

Keybindings allow the user to execute some Lua code all across Awesome. They all bear at least a list of modifier keys, the actual key to be pressed, the action they keybinding should yield, a description, and a group. The latter two will be useful for the keybindings help window which will display them all, sorted by group and with the description displayed next to the keybinding itself.

Here are some keybindings related to Awesome itself. Most of them will be described in tables, but due to some limitations from Org-mode (the Emacs mode used to write this document and generate my Awesome configuration), a few of them will be directly written as Lua code.

Here is a description of the tables displayed below:

  • Key: key which toggles the shortcut
  • Modifiers: modifier keys that are required to toggle the shortcut
  • Lambda?: whether or not the Action should be nested in a lambda function. Possible values are:
    • no: The value is a Lua function to be executed as is
    • yes: The value is to be inserted into a lambda
    • spawn: The value is to be inserted in an awful.spawn call in a lambda
    • shell: The value is to be inserted in an awful.spawn.with_shell call in a lambda
  • Action: code to be executed by the shortcut
  • What it does: short description of the shortcut’s action
  • Group: group in which the shortcut will appear in Awesome’s help window
  • Clientkey?: whether this should be a global shortcut or a shortcut only aimed at clients (value is yes or no)

Most of these keybindings are available at root-level of Awesome and will be declared in the globalkeys variable, which will be added then to root.keys (see https://awesomewm.org/doc/api/libraries/root.html#keysopen in new window).

globalkeys = gears.table.join(
  -- Awesome
  awful.key({modkey},"h",hotkeys_popup.show_help,
        {description="show help",group="awesome"}),
  awful.key({modkey, shift},"h",function() mainmenu:show() end,
        {description="show main menu",group="awesome"}),
  awful.key({modkey},"l",function() awful.spawn("plock") end,
        {description="lock screen",group="awesome"}),
  awful.key({modkey, shift},"q",awesome.quit,
        {description="quit awesome",group="awesome"}),
  awful.key({modkey, shift, control},"r",awesome.restart,
        {description="reload awesome",group="awesome"}),
  awful.key({modkey},"w",set_random_pape,
        {description="set random wallpaper",group="awesome"}),
  awful.key({modkey, shift},"w",function() awful.spawn("select-pape") end,
        {description="set wallpaper",group="awesome"}),
  awful.key({modkey},"x",invoke_lua_execute_prompt,
        {description="lua execute prompt",group="awesome"}),
  awful.key({modkey, control},"F4",function() awful.spawn("systemctl hibernate") end,
        {description="hibernate computer",group="awesome"}),
  awful.key({modkey, shift},"F4",function() awful.spawn("systemctl suspend") end,
        {description="suspend to RAM computer",group="awesome"}),
  awful.key({modkey, shift, control},"F4",function() awful.spawn("poweroff") end,
        {description="power off computer",group="awesome"}),
  -- App
  awful.key({modkey},"Return",function() awful.spawn(terminal) end,
        {description="open a terminal",group="app"}),
  awful.key({modkey},"n",function() awful.spawn("nemo") end,
        {description="open file manager",group="app"}),
  awful.key({modkey},"g",function() awful.spawn("gimp") end,
        {description="open GIMP",group="app"}),
  awful.key({modkey},"b",function() awful.spawn(os.getenv("BROWSER")) end,
        {description="invoke web browser",group="internet"}),
  awful.key({control, shift},"d",function() awful.spawn("lightcord") end,
        {description="launch Discord",group="internet"}),
  awful.key({},"Print",function() awful.spawn("scrot -e 'mv $f ~/Pictures/Screenshots'") end,
        {description="Screenshot",group="screenshot"}),
  awful.key({control},"Print",function() awful.spawn("scrot -s -e 'mv $f ~/Pictures/Screenshots'") end,
        {description="Screenshot (area selection)",group="screenshot"}),
  awful.key({shift},"Print",function() awful.spawn("scrot -d 3 -e 'mv $f ~/Pictures/Screenshots'") end,
        {description="Screenshot (3s delay)",group="screenshot"}),
  awful.key({modkey},"e",function() awful.spawn("emacsclient -c -n") end,
        {description="invoke Spacemacs",group="emacs"}),
  awful.key({modkey, shift},"e",function() awful.spawn("emacs") end,
        {description="invoke Vanilla Emacs",group="emacs"}),
  awful.key({modkey},"a",function() awful.spawn.with_shell("awiki") end,
        {description="find and open an ArchWiki page",group="rofi"}),
  awful.key({modkey},"d",function() awful.spawn("rofi -combi-modi drun,window -show combi") end,
        {description="rofi for drun and windows",group="rofi"}),
  awful.key({modkey, meta},"d",function() awful.spawn("rofi -show ssh") end,
        {description="rofi for SSH",group="rofi"}),
  awful.key({modkey, shift},"p",function() awful.spawn.with_shell("rofi-pass -t") end,
        {description="types password from ~pass~",group="rofi"}),
  awful.key({modkey, control, shift},"p",function() awful.spawn.with_shell("rofi-pass") end,
        {description="copy password from ~pass~",group="rofi"}),
  awful.key({modkey, meta},"e",function() awful.spawn.with_shell("rofi-emoji") end,
        {description="select and copy emoji from list",group="rofi"}),
  awful.key({modkey, meta},"m",function() awful.spawn.with_shell("rofi-mount") end,
        {description="volume mounting helper",group="rofi"}),
  awful.key({modkey, meta},"u",function() awful.spawn.with_shell("rofi-umount") end,
        {description="volume unmounting helper",group="rofi"}),
  awful.key({modkey, control},"w",function() awful.spawn.with_shell("wacom-setup") end,
        {description="set up my wacom tablet",group="rofi"}),
  awful.key({modkey},"y",function() awful.spawn.with_shell("ytplay") end,
        {description="play web video in mpv",group="rofi"}),
  awful.key({modkey, shift},"y",function() awful.spawn.with_shell("rofi-ytdl") end,
        {description="download video from web",group="rofi"}),
  -- Client
  awful.key({modkey, control},"n",restore_minimized_clients,
        {description="restore minimized",group="client"}),
  awful.key({modkey},"s",function() awful.client.focus.byidx(-1) end,
        {description="focus previous client",group="client"}),
  awful.key({modkey},"t",function() awful.client.focus.byidx(1) end,
        {description="focus next client",group="client"}),
  awful.key({modkey, shift},"s",function() awful.client.swap.byidx(-1) end,
        {description="swap with previous client",group="client"}),
  awful.key({modkey, shift},"t",function() awful.client.swap.byidx(1) end,
        {description="swap with next client",group="client"}),
  awful.key({modkey},"u",awful.client.urgent.jumpto,
        {description="jump to urgent client",group="client"}),
  awful.key({modkey},"Tab",client_go_back,
        {description="go back",group="client"}),
  -- Layout
  awful.key({modkey},"r",function() awful.tag.incmwfact(0.05) end,
        {description="increase master width factor",group="layout"}),
  awful.key({modkey},"c",function() awful.tag.incmwfact(-0.05) end,
        {description="decrease master width factor",group="layout"}),
  awful.key({modkey, shift},"r",function() awful.tag.incnmaster(1, nil, true) end,
        {description="increase number of master clients",group="layout"}),
  awful.key({modkey, shift},"c",function() awful.tag.incnmaster(-1, nil, true) end,
        {description="decrease number of master clients",group="layout"}),
  awful.key({modkey, control},"r",function() awful.tag.incncol(1, nil, true) end,
        {description="increase number of colums",group="layout"}),
  awful.key({modkey, control},"c",function() awful.tag.incncol(-1, nil, true) end,
        {description="decrease number of colums",group="layout"}),
  awful.key({modkey},"space",function() awful.layout.inc(1) end,
        {description="next layout",group="layout"}),
  awful.key({modkey, meta},"space",function() awful.layout.inc(-1) end,
        {description="previous layout",group="layout"}),
  -- Media
  awful.key({modkey, meta},"+",function() awful.spawn.with_shell("mpc volume +2") end,
        {description="increase mpd volume",group="media"}),
  awful.key({modkey, meta},"-",function() awful.spawn.with_shell("mpc volume -2") end,
        {description="decrease mpd volume",group="media"}),
  awful.key({modkey, meta},"n",function() awful.spawn(terminal.." -e ncmpcpp -q") end,
        {description="spawn ncmpcpp",group="media"}),
  awful.key({modkey, meta},"v",function() awful.spawn(terminal.." -e ncmpcpp -qs visualizer") end,
        {description="spawn ncmpcpp visualizer",group="media"}),
  awful.key({},"XF86AudioLowerVolume",function() awful.spawn.with_shell("amixer -q set Master 2%- unmute") end,
        {description="lower volume",group="media"}),
  awful.key({modkey, control},"Prior",function() awful.spawn.with_shell("amixer -q set Master 2%- unmute") end,
        {description="lower volume",group="media"}),
  awful.key({},"XF86AudioRaiseVolume",function() awful.spawn.with_shell("amixer -q set Master 2%+ unmute") end,
        {description="raise volume",group="media"}),
  awful.key({modkey, control},"Next",function() awful.spawn.with_shell("amixer -q set Master 2%+ unmute") end,
        {description="lower volume",group="media"}),
  awful.key({},"XF86AudioMute",function() awful.spawn.with_shell("amixer -q set master 1+ toggle") end,
        {description="toggle mute audio",group="media"}),
  awful.key({modkey, control},"Prior",function() awful.spawn.with_shell("amixer -q set master 1+ toggle") end,
        {description="toggle mute audio",group="media"}),
  awful.key({},"XF86AudioPrev",function() awful.spawn.with_shell("mpc prev") end,
        {description="previous mpd track",group="media"}),
  awful.key({meta},"XF86AudioLowerVolume",function() awful.spawn.with_shell("mpc prev") end,
        {description="prevous mpd track",group="media"}),
  awful.key({modkey},"Prior",function() awful.spawn.with_shell("mpc prev") end,
        {description="previous mpd track",group="media"}),
  awful.key({},"XF86AudioNext",function() awful.spawn.with_shell("mpc next") end,
        {description="next mpd track",group="media"}),
  awful.key({meta},"XF86AudioRaiseVolume",function() awful.spawn.with_shell("mpc next") end,
        {description="next mpd track",group="media"}),
  awful.key({modkey},"Next",function() awful.spawn.with_shell("mpc next") end,
        {description="next mpd track",group="media"}),
  awful.key({},"XF86AudioPlay",function() awful.spawn.with_shell("mpc toggle") end,
        {description="toggle mpd playback",group="media"}),
  awful.key({modkey},"p",function() awful.spawn.with_shell("mpc toggle") end,
        {description="toggle mpd playback",group="media"}),
  awful.key({},"XF86AudioStop",function() awful.spawn.with_shell("mpc stop") end,
        {description="stop playback",group="media"}),
  awful.key({meta},"XF86AudioPlay",function() awful.spawn.with_shell("mpc stop") end,
        {description="stop playback",group="media"}),
  awful.key({modkey, meta},"p",function() awful.spawn.with_shell("mpc stop") end,
        {description="stop playback",group="media"}),
  -- Screen
  awful.key({modkey, meta},"t",function() awful.screen.focus_relative(1) end,
        {description="focus next screen",group="screen"}),
  awful.key({modkey, meta},"s",function() awful.screen.focus_relative(-1) end,
        {description="focus previous screen",group="screen"}),
  awful.key({},"XF86MonBrightnessDown",function() awful.spawn.with_shell("xbacklight -dec 1") end,
        {description="decrease screen brightness",group="screen"}),
  awful.key({modkey, meta},"Next",function() awful.spawn.with_shell("xbacklight -dec 1") end,
        {description="decrease screen brightness",group="screen"}),
  awful.key({},"XF86MonBrightnessUp",function() awful.spawn.with_shell("xbacklight -inc 1") end,
        {description="increase screen brightness",group="screen"}),
  awful.key({modkey, meta},"Prev",function() awful.spawn.with_shell("xbacklight -inc 1") end,
        {description="increase screen brightness",group="screen"}),
  awful.key({modkey},"F3",function() awful.spawn("arandr") end,
        {description="randr graphical frontend",group="screen"}),
  awful.key({modkey},"o",function() awful.screen.focus_relative(1) end,
        {description="focus next screen",group="screen"}),
  -- Tags
  awful.key({modkey},"Escape",awful.tag.history.restore,
        {description="go back",group="tag"}),
  awful.key({modkey, control},"t",awful.tag.viewprev,
        {description="view prev",group="tag"}),
  awful.key({modkey, control},"s",awful.tag.viewnext,
        {description="view next",group="tag"}),
  -- Misc
  awful.key({},"XF86TouchpadToggle",function() awful.spawn.with_shell("tttapping") end,
        {description="toggle touchpad tapping",group="misc"}),
  awful.key({modkey},"#19",function() view_tag_n(10) end,
        {description="view tag #10",group="tag"}),
  awful.key({modkey, control},"#19",function() toggle_tag_n(10) end,
        {description="toggle tag #10",group="tag"}),
  awful.key({modkey, shift},"#19",function() move_focused_to_tag_n(10) end,
        {description="move focused client to tag #10",group="tag"}),
  awful.key({modkey, control, shift},"#19",function() toggle_focused_client_to_tag_n(10) end,
        {description="Toggle focused client on tag #10",group="tag"}),

  awful.key({modkey},"#18",function() view_tag_n(9) end,
        {description="view tag #9",group="tag"}),
  awful.key({modkey, control},"#18",function() toggle_tag_n(9) end,
        {description="toggle tag #9",group="tag"}),
  awful.key({modkey, shift},"#18",function() move_focused_to_tag_n(9) end,
        {description="move focused client to tag #9",group="tag"}),
  awful.key({modkey, control, shift},"#18",function() toggle_focused_client_to_tag_n(9) end,
        {description="Toggle focused client on tag #9",group="tag"}),

  awful.key({modkey},"#17",function() view_tag_n(8) end,
        {description="view tag #8",group="tag"}),
  awful.key({modkey, control},"#17",function() toggle_tag_n(8) end,
        {description="toggle tag #8",group="tag"}),
  awful.key({modkey, shift},"#17",function() move_focused_to_tag_n(8) end,
        {description="move focused client to tag #8",group="tag"}),
  awful.key({modkey, control, shift},"#17",function() toggle_focused_client_to_tag_n(8) end,
        {description="Toggle focused client on tag #8",group="tag"}),

  awful.key({modkey},"#16",function() view_tag_n(7) end,
        {description="view tag #7",group="tag"}),
  awful.key({modkey, control},"#16",function() toggle_tag_n(7) end,
        {description="toggle tag #7",group="tag"}),
  awful.key({modkey, shift},"#16",function() move_focused_to_tag_n(7) end,
        {description="move focused client to tag #7",group="tag"}),
  awful.key({modkey, control, shift},"#16",function() toggle_focused_client_to_tag_n(7) end,
        {description="Toggle focused client on tag #7",group="tag"}),

  awful.key({modkey},"#15",function() view_tag_n(6) end,
        {description="view tag #6",group="tag"}),
  awful.key({modkey, control},"#15",function() toggle_tag_n(6) end,
        {description="toggle tag #6",group="tag"}),
  awful.key({modkey, shift},"#15",function() move_focused_to_tag_n(6) end,
        {description="move focused client to tag #6",group="tag"}),
  awful.key({modkey, control, shift},"#15",function() toggle_focused_client_to_tag_n(6) end,
        {description="Toggle focused client on tag #6",group="tag"}),

  awful.key({modkey},"#14",function() view_tag_n(5) end,
        {description="view tag #5",group="tag"}),
  awful.key({modkey, control},"#14",function() toggle_tag_n(5) end,
        {description="toggle tag #5",group="tag"}),
  awful.key({modkey, shift},"#14",function() move_focused_to_tag_n(5) end,
        {description="move focused client to tag #5",group="tag"}),
  awful.key({modkey, control, shift},"#14",function() toggle_focused_client_to_tag_n(5) end,
        {description="Toggle focused client on tag #5",group="tag"}),

  awful.key({modkey},"#13",function() view_tag_n(4) end,
        {description="view tag #4",group="tag"}),
  awful.key({modkey, control},"#13",function() toggle_tag_n(4) end,
        {description="toggle tag #4",group="tag"}),
  awful.key({modkey, shift},"#13",function() move_focused_to_tag_n(4) end,
        {description="move focused client to tag #4",group="tag"}),
  awful.key({modkey, control, shift},"#13",function() toggle_focused_client_to_tag_n(4) end,
        {description="Toggle focused client on tag #4",group="tag"}),

  awful.key({modkey},"#12",function() view_tag_n(3) end,
        {description="view tag #3",group="tag"}),
  awful.key({modkey, control},"#12",function() toggle_tag_n(3) end,
        {description="toggle tag #3",group="tag"}),
  awful.key({modkey, shift},"#12",function() move_focused_to_tag_n(3) end,
        {description="move focused client to tag #3",group="tag"}),
  awful.key({modkey, control, shift},"#12",function() toggle_focused_client_to_tag_n(3) end,
        {description="Toggle focused client on tag #3",group="tag"}),

  awful.key({modkey},"#11",function() view_tag_n(2) end,
        {description="view tag #2",group="tag"}),
  awful.key({modkey, control},"#11",function() toggle_tag_n(2) end,
        {description="toggle tag #2",group="tag"}),
  awful.key({modkey, shift},"#11",function() move_focused_to_tag_n(2) end,
        {description="move focused client to tag #2",group="tag"}),
  awful.key({modkey, control, shift},"#11",function() toggle_focused_client_to_tag_n(2) end,
        {description="Toggle focused client on tag #2",group="tag"}),

  awful.key({modkey},"#10",function() view_tag_n(1) end,
        {description="view tag #1",group="tag"}),
  awful.key({modkey, control},"#10",function() toggle_tag_n(1) end,
        {description="toggle tag #1",group="tag"}),
  awful.key({modkey, shift},"#10",function() move_focused_to_tag_n(1) end,
        {description="move focused client to tag #1",group="tag"}),
  awful.key({modkey, control, shift},"#10",function() toggle_focused_client_to_tag_n(1) end,
        {description="Toggle focused client on tag #1",group="tag"})
)
root.keys(globalkeys)

clientkeys = gears.table.join(
  -- Client
  awful.key({modkey, meta},"c",function(c) awful.placement.centered(c) end,
        {description="center client",group="client"}),
  awful.key({modkey},"f",function(c) toggle_fullscreen_client(c) end,
        {description="toggle fullscreen",group="client"}),
  awful.key({modkey},"m",function(c) toggle_maximized(c) end,
        {description="toggle maximized",group="client"}),
  awful.key({modkey, shift},"m",function(c) toggle_horizontal_maximized(c) end,
        {description="toggle horizontally maximized",group="client"}),
  awful.key({modkey, control},"m",function(c) toggle_vertical_maximized(c) end,
        {description="toggle vertically maximized",group="client"}),
  awful.key({modkey, shift},"n",function(c) c.minimized = true end,
        {description="minimize",group="client"}),
  awful.key({modkey, shift},"o",function(c) c:move_to_screen() end,
        {description="move to screen",group="client"}),
  awful.key({modkey},"q",function(c) c:kill() end,
        {description="close client",group="client"}),
  awful.key({modkey, shift, control},"m",function(c) c:swap(awful.client.getmaster()) end,
        {description="swap with master client",group="client"}),
  awful.key({modkey},"v",function(c) c.ontop = not c.ontop end,
        {description="toggle keep on top",group="client"}),
  awful.key({modkey, control},"f",awful.client.floating.toggle,
        {description="toggle floating",group="client"})
)

Applications

KeyModifiersLambda?ActionWhat it doesGroup
Returnmodkeyyesawful.spawn(terminal)open a terminalapp
nmodkeyspawnnemoopen file managerapp
gmodkeyspawngimpopen GIMPapp

Internet apps

KeyModifiersLambda?ActionWhat it doesGroup
bmodkeyyesawful.spawn(os.getenv(“BROWSER”))invoke web browserinternet
dcontrol, shiftspawnlightcordlaunch Discordinternet

Screenshots

KeyModifiersLambda?ActionWhat it doesGroup
Printspawnscrot -e ‘mv $f ~/Pictures/Screenshots’Screenshotscreenshot
Printcontrolspawnscrot -s -e ‘mv $f ~/Pictures/Screenshots’Screenshot (area selection)screenshot
Printshiftspawnscrot -d 3 -e ‘mv $f ~/Pictures/Screenshots’Screenshot (3s delay)screenshot

Emacs

KeyModifiersLambda?ActionWhat it doesGroup
emodkeyspawnemacsclient -c -ninvoke Spacemacsemacs
emodkey, shiftspawnemacsinvoke Vanilla Emacsemacs

Rofi

KeyModifiersLambda?ActionWhat it doesGroup
amodkeyshellawikifind and open an ArchWiki pagerofi
dmodkeyspawnrofi -combi-modi drun,window -show combirofi for drun and windowsrofi
dmodkey, metaspawnrofi -show sshrofi for SSHrofi
pmodkey, shiftshellrofi-pass -ttypes password from passrofi
pmodkey, control, shiftshellrofi-passcopy password from passrofi
emodkey, metashellrofi-emojiselect and copy emoji from listrofi
mmodkey, metashellrofi-mountvolume mounting helperrofi
umodkey, metashellrofi-umountvolume unmounting helperrofi
wmodkey, controlshellwacom-setupset up my wacom tabletrofi
ymodkeyshellytplayplay web video in mpvrofi
ymodkey, shiftshellrofi-ytdldownload video from webrofi

Awesome

Here will be declared some shortcuts directly related to Awesome itself.

KeyModifiersLambda?ActionWhat it doesGroup
hmodkeynohotkeys_popup.show_helpshow helpawesome
hmodkey, shiftyesmainmenu:show()show main menuawesome
lmodkeyspawnplocklock screenawesome
qmodkey, shiftnoawesome.quitquit awesomeawesome
rmodkey, shift, controlnoawesome.restartreload awesomeawesome
wmodkeynoset_random_papeset random wallpaperawesome
wmodkey, shiftspawnselect-papeset wallpaperawesome
xmodkeynoinvoke_lua_execute_promptlua execute promptawesome
F4modkey, controlspawnsystemctl hibernatehibernate computerawesome
F4modkey, shiftspawnsystemctl suspendsuspend to RAM computerawesome
F4modkey, shift, controlspawnpoweroffpower off computerawesome

Clients

These shortcuts are related to clients (aka windows) management.

KeyModifiersLambda?ActionWhat it doesGroupClientkey?
cmodkey, metayesawful.placement.centered©center clientclientyes
fmodkeyyestoggle_fullscreen_client©toggle fullscreenclientyes
mmodkeyyestoggle_maximized©toggle maximizedclientyes
mmodkey, shiftyestoggle_horizontal_maximized©toggle horizontally maximizedclientyes
mmodkey, controlyestoggle_vertical_maximized©toggle vertically maximizedclientyes
nmodkey, shiftyesc.minimized = trueminimizeclientyes
nmodkey, controlnorestore_minimized_clientsrestore minimizedclientno
omodkey, shiftyesc:move_to_screen()move to screenclientyes
qmodkeyyesc:kill()close clientclientyes
smodkeyyesawful.client.focus.byidx(-1)focus previous clientclientno
tmodkeyyesawful.client.focus.byidx(1)focus next clientclientno
smodkey, shiftyesawful.client.swap.byidx(-1)swap with previous clientclientno
tmodkey, shiftyesawful.client.swap.byidx(1)swap with next clientclientno
mmodkey, shift, controlyesc:swap(awful.client.getmaster())swap with master clientclientyes
umodkeynoawful.client.urgent.jumptojump to urgent clientclientno
vmodkeyyesc.ontop = not c.ontoptoggle keep on topclientyes
fmodkey, controlnoawful.client.floating.toggletoggle floatingclientyes
Tabmodkeynoclient_go_backgo backclientno

Layout manipulation

KeyModifiersLambda?ActionWhat it doesGroup
rmodkeyyesawful.tag.incmwfact(0.05)increase master width factorlayout
cmodkeyyesawful.tag.incmwfact(-0.05)decrease master width factorlayout
rmodkey, shiftyesawful.tag.incnmaster(1, nil, true)increase number of master clientslayout
cmodkey, shiftyesawful.tag.incnmaster(-1, nil, true)decrease number of master clientslayout
rmodkey, controlyesawful.tag.incncol(1, nil, true)increase number of columslayout
cmodkey, controlyesawful.tag.incncol(-1, nil, true)decrease number of columslayout
spacemodkeyyesawful.layout.inc(1)next layoutlayout
spacemodkey, metayesawful.layout.inc(-1)previous layoutlayout

Media

KeyModifiersLambda?ActionWhat it doesGroup
+modkey, metashellmpc volume +2increase mpd volumemedia
-modkey, metashellmpc volume -2decrease mpd volumemedia
nmodkey, metaterminalncmpcpp -qspawn ncmpcppmedia
vmodkey, metaterminalncmpcpp -qs visualizerspawn ncmpcpp visualizermedia
XF86AudioLowerVolumeshellamixer -q set Master 2%- unmutelower volumemedia
Priormodkey, controlshellamixer -q set Master 2%- unmutelower volumemedia
XF86AudioRaiseVolumeshellamixer -q set Master 2%+ unmuteraise volumemedia
Nextmodkey, controlshellamixer -q set Master 2%+ unmutelower volumemedia
XF86AudioMuteshellamixer -q set master 1+ toggletoggle mute audiomedia
Priormodkey, controlshellamixer -q set master 1+ toggletoggle mute audiomedia
XF86AudioPrevshellmpc prevprevious mpd trackmedia
XF86AudioLowerVolumemetashellmpc prevprevous mpd trackmedia
Priormodkeyshellmpc prevprevious mpd trackmedia
XF86AudioNextshellmpc nextnext mpd trackmedia
XF86AudioRaiseVolumemetashellmpc nextnext mpd trackmedia
Nextmodkeyshellmpc nextnext mpd trackmedia
XF86AudioPlayshellmpc toggletoggle mpd playbackmedia
pmodkeyshellmpc toggletoggle mpd playbackmedia
XF86AudioStopshellmpc stopstop playbackmedia
XF86AudioPlaymetashellmpc stopstop playbackmedia
pmodkey, metashellmpc stopstop playbackmedia

Screen

KeyModifiersLambda?ActionWhat it doesGroup
tmodkey, metayesawful.screen.focus_relative(1)focus next screenscreen
smodkey, metayesawful.screen.focus_relative(-1)focus previous screenscreen
XF86MonBrightnessDownshellxbacklight -dec 1decrease screen brightnessscreen
Nextmodkey, metashellxbacklight -dec 1decrease screen brightnessscreen
XF86MonBrightnessUpshellxbacklight -inc 1increase screen brightnessscreen
Prevmodkey, metashellxbacklight -inc 1increase screen brightnessscreen
F3modkeyspawnarandrrandr graphical frontendscreen
omodkeyyesawful.screen.focus_relative(1)focus next screenscreen

Tags

KeyModifiersLambda?ActionWhat it doesGroup
Escapemodkeynoawful.tag.history.restorego backtag
tmodkey, controlnoawful.tag.viewprevview prevtag
smodkey, controlnoawful.tag.viewnextview nexttag

Another set of shortcuts is linked to the number row on the keyboard that allow the manipulation of the default tags that range from 1 to 10 (the latter is displayed as 0). Here is what the possible actions are:

KeyModifiersActionWhat it doesGroup
Numbermodkeyview_tag_n(view tag #tag
Numbermodkey, controltoggle_tag_n(toggle tag #tag
Numbermodkey, shiftmove_focused_to_tag_n(move focused client to tag #tag
Numbermodkey, control, shifttoggle_focused_client_to_tag_n(Toggle focused client on tag #tag

Misc

In this category you will find other keybindings that do not fit in other categories. For now, the only keybinding that is in this category is for toggling the touchpad’s tapping ability. This is linked to a special script I wrote here.

KeyModifiersLambda?ActionWhat it doesGroup
XF86TouchpadToggleshelltttappingtoggle touchpad tappingmisc

Rules

With awful.rules, users are able to describe some rules for window clients when the latter spawn, such as their placement, their properties or even execute a script. A rule can be applied through the manage signal, and they are all stored in awful.rules.rules, the global rules table, as follows:

awful.rules.rules = {
  -- Rules here
}

For more documentation on rules and their syntax, you can read the official documentationopen in new window.

Universal rules

The first rule is a universal rule which will match all clients, as you can see with its syntax below:

{ rule = {},
  properties = {
    -- List of properties
  }
}

Here is the list of properties with their value to apply to all clients, and a short explanation as to what they do.

PropertyValueWhat it does
border_widthbeautiful.border_widthSet the width of the window’s border
border_colorbeautiful.border_normalSet the color of the window’s border
focusawful.client.focus.filterSet focus on the new window, except filtered out windows
raisetrueSet it as raised window
keysclientkeysSet the client’s shortcuts set in Shortcuts/Clients
buttonsclientbuttonsSet the client’s mouse shortcuts from Mouse bindings
screenawful.screen.preferredSpawn the client on the main screen
placementawful.placement.noopen in new window_overlap+awful.placement.no_offscreenAvoid the client to appear off the screen and overlaping another client
round_cornerstrueEnable rounded corners for client

This is what my universal rules look like:

{ 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,
    round_corners = true
  }
}

Floating clients

Some clients will be declared by default as floating windows. For this, we will declare a rule that will match any of the provided conditions:

PropertyMatchesComment
instancepinentryMatches any Polkit
classArandrVisual frontend for Randr
classSxivSimple X Image Viewer
classTor BrowserNeeds a fixed window size to avoid fingerprinting
nameEvent Testerxev
rolepop-upAny pop-up window, such as Chromium’s detached Developer Tools

If any of these conditions is matched, then the client will be set as floating, as you can see below:

{ rule_any = {
    instance = { "pinentry" },
    class = { "Arandr" },
    class = { "Sxiv" },
    class = { "Tor Browser" },
    name = { "Event Tester" },
    role = { "pop-up" }
}, properties = { floating = true }}

Titlebars

Any normal or dialog client will get a titlebar. This is enabled like so:

{ rule_any = {type = { "normal", "dialog" }
             }, properties = { titlebars_enabled = true }
}

Default tag for clients

With the use of some rules, it is possible to define which client are assigned to which tag by default.

Client PropertyValueTag
classEmacs2
classfirefox3
classNemo4
classGimp*5
classSignal8
classSteam9
classMattermost0
classdiscord0
classlightcord0

This is what these rules look like:

{rule = {class = "Emacs"}, properties = {screen = 1, tag = "2"} },
{rule = {class = "firefox"}, properties = {screen = 1, tag = "3"} },
{rule = {class = "Nemo"}, properties = {screen = 1, tag = "4"} },
{rule = {class = "Gimp*"}, properties = {screen = 1, tag = "5"} },
{rule = {class = "Signal"}, properties = {screen = 1, tag = "8"} },
{rule = {class = "Steam"}, properties = {screen = 1, tag = "9"} },
{rule = {class = "Mattermost"}, properties = {screen = 1, tag = "0"} },
{rule = {class = "discord"}, properties = {screen = 1, tag = "0"} },
{rule = {class = "lightcord"}, properties = {screen = 1, tag = "0"} }

Signals

Signals are a way for Awesome to handle events, such as client creation or deletion.

Client creation

When a new client is created, the manage signal is emited. When so, the following snippet ensures this new client is not off the screen, unless its position was deliberately set by a program or by the user. It will also spawn the new client where the mouse currently is.

client.connect_signal("manage", function (c)
  awful.client.movetoscreen(c, mouse.screen)
  if awesome.startup
      and not c.size_hints.user_position
      and not c.size_hints.program_position then
    awful.placement.no_offscreen(c)
  end
end)

Titlebar creation

It is possible for Awesome to send request signals, such as the request to create titlebar (generally for new clients). The following snippet handles this titlebar creation if titlebar creation was set to true in the rules. For a detailed explanation of the code, see below.

client.connect_signal("request::titlebars", function(c)
                        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, {position="left", size = 22}) : setup {
                          { -- Top
                            awful.titlebar.widget.closebutton(c),
                            awful.titlebar.widget.minimizebutton(c),
                            awful.titlebar.widget.maximizedbutton(c),
                            layout = wibox.layout.fixed.vertical()
                          },
                          {
                            layout = wibox.layout.fixed.vertical()
                          }, -- Middle
                          { -- Bottom
                            awful.titlebar.widget.floatingbutton(c),
                            layout = wibox.layout.fixed.vertical()
                          },
                          layout = wibox.layout.align.vertical,
                          position = "left"
                        }
end)

The function has two main parts: the creation of the titlebar buttons (mouse handling on the titlebar), and the creation of the titlebar itself. The creation of the button is done by creating a local variable buttons which will be a table created by the library gears, in which will be buttons created by the user.

local buttons = gears.table.join(
  -- Buttons declared here
)

You can see a left click will enable the user to raise the window, but also it will enable the user to move the window (if it is floating of course).

awful.button({ }, 1, function()
    c:emit_signal("request::activate", "titlebar", {raise = true})
    awful.mouse.client.move(c)
end)

A right click on the titlebar will also raise the window, but will instead allow the user to resize the client.

awful.button({ }, 3, function()
  c:emit_signal("request::activate", "titlebar", {raise = true})
  awful.mouse.client.resize(c)
end)

Next comes the actual creation of the titlebar for the client c. For that, we call awful.titlebar(), tell it where the titlebar should be relative to the client and what its setup should be. The full call should look like so:

awful.titlebar(c, {position="left", size = 22}) : setup {
  { -- Top
    awful.titlebar.widget.closebutton(c),
    awful.titlebar.widget.minimizebutton(c),
    awful.titlebar.widget.maximizedbutton(c),
    layout = wibox.layout.fixed.vertical()
  },
  {
    layout = wibox.layout.fixed.vertical()
  }, -- Middle
  { -- Bottom
    awful.titlebar.widget.floatingbutton(c),
    layout = wibox.layout.fixed.vertical()
  },
  layout = wibox.layout.align.vertical,
  position = "left"
}

In the setup, I need to repeat to Awesome the titlebar should be on the left of the client, and I also tell it the layout alignment of the titlebar will be vertical, because I like vertial titlebars. I also first send it three tables:

  • The top or left elements of the titlebar (here the top)
  • The middle elements of the titlebar
  • The bottom or right elements of the titlebar (here the bottom)

You can notice in the setup’s code below that I haven’t included anything in the middle elements, the only elements I am interested in are the top and bottom elements. In the top elements, I have (top to bottom):

  • A close button
  • A maximize button
  • A minimize button
  • And an indication to Awesome these elements should be vertically aligned

To make Awesome happy, I also must indicate that the middle elements are vertically aligned, and then I can declare my bottom elements:

  • A button for toggling client floating
  • And again the indication to Awesome these elements should be vertically aligned
{ -- Top
  awful.titlebar.widget.closebutton(c),
  awful.titlebar.widget.minimizebutton(c),
  awful.titlebar.widget.maximizedbutton(c),
  layout = wibox.layout.fixed.vertical()
},
{
  layout = wibox.layout.fixed.vertical()
}, -- Middle
{ -- Bottom
  awful.titlebar.widget.floatingbutton(c),
  layout = wibox.layout.fixed.vertical()
},
layout = wibox.layout.align.vertical,
position = "left"

Changes of focus

The default Awesome configuration enables the following snippet of code that makes windows hovered by the user’s mouse focused. Just for completeness’ sake, I included it in this document, but be aware this won’t be tangled into my configuration file and focus will not follow my mouse.

client.connect_signal("mouse::enter", function(c)
                        c:emit_signal("request::activate", "mouse_enter", {raise = false})
end)

It is also possible to change the color of the borders based on client focus. While my clients don’t have any border, they do have a titlebar which color changes based on the client’s focus. This is handled by the following code snippet:

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)

Autostart

By simply adding a line requesting to spawn a command, it is possible to create some autolaunch. All of my autolaunched apps are launch through a custom script which you can [find here](file:///root/org/config/bin.md). The command gets called with awful.spawn.with_shell(), as you can see below.

awful.spawn.with_shell("autostart")