Where to Discuss?

Preface

Goal: Main modules in modularized configuration.

Table of Content


Artefacts

Now consider have a walk, moving some codes to files in main directory.

$ tree main
main
├── error-handling.lua
├── layouts.lua
├── menu.lua
├── rules.lua
├── signals.lua
├── tags.lua
└── user-variables.lua

0 directories, 7 files

Awesome WM: Artefacts in Main

We have already moved error-handling.lua and user-variables.lua in previous article. We will discuss here about the rest five: layouts, tags, menu, rules, and signal.

Calling Script

We are going to call these scripts in rc.lua.

-- Custom Local Library
local main = {
  layouts = require("main.layouts"),
  tags    = require("main.tags"),
  menu    = require("main.menu"),
  rules   = require("main.rules"),
}

Awesome WM: Vim Panes: Main Modules

Do not get intimidated with codes above. These can be explained step by step.


1: Layouts

The layout icon can be seen in top-right statusbar.

Awesome WM: Layout Icon

Module Script

You can add or remove, layout using this script below:

-- Standard awesome library
local awful = require("awful")

local _M = {}

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

function _M.get ()
  -- Table of layouts to cover with awful.layout.inc, order matters.
  local layouts = {
    awful.layout.suit.floating,           -- 1:

    awful.layout.suit.tile,               -- 2:
    awful.layout.suit.tile.left,          -- 3:
    awful.layout.suit.tile.bottom,        -- 4:
    awful.layout.suit.tile.top,           -- 5:

    awful.layout.suit.fair,               -- 6:
    awful.layout.suit.fair.horizontal,    -- 7:

    awful.layout.suit.spiral,             -- 8:
    awful.layout.suit.spiral.dwindle,     -- 9:

    awful.layout.suit.max,                -- 10:
    awful.layout.suit.max.fullscreen,     -- 11:
    awful.layout.suit.magnifier,          -- 12:

    awful.layout.suit.corner.nw           -- 13:
--  awful.layout.suit.corner.ne,
--  awful.layout.suit.corner.sw,
--  awful.layout.suit.corner.se,
  }

  return layouts
end

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

return setmetatable(
  {}, 
  { __call = function(_, ...) return _M.get(...) end }
)

Now we have these available: floating, tile, tile,left, tile.bottom, tile.top, fair, fair.horizontal, spiral, spiral.dwindle, max, max.fullscreen, magnifier, corner.nw. You can also add layout using other third party library.

.

I put number a comment, because I want to give different layout for different tag. what I mean is, this comment is required.

Layout Preview

It is easier to understand the layout using image.

Awesome WM: Layouts

Calling Script

In main configuration:

-- Custom Local Library
local main = {
  layouts = require("main.layouts")
}

-- Layouts
RC.layouts = main.layouts()

2: Tags

Standar Tag

Standard tags are using number.

Awesome WM: Tags Number

-- Standard awesome library
local awful = require("awful")

local _M = {}

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

function _M.get ()
  tags = {}

  awful.screen.connect_for_each_screen(function(s)
    -- Each screen has its own tag table.
    tags[s] = awful.tag(
      { "1", "2", "3", "4", "5", "6", "7", "8", "9" }, s, RC.layouts[1]
    )
  end)
  
  return tags
end

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

return setmetatable(
  {}, 
  { __call = function(_, ...) return _M.get(...) end }
)

.

Remember that RC.layouts[1] is, awful.layout.suit.floating.

Calling Script

In main configuration:

-- Custom Local Library
local main = {
  layouts = require("main.layouts"),
  tags    = require("main.tags")
}

-- Tags
RC.tags = main.tags()

Custom Tag

What about different tag names?

Awesome WM: Tags Takao

Well, you can rewrite the script as below:

function _M.get ()
  local tags = {}

  local tagpairs = {
--  names  = { "term", "net", "edit", "place", 5, 6, 7, 8, 9 },
    names  = {
      "❶ 一 term", "❷ 二 net", "❸ 三 edit",
      "❹ 四 place", "❺ 五 mail",
      " ❻ 六", "❼ 七", " ❽ 八", "❾ 九" },

    layout = {
      RC.layouts[1], RC.layouts[2], RC.layouts[4],
      RC.layouts[5], RC.layouts[6], RC.layouts[12],
      RC.layouts[9], RC.layouts[3], RC.layouts[7]
    }
  }

  awful.screen.connect_for_each_screen(function(s)
    -- Each screen has its own tag table.
    tags[s] = awful.tag(tagpairs.names, s, tagpairs.layout)
  end)
  
  return tags
end

3: Menu

This menu is very helpful for beginner. You can setup manually like what this article explain, or you can use third party to build XDG menu, for works with Awesome WM.

Module Script: Initialization.

This script is a little bit long. It takes some libraries to be loaded, and predefined variables to be set.

-- Standard awesome library
local awful = require("awful")
local hotkeys_popup = require("awful.hotkeys_popup").widget
-- Theme handling library
local beautiful = require("beautiful") -- for awesome.icon

local M = {}  -- menu
local _M = {} -- module

-- reading
-- https://awesomewm.org/apidoc/popups%20and%20bars/awful.menu.html

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

-- This is used later as the default terminal and editor to run.
-- local terminal = "xfce4-terminal"
local terminal = RC.vars.terminal

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

Module Script: Configuration Values

Right below the initialization, lays code that set configuration values.

M.awesome = {
  { "hotkeys", function() 
      hotkeys_popup.show_help(nil, awful.screen.focused()) 
    end },
  { "manual", terminal .. " -e man awesome" },
  { "edit config", editor_cmd .. " " .. awesome.conffile },
  { "Terminal", terminal },
  { "Shutdown/Logout", "oblogout" },
  { "restart", awesome.restart },
  { "quit", function() awesome.quit() end }
}

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

function _M.get()

  -- Main Menu
  local menu_items = {
    { "awesome", M.awesome, beautiful.awesome_subicon },
    { "open terminal", terminal }
  }

  return menu_items
end

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

return setmetatable(
  {}, 
  { __call = function(_, ...) return _M.get(...) end }
)

.

And the result is:

Awesome WM: Menu Simple

Calling Script

In main configuration:

-- Custom Local Library
local main = {
  layouts = require("main.layouts"),
  tags    = require("main.tags"),
  menu    = require("main.menu")
}

-- Menu
RC.mainmenu = awful.menu({ items = main.menu() })
RC.launcher = awful.widget.launcher(
  { image = beautiful.awesome_icon, menu = RC.mainmenu }
)
menubar.utils.terminal = RC.vars.terminal

Custom Menu

Of course we can append menu items. It is easy actually, by adding these setting.

M.favorite = {
  { "caja", "caja" },
  { "thunar", "thunar" },
  { "geany", "geany" },
  { "clementine", "clementine" },
  { "firefox", "firefox", awful.util.getdir("config") .. "/firefox.png" },
  { "chromium", "chromium" },
  { "&firefox", "firefox" },
  { "&thunderbird", "thunderbird" },
  { "libreoffice", "libreoffice" },
  { "transmission", "transmission-gtk" },
  { "gimp", "gimp" },
  { "inkscape", "inkscape" },
  { "screenshooter", "xfce4-screenshooter" }
}

M.network_main = {
  { "wicd-curses", "wicd-curses" },
  { "wicd-gtk", "wicd-gtk" }
}

And add those variables above in main menu.

function _M.get()

  -- Main Menu
  local menu_items = {
    { "awesome", M.awesome, beautiful.awesome_subicon },
    { "open terminal", terminal },
    { "network", M.network_main },
    { "favorite", M.favorite }
  }

  return menu_items
end

And the result is:

Awesome WM: Menu Custom


4: Rules

I mostly just cut and paste the rule. This is long, it has long documentation, and maybe deserve its own article.

-- Standard awesome library
local awful     = require("awful")
-- Theme handling library
local beautiful = require("beautiful")

local _M = {}

-- reading
-- https://awesomewm.org/apidoc/libraries/awful.rules.html

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

function _M.get(clientkeys, clientbuttons)
  local rules = {

    -- All clients will match this rule.
    { rule = { },
      properties = {
        border_width = beautiful.border_width,
        border_color = beautiful.border_normal,
        focus     = awful.client.focus.filter,
        raise     = true,
        keys      = clientkeys,
        buttons   = clientbuttons,
        screen    = awful.screen.preferred,
        placement = awful.placement.no_overlap+awful.placement.no_offscreen
      }
    },

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

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

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

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

  }

  return rules
end

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

return setmetatable(
  {}, 
  { __call = function(_, ...) return _M.get(...) end }
)

.

Calling Script

In main configuration:

-- Custom Local Library
local main = {
  layouts = require("main.layouts"),
  tags    = require("main.tags"),
  menu    = require("main.menu"),
  rules   = require("main.rules"),
}

-- Rules
awful.rules.rules = main.rules(clientkeys, clientbuttons)

You can later change the code to

-- Rules
awful.rules.rules = main.rules(
  binding.clientkeys(),
  binding.clientbuttons()
)

But now, leave it that way. Since we haven’t touch the binding section.


5: Signals

On most my Awesome WM time, I rarely make any customization in this signal section.

-- Standard awesome library
local gears = require("gears")
local awful = require("awful")

-- Widget and layout library
local wibox = require("wibox")

-- Theme handling library
local beautiful = require("beautiful")

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

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

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

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

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

I put titlebar signal in other files.

-- Custom Local Library: Common Functional Decoration
require("deco.titlebar")

You can choose not to have titlebar. People doing ricing, love borderless window.

Calling Script

In main configuration:

-- Signals
require("main.signals")

Since it does not return value, that code above is enough.


What is Next?

Consider continue reading [ Awesome WM - Binding Modules ]. There are, some interesting topic, about refactoringAwesome WM using Lua.

What do you think ?