weston/lua-shell/shell.lua
Marius Vlad 99f3a92f4a lua-shell: Use local pd to store background curtains
This avoids hitting the assert that we don't have any paint nodes in
available when the repaint loop starts.

As we only have just a single curtain, in multi-head/outputs case a new
output creation will destroy the previous curtain and we'll end up
hitting the empty paint nodes assert.

Note that this doesn't add any functionality it just makes sure we're actually
capable of running the lua-shell rather than dying.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2026-01-09 22:12:47 +02:00

362 lines
8.3 KiB
Lua

background_layer = {}
normal_layer = {}
hidden_layer = {}
fullscreen_layer = {}
current_width = 0
current_height = 0
function get_tile_row_col(count, width, height)
if (count == 0) then
return 1, 1
end
local cols = math.ceil(math.sqrt(count))
local rows = math.ceil(count / cols)
return cols, rows
end
function sort_views(views)
local count = 0
local sorted_views = {}
for k, v in pairs(views) do
count = count + 1
sorted_views[count] = k
end
table.sort(sorted_views)
return count, sorted_views
end
function relayout(output)
local views = normal_layer:get_views()
local output_width, output_height
local count = 0
local col = 0
local x = 0
local row = 0
local y = 0
local count, sorted_views = sort_views(views)
if (output == nil) then
output_width, output_height = primary_output:get_dimensions()
else
output_width, output_height = output:get_dimensions()
end
local cols, rows = get_tile_row_col(count)
local width = math.floor(output_width / cols)
local height = math.floor(output_height / rows)
for k, v in ipairs(sorted_views) do
col = col + 1
if (col > cols) then
row = row + 1
col = 1
x = 0
y = y + height
end
local view = views[v]
local surface = view:get_surface()
local gx, gy = surface:get_geometry()
view:set_position(x - gx, y - gy)
surface:set_state_normal(width, height)
x = x + width
end
end
function recreate_background(output)
local x, y = output:get_position()
local w, h = output:get_dimensions()
local pd = output:get_private()
if (pd.curtain ~= nil) then
pd.curtain:dispose()
end
pd.curtain = weston:create_curtain("output curtain")
pd.curtain:set_color(0xFF000000)
pd.curtain:set_position(x, y)
pd.curtain:set_dimensions(w, h)
pd.curtain:set_capture_input(true)
local bv = pd.curtain:get_view()
bv:set_output(output)
bv:set_layer(background_layer)
end
function my_output_create(output)
local pd = { has_fullscreen_view = false, curtain = nil }
if (primary_output == nil) then
primary_output = output
end
output:set_private(pd)
recreate_background(output)
-- Must set ready or no repaints will take place
output:set_ready()
end
function output_moved(output, move_x, move_y)
local views = background_layer:get_views()
for k, v in pairs(views) do
if v:get_output() == output then
x, y = v:get_position()
v:set_position(x + move_x, y + move_y)
end
end
views = normal_layer:get_views()
for k, v in pairs(views) do
if v:get_output() == output then
x, y = v:get_position()
v:set_position(x + move_x, y + move_y)
end
end
end
function output_resized(output)
recreate_background(output)
relayout(output)
end
function surface_added(surface)
local pd = {last_width = 0, last_height = 0, maximized = false,
map_fullscreen = false, fullscreen_output = nil}
pd.view = surface:create_view()
pd.width = 0
pd.height = 0
local outputs = weston:get_outputs()
for n, o in pairs(outputs) do
surface:set_output(o)
pd.view:set_output(o)
if (current_width == 0 and current_height == 0) then
output_width, output_height = o:get_dimensions()
current_width = output_width
current_height = output_height
else
current_width = math.floor(current_width / 2)
current_height = math.floor(current_height / 2)
end
pd.view:set_dimensions(current_width, current_height)
end
surface:set_private(pd)
end
function surface_removed(surface)
local pd = surface:get_private()
if (active_view == pd.view) then
pd.view:deactivate()
active_view = nil
end
if (pd.fullscreen_output) then
unset_fullscreen(surface)
end
pd.view:dispose()
current_width = current_width * 2
current_height = current_height * 2
relayout(nil)
end
function surface_maximize(surface, maximized)
if (maximized) then
local pd = surface:get_private()
pd.view:set_position(0, 0)
local output = pd.view:get_output()
if (output == nil) then
output = primary_output
end
surface:set_state_maximized(output)
pd.maximized = true
else
pd.maximized = false
relayout(nil)
end
end
function set_fullscreen(surface, output)
local surf_pd = surface:get_private()
local output_pd = output:get_private()
-- We only allow one fullscreen client
if (surf_pd.fullscreen_output ~= nil or output_pd.has_fullscreen_view) then
return
end
surface:set_state_fullscreen(output)
output_pd.has_fullscreen_view = true
output_pd.background_view:set_layer(fullscreen_layer)
surf_pd.view:move_in_front_of_other_view(output_pd.background_view)
surf_pd.fullscreen_output = output
surf_pd.view:set_position(0, 0)
end
function unset_fullscreen(surface)
local surf_pd = surface:get_private()
local output = surface:get_output()
local output_pd = output:get_private()
if (surf_pd.fullscreen_output == nil) then
return
end
output_pd.background_view:set_layer(background_layer)
surf_pd.view:set_layer(normal_layer)
output_pd.has_fullscreen_view = false
surf_pd.fullscreen_output = nil
relayout(nil)
end
function surface_fullscreen(surface, output, fullscreen)
if (fullscreen) then
local pd = surface:get_private()
if (output == nil) then
output = pd.view:get_output()
end
if (output == nil) then
output = primary_output
end
if (surface:is_mapped()) then
set_fullscreen(surface, output)
else
pd.map_fullscreen = true
end
else
unset_fullscreen(surface)
relayout(nil)
end
end
function lower_fullscreen_layer(surface, output)
local views_in_fs_layer = fullscreen_layer:get_views()
local count, sorted_views = sort_views(views_in_fs_layer)
for k, v in ipairs(sorted_views) do
local view = views_in_fs_layer[v]
local pd = view:get_private_surface()
-- no continue in lua, we have go the other way around
if (pd ~= nil) then
if (output ~= nil and pd.fullscreen_output == output) then
local output_pd = output:get_private()
if (output_pd.background_view) then
output_pd.background_view:set_layer(background_layer)
end
view:set_layer(normal_layer)
pd.map_fullscreen = false
pd.fullscreen_output = nil
output_pd.has_fullscreen_view = false
relayout(nil)
end
end
end
end
function surface_committed(surface)
local pd = surface:get_private()
local w, h = surface:get_dimensions()
local good_seat = nil
local output = nil
if (w == 0) then
return
end
local is_resized = w ~= pd.width or h ~= pd.height
pd.width = w
pd.height = h
if (is_resized) then
relayout(nil)
end
if surface:is_mapped() then
return
end
surface:map()
local seats = weston:get_seats()
for n, o in pairs(seats) do
good_seat = o
end
output = pd.view:get_output()
lower_fullscreen_layer(surface, output)
if (active_view ~= nil) then
active_view:deactivate()
end
pd.view:activate(good_seat)
active_view = pd.view
pd.view:set_layer(normal_layer)
if (pd.maximized) then
surface:set_state_maximized(output)
return
elseif (pd.map_fullscreen) then
set_fullscreen(surface, output)
return
end
relayout(nil)
end
function click_to_activate(focus_view, seat, button)
if (active_view == focus_view) then
return
end
if (active_view ~= nil) then
active_view:deactivate()
end
focus_view:activate(seat)
active_view = focus_view
end
function my_init()
background_layer = weston:create_layer()
background_layer:set_position(WESTON_LAYER_POSITION_BACKGROUND)
normal_layer = weston:create_layer()
normal_layer:set_position(WESTON_LAYER_POSITION_NORMAL)
hidden_layer = weston:create_layer()
hidden_layer:set_position(WESTON_LAYER_POSITION_HIDDEN)
fullscreen_layer = weston:create_layer()
fullscreen_layer:set_position(WESTON_LAYER_POSITION_FULLSCREEN)
weston:add_button_binding(BTN_LEFT, 0, click_to_activate)
weston:add_button_binding(BTN_RIGHT, 0, click_to_activate)
end
lua_shell_callbacks = {
init = my_init,
surface_added = surface_added,
surface_committed = surface_committed,
surface_fullscreen = surface_fullscreen,
surface_maximize = surface_maximize,
surface_removed = surface_removed,
output_create = my_output_create,
output_moved = output_moved,
output_resized = output_resized,
}