From e8bb1f4a1844f07fc2f6973f2e7b400f2ddf2f3d Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 25 Dec 2016 12:03:06 +0100 Subject: Initial commit. --- bindings.lua | 144 +++++++++++++++++++++++++++++ commondefs.lua | 4 + desktop.lua | 22 +++++ pager.lua | 52 +++++++++++ rc.lua | 284 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ utils.lua | 42 +++++++++ 6 files changed, 548 insertions(+) create mode 100644 bindings.lua create mode 100644 commondefs.lua create mode 100644 desktop.lua create mode 100644 pager.lua create mode 100644 rc.lua create mode 100644 utils.lua diff --git a/bindings.lua b/bindings.lua new file mode 100644 index 0000000..87b1a76 --- /dev/null +++ b/bindings.lua @@ -0,0 +1,144 @@ +local awful = require("awful") +local commondefs = require("commondefs") +local utils = require("utils") + +local modkey = commondefs.modkey + +local globalkeys = awful.util.table.join( + awful.key({ modkey, "Mod1" }, "Delete", awesome.restart), + awful.key({ modkey }, "Pause", function () awful.util.spawn("xscreensaver-command -lock") end), + + -- program launching + awful.key({ modkey, }, "t", function () awful.util.spawn(commondefs.terminal) end), + awful.key({ modkey, }, "v", function () awful.util.spawn(commondefs.terminal .. " -e alsamixer") end), + awful.key({ modkey, }, "Escape", function () awful.util.spawn(commondefs.terminal .. " -e htop") end), + + -- audio control + awful.key({ modkey }, "Prior", function () utils.vol_control(1) end), + awful.key({ modkey }, "Next", function () utils.vol_control(-1) end), + awful.key({ modkey }, "grave", function () awful.util.spawn("mpc toggle") end), + awful.key({ modkey }, "b", function () awful.util.spawn("mpc next") end), + awful.key({ modkey }, "p", function () awful.util.spawn("mpc prev") end), + + -- focus/screen switching + awful.key({ modkey, }, "q", function() utils.screen_focus_physical(1) end), + awful.key({ modkey, }, "w", function() utils.screen_focus_physical(2) end), + awful.key({ modkey, }, "e", function() utils.screen_focus_physical(3) end), + + awful.key({ modkey, }, "Left", awful.tag.viewprev ), + awful.key({ modkey, }, "Right", awful.tag.viewnext ), + + awful.key({ modkey, }, "Tab", + function () + awful.client.focus.byidx(1) + if client.focus then client.focus:raise() end + end), + awful.key({ modkey, "Shift" }, "Tab", + function () + awful.client.focus.byidx(-1) + if client.focus then client.focus:raise() end + end), + awful.key({ modkey, "Mod1" }, "Tab", + function () + awful.client.focus.history.previous() + if client.focus then + client.focus:raise() + end + end), + + -- Layout manipulation + awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( 1) end), + awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( -1) end), + awful.key({ modkey, }, "u", awful.client.urgent.jumpto), + + + awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end), + awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end), + awful.key({ modkey, }, ",", function () awful.tag.incnmaster( 1) end), + awful.key({ modkey, }, ".", function () awful.tag.incnmaster(-1) end), + awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1) end), + awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end), + + awful.key({ modkey, "Control" }, "n", awful.client.restore), + + -- Prompt + awful.key({ modkey }, "r", function () mypromptbox[mouse.screen]:run() end), + + awful.key({ modkey }, "x", + function () + awful.prompt.run({ prompt = "Run Lua code: " }, + mypromptbox[mouse.screen].widget, + awful.util.eval, nil, + awful.util.getdir("cache") .. "/history_eval") + end) +) + +-- Bind all key numbers to tags. +-- Be careful: we use keycodes to make it works on any keyboard layout. +-- This should map on the top row of your keyboard, usually 1 to 9. +for i = 1, 9 do + globalkeys = awful.util.table.join(globalkeys, + -- View tag only. + awful.key({ modkey }, "#" .. i + 9, + function () + local screen = mouse.screen + local tag = awful.tag.gettags(screen)[i] + if tag then + awful.tag.viewonly(tag) + end + end), + -- Toggle tag. + awful.key({ modkey, "Control" }, "#" .. i + 9, + function () + local screen = mouse.screen + local tag = awful.tag.gettags(screen)[i] + if tag then + awful.tag.viewtoggle(tag) + end + end), + -- Move client to tag. + awful.key({ modkey, "Shift" }, "#" .. i + 9, + function () + if client.focus then + local tag = awful.tag.gettags(client.focus.screen)[i] + if tag then + awful.client.movetotag(tag) + end + end + end), + -- Toggle tag. + awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9, + function () + if client.focus then + local tag = awful.tag.gettags(client.focus.screen)[i] + if tag then + awful.client.toggletag(tag) + end + end + end)) +end + +local clientkeys = awful.util.table.join( + awful.key({ modkey, }, "f", function (c) c.fullscreen = not c.fullscreen end), + awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end), + awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ), + awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end), + awful.key({ modkey, }, "o", awful.client.movetoscreen ), + awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end), + 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), + awful.key({ modkey, }, "m", + function (c) + c.maximized_horizontal = not c.maximized_horizontal + c.maximized_vertical = not c.maximized_vertical + end) +) + +return { + globalkeys = globalkeys, + clientkeys = clientkeys, +} diff --git a/commondefs.lua b/commondefs.lua new file mode 100644 index 0000000..9ec5c45 --- /dev/null +++ b/commondefs.lua @@ -0,0 +1,4 @@ +return { + terminal = "x-terminal-emulator", + modkey = "Mod4", +} diff --git a/desktop.lua b/desktop.lua new file mode 100644 index 0000000..376410b --- /dev/null +++ b/desktop.lua @@ -0,0 +1,22 @@ +local M = {} + +local awful = require("awful") + +local Desktop = {} + +function Desktop:new(name, nb_pages) + o = setmetatable({}, self) + + o.name = name + + o.pages = {} + for i = 1, nb_pages do + o.pages[i] = awful.tag.add(name .. i) + end + + return o +end + +M.Desktop = Desktop + +return M diff --git a/pager.lua b/pager.lua new file mode 100644 index 0000000..867b09b --- /dev/null +++ b/pager.lua @@ -0,0 +1,52 @@ +local M = {} + +local wibox = require("wibox") + +local Pager = {} + +local function pager_fit(pager, width, height) + return width, width * #pager.desktop.pages +end + +local function pager_draw(pager, wibox, cr, width, height) + if pager.desktop == nil then + return + end + + local nb_pages = #pager.desktop.pages + local page_height = height / nb_pages + + for i = 1, nb_pages do + local page = pager.desktop.pages[i] + local draw_h_start = (i - 1) * page_height + + for j, client in pairs(page:clients()) do + local text = client.name + local extents = cr:text_extents(text) + cr:move_to(0, draw_h_start) + cr:show_text(text) + draw_h_start = draw_h_start + extents.height + end + end + cr:set_line_width(3) + cr:stroke() +end + +local function pager_set_desktop(pager, desktop) + pager.desktop = desktop + pager:emit_signal("widget::updated") +end + +function Pager:new() + local pager = wibox.widget.base.make_widget() + + pager.fit = pager_fit + pager.draw = pager_draw + pager.set_desktop = pager_set_desktop + + return pager +end + +M.Pager = Pager + +return M diff --git a/rc.lua b/rc.lua new file mode 100644 index 0000000..aef7510 --- /dev/null +++ b/rc.lua @@ -0,0 +1,284 @@ +-- Standard awesome library +local gears = require("gears") +local awful = require("awful") +awful.rules = require("awful.rules") +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 bindings = require("bindings") +local commondefs = require("commondefs") +local desktop = require("desktop") +local pager = require("pager") + +-- {{{ 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 = err }) + in_error = false + end) +end +-- }}} + +-- {{{ Variable definitions +-- Themes define colours, icons, font and wallpapers. +beautiful.init("/usr/share/awesome/themes/default/theme.lua") + +-- Table of layouts to cover with awful.layout.inc, order matters. +local layouts = +{ + awful.layout.suit.tile, + awful.layout.suit.tile.bottom, +} +-- }}} + +-- {{{ Tags +-- Define a tag table which hold all screen tags. +tags = {} +for s = 1, screen.count() do + -- Each screen has its own tag table. + tags[s] = awful.tag({ 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s, layouts[1]) +end + +desktops = {} + +desktops[1] = desktop.Desktop:new("main", 10) +-- }}} + +-- Menubar configuration +menubar.utils.terminal = terminal -- Set the terminal for applications that require it +-- }}} + +-- {{{ Wibox +-- Create a textclock widget +mytextclock = awful.widget.textclock() + +-- Create a wibox for each screen and add it +mywibox = {} +mypromptbox = {} +mylayoutbox = {} +mytaglist = {} +mytaglist.buttons = awful.util.table.join( + awful.button({ }, 1, awful.tag.viewonly), + awful.button({ commondefs.modkey }, 1, awful.client.movetotag), + awful.button({ }, 3, awful.tag.viewtoggle), + awful.button({ commondefs.modkey }, 3, awful.client.toggletag), + awful.button({ }, 4, function(t) awful.tag.viewnext(awful.tag.getscreen(t)) end), + awful.button({ }, 5, function(t) awful.tag.viewprev(awful.tag.getscreen(t)) end) + ) +mytasklist = {} +mytasklist.buttons = awful.util.table.join( + awful.button({ }, 1, function (c) + if c == client.focus then + c.minimized = true + else + -- Without this, the following + -- :isvisible() makes no sense + c.minimized = false + if not c:isvisible() then + awful.tag.viewonly(c:tags()[1]) + end + -- This will also un-minimize + -- the client, if needed + client.focus = c + c:raise() + end + end), + awful.button({ }, 3, function () + if instance then + instance:hide() + instance = nil + else + instance = awful.menu.clients({ + theme = { width = 250 } + }) + end + end), + awful.button({ }, 4, function () + awful.client.focus.byidx(1) + if client.focus then client.focus:raise() end + end), + awful.button({ }, 5, function () + awful.client.focus.byidx(-1) + if client.focus then client.focus:raise() end + end)) + +for s = 1, screen.count() do + -- Create a promptbox for each screen + mypromptbox[s] = awful.widget.prompt() + -- Create an imagebox widget which will contains an icon indicating which layout we're using. + -- We need one layoutbox per screen. + mylayoutbox[s] = awful.widget.layoutbox(s) + mylayoutbox[s]:buttons(awful.util.table.join( + awful.button({ }, 1, function () awful.layout.inc(layouts, 1) end), + awful.button({ }, 3, function () awful.layout.inc(layouts, -1) end), + awful.button({ }, 4, function () awful.layout.inc(layouts, 1) end), + awful.button({ }, 5, function () awful.layout.inc(layouts, -1) end))) + + -- Create a taglist widget + mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.filter.all, mytaglist.buttons, nil, nil, wibox.layout.fixed.vertical()) + + -- Create a tasklist widget + --mytasklist[s] = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, mytasklist.buttons, nil, nil, wibox.layout.fixed.vertical()) + pgr = pager.Pager:new(desktops[1]) + pgr:set_desktop(desktops[1]) + mytasklist[s] = pgr + + -- Widgets that are aligned to the left + local left_layout = wibox.layout.fixed.vertical() + left_layout:add(mytaglist[s]) + left_layout:add(mypromptbox[s]) + + -- Widgets that are aligned to the right + local right_layout = wibox.layout.fixed.vertical() + if s == 1 then right_layout:add(wibox.widget.systray()) end + right_layout:add(mytextclock) + right_layout:add(mylayoutbox[s]) + + -- Now bring it all together (with the tasklist in the middle) + local layout = wibox.layout.align.vertical() + layout:set_top(left_layout) + layout:set_middle(mytasklist[s]) + layout:set_bottom(right_layout) + + -- Create the wibox + mywibox[s] = awful.wibox({ position = "right", screen = s, width = 128 }) + mywibox[s]:set_widget(layout) +end +-- }}} + +-- {{{ Mouse bindings +root.buttons(awful.util.table.join( + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) +)) +-- }}} + + +clientbuttons = awful.util.table.join( + awful.button({ }, 1, function (c) client.focus = c; c:raise() end), + awful.button({ commondefs.modkey }, 1, awful.mouse.client.move), + awful.button({ commondefs.modkey }, 3, awful.mouse.client.resize)) + +-- Set keys +root.keys(bindings.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 = 3, + border_color = "#000000", + focus = awful.client.focus.filter, + raise = true, + keys = bindings.clientkeys, + buttons = clientbuttons } }, + { rule = { class = "MPlayer" }, + properties = { floating = true } }, + { rule = { class = "pinentry" }, + properties = { floating = true } }, + { rule = { class = "gimp" }, + properties = { floating = true } }, + -- Set Firefox to always map on tags number 2 of screen 1. + -- { rule = { class = "Firefox" }, + -- properties = { tag = tags[1][2] } }, +} +-- }}} + +-- {{{ Signals +-- Signal function to execute when a new client appears. +client.connect_signal("manage", function (c, startup) + -- Enable sloppy focus + c:connect_signal("mouse::enter", function(c) + if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier + and awful.client.focus.filter(c) then + client.focus = c + end + end) + + if not startup then + -- Set the windows at the slave, + -- i.e. put it at the end of others instead of setting it master. + -- awful.client.setslave(c) + + -- Put windows in a smart way, only if they does not set an initial position. + if not c.size_hints.user_position and not c.size_hints.program_position then + awful.placement.no_overlap(c) + awful.placement.no_offscreen(c) + end + elseif not c.size_hints.user_position and not c.size_hints.program_position then + -- Prevent clients from being unreachable after screen count change + awful.placement.no_offscreen(c) + end + + local titlebars_enabled = false + if titlebars_enabled and (c.type == "normal" or c.type == "dialog") then + -- buttons for the titlebar + local buttons = awful.util.table.join( + awful.button({ }, 1, function() + client.focus = c + c:raise() + awful.mouse.client.move(c) + end), + awful.button({ }, 3, function() + client.focus = c + c:raise() + awful.mouse.client.resize(c) + end) + ) + + -- Widgets that are aligned to the left + local left_layout = wibox.layout.fixed.horizontal() + left_layout:add(awful.titlebar.widget.iconwidget(c)) + left_layout:buttons(buttons) + + -- Widgets that are aligned to the right + local right_layout = wibox.layout.fixed.horizontal() + right_layout:add(awful.titlebar.widget.floatingbutton(c)) + right_layout:add(awful.titlebar.widget.maximizedbutton(c)) + right_layout:add(awful.titlebar.widget.stickybutton(c)) + right_layout:add(awful.titlebar.widget.ontopbutton(c)) + right_layout:add(awful.titlebar.widget.closebutton(c)) + + -- The title goes in the middle + local middle_layout = wibox.layout.flex.horizontal() + local title = awful.titlebar.widget.titlewidget(c) + title:set_align("center") + middle_layout:add(title) + middle_layout:buttons(buttons) + + -- Now bring it all together + local layout = wibox.layout.align.horizontal() + layout:set_left(left_layout) + layout:set_right(right_layout) + layout:set_middle(middle_layout) + + awful.titlebar(c):set_widget(layout) + end +end) + +client.connect_signal("focus", function(c) c.border_color = "#b0e2ff" end) +client.connect_signal("unfocus", function(c) c.border_color = "#000000" end) +-- }}} diff --git a/utils.lua b/utils.lua new file mode 100644 index 0000000..1df9690 --- /dev/null +++ b/utils.lua @@ -0,0 +1,42 @@ +local M = {} + +local awful = require("awful") + +-- mapping from logical screen indices to indices corresponding to their +-- physical layout +local function map_screen_physical(n) + local function screen_cmp(s1, s2) + return s1[2].geometry.x < s2[2].geometry.x + end + + local screens = {} + for s = 1, screen.count() do + screens[s] = {s, screen[s]} + end + + table.sort(screens, screen_cmp) + + if screens[n] ~= nil then + return screens[n][1] + end + return nil +end + +local function screen_focus_physical(n) + local idx_logical = map_screen_physical(n) + if idx_logical then + awful.screen.focus(idx_logical) + end +end + +function M.screen_focus_physical(n) screen_focus_physical(n) end + +-- audio control functions +local function vol_control(n) + local cmd = string.format("amixer -q set Master %d%%", math.abs(n)) .. (n < 0 and "-" or "+") + awful.util.spawn(cmd) +end + +function M.vol_control(n) vol_control(n) end + +return M -- cgit v1.2.3