protocols: add ext-workspace implementation (#10818)

This commit is contained in:
outfoxxed
2025-06-26 09:32:44 -07:00
committed by GitHub
parent 1f337a7a5e
commit 3bbdf9dc5a
11 changed files with 510 additions and 22 deletions

View File

@@ -377,6 +377,7 @@ protocolnew("staging/content-type" "content-type-v1" false)
protocolnew("staging/color-management" "color-management-v1" false)
protocolnew("staging/xdg-toplevel-tag" "xdg-toplevel-tag-v1" false)
protocolnew("staging/xdg-system-bell" "xdg-system-bell-v1" false)
protocolnew("staging/ext-workspace" "ext-workspace-v1" false)
protocolwayland()

View File

@@ -75,6 +75,7 @@ protocols = [
wayland_protocol_dir / 'staging/color-management/color-management-v1.xml',
wayland_protocol_dir / 'staging/xdg-toplevel-tag/xdg-toplevel-tag-v1.xml',
wayland_protocol_dir / 'staging/xdg-system-bell/xdg-system-bell-v1.xml',
wayland_protocol_dir / 'staging/ext-workspace/ext-workspace-v1.xml',
]
wl_protocols = []

View File

@@ -1972,7 +1972,7 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor
const auto PWORKSPACEB = pMonitorB->m_activeWorkspace;
PWORKSPACEA->m_monitor = pMonitorB;
PWORKSPACEA->moveToMonitor(pMonitorB->m_id);
PWORKSPACEA->m_events.monitorChange.emit();
for (auto const& w : m_windows) {
if (w->m_workspace == PWORKSPACEA) {
@@ -1997,7 +1997,7 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor
}
PWORKSPACEB->m_monitor = pMonitorA;
PWORKSPACEB->moveToMonitor(pMonitorA->m_id);
PWORKSPACEB->m_events.monitorChange.emit();
for (auto const& w : m_windows) {
if (w->m_workspace == PWORKSPACEB) {
@@ -2177,7 +2177,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo
// move the workspace
pWorkspace->m_monitor = pMonitor;
pWorkspace->moveToMonitor(pMonitor->m_id);
pWorkspace->m_events.monitorChange.emit();
for (auto const& w : m_windows) {
if (w->m_workspace == pWorkspace) {
@@ -2221,7 +2221,15 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo
pMonitor->setSpecialWorkspace(nullptr);
setActiveMonitor(pMonitor);
auto oldWorkspace = pMonitor->m_activeWorkspace;
pMonitor->m_activeWorkspace = pWorkspace;
if (oldWorkspace)
oldWorkspace->m_events.activeChange.emit();
pWorkspace->m_events.activeChange.emit();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->m_id);
pWorkspace->startAnim(true, true, true);

View File

@@ -70,6 +70,8 @@ CWorkspace::~CWorkspace() {
g_pEventManager->postEvent({.event = "destroyworkspacev2", .data = std::format("{},{}", m_id, m_name)});
EMIT_HOOK_EVENT("destroyWorkspace", this);
}
m_events.destroy.emit();
}
void CWorkspace::startAnim(bool in, bool left, bool instant) {
@@ -185,14 +187,6 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
}
}
void CWorkspace::setActive(bool on) {
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
}
void CWorkspace::moveToMonitor(const MONITORID& id) {
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
}
PHLWINDOW CWorkspace::getLastFocusedWindow() {
if (!validMapped(m_lastFocusedWindow) || m_lastFocusedWindow->workspaceID() != m_id)
return nullptr;
@@ -650,6 +644,7 @@ void CWorkspace::rename(const std::string& name) {
g_pCompositor->ensurePersistentWorkspacesPresent(std::vector<SWorkspaceRule>{WORKSPACERULE}, m_self.lock());
g_pEventManager->postEvent({.event = "renameworkspace", .data = std::to_string(m_id) + "," + m_name});
m_events.rename.emit();
}
void CWorkspace::updateWindows() {

View File

@@ -4,6 +4,7 @@
#include <string>
#include "DesktopTypes.hpp"
#include "../helpers/MiscFunctions.hpp"
#include "../helpers/signal/Signal.hpp"
enum eFullscreenMode : int8_t {
FSMODE_NONE = 0,
@@ -21,6 +22,8 @@ class CWorkspace {
CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true);
~CWorkspace();
WP<CWorkspace> m_self;
// Workspaces ID-based have IDs > 0
// and workspaces name-based have IDs starting with -1337
WORKSPACEID m_id = WORKSPACE_INVALID;
@@ -60,8 +63,6 @@ class CWorkspace {
// Inert: destroyed and invalid. If this is true, release the ptr you have.
bool inert();
void startAnim(bool in, bool left, bool instant = false);
void setActive(bool on);
void moveToMonitor(const MONITORID&);
MONITORID monitorID();
PHLWINDOW getLastFocusedWindow();
void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace);
@@ -83,6 +84,13 @@ class CWorkspace {
void forceReportSizesToWindows();
void updateWindows();
struct {
CSignal destroy;
CSignal rename;
CSignal monitorChange;
CSignal activeChange;
} m_events;
private:
void init(PHLWORKSPACE self);
// Previous workspace ID and name is stored during a workspace change, allowing travel
@@ -91,7 +99,6 @@ class CWorkspace {
SP<HOOK_CALLBACK_FN> m_focusedWindowHook;
bool m_inert = true;
WP<CWorkspace> m_self;
};
inline bool valid(const PHLWORKSPACE& ref) {

View File

@@ -1026,7 +1026,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
m_activeWorkspace = PNEWWORKSPACE;
PNEWWORKSPACE->setActive(true);
PNEWWORKSPACE->m_events.activeChange.emit();
PNEWWORKSPACE->m_visible = true;
PNEWWORKSPACE->m_lastMonitor = "";
}
@@ -1183,12 +1183,15 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
return;
const auto POLDWORKSPACE = m_activeWorkspace;
if (POLDWORKSPACE)
POLDWORKSPACE->m_visible = false;
pWorkspace->m_visible = true;
m_activeWorkspace = pWorkspace;
if (POLDWORKSPACE) {
POLDWORKSPACE->m_visible = false;
POLDWORKSPACE->m_events.activeChange.emit();
}
pWorkspace->m_visible = true;
if (!internal) {
const auto ANIMTOLEFT = POLDWORKSPACE && (shouldWraparound(pWorkspace->m_id, POLDWORKSPACE->m_id) ^ (pWorkspace->m_id > POLDWORKSPACE->m_id));
if (POLDWORKSPACE)
@@ -1230,6 +1233,8 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
EMIT_HOOK_EVENT("workspace", pWorkspace);
}
pWorkspace->m_events.activeChange.emit();
g_pHyprRenderer->damageMonitor(m_self.lock());
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
@@ -1250,6 +1255,8 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
if (m_activeSpecialWorkspace == pWorkspace)
return;
const auto POLDSPECIAL = m_activeSpecialWorkspace;
m_specialFade->setConfig(g_pConfigManager->getAnimationPropertyConfig(pWorkspace ? "specialWorkspaceIn" : "specialWorkspaceOut"));
*m_specialFade = pWorkspace ? 1.F : 0.F;
@@ -1265,6 +1272,9 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
}
m_activeSpecialWorkspace.reset();
if (POLDSPECIAL)
POLDSPECIAL->m_events.activeChange.emit();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_id);
if (!(g_pCompositor->m_lastWindow.lock() && g_pCompositor->m_lastWindow->m_pinned && g_pCompositor->m_lastWindow->m_monitor == m_self)) {
@@ -1288,7 +1298,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
m_activeSpecialWorkspace->startAnim(false, false);
}
bool animate = true;
bool wasActive = false;
//close if open elsewhere
const auto PMONITORWORKSPACEOWNER = pWorkspace->m_monitor.lock();
if (const auto PMWSOWNER = pWorkspace->m_monitor.lock(); PMWSOWNER && PMWSOWNER->m_activeSpecialWorkspace == pWorkspace) {
@@ -1300,14 +1310,24 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
const auto PACTIVEWORKSPACE = PMWSOWNER->m_activeWorkspace;
g_pCompositor->updateFullscreenFadeOnWorkspace(PACTIVEWORKSPACE);
animate = false;
wasActive = true;
}
// open special
pWorkspace->m_monitor = m_self;
m_activeSpecialWorkspace = pWorkspace;
m_activeSpecialWorkspace->m_visible = true;
if (animate)
if (POLDSPECIAL)
POLDSPECIAL->m_events.activeChange.emit();
if (PMONITORWORKSPACEOWNER != m_self)
pWorkspace->m_events.monitorChange.emit();
if (!wasActive)
pWorkspace->m_events.activeChange.emit();
if (!wasActive)
pWorkspace->startAnim(true, true);
for (auto const& w : g_pCompositor->m_windows) {

View File

@@ -62,6 +62,7 @@
#include "../protocols/ContentType.hpp"
#include "../protocols/XDGTag.hpp"
#include "../protocols/XDGBell.hpp"
#include "../protocols/ExtWorkspace.hpp"
#include "../helpers/Monitor.hpp"
#include "../render/Renderer.hpp"
@@ -187,6 +188,7 @@ CProtocolManager::CProtocolManager() {
PROTO::contentType = makeUnique<CContentTypeProtocol>(&wp_content_type_manager_v1_interface, 1, "ContentType");
PROTO::xdgTag = makeUnique<CXDGToplevelTagProtocol>(&xdg_toplevel_tag_manager_v1_interface, 1, "XDGTag");
PROTO::xdgBell = makeUnique<CXDGSystemBellProtocol>(&xdg_system_bell_v1_interface, 1, "XDGBell");
PROTO::extWorkspace = makeUnique<CExtWorkspaceProtocol>(&ext_workspace_manager_v1_interface, 1, "ExtWorkspace");
if (*PENABLECM)
PROTO::colorManagement = makeUnique<CColorManagementProtocol>(&wp_color_manager_v1_interface, 1, "ColorManagement", *PDEBUGCM);
@@ -283,6 +285,7 @@ CProtocolManager::~CProtocolManager() {
PROTO::frogColorManagement.reset();
PROTO::xdgTag.reset();
PROTO::xdgBell.reset();
PROTO::extWorkspace.reset();
for (auto& [_, lease] : PROTO::lease) {
lease.reset();

View File

@@ -0,0 +1,331 @@
#include "ExtWorkspace.hpp"
#include "../Compositor.hpp"
#include "../managers/HookSystemManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include <algorithm>
#include <any>
#include <utility>
#include "core/Output.hpp"
CExtWorkspaceGroupResource::CExtWorkspaceGroupResource(WP<CExtWorkspaceManagerResource> manager, UP<CExtWorkspaceGroupHandleV1> resource, PHLMONITORREF monitor) :
m_monitor(std::move(monitor)), m_manager(std::move(manager)), m_resource(std::move(resource)) {
if (!good())
return;
m_resource->setData(this);
m_manager->m_resource->sendWorkspaceGroup(m_resource.get());
m_listeners.destroyed = m_monitor->m_events.destroy.registerListener([this](auto) { m_resource->sendRemoved(); });
m_resource->setOnDestroy([this](auto) { PROTO::extWorkspace->destroyGroup(m_self); });
m_resource->setDestroy([this](auto) { PROTO::extWorkspace->destroyGroup(m_self); });
m_resource->sendCapabilities(static_cast<extWorkspaceGroupHandleV1GroupCapabilities>(0));
const auto& output = PROTO::outputs.at(m_monitor->m_name);
if (auto resource = output->outputResourceFrom(m_resource->client()))
m_resource->sendOutputEnter(resource->getResource()->resource());
m_listeners.outputBound = output->m_events.outputBound.registerListener([this](std::any data) {
auto resource = std::any_cast<SP<CWLOutputResource>>(data);
if (resource->client() == m_resource->client())
m_resource->sendOutputEnter(resource->getResource()->resource());
});
m_manager->sendGroupToWorkspaces(m_self);
m_manager->scheduleDone();
}
bool CExtWorkspaceGroupResource::good() const {
return m_resource;
}
WP<CExtWorkspaceGroupResource> CExtWorkspaceGroupResource::fromResource(wl_resource* resource) {
auto handle = static_cast<CExtWorkspaceGroupHandleV1*>(wl_resource_get_user_data(resource))->data();
auto data = static_cast<CExtWorkspaceGroupResource*>(handle);
return data ? data->m_self : WP<CExtWorkspaceGroupResource>();
}
void CExtWorkspaceGroupResource::workspaceEnter(const WP<CExtWorkspaceHandleV1>& handle) {
m_resource->sendWorkspaceEnter(handle.get());
}
void CExtWorkspaceGroupResource::workspaceLeave(const WP<CExtWorkspaceHandleV1>& handle) {
m_resource->sendWorkspaceLeave(handle.get());
}
CExtWorkspaceResource::CExtWorkspaceResource(WP<CExtWorkspaceManagerResource> manager, UP<CExtWorkspaceHandleV1> resource, PHLWORKSPACEREF workspace) :
m_manager(std::move(manager)), m_resource(std::move(resource)), m_workspace(std::move(workspace)) {
if (!good())
return;
m_resource->setData(this);
m_manager->m_resource->sendWorkspace(m_resource.get());
m_listeners.destroyed = m_workspace->m_events.destroy.registerListener([this](auto) {
m_resource->sendRemoved();
if (m_manager)
m_manager->scheduleDone();
});
m_listeners.activeChanged = m_workspace->m_events.activeChange.registerListener([this](auto) {
sendState();
sendCapabilities();
});
m_listeners.monitorChanged = m_workspace->m_events.monitorChange.registerListener([this](auto) { this->sendGroup(); });
m_listeners.renamed = m_workspace->m_events.rename.registerListener([this](auto) {
m_resource->sendName(m_workspace->m_name.c_str());
if (m_manager)
m_manager->scheduleDone();
});
m_resource->setOnDestroy([this](auto) { PROTO::extWorkspace->destroyWorkspace(m_self); });
m_resource->setDestroy([this](auto) { PROTO::extWorkspace->destroyWorkspace(m_self); });
m_resource->setActivate([this](void*) { m_pendingState.activate = true; });
m_resource->setDeactivate([this](void*) { m_pendingState.deactivate = true; });
m_resource->setAssign([this](void*, wl_resource* groupResource) {
auto group = CExtWorkspaceGroupResource::fromResource(groupResource);
if (group)
m_pendingState.targetMonitor = group->m_monitor;
});
m_resource->sendName(m_workspace->m_name.c_str());
wl_array coordinates;
wl_array_init(&coordinates);
auto id = m_workspace->m_id;
if (id < 0 && !m_workspace->m_name.empty())
id += UINT32_MAX - 1337;
if (id > 0)
*static_cast<uint32_t*>(wl_array_add(&coordinates, sizeof(uint32_t))) = id;
m_resource->sendCoordinates(&coordinates);
wl_array_release(&coordinates);
sendState();
sendCapabilities();
sendGroup();
m_manager->scheduleDone();
}
bool CExtWorkspaceResource::good() const {
return m_resource;
}
bool CExtWorkspaceResource::isActive() const {
if (!m_workspace)
return false;
auto const& monitor = m_workspace->m_monitor;
auto const& cmpWorkspace = m_workspace->m_isSpecialWorkspace ? monitor->m_activeSpecialWorkspace : monitor->m_activeWorkspace;
return m_workspace == cmpWorkspace;
}
void CExtWorkspaceResource::sendState() {
uint32_t state = 0;
if (isActive())
state |= EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE;
if (m_workspace->hasUrgentWindow())
state |= EXT_WORKSPACE_HANDLE_V1_STATE_URGENT;
if (m_workspace->m_isSpecialWorkspace)
state |= EXT_WORKSPACE_HANDLE_V1_STATE_HIDDEN;
m_resource->sendState(static_cast<extWorkspaceHandleV1State>(state));
if (m_manager)
m_manager->scheduleDone();
}
void CExtWorkspaceResource::sendCapabilities() {
uint32_t capabilities = EXT_WORKSPACE_HANDLE_V1_WORKSPACE_CAPABILITIES_ASSIGN;
auto active = isActive();
if (!active)
capabilities |= EXT_WORKSPACE_HANDLE_V1_WORKSPACE_CAPABILITIES_ACTIVATE;
if (active && m_workspace->m_isSpecialWorkspace)
capabilities |= EXT_WORKSPACE_HANDLE_V1_WORKSPACE_CAPABILITIES_DEACTIVATE;
m_resource->sendCapabilities(static_cast<extWorkspaceHandleV1WorkspaceCapabilities>(capabilities));
if (m_manager)
m_manager->scheduleDone();
}
void CExtWorkspaceResource::sendGroup() {
if (m_group)
m_group->workspaceLeave(m_resource);
if (m_manager) {
m_group = m_manager->findGroup(m_workspace->m_monitor);
if (m_group)
m_group->workspaceEnter(m_resource);
m_manager->scheduleDone();
}
}
void CExtWorkspaceResource::commit() {
// order is important
if (m_pendingState.deactivate && isActive() && m_workspace->m_isSpecialWorkspace)
m_workspace->m_monitor->setSpecialWorkspace(nullptr);
if (m_pendingState.targetMonitor && m_workspace && m_workspace->m_monitor != m_pendingState.targetMonitor)
g_pCompositor->moveWorkspaceToMonitor(m_workspace.lock(), m_pendingState.targetMonitor.lock(), true);
if (m_pendingState.activate && !isActive() && m_workspace)
m_workspace->m_monitor->changeWorkspace(m_workspace.lock());
m_pendingState.activate = false;
m_pendingState.deactivate = false;
m_pendingState.targetMonitor.reset();
}
CExtWorkspaceManagerResource::CExtWorkspaceManagerResource(UP<CExtWorkspaceManagerV1> resource) : m_resource(std::move(resource)) {
if (!good())
return;
m_resource->setOnDestroy([this](auto) { PROTO::extWorkspace->destroyManager(m_self); });
m_resource->setStop([this](auto) {
m_resource->sendFinished();
PROTO::extWorkspace->destroyManager(m_self);
});
m_resource->setCommit([this](auto) {
for (auto& workspace : PROTO::extWorkspace->m_workspaces) {
if (workspace->m_manager == m_self)
workspace->commit();
}
});
}
void CExtWorkspaceManagerResource::init(WP<CExtWorkspaceManagerResource> self) {
if (!good())
return;
m_self = self;
for (auto const& m : g_pCompositor->m_monitors) {
onMonitorCreated(m);
}
for (auto const& w : g_pCompositor->m_workspaces) {
onWorkspaceCreated(w);
}
}
bool CExtWorkspaceManagerResource::good() const {
return m_resource;
}
void CExtWorkspaceManagerResource::scheduleDone() {
if (m_doneScheduled)
return;
m_doneScheduled = true;
g_pEventLoopManager->doLater([self = m_self] {
if (!self || !self->m_resource)
return;
self->m_doneScheduled = false;
self->m_resource->sendDone();
});
}
WP<CExtWorkspaceGroupResource> CExtWorkspaceManagerResource::findGroup(const PHLMONITORREF& monitor) const {
auto iter = std::ranges::find_if(PROTO::extWorkspace->m_groups,
[&](const UP<CExtWorkspaceGroupResource>& resource) { return resource->m_manager.get() == this && resource->m_monitor == monitor; });
return iter != PROTO::extWorkspace->m_groups.end() ? *iter : WP<CExtWorkspaceGroupResource>();
}
void CExtWorkspaceManagerResource::sendGroupToWorkspaces(const WP<CExtWorkspaceGroupResource>& group) {
for (auto& workspace : PROTO::extWorkspace->m_workspaces) {
if (workspace->m_manager == m_self && workspace->m_workspace && workspace->m_workspace->m_monitor == group->m_monitor)
workspace->sendGroup();
}
}
void CExtWorkspaceManagerResource::onMonitorCreated(const PHLMONITOR& monitor) {
auto& group = PROTO::extWorkspace->m_groups.emplace_back(
makeUnique<CExtWorkspaceGroupResource>(m_self, makeUnique<CExtWorkspaceGroupHandleV1>(m_resource->client(), m_resource->version(), 0), monitor));
group->m_self = group;
if UNLIKELY (!group->good()) {
LOGM(ERR, "Couldn't create a workspace group object");
wl_client_post_no_memory(m_resource->client());
return;
}
scheduleDone();
}
void CExtWorkspaceManagerResource::onWorkspaceCreated(const PHLWORKSPACE& workspace) {
auto& ws = PROTO::extWorkspace->m_workspaces.emplace_back(
makeUnique<CExtWorkspaceResource>(m_self, makeUnique<CExtWorkspaceHandleV1>(m_resource->client(), m_resource->version(), 0), workspace));
ws->m_self = ws;
if UNLIKELY (!ws->good()) {
LOGM(ERR, "Couldn't create a workspace object");
wl_client_post_no_memory(m_resource->client());
return;
}
}
CExtWorkspaceProtocol::CExtWorkspaceProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
static auto P1 = g_pHookSystem->hookDynamic("createWorkspace", [this](void* self, SCallbackInfo& info, std::any data) {
auto workspace = std::any_cast<CWorkspace*>(data)->m_self.lock();
for (auto const& m : m_managers) {
m->onWorkspaceCreated(workspace);
}
});
static auto P2 = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) {
auto monitor = std::any_cast<PHLMONITOR>(data);
for (auto const& m : m_managers) {
m->onMonitorCreated(monitor);
}
});
}
void CExtWorkspaceProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
auto& manager = m_managers.emplace_back(makeUnique<CExtWorkspaceManagerResource>(makeUnique<CExtWorkspaceManagerV1>(client, ver, id)));
manager->init(manager);
if UNLIKELY (!manager->good()) {
LOGM(ERR, "Couldn't create a workspace manager");
wl_client_post_no_memory(client);
return;
}
}
void CExtWorkspaceProtocol::destroyGroup(const WP<CExtWorkspaceGroupResource>& group) {
std::erase_if(m_groups, [&](const UP<CExtWorkspaceGroupResource>& resource) { return resource == group; });
}
void CExtWorkspaceProtocol::destroyWorkspace(const WP<CExtWorkspaceResource>& workspace) {
std::erase_if(m_workspaces, [&](const UP<CExtWorkspaceResource>& resource) { return resource == workspace; });
}
void CExtWorkspaceProtocol::destroyManager(const WP<CExtWorkspaceManagerResource>& manager) {
std::erase_if(PROTO::extWorkspace->m_managers, [&](const UP<CExtWorkspaceManagerResource>& resource) { return resource == manager; });
}

View File

@@ -0,0 +1,117 @@
#pragma once
#include "WaylandProtocol.hpp"
#include "../desktop/DesktopTypes.hpp"
#include "ext-workspace-v1.hpp"
#include <cstdint>
#include <vector>
#include "../helpers/signal/Signal.hpp"
#include "../helpers/Monitor.hpp"
class CExtWorkspaceManagerResource;
class CExtWorkspaceGroupResource {
public:
CExtWorkspaceGroupResource(WP<CExtWorkspaceManagerResource> manager, UP<CExtWorkspaceGroupHandleV1> resource, PHLMONITORREF monitor);
static WP<CExtWorkspaceGroupResource> fromResource(wl_resource*);
[[nodiscard]] bool good() const;
void workspaceEnter(const WP<CExtWorkspaceHandleV1>&);
void workspaceLeave(const WP<CExtWorkspaceHandleV1>&);
PHLMONITORREF m_monitor;
private:
WP<CExtWorkspaceGroupResource> m_self;
WP<CExtWorkspaceManagerResource> m_manager;
UP<CExtWorkspaceGroupHandleV1> m_resource;
struct {
CHyprSignalListener destroyed;
CHyprSignalListener outputBound;
} m_listeners;
friend class CExtWorkspaceManagerResource;
};
class CExtWorkspaceResource {
public:
CExtWorkspaceResource(WP<CExtWorkspaceManagerResource> manager, UP<CExtWorkspaceHandleV1> resource, PHLWORKSPACEREF workspace);
[[nodiscard]] bool good() const;
void commit();
private:
WP<CExtWorkspaceResource> m_self;
WP<CExtWorkspaceManagerResource> m_manager;
UP<CExtWorkspaceHandleV1> m_resource;
WP<CExtWorkspaceGroupResource> m_group;
PHLWORKSPACEREF m_workspace;
[[nodiscard]] bool isActive() const;
void sendState();
void sendCapabilities();
void sendGroup();
struct {
bool activate = false;
bool deactivate = false;
PHLMONITORREF targetMonitor;
} m_pendingState;
struct {
CHyprSignalListener destroyed;
CHyprSignalListener activeChanged;
CHyprSignalListener monitorChanged;
CHyprSignalListener renamed;
} m_listeners;
friend class CExtWorkspaceManagerResource;
};
class CExtWorkspaceManagerResource {
public:
CExtWorkspaceManagerResource(UP<CExtWorkspaceManagerV1> resource);
WP<CExtWorkspaceManagerResource> m_self;
void init(WP<CExtWorkspaceManagerResource> self);
[[nodiscard]] bool good() const;
void onMonitorCreated(const PHLMONITOR& monitor);
void onWorkspaceCreated(const PHLWORKSPACE& workspace);
void scheduleDone();
[[nodiscard]] WP<CExtWorkspaceGroupResource> findGroup(const PHLMONITORREF& monitor) const;
void sendGroupToWorkspaces(const WP<CExtWorkspaceGroupResource>& group);
UP<CExtWorkspaceManagerV1> m_resource;
private:
bool m_doneScheduled = false;
};
class CExtWorkspaceProtocol : public IWaylandProtocol {
public:
CExtWorkspaceProtocol(const wl_interface* iface, const int& var, const std::string& name);
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
void destroyManager(const WP<CExtWorkspaceManagerResource>& manager);
void destroyGroup(const WP<CExtWorkspaceGroupResource>& group);
void destroyWorkspace(const WP<CExtWorkspaceResource>& workspace);
private:
std::vector<UP<CExtWorkspaceManagerResource>> m_managers;
std::vector<UP<CExtWorkspaceGroupResource>> m_groups;
std::vector<UP<CExtWorkspaceResource>> m_workspaces;
friend class CExtWorkspaceManagerResource;
};
namespace PROTO {
inline UP<CExtWorkspaceProtocol> extWorkspace;
}

View File

@@ -107,6 +107,7 @@ void CWLOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver,
RESOURCE->m_self = RESOURCE;
RESOURCE->m_owner = m_self;
m_events.outputBound.emit(RESOURCE);
}
void CWLOutputProtocol::destroyResource(CWLOutputResource* resource) {

View File

@@ -46,6 +46,10 @@ class CWLOutputProtocol : public IWaylandProtocol {
void remove();
bool isDefunct(); // true if above was called
struct {
CSignal outputBound;
} m_events;
private:
void destroyResource(CWLOutputResource* resource);