-
Notifications
You must be signed in to change notification settings - Fork 0
/
init.lua
259 lines (226 loc) · 6.43 KB
/
init.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
-- This project is licensed under the MIT License (see LICENSE).
--- A tiling layout featuring two visible tiled clients.
--
-- @author James Reed <[email protected]>
-- @copyright 2019-2020 James Reed
-- @module awesome-dovetail
local awful = require("awful")
local gears = require("gears")
local dovetail = {}
--- Override this function to change how dovetail determines the current tag.
--- The function takes the current screen.
--
-- @param s The current screen.
-- @usage dovetail.get_tag = custom_get_tag
-- @function get_tag
function dovetail.get_tag(s)
return s.selected_tag
end
local function arrange(p, ornt, mirror)
ornt = ornt or "horizontal"
local w = "width"
local x = "x"
if ornt == "vertical" then
w = "height"
x = "y"
end
local tag = p.tag or dovetail.get_tag(screen[p.screen])
local mwfact = tag.master_width_factor
local cls = p.clients
local wa = p.workarea
if #cls == 0 then
return
end
-- Client geometries are directly manipulated by awesome.
-- See https://github.com/awesomeWM/awesome/issues/2676
local function new_geom(g)
return {x = g.x, y = g.y, width = g.width, height = g.height}
end
local function set_geom(c, g)
p.geometries[c] = new_geom(g)
end
local function arrange_stack(g)
for i, c in ipairs(cls) do
if i > 1 then
set_geom(c, g)
end
end
end
local master = cls[1]
if #cls == 1 then
set_geom(master, wa)
else
local mw = wa[w] * mwfact
local master_g = new_geom(wa)
local stack_g = new_geom(wa)
master_g[w] = mw
stack_g[x] = wa[x] + mw
stack_g[w] = wa[w] - mw
if mirror then
set_geom(master, stack_g)
arrange_stack(master_g)
else
set_geom(master, master_g)
arrange_stack(stack_g)
end
end
end
dovetail.layout = {}
--- Check if a layout is a dovetail layout.
--
-- @param layout The layout or the current layout if nil.
-- @return `true` if layout is a dovetail layout.
-- @function layout
setmetatable(dovetail.layout, {__call = function (_, layout)
return gears.string.startswith(awful.layout.getname(layout), "dovetail")
end})
function dovetail.layout.skip_gap(nclients)
return nclients == 1
end
--- Horizontally tiled layout with stack on the right.
--
-- @function layout.right
dovetail.layout.right = {
name = "dovetail.layout.right",
arrange = arrange,
skip_gap = dovetail.layout.skip_gap,
}
--- Horizontally tiled layout with stack on the left.
--
-- @function layout.left
dovetail.layout.left = {
name = "dovetail.layout.left",
arrange = function (p) arrange(p, "horizontal", true) end,
skip_gap = dovetail.layout.skip_gap,
}
--- Vertically tiled layout with stack on the bottom.
--
-- @function layout.bottom
dovetail.layout.bottom = {
name = "dovetail.layout.bottom",
arrange = function (p) arrange(p, "vertical") end,
skip_gap = dovetail.layout.skip_gap,
}
--- Vertically tiled layout with stack on the top.
--
-- @function layout.top
dovetail.layout.top = {
name = "dovetail.layout.top",
arrange = function (p) arrange(p, "vertical", true) end,
skip_gap = dovetail.layout.skip_gap,
}
local function set_focus(c, name)
if c then
c:emit_signal("request::activate", name, {raise=true})
end
end
local function get_clients(s)
local m = awful.client.getmaster(s)
for _, c in ipairs(s.tiled_clients) do
if c ~= m then
return m, c
end
end
return m, nil
end
local function with_focus(func, c)
c = c or client.focus
if c then
return func(c, get_clients(c.screen))
end
end
dovetail.focus = {}
--- Focus a client in the stack by its relative index.
-- @param i The index.
-- @return `true` if conditions were met to search for a client.
-- If `false`, a fallback `focus.byidx` method should be used.
-- @function focus.byidx
function dovetail.focus.byidx(i)
local name = "dovetail.focus.byidx"
if not dovetail.layout() then
return false
end
return with_focus(function (c, master, stack)
if c.floating then
return false
end
if c == master then
if not stack then
return false
end
c = stack
end
local n = awful.client.next(i, c)
while n and n ~= c do
if n ~= master then
set_focus(n, name)
break
end
n = awful.client.next(i, n)
end
return true
end)
end
--- If the master client is focused, focus the visible client in the stack, and
--- vice versa.
-- @function focus.other
function dovetail.focus.other()
local name = "dovetail.focus.other"
with_focus(function (c, master, stack)
if c == master then
set_focus(stack, name)
else
set_focus(master, name)
end
end)
end
dovetail.master = {}
--- Swap master client with top stack, focusing stack.
-- @param no_swap If `true`, only swaps if master client is focused.
-- @function master.demote
function dovetail.master.demote(no_swap)
local name = "dovetail.master.demote"
with_focus(function (c, master, stack)
if c == stack and no_swap then
return
end
awful.client.setmaster(stack)
if c ~= master then
set_focus(master, name)
end
end)
end
--- Swap top stack client with master, focusing master.
-- @param no_swap If `true`, only swaps if top stack client is focused.
-- @function master.promote
function dovetail.master.promote(no_swap)
local name = "dovetail.master.promote"
with_focus(function (c, master, stack)
if c == master and no_swap then
return
end
if master then
master:raise()
end
awful.client.setmaster(stack)
set_focus(stack, name)
end)
end
--- Send master client to bottom of stack and replace with top stack client,
--- maintaining focus.
-- @function master.cycle
function dovetail.master.cycle()
local name = "dovetail.master.cycle"
with_focus(function (c, master, stack)
if master then
master:lower()
end
local next = awful.client.next(1, stack, true)
awful.client.setmaster(stack)
if c == stack then
stack = next
end
set_focus(stack, name)
end)
end
return dovetail