fix(mango): use dwl-ipc selected output for preferredInteractiveOutput

This commit is contained in:
Ly-sec
2026-05-10 13:17:42 +02:00
parent edce19bb80
commit 41ef475a7c
5 changed files with 50 additions and 3 deletions
+8
View File
@@ -323,6 +323,14 @@ void CompositorPlatform::setCursorShape(std::uint32_t serial, std::uint32_t shap
}
wl_output* CompositorPlatform::preferredInteractiveOutput(std::chrono::milliseconds pointerMaxAge) const {
// Mango/dwl: zdwl_ipc_output_v2.active (committed on frame) tracks the compositor-selected monitor, which
// follows the cursor even when keyboard focus stays on a client in another tag/output.
if (compositors::detect() == compositors::CompositorKind::Mango && m_workspaces != nullptr) {
if (wl_output* ipc = m_workspaces->dwlIpcSelectedOutput(); ipc != nullptr) {
return ipc;
}
}
for (const auto& backend : m_focusedOutputBackends) {
if (backend == nullptr) {
continue;
@@ -193,7 +193,10 @@ void MangoWorkspaceBackend::onOutputActive(zdwl_ipc_output_v2* handle, std::uint
}
auto state = m_outputs.find(it->second);
if (state != m_outputs.end()) {
state->second.active = active != 0;
// Double-buffer like noctalia-qs: dwl commits ipc state on frame; applying active immediately can leave
// multiple outputs marked active if the compositor updates selection across outputs in one dispatch.
state->second.hasPendingIpcActive = true;
state->second.pendingIpcActive = active != 0;
}
}
@@ -237,8 +240,20 @@ void MangoWorkspaceBackend::onOutputFrame(zdwl_ipc_output_v2* handle) {
if (it != m_outputByHandle.end()) {
const auto stateIt = m_outputs.find(it->second);
if (stateIt != m_outputs.end()) {
kLog.debug("frame output={} total_tags={} snapshot={}", static_cast<const void*>(stateIt->second.output),
m_tagCount, summarizeTags(stateIt->second));
auto& st = stateIt->second;
if (st.hasPendingIpcActive) {
if (st.pendingIpcActive) {
for (auto& [_, other] : m_outputs) {
other.active = false;
}
st.active = true;
} else {
st.active = false;
}
st.hasPendingIpcActive = false;
}
kLog.debug("frame output={} total_tags={} snapshot={}", static_cast<const void*>(st.output), m_tagCount,
summarizeTags(st));
}
}
notifyChanged();
@@ -345,3 +360,12 @@ void MangoWorkspaceBackend::notifyChanged() {
m_changeCallback();
}
}
wl_output* MangoWorkspaceBackend::ipcSelectedOutput() const {
for (const auto& [_, state] : m_outputs) {
if (state.active) {
return state.output;
}
}
return nullptr;
}
@@ -36,6 +36,9 @@ public:
std::uint32_t focused);
void onOutputFrame(zdwl_ipc_output_v2* handle);
/// zdwl_ipc_output_v2.active after frame application — the compositor-selected monitor (cursor output).
[[nodiscard]] wl_output* ipcSelectedOutput() const;
private:
struct TagInfo {
bool active = false;
@@ -47,6 +50,8 @@ private:
wl_output* output = nullptr;
zdwl_ipc_output_v2* handle = nullptr;
bool active = false;
bool pendingIpcActive = false;
bool hasPendingIpcActive = false;
std::vector<TagInfo> tags;
};
+7
View File
@@ -211,6 +211,13 @@ std::vector<Workspace> WaylandWorkspaces::forOutput(wl_output* output) const {
return m_activeBackend != nullptr ? m_activeBackend->forOutput(output) : std::vector<Workspace>{};
}
wl_output* WaylandWorkspaces::dwlIpcSelectedOutput() const {
if (m_dwlIpcBackend == nullptr || !m_dwlIpcBackend->isAvailable()) {
return nullptr;
}
return static_cast<MangoWorkspaceBackend*>(m_dwlIpcBackend)->ipcSelectedOutput();
}
void WaylandWorkspaces::setActiveBackend(WorkspaceBackend* backend) {
m_activeBackend = backend;
kLog.info("workspace backend={}", backendName());
+3
View File
@@ -42,6 +42,9 @@ public:
[[nodiscard]] std::vector<Workspace> all() const;
[[nodiscard]] std::vector<Workspace> forOutput(wl_output* output) const;
/// dwl-ipc selected output (zdwl active bit), or nullptr if ipc is not bound or no output is active yet.
[[nodiscard]] wl_output* dwlIpcSelectedOutput() const;
private:
void setActiveBackend(WorkspaceBackend* backend);
void notifyChanged() const;