diff options
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbclipboard.cpp | 3 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 53 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbdrag.cpp | 63 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbdrag.h | 7 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 4 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.h | 2 |
7 files changed, 101 insertions, 34 deletions
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index f021ab8b4a..142a8dfcde 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -300,6 +300,9 @@ void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) m_timestamp[mode] = XCB_CURRENT_TIME; } + if (connection()->time() == XCB_CURRENT_TIME) + connection()->setTime(connection()->getTimestamp()); + if (data) { newOwner = owner(); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 401739f7d5..ad9fb1d19c 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -864,6 +864,59 @@ void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id) xcb_flush(xcb_connection()); } +namespace +{ + class PropertyNotifyEvent { + public: + PropertyNotifyEvent(xcb_window_t win, xcb_atom_t property) + : window(win), type(XCB_PROPERTY_NOTIFY), atom(property) {} + xcb_window_t window; + int type; + xcb_atom_t atom; + bool checkEvent(xcb_generic_event_t *event) const { + if (!event) + return false; + if ((event->response_type & ~0x80) != type) { + return false; + } else { + xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; + if ((pn->window == window) && (pn->atom == atom)) + return true; + } + return false; + } + }; +} + +xcb_timestamp_t QXcbConnection::getTimestamp() +{ + // send a dummy event to myself to get the timestamp from X server. + xcb_window_t rootWindow = screens().at(primaryScreen())->root(); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, rootWindow, atom(QXcbAtom::CLIP_TEMPORARY), + XCB_ATOM_INTEGER, 32, 0, NULL); + + connection()->flush(); + PropertyNotifyEvent checker(rootWindow, atom(QXcbAtom::CLIP_TEMPORARY)); + + xcb_generic_event_t *event = 0; + // lets keep this inside a loop to avoid a possible race condition, where + // reader thread has not yet had the time to acquire the mutex in order + // to add the new set of events to its event queue + while (true) { + connection()->sync(); + if (event = checkEvent(checker)) + break; + } + + xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; + xcb_timestamp_t timestamp = pn->time; + free(event); + + xcb_delete_property(xcb_connection(), rootWindow, atom(QXcbAtom::CLIP_TEMPORARY)); + + return timestamp; +} + void QXcbConnection::processXcbEvents() { QXcbEventArray *eventqueue = m_reader->lock(); diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 08dd304b3d..8a6c418788 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -319,7 +319,6 @@ public: QByteArray atomName(xcb_atom_t atom); const char *displayName() const { return m_displayName.constData(); } - xcb_connection_t *xcb_connection() const { return m_connection; } const xcb_setup_t *setup() const { return m_setup; } const xcb_format_t *formatForDepth(uint8_t depth) const; @@ -380,6 +379,8 @@ public: bool hasXRandr() const { return has_randr_extension; } bool hasInputShape() const { return has_input_shape; } + xcb_timestamp_t getTimestamp(); + private slots: void processXcbEvents(); diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 1a2de82fd3..5d887cd06d 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -53,6 +53,7 @@ #include <qguiapplication.h> #include <qrect.h> #include <qpainter.h> +#include <qtimer.h> #include <qpa/qwindowsysteminterface.h> @@ -140,8 +141,7 @@ QXcbDrag::QXcbDrag(QXcbConnection *c) : QXcbObject(c) init(); heartbeat = -1; - - transaction_expiry_timer = -1; + cleanup_timer = -1; } QXcbDrag::~QXcbDrag() @@ -510,17 +510,21 @@ void QXcbDrag::drop(const QMouseEvent *event) if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/) w = 0; - Transaction t = { connection()->time(), current_target, current_proxy_target, (w ? w->window() : 0), -// current_embedding_widget, - currentDrag() +// current_embeddig_widget, + currentDrag(), + QTime::currentTime() }; transactions.append(t); - restartDropExpiryTimer(); + + // timer is needed only for drops that came from other processes. + if (!t.targetWindow && cleanup_timer == -1) { + cleanup_timer = startTimer(XdndDropTransactionTimeout); + } if (w) { handleDrop(w->window(), &drop); @@ -563,16 +567,6 @@ xcb_atom_t QXcbDrag::toXdndAction(Qt::DropAction a) const } } -// timer used to discard old XdndDrop transactions -enum { XdndDropTransactionTimeout = 5000 }; // 5 seconds - -void QXcbDrag::restartDropExpiryTimer() -{ - if (transaction_expiry_timer != -1) - killTimer(transaction_expiry_timer); - transaction_expiry_timer = startTimer(XdndDropTransactionTimeout); -} - int QXcbDrag::findTransactionByWindow(xcb_window_t window) { int at = -1; @@ -771,8 +765,6 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t response.data.data32[3] = 0; // w, h response.data.data32[4] = toXdndAction(qt_response.acceptedAction()); // action - - if (answerRect.left() < 0) answerRect.setLeft(0); if (answerRect.right() > 4096) @@ -1015,7 +1007,6 @@ void QXcbDrag::handleFinished(const xcb_client_message_event_t *event) if (l[0]) { int at = findTransactionByWindow(l[0]); if (at != -1) { - restartDropExpiryTimer(); Transaction t = transactions.takeAt(at); // QDragManager *manager = QDragManager::self(); @@ -1044,12 +1035,13 @@ void QXcbDrag::handleFinished(const xcb_client_message_event_t *event) // current_proxy_target = proxy_target; // current_embedding_widget = embedding_widget; // manager->object = currentObject; + } else { + qWarning("QXcbDrag::handleFinished - drop data has expired"); } } waiting_for_status = false; } - void QXcbDrag::timerEvent(QTimerEvent* e) { if (e->timerId() == heartbeat && source_sameanswer.isNull()) { @@ -1057,19 +1049,35 @@ void QXcbDrag::timerEvent(QTimerEvent* e) QMouseEvent me(QEvent::MouseMove, pos, pos, pos, Qt::LeftButton, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); move(&me); - } else if (e->timerId() == transaction_expiry_timer) { + } else if (e->timerId() == cleanup_timer) { + bool stopTimer = true; for (int i = 0; i < transactions.count(); ++i) { const Transaction &t = transactions.at(i); if (t.targetWindow) { - // dnd within the same process, don't delete these + // dnd within the same process, don't delete, these are taken care of + // in handleFinished() continue; } - t.drag->deleteLater(); - transactions.removeAt(i--); - } + QTime currentTime = QTime::currentTime(); + int delta = t.time.msecsTo(currentTime); + if (delta > XdndDropTransactionTimeout) { + /* delete transactions which are older than XdndDropTransactionTimeout. It could mean + one of these: + - client has crashed and as a result we have never received XdndFinished + - showing dialog box on drop event where user's response takes more time than XdndDropTransactionTimeout (QTBUG-14493) + - dnd takes unusually long time to process data + */ + t.drag->deleteLater(); + transactions.removeAt(i--); + } else { + stopTimer = false; + } - killTimer(transaction_expiry_timer); - transaction_expiry_timer = -1; + } + if (stopTimer && cleanup_timer != -1) { + killTimer(cleanup_timer); + cleanup_timer = -1; + } } } @@ -1123,7 +1131,6 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event QDrag *transactionDrag = 0; if (at >= 0) { - restartDropExpiryTimer(); transactionDrag = transactions.at(at).drag; } else if (at == -2) { transactionDrag = currentDrag(); diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index 99c1e2d78f..41d15505ce 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -52,7 +52,7 @@ #include <qsharedpointer.h> #include <qpointer.h> #include <qvector.h> - +#include <qdatetime.h> #include <qpixmap.h> #include <qbackingstore.h> @@ -146,6 +146,10 @@ private: // timer used when target wants "continuous" move messages (eg. scroll) int heartbeat; + // 10 minute timer used to discard old XdndDrop transactions + enum { XdndDropTransactionTimeout = 600000 }; + int cleanup_timer; + QVector<xcb_atom_t> drag_types; struct Transaction @@ -156,6 +160,7 @@ private: QWindow *targetWindow; // QWidget *embedding_widget; QDrag *drag; + QTime time; }; QList<Transaction> transactions; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 64cb9afcc6..cefe1a7786 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -740,7 +740,7 @@ void QXcbWindow::setNetWmStates(NetWmStates states) xcb_flush(xcb_connection()); } -Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) +void QXcbWindow::setWindowFlags(Qt::WindowFlags flags) { Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); @@ -763,8 +763,6 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput); updateDoesNotAcceptFocus(flags & Qt::WindowDoesNotAcceptFocus); - - return flags; } void QXcbWindow::setMotifWindowFlags(Qt::WindowFlags flags) diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index ab18b502be..e2f62401dc 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -81,7 +81,7 @@ public: QMargins frameMargins() const; void setVisible(bool visible); - Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags); + void setWindowFlags(Qt::WindowFlags flags); Qt::WindowState setWindowState(Qt::WindowState state); WId winId() const; void setParent(const QPlatformWindow *window); |