21#include "wayland/datasource.h" 
   37using DnDActions = KWin::DataDeviceManagerInterface::DnDActions;
 
   39static QStringList atomToMimeTypes(xcb_atom_t atom)
 
   41    QStringList mimeTypes;
 
   44        mimeTypes << QString::fromLatin1(
"text/plain;charset=utf-8");
 
   46        mimeTypes << QString::fromLatin1(
"text/plain");
 
   48        mimeTypes << QString::fromLatin1(
"text/uri-list") << QString::fromLatin1(
"text/x-uri");
 
   50        mimeTypes << QStringLiteral(
"text/x-moz-url");
 
   52        mimeTypes << QStringLiteral(
"_NETSCAPE_URL");
 
   66        auto it = std::find_if(m_dataRequests.begin(), m_dataRequests.end(), [eventTime](
const QPair<xcb_timestamp_t, bool> &req) {
 
   67            return req.first == eventTime && req.second == false;
 
   69        if (it == m_dataRequests.end()) {
 
   77        m_dataRequests << QPair<xcb_timestamp_t, bool>(m_source->
timestamp(), 
false);
 
   86            QTimer::singleShot(2000, 
this, [
this] {
 
   90                } 
else if (m_dataRequests.size() == 0) {
 
   92                    m_visit->sendFinished();
 
  104        if (m_visit && !m_visit->
leave()) {
 
  105            connect(m_visit, &WlVisit::finish, this, &XToWlDrag::checkForFinished);
 
  114    seat->startDrag(&m_selectionSource, seat->focusedPointerSurface(), serial);
 
 
  125    if (m_visit && m_visit->
target() == target) {
 
  130        if (m_visit->
leave()) {
 
  134                m_oldVisits.removeOne(visit);
 
  137            m_oldVisits << m_visit;
 
  140    const bool hasCurrent = m_visit;
 
  149            seat->setDragTarget(
nullptr, 
nullptr);
 
  154    auto *ac = 
static_cast<Window *
>(target);
 
  155    m_visit = 
new WlVisit(ac, 
this, m_dnd);
 
 
  162    for (
auto *visit : std::as_const(m_oldVisits)) {
 
  163        if (visit->handleClientMessage(event)) {
 
 
  183void XToWlDrag::setOffers(
const Mimes &offers)
 
  186    if (offers.isEmpty()) {
 
  192    if (m_offers == offers) {
 
  200    QStringList mimeTypes;
 
  201    mimeTypes.reserve(offers.size());
 
  202    for (
const auto &mimePair : offers) {
 
  203        mimeTypes.append(mimePair.first);
 
  209using Mime = QPair<QString, xcb_atom_t>;
 
  211void XToWlDrag::setDragTarget()
 
  217    auto *ac = m_visit->
target();
 
  220    auto dropTarget = seat->dropHandlerForSurface(ac->surface());
 
  222    if (!dropTarget || !ac->surface()) {
 
  225    seat->setDragTarget(dropTarget, ac->surface(), ac->inputTransformation());
 
  228bool XToWlDrag::checkForFinished()
 
  238    if (m_dataRequests.size() == 0 && m_selectionSource.
isAccepted()) {
 
  242    const bool transfersFinished = std::all_of(m_dataRequests.begin(), m_dataRequests.end(),
 
  243                                               [](QPair<xcb_timestamp_t, bool> req) {
 
  246    if (transfersFinished) {
 
  250    return transfersFinished;
 
  259    xcb_connection_t *xcbConn = kwinApp()->x11Connection();
 
  261    m_window = xcb_generate_id(xcbConn);
 
  264    const uint32_t dndValues[] = {XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE};
 
  265    xcb_create_window(xcbConn,
 
  266                      XCB_COPY_FROM_PARENT,
 
  268                      kwinApp()->x11RootWindow(),
 
  272                      XCB_WINDOW_CLASS_INPUT_OUTPUT,
 
  273                      XCB_COPY_FROM_PARENT,
 
  278    xcb_change_property(xcbConn,
 
  279                        XCB_PROP_MODE_REPLACE,
 
  285    xcb_map_window(xcbConn, m_window);
 
 
  295    xcb_connection_t *xcbConn = kwinApp()->x11Connection();
 
  296    xcb_destroy_window(xcbConn, m_window);
 
 
  309    if (event->window != m_window) {
 
  315        return handleEnter(event);
 
  317        return handlePosition(event);
 
  319        return handleDrop(event);
 
  321        return handleLeave(event);
 
 
  326static bool hasMimeName(
const Mimes &mimes, 
const QString &name)
 
  328    return std::any_of(mimes.begin(), mimes.end(),
 
  329                       [name](
const Mime &m) {
 
  330                           return m.first == name;
 
  334bool WlVisit::handleEnter(xcb_client_message_event_t *event)
 
  342    xcb_client_message_data_t *data = &
event->data;
 
  343    m_srcWindow = data->data32[0];
 
  344    m_version = data->data32[1] >> 24;
 
  348    if (!(data->data32[1] & 1)) {
 
  350        for (
size_t i = 0; i < 3; i++) {
 
  351            xcb_atom_t mimeAtom = data->data32[2 + i];
 
  352            const auto mimeStrings = atomToMimeTypes(mimeAtom);
 
  353            for (
const auto &mime : mimeStrings) {
 
  354                if (!hasMimeName(offers, mime)) {
 
  355                    offers << 
Mime(mime, mimeAtom);
 
  361        getMimesFromWinProperty(offers);
 
  368void WlVisit::getMimesFromWinProperty(
Mimes &offers)
 
  370    xcb_connection_t *xcbConn = kwinApp()->x11Connection();
 
  371    auto cookie = xcb_get_property(xcbConn,
 
  375                                   XCB_GET_PROPERTY_TYPE_ANY,
 
  378    auto *reply = xcb_get_property_reply(xcbConn, cookie, 
nullptr);
 
  379    if (reply == 
nullptr) {
 
  382    if (reply->type != XCB_ATOM_ATOM || reply->value_len == 0) {
 
  388    xcb_atom_t *mimeAtoms = 
static_cast<xcb_atom_t *
>(xcb_get_property_value(reply));
 
  389    for (
size_t i = 0; i < reply->value_len; ++i) {
 
  390        const auto mimeStrings = atomToMimeTypes(mimeAtoms[i]);
 
  391        for (
const auto &mime : mimeStrings) {
 
  392            if (!hasMimeName(offers, mime)) {
 
  393                offers << 
Mime(mime, mimeAtoms[i]);
 
  400bool WlVisit::handlePosition(xcb_client_message_event_t *event)
 
  402    xcb_client_message_data_t *data = &
event->data;
 
  403    m_srcWindow = data->data32[0];
 
  407        m_action = DnDAction::None;
 
  408        m_actionAtom = XCB_ATOM_NONE;
 
  413    const xcb_timestamp_t timestamp = data->data32[3];
 
  419    if (action == DnDAction::None) {
 
  421        action = DnDAction::Copy;
 
  425    if (m_action != action) {
 
  427        m_actionAtom = actionAtom;
 
  435bool WlVisit::handleDrop(xcb_client_message_event_t *event)
 
  437    m_dropHandled = 
true;
 
  439    xcb_client_message_data_t *data = &
event->data;
 
  440    m_srcWindow = data->data32[0];
 
  441    const xcb_timestamp_t timestamp = data->data32[2];
 
  450void WlVisit::doFinish()
 
  457bool WlVisit::handleLeave(xcb_client_message_event_t *event)
 
  460    xcb_client_message_data_t *data = &
event->data;
 
  461    m_srcWindow = data->data32[0];
 
  466void WlVisit::sendStatus()
 
  469    uint32_t flags = 1 << 1;
 
  470    if (targetAcceptsAction()) {
 
  474    xcb_client_message_data_t data = {};
 
  475    data.data32[0] = m_window;
 
  476    data.data32[1] = flags;
 
  477    data.data32[4] = flags & (1 << 0) ? m_actionAtom : static_cast<uint32_t>(XCB_ATOM_NONE);
 
  483    const bool accepted = m_entered && m_action != DnDAction::None;
 
  484    xcb_client_message_data_t data = {};
 
  485    data.data32[0] = m_window;
 
  486    data.data32[1] = accepted;
 
  487    data.data32[2] = accepted ? m_actionAtom : 
static_cast<uint32_t
>(XCB_ATOM_NONE);
 
 
  491bool WlVisit::targetAcceptsAction()
 const 
  493    if (m_action == DnDAction::None) {
 
  497    return selAction == m_action || selAction == DnDAction::Copy;
 
  500void WlVisit::unmapProxyWindow()
 
  505    xcb_connection_t *xcbConn = kwinApp()->x11Connection();
 
  506    xcb_unmap_window(xcbConn, m_window);
 
  516#include "moc_drag_x.cpp" 
Xcb::Atom xdnd_action_copy
quint32 pointerButtonSerial(quint32 button) const
ClientConnection * client() const
SeatInterface * seat() const
SurfaceInterface * surface() const
void updateStackingOrder(bool propagate_new_windows=false)
void removeManualOverlay(xcb_window_t id)
void addManualOverlay(xcb_window_t id)
static uint32_t version()
static DnDAction atomToClientAction(xcb_atom_t atom)
static void sendClientMessage(xcb_window_t target, xcb_atom_t type, xcb_client_message_data_t *data)
void overwriteRequestorWindow(xcb_window_t window)
void transferFinished(xcb_timestamp_t eventTime)
static QString atomName(xcb_atom_t atom)
xcb_timestamp_t timestamp() const
void setTimestamp(xcb_timestamp_t time)
WlVisit(Window *target, XToWlDrag *drag, Dnd *dnd)
void finish(WlVisit *self)
bool handleClientMessage(xcb_client_message_event_t *event)
void offersReceived(const Mimes &offers)
void transferReady(xcb_atom_t target, qint32 fd)
void startTransfer(const QString &mimeName, qint32 fd)
void setOffers(const Mimes &offers)
bool handleClientMessage(xcb_client_message_event_t *event) override
void setDragAndDropAction(DataDeviceManagerInterface::DnDAction action)
DataDeviceManagerInterface::DnDAction selectedDragAndDropAction()
X11Source * x11Source() const
DragEventReply moveFilter(Window *target) override
XToWlDrag(X11Source *source, Dnd *dnd)
void dataRequested(const QString &mimeType, qint32 fd)
bool isAccepted() const override
void setMimeTypes(const QStringList &mimeTypes)
void setSupportedDndActions(DataDeviceManagerInterface::DnDActions dndActions)
DataDeviceManagerInterface::DnDAction selectedDndAction() const override
KWin::DataDeviceManagerInterface::DnDActions DnDActions
QPair< QString, xcb_atom_t > Mime
QList< QPair< QString, xcb_atom_t > > Mimes
WaylandServer * waylandServer()
KWIN_EXPORT Atoms * atoms