20#include "wayland/datasource.h"
31using DnDActions = KWin::DataDeviceManagerInterface::DnDActions;
57 , m_dataSource(dataSource)
60 xcb_connection_t *xcbConn = kwinApp()->x11Connection();
61 xcb_get_property_cookie_t cookie = xcb_get_property(xcbConn,
65 XCB_GET_PROPERTY_TYPE_ANY,
67 auto *reply = xcb_get_property_reply(xcbConn, cookie,
nullptr);
72 if (reply->type != XCB_ATOM_ATOM) {
77 xcb_atom_t *value =
static_cast<xcb_atom_t *
>(xcb_get_property_value(reply));
102 xcb_client_message_data_t *data = &
event->data;
103 if (data->data32[0] != m_target->
window()) {
108 m_accepts = data->data32[1] & 1;
109 xcb_atom_t actionAtom = data->data32[4];
111 if (m_dataSource && !m_dataSource->mimeTypes().isEmpty()) {
112 m_dataSource->accept(m_accepts ? m_dataSource->mimeTypes().constFirst() : QString());
117 m_pos.pending =
false;
119 if (!m_state.dropped) {
122 determineProposedAction();
123 requestDragAndDropAction();
128 m_pos.cached =
false;
130 }
else if (m_state.dropped) {
139 xcb_client_message_data_t *data = &
event->data;
141 if (data->data32[0] != m_target->
window()) {
146 if (!m_state.dropped) {
153 m_dataSource->dndFinished();
161 const int16_t x = globalPos.x();
162 const int16_t y = globalPos.y();
165 m_pos.cache = QPoint(x, y);
169 m_pos.pending =
true;
171 xcb_client_message_data_t data = {};
172 data.data32[0] = m_dnd->
window();
173 data.data32[2] = (x << 16) | y;
174 data.data32[3] = XCB_CURRENT_TIME;
182 if (m_state.dropped) {
186 if (m_state.finished) {
191 if (m_state.entered) {
197void Xvisit::receiveOffer()
199 retrieveSupportedActions();
201 this, &Xvisit::retrieveSupportedActions);
207 m_state.entered =
true;
218void Xvisit::sendEnter()
224 xcb_client_message_data_t data = {};
225 data.data32[0] = m_dnd->
window();
226 data.data32[1] = m_version << 24;
228 const auto mimeTypesNames = m_dataSource->mimeTypes();
229 const int mimesCount = mimeTypesNames.size();
234 for (
const auto &mimeName : mimeTypesNames) {
241 if (atom != XCB_ATOM_NONE) {
242 data.data32[cnt] = atom;
247 for (
int i = cnt; i < 5; i++) {
248 data.data32[i] = XCB_ATOM_NONE;
251 if (mimesCount > 3) {
255 QList<xcb_atom_t> targets;
256 targets.resize(mimesCount);
259 for (
const auto &mimeName : mimeTypesNames) {
261 if (atom != XCB_ATOM_NONE) {
267 xcb_change_property(kwinApp()->x11Connection(),
268 XCB_PROP_MODE_REPLACE,
272 32, cnt, targets.data());
277void Xvisit::sendDrop(uint32_t time)
279 xcb_client_message_data_t data = {};
280 data.data32[0] = m_dnd->
window();
281 data.data32[2] = time;
290void Xvisit::sendLeave()
292 xcb_client_message_data_t data = {};
293 data.data32[0] = m_dnd->
window();
297void Xvisit::retrieveSupportedActions()
299 m_supportedActions = m_dataSource->supportedDragAndDropActions();
300 determineProposedAction();
301 requestDragAndDropAction();
304void Xvisit::determineProposedAction()
306 DnDAction oldProposedAction = m_proposedAction;
307 if (m_supportedActions.testFlag(m_preferredAction)) {
308 m_proposedAction = m_preferredAction;
309 }
else if (m_supportedActions.testFlag(DnDAction::Copy)) {
310 m_proposedAction = DnDAction::Copy;
312 m_proposedAction = DnDAction::None;
315 if (oldProposedAction != m_proposedAction && m_state.entered) {
320void Xvisit::requestDragAndDropAction()
322 DnDAction action = m_preferredAction != DnDAction::None ? m_preferredAction : DnDAction::Copy;
327 if (m_supportedActions.testFlag(action)) {
329 }
else if (m_supportedActions.testFlag(DnDAction::Copy)) {
330 action = DnDAction::Copy;
331 }
else if (m_supportedActions.testFlag(DnDAction::Move)) {
332 action = DnDAction::Move;
335 m_dataSource->dndAction(action);
341 Q_ASSERT(!m_state.finished);
342 m_state.dropped =
true;
346 if (!m_state.entered) {
361 sendDrop(XCB_CURRENT_TIME);
364void Xvisit::doFinish()
366 m_state.finished =
true;
367 m_pos.cached =
false;
372void Xvisit::stopConnections()
376 disconnect(m_motionConnection);
377 m_motionConnection = QMetaObject::Connection();
383#include "moc_drag_wl.cpp"
The AbstractDataSource class abstracts the data that can be transferred to another client.
void supportedDragAndDropActionsChanged()
void pointerPosChanged(const QPointF &pos)
xcb_window_t window() const
static uint32_t version()
static DnDAction atomToClientAction(xcb_atom_t atom)
XwlDropHandler * dropHandler() const
static xcb_atom_t clientActionToAtom(DnDAction action)
static void sendClientMessage(xcb_window_t target, xcb_atom_t type, xcb_client_message_data_t *data)
xcb_window_t window() const
static xcb_atom_t mimeTypeToAtom(const QString &mimeType)
bool handleClientMessage(xcb_client_message_event_t *event) override
DragEventReply moveFilter(Window *target) override
bool handleFinished(xcb_client_message_event_t *event)
void sendPosition(const QPointF &globalPos)
bool handleStatus(xcb_client_message_event_t *event)
bool handleClientMessage(xcb_client_message_event_t *event)
void finish(Xvisit *self)
Xvisit(X11Window *target, AbstractDataSource *dataSource, Dnd *dnd, QObject *parent)
bool handleClientMessage(xcb_client_message_event_t *event)
KWin::DataDeviceManagerInterface::DnDActions DnDActions
KWayland::Client::Seat * seat
WaylandServer * waylandServer()
KWIN_EXPORT Atoms * atoms