由于 i3wm 支持的功能有限,定制性并没有那么强大,最近换成使用 Awesome WM 了,它使用 Lua 作为配置语言,所以可配置性极强。举个例子,i3wm 配置无法像真正的编程语言一样使用 if ... else 语句等,但 Awesome WM 可以,对于同一个快捷键就可以在不同时候有不同的功能。

Awesome WM 对多显示器支持很好,在官网上还有一个便捷切换显示器的脚本。这个脚本写得非常地巧妙,可以绑定到一个快捷键,每次按都能弹出通知,显示即将使用的显示器布局,当切换到想要的布局后停止按键就可以应用这一布局了。这利用的是 Notification 弹窗如果没有被响应时调用回调函数的特性。

demo

Awesome WM 的通知使用的是 naughty 模块,它包装了一系列很有用的功能,在 Awesome WM 的 API 文档中介绍了 naughty.notify用法,如下是传入参数的一些字段:

  • replaces_id: (int) Replace the notification with the given ID. (optional)
  • destroy: (func) Function to run when notification is destroyed. (optional)

replaces_id 可以用于替代上一个 Notification ,这样就有一种轮换的效果了;destroy 是当这个通知消失时的动作,它有一个传入的参数 reason 表示它消失的原因,可以通过这个来过滤非超时消失的情况:

local function naughty_destroy_callback(reason)
  if reason == naughty.notificationClosedReason.expired then
    ...
  end
end

可以照猫画虎,实现一个 exit.lua ,在模块内部实现一个类似迭代的效果,每次调用 exit 函数都会改变模组内部变量的状态:

local spawn = require("awful.spawn")
local naughty = require("naughty")

local icon_path = os.getenv("HOME") .. "/.config/awesome/images/power.png"

local state = { cid = nil }

local lock_command = '$HOME/.local/bin/fancy-lock && sleep 1 && '
local lock = { "Lock", lock_command }
local shutdown = { "Shut down", "shutdown now" }
local reboot = { "Reboot", "systemctl reboot" }
local suspend = { "Suspend", lock_command .. "systemctl suspend" }
local hibernate = { "Hibernate", lock_command .. "systemctl hibernate" }

local function menu()
  return { lock, shutdown, reboot, suspend }
end

local function naughty_destroy_callback(reason)
  if reason == naughty.notificationClosedReason.expired then
    local action = state.index and state.menu[state.index - 1][2]
    if action then
      spawn(string.format("sh -c \'%s\'", action), false)
      state.index = nil
    end
  end
end

local function exit()
  if not state.index then
    state.menu = menu()
    state.index = 1
  end

  local label, action
  local next = state.menu[state.index]
  state.index = state.index + 1

  if not next then
    label = 'Do nothing'
    state.index = nil
  else
    label, action = next[1], next[2]
  end

  state.cid = naughty.notify({
    title = "Awesome WM Exit",
    text = string.format("  <span color='yellow' weight='bold'>%-10s ?</span>", label),
    icon = icon_path,
    timeout = 3,
    screen = mouse.screen,
    replaces_id = state.cid,
    destroy = naughty_destroy_callback
  }).id
end

return {
  exit = exit,
  commands = {
    lock = lock,
    shutdown = shutdown,
    reboot = reboot,
    suspend = suspend,
    hibernate = hibernate
  }
}