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

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