summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp45
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp115
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h16
4 files changed, 169 insertions, 15 deletions
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index 0a4d675606..dabdfcb6c5 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -835,6 +835,8 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
alloc_error = buf.size() != nbytes+1;
}
+ QElapsedTimer timer;
+ timer.start();
for (;;) {
connection()->flush();
xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY);
@@ -870,9 +872,11 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
tmp_buf.resize(0);
offset += length;
}
- } else {
- break;
}
+
+ const auto elapsed = timer.elapsed();
+ if (elapsed > clipboard_timeout)
+ break;
}
// timed out ... create a new requestor window, otherwise the requestor
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 9abdae6a7c..34fbc0b10b 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -221,6 +221,12 @@ void QXcbConnection::printXcbEvent(const QLoggingCategory &log, const char *mess
}
#define CASE_PRINT_AND_RETURN(name) case name : PRINT_AND_RETURN(#name);
+#define XI_PRINT_AND_RETURN(name) { \
+ qCDebug(log, "%s | XInput Event(%s) | sequence: %d", message, name, sequence); \
+ return; \
+}
+#define XI_CASE_PRINT_AND_RETURN(name) case name : XI_PRINT_AND_RETURN(#name);
+
switch (response_type) {
CASE_PRINT_AND_RETURN( XCB_KEY_PRESS );
CASE_PRINT_AND_RETURN( XCB_KEY_RELEASE );
@@ -255,7 +261,44 @@ void QXcbConnection::printXcbEvent(const QLoggingCategory &log, const char *mess
CASE_PRINT_AND_RETURN( XCB_COLORMAP_NOTIFY );
CASE_PRINT_AND_RETURN( XCB_CLIENT_MESSAGE );
CASE_PRINT_AND_RETURN( XCB_MAPPING_NOTIFY );
- CASE_PRINT_AND_RETURN( XCB_GE_GENERIC );
+ case XCB_GE_GENERIC: {
+ if (hasXInput2() && isXIEvent(event)) {
+ auto *xiDeviceEvent = reinterpret_cast<const xcb_input_button_press_event_t*>(event); // qt_xcb_input_device_event_t
+ switch (xiDeviceEvent->event_type) {
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_KEY_PRESS );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_KEY_RELEASE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_BUTTON_PRESS );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_BUTTON_RELEASE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_MOTION );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_ENTER );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_LEAVE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_FOCUS_IN );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_FOCUS_OUT );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_HIERARCHY );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_PROPERTY );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_KEY_PRESS );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_KEY_RELEASE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_BUTTON_PRESS );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_BUTTON_RELEASE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_MOTION );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_TOUCH_BEGIN );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_TOUCH_UPDATE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_TOUCH_END );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_TOUCH_OWNERSHIP );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_TOUCH_BEGIN );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_TOUCH_UPDATE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_TOUCH_END );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_BARRIER_HIT );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_BARRIER_LEAVE );
+ default:
+ qCDebug(log, "%s | XInput Event(other type) | sequence: %d", message, sequence);
+ return;
+ }
+ } else {
+ qCDebug(log, "%s | %s(%d) | sequence: %d", message, "XCB_GE_GENERIC", response_type, sequence);
+ return;
+ }
+ }
}
// XFixes
if (isXFixesType(response_type, XCB_XFIXES_SELECTION_NOTIFY))
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 050182537d..da179591e9 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -564,6 +564,11 @@ void QXcbWindow::setGeometry(const QRect &rect)
{
QPlatformWindow::setGeometry(rect);
+ if (shouldDeferTask(Task::SetGeometry)) {
+ m_deferredGeometry = rect;
+ return;
+ }
+
propagateSizeHints();
QXcbScreen *currentScreen = xcbScreen();
@@ -688,6 +693,9 @@ void QXcbWindow::setVisible(bool visible)
void QXcbWindow::show()
{
+ if (shouldDeferTask(Task::Map))
+ return;
+
if (window()->isTopLevel()) {
// update WM_NORMAL_HINTS
@@ -738,6 +746,10 @@ void QXcbWindow::show()
void QXcbWindow::hide()
{
+ if (shouldDeferTask(Task::Unmap))
+ return;
+
+ m_wmStateValid = false;
xcb_unmap_window(xcb_connection(), m_window);
// send synthetic UnmapNotify event according to icccm 4.1.4
@@ -897,6 +909,9 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates()
void QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
{
+ if (shouldDeferTask(Task::SetWindowFlags))
+ return;
+
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
if (type == Qt::ToolTip)
@@ -926,6 +941,8 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput);
updateDoesNotAcceptFocus(flags & Qt::WindowDoesNotAcceptFocus);
+
+ m_isWmManagedWindow = !(flags & Qt::X11BypassWindowManagerHint);
}
void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags)
@@ -1125,6 +1142,9 @@ void QXcbWindow::setWindowState(Qt::WindowStates state)
if (state == m_windowState)
return;
+ if (shouldDeferTask(Task::SetWindowState))
+ return;
+
// unset old state
if (m_windowState & Qt::WindowMinimized)
xcb_map_window(xcb_connection(), m_window);
@@ -1874,6 +1894,10 @@ void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event)
if (event->window == m_window) {
m_mapped = false;
QWindowSystemInterface::handleExposeEvent(window(), QRegion());
+ if (!m_isWmManagedWindow) {
+ m_wmStateValid = true;
+ handleDeferredTasks();
+ }
}
}
@@ -2188,30 +2212,98 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event)
handleLeaveNotifyEvent(event->root_x, event->root_y, event->mode, event->detail, event->time);
}
+bool QXcbWindow::shouldDeferTask(Task task)
+{
+ if (m_wmStateValid)
+ return false;
+
+ m_deferredTasks.append(task);
+ return true;
+}
+
+void QXcbWindow::handleDeferredTasks()
+{
+ Q_ASSERT(m_wmStateValid == true);
+ if (m_deferredTasks.isEmpty())
+ return;
+
+ bool map = false;
+ bool unmap = false;
+
+ QVector<Task> tasks;
+ for (auto taskIt = m_deferredTasks.rbegin(); taskIt != m_deferredTasks.rend(); ++taskIt) {
+ if (!tasks.contains(*taskIt))
+ tasks.prepend(*taskIt);
+ }
+
+ for (Task task : tasks) {
+ switch (task) {
+ case Task::Map:
+ map = true;
+ unmap = false;
+ break;
+ case Task::Unmap:
+ unmap = true;
+ map = false;
+ break;
+ case Task::SetGeometry:
+ setGeometry(m_deferredGeometry);
+ break;
+ case Task::SetWindowFlags:
+ setWindowFlags(window()->flags());
+ break;
+ case Task::SetWindowState:
+ setWindowState(window()->windowState());
+ break;
+ }
+ }
+ m_deferredTasks.clear();
+
+ if (map) {
+ Q_ASSERT(unmap == false);
+ show();
+ }
+ if (unmap) {
+ Q_ASSERT(map == false);
+ hide();
+ }
+}
+
void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event)
{
connection()->setTime(event->time);
- const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
-
- if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) {
- if (propertyDeleted)
+ const bool wmStateChanged = event->atom == atom(QXcbAtom::WM_STATE);
+ const bool netWmStateChanged = event->atom == atom(QXcbAtom::_NET_WM_STATE);
+ if (netWmStateChanged || wmStateChanged) {
+ if (wmStateChanged && !m_wmStateValid && m_isWmManagedWindow) {
+ // ICCCM 4.1.4
+ // Clients that want to re-use a client window (e.g. by mapping it again)
+ // after withdrawing it must wait for the withdrawal to be complete before
+ // proceeding. The preferred method for doing this is for clients to wait for
+ // a window manager to update or remove the WM_STATE property.
+ m_wmStateValid = true;
+ handleDeferredTasks();
+ }
+ if (event->state == XCB_PROPERTY_DELETE)
return;
- Qt::WindowStates newState = Qt::WindowNoState;
-
- if (event->atom == atom(QXcbAtom::WM_STATE)) { // WM_STATE: Quick check for 'Minimize'.
+ if (wmStateChanged) {
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(),
0, m_window, atom(QXcbAtom::WM_STATE),
XCB_ATOM_ANY, 0, 1024);
if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) {
- const quint32 *data = (const quint32 *)xcb_get_property_value(reply.get());
- if (reply->length != 0)
- m_minimized = (data[0] == XCB_ICCCM_WM_STATE_ICONIC
- || (data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN && m_minimized));
+ auto data = static_cast<const quint32 *>(xcb_get_property_value(reply.get()));
+ if (reply->length != 0) {
+ const bool changedToWithdrawn = data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN;
+ const bool changedToIconic = data[0] == XCB_ICCCM_WM_STATE_ICONIC;
+ m_minimized = changedToIconic || (changedToWithdrawn && m_minimized);
+ }
}
}
+ // _NET_WM_STATE handling
+ Qt::WindowStates newState = Qt::WindowNoState;
const NetWmStates states = netWmStates();
// _NET_WM_STATE_HIDDEN should be set by the Window Manager to indicate that a window would
// not be visible on the screen if its desktop/viewport were active and its coordinates were
@@ -2233,7 +2325,6 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
if ((m_windowState & Qt::WindowMinimized) && connection()->mouseGrabber() == this)
connection()->setMouseGrabber(nullptr);
}
- return;
} else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) {
m_dirtyFrameMargins = true;
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 6f5c1f5ed9..55af9279b1 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -74,6 +74,14 @@ public:
Q_DECLARE_FLAGS(NetWmStates, NetWmState)
+ enum Task {
+ Map,
+ Unmap,
+ SetGeometry,
+ SetWindowFlags,
+ SetWindowState
+ };
+
QXcbWindow(QWindow *window);
~QXcbWindow();
@@ -143,6 +151,9 @@ public:
QXcbWindow *toWindow() override;
+ bool shouldDeferTask(Task task);
+ void handleDeferredTasks();
+
void handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global,
Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source);
@@ -281,6 +292,11 @@ protected:
int m_swapInterval = -1;
qreal m_sizeHintsScaleFactor = 1.0;
+
+ bool m_wmStateValid = true;
+ QVector<Task> m_deferredTasks;
+ bool m_isWmManagedWindow = true;
+ QRect m_deferredGeometry;
};
class QXcbForeignWindow : public QXcbWindow