19#include <xcb/xcb_event.h> 
   20#include <xcb/xfixes.h> 
   31    if (mimeType == QLatin1String(
"text/plain;charset=utf-8")) {
 
   34    if (mimeType == QLatin1String(
"text/plain")) {
 
   37    if (mimeType == QLatin1String(
"text/x-uri")) {
 
 
   45    return Xcb::Atom(mimeType.toLatin1(), 
false, kwinApp()->x11Connection());
 
 
   50    xcb_connection_t *xcbConn = kwinApp()->x11Connection();
 
   51    xcb_get_atom_name_cookie_t nameCookie = xcb_get_atom_name(xcbConn, 
atom);
 
   52    xcb_get_atom_name_reply_t *nameReply = xcb_get_atom_name_reply(xcbConn, nameCookie, 
nullptr);
 
   57    const size_t length = xcb_get_atom_name_name_length(nameReply);
 
   58    QString name = QString::fromLatin1(xcb_get_atom_name_name(nameReply), length);
 
 
   65    QStringList mimeTypes;
 
   68        mimeTypes << QString::fromLatin1(
"text/plain;charset=utf-8");
 
   70        mimeTypes << QString::fromLatin1(
"text/plain");
 
   72        mimeTypes << 
"text/uri-list" 
 
   84    xcb_connection_t *xcbConn = kwinApp()->x11Connection();
 
   85    m_window = xcb_generate_id(kwinApp()->x11Connection());
 
   86    m_requestorWindow = m_window;
 
 
   92    if (event->window != m_window) {
 
   95    if (event->selection != m_atom) {
 
   98    if (m_disownPending) {
 
  100        m_disownPending = 
false;
 
  103    if (event->owner == m_window && m_waylandSource) {
 
  108        m_timestamp = 
event->timestamp;
 
 
  119    switch (event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) {
 
  120    case XCB_SELECTION_NOTIFY:
 
  121        return handleSelectionNotify(
reinterpret_cast<xcb_selection_notify_event_t *
>(event));
 
  122    case XCB_PROPERTY_NOTIFY:
 
  123        return handlePropertyNotify(
reinterpret_cast<xcb_property_notify_event_t *
>(event));
 
  124    case XCB_SELECTION_REQUEST:
 
  125        return handleSelectionRequest(
reinterpret_cast<xcb_selection_request_event_t *
>(event));
 
  126    case XCB_CLIENT_MESSAGE:
 
  130            return handleXfixesNotify(
reinterpret_cast<xcb_xfixes_selection_notify_event_t *
>(event));
 
 
  141        xcb_selection_notify_event_t notify;
 
  144    memset(&u, 0, 
sizeof(u));
 
  145    static_assert(
sizeof(u.notify) < 32, 
"wouldn't need the union otherwise");
 
  146    u.notify.response_type = XCB_SELECTION_NOTIFY;
 
  147    u.notify.sequence = 0;
 
  148    u.notify.time = 
event->time;
 
  149    u.notify.requestor = 
event->requestor;
 
  150    u.notify.selection = 
event->selection;
 
  151    u.notify.target = 
event->target;
 
  152    u.notify.property = success ? 
event->property : xcb_atom_t(XCB_ATOM_NONE);
 
  154    xcb_connection_t *xcbConn = kwinApp()->x11Connection();
 
  155    xcb_send_event(xcbConn, 0, event->requestor, XCB_EVENT_MASK_NO_EVENT, (
const char *)&u);
 
 
  161    xcb_connection_t *xcbConn = kwinApp()->x11Connection();
 
  162    const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
 
  163    xcb_xfixes_select_selection_input(xcbConn,
 
 
  172    if (m_waylandSource) {
 
  173        m_waylandSource->deleteLater();
 
  174        m_waylandSource = 
nullptr;
 
  179        m_waylandSource = source;
 
 
  186    if (!event || event->owner == XCB_WINDOW_NONE) {
 
 
  200    xcb_connection_t *xcbConn = kwinApp()->x11Connection();
 
  202        xcb_set_selection_owner(xcbConn,
 
  205                                XCB_TIME_CURRENT_TIME);
 
  207        m_disownPending = 
true;
 
  208        xcb_set_selection_owner(xcbConn,
 
 
  219    if (
window == XCB_WINDOW_NONE) {
 
  223    m_requestorWindow = 
window;
 
 
  227bool Selection::handleSelectionRequest(xcb_selection_request_event_t *event)
 
  229    if (event->selection != m_atom) {
 
  233    if (qobject_cast<X11Window *>(
workspace()->activeWindow()) == 
nullptr) {
 
  240    if (m_window != event->owner || !m_waylandSource) {
 
  241        if (event->time < m_timestamp) {
 
  252bool Selection::handleSelectionNotify(xcb_selection_notify_event_t *event)
 
  257    for (TransferXtoWl *transfer : std::as_const(m_xToWlTransfers)) {
 
  258        if (transfer->handleSelectionNotify(event)) {
 
  265bool Selection::handlePropertyNotify(xcb_property_notify_event_t *event)
 
  267    for (TransferXtoWl *transfer : std::as_const(m_xToWlTransfers)) {
 
  268        if (transfer->handlePropertyNotify(event)) {
 
  272    for (TransferWltoX *transfer : std::as_const(m_wlToXTransfers)) {
 
  273        if (transfer->handlePropertyNotify(event)) {
 
  280void Selection::startTransferToWayland(xcb_atom_t target, qint32 fd)
 
  283    auto *transfer = 
new TransferXtoWl(m_atom, target, fd, m_xSource->
timestamp(), m_requestorWindow, 
this);
 
  284    m_xToWlTransfers << transfer;
 
  288        transfer->deleteLater();
 
  289        m_xToWlTransfers.removeOne(transfer);
 
  290        endTimeoutTransfersTimer();
 
  292    startTimeoutTransfersTimer();
 
  295void Selection::startTransferToX(xcb_selection_request_event_t *event, qint32 fd)
 
  298    auto *transfer = 
new TransferWltoX(m_atom, event, fd, 
this);
 
  306        transfer->deleteLater();
 
  307        m_wlToXTransfers.removeOne(transfer);
 
  308        endTimeoutTransfersTimer();
 
  315    m_wlToXTransfers.append(transfer);
 
  319    transfer->startTransferFromSource();
 
  323    startTimeoutTransfersTimer();
 
  326void Selection::startTimeoutTransfersTimer()
 
  328    if (m_timeoutTransfers) {
 
  331    m_timeoutTransfers = 
new QTimer(
this);
 
  332    connect(m_timeoutTransfers, &QTimer::timeout, 
this, &Selection::timeoutTransfers);
 
  333    m_timeoutTransfers->start(5000);
 
  336void Selection::endTimeoutTransfersTimer()
 
  338    if (m_xToWlTransfers.isEmpty() && m_wlToXTransfers.isEmpty()) {
 
  339        delete m_timeoutTransfers;
 
  340        m_timeoutTransfers = 
nullptr;
 
  344void Selection::timeoutTransfers()
 
  346    for (TransferXtoWl *transfer : std::as_const(m_xToWlTransfers)) {
 
  349    for (TransferWltoX *transfer : std::as_const(m_wlToXTransfers)) {
 
  357#include "moc_selection.cpp" 
int fixesSelectionNotifyEvent() const
static Extensions * self()
virtual void x11OffersChanged(const QStringList &added, const QStringList &removed)=0
bool handleXfixesNotify(xcb_xfixes_selection_notify_event_t *event)
void overwriteRequestorWindow(xcb_window_t window)
static void sendSelectionNotify(xcb_selection_request_event_t *event, bool success)
void transferFinished(xcb_timestamp_t eventTime)
static QStringList atomToMimeTypes(xcb_atom_t atom)
void createX11Source(xcb_xfixes_selection_notify_event_t *event)
static QString atomName(xcb_atom_t atom)
Selection(xcb_atom_t atom, QObject *parent)
static xcb_atom_t mimeTypeToAtomLiteral(const QString &mimeType)
void setWlSource(WlSource *source)
void ownSelection(bool own)
xcb_window_t window() const
virtual void x11OfferLost()=0
virtual void doHandleXfixesNotify(xcb_xfixes_selection_notify_event_t *event)=0
virtual bool handleClientMessage(xcb_client_message_event_t *event)
static xcb_atom_t mimeTypeToAtom(const QString &mimeType)
bool filterEvent(xcb_generic_event_t *event)
xcb_timestamp_t timestamp() const
void setTimestamp(xcb_timestamp_t time)
void selectionNotify(xcb_selection_request_event_t *event, bool success)
bool handleSelectionRequest(xcb_selection_request_event_t *event)
void transferReady(xcb_selection_request_event_t *event, qint32 fd)
bool handleSelectionNotify(xcb_selection_notify_event_t *event)
void offersChanged(const QStringList &added, const QStringList &removed)
void transferReady(xcb_atom_t target, qint32 fd)
void setRequestor(xcb_window_t window)
KWIN_EXPORT Atoms * atoms