All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
3 Licensed under GNU General Public License v2
4 * (c) 2016, Luke Bonham
9 local awful = require("awful")
10 local capi = { client = client }
12 local math = { floor = math.floor }
13 local string = { format = string.format }
18 local setmetatable = setmetatable
20 -- Quake-like Dropdown application spawn
23 -- If you have a rule like "awful.client.setslave" for your terminals,
24 -- ensure you use an exception for QuakeDD. Otherwise, you may
25 -- run into problems with focus.
27 function quake:display()
28 if self.followtag then self.screen = awful.screen.focused() end
29 local toscan = self.screen
30 if self.onlyone then toscan = nil end
32 -- First, we locate the client
35 for c in awful.client.iterate(function (c)
36 -- c.name may be changed!
37 return c.instance == self.name
44 -- Additional matching clients, let's remove the sticky bit
45 -- which may persist between awesome restarts. We don't close
46 -- them as they may be valuable. They will just turn into
54 if not client and not self.visible then return end
57 -- The client does not exist, we spawn it
58 cmd = string.format("%s %s %s", self.app,
59 string.format(self.argname, self.name), self.extra)
60 awful.spawn(cmd, { tag = self.screen.selected_tag })
65 client.floating = true
66 client.border_width = self.border
67 client.size_hints_honor = false
68 client:geometry(self.geometry[self.screen] or self:compute_size())
70 -- Set not sticky and on top
74 client.skip_taskbar = true
76 -- Additional user settings
77 if self.settings then self.settings(client) end
83 self.last_tag = self.screen.selected_tag
84 client:tags({self.screen.selected_tag})
85 capi.client.focus = client
88 local ctags = client:tags()
89 for i, t in pairs(ctags) do
98 function quake:compute_size()
99 -- skip if we already have a geometry for this screen
100 if not self.geometry[self.screen] then
102 if not self.overlap then
103 geom = screen[self.screen].workarea
105 geom = screen[self.screen].geometry
107 local width, height = self.width, self.height
108 if width <= 1 then width = math.floor(geom.width * width) - 2 * self.border end
109 if height <= 1 then height = math.floor(geom.height * height) end
111 if self.horiz == "left" then x = geom.x
112 elseif self.horiz == "right" then x = geom.width + geom.x - width
113 else x = geom.x + (geom.width - width)/2 end
114 if self.vert == "top" then y = geom.y
115 elseif self.vert == "bottom" then y = geom.height + geom.y - height
116 else y = geom.y + (geom.height - height)/2 end
117 self.geometry[self.screen] = { x = x, y = y, width = width, height = height }
119 return self.geometry[self.screen]
122 function quake:new(config)
123 local conf = config or {}
125 conf.app = conf.app or "xterm" -- application to spawn
126 conf.name = conf.name or "QuakeDD" -- window name
127 conf.argname = conf.argname or "-name %s" -- how to specify window name
128 conf.extra = conf.extra or "" -- extra arguments
129 conf.border = conf.border or 1 -- client border width
130 conf.visible = conf.visible or false -- initially not visible
131 conf.followtag = conf.followtag or false -- spawn on currently focused screen
132 conf.onlyone = conf.onlyone or false -- one instance for all screens
133 conf.overlap = conf.overlap or false -- overlap wibox
134 conf.screen = conf.screen or awful.screen.focused()
135 conf.settings = conf.settings
137 -- If width or height <= 1 this is a proportion of the workspace
138 conf.height = conf.height or 0.25 -- height
139 conf.width = conf.width or 1 -- width
140 conf.vert = conf.vert or "top" -- top, bottom or center
141 conf.horiz = conf.horiz or "left" -- left, right or center
142 conf.geometry = {} -- internal use
144 local dropdown = setmetatable(conf, { __index = quake })
146 capi.client.connect_signal("manage", function(c)
147 if c.instance == dropdown.name and c.screen == dropdown.screen then
151 capi.client.connect_signal("unmanage", function(c)
152 if c.instance == dropdown.name and c.screen == dropdown.screen then
153 dropdown.visible = false
160 function quake:toggle()
161 if self.followtag then self.screen = awful.screen.focused() end
162 local current_tag = self.screen.selected_tag
163 if current_tag and self.last_tag ~= current_tag and self.visible then
164 self:display():move_to_tag(current_tag)
166 self.visible = not self.visible
171 return setmetatable(quake, { __call = function(_, ...) return quake:new(...) end })