diff --git a/lib/quake.lua b/lib/quake.lua new file mode 100644 index 0000000..d8abc86 --- /dev/null +++ b/lib/quake.lua @@ -0,0 +1,151 @@ +-- Quake like console on top +-- Similar to: +-- http://git.sysphere.org/awesome-configs/tree/scratch/drop.lua + +-- But uses a different implementation. The main difference is that we +-- are able to detect the Quake console from its name +-- (QuakeConsoleNeedsUniqueName by default). + +-- Use: + +-- local quake = require("quake") +-- local quakeconsole = {} +-- for s = 1, screen.count() do +-- quakeconsole[s] = quake({ terminal = config.terminal, +-- height = 0.3, +-- screen = s }) +-- end + +-- config.keys.global = awful.util.table.join( +-- config.keys.global, +-- awful.key({ modkey }, "`", +-- function () quakeconsole[mouse.screen]:toggle() end) + +local setmetatable = setmetatable +local string = string +local awful = require("awful") +local capi = { mouse = mouse, + screen = screen, + client = client, + timer = timer } + +-- I use a namespace for my modules... +module("vbe/quake") + +local QuakeConsole = {} + +-- Display +function QuakeConsole:display() + -- First, we locate the terminal + local client = nil + local i = 0 + for c in awful.client.cycle(function (c) + -- c.name may be changed! + return c.icon_name == self.name + end, + nil, self.screen) do + i = i + 1 + if i == 1 then + client = c + else + -- Additional matching clients, let's remove the sticky bit + -- which may persist between awesome restarts. We don't close + -- them as they may be valuable. They will just turn into a + -- classic terminal. + c.sticky = false + c.ontop = false + c.above = false + end + end + + if not client and not self.visible then + -- The terminal is not here yet but we don't want it yet. Just do nothing. + return + end + + if not client then + -- The client does not exist, we spawn it + awful.util.spawn(self.terminal .. " " .. string.format(self.argname, self.name), + false, self.screen) + return + end + + -- Comptute size + local geom = capi.screen[self.screen].workarea + local width, height = self.width, self.height + if width <= 1 then width = geom.width * width end + if height <= 1 then height = geom.height * height end + local x, y + if self.horiz == "left" then x = geom.x + elseif self.horiz == "right" then x = geom.width + geom.x - width + else x = geom.x + (geom.width - width)/2 end + if self.vert == "top" then y = geom.y + elseif self.vert == "bottom" then y = geom.height + geom.y - height + else y = geom.y + (geom.height - height)/2 end + + -- Resize + awful.client.floating.set(client, true) + client.border_width = 0 + client.size_hints_honor = false + client:geometry({ x = x, y = y, width = width, height = height }) + + -- Sticky and on top + client.ontop = true + client.above = true + client.skip_taskbar = true + client.sticky = true + + -- Toggle display + if self.visible then + client.hidden = false + client:raise() + capi.client.focus = client + else + client.hidden = true + end +end + +-- Create a console +function QuakeConsole:new(config) + -- The "console" object is just its configuration. + + -- The application to be invoked is: + -- config.terminal .. " " .. string.format(config.argname, config.name) + config.terminal = config.terminal or "xterm" -- application to spawn + config.name = config.name or "QuakeConsoleNeedsUniqueName" -- window name + config.argname = config.argname or "-name %s" -- how to specify window name + + -- If width or height <= 1 this is a proportion of the workspace + config.height = config.height or 0.25 -- height + config.width = config.width or 1 -- width + config.vert = config.vert or "top" -- top, bottom or center + config.horiz = config.horiz or "center" -- left, right or center + + config.screen = config.screen or capi.mouse.screen + config.visible = config.visible or false -- Initially, not visible + + local console = setmetatable(config, { __index = QuakeConsole }) + capi.client.add_signal("manage", + function(c) + if c.name == console.name and c.screen == console.screen then + console:display() + end + end) + + local reattach = capi.timer { timeout = 0 } + reattach:add_signal("timeout", + function() + reattach:stop() + console:display() + end) + reattach:start() + return console +end + +-- Toggle the console +function QuakeConsole:toggle() + self.visible = not self.visible + self:display() +end + +setmetatable(_M, { __call = function(_, ...) return QuakeConsole:new(...) end }) diff --git a/rc/quake.lua b/rc/quake.lua index 69c7a5d..5780b2d 100644 --- a/rc/quake.lua +++ b/rc/quake.lua @@ -1,67 +1,14 @@ --- Quake like console on top --- See: --- http://git.sysphere.org/awesome-configs/tree/scratch/drop.lua +local quake = loadrc("quake", "vbe/quake") -local quake = {} -- List of quake consoles -local height = 0.3 - --- When a quake console is closed, remove it from the list -client.add_signal("unmanage", - function (c) - for i, cl in pairs(quake) do - if cl == c then - quake[i] = nil - end - end - end) - --- Toggle the console -local function toggle() - local cscreen = mouse.screen - - if not quake[cscreen] then - -- We must spawn a new console - - local function spawn (c) - -- We assume that c is our Quake console. 99.9% sure. - quake[cscreen] = c - - -- Setup on top - awful.client.floating.set(c, true) - c.border_width = 0 - c.size_hints_honor = false - local geom = screen[cscreen].workarea - c:geometry({ x = geom.x, - y = geom.y, - width = geom.width, - height = geom.height * height }) - c.ontop = true - c.above = true - c.skip_taskbar = true - c.sticky = true - c:raise() - client.focus = c - - -- Remove our signal handler - client.remove_signal("manage", spawn) - end - - client.add_signal("manage", spawn) - awful.util.spawn(config.terminal, false) - else - -- Display an existing console - - c = quake[cscreen] - if c.hidden then - c.hidden = false - c:raise() - client.focus = c - else - c.hidden = true - end - end +local quakeconsole = {} +for s = 1, screen.count() do + quakeconsole[s] = quake({ terminal = config.terminal, + height = 0.3, + screen = s }) end config.keys.global = awful.util.table.join( config.keys.global, - awful.key({ modkey }, "`", toggle, "Toggle Quake console")) + awful.key({ modkey }, "`", + function () quakeconsole[mouse.screen]:toggle() end, + "Toggle Quake console"))