local M = {} local awful = require("awful") local object = require("gears.object") local stack = require("stack") local Workspace = {} function Workspace:add_desktop(idx, name, nb_pages) local desk = object() desk.name = name desk.pages = {} desk.indices_free = stack.Stack:new() for i = 1, nb_pages do desk.pages[i] = awful.tag.add(name .. i, { layout = self.layouts[1] }) desk.indices_free:push(i) end desk.screen_map = {} self.desktops[idx] = desk return idx end function Workspace:rename_desktop(idx, name) local desk = self.desktops[idx] desk.name = name desk:emit_signal("desktop:name", name) end function Workspace:_apply_state() local orig_focus = mouse.screen for s in screen do if self.screen_state[s] then awful.tag.viewnone(s) local desk = self.screen_state[s].desktop_idx local page = self.desktops[desk].pages[self.screen_state[s].page_idx] page.screen = s end end for s in screen do local state = self.screen_state[s] if state then local desk_idx = state.desktop_idx local desk = self.desktops[desk_idx] local page_idx = state.page_idx local page = desk.pages[page_idx] print("workspace displaying: " .. s.index .. " => " .. desk_idx .. "/" .. page_idx) page:view_only() desk:emit_signal("page:view", s, page_idx) end end awful.screen.focus(orig_focus) end function Workspace:view(screen, desktop_idx, page_idx) print("workspace: " .. screen.index .. ": view " .. desktop_idx .. "/" .. (page_idx or "nil")) if self.desktops[desktop_idx] == nil then print("Adding desktop " .. desktop_idx) self:add_desktop(desktop_idx, "Desktop " .. desktop_idx, 10) end local desktop = self.desktops[desktop_idx] -- the current state of the target screen local state_cur = self.screen_state[screen] -- the screen on which the new page is currently displayed (if any) local screen_other = nil if page_idx == nil then -- the page is not specified if state_cur and state_cur.desktop_idx == desktop_idx then -- requested desktop is already displayed on this screen, nothing to do return end -- take the topmost free one page_idx = desktop.indices_free:pop() if page_idx == nil then print("No free pages on desktop") return end else -- check if the page is already displayed somewhere screen_other = desktop.screen_map[page_idx] if screen_other == screen then -- the page is already displayed on this screen, nothing to do return elseif screen_other == nil then desktop.indices_free:remove(page_idx) end end if screen_other then -- the page we want is already shown on some other screen, so we swap -- the contents of the two screens self.screen_state[screen] = self.screen_state[screen_other] self.screen_state[screen_other] = state_cur desktop.screen_map[page_idx] = screen self.signals:emit_signal("desktop:view", screen, desktop_idx) if state_cur then self.desktops[state_cur.desktop_idx].screen_map[state_cur.page_idx] = screen_other self.signals:emit_signal("desktop:view", screen_other, state_cur.desktop_idx) end else -- mark previous page as free if state_cur then self.desktops[state_cur.desktop_idx].screen_map[state_cur.page_idx] = nil self.desktops[state_cur.desktop_idx].indices_free:push(state_cur.page_idx) end desktop.screen_map[page_idx] = screen self.screen_state[screen] = { page_idx = page_idx, desktop_idx = desktop_idx } self.signals:emit_signal("desktop:view", screen, desktop_idx) end self:_apply_state() end function Workspace:view_relative(offset, screen) screen = screen or mouse.screen print("view relative " .. offset .. " on " .. screen.index) local state = self.screen_state[screen] if state then local desk = state.desktop_idx print("state " .. state.page_idx .. " res " .. (state.page_idx + offset) % 10) local page = 1 + ((state.page_idx - 1 + offset) % #self.desktops[desk].pages) print("desk " .. desk .. " " .. #self.desktops[desk].pages) print("view relative switch to " .. page) self:view(screen, desk, page) end end function Workspace:move_client(client, desk, page) print("move to " .. desk .. "/" .. page) local dst_page = self.desktops[desk].pages[page] local dst_screen = awful.tag.getscreen(dst_page) client:move_to_screen(dst_screen) awful.client.movetotag(dst_page, client) end function Workspace:new(layouts) local o = setmetatable({}, self) self.__index = self o.desktops = {} o.screen_state = {} o.layouts = layouts o.signals = object() return o end M.Workspace = Workspace return M