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