local M = {} local awful = require("awful") local object = require("gears.object") local stack = require("stack") local timer = require("gears.timer") local Workspace = {} local function desk_find_empty_page(desk) for i, page in ipairs(desk.pages) do if #page:clients() == 0 then return i end end return nil end function Workspace:_add_desktop(idx, name, nb_pages) local desk = object() desk.name = name desk.idx = idx desk.pages = {} desk.indices_free = stack.Stack:new() for i = 1, nb_pages do desk.pages[i] = awful.tag.add(string.format("%02x%02x", idx, i), { layout = self.layouts[1] }) desk.indices_free:push(i) end desk.screen_map = {} desk.find_empty_page = desk_find_empty_page 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] page:view_only() desk:emit_signal("page:view", s, page_idx) end end timer.delayed_call(awful.screen.focus, orig_focus) end function Workspace:view(screen, desktop_idx, page_idx) 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 local desk = self.desktops[state_cur.desktop_idx] desk.screen_map[state_cur.page_idx] = nil desk.indices_free:push(state_cur.page_idx) desk:emit_signal("page:hide", 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 local state = self.screen_state[screen] if state then local desk = state.desktop_idx local page = 1 + ((state.page_idx - 1 + offset) % #self.desktops[desk].pages) self:view(screen, desk, page) end end function Workspace:move_client(client, 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:client_move_relative(client, offset) -- FIXME this is wrong, mouse screen is not necessarily -- where the client is local state = self.screen_state[mouse.screen] if state then local desk = state.desktop_idx local page = 1 + ((state.page_idx - 1 + offset) % #self.desktops[desk].pages) self:move_client(client, desk, page) end end function Workspace:new(layouts) local o = setmetatable({}, self) self.__index = self o.desktops = {} o.screen_state = {} o.layouts = layouts o.signals = object() for i = 1, 12 do o:_add_desktop(i, "Desktop " .. i, 10) end return o end M.Workspace = Workspace return M