]> git.madduck.net Git - etc/awesome.git/blob - util/quake.lua

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

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.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

imap: asynchronous: forgot shell
[etc/awesome.git] / util / quake.lua
1
2 --[[
3                                                    
4      Licensed under GNU General Public License v2  
5       * (c) 2016, Luke Bonham                      
6       * (c) 2015, unknown                          
7                                                    
8 --]]
9
10 local awful        = require("awful")
11 local capi         = { client = client,
12                        timer  = require("gears.timer") }
13 local math         = { floor  = math.floor }
14 local string       = string
15
16 local pairs        = pairs
17 local screen       = screen
18 local setmetatable = setmetatable
19 local tostring     = tostring
20
21 -- Quake-like Dropdown application spawn
22 local quake = {}
23
24 -- If you have a rule like "awful.client.setslave" for your terminals,
25 -- ensure you use an exception for QuakeDD. Otherwise, you may
26 -- run into problems with focus.
27
28 function quake:display()
29     if self.followtag then self.screen = awful.screen.focused() end
30
31     -- First, we locate the client
32     local client = nil
33     local i = 0
34     for c in awful.client.iterate(function (c)
35         -- c.name may be changed!
36         return c.instance == self.name
37     end, nil, self.screen)
38     do
39         i = i + 1
40         if i == 1 then
41             client = c
42         else
43             -- Additional matching clients, let's remove the sticky bit
44             -- which may persist between awesome restarts. We don't close
45             -- them as they may be valuable. They will just turn into
46             -- normal clients.
47             c.sticky = false
48             c.ontop = false
49             c.above = false
50         end
51     end
52
53     if not client and not self.visible then return end
54
55     if not client then
56         -- The client does not exist, we spawn it
57         cmd = string.format("%s %s %s", self.app,
58               string.format(self.argname, self.name), self.extra)
59         awful.spawn(cmd, { tag = self.screen.selected_tag })
60         self.notexist = true
61         return
62     end
63
64     -- Resize
65     client.floating = true
66     client.border_width = self.border
67     client.size_hints_honor = false
68     if self.notexist then
69         self:compute_size()
70         client:geometry(self.geometry)
71         self.notexist = false
72     end
73
74     -- Not sticky and on top
75     client.sticky = false
76     client.ontop = true
77     client.above = true
78     client.skip_taskbar = true
79
80     -- Toggle display
81     if self.visible then
82         client.hidden = false
83         client:raise()
84         self.last_tag = self.screen.selected_tag
85         client:tags({self.screen.selected_tag})
86         capi.client.focus = client
87    else
88         client.hidden = true
89         local ctags = client:tags()
90         for i, t in pairs(ctags) do
91             ctags[i] = nil
92         end
93         client:tags(ctags)
94     end
95
96     return client
97 end
98
99 function quake:compute_size()
100     local geom
101     if not self.overlap then
102         geom = screen[self.screen].workarea
103     else
104         geom = screen[self.screen].geometry
105     end
106     local width, height = self.width, self.height
107     if width  <= 1 then width = math.floor(geom.width * width) - 2 * self.border end
108     if height <= 1 then height = math.floor(geom.height * height) end
109     local x, y
110     if     self.horiz == "left"  then x = geom.x
111     elseif self.horiz == "right" then x = geom.width + geom.x - width
112     else   x = geom.x + (geom.width - width)/2 end
113     if     self.vert == "top"    then y = geom.y
114     elseif self.vert == "bottom" then y = geom.height + geom.y - height
115     else   y = geom.y + (geom.height - height)/2 end
116     self.geometry = { x = x, y = y, width = width, height = height }
117 end
118
119 function quake:new(config)
120     local conf = config or {}
121
122     conf.app        = conf.app       or "xterm"    -- application to spawn
123     conf.name       = conf.name      or "QuakeDD"  -- window name
124     conf.argname    = conf.argname   or "-name %s" -- how to specify window name
125     conf.extra      = conf.extra     or ""         -- extra arguments
126     conf.border     = conf.border    or 1          -- client border width
127     conf.visible    = conf.visible   or false      -- initially not visible
128     conf.followtag  = conf.followtag or false      -- spawn on currently focused screen
129     conf.overlap    = conf.overlap   or false      -- overlap wibox
130     conf.screen     = conf.screen    or awful.screen.focused()
131
132     -- If width or height <= 1 this is a proportion of the workspace
133     conf.height       = conf.height       or 0.25     -- height
134     conf.width        = conf.width        or 1        -- width
135     conf.vert         = conf.vert         or "top"    -- top, bottom or center
136     conf.horiz        = conf.horiz        or "left"   -- left, right or center
137
138     local console = setmetatable(conf, { __index = quake })
139     capi.client.connect_signal("manage", function(c)
140         if c.instance == console.name and c.screen == console.screen then
141             console:display()
142         end
143     end)
144     capi.client.connect_signal("unmanage", function(c)
145         if c.instance == console.name and c.screen == console.screen then
146             console.visible = false
147         end
148      end)
149
150     -- "Reattach" currently running quake application. This is in case awesome is restarted.
151     local reattach = capi.timer { timeout = 0 }
152     reattach:connect_signal("timeout", function()
153         if self.followtag then self.screen = awful.screen.focused() end
154         reattach:stop()
155         console:display()
156     end)
157     reattach:start()
158
159     return console
160 end
161
162 function quake:toggle()
163      if self.followtag then self.screen = awful.screen.focused() end
164      local current_tag = self.screen.selected_tag
165      if current_tag and self.last_tag ~= current_tag and self.visible then
166          self:display():move_to_tag(current_tag)
167      else
168          self.visible = not self.visible
169          self:display()
170      end
171 end
172
173 return setmetatable(quake, { __call = function(_, ...) return quake:new(...) end })