mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-05 22:51:58 -07:00
protocols: add ext-workspace implementation (#10818)
This commit is contained in:
@@ -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()
|
||||
|
||||
|
@@ -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 = []
|
||||
|
@@ -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);
|
||||
|
@@ -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() {
|
||||
|
@@ -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) {
|
||||
|
@@ -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) {
|
||||
|
@@ -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();
|
||||
|
331
src/protocols/ExtWorkspace.cpp
Normal file
331
src/protocols/ExtWorkspace.cpp
Normal 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; });
|
||||
}
|
117
src/protocols/ExtWorkspace.hpp
Normal file
117
src/protocols/ExtWorkspace.hpp
Normal 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;
|
||||
}
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user