From 0ded3ecd3bb65b37602e2ad06d657b47dd3025e7 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 13 Jun 2020 10:30:56 +0200 Subject: workspace: avoid unnecessary page stealing When switching to a different desktop, the current code would use the last-used tag even if it is currently displayed. Instead, keep a per-desktop stack of free tags and pick the first of those. --- workspace.lua | 129 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 65 insertions(+), 64 deletions(-) (limited to 'workspace.lua') diff --git a/workspace.lua b/workspace.lua index 768293f..bd16161 100644 --- a/workspace.lua +++ b/workspace.lua @@ -2,39 +2,23 @@ local M = {} local awful = require("awful") local object = require("gears.object") +local stack = require("stack") local Workspace = {} -local function desktop_show(self, screen, page_idx) - if page_idx == nil then - local page_hist = self.page_history[screen] - if page_hist ~= nil then - page_idx = page_hist - else - page_idx = 1 - end - end - - local page = self.pages[page_idx] - - if page then - self.page_history[screen] = page_idx - end - return page_idx -end - 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 - -- page_history[i] is the last page viewed on screen i - desk.page_history = {} + desk.screen_map = {} self.desktops[idx] = desk return idx @@ -53,17 +37,17 @@ function Workspace:_apply_state() if self.screen_state[s] then awful.tag.viewnone(s) - local desk = self.screen_state[s].desktop - local page = self.desktops[desk].pages[self.screen_state[s].page] + 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 + local desk_idx = state.desktop_idx local desk = self.desktops[desk_idx] - local page_idx = state.page + local page_idx = state.page_idx local page = desk.pages[page_idx] print("workspace displaying: " .. s.index .. " => " .. desk_idx .. "/" .. page_idx) @@ -76,54 +60,71 @@ function Workspace:_apply_state() awful.screen.focus(orig_focus) end -function Workspace:view(screen, desktop, page_idx) - if self.desktops[desktop] == nil then - print("Adding desktop " .. desktop) - self:add_desktop(desktop, "Desktop " .. desktop, 10) - end - print("workspace: " .. screen.index .. ": view " .. desktop .. "/" .. (page_idx or "nil")) - -- the page currently displayed on the target screen - local old = {} - if self.screen_state[screen] then - old.desk = self.screen_state[screen].desktop - old.page_idx = self.screen_state[screen].page - old.page = self.desktops[old.desk].pages[page_old_idx] - print(screen.index .. " now showing " .. old.desk .. "/" .. old.page_idx) - end +function Workspace:view(screen, desktop_idx, page_idx) + print("workspace: " .. screen.index .. ": view " .. desktop_idx .. "/" .. (page_idx or "nil")) - -- the page to display on the target screen - page_idx = desktop_show(self.desktops[desktop], screen, page_idx) - local page_new = nil - if page_idx then - page_new = self.desktops[desktop].pages[page_idx] + 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_cur = nil - if page_new and page_new.selected then - screen_cur = page_new.screen - print("page " .. page_idx .. " now displayed on " .. screen_cur.index) - end + local screen_other = nil - if old.page ~= page_new or page_new == nil then - self.screen_state[screen] = { page = page_idx, desktop = desktop } - if desktop ~= old.desk then - self.signals:emit_signal("desktop:view", screen, desktop) + 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 - if screen_cur then - local desk_prev = self.screen_state[screen_cur].desktop - old.page_idx = desktop_show(self.desktops[old.desk], screen_cur, old.page_idx) - - self.screen_state[screen_cur] = { page = old.page_idx, desktop = old.desk } - if desk_prev ~= old.desk then - self.signals:emit_signal("desktop:view", screen_cur, old.desk) - 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 - self:_apply_state() + 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) @@ -132,9 +133,9 @@ function Workspace:view_relative(offset, screen) local state = self.screen_state[screen] if state then - local desk = state.desktop - print("state " .. state.page .. " res " .. (state.page + offset) % 10) - local page = 1 + ((state.page - 1 + offset) % #self.desktops[desk].pages) + 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) -- cgit v1.2.3