summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVaxry <vaxry@vaxry.net>2024-05-10 23:28:33 +0100
committerVaxry <43317083+vaxerski@users.noreply.github.com>2024-05-14 23:02:24 +0100
commit0cfdde3d1acbfbf698af17f6986fbc4d644214da (patch)
tree579ac53bc228db6d0feb373448c8e5557d3285d4 /src
parent121d3a72137d4780602cf245704615f63357ea22 (diff)
xdg-shell: move to new impl
Diffstat (limited to 'src')
-rw-r--r--src/Compositor.cpp51
-rw-r--r--src/Compositor.hpp1
-rw-r--r--src/config/ConfigManager.cpp4
-rw-r--r--src/debug/HyprCtl.cpp12
-rw-r--r--src/desktop/Popup.cpp116
-rw-r--r--src/desktop/Popup.hpp31
-rw-r--r--src/desktop/Window.cpp206
-rw-r--r--src/desktop/Window.hpp31
-rw-r--r--src/events/Events.hpp3
-rw-r--r--src/events/Windows.cpp175
-rw-r--r--src/includes.hpp2
-rw-r--r--src/layout/IHyprLayout.cpp11
-rw-r--r--src/managers/ProtocolManager.cpp2
-rw-r--r--src/managers/XWaylandManager.cpp121
-rw-r--r--src/managers/XWaylandManager.hpp3
-rw-r--r--src/managers/input/InputManager.cpp6
-rw-r--r--src/protocols/ForeignToplevel.cpp2
-rw-r--r--src/protocols/ForeignToplevelWlr.cpp4
-rw-r--r--src/protocols/LayerShell.cpp7
-rw-r--r--src/protocols/XDGShell.cpp697
-rw-r--r--src/protocols/XDGShell.hpp256
-rw-r--r--src/render/Renderer.cpp27
22 files changed, 1349 insertions, 419 deletions
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index efc02a5f..c56dd280 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -18,6 +18,7 @@
#include "protocols/FractionalScale.hpp"
#include "protocols/PointerConstraints.hpp"
#include "protocols/LayerShell.hpp"
+#include "protocols/XDGShell.hpp"
#include "desktop/LayerSurface.hpp"
#include <sys/types.h>
@@ -229,8 +230,6 @@ void CCompositor::initServer() {
// wlr_primary_selection_v1_device_manager_create(m_sWLDisplay);
wlr_viewporter_create(m_sWLDisplay);
- m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 6);
-
m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend);
if (!m_sWRLDRMLeaseMgr) {
Debug::log(INFO, "Failed to create wlr_drm_lease_v1_manager");
@@ -253,7 +252,6 @@ void CCompositor::initServer() {
void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend");
- addWLSignal(&m_sWLRXDGShell->events.new_toplevel, &Events::listen_newXDGToplevel, m_sWLRXDGShell, "XDG Shell");
addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend");
// addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat");
// addWLSignal(&m_sSeat.seat->events.request_start_drag, &Events::listen_requestDrag, &m_sSeat, "Seat");
@@ -271,7 +269,6 @@ void CCompositor::initAllSignals() {
void CCompositor::removeAllSignals() {
removeWLSignal(&Events::listen_newOutput);
- removeWLSignal(&Events::listen_newXDGToplevel);
removeWLSignal(&Events::listen_newInput);
removeWLSignal(&Events::listen_requestSetSel);
removeWLSignal(&Events::listen_requestDrag);
@@ -805,22 +802,28 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, PHLWINDOW p
RASSERT(!pWindow->m_bIsX11, "Cannot call vectorWindowToSurface on an X11 window!");
- const auto PSURFACE = pWindow->m_uSurface.xdg;
+ double subx, suby;
+
+ CBox geom = pWindow->m_pXDGSurface->current.geometry;
- double subx, suby;
+ // try popups first
+ const auto PPOPUP = pWindow->m_pPopupHead->at(pos);
- // calc for oversized windows... fucking bullshit, again.
- CBox geom;
- wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, geom.pWlr());
- geom.applyFromWlr();
+ wlr_surface* found = PPOPUP ? PPOPUP->m_sWLSurface.wlr() : nullptr;
- const auto PFOUND =
- wlr_xdg_surface_surface_at(PSURFACE, pos.x - pWindow->m_vRealPosition.value().x + geom.x, pos.y - pWindow->m_vRealPosition.value().y + geom.y, &subx, &suby);
+ if (!PPOPUP)
+ found = wlr_surface_surface_at(pWindow->m_pWLSurface.wlr(), pos.x - pWindow->m_vRealPosition.value().x + geom.x, pos.y - pWindow->m_vRealPosition.value().y + geom.y, &subx,
+ &suby);
+ else {
+ const auto OFF = PPOPUP->coordsRelativeToParent();
+ subx = pos.x - OFF.x + geom.x - pWindow->m_vRealPosition.goal().x;
+ suby = pos.y - OFF.y + geom.y - pWindow->m_vRealPosition.goal().y;
+ }
- if (PFOUND) {
+ if (found) {
sl.x = subx;
sl.y = suby;
- return PFOUND;
+ return found;
}
sl.x = pos.x - pWindow->m_vRealPosition.value().x;
@@ -829,7 +832,7 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, PHLWINDOW p
sl.x += geom.x;
sl.y += geom.y;
- return PSURFACE->surface;
+ return pWindow->m_pWLSurface.wlr();
}
Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindow, wlr_surface* pSurface) {
@@ -839,12 +842,14 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo
if (pWindow->m_bIsX11)
return vec - pWindow->m_vRealPosition.goal();
- const auto PSURFACE = pWindow->m_uSurface.xdg;
+ const auto PPOPUP = pWindow->m_pPopupHead->at(vec);
+ if (PPOPUP)
+ return vec - PPOPUP->coordsGlobal();
std::tuple<wlr_surface*, int, int> iterData = {pSurface, -1337, -1337};
- wlr_xdg_surface_for_each_surface(
- PSURFACE,
+ wlr_surface_for_each_surface(
+ pWindow->m_pWLSurface.wlr(),
[](wlr_surface* surf, int x, int y, void* data) {
const auto PDATA = (std::tuple<wlr_surface*, int, int>*)data;
if (surf == std::get<0>(*PDATA)) {
@@ -854,9 +859,7 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo
},
&iterData);
- CBox geom = {};
- wlr_xdg_surface_get_geometry(PSURFACE, geom.pWlr());
- geom.applyFromWlr();
+ CBox geom = pWindow->m_pXDGSurface->current.geometry;
if (std::get<1>(iterData) == -1337 && std::get<2>(iterData) == -1337)
return vec - pWindow->m_vRealPosition.goal();
@@ -993,7 +996,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) {
pWindow->m_bIsUrgent = false;
// Send an event
- g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(pWindow) + "," + pWindow->m_szTitle});
+ g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", pWindow->m_szClass + "," + pWindow->m_szTitle});
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)pWindow.get())});
EMIT_HOOK_EVENT("activeWindow", pWindow);
@@ -2310,7 +2313,7 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) {
switch (mode) {
case MODE_CLASS_REGEX: {
- const auto windowClass = g_pXWaylandManager->getAppIDClass(w);
+ const auto windowClass = w->m_szClass;
if (!std::regex_search(windowClass, regexCheck))
continue;
break;
@@ -2322,7 +2325,7 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) {
break;
}
case MODE_TITLE_REGEX: {
- const auto windowTitle = g_pXWaylandManager->getTitle(w);
+ const auto windowTitle = w->m_szTitle;
if (!std::regex_search(windowTitle, regexCheck))
continue;
break;
diff --git a/src/Compositor.hpp b/src/Compositor.hpp
index eedcea56..574889bc 100644
--- a/src/Compositor.hpp
+++ b/src/Compositor.hpp
@@ -50,7 +50,6 @@ class CCompositor {
wlr_subcompositor* m_sWLRSubCompositor;
wlr_drm* m_sWRLDRM;
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
- wlr_xdg_shell* m_sWLRXDGShell;
wlr_egl* m_sWLREGL;
int m_iDRMFD;
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 4a75ca1d..15d5ae81 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -1042,8 +1042,8 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
std::vector<SWindowRule> returns;
- std::string title = g_pXWaylandManager->getTitle(pWindow);
- std::string appidclass = g_pXWaylandManager->getAppIDClass(pWindow);
+ std::string title = pWindow->m_szTitle;
+ std::string appidclass = pWindow->m_szClass;
Debug::log(LOG, "Searching for matching rules for {} (title: {})", appidclass, title);
diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
index f8fdb03f..51071533 100644
--- a/src/debug/HyprCtl.cpp
+++ b/src/debug/HyprCtl.cpp
@@ -210,10 +210,10 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
(uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (int64_t)w->m_iMonitorID,
- escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w)), escapeJSONStrings(g_pXWaylandManager->getTitle(w)), escapeJSONStrings(w->m_szInitialClass),
- escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"),
- (w->m_bIsFullscreen ? "true" : "false"), (w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0),
- w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
+ escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(),
+ ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"),
+ (w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format),
+ (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
} else {
return std::format("Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
@@ -221,8 +221,8 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
"{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
(uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
- (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w),
- g_pXWaylandManager->getTitle(w), w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen,
+ (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass,
+ w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen,
(w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), (int)w->m_bFakeFullscreenState, getGroupedData(w, format),
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
}
diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp
index e172744d..605dfdfd 100644
--- a/src/desktop/Popup.cpp
+++ b/src/desktop/Popup.cpp
@@ -2,6 +2,7 @@
#include "../config/ConfigValue.hpp"
#include "../Compositor.hpp"
#include "../protocols/LayerShell.hpp"
+#include "../protocols/XDGShell.hpp"
#include <ranges>
CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) {
@@ -12,14 +13,13 @@ CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) {
initAllSignals();
}
-CPopup::CPopup(wlr_xdg_popup* popup, CPopup* pOwner) : m_pParent(pOwner), m_pWLR(popup) {
- m_pWLR->base->data = this;
- m_sWLSurface.assign(popup->base->surface, this);
+CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner), m_pResource(popup) {
+ m_sWLSurface.assign(popup->surface->surface, this);
m_pLayerOwner = pOwner->m_pLayerOwner;
m_pWindowOwner = pOwner->m_pWindowOwner;
- m_vLastSize = {m_pWLR->current.geometry.width, m_pWLR->current.geometry.height};
+ m_vLastSize = popup->surface->current.geometry.size();
unconstrain();
initAllSignals();
@@ -27,71 +27,32 @@ CPopup::CPopup(wlr_xdg_popup* popup, CPopup* pOwner) : m_pParent(pOwner), m_pWLR
CPopup::~CPopup() {
m_sWLSurface.unassign();
- if (m_pWLR)
- m_pWLR->base->data = nullptr;
-
- hyprListener_commitPopup.removeCallback();
- hyprListener_repositionPopup.removeCallback();
- hyprListener_mapPopup.removeCallback();
- hyprListener_unmapPopup.removeCallback();
- hyprListener_newPopup.removeCallback();
- hyprListener_destroyPopup.removeCallback();
-}
-
-static void onNewPopup(void* owner, void* data) {
- const auto POPUP = (CPopup*)owner;
- POPUP->onNewPopup((wlr_xdg_popup*)data);
-}
-
-static void onMapPopup(void* owner, void* data) {
- const auto POPUP = (CPopup*)owner;
- POPUP->onMap();
-}
-
-static void onDestroyPopup(void* owner, void* data) {
- const auto POPUP = (CPopup*)owner;
- POPUP->onDestroy();
-}
-
-static void onUnmapPopup(void* owner, void* data) {
- const auto POPUP = (CPopup*)owner;
- POPUP->onUnmap();
-}
-
-static void onCommitPopup(void* owner, void* data) {
- const auto POPUP = (CPopup*)owner;
- POPUP->onCommit();
-}
-
-static void onRepositionPopup(void* owner, void* data) {
- const auto POPUP = (CPopup*)owner;
- POPUP->onReposition();
}
void CPopup::initAllSignals() {
- if (!m_pWLR) {
+ if (!m_pResource) {
if (!m_pWindowOwner.expired())
- hyprListener_newPopup.initCallback(&m_pWindowOwner->m_uSurface.xdg->events.new_popup, ::onNewPopup, this, "CPopup Head");
+ listeners.newPopup = m_pWindowOwner->m_pXDGSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); });
else if (!m_pLayerOwner.expired())
- listeners.newPopup = m_pLayerOwner->layerSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<wlr_xdg_popup*>(d)); });
+ listeners.newPopup = m_pLayerOwner->layerSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); });
else
ASSERT(false);
return;
}
- hyprListener_repositionPopup.initCallback(&m_pWLR->events.reposition, ::onRepositionPopup, this, "CPopup");
- hyprListener_destroyPopup.initCallback(&m_pWLR->events.destroy, ::onDestroyPopup, this, "CPopup");
- hyprListener_mapPopup.initCallback(&m_sWLSurface.wlr()->events.map, ::onMapPopup, this, "CPopup");
- hyprListener_unmapPopup.initCallback(&m_sWLSurface.wlr()->events.unmap, ::onUnmapPopup, this, "CPopup");
- hyprListener_commitPopup.initCallback(&m_sWLSurface.wlr()->events.commit, ::onCommitPopup, this, "CPopup");
- hyprListener_newPopup.initCallback(&m_pWLR->base->events.new_popup, ::onNewPopup, this, "CPopup");
+ listeners.reposition = m_pResource->events.reposition.registerListener([this](std::any d) { this->onReposition(); });
+ listeners.map = m_pResource->surface->events.map.registerListener([this](std::any d) { this->onMap(); });
+ listeners.unmap = m_pResource->surface->events.unmap.registerListener([this](std::any d) { this->onUnmap(); });
+ listeners.destroy = m_pResource->surface->events.destroy.registerListener([this](std::any d) { this->onDestroy(); });
+ listeners.commit = m_pResource->surface->events.commit.registerListener([this](std::any d) { this->onCommit(); });
+ listeners.newPopup = m_pResource->surface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); });
}
-void CPopup::onNewPopup(wlr_xdg_popup* popup) {
+void CPopup::onNewPopup(SP<CXDGPopupResource> popup) {
const auto POPUP = m_vChildren.emplace_back(std::make_unique<CPopup>(popup, this)).get();
- Debug::log(LOG, "New popup at wlr {:x} and hl {:x}", (uintptr_t)popup, (uintptr_t)POPUP);
+ Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP);
}
void CPopup::onDestroy() {
@@ -104,7 +65,7 @@ void CPopup::onDestroy() {
}
void CPopup::onMap() {
- m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
+ m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height};
const auto COORDS = coordsGlobal();
CBox box;
@@ -126,7 +87,9 @@ void CPopup::onMap() {
}
void CPopup::onUnmap() {
- m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
+ if (!m_pResource || !m_pResource->surface)
+ return;
+ m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height};
const auto COORDS = coordsGlobal();
CBox box;
@@ -140,16 +103,27 @@ void CPopup::onUnmap() {
if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
+
+ // damage all children
+ breadthfirst(
+ [this](CPopup* p, void* data) {
+ if (!p->m_pResource)
+ return;
+
+ auto box = CBox{p->coordsGlobal(), p->size()};
+ g_pHyprRenderer->damageBox(&box);
+ },
+ nullptr);
}
void CPopup::onCommit(bool ignoreSiblings) {
- if (m_pWLR->base->initial_commit) {
- wlr_xdg_surface_schedule_configure(m_pWLR->base);
+ if (m_pResource->surface->initialCommit) {
+ m_pResource->surface->scheduleConfigure();
return;
}
if (!m_pWindowOwner.expired() && (!m_pWindowOwner->m_bIsMapped || !m_pWindowOwner->m_pWorkspace->m_bVisible)) {
- m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
+ m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height};
static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage");
if (*PLOGDAMAGE)
@@ -157,16 +131,17 @@ void CPopup::onCommit(bool ignoreSiblings) {
return;
}
- if (!m_pWLR->base->surface->mapped)
+ if (!m_pResource->surface->mapped)
return;
const auto COORDS = coordsGlobal();
const auto COORDSLOCAL = coordsRelativeToParent();
- if (m_vLastSize != Vector2D{m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height} || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) {
+ if (m_vLastSize != Vector2D{m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height} || m_bRequestedReposition ||
+ m_vLastPos != COORDSLOCAL) {
CBox box = {localToGlobal(m_vLastPos), m_vLastSize};
g_pHyprRenderer->damageBox(&box);
- m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
+ m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height};
box = {COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
@@ -202,20 +177,25 @@ void CPopup::unconstrain() {
return;
CBox box = {PMONITOR->vecPosition.x - COORDS.x, PMONITOR->vecPosition.y - COORDS.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
- wlr_xdg_popup_unconstrain_from_box(m_pWLR, box.pWlr());
+ m_pResource->applyPositioning(box, COORDS - PMONITOR->vecPosition);
+ wlr_surface_send_enter(m_pResource->surface->surface, PMONITOR->output);
}
Vector2D CPopup::coordsRelativeToParent() {
Vector2D offset;
- CPopup* current = this;
+ if (!m_pResource)
+ return {};
+
+ CPopup* current = this;
+ offset -= current->m_pResource->surface->current.geometry.pos();
- offset -= {m_pWLR->base->current.geometry.x, m_pWLR->base->current.geometry.y};
+ offset -= m_pResource->surface->current.geometry.pos();
- while (current->m_pParent) {
+ while (current->m_pParent && current->m_pResource) {
offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy};
- offset += {current->m_pWLR->current.geometry.x, current->m_pWLR->current.geometry.y};
+ offset += current->m_pResource->geometry.pos();
current = current->m_pParent;
}
@@ -309,7 +289,7 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
breadthfirst([](CPopup* popup, void* data) { ((std::vector<CPopup*>*)data)->push_back(popup); }, &popups);
for (auto& p : popups | std::views::reverse) {
- if (!p->m_pWLR)
+ if (!p->m_pResource)
continue;
if (!allowsInput) {
diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp
index 6aa7ce61..e6c35e68 100644
--- a/src/desktop/Popup.hpp
+++ b/src/desktop/Popup.hpp
@@ -5,6 +5,8 @@
#include "Subsurface.hpp"
#include "../helpers/signal/Listener.hpp"
+class CXDGPopupResource;
+
class CPopup {
public:
// dummy head nodes
@@ -12,7 +14,7 @@ class CPopup {
CPopup(PHLLS pOwner);
// real nodes
- CPopup(wlr_xdg_popup* popup, CPopup* pOwner);
+ CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner);
~CPopup();
@@ -21,7 +23,7 @@ class CPopup {
Vector2D size();
- void onNewPopup(wlr_xdg_popup* popup);
+ void onNewPopup(SP<CXDGPopupResource> popup);
void onDestroy();
void onMap();
void onUnmap();
@@ -45,31 +47,28 @@ class CPopup {
PHLLSREF m_pLayerOwner;
// T2 owners
- CPopup* m_pParent = nullptr;
+ CPopup* m_pParent = nullptr;
- wlr_xdg_popup* m_pWLR = nullptr;
+ WP<CXDGPopupResource> m_pResource;
- Vector2D m_vLastSize = {};
- Vector2D m_vLastPos = {};
+ Vector2D m_vLastSize = {};
+ Vector2D m_vLastPos = {};
- bool m_bRequestedReposition = false;
+ bool m_bRequestedReposition = false;
- bool m_bInert = false;
+ bool m_bInert = false;
//
std::vector<std::unique_ptr<CPopup>> m_vChildren;
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
- // signals
- DYNLISTENER(newPopup);
- DYNLISTENER(destroyPopup);
- DYNLISTENER(mapPopup);
- DYNLISTENER(unmapPopup);
- DYNLISTENER(commitPopup);
- DYNLISTENER(repositionPopup);
-
struct {
CHyprSignalListener newPopup;
+ CHyprSignalListener destroy;
+ CHyprSignalListener map;
+ CHyprSignalListener unmap;
+ CHyprSignalListener commit;
+ CHyprSignalListener reposition;
} listeners;
void initAllSignals();
diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp
index e87bd99c..c11a714b 100644
--- a/src/desktop/Window.cpp
+++ b/src/desktop/Window.cpp
@@ -6,6 +6,7 @@
#include "../config/ConfigValue.hpp"
#include <any>
#include "../managers/TokenManager.hpp"
+#include "../protocols/XDGShell.hpp"
PHLWINDOW CWindow::create() {
PHLWINDOW pWindow = SP<CWindow>(new CWindow);
@@ -27,6 +28,39 @@ PHLWINDOW CWindow::create() {
return pWindow;
}
+PHLWINDOW CWindow::create(SP<CXDGSurfaceResource> resource) {
+ PHLWINDOW pWindow = SP<CWindow>(new CWindow(resource));
+
+ pWindow->m_pSelf = pWindow;
+ resource->toplevel->window = pWindow;
+
+ pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
+ pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
+ pWindow->m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER);
+ pWindow->m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER);
+ pWindow->m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
+ pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
+ pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
+ pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
+
+ pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow));
+ pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow));
+
+ pWindow->m_pWLSurface.assign(pWindow->m_pXDGSurface->surface, pWindow);
+
+ return pWindow;
+}
+
+CWindow::CWindow(SP<CXDGSurfaceResource> resource) : m_pXDGSurface(resource) {
+ listeners.map = m_pXDGSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); });
+ listeners.ack = m_pXDGSurface->events.ack.registerListener([this](std::any d) { onAck(std::any_cast<uint32_t>(d)); });
+ listeners.unmap = m_pXDGSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); });
+ listeners.destroy = m_pXDGSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); });
+ listeners.commit = m_pXDGSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); });
+ listeners.updateState = m_pXDGSurface->toplevel->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); });
+ listeners.updateMetadata = m_pXDGSurface->toplevel->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); });
+}
+
CWindow::CWindow() {
;
}
@@ -74,21 +108,24 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
- if (m_pWLSurface.exists() && !m_bIsX11) {
+ if (m_pWLSurface.exists() && !m_bIsX11 && m_pPopupHead) {
CBox surfaceExtents = {0, 0, 0, 0};
// TODO: this could be better, perhaps make a getFullWindowRegion?
- wlr_xdg_surface_for_each_popup_surface(
- m_uSurface.xdg,
- [](wlr_surface* surf, int sx, int sy, void* data) {
+ m_pPopupHead->breadthfirst(
+ [](CPopup* popup, void* data) {
+ if (!popup->m_sWLSurface.wlr())
+ return;
+
CBox* pSurfaceExtents = (CBox*)data;
- if (sx < pSurfaceExtents->x)
- pSurfaceExtents->x = sx;
- if (sy < pSurfaceExtents->y)
- pSurfaceExtents->y = sy;
- if (sx + surf->current.width > pSurfaceExtents->width)
- pSurfaceExtents->width = sx + surf->current.width - pSurfaceExtents->x;
- if (sy + surf->current.height > pSurfaceExtents->height)
- pSurfaceExtents->height = sy + surf->current.height - pSurfaceExtents->y;
+ CBox surf = CBox{popup->coordsRelativeToParent(), popup->size()};
+ if (surf.x < pSurfaceExtents->x)
+ pSurfaceExtents->x = surf.x;
+ if (surf.y < pSurfaceExtents->y)
+ pSurfaceExtents->y = surf.y;
+ if (surf.x + surf.w > pSurfaceExtents->width)
+ pSurfaceExtents->width = surf.x + surf.w - pSurfaceExtents->x;
+ if (surf.y + surf.h > pSurfaceExtents->height)
+ pSurfaceExtents->height = surf.y + surf.h - pSurfaceExtents->y;
},
&surfaceExtents);
@@ -258,10 +295,10 @@ bool CWindow::checkInputOnDecos(const eInputType type, const Vector2D& mouseCoor
pid_t CWindow::getPID() {
pid_t PID = -1;
if (!m_bIsX11) {
- if (!m_uSurface.xdg)
+ if (!m_pXDGSurface || !m_pXDGSurface->owner /* happens at unmap */)
return -1;
- wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
+ wl_client_get_credentials(m_pXDGSurface->owner->client(), &PID, nullptr, nullptr);
} else {
if (!m_uSurface.xwayland)
return -1;
@@ -511,8 +548,8 @@ void CWindow::onMap() {
g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf);
- hyprListener_unmapWindow.initCallback(m_bIsX11 ? &m_uSurface.xwayland->surface->events.unmap : &m_uSurface.xdg->surface->events.unmap, &Events::listener_unmapWindow, this,
- "CWindow");
+ if (m_bIsX11)
+ hyprListener_unmapWindow.initCallback(&m_uSurface.xwayland->surface->events.unmap, &Events::listener_unmapWindow, this, "CWindow");
m_vReportedSize = m_vPendingReportedSize;
m_bAnimatingIn = true;
@@ -793,26 +830,14 @@ bool CWindow::isInCurvedCorner(double x, double y) {
return false;
}
-void findExtensionForVector2D(wlr_surface* surface, int x, int y, void* data) {
- const auto DATA = (SExtensionFindingData*)data;
-
- CBox box = {DATA->origin.x + x, DATA->origin.y + y, surface->current.width, surface->current.height};
-
- if (box.containsPoint(DATA->vec))
- *DATA->found = surface;
-}
-
// checks if the wayland window has a popup at pos
bool CWindow::hasPopupAt(const Vector2D& pos) {
if (m_bIsX11)
return false;
- wlr_surface* resultSurf = nullptr;
- Vector2D origin = m_vRealPosition.value();
- SExtensionFindingData data = {origin, pos, &resultSurf};
- wlr_xdg_surface_for_each_popup_surface(m_uSurface.xdg, findExtensionForVector2D, &data);
+ CPopup* popup = m_pPopupHead->at(pos);
- return resultSurf;
+ return popup && popup->m_sWLSurface.wlr();
}
void CWindow::applyGroupRules() {
@@ -1096,11 +1121,11 @@ bool CWindow::opaque() {
if (m_bIsX11)
return !m_uSurface.xwayland->has_alpha;
- if (m_uSurface.xdg->surface->opaque)
+ if (m_pXDGSurface->surface->opaque)
return true;
- const auto EXTENTS = pixman_region32_extents(&m_uSurface.xdg->surface->opaque_region);
- if (EXTENTS->x2 - EXTENTS->x1 >= m_uSurface.xdg->surface->current.buffer_width && EXTENTS->y2 - EXTENTS->y1 >= m_uSurface.xdg->surface->current.buffer_height)
+ const auto EXTENTS = pixman_region32_extents(&m_pXDGSurface->surface->opaque_region);
+ if (EXTENTS->x2 - EXTENTS->x1 >= m_pXDGSurface->surface->current.buffer_width && EXTENTS->y2 - EXTENTS->y1 >= m_pXDGSurface->surface->current.buffer_height)
return true;
return false;
@@ -1162,10 +1187,10 @@ void CWindow::setSuspended(bool suspend) {
if (suspend == m_bSuspended)
return;
- if (m_bIsX11)
+ if (m_bIsX11 || !m_pXDGSurface->toplevel)
return;
- wlr_xdg_toplevel_set_suspended(m_uSurface.xdg->toplevel, suspend);
+ m_pXDGSurface->toplevel->setSuspeneded(suspend);
m_bSuspended = suspend;
}
@@ -1222,11 +1247,20 @@ void CWindow::onWorkspaceAnimUpdate() {
int CWindow::popupsCount() {
if (m_bIsX11)
+ return 0;
+
+ int no = -1;
+ m_pPopupHead->breadthfirst([](CPopup* p, void* d) { *((int*)d) += 1; }, &no);
+ return no;
+}
+
+int CWindow::surfacesCount() {
+ if (m_bIsX11)
return 1;
int no = 0;
- wlr_xdg_surface_for_each_popup_surface(
- m_uSurface.xdg, [](wlr_surface* s, int x, int y, void* data) { *(int*)data += 1; }, &no);
+ wlr_surface_for_each_surface(
+ m_pWLSurface.wlr(), [](wlr_surface* surf, int x, int y, void* data) { *((int*)data) += 1; }, &no);
return no;
}
@@ -1278,6 +1312,9 @@ std::unordered_map<std::string, std::string> CWindow::getEnv() {
}
void CWindow::activate(bool force) {
+ if (g_pCompositor->m_pLastWindow == m_pSelf)
+ return;
+
static auto PFOCUSONACTIVATE = CConfigValue<Hyprlang::INT>("misc:focus_on_activate");
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)this)});
@@ -1295,3 +1332,98 @@ void CWindow::activate(bool force) {
g_pCompositor->focusWindow(m_pSelf.lock());
g_pCompositor->warpCursorTo(middle());
}
+
+void CWindow::onUpdateState() {
+ if (!m_pXDGSurface)
+ return;
+
+ if (m_pXDGSurface->toplevel->state.requestsFullscreen) {
+ bool fs = m_pXDGSurface->toplevel->state.requestsFullscreen.value();
+
+ if (fs != m_bIsFullscreen && m_pXDGSurface->mapped)
+ g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_FULL);
+
+ if (!m_pXDGSurface->mapped)
+ m_bWantsInitialFullscreen = fs;
+ }
+
+ if (m_pXDGSurface->toplevel->state.requestsMaximize) {
+ bool fs = m_pXDGSurface->toplevel->state.requestsMaximize.value();
+
+ if (fs != m_bIsFullscreen && m_pXDGSurface->mapped)
+ g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_MAXIMIZED);
+ }
+}
+
+void CWindow::onUpdateMeta() {
+ const auto NEWTITLE = fetchTitle();
+
+ if (m_szTitle != NEWTITLE) {
+ m_szTitle = NEWTITLE;
+ g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)this)});
+ EMIT_HOOK_EVENT("windowTitle", m_pSelf.lock());
+
+ if (m_pSelf == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others
+ g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", m_szClass + "," + m_szTitle});
+ g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)this)});
+ EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock());
+ }
+
+ updateDynamicRules();
+ g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock());
+ updateToplevel();
+
+ Debug::log(LOG, "Window {:x} set title to {}", (uintptr_t)this, m_szTitle);
+ }
+
+ const auto NEWCLASS = fetchClass();
+ if (m_szClass != NEWCLASS) {
+ m_szClass = NEWCLASS;
+
+ if (m_pSelf == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others
+ g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", m_szClass + "," + m_szTitle});
+ g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)this)});
+ EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock());
+ }
+
+ updateDynamicRules();
+ g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock());
+ updateToplevel();
+
+ Debug::log(LOG, "Window {:x} set class to {}", (uintptr_t)this, m_szClass);
+ }
+}
+
+std::string CWindow::fetchTitle() {
+ if (!m_bIsX11) {
+ if (m_pXDGSurface && m_pXDGSurface->toplevel)
+ return m_pXDGSurface->toplevel->state.title;
+ } else {
+ if (m_uSurface.xwayland && m_uSurface.xwayland->title)
+ return m_uSurface.xwayland->title;
+ }
+
+ return "";
+}
+
+std::string CWindow::fetchClass() {
+ if (!m_bIsX11) {
+ if (m_pXDGSurface && m_pXDGSurface->toplevel)
+ return m_pXDGSurface->toplevel->state.appid;
+ } else {
+ if (m_uSurface.xwayland && m_uSurface.xwayland->_class)
+ return m_uSurface.xwayland->_class;
+ }
+
+ return "";
+}
+
+void CWindow::onAck(uint32_t serial) {
+ const auto SERIAL = std::find_if(m_vPendingSizeAcks.rbegin(), m_vPendingSizeAcks.rend(), [serial](const auto& e) { return e.first == serial; });
+
+ if (SERIAL == m_vPendingSizeAcks.rend())
+ return;
+
+ m_pPendingSizeAck = *SERIAL;
+ std::erase_if(m_vPendingSizeAcks, [&](const auto& el) { return el.first <= SERIAL->first; });
+} \ No newline at end of file
diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp
index 6bff095c..24d9562b 100644
--- a/src/desktop/Window.hpp
+++ b/src/desktop/Window.hpp
@@ -14,6 +14,8 @@
#include "DesktopTypes.hpp"
#include "../helpers/signal/Signal.hpp"
+class CXDGSurfaceResource;
+
enum eIdleInhibitMode {
IDLEINHIBIT_NONE = 0,
IDLEINHIBIT_ALWAYS,
@@ -196,9 +198,12 @@ struct SInitialWorkspaceToken {
class CWindow {
public:
+ static PHLWINDOW create(SP<CXDGSurfaceResource>);
+ // xwl
static PHLWINDOW create();
private:
+ CWindow(SP<CXDGSurfaceResource> resource);
CWindow();
public:
@@ -233,9 +238,9 @@ class CWindow {
} events;
union {
- wlr_xdg_surface* xdg;
wlr_xwayland_surface* xwayland;
} m_uSurface;
+ WP<CXDGSurfaceResource> m_pXDGSurface;
// this is the position and size of the "bounding box"
Vector2D m_vPosition = Vector2D(0, 0);
@@ -271,6 +276,7 @@ class CWindow {
bool m_bWasMaximized = false;
uint64_t m_iMonitorID = -1;
std::string m_szTitle = "";
+ std::string m_szClass = "";
std::string m_szInitialTitle = "";
std::string m_szInitialClass = "";
PHLWORKSPACE m_pWorkspace;
@@ -385,7 +391,7 @@ class CWindow {
// For the list lookup
bool operator==(const CWindow& rhs) {
- return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
+ return m_pXDGSurface == rhs.m_pXDGSurface && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
m_bFadingOut == rhs.m_bFadingOut;
}
@@ -424,6 +430,7 @@ class CWindow {
int workspaceID();
bool onSpecialWorkspace();
void activate(bool force = false);
+ int surfacesCount();
int getRealBorderSize();
void updateSpecialRenderData();
@@ -450,6 +457,13 @@ class CWindow {
void switchWithWindowInGroup(PHLWINDOW pWindow);
void setAnimationsToMove();
void onWorkspaceAnimUpdate();
+ void onUpdateState();
+ void onUpdateMeta();
+ std::string fetchTitle();
+ std::string fetchClass();
+
+ // listeners
+ void onAck(uint32_t serial);
//
std::unordered_map<std::string, std::string> getEnv();
@@ -457,6 +471,17 @@ class CWindow {
//
PHLWINDOWREF m_pSelf;
+ // make private once we move listeners to inside CWindow
+ struct {
+ CHyprSignalListener map;
+ CHyprSignalListener ack;
+ CHyprSignalListener unmap;
+ CHyprSignalListener commit;
+ CHyprSignalListener destroy;
+ CHyprSignalListener updateState;
+ CHyprSignalListener updateMetadata;
+ } listeners;
+
private:
// For hidden windows and stuff
bool m_bHidden = false;
@@ -520,7 +545,7 @@ struct std::formatter<PHLWINDOW, CharT> : std::formatter<CharT> {
if (formatMonitor)
std::format_to(out, ", monitor: {}", w->m_iMonitorID);
if (formatClass)
- std::format_to(out, ", class: {}", g_pXWaylandManager->getAppIDClass(w));
+ std::format_to(out, ", class: {}", w->m_szClass);
return std::format_to(out, "]");
}
};
diff --git a/src/events/Events.hpp b/src/events/Events.hpp
index 2e627d39..7cc0eb32 100644
--- a/src/events/Events.hpp
+++ b/src/events/Events.hpp
@@ -18,9 +18,6 @@ namespace Events {
// Layer events
LISTENER(newLayerSurface);
- // Surface XDG (window)
- LISTENER(newXDGToplevel);
-
// Window events
DYNLISTENFUNC(commitWindow);
DYNLISTENFUNC(mapWindow);
diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp
index b85ed6e1..384ea9ed 100644
--- a/src/events/Windows.cpp
+++ b/src/events/Windows.cpp
@@ -8,6 +8,7 @@
#include "../render/Renderer.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/LayerShell.hpp"
+#include "../protocols/XDGShell.hpp"
// ------------------------------------------------------------ //
// __ _______ _ _ _____ ______ _______ //
@@ -25,11 +26,10 @@ void addViewCoords(void* pWindow, int* x, int* y) {
*y += PWINDOW->m_vRealPosition.goal().y;
if (!PWINDOW->m_bIsX11 && PWINDOW->m_bIsMapped) {
- wlr_box geom;
- wlr_xdg_surface_get_geometry(PWINDOW->m_uSurface.xdg, &geom);
+ Vector2D pos = PWINDOW->m_pXDGSurface->current.geometry.pos();
- *x -= geom.x;
- *y -= geom.y;
+ *x -= pos.x;
+ *y -= pos.y;
}
}
@@ -67,11 +67,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bIsMapped = true;
PWINDOW->m_bReadyToDelete = false;
PWINDOW->m_bFadingOut = false;
- PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
+ PWINDOW->m_szTitle = PWINDOW->fetchTitle();
PWINDOW->m_iX11Type = PWINDOW->m_bIsX11 ? (PWINDOW->m_uSurface.xwayland->override_redirect ? 2 : 1) : 1;
PWINDOW->m_bFirstMap = true;
PWINDOW->m_szInitialTitle = PWINDOW->m_szTitle;
- PWINDOW->m_szInitialClass = g_pXWaylandManager->getAppIDClass(PWINDOW);
+ PWINDOW->m_szInitialClass = PWINDOW->fetchClass();
// check for token
std::string requestedWorkspace = "";
@@ -111,9 +111,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (g_pInputManager->m_bLastFocusOnLS) // waybar fix
g_pInputManager->releaseAllMouseButtons();
- // Set all windows tiled regardless of anything
- g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
-
// checks if the window wants borders and sets the appropriate flag
g_pXWaylandManager->checkBorders(PWINDOW);
@@ -146,10 +143,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
// window rules
- PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false);
- bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen ||
- (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen) ||
- (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen);
+ PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false);
+ bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen);
bool requestsFakeFullscreen = false;
bool requestsMaximize = false;
bool overridingNoFullscreen = false;
@@ -508,19 +503,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_fDimPercent.setValueAndWarp(0);
}
- if (!PWINDOW->m_bIsX11) {
- PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW.get(), "XDG Window Late");
- PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW.get(),
- "XDG Window Late");
- PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_minimize, &Events::listener_requestMinimize, PWINDOW.get(),
- "XDG Window Late");
- PWINDOW->hyprListener_requestMove.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_move, &Events::listener_requestMove, PWINDOW.get(), "XDG Window Late");
- PWINDOW->hyprListener_requestResize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_resize, &Events::listener_requestResize, PWINDOW.get(),
- "XDG Window Late");
- PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW.get(),
- "XDG Window Late");
- PWINDOW->hyprListener_ackConfigure.initCallback(&PWINDOW->m_uSurface.xdg->events.ack_configure, &Events::listener_ackConfigure, PWINDOW.get(), "XDG Window Late");
- } else {
+ if (PWINDOW->m_bIsX11) {
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW.get(),
"XWayland Window Late");
PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW.get(),
@@ -573,7 +556,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) {
// don't swallow ourselves
std::regex rgx(*PSWALLOWREGEX);
- if (!std::regex_match(g_pXWaylandManager->getAppIDClass(PWINDOW), rgx)) {
+ if (!std::regex_match(PWINDOW->m_szClass, rgx)) {
// check parent
int ppid = getPPIDof(PWINDOW->getPID());
@@ -615,12 +598,12 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
if (finalFound) {
- bool valid = std::regex_match(g_pXWaylandManager->getAppIDClass(finalFound), rgx);
+ bool valid = std::regex_match(PWINDOW->m_szClass, rgx);
if (std::string{*PSWALLOWEXREGEX} != STRVAL_EMPTY) {
std::regex exc(*PSWALLOWEXREGEX);
- valid = valid && !std::regex_match(g_pXWaylandManager->getTitle(finalFound), exc);
+ valid = valid && !std::regex_match(PWINDOW->m_szTitle, exc);
}
// check if it's the window we want & not exempt from getting swallowed
@@ -644,7 +627,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goal(), PWINDOW->m_vRealSize.goal());
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
- g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, g_pXWaylandManager->getAppIDClass(PWINDOW), PWINDOW->m_szTitle)});
+ g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, PWINDOW->m_szClass, PWINDOW->m_szTitle)});
EMIT_HOOK_EVENT("openWindow", PWINDOW);
// apply data from default decos. Borders, shadows.
@@ -705,15 +688,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW);
if (!PWINDOW->m_bIsX11) {
- Debug::log(LOG, "Unregistered late callbacks XDG");
- PWINDOW->hyprListener_setTitleWindow.removeCallback();
- PWINDOW->hyprListener_requestMaximize.removeCallback();
- PWINDOW->hyprListener_requestMinimize.removeCallback();
- PWINDOW->hyprListener_requestMove.removeCallback();
- PWINDOW->hyprListener_requestResize.removeCallback();
- PWINDOW->hyprListener_fullscreenWindow.removeCallback();
- PWINDOW->hyprListener_ackConfigure.removeCallback();
- } else {
Debug::log(LOG, "Unregistered late callbacks XWL");
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
PWINDOW->hyprListener_activateX11.removeCallback();
@@ -804,29 +778,15 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->onUnmap();
}
-void Events::listener_ackConfigure(void* owner, void* data) {
- PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
- const auto E = (wlr_xdg_surface_configure*)data;
-
- // find last matching serial
- const auto SERIAL = std::find_if(PWINDOW->m_vPendingSizeAcks.rbegin(), PWINDOW->m_vPendingSizeAcks.rend(), [&](const auto& e) { return e.first == E->serial; });
-
- if (SERIAL == PWINDOW->m_vPendingSizeAcks.rend())
- return;
-
- PWINDOW->m_pPendingSizeAck = *SERIAL;
- std::erase_if(PWINDOW->m_vPendingSizeAcks, [&](const auto& el) { return el.first == SERIAL->first; });
-}
-
void Events::listener_commitWindow(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
- if (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->initial_commit) {
+ if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface->initialCommit) {
Vector2D predSize = g_pLayoutManager->getCurrentLayout()->predictSizeForNewWindow(PWINDOW);
Debug::log(LOG, "Layout predicts size {} for {}", predSize, PWINDOW);
- wlr_xdg_toplevel_set_size(PWINDOW->m_uSurface.xdg->toplevel, predSize.x, predSize.y);
+ PWINDOW->m_pXDGSurface->toplevel->setSize(predSize);
return;
}
@@ -841,8 +801,8 @@ void Events::listener_commitWindow(void* owner, void* data) {
}
if (!PWINDOW->m_bIsX11 && !PWINDOW->m_bIsFullscreen && PWINDOW->m_bIsFloating) {
- const auto MINSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.min_width, PWINDOW->m_uSurface.xdg->toplevel->current.min_height};
- const auto MAXSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.max_width, PWINDOW->m_uSurface.xdg->toplevel->current.max_height};
+ const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize;
+ const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize;
if (MAXSIZE > Vector2D{1, 1}) {
const auto REALSIZE = PWINDOW->m_vRealSize.goal();
@@ -861,7 +821,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + DELTA / 2.0;
PWINDOW->m_vRealSize = newSize;
- g_pXWaylandManager->setWindowSize(PWINDOW, newSize, true);
+ g_pXWaylandManager->setWindowSize(PWINDOW, newSize);
g_pHyprRenderer->damageWindow(PWINDOW);
}
}
@@ -918,11 +878,13 @@ void Events::listener_destroyWindow(void* owner, void* data) {
PWINDOW->hyprListener_associateX11.removeCallback();
PWINDOW->hyprListener_dissociateX11.removeCallback();
+ PWINDOW->listeners = {};
+
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
PWINDOW->m_bReadyToDelete = true;
- PWINDOW->m_uSurface.xdg = nullptr;
+ PWINDOW->m_pXDGSurface.reset();
if (!PWINDOW->m_bFadingOut) {
Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW);
@@ -936,31 +898,14 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
if (!validMapped(PWINDOW))
return;
- const auto NEWTITLE = g_pXWaylandManager->getTitle(PWINDOW);
-
- if (NEWTITLE == PWINDOW->m_szTitle)
- return;
-
- PWINDOW->m_szTitle = NEWTITLE;
- g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)PWINDOW.get())});
- EMIT_HOOK_EVENT("windowTitle", PWINDOW);
-
- if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) { // if it's the active, let's post an event to update others
- g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle});
- g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)PWINDOW.get())});
- EMIT_HOOK_EVENT("activeWindow", PWINDOW);
- }
-
- PWINDOW->updateDynamicRules();
- g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
- PWINDOW->updateToplevel();
-
- Debug::log(LOG, "Window {:x} set title to {}", PWINDOW, PWINDOW->m_szTitle);
+ PWINDOW->onUpdateMeta();
}
void Events::listener_fullscreenWindow(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
+ // x11 only
+
if (!PWINDOW->m_bIsMapped) {
PWINDOW->m_bWantsInitialFullscreen = true;
return;
@@ -971,41 +916,13 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
bool requestedFullState = false;
- if (!PWINDOW->m_bIsX11) {
- const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested;
-
- if (REQUESTED->fullscreen && PWINDOW->m_bIsFullscreen) {
- const auto PWORKSPACE = PWINDOW->m_pWorkspace;
- if (PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) {
- // Store that we were maximized
- PWINDOW->m_bWasMaximized = true;
- g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_MAXIMIZED);
- g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL);
- } else
- PWINDOW->m_bWasMaximized = false;
- } else if (REQUESTED->fullscreen != PWINDOW->m_bIsFullscreen && !PWINDOW->m_bFakeFullscreenState) {
- g_pCompositor->setWindowFullscreen(PWINDOW, REQUESTED->fullscreen, FULLSCREEN_FULL);
- if (PWINDOW->m_bWasMaximized && !REQUESTED->fullscreen) {
- // Was maximized before the fullscreen request, return now back to maximized instead of normal
- g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_MAXIMIZED);
- }
- }
-
- // Disable the maximize flag when we receive a de-fullscreen request
- PWINDOW->m_bWasMaximized &= REQUESTED->fullscreen;
-
- requestedFullState = REQUESTED->fullscreen;
-
- wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
- } else {
- if (!PWINDOW->m_uSurface.xwayland->surface->mapped)
- return;
+ if (!PWINDOW->m_uSurface.xwayland->surface->mapped)
+ return;
- if (!PWINDOW->m_bFakeFullscreenState)
- g_pCompositor->setWindowFullscreen(PWINDOW, PWINDOW->m_uSurface.xwayland->fullscreen, FULLSCREEN_FULL);
+ if (!PWINDOW->m_bFakeFullscreenState)
+ g_pCompositor->setWindowFullscreen(PWINDOW, PWINDOW->m_uSurface.xwayland->fullscreen, FULLSCREEN_FULL);
- requestedFullState = PWINDOW->m_uSurface.xwayland->fullscreen;
- }
+ requestedFullState = PWINDOW->m_uSurface.xwayland->fullscreen;
if (!requestedFullState && PWINDOW->m_bFakeFullscreenState) {
g_pXWaylandManager->setWindowFullscreen(PWINDOW, false); // fixes for apps expecting a de-fullscreen (e.g. ff)
@@ -1177,7 +1094,7 @@ void Events::listener_associateX11(void* owner, void* data) {
PWINDOW->hyprListener_mapWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.map, &Events::listener_mapWindow, PWINDOW.get(), "XWayland Window");
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.commit, &Events::listener_commitWindow, PWINDOW.get(), "XWayland Window");
- PWINDOW->m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(PWINDOW), PWINDOW);
+ PWINDOW->m_pWLSurface.assign(PWINDOW->m_uSurface.xwayland->surface, PWINDOW);
}
void Events::listener_dissociateX11(void* owner, void* data) {
@@ -1211,23 +1128,6 @@ void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW.get(), "XWayland Window");
}
-void Events::listener_newXDGToplevel(wl_listener* listener, void* data) {
- // A window got opened
- const auto XDGTOPLEVEL = (wlr_xdg_toplevel*)data;
- const auto XDGSURFACE = XDGTOPLEVEL->base;
-
- Debug::log(LOG, "New XDG Toplevel created. (class: {})", XDGSURFACE->toplevel->app_id ? XDGSURFACE->toplevel->app_id : "null");
-
- const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(CWindow::create());
- PNEWWINDOW->m_uSurface.xdg = XDGSURFACE;
-
- PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->surface->events.map, &Events::listener_mapWindow, PNEWWINDOW.get(), "XDG Window");
- PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XDGSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW.get(), "XDG Window");
- PNEWWINDOW->hyprListener_commitWindow.initCallback(&XDGSURFACE->surface->events.commit, &Events::listener_commitWindow, PNEWWINDOW.get(), "XDG Window");
-
- PNEWWINDOW->m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(PNEWWINDOW), PNEWWINDOW);
-}
-
void Events::listener_requestMaximize(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
@@ -1240,7 +1140,6 @@ void Events::listener_requestMaximize(void* owner, void* data) {
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen,
FULLSCREEN_MAXIMIZED); // this will be rejected if there already is a fullscreen window
- wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
} else {
if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1)
return;
@@ -1269,17 +1168,3 @@ void Events::listener_requestMinimize(void* owner, void* data) {
EMIT_HOOK_EVENT("minimize", (std::vector<std::any>{PWINDOW, (int64_t)(1)}));
}
}
-
-void Events::listener_requestMove(void* owner, void* data) {
- PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
-
- // ignore
- wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
-}
-
-void Events::listener_requestResize(void* owner, void* data) {
- PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
-
- // ignore
- wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
-}
diff --git a/src/includes.hpp b/src/includes.hpp
index c75796b9..dfbe0221 100644
--- a/src/includes.hpp
+++ b/src/includes.hpp
@@ -52,8 +52,6 @@ extern "C" {
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_primary_selection_v1.h>
#include <wlr/types/wlr_viewporter.h>
-#include <wlr/types/wlr_xdg_output_v1.h>
-#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_damage_ring.h>
#include <wlr/util/log.h>
diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp
index 6f7252d2..a31180e1 100644
--- a/src/layout/IHyprLayout.cpp
+++ b/src/layout/IHyprLayout.cpp
@@ -4,6 +4,7 @@
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../config/ConfigValue.hpp"
#include "../desktop/Window.hpp"
+#include "../protocols/XDGShell.hpp"
void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) {
@@ -140,8 +141,12 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
// TODO: detect a popup in a more consistent way.
if ((desiredGeometry.x == 0 && desiredGeometry.y == 0) || !visible || !pWindow->m_bIsX11) {
- // if it's not, fall back to the center placement
- pWindow->m_vRealPosition = PMONITOR->vecPosition + Vector2D((PMONITOR->vecSize.x - desiredGeometry.width) / 2.f, (PMONITOR->vecSize.y - desiredGeometry.height) / 2.f);
+ // if the pos isn't set, fall back to the center placement if it's not a child, otherwise middle of parent if available
+ if (!pWindow->m_bIsX11 && pWindow->m_pXDGSurface->toplevel->parent && validMapped(pWindow->m_pXDGSurface->toplevel->parent->window))
+ pWindow->m_vRealPosition = pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealPosition.goal() +
+ pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealSize.goal() / 2.F - desiredGeometry.size() / 2.F;
+ else
+ pWindow->m_vRealPosition = PMONITOR->vecPosition + desiredGeometry.size() / 2.F;
} else {
// if it is, we respect where it wants to put itself, but apply monitor offset if outside
// most of these are popups
@@ -693,7 +698,7 @@ Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) {
else
sizePredicted = predictSizeForNewWindowFloating(pWindow);
- Vector2D maxSize = Vector2D{pWindow->m_uSurface.xdg->toplevel->pending.max_width, pWindow->m_uSurface.xdg->toplevel->pending.max_height};
+ Vector2D maxSize = pWindow->m_pXDGSurface->toplevel->pending.maxSize;
if ((maxSize.x > 0 && maxSize.x < sizePredicted.x) || (maxSize.y > 0 && maxSize.y < sizePredicted.y))
sizePredicted = {};
diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp
index f853e16f..e53eb111 100644
--- a/src/managers/ProtocolManager.cpp
+++ b/src/managers/ProtocolManager.cpp
@@ -29,6 +29,7 @@
#include "../protocols/LayerShell.hpp"
#include "../protocols/PresentationTime.hpp"
#include "../protocols/core/Seat.hpp"
+#include "../protocols/XDGShell.hpp"
CProtocolManager::CProtocolManager() {
@@ -64,6 +65,7 @@ CProtocolManager::CProtocolManager() {
PROTO::tablet = std::make_unique<CTabletV2Protocol>(&zwp_tablet_manager_v2_interface, 1, "TabletV2");
PROTO::layerShell = std::make_unique<CLayerShellProtocol>(&zwlr_layer_shell_v1_interface, 5, "LayerShell");
PROTO::presentation = std::make_unique<CPresentationProtocol>(&wp_presentation_interface, 1, "Presentation");
+ PROTO::xdgShell = std::make_unique<CXDGShellProtocol>(&xdg_wm_base_interface, 6, "XDGShell");
// Old protocol implementations.
// TODO: rewrite them to use hyprwayland-scanner.
diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp
index 423c45ca..390c6ece 100644
--- a/src/managers/XWaylandManager.cpp
+++ b/src/managers/XWaylandManager.cpp
@@ -2,6 +2,7 @@
#include "../Compositor.hpp"
#include "../events/Events.hpp"
#include "../config/ConfigValue.hpp"
+#include "../protocols/XDGShell.hpp"
#define OUTPUT_MANAGER_VERSION 3
#define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3
@@ -34,27 +35,32 @@ CHyprXWaylandManager::~CHyprXWaylandManager() {
}
wlr_surface* CHyprXWaylandManager::getWindowSurface(PHLWINDOW pWindow) {
- if (pWindow->m_bIsX11)
- return pWindow->m_uSurface.xwayland->surface;
-
- return pWindow->m_uSurface.xdg->surface;
+ return pWindow->m_pWLSurface.wlr();
}
void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) {
if (!pSurface)
return;
- if (wlr_xdg_surface_try_from_wlr_surface(pSurface)) {
- if (const auto PSURF = wlr_xdg_surface_try_from_wlr_surface(pSurface); PSURF && PSURF->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL)
- wlr_xdg_toplevel_set_activated(PSURF->toplevel, activate);
-
- } else if (wlr_xwayland_surface_try_from_wlr_surface(pSurface)) {
+ if (wlr_xwayland_surface_try_from_wlr_surface(pSurface)) {
const auto XSURF = wlr_xwayland_surface_try_from_wlr_surface(pSurface);
wlr_xwayland_surface_activate(XSURF, activate);
if (activate && !XSURF->override_redirect)
wlr_xwayland_surface_restack(XSURF, nullptr, XCB_STACK_MODE_ABOVE);
}
+
+ // TODO:
+ // this cannot be nicely done until we rewrite wlr_surface
+ for (auto& w : g_pCompositor->m_vWindows) {
+ if (w->m_bIsX11 || !w->m_bIsMapped)
+ continue;
+
+ if (w->m_pWLSurface.wlr() != pSurface)
+ continue;
+
+ w->m_pXDGSurface->toplevel->setActive(activate);
+ }
}
void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) {
@@ -68,8 +74,8 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) {
}
wlr_xwayland_surface_activate(pWindow->m_uSurface.xwayland, activate);
- } else
- wlr_xdg_toplevel_set_activated(pWindow->m_uSurface.xdg->toplevel, activate);
+ } else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel)
+ pWindow->m_pXDGSurface->toplevel->setActive(activate);
if (activate) {
g_pCompositor->m_pLastFocus = getWindowSurface(pWindow);
@@ -95,64 +101,15 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) {
pbox->width = pWindow->m_uSurface.xwayland->width;
pbox->height = pWindow->m_uSurface.xwayland->height;
}
- } else {
- wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, pbox->pWlr());
- pbox->applyFromWlr();
- }
-}
-
-std::string CHyprXWaylandManager::getTitle(PHLWINDOW pWindow) {
- try {
- if (pWindow->m_bIsX11) {
- if (!pWindow->m_bIsMapped)
- return "";
-
- if (pWindow->m_uSurface.xwayland && pWindow->m_uSurface.xwayland->title) {
- return std::string(pWindow->m_uSurface.xwayland->title);
- }
- } else if (pWindow->m_uSurface.xdg) {
- if (pWindow->m_bFadingOut || !pWindow->m_uSurface.xdg)
- return "";
-
- if (pWindow->m_uSurface.xdg->toplevel && pWindow->m_uSurface.xdg->toplevel->title) {
- return std::string(pWindow->m_uSurface.xdg->toplevel->title);
- }
- } else {
- return "";
- }
- } catch (...) { Debug::log(ERR, "Error in getTitle (probably null title)"); }
-
- return "";
-}
-
-std::string CHyprXWaylandManager::getAppIDClass(PHLWINDOW pWindow) {
- try {
- if (pWindow->m_bIsX11) {
- if (!pWindow->m_bIsMapped)
- return "";
-
- if (pWindow->m_uSurface.xwayland && pWindow->m_uSurface.xwayland->_class) {
- return std::string(pWindow->m_uSurface.xwayland->_class);
- }
- } else if (pWindow->m_uSurface.xdg) {
- if (pWindow->m_bFadingOut || !pWindow->m_uSurface.xdg)
- return "";
-
- if (pWindow->m_uSurface.xdg->toplevel && pWindow->m_uSurface.xdg->toplevel->app_id) {
- return std::string(pWindow->m_uSurface.xdg->toplevel->app_id);
- }
- } else
- return "";
- } catch (std::logic_error& e) { Debug::log(ERR, "Error in getAppIDClass: {}", e.what()); }
-
- return "";
+ } else if (pWindow->m_pXDGSurface)
+ *pbox = pWindow->m_pXDGSurface->current.geometry;
}
void CHyprXWaylandManager::sendCloseWindow(PHLWINDOW pWindow) {
if (pWindow->m_bIsX11)
wlr_xwayland_surface_close(pWindow->m_uSurface.xwayland);
- else
- wlr_xdg_toplevel_send_close(pWindow->m_uSurface.xdg->toplevel);
+ else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel)
+ pWindow->m_pXDGSurface->toplevel->close();
}
void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool force) {
@@ -189,23 +146,12 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool
if (pWindow->m_bIsX11)
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, windowPos.x, windowPos.y, size.x, size.y);
- else
- pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(wlr_xdg_toplevel_set_size(pWindow->m_uSurface.xdg->toplevel, size.x, size.y), size.floor()));
-}
-
-void CHyprXWaylandManager::setWindowStyleTiled(PHLWINDOW pWindow, uint32_t edgez) {
- if (pWindow->m_bIsX11)
- return;
-
- wlr_xdg_toplevel_set_tiled(pWindow->m_uSurface.xdg->toplevel, edgez);
- wlr_xdg_toplevel_set_maximized(pWindow->m_uSurface.xdg->toplevel, true);
+ else if (pWindow->m_pXDGSurface->toplevel)
+ pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor()));
}
wlr_surface* CHyprXWaylandManager::surfaceAt(PHLWINDOW pWindow, const Vector2D& client, Vector2D& surface) {
- if (pWindow->m_bIsX11)
- return wlr_surface_surface_at(pWindow->m_uSurface.xwayland->surface, client.x, client.y, &surface.x, &surface.y);
-
- return wlr_xdg_surface_surface_at(pWindow->m_uSurface.xdg, client.x, client.y, &surface.x, &surface.y);
+ return wlr_surface_surface_at(pWindow->m_pWLSurface.wlr(), client.x, client.y, &surface.x, &surface.y);
}
bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) {
@@ -251,10 +197,10 @@ bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) {
if (SIZEHINTS && (pWindow->m_uSurface.xwayland->parent || ((SIZEHINTS->min_width == SIZEHINTS->max_width) && (SIZEHINTS->min_height == SIZEHINTS->max_height))))
return true;
} else {
- const auto PSTATE = pending ? &pWindow->m_uSurface.xdg->toplevel->pending : &pWindow->m_uSurface.xdg->toplevel->current;
+ const auto PSTATE = pending ? &pWindow->m_pXDGSurface->toplevel->pending : &pWindow->m_pXDGSurface->toplevel->current;
- if ((PSTATE->min_width != 0 && PSTATE->min_height != 0 && (PSTATE->min_width == PSTATE->max_width || PSTATE->min_height == PSTATE->max_height)) ||
- pWindow->m_uSurface.xdg->toplevel->parent)
+ if (pWindow->m_pXDGSurface->toplevel->parent ||
+ (PSTATE->minSize.x != 0 && PSTATE->minSize.y != 0 && (PSTATE->minSize.x == PSTATE->maxSize.x || PSTATE->minSize.y == PSTATE->maxSize.y)))
return true;
}
@@ -297,20 +243,19 @@ void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) {
void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscreen) {
if (pWindow->m_bIsX11)
wlr_xwayland_surface_set_fullscreen(pWindow->m_uSurface.xwayland, fullscreen);
- else
- wlr_xdg_toplevel_set_fullscreen(pWindow->m_uSurface.xdg->toplevel, fullscreen);
+ else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel)
+ pWindow->m_pXDGSurface->toplevel->setFullscreen(fullscreen);
}
Vector2D CHyprXWaylandManager::getMaxSizeForWindow(PHLWINDOW pWindow) {
if (!validMapped(pWindow))
return Vector2D(99999, 99999);
- if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel) ||
- pWindow->m_sAdditionalConfigData.noMaxSize)
+ if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize)
return Vector2D(99999, 99999);
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->max_width, pWindow->m_uSurface.xwayland->size_hints->max_height) :
- Vector2D(pWindow->m_uSurface.xdg->toplevel->current.max_width, pWindow->m_uSurface.xdg->toplevel->current.max_height);
+ pWindow->m_pXDGSurface->toplevel->current.maxSize;
if (MAXSIZE.x < 5)
MAXSIZE.x = 99999;
@@ -324,11 +269,11 @@ Vector2D CHyprXWaylandManager::getMinSizeForWindow(PHLWINDOW pWindow) {
if (!validMapped(pWindow))
return Vector2D(0, 0);
- if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel))
+ if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel))
return Vector2D(0, 0);
auto MINSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->min_width, pWindow->m_uSurface.xwayland->size_hints->min_height) :
- Vector2D(pWindow->m_uSurface.xdg->toplevel->current.min_width, pWindow->m_uSurface.xdg->toplevel->current.min_height);
+ pWindow->m_pXDGSurface->toplevel->current.minSize;
MINSIZE = MINSIZE.clamp({1, 1});
diff --git a/src/managers/XWaylandManager.hpp b/src/managers/XWaylandManager.hpp
index 6edadd71..8889eb61 100644
--- a/src/managers/XWaylandManager.hpp
+++ b/src/managers/XWaylandManager.hpp
@@ -17,11 +17,8 @@ class CHyprXWaylandManager {
void activateSurface(wlr_surface*, bool);
void activateWindow(PHLWINDOW, bool);
void getGeometryForWindow(PHLWINDOW, CBox*);
- std::string getTitle(PHLWINDOW);
- std::string getAppIDClass(PHLWINDOW);
void sendCloseWindow(PHLWINDOW);
void setWindowSize(PHLWINDOW, Vector2D, bool force = false);
- void setWindowStyleTiled(PHLWINDOW, uint32_t);
void setWindowFullscreen(PHLWINDOW, bool);
wlr_surface* surfaceAt(PHLWINDOW, const Vector2D&, Vector2D&);
bool shouldBeFloated(PHLWINDOW, bool pending = false);
diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
index 62d9e687..bb0ab65a 100644
--- a/src/managers/input/InputManager.cpp
+++ b/src/managers/input/InputManager.cpp
@@ -15,6 +15,7 @@
#include "../../protocols/VirtualPointer.hpp"
#include "../../protocols/LayerShell.hpp"
#include "../../protocols/core/Seat.hpp"
+#include "../../protocols/XDGShell.hpp"
#include "../../devices/Mouse.hpp"
#include "../../devices/VirtualPointer.hpp"
@@ -387,10 +388,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (pFoundWindow && !pFoundWindow->m_bIsX11 && surfacePos != Vector2D(-1337, -1337)) {
// calc for oversized windows... fucking bullshit.
- wlr_box geom;
- wlr_xdg_surface_get_geometry(pFoundWindow->m_uSurface.xdg, &geom);
+ CBox geom = pFoundWindow->m_pXDGSurface->current.geometry;
- surfaceLocal = mouseCoords - surfacePos + Vector2D(geom.x, geom.y);
+ surfaceLocal = mouseCoords - surfacePos + geom.pos();
}
if (pFoundWindow && pFoundWindow->m_bIsX11) // for x11 force scale zero
diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp
index 0d2a7e57..40420da7 100644
--- a/src/protocols/ForeignToplevel.cpp
+++ b/src/protocols/ForeignToplevel.cpp
@@ -91,7 +91,7 @@ void CForeignToplevelList::onClass(PHLWINDOW pWindow) {
if (!H || H->closed)
return;
- H->resource->sendAppId(g_pXWaylandManager->getAppIDClass(pWindow).c_str());
+ H->resource->sendAppId(pWindow->m_szClass.c_str());
}
void CForeignToplevelList::onUnmap(PHLWINDOW pWindow) {
diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp
index 1762ad2a..782fbc0e 100644
--- a/src/protocols/ForeignToplevelWlr.cpp
+++ b/src/protocols/ForeignToplevelWlr.cpp
@@ -195,7 +195,7 @@ void CForeignToplevelWlrManager::onMap(PHLWINDOW pWindow) {
LOGM(LOG, "Newly mapped window {:016x}", (uintptr_t)pWindow.get());
resource->sendToplevel(NEWHANDLE->resource.get());
- NEWHANDLE->resource->sendAppId(g_pXWaylandManager->getAppIDClass(pWindow).c_str());
+ NEWHANDLE->resource->sendAppId(pWindow->m_szClass.c_str());
NEWHANDLE->resource->sendTitle(pWindow->m_szTitle.c_str());
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); PMONITOR)
NEWHANDLE->sendMonitor(PMONITOR);
@@ -231,7 +231,7 @@ void CForeignToplevelWlrManager::onClass(PHLWINDOW pWindow) {
if (!H || H->closed)
return;
- H->resource->sendAppId(g_pXWaylandManager->getAppIDClass(pWindow).c_str());
+ H->resource->sendAppId(pWindow->m_szClass.c_str());
H->resource->sendDone();
}
diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp
index ced765fd..962b89a3 100644
--- a/src/protocols/LayerShell.cpp
+++ b/src/protocols/LayerShell.cpp
@@ -1,5 +1,6 @@
#include "LayerShell.hpp"
#include "../Compositor.hpp"
+#include "XDGShell.hpp"
#define LOGM PROTO::layerShell->protoLog
@@ -118,14 +119,14 @@ CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, wlr_
});
resource->setGetPopup([this](CZwlrLayerSurfaceV1* r, wl_resource* popup_) {
- auto popup = wlr_xdg_popup_from_resource(popup_);
+ auto popup = CXDGPopupResource::fromResource(popup_);
- if (popup->parent) {
+ if (popup->taken) {
r->error(-1, "Parent already exists!");
return;
}
- popup->parent = surface;
+ popup->taken = true;
events.newPopup.emit(popup);
});
diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp
new file mode 100644
index 00000000..fcb2d63b
--- /dev/null
+++ b/src/protocols/XDGShell.cpp
@@ -0,0 +1,697 @@
+#include "XDGShell.hpp"
+#include <algorithm>
+#include "../Compositor.hpp"
+
+#define LOGM PROTO::xdgShell->protoLog
+
+CXDGPopupResource::CXDGPopupResource(SP<CXdgPopup> resource_, SP<CXDGSurfaceResource> owner_, SP<CXDGSurfaceResource> surface_, SP<CXDGPositionerResource> positioner) :
+ surface(surface_), parent(owner_), resource(resource_), positionerRules(positioner) {
+ if (!good())
+ return;
+
+ resource->setData(this);
+
+ resource->setDestroy([this](CXdgPopup* r) {
+ if (surface && surface->mapped)
+ surface->events.unmap.emit();
+ events.destroy.emit();
+ PROTO::xdgShell->destroyResource(this);
+ });
+ resource->setOnDestroy([this](CXdgPopup* r) {
+ if (surface && surface->mapped)
+ surface->events.unmap.emit();
+ events.destroy.emit();
+ PROTO::xdgShell->destroyResource(this);
+ });
+
+ resource->setReposition([this](CXdgPopup* r, wl_resource* positionerRes, uint32_t token) {
+ LOGM(LOG, "Popup {:x} asks for reposition", (uintptr_t)this);
+ lastRepositionToken = token;
+ auto pos = CXDGPositionerResource::fromResource(positionerRes);
+ if (!pos)
+ return;
+ positionerRules = CXDGPositionerRules{pos};
+ events.reposition.emit();
+ });
+
+ if (parent)
+ taken = true;
+}
+
+CXDGPopupResource::~CXDGPopupResource() {
+ events.destroy.emit();
+}
+
+void CXDGPopupResource::applyPositioning(const CBox& box, const Vector2D& t1coord) {
+ CBox constraint = box.copy().translate(surface->pending.geometry.pos());
+
+ geometry = positionerRules.getPosition(constraint, accumulateParentOffset() + t1coord);
+
+ LOGM(LOG, "Popup {:x} gets unconstrained to {} {}", (uintptr_t)this, geometry.pos(), geometry.size());
+
+ configure(geometry);
+
+ if (lastRepositionToken)
+ repositioned();
+}
+
+Vector2D CXDGPopupResource::accumulateParentOffset() {
+ SP<CXDGSurfaceResource> current = parent.lock();
+ Vector2D off;
+ while (current) {
+ off += current->current.geometry.pos();
+ if (current->popup) {
+ off += current->popup->geometry.pos();
+ current = current->popup->parent.lock();
+ } else
+ break;
+ }
+ return off;
+}
+
+SP<CXDGPopupResource> CXDGPopupResource::fromResource(wl_resource* res) {
+ auto data = (CXDGPopupResource*)(((CXdgPopup*)wl_resource_get_user_data(res))->data());
+ return data ? data->self.lock() : nullptr;
+}
+
+bool CXDGPopupResource::good() {
+ return resource->resource();
+}
+
+void CXDGPopupResource::configure(const CBox& box) {
+ resource->sendConfigure(box.x, box.y, box.w, box.h);
+ if (surface)
+ surface->scheduleConfigure();
+}
+
+void CXDGPopupResource::done() {
+ resource->sendPopupDone();
+}
+
+void CXDGPopupResource::repositioned() {
+ if (!lastRepositionToken)
+ return;
+
+ LOGM(LOG, "repositioned: sending reposition token {}", lastRepositionToken);
+
+ resource->sendRepositioned(lastRepositionToken);
+ lastRepositionToken = 0;
+}
+
+CXDGToplevelResource::CXDGToplevelResource(SP<CXdgToplevel> resource_, SP<CXDGSurfaceResource> owner_) : owner(owner_), resource(resource_) {
+ if (!good())
+ return;
+
+ resource->setData(this);
+
+ resource->setDestroy([this](CXdgToplevel* r) {
+ events.destroy.emit();
+ PROTO::xdgShell->destroyResource(this);
+ });
+ resource->setOnDestroy([this](CXdgToplevel* r) {
+ events.destroy.emit();
+ PROTO::xdgShell->destroyResource(this);
+ });
+
+ if (resource->version() >= 5) {
+ wl_array arr;
+ wl_array_init(&arr);
+ auto p = (uint32_t*)wl_array_add(&arr, sizeof(uint32_t));
+ *p = XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN;
+ p = (uint32_t*)wl_array_add(&arr, sizeof(uint32_t));
+ *p = XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE;
+ resource->sendWmCapabilities(&arr);
+ wl_array_release(&arr);
+ }
+
+ pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_LEFT);
+ pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_RIGHT);
+ pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_TOP);
+ pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_BOTTOM);
+
+ resource->setSetTitle([this](CXdgToplevel* r, const char* t) {
+ state.title = t;
+ events.metadataChanged.emit();
+ });
+
+ resource->setSetAppId([this](CXdgToplevel* r, const char* id) {
+ state.appid = id;
+ events.metadataChanged.emit();
+ });
+
+ resource->setSetMaxSize([this](CXdgToplevel* r, int32_t x, int32_t y) {
+ pending.maxSize = {x, y};
+ events.sizeLimitsChanged.emit();
+ });
+
+ resource->setSetMinSize([this](CXdgToplevel* r, int32_t x, int32_t y) {
+ pending.minSize = {x, y};
+ events.sizeLimitsChanged.emit();
+ });
+
+ resource->setSetMaximized([this](CXdgToplevel* r) {
+ state.requestsMaximize = true;
+ events.stateChanged.emit();
+ state.requestsMaximize.reset();
+ });
+
+ resource->setUnsetMaximized([this](CXdgToplevel* r) {
+ state.requestsMaximize = false;
+ events.stateChanged.emit();
+ state.requestsMaximize.reset();
+ });
+
+ resource->setSetFullscreen([this](CXdgToplevel* r, wl_resource* output) {
+ state.requestsFullscreen = true;
+ events.stateChanged.emit();
+ state.requestsFullscreen.reset();
+ });
+
+ resource->setUnsetFullscreen([this](CXdgToplevel* r) {
+ state.requestsFullscreen = false;
+ events.stateChanged.emit();
+ state.requestsFullscreen.reset();
+ });
+
+ resource->setSetMinimized([this](CXdgToplevel* r) {
+ state.requestsMinimize = true;
+ events.stateChanged.emit();
+ state.requestsFullscreen.reset();
+ });
+
+ resource->setSetParent([this](CXdgToplevel* r, wl_resource* parentR) {
+ auto newp = parentR ? CXDGToplevelResource::fromResource(parentR) : nullptr;
+ parent = newp;
+
+ LOGM(LOG, "Toplevel {:x} sets parent to {:x}", (uintptr_t)this, (uintptr_t)newp.get());
+ });
+}
+
+CXDGToplevelResource::~CXDGToplevelResource() {
+ events.destroy.emit();
+}
+
+SP<CXDGToplevelResource> CXDGToplevelResource::fromResource(wl_resource* res) {
+ auto data = (CXDGToplevelResource*)(((CXdgToplevel*)wl_resource_get_user_data(res))->data());
+ return data ? data->self.lock() : nullptr;
+}
+
+bool CXDGToplevelResource::good() {
+ return resource->resource();
+}
+
+uint32_t CXDGToplevelResource::setSize(const Vector2D& size) {
+ pendingApply.size = size;
+ applyState();
+ return owner->scheduleConfigure();
+}
+
+uint32_t CXDGToplevelResource::setMaximized(bool maximized) {
+ bool set = std::find(pendingApply.states.begin(), pendingApply.states.end(), XDG_TOPLEVEL_STATE_MAXIMIZED) != pendingApply.states.end();
+
+ if (maximized == set)
+ return owner->scheduledSerial;
+
+ if (maximized && !set)
+ pendingApply.states.push_back(XDG_TOPLEVEL_STATE_MAXIMIZED);
+ else if (!maximized && set)
+ std::erase(pendingApply.states, XDG_TOPLEVEL_STATE_MAXIMIZED);
+ applyState();
+ return owner->scheduleConfigure();
+}
+
+uint32_t CXDGToplevelResource::setFullscreen(bool fullscreen) {
+ bool set = std::find(pendingApply.states.begin(), pendingApply.states.end(), XDG_TOPLEVEL_STATE_FULLSCREEN) != pendingApply.states.end();
+
+ if (fullscreen == set)
+ return owner->scheduledSerial;
+
+ if (fullscreen && !set)
+ pendingApply.states.push_back(XDG_TOPLEVEL_STATE_FULLSCREEN);
+ else if (!fullscreen && set)
+ std::erase(pendingApply.states, XDG_TOPLEVEL_STATE_FULLSCREEN);
+ applyState();
+ return owner->scheduleConfigure();
+}
+
+uint32_t CXDGToplevelResource::setActive(bool active) {
+ bool set = std::find(pendingApply.states.begin(), pendingApply.states.end(), XDG_TOPLEVEL_STATE_ACTIVATED) != pendingApply.states.end();
+
+ if (active == set)
+ return owner->scheduledSerial;
+
+ if (active && !set)
+ pendingApply.states.push_back(XDG_TOPLEVEL_STATE_ACTIVATED);
+ else if (!active && set)
+ std::erase(pendingApply.states, XDG_TOPLEVEL_STATE_ACTIVATED);
+ applyState();
+ return owner->scheduleConfigure();
+}
+
+uint32_t CXDGToplevelResource::setSuspeneded(bool sus) {
+ bool set = std::find(pendingApply.states.begin(), pendingApply.states.end(), XDG_TOPLEVEL_STATE_SUSPENDED) != pendingApply.states.end();
+
+ if (sus == set)
+ return owner->scheduledSerial;
+
+ if (sus && !set)
+ pendingApply.states.push_back(XDG_TOPLEVEL_STATE_SUSPENDED);
+ else if (!sus && set)
+ std::erase(pendingApply.states, XDG_TOPLEVEL_STATE_SUSPENDED);
+ applyState();
+ return owner->scheduleConfigure();
+}
+
+void CXDGToplevelResource::applyState() {
+ wl_array arr;
+ wl_array_init(&arr);
+ wl_array_add(&arr, pendingApply.states.size() * sizeof(int));
+ memcpy(arr.data, pendingApply.states.data(), pendingApply.states.size() * sizeof(int));
+
+ resource->sendConfigure(pendingApply.size.x, pendingApply.size.y, &arr);
+
+ wl_array_release(&arr);
+}
+
+void CXDGToplevelResource::close() {
+ resource->sendClose();
+}
+
+CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, wlr_surface* surface_) : owner(owner_), surface(surface_), resource(resource_) {
+ if (!good())
+ return;
+
+ resource->setData(this);
+
+ resource->setDestroy([this](CXdgSurface* r) {
+ if (mapped)
+ events.unmap.emit();
+ events.destroy.emit();
+ PROTO::xdgShell->destroyResource(this);
+ });
+ resource->setOnDestroy([this](CXdgSurface* r) {
+ if (mapped)
+ events.unmap.emit();
+ events.destroy.emit();
+ PROTO::xdgShell->destroyResource(this);
+ });
+
+ hyprListener_surfaceDestroy.initCallback(
+ &surface->events.destroy,
+ [this](void* owner, void* data) {
+ LOGM(WARN, "wl_surface destroyed before its xdg_surface role object");
+ hyprListener_surfaceDestroy.removeCallback();
+ hyprListener_surfaceCommit.removeCallback();
+
+ if (mapped)
+ events.unmap.emit();
+
+ mapped = false;
+ surface = nullptr;
+ events.destroy.emit();
+ },
+ nullptr, "CXDGSurfaceResource");
+
+ hyprListener_surfaceCommit.initCallback(
+ &surface->events.commit,
+ [this](void* owner, void* data) {
+ current = pending;
+ if (toplevel)
+ toplevel->current = toplevel->pending;
+
+ if (initialCommit && surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0) {
+ resource->error(-1, "Buffer attached before initial commit");
+ return;
+ }
+
+ if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0 && !mapped) {
+ // this forces apps to not draw CSD.
+ if (toplevel)
+ toplevel->setMaximized(true);
+
+ mapped = true;
+ wlr_surface_map(surface);
+ events.map.emit();
+ return;
+ }
+
+ if (surface->pending.buffer_width <= 0 && surface->pending.buffer_height <= 0 && mapped) {
+ mapped = false;
+ wlr_surface_unmap(surface);
+ events.unmap.emit();
+ return;
+ }
+
+ events.commit.emit();
+ initialCommit = false;
+ },
+ nullptr, "CXDGSurfaceResource");
+
+ resource->setGetToplevel([this](CXdgSurface* r, uint32_t id) {
+ const auto RESOURCE = PROTO::xdgShell->m_vToplevels.emplace_back(makeShared<CXDGToplevelResource>(makeShared<CXdgToplevel>(r->client(), r->version(), id), self.lock()));
+
+ if (!RESOURCE->good()) {
+ r->noMemory();
+ PROTO::xdgShell->m_vToplevels.pop_back();
+ return;
+ }
+
+ toplevel = RESOURCE;
+ toplevel->self = RESOURCE;
+
+ LOGM(LOG, "xdg_surface {:x} gets a toplevel {:x}", (uintptr_t)owner.get(), (uintptr_t)RESOURCE.get());
+
+ g_pCompositor->m_vWindows.emplace_back(CWindow::create(self.lock()));
+
+ for (auto& p : popups) {
+ if (!p)
+ continue;
+ events.newPopup.emit(p);
+ }
+ });
+
+ resource->setGetPopup([this](CXdgSurface* r, uint32_t id, wl_resource* parentXDG, wl_resource* positionerRes) {
+ auto parent = parentXDG ? CXDGSurfaceResource::fromResource(parentXDG) : nullptr;
+ auto positioner = CXDGPositionerResource::fromResource(positionerRes);
+ const auto RESOURCE =
+ PROTO::xdgShell->m_vPopups.emplace_back(makeShared<CXDGPopupResource>(makeShared<CXdgPopup>(r->client(), r->version(), id), parent, self.lock(), positioner));
+
+ if (!RESOURCE->good()) {
+ r->noMemory();
+ PROTO::xdgShell->m_vPopups.pop_back();
+ return;
+ }
+
+ popup = RESOURCE;
+ RESOURCE->self = RESOURCE;
+
+ LOGM(LOG, "xdg_surface {:x} gets a popup {:x} owner {:x}", (uintptr_t)self.get(), (uintptr_t)RESOURCE.get(), (uintptr_t)parent.get());
+
+ if (!parent)
+ return;
+
+ parent->popups.emplace_back(RESOURCE);
+ if (parent->mapped)
+ parent->events.newPopup.emit(RESOURCE);
+ });
+
+ resource->setAckConfigure([this](CXdgSurface* r, uint32_t serial) {
+ events.ack.emit(serial);
+ ; // TODO: verify it
+ });
+
+ resource->setSetWindowGeometry([this](CXdgSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) {
+ LOGM(LOG, "xdg_surface {:x} requests geometry {}x{} {}x{}", (uintptr_t)this, x, y, w, h);
+ pending.geometry = {x, y, w, h};
+ });
+}
+
+CXDGSurfaceResource::~CXDGSurfaceResource() {
+ events.destroy.emit();
+ if (configureSource)
+ wl_event_source_remove(configureSource);
+}
+
+bool CXDGSurfaceResource::good() {
+ return resource->resource();
+}
+
+SP<CXDGSurfaceResource> CXDGSurfaceResource::fromResource(wl_resource* res) {
+ auto data = (CXDGSurfaceResource*)(((CXdgSurface*)wl_resource_get_user_data(res))->data());
+ return data ? data->self.lock() : nullptr;
+}
+
+static void onConfigure(void* data) {
+ ((CXDGSurfaceResource*)data)->configure();
+}
+
+uint32_t CXDGSurfaceResource::scheduleConfigure() {
+ if (configureSource)
+ return scheduledSerial;
+
+ configureSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, onConfigure, this);
+ scheduledSerial = wl_display_next_serial(g_pCompositor->m_sWLDisplay);
+
+ return scheduledSerial;
+}
+
+void CXDGSurfaceResource::configure() {
+ configureSource = nullptr;
+ resource->sendConfigure(scheduledSerial);
+}
+
+CXDGPositionerResource::CXDGPositionerResource(SP<CXdgPositioner> resource_, SP<CXDGWMBase> owner_) : owner(owner_), resource(resource_) {
+ if (!good())
+ return;
+
+ resource->setData(this);
+
+ resource->setDestroy([this](CXdgPositioner* r) { PROTO::xdgShell->destroyResource(this); });
+ resource->setOnDestroy([this](CXdgPositioner* r) { PROTO::xdgShell->destroyResource(this); });
+
+ resource->setSetSize([this](CXdgPositioner* r, int32_t x, int32_t y) {
+ if (x <= 0 || y <= 0) {
+ r->error(XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid size");
+ return;
+ }
+
+ state.requestedSize = {x, y};
+ });
+
+ resource->setSetAnchorRect([this](CXdgPositioner* r, int32_t x, int32_t y, int32_t w, int32_t h) {
+ if (w <= 0 || h <= 0) {
+ r->error(XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid box");
+ return;
+ }
+
+ state.anchorRect = {x, y, w, h};
+ });
+
+ resource->setSetOffset([this](CXdgPositioner* r, int32_t x, int32_t y) { state.offset = {x, y}; });
+
+ resource->setSetAnchor([this](CXdgPositioner* r, xdgPositionerAnchor a) { state.anchor = a; });
+
+ resource->setSetGravity([this](CXdgPositioner* r, xdgPositionerGravity g) { state.gravity = g; });
+
+ resource->setSetConstraintAdjustment([this](CXdgPositioner* r, xdgPositionerConstraintAdjustment a) { state.constraintAdjustment = (uint32_t)a; });
+
+ // TODO: support this shit better. The current impl _works_, but is lacking and could be wrong in a few cases.
+ // doesn't matter _that_ much for now, though.
+}
+
+SP<CXDGPositionerResource> CXDGPositionerResource::fromResource(wl_resource* res) {
+ auto data = (CXDGPositionerResource*)(((CXdgPositioner*)wl_resource_get_user_data(res))->data());
+ return data ? data->self.lock() : nullptr;
+}
+
+bool CXDGPositionerResource::good() {
+ return resource->resource();
+}
+
+CXDGPositionerRules::CXDGPositionerRules(SP<CXDGPositionerResource> positioner) {
+ state = positioner->state;
+}
+
+static Vector2D pointForAnchor(const CBox& box, xdgPositionerAnchor anchor) {
+ switch (anchor) {
+ case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.F, 0};
+ case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.F, box.size().y};
+ case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0, box.size().y / 2.F};
+ case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F};
+ case XDG_POSITIONER_ANCHOR_TOP_LEFT: return box.pos();
+ case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: return box.pos() + Vector2D{0, box.size().y};
+ case XDG_POSITIONER_ANCHOR_TOP_RIGHT: return box.pos() + Vector2D{box.size().x, 0};
+ case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y};
+ default: return box.pos();
+ }
+
+ return {};
+}
+
+CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& parentCoord) {
+
+ Debug::log(LOG, "GetPosition with constraint {} {} and parent {}", constraint.pos(), constraint.size(), parentCoord);
+
+ CBox predictedBox = {parentCoord + constraint.pos() + pointForAnchor(state.anchorRect, state.anchor) + state.offset, state.requestedSize};
+
+ bool success = predictedBox.inside(constraint);
+
+ if (success)
+ return predictedBox.translate(-parentCoord - constraint.pos());
+
+ if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y)) {
+ // attempt to flip
+ const bool flipX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X;
+ const bool flipY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y;
+
+ CBox test = predictedBox;
+ success = true;
+ if (flipX && test.copy().translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0}).expand(-1).inside(constraint))
+ test.translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0});
+ else if (flipY && test.copy().translate(Vector2D{0, -predictedBox.h - state.anchorRect.h}).expand(-1).inside(constraint))
+ test.translate(Vector2D{0, -predictedBox.h - state.anchorRect.h});
+ else if (flipX && flipY && test.copy().translate(Vector2D{-predictedBox.w - state.anchorRect.w, -predictedBox.h - state.anchorRect.h}).expand(-1).inside(constraint))
+ test.translate(Vector2D{-predictedBox.w - state.anchorRect.w, -predictedBox.h - state.anchorRect.h});
+ else
+ success = false;
+
+ if (success)
+ return test.translate(-parentCoord - constraint.pos());
+ }
+
+ if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y)) {
+ // attempt to slide
+ const bool slideX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X;
+ const bool slideY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
+
+ //const bool gravityLeft = state.gravity == XDG_POSITIONER_GRAVITY_NONE || state.gravity == XDG_POSITIONER_GRAVITY_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_TOP_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_BOTTOM_LEFT;
+ //const bool gravityTop = state.gravity == XDG_POSITIONER_GRAVITY_NONE || state.gravity == XDG_POSITIONER_GRAVITY_TOP || state.gravity == XDG_POSITIONER_GRAVITY_TOP_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_TOP_RIGHT;
+
+ const bool leftEdgeOut = predictedBox.x < constraint.x;
+ const bool topEdgeOut = predictedBox.y < constraint.y;
+ const bool rightEdgeOut = predictedBox.x + predictedBox.w > constraint.x + constraint.w;
+ const bool bottomEdgeOut = predictedBox.y + predictedBox.h > constraint.y + constraint.h;
+
+ CBox test = predictedBox;
+
+ // TODO: this isn't truly conformant.
+ if (leftEdgeOut && slideX)
+ test.x = constraint.x;
+ if (rightEdgeOut && slideX)
+ test.x = constraint.x + constraint.w - predictedBox.w;
+ if (topEdgeOut && slideY)
+ test.y = constraint.y;
+ if (bottomEdgeOut && slideY)
+ test.y = constraint.y + constraint.h - predictedBox.y;
+
+ success = test.copy().expand(-1).inside(constraint);
+
+ if (success)
+ return test.translate(-parentCoord - constraint.pos());
+ }
+
+ if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y)) {
+ const bool resizeX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X;
+ const bool resizeY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
+
+ const bool leftEdgeOut = predictedBox.x < constraint.x;
+ const bool topEdgeOut = predictedBox.y < constraint.y;
+ const bool rightEdgeOut = predictedBox.x + predictedBox.w > constraint.x + constraint.w;
+ const bool bottomEdgeOut = predictedBox.y + predictedBox.h > constraint.y + constraint.h;
+
+ CBox test = predictedBox;
+
+ // TODO: this isn't truly conformant.
+ if (leftEdgeOut && resizeX) {
+ test.w = test.x + test.w - constraint.x;
+ test.x = constraint.x;
+ }
+ if (rightEdgeOut && resizeX)
+ test.w = -(constraint.w + constraint.x - test.w - test.x);
+ if (topEdgeOut && resizeY) {
+ test.h = test.y + test.h - constraint.y;
+ test.y = constraint.y;
+ }
+ if (bottomEdgeOut && resizeY)
+ test.h = -(constraint.h + constraint.y - test.h - test.y);
+
+ success = test.copy().expand(-1).inside(constraint);
+
+ if (success)
+ return test.translate(parentCoord - constraint.pos());
+ }
+
+ LOGM(WARN, "Compositor/client bug: xdg_positioner couldn't find a place");
+
+ return predictedBox.translate(-parentCoord - constraint.pos());
+}
+
+CXDGWMBase::CXDGWMBase(SP<CXdgWmBase> resource_) : resource(resource_) {
+ if (!good())
+ return;
+
+ resource->setDestroy([this](CXdgWmBase* r) { PROTO::xdgShell->destroyResource(this); });
+ resource->setOnDestroy([this](CXdgWmBase* r) { PROTO::xdgShell->destroyResource(this); });
+
+ pClient = resource->client();
+
+ resource->setCreatePositioner([this](CXdgWmBase* r, uint32_t id) {
+ const auto RESOURCE =
+ PROTO::xdgShell->m_vPositioners.emplace_back(makeShared<CXDGPositionerResource>(makeShared<CXdgPositioner>(r->client(), r->version(), id), self.lock()));
+
+ if (!RESOURCE->good()) {
+ r->noMemory();
+ PROTO::xdgShell->m_vPositioners.pop_back();
+ return;
+ }
+
+ RESOURCE->self = RESOURCE;
+
+ positioners.emplace_back(RESOURCE);
+
+ LOGM(LOG, "New xdg_positioner at {:x}", (uintptr_t)RESOURCE.get());
+ });
+
+ resource->setGetXdgSurface([this](CXdgWmBase* r, uint32_t id, wl_resource* surf) {
+ const auto RESOURCE = PROTO::xdgShell->m_vSurfaces.emplace_back(
+ makeShared<CXDGSurfaceResource>(makeShared<CXdgSurface>(r->client(), r->version(), id), self.lock(), wlr_surface_from_resource(surf)));
+
+ if (!RESOURCE->good()) {
+ r->noMemory();
+ PROTO::xdgShell->m_vSurfaces.pop_back();
+ return;
+ }
+
+ RESOURCE->self = RESOURCE;
+
+ surfaces.emplace_back(RESOURCE);
+
+ LOGM(LOG, "New xdg_surface at {:x}", (uintptr_t)RESOURCE.get());
+ });
+}
+
+bool CXDGWMBase::good() {
+ return resource->resource();
+}
+
+wl_client* CXDGWMBase::client() {
+ return pClient;
+}
+
+CXDGShellProtocol::CXDGShellProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
+ ;
+}
+
+void CXDGShellProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
+ const auto RESOURCE = m_vWMBases.emplace_back(makeShared<CXDGWMBase>(makeShared<CXdgWmBase>(client, ver, id)));
+
+ if (!RESOURCE->good()) {
+ wl_client_post_no_memory(client);
+ m_vWMBases.pop_back();
+ return;
+ }
+
+ RESOURCE->self = RESOURCE;
+
+ LOGM(LOG, "New xdg_wm_base at {:x}", (uintptr_t)RESOURCE.get());
+}
+
+void CXDGShellProtocol::destroyResource(CXDGWMBase* resource) {
+ std::erase_if(m_vWMBases, [&](const auto& other) { return other.get() == resource; });
+}
+
+void CXDGShellProtocol::destroyResource(CXDGPositionerResource* resource) {
+ std::erase_if(m_vPositioners, [&](const auto& other) { return other.get() == resource; });
+}
+
+void CXDGShellProtocol::destroyResource(CXDGSurfaceResource* resource) {
+ std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; });
+}
+
+void CXDGShellProtocol::destroyResource(CXDGToplevelResource* resource) {
+ std::erase_if(m_vToplevels, [&](const auto& other) { return other.get() == resource; });
+}
+
+void CXDGShellProtocol::destroyResource(CXDGPopupResource* resource) {
+ std::erase_if(m_vPopups, [&](const auto& other) { return other.get() == resource; });
+}
diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp
new file mode 100644
index 00000000..e214b6ac
--- /dev/null
+++ b/src/protocols/XDGShell.hpp
@@ -0,0 +1,256 @@
+#pragma once
+
+#include <memory>
+#include <vector>
+#include <cstdint>
+#include <optional>
+#include "WaylandProtocol.hpp"
+#include "xdg-shell.hpp"
+#include "../helpers/Vector2D.hpp"
+#include "../helpers/Box.hpp"
+#include "../helpers/signal/Signal.hpp"
+
+class CXDGWMBase;
+class CXDGPositionerResource;
+class CXDGSurfaceResource;
+class CXDGToplevelResource;
+class CXDGPopupResource;
+class CSeatGrab;
+
+struct SXDGPositionerState {
+ Vector2D requestedSize;
+ CBox anchorRect;
+ xdgPositionerAnchor anchor = XDG_POSITIONER_ANCHOR_NONE;
+ xdgPositionerGravity gravity = XDG_POSITIONER_GRAVITY_NONE;
+ uint32_t constraintAdjustment = 0;
+ Vector2D offset;
+ bool reactive = false;
+ Vector2D parentSize;
+};
+
+class CXDGPositionerRules {
+ public:
+ CXDGPositionerRules(SP<CXDGPositionerResource> positioner);
+
+ CBox getPosition(const CBox& constraint, const Vector2D& parentPos);
+
+ private:
+ SXDGPositionerState state;
+};
+
+class CXDGPopupResource {
+ public:
+ CXDGPopupResource(SP<CXdgPopup> resource_, SP<CXDGSurfaceResource> parent_, SP<CXDGSurfaceResource> surface_, SP<CXDGPositionerResource> positioner_);
+ ~CXDGPopupResource();
+
+ static SP<CXDGPopupResource> fromResource(wl_resource*);
+
+ bool good();
+
+ void applyPositioning(const CBox& availableBox, const Vector2D& t1coord /* relative to box */);
+
+ WP<CXDGSurfaceResource> surface;
+ WP<CXDGSurfaceResource> parent;
+ WP<CXDGPopupResource> self;
+
+ bool taken = false;
+
+ CBox geometry;
+
+ struct {
+ CSignal reposition;
+ CSignal destroy; // only the role
+ } events;
+
+ // schedules a configure event
+ void configure(const CBox& box);
+
+ void done();
+ void repositioned();
+
+ private:
+ SP<CXdgPopup> resource;
+
+ uint32_t lastRepositionToken = 0;
+
+ Vector2D accumulateParentOffset();
+
+ CXDGPositionerRules positionerRules;
+};
+
+class CXDGToplevelResource {
+ public:
+ CXDGToplevelResource(SP<CXdgToplevel> resource_, SP<CXDGSurfaceResource> owner_);
+ ~CXDGToplevelResource();
+
+ static SP<CXDGToplevelResource> fromResource(wl_resource*);
+
+ WP<CXDGSurfaceResource> owner;
+ WP<CXDGToplevelResource> self;
+
+ PHLWINDOWREF window;
+
+ bool good();
+
+ // schedule a configure event
+ uint32_t setSize(const Vector2D& size);
+ uint32_t setMaximized(bool maximized);
+ uint32_t setFullscreen(bool fullscreen);
+ uint32_t setActive(bool active);
+ uint32_t setSuspeneded(bool sus);
+
+ void close();
+
+ struct {
+ CSignal sizeLimitsChanged;
+ CSignal stateChanged; // maximized, fs, minimized, etc.
+ CSignal metadataChanged; // title, appid
+ CSignal destroy; // only the role
+ } events;
+
+ struct {
+ std::string title;
+ std::string appid;
+
+ // volatile state: is reset after the stateChanged signal fires
+ std::optional<bool> requestsMaximize;
+ std::optional<bool> requestsFullscreen;
+ std::optional<bool> requestsMinimize;
+ } state;
+
+ struct {
+ Vector2D size;
+ std::vector<xdgToplevelState> states;
+ } pendingApply;
+
+ struct {
+ Vector2D minSize = {1, 1};
+ Vector2D maxSize = {1337420, 694200};
+ } pending, current;
+
+ WP<CXDGToplevelResource> parent;
+
+ private:
+ SP<CXdgToplevel> resource;
+ void applyState();
+};
+
+class CXDGSurfaceResource {
+ public:
+ CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, wlr_surface* surface_);
+ ~CXDGSurfaceResource();
+
+ static SP<CXDGSurfaceResource> fromResource(wl_resource*);
+
+ bool good();
+
+ WP<CXDGWMBase> owner;
+ wlr_surface* surface = nullptr;
+
+ WP<CXDGToplevelResource> toplevel;
+ WP<CXDGPopupResource> popup;
+
+ WP<CXDGSurfaceResource> self;
+
+ struct {
+ CBox geometry;
+ } pending, current;
+
+ struct {
+ CSignal ack;
+ CSignal commit;
+ CSignal map;
+ CSignal unmap;
+ CSignal destroy;
+ CSignal newPopup; // SP<CXDGPopupResource>
+ } events;
+
+ bool initialCommit = true;
+ bool mapped = false;
+
+ uint32_t scheduleConfigure();
+ // do not call directly
+ void configure();
+
+ private:
+ SP<CXdgSurface> resource;
+
+ uint32_t lastConfigureSerial = 0;
+ uint32_t scheduledSerial = 0;
+
+ wl_event_source* configureSource = nullptr;
+
+ //
+ std::vector<WP<CXDGPopupResource>> popups;
+
+ DYNLISTENER(surfaceDestroy);
+ DYNLISTENER(surfaceCommit);
+
+ friend class CXDGPopupResource;
+ friend class CXDGToplevelResource;
+};
+
+class CXDGPositionerResource {
+ public:
+ CXDGPositionerResource(SP<CXdgPositioner> resource_, SP<CXDGWMBase> owner_);
+
+ static SP<CXDGPositionerResource> fromResource(wl_resource*);
+
+ bool good();
+
+ SXDGPositionerState state;
+
+ WP<CXDGWMBase> owner;
+ WP<CXDGPositionerResource> self;
+
+ private:
+ SP<CXdgPositioner> resource;
+};
+
+class CXDGWMBase {
+ public:
+ CXDGWMBase(SP<CXdgWmBase> resource_);
+
+ bool good();
+ wl_client* client();
+
+ std::vector<WP<CXDGPositionerResource>> positioners;
+ std::vector<WP<CXDGSurfaceResource>> surfaces;
+
+ WP<CXDGWMBase> self;
+
+ private:
+ SP<CXdgWmBase> resource;
+ wl_client* pClient = nullptr;
+};
+
+class CXDGShellProtocol : public IWaylandProtocol {
+ public:
+ CXDGShellProtocol(const wl_interface* iface, const int& ver, const std::string& name);
+
+ virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
+
+ private:
+ void destroyResource(CXDGWMBase* resource);
+ void destroyResource(CXDGPositionerResource* resource);
+ void destroyResource(CXDGSurfaceResource* resource);
+ void destroyResource(CXDGToplevelResource* resource);
+ void destroyResource(CXDGPopupResource* resource);
+
+ //
+ std::vector<SP<CXDGWMBase>> m_vWMBases;
+ std::vector<SP<CXDGPositionerResource>> m_vPositioners;
+ std::vector<SP<CXDGSurfaceResource>> m_vSurfaces;
+ std::vector<SP<CXDGToplevelResource>> m_vToplevels;
+ std::vector<SP<CXDGPopupResource>> m_vPopups;
+
+ friend class CXDGWMBase;
+ friend class CXDGPositionerResource;
+ friend class CXDGSurfaceResource;
+ friend class CXDGToplevelResource;
+ friend class CXDGPopupResource;
+};
+
+namespace PROTO {
+ inline UP<CXDGShellProtocol> xdgShell;
+};
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index 38dba439..1aa246fb 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -10,6 +10,7 @@
#include "../desktop/LayerSurface.hpp"
#include "../protocols/SessionLock.hpp"
#include "../protocols/LayerShell.hpp"
+#include "../protocols/XDGShell.hpp"
#include "../protocols/PresentationTime.hpp"
extern "C" {
@@ -615,9 +616,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec
if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_POPUP) {
if (!pWindow->m_bIsX11) {
- CBox geom;
- wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, geom.pWlr());
- geom.applyFromWlr();
+ CBox geom = pWindow->m_pXDGSurface->current.geometry;
renderdata.x -= geom.x;
renderdata.y -= geom.y;
@@ -643,7 +642,20 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec
if (pWindow->m_sAdditionalConfigData.nearestNeighbor.toUnderlying())
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true;
- wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata);
+ pWindow->m_pPopupHead->breadthfirst(
+ [](CPopup* popup, void* data) {
+ if (!popup->m_sWLSurface.wlr())
+ return;
+ auto pos = popup->coordsRelativeToParent();
+ auto rd = (SRenderData*)data;
+ Vector2D oldPos = {rd->x, rd->y};
+ rd->x += pos.x;
+ rd->y += pos.y;
+ wlr_surface_for_each_surface(popup->m_sWLSurface.wlr(), renderSurface, rd);
+ rd->x = oldPos.x;
+ rd->y = oldPos.y;
+ },
+ &renderdata);
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
@@ -1000,9 +1012,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa
if (!main || !pWindow)
return;
- CBox geom;
- wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, geom.pWlr());
- geom.applyFromWlr();
+ CBox geom = pWindow->m_pXDGSurface->current.geometry;
// ignore X and Y, adjust uv
if (geom.x != 0 || geom.y != 0 || geom.width > pWindow->m_vRealSize.value().x || geom.height > pWindow->m_vRealSize.value().y) {
@@ -2530,8 +2540,7 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) {
if (PCANDIDATE->m_bIsX11) {
surfaceCount = 1;
} else {
- wlr_xdg_surface_for_each_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
- wlr_xdg_surface_for_each_popup_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
+ surfaceCount = PCANDIDATE->popupsCount() + PCANDIDATE->surfacesCount();
}
if (surfaceCount > 1)