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