background_layer = {} normal_layer = {} hidden_layer = {} fullscreen_layer = {} background_curtain = nil 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() if (background_curtain ~= nil) then background_curtain:dispose() end background_curtain = weston:create_curtain("output curtain") background_curtain:set_color(0xFF000000) background_curtain:set_position(x, y) background_curtain:set_dimensions(w, h) background_curtain:set_capture_input(true) bv = background_curtain:get_view() bv:set_output(output) bv:set_layer(background_layer) end function my_output_create(output) local pd = { has_fullscreen_view = false } if (primary_output == nil) then primary_output = output end recreate_background(output) pd.background_view = bv output:set_private(pd) 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, }