111
awesome/bootstrap.lua
Normal file
@@ -0,0 +1,111 @@
|
||||
-- Alexander Tsepkov, 2015
|
||||
--
|
||||
-- Collection of utilities for awesome WM to import/use awesome-zen platform better.
|
||||
|
||||
|
||||
local awful = require("awful")
|
||||
local naughty = require("naughty")
|
||||
|
||||
|
||||
-- spawn a system tool/utility once, useful for those pesky system tray icons that keep stacking with themselves,
|
||||
-- also can be used to load anything, including compositor, etc.
|
||||
function spawn_once_name(name, command)
|
||||
os.execute("pgrep " .. name .. " || " .. command .. " &")
|
||||
end
|
||||
function spawn_once(name)
|
||||
spawn_once_name(name, name)
|
||||
end
|
||||
|
||||
-- loads a widget
|
||||
function load_widget(config)
|
||||
require(config.widget)
|
||||
|
||||
-- if user defined a zenstate, assign it to the widget so it can respond accordingly
|
||||
if config.zenstate then
|
||||
widget.zenstate = config.zenstate
|
||||
end
|
||||
|
||||
-- notify that the widget was loaded, if asked by rc.lua
|
||||
if config.notify then
|
||||
naughty.notify({
|
||||
title = "Widget Loaded",
|
||||
text = "Loaded " .. config.widget
|
||||
})
|
||||
end
|
||||
|
||||
return widget
|
||||
end
|
||||
|
||||
-- load utility if not loaded yet, if loaded avoid loading it twice, print message if asked
|
||||
function load_script(name, notify)
|
||||
local success
|
||||
local result
|
||||
|
||||
-- Which file? In rc/ or in lib/?
|
||||
local path = awful.util.getdir("config") ..
|
||||
"/" .. name .. ".lua"
|
||||
|
||||
-- Execute the RC/module file
|
||||
success, result = pcall(function() return dofile(path) end)
|
||||
if not success then
|
||||
naughty.notify({
|
||||
title = "Error Loading Script",
|
||||
text = "When loading `" .. name .. "`, got the following error:\n" .. result,
|
||||
preset = naughty.config.presets.critical
|
||||
})
|
||||
return print("E: error loading script: '" .. name .. "': " .. result)
|
||||
elseif notify then
|
||||
naughty.notify({
|
||||
title = "Script Loaded",
|
||||
text = "Loaded " .. name
|
||||
})
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
-- rounding error is pretty bad in lua
|
||||
local EPSILON = 1e-3
|
||||
-- compare two tables, because out of the box lua sucks
|
||||
function equals(a, b)
|
||||
if a == b then return true end
|
||||
local aType = type(a)
|
||||
local bType = type(b)
|
||||
if aType == 'number' and bType == 'number' and math.abs(a - b) < EPSILON then return true end
|
||||
if aType ~= bType then return false end
|
||||
if aType ~= 'table' then return false end
|
||||
|
||||
local seen = {}
|
||||
for key, val1 in pairs(a) do
|
||||
local val2 = b[key]
|
||||
if val2 == nil or equals(val1, val2) == false then
|
||||
return false
|
||||
end
|
||||
seen[key] = true
|
||||
end
|
||||
|
||||
for key, _ in pairs(b) do
|
||||
if not seen[key] then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-- dump loa table to string
|
||||
function dump(tbl, indent)
|
||||
local output = ''
|
||||
if not indent then indent = 0 end
|
||||
for k, v in pairs(tbl) do
|
||||
formatting = string.rep(" ", indent) .. k .. ": "
|
||||
if type(v) == "table" then
|
||||
output = output .. formatting .. "\n"
|
||||
tprint(v, indent+1)
|
||||
elseif type(v) == 'boolean' then
|
||||
output = output .. formatting .. tostring(v) .. "\n"
|
||||
else
|
||||
output = output .. formatting .. v .. "\n"
|
||||
end
|
||||
end
|
||||
return output
|
||||
end
|
||||
596
awesome/rc.lua
Normal file
@@ -0,0 +1,596 @@
|
||||
-- If LuaRocks is installed, make sure that packages installed through it are
|
||||
-- found (e.g. lgi). If LuaRocks is not installed, do nothing.
|
||||
pcall(require, "luarocks.loader")
|
||||
|
||||
-- Standard awesome library
|
||||
local gears = require("gears")
|
||||
local awful = require("awful")
|
||||
require("awful.autofocus")
|
||||
-- Widget and layout library
|
||||
local wibox = require("wibox")
|
||||
-- Theme handling library
|
||||
local beautiful = require("beautiful")
|
||||
-- Notification library
|
||||
local naughty = require("naughty")
|
||||
local menubar = require("menubar")
|
||||
local hotkeys_popup = require("awful.hotkeys_popup")
|
||||
-- Enable hotkeys help widget for VIM and other apps
|
||||
-- when client with a matching name is opened:
|
||||
require("awful.hotkeys_popup.keys")
|
||||
|
||||
-- Load Debian menu entries
|
||||
local debian = require("debian.menu")
|
||||
local has_fdo, freedesktop = pcall(require, "freedesktop")
|
||||
|
||||
-- {{{ Error handling
|
||||
-- Check if awesome encountered an error during startup and fell back to
|
||||
-- another config (This code will only ever execute for the fallback config)
|
||||
if awesome.startup_errors then
|
||||
naughty.notify({ preset = naughty.config.presets.critical,
|
||||
title = "Oops, there were errors during startup!",
|
||||
text = awesome.startup_errors })
|
||||
end
|
||||
|
||||
-- Handle runtime errors after startup
|
||||
do
|
||||
local in_error = false
|
||||
awesome.connect_signal("debug::error", function (err)
|
||||
-- Make sure we don't go into an endless error loop
|
||||
if in_error then return end
|
||||
in_error = true
|
||||
|
||||
naughty.notify({ preset = naughty.config.presets.critical,
|
||||
title = "Oops, an error happened!",
|
||||
text = tostring(err) })
|
||||
in_error = false
|
||||
end)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Variable definitions
|
||||
-- Themes define colours, icons, font and wallpapers.
|
||||
beautiful.init("~/.config/awesome/theme.lua")
|
||||
|
||||
-- This is used later as the default terminal and editor to run.
|
||||
terminal = "x-terminal-emulator"
|
||||
editor = "vim"
|
||||
editor_cmd = terminal .. " -e " .. editor
|
||||
|
||||
-- Default modkey.
|
||||
-- Usually, Mod4 is the key with a logo between Control and Alt.
|
||||
-- If you do not like this or do not have such a key,
|
||||
-- I suggest you to remap Mod4 to another key using xmodmap or other tools.
|
||||
-- However, you can use another modifier like Mod1, but it may interact with others.
|
||||
modkey = "Mod4"
|
||||
|
||||
-- Table of layouts to cover with awful.layout.inc, order matters.
|
||||
awful.layout.layouts = {
|
||||
awful.layout.suit.floating,
|
||||
awful.layout.suit.tile,
|
||||
awful.layout.suit.tile.left,
|
||||
awful.layout.suit.tile.bottom,
|
||||
awful.layout.suit.tile.top,
|
||||
awful.layout.suit.fair,
|
||||
awful.layout.suit.fair.horizontal,
|
||||
awful.layout.suit.spiral,
|
||||
awful.layout.suit.spiral.dwindle,
|
||||
awful.layout.suit.max,
|
||||
awful.layout.suit.max.fullscreen,
|
||||
awful.layout.suit.magnifier,
|
||||
awful.layout.suit.corner.nw,
|
||||
-- awful.layout.suit.corner.ne,
|
||||
-- awful.layout.suit.corner.sw,
|
||||
-- awful.layout.suit.corner.se,
|
||||
}
|
||||
-- }}}
|
||||
|
||||
-- {{{ Menu
|
||||
-- Create a launcher widget and a main menu
|
||||
myawesomemenu = {
|
||||
{ "hotkeys", function() hotkeys_popup.show_help(nil, awful.screen.focused()) end },
|
||||
{ "manual", terminal .. " -e man awesome" },
|
||||
{ "edit config", editor_cmd .. " " .. awesome.conffile },
|
||||
{ "restart", awesome.restart },
|
||||
{ "quit", function() awesome.quit() end },
|
||||
}
|
||||
|
||||
local menu_awesome = { "awesome", myawesomemenu, beautiful.awesome_icon }
|
||||
local menu_terminal = { "open terminal", terminal }
|
||||
|
||||
if has_fdo then
|
||||
mymainmenu = freedesktop.menu.build({
|
||||
before = { menu_awesome },
|
||||
after = { menu_terminal }
|
||||
})
|
||||
else
|
||||
mymainmenu = awful.menu({
|
||||
items = {
|
||||
menu_awesome,
|
||||
{ "Debian", debian.menu.Debian_menu.Debian },
|
||||
menu_terminal,
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
|
||||
menu = mymainmenu })
|
||||
|
||||
-- Menubar configuration
|
||||
menubar.utils.terminal = terminal -- Set the terminal for applications that require it
|
||||
-- }}}
|
||||
|
||||
-- Keyboard map indicator and switcher
|
||||
mykeyboardlayout = awful.widget.keyboardlayout()
|
||||
|
||||
-- {{{ Wibar
|
||||
-- Create a textclock widget
|
||||
mytextclock = wibox.widget.textclock()
|
||||
|
||||
-- Create a wibox for each screen and add it
|
||||
local taglist_buttons = gears.table.join(
|
||||
awful.button({ }, 1, function(t) t:view_only() end),
|
||||
awful.button({ modkey }, 1, function(t)
|
||||
if client.focus then
|
||||
client.focus:move_to_tag(t)
|
||||
end
|
||||
end),
|
||||
awful.button({ }, 3, awful.tag.viewtoggle),
|
||||
awful.button({ modkey }, 3, function(t)
|
||||
if client.focus then
|
||||
client.focus:toggle_tag(t)
|
||||
end
|
||||
end),
|
||||
awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
|
||||
awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
|
||||
)
|
||||
|
||||
local tasklist_buttons = gears.table.join(
|
||||
awful.button({ }, 1, function (c)
|
||||
if c == client.focus then
|
||||
c.minimized = true
|
||||
else
|
||||
c:emit_signal(
|
||||
"request::activate",
|
||||
"tasklist",
|
||||
{raise = true}
|
||||
)
|
||||
end
|
||||
end),
|
||||
awful.button({ }, 3, function()
|
||||
awful.menu.client_list({ theme = { width = 250 } })
|
||||
end),
|
||||
awful.button({ }, 4, function ()
|
||||
awful.client.focus.byidx(1)
|
||||
end),
|
||||
awful.button({ }, 5, function ()
|
||||
awful.client.focus.byidx(-1)
|
||||
end))
|
||||
|
||||
local function set_wallpaper(s)
|
||||
-- Wallpaper
|
||||
if beautiful.wallpaper then
|
||||
local wallpaper = beautiful.wallpaper
|
||||
-- If wallpaper is a function, call it with the screen
|
||||
if type(wallpaper) == "function" then
|
||||
wallpaper = wallpaper(s)
|
||||
end
|
||||
gears.wallpaper.maximized(wallpaper, s, true)
|
||||
end
|
||||
end
|
||||
|
||||
-- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
|
||||
screen.connect_signal("property::geometry", set_wallpaper)
|
||||
|
||||
awful.screen.connect_for_each_screen(function(s)
|
||||
-- Wallpaper
|
||||
set_wallpaper(s)
|
||||
|
||||
-- Each screen has its own tag table.
|
||||
awful.tag({ "code", "web", "cli", "Files", "Zeugs" }, s, awful.layout.layouts[1])
|
||||
|
||||
|
||||
-- Create a promptbox for each screen
|
||||
s.mypromptbox = awful.widget.prompt()
|
||||
-- Create an imagebox widget which will contain an icon indicating which layout we're using.
|
||||
-- We need one layoutbox per screen.
|
||||
s.mylayoutbox = awful.widget.layoutbox(s)
|
||||
s.mylayoutbox:buttons(gears.table.join(
|
||||
awful.button({ }, 1, function () awful.layout.inc( 1) end),
|
||||
awful.button({ }, 3, function () awful.layout.inc(-1) end),
|
||||
awful.button({ }, 4, function () awful.layout.inc( 1) end),
|
||||
awful.button({ }, 5, function () awful.layout.inc(-1) end)))
|
||||
-- Create a taglist widget
|
||||
s.mytaglist = awful.widget.taglist {
|
||||
screen = s,
|
||||
filter = awful.widget.taglist.filter.all,
|
||||
buttons = taglist_buttons
|
||||
}
|
||||
|
||||
-- Create a tasklist widget
|
||||
s.mytasklist = awful.widget.tasklist {
|
||||
screen = s,
|
||||
filter = awful.widget.tasklist.filter.currenttags,
|
||||
buttons = tasklist_buttons
|
||||
}
|
||||
|
||||
-- Create the wibox
|
||||
s.mywibox = awful.wibar({ position = "top", screen = s })
|
||||
|
||||
-- Add widgets to the wibox
|
||||
s.mywibox:setup {
|
||||
layout = wibox.layout.align.horizontal,
|
||||
{ -- Left widgets
|
||||
layout = wibox.layout.fixed.horizontal,
|
||||
mylauncher,
|
||||
s.mytaglist,
|
||||
s.mypromptbox,
|
||||
},
|
||||
s.mytasklist, -- Middle widget
|
||||
{ -- Right widgets
|
||||
layout = wibox.layout.fixed.horizontal,
|
||||
mykeyboardlayout,
|
||||
wibox.widget.systray(),
|
||||
mytextclock,
|
||||
s.mylayoutbox,
|
||||
},
|
||||
}
|
||||
end)
|
||||
-- }}}
|
||||
-- {{{ Mouse bindings
|
||||
root.buttons(gears.table.join(
|
||||
awful.button({ }, 3, function () mymainmenu:toggle() end),
|
||||
awful.button({ }, 4, awful.tag.viewnext),
|
||||
awful.button({ }, 5, awful.tag.viewprev)
|
||||
))
|
||||
-- }}}
|
||||
|
||||
-- {{{ Key bindings
|
||||
globalkeys = gears.table.join(
|
||||
awful.key({ modkey, }, "s", hotkeys_popup.show_help,
|
||||
{description="show help", group="awesome"}),
|
||||
awful.key({ modkey, }, "Left", awful.tag.viewprev,
|
||||
{description = "view previous", group = "tag"}),
|
||||
awful.key({ modkey, }, "Right", awful.tag.viewnext,
|
||||
{description = "view next", group = "tag"}),
|
||||
awful.key({ modkey, }, "Escape", awful.tag.history.restore,
|
||||
{description = "go back", group = "tag"}),
|
||||
|
||||
awful.key({ modkey, }, "j",
|
||||
function ()
|
||||
awful.client.focus.byidx( 1)
|
||||
end,
|
||||
{description = "focus next by index", group = "client"}
|
||||
),
|
||||
awful.key({ modkey, }, "k",
|
||||
function ()
|
||||
awful.client.focus.byidx(-1)
|
||||
end,
|
||||
{description = "focus previous by index", group = "client"}
|
||||
),
|
||||
awful.key({ modkey, }, "w", function () mymainmenu:show() end,
|
||||
{description = "show main menu", group = "awesome"}),
|
||||
|
||||
-- Layout manipulation
|
||||
awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( 1) end,
|
||||
{description = "swap with next client by index", group = "client"}),
|
||||
awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( -1) end,
|
||||
{description = "swap with previous client by index", group = "client"}),
|
||||
awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative( 1) end,
|
||||
{description = "focus the next screen", group = "screen"}),
|
||||
awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end,
|
||||
{description = "focus the previous screen", group = "screen"}),
|
||||
awful.key({ modkey, }, "u", awful.client.urgent.jumpto,
|
||||
{description = "jump to urgent client", group = "client"}),
|
||||
awful.key({ modkey, }, "Tab",
|
||||
function ()
|
||||
awful.client.focus.history.previous()
|
||||
if client.focus then
|
||||
client.focus:raise()
|
||||
end
|
||||
end,
|
||||
{description = "go back", group = "client"}),
|
||||
|
||||
-- Standard program
|
||||
awful.key({ modkey, }, "Return", function () awful.spawn(terminal) end,
|
||||
{description = "open a terminal", group = "launcher"}),
|
||||
awful.key({ modkey, "Control" }, "r", awesome.restart,
|
||||
{description = "reload awesome", group = "awesome"}),
|
||||
awful.key({ modkey, "Shift" }, "q", awesome.quit,
|
||||
{description = "quit awesome", group = "awesome"}),
|
||||
|
||||
awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end,
|
||||
{description = "increase master width factor", group = "layout"}),
|
||||
awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end,
|
||||
{description = "decrease master width factor", group = "layout"}),
|
||||
awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1, nil, true) end,
|
||||
{description = "increase the number of master clients", group = "layout"}),
|
||||
awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1, nil, true) end,
|
||||
{description = "decrease the number of master clients", group = "layout"}),
|
||||
awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1, nil, true) end,
|
||||
{description = "increase the number of columns", group = "layout"}),
|
||||
awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1, nil, true) end,
|
||||
{description = "decrease the number of columns", group = "layout"}),
|
||||
awful.key({ modkey, }, "space", function () awful.layout.inc( 1) end,
|
||||
{description = "select next", group = "layout"}),
|
||||
awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(-1) end,
|
||||
{description = "select previous", group = "layout"}),
|
||||
|
||||
awful.key({ modkey, "Control" }, "n",
|
||||
function ()
|
||||
local c = awful.client.restore()
|
||||
-- Focus restored client
|
||||
if c then
|
||||
c:emit_signal(
|
||||
"request::activate", "key.unminimize", {raise = true}
|
||||
)
|
||||
end
|
||||
end,
|
||||
{description = "restore minimized", group = "client"}),
|
||||
|
||||
-- Prompt
|
||||
awful.key({ modkey }, "r", function () awful.screen.focused().mypromptbox:run() end,
|
||||
{description = "run prompt", group = "launcher"}),
|
||||
|
||||
awful.key({ modkey }, "x",
|
||||
function ()
|
||||
awful.prompt.run {
|
||||
prompt = "Run Lua code: ",
|
||||
textbox = awful.screen.focused().mypromptbox.widget,
|
||||
exe_callback = awful.util.eval,
|
||||
history_path = awful.util.get_cache_dir() .. "/history_eval"
|
||||
}
|
||||
end,
|
||||
{description = "lua execute prompt", group = "awesome"}),
|
||||
-- Menubar
|
||||
awful.key({ modkey }, "p", function() menubar.show() end,
|
||||
{description = "show the menubar", group = "launcher"})
|
||||
)
|
||||
|
||||
clientkeys = gears.table.join(
|
||||
awful.key({ modkey, }, "f",
|
||||
function (c)
|
||||
c.fullscreen = not c.fullscreen
|
||||
c:raise()
|
||||
end,
|
||||
{description = "toggle fullscreen", group = "client"}),
|
||||
awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end,
|
||||
{description = "close", group = "client"}),
|
||||
awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ,
|
||||
{description = "toggle floating", group = "client"}),
|
||||
awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
|
||||
{description = "move to master", group = "client"}),
|
||||
awful.key({ modkey, }, "o", function (c) c:move_to_screen() end,
|
||||
{description = "move to screen", group = "client"}),
|
||||
awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end,
|
||||
{description = "toggle keep on top", group = "client"}),
|
||||
awful.key({ modkey, }, "n",
|
||||
function (c)
|
||||
-- The client currently has the input focus, so it cannot be
|
||||
-- minimized, since minimized clients can't have the focus.
|
||||
c.minimized = true
|
||||
end ,
|
||||
{description = "minimize", group = "client"}),
|
||||
awful.key({ modkey, }, "m",
|
||||
function (c)
|
||||
c.maximized = not c.maximized
|
||||
c:raise()
|
||||
end ,
|
||||
{description = "(un)maximize", group = "client"}),
|
||||
awful.key({ modkey, "Control" }, "m",
|
||||
function (c)
|
||||
c.maximized_vertical = not c.maximized_vertical
|
||||
c:raise()
|
||||
end ,
|
||||
{description = "(un)maximize vertically", group = "client"}),
|
||||
awful.key({ modkey, "Shift" }, "m",
|
||||
function (c)
|
||||
c.maximized_horizontal = not c.maximized_horizontal
|
||||
c:raise()
|
||||
end ,
|
||||
{description = "(un)maximize horizontally", group = "client"})
|
||||
)
|
||||
|
||||
-- Bind all key numbers to tags.
|
||||
-- Be careful: we use keycodes to make it work on any keyboard layout.
|
||||
-- This should map on the top row of your keyboard, usually 1 to 9.
|
||||
for i = 1, 9 do
|
||||
globalkeys = gears.table.join(globalkeys,
|
||||
-- View tag only.
|
||||
awful.key({ modkey }, "#" .. i + 9,
|
||||
function ()
|
||||
local screen = awful.screen.focused()
|
||||
local tag = screen.tags[i]
|
||||
if tag then
|
||||
tag:view_only()
|
||||
end
|
||||
end,
|
||||
{description = "view tag #"..i, group = "tag"}),
|
||||
-- Toggle tag display.
|
||||
awful.key({ modkey, "Control" }, "#" .. i + 9,
|
||||
function ()
|
||||
local screen = awful.screen.focused()
|
||||
local tag = screen.tags[i]
|
||||
if tag then
|
||||
awful.tag.viewtoggle(tag)
|
||||
end
|
||||
end,
|
||||
{description = "toggle tag #" .. i, group = "tag"}),
|
||||
-- Move client to tag.
|
||||
awful.key({ modkey, "Shift" }, "#" .. i + 9,
|
||||
function ()
|
||||
if client.focus then
|
||||
local tag = client.focus.screen.tags[i]
|
||||
if tag then
|
||||
client.focus:move_to_tag(tag)
|
||||
end
|
||||
end
|
||||
end,
|
||||
{description = "move focused client to tag #"..i, group = "tag"}),
|
||||
-- Toggle tag on focused client.
|
||||
awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
|
||||
function ()
|
||||
if client.focus then
|
||||
local tag = client.focus.screen.tags[i]
|
||||
if tag then
|
||||
client.focus:toggle_tag(tag)
|
||||
end
|
||||
end
|
||||
end,
|
||||
{description = "toggle focused client on tag #" .. i, group = "tag"})
|
||||
)
|
||||
end
|
||||
|
||||
clientbuttons = gears.table.join(
|
||||
awful.button({ }, 1, function (c)
|
||||
c:emit_signal("request::activate", "mouse_click", {raise = true})
|
||||
end),
|
||||
awful.button({ modkey }, 1, function (c)
|
||||
c:emit_signal("request::activate", "mouse_click", {raise = true})
|
||||
awful.mouse.client.move(c)
|
||||
end),
|
||||
awful.button({ modkey }, 3, function (c)
|
||||
c:emit_signal("request::activate", "mouse_click", {raise = true})
|
||||
awful.mouse.client.resize(c)
|
||||
end)
|
||||
)
|
||||
|
||||
-- Set keys
|
||||
root.keys(globalkeys)
|
||||
-- }}}
|
||||
|
||||
-- {{{ Rules
|
||||
-- Rules to apply to new clients (through the "manage" signal).
|
||||
awful.rules.rules = {
|
||||
-- All clients will match this rule.
|
||||
{ rule = { },
|
||||
properties = { border_width = beautiful.border_width,
|
||||
border_color = beautiful.border_normal,
|
||||
focus = awful.client.focus.filter,
|
||||
raise = true,
|
||||
keys = clientkeys,
|
||||
buttons = clientbuttons,
|
||||
screen = awful.screen.preferred,
|
||||
placement = awful.placement.no_overlap+awful.placement.no_offscreen
|
||||
}
|
||||
},
|
||||
|
||||
{ rule = { class = "Atom" },
|
||||
properties = { tag = 'code', screen=1 } },
|
||||
{ rule = { class = "Firefox" },
|
||||
properties = { tag = 'web', screen=2 } },
|
||||
{ rule = { instance = "x-terminal-emulator" },
|
||||
properties = { tag = 'cli', floating=true, screen=2 } },
|
||||
|
||||
|
||||
-- Floating clients.
|
||||
{ rule_any = {
|
||||
instance = {
|
||||
"DTA", -- Firefox addon DownThemAll.
|
||||
"copyq", -- Includes session name in class.
|
||||
"pinentry",
|
||||
},
|
||||
class = {
|
||||
"Arandr",
|
||||
"Blueman-manager",
|
||||
"Gpick",
|
||||
"Kruler",
|
||||
"MessageWin", -- kalarm.
|
||||
"Sxiv",
|
||||
"Tor Browser", -- Needs a fixed window size to avoid fingerprinting by screen size.
|
||||
"Wpa_gui",
|
||||
"veromix",
|
||||
"xtightvncviewer"},
|
||||
|
||||
-- Note that the name property shown in xprop might be set slightly after creation of the client
|
||||
-- and the name shown there might not match defined rules here.
|
||||
name = {
|
||||
"Event Tester", -- xev.
|
||||
},
|
||||
role = {
|
||||
"AlarmWindow", -- Thunderbird's calendar.
|
||||
"ConfigManager", -- Thunderbird's about:config.
|
||||
"pop-up", -- e.g. Google Chrome's (detached) Developer Tools.
|
||||
}
|
||||
}, properties = { floating = true }},
|
||||
|
||||
-- Add titlebars to normal clients and dialogs
|
||||
{ rule_any = {type = { "normal", "dialog" }
|
||||
}, properties = { titlebars_enabled = true }
|
||||
},
|
||||
|
||||
-- Set Firefox to always map on the tag named "2" on screen 1.
|
||||
-- { rule = { class = "Firefox" },
|
||||
-- properties = { screen = 1, tag = "2" } },
|
||||
}
|
||||
-- }}}
|
||||
|
||||
-- {{{ Signals
|
||||
-- Signal function to execute when a new client appears.
|
||||
client.connect_signal("manage", function (c)
|
||||
-- Set the windows at the slave,
|
||||
-- i.e. put it at the end of others instead of setting it master.
|
||||
-- if not awesome.startup then awful.client.setslave(c) end
|
||||
|
||||
if awesome.startup
|
||||
and not c.size_hints.user_position
|
||||
and not c.size_hints.program_position then
|
||||
-- Prevent clients from being unreachable after screen count changes.
|
||||
awful.placement.no_offscreen(c)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Add a titlebar if titlebars_enabled is set to true in the rules.
|
||||
client.connect_signal("request::titlebars", function(c)
|
||||
-- buttons for the titlebar
|
||||
local buttons = gears.table.join(
|
||||
awful.button({ }, 1, function()
|
||||
c:emit_signal("request::activate", "titlebar", {raise = true})
|
||||
awful.mouse.client.move(c)
|
||||
end),
|
||||
awful.button({ }, 3, function()
|
||||
c:emit_signal("request::activate", "titlebar", {raise = true})
|
||||
awful.mouse.client.resize(c)
|
||||
end)
|
||||
)
|
||||
|
||||
awful.titlebar(c) : setup {
|
||||
{ -- Left
|
||||
awful.titlebar.widget.iconwidget(c),
|
||||
buttons = buttons,
|
||||
layout = wibox.layout.fixed.horizontal
|
||||
},
|
||||
{ -- Middle
|
||||
{ -- Title
|
||||
align = "center",
|
||||
widget = awful.titlebar.widget.titlewidget(c)
|
||||
},
|
||||
buttons = buttons,
|
||||
layout = wibox.layout.flex.horizontal
|
||||
},
|
||||
{ -- Right
|
||||
awful.titlebar.widget.floatingbutton (c),
|
||||
awful.titlebar.widget.maximizedbutton(c),
|
||||
awful.titlebar.widget.stickybutton (c),
|
||||
awful.titlebar.widget.ontopbutton (c),
|
||||
awful.titlebar.widget.closebutton (c),
|
||||
layout = wibox.layout.fixed.horizontal()
|
||||
},
|
||||
layout = wibox.layout.align.horizontal
|
||||
}
|
||||
end)
|
||||
|
||||
-- Enable sloppy focus, so that focus follows mouse.
|
||||
client.connect_signal("mouse::enter", function(c)
|
||||
c:emit_signal("request::activate", "mouse_enter", {raise = false})
|
||||
end)
|
||||
|
||||
client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
|
||||
client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
|
||||
|
||||
dofile(os.getenv("HOME") .. "/.config/awesome/bootstrap.lua")
|
||||
spawn_once_name("numlockx", "numlockx on")
|
||||
spawn_once("compton")
|
||||
spawn_once("volumeicon")
|
||||
|
||||
-- }}}
|
||||
137
awesome/theme.lua
Normal file
@@ -0,0 +1,137 @@
|
||||
---------------------------
|
||||
-- Default awesome theme --
|
||||
---------------------------
|
||||
|
||||
local theme_assets = require("beautiful.theme_assets")
|
||||
local xresources = require("beautiful.xresources")
|
||||
local dpi = xresources.apply_dpi
|
||||
|
||||
local gfs = require("gears.filesystem")
|
||||
local themes_path = gfs.get_themes_dir()
|
||||
|
||||
local theme = {}
|
||||
|
||||
theme.font = "Ubuntu 8"
|
||||
|
||||
theme.bg_normal = "#222222"
|
||||
theme.bg_focus = "#535d6c"
|
||||
theme.bg_urgent = "#ff0000"
|
||||
theme.bg_minimize = "#444444"
|
||||
theme.bg_systray = theme.bg_normal
|
||||
|
||||
theme.fg_normal = "#aaaaaa"
|
||||
theme.fg_focus = "#ffffff"
|
||||
theme.fg_urgent = "#ffffff"
|
||||
theme.fg_minimize = "#ffffff"
|
||||
|
||||
theme.useless_gap = dpi(0)
|
||||
theme.border_width = dpi(1)
|
||||
theme.border_normal = "#000000"
|
||||
theme.border_focus = "#222222"
|
||||
theme.border_marked = "#91231c"
|
||||
|
||||
-- There are other variable sets
|
||||
-- overriding the default one when
|
||||
-- defined, the sets are:
|
||||
-- taglist_[bg|fg]_[focus|urgent|occupied|empty|volatile]
|
||||
-- tasklist_[bg|fg]_[focus|urgent]
|
||||
-- titlebar_[bg|fg]_[normal|focus]
|
||||
-- tooltip_[font|opacity|fg_color|bg_color|border_width|border_color]
|
||||
-- mouse_finder_[color|timeout|animate_timeout|radius|factor]
|
||||
-- prompt_[fg|bg|fg_cursor|bg_cursor|font]
|
||||
-- hotkeys_[bg|fg|border_width|border_color|shape|opacity|modifiers_fg|label_bg|label_fg|group_margin|font|description_font]
|
||||
-- Example:
|
||||
--theme.taglist_bg_focus = "#ff0000"
|
||||
theme.tasklist_bg_normal = "#000000"
|
||||
theme.tasklist_bg_focus = "#111111"
|
||||
theme.tasklist_fg = "#fcfcfc"
|
||||
theme.titlebar_bg = "#000000"
|
||||
theme.titlebar_fg = "#fcfcfc"
|
||||
|
||||
-- Generate taglist squares:
|
||||
local taglist_square_size = dpi(4)
|
||||
theme.taglist_squares_sel = theme_assets.taglist_squares_sel(
|
||||
taglist_square_size, theme.fg_normal
|
||||
)
|
||||
theme.taglist_squares_unsel = theme_assets.taglist_squares_unsel(
|
||||
taglist_square_size, theme.fg_normal
|
||||
)
|
||||
|
||||
-- Variables set for theming notifications:
|
||||
-- notification_font
|
||||
-- notification_[bg|fg]
|
||||
-- notification_[width|height|margin]
|
||||
-- notification_[border_color|border_width|shape|opacity]
|
||||
|
||||
-- Variables set for theming the menu:
|
||||
-- menu_[bg|fg]_[normal|focus]
|
||||
-- menu_[border_color|border_width]
|
||||
theme.menu_submenu_icon = themes_path.."default/submenu.png"
|
||||
theme.menu_height = dpi(15)
|
||||
theme.menu_width = dpi(100)
|
||||
|
||||
-- You can add as many variables as
|
||||
-- you wish and access them by using
|
||||
-- beautiful.variable in your rc.lua
|
||||
--theme.bg_widget = "#cc0000"
|
||||
|
||||
-- Define the image to load
|
||||
theme.titlebar_close_button_normal = themes_path.."default/titlebar/close_normal.png"
|
||||
theme.titlebar_close_button_focus = themes_path.."default/titlebar/close_focus.png"
|
||||
|
||||
theme.titlebar_minimize_button_normal = themes_path.."default/titlebar/minimize_normal.png"
|
||||
theme.titlebar_minimize_button_focus = themes_path.."default/titlebar/minimize_focus.png"
|
||||
|
||||
theme.titlebar_ontop_button_normal_inactive = themes_path.."default/titlebar/ontop_normal_inactive.png"
|
||||
theme.titlebar_ontop_button_focus_inactive = themes_path.."default/titlebar/ontop_focus_inactive.png"
|
||||
theme.titlebar_ontop_button_normal_active = themes_path.."default/titlebar/ontop_normal_active.png"
|
||||
theme.titlebar_ontop_button_focus_active = themes_path.."default/titlebar/ontop_focus_active.png"
|
||||
|
||||
theme.titlebar_sticky_button_normal_inactive = themes_path.."default/titlebar/sticky_normal_inactive.png"
|
||||
theme.titlebar_sticky_button_focus_inactive = themes_path.."default/titlebar/sticky_focus_inactive.png"
|
||||
theme.titlebar_sticky_button_normal_active = themes_path.."default/titlebar/sticky_normal_active.png"
|
||||
theme.titlebar_sticky_button_focus_active = themes_path.."default/titlebar/sticky_focus_active.png"
|
||||
|
||||
theme.titlebar_floating_button_normal_inactive = themes_path.."default/titlebar/floating_normal_inactive.png"
|
||||
theme.titlebar_floating_button_focus_inactive = themes_path.."default/titlebar/floating_focus_inactive.png"
|
||||
theme.titlebar_floating_button_normal_active = themes_path.."default/titlebar/floating_normal_active.png"
|
||||
theme.titlebar_floating_button_focus_active = themes_path.."default/titlebar/floating_focus_active.png"
|
||||
|
||||
theme.titlebar_maximized_button_normal_inactive = themes_path.."default/titlebar/maximized_normal_inactive.png"
|
||||
theme.titlebar_maximized_button_focus_inactive = themes_path.."default/titlebar/maximized_focus_inactive.png"
|
||||
theme.titlebar_maximized_button_normal_active = themes_path.."default/titlebar/maximized_normal_active.png"
|
||||
theme.titlebar_maximized_button_focus_active = themes_path.."default/titlebar/maximized_focus_active.png"
|
||||
|
||||
theme.wallpaper = "~/Bilder/paintpowder_1.jpg"
|
||||
|
||||
-- You can use your own layout icons like this:
|
||||
theme.layout_fairh = themes_path.."default/layouts/fairhw.png"
|
||||
theme.layout_fairv = themes_path.."default/layouts/fairvw.png"
|
||||
theme.layout_floating = themes_path.."default/layouts/floatingw.png"
|
||||
theme.layout_magnifier = themes_path.."default/layouts/magnifierw.png"
|
||||
theme.layout_max = themes_path.."default/layouts/maxw.png"
|
||||
theme.layout_fullscreen = themes_path.."default/layouts/fullscreenw.png"
|
||||
theme.layout_tilebottom = themes_path.."default/layouts/tilebottomw.png"
|
||||
theme.layout_tileleft = themes_path.."default/layouts/tileleftw.png"
|
||||
theme.layout_tile = themes_path.."default/layouts/tilew.png"
|
||||
theme.layout_tiletop = themes_path.."default/layouts/tiletopw.png"
|
||||
theme.layout_spiral = themes_path.."default/layouts/spiralw.png"
|
||||
theme.layout_dwindle = themes_path.."default/layouts/dwindlew.png"
|
||||
theme.layout_cornernw = themes_path.."default/layouts/cornernww.png"
|
||||
theme.layout_cornerne = themes_path.."default/layouts/cornernew.png"
|
||||
theme.layout_cornersw = themes_path.."default/layouts/cornersww.png"
|
||||
theme.layout_cornerse = themes_path.."default/layouts/cornersew.png"
|
||||
|
||||
-- Generate Awesome icon:
|
||||
theme.awesome_icon = theme_assets.awesome_icon(
|
||||
theme.menu_height, theme.bg_focus, theme.fg_focus
|
||||
)
|
||||
|
||||
-- Define the icon theme for application icons. If not set then the icons
|
||||
-- from /usr/share/icons and /usr/share/icons/hicolor will be used.
|
||||
theme.icon_theme = nil
|
||||
|
||||
|
||||
return theme
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
48
awesome/utils/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
Utils
|
||||
-----
|
||||
This directory contains a list of convenience utilities for awesome WM.
|
||||
|
||||
## remember_positions.lua
|
||||
By default, awesome WM doesn't remember positions of your floating windows when you cycle through different layouts. This can be a problem both to the users who accidentally switched layouts as well as those wishing to temporarily rearrange windows and come back to original layout once they're done with their work. It's also a problem for those reloading their awesome configuration, since it forgets original window positions as well. This script fixes that. To take advantage of it, install it by adding the following line to your `rc.lua`:
|
||||
|
||||
load_script("utils/remember_positions", true)
|
||||
|
||||
|
||||
## ondemand_tile.lua
|
||||
Move floating window into any corner/tile via convenient shortcuts, i.e:
|
||||
|
||||
local positions = require('utils.ondemand_tile')
|
||||
|
||||
-- later in code
|
||||
awful.key({ modkey, "Shift" }, "Down", function (c) position.at('bottom', c) end),
|
||||
awful.key({ modkey, "Shift" }, "Left", function (c) position.at('left', c) end),
|
||||
awful.key({ modkey, "Shift" }, "Right", function (c) position.at('right', c) end),
|
||||
awful.key({ modkey, "Shift" }, "Up", function (c) position.at('top', c) end),
|
||||
|
||||
Positions can be specified as a table `{x, y, w, h}` or as a string to identify one of existing presets:
|
||||
|
||||
left
|
||||
right
|
||||
top
|
||||
bottom
|
||||
top_left
|
||||
top_right
|
||||
bottom_left
|
||||
bottom_right
|
||||
fullscreen
|
||||
center_pad
|
||||
left_third
|
||||
middle_third
|
||||
right_third
|
||||
left_two_thirds
|
||||
right_two_thirds
|
||||
middle_two_thirds
|
||||
|
||||
There is also a compound-resize option in positions module. It stacks previous tiling actions on top of each other in an intuitive manner. For example, when the window is on the `left` half of the screen, sending `down` event will move it to `bottom_left` position. In this way you can iterate through most of the presets in an intuitive manner with just 4 shortcuts:
|
||||
|
||||
awful.key({ modkey, "Shift" }, "Down", function (c) position.compound('bottom', c) end),
|
||||
awful.key({ modkey, "Shift" }, "Left", function (c) position.compound('left', c) end),
|
||||
awful.key({ modkey, "Shift" }, "Right", function (c) position.compound('right', c) end),
|
||||
awful.key({ modkey, "Shift" }, "Up", function (c) position.compound('top', c) end),
|
||||
|
||||
|
||||
259
awesome/utils/ondemand_tile.lua
Normal file
@@ -0,0 +1,259 @@
|
||||
-- Alexander Tsepkov, 2015
|
||||
--
|
||||
-- Logic to compute window positions in order to tile them on the fly, even when in floating layout
|
||||
|
||||
|
||||
local awful = require("awful")
|
||||
|
||||
local position = {}
|
||||
|
||||
local capi =
|
||||
{
|
||||
client = client,
|
||||
mouse = mouse,
|
||||
screen = screen,
|
||||
wibox = wibox,
|
||||
awesome = awesome,
|
||||
}
|
||||
local coords = {
|
||||
left = {
|
||||
x = 0,
|
||||
y = 0,
|
||||
h = 1,
|
||||
w = 1 / 2
|
||||
},
|
||||
right = {
|
||||
x = 1 / 2,
|
||||
y = 0,
|
||||
h = 1,
|
||||
w = 1 / 2
|
||||
},
|
||||
top = {
|
||||
x = 0,
|
||||
y = 0,
|
||||
h = 1 / 2,
|
||||
w = 1,
|
||||
},
|
||||
bottom = {
|
||||
x = 0,
|
||||
y = 1 / 2,
|
||||
h = 1 / 2,
|
||||
w = 1
|
||||
},
|
||||
top_left = {
|
||||
x = 0,
|
||||
y = 0,
|
||||
h = 1 / 2,
|
||||
w = 1 / 2
|
||||
},
|
||||
top_right = {
|
||||
x = 1 / 2,
|
||||
y = 0,
|
||||
h = 1 / 2,
|
||||
w = 1 / 2
|
||||
},
|
||||
bottom_left = {
|
||||
x = 0,
|
||||
y = 1 / 2,
|
||||
h = 1 / 2,
|
||||
w = 1 / 2
|
||||
},
|
||||
bottom_right = {
|
||||
x = 1 / 2,
|
||||
y = 1 / 2,
|
||||
h = 1 / 2,
|
||||
w = 1 / 2
|
||||
},
|
||||
fullscreen = {
|
||||
x = 0,
|
||||
y = 0,
|
||||
h = 1,
|
||||
w = 1
|
||||
},
|
||||
center_pad = {
|
||||
x = 1 / 8,
|
||||
y = 1 / 8,
|
||||
h = (1 / 4) * 3,
|
||||
w = (1 / 4) * 3
|
||||
},
|
||||
left_third = {
|
||||
x = 0,
|
||||
y = 0,
|
||||
h = 1,
|
||||
w = 1 / 3
|
||||
},
|
||||
middle_third = {
|
||||
x = (1 / 3),
|
||||
y = 0,
|
||||
h = 1,
|
||||
w = 1 / 3
|
||||
},
|
||||
left_two_thirds = {
|
||||
x = 0,
|
||||
y = 0,
|
||||
h = 1,
|
||||
w = (1 / 3) * 2
|
||||
},
|
||||
right_third = {
|
||||
x = ((1 / 3) * 2),
|
||||
y = 0,
|
||||
h = 1,
|
||||
w = 1 / 3
|
||||
},
|
||||
right_two_thirds = {
|
||||
x = (1 / 3),
|
||||
y = 0,
|
||||
h = 1,
|
||||
w = (1 / 3) * 2
|
||||
},
|
||||
middle_two_thirds = {
|
||||
x = (1 / 6),
|
||||
y = 0,
|
||||
h = 1,
|
||||
w = (1 / 3) * 2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-- takes geometry, client window, and parent window (uses entire screen as parent window if omitted)
|
||||
-- resizes client window based on geometry in relation to parent window. If geometry is a string, uses
|
||||
-- one of existing geometry presets, if geometry is a table, reads x, y, w, h values from it to determine
|
||||
-- position and size.
|
||||
function position.at(geometry, c, p)
|
||||
if type(geometry) == "string" then
|
||||
geometry = coords[geometry]
|
||||
end
|
||||
local c = c or capi.client.focus
|
||||
local c_geometry = c:geometry()
|
||||
local screen = c.screen or awful.screen.getbycoord(c_geometry.x, c_geometry.y)
|
||||
local s_geometry
|
||||
if p then
|
||||
s_geometry = p:geometry()
|
||||
else
|
||||
-- s_geometry = capi.screen[screen].geometry
|
||||
s_geometry = capi.screen[screen].workarea
|
||||
end
|
||||
return c:geometry({
|
||||
x = s_geometry.x + s_geometry.width * geometry.x,
|
||||
y = s_geometry.y + s_geometry.height * geometry.y,
|
||||
width = s_geometry.width * geometry.w,
|
||||
height = s_geometry.height * geometry.h
|
||||
})
|
||||
end
|
||||
|
||||
-- A smarter version of the above function, computes existing window state to see if it already matches
|
||||
-- a position above, and stacks direction intuitively
|
||||
-- Direction should be a string identifying 1 of 4 directions: left, right, top, bottom
|
||||
function position.compound(direction, c, p)
|
||||
local c = c or capi.client.focus
|
||||
local c_geometry = c:geometry()
|
||||
local screen = c.screen or awful.screen.getbycoord(c_geometry.x, c_geometry.y)
|
||||
local s_geometry
|
||||
if p then
|
||||
s_geometry = p:geometry()
|
||||
else
|
||||
s_geometry = capi.screen[screen].workarea
|
||||
end
|
||||
|
||||
empirical_geometry = {
|
||||
x = (c_geometry.x - s_geometry.x) / s_geometry.width,
|
||||
y = (c_geometry.y - s_geometry.y) / s_geometry.height,
|
||||
h = c_geometry.height / s_geometry.height,
|
||||
w = c_geometry.width / s_geometry.width
|
||||
}
|
||||
|
||||
-- figure out if we're already in one of the preset states
|
||||
local state = nil
|
||||
for key, val in pairs(coords) do
|
||||
if equals(val, empirical_geometry) then
|
||||
state = key
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- local naughty = require('naughty')
|
||||
-- naughty.notify({text=dump(empirical_geometry)})
|
||||
local geometry
|
||||
if state == nil then
|
||||
-- just starting, no stack yet
|
||||
geometry = coords[direction]
|
||||
elseif direction == 'left' then
|
||||
-- stacking left
|
||||
if state == 'left' then
|
||||
geometry = coords['left_third']
|
||||
elseif state == 'top' then
|
||||
geometry = coords['top_left']
|
||||
elseif state == 'bottom' then
|
||||
geometry = coords['bottom_left']
|
||||
elseif state == 'right' then
|
||||
geometry = coords['middle_third']
|
||||
elseif state == 'middle_third' or state == 'center_pad' then
|
||||
geometry = coords['left']
|
||||
elseif state == 'right_third' then
|
||||
geometry = coords['right']
|
||||
elseif state == 'top_right' then
|
||||
geometry = coords['top']
|
||||
elseif state == 'bottom_right' then
|
||||
geometry = coords['bottom']
|
||||
end
|
||||
elseif direction == 'right' then
|
||||
-- stacking right
|
||||
if state == 'right' then
|
||||
geometry = coords['right_third']
|
||||
elseif state == 'top' then
|
||||
geometry = coords['top_right']
|
||||
elseif state == 'bottom' then
|
||||
geometry = coords['bottom_right']
|
||||
elseif state == 'left' then
|
||||
geometry = coords['middle_third']
|
||||
elseif state == 'middle_third' or state == 'center_pad' then
|
||||
geometry = coords['right']
|
||||
elseif state == 'left_third' then
|
||||
geometry = coords['left']
|
||||
elseif state == 'top_left' then
|
||||
geometry = coords['top']
|
||||
elseif state == 'bottom_left' then
|
||||
geometry = coords['bottom']
|
||||
end
|
||||
elseif direction == 'top' then
|
||||
-- stacking up
|
||||
if state == 'left' or state == 'left_third' then
|
||||
geometry = coords['top_left']
|
||||
elseif state == 'bottom' or state == 'middle_third' then
|
||||
geometry = coords['center_pad']
|
||||
elseif state == 'right' or state == 'right_third' then
|
||||
geometry = coords['top_right']
|
||||
elseif state == 'center_pad' then
|
||||
geometry = coords['top']
|
||||
elseif state == 'bottom_left' then
|
||||
geometry = coords['left']
|
||||
elseif state == 'bottom_right' then
|
||||
geometry = coords['right']
|
||||
end
|
||||
elseif direction == 'bottom' then
|
||||
-- stacking down
|
||||
if state == 'left' or state == 'left_third' then
|
||||
geometry = coords['bottom_left']
|
||||
elseif state == 'top' or state == 'middle_third' then
|
||||
geometry = coords['center_pad']
|
||||
elseif state == 'right' or state == 'right_third' then
|
||||
geometry = coords['bottom_right']
|
||||
elseif state == 'center_pad' then
|
||||
geometry = coords['bottom']
|
||||
elseif state == 'top_left' then
|
||||
geometry = coords['left']
|
||||
elseif state == 'top_right' then
|
||||
geometry = coords['right']
|
||||
end
|
||||
end
|
||||
|
||||
if geometry == nil then return c:geometry() end
|
||||
return c:geometry({
|
||||
x = s_geometry.x + s_geometry.width * geometry.x,
|
||||
y = s_geometry.y + s_geometry.height * geometry.y,
|
||||
width = s_geometry.width * geometry.w,
|
||||
height = s_geometry.height * geometry.h
|
||||
})
|
||||
end
|
||||
|
||||
return position
|
||||
33
awesome/utils/remember_positions.lua
Normal file
@@ -0,0 +1,33 @@
|
||||
-- Alexander Tsepkov, 2015
|
||||
--
|
||||
-- By default awesome forgets window positions when you switch between layouts, this is especially a problem
|
||||
-- for floating layout, which awesome wasn't designed to handle gracefully out of the box. This tidbit of code
|
||||
-- fixes that issue by remembering window positions in floating layout and coming back to the same positions when
|
||||
-- you return to floating layout from a tiling one.
|
||||
local awful = require("awful")
|
||||
|
||||
floatgeoms = {}
|
||||
|
||||
tag.connect_signal("property::layout", function(t)
|
||||
for k, c in ipairs(t:clients()) do
|
||||
if ((awful.layout.get(mouse.screen) == awful.layout.suit.floating)
|
||||
or (awful.client.floating.get(c) == true)) then
|
||||
c:geometry(floatgeoms[c.window])
|
||||
end
|
||||
end
|
||||
client.connect_signal("unmanage", function(c) floatgeoms[c.window] = nil end)
|
||||
end)
|
||||
|
||||
client.connect_signal("property::geometry", function(c)
|
||||
if ((awful.layout.get(mouse.screen) == awful.layout.suit.floating) or (awful.client.floating.get(c) == true)) then
|
||||
floatgeoms[c.window] = c:geometry()
|
||||
end
|
||||
end)
|
||||
|
||||
client.connect_signal("unmanage", function(c) floatgeoms[c.window] = nil end)
|
||||
|
||||
client.connect_signal("manage", function(c)
|
||||
if ((awful.layout.get(mouse.screen) == awful.layout.suit.floating) or (awful.client.floating.get(c) == true)) then
|
||||
floatgeoms[c.window] = c:geometry()
|
||||
end
|
||||
end)
|
||||
103
awesome/widgets/README.md
Normal file
@@ -0,0 +1,103 @@
|
||||
Widgets
|
||||
-------
|
||||
This directory contains a list of widget that you can use in your theme.
|
||||
|
||||
## Existing Widgets
|
||||
|
||||
### Temperature
|
||||
A widget that shows current CPU temperature and changes color as the temperature gets higher. It even warns the user when the temperature reaches critical levels.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
In case you don't notice the red icon, the widget will grab your attention via a message:
|
||||

|
||||
|
||||
To use this widget, simply add the following to your `rc.lua`:
|
||||
|
||||
myTempWidget = load_widget({
|
||||
widget = "widgets.temperature.widget"
|
||||
})
|
||||
|
||||
And then add the widget to your wibox (here is an example, although your code may look different):
|
||||
|
||||
right_layout:add(myTempWidget)
|
||||
|
||||
You could also add an optional callback to `load_widget` that determines when to show/hide the temperature widget:
|
||||
|
||||
myTempWidget = load_widget({
|
||||
widget = "widgets.temperature.temp",
|
||||
zenstate = function(t) if t < 60 then return true end return false end,
|
||||
})
|
||||
|
||||
The above example will hide temperature widget when the temperature falls below 60 degrees and show it when it goes above.
|
||||
|
||||
|
||||
### Volume
|
||||
Allow user to control volume via the keyboard volume keys and see feedback. This widget is compatible with pulseaudio and automatically gets volume of the relevant output (i.e. if you've switched to HDMI, you'll be controlling the HDMI volume).
|
||||

|
||||

|
||||

|
||||
|
||||
Install this widget the usual way:
|
||||
|
||||
volume = load_widget({
|
||||
widget = "widgets.volume.widget"
|
||||
})
|
||||
|
||||
Since this widget has no icon, `zenstate` does nothing (I use Maato's volumeicon for icon instead, which works great as an icon but not so well with actual audio controls, which is where this widget excels). To map this widget to your volume keys, add the following in your rc.lua clientkeys section:
|
||||
|
||||
awful.key({ }, "XF86AudioRaiseVolume", volume.up),
|
||||
awful.key({ }, "XF86AudioLowerVolume", volume.down),
|
||||
awful.key({ }, "XF86AudioMute", volume.toggle),
|
||||
|
||||
|
||||
## Memory Usage
|
||||
Display memory usage as a percentage and show more detail, including biggest-offending processes when user hovers over. Like temperature widget, color adjusts automatically based on how much memory you use and informs you when the status reaches critical.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
As with temperature widget, the widget will notify you when the memory usage gets uncomfortably high but before the point of no return:
|
||||
|
||||

|
||||
|
||||
Hover example:
|
||||
|
||||

|
||||
|
||||
To use this widget, simply add the following to your `rc.lua`:
|
||||
|
||||
memoryWidget = load_widget({
|
||||
widget = "widgets.memory.widget"
|
||||
})
|
||||
|
||||
As with temperature widget, this widget accepts a zenstate parameter telling it when to hide, if ever.
|
||||
|
||||
|
||||
## Adding New Widgets
|
||||
Interested in adding your own widget to `Zen` library? Great!
|
||||
|
||||
Make sure your widget follows these `Zen` guidelines, otherwise your pull request may get rejected:
|
||||
|
||||
- Your widget must embrace `Zen` philosophy (it must be as minimalistic as possible, remember that "less is more", don't confuse user with excessive options and prompts, don't take up unnecessary real estate on the screen, try to minimize the number of dependencies your widget brings in)
|
||||
- Your widget must catch all errors that it could generate (It doesn't matter if `awesome` or `bash` is at fault, if as a result of adding your widget user will start seeing occasional red notifications from awesome, your widget will be rejected)
|
||||
- Your widget must not be dominated by an existing `Zen` widget or perform identical functionality (there is no reason to have 50 volume widgets, for example, they just add clutter and confusion, but if you think your widget is superior to an existing widget by all means submit it). I don't want this repository to become another widget graveyard.
|
||||
- Your widget must follow `Zen` architecture, it must conform to the `load_widget` options. That basically means the following:
|
||||
- You must include a handler for user-defined `zenstate` callback, a function that determines when the widget can hide or change state (you can define inputs for the callback and document them in this README, the function will return a boolean identifying true (show) and false (hide) states)
|
||||
- Your widget must be named `widget` by the end of your script, since this is what `load_widget` script assumes as the name and returns to the user
|
||||
- You must include a brief description and screenshot or two of your widget, awesome WM is cluttered with undocumented widgets that users have no way of previewing before installing. Once again, I don't want this repository to become another widget graveyard.
|
||||
|
||||
|
||||
## To Add
|
||||
- CPU Usage
|
||||
- Audio Player
|
||||
- Calendar
|
||||
- Battery
|
||||
- Network
|
||||
- Define/Search Word
|
||||
|
||||
|
||||
BIN
awesome/widgets/memory/1.png
Normal file
|
After Width: | Height: | Size: 510 B |
BIN
awesome/widgets/memory/2.png
Normal file
|
After Width: | Height: | Size: 730 B |
BIN
awesome/widgets/memory/3.png
Normal file
|
After Width: | Height: | Size: 851 B |
BIN
awesome/widgets/memory/hover_example.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
awesome/widgets/memory/max.png
Normal file
|
After Width: | Height: | Size: 925 B |
15
awesome/widgets/memory/mem.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2015 Alexander Tsepkov
|
||||
|
||||
#
|
||||
colorize_title='1s/\(.*\)/<span foreground="#669900"><b>\1<\/b><\/span>/'
|
||||
case "$1" in
|
||||
simple)
|
||||
free | grep Mem | awk '{printf("%.1f\n", $3/$2 * 100)}'
|
||||
;;
|
||||
summary)
|
||||
free -h | sed -e "$colorize_title"
|
||||
echo ''
|
||||
ps -eo pid:6,time:10,pmem:6,rss:8,comm --sort -rss | head -n 20 | sed -e "$colorize_title"
|
||||
;;
|
||||
esac
|
||||
BIN
awesome/widgets/memory/notification_example.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
85
awesome/widgets/memory/widget.lua
Normal file
@@ -0,0 +1,85 @@
|
||||
-- Alexander Tsepkov, 2015
|
||||
--
|
||||
-- Memory Monitor for awesome that changes color as the memory usage goes up
|
||||
-- dependency: FontAwesome
|
||||
|
||||
|
||||
local awful = require("awful")
|
||||
local wibox = require("wibox")
|
||||
local naughty = require("naughty")
|
||||
|
||||
|
||||
local last_id
|
||||
widget = wibox.widget.textbox()
|
||||
function testmem()
|
||||
local fd = io.popen(os.getenv("HOME") .. "/.config/awesome/widgets/memory/mem.sh simple")
|
||||
if fd then
|
||||
-- occasionally awesome craps out for no reason running the operation
|
||||
-- and fd is nil, do nothing in that case (aside from ignoring the value
|
||||
-- rather than throwing an error), it will fix itself next run
|
||||
local memstr = fd:read("*all")
|
||||
local mem = tonumber(memstr)
|
||||
fd:close()
|
||||
local color
|
||||
local font = "<span font='FontAwesome 8' "
|
||||
if mem > 94 then
|
||||
color = font .. "color='#FF0000'>"
|
||||
last_id = naughty.notify({
|
||||
title = "High Memory Usage",
|
||||
text = "Consider closing some processes to prevent miserable experience.",
|
||||
preset = naughty.config.presets.critical,
|
||||
replaces_id = last_id,
|
||||
icon = os.getenv("HOME") .. "/.config/awesome/widgets/memory/" .. "max.png"
|
||||
}).id
|
||||
elseif mem > 85 then
|
||||
color = font .. "color='#FF8000'>"
|
||||
elseif mem > 75 then
|
||||
color = font .. "color='#F5F549'>"
|
||||
else
|
||||
color = font .. "color='#669900'>"
|
||||
end
|
||||
|
||||
if widget.zenstate ~= nil then
|
||||
if widget.zenstate(mem) then
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
return color .. "" .. mem .. " </span>"
|
||||
end
|
||||
return "N/A " -- something failed
|
||||
end
|
||||
|
||||
-- to display on hover event
|
||||
local summary = nil
|
||||
function show_tooltip()
|
||||
local font = 'monospace 8'
|
||||
local text_color = '#FFFFFF'
|
||||
local fd = io.popen(os.getenv("HOME") .. "/.config/awesome/widgets/memory/mem.sh summary")
|
||||
local str = fd:read("*all")
|
||||
local content = string.format('<span font="%s" foreground="%s">%s</span>', font, text_color, str)
|
||||
summary = naughty.notify({
|
||||
-- title = "Memory Usage",
|
||||
text = content,
|
||||
timeout = 0,
|
||||
hover_timeout = 0.5,
|
||||
width = 60*8
|
||||
})
|
||||
end
|
||||
|
||||
function hide_tooltip()
|
||||
if summary ~= nil then
|
||||
naughty.destroy(summary)
|
||||
end
|
||||
end
|
||||
|
||||
widget:set_markup(testmem())
|
||||
widget:connect_signal("mouse::enter", show_tooltip)
|
||||
widget:connect_signal("mouse::leave", hide_tooltip)
|
||||
|
||||
-- update every 30 secs
|
||||
memtimer = timer({ timeout = 30 })
|
||||
memtimer:connect_signal("timeout", function()
|
||||
widget:set_markup(testmem())
|
||||
end)
|
||||
memtimer:start()
|
||||
BIN
awesome/widgets/temperature/1.png
Normal file
|
After Width: | Height: | Size: 654 B |
BIN
awesome/widgets/temperature/2.png
Normal file
|
After Width: | Height: | Size: 639 B |
BIN
awesome/widgets/temperature/3.png
Normal file
|
After Width: | Height: | Size: 675 B |
BIN
awesome/widgets/temperature/4.png
Normal file
|
After Width: | Height: | Size: 602 B |
BIN
awesome/widgets/temperature/hot.png
Normal file
|
After Width: | Height: | Size: 859 B |
BIN
awesome/widgets/temperature/notification_example.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
4
awesome/widgets/temperature/sensors.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2015 Alexander Tsepkov
|
||||
|
||||
sensors | awk '/^Core/ {t=substr($3,2,4);if (t>max) max=t} END {print max}'
|
||||
56
awesome/widgets/temperature/widget.lua
Normal file
@@ -0,0 +1,56 @@
|
||||
-- Alexander Tsepkov, 2015
|
||||
--
|
||||
-- Temperature Monitor for awesome that changes color as the temperature goes up
|
||||
-- dependency: FontAwesome
|
||||
|
||||
|
||||
local wibox = require("wibox")
|
||||
local naughty = require("naughty")
|
||||
|
||||
local last_id
|
||||
widget = wibox.widget.textbox()
|
||||
function testtemps()
|
||||
local fd = io.popen(os.getenv("HOME") .. "/.config/awesome/widgets/temperature/sensors.sh")
|
||||
if fd then
|
||||
-- occasionally awesome craps out for no reason running the operation
|
||||
-- and fd is nil, do nothing in that case (aside from ignoring the value
|
||||
-- rather than throwing an error), it will fix itself next run
|
||||
local tempstr = fd:read("*all")
|
||||
local temp = tonumber(tempstr)
|
||||
fd:close()
|
||||
local color
|
||||
local font = "<span font='FontAwesome 8' "
|
||||
if temp > 90 then
|
||||
color = font .. "color='#FF0000'>"
|
||||
last_id = naughty.notify({
|
||||
title = "Temperature Critical",
|
||||
text = "CPU temperature is dangerously hot, turn it off to prevent damage.",
|
||||
preset = naughty.config.presets.critical,
|
||||
replaces_id = last_id,
|
||||
icon = os.getenv("HOME") .. "/.config/awesome/widgets/temperature/" .. "hot.png"
|
||||
}).id
|
||||
elseif temp > 80 then
|
||||
color = font .. "color='#FF8000'>"
|
||||
elseif temp > 70 then
|
||||
color = font .. "color='#F5F549'>"
|
||||
else
|
||||
color = font .. "color='#669900'>"
|
||||
end
|
||||
|
||||
if widget.zenstate ~= nil then
|
||||
if widget.zenstate(temp) then
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
return color .. "" .. temp .. " </span>"
|
||||
end
|
||||
return "N/A " -- something failed
|
||||
end
|
||||
|
||||
widget:set_markup(testtemps())
|
||||
|
||||
-- update every 30 secs
|
||||
temptimer = timer({ timeout = 30 })
|
||||
temptimer:connect_signal("timeout", function() widget:set_markup(testtemps()) end)
|
||||
temptimer:start()
|
||||
BIN
awesome/widgets/volume/1.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
awesome/widgets/volume/2.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
awesome/widgets/volume/3.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
awesome/widgets/volume/audio-0.png
Normal file
|
After Width: | Height: | Size: 1015 B |
BIN
awesome/widgets/volume/audio-1.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
awesome/widgets/volume/audio-2.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
awesome/widgets/volume/audio-3.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
awesome/widgets/volume/audio-muted.png
Normal file
|
After Width: | Height: | Size: 872 B |
52
awesome/widgets/volume/pa-vol.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2015 Alexander Tsepkov
|
||||
|
||||
|
||||
#SINK_NAME="alsa_output.pci-0000_00_1b.0.analog-stereo"
|
||||
#SINK_NAME="alsa_output.pci-0000_00_1b.0.hdmi-stereo"
|
||||
SOUND_DEVICE=`pacmd dump | grep -P "^set-card-profile" | grep stereo | cut -d: -f2 | cut -d+ -f1`
|
||||
SINK_NAME="alsa_output.pci-0000_00_1b.0.$SOUND_DEVICE"
|
||||
VOL_STEP="0x01000"
|
||||
|
||||
MUTE_STATE=`pacmd dump | grep -P "^set-sink-mute $SINK_NAME\s+" | perl -p -i -e 's/.+\s(yes|no)$/$1/'`
|
||||
VOL_NOW=`pacmd dump | grep -P "^set-sink-volume $SINK_NAME\s+" | perl -p -i -e 's/.+\s(.x.+)$/$1/'`
|
||||
VOL_MAX=$((0x10000))
|
||||
|
||||
case "$1" in
|
||||
plus)
|
||||
if [ $MUTE_STATE = yes ]; then
|
||||
echo "Muted"
|
||||
else
|
||||
VOL_NEW=$((VOL_NOW + VOL_STEP))
|
||||
if [ $VOL_NEW -gt $VOL_MAX ]
|
||||
then
|
||||
VOL_NEW=$VOL_MAX
|
||||
fi
|
||||
pactl set-sink-volume $SINK_NAME `printf "0x%X" $VOL_NEW`
|
||||
echo "$((100*VOL_NEW / VOL_MAX))%"
|
||||
fi
|
||||
|
||||
;;
|
||||
minus)
|
||||
if [ $MUTE_STATE = yes ]; then
|
||||
echo "Muted"
|
||||
else
|
||||
VOL_NEW=$((VOL_NOW - VOL_STEP))
|
||||
if [ $(($VOL_NEW)) -lt $((0x00000)) ]
|
||||
then
|
||||
VOL_NEW=$((0x00000))
|
||||
fi
|
||||
pactl set-sink-volume $SINK_NAME `printf "0x%X" $VOL_NEW`
|
||||
echo "$((100*VOL_NEW / VOL_MAX))%"
|
||||
fi
|
||||
|
||||
;;
|
||||
mute)
|
||||
if [ $MUTE_STATE = no ]; then
|
||||
pactl set-sink-mute $SINK_NAME 1
|
||||
echo "Muted"
|
||||
elif [ $MUTE_STATE = yes ]; then
|
||||
pactl set-sink-mute $SINK_NAME 0
|
||||
echo "$((100*VOL_NOW / VOL_MAX))%"
|
||||
fi
|
||||
esac
|
||||
52
awesome/widgets/volume/widget.lua
Normal file
@@ -0,0 +1,52 @@
|
||||
-- Alexander Tsepkov, 2015
|
||||
--
|
||||
-- Minimalistic Volume Widget that works with multiple output sources
|
||||
-- dependency: FontAwesome
|
||||
|
||||
|
||||
local wibox = require("wibox")
|
||||
local naughty = require("naughty")
|
||||
|
||||
local last_id
|
||||
local vol_muted
|
||||
function mixercommand(command)
|
||||
local fd = io.popen(os.getenv("HOME") .. "/.config/awesome/pa-vol.sh " .. command)
|
||||
local status = fd:read("*all")
|
||||
fd:close()
|
||||
local pic = os.getenv("HOME") .. "/.config/awesome/widgets/volume/"
|
||||
local value
|
||||
if status == "Muted\n" then
|
||||
pic = pic .. "audio-muted.png"
|
||||
else
|
||||
-- dividing by 26 is a little cheat to prevent overflow on 100%
|
||||
value = math.floor(tonumber(string.sub(status:gsub("%s+$", ""), 0, -2)) / 26)
|
||||
pic = pic .. "audio-" .. value .. ".png"
|
||||
end
|
||||
last_id = naughty.notify({
|
||||
title = "Volume",
|
||||
text = status,
|
||||
replaces_id = last_id,
|
||||
icon = pic,
|
||||
}).id
|
||||
end
|
||||
function volumeup()
|
||||
mixercommand("plus")
|
||||
end
|
||||
|
||||
function volumedown()
|
||||
mixercommand("minus")
|
||||
end
|
||||
|
||||
function volumetoggle()
|
||||
mixercommand("mute")
|
||||
end
|
||||
|
||||
-- zenstate not applicable bescause there is no volume icon for this widget at all
|
||||
|
||||
-- this widget doesn't have an icon, I use volumeicon instead but I prefer the messages/control through this
|
||||
-- widget instead
|
||||
widget = {
|
||||
up = volumeup,
|
||||
down = volumedown,
|
||||
toggle = volumetoggle,
|
||||
}
|
||||