Remove Wayland::Client usage in wl->xwl drags

This commit is contained in:
David Edmundson 2021-06-03 09:04:26 +00:00
parent 6c97cd118d
commit 4a16e18808
6 changed files with 103 additions and 101 deletions

View file

@ -44,33 +44,5 @@ void Drag::sendClientMessage(xcb_window_t target, xcb_atom_t type, xcb_client_me
xcb_flush(xcbConn);
}
DnDAction Drag::atomToClientAction(xcb_atom_t atom)
{
if (atom == atoms->xdnd_action_copy) {
return DnDAction::Copy;
} else if (atom == atoms->xdnd_action_move) {
return DnDAction::Move;
} else if (atom == atoms->xdnd_action_ask) {
// we currently do not support it - need some test client first
return DnDAction::None;
// return DnDAction::Ask;
}
return DnDAction::None;
}
xcb_atom_t Drag::clientActionToAtom(DnDAction action)
{
if (action == DnDAction::Copy) {
return atoms->xdnd_action_copy;
} else if (action == DnDAction::Move) {
return atoms->xdnd_action_move;
} else if (action == DnDAction::Ask) {
// we currently do not support it - need some test client first
return XCB_ATOM_NONE;
// return atoms->xdnd_action_ask;
}
return XCB_ATOM_NONE;
}
} // namespace Xwl
} // namespace KWin

View file

@ -9,9 +9,8 @@
#ifndef KWIN_XWL_DRAG
#define KWIN_XWL_DRAG
#include <KWayland/Client/datadevicemanager.h>
#include <QPoint>
#include <QObject>
#include <xcb/xcb.h>
@ -23,8 +22,6 @@ namespace Xwl
{
enum class DragEventReply;
using DnDAction = KWayland::Client::DataDeviceManager::DnDAction;
/**
* An ongoing drag operation.
*/
@ -37,8 +34,6 @@ public:
~Drag() override;
static void sendClientMessage(xcb_window_t target, xcb_atom_t type, xcb_client_message_data_t *data);
static DnDAction atomToClientAction(xcb_atom_t atom);
static xcb_atom_t clientActionToAtom(DnDAction action);
virtual bool handleClientMessage(xcb_client_message_event_t *event) = 0;
virtual DragEventReply moveFilter(Toplevel *target, const QPoint &pos) = 0;

View file

@ -17,9 +17,6 @@
#include "wayland_server.h"
#include "workspace.h"
#include <KWayland/Client/datadevice.h>
#include <KWayland/Client/datasource.h>
#include <KWaylandServer/datasource_interface.h>
#include <KWaylandServer/datadevice_interface.h>
#include <KWaylandServer/seat_interface.h>
@ -33,6 +30,37 @@ namespace KWin
namespace Xwl
{
using DnDAction = KWaylandServer::DataDeviceManagerInterface::DnDAction;
using DnDActions = KWaylandServer::DataDeviceManagerInterface::DnDActions;
static DnDAction atomToClientAction(xcb_atom_t atom)
{
if (atom == atoms->xdnd_action_copy) {
return DnDAction::Copy;
} else if (atom == atoms->xdnd_action_move) {
return DnDAction::Move;
} else if (atom == atoms->xdnd_action_ask) {
// we currently do not support it - need some test client first
return DnDAction::None;
// return DnDAction::Ask;
}
return DnDAction::None;
}
static xcb_atom_t clientActionToAtom(DnDAction action)
{
if (action == DnDAction::Copy) {
return atoms->xdnd_action_copy;
} else if (action == DnDAction::Move) {
return atoms->xdnd_action_move;
} else if (action == DnDAction::Ask) {
// we currently do not support it - need some test client first
return XCB_ATOM_NONE;
// return atoms->xdnd_action_ask;
}
return XCB_ATOM_NONE;
}
WlToXDrag::WlToXDrag()
{
m_dsi = waylandServer()->seat()->dragSource()->dragSource();
@ -129,12 +157,8 @@ Xvisit::Xvisit(WlToXDrag *drag, AbstractClient *target)
}
free(reply);
const auto *dd = DataBridge::self()->dataDevice();
// proxy drop
m_enterConnection = connect(dd, &KWayland::Client::DataDevice::dragEntered,
this, &Xvisit::receiveOffer);
m_dropConnection = connect(dd, &KWayland::Client::DataDevice::dropped,
this, &Xvisit::drop);
m_dropConnection = connect(waylandServer()->seat(), &KWaylandServer::SeatInterface::dragDropped, this, &Xvisit::drop);
receiveOffer();
}
bool Xvisit::handleClientMessage(xcb_client_message_event_t *event)
@ -158,9 +182,9 @@ bool Xvisit::handleStatus(xcb_client_message_event_t *event)
m_accepts = data->data32[1] & 1;
xcb_atom_t actionAtom = data->data32[4];
auto drag = m_drag->dataSourceIface();
if (drag && !drag->mimeTypes().isEmpty()) {
drag->accept(m_accepts ? drag->mimeTypes().constFirst() : QString());
auto dataSource = m_drag->dataSourceIface();
if (dataSource && !dataSource->mimeTypes().isEmpty()) {
dataSource->accept(m_accepts ? dataSource->mimeTypes().constFirst() : QString());
}
// TODO: we could optimize via rectangle in data32[2] and data32[3]
@ -169,7 +193,7 @@ bool Xvisit::handleStatus(xcb_client_message_event_t *event)
if (!m_state.dropped) {
// as long as the drop is not yet done determine requested action
m_preferredAction = Drag::atomToClientAction(actionAtom);
m_preferredAction = atomToClientAction(actionAtom);
determineProposedAction();
requestDragAndDropAction();
}
@ -206,11 +230,8 @@ bool Xvisit::handleFinished(xcb_client_message_event_t *event)
Q_UNUSED(success);
Q_UNUSED(usedActionAtom);
// data offer might have been deleted already by the DataDevice
if (!m_dataOffer.isNull()) {
m_dataOffer->dragAndDropFinished();
delete m_dataOffer;
m_dataOffer = nullptr;
if (auto dataSource = m_drag->dataSourceIface()) {
dataSource->dndFinished();
}
doFinish();
return true;
@ -232,14 +253,17 @@ void Xvisit::sendPosition(const QPointF &globalPos)
data.data32[0] = DataBridge::self()->dnd()->window();
data.data32[2] = (x << 16) | y;
data.data32[3] = XCB_CURRENT_TIME;
data.data32[4] = Drag::clientActionToAtom(m_proposedAction);
data.data32[4] = clientActionToAtom(m_proposedAction);
Drag::sendClientMessage(m_target->window(), atoms->xdnd_position, &data);
}
void Xvisit::leave()
{
Q_ASSERT(!m_state.dropped);
if (m_state.dropped) {
// dropped, but not yet finished, it'll be cleaned up when the drag finishes
return;
}
if (m_state.finished) {
// was already finished
return;
@ -253,17 +277,9 @@ void Xvisit::leave()
void Xvisit::receiveOffer()
{
if (m_state.finished) {
// already ended
return;
}
Q_ASSERT(m_dataOffer.isNull());
m_dataOffer = DataBridge::self()->dataDevice()->dragOffer();
Q_ASSERT(!m_dataOffer.isNull());
retrieveSupportedActions();
m_actionConnection = connect(m_dataOffer, &KWayland::Client::DataOffer::sourceDragAndDropActionsChanged,
auto dragSource = m_drag->dataSourceIface();
connect(dragSource, &KWaylandServer::AbstractDataSource::supportedDragAndDropActionsChanged,
this, &Xvisit::retrieveSupportedActions);
enter();
}
@ -283,8 +299,8 @@ void Xvisit::enter()
void Xvisit::sendEnter()
{
auto drag = m_drag->dataSourceIface();
if (!drag) {
auto dataSource = m_drag->dataSourceIface();
if (!dataSource) {
return;
}
@ -292,9 +308,7 @@ void Xvisit::sendEnter()
data.data32[0] = DataBridge::self()->dnd()->window();
data.data32[1] = m_version << 24;
// TODO: replace this with the mime type getter from m_dataOffer,
// then we can get rid of m_drag.
const auto mimeTypesNames = drag->mimeTypes();
const auto mimeTypesNames = dataSource->mimeTypes();
const int mimesCount = mimeTypesNames.size();
size_t cnt = 0;
size_t totalCnt = 0;
@ -363,7 +377,7 @@ void Xvisit::sendLeave()
void Xvisit::retrieveSupportedActions()
{
m_supportedActions = m_dataOffer->sourceDragAndDropActions();
m_supportedActions = m_drag->dataSourceIface()->supportedDragAndDropActions();
determineProposedAction();
requestDragAndDropAction();
}
@ -386,16 +400,22 @@ void Xvisit::determineProposedAction()
void Xvisit::requestDragAndDropAction()
{
if (m_dataOffer.isNull()) {
return;
}
const auto pref = m_preferredAction != DnDAction::None ? m_preferredAction:
DnDAction action = m_preferredAction != DnDAction::None ? m_preferredAction:
DnDAction::Copy;
// we assume the X client supports Move, but this might be wrong - then
// the drag just cancels, if the user tries to force it.
m_dataOffer->setDragAndDropActions(DnDAction::Copy | DnDAction::Move, pref);
waylandServer()->dispatch();
// As we skip the client data device, we do action negotiation directly then tell the source.
if (m_supportedActions.testFlag(action)) {
// everything is supported, no changes are needed
} else if (m_supportedActions.testFlag(DnDAction::Copy)) {
action = DnDAction::Copy;
} else if (m_supportedActions.testFlag(DnDAction::Move)) {
action = DnDAction::Move;
}
if (auto dataSource = m_drag->dataSourceIface()) {
dataSource->dndAction(action);
}
}
void Xvisit::drop()

View file

@ -11,19 +11,12 @@
#include "drag.h"
#include <KWayland/Client/dataoffer.h>
#include <KWaylandServer/datadevicemanager_interface.h>
#include <QPoint>
#include <QPointer>
#include <QVector>
namespace KWayland
{
namespace Client
{
class Surface;
}
}
namespace KWaylandServer
{
class DataDeviceInterface;
@ -42,8 +35,6 @@ class X11Source;
enum class DragEventReply;
class Xvisit;
using DnDActions = KWayland::Client::DataDeviceManager::DnDActions;
class WlToXDrag : public Drag
{
Q_OBJECT
@ -125,16 +116,12 @@ private:
QPoint cache;
} m_pos;
// Must be QPointer, because KWayland::Client::DataDevice
// might delete it.
QPointer<KWayland::Client::DataOffer> m_dataOffer;
// supported by the Wl source
DnDActions m_supportedActions = DnDAction::None;
KWaylandServer::DataDeviceManagerInterface::DnDActions m_supportedActions = KWaylandServer::DataDeviceManagerInterface::DnDAction::None;
// preferred by the X client
DnDAction m_preferredAction = DnDAction::None;
KWaylandServer::DataDeviceManagerInterface::DnDAction m_preferredAction = KWaylandServer::DataDeviceManagerInterface::DnDAction::None;
// decided upon by the compositor
DnDAction m_proposedAction = DnDAction::None;
KWaylandServer::DataDeviceManagerInterface::DnDAction m_proposedAction = KWaylandServer::DataDeviceManagerInterface::DnDAction::None;
struct {
bool entered = false;

View file

@ -33,6 +33,37 @@ namespace KWin
namespace Xwl
{
using DnDAction = KWayland::Client::DataDeviceManager::DnDAction;
using DnDActions = KWayland::Client::DataDeviceManager::DnDActions;
static DnDAction atomToClientAction(xcb_atom_t atom)
{
if (atom == atoms->xdnd_action_copy) {
return DnDAction::Copy;
} else if (atom == atoms->xdnd_action_move) {
return DnDAction::Move;
} else if (atom == atoms->xdnd_action_ask) {
// we currently do not support it - need some test client first
return DnDAction::None;
// return DnDAction::Ask;
}
return DnDAction::None;
}
xcb_atom_t clientActionToAtom(DnDAction action)
{
if (action == DnDAction::Copy) {
return atoms->xdnd_action_copy;
} else if (action == DnDAction::Move) {
return atoms->xdnd_action_move;
} else if (action == DnDAction::Ask) {
// we currently do not support it - need some test client first
return XCB_ATOM_NONE;
// return atoms->xdnd_action_ask;
}
return XCB_ATOM_NONE;
}
static QStringList atomToMimeTypes(xcb_atom_t atom)
{
QStringList mimeTypes;
@ -438,7 +469,7 @@ bool WlVisit::handlePosition(xcb_client_message_event_t *event)
xcb_atom_t actionAtom = m_version > 1 ? data->data32[4] :
atoms->xdnd_action_copy;
auto action = Drag::atomToClientAction(actionAtom);
auto action = atomToClientAction(actionAtom);
if (action == DnDAction::None) {
// copy action is always possible in XDND

View file

@ -12,9 +12,6 @@
#include "drag.h"
#include <KWayland/Client/datadevicemanager.h>
#include <KWayland/Client/dataoffer.h>
#include <KWaylandServer/datadevicemanager_interface.h>
#include <QPoint>
#include <QPointer>
@ -52,8 +49,8 @@ public:
DragEventReply moveFilter(Toplevel *target, const QPoint &pos) override;
bool handleClientMessage(xcb_client_message_event_t *event) override;
void setDragAndDropAction(DnDAction action);
DnDAction selectedDragAndDropAction();
void setDragAndDropAction(KWayland::Client::DataDeviceManager::DnDAction action);
KWayland::Client::DataDeviceManager::DnDAction selectedDragAndDropAction();
bool end() override {
return false;
@ -81,7 +78,7 @@ private:
QVector<WlVisit *> m_oldVisits;
bool m_performed = false;
DnDAction m_lastSelectedDragAndDropAction = DnDAction::None;
KWayland::Client::DataDeviceManager::DnDAction m_lastSelectedDragAndDropAction = KWayland::Client::DataDeviceManager::DnDAction::None;
Q_DISABLE_COPY(XToWlDrag)
};
@ -142,7 +139,7 @@ private:
uint32_t m_version = 0;
xcb_atom_t m_actionAtom;
DnDAction m_action = DnDAction::None;
KWayland::Client::DataDeviceManager::DnDAction m_action = KWayland::Client::DataDeviceManager::DnDAction::None;
bool m_mapped = false;
bool m_entered = false;