protocols/outputMgmt: fix wlr-randr by defering success event until monitor reloads (#12236)

wlr-randr disconnects immediately after receiving success event, but
before applying the monitor configuration. This causes the state to be
lost when performMonitorReload() is called.

By postponing the success event until the call of the hook
monitorLayoutChanged we ensure the configuration to remain valid during
the reload process.
This commit is contained in:
nikromen 2025-11-09 00:45:53 +01:00 committed by GitHub
parent 522edc8712
commit 06b37c3907
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 30 additions and 2 deletions

View file

@ -28,6 +28,8 @@ COutputManager::COutputManager(SP<CZwlrOutputManagerV1> resource_) : m_resource(
PROTO::outputManagement->m_configurations.pop_back();
return;
}
RESOURCE->m_self = RESOURCE;
});
// send all heads at start
@ -335,7 +337,7 @@ COutputConfiguration::COutputConfiguration(SP<CZwlrOutputConfigurationV1> resour
const auto SUCCESS = applyTestConfiguration(false);
if (SUCCESS)
m_resource->sendSucceeded();
PROTO::outputManagement->m_pendingConfigurationSuccessEvents.emplace_back(m_self);
else
m_resource->sendFailed();
@ -576,7 +578,10 @@ bool COutputConfigurationHead::good() {
}
COutputManagementProtocol::COutputManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
static auto P = g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); });
static auto P = g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) {
updateAllOutputs();
sendPendingSuccessEvents();
});
}
void COutputManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
@ -647,3 +652,19 @@ SP<SWlrManagerSavedOutputState> COutputManagementProtocol::getOutputStateFor(PHL
return nullptr;
}
void COutputManagementProtocol::sendPendingSuccessEvents() {
if (m_pendingConfigurationSuccessEvents.empty())
return;
LOGM(LOG, "Sending {} pending configuration success events", m_pendingConfigurationSuccessEvents.size());
for (auto const& config : m_pendingConfigurationSuccessEvents) {
if (!config)
continue;
config->m_resource->sendSucceeded();
}
m_pendingConfigurationSuccessEvents.clear();
}

View file

@ -141,8 +141,12 @@ class COutputConfiguration {
SP<CZwlrOutputConfigurationV1> m_resource;
std::vector<WP<COutputConfigurationHead>> m_heads;
WP<COutputManager> m_owner;
WP<COutputConfiguration> m_self;
bool applyTestConfiguration(bool test);
friend class COutputManagementProtocol;
friend class COutputManager;
};
class COutputManagementProtocol : public IWaylandProtocol {
@ -154,6 +158,8 @@ class COutputManagementProtocol : public IWaylandProtocol {
// doesn't have to return one
SP<SWlrManagerSavedOutputState> getOutputStateFor(PHLMONITOR pMonitor);
void sendPendingSuccessEvents();
private:
void destroyResource(COutputManager* resource);
void destroyResource(COutputHead* resource);
@ -169,6 +175,7 @@ class COutputManagementProtocol : public IWaylandProtocol {
std::vector<SP<COutputMode>> m_modes;
std::vector<SP<COutputConfiguration>> m_configurations;
std::vector<SP<COutputConfigurationHead>> m_configurationHeads;
std::vector<WP<COutputConfiguration>> m_pendingConfigurationSuccessEvents;
SP<COutputHead> headFromResource(wl_resource* r);
SP<COutputMode> modeFromResource(wl_resource* r);