windows: honor xdg_toplevel_set_fullscreen output hint (#8965)

Co-authored-by: Dardo D Kleiner <dardo.kleiner@nrl.navy.mil>
This commit is contained in:
Dardo D Kleiner 2025-01-09 17:38:38 -05:00 committed by GitHub
parent 9dc9366fc6
commit f9c37ca43b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 55 additions and 10 deletions

View file

@ -1382,15 +1382,26 @@ void CWindow::activate(bool force) {
} }
void CWindow::onUpdateState() { void CWindow::onUpdateState() {
std::optional<bool> requestsFS = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreen : m_pXWaylandSurface->state.requestsFullscreen; std::optional<bool> requestsFS = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreen : m_pXWaylandSurface->state.requestsFullscreen;
std::optional<bool> requestsMX = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsMaximize : m_pXWaylandSurface->state.requestsMaximize; std::optional<MONITORID> requestsID = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreenMonitor : MONITOR_INVALID;
std::optional<bool> requestsMX = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsMaximize : m_pXWaylandSurface->state.requestsMaximize;
if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) { if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) {
bool fs = requestsFS.value(); if (requestsID.has_value() && (requestsID.value() != MONITOR_INVALID) && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN_OUTPUT)) {
if (m_bIsMapped) { if (m_bIsMapped) {
g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_FULLSCREEN, requestsFS.value()); const auto monitor = g_pCompositor->getMonitorFromID(requestsID.value());
g_pCompositor->moveWindowToWorkspaceSafe(m_pSelf.lock(), monitor->activeWorkspace);
g_pCompositor->setActiveMonitor(monitor);
}
if (!m_bIsMapped)
m_iWantsInitialFullscreenMonitor = requestsID.value();
} }
bool fs = requestsFS.value();
if (m_bIsMapped)
g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_FULLSCREEN, requestsFS.value());
if (!m_bIsMapped) if (!m_bIsMapped)
m_bWantsInitialFullscreen = fs; m_bWantsInitialFullscreen = fs;
} }

View file

@ -57,6 +57,7 @@ enum eSuppressEvents : uint8_t {
SUPPRESS_MAXIMIZE = 1 << 1, SUPPRESS_MAXIMIZE = 1 << 1,
SUPPRESS_ACTIVATE = 1 << 2, SUPPRESS_ACTIVATE = 1 << 2,
SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3, SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3,
SUPPRESS_FULLSCREEN_OUTPUT = 1 << 4,
}; };
class IWindowTransformer; class IWindowTransformer;
@ -288,7 +289,8 @@ class CWindow {
bool m_bNoInitialFocus = false; bool m_bNoInitialFocus = false;
// Fullscreen and Maximize // Fullscreen and Maximize
bool m_bWantsInitialFullscreen = false; bool m_bWantsInitialFullscreen = false;
MONITORID m_iWantsInitialFullscreenMonitor = MONITOR_INVALID;
// bitfield eSuppressEvents // bitfield eSuppressEvents
uint64_t m_eSuppressedEvents = SUPPRESS_NONE; uint64_t m_eSuppressedEvents = SUPPRESS_NONE;

View file

@ -131,6 +131,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
std::optional<SFullscreenState> requestedFSState; std::optional<SFullscreenState> requestedFSState;
if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen)) if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen))
requestedClientFSMode = FSMODE_FULLSCREEN; requestedClientFSMode = FSMODE_FULLSCREEN;
MONITORID requestedFSMonitor = PWINDOW->m_iWantsInitialFullscreenMonitor;
for (auto const& r : PWINDOW->m_vMatchedRules) { for (auto const& r : PWINDOW->m_vMatchedRules) {
switch (r->ruleType) { switch (r->ruleType) {
@ -168,6 +169,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWORKSPACE = PWINDOW->m_pWorkspace; PWORKSPACE = PWINDOW->m_pWorkspace;
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW); Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
requestedFSMonitor = MONITOR_INVALID;
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r->szRule, r->szValue, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r->szRule, r->szValue, e.what()); }
break; break;
} }
@ -186,6 +188,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
requestedWorkspace = ""; requestedWorkspace = "";
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r->szValue); Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r->szValue);
requestedFSMonitor = MONITOR_INVALID;
break; break;
} }
case CWindowRule::RULE_FLOAT: { case CWindowRule::RULE_FLOAT: {
@ -227,6 +230,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE; PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE;
else if (vars[i] == "activatefocus") else if (vars[i] == "activatefocus")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY; PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY;
else if (vars[i] == "fullscreenoutput")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN_OUTPUT;
else else
Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]); Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
} }
@ -337,10 +342,30 @@ void Events::listener_mapWindow(void* owner, void* data) {
PMONITOR = g_pCompositor->m_pLastMonitor.lock(); PMONITOR = g_pCompositor->m_pLastMonitor.lock();
} }
requestedFSMonitor = MONITOR_INVALID;
} else } else
workspaceSilent = false; workspaceSilent = false;
} }
if (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN_OUTPUT)
requestedFSMonitor = MONITOR_INVALID;
else if (requestedFSMonitor != MONITOR_INVALID) {
if (const auto PM = g_pCompositor->getMonitorFromID(requestedFSMonitor); PM)
PWINDOW->m_pMonitor = PM;
const auto PMONITORFROMID = PWINDOW->m_pMonitor.lock();
if (PWINDOW->m_pMonitor != PMONITOR) {
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID()));
PMONITOR = PMONITORFROMID;
}
PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
PWORKSPACE = PWINDOW->m_pWorkspace;
Debug::log(LOG, "Requested monitor, applying to {:mw}", PWINDOW);
}
if (PWORKSPACE->m_bDefaultFloating) if (PWORKSPACE->m_bDefaultFloating)
PWINDOW->m_bIsFloating = true; PWINDOW->m_bIsFloating = true;

View file

@ -5,6 +5,7 @@
#include "../managers/SeatManager.hpp" #include "../managers/SeatManager.hpp"
#include "core/Seat.hpp" #include "core/Seat.hpp"
#include "core/Compositor.hpp" #include "core/Compositor.hpp"
#include "protocols/core/Output.hpp"
#include <cstring> #include <cstring>
#include <ranges> #include <ranges>
@ -191,9 +192,14 @@ CXDGToplevelResource::CXDGToplevelResource(SP<CXdgToplevel> resource_, SP<CXDGSu
}); });
resource->setSetFullscreen([this](CXdgToplevel* r, wl_resource* output) { resource->setSetFullscreen([this](CXdgToplevel* r, wl_resource* output) {
if (output)
if (const auto PM = CWLOutputResource::fromResource(output)->monitor; PM)
state.requestsFullscreenMonitor = PM->ID;
state.requestsFullscreen = true; state.requestsFullscreen = true;
events.stateChanged.emit(); events.stateChanged.emit();
state.requestsFullscreen.reset(); state.requestsFullscreen.reset();
state.requestsFullscreenMonitor.reset();
}); });
resource->setUnsetFullscreen([this](CXdgToplevel* r) { resource->setUnsetFullscreen([this](CXdgToplevel* r) {
@ -205,7 +211,7 @@ CXDGToplevelResource::CXDGToplevelResource(SP<CXdgToplevel> resource_, SP<CXDGSu
resource->setSetMinimized([this](CXdgToplevel* r) { resource->setSetMinimized([this](CXdgToplevel* r) {
state.requestsMinimize = true; state.requestsMinimize = true;
events.stateChanged.emit(); events.stateChanged.emit();
state.requestsFullscreen.reset(); state.requestsMinimize.reset();
}); });
resource->setSetParent([this](CXdgToplevel* r, wl_resource* parentR) { resource->setSetParent([this](CXdgToplevel* r, wl_resource* parentR) {

View file

@ -123,9 +123,10 @@ class CXDGToplevelResource {
std::string appid; std::string appid;
// volatile state: is reset after the stateChanged signal fires // volatile state: is reset after the stateChanged signal fires
std::optional<bool> requestsMaximize; std::optional<bool> requestsMaximize;
std::optional<bool> requestsFullscreen; std::optional<bool> requestsFullscreen;
std::optional<bool> requestsMinimize; std::optional<MONITORID> requestsFullscreenMonitor;
std::optional<bool> requestsMinimize;
} state; } state;
struct { struct {