local keys = {} local awful = require("awful") local scratch = require("scratch") local utils = require("utils") local capi = { key = key } local drop = require("drop") local exec = utils.execute local spawn = function(command) return exec(awful.util.spawn, command) end local raise = function(command, rules) local matcher = function(c) return awful.rules.match(c, rules) end return function() awful.client.run_or_raise(command, matcher) end end local terminal = "xfce4-terminal" keys.modifiers = { ["M"]="Mod4", ["A"]="Mod1", ["C"]="Control", ["S"]="Shift", } keys.globals = { ["M-Left"] = awful.tag.viewprev, ["M-Right"] = awful.tag.viewnext, ["M-S-Left"] = exec(utils.relativetotag, -1), ["M-S-Right"] = exec(utils.relativetotag, 1), ["M-j"] = function() awful.client.focus.byidx(1) if client.focus then client.focus:raise() end end, ["M-k"] = function() awful.client.focus.byidx(-1) if client.focus then client.focus:raise() end end, ["M-S-j"] = exec(awful.client.swap.byidx, 1), ["M-S-k"] = exec(awful.client.swap.byidx, -1), ["M-C-j"] = exec(awful.screen.focus_relative, 1), ["M-C-k"] = exec(awful.screen.focus_relative, -1), ["M-u"] = awful.client.urgent.jumpto, ["M-Return"] = spawn(terminal), ["M-C-r"] = awesome.restart, ["M-C-q"] = awesome.quit, ["M-C-n"] = awful.client.restore, ["M-r"] = spawn("dmenu_run -b -fn 'Hack-16'"), ["M-d"] = exec(drop.toggle, terminal, terminal, "top"), ["M-a"] = { ["M-f"] = raise("firefox", { class = "Firefox" }), ["M-l"] = spawn("i3lock -f -i $(ls ~/CS/python/wallpapers/image | sort -R | head -n1)"), ["M-s"] = raise("spotify --force-device-scale-factor=1.25", { class = "Spotify" }), ["M-v"] = raise("gvim", { class = "Gvim" }), }, ["XF86AudioPlay"] = spawn("playerctl play-pause"), ["XF86AudioNext"] = spawn("playerctl next"), ["XF86AudioPrev"] = spawn("playerctl previous"), } -- TODO: allow depth > 1 keys.client = { ["M-S-c"] = function(c) c:kill() end, ["M-f"] = function(c) c.fullscreen = not c.fullscreen end, ["M-m"] = function(c) c.maximized_horizontal = not c.maximized_horizontal c.maximized_vertical = not c.maximized_vertical end, ["M-n"] = function(c) c.minimized = true end, ["M-o"] = awful.client.movetoscreen, ["M-space"] = function(c) awful.client.floating.toggle() c.ontop = not c.ontop end, ["M-C-d"] = drop.toggle_set, } -- Translate a key binding into a list of modifiers and a key -- e.g: translate("M-S-j") = { "M", "S" }, "j" local translate = function(input) local modifiers = {} local items = input:split("-") local key = table.remove(items) for _, item in ipairs(items) do table.insert(modifiers, keys.modifiers[item]) end return modifiers, key end -- DFS the given table, recurse when a value is itself a table, with callback local function traverse(t, callback) for key, value in pairs(t) do callback(key, value) if type(value) == "table" then traverse(value, callback) end end end -- Find all different bindings from a bindings table local allBindings = function(t) local bindings = {} local callback = function(b, _) bindings[b] = true end traverse(t, callback) return table.keys(bindings) end keys.state = keys.globals local handleKeyPress = function(binding) local action = keys.state[binding] if action == nil then keys.state = keys.globals elseif type(action) == "table" then keys.state = action else action() end end keys.bindGlobals = function() local toKey = function(binding) local modifiers, key = translate(binding) local key = capi.key({ modifiers = modifiers, key = key }) key:connect_signal("press", function () handleKeyPress(binding) end) return key end return utils.map(toKey, allBindings(keys.globals)) end keys.bindClient = function() local toKey = function(binding) local modifiers, key = translate(binding) return awful.key(modifiers, key, keys.client[binding]) end local result = {} for binding, f in pairs(keys.client) do local modifiers, key = translate(binding) result = awful.util.table.join( result, awful.key(modifiers, key, f) ) end return result end return keys ---------- local awful = require("awful") local capi = { mouse = mouse, client = client, screen = screen } local utils = require("utils") local naughty = require("naughty") local drop = {} drop.dropdown = {} drop.width, drop.height = 0.9, 0.55 drop.spawn = function(c, position, callback) local screen = capi.mouse.screen awful.client.floating.set(c, true) local screengeom = capi.screen[screen].workarea local width = screengeom.width * drop.width local height = screengeom.height * drop.height local x = screengeom.x + (screengeom.width - width) / 2 local y if position == "top" then y = screengeom.y elseif position == "bottom" then y = screengeom.y + screengeom.height - height else y = screengeom.y + (screengeom.height - height) / 2 end c:geometry({ x = x, y = y, width = width, height = height }) c.ontop = true c.above = true c.skip_taskbar = true c.sticky = true if c.titlebar then awful.titlebar.remove(c) end if callback then callback(c) end end drop.set = function(c) local program = c.class if not drop.dropdown[program] then drop.dropdown[program] = {} end drop.dropdown[program][capi.mouse.screen] = c drop.spawn(c, "top") end drop.toggle_set = function(c) local program = c.class if drop.dropdown[program] and drop.dropdown[program][capi.mouse.screen] then if c.above and c.skip_taskbar and c.sticky then c.ontop = false c.above = false c.skip_taskbar = false c.sticky = false awful.client.floating.set(c, false) drop.dropdown[program][capi.mouse.screen] = nil end else drop.set(c) end end drop.toggle = function(program, command, position) local connect_signal = capi.client.connect_signal local disconnect_signal = capi.client.disconnect_signal local dropdown = drop.dropdown local screen = capi.mouse.screen if not dropdown[program] then dropdown[program] = {} capi.client.connect_signal("unmanage", function(c) for scr, cl in pairs(dropdown[program]) do if cl == c then dropdown[program][scr] = nil end end end) end if not dropdown[program][screen] then spawn = function(c) local callback = function(c) c:raise() capi.client.focus = c disconnect_signal("manage", spawn) dropdown[program][screen] = c end drop.spawn(c, position, callback) end connect_signal("manage", spawn) awful.util.spawn(command, false) else c = dropdown[program][screen] if not c:isvisible() then c.hidden = true awful.client.movetotag(awful.tag.selected(screen), c) end if c.hidden then c.hidden = false c:raise() capi.client.focus = c else c.hidden = true local ctags = c:tags() for i, t in pairs(ctags) do ctags[i] = nil end c:tags(ctags) end end end return drop