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

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