mirror of
https://github.com/hyprwm/Hyprland
synced 2026-05-07 11:58:02 +02:00
xdg-shell: queue state updates for toplevel (#14227)
ref https://github.com/hyprwm/Hyprland/discussions/14224
This commit is contained in:
parent
cfb2deb664
commit
450d8a0bf7
4 changed files with 93 additions and 38 deletions
|
|
@ -16,6 +16,17 @@ using namespace Hyprutils::OS;
|
|||
|
||||
#define TIMESPEC_NSEC_PER_SEC 1000000000L
|
||||
|
||||
static uint64_t LAST_DO_LATER_SEQ = 1;
|
||||
|
||||
SEventLoopDoLaterLock::SEventLoopDoLaterLock(uint64_t seq_) : seq(seq_) {
|
||||
;
|
||||
}
|
||||
|
||||
SEventLoopDoLaterLock::~SEventLoopDoLaterLock() {
|
||||
if (g_pEventLoopManager && seq > 0)
|
||||
g_pEventLoopManager->removeDoLater(seq);
|
||||
}
|
||||
|
||||
CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) {
|
||||
m_timers.timerfd = CFileDescriptor{timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC)};
|
||||
m_wayland.loop = wlEventLoop;
|
||||
|
|
@ -201,11 +212,13 @@ void CEventLoopManager::nudgeTimers() {
|
|||
timerfd_settime(m_timers.timerfd.get(), TFD_TIMER_ABSTIME, &ts, nullptr);
|
||||
}
|
||||
|
||||
void CEventLoopManager::doLater(const std::function<void()>& fn) {
|
||||
m_idle.fns.emplace_back(fn);
|
||||
uint64_t CEventLoopManager::doLater(const std::function<void()>& fn) {
|
||||
const uint64_t NEW_SEQ = ++LAST_DO_LATER_SEQ;
|
||||
|
||||
m_idle.fns.emplace_back(std::make_pair<>(NEW_SEQ, fn));
|
||||
|
||||
if (m_idle.eventSource)
|
||||
return;
|
||||
return NEW_SEQ;
|
||||
|
||||
m_idle.eventSource = wl_event_loop_add_idle(
|
||||
m_wayland.loop,
|
||||
|
|
@ -215,11 +228,26 @@ void CEventLoopManager::doLater(const std::function<void()>& fn) {
|
|||
IDLE->fns.clear();
|
||||
IDLE->eventSource = nullptr;
|
||||
for (auto& f : fns) {
|
||||
if (f)
|
||||
f();
|
||||
if (f.second)
|
||||
f.second();
|
||||
}
|
||||
},
|
||||
&m_idle);
|
||||
|
||||
return NEW_SEQ;
|
||||
}
|
||||
|
||||
void CEventLoopManager::removeDoLater(uint64_t seq) {
|
||||
std::erase_if(m_idle.fns, [&seq](const auto& e) { return e.first == seq; });
|
||||
|
||||
if (m_idle.fns.empty() && m_idle.eventSource) {
|
||||
wl_event_source_remove(m_idle.eventSource);
|
||||
m_idle.eventSource = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
UP<SEventLoopDoLaterLock> CEventLoopManager::doLaterLock(const std::function<void()>& fn) {
|
||||
return makeUnique<SEventLoopDoLaterLock>(doLater(fn));
|
||||
}
|
||||
|
||||
void CEventLoopManager::doOnReadable(CFileDescriptor fd, std::function<void()>&& fn) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,13 @@ namespace Aquamarine {
|
|||
struct SPollFD;
|
||||
};
|
||||
|
||||
struct SEventLoopDoLaterLock {
|
||||
SEventLoopDoLaterLock(uint64_t seq);
|
||||
~SEventLoopDoLaterLock();
|
||||
|
||||
uint64_t seq = 0;
|
||||
};
|
||||
|
||||
class CEventLoopManager {
|
||||
public:
|
||||
CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop);
|
||||
|
|
@ -30,12 +37,16 @@ class CEventLoopManager {
|
|||
// schedules a recalc of the timers
|
||||
void scheduleRecalc();
|
||||
|
||||
// schedules a function to run later, aka in a wayland idle event.
|
||||
void doLater(const std::function<void()>& fn);
|
||||
// schedules a function to run later, aka in a wayland idle event. Returns a sequence which can be used to remove it.
|
||||
uint64_t doLater(const std::function<void()>& fn);
|
||||
void removeDoLater(uint64_t seq);
|
||||
|
||||
// automatically cleaned up doLater instance
|
||||
[[nodiscard]] UP<SEventLoopDoLaterLock> doLaterLock(const std::function<void()>& fn);
|
||||
|
||||
struct SIdleData {
|
||||
wl_event_source* eventSource = nullptr;
|
||||
std::vector<std::function<void()>> fns;
|
||||
wl_event_source* eventSource = nullptr;
|
||||
std::vector<std::pair<uint64_t, std::function<void()>>> fns;
|
||||
};
|
||||
|
||||
struct SReadableWaiter {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "../Compositor.hpp"
|
||||
#include "../managers/SeatManager.hpp"
|
||||
#include "../managers/ANRManager.hpp"
|
||||
#include "../managers/eventLoop/EventLoopManager.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "core/Seat.hpp"
|
||||
#include "core/Compositor.hpp"
|
||||
|
|
@ -286,7 +287,7 @@ bool CXDGToplevelResource::anyChildModal() {
|
|||
|
||||
uint32_t CXDGToplevelResource::setSize(const Vector2D& size) {
|
||||
m_pendingApply.size = size;
|
||||
applyState();
|
||||
scheduleStateApplication();
|
||||
return m_owner->scheduleConfigure();
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +301,9 @@ uint32_t CXDGToplevelResource::setMaximized(bool maximized) {
|
|||
m_pendingApply.states.push_back(XDG_TOPLEVEL_STATE_MAXIMIZED);
|
||||
else if (!maximized && set)
|
||||
std::erase(m_pendingApply.states, XDG_TOPLEVEL_STATE_MAXIMIZED);
|
||||
applyState();
|
||||
|
||||
scheduleStateApplication();
|
||||
|
||||
return m_owner->scheduleConfigure();
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +317,9 @@ uint32_t CXDGToplevelResource::setFullscreen(bool fullscreen) {
|
|||
m_pendingApply.states.push_back(XDG_TOPLEVEL_STATE_FULLSCREEN);
|
||||
else if (!fullscreen && set)
|
||||
std::erase(m_pendingApply.states, XDG_TOPLEVEL_STATE_FULLSCREEN);
|
||||
applyState();
|
||||
|
||||
scheduleStateApplication();
|
||||
|
||||
return m_owner->scheduleConfigure();
|
||||
}
|
||||
|
||||
|
|
@ -328,7 +333,9 @@ uint32_t CXDGToplevelResource::setActive(bool active) {
|
|||
m_pendingApply.states.push_back(XDG_TOPLEVEL_STATE_ACTIVATED);
|
||||
else if (!active && set)
|
||||
std::erase(m_pendingApply.states, XDG_TOPLEVEL_STATE_ACTIVATED);
|
||||
applyState();
|
||||
|
||||
scheduleStateApplication();
|
||||
|
||||
return m_owner->scheduleConfigure();
|
||||
}
|
||||
|
||||
|
|
@ -345,22 +352,32 @@ uint32_t CXDGToplevelResource::setSuspeneded(bool sus) {
|
|||
m_pendingApply.states.push_back(XDG_TOPLEVEL_STATE_SUSPENDED);
|
||||
else if (!sus && set)
|
||||
std::erase(m_pendingApply.states, XDG_TOPLEVEL_STATE_SUSPENDED);
|
||||
applyState();
|
||||
|
||||
scheduleStateApplication();
|
||||
|
||||
return m_owner->scheduleConfigure();
|
||||
}
|
||||
|
||||
void CXDGToplevelResource::applyState() {
|
||||
wl_array arr;
|
||||
wl_array_init(&arr);
|
||||
void CXDGToplevelResource::scheduleStateApplication() {
|
||||
|
||||
if (!m_pendingApply.states.empty()) {
|
||||
wl_array_add(&arr, m_pendingApply.states.size() * sizeof(int));
|
||||
memcpy(arr.data, m_pendingApply.states.data(), m_pendingApply.states.size() * sizeof(int));
|
||||
}
|
||||
if (m_stateUpdate)
|
||||
return;
|
||||
|
||||
m_resource->sendConfigure(m_pendingApply.size.x, m_pendingApply.size.y, &arr);
|
||||
m_stateUpdate = g_pEventLoopManager->doLaterLock([this] {
|
||||
wl_array arr;
|
||||
wl_array_init(&arr);
|
||||
|
||||
wl_array_release(&arr);
|
||||
if (!m_pendingApply.states.empty()) {
|
||||
wl_array_add(&arr, m_pendingApply.states.size() * sizeof(int));
|
||||
memcpy(arr.data, m_pendingApply.states.data(), m_pendingApply.states.size() * sizeof(int));
|
||||
}
|
||||
|
||||
m_resource->sendConfigure(m_pendingApply.size.x, m_pendingApply.size.y, &arr);
|
||||
|
||||
wl_array_release(&arr);
|
||||
|
||||
m_stateUpdate.reset();
|
||||
});
|
||||
}
|
||||
|
||||
void CXDGToplevelResource::close() {
|
||||
|
|
@ -516,8 +533,6 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas
|
|||
|
||||
CXDGSurfaceResource::~CXDGSurfaceResource() {
|
||||
m_events.destroy.emit();
|
||||
if (m_configureSource)
|
||||
wl_event_source_remove(m_configureSource);
|
||||
if (m_surface)
|
||||
m_surface->resetRole();
|
||||
}
|
||||
|
|
@ -531,22 +546,19 @@ SP<CXDGSurfaceResource> CXDGSurfaceResource::fromResource(wl_resource* res) {
|
|||
return data ? data->m_self.lock() : nullptr;
|
||||
}
|
||||
|
||||
static void onConfigure(void* data) {
|
||||
sc<CXDGSurfaceResource*>(data)->configure();
|
||||
}
|
||||
|
||||
uint32_t CXDGSurfaceResource::scheduleConfigure() {
|
||||
if (m_configureSource)
|
||||
if (m_stateUpdate)
|
||||
return m_scheduledSerial;
|
||||
|
||||
m_configureSource = wl_event_loop_add_idle(g_pCompositor->m_wlEventLoop, onConfigure, this);
|
||||
m_stateUpdate = g_pEventLoopManager->doLaterLock([this] { configure(); });
|
||||
|
||||
m_scheduledSerial = wl_display_next_serial(g_pCompositor->m_wlDisplay);
|
||||
|
||||
return m_scheduledSerial;
|
||||
}
|
||||
|
||||
void CXDGSurfaceResource::configure() {
|
||||
m_configureSource = nullptr;
|
||||
m_stateUpdate.reset();
|
||||
m_resource->sendConfigure(m_scheduledSerial);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class CXDGPopupResource;
|
|||
class CSeatGrab;
|
||||
class CWLSurfaceResource;
|
||||
class CXDGDialogV1Resource;
|
||||
struct SEventLoopDoLaterLock;
|
||||
|
||||
struct SXDGPositionerState {
|
||||
Vector2D requestedSize;
|
||||
|
|
@ -149,8 +150,11 @@ class CXDGToplevelResource {
|
|||
std::vector<WP<CXDGToplevelResource>> m_children;
|
||||
|
||||
private:
|
||||
SP<CXdgToplevel> m_resource;
|
||||
void applyState();
|
||||
SP<CXdgToplevel> m_resource;
|
||||
|
||||
UP<SEventLoopDoLaterLock> m_stateUpdate;
|
||||
|
||||
void scheduleStateApplication();
|
||||
};
|
||||
|
||||
class CXDGSurfaceRole : public ISurfaceRole {
|
||||
|
|
@ -202,12 +206,12 @@ class CXDGSurfaceResource {
|
|||
void configure();
|
||||
|
||||
private:
|
||||
SP<CXdgSurface> m_resource;
|
||||
SP<CXdgSurface> m_resource;
|
||||
|
||||
uint32_t m_lastConfigureSerial = 0;
|
||||
uint32_t m_scheduledSerial = 0;
|
||||
UP<SEventLoopDoLaterLock> m_stateUpdate;
|
||||
|
||||
wl_event_source* m_configureSource = nullptr;
|
||||
uint32_t m_lastConfigureSerial = 0;
|
||||
uint32_t m_scheduledSerial = 0;
|
||||
|
||||
//
|
||||
std::vector<WP<CXDGPopupResource>> m_popups;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue