]> 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:

4314a1614190d9767d342d1a46457d112c9541a9
[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         awful.spawn(string.format("%s %s %s", self.app,
58                     string.format(self.argname, self.name), self.extra),
59                     false, self.screen)
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 = screen[self.screen].workarea
101     local width, height = self.width, self.height
102     if width  <= 1 then width = math.floor(geom.width * width) - 2 * self.border end
103     if height <= 1 then height = math.floor(geom.height * height) end
104     local x, y
105     if     self.horiz == "left"  then x = geom.x
106     elseif self.horiz == "right" then x = geom.width + geom.x - width
107     else   x = geom.x + (geom.width - width)/2 end
108     if     self.vert == "top"    then y = geom.y
109     elseif self.vert == "bottom" then y = geom.height + geom.y - height
110     else   y = geom.y + (geom.height - height)/2 end
111     self.geometry = { x = x, y = y, width = width, height = height }
112 end
113
114 function quake:new(config)
115     local conf = config or {}
116
117     conf.app       = conf.app       or "xterm"    -- application to spawn
118     conf.name      = conf.name      or "QuakeDD"  -- window name
119     conf.argname   = conf.argname   or "-name %s" -- how to specify window name
120     conf.extra     = conf.extra     or ""         -- extra arguments
121     conf.visible   = conf.visible   or false      -- initially not visible
122     conf.border    = conf.border    or 1          -- client border width
123     conf.followtag = conf.followtag or false      -- spawn on currently focused screen
124     conf.screen    = conf.screen    or awful.screen.focused()
125
126     -- If width or height <= 1 this is a proportion of the workspace
127     conf.height       = conf.height       or 0.25     -- height
128     conf.width        = conf.width        or 1        -- width
129     conf.vert         = conf.vert         or "top"    -- top, bottom or center
130     conf.horiz        = conf.horiz        or "left"   -- left, right or center
131
132     local console = setmetatable(conf, { __index = quake })
133     capi.client.connect_signal("manage", function(c)
134         if c.instance == console.name and c.screen == console.screen then
135             console:display()
136         end
137     end)
138     capi.client.connect_signal("unmanage", function(c)
139         if c.instance == console.name and c.screen == console.screen then
140             console.visible = false
141         end
142      end)
143
144     -- "Reattach" currently running quake application. This is in case awesome is restarted.
145     local reattach = capi.timer { timeout = 0 }
146     reattach:connect_signal("timeout", function()
147         if self.followtag then self.screen = awful.screen.focused() end
148         reattach:stop()
149         console:display()
150     end)
151     reattach:start()
152
153     return console
154 end
155
156 function quake:toggle()
157      if self.followtag then self.screen = awful.screen.focused() end
158      local current_tag = self.screen.selected_tag
159      if current_tag and self.last_tag ~= current_tag and self.visible then
160          self:display():move_to_tag(current_tag)
161      else
162          self.visible = not self.visible
163          self:display()
164      end
165 end
166
167 return setmetatable(quake, { __call = function(_, ...) return quake:new(...) end })