~felipetavares/dotfiles

dotfiles/.config/awesome/ultrawide.lua -rw-r--r-- 4.8 KiB
6595e845Felipe Tavares adding widescreen layout for awesomewm a month ago
                                                                                
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
--[[

     This is similar to lain's "centerwork" layout, however it:

     - doesn't needlessy move windows around;
     - has a better resizing experience;
     - has a better moving windows experience;
     - allows for more columns

     Licensed under GNU General Public License v2
      * (c) 2022,      Felipe Tavares
      * (c) 2018,      Eugene Pakhomov
      * (c) 2016,      Henrik Antonsson
      * (c) 2015,      Joerg Jaspert
      * (c) 2014,      projektile
      * (c) 2013,      Luca CPZ
      * (c) 2010-2012, Peter Hofmann

--]]

local gears = require("gears")
local clientlib = client
local taglib = require("awful.tag")
local resize = require("awful.mouse.resize")
local optimizer = require("layout_optimizer")

local mouse = mouse
local mousegrabber = mousegrabber

local ultrawide = {
    name = "ultrawide",
    tags = {},
}

resize.add_move_callback(function(client, geometry, args)
        client.floating = true
end, "mouse.move")

resize.add_leave_callback(function(client, geometry, args)
        client.floating = false
end, "mouse.move")


local function workarea_to_tiles(layout, tag, workarea, clients_number)
    local columns = math.max(3, clients_number)

    local column_width = workarea.width / columns
    local column_height = workarea.height

    if layout.tags[tag] == nil then
        layout.tags[tag] = {tiles = {}, locations = {}}
    end

    tiles = layout.tags[tag].tiles

    for i=1,columns-#tiles do
        table.insert(tiles, {
                         x = 0, y = 0, width = 0, height = 0,
                         -- the client assigned to this tile
                         client = nil
        })
    end

    for i=#tiles,1,-1 do
        if tiles[i].client == nil and #tiles > columns then
            table.remove(tiles, i)
        end
    end

    local f = tag.master_width_factor
    local cursor = workarea.x

    for i, tile in ipairs(tiles) do
        local w

        if i == math.ceil(columns/2) then
            w = workarea.width * f
        else
            w = workarea.width * (1-f) / (columns-1)
        end

        tile.x = cursor
        tile.y = workarea.y
        tile.width = w
        tile.height = workarea.height

        cursor = cursor + w
    end

    return tiles
end

local function assign_client_to_tile(geometries, client, tile)
    geometries[client] = {
        x = tile.x, y = tile.y, width = tile.width, height = tile.height
    }
end

local function arrange(p, layout)
    local tag = taglib.selected(p.screen)
    local tiles = workarea_to_tiles(layout, tag, p.workarea, #p.clients)
    local geometries = p.geometries

    -- focused client are given priority
    table.sort(p.clients, function(a, b) return a == clientlib.focus end)

    -- tries to find how to fit the windows in the tiles, brute force as of now
    local mapping = optimizer.find_min_movement_mapping(p.clients, tiles)

    -- apply the mapping
    for i, client in ipairs(p.clients) do
        assign_client_to_tile(geometries, client, tiles[mapping[i]])
    end
end

local function mouse_resize_handler(c, _, _, _, orientation)
    local wa     = c.screen.workarea
    local mwfact = c.screen.selected_tag.master_width_factor
    local g      = c:geometry()
    local offset = 0
    local cursor = "cross"

    local corner_coords

    if orientation == 'vertical' then
        if g.height + 15 >= wa.height then
            offset = g.height * .5
            cursor = "sb_h_double_arrow"
        elseif g.y + g.height + 15 <= wa.y + wa.height then
            offset = g.height
        end
        corner_coords = { x = wa.x + wa.width * (1 - mwfact) / 2, y = g.y + offset }
    else
        if g.width + 15 >= wa.width then
            offset = g.width * .5
            cursor = "sb_v_double_arrow"
        elseif g.x + g.width + 15 <= wa.x + wa.width then
            offset = g.width
        end
        corner_coords = { y = wa.y + wa.height * (1 - mwfact) / 2, x = g.x + offset }
    end

    mouse.coords(corner_coords)

    local prev_coords = {}

    mousegrabber.run(function(m)
        if not c.valid then return false end
        for _, v in ipairs(m.buttons) do
            if v then
                prev_coords = { x = m.x, y = m.y }
                local new_mwfact
                if orientation == 'vertical' then
                    new_mwfact = 1 - (m.x - wa.x) / wa.width * 2
                else
                    new_mwfact = 1 - (m.y - wa.y) / wa.height * 2
                end
                c.screen.selected_tag.master_width_factor = math.min(math.max(new_mwfact, 0.01), 0.99)
                return true
            end
        end
        return prev_coords.x == m.x and prev_coords.y == m.y
    end, cursor)
end

function ultrawide.arrange(p)
    return arrange(p, ultrawide)
end

function ultrawide.mouse_resize_handler(c, corner, x, y)
    return mouse_resize_handler(c, corner, x, y, 'vertical')
end

return ultrawide