From d841bacb12879acca8e30d2f1fa61da6f3e69d2a Mon Sep 17 00:00:00 2001 From: Lucien Cartier-Tilet Date: Fri, 10 Apr 2020 19:32:58 +0200 Subject: [PATCH] Added AwesomeWM configuration --- org/config/awesome.org | 1449 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1449 insertions(+) create mode 100644 org/config/awesome.org diff --git a/org/config/awesome.org b/org/config/awesome.org new file mode 100644 index 0000000..2eebbb4 --- /dev/null +++ b/org/config/awesome.org @@ -0,0 +1,1449 @@ +# -*- org-confirm-babel-evaluate: nil -*- +#+title: AwesomeWM configuration +#+INCLUDE: headers.org +#+OPTIONS: auto-id:t +#+HTML_HEAD_EXTRA: +#+HTML_HEAD_EXTRA: +#+HTML_HEAD_EXTRA: +#+PROPERTY: header-args :noweb yes :exports code :tangle no :exports none +#+PROPERTY: header-args:lua :tangle ~/.config/awesome/rc.lua :comments link :exports code :noweb yes +#+STARTUP: content + +* Table of Contents :TOC:noexport: + :PROPERTIES: + :CUSTOM_ID: h-fd4262b7-b9e1-49c8-83fd-02207a6388c0 + :END: + +- [[#introduction][Introduction]] +- [[#loading-libraries][Loading libraries]] +- [[#error-handling][Error handling]] +- [[#variable-definitions][Variable definitions]] + - [[#themes][Themes]] + - [[#default-terminal-and-text-editor][Default terminal and text editor]] + - [[#keys][Keys]] + - [[#wallpapers-directory][Wallpapers directory]] +- [[#custom-functions][Custom functions]] + - [[#wallpaper-related-functions][Wallpaper-related functions]] + - [[#set-a-random-wallpaper][Set a random wallpaper]] + - [[#restore-previous-wallpaper][Restore previous wallpaper]] + - [[#layout-manipulation][Layout manipulation]] + - [[#clients-manipulation][Clients manipulation]] + - [[#tag-manipulation][Tag manipulation]] + - [[#awesome-prompt][Awesome prompt]] +- [[#layouts][Layouts]] +- [[#top-bar][Top bar]] + - [[#menus][Menus]] + - [[#other-widgets][Other widgets]] + - [[#tag-list][Tag list]] + - [[#tasks-list][Tasks list]] +- [[#theme-and-display][Theme and display]] + - [[#screen-update][Screen update]] +- [[#mouse-bindings][Mouse bindings]] +- [[#keybindings][Keybindings]] + - [[#applications][Applications]] + - [[#awesome][Awesome]] + - [[#clients][Clients]] + - [[#layout-manipulation-1][Layout manipulation]] + - [[#media][Media]] + - [[#screen][Screen]] + - [[#tags][Tags]] +- [[#rules][Rules]] + - [[#universal-rules][Universal rules]] + - [[#floating-clients][Floating clients]] + - [[#titlebars][Titlebars]] + - [[#default-tag-for-clients][Default tag for clients]] +- [[#signals][Signals]] + - [[#client-creation][Client creation]] + - [[#titlebar-creation][Titlebar creation]] + - [[#changes-of-focus][Changes of focus]] +- [[#autostart][Autostart]] + +* Introduction + :PROPERTIES: + :CUSTOM_ID: h-a4b01b3e-dc01-489d-9abc-f2f7f25978c4 + :END: + 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~. + +* Loading libraries + :PROPERTIES: + :CUSTOM_ID: h-bbe91e08-98a8-4ef3-acfb-def01ba1fb4d + :END: + 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: + #+BEGIN_SRC lua + math.randomseed(os.time()) + #+END_SRC + + 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. + #+BEGIN_SRC lua + pcall(require, "luarocks.loader") + #+END_SRC + + Next, we’ll also load the following libraries + #+NAME: table-imported-libraries + | Library | Import as | What it is | + |---------------------+---------------+---------------------------| + | gears | gears | Standard Awesome library | + | awful | awful | Standard Awesome library | + | wibox | wibox | Widget and layout library | + | beautiful | beautiful | Theme handling library | + | naughty | naughty | Notification library | + | menubar | menubar | Create menus | + | awful.hotkeys_popup | hotkeys_popup | Help window for hotkeys | + + #+NAME: imported-libraries + #+BEGIN_SRC emacs-lisp :var libs=table-imported-libraries :cache yes + (mapconcat (lambda (x) (format "local %s = require(\"%s\")" + (cadr x) + (car x))) + libs + "\n") + #+END_SRC + + #+RESULTS[a66d7b66dbd4b4001dc3f649840b66761cc915b5]: imported-libraries + : 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") + + Here is the actual code in the config file: + #+BEGIN_SRC lua + <> + #+END_SRC + + I also want to be able to autofocus the first window when I go to another + workspace, so let’s require that: + #+BEGIN_SRC lua + require("awful.autofocus") + #+END_SRC + + And finally, I want to be able to declare some shortcuts specific to some + appls thanks to the hotkeys help widget. + #+BEGIN_SRC lua + require("awful.hotkeys_popup.keys") + #+END_SRC + + By the way, let’s initialize the ~random~ method of the ~math~ library: + #+BEGIN_SRC lua + math.randomseed(os.time()) + #+END_SRC + +* Error handling + :PROPERTIES: + :CUSTOM_ID: h-6c9ab69b-433d-4c99-92a6-0cdc84e7d23f + :END: + 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. + #+BEGIN_SRC lua + if awesome.startup_errors then + naughty.notify({ preset = naughty.config.presets.critical, + title = "Oops, there were errors during startup!", + text = awesome.startup_errors }) + end + #+END_SRC + + And this code handles runtime errors after startup thanks to signals. + #+BEGIN_SRC lua + 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 + #+END_SRC + +* Variable definitions + :PROPERTIES: + :CUSTOM_ID: h-85fcc156-5baf-4c8c-b771-7d7ae0466518 + :END: +** Themes + :PROPERTIES: + :CUSTOM_ID: h-b2f0f248-68ba-4bdd-a63d-98ee640b071c + :END: + The following line will load the default colors, icons, fonts and wallpapers. + It is possible to write a custom theme for Awesome by loading a different Lua + file. + #+BEGIN_SRC lua + beautiful.init("/home/phundrak/.config/awesome/xresources/theme.lua") + #+END_SRC + +** Default terminal and text editor + :PROPERTIES: + :CUSTOM_ID: h-a57e91b3-fd2a-4fc4-ac2c-2c8362882163 + :END: + 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. + #+BEGIN_SRC lua + terminal = "st" + editor = os.getenv("EDITOR") or "emacsclient -c" + #+END_SRC + +** Keys + :PROPERTIES: + :CUSTOM_ID: h-d615bb11-b35d-4b7b-af6c-1f8e2fa4c647 + :END: + 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. + #+BEGIN_SRC lua + modkey = "Mod4" + shift = "Shift" + control = "Control" + #+END_SRC + +** Wallpapers directory + :PROPERTIES: + :CUSTOM_ID: h-027a8758-fa96-473f-8ad3-44e07a5e7f4b + :END: + This variable is a variable I personally set for a function described below + in order to have a variable pointing to my wallpaper directory. + #+BEGIN_SRC lua + local papes_dir = "~/Pictures/Wallpapers" + #+END_SRC + +* Custom functions + :PROPERTIES: + :CUSTOM_ID: h-7f60dc78-b63b-4523-9c01-331aa78720f2 + :END: +** Wallpaper-related functions + :PROPERTIES: + :CUSTOM_ID: h-f961557b-1db6-4acd-90dc-0666316bebdb + :END: +*** Set a random wallpaper + :PROPERTIES: + :CUSTOM_ID: h-9983ae6b-e372-41b7-8cce-08f62781fa81 + :END: + The following function allows the user to get the list of available + wallpapers I have in my wallpapers directory. This depends on the variable + described in [[#h-027a8758-fa96-473f-8ad3-44e07a5e7f4b]]. By the way, the assert + on line 3 allows Lua to wait for ~popen~ to run. + #+BEGIN_SRC lua -n + local function get_papes() + local i, papes, popen = 0, {}, io.popen + local pfile = assert(popen('find '..papes_dir..' -type f')) + for filename in pfile:lines() do + i = i + 1 + papes[i] = filename + end + pfile:close() + return papes + end + #+END_SRC + + This function is another one that sets a random wallpaper from the list of + wallpapers provided by ~get_papes()~ described above. This depends on + [[https://github.com/l3ib/nitrogen/][Nitrogen]] and [[https://github.com/dylanaraps/pywal][Pywal]]. + #+BEGIN_SRC lua + local function set_random_pape() + papes = get_papes() + pape = papes[math.random(#papes)] + awful.spawn.with_shell("nitrogen --set-scaled "..pape.." && wal -o wal-set -i "..pape) + naughty.notify({ prest = naughty.config.presets.normal, + title = "Wallpaper change", + text = "Done!"}) + end + #+END_SRC + +*** Restore previous wallpaper + :PROPERTIES: + :CUSTOM_ID: h-39816309-d36d-4fb1-9c76-942a85b7407b + :END: + I also wrote the following function that will restore the previously set + wallpaper: + #+BEGIN_SRC lua + local function set_wallpaper(_) + awful.spawn.with_shell("nitrogen --set-scaled (cat $HOME/.cache/wal/wal)") + awful.spawn.with_shell("wal -i (cat $HOME/.cache/wal/wal)") + awful.spawn.with_shell("xrdb $HOME/.Xresources") + end + #+END_SRC + +** Layout manipulation + :PROPERTIES: + :CUSTOM_ID: h-08050731-281d-4ab8-902e-bcd2e3b3d452 + :END: + The following function is used by a shortcut described below in + [[#h-521b02ca-0ad3-44e8-8d5b-1e75401490da]]. + #+BEGIN_SRC lua + local function client_go_back() + awful.client.focus.history.previous() + if client.focus then + client.focus:raise() + end + end + #+END_SRC + +** Clients manipulation + :PROPERTIES: + :CUSTOM_ID: h-37850b12-d82e-4657-b13e-42cc1d4fc2dd + :END: + #+BEGIN_SRC lua + 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 + #+END_SRC + + #+BEGIN_SRC lua + local function toggle_fullscreen_client(c) + c.fullscreen = not c.fullscreen + c:raise() + end + #+END_SRC + + #+BEGIN_SRC lua + local function toggle_maximized(c) + c.maximized = not c.maximized + c:raise() + end + #+END_SRC + + #+BEGIN_SRC lua + local function toggle_vertical_maximized(c) + c.maximized_vertical = not c.maximized_vertical + c:raise() + end + #+END_SRC + + #+BEGIN_SRC lua + local function toggle_horizontal_maximized(c) + c.maximized_horizontal = not c.maximized_horizontal + c:raise() + end + #+END_SRC + +** Tag manipulation + :PROPERTIES: + :CUSTOM_ID: h-8d449633-cba8-43c3-9000-25d8fbe9204e + :END: + #+BEGIN_SRC lua + local function view_tag_n(i) + local screen = awful.screen.focused() + local tag = screen.tags[i] + if tag then + tag:view_only() + end + end + #+END_SRC + + #+BEGIN_SRC lua + 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 + #+END_SRC + + #+BEGIN_SRC lua + 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 + #+END_SRC + + #+BEGIN_SRC lua + 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 + #+END_SRC + +** Awesome prompt + :PROPERTIES: + :CUSTOM_ID: h-e2eb6c6f-1efb-451e-90d1-cc6dc217498b + :END: + #+BEGIN_SRC lua + 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 + #+END_SRC + +* Layouts + :PROPERTIES: + :CUSTOM_ID: h-97ec07e5-68de-4c7e-bdf2-84255c09b552 + :END: + 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. + #+NAME: table-layouts + | Layout | Enabled? | + |-----------------+----------| + | magnifier | yes | + | fair | yes | + | fair.horizontal | yes | + | floating | yes | + | tile | yes | + | tile.left | yes | + | tile.bottom | yes | + | tile.top | yes | + | spiral | yes | + | max | yes | + | spiral.dwindle | no | + | max.fullscreen | no | + | corner.nw | no | + | corner.ne | no | + | corner.sw | no | + | corner.se | no | + + #+NAME: list-layouts + #+BEGIN_SRC emacs-lisp :var layouts=table-layouts :cache yes + (mapconcat (lambda (x) (if (string= (cadr x) "yes") + (format "awful.layout.suit.%s,\n" (car x)))) + layouts + "") + #+END_SRC + + #+RESULTS[cda51a1db4af80af635cc4205a4077055b7b157f]: list-layouts + #+begin_example + awful.layout.suit.magnifier, + awful.layout.suit.fair, + awful.layout.suit.fair.horizontal, + 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.spiral, + awful.layout.suit.max, + #+end_example + + Here is the code that activates these layouts: + #+BEGIN_SRC lua + awful.layout.layouts = { + <> + } + #+END_SRC + +* Top bar + :PROPERTIES: + :CUSTOM_ID: h-cc08d2b1-ac99-4174-9af0-8bdf1f8a3491 + :END: + 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. + +** Menus + :PROPERTIES: + :CUSTOM_ID: h-1ac72dd7-b8ea-45e6-b220-4462783eb87d + :END: + #+NAME: make-menu + #+BEGIN_SRC emacs-lisp :var menu=table-awesome-menu + (mapconcat (lambda (x) + (format "{ \"%s\", %s }" + (car x) + (mapconcat (lambda (y) (format "%s" y)) + (cdr x) + ","))) + menu + ",\n") + #+END_SRC + + #+RESULTS: make-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 } + + 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: + #+NAME: table-awesome-menu + | Name | Command | + |-------------+---------------------------------------------------------------------| + | hotkeys | function() hotkeys_popup.show_help(nil, awful.screen.focused()) end | + | edit config | editor .. " " .. awesome.conffile | + | restart | awesome.restart | + | quit | function() awesome.quit() end | + + And here is the actual code: + #+BEGIN_SRC lua + awesomewm_menu = { + <> + } + #+END_SRC + + Next, let’s create the main menu that will be used on ~S-w~ and at the top + left of the window: + #+NAME: table-main-menu + | Name | Command | Icon | + |---------------+----------------+------------------------| + | awesome | awesomewm_menu | beautiful.awesome_icon | + | open terminal | terminal | nil | + + Here is the actual code: + #+BEGIN_SRC lua + mainmenu = awful.menu({ items = { + <> + }}) + #+END_SRC + + 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: + #+BEGIN_SRC lua + launcher = awful.widget.launcher({ image = beautiful.awesome_icon, + menu = mainmenu }) + #+END_SRC + + Finally, let’s declare the menubar’s terminal for applications that require + it. + #+BEGIN_SRC lua + menubar.utils.terminal = terminal + #+END_SRC + +** Other widgets + :PROPERTIES: + :CUSTOM_ID: h-303c5e0d-6afa-45fe-91aa-e0c43e48040d + :END: + Let’s declare the keyboard map indicator and switcher for the top bar: + #+BEGIN_SRC lua + keyboardlayout = awful.widget.keyboardlayout() + #+END_SRC + + Let’s also create a clock widget: + #+BEGIN_SRC lua + textclock = wibox.widget.textclock() + #+END_SRC + +** Tag list + :PROPERTIES: + :CUSTOM_ID: h-2113b6d4-9160-4d7f-a00e-fcae82c032f1 + :END: + 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: + #+BEGIN_SRC lua :tangle no + local tasklist_buttons = gears.table.join( + -- configuration goes here + ) + #+END_SRC + + ~gears.table.join()~ joins several tables together, as described [[https://awesomewm.org/doc/api/libraries/gears.table.html][here]], 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. + #+NAME: tag-simple-left-click + #+BEGIN_SRC lua :tangle no + awful.button({ }, 1, function(t) t:view_only() end) + #+END_SRC + + 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. + #+NAME: tag-mod-left-click + #+BEGIN_SRC lua :tangle no + awful.button({ modkey }, 1, awful.tag.viewtoggle) + #+END_SRC + + 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. + #+NAME: tag-simple-right-click + #+BEGIN_SRC lua :tangle no + awful.button({ }, 3, function(t) + if client.focus then + client.focus:move_to_tag(t) + end + end) + #+END_SRC + + However, a right click combined with the modkey will add the clicked tag to + the currently focused window, making it visible to both tags. + #+NAME: tag-mod-right-click + #+BEGIN_SRC lua :tangle no + awful.button({ modkey }, 3, function(t) + if client.focus then + client.focus:toggle_tag(t) + end + end) + #+END_SRC + + 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. + #+NAME: tag-simple-scroll-up + #+BEGIN_SRC lua :tangle no + awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end) + #+END_SRC + + Otherwise, if a scroll down is detected, the next tag will be displayed. + #+NAME: tag-simple-scroll-down + #+BEGIN_SRC lua :tangle no + awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end) + #+END_SRC + + So, here’s the actual configuration code for the taglist: + #+BEGIN_SRC lua :comments link + local taglist_buttons = gears.table.join( + <>, + <>, + <>, + <>, + <>, + <> + ) + #+END_SRC + +** Tasks list + :PROPERTIES: + :CUSTOM_ID: h-b27681ce-499f-49da-b6b9-03443d479626 + :END: + 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: + #+BEGIN_SRC lua :tangle no + local tasklist_buttons = gears.table.join( + -- List of clicks + ) + #+END_SRC + + 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. + #+NAME: task-simple-left-click + #+BEGIN_SRC lua :tangle no + awful.button({ }, 1, function (c) + if c == client.focus then + c.minimized = true + else + c:emit_signal( + "request::activate", + "tasklist", + {raise = true} + ) + end + end) + #+END_SRC + + 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. + #+NAME: task-simple-right-click + #+BEGIN_SRC lua :tangle no + awful.button({ }, 3, function() + awful.menu.client_list({ theme = { width = 250 } }) + end) + #+END_SRC + + If a scroll up is detected, then let’s select the previous client in the + tasklist. + #+NAME: task-simple-scroll-up + #+BEGIN_SRC lua :tangle no + awful.button({ }, 4, function () + awful.client.focus.byidx(1) + end) + #+END_SRC + + If a scroll down is detected, then let’s select the next client in the + tasklist. + #+NAME: task-simple-scroll-down + #+BEGIN_SRC lua :tangle no + awful.button({ }, 5, function () + awful.client.focus.byidx(-1) + end) + #+END_SRC + + So, here’s the actual code for the tasklist: + #+BEGIN_SRC lua :comments link + local tasklist_buttons = gears.table.join( + <>, + <>, + <>, + <> + ) + #+END_SRC + +* Theme and display + :PROPERTIES: + :CUSTOM_ID: h-ffa1d827-89a4-4699-b8a4-830d4bdbc5fe + :END: +** Screen update + :PROPERTIES: + :CUSTOM_ID: h-d2d98621-0450-4038-8754-8aae999b1c9d + :END: + 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 [[#h-39816309-d36d-4fb1-9c76-942a85b7407b][function that does exactly + that]]! Let’s connect this function to the geometry change signal: + #+BEGIN_SRC lua :comments link + screen.connect_signal("property::geometry", set_wallpaper) + #+END_SRC + + 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: + #+BEGIN_SRC lua :tangle no + awful.screen.connect_for_each_screen(function(s) + -- Code to be executed goes here + end) + #+END_SRC + + 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: + #+NAME: screen-set-pape + #+BEGIN_SRC lua :tangle no + set_wallpaper() + #+END_SRC + + 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 + [[#h-97ec07e5-68de-4c7e-bdf2-84255c09b552][the layouts list described above]]. + #+NAME: screen-taglist + #+BEGIN_SRC lua :tangle no + awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" }, s, awful.layout.layouts[1]) + #+END_SRC + + Next, let’s create the taglist widget. It will use the ~taglist_buttons~ + [[#h-2113b6d4-9160-4d7f-a00e-fcae82c032f1][declared above]] in order to handle clicks on tags, and due to the filter, all + tags will be displayed in the tagbar ([[https://awesomewm.org/apidoc/widgets/awful.widget.taglist.html#List_filters][more about tag filters]]). + #+NAME: screen-taglist-widget + #+BEGIN_SRC lua :tangle no + s.taglist = awful.widget.taglist { + screen = s, + filter = awful.widget.taglist.filter.all, + buttons = taglist_buttons + } + #+END_SRC + + A tasklist widget will also get created thanks with the ~tasklist_button~ + [[#h-2113b6d4-9160-4d7f-a00e-fcae82c032f1][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. + #+NAME: screen-tasklist-widget + #+BEGIN_SRC lua :tangle no + s.tasklist = awful.widget.tasklist { + screen = s, + filter = awful.widget.tasklist.filter.currenttags, + buttons = tasklist_buttons + } + #+END_SRC + + A promptbox will also be created for the screen: + #+NAME: screen-promptbox + #+BEGIN_SRC lua :tangle no + s.promptbox = awful.widget.prompt() + #+END_SRC + + 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. + #+NAME: screen-layout-indicator + #+BEGIN_SRC lua :tangle no + 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))) + #+END_SRC + + Now it is time to create the widget, a ~wibox~ that will contain our bar. + #+NAME: screen-wibox-widget + #+BEGIN_SRC lua :tangle no + s.wibox = awful.wibar({ position = "top", screen = s }) + #+END_SRC + + 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. + #+NAME: screen-wibox-setup + #+BEGIN_SRC lua :tangle no + 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_SRC + + In the end, our code looks like this: + #+BEGIN_SRC lua :comments link + awful.screen.connect_for_each_screen(function(s) + <> + <> + <> + <> + <> + <> + <> + <> + end) + #+END_SRC + +* Mouse bindings + :PROPERTIES: + :CUSTOM_ID: h-8932afa5-64fe-4549-ac57-ef698dcb7e6c + :END: + 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. + #+BEGIN_SRC lua + root.buttons(gears.table.join( + awful.button({}, 3, function() mainmenu:toggle() end) + )) + #+END_SRC + + 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 floating window after focusing it. + - A right click combined with the modkey will allow the user to resize a + floating window after focusing it. + + #+BEGIN_SRC lua + 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) + ) + #+END_SRC + +* Keybindings + :PROPERTIES: + :CUSTOM_ID: h-c44e17f7-ef46-4ec1-bd26-ff6bbcd02c65 + :END: + 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 + - Function :: whether or not the ~Action~ should be nested in a lambda + function (value is ~yes~ or ~no~) + - 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~) + + #+NAME: gen-sc-glob + #+BEGIN_SRC emacs-lisp :var table=sc-client + (mapconcat (lambda (x) + (format "awful.key({%s},\"%s\",%s,\n\t{description=\"%s\",group=\"%s\"})" + (nth 1 x) (nth 0 x) + (if (string= "yes" (nth 2 x)) + (format "function() %s end" (nth 3 x)) + (nth 3 x)) + (nth 4 x) (nth 5 x))) + (seq-filter (lambda (x) + (not (string= "yes" (nth 6 x)))) + table) + ",\n") + #+END_SRC + + #+NAME: gen-sc-client + #+BEGIN_SRC emacs-lisp :var table=sc-client + (mapconcat (lambda (x) + (format "awful.key({%s},\"%s\",%s,\n\t{description=\"%s\",group=\"%s\"})" + (nth 1 x) (nth 0 x) + (if (string= "yes" (nth 2 x)) + (format "function(c) %s end" (nth 3 x)) + (nth 3 x)) + (nth 4 x) (nth 5 x))) + (seq-filter (lambda (x) + (string= "yes" (nth 6 x))) + table) + ",\n") + #+END_SRC + + #+NAME: sc-tag-num-gen + #+BEGIN_SRC emacs-lisp :var input=sc-tag-num :results drawer + (let (result) + (dotimes (i 10 result) + (let* ((j (+ 1 i))) + (setq result + (cons (mapconcat (lambda (line) + (format "awful.key({%s},\"#%d\",function() %s%d) end,\n\t{description=\"%s%d\",tag=\"%s\"})" + (nth 1 line) (+ j 9) (nth 2 line) j (nth 3 line) j (nth 4 line))) + input + ",\n") + result)))) + (mapconcat (lambda (x) x) + result + ",\n\n")) + #+END_SRC + + 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#keys]]). + + #+BEGIN_SRC lua + globalkeys = gears.table.join( + -- Awesome + <>, + -- App + <>, + -- Client + <>, + -- Layout + <>, + -- Media + <>, + -- Screen + <>, + -- Tags + <>, + <> + ) + root.keys(globalkeys) + + clientkeys = gears.table.join( + -- Client + <> + ) + #+END_SRC + +** Applications + :PROPERTIES: + :CUSTOM_ID: h-58cc4798-5686-41bb-8c1a-f9e15368255a + :END: + #+NAME: sc-app + | Key | Modifiers | Function? | Action | What it does | Group | + |--------+-----------+-----------+-----------------------------------+----------------------+-------| + | d | modkey | yes | awful.spawn("j4-dmenu-desktop") | invoke rofi | app | + | e | modkey | yes | awful.spawn("emacsclient -c") | invoke Emacs | app | + | b | modkey | yes | awful.spawn(os.getenv("BROWSER")) | invoke web browser | app | + | w | modkey | yes | set_random_pape() | set random wallpaper | app | + | Return | modkey | yes | awful.spawn(terminal) | open a terminal | app | + +** Awesome + :PROPERTIES: + :CUSTOM_ID: h-e1dbf76d-7c55-4d7d-9bc6-9d95ea9531b2 + :END: + Here will be declared some shortcuts directly related to Awesome itself. + #+NAME: sc-awesome + | Key | Modifiers | Function? | Action | What it does | Group | Clientkey | + |-----+-----------------+-----------+-----------------------------+--------------------+---------+-----------| + | h | modkey | no | hotkeys_popup.show_help | show help | awesome | no | + | h | modkey, shift | yes | mainmenu:show() | show main menu | awesome | no | + | r | modkey, control | no | awesome.restart | reload awesome | awesome | no | + | q | modkey, shift | no | awesome.quit | quit awesome | awesome | no | + | x | modkey | yes | invoke_lua_execute_prompt() | lua execute prompt | awesome | no | + +** Clients + :PROPERTIES: + :CUSTOM_ID: h-521b02ca-0ad3-44e8-8d5b-1e75401490da + :END: + These shortcuts are related to clients (aka windows) management. + #+NAME: sc-client + | Key | Modifiers | Function? | Action | What it does | Group | Clientkey | + |--------+-----------------+-----------+----------------------------------+------------------------------------+--------+-----------| + | Left | modkey | yes | awful.client.focus.byidx(1) | view previous | client | no | + | Right | modkey | yes | awful.client.focus.byidx(-1) | view next | client | no | + | t | modkey, shift | yes | awful.client.swap.byidx(1) | swap with next client by index | client | no | + | s | modkey, shift | yes | awful.client.swap.byidx(-1) | swap with previous client by index | client | no | + | u | modkey | no | awful.client.urgent.jumpto | jump to urgent client | client | no | + | Tab | modkey | yes | client_go_back() | go back | client | no | + | n | modkey, control | yes | restore_minimized_clients() | restore minimized | client | no | + | f | modkey | yes | toggle_fullscreen_client(c) | toggle fullscreen | client | yes | + | q | modkey | yes | c:kill() | close client | client | yes | + | space | modkey, control | no | awful.client.floating.toggle | toggle floating | client | yes | + | Return | modkey, control | yes | c:swap(awful.client.getmaster()) | move to master | client | yes | + | o | modkey | yes | c:move_to_screen() | move to screen | client | yes | + | v | modkey | yes | c.ontop = not c.ontop | toggle keep on top | client | yes | + | n | modkey | yes | c.minimized = true | minimize | client | yes | + | m | modkey | yes | toggle_maximized(c) | toggle maximized | client | yes | + | m | modkey, control | yes | toggle_vertical_maximized(c) | toggle vertically maximized | client | yes | + | m | modkey, shift | yes | toggle_horizontal_maximized(c) | toggle horizontally maximized | client | yes | + +** Layout manipulation + :PROPERTIES: + :CUSTOM_ID: h-4197bf08-bf4f-4f24-9d9d-333416bec7ef + :END: + #+NAME: sc-layout + | Key | Modifiers | Function? | Action | What it does | Group | + |-------+-----------------+-----------+-------------------------------------+-----------------------------------+--------| + | r | modkey | yes | awful.tag.incmwfact(0.05) | increase master width factor | layout | + | c | modkey | yes | awful.tag.incmwfact(-0.05) | decrease master width factor | layout | + | r | modkey, shift | yes | awful.tag.incnmaster(1, nil, true) | increase number of master clients | layout | + | c | modkey, shift | yes | awful.tag.incnmaster(-1, nil, true) | decrease number of master clients | layout | + | r | modkey, control | yes | awful.tag.incncol(1, nil, true) | increase number of colums | layout | + | c | modkey, control | yes | awful.tag.incncol(-1, nil, true) | decrease number of colums | layout | + | space | modkey | yes | awful.layout.inc(1) | next layout | layout | + | space | modkey, shift | yes | awful.layout.inc(-1) | previous layout | layout | + +** Media + :PROPERTIES: + :CUSTOM_ID: h-78ca2ce5-3d6b-4361-8613-1a7b1695c851 + :END: + #+NAME: sc-media + | Key | Modifiers | Function? | Action | What it does | Group | + |---------------+-----------+-----------+--------------------------------------+---------------------+-------| + | p | modkey | yes | awful.spawn.with_shell("mpc toggle") | toggle mpd playback | media | + | XF86AudioPlay | | yes | awful.spawn.with_shell("mpc toggle") | toggle mpd playback | media | + +** Screen + :PROPERTIES: + :CUSTOM_ID: h-f47d70cd-c9d3-41f1-89d1-e7dcbf593e97 + :END: + #+NAME: sc-screen + | Key | Modifiers | Function? | Action | What it does | Group | + |-----+-----------------+-----------+---------------------------------+-----------------------+--------| + | t | modkey, control | yes | awful.screen.focus_relative(1) | focus next screen | screen | + | s | modkey, control | yes | awful.screen.focus_relative(-1) | focus previous screen | screen | + +** Tags + :PROPERTIES: + :CUSTOM_ID: h-cf656040-b21a-4c11-a6ed-e99ea73c861c + :END: + #+NAME: sc-tag + | Key | Modifiers | Function? | Action | What it does | Group | + |--------+-----------+-----------+---------------------------+--------------+-------| + | Escape | modkey | no | awful.tag.history.restore | go back | tag | + | t | modkey | no | awful.tag.viewprev | view prev | tag | + | s | modkey | no | awful.tag.viewnext | view next | tag | + + 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: + #+NAME: sc-tag-num + | Key | Modifiers | Action | What it does | Group | + |--------+------------------------+---------------------------------+--------------------------------+-------| + | Number | modkey | view_tag_n( | view tag # | tag | + | Number | modkey, control | toggle_tag_n( | toggle tag # | tag | + | Number | modkey, shift | move_focused_to_tag_n( | move focused client to tag # | tag | + | Number | modkey, control, shift | toggle_focused_client_to_tag_n( | Toggle focused client on tag # | tag | + +* Rules + :PROPERTIES: + :CUSTOM_ID: h-972e7966-6adf-41bc-9ab3-e58725b93f7c + :END: + 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: + #+BEGIN_SRC lua :tangle no + awful.rules.rules = { + -- Rules here + } + #+END_SRC + + # Block for exporting rules from below + #+BEGIN_SRC lua :exports none + awful.rules.rules = { + <>, + <>, + <>, + <> + } + #+END_SRC + + For more documentation on rules and their syntax, you can read the [[https://awesomewm.org/doc/api/libraries/awful.rules.html][official + documentation]]. + +** Universal rules + :PROPERTIES: + :CUSTOM_ID: h-7311bbcd-c169-4b70-bf09-d1870afe1aa4 + :END: + The first rule is a universal rule which will match all clients, as you can + see with its syntax below: + #+BEGIN_SRC lua :tangle no + { rule = {}, + properties = { + -- List of properties + } + } + #+END_SRC + + Here is the list of properties with their value to apply to all clients, and + a short explanation as to what they do. + #+NAME: rules-universal-properties-table + | Property | Value | What it does | + |---------------+---------------------------------------------------------+---------------------------------------------------------------------| + | border_width | beautiful.border_width | Set the width of the window’s border | + | border_color | beautiful.border_normal | Set the color of the window’s border | + | focus | awful.client.focus.filter | Set focus on the new window, except filtered out windows | + | raise | true | Set it as raised window | + | keys | clientkeys | Set the client’s shortcuts set in [[#h-521b02ca-0ad3-44e8-8d5b-1e75401490da][Shortcuts/Clients]] | + | buttons | clientbuttons | Set the client’s mouse shortcuts from [[#h-8932afa5-64fe-4549-ac57-ef698dcb7e6c][Mouse bindings]] | + | screen | awful.screen.preferred | Spawn the client on the main screen | + | placement | awful.placement.no_overlap+awful.placement.no_offscreen | Avoid the client to appear off the screen and overlaping another client | + | round_corners | true | Enable rounded corners for client | + + #+NAME: rules-universal-properties + #+BEGIN_SRC emacs-lisp :tangle no :exports none :var properties=rules-universal-properties-table :cache yes + (mapconcat (lambda (x) + (format "%s = %s" + (car x) + (cadr x))) + properties + ",\n") + #+END_SRC + + #+RESULTS[5ddcb42f901ac56237de5ed102800b588f462100]: rules-universal-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 + + This is what my universal rules look like: + #+NAME: rules-universal + #+BEGIN_SRC lua :tangle no + { rule = {}, + properties = { + <> + } + } + #+END_SRC + +** Floating clients + :PROPERTIES: + :CUSTOM_ID: h-9ba9a5a6-d98a-4c9c-8a7d-62e4ab546424 + :END: + 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: + #+NAME: rules-floating-conditions-table + | Property | Matches | Comment | + |----------+--------------+----------------------------------------------------------------| + | instance | pinentry | Matches any Polkit | + | class | Arandr | Visual frontend for Randr | + | class | Sxiv | Simple X Image Viewer | + | class | Tor Browser | Needs a fixed window size to avoid fingerprinting | + | name | Event Tester | xev | + | role | pop-up | Any pop-up window, such as Chromium’s detached Developer Tools | + + #+NAME: rules-floating-conditions + #+BEGIN_SRC emacs-lisp :exports none :tangle no :var conditions=rules-floating-conditions-table :cache yes + (mapconcat (lambda (x) + (format "%s = { \"%s\" }" (car x) (cadr x))) + conditions + ",\n") + #+END_SRC + + #+RESULTS: rules-floating-conditions + : instance = { "pinentry" }, + : class = { "Arandr" }, + : class = { "Sxiv" }, + : class = { "Tor Browser" }, + : name = { "Event Tester" }, + : role = { "pop-up" } + + If any of these conditions is matched, then the client will be set as + floating, as you can see below: + #+NAME: rules-floating + #+BEGIN_SRC lua :tangle no + { rule_any = { + <> + }, properties = { floating = true }} + #+END_SRC + +** Titlebars + :PROPERTIES: + :CUSTOM_ID: h-c6ae6b03-92c0-428d-9b0f-831cec7257d9 + :END: + Any normal or dialog client will get a titlebar. This is enabled like so: + #+NAME: rules-titlebars + #+BEGIN_SRC lua :tangle no + { rule_any = {type = { "normal", "dialog" } + }, properties = { titlebars_enabled = true } + } + #+END_SRC + +** Default tag for clients + :PROPERTIES: + :CUSTOM_ID: h-5d846dc4-bbdc-4270-b0fc-44c9dbdaf35f + :END: + With the use of some rules, it is possible to define which client are + assigned to which tag by default. Here is the list of my defaults: + #+NAME: rules-default-tags-table + | Client Property | Value | Screen | Tag | + |-----------------+---------+--------+-----| + | class | Emacs | 1 | 2 | + | class | firefox | 1 | 3 | + | class | Nemo | 1 | 4 | + | class | Gimp* | 1 | 5 | + | class | discord | 1 | 0 | + + #+NAME: rules-default-tags-generate + #+BEGIN_SRC emacs-lisp :tangle no :exports none :cache yes :var tags=rules-default-tags-table + (mapconcat (lambda (x) + (format "{rule = {%s = \"%s\"}, properties = {screen = %d, tag = \"%d\"} }" + (nth 0 x) (nth 1 x) (nth 2 x) (nth 3 x))) + tags + ",\n") + #+END_SRC + + #+RESULTS[8f3d5fdf3c6a404831cfe65dfc6491762d54c1f8]: rules-default-tags-generate + : {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 = "discord"}, properties = {screen = 1, tag = "0"} } + + This is what these rules look like: + #+NAME: rules-default-tags + #+BEGIN_SRC lua :tangle no + <> + #+END_SRC + +* Signals + :PROPERTIES: + :CUSTOM_ID: h-a7ab2551-7c6f-498f-926c-b6f8c5564d68 + :END: + Signals are a way for Awesome to handle events, such as client creation or + deletion. + +** Client creation + :PROPERTIES: + :CUSTOM_ID: h-9eead015-e1f3-4594-b0fa-d5275a502a87 + :END: + 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. + #+BEGIN_SRC lua + client.connect_signal("manage", function (c) + 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) + #+END_SRC + +** Titlebar creation + :PROPERTIES: + :CUSTOM_ID: h-506d0716-ffba-4b16-9bac-6aede468b642 + :END: + 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 [[#h-972e7966-6adf-41bc-9ab3-e58725b93f7c][rules]]. + For a detailed explanation of the code, see below. + #+BEGIN_SRC lua + client.connect_signal("request::titlebars", function(c) + local buttons = gears.table.join( + <>, + <> + ) + + <> + end) + #+END_SRC + + 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. + #+BEGIN_SRC lua :tangle no + local buttons = gears.table.join( + -- Buttons declared here + ) + #+END_SRC + + 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). + #+NAME: signal-titlebar-button1 + #+BEGIN_SRC lua :tangle no + awful.button({ }, 1, function() + c:emit_signal("request::activate", "titlebar", {raise = true}) + awful.mouse.client.move(c) + end) + #+END_SRC + + A right click on the titlebar will also raise the window, but will instead + allow the user to resize the client. + #+NAME: signal-titlebar-button3 + #+BEGIN_SRC lua :tangle no + awful.button({ }, 3, function() + c:emit_signal("request::activate", "titlebar", {raise = true}) + awful.mouse.client.resize(c) + end) + #+END_SRC + + 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: + #+NAME: signal-titlebar-create + #+BEGIN_SRC lua :tangle no + awful.titlebar(c, {position="left"}) : setup { + <> + } + #+END_SRC + + 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 or bottom elements, the only elements I am interested in are the + top elements. I have (top to bottom): + - A close button + - A maximize button + - A minimize button + - A button for toggling client floating + - And an indication to Awesome these elements should be vertically aligned + #+NAME: signal-titlebar-setup + #+BEGIN_SRC lua :tangle no + { -- Top + awful.titlebar.widget.closebutton(c), + awful.titlebar.widget.maximizedbutton(c), + awful.titlebar.widget.minimizebutton(c), + awful.titlebar.widget.floatingbutton(c), + layout = wibox.layout.fixed.vertical() + }, + layout = wibox.layout.align.vertical, + position = "left" + #+END_SRC + +** Changes of focus + :PROPERTIES: + :CUSTOM_ID: h-b86fa83c-0266-4b7a-a77b-42ad50efbd1f + :END: + 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. + #+BEGIN_SRC lua :tangle no + client.connect_signal("mouse::enter", function(c) + c:emit_signal("request::activate", "mouse_enter", {raise = false}) + end) + #+END_SRC + + 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: + #+BEGIN_SRC lua + 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) + #+end_SRC + +* Autostart + :PROPERTIES: + :CUSTOM_ID: h-62e6ce88-26c9-4aca-9578-aaa06cd69e2e + :END: + 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 the + shell. + #+NAME: autostart-table + | Command | What it is for | + |-----------------------------------------------------+----------------------------------------| + | pkill xfce-polkit; /usr/lib/xfce-polkit/xfce-polkit | Launch or relaunch Polkit | + | pkill picom; compton --experimental-backends | Launch or relaunch Picom | + | xss-lock -- i3lock -fol | Enable lockscreen after a blank screen | + | nm-applet | Launch NetworkManager applet | + | numlockx on | Enable numlock | + | mpc stop | Stop music | + | mpd_discord_richpresence --no-idle --fork | Launch MPD rich presence for Discord | + | sleep 3 && emacsclient -c -e \"(delete-frame)\" | Launch blank EmacsClient | + + #+NAME: autostart + #+BEGIN_SRC emacs-lisp :tangle no :exports none :cache yes :var apps=autostart-table + (mapconcat (lambda (x) + (format "awful.spawn.with_shell(\"%s\")" + (car x))) + apps + "\n") + #+END_SRC + + #+RESULTS[40820b365b792a3979427935b1f36790f6ec253d]: autostart + : awful.spawn.with_shell("pkill xfce-polkit; /usr/lib/xfce-polkit/xfce-polkit") + : awful.spawn.with_shell("pkill picom; compton --experimental-backends") + : awful.spawn.with_shell("xss-lock -- i3lock -fol") + : awful.spawn.with_shell("nm-applet") + : awful.spawn.with_shell("numlockx on") + : awful.spawn.with_shell("mpc stop") + : awful.spawn.with_shell("mpd_discord_richpresence --no-idle --fork") + : awful.spawn.with_shell("sleep 3 && emacsclient -c -e \"(delete-frame)\"") + + Each of the command gets called with the call of ~awful.spawn.with_shell()~, + as you can see below. + #+BEGIN_SRC lua + <> + #+END_SRC