summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2018-02-16 08:54:58 +0100
committerLiang Qi <liang.qi@qt.io>2018-02-16 08:54:58 +0100
commit942ab490724fcc9544e786e5783718e1a07aa50b (patch)
treefeb7d3ff716edb37b2ca60e33c05adf8777bd964 /src/plugins/platforms/xcb
parent0fb8271a467202990c90321066e40faed640a7a8 (diff)
parent24adaa9a742e6f95ff897d0eb9a2bce0527dd042 (diff)
Merge remote-tracking branch 'origin/5.11' into dev
Conflicts: src/corelib/tools/tools.pri Change-Id: I705630f9cecbf0ce51a22fc6116b8c49611259e9
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp166
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp37
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h6
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp6
5 files changed, 172 insertions, 47 deletions
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
index 56a737e882..21024385b0 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
@@ -134,7 +134,11 @@ static void updateFormatFromContext(QSurfaceFormat &format)
}
format.setProfile(QSurfaceFormat::NoProfile);
+ const bool isStereo = format.testOption(QSurfaceFormat::StereoBuffers);
format.setOptions(QSurfaceFormat::FormatOptions());
+ // Restore flags that come from the VisualInfo/FBConfig.
+ if (isStereo)
+ format.setOption(QSurfaceFormat::StereoBuffers);
if (format.renderableType() == QSurfaceFormat::OpenGL) {
if (format.version() < qMakePair(3, 0)) {
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 1cf45c96d1..eae0ee7613 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -48,9 +48,11 @@
#include <sys/ipc.h>
#include <sys/shm.h>
+#include <sys/mman.h>
#include <stdio.h>
#include <errno.h>
+#include <unistd.h>
#include <qdebug.h>
#include <qpainter.h>
@@ -61,6 +63,11 @@
#include <qendian.h>
#include <algorithm>
+
+#if (XCB_SHM_MAJOR_VERSION == 1 && XCB_SHM_MINOR_VERSION >= 2) || XCB_SHM_MAJOR_VERSION > 1
+#define XCB_USE_SHM_FD
+#endif
+
QT_BEGIN_NAMESPACE
class QXcbShmImage : public QXcbObject
@@ -85,6 +92,9 @@ public:
void preparePaint(const QRegion &region);
private:
+ void createShmSegment(size_t segmentSize);
+ void destroyShmSegment(size_t segmentSize);
+
void destroy();
void ensureGC(xcb_drawable_t dst);
@@ -154,6 +164,11 @@ private:
QImage *m_image;
};
+static inline size_t imageDataSize(const xcb_image_t *image)
+{
+ return static_cast<size_t>(image->stride) * image->height;
+}
+
QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format)
: QXcbObject(screen->connection())
, m_graphics_buffer(nullptr)
@@ -173,39 +188,13 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI
XCB_IMAGE_ORDER_MSB_FIRST,
0, ~0, 0);
- const int segmentSize = m_xcb_image->stride * m_xcb_image->height;
+ const size_t segmentSize = imageDataSize(m_xcb_image);
if (!segmentSize)
return;
- int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600);
- if (id == -1) {
- qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %d (%dx%d)",
- errno, strerror(errno), segmentSize, size.width(), size.height());
- } else {
- m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat(id, 0, 0);
- }
- m_shm_info.shmid = id;
- m_shm_info.shmseg = xcb_generate_id(xcb_connection());
-
- const xcb_query_extension_reply_t *shm_reply = xcb_get_extension_data(xcb_connection(), &xcb_shm_id);
- bool shm_present = shm_reply != NULL && shm_reply->present;
- xcb_generic_error_t *error = NULL;
- if (shm_present)
- error = xcb_request_check(xcb_connection(), xcb_shm_attach_checked(xcb_connection(), m_shm_info.shmseg, m_shm_info.shmid, false));
- if (!shm_present || error || id == -1) {
- free(error);
-
- if (id != -1) {
- shmdt(m_shm_info.shmaddr);
- shmctl(m_shm_info.shmid, IPC_RMID, 0);
- }
- m_shm_info.shmaddr = 0;
+ createShmSegment(segmentSize);
- m_xcb_image->data = (uint8_t *)malloc(segmentSize);
- } else {
- if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1)
- qWarning("QXcbBackingStore: Error while marking the shared memory segment to be destroyed");
- }
+ m_xcb_image->data = m_shm_info.shmaddr ? m_shm_info.shmaddr : (uint8_t *)malloc(segmentSize);
m_hasAlpha = QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha;
if (!m_hasAlpha)
@@ -270,6 +259,111 @@ void QXcbShmImage::flushScrolledRegion(bool clientSideScroll)
}
}
+void QXcbShmImage::createShmSegment(size_t segmentSize)
+{
+ m_shm_info.shmaddr = nullptr;
+
+ if (!connection()->hasShm())
+ return;
+
+#ifdef XCB_USE_SHM_FD
+ if (connection()->hasShmFd()) {
+ if (Q_UNLIKELY(segmentSize > std::numeric_limits<uint32_t>::max())) {
+ qWarning("QXcbShmImage: xcb_shm_create_segment() can't be called for size %zu, maximum allowed size is %u",
+ segmentSize, std::numeric_limits<uint32_t>::max());
+ return;
+ }
+ const auto seg = xcb_generate_id(xcb_connection());
+ auto reply = Q_XCB_REPLY(xcb_shm_create_segment,
+ xcb_connection(), seg, segmentSize, false);
+ if (!reply) {
+ qWarning("QXcbShmImage: xcb_shm_create_segment() failed for size %zu", segmentSize);
+ return;
+ }
+
+ int *fds = xcb_shm_create_segment_reply_fds(xcb_connection(), reply.get());
+ if (reply->nfd != 1) {
+ for (int i = 0; i < reply->nfd; i++)
+ close(fds[i]);
+
+ qWarning("QXcbShmImage: failed to get file descriptor for shm segment of size %zu", segmentSize);
+ return;
+ }
+
+ void *addr = mmap(nullptr, segmentSize, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0], 0);
+ if (addr == MAP_FAILED) {
+ qWarning("QXcbShmImage: failed to mmap segment from X server (%d: %s) for size %zu",
+ errno, strerror(errno), segmentSize);
+ close(fds[0]);
+ xcb_shm_detach(xcb_connection(), seg);
+ return;
+ }
+
+ close(fds[0]);
+ m_shm_info.shmseg = seg;
+ m_shm_info.shmaddr = static_cast<quint8 *>(addr);
+ } else
+#endif
+ {
+ const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600);
+ if (id == -1) {
+ qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %zu",
+ errno, strerror(errno), segmentSize);
+ return;
+ }
+
+ void *addr = shmat(id, 0, 0);
+ if (addr == (void *)-1) {
+ qWarning("QXcbShmImage: shmat() failed (%d: %s) for id %d",
+ errno, strerror(errno), id);
+ return;
+ }
+
+ if (shmctl(id, IPC_RMID, 0) == -1)
+ qWarning("QXcbBackingStore: Error while marking the shared memory segment to be destroyed");
+
+ const auto seg = xcb_generate_id(xcb_connection());
+ auto cookie = xcb_shm_attach_checked(xcb_connection(), seg, id, false);
+ auto *error = xcb_request_check(xcb_connection(), cookie);
+ if (error) {
+ connection()->printXcbError("QXcbShmImage: xcb_shm_attach() failed with error", error);
+ free(error);
+ if (shmdt(addr) == -1) {
+ qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p",
+ errno, strerror(errno), addr);
+ }
+ return;
+ }
+
+ m_shm_info.shmseg = seg;
+ m_shm_info.shmid = id; // unused
+ m_shm_info.shmaddr = static_cast<quint8 *>(addr);
+ }
+}
+
+void QXcbShmImage::destroyShmSegment(size_t segmentSize)
+{
+ auto cookie = xcb_shm_detach_checked(xcb_connection(), m_shm_info.shmseg);
+ xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
+ if (error)
+ connection()->printXcbError("QXcbShmImage: xcb_shm_detach() failed with error", error);
+
+#ifdef XCB_USE_SHM_FD
+ if (connection()->hasShmFd()) {
+ if (munmap(m_shm_info.shmaddr, segmentSize) == -1) {
+ qWarning("QXcbShmImage: munmap() failed (%d: %s) for %p with size %zu",
+ errno, strerror(errno), m_shm_info.shmaddr, segmentSize);
+ }
+ } else
+#endif
+ {
+ if (shmdt(m_shm_info.shmaddr) == -1) {
+ qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p",
+ errno, strerror(errno), m_shm_info.shmaddr);
+ }
+ }
+}
+
extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
bool QXcbShmImage::scroll(const QRegion &area, int dx, int dy)
@@ -318,17 +412,11 @@ bool QXcbShmImage::scroll(const QRegion &area, int dx, int dy)
void QXcbShmImage::destroy()
{
- const int segmentSize = m_xcb_image ? (m_xcb_image->stride * m_xcb_image->height) : 0;
- if (segmentSize && m_shm_info.shmaddr)
- xcb_shm_detach(xcb_connection(), m_shm_info.shmseg);
-
- if (segmentSize) {
- if (m_shm_info.shmaddr) {
- shmdt(m_shm_info.shmaddr);
- shmctl(m_shm_info.shmid, IPC_RMID, 0);
- } else {
+ if (m_xcb_image->data) {
+ if (m_shm_info.shmaddr)
+ destroyShmSegment(imageDataSize(m_xcb_image));
+ else
free(m_xcb_image->data);
- }
}
xcb_image_destroy(m_xcb_image);
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index d6013541fc..ee25d6a12f 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -582,6 +582,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeAllAtoms();
+ initializeShm();
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR"))
initializeXRandr();
if (!has_randr_extension)
@@ -961,14 +962,20 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error)
if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), error, &result))
return;
+ printXcbError("QXcbConnection: XCB error", error);
+}
+
+void QXcbConnection::printXcbError(const char *message, 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);
- qWarning("QXcbConnection: XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d",
- 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));
+ qWarning("%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d",
+ message,
+ 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));
}
static Qt::MouseButtons translateMouseButtons(int s)
@@ -2084,6 +2091,26 @@ void QXcbConnection::sync()
free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0));
}
+void QXcbConnection::initializeShm()
+{
+ const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_shm_id);
+ if (!reply || !reply->present) {
+ qWarning("QXcbConnection: MIT-SHM extension is not present on the X server.");
+ return;
+ }
+
+ has_shm = true;
+
+ auto shm_query = Q_XCB_REPLY(xcb_shm_query_version, m_connection);
+ if (!shm_query) {
+ qWarning("QXcbConnection: Failed to request MIT-SHM version");
+ return;
+ }
+
+ has_shm_fd = (shm_query->major_version == 1 && shm_query->minor_version >= 2) ||
+ shm_query->major_version > 1;
+}
+
void QXcbConnection::initializeXFixes()
{
const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xfixes_id);
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 2e06292f78..0a7f878ed8 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -438,6 +438,7 @@ public:
void sync();
void handleXcbError(xcb_generic_error_t *error);
+ void printXcbError(const char *message, xcb_generic_error_t *error);
void handleXcbEvent(xcb_generic_event_t *event);
void printXcbEvent(const QLoggingCategory &log, const char *message,
xcb_generic_event_t *event) const;
@@ -475,6 +476,8 @@ public:
bool hasXKB() const { return has_xkb; }
bool hasXRender() const { return has_render_extension; }
bool hasXInput2() const { return m_xi2Enabled; }
+ bool hasShm() const { return has_shm; }
+ bool hasShmFd() const { return has_shm_fd; }
bool threadedEventHandling() const { return m_reader->isRunning(); }
@@ -542,6 +545,7 @@ private slots:
private:
void initializeAllAtoms();
void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0);
+ void initializeShm();
void initializeXFixes();
void initializeXRender();
void initializeXRandr();
@@ -696,6 +700,8 @@ private:
bool has_input_shape;
bool has_xkb = false;
bool has_render_extension = false;
+ bool has_shm = false;
+ bool has_shm_fd = false;
Qt::MouseButtons m_buttonState = 0;
Qt::MouseButton m_button = Qt::NoButton;
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 5b05a230e4..e9a6e536a7 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -2071,7 +2071,7 @@ bool QXcbWindow::isEmbedded() const
QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const
{
if (!m_embedded)
- return pos;
+ return QPlatformWindow::mapToGlobal(pos);
QPoint ret;
auto reply = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(),
@@ -2088,7 +2088,7 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const
QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const
{
if (!m_embedded)
- return pos;
+ return QPlatformWindow::mapFromGlobal(pos);
QPoint ret;
auto reply = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(),
@@ -2857,7 +2857,7 @@ QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window)
utf8Atom, 0, 1024);
if (reply && reply->format == 8 && reply->type == utf8Atom) {
const char *name = reinterpret_cast<const char *>(xcb_get_property_value(reply.get()));
- return QString::fromUtf8(name);
+ return QString::fromUtf8(name, xcb_get_property_value_length(reply.get()));
}
return QString();
}