summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb
diff options
context:
space:
mode:
authorSamuel Rødal <samuel.rodal@nokia.com>2011-04-06 17:17:50 +0200
committerSamuel Rødal <samuel.rodal@nokia.com>2011-04-07 13:23:35 +0200
commit3a7a03f5ab0f927211050d2dcceb9440e2b0aeeb (patch)
tree274a88c1a714e3ef9e42f79283168bf79a6040f0 /src/plugins/platforms/xcb
parentdfa586395b0dabbf6b81e77625a4f8d43ee9a80d (diff)
Implemented _NET_WM_SYNC_REQUEST protocol in XCB plugin.
Excluded KWin for now, as it sends multiple ConfigureNotify events per _NET_WM_SYNC_REQUEST message.
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r--src/plugins/platforms/xcb/README3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp59
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h1
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp36
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h6
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp48
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h9
-rw-r--r--src/plugins/platforms/xcb/qxcbwindowsurface.cpp13
-rw-r--r--src/plugins/platforms/xcb/qxcbwindowsurface.h1
-rw-r--r--src/plugins/platforms/xcb/xcb.pro2
10 files changed, 146 insertions, 32 deletions
diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README
index e88596b170..17a86e6d08 100644
--- a/src/plugins/platforms/xcb/README
+++ b/src/plugins/platforms/xcb/README
@@ -1,2 +1,3 @@
Required packages:
-libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev
+libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev
+
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 84d98e84d1..2413a32534 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -105,6 +105,8 @@ QXcbConnection::QXcbConnection(const char *displayName)
#endif //XCB_USE_XLIB
m_setup = xcb_get_setup(xcb_connection());
+ initializeAllAtoms();
+
xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
int screenNumber = 0;
@@ -115,8 +117,6 @@ QXcbConnection::QXcbConnection(const char *displayName)
m_keyboard = new QXcbKeyboard(this);
- initializeAllAtoms();
-
#ifdef XCB_USE_DRI2
initializeDri2();
#endif
@@ -379,6 +379,34 @@ void QXcbConnection::log(const char *file, int line, int sequence)
}
#endif
+void QXcbConnection::handleXcbError(xcb_generic_error_t *error)
+{
+ uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1);
+ uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1);
+
+ printf("XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d\n",
+ int(error->error_code), xcb_errors[clamped_error_code],
+ int(error->sequence), int(error->resource_id),
+ int(error->major_code), xcb_protocol_request_codes[clamped_major_code],
+ int(error->minor_code));
+#ifdef Q_XCB_DEBUG
+ int i = 0;
+ for (; i < m_callLog.size(); ++i) {
+ if (m_callLog.at(i).sequence == error->sequence) {
+ printf("Caused by: %s:%d\n", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
+ break;
+ } else if (m_callLog.at(i).sequence > error->sequence) {
+ printf("Caused some time before: %s:%d\n", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
+ if (i > 0)
+ printf("and after: %s:%d\n", qPrintable(m_callLog.at(i-1).file), m_callLog.at(i-1).line);
+ break;
+ }
+ }
+ if (i == m_callLog.size() && !m_callLog.isEmpty())
+ printf("Caused some time after: %s:%d\n", qPrintable(m_callLog.first().file), m_callLog.first().line);
+#endif
+}
+
void QXcbConnection::processXcbEvents()
{
while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) {
@@ -387,32 +415,7 @@ void QXcbConnection::processXcbEvents()
uint response_type = event->response_type & ~0x80;
if (!response_type) {
- xcb_generic_error_t *error = (xcb_generic_error_t *)event;
-
- uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1);
- uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1);
-
- printf("XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d\n",
- int(error->error_code), xcb_errors[clamped_error_code],
- int(error->sequence), int(error->resource_id),
- int(error->major_code), xcb_protocol_request_codes[clamped_major_code],
- int(error->minor_code));
-#ifdef Q_XCB_DEBUG
- int i = 0;
- for (; i < m_callLog.size(); ++i) {
- if (m_callLog.at(i).sequence == error->sequence) {
- printf("Caused by: %s:%d\n", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
- break;
- } else if (m_callLog.at(i).sequence > error->sequence) {
- printf("Caused some time before: %s:%d\n", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
- if (i > 0)
- printf("and after: %s:%d\n", qPrintable(m_callLog.at(i-1).file), m_callLog.at(i-1).line);
- break;
- }
- }
- if (i == m_callLog.size() && !m_callLog.isEmpty())
- printf("Caused some time after: %s:%d\n", qPrintable(m_callLog.first().file), m_callLog.first().line);
-#endif
+ handleXcbError((xcb_generic_error_t *)event);
continue;
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 53846f1d5d..e38b44ed03 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -252,6 +252,7 @@ public:
#endif
void sync();
+ void handleXcbError(xcb_generic_error_t *error);
private slots:
void processXcbEvents();
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 49ed44c300..1c12ee3059 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -66,6 +66,42 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num
};
xcb_change_window_attributes(xcb_connection(), screen->root, mask, values);
+
+ xcb_generic_error_t *error;
+
+ xcb_get_property_reply_t *reply =
+ xcb_get_property_reply(xcb_connection(),
+ xcb_get_property(xcb_connection(), false, screen->root,
+ atom(QXcbAtom::_NET_SUPPORTING_WM_CHECK),
+ XCB_ATOM_WINDOW, 0, 1024), &error);
+
+ if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) {
+ xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply));
+
+ if (windowManager != XCB_WINDOW_NONE) {
+ xcb_get_property_reply_t *windowManagerReply =
+ xcb_get_property_reply(xcb_connection(),
+ xcb_get_property(xcb_connection(), false, windowManager,
+ atom(QXcbAtom::_NET_WM_NAME),
+ atom(QXcbAtom::UTF8_STRING), 0, 1024), &error);
+ if (windowManagerReply && windowManagerReply->format == 8 && windowManagerReply->type == atom(QXcbAtom::UTF8_STRING)) {
+ m_windowManagerName = QString::fromUtf8((const char *)xcb_get_property_value(windowManagerReply), xcb_get_property_value_length(windowManagerReply));
+ printf("Running window manager: %s\n", qPrintable(m_windowManagerName));
+ } else if (error) {
+ connection->handleXcbError(error);
+ free(error);
+ }
+
+ free(windowManagerReply);
+ }
+ } else if (error) {
+ connection->handleXcbError(error);
+ free(error);
+ }
+
+ free(reply);
+
+ m_syncRequestSupported = m_windowManagerName != QLatin1String("KWin");
}
QXcbScreen::~QXcbScreen()
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index 6f69fc78a1..9547d016b7 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -43,6 +43,7 @@
#define QXCBSCREEN_H
#include <QtGui/QPlatformScreen>
+#include <QtCore/QString>
#include <xcb/xcb.h>
@@ -66,9 +67,14 @@ public:
xcb_screen_t *screen() const { return m_screen; }
xcb_window_t root() const { return m_screen->root; }
+ QString windowManagerName() const { return m_windowManagerName; }
+ bool syncRequestSupported() const { return m_syncRequestSupported; }
+
private:
xcb_screen_t *m_screen;
int m_number;
+ QString m_windowManagerName;
+ bool m_syncRequestSupported;
};
#endif
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 4a9409c808..1e9a0f8418 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -41,6 +41,8 @@
#include "qxcbwindow.h"
+#include <QtDebug>
+
#include "qxcbconnection.h"
#include "qxcbscreen.h"
#ifdef XCB_USE_DRI2
@@ -171,6 +173,9 @@ QXcbWindow::QXcbWindow(QWidget *tlw)
properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS);
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING);
+ if (m_screen->syncRequestSupported())
+ properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST);
+
if (tlw->windowFlags() & Qt::WindowContextHelpButtonHint)
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP);
@@ -178,10 +183,26 @@ QXcbWindow::QXcbWindow(QWidget *tlw)
XCB_PROP_MODE_REPLACE,
m_window,
atom(QXcbAtom::WM_PROTOCOLS),
- 4,
+ XCB_ATOM_ATOM,
32,
propertyCount,
properties));
+ m_syncValue.hi = 0;
+ m_syncValue.lo = 0;
+
+ if (m_screen->syncRequestSupported()) {
+ m_syncCounter = xcb_generate_id(xcb_connection());
+ Q_XCB_CALL(xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue));
+
+ Q_XCB_CALL(xcb_change_property(xcb_connection(),
+ XCB_PROP_MODE_REPLACE,
+ m_window,
+ atom(QXcbAtom::_NET_WM_SYNC_REQUEST_COUNTER),
+ XCB_ATOM_CARDINAL,
+ 32,
+ 1,
+ &m_syncCounter));
+ }
if (isTransient(tlw) && tlw->parentWidget()) {
// ICCCM 4.1.2.6
@@ -197,6 +218,8 @@ QXcbWindow::QXcbWindow(QWidget *tlw)
QXcbWindow::~QXcbWindow()
{
delete m_context;
+ if (m_screen->syncRequestSupported())
+ Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter));
Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window));
}
@@ -474,6 +497,13 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&reply);
xcb_flush(xcb_connection());
+ } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) {
+ if (!m_hasReceivedSyncRequest) {
+ m_hasReceivedSyncRequest = true;
+ printf("Window manager supports _NET_WM_SYNC_REQUEST, syncing resizes\n");
+ }
+ m_syncValue.lo = event->data.data32[2];
+ m_syncValue.hi = event->data.data32[3];
}
}
}
@@ -489,8 +519,11 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
}
QRect rect(xpos, ypos, event->width, event->height);
- QPlatformWindow::setGeometry(rect);
+ if (rect == geometry())
+ return;
+
+ QPlatformWindow::setGeometry(rect);
QWindowSystemInterface::handleGeometryChange(widget(), rect);
#if XCB_USE_DRI2
@@ -593,3 +626,14 @@ void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
QWindowSystemInterface::handleWindowActivated(0);
}
+void QXcbWindow::updateSyncRequestCounter()
+{
+ if (m_screen->syncRequestSupported() && m_syncValue.lo != 0 || m_syncValue.hi != 0) {
+ Q_XCB_CALL(xcb_sync_set_counter(xcb_connection(), m_syncCounter, m_syncValue));
+ xcb_flush(xcb_connection());
+ connection()->sync();
+
+ m_syncValue.lo = 0;
+ m_syncValue.hi = 0;
+ }
+}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 1e9930d79c..0fa4d0f7dc 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -46,6 +46,7 @@
#include <QtGui/QPlatformWindowFormat>
#include <xcb/xcb.h>
+#include <xcb/sync.h>
#include "qxcbobject.h"
@@ -88,11 +89,19 @@ public:
void handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global);
+ void updateSyncRequestCounter();
+
private:
+
QXcbScreen *m_screen;
xcb_window_t m_window;
QPlatformGLContext *m_context;
+
+ xcb_sync_int64_t m_syncValue;
+ xcb_sync_counter_t m_syncCounter;
+
+ bool m_hasReceivedSyncRequest;
};
#endif
diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp
index c068d1c2ff..718f09383c 100644
--- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp
@@ -170,6 +170,7 @@ void QXcbShmImage::preparePaint(const QRegion &region)
QXcbWindowSurface::QXcbWindowSurface(QWidget *widget, bool setDefaultSurface)
: QWindowSurface(widget, setDefaultSurface)
, m_image(0)
+ , m_syncingResize(false)
{
QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(widget));
setConnection(screen->connection());
@@ -213,10 +214,20 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoi
m_image->put(window->window(), rects.at(i).topLeft() - widgetOffset, rects.at(i).translated(offset));
Q_XCB_NOOP(connection());
+
+ if (m_syncingResize) {
+ xcb_flush(xcb_connection());
+ connection()->sync();
+ m_syncingResize = false;
+ window->updateSyncRequestCounter();
+ }
}
void QXcbWindowSurface::resize(const QSize &size)
{
+ if (size == QWindowSurface::size())
+ return;
+
Q_XCB_NOOP(connection());
QWindowSurface::resize(size);
@@ -225,6 +236,8 @@ void QXcbWindowSurface::resize(const QSize &size)
delete m_image;
m_image = new QXcbShmImage(screen, size);
Q_XCB_NOOP(connection());
+
+ m_syncingResize = true;
}
extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.h b/src/plugins/platforms/xcb/qxcbwindowsurface.h
index f87e122eda..23d32ef445 100644
--- a/src/plugins/platforms/xcb/qxcbwindowsurface.h
+++ b/src/plugins/platforms/xcb/qxcbwindowsurface.h
@@ -66,6 +66,7 @@ public:
private:
QXcbShmImage *m_image;
+ bool m_syncingResize;
};
#endif
diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro
index 122cb40639..101bdcd3c1 100644
--- a/src/plugins/platforms/xcb/xcb.pro
+++ b/src/plugins/platforms/xcb/xcb.pro
@@ -62,7 +62,7 @@ contains(QT_CONFIG, opengl) {
}
}
-LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm
+LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync
include (../fontdatabases/genericunix/genericunix.pri)