summaryrefslogtreecommitdiff
path: root/src/protocols
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2024-12-15 00:37:17 +0100
committerGitHub <noreply@github.com>2024-12-15 00:37:17 +0100
commitdb249648776875ce3142141d0d3055e43ce606aa (patch)
tree50cac68a73e0da6e8154bd4deef08a11e2784ad2 /src/protocols
parent9f7a96b997d90c4c188f3837e02859a25a05611e (diff)
xwayland: Support cross DnD from Wayland (#8708)
Adds support for drag-and-drop from Wayland clients to XWayland ones
Diffstat (limited to 'src/protocols')
-rw-r--r--src/protocols/core/DataDevice.cpp151
-rw-r--r--src/protocols/core/DataDevice.hpp69
-rw-r--r--src/protocols/types/DataDevice.cpp12
-rw-r--r--src/protocols/types/DataDevice.hpp39
4 files changed, 211 insertions, 60 deletions
diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp
index d23e3415..9447f04f 100644
--- a/src/protocols/core/DataDevice.cpp
+++ b/src/protocols/core/DataDevice.cpp
@@ -6,6 +6,8 @@
#include "../../Compositor.hpp"
#include "Seat.hpp"
#include "Compositor.hpp"
+#include "../../xwayland/XWayland.hpp"
+#include "../../xwayland/Server.hpp"
CWLDataOfferResource::CWLDataOfferResource(SP<CWlDataOffer> resource_, SP<IDataSource> source_) : source(source_), resource(resource_) {
if (!good())
@@ -103,6 +105,22 @@ void CWLDataOfferResource::sendData() {
}
}
+eDataSourceType CWLDataOfferResource::type() {
+ return DATA_SOURCE_TYPE_WAYLAND;
+}
+
+SP<CWLDataOfferResource> CWLDataOfferResource::getWayland() {
+ return self.lock();
+}
+
+SP<CX11DataOffer> CWLDataOfferResource::getX11() {
+ return nullptr;
+}
+
+SP<IDataSource> CWLDataOfferResource::getSource() {
+ return source.lock();
+}
+
CWLDataSourceResource::CWLDataSourceResource(SP<CWlDataSource> resource_, SP<CWLDataDeviceResource> device_) : device(device_), resource(resource_) {
if (!good())
return;
@@ -209,6 +227,10 @@ uint32_t CWLDataSourceResource::actions() {
return supportedActions;
}
+eDataSourceType CWLDataSourceResource::type() {
+ return DATA_SOURCE_TYPE_WAYLAND;
+}
+
CWLDataDeviceResource::CWLDataDeviceResource(SP<CWlDataDevice> resource_) : resource(resource_) {
if (!good())
return;
@@ -260,15 +282,18 @@ wl_client* CWLDataDeviceResource::client() {
return pClient;
}
-void CWLDataDeviceResource::sendDataOffer(SP<CWLDataOfferResource> offer) {
- if (offer)
- resource->sendDataOffer(offer->resource.get());
- else
+void CWLDataDeviceResource::sendDataOffer(SP<IDataOffer> offer) {
+ if (!offer)
resource->sendDataOfferRaw(nullptr);
+ else if (const auto WL = offer->getWayland(); WL)
+ resource->sendDataOffer(WL->resource.get());
+ //FIXME: X11
}
-void CWLDataDeviceResource::sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<CWLDataOfferResource> offer) {
- resource->sendEnterRaw(serial, surf->getResource()->resource(), wl_fixed_from_double(local.x), wl_fixed_from_double(local.y), offer->resource->resource());
+void CWLDataDeviceResource::sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<IDataOffer> offer) {
+ if (const auto WL = offer->getWayland(); WL)
+ resource->sendEnterRaw(serial, surf->getResource()->resource(), wl_fixed_from_double(local.x), wl_fixed_from_double(local.y), WL->resource->resource());
+ // FIXME: X11
}
void CWLDataDeviceResource::sendLeave() {
@@ -283,11 +308,23 @@ void CWLDataDeviceResource::sendDrop() {
resource->sendDrop();
}
-void CWLDataDeviceResource::sendSelection(SP<CWLDataOfferResource> offer) {
+void CWLDataDeviceResource::sendSelection(SP<IDataOffer> offer) {
if (!offer)
resource->sendSelectionRaw(nullptr);
- else
- resource->sendSelection(offer->resource.get());
+ else if (const auto WL = offer->getWayland(); WL)
+ resource->sendSelection(WL->resource.get());
+}
+
+eDataSourceType CWLDataDeviceResource::type() {
+ return DATA_SOURCE_TYPE_WAYLAND;
+}
+
+SP<CWLDataDeviceResource> CWLDataDeviceResource::getWayland() {
+ return self.lock();
+}
+
+SP<CX11DataDevice> CWLDataDeviceResource::getX11() {
+ return nullptr;
}
CWLDataDeviceManagerResource::CWLDataDeviceManagerResource(SP<CWlDataDeviceManager> resource_) : resource(resource_) {
@@ -377,32 +414,53 @@ void CWLDataDeviceProtocol::destroyResource(CWLDataOfferResource* resource) {
std::erase_if(m_vOffers, [&](const auto& other) { return other.get() == resource; });
}
-SP<CWLDataDeviceResource> CWLDataDeviceProtocol::dataDeviceForClient(wl_client* c) {
+SP<IDataDevice> CWLDataDeviceProtocol::dataDeviceForClient(wl_client* c) {
+#ifndef NO_XWAYLAND
+ if (c == g_pXWayland->pServer->xwaylandClient)
+ return g_pXWayland->pWM->getDataDevice();
+#endif
+
auto it = std::find_if(m_vDevices.begin(), m_vDevices.end(), [c](const auto& e) { return e->client() == c; });
if (it == m_vDevices.end())
return nullptr;
return *it;
}
-void CWLDataDeviceProtocol::sendSelectionToDevice(SP<CWLDataDeviceResource> dev, SP<IDataSource> sel) {
+void CWLDataDeviceProtocol::sendSelectionToDevice(SP<IDataDevice> dev, SP<IDataSource> sel) {
if (!sel) {
dev->sendSelection(nullptr);
return;
}
- const auto OFFER = m_vOffers.emplace_back(makeShared<CWLDataOfferResource>(makeShared<CWlDataOffer>(dev->resource->client(), dev->resource->version(), 0), sel));
+ SP<IDataOffer> offer;
- if (!OFFER->good()) {
- dev->resource->noMemory();
- m_vOffers.pop_back();
+ if (const auto WL = dev->getWayland(); WL) {
+ const auto OFFER = m_vOffers.emplace_back(makeShared<CWLDataOfferResource>(makeShared<CWlDataOffer>(WL->resource->client(), WL->resource->version(), 0), sel));
+ if (!OFFER->good()) {
+ WL->resource->noMemory();
+ m_vOffers.pop_back();
+ return;
+ }
+ OFFER->source = sel;
+ OFFER->self = OFFER;
+ offer = OFFER;
+ }
+#ifndef NO_XWAYLAND
+ else if (const auto X11 = dev->getX11(); X11)
+ offer = g_pXWayland->pWM->createX11DataOffer(g_pSeatManager->state.keyboardFocus.lock(), sel);
+#endif
+
+ if (!offer) {
+ LOGM(ERR, "No offer could be created in sendSelectionToDevice");
return;
}
- LOGM(LOG, "New offer {:x} for data source {:x}", (uintptr_t)OFFER.get(), (uintptr_t)sel.get());
+ LOGM(LOG, "New {} offer {:x} for data source {:x}", offer->type() == DATA_SOURCE_TYPE_WAYLAND ? "wayland" : "X11", (uintptr_t)offer.get(), (uintptr_t)sel.get());
- dev->sendDataOffer(OFFER);
- OFFER->sendData();
- dev->sendSelection(OFFER);
+ dev->sendDataOffer(offer);
+ if (const auto WL = offer->getWayland(); WL)
+ WL->sendData();
+ dev->sendSelection(offer);
}
void CWLDataDeviceProtocol::onDestroyDataSource(WP<CWLDataSourceResource> source) {
@@ -424,7 +482,7 @@ void CWLDataDeviceProtocol::setSelection(SP<IDataSource> source) {
return;
auto DESTDEVICE = dataDeviceForClient(g_pSeatManager->state.keyboardFocusResource->client());
- if (DESTDEVICE)
+ if (DESTDEVICE && DESTDEVICE->type() == DATA_SOURCE_TYPE_WAYLAND)
sendSelectionToDevice(DESTDEVICE, nullptr);
return;
@@ -442,6 +500,11 @@ void CWLDataDeviceProtocol::setSelection(SP<IDataSource> source) {
return;
}
+ if (DESTDEVICE->type() != DATA_SOURCE_TYPE_WAYLAND) {
+ LOGM(LOG, "CWLDataDeviceProtocol::setSelection: ignoring X11 data device");
+ return;
+ }
+
sendSelectionToDevice(DESTDEVICE, source);
}
@@ -589,22 +652,38 @@ void CWLDataDeviceProtocol::updateDrag() {
if (!dnd.focusedDevice)
return;
- // make a new offer
- const auto OFFER = m_vOffers.emplace_back(
- makeShared<CWLDataOfferResource>(makeShared<CWlDataOffer>(dnd.focusedDevice->resource->client(), dnd.focusedDevice->resource->version(), 0), dnd.currentSource.lock()));
+ SP<IDataOffer> offer;
+
+ if (const auto WL = dnd.focusedDevice->getWayland(); WL) {
+ const auto OFFER =
+ m_vOffers.emplace_back(makeShared<CWLDataOfferResource>(makeShared<CWlDataOffer>(WL->resource->client(), WL->resource->version(), 0), dnd.currentSource.lock()));
+ if (!OFFER->good()) {
+ WL->resource->noMemory();
+ m_vOffers.pop_back();
+ return;
+ }
+ OFFER->source = dnd.currentSource;
+ OFFER->self = OFFER;
+ offer = OFFER;
+ }
+#ifndef NO_XWAYLAND
+ else if (const auto X11 = dnd.focusedDevice->getX11(); X11)
+ offer = g_pXWayland->pWM->createX11DataOffer(g_pSeatManager->state.keyboardFocus.lock(), dnd.currentSource.lock());
+#endif
- if (!OFFER->good()) {
- dnd.currentSource->resource->noMemory();
- m_vOffers.pop_back();
+ if (!offer) {
+ LOGM(ERR, "No offer could be created in updateDrag");
return;
}
- LOGM(LOG, "New dnd offer {:x} for data source {:x}", (uintptr_t)OFFER.get(), (uintptr_t)dnd.currentSource.get());
+ LOGM(LOG, "New {} dnd offer {:x} for data source {:x}", offer->type() == DATA_SOURCE_TYPE_WAYLAND ? "wayland" : "X11", (uintptr_t)offer.get(),
+ (uintptr_t)dnd.currentSource.get());
- dnd.focusedDevice->sendDataOffer(OFFER);
- OFFER->sendData();
+ dnd.focusedDevice->sendDataOffer(offer);
+ if (const auto WL = offer->getWayland(); WL)
+ WL->sendData();
dnd.focusedDevice->sendEnter(wl_display_next_serial(g_pCompositor->m_sWLDisplay), g_pSeatManager->state.dndPointerFocus.lock(),
- g_pSeatManager->state.dndPointerFocus->current.size / 2.F, OFFER);
+ g_pSeatManager->state.dndPointerFocus->current.size / 2.F, offer);
}
void CWLDataDeviceProtocol::resetDndState() {
@@ -651,6 +730,18 @@ bool CWLDataDeviceProtocol::wasDragSuccessful() {
return true;
}
+#ifndef NO_XWAYLAND
+ for (auto const& o : g_pXWayland->pWM->dndDataOffers) {
+ if (o->dead || !o->source || !o->source->hasDnd())
+ continue;
+
+ if (o->source != dnd.currentSource)
+ continue;
+
+ return true;
+ }
+#endif
+
return false;
}
diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp
index bf22b511..ae22e474 100644
--- a/src/protocols/core/DataDevice.hpp
+++ b/src/protocols/core/DataDevice.hpp
@@ -26,21 +26,27 @@ class CWLDataOfferResource;
class CWLSurfaceResource;
class CMonitor;
-class CWLDataOfferResource {
+class CWLDataOfferResource : public IDataOffer {
public:
CWLDataOfferResource(SP<CWlDataOffer> resource_, SP<IDataSource> source_);
~CWLDataOfferResource();
- bool good();
- void sendData();
+ bool good();
+ void sendData();
+
+ virtual eDataSourceType type();
+ virtual SP<CWLDataOfferResource> getWayland();
+ virtual SP<CX11DataOffer> getX11();
+ virtual SP<IDataSource> getSource();
- WP<IDataSource> source;
+ WP<IDataSource> source;
+ WP<CWLDataOfferResource> self;
- bool dead = false;
- bool accepted = false;
- bool recvd = false;
+ bool dead = false;
+ bool accepted = false;
+ bool recvd = false;
- uint32_t actions = 0;
+ uint32_t actions = 0;
private:
SP<CWlDataOffer> resource;
@@ -66,9 +72,9 @@ class CWLDataSourceResource : public IDataSource {
virtual void error(uint32_t code, const std::string& msg);
virtual void sendDndFinished();
virtual uint32_t actions(); // wl_data_device_manager.dnd_action
-
- void sendDndDropPerformed();
- void sendDndAction(wl_data_device_manager_dnd_action a);
+ virtual eDataSourceType type();
+ virtual void sendDndDropPerformed();
+ virtual void sendDndAction(wl_data_device_manager_dnd_action a);
bool used = false;
bool dnd = false;
@@ -88,21 +94,24 @@ class CWLDataSourceResource : public IDataSource {
friend class CWLDataDeviceProtocol;
};
-class CWLDataDeviceResource {
+class CWLDataDeviceResource : public IDataDevice {
public:
CWLDataDeviceResource(SP<CWlDataDevice> resource_);
- bool good();
- wl_client* client();
+ bool good();
+ wl_client* client();
- void sendDataOffer(SP<CWLDataOfferResource> offer);
- void sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<CWLDataOfferResource> offer);
- void sendLeave();
- void sendMotion(uint32_t timeMs, const Vector2D& local);
- void sendDrop();
- void sendSelection(SP<CWLDataOfferResource> offer);
+ virtual SP<CWLDataDeviceResource> getWayland();
+ virtual SP<CX11DataDevice> getX11();
+ virtual void sendDataOffer(SP<IDataOffer> offer);
+ virtual void sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<IDataOffer> offer);
+ virtual void sendLeave();
+ virtual void sendMotion(uint32_t timeMs, const Vector2D& local);
+ virtual void sendDrop();
+ virtual void sendSelection(SP<IDataOffer> offer);
+ virtual eDataSourceType type();
- WP<CWLDataDeviceResource> self;
+ WP<CWLDataDeviceResource> self;
private:
SP<CWlDataDevice> resource;
@@ -152,19 +161,19 @@ class CWLDataDeviceProtocol : public IWaylandProtocol {
void onDestroyDataSource(WP<CWLDataSourceResource> source);
void setSelection(SP<IDataSource> source);
- void sendSelectionToDevice(SP<CWLDataDeviceResource> dev, SP<IDataSource> sel);
+ void sendSelectionToDevice(SP<IDataDevice> dev, SP<IDataSource> sel);
void updateSelection();
void onKeyboardFocus();
void onDndPointerFocus();
struct {
- WP<CWLDataDeviceResource> focusedDevice;
- WP<CWLDataSourceResource> currentSource;
- WP<CWLSurfaceResource> dndSurface;
- WP<CWLSurfaceResource> originSurface;
- bool overriddenCursor = false;
- CHyprSignalListener dndSurfaceDestroy;
- CHyprSignalListener dndSurfaceCommit;
+ WP<IDataDevice> focusedDevice;
+ WP<IDataSource> currentSource;
+ WP<CWLSurfaceResource> dndSurface;
+ WP<CWLSurfaceResource> originSurface;
+ bool overriddenCursor = false;
+ CHyprSignalListener dndSurfaceDestroy;
+ CHyprSignalListener dndSurfaceCommit;
// for ending a dnd
SP<HOOK_CALLBACK_FN> mouseMove;
@@ -182,7 +191,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol {
bool wasDragSuccessful();
//
- SP<CWLDataDeviceResource> dataDeviceForClient(wl_client*);
+ SP<IDataDevice> dataDeviceForClient(wl_client*);
friend class CSeatManager;
friend class CWLDataDeviceManagerResource;
diff --git a/src/protocols/types/DataDevice.cpp b/src/protocols/types/DataDevice.cpp
index 36a7a157..fef11b64 100644
--- a/src/protocols/types/DataDevice.cpp
+++ b/src/protocols/types/DataDevice.cpp
@@ -27,3 +27,15 @@ void IDataSource::sendDndFinished() {
uint32_t IDataSource::actions() {
return 7; // all
}
+
+void IDataSource::sendDndDropPerformed() {
+ ;
+}
+
+void IDataSource::sendDndAction(wl_data_device_manager_dnd_action a) {
+ ;
+}
+
+void IDataOffer::markDead() {
+ ;
+}
diff --git a/src/protocols/types/DataDevice.hpp b/src/protocols/types/DataDevice.hpp
index 80f75b8e..62f10de2 100644
--- a/src/protocols/types/DataDevice.hpp
+++ b/src/protocols/types/DataDevice.hpp
@@ -4,6 +4,15 @@
#include <vector>
#include <cstdint>
#include "../../helpers/signal/Signal.hpp"
+#include <wayland-server-protocol.h>
+#include "../../helpers/memory/Memory.hpp"
+#include "../../helpers/math/Math.hpp"
+
+class CWLDataOfferResource;
+class CX11DataOffer;
+class CX11DataDevice;
+class CWLDataDeviceResource;
+class CWLSurfaceResource;
enum eDataSourceType : uint8_t {
DATA_SOURCE_TYPE_WAYLAND = 0,
@@ -27,6 +36,8 @@ class IDataSource {
virtual void error(uint32_t code, const std::string& msg) = 0;
virtual eDataSourceType type();
virtual uint32_t actions(); // wl_data_device_manager.dnd_action
+ virtual void sendDndDropPerformed();
+ virtual void sendDndAction(wl_data_device_manager_dnd_action a);
struct {
CSignal destroy;
@@ -35,3 +46,31 @@ class IDataSource {
private:
bool wasUsed = false;
};
+
+class IDataOffer {
+ public:
+ IDataOffer() = default;
+ virtual ~IDataOffer() = default;
+
+ virtual eDataSourceType type() = 0;
+ virtual SP<CWLDataOfferResource> getWayland() = 0;
+ virtual SP<CX11DataOffer> getX11() = 0;
+ virtual SP<IDataSource> getSource() = 0;
+ virtual void markDead();
+};
+
+class IDataDevice {
+ public:
+ IDataDevice() = default;
+ virtual ~IDataDevice() = default;
+
+ virtual SP<CWLDataDeviceResource> getWayland() = 0;
+ virtual SP<CX11DataDevice> getX11() = 0;
+ virtual void sendDataOffer(SP<IDataOffer> offer) = 0;
+ virtual void sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<IDataOffer> offer) = 0;
+ virtual void sendLeave() = 0;
+ virtual void sendMotion(uint32_t timeMs, const Vector2D& local) = 0;
+ virtual void sendDrop() = 0;
+ virtual void sendSelection(SP<IDataOffer> offer) = 0;
+ virtual eDataSourceType type() = 0;
+};