xdg: rewrite entire popup implementation
This commit is contained in:
parent
b39dcfa497
commit
2e111c8cf9
13 changed files with 358 additions and 344 deletions
225
src/desktop/Popup.cpp
Normal file
225
src/desktop/Popup.cpp
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
#include "Popup.hpp"
|
||||
|
||||
CPopup::CPopup(CWindow* pOwner) : m_pWindowOwner(pOwner) {
|
||||
initAllSignals();
|
||||
}
|
||||
|
||||
CPopup::CPopup(SLayerSurface* 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);
|
||||
|
||||
m_pLayerOwner = pOwner->m_pLayerOwner;
|
||||
m_pWindowOwner = pOwner->m_pWindowOwner;
|
||||
|
||||
m_vLastSize = {m_pWLR->current.geometry.width, m_pWLR->current.geometry.height};
|
||||
unconstrain();
|
||||
|
||||
initAllSignals();
|
||||
}
|
||||
|
||||
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_pWindowOwner)
|
||||
hyprListener_newPopup.initCallback(&m_pWindowOwner->m_uSurface.xdg->events.new_popup, ::onNewPopup, this, "CPopup Head");
|
||||
else if (m_pLayerOwner)
|
||||
hyprListener_newPopup.initCallback(&m_pLayerOwner->layerSurface->events.new_popup, ::onNewPopup, this, "CPopup Head");
|
||||
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");
|
||||
}
|
||||
|
||||
void CPopup::onNewPopup(wlr_xdg_popup* 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);
|
||||
}
|
||||
|
||||
void CPopup::onDestroy() {
|
||||
m_bInert = true;
|
||||
|
||||
if (!m_pParent)
|
||||
return; // head node
|
||||
|
||||
std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; });
|
||||
}
|
||||
|
||||
void CPopup::onMap() {
|
||||
m_vLastSize = {m_pWLR->current.geometry.width, m_pWLR->current.geometry.height};
|
||||
const auto COORDS = coordsGlobal();
|
||||
|
||||
CBox box = {COORDS, m_vLastSize};
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
|
||||
m_vLastPos = coordsRelativeToParent();
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
||||
m_pSubsurfaceHead = std::make_unique<CSubsurface>(this);
|
||||
|
||||
unconstrain();
|
||||
}
|
||||
|
||||
void CPopup::onUnmap() {
|
||||
m_vLastSize = {m_pWLR->current.geometry.width, m_pWLR->current.geometry.height};
|
||||
const auto COORDS = coordsGlobal();
|
||||
|
||||
CBox box = {COORDS, m_vLastSize};
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
|
||||
m_pSubsurfaceHead.reset();
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
}
|
||||
|
||||
void CPopup::onCommit() {
|
||||
if (m_pWLR->base->initial_commit) {
|
||||
wlr_xdg_surface_schedule_configure(m_pWLR->base);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto COORDS = coordsGlobal();
|
||||
const auto COORDSLOCAL = coordsRelativeToParent();
|
||||
|
||||
if (m_vLastSize != Vector2D{m_pWLR->current.geometry.width, m_pWLR->current.geometry.height} || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) {
|
||||
CBox box = {localToGlobal(m_vLastPos), m_vLastSize};
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
m_vLastSize = {m_pWLR->current.geometry.width, m_pWLR->current.geometry.height};
|
||||
box = {COORDS, m_vLastSize};
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
|
||||
m_vLastPos = COORDSLOCAL;
|
||||
}
|
||||
|
||||
m_pSubsurfaceHead->recheckDamageForSubsurfaces();
|
||||
|
||||
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y);
|
||||
|
||||
m_bRequestedReposition = false;
|
||||
}
|
||||
|
||||
void CPopup::onReposition() {
|
||||
Debug::log(LOG, "Popup {:x} requests reposition", (uintptr_t)this);
|
||||
|
||||
m_bRequestedReposition = true;
|
||||
|
||||
m_vLastPos = coordsRelativeToParent();
|
||||
|
||||
unconstrain();
|
||||
}
|
||||
|
||||
void CPopup::unconstrain() {
|
||||
const auto COORDS = t1ParentCoords();
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS);
|
||||
|
||||
if (!PMONITOR)
|
||||
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());
|
||||
}
|
||||
|
||||
Vector2D CPopup::coordsRelativeToParent() {
|
||||
Vector2D offset;
|
||||
|
||||
CPopup* current = this;
|
||||
|
||||
while (current->m_pParent) {
|
||||
|
||||
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};
|
||||
|
||||
current = current->m_pParent;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
Vector2D CPopup::coordsGlobal() {
|
||||
return localToGlobal(coordsRelativeToParent());
|
||||
}
|
||||
|
||||
Vector2D CPopup::localToGlobal(const Vector2D& rel) {
|
||||
return t1ParentCoords() + rel;
|
||||
}
|
||||
|
||||
Vector2D CPopup::t1ParentCoords() {
|
||||
if (m_pWindowOwner)
|
||||
return m_pWindowOwner->m_vRealPosition.vec();
|
||||
if (m_pLayerOwner)
|
||||
return m_pLayerOwner->realPosition.vec();
|
||||
|
||||
ASSERT(false);
|
||||
return {};
|
||||
}
|
||||
|
||||
void CPopup::recheckTree() {
|
||||
CPopup* curr = this;
|
||||
while (curr->m_pParent) {
|
||||
curr = curr->m_pParent;
|
||||
}
|
||||
|
||||
curr->recheckChildrenRecursive();
|
||||
}
|
||||
|
||||
void CPopup::recheckChildrenRecursive() {
|
||||
for (auto& c : m_vChildren) {
|
||||
c->onCommit();
|
||||
c->recheckChildrenRecursive();
|
||||
}
|
||||
}
|
||||
69
src/desktop/Popup.hpp
Normal file
69
src/desktop/Popup.hpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "Subsurface.hpp"
|
||||
|
||||
struct SLayerSurface;
|
||||
|
||||
class CPopup {
|
||||
public:
|
||||
// dummy head nodes
|
||||
CPopup(CWindow* pOwner);
|
||||
CPopup(SLayerSurface* pOwner);
|
||||
|
||||
// real nodes
|
||||
CPopup(wlr_xdg_popup* popup, CPopup* pOwner);
|
||||
|
||||
~CPopup();
|
||||
|
||||
Vector2D coordsRelativeToParent();
|
||||
Vector2D coordsGlobal();
|
||||
|
||||
void onNewPopup(wlr_xdg_popup* popup);
|
||||
void onDestroy();
|
||||
void onMap();
|
||||
void onUnmap();
|
||||
void onCommit();
|
||||
void onReposition();
|
||||
|
||||
void recheckTree();
|
||||
|
||||
CWLSurface m_sWLSurface;
|
||||
|
||||
private:
|
||||
// T1 owners, each popup has to have one of these
|
||||
CWindow* m_pWindowOwner = nullptr;
|
||||
SLayerSurface* m_pLayerOwner = nullptr;
|
||||
|
||||
// T2 owners
|
||||
CPopup* m_pParent = nullptr;
|
||||
|
||||
wlr_xdg_popup* m_pWLR = nullptr;
|
||||
|
||||
Vector2D m_vLastSize = {};
|
||||
Vector2D m_vLastPos = {};
|
||||
|
||||
bool m_bRequestedReposition = 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);
|
||||
|
||||
void initAllSignals();
|
||||
void unconstrain();
|
||||
void recheckChildrenRecursive();
|
||||
|
||||
Vector2D localToGlobal(const Vector2D& rel);
|
||||
Vector2D t1ParentCoords();
|
||||
};
|
||||
|
|
@ -16,12 +16,30 @@ CSubsurface::CSubsurface(CWindow* pOwner) : m_pWindowParent(pOwner) {
|
|||
}
|
||||
}
|
||||
|
||||
CSubsurface::CSubsurface(CPopup* pOwner) : m_pPopupParent(pOwner) {
|
||||
initSignals();
|
||||
|
||||
wlr_subsurface* wlrSubsurface;
|
||||
wl_list_for_each(wlrSubsurface, &pOwner->m_sWLSurface.wlr()->current.subsurfaces_below, current.link) {
|
||||
::onNewSubsurface(this, wlrSubsurface);
|
||||
}
|
||||
wl_list_for_each(wlrSubsurface, &pOwner->m_sWLSurface.wlr()->current.subsurfaces_above, current.link) {
|
||||
::onNewSubsurface(this, wlrSubsurface);
|
||||
}
|
||||
}
|
||||
|
||||
CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CWindow* pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) {
|
||||
m_sWLSurface.assign(pSubsurface->surface);
|
||||
initSignals();
|
||||
initExistingSubsurfaces();
|
||||
}
|
||||
|
||||
CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) {
|
||||
m_sWLSurface.assign(pSubsurface->surface);
|
||||
initSignals();
|
||||
initExistingSubsurfaces();
|
||||
}
|
||||
|
||||
CSubsurface::~CSubsurface() {
|
||||
hyprListener_newSubsurface.removeCallback();
|
||||
|
||||
|
|
@ -30,11 +48,6 @@ CSubsurface::~CSubsurface() {
|
|||
|
||||
hyprListener_commitSubsurface.removeCallback();
|
||||
hyprListener_destroySubsurface.removeCallback();
|
||||
|
||||
const auto COORDS = coordsGlobal();
|
||||
|
||||
CBox box = {COORDS, m_vLastSize};
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
}
|
||||
|
||||
static void onNewSubsurface(void* owner, void* data) {
|
||||
|
|
@ -68,10 +81,12 @@ void CSubsurface::initSignals() {
|
|||
hyprListener_destroySubsurface.initCallback(&m_pSubsurface->events.destroy, &onDestroySubsurface, this, "CSubsurface");
|
||||
hyprListener_newSubsurface.initCallback(&m_pSubsurface->surface->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface");
|
||||
hyprListener_mapSubsurface.initCallback(&m_pSubsurface->surface->events.map, &onMapSubsurface, this, "CSubsurface");
|
||||
hyprListener_newSubsurface.initCallback(&m_pSubsurface->surface->events.unmap, &onUnmapSubsurface, this, "CSubsurface");
|
||||
hyprListener_unmapSubsurface.initCallback(&m_pSubsurface->surface->events.unmap, &onUnmapSubsurface, this, "CSubsurface");
|
||||
} else {
|
||||
if (m_pWindowParent)
|
||||
hyprListener_newSubsurface.initCallback(&m_pWindowParent->m_pWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface");
|
||||
hyprListener_newSubsurface.initCallback(&m_pWindowParent->m_pWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head");
|
||||
else if (m_pPopupParent)
|
||||
hyprListener_newSubsurface.initCallback(&m_pPopupParent->m_sWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head");
|
||||
else
|
||||
RASSERT(false, "CSubsurface::initSignals empty subsurface");
|
||||
}
|
||||
|
|
@ -93,11 +108,9 @@ void CSubsurface::checkSiblingDamage() {
|
|||
}
|
||||
|
||||
void CSubsurface::recheckDamageForSubsurfaces() {
|
||||
const double SCALE = m_pWindowParent && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0;
|
||||
|
||||
for (auto& n : m_vChildren) {
|
||||
const auto COORDS = n->coordsGlobal();
|
||||
g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y, SCALE);
|
||||
g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,11 +125,14 @@ void CSubsurface::onCommit() {
|
|||
return;
|
||||
}
|
||||
|
||||
const auto COORDS = coordsGlobal();
|
||||
const auto COORDS = coordsGlobal();
|
||||
|
||||
const double SCALE = m_pWindowParent && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0;
|
||||
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y);
|
||||
|
||||
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y, SCALE);
|
||||
if (m_pPopupParent)
|
||||
m_pPopupParent->recheckTree();
|
||||
if (m_pWindowParent) // I hate you firefox why are you doing this
|
||||
m_pWindowParent->m_pPopupHead->recheckTree();
|
||||
|
||||
// I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox)
|
||||
checkSiblingDamage();
|
||||
|
|
@ -130,9 +146,6 @@ void CSubsurface::onCommit() {
|
|||
}
|
||||
|
||||
if (m_pWindowParent) {
|
||||
if (m_pWindowParent->m_bIsX11)
|
||||
m_pWindowParent->m_vReportedSize = m_pWindowParent->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
|
||||
|
||||
// tearing: if solitary, redraw it. This still might be a single surface window
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_pWindowParent->m_iMonitorID);
|
||||
if (PMONITOR && PMONITOR->solitaryClient == m_pWindowParent && m_pWindowParent->canBeTorn() && PMONITOR->tearingState.canTear &&
|
||||
|
|
@ -155,6 +168,8 @@ void CSubsurface::onDestroy() {
|
|||
// destroy children
|
||||
m_vChildren.clear();
|
||||
|
||||
m_bInert = true;
|
||||
|
||||
if (!m_pSubsurface)
|
||||
return; // dummy node, nothing to do, it's the parent dying
|
||||
|
||||
|
|
@ -167,6 +182,8 @@ void CSubsurface::onNewSubsurface(wlr_subsurface* pSubsurface) {
|
|||
|
||||
if (m_pWindowParent)
|
||||
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pWindowParent)).get();
|
||||
else if (m_pPopupParent)
|
||||
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pPopupParent)).get();
|
||||
PSUBSURFACE->m_pParent = this;
|
||||
|
||||
ASSERT(PSUBSURFACE);
|
||||
|
|
@ -220,6 +237,8 @@ Vector2D CSubsurface::coordsGlobal() {
|
|||
|
||||
if (m_pWindowParent)
|
||||
coords += m_pWindowParent->m_vRealPosition.vec();
|
||||
else if (m_pPopupParent)
|
||||
coords += m_pPopupParent->coordsGlobal();
|
||||
|
||||
return coords;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,17 @@
|
|||
#include "WLSurface.hpp"
|
||||
|
||||
class CWindow;
|
||||
struct SXDGPopup;
|
||||
class CPopup;
|
||||
|
||||
class CSubsurface {
|
||||
public:
|
||||
// root dummy nodes
|
||||
CSubsurface(CWindow* pOwner);
|
||||
CSubsurface(CPopup* pOwner);
|
||||
|
||||
// real nodes
|
||||
CSubsurface(wlr_subsurface* pSubsurface, CWindow* pOwner);
|
||||
CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner);
|
||||
|
||||
~CSubsurface();
|
||||
|
||||
|
|
@ -29,7 +31,6 @@ class CSubsurface {
|
|||
void recheckDamageForSubsurfaces();
|
||||
|
||||
private:
|
||||
|
||||
DYNLISTENER(destroySubsurface);
|
||||
DYNLISTENER(commitSubsurface);
|
||||
DYNLISTENER(newSubsurface);
|
||||
|
|
@ -44,9 +45,12 @@ class CSubsurface {
|
|||
CSubsurface* m_pParent = nullptr;
|
||||
|
||||
CWindow* m_pWindowParent = nullptr;
|
||||
CPopup* m_pPopupParent = nullptr;
|
||||
|
||||
std::vector<std::unique_ptr<CSubsurface>> m_vChildren;
|
||||
|
||||
bool m_bInert = false;
|
||||
|
||||
void initSignals();
|
||||
void initExistingSubsurfaces();
|
||||
void checkSiblingDamage();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue