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

be9258c0befbdafc6ad688ab5b0fde013c97cca6
[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(self.app .. " " .. string.format(self.argname, self.name) ..
56                         " " .. self.extra, false, self.screen)
57        self.notexist = true
58        return
59    end
60
61    -- Resize
62    awful.client.floating.set(client, true)
63    client.border_width = self.border
64    client.size_hints_honor = false
65    if self.notexist then
66        client:geometry(self.geometry)
67        self.notexist = false
68    end
69
70    -- Not sticky and on top
71    client.ontop = true
72    client.above = true
73    client.skip_taskbar = true
74    client.sticky = false
75
76    -- Toggle display
77    if self.visible then
78        client.hidden = false
79        client:raise()
80        self.last_tag = tostring(awful.tag.selected(self.screen))
81        client:tags({awful.tag.selected(self.screen)})
82        capi.client.focus = client
83    else
84        client.hidden = true
85        local ctags = client:tags()
86        for i, t in pairs(ctags) do
87            ctags[i] = nil
88        end
89        client:tags(ctags)
90    end
91
92    return client
93 end
94
95 function quake:new(config)
96    local conf = config or {}
97
98    conf.app      = conf.app      or "xterm"    -- application to spawn
99    conf.name     = conf.name     or "QuakeDD"  -- window name
100    conf.argname  = conf.argname  or "-name %s" -- how to specify window name
101    conf.extra    = conf.extra    or ""         -- extra arguments
102    conf.visible  = conf.visible  or false      -- initially not visible
103    conf.screen   = conf.screen   or capi.mouse.screen
104    conf.border   = conf.border   or 1
105
106    -- If width or height <= 1 this is a proportion of the workspace
107    wibox_height = conf.wibox_height or 18       -- statusbar weight
108    height       = conf.height       or 0.25     -- height
109    width        = conf.width        or 1        -- width
110    vert         = conf.vert         or "top"    -- top, bottom or center
111    horiz        = conf.horiz        or "center" -- left, right or center
112
113    -- Compute size
114    local geom = capi.screen[conf.screen].workarea
115    if width  <= 1 then width = geom.width * width end
116    if height <= 1 then height = geom.height * height end
117    local x, y
118    if     horiz == "left"  then x = geom.x
119    elseif horiz == "right" then x = geom.width + geom.x - width
120    else   x = geom.x + (geom.width - width)/2 end
121    if     vert == "top"    then y = geom.y
122    elseif vert == "bottom" then y = geom.height + geom.y - height
123    else   y = geom.y + (geom.height - height)/2 end
124    conf.geometry = { x = x, y = y + wibox_height, width = width, height = height }
125
126    local console = setmetatable(conf, { __index = quake })
127    capi.client.connect_signal("manage", function(c)
128        if c.instance == console.name and c.screen == console.screen then
129            console:display()
130        end
131    end)
132    capi.client.connect_signal("unmanage", function(c)
133        if c.instance == console.name and c.screen == console.screen then
134            console.visible = false
135        end
136     end)
137
138    -- "Reattach" currently running quake application. This is in case awesome is restarted.
139    local reattach = capi.timer { timeout = 0 }
140    reattach:connect_signal("timeout", function()
141        reattach:stop()
142        console:display()
143    end)
144    reattach:start()
145
146    return console
147 end
148
149 function quake:toggle()
150     current_tag = awful.tag.selected(self.screen)
151     if self.last_tag ~= tostring(current_tag) and self.visible then
152         awful.client.movetotag(current_tag, self:display())
153     else
154         self.visible = not self.visible
155         self:display()
156     end
157 end
158
159 setmetatable(quake, { __call = function(_, ...) return quake:new(...) end })
160
161 return quake