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

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