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); 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 Xwl
} // namespace KWin } // namespace KWin

View file

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

View file

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

View file

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

View file

@ -33,6 +33,37 @@ namespace KWin
namespace Xwl 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) static QStringList atomToMimeTypes(xcb_atom_t atom)
{ {
QStringList mimeTypes; 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] : xcb_atom_t actionAtom = m_version > 1 ? data->data32[4] :
atoms->xdnd_action_copy; atoms->xdnd_action_copy;
auto action = Drag::atomToClientAction(actionAtom); auto action = atomToClientAction(actionAtom);
if (action == DnDAction::None) { if (action == DnDAction::None) {
// copy action is always possible in XDND // copy action is always possible in XDND

View file

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